From 6ad2814b01db17e23a9f15936a51f2dadc66ba96 Mon Sep 17 00:00:00 2001 From: Mikhael Bogdanov Date: Tue, 20 May 2014 14:14:48 +0400 Subject: [PATCH] Suppot inlining default methods, inlining function into its default. --- .../jetbrains/jet/codegen/CallGenerator.java | 36 ++++++-- .../jetbrains/jet/codegen/CallableMethod.java | 8 +- .../jetbrains/jet/codegen/ClosureCodegen.java | 4 +- .../jet/codegen/ExpressionCodegen.java | 30 +++---- .../jet/codegen/FunctionCodegen.java | 57 +++++++------ .../codegen/ImplementationBodyCodegen.java | 5 +- .../jet/codegen/inline/InlineCodegen.java | 82 ++++++++++++------- .../jet/codegen/state/JetTypeMapper.java | 17 +++- .../codegen/boxInline/defaultMethod/1.kt | 22 +++++ .../codegen/boxInline/defaultMethod/2.kt | 12 +++ .../boxInline/inlineInDefaultParameter/1.kt | 26 ++++++ .../boxInline/inlineInDefaultParameter/2.kt | 5 ++ .../boxInline/simpleDefaultMethod/1.kt | 22 +++++ .../boxInline/simpleDefaultMethod/2.kt | 11 +++ .../BlackBoxInlineCodegenTestGenerated.java | 15 ++++ ...otlinAgainstInlineKotlinTestGenerated.java | 15 ++++ 16 files changed, 276 insertions(+), 91 deletions(-) create mode 100644 compiler/testData/codegen/boxInline/defaultMethod/1.kt create mode 100644 compiler/testData/codegen/boxInline/defaultMethod/2.kt create mode 100644 compiler/testData/codegen/boxInline/inlineInDefaultParameter/1.kt create mode 100644 compiler/testData/codegen/boxInline/inlineInDefaultParameter/2.kt create mode 100644 compiler/testData/codegen/boxInline/simpleDefaultMethod/1.kt create mode 100644 compiler/testData/codegen/boxInline/simpleDefaultMethod/2.kt diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/CallGenerator.java b/compiler/backend/src/org/jetbrains/jet/codegen/CallGenerator.java index c0f64a1c5b2..06ef356842d 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/CallGenerator.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/CallGenerator.java @@ -17,6 +17,7 @@ package org.jetbrains.jet.codegen; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.org.objectweb.asm.Type; import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor; import org.jetbrains.jet.lang.psi.JetExpression; @@ -34,20 +35,28 @@ public interface CallGenerator { @Override public void genCall( - CallableMethod callableMethod, - ResolvedCall resolvedCall, int mask, - ExpressionCodegen codegen + @NotNull CallableMethod callableMethod, + ResolvedCall resolvedCall, + boolean callDefault, + @NotNull ExpressionCodegen codegen ) { - if (mask == 0) { + if (!callDefault) { callableMethod.invokeWithNotNullAssertion(codegen.v, codegen.getState(), resolvedCall); } else { - callableMethod.invokeDefaultWithNotNullAssertion(codegen.v, codegen.getState(), resolvedCall, mask); + callableMethod.invokeDefaultWithNotNullAssertion(codegen.v, codegen.getState(), resolvedCall); } } @Override - public void afterParameterPut(Type type, StackValue stackValue, ValueParameterDescriptor valueParameterDescriptor) { + public void genCallWithoutNullAssertion( + @NotNull CallableMethod method, @NotNull ExpressionCodegen codegen + ) { + method.invokeWithoutAssertions(codegen.v); + } + + @Override + public void afterParameterPut(@NotNull Type type, StackValue stackValue, @NotNull ValueParameterDescriptor valueParameterDescriptor) { } @@ -72,11 +81,20 @@ public interface CallGenerator { ) { stackValue.put(stackValue.type, codegen.v); } + + @Override + public void putValueIfNeeded( + @Nullable ValueParameterDescriptor valueParameterDescriptor, @NotNull Type parameterType, @NotNull StackValue value + ) { + value.put(value.type, codegen.v); + } } - void genCall(CallableMethod callableMethod, ResolvedCall resolvedCall, int mask, ExpressionCodegen codegen); + void genCall(@NotNull CallableMethod callableMethod, @Nullable ResolvedCall resolvedCall, boolean callDefault, @NotNull ExpressionCodegen codegen); - void afterParameterPut(Type type, StackValue stackValue, ValueParameterDescriptor valueParameterDescriptor); + void genCallWithoutNullAssertion(@NotNull CallableMethod callableMethod, @NotNull ExpressionCodegen codegen); + + void afterParameterPut(@NotNull Type type, StackValue stackValue, @NotNull ValueParameterDescriptor valueParameterDescriptor); void genValueAndPut( @NotNull ValueParameterDescriptor valueParameterDescriptor, @@ -84,6 +102,8 @@ public interface CallGenerator { @NotNull Type parameterType ); + void putValueIfNeeded(@Nullable ValueParameterDescriptor valueParameterDescriptor, @NotNull Type parameterType, @NotNull StackValue value); + void putCapturedValueOnStack( @NotNull StackValue stackValue, @NotNull Type valueType, int paramIndex diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/CallableMethod.java b/compiler/backend/src/org/jetbrains/jet/codegen/CallableMethod.java index 3b09c1fb0d3..b25e8dcf604 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/CallableMethod.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/CallableMethod.java @@ -128,14 +128,13 @@ public class CallableMethod implements Callable { return generateCalleeType; } - private void invokeDefault(InstructionAdapter v, int mask) { + private void invokeDefault(InstructionAdapter v) { if (defaultImplOwner == null || defaultImplParam == null) { throw new IllegalStateException(); } Method method = getAsmMethod(); - v.iconst(mask); String desc = method.getDescriptor().replace(")", "I)"); if ("".equals(method.getName())) { v.visitMethodInsn(INVOKESPECIAL, defaultImplOwner.getInternalName(), "", desc); @@ -151,10 +150,9 @@ public class CallableMethod implements Callable { public void invokeDefaultWithNotNullAssertion( @NotNull InstructionAdapter v, @NotNull GenerationState state, - @NotNull ResolvedCall resolvedCall, - int mask + @NotNull ResolvedCall resolvedCall ) { - invokeDefault(v, mask); + invokeDefault(v); AsmUtil.genNotNullAssertionForMethod(v, state, resolvedCall); } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java index f920c59cf19..d119ddc3512 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java @@ -175,7 +175,9 @@ public class ClosureCodegen extends ParentCodegenAwareImpl { typeMapper.mapSignature(funDescriptor), funDescriptor, context.getContextKind(), - DefaultParameterValueLoader.DEFAULT); + DefaultParameterValueLoader.DEFAULT, + null); + cv.done(); } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index d117f4c9e7e..6bf626a2d1d 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -2078,8 +2078,8 @@ public class ExpressionCodegen extends JetVisitor implem resolvedCall = ((VariableAsFunctionResolvedCall) resolvedCall).getFunctionCall(); } - assert callGenerator == defaultCallGenerator || !hasDefaultArguments(resolvedCall) && !tailRecursionCodegen.isTailRecursion(resolvedCall) : - "Method with defaults or tail recursive couldn't be inlined " + descriptor; + assert callGenerator == defaultCallGenerator || !tailRecursionCodegen.isTailRecursion(resolvedCall) : + "Tail recursive method couldn't be inlined " + descriptor; int mask = pushMethodArgumentsWithCallReceiver(receiver, resolvedCall, callableMethod, false, callGenerator); @@ -2088,10 +2088,16 @@ public class ExpressionCodegen extends JetVisitor implem return; } - callGenerator.genCall(callableMethod, resolvedCall, mask, this); + boolean callDefault = mask != 0; + if (callDefault) { + callGenerator.putValueIfNeeded(null, Type.INT_TYPE, StackValue.constant(mask, Type.INT_TYPE)); + } + + callGenerator.genCall(callableMethod, resolvedCall, callDefault, this); } - protected CallGenerator getOrCreateCallGenerator(CallableDescriptor descriptor, JetElement callElement) { + @NotNull + protected CallGenerator getOrCreateCallGenerator(@NotNull CallableDescriptor descriptor, @Nullable JetElement callElement) { boolean isInline = state.isInlineEnabled() && descriptor instanceof SimpleFunctionDescriptor && ((SimpleFunctionDescriptor) descriptor).getInlineStrategy().isInline(); @@ -2328,22 +2334,6 @@ public class ExpressionCodegen extends JetVisitor implem return mask; } - private static boolean hasDefaultArguments(@NotNull ResolvedCall resolvedCall) { - List valueArguments = resolvedCall.getValueArgumentsByIndex(); - CallableDescriptor fd = resolvedCall.getResultingDescriptor(); - if (valueArguments == null) { - throw new IllegalStateException("Failed to arrange value arguments by index: " + resolvedCall.getResultingDescriptor()); - } - - for (ValueParameterDescriptor valueParameter : fd.getValueParameters()) { - 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(); diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java index 7c8a8fa8034..2e491f01f6f 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java @@ -105,7 +105,7 @@ public class FunctionCodegen extends ParentCodegenAwareImpl { } generateDefaultIfNeeded(owner.intoFunction(functionDescriptor), method, functionDescriptor, kind, - DefaultParameterValueLoader.DEFAULT); + DefaultParameterValueLoader.DEFAULT, function); } public void generateMethod( @@ -536,7 +536,8 @@ public class FunctionCodegen extends ParentCodegenAwareImpl { @NotNull JvmMethodSignature signature, @NotNull FunctionDescriptor functionDescriptor, @NotNull OwnerKind kind, - @NotNull DefaultParameterValueLoader loadStrategy + @NotNull DefaultParameterValueLoader loadStrategy, + @Nullable JetNamedFunction function ) { DeclarationDescriptor contextClass = owner.getContextDescriptor().getContainingDeclaration(); @@ -550,20 +551,14 @@ public class FunctionCodegen extends ParentCodegenAwareImpl { return; } - boolean isStatic = isStatic(kind); - Method jvmSignature = signature.getAsmMethod(); int flags = getVisibilityAccessFlag(functionDescriptor) | getDeprecatedAccessFlag(functionDescriptor); - Type ownerType = typeMapper.mapOwner(functionDescriptor, true); - String descriptor = jvmSignature.getDescriptor().replace(")", "I)"); boolean isConstructor = "".equals(jvmSignature.getName()); - if (!isStatic && !isConstructor) { - descriptor = descriptor.replace("(", "(" + ownerType.getDescriptor()); - } - Method defaultMethod = new Method(isConstructor ? "" : jvmSignature.getName() + JvmAbi.DEFAULT_PARAMS_IMPL_SUFFIX, descriptor); + Method defaultMethod = typeMapper.mapDefaultMethod(functionDescriptor, kind, owner); + MethodVisitor mv = v.newMethod(null, flags | (isConstructor ? 0 : ACC_STATIC), defaultMethod.getName(), defaultMethod.getDescriptor(), null, @@ -574,8 +569,9 @@ public class FunctionCodegen extends ParentCodegenAwareImpl { mv.visitCode(); generateStaticDelegateMethodBody(mv, defaultMethod, (PackageFacadeContext) this.owner); endVisit(mv, "default method delegation", callableDescriptorToDeclaration(state.getBindingContext(), functionDescriptor)); - } else { - generateDefaultImpl(owner, signature, functionDescriptor, isStatic, mv, loadStrategy); + } + else { + generateDefaultImpl(owner, signature, functionDescriptor, isStatic(kind), mv, loadStrategy, function); } } } @@ -586,17 +582,32 @@ public class FunctionCodegen extends ParentCodegenAwareImpl { @NotNull FunctionDescriptor functionDescriptor, boolean aStatic, @NotNull MethodVisitor mv, - @NotNull DefaultParameterValueLoader loadStrategy + @NotNull DefaultParameterValueLoader loadStrategy, + @Nullable JetNamedFunction function ) { mv.visitCode(); + generateDefaultImplBody(methodContext, signature, functionDescriptor, aStatic, mv, loadStrategy, function, getParentCodegen(), state); + endVisit(mv, "default method", callableDescriptorToDeclaration(state.getBindingContext(), functionDescriptor)); + } + public static void generateDefaultImplBody( + @NotNull MethodContext methodContext, + @NotNull JvmMethodSignature signature, + @NotNull FunctionDescriptor functionDescriptor, + boolean aStatic, + @NotNull MethodVisitor mv, + @NotNull DefaultParameterValueLoader loadStrategy, + @Nullable JetNamedFunction function, + @NotNull MemberCodegen parentCodegen, + @NotNull GenerationState state + ) { FrameMap frameMap = new FrameMap(); if (!aStatic) { frameMap.enterTemp(OBJECT_TYPE); } - ExpressionCodegen codegen = new ExpressionCodegen(mv, frameMap, signature.getReturnType(), methodContext, state, getParentCodegen()); + ExpressionCodegen codegen = new ExpressionCodegen(mv, frameMap, signature.getReturnType(), methodContext, state, parentCodegen); Type[] argTypes = signature.getAsmMethod().getArgumentTypes(); List paramDescrs = functionDescriptor.getValueParameters(); @@ -616,14 +627,18 @@ public class FunctionCodegen extends ParentCodegenAwareImpl { int maskIndex = frameMap.enterTemp(Type.INT_TYPE); + CallGenerator generator = codegen.getOrCreateCallGenerator(functionDescriptor, function); + InstructionAdapter iv = new InstructionAdapter(mv); loadExplicitArgumentsOnStack(iv, OBJECT_TYPE, aStatic, signature); + generator.putHiddenParams(); for (int index = 0; index < paramDescrs.size(); index++) { ValueParameterDescriptor parameterDescriptor = paramDescrs.get(index); Type t = argTypes[countOfExtraVarsInMethodArgs + index]; + int parameterIndex = frameMap.getIndex(parameterDescriptor); if (parameterDescriptor.declaresDefaultValue()) { iv.load(maskIndex, Type.INT_TYPE); iv.iconst(1 << index); @@ -633,28 +648,24 @@ public class FunctionCodegen extends ParentCodegenAwareImpl { loadStrategy.putValueOnStack(parameterDescriptor, codegen); - int ind = frameMap.getIndex(parameterDescriptor); - iv.store(ind, t); + iv.store(parameterIndex, t); iv.mark(loadArg); } - iv.load(frameMap.getIndex(parameterDescriptor), t); + generator.putValueIfNeeded(parameterDescriptor, t, StackValue.local(parameterIndex, t)); } CallableMethod method; if (functionDescriptor instanceof ConstructorDescriptor) { - method = typeMapper.mapToCallableMethod((ConstructorDescriptor) functionDescriptor); + method = state.getTypeMapper().mapToCallableMethod((ConstructorDescriptor) functionDescriptor); } else { - method = typeMapper.mapToCallableMethod(functionDescriptor, false, methodContext); + method = state.getTypeMapper().mapToCallableMethod(functionDescriptor, false, methodContext); } - iv.visitMethodInsn(method.getInvokeOpcode(), method.getOwner().getInternalName(), method.getAsmMethod().getName(), - method.getAsmMethod().getDescriptor()); + generator.genCallWithoutNullAssertion(method, codegen); iv.areturn(signature.getReturnType()); - - endVisit(mv, "default method", callableDescriptorToDeclaration(state.getBindingContext(), functionDescriptor)); } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java index ab38c12a3ca..fd7c25c286b 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java @@ -871,7 +871,8 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { Type propertyType = typeMapper.mapType(property); codegen.intermediateValueForProperty(property, false, null).put(propertyType, codegen.v); } - } + }, + null ); } } @@ -1135,7 +1136,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { ); functionCodegen.generateDefaultIfNeeded(constructorContext, constructorSignature, constructorDescriptor, - OwnerKind.IMPLEMENTATION, DefaultParameterValueLoader.DEFAULT); + OwnerKind.IMPLEMENTATION, DefaultParameterValueLoader.DEFAULT, null); CallableMethod callableMethod = typeMapper.mapToCallableMethod(constructorDescriptor); FunctionCodegen.generateConstructorWithoutParametersIfNeeded(state, callableMethod, constructorDescriptor, v); diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/inline/InlineCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/inline/InlineCodegen.java index 92f86c7a7fa..ca02de92441 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/inline/InlineCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/inline/InlineCodegen.java @@ -56,6 +56,7 @@ import java.util.*; import static org.jetbrains.jet.codegen.AsmUtil.getMethodAsmFlags; import static org.jetbrains.jet.codegen.AsmUtil.isPrimitive; +import static org.jetbrains.jet.codegen.AsmUtil.isStatic; public class InlineCodegen implements CallGenerator { private final GenerationState state; @@ -105,15 +106,19 @@ public class InlineCodegen implements CallGenerator { JvmCodegenUtil.isCallInsideSameModuleAsDeclared(functionDescriptor, codegen.getContext()); } + @Override + public void genCallWithoutNullAssertion( + @NotNull CallableMethod callableMethod, @NotNull ExpressionCodegen codegen + ) { + genCall(callableMethod, null, false, codegen); + } @Override - public void genCall(CallableMethod callableMethod, ResolvedCall resolvedCall, int mask, ExpressionCodegen codegen) { - assert mask == 0 : "Default method invocation couldn't be inlined " + resolvedCall; - + public void genCall(@NotNull CallableMethod callableMethod, @Nullable ResolvedCall resolvedCall, boolean callDefault, @NotNull ExpressionCodegen codegen) { MethodNode node = null; try { - node = createMethodNode(callableMethod); + node = createMethodNode(callDefault); endCall(inlineCall(node)); } catch (CompilationException e) { @@ -139,17 +144,21 @@ public class InlineCodegen implements CallGenerator { } @NotNull - private MethodNode createMethodNode(CallableMethod callableMethod) - throws ClassNotFoundException, IOException { + private MethodNode createMethodNode(boolean callDefault) throws ClassNotFoundException, IOException { + JvmMethodSignature jvmSignature = typeMapper.mapSignature(functionDescriptor, context.getContextKind()); + + Method asmMethod; + if (callDefault) { + asmMethod = typeMapper.mapDefaultMethod(functionDescriptor, context.getContextKind(), context); + } + else { + asmMethod = jvmSignature.getAsmMethod(); + } + MethodNode node; if (functionDescriptor instanceof DeserializedSimpleFunctionDescriptor) { VirtualFile file = InlineCodegenUtil.getVirtualFileForCallable((DeserializedSimpleFunctionDescriptor) functionDescriptor, state); - String methodDesc = callableMethod.getAsmMethod().getDescriptor(); - DeclarationDescriptor parentDescriptor = functionDescriptor.getContainingDeclaration(); - if (DescriptorUtils.isTrait(parentDescriptor)) { - methodDesc = "(" + typeMapper.mapType((ClassDescriptor) parentDescriptor).getDescriptor() + methodDesc.substring(1); - } - node = InlineCodegenUtil.getMethodNode(file.getInputStream(), functionDescriptor.getName().asString(), methodDesc); + node = InlineCodegenUtil.getMethodNode(file.getInputStream(), asmMethod.getName(), asmMethod.getDescriptor()); if (node == null) { throw new RuntimeException("Couldn't obtain compiled function body for " + descriptorName(functionDescriptor)); @@ -162,25 +171,33 @@ public class InlineCodegen implements CallGenerator { 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(InlineCodegenUtil.API, - getMethodAsmFlags(functionDescriptor, context.getContextKind()), + getMethodAsmFlags(functionDescriptor, context.getContextKind()) | (callDefault ? Opcodes.ACC_STATIC : 0), asmMethod.getName(), asmMethod.getDescriptor(), jvmSignature.getGenericsSignature(), null); //for maxLocals calculation - MethodVisitor adapter = InlineCodegenUtil.wrapWithMaxLocalCalc(node); - FunctionCodegen.generateMethodBody(adapter, functionDescriptor, context.getParentContext().intoFunction(functionDescriptor), - jvmSignature, - new FunctionGenerationStrategy.FunctionDefault(state, - functionDescriptor, - (JetDeclarationWithBody) element), - codegen.getParentCodegen()); - adapter.visitMaxs(-1, -1); - adapter.visitEnd(); + MethodVisitor maxCalcAdapter = InlineCodegenUtil.wrapWithMaxLocalCalc(node); + MethodContext methodContext = context.getParentContext().intoFunction(functionDescriptor); + MemberCodegen parentCodegen = codegen.getParentCodegen(); + if (callDefault) { + boolean isStatic = isStatic(codegen.getContext().getContextKind()); + FunctionCodegen.generateDefaultImplBody( + methodContext, jvmSignature, functionDescriptor, isStatic, maxCalcAdapter, DefaultParameterValueLoader.DEFAULT, + (JetNamedFunction) element, parentCodegen, state + ); + } + else { + FunctionCodegen.generateMethodBody( + maxCalcAdapter, functionDescriptor, methodContext, jvmSignature, + new FunctionGenerationStrategy.FunctionDefault(state, functionDescriptor, (JetDeclarationWithBody) element), + parentCodegen + ); + } + maxCalcAdapter.visitMaxs(-1, -1); + maxCalcAdapter.visitEnd(); } return node; } @@ -240,11 +257,11 @@ public class InlineCodegen implements CallGenerator { @Override - public void afterParameterPut(@NotNull Type type, @Nullable StackValue stackValue, ValueParameterDescriptor valueParameterDescriptor) { + public void afterParameterPut(@NotNull Type type, @Nullable StackValue stackValue, @Nullable ValueParameterDescriptor valueParameterDescriptor) { putCapturedInLocal(type, stackValue, valueParameterDescriptor, -1); } - public void putCapturedInLocal( + private void putCapturedInLocal( @NotNull Type type, @Nullable StackValue stackValue, @Nullable ValueParameterDescriptor valueParameterDescriptor, int capturedParamIndex ) { if (!asFunctionInline && Type.VOID_TYPE != type) { @@ -449,13 +466,18 @@ public class InlineCodegen implements CallGenerator { rememberClosure((JetFunctionLiteralExpression) argumentExpression, parameterType); } else { StackValue value = codegen.gen(argumentExpression); - if (shouldPutValue(parameterType, value, valueParameterDescriptor)) { - value.put(parameterType, codegen.v); - } - afterParameterPut(parameterType, value, valueParameterDescriptor); + putValueIfNeeded(valueParameterDescriptor, parameterType, value); } } + @Override + public void putValueIfNeeded(@Nullable ValueParameterDescriptor valueParameterDescriptor, @NotNull Type parameterType, @NotNull StackValue value) { + if (shouldPutValue(parameterType, value, valueParameterDescriptor)) { + value.put(parameterType, codegen.v); + } + afterParameterPut(parameterType, value, valueParameterDescriptor); + } + @Override public void putCapturedValueOnStack( @NotNull StackValue stackValue, @NotNull Type valueType, int paramIndex diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/state/JetTypeMapper.java b/compiler/backend/src/org/jetbrains/jet/codegen/state/JetTypeMapper.java index a86bef4875b..db0275feac9 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/state/JetTypeMapper.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/state/JetTypeMapper.java @@ -45,12 +45,12 @@ import org.jetbrains.jet.lang.resolve.name.FqNameUnsafe; import org.jetbrains.jet.lang.types.*; import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; import org.jetbrains.org.objectweb.asm.Type; +import org.jetbrains.org.objectweb.asm.commons.Method; import java.util.ArrayList; import java.util.List; -import static org.jetbrains.jet.codegen.AsmUtil.boxType; -import static org.jetbrains.jet.codegen.AsmUtil.getTraitImplThisParameterType; +import static org.jetbrains.jet.codegen.AsmUtil.*; import static org.jetbrains.jet.codegen.JvmCodegenUtil.*; import static org.jetbrains.jet.codegen.binding.CodegenBinding.*; import static org.jetbrains.jet.lang.resolve.BindingContextUtils.isVarCapturedInClosure; @@ -582,6 +582,19 @@ public class JetTypeMapper { return sw.makeJvmMethodSignature(mapFunctionName(f)); } + @NotNull + public Method mapDefaultMethod(@NotNull FunctionDescriptor functionDescriptor, @NotNull OwnerKind kind, @NotNull CodegenContext context) { + Method jvmSignature = mapSignature(functionDescriptor, kind).getAsmMethod(); + Type ownerType = mapOwner(functionDescriptor, isCallInsideSameModuleAsDeclared(functionDescriptor, context)); + String descriptor = jvmSignature.getDescriptor().replace(")", "I)"); + boolean isConstructor = "".equals(jvmSignature.getName()); + if (!isStatic(kind) && !isConstructor) { + descriptor = descriptor.replace("(", "(" + ownerType.getDescriptor()); + } + + return new Method(isConstructor ? "" : jvmSignature.getName() + JvmAbi.DEFAULT_PARAMS_IMPL_SUFFIX, descriptor); + } + /** * @return true iff a given function descriptor should be compiled to a method with boxed return type regardless of whether return type * of that descriptor is nullable or not. This happens when a function returning a value of a primitive type overrides another function diff --git a/compiler/testData/codegen/boxInline/defaultMethod/1.kt b/compiler/testData/codegen/boxInline/defaultMethod/1.kt new file mode 100644 index 00000000000..0a495bba718 --- /dev/null +++ b/compiler/testData/codegen/boxInline/defaultMethod/1.kt @@ -0,0 +1,22 @@ +import test.* + +fun simple(): String { + val k = "K" + return simpleFun(lambda = {it + "O"}) + simpleFun("K", {k + it}) +} + +fun simpleR(): String { + val k = "K" + return simpleFunR({it + "O"}) + simpleFunR({k + it}, "K") +} + +fun box(): String { + + var result = simple() + if (result != "OOKK") return "fail1: ${result}" + + result = simpleR() + if (result != "OOKK") return "fail2: ${result}" + + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/boxInline/defaultMethod/2.kt b/compiler/testData/codegen/boxInline/defaultMethod/2.kt new file mode 100644 index 00000000000..de98a85e1b2 --- /dev/null +++ b/compiler/testData/codegen/boxInline/defaultMethod/2.kt @@ -0,0 +1,12 @@ +package test + + +inline fun simpleFun(arg: String = "O", lambda: (String) -> T): T { + return lambda(arg) +} + + +inline fun simpleFunR(lambda: (String) -> T, arg: String = "O"): T { + return lambda(arg) +} + diff --git a/compiler/testData/codegen/boxInline/inlineInDefaultParameter/1.kt b/compiler/testData/codegen/boxInline/inlineInDefaultParameter/1.kt new file mode 100644 index 00000000000..938d673b798 --- /dev/null +++ b/compiler/testData/codegen/boxInline/inlineInDefaultParameter/1.kt @@ -0,0 +1,26 @@ +import test.* + +fun testCompilation(arg: String = getStringInline()): String { + return arg +} + +inline fun testCompilationInline(arg: String = getStringInline()): String { + return arg +} + +fun box(): String { + var result = testCompilation() + if (result != "OK") return "fail1: ${result}" + + result = testCompilation("OKOK") + if (result != "OKOK") return "fail2: ${result}" + + + result = testCompilationInline() + if (result != "OK") return "fail3: ${result}" + + result = testCompilationInline("OKOK") + if (result != "OKOK") return "fail4: ${result}" + + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/boxInline/inlineInDefaultParameter/2.kt b/compiler/testData/codegen/boxInline/inlineInDefaultParameter/2.kt new file mode 100644 index 00000000000..f0ff8732670 --- /dev/null +++ b/compiler/testData/codegen/boxInline/inlineInDefaultParameter/2.kt @@ -0,0 +1,5 @@ +package test + +inline fun getStringInline(): String { + return "OK" +} diff --git a/compiler/testData/codegen/boxInline/simpleDefaultMethod/1.kt b/compiler/testData/codegen/boxInline/simpleDefaultMethod/1.kt new file mode 100644 index 00000000000..cb4936a747e --- /dev/null +++ b/compiler/testData/codegen/boxInline/simpleDefaultMethod/1.kt @@ -0,0 +1,22 @@ +import test.* + +fun testCompilation(): String { + emptyFun() + emptyFun("K") + + return "OK" +} + +fun simple(): String { + return simpleFun() + simpleFun("K") +} + +fun box(): String { + var result = testCompilation() + if (result != "OK") return "fail1: ${result}" + + result = simple() + if (result != "OK") return "fail2: ${result}" + + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/boxInline/simpleDefaultMethod/2.kt b/compiler/testData/codegen/boxInline/simpleDefaultMethod/2.kt new file mode 100644 index 00000000000..71ed00adaf0 --- /dev/null +++ b/compiler/testData/codegen/boxInline/simpleDefaultMethod/2.kt @@ -0,0 +1,11 @@ +package test + +inline fun emptyFun(arg: String = "O") { + +} + +inline fun simpleFun(arg: String = "O"): String { + val r = arg; + return r; +} + diff --git a/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxInlineCodegenTestGenerated.java b/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxInlineCodegenTestGenerated.java index 738e2ebecb7..76896bf630e 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxInlineCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxInlineCodegenTestGenerated.java @@ -91,6 +91,11 @@ public class BlackBoxInlineCodegenTestGenerated extends AbstractBlackBoxCodegenT doTestMultiFileWithInlineCheck("compiler/testData/codegen/boxInline/closureChain"); } + @TestMetadata("defaultMethod") + public void testDefaultMethod() throws Exception { + doTestMultiFileWithInlineCheck("compiler/testData/codegen/boxInline/defaultMethod"); + } + @TestMetadata("extension") public void testExtension() throws Exception { doTestMultiFileWithInlineCheck("compiler/testData/codegen/boxInline/extension"); @@ -126,6 +131,11 @@ public class BlackBoxInlineCodegenTestGenerated extends AbstractBlackBoxCodegenT doTestMultiFileWithInlineCheck("compiler/testData/codegen/boxInline/inlineChain"); } + @TestMetadata("inlineInDefaultParameter") + public void testInlineInDefaultParameter() throws Exception { + doTestMultiFileWithInlineCheck("compiler/testData/codegen/boxInline/inlineInDefaultParameter"); + } + @TestMetadata("lambdaClassClash") public void testLambdaClassClash() throws Exception { doTestMultiFileWithInlineCheck("compiler/testData/codegen/boxInline/lambdaClassClash"); @@ -221,6 +231,11 @@ public class BlackBoxInlineCodegenTestGenerated extends AbstractBlackBoxCodegenT doTestMultiFileWithInlineCheck("compiler/testData/codegen/boxInline/simpleCapturingInPackage"); } + @TestMetadata("simpleDefaultMethod") + public void testSimpleDefaultMethod() throws Exception { + doTestMultiFileWithInlineCheck("compiler/testData/codegen/boxInline/simpleDefaultMethod"); + } + @TestMetadata("simpleDouble") public void testSimpleDouble() throws Exception { doTestMultiFileWithInlineCheck("compiler/testData/codegen/boxInline/simpleDouble"); diff --git a/compiler/tests/org/jetbrains/jet/jvm/compiler/CompileKotlinAgainstInlineKotlinTestGenerated.java b/compiler/tests/org/jetbrains/jet/jvm/compiler/CompileKotlinAgainstInlineKotlinTestGenerated.java index 1a2b7552d42..0cd9769af20 100644 --- a/compiler/tests/org/jetbrains/jet/jvm/compiler/CompileKotlinAgainstInlineKotlinTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/jvm/compiler/CompileKotlinAgainstInlineKotlinTestGenerated.java @@ -91,6 +91,11 @@ public class CompileKotlinAgainstInlineKotlinTestGenerated extends AbstractCompi doBoxTestWithInlineCheck("compiler/testData/codegen/boxInline/closureChain"); } + @TestMetadata("defaultMethod") + public void testDefaultMethod() throws Exception { + doBoxTestWithInlineCheck("compiler/testData/codegen/boxInline/defaultMethod"); + } + @TestMetadata("extension") public void testExtension() throws Exception { doBoxTestWithInlineCheck("compiler/testData/codegen/boxInline/extension"); @@ -126,6 +131,11 @@ public class CompileKotlinAgainstInlineKotlinTestGenerated extends AbstractCompi doBoxTestWithInlineCheck("compiler/testData/codegen/boxInline/inlineChain"); } + @TestMetadata("inlineInDefaultParameter") + public void testInlineInDefaultParameter() throws Exception { + doBoxTestWithInlineCheck("compiler/testData/codegen/boxInline/inlineInDefaultParameter"); + } + @TestMetadata("lambdaClassClash") public void testLambdaClassClash() throws Exception { doBoxTestWithInlineCheck("compiler/testData/codegen/boxInline/lambdaClassClash"); @@ -221,6 +231,11 @@ public class CompileKotlinAgainstInlineKotlinTestGenerated extends AbstractCompi doBoxTestWithInlineCheck("compiler/testData/codegen/boxInline/simpleCapturingInPackage"); } + @TestMetadata("simpleDefaultMethod") + public void testSimpleDefaultMethod() throws Exception { + doBoxTestWithInlineCheck("compiler/testData/codegen/boxInline/simpleDefaultMethod"); + } + @TestMetadata("simpleDouble") public void testSimpleDouble() throws Exception { doBoxTestWithInlineCheck("compiler/testData/codegen/boxInline/simpleDouble");