Esempio n. 1
0
  void generateDefaultIfNeeded(
      @NotNull MethodContext owner,
      @NotNull FunctionDescriptor functionDescriptor,
      @NotNull OwnerKind kind,
      @NotNull DefaultParameterValueLoader loadStrategy,
      @Nullable KtNamedFunction function) {
    DeclarationDescriptor contextClass = owner.getContextDescriptor().getContainingDeclaration();

    if (kind != OwnerKind.DEFAULT_IMPLS && isInterface(contextClass)) {
      return;
    }

    if (!isDefaultNeeded(functionDescriptor)) {
      return;
    }

    int flags =
        getVisibilityAccessFlag(functionDescriptor)
            | getDeprecatedAccessFlag(functionDescriptor)
            | ACC_SYNTHETIC;
    if (!(functionDescriptor instanceof ConstructorDescriptor)) {
      flags |= ACC_STATIC | ACC_BRIDGE;
    }
    // $default methods are never private to be accessible from other class files (e.g. inner)
    // without the need of synthetic accessors
    flags &= ~ACC_PRIVATE;

    Method defaultMethod = typeMapper.mapDefaultMethod(functionDescriptor, kind);

    MethodVisitor mv =
        v.newMethod(
            JvmDeclarationOriginKt.Synthetic(function, functionDescriptor),
            flags,
            defaultMethod.getName(),
            defaultMethod.getDescriptor(),
            null,
            getThrownExceptions(functionDescriptor, typeMapper));

    // Only method annotations are copied to the $default method. Parameter annotations are not
    // copied until there are valid use cases;
    // enum constructors have two additional synthetic parameters which somewhat complicate this
    // task
    AnnotationCodegen.forMethod(mv, typeMapper)
        .genAnnotations(functionDescriptor, defaultMethod.getReturnType());

    if (state.getClassBuilderMode() == ClassBuilderMode.FULL) {
      if (this.owner instanceof MultifileClassFacadeContext) {
        mv.visitCode();
        generateFacadeDelegateMethodBody(
            mv, defaultMethod, (MultifileClassFacadeContext) this.owner);
        endVisit(mv, "default method delegation", getSourceFromDescriptor(functionDescriptor));
      } else {
        mv.visitCode();
        generateDefaultImplBody(
            owner, functionDescriptor, mv, loadStrategy, function, memberCodegen, defaultMethod);
        endVisit(mv, "default method", getSourceFromDescriptor(functionDescriptor));
      }
    }
  }
Esempio n. 2
0
  private void generateBridge(
      @Nullable PsiElement origin,
      @NotNull FunctionDescriptor descriptor,
      @NotNull Method bridge,
      @NotNull Method delegateTo,
      boolean isSpecialBridge,
      boolean isStubDeclarationWithDelegationToSuper) {
    boolean isSpecialOrDelegationToSuper =
        isSpecialBridge || isStubDeclarationWithDelegationToSuper;
    int flags =
        ACC_PUBLIC
            | ACC_BRIDGE
            | (!isSpecialOrDelegationToSuper ? ACC_SYNTHETIC : 0)
            | (isSpecialBridge ? ACC_FINAL : 0); // TODO.

    MethodVisitor mv =
        v.newMethod(
            JvmDeclarationOriginKt.Bridge(descriptor, origin),
            flags,
            bridge.getName(),
            bridge.getDescriptor(),
            null,
            null);
    if (state.getClassBuilderMode() != ClassBuilderMode.FULL) return;

    mv.visitCode();

    Type[] argTypes = bridge.getArgumentTypes();
    Type[] originalArgTypes = delegateTo.getArgumentTypes();

    InstructionAdapter iv = new InstructionAdapter(mv);
    MemberCodegen.markLineNumberForDescriptor(owner.getThisDescriptor(), iv);

    if (delegateTo.getArgumentTypes().length == 1 && isSpecialBridge) {
      generateTypeCheckBarrierIfNeeded(
          iv, descriptor, bridge.getReturnType(), delegateTo.getArgumentTypes()[0]);
    }

    iv.load(0, OBJECT_TYPE);
    for (int i = 0, reg = 1; i < argTypes.length; i++) {
      StackValue.local(reg, argTypes[i]).put(originalArgTypes[i], iv);
      //noinspection AssignmentToForLoopParameter
      reg += argTypes[i].getSize();
    }

    if (isStubDeclarationWithDelegationToSuper) {
      ClassDescriptor parentClass =
          getSuperClassDescriptor((ClassDescriptor) descriptor.getContainingDeclaration());
      assert parentClass != null;
      String parentInternalName = typeMapper.mapClass(parentClass).getInternalName();
      iv.invokespecial(parentInternalName, delegateTo.getName(), delegateTo.getDescriptor());
    } else {
      iv.invokevirtual(v.getThisName(), delegateTo.getName(), delegateTo.getDescriptor());
    }

    StackValue.coerce(delegateTo.getReturnType(), bridge.getReturnType(), iv);
    iv.areturn(bridge.getReturnType());

    endVisit(mv, "bridge method", origin);
  }
Esempio n. 3
0
  private void generateConstInstance() {
    MethodVisitor mv =
        v.newMethod(
            OtherOrigin(element, funDescriptor),
            ACC_STATIC | ACC_SYNTHETIC,
            "<clinit>",
            "()V",
            null,
            ArrayUtil.EMPTY_STRING_ARRAY);
    InstructionAdapter iv = new InstructionAdapter(mv);

    v.newField(
        OtherOrigin(element, funDescriptor),
        ACC_STATIC | ACC_FINAL | ACC_PUBLIC,
        JvmAbi.INSTANCE_FIELD,
        asmType.getDescriptor(),
        null,
        null);

    if (state.getClassBuilderMode() == ClassBuilderMode.FULL) {
      mv.visitCode();
      iv.anew(asmType);
      iv.dup();
      iv.invokespecial(asmType.getInternalName(), "<init>", "()V", false);
      iv.putstatic(asmType.getInternalName(), JvmAbi.INSTANCE_FIELD, asmType.getDescriptor());
      mv.visitInsn(RETURN);
      FunctionCodegen.endVisit(mv, "<clinit>", element);
    }
  }
Esempio n. 4
0
  private void generateBridge(@NotNull Method bridge, @NotNull Method delegate) {
    if (bridge.equals(delegate)) return;

    MethodVisitor mv =
        v.newMethod(
            OtherOrigin(element, funDescriptor),
            ACC_PUBLIC | ACC_BRIDGE,
            bridge.getName(),
            bridge.getDescriptor(),
            null,
            ArrayUtil.EMPTY_STRING_ARRAY);

    if (state.getClassBuilderMode() != ClassBuilderMode.FULL) return;

    mv.visitCode();

    InstructionAdapter iv = new InstructionAdapter(mv);
    ImplementationBodyCodegen.markLineNumberForSyntheticFunction(
        DescriptorUtils.getParentOfType(funDescriptor, ClassDescriptor.class), iv);

    iv.load(0, asmType);

    ReceiverParameterDescriptor receiver = funDescriptor.getExtensionReceiverParameter();
    int count = 1;
    if (receiver != null) {
      StackValue.local(count, bridge.getArgumentTypes()[count - 1])
          .put(typeMapper.mapType(receiver.getType()), iv);
      count++;
    }

    List<ValueParameterDescriptor> params = funDescriptor.getValueParameters();
    for (ValueParameterDescriptor param : params) {
      StackValue.local(count, bridge.getArgumentTypes()[count - 1])
          .put(typeMapper.mapType(param.getType()), iv);
      count++;
    }

    iv.invokevirtual(
        asmType.getInternalName(), delegate.getName(), delegate.getDescriptor(), false);
    StackValue.onStack(delegate.getReturnType()).put(bridge.getReturnType(), iv);

    iv.areturn(bridge.getReturnType());

    FunctionCodegen.endVisit(mv, "bridge", element);
  }
Esempio n. 5
0
  @NotNull
  private Method generateConstructor(@NotNull Type superClassAsmType) {
    List<FieldInfo> args = calculateConstructorParameters(typeMapper, closure, asmType);

    Type[] argTypes = fieldListToTypeArray(args);

    Method constructor = new Method("<init>", Type.VOID_TYPE, argTypes);
    MethodVisitor mv =
        v.newMethod(
            OtherOrigin(element, funDescriptor),
            visibilityFlag,
            "<init>",
            constructor.getDescriptor(),
            null,
            ArrayUtil.EMPTY_STRING_ARRAY);
    if (state.getClassBuilderMode() == ClassBuilderMode.FULL) {
      mv.visitCode();
      InstructionAdapter iv = new InstructionAdapter(mv);

      int k = 1;
      for (FieldInfo fieldInfo : args) {
        k = genAssignInstanceFieldFromParam(fieldInfo, k, iv);
      }

      iv.load(0, superClassAsmType);

      if (superClassAsmType.equals(LAMBDA) || superClassAsmType.equals(FUNCTION_REFERENCE)) {
        int arity = funDescriptor.getValueParameters().size();
        if (funDescriptor.getExtensionReceiverParameter() != null) arity++;
        if (funDescriptor.getDispatchReceiverParameter() != null) arity++;
        iv.iconst(arity);
        iv.invokespecial(superClassAsmType.getInternalName(), "<init>", "(I)V", false);
      } else {
        iv.invokespecial(superClassAsmType.getInternalName(), "<init>", "()V", false);
      }

      iv.visitInsn(RETURN);

      FunctionCodegen.endVisit(iv, "constructor", element);
    }
    return constructor;
  }
Esempio n. 6
0
  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());
  }