Ejemplo n.º 1
0
  private void putCapturedInLocal(
      @NotNull Type type,
      @Nullable StackValue stackValue,
      @Nullable ValueParameterDescriptor valueParameterDescriptor,
      int capturedParamIndex) {
    if (!asFunctionInline && Type.VOID_TYPE != type) {
      // TODO remap only inlinable closure => otherwise we could get a lot of problem
      boolean couldBeRemapped = !shouldPutValue(type, stackValue, valueParameterDescriptor);
      StackValue remappedIndex = couldBeRemapped ? stackValue : null;

      ParameterInfo info;
      if (capturedParamIndex >= 0) {
        CapturedParamDesc capturedParamInfoInLambda =
            activeLambda.getCapturedVars().get(capturedParamIndex);
        info =
            invocationParamBuilder.addCapturedParam(
                capturedParamInfoInLambda, capturedParamInfoInLambda.getFieldName());
        info.setRemapValue(remappedIndex);
      } else {
        info = invocationParamBuilder.addNextParameter(type, false, remappedIndex);
      }

      putParameterOnStack(info);
    }
  }
Ejemplo n.º 2
0
  @Override
  public void putHiddenParams() {
    List<JvmMethodParameterSignature> valueParameters = jvmSignature.getValueParameters();

    if (!isStaticMethod(functionDescriptor, context)) {
      invocationParamBuilder.addNextParameter(AsmTypes.OBJECT_TYPE, false, null);
    }

    for (JvmMethodParameterSignature param : valueParameters) {
      if (param.getKind() == JvmMethodParameterKind.VALUE) {
        break;
      }
      invocationParamBuilder.addNextParameter(param.getAsmType(), false, null);
    }

    List<ParameterInfo> infos = invocationParamBuilder.listNotCaptured();
    putParameterOnStack(infos.toArray(new ParameterInfo[infos.size()]));
  }
Ejemplo n.º 3
0
  public void rememberClosure(JetExpression expression, Type type) {
    JetExpression lambda = JetPsiUtil.deparenthesize(expression);
    assert isInlinableParameterExpression(lambda)
        : "Couldn't find inline expression in " + expression.getText();

    LambdaInfo info = new LambdaInfo(lambda, typeMapper);

    ParameterInfo closureInfo = invocationParamBuilder.addNextParameter(type, true, null);
    closureInfo.setLambda(info);
    expressionMap.put(closureInfo.getIndex(), info);
  }
Ejemplo n.º 4
0
 public void leaveTemps() {
   FrameMap frameMap = codegen.getFrameMap();
   List<ParameterInfo> infos = invocationParamBuilder.listAllParams();
   for (ListIterator<? extends ParameterInfo> iterator = infos.listIterator(infos.size());
       iterator.hasPrevious(); ) {
     ParameterInfo param = iterator.previous();
     if (!param.isSkippedOrRemapped()) {
       frameMap.leaveTemp(param.type);
     }
   }
 }
Ejemplo n.º 5
0
public class InlineCodegen extends CallGenerator {
  private final GenerationState state;
  private final JetTypeMapper typeMapper;

  private final SimpleFunctionDescriptor functionDescriptor;
  private final JvmMethodSignature jvmSignature;
  private final JetElement callElement;
  private final MethodContext context;
  private final ExpressionCodegen codegen;

  private final boolean asFunctionInline;
  private final int initialFrameSize;
  private final boolean isSameModule;

  protected final ParametersBuilder invocationParamBuilder = ParametersBuilder.newBuilder();
  protected final Map<Integer, LambdaInfo> expressionMap = new HashMap<Integer, LambdaInfo>();

  private final ReifiedTypeInliner reifiedTypeInliner;

  private LambdaInfo activeLambda;

  private final SourceMapper sourceMapper;

  public InlineCodegen(
      @NotNull ExpressionCodegen codegen,
      @NotNull GenerationState state,
      @NotNull SimpleFunctionDescriptor functionDescriptor,
      @NotNull JetElement callElement,
      @Nullable ReifiedTypeParameterMappings typeParameterMappings) {
    assert InlineUtil.isInline(functionDescriptor)
        : "InlineCodegen could inline only inline function: " + functionDescriptor;

    this.state = state;
    this.typeMapper = state.getTypeMapper();
    this.codegen = codegen;
    this.callElement = callElement;
    this.functionDescriptor = functionDescriptor.getOriginal();

    reifiedTypeInliner = new ReifiedTypeInliner(typeParameterMappings);

    initialFrameSize = codegen.getFrameMap().getCurrentSize();

    context = (MethodContext) getContext(functionDescriptor, state);
    jvmSignature = typeMapper.mapSignature(functionDescriptor, context.getContextKind());

    // TODO: implement AS_FUNCTION inline strategy
    InlineStrategy inlineStrategy = InlineUtil.getInlineStrategy(functionDescriptor);
    this.asFunctionInline = false;

    isSameModule =
        JvmCodegenUtil.isCallInsideSameModuleAsDeclared(
            functionDescriptor, codegen.getContext(), state.getOutDirectory());

    sourceMapper = codegen.getParentCodegen().getOrCreateSourceMapper();
    reportIncrementalInfo(
        functionDescriptor, codegen.getContext().getFunctionDescriptor().getOriginal());
  }

  @Override
  public void genCallWithoutAssertions(
      @NotNull CallableMethod callableMethod, @NotNull ExpressionCodegen codegen) {
    genCall(callableMethod, null, false, codegen);
  }

  @Override
  public void genCallInner(
      @NotNull Callable callableMethod,
      @Nullable ResolvedCall<?> resolvedCall,
      boolean callDefault,
      @NotNull ExpressionCodegen codegen) {
    SMAPAndMethodNode nodeAndSmap = null;
    if (!state.getInlineCycleReporter().enterIntoInlining(resolvedCall)) {
      generateStub(resolvedCall, codegen);
      return;
    }

    try {
      nodeAndSmap = createMethodNode(callDefault);
      endCall(inlineCall(nodeAndSmap));
    } catch (CompilationException e) {
      throw e;
    } catch (Exception e) {
      boolean generateNodeText = !(e instanceof InlineException);
      PsiElement element =
          DescriptorToSourceUtils.descriptorToDeclaration(
              this.codegen.getContext().getContextDescriptor());
      throw new CompilationException(
          "Couldn't inline method call '"
              + functionDescriptor.getName()
              + "' into \n"
              + (element != null
                  ? element.getText()
                  : "null psi element " + this.codegen.getContext().getContextDescriptor())
              + (generateNodeText
                  ? ("\ncause: "
                      + InlineCodegenUtil.getNodeText(
                          nodeAndSmap != null ? nodeAndSmap.getNode() : null))
                  : ""),
          e,
          callElement);
    } finally {
      state.getInlineCycleReporter().exitFromInliningOf(resolvedCall);
    }
  }

  protected void generateStub(
      @Nullable ResolvedCall<?> resolvedCall, @NotNull ExpressionCodegen codegen) {
    leaveTemps();
    assert resolvedCall != null;
    String message =
        "Call is part of inline cycle: " + resolvedCall.getCall().getCallElement().getText();
    AsmUtil.genThrow(codegen.v, "java/lang/UnsupportedOperationException", message);
  }

  private void endCall(@NotNull InlineResult result) {
    leaveTemps();

    codegen.propagateChildReifiedTypeParametersUsages(result.getReifiedTypeParametersUsages());

    state.getFactory().removeInlinedClasses(result.getClassesToRemove());

    codegen.markLineNumberAfterInlineIfNeeded();
  }

  @NotNull
  private SMAPAndMethodNode createMethodNode(boolean callDefault)
      throws ClassNotFoundException, IOException {
    JvmMethodSignature jvmSignature =
        typeMapper.mapSignature(functionDescriptor, context.getContextKind());

    Method asmMethod;
    if (callDefault) {
      asmMethod = typeMapper.mapDefaultMethod(functionDescriptor, context.getContextKind());
    } else {
      asmMethod = jvmSignature.getAsmMethod();
    }

    SMAPAndMethodNode nodeAndSMAP;
    if (functionDescriptor instanceof DeserializedSimpleFunctionDescriptor) {
      JetTypeMapper.ContainingClassesInfo containingClasses =
          typeMapper.getContainingClassesForDeserializedCallable(
              (DeserializedSimpleFunctionDescriptor) functionDescriptor);

      VirtualFile file =
          InlineCodegenUtil.getVirtualFileForCallable(containingClasses.getImplClassId(), state);
      nodeAndSMAP =
          InlineCodegenUtil.getMethodNode(
              file.contentsToByteArray(),
              asmMethod.getName(),
              asmMethod.getDescriptor(),
              containingClasses.getFacadeClassId());

      if (nodeAndSMAP == null) {
        throw new RuntimeException(
            "Couldn't obtain compiled function body for " + descriptorName(functionDescriptor));
      }
    } else {
      PsiElement element = DescriptorToSourceUtils.descriptorToDeclaration(functionDescriptor);

      if (element == null || !(element instanceof JetNamedFunction)) {
        throw new RuntimeException(
            "Couldn't find declaration for function " + descriptorName(functionDescriptor));
      }
      JetNamedFunction inliningFunction = (JetNamedFunction) element;

      MethodNode node =
          new MethodNode(
              InlineCodegenUtil.API,
              getMethodAsmFlags(functionDescriptor, context.getContextKind())
                  | (callDefault ? Opcodes.ACC_STATIC : 0),
              asmMethod.getName(),
              asmMethod.getDescriptor(),
              jvmSignature.getGenericsSignature(),
              null);

      // for maxLocals calculation
      MethodVisitor maxCalcAdapter = InlineCodegenUtil.wrapWithMaxLocalCalc(node);
      MethodContext methodContext = context.getParentContext().intoFunction(functionDescriptor);

      SMAP smap;
      if (callDefault) {
        Type implementationOwner = typeMapper.mapOwner(functionDescriptor);
        FakeMemberCodegen parentCodegen =
            new FakeMemberCodegen(
                codegen.getParentCodegen(),
                inliningFunction,
                (FieldOwnerContext) methodContext.getParentContext(),
                implementationOwner.getInternalName());
        FunctionCodegen.generateDefaultImplBody(
            methodContext,
            functionDescriptor,
            maxCalcAdapter,
            DefaultParameterValueLoader.DEFAULT,
            inliningFunction,
            parentCodegen);
        smap =
            createSMAPWithDefaultMapping(
                inliningFunction, parentCodegen.getOrCreateSourceMapper().getResultMappings());
      } else {
        smap =
            generateMethodBody(
                maxCalcAdapter,
                functionDescriptor,
                methodContext,
                inliningFunction,
                jvmSignature,
                false);
      }

      nodeAndSMAP = new SMAPAndMethodNode(node, smap);
      maxCalcAdapter.visitMaxs(-1, -1);
      maxCalcAdapter.visitEnd();
    }
    return nodeAndSMAP;
  }

  private InlineResult inlineCall(SMAPAndMethodNode nodeAndSmap) {
    MethodNode node = nodeAndSmap.getNode();
    ReifiedTypeParametersUsages reificationResult =
        reifiedTypeInliner.reifyInstructions(node.instructions);
    generateClosuresBodies();

    // through generation captured parameters will be added to invocationParamBuilder
    putClosureParametersOnStack();

    addInlineMarker(codegen.v, true);

    Parameters parameters = invocationParamBuilder.buildParameters();

    InliningContext info =
        new RootInliningContext(
            expressionMap,
            state,
            codegen.getInlineNameGenerator().subGenerator(functionDescriptor.getName().asString()),
            codegen.getContext(),
            callElement,
            codegen.getParentCodegen().getClassName(),
            reifiedTypeInliner);

    MethodInliner inliner =
        new MethodInliner(
            node,
            parameters,
            info,
            new FieldRemapper(null, null, parameters),
            isSameModule,
            "Method inlining " + callElement.getText(),
            createNestedSourceMapper(nodeAndSmap)); // with captured

    LocalVarRemapper remapper = new LocalVarRemapper(parameters, initialFrameSize);

    MethodNode adapter = InlineCodegenUtil.createEmptyMethodNode();
    // hack to keep linenumber info, otherwise jdi will skip begin of linenumber chain
    adapter.visitInsn(Opcodes.NOP);

    InlineResult result = inliner.doInline(adapter, remapper, true, LabelOwner.SKIP_ALL);
    result.getReifiedTypeParametersUsages().mergeAll(reificationResult);

    CallableMemberDescriptor descriptor = codegen.getContext().getContextDescriptor();
    final Set<String> labels =
        getDeclarationLabels(
            DescriptorToSourceUtils.descriptorToDeclaration(descriptor), descriptor);
    LabelOwner labelOwner =
        new LabelOwner() {
          @Override
          public boolean isMyLabel(@NotNull String name) {
            return labels.contains(name);
          }
        };

    List<MethodInliner.PointForExternalFinallyBlocks> infos =
        MethodInliner.processReturns(adapter, labelOwner, true, null);
    generateAndInsertFinallyBlocks(
        adapter,
        infos,
        ((StackValue.Local) remapper.remap(parameters.totalSize() + 1).value).index);
    removeFinallyMarkers(adapter);

    adapter.accept(new InliningInstructionAdapter(codegen.v));

    addInlineMarker(codegen.v, false);

    return result;
  }

  private void generateClosuresBodies() {
    for (LambdaInfo info : expressionMap.values()) {
      info.setNode(generateLambdaBody(info));
    }
  }

  private SMAPAndMethodNode generateLambdaBody(LambdaInfo info) {
    JetExpression declaration = info.getFunctionWithBodyOrCallableReference();
    FunctionDescriptor descriptor = info.getFunctionDescriptor();

    MethodContext parentContext = codegen.getContext();

    MethodContext context =
        parentContext.intoClosure(descriptor, codegen, typeMapper).intoInlinedLambda(descriptor);

    JvmMethodSignature jvmMethodSignature = typeMapper.mapSignature(descriptor);
    Method asmMethod = jvmMethodSignature.getAsmMethod();
    MethodNode methodNode =
        new MethodNode(
            InlineCodegenUtil.API,
            getMethodAsmFlags(descriptor, context.getContextKind()),
            asmMethod.getName(),
            asmMethod.getDescriptor(),
            jvmMethodSignature.getGenericsSignature(),
            null);

    MethodVisitor adapter = InlineCodegenUtil.wrapWithMaxLocalCalc(methodNode);

    SMAP smap =
        generateMethodBody(adapter, descriptor, context, declaration, jvmMethodSignature, true);
    adapter.visitMaxs(-1, -1);
    return new SMAPAndMethodNode(methodNode, smap);
  }

  private SMAP generateMethodBody(
      @NotNull MethodVisitor adapter,
      @NotNull FunctionDescriptor descriptor,
      @NotNull MethodContext context,
      @NotNull JetExpression expression,
      @NotNull JvmMethodSignature jvmMethodSignature,
      boolean isLambda) {
    FakeMemberCodegen parentCodegen =
        new FakeMemberCodegen(
            codegen.getParentCodegen(),
            expression,
            (FieldOwnerContext) context.getParentContext(),
            isLambda
                ? codegen.getParentCodegen().getClassName()
                : typeMapper.mapOwner(descriptor).getInternalName());

    FunctionGenerationStrategy strategy =
        expression instanceof JetCallableReferenceExpression
            ? new FunctionReferenceGenerationStrategy(
                state,
                descriptor,
                CallUtilKt.getResolvedCallWithAssert(
                    ((JetCallableReferenceExpression) expression).getCallableReference(),
                    codegen.getBindingContext()))
            : new FunctionGenerationStrategy.FunctionDefault(
                state, descriptor, (JetDeclarationWithBody) expression);

    FunctionCodegen.generateMethodBody(
        adapter,
        descriptor,
        context,
        jvmMethodSignature,
        strategy,
        // Wrapping for preventing marking actual parent codegen as containing reifier markers
        parentCodegen);

    return createSMAPWithDefaultMapping(
        expression, parentCodegen.getOrCreateSourceMapper().getResultMappings());
  }

  private static SMAP createSMAPWithDefaultMapping(
      @NotNull JetExpression declaration, @NotNull List<FileMapping> mappings) {
    PsiFile containingFile = declaration.getContainingFile();
    Integer lineNumbers = CodegenUtil.getLineNumberForElement(containingFile, true);
    assert lineNumbers != null : "Couldn't extract line count in " + containingFile;

    return new SMAP(mappings);
  }

  private static class FakeMemberCodegen extends MemberCodegen {

    private final MemberCodegen delegate;
    @NotNull private final String className;

    public FakeMemberCodegen(
        @NotNull MemberCodegen wrapped,
        @NotNull JetElement declaration,
        @NotNull FieldOwnerContext codegenContext,
        @NotNull String className) {
      super(wrapped, declaration, codegenContext);
      delegate = wrapped;
      this.className = className;
    }

    @Override
    protected void generateDeclaration() {
      throw new IllegalStateException();
    }

    @Override
    protected void generateBody() {
      throw new IllegalStateException();
    }

    @Override
    protected void generateKotlinAnnotation() {
      throw new IllegalStateException();
    }

    @NotNull
    @Override
    public NameGenerator getInlineNameGenerator() {
      return delegate.getInlineNameGenerator();
    }

    @NotNull
    @Override
    // TODO: obtain name from context
    public String getClassName() {
      return className;
    }
  }

  @Override
  public void afterParameterPut(
      @NotNull Type type,
      @Nullable StackValue stackValue,
      @Nullable ValueParameterDescriptor valueParameterDescriptor) {
    putCapturedInLocal(type, stackValue, valueParameterDescriptor, -1);
  }

  private void putCapturedInLocal(
      @NotNull Type type,
      @Nullable StackValue stackValue,
      @Nullable ValueParameterDescriptor valueParameterDescriptor,
      int capturedParamIndex) {
    if (!asFunctionInline && Type.VOID_TYPE != type) {
      // TODO remap only inlinable closure => otherwise we could get a lot of problem
      boolean couldBeRemapped = !shouldPutValue(type, stackValue, valueParameterDescriptor);
      StackValue remappedIndex = couldBeRemapped ? stackValue : null;

      ParameterInfo info;
      if (capturedParamIndex >= 0) {
        CapturedParamDesc capturedParamInfoInLambda =
            activeLambda.getCapturedVars().get(capturedParamIndex);
        info =
            invocationParamBuilder.addCapturedParam(
                capturedParamInfoInLambda, capturedParamInfoInLambda.getFieldName());
        info.setRemapValue(remappedIndex);
      } else {
        info = invocationParamBuilder.addNextParameter(type, false, remappedIndex);
      }

      putParameterOnStack(info);
    }
  }

  /*descriptor is null for captured vars*/
  public boolean shouldPutValue(
      @NotNull Type type,
      @Nullable StackValue stackValue,
      @Nullable ValueParameterDescriptor descriptor) {

    if (stackValue == null) {
      // default or vararg
      return true;
    }

    // remap only inline functions (and maybe non primitives)
    // TODO - clean asserion and remapping logic
    if (isPrimitive(type) != isPrimitive(stackValue.type)) {
      // don't remap boxing/unboxing primitives - lost identity and perfomance
      return true;
    }

    if (stackValue instanceof StackValue.Local) {
      return false;
    }

    StackValue field = stackValue;
    if (stackValue instanceof StackValue.FieldForSharedVar) {
      field = ((StackValue.FieldForSharedVar) stackValue).receiver;
    }

    // check that value corresponds to captured inlining parameter
    if (field instanceof StackValue.Field) {
      DeclarationDescriptor varDescriptor = ((StackValue.Field) field).descriptor;
      // check that variable is inline function parameter
      return !(varDescriptor instanceof ParameterDescriptor
          && InlineUtil.isInlineLambdaParameter((ParameterDescriptor) varDescriptor)
          && InlineUtil.isInline(varDescriptor.getContainingDeclaration()));
    }

    return true;
  }

  private void putParameterOnStack(ParameterInfo... infos) {
    int[] index = new int[infos.length];
    for (int i = 0; i < infos.length; i++) {
      ParameterInfo info = infos[i];
      if (!info.isSkippedOrRemapped()) {
        index[i] = codegen.getFrameMap().enterTemp(info.getType());
      } else {
        index[i] = -1;
      }
    }

    for (int i = infos.length - 1; i >= 0; i--) {
      ParameterInfo info = infos[i];
      if (!info.isSkippedOrRemapped()) {
        Type type = info.type;
        StackValue.local(index[i], type).store(StackValue.onStack(type), codegen.v);
      }
    }
  }

  @Override
  public void putHiddenParams() {
    List<JvmMethodParameterSignature> valueParameters = jvmSignature.getValueParameters();

    if (!isStaticMethod(functionDescriptor, context)) {
      invocationParamBuilder.addNextParameter(AsmTypes.OBJECT_TYPE, false, null);
    }

    for (JvmMethodParameterSignature param : valueParameters) {
      if (param.getKind() == JvmMethodParameterKind.VALUE) {
        break;
      }
      invocationParamBuilder.addNextParameter(param.getAsmType(), false, null);
    }

    List<ParameterInfo> infos = invocationParamBuilder.listNotCaptured();
    putParameterOnStack(infos.toArray(new ParameterInfo[infos.size()]));
  }

  public void leaveTemps() {
    FrameMap frameMap = codegen.getFrameMap();
    List<ParameterInfo> infos = invocationParamBuilder.listAllParams();
    for (ListIterator<? extends ParameterInfo> iterator = infos.listIterator(infos.size());
        iterator.hasPrevious(); ) {
      ParameterInfo param = iterator.previous();
      if (!param.isSkippedOrRemapped()) {
        frameMap.leaveTemp(param.type);
      }
    }
  }

  /*lambda or callable reference*/
  public static boolean isInliningParameter(
      JetExpression expression, ValueParameterDescriptor valueParameterDescriptor) {
    // TODO deparenthisise typed
    JetExpression deparenthesized = JetPsiUtil.deparenthesize(expression);
    return InlineUtil.isInlineLambdaParameter(valueParameterDescriptor)
        && isInlinableParameterExpression(deparenthesized);
  }

  protected static boolean isInlinableParameterExpression(JetExpression deparenthesized) {
    return deparenthesized instanceof JetFunctionLiteralExpression
        || deparenthesized instanceof JetNamedFunction
        || deparenthesized instanceof JetCallableReferenceExpression;
  }

  public void rememberClosure(JetExpression expression, Type type) {
    JetExpression lambda = JetPsiUtil.deparenthesize(expression);
    assert isInlinableParameterExpression(lambda)
        : "Couldn't find inline expression in " + expression.getText();

    LambdaInfo info = new LambdaInfo(lambda, typeMapper);

    ParameterInfo closureInfo = invocationParamBuilder.addNextParameter(type, true, null);
    closureInfo.setLambda(info);
    expressionMap.put(closureInfo.getIndex(), info);
  }

  @NotNull
  protected static Set<String> getDeclarationLabels(
      @Nullable PsiElement lambdaOrFun, @NotNull DeclarationDescriptor descriptor) {
    Set<String> result = new HashSet<String>();

    if (lambdaOrFun != null) {
      Name label = LabelResolver.INSTANCE.getLabelNameIfAny(lambdaOrFun);
      if (label != null) {
        result.add(label.asString());
      }
    }

    if (!isFunctionLiteral(descriptor)) {
      if (!descriptor.getName().isSpecial()) {
        result.add(descriptor.getName().asString());
      }
      result.add(InlineCodegenUtil.FIRST_FUN_LABEL);
    }
    return result;
  }

  private void putClosureParametersOnStack() {
    for (LambdaInfo next : expressionMap.values()) {
      activeLambda = next;
      codegen.pushClosureOnStack(next.getClassDescriptor(), true, this);
    }
    activeLambda = null;
  }

  public static CodegenContext getContext(DeclarationDescriptor descriptor, GenerationState state) {
    if (descriptor instanceof PackageFragmentDescriptor) {
      return new PackageContext(
          (PackageFragmentDescriptor) descriptor, state.getRootContext(), null);
    }

    CodegenContext parent = getContext(descriptor.getContainingDeclaration(), state);

    if (descriptor instanceof ClassDescriptor) {
      OwnerKind kind =
          DescriptorUtils.isInterface(descriptor)
              ? OwnerKind.DEFAULT_IMPLS
              : OwnerKind.IMPLEMENTATION;
      return parent.intoClass((ClassDescriptor) descriptor, kind, state);
    } else if (descriptor instanceof ScriptDescriptor) {
      ClassDescriptor classDescriptorForScript =
          state.getBindingContext().get(CLASS_FOR_SCRIPT, (ScriptDescriptor) descriptor);
      assert classDescriptorForScript != null : "Can't find class for script: " + descriptor;
      List<ScriptDescriptor> earlierScripts = state.getEarlierScriptsForReplInterpreter();
      return parent.intoScript(
          (ScriptDescriptor) descriptor,
          earlierScripts == null ? Collections.emptyList() : earlierScripts,
          classDescriptorForScript);
    } else if (descriptor instanceof FunctionDescriptor) {
      return parent.intoFunction((FunctionDescriptor) descriptor);
    }

    throw new IllegalStateException("Couldn't build context for " + descriptorName(descriptor));
  }

  private static boolean isStaticMethod(
      FunctionDescriptor functionDescriptor, MethodContext context) {
    return (getMethodAsmFlags(functionDescriptor, context.getContextKind()) & Opcodes.ACC_STATIC)
        != 0;
  }

  private static String descriptorName(DeclarationDescriptor descriptor) {
    return DescriptorRenderer.SHORT_NAMES_IN_TYPES.render(descriptor);
  }

  @Override
  public void genValueAndPut(
      @NotNull ValueParameterDescriptor valueParameterDescriptor,
      @NotNull JetExpression argumentExpression,
      @NotNull Type parameterType) {
    if (isInliningParameter(argumentExpression, valueParameterDescriptor)) {
      rememberClosure(argumentExpression, parameterType);
    } else {
      StackValue value = codegen.gen(argumentExpression);
      putValueIfNeeded(valueParameterDescriptor, parameterType, value);
    }
  }

  @Override
  public void putValueIfNeeded(
      @Nullable ValueParameterDescriptor valueParameterDescriptor,
      @NotNull Type parameterType,
      @NotNull StackValue value) {
    if (shouldPutValue(parameterType, value, valueParameterDescriptor)) {
      value.put(parameterType, codegen.v);
    }
    afterParameterPut(parameterType, value, valueParameterDescriptor);
  }

  @Override
  public void putCapturedValueOnStack(
      @NotNull StackValue stackValue, @NotNull Type valueType, int paramIndex) {
    if (shouldPutValue(stackValue.type, stackValue, null)) {
      stackValue.put(stackValue.type, codegen.v);
    }
    putCapturedInLocal(stackValue.type, stackValue, null, paramIndex);
  }

  public void generateAndInsertFinallyBlocks(
      @NotNull MethodNode intoNode,
      @NotNull List<MethodInliner.PointForExternalFinallyBlocks> insertPoints,
      int offsetForFinallyLocalVar) {
    if (!codegen.hasFinallyBlocks()) return;

    Map<AbstractInsnNode, MethodInliner.PointForExternalFinallyBlocks> extensionPoints =
        new HashMap<AbstractInsnNode, MethodInliner.PointForExternalFinallyBlocks>();
    for (MethodInliner.PointForExternalFinallyBlocks insertPoint : insertPoints) {
      extensionPoints.put(insertPoint.beforeIns, insertPoint);
    }

    DefaultProcessor processor = new DefaultProcessor(intoNode, offsetForFinallyLocalVar);

    int curFinallyDepth = 0;
    AbstractInsnNode curInstr = intoNode.instructions.getFirst();
    while (curInstr != null) {
      processor.processInstruction(curInstr, true);
      if (InlineCodegenUtil.isFinallyStart(curInstr)) {
        // TODO depth index calc could be more precise
        curFinallyDepth = getConstant(curInstr.getPrevious());
      }

      MethodInliner.PointForExternalFinallyBlocks extension = extensionPoints.get(curInstr);
      if (extension != null) {
        Label start = new Label();

        MethodNode finallyNode = InlineCodegenUtil.createEmptyMethodNode();
        finallyNode.visitLabel(start);

        ExpressionCodegen finallyCodegen =
            new ExpressionCodegen(
                finallyNode,
                codegen.getFrameMap(),
                codegen.getReturnType(),
                codegen.getContext(),
                codegen.getState(),
                codegen.getParentCodegen());
        finallyCodegen.addBlockStackElementsForNonLocalReturns(
            codegen.getBlockStackElements(), curFinallyDepth);

        FrameMap frameMap = finallyCodegen.getFrameMap();
        FrameMap.Mark mark = frameMap.mark();
        while (frameMap.getCurrentSize() < processor.getNextFreeLocalIndex()) {
          frameMap.enterTemp(Type.INT_TYPE);
        }

        finallyCodegen.generateFinallyBlocksIfNeeded(
            extension.returnType, extension.finallyIntervalEnd.getLabel());

        // Exception table for external try/catch/finally blocks will be generated in original
        // codegen after exiting this method
        InlineCodegenUtil.insertNodeBefore(finallyNode, intoNode, curInstr);

        SimpleInterval splitBy =
            new SimpleInterval((LabelNode) start.info, extension.finallyIntervalEnd);
        processor.getTryBlocksMetaInfo().splitCurrentIntervals(splitBy, true);

        // processor.getLocalVarsMetaInfo().splitAndRemoveIntervalsFromCurrents(splitBy);

        mark.dropTo();
      }

      curInstr = curInstr.getNext();
    }

    processor.substituteTryBlockNodes(intoNode);

    // processor.substituteLocalVarTable(intoNode);
  }

  public void removeFinallyMarkers(@NotNull MethodNode intoNode) {
    if (InlineCodegenUtil.isFinallyMarkerRequired(codegen.getContext())) return;

    InsnList instructions = intoNode.instructions;
    AbstractInsnNode curInstr = instructions.getFirst();
    while (curInstr != null) {
      if (InlineCodegenUtil.isFinallyMarker(curInstr)) {
        AbstractInsnNode marker = curInstr;
        // just to assert
        getConstant(marker.getPrevious());
        curInstr = curInstr.getNext();
        instructions.remove(marker.getPrevious());
        instructions.remove(marker);
        continue;
      }
      curInstr = curInstr.getNext();
    }
  }

  private SourceMapper createNestedSourceMapper(@NotNull SMAPAndMethodNode nodeAndSmap) {
    return new NestedSourceMapper(
        sourceMapper, nodeAndSmap.getRanges(), nodeAndSmap.getClassSMAP().getSourceInfo());
  }

  private void reportIncrementalInfo(
      @NotNull FunctionDescriptor sourceDescriptor, @NotNull FunctionDescriptor targetDescriptor) {
    IncrementalCompilationComponents incrementalCompilationComponents =
        state.getIncrementalCompilationComponents();
    TargetId targetId = state.getTargetId();

    if (incrementalCompilationComponents == null || targetId == null) return;

    IncrementalCache incrementalCache =
        incrementalCompilationComponents.getIncrementalCache(targetId);
    String sourceFile = getClassFilePath(sourceDescriptor, incrementalCache);
    String targetFile = getSourceFilePath(targetDescriptor);
    incrementalCache.registerInline(sourceFile, jvmSignature.toString(), targetFile);
  }
}
Ejemplo n.º 6
0
  private InlineResult inlineCall(SMAPAndMethodNode nodeAndSmap) {
    MethodNode node = nodeAndSmap.getNode();
    ReifiedTypeParametersUsages reificationResult =
        reifiedTypeInliner.reifyInstructions(node.instructions);
    generateClosuresBodies();

    // through generation captured parameters will be added to invocationParamBuilder
    putClosureParametersOnStack();

    addInlineMarker(codegen.v, true);

    Parameters parameters = invocationParamBuilder.buildParameters();

    InliningContext info =
        new RootInliningContext(
            expressionMap,
            state,
            codegen.getInlineNameGenerator().subGenerator(functionDescriptor.getName().asString()),
            codegen.getContext(),
            callElement,
            codegen.getParentCodegen().getClassName(),
            reifiedTypeInliner);

    MethodInliner inliner =
        new MethodInliner(
            node,
            parameters,
            info,
            new FieldRemapper(null, null, parameters),
            isSameModule,
            "Method inlining " + callElement.getText(),
            createNestedSourceMapper(nodeAndSmap)); // with captured

    LocalVarRemapper remapper = new LocalVarRemapper(parameters, initialFrameSize);

    MethodNode adapter = InlineCodegenUtil.createEmptyMethodNode();
    // hack to keep linenumber info, otherwise jdi will skip begin of linenumber chain
    adapter.visitInsn(Opcodes.NOP);

    InlineResult result = inliner.doInline(adapter, remapper, true, LabelOwner.SKIP_ALL);
    result.getReifiedTypeParametersUsages().mergeAll(reificationResult);

    CallableMemberDescriptor descriptor = codegen.getContext().getContextDescriptor();
    final Set<String> labels =
        getDeclarationLabels(
            DescriptorToSourceUtils.descriptorToDeclaration(descriptor), descriptor);
    LabelOwner labelOwner =
        new LabelOwner() {
          @Override
          public boolean isMyLabel(@NotNull String name) {
            return labels.contains(name);
          }
        };

    List<MethodInliner.PointForExternalFinallyBlocks> infos =
        MethodInliner.processReturns(adapter, labelOwner, true, null);
    generateAndInsertFinallyBlocks(
        adapter,
        infos,
        ((StackValue.Local) remapper.remap(parameters.totalSize() + 1).value).index);
    removeFinallyMarkers(adapter);

    adapter.accept(new InliningInstructionAdapter(codegen.v));

    addInlineMarker(codegen.v, false);

    return result;
  }