com.googlecode.d2j.tools.jar.DexWeaver Maven / Gradle / Ivy
The newest version!
/*
* dex2jar - Tools to work with android .dex and java .class files
* Copyright (c) 2009-2015 Panxiaobo
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.googlecode.d2j.tools.jar;
import com.googlecode.d2j.DexConstants;
import com.googlecode.d2j.DexLabel;
import com.googlecode.d2j.Field;
import com.googlecode.d2j.Method;
import com.googlecode.d2j.node.DexCodeNode;
import com.googlecode.d2j.node.DexMethodNode;
import com.googlecode.d2j.reader.Op;
import com.googlecode.d2j.visitors.DexClassVisitor;
import com.googlecode.d2j.visitors.DexCodeVisitor;
import com.googlecode.d2j.visitors.DexFileVisitor;
import com.googlecode.d2j.visitors.DexMethodVisitor;
import org.objectweb.asm.Type;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
/**
* only implement sub set of InvocationWeaver
* 2. Replace method A to another method B, parameter of B must be MethodInvocation
* 3. Replace Methods Implementations
*/
public class DexWeaver extends BaseWeaver {
interface CB {
String getKey(Method mtd);
}
public String buildInvocationClz(DexFileVisitor dfv) {
String typeName = getCurrentInvocationName();
String typeNameDesc = "L" + typeName + ";";
DexClassVisitor dcv = dfv.visit(DexConstants.ACC_PUBLIC, typeNameDesc, "Ljava/lang/Object;", new String[]{
invocationInterfaceDesc});
dcv.visitField(DexConstants.ACC_PRIVATE | DexConstants.ACC_FINAL,
new Field(typeNameDesc, "thiz", "Ljava/lang/Object;"), null).visitEnd();
dcv.visitField(DexConstants.ACC_PRIVATE | DexConstants.ACC_FINAL, new Field(typeNameDesc, "args", "[Ljava/lang/Object;"), null)
.visitEnd();
dcv.visitField(DexConstants.ACC_PRIVATE | DexConstants.ACC_FINAL, new Field(typeNameDesc, "idx", "I"), null)
.visitEnd();
{
DexMethodVisitor mv = dcv
.visitMethod(DexConstants.ACC_PUBLIC | DexConstants.ACC_CONSTRUCTOR, new Method(typeNameDesc, "", new String[]{
"Ljava/lang/Object;", "[Ljava/lang/Object;", "I"}, "V"));
DexCodeVisitor codeVisitor = mv.visitCode();
codeVisitor.visitRegister(4);
codeVisitor.visitFieldStmt(Op.IPUT_OBJECT, 1, 0, new Field(typeNameDesc, "thiz", "Ljava/lang/Object;"));
codeVisitor.visitFieldStmt(Op.IPUT_OBJECT, 2, 0, new Field(typeNameDesc, "args", "[Ljava/lang/Object;"));
codeVisitor.visitFieldStmt(Op.IPUT, 3, 0, new Field(typeNameDesc, "idx", "I"));
codeVisitor.visitStmt0R(Op.RETURN_VOID);
codeVisitor.visitEnd();
mv.visitEnd();
}
{
genSwitchMethod(dcv, typeNameDesc, "getMethodOwner", new CB() {
@Override
public String getKey(Method mtd) {
return toInternal(mtd.getOwner());
}
});
genSwitchMethod(dcv, typeNameDesc, "getMethodName", new CB() {
@Override
public String getKey(Method mtd) {
return mtd.getName();
}
});
genSwitchMethod(dcv, typeNameDesc, "getMethodDesc", new CB() {
@Override
public String getKey(Method mtd) {
return mtd.getDesc();
}
});
}
{
DexMethodVisitor mv = dcv
.visitMethod(DexConstants.ACC_PUBLIC, new Method(typeNameDesc, "getArguments", new String[0], "[Ljava/lang/Object;"));
DexCodeVisitor code = mv.visitCode();
code.visitRegister(2);
code.visitFieldStmt(Op.IGET, 0, 1, new Field(typeNameDesc, "args", "[Ljava/lang/Object;"));
code.visitStmt1R(Op.RETURN_OBJECT, 0);
code.visitEnd();
mv.visitEnd();
}
{
DexMethodVisitor mv = dcv
.visitMethod(DexConstants.ACC_PUBLIC, new Method(typeNameDesc, "getThis", new String[0], "Ljava/lang/Object;"));
DexCodeVisitor code = mv.visitCode();
code.visitRegister(2);
code.visitFieldStmt(Op.IGET, 0, 1, new Field(typeNameDesc, "thiz", "Ljava/lang/Object;"));
code.visitStmt1R(Op.RETURN_OBJECT, 0);
code.visitEnd();
mv.visitEnd();
}
{
DexMethodVisitor mv = dcv
.visitMethod(DexConstants.ACC_PUBLIC, new Method(typeNameDesc, "proceed", new String[0], "Ljava/lang/Object;"));
DexCodeVisitor code = mv.visitCode();
code.visitRegister(4);
code.visitFieldStmt(Op.IGET, 0, 3, new Field(typeNameDesc, "thiz", "Ljava/lang/Object;"));
code.visitFieldStmt(Op.IGET, 1, 3, new Field(typeNameDesc, "args", "[Ljava/lang/Object;"));
code.visitFieldStmt(Op.IGET, 2, 3, new Field(typeNameDesc, "idx", "I"));
DexLabel labels[] = new DexLabel[callbacks.size()];
for (int i = 0; i < labels.length; i++) {
labels[i] = new DexLabel();
}
code.visitPackedSwitchStmt(Op.PACKED_SWITCH, 2, 0, labels);
code.visitTypeStmt(Op.NEW_INSTANCE, 0, 0, "Ljava/lang/RuntimeException;");
code.visitConstStmt(Op.CONST_STRING, 1, "invalid idx");
code.visitMethodStmt(Op.INVOKE_DIRECT, new int[]{0,
1}, new Method("Ljava/lang/RuntimeException;", "", new String[]{"Ljava/lang/String;"}, "V"));
code.visitStmt1R(Op.THROW, 0);
for (int i = 0; i < labels.length; i++) {
code.visitLabel(labels[i]);
Callback callback = callbacks.get(i);
Method mCallback = (Method) callback.callback;
if (callback.isStatic) {
code.visitMethodStmt(Op.INVOKE_STATIC, new int[]{1}, mCallback);
} else if (callback.isSpecial) {
code.visitTypeStmt(Op.CHECK_CAST, 0, -1, mCallback.getOwner());
code.visitMethodStmt(Op.INVOKE_VIRTUAL, new int[]{0, 1}, mCallback);
} else {
code.visitMethodStmt(Op.INVOKE_STATIC, new int[]{0, 1}, mCallback);
}
code.visitStmt1R(Op.MOVE_RESULT_OBJECT, 0);
code.visitStmt1R(Op.RETURN_OBJECT, 0);
}
code.visitEnd();
mv.visitEnd();
}
dcv.visitEnd();
return typeName;
}
private void genSwitchMethod(DexClassVisitor dcv, String typeNameDesc, String methodName, CB callback) {
DexMethodVisitor dmv = dcv
.visitMethod(DexConstants.ACC_PUBLIC, new Method(typeNameDesc, methodName, new String[0], "Ljava/lang/String;"));
DexCodeVisitor code = dmv.visitCode();
code.visitRegister(3);
code.visitFieldStmt(Op.IGET, 0, 2, new Field(typeNameDesc, "idx", "I"));
DexLabel labels[] = new DexLabel[callbacks.size()];
Map strMap = new TreeMap<>();
for (int i = 0; i < labels.length; i++) {
Callback cb = callbacks.get(i);
String key = callback.getKey((Method) cb.target);
DexLabel label = strMap.get(key);
if (label == null) {
label = new DexLabel();
strMap.put(key, label);
}
labels[i] = label;
}
code.visitPackedSwitchStmt(Op.PACKED_SWITCH, 0, 0, labels);
code.visitTypeStmt(Op.NEW_INSTANCE, 0, 0, "Ljava/lang/RuntimeException;");
code.visitConstStmt(Op.CONST_STRING, 1, "invalid idx");
code.visitMethodStmt(Op.INVOKE_DIRECT, new int[]{0,
1}, new Method("Ljava/lang/RuntimeException;", "", new String[]{"Ljava/lang/String;"}, "V"));
code.visitStmt1R(Op.THROW, 0);
for (Map.Entry e : strMap.entrySet()) {
code.visitLabel(e.getValue());
code.visitConstStmt(Op.CONST_STRING, 0, e.getKey());
code.visitStmt1R(Op.RETURN_OBJECT, 0);
}
code.visitEnd();
dmv.visitEnd();
}
public DexFileVisitor wrap(DexFileVisitor dcv) {
return dcv == null ? null : new DexFileVisitor(dcv) {
@Override
public DexClassVisitor visit(int access_flags, String className, String superClass, String[] interfaceNames) {
return wrap(className, super.visit(access_flags, className, superClass, interfaceNames));
}
};
}
public DexClassVisitor wrap(final String classNameDesc, final DexClassVisitor dcv) {
return dcv == null ? null : new DexClassVisitor(dcv) {
Map cache = new HashMap<>();
@Override
public DexMethodVisitor visitMethod(final int accessFlags, Method method) {
final DexMethodVisitor dmv = superVisitDexMethod(accessFlags, method);
final MtdInfo mapTo = findDefinedTargetMethod(method.getOwner(), method.getName(), method.getDesc());
if (mapTo != null) {
final Method t = new Method(
method.getOwner(), buildMethodAName(method.getName()), method.getParameterTypes(), method
.getReturnType()
);
final Method src = method;
return new DexMethodNode(accessFlags, method) {
@Override
public void visitEnd() {
super.visitEnd();
DexCodeNode code = this.codeNode;
this.codeNode = null;
accept(dmv);
Op opcode;
if (Modifier.isStatic(access)) {
opcode = Op.INVOKE_STATIC_RANGE;
} else {
opcode = Op.INVOKE_VIRTUAL_RANGE;
}
generateMtdACode(opcode, t, mapTo, dmv, src);
int newAccess = (access & ~(DexConstants.ACC_PRIVATE | DexConstants.ACC_PROTECTED)) | DexConstants.ACC_PUBLIC; // make sure public
code.accept(wrap(superVisitDexMethod(newAccess, t), dcv));
}
};
} else {
return wrap(dmv, dcv);
}
}
private DexMethodVisitor wrap(DexMethodVisitor dmv, final DexClassVisitor classVisitor) {
return dmv == null ? null : new DexMethodVisitor(dmv) {
@Override
public DexCodeVisitor visitCode() {
return wrap(super.visitCode(), classVisitor);
}
};
}
private DexCodeVisitor wrap(DexCodeVisitor dcv, final DexClassVisitor classVisitor) {
return dcv == null ? null : new DexCodeVisitor(dcv) {
@Override
public void visitMethodStmt(Op op, int[] args, Method method) {
MtdInfo mapTo = findTargetMethod(method.getOwner(), method.getName(), method.getDesc());
if (mapTo != null) {
Method methodA = cache.get(buildKey(method.getOwner(), method.getName(), method.getDesc()));
if (methodA == null) {
if (isStatic(op)) {
methodA = new Method(classNameDesc, buildMethodAName(method.getName()), method
.getParameterTypes(), method.getReturnType());
} else {
methodA = new Method(classNameDesc, buildMethodAName(method.getName()), join(method
.getOwner(), method.getParameterTypes()), method.getReturnType());
}
DexMethodVisitor dmv = classVisitor
.visitMethod(DexConstants.ACC_PRIVATE | DexConstants.ACC_STATIC, methodA);
generateMtdACode(op, method, mapTo, dmv, method);
dmv.visitEnd();
cache.put(buildKey(method.getOwner(), method.getName(), method.getDesc()), methodA);
}
super.visitMethodStmt(isRange(op) ? Op.INVOKE_STATIC_RANGE : Op.INVOKE_STATIC, args, methodA);
} else {
super.visitMethodStmt(op, args, method);
}
}
};
}
private void generateMtdACode(Op opcode, Method t, MtdInfo mapTo, DexMethodVisitor dmv, Method src) {
DexCodeVisitor dcv = dmv.visitCode();
int countArge = countArgs(t);
boolean haveThis = haveThis(opcode);
int registers = 4 + (haveThis ? 1 : 0) + countArge;
dcv.visitRegister(registers);
int argStart = 4;
if (haveThis) {
dcv.visitStmt2R(Op.MOVE_OBJECT, 0, argStart);
argStart++;
} else {
dcv.visitConstStmt(Op.CONST_4, 0, 0);
}
if (t.getParameterTypes().length == 0) {
dcv.visitConstStmt(Op.CONST_4, 1, 0);
} else {
dcv.visitConstStmt(Op.CONST, 1, t.getParameterTypes().length);
dcv.visitTypeStmt(Op.NEW_ARRAY, 1, 1, "[Ljava/lang/Object;");
for (int i = 0; i < t.getParameterTypes().length; i++) {
char type = t.getParameterTypes()[i].charAt(0);
dcv.visitConstStmt(Op.CONST, 2, i);
box(type, argStart, 3, dcv);
dcv.visitStmt3R(Op.APUT_OBJECT, 3, 1, 2);
if (type == 'J' || type == 'D') {
argStart += 2;
} else {
argStart += 1;
}
}
}
int nextIdx = callbacks.size();
dcv.visitConstStmt(Op.CONST, 2, nextIdx);
String miTypeDesc = "L" + getCurrentInvocationName() + ";";
dcv.visitTypeStmt(Op.NEW_INSTANCE, 3, 0, miTypeDesc);
dcv.visitMethodStmt(Op.INVOKE_DIRECT, new int[]{3, 0, 1,
2}, new Method(miTypeDesc, "", new String[]{
"Ljava/lang/Object;", "[Ljava/lang/Object;", "I"
}, "V"));
Method call = build(mapTo);
dcv.visitMethodStmt(Op.INVOKE_STATIC, new int[]{3}, call);
if (!"V".equals(t.getReturnType())) {
switch (call.getReturnType().charAt(0)) {
case '[':
case 'L':
dcv.visitStmt1R(Op.MOVE_RESULT_OBJECT, 0);
break;
case 'J':
case 'D':
dcv.visitStmt1R(Op.MOVE_RESULT_WIDE, 0);
break;
default:
dcv.visitStmt1R(Op.MOVE_RESULT, 0);
break;
}
unbox(t.getReturnType(), 0, dcv);
switch (t.getReturnType().charAt(0)) {
case '[':
case 'L':
dcv.visitStmt1R(Op.RETURN_OBJECT, 0);
break;
case 'J':
case 'D':
dcv.visitStmt1R(Op.RETURN_WIDE, 0);
break;
default:
dcv.visitStmt1R(Op.RETURN, 0);
break;
}
} else {
dcv.visitStmt0R(Op.RETURN_VOID);
}
Callback cb = new Callback();
cb.idx = nextIdx;
cb.callback = newMethodCallback(opcode, t);
cb.target = src;
cb.isSpecial = isSuper(opcode);
cb.isStatic = isStatic(opcode);
callbacks.add(cb);
}
private Method newMethodCallback(Op opcode, Method t) {
boolean isStatic = !haveThis(opcode);
boolean isSuper = isSuper(opcode);
Method m;
if (isSuper || isStatic) {
m = new Method(t.getOwner(), buildCallbackMethodName(t.getName()), new String[]{
"[Ljava/lang/Object;"
}, "Ljava/lang/Object;");
} else {
m = new Method(t.getOwner(), buildCallbackMethodName(t.getName()), new String[]{
"Ljava/lang/Object;", "[Ljava/lang/Object;"
}, "Ljava/lang/Object;");
}
DexMethodVisitor dmv = superVisitDexMethod(
DexConstants.ACC_PUBLIC | (isSuper ? 0 : DexConstants.ACC_STATIC), m);
DexCodeVisitor dcv = dmv.visitCode();
int totalRegs;
int argStart;
if (isStatic) {
totalRegs = 1 + countArgs(t) + 1;
argStart = totalRegs - 1;
} else {
totalRegs = 1 + countArgs(t) + 2;
argStart = totalRegs - 2;
}
dcv.visitRegister(totalRegs);
int args[] = new int[countArgs(t) + (isStatic ? 0 : 1)];
int args_index = 0;
int i = 1;
if (!isStatic) {
if (i != argStart) {
dcv.visitStmt2R(Op.MOVE_OBJECT, i, argStart);
}
if(!isSuper) {
dcv.visitTypeStmt(Op.CHECK_CAST, i, -1, t.getOwner());
}
args[args_index++] = i;
i++;
argStart++;
}
String[] parameterTypes = t.getParameterTypes();
for (int i1 = 0; i1 < parameterTypes.length; i1++) {
String argType = parameterTypes[i1];
dcv.visitConstStmt(Op.CONST, 0, i1);
dcv.visitStmt3R(Op.AGET_OBJECT, i, argStart, 0);
unbox(argType, i, dcv);
args[args_index++] = i;
if (argType.charAt(0) == 'J' || argType.charAt(0) == 'D') {
args[args_index++] = i + 1;
i += 2;
} else {
i += 1;
}
}
dcv.visitMethodStmt(opcode, args, t);
if ("V".equals(t.getReturnType())) {
dcv.visitConstStmt(Op.CONST, 0, 0);
} else {
switch (t.getReturnType().charAt(0)) {
case '[':
case 'L':
dcv.visitStmt1R(Op.MOVE_RESULT_OBJECT, 0);
break;
case 'J':
case 'D':
dcv.visitStmt1R(Op.MOVE_RESULT_WIDE, 0);
break;
default:
dcv.visitStmt1R(Op.MOVE_RESULT, 0);
break;
}
box(t.getReturnType().charAt(0), 0, 0, dcv);
}
dcv.visitStmt1R(Op.RETURN_OBJECT, 0);
return m;
}
private DexMethodVisitor superVisitDexMethod(int accessFlags, Method method) {
return super.visitMethod(accessFlags, method);
}
};
}
private String[] join(String a, String[] b) {
String joined[] = new String[b.length + 1];
joined[0] = a;
System.arraycopy(b, 0, joined, 1, b.length);
return joined;
}
private boolean isStatic(Op op) {
return op == Op.INVOKE_STATIC || op == Op.INVOKE_STATIC_RANGE;
}
private boolean isRange(Op op) {
switch (op) {
case INVOKE_STATIC_RANGE:
case INVOKE_DIRECT_RANGE:
case INVOKE_INTERFACE_RANGE:
case INVOKE_SUPER_RANGE:
case INVOKE_VIRTUAL_RANGE:
return true;
default:
return false;
}
}
private void unbox(String argType, int i, DexCodeVisitor dcv) {
switch (argType.charAt(0)) {
case '[':
case 'L':
dcv.visitTypeStmt(Op.CHECK_CAST, i, i, argType);
break;
case 'Z':
dcv.visitTypeStmt(Op.CHECK_CAST, i, i, "Ljava/lang/Boolean;");
dcv.visitMethodStmt(Op.INVOKE_VIRTUAL_RANGE, new int[]{
i}, new Method("Ljava/lang/Boolean;", "booleanValue", new String[]{}, "Z"));
dcv.visitStmt1R(Op.MOVE_RESULT, i);
break;
case 'B':
dcv.visitTypeStmt(Op.CHECK_CAST, i, i, "Ljava/lang/Byte;");
dcv.visitMethodStmt(Op.INVOKE_VIRTUAL_RANGE, new int[]{
i}, new Method("Ljava/lang/Byte;", "byteValue", new String[]{}, "B"));
dcv.visitStmt1R(Op.MOVE_RESULT, i);
break;
case 'S':
dcv.visitTypeStmt(Op.CHECK_CAST, i, i, "Ljava/lang/Short;");
dcv.visitMethodStmt(Op.INVOKE_VIRTUAL_RANGE, new int[]{
i}, new Method("Ljava/lang/Short;", "shortValue", new String[]{}, "S"));
dcv.visitStmt1R(Op.MOVE_RESULT, i);
break;
case 'C':
dcv.visitTypeStmt(Op.CHECK_CAST, i, i, "Ljava/lang/Character;");
dcv.visitMethodStmt(Op.INVOKE_VIRTUAL_RANGE, new int[]{
i}, new Method("Ljava/lang/Character;", "charValue", new String[]{}, "C"));
dcv.visitStmt1R(Op.MOVE_RESULT, i);
break;
case 'I':
dcv.visitTypeStmt(Op.CHECK_CAST, i, i, "Ljava/lang/Integer;");
dcv.visitMethodStmt(Op.INVOKE_VIRTUAL_RANGE, new int[]{
i}, new Method("Ljava/lang/Integer;", "intValue", new String[]{}, "I"));
dcv.visitStmt1R(Op.MOVE_RESULT, i);
break;
case 'F':
dcv.visitTypeStmt(Op.CHECK_CAST, i, i, "Ljava/lang/Float;");
dcv.visitMethodStmt(Op.INVOKE_VIRTUAL_RANGE, new int[]{
i}, new Method("Ljava/lang/Float;", "floatValue", new String[]{}, "F"));
dcv.visitStmt1R(Op.MOVE_RESULT, i);
break;
case 'D':
dcv.visitTypeStmt(Op.CHECK_CAST, i, i, "Ljava/lang/Double;");
dcv.visitMethodStmt(Op.INVOKE_VIRTUAL_RANGE, new int[]{
i}, new Method("Ljava/lang/Double;", "doubleValue", new String[]{}, "D"));
dcv.visitStmt1R(Op.MOVE_RESULT_WIDE, i);
break;
case 'J':
dcv.visitTypeStmt(Op.CHECK_CAST, i, i, "Ljava/lang/Long;");
dcv.visitMethodStmt(Op.INVOKE_VIRTUAL_RANGE, new int[]{
i}, new Method("Ljava/lang/Long;", "longValue", new String[]{}, "J"));
dcv.visitStmt1R(Op.MOVE_RESULT_WIDE, i);
break;
}
}
private boolean isSuper(Op opcode) {
return opcode == Op.INVOKE_SUPER || opcode == Op.INVOKE_SUPER_RANGE;
}
private Method build(MtdInfo mapTo) {
Type[] ts = Type.getArgumentTypes(mapTo.desc);
String ss[] = new String[ts.length];
for (int i = 0; i < ss.length; i++) {
ss[i] = ts[i].getDescriptor();
}
return new Method(mapTo.owner, mapTo.name, ss, Type.getReturnType(mapTo.desc).getDescriptor());
}
private void box(char type, int from, int to, DexCodeVisitor dcv) {
switch (type) {
case 'L':
case '[':
dcv.visitStmt2R(Op.MOVE_OBJECT, from, to);
break;
case 'Z':
dcv.visitMethodStmt(Op.INVOKE_STATIC_RANGE, new int[]{
from}, new Method("Ljava/lang/Boolean;", "valueOf", new String[]{"Z"}, "Ljava/lang/Boolean;"));
dcv.visitStmt1R(Op.MOVE_RESULT_OBJECT, to);
break;
case 'B':
dcv.visitMethodStmt(Op.INVOKE_STATIC_RANGE, new int[]{
from}, new Method("Ljava/lang/Byte;", "valueOf", new String[]{"B"}, "Ljava/lang/Byte;"));
dcv.visitStmt1R(Op.MOVE_RESULT_OBJECT, to);
break;
case 'S':
dcv.visitMethodStmt(Op.INVOKE_STATIC_RANGE, new int[]{
from}, new Method("Ljava/lang/Short;", "valueOf", new String[]{"S"}, "Ljava/lang/Short;"));
dcv.visitStmt1R(Op.MOVE_RESULT_OBJECT, to);
break;
case 'C':
dcv.visitMethodStmt(Op.INVOKE_STATIC_RANGE, new int[]{
from}, new Method("Ljava/lang/Character;", "valueOf", new String[]{
"C"}, "Ljava/lang/Character;"));
dcv.visitStmt1R(Op.MOVE_RESULT_OBJECT, to);
break;
case 'I':
dcv.visitMethodStmt(Op.INVOKE_STATIC_RANGE, new int[]{
from}, new Method("Ljava/lang/Integer;", "valueOf", new String[]{"I"}, "Ljava/lang/Integer;"));
dcv.visitStmt1R(Op.MOVE_RESULT_OBJECT, to);
break;
case 'F':
dcv.visitMethodStmt(Op.INVOKE_STATIC_RANGE, new int[]{
from}, new Method("Ljava/lang/Float;", "valueOf", new String[]{"F"}, "Ljava/lang/Float;"));
dcv.visitStmt1R(Op.MOVE_RESULT_OBJECT, to);
break;
case 'D':
dcv.visitMethodStmt(Op.INVOKE_STATIC_RANGE, new int[]{
from, from + 1}, new Method("Ljava/lang/Double;", "valueOf", new String[]{
"D"}, "Ljava/lang/Double;"));
dcv.visitStmt1R(Op.MOVE_RESULT_OBJECT, to);
break;
case 'J':
dcv.visitMethodStmt(Op.INVOKE_STATIC_RANGE, new int[]{
from, from + 1}, new Method("Ljava/lang/Long;", "valueOf", new String[]{
"J"}, "Ljava/lang/Long;"));
dcv.visitStmt1R(Op.MOVE_RESULT_OBJECT, to);
break;
}
}
private boolean haveThis(Op opcode) {
return opcode != Op.INVOKE_STATIC && opcode != Op.INVOKE_STATIC_RANGE;
}
static int countArgs(Method t) {
int i = 0;
for (String arg : t.getParameterTypes()) {
char type = arg.charAt(0);
if (type == 'J' || type == 'D') {
i += 2;
} else {
i += 1;
}
}
return i;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy