diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ClassBodyCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ClassBodyCodegen.java index be75149b092..fccd8638cab 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ClassBodyCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ClassBodyCodegen.java @@ -42,7 +42,6 @@ public abstract class ClassBodyCodegen extends MemberCodegen { protected final OwnerKind kind; protected final ClassDescriptor descriptor; protected final ClassBuilder v; - protected final ClassContext context; private MethodVisitor clInitMethod; @@ -55,10 +54,9 @@ public abstract class ClassBodyCodegen extends MemberCodegen { @NotNull GenerationState state, @Nullable MemberCodegen parentCodegen ) { - super(state, parentCodegen); + super(state, parentCodegen, context, v); descriptor = state.getBindingContext().get(BindingContext.CLASS, aClass); myClass = aClass; - this.context = context; this.kind = context.getContextKind(); this.v = v; } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java index 136d2209e74..159bb128f3a 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java @@ -28,12 +28,15 @@ import org.jetbrains.asm4.commons.Method; import org.jetbrains.jet.codegen.binding.CalculatedClosure; import org.jetbrains.jet.codegen.context.CodegenContext; import org.jetbrains.jet.codegen.context.LocalLookup; +import org.jetbrains.jet.codegen.context.MethodContext; import org.jetbrains.jet.codegen.signature.BothSignatureWriter; import org.jetbrains.jet.codegen.signature.JvmMethodSignature; import org.jetbrains.jet.codegen.state.GenerationState; import org.jetbrains.jet.codegen.state.JetTypeMapper; import org.jetbrains.jet.lang.descriptors.*; +import org.jetbrains.jet.lang.psi.JetDeclarationWithBody; import org.jetbrains.jet.lang.resolve.BindingContext; +import org.jetbrains.jet.lang.resolve.java.AsmTypeConstants; import org.jetbrains.jet.lang.resolve.java.JvmAbi; import org.jetbrains.jet.lang.resolve.java.sam.SingleAbstractMethodUtils; import org.jetbrains.jet.lang.resolve.name.Name; @@ -294,7 +297,7 @@ public class ClosureCodegen extends ParentCodegenAwareImpl { return signature; } - private static FunctionDescriptor getInvokeFunction(FunctionDescriptor funDescriptor) { + public static FunctionDescriptor getInvokeFunction(FunctionDescriptor funDescriptor) { int paramCount = funDescriptor.getValueParameters().size(); KotlinBuiltIns builtIns = KotlinBuiltIns.getInstance(); ClassDescriptor funClass = funDescriptor.getReceiverParameter() == null diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index 932cc931786..b4947f3f031 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -32,6 +32,8 @@ import org.jetbrains.asm4.MethodVisitor; import org.jetbrains.asm4.Type; import org.jetbrains.asm4.commons.InstructionAdapter; import org.jetbrains.asm4.commons.Method; +import org.jetbrains.jet.codegen.asm.InlineCodegen; +import org.jetbrains.jet.codegen.asm.Inliner; import org.jetbrains.jet.codegen.binding.CalculatedClosure; import org.jetbrains.jet.codegen.binding.CodegenBinding; import org.jetbrains.jet.codegen.binding.MutableClosure; @@ -1353,27 +1355,38 @@ public class ExpressionCodegen extends JetVisitor implem } protected void pushClosureOnStack(CalculatedClosure closure, boolean ignoreThisAndReceiver) { + pushClosureOnStack(closure, ignoreThisAndReceiver, Inliner.NOT_INLINE); + } + + public void pushClosureOnStack(CalculatedClosure closure, boolean ignoreThisAndReceiver, Inliner inliner) { if (closure != null) { if (!ignoreThisAndReceiver) { ClassDescriptor captureThis = closure.getCaptureThis(); if (captureThis != null) { - generateThisOrOuter(captureThis, false).put(OBJECT_TYPE, v); + StackValue thisOrOuter = generateThisOrOuter(captureThis, false); + thisOrOuter.put(OBJECT_TYPE, v); + inliner.putInLocal(OBJECT_TYPE, thisOrOuter); } JetType captureReceiver = closure.getCaptureReceiverType(); if (captureReceiver != null) { - v.load(context.isStatic() ? 0 : 1, typeMapper.mapType(captureReceiver)); + Type asmType = typeMapper.mapType(captureReceiver); + StackValue.Local capturedReceiver = StackValue.local(context.isStatic() ? 0 : 1, asmType); + capturedReceiver.put(asmType, v); + inliner.putInLocal(asmType, capturedReceiver); } } for (Map.Entry entry : closure.getCaptureVariables().entrySet()) { - //if (entry.getKey() instanceof VariableDescriptor && !(entry.getKey() instanceof PropertyDescriptor)) { Type sharedVarType = typeMapper.getSharedVarType(entry.getKey()); if (sharedVarType == null) { sharedVarType = typeMapper.mapType((VariableDescriptor) entry.getKey()); } - entry.getValue().getOuterValue(this).put(sharedVarType, v); - //} + StackValue capturedVar = entry.getValue().getOuterValue(this); + if (inliner.shouldPutValue(sharedVarType, capturedVar, context)) { + capturedVar.put(sharedVarType, v); + } + inliner.putInLocal(sharedVarType, capturedVar); } } } @@ -1971,7 +1984,7 @@ public class ExpressionCodegen extends JetVisitor implem @NotNull public StackValue invokeFunction( - Call call, + @NotNull Call call, StackValue receiver, ResolvedCall resolvedCall ) { @@ -2095,20 +2108,31 @@ public class ExpressionCodegen extends JetVisitor implem @NotNull ResolvedCall resolvedCall, @NotNull StackValue receiver ) { + boolean disable = false; + CallableDescriptor descriptor = resolvedCall.getResultingDescriptor(); + boolean isInline = descriptor instanceof SimpleFunctionDescriptor && ((SimpleFunctionDescriptor) descriptor).isInline(); + Inliner inliner = !isInline ? Inliner.NOT_INLINE + : new InlineCodegen(this, true, state, disable, (SimpleFunctionDescriptor) unwrapFakeOverride((CallableMemberDescriptor)descriptor.getOriginal())); + if (resolvedCall instanceof VariableAsFunctionResolvedCall) { resolvedCall = ((VariableAsFunctionResolvedCall) resolvedCall).getFunctionCall(); } - if (!(resolvedCall.getResultingDescriptor() instanceof ConstructorDescriptor)) { // otherwise already + if (!(descriptor instanceof ConstructorDescriptor)) { // otherwise already receiver = StackValue.receiver(resolvedCall, receiver, this, callableMethod); receiver.put(receiver.type, v); } - pushArgumentsAndInvoke(resolvedCall, callableMethod); + assert inliner == Inliner.NOT_INLINE || !hasDefaults(resolvedCall) && !tailRecursionCodegen.isTailRecursion(resolvedCall) : + "Method with defaults or tail recursive couldn't be inlined " + descriptor; + + pushArgumentsAndInvoke(resolvedCall, callableMethod, inliner); } - private void pushArgumentsAndInvoke(@NotNull ResolvedCall resolvedCall, @NotNull CallableMethod callable) { - int mask = pushMethodArguments(resolvedCall, callable.getValueParameterTypes()); + private void pushArgumentsAndInvoke(@NotNull ResolvedCall resolvedCall, @NotNull CallableMethod callable, @NotNull Inliner inliner) { + inliner.putHiddenParams(); + + int mask = pushMethodArguments(resolvedCall, callable.getValueParameterTypes(), inliner); if (tailRecursionCodegen.isTailRecursion(resolvedCall)) { tailRecursionCodegen.generateTailRecursion(resolvedCall); @@ -2116,11 +2140,17 @@ public class ExpressionCodegen extends JetVisitor implem } if (mask == 0) { - callable.invokeWithNotNullAssertion(v, state, resolvedCall); + if (inliner != Inliner.NOT_INLINE) { + inliner.inlineCall(callable, getParentCodegen().getBuilder().getVisitor()); + } else { + callable.invokeWithNotNullAssertion(v, state, resolvedCall); + } } else { callable.invokeDefaultWithNotNullAssertion(v, state, resolvedCall, mask); } + + inliner.leaveTemps(); } private void genThisAndReceiverFromResolvedCall( @@ -2283,10 +2313,18 @@ public class ExpressionCodegen extends JetVisitor implem } private int pushMethodArguments(@NotNull ResolvedCall resolvedCall, List valueParameterTypes) { - return pushMethodArguments(resolvedCall, valueParameterTypes, false); + return pushMethodArguments(resolvedCall, valueParameterTypes, null); } private int pushMethodArguments(@NotNull ResolvedCall resolvedCall, List valueParameterTypes, boolean skipLast) { + return pushMethodArguments(resolvedCall, valueParameterTypes, skipLast, null); + } + + private int pushMethodArguments(@NotNull ResolvedCall resolvedCall, List valueParameterTypes, Inliner inliner) { + return pushMethodArguments(resolvedCall, valueParameterTypes, false, inliner); + } + + private int pushMethodArguments(@NotNull ResolvedCall resolvedCall, List valueParameterTypes, boolean skipLast, Inliner inliner) { @SuppressWarnings("unchecked") List valueArguments = resolvedCall.getValueArgumentsByIndex(); CallableDescriptor fd = resolvedCall.getResultingDescriptor(); @@ -2296,15 +2334,18 @@ public class ExpressionCodegen extends JetVisitor implem throw new IllegalStateException(); } + inliner = inliner != null ? inliner : Inliner.NOT_INLINE; int mask = 0; - for (Iterator iterator = valueParameters.iterator(); iterator.hasNext(); ) { ValueParameterDescriptor valueParameter = iterator.next(); if (skipLast && !iterator.hasNext()) { continue; } + boolean putInLocal = true; + StackValue valueIfPresent = null; + ResolvedValueArgument resolvedValueArgument = valueArguments.get(valueParameter.getIndex()); Type parameterType = valueParameterTypes.get(valueParameter.getIndex()); if (resolvedValueArgument instanceof ExpressionValueArgument) { @@ -2313,9 +2354,17 @@ public class ExpressionCodegen extends JetVisitor implem JetExpression argumentExpression = valueArgument.getArgumentExpression(); assert argumentExpression != null : valueArgument.asElement().getText(); - gen(argumentExpression, parameterType); - } - else if (resolvedValueArgument instanceof DefaultValueArgument) { + if (inliner.isInliningClosure(argumentExpression)) { + inliner.rememberClosure((JetFunctionLiteralExpression) argumentExpression, parameterType); + putInLocal = false; + } else { + StackValue value = gen(argumentExpression); + if (inliner.shouldPutValue(parameterType, value, context)) { + value.put(parameterType, v); + } + valueIfPresent = value; + } + } else if (resolvedValueArgument instanceof DefaultValueArgument) { pushDefaultValueOnStack(parameterType, v); mask |= (1 << valueParameter.getIndex()); } @@ -2326,10 +2375,29 @@ public class ExpressionCodegen extends JetVisitor implem else { throw new UnsupportedOperationException(); } + + if (putInLocal) { + inliner.putInLocal(parameterType, valueIfPresent); + } } return mask; } + private boolean hasDefaults(@NotNull ResolvedCall resolvedCall) { + @SuppressWarnings("unchecked") + List valueArguments = resolvedCall.getValueArgumentsByIndex(); + CallableDescriptor fd = resolvedCall.getResultingDescriptor(); + + for (ValueParameterDescriptor valueParameter : fd.getValueParameters()) { + StackValue valueIfPresent = null; + ResolvedValueArgument resolvedValueArgument = valueArguments.get(valueParameter.getIndex()); + if (resolvedValueArgument instanceof DefaultValueArgument) { + return true; + } + } + return false; + } + public void genVarargs(ValueParameterDescriptor valueParameterDescriptor, VarargValueArgument valueArgument) { JetType outType = valueParameterDescriptor.getType(); @@ -2576,7 +2644,7 @@ public class ExpressionCodegen extends JetVisitor implem @NotNull private ReceiverValue computeAndSaveReceiver( - @NotNull JvmMethodSignature signature, + @NotNull JvmMethodSignature signature, @NotNull ExpressionCodegen codegen, @Nullable ReceiverParameterDescriptor receiver ) { @@ -2951,7 +3019,7 @@ public class ExpressionCodegen extends JetVisitor implem receiver.put(receiver.type, v); } - pushArgumentsAndInvoke(resolvedCall, callable); + pushArgumentsAndInvoke(resolvedCall, callable, Inliner.NOT_INLINE); if (keepReturnValue) { value.store(callable.getReturnType(), v); @@ -3823,4 +3891,26 @@ The "returned" value of try expression with no finally is either the last expres } throw new IllegalStateException("Script codegen should be present in codegen tree"); } + + public InstructionAdapter getInstructionAdapter() { + return v; + } + + public JetTypeMapper getTypeMapper() { + return typeMapper; + } + + public MethodVisitor getMethodVisitor() { + return methodVisitor; + } + + @NotNull + public FrameMap getFrameMap() { + return myFrameMap; + } + + @NotNull + public MethodContext getContext() { + return context; + } } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/FrameMap.java b/compiler/backend/src/org/jetbrains/jet/codegen/FrameMap.java index 43c35297c1f..d0b07c08998 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/FrameMap.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/FrameMap.java @@ -70,6 +70,10 @@ public class FrameMap { return new Mark(myMaxIndex); } + public int getCurrentSize() { + return myMaxIndex; + } + public class Mark { private final int myIndex; diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java index b05019fac91..5e99154bfe6 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java @@ -130,7 +130,7 @@ public class FunctionCodegen extends ParentCodegenAwareImpl { mv, jvmSignature, functionDescriptor, - getThisTypeForFunction(functionDescriptor, methodContext), + getThisTypeForFunction(functionDescriptor, methodContext, state.getTypeMapper()), new Label(), new Label(), methodContext.getContextKind() @@ -138,7 +138,7 @@ public class FunctionCodegen extends ParentCodegenAwareImpl { return; } - generateMethodBody(mv, functionDescriptor, methodContext, jvmSignature, strategy); + generateMethodBody(mv, functionDescriptor, methodContext, jvmSignature, strategy, getParentCodegen()); endVisit(mv, null, origin); @@ -237,7 +237,7 @@ public class FunctionCodegen extends ParentCodegenAwareImpl { } @Nullable - private Type getThisTypeForFunction(@NotNull FunctionDescriptor functionDescriptor, @NotNull MethodContext context) { + private static Type getThisTypeForFunction(@NotNull FunctionDescriptor functionDescriptor, @NotNull MethodContext context, @NotNull JetTypeMapper typeMapper) { ReceiverParameterDescriptor expectedThisObject = functionDescriptor.getExpectedThisObject(); if (functionDescriptor instanceof ConstructorDescriptor) { return typeMapper.mapType(functionDescriptor); @@ -253,18 +253,22 @@ public class FunctionCodegen extends ParentCodegenAwareImpl { } } - private void generateMethodBody( + public static void generateMethodBody( @NotNull MethodVisitor mv, @NotNull FunctionDescriptor functionDescriptor, @NotNull MethodContext context, @NotNull JvmMethodSignature signature, - @NotNull FunctionGenerationStrategy strategy + @NotNull FunctionGenerationStrategy strategy, + @NotNull MemberCodegen parentCodegen ) { mv.visitCode(); Label methodBegin = new Label(); mv.visitLabel(methodBegin); + GenerationState state = parentCodegen.getState(); + JetTypeMapper typeMapper = state.getTypeMapper(); + if (context.getParentContext() instanceof PackageFacadeContext) { generateStaticDelegateMethodBody(mv, signature.getAsmMethod(), (PackageFacadeContext) context.getParentContext()); } @@ -283,15 +287,16 @@ public class FunctionCodegen extends ParentCodegenAwareImpl { genNotNullAssertionsForParameters(new InstructionAdapter(mv), state, functionDescriptor, frameMap); } - strategy.generateBody(mv, signature, context, getParentCodegen()); + strategy.generateBody(mv, signature, context, parentCodegen); } Label methodEnd = new Label(); mv.visitLabel(methodEnd); - - Type thisType = getThisTypeForFunction(functionDescriptor, context); - generateLocalVariableTable(mv, signature, functionDescriptor, thisType, methodBegin, methodEnd, context.getContextKind()); + if (strategy.generateLocalVarTable()) { + Type thisType = getThisTypeForFunction(functionDescriptor, context, typeMapper); + generateLocalVariableTable(mv, signature, functionDescriptor, thisType, methodBegin, methodEnd, context.getContextKind()); + } } private static void generateLocalVariableTable( diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/FunctionGenerationStrategy.java b/compiler/backend/src/org/jetbrains/jet/codegen/FunctionGenerationStrategy.java index 5e1a70079d9..0f70e6473ca 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/FunctionGenerationStrategy.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/FunctionGenerationStrategy.java @@ -50,6 +50,10 @@ public abstract class FunctionGenerationStrategy { return frameMap; } + public boolean generateLocalVarTable() { + return true; + } + public static class FunctionDefault extends CodegenBased { private final JetDeclarationWithBody declaration; diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/MemberCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/MemberCodegen.java index 12e6f0d3ebf..00a0f336cb0 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/MemberCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/MemberCodegen.java @@ -24,16 +24,34 @@ import org.jetbrains.jet.codegen.context.CodegenContext; import org.jetbrains.jet.codegen.context.FieldOwnerContext; import org.jetbrains.jet.codegen.state.GenerationState; import org.jetbrains.jet.lang.descriptors.ClassDescriptor; +import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.name.SpecialNames; import org.jetbrains.jet.lang.types.ErrorUtils; +import java.util.HashMap; +import java.util.Map; + public class MemberCodegen extends ParentCodegenAwareImpl { - public MemberCodegen(@NotNull GenerationState state, @Nullable MemberCodegen parentCodegen) { + protected final FieldOwnerContext context; + + private final ClassBuilder builder; + + @NotNull + private Map inlinedClosures = new HashMap(); + + public MemberCodegen( + @NotNull GenerationState state, + @Nullable MemberCodegen parentCodegen, + FieldOwnerContext context, + ClassBuilder builder + ) { super(state, parentCodegen); + this.context = context; + this.builder = builder; } public void genFunctionOrProperty( @@ -75,35 +93,45 @@ public class MemberCodegen extends ParentCodegenAwareImpl { } } - public void genClassOrObject(CodegenContext parentContext, JetClassOrObject aClass) { + public static void genClassOrObject( + @NotNull CodegenContext parentContext, + @NotNull JetClassOrObject aClass, + @NotNull GenerationState state, + @Nullable MemberCodegen parentCodegen + ) { ClassDescriptor descriptor = state.getBindingContext().get(BindingContext.CLASS, aClass); if (descriptor == null || ErrorUtils.isError(descriptor)) { - badDescriptor(descriptor); + badDescriptor(descriptor, state.getClassBuilderMode()); return; } if (descriptor.getName().equals(SpecialNames.NO_NAME_PROVIDED)) { - badDescriptor(descriptor); + badDescriptor(descriptor, state.getClassBuilderMode()); } ClassBuilder classBuilder = state.getFactory().forClassImplementation(descriptor, aClass.getContainingFile()); ClassContext classContext = parentContext.intoClass(descriptor, OwnerKind.IMPLEMENTATION, state); - new ImplementationBodyCodegen(aClass, classContext, classBuilder, state, this).generate(); + new ImplementationBodyCodegen(aClass, classContext, classBuilder, state, parentCodegen).generate(); classBuilder.done(); if (aClass instanceof JetClass && ((JetClass) aClass).isTrait()) { ClassBuilder traitBuilder = state.getFactory().forTraitImplementation(descriptor, state, aClass.getContainingFile()); - new TraitImplBodyCodegen(aClass, parentContext.intoClass(descriptor, OwnerKind.TRAIT_IMPL, state), traitBuilder, state, this) + new TraitImplBodyCodegen(aClass, parentContext.intoClass(descriptor, OwnerKind.TRAIT_IMPL, state), traitBuilder, state, parentCodegen) .generate(); traitBuilder.done(); } } - private void badDescriptor(ClassDescriptor descriptor) { - if (state.getClassBuilderMode() != ClassBuilderMode.LIGHT_CLASSES) { + private static void badDescriptor(ClassDescriptor descriptor, ClassBuilderMode mode) { + if (mode != ClassBuilderMode.LIGHT_CLASSES) { throw new IllegalStateException( - "Generating bad descriptor in ClassBuilderMode = " + state.getClassBuilderMode() + ": " + descriptor); + "Generating bad descriptor in ClassBuilderMode = " + mode + ": " + descriptor); } } + + @NotNull + public ClassBuilder getBuilder() { + return builder; + } } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/PackageCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/PackageCodegen.java index 659f5db0f1b..142d0a4e55a 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/PackageCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/PackageCodegen.java @@ -31,6 +31,7 @@ import org.jetbrains.asm4.Type; import org.jetbrains.jet.codegen.context.CodegenContext; import org.jetbrains.jet.codegen.context.FieldOwnerContext; import org.jetbrains.jet.codegen.state.GenerationState; +import org.jetbrains.jet.codegen.state.GenerationStateAware; import org.jetbrains.jet.descriptors.serialization.BitEncoding; import org.jetbrains.jet.descriptors.serialization.DescriptorSerializer; import org.jetbrains.jet.descriptors.serialization.PackageData; @@ -53,7 +54,8 @@ import static org.jetbrains.jet.codegen.AsmUtil.asmTypeByFqNameWithoutInnerClass import static org.jetbrains.jet.descriptors.serialization.NameSerializationUtil.createNameResolver; import static org.jetbrains.jet.lang.resolve.java.PackageClassUtils.getPackageClassFqName; -public class PackageCodegen extends MemberCodegen { +public class PackageCodegen extends GenerationStateAware { + @NotNull private final ClassBuilderOnDemand v; @NotNull @@ -69,7 +71,7 @@ public class PackageCodegen extends MemberCodegen { @NotNull GenerationState state, @NotNull Collection packageFiles ) { - super(state, null); + super(state); checkAllFilesHaveSamePackage(packageFiles); this.v = v; @@ -192,10 +194,10 @@ public class PackageCodegen extends MemberCodegen { new PackagePartCodegen(builder, file, packagePartType, packagePartContext, state).generate(); FieldOwnerContext packageFacade = CodegenContext.STATIC.intoPackageFacade(packagePartType, getPackageFragment(file)); - + MemberCodegen memberCodegen = new MemberCodegen(state, null, packageFacade, null); for (JetDeclaration declaration : file.getDeclarations()) { if (declaration instanceof JetNamedFunction || declaration instanceof JetProperty) { - genFunctionOrProperty(packageFacade, (JetTypeParameterListOwner) declaration, v.getClassBuilder()); + memberCodegen.genFunctionOrProperty(packageFacade, (JetTypeParameterListOwner) declaration, v.getClassBuilder()); } } @@ -211,7 +213,7 @@ public class PackageCodegen extends MemberCodegen { public void generateClassOrObject(@NotNull JetClassOrObject classOrObject) { CodegenContext context = CodegenContext.STATIC.intoPackagePart(getPackageFragment((JetFile) classOrObject.getContainingFile())); - genClassOrObject(context, classOrObject); + MemberCodegen.genClassOrObject(context, classOrObject, state, null); } /** diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/PackagePartCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/PackagePartCodegen.java index ec1c316a75c..795fd51b784 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/PackagePartCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/PackagePartCodegen.java @@ -59,7 +59,7 @@ public class PackagePartCodegen extends MemberCodegen { @NotNull FieldOwnerContext context, @NotNull GenerationState state ) { - super(state, null); + super(state, null, context, v); this.v = v; this.jetFile = jetFile; this.packagePartName = packagePartName; diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ScriptCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ScriptCodegen.java index c2088854173..47bf7ac338b 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ScriptCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ScriptCodegen.java @@ -53,8 +53,12 @@ public class ScriptCodegen extends MemberCodegen { ClassDescriptor classDescriptorForScript = state.getBindingContext().get(CLASS_FOR_SCRIPT, scriptDescriptor); assert classDescriptorForScript != null; + Type className = state.getBindingContext().get(ASM_TYPE, classDescriptorForScript); + assert className != null; + + ClassBuilder builder = state.getFactory().newVisitor(className, declaration.getContainingFile()); ScriptContext scriptContext = parentContext.intoScript(scriptDescriptor, classDescriptorForScript); - return new ScriptCodegen(declaration, state, scriptContext, state.getEarlierScriptsForReplInterpreter()); + return new ScriptCodegen(declaration, state, scriptContext, state.getEarlierScriptsForReplInterpreter(), builder); } @NotNull @@ -70,9 +74,10 @@ public class ScriptCodegen extends MemberCodegen { @NotNull JetScript scriptDeclaration, @NotNull GenerationState state, @NotNull ScriptContext context, - @Nullable List earlierScripts + @Nullable List earlierScripts, + @NotNull ClassBuilder builder ) { - super(state, null); + super(state, null, context, builder); this.scriptDeclaration = scriptDeclaration; this.context = context; this.earlierScripts = earlierScripts == null ? Collections.emptyList() : earlierScripts; @@ -84,8 +89,7 @@ public class ScriptCodegen extends MemberCodegen { Type classType = bindingContext.get(ASM_TYPE, classDescriptorForScript); assert classType != null; - ClassBuilder classBuilder = state.getFactory().newVisitor(classType, scriptDeclaration.getContainingFile()); - + ClassBuilder classBuilder = getBuilder(); classBuilder.defineClass(scriptDeclaration, V1_6, ACC_PUBLIC, diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/StackValue.java b/compiler/backend/src/org/jetbrains/jet/codegen/StackValue.java index 47423d1ca28..234b2a864fc 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/StackValue.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/StackValue.java @@ -387,6 +387,10 @@ public abstract class StackValue { coerceFrom(topOfStackType, v); v.store(index, this.type); } + + public int getIndex() { + return index; + } } public static class OnStack extends StackValue { diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/asm/ClosureInfo.java b/compiler/backend/src/org/jetbrains/jet/codegen/asm/ClosureInfo.java new file mode 100644 index 00000000000..069e48b0ac3 --- /dev/null +++ b/compiler/backend/src/org/jetbrains/jet/codegen/asm/ClosureInfo.java @@ -0,0 +1,141 @@ +/* + * Copyright 2010-2013 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.jet.codegen.asm; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.asm4.Type; +import org.jetbrains.asm4.tree.MethodNode; +import org.jetbrains.jet.codegen.AsmUtil; +import org.jetbrains.jet.codegen.binding.CalculatedClosure; +import org.jetbrains.jet.codegen.context.EnclosedValueDescriptor; +import org.jetbrains.jet.codegen.state.JetTypeMapper; +import org.jetbrains.jet.lang.descriptors.ClassDescriptor; +import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; +import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor; +import org.jetbrains.jet.lang.psi.JetFunctionLiteral; +import org.jetbrains.jet.lang.psi.JetFunctionLiteralExpression; +import org.jetbrains.jet.lang.resolve.BindingContext; +import org.jetbrains.jet.lang.resolve.java.JvmClassName; + +import java.util.*; + +import static org.jetbrains.jet.codegen.binding.CodegenBinding.CLOSURE; +import static org.jetbrains.jet.codegen.binding.CodegenBinding.anonymousClassForFunction; +import static org.jetbrains.jet.codegen.binding.CodegenBinding.asmTypeForAnonymousClass; + +public class ClosureInfo { + + public final JetFunctionLiteralExpression expression; + + @NotNull private final JetTypeMapper typeMapper; + + public final CalculatedClosure closure; + + private MethodNode node; + + private Collection capturedVars; + + private final FunctionDescriptor functionDescriptor; + + private final ClassDescriptor classDescriptor; + + private final Type closureClassType; + + private int paramOffset; + + ClosureInfo(@NotNull JetFunctionLiteralExpression expression, @NotNull JetTypeMapper typeMapper) { + this.expression = expression; + this.typeMapper = typeMapper; + BindingContext bindingContext = typeMapper.getBindingContext(); + functionDescriptor = bindingContext.get(BindingContext.FUNCTION, expression.getFunctionLiteral()); + assert functionDescriptor != null : "Function is not resolved to descriptor: " + expression.getText(); + + classDescriptor = anonymousClassForFunction(bindingContext, functionDescriptor); + closureClassType = asmTypeForAnonymousClass(bindingContext, functionDescriptor); + + closure = bindingContext.get(CLOSURE, classDescriptor); + + } + + public MethodNode getNode() { + return node; + } + + public void setNode(MethodNode node) { + this.node = node; + } + + public FunctionDescriptor getFunctionDescriptor() { + return functionDescriptor; + } + + public JetFunctionLiteral getFunctionLiteral() { + return expression.getFunctionLiteral(); + } + + public ClassDescriptor getClassDescriptor() { + return classDescriptor; + } + + public Type getClosureClassType() { + return closureClassType; + } + + public Collection getCapturedVars() { + //lazy initialization cause it would be calculated after object creation + if (capturedVars == null) { + capturedVars = new ArrayList(); + + if (closure.getCaptureThis() != null) { + EnclosedValueDescriptor descriptor = new EnclosedValueDescriptor(AsmUtil.CAPTURED_THIS_FIELD, null, null, typeMapper.mapType(closure.getCaptureThis())); + capturedVars.add(descriptor); + } + + if (closure.getCaptureReceiverType() != null) { + EnclosedValueDescriptor descriptor = new EnclosedValueDescriptor(AsmUtil.CAPTURED_RECEIVER_FIELD, null, null, typeMapper.mapType(closure.getCaptureReceiverType())); + capturedVars.add(descriptor); + } + + if (closure != null) { + capturedVars.addAll(closure.getCaptureVariables().values()); + } + } + return capturedVars; + } + + public int getParamOffset() { + return paramOffset; + } + + public void setParamOffset(int paramOffset) { + this.paramOffset = paramOffset; + } + + public List getParamsWithoutCapturedValOrVar() { + Type[] types = typeMapper.mapSignature(functionDescriptor).getAsmMethod().getArgumentTypes(); + return Arrays.asList(types); + } + + public int getCapturedVarsSize() { + int size = 0; + for (Iterator iterator = getCapturedVars().iterator(); iterator.hasNext(); ) { + EnclosedValueDescriptor next = iterator.next(); + size += next.getType().getSize(); + } + return size; + } +} diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/asm/ClosureUsage.java b/compiler/backend/src/org/jetbrains/jet/codegen/asm/ClosureUsage.java new file mode 100644 index 00000000000..d502c505418 --- /dev/null +++ b/compiler/backend/src/org/jetbrains/jet/codegen/asm/ClosureUsage.java @@ -0,0 +1,33 @@ +/* + * Copyright 2010-2013 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.jet.codegen.asm; + +class ClosureUsage { + + public final int index; + + public final boolean inlinable; + + ClosureUsage(int index, boolean isInlinable) { + this.index = index; + inlinable = isInlinable; + } + + public boolean isInlinable() { + return inlinable; + } +} diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/asm/InlineCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/asm/InlineCodegen.java new file mode 100644 index 00000000000..843c92904e3 --- /dev/null +++ b/compiler/backend/src/org/jetbrains/jet/codegen/asm/InlineCodegen.java @@ -0,0 +1,598 @@ +/* +* Copyright 2010-2013 JetBrains s.r.o. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +package org.jetbrains.jet.codegen.asm; + +import com.google.common.collect.Lists; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.PsiElement; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.asm4.*; +import org.jetbrains.asm4.commons.InstructionAdapter; +import org.jetbrains.asm4.commons.Method; +import org.jetbrains.asm4.tree.*; +import org.jetbrains.asm4.tree.analysis.*; +import org.jetbrains.asm4.tree.analysis.Frame; +import org.jetbrains.asm4.util.Textifier; +import org.jetbrains.asm4.util.TraceMethodVisitor; +import org.jetbrains.jet.codegen.*; +import org.jetbrains.jet.codegen.context.CodegenContext; +import org.jetbrains.jet.codegen.context.EnclosedValueDescriptor; +import org.jetbrains.jet.codegen.context.MethodContext; +import org.jetbrains.jet.codegen.signature.JvmMethodParameterKind; +import org.jetbrains.jet.codegen.signature.JvmMethodParameterSignature; +import org.jetbrains.jet.codegen.signature.JvmMethodSignature; +import org.jetbrains.jet.codegen.state.GenerationState; +import org.jetbrains.jet.codegen.state.JetTypeMapper; +import org.jetbrains.jet.descriptors.serialization.descriptors.DeserializedSimpleFunctionDescriptor; +import org.jetbrains.jet.lang.descriptors.*; +import org.jetbrains.jet.lang.psi.*; +import org.jetbrains.jet.lang.resolve.BindingContext; +import org.jetbrains.jet.lang.resolve.BindingContextUtils; +import org.jetbrains.jet.lang.resolve.java.AsmTypeConstants; +import org.jetbrains.jet.renderer.DescriptorRenderer; + +import java.io.IOException; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.*; + + +import static org.jetbrains.jet.codegen.AsmUtil.*; + +public class InlineCodegen implements ParentCodegenAware, Inliner { + + public final static String INVOKE = "invoke"; + + private final ExpressionCodegen codegen; + + private final boolean notSeparateInline; + + private final GenerationState state; + + private final boolean disabled; + + private final SimpleFunctionDescriptor functionDescriptor; + + private final List tempTypes = new ArrayList(); + + private final List closures = new ArrayList(); + + private final Map expressionMap = new HashMap(); + + private final JetTypeMapper typeMapper; + + private final BindingContext bindingContext; + + private final MethodContext context; + + private final FrameMap originalFunctionFrame; + + private final int initialFrameSize; + + private final JvmMethodSignature jvmSignature; + + public InlineCodegen( + @NotNull ExpressionCodegen codegen, + boolean notSeparateInline, + @NotNull GenerationState state, + boolean disabled, + @NotNull SimpleFunctionDescriptor functionDescriptor + ) { + this.codegen = codegen; + this.notSeparateInline = notSeparateInline; + this.state = state; + this.disabled = disabled; + this.functionDescriptor = functionDescriptor.getOriginal(); + typeMapper = codegen.getTypeMapper(); + bindingContext = codegen.getBindingContext(); + initialFrameSize = codegen.getFrameMap().getCurrentSize(); + + context = (MethodContext) getContext(functionDescriptor, state); + originalFunctionFrame = context.prepareFrame(typeMapper); + jvmSignature = typeMapper.mapSignature(functionDescriptor, context.getContextKind()); + } + + + @Override + public void inlineCall(CallableMethod callableMethod, ClassVisitor visitor) { + MethodNode node = null; + + try { + node = createMethodNode(callableMethod); + inlineCall(node, true); + } + catch (CompilationException e) { + throw e; + } + catch (Exception e) { + String text = getNodeText(node); + PsiElement element = BindingContextUtils.descriptorToDeclaration(bindingContext, codegen.getContext().getContextDescriptor()); + throw new CompilationException("Couldn't inline method call '" + + functionDescriptor.getName() + + "' into \n" + (element != null ? element.getText() : "null psi element " + codegen.getContext().getContextDescriptor()) + + "\ncause: " + + text, e, null); + } + } + + @NotNull + private MethodNode createMethodNode(CallableMethod callableMethod) + throws ClassNotFoundException, IOException { + MethodNode node = null; + if (functionDescriptor instanceof DeserializedSimpleFunctionDescriptor) { + VirtualFile file = InlineCodegenUtil.getVirtualFileForCallable((DeserializedSimpleFunctionDescriptor) functionDescriptor, state); + node = InlineCodegenUtil.getMethodNode(file.getInputStream(), functionDescriptor.getName().asString(), + callableMethod.getAsmMethod().getDescriptor()); + + if (node == null) { + throw new RuntimeException("Couldn't obtain compiled function body for " + descriptorName(functionDescriptor)); + } + } + else { + PsiElement element = BindingContextUtils.descriptorToDeclaration(bindingContext, functionDescriptor); + + if (element == null) { + throw new RuntimeException("Couldn't find declaration for function " + descriptorName(functionDescriptor)); + } + + JvmMethodSignature jvmSignature = typeMapper.mapSignature(functionDescriptor, context.getContextKind()); + Method asmMethod = jvmSignature.getAsmMethod(); + node = new MethodNode(Opcodes.ASM4, + getMethodAsmFlags(functionDescriptor, context.getContextKind()), + asmMethod.getName(), + asmMethod.getDescriptor(), + jvmSignature.getGenericsSignature(), + null); + + FunctionCodegen.generateMethodBody(node, functionDescriptor, context.getParentContext().intoFunction(functionDescriptor), + jvmSignature, + new FunctionGenerationStrategy.FunctionDefault(state, + functionDescriptor, + (JetDeclarationWithBody) element), + getParentCodegen()); + //TODO + node.visitMaxs(20, 20); + node.visitEnd(); + } + return node; + } + + private void inlineCall(MethodNode node, boolean inlineClosures) { + if (inlineClosures) { + removeClosureAssertions(node); + try { + markPlacesForInlineAndRemoveInlinable(node); + } + catch (AnalyzerException e) { + throw new RuntimeException(e); + } + } + + int valueParamSize = originalFunctionFrame.getCurrentSize(); + int originalSize = codegen.getFrameMap().getCurrentSize(); + generateClosuresBodies(); + putClosureParametersOnStack(); + int additionalParams = codegen.getFrameMap().getCurrentSize() - originalSize; + VarRemapper remapper = new VarRemapper.ParamRemapper(initialFrameSize, valueParamSize, additionalParams, tempTypes); + + doInline(node.access, node.desc, codegen.getMethodVisitor(), node, remapper.doRemap(valueParamSize + additionalParams), inlineClosures, remapper); + } + + private void removeClosureAssertions(MethodNode node) { + AbstractInsnNode cur = node.instructions.getFirst(); + while (cur != null && cur.getNext() != null) { + AbstractInsnNode next = cur.getNext(); + if (next.getType() == AbstractInsnNode.METHOD_INSN) { + MethodInsnNode methodInsnNode = (MethodInsnNode) next; + if (methodInsnNode.name.equals("checkParameterIsNotNull") && methodInsnNode.owner.equals("jet/runtime/Intrinsics")) { + AbstractInsnNode prev = cur.getPrevious(); + assert prev.getType() == AbstractInsnNode.VAR_INSN && prev.getOpcode() == Opcodes.ALOAD; + int varIndex = ((VarInsnNode) prev).var; + ClosureInfo closure = expressionMap.get(varIndex); + if (closure != null) { + node.instructions.remove(prev); + node.instructions.remove(cur); + cur = next.getNext(); + node.instructions.remove(next); + next = cur; + } + } + } + cur = next; + } + } + + private void markPlacesForInlineAndRemoveInlinable(@NotNull MethodNode node) throws AnalyzerException { + Analyzer analyzer = new Analyzer(new SourceInterpreter()); + Frame[] sources = analyzer.analyze("fake", node); + + AbstractInsnNode cur = node.instructions.getFirst(); + int index = 0; + while (cur != null) { + if (cur.getType() == AbstractInsnNode.METHOD_INSN) { + MethodInsnNode methodInsnNode = (MethodInsnNode) cur; + //TODO check closure + if (isInvokeOnInlinable(methodInsnNode.owner, methodInsnNode.name) /*&& methodInsnNode.owner.equals(INLINE_RUNTIME)*/) { + Frame frame = sources[index]; + SourceValue sourceValue = frame.getStack(frame.getStackSize() - Type.getArgumentTypes(methodInsnNode.desc).length - 1); + assert sourceValue.insns.size() == 1; + + AbstractInsnNode insnNode = sourceValue.insns.iterator().next(); + assert insnNode.getType() == AbstractInsnNode.VAR_INSN && insnNode.getOpcode() == Opcodes.ALOAD; + int varIndex = ((VarInsnNode) insnNode).var; + ClosureInfo closureInfo = expressionMap.get(varIndex); + if (closureInfo != null) { //TODO: maybe add separate map for noninlinable closures + closures.add(new ClosureUsage(varIndex, true)); + node.instructions.remove(insnNode); + } else { + closures.add(new ClosureUsage(varIndex, false)); + } + } + } + cur = cur.getNext(); + index++; + } + } + + private void doInline( + int access, + String desc, + MethodVisitor mv, + MethodNode methodNode, + int frameSize, + final boolean inlineClosures, + @NotNull VarRemapper remapper + ) { + + Label end = new Label(); + + final LinkedList infos = new LinkedList(closures); + methodNode.instructions.resetLabels(); + MethodVisitor methodVisitor = codegen.getMethodVisitor(); + + InliningAdapter inliner = new InliningAdapter(methodVisitor, Opcodes.ASM4, desc, end, frameSize, remapper) { + @Override + public void visitMethodInsn(int opcode, String owner, String name, String desc) { + if (inlineClosures && /*INLINE_RUNTIME.equals(owner) &&*/ isInvokeOnInlinable(owner, name)) { //TODO add method + assert !infos.isEmpty(); + ClosureUsage closureUsage = infos.remove(); + ClosureInfo info = expressionMap.get(closureUsage.index); + + if (!closureUsage.isInlinable()) { + //noninlinable closure + super.visitMethodInsn(opcode, owner, name, desc); + return; + } + + //TODO replace with codegen + int valueParamShift = getNextLocalIndex(); + remapper.setNestedRemap(true); + putStackValuesIntoLocals(info.getParamsWithoutCapturedValOrVar(), valueParamShift, this, desc); + Label closureEnd = new Label(); + InliningAdapter closureInliner = new InliningAdapter(mv, Opcodes.ASM4, desc, closureEnd, getNextLocalIndex(), + new VarRemapper.ClosureRemapper(info, valueParamShift, tempTypes)); + + info.getNode().instructions.resetLabels(); + info.getNode().accept(closureInliner); //TODO + + remapper.setNestedRemap(false); + mv.visitLabel(closureEnd); + + Method bridge = typeMapper.mapSignature(ClosureCodegen.getInvokeFunction(info.getFunctionDescriptor())).getAsmMethod(); + Method delegate = typeMapper.mapSignature(info.getFunctionDescriptor()).getAsmMethod(); + StackValue.onStack(delegate.getReturnType()).put(bridge.getReturnType(), closureInliner); + } + else { + super.visitMethodInsn(opcode, owner, name, desc); + } + } + }; + + methodNode.accept(inliner); + + methodVisitor.visitLabel(end); + } + + private boolean isInvokeOnInlinable(String owner, String name) { + return INVOKE.equals(name) && /*TODO: check type*/owner.contains("Function"); + } + + + private void generateClosuresBodies() { + for (ClosureInfo info : expressionMap.values()) { + info.setNode(generateClosureBody(info)); + } + } + + private MethodNode generateClosureBody(ClosureInfo info) { + JetFunctionLiteral declaration = info.getFunctionLiteral(); + FunctionDescriptor descriptor = info.getFunctionDescriptor(); + + MethodContext parentContext = codegen.getContext(); + + MethodContext context = parentContext.intoClosure(descriptor, codegen, typeMapper).intoFunction(descriptor); + + JvmMethodSignature jvmMethodSignature = typeMapper.mapSignature(descriptor); + Method asmMethod = jvmMethodSignature.getAsmMethod(); + MethodNode methodNode = new MethodNode(Opcodes.ASM4, getMethodAsmFlags(descriptor, context.getContextKind()), asmMethod.getName(), asmMethod.getDescriptor(), jvmMethodSignature.getGenericsSignature(), null); + + FunctionCodegen.generateMethodBody(methodNode, descriptor, context, jvmMethodSignature, new FunctionGenerationStrategy.FunctionDefault(state, descriptor, declaration) { + @Override + public boolean generateLocalVarTable() { + return false; + } + }, codegen.getParentCodegen()); + + return transformClosure(methodNode, info); + } + + @NotNull + private static MethodNode transformClosure(@NotNull MethodNode node, @NotNull ClosureInfo info) { + //remove all this and shift all variables to captured ones size + final int localVarSHift = info.getCapturedVarsSize(); + MethodNode transformedNode = new MethodNode(node.access, node.name, node.desc, node.signature, null) { + + private boolean remappingCaptured = false; + @Override + public void visitVarInsn(int opcode, int var) { + super.visitVarInsn(opcode, var + (remappingCaptured ? 0 : localVarSHift - 1/*remove this*/)); + } + }; + node.accept(transformedNode); + + + //remove all field access to local var + AbstractInsnNode cur = transformedNode.instructions.getFirst(); + while (cur != null) { + if (cur.getType() == AbstractInsnNode.FIELD_INSN) { + FieldInsnNode fieldInsnNode = (FieldInsnNode) cur; + //TODO check closure + String owner = fieldInsnNode.owner; + if (info.getClosureClassType().getInternalName().equals(fieldInsnNode.owner)) { + int opcode = fieldInsnNode.getOpcode(); + String name = fieldInsnNode.name; + String desc = fieldInsnNode.desc; + + Collection vars = info.getCapturedVars(); + int index = 0;//skip this + boolean found = false; + for (EnclosedValueDescriptor valueDescriptor : vars) { + Type type = valueDescriptor.getType(); + if (valueDescriptor.getFieldName().equals(name)) { + opcode = opcode == Opcodes.GETFIELD ? type.getOpcode(Opcodes.ILOAD) : type.getOpcode(Opcodes.ISTORE); + found = true; + break; + } + index += type.getSize(); + } + if (!found) { + throw new UnsupportedOperationException("Coudn't find field " + + owner + + "." + + name + + " (" + + desc + + ") in captured vars of " + + info.getFunctionLiteral().getText()); + } + + + VarInsnNode varInsNode = new VarInsnNode(opcode, index); + + AbstractInsnNode prev = cur.getPrevious(); + while (prev.getType() == AbstractInsnNode.LABEL || prev.getType() == AbstractInsnNode.LINE) { + prev = prev.getPrevious(); + } + + assert prev.getType() == AbstractInsnNode.VAR_INSN; + VarInsnNode loadThis = (VarInsnNode) prev; + assert /*loadThis.var == info.getCapturedVarsSize() - 1 && */loadThis.getOpcode() == Opcodes.ALOAD; + + transformedNode.instructions.remove(prev); + transformedNode.instructions.insertBefore(cur, varInsNode); + transformedNode.instructions.remove(cur); + cur = varInsNode; + + } + } + cur = cur.getNext(); + } + + return transformedNode; + } + + @Override + public void putInLocal(Type type, StackValue stackValue) { + if (!disabled && notSeparateInline && Type.VOID_TYPE != type) { + //TODO remap only inlinable closure => otherwise we could get a lot of problem + boolean couldBeRemapped = !shouldPutValue(type, stackValue, codegen.getContext()); + int remappedIndex = couldBeRemapped ? ((StackValue.Local) stackValue).getIndex() : -1; + + ParameterInfo info = new ParameterInfo(type, false, remappedIndex, couldBeRemapped ? -1 : codegen.getFrameMap().enterTemp(type)); + + doWithParameter(info); + } + } + + @Override + public boolean shouldPutValue(Type type, StackValue stackValue, MethodContext context) { + if (stackValue != null && context.isInlineFunction() && stackValue instanceof StackValue.Local) { + if (isInvokeOnInlinable(type.getClassName(), "invoke")) { + //TODO remap only inlinable closure => otherwise we could get a lot of problem + return false; //TODO check annotations + } + } + return true; + } + + private void doWithParameter(ParameterInfo info) { + recordParamInfo(info, true); + putParameterOnStack(info); + } + + private int recordParamInfo(ParameterInfo info, boolean addToFrame) { + Type type = info.type; + tempTypes.add(info); + if (info.getType().getSize() == 2) { + tempTypes.add(ParameterInfo.STUB); + } + if (addToFrame) { + return originalFunctionFrame.enterTemp(type); + } + return -1; + } + + private void putParameterOnStack(ParameterInfo info) { + if (!info.isSkippedOrRemapped()) { + int index = info.index; + Type type = info.type; + StackValue.local(index, type).store(type, codegen.getInstructionAdapter()); + } + } + + @Override + public void putHiddenParams() { + List types = jvmSignature.getValueParameters(); + + if (!isStaticMethod(functionDescriptor, context)) { + Type type = AsmTypeConstants.OBJECT_TYPE; + ParameterInfo info = new ParameterInfo(type, false, -1, codegen.getFrameMap().enterTemp(type)); + recordParamInfo(info, false); + } + + for (JvmMethodParameterSignature param : types) { + if (param.getKind() == JvmMethodParameterKind.VALUE) { + break; + } + Type type = param.getAsmType(); + ParameterInfo info = new ParameterInfo(type, false, -1, codegen.getFrameMap().enterTemp(type)); + recordParamInfo(info, false); + } + + for (ListIterator iterator = tempTypes.listIterator(tempTypes.size()); iterator.hasPrevious(); ) { + ParameterInfo param = iterator.previous(); + putParameterOnStack(param); + } + } + + @Override + public void leaveTemps() { + FrameMap frameMap = codegen.getFrameMap(); + for (ListIterator iterator = tempTypes.listIterator(tempTypes.size()); iterator.hasPrevious(); ) { + ParameterInfo param = iterator.previous(); + if (!param.isSkippedOrRemapped()) { + frameMap.leaveTemp(param.type); + } + } + } + + public boolean isDisabled() { + return disabled; + } + + private static void putStackValuesIntoLocals(List directOrder, int shift, InstructionAdapter mv, String descriptor) { + Type [] actualParams = Type.getArgumentTypes(descriptor); //last param is closure itself + assert actualParams.length == directOrder.size() : "Number of expected and actual params should be equals!"; + + int size = 0; + for (Type next : directOrder) { + size += next.getSize(); + } + + shift += size; + int index = directOrder.size(); + + for (Type next : Lists.reverse(directOrder)) { + shift -= next.getSize(); + Type typeOnStack = actualParams[--index]; + if (!typeOnStack.equals(next)) { + StackValue.onStack(typeOnStack).put(next, mv); + } + mv.visitVarInsn(next.getOpcode(Opcodes.ISTORE), shift); + } + } + + @Override + public boolean isInliningClosure(JetExpression expression) { + return !disabled && expression instanceof JetFunctionLiteralExpression; + } + + @Override + public void rememberClosure(JetFunctionLiteralExpression expression, Type type) { + ParameterInfo closureInfo = new ParameterInfo(type, true, -1, -1); + int index = recordParamInfo(closureInfo, true); + + ClosureInfo info = new ClosureInfo(expression, typeMapper); + expressionMap.put(index, info); + } + + private void putClosureParametersOnStack() { + //TODO: SORT + for (ClosureInfo next : expressionMap.values()) { + if (next.closure != null) { + int size = tempTypes.size(); + next.setParamOffset(size); + codegen.pushClosureOnStack(next.closure, false, this); + } + } + } + + @Nullable + @Override + public MemberCodegen getParentCodegen() { + return codegen.getParentCodegen(); + } + + public static CodegenContext getContext(DeclarationDescriptor descriptor, GenerationState state) { + if (descriptor instanceof NamespaceDescriptor) { + return new NamespaceContext((NamespaceDescriptor) descriptor, null); + } + + CodegenContext parent = getContext(descriptor.getContainingDeclaration(), state); + + if (descriptor instanceof ClassDescriptor) { + return parent.intoClass((ClassDescriptor) descriptor, OwnerKind.IMPLEMENTATION, state); + } + else if (descriptor instanceof FunctionDescriptor) { + return parent.intoFunction((FunctionDescriptor) descriptor); + } + + throw new IllegalStateException("Coudn't build context for " + descriptorName(descriptor)); + } + + private static boolean isStaticMethod(FunctionDescriptor functionDescriptor, MethodContext context) { + return (getMethodAsmFlags(functionDescriptor, context.getContextKind()) & Opcodes.ACC_STATIC) == Opcodes.ACC_STATIC; + } + + @NotNull + private static String getNodeText(@Nullable MethodNode node) { + if (node == null) { + return "Not generated"; + } + Textifier p = new Textifier(); + node.accept(new TraceMethodVisitor(p)); + StringWriter sw = new StringWriter(); + p.print(new PrintWriter(sw)); + sw.flush(); + return node.name + ": \n " + sw.getBuffer().toString(); + } + + private static String descriptorName(DeclarationDescriptor descriptor) { + return DescriptorRenderer.SHORT_NAMES_IN_TYPES.render(descriptor); + } +} diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/asm/InlineCodegenUtil.java b/compiler/backend/src/org/jetbrains/jet/codegen/asm/InlineCodegenUtil.java new file mode 100644 index 00000000000..d12ef4cfa0c --- /dev/null +++ b/compiler/backend/src/org/jetbrains/jet/codegen/asm/InlineCodegenUtil.java @@ -0,0 +1,138 @@ +/* + * Copyright 2010-2013 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.jet.codegen.asm; + +import com.intellij.openapi.components.ServiceManager; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.VirtualFile; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.asm4.ClassReader; +import org.jetbrains.asm4.ClassVisitor; +import org.jetbrains.asm4.MethodVisitor; +import org.jetbrains.asm4.Opcodes; +import org.jetbrains.asm4.tree.MethodNode; +import org.jetbrains.jet.codegen.state.GenerationState; +import org.jetbrains.jet.descriptors.serialization.JavaProtoBuf; +import org.jetbrains.jet.descriptors.serialization.ProtoBuf; +import org.jetbrains.jet.descriptors.serialization.descriptors.DeserializedSimpleFunctionDescriptor; +import org.jetbrains.jet.lang.descriptors.*; +import org.jetbrains.jet.lang.resolve.DescriptorUtils; +import org.jetbrains.jet.lang.resolve.java.PackageClassUtils; +import org.jetbrains.jet.lang.resolve.kotlin.VirtualFileFinder; +import org.jetbrains.jet.lang.resolve.name.FqName; +import org.jetbrains.jet.lang.resolve.name.Name; + +import java.io.IOException; +import java.io.InputStream; + +import static org.jetbrains.jet.lang.resolve.DescriptorUtils.getFQName; + +public class InlineCodegenUtil { + + private final static int API = Opcodes.ASM4; + + @Nullable + public static MethodNode getMethodNode( + InputStream classData, + final String methodName, + final String methodDescriptor + ) throws ClassNotFoundException, IOException { + ClassReader cr = new ClassReader(classData); + final MethodNode[] methodNode = new MethodNode[1]; + cr.accept(new ClassVisitor(API) { + + @Override + public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { + if (methodName.equals(name) && methodDescriptor.equals(desc)) { + return methodNode[0] = new MethodNode(access, name, desc, signature, exceptions); + } + return null; + } + }, ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES); + + return methodNode[0]; + } + + + @NotNull + public static VirtualFile getVirtualFileForCallable(DeserializedSimpleFunctionDescriptor deserializedDescriptor, GenerationState state) { + VirtualFile file = null; + DeclarationDescriptor parentDeclatation = deserializedDescriptor.getContainingDeclaration(); + if (parentDeclatation instanceof NamespaceDescriptor) { + ProtoBuf.Callable proto = deserializedDescriptor.getFunctionProto(); + if (proto.hasExtension(JavaProtoBuf.implClassName)) { + Name name = deserializedDescriptor.getNameResolver().getName(proto.getExtension(JavaProtoBuf.implClassName)); + FqName namespaceFqName = + PackageClassUtils.getPackageClassFqName(((NamespaceDescriptor) parentDeclatation).getFqName()).parent().child( + name); + file = findVirtualFile(state.getProject(), namespaceFqName); + } else { + assert false : "Function in namespace should have implClassName property in proto: " + deserializedDescriptor; + } + } else { + file = findVirtualFileContainingDescriptor(state.getProject(), deserializedDescriptor); + } + + if (file == null) { + throw new RuntimeException("Couldn't find declaration file for " + deserializedDescriptor.getName()); + } + + return file; + } + + @Nullable + private static VirtualFile findVirtualFile(@NotNull Project project, @NotNull FqName containerFqName) { + VirtualFileFinder fileFinder = ServiceManager.getService(project, VirtualFileFinder.class); + VirtualFile virtualFile = fileFinder.find(containerFqName); + if (virtualFile == null) { + return null; + } + return virtualFile; + } + + //TODO: navigate to inner classes + @Nullable + private static FqName getContainerFqName(@NotNull DeclarationDescriptor referencedDescriptor) { + ClassOrNamespaceDescriptor + containerDescriptor = DescriptorUtils.getParentOfType(referencedDescriptor, ClassOrNamespaceDescriptor.class, false); + if (containerDescriptor instanceof NamespaceDescriptor) { + return PackageClassUtils.getPackageClassFqName(getFQName(containerDescriptor).toSafe()); + } + if (containerDescriptor instanceof ClassDescriptor) { + ClassKind classKind = ((ClassDescriptor) containerDescriptor).getKind(); + if (classKind == ClassKind.CLASS_OBJECT || classKind == ClassKind.ENUM_ENTRY) { + return getContainerFqName(containerDescriptor.getContainingDeclaration()); + } + return getFQName(containerDescriptor).toSafe(); + } + return null; + } + + @Nullable + private static VirtualFile findVirtualFileContainingDescriptor( + @NotNull Project project, + @NotNull DeclarationDescriptor referencedDescriptor + ) { + FqName containerFqName = getContainerFqName(referencedDescriptor); + if (containerFqName == null) { + return null; + } + return findVirtualFile(project, containerFqName); + } + +} diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/asm/Inliner.java b/compiler/backend/src/org/jetbrains/jet/codegen/asm/Inliner.java new file mode 100644 index 00000000000..2d9da0e44e8 --- /dev/null +++ b/compiler/backend/src/org/jetbrains/jet/codegen/asm/Inliner.java @@ -0,0 +1,83 @@ +/* + * Copyright 2010-2013 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.jet.codegen.asm; + +import org.jetbrains.asm4.ClassVisitor; +import org.jetbrains.asm4.Type; +import org.jetbrains.jet.codegen.CallableMethod; +import org.jetbrains.jet.codegen.StackValue; +import org.jetbrains.jet.codegen.context.MethodContext; +import org.jetbrains.jet.lang.psi.JetExpression; +import org.jetbrains.jet.lang.psi.JetFunctionLiteralExpression; + +public interface Inliner { + + Inliner NOT_INLINE = new Inliner() { + @Override + public void inlineCall( + CallableMethod callableMethod, ClassVisitor visitor + ) { + throw new UnsupportedOperationException(); + } + + @Override + public void putInLocal(Type type, StackValue stackValue) { + + } + + @Override + public void leaveTemps() { + + } + + @Override + public boolean isInliningClosure(JetExpression expression) { + return false; + } + + @Override + public void rememberClosure(JetFunctionLiteralExpression expression, Type type) { + throw new UnsupportedOperationException(); + } + + @Override + public void putHiddenParams() { + + } + + @Override + public boolean shouldPutValue( + Type type, StackValue stackValue, MethodContext context + ) { + return true; + } + }; + + void inlineCall(CallableMethod callableMethod, ClassVisitor visitor); + + void putInLocal(Type type, StackValue stackValue); + + boolean shouldPutValue(Type type, StackValue stackValue, MethodContext context); + + void putHiddenParams(); + + void leaveTemps(); + + boolean isInliningClosure(JetExpression expression); + + void rememberClosure(JetFunctionLiteralExpression expression, Type type); +} diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/asm/InliningAdapter.java b/compiler/backend/src/org/jetbrains/jet/codegen/asm/InliningAdapter.java new file mode 100644 index 00000000000..d295b68f427 --- /dev/null +++ b/compiler/backend/src/org/jetbrains/jet/codegen/asm/InliningAdapter.java @@ -0,0 +1,94 @@ +/* + * Copyright 2010-2013 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.jet.codegen.asm; + +import org.jetbrains.asm4.*; +import org.jetbrains.asm4.commons.InstructionAdapter; + +import java.util.ArrayList; +import java.util.List; + +//http://asm.ow2.org/current/asm-transformations.pdf +public class InliningAdapter extends InstructionAdapter { + + private final Label end; + protected final VarRemapper remapper; + private int nextLocalIndex = 0; + + public InliningAdapter(MethodVisitor mv, int api, String desc, Label end, int localsStart, VarRemapper remapper) { + super(api, mv); + this.end = end; + this.remapper = remapper; + nextLocalIndex = localsStart; + } + + public void visitInsn(int opcode) { + if (opcode >= Opcodes.IRETURN && opcode <= Opcodes.RETURN) { + super.visitJumpInsn(Opcodes.GOTO, end); + } + else { + super.visitInsn(opcode); + } + } + + @Override + public void visitIincInsn(int var, int increment) { + super.visitIincInsn(remapper.remap(var), increment); + } + + @Override + public void visitVarInsn(int opcode, int var) { + int newVar = remapper.remap(var); + super.visitVarInsn(opcode, newVar); + int size = newVar + (opcode == Opcodes.DSTORE || opcode == Opcodes.LSTORE ? 2 : 1); + if (size > nextLocalIndex) { + nextLocalIndex = size; + } + } + + public int getNextLocalIndex() { + return nextLocalIndex; + } + + @Override + public void visitLocalVariable( + String name, String desc, String signature, Label start, Label end, int index + ) { + //super.visitLocalVariable(name, desc, signature, start, end, index); + } + + @Override + public AnnotationVisitor visitAnnotationDefault() { + return null; + } + + @Override + public void visitMaxs(int maxStack, int maxLocals) { + + } + + @Override + public AnnotationVisitor visitAnnotation(String desc, boolean visible) { + return null; + } + + @Override + public AnnotationVisitor visitParameterAnnotation(int parameter, String desc, boolean visible) { + return null; + } + +} \ No newline at end of file diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/asm/ParameterInfo.java b/compiler/backend/src/org/jetbrains/jet/codegen/asm/ParameterInfo.java new file mode 100644 index 00000000000..fae0f0736d5 --- /dev/null +++ b/compiler/backend/src/org/jetbrains/jet/codegen/asm/ParameterInfo.java @@ -0,0 +1,56 @@ +/* + * Copyright 2010-2013 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.jet.codegen.asm; + +import org.jetbrains.asm4.Type; +import org.jetbrains.jet.lang.resolve.java.AsmTypeConstants; + +class ParameterInfo { + + public static final ParameterInfo STUB = new ParameterInfo(AsmTypeConstants.OBJECT_TYPE, true, -1, -1); + + public final int index; + + public final Type type; + + public final boolean isSkipped; + + public final int remapIndex; + + ParameterInfo(Type type, boolean skipped, int remapIndex, int index) { + this.type = type; + this.isSkipped = skipped; + this.remapIndex = remapIndex; + this.index = index; + } + + public boolean isSkippedOrRemapped() { + return isSkipped || remapIndex != -1; + } + + public int getInlinedIndex() { + return remapIndex != -1 ? remapIndex : index; + } + + public boolean isSkipped() { + return isSkipped; + } + + public Type getType() { + return type; + } +} diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/asm/VarRemapper.java b/compiler/backend/src/org/jetbrains/jet/codegen/asm/VarRemapper.java new file mode 100644 index 00000000000..78b134b41c9 --- /dev/null +++ b/compiler/backend/src/org/jetbrains/jet/codegen/asm/VarRemapper.java @@ -0,0 +1,114 @@ +/* + * Copyright 2010-2013 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.jet.codegen.asm; + +import java.util.List; + +public abstract class VarRemapper { + + public static class ShiftRemapper extends VarRemapper { + + private final int shift; + + public ShiftRemapper(int shift) { + this.shift = shift; + } + + @Override + public int doRemap(int index) { + return index + shift; + } + } + + public static class ClosureRemapper extends ShiftRemapper { + + private final ClosureInfo info; + private final List originalParams; + private final int capturedSize; + + public ClosureRemapper(ClosureInfo info, int valueParametersShift, List originalParams) { + super(valueParametersShift); + this.info = info; + this.originalParams = originalParams; + capturedSize = info.getCapturedVarsSize(); + } + + @Override + public int doRemap(int index) { + if (index < capturedSize) { + return originalParams.get(info.getParamOffset() + index).getInlinedIndex(); + } + return super.doRemap(index - capturedSize); + } + } + + public static class ParamRemapper extends VarRemapper { + + private final int paramShift; + private final int paramSize; + private final int additionalParamsSize; + private final List params; + private final int actualParams; + + public ParamRemapper(int paramShift, int paramSize, int additionalParamsSize, List params) { + this.paramShift = paramShift; + this.paramSize = paramSize; + this.additionalParamsSize = additionalParamsSize; + this.params = params; + + int paramCount = 0; + for (int i = 0; i < params.size(); i++) { + ParameterInfo info = params.get(i); + if (!info.isSkippedOrRemapped()) { + paramCount += info.getType().getSize(); + } + } + actualParams = paramCount; + } + + @Override + public int doRemap(int index) { + if (index < paramSize) { + ParameterInfo info = params.get(index); + if (info.isSkipped) { + throw new RuntimeException("Trying to access skipped parameter: " + info.type + " at " +index); + } + return info.getInlinedIndex(); + } else { + return paramShift + actualParams + index; //captured params not used directly in this inlined method, they used in closure + } + } + } + + + + protected boolean nestedRemmapper; + + public int remap(int index) { + if (nestedRemmapper) { + return index; + } + return doRemap(index); + } + + abstract public int doRemap(int index); + + public void setNestedRemap(boolean nestedRemap) { + nestedRemmapper = nestedRemap; + } + +} diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/context/EnclosedValueDescriptor.java b/compiler/backend/src/org/jetbrains/jet/codegen/context/EnclosedValueDescriptor.java index 1195a9f17fe..de96ed582fa 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/context/EnclosedValueDescriptor.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/context/EnclosedValueDescriptor.java @@ -23,11 +23,13 @@ import org.jetbrains.jet.codegen.state.GenerationState; import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; public final class EnclosedValueDescriptor { + private final String fieldName; private final DeclarationDescriptor descriptor; private final StackValue innerValue; private final Type type; - public EnclosedValueDescriptor(DeclarationDescriptor descriptor, StackValue innerValue, Type type) { + public EnclosedValueDescriptor(String fieldName, DeclarationDescriptor descriptor, StackValue innerValue, Type type) { + this.fieldName = fieldName; this.descriptor = descriptor; this.innerValue = innerValue; this.type = type; @@ -55,4 +57,8 @@ public final class EnclosedValueDescriptor { throw new IllegalStateException(); } + + public String getFieldName() { + return fieldName; + } } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/context/LocalLookup.java b/compiler/backend/src/org/jetbrains/jet/codegen/context/LocalLookup.java index f39e610eef9..e6d3d74ce09 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/context/LocalLookup.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/context/LocalLookup.java @@ -61,7 +61,7 @@ public interface LocalLookup { : StackValue.field(type, classType, fieldName, false); closure.recordField(fieldName, type); - closure.captureVariable(new EnclosedValueDescriptor(d, innerValue, type)); + closure.captureVariable(new EnclosedValueDescriptor(fieldName, d, innerValue, type)); return innerValue; } @@ -92,7 +92,7 @@ public interface LocalLookup { StackValue innerValue = StackValue.field(localType, classType, fieldName, false); closure.recordField(fieldName, localType); - closure.captureVariable(new EnclosedValueDescriptor(d, innerValue, localType)); + closure.captureVariable(new EnclosedValueDescriptor(fieldName, d, innerValue, localType)); return innerValue; } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/context/MethodContext.java b/compiler/backend/src/org/jetbrains/jet/codegen/context/MethodContext.java index c9bded8b452..1b53944bef5 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/context/MethodContext.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/context/MethodContext.java @@ -23,10 +23,7 @@ import org.jetbrains.jet.codegen.OwnerKind; import org.jetbrains.jet.codegen.StackValue; import org.jetbrains.jet.codegen.binding.MutableClosure; import org.jetbrains.jet.codegen.state.GenerationState; -import org.jetbrains.jet.lang.descriptors.CallableMemberDescriptor; -import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; -import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; -import org.jetbrains.jet.lang.descriptors.PropertyAccessorDescriptor; +import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.resolve.java.AsmTypeConstants; public class MethodContext extends CodegenContext { @@ -81,4 +78,11 @@ public class MethodContext extends CodegenContext { return "Method: " + getContextDescriptor(); } + public boolean isInlineFunction() { + DeclarationDescriptor descriptor = getContextDescriptor(); + if (descriptor instanceof SimpleFunctionDescriptor) { + return ((SimpleFunctionDescriptor) descriptor).isInline(); + } + return false; + } }