Suppot inlining default methods, inlining function into its default.
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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 ("<init>".equals(method.getName())) {
|
||||
v.visitMethodInsn(INVOKESPECIAL, defaultImplOwner.getInternalName(), "<init>", 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);
|
||||
}
|
||||
|
||||
|
||||
@@ -175,7 +175,9 @@ public class ClosureCodegen extends ParentCodegenAwareImpl {
|
||||
typeMapper.mapSignature(funDescriptor),
|
||||
funDescriptor,
|
||||
context.getContextKind(),
|
||||
DefaultParameterValueLoader.DEFAULT);
|
||||
DefaultParameterValueLoader.DEFAULT,
|
||||
null);
|
||||
|
||||
|
||||
cv.done();
|
||||
}
|
||||
|
||||
@@ -2078,8 +2078,8 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> 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<StackValue, StackValue> 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<StackValue, StackValue> implem
|
||||
return mask;
|
||||
}
|
||||
|
||||
private static boolean hasDefaultArguments(@NotNull ResolvedCall<?> resolvedCall) {
|
||||
List<ResolvedValueArgument> 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();
|
||||
|
||||
|
||||
@@ -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 = "<init>".equals(jvmSignature.getName());
|
||||
if (!isStatic && !isConstructor) {
|
||||
descriptor = descriptor.replace("(", "(" + ownerType.getDescriptor());
|
||||
}
|
||||
|
||||
Method defaultMethod = new Method(isConstructor ? "<init>" : 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<ValueParameterDescriptor> 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));
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 = "<init>".equals(jvmSignature.getName());
|
||||
if (!isStatic(kind) && !isConstructor) {
|
||||
descriptor = descriptor.replace("(", "(" + ownerType.getDescriptor());
|
||||
}
|
||||
|
||||
return new Method(isConstructor ? "<init>" : 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
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package test
|
||||
|
||||
|
||||
inline fun <T> simpleFun(arg: String = "O", lambda: (String) -> T): T {
|
||||
return lambda(arg)
|
||||
}
|
||||
|
||||
|
||||
inline fun <T> simpleFunR(lambda: (String) -> T, arg: String = "O"): T {
|
||||
return lambda(arg)
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package test
|
||||
|
||||
inline fun getStringInline(): String {
|
||||
return "OK"
|
||||
}
|
||||
@@ -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"
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package test
|
||||
|
||||
inline fun emptyFun(arg: String = "O") {
|
||||
|
||||
}
|
||||
|
||||
inline fun simpleFun(arg: String = "O"): String {
|
||||
val r = arg;
|
||||
return r;
|
||||
}
|
||||
|
||||
+15
@@ -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");
|
||||
|
||||
+15
@@ -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");
|
||||
|
||||
Reference in New Issue
Block a user