From 10a47ea86f05ecce2ec3b42d8c952956cc3c3e04 Mon Sep 17 00:00:00 2001 From: Alex Tkachman Date: Mon, 27 Aug 2012 17:43:03 +0300 Subject: [PATCH] big codegen rewrite --- .../jet/codegen/ClassBodyCodegen.java | 1 + .../jet/codegen/ClassBuilderFactories.java | 2 +- .../jetbrains/jet/codegen/ClassCodegen.java | 16 +- .../jetbrains/jet/codegen/ClosureCodegen.java | 201 +++---- .../jetbrains/jet/codegen/CodegenContext.java | 262 --------- .../jet/codegen/CodegenContexts.java | 290 ---------- .../jetbrains/jet/codegen/CodegenUtil.java | 124 +++- .../jet/codegen/ConstructorFrameMap.java | 29 +- .../jet/codegen/ExpressionCodegen.java | 271 ++++----- .../jet/codegen/FunctionCodegen.java | 10 +- .../GeneratedAnonymousClassDescriptor.java | 81 --- .../jet/codegen/GenerationState.java | 26 +- .../codegen/ImplementationBodyCodegen.java | 277 +++++---- .../jetbrains/jet/codegen/JetTypeMapper.java | 104 +++- .../jet/codegen/LocalClassClosureCodegen.java | 35 -- .../jetbrains/jet/codegen/MemberCodegen.java | 1 + .../jet/codegen/NamespaceCodegen.java | 13 +- .../jet/codegen/ObjectOrClosureCodegen.java | 144 ----- .../jet/codegen/PropertyCodegen.java | 1 + .../jetbrains/jet/codegen/ScriptCodegen.java | 10 +- .../jet/codegen/TraitImplBodyCodegen.java | 1 + .../codegen/context/CalculatedClosure.java | 57 ++ .../{ => context}/ClosureAnnotator.java | 213 ++++--- .../jet/codegen/context/CodegenContext.java | 544 ++++++++++++++++++ .../EnclosedValueDescriptor.java | 29 +- .../jet/codegen/context/LocalLookup.java | 136 +++++ .../jet/codegen/context/MutableClosure.java | 130 +++++ .../signature/JvmMethodParameterKind.java | 4 +- .../jet/di/InjectorForJetTypeMapper.java | 2 +- .../jet/di/InjectorForJvmCodegen.java | 2 +- .../jetbrains/jet/codegen/ArrayGenTest.java | 233 ++++---- .../jetbrains/jet/codegen/ClassGenTest.java | 2 +- .../jet/codegen/FunctionGenTest.java | 22 +- .../jet/codegen/LocalClassGenTest.java | 2 +- .../jet/di/AllInjectorsGenerator.java | 10 +- 35 files changed, 1736 insertions(+), 1549 deletions(-) delete mode 100644 compiler/backend/src/org/jetbrains/jet/codegen/CodegenContext.java delete mode 100644 compiler/backend/src/org/jetbrains/jet/codegen/CodegenContexts.java delete mode 100644 compiler/backend/src/org/jetbrains/jet/codegen/GeneratedAnonymousClassDescriptor.java delete mode 100644 compiler/backend/src/org/jetbrains/jet/codegen/LocalClassClosureCodegen.java delete mode 100644 compiler/backend/src/org/jetbrains/jet/codegen/ObjectOrClosureCodegen.java create mode 100644 compiler/backend/src/org/jetbrains/jet/codegen/context/CalculatedClosure.java rename compiler/backend/src/org/jetbrains/jet/codegen/{ => context}/ClosureAnnotator.java (73%) create mode 100644 compiler/backend/src/org/jetbrains/jet/codegen/context/CodegenContext.java rename compiler/backend/src/org/jetbrains/jet/codegen/{ => context}/EnclosedValueDescriptor.java (56%) create mode 100644 compiler/backend/src/org/jetbrains/jet/codegen/context/LocalLookup.java create mode 100644 compiler/backend/src/org/jetbrains/jet/codegen/context/MutableClosure.java diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ClassBodyCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ClassBodyCodegen.java index 603d2c156b8..4aaf60a7ae9 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ClassBodyCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ClassBodyCodegen.java @@ -20,6 +20,7 @@ import org.jetbrains.asm4.MethodVisitor; import org.jetbrains.asm4.Opcodes; import org.jetbrains.asm4.Type; import org.jetbrains.asm4.commons.InstructionAdapter; +import org.jetbrains.jet.codegen.context.CodegenContext; import org.jetbrains.jet.lang.descriptors.ClassDescriptor; import org.jetbrains.jet.lang.descriptors.PropertyDescriptor; import org.jetbrains.jet.lang.psi.*; diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ClassBuilderFactories.java b/compiler/backend/src/org/jetbrains/jet/codegen/ClassBuilderFactories.java index 1bc6620a805..b66b4e7282e 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ClassBuilderFactories.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ClassBuilderFactories.java @@ -125,7 +125,7 @@ public class ClassBuilderFactories { return super.getCommonSuperClass(type1, type2); } catch (Throwable t) { - // @todo we might need at some point do more sofisticated handling + // @todo we might need at some point do more sophisticated handling return "java/lang/Object"; } } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ClassCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ClassCodegen.java index afea914079f..fdcbc731c56 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ClassCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ClassCodegen.java @@ -16,6 +16,7 @@ package org.jetbrains.jet.codegen; +import org.jetbrains.jet.codegen.context.CodegenContext; import org.jetbrains.jet.lang.descriptors.ClassDescriptor; import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; import org.jetbrains.jet.lang.psi.*; @@ -30,14 +31,14 @@ import java.util.Map; */ public class ClassCodegen { private GenerationState state; - private JetTypeMapper jetTypeMapper; - + @SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"}) private JetTypeMapper jetTypeMapper; @Inject public void setState(GenerationState state) { this.state = state; } + @SuppressWarnings("UnusedParameters") @Inject public void setJetTypeMapper(JetTypeMapper jetTypeMapper) { this.jetTypeMapper = jetTypeMapper; @@ -48,13 +49,13 @@ public class ClassCodegen { ClassDescriptor descriptor = state.getBindingContext().get(BindingContext.CLASS, aClass); ClassBuilder classBuilder = state.forClassImplementation(descriptor); - final CodegenContext contextForInners = context.intoClass(descriptor, OwnerKind.IMPLEMENTATION, jetTypeMapper); + final CodegenContext contextForInners = context.intoClass(descriptor, OwnerKind.IMPLEMENTATION, state); if (state.getClassBuilderMode() == ClassBuilderMode.SIGNATURES) { // Outer class implementation must happen prior inner classes so we get proper scoping tree in JetLightClass's delegate // The same code is present below for the case when we generate real bytecode. This is because the order should be // different for the case when we compute closures - generateImplementation(context, aClass, OwnerKind.IMPLEMENTATION, contextForInners.accessors, classBuilder); + generateImplementation(context, aClass, OwnerKind.IMPLEMENTATION, contextForInners.getAccessors(), classBuilder); } for (JetDeclaration declaration : aClass.getDeclarations()) { @@ -72,7 +73,7 @@ public class ClassCodegen { } if (state.getClassBuilderMode() != ClassBuilderMode.SIGNATURES) { - generateImplementation(context, aClass, OwnerKind.IMPLEMENTATION, contextForInners.accessors, classBuilder); + generateImplementation(context, aClass, OwnerKind.IMPLEMENTATION, contextForInners.getAccessors(), classBuilder); } classBuilder.done(); @@ -86,13 +87,14 @@ public class ClassCodegen { ClassBuilder classBuilder ) { ClassDescriptor descriptor = state.getBindingContext().get(BindingContext.CLASS, aClass); - CodegenContext classContext = context.intoClass(descriptor, kind, jetTypeMapper); + CodegenContext classContext = context.intoClass(descriptor, kind, state); classContext.copyAccessors(accessors); + new ImplementationBodyCodegen(aClass, classContext, classBuilder, state).generate(); if (aClass instanceof JetClass && ((JetClass) aClass).isTrait()) { ClassBuilder traitBuilder = state.forTraitImplementation(descriptor); - new TraitImplBodyCodegen(aClass, context.intoClass(descriptor, OwnerKind.TRAIT_IMPL, jetTypeMapper), traitBuilder, state) + new TraitImplBodyCodegen(aClass, context.intoClass(descriptor, OwnerKind.TRAIT_IMPL, state), traitBuilder, state) .generate(); traitBuilder.done(); } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java index 265a64f84ca..58c02ddfc58 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java @@ -22,15 +22,16 @@ package org.jetbrains.jet.codegen; import com.intellij.openapi.util.Pair; import com.intellij.psi.PsiElement; -import org.jetbrains.annotations.NotNull; import org.jetbrains.asm4.Label; import org.jetbrains.asm4.MethodVisitor; import org.jetbrains.asm4.Type; import org.jetbrains.asm4.commons.InstructionAdapter; import org.jetbrains.asm4.commons.Method; import org.jetbrains.asm4.signature.SignatureWriter; -import org.jetbrains.jet.codegen.signature.BothSignatureWriter; -import org.jetbrains.jet.codegen.signature.JvmMethodParameterKind; +import org.jetbrains.jet.codegen.context.CalculatedClosure; +import org.jetbrains.jet.codegen.context.ClosureAnnotator; +import org.jetbrains.jet.codegen.context.CodegenContext; +import org.jetbrains.jet.codegen.context.MutableClosure; import org.jetbrains.jet.codegen.signature.JvmMethodSignature; import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.psi.JetDeclarationWithBody; @@ -39,7 +40,6 @@ import org.jetbrains.jet.lang.psi.JetExpression; import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.BindingContextUtils; import org.jetbrains.jet.lang.resolve.java.JvmClassName; -import org.jetbrains.jet.lang.resolve.name.Name; import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor; import org.jetbrains.jet.lang.types.JetType; @@ -48,81 +48,42 @@ import java.util.List; import static org.jetbrains.asm4.Opcodes.*; -public class ClosureCodegen extends ObjectOrClosureCodegen { +public class ClosureCodegen { private final BindingContext bindingContext; private final ClosureAnnotator closureAnnotator; private final JetTypeMapper typeMapper; - public ClosureCodegen(GenerationState state, ExpressionCodegen exprContext, CodegenContext context) { - super(exprContext, context, state); + Method constructor; + private final GenerationState state; + private final MutableClosure closure; + JvmClassName name; + + + public ClosureCodegen(GenerationState state, MutableClosure closure) { + this.state = state; + this.closure = closure; bindingContext = state.getBindingContext(); - typeMapper = this.state.getInjector().getJetTypeMapper(); + typeMapper = state.getInjector().getJetTypeMapper(); closureAnnotator = typeMapper.getClosureAnnotator(); } - private static JvmMethodSignature erasedInvokeSignature(FunctionDescriptor fd) { + public ClosureCodegen gen(JetExpression fun, CodegenContext context, ExpressionCodegen expressionCodegen) { + final SimpleFunctionDescriptor descriptor = bindingContext.get(BindingContext.FUNCTION, fun); + assert descriptor != null; - 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.OBJECT_TYPE, true); - signatureWriter.writeParameterTypeEnd(); - } - - signatureWriter.writeParametersEnd(); - - signatureWriter.writeReturnType(); - signatureWriter.writeAsmType(JetTypeMapper.OBJECT_TYPE, true); - signatureWriter.writeReturnTypeEnd(); - - return signatureWriter.makeJvmMethodSignature("invoke"); - } - - public static CallableMethod asCallableMethod(FunctionDescriptor fd, @NotNull JetTypeMapper typeMapper) { - JvmMethodSignature descriptor = erasedInvokeSignature(fd); - JvmClassName owner = getInternalClassName(fd); - Type receiverParameterType; - if (fd.getReceiverParameter().exists()) { - receiverParameterType = typeMapper.mapType(fd.getOriginal().getReceiverParameter().getType(), MapTypeMode.VALUE); - } - else { - receiverParameterType = null; - } - return new CallableMethod( - owner, null, null, descriptor, INVOKEVIRTUAL, - getInternalClassName(fd), receiverParameterType, getInternalClassName(fd).getAsmType()); - } - - protected JvmMethodSignature invokeSignature(FunctionDescriptor fd) { - return typeMapper.mapSignature(Name.identifier("invoke"), fd); - } - - public GeneratedAnonymousClassDescriptor gen(JetExpression fun) { final Pair nameAndVisitor = state.forAnonymousSubclass(fun); final FunctionDescriptor funDescriptor = bindingContext.get(BindingContext.FUNCTION, fun); - cv = nameAndVisitor.getSecond(); + ClassBuilder cv = nameAndVisitor.getSecond(); name = nameAndVisitor.getFirst(); SignatureWriter signatureWriter = new SignatureWriter(); assert funDescriptor != null; final List parameters = funDescriptor.getValueParameters(); - final JvmClassName funClass = getInternalClassName(funDescriptor); + final JvmClassName funClass = CodegenUtil.getInternalClassName(funDescriptor); signatureWriter.visitClassType(funClass.getInternalName()); for (ValueParameterDescriptor parameter : parameters) { appendType(signatureWriter, parameter.getType(), '='); @@ -143,46 +104,27 @@ public class ClosureCodegen extends ObjectOrClosureCodegen { generateBridge(name.getInternalName(), funDescriptor, fun, cv); - captureThis = generateBody(funDescriptor, cv, (JetDeclarationWithBody) fun); + generateBody(funDescriptor, cv, (JetDeclarationWithBody) fun, context, expressionCodegen); - final ClassDescriptor enclosingClass = context.getEnclosingClass(); - if (enclosingClass == null) { - captureThis = null; + constructor = generateConstructor(funClass, fun, cv, closure); + + if (CodegenUtil.isConst(closure)) { + generateConstInstance(fun, cv); } - final Method constructor = generateConstructor(funClass, fun, funDescriptor); - - if (captureThis != null) { - cv.newField(fun, ACC_FINAL, "this$0", typeMapper.mapType(enclosingClass.getDefaultType(), MapTypeMode.IMPL).getDescriptor(), - null, null); - } - - if (isConst()) { - generateConstInstance(fun); - } + CodegenUtil.generateClosureFields(closure, cv, state.getInjector().getJetTypeMapper()); cv.done(); - final GeneratedAnonymousClassDescriptor answer = - new GeneratedAnonymousClassDescriptor(name, constructor, captureThis, captureReceiver); - for (DeclarationDescriptor descriptor : closure.keySet()) { - if (descriptor == funDescriptor) { - continue; - } - if (descriptor instanceof VariableDescriptor || CodegenUtil.isNamedFun(descriptor, state.getBindingContext()) && - descriptor.getContainingDeclaration() instanceof FunctionDescriptor) { - final EnclosedValueDescriptor valueDescriptor = closure.get(descriptor); - answer.addArg(valueDescriptor.getOuterValue()); - } - } - return answer; + return this; } - private void generateConstInstance(PsiElement fun) { + private void generateConstInstance(PsiElement fun, ClassBuilder cv) { String classDescr = name.getDescriptor(); - cv.newField(fun, ACC_PRIVATE | ACC_STATIC | ACC_FINAL, "$instance", classDescr, null, null); + cv.newField(fun, ACC_PRIVATE | ACC_STATIC | ACC_FINAL | ACC_SYNTHETIC, "$instance", classDescr, null, null); - MethodVisitor mv = cv.newMethod(fun, ACC_PUBLIC | ACC_STATIC, "$getInstance", "()" + classDescr, null, new String[0]); + MethodVisitor mv = + cv.newMethod(fun, ACC_PUBLIC | ACC_STATIC | ACC_SYNTHETIC, "$getInstance", "()" + classDescr, null, new String[0]); if (state.getClassBuilderMode() == ClassBuilderMode.STUBS) { StubCodegen.generateStubCode(mv); } @@ -206,21 +148,29 @@ public class ClosureCodegen extends ObjectOrClosureCodegen { } } - private ClassDescriptor generateBody(FunctionDescriptor funDescriptor, ClassBuilder cv, JetDeclarationWithBody body) { - ClassDescriptor function = - closureAnnotator.classDescriptorForFunctionDescriptor(funDescriptor); + private ClassDescriptor generateBody( + FunctionDescriptor funDescriptor, + ClassBuilder cv, + JetDeclarationWithBody body, + CodegenContext context, + ExpressionCodegen expressionCodegen + ) { - final CodegenContexts.ClosureContext closureContext = context.intoClosure( - funDescriptor, function, this, typeMapper); + final CodegenContext closureContext = context.intoClosure(funDescriptor, expressionCodegen); FunctionCodegen fc = new FunctionCodegen(closureContext, cv, state); - JvmMethodSignature jvmMethodSignature = invokeSignature(funDescriptor); + JvmMethodSignature jvmMethodSignature = typeMapper.invokeSignature(funDescriptor); fc.generateMethod(body, jvmMethodSignature, false, null, funDescriptor); - return closureContext.outerWasUsed; + return closureContext.closure.getCaptureThis(); } - private void generateBridge(String className, FunctionDescriptor funDescriptor, JetExpression fun, ClassBuilder cv) { - final JvmMethodSignature bridge = erasedInvokeSignature(funDescriptor); - final Method delegate = invokeSignature(funDescriptor).getAsmMethod(); + private void generateBridge( + String className, + FunctionDescriptor funDescriptor, + JetExpression fun, + ClassBuilder cv + ) { + final JvmMethodSignature bridge = CodegenUtil.erasedInvokeSignature(funDescriptor); + final Method delegate = typeMapper.invokeSignature(funDescriptor).getAsmMethod(); if (bridge.getAsmMethod().getDescriptor().equals(delegate.getDescriptor())) { return; @@ -265,9 +215,14 @@ public class ClosureCodegen extends ObjectOrClosureCodegen { } } - private Method generateConstructor(JvmClassName funClass, JetExpression fun, FunctionDescriptor funDescriptor) { + private Method generateConstructor( + JvmClassName funClass, + JetExpression fun, + ClassBuilder cv, + CalculatedClosure closure + ) { final ArrayList> args = new ArrayList>(); - boolean putFieldForMyself = calculateConstructorParameters(funDescriptor, args); + calculateConstructorParameters(args, state, closure); final Type[] argTypes = nameAnTypeListToTypeArray(args); @@ -293,14 +248,6 @@ public class ClosureCodegen extends ObjectOrClosureCodegen { StackValue.field(type, name, nameAndType.first, false).store(type, iv); } - if (putFieldForMyself) { - Type type = name.getAsmType(); - String fieldName = "$" + funDescriptor.getName(); - iv.load(0, type); - iv.dup(); - StackValue.field(type, name, fieldName, false).store(type, iv); - } - iv.visitInsn(RETURN); FunctionCodegen.endVisit(iv, "constructor", fun); @@ -308,22 +255,24 @@ public class ClosureCodegen extends ObjectOrClosureCodegen { return constructor; } - private boolean calculateConstructorParameters(FunctionDescriptor funDescriptor, List> args) { + private void calculateConstructorParameters( + List> args, + GenerationState state, + CalculatedClosure closure + ) { + final ClassDescriptor captureThis = closure.getCaptureThis(); if (captureThis != null) { - final Type type = typeMapper.mapType(context.getThisDescriptor().getDefaultType(), MapTypeMode.VALUE); - args.add(new Pair("this$0", type)); + final Type type = typeMapper.mapType(captureThis.getDefaultType(), MapTypeMode.VALUE); + args.add(new Pair(CodegenUtil.THIS$0, type)); } + final ClassifierDescriptor captureReceiver = closure.getCaptureReceiver(); if (captureReceiver != null) { - args.add(new Pair("receiver$0", typeMapper.mapType(captureReceiver.getDefaultType(), MapTypeMode.VALUE))); + args.add(new Pair(CodegenUtil.RECEIVER$0, + typeMapper.mapType(captureReceiver.getDefaultType(), MapTypeMode.VALUE))); } - boolean putFieldForMyself = false; - - for (DeclarationDescriptor descriptor : closure.keySet()) { - if (descriptor == funDescriptor) { - putFieldForMyself = true; - } - else if (descriptor instanceof VariableDescriptor && !(descriptor instanceof PropertyDescriptor)) { + for (DeclarationDescriptor descriptor : closure.getCaptureVariables().keySet()) { + if (descriptor instanceof VariableDescriptor && !(descriptor instanceof PropertyDescriptor)) { final Type sharedVarType = typeMapper.getSharedVarType(descriptor); final Type type = sharedVarType != null @@ -343,7 +292,6 @@ public class ClosureCodegen extends ObjectOrClosureCodegen { assert captureReceiver != null; } } - return putFieldForMyself; } private static Type[] nameAnTypeListToTypeArray(List> args) { @@ -354,17 +302,6 @@ public class ClosureCodegen extends ObjectOrClosureCodegen { return argTypes; } - @NotNull - public static JvmClassName getInternalClassName(FunctionDescriptor descriptor) { - final int paramCount = descriptor.getValueParameters().size(); - if (descriptor.getReceiverParameter().exists()) { - return JvmClassName.byInternalName("jet/ExtensionFunction" + paramCount); - } - else { - return JvmClassName.byInternalName("jet/Function" + paramCount); - } - } - private void appendType(SignatureWriter signatureWriter, JetType type, char variance) { signatureWriter.visitTypeArgument(variance); diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/CodegenContext.java b/compiler/backend/src/org/jetbrains/jet/codegen/CodegenContext.java deleted file mode 100644 index 2a582b58276..00000000000 --- a/compiler/backend/src/org/jetbrains/jet/codegen/CodegenContext.java +++ /dev/null @@ -1,262 +0,0 @@ -/* - * Copyright 2010-2012 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jetbrains.jet.codegen; - -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.jetbrains.asm4.Type; -import org.jetbrains.asm4.commons.InstructionAdapter; -import org.jetbrains.jet.lang.descriptors.*; -import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; - -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; - -import static org.jetbrains.jet.codegen.JetTypeMapper.OBJECT_TYPE; - -/* - * @author max - * @author alex.tkachman - */ -public abstract class CodegenContext { - - @NotNull - private final DeclarationDescriptor contextDescriptor; - - private final OwnerKind contextKind; - @Nullable - private final CodegenContext parentContext; - public final ObjectOrClosureCodegen closure; - private final ClassDescriptor thisDescriptor; - - HashMap accessors; - - protected StackValue outerExpression; - - protected ClassDescriptor outerWasUsed; - - public CodegenContext( - JetTypeMapper typeMapper, - @NotNull DeclarationDescriptor contextDescriptor, - OwnerKind contextKind, - @Nullable CodegenContext parentContext, - @Nullable ObjectOrClosureCodegen closureCodegen, - ClassDescriptor thisDescriptor - ) { - this.contextDescriptor = contextDescriptor; - this.contextKind = contextKind; - this.parentContext = parentContext; - closure = closureCodegen; - this.thisDescriptor = thisDescriptor; - - final ClassDescriptor enclosingClass = getEnclosingClass(); - //outerExpression = enclosingClass != null && hasThisDescriptor() && typeMapper != null - // ? StackValue.field(typeMapper.mapType(enclosingClass.getDefaultType(),MapTypeMode.VALUE), typeMapper.getJvmClassName(thisDescriptor), "this$0", false) - // : null; - } - - @NotNull - protected final ClassDescriptor getThisDescriptor() { - if (thisDescriptor == null) { - throw new UnsupportedOperationException(); - } - return thisDescriptor; - } - - protected final boolean hasThisDescriptor() { - return thisDescriptor != null; - } - - public DeclarationDescriptor getClassOrNamespaceDescriptor() { - CodegenContext c = this; - while (true) { - assert c != null; - DeclarationDescriptor contextDescriptor = c.getContextDescriptor(); - if (!(contextDescriptor instanceof ClassDescriptor) && !(contextDescriptor instanceof NamespaceDescriptor)) { - c = c.getParentContext(); - } - else { - return contextDescriptor; - } - } - } - - protected CallableDescriptor getReceiverDescriptor() { - return null; - } - - protected StackValue getOuterExpression(@Nullable StackValue prefix) { - if (outerExpression == null) { - throw new UnsupportedOperationException(); - } - - outerWasUsed = getEnclosingClass(); - return prefix != null ? StackValue.composed(prefix, outerExpression) : outerExpression; - } - - @NotNull - public DeclarationDescriptor getContextDescriptor() { - return contextDescriptor; - } - - public OwnerKind getContextKind() { - return contextKind; - } - - public CodegenContext intoNamespace(NamespaceDescriptor descriptor, JetTypeMapper typeMapper) { - return new CodegenContexts.NamespaceContext(typeMapper, descriptor, this, null); - } - - public CodegenContext intoNamespacePart(String delegateTo, NamespaceDescriptor descriptor, JetTypeMapper typeMapper) { - return new CodegenContexts.NamespaceContext(typeMapper, descriptor, this, new OwnerKind.StaticDelegateKind(delegateTo)); - } - - public CodegenContext intoClass(ClassDescriptor descriptor, OwnerKind kind, JetTypeMapper typeMapper) { - return new CodegenContexts.ClassContext(typeMapper, descriptor, kind, this); - } - - public CodegenContext intoAnonymousClass( - @NotNull ObjectOrClosureCodegen closure, - ClassDescriptor descriptor, - OwnerKind kind, - JetTypeMapper typeMapper - ) { - return new CodegenContexts.AnonymousClassContext(typeMapper, descriptor, kind, this, closure); - } - - public CodegenContexts.MethodContext intoFunction(FunctionDescriptor descriptor, JetTypeMapper typeMapper) { - return new CodegenContexts.MethodContext(typeMapper, descriptor, getContextKind(), this); - } - - public CodegenContexts.ConstructorContext intoConstructor(ConstructorDescriptor descriptor, JetTypeMapper typeMapper) { - if (descriptor == null) { - descriptor = new ConstructorDescriptorImpl(getThisDescriptor(), Collections.emptyList(), true) - .initialize(Collections.emptyList(), Collections.emptyList(), - Visibilities.PUBLIC); - } - return new CodegenContexts.ConstructorContext(typeMapper, descriptor, getContextKind(), this); - } - - public CodegenContext intoScript(@NotNull ScriptDescriptor script, @NotNull ClassDescriptor classDescriptor, JetTypeMapper typeMapper) { - return new CodegenContexts.ScriptContext(typeMapper, script, classDescriptor, OwnerKind.IMPLEMENTATION, this, closure); - } - - public CodegenContexts.ClosureContext intoClosure( - FunctionDescriptor funDescriptor, - ClassDescriptor classDescriptor, - ClosureCodegen closureCodegen, - JetTypeMapper typeMapper - ) { - return new CodegenContexts.ClosureContext(typeMapper, funDescriptor, classDescriptor, this, closureCodegen); - } - - public FrameMap prepareFrame(JetTypeMapper mapper) { - FrameMap frameMap = new FrameMap(); - - if (getContextKind() != OwnerKind.NAMESPACE) { - frameMap.enterTemp(OBJECT_TYPE); // 0 slot for this - } - - CallableDescriptor receiverDescriptor = getReceiverDescriptor(); - if (receiverDescriptor != null) { - Type type = mapper.mapType(receiverDescriptor.getReceiverParameter().getType(), MapTypeMode.VALUE); - frameMap.enterTemp(type); // Next slot for fake this - } - - return frameMap; - } - - @Nullable - public CodegenContext getParentContext() { - return parentContext; - } - - public StackValue lookupInContext(DeclarationDescriptor d, InstructionAdapter v, StackValue result) { - final ObjectOrClosureCodegen top = closure; - if (top != null) { - final StackValue answer = top.lookupInContext(d, result); - if (answer != null) { - return result == null ? answer : StackValue.composed(result, answer); - } - - StackValue outer = getOuterExpression(null); - result = result == null ? outer : StackValue.composed(result, outer); - } - - return parentContext != null ? parentContext.lookupInContext(d, v, result) : null; - } - - public ClassDescriptor getEnclosingClass() { - CodegenContext cur = getParentContext(); - while (cur != null && !(cur.getContextDescriptor() instanceof ClassDescriptor)) { - cur = cur.getParentContext(); - } - - return cur == null ? null : (ClassDescriptor) cur.getContextDescriptor(); - } - - DeclarationDescriptor getAccessor(DeclarationDescriptor descriptor) { - if (accessors == null) { - accessors = new HashMap(); - } - descriptor = descriptor.getOriginal(); - DeclarationDescriptor accessor = accessors.get(descriptor); - if (accessor != null) { - return accessor; - } - - if (descriptor instanceof SimpleFunctionDescriptor) { - accessor = new AccessorForFunctionDescriptor(descriptor, contextDescriptor, accessors.size()); - } - else if (descriptor instanceof PropertyDescriptor) { - accessor = new AccessorForPropertyDescriptor((PropertyDescriptor) descriptor, contextDescriptor, accessors.size()); - } - else { - throw new UnsupportedOperationException(); - } - accessors.put(descriptor, accessor); - return accessor; - } - - public StackValue getReceiverExpression(JetTypeMapper typeMapper) { - assert getReceiverDescriptor() != null; - Type asmType = typeMapper.mapType(getReceiverDescriptor().getReceiverParameter().getType(), MapTypeMode.VALUE); - return hasThisDescriptor() ? StackValue.local(1, asmType) : StackValue.local(0, asmType); - } - - public abstract boolean isStatic(); - - public void copyAccessors(Map accessors) { - if (accessors != null) { - if (this.accessors == null) { - this.accessors = new HashMap(); - } - this.accessors.putAll(accessors); - } - } - - protected void initOuterExpression(JetTypeMapper typeMapper, ClassDescriptor classDescriptor) { - final ClassDescriptor enclosingClass = getEnclosingClass(); - outerExpression = enclosingClass != null - ? StackValue - .field(typeMapper.mapType(enclosingClass.getDefaultType(), MapTypeMode.VALUE), typeMapper.getJvmClassName( - classDescriptor), "this$0", - false) - : null; - } -} diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/CodegenContexts.java b/compiler/backend/src/org/jetbrains/jet/codegen/CodegenContexts.java deleted file mode 100644 index 619b1439484..00000000000 --- a/compiler/backend/src/org/jetbrains/jet/codegen/CodegenContexts.java +++ /dev/null @@ -1,290 +0,0 @@ -/* - * Copyright 2010-2012 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jetbrains.jet.codegen; - -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.jetbrains.asm4.commons.InstructionAdapter; -import org.jetbrains.jet.lang.descriptors.*; -import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; -import org.jetbrains.jet.lang.resolve.name.Name; -import org.jetbrains.jet.lang.types.TypeSubstitutor; - -import java.util.List; - -/** - * @author alex.tkachman - * @author Stepan Koltsov - */ -public class CodegenContexts { - private CodegenContexts() { - } - - private static class FakeDescriptorForStaticContext implements DeclarationDescriptor { - - @NotNull - @Override - public DeclarationDescriptor getOriginal() { - throw new IllegalStateException(); - } - - @Override - public DeclarationDescriptor getContainingDeclaration() { - throw new IllegalStateException(); - } - - @Override - public DeclarationDescriptor substitute(TypeSubstitutor substitutor) { - throw new IllegalStateException(); - } - - @Override - public R accept(DeclarationDescriptorVisitor visitor, D data) { - throw new IllegalStateException(); - } - - @Override - public void acceptVoid(DeclarationDescriptorVisitor visitor) { - throw new IllegalStateException(); - } - - @Override - public List getAnnotations() { - throw new IllegalStateException(); - } - - @NotNull - @Override - public Name getName() { - throw new IllegalStateException(); - } - } - - public static final CodegenContext STATIC = - new CodegenContext(null, new FakeDescriptorForStaticContext(), OwnerKind.NAMESPACE, null, null, null) { - @Override - public boolean isStatic() { - return true; - } - - @Override - public String toString() { - return "ROOT"; - } - }; - private static final StackValue local1 = StackValue.local(1, JetTypeMapper.OBJECT_TYPE); - - public abstract static class ReceiverContext extends CodegenContext { - final CallableDescriptor receiverDescriptor; - - public ReceiverContext( - JetTypeMapper typeMapper, - CallableDescriptor contextDescriptor, - OwnerKind contextKind, - CodegenContext parentContext, - @Nullable ObjectOrClosureCodegen closureCodegen, - ClassDescriptor thisDescriptor - ) { - super(typeMapper, contextDescriptor, contextKind, parentContext, closureCodegen, thisDescriptor); - receiverDescriptor = contextDescriptor.getReceiverParameter().exists() ? contextDescriptor : null; - } - - @Override - protected CallableDescriptor getReceiverDescriptor() { - return receiverDescriptor; - } - } - - public static class MethodContext extends ReceiverContext { - - public MethodContext( - JetTypeMapper typeMapper, - @NotNull FunctionDescriptor contextType, - OwnerKind contextKind, - CodegenContext parentContext - ) { - super(typeMapper, contextType instanceof PropertyAccessorDescriptor - ? ((PropertyAccessorDescriptor) contextType).getCorrespondingProperty() - : contextType, contextKind, parentContext, null, - parentContext.hasThisDescriptor() ? parentContext.getThisDescriptor() : null); - } - - @Override - public StackValue lookupInContext(DeclarationDescriptor d, InstructionAdapter v, StackValue result) { - //noinspection ConstantConditions - return getParentContext().lookupInContext(d, v, result); - } - - @Override - public boolean isStatic() { - //noinspection ConstantConditions - return getParentContext().isStatic(); - } - - @Override - protected StackValue getOuterExpression(StackValue prefix) { - //noinspection ConstantConditions - return getParentContext().getOuterExpression(prefix); - } - - @Override - public String toString() { - return "Method: " + getContextDescriptor(); - } - } - - public static class ConstructorContext extends MethodContext { - public ConstructorContext( - JetTypeMapper typeMapper, - ConstructorDescriptor contextDescriptor, - OwnerKind kind, - CodegenContext parent - ) { - super(typeMapper, contextDescriptor, kind, parent); - - final ClassDescriptor type = getEnclosingClass(); - outerExpression = type != null ? local1 : null; - } - - @Override - protected StackValue getOuterExpression(StackValue prefix) { - return outerExpression; - } - - @Override - public String toString() { - return "Constructor: " + getContextDescriptor().getName(); - } - } - - public static class ScriptContext extends CodegenContext { - @NotNull - private final ScriptDescriptor scriptDescriptor; - - public ScriptContext( - JetTypeMapper typeMapper, - @NotNull ScriptDescriptor scriptDescriptor, - @NotNull ClassDescriptor contextDescriptor, - @NotNull OwnerKind contextKind, - @Nullable CodegenContext parentContext, - @Nullable ObjectOrClosureCodegen closureCodegen - ) { - super(typeMapper, contextDescriptor, contextKind, parentContext, closureCodegen, contextDescriptor); - - this.scriptDescriptor = scriptDescriptor; - } - - @NotNull - public ScriptDescriptor getScriptDescriptor() { - return scriptDescriptor; - } - - @Override - public boolean isStatic() { - return true; - } - } - - public static class ClassContext extends CodegenContext { - public ClassContext( - JetTypeMapper typeMapper, - ClassDescriptor contextDescriptor, - OwnerKind contextKind, - CodegenContext parentContext - ) { - super(typeMapper, contextDescriptor, contextKind, parentContext, null, contextDescriptor); - initOuterExpression(typeMapper, contextDescriptor); - } - - @Override - public boolean isStatic() { - return false; - } - } - - public static class AnonymousClassContext extends CodegenContext { - public AnonymousClassContext( - JetTypeMapper typeMapper, - ClassDescriptor contextDescriptor, - OwnerKind contextKind, - CodegenContext parentContext, - @NotNull ObjectOrClosureCodegen closure - ) { - super(typeMapper, contextDescriptor, contextKind, parentContext, closure, contextDescriptor); - initOuterExpression(typeMapper, contextDescriptor); - } - - @Override - public boolean isStatic() { - return false; - } - - @Override - public String toString() { - return "Anonymous: " + getThisDescriptor(); - } - } - - public static class ClosureContext extends ReceiverContext { - private final ClassDescriptor classDescriptor; - - public ClosureContext( - JetTypeMapper typeMapper, - FunctionDescriptor contextDescriptor, - ClassDescriptor classDescriptor, - CodegenContext parentContext, - @NotNull ObjectOrClosureCodegen closureCodegen - ) { - super(typeMapper, contextDescriptor, OwnerKind.IMPLEMENTATION, parentContext, closureCodegen, classDescriptor); - this.classDescriptor = classDescriptor; - - initOuterExpression(typeMapper, classDescriptor); - } - - @NotNull - @Override - public DeclarationDescriptor getContextDescriptor() { - return classDescriptor; - } - - @Override - public boolean isStatic() { - return false; - } - - @Override - public String toString() { - return "Closure: " + classDescriptor; - } - } - - public static class NamespaceContext extends CodegenContext { - public NamespaceContext(JetTypeMapper typeMapper, NamespaceDescriptor contextDescriptor, CodegenContext parent, OwnerKind kind) { - super(typeMapper, contextDescriptor, kind != null ? kind : OwnerKind.NAMESPACE, parent, null, null); - } - - @Override - public boolean isStatic() { - return true; - } - - @Override - public String toString() { - return "Namespace: " + getContextDescriptor().getName(); - } - } -} diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/CodegenUtil.java b/compiler/backend/src/org/jetbrains/jet/codegen/CodegenUtil.java index 9a4ebaaaacd..a30ad68cef5 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/CodegenUtil.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/CodegenUtil.java @@ -16,31 +16,39 @@ package org.jetbrains.jet.codegen; +import com.intellij.openapi.util.Pair; import com.intellij.psi.PsiElement; import org.jetbrains.annotations.NotNull; import org.jetbrains.asm4.MethodVisitor; import org.jetbrains.asm4.Type; import org.jetbrains.asm4.commons.InstructionAdapter; +import org.jetbrains.jet.codegen.context.CalculatedClosure; +import org.jetbrains.jet.codegen.signature.BothSignatureWriter; +import org.jetbrains.jet.codegen.signature.JvmMethodParameterKind; +import org.jetbrains.jet.codegen.signature.JvmMethodSignature; import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.BindingContextUtils; +import org.jetbrains.jet.lang.resolve.java.JvmClassName; import org.jetbrains.jet.lang.resolve.java.JvmStdlibNames; import org.jetbrains.jet.lang.resolve.name.Name; import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lang.types.lang.JetStandardClasses; -import java.util.BitSet; -import java.util.Collection; -import java.util.Collections; -import java.util.Random; +import java.util.*; + +import static org.jetbrains.asm4.Opcodes.*; /** * @author abreslav * @author alex.tkachman */ public class CodegenUtil { + public static final String RECEIVER$0 = "receiver$0"; + public static final String THIS$0 = "this$0"; + private CodegenUtil() { } @@ -83,6 +91,14 @@ public class CodegenUtil { !(myClass.getParent() instanceof JetClassObject); } + public static boolean isObjectLiteral(ClassDescriptor declaration, BindingContext bindingContext) { + PsiElement psiElement = BindingContextUtils.descriptorToDeclaration(bindingContext, declaration); + if (psiElement instanceof JetObjectDeclaration && ((JetObjectDeclaration) psiElement).isObjectLiteral()) { + return true; + } + return false; + } + public static boolean isLocalFun(DeclarationDescriptor fd, BindingContext bindingContext) { PsiElement psiElement = BindingContextUtils.descriptorToDeclaration(bindingContext, fd); if (psiElement instanceof JetNamedFunction && psiElement.getParent() instanceof JetBlockExpression) { @@ -126,12 +142,12 @@ public class CodegenUtil { } public static void generateThrow(MethodVisitor mv, String exception, String message) { - InstructionAdapter instructionAdapter = new InstructionAdapter(mv); - instructionAdapter.anew(Type.getObjectType(exception)); - instructionAdapter.dup(); - instructionAdapter.aconst(message); - instructionAdapter.invokespecial(exception, "", "(Ljava/lang/String;)V"); - instructionAdapter.athrow(); + InstructionAdapter iv = new InstructionAdapter(mv); + iv.anew(Type.getObjectType(exception)); + iv.dup(); + iv.aconst(message); + iv.invokespecial(exception, "", "(Ljava/lang/String;)V"); + iv.athrow(); } public static void generateMethodThrow(MethodVisitor mv, String exception, String message) { @@ -140,4 +156,92 @@ public class CodegenUtil { mv.visitMaxs(-1, -1); mv.visitEnd(); } + + @NotNull + public static JvmClassName getInternalClassName(FunctionDescriptor descriptor) { + final int paramCount = descriptor.getValueParameters().size(); + if (descriptor.getReceiverParameter().exists()) { + return JvmClassName.byInternalName("jet/ExtensionFunction" + paramCount); + } + else { + return JvmClassName.byInternalName("jet/Function" + paramCount); + } + } + + 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.OBJECT_TYPE, true); + signatureWriter.writeParameterTypeEnd(); + } + + signatureWriter.writeParametersEnd(); + + signatureWriter.writeReturnType(); + signatureWriter.writeAsmType(JetTypeMapper.OBJECT_TYPE, true); + signatureWriter.writeReturnTypeEnd(); + + return signatureWriter.makeJvmMethodSignature("invoke"); + } + + public static boolean isConst(CalculatedClosure closure) { + return closure.getCaptureThis() == null && closure.getCaptureReceiver() == null && closure.getCaptureVariables().isEmpty(); + } + + public static JetDelegatorToSuperCall findSuperCall(JetElement classOrObject, BindingContext bindingContext) { + if (!(classOrObject instanceof JetClassOrObject)) { + return null; + } + + if (classOrObject instanceof JetClass && ((JetClass) classOrObject).isTrait()) { + return null; + } + for (JetDelegationSpecifier specifier : ((JetClassOrObject) classOrObject).getDelegationSpecifiers()) { + if (specifier instanceof JetDelegatorToSuperCall) { + JetType superType = bindingContext.get(BindingContext.TYPE, specifier.getTypeReference()); + assert superType != null; + ClassDescriptor superClassDescriptor = (ClassDescriptor) superType.getConstructor().getDeclarationDescriptor(); + assert superClassDescriptor != null; + if (!isInterface(superClassDescriptor)) { + return (JetDelegatorToSuperCall) specifier; + } + } + } + + return null; + } + + public static void generateClosureFields(CalculatedClosure closure, ClassBuilder v, JetTypeMapper typeMapper) { + final ClassifierDescriptor captureThis = closure.getCaptureThis(); + final int access = ACC_PUBLIC | ACC_SYNTHETIC | ACC_FINAL; + if (captureThis != null) { + v.newField(null, access, THIS$0, typeMapper.mapType(captureThis.getDefaultType(), MapTypeMode.VALUE).getDescriptor(), null, + null); + } + + final ClassifierDescriptor captureReceiver = closure.getCaptureReceiver(); + if (captureReceiver != null) { + v.newField(null, access, RECEIVER$0, typeMapper.mapType(captureReceiver.getDefaultType(), MapTypeMode.VALUE).getDescriptor(), + null, null); + } + + final List> fields = closure.getRecordedFields(); + for (Pair field : fields) { + v.newField(null, access, field.first, field.second.getDescriptor(), null, null); + } + } } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ConstructorFrameMap.java b/compiler/backend/src/org/jetbrains/jet/codegen/ConstructorFrameMap.java index 0e0a5cadda2..bf65e2ecfbf 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ConstructorFrameMap.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ConstructorFrameMap.java @@ -18,7 +18,8 @@ package org.jetbrains.jet.codegen; import org.jetbrains.annotations.Nullable; import org.jetbrains.asm4.Type; -import org.jetbrains.jet.lang.descriptors.ClassKind; +import org.jetbrains.jet.codegen.signature.JvmMethodParameterKind; +import org.jetbrains.jet.codegen.signature.JvmMethodParameterSignature; import org.jetbrains.jet.lang.descriptors.ConstructorDescriptor; import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor; @@ -32,23 +33,25 @@ import java.util.List; public class ConstructorFrameMap extends FrameMap { private int myOuterThisIndex = -1; - public ConstructorFrameMap(CallableMethod callableMethod, @Nullable ConstructorDescriptor descriptor, boolean hasThis0) { + public ConstructorFrameMap(CallableMethod callableMethod, @Nullable ConstructorDescriptor descriptor) { enterTemp(JetTypeMapper.OBJECT_TYPE); // this - if (descriptor != null) { - if (hasThis0) { - myOuterThisIndex = enterTemp(JetTypeMapper.OBJECT_TYPE); // outer class instance + + final List parameterTypes = callableMethod.getSignature().getKotlinParameterTypes(); + if (parameterTypes != null) { + for (JvmMethodParameterSignature parameterType : parameterTypes) { + if (parameterType.getKind() == JvmMethodParameterKind.OUTER) { + myOuterThisIndex = enterTemp(JetTypeMapper.OBJECT_TYPE); // this0 + } + else if (parameterType.getKind() != JvmMethodParameterKind.VALUE) { + enterTemp(parameterType.getAsmType()); + } + else { + break; + } } } List explicitArgTypes = callableMethod.getValueParameterTypes(); - - if (descriptor != null && - (descriptor.getContainingDeclaration().getKind() == ClassKind.ENUM_CLASS || - descriptor.getContainingDeclaration().getKind() == ClassKind.ENUM_ENTRY)) { - enterTemp(JetTypeMapper.OBJECT_TYPE); // name - enterTemp(Type.INT_TYPE); // ordinal - } - List paramDescrs = descriptor != null ? descriptor.getValueParameters() : Collections.emptyList(); diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index 54be6f5156a..88ec2b2ae2f 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -33,6 +33,7 @@ import org.jetbrains.asm4.Opcodes; import org.jetbrains.asm4.Type; import org.jetbrains.asm4.commons.InstructionAdapter; import org.jetbrains.asm4.commons.Method; +import org.jetbrains.jet.codegen.context.*; import org.jetbrains.jet.codegen.intrinsics.IntrinsicMethod; import org.jetbrains.jet.codegen.signature.JvmPropertyAccessorSignature; import org.jetbrains.jet.lang.descriptors.*; @@ -63,7 +64,7 @@ import static org.jetbrains.jet.lang.resolve.BindingContextUtils.getNotNull; * @author yole * @author alex.tkachman */ -public class ExpressionCodegen extends JetVisitor { +public class ExpressionCodegen extends JetVisitor implements LocalLookup { private static final String CLASS_NO_PATTERN_MATCHED_EXCEPTION = "jet/NoPatternMatchedException"; private static final String CLASS_TYPE_CAST_EXCEPTION = "jet/TypeCastException"; @@ -78,7 +79,7 @@ public class ExpressionCodegen extends JetVisitor { private final Type returnType; private final BindingContext bindingContext; - private final CodegenContext context; + final CodegenContext context; private final Stack blockStackElements = new Stack(); private final Collection localVariableNames = new HashSet(); @@ -136,6 +137,10 @@ public class ExpressionCodegen extends JetVisitor { this.context = context; } + public GenerationState getState() { + return state; + } + StackValue castToRequiredTypeOfInterfaceIfNeeded(StackValue inner, DeclarationDescriptor provided, @Nullable ClassDescriptor required) { if (required == null) { return inner; @@ -218,14 +223,11 @@ public class ExpressionCodegen extends JetVisitor { private StackValue visitClassOrObject(JetClassOrObject declaration) { ClassDescriptor descriptor = bindingContext.get(BindingContext.CLASS, declaration); - ObjectOrClosureCodegen closure = new LocalClassClosureCodegen(this, context, state, descriptor); + assert descriptor != null; + Pair nameAndVisitor = state.forAnonymousSubclass(declaration); - closure.cv = nameAndVisitor.getSecond(); - closure.name = nameAndVisitor.getFirst(); - final CodegenContext objectContext = closure.context.intoAnonymousClass( - closure, descriptor, OwnerKind.IMPLEMENTATION, - typeMapper); + final CodegenContext objectContext = context.intoAnonymousClass(descriptor, this); new ImplementationBodyCodegen(declaration, objectContext, nameAndVisitor.getSecond(), state).generate(); return StackValue.none(); @@ -394,13 +396,13 @@ public class ExpressionCodegen extends JetVisitor { return StackValue.none(); } - generateForInIterable(expression, loopRangeType); + generateForInIterable(expression); return StackValue.none(); } } @SuppressWarnings("ConstantConditions") - private void generateForInIterable(JetForExpression expression, Type loopRangeType) { + private void generateForInIterable(JetForExpression expression) { generateForLoop(expression.getBody(), new IteratorForLoopGenerator(expression)); } @@ -410,9 +412,13 @@ public class ExpressionCodegen extends JetVisitor { private interface ForLoopGenerator { void beforeLoop(); + void conditionAndJump(@NotNull Label loopExit); + void beforeBody(); + void afterBody(); + void afterLoop(); } @@ -457,6 +463,7 @@ public class ExpressionCodegen extends JetVisitor { @NotNull private JetType getElementType(JetForExpression forExpression) { JetExpression loopRange = forExpression.getLoopRange(); + assert loopRange != null; ResolvedCall nextCall = getNotNull(bindingContext, LOOP_RANGE_NEXT_RESOLVED_CALL, loopRange, "No next() function " + DiagnosticUtils.atLocation(loopRange)); @@ -470,7 +477,7 @@ public class ExpressionCodegen extends JetVisitor { if (loopParameter != null) { // E e = tmp.next() final VariableDescriptor parameterDescriptor = bindingContext.get(BindingContext.VALUE_PARAMETER, loopParameter); - final Type asmTypeForParameter = asmType(parameterDescriptor.getType()); + @SuppressWarnings("ConstantConditions") final Type asmTypeForParameter = asmType(parameterDescriptor.getType()); final int parameterIndex = myFrameMap.enter(parameterDescriptor, asmTypeForParameter); leaveVariableTasks.add(new Runnable() { @Override @@ -510,7 +517,7 @@ public class ExpressionCodegen extends JetVisitor { for (JetMultiDeclarationEntry variableDeclaration : entries) { final VariableDescriptor componentDescriptor = bindingContext.get(BindingContext.VARIABLE, variableDeclaration); - final Type componentAsmType = asmType(componentDescriptor.getReturnType()); + @SuppressWarnings("ConstantConditions") final Type componentAsmType = asmType(componentDescriptor.getReturnType()); final int componentVarIndex = myFrameMap.enter(componentDescriptor, componentAsmType); leaveVariableTasks.add(new Runnable() { @Override @@ -524,7 +531,8 @@ public class ExpressionCodegen extends JetVisitor { }); - ResolvedCall resolvedCall = bindingContext.get(BindingContext.COMPONENT_RESOLVED_CALL, variableDeclaration); + ResolvedCall resolvedCall = + bindingContext.get(BindingContext.COMPONENT_RESOLVED_CALL, variableDeclaration); assert resolvedCall != null : "Resolved call is null for " + variableDeclaration.getText(); Call call = makeFakeCall(new TransientReceiver(elementType)); invokeFunction(call, StackValue.local(tmpParameterIndex, asmElementType), resolvedCall); @@ -554,9 +562,10 @@ public class ExpressionCodegen extends JetVisitor { super(forExpression); JetExpression loopRange = forExpression.getLoopRange(); + assert loopRange != null; this.iteratorCall = getNotNull(bindingContext, - LOOP_RANGE_ITERATOR_RESOLVED_CALL, loopRange, - "No .iterator() function " + DiagnosticUtils.atLocation(loopRange)); + LOOP_RANGE_ITERATOR_RESOLVED_CALL, loopRange, + "No .iterator() function " + DiagnosticUtils.atLocation(loopRange)); JetType iteratorType = iteratorCall.getResultingDescriptor().getReturnType(); assert iteratorType != null; @@ -583,10 +592,10 @@ public class ExpressionCodegen extends JetVisitor { // tmp.hasNext() JetExpression loopRange = forExpression.getLoopRange(); - ResolvedCall hasNextCall = getNotNull(bindingContext, + @SuppressWarnings("ConstantConditions") ResolvedCall hasNextCall = getNotNull(bindingContext, LOOP_RANGE_HAS_NEXT_RESOLVED_CALL, loopRange, "No hasNext() function " + DiagnosticUtils.atLocation(loopRange)); - Call fakeCall = makeFakeCall(new TransientReceiver(iteratorCall.getResultingDescriptor().getReturnType())); + @SuppressWarnings("ConstantConditions") Call fakeCall = makeFakeCall(new TransientReceiver(iteratorCall.getResultingDescriptor().getReturnType())); invokeFunction(fakeCall, StackValue.local(iteratorVarIndex, asmTypeForIterator), hasNextCall); JetType type = hasNextCall.getResultingDescriptor().getReturnType(); @@ -599,9 +608,10 @@ public class ExpressionCodegen extends JetVisitor { @Override protected void assignToLoopParameter(int parameterIndex) { - Call fakeCall = + @SuppressWarnings("ConstantConditions") Call fakeCall = makeFakeCall(new TransientReceiver(iteratorCall.getResultingDescriptor().getReturnType())); invokeFunction(fakeCall, StackValue.local(iteratorVarIndex, asmTypeForIterator), nextCall); + //noinspection ConstantConditions v.store(parameterIndex, asmType(nextCall.getResultingDescriptor().getReturnType())); } @@ -763,7 +773,7 @@ public class ExpressionCodegen extends JetVisitor { @Override protected void generatePrologue() { - myIndexVar = lookupLocal(parameterDescriptor); + myIndexVar = lookupLocalIndex(parameterDescriptor); myCountVar = myFrameMap.enterTemp(Type.INT_TYPE); myDeltaVar = myFrameMap.enterTemp(Type.INT_TYPE); if (isIntRangeExpr(expression.getLoopRange())) { @@ -977,7 +987,7 @@ public class ExpressionCodegen extends JetVisitor { StackValue closure = genClosure(function); DeclarationDescriptor descriptor = bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, function); - int index = myFrameMap.getIndex(descriptor); + int index = lookupLocalIndex(descriptor); closure.put(OBJECT_TYPE, v); v.store(index, OBJECT_TYPE); return StackValue.none(); @@ -996,89 +1006,90 @@ public class ExpressionCodegen extends JetVisitor { } private StackValue genClosure(JetExpression expression) { - ClosureCodegen closureCodegen = new ClosureCodegen(state, this, context); - final GeneratedAnonymousClassDescriptor closure = closureCodegen.gen(expression); + final FunctionDescriptor descriptor = bindingContext.get(BindingContext.FUNCTION, expression); + final ClosureAnnotator closureAnnotator = state.getInjector().getClosureAnnotator(); + final ClassDescriptor classDescriptor = closureAnnotator.classDescriptorForFunctionDescriptor(descriptor); + final CalculatedClosure closure = closureAnnotator.getCalculatedClosure(classDescriptor); - if (closureCodegen.isConst()) { - v.invokestatic(closure.getClassname().getInternalName(), "$getInstance", "()" + closure.getClassname().getDescriptor()); + ClosureCodegen closureCodegen = new ClosureCodegen(state, (MutableClosure) closure).gen(expression, context, this); + + final JvmClassName className = closureCodegen.name; + final Type asmType = className.getAsmType(); + final String internalName = className.getInternalName(); + if (CodegenUtil.isConst(closure)) { + v.invokestatic(internalName, "$getInstance", "()" + className.getDescriptor()); } else { - v.anew(closure.getClassname().getAsmType()); + v.anew(asmType); v.dup(); - final Method cons = closure.getConstructor(); - - int k = 0; - if (closure.isCaptureThis()) { - k++; - v.load(0, OBJECT_TYPE); - } - - if (closure.isCaptureReceiver()) { - k++; - v.load(context.getContextDescriptor().getContainingDeclaration() instanceof NamespaceDescriptor ? 0 : 1, - typeMapper.mapType(closure.getCaptureReceiver().getDefaultType(), MapTypeMode.IMPL)); - } - - for (int i = 0; i < closure.getArgs().size(); i++) { - StackValue arg = closure.getArgs().get(i); - arg.put(cons.getArgumentTypes()[i + k], v); - } - - v.invokespecial(closure.getClassname().getInternalName(), "", cons.getDescriptor()); + final Method cons = closureCodegen.constructor; + pushClosureOnStack(closure, false); + v.invokespecial(internalName, "", cons.getDescriptor()); } - return StackValue.onStack(closure.getClassname().getAsmType()); + return StackValue.onStack(asmType); } @Override public StackValue visitObjectLiteralExpression(JetObjectLiteralExpression expression, StackValue receiver) { - ObjectOrClosureCodegen closureCodegen = new ObjectOrClosureCodegen(this, context, state); - GeneratedAnonymousClassDescriptor closure = state.generateObjectLiteral(expression, closureCodegen); - Type type = closure.getClassname().getAsmType(); + CalculatedClosure closure = state.generateObjectLiteral(expression, this); + + ConstructorDescriptor constructorDescriptor = bindingContext.get(BindingContext.CONSTRUCTOR, expression.getObjectDeclaration()); + assert constructorDescriptor != null; + CallableMethod constructor = typeMapper.mapToCallableMethod(constructorDescriptor, closure); + + final JvmClassName name = closure.getClassName(); + Type type = name.getAsmType(); v.anew(type); v.dup(); - final List consArgTypes = new LinkedList(Arrays.asList(closure.getConstructor().getArgumentTypes())); + final Method cons = constructor.getSignature().getAsmMethod(); - if (consArgTypes.size() > 0) { - v.load(0, OBJECT_TYPE); - } + pushClosureOnStack(closure, false); - if (closureCodegen.captureReceiver != null) { - final Type asmType = typeMapper.mapType(closureCodegen.captureReceiver.getDefaultType(), MapTypeMode.IMPL); - v.load(context.isStatic() ? 0 : 1, asmType); - consArgTypes.add(asmType); - } - - for (Map.Entry entry : closureCodegen.closure.entrySet()) { - if (entry.getKey() instanceof VariableDescriptor && !(entry.getKey() instanceof PropertyDescriptor)) { - Type sharedVarType = typeMapper.getSharedVarType(entry.getKey()); - if (sharedVarType == null) { - sharedVarType = state.getInjector().getJetTypeMapper() - .mapType(((VariableDescriptor) entry.getKey()).getType(), MapTypeMode.VALUE); - } - consArgTypes.add(sharedVarType); - entry.getValue().getOuterValue().put(sharedVarType, v); - } - } - - if (closureCodegen.superCall != null) { + final JetDelegatorToSuperCall superCall = closure.getSuperCall(); + if (superCall != null) { ConstructorDescriptor superConstructor = (ConstructorDescriptor) bindingContext.get(BindingContext.REFERENCE_TARGET, - closureCodegen.superCall + superCall .getCalleeExpression() .getConstructorReferenceExpression()); assert superConstructor != null; - CallableMethod superCallable = typeMapper.mapToCallableMethod(superConstructor, - typeMapper.hasThis0(superConstructor.getContainingDeclaration())); + CallableMethod superCallable = typeMapper + .mapToCallableMethod(superConstructor, typeMapper.getCalculatedClosure(superConstructor.getContainingDeclaration())); Type[] argumentTypes = superCallable.getSignature().getAsmMethod().getArgumentTypes(); - Collections.addAll(consArgTypes, argumentTypes); - ResolvedCall resolvedCall = bindingContext.get(BindingContext.RESOLVED_CALL, closureCodegen.superCall.getCalleeExpression()); + ResolvedCall resolvedCall = bindingContext.get(BindingContext.RESOLVED_CALL, superCall.getCalleeExpression()); assert resolvedCall != null; pushMethodArguments(resolvedCall, Arrays.asList(argumentTypes)); } - Method cons = new Method("", Type.VOID_TYPE, consArgTypes.toArray(new Type[consArgTypes.size()])); - v.invokespecial(closure.getClassname().getInternalName(), "", cons.getDescriptor()); - return StackValue.onStack(closure.getClassname().getAsmType()); + v.invokespecial(name.getInternalName(), "", cons.getDescriptor()); + return StackValue.onStack(type); + } + + protected void pushClosureOnStack(CalculatedClosure closure, boolean ignoreThisAndReceiver) { + if (closure != null) { + if (!ignoreThisAndReceiver) { + final ClassDescriptor captureThis = closure.getCaptureThis(); + if (captureThis != null) { + generateThisOrOuter(captureThis).put(OBJECT_TYPE, v); + } + + final ClassifierDescriptor captureReceiver = closure.getCaptureReceiver(); + if (captureReceiver != null) { + final Type asmType = typeMapper.mapType(captureReceiver.getDefaultType(), MapTypeMode.IMPL); + v.load(context.isStatic() ? 0 : 1, asmType); + } + } + + for (Map.Entry entry : closure.getCaptureVariables().entrySet()) { + //if (entry.getKey() instanceof VariableDescriptor && !(entry.getKey() instanceof PropertyDescriptor)) { + Type sharedVarType = typeMapper.getSharedVarType(entry.getKey()); + if (sharedVarType == null) { + sharedVarType = typeMapper.mapType(((VariableDescriptor) entry.getKey()).getType(), MapTypeMode.VALUE); + } + entry.getValue().getOuterValue(this).put(sharedVarType, v); + //} + } + } } private StackValue generateBlock(List statements) { @@ -1301,7 +1312,7 @@ public class ExpressionCodegen extends JetVisitor { } } - int index = lookupLocal(descriptor); + int index = lookupLocalIndex(descriptor); if (index >= 0) { return stackValueForLocal(descriptor, index); } @@ -1379,7 +1390,7 @@ public class ExpressionCodegen extends JetVisitor { return StackValue.onStack(OBJECT_TYPE); } - StackValue value = context.lookupInContext(descriptor, v, StackValue.local(0, OBJECT_TYPE)); + StackValue value = context.lookupInContext(descriptor, StackValue.local(0, OBJECT_TYPE), state, false); if (value != null) { if (value instanceof StackValue.Composed) { @@ -1445,39 +1456,13 @@ public class ExpressionCodegen extends JetVisitor { } } - public int lookupLocal(DeclarationDescriptor descriptor) { - return myFrameMap.getIndex(descriptor); + @Override + public boolean lookupLocal(DeclarationDescriptor descriptor) { + return lookupLocalIndex(descriptor) != -1; } - public void invokeFunctionNoParams(FunctionDescriptor functionDescriptor, Type expectedType, InstructionAdapter v) { - DeclarationDescriptor containingDeclaration = functionDescriptor.getOriginal().getContainingDeclaration(); - boolean isStatic = containingDeclaration instanceof NamespaceDescriptor; - functionDescriptor = functionDescriptor.getOriginal(); - JvmClassName owner; - - IntrinsicMethod intrinsic = state.getInjector().getIntrinsics().getIntrinsic(functionDescriptor); - if (intrinsic != null) { - intrinsic.generate(this, v, expectedType, null, null, StackValue.onStack(OBJECT_TYPE), state); - return; - } - - boolean isInterface; - boolean isInsideClass = containingDeclaration == context.getThisDescriptor(); - if (isInsideClass || isStatic) { - owner = typeMapper.getOwner(functionDescriptor, contextKind()); - isInterface = false; - } - else { - owner = typeMapper.getOwner(functionDescriptor, OwnerKind.IMPLEMENTATION); - isInterface = CodegenUtil.isInterface(containingDeclaration); - } - - int opcode = isStatic ? Opcodes.INVOKESTATIC : isInterface ? Opcodes.INVOKEINTERFACE : Opcodes.INVOKEVIRTUAL; - v.visitMethodInsn(opcode, owner.getInternalName(), functionDescriptor.getName().getName(), - typeMapper.mapSignature(functionDescriptor.getName(), functionDescriptor).getAsmMethod().getDescriptor()); - JetType returnType = functionDescriptor.getReturnType(); - assert returnType != null; - StackValue.onStack(asmType(returnType)).coerce(expectedType, v); + public int lookupLocalIndex(DeclarationDescriptor descriptor) { + return myFrameMap.getIndex(descriptor); } public StackValue.Property intermediateValueForProperty( @@ -1499,7 +1484,7 @@ public class ExpressionCodegen extends JetVisitor { boolean isInsideClass = !isFakeOverride && (((containingDeclaration == null && !context.hasThisDescriptor() || context.hasThisDescriptor() && containingDeclaration == context.getThisDescriptor()) || - (context.getParentContext() instanceof CodegenContexts.NamespaceContext) && + (context.getParentContext() instanceof CodegenContext.NamespaceContext) && context.getParentContext().getContextDescriptor() == containingDeclaration) && contextKind() != OwnerKind.TRAIT_IMPL); Method getter = null; @@ -1681,7 +1666,7 @@ public class ExpressionCodegen extends JetVisitor { if (enclosed != context.getThisDescriptor()) { CodegenContext c = context; //noinspection ConstantConditions - while (!(c instanceof CodegenContexts.ClassContext) || + while (!(c instanceof CodegenContext.ClassContext) || !DescriptorUtils.isSubclass(c.getThisDescriptor(), enclosed)) { c = c.getParentContext(); assert c != null; @@ -1761,7 +1746,7 @@ public class ExpressionCodegen extends JetVisitor { //} if (isCallAsFunctionObject(fd)) { SimpleFunctionDescriptor invoke = CodegenUtil.createInvoke(fd); - callableMethod = ClosureCodegen.asCallableMethod(invoke, typeMapper); + callableMethod = typeMapper.asCallableMethod(invoke); } else { callableMethod = typeMapper.mapToCallableMethod(fd, superCall, OwnerKind.IMPLEMENTATION); @@ -1895,14 +1880,12 @@ public class ExpressionCodegen extends JetVisitor { } private StackValue generateReceiver(DeclarationDescriptor provided) { - assert context instanceof CodegenContexts.ReceiverContext; - CodegenContexts.ReceiverContext cur = (CodegenContexts.ReceiverContext) context; - if (cur.getReceiverDescriptor() == provided) { - StackValue result = cur.getReceiverExpression(typeMapper); + if (context.getReceiverDescriptor() == provided) { + StackValue result = context.getReceiverExpression(typeMapper); return castToRequiredTypeOfInterfaceIfNeeded(result, provided, null); } - StackValue result = context.lookupInContext(provided, v, StackValue.local(0, OBJECT_TYPE)); + StackValue result = context.lookupInContext(provided, StackValue.local(0, OBJECT_TYPE), state, false); return castToRequiredTypeOfInterfaceIfNeeded(result, provided, null); } @@ -1910,12 +1893,12 @@ public class ExpressionCodegen extends JetVisitor { CodegenContext cur = context; StackValue result = StackValue.local(0, OBJECT_TYPE); while (cur != null) { - if (cur instanceof CodegenContexts.MethodContext && !(cur instanceof CodegenContexts.ConstructorContext)) { + if (cur instanceof CodegenContext.MethodContext && !(cur instanceof CodegenContext.ConstructorContext)) { cur = cur.getParentContext(); } - if (cur instanceof CodegenContexts.ScriptContext) { - CodegenContexts.ScriptContext scriptContext = (CodegenContexts.ScriptContext) cur; + if (cur instanceof CodegenContext.ScriptContext) { + CodegenContext.ScriptContext scriptContext = (CodegenContext.ScriptContext) cur; JvmClassName currentScriptClassName = state.getInjector().getClosureAnnotator().classNameForScriptDescriptor(scriptContext.getScriptDescriptor()); @@ -1933,9 +1916,9 @@ public class ExpressionCodegen extends JetVisitor { } assert cur != null; - result = cur.getOuterExpression(result); + result = cur.getOuterExpression(result, false); - if (cur instanceof CodegenContexts.ConstructorContext) { + if (cur instanceof CodegenContext.ConstructorContext) { cur = cur.getParentContext(); } assert cur != null; @@ -1953,7 +1936,7 @@ public class ExpressionCodegen extends JetVisitor { Type type = asmType(calleeContainingClass.getDefaultType()); StackValue result = StackValue.local(0, type); while (cur != null) { - if (cur instanceof CodegenContexts.MethodContext && !(cur instanceof CodegenContexts.ConstructorContext)) { + if (cur instanceof CodegenContext.MethodContext && !(cur instanceof CodegenContext.ConstructorContext)) { cur = cur.getParentContext(); } @@ -1969,9 +1952,9 @@ public class ExpressionCodegen extends JetVisitor { } } - result = cur.getOuterExpression(result); + result = cur.getOuterExpression(result, false); - if (cur instanceof CodegenContexts.ConstructorContext) { + if (cur instanceof CodegenContext.ConstructorContext) { cur = cur.getParentContext(); } assert cur != null; @@ -2125,7 +2108,7 @@ public class ExpressionCodegen extends JetVisitor { if (typeMapper.isVarCapturedInClosure(declarationDescriptor)) { return -1; } - return lookupLocal(declarationDescriptor); + return lookupLocalIndex(declarationDescriptor); } @Override @@ -2220,7 +2203,6 @@ public class ExpressionCodegen extends JetVisitor { } private StackValue generateIn(JetBinaryExpression expression) { - JetExpression expr = expression.getLeft(); boolean inverted = expression.getOperationReference().getReferencedNameElementType() == JetTokens.NOT_IN; if (isIntRangeExpr(expression.getRight())) { StackValue leftValue = StackValue.expression(Type.INT_TYPE, expression.getLeft(), this); @@ -2651,9 +2633,9 @@ public class ExpressionCodegen extends JetVisitor { } private StackValue invokeOperation(JetOperationExpression expression, FunctionDescriptor op, CallableMethod callable) { - int functionLocalIndex = myFrameMap.getIndex(op); + int functionLocalIndex = lookupLocalIndex(op); if (functionLocalIndex >= 0) { - stackValueForLocal(op, functionLocalIndex).put(ClosureCodegen.getInternalClassName(op).getAsmType(), v); + stackValueForLocal(op, functionLocalIndex).put(CodegenUtil.getInternalClassName(op).getAsmType(), v); } ResolvedCall resolvedCall = bindingContext.get(BindingContext.RESOLVED_CALL, expression.getOperationReference()); @@ -2840,7 +2822,7 @@ public class ExpressionCodegen extends JetVisitor { if (JetPsiUtil.isScriptDeclaration(variableDeclaration)) { return; } - int index = lookupLocal(variableDescriptor); + int index = lookupLocalIndex(variableDescriptor); if (index < 0) { throw new IllegalStateException("Local variable not found for " + variableDescriptor); @@ -2894,15 +2876,13 @@ public class ExpressionCodegen extends JetVisitor { v.anew(type); v.dup(); - // TODO typechecker must verify that we're the outer class of the instance being created - //noinspection ConstantConditions - if (!receiver.type.equals(Type.VOID_TYPE)) { - receiver.put(receiver.type, v); - } - + final ClassDescriptor classDescriptor = ((ConstructorDescriptor) constructorDescriptor).getContainingDeclaration(); CallableMethod method = typeMapper .mapToCallableMethod((ConstructorDescriptor) constructorDescriptor, typeMapper - .hasThis0(((ConstructorDescriptor) constructorDescriptor).getContainingDeclaration())); + .getCalculatedClosure(classDescriptor)); + + receiver.put(receiver.type, v); + pushClosureOnStack(typeMapper.getCalculatedClosure(classDescriptor), true); invokeMethodWithArguments(method, expression, StackValue.none()); } } @@ -3089,10 +3069,10 @@ public class ExpressionCodegen extends JetVisitor { return StackValue.thisOrOuter(this, (ClassDescriptor) descriptor); } else { - if (descriptor instanceof FunctionDescriptor || descriptor instanceof PropertyDescriptor) { + if (descriptor instanceof CallableDescriptor) { return generateReceiver(descriptor); } - throw new UnsupportedOperationException(); + throw new UnsupportedOperationException("neither this nor receiver"); } } @@ -3143,7 +3123,7 @@ The "returned" value of try expression with no finally is either the last expres assert descriptor != null; Type descriptorType = asmType(descriptor.getType()); myFrameMap.enter(descriptor, descriptorType); - int index = lookupLocal(descriptor); + int index = lookupLocalIndex(descriptor); v.store(index, descriptorType); gen(clause.getCatchBody(), expectedAsmType); @@ -3308,7 +3288,7 @@ The "returned" value of try expression with no finally is either the last expres myFrameMap.enter(variableDescriptor, varType); expressionToMatch.dupReceiver(v); expressionToMatch.put(varType, v); - final int varIndex = myFrameMap.getIndex(variableDescriptor); + final int varIndex = lookupLocalIndex(variableDescriptor); v.store(varIndex, varType); return generateWhenCondition(varType, varIndex, false, ((JetBindingPattern) pattern).getCondition(), null); } @@ -3573,5 +3553,4 @@ The "returned" value of try expression with no finally is either the last expres public String toString() { return context.getContextDescriptor().toString(); } - } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java index 0ccbc84a91e..5ec69a6d8b3 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java @@ -25,6 +25,7 @@ import org.jetbrains.asm4.MethodVisitor; import org.jetbrains.asm4.Type; import org.jetbrains.asm4.commons.InstructionAdapter; import org.jetbrains.asm4.commons.Method; +import org.jetbrains.jet.codegen.context.CodegenContext; import org.jetbrains.jet.codegen.signature.JvmMethodSignature; import org.jetbrains.jet.codegen.signature.kotlin.JetMethodAnnotationWriter; import org.jetbrains.jet.codegen.signature.kotlin.JetValueParameterAnnotationWriter; @@ -74,7 +75,7 @@ public class FunctionCodegen { @Nullable String propertyTypeSignature, FunctionDescriptor functionDescriptor ) { - CodegenContexts.MethodContext funContext = owner.intoFunction(functionDescriptor, state.getInjector().getJetTypeMapper()); + CodegenContext.MethodContext funContext = owner.intoFunction(functionDescriptor); final JetExpression bodyExpression = f.getBodyExpression(); generatedMethod(bodyExpression, jvmMethod, needJetAnnotations, propertyTypeSignature, funContext, functionDescriptor, f); @@ -84,7 +85,7 @@ public class FunctionCodegen { JetExpression bodyExpressions, JvmMethodSignature jvmSignature, boolean needJetAnnotations, @Nullable String propertyTypeSignature, - CodegenContexts.MethodContext context, + CodegenContext.MethodContext context, FunctionDescriptor functionDescriptor, JetDeclarationWithBody fun ) { @@ -334,7 +335,6 @@ public class FunctionCodegen { } endVisit(mv, null, fun); - mv.visitEnd(); generateBridgeIfNeeded(owner, state, v, jvmSignature.getAsmMethod(), functionDescriptor, kind); } @@ -417,7 +417,7 @@ public class FunctionCodegen { } static void generateDefaultIfNeeded( - CodegenContexts.MethodContext owner, + CodegenContext.MethodContext owner, GenerationState state, ClassBuilder v, Method jvmSignature, @@ -477,7 +477,7 @@ public class FunctionCodegen { } private static void generateDefaultImpl( - CodegenContexts.MethodContext owner, + CodegenContext.MethodContext owner, GenerationState state, Method jvmSignature, FunctionDescriptor functionDescriptor, diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/GeneratedAnonymousClassDescriptor.java b/compiler/backend/src/org/jetbrains/jet/codegen/GeneratedAnonymousClassDescriptor.java deleted file mode 100644 index e3b49b4af00..00000000000 --- a/compiler/backend/src/org/jetbrains/jet/codegen/GeneratedAnonymousClassDescriptor.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright 2010-2012 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * @author max - */ -package org.jetbrains.jet.codegen; - -import org.jetbrains.asm4.commons.Method; -import org.jetbrains.jet.lang.descriptors.ClassDescriptor; -import org.jetbrains.jet.lang.descriptors.ClassifierDescriptor; -import org.jetbrains.jet.lang.resolve.java.JvmClassName; - -import java.util.ArrayList; -import java.util.List; - -public class GeneratedAnonymousClassDescriptor { - private final JvmClassName classname; - private final Method constructor; - - private final ClassDescriptor captureThis; - private final ClassifierDescriptor captureReceiver; - private final List args = new ArrayList(); - - public GeneratedAnonymousClassDescriptor( - JvmClassName classname, - Method constructor, - ClassDescriptor captureThis, - ClassifierDescriptor captureReceiver - ) { - this.classname = classname; - this.constructor = constructor; - this.captureThis = captureThis; - this.captureReceiver = captureReceiver; - } - - public JvmClassName getClassname() { - return classname; - } - - public Method getConstructor() { - return constructor; - } - - public void addArg(StackValue local) { - args.add(local); - } - - public List getArgs() { - return args; - } - - public boolean isCaptureThis() { - return captureThis != null; - } - - public boolean isCaptureReceiver() { - return captureReceiver != null; - } - - public ClassDescriptor getCaptureThis() { - return captureThis; - } - - public ClassifierDescriptor getCaptureReceiver() { - return captureReceiver; - } -} diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/GenerationState.java b/compiler/backend/src/org/jetbrains/jet/codegen/GenerationState.java index 676816764a6..3d57bbecf60 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/GenerationState.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/GenerationState.java @@ -25,9 +25,10 @@ import com.intellij.util.containers.MultiMap; import org.jetbrains.annotations.NotNull; import org.jetbrains.asm4.commons.Method; import org.jetbrains.jet.analyzer.AnalyzeExhaust; +import org.jetbrains.jet.codegen.context.CalculatedClosure; +import org.jetbrains.jet.codegen.context.CodegenContext; import org.jetbrains.jet.di.InjectorForJvmCodegen; import org.jetbrains.jet.lang.descriptors.ClassDescriptor; -import org.jetbrains.jet.lang.descriptors.ConstructorDescriptor; import org.jetbrains.jet.lang.descriptors.ScriptDescriptor; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.BindingContext; @@ -56,7 +57,6 @@ public class GenerationState { // out parameter private Method scriptConstructorMethod; private final BindingContext bindingContext; - private final JetTypeMapper typeMapper; public GenerationState(Project project, ClassBuilderFactory builderFactory, AnalyzeExhaust analyzeExhaust, List files) { @@ -75,7 +75,6 @@ public class GenerationState { this.injector = new InjectorForJvmCodegen( bindingContext, this.files, builtinToJavaTypesMapping, builderFactory.getClassBuilderMode(), this, builderFactory, project); - typeMapper = injector.getJetTypeMapper(); } private void markUsed() { @@ -195,25 +194,20 @@ public class GenerationState { codegen.generate(errorHandler, progress); } - public GeneratedAnonymousClassDescriptor generateObjectLiteral(JetObjectLiteralExpression literal, ObjectOrClosureCodegen closure) { + public CalculatedClosure generateObjectLiteral(JetObjectLiteralExpression literal, ExpressionCodegen expressionCodegen) { JetObjectDeclaration objectDeclaration = literal.getObjectDeclaration(); Pair nameAndVisitor = forAnonymousSubclass(objectDeclaration); - closure.cv = nameAndVisitor.getSecond(); - closure.name = nameAndVisitor.getFirst(); - final CodegenContext objectContext = closure.context.intoAnonymousClass( - closure, bindingContext.get(BindingContext.CLASS, objectDeclaration), OwnerKind.IMPLEMENTATION, - typeMapper); + final ClassDescriptor classDescriptor = bindingContext.get(BindingContext.CLASS, objectDeclaration); + assert classDescriptor != null; + + final CalculatedClosure closure = getInjector().getClosureAnnotator().getCalculatedClosure(classDescriptor); + + final CodegenContext objectContext = expressionCodegen.context.intoAnonymousClass(classDescriptor, expressionCodegen); new ImplementationBodyCodegen(objectDeclaration, objectContext, nameAndVisitor.getSecond(), this).generate(); - ConstructorDescriptor constructorDescriptor = bindingContext.get(BindingContext.CONSTRUCTOR, objectDeclaration); - assert constructorDescriptor != null; - CallableMethod callableMethod = typeMapper.mapToCallableMethod( - constructorDescriptor, - typeMapper.hasThis0(constructorDescriptor.getContainingDeclaration())); - return new GeneratedAnonymousClassDescriptor(nameAndVisitor.first, callableMethod.getSignature().getAsmMethod(), - objectContext.outerWasUsed, null); + return closure; } public String createText() { diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java index 3fe4135ef91..be1d99a86da 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java @@ -26,6 +26,9 @@ import org.jetbrains.asm4.MethodVisitor; import org.jetbrains.asm4.Type; import org.jetbrains.asm4.commons.InstructionAdapter; import org.jetbrains.asm4.commons.Method; +import org.jetbrains.jet.codegen.context.CalculatedClosure; +import org.jetbrains.jet.codegen.context.CodegenContext; +import org.jetbrains.jet.codegen.context.MutableClosure; import org.jetbrains.jet.codegen.signature.*; import org.jetbrains.jet.codegen.signature.kotlin.JetMethodAnnotationWriter; import org.jetbrains.jet.codegen.signature.kotlin.JetValueParameterAnnotationWriter; @@ -34,6 +37,7 @@ import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.BindingContextUtils; import org.jetbrains.jet.lang.resolve.OverridingUtil; +import org.jetbrains.jet.lang.resolve.calls.ResolvedCall; import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant; import org.jetbrains.jet.lang.resolve.java.JdkNames; import org.jetbrains.jet.lang.resolve.java.JvmAbi; @@ -294,9 +298,9 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { JetType superType = bindingContext.get(BindingContext.TYPE, specifier.getTypeReference()); assert superType != null; ClassDescriptor superClassDescriptor = (ClassDescriptor) superType.getConstructor().getDeclarationDescriptor(); + assert superClassDescriptor != null; if (!CodegenUtil.isInterface(superClassDescriptor)) { superClassType = superType; - assert superClassDescriptor != null; superClass = typeMapper.mapType(superClassDescriptor.getDefaultType(), MapTypeMode.IMPL).getInternalName(); superCall = specifier; } @@ -338,6 +342,8 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { generateAccessors(); generateEnumMethods(); + + CodegenUtil.generateClosureFields(context.closure, v, state.getInjector().getJetTypeMapper()); } private void generateEnumMethods() { @@ -373,10 +379,8 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { } private void generateAccessors() { - if (context.accessors != null) { - for (Map.Entry entry : context.accessors.entrySet()) { - genAccessor(entry); - } + for (Map.Entry entry : context.getAccessors().entrySet()) { + genAccessor(entry); } } @@ -551,73 +555,15 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { ConstructorDescriptor constructorDescriptor = bindingContext.get(BindingContext.CONSTRUCTOR, myClass); - CodegenContexts.ConstructorContext constructorContext = context.intoConstructor(constructorDescriptor, typeMapper); + final CodegenContext.ConstructorContext constructorContext = context.intoConstructor(constructorDescriptor); - JvmMethodSignature constructorMethod; - CallableMethod callableMethod; - boolean hasThis0 = typeMapper.hasThis0(descriptor); - if (constructorDescriptor == null) { - BothSignatureWriter signatureWriter = new BothSignatureWriter(BothSignatureWriter.Mode.METHOD, false); + lookupConstructorExpressionsInClosureIfPresent(constructorContext); - signatureWriter.writeFormalTypeParametersStart(); - signatureWriter.writeFormalTypeParametersEnd(); + MutableClosure closure = context.closure; + boolean hasThis0 = closure != null && closure.getCaptureThis() != null; - signatureWriter.writeParametersStart(); - - if (hasThis0) { - signatureWriter.writeParameterType(JvmMethodParameterKind.THIS0); - typeMapper - .mapType(typeMapper.getClosureAnnotator().getEclosingClassDescriptor(descriptor).getDefaultType(), signatureWriter, - MapTypeMode.VALUE); - signatureWriter.writeParameterTypeEnd(); - } - - signatureWriter.writeParametersEnd(); - - signatureWriter.writeVoidReturn(); - - constructorMethod = signatureWriter.makeJvmMethodSignature(""); - callableMethod = - new CallableMethod(JvmClassName.byInternalName("Ignored"), null, null, constructorMethod, INVOKESPECIAL, null, null, - null); - } - else { - callableMethod = typeMapper.mapToCallableMethod(constructorDescriptor, - typeMapper.hasThis0(constructorDescriptor.getContainingDeclaration())); - constructorMethod = callableMethod.getSignature(); - } - - lookupDelegateExpressionInClosureIfPresent(); - - ObjectOrClosureCodegen closure = context.closure; - int firstSuperArgument = -1; - final List consArgTypes = - new LinkedList(constructorMethod.getKotlinParameterTypes()); - - int insert = addClosureToConstructorParameters(hasThis0, closure, consArgTypes); - - if (myClass instanceof JetObjectDeclaration && ((JetObjectDeclaration) myClass).isObjectLiteral()) { - if (superCall instanceof JetDelegatorToSuperCall) { - if (closure != null) { - closure.superCall = (JetDelegatorToSuperCall) superCall; - } - DeclarationDescriptor declarationDescriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, - ((JetDelegatorToSuperCall) superCall).getCalleeExpression() - .getConstructorReferenceExpression()); - if (declarationDescriptor instanceof ClassDescriptorFromSource) { - declarationDescriptor = ((ClassDescriptorFromSource) declarationDescriptor).getUnsubstitutedPrimaryConstructor(); - } - ConstructorDescriptor superConstructor = (ConstructorDescriptor) declarationDescriptor; - CallableMethod superCallable = typeMapper.mapToCallableMethod(superConstructor, typeMapper - .hasThis0(superConstructor.getContainingDeclaration())); - firstSuperArgument = insert; - for (Type t : superCallable.getSignature().getAsmMethod().getArgumentTypes()) { - consArgTypes.add(insert++, new JvmMethodParameterSignature(t, "", JvmMethodParameterKind.SHARED_VAR)); - } - } - - constructorMethod = JvmMethodSignature.simple("", Type.VOID_TYPE, consArgTypes); - } + final CallableMethod callableMethod = typeMapper.mapToCallableMethod(constructorDescriptor, context.closure); + final JvmMethodSignature constructorMethod = callableMethod.getSignature(); assert constructorDescriptor != null; int flags = JetTypeMapper.getAccessModifiers(constructorDescriptor, 0); @@ -643,18 +589,16 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { return; } - generatePrimiryConstructorImpl(constructorDescriptor, constructorContext, constructorMethod, callableMethod, hasThis0, closure, - firstSuperArgument, mv); + generatePrimiryConstructorImpl(constructorDescriptor, constructorContext, constructorMethod, callableMethod, hasThis0, closure, mv); } private void generatePrimiryConstructorImpl( ConstructorDescriptor constructorDescriptor, - CodegenContexts.ConstructorContext constructorContext, + CodegenContext.ConstructorContext constructorContext, JvmMethodSignature constructorMethod, CallableMethod callableMethod, boolean hasThis0, - ObjectOrClosureCodegen closure, - int firstSuperArgument, + MutableClosure closure, MethodVisitor mv ) { mv.visitCode(); @@ -663,7 +607,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { ? constructorDescriptor.getValueParameters() : Collections.emptyList(); - ConstructorFrameMap frameMap = new ConstructorFrameMap(callableMethod, constructorDescriptor, hasThis0); + ConstructorFrameMap frameMap = new ConstructorFrameMap(callableMethod, constructorDescriptor); final InstructionAdapter iv = new InstructionAdapter(mv); ExpressionCodegen codegen = new ExpressionCodegen(mv, frameMap, Type.VOID_TYPE, constructorContext, state); @@ -678,38 +622,31 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { genSuperCallToDelegatorToSuperClass(iv); } else { - ConstructorDescriptor constructorDescriptor1 = (ConstructorDescriptor) bindingContext.get(BindingContext.REFERENCE_TARGET, - ((JetDelegatorToSuperCall) superCall) - .getCalleeExpression() - .getConstructorReferenceExpression()); - generateDelegatorToConstructorCall(iv, codegen, (JetDelegatorToSuperCall) superCall, constructorDescriptor1, frameMap, - firstSuperArgument); + generateDelegatorToConstructorCall(iv, codegen, constructorDescriptor, frameMap); } - final ClassDescriptor outerDescriptor = typeMapper.getClosureAnnotator().getEclosingClassDescriptor(descriptor); - final boolean hasOuterThis = typeMapper.hasThis0(descriptor) && outerDescriptor != null; - if (hasOuterThis) { - final Type type = typeMapper.mapType(outerDescriptor.getDefaultType(), MapTypeMode.VALUE); + if (hasThis0) { + final Type type = typeMapper + .mapType(typeMapper.getClosureAnnotator().getEclosingClassDescriptor(descriptor).getDefaultType(), MapTypeMode.VALUE); String interfaceDesc = type.getDescriptor(); - final String fieldName = "this$0"; - v.newField(myClass, ACC_FINAL, fieldName, interfaceDesc, null, null); iv.load(0, classType); iv.load(frameMap.getOuterThisIndex(), type); - iv.putfield(classname.getInternalName(), fieldName, interfaceDesc); + iv.putfield(classname.getInternalName(), CodegenUtil.THIS$0, interfaceDesc); } if (closure != null) { - int k = hasOuterThis ? 2 : 1; - if (closure.captureReceiver != null) { + int k = hasThis0 ? 2 : 1; + final String internalName = typeMapper.mapType(descriptor.getDefaultType(), MapTypeMode.VALUE).getInternalName(); + final ClassifierDescriptor captureReceiver = closure.getCaptureReceiver(); + if (captureReceiver != null) { iv.load(0, JetTypeMapper.OBJECT_TYPE); - final Type asmType = typeMapper.mapType(closure.captureReceiver.getDefaultType(), MapTypeMode.IMPL); + final Type asmType = typeMapper.mapType(captureReceiver.getDefaultType(), MapTypeMode.IMPL); iv.load(1, asmType); - iv.putfield(typeMapper.mapType(descriptor.getDefaultType(), MapTypeMode.VALUE).getInternalName(), "receiver$0", - asmType.getDescriptor()); + iv.putfield(internalName, CodegenUtil.RECEIVER$0, asmType.getDescriptor()); k += asmType.getSize(); } - for (DeclarationDescriptor varDescr : closure.closure.keySet()) { + for (DeclarationDescriptor varDescr : closure.getCaptureVariables().keySet()) { if (varDescr instanceof VariableDescriptor && !(varDescr instanceof PropertyDescriptor)) { Type sharedVarType = typeMapper.getSharedVarType(varDescr); if (sharedVarType == null) { @@ -718,7 +655,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { iv.load(0, JetTypeMapper.OBJECT_TYPE); iv.load(k, StackValue.refType(sharedVarType)); k += StackValue.refType(sharedVarType).getSize(); - iv.putfield(typeMapper.mapType(descriptor.getDefaultType(), MapTypeMode.VALUE).getInternalName(), + iv.putfield(internalName, "$" + varDescr.getName(), sharedVarType.getDescriptor()); } } @@ -847,37 +784,30 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { .getDefaultType(), MapTypeMode.IMPL) .getInternalName()), - state.getInjector().getJetTypeMapper()); + state); generateDelegates(superClass, delegateContext, field); } private int addClosureToConstructorParameters( - boolean hasThis0, - ObjectOrClosureCodegen closure, + MutableClosure closure, List consArgTypes ) { int insert = 0; if (closure != null) { - if (closure.captureThis != null) { - if (!hasThis0) { - consArgTypes.add(insert, - new JvmMethodParameterSignature(Type.getObjectType(context.getThisDescriptor().getName().getName()), - "", JvmMethodParameterKind.THIS0)); - } + if (closure.getCaptureThis() != null) { + consArgTypes.add(insert, + new JvmMethodParameterSignature(Type.getObjectType(context.getThisDescriptor().getName().getName()), + "", JvmMethodParameterKind.OUTER)); insert++; } - else { - if (hasThis0) { - insert++; - } - } - if (closure.captureReceiver != null) { - final Type asmType = typeMapper.mapType(closure.captureReceiver.getDefaultType(), MapTypeMode.IMPL); + final ClassifierDescriptor captureReceiver = closure.getCaptureReceiver(); + if (captureReceiver != null) { + final Type asmType = typeMapper.mapType(captureReceiver.getDefaultType(), MapTypeMode.IMPL); consArgTypes.add(insert++, new JvmMethodParameterSignature(asmType, "", JvmMethodParameterKind.RECEIVER)); } - for (DeclarationDescriptor descriptor : closure.closure.keySet()) { + for (DeclarationDescriptor descriptor : closure.getCaptureVariables().keySet()) { if (descriptor instanceof VariableDescriptor && !(descriptor instanceof PropertyDescriptor)) { final Type sharedVarType = typeMapper.getSharedVarType(descriptor); final Type type; @@ -891,30 +821,64 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { consArgTypes.add(insert++, new JvmMethodParameterSignature(type, "", JvmMethodParameterKind.SHARED_VAR)); } else if (descriptor instanceof FunctionDescriptor) { - assert closure.captureReceiver != null; + assert captureReceiver != null; } } } return insert; } - private void lookupDelegateExpressionInClosureIfPresent() { - if (context.closure != null) { - for (JetDelegationSpecifier specifier : myClass.getDelegationSpecifiers()) { - if (specifier != superCall && specifier instanceof JetDelegatorByExpressionSpecifier) { + private void lookupConstructorExpressionsInClosureIfPresent(final CodegenContext.ConstructorContext constructorContext) { + final JetVisitorVoid visitor = new JetVisitorVoid() { + @Override + public void visitJetElement(JetElement e) { + e.acceptChildren(this); + } + + @Override + public void visitSimpleNameExpression(JetSimpleNameExpression expr) { + final DeclarationDescriptor descriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, expr); + if (descriptor instanceof VariableDescriptor && !(descriptor instanceof PropertyDescriptor)) { + ConstructorDescriptor constructorDescriptor = (ConstructorDescriptor) constructorContext.getContextDescriptor(); + for (ValueParameterDescriptor parameterDescriptor : constructorDescriptor.getValueParameters()) { + //noinspection ConstantConditions + if (descriptor.equals(parameterDescriptor)) { + return; + } + } + constructorContext.lookupInContext(descriptor, null, state, true); + } + } + }; + + for (JetDeclaration declaration : myClass.getDeclarations()) { + if (declaration instanceof JetProperty) { + final JetProperty property = (JetProperty) declaration; + final JetExpression initializer = property.getInitializer(); + if (initializer != null) { + initializer.accept(visitor); + } + } + else if (declaration instanceof JetClassInitializer) { + final JetClassInitializer initializer = (JetClassInitializer) declaration; + initializer.accept(visitor); + } + } + + for (JetDelegationSpecifier specifier : myClass.getDelegationSpecifiers()) { + if (specifier != superCall) { + if (specifier instanceof JetDelegatorByExpressionSpecifier) { JetExpression delegateExpression = ((JetDelegatorByExpressionSpecifier) specifier).getDelegateExpression(); assert delegateExpression != null; - delegateExpression.accept(new JetVisitorVoid() { - @Override - public void visitJetElement(JetElement e) { - e.acceptChildren(this); - } - - @Override - public void visitSimpleNameExpression(JetSimpleNameExpression expr) { - context.closure.lookupInContext(bindingContext.get(BindingContext.REFERENCE_TARGET, expr), null); - } - }); + delegateExpression.accept(visitor); + } + } + else { + if (superCall instanceof JetDelegatorToSuperCall) { + final JetValueArgumentList argumentList = ((JetDelegatorToSuperCall) superCall).getValueArgumentList(); + if (argumentList != null) { + argumentList.accept(visitor); + } } } } @@ -1059,48 +1023,63 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { } private void generateDelegatorToConstructorCall( - InstructionAdapter iv, ExpressionCodegen codegen, JetCallElement constructorCall, + InstructionAdapter iv, ExpressionCodegen codegen, ConstructorDescriptor constructorDescriptor, - ConstructorFrameMap frameMap, int firstSuperArgument + ConstructorFrameMap frameMap ) { ClassDescriptor classDecl = constructorDescriptor.getContainingDeclaration(); iv.load(0, OBJECT_TYPE); + if (classDecl.getKind() == ClassKind.ENUM_CLASS || classDecl.getKind() == ClassKind.ENUM_ENTRY) { - iv.load(1, JetTypeMapper.OBJECT_TYPE); + iv.load(1, OBJECT_TYPE); iv.load(2, Type.INT_TYPE); } - if (classDecl.getContainingDeclaration() instanceof ClassDescriptor) { - iv.load(frameMap.getOuterThisIndex(), - typeMapper.mapType(((ClassDescriptor) descriptor.getContainingDeclaration()).getDefaultType(), MapTypeMode.IMPL)); - } + CallableMethod method = typeMapper.mapToCallableMethod(constructorDescriptor, context.closure); - CallableMethod method = typeMapper - .mapToCallableMethod(constructorDescriptor, typeMapper.hasThis0(constructorDescriptor.getContainingDeclaration())); + final ResolvedCall resolvedCall = + bindingContext.get(BindingContext.RESOLVED_CALL, ((JetCallElement) superCall).getCalleeExpression()); + assert resolvedCall != null; + final ConstructorDescriptor superConstructor = (ConstructorDescriptor) resolvedCall.getResultingDescriptor(); + + final CalculatedClosure closureForSuper = typeMapper.getCalculatedClosure(superConstructor.getContainingDeclaration()); + CallableMethod superCallable = typeMapper.mapToCallableMethod(superConstructor, + closureForSuper); + + if (closureForSuper != null && closureForSuper.getCaptureThis() != null) { + iv.load(frameMap.getOuterThisIndex(), OBJECT_TYPE); + } if (myClass instanceof JetObjectDeclaration && superCall instanceof JetDelegatorToSuperCall && ((JetObjectDeclaration) myClass).isObjectLiteral()) { - ConstructorDescriptor superConstructor = (ConstructorDescriptor) bindingContext.get(BindingContext.REFERENCE_TARGET, - ((JetDelegatorToSuperCall) superCall) - .getCalleeExpression() - .getConstructorReferenceExpression()); - assert superConstructor != null; - CallableMethod superCallable = typeMapper.mapToCallableMethod(superConstructor, - typeMapper.hasThis0(superConstructor.getContainingDeclaration())); - int nextVar = firstSuperArgument + 1; + int nextVar = findFirstSuperArgument(method); for (Type t : superCallable.getSignature().getAsmMethod().getArgumentTypes()) { iv.load(nextVar, t); nextVar += t.getSize(); } - method.invoke(codegen.v); + superCallable.invoke(codegen.v); } else { - codegen.invokeMethodWithArguments(method, constructorCall, StackValue.none()); + codegen.invokeMethodWithArguments(superCallable, (JetCallElement) superCall, StackValue.none()); } } + private static int findFirstSuperArgument(CallableMethod method) { + final List types = method.getSignature().getKotlinParameterTypes(); + if (types != null) { + int i = 0; + for (JvmMethodParameterSignature type : types) { + if (type.getKind() == JvmMethodParameterKind.SUPER_CALL_PARAM) { + return i + 1; // because of this + } + i += type.getAsmType().getSize(); + } + } + return -1; + } + @Override protected void generateDeclaration(PropertyCodegen propertyCodegen, JetDeclaration declaration, FunctionCodegen functionCodegen) { if (declaration instanceof JetClassObject) { @@ -1171,7 +1150,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { .get(BindingContext.REFERENCE_TARGET, superCall.getCalleeExpression().getConstructorReferenceExpression()); assert constructorDescriptor != null; CallableMethod method = typeMapper.mapToCallableMethod(constructorDescriptor, typeMapper - .hasThis0(constructorDescriptor.getContainingDeclaration())); + .getCalculatedClosure(constructorDescriptor.getContainingDeclaration())); codegen.invokeMethodWithArguments(method, superCall, StackValue.none()); } else { @@ -1206,7 +1185,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { Type type = typeMapper.mapType(jetType, MapTypeMode.VALUE); if (skipDefaultValue(propertyDescriptor, value, type)) continue; } - iv.load(0, JetTypeMapper.OBJECT_TYPE); + iv.load(0, OBJECT_TYPE); Type type = codegen.expressionType(initializer); if (jetType.isNullable()) { type = JetTypeMapper.boxType(type); diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java b/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java index b8877da9fe9..75af01daf32 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java @@ -21,12 +21,13 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.asm4.Opcodes; import org.jetbrains.asm4.Type; -import org.jetbrains.jet.codegen.signature.BothSignatureWriter; -import org.jetbrains.jet.codegen.signature.JvmMethodParameterKind; -import org.jetbrains.jet.codegen.signature.JvmMethodSignature; -import org.jetbrains.jet.codegen.signature.JvmPropertyAccessorSignature; +import org.jetbrains.jet.codegen.context.CalculatedClosure; +import org.jetbrains.jet.codegen.context.ClosureAnnotator; +import org.jetbrains.jet.codegen.context.EnclosedValueDescriptor; +import org.jetbrains.jet.codegen.signature.*; import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.psi.JetClassObject; +import org.jetbrains.jet.lang.psi.JetDelegatorToSuperCall; import org.jetbrains.jet.lang.psi.JetElement; import org.jetbrains.jet.lang.psi.JetObjectDeclaration; import org.jetbrains.jet.lang.resolve.BindingContext; @@ -40,10 +41,7 @@ import org.jetbrains.jet.lang.types.lang.JetStandardClasses; import org.jetbrains.jet.lang.types.lang.JetStandardLibrary; import javax.inject.Inject; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Iterator; -import java.util.List; +import java.util.*; import static org.jetbrains.asm4.Opcodes.*; @@ -103,7 +101,12 @@ public class JetTypeMapper { } public boolean hasThis0(ClassDescriptor classDescriptor) { - return closureAnnotator.hasThis0(classDescriptor); + final CalculatedClosure closure = closureAnnotator.getCalculatedClosure(classDescriptor); + return closure != null && closure.getCaptureThis() != null; + } + + public CalculatedClosure getCalculatedClosure(ClassDescriptor classDescriptor) { + return closureAnnotator.getCalculatedClosure(classDescriptor); } public ClosureAnnotator getClosureAnnotator() { @@ -856,22 +859,27 @@ public class JetTypeMapper { jvmMethodSignature.getKotlinParameterType(jvmMethodSignature.getParameterCount() - 1)); } - private JvmMethodSignature mapConstructorSignature(ConstructorDescriptor descriptor, boolean hasThis0) { + private JvmMethodSignature mapConstructorSignature(ConstructorDescriptor descriptor, CalculatedClosure closure) { BothSignatureWriter signatureWriter = new BothSignatureWriter(BothSignatureWriter.Mode.METHOD, true); - List parameters = descriptor.getOriginal().getValueParameters(); - // constructor type parmeters are fake writeFormalTypeParameters(Collections.emptyList(), signatureWriter); signatureWriter.writeParametersStart(); ClassDescriptor containingDeclaration = descriptor.getContainingDeclaration(); - if (hasThis0) { - signatureWriter.writeParameterType(JvmMethodParameterKind.THIS0); - mapType(closureAnnotator.getEclosingClassDescriptor(containingDeclaration).getDefaultType(), signatureWriter, - MapTypeMode.VALUE); + final ClassDescriptor captureThis = closure != null ? closure.getCaptureThis() : null; + if (captureThis != null) { + signatureWriter.writeParameterType(JvmMethodParameterKind.OUTER); + mapType(captureThis.getDefaultType(), signatureWriter, MapTypeMode.VALUE); + signatureWriter.writeParameterTypeEnd(); + } + + final ClassifierDescriptor captureReceiver = closure != null ? closure.getCaptureReceiver() : null; + if (captureReceiver != null) { + signatureWriter.writeParameterType(JvmMethodParameterKind.RECEIVER); + mapType(captureReceiver.getDefaultType(), signatureWriter, MapTypeMode.VALUE); signatureWriter.writeParameterTypeEnd(); } @@ -884,7 +892,46 @@ public class JetTypeMapper { signatureWriter.writeParameterTypeEnd(); } - for (ValueParameterDescriptor parameter : parameters) { + if (closure != null) { + for (Map.Entry entry : closure.getCaptureVariables().entrySet()) { + if (entry.getKey() instanceof VariableDescriptor && !(entry.getKey() instanceof PropertyDescriptor)) { + Type sharedVarType = getSharedVarType(entry.getKey()); + if (sharedVarType == null) { + sharedVarType = mapType(((VariableDescriptor) entry.getKey()).getType(), MapTypeMode.VALUE); + } + signatureWriter.writeParameterType(JvmMethodParameterKind.SHARED_VAR); + signatureWriter.writeAsmType(sharedVarType, false); + signatureWriter.writeParameterTypeEnd(); + } + } + + final JetDelegatorToSuperCall superCall = closure.getSuperCall(); + if (superCall != null) { + DeclarationDescriptor superDescriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, + superCall + .getCalleeExpression() + .getConstructorReferenceExpression()); + + if(superDescriptor instanceof ConstructorDescriptor) { + final ConstructorDescriptor superConstructor = (ConstructorDescriptor) superDescriptor; + + if (CodegenUtil.isObjectLiteral(descriptor.getContainingDeclaration(), bindingContext)) { + CallableMethod superCallable = mapToCallableMethod(superConstructor, + getCalculatedClosure(superConstructor.getContainingDeclaration())); + final List types = superCallable.getSignature().getKotlinParameterTypes(); + if (types != null) { + for (JvmMethodParameterSignature type : types) { + signatureWriter.writeParameterType(JvmMethodParameterKind.SUPER_CALL_PARAM); + signatureWriter.writeAsmType(type.getAsmType(), false); + signatureWriter.writeParameterTypeEnd(); + } + } + } + } + } + } + + for (ValueParameterDescriptor parameter : descriptor.getOriginal().getValueParameters()) { signatureWriter.writeParameterType(JvmMethodParameterKind.VALUE); mapType(parameter.getType(), signatureWriter, MapTypeMode.VALUE); signatureWriter.writeParameterTypeEnd(); @@ -925,8 +972,8 @@ public class JetTypeMapper { return signatureWriter.makeJvmMethodSignature(""); } - public CallableMethod mapToCallableMethod(ConstructorDescriptor descriptor, boolean hasThis0) { - final JvmMethodSignature method = mapConstructorSignature(descriptor, hasThis0); + public CallableMethod mapToCallableMethod(ConstructorDescriptor descriptor, CalculatedClosure closure) { + final JvmMethodSignature method = mapConstructorSignature(descriptor, closure); JetType defaultType = descriptor.getContainingDeclaration().getDefaultType(); Type mapped = mapType(defaultType, MapTypeMode.IMPL); if (mapped.getSort() != Type.OBJECT) { @@ -999,4 +1046,23 @@ public class JetTypeMapper { return Boolean.TRUE.equals(bindingContext.get(BindingContext.CAPTURED_IN_CLOSURE, variableDescriptor)) && variableDescriptor.isVar(); } + + protected JvmMethodSignature invokeSignature(FunctionDescriptor fd) { + return mapSignature(Name.identifier("invoke"), fd); + } + + public CallableMethod asCallableMethod(FunctionDescriptor fd) { + JvmMethodSignature descriptor = CodegenUtil.erasedInvokeSignature(fd); + JvmClassName owner = CodegenUtil.getInternalClassName(fd); + Type receiverParameterType; + if (fd.getReceiverParameter().exists()) { + receiverParameterType = mapType(fd.getOriginal().getReceiverParameter().getType(), MapTypeMode.VALUE); + } + else { + receiverParameterType = null; + } + return new CallableMethod( + owner, null, null, descriptor, INVOKEVIRTUAL, + CodegenUtil.getInternalClassName(fd), receiverParameterType, CodegenUtil.getInternalClassName(fd).getAsmType()); + } } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/LocalClassClosureCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/LocalClassClosureCodegen.java deleted file mode 100644 index 7714898ac70..00000000000 --- a/compiler/backend/src/org/jetbrains/jet/codegen/LocalClassClosureCodegen.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2010-2012 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jetbrains.jet.codegen; - -import org.jetbrains.annotations.NotNull; -import org.jetbrains.jet.lang.descriptors.ClassDescriptor; - -/** - * @author alex.tkachman - */ -public class LocalClassClosureCodegen extends ObjectOrClosureCodegen { - public LocalClassClosureCodegen( - ExpressionCodegen exprContext, - CodegenContext context, - @NotNull GenerationState state, - ClassDescriptor descriptor - ) { - super(exprContext, context, state); - state.getInjector().getClosureAnnotator().recordLocalClass(descriptor, this); - } -} diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/MemberCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/MemberCodegen.java index 30faa2bcbf3..0ab1b72688b 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/MemberCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/MemberCodegen.java @@ -17,6 +17,7 @@ package org.jetbrains.jet.codegen; import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.codegen.context.CodegenContext; import org.jetbrains.jet.lang.psi.JetNamedFunction; import org.jetbrains.jet.lang.psi.JetProperty; import org.jetbrains.jet.lang.psi.JetTypeParameterListOwner; diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/NamespaceCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/NamespaceCodegen.java index 94bcd644beb..350dfbb5c3f 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/NamespaceCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/NamespaceCodegen.java @@ -24,6 +24,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.asm4.MethodVisitor; import org.jetbrains.asm4.Type; import org.jetbrains.asm4.commons.InstructionAdapter; +import org.jetbrains.jet.codegen.context.CodegenContext; import org.jetbrains.jet.lang.descriptors.NamespaceDescriptor; import org.jetbrains.jet.lang.descriptors.PropertyDescriptor; import org.jetbrains.jet.lang.diagnostics.DiagnosticUtils; @@ -122,19 +123,19 @@ public class NamespaceCodegen { NamespaceDescriptor descriptor = state.getBindingContext().get(BindingContext.FILE_TO_NAMESPACE, file); for (JetDeclaration declaration : file.getDeclarations()) { if (declaration instanceof JetProperty) { - final CodegenContext context = CodegenContexts.STATIC.intoNamespace(descriptor, state.getInjector().getJetTypeMapper()); + final CodegenContext context = CodegenContext.STATIC.intoNamespace(descriptor); state.getInjector().getMemberCodegen().generateFunctionOrProperty( (JetTypeParameterListOwner) declaration, context, v.getClassBuilder()); } else if (declaration instanceof JetNamedFunction) { if (!multiFile) { - final CodegenContext context = CodegenContexts.STATIC.intoNamespace(descriptor, state.getInjector().getJetTypeMapper()); + final CodegenContext context = CodegenContext.STATIC.intoNamespace(descriptor); state.getInjector().getMemberCodegen().generateFunctionOrProperty( (JetTypeParameterListOwner) declaration, context, v.getClassBuilder()); } } else if (declaration instanceof JetClassOrObject) { - final CodegenContext context = CodegenContexts.STATIC.intoNamespace(descriptor, state.getInjector().getJetTypeMapper()); + final CodegenContext context = CodegenContext.STATIC.intoNamespace(descriptor); state.getInjector().getClassCodegen().generate(context, (JetClassOrObject) declaration); } else if (declaration instanceof JetScript) { @@ -170,13 +171,13 @@ public class NamespaceCodegen { if (declaration instanceof JetNamedFunction) { { final CodegenContext context = - CodegenContexts.STATIC.intoNamespace(descriptor, state.getInjector().getJetTypeMapper()); + CodegenContext.STATIC.intoNamespace(descriptor); state.getInjector().getMemberCodegen() .generateFunctionOrProperty((JetTypeParameterListOwner) declaration, context, builder); } { final CodegenContext context = - CodegenContexts.STATIC.intoNamespacePart(className, descriptor, state.getInjector().getJetTypeMapper()); + CodegenContext.STATIC.intoNamespacePart(className, descriptor); state.getInjector().getMemberCodegen() .generateFunctionOrProperty((JetTypeParameterListOwner) declaration, context, v.getClassBuilder()); } @@ -232,7 +233,7 @@ public class NamespaceCodegen { mv.visitCode(); FrameMap frameMap = new FrameMap(); - ExpressionCodegen codegen = new ExpressionCodegen(mv, frameMap, Type.VOID_TYPE, CodegenContexts.STATIC, state); + ExpressionCodegen codegen = new ExpressionCodegen(mv, frameMap, Type.VOID_TYPE, CodegenContext.STATIC, state); for (JetFile file : files) { for (JetDeclaration declaration : file.getDeclarations()) { diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ObjectOrClosureCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ObjectOrClosureCodegen.java deleted file mode 100644 index 8169b742652..00000000000 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ObjectOrClosureCodegen.java +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright 2010-2012 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jetbrains.jet.codegen; - -import org.jetbrains.annotations.Nullable; -import org.jetbrains.asm4.Opcodes; -import org.jetbrains.asm4.Type; -import org.jetbrains.jet.lang.descriptors.*; -import org.jetbrains.jet.lang.psi.JetDelegatorToSuperCall; -import org.jetbrains.jet.lang.psi.JetElement; -import org.jetbrains.jet.lang.resolve.BindingContextUtils; -import org.jetbrains.jet.lang.resolve.java.JvmClassName; - -import java.util.LinkedHashMap; -import java.util.Map; - -/** - * @author alex.tkachman - */ -public class ObjectOrClosureCodegen { - protected ClassDescriptor captureThis; - protected ClassifierDescriptor captureReceiver; - - public final GenerationState state; - private final ExpressionCodegen exprContext; - protected final CodegenContext context; - protected ClassBuilder cv = null; - public JvmClassName name = null; - protected final Map closure = - new LinkedHashMap(); - public JetDelegatorToSuperCall superCall; - - public ObjectOrClosureCodegen(ExpressionCodegen exprContext, CodegenContext context, GenerationState state) { - this.exprContext = exprContext; - this.context = context; - this.state = state; - } - - public StackValue lookupInContext(DeclarationDescriptor d, @Nullable StackValue result) { - EnclosedValueDescriptor answer = closure.get(d); - if (answer != null) { - StackValue innerValue = answer.getInnerValue(); - return result != null ? innerValue : StackValue.composed(result, innerValue); - } - - if (d instanceof VariableDescriptor && !(d instanceof PropertyDescriptor)) { - VariableDescriptor vd = (VariableDescriptor) d; - - final int idx = exprContext.lookupLocal(vd); - if (idx < 0) return null; - - final Type sharedVarType = state.getInjector().getJetTypeMapper().getSharedVarType(vd); - Type localType = state.getInjector().getJetTypeMapper().mapType(vd.getType(), MapTypeMode.VALUE); - final Type type = sharedVarType != null ? sharedVarType : localType; - - StackValue outerValue = StackValue.local(idx, type); - final String fieldName = "$" + vd.getName(); - StackValue innerValue = sharedVarType != null - ? StackValue.fieldForSharedVar(localType, name, fieldName) - : StackValue.field(type, name, fieldName, false); - - cv.newField(null, Opcodes.ACC_PUBLIC, fieldName, type.getDescriptor(), null, null); - - answer = new EnclosedValueDescriptor(d, innerValue, outerValue); - closure.put(d, answer); - - return innerValue; - } - - if (CodegenUtil.isNamedFun(d, state.getBindingContext()) && d.getContainingDeclaration() instanceof FunctionDescriptor) { - FunctionDescriptor vd = (FunctionDescriptor) d; - - final int idx = exprContext.lookupLocal(vd); - if (idx < 0) return null; - - JetElement expression = (JetElement) BindingContextUtils.callableDescriptorToDeclaration(state.getBindingContext(), vd); - JvmClassName cn = state.getInjector().getJetTypeMapper().getClosureAnnotator().classNameForAnonymousClass(expression); - Type localType = cn.getAsmType(); - - StackValue outerValue = StackValue.local(idx, localType); - final String fieldName = "$" + vd.getName(); - StackValue innerValue = StackValue.field(localType, name, fieldName, false); - - cv.newField(null, Opcodes.ACC_PUBLIC, fieldName, localType.getDescriptor(), null, null); - - answer = new EnclosedValueDescriptor(d, innerValue, outerValue); - closure.put(d, answer); - - return innerValue; - } - - if (d instanceof FunctionDescriptor) { - // we are looking for receiver - FunctionDescriptor fd = (FunctionDescriptor) d; - - // we generate method - assert context instanceof CodegenContexts.ReceiverContext; - - CodegenContexts.ReceiverContext fcontext = (CodegenContexts.ReceiverContext) context; - - if (fcontext.getReceiverDescriptor() != fd) { - return null; - } - - Type type = state.getInjector().getJetTypeMapper() - .mapType(fcontext.getReceiverDescriptor().getReceiverParameter().getType(), MapTypeMode.VALUE); - boolean isStatic = fcontext.getContextDescriptor().getContainingDeclaration() instanceof NamespaceDescriptor; - StackValue outerValue = StackValue.local(isStatic ? 0 : 1, type); - final String fieldName = "receiver$0"; - StackValue innerValue = StackValue.field(type, name, fieldName, false); - - cv.newField(null, Opcodes.ACC_PUBLIC, fieldName, type.getDescriptor(), null, null); - - answer = new EnclosedValueDescriptor(d, innerValue, outerValue); - closure.put(d, answer); - - assert captureReceiver == null; - captureReceiver = - fcontext.getReceiverDescriptor().getReceiverParameter().getType().getConstructor().getDeclarationDescriptor(); - - return innerValue; - } - - return null; - } - - public boolean isConst() { - return captureThis == null && captureReceiver == null && closure.isEmpty(); - } -} diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/PropertyCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/PropertyCodegen.java index 8698aa4a1ee..d3d5a787904 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/PropertyCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/PropertyCodegen.java @@ -24,6 +24,7 @@ import org.jetbrains.asm4.MethodVisitor; import org.jetbrains.asm4.Opcodes; import org.jetbrains.asm4.Type; import org.jetbrains.asm4.commons.InstructionAdapter; +import org.jetbrains.jet.codegen.context.CodegenContext; import org.jetbrains.jet.codegen.signature.JvmPropertyAccessorSignature; import org.jetbrains.jet.codegen.signature.kotlin.JetMethodAnnotationWriter; import org.jetbrains.jet.lang.descriptors.*; diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ScriptCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ScriptCodegen.java index 5bc78204c00..2fa41e3e8f9 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ScriptCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ScriptCodegen.java @@ -23,6 +23,8 @@ import org.jetbrains.asm4.MethodVisitor; import org.jetbrains.asm4.Opcodes; import org.jetbrains.asm4.Type; import org.jetbrains.asm4.commons.InstructionAdapter; +import org.jetbrains.jet.codegen.context.ClosureAnnotator; +import org.jetbrains.jet.codegen.context.CodegenContext; import org.jetbrains.jet.codegen.signature.JvmMethodSignature; import org.jetbrains.jet.lang.descriptors.ClassDescriptor; import org.jetbrains.jet.lang.descriptors.ScriptDescriptor; @@ -99,9 +101,9 @@ public class ScriptCodegen { assert scriptDescriptor != null; ClassDescriptor classDescriptorForScript = closureAnnotator.classDescriptorForScriptDescriptor(scriptDescriptor); - CodegenContexts.ScriptContext context = - (CodegenContexts.ScriptContext) CodegenContexts.STATIC - .intoScript(scriptDescriptor, classDescriptorForScript, state.getInjector().getJetTypeMapper()); + CodegenContext.ScriptContext context = + (CodegenContext.ScriptContext) CodegenContext.STATIC + .intoScript(scriptDescriptor, classDescriptorForScript); JvmClassName className = closureAnnotator.classNameForClassDescriptor(classDescriptorForScript); @@ -117,7 +119,7 @@ public class ScriptCodegen { genMembers(scriptDeclaration, context, classBuilder); genFieldsForParameters(scriptDescriptor, classBuilder); genConstructor(scriptDeclaration, scriptDescriptor, classDescriptorForScript, classBuilder, - context.intoFunction(scriptDescriptor.getScriptCodeDescriptor(), state.getInjector().getJetTypeMapper()), + context.intoFunction(scriptDescriptor.getScriptCodeDescriptor()), earlierScripts); classBuilder.done(); diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/TraitImplBodyCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/TraitImplBodyCodegen.java index 86530e482db..0b72feb81d8 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/TraitImplBodyCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/TraitImplBodyCodegen.java @@ -17,6 +17,7 @@ package org.jetbrains.jet.codegen; import org.jetbrains.asm4.Opcodes; +import org.jetbrains.jet.codegen.context.CodegenContext; import org.jetbrains.jet.lang.descriptors.ClassDescriptor; import org.jetbrains.jet.lang.descriptors.ClassKind; import org.jetbrains.jet.lang.psi.JetClassOrObject; diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/context/CalculatedClosure.java b/compiler/backend/src/org/jetbrains/jet/codegen/context/CalculatedClosure.java new file mode 100644 index 00000000000..a6e14d7bc48 --- /dev/null +++ b/compiler/backend/src/org/jetbrains/jet/codegen/context/CalculatedClosure.java @@ -0,0 +1,57 @@ +/* + * Copyright 2010-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.jet.codegen.context; + +import com.intellij.openapi.util.Pair; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.asm4.Type; +import org.jetbrains.jet.lang.descriptors.ClassDescriptor; +import org.jetbrains.jet.lang.descriptors.ClassifierDescriptor; +import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; +import org.jetbrains.jet.lang.psi.JetDelegatorToSuperCall; +import org.jetbrains.jet.lang.resolve.java.JvmClassName; + +import java.util.List; +import java.util.Map; + +/** + * @author alex.tkachman + */ +public interface CalculatedClosure { + + @Nullable + ClassDescriptor getEnclosingClass(); + + @NotNull + JvmClassName getClassName(); + + @Nullable + JetDelegatorToSuperCall getSuperCall(); + + @Nullable + ClassDescriptor getCaptureThis(); + + @Nullable + ClassifierDescriptor getCaptureReceiver(); + + @NotNull + Map getCaptureVariables(); + + @NotNull + List> getRecordedFields(); +} diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ClosureAnnotator.java b/compiler/backend/src/org/jetbrains/jet/codegen/context/ClosureAnnotator.java similarity index 73% rename from compiler/backend/src/org/jetbrains/jet/codegen/ClosureAnnotator.java rename to compiler/backend/src/org/jetbrains/jet/codegen/context/ClosureAnnotator.java index 8bd1ff9b0ce..d77de3feae2 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ClosureAnnotator.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/context/ClosureAnnotator.java @@ -14,14 +14,17 @@ * limitations under the License. */ -package org.jetbrains.jet.codegen; +package org.jetbrains.jet.codegen.context; import com.intellij.util.containers.MultiMap; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.codegen.CodegenUtil; import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; import org.jetbrains.jet.lang.psi.*; 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.JvmClassName; import org.jetbrains.jet.lang.resolve.name.FqName; @@ -36,15 +39,11 @@ import java.util.*; * @author alex.tkachman */ public class ClosureAnnotator { - private final Map classNamesForClassDescriptor = new HashMap(); - private final Map anonymousSubclassesCount = new HashMap(); + private final Map closuresForClassDescriptor = new HashMap(); private final Map classNameForScript = new HashMap(); - private final Map localClassCodegenForClass = - new HashMap(); private final Set scriptClassNames = new HashSet(); private final Map classesForFunctions = new HashMap(); - private final Map enclosing = new HashMap(); private final MultiMap namespaceName2MultiNamespaceFiles = MultiMap.create(); private final MultiMap namespaceName2Files = MultiMap.create(); @@ -76,7 +75,7 @@ public class ClosureAnnotator { int arity = funDescriptor.getValueParameters().size(); classDescriptor = new ClassDescriptorImpl( - funDescriptor, + funDescriptor.getContainingDeclaration(), Collections.emptyList(), Modality.FINAL, Name.special("")); @@ -107,7 +106,6 @@ public class ClosureAnnotator { Collections.emptyList(), Modality.FINAL, Name.special("")); - recordName(classDescriptor, className); classDescriptor.initialize( false, Collections.emptyList(), @@ -116,6 +114,8 @@ public class ClosureAnnotator { Collections.emptySet(), null); + recordClosure(null, classDescriptor, null, className, false); + ClassDescriptorImpl oldDescriptor = classesForFunctions.put(scriptDescriptor, classDescriptor); if (oldDescriptor != null) { throw new IllegalStateException("Rewrite at key " + scriptDescriptor + " for class"); @@ -150,7 +150,8 @@ public class ClosureAnnotator { @NotNull public JvmClassName classNameForScriptDescriptor(@NotNull ScriptDescriptor scriptDescriptor) { - return classNameForClassDescriptor(classDescriptorForScriptDescriptor(scriptDescriptor)); + final ClassDescriptor classDescriptor = classDescriptorForScriptDescriptor(scriptDescriptor); + return closuresForClassDescriptor.get(classDescriptor).getClassName(); } private void mapFilesToNamespaces(Collection files) { @@ -213,65 +214,90 @@ public class ClosureAnnotator { return classNameForClassDescriptor(descriptor); } - public ClassDescriptor getEclosingClassDescriptor(ClassDescriptor descriptor) { - return enclosing.get(descriptor); + public JvmClassName classNameForClassDescriptor(ClassDescriptor descriptor) { + final CalculatedClosure closure = closuresForClassDescriptor.get(descriptor); + return closure == null ? null : closure.getClassName(); } - public boolean hasThis0(ClassDescriptor classDescriptor) { - if (classDescriptor.getKind() == ClassKind.ENUM_CLASS - || classDescriptor.getKind() == ClassKind.ENUM_ENTRY - || classDescriptor.getKind() == ClassKind.CLASS_OBJECT) { + public ClassDescriptor getEclosingClassDescriptor(ClassDescriptor descriptor) { + final CalculatedClosure closure = closuresForClassDescriptor.get(descriptor); + return closure == null ? null : closure.getEnclosingClass(); + } + + public boolean canHaveOuter(ClassDescriptor classDescriptor) { + if (DescriptorUtils.isClassObject(classDescriptor)) { + return false; + } + if (classDescriptor.getKind() == ClassKind.ENUM_CLASS || classDescriptor.getKind() == ClassKind.ENUM_ENTRY) { return false; } - ClassDescriptor other = enclosing.get(classDescriptor); - return other != null; + return getEclosingClassDescriptor(classDescriptor) != null; } public boolean enumEntryNeedSubclass(JetEnumEntry enumEntry) { - ClassDescriptor descriptor = bindingContext.get(BindingContext.CLASS, enumEntry); - return enumEntryNeedSubclass.get(descriptor); + return Boolean.TRUE.equals(enumEntryNeedSubclass.get(bindingContext.get(BindingContext.CLASS, enumEntry))); } public boolean enumEntryNeedSubclass(ClassDescriptor enumEntry) { - Boolean aBoolean = enumEntryNeedSubclass.get(enumEntry); - return aBoolean != null && aBoolean; + return Boolean.TRUE.equals(enumEntryNeedSubclass.get(enumEntry)); } - public void recordLocalClass(ClassDescriptor descriptor, LocalClassClosureCodegen codegen) { - LocalClassClosureCodegen put = localClassCodegenForClass.put(descriptor, codegen); - assert put == null; + public CalculatedClosure getCalculatedClosure(@NotNull ClassDescriptor descriptor) { + //noinspection SuspiciousMethodCalls + return closuresForClassDescriptor.get(descriptor.getOriginal()); } - private class MyJetVisitorVoid extends JetVisitorVoid { - private final LinkedList classStack = new LinkedList(); - private final LinkedList nameStack = new LinkedList(); + private void recordClosure( + @Nullable JetElement element, + ClassDescriptor classDescriptor, + @Nullable ClassDescriptor enclosing, + JvmClassName name, + boolean functionLiteral + ) { + final JetDelegatorToSuperCall superCall = CodegenUtil.findSuperCall(element, bindingContext); - private void recordEnclosing(ClassDescriptor classDescriptor) { - if (classStack.size() > 0) { - ClassDescriptor put = enclosing.put(classDescriptor, classStack.peek()); - assert put == null; + CallableDescriptor enclosingReceiver = null; + if (classDescriptor.getContainingDeclaration() instanceof CallableDescriptor) { + enclosingReceiver = (CallableDescriptor) classDescriptor.getContainingDeclaration(); + enclosingReceiver = enclosingReceiver instanceof PropertyAccessorDescriptor + ? ((PropertyAccessorDescriptor) enclosingReceiver).getCorrespondingProperty() + : enclosingReceiver; + + if (!enclosingReceiver.getReceiverParameter().exists()) { + enclosingReceiver = null; } } - private JvmClassName recordAnonymousClass(JetElement declaration) { + final MutableClosure closure = new MutableClosure(superCall, enclosing, name, enclosingReceiver); + + final CalculatedClosure old = closuresForClassDescriptor.put(classDescriptor, closure); + assert old == null; + + // TODO: this is temporary before we have proper inner classes + if (canHaveOuter(classDescriptor) && !functionLiteral) { + closure.setCaptureThis(); + } + } + + private class MyJetVisitorVoid extends JetVisitorVoid { + private final Map anonymousSubclassesCount = new HashMap(); + + private final LinkedList classStack = new LinkedList(); + private final LinkedList nameStack = new LinkedList(); + + private String inventAnonymousClassName(JetElement declaration) { String top = nameStack.peek(); Integer cnt = anonymousSubclassesCount.get(top); if (cnt == null) { cnt = 0; } - JvmClassName name = JvmClassName.byInternalName(top + "$" + (cnt + 1)); + String name = top + "$" + (cnt + 1); ClassDescriptor descriptor = bindingContext.get(BindingContext.CLASS, declaration); if (descriptor == null) { - if (declaration instanceof JetFunctionLiteralExpression || declaration instanceof JetNamedFunction) { - DeclarationDescriptor declarationDescriptor = bindingContext.get(BindingContext.FUNCTION, declaration); - assert declarationDescriptor instanceof FunctionDescriptor; - descriptor = classDescriptorForFunctionDescriptor((FunctionDescriptor) declarationDescriptor); - } - else if (declaration instanceof JetObjectLiteralExpression) { - descriptor = - bindingContext.get(BindingContext.CLASS, ((JetObjectLiteralExpression) declaration).getObjectDeclaration()); - assert descriptor != null; + if (declaration instanceof JetFunctionLiteralExpression || + declaration instanceof JetNamedFunction || + declaration instanceof JetObjectLiteralExpression) { } else { throw new IllegalStateException( @@ -279,20 +305,11 @@ public class ClosureAnnotator { declaration.getClass().getName()); } } - recordName(descriptor, name); anonymousSubclassesCount.put(top, cnt + 1); return name; } - private JvmClassName recordClassObject(JetClassObject declaration) { - JvmClassName name = JvmClassName.byInternalName(nameStack.peek() + JvmAbi.CLASS_OBJECT_SUFFIX); - ClassDescriptor classDescriptor = bindingContext.get(BindingContext.CLASS, declaration.getObjectDeclaration()); - assert classDescriptor != null; - recordName(classDescriptor, name); - return name; - } - @Override public void visitJetElement(JetElement element) { super.visitJetElement(element); @@ -302,6 +319,8 @@ public class ClosureAnnotator { @Override public void visitJetFile(JetFile file) { if (file.isScript()) { + //noinspection ConstantConditions + classStack.push(classDescriptorForScriptDescriptor(bindingContext.get(BindingContext.SCRIPT, file.getScript()))); //noinspection ConstantConditions nameStack.push(classNameForScriptPsi(file.getScript()).getInternalName()); } @@ -310,21 +329,39 @@ public class ClosureAnnotator { } file.acceptChildren(this); nameStack.pop(); + if (file.isScript()) { + classStack.pop(); + } } @Override public void visitEnumEntry(JetEnumEntry enumEntry) { ClassDescriptor descriptor = bindingContext.get(BindingContext.CLASS, enumEntry); - enumEntryNeedSubclass.put(descriptor, !enumEntry.getDeclarations().isEmpty()); - super.visitEnumEntry(enumEntry); + assert descriptor != null; + + final boolean trivial = enumEntry.getDeclarations().isEmpty(); + if (!trivial) { + enumEntryNeedSubclass.put(descriptor, Boolean.TRUE); + + classStack.push(descriptor); + nameStack.push(nameStack.peek() + "$" + descriptor.getName().getName()); + super.visitEnumEntry(enumEntry); + nameStack.pop(); + classStack.pop(); + } + else { + super.visitEnumEntry(enumEntry); + } } @Override public void visitClassObject(JetClassObject classObject) { - JvmClassName name = recordClassObject(classObject); ClassDescriptor classDescriptor = bindingContext.get(BindingContext.CLASS, classObject.getObjectDeclaration()); assert classDescriptor != null; - recordEnclosing(classDescriptor); + + JvmClassName name = JvmClassName.byInternalName(nameStack.peek() + JvmAbi.CLASS_OBJECT_SUFFIX); + recordClosure(classObject, classDescriptor, classStack.peek(), name, false); + classStack.push(classDescriptor); nameStack.push(name.getInternalName()); super.visitClassObject(classObject); @@ -341,16 +378,12 @@ public class ClosureAnnotator { ClassDescriptor classDescriptor = bindingContext.get(BindingContext.CLASS, declaration); // working around a problem with shallow analysis if (classDescriptor == null) return; - recordEnclosing(classDescriptor); + + String name = getName(classDescriptor); + recordClosure(declaration, classDescriptor, classStack.peek(), JvmClassName.byInternalName(name), false); + classStack.push(classDescriptor); - String base = nameStack.peek(); - if (classDescriptor.getContainingDeclaration() instanceof NamespaceDescriptor) { - nameStack.push(base.isEmpty() ? classDescriptor.getName().getName() : base + '/' + classDescriptor.getName()); - } - else { - nameStack.push(base + '$' + classDescriptor.getName()); - } - recordName(classDescriptor, JvmClassName.byInternalName(nameStack.peek())); + nameStack.push(name); super.visitObjectDeclaration(declaration); nameStack.pop(); classStack.pop(); @@ -362,21 +395,23 @@ public class ClosureAnnotator { ClassDescriptor classDescriptor = bindingContext.get(BindingContext.CLASS, klass); // working around a problem with shallow analysis if (classDescriptor == null) return; - recordEnclosing(classDescriptor); + + String name = getName(classDescriptor); + recordClosure(klass, classDescriptor, classStack.peek(), JvmClassName.byInternalName(name), false); + classStack.push(classDescriptor); - String base = nameStack.peek(); - if (classDescriptor.getContainingDeclaration() instanceof NamespaceDescriptor) { - nameStack.push(base.isEmpty() ? classDescriptor.getName().getName() : base + '/' + classDescriptor.getName()); - } - else { - nameStack.push(base + '$' + classDescriptor.getName()); - } - recordName(classDescriptor, JvmClassName.byInternalName(nameStack.peek())); + nameStack.push(name); super.visitClass(klass); nameStack.pop(); classStack.pop(); } + private String getName(ClassDescriptor classDescriptor) { + String base = nameStack.peek(); + return classDescriptor.getContainingDeclaration() instanceof NamespaceDescriptor ? base.isEmpty() ? classDescriptor.getName() + .getName() : base + '/' + classDescriptor.getName() : base + '$' + classDescriptor.getName(); + } + @Override public void visitObjectLiteralExpression(JetObjectLiteralExpression expression) { ClassDescriptor classDescriptor = bindingContext.get(BindingContext.CLASS, expression.getObjectDeclaration()); @@ -385,8 +420,10 @@ public class ClosureAnnotator { super.visitObjectLiteralExpression(expression); return; } - recordAnonymousClass(expression.getObjectDeclaration()); - recordEnclosing(classDescriptor); + + final String name = inventAnonymousClassName(expression.getObjectDeclaration()); + recordClosure(expression.getObjectDeclaration(), classDescriptor, classStack.peek(), JvmClassName.byInternalName(name), false); + classStack.push(classDescriptor); nameStack.push(classNameForClassDescriptor(classDescriptor).getInternalName()); super.visitObjectLiteralExpression(expression); @@ -400,11 +437,13 @@ public class ClosureAnnotator { (FunctionDescriptor) bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, expression); // working around a problem with shallow analysis if (functionDescriptor == null) return; - JvmClassName name = recordAnonymousClass(expression); + + String name = inventAnonymousClassName(expression); ClassDescriptor classDescriptor = classDescriptorForFunctionDescriptor(functionDescriptor); - recordEnclosing(classDescriptor); + recordClosure(expression, classDescriptor, classStack.peek(), JvmClassName.byInternalName(name), true); + classStack.push(classDescriptor); - nameStack.push(name.getInternalName()); + nameStack.push(name); super.visitFunctionLiteralExpression(expression); nameStack.pop(); classStack.pop(); @@ -442,26 +481,16 @@ public class ClosureAnnotator { nameStack.pop(); } else { - JvmClassName name = recordAnonymousClass(function); + String name = inventAnonymousClassName(function); ClassDescriptor classDescriptor = classDescriptorForFunctionDescriptor(functionDescriptor); - recordEnclosing(classDescriptor); + recordClosure(function, classDescriptor, classStack.peek(), JvmClassName.byInternalName(name), true); + classStack.push(classDescriptor); - nameStack.push(name.getInternalName()); + nameStack.push(name); super.visitNamedFunction(function); nameStack.pop(); classStack.pop(); } } } - - private void recordName(@NotNull ClassDescriptor classDescriptor, @NotNull JvmClassName name) { - JvmClassName old = classNamesForClassDescriptor.put(classDescriptor, name); - if (old != null) { - throw new IllegalStateException("rewrite at key " + classDescriptor); - } - } - - public JvmClassName classNameForClassDescriptor(@NotNull ClassDescriptor classDescriptor) { - return classNamesForClassDescriptor.get(classDescriptor); - } } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/context/CodegenContext.java b/compiler/backend/src/org/jetbrains/jet/codegen/context/CodegenContext.java new file mode 100644 index 00000000000..3eb82b01d86 --- /dev/null +++ b/compiler/backend/src/org/jetbrains/jet/codegen/context/CodegenContext.java @@ -0,0 +1,544 @@ +/* + * Copyright 2010-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.jet.codegen.context; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.asm4.Type; +import org.jetbrains.jet.codegen.*; +import org.jetbrains.jet.lang.descriptors.*; +import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; +import org.jetbrains.jet.lang.resolve.name.Name; +import org.jetbrains.jet.lang.types.TypeSubstitutor; + +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.jetbrains.jet.codegen.JetTypeMapper.OBJECT_TYPE; + +/* + * @author max + * @author alex.tkachman + */ +public abstract class CodegenContext { + + public static final CodegenContext STATIC = + new CodegenContext(new FakeDescriptorForStaticContext(), OwnerKind.NAMESPACE, null, null, null, null) { + @Override + public boolean isStatic() { + return true; + } + + @Override + public String toString() { + return "ROOT"; + } + }; + private static final StackValue local1 = StackValue.local(1, OBJECT_TYPE); + @NotNull + private final DeclarationDescriptor contextDescriptor; + + private final OwnerKind contextKind; + @Nullable + private final CodegenContext parentContext; + private final ClassDescriptor thisDescriptor; + + public final MutableClosure closure; + + HashMap accessors; + + protected StackValue outerExpression; + private final LocalLookup enclosingLocalLookup; + + public CodegenContext( + @NotNull DeclarationDescriptor contextDescriptor, + OwnerKind contextKind, + @Nullable CodegenContext parentContext, + @Nullable MutableClosure closure, + @Nullable ClassDescriptor thisDescriptor, + @Nullable LocalLookup expressionCodegen + ) { + this.contextDescriptor = contextDescriptor; + this.contextKind = contextKind; + this.parentContext = parentContext; + this.closure = closure; + this.thisDescriptor = thisDescriptor; + this.enclosingLocalLookup = expressionCodegen; + } + + @NotNull + public final ClassDescriptor getThisDescriptor() { + if (thisDescriptor == null) { + throw new UnsupportedOperationException(); + } + return thisDescriptor; + } + + public final boolean hasThisDescriptor() { + return thisDescriptor != null; + } + + public DeclarationDescriptor getClassOrNamespaceDescriptor() { + CodegenContext c = this; + while (true) { + assert c != null; + DeclarationDescriptor contextDescriptor = c.getContextDescriptor(); + if (!(contextDescriptor instanceof ClassDescriptor) && !(contextDescriptor instanceof NamespaceDescriptor)) { + c = c.getParentContext(); + } + else { + return contextDescriptor; + } + } + } + + public CallableDescriptor getReceiverDescriptor() { + return null; + } + + public StackValue getOuterExpression(@Nullable StackValue prefix, boolean ignoreNoOuter) { + if (outerExpression == null) { + if (ignoreNoOuter) { + return null; + } + else { + throw new UnsupportedOperationException(); + } + } + + closure.setCaptureThis(); + return prefix != null ? StackValue.composed(prefix, outerExpression) : outerExpression; + } + + @NotNull + public DeclarationDescriptor getContextDescriptor() { + return contextDescriptor; + } + + public OwnerKind getContextKind() { + return contextKind; + } + + public CodegenContext intoNamespace(NamespaceDescriptor descriptor) { + return new NamespaceContext(descriptor, this, null); + } + + public CodegenContext intoNamespacePart(String delegateTo, NamespaceDescriptor descriptor) { + return new NamespaceContext(descriptor, this, new OwnerKind.StaticDelegateKind(delegateTo)); + } + + public CodegenContext intoClass(ClassDescriptor descriptor, OwnerKind kind, GenerationState state) { + return new ClassContext(state.getInjector().getJetTypeMapper(), descriptor, kind, this, null); + } + + public CodegenContext intoAnonymousClass( + ClassDescriptor descriptor, + ExpressionCodegen expressionCodegen + ) { + final JetTypeMapper typeMapper = expressionCodegen.getState().getInjector().getJetTypeMapper(); + return new AnonymousClassContext(typeMapper, descriptor, OwnerKind.IMPLEMENTATION, this, + expressionCodegen); + } + + public MethodContext intoFunction(FunctionDescriptor descriptor) { + return new MethodContext(descriptor, getContextKind(), this); + } + + public ConstructorContext intoConstructor(ConstructorDescriptor descriptor) { + if (descriptor == null) { + descriptor = new ConstructorDescriptorImpl(getThisDescriptor(), Collections.emptyList(), true) + .initialize(Collections.emptyList(), Collections.emptyList(), + Visibilities.PUBLIC); + } + return new ConstructorContext(descriptor, getContextKind(), this); + } + + public CodegenContext intoScript(@NotNull ScriptDescriptor script, @NotNull ClassDescriptor classDescriptor) { + return new ScriptContext(script, classDescriptor, OwnerKind.IMPLEMENTATION, this, closure); + } + + public CodegenContext intoClosure( + FunctionDescriptor funDescriptor, + ExpressionCodegen expressionCodegen + ) { + final JetTypeMapper typeMapper = expressionCodegen.getState().getInjector().getJetTypeMapper(); + return new ClosureContext(typeMapper, funDescriptor, + typeMapper.getClosureAnnotator().classDescriptorForFunctionDescriptor(funDescriptor), + this, expressionCodegen); + } + + public FrameMap prepareFrame(JetTypeMapper mapper) { + FrameMap frameMap = new FrameMap(); + + if (getContextKind() != OwnerKind.NAMESPACE) { + frameMap.enterTemp(OBJECT_TYPE); // 0 slot for this + } + + CallableDescriptor receiverDescriptor = getReceiverDescriptor(); + if (receiverDescriptor != null) { + Type type = mapper.mapType(receiverDescriptor.getReceiverParameter().getType(), MapTypeMode.VALUE); + frameMap.enterTemp(type); // Next slot for receiver + } + + return frameMap; + } + + @Nullable + public CodegenContext getParentContext() { + return parentContext; + } + + public ClassDescriptor getEnclosingClass() { + CodegenContext cur = getParentContext(); + while (cur != null && !(cur.getContextDescriptor() instanceof ClassDescriptor)) { + cur = cur.getParentContext(); + } + + return cur == null ? null : (ClassDescriptor) cur.getContextDescriptor(); + } + + public DeclarationDescriptor getAccessor(DeclarationDescriptor descriptor) { + if (accessors == null) { + accessors = new HashMap(); + } + descriptor = descriptor.getOriginal(); + DeclarationDescriptor accessor = accessors.get(descriptor); + if (accessor != null) { + return accessor; + } + + if (descriptor instanceof SimpleFunctionDescriptor) { + accessor = new AccessorForFunctionDescriptor(descriptor, contextDescriptor, accessors.size()); + } + else if (descriptor instanceof PropertyDescriptor) { + accessor = new AccessorForPropertyDescriptor((PropertyDescriptor) descriptor, contextDescriptor, accessors.size()); + } + else { + throw new UnsupportedOperationException(); + } + accessors.put(descriptor, accessor); + return accessor; + } + + public StackValue getReceiverExpression(JetTypeMapper typeMapper) { + assert getReceiverDescriptor() != null; + Type asmType = typeMapper.mapType(getReceiverDescriptor().getReceiverParameter().getType(), MapTypeMode.VALUE); + return hasThisDescriptor() ? StackValue.local(1, asmType) : StackValue.local(0, asmType); + } + + public abstract boolean isStatic(); + + public void copyAccessors(Map accessors) { + if (accessors != null) { + if (this.accessors == null) { + this.accessors = new HashMap(); + } + this.accessors.putAll(accessors); + } + } + + protected void initOuterExpression(JetTypeMapper typeMapper, ClassDescriptor classDescriptor) { + final ClassDescriptor enclosingClass = getEnclosingClass(); + outerExpression = enclosingClass != null + ? StackValue + .field(typeMapper.mapType(enclosingClass.getDefaultType(), MapTypeMode.VALUE), typeMapper.getJvmClassName( + classDescriptor), CodegenUtil.THIS$0, + false) + : null; + } + + public StackValue lookupInContext(DeclarationDescriptor d, StackValue result, GenerationState state, boolean ignoreNoOuter) { + final MutableClosure top = closure; + if (top != null) { + EnclosedValueDescriptor answer = closure.getCaptureVariables().get(d); + if (answer != null) { + StackValue innerValue = answer.getInnerValue(); + return result == null ? innerValue : StackValue.composed(result, innerValue); + } + + for (LocalLookup.LocalLookupCase aCase : LocalLookup.LocalLookupCase.values()) { + if (aCase.isCase(d, state)) { + StackValue innerValue = aCase.innerValue(d, enclosingLocalLookup, state, closure); + if (innerValue == null) { + break; + } + else { + return result == null ? innerValue : StackValue.composed(result, innerValue); + } + } + } + + StackValue outer = getOuterExpression(null, ignoreNoOuter); + result = result == null ? outer : StackValue.composed(result, outer); + } + + return parentContext != null ? parentContext.lookupInContext(d, result, state, ignoreNoOuter) : null; + } + + @NotNull + public Map getAccessors() { + return accessors == null ? Collections.emptyMap() : accessors; + } + + private static class FakeDescriptorForStaticContext implements DeclarationDescriptor { + + @NotNull + @Override + public DeclarationDescriptor getOriginal() { + throw new IllegalStateException(); + } + + @Override + public DeclarationDescriptor getContainingDeclaration() { + throw new IllegalStateException(); + } + + @Override + public DeclarationDescriptor substitute(TypeSubstitutor substitutor) { + throw new IllegalStateException(); + } + + @Override + public R accept(DeclarationDescriptorVisitor visitor, D data) { + throw new IllegalStateException(); + } + + @Override + public void acceptVoid(DeclarationDescriptorVisitor visitor) { + throw new IllegalStateException(); + } + + @Override + public List getAnnotations() { + throw new IllegalStateException(); + } + + @NotNull + @Override + public Name getName() { + throw new IllegalStateException(); + } + } + + private abstract static class ReceiverContext extends CodegenContext { + final CallableDescriptor receiverDescriptor; + + public ReceiverContext( + CallableDescriptor contextDescriptor, + OwnerKind contextKind, + CodegenContext parentContext, + @Nullable MutableClosure closure, + ClassDescriptor thisDescriptor, + @Nullable LocalLookup localLookup + ) { + super(contextDescriptor, contextKind, parentContext, closure, thisDescriptor, localLookup); + receiverDescriptor = contextDescriptor.getReceiverParameter().exists() ? contextDescriptor : null; + } + + @Override + public CallableDescriptor getReceiverDescriptor() { + return receiverDescriptor; + } + } + + public static class MethodContext extends ReceiverContext { + public MethodContext( + @NotNull FunctionDescriptor contextType, + OwnerKind contextKind, + CodegenContext parentContext + ) { + super(contextType instanceof PropertyAccessorDescriptor + ? ((PropertyAccessorDescriptor) contextType).getCorrespondingProperty() + : contextType, contextKind, parentContext, null, + parentContext.hasThisDescriptor() ? parentContext.getThisDescriptor() : null, null); + } + + @Override + public StackValue lookupInContext(DeclarationDescriptor d, StackValue result, GenerationState state, boolean ignoreNoOuter) { + if (getContextDescriptor() == d) { + return StackValue.local(0, JetTypeMapper.OBJECT_TYPE); + } + + //noinspection ConstantConditions + return getParentContext().lookupInContext(d, result, state, ignoreNoOuter); + } + + @Override + public boolean isStatic() { + //noinspection ConstantConditions + return getParentContext().isStatic(); + } + + @Override + public StackValue getOuterExpression(StackValue prefix, boolean ignoreNoOuter) { + //noinspection ConstantConditions + return getParentContext().getOuterExpression(prefix, false); + } + + @Override + public String toString() { + return "Method: " + getContextDescriptor(); + } + } + + public static class ConstructorContext extends MethodContext { + public ConstructorContext( + ConstructorDescriptor contextDescriptor, + OwnerKind kind, + CodegenContext parent + ) { + super(contextDescriptor, kind, parent); + + final ClassDescriptor type = getEnclosingClass(); + outerExpression = type != null ? local1 : null; + } + + @Override + public StackValue getOuterExpression(StackValue prefix, boolean ignoreNoOuter) { + return outerExpression; + } + + @Override + public String toString() { + return "Constructor: " + getContextDescriptor().getName(); + } + } + + public static class ScriptContext extends CodegenContext { + @NotNull + private final ScriptDescriptor scriptDescriptor; + + public ScriptContext( + @NotNull ScriptDescriptor scriptDescriptor, + @NotNull ClassDescriptor contextDescriptor, + @NotNull OwnerKind contextKind, + @Nullable CodegenContext parentContext, + @Nullable MutableClosure closure + ) { + super(contextDescriptor, contextKind, parentContext, closure, contextDescriptor, null); + + this.scriptDescriptor = scriptDescriptor; + } + + @NotNull + public ScriptDescriptor getScriptDescriptor() { + return scriptDescriptor; + } + + @Override + public boolean isStatic() { + return true; + } + } + + public static class ClassContext extends CodegenContext { + public ClassContext( + JetTypeMapper typeMapper, + ClassDescriptor contextDescriptor, + OwnerKind contextKind, + CodegenContext parentContext, + LocalLookup localLookup + ) { + super(contextDescriptor, contextKind, parentContext, (MutableClosure) typeMapper.getCalculatedClosure(contextDescriptor), + contextDescriptor, + localLookup); + initOuterExpression(typeMapper, contextDescriptor); + } + + @Override + public boolean isStatic() { + return false; + } + } + + private static class AnonymousClassContext extends CodegenContext { + public AnonymousClassContext( + JetTypeMapper typeMapper, + ClassDescriptor contextDescriptor, + OwnerKind contextKind, + CodegenContext parentContext, + LocalLookup localLookup + ) { + super(contextDescriptor, contextKind, parentContext, (MutableClosure) typeMapper.getCalculatedClosure(contextDescriptor), + contextDescriptor, + localLookup); + initOuterExpression(typeMapper, contextDescriptor); + } + + @Override + public boolean isStatic() { + return false; + } + + @Override + public String toString() { + return "Anonymous: " + getThisDescriptor(); + } + } + + private static class ClosureContext extends ReceiverContext { + private final ClassDescriptor classDescriptor; + + public ClosureContext( + JetTypeMapper typeMapper, + FunctionDescriptor contextDescriptor, + ClassDescriptor classDescriptor, + CodegenContext parentContext, + LocalLookup localLookup + ) { + super(contextDescriptor, OwnerKind.IMPLEMENTATION, parentContext, + (MutableClosure) typeMapper.getCalculatedClosure(classDescriptor), classDescriptor, localLookup); + this.classDescriptor = classDescriptor; + + initOuterExpression(typeMapper, classDescriptor); + } + + @NotNull + @Override + public DeclarationDescriptor getContextDescriptor() { + return classDescriptor; + } + + @Override + public boolean isStatic() { + return false; + } + + @Override + public String toString() { + return "Closure: " + classDescriptor; + } + } + + public static class NamespaceContext extends CodegenContext { + public NamespaceContext(NamespaceDescriptor contextDescriptor, CodegenContext parent, OwnerKind kind) { + super(contextDescriptor, kind != null ? kind : OwnerKind.NAMESPACE, parent, null, null, null); + } + + @Override + public boolean isStatic() { + return true; + } + + @Override + public String toString() { + return "Namespace: " + getContextDescriptor().getName(); + } + } +} diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/EnclosedValueDescriptor.java b/compiler/backend/src/org/jetbrains/jet/codegen/context/EnclosedValueDescriptor.java similarity index 56% rename from compiler/backend/src/org/jetbrains/jet/codegen/EnclosedValueDescriptor.java rename to compiler/backend/src/org/jetbrains/jet/codegen/context/EnclosedValueDescriptor.java index 73793f26af5..4ddeab167f8 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/EnclosedValueDescriptor.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/context/EnclosedValueDescriptor.java @@ -17,19 +17,23 @@ /* * @author max */ -package org.jetbrains.jet.codegen; +package org.jetbrains.jet.codegen.context; +import org.jetbrains.asm4.Type; +import org.jetbrains.jet.codegen.ExpressionCodegen; +import org.jetbrains.jet.codegen.GenerationState; +import org.jetbrains.jet.codegen.StackValue; import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; -public class EnclosedValueDescriptor { +public final class EnclosedValueDescriptor { private final DeclarationDescriptor descriptor; private final StackValue innerValue; - private final StackValue outerValue; + private final Type type; - public EnclosedValueDescriptor(DeclarationDescriptor descriptor, StackValue innerValue, StackValue outerValue) { + public EnclosedValueDescriptor(DeclarationDescriptor descriptor, StackValue innerValue, Type type) { this.descriptor = descriptor; this.innerValue = innerValue; - this.outerValue = outerValue; + this.type = type; } public DeclarationDescriptor getDescriptor() { @@ -40,7 +44,18 @@ public class EnclosedValueDescriptor { return innerValue; } - public StackValue getOuterValue() { - return outerValue; + public Type getType() { + return type; + } + + public StackValue getOuterValue(ExpressionCodegen expressionCodegen) { + final GenerationState state = expressionCodegen.getState(); + for (LocalLookup.LocalLookupCase aCase : LocalLookup.LocalLookupCase.values()) { + if (aCase.isCase(descriptor, state)) { + return aCase.outerValue(this, expressionCodegen); + } + } + + throw new IllegalStateException(); } } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/context/LocalLookup.java b/compiler/backend/src/org/jetbrains/jet/codegen/context/LocalLookup.java new file mode 100644 index 00000000000..4b6fa4a0915 --- /dev/null +++ b/compiler/backend/src/org/jetbrains/jet/codegen/context/LocalLookup.java @@ -0,0 +1,136 @@ +/* + * Copyright 2010-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.jet.codegen.context; + +import org.jetbrains.asm4.Type; +import org.jetbrains.jet.codegen.*; +import org.jetbrains.jet.lang.descriptors.*; +import org.jetbrains.jet.lang.psi.JetElement; +import org.jetbrains.jet.lang.resolve.BindingContextUtils; +import org.jetbrains.jet.lang.resolve.java.JvmClassName; +import org.jetbrains.jet.lang.types.JetType; + +/** + * @author alex.tkachman + */ +public interface LocalLookup { + boolean lookupLocal(DeclarationDescriptor descriptor); + + enum LocalLookupCase { + VAR { + @Override + public boolean isCase(DeclarationDescriptor d, GenerationState state) { + return (d instanceof VariableDescriptor) && !(d instanceof PropertyDescriptor); + } + + @Override + public StackValue innerValue(DeclarationDescriptor d, LocalLookup localLookup, GenerationState state, MutableClosure closure) { + VariableDescriptor vd = (VariableDescriptor) d; + + final boolean idx = localLookup != null && localLookup.lookupLocal(vd); + if (!idx) return null; + + final Type sharedVarType = state.getInjector().getJetTypeMapper().getSharedVarType(vd); + Type localType = state.getInjector().getJetTypeMapper().mapType(vd.getType(), MapTypeMode.VALUE); + final Type type = sharedVarType != null ? sharedVarType : localType; + + final String fieldName = "$" + vd.getName(); + StackValue innerValue = sharedVarType != null + ? StackValue.fieldForSharedVar(localType, closure.getClassName(), fieldName) + : StackValue.field(type, closure.getClassName(), fieldName, false); + + closure.recordField(fieldName, type); + closure.captureVariable(new EnclosedValueDescriptor(d, innerValue, type)); + + return innerValue; + } + }, + + LOCAL_NAMED_FUNCTION { + @Override + public boolean isCase(DeclarationDescriptor d, GenerationState state) { + return CodegenUtil.isNamedFun(d, state.getBindingContext()) && (d.getContainingDeclaration() instanceof FunctionDescriptor); + } + + @Override + public StackValue innerValue(DeclarationDescriptor d, LocalLookup localLookup, GenerationState state, MutableClosure closure) { + FunctionDescriptor vd = (FunctionDescriptor) d; + + final boolean idx = localLookup.lookupLocal(vd); + if (!idx) return null; + + JetElement expression = (JetElement) BindingContextUtils.callableDescriptorToDeclaration(state.getBindingContext(), vd); + JvmClassName cn = state.getInjector().getJetTypeMapper().getClosureAnnotator().classNameForAnonymousClass(expression); + Type localType = cn.getAsmType(); + + final String fieldName = "$" + vd.getName(); + StackValue innerValue = StackValue.field(localType, closure.getClassName(), fieldName, false); + + closure.recordField(fieldName, localType); + closure.captureVariable(new EnclosedValueDescriptor(d, innerValue, localType)); + + return innerValue; + } + }, + + RECEIVER { + @Override + public boolean isCase(DeclarationDescriptor d, GenerationState state) { + return d instanceof FunctionDescriptor; + } + + @Override + public StackValue innerValue( + DeclarationDescriptor d, + LocalLookup enclosingLocalLookup, + GenerationState state, + MutableClosure closure + ) { + if (closure.getEnclosingReceiverDescriptor() != d) return null; + + final JetType receiverType = ((CallableDescriptor) d).getReceiverParameter().getType(); + Type type = state.getInjector().getJetTypeMapper().mapType(receiverType, MapTypeMode.VALUE); + StackValue innerValue = StackValue.field(type, closure.getClassName(), CodegenUtil.RECEIVER$0, false); + closure.setCaptureReceiver(); + + return innerValue; + } + + @Override + public StackValue outerValue(EnclosedValueDescriptor d, ExpressionCodegen expressionCodegen) { + CallableDescriptor descriptor = (FunctionDescriptor) d.getDescriptor(); + return StackValue.local(descriptor.getExpectedThisObject().exists() ? 1 : 0, d.getType()); + } + }; + + public abstract boolean isCase(DeclarationDescriptor d, GenerationState state); + + public abstract StackValue innerValue( + DeclarationDescriptor d, + LocalLookup localLookup, + GenerationState state, + MutableClosure closure + ); + + public StackValue outerValue(EnclosedValueDescriptor d, ExpressionCodegen expressionCodegen) { + final int idx = expressionCodegen.lookupLocalIndex(d.getDescriptor()); + assert idx != -1; + + return StackValue.local(idx, d.getType()); + } + } +} diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/context/MutableClosure.java b/compiler/backend/src/org/jetbrains/jet/codegen/context/MutableClosure.java new file mode 100644 index 00000000000..0b1a3f98106 --- /dev/null +++ b/compiler/backend/src/org/jetbrains/jet/codegen/context/MutableClosure.java @@ -0,0 +1,130 @@ +/* + * Copyright 2010-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.jet.codegen.context; + +import com.intellij.openapi.util.Pair; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.asm4.Type; +import org.jetbrains.jet.lang.descriptors.CallableDescriptor; +import org.jetbrains.jet.lang.descriptors.ClassDescriptor; +import org.jetbrains.jet.lang.descriptors.ClassifierDescriptor; +import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; +import org.jetbrains.jet.lang.psi.JetDelegatorToSuperCall; +import org.jetbrains.jet.lang.resolve.java.JvmClassName; + +import java.util.*; + +/** + * @author alex.tkachman + */ +public final class MutableClosure implements CalculatedClosure { + private final JetDelegatorToSuperCall superCall; + + private final ClassDescriptor enclosingClass; + private final CallableDescriptor enclosingReceiverDescriptor; + + private final JvmClassName name; + + private boolean captureThis; + private boolean captureReceiver; + + private Map captureVariables; + private List> recordedFields; + + MutableClosure( + JetDelegatorToSuperCall superCall, + ClassDescriptor enclosingClass, + JvmClassName className, + CallableDescriptor enclosingReceiverDescriptor + ) { + this.superCall = superCall; + this.enclosingClass = enclosingClass; + this.enclosingReceiverDescriptor = enclosingReceiverDescriptor; + this.name = className; + } + + @Nullable + @Override + public ClassDescriptor getEnclosingClass() { + return enclosingClass; + } + + @NotNull + @Override + public JvmClassName getClassName() { + return name; + } + + @Override + public JetDelegatorToSuperCall getSuperCall() { + return superCall; + } + + @Override + public ClassDescriptor getCaptureThis() { + return captureThis ? enclosingClass : null; + } + + public void setCaptureThis() { + this.captureThis = true; + } + + @Override + public ClassifierDescriptor getCaptureReceiver() { + return captureReceiver + ? enclosingReceiverDescriptor.getReceiverParameter().getType().getConstructor().getDeclarationDescriptor() + : null; + } + + public void setCaptureReceiver() { + if (enclosingReceiverDescriptor == null) { + throw new IllegalStateException(); + } + this.captureReceiver = true; + } + + @NotNull + @Override + public Map getCaptureVariables() { + return captureVariables != null ? captureVariables : Collections.emptyMap(); + } + + @NotNull + @Override + public List> getRecordedFields() { + return recordedFields != null ? recordedFields : Collections.>emptyList(); + } + + public void recordField(String name, Type type) { + if (recordedFields == null) { + recordedFields = new LinkedList>(); + } + recordedFields.add(new Pair(name, type)); + } + + public void captureVariable(EnclosedValueDescriptor value) { + if (captureVariables == null) { + captureVariables = new HashMap(); + } + captureVariables.put(value.getDescriptor(), value); + } + + public CallableDescriptor getEnclosingReceiverDescriptor() { + return enclosingReceiverDescriptor; + } +} diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/signature/JvmMethodParameterKind.java b/compiler/backend/src/org/jetbrains/jet/codegen/signature/JvmMethodParameterKind.java index 4121da62911..1475227e46c 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/signature/JvmMethodParameterKind.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/signature/JvmMethodParameterKind.java @@ -18,13 +18,15 @@ package org.jetbrains.jet.codegen.signature; /** * @author Stepan Koltsov + * @author alex.tkachman */ public enum JvmMethodParameterKind { VALUE, THIS, - THIS0, + OUTER, RECEIVER, SHARED_VAR, ENUM_NAME, ENUM_ORDINAL, + SUPER_CALL_PARAM } diff --git a/compiler/backend/src/org/jetbrains/jet/di/InjectorForJetTypeMapper.java b/compiler/backend/src/org/jetbrains/jet/di/InjectorForJetTypeMapper.java index 67eb799cee9..f1a3fa6f2a0 100644 --- a/compiler/backend/src/org/jetbrains/jet/di/InjectorForJetTypeMapper.java +++ b/compiler/backend/src/org/jetbrains/jet/di/InjectorForJetTypeMapper.java @@ -23,7 +23,7 @@ import org.jetbrains.jet.lang.psi.JetFile; import org.jetbrains.jet.codegen.JetTypeMapper; import org.jetbrains.jet.codegen.BuiltinToJavaTypesMapping; import org.jetbrains.jet.codegen.ClassBuilderMode; -import org.jetbrains.jet.codegen.ClosureAnnotator; +import org.jetbrains.jet.codegen.context.ClosureAnnotator; import org.jetbrains.annotations.NotNull; import javax.annotation.PreDestroy; diff --git a/compiler/backend/src/org/jetbrains/jet/di/InjectorForJvmCodegen.java b/compiler/backend/src/org/jetbrains/jet/di/InjectorForJvmCodegen.java index 4359135f053..41f664141b7 100644 --- a/compiler/backend/src/org/jetbrains/jet/di/InjectorForJvmCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/di/InjectorForJvmCodegen.java @@ -31,7 +31,7 @@ import org.jetbrains.jet.codegen.ScriptCodegen; import org.jetbrains.jet.codegen.intrinsics.IntrinsicMethods; import org.jetbrains.jet.codegen.ClassFileFactory; import org.jetbrains.jet.codegen.MemberCodegen; -import org.jetbrains.jet.codegen.ClosureAnnotator; +import org.jetbrains.jet.codegen.context.ClosureAnnotator; import org.jetbrains.annotations.NotNull; import javax.annotation.PreDestroy; diff --git a/compiler/tests/org/jetbrains/jet/codegen/ArrayGenTest.java b/compiler/tests/org/jetbrains/jet/codegen/ArrayGenTest.java index 8c1f04b5bba..b591819c982 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/ArrayGenTest.java +++ b/compiler/tests/org/jetbrains/jet/codegen/ArrayGenTest.java @@ -28,30 +28,36 @@ public class ArrayGenTest extends CodegenTestCase { createEnvironmentWithMockJdkAndIdeaAnnotations(ConfigurationKind.JDK_ONLY); } - public void testKt238 () throws Exception { + public void testKt238() throws Exception { blackBoxFile("regressions/kt238.jet"); } - public void testKt326 () throws Exception { -// blackBoxFile("regressions/kt326.jet"); -// System.out.println(generateToText()); + public void testKt326() throws Exception { + // blackBoxFile("regressions/kt326.jet"); + // System.out.println(generateToText()); } - public void testKt779 () throws Exception { + public void testKt779() throws Exception { blackBoxFile("regressions/kt779.jet"); -// System.out.println(generateToText()); + // System.out.println(generateToText()); } - public void testCreateMultiInt () throws Exception { + public void testCreateMultiInt() throws Exception { loadText("fun foo() = Array> (5, { Array(it, {239}) })"); Method foo = generateFunction(); - Integer[][] invoke = (Integer[][]) foo.invoke(null); - assertEquals(invoke[2].length, 2); - assertEquals(invoke[4].length, 4); - assertEquals(invoke[4][2].intValue(), 239); + try { + Integer[][] invoke = (Integer[][]) foo.invoke(null); + assertEquals(invoke[2].length, 2); + assertEquals(invoke[4].length, 4); + assertEquals(invoke[4][2].intValue(), 239); + } + catch (Throwable e) { + System.out.println(generateToText()); + throw ((e instanceof RuntimeException)) ? (RuntimeException) e : new RuntimeException(e); + } } - public void testCreateMultiIntNullable () throws Exception { + public void testCreateMultiIntNullable() throws Exception { loadText("fun foo() = Array> (5, { arrayOfNulls(it) })"); Method foo = generateFunction(); Integer[][] invoke = (Integer[][]) foo.invoke(null); @@ -59,7 +65,7 @@ public class ArrayGenTest extends CodegenTestCase { assertEquals(invoke[4].length, 4); } - public void testCreateMultiString () throws Exception { + public void testCreateMultiString() throws Exception { loadText("fun foo() = Array> (5, { Array(0,{\"\"}) })"); Method foo = generateFunction(); Object invoke = foo.invoke(null); @@ -67,16 +73,16 @@ public class ArrayGenTest extends CodegenTestCase { assertTrue(invoke instanceof Object[]); } - public void testCreateMultiGenerics () throws Exception { -// loadText("class L() { val a = Array(5) } fun foo() = L.a"); -// System.out.println(generateToText()); -// Method foo = generateFunction(); -// Object invoke = foo.invoke(null); -// System.out.println(invoke.getClass()); -// assertTrue(invoke.getClass() == Object[].class); + public void testCreateMultiGenerics() throws Exception { + // loadText("class L() { val a = Array(5) } fun foo() = L.a"); + // System.out.println(generateToText()); + // Method foo = generateFunction(); + // Object invoke = foo.invoke(null); + // System.out.println(invoke.getClass()); + // assertTrue(invoke.getClass() == Object[].class); } - public void testIntGenerics () throws Exception { + public void testIntGenerics() throws Exception { loadText("class L(var a : T) {} fun foo() = L(5).a"); //System.out.println(generateToText()); Method foo = generateFunction(); @@ -85,221 +91,222 @@ public class ArrayGenTest extends CodegenTestCase { assertTrue(invoke instanceof Integer); } - public void testIterator () throws Exception { + public void testIterator() throws Exception { loadText("fun box() { val x = Array(5, { it } ).iterator(); while(x.hasNext()) { java.lang.System.out?.println(x.next()) } }"); -// System.out.println(generateToText()); + // System.out.println(generateToText()); Method foo = generateFunction(); foo.invoke(null); } - public void testPrimitiveIterator () throws Exception { + public void testPrimitiveIterator() throws Exception { loadText("fun box() { val x = ByteArray(5).iterator(); while(x.hasNext()) { java.lang.System.out?.println(x.nextByte()) } }"); -// System.out.println(generateToText()); + // System.out.println(generateToText()); Method foo = generateFunction(); foo.invoke(null); } - public void testPrimitiveIteratorByte () throws Exception { + public void testPrimitiveIteratorByte() throws Exception { loadText("fun box() { for(x in ByteArray(5)) { java.lang.System.out?.println(x) } }"); -// System.out.println(generateToText()); + // System.out.println(generateToText()); Method foo = generateFunction(); foo.invoke(null); } - public void testPrimitiveIteratorShort () throws Exception { + public void testPrimitiveIteratorShort() throws Exception { loadText("fun box() { for(x in ShortArray(5)) { java.lang.System.out?.println(x) } }"); -// System.out.println(generateToText()); + // System.out.println(generateToText()); Method foo = generateFunction(); foo.invoke(null); } - public void testPrimitiveIteratorInt () throws Exception { + public void testPrimitiveIteratorInt() throws Exception { loadText("fun box() { for(x in IntArray(5)) { java.lang.System.out?.println(x) } }"); -// System.out.println(generateToText()); + // System.out.println(generateToText()); Method foo = generateFunction(); foo.invoke(null); } - public void testPrimitiveIteratorLong () throws Exception { + public void testPrimitiveIteratorLong() throws Exception { loadText("fun box() { for(x in LongArray(5)) { java.lang.System.out?.println(x) } }"); -// System.out.println(generateToText()); + // System.out.println(generateToText()); Method foo = generateFunction(); foo.invoke(null); } - public void testPrimitiveIteratorFloat () throws Exception { + public void testPrimitiveIteratorFloat() throws Exception { loadText("fun box() { for(x in FloatArray(5)) { java.lang.System.out?.println(x) } }"); -// System.out.println(generateToText()); + // System.out.println(generateToText()); Method foo = generateFunction(); foo.invoke(null); } - public void testPrimitiveIteratorDouble () throws Exception { + public void testPrimitiveIteratorDouble() throws Exception { loadText("fun box() { for(x in DoubleArray(5)) { java.lang.System.out?.println(x) } }"); -// System.out.println(generateToText()); + // System.out.println(generateToText()); Method foo = generateFunction(); foo.invoke(null); } - public void testPrimitiveIteratorChar () throws Exception { + public void testPrimitiveIteratorChar() throws Exception { loadText("fun box() { for(x in CharArray(5)) { java.lang.System.out?.println(x) } }"); -// System.out.println(generateToText()); + // System.out.println(generateToText()); Method foo = generateFunction(); foo.invoke(null); } - public void testPrimitiveIteratorBoolean () throws Exception { + public void testPrimitiveIteratorBoolean() throws Exception { loadText("fun box() { for(x in BooleanArray(5)) { java.lang.System.out?.println(x) } }"); -// System.out.println(generateToText()); + // System.out.println(generateToText()); Method foo = generateFunction(); foo.invoke(null); } - public void testLongIterator () throws Exception { + public void testLongIterator() throws Exception { loadText("fun box() { val x = LongArray(5).iterator(); while(x.hasNext()) { java.lang.System.out?.println(x.nextLong()) } }"); -// System.out.println(generateToText()); + // System.out.println(generateToText()); Method foo = generateFunction(); foo.invoke(null); } - public void testCharIterator () throws Exception { + public void testCharIterator() throws Exception { loadText("fun box() { val x = CharArray(5).iterator(); while(x.hasNext()) { java.lang.System.out?.println(x.next()) } }"); -// System.out.println(generateToText()); + // System.out.println(generateToText()); Method foo = generateFunction(); foo.invoke(null); } - public void testByteIterator () throws Exception { + public void testByteIterator() throws Exception { loadText("fun box() { val x = ByteArray(5).iterator(); while(x.hasNext()) { java.lang.System.out?.println(x.next()) } }"); -// System.out.println(generateToText()); + // System.out.println(generateToText()); Method foo = generateFunction(); foo.invoke(null); } - public void testShortIterator () throws Exception { + public void testShortIterator() throws Exception { loadText("fun box() { val x = ShortArray(5).iterator(); while(x.hasNext()) { java.lang.System.out?.println(x.next()) } }"); -// System.out.println(generateToText()); + // System.out.println(generateToText()); Method foo = generateFunction(); foo.invoke(null); } - public void testIntIterator () throws Exception { + public void testIntIterator() throws Exception { loadText("fun box() { val x = IntArray(5).iterator(); while(x.hasNext()) { java.lang.System.out?.println(x.next()) } }"); -// System.out.println(generateToText()); + // System.out.println(generateToText()); Method foo = generateFunction(); foo.invoke(null); } - public void testLongIterator2 () throws Exception { + public void testLongIterator2() throws Exception { loadText("fun box() { val x = LongArray(5).iterator(); while(x.hasNext()) { java.lang.System.out?.println(x.next()) } }"); -// System.out.println(generateToText()); + // System.out.println(generateToText()); Method foo = generateFunction(); foo.invoke(null); } - public void testFloatIterator () throws Exception { + public void testFloatIterator() throws Exception { loadText("fun box() { val x = FloatArray(5).iterator(); while(x.hasNext()) { java.lang.System.out?.println(x.next()) } }"); -// System.out.println(generateToText()); + // System.out.println(generateToText()); Method foo = generateFunction(); foo.invoke(null); } - public void testDoubleIterator () throws Exception { + public void testDoubleIterator() throws Exception { loadText("fun box() { val x = ShortArray(5).iterator(); while(x.hasNext()) { java.lang.System.out?.println(x.next()) } }"); -// System.out.println(generateToText()); + // System.out.println(generateToText()); Method foo = generateFunction(); foo.invoke(null); } - public void testBooleanIterator () throws Exception { + public void testBooleanIterator() throws Exception { loadText("fun box() { val x = BooleanArray(5).iterator(); while(x.hasNext()) { java.lang.System.out?.println(x.next()) } }"); -// System.out.println(generateToText()); + // System.out.println(generateToText()); Method foo = generateFunction(); foo.invoke(null); } - public void testArrayIndices () throws Exception { - loadText("fun box() { val x = Array(5, {it}).indices.iterator(); while(x.hasNext()) { java.lang.System.out?.println(x.next()) } }"); -// System.out.println(generateToText()); + public void testArrayIndices() throws Exception { + loadText( + "fun box() { val x = Array(5, {it}).indices.iterator(); while(x.hasNext()) { java.lang.System.out?.println(x.next()) } }"); + // System.out.println(generateToText()); Method foo = generateFunction(); foo.invoke(null); } - public void testCharIndices () throws Exception { + public void testCharIndices() throws Exception { loadText("fun box() { val x = CharArray(5).indices.iterator(); while(x.hasNext()) { java.lang.System.out?.println(x.next()) } }"); -// System.out.println(generateToText()); + // System.out.println(generateToText()); Method foo = generateFunction(); foo.invoke(null); } - public void testCollectionPlusAssign () throws Exception { + public void testCollectionPlusAssign() throws Exception { blackBoxFile("regressions/kt33.jet"); } - public void testArrayPlusAssign () throws Exception { + public void testArrayPlusAssign() throws Exception { loadText("fun box() : Int { val s = IntArray(1); s [0] = 5; s[0] += 7; return s[0] }"); -// System.out.println(generateToText()); + // System.out.println(generateToText()); Method foo = generateFunction(); - assertTrue((Integer)foo.invoke(null) == 12); + assertTrue((Integer) foo.invoke(null) == 12); } - public void testCollectionAssignGetMultiIndex () throws Exception { - loadText("import java.util.ArrayList\n" + - "fun box() : String { val s = ArrayList(1); s.add(\"\"); s [1, -1] = \"5\"; s[2, -2] += \"7\"; return s[2,-2] }\n" + - "fun ArrayList.get(index1: Int, index2 : Int) = this[index1+index2]!!\n" + - "fun ArrayList.set(index1: Int, index2 : Int, elem: String) { this[index1+index2] = elem }\n"); -// System.out.println(generateToText()); - Method foo = generateFunction("box"); - assertTrue(foo.invoke(null).equals("57")); - } - - public void testArrayGetAssignMultiIndex () throws Exception { - loadText( - "fun box() : String? { val s = Array(1,{ \"\" }); s [1, -1] = \"5\"; s[2, -2] += \"7\"; return s[-3,3] }\n" + - "fun Array.get(index1: Int, index2 : Int) = this[index1+index2]\n" + - "fun Array.set(index1: Int, index2 : Int, elem: String) { this[index1+index2] = elem\n }"); -// System.out.println(generateToText()); + public void testCollectionAssignGetMultiIndex() throws Exception { + loadText("import java.util.ArrayList\n" + + "fun box() : String { val s = ArrayList(1); s.add(\"\"); s [1, -1] = \"5\"; s[2, -2] += \"7\"; return s[2,-2] }\n" + + "fun ArrayList.get(index1: Int, index2 : Int) = this[index1+index2]!!\n" + + "fun ArrayList.set(index1: Int, index2 : Int, elem: String) { this[index1+index2] = elem }\n"); + // System.out.println(generateToText()); Method foo = generateFunction("box"); assertTrue(foo.invoke(null).equals("57")); } - public void testCollectionGetMultiIndex () throws Exception { - loadText("import java.util.ArrayList\n" + - "fun box() : String { val s = ArrayList(1); s.add(\"\"); s [1, -1] = \"5\"; return s[2, -2] }\n" + - "fun ArrayList.get(index1: Int, index2 : Int) = this[index1+index2]!!\n" + - "fun ArrayList.set(index1: Int, index2 : Int, elem: String) { this[index1+index2] = elem }\n"); -// System.out.println(generateToText()); - Method foo = generateFunction("box"); - assertTrue(foo.invoke(null).equals("5")); - } - - public void testArrayGetMultiIndex () throws Exception { + public void testArrayGetAssignMultiIndex() throws Exception { loadText( - "fun box() : String? { val s = Array(1,{ \"\" }); s [1, -1] = \"5\"; return s[-2, 2] }\n" + - "fun Array.get(index1: Int, index2 : Int) = this[index1+index2]\n" + - "fun Array.set(index1: Int, index2 : Int, elem: String) { this[index1+index2] = elem\n }"); -// System.out.println(generateToText()); + "fun box() : String? { val s = Array(1,{ \"\" }); s [1, -1] = \"5\"; s[2, -2] += \"7\"; return s[-3,3] }\n" + + "fun Array.get(index1: Int, index2 : Int) = this[index1+index2]\n" + + "fun Array.set(index1: Int, index2 : Int, elem: String) { this[index1+index2] = elem\n }"); + // System.out.println(generateToText()); + Method foo = generateFunction("box"); + assertTrue(foo.invoke(null).equals("57")); + } + + public void testCollectionGetMultiIndex() throws Exception { + loadText("import java.util.ArrayList\n" + + "fun box() : String { val s = ArrayList(1); s.add(\"\"); s [1, -1] = \"5\"; return s[2, -2] }\n" + + "fun ArrayList.get(index1: Int, index2 : Int) = this[index1+index2]!!\n" + + "fun ArrayList.set(index1: Int, index2 : Int, elem: String) { this[index1+index2] = elem }\n"); + // System.out.println(generateToText()); Method foo = generateFunction("box"); assertTrue(foo.invoke(null).equals("5")); } - public void testMap () throws Exception { + public void testArrayGetMultiIndex() throws Exception { loadText( - "fun box() : Int? { val s = java.util.HashMap(); s[\"239\"] = 239; return s[\"239\"] }\n" + - "fun java.util.HashMap.set(index: String, elem: Int?) { this.put(index, elem) }"); -// System.out.println(generateToText()); + "fun box() : String? { val s = Array(1,{ \"\" }); s [1, -1] = \"5\"; return s[-2, 2] }\n" + + "fun Array.get(index1: Int, index2 : Int) = this[index1+index2]\n" + + "fun Array.set(index1: Int, index2 : Int, elem: String) { this[index1+index2] = elem\n }"); + // System.out.println(generateToText()); Method foo = generateFunction("box"); - assertTrue((Integer)foo.invoke(null) == 239); + assertTrue(foo.invoke(null).equals("5")); } - public void testLongDouble () throws Exception { + public void testMap() throws Exception { loadText( - "fun box() : Int { var l = IntArray(1); l[0.toLong()] = 4; l[0.toLong()] += 6; return l[0.toLong()];}\n" + - "fun IntArray.set(index: Long, elem: Int) { this[index.toInt()] = elem }\n" + - "fun IntArray.get(index: Long) = this[index.toInt()]"); -// System.out.println(generateToText()); + "fun box() : Int? { val s = java.util.HashMap(); s[\"239\"] = 239; return s[\"239\"] }\n" + + "fun java.util.HashMap.set(index: String, elem: Int?) { this.put(index, elem) }"); + // System.out.println(generateToText()); Method foo = generateFunction("box"); - assertTrue((Integer)foo.invoke(null) == 10); + assertTrue((Integer) foo.invoke(null) == 239); + } + + public void testLongDouble() throws Exception { + loadText( + "fun box() : Int { var l = IntArray(1); l[0.toLong()] = 4; l[0.toLong()] += 6; return l[0.toLong()];}\n" + + "fun IntArray.set(index: Long, elem: Int) { this[index.toInt()] = elem }\n" + + "fun IntArray.get(index: Long) = this[index.toInt()]"); + // System.out.println(generateToText()); + Method foo = generateFunction("box"); + assertTrue((Integer) foo.invoke(null) == 10); } public void testKt503() { @@ -308,7 +315,7 @@ public class ArrayGenTest extends CodegenTestCase { public void testKt602() { blackBoxFile("regressions/kt602.jet"); -// System.out.println(generateToText()); + // System.out.println(generateToText()); } public void testKt950() { @@ -317,12 +324,12 @@ public class ArrayGenTest extends CodegenTestCase { public void testKt594() throws Exception { loadFile("regressions/kt594.jet"); -// System.out.println(generateToText()); + // System.out.println(generateToText()); blackBox(); } public void testNonNullArray() throws Exception { blackBoxFile("classes/nonnullarray.jet"); -// System.out.println(generateToText()); + // System.out.println(generateToText()); } } diff --git a/compiler/tests/org/jetbrains/jet/codegen/ClassGenTest.java b/compiler/tests/org/jetbrains/jet/codegen/ClassGenTest.java index b0829a009b4..86800186409 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/ClassGenTest.java +++ b/compiler/tests/org/jetbrains/jet/codegen/ClassGenTest.java @@ -332,7 +332,7 @@ public class ClassGenTest extends CodegenTestCase { } public void testSelfCreate() throws Exception { - createEnvironmentWithFullJdk(); + createEnvironmentWithMockJdkAndIdeaAnnotations(ConfigurationKind.JDK_ONLY); blackBoxFile("classes/selfcreate.kt"); } diff --git a/compiler/tests/org/jetbrains/jet/codegen/FunctionGenTest.java b/compiler/tests/org/jetbrains/jet/codegen/FunctionGenTest.java index 4f3aa6d49a1..6de126c6881 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/FunctionGenTest.java +++ b/compiler/tests/org/jetbrains/jet/codegen/FunctionGenTest.java @@ -16,15 +16,9 @@ package org.jetbrains.jet.codegen; -import com.intellij.openapi.util.io.FileUtil; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.jet.CompileCompilerDependenciesTest; import org.jetbrains.jet.ConfigurationKind; -import org.jetbrains.jet.JetTestUtils; -import org.jetbrains.jet.TestJdkKind; -import org.jetbrains.jet.cli.jvm.compiler.JetCoreEnvironment; -import java.io.File; +import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; @@ -89,6 +83,19 @@ public class FunctionGenTest extends CodegenTestCase { assertFalse((Boolean) foo.invoke(null, "mama")); } + public void testNoRefToOuter() throws InvocationTargetException, IllegalAccessException, NoSuchMethodException, InstantiationException { + loadText("class A() { fun f() : ()->String { val s = \"OK\"; return { -> s } } }"); + // System.out.println(generateToText()); + Class foo = generateClass("A"); + final Object obj = foo.newInstance(); + final Method f = foo.getMethod("f"); + final Object closure = f.invoke(obj); + final Class aClass = closure.getClass(); + final Field[] fields = aClass.getFields(); + assertEquals(1, fields.length); + assertEquals("$s", fields[0].getName()); + } + public void testAnyEquals() throws InvocationTargetException, IllegalAccessException { loadText("fun foo(x: Any) = x.equals(\"lala\")"); // System.out.println(generateToText()); @@ -115,6 +122,7 @@ public class FunctionGenTest extends CodegenTestCase { public void testKt1199() { blackBoxFile("regressions/kt1199.kt"); + System.out.println(generateToText()); } public void testFunction() throws InvocationTargetException, IllegalAccessException { diff --git a/compiler/tests/org/jetbrains/jet/codegen/LocalClassGenTest.java b/compiler/tests/org/jetbrains/jet/codegen/LocalClassGenTest.java index 3d56d679165..2800730b9fa 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/LocalClassGenTest.java +++ b/compiler/tests/org/jetbrains/jet/codegen/LocalClassGenTest.java @@ -33,7 +33,7 @@ public class LocalClassGenTest extends CodegenTestCase { } public void testWithClosure() { - //blackBoxFile("localcls/withclosure.kt"); + blackBoxFile("localcls/withclosure.kt"); } public void testEnum() { diff --git a/injector-generator/src/org/jetbrains/jet/di/AllInjectorsGenerator.java b/injector-generator/src/org/jetbrains/jet/di/AllInjectorsGenerator.java index 3f018c3f561..77f39e0feef 100644 --- a/injector-generator/src/org/jetbrains/jet/di/AllInjectorsGenerator.java +++ b/injector-generator/src/org/jetbrains/jet/di/AllInjectorsGenerator.java @@ -18,6 +18,7 @@ package org.jetbrains.jet.di; import com.intellij.openapi.project.Project; import org.jetbrains.jet.codegen.*; +import org.jetbrains.jet.codegen.context.ClosureAnnotator; import org.jetbrains.jet.codegen.intrinsics.IntrinsicMethods; import org.jetbrains.jet.lang.BuiltinsScopeExtensionMode; import org.jetbrains.jet.lang.ModuleConfiguration; @@ -163,15 +164,15 @@ public class AllInjectorsGenerator { generator.generate("compiler/tests", "org.jetbrains.jet.di", "InjectorForTests"); } - + private static void generateInjectorForJavaSemanticServices() throws IOException { DependencyInjectorGenerator generator = new DependencyInjectorGenerator(false); - + // Fields generator.addPublicField(JavaSemanticServices.class); generator.addPublicField(JavaDescriptorResolver.class); generator.addField(true, BindingTrace.class, null, - new GivenExpression("new org.jetbrains.jet.lang.resolve.BindingTraceContext()")); + new GivenExpression("new org.jetbrains.jet.lang.resolve.BindingTraceContext()")); generator.addField(JavaBridgeConfiguration.class); generator.addPublicField(PsiClassFinderImpl.class); generator.addField(false, ModuleDescriptor.class, null, @@ -181,7 +182,7 @@ public class AllInjectorsGenerator { // Parameters generator.addPublicParameter(Project.class); - + generator.generate("compiler/frontend.java/src", "org.jetbrains.jet.di", "InjectorForJavaSemanticServices"); } @@ -226,5 +227,4 @@ public class AllInjectorsGenerator { generator.addPublicParameter(BodiesResolveContext.class); generator.generate("compiler/frontend/src", "org.jetbrains.jet.di", "InjectorForBodyResolve"); } - }