Convert InlineCodegenUtil to Kotlin
This commit is contained in:
@@ -20,7 +20,6 @@ import com.intellij.psi.PsiElement;
|
|||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.kotlin.codegen.inline.FileMapping;
|
import org.jetbrains.kotlin.codegen.inline.FileMapping;
|
||||||
import org.jetbrains.kotlin.codegen.inline.InlineCodegenUtil;
|
|
||||||
import org.jetbrains.kotlin.codegen.inline.SMAPBuilder;
|
import org.jetbrains.kotlin.codegen.inline.SMAPBuilder;
|
||||||
import org.jetbrains.kotlin.codegen.serialization.JvmSerializationBindings;
|
import org.jetbrains.kotlin.codegen.serialization.JvmSerializationBindings;
|
||||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin;
|
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin;
|
||||||
@@ -29,6 +28,8 @@ import org.jetbrains.org.objectweb.asm.*;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.jetbrains.kotlin.codegen.inline.InlineCodegenUtilsKt.GENERATE_SMAP;
|
||||||
|
|
||||||
public abstract class AbstractClassBuilder implements ClassBuilder {
|
public abstract class AbstractClassBuilder implements ClassBuilder {
|
||||||
protected static final MethodVisitor EMPTY_METHOD_VISITOR = new MethodVisitor(Opcodes.ASM5) {};
|
protected static final MethodVisitor EMPTY_METHOD_VISITOR = new MethodVisitor(Opcodes.ASM5) {};
|
||||||
protected static final FieldVisitor EMPTY_FIELD_VISITOR = new FieldVisitor(Opcodes.ASM5) {};
|
protected static final FieldVisitor EMPTY_FIELD_VISITOR = new FieldVisitor(Opcodes.ASM5) {};
|
||||||
@@ -105,7 +106,7 @@ public abstract class AbstractClassBuilder implements ClassBuilder {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void done() {
|
public void done() {
|
||||||
if (!fileMappings.isEmpty() && InlineCodegenUtil.GENERATE_SMAP) {
|
if (!fileMappings.isEmpty() && GENERATE_SMAP) {
|
||||||
FileMapping origin = fileMappings.get(0);
|
FileMapping origin = fileMappings.get(0);
|
||||||
assert sourceName == null || origin.getName().equals(sourceName) : "Error " + origin.getName() + " != " + sourceName;
|
assert sourceName == null || origin.getName().equals(sourceName) : "Error " + origin.getName() + " != " + sourceName;
|
||||||
getVisitor().visitSource(origin.getName(), new SMAPBuilder(origin.getName(), origin.getPath(), fileMappings).build());
|
getVisitor().visitSource(origin.getName(), new SMAPBuilder(origin.getName(), origin.getPath(), fileMappings).build());
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ import org.jetbrains.kotlin.codegen.binding.CalculatedClosure;
|
|||||||
import org.jetbrains.kotlin.codegen.context.ClosureContext;
|
import org.jetbrains.kotlin.codegen.context.ClosureContext;
|
||||||
import org.jetbrains.kotlin.codegen.context.EnclosedValueDescriptor;
|
import org.jetbrains.kotlin.codegen.context.EnclosedValueDescriptor;
|
||||||
import org.jetbrains.kotlin.codegen.coroutines.CoroutineCodegenUtilKt;
|
import org.jetbrains.kotlin.codegen.coroutines.CoroutineCodegenUtilKt;
|
||||||
import org.jetbrains.kotlin.codegen.inline.InlineCodegenUtil;
|
|
||||||
import org.jetbrains.kotlin.codegen.serialization.JvmSerializerExtension;
|
import org.jetbrains.kotlin.codegen.serialization.JvmSerializerExtension;
|
||||||
import org.jetbrains.kotlin.codegen.signature.BothSignatureWriter;
|
import org.jetbrains.kotlin.codegen.signature.BothSignatureWriter;
|
||||||
import org.jetbrains.kotlin.codegen.signature.JvmSignatureWriter;
|
import org.jetbrains.kotlin.codegen.signature.JvmSignatureWriter;
|
||||||
@@ -60,6 +59,7 @@ import java.util.List;
|
|||||||
import static org.jetbrains.kotlin.codegen.AsmUtil.*;
|
import static org.jetbrains.kotlin.codegen.AsmUtil.*;
|
||||||
import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.isConst;
|
import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.isConst;
|
||||||
import static org.jetbrains.kotlin.codegen.binding.CodegenBinding.CLOSURE;
|
import static org.jetbrains.kotlin.codegen.binding.CodegenBinding.CLOSURE;
|
||||||
|
import static org.jetbrains.kotlin.codegen.inline.InlineCodegenUtilsKt.initDefaultSourceMappingIfNeeded;
|
||||||
import static org.jetbrains.kotlin.codegen.serialization.JvmSerializationBindings.METHOD_FOR_FUNCTION;
|
import static org.jetbrains.kotlin.codegen.serialization.JvmSerializationBindings.METHOD_FOR_FUNCTION;
|
||||||
import static org.jetbrains.kotlin.resolve.jvm.AsmTypes.*;
|
import static org.jetbrains.kotlin.resolve.jvm.AsmTypes.*;
|
||||||
import static org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin.NO_ORIGIN;
|
import static org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin.NO_ORIGIN;
|
||||||
@@ -158,7 +158,7 @@ public class ClosureCodegen extends MemberCodegen<KtElement> {
|
|||||||
superInterfaceAsmTypes
|
superInterfaceAsmTypes
|
||||||
);
|
);
|
||||||
|
|
||||||
InlineCodegenUtil.initDefaultSourceMappingIfNeeded(context, this, state);
|
initDefaultSourceMappingIfNeeded(context, this, state);
|
||||||
|
|
||||||
v.visitSource(element.getContainingFile().getName(), null);
|
v.visitSource(element.getContainingFile().getName(), null);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -107,7 +107,7 @@ import static org.jetbrains.kotlin.builtins.KotlinBuiltIns.isInt;
|
|||||||
import static org.jetbrains.kotlin.codegen.AsmUtil.*;
|
import static org.jetbrains.kotlin.codegen.AsmUtil.*;
|
||||||
import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.*;
|
import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.*;
|
||||||
import static org.jetbrains.kotlin.codegen.binding.CodegenBinding.*;
|
import static org.jetbrains.kotlin.codegen.binding.CodegenBinding.*;
|
||||||
import static org.jetbrains.kotlin.codegen.inline.InlineCodegenUtil.addInlineMarker;
|
import static org.jetbrains.kotlin.codegen.inline.InlineCodegenUtilsKt.*;
|
||||||
import static org.jetbrains.kotlin.resolve.BindingContext.*;
|
import static org.jetbrains.kotlin.resolve.BindingContext.*;
|
||||||
import static org.jetbrains.kotlin.resolve.BindingContextUtils.getDelegationConstructorCall;
|
import static org.jetbrains.kotlin.resolve.BindingContextUtils.getDelegationConstructorCall;
|
||||||
import static org.jetbrains.kotlin.resolve.BindingContextUtils.isVarCapturedInClosure;
|
import static org.jetbrains.kotlin.resolve.BindingContextUtils.isVarCapturedInClosure;
|
||||||
@@ -1414,14 +1414,14 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
|||||||
Label finallyStart = new Label();
|
Label finallyStart = new Label();
|
||||||
v.mark(finallyStart);
|
v.mark(finallyStart);
|
||||||
finallyBlockStackElement.addGapLabel(finallyStart);
|
finallyBlockStackElement.addGapLabel(finallyStart);
|
||||||
if (InlineCodegenUtil.isFinallyMarkerRequired(context)) {
|
if (isFinallyMarkerRequired(context)) {
|
||||||
InlineCodegenUtil.generateFinallyMarker(v, finallyDepth, true);
|
generateFinallyMarker(v, finallyDepth, true);
|
||||||
}
|
}
|
||||||
//noinspection ConstantConditions
|
//noinspection ConstantConditions
|
||||||
gen(jetTryExpression.getFinallyBlock().getFinalExpression(), Type.VOID_TYPE);
|
gen(jetTryExpression.getFinallyBlock().getFinalExpression(), Type.VOID_TYPE);
|
||||||
|
|
||||||
if (InlineCodegenUtil.isFinallyMarkerRequired(context)) {
|
if (isFinallyMarkerRequired(context)) {
|
||||||
InlineCodegenUtil.generateFinallyMarker(v, finallyDepth, false);
|
generateFinallyMarker(v, finallyDepth, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1464,7 +1464,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
|||||||
generateFinallyBlocksIfNeeded(returnType, afterReturnLabel);
|
generateFinallyBlocksIfNeeded(returnType, afterReturnLabel);
|
||||||
|
|
||||||
if (isNonLocalReturn) {
|
if (isNonLocalReturn) {
|
||||||
InlineCodegenUtil.generateGlobalReturnFlag(v, nonLocalReturn.labelName);
|
generateGlobalReturnFlag(v, nonLocalReturn.labelName);
|
||||||
v.visitInsn(returnType.getOpcode(Opcodes.IRETURN));
|
v.visitInsn(returnType.getOpcode(Opcodes.IRETURN));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -1502,7 +1502,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
|||||||
FunctionDescriptor containingFunction =
|
FunctionDescriptor containingFunction =
|
||||||
BindingContextUtils.getContainingFunctionSkipFunctionLiterals(descriptor, true).getFirst();
|
BindingContextUtils.getContainingFunctionSkipFunctionLiterals(descriptor, true).getFirst();
|
||||||
//FIRST_FUN_LABEL to prevent clashing with existing labels
|
//FIRST_FUN_LABEL to prevent clashing with existing labels
|
||||||
return new NonLocalReturnInfo(typeMapper.mapReturnType(containingFunction), InlineCodegenUtil.FIRST_FUN_LABEL);
|
return new NonLocalReturnInfo(typeMapper.mapReturnType(containingFunction), FIRST_FUN_LABEL);
|
||||||
} else {
|
} else {
|
||||||
//local
|
//local
|
||||||
return null;
|
return null;
|
||||||
@@ -4217,8 +4217,8 @@ The "returned" value of try expression with no finally is either the last expres
|
|||||||
public NameGenerator getInlineNameGenerator() {
|
public NameGenerator getInlineNameGenerator() {
|
||||||
NameGenerator nameGenerator = getParentCodegen().getInlineNameGenerator();
|
NameGenerator nameGenerator = getParentCodegen().getInlineNameGenerator();
|
||||||
Name name = context.getContextDescriptor().getName();
|
Name name = context.getContextDescriptor().getName();
|
||||||
String inlinedName = name.isSpecial() ? InlineCodegenUtil.SPECIAL_TRANSFORMATION_NAME : name.asString();
|
String inlinedName = name.isSpecial() ? SPECIAL_TRANSFORMATION_NAME : name.asString();
|
||||||
return nameGenerator.subGenerator(inlinedName + InlineCodegenUtil.INLINE_CALL_TRANSFORMATION_SUFFIX);
|
return nameGenerator.subGenerator(inlinedName + INLINE_CALL_TRANSFORMATION_SUFFIX);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Type getReturnType() {
|
public Type getReturnType() {
|
||||||
|
|||||||
@@ -31,7 +31,6 @@ import org.jetbrains.kotlin.codegen.binding.CodegenBinding;
|
|||||||
import org.jetbrains.kotlin.codegen.binding.MutableClosure;
|
import org.jetbrains.kotlin.codegen.binding.MutableClosure;
|
||||||
import org.jetbrains.kotlin.codegen.context.*;
|
import org.jetbrains.kotlin.codegen.context.*;
|
||||||
import org.jetbrains.kotlin.codegen.extensions.ExpressionCodegenExtension;
|
import org.jetbrains.kotlin.codegen.extensions.ExpressionCodegenExtension;
|
||||||
import org.jetbrains.kotlin.codegen.inline.InlineCodegenUtil;
|
|
||||||
import org.jetbrains.kotlin.codegen.signature.BothSignatureWriter;
|
import org.jetbrains.kotlin.codegen.signature.BothSignatureWriter;
|
||||||
import org.jetbrains.kotlin.codegen.signature.JvmSignatureWriter;
|
import org.jetbrains.kotlin.codegen.signature.JvmSignatureWriter;
|
||||||
import org.jetbrains.kotlin.codegen.state.GenerationState;
|
import org.jetbrains.kotlin.codegen.state.GenerationState;
|
||||||
@@ -79,6 +78,7 @@ import static org.jetbrains.kotlin.codegen.CodegenUtilKt.isGenericToArray;
|
|||||||
import static org.jetbrains.kotlin.codegen.CodegenUtilKt.isNonGenericToArray;
|
import static org.jetbrains.kotlin.codegen.CodegenUtilKt.isNonGenericToArray;
|
||||||
import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.*;
|
import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.*;
|
||||||
import static org.jetbrains.kotlin.codegen.binding.CodegenBinding.enumEntryNeedSubclass;
|
import static org.jetbrains.kotlin.codegen.binding.CodegenBinding.enumEntryNeedSubclass;
|
||||||
|
import static org.jetbrains.kotlin.codegen.inline.InlineCodegenUtilsKt.initDefaultSourceMappingIfNeeded;
|
||||||
import static org.jetbrains.kotlin.resolve.BindingContextUtils.getDelegationConstructorCall;
|
import static org.jetbrains.kotlin.resolve.BindingContextUtils.getDelegationConstructorCall;
|
||||||
import static org.jetbrains.kotlin.resolve.BindingContextUtils.getNotNull;
|
import static org.jetbrains.kotlin.resolve.BindingContextUtils.getNotNull;
|
||||||
import static org.jetbrains.kotlin.resolve.DescriptorToSourceUtils.descriptorToDeclaration;
|
import static org.jetbrains.kotlin.resolve.DescriptorToSourceUtils.descriptorToDeclaration;
|
||||||
@@ -217,7 +217,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
|||||||
|
|
||||||
v.visitSource(myClass.getContainingKtFile().getName(), null);
|
v.visitSource(myClass.getContainingKtFile().getName(), null);
|
||||||
|
|
||||||
InlineCodegenUtil.initDefaultSourceMappingIfNeeded(context, this, state);
|
initDefaultSourceMappingIfNeeded(context, this, state);
|
||||||
|
|
||||||
writeEnclosingMethod();
|
writeEnclosingMethod();
|
||||||
|
|
||||||
|
|||||||
@@ -25,7 +25,10 @@ import org.jetbrains.annotations.Nullable;
|
|||||||
import org.jetbrains.kotlin.backend.common.CodegenUtil;
|
import org.jetbrains.kotlin.backend.common.CodegenUtil;
|
||||||
import org.jetbrains.kotlin.codegen.annotation.AnnotatedSimple;
|
import org.jetbrains.kotlin.codegen.annotation.AnnotatedSimple;
|
||||||
import org.jetbrains.kotlin.codegen.context.*;
|
import org.jetbrains.kotlin.codegen.context.*;
|
||||||
import org.jetbrains.kotlin.codegen.inline.*;
|
import org.jetbrains.kotlin.codegen.inline.DefaultSourceMapper;
|
||||||
|
import org.jetbrains.kotlin.codegen.inline.NameGenerator;
|
||||||
|
import org.jetbrains.kotlin.codegen.inline.ReifiedTypeParametersUsages;
|
||||||
|
import org.jetbrains.kotlin.codegen.inline.SourceMapper;
|
||||||
import org.jetbrains.kotlin.codegen.serialization.JvmSerializerExtension;
|
import org.jetbrains.kotlin.codegen.serialization.JvmSerializerExtension;
|
||||||
import org.jetbrains.kotlin.codegen.state.GenerationState;
|
import org.jetbrains.kotlin.codegen.state.GenerationState;
|
||||||
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper;
|
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper;
|
||||||
@@ -71,6 +74,7 @@ import java.util.*;
|
|||||||
import static org.jetbrains.kotlin.codegen.AsmUtil.*;
|
import static org.jetbrains.kotlin.codegen.AsmUtil.*;
|
||||||
import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.isJvm8InterfaceWithDefaultsMember;
|
import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.isJvm8InterfaceWithDefaultsMember;
|
||||||
import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.isNonDefaultInterfaceMember;
|
import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.isNonDefaultInterfaceMember;
|
||||||
|
import static org.jetbrains.kotlin.codegen.inline.InlineCodegenUtilsKt.getInlineName;
|
||||||
import static org.jetbrains.kotlin.descriptors.CallableMemberDescriptor.Kind.SYNTHESIZED;
|
import static org.jetbrains.kotlin.descriptors.CallableMemberDescriptor.Kind.SYNTHESIZED;
|
||||||
import static org.jetbrains.kotlin.resolve.BindingContext.*;
|
import static org.jetbrains.kotlin.resolve.BindingContext.*;
|
||||||
import static org.jetbrains.kotlin.resolve.DescriptorUtils.*;
|
import static org.jetbrains.kotlin.resolve.DescriptorUtils.*;
|
||||||
@@ -437,7 +441,7 @@ public abstract class MemberCodegen<T extends KtPureElement/* TODO: & KtDeclarat
|
|||||||
@NotNull
|
@NotNull
|
||||||
public NameGenerator getInlineNameGenerator() {
|
public NameGenerator getInlineNameGenerator() {
|
||||||
if (inlineNameGenerator == null) {
|
if (inlineNameGenerator == null) {
|
||||||
String prefix = InlineCodegenUtil.getInlineName(context, typeMapper, fileClassesProvider);
|
String prefix = getInlineName(context, typeMapper, fileClassesProvider);
|
||||||
inlineNameGenerator = new NameGenerator(prefix);
|
inlineNameGenerator = new NameGenerator(prefix);
|
||||||
}
|
}
|
||||||
return inlineNameGenerator;
|
return inlineNameGenerator;
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ package org.jetbrains.kotlin.codegen;
|
|||||||
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.kotlin.codegen.inline.InlineCodegenUtil;
|
|
||||||
import org.jetbrains.org.objectweb.asm.MethodVisitor;
|
import org.jetbrains.org.objectweb.asm.MethodVisitor;
|
||||||
import org.jetbrains.org.objectweb.asm.Opcodes;
|
import org.jetbrains.org.objectweb.asm.Opcodes;
|
||||||
import org.jetbrains.org.objectweb.asm.tree.LocalVariableNode;
|
import org.jetbrains.org.objectweb.asm.tree.LocalVariableNode;
|
||||||
@@ -29,6 +28,9 @@ import org.jetbrains.org.objectweb.asm.util.TraceMethodVisitor;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.jetbrains.kotlin.codegen.inline.InlineCodegenUtilsKt.getNodeText;
|
||||||
|
import static org.jetbrains.kotlin.codegen.inline.InlineCodegenUtilsKt.wrapWithMaxLocalCalc;
|
||||||
|
|
||||||
public abstract class TransformationMethodVisitor extends MethodVisitor {
|
public abstract class TransformationMethodVisitor extends MethodVisitor {
|
||||||
|
|
||||||
private final MethodNode methodNode;
|
private final MethodNode methodNode;
|
||||||
@@ -46,7 +48,7 @@ public abstract class TransformationMethodVisitor extends MethodVisitor {
|
|||||||
this.delegate = delegate;
|
this.delegate = delegate;
|
||||||
this.methodNode = new MethodNode(access, name, desc, signature, exceptions);
|
this.methodNode = new MethodNode(access, name, desc, signature, exceptions);
|
||||||
this.methodNode.localVariables = new ArrayList<>(5);
|
this.methodNode.localVariables = new ArrayList<>(5);
|
||||||
this.mv = InlineCodegenUtil.wrapWithMaxLocalCalc(methodNode);
|
this.mv = wrapWithMaxLocalCalc(methodNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -83,7 +85,7 @@ public abstract class TransformationMethodVisitor extends MethodVisitor {
|
|||||||
delegate.visitEnd();
|
delegate.visitEnd();
|
||||||
}
|
}
|
||||||
catch (Throwable t) {
|
catch (Throwable t) {
|
||||||
throw new CompilationException("Couldn't transform method node: " + InlineCodegenUtil.getNodeText(methodNode), t, null);
|
throw new CompilationException("Couldn't transform method node: " + getNodeText(methodNode), t, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -21,8 +21,8 @@ import org.jetbrains.kotlin.codegen.AsmUtil
|
|||||||
import org.jetbrains.kotlin.codegen.ClassBuilder
|
import org.jetbrains.kotlin.codegen.ClassBuilder
|
||||||
import org.jetbrains.kotlin.codegen.StackValue
|
import org.jetbrains.kotlin.codegen.StackValue
|
||||||
import org.jetbrains.kotlin.codegen.TransformationMethodVisitor
|
import org.jetbrains.kotlin.codegen.TransformationMethodVisitor
|
||||||
import org.jetbrains.kotlin.codegen.inline.InlineCodegenUtil
|
|
||||||
import org.jetbrains.kotlin.codegen.inline.MaxStackFrameSizeAndLocalsCalculator
|
import org.jetbrains.kotlin.codegen.inline.MaxStackFrameSizeAndLocalsCalculator
|
||||||
|
import org.jetbrains.kotlin.codegen.inline.isInlineMarker
|
||||||
import org.jetbrains.kotlin.codegen.optimization.DeadCodeEliminationMethodTransformer
|
import org.jetbrains.kotlin.codegen.optimization.DeadCodeEliminationMethodTransformer
|
||||||
import org.jetbrains.kotlin.codegen.optimization.common.*
|
import org.jetbrains.kotlin.codegen.optimization.common.*
|
||||||
import org.jetbrains.kotlin.codegen.optimization.fixStack.FixStackMethodTransformer
|
import org.jetbrains.kotlin.codegen.optimization.fixStack.FixStackMethodTransformer
|
||||||
@@ -681,7 +681,7 @@ private fun findSafelyReachableReturns(methodNode: MethodNode): Array<Set<Int>?>
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!insn.isMeaningful || insn.opcode in SAFE_OPCODES || insn.isInvisibleInDebugVarInsn(methodNode) ||
|
if (!insn.isMeaningful || insn.opcode in SAFE_OPCODES || insn.isInvisibleInDebugVarInsn(methodNode) ||
|
||||||
InlineCodegenUtil.isInlineMarker(insn)) {
|
isInlineMarker(insn)) {
|
||||||
setOf()
|
setOf()
|
||||||
}
|
}
|
||||||
else null
|
else null
|
||||||
|
|||||||
+10
-11
@@ -21,7 +21,6 @@ import org.jetbrains.kotlin.codegen.AsmUtil
|
|||||||
import org.jetbrains.kotlin.codegen.ClassBuilder
|
import org.jetbrains.kotlin.codegen.ClassBuilder
|
||||||
import org.jetbrains.kotlin.codegen.StackValue
|
import org.jetbrains.kotlin.codegen.StackValue
|
||||||
import org.jetbrains.kotlin.codegen.coroutines.COROUTINE_IMPL_ASM_TYPE
|
import org.jetbrains.kotlin.codegen.coroutines.COROUTINE_IMPL_ASM_TYPE
|
||||||
import org.jetbrains.kotlin.codegen.inline.InlineCodegenUtil.isThis0
|
|
||||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
|
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
|
||||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin.Companion.NO_ORIGIN
|
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin.Companion.NO_ORIGIN
|
||||||
import org.jetbrains.org.objectweb.asm.*
|
import org.jetbrains.org.objectweb.asm.*
|
||||||
@@ -49,7 +48,7 @@ class AnonymousObjectTransformer(
|
|||||||
val classBuilder = createRemappingClassBuilderViaFactory(inliningContext)
|
val classBuilder = createRemappingClassBuilderViaFactory(inliningContext)
|
||||||
val methodsToTransform = ArrayList<MethodNode>()
|
val methodsToTransform = ArrayList<MethodNode>()
|
||||||
|
|
||||||
createClassReader().accept(object : ClassVisitor(InlineCodegenUtil.API, classBuilder.visitor) {
|
createClassReader().accept(object : ClassVisitor(API, classBuilder.visitor) {
|
||||||
override fun visit(version: Int, access: Int, name: String, signature: String?, superName: String, interfaces: Array<String>) {
|
override fun visit(version: Int, access: Int, name: String, signature: String?, superName: String, interfaces: Array<String>) {
|
||||||
classBuilder.defineClass(null, version, access, name, signature, superName, interfaces)
|
classBuilder.defineClass(null, version, access, name, signature, superName, interfaces)
|
||||||
if (COROUTINE_IMPL_ASM_TYPE.internalName == superName) {
|
if (COROUTINE_IMPL_ASM_TYPE.internalName == superName) {
|
||||||
@@ -79,7 +78,7 @@ class AnonymousObjectTransformer(
|
|||||||
|
|
||||||
override fun visitField(access: Int, name: String, desc: String, signature: String?, value: Any?): FieldVisitor? {
|
override fun visitField(access: Int, name: String, desc: String, signature: String?, value: Any?): FieldVisitor? {
|
||||||
addUniqueField(name)
|
addUniqueField(name)
|
||||||
if (InlineCodegenUtil.isCapturedFieldName(name)) {
|
if (isCapturedFieldName(name)) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -103,7 +102,7 @@ class AnonymousObjectTransformer(
|
|||||||
//seems we can't do any clever mapping cause we don't know any about original class name
|
//seems we can't do any clever mapping cause we don't know any about original class name
|
||||||
sourceMapper = IdenticalSourceMapper
|
sourceMapper = IdenticalSourceMapper
|
||||||
}
|
}
|
||||||
if (sourceInfo != null && !InlineCodegenUtil.GENERATE_SMAP) {
|
if (sourceInfo != null && !GENERATE_SMAP) {
|
||||||
classBuilder.visitSource(sourceInfo!!, debugInfo)
|
classBuilder.visitSource(sourceInfo!!, debugInfo)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -139,7 +138,7 @@ class AnonymousObjectTransformer(
|
|||||||
}
|
}
|
||||||
|
|
||||||
deferringMethods.forEach { method ->
|
deferringMethods.forEach { method ->
|
||||||
InlineCodegenUtil.removeFinallyMarkers(method.intermediate)
|
removeFinallyMarkers(method.intermediate)
|
||||||
method.visitEnd()
|
method.visitEnd()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -286,7 +285,7 @@ class AnonymousObjectTransformer(
|
|||||||
|
|
||||||
val intermediateMethodNode = MethodNode(constructor!!.access, "<init>", constructorDescriptor, null, ArrayUtil.EMPTY_STRING_ARRAY)
|
val intermediateMethodNode = MethodNode(constructor!!.access, "<init>", constructorDescriptor, null, ArrayUtil.EMPTY_STRING_ARRAY)
|
||||||
inlineMethodAndUpdateGlobalResult(parentRemapper, intermediateMethodNode, constructor!!, constructorInlineBuilder, true)
|
inlineMethodAndUpdateGlobalResult(parentRemapper, intermediateMethodNode, constructor!!, constructorInlineBuilder, true)
|
||||||
InlineCodegenUtil.removeFinallyMarkers(intermediateMethodNode)
|
removeFinallyMarkers(intermediateMethodNode)
|
||||||
|
|
||||||
val first = intermediateMethodNode.instructions.first
|
val first = intermediateMethodNode.instructions.first
|
||||||
val oldStartLabel = if (first is LabelNode) first.label else null
|
val oldStartLabel = if (first is LabelNode) first.label else null
|
||||||
@@ -429,8 +428,8 @@ class AnonymousObjectTransformer(
|
|||||||
val parent = parentFieldRemapper.parent as? RegeneratedLambdaFieldRemapper ?:
|
val parent = parentFieldRemapper.parent as? RegeneratedLambdaFieldRemapper ?:
|
||||||
throw AssertionError("Expecting RegeneratedLambdaFieldRemapper, but ${parentFieldRemapper.parent}")
|
throw AssertionError("Expecting RegeneratedLambdaFieldRemapper, but ${parentFieldRemapper.parent}")
|
||||||
val ownerType = Type.getObjectType(parent.originalLambdaInternalName)
|
val ownerType = Type.getObjectType(parent.originalLambdaInternalName)
|
||||||
val desc = CapturedParamDesc(ownerType, InlineCodegenUtil.THIS, ownerType)
|
val desc = CapturedParamDesc(ownerType, THIS, ownerType)
|
||||||
val recapturedParamInfo = capturedParamBuilder.addCapturedParam(desc, InlineCodegenUtil.`THIS$0`/*outer lambda/object*/, false)
|
val recapturedParamInfo = capturedParamBuilder.addCapturedParam(desc, THIS_0/*outer lambda/object*/, false)
|
||||||
val composed = StackValue.LOCAL_0
|
val composed = StackValue.LOCAL_0
|
||||||
recapturedParamInfo.remapValue = composed
|
recapturedParamInfo.remapValue = composed
|
||||||
allRecapturedParameters.add(desc)
|
allRecapturedParameters.add(desc)
|
||||||
@@ -458,16 +457,16 @@ class AnonymousObjectTransformer(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun getNewFieldName(oldName: String, originalField: Boolean): String {
|
private fun getNewFieldName(oldName: String, originalField: Boolean): String {
|
||||||
if (InlineCodegenUtil.`THIS$0` == oldName) {
|
if (THIS_0 == oldName) {
|
||||||
if (!originalField) {
|
if (!originalField) {
|
||||||
return oldName
|
return oldName
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
//rename original 'this$0' in declaration site lambda (inside inline function) to use this$0 only for outer lambda/object access on call site
|
//rename original 'this$0' in declaration site lambda (inside inline function) to use this$0 only for outer lambda/object access on call site
|
||||||
return addUniqueField(oldName + InlineCodegenUtil.INLINE_FUN_THIS_0_SUFFIX)
|
return addUniqueField(oldName + INLINE_FUN_THIS_0_SUFFIX)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return addUniqueField(oldName + InlineCodegenUtil.INLINE_TRANSFORMATION_SUFFIX)
|
return addUniqueField(oldName + INLINE_TRANSFORMATION_SUFFIX)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun addUniqueField(name: String): String {
|
private fun addUniqueField(name: String): String {
|
||||||
|
|||||||
+1
-1
@@ -38,7 +38,7 @@ abstract class CoveringTryCatchNodeProcessor(parameterSize: Int) {
|
|||||||
|
|
||||||
open fun processInstruction(curInstr: AbstractInsnNode, directOrder: Boolean) {
|
open fun processInstruction(curInstr: AbstractInsnNode, directOrder: Boolean) {
|
||||||
if (curInstr is VarInsnNode || curInstr is IincInsnNode) {
|
if (curInstr is VarInsnNode || curInstr is IincInsnNode) {
|
||||||
val argSize = InlineCodegenUtil.getLoadStoreArgSize(curInstr.opcode)
|
val argSize = getLoadStoreArgSize(curInstr.opcode)
|
||||||
val varIndex = if (curInstr is VarInsnNode) curInstr.`var` else (curInstr as IincInsnNode).`var`
|
val varIndex = if (curInstr is VarInsnNode) curInstr.`var` else (curInstr as IincInsnNode).`var`
|
||||||
nextFreeLocalIndex = Math.max(nextFreeLocalIndex, varIndex + argSize)
|
nextFreeLocalIndex = Math.max(nextFreeLocalIndex, varIndex + argSize)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ import org.jetbrains.org.objectweb.asm.tree.MethodNode
|
|||||||
class DeferredMethodVisitor(
|
class DeferredMethodVisitor(
|
||||||
val intermediate: MethodNode,
|
val intermediate: MethodNode,
|
||||||
val resultNode: () -> MethodVisitor
|
val resultNode: () -> MethodVisitor
|
||||||
) : MethodVisitor(InlineCodegenUtil.API, intermediate) {
|
) : MethodVisitor(API, intermediate) {
|
||||||
|
|
||||||
override fun visitEnd() {
|
override fun visitEnd() {
|
||||||
super.visitEnd()
|
super.visitEnd()
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ open class FieldRemapper(
|
|||||||
protected open fun canProcess(fieldOwner: String, fieldName: String, isFolding: Boolean): Boolean {
|
protected open fun canProcess(fieldOwner: String, fieldName: String, isFolding: Boolean): Boolean {
|
||||||
return fieldOwner == originalLambdaInternalName &&
|
return fieldOwner == originalLambdaInternalName &&
|
||||||
//don't process general field of anonymous objects
|
//don't process general field of anonymous objects
|
||||||
InlineCodegenUtil.isCapturedFieldName(fieldName)
|
isCapturedFieldName(fieldName)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun foldFieldAccessChainIfNeeded(capturedFieldAccess: List<AbstractInsnNode>, node: MethodNode): AbstractInsnNode? =
|
fun foldFieldAccessChainIfNeeded(capturedFieldAccess: List<AbstractInsnNode>, node: MethodNode): AbstractInsnNode? =
|
||||||
@@ -68,7 +68,7 @@ open class FieldRemapper(
|
|||||||
|
|
||||||
val insnNode = capturedFieldAccess[currentInstruction] as FieldInsnNode
|
val insnNode = capturedFieldAccess[currentInstruction] as FieldInsnNode
|
||||||
if (canProcess(insnNode.owner, insnNode.name, true)) {
|
if (canProcess(insnNode.owner, insnNode.name, true)) {
|
||||||
insnNode.name = InlineCodegenUtil.CAPTURED_FIELD_FOLD_PREFIX + getFieldNameForFolding(insnNode)
|
insnNode.name = CAPTURED_FIELD_FOLD_PREFIX + getFieldNameForFolding(insnNode)
|
||||||
insnNode.opcode = Opcodes.GETSTATIC
|
insnNode.opcode = Opcodes.GETSTATIC
|
||||||
|
|
||||||
node.remove(InsnSequence(capturedFieldAccess[0], insnNode))
|
node.remove(InsnSequence(capturedFieldAccess[0], insnNode))
|
||||||
|
|||||||
@@ -25,7 +25,9 @@ import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static org.jetbrains.kotlin.codegen.inline.InlineCodegenUtil.getLoadStoreArgSize;
|
import static org.jetbrains.kotlin.codegen.inline.InlineCodegenUtilsKt.API;
|
||||||
|
import static org.jetbrains.kotlin.codegen.inline.InlineCodegenUtilsKt.GENERATE_SMAP;
|
||||||
|
import static org.jetbrains.kotlin.codegen.inline.InlineCodegenUtilsKt.getLoadStoreArgSize;
|
||||||
|
|
||||||
public class InlineAdapter extends InstructionAdapter {
|
public class InlineAdapter extends InstructionAdapter {
|
||||||
private final SourceMapper sourceMapper;
|
private final SourceMapper sourceMapper;
|
||||||
@@ -36,7 +38,7 @@ public class InlineAdapter extends InstructionAdapter {
|
|||||||
private int nextLocalIndexBeforeInline = -1;
|
private int nextLocalIndexBeforeInline = -1;
|
||||||
|
|
||||||
public InlineAdapter(@NotNull MethodVisitor mv, int localsSize, @NotNull SourceMapper sourceMapper) {
|
public InlineAdapter(@NotNull MethodVisitor mv, int localsSize, @NotNull SourceMapper sourceMapper) {
|
||||||
super(InlineCodegenUtil.API, mv);
|
super(API, mv);
|
||||||
this.nextLocalIndex = localsSize;
|
this.nextLocalIndex = localsSize;
|
||||||
this.sourceMapper = sourceMapper;
|
this.sourceMapper = sourceMapper;
|
||||||
}
|
}
|
||||||
@@ -86,7 +88,7 @@ public class InlineAdapter extends InstructionAdapter {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitLineNumber(int line, @NotNull Label start) {
|
public void visitLineNumber(int line, @NotNull Label start) {
|
||||||
if (InlineCodegenUtil.GENERATE_SMAP) {
|
if (GENERATE_SMAP) {
|
||||||
line = sourceMapper.mapLineNumber(line);
|
line = sourceMapper.mapLineNumber(line);
|
||||||
}
|
}
|
||||||
//skip not mapped lines
|
//skip not mapped lines
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ import org.jetbrains.kotlin.codegen.AsmUtil.isPrimitive
|
|||||||
import org.jetbrains.kotlin.codegen.context.*
|
import org.jetbrains.kotlin.codegen.context.*
|
||||||
import org.jetbrains.kotlin.codegen.coroutines.createMethodNodeForSuspendCoroutineOrReturn
|
import org.jetbrains.kotlin.codegen.coroutines.createMethodNodeForSuspendCoroutineOrReturn
|
||||||
import org.jetbrains.kotlin.codegen.coroutines.isBuiltInSuspendCoroutineOrReturnInJvm
|
import org.jetbrains.kotlin.codegen.coroutines.isBuiltInSuspendCoroutineOrReturnInJvm
|
||||||
import org.jetbrains.kotlin.codegen.inline.InlineCodegenUtil.*
|
|
||||||
import org.jetbrains.kotlin.codegen.intrinsics.bytecode
|
import org.jetbrains.kotlin.codegen.intrinsics.bytecode
|
||||||
import org.jetbrains.kotlin.codegen.intrinsics.classId
|
import org.jetbrains.kotlin.codegen.intrinsics.classId
|
||||||
import org.jetbrains.kotlin.codegen.state.GenerationState
|
import org.jetbrains.kotlin.codegen.state.GenerationState
|
||||||
@@ -168,7 +167,7 @@ class InlineCodegen(
|
|||||||
"Couldn't inline method call '" + functionDescriptor.name + "' into\n" +
|
"Couldn't inline method call '" + functionDescriptor.name + "' into\n" +
|
||||||
DescriptorRenderer.DEBUG_TEXT.render(contextDescriptor) + "\n" +
|
DescriptorRenderer.DEBUG_TEXT.render(contextDescriptor) + "\n" +
|
||||||
(element?.text ?: "<no source>") +
|
(element?.text ?: "<no source>") +
|
||||||
if (generateNodeText) "\nCause: " + InlineCodegenUtil.getNodeText(node) else "",
|
if (generateNodeText) "\nCause: " + getNodeText(node) else "",
|
||||||
e, callElement
|
e, callElement
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -230,7 +229,7 @@ class InlineCodegen(
|
|||||||
|
|
||||||
val remapper = LocalVarRemapper(parameters, initialFrameSize)
|
val remapper = LocalVarRemapper(parameters, initialFrameSize)
|
||||||
|
|
||||||
val adapter = InlineCodegenUtil.createEmptyMethodNode()
|
val adapter = createEmptyMethodNode()
|
||||||
//hack to keep linenumber info, otherwise jdi will skip begin of linenumber chain
|
//hack to keep linenumber info, otherwise jdi will skip begin of linenumber chain
|
||||||
adapter.visitInsn(Opcodes.NOP)
|
adapter.visitInsn(Opcodes.NOP)
|
||||||
|
|
||||||
@@ -245,8 +244,8 @@ class InlineCodegen(
|
|||||||
adapter, infos, (remapper.remap(parameters.argsSizeOnStack + 1).value as StackValue.Local).index
|
adapter, infos, (remapper.remap(parameters.argsSizeOnStack + 1).value as StackValue.Local).index
|
||||||
)
|
)
|
||||||
removeStaticInitializationTrigger(adapter)
|
removeStaticInitializationTrigger(adapter)
|
||||||
if (!InlineCodegenUtil.isFinallyMarkerRequired(codegen.getContext())) {
|
if (!isFinallyMarkerRequired(codegen.getContext())) {
|
||||||
InlineCodegenUtil.removeFinallyMarkers(adapter)
|
removeFinallyMarkers(adapter)
|
||||||
}
|
}
|
||||||
|
|
||||||
adapter.accept(MethodBodyVisitor(codegen.v))
|
adapter.accept(MethodBodyVisitor(codegen.v))
|
||||||
@@ -539,7 +538,7 @@ class InlineCodegen(
|
|||||||
var curInstr: AbstractInsnNode? = intoNode.instructions.first
|
var curInstr: AbstractInsnNode? = intoNode.instructions.first
|
||||||
while (curInstr != null) {
|
while (curInstr != null) {
|
||||||
processor.processInstruction(curInstr, true)
|
processor.processInstruction(curInstr, true)
|
||||||
if (InlineCodegenUtil.isFinallyStart(curInstr)) {
|
if (isFinallyStart(curInstr)) {
|
||||||
//TODO depth index calc could be more precise
|
//TODO depth index calc could be more precise
|
||||||
curFinallyDepth = getConstant(curInstr.previous)
|
curFinallyDepth = getConstant(curInstr.previous)
|
||||||
}
|
}
|
||||||
@@ -548,7 +547,7 @@ class InlineCodegen(
|
|||||||
if (extension != null) {
|
if (extension != null) {
|
||||||
val start = Label()
|
val start = Label()
|
||||||
|
|
||||||
val finallyNode = InlineCodegenUtil.createEmptyMethodNode()
|
val finallyNode = createEmptyMethodNode()
|
||||||
finallyNode.visitLabel(start)
|
finallyNode.visitLabel(start)
|
||||||
|
|
||||||
val finallyCodegen = ExpressionCodegen(finallyNode, codegen.frameMap, codegen.returnType,
|
val finallyCodegen = ExpressionCodegen(finallyNode, codegen.frameMap, codegen.returnType,
|
||||||
@@ -569,7 +568,7 @@ class InlineCodegen(
|
|||||||
finallyCodegen.generateFinallyBlocksIfNeeded(extension.returnType, extension.finallyIntervalEnd.label)
|
finallyCodegen.generateFinallyBlocksIfNeeded(extension.returnType, extension.finallyIntervalEnd.label)
|
||||||
|
|
||||||
//Exception table for external try/catch/finally blocks will be generated in original codegen after exiting this method
|
//Exception table for external try/catch/finally blocks will be generated in original codegen after exiting this method
|
||||||
InlineCodegenUtil.insertNodeBefore(finallyNode, intoNode, curInstr)
|
insertNodeBefore(finallyNode, intoNode, curInstr)
|
||||||
|
|
||||||
val splitBy = SimpleInterval(start.info as LabelNode, extension.finallyIntervalEnd)
|
val splitBy = SimpleInterval(start.info as LabelNode, extension.finallyIntervalEnd)
|
||||||
processor.tryBlocksMetaInfo.splitCurrentIntervals(splitBy, true)
|
processor.tryBlocksMetaInfo.splitCurrentIntervals(splitBy, true)
|
||||||
@@ -620,12 +619,12 @@ class InlineCodegen(
|
|||||||
callDefault: Boolean,
|
callDefault: Boolean,
|
||||||
resolvedCall: ResolvedCall<*>?
|
resolvedCall: ResolvedCall<*>?
|
||||||
): SMAPAndMethodNode {
|
): SMAPAndMethodNode {
|
||||||
if (InlineCodegenUtil.isSpecialEnumMethod(functionDescriptor)) {
|
if (isSpecialEnumMethod(functionDescriptor)) {
|
||||||
assert(resolvedCall != null) { "Resolved call for $functionDescriptor should be not null" }
|
assert(resolvedCall != null) { "Resolved call for $functionDescriptor should be not null" }
|
||||||
val arguments = resolvedCall!!.typeArguments
|
val arguments = resolvedCall!!.typeArguments
|
||||||
assert(arguments.size == 1) { "Resolved call for $functionDescriptor should have 1 type argument" }
|
assert(arguments.size == 1) { "Resolved call for $functionDescriptor should have 1 type argument" }
|
||||||
|
|
||||||
val node = InlineCodegenUtil.createSpecialEnumMethodBody(
|
val node = createSpecialEnumMethodBody(
|
||||||
codegen,
|
codegen,
|
||||||
functionDescriptor.name.asString(),
|
functionDescriptor.name.asString(),
|
||||||
arguments.keys.iterator().next().defaultType,
|
arguments.keys.iterator().next().defaultType,
|
||||||
@@ -689,7 +688,7 @@ class InlineCodegen(
|
|||||||
if (isBuiltInArrayIntrinsic(callableDescriptor)) {
|
if (isBuiltInArrayIntrinsic(callableDescriptor)) {
|
||||||
val classId = classId
|
val classId = classId
|
||||||
val bytes = state.inlineCache.classBytes.getOrPut(classId) { bytecode }
|
val bytes = state.inlineCache.classBytes.getOrPut(classId) { bytecode }
|
||||||
return InlineCodegenUtil.getMethodNode(bytes, asmMethod.name, asmMethod.descriptor, classId.asString())
|
return getMethodNode(bytes, asmMethod.name, asmMethod.descriptor, classId.asString())
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(callableDescriptor is DeserializedCallableMemberDescriptor) { "Not a deserialized function or proper: " + callableDescriptor }
|
assert(callableDescriptor is DeserializedCallableMemberDescriptor) { "Not a deserialized function or proper: " + callableDescriptor }
|
||||||
@@ -699,7 +698,7 @@ class InlineCodegen(
|
|||||||
val containerId = containingClasses.implClassId
|
val containerId = containingClasses.implClassId
|
||||||
|
|
||||||
val bytes = state.inlineCache.classBytes.getOrPut(containerId) {
|
val bytes = state.inlineCache.classBytes.getOrPut(containerId) {
|
||||||
val file = InlineCodegenUtil.findVirtualFile(state, containerId) ?: throw IllegalStateException("Couldn't find declaration file for " + containerId)
|
val file = findVirtualFile(state, containerId) ?: throw IllegalStateException("Couldn't find declaration file for " + containerId)
|
||||||
try {
|
try {
|
||||||
file.contentsToByteArray()
|
file.contentsToByteArray()
|
||||||
}
|
}
|
||||||
@@ -708,7 +707,7 @@ class InlineCodegen(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return InlineCodegenUtil.getMethodNode(bytes, asmMethod.name, asmMethod.descriptor, containerId.asString())
|
return getMethodNode(bytes, asmMethod.name, asmMethod.descriptor, containerId.asString())
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun doCreateMethodNodeFromSource(
|
private fun doCreateMethodNodeFromSource(
|
||||||
@@ -728,14 +727,14 @@ class InlineCodegen(
|
|||||||
val inliningFunction = element as KtDeclarationWithBody?
|
val inliningFunction = element as KtDeclarationWithBody?
|
||||||
|
|
||||||
val node = MethodNode(
|
val node = MethodNode(
|
||||||
InlineCodegenUtil.API,
|
API,
|
||||||
getMethodAsmFlags(callableDescriptor, context.contextKind, state) or if (callDefault) Opcodes.ACC_STATIC else 0,
|
getMethodAsmFlags(callableDescriptor, context.contextKind, state) or if (callDefault) Opcodes.ACC_STATIC else 0,
|
||||||
asmMethod.name,
|
asmMethod.name,
|
||||||
asmMethod.descriptor, null, null
|
asmMethod.descriptor, null, null
|
||||||
)
|
)
|
||||||
|
|
||||||
//for maxLocals calculation
|
//for maxLocals calculation
|
||||||
val maxCalcAdapter = InlineCodegenUtil.wrapWithMaxLocalCalc(node)
|
val maxCalcAdapter = wrapWithMaxLocalCalc(node)
|
||||||
val parentContext = context.parentContext ?: error("Context has no parent: " + context)
|
val parentContext = context.parentContext ?: error("Context has no parent: " + context)
|
||||||
val methodContext = parentContext.intoFunction(callableDescriptor)
|
val methodContext = parentContext.intoFunction(callableDescriptor)
|
||||||
|
|
||||||
@@ -919,7 +918,7 @@ class InlineCodegen(
|
|||||||
if (!descriptor.name.isSpecial) {
|
if (!descriptor.name.isSpecial) {
|
||||||
result.add(descriptor.name.asString())
|
result.add(descriptor.name.asString())
|
||||||
}
|
}
|
||||||
result.add(InlineCodegenUtil.FIRST_FUN_LABEL)
|
result.add(FIRST_FUN_LABEL)
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,580 +14,534 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.jetbrains.kotlin.codegen.inline;
|
package org.jetbrains.kotlin.codegen.inline
|
||||||
|
|
||||||
import com.intellij.openapi.vfs.VirtualFile;
|
import com.intellij.openapi.vfs.VirtualFile
|
||||||
import com.intellij.psi.PsiFile;
|
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||||
import kotlin.text.StringsKt;
|
import org.jetbrains.kotlin.codegen.AsmUtil
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.kotlin.codegen.ExpressionCodegen
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.kotlin.codegen.MemberCodegen
|
||||||
import org.jetbrains.kotlin.backend.common.output.OutputFile;
|
import org.jetbrains.kotlin.codegen.binding.CodegenBinding
|
||||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
|
import org.jetbrains.kotlin.codegen.context.CodegenContext
|
||||||
import org.jetbrains.kotlin.codegen.AsmUtil;
|
import org.jetbrains.kotlin.codegen.context.CodegenContextUtil
|
||||||
import org.jetbrains.kotlin.codegen.ExpressionCodegen;
|
import org.jetbrains.kotlin.codegen.context.InlineLambdaContext
|
||||||
import org.jetbrains.kotlin.codegen.MemberCodegen;
|
import org.jetbrains.kotlin.codegen.context.MethodContext
|
||||||
import org.jetbrains.kotlin.codegen.binding.CodegenBinding;
|
import org.jetbrains.kotlin.codegen.intrinsics.*
|
||||||
import org.jetbrains.kotlin.codegen.context.CodegenContext;
|
import org.jetbrains.kotlin.codegen.state.GenerationState
|
||||||
import org.jetbrains.kotlin.codegen.context.CodegenContextUtil;
|
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
|
||||||
import org.jetbrains.kotlin.codegen.context.InlineLambdaContext;
|
import org.jetbrains.kotlin.codegen.`when`.WhenByEnumsMapping
|
||||||
import org.jetbrains.kotlin.codegen.context.MethodContext;
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicArrayConstructorsKt;
|
import org.jetbrains.kotlin.fileClasses.*
|
||||||
import org.jetbrains.kotlin.codegen.state.GenerationState;
|
import org.jetbrains.kotlin.fileClasses.JvmFileClassesProvider
|
||||||
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper;
|
import org.jetbrains.kotlin.load.java.JvmAbi
|
||||||
import org.jetbrains.kotlin.codegen.when.WhenByEnumsMapping;
|
import org.jetbrains.kotlin.load.kotlin.VirtualFileFinder
|
||||||
import org.jetbrains.kotlin.descriptors.*;
|
import org.jetbrains.kotlin.name.ClassId
|
||||||
import org.jetbrains.kotlin.fileClasses.FileClasses;
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.fileClasses.JvmFileClassesProvider;
|
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
|
||||||
import org.jetbrains.kotlin.load.java.JvmAbi;
|
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
|
||||||
import org.jetbrains.kotlin.load.kotlin.VirtualFileFinder;
|
import org.jetbrains.kotlin.resolve.jvm.JvmClassName
|
||||||
import org.jetbrains.kotlin.name.ClassId;
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
import org.jetbrains.kotlin.name.FqName;
|
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||||
import org.jetbrains.kotlin.name.Name;
|
import org.jetbrains.org.objectweb.asm.*
|
||||||
import org.jetbrains.kotlin.psi.KtFile;
|
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils;
|
import org.jetbrains.org.objectweb.asm.tree.*
|
||||||
import org.jetbrains.kotlin.resolve.jvm.AsmTypes;
|
import org.jetbrains.org.objectweb.asm.util.Printer
|
||||||
import org.jetbrains.kotlin.resolve.jvm.JvmClassName;
|
import org.jetbrains.org.objectweb.asm.util.Textifier
|
||||||
import org.jetbrains.kotlin.types.KotlinType;
|
import org.jetbrains.org.objectweb.asm.util.TraceMethodVisitor
|
||||||
import org.jetbrains.kotlin.util.OperatorNameConventions;
|
|
||||||
import org.jetbrains.org.objectweb.asm.*;
|
|
||||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter;
|
|
||||||
import org.jetbrains.org.objectweb.asm.tree.*;
|
|
||||||
import org.jetbrains.org.objectweb.asm.util.Printer;
|
|
||||||
import org.jetbrains.org.objectweb.asm.util.Textifier;
|
|
||||||
import org.jetbrains.org.objectweb.asm.util.TraceMethodVisitor;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter
|
||||||
import java.io.StringWriter;
|
import java.io.StringWriter
|
||||||
import java.util.List;
|
|
||||||
import java.util.ListIterator;
|
|
||||||
|
|
||||||
import static org.jetbrains.kotlin.resolve.jvm.AsmTypes.ENUM_TYPE;
|
import org.jetbrains.kotlin.resolve.jvm.AsmTypes.ENUM_TYPE
|
||||||
import static org.jetbrains.kotlin.resolve.jvm.AsmTypes.JAVA_CLASS_TYPE;
|
import org.jetbrains.kotlin.resolve.jvm.AsmTypes.JAVA_CLASS_TYPE
|
||||||
|
|
||||||
public class InlineCodegenUtil {
|
|
||||||
public static final boolean GENERATE_SMAP = true;
|
|
||||||
public static final int API = Opcodes.ASM5;
|
|
||||||
|
|
||||||
private static final String CAPTURED_FIELD_PREFIX = "$";
|
const val GENERATE_SMAP = true
|
||||||
private static final String NON_CAPTURED_FIELD_PREFIX = "$$";
|
const val API = Opcodes.ASM5
|
||||||
public static final String THIS$0 = "this$0";
|
const val THIS = "this"
|
||||||
public static final String THIS = "this";
|
const val THIS_0 = "this$0"
|
||||||
private static final String RECEIVER$0 = "receiver$0";
|
const val FIRST_FUN_LABEL = "$$$$\$ROOT$$$$$"
|
||||||
private static final String NON_LOCAL_RETURN = "$$$$$NON_LOCAL_RETURN$$$$$";
|
const val NUMBERED_FUNCTION_PREFIX = "kotlin/jvm/functions/Function"
|
||||||
public static final String FIRST_FUN_LABEL = "$$$$$ROOT$$$$$";
|
const val SPECIAL_TRANSFORMATION_NAME = "\$special"
|
||||||
public static final String NUMBERED_FUNCTION_PREFIX = "kotlin/jvm/functions/Function";
|
const val INLINE_TRANSFORMATION_SUFFIX = "\$inlined"
|
||||||
private static final String INLINE_MARKER_CLASS_NAME = "kotlin/jvm/internal/InlineMarker";
|
const val INLINE_CALL_TRANSFORMATION_SUFFIX = "$" + INLINE_TRANSFORMATION_SUFFIX
|
||||||
private static final String INLINE_MARKER_BEFORE_METHOD_NAME = "beforeInlineCall";
|
const val INLINE_FUN_THIS_0_SUFFIX = "\$inline_fun"
|
||||||
private static final String INLINE_MARKER_AFTER_METHOD_NAME = "afterInlineCall";
|
const val INLINE_FUN_VAR_SUFFIX = "\$iv"
|
||||||
private static final String INLINE_MARKER_FINALLY_START = "finallyStart";
|
const val DEFAULT_LAMBDA_FAKE_CALL = "$$\$DEFAULT_LAMBDA_FAKE_CALL$$$"
|
||||||
private static final String INLINE_MARKER_FINALLY_END = "finallyEnd";
|
|
||||||
public static final String SPECIAL_TRANSFORMATION_NAME = "$special";
|
|
||||||
public static final String INLINE_TRANSFORMATION_SUFFIX = "$inlined";
|
|
||||||
public static final String INLINE_CALL_TRANSFORMATION_SUFFIX = "$" + INLINE_TRANSFORMATION_SUFFIX;
|
|
||||||
public static final String INLINE_FUN_THIS_0_SUFFIX = "$inline_fun";
|
|
||||||
public static final String INLINE_FUN_VAR_SUFFIX = "$iv";
|
|
||||||
|
|
||||||
public static final String DEFAULT_LAMBDA_FAKE_CALL = "$$$DEFAULT_LAMBDA_FAKE_CALL$$$";
|
const val CAPTURED_FIELD_FOLD_PREFIX = "$$$"
|
||||||
public static final String CAPTURED_FIELD_FOLD_PREFIX = "$$$";
|
private const val `RECEIVER$0` = "receiver$0"
|
||||||
|
private const val NON_LOCAL_RETURN = "$$$$\$NON_LOCAL_RETURN$$$$$"
|
||||||
|
private const val CAPTURED_FIELD_PREFIX = "$"
|
||||||
|
private const val NON_CAPTURED_FIELD_PREFIX = "$$"
|
||||||
|
private const val INLINE_MARKER_CLASS_NAME = "kotlin/jvm/internal/InlineMarker"
|
||||||
|
private const val INLINE_MARKER_BEFORE_METHOD_NAME = "beforeInlineCall"
|
||||||
|
private const val INLINE_MARKER_AFTER_METHOD_NAME = "afterInlineCall"
|
||||||
|
private const val INLINE_MARKER_FINALLY_START = "finallyStart"
|
||||||
|
|
||||||
@Nullable
|
private const val INLINE_MARKER_FINALLY_END = "finallyEnd"
|
||||||
public static SMAPAndMethodNode getMethodNode(
|
|
||||||
byte[] classData,
|
|
||||||
@NotNull String methodName,
|
|
||||||
@NotNull String methodDescriptor,
|
|
||||||
@NotNull String classInternalName
|
|
||||||
) {
|
|
||||||
ClassReader cr = new ClassReader(classData);
|
|
||||||
MethodNode[] node = new MethodNode[1];
|
|
||||||
String[] debugInfo = new String[2];
|
|
||||||
int[] lines = new int[2];
|
|
||||||
lines[0] = Integer.MAX_VALUE;
|
|
||||||
lines[1] = Integer.MIN_VALUE;
|
|
||||||
//noinspection PointlessBitwiseExpression
|
|
||||||
cr.accept(new ClassVisitor(API) {
|
|
||||||
|
|
||||||
@Override
|
fun getMethodNode(
|
||||||
public void visitSource(String source, String debug) {
|
classData: ByteArray,
|
||||||
super.visitSource(source, debug);
|
methodName: String,
|
||||||
debugInfo[0] = source;
|
methodDescriptor: String,
|
||||||
debugInfo[1] = debug;
|
classInternalName: String
|
||||||
|
): SMAPAndMethodNode? {
|
||||||
|
val cr = ClassReader(classData)
|
||||||
|
var node: MethodNode? = null
|
||||||
|
val debugInfo = arrayOfNulls<String>(2)
|
||||||
|
val lines = IntArray(2)
|
||||||
|
lines[0] = Integer.MAX_VALUE
|
||||||
|
lines[1] = Integer.MIN_VALUE
|
||||||
|
|
||||||
|
cr.accept(object : ClassVisitor(API) {
|
||||||
|
|
||||||
|
override fun visitSource(source: String?, debug: String?) {
|
||||||
|
super.visitSource(source, debug)
|
||||||
|
debugInfo[0] = source
|
||||||
|
debugInfo[1] = debug
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
override fun visitMethod(
|
||||||
public MethodVisitor visitMethod(
|
access: Int,
|
||||||
int access,
|
name: String,
|
||||||
@NotNull String name,
|
desc: String,
|
||||||
@NotNull String desc,
|
signature: String?,
|
||||||
String signature,
|
exceptions: Array<String>?
|
||||||
String[] exceptions
|
): MethodVisitor? {
|
||||||
) {
|
if (methodName == name && methodDescriptor == desc) {
|
||||||
if (methodName.equals(name) && methodDescriptor.equals(desc)) {
|
node = object : MethodNode(API, access, name, desc, signature, exceptions) {
|
||||||
node[0] = new MethodNode(API, access, name, desc, signature, exceptions) {
|
override fun visitLineNumber(line: Int, start: Label) {
|
||||||
@Override
|
super.visitLineNumber(line, start)
|
||||||
public void visitLineNumber(int line, @NotNull Label start) {
|
lines[0] = Math.min(lines[0], line)
|
||||||
super.visitLineNumber(line, start);
|
lines[1] = Math.max(lines[1], line)
|
||||||
lines[0] = Math.min(lines[0], line);
|
|
||||||
lines[1] = Math.max(lines[1], line);
|
|
||||||
}
|
}
|
||||||
};
|
|
||||||
return node[0];
|
|
||||||
}
|
}
|
||||||
return null;
|
return node
|
||||||
}
|
}
|
||||||
}, ClassReader.SKIP_FRAMES | (GENERATE_SMAP ? 0 : ClassReader.SKIP_DEBUG));
|
return null
|
||||||
|
}
|
||||||
|
}, ClassReader.SKIP_FRAMES or if (GENERATE_SMAP) 0 else ClassReader.SKIP_DEBUG)
|
||||||
|
|
||||||
if (node[0] == null) {
|
if (node == null) {
|
||||||
return null;
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IntrinsicArrayConstructorsKt.getClassId().asString().equals(classInternalName)) {
|
if (classId.asString() == classInternalName) {
|
||||||
// Don't load source map for intrinsic array constructors
|
// Don't load source map for intrinsic array constructors
|
||||||
debugInfo[0] = null;
|
debugInfo[0] = null
|
||||||
}
|
}
|
||||||
|
|
||||||
SMAP smap = SMAPParser.parseOrCreateDefault(debugInfo[1], debugInfo[0], classInternalName, lines[0], lines[1]);
|
val smap = SMAPParser.parseOrCreateDefault(debugInfo[1], debugInfo[0], classInternalName, lines[0], lines[1])
|
||||||
return new SMAPAndMethodNode(node[0], smap);
|
return SMAPAndMethodNode(node!!, smap)
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void initDefaultSourceMappingIfNeeded(
|
fun initDefaultSourceMappingIfNeeded(
|
||||||
@NotNull CodegenContext context, @NotNull MemberCodegen codegen, @NotNull GenerationState state
|
context: CodegenContext<*>, codegen: MemberCodegen<*>, state: GenerationState
|
||||||
) {
|
) {
|
||||||
if (state.isInlineDisabled()) return;
|
if (state.isInlineDisabled) return
|
||||||
|
|
||||||
CodegenContext<?> parentContext = context.getParentContext();
|
var parentContext: CodegenContext<*>? = context.parentContext
|
||||||
while (parentContext != null) {
|
while (parentContext != null) {
|
||||||
if (parentContext.isInlineMethodContext()) {
|
if (parentContext.isInlineMethodContext) {
|
||||||
//just init default one to one mapping
|
//just init default one to one mapping
|
||||||
codegen.getOrCreateSourceMapper();
|
codegen.orCreateSourceMapper
|
||||||
break;
|
break
|
||||||
}
|
}
|
||||||
parentContext = parentContext.getParentContext();
|
parentContext = parentContext.parentContext
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
fun findVirtualFile(state: GenerationState, classId: ClassId): VirtualFile? {
|
||||||
public static VirtualFile findVirtualFile(@NotNull GenerationState state, @NotNull ClassId classId) {
|
return VirtualFileFinder.getInstance(state.project).findVirtualFileWithHeader(classId)
|
||||||
return VirtualFileFinder.SERVICE.getInstance(state.getProject()).findVirtualFileWithHeader(classId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
fun findVirtualFileImprecise(state: GenerationState, internalClassName: String): VirtualFile? {
|
||||||
public static VirtualFile findVirtualFileImprecise(@NotNull GenerationState state, @NotNull String internalClassName) {
|
val packageFqName = JvmClassName.byInternalName(internalClassName).packageFqName
|
||||||
FqName packageFqName = JvmClassName.byInternalName(internalClassName).getPackageFqName();
|
val classNameWithDollars = internalClassName.substringAfterLast("/", internalClassName)
|
||||||
String classNameWithDollars = StringsKt.substringAfterLast(internalClassName, "/", internalClassName);
|
|
||||||
//TODO: we cannot construct proper classId at this point, we need to read InnerClasses info from class file
|
//TODO: we cannot construct proper classId at this point, we need to read InnerClasses info from class file
|
||||||
// we construct valid.package.name/RelativeClassNameAsSingleName that should work in compiler, but fails for inner classes in IDE
|
// we construct valid.package.name/RelativeClassNameAsSingleName that should work in compiler, but fails for inner classes in IDE
|
||||||
return findVirtualFile(state, new ClassId(packageFqName, Name.identifier(classNameWithDollars)));
|
return findVirtualFile(state, ClassId(packageFqName, Name.identifier(classNameWithDollars)))
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
fun getInlineName(
|
||||||
public static String getInlineName(
|
codegenContext: CodegenContext<*>,
|
||||||
@NotNull CodegenContext codegenContext,
|
typeMapper: KotlinTypeMapper,
|
||||||
@NotNull KotlinTypeMapper typeMapper,
|
fileClassesManager: JvmFileClassesProvider
|
||||||
@NotNull JvmFileClassesProvider fileClassesManager
|
): String {
|
||||||
) {
|
return getInlineName(codegenContext, codegenContext.contextDescriptor, typeMapper, fileClassesManager)
|
||||||
return getInlineName(codegenContext, codegenContext.getContextDescriptor(), typeMapper, fileClassesManager);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
private fun getInlineName(
|
||||||
private static String getInlineName(
|
codegenContext: CodegenContext<*>,
|
||||||
@NotNull CodegenContext codegenContext,
|
currentDescriptor: DeclarationDescriptor,
|
||||||
@NotNull DeclarationDescriptor currentDescriptor,
|
typeMapper: KotlinTypeMapper,
|
||||||
@NotNull KotlinTypeMapper typeMapper,
|
fileClassesProvider: JvmFileClassesProvider
|
||||||
@NotNull JvmFileClassesProvider fileClassesProvider
|
): String {
|
||||||
) {
|
if (currentDescriptor is PackageFragmentDescriptor) {
|
||||||
if (currentDescriptor instanceof PackageFragmentDescriptor) {
|
val file = DescriptorToSourceUtils.getContainingFile(codegenContext.contextDescriptor)
|
||||||
PsiFile file = DescriptorToSourceUtils.getContainingFile(codegenContext.getContextDescriptor());
|
|
||||||
|
|
||||||
Type implementationOwnerType;
|
val implementationOwnerType: Type? =
|
||||||
if (file == null) {
|
if (file == null) {
|
||||||
implementationOwnerType = CodegenContextUtil.getImplementationOwnerClassType(codegenContext);
|
CodegenContextUtil.getImplementationOwnerClassType(codegenContext)
|
||||||
}
|
|
||||||
else {
|
|
||||||
implementationOwnerType = FileClasses.getFileClassType(fileClassesProvider, (KtFile) file);
|
|
||||||
}
|
}
|
||||||
|
else fileClassesProvider.getFileClassType(file)
|
||||||
|
|
||||||
if (implementationOwnerType == null) {
|
if (implementationOwnerType == null) {
|
||||||
DeclarationDescriptor contextDescriptor = codegenContext.getContextDescriptor();
|
val contextDescriptor = codegenContext.contextDescriptor
|
||||||
//noinspection ConstantConditions
|
throw RuntimeException(
|
||||||
throw new RuntimeException(
|
|
||||||
"Couldn't find declaration for " +
|
"Couldn't find declaration for " +
|
||||||
contextDescriptor.getContainingDeclaration().getName() + "." + contextDescriptor.getName() +
|
contextDescriptor.containingDeclaration!!.name + "." + contextDescriptor.name +
|
||||||
"; context: " + codegenContext
|
"; context: " + codegenContext
|
||||||
);
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return implementationOwnerType.getInternalName();
|
return implementationOwnerType.internalName
|
||||||
}
|
}
|
||||||
else if (currentDescriptor instanceof ClassifierDescriptor) {
|
else if (currentDescriptor is ClassifierDescriptor) {
|
||||||
Type type = typeMapper.mapType((ClassifierDescriptor) currentDescriptor);
|
return typeMapper.mapType(currentDescriptor).internalName
|
||||||
return type.getInternalName();
|
|
||||||
}
|
}
|
||||||
else if (currentDescriptor instanceof FunctionDescriptor) {
|
else if (currentDescriptor is FunctionDescriptor) {
|
||||||
ClassDescriptor descriptor =
|
val descriptor = typeMapper.bindingContext.get(CodegenBinding.CLASS_FOR_CALLABLE, currentDescriptor)
|
||||||
typeMapper.getBindingContext().get(CodegenBinding.CLASS_FOR_CALLABLE, (FunctionDescriptor) currentDescriptor);
|
|
||||||
if (descriptor != null) {
|
if (descriptor != null) {
|
||||||
return typeMapper.mapType(descriptor).getInternalName();
|
return typeMapper.mapType(descriptor).internalName
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: add suffix for special case
|
//TODO: add suffix for special case
|
||||||
String suffix = currentDescriptor.getName().isSpecial() ? "" : currentDescriptor.getName().asString();
|
val suffix = if (currentDescriptor.name.isSpecial) "" else currentDescriptor.name.asString()
|
||||||
|
|
||||||
//noinspection ConstantConditions
|
|
||||||
return getInlineName(codegenContext, currentDescriptor.getContainingDeclaration(), typeMapper, fileClassesProvider) + "$" + suffix;
|
return getInlineName(codegenContext, currentDescriptor.containingDeclaration!!, typeMapper, fileClassesProvider) + "$" + suffix
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isInvokeOnLambda(@NotNull String owner, @NotNull String name) {
|
fun isInvokeOnLambda(owner: String, name: String): Boolean {
|
||||||
return OperatorNameConventions.INVOKE.asString().equals(name) &&
|
return OperatorNameConventions.INVOKE.asString() == name &&
|
||||||
owner.startsWith(NUMBERED_FUNCTION_PREFIX) &&
|
owner.startsWith(NUMBERED_FUNCTION_PREFIX) &&
|
||||||
isInteger(owner.substring(NUMBERED_FUNCTION_PREFIX.length()));
|
isInteger(owner.substring(NUMBERED_FUNCTION_PREFIX.length))
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isAnonymousConstructorCall(@NotNull String internalName, @NotNull String methodName) {
|
fun isAnonymousConstructorCall(internalName: String, methodName: String): Boolean {
|
||||||
return "<init>".equals(methodName) && isAnonymousClass(internalName);
|
return "<init>" == methodName && isAnonymousClass(internalName)
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isWhenMappingAccess(@NotNull String internalName, @NotNull String fieldName) {
|
fun isWhenMappingAccess(internalName: String, fieldName: String): Boolean {
|
||||||
return fieldName.startsWith(WhenByEnumsMapping.MAPPING_ARRAY_FIELD_PREFIX) &&
|
return fieldName.startsWith(WhenByEnumsMapping.MAPPING_ARRAY_FIELD_PREFIX) && internalName.endsWith(WhenByEnumsMapping.MAPPINGS_CLASS_NAME_POSTFIX)
|
||||||
internalName.endsWith(WhenByEnumsMapping.MAPPINGS_CLASS_NAME_POSTFIX);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isAnonymousSingletonLoad(@NotNull String internalName, @NotNull String fieldName) {
|
fun isAnonymousSingletonLoad(internalName: String, fieldName: String): Boolean {
|
||||||
return JvmAbi.INSTANCE_FIELD.equals(fieldName) && isAnonymousClass(internalName);
|
return JvmAbi.INSTANCE_FIELD == fieldName && isAnonymousClass(internalName)
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isAnonymousClass(@NotNull String internalName) {
|
fun isAnonymousClass(internalName: String): Boolean {
|
||||||
String shortName = getLastNamePart(internalName);
|
val shortName = getLastNamePart(internalName)
|
||||||
int index = shortName.lastIndexOf("$");
|
val index = shortName.lastIndexOf("$")
|
||||||
|
|
||||||
if (index < 0) {
|
if (index < 0) {
|
||||||
return false;
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
String suffix = shortName.substring(index + 1);
|
val suffix = shortName.substring(index + 1)
|
||||||
return isInteger(suffix);
|
return isInteger(suffix)
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
private fun getLastNamePart(internalName: String): String {
|
||||||
private static String getLastNamePart(@NotNull String internalName) {
|
val index = internalName.lastIndexOf("/")
|
||||||
int index = internalName.lastIndexOf("/");
|
return if (index < 0) internalName else internalName.substring(index + 1)
|
||||||
return index < 0 ? internalName : internalName.substring(index + 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
fun wrapWithMaxLocalCalc(methodNode: MethodNode): MethodVisitor {
|
||||||
public static MethodVisitor wrapWithMaxLocalCalc(@NotNull MethodNode methodNode) {
|
return MaxStackFrameSizeAndLocalsCalculator(API, methodNode.access, methodNode.desc, methodNode)
|
||||||
return new MaxStackFrameSizeAndLocalsCalculator(API, methodNode.access, methodNode.desc, methodNode);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isInteger(@NotNull String string) {
|
private fun isInteger(string: String): Boolean {
|
||||||
if (string.isEmpty()) {
|
if (string.isEmpty()) {
|
||||||
return false;
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < string.length(); i++) {
|
for (i in 0..string.length - 1) {
|
||||||
if (!Character.isDigit(string.charAt(i))) {
|
if (!Character.isDigit(string[i])) {
|
||||||
return false;
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isCapturedFieldName(@NotNull String fieldName) {
|
fun isCapturedFieldName(fieldName: String): Boolean {
|
||||||
// TODO: improve this heuristic
|
// TODO: improve this heuristic
|
||||||
return fieldName.startsWith(CAPTURED_FIELD_PREFIX) &&
|
return fieldName.startsWith(CAPTURED_FIELD_PREFIX) && !fieldName.startsWith(NON_CAPTURED_FIELD_PREFIX) ||
|
||||||
!fieldName.startsWith(NON_CAPTURED_FIELD_PREFIX) ||
|
THIS_0 == fieldName ||
|
||||||
THIS$0.equals(fieldName) ||
|
`RECEIVER$0` == fieldName
|
||||||
RECEIVER$0.equals(fieldName);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isReturnOpcode(int opcode) {
|
fun isReturnOpcode(opcode: Int): Boolean {
|
||||||
return opcode >= Opcodes.IRETURN && opcode <= Opcodes.RETURN;
|
return opcode >= Opcodes.IRETURN && opcode <= Opcodes.RETURN
|
||||||
}
|
}
|
||||||
|
|
||||||
//marked return could be either non-local or local in case of labeled lambda self-returns
|
//marked return could be either non-local or local in case of labeled lambda self-returns
|
||||||
public static boolean isMarkedReturn(@NotNull AbstractInsnNode returnIns) {
|
fun isMarkedReturn(returnIns: AbstractInsnNode): Boolean {
|
||||||
return getMarkedReturnLabelOrNull(returnIns) != null;
|
return getMarkedReturnLabelOrNull(returnIns) != null
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
fun getMarkedReturnLabelOrNull(returnInsn: AbstractInsnNode): String? {
|
||||||
public static String getMarkedReturnLabelOrNull(@NotNull AbstractInsnNode returnInsn) {
|
if (!isReturnOpcode(returnInsn.opcode)) {
|
||||||
if (!isReturnOpcode(returnInsn.getOpcode())) {
|
return null
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
AbstractInsnNode previous = returnInsn.getPrevious();
|
val previous = returnInsn.previous
|
||||||
if (previous instanceof MethodInsnNode) {
|
if (previous is MethodInsnNode) {
|
||||||
MethodInsnNode marker = (MethodInsnNode) previous;
|
val marker = previous
|
||||||
if (NON_LOCAL_RETURN.equals(marker.owner)) {
|
if (NON_LOCAL_RETURN == marker.owner) {
|
||||||
return marker.name;
|
return marker.name
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void generateGlobalReturnFlag(@NotNull InstructionAdapter iv, @NotNull String labelName) {
|
fun generateGlobalReturnFlag(iv: InstructionAdapter, labelName: String) {
|
||||||
iv.invokestatic(NON_LOCAL_RETURN, labelName, "()V", false);
|
iv.invokestatic(NON_LOCAL_RETURN, labelName, "()V", false)
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
fun getReturnType(opcode: Int): Type {
|
||||||
public static Type getReturnType(int opcode) {
|
when (opcode) {
|
||||||
switch (opcode) {
|
Opcodes.RETURN -> return Type.VOID_TYPE
|
||||||
case Opcodes.RETURN:
|
Opcodes.IRETURN -> return Type.INT_TYPE
|
||||||
return Type.VOID_TYPE;
|
Opcodes.DRETURN -> return Type.DOUBLE_TYPE
|
||||||
case Opcodes.IRETURN:
|
Opcodes.FRETURN -> return Type.FLOAT_TYPE
|
||||||
return Type.INT_TYPE;
|
Opcodes.LRETURN -> return Type.LONG_TYPE
|
||||||
case Opcodes.DRETURN:
|
else -> return AsmTypes.OBJECT_TYPE
|
||||||
return Type.DOUBLE_TYPE;
|
|
||||||
case Opcodes.FRETURN:
|
|
||||||
return Type.FLOAT_TYPE;
|
|
||||||
case Opcodes.LRETURN:
|
|
||||||
return Type.LONG_TYPE;
|
|
||||||
default:
|
|
||||||
return AsmTypes.OBJECT_TYPE;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void insertNodeBefore(@NotNull MethodNode from, @NotNull MethodNode to, @NotNull AbstractInsnNode beforeNode) {
|
fun insertNodeBefore(from: MethodNode, to: MethodNode, beforeNode: AbstractInsnNode) {
|
||||||
ListIterator<AbstractInsnNode> iterator = from.instructions.iterator();
|
val iterator = from.instructions.iterator()
|
||||||
while (iterator.hasNext()) {
|
while (iterator.hasNext()) {
|
||||||
AbstractInsnNode next = iterator.next();
|
val next = iterator.next()
|
||||||
to.instructions.insertBefore(beforeNode, next);
|
to.instructions.insertBefore(beforeNode, next)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
fun createEmptyMethodNode(): MethodNode {
|
||||||
public static MethodNode createEmptyMethodNode() {
|
return MethodNode(API, 0, "fake", "()V", null, null)
|
||||||
return new MethodNode(API, 0, "fake", "()V", null, null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
fun firstLabelInChain(node: LabelNode): LabelNode {
|
||||||
public static LabelNode firstLabelInChain(@NotNull LabelNode node) {
|
var curNode = node
|
||||||
LabelNode curNode = node;
|
while (curNode.previous is LabelNode) {
|
||||||
while (curNode.getPrevious() instanceof LabelNode) {
|
curNode = curNode.previous as LabelNode
|
||||||
curNode = (LabelNode) curNode.getPrevious();
|
|
||||||
}
|
}
|
||||||
return curNode;
|
return curNode
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
fun getNodeText(node: MethodNode?): String {
|
||||||
public static String getNodeText(@Nullable MethodNode node) {
|
val textifier = Textifier()
|
||||||
Textifier textifier = new Textifier();
|
|
||||||
if (node == null) {
|
if (node == null) {
|
||||||
return "Not generated";
|
return "Not generated"
|
||||||
}
|
}
|
||||||
node.accept(new TraceMethodVisitor(textifier));
|
node.accept(TraceMethodVisitor(textifier))
|
||||||
StringWriter sw = new StringWriter();
|
val sw = StringWriter()
|
||||||
textifier.print(new PrintWriter(sw));
|
textifier.print(PrintWriter(sw))
|
||||||
sw.flush();
|
sw.flush()
|
||||||
return node.name + " " + node.desc + ":\n" + sw.getBuffer().toString();
|
return node.name + " " + node.desc + ":\n" + sw.buffer.toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
fun getInsnText(node: AbstractInsnNode?): String {
|
||||||
public static String getInsnText(@Nullable AbstractInsnNode node) {
|
if (node == null) return "<null>"
|
||||||
if (node == null) return "<null>";
|
val textifier = Textifier()
|
||||||
Textifier textifier = new Textifier();
|
node.accept(TraceMethodVisitor(textifier))
|
||||||
node.accept(new TraceMethodVisitor(textifier));
|
val sw = StringWriter()
|
||||||
StringWriter sw = new StringWriter();
|
textifier.print(PrintWriter(sw))
|
||||||
textifier.print(new PrintWriter(sw));
|
sw.flush()
|
||||||
sw.flush();
|
return sw.toString().trim { it <= ' ' }
|
||||||
return sw.toString().trim();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
fun getInsnOpcodeText(node: AbstractInsnNode?): String {
|
||||||
public static String getInsnOpcodeText(@Nullable AbstractInsnNode node) {
|
return if (node == null) "null" else Printer.OPCODES[node.opcode]
|
||||||
return node == null ? "null" : Printer.OPCODES[node.getOpcode()];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
internal /* package */ fun buildClassReaderByInternalName(state: GenerationState, internalName: String): ClassReader {
|
||||||
/* package */ static ClassReader buildClassReaderByInternalName(@NotNull GenerationState state, @NotNull String internalName) {
|
|
||||||
//try to find just compiled classes then in dependencies
|
//try to find just compiled classes then in dependencies
|
||||||
try {
|
try {
|
||||||
OutputFile outputFile = state.getFactory().get(internalName + ".class");
|
val outputFile = state.factory.get(internalName + ".class")
|
||||||
if (outputFile != null) {
|
if (outputFile != null) {
|
||||||
return new ClassReader(outputFile.asByteArray());
|
return ClassReader(outputFile.asByteArray())
|
||||||
}
|
}
|
||||||
VirtualFile file = findVirtualFileImprecise(state, internalName);
|
val file = findVirtualFileImprecise(state, internalName)
|
||||||
if (file != null) {
|
if (file != null) {
|
||||||
return new ClassReader(file.contentsToByteArray());
|
return ClassReader(file.contentsToByteArray())
|
||||||
}
|
}
|
||||||
throw new RuntimeException("Couldn't find virtual file for " + internalName);
|
throw RuntimeException("Couldn't find virtual file for " + internalName)
|
||||||
}
|
|
||||||
catch (IOException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
}
|
||||||
|
catch (e: IOException) {
|
||||||
|
throw RuntimeException(e)
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void generateFinallyMarker(@NotNull InstructionAdapter v, int depth, boolean start) {
|
|
||||||
v.iconst(depth);
|
|
||||||
v.invokestatic(INLINE_MARKER_CLASS_NAME, start ? INLINE_MARKER_FINALLY_START : INLINE_MARKER_FINALLY_END, "(I)V", false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isFinallyEnd(@NotNull AbstractInsnNode node) {
|
fun generateFinallyMarker(v: InstructionAdapter, depth: Int, start: Boolean) {
|
||||||
return isFinallyMarker(node, INLINE_MARKER_FINALLY_END);
|
v.iconst(depth)
|
||||||
|
v.invokestatic(INLINE_MARKER_CLASS_NAME, if (start) INLINE_MARKER_FINALLY_START else INLINE_MARKER_FINALLY_END, "(I)V", false)
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isFinallyStart(@NotNull AbstractInsnNode node) {
|
fun isFinallyEnd(node: AbstractInsnNode): Boolean {
|
||||||
return isFinallyMarker(node, INLINE_MARKER_FINALLY_START);
|
return isFinallyMarker(node, INLINE_MARKER_FINALLY_END)
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isFinallyMarker(@Nullable AbstractInsnNode node) {
|
fun isFinallyStart(node: AbstractInsnNode): Boolean {
|
||||||
return node != null && (isFinallyStart(node) || isFinallyEnd(node));
|
return isFinallyMarker(node, INLINE_MARKER_FINALLY_START)
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isFinallyMarker(@NotNull AbstractInsnNode node, String name) {
|
fun isFinallyMarker(node: AbstractInsnNode?): Boolean {
|
||||||
if (!(node instanceof MethodInsnNode)) return false;
|
return node != null && (isFinallyStart(node) || isFinallyEnd(node))
|
||||||
MethodInsnNode method = (MethodInsnNode) node;
|
|
||||||
return INLINE_MARKER_CLASS_NAME.equals(method.owner) && name.equals(method.name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isFinallyMarkerRequired(@NotNull MethodContext context) {
|
private fun isFinallyMarker(node: AbstractInsnNode, name: String): Boolean {
|
||||||
return context.isInlineMethodContext() || context instanceof InlineLambdaContext;
|
if (node !is MethodInsnNode) return false
|
||||||
|
val method = node
|
||||||
|
return INLINE_MARKER_CLASS_NAME == method.owner && name == method.name
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int getConstant(@NotNull AbstractInsnNode ins) {
|
fun isFinallyMarkerRequired(context: MethodContext): Boolean {
|
||||||
int opcode = ins.getOpcode();
|
return context.isInlineMethodContext || context is InlineLambdaContext
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getConstant(ins: AbstractInsnNode): Int {
|
||||||
|
val opcode = ins.opcode
|
||||||
if (opcode >= Opcodes.ICONST_0 && opcode <= Opcodes.ICONST_5) {
|
if (opcode >= Opcodes.ICONST_0 && opcode <= Opcodes.ICONST_5) {
|
||||||
return opcode - Opcodes.ICONST_0;
|
return opcode - Opcodes.ICONST_0
|
||||||
}
|
}
|
||||||
else if (opcode == Opcodes.BIPUSH || opcode == Opcodes.SIPUSH) {
|
else if (opcode == Opcodes.BIPUSH || opcode == Opcodes.SIPUSH) {
|
||||||
return ((IntInsnNode) ins).operand;
|
return (ins as IntInsnNode).operand
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
LdcInsnNode index = (LdcInsnNode) ins;
|
val index = ins as LdcInsnNode
|
||||||
return (Integer) index.cst;
|
return index.cst as Int
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void removeFinallyMarkers(@NotNull MethodNode intoNode) {
|
fun removeFinallyMarkers(intoNode: MethodNode) {
|
||||||
InsnList instructions = intoNode.instructions;
|
val instructions = intoNode.instructions
|
||||||
AbstractInsnNode curInstr = instructions.getFirst();
|
var curInstr: AbstractInsnNode? = instructions.first
|
||||||
while (curInstr != null) {
|
while (curInstr != null) {
|
||||||
if (isFinallyMarker(curInstr)) {
|
if (isFinallyMarker(curInstr)) {
|
||||||
AbstractInsnNode marker = curInstr;
|
val marker = curInstr
|
||||||
//just to assert
|
//just to assert
|
||||||
getConstant(marker.getPrevious());
|
getConstant(marker.previous)
|
||||||
curInstr = curInstr.getNext();
|
curInstr = curInstr.next
|
||||||
instructions.remove(marker.getPrevious());
|
instructions.remove(marker.previous)
|
||||||
instructions.remove(marker);
|
instructions.remove(marker)
|
||||||
continue;
|
continue
|
||||||
}
|
}
|
||||||
curInstr = curInstr.getNext();
|
curInstr = curInstr.next
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void addInlineMarker(@NotNull InstructionAdapter v, boolean isStartNotEnd) {
|
fun addInlineMarker(v: InstructionAdapter, isStartNotEnd: Boolean) {
|
||||||
v.visitMethodInsn(
|
v.visitMethodInsn(
|
||||||
Opcodes.INVOKESTATIC, INLINE_MARKER_CLASS_NAME,
|
Opcodes.INVOKESTATIC, INLINE_MARKER_CLASS_NAME,
|
||||||
isStartNotEnd ? INLINE_MARKER_BEFORE_METHOD_NAME : INLINE_MARKER_AFTER_METHOD_NAME,
|
if (isStartNotEnd) INLINE_MARKER_BEFORE_METHOD_NAME else INLINE_MARKER_AFTER_METHOD_NAME,
|
||||||
"()V", false
|
"()V", false
|
||||||
);
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isInlineMarker(@NotNull AbstractInsnNode insn) {
|
fun isInlineMarker(insn: AbstractInsnNode): Boolean {
|
||||||
return isInlineMarker(insn, null);
|
return isInlineMarker(insn, null)
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isInlineMarker(@NotNull AbstractInsnNode insn, @Nullable String name) {
|
private fun isInlineMarker(insn: AbstractInsnNode, name: String?): Boolean {
|
||||||
if (!(insn instanceof MethodInsnNode)) {
|
if (insn !is MethodInsnNode) {
|
||||||
return false;
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
MethodInsnNode methodInsnNode = (MethodInsnNode) insn;
|
val methodInsnNode = insn
|
||||||
return insn.getOpcode() == Opcodes.INVOKESTATIC &&
|
return insn.getOpcode() == Opcodes.INVOKESTATIC &&
|
||||||
methodInsnNode.owner.equals(INLINE_MARKER_CLASS_NAME) &&
|
methodInsnNode.owner == INLINE_MARKER_CLASS_NAME &&
|
||||||
(name != null ? methodInsnNode.name.equals(name)
|
if (name != null)
|
||||||
: methodInsnNode.name.equals(INLINE_MARKER_BEFORE_METHOD_NAME) ||
|
methodInsnNode.name == name
|
||||||
methodInsnNode.name.equals(INLINE_MARKER_AFTER_METHOD_NAME));
|
else
|
||||||
|
methodInsnNode.name == INLINE_MARKER_BEFORE_METHOD_NAME || methodInsnNode.name == INLINE_MARKER_AFTER_METHOD_NAME
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isBeforeInlineMarker(@NotNull AbstractInsnNode insn) {
|
fun isBeforeInlineMarker(insn: AbstractInsnNode): Boolean {
|
||||||
return isInlineMarker(insn, INLINE_MARKER_BEFORE_METHOD_NAME);
|
return isInlineMarker(insn, INLINE_MARKER_BEFORE_METHOD_NAME)
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isAfterInlineMarker(@NotNull AbstractInsnNode insn) {
|
fun isAfterInlineMarker(insn: AbstractInsnNode): Boolean {
|
||||||
return isInlineMarker(insn, INLINE_MARKER_AFTER_METHOD_NAME);
|
return isInlineMarker(insn, INLINE_MARKER_AFTER_METHOD_NAME)
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int getLoadStoreArgSize(int opcode) {
|
fun getLoadStoreArgSize(opcode: Int): Int {
|
||||||
return opcode == Opcodes.DSTORE || opcode == Opcodes.LSTORE || opcode == Opcodes.DLOAD || opcode == Opcodes.LLOAD ? 2 : 1;
|
return if (opcode == Opcodes.DSTORE || opcode == Opcodes.LSTORE || opcode == Opcodes.DLOAD || opcode == Opcodes.LLOAD) 2 else 1
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isStoreInstruction(int opcode) {
|
fun isStoreInstruction(opcode: Int): Boolean {
|
||||||
return opcode >= Opcodes.ISTORE && opcode <= Opcodes.ASTORE;
|
return opcode >= Opcodes.ISTORE && opcode <= Opcodes.ASTORE
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int calcMarkerShift(@NotNull Parameters parameters, @NotNull MethodNode node) {
|
fun calcMarkerShift(parameters: Parameters, node: MethodNode): Int {
|
||||||
int markerShiftTemp = getIndexAfterLastMarker(node);
|
val markerShiftTemp = getIndexAfterLastMarker(node)
|
||||||
return markerShiftTemp - parameters.getRealParametersSizeOnStack() + parameters.getArgsSizeOnStack();
|
return markerShiftTemp - parameters.realParametersSizeOnStack + parameters.argsSizeOnStack
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int getIndexAfterLastMarker(@NotNull MethodNode node) {
|
private fun getIndexAfterLastMarker(node: MethodNode): Int {
|
||||||
int result = -1;
|
var result = -1
|
||||||
for (LocalVariableNode variable : node.localVariables) {
|
for (variable in node.localVariables) {
|
||||||
if (isFakeLocalVariableForInline(variable.name)) {
|
if (isFakeLocalVariableForInline(variable.name)) {
|
||||||
result = Math.max(result, variable.index + 1);
|
result = Math.max(result, variable.index + 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isFakeLocalVariableForInline(@NotNull String name) {
|
fun isFakeLocalVariableForInline(name: String): Boolean {
|
||||||
return name.startsWith(JvmAbi.LOCAL_VARIABLE_NAME_PREFIX_INLINE_FUNCTION) ||
|
return name.startsWith(JvmAbi.LOCAL_VARIABLE_NAME_PREFIX_INLINE_FUNCTION) || name.startsWith(JvmAbi.LOCAL_VARIABLE_NAME_PREFIX_INLINE_ARGUMENT)
|
||||||
name.startsWith(JvmAbi.LOCAL_VARIABLE_NAME_PREFIX_INLINE_ARGUMENT);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isThis0(@NotNull String name) {
|
fun isThis0(name: String): Boolean {
|
||||||
return THIS$0.equals(name);
|
return THIS_0 == name
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isSpecialEnumMethod(@NotNull FunctionDescriptor functionDescriptor) {
|
fun isSpecialEnumMethod(functionDescriptor: FunctionDescriptor): Boolean {
|
||||||
DeclarationDescriptor containingDeclaration = functionDescriptor.getContainingDeclaration();
|
val containingDeclaration = functionDescriptor.containingDeclaration as? PackageFragmentDescriptor ?: return false
|
||||||
if (!(containingDeclaration instanceof PackageFragmentDescriptor)) {
|
if (containingDeclaration.fqName != KotlinBuiltIns.BUILT_INS_PACKAGE_FQ_NAME) {
|
||||||
return false;
|
return false
|
||||||
}
|
}
|
||||||
if (!((PackageFragmentDescriptor) containingDeclaration).getFqName().equals(KotlinBuiltIns.BUILT_INS_PACKAGE_FQ_NAME)) {
|
if (functionDescriptor.typeParameters.size != 1) {
|
||||||
return false;
|
return false
|
||||||
}
|
}
|
||||||
if (functionDescriptor.getTypeParameters().size() != 1) {
|
val name = functionDescriptor.name.asString()
|
||||||
return false;
|
val parameters = functionDescriptor.valueParameters
|
||||||
}
|
return "enumValues" == name && parameters.size == 0 || "enumValueOf" == name && parameters.size == 1 && KotlinBuiltIns.isString(parameters[0].type)
|
||||||
String name = functionDescriptor.getName().asString();
|
|
||||||
List<ValueParameterDescriptor> parameters = functionDescriptor.getValueParameters();
|
|
||||||
return "enumValues".equals(name) && parameters.size() == 0 ||
|
|
||||||
"enumValueOf".equals(name) && parameters.size() == 1 && KotlinBuiltIns.isString(parameters.get(0).getType());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static MethodNode createSpecialEnumMethodBody(
|
fun createSpecialEnumMethodBody(
|
||||||
@NotNull ExpressionCodegen codegen,
|
codegen: ExpressionCodegen,
|
||||||
@NotNull String name,
|
name: String,
|
||||||
@NotNull KotlinType type,
|
type: KotlinType,
|
||||||
@NotNull KotlinTypeMapper typeMapper
|
typeMapper: KotlinTypeMapper
|
||||||
) {
|
): MethodNode {
|
||||||
boolean isValueOf = "enumValueOf".equals(name);
|
val isValueOf = "enumValueOf" == name
|
||||||
Type invokeType = typeMapper.mapType(type);
|
val invokeType = typeMapper.mapType(type)
|
||||||
String desc = getSpecialEnumFunDescriptor(invokeType, isValueOf);
|
val desc = getSpecialEnumFunDescriptor(invokeType, isValueOf)
|
||||||
MethodNode node = new MethodNode(API, Opcodes.ACC_STATIC, "fake", desc, null, null);
|
val node = MethodNode(API, Opcodes.ACC_STATIC, "fake", desc, null, null)
|
||||||
codegen.putReifiedOperationMarkerIfTypeIsReifiedParameter(type, ReifiedTypeInliner.OperationKind.ENUM_REIFIED, new InstructionAdapter(node));
|
codegen.putReifiedOperationMarkerIfTypeIsReifiedParameter(type, ReifiedTypeInliner.OperationKind.ENUM_REIFIED, InstructionAdapter(node))
|
||||||
if (isValueOf) {
|
if (isValueOf) {
|
||||||
node.visitInsn(Opcodes.ACONST_NULL);
|
node.visitInsn(Opcodes.ACONST_NULL)
|
||||||
node.visitVarInsn(Opcodes.ALOAD, 0);
|
node.visitVarInsn(Opcodes.ALOAD, 0)
|
||||||
|
|
||||||
node.visitMethodInsn(Opcodes.INVOKESTATIC, ENUM_TYPE.getInternalName(), "valueOf",
|
node.visitMethodInsn(Opcodes.INVOKESTATIC, ENUM_TYPE.internalName, "valueOf",
|
||||||
Type.getMethodDescriptor(ENUM_TYPE, JAVA_CLASS_TYPE, AsmTypes.JAVA_STRING_TYPE), false);
|
Type.getMethodDescriptor(ENUM_TYPE, JAVA_CLASS_TYPE, AsmTypes.JAVA_STRING_TYPE), false)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
node.visitInsn(Opcodes.ICONST_0);
|
node.visitInsn(Opcodes.ICONST_0)
|
||||||
node.visitTypeInsn(Opcodes.ANEWARRAY, ENUM_TYPE.getInternalName());
|
node.visitTypeInsn(Opcodes.ANEWARRAY, ENUM_TYPE.internalName)
|
||||||
}
|
}
|
||||||
node.visitInsn(Opcodes.ARETURN);
|
node.visitInsn(Opcodes.ARETURN)
|
||||||
node.visitMaxs(isValueOf ? 3 : 2, isValueOf ? 1 : 0);
|
node.visitMaxs(if (isValueOf) 3 else 2, if (isValueOf) 1 else 0)
|
||||||
return node;
|
return node
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
fun getSpecialEnumFunDescriptor(type: Type, isValueOf: Boolean): String {
|
||||||
public static String getSpecialEnumFunDescriptor(@NotNull Type type, boolean isValueOf) {
|
return if (isValueOf) Type.getMethodDescriptor(type, AsmTypes.JAVA_STRING_TYPE) else Type.getMethodDescriptor(AsmUtil.getArrayType(type))
|
||||||
return isValueOf ? Type.getMethodDescriptor(type, AsmTypes.JAVA_STRING_TYPE) : Type.getMethodDescriptor(AsmUtil.getArrayType(type));
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
|||||||
+8
-9
@@ -22,7 +22,6 @@ import org.jetbrains.annotations.NotNull;
|
|||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.annotations.ReadOnly;
|
import org.jetbrains.annotations.ReadOnly;
|
||||||
import org.jetbrains.annotations.TestOnly;
|
import org.jetbrains.annotations.TestOnly;
|
||||||
import org.jetbrains.kotlin.codegen.optimization.common.UtilKt;
|
|
||||||
import org.jetbrains.org.objectweb.asm.Label;
|
import org.jetbrains.org.objectweb.asm.Label;
|
||||||
import org.jetbrains.org.objectweb.asm.Opcodes;
|
import org.jetbrains.org.objectweb.asm.Opcodes;
|
||||||
import org.jetbrains.org.objectweb.asm.Type;
|
import org.jetbrains.org.objectweb.asm.Type;
|
||||||
@@ -34,7 +33,7 @@ import java.io.PrintWriter;
|
|||||||
import java.io.StringWriter;
|
import java.io.StringWriter;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
import static org.jetbrains.kotlin.codegen.inline.InlineCodegenUtil.*;
|
import static org.jetbrains.kotlin.codegen.inline.InlineCodegenUtilsKt.*;
|
||||||
import static org.jetbrains.kotlin.codegen.inline.MethodInlinerUtilKt.getNextMeaningful;
|
import static org.jetbrains.kotlin.codegen.inline.MethodInlinerUtilKt.getNextMeaningful;
|
||||||
|
|
||||||
public class InternalFinallyBlockInliner extends CoveringTryCatchNodeProcessor {
|
public class InternalFinallyBlockInliner extends CoveringTryCatchNodeProcessor {
|
||||||
@@ -106,7 +105,7 @@ public class InternalFinallyBlockInliner extends CoveringTryCatchNodeProcessor {
|
|||||||
|
|
||||||
private int initAndGetVarIndexForNonLocalReturnValue() {
|
private int initAndGetVarIndexForNonLocalReturnValue() {
|
||||||
MaxLocalsCalculator tempCalcNode = new MaxLocalsCalculator(
|
MaxLocalsCalculator tempCalcNode = new MaxLocalsCalculator(
|
||||||
InlineCodegenUtil.API,
|
API,
|
||||||
inlineFun.access, inlineFun.desc, null
|
inlineFun.access, inlineFun.desc, null
|
||||||
);
|
);
|
||||||
inlineFun.accept(tempCalcNode);
|
inlineFun.accept(tempCalcNode);
|
||||||
@@ -126,8 +125,8 @@ public class InternalFinallyBlockInliner extends CoveringTryCatchNodeProcessor {
|
|||||||
processInstruction(curIns, false);
|
processInstruction(curIns, false);
|
||||||
|
|
||||||
//At this point only global return is possible, local one already substituted with: goto endLabel
|
//At this point only global return is possible, local one already substituted with: goto endLabel
|
||||||
if (!InlineCodegenUtil.isReturnOpcode(curIns.getOpcode()) ||
|
if (!isReturnOpcode(curIns.getOpcode()) ||
|
||||||
!InlineCodegenUtil.isMarkedReturn(curIns)) {
|
!isMarkedReturn(curIns)) {
|
||||||
curIns = curIns.getPrevious();
|
curIns = curIns.getPrevious();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -147,7 +146,7 @@ public class InternalFinallyBlockInliner extends CoveringTryCatchNodeProcessor {
|
|||||||
AbstractInsnNode nextPrev = instrInsertFinallyBefore.getPrevious();
|
AbstractInsnNode nextPrev = instrInsertFinallyBefore.getPrevious();
|
||||||
assert markedReturn.getNext() instanceof LabelNode : "Label should be occurred after non-local return";
|
assert markedReturn.getNext() instanceof LabelNode : "Label should be occurred after non-local return";
|
||||||
LabelNode newFinallyEnd = (LabelNode) markedReturn.getNext();
|
LabelNode newFinallyEnd = (LabelNode) markedReturn.getNext();
|
||||||
Type nonLocalReturnType = InlineCodegenUtil.getReturnType(markedReturn.getOpcode());
|
Type nonLocalReturnType = getReturnType(markedReturn.getOpcode());
|
||||||
|
|
||||||
//Generally there could be several tryCatch blocks (group) on one code interval (same start and end labels, but maybe different handlers) -
|
//Generally there could be several tryCatch blocks (group) on one code interval (same start and end labels, but maybe different handlers) -
|
||||||
// all of them refer to one try/*catches*/finally or try/catches.
|
// all of them refer to one try/*catches*/finally or try/catches.
|
||||||
@@ -216,7 +215,7 @@ public class InternalFinallyBlockInliner extends CoveringTryCatchNodeProcessor {
|
|||||||
finallyBlockCopy.visitLabel(insertedBlockEnd);
|
finallyBlockCopy.visitLabel(insertedBlockEnd);
|
||||||
|
|
||||||
//Copying finally body before non-local return instruction
|
//Copying finally body before non-local return instruction
|
||||||
InlineCodegenUtil.insertNodeBefore(finallyBlockCopy, inlineFun, instrInsertFinallyBefore);
|
insertNodeBefore(finallyBlockCopy, inlineFun, instrInsertFinallyBefore);
|
||||||
|
|
||||||
updateExceptionTable(clusterBlocks, newFinallyStart, newFinallyEnd,
|
updateExceptionTable(clusterBlocks, newFinallyStart, newFinallyEnd,
|
||||||
tryCatchBlockInlinedInFinally, labelsInsideFinally, (LabelNode) insertedBlockEnd.info);
|
tryCatchBlockInlinedInFinally, labelsInsideFinally, (LabelNode) insertedBlockEnd.info);
|
||||||
@@ -251,7 +250,7 @@ public class InternalFinallyBlockInliner extends CoveringTryCatchNodeProcessor {
|
|||||||
int depthShift
|
int depthShift
|
||||||
) {
|
) {
|
||||||
if (isInsOrJumpInsideFinally) {
|
if (isInsOrJumpInsideFinally) {
|
||||||
if (InlineCodegenUtil.isFinallyMarker(currentIns.getNext())) {
|
if (isFinallyMarker(currentIns.getNext())) {
|
||||||
Integer constant = getConstant(currentIns);
|
Integer constant = getConstant(currentIns);
|
||||||
finallyBlockCopy.visitLdcInsn(constant + depthShift);
|
finallyBlockCopy.visitLdcInsn(constant + depthShift);
|
||||||
} else {
|
} else {
|
||||||
@@ -455,7 +454,7 @@ public class InternalFinallyBlockInliner extends CoveringTryCatchNodeProcessor {
|
|||||||
AbstractInsnNode current = meaningful.getNext();
|
AbstractInsnNode current = meaningful.getNext();
|
||||||
while (endFinallyChainExclusive != current) {
|
while (endFinallyChainExclusive != current) {
|
||||||
current = current.getNext();
|
current = current.getNext();
|
||||||
if (InlineCodegenUtil.isFinallyEnd(current)) {
|
if (isFinallyEnd(current)) {
|
||||||
Integer currentDepth = getConstant(current.getPrevious());
|
Integer currentDepth = getConstant(current.getPrevious());
|
||||||
if (currentDepth.equals(finallyDepth)) {
|
if (currentDepth.equals(finallyDepth)) {
|
||||||
endFinallyChainExclusive = current.getNext();
|
endFinallyChainExclusive = current.getNext();
|
||||||
|
|||||||
@@ -106,10 +106,10 @@ class DefaultLambda(
|
|||||||
override fun isMyLabel(name: String): Boolean = false
|
override fun isMyLabel(name: String): Boolean = false
|
||||||
|
|
||||||
override fun generateLambdaBody(codegen: ExpressionCodegen, reifiedTypeInliner: ReifiedTypeInliner) {
|
override fun generateLambdaBody(codegen: ExpressionCodegen, reifiedTypeInliner: ReifiedTypeInliner) {
|
||||||
val classReader = InlineCodegenUtil.buildClassReaderByInternalName(codegen.state, lambdaClassType.internalName)
|
val classReader = buildClassReaderByInternalName(codegen.state, lambdaClassType.internalName)
|
||||||
var isPropertyReference = false
|
var isPropertyReference = false
|
||||||
var isFunctionReference = false
|
var isFunctionReference = false
|
||||||
classReader.accept(object: ClassVisitor(InlineCodegenUtil.API){
|
classReader.accept(object: ClassVisitor(API){
|
||||||
override fun visit(version: Int, access: Int, name: String, signature: String?, superName: String?, interfaces: Array<out String>?) {
|
override fun visit(version: Int, access: Int, name: String, signature: String?, superName: String?, interfaces: Array<out String>?) {
|
||||||
isPropertyReference = superName?.startsWith("kotlin/jvm/internal/PropertyReference") ?: false
|
isPropertyReference = superName?.startsWith("kotlin/jvm/internal/PropertyReference") ?: false
|
||||||
isFunctionReference = "kotlin/jvm/internal/FunctionReference" == superName
|
isFunctionReference = "kotlin/jvm/internal/FunctionReference" == superName
|
||||||
@@ -128,7 +128,7 @@ class DefaultLambda(
|
|||||||
}
|
}
|
||||||
|
|
||||||
val descriptor = Type.getMethodDescriptor(Type.VOID_TYPE, *capturedArgs)
|
val descriptor = Type.getMethodDescriptor(Type.VOID_TYPE, *capturedArgs)
|
||||||
val constructor = InlineCodegenUtil.getMethodNode(
|
val constructor = getMethodNode(
|
||||||
classReader.b,
|
classReader.b,
|
||||||
"<init>",
|
"<init>",
|
||||||
descriptor,
|
descriptor,
|
||||||
@@ -156,7 +156,7 @@ class DefaultLambda(
|
|||||||
codegen.state.typeMapper.mapSignatureSkipGeneric(invokeMethodDescriptor).asmMethod.descriptor
|
codegen.state.typeMapper.mapSignatureSkipGeneric(invokeMethodDescriptor).asmMethod.descriptor
|
||||||
)
|
)
|
||||||
|
|
||||||
node = InlineCodegenUtil.getMethodNode(
|
node = getMethodNode(
|
||||||
classReader.b,
|
classReader.b,
|
||||||
invokeMethod.name,
|
invokeMethod.name,
|
||||||
invokeMethod.descriptor,
|
invokeMethod.descriptor,
|
||||||
@@ -271,11 +271,11 @@ class ExpressionLambda(
|
|||||||
val jvmMethodSignature = typeMapper.mapSignatureSkipGeneric(invokeMethodDescriptor)
|
val jvmMethodSignature = typeMapper.mapSignatureSkipGeneric(invokeMethodDescriptor)
|
||||||
val asmMethod = jvmMethodSignature.asmMethod
|
val asmMethod = jvmMethodSignature.asmMethod
|
||||||
val methodNode = MethodNode(
|
val methodNode = MethodNode(
|
||||||
InlineCodegenUtil.API, AsmUtil.getMethodAsmFlags(invokeMethodDescriptor, context.contextKind, codegen.state),
|
API, AsmUtil.getMethodAsmFlags(invokeMethodDescriptor, context.contextKind, codegen.state),
|
||||||
asmMethod.name, asmMethod.descriptor, null, null
|
asmMethod.name, asmMethod.descriptor, null, null
|
||||||
)
|
)
|
||||||
|
|
||||||
node = InlineCodegenUtil.wrapWithMaxLocalCalc(methodNode).let { adapter ->
|
node = wrapWithMaxLocalCalc(methodNode).let { adapter ->
|
||||||
val smap = InlineCodegen.generateMethodBody(
|
val smap = InlineCodegen.generateMethodBody(
|
||||||
adapter, invokeMethodDescriptor, context, functionWithBodyOrCallableReference, jvmMethodSignature, codegen, this
|
adapter, invokeMethodDescriptor, context, functionWithBodyOrCallableReference, jvmMethodSignature, codegen, this
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -103,7 +103,7 @@ class LocalVarRemapper(private val params: Parameters, private val additionalShi
|
|||||||
val remapInfo = remap(`var`)
|
val remapInfo = remap(`var`)
|
||||||
val value = remapInfo.value
|
val value = remapInfo.value
|
||||||
if (value is StackValue.Local) {
|
if (value is StackValue.Local) {
|
||||||
val isStore = InlineCodegenUtil.isStoreInstruction(opcode)
|
val isStore = isStoreInstruction(opcode)
|
||||||
if (remapInfo.parameterInfo != null) {
|
if (remapInfo.parameterInfo != null) {
|
||||||
//All remapped value parameters can't be rewritten except case of default ones.
|
//All remapped value parameters can't be rewritten except case of default ones.
|
||||||
//On remapping default parameter to actual value there is only one instruction that writes to it according to mask value
|
//On remapping default parameter to actual value there is only one instruction that writes to it according to mask value
|
||||||
|
|||||||
@@ -23,10 +23,12 @@ import org.jetbrains.org.objectweb.asm.MethodVisitor;
|
|||||||
import org.jetbrains.org.objectweb.asm.TypePath;
|
import org.jetbrains.org.objectweb.asm.TypePath;
|
||||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter;
|
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter;
|
||||||
|
|
||||||
|
import static org.jetbrains.kotlin.codegen.inline.InlineCodegenUtilsKt.API;
|
||||||
|
|
||||||
public class MethodBodyVisitor extends InstructionAdapter {
|
public class MethodBodyVisitor extends InstructionAdapter {
|
||||||
|
|
||||||
public MethodBodyVisitor(MethodVisitor mv) {
|
public MethodBodyVisitor(MethodVisitor mv) {
|
||||||
super(InlineCodegenUtil.API, mv);
|
super(API, mv);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ package org.jetbrains.kotlin.codegen.inline
|
|||||||
|
|
||||||
import org.jetbrains.kotlin.codegen.ClosureCodegen
|
import org.jetbrains.kotlin.codegen.ClosureCodegen
|
||||||
import org.jetbrains.kotlin.codegen.StackValue
|
import org.jetbrains.kotlin.codegen.StackValue
|
||||||
import org.jetbrains.kotlin.codegen.inline.InlineCodegenUtil.*
|
|
||||||
import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicMethods
|
import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicMethods
|
||||||
import org.jetbrains.kotlin.codegen.optimization.FixStackWithLabelNormalizationMethodTransformer
|
import org.jetbrains.kotlin.codegen.optimization.FixStackWithLabelNormalizationMethodTransformer
|
||||||
import org.jetbrains.kotlin.codegen.optimization.common.InsnSequence
|
import org.jetbrains.kotlin.codegen.optimization.common.InsnSequence
|
||||||
@@ -87,7 +86,7 @@ class MethodInliner(
|
|||||||
transformedNode.instructions.resetLabels()
|
transformedNode.instructions.resetLabels()
|
||||||
|
|
||||||
val resultNode = MethodNode(
|
val resultNode = MethodNode(
|
||||||
InlineCodegenUtil.API, transformedNode.access, transformedNode.name, transformedNode.desc,
|
API, transformedNode.access, transformedNode.name, transformedNode.desc,
|
||||||
transformedNode.signature, transformedNode.exceptions?.toTypedArray()
|
transformedNode.signature, transformedNode.exceptions?.toTypedArray()
|
||||||
)
|
)
|
||||||
val visitor = RemapVisitor(resultNode, remapper, nodeRemapper)
|
val visitor = RemapVisitor(resultNode, remapper, nodeRemapper)
|
||||||
@@ -130,7 +129,7 @@ class MethodInliner(
|
|||||||
AsmTypeRemapper(remapper, result)
|
AsmTypeRemapper(remapper, result)
|
||||||
)
|
)
|
||||||
|
|
||||||
val markerShift = InlineCodegenUtil.calcMarkerShift(parameters, node)
|
val markerShift = calcMarkerShift(parameters, node)
|
||||||
val lambdaInliner = object : InlineAdapter(remappingMethodAdapter, parameters.argsSizeOnStack, sourceMapper) {
|
val lambdaInliner = object : InlineAdapter(remappingMethodAdapter, parameters.argsSizeOnStack, sourceMapper) {
|
||||||
private var transformationInfo: TransformationInfo? = null
|
private var transformationInfo: TransformationInfo? = null
|
||||||
|
|
||||||
@@ -312,11 +311,11 @@ class MethodInliner(
|
|||||||
val realParametersSize = parameters.realParametersSizeOnStack
|
val realParametersSize = parameters.realParametersSizeOnStack
|
||||||
|
|
||||||
val transformedNode = object : MethodNode(
|
val transformedNode = object : MethodNode(
|
||||||
InlineCodegenUtil.API, node.access, node.name,
|
API, node.access, node.name,
|
||||||
Type.getMethodDescriptor(Type.getReturnType(node.desc), *(Type.getArgumentTypes(node.desc) + parameters.capturedTypes)),
|
Type.getMethodDescriptor(Type.getReturnType(node.desc), *(Type.getArgumentTypes(node.desc) + parameters.capturedTypes)),
|
||||||
node.signature, node.exceptions?.toTypedArray()
|
node.signature, node.exceptions?.toTypedArray()
|
||||||
) {
|
) {
|
||||||
private val GENERATE_DEBUG_INFO = InlineCodegenUtil.GENERATE_SMAP && inlineOnlySmapSkipper == null
|
private val GENERATE_DEBUG_INFO = GENERATE_SMAP && inlineOnlySmapSkipper == null
|
||||||
|
|
||||||
private val isInliningLambda = nodeRemapper.isInsideInliningLambda
|
private val isInliningLambda = nodeRemapper.isInsideInliningLambda
|
||||||
|
|
||||||
@@ -343,8 +342,8 @@ class MethodInliner(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun visitMethodInsn(opcode: Int, owner: String, name: String, desc: String, itf: Boolean) {
|
override fun visitMethodInsn(opcode: Int, owner: String, name: String, desc: String, itf: Boolean) {
|
||||||
if (InlineCodegenUtil.DEFAULT_LAMBDA_FAKE_CALL == owner) {
|
if (DEFAULT_LAMBDA_FAKE_CALL == owner) {
|
||||||
val index = name.substringAfter(InlineCodegenUtil.DEFAULT_LAMBDA_FAKE_CALL).toInt()
|
val index = name.substringAfter(DEFAULT_LAMBDA_FAKE_CALL).toInt()
|
||||||
val lambda = getLambdaIfExists(index) as DefaultLambda
|
val lambda = getLambdaIfExists(index) as DefaultLambda
|
||||||
lambda.parameterOffsetsInDefault.zip(lambda.capturedVars).asReversed().forEach {
|
lambda.parameterOffsetsInDefault.zip(lambda.capturedVars).asReversed().forEach {
|
||||||
(_, captured) ->
|
(_, captured) ->
|
||||||
@@ -362,7 +361,7 @@ class MethodInliner(
|
|||||||
name: String, desc: String, signature: String?, start: Label, end: Label, index: Int
|
name: String, desc: String, signature: String?, start: Label, end: Label, index: Int
|
||||||
) {
|
) {
|
||||||
if (isInliningLambda || GENERATE_DEBUG_INFO) {
|
if (isInliningLambda || GENERATE_DEBUG_INFO) {
|
||||||
val varSuffix = if (inliningContext.isRoot && !InlineCodegenUtil.isFakeLocalVariableForInline(name)) INLINE_FUN_VAR_SUFFIX else ""
|
val varSuffix = if (inliningContext.isRoot && !isFakeLocalVariableForInline(name)) INLINE_FUN_VAR_SUFFIX else ""
|
||||||
val varName = if (!varSuffix.isEmpty() && name == "this") name + "_" else name
|
val varName = if (!varSuffix.isEmpty() && name == "this") name + "_" else name
|
||||||
super.visitLocalVariable(varName + varSuffix, desc, signature, start, end, getNewIndex(index))
|
super.visitLocalVariable(varName + varSuffix, desc, signature, start, end, getNewIndex(index))
|
||||||
}
|
}
|
||||||
@@ -400,9 +399,9 @@ class MethodInliner(
|
|||||||
awaitClassReification = true
|
awaitClassReification = true
|
||||||
}
|
}
|
||||||
else if (cur is MethodInsnNode) {
|
else if (cur is MethodInsnNode) {
|
||||||
if (InlineCodegenUtil.isFinallyStart(cur)) {
|
if (isFinallyStart(cur)) {
|
||||||
//TODO deep index calc could be more precise
|
//TODO deep index calc could be more precise
|
||||||
currentFinallyDeep = InlineCodegenUtil.getConstant(cur.previous)
|
currentFinallyDeep = getConstant(cur.previous)
|
||||||
}
|
}
|
||||||
|
|
||||||
val owner = cur.owner
|
val owner = cur.owner
|
||||||
@@ -668,7 +667,7 @@ class MethodInliner(
|
|||||||
insertBeforeInsn: AbstractInsnNode,
|
insertBeforeInsn: AbstractInsnNode,
|
||||||
sourceValueFrame: Frame<SourceValue>
|
sourceValueFrame: Frame<SourceValue>
|
||||||
) {
|
) {
|
||||||
assert(InlineCodegenUtil.isReturnOpcode(returnInsn.opcode)) { "return instruction expected" }
|
assert(isReturnOpcode(returnInsn.opcode)) { "return instruction expected" }
|
||||||
assert(returnOpcode < 0 || returnOpcode == returnInsn.opcode) { "Return op should be " + Printer.OPCODES[returnOpcode] + ", got " + Printer.OPCODES[returnInsn.opcode] }
|
assert(returnOpcode < 0 || returnOpcode == returnInsn.opcode) { "Return op should be " + Printer.OPCODES[returnOpcode] + ", got " + Printer.OPCODES[returnInsn.opcode] }
|
||||||
returnOpcode = returnInsn.opcode
|
returnOpcode = returnInsn.opcode
|
||||||
|
|
||||||
@@ -771,9 +770,9 @@ class MethodInliner(
|
|||||||
|
|
||||||
var cur: AbstractInsnNode? = node.instructions.first
|
var cur: AbstractInsnNode? = node.instructions.first
|
||||||
while (cur != null) {
|
while (cur != null) {
|
||||||
if (cur is MethodInsnNode && InlineCodegenUtil.isFinallyMarker(cur)) {
|
if (cur is MethodInsnNode && isFinallyMarker(cur)) {
|
||||||
val constant = cur.previous
|
val constant = cur.previous
|
||||||
val curDeep = InlineCodegenUtil.getConstant(constant)
|
val curDeep = getConstant(constant)
|
||||||
node.instructions.insert(constant, LdcInsnNode(curDeep + finallyDeepShift))
|
node.instructions.insert(constant, LdcInsnNode(curDeep + finallyDeepShift))
|
||||||
node.instructions.remove(constant)
|
node.instructions.remove(constant)
|
||||||
}
|
}
|
||||||
@@ -829,9 +828,9 @@ class MethodInliner(
|
|||||||
val instructions = node.instructions
|
val instructions = node.instructions
|
||||||
var insnNode: AbstractInsnNode? = instructions.first
|
var insnNode: AbstractInsnNode? = instructions.first
|
||||||
while (insnNode != null) {
|
while (insnNode != null) {
|
||||||
if (InlineCodegenUtil.isReturnOpcode(insnNode.opcode)) {
|
if (isReturnOpcode(insnNode.opcode)) {
|
||||||
var isLocalReturn = true
|
var isLocalReturn = true
|
||||||
val labelName = InlineCodegenUtil.getMarkedReturnLabelOrNull(insnNode)
|
val labelName = getMarkedReturnLabelOrNull(insnNode)
|
||||||
|
|
||||||
if (labelName != null) {
|
if (labelName != null) {
|
||||||
isLocalReturn = labelOwner.isMyLabel(labelName)
|
isLocalReturn = labelOwner.isMyLabel(labelName)
|
||||||
|
|||||||
@@ -121,7 +121,7 @@ fun MethodNode.findCapturedFieldAssignmentInstructions(): Sequence<FieldInsnNode
|
|||||||
val prevPrev = fieldNode.previous?.previous as? VarInsnNode
|
val prevPrev = fieldNode.previous?.previous as? VarInsnNode
|
||||||
|
|
||||||
fieldNode.opcode == Opcodes.PUTFIELD &&
|
fieldNode.opcode == Opcodes.PUTFIELD &&
|
||||||
InlineCodegenUtil.isCapturedFieldName(fieldNode.name) &&
|
isCapturedFieldName(fieldNode.name) &&
|
||||||
fieldNode.previous is VarInsnNode && prevPrev != null && prevPrev.`var` == 0
|
fieldNode.previous is VarInsnNode && prevPrev != null && prevPrev.`var` == 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ abstract class ObjectTransformer<out T : TransformationInfo>(@JvmField val trans
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun createClassReader(): ClassReader {
|
fun createClassReader(): ClassReader {
|
||||||
return InlineCodegenUtil.buildClassReaderByInternalName(state, transformationInfo.oldClassName)
|
return buildClassReaderByInternalName(state, transformationInfo.oldClassName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,7 +64,7 @@ class WhenMappingTransformer(
|
|||||||
/*MAPPING File could contains mappings for several enum classes, we should filter one*/
|
/*MAPPING File could contains mappings for several enum classes, we should filter one*/
|
||||||
val methodNodes = arrayListOf<MethodNode>()
|
val methodNodes = arrayListOf<MethodNode>()
|
||||||
val fieldNode = transformationInfo.fieldNode
|
val fieldNode = transformationInfo.fieldNode
|
||||||
classReader.accept(object : ClassVisitor(InlineCodegenUtil.API, classBuilder.visitor) {
|
classReader.accept(object : ClassVisitor(API, classBuilder.visitor) {
|
||||||
override fun visit(version: Int, access: Int, name: String, signature: String?, superName: String, interfaces: Array<String>) {
|
override fun visit(version: Int, access: Int, name: String, signature: String?, superName: String, interfaces: Array<String>) {
|
||||||
classBuilder.defineClass(null, version, access, name, signature, superName, interfaces)
|
classBuilder.defineClass(null, version, access, name, signature, superName, interfaces)
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-3
@@ -17,8 +17,6 @@
|
|||||||
package org.jetbrains.kotlin.codegen.inline
|
package org.jetbrains.kotlin.codegen.inline
|
||||||
|
|
||||||
import org.jetbrains.kotlin.codegen.StackValue
|
import org.jetbrains.kotlin.codegen.StackValue
|
||||||
import org.jetbrains.kotlin.codegen.inline.InlineCodegenUtil.CAPTURED_FIELD_FOLD_PREFIX
|
|
||||||
import org.jetbrains.kotlin.codegen.inline.InlineCodegenUtil.THIS
|
|
||||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||||
import org.jetbrains.org.objectweb.asm.Type
|
import org.jetbrains.org.objectweb.asm.Type
|
||||||
import org.jetbrains.org.objectweb.asm.tree.FieldInsnNode
|
import org.jetbrains.org.objectweb.asm.tree.FieldInsnNode
|
||||||
@@ -67,7 +65,7 @@ class RegeneratedLambdaFieldRemapper(
|
|||||||
val field = findFieldInSuper(fin) ?:
|
val field = findFieldInSuper(fin) ?:
|
||||||
//search in parent
|
//search in parent
|
||||||
findFieldInSuper(FieldInsnNode(
|
findFieldInSuper(FieldInsnNode(
|
||||||
Opcodes.GETSTATIC, originalLambdaInternalName, InlineCodegenUtil.`THIS$0`,
|
Opcodes.GETSTATIC, originalLambdaInternalName, THIS_0,
|
||||||
Type.getObjectType(parent!!.originalLambdaInternalName!!).descriptor
|
Type.getObjectType(parent!!.originalLambdaInternalName!!).descriptor
|
||||||
))?.also { fromParent = true } ?:
|
))?.also { fromParent = true } ?:
|
||||||
throw AssertionError("Couldn't find captured this $originalLambdaInternalName for $fieldName")
|
throw AssertionError("Couldn't find captured this $originalLambdaInternalName for $fieldName")
|
||||||
|
|||||||
@@ -169,7 +169,7 @@ class ReifiedTypeInliner(private val parametersMapping: TypeParameterMappings?)
|
|||||||
) = rewriteNextTypeInsn(insn, Opcodes.CHECKCAST) { stubCheckcast: AbstractInsnNode ->
|
) = rewriteNextTypeInsn(insn, Opcodes.CHECKCAST) { stubCheckcast: AbstractInsnNode ->
|
||||||
if (stubCheckcast !is TypeInsnNode) return false
|
if (stubCheckcast !is TypeInsnNode) return false
|
||||||
|
|
||||||
val newMethodNode = MethodNode(InlineCodegenUtil.API)
|
val newMethodNode = MethodNode(API)
|
||||||
generateAsCast(InstructionAdapter(newMethodNode), kotlinType, asmType, safe)
|
generateAsCast(InstructionAdapter(newMethodNode), kotlinType, asmType, safe)
|
||||||
|
|
||||||
instructions.insert(insn, newMethodNode.instructions)
|
instructions.insert(insn, newMethodNode.instructions)
|
||||||
@@ -189,7 +189,7 @@ class ReifiedTypeInliner(private val parametersMapping: TypeParameterMappings?)
|
|||||||
) = rewriteNextTypeInsn(insn, Opcodes.INSTANCEOF) { stubInstanceOf: AbstractInsnNode ->
|
) = rewriteNextTypeInsn(insn, Opcodes.INSTANCEOF) { stubInstanceOf: AbstractInsnNode ->
|
||||||
if (stubInstanceOf !is TypeInsnNode) return false
|
if (stubInstanceOf !is TypeInsnNode) return false
|
||||||
|
|
||||||
val newMethodNode = MethodNode(InlineCodegenUtil.API)
|
val newMethodNode = MethodNode(API)
|
||||||
generateIsCheck(InstructionAdapter(newMethodNode), kotlinType, asmType)
|
generateIsCheck(InstructionAdapter(newMethodNode), kotlinType, asmType)
|
||||||
|
|
||||||
instructions.insert(insn, newMethodNode.instructions)
|
instructions.insert(insn, newMethodNode.instructions)
|
||||||
@@ -231,14 +231,14 @@ class ReifiedTypeInliner(private val parametersMapping: TypeParameterMappings?)
|
|||||||
if (next3 is MethodInsnNode && next3.name == "valueOf") {
|
if (next3 is MethodInsnNode && next3.name == "valueOf") {
|
||||||
instructions.remove(next1)
|
instructions.remove(next1)
|
||||||
next3.owner = parameter.internalName
|
next3.owner = parameter.internalName
|
||||||
next3.desc = InlineCodegenUtil.getSpecialEnumFunDescriptor(parameter, true)
|
next3.desc = getSpecialEnumFunDescriptor(parameter, true)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (next1.opcode == Opcodes.ICONST_0 && next2.opcode == Opcodes.ANEWARRAY) {
|
else if (next1.opcode == Opcodes.ICONST_0 && next2.opcode == Opcodes.ANEWARRAY) {
|
||||||
instructions.remove(next1)
|
instructions.remove(next1)
|
||||||
instructions.remove(next2)
|
instructions.remove(next2)
|
||||||
val desc = InlineCodegenUtil.getSpecialEnumFunDescriptor(parameter, false)
|
val desc = getSpecialEnumFunDescriptor(parameter, false)
|
||||||
instructions.insert(insn, MethodInsnNode(Opcodes.INVOKESTATIC, parameter.internalName, "values", desc, false))
|
instructions.insert(insn, MethodInsnNode(Opcodes.INVOKESTATIC, parameter.internalName, "values", desc, false))
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,8 @@ import org.jetbrains.org.objectweb.asm.Opcodes;
|
|||||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter;
|
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter;
|
||||||
import org.jetbrains.org.objectweb.asm.tree.FieldInsnNode;
|
import org.jetbrains.org.objectweb.asm.tree.FieldInsnNode;
|
||||||
|
|
||||||
|
import static org.jetbrains.kotlin.codegen.inline.InlineCodegenUtilsKt.CAPTURED_FIELD_FOLD_PREFIX;
|
||||||
|
|
||||||
public class RemapVisitor extends MethodBodyVisitor {
|
public class RemapVisitor extends MethodBodyVisitor {
|
||||||
private final LocalVarRemapper remapper;
|
private final LocalVarRemapper remapper;
|
||||||
private final FieldRemapper nodeRemapper;
|
private final FieldRemapper nodeRemapper;
|
||||||
@@ -59,7 +61,7 @@ public class RemapVisitor extends MethodBodyVisitor {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitFieldInsn(int opcode, @NotNull String owner, @NotNull String name, @NotNull String desc) {
|
public void visitFieldInsn(int opcode, @NotNull String owner, @NotNull String name, @NotNull String desc) {
|
||||||
if (name.startsWith(InlineCodegenUtil.CAPTURED_FIELD_FOLD_PREFIX) &&
|
if (name.startsWith(CAPTURED_FIELD_FOLD_PREFIX) &&
|
||||||
(nodeRemapper instanceof RegeneratedLambdaFieldRemapper || nodeRemapper.isRoot())) {
|
(nodeRemapper instanceof RegeneratedLambdaFieldRemapper || nodeRemapper.isRoot())) {
|
||||||
FieldInsnNode fin = new FieldInsnNode(opcode, owner, name, desc);
|
FieldInsnNode fin = new FieldInsnNode(opcode, owner, name, desc);
|
||||||
StackValue inline = nodeRemapper.getFieldForInline(fin, null);
|
StackValue inline = nodeRemapper.getFieldForInline(fin, null);
|
||||||
|
|||||||
@@ -16,7 +16,6 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.codegen.inline
|
package org.jetbrains.kotlin.codegen.inline
|
||||||
|
|
||||||
import org.jetbrains.kotlin.codegen.inline.InlineCodegenUtil.firstLabelInChain
|
|
||||||
import org.jetbrains.org.objectweb.asm.tree.LabelNode
|
import org.jetbrains.org.objectweb.asm.tree.LabelNode
|
||||||
import org.jetbrains.org.objectweb.asm.tree.TryCatchBlockNode
|
import org.jetbrains.org.objectweb.asm.tree.TryCatchBlockNode
|
||||||
|
|
||||||
|
|||||||
@@ -18,8 +18,6 @@ package org.jetbrains.kotlin.codegen.inline
|
|||||||
|
|
||||||
import org.jetbrains.kotlin.codegen.AsmUtil
|
import org.jetbrains.kotlin.codegen.AsmUtil
|
||||||
import org.jetbrains.kotlin.codegen.OwnerKind
|
import org.jetbrains.kotlin.codegen.OwnerKind
|
||||||
import org.jetbrains.kotlin.codegen.inline.InlineCodegenUtil.DEFAULT_LAMBDA_FAKE_CALL
|
|
||||||
import org.jetbrains.kotlin.codegen.inline.InlineCodegenUtil.getConstant
|
|
||||||
import org.jetbrains.kotlin.codegen.inline.ReifiedTypeInliner.Companion.isNeedClassReificationMarker
|
import org.jetbrains.kotlin.codegen.inline.ReifiedTypeInliner.Companion.isNeedClassReificationMarker
|
||||||
import org.jetbrains.kotlin.codegen.optimization.common.InsnSequence
|
import org.jetbrains.kotlin.codegen.optimization.common.InsnSequence
|
||||||
import org.jetbrains.kotlin.codegen.optimization.common.asSequence
|
import org.jetbrains.kotlin.codegen.optimization.common.asSequence
|
||||||
|
|||||||
+4
-3
@@ -17,7 +17,8 @@
|
|||||||
package org.jetbrains.kotlin.codegen.optimization.boxing
|
package org.jetbrains.kotlin.codegen.optimization.boxing
|
||||||
|
|
||||||
import com.intellij.openapi.util.Pair
|
import com.intellij.openapi.util.Pair
|
||||||
import org.jetbrains.kotlin.codegen.inline.InlineCodegenUtil
|
import org.jetbrains.kotlin.codegen.inline.getInsnOpcodeText
|
||||||
|
import org.jetbrains.kotlin.codegen.inline.getInsnText
|
||||||
import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicMethods
|
import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicMethods
|
||||||
import org.jetbrains.kotlin.codegen.optimization.common.StrictBasicValue
|
import org.jetbrains.kotlin.codegen.optimization.common.StrictBasicValue
|
||||||
import org.jetbrains.kotlin.codegen.optimization.common.*
|
import org.jetbrains.kotlin.codegen.optimization.common.*
|
||||||
@@ -324,7 +325,7 @@ class RedundantBoxingMethodTransformer : MethodTransformer() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun throwCannotAdaptInstruction(insn: AbstractInsnNode): Nothing =
|
private fun throwCannotAdaptInstruction(insn: AbstractInsnNode): Nothing =
|
||||||
throw AssertionError("Cannot adapt instruction: ${InlineCodegenUtil.getInsnText(insn)}")
|
throw AssertionError("Cannot adapt instruction: ${getInsnText(insn)}")
|
||||||
|
|
||||||
private fun adaptAreEqualIntrinsic(
|
private fun adaptAreEqualIntrinsic(
|
||||||
node: MethodNode,
|
node: MethodNode,
|
||||||
@@ -392,7 +393,7 @@ class RedundantBoxingMethodTransformer : MethodTransformer() {
|
|||||||
next.getOpcode() == Opcodes.IFNE ->
|
next.getOpcode() == Opcodes.IFNE ->
|
||||||
insertBefore(insn, JumpInsnNode(ifNotEqualOpcode, nextLabel))
|
insertBefore(insn, JumpInsnNode(ifNotEqualOpcode, nextLabel))
|
||||||
else ->
|
else ->
|
||||||
throw AssertionError("IFEQ or IFNE expected: " + InlineCodegenUtil.getInsnOpcodeText(next))
|
throw AssertionError("IFEQ or IFNE expected: " + getInsnOpcodeText(next))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-3
@@ -46,7 +46,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.codegen.optimization.common
|
package org.jetbrains.kotlin.codegen.optimization.common
|
||||||
|
|
||||||
import org.jetbrains.kotlin.codegen.inline.InlineCodegenUtil
|
import org.jetbrains.kotlin.codegen.inline.getInsnText
|
||||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||||
import org.jetbrains.org.objectweb.asm.Type
|
import org.jetbrains.org.objectweb.asm.Type
|
||||||
import org.jetbrains.org.objectweb.asm.tree.*
|
import org.jetbrains.org.objectweb.asm.tree.*
|
||||||
@@ -146,10 +146,10 @@ open class MethodAnalyzer<V : Value>(
|
|||||||
|
|
||||||
}
|
}
|
||||||
catch (e: AnalyzerException) {
|
catch (e: AnalyzerException) {
|
||||||
throw AnalyzerException(e.node, "Error at instruction #" + insn + " ${InlineCodegenUtil.getInsnText(insnNode)}: " + e.message, e)
|
throw AnalyzerException(e.node, "Error at instruction #" + insn + " ${getInsnText(insnNode)}: " + e.message, e)
|
||||||
}
|
}
|
||||||
catch (e: Exception) {
|
catch (e: Exception) {
|
||||||
throw AnalyzerException(insnNode, "Error at instruction #" + insn + " ${InlineCodegenUtil.getInsnText(insnNode)}: " + e.message, e)
|
throw AnalyzerException(insnNode, "Error at instruction #" + insn + " ${getInsnText(insnNode)}: " + e.message, e)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-4
@@ -19,7 +19,6 @@ package org.jetbrains.kotlin.codegen.optimization.common;
|
|||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.kotlin.codegen.AsmUtil;
|
import org.jetbrains.kotlin.codegen.AsmUtil;
|
||||||
import org.jetbrains.kotlin.codegen.inline.InlineCodegenUtil;
|
|
||||||
import org.jetbrains.org.objectweb.asm.Handle;
|
import org.jetbrains.org.objectweb.asm.Handle;
|
||||||
import org.jetbrains.org.objectweb.asm.Opcodes;
|
import org.jetbrains.org.objectweb.asm.Opcodes;
|
||||||
import org.jetbrains.org.objectweb.asm.Type;
|
import org.jetbrains.org.objectweb.asm.Type;
|
||||||
@@ -30,6 +29,7 @@ import org.jetbrains.org.objectweb.asm.tree.analysis.Interpreter;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.jetbrains.kotlin.codegen.inline.InlineCodegenUtilsKt.getInsnOpcodeText;
|
||||||
import static org.jetbrains.kotlin.codegen.optimization.common.StrictBasicValue.*;
|
import static org.jetbrains.kotlin.codegen.optimization.common.StrictBasicValue.*;
|
||||||
|
|
||||||
public class OptimizationBasicInterpreter extends Interpreter<BasicValue> implements Opcodes {
|
public class OptimizationBasicInterpreter extends Interpreter<BasicValue> implements Opcodes {
|
||||||
@@ -137,7 +137,7 @@ public class OptimizationBasicInterpreter extends Interpreter<BasicValue> implem
|
|||||||
case NEW:
|
case NEW:
|
||||||
return newValue(Type.getObjectType(((TypeInsnNode) insn).desc));
|
return newValue(Type.getObjectType(((TypeInsnNode) insn).desc));
|
||||||
default:
|
default:
|
||||||
throw new IllegalArgumentException("Unexpected instruction: " + InlineCodegenUtil.getInsnOpcodeText(insn));
|
throw new IllegalArgumentException("Unexpected instruction: " + getInsnOpcodeText(insn));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -222,7 +222,7 @@ public class OptimizationBasicInterpreter extends Interpreter<BasicValue> implem
|
|||||||
case PUTFIELD:
|
case PUTFIELD:
|
||||||
return null;
|
return null;
|
||||||
default:
|
default:
|
||||||
throw new IllegalArgumentException("Unexpected instruction: " + InlineCodegenUtil.getInsnOpcodeText(insn));
|
throw new IllegalArgumentException("Unexpected instruction: " + getInsnOpcodeText(insn));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -341,7 +341,7 @@ public class OptimizationBasicInterpreter extends Interpreter<BasicValue> implem
|
|||||||
case IFNONNULL:
|
case IFNONNULL:
|
||||||
return null;
|
return null;
|
||||||
default:
|
default:
|
||||||
throw new IllegalArgumentException("Unexpected instruction: " + InlineCodegenUtil.getInsnOpcodeText(insn));
|
throw new IllegalArgumentException("Unexpected instruction: " + getInsnOpcodeText(insn));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.codegen.optimization.common
|
package org.jetbrains.kotlin.codegen.optimization.common
|
||||||
|
|
||||||
import org.jetbrains.kotlin.codegen.inline.InlineCodegenUtil
|
import org.jetbrains.kotlin.codegen.inline.getInsnText
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||||
import org.jetbrains.org.objectweb.asm.Opcodes.*
|
import org.jetbrains.org.objectweb.asm.Opcodes.*
|
||||||
@@ -176,7 +176,7 @@ fun insnListOf(vararg insns: AbstractInsnNode) = InsnList().apply { insns.forEac
|
|||||||
fun AbstractInsnNode.isStoreOperation(): Boolean = opcode in Opcodes.ISTORE..Opcodes.ASTORE
|
fun AbstractInsnNode.isStoreOperation(): Boolean = opcode in Opcodes.ISTORE..Opcodes.ASTORE
|
||||||
fun AbstractInsnNode.isLoadOperation(): Boolean = opcode in Opcodes.ILOAD..Opcodes.ALOAD
|
fun AbstractInsnNode.isLoadOperation(): Boolean = opcode in Opcodes.ILOAD..Opcodes.ALOAD
|
||||||
|
|
||||||
val AbstractInsnNode?.insnText get() = InlineCodegenUtil.getInsnText(this)
|
val AbstractInsnNode?.insnText get() = getInsnText(this)
|
||||||
val AbstractInsnNode?.debugText get() =
|
val AbstractInsnNode?.debugText get() =
|
||||||
if (this == null) "<null>" else "${this::class.java.simpleName}: $insnText"
|
if (this == null) "<null>" else "${this::class.java.simpleName}: $insnText"
|
||||||
|
|
||||||
|
|||||||
+6
-4
@@ -17,7 +17,9 @@
|
|||||||
package org.jetbrains.kotlin.codegen.optimization.fixStack
|
package org.jetbrains.kotlin.codegen.optimization.fixStack
|
||||||
|
|
||||||
import com.intellij.util.containers.Stack
|
import com.intellij.util.containers.Stack
|
||||||
import org.jetbrains.kotlin.codegen.inline.InlineCodegenUtil
|
import org.jetbrains.kotlin.codegen.inline.isAfterInlineMarker
|
||||||
|
import org.jetbrains.kotlin.codegen.inline.isBeforeInlineMarker
|
||||||
|
import org.jetbrains.kotlin.codegen.inline.isMarkedReturn
|
||||||
import org.jetbrains.kotlin.codegen.optimization.common.MethodAnalyzer
|
import org.jetbrains.kotlin.codegen.optimization.common.MethodAnalyzer
|
||||||
import org.jetbrains.kotlin.codegen.optimization.common.OptimizationBasicInterpreter
|
import org.jetbrains.kotlin.codegen.optimization.common.OptimizationBasicInterpreter
|
||||||
import org.jetbrains.kotlin.codegen.pseudoInsns.PseudoInsn
|
import org.jetbrains.kotlin.codegen.pseudoInsns.PseudoInsn
|
||||||
@@ -103,11 +105,11 @@ internal class FixStackAnalyzer(
|
|||||||
executeSaveStackBeforeTry(insn)
|
executeSaveStackBeforeTry(insn)
|
||||||
PseudoInsn.RESTORE_STACK_IN_TRY_CATCH.isa(insn) ->
|
PseudoInsn.RESTORE_STACK_IN_TRY_CATCH.isa(insn) ->
|
||||||
executeRestoreStackInTryCatch(insn)
|
executeRestoreStackInTryCatch(insn)
|
||||||
InlineCodegenUtil.isBeforeInlineMarker(insn) ->
|
isBeforeInlineMarker(insn) ->
|
||||||
executeBeforeInlineCallMarker(insn)
|
executeBeforeInlineCallMarker(insn)
|
||||||
InlineCodegenUtil.isAfterInlineMarker(insn) ->
|
isAfterInlineMarker(insn) ->
|
||||||
executeAfterInlineCallMarker(insn)
|
executeAfterInlineCallMarker(insn)
|
||||||
InlineCodegenUtil.isMarkedReturn(insn) -> {
|
isMarkedReturn(insn) -> {
|
||||||
// KT-9644: might throw "Incompatible return type" on non-local return, in fact we don't care.
|
// KT-9644: might throw "Incompatible return type" on non-local return, in fact we don't care.
|
||||||
if (insn.opcode == Opcodes.RETURN) return
|
if (insn.opcode == Opcodes.RETURN) return
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-3
@@ -18,7 +18,8 @@ package org.jetbrains.kotlin.codegen.optimization.fixStack
|
|||||||
|
|
||||||
import com.intellij.util.SmartList
|
import com.intellij.util.SmartList
|
||||||
import com.intellij.util.containers.Stack
|
import com.intellij.util.containers.Stack
|
||||||
import org.jetbrains.kotlin.codegen.inline.InlineCodegenUtil
|
import org.jetbrains.kotlin.codegen.inline.isAfterInlineMarker
|
||||||
|
import org.jetbrains.kotlin.codegen.inline.isBeforeInlineMarker
|
||||||
import org.jetbrains.kotlin.codegen.optimization.common.InsnSequence
|
import org.jetbrains.kotlin.codegen.optimization.common.InsnSequence
|
||||||
import org.jetbrains.kotlin.codegen.pseudoInsns.PseudoInsn
|
import org.jetbrains.kotlin.codegen.pseudoInsns.PseudoInsn
|
||||||
import org.jetbrains.kotlin.codegen.pseudoInsns.parsePseudoInsnOrNull
|
import org.jetbrains.kotlin.codegen.pseudoInsns.parsePseudoInsnOrNull
|
||||||
@@ -56,10 +57,10 @@ internal class FixStackContext(val methodNode: MethodNode) {
|
|||||||
visitFakeAlwaysTrueIfeq(insnNode)
|
visitFakeAlwaysTrueIfeq(insnNode)
|
||||||
pseudoInsn == PseudoInsn.FAKE_ALWAYS_FALSE_IFEQ ->
|
pseudoInsn == PseudoInsn.FAKE_ALWAYS_FALSE_IFEQ ->
|
||||||
visitFakeAlwaysFalseIfeq(insnNode)
|
visitFakeAlwaysFalseIfeq(insnNode)
|
||||||
InlineCodegenUtil.isBeforeInlineMarker(insnNode) -> {
|
isBeforeInlineMarker(insnNode) -> {
|
||||||
inlineMarkersStack.push(insnNode)
|
inlineMarkersStack.push(insnNode)
|
||||||
}
|
}
|
||||||
InlineCodegenUtil.isAfterInlineMarker(insnNode) -> {
|
isAfterInlineMarker(insnNode) -> {
|
||||||
assert(inlineMarkersStack.isNotEmpty()) { "Mismatching after inline method marker at ${indexOf(insnNode)}" }
|
assert(inlineMarkersStack.isNotEmpty()) { "Mismatching after inline method marker at ${indexOf(insnNode)}" }
|
||||||
openingInlineMethodMarker[insnNode] = inlineMarkersStack.pop()
|
openingInlineMethodMarker[insnNode] = inlineMarkersStack.pop()
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-4
@@ -16,7 +16,9 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.codegen.optimization.fixStack
|
package org.jetbrains.kotlin.codegen.optimization.fixStack
|
||||||
|
|
||||||
import org.jetbrains.kotlin.codegen.inline.InlineCodegenUtil
|
import org.jetbrains.kotlin.codegen.inline.isAfterInlineMarker
|
||||||
|
import org.jetbrains.kotlin.codegen.inline.isBeforeInlineMarker
|
||||||
|
import org.jetbrains.kotlin.codegen.inline.isInlineMarker
|
||||||
import org.jetbrains.kotlin.codegen.optimization.common.InsnSequence
|
import org.jetbrains.kotlin.codegen.optimization.common.InsnSequence
|
||||||
import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer
|
import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer
|
||||||
import org.jetbrains.kotlin.codegen.pseudoInsns.PseudoInsn
|
import org.jetbrains.kotlin.codegen.pseudoInsns.PseudoInsn
|
||||||
@@ -33,7 +35,7 @@ class FixStackMethodTransformer : MethodTransformer() {
|
|||||||
// If inline method markers are inconsistent, remove them now
|
// If inline method markers are inconsistent, remove them now
|
||||||
if (!context.consistentInlineMarkers) {
|
if (!context.consistentInlineMarkers) {
|
||||||
InsnSequence(methodNode.instructions).forEach { insnNode ->
|
InsnSequence(methodNode.instructions).forEach { insnNode ->
|
||||||
if (InlineCodegenUtil.isInlineMarker(insnNode))
|
if (isInlineMarker(insnNode))
|
||||||
methodNode.instructions.remove(insnNode)
|
methodNode.instructions.remove(insnNode)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -131,9 +133,9 @@ class FixStackMethodTransformer : MethodTransformer() {
|
|||||||
transformSaveStackMarker(methodNode, actions, analyzer, marker, localVariablesManager)
|
transformSaveStackMarker(methodNode, actions, analyzer, marker, localVariablesManager)
|
||||||
pseudoInsn == PseudoInsn.RESTORE_STACK_IN_TRY_CATCH ->
|
pseudoInsn == PseudoInsn.RESTORE_STACK_IN_TRY_CATCH ->
|
||||||
transformRestoreStackMarker(methodNode, actions, marker, localVariablesManager)
|
transformRestoreStackMarker(methodNode, actions, marker, localVariablesManager)
|
||||||
InlineCodegenUtil.isBeforeInlineMarker(marker) ->
|
isBeforeInlineMarker(marker) ->
|
||||||
transformBeforeInlineCallMarker(methodNode, actions, analyzer, marker, localVariablesManager)
|
transformBeforeInlineCallMarker(methodNode, actions, analyzer, marker, localVariablesManager)
|
||||||
InlineCodegenUtil.isAfterInlineMarker(marker) ->
|
isAfterInlineMarker(marker) ->
|
||||||
transformAfterInlineCallMarker(methodNode, actions, analyzer, marker, localVariablesManager)
|
transformAfterInlineCallMarker(methodNode, actions, analyzer, marker, localVariablesManager)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ package org.jetbrains.kotlin.codegen
|
|||||||
import com.intellij.openapi.util.io.FileUtil
|
import com.intellij.openapi.util.io.FileUtil
|
||||||
import com.intellij.openapi.util.text.StringUtil
|
import com.intellij.openapi.util.text.StringUtil
|
||||||
import org.jetbrains.kotlin.backend.common.output.OutputFile
|
import org.jetbrains.kotlin.backend.common.output.OutputFile
|
||||||
import org.jetbrains.kotlin.codegen.inline.InlineCodegenUtil
|
import org.jetbrains.kotlin.codegen.inline.GENERATE_SMAP
|
||||||
import org.jetbrains.kotlin.codegen.inline.RangeMapping
|
import org.jetbrains.kotlin.codegen.inline.RangeMapping
|
||||||
import org.jetbrains.kotlin.codegen.inline.SMAPParser
|
import org.jetbrains.kotlin.codegen.inline.SMAPParser
|
||||||
import org.jetbrains.kotlin.codegen.inline.toRange
|
import org.jetbrains.kotlin.codegen.inline.toRange
|
||||||
@@ -61,7 +61,7 @@ object SMAPTestUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun checkSMAP(inputFiles: List<CodegenTestCase.TestFile>, outputFiles: Iterable<OutputFile>) {
|
fun checkSMAP(inputFiles: List<CodegenTestCase.TestFile>, outputFiles: Iterable<OutputFile>) {
|
||||||
if (!InlineCodegenUtil.GENERATE_SMAP) return
|
if (!GENERATE_SMAP) return
|
||||||
|
|
||||||
val sourceData = inputFiles.mapNotNull { extractSmapFromTestDataFile(it) }
|
val sourceData = inputFiles.mapNotNull { extractSmapFromTestDataFile(it) }
|
||||||
val compiledSmaps = extractSMAPFromClasses(outputFiles)
|
val compiledSmaps = extractSMAPFromClasses(outputFiles)
|
||||||
|
|||||||
+2
-2
@@ -29,7 +29,7 @@ import org.jetbrains.kotlin.cli.js.K2JSCompiler
|
|||||||
import org.jetbrains.kotlin.cli.jvm.K2JVMCompiler
|
import org.jetbrains.kotlin.cli.jvm.K2JVMCompiler
|
||||||
import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles
|
import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles
|
||||||
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
|
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
|
||||||
import org.jetbrains.kotlin.codegen.inline.InlineCodegenUtil
|
import org.jetbrains.kotlin.codegen.inline.GENERATE_SMAP
|
||||||
import org.jetbrains.kotlin.config.KotlinCompilerVersion.TEST_IS_PRE_RELEASE_SYSTEM_PROPERTY
|
import org.jetbrains.kotlin.config.KotlinCompilerVersion.TEST_IS_PRE_RELEASE_SYSTEM_PROPERTY
|
||||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.PackageViewDescriptor
|
import org.jetbrains.kotlin.descriptors.PackageViewDescriptor
|
||||||
@@ -433,7 +433,7 @@ class CompileKotlinAgainstCustomBinariesTest : TestCaseWithTmpdir() {
|
|||||||
*E
|
*E
|
||||||
""".trimIndent() + "\n"
|
""".trimIndent() + "\n"
|
||||||
|
|
||||||
if (InlineCodegenUtil.GENERATE_SMAP) {
|
if (GENERATE_SMAP) {
|
||||||
assertEquals(expected, debugInfo)
|
assertEquals(expected, debugInfo)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|||||||
@@ -21,12 +21,12 @@ import com.intellij.debugger.jdi.LocalVariableProxyImpl
|
|||||||
import com.intellij.debugger.jdi.StackFrameProxyImpl
|
import com.intellij.debugger.jdi.StackFrameProxyImpl
|
||||||
import com.intellij.debugger.ui.impl.watch.MethodsTracker
|
import com.intellij.debugger.ui.impl.watch.MethodsTracker
|
||||||
import com.intellij.debugger.ui.impl.watch.StackFrameDescriptorImpl
|
import com.intellij.debugger.ui.impl.watch.StackFrameDescriptorImpl
|
||||||
import org.jetbrains.kotlin.codegen.inline.InlineCodegenUtil
|
import org.jetbrains.kotlin.codegen.inline.isFakeLocalVariableForInline
|
||||||
|
|
||||||
class KotlinStackFrame(frame: StackFrameProxyImpl) : JavaStackFrame(StackFrameDescriptorImpl(frame, MethodsTracker()), true) {
|
class KotlinStackFrame(frame: StackFrameProxyImpl) : JavaStackFrame(StackFrameDescriptorImpl(frame, MethodsTracker()), true) {
|
||||||
override fun getVisibleVariables(): List<LocalVariableProxyImpl>? {
|
override fun getVisibleVariables(): List<LocalVariableProxyImpl>? {
|
||||||
return super.getVisibleVariables().filter {
|
return super.getVisibleVariables().filter {
|
||||||
!InlineCodegenUtil.isFakeLocalVariableForInline(it.name())
|
!isFakeLocalVariableForInline(it.name())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -29,7 +29,7 @@ import com.intellij.util.containers.ConcurrentWeakFactoryMap
|
|||||||
import com.intellij.util.containers.ContainerUtil
|
import com.intellij.util.containers.ContainerUtil
|
||||||
import com.sun.jdi.Location
|
import com.sun.jdi.Location
|
||||||
import com.sun.jdi.ReferenceType
|
import com.sun.jdi.ReferenceType
|
||||||
import org.jetbrains.kotlin.codegen.inline.InlineCodegenUtil
|
import org.jetbrains.kotlin.codegen.inline.API
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||||
import org.jetbrains.kotlin.idea.debugger.evaluate.KotlinDebuggerCaches
|
import org.jetbrains.kotlin.idea.debugger.evaluate.KotlinDebuggerCaches
|
||||||
import org.jetbrains.kotlin.idea.refactoring.getLineCount
|
import org.jetbrains.kotlin.idea.refactoring.getLineCount
|
||||||
@@ -199,7 +199,7 @@ private fun findClassFileByPath(packageName: String, className: String, outputDi
|
|||||||
private fun readLineNumberTableMapping(bytes: ByteArray): Map<BytecodeMethodKey, Map<String, Set<Int>>> {
|
private fun readLineNumberTableMapping(bytes: ByteArray): Map<BytecodeMethodKey, Map<String, Set<Int>>> {
|
||||||
val lineNumberMapping = HashMap<BytecodeMethodKey, Map<String, Set<Int>>>()
|
val lineNumberMapping = HashMap<BytecodeMethodKey, Map<String, Set<Int>>>()
|
||||||
|
|
||||||
ClassReader(bytes).accept(object : ClassVisitor(InlineCodegenUtil.API) {
|
ClassReader(bytes).accept(object : ClassVisitor(API) {
|
||||||
override fun visitMethod(access: Int, name: String?, desc: String?, signature: String?, exceptions: Array<out String>?): MethodVisitor? {
|
override fun visitMethod(access: Int, name: String?, desc: String?, signature: String?, exceptions: Array<out String>?): MethodVisitor? {
|
||||||
if (name == null || desc == null) {
|
if (name == null || desc == null) {
|
||||||
return null
|
return null
|
||||||
|
|||||||
@@ -26,7 +26,8 @@ import org.jetbrains.eval4j.jdi.asJdiValue
|
|||||||
import org.jetbrains.eval4j.jdi.asValue
|
import org.jetbrains.eval4j.jdi.asValue
|
||||||
import org.jetbrains.eval4j.obj
|
import org.jetbrains.eval4j.obj
|
||||||
import org.jetbrains.kotlin.codegen.AsmUtil
|
import org.jetbrains.kotlin.codegen.AsmUtil
|
||||||
import org.jetbrains.kotlin.codegen.inline.InlineCodegenUtil
|
import org.jetbrains.kotlin.codegen.inline.INLINE_FUN_VAR_SUFFIX
|
||||||
|
import org.jetbrains.kotlin.codegen.inline.NUMBERED_FUNCTION_PREFIX
|
||||||
import org.jetbrains.kotlin.idea.debugger.isInsideInlineFunctionBody
|
import org.jetbrains.kotlin.idea.debugger.isInsideInlineFunctionBody
|
||||||
import org.jetbrains.kotlin.idea.debugger.numberOfInlinedFunctions
|
import org.jetbrains.kotlin.idea.debugger.numberOfInlinedFunctions
|
||||||
import org.jetbrains.kotlin.idea.util.application.runReadAction
|
import org.jetbrains.kotlin.idea.util.application.runReadAction
|
||||||
@@ -128,12 +129,12 @@ class FrameVisitor(context: EvaluationContextImpl) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun findLocalVariableForInlineArgument(name: String, number: Int, asmType: Type?, checkType: Boolean): Value? {
|
private fun findLocalVariableForInlineArgument(name: String, number: Int, asmType: Type?, checkType: Boolean): Value? {
|
||||||
return findLocalVariable(name + InlineCodegenUtil.INLINE_FUN_VAR_SUFFIX.repeat(number), asmType, checkType)
|
return findLocalVariable(name + INLINE_FUN_VAR_SUFFIX.repeat(number), asmType, checkType)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun isFunctionType(type: Type?): Boolean {
|
private fun isFunctionType(type: Type?): Boolean {
|
||||||
return type?.sort == Type.OBJECT &&
|
return type?.sort == Type.OBJECT &&
|
||||||
type.internalName.startsWith(InlineCodegenUtil.NUMBERED_FUNCTION_PREFIX)
|
type.internalName.startsWith(NUMBERED_FUNCTION_PREFIX)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun findLocalVariable(name: String, asmType: Type?, checkType: Boolean): Value? {
|
private fun findLocalVariable(name: String, asmType: Type?, checkType: Boolean): Value? {
|
||||||
|
|||||||
@@ -18,8 +18,8 @@ package org.jetbrains.kotlin.idea.debugger
|
|||||||
|
|
||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
import com.intellij.psi.search.GlobalSearchScope
|
import com.intellij.psi.search.GlobalSearchScope
|
||||||
|
import org.jetbrains.kotlin.codegen.inline.API
|
||||||
import org.jetbrains.kotlin.codegen.inline.FileMapping
|
import org.jetbrains.kotlin.codegen.inline.FileMapping
|
||||||
import org.jetbrains.kotlin.codegen.inline.InlineCodegenUtil
|
|
||||||
import org.jetbrains.kotlin.codegen.inline.SMAP
|
import org.jetbrains.kotlin.codegen.inline.SMAP
|
||||||
import org.jetbrains.kotlin.codegen.inline.SMAPParser
|
import org.jetbrains.kotlin.codegen.inline.SMAPParser
|
||||||
import org.jetbrains.kotlin.psi.KtFile
|
import org.jetbrains.kotlin.psi.KtFile
|
||||||
@@ -62,7 +62,7 @@ fun mapStacktraceLineToSource(smapData: SmapData,
|
|||||||
fun readDebugInfo(bytes: ByteArray): SmapData? {
|
fun readDebugInfo(bytes: ByteArray): SmapData? {
|
||||||
val cr = ClassReader(bytes)
|
val cr = ClassReader(bytes)
|
||||||
var debugInfo: String? = null
|
var debugInfo: String? = null
|
||||||
cr.accept(object : ClassVisitor(InlineCodegenUtil.API) {
|
cr.accept(object : ClassVisitor(API) {
|
||||||
override fun visitSource(source: String?, debug: String?) {
|
override fun visitSource(source: String?, debug: String?) {
|
||||||
debugInfo = debug
|
debugInfo = debug
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user