private void setCanCallSettersField( MethodVisitor methodVisitor, Type generatedType, boolean canCallSetters) { putThisOnStack(methodVisitor); methodVisitor.visitLdcInsn(canCallSetters); methodVisitor.visitFieldInsn( PUTFIELD, generatedType.getInternalName(), CAN_CALL_SETTERS_FIELD_NAME, Type.BOOLEAN_TYPE.getDescriptor()); }
private void writeManagedTypeStaticField( Type generatedType, Class<?> managedTypeClass, MethodVisitor constructorVisitor) { constructorVisitor.visitLdcInsn(Type.getType(managedTypeClass)); constructorVisitor.visitMethodInsn( INVOKESTATIC, MODELTYPE_INTERNAL_NAME, "of", MODELTYPE_OF_METHOD_DESCRIPTOR, false); constructorVisitor.visitFieldInsn( PUTSTATIC, generatedType.getInternalName(), MANAGED_TYPE_FIELD_NAME, Type.getDescriptor(ModelType.class)); }
/** Generate a call to the delegate object. */ protected MethodVisitor makeDelegateCall( final String name, final String desc, final String signature, final String[] exceptions, final int accessFlags) { MethodVisitor mv = super.visitMethod(accessFlags, name, desc, signature, exceptions); mv.visitVarInsn(ALOAD, 0); // load this mv.visitFieldInsn( GETFIELD, proxyName, DELEGATE_OBJECT_FIELD, BytecodeHelper.getTypeDescription(delegateClass)); // load delegate // using InvokerHelper to allow potential intercepted calls int size; mv.visitLdcInsn(name); // method name Type[] args = Type.getArgumentTypes(desc); BytecodeHelper.pushConstant(mv, args.length); mv.visitTypeInsn(ANEWARRAY, "java/lang/Object"); size = 3; int idx = 1; for (int i = 0; i < args.length; i++) { Type arg = args[i]; mv.visitInsn(DUP); BytecodeHelper.pushConstant(mv, i); // primitive types must be boxed if (isPrimitive(arg)) { mv.visitIntInsn(getLoadInsn(arg), idx); String wrappedType = getWrappedClassDescriptor(arg); mv.visitMethodInsn( INVOKESTATIC, wrappedType, "valueOf", "(" + arg.getDescriptor() + ")L" + wrappedType + ";"); } else { mv.visitVarInsn(ALOAD, idx); // load argument i } size = Math.max(6, 5 + registerLen(arg)); idx += registerLen(arg); mv.visitInsn(AASTORE); // store value into array } mv.visitMethodInsn( INVOKESTATIC, "org/codehaus/groovy/runtime/InvokerHelper", "invokeMethod", "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/Object;"); unwrapResult(mv, desc); mv.visitMaxs(size, registerLen(args) + 1); return EMPTY_VISITOR; }
// the overload of type Object for Groovy coercions: public void setFoo(Object foo) private void createTypeConvertingSetter( ClassVisitor visitor, Type generatedType, ModelProperty<?> property) { if (!property.isWritable() || !(property.getSchema() instanceof ScalarValueSchema)) { return; } Class<?> propertyClass = property.getType().getConcreteClass(); Type propertyType = Type.getType(propertyClass); Class<?> boxedClass = propertyClass.isPrimitive() ? BOXED_TYPES.get(propertyClass) : propertyClass; Type boxedType = Type.getType(boxedClass); Method setter = property.getSetter().getMethod(); MethodVisitor methodVisitor = declareMethod( visitor, setter.getName(), SET_OBJECT_PROPERTY_DESCRIPTOR, SET_OBJECT_PROPERTY_DESCRIPTOR); putThisOnStack(methodVisitor); putTypeConverterFieldValueOnStack(methodVisitor, generatedType); // Object converted = $typeConverter.convert(foo, Float.class, false); methodVisitor.visitVarInsn(ALOAD, 1); // put var #1 ('foo') on the stack methodVisitor.visitLdcInsn(boxedType); // push the constant Class onto the stack methodVisitor.visitInsn( propertyClass.isPrimitive() ? ICONST_1 : ICONST_0); // push int 1 or 0 (interpreted as true or false) onto the stack methodVisitor.visitMethodInsn( INVOKEINTERFACE, TYPE_CONVERTER_TYPE.getInternalName(), "convert", COERCE_TO_SCALAR_DESCRIPTOR, true); methodVisitor.visitTypeInsn(CHECKCAST, boxedType.getInternalName()); if (propertyClass.isPrimitive()) { unboxType(methodVisitor, propertyClass); } // invoke the typed setter, popping 'this' and 'converted' from the stack methodVisitor.visitMethodInsn( INVOKEVIRTUAL, generatedType.getInternalName(), setter.getName(), Type.getMethodDescriptor(Type.VOID_TYPE, propertyType), false); finishVisitingMethod(methodVisitor); }
protected MethodVisitor makeDelegateToClosureCall( final String name, final String desc, final String signature, final String[] exceptions, final int accessFlags) { MethodVisitor mv = super.visitMethod(accessFlags, name, desc, signature, exceptions); // TraceMethodVisitor tmv = new TraceMethodVisitor(mv); // mv = tmv; mv.visitCode(); int stackSize = 0; // method body should be: // this.$delegate$closure$methodName.call(new Object[] { method arguments }) Type[] args = Type.getArgumentTypes(desc); int arrayStore = args.length + 1; BytecodeHelper.pushConstant(mv, args.length); mv.visitTypeInsn(ANEWARRAY, "java/lang/Object"); // stack size = 1 stackSize = 1; int idx = 1; for (int i = 0; i < args.length; i++) { Type arg = args[i]; mv.visitInsn(DUP); // stack size = 2 BytecodeHelper.pushConstant(mv, i); // array index, stack size = 3 stackSize = 3; // primitive types must be boxed if (isPrimitive(arg)) { mv.visitIntInsn(getLoadInsn(arg), idx); String wrappedType = getWrappedClassDescriptor(arg); mv.visitMethodInsn( INVOKESTATIC, wrappedType, "valueOf", "(" + arg.getDescriptor() + ")L" + wrappedType + ";"); } else { mv.visitVarInsn(ALOAD, idx); // load argument i } idx += registerLen(arg); stackSize = Math.max(4, 3 + registerLen(arg)); mv.visitInsn(AASTORE); // store value into array } mv.visitVarInsn(ASTORE, arrayStore); // store array int arrayIndex = arrayStore; mv.visitVarInsn(ALOAD, 0); // load this mv.visitFieldInsn( GETFIELD, proxyName, CLOSURES_MAP_FIELD, "Ljava/util/Map;"); // load closure map mv.visitLdcInsn(name); // load method name mv.visitMethodInsn( INVOKEINTERFACE, "java/util/Map", "get", "(Ljava/lang/Object;)Ljava/lang/Object;"); arrayStore++; mv.visitVarInsn(ASTORE, arrayStore); // if null, test if wildcard exists Label notNull = new Label(); mv.visitIntInsn(ALOAD, arrayStore); mv.visitJumpInsn(IFNONNULL, notNull); mv.visitVarInsn(ALOAD, 0); // load this mv.visitFieldInsn( GETFIELD, proxyName, CLOSURES_MAP_FIELD, "Ljava/util/Map;"); // load closure map mv.visitLdcInsn("*"); // load wildcard mv.visitMethodInsn( INVOKEINTERFACE, "java/util/Map", "get", "(Ljava/lang/Object;)Ljava/lang/Object;"); mv.visitVarInsn(ASTORE, arrayStore); mv.visitLabel(notNull); mv.visitVarInsn(ALOAD, arrayStore); mv.visitMethodInsn( INVOKESTATIC, BytecodeHelper.getClassInternalName(this.getClass()), "ensureClosure", "(Ljava/lang/Object;)Lgroovy/lang/Closure;"); mv.visitVarInsn(ALOAD, arrayIndex); // load argument array stackSize++; mv.visitMethodInsn( INVOKEVIRTUAL, "groovy/lang/Closure", "call", "([Ljava/lang/Object;)Ljava/lang/Object;"); // call closure unwrapResult(mv, desc); mv.visitMaxs(stackSize, arrayStore + 1); mv.visitEnd(); // System.out.println("tmv.getText() = " + tmv.getText()); return EMPTY_VISITOR; }
private void putConstantOnStack(MethodVisitor methodVisitor, Object value) { methodVisitor.visitLdcInsn(value); }