Default function generation refactoring

This commit is contained in:
Mikhael Bogdanov
2013-05-08 11:32:09 +04:00
parent 702dadccf4
commit 6da8ba3fec
2 changed files with 62 additions and 130 deletions
@@ -137,11 +137,11 @@ public class AsmUtil {
} }
public static boolean isStaticMethod(OwnerKind kind, FunctionDescriptor functionDescriptor) { public static boolean isStaticMethod(OwnerKind kind, FunctionDescriptor functionDescriptor) {
return isStatic(kind) || kind == OwnerKind.TRAIT_IMPL || JetTypeMapper.isAccessor(functionDescriptor); return isStatic(kind) || JetTypeMapper.isAccessor(functionDescriptor);
} }
public static boolean isStatic(OwnerKind kind) { public static boolean isStatic(OwnerKind kind) {
return kind == OwnerKind.NAMESPACE || kind instanceof OwnerKind.StaticDelegateKind; return kind == OwnerKind.NAMESPACE || kind instanceof OwnerKind.StaticDelegateKind || kind == OwnerKind.TRAIT_IMPL;
} }
public static int getMethodAsmFlags(FunctionDescriptor functionDescriptor, OwnerKind kind) { public static int getMethodAsmFlags(FunctionDescriptor functionDescriptor, OwnerKind kind) {
@@ -41,7 +41,6 @@ import org.jetbrains.jet.codegen.state.JetTypeMapperMode;
import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.psi.JetNamedFunction; import org.jetbrains.jet.lang.psi.JetNamedFunction;
import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
import org.jetbrains.jet.lang.resolve.java.JvmAbi; import org.jetbrains.jet.lang.resolve.java.JvmAbi;
import org.jetbrains.jet.lang.resolve.java.JvmClassName; import org.jetbrains.jet.lang.resolve.java.JvmClassName;
import org.jetbrains.jet.lang.resolve.java.JvmStdlibNames; import org.jetbrains.jet.lang.resolve.java.JvmStdlibNames;
@@ -519,12 +518,12 @@ public class FunctionCodegen extends GenerationStateAware {
static void generateDefaultIfNeeded( static void generateDefaultIfNeeded(
@NotNull MethodContext owner, @NotNull MethodContext owner,
GenerationState state, @NotNull GenerationState state,
ClassBuilder v, @NotNull ClassBuilder v,
JvmMethodSignature signature, @NotNull JvmMethodSignature signature,
@NotNull FunctionDescriptor functionDescriptor, @NotNull FunctionDescriptor functionDescriptor,
OwnerKind kind, @NotNull OwnerKind kind,
DefaultParameterValueLoader loadStrategy @NotNull DefaultParameterValueLoader loadStrategy
) { ) {
DeclarationDescriptor contextClass = owner.getContextDescriptor().getContainingDeclaration(); DeclarationDescriptor contextClass = owner.getContextDescriptor().getContainingDeclaration();
@@ -538,21 +537,10 @@ public class FunctionCodegen extends GenerationStateAware {
return; return;
} }
ReceiverParameterDescriptor receiverParameter = functionDescriptor.getReceiverParameter();
boolean hasReceiver = receiverParameter != null;
// Has outer in local variables (constructor for inner class)
boolean hasOuter = functionDescriptor instanceof ConstructorDescriptor &&
CodegenBinding.canHaveOuter(state.getBindingContext(), ((ConstructorDescriptor) functionDescriptor).getContainingDeclaration());
boolean isStatic = isStatic(kind); boolean isStatic = isStatic(kind);
Method jvmSignature = signature.getAsmMethod(); Method jvmSignature = signature.getAsmMethod();
if (kind == OwnerKind.TRAIT_IMPL) {
String correctedDescr = "(" + jvmSignature.getDescriptor().substring(jvmSignature.getDescriptor().indexOf(";") + 1);
jvmSignature = new Method(jvmSignature.getName(), correctedDescr);
}
int flags = ACC_PUBLIC | ACC_SYNTHETIC; // TODO. int flags = ACC_PUBLIC | ACC_SYNTHETIC; // TODO.
JvmClassName ownerInternalName; JvmClassName ownerInternalName;
@@ -573,86 +561,63 @@ public class FunctionCodegen extends GenerationStateAware {
MethodVisitor mv = v.newMethod(null, flags | (isConstructor ? 0 : ACC_STATIC), MethodVisitor mv = v.newMethod(null, flags | (isConstructor ? 0 : ACC_STATIC),
isConstructor ? "<init>" : jvmSignature.getName() + JvmAbi.DEFAULT_PARAMS_IMPL_SUFFIX, isConstructor ? "<init>" : jvmSignature.getName() + JvmAbi.DEFAULT_PARAMS_IMPL_SUFFIX,
descriptor, null, null); descriptor, null, null);
InstructionAdapter iv = new InstructionAdapter(mv);
if (state.getClassBuilderMode() == ClassBuilderMode.STUBS) { if (state.getClassBuilderMode() == ClassBuilderMode.STUBS) {
genStubCode(mv); genStubCode(mv);
} }
else if (state.getClassBuilderMode() == ClassBuilderMode.FULL) { else if (state.getClassBuilderMode() == ClassBuilderMode.FULL) {
generateDefaultImpl(owner, state, jvmSignature, functionDescriptor, kind, receiverParameter, hasReceiver, hasOuter, isStatic, generateDefaultImpl(owner, state, signature, functionDescriptor, kind, isStatic, mv, loadStrategy);
ownerInternalName,
isConstructor, mv, iv, loadStrategy);
} }
} }
private static void generateDefaultImpl( private static void generateDefaultImpl(
MethodContext owner, @NotNull MethodContext methodContext,
GenerationState state, @NotNull GenerationState state,
Method jvmSignature, @NotNull JvmMethodSignature signature,
FunctionDescriptor functionDescriptor, @NotNull FunctionDescriptor functionDescriptor,
OwnerKind kind, @NotNull OwnerKind kind,
ReceiverParameterDescriptor receiverParameter,
boolean hasReceiver, boolean hasOuter,
boolean aStatic, boolean aStatic,
JvmClassName ownerInternalName, @NotNull MethodVisitor mv,
boolean constructor, @NotNull DefaultParameterValueLoader loadStrategy
MethodVisitor mv,
InstructionAdapter iv,
DefaultParameterValueLoader loadStrategy
) { ) {
mv.visitCode(); mv.visitCode();
boolean isEnumConstructor = functionDescriptor instanceof ConstructorDescriptor && FrameMap frameMap = new FrameMap();
DescriptorUtils.isEnumClass(functionDescriptor.getContainingDeclaration());
FrameMap frameMap = owner.prepareFrame(state.getTypeMapper()); if (!aStatic) {
if (kind instanceof OwnerKind.StaticDelegateKind) {
frameMap.leaveTemp(OBJECT_TYPE);
}
if (hasOuter) {
frameMap.enterTemp(OBJECT_TYPE); frameMap.enterTemp(OBJECT_TYPE);
} }
if (isEnumConstructor) { Method jvmSignature = signature.getAsmMethod();
frameMap.enterTemp(OBJECT_TYPE); ExpressionCodegen codegen = new ExpressionCodegen(mv, frameMap, jvmSignature.getReturnType(), methodContext, state);
frameMap.enterTemp(Type.INT_TYPE);
}
ExpressionCodegen codegen = new ExpressionCodegen(mv, frameMap, jvmSignature.getReturnType(), owner, state);
Type receiverType = null;
if (hasReceiver) {
receiverType = state.getTypeMapper().mapType(receiverParameter.getType());
}
int extraInLocalVariablesTable = getSizeOfExplicitArgumentsInLocalVariablesTable(aStatic, hasOuter, isEnumConstructor, receiverType);
int countOfExtraVarsInMethodArgs = getCountOfExplicitArgumentsInMethodArguments(hasOuter, hasReceiver, isEnumConstructor);
Type[] argTypes = jvmSignature.getArgumentTypes(); Type[] argTypes = jvmSignature.getArgumentTypes();
List<ValueParameterDescriptor> paramDescrs = functionDescriptor.getValueParameters(); List<ValueParameterDescriptor> paramDescrs = functionDescriptor.getValueParameters();
int paramSizeInLocalVariablesTable = 0; Iterator<ValueParameterDescriptor> iterator = paramDescrs.iterator();
for (int i = 0; i < paramDescrs.size(); i++) {
Type argType = argTypes[i + countOfExtraVarsInMethodArgs]; int countOfExtraVarsInMethodArgs = 0;
int size = argType.getSize(); List<JvmMethodParameterSignature> params = signature.getKotlinParameterTypes();
frameMap.enter(paramDescrs.get(i), argType);
paramSizeInLocalVariablesTable += size; for (int i = 0; i < params.size(); i++) {
JvmMethodParameterSignature parameterSignature = params.get(i);
if (parameterSignature.getKind() != JvmMethodParameterKind.VALUE) {
countOfExtraVarsInMethodArgs++;
frameMap.enterTemp(parameterSignature.getAsmType());
} else {
frameMap.enter(iterator.next(), parameterSignature.getAsmType());
}
} }
int maskIndex = extraInLocalVariablesTable + paramSizeInLocalVariablesTable; int maskIndex = frameMap.enterTemp(Type.INT_TYPE);
loadExplicitArgumentsOnStack(iv, OBJECT_TYPE, receiverType, ownerInternalName.getAsmType(), aStatic, hasOuter, isEnumConstructor); InstructionAdapter iv = new InstructionAdapter(mv);
loadExplicitArgumentsOnStack(iv, OBJECT_TYPE, aStatic, signature);
int indexInLocalVariablesTable = extraInLocalVariablesTable;
for (int index = 0; index < paramDescrs.size(); index++) { for (int index = 0; index < paramDescrs.size(); index++) {
ValueParameterDescriptor parameterDescriptor = paramDescrs.get(index); ValueParameterDescriptor parameterDescriptor = paramDescrs.get(index);
Type t = argTypes[countOfExtraVarsInMethodArgs + index]; Type t = argTypes[countOfExtraVarsInMethodArgs + index];
if (frameMap.getIndex(parameterDescriptor) < 0) {
frameMap.enter(parameterDescriptor, t);
}
if (parameterDescriptor.declaresDefaultValue()) { if (parameterDescriptor.declaresDefaultValue()) {
iv.load(maskIndex, Type.INT_TYPE); iv.load(maskIndex, Type.INT_TYPE);
iv.iconst(1 << index); iv.iconst(1 << index);
@@ -668,81 +633,48 @@ public class FunctionCodegen extends GenerationStateAware {
iv.mark(loadArg); iv.mark(loadArg);
} }
iv.load(indexInLocalVariablesTable, t); iv.load(frameMap.getIndex(parameterDescriptor), t);
indexInLocalVariablesTable += t.getSize();
} }
String internalName = ownerInternalName.getInternalName(); CallableMethod method = null;
String jvmSignatureName = jvmSignature.getName(); if (functionDescriptor instanceof ConstructorDescriptor) {
String jvmSignatureDescriptor = jvmSignature.getDescriptor(); method = state.getTypeMapper().mapToCallableMethod((ConstructorDescriptor) functionDescriptor);
if (!aStatic) { } else {
if (kind == OwnerKind.TRAIT_IMPL) { method = state.getTypeMapper()
iv.invokeinterface(internalName, jvmSignatureName, jvmSignatureDescriptor); .mapToCallableMethod(functionDescriptor, false, isCallInsideSameClassAsDeclared(functionDescriptor, methodContext),
} isCallInsideSameModuleAsDeclared(functionDescriptor, methodContext), OwnerKind.IMPLEMENTATION);
else {
if (!constructor && functionDescriptor.getVisibility() != Visibilities.PRIVATE) {
iv.invokevirtual(internalName, jvmSignatureName, jvmSignatureDescriptor);
}
else {
iv.invokespecial(internalName, jvmSignatureName, jvmSignatureDescriptor);
}
}
}
else {
iv.invokestatic(internalName, jvmSignatureName, jvmSignatureDescriptor);
} }
iv.visitMethodInsn(method.getInvokeOpcode(), method.getOwner().getInternalName(), method.getSignature().getAsmMethod().getName(),
method.getSignature().getAsmMethod().getDescriptor());
iv.areturn(jvmSignature.getReturnType()); iv.areturn(jvmSignature.getReturnType());
endVisit(mv, "default method", callableDescriptorToDeclaration(state.getBindingContext(), functionDescriptor)); endVisit(mv, "default method", callableDescriptorToDeclaration(state.getBindingContext(), functionDescriptor));
mv.visitEnd(); mv.visitEnd();
} }
private static int getSizeOfExplicitArgumentsInLocalVariablesTable(
private static void loadExplicitArgumentsOnStack(
@NotNull InstructionAdapter iv,
@NotNull Type ownerType,
boolean isStatic, boolean isStatic,
boolean hasOuter, @NotNull JvmMethodSignature signature
boolean isEnumConstructor,
@Nullable Type receiverType
) { ) {
int result = 0;
if (!isStatic) result++;
if (receiverType != null) result += receiverType.getSize();
if (hasOuter) result++;
if (isEnumConstructor) result += 2;
return result;
}
private static int getCountOfExplicitArgumentsInMethodArguments(
boolean hasOuter,
boolean hasReceiver,
boolean isEnumConstructor
) {
int result = 0;
if (hasReceiver) result++;
if (hasOuter) result++;
if (isEnumConstructor) result += 2;
return result;
}
private static void loadExplicitArgumentsOnStack(@NotNull InstructionAdapter iv,
@NotNull Type ownerType, @Nullable Type receiverType, @NotNull Type outerType,
boolean isStatic, boolean hasOuter, boolean isEnumConstructor) {
int var = 0; int var = 0;
if (!isStatic) { if (!isStatic) {
iv.load(var++, ownerType); iv.load(var, ownerType);
var += ownerType.getSize();
} }
if (hasOuter) { List<JvmMethodParameterSignature> params = signature.getKotlinParameterTypes();
iv.load(var++, outerType); for (int i = 0; i < params.size(); i++) {
} JvmMethodParameterSignature parameterSignature = params.get(i);
if (parameterSignature.getKind() != JvmMethodParameterKind.VALUE) {
if (isEnumConstructor) { Type type = parameterSignature.getAsmType();
iv.load(var++, OBJECT_TYPE); iv.load(var, type);
iv.load(var++, Type.INT_TYPE); var += type.getSize();
} }
if (receiverType != null) {
iv.load(var, receiverType);
} }
} }