refactoring in progress

This commit is contained in:
Alex Tkachman
2012-02-27 22:59:34 +02:00
parent 1610e7eefd
commit 9ba1dbf98a
21 changed files with 396 additions and 209 deletions
@@ -37,9 +37,6 @@ public class ClassCodegen {
public void generate(CodegenContext context, JetClassOrObject aClass) { public void generate(CodegenContext context, JetClassOrObject aClass) {
ClassDescriptor descriptor = state.getBindingContext().get(BindingContext.CLASS, aClass); ClassDescriptor descriptor = state.getBindingContext().get(BindingContext.CLASS, aClass);
ClassBuilder classBuilder = state.forClassImplementation(descriptor); ClassBuilder classBuilder = state.forClassImplementation(descriptor);
if (classBuilder.generateCode()) {
GenerationState.prepareAnonymousClasses(aClass, state.getTypeMapper());
}
final CodegenContext contextForInners = context.intoClass(descriptor, OwnerKind.IMPLEMENTATION, state.getTypeMapper()); final CodegenContext contextForInners = context.intoClass(descriptor, OwnerKind.IMPLEMENTATION, state.getTypeMapper());
@@ -0,0 +1,288 @@
/*
* Copyright 2000-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 com.intellij.util.containers.MultiMap;
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.java.JvmAbi;
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
import org.jetbrains.jet.lang.types.JetStandardClasses;
import java.util.*;
/**
* @author alex.tkachman
*/
public class ClosureAnnotator {
private final Map<JetElement, String> classNamesForAnonymousClasses = new HashMap<JetElement, String>();
private final Map<ClassDescriptor, String> classNamesForClassDescriptor = new HashMap<ClassDescriptor, String>();
private final Map<String, Integer> anonymousSubclassesCount = new HashMap<String, Integer>();
private final Map<FunctionDescriptor, ClassDescriptorImpl> classesForFunctions = new HashMap<FunctionDescriptor, ClassDescriptorImpl>();
private final Map<DeclarationDescriptor,ClassDescriptor> enclosing = new HashMap<DeclarationDescriptor, ClassDescriptor>();
private final MultiMap<String,JetFile> namespaceName2Files = MultiMap.create();
private final BindingContext bindingContext;
public ClosureAnnotator(BindingContext bindingContext, Collection<JetFile> files) {
this.bindingContext = bindingContext;
mapFilesToNamespaces(files);
prepareAnonymousClasses();
}
public ClassDescriptor classDescriptorForFunctionDescriptor(FunctionDescriptor funDescriptor, String name) {
ClassDescriptorImpl classDescriptor = classesForFunctions.get(funDescriptor);
if(classDescriptor == null) {
int arity = funDescriptor.getValueParameters().size();
classDescriptor = new ClassDescriptorImpl(
funDescriptor,
Collections.<AnnotationDescriptor>emptyList(),
name);
classDescriptor.initialize(
false,
Collections.<TypeParameterDescriptor>emptyList(),
Collections.singleton((funDescriptor.getReceiverParameter().exists() ? JetStandardClasses.getReceiverFunction(arity) : JetStandardClasses.getFunction(arity)).getDefaultType()), JetScope.EMPTY, Collections.<ConstructorDescriptor>emptySet(), null);
classesForFunctions.put(funDescriptor, classDescriptor);
}
return classDescriptor;
}
private void mapFilesToNamespaces(Collection<JetFile> files) {
for (JetFile file : files) {
String fqName = JetPsiUtil.getFQName(file);
namespaceName2Files.putValue(fqName, file);
}
}
private void prepareAnonymousClasses() {
MyJetVisitorVoid visitor = new MyJetVisitorVoid();
for (Map.Entry<String,Collection<JetFile>> entry : namespaceName2Files.entrySet()) {
for (JetFile jetFile : entry.getValue()) {
jetFile.accept(visitor);
}
}
}
public String classNameForAnonymousClass(JetElement expression) {
if(expression instanceof JetObjectLiteralExpression) {
JetObjectLiteralExpression jetObjectLiteralExpression = (JetObjectLiteralExpression) expression;
expression = jetObjectLiteralExpression.getObjectDeclaration();
}
if(expression instanceof JetFunctionLiteralExpression) {
JetFunctionLiteralExpression jetFunctionLiteralExpression = (JetFunctionLiteralExpression) expression;
expression = jetFunctionLiteralExpression.getFunctionLiteral();
}
String name = classNamesForAnonymousClasses.get(expression);
assert name != null;
return name;
}
public ClassDescriptor getEclosingClassDescriptor(ClassDescriptor descriptor) {
return enclosing.get(descriptor);
}
public boolean hasThis0(ClassDescriptor classDescriptor) {
if(CodegenUtil.isClassObject(classDescriptor))
return false;
ClassDescriptor other = enclosing.get(classDescriptor);
return other != null;
}
private class MyJetVisitorVoid extends JetVisitorVoid {
private LinkedList<ClassDescriptor> classStack = new LinkedList<ClassDescriptor>();
private LinkedList<String> nameStack = new LinkedList<String>();
private void recordEnclosing(ClassDescriptor classDescriptor) {
if(classStack.size() > 0) {
ClassDescriptor put = enclosing.put(classDescriptor, classStack.peek());
assert put == null;
}
}
private String recordAnonymousClass(JetElement declaration) {
String name = classNamesForAnonymousClasses.get(declaration);
assert name == null;
String top = nameStack.peek();
Integer cnt = anonymousSubclassesCount.get(top);
if(cnt == null) {
cnt = 0;
}
name = top + "$" + (cnt + 1);
classNamesForAnonymousClasses.put(declaration, name);
anonymousSubclassesCount.put(top, cnt + 1);
return name;
}
private String recordClassObject(JetClassObject declaration) {
String name = classNamesForAnonymousClasses.get(declaration.getObjectDeclaration());
assert name == null;
name = nameStack.peek() + JvmAbi.CLASS_OBJECT_SUFFIX;
classNamesForAnonymousClasses.put(declaration.getObjectDeclaration(), name);
return name;
}
@Override
public void visitJetElement(JetElement element) {
super.visitJetElement(element);
element.acceptChildren(this);
}
@Override
public void visitJetFile(JetFile file) {
nameStack.push(JetPsiUtil.getFQName(file).replace('.', '/'));
file.acceptChildren(this);
nameStack.pop();
}
@Override
public void visitClassObject(JetClassObject classObject) {
String name = recordClassObject(classObject);
ClassDescriptor classDescriptor = bindingContext.get(BindingContext.CLASS, classObject.getObjectDeclaration());
recordEnclosing(classDescriptor);
recordName(classDescriptor, name);
classStack.push(classDescriptor);
nameStack.push(name);
super.visitClassObject(classObject);
nameStack.pop();
classStack.pop();
}
@Override
public void visitObjectDeclaration(JetObjectDeclaration declaration) {
if(declaration.getParent() instanceof JetObjectLiteralExpression || declaration.getParent() instanceof JetClassObject) {
super.visitObjectDeclaration(declaration);
}
else {
ClassDescriptor classDescriptor = bindingContext.get(BindingContext.CLASS, declaration);
recordEnclosing(classDescriptor);
classStack.push(classDescriptor);
String base = nameStack.peek();
if(classDescriptor.getContainingDeclaration() instanceof NamespaceDescriptor) {
nameStack.push(base.isEmpty() ? classDescriptor.getName() : base + '/' + classDescriptor.getName());
}
else
nameStack.push(base + '$' + classDescriptor.getName());
super.visitObjectDeclaration(declaration);
nameStack.pop();
classStack.pop();
}
}
@Override
public void visitClass(JetClass klass) {
ClassDescriptor classDescriptor = bindingContext.get(BindingContext.CLASS, klass);
recordEnclosing(classDescriptor);
classStack.push(classDescriptor);
String base = nameStack.peek();
if(classDescriptor.getContainingDeclaration() instanceof NamespaceDescriptor) {
nameStack.push(base.isEmpty() ? classDescriptor.getName() : base + '/' + classDescriptor.getName());
}
else
nameStack.push(base + '$' + classDescriptor.getName());
super.visitClass(klass);
nameStack.pop();
classStack.pop();
}
@Override
public void visitObjectLiteralExpression(JetObjectLiteralExpression expression) {
String name = recordAnonymousClass(expression.getObjectDeclaration());
ClassDescriptor classDescriptor = bindingContext.get(BindingContext.CLASS, expression.getObjectDeclaration());
recordName(classDescriptor, name);
recordEnclosing(classDescriptor);
classStack.push(classDescriptor);
nameStack.push(classNameForClassDescriptor(classDescriptor));
super.visitObjectLiteralExpression(expression);
nameStack.pop();
classStack.pop();
}
@Override
public void visitFunctionLiteralExpression(JetFunctionLiteralExpression expression) {
String name = recordAnonymousClass(expression.getFunctionLiteral());
FunctionDescriptor declarationDescriptor = (FunctionDescriptor) bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, expression);
ClassDescriptor classDescriptor = classDescriptorForFunctionDescriptor(declarationDescriptor, name);
recordName(classDescriptor, name);
recordEnclosing(classDescriptor);
classStack.push(classDescriptor);
nameStack.push(classNameForClassDescriptor(classDescriptor));
super.visitFunctionLiteralExpression(expression);
nameStack.pop();
classStack.pop();
}
private void recordName(ClassDescriptor classDescriptor, String name) {
String old = classNamesForClassDescriptor.put(classDescriptor, name);
assert old == null;
}
@Override
public void visitProperty(JetProperty property) {
nameStack.push(nameStack.peek() + '$' + property.getName());
super.visitProperty(property);
nameStack.pop();
}
@Override
public void visitNamedFunction(JetNamedFunction function) {
FunctionDescriptor functionDescriptor = (FunctionDescriptor) bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, function);
DeclarationDescriptor containingDeclaration = functionDescriptor.getContainingDeclaration();
if (containingDeclaration instanceof ClassDescriptor) {
nameStack.push(nameStack.peek() + '$' + function.getName());
super.visitNamedFunction(function);
nameStack.pop();
}
else if (containingDeclaration instanceof NamespaceDescriptor) {
String peek = nameStack.peek();
if(peek.isEmpty())
peek = "namespace";
else
peek = peek + "/namespace";
nameStack.push(peek + '$' + function.getName());
super.visitNamedFunction(function);
nameStack.pop();
}
else {
String name = recordAnonymousClass(function);
ClassDescriptor classDescriptor = classDescriptorForFunctionDescriptor(functionDescriptor, name);
recordName(classDescriptor, name);
recordEnclosing(classDescriptor);
classStack.push(classDescriptor);
nameStack.push(name);
super.visitNamedFunction(function);
nameStack.pop();
classStack.pop();
}
}
}
public String classNameForClassDescriptor(ClassDescriptor classDescriptor) {
String name = classNamesForClassDescriptor.get(classDescriptor);
assert name != null;
return name;
}
}
@@ -23,12 +23,10 @@ package org.jetbrains.jet.codegen;
import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.Pair;
import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElement;
import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
import org.jetbrains.jet.lang.psi.JetDeclarationWithBody; import org.jetbrains.jet.lang.psi.JetDeclarationWithBody;
import org.jetbrains.jet.lang.psi.JetElement; import org.jetbrains.jet.lang.psi.JetElement;
import org.jetbrains.jet.lang.psi.JetExpression; import org.jetbrains.jet.lang.psi.JetExpression;
import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor; import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor;
import org.jetbrains.jet.lang.types.JetStandardClasses; import org.jetbrains.jet.lang.types.JetStandardClasses;
import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lang.types.JetType;
@@ -40,7 +38,6 @@ import org.objectweb.asm.commons.Method;
import org.objectweb.asm.signature.SignatureWriter; import org.objectweb.asm.signature.SignatureWriter;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
import static org.objectweb.asm.Opcodes.*; import static org.objectweb.asm.Opcodes.*;
@@ -136,11 +133,11 @@ public class ClosureCodegen extends ObjectOrClosureCodegen {
ClassDescriptor thisDescriptor = context.getThisDescriptor(); ClassDescriptor thisDescriptor = context.getThisDescriptor();
final Type enclosingType = thisDescriptor == null ? null : state.getTypeMapper().mapType(thisDescriptor.getDefaultType()); final Type enclosingType = thisDescriptor == null ? null : state.getTypeMapper().mapType(thisDescriptor.getDefaultType());
if (enclosingType == null) if (enclosingType == null)
captureThis = false; captureThis = null;
final Method constructor = generateConstructor(funClass, fun); final Method constructor = generateConstructor(funClass, fun);
if (captureThis) { if (captureThis != null) {
cv.newField(fun, ACC_FINAL, "this$0", enclosingType.getDescriptor(), null, null); cv.newField(fun, ACC_FINAL, "this$0", enclosingType.getDescriptor(), null, null);
} }
@@ -189,17 +186,8 @@ public class ClosureCodegen extends ObjectOrClosureCodegen {
} }
} }
private boolean generateBody(FunctionDescriptor funDescriptor, ClassBuilder cv, JetDeclarationWithBody body) { private Type generateBody(FunctionDescriptor funDescriptor, ClassBuilder cv, JetDeclarationWithBody body) {
int arity = funDescriptor.getValueParameters().size(); ClassDescriptor function = state.getTypeMapper().getClosureAnnotator().classDescriptorForFunctionDescriptor(funDescriptor, name);
ClassDescriptorImpl function = new ClassDescriptorImpl(
funDescriptor,
Collections.<AnnotationDescriptor>emptyList(),
name);
function = function.initialize(
false,
Collections.<TypeParameterDescriptor>emptyList(),
Collections.singleton((funDescriptor.getReceiverParameter().exists() ? JetStandardClasses.getReceiverFunction(arity) : JetStandardClasses.getFunction(arity)).getDefaultType()), JetScope.EMPTY, Collections.<ConstructorDescriptor>emptySet(), null);
final CodegenContext.ClosureContext closureContext = context.intoClosure(funDescriptor, function, name, this, state.getTypeMapper()); final CodegenContext.ClosureContext closureContext = context.intoClosure(funDescriptor, function, name, this, state.getTypeMapper());
FunctionCodegen fc = new FunctionCodegen(closureContext, cv, state); FunctionCodegen fc = new FunctionCodegen(closureContext, cv, state);
@@ -248,7 +236,7 @@ public class ClosureCodegen extends ObjectOrClosureCodegen {
} }
private Method generateConstructor(String funClass, PsiElement fun) { private Method generateConstructor(String funClass, PsiElement fun) {
int argCount = captureThis ? 1 : 0; int argCount = captureThis != null ? 1 : 0;
argCount += (captureReceiver != null ? 1 : 0); argCount += (captureReceiver != null ? 1 : 0);
ArrayList<DeclarationDescriptor> variableDescriptors = new ArrayList<DeclarationDescriptor>(); ArrayList<DeclarationDescriptor> variableDescriptors = new ArrayList<DeclarationDescriptor>();
@@ -270,7 +258,7 @@ public class ClosureCodegen extends ObjectOrClosureCodegen {
Type[] argTypes = new Type[argCount]; Type[] argTypes = new Type[argCount];
int i = 0; int i = 0;
if (captureThis) { if (captureThis != null) {
argTypes[i++] = state.getTypeMapper().mapType(context.getThisDescriptor().getDefaultType()); argTypes[i++] = state.getTypeMapper().mapType(context.getThisDescriptor().getDefaultType());
} }
@@ -285,7 +273,7 @@ public class ClosureCodegen extends ObjectOrClosureCodegen {
argTypes[i++] = type; argTypes[i++] = type;
} }
else if(CodegenUtil.isNamedFun(descriptor, state.getBindingContext()) && descriptor.getContainingDeclaration() instanceof FunctionDescriptor) { else if(CodegenUtil.isNamedFun(descriptor, state.getBindingContext()) && descriptor.getContainingDeclaration() instanceof FunctionDescriptor) {
final Type type = Type.getObjectType(state.getTypeMapper().classNameForAnonymousClass((JetElement) bindingContext.get(BindingContext.DESCRIPTOR_TO_DECLARATION, descriptor))); final Type type = Type.getObjectType(state.getTypeMapper().getClosureAnnotator().classNameForAnonymousClass((JetElement) bindingContext.get(BindingContext.DESCRIPTOR_TO_DECLARATION, descriptor)));
argTypes[i++] = type; argTypes[i++] = type;
} }
} }
@@ -304,11 +292,11 @@ public class ClosureCodegen extends ObjectOrClosureCodegen {
StackValue.local(0, JetTypeMapper.TYPE_OBJECT).put(JetTypeMapper.TYPE_OBJECT, iv); StackValue.local(0, JetTypeMapper.TYPE_OBJECT).put(JetTypeMapper.TYPE_OBJECT, iv);
StackValue.local(i, type).put(type, iv); StackValue.local(i, type).put(type, iv);
final String fieldName; final String fieldName;
if (captureThis && i == 1) { if (captureThis != null && i == 1) {
fieldName = "this$0"; fieldName = "this$0";
} }
else { else {
if (captureReceiver != null && (captureThis && i == 2 || !captureThis && i == 1)) { if (captureReceiver != null && (captureThis != null && i == 2 || captureThis == null && i == 1)) {
fieldName = "receiver$0"; fieldName = "receiver$0";
} }
else { else {
@@ -68,7 +68,7 @@ public abstract class CodegenContext {
protected StackValue outerExpression; protected StackValue outerExpression;
protected boolean outerWasUsed ; protected Type outerWasUsed ;
public CodegenContext(DeclarationDescriptor contextType, OwnerKind contextKind, @Nullable CodegenContext parentContext, @Nullable ObjectOrClosureCodegen closureCodegen) { public CodegenContext(DeclarationDescriptor contextType, OwnerKind contextKind, @Nullable CodegenContext parentContext, @Nullable ObjectOrClosureCodegen closureCodegen) {
this.contextType = contextType; this.contextType = contextType;
@@ -100,7 +100,7 @@ public abstract class CodegenContext {
if(outerExpression == null) if(outerExpression == null)
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
outerWasUsed = true; outerWasUsed = outerExpression.type;
return prefix != null ? StackValue.composed(prefix, outerExpression) : outerExpression; return prefix != null ? StackValue.composed(prefix, outerExpression) : outerExpression;
} }
@@ -59,21 +59,6 @@ public class CodegenUtil {
return false; return false;
} }
public static boolean hasThis0(ClassDescriptor classDescriptor) {
return getOuterClassDescriptor(classDescriptor) != null && !isClassObject(classDescriptor);
}
public static ClassDescriptor getOuterClassDescriptor(DeclarationDescriptor descriptor) {
DeclarationDescriptor outerDescriptor = descriptor.getContainingDeclaration();
while(outerDescriptor != null) {
if(outerDescriptor instanceof ClassDescriptor)
break;
outerDescriptor = outerDescriptor.getContainingDeclaration();
}
return (ClassDescriptor) outerDescriptor;
}
public static SimpleFunctionDescriptor createInvoke(FunctionDescriptor fd) { public static SimpleFunctionDescriptor createInvoke(FunctionDescriptor fd) {
int arity = fd.getValueParameters().size(); int arity = fd.getValueParameters().size();
SimpleFunctionDescriptorImpl invokeDescriptor = new SimpleFunctionDescriptorImpl( SimpleFunctionDescriptorImpl invokeDescriptor = new SimpleFunctionDescriptorImpl(
@@ -17,7 +17,6 @@
package org.jetbrains.jet.codegen; package org.jetbrains.jet.codegen;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
import org.jetbrains.jet.lang.descriptors.ConstructorDescriptor; import org.jetbrains.jet.lang.descriptors.ConstructorDescriptor;
import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor; import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
import org.objectweb.asm.Type; import org.objectweb.asm.Type;
@@ -33,10 +32,10 @@ public class ConstructorFrameMap extends FrameMap {
private int myOuterThisIndex = -1; private int myOuterThisIndex = -1;
private int myTypeInfoIndex = -1; private int myTypeInfoIndex = -1;
public ConstructorFrameMap(CallableMethod callableMethod, @Nullable ConstructorDescriptor descriptor, ClassDescriptor classDescriptor, OwnerKind kind) { public ConstructorFrameMap(CallableMethod callableMethod, @Nullable ConstructorDescriptor descriptor, boolean hasThis0) {
enterTemp(); // this enterTemp(); // this
if (descriptor != null) { if (descriptor != null) {
if (CodegenUtil.hasThis0(classDescriptor)) { if (hasThis0) {
myOuterThisIndex = enterTemp(); // outer class instance myOuterThisIndex = enterTemp(); // outer class instance
} }
} }
@@ -809,7 +809,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
if(closureCodegen.superCall != null) { if(closureCodegen.superCall != null) {
ConstructorDescriptor superConstructor = (ConstructorDescriptor) bindingContext.get(BindingContext.REFERENCE_TARGET, closureCodegen.superCall.getCalleeExpression().getConstructorReferenceExpression()); ConstructorDescriptor superConstructor = (ConstructorDescriptor) bindingContext.get(BindingContext.REFERENCE_TARGET, closureCodegen.superCall.getCalleeExpression().getConstructorReferenceExpression());
CallableMethod superCallable = typeMapper.mapToCallableMethod(superConstructor, OwnerKind.IMPLEMENTATION); CallableMethod superCallable = typeMapper.mapToCallableMethod(superConstructor, OwnerKind.IMPLEMENTATION, typeMapper.hasThis0(superConstructor.getContainingDeclaration()));
Type[] argumentTypes = superCallable.getSignature().getAsmMethod().getArgumentTypes(); Type[] argumentTypes = superCallable.getSignature().getAsmMethod().getArgumentTypes();
Collections.addAll(consArgTypes, argumentTypes); Collections.addAll(consArgTypes, argumentTypes);
ResolvedCall resolvedCall = bindingContext.get(BindingContext.RESOLVED_CALL, closureCodegen.superCall.getCalleeExpression()); ResolvedCall resolvedCall = bindingContext.get(BindingContext.RESOLVED_CALL, closureCodegen.superCall.getCalleeExpression());
@@ -2258,7 +2258,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
receiver.put(receiver.type, v); receiver.put(receiver.type, v);
} }
CallableMethod method = typeMapper.mapToCallableMethod((ConstructorDescriptor) constructorDescriptor, OwnerKind.IMPLEMENTATION); CallableMethod method = typeMapper.mapToCallableMethod((ConstructorDescriptor) constructorDescriptor, OwnerKind.IMPLEMENTATION, typeMapper.hasThis0(((ConstructorDescriptor) constructorDescriptor).getContainingDeclaration()));
invokeMethodWithArguments(method, expression, StackValue.none()); invokeMethodWithArguments(method, expression, StackValue.none());
} }
} }
@@ -28,11 +28,11 @@ import java.util.List;
public class GeneratedAnonymousClassDescriptor { public class GeneratedAnonymousClassDescriptor {
private final String classname; private final String classname;
private Method constructor; private Method constructor;
private final boolean captureThis; private final Type captureThis;
private final Type captureReceiver; private final Type captureReceiver;
private List<StackValue> args = new ArrayList<StackValue>(); private List<StackValue> args = new ArrayList<StackValue>();
public GeneratedAnonymousClassDescriptor(String classname, Method constructor, boolean captureThis, Type captureReceiver) { public GeneratedAnonymousClassDescriptor(String classname, Method constructor, Type captureThis, Type captureReceiver) {
this.classname = classname; this.classname = classname;
this.constructor = constructor; this.constructor = constructor;
this.captureThis = captureThis; this.captureThis = captureThis;
@@ -56,7 +56,7 @@ public class GeneratedAnonymousClassDescriptor {
} }
public boolean isCaptureThis() { public boolean isCaptureThis() {
return captureThis; return captureThis != null;
} }
public Type isCaptureReceiver() { public Type isCaptureReceiver() {
@@ -22,7 +22,6 @@ package org.jetbrains.jet.codegen;
import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.project.Project; import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.Pair;
import com.intellij.psi.PsiElement;
import com.intellij.util.containers.Stack; import com.intellij.util.containers.Stack;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.codegen.intrinsics.IntrinsicMethods; import org.jetbrains.jet.codegen.intrinsics.IntrinsicMethods;
@@ -102,7 +101,7 @@ public class GenerationState {
} }
public Pair<String, ClassBuilder> forAnonymousSubclass(JetExpression expression) { public Pair<String, ClassBuilder> forAnonymousSubclass(JetExpression expression) {
String className = typeMapper.classNameForAnonymousClass(expression); String className = typeMapper.getClosureAnnotator().classNameForAnonymousClass(expression);
return Pair.create(className, factory.forAnonymousSubclass(className)); return Pair.create(className, factory.forAnonymousSubclass(className));
} }
@@ -113,7 +112,7 @@ public class GenerationState {
public BindingContext compile(JetFile file) { public BindingContext compile(JetFile file) {
final BindingContext bindingContext = AnalyzerFacade.analyzeOneFileWithJavaIntegration(file, JetControlFlowDataTraceFactory.EMPTY); final BindingContext bindingContext = AnalyzerFacade.analyzeOneFileWithJavaIntegration(file, JetControlFlowDataTraceFactory.EMPTY);
AnalyzingUtils.throwExceptionOnErrors(bindingContext); AnalyzingUtils.throwExceptionOnErrors(bindingContext);
compileCorrectFiles(bindingContext, Collections.singletonList(file)); compileCorrectFiles(bindingContext, Collections.singletonList(file), CompilationErrorHandler.THROW_EXCEPTION, true);
return bindingContext; return bindingContext;
// NamespaceCodegen codegen = forNamespace(namespace); // NamespaceCodegen codegen = forNamespace(namespace);
// bindingContexts.push(bindingContext); // bindingContexts.push(bindingContext);
@@ -129,12 +128,13 @@ public class GenerationState {
// } // }
} }
public void compileCorrectFiles(BindingContext bindingContext, List<JetFile> files) { public void compileCorrectFiles(BindingContext bindingContext, List<JetFile> files, boolean annotate) {
compileCorrectFiles(bindingContext, files, CompilationErrorHandler.THROW_EXCEPTION); compileCorrectFiles(bindingContext, files, CompilationErrorHandler.THROW_EXCEPTION, annotate);
} }
public void compileCorrectFiles(BindingContext bindingContext, List<JetFile> files, CompilationErrorHandler errorHandler) { public void compileCorrectFiles(BindingContext bindingContext, List<JetFile> files, CompilationErrorHandler errorHandler, boolean annotate) {
typeMapper = new JetTypeMapper(standardLibrary, bindingContext); ClosureAnnotator closureAnnotator = !annotate ? null : new ClosureAnnotator(bindingContext, files);
typeMapper = new JetTypeMapper(standardLibrary, bindingContext, closureAnnotator);
bindingContexts.push(bindingContext); bindingContexts.push(bindingContext);
try { try {
for (JetFile namespace : files) { for (JetFile namespace : files) {
@@ -172,30 +172,10 @@ public class GenerationState {
new ImplementationBodyCodegen(objectDeclaration, objectContext, nameAndVisitor.getSecond(), this).generate(); new ImplementationBodyCodegen(objectDeclaration, objectContext, nameAndVisitor.getSecond(), this).generate();
ConstructorDescriptor constructorDescriptor = closure.state.getBindingContext().get(BindingContext.CONSTRUCTOR, objectDeclaration); ConstructorDescriptor constructorDescriptor = closure.state.getBindingContext().get(BindingContext.CONSTRUCTOR, objectDeclaration);
CallableMethod callableMethod = closure.state.getTypeMapper().mapToCallableMethod(constructorDescriptor, OwnerKind.IMPLEMENTATION); CallableMethod callableMethod = closure.state.getTypeMapper().mapToCallableMethod(constructorDescriptor, OwnerKind.IMPLEMENTATION, typeMapper.hasThis0(constructorDescriptor.getContainingDeclaration()));
return new GeneratedAnonymousClassDescriptor(nameAndVisitor.first, callableMethod.getSignature().getAsmMethod(), objectContext.outerWasUsed, null); return new GeneratedAnonymousClassDescriptor(nameAndVisitor.first, callableMethod.getSignature().getAsmMethod(), objectContext.outerWasUsed, null);
} }
public static void prepareAnonymousClasses(PsiElement element, final JetTypeMapper typeMapper) {
element.acceptChildren(new JetVisitorVoid() {
@Override
public void visitJetElement(JetElement element) {
super.visitJetElement(element);
element.acceptChildren(this);
}
@Override
public void visitObjectLiteralExpression(JetObjectLiteralExpression expression) {
typeMapper.classNameForAnonymousClass(expression.getObjectDeclaration());
}
@Override
public void visitFunctionLiteralExpression(JetFunctionLiteralExpression expression) {
typeMapper.classNameForAnonymousClass(expression.getFunctionLiteral());
}
});
}
public String createText() { public String createText() {
StringBuilder answer = new StringBuilder(); StringBuilder answer = new StringBuilder();
@@ -403,6 +403,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
JvmMethodSignature constructorMethod; JvmMethodSignature constructorMethod;
CallableMethod callableMethod; CallableMethod callableMethod;
boolean hasThis0 = typeMapper.hasThis0(descriptor);
if (constructorDescriptor == null) { if (constructorDescriptor == null) {
BothSignatureWriter signatureWriter = new BothSignatureWriter(BothSignatureWriter.Mode.METHOD, false); BothSignatureWriter signatureWriter = new BothSignatureWriter(BothSignatureWriter.Mode.METHOD, false);
@@ -411,9 +412,9 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
signatureWriter.writeParametersStart(); signatureWriter.writeParametersStart();
if (CodegenUtil.hasThis0(descriptor)) { if (hasThis0) {
signatureWriter.writeParameterType(JvmMethodParameterKind.THIS0); signatureWriter.writeParameterType(JvmMethodParameterKind.THIS0);
typeMapper.mapType(CodegenUtil.getOuterClassDescriptor(descriptor).getDefaultType(), OwnerKind.IMPLEMENTATION, signatureWriter, false); typeMapper.mapType(typeMapper.getClosureAnnotator().getEclosingClassDescriptor(descriptor).getDefaultType(), OwnerKind.IMPLEMENTATION, signatureWriter, false);
signatureWriter.writeParameterTypeEnd(); signatureWriter.writeParameterTypeEnd();
} }
@@ -425,7 +426,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
callableMethod = new CallableMethod("", "", "", constructorMethod, INVOKESPECIAL); callableMethod = new CallableMethod("", "", "", constructorMethod, INVOKESPECIAL);
} }
else { else {
callableMethod = typeMapper.mapToCallableMethod(constructorDescriptor, kind); callableMethod = typeMapper.mapToCallableMethod(constructorDescriptor, kind, typeMapper.hasThis0(constructorDescriptor.getContainingDeclaration()));
constructorMethod = callableMethod.getSignature(); constructorMethod = callableMethod.getSignature();
} }
@@ -435,13 +436,13 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
int insert = 0; int insert = 0;
if(closure != null) { if(closure != null) {
if(closure.captureThis) { if(closure.captureThis != null) {
if(!CodegenUtil.hasThis0(descriptor)) if(!hasThis0)
consArgTypes.add(insert, new JvmMethodParameterSignature(Type.getObjectType(context.getThisDescriptor().getName()), "", JvmMethodParameterKind.THIS0)); consArgTypes.add(insert, new JvmMethodParameterSignature(Type.getObjectType(context.getThisDescriptor().getName()), "", JvmMethodParameterKind.THIS0));
insert++; insert++;
} }
else { else {
if(CodegenUtil.hasThis0(descriptor)) if(hasThis0)
insert++; insert++;
} }
@@ -469,7 +470,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
declarationDescriptor = ((ClassDescriptor)declarationDescriptor).getUnsubstitutedPrimaryConstructor(); declarationDescriptor = ((ClassDescriptor)declarationDescriptor).getUnsubstitutedPrimaryConstructor();
} }
ConstructorDescriptor superConstructor = (ConstructorDescriptor) declarationDescriptor; ConstructorDescriptor superConstructor = (ConstructorDescriptor) declarationDescriptor;
CallableMethod superCallable = typeMapper.mapToCallableMethod(superConstructor, OwnerKind.IMPLEMENTATION); CallableMethod superCallable = typeMapper.mapToCallableMethod(superConstructor, OwnerKind.IMPLEMENTATION, typeMapper.hasThis0(superConstructor.getContainingDeclaration()));
firstSuperArgument = insert; firstSuperArgument = insert;
for(Type t : superCallable.getSignature().getAsmMethod().getArgumentTypes()) { for(Type t : superCallable.getSignature().getAsmMethod().getArgumentTypes()) {
consArgTypes.add(insert++, new JvmMethodParameterSignature(t, "", JvmMethodParameterKind.SHARED_VAR)); consArgTypes.add(insert++, new JvmMethodParameterSignature(t, "", JvmMethodParameterKind.SHARED_VAR));
@@ -494,7 +495,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
if (constructorDescriptor != null) { if (constructorDescriptor != null) {
int i = 0; int i = 0;
if (CodegenUtil.hasThis0(descriptor)) { if (hasThis0) {
i++; i++;
} }
@@ -514,7 +515,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
? constructorDescriptor.getValueParameters() ? constructorDescriptor.getValueParameters()
: Collections.<ValueParameterDescriptor>emptyList(); : Collections.<ValueParameterDescriptor>emptyList();
ConstructorFrameMap frameMap = new ConstructorFrameMap(callableMethod, constructorDescriptor, descriptor, kind); ConstructorFrameMap frameMap = new ConstructorFrameMap(callableMethod, constructorDescriptor, hasThis0);
final InstructionAdapter iv = new InstructionAdapter(mv); final InstructionAdapter iv = new InstructionAdapter(mv);
ExpressionCodegen codegen = new ExpressionCodegen(mv, frameMap, Type.VOID_TYPE, constructorContext, state); ExpressionCodegen codegen = new ExpressionCodegen(mv, frameMap, Type.VOID_TYPE, constructorContext, state);
@@ -548,9 +549,9 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
List<Type> parameterTypes = new ArrayList<Type>(); List<Type> parameterTypes = new ArrayList<Type>();
assert superType != null; assert superType != null;
ClassDescriptor superClassDescriptor = (ClassDescriptor) superType.getConstructor().getDeclarationDescriptor(); ClassDescriptor superClassDescriptor = (ClassDescriptor) superType.getConstructor().getDeclarationDescriptor();
if (CodegenUtil.hasThis0(superClassDescriptor)) { if (typeMapper.hasThis0(superClassDescriptor)) {
iv.load(1, JetTypeMapper.TYPE_OBJECT); iv.load(1, JetTypeMapper.TYPE_OBJECT);
parameterTypes.add(typeMapper.mapType(CodegenUtil.getOuterClassDescriptor(descriptor).getDefaultType(), OwnerKind.IMPLEMENTATION)); parameterTypes.add(typeMapper.mapType(typeMapper.getClosureAnnotator().getEclosingClassDescriptor(descriptor).getDefaultType(), OwnerKind.IMPLEMENTATION));
} }
Method superCallMethod = new Method("<init>", Type.VOID_TYPE, parameterTypes.toArray(new Type[parameterTypes.size()])); Method superCallMethod = new Method("<init>", Type.VOID_TYPE, parameterTypes.toArray(new Type[parameterTypes.size()]));
iv.invokespecial(typeMapper.mapType(superClassDescriptor.getDefaultType(), OwnerKind.IMPLEMENTATION).getInternalName(), "<init>", superCallMethod.getDescriptor()); iv.invokespecial(typeMapper.mapType(superClassDescriptor.getDefaultType(), OwnerKind.IMPLEMENTATION).getInternalName(), "<init>", superCallMethod.getDescriptor());
@@ -587,9 +588,9 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
} }
} }
final ClassDescriptor outerDescriptor = getOuterClassDescriptor(); final ClassDescriptor outerDescriptor = typeMapper.getClosureAnnotator().getEclosingClassDescriptor(descriptor);
if (outerDescriptor != null && !CodegenUtil.isClassObject(outerDescriptor)) { if (typeMapper.hasThis0(descriptor) && outerDescriptor != null) {
final Type type = typeMapper.mapType(outerDescriptor.getDefaultType(), OwnerKind.IMPLEMENTATION); final Type type = typeMapper.mapType(outerDescriptor.getDefaultType());
String interfaceDesc = type.getDescriptor(); String interfaceDesc = type.getDescriptor();
final String fieldName = "this$0"; final String fieldName = "this$0";
v.newField(myClass, ACC_FINAL, fieldName, interfaceDesc, null, null); v.newField(myClass, ACC_FINAL, fieldName, interfaceDesc, null, null);
@@ -714,15 +715,6 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
} }
} }
@Nullable
private ClassDescriptor getOuterClassDescriptor() {
if (myClass.getParent() instanceof JetClassObject) {
return null;
}
return CodegenUtil.getOuterClassDescriptor(descriptor);
}
private void generateDelegatorToConstructorCall(InstructionAdapter iv, ExpressionCodegen codegen, JetCallElement constructorCall, private void generateDelegatorToConstructorCall(InstructionAdapter iv, ExpressionCodegen codegen, JetCallElement constructorCall,
ConstructorDescriptor constructorDescriptor, ConstructorDescriptor constructorDescriptor,
ConstructorFrameMap frameMap, int firstSuperArgument) { ConstructorFrameMap frameMap, int firstSuperArgument) {
@@ -734,11 +726,11 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
iv.load(frameMap.getOuterThisIndex(), typeMapper.mapType(((ClassDescriptor) descriptor.getContainingDeclaration()).getDefaultType(), OwnerKind.IMPLEMENTATION)); iv.load(frameMap.getOuterThisIndex(), typeMapper.mapType(((ClassDescriptor) descriptor.getContainingDeclaration()).getDefaultType(), OwnerKind.IMPLEMENTATION));
} }
CallableMethod method = typeMapper.mapToCallableMethod(constructorDescriptor, kind); CallableMethod method = typeMapper.mapToCallableMethod(constructorDescriptor, kind, typeMapper.hasThis0(constructorDescriptor.getContainingDeclaration()));
if(myClass instanceof JetObjectDeclaration && superCall instanceof JetDelegatorToSuperCall && ((JetObjectDeclaration) myClass).isObjectLiteral()) { if(myClass instanceof JetObjectDeclaration && superCall instanceof JetDelegatorToSuperCall && ((JetObjectDeclaration) myClass).isObjectLiteral()) {
ConstructorDescriptor superConstructor = (ConstructorDescriptor) bindingContext.get(BindingContext.REFERENCE_TARGET, ((JetDelegatorToSuperCall) superCall).getCalleeExpression().getConstructorReferenceExpression()); ConstructorDescriptor superConstructor = (ConstructorDescriptor) bindingContext.get(BindingContext.REFERENCE_TARGET, ((JetDelegatorToSuperCall) superCall).getCalleeExpression().getConstructorReferenceExpression());
CallableMethod superCallable = typeMapper.mapToCallableMethod(superConstructor, OwnerKind.IMPLEMENTATION); CallableMethod superCallable = typeMapper.mapToCallableMethod(superConstructor, OwnerKind.IMPLEMENTATION, typeMapper.hasThis0(superConstructor.getContainingDeclaration()));
int nextVar = firstSuperArgument+1; int nextVar = firstSuperArgument+1;
for(Type t : superCallable.getSignature().getAsmMethod().getArgumentTypes()) { for(Type t : superCallable.getSignature().getAsmMethod().getArgumentTypes()) {
iv.load(nextVar, t); iv.load(nextVar, t);
@@ -799,7 +791,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
if (specifier instanceof JetDelegatorToSuperCall) { if (specifier instanceof JetDelegatorToSuperCall) {
final JetDelegatorToSuperCall superCall = (JetDelegatorToSuperCall) specifier; final JetDelegatorToSuperCall superCall = (JetDelegatorToSuperCall) specifier;
ConstructorDescriptor constructorDescriptor = (ConstructorDescriptor) bindingContext.get(BindingContext.REFERENCE_TARGET, superCall.getCalleeExpression().getConstructorReferenceExpression()); ConstructorDescriptor constructorDescriptor = (ConstructorDescriptor) bindingContext.get(BindingContext.REFERENCE_TARGET, superCall.getCalleeExpression().getConstructorReferenceExpression());
CallableMethod method = typeMapper.mapToCallableMethod(constructorDescriptor, OwnerKind.IMPLEMENTATION); CallableMethod method = typeMapper.mapToCallableMethod(constructorDescriptor, OwnerKind.IMPLEMENTATION, typeMapper.hasThis0(constructorDescriptor.getContainingDeclaration()));
codegen.invokeMethodWithArguments(method, superCall, StackValue.none()); codegen.invokeMethodWithArguments(method, superCall, StackValue.none());
} }
else { else {
@@ -818,13 +810,13 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
if (constructorDescriptor == null) { if (constructorDescriptor == null) {
throw new UnsupportedOperationException("failed to get descriptor for secondary constructor"); throw new UnsupportedOperationException("failed to get descriptor for secondary constructor");
} }
CallableMethod method = typeMapper.mapToCallableMethod(constructorDescriptor, kind); CallableMethod method = typeMapper.mapToCallableMethod(constructorDescriptor, kind, typeMapper.hasThis0(constructorDescriptor.getContainingDeclaration()));
int flags = ACC_PUBLIC; // TODO int flags = ACC_PUBLIC; // TODO
final MethodVisitor mv = v.newMethod(constructor, flags, "<init>", method.getSignature().getAsmMethod().getDescriptor(), null, null); final MethodVisitor mv = v.newMethod(constructor, flags, "<init>", method.getSignature().getAsmMethod().getDescriptor(), null, null);
if (v.generateCode()) { if (v.generateCode()) {
mv.visitCode(); mv.visitCode();
ConstructorFrameMap frameMap = new ConstructorFrameMap(method, constructorDescriptor, descriptor, kind); ConstructorFrameMap frameMap = new ConstructorFrameMap(method, constructorDescriptor, typeMapper.hasThis0(constructorDescriptor.getContainingDeclaration()));
final InstructionAdapter iv = new InstructionAdapter(mv); final InstructionAdapter iv = new InstructionAdapter(mv);
ExpressionCodegen codegen = new ExpressionCodegen(mv, frameMap, Type.VOID_TYPE, context, state); ExpressionCodegen codegen = new ExpressionCodegen(mv, frameMap, Type.VOID_TYPE, context, state);
@@ -21,10 +21,12 @@ import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.*; 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.psi.*;
import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.DescriptorUtils; import org.jetbrains.jet.lang.resolve.DescriptorUtils;
import org.jetbrains.jet.lang.resolve.java.*; import org.jetbrains.jet.lang.resolve.java.*;
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor; import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor;
import org.jetbrains.jet.lang.types.*; import org.jetbrains.jet.lang.types.*;
import org.objectweb.asm.Opcodes; import org.objectweb.asm.Opcodes;
@@ -51,9 +53,17 @@ public class JetTypeMapper {
public static final Type ARRAY_GENERIC_TYPE = Type.getType(Object[].class); public static final Type ARRAY_GENERIC_TYPE = Type.getType(Object[].class);
private final JetStandardLibrary standardLibrary; private final JetStandardLibrary standardLibrary;
private final BindingContext bindingContext; public final BindingContext bindingContext;
private final Map<JetElement, String> classNamesForAnonymousClasses = new HashMap<JetElement, String>();
private final Map<String, Integer> anonymousSubclassesCount = new HashMap<String, Integer>(); public boolean hasThis0(ClassDescriptor classDescriptor) {
return closureAnnotator.hasThis0(classDescriptor);
}
public ClosureAnnotator getClosureAnnotator() {
return closureAnnotator;
}
private final ClosureAnnotator closureAnnotator;
private final HashMap<JetType,String> knowTypeNames = new HashMap<JetType, String>(); private final HashMap<JetType,String> knowTypeNames = new HashMap<JetType, String>();
private final HashMap<JetType,Type> knowTypes = new HashMap<JetType, Type>(); private final HashMap<JetType,Type> knowTypes = new HashMap<JetType, Type>();
@@ -72,13 +82,10 @@ public class JetTypeMapper {
public static final Type TYPE_FUNCTION0 = Type.getObjectType("jet/Function0"); public static final Type TYPE_FUNCTION0 = Type.getObjectType("jet/Function0");
public static final Type TYPE_FUNCTION1 = Type.getObjectType("jet/Function1"); public static final Type TYPE_FUNCTION1 = Type.getObjectType("jet/Function1");
public JetStandardLibrary getStandardLibrary() { public JetTypeMapper(JetStandardLibrary standardLibrary, BindingContext bindingContext, ClosureAnnotator closureAnnotator) {
return standardLibrary;
}
public JetTypeMapper(JetStandardLibrary standardLibrary, BindingContext bindingContext) {
this.standardLibrary = standardLibrary; this.standardLibrary = standardLibrary;
this.bindingContext = bindingContext; this.bindingContext = bindingContext;
this.closureAnnotator = closureAnnotator;
initKnownTypes(); initKnownTypes();
initKnownTypeNames(); initKnownTypeNames();
} }
@@ -193,7 +200,7 @@ public class JetTypeMapper {
DeclarationDescriptor container = descriptor.getContainingDeclaration(); DeclarationDescriptor container = descriptor.getContainingDeclaration();
String name = descriptor.getName(); String name = descriptor.getName();
if(JetPsiUtil.NO_NAME_PROVIDED.equals(name)) { if(JetPsiUtil.NO_NAME_PROVIDED.equals(name)) {
return classNameForAnonymousClass((JetElement) bindingContext.get(BindingContext.DESCRIPTOR_TO_DECLARATION, descriptor)); return closureAnnotator.classNameForAnonymousClass((JetElement) bindingContext.get(BindingContext.DESCRIPTOR_TO_DECLARATION, descriptor));
} }
if(name.contains("/")) if(name.contains("/"))
return name; return name;
@@ -667,21 +674,20 @@ public class JetTypeMapper {
return new JvmPropertyAccessorSignature(jvmMethodSignature, jvmMethodSignature.getKotlinParameterType(jvmMethodSignature.getParameterCount() - 1)); return new JvmPropertyAccessorSignature(jvmMethodSignature, jvmMethodSignature.getKotlinParameterType(jvmMethodSignature.getParameterCount() - 1));
} }
private JvmMethodSignature mapConstructorSignature(ConstructorDescriptor descriptor) { private JvmMethodSignature mapConstructorSignature(ConstructorDescriptor descriptor, boolean hasThis0) {
BothSignatureWriter signatureWriter = new BothSignatureWriter(BothSignatureWriter.Mode.METHOD, true); BothSignatureWriter signatureWriter = new BothSignatureWriter(BothSignatureWriter.Mode.METHOD, true);
List<ValueParameterDescriptor> parameters = descriptor.getOriginal().getValueParameters(); List<ValueParameterDescriptor> parameters = descriptor.getOriginal().getValueParameters();
ClassDescriptor classDescriptor = descriptor.getContainingDeclaration();
// constructor type parmeters are fake // constructor type parmeters are fake
writeFormalTypeParameters(Collections.<TypeParameterDescriptor>emptyList(), signatureWriter); writeFormalTypeParameters(Collections.<TypeParameterDescriptor>emptyList(), signatureWriter);
signatureWriter.writeParametersStart(); signatureWriter.writeParametersStart();
if (CodegenUtil.hasThis0(classDescriptor)) { if (hasThis0) {
signatureWriter.writeParameterType(JvmMethodParameterKind.THIS0); signatureWriter.writeParameterType(JvmMethodParameterKind.THIS0);
mapType(CodegenUtil.getOuterClassDescriptor(classDescriptor).getDefaultType(), OwnerKind.IMPLEMENTATION, signatureWriter); mapType(closureAnnotator.getEclosingClassDescriptor(descriptor.getContainingDeclaration()).getDefaultType(), OwnerKind.IMPLEMENTATION, signatureWriter);
signatureWriter.writeParameterTypeEnd(); signatureWriter.writeParameterTypeEnd();
} }
@@ -698,8 +704,8 @@ public class JetTypeMapper {
return signatureWriter.makeJvmMethodSignature("<init>"); return signatureWriter.makeJvmMethodSignature("<init>");
} }
public CallableMethod mapToCallableMethod(ConstructorDescriptor descriptor, OwnerKind kind) { public CallableMethod mapToCallableMethod(ConstructorDescriptor descriptor, OwnerKind kind, boolean hasThis0) {
final JvmMethodSignature method = mapConstructorSignature(descriptor); final JvmMethodSignature method = mapConstructorSignature(descriptor, hasThis0);
String owner = mapType(descriptor.getContainingDeclaration().getDefaultType(), kind).getInternalName(); String owner = mapType(descriptor.getContainingDeclaration().getDefaultType(), kind).getInternalName();
return new CallableMethod(owner, owner, owner, method, INVOKESPECIAL); return new CallableMethod(owner, owner, owner, method, INVOKESPECIAL);
} }
@@ -726,54 +732,6 @@ public class JetTypeMapper {
} }
} }
String classNameForAnonymousClass(JetElement expression) {
if(expression instanceof JetObjectLiteralExpression) {
JetObjectLiteralExpression jetObjectLiteralExpression = (JetObjectLiteralExpression) expression;
expression = jetObjectLiteralExpression.getObjectDeclaration();
}
if(expression instanceof JetFunctionLiteralExpression) {
JetFunctionLiteralExpression jetFunctionLiteralExpression = (JetFunctionLiteralExpression) expression;
expression = jetFunctionLiteralExpression.getFunctionLiteral();
}
String name = classNamesForAnonymousClasses.get(expression);
if (name != null) {
return name;
}
@SuppressWarnings("unchecked")
PsiElement container = PsiTreeUtil.getParentOfType(expression, JetFile.class, JetClass.class, JetObjectDeclaration.class, JetFunctionLiteral.class);
String baseName;
if(container instanceof JetFile) {
baseName = NamespaceCodegen.getJVMClassName(JetPsiUtil.getFQName(((JetFile) container)), true);
}
else if(container instanceof JetClass) {
ClassDescriptor aClass = bindingContext.get(BindingContext.CLASS, container);
baseName = mapType(aClass.getDefaultType(), OwnerKind.IMPLEMENTATION).getInternalName();
ClassDescriptor myClass = bindingContext.get(BindingContext.CLASS, expression);
if(CodegenUtil.isClassObject(myClass)) {
return mapType(aClass.getDefaultType(), OwnerKind.IMPLEMENTATION).getInternalName() + JvmAbi.CLASS_OBJECT_SUFFIX;
}
else
baseName = classNameForAnonymousClass((JetElement) container);
}
else {
baseName = classNameForAnonymousClass((JetElement) container);
}
Integer count = anonymousSubclassesCount.get(baseName);
if (count == null) count = 0;
anonymousSubclassesCount.put(baseName, count + 1);
final String className = baseName + "$" + (count + 1);
classNamesForAnonymousClasses.put(expression, className);
return className;
}
public Collection<String> allJvmNames(JetClassOrObject jetClass) { public Collection<String> allJvmNames(JetClassOrObject jetClass) {
Set<String> result = new HashSet<String>(); Set<String> result = new HashSet<String>();
final ClassDescriptor classDescriptor = bindingContext.get(BindingContext.CLASS, jetClass); final ClassDescriptor classDescriptor = bindingContext.get(BindingContext.CLASS, jetClass);
@@ -856,7 +814,7 @@ public class JetTypeMapper {
} }
else if (descriptor instanceof SimpleFunctionDescriptor && descriptor.getContainingDeclaration() instanceof FunctionDescriptor) { else if (descriptor instanceof SimpleFunctionDescriptor && descriptor.getContainingDeclaration() instanceof FunctionDescriptor) {
PsiElement psiElement = bindingContext.get(BindingContext.DESCRIPTOR_TO_DECLARATION, descriptor); PsiElement psiElement = bindingContext.get(BindingContext.DESCRIPTOR_TO_DECLARATION, descriptor);
return Type.getObjectType(classNameForAnonymousClass((JetElement) psiElement)); return Type.getObjectType(closureAnnotator.classNameForAnonymousClass((JetElement) psiElement));
} }
else if (descriptor instanceof FunctionDescriptor) { else if (descriptor instanceof FunctionDescriptor) {
return StackValue.sharedTypeForType(mapType(((FunctionDescriptor) descriptor).getReceiverParameter().getType())); return StackValue.sharedTypeForType(mapType(((FunctionDescriptor) descriptor).getReceiverParameter().getType()));
@@ -24,9 +24,7 @@ import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
public enum JvmMethodParameterKind { public enum JvmMethodParameterKind {
VALUE, VALUE,
THIS, THIS,
/** @see CodegenUtil#hasThis0(ClassDescriptor) */
THIS0, THIS0,
RECEIVER, RECEIVER,
TYPE_INFO,
SHARED_VAR, SHARED_VAR,
} }
@@ -17,24 +17,15 @@
package org.jetbrains.jet.codegen; package org.jetbrains.jet.codegen;
import com.intellij.psi.PsiFile; import com.intellij.psi.PsiFile;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.descriptors.NamespaceDescriptor; import org.jetbrains.jet.lang.descriptors.NamespaceDescriptor;
import org.jetbrains.jet.lang.descriptors.PropertyDescriptor; import org.jetbrains.jet.lang.descriptors.PropertyDescriptor;
import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.java.JvmAbi; import org.jetbrains.jet.lang.resolve.java.JvmAbi;
import org.jetbrains.jet.lang.resolve.java.JvmStdlibNames;
import org.jetbrains.jet.lang.types.JetStandardClasses;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.TypeProjection;
import org.jetbrains.jet.lang.types.TypeUtils;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Type; import org.objectweb.asm.Type;
import org.objectweb.asm.commons.InstructionAdapter; import org.objectweb.asm.commons.InstructionAdapter;
import java.util.List;
import static org.objectweb.asm.Opcodes.*; import static org.objectweb.asm.Opcodes.*;
/** /**
@@ -68,10 +59,6 @@ public class NamespaceCodegen {
final PropertyCodegen propertyCodegen = new PropertyCodegen(context, v, functionCodegen, state); final PropertyCodegen propertyCodegen = new PropertyCodegen(context, v, functionCodegen, state);
final ClassCodegen classCodegen = state.forClass(); final ClassCodegen classCodegen = state.forClass();
if (v.generateCode()) {
GenerationState.prepareAnonymousClasses(file, state.getTypeMapper());
}
for (JetDeclaration declaration : file.getDeclarations()) { for (JetDeclaration declaration : file.getDeclarations()) {
if (declaration instanceof JetProperty) { if (declaration instanceof JetProperty) {
propertyCodegen.gen((JetProperty) declaration); propertyCodegen.gen((JetProperty) declaration);
@@ -30,7 +30,7 @@ import java.util.Map;
* @author alex.tkachman * @author alex.tkachman
*/ */
public class ObjectOrClosureCodegen { public class ObjectOrClosureCodegen {
protected boolean captureThis; protected Type captureThis;
protected Type captureReceiver; protected Type captureReceiver;
public final GenerationState state; public final GenerationState state;
@@ -83,7 +83,7 @@ public class ObjectOrClosureCodegen {
if (idx < 0) return null; if (idx < 0) return null;
JetElement expression = (JetElement) state.getBindingContext().get(BindingContext.DESCRIPTOR_TO_DECLARATION, vd); JetElement expression = (JetElement) state.getBindingContext().get(BindingContext.DESCRIPTOR_TO_DECLARATION, vd);
String cn = state.getTypeMapper().classNameForAnonymousClass(expression); String cn = state.getTypeMapper().getClosureAnnotator().classNameForAnonymousClass(expression);
Type localType = Type.getObjectType(cn); Type localType = Type.getObjectType(cn);
StackValue outerValue = StackValue.local(idx, localType); StackValue outerValue = StackValue.local(idx, localType);
@@ -131,6 +131,6 @@ public class ObjectOrClosureCodegen {
} }
public boolean isConst () { public boolean isConst () {
return !captureThis && captureReceiver != null && closure.isEmpty(); return captureThis == null && captureReceiver == null && closure.isEmpty();
} }
} }
@@ -25,10 +25,7 @@ import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiManager; import com.intellij.psi.PsiManager;
import com.intellij.psi.PsiRecursiveElementWalkingVisitor; import com.intellij.psi.PsiRecursiveElementWalkingVisitor;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.codegen.ClassBuilderFactory; import org.jetbrains.jet.codegen.*;
import org.jetbrains.jet.codegen.ClassFileFactory;
import org.jetbrains.jet.codegen.GenerationState;
import org.jetbrains.jet.codegen.JetTypeMapper;
import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowDataTraceFactory; import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowDataTraceFactory;
import org.jetbrains.jet.lang.descriptors.ClassDescriptor; import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
import org.jetbrains.jet.lang.descriptors.ClassOrNamespaceDescriptor; import org.jetbrains.jet.lang.descriptors.ClassOrNamespaceDescriptor;
@@ -201,7 +198,7 @@ public class CompileSession {
public ClassFileFactory generate() { public ClassFileFactory generate() {
Project project = myEnvironment.getProject(); Project project = myEnvironment.getProject();
GenerationState generationState = new GenerationState(project, ClassBuilderFactory.BINARIES, myFileNameTransformer); GenerationState generationState = new GenerationState(project, ClassBuilderFactory.BINARIES, myFileNameTransformer);
generationState.compileCorrectFiles(myBindingContext, mySourceFiles); generationState.compileCorrectFiles(myBindingContext, mySourceFiles, CompilationErrorHandler.THROW_EXCEPTION, true);
ClassFileFactory answer = generationState.getFactory(); ClassFileFactory answer = generationState.getFactory();
List<CompilerPlugin> fileProcessors = myEnvironment.getCompilerPlugins(); List<CompilerPlugin> fileProcessors = myEnvironment.getCompilerPlugins();
@@ -43,7 +43,9 @@ import com.intellij.util.containers.Stack;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.codegen.ClassBuilder; import org.jetbrains.jet.codegen.ClassBuilder;
import org.jetbrains.jet.codegen.ClassBuilderFactory; import org.jetbrains.jet.codegen.ClassBuilderFactory;
import org.jetbrains.jet.codegen.CompilationErrorHandler;
import org.jetbrains.jet.codegen.GenerationState; import org.jetbrains.jet.codegen.GenerationState;
import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowDataTraceFactory;
import org.jetbrains.jet.lang.psi.JetFile; import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.psi.JetPsiUtil; import org.jetbrains.jet.lang.psi.JetPsiUtil;
import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.BindingContext;
@@ -184,8 +186,10 @@ public class JetLightClass extends AbstractLightClass implements JetJavaMirrorMa
}; };
List<JetFile> files = Collections.singletonList(file); List<JetFile> files = Collections.singletonList(file);
final BindingContext context = AnalyzerFacade.shallowAnalyzeFiles(files); //todo:
state.compileCorrectFiles(context, files); // final BindingContext context = AnalyzerFacade.shallowAnalyzeFiles(files);
final BindingContext context = AnalyzerFacade.analyzeOneFileWithJavaIntegration(file, JetControlFlowDataTraceFactory.EMPTY);
state.compileCorrectFiles(context, files, CompilationErrorHandler.THROW_EXCEPTION, true);
state.getFactory().files(); state.getFactory().files();
return answer; return answer;
@@ -0,0 +1,17 @@
package p
class C(val y : Int) {
val initChild = { ->
object : java.lang.Object() {
override fun toString(): String {
return "child" + y
}
}
}
}
fun box(): String {
val c = C(3).initChild
val x = c().toString()
return if(x == "child3") "OK" else x
}
@@ -31,6 +31,11 @@ public class ObjectGenTest extends CodegenTestCase {
// System.out.println(generateToText()); // System.out.println(generateToText());
} }
public void testObjectLiteralInClosure() throws Exception {
blackBoxFile("objects/objectLiteralInClosure.jet");
// System.out.println(generateToText());
}
public void testMethodOnObject() throws Exception { public void testMethodOnObject() throws Exception {
blackBoxFile("objects/methodOnObject.jet"); blackBoxFile("objects/methodOnObject.jet");
} }
@@ -96,7 +96,8 @@ public class TestlibTest extends CodegenTestCase {
new URLClassLoader(new URL[]{ForTestCompileStdlib.stdlibJarForTests().toURI().toURL(), junitJar.toURI().toURL()}, new URLClassLoader(new URL[]{ForTestCompileStdlib.stdlibJarForTests().toURI().toURL(), junitJar.toURI().toURL()},
TestCase.class.getClassLoader())); TestCase.class.getClassLoader()));
JetTypeMapper typeMapper = new JetTypeMapper(classFileFactory.state.getStandardLibrary(), session.getMyBindingContext()); ClosureAnnotator closureAnnotator = new ClosureAnnotator(session.getMyBindingContext(), session.getSourceFileNamespaces());
JetTypeMapper typeMapper = new JetTypeMapper(classFileFactory.state.getStandardLibrary(), session.getMyBindingContext(), closureAnnotator);
TestSuite suite = new TestSuite("stdlib_test"); TestSuite suite = new TestSuite("stdlib_test");
try { try {
for(JetFile jetFile : session.getSourceFileNamespaces()) { for(JetFile jetFile : session.getSourceFileNamespaces()) {
@@ -34,7 +34,7 @@ import com.sun.jdi.ReferenceType;
import com.sun.jdi.request.ClassPrepareRequest; import com.sun.jdi.request.ClassPrepareRequest;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.codegen.GenerationState; import org.jetbrains.jet.codegen.ClosureAnnotator;
import org.jetbrains.jet.codegen.JetTypeMapper; import org.jetbrains.jet.codegen.JetTypeMapper;
import org.jetbrains.jet.codegen.NamespaceCodegen; import org.jetbrains.jet.codegen.NamespaceCodegen;
import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.psi.*;
@@ -154,18 +154,8 @@ public class JetPositionManager implements PositionManager {
} }
final BindingContext bindingContext = WholeProjectAnalyzerFacade.analyzeProjectWithCacheOnAFile(file); final BindingContext bindingContext = WholeProjectAnalyzerFacade.analyzeProjectWithCacheOnAFile(file);
final JetStandardLibrary standardLibrary = JetStandardLibrary.getInstance(); final JetStandardLibrary standardLibrary = JetStandardLibrary.getInstance();
final JetTypeMapper typeMapper = new JetTypeMapper(standardLibrary, bindingContext); ClosureAnnotator closureAnnotator = new ClosureAnnotator(bindingContext, Collections.singleton(file));
file.acceptChildren(new JetVisitorVoid() { final JetTypeMapper typeMapper = new JetTypeMapper(standardLibrary, bindingContext, closureAnnotator);
@Override
public void visitJetElement(JetElement element) {
element.acceptChildren(this);
}
@Override
public void visitClass(JetClass klass) {
GenerationState.prepareAnonymousClasses(klass, typeMapper);
}
});
myTypeMappers.put(file, typeMapper); myTypeMappers.put(file, typeMapper);
return typeMapper; return typeMapper;
} }
@@ -38,6 +38,7 @@ import com.intellij.psi.PsiManager;
import com.intellij.util.Alarm; import com.intellij.util.Alarm;
import org.jetbrains.jet.codegen.ClassBuilderFactory; import org.jetbrains.jet.codegen.ClassBuilderFactory;
import org.jetbrains.jet.codegen.ClassFileFactory; import org.jetbrains.jet.codegen.ClassFileFactory;
import org.jetbrains.jet.codegen.CompilationErrorHandler;
import org.jetbrains.jet.codegen.GenerationState; import org.jetbrains.jet.codegen.GenerationState;
import org.jetbrains.jet.lang.psi.JetFile; import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.resolve.AnalyzingUtils; import org.jetbrains.jet.lang.resolve.AnalyzingUtils;
@@ -203,7 +204,7 @@ public class BytecodeToolwindow extends JPanel implements Disposable {
try { try {
BindingContext binding = WholeProjectAnalyzerFacade.analyzeProjectWithCacheOnAFile(file); BindingContext binding = WholeProjectAnalyzerFacade.analyzeProjectWithCacheOnAFile(file);
AnalyzingUtils.throwExceptionOnErrors(binding); AnalyzingUtils.throwExceptionOnErrors(binding);
state.compileCorrectFiles(binding, Collections.singletonList(file)); state.compileCorrectFiles(binding, Collections.singletonList(file), CompilationErrorHandler.THROW_EXCEPTION, true);
} catch (Exception e) { } catch (Exception e) {
StringWriter out = new StringWriter(1024); StringWriter out = new StringWriter(1024);
e.printStackTrace(new PrintWriter(out)); e.printStackTrace(new PrintWriter(out));