com.googlecode.d2j.tools.jar.DexWeaver Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of gradle Show documentation
Show all versions of gradle Show documentation
fakeradnroid gradle builder
/*
* 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;
}
}