List of usage examples for org.objectweb.asm Type VOID
int VOID
To view the source code for org.objectweb.asm Type VOID.
Click Source Link
From source file:ch.eiafr.cojac.instrumenters.FloatProxyMethod.java
License:Apache License
private Object[] addReturnTypeTo(Object[] stackContent, Type returnType) { int sort = returnType.getSort(); if (sort == Type.VOID) return stackContent; if (sort == Type.ARRAY || sort == Type.OBJECT) return addTo(stackContent, returnType.getInternalName()); // else primitive type switch (sort) { case Type.BOOLEAN: case Type.BYTE: case Type.CHAR: case Type.SHORT: case Type.INT: return addTo(stackContent, Opcodes.INTEGER); case Type.LONG: return addTo(stackContent, Opcodes.LONG); //return addTo(addTo(stackContent, Opcodes.LONG), Opcodes.TOP); }//from www. j a va2 s . co m return stackContent; }
From source file:cl.inria.stiq.db.structure.impl.StructureDatabase.java
License:Open Source License
public static ITypeInfo getType(IMutableStructureDatabase aStructureDatabase, String aName, boolean aCreateIfAbsent, boolean aFailIfAbsent) { aName = transformClassName(aName);/*w w w . java 2s. c o m*/ Type theType = Type.getType(aName); switch (theType.getSort()) { case Type.OBJECT: { String theClassName = theType.getClassName(); return aCreateIfAbsent ? aStructureDatabase.getNewClass(theClassName) : aStructureDatabase.getClass(theClassName, aFailIfAbsent); } case Type.ARRAY: { ITypeInfo theElementType = getType(aStructureDatabase, theType.getElementType().getDescriptor(), aCreateIfAbsent, aFailIfAbsent); int theDimensions = theType.getDimensions(); return new ArrayTypeInfo(null, // That should be safe... if there is a problem we'll see what we do theElementType, theDimensions); } case Type.VOID: return PrimitiveTypeInfo.VOID; case Type.BOOLEAN: return PrimitiveTypeInfo.BOOLEAN; case Type.BYTE: return PrimitiveTypeInfo.BYTE; case Type.CHAR: return PrimitiveTypeInfo.CHAR; case Type.DOUBLE: return PrimitiveTypeInfo.DOUBLE; case Type.FLOAT: return PrimitiveTypeInfo.FLOAT; case Type.INT: return PrimitiveTypeInfo.INT; case Type.LONG: return PrimitiveTypeInfo.LONG; case Type.SHORT: return PrimitiveTypeInfo.SHORT; default: // This is not a "normal" failure, so always throw exception throw new RuntimeException("Not handled: " + theType); } }
From source file:cl.inria.stiq.instrumenter.BCIUtils.java
License:Open Source License
/** * Returns the sort of data (as defined by {@link Type} that correponds to * the given opcode.//w w w . ja v a 2 s. co m */ public static int getSort(int aOpcode) { switch (aOpcode) { case AALOAD: case AASTORE: case ACONST_NULL: case ALOAD: case ANEWARRAY: case ARETURN: case ASTORE: case IF_ACMPEQ: case IF_ACMPNE: return Type.OBJECT; case BALOAD: case BASTORE: return Type.BYTE; case CALOAD: case CASTORE: return Type.CHAR; case DADD: case DALOAD: case DASTORE: case DCMPG: case DCMPL: case DCONST_0: case DCONST_1: case DDIV: case DLOAD: case DMUL: case DNEG: case DREM: case DRETURN: case DSTORE: case DSUB: return Type.DOUBLE; case FADD: case FALOAD: case FASTORE: case FCMPG: case FCMPL: case FCONST_0: case FCONST_1: case FCONST_2: case FDIV: case FLOAD: case FMUL: case FNEG: case FREM: case FRETURN: case FSTORE: case FSUB: return Type.FLOAT; case BIPUSH: case IADD: case IALOAD: case IAND: case IASTORE: case ICONST_0: case ICONST_1: case ICONST_2: case ICONST_3: case ICONST_4: case ICONST_5: case ICONST_M1: case IDIV: case IF_ICMPEQ: case IF_ICMPGE: case IF_ICMPGT: case IF_ICMPLE: case IF_ICMPLT: case IF_ICMPNE: case IINC: case ILOAD: case IMUL: case INEG: case IOR: case IREM: case IRETURN: case ISHL: case ISHR: case ISTORE: case ISUB: case IUSHR: case IXOR: return Type.INT; case LADD: case LALOAD: case LAND: case LASTORE: case LCMP: case LCONST_0: case LCONST_1: case LDIV: case LLOAD: case LMUL: case LNEG: case LOR: case LREM: case LRETURN: case LSHL: case LSHR: case LSTORE: case LSUB: case LUSHR: case LXOR: return Type.LONG; case SALOAD: case SASTORE: case SIPUSH: return Type.SHORT; case RETURN: return Type.VOID; default: return -1; } }
From source file:cl.inria.stiq.instrumenter.BCIUtils.java
License:Open Source License
/** * Returns a one-character descriptor for the given type. These are the classical * JVM descriptor characters, with just L for reference types. *///w w w . j a v a 2 s .co m public static char getCompleteSigForSort(int aSort) { switch (aSort) { case Type.ARRAY: case Type.OBJECT: return 'L'; case Type.BOOLEAN: return 'Z'; case Type.BYTE: return 'B'; case Type.CHAR: return 'C'; case Type.INT: return 'I'; case Type.SHORT: return 'S'; case Type.DOUBLE: return 'D'; case Type.FLOAT: return 'F'; case Type.LONG: return 'J'; case Type.VOID: return 'V'; default: throw new RuntimeException("Not handled: " + aSort); } }
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 w w w. j av a 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
/** * Deconstruct a constructor into its components and adds the necessary code to link the components * later. The generated bytecode does not correspond exactly to this code, but in essence, for * a constructor of this form:/*from w w w. j ava 2 s . c om*/ * <p/> * <code> * <init>(int x) { * super(x = 1, expr2() ? 3 : 7) * doSomething(x) * } * </code> * <p/> * it creates the two parts: * <code> * Object[] init$args(Object[] locals, int x) { * Object[] args = new Object[2]; * args[0] = (x = 1) * args[1] = expr2() ? 3 : 7; * locals[0] = x; * return new Object[] {"myclass.<init>(I;I;)V", args}; * } * * void init$body(int x) { * doSomething(x); * } * </code> * * @param owner the owning class. * @param method the constructor method. */ @NonNull public static Constructor deconstruct(@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"); } VarInsnNode lastThis = null; int stackAtThis = -1; boolean poppedThis = false; // 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); } } else if (insn instanceof VarInsnNode) { VarInsnNode var = (VarInsnNode) insn; if (var.var == 0) { lastThis = var; stackAtThis = frame.getStackSize(); poppedThis = false; } } 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.IncrementalChangeVisitor.java
License:Apache License
/** * To each class, add the dispatch method called by the original code that acts as a trampoline to * invoke the changed methods.//from ww w .j av a2 s . com * <p> * Pseudo code: * <code> * Object access$dispatch(String name, object[] args) { * if (name.equals( * "firstMethod.(L$type;Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/Object;")) { * return firstMethod(($type)arg[0], (String)arg[1], arg[2]); * } * if (name.equals("secondMethod.(L$type;Ljava/lang/String;I;)V")) { * secondMethod(($type)arg[0], (String)arg[1], (int)arg[2]); * return; * } * ... * StringBuilder $local1 = new StringBuilder(); * $local1.append("Method not found "); * $local1.append(name); * $local1.append(" in " + visitedClassName + * "$dispatch implementation, restart the application"); * throw new $package/InstantReloadException($local1.toString()); * } * </code> */ private void addDispatchMethod() { int access = Opcodes.ACC_PUBLIC | Opcodes.ACC_VARARGS; Method m = new Method("access$dispatch", "(Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/Object;"); MethodVisitor visitor = super.visitMethod(access, m.getName(), m.getDescriptor(), null, null); final GeneratorAdapter mv = new GeneratorAdapter(access, m, visitor); if (TRACING_ENABLED) { mv.push("Redirecting "); mv.loadArg(0); trace(mv, 2); } List<MethodNode> allMethods = new ArrayList<>(); // if we are disabled, do not generate any dispatch, the method will throw an exception // if invoked which should never happen. if (!instantRunDisabled) { //noinspection unchecked allMethods.addAll(classNode.methods); allMethods.addAll(addedMethods); } final Map<String, MethodNode> methods = new HashMap<>(); for (MethodNode methodNode : allMethods) { if (methodNode.name.equals("<clinit>") || methodNode.name.equals("<init>")) { continue; } if (!isAccessCompatibleWithInstantRun(methodNode.access)) { continue; } methods.put(methodNode.name + "." + methodNode.desc, methodNode); } new StringSwitch() { @Override void visitString() { mv.visitVarInsn(Opcodes.ALOAD, 1); } @Override void visitCase(String methodName) { MethodNode methodNode = methods.get(methodName); String name = methodNode.name; boolean isStatic = (methodNode.access & Opcodes.ACC_STATIC) != 0; String newDesc = computeOverrideMethodDesc(methodNode.desc, isStatic); if (TRACING_ENABLED) { trace(mv, "M: " + name + " P:" + newDesc); } Type[] args = Type.getArgumentTypes(newDesc); int argc = 0; for (Type t : args) { mv.visitVarInsn(Opcodes.ALOAD, 2); mv.push(argc); mv.visitInsn(Opcodes.AALOAD); ByteCodeUtils.unbox(mv, t); argc++; } mv.visitMethodInsn(Opcodes.INVOKESTATIC, visitedClassName + "$override", isStatic ? computeOverrideMethodName(name, methodNode.desc) : name, newDesc, false); Type ret = Type.getReturnType(methodNode.desc); if (ret.getSort() == Type.VOID) { mv.visitInsn(Opcodes.ACONST_NULL); } else { mv.box(ret); } mv.visitInsn(Opcodes.ARETURN); } @Override void visitDefault() { writeMissingMessageWithHash(mv, visitedClassName); } }.visit(mv, methods.keySet()); mv.visitMaxs(0, 0); mv.visitEnd(); super.visitEnd(); }
From source file:com.android.build.gradle.internal.incremental.IncrementalSupportVisitor.java
License:Apache License
/*** * Inserts a trampoline to this class so that the updated methods can make calls to super * class methods./* w ww . j ava2 s . co m*/ * <p> * Pseudo code for this trampoline: * <code> * Object access$super($classType instance, String name, object[] args) { * switch(name) { * case "firstMethod.(Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/Object;": * return super~instance.firstMethod((String)arg[0], arg[1]); * case "secondMethod.(Ljava/lang/String;I)V": * return super~instance.firstMethod((String)arg[0], arg[1]); * * default: * StringBuilder $local1 = new StringBuilder(); * $local1.append("Method not found "); * $local1.append(name); * $local1.append(" in " $classType $super implementation"); * throw new $package/InstantReloadException($local1.toString()); * } * </code> */ private void createAccessSuper() { int access = Opcodes.ACC_STATIC | Opcodes.ACC_PUBLIC | Opcodes.ACC_SYNTHETIC | Opcodes.ACC_VARARGS; Method m = new Method("access$super", "(L" + visitedClassName + ";Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/Object;"); MethodVisitor visitor = super.visitMethod(access, m.getName(), m.getDescriptor(), null, null); final GeneratorAdapter mv = new GeneratorAdapter(access, m, visitor); // Gather all methods from itself and its superclasses to generate a giant access$super // implementation. // This will work fine as long as we don't support adding methods to a class. final Map<String, MethodReference> uniqueMethods = new HashMap<>(); if (parentNodes.isEmpty()) { // if we cannot determine the parents for this class, let's blindly add all the // method of the current class as a gateway to a possible parent version. addAllNewMethods(classNode, classNode, uniqueMethods); } else { // otherwise, use the parent list. for (ClassNode parentNode : parentNodes) { addAllNewMethods(classNode, parentNode, uniqueMethods); } } new StringSwitch() { @Override void visitString() { mv.visitVarInsn(Opcodes.ALOAD, 1); } @Override void visitCase(String methodName) { MethodReference methodRef = uniqueMethods.get(methodName); mv.visitVarInsn(Opcodes.ALOAD, 0); Type[] args = Type.getArgumentTypes(methodRef.method.desc); int argc = 0; for (Type t : args) { mv.visitVarInsn(Opcodes.ALOAD, 2); mv.push(argc); mv.visitInsn(Opcodes.AALOAD); ByteCodeUtils.unbox(mv, t); argc++; } if (TRACING_ENABLED) { trace(mv, "super selected ", methodRef.owner.name, methodRef.method.name, methodRef.method.desc); } String parentName = findParentClassForMethod(methodRef); logger.verbose("Generating access$super for %1$s recev %2$s", methodRef.method.name, parentName); // Call super on the other object, yup this works cos we are on the right place to // call from. mv.visitMethodInsn(Opcodes.INVOKESPECIAL, parentName, methodRef.method.name, methodRef.method.desc, false); Type ret = Type.getReturnType(methodRef.method.desc); if (ret.getSort() == Type.VOID) { mv.visitInsn(Opcodes.ACONST_NULL); } else { mv.box(ret); } mv.visitInsn(Opcodes.ARETURN); } @Override void visitDefault() { writeMissingMessageWithHash(mv, visitedClassName); } }.visit(mv, uniqueMethods.keySet()); mv.visitMaxs(0, 0); mv.visitEnd(); }
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 ww w. ja va2s . 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); } }
From source file:com.android.build.gradle.internal2.incremental.IncrementalChangeVisitor.java
License:Apache License
/** * To each class, add the dispatch method called by the original code that acts as a trampoline to * invoke the changed methods.//from www . j a va 2s .co m * <p> * Pseudo code: * <code> * Object access$dispatch(String name, object[] args) { * if (name.equals( * "firstMethod.(L$type;Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/Object;")) { * return firstMethod(($type)arg[0], (String)arg[1], arg[2]); * } * if (name.equals("secondMethod.(L$type;Ljava/lang/String;I;)V")) { * secondMethod(($type)arg[0], (String)arg[1], (int)arg[2]); * return; * } * ... * StringBuilder $local1 = new StringBuilder(); * $local1.append("Method not found "); * $local1.append(name); * $local1.append(" in " + visitedClassName + * "$dispatch implementation, restart the application"); * throw new $package/InstantReloadException($local1.toString()); * } * </code> */ private void addDispatchMethod() { int access = Opcodes.ACC_PUBLIC | Opcodes.ACC_VARARGS; Method m = new Method("access$dispatch", "(Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/Object;"); MethodVisitor visitor = super.visitMethod(access, m.getName(), m.getDescriptor(), null, null); final GeneratorAdapter mv = new GeneratorAdapter(access, m, visitor); if (TRACING_ENABLED) { mv.push("Redirecting "); mv.loadArg(0); trace(mv, 2); } List<MethodNode> allMethods = new ArrayList<>(); // if we are disabled, do not generate any dispatch, the method will throw an exception // if invoked which should never happen. if (!instantRunDisabled) { //noinspection unchecked allMethods.addAll(classNode.methods); allMethods.addAll(addedMethods); } final Map<String, MethodNode> methods = new HashMap<>(); for (MethodNode methodNode : allMethods) { if (methodNode.name.equals(ByteCodeUtils.CLASS_INITIALIZER) || methodNode.name.equals(ByteCodeUtils.CONSTRUCTOR)) { continue; } if (!isAccessCompatibleWithInstantRun(methodNode.access)) { continue; } methods.put(methodNode.name + "." + methodNode.desc, methodNode); } new StringSwitch() { @Override void visitString() { mv.visitVarInsn(Opcodes.ALOAD, 1); } @Override void visitCase(String methodName) { MethodNode methodNode = methods.get(methodName); String name = methodNode.name; boolean isStatic = (methodNode.access & Opcodes.ACC_STATIC) != 0; String newDesc = computeOverrideMethodDesc(methodNode.desc, isStatic); if (TRACING_ENABLED) { trace(mv, "M: " + name + " P:" + newDesc); } Type[] args = Type.getArgumentTypes(newDesc); int argc = 0; for (Type t : args) { mv.visitVarInsn(Opcodes.ALOAD, 2); mv.push(argc); mv.visitInsn(Opcodes.AALOAD); ByteCodeUtils.unbox(mv, t); argc++; } mv.visitMethodInsn(Opcodes.INVOKESTATIC, visitedClassName + "$override", isStatic ? computeOverrideMethodName(name, methodNode.desc) : name, newDesc, false); Type ret = Type.getReturnType(methodNode.desc); if (ret.getSort() == Type.VOID) { mv.visitInsn(Opcodes.ACONST_NULL); } else { mv.box(ret); } mv.visitInsn(Opcodes.ARETURN); } @Override void visitDefault() { writeMissingMessageWithHash(mv, visitedClassName); } }.visit(mv, methods.keySet()); mv.visitMaxs(0, 0); mv.visitEnd(); super.visitEnd(); }