List of usage examples for org.objectweb.asm Type getSize
public int getSize()
From source file:br.usp.each.saeg.badua.core.internal.instr.InstrSupport.java
License:Open Source License
public static void swap(final MethodVisitor mv, final Type stackTop, final Type belowTop) { if (stackTop.getSize() == 1) { if (belowTop.getSize() == 1) { // Top = 1, below = 1 mv.visitInsn(Opcodes.SWAP);//from ww w . ja v a2 s.c o m } else { // Top = 1, below = 2 mv.visitInsn(Opcodes.DUP_X2); mv.visitInsn(Opcodes.POP); } } else { if (belowTop.getSize() == 1) { // Top = 2, below = 1 mv.visitInsn(Opcodes.DUP2_X1); } else { // Top = 2, below = 2 mv.visitInsn(Opcodes.DUP2_X2); } mv.visitInsn(Opcodes.POP2); } }
From source file:ch.eiafr.cojac.FloatVariablesSorter.java
License:Apache License
public FloatVariablesSorter(int access, String oldDesc, AnalyzerAdapter mv) { super(Opcodes.ASM5, mv); Type[] args = Type.getArgumentTypes(oldDesc); firstFrameMapping = new int[1 + args.length * 2]; // +1 for 'this' Arrays.fill(firstFrameMapping, -1); // so that erroneously using unwritten cells will cause problems... boolean hasTarget = (Opcodes.ACC_STATIC & access) == 0; // not static -> there is a 'this' param int oldVarIndex = 0; int newVarIndex = 0; int lastIndexSet = -1; if (hasTarget) { oldVarIndex = newVarIndex = 1;// w w w.j a va 2 s .com firstFrameMapping[0] = 0; // 'this' remains 'this' after remapping... lastIndexSet = 0; } for (Type arg : args) { firstFrameMapping[oldVarIndex] = newVarIndex; lastIndexSet = oldVarIndex; oldVarIndex += arg.getSize(); newVarIndex += arg.getSize(); if (arg.equals(Type.DOUBLE_TYPE)) { newVarIndex--; } assert !arg.equals(COJAC_DOUBLE_WRAPPER_TYPE); // this would be strange (the descriptor is the old one) } maxRenumber = lastIndexSet; }
From source file:ch.eiafr.cojac.instrumenters.FloatProxyMethod.java
License:Apache License
public void nativeCall(MethodVisitor mv, int access, String owner, String name, String desc) { boolean isStatic = (access & ACC_STATIC) > 0; String newDesc = replaceFloatMethodDescription(desc); MethodVisitor newMv = ccv.addProxyMethod(access & ~ACC_NATIVE, name, newDesc, null, null); int varIndex = 0; int opcode = INVOKESTATIC; if (!isStatic) { newMv.visitVarInsn(ALOAD, 0);/* w ww . ja va 2s . c o m*/ varIndex = 1; opcode = INVOKEVIRTUAL; } ConversionContext cc = new ConversionContext(opcode, owner, name, desc); Type args[] = Type.getArgumentTypes(newDesc); for (Type type : args) { newMv.visitVarInsn(getLoadOpcode(type), varIndex); varIndex += type.getSize(); } convertArgumentsToReal(mv, cc); // stack >> [target] allParamsArr [target] allParamsArr maybeConvertTarget(mv, cc.opcode, cc.owner); // stack >> [target] allParamsArr [newTarget] allParamsArr explodeOnStack(mv, cc, true); // stack >> [target] allParamsArr [newTarget] nprm0 nprm1 nprm2... newMv.visitMethodInsn(opcode, owner, name, desc, false); // stack >> [target] allParamsArr [possibleResult] checkArraysAfterCall(newMv, cc.convertedArrays, desc); // stack >> [target] [possibleResult] convertReturnType(newMv, desc); // stack >> [target] [newPossibleResult] newMv.visitInsn(afterFloatReplacement(Type.getReturnType(desc)).getOpcode(IRETURN)); // stack >> [target] // left on the stack... not a problem! newMv.visitMaxs(0, 0); }
From source file:ch.eiafr.cojac.instrumenters.FloatProxyMethod.java
License:Apache License
private static void explodeOnStack(MethodVisitor mv, ConversionContext cc, boolean wantTheConversion) { Type[] args = wantTheConversion ? cc.outArgs : cc.inArgs; // stack >> ... allParamsArr for (int i = 0; i < args.length; i++) { // stack >> ... allParamsArr Type oa = args[i]; int oaSort = oa.getSort(); mv.visitInsn(DUP);/*from ww w. j a v a 2 s . c om*/ mv.visitLdcInsn(i); mv.visitInsn(AALOAD); boolean keepBothVersions = (oa.getSort() == Type.ARRAY); if (keepBothVersions) { mv.visitTypeInsn(CHECKCAST, "[" + OBJ_TYPE.getDescriptor()); mv.visitLdcInsn(wantTheConversion ? 1 : 0); mv.visitInsn(AALOAD); } if (oaSort == Type.ARRAY || oaSort == Type.OBJECT) { // else: primitive type mv.visitTypeInsn(CHECKCAST, oa.getInternalName()); } else { String jWrapperName = getJWrapper(oa).getInternalName(); mv.visitTypeInsn(CHECKCAST, jWrapperName); mv.visitMethodInsn(INVOKEVIRTUAL, jWrapperName, getWrapperToPrimitiveMethod(oa), "()" + oa.getDescriptor(), false); } if (oa.getSize() == 2) { // Object DD Swap when double or long mv.visitInsn(DUP2_X1); // DD Object DD mv.visitInsn(POP2); // DD Object } else { mv.visitInsn(SWAP); } // stack >> ... nprmI allParamsArr } mv.visitInsn(POP); // stack >> ... nprm0 nprm1 nprm2... }
From source file:ch.eiafr.cojac.instrumenters.FloatProxyMethod.java
License:Apache License
private static void checkArraysAfterCall(MethodVisitor mv, Map<Integer, Type> convertedArrays, String desc) { // stack >> allParamsArr [possibleResult] Type returnType = Type.getReturnType(desc); int returnTypeSize = returnType.getSize(); if (returnTypeSize == 1) { mv.visitInsn(SWAP);//from ww w . j a v a2s . c om } else if (returnTypeSize == 2) { // mv.visitInsn(NOP); just a marker as a debugging helper mv.visitInsn(DUP2_X1); // D D Object D D mv.visitInsn(POP2); // D D Object } // stack >> [possibleResult] allParamsArr for (int pos : convertedArrays.keySet()) { // Type type = convertedArrays.get(pos); mv.visitInsn(DUP); // stack >> [possibleResult] allParamsArr allParamsArr mv.visitLdcInsn(pos); // stack >> [possibleResult] allParamsArr allParamsArr i mv.visitInsn(AALOAD); // stack >> [possibleResult] allParamsArr allParamsArr[i] mv.visitTypeInsn(CHECKCAST, "[" + OBJ_TYPE.getDescriptor()); // stack >> [possibleResult] allParamsArr allParamsArr[i] (of type Object[]) mv.visitInsn(DUP); // stack >> [possibleResult] allParamsArr allParamsArr[i] allParamsArr[i] mv.visitLdcInsn(0); // stack >> [possibleResult] allParamsArr allParamsArr[i] allParamsArr[i] 0 mv.visitInsn(AALOAD); // stack >> [possibleResult] allParamsArr allParamsArr[i] allParamsArr[i][0] mv.visitInsn(SWAP); // stack >> [possibleResult] allParamsArr allParamsArr[i][0] allParamsArr[i] mv.visitLdcInsn(1); // stack >> [possibleResult] allParamsArr allParamsArr[i][0] allParamsArr[i] 1 mv.visitInsn(AALOAD); // stack >> [possibleResult] allParamsArr allParamsArr[i][0] allParamsArr[i][1] // mergeOriginalArrayIntoCojac mv.visitMethodInsn(INVOKESTATIC, DN_NAME, "mergeOriginalArrayIntoCojac", "(" + OBJ_DESC + OBJ_DESC + ")V", false); // stack >> [possibleResult] allParamsArr } // stack >> [possibleResult] allParamsArr mv.visitInsn(POP); // stack >> [possibleResult] }
From source file:com.android.build.gradle.internal.incremental.ByteCodeUtils.java
License:Apache License
/** * Converts Types to LocalVariables, assuming they start from variable 0. *//* ww w . j a v a 2 s . c om*/ static List<LocalVariable> toLocalVariables(@NonNull List<Type> types) { List<LocalVariable> variables = Lists.newArrayList(); int stack = 0; for (int i = 0; i < types.size(); i++) { Type type = types.get(i); variables.add(new LocalVariable(type, stack)); stack += type.getSize(); } return variables; }
From source file:com.android.build.gradle.internal.incremental.ConstructorArgsRedirection.java
License:Apache License
@Override protected void restore(GeneratorAdapter mv, List<Type> args) { // At this point, init$args has been called and the result Object is on the stack. // The value of that Object is Object[] with exactly n + 1 elements. // The first element is a string with the qualified name of the constructor to call. // The remaining elements are the constructtor arguments. // Create a new local that holds the result of init$args call. mv.visitTypeInsn(Opcodes.CHECKCAST, "[Ljava/lang/Object;"); int constructorArgs = mv.newLocal(Type.getType("[Ljava/lang/Object;")); mv.storeLocal(constructorArgs);//from w w w.j a va2 s. c om // Reinstate local values mv.loadLocal(locals); int stackIndex = 0; for (int arrayIndex = 0; arrayIndex < args.size(); arrayIndex++) { Type arg = args.get(arrayIndex); // Do not restore "this" if (arrayIndex > 0) { // duplicates the array mv.dup(); // index in the array of objects to restore the boxed parameter. mv.push(arrayIndex); // get it from the array mv.arrayLoad(Type.getType(Object.class)); // unbox the argument ByteCodeUtils.unbox(mv, arg); // restore the argument mv.visitVarInsn(arg.getOpcode(Opcodes.ISTORE), stackIndex); } // stack index must progress according to the parameter type we just processed. stackIndex += arg.getSize(); } // pops the array mv.pop(); // Push a null for the marker parameter. mv.loadLocal(constructorArgs); mv.visitInsn(Opcodes.ACONST_NULL); // Invoke the constructor mv.visitMethodInsn(Opcodes.INVOKESPECIAL, thisClassName, "<init>", DISPATCHING_THIS_SIGNATURE, false); mv.goTo(end.getLabel()); }
From source file:com.android.build.gradle.internal.incremental.ConstructorBuilder.java
License:Apache License
/** * Deconstruct a constructor into its components and adds the necessary code to link the components * later. This code is not valid java, but it can be expressed in bytecode. In essence for this constructor: * <pre>{@code/*from ww w .j a va 2 s.co m*/ * <init>(int x) { * int a = 2; * super(int b = 3, x = 1, expr2() ? 3 : a++) * doSomething(x + a) * } * }</pre> * it creates two parts: * <pre>{@code * Object[] init$args(Clazz this, int x, Object[] locals) { // this is always null here * int a = locals[0]; * int b = 3; * Object[] args = new Object[3]; * args[0] = b; * args[1] = (x = 1) * args[2] = expr2() ? 3 : a++; * locals = new Object[3]; // The arguments + the locals * locals[0] = NULL; * locals[1] = x; * locals[2] = new Object[2]; * locals[2][0] = a; * locals[2][1] = b; * return new Object[] {locals, "myclass.<init>(I;I;)V", args}; * } * * void init$body(int x, Object[] locals) { * int a = locals[0]; * int b = locals[1]; * doSomething(x + a); * } * }</pre> * * @param owner the owning class. * @param method the constructor method. */ @NonNull public static Constructor build(@NonNull String owner, @NonNull MethodNode method) { // Basic interpreter uses BasicValue.REFERENCE_VALUE for all object types. However // we need to distinguish one in particular. The value of the local variable 0, ie. the // uninitialized this. By doing it this way we ensure that whenever there is a ALOAD_0 // a LocalValue instance will be on the stack. BasicInterpreter interpreter = new BasicInterpreter() { boolean done = false; @Override // newValue is called first to initialize the frame values of all the local variables // we intercept the first one to create our own special value. public BasicValue newValue(Type type) { if (type == null) { return BasicValue.UNINITIALIZED_VALUE; } else if (type.getSort() == Type.VOID) { return null; } else { // If this is the first value created (i.e. the first local variable) // we use a special marker. BasicValue ret = done ? super.newValue(type) : new LocalValue(type); done = true; return ret; } } }; Analyzer analyzer = new Analyzer(interpreter); AbstractInsnNode[] instructions = method.instructions.toArray(); try { Frame[] frames = analyzer.analyze(owner, method); if (frames.length != instructions.length) { // Should never happen. throw new IllegalStateException("The number of frames is not equals to the number of instructions"); } int stackAtThis = -1; boolean poppedThis = false; int firstLocal = 1; for (Type type : Type.getArgumentTypes(method.desc)) { firstLocal += type.getSize(); } LinkedHashSet<LocalVariable> variables = new LinkedHashSet<LocalVariable>(); VarInsnNode lastThis = null; int localsAtLastThis = 0; // Records the most recent line number encountered. For javac, there should always be // a line number node before the call of interest to this(...) or super(...). For robustness, // -1 is recorded as a sentinel to indicate this assumption didn't hold. Upstream consumers // should check for -1 and recover in a reasonable way (for example, don't set the line // number in generated code). int recentLine = -1; for (int i = 0; i < instructions.length; i++) { AbstractInsnNode insn = instructions[i]; Frame frame = frames[i]; if (frame.getStackSize() < stackAtThis) { poppedThis = true; } if (insn instanceof MethodInsnNode) { // TODO: Do we need to check that the stack is empty after this super call? MethodInsnNode methodhInsn = (MethodInsnNode) insn; Type[] types = Type.getArgumentTypes(methodhInsn.desc); Value value = frame.getStack(frame.getStackSize() - types.length - 1); if (value instanceof LocalValue && methodhInsn.name.equals("<init>")) { if (poppedThis) { throw new IllegalStateException("Unexpected constructor structure."); } return split(owner, method, lastThis, methodhInsn, recentLine, new ArrayList<LocalVariable>(variables), localsAtLastThis); } } else if (insn instanceof VarInsnNode) { VarInsnNode var = (VarInsnNode) insn; if (var.var == 0) { lastThis = var; localsAtLastThis = variables.size(); stackAtThis = frame.getStackSize(); poppedThis = false; } Type type = ByteCodeUtils.getTypeForStoreOpcode(var.getOpcode()); if (type != null && var.var >= firstLocal) { // Variables are equals based on their number, so they will be added // to the set only if they are new, and in the order they are seen. variables.add(new LocalVariable(type, var.var)); } } else if (insn instanceof LineNumberNode) { // Record the most recent line number encountered so that call to this(...) // or super(...) has line number information. Ultimately used to emit a line // number in the generated code. LineNumberNode lineNumberNode = (LineNumberNode) insn; recentLine = lineNumberNode.line; } } throw new IllegalStateException("Unexpected constructor structure."); } catch (AnalyzerException e) { throw new IllegalStateException(e); } }
From source file:com.android.build.gradle.internal.incremental.ConstructorDelegationDetector.java
License:Apache License
/** * Splits the constructor in two methods, the "set up" and the "body" parts (see above). *///from w w w . j ava2 s .c o m @NonNull private static Constructor split(@NonNull String owner, @NonNull MethodNode method, @NonNull VarInsnNode loadThis, @NonNull MethodInsnNode delegation, int loadThisLine) { String[] exceptions = ((List<String>) method.exceptions).toArray(new String[method.exceptions.size()]); String newDesc = method.desc.replaceAll("\\((.*)\\)V", "([Ljava/lang/Object;$1)Ljava/lang/Object;"); MethodNode initArgs = new MethodNode(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, "init$args", newDesc, null, exceptions); AbstractInsnNode insn = loadThis.getNext(); while (insn != delegation) { insn.accept(initArgs); insn = insn.getNext(); } LabelNode labelBefore = new LabelNode(); labelBefore.accept(initArgs); GeneratorAdapter mv = new GeneratorAdapter(initArgs, initArgs.access, initArgs.name, initArgs.desc); // Copy the arguments back to the argument array // The init_args part cannot access the "this" object and can have side effects on the // local variables. Because of this we use the first argument (which we want to keep // so all the other arguments remain unchanged) as a reference to the array where to // return the values of the modified local variables. Type[] types = Type.getArgumentTypes(initArgs.desc); int stack = 1; // Skip the first one which is a reference to the local array. for (int i = 1; i < types.length; i++) { Type type = types[i]; // This is not this, but the array of local arguments final values. mv.visitVarInsn(Opcodes.ALOAD, 0); mv.push(i); mv.visitVarInsn(type.getOpcode(Opcodes.ILOAD), stack); mv.box(type); mv.arrayStore(Type.getType(Object.class)); stack += type.getSize(); } // Create the args array with the values to send to the delegated constructor Type[] returnTypes = Type.getArgumentTypes(delegation.desc); // The extra element for the qualified name of the constructor. mv.push(returnTypes.length + 1); mv.newArray(Type.getType(Object.class)); int args = mv.newLocal(Type.getType("[Ljava/lang/Object;")); mv.storeLocal(args); for (int i = returnTypes.length - 1; i >= 0; i--) { Type type = returnTypes[i]; mv.loadLocal(args); mv.swap(type, Type.getType(Object.class)); mv.push(i + 1); mv.swap(type, Type.INT_TYPE); mv.box(type); mv.arrayStore(Type.getType(Object.class)); } // Store the qualified name of the constructor in the first element of the array. mv.loadLocal(args); mv.push(0); mv.push(delegation.owner + "." + delegation.desc); // Name of the constructor to be called. mv.arrayStore(Type.getType(Object.class)); mv.loadLocal(args); mv.returnValue(); newDesc = method.desc.replace("(", "(L" + owner + ";"); MethodNode body = new MethodNode(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, "init$body", newDesc, null, exceptions); LabelNode labelAfter = new LabelNode(); labelAfter.accept(body); Set<LabelNode> bodyLabels = new HashSet<LabelNode>(); insn = delegation.getNext(); while (insn != null) { if (insn instanceof LabelNode) { bodyLabels.add((LabelNode) insn); } insn.accept(body); insn = insn.getNext(); } // manually transfer the exception table from the existing constructor to the new // "init$body" method. The labels were transferred just above so we can reuse them. //noinspection unchecked for (TryCatchBlockNode tryCatch : (List<TryCatchBlockNode>) method.tryCatchBlocks) { tryCatch.accept(body); } //noinspection unchecked for (LocalVariableNode variable : (List<LocalVariableNode>) method.localVariables) { boolean startsInBody = bodyLabels.contains(variable.start); boolean endsInBody = bodyLabels.contains(variable.end); if (!startsInBody && !endsInBody) { if (variable.index != 0) { // '#0' on init$args is not 'this' variable.accept(initArgs); } } else if (startsInBody && endsInBody) { variable.accept(body); } else if (!startsInBody && endsInBody) { // The variable spans from the args to the end of the method, create two: if (variable.index != 0) { // '#0' on init$args is not 'this' LocalVariableNode var0 = new LocalVariableNode(variable.name, variable.desc, variable.signature, variable.start, labelBefore, variable.index); var0.accept(initArgs); } LocalVariableNode var1 = new LocalVariableNode(variable.name, variable.desc, variable.signature, labelAfter, variable.end, variable.index); var1.accept(body); } else { throw new IllegalStateException("Local variable starts after it ends."); } } return new Constructor(loadThis, loadThisLine, initArgs, delegation, body); }
From source file:com.android.build.gradle.internal2.incremental.ConstructorBuilder.java
License:Apache License
/** * Deconstruct a constructor into its components and adds the necessary code to link the components * later. This code is not valid java, but it can be expressed in bytecode. In essence for this constructor: * <pre>{@code/*from www .ja v a 2 s . com*/ * <init>(int x) { * int a = 2; * super(int b = 3, x = 1, expr2() ? 3 : a++) * doSomething(x + a) * } * }</pre> * it creates two parts: * <pre>{@code * Object[] init$args(Clazz this, int x, Object[] locals) { // this is always null here * int a = locals[0]; * int b = 3; * Object[] args = new Object[3]; * args[0] = b; * args[1] = (x = 1) * args[2] = expr2() ? 3 : a++; * locals = new Object[3]; // The arguments + the locals * locals[0] = NULL; * locals[1] = x; * locals[2] = new Object[2]; * locals[2][0] = a; * locals[2][1] = b; * return new Object[] {locals, "myclass.<init>(I;I;)V", args}; * } * * void init$body(int x, Object[] locals) { * int a = locals[0]; * int b = locals[1]; * doSomething(x + a); * } * }</pre> * * @param owner the owning class. * @param method the constructor method. */ @NonNull public static Constructor build(@NonNull String owner, @NonNull MethodNode method) { // Basic interpreter uses BasicValue.REFERENCE_VALUE for all object types. However // we need to distinguish one in particular. The value of the local variable 0, ie. the // uninitialized this. By doing it this way we ensure that whenever there is a ALOAD_0 // a LocalValue instance will be on the stack. BasicInterpreter interpreter = new BasicInterpreter() { boolean done = false; @Override // newValue is called first to initialize the frame values of all the local variables // we intercept the first one to create our own special value. public BasicValue newValue(Type type) { if (type == null) { return BasicValue.UNINITIALIZED_VALUE; } else if (type.getSort() == Type.VOID) { return null; } else { // If this is the first value created (i.e. the first local variable) // we use a special marker. BasicValue ret = done ? super.newValue(type) : new LocalValue(type); done = true; return ret; } } }; Analyzer analyzer = new Analyzer(interpreter); AbstractInsnNode[] instructions = method.instructions.toArray(); try { Frame[] frames = analyzer.analyze(owner, method); if (frames.length != instructions.length) { // Should never happen. throw new IllegalStateException("The number of frames is not equals to the number of instructions"); } int stackAtThis = -1; boolean poppedThis = false; int firstLocal = 1; for (Type type : Type.getArgumentTypes(method.desc)) { firstLocal += type.getSize(); } LinkedHashSet<LocalVariable> variables = new LinkedHashSet<LocalVariable>(); VarInsnNode lastThis = null; int localsAtLastThis = 0; // Records the most recent line number encountered. For javac, there should always be // a line number node before the call of interest to this(...) or super(...). For robustness, // -1 is recorded as a sentinel to indicate this assumption didn't hold. Upstream consumers // should check for -1 and recover in a reasonable way (for example, don't set the line // number in generated code). int recentLine = -1; for (int i = 0; i < instructions.length; i++) { AbstractInsnNode insn = instructions[i]; Frame frame = frames[i]; if (frame.getStackSize() < stackAtThis) { poppedThis = true; } if (insn instanceof MethodInsnNode) { // TODO: Do we need to check that the stack is empty after this super call? MethodInsnNode methodhInsn = (MethodInsnNode) insn; Type[] types = Type.getArgumentTypes(methodhInsn.desc); Value value = frame.getStack(frame.getStackSize() - types.length - 1); if (value instanceof LocalValue && methodhInsn.name.equals(ByteCodeUtils.CONSTRUCTOR)) { if (poppedThis) { throw new IllegalStateException("Unexpected constructor structure."); } return split(owner, method, lastThis, methodhInsn, recentLine, new ArrayList<LocalVariable>(variables), localsAtLastThis); } } else if (insn instanceof VarInsnNode) { VarInsnNode var = (VarInsnNode) insn; if (var.var == 0) { lastThis = var; localsAtLastThis = variables.size(); stackAtThis = frame.getStackSize(); poppedThis = false; } Type type = ByteCodeUtils.getTypeForStoreOpcode(var.getOpcode()); if (type != null && var.var >= firstLocal) { // Variables are equals based on their number, so they will be added // to the set only if they are new, and in the order they are seen. variables.add(new LocalVariable(type, var.var)); } } else if (insn instanceof LineNumberNode) { // Record the most recent line number encountered so that call to this(...) // or super(...) has line number information. Ultimately used to emit a line // number in the generated code. LineNumberNode lineNumberNode = (LineNumberNode) insn; recentLine = lineNumberNode.line; } } throw new IllegalStateException("Unexpected constructor structure."); } catch (AnalyzerException e) { throw new IllegalStateException(e); } }