@Contract("null, null, _, _ -> fail") private static void loadMH(GeneratorAdapter adapter, Type reflectorClass, int flags, int mhIndex) { if((flags & Magic.REFLECTOR_METHOD_USE_METHODHANDLE) == 0) return; /* Load MethodHandle field */ adapter.loadThis(); adapter.getField(notNull(reflectorClass, "Reflector class shouldn't be null!"), MHF, MH_ARRAY); /* Load index */ if(mhIndex >= 0 && mhIndex <= 5) /* ICONST_x offset is 3, iow ICONST_0 = 3, ICONST_1 = 4 */ adapter.visitInsn(ICONST_0 + mhIndex); else adapter.visitIntInsn(BIPUSH, mhIndex); /* Load MethodHandle from array */ adapter.visitInsn(AALOAD); }
private static void createClassArray(GeneratorAdapter mv, List<Type> args) { // create an array of objects capable of containing all the parameters and optionally the "this" createLocals(mv, args); // we need to maintain the stack index when loading parameters from, as for long and double // values, it uses 2 stack elements, all others use only 1 stack element. int stackIndex = 0; for (int arrayIndex = 0; arrayIndex < args.size(); arrayIndex++) { Type arg = args.get(arrayIndex); // duplicate the array of objects reference, it will be used to store the value in. mv.dup(); // index in the array of objects to store the boxed parameter. mv.push(arrayIndex); // Pushes the appropriate local variable on the stack redirectLocal(mv, arg); // mv.visitLdcInsn(Type.getType(arg.getDescriptor())); // potentially box up intrinsic types. // mv.box(arg); mv.arrayStore(Type.getType(Class.class)); // stack index must progress according to the parameter type we just processed. // stackIndex += arg.getSize(); } }
public void visitEnd() { if (! doneAddField) { doneAddField = true; super.visitField(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, CLASS_FIELD, Type.getDescriptor(Agent.class), null, null); } if (! doneAddMethod) { doneAddMethod = true; GeneratorAdapter mg = new GeneratorAdapter(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, new Method(LOG_CLASS_METHOD, LOG_CLASS_SIGNATURE), LOG_CLASS_SIGNATURE, new Type[] {}, this); Label target = mg.newLabel(); mg.getStatic(JAVA_LANG_SYSTEM_TYPE, CLASS_FIELD, JAVA_LANG_CLASS_TYPE); mg.ifNull(target); mg.push(LOG_INTERNAL_TYPE); mg.putStatic(JAVA_LANG_SYSTEM_TYPE, CLASS_FIELD, JAVA_LANG_CLASS_TYPE); mg.mark(target); mg.getStatic(JAVA_LANG_SYSTEM_TYPE, CLASS_FIELD, JAVA_LANG_CLASS_TYPE); mg.returnValue(); } super.visitEnd(); }
@SuppressWarnings("unchecked") public void visitEnd() { if (!done && found) { done = true; try { GeneratorAdapter mg = new GeneratorAdapter(Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC, new Method(LOG_INTERNAL_METHOD, LOG_METHOD_SIGNATURE), LOG_METHOD_SIGNATURE, new Type[] {}, this); Label start = mg.mark(); mg.invokeStatic(LOG_INTERNAL_TYPE, Method.getMethod(LOG_INTERNAL_CLASS.getMethod(LOG_METHOD_NAME))); mg.returnValue(); Label end = mg.mark(); mg.catchException(start, end, JAVA_LANG_THROWABLE_TYPE); mg.returnValue(); mg.endMethod(); } catch (NoSuchMethodException nsme) { System.err.println("Unable to find Agent.rlogCallChain method"); System.err.println("M:"+nsme); nsme.printStackTrace(); } } super.visitEnd(); }
@SuppressWarnings("unchecked") public void visitEnd() { if (!foundClinit && instrument()) { // didn't find <clinit> so lets make one try { GeneratorAdapter mg = new GeneratorAdapter(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, new Method(CLINIT_NAME, CLINIT_SIGNATURE), CLINIT_SIGNATURE, new Type[] {}, this); Label start = mg.mark(); mg.push(className); mg.invokeStatic(LOG_INTERNAL_TYPE, Method.getMethod(LOG_INTERNAL_CLASS.getMethod(LOG_METHOD_NAME, String.class))); Label end = mg.mark(); mg.returnValue(); mg.catchException(start, end, JAVA_LANG_THROWABLE_TYPE); mg.returnValue(); mg.endMethod(); } catch (NoSuchMethodException nsme) { System.out.println("Unable to find Agent.reportClass method"); } } super.visitEnd(); }
private void visitx(GeneratorAdapter mv, List<String> strings) { if (strings.size() == 1) { visitCase(strings.get(0)); return; } for (String string : strings) { Label label = new Label(); visitString(); mv.visitLdcInsn(string); mv.invokeVirtual(STRING_TYPE, Method.getMethod("boolean equals(Object)")); mv.visitJumpInsn(Opcodes.IFEQ, label); visitCase(string); mv.visitLabel(label); } visitDefault(); }
/** * Given an array on the stack, it loads it with the values of the given variables stating at * offset. */ static void loadVariableArray( GeneratorAdapter mv, List<LocalVariable> variables, int offset) { // we need to maintain the stack index when loading parameters from, as for long and double // values, it uses 2 stack elements, all others use only 1 stack element. for (int i = offset; i < variables.size(); i++) { LocalVariable variable = variables.get(i); // duplicate the array of objects reference, it will be used to store the value in. mv.dup(); // index in the array of objects to store the boxed parameter. mv.push(i); // Pushes the appropriate local variable on the stack mv.visitVarInsn(variable.type.getOpcode(Opcodes.ILOAD), variable.var); // potentially box up intrinsic types. mv.box(variable.type); // store it in the array mv.arrayStore(Type.getType(Object.class)); } }
/** * Adds the instructions to do a generic redirection. */ protected void redirect(GeneratorAdapter mv, int change) { // code to check if a new implementation of the current class is available. Label l0 = new Label(); mv.loadLocal(change); mv.visitJumpInsn(Opcodes.IFNULL, l0); doRedirect(mv, change); // Return if (type == Type.VOID_TYPE) { mv.pop(); } else { ByteCodeUtils.unbox(mv, type); } mv.returnValue(); // jump label for classes without any new implementation, just invoke the original // method implementation. mv.visitLabel(l0); }
void emitConstants(GeneratorAdapter clinitgen){ try { Var.pushThreadBindings(RT.map(RT.PRINT_DUP, RT.T)); for(int i = 0; i < constants.count(); i++) { if(usedConstants.contains(i)) { emitValue(constants.nth(i), clinitgen); clinitgen.checkCast(constantType(i)); clinitgen.putStatic(objtype, constantName(i), constantType(i)); } } } finally { Var.popThreadBindings(); } }
public void emitAssignLocal(GeneratorAdapter gen, LocalBinding lb,Expr val){ if(!isMutable(lb)) throw new IllegalArgumentException("Cannot assign to non-mutable: " + lb.name); Class primc = lb.getPrimitiveType(); gen.loadThis(); if(primc != null) { if(!(val instanceof MaybePrimitiveExpr && ((MaybePrimitiveExpr) val).canEmitPrimitive())) throw new IllegalArgumentException("Must assign primitive to primitive mutable: " + lb.name); MaybePrimitiveExpr me = (MaybePrimitiveExpr) val; me.emitUnboxed(C.EXPRESSION, this, gen); gen.putField(objtype, lb.name, Type.getType(primc)); } else { val.emit(C.EXPRESSION, this, gen); gen.putField(objtype, lb.name, OBJECT_TYPE); } }
public void emit(C context, ObjExpr objx, GeneratorAdapter gen){ boolean allKeysConstant = true; boolean allConstantKeysUnique = true; IPersistentSet constantKeys = PersistentHashSet.EMPTY; for(int i = 0; i < keyvals.count(); i+=2) { Expr k = (Expr) keyvals.nth(i); if(k instanceof LiteralExpr) { Object kval = k.eval(); if (constantKeys.contains(kval)) allConstantKeysUnique = false; else constantKeys = (IPersistentSet)constantKeys.cons(kval); } else allKeysConstant = false; } MethodExpr.emitArgsAsArray(keyvals, objx, gen); if((allKeysConstant && allConstantKeysUnique) || (keyvals.count() <= 2)) gen.invokeStatic(RT_TYPE, mapUniqueKeysMethod); else gen.invokeStatic(RT_TYPE, mapMethod); if(context == C.STATEMENT) gen.pop(); }
public void emitLetFnInits(GeneratorAdapter gen, ObjExpr objx, IPersistentSet letFnLocals){ //objx arg is enclosing objx, not this gen.checkCast(objtype); for(ISeq s = RT.keys(closes); s != null; s = s.next()) { LocalBinding lb = (LocalBinding) s.first(); if(letFnLocals.contains(lb)) { Class primc = lb.getPrimitiveType(); gen.dup(); if(primc != null) { objx.emitUnboxedLocal(gen, lb); gen.putField(objtype, lb.name, Type.getType(primc)); } else { objx.emitLocal(gen, lb, false); gen.putField(objtype, lb.name, OBJECT_TYPE); } } } gen.pop(); }
public void emitAssign(C context, ObjExpr objx, GeneratorAdapter gen, Expr val){ if(targetClass != null && field != null) { target.emit(C.EXPRESSION, objx, gen); gen.checkCast(getType(targetClass)); val.emit(C.EXPRESSION, objx, gen); gen.visitLineNumber(line, gen.mark()); gen.dupX1(); HostExpr.emitUnboxArg(objx, gen, field.getType()); gen.putField(getType(targetClass), fieldName, Type.getType(field.getType())); } else { target.emit(C.EXPRESSION, objx, gen); gen.push(fieldName); val.emit(C.EXPRESSION, objx, gen); gen.visitLineNumber(line, gen.mark()); gen.invokeStatic(REFLECTOR_TYPE, setInstanceFieldMethod); } if(context == C.STATEMENT) gen.pop(); }
protected void emitMethods(ClassVisitor cv){ //override of invoke/doInvoke for each method for(ISeq s = RT.seq(methods); s != null; s = s.next()) { ObjMethod method = (ObjMethod) s.first(); method.emit(this, cv); } if(isVariadic()) { GeneratorAdapter gen = new GeneratorAdapter(ACC_PUBLIC, Method.getMethod("int getRequiredArity()"), null, null, cv); gen.visitCode(); gen.push(variadicMethod.reqParms.count()); gen.returnValue(); gen.endMethod(); } }
void emitClearLocals(GeneratorAdapter gen){ // for(int i = 1; i < numParams() + 1; i++) // { // if(!localsUsedInCatchFinally.contains(i)) // { // gen.visitInsn(Opcodes.ACONST_NULL); // gen.visitVarInsn(OBJECT_TYPE.getOpcode(Opcodes.ISTORE), i); // } // } // for(int i = numParams() + 1; i < maxLocal + 1; i++) // { // if(!localsUsedInCatchFinally.contains(i)) // { // LocalBinding b = (LocalBinding) RT.get(indexlocals, i); // if(b == null || maybePrimitiveType(b.init) == null) // { // gen.visitInsn(Opcodes.ACONST_NULL); // gen.visitVarInsn(OBJECT_TYPE.getOpcode(Opcodes.ISTORE), i); // } // } // } // if(((FnExpr)objx).onceOnly) // { // objx.emitClearCloses(gen); // } }
public void emit(C context, ObjExpr objx, GeneratorAdapter gen){ if(args.count() <= Tuple.MAX_SIZE) { for(int i = 0; i < args.count(); i++) { ((Expr) args.nth(i)).emit(C.EXPRESSION, objx, gen); } gen.invokeStatic(TUPLE_TYPE, createTupleMethods[args.count()]); } else { MethodExpr.emitArgsAsArray(args, objx, gen); gen.invokeStatic(RT_TYPE, vectorMethod); } if(context == C.STATEMENT) gen.pop(); }
public void emit(C context, ObjExpr objx, GeneratorAdapter gen){ if(isProtocol) { gen.visitLineNumber(line, gen.mark()); emitProto(context,objx,gen); } else { fexpr.emit(C.EXPRESSION, objx, gen); gen.visitLineNumber(line, gen.mark()); gen.checkCast(IFN_TYPE); emitArgsAndCall(0, context,objx,gen); } if(context == C.STATEMENT) gen.pop(); }
public void emit(C context, ObjExpr objx, GeneratorAdapter gen){ if(targetClass != null && field != null) { target.emit(C.EXPRESSION, objx, gen); gen.visitLineNumber(line, gen.mark()); gen.checkCast(getType(targetClass)); gen.getField(getType(targetClass), fieldName, Type.getType(field.getType())); //if(context != C.STATEMENT) HostExpr.emitBoxReturn(objx, gen, field.getType()); if(context == C.STATEMENT) { gen.pop(); } } else { target.emit(C.EXPRESSION, objx, gen); gen.visitLineNumber(line, gen.mark()); gen.push(fieldName); gen.push(requireField); gen.invokeStatic(REFLECTOR_TYPE, invokeNoArgInstanceMember); if(context == C.STATEMENT) gen.pop(); } }
void emitArgsAndCall(int firstArgToEmit, C context, ObjExpr objx, GeneratorAdapter gen){ for(int i = firstArgToEmit; i < Math.min(MAX_POSITIONAL_ARITY, args.count()); i++) { Expr e = (Expr) args.nth(i); e.emit(C.EXPRESSION, objx, gen); } if(args.count() > MAX_POSITIONAL_ARITY) { PersistentVector restArgs = PersistentVector.EMPTY; for(int i = MAX_POSITIONAL_ARITY; i < args.count(); i++) { restArgs = restArgs.cons(args.nth(i)); } MethodExpr.emitArgsAsArray(restArgs, objx, gen); } gen.visitLineNumber(line, gen.mark()); if(context == C.RETURN) { ObjMethod method = (ObjMethod) METHOD.deref(); method.emitClearLocals(gen); } gen.invokeInterface(IFN_TYPE, new Method("invoke", OBJECT_TYPE, ARG_TYPES[Math.min(MAX_POSITIONAL_ARITY + 1, args.count())])); }
/** Writes a static binary instruction */ public void writeBinaryInstruction(Location location, Type type, Operation operation) { final Sort sort = type.sort; if ((sort == Sort.FLOAT || sort == Sort.DOUBLE) && (operation == Operation.LSH || operation == Operation.USH || operation == Operation.RSH || operation == Operation.BWAND || operation == Operation.XOR || operation == Operation.BWOR)) { throw location.createError(new IllegalStateException("Illegal tree structure.")); } switch (operation) { case MUL: math(GeneratorAdapter.MUL, type.type); break; case DIV: math(GeneratorAdapter.DIV, type.type); break; case REM: math(GeneratorAdapter.REM, type.type); break; case ADD: math(GeneratorAdapter.ADD, type.type); break; case SUB: math(GeneratorAdapter.SUB, type.type); break; case LSH: math(GeneratorAdapter.SHL, type.type); break; case USH: math(GeneratorAdapter.USHR, type.type); break; case RSH: math(GeneratorAdapter.SHR, type.type); break; case BWAND: math(GeneratorAdapter.AND, type.type); break; case XOR: math(GeneratorAdapter.XOR, type.type); break; case BWOR: math(GeneratorAdapter.OR, type.type); break; default: throw location.createError(new IllegalStateException("Illegal tree structure.")); } }
/** * Generates unboxing bytecode for the passed type. An {@link Object} is expected to be on the * stack when these bytecodes are inserted. * * ASM takes a short cut when dealing with short/byte types and convert them into int rather * than short/byte types. This is not an issue on the jvm nor Android's ART but it is an issue * on Dalvik. * * @param mv the {@link GeneratorAdapter} generating a method implementation. * @param type the expected un-boxed type. */ public static void unbox(GeneratorAdapter mv, Type type) { if (type.equals(Type.SHORT_TYPE)) { mv.checkCast(NUMBER_TYPE); mv.invokeVirtual(NUMBER_TYPE, SHORT_VALUE); } else if (type.equals(Type.BYTE_TYPE)) { mv.checkCast(NUMBER_TYPE); mv.invokeVirtual(NUMBER_TYPE, BYTE_VALUE); } else { mv.unbox(type); } }
private static void prepareMethodParameters(GeneratorAdapter mv, String className, List<Type> args, Type returnType, boolean isStatic, int methodId) { //第一个参数:new Object[]{...};,如果方法没有参数直接传入new Object[0] if (args.size() == 0) { mv.visitInsn(Opcodes.ICONST_0); mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object"); } else { createObjectArray(mv, args, isStatic); } //第二个参数:this,如果方法是static的话就直接传入null if (isStatic) { mv.visitInsn(Opcodes.ACONST_NULL); } else { mv.visitVarInsn(Opcodes.ALOAD, 0); } //第三个参数:changeQuickRedirect mv.visitFieldInsn(Opcodes.GETSTATIC, className, REDIRECTFIELD_NAME, REDIRECTCLASSNAME); //第四个参数:false,标志是否为static mv.visitInsn(isStatic ? Opcodes.ICONST_1 : Opcodes.ICONST_0); //第五个参数: mv.push(methodId); //第六个参数:参数class数组 createClassArray(mv, args); //第七个参数:返回值类型class createReturnClass(mv, returnType); }
/** * Pushes in the stack the value that should be redirected for the given local. */ protected static void redirectLocal(GeneratorAdapter mv, Type arg) { switch (arg.getDescriptor()) { case "Z": mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Boolean", "TYPE", "Ljava/lang/Class;"); break; case "B": mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Byte", "TYPE", "Ljava/lang/Class;"); break; case "C": mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Character", "TYPE", "Ljava/lang/Class;"); break; case "S": mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Short", "TYPE", "Ljava/lang/Class;"); break; case "I": mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Integer", "TYPE", "Ljava/lang/Class;"); break; case "F": mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Float", "TYPE", "Ljava/lang/Class;"); break; case "D": mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Double", "TYPE", "Ljava/lang/Class;"); break; case "J": mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Long", "TYPE", "Ljava/lang/Class;"); break; case "V": mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Void", "TYPE", "Ljava/lang/Class;"); break; default: mv.visitLdcInsn(Type.getType(arg.getDescriptor())); } }
@Contract("null, null, null -> fail") static void generateFailedMethod(ClassVisitor cv, Method interfaceMethod, String errorMessage) { String methodName = interfaceMethod.getName(); String methodDescriptor = Type.getMethodDescriptor(interfaceMethod); MethodVisitor mv = cv.visitMethod(ACC_PUBLIC, methodName, methodDescriptor, null, null); GeneratorAdapter adapter = new GeneratorAdapter(mv, ACC_PUBLIC, methodName, methodDescriptor); adapter.visitCode(); /* Throw exception */ adapter.throwException(Type.getType(RuntimeException.class), errorMessage); /* End method generation */ adapter.endMethod(); }
@Contract("null, null, null, !null -> fail") private static void loadArguments(GeneratorAdapter ga, Type[] interfaceTypes, Type[] targetTypes, boolean isTargetPublic) { Ensure.ensureCondition(interfaceTypes.length == targetTypes.length, "Interface and target parameter count don't match!"); /* Iterate through all types */ for(int i = 0; i < interfaceTypes.length; i++) { Type interfaceType = interfaceTypes[i]; Type targetType = targetTypes[i]; ga.loadArg(i); /* Do not do boxing/unboxing if MethodHandle.invoke is used, it handles them on its own */ if(!isTargetPublic) continue; if(isPrimitive(interfaceType)) { if(!isPrimitive(targetType)) { ga.box(targetType); } } else { if(isPrimitive(targetType)) { ga.unbox(targetType); } else { if(interfaceType.equals(OBJECT)) { ga.checkCast(targetType); ga.cast(interfaceType, targetType); } } } } }
@Contract("null, null, null, _ -> fail") private static void loadInstance(GeneratorAdapter adapter, Type reflectorClass, Type targetClass, int flags) { if((flags & Magic.REFLECTOR_METHOD_USE_INSTANCE) == 0) return; adapter.loadThis(); adapter.getField(reflectorClass, REFF, (flags & Magic.TARGET_CLASS_VISIBILITY_PUBLIC) != 0 ? targetClass : OBJECT); }
@Contract("null, null, null -> fail") private static void handleReturn(GeneratorAdapter ga, Method interfaceMethod, Type targetReturnType) { Type returnType = Type.getReturnType(interfaceMethod); if(isPrimitive(returnType)) { if(!isPrimitive(targetReturnType)) { ga.unbox(targetReturnType); } } else { if(isPrimitive(targetReturnType)) { ga.box(targetReturnType); } } }
void writeMissingMessageWithHash(GeneratorAdapter mv, String visitedClassName) { mv.newInstance(INSTANT_RELOAD_EXCEPTION_TYPE); mv.dup(); mv.push("int switch could not find %d in %s"); mv.push(3); mv.newArray(OBJECT_TYPE); mv.dup(); mv.push(0); visitInt(); mv.visitMethodInsn( Opcodes.INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;", false); mv.arrayStore(OBJECT_TYPE); mv.dup(); mv.push(2); mv.push(visitedClassName); mv.arrayStore(OBJECT_TYPE); mv.visitMethodInsn( Opcodes.INVOKESTATIC, "java/lang/String", "format", "(Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/String;", false); mv.invokeConstructor(INSTANT_RELOAD_EXCEPTION_TYPE, Method.getMethod("void <init> (String)")); mv.throwException(); }
void visit(GeneratorAdapter mv, Set<String> strings, String className) { this.className = className; this.classData = AcesoProguardMap.instance().getClassData(className); if (classData == null) { throw new GradleException("can not find class: " + className + " , sure you aceso-mapping is right and this class not in blacklist."); } visitClassifier(mv, strings); }
/** * Pushes an array on the stack that contains the value of all the given variables. */ static void newVariableArray( GeneratorAdapter mv, List<LocalVariable> variables) { mv.push(variables.size()); mv.newArray(Type.getType(Object.class)); loadVariableArray(mv, variables, 0); }
@Override protected void doRedirect( GeneratorAdapter mv, int change) { mv.loadLocal(change); mv.push(AcesoProguardMap.instance().getMtdIndex(visitedClassName, IncrementalTool.getMtdSig(mtdName,mtdDesc))); ByteCodeUtils.newVariableArray(mv, ByteCodeUtils.toLocalVariables(types)); // now invoke the generic dispatch method. mv.invokeInterface(IncrementalVisitor.CHANGE_TYPE, Method.getMethod("Object access$dispatch(int, Object[])")); }
protected static void trace( GeneratorAdapter mv, int argsNumber) { StringBuilder methodSignature = new StringBuilder("void trace(String"); for (int i = 0; i < argsNumber - 1; i++) { methodSignature.append(", String"); } methodSignature.append(")"); mv.invokeStatic(Type.getObjectType(PACKAGE + "/AndroidInstantRuntime"), Method.getMethod(methodSignature.toString())); }
SynchronizedMethodTransformer(GeneratorAdapter mv, String className, String methodName, String fileName, int access, int classVersion) { super(mv, className, methodName, fileName); this.className = className; this.classVersion = classVersion; this.isSynchronized = (access & ACC_SYNCHRONIZED) != 0; this.isStatic = (access & ACC_STATIC) != 0; if (isSynchronized) { mv.visitTryCatchBlock(tryLabel, catchLabel, catchLabel, null); } }