From aa2f2742d5addfab04b5109b0defe79d05ec4f2a Mon Sep 17 00:00:00 2001 From: Stepan Koltsov Date: Fri, 13 Jan 2012 03:55:10 +0400 Subject: [PATCH] BothSignatureWriter should write JVM signatures too (this simplifies body of JetTypeMapper) --- .../jet/codegen/BothSignatureWriter.java | 120 ++++++++- .../jetbrains/jet/codegen/CallableMethod.java | 6 +- .../jetbrains/jet/codegen/ClosureCodegen.java | 45 +++- .../jet/codegen/FunctionCodegen.java | 3 +- .../codegen/ImplementationBodyCodegen.java | 27 +- .../jetbrains/jet/codegen/JetTypeMapper.java | 241 ++++++++---------- .../jet/codegen/JvmMethodParameterKind.java | 15 ++ .../codegen/JvmMethodParameterSignature.java | 38 +++ .../jet/codegen/JvmMethodSignature.java | 57 ++++- 9 files changed, 377 insertions(+), 175 deletions(-) create mode 100644 compiler/backend/src/org/jetbrains/jet/codegen/JvmMethodParameterKind.java create mode 100644 compiler/backend/src/org/jetbrains/jet/codegen/JvmMethodParameterSignature.java diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/BothSignatureWriter.java b/compiler/backend/src/org/jetbrains/jet/codegen/BothSignatureWriter.java index 3024b076800..66273168bdc 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/BothSignatureWriter.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/BothSignatureWriter.java @@ -3,11 +3,12 @@ package org.jetbrains.jet.codegen; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.resolve.java.JetSignatureUtils; +import org.jetbrains.jet.lang.types.Variance; import org.jetbrains.jet.rt.signature.JetSignatureAdapter; import org.jetbrains.jet.rt.signature.JetSignatureReader; import org.jetbrains.jet.rt.signature.JetSignatureWriter; -import org.jetbrains.jet.lang.types.Variance; import org.objectweb.asm.Type; +import org.objectweb.asm.commons.Method; import org.objectweb.asm.signature.SignatureVisitor; import org.objectweb.asm.signature.SignatureWriter; import org.objectweb.asm.util.CheckSignatureAdapter; @@ -40,6 +41,7 @@ public class BothSignatureWriter { TYPE_PARAMETERS, PARAMETERS, + PARAMETER, RETURN_TYPE, METHOD_END, @@ -55,16 +57,26 @@ public class BothSignatureWriter { private String kotlinClassParameters; private String kotlinClassSignature; - private List kotlinParameterTypes = new ArrayList(); + private List kotlinParameterTypes = new ArrayList(); private String kotlinReturnType; + + private int jvmCurrentTypeArrayLevel; + private Type jvmCurrentType; + private Type jvmReturnType; + + private JvmMethodParameterKind currentParameterKind; private final Mode mode; + private final boolean needGenerics; + private State state = State.START; private boolean generic = false; - public BothSignatureWriter(Mode mode) { + public BothSignatureWriter(Mode mode, boolean needGenerics) { this.mode = mode; + this.needGenerics = needGenerics; + if (DEBUG_SIGNATURE_WRITER) { signatureVisitor = new CheckSignatureAdapter(mode.asmType, signatureWriter); } else { @@ -152,11 +164,27 @@ public class BothSignatureWriter { } signatureVisitor().visitBaseType(c); jetSignatureWriter.visitBaseType(c, nullable); + writeAsmType0(Type.getType(String.valueOf(c))); + } + + private String makeArrayPrefix() { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < jvmCurrentTypeArrayLevel; ++i) { + sb.append('['); + } + return sb.toString(); + } + + private void writeAsmType0(Type type) { + if (jvmCurrentType == null) { + jvmCurrentType = Type.getType(makeArrayPrefix() + type.getDescriptor()); + } } public void writeClassBegin(String internalName, boolean nullable) { signatureVisitor().visitClassType(internalName); jetSignatureWriter.visitClassType(internalName, nullable); + writeAsmType0(Type.getObjectType(internalName)); } public void writeClassEnd() { @@ -167,6 +195,9 @@ public class BothSignatureWriter { public void writeArrayType(boolean nullable) { push(signatureVisitor().visitArrayType()); jetSignatureWriter.visitArrayType(nullable); + if (jvmCurrentType == null) { + ++jvmCurrentTypeArrayLevel; + } } public void writeArrayEnd() { @@ -183,10 +214,11 @@ public class BothSignatureWriter { pop(); } - public void writeTypeVariable(final String name, boolean nullable) { + public void writeTypeVariable(final String name, boolean nullable, Type asmType) { signatureVisitor().visitTypeVariable(name); jetSignatureWriter.visitTypeVariable(name, nullable); generic = true; + writeAsmType0(asmType); } public void writeFormalTypeParameter(final String name, Variance variance) { @@ -202,7 +234,7 @@ public class BothSignatureWriter { jetSignatureWriter.visitFormalTypeParameterEnd(); } - public void writerFormalTypeParametersStart() { + public void writeFormalTypeParametersStart() { checkTopLevel(); transitionState(State.START, State.TYPE_PARAMETERS); jetSignatureWriter = new JetSignatureWriter(); @@ -242,28 +274,59 @@ public class BothSignatureWriter { public void writeParametersStart() { transitionState(State.TYPE_PARAMETERS, State.PARAMETERS); + + // hacks + jvmCurrentType = null; + jvmCurrentTypeArrayLevel = 0; } public void writeParametersEnd() { checkState(State.PARAMETERS); } - public void writeParameterType() { + public void writeParameterType(JvmMethodParameterKind parameterKind) { + transitionState(State.PARAMETERS, State.PARAMETER); + push(signatureVisitor().visitParameterType()); jetSignatureWriter = new JetSignatureWriter(); + if (jvmCurrentType != null || jvmCurrentTypeArrayLevel != 0) { + throw new IllegalStateException(); + } + + if (currentParameterKind != null) { + throw new IllegalStateException(); + } + this.currentParameterKind = parameterKind; + //jetSignatureWriter.visitParameterType(); } public void writeParameterTypeEnd() { pop(); + + if (jvmCurrentType == null) { + throw new IllegalStateException(); + } + String signature = jetSignatureWriter.toString(); - kotlinParameterTypes.add(signature); + kotlinParameterTypes.add(new JvmMethodParameterSignature(jvmCurrentType, signature, currentParameterKind)); if (DEBUG_SIGNATURE_WRITER) { new JetSignatureReader(signature).acceptTypeOnly(new JetSignatureAdapter()); } + currentParameterKind = null; + jvmCurrentType = null; + jvmCurrentTypeArrayLevel = 0; + jetSignatureWriter = null; + transitionState(State.PARAMETER, State.PARAMETERS); + } + + public void writeTypeInfoParameter() { + writeParameterType(JvmMethodParameterKind.TYPE_INFO); + writeAsmType(JetTypeMapper.TYPE_TYPEINFO, false); + writeParameterTypeEnd(); } public void writeReturnType() { @@ -271,6 +334,10 @@ public class BothSignatureWriter { jetSignatureWriter = new JetSignatureWriter(); + if (jvmCurrentType != null) { + throw new IllegalStateException(); + } + push(signatureVisitor().visitReturnType()); //jetSignatureWriter.visitReturnType(); } @@ -280,6 +347,14 @@ public class BothSignatureWriter { kotlinReturnType = jetSignatureWriter.toString(); + if (jvmCurrentType == null) { + throw new IllegalStateException(); + } + + jvmReturnType = jvmCurrentType; + jvmCurrentType = null; + jvmCurrentTypeArrayLevel = 0; + if (DEBUG_SIGNATURE_WRITER) { new JetSignatureReader(kotlinReturnType).acceptTypeOnly(new JetSignatureAdapter()); } @@ -288,6 +363,12 @@ public class BothSignatureWriter { transitionState(State.RETURN_TYPE, State.METHOD_END); } + public void writeVoidReturn() { + writeReturnType(); + writeAsmType(Type.VOID_TYPE, false); + writeReturnTypeEnd(); + } + public void writeSupersStart() { transitionState(State.TYPE_PARAMETERS, State.SUPERS); jetSignatureWriter = new JetSignatureWriter(); @@ -333,6 +414,14 @@ public class BothSignatureWriter { + @NotNull + public Method makeAsmMethod(String name) { + List jvmParameterTypes = new ArrayList(kotlinParameterTypes.size()); + for (JvmMethodParameterSignature p : kotlinParameterTypes) { + jvmParameterTypes.add(p.getAsmType()); + } + return new Method(name, jvmReturnType, jvmParameterTypes.toArray(new Type[0])); + } @Nullable public String makeJavaString() { @@ -344,7 +433,7 @@ public class BothSignatureWriter { } @NotNull - public List makeKotlinParameterTypes() { + public List makeKotlinParameterTypes() { checkState(State.METHOD_END); // TODO: return nulls if equal to #makeJavaString return kotlinParameterTypes; @@ -373,4 +462,19 @@ public class BothSignatureWriter { return kotlinClassParameters + kotlinClassSignature; } + @NotNull + public JvmMethodSignature makeJvmMethodSignature(String name) { + if (needGenerics) { + return new JvmMethodSignature( + makeAsmMethod(name), + makeJavaString(), + makeKotlinMethodTypeParameters(), + makeKotlinParameterTypes(), + makeKotlinReturnTypeSignature() + ); + } else { + return new JvmMethodSignature(makeAsmMethod(name), makeKotlinParameterTypes()); + } + } + } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/CallableMethod.java b/compiler/backend/src/org/jetbrains/jet/codegen/CallableMethod.java index f93b818b852..fe479826648 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/CallableMethod.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/CallableMethod.java @@ -19,17 +19,15 @@ public class CallableMethod implements Callable { private String owner; private final JvmMethodSignature signature; private int invokeOpcode; - private final List valueParameterTypes; private ClassDescriptor thisClass = null; private CallableDescriptor receiverFunction = null; private Type generateCalleeType = null; - public CallableMethod(String owner, JvmMethodSignature signature, int invokeOpcode, List valueParameterTypes) { + public CallableMethod(String owner, JvmMethodSignature signature, int invokeOpcode) { this.owner = owner; this.signature = signature; this.invokeOpcode = invokeOpcode; - this.valueParameterTypes = valueParameterTypes; } public String getOwner() { @@ -45,7 +43,7 @@ public class CallableMethod implements Callable { } public List getValueParameterTypes() { - return valueParameterTypes; + return signature.getValueParameterTypes(); } public void setNeedsReceiver(@Nullable CallableDescriptor receiverClass) { diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java index d49a9befa10..43f89484007 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java @@ -39,23 +39,40 @@ public class ClosureCodegen extends ObjectOrClosureCodegen { bindingContext = state.getBindingContext(); } - public static Method erasedInvokeSignature(FunctionDescriptor fd) { + public static JvmMethodSignature erasedInvokeSignature(FunctionDescriptor fd) { + + BothSignatureWriter signatureWriter = new BothSignatureWriter(BothSignatureWriter.Mode.METHOD, false); + + signatureWriter.writeFormalTypeParametersStart(); + signatureWriter.writeFormalTypeParametersEnd(); + boolean isExtensionFunction = fd.getReceiverParameter().exists(); int paramCount = fd.getValueParameters().size(); if (isExtensionFunction) { paramCount++; } + + signatureWriter.writeParametersStart(); + + for (int i = 0; i < paramCount; ++i) { + signatureWriter.writeParameterType(JvmMethodParameterKind.VALUE); + signatureWriter.writeAsmType(JetTypeMapper.TYPE_OBJECT, true); + signatureWriter.writeParameterTypeEnd(); + } + + signatureWriter.writeParametersEnd(); - Type[] args = new Type[paramCount]; - Arrays.fill(args, JetTypeMapper.TYPE_OBJECT); - return new Method("invoke", JetTypeMapper.TYPE_OBJECT, args); + signatureWriter.writeReturnType(); + signatureWriter.writeAsmType(JetTypeMapper.TYPE_OBJECT, true); + signatureWriter.writeReturnTypeEnd(); + + return signatureWriter.makeJvmMethodSignature("invoke"); } public static CallableMethod asCallableMethod(FunctionDescriptor fd) { - Method descriptor = erasedInvokeSignature(fd); + JvmMethodSignature descriptor = erasedInvokeSignature(fd); String owner = getInternalClassName(fd); - JvmMethodSignature jvmMethodSignature = new JvmMethodSignature(descriptor, null, null, null, ""); - final CallableMethod result = new CallableMethod(owner, jvmMethodSignature, INVOKEVIRTUAL, Arrays.asList(descriptor.getArgumentTypes())); + final CallableMethod result = new CallableMethod(owner, descriptor, INVOKEVIRTUAL); if (fd.getReceiverParameter().exists()) { result.setNeedsReceiver(fd); } @@ -63,8 +80,8 @@ public class ClosureCodegen extends ObjectOrClosureCodegen { return result; } - public Method invokeSignature(FunctionDescriptor fd) { - return state.getTypeMapper().mapSignature("invoke", fd).getAsmMethod(); + public JvmMethodSignature invokeSignature(FunctionDescriptor fd) { + return state.getTypeMapper().mapSignature("invoke", fd); } public GeneratedAnonymousClassDescriptor gen(JetFunctionLiteralExpression fun) { @@ -166,19 +183,19 @@ public class ClosureCodegen extends ObjectOrClosureCodegen { final CodegenContext.ClosureContext closureContext = context.intoClosure(funDescriptor, function, name, this, state.getTypeMapper()); FunctionCodegen fc = new FunctionCodegen(closureContext, cv, state); - JvmMethodSignature jvmMethodSignature = new JvmMethodSignature(invokeSignature(funDescriptor), null, null, null, ""); + JvmMethodSignature jvmMethodSignature = invokeSignature(funDescriptor); fc.generateMethod(body, jvmMethodSignature, null, funDescriptor); return closureContext.outerWasUsed; } private void generateBridge(String className, FunctionDescriptor funDescriptor, JetExpression fun, ClassBuilder cv) { - final Method bridge = erasedInvokeSignature(funDescriptor); - final Method delegate = invokeSignature(funDescriptor); + final JvmMethodSignature bridge = erasedInvokeSignature(funDescriptor); + final Method delegate = invokeSignature(funDescriptor).getAsmMethod(); - if(bridge.getDescriptor().equals(delegate.getDescriptor())) + if(bridge.getAsmMethod().getDescriptor().equals(delegate.getDescriptor())) return; - final MethodVisitor mv = cv.newMethod(fun, ACC_PUBLIC, "invoke", bridge.getDescriptor(), null, new String[0]); + final MethodVisitor mv = cv.newMethod(fun, ACC_PUBLIC, "invoke", bridge.getAsmMethod().getDescriptor(), null, new String[0]); if (cv.generateCode()) { mv.visitCode(); diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java index 8052f4be10e..8db55f9de7c 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java @@ -1,6 +1,7 @@ package org.jetbrains.jet.codegen; import com.intellij.psi.PsiElement; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.psi.*; @@ -144,7 +145,7 @@ public class FunctionCodegen { av.visit(JvmStdlibNames.JET_VALUE_PARAMETER_NULLABLE_FIELD, true); } if (jvmSignature.getKotlinParameterTypes() != null && jvmSignature.getKotlinParameterTypes().get(i) != null) { - av.visit(JvmStdlibNames.JET_VALUE_PARAMETER_TYPE_FIELD, jvmSignature.getKotlinParameterTypes().get(i + start)); + av.visit(JvmStdlibNames.JET_VALUE_PARAMETER_TYPE_FIELD, jvmSignature.getKotlinParameterTypes().get(i + start).getKotlinSignature()); } av.visitEnd(); } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java index 5a51059fe62..336064107e7 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java @@ -115,7 +115,8 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { LinkedHashSet superInterfacesLinkedHashSet = new LinkedHashSet(); - BothSignatureWriter signatureVisitor = new BothSignatureWriter(BothSignatureWriter.Mode.CLASS); + // TODO: generics signature is not always needed + BothSignatureWriter signatureVisitor = new BothSignatureWriter(BothSignatureWriter.Mode.CLASS, true); { // type parameters @@ -351,17 +352,31 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { Method constructorMethod; CallableMethod callableMethod; if (constructorDescriptor == null) { - List parameterTypes = new ArrayList(); + + BothSignatureWriter signatureWriter = new BothSignatureWriter(BothSignatureWriter.Mode.METHOD, false); + + signatureWriter.writeFormalTypeParametersStart(); + signatureWriter.writeFormalTypeParametersEnd(); + + signatureWriter.writeParametersStart(); + if (CodegenUtil.hasThis0(descriptor)) { - parameterTypes.add(typeMapper.mapType(CodegenUtil.getOuterClassDescriptor(descriptor).getDefaultType(), OwnerKind.IMPLEMENTATION)); + signatureWriter.writeParameterType(JvmMethodParameterKind.THIS0); + typeMapper.mapType(CodegenUtil.getOuterClassDescriptor(descriptor).getDefaultType(), OwnerKind.IMPLEMENTATION, signatureWriter, false); + signatureWriter.writeParameterTypeEnd(); } if (CodegenUtil.requireTypeInfoConstructorArg(descriptor.getDefaultType())) { - parameterTypes.add(JetTypeMapper.TYPE_TYPEINFO); + signatureWriter.writeTypeInfoParameter(); } - constructorMethod = new Method("", Type.VOID_TYPE, parameterTypes.toArray(new Type[parameterTypes.size()])); - callableMethod = new CallableMethod("", new JvmMethodSignature(constructorMethod, null, null, null, "") /* TODO */, Opcodes.INVOKESPECIAL, Collections.emptyList()); + signatureWriter.writeParametersEnd(); + + signatureWriter.writeVoidReturn(); + + JvmMethodSignature jvmMethodSignature = signatureWriter.makeJvmMethodSignature(""); + constructorMethod = jvmMethodSignature.getAsmMethod(); + callableMethod = new CallableMethod("", jvmMethodSignature, Opcodes.INVOKESPECIAL); } else { callableMethod = typeMapper.mapToCallableMethod(constructorDescriptor, kind); diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java b/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java index f7f0f310f2a..41b27664c82 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java @@ -306,12 +306,13 @@ public class JetTypeMapper { } if (descriptor instanceof TypeParameterDescriptor) { + + Type type = mapType(((TypeParameterDescriptor) descriptor).getUpperBoundsAsType(), kind); if (signatureVisitor != null) { TypeParameterDescriptor typeParameterDescriptor = (TypeParameterDescriptor) jetType.getConstructor().getDeclarationDescriptor(); - signatureVisitor.writeTypeVariable(typeParameterDescriptor.getName(), jetType.isNullable()); + signatureVisitor.writeTypeVariable(typeParameterDescriptor.getName(), jetType.isNullable(), type); } - - return mapType(((TypeParameterDescriptor) descriptor).getUpperBoundsAsType(), kind); + return type; } throw new UnsupportedOperationException("Unknown type " + jetType); @@ -355,8 +356,7 @@ public class JetTypeMapper { return null; final DeclarationDescriptor functionParent = functionDescriptor.getContainingDeclaration(); - final List valueParameterTypes = new ArrayList(); - JvmMethodSignature descriptor = mapSignature(functionDescriptor.getOriginal(), true, valueParameterTypes, kind); + JvmMethodSignature descriptor = mapSignature(functionDescriptor.getOriginal(), true, kind); String owner; int invokeOpcode; ClassDescriptor thisClass; @@ -383,7 +383,7 @@ public class JetTypeMapper { ? (superCall ? Opcodes.INVOKESTATIC : Opcodes.INVOKEINTERFACE) : (superCall ? Opcodes.INVOKESPECIAL : Opcodes.INVOKEVIRTUAL); if(isInterface && superCall) { - descriptor = mapSignature(functionDescriptor.getOriginal(), false, valueParameterTypes, OwnerKind.TRAIT_IMPL); + descriptor = mapSignature(functionDescriptor.getOriginal(), false, OwnerKind.TRAIT_IMPL); } thisClass = (ClassDescriptor) functionParent; } @@ -391,7 +391,7 @@ public class JetTypeMapper { throw new UnsupportedOperationException("unknown function parent"); } - final CallableMethod result = new CallableMethod(owner, descriptor, invokeOpcode, valueParameterTypes); + final CallableMethod result = new CallableMethod(owner, descriptor, invokeOpcode); result.setNeedsThis(thisClass); if(functionDescriptor.getReceiverParameter().exists()) { result.setNeedsReceiver(functionDescriptor); @@ -400,7 +400,7 @@ public class JetTypeMapper { return result; } - private JvmMethodSignature mapSignature(FunctionDescriptor f, boolean needGenericSignature, List valueParameterTypes, OwnerKind kind) { + private JvmMethodSignature mapSignature(FunctionDescriptor f, boolean needGenericSignature, OwnerKind kind) { for (ValueParameterDescriptor valueParameterDescriptor : f.getValueParameters()) { if (valueParameterDescriptor.hasDefaultValue()) { @@ -413,94 +413,57 @@ public class JetTypeMapper { needGenericSignature = false; } - BothSignatureWriter signatureVisitor = null; - if (needGenericSignature) { - signatureVisitor = new BothSignatureWriter(BothSignatureWriter.Mode.METHOD); - } + BothSignatureWriter signatureVisitor = new BothSignatureWriter(BothSignatureWriter.Mode.METHOD, needGenericSignature); writeFormalTypeParameters(f.getTypeParameters(), signatureVisitor); final ReceiverDescriptor receiverTypeRef = f.getReceiverParameter(); final JetType receiverType = !receiverTypeRef.exists() ? null : receiverTypeRef.getType(); final List parameters = f.getValueParameters(); - List parameterTypes = new ArrayList(); + + signatureVisitor.writeParametersStart(); + if(kind == OwnerKind.TRAIT_IMPL) { ClassDescriptor containingDeclaration = (ClassDescriptor) f.getContainingDeclaration(); JetType jetType = TraitImplBodyCodegen.getSuperClass(containingDeclaration, bindingContext); - Type type = mapType(jetType, signatureVisitor); + Type type = mapType(jetType); if(type.getInternalName().equals("java/lang/Object")) { jetType = containingDeclaration.getDefaultType(); - type = mapType(jetType, signatureVisitor); + type = mapType(jetType); } - valueParameterTypes.add(type); - parameterTypes.add(type); + + signatureVisitor.writeParameterType(JvmMethodParameterKind.THIS); + signatureVisitor.writeAsmType(type, jetType.isNullable()); + signatureVisitor.writeParameterTypeEnd(); } + if (receiverType != null) { - if (signatureVisitor != null) { - signatureVisitor.writeParameterType(); - } - parameterTypes.add(mapType(receiverType, signatureVisitor)); - if (signatureVisitor != null) { - signatureVisitor.writeParameterTypeEnd(); - } - } - if (signatureVisitor != null) { - signatureVisitor.writeParametersStart(); + signatureVisitor.writeParameterType(JvmMethodParameterKind.RECEIVER); + mapType(receiverType, signatureVisitor); + signatureVisitor.writeParameterTypeEnd(); } for (TypeParameterDescriptor parameterDescriptor : f.getTypeParameters()) { if(parameterDescriptor.isReified()) { - parameterTypes.add(TYPE_TYPEINFO); - if (signatureVisitor != null) { - signatureVisitor.writeParameterType(); - visitAsmType(signatureVisitor, TYPE_TYPEINFO, false); - signatureVisitor.writeParameterTypeEnd(); - } + signatureVisitor.writeTypeInfoParameter(); } } for (ValueParameterDescriptor parameter : parameters) { - if (signatureVisitor != null) { - signatureVisitor.writeParameterType(); - } - Type type = mapType(parameter.getOutType(), signatureVisitor); - if (signatureVisitor != null) { - signatureVisitor.writeParameterTypeEnd(); - } - valueParameterTypes.add(type); - parameterTypes.add(type); + signatureVisitor.writeParameterType(JvmMethodParameterKind.VALUE); + mapType(parameter.getOutType(), signatureVisitor); + signatureVisitor.writeParameterTypeEnd(); } - - if (signatureVisitor != null) { - signatureVisitor.writeParametersEnd(); - } - - Type returnType; + + signatureVisitor.writeParametersEnd(); + if (f instanceof ConstructorDescriptor) { - returnType = Type.VOID_TYPE; - if (signatureVisitor != null) { - signatureVisitor.writeReturnType(); - visitAsmType(signatureVisitor, Type.VOID_TYPE, false); - signatureVisitor.writeReturnTypeEnd(); - } + signatureVisitor.writeVoidReturn(); } else { - if (signatureVisitor != null) { - signatureVisitor.writeReturnType(); - returnType = mapReturnType(f.getReturnType(), signatureVisitor); - signatureVisitor.writeReturnTypeEnd(); - } - else { - returnType = mapReturnType(f.getReturnType(), null); - } - } - Method method = new Method(f.getName(), returnType, parameterTypes.toArray(new Type[parameterTypes.size()])); - if (signatureVisitor == null) { - return new JvmMethodSignature(method, null, null, null, ""); - } else { - return new JvmMethodSignature(method, signatureVisitor.makeJavaString(), - signatureVisitor.makeKotlinMethodTypeParameters(), - signatureVisitor.makeKotlinParameterTypes(), - signatureVisitor.makeKotlinReturnTypeSignature()); + signatureVisitor.writeReturnType(); + mapReturnType(f.getReturnType(), signatureVisitor); + signatureVisitor.writeReturnTypeEnd(); } + return signatureVisitor.makeJvmMethodSignature(f.getName()); } @@ -509,7 +472,7 @@ public class JetTypeMapper { return; } - signatureVisitor.writerFormalTypeParametersStart(); + signatureVisitor.writeFormalTypeParametersStart(); for (TypeParameterDescriptor typeParameterDescriptor : typeParameters) { writeFormalTypeParameter(typeParameterDescriptor, signatureVisitor); } @@ -560,27 +523,43 @@ public class JetTypeMapper { public JvmMethodSignature mapSignature(String name, FunctionDescriptor f) { final ReceiverDescriptor receiver = f.getReceiverParameter(); + + BothSignatureWriter signatureWriter = new BothSignatureWriter(BothSignatureWriter.Mode.METHOD, false); + + signatureWriter.writeFormalTypeParametersStart(); + signatureWriter.writeFormalTypeParametersEnd(); + + signatureWriter.writeParametersStart(); + final List parameters = f.getValueParameters(); - List parameterTypes = new ArrayList(); if (receiver.exists()) { - parameterTypes.add(mapType(receiver.getType())); + signatureWriter.writeParameterType(JvmMethodParameterKind.RECEIVER); + mapType(receiver.getType(), signatureWriter); + signatureWriter.writeParameterTypeEnd(); } for (ValueParameterDescriptor parameter : parameters) { - parameterTypes.add(mapType(parameter.getOutType())); + signatureWriter.writeParameterType(JvmMethodParameterKind.VALUE); + mapType(parameter.getOutType(), signatureWriter); + signatureWriter.writeParameterTypeEnd(); } - Type returnType = mapReturnType(f.getReturnType()); - // TODO: proper generic signature - return new JvmMethodSignature(new Method(name, returnType, parameterTypes.toArray(new Type[parameterTypes.size()])), null, null, null, ""); + + signatureWriter.writeParametersEnd(); + + signatureWriter.writeReturnType(); + mapReturnType(f.getReturnType(), signatureWriter); + signatureWriter.writeReturnTypeEnd(); + + return signatureWriter.makeJvmMethodSignature(name); } public JvmPropertyAccessorSignature mapGetterSignature(PropertyDescriptor descriptor, OwnerKind kind) { String name = PropertyCodegen.getterName(descriptor.getName()); - ArrayList params = new ArrayList(); - BothSignatureWriter signatureWriter = new BothSignatureWriter(BothSignatureWriter.Mode.METHOD); + // TODO: do not generate generics if not needed + BothSignatureWriter signatureWriter = new BothSignatureWriter(BothSignatureWriter.Mode.METHOD, true); - signatureWriter.writerFormalTypeParametersStart(); + signatureWriter.writeFormalTypeParametersStart(); signatureWriter.writeFormalTypeParametersEnd(); signatureWriter.writeParametersStart(); @@ -588,41 +567,30 @@ public class JetTypeMapper { if(kind == OwnerKind.TRAIT_IMPL) { ClassDescriptor containingDeclaration = (ClassDescriptor) descriptor.getContainingDeclaration(); assert containingDeclaration != null; - signatureWriter.writeParameterType(); - params.add(mapType(containingDeclaration.getDefaultType(), signatureWriter)); + signatureWriter.writeParameterType(JvmMethodParameterKind.THIS); + mapType(containingDeclaration.getDefaultType(), signatureWriter); signatureWriter.writeParameterTypeEnd(); } if(descriptor.getReceiverParameter().exists()) { - signatureWriter.writeParameterType(); - params.add(mapType(descriptor.getReceiverParameter().getType(), signatureWriter)); + signatureWriter.writeParameterType(JvmMethodParameterKind.RECEIVER); + mapType(descriptor.getReceiverParameter().getType(), signatureWriter); signatureWriter.writeParameterTypeEnd(); } for (TypeParameterDescriptor typeParameterDescriptor : descriptor.getTypeParameters()) { if(typeParameterDescriptor.isReified()) { - signatureWriter.writeParameterType(); - params.add(TYPE_TYPEINFO); - visitAsmType(signatureWriter, TYPE_TYPEINFO, false); - signatureWriter.writeParameterTypeEnd(); + signatureWriter.writeTypeInfoParameter(); } } signatureWriter.writeParametersEnd(); signatureWriter.writeReturnType(); - Type returnType = mapType(descriptor.getOutType(), signatureWriter); + mapType(descriptor.getOutType(), signatureWriter); signatureWriter.writeReturnTypeEnd(); - // TODO: proper generic signature - Method asmMethod = new Method(name, returnType, params.toArray(new Type[params.size()])); - JvmMethodSignature jvmMethodSignature = new JvmMethodSignature( - asmMethod, - signatureWriter.makeJavaString(), - signatureWriter.makeKotlinMethodTypeParameters(), - signatureWriter.makeKotlinParameterTypes(), - signatureWriter.makeKotlinReturnTypeSignature() - ); + JvmMethodSignature jvmMethodSignature = signatureWriter.makeJvmMethodSignature(name); return new JvmPropertyAccessorSignature(jvmMethodSignature, jvmMethodSignature.getKotlinReturnType()); } @@ -632,10 +600,11 @@ public class JetTypeMapper { if (!descriptor.isVar()) { return null; } + + // TODO: generics signature is not always needed + BothSignatureWriter signatureWriter = new BothSignatureWriter(BothSignatureWriter.Mode.METHOD, true); - BothSignatureWriter signatureWriter = new BothSignatureWriter(BothSignatureWriter.Mode.METHOD); - - signatureWriter.writerFormalTypeParametersStart(); + signatureWriter.writeFormalTypeParametersStart(); signatureWriter.writeFormalTypeParametersEnd(); JetType outType = descriptor.getOutType(); @@ -643,79 +612,77 @@ public class JetTypeMapper { signatureWriter.writeParametersStart(); String name = PropertyCodegen.setterName(descriptor.getName()); - ArrayList params = new ArrayList(); if(kind == OwnerKind.TRAIT_IMPL) { ClassDescriptor containingDeclaration = (ClassDescriptor) descriptor.getContainingDeclaration(); assert containingDeclaration != null; - signatureWriter.writeParameterType(); - params.add(mapType(containingDeclaration.getDefaultType(), signatureWriter)); + signatureWriter.writeParameterType(JvmMethodParameterKind.THIS); + mapType(containingDeclaration.getDefaultType(), signatureWriter); signatureWriter.writeParameterTypeEnd(); } if(descriptor.getReceiverParameter().exists()) { - signatureWriter.writeParameterType(); - params.add(mapType(descriptor.getReceiverParameter().getType(), signatureWriter)); + signatureWriter.writeParameterType(JvmMethodParameterKind.RECEIVER); + mapType(descriptor.getReceiverParameter().getType(), signatureWriter); signatureWriter.writeParameterTypeEnd(); } for (TypeParameterDescriptor typeParameterDescriptor : descriptor.getTypeParameters()) { if(typeParameterDescriptor.isReified()) { - signatureWriter.writeParameterType(); - params.add(TYPE_TYPEINFO); - signatureWriter.writeParameterType(); - visitAsmType(signatureWriter, TYPE_TYPEINFO, false); - signatureWriter.writeParameterTypeEnd(); + signatureWriter.writeTypeInfoParameter(); } } - signatureWriter.writeParameterType(); - params.add(mapType(outType, signatureWriter)); + signatureWriter.writeParameterType(JvmMethodParameterKind.VALUE); + mapType(outType, signatureWriter); signatureWriter.writeParameterTypeEnd(); signatureWriter.writeParametersEnd(); - signatureWriter.writeReturnType(); - visitAsmType(signatureWriter, Type.VOID_TYPE, false); - signatureWriter.writeReturnTypeEnd(); + signatureWriter.writeVoidReturn(); - Method asmMethod = new Method(name, Type.VOID_TYPE, params.toArray(new Type[params.size()])); - JvmMethodSignature jvmMethodSignature = new JvmMethodSignature( - asmMethod, - signatureWriter.makeJavaString(), - signatureWriter.makeKotlinMethodTypeParameters(), - signatureWriter.makeKotlinParameterTypes(), - signatureWriter.makeKotlinReturnTypeSignature() - ); + JvmMethodSignature jvmMethodSignature = signatureWriter.makeJvmMethodSignature(name); return new JvmPropertyAccessorSignature(jvmMethodSignature, jvmMethodSignature.getKotlinParameterType(jvmMethodSignature.getParameterCount() - 1)); } - private JvmMethodSignature mapConstructorSignature(ConstructorDescriptor descriptor, List valueParameterTypes) { + private JvmMethodSignature mapConstructorSignature(ConstructorDescriptor descriptor) { + + BothSignatureWriter signatureWriter = new BothSignatureWriter(BothSignatureWriter.Mode.METHOD, true); + List parameters = descriptor.getOriginal().getValueParameters(); - List parameterTypes = new ArrayList(); ClassDescriptor classDescriptor = descriptor.getContainingDeclaration(); + + signatureWriter.writeFormalTypeParametersStart(); + signatureWriter.writeFormalTypeParametersEnd(); + + signatureWriter.writeParametersStart(); + if (CodegenUtil.hasThis0(classDescriptor)) { - parameterTypes.add(mapType(CodegenUtil.getOuterClassDescriptor(classDescriptor).getDefaultType(), OwnerKind.IMPLEMENTATION)); + signatureWriter.writeParameterType(JvmMethodParameterKind.THIS0); + mapType(CodegenUtil.getOuterClassDescriptor(classDescriptor).getDefaultType(), OwnerKind.IMPLEMENTATION, signatureWriter); + signatureWriter.writeParameterTypeEnd(); } if (CodegenUtil.requireTypeInfoConstructorArg(classDescriptor.getDefaultType())) { - parameterTypes.add(TYPE_TYPEINFO); + signatureWriter.writeTypeInfoParameter(); } for (ValueParameterDescriptor parameter : parameters) { - final Type type = mapType(parameter.getOutType()); - parameterTypes.add(type); - valueParameterTypes.add(type); + signatureWriter.writeParameterType(JvmMethodParameterKind.VALUE); + mapType(parameter.getOutType(), signatureWriter); + signatureWriter.writeParameterTypeEnd(); } + + signatureWriter.writeParametersEnd(); + + signatureWriter.writeVoidReturn(); - Method method = new Method("", Type.VOID_TYPE, parameterTypes.toArray(new Type[parameterTypes.size()])); - return new JvmMethodSignature(method, null, null, null, ""); // TODO: generics signature + return signatureWriter.makeJvmMethodSignature(""); } public CallableMethod mapToCallableMethod(ConstructorDescriptor descriptor, OwnerKind kind) { - List valueParameterTypes = new ArrayList(); - final JvmMethodSignature method = mapConstructorSignature(descriptor, valueParameterTypes); + final JvmMethodSignature method = mapConstructorSignature(descriptor); String owner = mapType(descriptor.getContainingDeclaration().getDefaultType(), kind).getInternalName(); - return new CallableMethod(owner, method, INVOKESPECIAL, valueParameterTypes); + return new CallableMethod(owner, method, INVOKESPECIAL); } static int getAccessModifiers(JetDeclaration p, int defaultFlags) { diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/JvmMethodParameterKind.java b/compiler/backend/src/org/jetbrains/jet/codegen/JvmMethodParameterKind.java new file mode 100644 index 00000000000..66cc3ef7376 --- /dev/null +++ b/compiler/backend/src/org/jetbrains/jet/codegen/JvmMethodParameterKind.java @@ -0,0 +1,15 @@ +package org.jetbrains.jet.codegen; + +import org.jetbrains.jet.lang.descriptors.ClassDescriptor; + +/** + * @author Stepan Koltsov + */ +public enum JvmMethodParameterKind { + VALUE, + THIS, + /** @see CodegenUtil#hasThis0(ClassDescriptor) */ + THIS0, + RECEIVER, + TYPE_INFO, +} diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/JvmMethodParameterSignature.java b/compiler/backend/src/org/jetbrains/jet/codegen/JvmMethodParameterSignature.java new file mode 100644 index 00000000000..dc5991704d4 --- /dev/null +++ b/compiler/backend/src/org/jetbrains/jet/codegen/JvmMethodParameterSignature.java @@ -0,0 +1,38 @@ +package org.jetbrains.jet.codegen; + +import org.jetbrains.annotations.NotNull; +import org.objectweb.asm.Type; + +/** + * @author Stepan Koltsov + */ +public class JvmMethodParameterSignature { + @NotNull + private final Type asmType; + @NotNull + private final String kotlinSignature; + @NotNull + private final JvmMethodParameterKind kind; + + public JvmMethodParameterSignature( + @NotNull Type asmType, @NotNull String kotlinSignature, @NotNull JvmMethodParameterKind kind) { + this.asmType = asmType; + this.kotlinSignature = kotlinSignature; + this.kind = kind; + } + + @NotNull + public Type getAsmType() { + return asmType; + } + + @NotNull + public String getKotlinSignature() { + return kotlinSignature; + } + + @NotNull + public JvmMethodParameterKind getKind() { + return kind; + } +} diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/JvmMethodSignature.java b/compiler/backend/src/org/jetbrains/jet/codegen/JvmMethodSignature.java index 64333aab773..a3487e8a50d 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/JvmMethodSignature.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/JvmMethodSignature.java @@ -2,46 +2,76 @@ package org.jetbrains.jet.codegen; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.objectweb.asm.Type; import org.objectweb.asm.commons.Method; +import java.util.ArrayList; import java.util.List; /** * @author Stepan Koltsov */ public class JvmMethodSignature { - + + @NotNull private final Method asmMethod; /** Null when we don't care about type parameters */ private final String genericsSignature; private final String kotlinTypeParameter; - private final List kotlinParameterTypes; + @NotNull + private final List kotlinParameterTypes; @NotNull private final String kotlinReturnType; + /** + * Generics info is generated. However it can be trivial (e.g. fields are null). + */ + private final boolean genericsAvailable; + public JvmMethodSignature(@NotNull Method asmMethod, @Nullable String genericsSignature, - @Nullable String kotlinTypeParameters, @Nullable List kotlinParameterTypes, @NotNull String kotlinReturnType) { + @Nullable String kotlinTypeParameters, @NotNull List kotlinParameterTypes, @NotNull String kotlinReturnType) { this.asmMethod = asmMethod; this.genericsSignature = genericsSignature; this.kotlinTypeParameter = kotlinTypeParameters; this.kotlinParameterTypes = kotlinParameterTypes; this.kotlinReturnType = kotlinReturnType; + this.genericsAvailable = true; + } + + public JvmMethodSignature(@NotNull Method asmMethod, @NotNull List kotlinParameterTypes) { + this.asmMethod = asmMethod; + this.genericsSignature = null; + this.kotlinTypeParameter = null; + this.kotlinParameterTypes = kotlinParameterTypes; + this.kotlinReturnType = ""; + this.genericsAvailable = false; } + private void checkGenericsAvailable() { + if (!genericsAvailable) { + // TODO: uncomment following line and fix all broken tests + //throw new IllegalStateException("incorrect call sequence"); + } + } + + @NotNull public Method getAsmMethod() { return asmMethod; } public String getGenericsSignature() { + checkGenericsAvailable(); return genericsSignature; } public String getKotlinTypeParameter() { + checkGenericsAvailable(); return kotlinTypeParameter; } @Nullable - public List getKotlinParameterTypes() { + public List getKotlinParameterTypes() { + checkGenericsAvailable(); return kotlinParameterTypes; } @@ -52,15 +82,32 @@ public class JvmMethodSignature { @NotNull public String getKotlinParameterType(int i) { + checkGenericsAvailable(); if (kotlinParameterTypes == null) { return ""; } else { - return kotlinParameterTypes.get(i); + return kotlinParameterTypes.get(i).getKotlinSignature(); } } @NotNull public String getKotlinReturnType() { + checkGenericsAvailable(); return kotlinReturnType; } + + public List getValueParameterTypes() { + List r = new ArrayList(kotlinParameterTypes.size()); + for (JvmMethodParameterSignature p : kotlinParameterTypes) { + if (p.getKind() == JvmMethodParameterKind.VALUE) { + r.add(p.getAsmType()); + } + } + return r; + } + + @NotNull + public String getName() { + return asmMethod.getName(); + } }