Refactor CodegenBinding & PsiCodegenPredictor

Use ASM Type to store names of classes, use strings in PsiCodegenPredictor.
Inline some methods, move closer to their usages
This commit is contained in:
Alexander Udalov
2013-10-02 19:16:31 +04:00
parent 035a7cccda
commit 8729c88aa2
12 changed files with 132 additions and 154 deletions
@@ -53,7 +53,6 @@ import org.jetbrains.jet.lang.resolve.calls.util.ExpressionAsFunctionDescriptor;
import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant; import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
import org.jetbrains.jet.lang.resolve.java.AsmTypeConstants; import org.jetbrains.jet.lang.resolve.java.AsmTypeConstants;
import org.jetbrains.jet.lang.resolve.java.JvmAbi; import org.jetbrains.jet.lang.resolve.java.JvmAbi;
import org.jetbrains.jet.lang.resolve.java.JvmClassName;
import org.jetbrains.jet.lang.resolve.java.descriptor.ClassDescriptorFromJvmBytecode; import org.jetbrains.jet.lang.resolve.java.descriptor.ClassDescriptorFromJvmBytecode;
import org.jetbrains.jet.lang.resolve.java.descriptor.SamConstructorDescriptor; import org.jetbrains.jet.lang.resolve.java.descriptor.SamConstructorDescriptor;
import org.jetbrains.jet.lang.resolve.name.Name; import org.jetbrains.jet.lang.resolve.name.Name;
@@ -1327,10 +1326,9 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
assert constructorDescriptor != null; assert constructorDescriptor != null;
CallableMethod constructor = typeMapper.mapToCallableMethod(constructorDescriptor, closure); CallableMethod constructor = typeMapper.mapToCallableMethod(constructorDescriptor, closure);
JvmClassName name = bindingContext.get(FQN, constructorDescriptor.getContainingDeclaration()); Type type = bindingContext.get(ASM_TYPE, constructorDescriptor.getContainingDeclaration());
assert name != null; assert type != null;
Type type = name.getAsmType();
v.anew(type); v.anew(type);
v.dup(); v.dup();
Method cons = constructor.getSignature().getAsmMethod(); Method cons = constructor.getSignature().getAsmMethod();
@@ -1352,7 +1350,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
pushMethodArguments(resolvedCall, Arrays.asList(argumentTypes)); pushMethodArguments(resolvedCall, Arrays.asList(argumentTypes));
} }
v.invokespecial(name.getInternalName(), "<init>", cons.getDescriptor()); v.invokespecial(type.getInternalName(), "<init>", cons.getDescriptor());
return StackValue.onStack(type); return StackValue.onStack(type);
} }
@@ -26,7 +26,6 @@ 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.psi.JetScript; import org.jetbrains.jet.lang.psi.JetScript;
import org.jetbrains.jet.lang.resolve.ScriptNameUtil; import org.jetbrains.jet.lang.resolve.ScriptNameUtil;
import org.jetbrains.jet.lang.resolve.java.JvmClassName;
import org.jetbrains.jet.lang.resolve.name.FqName; import org.jetbrains.jet.lang.resolve.name.FqName;
import java.util.Collection; import java.util.Collection;
@@ -45,7 +44,7 @@ public class KotlinCodegenFacade {
String name = ScriptNameUtil.classNameForScript(file); String name = ScriptNameUtil.classNameForScript(file);
JetScript script = file.getScript(); JetScript script = file.getScript();
assert script != null; assert script != null;
registerClassNameForScript(state.getBindingTrace(), script, JvmClassName.byInternalName(name)); registerClassNameForScript(state.getBindingTrace(), script, Type.getObjectType(name));
} }
} }
@@ -34,7 +34,6 @@ import org.jetbrains.jet.lang.descriptors.ScriptDescriptor;
import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor; import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
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.JvmClassName;
import javax.inject.Inject; import javax.inject.Inject;
import java.util.Collections; import java.util.Collections;
@@ -69,18 +68,16 @@ public class ScriptCodegen extends MemberCodegen {
ClassDescriptor classDescriptorForScript = bindingContext.get(CLASS_FOR_SCRIPT, scriptDescriptor); ClassDescriptor classDescriptorForScript = bindingContext.get(CLASS_FOR_SCRIPT, scriptDescriptor);
assert classDescriptorForScript != null; assert classDescriptorForScript != null;
ScriptContext context = ScriptContext context = (ScriptContext) CodegenContext.STATIC.intoScript(scriptDescriptor, classDescriptorForScript);
(ScriptContext) CodegenContext.STATIC
.intoScript(scriptDescriptor, classDescriptorForScript);
JvmClassName className = bindingContext.get(FQN, classDescriptorForScript); Type classType = bindingContext.get(ASM_TYPE, classDescriptorForScript);
assert className != null; assert classType != null;
ClassBuilder classBuilder = classFileFactory.newVisitor(className.getAsmType(), scriptDeclaration.getContainingFile()); ClassBuilder classBuilder = classFileFactory.newVisitor(classType, scriptDeclaration.getContainingFile());
classBuilder.defineClass(scriptDeclaration, classBuilder.defineClass(scriptDeclaration,
V1_6, V1_6,
ACC_PUBLIC, ACC_PUBLIC,
className.getInternalName(), classType.getInternalName(),
null, null,
"java/lang/Object", "java/lang/Object",
new String[0]); new String[0]);
@@ -120,13 +117,13 @@ public class ScriptCodegen extends MemberCodegen {
InstructionAdapter instructionAdapter = new InstructionAdapter(mv); InstructionAdapter instructionAdapter = new InstructionAdapter(mv);
JvmClassName className = bindingContext.get(FQN, classDescriptorForScript); Type classType = bindingContext.get(ASM_TYPE, classDescriptorForScript);
assert className != null; assert classType != null;
instructionAdapter.load(0, className.getAsmType()); instructionAdapter.load(0, classType);
instructionAdapter.invokespecial("java/lang/Object", "<init>", "()V"); instructionAdapter.invokespecial("java/lang/Object", "<init>", "()V");
instructionAdapter.load(0, className.getAsmType()); instructionAdapter.load(0, classType);
FrameMap frameMap = context.prepareFrame(typeMapper); FrameMap frameMap = context.prepareFrame(typeMapper);
@@ -152,25 +149,25 @@ public class ScriptCodegen extends MemberCodegen {
for (ScriptDescriptor earlierScript : importedScripts) { for (ScriptDescriptor earlierScript : importedScripts) {
Type earlierClassType = asmTypeForScriptDescriptor(bindingContext, earlierScript); Type earlierClassType = asmTypeForScriptDescriptor(bindingContext, earlierScript);
instructionAdapter.load(0, className.getAsmType()); instructionAdapter.load(0, classType);
instructionAdapter.load(offset, earlierClassType); instructionAdapter.load(offset, earlierClassType);
offset += earlierClassType.getSize(); offset += earlierClassType.getSize();
instructionAdapter.putfield(className.getInternalName(), getScriptFieldName(earlierScript), earlierClassType.getDescriptor()); instructionAdapter.putfield(classType.getInternalName(), getScriptFieldName(earlierScript), earlierClassType.getDescriptor());
} }
for (ValueParameterDescriptor parameter : scriptDescriptor.getValueParameters()) { for (ValueParameterDescriptor parameter : scriptDescriptor.getValueParameters()) {
Type parameterType = typeMapper.mapType(parameter.getType()); Type parameterType = typeMapper.mapType(parameter.getType());
instructionAdapter.load(0, className.getAsmType()); instructionAdapter.load(0, classType);
instructionAdapter.load(offset, parameterType); instructionAdapter.load(offset, parameterType);
offset += parameterType.getSize(); offset += parameterType.getSize();
instructionAdapter.putfield(className.getInternalName(), parameter.getName().getIdentifier(), parameterType.getDescriptor()); instructionAdapter.putfield(classType.getInternalName(), parameter.getName().getIdentifier(), parameterType.getDescriptor());
} }
StackValue stackValue = StackValue stackValue =
new ExpressionCodegen(mv, frameMap, Type.VOID_TYPE, context, state).gen(scriptDeclaration.getBlockExpression()); new ExpressionCodegen(mv, frameMap, Type.VOID_TYPE, context, state).gen(scriptDeclaration.getBlockExpression());
if (stackValue.type != Type.VOID_TYPE) { if (stackValue.type != Type.VOID_TYPE) {
stackValue.put(stackValue.type, instructionAdapter); stackValue.put(stackValue.type, instructionAdapter);
instructionAdapter.putfield(className.getInternalName(), ScriptDescriptor.LAST_EXPRESSION_VALUE_FIELD_NAME, instructionAdapter.putfield(classType.getInternalName(), ScriptDescriptor.LAST_EXPRESSION_VALUE_FIELD_NAME,
blockType.getDescriptor()); blockType.getDescriptor());
} }
@@ -204,8 +201,7 @@ public class ScriptCodegen extends MemberCodegen {
ScriptDescriptor earlierDescriptor = t.first; ScriptDescriptor earlierDescriptor = t.first;
Type earlierClassName = t.second; Type earlierClassName = t.second;
registerClassNameForScript(state.getBindingTrace(), earlierDescriptor, registerClassNameForScript(state.getBindingTrace(), earlierDescriptor, earlierClassName);
JvmClassName.byInternalName(earlierClassName.getInternalName()));
} }
List<ScriptDescriptor> earlierScriptDescriptors = Lists.newArrayList(); List<ScriptDescriptor> earlierScriptDescriptors = Lists.newArrayList();
@@ -243,7 +239,7 @@ public class ScriptCodegen extends MemberCodegen {
@NotNull CompilationErrorHandler errorHandler @NotNull CompilationErrorHandler errorHandler
) { ) {
registerEarlierScripts(earlierScripts); registerEarlierScripts(earlierScripts);
registerClassNameForScript(state.getBindingTrace(), script, JvmClassName.byInternalName(classType.getInternalName())); registerClassNameForScript(state.getBindingTrace(), script, classType);
state.beforeCompile(); state.beforeCompile();
KotlinCodegenFacade.generateNamespace( KotlinCodegenFacade.generateNamespace(
@@ -22,6 +22,7 @@ import com.intellij.psi.tree.TokenSet;
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.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.asm4.Type;
import org.jetbrains.jet.codegen.SamCodegenUtil; import org.jetbrains.jet.codegen.SamCodegenUtil;
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.descriptors.annotations.AnnotationDescriptor;
@@ -153,9 +154,9 @@ class CodegenAnnotatingVisitor extends JetVisitorVoid {
super.visitEnumEntry(enumEntry); super.visitEnumEntry(enumEntry);
} }
else { else {
JvmClassName jvmClassName = bindingTrace.get(FQN, peekFromStack(classStack)); Type asmType = bindingTrace.get(ASM_TYPE, peekFromStack(classStack));
assert PsiCodegenPredictor.checkPredictedNameFromPsi(bindingTrace, descriptor, jvmClassName); assert PsiCodegenPredictor.checkPredictedNameFromPsi(bindingTrace, descriptor, asmType);
bindingTrace.record(FQN, descriptor, jvmClassName); bindingTrace.record(ASM_TYPE, descriptor, asmType);
} }
} }
@@ -231,7 +232,7 @@ class CodegenAnnotatingVisitor extends JetVisitorVoid {
classStack.push(classDescriptor); classStack.push(classDescriptor);
//noinspection ConstantConditions //noinspection ConstantConditions
nameStack.push(bindingContext.get(FQN, classDescriptor).getInternalName()); nameStack.push(bindingContext.get(ASM_TYPE, classDescriptor).getInternalName());
super.visitObjectLiteralExpression(expression); super.visitObjectLiteralExpression(expression);
nameStack.pop(); nameStack.pop();
classStack.pop(); classStack.pop();
@@ -286,7 +287,7 @@ class CodegenAnnotatingVisitor extends JetVisitorVoid {
boolean functionLiteral boolean functionLiteral
) { ) {
CodegenBinding.recordClosure(bindingTrace, element, classDescriptor, peekFromStack(classStack), CodegenBinding.recordClosure(bindingTrace, element, classDescriptor, peekFromStack(classStack),
JvmClassName.byInternalName(name), functionLiteral); Type.getObjectType(name), functionLiteral);
} }
@Override @Override
@@ -28,7 +28,6 @@ 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.BindingTrace; import org.jetbrains.jet.lang.resolve.BindingTrace;
import org.jetbrains.jet.lang.resolve.java.JvmAbi; import org.jetbrains.jet.lang.resolve.java.JvmAbi;
import org.jetbrains.jet.lang.resolve.java.JvmClassName;
import org.jetbrains.jet.lang.resolve.java.descriptor.ClassDescriptorFromJvmBytecode; import org.jetbrains.jet.lang.resolve.java.descriptor.ClassDescriptorFromJvmBytecode;
import org.jetbrains.jet.lang.resolve.name.FqName; import org.jetbrains.jet.lang.resolve.name.FqName;
import org.jetbrains.jet.lang.resolve.name.Name; import org.jetbrains.jet.lang.resolve.name.Name;
@@ -52,7 +51,7 @@ public class CodegenBinding {
public static final WritableSlice<ScriptDescriptor, ClassDescriptor> CLASS_FOR_SCRIPT = Slices.createSimpleSlice(); public static final WritableSlice<ScriptDescriptor, ClassDescriptor> CLASS_FOR_SCRIPT = Slices.createSimpleSlice();
public static final WritableSlice<DeclarationDescriptor, JvmClassName> FQN = Slices.createSimpleSlice(); public static final WritableSlice<DeclarationDescriptor, Type> ASM_TYPE = Slices.createSimpleSlice();
public static final WritableSlice<ClassDescriptor, Boolean> ENUM_ENTRY_CLASS_NEED_SUBCLASS = Slices.createSimpleSetSlice(); public static final WritableSlice<ClassDescriptor, Boolean> ENUM_ENTRY_CLASS_NEED_SUBCLASS = Slices.createSimpleSetSlice();
@@ -82,7 +81,7 @@ public class CodegenBinding {
public static Type asmTypeForScriptDescriptor(BindingContext bindingContext, @NotNull ScriptDescriptor scriptDescriptor) { public static Type asmTypeForScriptDescriptor(BindingContext bindingContext, @NotNull ScriptDescriptor scriptDescriptor) {
ClassDescriptor classDescriptor = bindingContext.get(CLASS_FOR_SCRIPT, scriptDescriptor); ClassDescriptor classDescriptor = bindingContext.get(CLASS_FOR_SCRIPT, scriptDescriptor);
//noinspection ConstantConditions //noinspection ConstantConditions
return fqn(bindingContext, classDescriptor); return asmType(bindingContext, classDescriptor);
} }
@NotNull @NotNull
@@ -109,9 +108,9 @@ public class CodegenBinding {
} }
@NotNull @NotNull
private static Type fqn(@NotNull BindingContext bindingContext, @NotNull ClassDescriptor descriptor) { private static Type asmType(@NotNull BindingContext bindingContext, @NotNull ClassDescriptor descriptor) {
//noinspection ConstantConditions //noinspection ConstantConditions
return bindingContext.get(FQN, descriptor).getAsmType(); return bindingContext.get(ASM_TYPE, descriptor);
} }
@NotNull @NotNull
@@ -128,25 +127,25 @@ public class CodegenBinding {
return asmTypeForAnonymousClass(bindingContext, functionDescriptor); return asmTypeForAnonymousClass(bindingContext, functionDescriptor);
} }
return fqn(bindingContext, descriptor); return asmType(bindingContext, descriptor);
} }
@NotNull @NotNull
public static Type asmTypeForAnonymousClass(@NotNull BindingContext bindingContext, @NotNull FunctionDescriptor descriptor) { public static Type asmTypeForAnonymousClass(@NotNull BindingContext bindingContext, @NotNull FunctionDescriptor descriptor) {
ClassDescriptor classDescriptor = anonymousClassForFunction(bindingContext, descriptor); ClassDescriptor classDescriptor = anonymousClassForFunction(bindingContext, descriptor);
return fqn(bindingContext, classDescriptor); return asmType(bindingContext, classDescriptor);
} }
public static void registerClassNameForScript( public static void registerClassNameForScript(
BindingTrace bindingTrace, BindingTrace bindingTrace,
@NotNull ScriptDescriptor scriptDescriptor, @NotNull ScriptDescriptor scriptDescriptor,
@NotNull JvmClassName className @NotNull Type asmType
) { ) {
ClassDescriptorImpl classDescriptor = new ClassDescriptorImpl( ClassDescriptorImpl classDescriptor = new ClassDescriptorImpl(
scriptDescriptor, scriptDescriptor,
Collections.<AnnotationDescriptor>emptyList(), Collections.<AnnotationDescriptor>emptyList(),
Modality.FINAL, Modality.FINAL,
Name.special("<script-" + className + ">")); Name.special("<script-" + asmType.getInternalName() + ">"));
classDescriptor.initialize( classDescriptor.initialize(
false, false,
Collections.<TypeParameterDescriptor>emptyList(), Collections.<TypeParameterDescriptor>emptyList(),
@@ -156,7 +155,7 @@ public class CodegenBinding {
null, null,
false); false);
recordClosure(bindingTrace, null, classDescriptor, null, className, false); recordClosure(bindingTrace, null, classDescriptor, null, asmType, false);
bindingTrace.record(CLASS_FOR_SCRIPT, scriptDescriptor, classDescriptor); bindingTrace.record(CLASS_FOR_SCRIPT, scriptDescriptor, classDescriptor);
} }
@@ -200,7 +199,7 @@ public class CodegenBinding {
@Nullable JetElement element, @Nullable JetElement element,
ClassDescriptor classDescriptor, ClassDescriptor classDescriptor,
@Nullable ClassDescriptor enclosing, @Nullable ClassDescriptor enclosing,
JvmClassName name, Type asmType,
boolean functionLiteral boolean functionLiteral
) { ) {
JetDelegatorToSuperCall superCall = findSuperCall(bindingTrace.getBindingContext(), element); JetDelegatorToSuperCall superCall = findSuperCall(bindingTrace.getBindingContext(), element);
@@ -219,8 +218,8 @@ public class CodegenBinding {
MutableClosure closure = new MutableClosure(superCall, enclosing, enclosingReceiver); MutableClosure closure = new MutableClosure(superCall, enclosing, enclosingReceiver);
assert PsiCodegenPredictor.checkPredictedNameFromPsi(bindingTrace, classDescriptor, name); assert PsiCodegenPredictor.checkPredictedNameFromPsi(bindingTrace, classDescriptor, asmType);
bindingTrace.record(FQN, classDescriptor, name); bindingTrace.record(ASM_TYPE, classDescriptor, asmType);
bindingTrace.record(CLOSURE, classDescriptor, closure); bindingTrace.record(CLOSURE, classDescriptor, closure);
// TODO: this is temporary before we have proper inner classes // TODO: this is temporary before we have proper inner classes
@@ -249,13 +248,13 @@ public class CodegenBinding {
public static void registerClassNameForScript( public static void registerClassNameForScript(
BindingTrace bindingTrace, BindingTrace bindingTrace,
@NotNull JetScript jetScript, @NotNull JetScript jetScript,
@NotNull JvmClassName className @NotNull Type asmType
) { ) {
ScriptDescriptor descriptor = bindingTrace.getBindingContext().get(SCRIPT, jetScript); ScriptDescriptor descriptor = bindingTrace.getBindingContext().get(SCRIPT, jetScript);
if (descriptor == null) { if (descriptor == null) {
throw new IllegalStateException("Descriptor is not found for PSI " + jetScript); throw new IllegalStateException("Descriptor is not found for PSI " + jetScript);
} }
registerClassNameForScript(bindingTrace, descriptor, className); registerClassNameForScript(bindingTrace, descriptor, asmType);
} }
@NotNull @NotNull
@@ -324,22 +323,22 @@ public class CodegenBinding {
} }
@NotNull @NotNull
public static JvmClassName getJvmInternalName(@NotNull BindingTrace bindingTrace, @NotNull DeclarationDescriptor descriptor) { public static Type getAsmType(@NotNull BindingTrace bindingTrace, @NotNull DeclarationDescriptor descriptor) {
descriptor = descriptor.getOriginal(); descriptor = descriptor.getOriginal();
JvmClassName alreadyComputedName = bindingTrace.getBindingContext().get(FQN, descriptor); Type alreadyComputedType = bindingTrace.getBindingContext().get(ASM_TYPE, descriptor);
if (alreadyComputedName != null) { if (alreadyComputedType != null) {
return alreadyComputedName; return alreadyComputedType;
} }
JvmClassName name = JvmClassName.byInternalName(getJvmInternalFQNameImpl(bindingTrace, descriptor)); Type asmType = Type.getObjectType(getAsmTypeImpl(bindingTrace, descriptor));
assert PsiCodegenPredictor.checkPredictedNameFromPsi(bindingTrace, descriptor, name); assert PsiCodegenPredictor.checkPredictedNameFromPsi(bindingTrace, descriptor, asmType);
bindingTrace.record(FQN, descriptor, name); bindingTrace.record(ASM_TYPE, descriptor, asmType);
return name; return asmType;
} }
@NotNull @NotNull
private static String getJvmInternalFQNameImpl(@NotNull BindingTrace bindingTrace, @NotNull DeclarationDescriptor descriptor) { private static String getAsmTypeImpl(@NotNull BindingTrace bindingTrace, @NotNull DeclarationDescriptor descriptor) {
if (descriptor instanceof FunctionDescriptor) { if (descriptor instanceof FunctionDescriptor) {
throw new IllegalStateException("requested fq name for function: " + descriptor); throw new IllegalStateException("requested fq name for function: " + descriptor);
} }
@@ -357,7 +356,7 @@ public class CodegenBinding {
return descriptor.getName().getIdentifier(); return descriptor.getName().getIdentifier();
} }
String containerInternalName = getJvmInternalName(bindingTrace, container).getInternalName(); String containerInternalName = getAsmType(bindingTrace, container).getInternalName();
if (descriptor instanceof ClassDescriptor && container instanceof ClassDescriptor) { if (descriptor instanceof ClassDescriptor && container instanceof ClassDescriptor) {
ClassDescriptor klass = (ClassDescriptor) descriptor; ClassDescriptor klass = (ClassDescriptor) descriptor;
@@ -21,6 +21,7 @@ import com.intellij.psi.PsiElement;
import com.intellij.psi.util.PsiTreeUtil; 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.asm4.Type;
import org.jetbrains.jet.codegen.NamespaceCodegen; import org.jetbrains.jet.codegen.NamespaceCodegen;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.psi.*;
@@ -30,7 +31,6 @@ import org.jetbrains.jet.lang.resolve.BindingTrace;
import org.jetbrains.jet.lang.resolve.DelegatingBindingTrace; import org.jetbrains.jet.lang.resolve.DelegatingBindingTrace;
import org.jetbrains.jet.lang.resolve.java.JvmAbi; import org.jetbrains.jet.lang.resolve.java.JvmAbi;
import org.jetbrains.jet.lang.resolve.java.JvmClassName; import org.jetbrains.jet.lang.resolve.java.JvmClassName;
import org.jetbrains.jet.lang.resolve.java.PackageClassUtils;
import org.jetbrains.jet.lang.resolve.name.FqName; import org.jetbrains.jet.lang.resolve.name.FqName;
import org.jetbrains.jet.lang.resolve.name.Name; import org.jetbrains.jet.lang.resolve.name.Name;
import org.jetbrains.jet.util.slicedmap.WritableSlice; import org.jetbrains.jet.util.slicedmap.WritableSlice;
@@ -38,18 +38,19 @@ import org.jetbrains.jet.util.slicedmap.WritableSlice;
import java.util.Collection; import java.util.Collection;
import static org.jetbrains.jet.lang.resolve.BindingContextUtils.descriptorToDeclaration; import static org.jetbrains.jet.lang.resolve.BindingContextUtils.descriptorToDeclaration;
import static org.jetbrains.jet.lang.resolve.java.PackageClassUtils.getPackageClassFqName;
public final class PsiCodegenPredictor { public final class PsiCodegenPredictor {
private PsiCodegenPredictor() { private PsiCodegenPredictor() {
} }
public static boolean checkPredictedNameFromPsi( public static boolean checkPredictedNameFromPsi(
@NotNull BindingTrace bindingTrace, @NotNull DeclarationDescriptor descriptor, JvmClassName nameFromDescriptors @NotNull BindingTrace bindingTrace, @NotNull DeclarationDescriptor descriptor, @Nullable Type nameFromDescriptors
) { ) {
PsiElement element = descriptorToDeclaration(bindingTrace.getBindingContext(), descriptor); PsiElement element = descriptorToDeclaration(bindingTrace.getBindingContext(), descriptor);
if (element instanceof JetDeclaration) { if (element instanceof JetDeclaration) {
JvmClassName classNameFromPsi = getPredefinedJvmClassName((JetDeclaration) element); String classNameFromPsi = getPredefinedJvmInternalName((JetDeclaration) element);
assert classNameFromPsi == null || classNameFromPsi.equals(nameFromDescriptors) : assert classNameFromPsi == null || Type.getObjectType(classNameFromPsi).equals(nameFromDescriptors) :
String.format("Invalid algorithm for getting qualified name from psi! Predicted: %s, actual %s\n" + String.format("Invalid algorithm for getting qualified name from psi! Predicted: %s, actual %s\n" +
"Element: %s", classNameFromPsi, nameFromDescriptors, element.getText()); "Element: %s", classNameFromPsi, nameFromDescriptors, element.getText());
} }
@@ -57,97 +58,79 @@ public final class PsiCodegenPredictor {
return true; return true;
} }
@Nullable
public static JvmClassName getPredefinedJvmClassName(@NotNull JetFile jetFile, boolean withNamespace) {
String packageName = jetFile.getPackageName();
if (packageName == null) {
return null;
}
JvmClassName packageJvmName = JvmClassName.byFqNameWithoutInnerClasses(packageName);
return !withNamespace ? packageJvmName : addPackageClass(packageJvmName);
}
/** /**
* TODO: Finish this method for all cases. Now it's only used and tested in JetLightClass. * TODO: Finish this method for all cases. Now it's only used and tested in JetLightClass.
* *
* @return null if no prediction can be done. * @return null if no prediction can be done.
*/ */
@Nullable @Nullable
public static JvmClassName getPredefinedJvmClassName(@NotNull JetDeclaration declaration) { public static String getPredefinedJvmInternalName(@NotNull JetDeclaration declaration) {
// TODO: Method won't work for declarations inside class objects // TODO: Method won't work for declarations inside class objects
// TODO: Method won't give correct class name for traits implementations // TODO: Method won't give correct class name for traits implementations
JetDeclaration parentDeclaration = PsiTreeUtil.getParentOfType(declaration, JetDeclaration.class); JetDeclaration parentDeclaration = PsiTreeUtil.getParentOfType(declaration, JetDeclaration.class);
if (parentDeclaration instanceof JetClassObject) { if (parentDeclaration instanceof JetClassObject) {
assert declaration instanceof JetObjectDeclaration : "Only object declarations can be children of JetClassObject: " + declaration; assert declaration instanceof JetObjectDeclaration : "Only object declarations can be children of JetClassObject: " + declaration;
return getPredefinedJvmClassName(parentDeclaration); return getPredefinedJvmInternalName(parentDeclaration);
} }
JvmClassName parentClassName = parentDeclaration != null ? String parentInternalName;
getPredefinedJvmClassName(parentDeclaration) : if (parentDeclaration != null) {
getPredefinedJvmClassName((JetFile) declaration.getContainingFile(), false); parentInternalName = getPredefinedJvmInternalName(parentDeclaration);
if (parentClassName == null) { if (parentInternalName == null) {
return null; return null;
}
}
else {
String packageName = ((JetFile) declaration.getContainingFile()).getPackageName();
if (packageName == null) {
return null;
}
parentInternalName = JvmClassName.byFqNameWithoutInnerClasses(packageName).getInternalName();
} }
if (declaration instanceof JetClassObject) { if (declaration instanceof JetClassObject) {
// Get parent and assign Class object prefix // Get parent and assign Class object prefix
return JvmClassName.byInternalName(parentClassName.getInternalName() + JvmAbi.CLASS_OBJECT_SUFFIX); return parentInternalName + JvmAbi.CLASS_OBJECT_SUFFIX;
} }
if (declaration instanceof JetNamedDeclaration) { if (!PsiTreeUtil.instanceOf(declaration, JetClass.class, JetObjectDeclaration.class, JetNamedFunction.class, JetProperty.class) ||
if (!PsiTreeUtil.instanceOf(declaration, JetClass.class, JetObjectDeclaration.class, JetNamedFunction.class, JetProperty.class) || declaration instanceof JetEnumEntry) {
declaration instanceof JetEnumEntry) { // Other subclasses are not valid for class name prediction.
// Other subclasses are not valid for class name prediction. // For example EnumEntry, JetFunctionLiteral
// For example EnumEntry, JetFunctionLiteral return null;
return null;
}
JetNamedDeclaration namedDeclaration = (JetNamedDeclaration) declaration;
Name name = namedDeclaration.getNameAsName();
if (name == null) {
return null;
}
FqName fqName = parentClassName.getFqName();
if (declaration instanceof JetNamedFunction) {
if (parentDeclaration == null) {
JvmClassName packageClass = addPackageClass(parentClassName);
return JvmClassName.byInternalName(packageClass.getInternalName() + "$" + name.asString());
}
if (!(parentDeclaration instanceof JetClass || parentDeclaration instanceof JetObjectDeclaration)) {
// Can't generate predefined name for internal functions
return null;
}
}
// NOTE: looks like a bug - for class in getter of top level property class name will be $propertyName$ClassName but not
// namespace$propertyName$ClassName
if (declaration instanceof JetProperty) {
return JvmClassName.byInternalName(parentClassName.getInternalName() + "$" + name.asString());
}
if (fqName.isRoot()) {
return JvmClassName.byInternalName(name.asString());
}
return JvmClassName.byInternalName(parentDeclaration == null ?
parentClassName.getInternalName() + "/" + name.asString() :
parentClassName.getInternalName() + "$" + name.asString());
} }
return null; JetNamedDeclaration namedDeclaration = (JetNamedDeclaration) declaration;
} Name name = namedDeclaration.getNameAsName();
if (name == null) {
return null;
}
private static JvmClassName addPackageClass(JvmClassName packageName) { if (declaration instanceof JetNamedFunction) {
FqName name = packageName.getFqName(); if (parentDeclaration == null) {
String packageClassName = PackageClassUtils.getPackageClassName(name); FqName fqName = JvmClassName.byInternalName(parentInternalName).getFqName();
return name.isRoot() ? JvmClassName packageClass = JvmClassName.byFqNameWithoutInnerClasses(getPackageClassFqName(fqName));
JvmClassName.byFqNameWithoutInnerClasses(packageClassName) : return packageClass.getInternalName() + "$" + name.asString();
JvmClassName.byInternalName(packageName.getInternalName() + "/" + packageClassName); }
if (!(parentDeclaration instanceof JetClass || parentDeclaration instanceof JetObjectDeclaration)) {
// Can't generate predefined name for internal functions
return null;
}
}
// NOTE: looks like a bug - for class in getter of top level property class name will be $propertyName$ClassName but not
// namespace$propertyName$ClassName
if (declaration instanceof JetProperty) {
return parentInternalName + "$" + name.asString();
}
if (parentInternalName.isEmpty()) {
return name.asString();
}
return parentInternalName + (parentDeclaration == null ? "/" : "$") + name.asString();
} }
@Nullable @Nullable
@@ -166,7 +149,7 @@ public final class PsiCodegenPredictor {
public static JetFile getFileForCodegenNamedClass( public static JetFile getFileForCodegenNamedClass(
@NotNull BindingContext context, @NotNull BindingContext context,
@NotNull Collection<JetFile> allNamespaceFiles, @NotNull Collection<JetFile> allNamespaceFiles,
@NotNull final JvmClassName className @NotNull final String classInternalName
) { ) {
final Ref<DeclarationDescriptor> resultingDescriptor = Ref.create(); final Ref<DeclarationDescriptor> resultingDescriptor = Ref.create();
@@ -174,8 +157,8 @@ public final class PsiCodegenPredictor {
@Override @Override
public <K, V> void record(WritableSlice<K, V> slice, K key, V value) { public <K, V> void record(WritableSlice<K, V> slice, K key, V value) {
super.record(slice, key, value); super.record(slice, key, value);
if (slice == CodegenBinding.FQN && key instanceof DeclarationDescriptor) { if (slice == CodegenBinding.ASM_TYPE && key instanceof DeclarationDescriptor && value instanceof Type) {
if (className.equals(value)) { if (classInternalName.equals(((Type) value).getInternalName())) {
resultingDescriptor.set((DeclarationDescriptor) key); resultingDescriptor.set((DeclarationDescriptor) key);
} }
} }
@@ -29,7 +29,6 @@ import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
import org.jetbrains.jet.lang.descriptors.impl.ConstructorDescriptorImpl; import org.jetbrains.jet.lang.descriptors.impl.ConstructorDescriptorImpl;
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.JvmClassName;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
@@ -278,7 +277,7 @@ public abstract class CodegenContext<T extends DeclarationDescriptor> {
ClassDescriptor enclosingClass = getEnclosingClass(); ClassDescriptor enclosingClass = getEnclosingClass();
outerExpression = enclosingClass != null && canHaveOuter(typeMapper.getBindingContext(), classDescriptor) outerExpression = enclosingClass != null && canHaveOuter(typeMapper.getBindingContext(), classDescriptor)
? StackValue.field(typeMapper.mapType(enclosingClass), ? StackValue.field(typeMapper.mapType(enclosingClass),
CodegenBinding.getJvmInternalName(typeMapper.getBindingTrace(), classDescriptor).getAsmType(), CodegenBinding.getAsmType(typeMapper.getBindingTrace(), classDescriptor),
CAPTURED_THIS_FIELD, CAPTURED_THIS_FIELD,
false) false)
: null; : null;
@@ -295,8 +294,7 @@ public abstract class CodegenContext<T extends DeclarationDescriptor> {
for (LocalLookup.LocalLookupCase aCase : LocalLookup.LocalLookupCase.values()) { for (LocalLookup.LocalLookupCase aCase : LocalLookup.LocalLookupCase.values()) {
if (aCase.isCase(d, state)) { if (aCase.isCase(d, state)) {
JvmClassName className = state.getBindingContext().get(FQN, getThisDescriptor()); Type classType = state.getBindingContext().get(ASM_TYPE, getThisDescriptor());
Type classType = className == null ? null : className.getAsmType();
StackValue innerValue = aCase.innerValue(d, enclosingLocalLookup, state, closure, classType); StackValue innerValue = aCase.innerValue(d, enclosingLocalLookup, state, closure, classType);
if (innerValue == null) { if (innerValue == null) {
break; break;
@@ -334,13 +334,13 @@ public class JetTypeMapper extends BindingTraceAware {
} }
if (descriptor instanceof ClassDescriptor) { if (descriptor instanceof ClassDescriptor) {
JvmClassName name = getJvmInternalName(bindingTrace, descriptor); Type descriptorAsmType = getAsmType(bindingTrace, descriptor);
Type asmType; Type asmType;
if (kind == JetTypeMapperMode.TRAIT_IMPL) { if (kind == JetTypeMapperMode.TRAIT_IMPL) {
asmType = Type.getObjectType(name.getInternalName() + JvmAbi.TRAIT_IMPL_SUFFIX); asmType = Type.getObjectType(descriptorAsmType.getInternalName() + JvmAbi.TRAIT_IMPL_SUFFIX);
} }
else { else {
asmType = name.getAsmType(); asmType = descriptorAsmType;
} }
writeGenericType(signatureVisitor, asmType, jetType, howThisTypeIsUsed); writeGenericType(signatureVisitor, asmType, jetType, howThisTypeIsUsed);
@@ -43,8 +43,8 @@ import org.jetbrains.jet.codegen.binding.PsiCodegenPredictor;
import org.jetbrains.jet.lang.descriptors.ClassDescriptor; import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.DescriptorUtils; import org.jetbrains.jet.lang.resolve.DescriptorUtils;
import org.jetbrains.jet.lang.resolve.java.jetAsJava.JetJavaMirrorMarker;
import org.jetbrains.jet.lang.resolve.java.JvmClassName; import org.jetbrains.jet.lang.resolve.java.JvmClassName;
import org.jetbrains.jet.lang.resolve.java.jetAsJava.JetJavaMirrorMarker;
import org.jetbrains.jet.lang.resolve.name.FqName; import org.jetbrains.jet.lang.resolve.name.FqName;
import org.jetbrains.jet.lang.resolve.name.FqNameUnsafe; import org.jetbrains.jet.lang.resolve.name.FqNameUnsafe;
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
@@ -66,10 +66,10 @@ public class KotlinLightClassForExplicitDeclaration extends AbstractLightClass i
return null; return null;
} }
JvmClassName jvmClassName = PsiCodegenPredictor.getPredefinedJvmClassName(classOrObject); String jvmInternalName = PsiCodegenPredictor.getPredefinedJvmInternalName(classOrObject);
if (jvmClassName == null) return null; if (jvmInternalName == null) return null;
return new KotlinLightClassForExplicitDeclaration(manager, jvmClassName.getFqName(), classOrObject); return new KotlinLightClassForExplicitDeclaration(manager, JvmClassName.byInternalName(jvmInternalName).getFqName(), classOrObject);
} }
private final FqName classFqName; // FqName of (possibly inner) class private final FqName classFqName; // FqName of (possibly inner) class
@@ -36,11 +36,10 @@ import com.intellij.util.PathUtil;
import com.intellij.util.SmartList; import com.intellij.util.SmartList;
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.binding.PsiCodegenPredictor;
import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.java.jetAsJava.JetClsMethod;
import org.jetbrains.jet.lang.resolve.java.JvmAbi; import org.jetbrains.jet.lang.resolve.java.JvmAbi;
import org.jetbrains.jet.lang.resolve.java.JvmClassName; import org.jetbrains.jet.lang.resolve.java.PackageClassUtils;
import org.jetbrains.jet.lang.resolve.java.jetAsJava.JetClsMethod;
import org.jetbrains.jet.lang.resolve.name.FqName; import org.jetbrains.jet.lang.resolve.name.FqName;
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
import org.jetbrains.jet.utils.ExceptionUtils; import org.jetbrains.jet.utils.ExceptionUtils;
@@ -235,12 +234,11 @@ public class LightClassUtil {
if (parent instanceof JetFile) { if (parent instanceof JetFile) {
// top-level declaration // top-level declaration
JvmClassName jvmName = PsiCodegenPredictor.getPredefinedJvmClassName((JetFile) parent, true); FqName fqName = getPackageClassNameForFile((JetFile) parent);
if (jvmName != null) { if (fqName != null) {
Project project = declaration.getProject(); Project project = declaration.getProject();
String fqName = jvmName.getFqName().asString(); return JavaElementFinder.getInstance(project).findClass(fqName.asString(), GlobalSearchScope.allScope(project));
return JavaElementFinder.getInstance(project).findClass(fqName, GlobalSearchScope.allScope(project));
} }
} }
else if (parent instanceof JetClassBody) { else if (parent instanceof JetClassBody) {
@@ -251,6 +249,12 @@ public class LightClassUtil {
return null; return null;
} }
@Nullable
private static FqName getPackageClassNameForFile(@NotNull JetFile jetFile) {
String packageName = jetFile.getPackageName();
return packageName == null ? null : PackageClassUtils.getPackageClassFqName(new FqName(packageName));
}
private static PropertyAccessorsPsiMethods extractPropertyAccessors( private static PropertyAccessorsPsiMethods extractPropertyAccessors(
@NotNull JetDeclaration jetDeclaration, @NotNull JetDeclaration jetDeclaration,
@Nullable PsiMethod specialGetter, @Nullable PsiMethod specialSetter @Nullable PsiMethod specialGetter, @Nullable PsiMethod specialSetter
@@ -375,11 +375,11 @@ public class JetSourceNavigationHelper {
@Nullable @Nullable
public static PsiClass getOriginalClass(@NotNull JetClassOrObject classOrObject) { public static PsiClass getOriginalClass(@NotNull JetClassOrObject classOrObject) {
// Copied from JavaPsiImplementationHelperImpl:getOriginalClass() // Copied from JavaPsiImplementationHelperImpl:getOriginalClass()
JvmClassName className = PsiCodegenPredictor.getPredefinedJvmClassName(classOrObject); String internalName = PsiCodegenPredictor.getPredefinedJvmInternalName(classOrObject);
if (className == null) { if (internalName == null) {
return null; return null;
} }
String fqName = className.getFqName().asString(); String fqName = JvmClassName.byInternalName(internalName).getFqName().asString();
JetFile file = (JetFile) classOrObject.getContainingFile(); JetFile file = (JetFile) classOrObject.getContainingFile();
@@ -74,7 +74,7 @@ public class DebuggerUtils {
// we may actually need to analyze the project in order to find a file which produces this class // we may actually need to analyze the project in order to find a file which produces this class
AnalyzeExhaust analyzeExhaust = AnalyzerFacadeWithCache.analyzeFileWithCache(anyFile); AnalyzeExhaust analyzeExhaust = AnalyzerFacadeWithCache.analyzeFileWithCache(anyFile);
return PsiCodegenPredictor.getFileForCodegenNamedClass(analyzeExhaust.getBindingContext(), allNamespaceFiles, className); return PsiCodegenPredictor.getFileForCodegenNamedClass(analyzeExhaust.getBindingContext(), allNamespaceFiles, className.getInternalName());
} }
@NotNull @NotNull