コード例 #1
0
  private static String getInlineName(
      @NotNull CodegenContext codegenContext,
      @NotNull DeclarationDescriptor currentDescriptor,
      @NotNull JetTypeMapper typeMapper,
      @NotNull JvmFileClassesProvider fileClassesProvider) {
    if (currentDescriptor instanceof PackageFragmentDescriptor) {
      PsiFile file = getContainingFile(codegenContext);

      Type implementationOwnerType;
      if (file == null) {
        implementationOwnerType =
            CodegenContextUtil.getImplementationOwnerClassType(codegenContext);
      } else {
        implementationOwnerType =
            FileClassesPackage.getFileClassType(fileClassesProvider, (JetFile) file);
      }

      if (implementationOwnerType == null) {
        DeclarationDescriptor contextDescriptor = codegenContext.getContextDescriptor();
        //noinspection ConstantConditions
        throw new RuntimeException(
            "Couldn't find declaration for "
                + contextDescriptor.getContainingDeclaration().getName()
                + "."
                + contextDescriptor.getName()
                + "; context: "
                + codegenContext);
      }

      return implementationOwnerType.getInternalName();
    } else if (currentDescriptor instanceof ClassifierDescriptor) {
      Type type = typeMapper.mapType((ClassifierDescriptor) currentDescriptor);
      return type.getInternalName();
    } else if (currentDescriptor instanceof FunctionDescriptor) {
      ClassDescriptor descriptor =
          typeMapper
              .getBindingContext()
              .get(CodegenBinding.CLASS_FOR_CALLABLE, (FunctionDescriptor) currentDescriptor);
      if (descriptor != null) {
        Type type = typeMapper.mapType(descriptor);
        return type.getInternalName();
      }
    }

    // TODO: add suffix for special case
    String suffix =
        currentDescriptor.getName().isSpecial() ? "" : currentDescriptor.getName().asString();

    //noinspection ConstantConditions
    return getInlineName(
            codegenContext,
            currentDescriptor.getContainingDeclaration(),
            typeMapper,
            fileClassesProvider)
        + "$"
        + suffix;
  }
コード例 #2
0
 private void declareClass(
     ClassVisitor visitor,
     Collection<String> interfaceInternalNames,
     Type generatedType,
     Type superclassType) {
   visitor.visit(
       V1_6,
       ACC_PUBLIC,
       generatedType.getInternalName(),
       null,
       superclassType.getInternalName(),
       Iterables.toArray(interfaceInternalNames, String.class));
 }
コード例 #3
0
  // 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);
  }
コード例 #4
0
  @NotNull
  private InlineResult inlineMethod(
      @NotNull AnonymousObjectGeneration anonymousObjectGen,
      @NotNull FieldRemapper parentRemapper,
      @NotNull MethodVisitor deferringVisitor,
      @NotNull MethodNode sourceNode,
      @NotNull ParametersBuilder capturedBuilder,
      boolean isConstructor) {
    ReifiedTypeParametersUsages typeParametersToReify =
        inliningContext.reifedTypeInliner.reifyInstructions(sourceNode);
    Parameters parameters =
        isConstructor
            ? capturedBuilder.buildParameters()
            : getMethodParametersWithCaptured(capturedBuilder, sourceNode);

    RegeneratedLambdaFieldRemapper remapper =
        new RegeneratedLambdaFieldRemapper(
            oldObjectType.getInternalName(),
            newLambdaType.getInternalName(),
            parameters,
            anonymousObjectGen.getCapturedLambdasToInline(),
            parentRemapper,
            isConstructor);

    MethodInliner inliner =
        new MethodInliner(
            sourceNode,
            parameters,
            inliningContext.subInline(inliningContext.nameGenerator.subGenerator("lambda")),
            remapper,
            isSameModule,
            "Transformer for " + anonymousObjectGen.getOwnerInternalName(),
            sourceMapper,
            new InlineCallSiteInfo(
                anonymousObjectGen.getOwnerInternalName(),
                sourceNode.name,
                isConstructor
                    ? anonymousObjectGen.getNewConstructorDescriptor()
                    : sourceNode.desc));

    InlineResult result =
        inliner.doInline(
            deferringVisitor,
            new LocalVarRemapper(parameters, 0),
            false,
            LabelOwner.NOT_APPLICABLE);
    result.getReifiedTypeParametersUsages().mergeAll(typeParametersToReify);
    deferringVisitor.visitMaxs(-1, -1);
    return result;
  }
コード例 #5
0
ファイル: ClassWriter.java プロジェクト: tempbottle/ASM
 /**
  * Adds a number or string constant to the constant pool of the class being build. Does nothing if
  * the constant pool already contains a similar item.
  *
  * @param cst the value of the constant to be added to the constant pool. This parameter must be
  *     an {@link Integer}, a {@link Float}, a {@link Long}, a {@link Double}, a {@link String} or
  *     a {@link Type}.
  * @return a new or already existing constant item with the given value.
  */
 Item newConstItem(final Object cst) {
   if (cst instanceof Integer) {
     int val = ((Integer) cst).intValue();
     return newInteger(val);
   } else if (cst instanceof Byte) {
     int val = ((Byte) cst).intValue();
     return newInteger(val);
   } else if (cst instanceof Character) {
     int val = ((Character) cst).charValue();
     return newInteger(val);
   } else if (cst instanceof Short) {
     int val = ((Short) cst).intValue();
     return newInteger(val);
   } else if (cst instanceof Boolean) {
     int val = ((Boolean) cst).booleanValue() ? 1 : 0;
     return newInteger(val);
   } else if (cst instanceof Float) {
     float val = ((Float) cst).floatValue();
     return newFloat(val);
   } else if (cst instanceof Long) {
     long val = ((Long) cst).longValue();
     return newLong(val);
   } else if (cst instanceof Double) {
     double val = ((Double) cst).doubleValue();
     return newDouble(val);
   } else if (cst instanceof String) {
     return newString((String) cst);
   } else if (cst instanceof Type) {
     Type t = (Type) cst;
     return newClassItem(t.getSort() == Type.OBJECT ? t.getInternalName() : t.getDescriptor());
   } else {
     throw new IllegalArgumentException("value " + cst);
   }
 }
コード例 #6
0
 private void castFirstStackElement(MethodVisitor methodVisitor, Class<?> returnType) {
   if (returnType.isPrimitive()) {
     unboxType(methodVisitor, returnType);
   } else {
     methodVisitor.visitTypeInsn(CHECKCAST, Type.getInternalName(returnType));
   }
 }
コード例 #7
0
 private void boxType(MethodVisitor methodVisitor, Class<?> primitiveType) {
   Class<?> boxedType = BOXED_TYPES.get(primitiveType);
   methodVisitor.visitMethodInsn(
       INVOKESTATIC,
       Type.getInternalName(boxedType),
       "valueOf",
       "(" + Type.getDescriptor(primitiveType) + ")" + Type.getDescriptor(boxedType),
       false);
 }
コード例 #8
0
 private void assignTypeConverterField(MethodVisitor constructorVisitor, Type generatedType) {
   putThisOnStack(constructorVisitor);
   putSecondMethodArgumentOnStack(constructorVisitor);
   constructorVisitor.visitFieldInsn(
       PUTFIELD,
       generatedType.getInternalName(),
       TYPE_CONVERTER_FIELD_NAME,
       TYPE_CONVERTER_TYPE.getDescriptor());
 }
コード例 #9
0
 private void assignStateField(MethodVisitor constructorVisitor, Type generatedType) {
   putThisOnStack(constructorVisitor);
   putFirstMethodArgumentOnStack(constructorVisitor);
   constructorVisitor.visitFieldInsn(
       PUTFIELD,
       generatedType.getInternalName(),
       STATE_FIELD_NAME,
       MODEL_ELEMENT_STATE_TYPE.getDescriptor());
 }
コード例 #10
0
 private void invokeSuperConstructor(MethodVisitor constructorVisitor, Type superclassType) {
   putThisOnStack(constructorVisitor);
   constructorVisitor.visitMethodInsn(
       INVOKESPECIAL,
       superclassType.getInternalName(),
       CONSTRUCTOR_NAME,
       Type.getMethodDescriptor(Type.VOID_TYPE),
       false);
 }
コード例 #11
0
 private void invokeSuperMethod(MethodVisitor methodVisitor, Class<?> superClass, Method method) {
   putThisOnStack(methodVisitor);
   methodVisitor.visitMethodInsn(
       INVOKESPECIAL,
       Type.getInternalName(superClass),
       method.getName(),
       Type.getMethodDescriptor(method),
       false);
 }
コード例 #12
0
 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());
 }
コード例 #13
0
 private void assignDelegateField(
     MethodVisitor constructorVisitor, Type generatedType, Type delegateType) {
   putThisOnStack(constructorVisitor);
   putThirdMethodArgumentOnStack(constructorVisitor);
   constructorVisitor.visitFieldInsn(
       PUTFIELD,
       generatedType.getInternalName(),
       DELEGATE_FIELD_NAME,
       delegateType.getDescriptor());
 }
コード例 #14
0
  private void throwExceptionBecauseCalledOnItself(MethodVisitor methodVisitor) {
    String exceptionInternalName = Type.getInternalName(UnsupportedOperationException.class);
    methodVisitor.visitTypeInsn(NEW, exceptionInternalName);
    methodVisitor.visitInsn(DUP);
    putConstantOnStack(methodVisitor, "Calling setters of a managed type on itself is not allowed");

    String constructorDescriptor = Type.getMethodDescriptor(Type.VOID_TYPE, STRING_TYPE);
    methodVisitor.visitMethodInsn(
        INVOKESPECIAL, exceptionInternalName, CONSTRUCTOR_NAME, constructorDescriptor, false);
    methodVisitor.visitInsn(ATHROW);
  }
コード例 #15
0
 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));
 }
コード例 #16
0
 private void unboxType(MethodVisitor methodVisitor, Class<?> primitiveClass) {
   // Float f = (Float) tmp
   // f==null?0:f.floatValue()
   Class<?> boxedType = BOXED_TYPES.get(primitiveClass);
   Type primitiveType = Type.getType(primitiveClass);
   methodVisitor.visitTypeInsn(CHECKCAST, Type.getInternalName(boxedType));
   methodVisitor.visitInsn(DUP);
   Label exit = new Label();
   Label elseValue = new Label();
   methodVisitor.visitJumpInsn(IFNONNULL, elseValue);
   methodVisitor.visitInsn(POP);
   pushDefaultValue(methodVisitor, primitiveClass);
   methodVisitor.visitJumpInsn(GOTO, exit);
   methodVisitor.visitLabel(elseValue);
   methodVisitor.visitMethodInsn(
       INVOKEVIRTUAL,
       Type.getInternalName(boxedType),
       primitiveClass.getSimpleName() + "Value",
       Type.getMethodDescriptor(primitiveType),
       false);
   methodVisitor.visitLabel(exit);
 }
コード例 #17
0
 private void writeDelegatingToString(
     ClassVisitor visitor, Type generatedType, Type delegateType) {
   MethodVisitor methodVisitor =
       declareMethod(visitor, "toString", TO_STRING_METHOD_DESCRIPTOR, CONCRETE_SIGNATURE);
   putDelegateFieldValueOnStack(methodVisitor, generatedType, delegateType);
   methodVisitor.visitMethodInsn(
       INVOKEVIRTUAL,
       delegateType.getInternalName(),
       "getDisplayName",
       TO_STRING_METHOD_DESCRIPTOR,
       false);
   finishVisitingMethod(methodVisitor, ARETURN);
 }
コード例 #18
0
 private void invokeDelegateMethod(
     MethodVisitor methodVisitor, Type generatedType, Type delegateType, Method method) {
   putDelegateFieldValueOnStack(methodVisitor, generatedType, delegateType);
   Class<?>[] parameterTypes = method.getParameterTypes();
   for (int paramNo = 0; paramNo < parameterTypes.length; paramNo++) {
     putMethodArgumentOnStack(methodVisitor, Type.getType(parameterTypes[paramNo]), paramNo + 1);
   }
   methodVisitor.visitMethodInsn(
       INVOKEVIRTUAL,
       delegateType.getInternalName(),
       method.getName(),
       Type.getMethodDescriptor(method),
       false);
 }
コード例 #19
0
 private void unwrapResult(final MethodVisitor mv, final String desc) {
   Type returnType = Type.getReturnType(desc);
   if (returnType == Type.VOID_TYPE) {
     mv.visitInsn(POP);
     mv.visitInsn(RETURN);
   } else {
     if (isPrimitive(returnType)) {
       BytecodeHelper.unbox(mv, ClassHelper.make(returnType.getClassName()));
     } else {
       mv.visitTypeInsn(CHECKCAST, returnType.getInternalName());
     }
     mv.visitInsn(getReturnInsn(returnType));
   }
 }
コード例 #20
0
 private void writeHashCodeMethod(ClassVisitor visitor, Type generatedType) {
   MethodVisitor methodVisitor =
       declareMethod(visitor, "hashCode", HASH_CODE_METHOD_DESCRIPTOR, null);
   methodVisitor.visitVarInsn(ALOAD, 0);
   methodVisitor.visitMethodInsn(
       INVOKEVIRTUAL,
       generatedType.getInternalName(),
       "getBackingNode",
       GET_BACKING_NODE_METHOD_DESCRIPTOR,
       false);
   methodVisitor.visitMethodInsn(
       INVOKEINTERFACE, MUTABLE_MODEL_NODE_TYPE, "hashCode", HASH_CODE_METHOD_DESCRIPTOR, true);
   methodVisitor.visitInsn(IRETURN);
   finishVisitingMethod(methodVisitor, Opcodes.IRETURN);
 }
コード例 #21
0
ファイル: Compiler.java プロジェクト: damc-dev/byteman
  public static Class getHelperAdapter(Rule rule, Class helperClass, boolean compileToBytecode)
      throws CompileException {
    Class adapterClass;
    // ok we have to create the adapter class

    // n.b. we don't bother synchronizing here -- if another rule is racing to create an adapter
    // in parallel we don't really care about generating two of them -- we can use whichever
    // one gets installed last

    try {
      String helperName = Type.getInternalName(helperClass);
      String compiledHelperName;

      // we put the helper in the
      if (compileToBytecode) {
        compiledHelperName = helperName + "_HelperAdapter_Compiled_" + nextId();
      } else {
        compiledHelperName = helperName + "_HelperAdapter_Interpreted_" + nextId();
      }

      byte[] classBytes =
          compileBytes(rule, helperClass, helperName, compiledHelperName, compileToBytecode);
      String externalName = compiledHelperName.replace('/', '.');
      // dump the compiled class bytes if required
      Transformer.maybeDumpClass(externalName, classBytes);
      // ensure the class is loaded
      // think we need to load the generated helper using the class loader of the trigger class
      ClassLoader loader = rule.getLoader();
      adapterClass = loadHelperAdapter(loader, externalName, classBytes);
    } catch (CompileException ce) {
      throw ce;
    } catch (Throwable th) {
      if (compileToBytecode) {
        throw new CompileException(
            "Compiler.createHelperAdapter : exception creating compiled helper adapter for "
                + helperClass.getName(),
            th);
      } else {
        throw new CompileException(
            "Compiler.createHelperAdapter : exception creating interpreted helper adapter for "
                + helperClass.getName(),
            th);
      }
    }

    return adapterClass;
  }
コード例 #22
0
  private void writeSetMethod(ClassVisitor visitor, Type generatedType, ModelProperty<?> property) {
    if (property.isWritable() && property.getSchema() instanceof ScalarValueSchema) {

      // TODO - should we support this?
      // Adds a void $propName(Object value) method that sets the value
      MethodVisitor methodVisitor =
          declareMethod(
              visitor,
              property.getName(),
              Type.getMethodDescriptor(Type.VOID_TYPE, OBJECT_TYPE),
              null);
      putThisOnStack(methodVisitor);
      putFirstMethodArgumentOnStack(methodVisitor);
      methodVisitor.visitMethodInsn(
          INVOKEVIRTUAL,
          generatedType.getInternalName(),
          property.getSetter().getName(),
          Type.getMethodDescriptor(Type.VOID_TYPE, OBJECT_TYPE),
          false);
      finishVisitingMethod(methodVisitor);
    }
  }
コード例 #23
0
 private void writeEqualsMethod(ClassVisitor cw, Type generatedType) {
   MethodVisitor methodVisitor =
       cw.visitMethod(Opcodes.ACC_PUBLIC, "equals", EQUALS_METHOD_DESCRIPTOR, null, null);
   methodVisitor.visitCode();
   methodVisitor.visitVarInsn(ALOAD, 0);
   methodVisitor.visitVarInsn(ALOAD, 1);
   Label notSameLabel = new Label();
   methodVisitor.visitJumpInsn(IF_ACMPNE, notSameLabel);
   methodVisitor.visitInsn(ICONST_1);
   methodVisitor.visitInsn(IRETURN);
   methodVisitor.visitLabel(notSameLabel);
   methodVisitor.visitVarInsn(ALOAD, 1);
   methodVisitor.visitTypeInsn(INSTANCEOF, MANAGED_INSTANCE_TYPE);
   Label notManagedInstanceLabel = new Label();
   methodVisitor.visitJumpInsn(IFNE, notManagedInstanceLabel);
   methodVisitor.visitInsn(ICONST_0);
   methodVisitor.visitInsn(IRETURN);
   methodVisitor.visitLabel(notManagedInstanceLabel);
   methodVisitor.visitVarInsn(ALOAD, 0);
   methodVisitor.visitMethodInsn(
       INVOKEVIRTUAL,
       generatedType.getInternalName(),
       "getBackingNode",
       GET_BACKING_NODE_METHOD_DESCRIPTOR,
       false);
   methodVisitor.visitVarInsn(ALOAD, 1);
   methodVisitor.visitTypeInsn(CHECKCAST, MANAGED_INSTANCE_TYPE);
   methodVisitor.visitMethodInsn(
       INVOKEINTERFACE,
       MANAGED_INSTANCE_TYPE,
       "getBackingNode",
       GET_BACKING_NODE_METHOD_DESCRIPTOR,
       true);
   methodVisitor.visitMethodInsn(
       INVOKEINTERFACE, MUTABLE_MODEL_NODE_TYPE, "equals", EQUALS_METHOD_DESCRIPTOR, true);
   finishVisitingMethod(methodVisitor, Opcodes.IRETURN);
 }
コード例 #24
0
  public byte[] buildClass(ClassDefinition core)
      throws IOException, IntrospectionException, SecurityException, IllegalArgumentException,
          ClassNotFoundException, NoSuchMethodException, IllegalAccessException,
          InvocationTargetException, InstantiationException, NoSuchFieldException {

    Class coreKlazz = core.getDefinedClass();
    String coreName = coreKlazz.getName();
    String wrapperName = coreName + "Wrapper";

    ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
    FieldVisitor fv;
    MethodVisitor mv;

    cw.visit(
        V1_5,
        ACC_PUBLIC + ACC_SUPER,
        BuildUtils.getInternalType(wrapperName),
        BuildUtils.getTypeDescriptor(coreName)
            + "Lorg/drools/factmodel/traits/CoreWrapper<"
            + BuildUtils.getTypeDescriptor(coreName)
            + ">;",
        BuildUtils.getInternalType(coreName),
        new String[] {
          Type.getInternalName(CoreWrapper.class), Type.getInternalName(Externalizable.class)
        });

    {
      fv = cw.visitField(ACC_PRIVATE, "core", BuildUtils.getTypeDescriptor(coreName), null, null);
      fv.visitEnd();
    }
    {
      fv =
          cw.visitField(
              ACC_PRIVATE,
              TraitableBean.MAP_FIELD_NAME,
              Type.getDescriptor(Map.class),
              "Ljava/util/Map<Ljava/lang/String;Ljava/lang/Object;>;",
              null);
      fv.visitEnd();
    }
    {
      fv =
          cw.visitField(
              ACC_PRIVATE,
              TraitableBean.TRAITSET_FIELD_NAME,
              Type.getDescriptor(Map.class),
              "Ljava/util/Map<Ljava/lang/String;Lorg/drools/factmodel/traits/Thing;>;",
              null);
      fv.visitEnd();
    }

    {
      mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
      mv.visitCode();

      mv.visitVarInsn(ALOAD, 0);
      mv.visitMethodInsn(INVOKESPECIAL, BuildUtils.getInternalType(coreName), "<init>", "()V");

      //            mv.visitVarInsn( ALOAD, 0 );
      //            mv.visitTypeInsn( NEW, Type.getInternalName( HashMap.class ) );
      //            mv.visitInsn( DUP );
      //            mv.visitMethodInsn( INVOKESPECIAL, Type.getInternalName( HashMap.class ),
      // "<init>", "()V" );
      //            mv.visitFieldInsn( PUTFIELD,
      //                    BuildUtils.getInternalType( wrapperName ),
      //                    TraitableBean.MAP_FIELD_NAME,
      //                    Type.getDescriptor( Map.class ) );

      //            mv.visitVarInsn( ALOAD, 0 );
      //            mv.visitTypeInsn( NEW, Type.getInternalName( VetoableTypedMap.class ) );
      //            mv.visitInsn( DUP );
      //            mv.visitTypeInsn( NEW, Type.getInternalName( HashMap.class ) );
      //            mv.visitInsn( DUP );
      //            mv.visitMethodInsn( INVOKESPECIAL, Type.getInternalName( HashMap.class ),
      // "<init>", "()V" );
      //            mv.visitMethodInsn( INVOKESPECIAL, Type.getInternalName( VetoableTypedMap.class
      // ), "<init>", "(" + Type.getDescriptor( Map.class ) + ")V" );
      //            mv.visitFieldInsn( PUTFIELD,
      //                    BuildUtils.getInternalType( wrapperName ),
      //                    TraitableBean.TRAITSET_FIELD_NAME,
      //                    Type.getDescriptor( Map.class ) );

      mv.visitInsn(RETURN);
      mv.visitMaxs(0, 0);
      mv.visitEnd();
    }
    if (coreKlazz == null || needsMethod(coreKlazz, "getCore")) {
      {
        mv =
            cw.visitMethod(
                ACC_PUBLIC,
                "getCore",
                "()" + Type.getDescriptor(Object.class),
                "()" + BuildUtils.getTypeDescriptor(coreName),
                null);
        mv.visitCode();
        mv.visitVarInsn(ALOAD, 0);
        mv.visitFieldInsn(
            GETFIELD,
            BuildUtils.getInternalType(wrapperName),
            "core",
            BuildUtils.getTypeDescriptor(coreName));
        mv.visitInsn(ARETURN);
        mv.visitMaxs(0, 0);
        mv.visitEnd();
      }
    }
    if (coreKlazz == null || needsMethod(coreKlazz, "getDynamicProperties")) {
      {
        mv =
            cw.visitMethod(
                ACC_PUBLIC,
                "getDynamicProperties",
                "()" + Type.getDescriptor(Map.class),
                "()Ljava/util/Map<Ljava/lang/String;Ljava/lang/Object;>;",
                null);
        mv.visitCode();
        mv.visitVarInsn(ALOAD, 0);
        mv.visitFieldInsn(
            GETFIELD,
            BuildUtils.getInternalType(wrapperName),
            TraitableBean.MAP_FIELD_NAME,
            Type.getDescriptor(Map.class));
        mv.visitInsn(ARETURN);
        mv.visitMaxs(0, 0);
        mv.visitEnd();

        mv =
            cw.visitMethod(
                ACC_PUBLIC,
                "setDynamicProperties",
                "(" + Type.getDescriptor(Map.class) + ")V",
                "(Ljava/util/Map<Ljava/lang/String;Ljava/lang/Object;>;)V",
                null);
        mv.visitCode();
        mv.visitVarInsn(ALOAD, 0);
        mv.visitVarInsn(ALOAD, 1);
        mv.visitFieldInsn(
            PUTFIELD,
            BuildUtils.getInternalType(wrapperName),
            TraitableBean.MAP_FIELD_NAME,
            Type.getDescriptor(Map.class));
        mv.visitInsn(RETURN);
        mv.visitMaxs(0, 0);
        mv.visitEnd();
      }
    }
    if (coreKlazz == null || needsMethod(coreKlazz, "getTraitMap")) {
      {
        mv =
            cw.visitMethod(
                ACC_PUBLIC,
                "getTraitMap",
                "()" + Type.getDescriptor(Map.class),
                "()Ljava/util/Map<Ljava/lang/String;Lorg/drools/factmodel/traits/Thing;>;",
                null);
        mv.visitCode();
        mv.visitVarInsn(ALOAD, 0);
        mv.visitFieldInsn(
            GETFIELD,
            BuildUtils.getInternalType(wrapperName),
            TraitableBean.TRAITSET_FIELD_NAME,
            Type.getDescriptor(Map.class));
        Label l0 = new Label();
        mv.visitJumpInsn(IFNONNULL, l0);
        mv.visitVarInsn(ALOAD, 0);
        mv.visitTypeInsn(NEW, Type.getInternalName(VetoableTypedMap.class));
        mv.visitInsn(DUP);
        mv.visitTypeInsn(NEW, Type.getInternalName(HashMap.class));
        mv.visitInsn(DUP);
        mv.visitMethodInsn(INVOKESPECIAL, Type.getInternalName(HashMap.class), "<init>", "()V");
        mv.visitMethodInsn(
            INVOKESPECIAL,
            Type.getInternalName(VetoableTypedMap.class),
            "<init>",
            "(" + Type.getDescriptor(Map.class) + ")V");
        mv.visitFieldInsn(
            PUTFIELD,
            BuildUtils.getInternalType(wrapperName),
            TraitableBean.TRAITSET_FIELD_NAME,
            Type.getDescriptor(Map.class));
        mv.visitLabel(l0);
        mv.visitVarInsn(ALOAD, 0);
        mv.visitFieldInsn(
            GETFIELD,
            BuildUtils.getInternalType(wrapperName),
            TraitableBean.TRAITSET_FIELD_NAME,
            Type.getDescriptor(Map.class));
        mv.visitInsn(ARETURN);
        mv.visitMaxs(0, 0);
        mv.visitEnd();
      }
    }
    if (coreKlazz == null || needsMethod(coreKlazz, "setTraitMap", Map.class)) {
      {
        mv = cw.visitMethod(ACC_PUBLIC, "setTraitMap", "(Ljava/util/Map;)V", null, null);
        mv.visitCode();
        mv.visitVarInsn(ALOAD, 0);
        mv.visitTypeInsn(NEW, Type.getInternalName(VetoableTypedMap.class));
        mv.visitInsn(DUP);
        mv.visitVarInsn(ALOAD, 1);
        mv.visitMethodInsn(
            INVOKESPECIAL,
            Type.getInternalName(VetoableTypedMap.class),
            "<init>",
            "(" + Type.getDescriptor(Map.class) + ")V");
        mv.visitFieldInsn(
            PUTFIELD,
            BuildUtils.getInternalType(wrapperName),
            TraitableBean.TRAITSET_FIELD_NAME,
            Type.getDescriptor(Map.class));
        mv.visitInsn(RETURN);
        mv.visitMaxs(0, 0);
        mv.visitEnd();
      }
    }
    if (coreKlazz == null || needsMethod(coreKlazz, "addTrait", String.class, Thing.class)) {
      {
        mv =
            cw.visitMethod(
                ACC_PUBLIC,
                "addTrait",
                "(" + Type.getDescriptor(String.class) + Type.getDescriptor(Thing.class) + ")V",
                "(" + Type.getDescriptor(String.class) + Type.getDescriptor(Thing.class) + ")V",
                null);
        mv.visitCode();
        mv.visitVarInsn(ALOAD, 0);
        mv.visitMethodInsn(
            INVOKEVIRTUAL,
            BuildUtils.getInternalType(wrapperName),
            "getTraitMap",
            "()" + Type.getDescriptor(Map.class));
        mv.visitTypeInsn(CHECKCAST, Type.getInternalName(VetoableTypedMap.class));
        mv.visitVarInsn(ALOAD, 1);
        mv.visitVarInsn(ALOAD, 2);
        mv.visitMethodInsn(
            INVOKEVIRTUAL,
            Type.getInternalName(VetoableTypedMap.class),
            "putSafe",
            "("
                + Type.getDescriptor(String.class)
                + Type.getDescriptor(Thing.class)
                + ")"
                + Type.getDescriptor(Thing.class));
        mv.visitInsn(POP);
        mv.visitInsn(RETURN);
        mv.visitMaxs(0, 0);
        mv.visitEnd();
      }
    }
    if (coreKlazz == null || needsMethod(coreKlazz, "getTrait", String.class)) {
      {
        mv =
            cw.visitMethod(
                ACC_PUBLIC,
                "getTrait",
                "(" + Type.getDescriptor(String.class) + ")" + Type.getDescriptor(Thing.class),
                "(" + Type.getDescriptor(String.class) + ")" + Type.getDescriptor(Thing.class),
                null);
        mv.visitCode();
        mv.visitVarInsn(ALOAD, 0);
        mv.visitMethodInsn(
            INVOKEVIRTUAL,
            BuildUtils.getInternalType(wrapperName),
            "getTraitMap",
            "()" + Type.getDescriptor(Map.class));
        mv.visitVarInsn(ALOAD, 1);
        mv.visitMethodInsn(
            INVOKEINTERFACE,
            Type.getInternalName(Map.class),
            "get",
            "(" + Type.getDescriptor(Object.class) + ")" + Type.getDescriptor(Object.class));
        mv.visitTypeInsn(CHECKCAST, Type.getInternalName(Thing.class));
        mv.visitInsn(ARETURN);
        mv.visitMaxs(0, 0);
        mv.visitEnd();
      }
    }
    if (coreKlazz == null || needsMethod(coreKlazz, "hasTrait", String.class)) {
      {
        mv =
            cw.visitMethod(
                ACC_PUBLIC, "hasTrait", "(" + Type.getDescriptor(String.class) + ")Z", null, null);
        mv.visitCode();
        mv.visitVarInsn(ALOAD, 0);
        mv.visitMethodInsn(
            INVOKEVIRTUAL,
            BuildUtils.getInternalType(wrapperName),
            "getTraitMap",
            "()" + Type.getDescriptor(Map.class));
        mv.visitVarInsn(ALOAD, 1);
        mv.visitMethodInsn(
            INVOKEINTERFACE,
            Type.getInternalName(Map.class),
            "containsKey",
            "(" + Type.getDescriptor(Object.class) + ")Z");
        mv.visitInsn(IRETURN);
        mv.visitMaxs(0, 0);
        mv.visitEnd();
      }
    }
    if (coreKlazz == null || needsMethod(coreKlazz, "removeTrait", String.class)) {
      {
        mv =
            cw.visitMethod(
                ACC_PUBLIC,
                "removeTrait",
                "(" + Type.getDescriptor(String.class) + ")" + Type.getDescriptor(Thing.class),
                "(" + Type.getDescriptor(String.class) + ")" + Type.getDescriptor(Thing.class),
                null);
        mv.visitCode();
        mv.visitVarInsn(ALOAD, 0);
        mv.visitMethodInsn(
            INVOKEVIRTUAL,
            BuildUtils.getInternalType(wrapperName),
            "getTraitMap",
            "()" + Type.getDescriptor(Map.class));
        mv.visitVarInsn(ALOAD, 1);
        mv.visitMethodInsn(
            INVOKEINTERFACE,
            Type.getInternalName(Map.class),
            "remove",
            "(" + Type.getDescriptor(Object.class) + ")" + Type.getDescriptor(Object.class));
        mv.visitTypeInsn(CHECKCAST, Type.getInternalName(Thing.class));
        mv.visitInsn(ARETURN);
        mv.visitMaxs(0, 0);
        mv.visitEnd();
      }
    }
    if (coreKlazz == null || needsMethod(coreKlazz, "getTraits")) {
      {
        mv =
            cw.visitMethod(
                ACC_PUBLIC,
                "getTraits",
                "()" + Type.getDescriptor(Collection.class),
                "()Ljava/util/Collection<Ljava/lang/String;>;",
                null);
        mv.visitCode();
        mv.visitVarInsn(ALOAD, 0);
        mv.visitMethodInsn(
            INVOKEVIRTUAL,
            BuildUtils.getInternalType(wrapperName),
            "getTraitMap",
            "()" + Type.getDescriptor(Map.class));
        mv.visitMethodInsn(
            INVOKEINTERFACE,
            Type.getInternalName(Map.class),
            "keySet",
            "()" + Type.getDescriptor(Set.class));
        mv.visitInsn(ARETURN);
        mv.visitMaxs(0, 0);
        mv.visitEnd();
      }
    }

    {
      mv =
          cw.visitMethod(
              ACC_PUBLIC,
              "writeExternal",
              "(" + Type.getDescriptor(ObjectOutput.class) + ")V",
              null,
              new String[] {Type.getInternalName(IOException.class)});
      mv.visitCode();

      mv.visitVarInsn(ALOAD, 1);
      mv.visitVarInsn(ALOAD, 0);
      mv.visitMethodInsn(
          INVOKEVIRTUAL,
          BuildUtils.getInternalType(wrapperName),
          "getCore",
          "()" + Type.getDescriptor(Object.class));
      mv.visitMethodInsn(
          INVOKEINTERFACE,
          Type.getInternalName(ObjectOutput.class),
          "writeObject",
          "(" + Type.getDescriptor(Object.class) + ")V");

      mv.visitVarInsn(ALOAD, 1);
      mv.visitVarInsn(ALOAD, 0);
      mv.visitFieldInsn(
          GETFIELD,
          BuildUtils.getInternalType(wrapperName),
          TraitableBean.MAP_FIELD_NAME,
          Type.getDescriptor(Map.class));
      mv.visitMethodInsn(
          INVOKEINTERFACE,
          Type.getInternalName(ObjectOutput.class),
          "writeObject",
          "(" + Type.getDescriptor(Object.class) + ")V");

      mv.visitVarInsn(ALOAD, 1);
      mv.visitVarInsn(ALOAD, 0);
      mv.visitFieldInsn(
          GETFIELD,
          BuildUtils.getInternalType(wrapperName),
          TraitableBean.TRAITSET_FIELD_NAME,
          Type.getDescriptor(Map.class));
      mv.visitMethodInsn(
          INVOKEINTERFACE,
          Type.getInternalName(ObjectOutput.class),
          "writeObject",
          "(" + Type.getDescriptor(Object.class) + ")V");

      mv.visitInsn(RETURN);
      mv.visitMaxs(0, 0);
      mv.visitEnd();
    }
    {
      mv =
          cw.visitMethod(
              ACC_PUBLIC,
              "readExternal",
              "(" + Type.getDescriptor(ObjectInput.class) + ")V",
              null,
              new String[] {
                Type.getInternalName(IOException.class),
                Type.getInternalName(ClassNotFoundException.class)
              });
      mv.visitCode();

      mv.visitVarInsn(ALOAD, 0);
      mv.visitVarInsn(ALOAD, 1);
      mv.visitMethodInsn(
          INVOKEINTERFACE,
          Type.getInternalName(ObjectInput.class),
          "readObject",
          "()" + Type.getDescriptor(Object.class));
      mv.visitTypeInsn(CHECKCAST, BuildUtils.getInternalType(coreName));
      mv.visitFieldInsn(
          PUTFIELD,
          BuildUtils.getInternalType(wrapperName),
          "core",
          BuildUtils.getTypeDescriptor(coreName));

      mv.visitVarInsn(ALOAD, 0);
      mv.visitVarInsn(ALOAD, 1);
      mv.visitMethodInsn(
          INVOKEINTERFACE,
          Type.getInternalName(ObjectInput.class),
          "readObject",
          "()" + Type.getDescriptor(Object.class));
      mv.visitTypeInsn(CHECKCAST, Type.getInternalName(Map.class));
      mv.visitFieldInsn(
          PUTFIELD,
          BuildUtils.getInternalType(wrapperName),
          TraitableBean.MAP_FIELD_NAME,
          Type.getDescriptor(Map.class));

      mv.visitVarInsn(ALOAD, 0);
      mv.visitVarInsn(ALOAD, 1);
      mv.visitMethodInsn(
          INVOKEINTERFACE,
          Type.getInternalName(ObjectInput.class),
          "readObject",
          "()" + Type.getDescriptor(Object.class));
      mv.visitTypeInsn(CHECKCAST, Type.getInternalName(Map.class));
      mv.visitFieldInsn(
          PUTFIELD,
          BuildUtils.getInternalType(wrapperName),
          TraitableBean.TRAITSET_FIELD_NAME,
          Type.getDescriptor(Map.class));

      mv.visitInsn(RETURN);
      mv.visitMaxs(0, 0);
      mv.visitEnd();
    }

    {
      mv =
          cw.visitMethod(
              ACC_PUBLIC, "init", "(" + BuildUtils.getTypeDescriptor(coreName) + ")V", null, null);
      mv.visitCode();
      mv.visitVarInsn(ALOAD, 0);
      mv.visitVarInsn(ALOAD, 1);
      mv.visitFieldInsn(
          PUTFIELD,
          BuildUtils.getInternalType(wrapperName),
          "core",
          BuildUtils.getTypeDescriptor(coreName));
      mv.visitInsn(RETURN);
      mv.visitMaxs(0, 0);
      mv.visitEnd();
    }

    Method[] ms = coreKlazz.getMethods();
    for (Method method : ms) {
      if (Modifier.isFinal(method.getModifiers())) {
        continue;
      }

      String signature = TraitFactory.buildSignature(method);
      {
        mv = cw.visitMethod(ACC_PUBLIC, method.getName(), signature, null, null);
        mv.visitCode();
        mv.visitVarInsn(ALOAD, 0);
        mv.visitFieldInsn(
            GETFIELD,
            BuildUtils.getInternalType(wrapperName),
            "core",
            BuildUtils.getTypeDescriptor(coreName));
        int j = 1;
        for (Class arg : method.getParameterTypes()) {
          mv.visitVarInsn(BuildUtils.varType(arg.getName()), j++);
        }
        mv.visitMethodInsn(
            INVOKEVIRTUAL, BuildUtils.getInternalType(coreName), method.getName(), signature);

        mv.visitInsn(BuildUtils.returnType(method.getReturnType().getName()));
        int stack = TraitFactory.getStackSize(method);
        mv.visitMaxs(0, 0);
        mv.visitEnd();
      }
    }

    {
      mv =
          cw.visitMethod(
              ACC_PUBLIC + ACC_BRIDGE + ACC_SYNTHETIC,
              "init",
              "(" + Type.getDescriptor(Object.class) + ")V",
              null,
              null);
      mv.visitCode();
      mv.visitVarInsn(ALOAD, 0);
      mv.visitVarInsn(ALOAD, 1);
      mv.visitTypeInsn(CHECKCAST, BuildUtils.getInternalType(coreName));
      mv.visitMethodInsn(
          INVOKEVIRTUAL,
          BuildUtils.getInternalType(wrapperName),
          "init",
          "(" + BuildUtils.getTypeDescriptor(coreName) + ")V");
      mv.visitInsn(RETURN);
      mv.visitMaxs(0, 0);
      mv.visitEnd();
    }

    {
      mv =
          cw.visitMethod(
              ACC_PUBLIC,
              "denyTrait",
              "(" + Type.getDescriptor(Class.class) + ")V",
              null,
              new String[] {Type.getInternalName(LogicalTypeInconsistencyException.class)});
      mv.visitCode();
      mv.visitVarInsn(ALOAD, 0);
      mv.visitFieldInsn(
          GETFIELD,
          BuildUtils.getInternalType(wrapperName),
          TraitableBean.TRAITSET_FIELD_NAME,
          Type.getDescriptor(Map.class));
      mv.visitTypeInsn(CHECKCAST, Type.getInternalName(VetoableTypedMap.class));
      mv.visitVarInsn(ALOAD, 1);
      mv.visitMethodInsn(
          INVOKEVIRTUAL,
          Type.getInternalName(VetoableTypedMap.class),
          "addToVetoable",
          "(" + Type.getDescriptor(Class.class) + ")V");
      mv.visitInsn(RETURN);
      mv.visitMaxs(0, 0);
      mv.visitEnd();
    }
    {
      mv =
          cw.visitMethod(
              ACC_PUBLIC, "allowTrait", "(" + Type.getDescriptor(Class.class) + ")V", null, null);
      mv.visitCode();
      mv.visitVarInsn(ALOAD, 0);
      mv.visitFieldInsn(
          GETFIELD,
          BuildUtils.getInternalType(wrapperName),
          TraitableBean.TRAITSET_FIELD_NAME,
          Type.getDescriptor(Map.class));
      mv.visitTypeInsn(CHECKCAST, Type.getInternalName(VetoableTypedMap.class));
      mv.visitVarInsn(ALOAD, 1);
      mv.visitMethodInsn(
          INVOKEVIRTUAL,
          Type.getInternalName(VetoableTypedMap.class),
          "removeFromVetoable",
          "(" + Type.getDescriptor(Class.class) + ")V");
      mv.visitInsn(RETURN);
      mv.visitMaxs(0, 0);
      mv.visitEnd();
    }
    cw.visitEnd();

    return cw.toByteArray();
  }
コード例 #25
0
public class ManagedProxyClassGenerator extends AbstractProxyClassGenerator {
  /*
     Note: there is deliberately no internal synchronizing or caching at this level.
     Class generation should be performed behind a ManagedProxyFactory.
  */

  private static final String STATE_FIELD_NAME = "$state";
  private static final String TYPE_CONVERTER_FIELD_NAME = "$typeConverter";
  private static final String MANAGED_TYPE_FIELD_NAME = "$managedType";
  private static final String DELEGATE_FIELD_NAME = "$delegate";
  private static final String CAN_CALL_SETTERS_FIELD_NAME = "$canCallSetters";
  private static final Type OBJECT_TYPE = Type.getType(Object.class);
  private static final Type STRING_TYPE = Type.getType(String.class);
  private static final Type CLASS_TYPE = Type.getType(Class.class);
  private static final Type CLOSURE_TYPE = Type.getType(Closure.class);
  private static final Type TYPE_CONVERTER_TYPE = Type.getType(TypeConverter.class);
  private static final Type MODELTYPE_TYPE = Type.getType(ModelType.class);
  private static final Type MODEL_ELEMENT_STATE_TYPE = Type.getType(ModelElementState.class);
  private static final String STATE_SET_METHOD_DESCRIPTOR =
      Type.getMethodDescriptor(Type.VOID_TYPE, STRING_TYPE, OBJECT_TYPE);
  private static final String STATE_GET_METHOD_DESCRIPTOR =
      Type.getMethodDescriptor(OBJECT_TYPE, STRING_TYPE);
  private static final String STATE_APPLY_METHOD_DESCRIPTOR =
      Type.getMethodDescriptor(Type.VOID_TYPE, STRING_TYPE, CLOSURE_TYPE);
  private static final String MANAGED_INSTANCE_TYPE = Type.getInternalName(ManagedInstance.class);
  private static final String NO_DELEGATE_CONSTRUCTOR_DESCRIPTOR =
      Type.getMethodDescriptor(Type.VOID_TYPE, MODEL_ELEMENT_STATE_TYPE, TYPE_CONVERTER_TYPE);
  private static final String TO_STRING_METHOD_DESCRIPTOR = Type.getMethodDescriptor(STRING_TYPE);
  private static final String MUTABLE_MODEL_NODE_TYPE =
      Type.getInternalName(MutableModelNode.class);
  private static final String GET_BACKING_NODE_METHOD_DESCRIPTOR =
      Type.getMethodDescriptor(Type.getType(MutableModelNode.class));
  private static final String MODELTYPE_INTERNAL_NAME = MODELTYPE_TYPE.getInternalName();
  private static final String MODELTYPE_OF_METHOD_DESCRIPTOR =
      Type.getMethodDescriptor(MODELTYPE_TYPE, CLASS_TYPE);
  private static final String GET_MANAGED_TYPE_METHOD_DESCRIPTOR =
      Type.getMethodDescriptor(MODELTYPE_TYPE);
  private static final String GET_PROPERTY_MISSING_METHOD_DESCRIPTOR =
      Type.getMethodDescriptor(OBJECT_TYPE, STRING_TYPE);
  private static final String MISSING_PROPERTY_EXCEPTION_TYPE =
      Type.getInternalName(MissingPropertyException.class);
  private static final String CLASS_INTERNAL_NAME = Type.getInternalName(Class.class);
  private static final String FOR_NAME_METHOD_DESCRIPTOR =
      Type.getMethodDescriptor(CLASS_TYPE, STRING_TYPE);
  private static final String HASH_CODE_METHOD_DESCRIPTOR =
      Type.getMethodDescriptor(Type.getType(int.class));
  private static final String EQUALS_METHOD_DESCRIPTOR =
      Type.getMethodDescriptor(Type.getType(boolean.class), OBJECT_TYPE);
  private static final String OBJECT_ARRAY_TYPE = Type.getInternalName(Object[].class);
  private static final String MISSING_METHOD_EXCEPTION_TYPE =
      Type.getInternalName(MissingMethodException.class);
  private static final String MISSING_PROPERTY_CONSTRUCTOR_DESCRIPTOR =
      Type.getMethodDescriptor(Type.VOID_TYPE, STRING_TYPE, CLASS_TYPE);
  private static final String METHOD_MISSING_METHOD_DESCRIPTOR =
      Type.getMethodDescriptor(OBJECT_TYPE, STRING_TYPE, OBJECT_TYPE);
  private static final String SET_PROPERTY_MISSING_METHOD_DESCRIPTOR =
      Type.getMethodDescriptor(OBJECT_TYPE, STRING_TYPE, OBJECT_TYPE);
  private static final String MISSING_METHOD_EXCEPTION_CONSTRUCTOR_DESCRIPTOR =
      Type.getMethodDescriptor(
          Type.VOID_TYPE, STRING_TYPE, CLASS_TYPE, Type.getType(Object[].class));
  private static final Equivalence<Method> METHOD_EQUIVALENCE = new MethodSignatureEquivalence();
  private static final String SET_OBJECT_PROPERTY_DESCRIPTOR =
      Type.getMethodDescriptor(Type.VOID_TYPE, OBJECT_TYPE);
  private static final String COERCE_TO_SCALAR_DESCRIPTOR =
      Type.getMethodDescriptor(OBJECT_TYPE, OBJECT_TYPE, CLASS_TYPE, Type.getType(boolean.class));
  private static final String MODEL_ELEMENT_STATE_TYPE_INTERNAL_NAME =
      MODEL_ELEMENT_STATE_TYPE.getInternalName();
  private static final Map<Class<?>, Class<?>> BOXED_TYPES =
      ImmutableMap.<Class<?>, Class<?>>builder()
          .put(byte.class, Byte.class)
          .put(short.class, Short.class)
          .put(int.class, Integer.class)
          .put(boolean.class, Boolean.class)
          .put(float.class, Float.class)
          .put(char.class, Character.class)
          .put(double.class, Double.class)
          .put(long.class, Long.class)
          .build();

  /**
   * Generates an implementation of the given managed type.
   *
   * <p>The generated class will implement/extend the managed type and will:
   *
   * <ul>
   *   <li>provide implementations for abstract getters and setters that delegate to model nodes
   *   <li>provide a `toString()` implementation
   *   <li>mix-in implementation of {@link ManagedInstance}
   *   <li>provide a constructor that accepts a {@link ModelElementState}, which will be used to
   *       implement the above.
   * </ul>
   *
   * In case a delegate schema is supplied, the generated class will also have:
   *
   * <ul>
   *   <li>a constructor that also takes a delegate instance
   *   <li>methods that call through to the delegate instance
   * </ul>
   */
  public <T, M extends T, D extends T> Class<? extends M> generate(
      StructSchema<M> viewSchema, @Nullable StructSchema<D> delegateSchema) {
    if (delegateSchema != null
        && Modifier.isAbstract(delegateSchema.getType().getConcreteClass().getModifiers())) {
      throw new IllegalArgumentException("Delegate type must be null or a non-abstract type");
    }
    ClassWriter visitor = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);

    ModelType<M> viewType = viewSchema.getType();

    StringBuilder generatedTypeNameBuilder = new StringBuilder(viewType.getName());
    if (delegateSchema != null) {
      generatedTypeNameBuilder
          .append("$BackedBy_")
          .append(delegateSchema.getType().getName().replaceAll("\\.", "_"));
    } else {
      generatedTypeNameBuilder.append("$Impl");
    }

    String generatedTypeName = generatedTypeNameBuilder.toString();
    Type generatedType = Type.getType("L" + generatedTypeName.replaceAll("\\.", "/") + ";");

    Class<M> viewClass = viewType.getConcreteClass();
    Class<?> superclass;
    final ImmutableSet.Builder<String> interfacesToImplement = ImmutableSet.builder();
    final ImmutableSet.Builder<Class<?>> typesToDelegate = ImmutableSet.builder();
    typesToDelegate.add(viewClass);
    interfacesToImplement.add(MANAGED_INSTANCE_TYPE);
    if (viewClass.isInterface()) {
      superclass = Object.class;
      interfacesToImplement.add(Type.getInternalName(viewClass));
    } else {
      superclass = viewClass;
    }
    // TODO:LPTR This should be removed once BinaryContainer is a ModelMap
    // We need to also implement all the interfaces of the delegate type because otherwise
    // BinaryContainer won't recognize managed binaries as BinarySpecInternal
    if (delegateSchema != null) {
      ModelSchemaUtils.walkTypeHierarchy(
          delegateSchema.getType().getConcreteClass(),
          new ModelSchemaUtils.TypeVisitor<D>() {
            @Override
            public void visitType(Class<? super D> type) {
              if (type.isInterface()) {
                typesToDelegate.add(type);
                interfacesToImplement.add(Type.getInternalName(type));
              }
            }
          });
    }

    generateProxyClass(
        visitor,
        viewSchema,
        delegateSchema,
        interfacesToImplement.build(),
        typesToDelegate.build(),
        generatedType,
        Type.getType(superclass));

    ClassLoader targetClassLoader = viewClass.getClassLoader();
    if (delegateSchema != null) {
      // TODO - remove this once the above is removed
      try {
        viewClass.getClassLoader().loadClass(delegateSchema.getType().getConcreteClass().getName());
      } catch (ClassNotFoundException e) {
        // Delegate class is not visible to managed view type -> view type is more general than
        // delegate type, so use the delegate classloader instead
        targetClassLoader = delegateSchema.getType().getConcreteClass().getClassLoader();
      }
    }

    return defineClass(visitor, targetClassLoader, generatedTypeName);
  }

  private void generateProxyClass(
      ClassWriter visitor,
      StructSchema<?> viewSchema,
      StructSchema<?> delegateSchema,
      Collection<String> interfacesToImplement,
      Set<Class<?>> typesToDelegate,
      Type generatedType,
      Type superclassType) {
    ModelType<?> viewType = viewSchema.getType();
    Class<?> viewClass = viewType.getConcreteClass();
    declareClass(visitor, interfacesToImplement, generatedType, superclassType);
    declareStateField(visitor);
    declareTypeConverterField(visitor);
    declareManagedTypeField(visitor);
    declareCanCallSettersField(visitor);
    writeStaticConstructor(visitor, generatedType, viewClass);
    writeConstructor(visitor, generatedType, superclassType, delegateSchema);
    writeToString(visitor, generatedType, viewClass, delegateSchema);
    writeManagedInstanceMethods(visitor, generatedType);
    if (delegateSchema != null) {
      declareDelegateField(visitor, delegateSchema);
      writeDelegateMethods(visitor, generatedType, delegateSchema, typesToDelegate);
    }
    writeGroovyMethods(visitor, viewClass);
    writePropertyMethods(visitor, generatedType, viewSchema, delegateSchema);
    writeHashCodeMethod(visitor, generatedType);
    writeEqualsMethod(visitor, generatedType);
    visitor.visitEnd();
  }

  private void declareClass(
      ClassVisitor visitor,
      Collection<String> interfaceInternalNames,
      Type generatedType,
      Type superclassType) {
    visitor.visit(
        V1_6,
        ACC_PUBLIC,
        generatedType.getInternalName(),
        null,
        superclassType.getInternalName(),
        Iterables.toArray(interfaceInternalNames, String.class));
  }

  private void declareStateField(ClassVisitor visitor) {
    declareField(visitor, STATE_FIELD_NAME, ModelElementState.class);
  }

  private void declareTypeConverterField(ClassVisitor visitor) {
    declareField(visitor, TYPE_CONVERTER_FIELD_NAME, TypeConverter.class);
  }

  private void declareManagedTypeField(ClassVisitor visitor) {
    declareStaticField(visitor, MANAGED_TYPE_FIELD_NAME, ModelType.class);
  }

  private void declareDelegateField(ClassVisitor visitor, StructSchema<?> delegateSchema) {
    declareField(visitor, DELEGATE_FIELD_NAME, delegateSchema.getType().getConcreteClass());
  }

  private void declareCanCallSettersField(ClassVisitor visitor) {
    declareField(visitor, CAN_CALL_SETTERS_FIELD_NAME, Boolean.TYPE);
  }

  private void declareField(ClassVisitor visitor, String name, Class<?> fieldClass) {
    visitor.visitField(
        ACC_PRIVATE | ACC_FINAL | ACC_SYNTHETIC, name, Type.getDescriptor(fieldClass), null, null);
  }

  private FieldVisitor declareStaticField(ClassVisitor visitor, String name, Class<?> fieldClass) {
    return visitor.visitField(
        ACC_PRIVATE | ACC_FINAL | ACC_STATIC | ACC_SYNTHETIC,
        name,
        Type.getDescriptor(fieldClass),
        null,
        null);
  }

  private void writeConstructor(
      ClassVisitor visitor,
      Type generatedType,
      Type superclassType,
      StructSchema<?> delegateSchema) {
    String constructorDescriptor;
    Type delegateType;
    if (delegateSchema == null) {
      delegateType = null;
      constructorDescriptor = NO_DELEGATE_CONSTRUCTOR_DESCRIPTOR;
    } else {
      delegateType = Type.getType(delegateSchema.getType().getConcreteClass());
      constructorDescriptor =
          Type.getMethodDescriptor(
              Type.VOID_TYPE, MODEL_ELEMENT_STATE_TYPE, TYPE_CONVERTER_TYPE, delegateType);
    }
    MethodVisitor constructorVisitor =
        declareMethod(visitor, CONSTRUCTOR_NAME, constructorDescriptor, CONCRETE_SIGNATURE);

    invokeSuperConstructor(constructorVisitor, superclassType);
    assignStateField(constructorVisitor, generatedType);
    assignTypeConverterField(constructorVisitor, generatedType);
    if (delegateType != null) {
      assignDelegateField(constructorVisitor, generatedType, delegateType);
    }
    setCanCallSettersField(constructorVisitor, generatedType, true);
    finishVisitingMethod(constructorVisitor);
  }

  private void writeStaticConstructor(
      ClassVisitor visitor, Type generatedType, Class<?> managedTypeClass) {
    MethodVisitor constructorVisitor =
        declareMethod(visitor, STATIC_CONSTRUCTOR_NAME, "()V", CONCRETE_SIGNATURE, ACC_STATIC);
    writeManagedTypeStaticField(generatedType, managedTypeClass, constructorVisitor);
    finishVisitingMethod(constructorVisitor);
  }

  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));
  }

  private void invokeSuperConstructor(MethodVisitor constructorVisitor, Type superclassType) {
    putThisOnStack(constructorVisitor);
    constructorVisitor.visitMethodInsn(
        INVOKESPECIAL,
        superclassType.getInternalName(),
        CONSTRUCTOR_NAME,
        Type.getMethodDescriptor(Type.VOID_TYPE),
        false);
  }

  private void writeToString(
      ClassVisitor visitor,
      Type generatedType,
      Class<?> viewClass,
      StructSchema<?> delegateSchema) {
    Method toStringMethod = getToStringMethod(viewClass);

    if (toStringMethod != null && !toStringMethod.getDeclaringClass().equals(Object.class)) {
      writeNonAbstractMethodWrapper(visitor, generatedType, viewClass, toStringMethod);
    } else if (delegateSchema != null && delegateSchema.hasProperty("displayName")) {
      writeDelegatingToString(
          visitor, generatedType, Type.getType(delegateSchema.getType().getConcreteClass()));
    } else {
      writeDefaultToString(visitor, generatedType);
    }
  }

  private void writeDelegatingToString(
      ClassVisitor visitor, Type generatedType, Type delegateType) {
    MethodVisitor methodVisitor =
        declareMethod(visitor, "toString", TO_STRING_METHOD_DESCRIPTOR, CONCRETE_SIGNATURE);
    putDelegateFieldValueOnStack(methodVisitor, generatedType, delegateType);
    methodVisitor.visitMethodInsn(
        INVOKEVIRTUAL,
        delegateType.getInternalName(),
        "getDisplayName",
        TO_STRING_METHOD_DESCRIPTOR,
        false);
    finishVisitingMethod(methodVisitor, ARETURN);
  }

  private void writeDefaultToString(ClassVisitor visitor, Type generatedType) {
    MethodVisitor methodVisitor =
        declareMethod(visitor, "toString", TO_STRING_METHOD_DESCRIPTOR, CONCRETE_SIGNATURE);
    putStateFieldValueOnStack(methodVisitor, generatedType);
    methodVisitor.visitMethodInsn(
        INVOKEINTERFACE,
        MODEL_ELEMENT_STATE_TYPE_INTERNAL_NAME,
        "getDisplayName",
        TO_STRING_METHOD_DESCRIPTOR,
        true);
    finishVisitingMethod(methodVisitor, ARETURN);
  }

  private Method getToStringMethod(Class<?> managedTypeClass) {
    try {
      return managedTypeClass.getMethod("toString");
    } catch (NoSuchMethodException e) {
      return null;
    }
  }

  private void writeGroovyMethods(ClassVisitor visitor, Class<?> managedTypeClass) {
    // Object propertyMissing(String name)
    MethodVisitor methodVisitor =
        declareMethod(
            visitor, "propertyMissing", GET_PROPERTY_MISSING_METHOD_DESCRIPTOR, CONCRETE_SIGNATURE);

    // throw new MissingPropertyException(name, <managed-type>.class)
    methodVisitor.visitTypeInsn(NEW, MISSING_PROPERTY_EXCEPTION_TYPE);
    methodVisitor.visitInsn(DUP);
    putFirstMethodArgumentOnStack(methodVisitor);
    putClassOnStack(methodVisitor, managedTypeClass);
    methodVisitor.visitMethodInsn(
        INVOKESPECIAL,
        MISSING_PROPERTY_EXCEPTION_TYPE,
        "<init>",
        MISSING_PROPERTY_CONSTRUCTOR_DESCRIPTOR,
        false);
    finishVisitingMethod(methodVisitor, ATHROW);

    // Object propertyMissing(String name, Object value)

    methodVisitor =
        declareMethod(
            visitor, "propertyMissing", SET_PROPERTY_MISSING_METHOD_DESCRIPTOR, CONCRETE_SIGNATURE);

    // throw new MissingPropertyException(name, <managed-type>.class)
    methodVisitor.visitTypeInsn(NEW, MISSING_PROPERTY_EXCEPTION_TYPE);
    methodVisitor.visitInsn(DUP);
    putFirstMethodArgumentOnStack(methodVisitor);
    putClassOnStack(methodVisitor, managedTypeClass);
    methodVisitor.visitMethodInsn(
        INVOKESPECIAL,
        MISSING_PROPERTY_EXCEPTION_TYPE,
        "<init>",
        MISSING_PROPERTY_CONSTRUCTOR_DESCRIPTOR,
        false);
    finishVisitingMethod(methodVisitor, ATHROW);

    // Object methodMissing(String name, Object args)
    methodVisitor =
        declareMethod(
            visitor, "methodMissing", METHOD_MISSING_METHOD_DESCRIPTOR, CONCRETE_SIGNATURE);

    // throw new MissingMethodException(name, <managed-type>.class, args)
    methodVisitor.visitTypeInsn(NEW, MISSING_METHOD_EXCEPTION_TYPE);
    methodVisitor.visitInsn(DUP);
    putMethodArgumentOnStack(methodVisitor, 1);
    putClassOnStack(methodVisitor, managedTypeClass);
    putMethodArgumentOnStack(methodVisitor, 2);
    methodVisitor.visitTypeInsn(CHECKCAST, OBJECT_ARRAY_TYPE);
    methodVisitor.visitMethodInsn(
        INVOKESPECIAL,
        MISSING_METHOD_EXCEPTION_TYPE,
        "<init>",
        MISSING_METHOD_EXCEPTION_CONSTRUCTOR_DESCRIPTOR,
        false);
    finishVisitingMethod(methodVisitor, ATHROW);
  }

  private void putClassOnStack(MethodVisitor methodVisitor, Class<?> managedTypeClass) {
    putConstantOnStack(methodVisitor, managedTypeClass.getName());
    methodVisitor.visitMethodInsn(
        INVOKESTATIC, CLASS_INTERNAL_NAME, "forName", FOR_NAME_METHOD_DESCRIPTOR, false);
  }

  private void writeManagedInstanceMethods(ClassVisitor visitor, Type generatedType) {
    writeManagedInstanceGetBackingNodeMethod(visitor, generatedType);
    writeManagedInstanceGetManagedTypeMethod(visitor, generatedType);
  }

  private void writeManagedInstanceGetBackingNodeMethod(ClassVisitor visitor, Type generatedType) {
    MethodVisitor methodVisitor =
        declareMethod(
            visitor,
            "getBackingNode",
            GET_BACKING_NODE_METHOD_DESCRIPTOR,
            CONCRETE_SIGNATURE,
            ACC_PUBLIC | ACC_SYNTHETIC);
    putStateFieldValueOnStack(methodVisitor, generatedType);
    methodVisitor.visitMethodInsn(
        INVOKEINTERFACE,
        MODEL_ELEMENT_STATE_TYPE_INTERNAL_NAME,
        "getBackingNode",
        GET_BACKING_NODE_METHOD_DESCRIPTOR,
        true);
    finishVisitingMethod(methodVisitor, ARETURN);
  }

  private void writeManagedInstanceGetManagedTypeMethod(ClassVisitor visitor, Type generatedType) {
    MethodVisitor managedTypeVisitor =
        declareMethod(
            visitor,
            "getManagedType",
            GET_MANAGED_TYPE_METHOD_DESCRIPTOR,
            CONCRETE_SIGNATURE,
            ACC_PUBLIC | ACC_SYNTHETIC);
    putManagedTypeFieldValueOnStack(managedTypeVisitor, generatedType);
    finishVisitingMethod(managedTypeVisitor, ARETURN);
  }

  private void assignStateField(MethodVisitor constructorVisitor, Type generatedType) {
    putThisOnStack(constructorVisitor);
    putFirstMethodArgumentOnStack(constructorVisitor);
    constructorVisitor.visitFieldInsn(
        PUTFIELD,
        generatedType.getInternalName(),
        STATE_FIELD_NAME,
        MODEL_ELEMENT_STATE_TYPE.getDescriptor());
  }

  private void assignTypeConverterField(MethodVisitor constructorVisitor, Type generatedType) {
    putThisOnStack(constructorVisitor);
    putSecondMethodArgumentOnStack(constructorVisitor);
    constructorVisitor.visitFieldInsn(
        PUTFIELD,
        generatedType.getInternalName(),
        TYPE_CONVERTER_FIELD_NAME,
        TYPE_CONVERTER_TYPE.getDescriptor());
  }

  private void assignDelegateField(
      MethodVisitor constructorVisitor, Type generatedType, Type delegateType) {
    putThisOnStack(constructorVisitor);
    putThirdMethodArgumentOnStack(constructorVisitor);
    constructorVisitor.visitFieldInsn(
        PUTFIELD,
        generatedType.getInternalName(),
        DELEGATE_FIELD_NAME,
        delegateType.getDescriptor());
  }

  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 writePropertyMethods(
      ClassVisitor visitor,
      Type generatedType,
      StructSchema<?> viewSchema,
      StructSchema<?> delegateSchema) {
    Collection<String> delegatePropertyNames;
    if (delegateSchema != null) {
      delegatePropertyNames = delegateSchema.getPropertyNames();
    } else {
      delegatePropertyNames = Collections.emptySet();
    }
    Class<?> viewClass = viewSchema.getType().getConcreteClass();
    for (ModelProperty<?> property : viewSchema.getProperties()) {
      String propertyName = property.getName();

      writeConfigureMethod(visitor, generatedType, property);
      writeSetMethod(visitor, generatedType, property);
      createTypeConvertingSetter(visitor, generatedType, property);

      // Delegated properties are handled in writeDelegateMethods()
      if (delegatePropertyNames.contains(propertyName)) {
        continue;
      }
      switch (property.getStateManagementType()) {
        case MANAGED:
          writeGetters(visitor, generatedType, property);
          writeSetter(visitor, generatedType, property);
          break;

        case UNMANAGED:
          for (WeaklyTypeReferencingMethod<?, ?> getter : property.getGetters()) {
            Method getterMethod = getter.getMethod();
            if (!Modifier.isFinal(getterMethod.getModifiers())
                && !propertyName.equals("metaClass")) {
              writeNonAbstractMethodWrapper(visitor, generatedType, viewClass, getterMethod);
            }
          }
          break;
      }
    }
  }

  private void writeSetMethod(ClassVisitor visitor, Type generatedType, ModelProperty<?> property) {
    if (property.isWritable() && property.getSchema() instanceof ScalarValueSchema) {

      // TODO - should we support this?
      // Adds a void $propName(Object value) method that sets the value
      MethodVisitor methodVisitor =
          declareMethod(
              visitor,
              property.getName(),
              Type.getMethodDescriptor(Type.VOID_TYPE, OBJECT_TYPE),
              null);
      putThisOnStack(methodVisitor);
      putFirstMethodArgumentOnStack(methodVisitor);
      methodVisitor.visitMethodInsn(
          INVOKEVIRTUAL,
          generatedType.getInternalName(),
          property.getSetter().getName(),
          Type.getMethodDescriptor(Type.VOID_TYPE, OBJECT_TYPE),
          false);
      finishVisitingMethod(methodVisitor);
    }
  }

  private void writeConfigureMethod(
      ClassVisitor visitor, Type generatedType, ModelProperty<?> property) {
    if (!property.isWritable() && property.getSchema() instanceof CompositeSchema) {
      // Adds a void $propName(Closure<?> cl) method that delegates to model state

      MethodVisitor methodVisitor =
          declareMethod(
              visitor,
              property.getName(),
              Type.getMethodDescriptor(Type.VOID_TYPE, CLOSURE_TYPE),
              null);
      putStateFieldValueOnStack(methodVisitor, generatedType);
      putConstantOnStack(methodVisitor, property.getName());
      putFirstMethodArgumentOnStack(methodVisitor);
      methodVisitor.visitMethodInsn(
          INVOKEINTERFACE,
          MODEL_ELEMENT_STATE_TYPE_INTERNAL_NAME,
          "apply",
          STATE_APPLY_METHOD_DESCRIPTOR,
          true);
      finishVisitingMethod(methodVisitor);
      return;
    }
    if (!property.isWritable() && property.getSchema() instanceof UnmanagedImplStructSchema) {
      UnmanagedImplStructSchema<?> structSchema =
          (UnmanagedImplStructSchema<?>) property.getSchema();
      if (!structSchema.isAnnotated()) {
        return;
      }

      // Adds a void $propName(Closure<?> cl) method that executes the closure
      MethodVisitor methodVisitor =
          declareMethod(
              visitor,
              property.getName(),
              Type.getMethodDescriptor(Type.VOID_TYPE, CLOSURE_TYPE),
              null);
      putThisOnStack(methodVisitor);
      methodVisitor.visitMethodInsn(
          INVOKEVIRTUAL,
          generatedType.getInternalName(),
          property.getGetters().get(0).getName(),
          Type.getMethodDescriptor(Type.getType(property.getType().getConcreteClass())),
          false);
      putFirstMethodArgumentOnStack(methodVisitor);
      methodVisitor.visitMethodInsn(
          INVOKESTATIC,
          Type.getInternalName(ClosureBackedAction.class),
          "execute",
          Type.getMethodDescriptor(Type.VOID_TYPE, OBJECT_TYPE, CLOSURE_TYPE),
          false);
      finishVisitingMethod(methodVisitor);
      return;
    }

    // Adds a void $propName(Closure<?> cl) method that throws MME, to avoid attempts to convert
    // closure to something else
    MethodVisitor methodVisitor =
        declareMethod(
            visitor,
            property.getName(),
            Type.getMethodDescriptor(Type.VOID_TYPE, CLOSURE_TYPE),
            null);
    putThisOnStack(methodVisitor);
    putConstantOnStack(methodVisitor, property.getName());
    methodVisitor.visitInsn(Opcodes.ICONST_1);
    methodVisitor.visitTypeInsn(Opcodes.ANEWARRAY, OBJECT_TYPE.getInternalName());
    methodVisitor.visitInsn(Opcodes.DUP);
    methodVisitor.visitInsn(Opcodes.ICONST_0);
    putFirstMethodArgumentOnStack(methodVisitor);
    methodVisitor.visitInsn(Opcodes.AASTORE);
    methodVisitor.visitMethodInsn(
        INVOKEVIRTUAL,
        generatedType.getInternalName(),
        "methodMissing",
        METHOD_MISSING_METHOD_DESCRIPTOR,
        false);
    finishVisitingMethod(methodVisitor);
  }

  private void writeSetter(ClassVisitor visitor, Type generatedType, ModelProperty<?> property) {
    WeaklyTypeReferencingMethod<?, Void> weakSetter = property.getSetter();
    // There is no setter for this property
    if (weakSetter == null) {
      return;
    }

    String propertyName = property.getName();
    Class<?> propertyClass = property.getType().getConcreteClass();
    Type propertyType = Type.getType(propertyClass);
    Label calledOutsideOfConstructor = new Label();

    Method setter = weakSetter.getMethod();

    // the regular typed setter
    String methodDescriptor = Type.getMethodDescriptor(Type.VOID_TYPE, propertyType);
    MethodVisitor methodVisitor =
        declareMethod(
            visitor, setter.getName(), methodDescriptor, AsmClassGeneratorUtils.signature(setter));

    putCanCallSettersFieldValueOnStack(methodVisitor, generatedType);
    jumpToLabelIfStackEvaluatesToTrue(methodVisitor, calledOutsideOfConstructor);
    throwExceptionBecauseCalledOnItself(methodVisitor);

    methodVisitor.visitLabel(calledOutsideOfConstructor);
    putStateFieldValueOnStack(methodVisitor, generatedType);
    putConstantOnStack(methodVisitor, propertyName);
    putFirstMethodArgumentOnStack(methodVisitor, propertyType);
    if (propertyClass.isPrimitive()) {
      boxType(methodVisitor, propertyClass);
    }
    invokeStateSetMethod(methodVisitor);

    finishVisitingMethod(methodVisitor);
  }

  // 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);
  }

  private void writeHashCodeMethod(ClassVisitor visitor, Type generatedType) {
    MethodVisitor methodVisitor =
        declareMethod(visitor, "hashCode", HASH_CODE_METHOD_DESCRIPTOR, null);
    methodVisitor.visitVarInsn(ALOAD, 0);
    methodVisitor.visitMethodInsn(
        INVOKEVIRTUAL,
        generatedType.getInternalName(),
        "getBackingNode",
        GET_BACKING_NODE_METHOD_DESCRIPTOR,
        false);
    methodVisitor.visitMethodInsn(
        INVOKEINTERFACE, MUTABLE_MODEL_NODE_TYPE, "hashCode", HASH_CODE_METHOD_DESCRIPTOR, true);
    methodVisitor.visitInsn(IRETURN);
    finishVisitingMethod(methodVisitor, Opcodes.IRETURN);
  }

  private void writeEqualsMethod(ClassVisitor cw, Type generatedType) {
    MethodVisitor methodVisitor =
        cw.visitMethod(Opcodes.ACC_PUBLIC, "equals", EQUALS_METHOD_DESCRIPTOR, null, null);
    methodVisitor.visitCode();
    methodVisitor.visitVarInsn(ALOAD, 0);
    methodVisitor.visitVarInsn(ALOAD, 1);
    Label notSameLabel = new Label();
    methodVisitor.visitJumpInsn(IF_ACMPNE, notSameLabel);
    methodVisitor.visitInsn(ICONST_1);
    methodVisitor.visitInsn(IRETURN);
    methodVisitor.visitLabel(notSameLabel);
    methodVisitor.visitVarInsn(ALOAD, 1);
    methodVisitor.visitTypeInsn(INSTANCEOF, MANAGED_INSTANCE_TYPE);
    Label notManagedInstanceLabel = new Label();
    methodVisitor.visitJumpInsn(IFNE, notManagedInstanceLabel);
    methodVisitor.visitInsn(ICONST_0);
    methodVisitor.visitInsn(IRETURN);
    methodVisitor.visitLabel(notManagedInstanceLabel);
    methodVisitor.visitVarInsn(ALOAD, 0);
    methodVisitor.visitMethodInsn(
        INVOKEVIRTUAL,
        generatedType.getInternalName(),
        "getBackingNode",
        GET_BACKING_NODE_METHOD_DESCRIPTOR,
        false);
    methodVisitor.visitVarInsn(ALOAD, 1);
    methodVisitor.visitTypeInsn(CHECKCAST, MANAGED_INSTANCE_TYPE);
    methodVisitor.visitMethodInsn(
        INVOKEINTERFACE,
        MANAGED_INSTANCE_TYPE,
        "getBackingNode",
        GET_BACKING_NODE_METHOD_DESCRIPTOR,
        true);
    methodVisitor.visitMethodInsn(
        INVOKEINTERFACE, MUTABLE_MODEL_NODE_TYPE, "equals", EQUALS_METHOD_DESCRIPTOR, true);
    finishVisitingMethod(methodVisitor, Opcodes.IRETURN);
  }

  private void throwExceptionBecauseCalledOnItself(MethodVisitor methodVisitor) {
    String exceptionInternalName = Type.getInternalName(UnsupportedOperationException.class);
    methodVisitor.visitTypeInsn(NEW, exceptionInternalName);
    methodVisitor.visitInsn(DUP);
    putConstantOnStack(methodVisitor, "Calling setters of a managed type on itself is not allowed");

    String constructorDescriptor = Type.getMethodDescriptor(Type.VOID_TYPE, STRING_TYPE);
    methodVisitor.visitMethodInsn(
        INVOKESPECIAL, exceptionInternalName, CONSTRUCTOR_NAME, constructorDescriptor, false);
    methodVisitor.visitInsn(ATHROW);
  }

  private void jumpToLabelIfStackEvaluatesToTrue(MethodVisitor methodVisitor, Label label) {
    methodVisitor.visitJumpInsn(IFNE, label);
  }

  private void invokeStateSetMethod(MethodVisitor methodVisitor) {
    methodVisitor.visitMethodInsn(
        INVOKEINTERFACE,
        MODEL_ELEMENT_STATE_TYPE_INTERNAL_NAME,
        "set",
        STATE_SET_METHOD_DESCRIPTOR,
        true);
  }

  private void putConstantOnStack(MethodVisitor methodVisitor, Object value) {
    methodVisitor.visitLdcInsn(value);
  }

  private MethodVisitor declareMethod(ClassVisitor visitor, Method method) {
    return declareMethod(visitor, method.getName(), Type.getMethodDescriptor(method));
  }

  private MethodVisitor declareMethod(
      ClassVisitor visitor, String methodName, String methodDescriptor) {
    return declareMethod(visitor, methodName, methodDescriptor, CONCRETE_SIGNATURE);
  }

  private MethodVisitor declareMethod(
      ClassVisitor visitor, String methodName, String methodDescriptor, String methodSignature) {
    return declareMethod(visitor, methodName, methodDescriptor, methodSignature, ACC_PUBLIC);
  }

  private MethodVisitor declareMethod(
      ClassVisitor visitor,
      String methodName,
      String methodDescriptor,
      String methodSignature,
      int access) {
    MethodVisitor methodVisitor =
        visitor.visitMethod(access, methodName, methodDescriptor, methodSignature, NO_EXCEPTIONS);
    methodVisitor.visitCode();
    return methodVisitor;
  }

  private void putFirstMethodArgumentOnStack(MethodVisitor methodVisitor, Type argType) {
    int loadCode = argType.getOpcode(ILOAD);
    methodVisitor.visitVarInsn(loadCode, 1);
  }

  private void putFirstMethodArgumentOnStack(MethodVisitor methodVisitor) {
    putFirstMethodArgumentOnStack(methodVisitor, OBJECT_TYPE);
  }

  private void putSecondMethodArgumentOnStack(MethodVisitor methodVisitor) {
    methodVisitor.visitVarInsn(ALOAD, 2);
  }

  private void putThirdMethodArgumentOnStack(MethodVisitor methodVisitor) {
    methodVisitor.visitVarInsn(ALOAD, 3);
  }

  private void putMethodArgumentOnStack(MethodVisitor methodVisitor, int index) {
    methodVisitor.visitVarInsn(ALOAD, index);
  }

  private void putMethodArgumentOnStack(MethodVisitor methodVisitor, Type type, int index) {
    methodVisitor.visitVarInsn(type.getOpcode(ILOAD), index);
  }

  private void putStateFieldValueOnStack(MethodVisitor methodVisitor, Type generatedType) {
    putFieldValueOnStack(methodVisitor, generatedType, STATE_FIELD_NAME, MODEL_ELEMENT_STATE_TYPE);
  }

  private void putTypeConverterFieldValueOnStack(MethodVisitor methodVisitor, Type generatedType) {
    putFieldValueOnStack(
        methodVisitor, generatedType, TYPE_CONVERTER_FIELD_NAME, TYPE_CONVERTER_TYPE);
  }

  private void putManagedTypeFieldValueOnStack(MethodVisitor methodVisitor, Type generatedType) {
    putStaticFieldValueOnStack(
        methodVisitor, generatedType, MANAGED_TYPE_FIELD_NAME, MODELTYPE_TYPE);
  }

  private void putDelegateFieldValueOnStack(
      MethodVisitor methodVisitor, Type generatedType, Type delegateType) {
    putFieldValueOnStack(methodVisitor, generatedType, DELEGATE_FIELD_NAME, delegateType);
  }

  private void putCanCallSettersFieldValueOnStack(MethodVisitor methodVisitor, Type generatedType) {
    putFieldValueOnStack(
        methodVisitor, generatedType, CAN_CALL_SETTERS_FIELD_NAME, Type.BOOLEAN_TYPE);
  }

  private void putFieldValueOnStack(
      MethodVisitor methodVisitor, Type generatedType, String name, Type fieldType) {
    putThisOnStack(methodVisitor);
    methodVisitor.visitFieldInsn(
        GETFIELD, generatedType.getInternalName(), name, fieldType.getDescriptor());
  }

  private void putStaticFieldValueOnStack(
      MethodVisitor methodVisitor, Type generatedType, String name, Type fieldType) {
    methodVisitor.visitFieldInsn(
        GETSTATIC, generatedType.getInternalName(), name, fieldType.getDescriptor());
  }

  private void writeGetters(ClassVisitor visitor, Type generatedType, ModelProperty<?> property) {
    Class<?> propertyClass = property.getType().getConcreteClass();
    Type propertyType = Type.getType(propertyClass);
    Set<String> processedNames = Sets.newHashSet();
    for (WeaklyTypeReferencingMethod<?, ?> weakGetter : property.getGetters()) {
      Method getter = weakGetter.getMethod();
      if (!processedNames.add(getter.getName())) {
        continue;
      }
      MethodVisitor methodVisitor =
          declareMethod(
              visitor,
              getter.getName(),
              Type.getMethodDescriptor(propertyType),
              AsmClassGeneratorUtils.signature(getter));

      putStateFieldValueOnStack(methodVisitor, generatedType);
      putConstantOnStack(methodVisitor, property.getName());
      invokeStateGetMethod(methodVisitor);
      castFirstStackElement(methodVisitor, propertyClass);
      finishVisitingMethod(methodVisitor, returnCode(propertyType));
    }
  }

  private int returnCode(Type returnType) {
    return returnType.getOpcode(IRETURN);
  }

  private void castFirstStackElement(MethodVisitor methodVisitor, Class<?> returnType) {
    if (returnType.isPrimitive()) {
      unboxType(methodVisitor, returnType);
    } else {
      methodVisitor.visitTypeInsn(CHECKCAST, Type.getInternalName(returnType));
    }
  }

  private void boxType(MethodVisitor methodVisitor, Class<?> primitiveType) {
    Class<?> boxedType = BOXED_TYPES.get(primitiveType);
    methodVisitor.visitMethodInsn(
        INVOKESTATIC,
        Type.getInternalName(boxedType),
        "valueOf",
        "(" + Type.getDescriptor(primitiveType) + ")" + Type.getDescriptor(boxedType),
        false);
  }

  private void unboxType(MethodVisitor methodVisitor, Class<?> primitiveClass) {
    // Float f = (Float) tmp
    // f==null?0:f.floatValue()
    Class<?> boxedType = BOXED_TYPES.get(primitiveClass);
    Type primitiveType = Type.getType(primitiveClass);
    methodVisitor.visitTypeInsn(CHECKCAST, Type.getInternalName(boxedType));
    methodVisitor.visitInsn(DUP);
    Label exit = new Label();
    Label elseValue = new Label();
    methodVisitor.visitJumpInsn(IFNONNULL, elseValue);
    methodVisitor.visitInsn(POP);
    pushDefaultValue(methodVisitor, primitiveClass);
    methodVisitor.visitJumpInsn(GOTO, exit);
    methodVisitor.visitLabel(elseValue);
    methodVisitor.visitMethodInsn(
        INVOKEVIRTUAL,
        Type.getInternalName(boxedType),
        primitiveClass.getSimpleName() + "Value",
        Type.getMethodDescriptor(primitiveType),
        false);
    methodVisitor.visitLabel(exit);
  }

  private void pushDefaultValue(MethodVisitor methodVisitor, Class<?> primitiveType) {
    int ins = ICONST_0;
    if (long.class == primitiveType) {
      ins = LCONST_0;
    } else if (double.class == primitiveType) {
      ins = DCONST_0;
    } else if (float.class == primitiveType) {
      ins = FCONST_0;
    }
    methodVisitor.visitInsn(ins);
  }

  private void invokeStateGetMethod(MethodVisitor methodVisitor) {
    methodVisitor.visitMethodInsn(
        INVOKEINTERFACE,
        MODEL_ELEMENT_STATE_TYPE_INTERNAL_NAME,
        "get",
        STATE_GET_METHOD_DESCRIPTOR,
        true);
  }

  private void writeNonAbstractMethodWrapper(
      ClassVisitor visitor, Type generatedType, Class<?> managedTypeClass, Method method) {
    Label start = new Label();
    Label end = new Label();
    Label handler = new Label();

    MethodVisitor methodVisitor = declareMethod(visitor, method);

    methodVisitor.visitTryCatchBlock(start, end, handler, null);

    setCanCallSettersField(methodVisitor, generatedType, false);

    methodVisitor.visitLabel(start);
    invokeSuperMethod(methodVisitor, managedTypeClass, method);
    methodVisitor.visitLabel(end);

    setCanCallSettersField(methodVisitor, generatedType, true);
    methodVisitor.visitInsn(ARETURN);

    methodVisitor.visitLabel(handler);
    setCanCallSettersField(methodVisitor, generatedType, true);
    methodVisitor.visitInsn(ATHROW);

    methodVisitor.visitMaxs(0, 0);
    methodVisitor.visitEnd();
  }

  private void writeDelegateMethods(
      final ClassVisitor visitor,
      final Type generatedType,
      StructSchema<?> delegateSchema,
      Set<Class<?>> typesToDelegate) {
    Class<?> delegateClass = delegateSchema.getType().getConcreteClass();
    Type delegateType = Type.getType(delegateClass);
    Map<Equivalence.Wrapper<Method>, Map<Class<?>, Method>> methodsToDelegate = Maps.newHashMap();
    for (Class<?> typeToDelegate : typesToDelegate) {
      for (Method methodToDelegate : typeToDelegate.getMethods()) {
        if (ModelSchemaUtils.isIgnoredMethod(methodToDelegate)) {
          continue;
        }
        Equivalence.Wrapper<Method> methodKey = METHOD_EQUIVALENCE.wrap(methodToDelegate);
        Map<Class<?>, Method> methodsByReturnType = methodsToDelegate.get(methodKey);
        if (methodsByReturnType == null) {
          methodsByReturnType = Maps.newHashMap();
          methodsToDelegate.put(methodKey, methodsByReturnType);
        }
        methodsByReturnType.put(methodToDelegate.getReturnType(), methodToDelegate);
      }
    }
    Set<Equivalence.Wrapper<Method>> delegateMethodKeys =
        ImmutableSet.copyOf(
            Iterables.transform(
                Arrays.asList(delegateClass.getMethods()),
                new Function<Method, Equivalence.Wrapper<Method>>() {
                  @Override
                  public Equivalence.Wrapper<Method> apply(Method method) {
                    return METHOD_EQUIVALENCE.wrap(method);
                  }
                }));
    for (Map.Entry<Equivalence.Wrapper<Method>, Map<Class<?>, Method>> entry :
        methodsToDelegate.entrySet()) {
      Equivalence.Wrapper<Method> methodKey = entry.getKey();
      if (!delegateMethodKeys.contains(methodKey)) {
        continue;
      }

      Map<Class<?>, Method> methodsByReturnType = entry.getValue();
      for (Method methodToDelegate : methodsByReturnType.values()) {
        writeDelegatedMethod(visitor, generatedType, delegateType, methodToDelegate);
      }
    }
  }

  private void writeDelegatedMethod(
      ClassVisitor visitor, Type generatedType, Type delegateType, Method method) {
    MethodVisitor methodVisitor =
        declareMethod(
            visitor,
            method.getName(),
            Type.getMethodDescriptor(method),
            AsmClassGeneratorUtils.signature(method));
    invokeDelegateMethod(methodVisitor, generatedType, delegateType, method);
    Class<?> returnType = method.getReturnType();
    finishVisitingMethod(methodVisitor, returnCode(Type.getType(returnType)));
  }

  private void invokeDelegateMethod(
      MethodVisitor methodVisitor, Type generatedType, Type delegateType, Method method) {
    putDelegateFieldValueOnStack(methodVisitor, generatedType, delegateType);
    Class<?>[] parameterTypes = method.getParameterTypes();
    for (int paramNo = 0; paramNo < parameterTypes.length; paramNo++) {
      putMethodArgumentOnStack(methodVisitor, Type.getType(parameterTypes[paramNo]), paramNo + 1);
    }
    methodVisitor.visitMethodInsn(
        INVOKEVIRTUAL,
        delegateType.getInternalName(),
        method.getName(),
        Type.getMethodDescriptor(method),
        false);
  }

  private void invokeSuperMethod(MethodVisitor methodVisitor, Class<?> superClass, Method method) {
    putThisOnStack(methodVisitor);
    methodVisitor.visitMethodInsn(
        INVOKESPECIAL,
        Type.getInternalName(superClass),
        method.getName(),
        Type.getMethodDescriptor(method),
        false);
  }
}
コード例 #26
0
  @NotNull
  public InlineResult doTransform(
      @NotNull AnonymousObjectGeneration anonymousObjectGen,
      @NotNull FieldRemapper parentRemapper) {
    final List<InnerClassNode> innerClassNodes = new ArrayList<InnerClassNode>();
    ClassBuilder classBuilder = createClassBuilder();
    final List<MethodNode> methodsToTransform = new ArrayList<MethodNode>();

    reader.accept(
        new ClassVisitor(InlineCodegenUtil.API, classBuilder.getVisitor()) {
          @Override
          public void visit(
              int version,
              int access,
              @NotNull String name,
              String signature,
              String superName,
              String[] interfaces) {
            InlineCodegenUtil.assertVersionNotGreaterThanJava6(version, name);
            super.visit(version, access, name, signature, superName, interfaces);
          }

          @Override
          public void visitInnerClass(
              @NotNull String name, String outerName, String innerName, int access) {
            innerClassNodes.add(new InnerClassNode(name, outerName, innerName, access));
          }

          @Override
          public MethodVisitor visitMethod(
              int access,
              @NotNull String name,
              @NotNull String desc,
              String signature,
              String[] exceptions) {
            MethodNode node = new MethodNode(access, name, desc, signature, exceptions);
            if (name.equals("<init>")) {
              if (constructor != null)
                throw new RuntimeException(
                    "Lambda, SAM or anonymous object should have only one constructor");

              constructor = node;
            } else {
              methodsToTransform.add(node);
            }
            return node;
          }

          @Override
          public FieldVisitor visitField(
              int access,
              @NotNull String name,
              @NotNull String desc,
              String signature,
              Object value) {
            addUniqueField(name);
            if (InlineCodegenUtil.isCapturedFieldName(name)) {
              return null;
            } else {
              return super.visitField(access, name, desc, signature, value);
            }
          }

          @Override
          public void visitSource(String source, String debug) {
            sourceInfo = source;
            debugInfo = debug;
          }

          @Override
          public void visitEnd() {}
        },
        ClassReader.SKIP_FRAMES);

    if (!inliningContext.isInliningLambda) {
      if (debugInfo != null && !debugInfo.isEmpty()) {
        sourceMapper = SourceMapper.Companion.createFromSmap(SMAPParser.parse(debugInfo));
      } else {
        // seems we can't do any clever mapping cause we don't know any about original class name
        sourceMapper = IdenticalSourceMapper.INSTANCE;
      }
      if (sourceInfo != null && !InlineCodegenUtil.GENERATE_SMAP) {
        classBuilder.visitSource(sourceInfo, debugInfo);
      }
    } else {
      if (sourceInfo != null) {
        classBuilder.visitSource(sourceInfo, debugInfo);
      }
      sourceMapper = IdenticalSourceMapper.INSTANCE;
    }

    ParametersBuilder allCapturedParamBuilder = ParametersBuilder.newBuilder();
    ParametersBuilder constructorParamBuilder = ParametersBuilder.newBuilder();
    List<CapturedParamInfo> additionalFakeParams =
        extractParametersMappingAndPatchConstructor(
            constructor,
            allCapturedParamBuilder,
            constructorParamBuilder,
            anonymousObjectGen,
            parentRemapper);
    List<MethodVisitor> deferringMethods = new ArrayList<MethodVisitor>();

    for (MethodNode next : methodsToTransform) {
      MethodVisitor deferringVisitor = newMethod(classBuilder, next);
      InlineResult funResult =
          inlineMethodAndUpdateGlobalResult(
              anonymousObjectGen,
              parentRemapper,
              deferringVisitor,
              next,
              allCapturedParamBuilder,
              false);

      Type returnType = Type.getReturnType(next.desc);
      if (!AsmUtil.isPrimitive(returnType)) {
        String oldFunReturnType = returnType.getInternalName();
        String newFunReturnType = funResult.getChangedTypes().get(oldFunReturnType);
        if (newFunReturnType != null) {
          inliningContext.typeRemapper.addAdditionalMappings(oldFunReturnType, newFunReturnType);
        }
      }
      deferringMethods.add(deferringVisitor);
    }

    for (MethodVisitor method : deferringMethods) {
      method.visitEnd();
    }

    generateConstructorAndFields(
        classBuilder,
        allCapturedParamBuilder,
        constructorParamBuilder,
        anonymousObjectGen,
        parentRemapper,
        additionalFakeParams);

    SourceMapper.Companion.flushToClassBuilder(sourceMapper, classBuilder);

    ClassVisitor visitor = classBuilder.getVisitor();
    for (InnerClassNode node : innerClassNodes) {
      visitor.visitInnerClass(node.name, node.outerName, node.innerName, node.access);
    }

    writeOuterInfo(visitor);

    classBuilder.done();

    anonymousObjectGen.setNewLambdaType(newLambdaType);
    return transformationResult;
  }
コード例 #27
0
  private void writeConfigureMethod(
      ClassVisitor visitor, Type generatedType, ModelProperty<?> property) {
    if (!property.isWritable() && property.getSchema() instanceof CompositeSchema) {
      // Adds a void $propName(Closure<?> cl) method that delegates to model state

      MethodVisitor methodVisitor =
          declareMethod(
              visitor,
              property.getName(),
              Type.getMethodDescriptor(Type.VOID_TYPE, CLOSURE_TYPE),
              null);
      putStateFieldValueOnStack(methodVisitor, generatedType);
      putConstantOnStack(methodVisitor, property.getName());
      putFirstMethodArgumentOnStack(methodVisitor);
      methodVisitor.visitMethodInsn(
          INVOKEINTERFACE,
          MODEL_ELEMENT_STATE_TYPE_INTERNAL_NAME,
          "apply",
          STATE_APPLY_METHOD_DESCRIPTOR,
          true);
      finishVisitingMethod(methodVisitor);
      return;
    }
    if (!property.isWritable() && property.getSchema() instanceof UnmanagedImplStructSchema) {
      UnmanagedImplStructSchema<?> structSchema =
          (UnmanagedImplStructSchema<?>) property.getSchema();
      if (!structSchema.isAnnotated()) {
        return;
      }

      // Adds a void $propName(Closure<?> cl) method that executes the closure
      MethodVisitor methodVisitor =
          declareMethod(
              visitor,
              property.getName(),
              Type.getMethodDescriptor(Type.VOID_TYPE, CLOSURE_TYPE),
              null);
      putThisOnStack(methodVisitor);
      methodVisitor.visitMethodInsn(
          INVOKEVIRTUAL,
          generatedType.getInternalName(),
          property.getGetters().get(0).getName(),
          Type.getMethodDescriptor(Type.getType(property.getType().getConcreteClass())),
          false);
      putFirstMethodArgumentOnStack(methodVisitor);
      methodVisitor.visitMethodInsn(
          INVOKESTATIC,
          Type.getInternalName(ClosureBackedAction.class),
          "execute",
          Type.getMethodDescriptor(Type.VOID_TYPE, OBJECT_TYPE, CLOSURE_TYPE),
          false);
      finishVisitingMethod(methodVisitor);
      return;
    }

    // Adds a void $propName(Closure<?> cl) method that throws MME, to avoid attempts to convert
    // closure to something else
    MethodVisitor methodVisitor =
        declareMethod(
            visitor,
            property.getName(),
            Type.getMethodDescriptor(Type.VOID_TYPE, CLOSURE_TYPE),
            null);
    putThisOnStack(methodVisitor);
    putConstantOnStack(methodVisitor, property.getName());
    methodVisitor.visitInsn(Opcodes.ICONST_1);
    methodVisitor.visitTypeInsn(Opcodes.ANEWARRAY, OBJECT_TYPE.getInternalName());
    methodVisitor.visitInsn(Opcodes.DUP);
    methodVisitor.visitInsn(Opcodes.ICONST_0);
    putFirstMethodArgumentOnStack(methodVisitor);
    methodVisitor.visitInsn(Opcodes.AASTORE);
    methodVisitor.visitMethodInsn(
        INVOKEVIRTUAL,
        generatedType.getInternalName(),
        "methodMissing",
        METHOD_MISSING_METHOD_DESCRIPTOR,
        false);
    finishVisitingMethod(methodVisitor);
  }
コード例 #28
0
ファイル: FunctionCodegen.java プロジェクト: AlexJuca/kotlin
  public void generateMethod(
      @NotNull JvmDeclarationOrigin origin,
      @NotNull FunctionDescriptor functionDescriptor,
      @NotNull MethodContext methodContext,
      @NotNull FunctionGenerationStrategy strategy) {
    OwnerKind contextKind = methodContext.getContextKind();
    if (isInterface(functionDescriptor.getContainingDeclaration())
        && functionDescriptor.getVisibility() == Visibilities.PRIVATE
        && contextKind != OwnerKind.DEFAULT_IMPLS) {
      return;
    }

    JvmMethodSignature jvmSignature = typeMapper.mapSignature(functionDescriptor, contextKind);
    Method asmMethod = jvmSignature.getAsmMethod();

    int flags = getMethodAsmFlags(functionDescriptor, contextKind);
    boolean isNative = NativeKt.hasNativeAnnotation(functionDescriptor);

    if (isNative && owner instanceof MultifileClassFacadeContext) {
      // Native methods are only defined in facades and do not need package part implementations
      return;
    }
    MethodVisitor mv =
        v.newMethod(
            origin,
            flags,
            asmMethod.getName(),
            asmMethod.getDescriptor(),
            jvmSignature.getGenericsSignature(),
            getThrownExceptions(functionDescriptor, typeMapper));

    if (CodegenContextUtil.isImplClassOwner(owner)) {
      v.getSerializationBindings().put(METHOD_FOR_FUNCTION, functionDescriptor, asmMethod);
    }

    generateMethodAnnotations(functionDescriptor, asmMethod, mv);

    generateParameterAnnotations(
        functionDescriptor, mv, typeMapper.mapSignature(functionDescriptor));

    generateBridges(functionDescriptor);

    boolean staticInCompanionObject =
        AnnotationUtilKt.isPlatformStaticInCompanionObject(functionDescriptor);
    if (staticInCompanionObject) {
      ImplementationBodyCodegen parentBodyCodegen =
          (ImplementationBodyCodegen) memberCodegen.getParentCodegen();
      parentBodyCodegen.addAdditionalTask(
          new JvmStaticGenerator(functionDescriptor, origin, state));
    }

    if (state.getClassBuilderMode() == ClassBuilderMode.LIGHT_CLASSES
        || isAbstractMethod(functionDescriptor, contextKind)) {
      generateLocalVariableTable(
          mv,
          jvmSignature,
          functionDescriptor,
          getThisTypeForFunction(functionDescriptor, methodContext, typeMapper),
          new Label(),
          new Label(),
          contextKind);

      mv.visitEnd();
      return;
    }

    if (!isNative) {
      generateMethodBody(
          mv, functionDescriptor, methodContext, jvmSignature, strategy, memberCodegen);
    } else if (staticInCompanionObject) {
      // native @JvmStatic foo() in companion object should delegate to the static native function
      // moved to the outer class
      mv.visitCode();
      FunctionDescriptor staticFunctionDescriptor =
          JvmStaticGenerator.createStaticFunctionDescriptor(functionDescriptor);
      JvmMethodSignature jvmMethodSignature =
          typeMapper.mapSignature(
              memberCodegen.getContext().accessibleDescriptor(staticFunctionDescriptor, null));
      Type owningType =
          typeMapper.mapClass(
              (ClassifierDescriptor) staticFunctionDescriptor.getContainingDeclaration());
      generateDelegateToMethodBody(
          false, mv, jvmMethodSignature.getAsmMethod(), owningType.getInternalName());
    }

    endVisit(mv, null, origin.getElement());
  }
コード例 #29
0
 private void putFieldValueOnStack(
     MethodVisitor methodVisitor, Type generatedType, String name, Type fieldType) {
   putThisOnStack(methodVisitor);
   methodVisitor.visitFieldInsn(
       GETFIELD, generatedType.getInternalName(), name, fieldType.getDescriptor());
 }
コード例 #30
0
 private void putStaticFieldValueOnStack(
     MethodVisitor methodVisitor, Type generatedType, String name, Type fieldType) {
   methodVisitor.visitFieldInsn(
       GETSTATIC, generatedType.getInternalName(), name, fieldType.getDescriptor());
 }