List of usage examples for org.objectweb.asm Opcodes ACC_STATIC
int ACC_STATIC
To view the source code for org.objectweb.asm Opcodes ACC_STATIC.
Click Source Link
From source file:com.android.build.gradle.internal.incremental.IncrementalSupportVisitor.java
License:Apache License
/** * Add all unseen methods from the passed ClassNode's methods. * * @see ClassNode#methods//from w w w . ja va 2 s .c o m * @param instrumentedClass class that is being visited * @param superClass the class to save all new methods from * @param methods the methods already encountered in the ClassNode hierarchy */ private static void addAllNewMethods(ClassNode instrumentedClass, ClassNode superClass, Map<String, MethodReference> methods) { //noinspection unchecked for (MethodNode method : (List<MethodNode>) superClass.methods) { if (method.name.equals(ByteCodeUtils.CONSTRUCTOR) || method.name.equals("<clinit>")) { continue; } String name = method.name + "." + method.desc; if (isAccessCompatibleWithInstantRun(method.access) && !methods.containsKey(name) && (method.access & Opcodes.ACC_STATIC) == 0 && isCallableFromSubclass(method, superClass, instrumentedClass)) { methods.put(name, new MethodReference(method, superClass)); } } }
From source file:com.android.build.gradle.internal.transforms.InstantRunTransform.java
License:Apache License
/** * Use asm to generate a concrete subclass of the AppPathLoaderImpl class. * It only implements one method :/*from w w w . j a v a2 s. c o m*/ * String[] getPatchedClasses(); * * The method is supposed to return the list of classes that were patched in this iteration. * This will be used by the InstantRun runtime to load all patched classes and register them * as overrides on the original classes.2 class files. * * @param patchFileContents list of patched class names. * @param outputDir output directory where to generate the .class file in. */ private static void writePatchFileContents(@NonNull ImmutableList<String> patchFileContents, @NonNull File outputDir, long buildId) { ClassWriter cw = new ClassWriter(0); MethodVisitor mv; cw.visit(Opcodes.V1_6, Opcodes.ACC_PUBLIC + Opcodes.ACC_SUPER, IncrementalVisitor.APP_PATCHES_LOADER_IMPL, null, IncrementalVisitor.ABSTRACT_PATCHES_LOADER_IMPL, null); // Add the build ID to force the patch file to be repackaged. cw.visitField(Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC + Opcodes.ACC_FINAL, "BUILD_ID", "J", null, buildId); { mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "<init>", "()V", null, null); mv.visitCode(); mv.visitVarInsn(Opcodes.ALOAD, 0); mv.visitMethodInsn(Opcodes.INVOKESPECIAL, IncrementalVisitor.ABSTRACT_PATCHES_LOADER_IMPL, "<init>", "()V", false); mv.visitInsn(Opcodes.RETURN); mv.visitMaxs(1, 1); mv.visitEnd(); } { mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "getPatchedClasses", "()[Ljava/lang/String;", null, null); mv.visitCode(); mv.visitIntInsn(Opcodes.BIPUSH, patchFileContents.size()); mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/String"); for (int index = 0; index < patchFileContents.size(); index++) { mv.visitInsn(Opcodes.DUP); mv.visitIntInsn(Opcodes.BIPUSH, index); mv.visitLdcInsn(patchFileContents.get(index)); mv.visitInsn(Opcodes.AASTORE); } mv.visitInsn(Opcodes.ARETURN); mv.visitMaxs(4, 1); mv.visitEnd(); } cw.visitEnd(); byte[] classBytes = cw.toByteArray(); File outputFile = new File(outputDir, IncrementalVisitor.APP_PATCHES_LOADER_IMPL + ".class"); try { Files.createParentDirs(outputFile); Files.write(classBytes, outputFile); } catch (IOException e) { throw new RuntimeException(e); } }
From source file:com.android.build.gradle.internal2.incremental.ConstructorBuilder.java
License:Apache License
/** * Splits the constructor in two methods, the "set up" and the "body" parts (see above). *///from w w w .java 2 s. c o m @NonNull private static Constructor split(@NonNull String owner, @NonNull MethodNode method, @NonNull VarInsnNode loadThis, @NonNull MethodInsnNode delegation, int loadThisLine, @NonNull List<LocalVariable> variables, int localsAtLoadThis) { String[] exceptions = ((List<String>) method.exceptions).toArray(new String[method.exceptions.size()]); // Do not add the local array yet, as we treat it as a new variable. String newDesc = method.desc.replace(")V", ")Ljava/lang/Object;"); newDesc = newDesc.replace("(", "([L" + owner + ";"); Type[] argumentTypes = Type.getArgumentTypes(newDesc); // Store the non hotswappable part of the constructor List<AbstractInsnNode> fixed = Lists.newLinkedList(); AbstractInsnNode insn = method.instructions.getFirst(); while (insn != loadThis) { fixed.add(insn); insn = insn.getNext(); } fixed.add(loadThis); MethodNode initArgs = new MethodNode(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, "init$args", newDesc, null, exceptions); GeneratorAdapter mv = new GeneratorAdapter(initArgs, initArgs.access, initArgs.name, initArgs.desc); int newArgument = mv.newLocal(Type.getType("[Ljava/lang/Object;")); mv.loadLocal(newArgument); ByteCodeUtils.restoreVariables(mv, variables.subList(0, localsAtLoadThis)); // Now insert the original method insn = loadThis.getNext(); while (insn != delegation) { insn.accept(mv); insn = insn.getNext(); } LabelNode labelBefore = new LabelNode(); labelBefore.accept(mv); // Create the args array with the local variables and the values to send to the delegated constructor Type[] returnTypes = Type.getArgumentTypes(delegation.desc); // The extra elements for the local variables and the qualified name of the constructor. mv.push(returnTypes.length + 2); 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 + 2); mv.swap(type, Type.INT_TYPE); mv.box(type); mv.arrayStore(Type.getType(Object.class)); } // Store the qualified name of the constructor in the second element of the array. mv.loadLocal(args); mv.push(1); mv.push(delegation.owner + "." + delegation.desc); // Name of the constructor to be called. mv.arrayStore(Type.getType(Object.class)); // Create the locals array and place it in the first element of the return array mv.loadLocal(args); mv.push(0); mv.push(argumentTypes.length + 1); mv.newArray(Type.getType(Object.class)); ByteCodeUtils.loadVariableArray(mv, ByteCodeUtils.toLocalVariables(Arrays.asList(argumentTypes)), 0); mv.dup(); mv.push(argumentTypes.length); ByteCodeUtils.newVariableArray(mv, variables); mv.arrayStore(Type.getType(Object.class)); mv.arrayStore(Type.getType(Object.class)); mv.loadLocal(args); mv.returnValue(); // Move the first variable up to be an argument initArgs.desc = initArgs.desc.replace(")", "[Ljava/lang/Object;)"); newDesc = method.desc.replace("(", "(L" + owner + ";"); MethodNode body = new MethodNode(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, "init$body", newDesc, null, exceptions); mv = new GeneratorAdapter(body, body.access, body.name, body.desc); newArgument = mv.newLocal(Type.getType("[Ljava/lang/Object;")); LabelNode labelAfter = new LabelNode(); labelAfter.accept(body); Set<LabelNode> bodyLabels = new HashSet<LabelNode>(); mv.loadLocal(newArgument); ByteCodeUtils.restoreVariables(mv, variables); insn = delegation.getNext(); while (insn != null) { if (insn instanceof LabelNode) { bodyLabels.add((LabelNode) insn); } insn.accept(mv); 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(mv); } //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."); } } // Move the first variable up to be an argument body.desc = body.desc.replace(")", "[Ljava/lang/Object;)"); return new Constructor(owner, method, fixed, loadThis, loadThisLine, initArgs, delegation, body, variables, localsAtLoadThis); }
From source file:com.android.build.gradle.internal2.incremental.IncrementalChangeVisitor.java
License:Apache License
/** * Turns this class into an override class that can be loaded by our custom class loader: *<ul>//from w w w . j av a2s . co m * <li>Make the class name be OriginalName$override</li> * <li>Ensure the class derives from java.lang.Object, no other inheritance</li> * <li>Ensure the class has a public parameterless constructor that is a noop.</li> *</ul> */ @Override public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { // TODO: modified by achellies, ?,??,?ClassClass,Opcodes.INVOKESPECIAL?super super.visit(version, Opcodes.ACC_PUBLIC | Opcodes.ACC_SUPER, name + OVERRIDE_SUFFIX, signature, superName, // TODO modified by achellies, "java/lang/Object" -> superName new String[] { CHANGE_TYPE.getInternalName() }); if (DEBUG) { System.out.println(">>>>>>>> Processing " + name + "<<<<<<<<<<<<<"); } visitedClassName = name; visitedSuperName = superName; instanceToStaticDescPrefix = "(L" + visitedClassName + ";"; // Create empty constructor MethodVisitor mv = super.visitMethod(Opcodes.ACC_PUBLIC, ByteCodeUtils.CONSTRUCTOR, "()V", null, null); mv.visitCode(); mv.visitVarInsn(Opcodes.ALOAD, 0); mv.visitMethodInsn(Opcodes.INVOKESPECIAL, superName, ByteCodeUtils.CONSTRUCTOR, "()V", // TODO modified by achellies, "java/lang/Object" -> superName false); mv.visitInsn(Opcodes.RETURN); mv.visitMaxs(0, 0); mv.visitEnd(); super.visitField(Opcodes.ACC_PUBLIC | Opcodes.ACC_SYNTHETIC | Opcodes.ACC_STATIC, "$obsolete", "Z", null, null); }
From source file:com.android.build.gradle.internal2.incremental.IncrementalChangeVisitor.java
License:Apache License
/** * Generates new delegates for all 'patchable' methods in the visited class. Delegates * are static methods that do the same thing the visited code does, but from outside the class. * For instance methods, the instance is passed as the first argument. Note that: * <ul>/*from www. ja v a 2 s . c om*/ * <li>We ignore the class constructor as we don't support it right now</li> * <li>We skip abstract methods.</li> * <li>For constructors split the method body into super arguments and the rest of * the method body, see {@link ConstructorBuilder}</li> * </ul> */ @Override public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { if (instantRunDisabled || !isAccessCompatibleWithInstantRun(access)) { // Nothing to generate. return null; } if (name.equals(ByteCodeUtils.CLASS_INITIALIZER)) { // we skip the class init as it can reset static fields which we don't support right now return null; } boolean isStatic = (access & Opcodes.ACC_STATIC) != 0; String newDesc = computeOverrideMethodDesc(desc, isStatic); if (DEBUG) { System.out.println(">>> Visiting method " + visitedClassName + ":" + name + ":" + desc); if (exceptions != null) { for (String exception : exceptions) { System.out.println("> Exception thrown : " + exception); } } } if (DEBUG) { System.out.println("New Desc is " + newDesc + ":" + isStatic); } // Do not carry on any access flags from the original method. For example synchronized // on the original method would translate into a static synchronized method here. access = Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC; MethodNode method = getMethodByNameInClass(name, desc, classNode); if (name.equals(ByteCodeUtils.CONSTRUCTOR)) { Constructor constructor = ConstructorBuilder.build(visitedClassName, method); MethodVisitor original = super.visitMethod(access, constructor.args.name, constructor.args.desc, constructor.args.signature, exceptions); ISVisitor mv = new ISVisitor(original, access, constructor.args.name, constructor.args.desc, isStatic, true /* isConstructor */); constructor.args.accept(mv); original = super.visitMethod(access, constructor.body.name, constructor.body.desc, constructor.body.signature, exceptions); mv = new ISVisitor(original, access, constructor.body.name, newDesc, isStatic, true /* isConstructor */); constructor.body.accept(mv); // Remember our created methods so we can generated the access$dispatch for them. addedMethods.add(constructor.args); addedMethods.add(constructor.body); return null; } else { String newName = isStatic ? computeOverrideMethodName(name, desc) : name; MethodVisitor original = super.visitMethod(access, newName, newDesc, signature, exceptions); return new ISVisitor(original, access, newName, newDesc, isStatic, false /* isConstructor */); } }
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./*w ww .j a v a 2 s. c o 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(); }
From source file:com.android.build.gradle.internal2.incremental.IncrementalSupportVisitor.java
License:Apache License
/** * Ensures that the class contains a $change field used for referencing the IncrementalChange * dispatcher./*from ww w . j a v a 2 s . c o m*/ * * <p>Also updates package_private visibility to public so we can call into this class from * outside the package. * * <p>All classes will have a serialVersionUID added (if one does not already exist), as * otherwise, serialVersionUID would be different for instrumented and non-instrumented classes. * We do this for all classes. Due to incremental changes, there could be a class that starts * implementing {@link java.io.Serializable}, thus making all of its subclasses serializable as * well. Those subclasses might be used for persistence, and we need to make sure their * serialVersionUID are stable across instant run and non-instant run builds. */ @Override public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { visitedClassName = name; visitedSuperName = superName; // TODO: disabled by achellies // addSerialUidIfMissing(); super.visitField(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC | Opcodes.ACC_VOLATILE | Opcodes.ACC_SYNTHETIC | Opcodes.ACC_TRANSIENT, "$change", getRuntimeTypeName(CHANGE_TYPE), null, null); access = transformClassAccessForInstantRun(access); super.visit(version, access, name, signature, superName, interfaces); }
From source file:com.android.build.gradle.internal2.incremental.IncrementalSupportVisitor.java
License:Apache License
/** * Insert Constructor specific logic({@link ConstructorRedirection} and * {@link ConstructorBuilder}) for constructor redirecting or * normal method redirecting ({@link MethodRedirection}) for other methods. *///from w w w .ja va 2 s . c o m @Override public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { access = transformAccessForInstantRun(access); MethodVisitor defaultVisitor = super.visitMethod(access, name, desc, signature, exceptions); MethodNode method = getMethodByNameInClass(name, desc, classNode); // does the method use blacklisted APIs. boolean hasIncompatibleChange = InstantRunMethodVerifier .verifyMethod(method) != InstantRunVerifierStatus.COMPATIBLE; if (hasIncompatibleChange || disableRedirectionForClass || !isAccessCompatibleWithInstantRun(access) || name.equals(ByteCodeUtils.CLASS_INITIALIZER)) { return defaultVisitor; } else { ArrayList<Type> args = new ArrayList<Type>(Arrays.asList(Type.getArgumentTypes(desc))); boolean isStatic = (access & Opcodes.ACC_STATIC) != 0; if (!isStatic) { args.add(0, Type.getType(Object.class)); } ISMethodVisitor mv = new ISMethodVisitor(defaultVisitor, access, name, desc); if (name.equals(ByteCodeUtils.CONSTRUCTOR)) { Constructor constructor = ConstructorBuilder.build(visitedClassName, method); LabelNode start = new LabelNode(); method.instructions.insert(constructor.loadThis, start); if (constructor.lineForLoad != -1) { // Record the line number from the start of LOAD_0 for uninitialized 'this'. // This allows a breakpoint to be set at the line with this(...) or super(...) // call in the constructor. method.instructions.insert(constructor.loadThis, new LineNumberNode(constructor.lineForLoad, start)); } mv.addRedirection(new ConstructorRedirection(start, constructor, args)); } else { mv.addRedirection(new MethodRedirection(new LabelNode(mv.getStartLabel()), name + "." + desc, args, Type.getReturnType(desc))); } method.accept(mv); return null; } }
From source file:com.android.build.gradle.internal2.incremental.IncrementalSupportVisitor.java
License:Apache License
/*** * Inserts a trampoline to this class so that the updated methods can make calls to super * class methods.//from ww w . j a v a2 s . c om * <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); LOG.verbose("Generating access$super for " + methodRef.method.name + " recv " + 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.IncrementalSupportVisitor.java
License:Apache License
/** * Add all unseen methods from the passed ClassNode's methods. * * @see ClassNode#methods/* w w w .j ava 2s . co m*/ * @param instrumentedClass class that is being visited * @param superClass the class to save all new methods from * @param methods the methods already encountered in the ClassNode hierarchy */ private static void addAllNewMethods(ClassNode instrumentedClass, ClassNode superClass, Map<String, MethodReference> methods) { //noinspection unchecked for (MethodNode method : (List<MethodNode>) superClass.methods) { if (method.name.equals(ByteCodeUtils.CONSTRUCTOR) || method.name.equals(ByteCodeUtils.CLASS_INITIALIZER)) { continue; } String name = method.name + "." + method.desc; if (isAccessCompatibleWithInstantRun(method.access) && !methods.containsKey(name) && (method.access & Opcodes.ACC_STATIC) == 0 && isCallableFromSubclass(method, superClass, instrumentedClass)) { methods.put(name, new MethodReference(method, superClass)); } } }