unification of codegen for singletons between object declarations, classobjects and const closures
This commit is contained in:
@@ -22,7 +22,6 @@ package org.jetbrains.jet.codegen;
|
||||
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import org.jetbrains.asm4.Label;
|
||||
import org.jetbrains.asm4.MethodVisitor;
|
||||
import org.jetbrains.asm4.Type;
|
||||
import org.jetbrains.asm4.commons.InstructionAdapter;
|
||||
@@ -41,6 +40,7 @@ import org.jetbrains.jet.lang.psi.JetElement;
|
||||
import org.jetbrains.jet.lang.psi.JetExpression;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContextUtils;
|
||||
import org.jetbrains.jet.lang.resolve.java.JvmAbi;
|
||||
import org.jetbrains.jet.lang.resolve.java.JvmClassName;
|
||||
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor;
|
||||
import org.jetbrains.jet.lang.types.JetType;
|
||||
@@ -49,10 +49,10 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static org.jetbrains.asm4.Opcodes.*;
|
||||
import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.OBJECT_TYPE;
|
||||
import static org.jetbrains.jet.codegen.CodegenUtil.*;
|
||||
import static org.jetbrains.jet.codegen.binding.CodegenBinding.classNameForAnonymousClass;
|
||||
import static org.jetbrains.jet.codegen.binding.CodegenBinding.isLocalNamedFun;
|
||||
import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.OBJECT_TYPE;
|
||||
|
||||
public class ClosureCodegen extends GenerationStateAware {
|
||||
|
||||
@@ -116,31 +116,19 @@ public class ClosureCodegen extends GenerationStateAware {
|
||||
}
|
||||
|
||||
private void generateConstInstance(PsiElement fun, ClassBuilder cv) {
|
||||
String classDescr = name.getDescriptor();
|
||||
cv.newField(fun, ACC_PRIVATE | ACC_STATIC | ACC_FINAL | ACC_SYNTHETIC, "$instance", classDescr, null, null);
|
||||
MethodVisitor mv = cv.newMethod(fun, ACC_PUBLIC | ACC_STATIC | ACC_SYNTHETIC, "<clinit>", "()V", null, new String[0]);
|
||||
final InstructionAdapter iv = new InstructionAdapter(mv);
|
||||
|
||||
cv.newField(fun, ACC_PUBLIC | ACC_STATIC | ACC_FINAL, JvmAbi.INSTANCE_FIELD, name.getDescriptor(), null, null);
|
||||
|
||||
MethodVisitor mv =
|
||||
cv.newMethod(fun, ACC_PUBLIC | ACC_STATIC | ACC_SYNTHETIC, "$getInstance", "()" + classDescr, null, new String[0]);
|
||||
if (state.getClassBuilderMode() == ClassBuilderMode.STUBS) {
|
||||
StubCodegen.generateStubCode(mv);
|
||||
}
|
||||
else if (state.getClassBuilderMode() == ClassBuilderMode.FULL) {
|
||||
mv.visitCode();
|
||||
mv.visitFieldInsn(GETSTATIC, name.getInternalName(), "$instance", classDescr);
|
||||
mv.visitInsn(DUP);
|
||||
Label ret = new Label();
|
||||
mv.visitJumpInsn(IFNONNULL, ret);
|
||||
|
||||
mv.visitInsn(POP);
|
||||
mv.visitTypeInsn(NEW, name.getInternalName());
|
||||
mv.visitInsn(DUP);
|
||||
mv.visitMethodInsn(INVOKESPECIAL, name.getInternalName(), "<init>", "()V");
|
||||
mv.visitInsn(DUP);
|
||||
mv.visitFieldInsn(PUTSTATIC, name.getInternalName(), "$instance", classDescr);
|
||||
|
||||
mv.visitLabel(ret);
|
||||
mv.visitInsn(ARETURN);
|
||||
FunctionCodegen.endVisit(mv, "$getInstance", fun);
|
||||
initSingletonField(fun, name.getAsmType(), cv, iv);
|
||||
mv.visitInsn(RETURN);
|
||||
FunctionCodegen.endVisit(mv, "<clinit>", fun);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -49,8 +49,8 @@ import org.jetbrains.jet.lang.types.lang.JetStandardLibrary;
|
||||
import java.util.*;
|
||||
|
||||
import static org.jetbrains.asm4.Opcodes.*;
|
||||
import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.OBJECT_TYPE;
|
||||
import static org.jetbrains.jet.lang.resolve.DescriptorUtils.isClassObject;
|
||||
import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.OBJECT_TYPE;
|
||||
|
||||
/**
|
||||
* @author abreslav
|
||||
@@ -364,4 +364,11 @@ public class CodegenUtil {
|
||||
throw new IllegalStateException("code generation for synthesized members should be handled separately");
|
||||
}
|
||||
}
|
||||
|
||||
public static void initSingletonField(PsiElement element, Type classAsmType, ClassBuilder builder, InstructionAdapter iv) {
|
||||
iv.anew(classAsmType);
|
||||
iv.dup();
|
||||
iv.invokespecial(classAsmType.getInternalName(), "<init>", "()V");
|
||||
iv.putstatic(classAsmType.getInternalName(), JvmAbi.INSTANCE_FIELD, classAsmType.getDescriptor());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,6 +48,7 @@ import org.jetbrains.jet.lang.resolve.BindingContextUtils;
|
||||
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
|
||||
import org.jetbrains.jet.lang.resolve.calls.*;
|
||||
import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
|
||||
import org.jetbrains.jet.lang.resolve.java.JvmAbi;
|
||||
import org.jetbrains.jet.lang.resolve.java.JvmClassName;
|
||||
import org.jetbrains.jet.lang.resolve.scopes.receivers.*;
|
||||
import org.jetbrains.jet.lang.types.JetType;
|
||||
@@ -1046,9 +1047,8 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
||||
|
||||
final JvmClassName className = closureCodegen.name;
|
||||
final Type asmType = className.getAsmType();
|
||||
final String internalName = className.getInternalName();
|
||||
if (isConst(closure)) {
|
||||
v.invokestatic(internalName, "$getInstance", "()" + className.getDescriptor());
|
||||
v.getstatic(className.getInternalName(), JvmAbi.INSTANCE_FIELD, className.getDescriptor());
|
||||
}
|
||||
else {
|
||||
v.anew(asmType);
|
||||
@@ -1056,7 +1056,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
||||
|
||||
final Method cons = closureCodegen.constructor;
|
||||
pushClosureOnStack(closure, false);
|
||||
v.invokespecial(internalName, "<init>", cons.getDescriptor());
|
||||
v.invokespecial(className.getInternalName(), "<init>", cons.getDescriptor());
|
||||
}
|
||||
return StackValue.onStack(asmType);
|
||||
}
|
||||
@@ -1870,7 +1870,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
||||
v.load(0, OBJECT_TYPE);
|
||||
}
|
||||
else {
|
||||
v.getstatic(exprType.getInternalName(), "$instance", exprType.getDescriptor());
|
||||
v.getstatic(exprType.getInternalName(), JvmAbi.INSTANCE_FIELD, exprType.getDescriptor());
|
||||
}
|
||||
StackValue.onStack(exprType).put(type, v);
|
||||
}
|
||||
|
||||
@@ -200,7 +200,8 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
||||
|
||||
if (descriptor.getClassObjectDescriptor() != null) {
|
||||
int innerClassAccess = ACC_PUBLIC | ACC_FINAL | ACC_STATIC;
|
||||
v.visitInnerClass(classAsmType.getInternalName() + JvmAbi.CLASS_OBJECT_SUFFIX, classAsmType.getInternalName(), JvmAbi.CLASS_OBJECT_CLASS_NAME,
|
||||
v.visitInnerClass(classAsmType.getInternalName() + JvmAbi.CLASS_OBJECT_SUFFIX, classAsmType.getInternalName(),
|
||||
JvmAbi.CLASS_OBJECT_CLASS_NAME,
|
||||
innerClassAccess);
|
||||
}
|
||||
}
|
||||
@@ -330,8 +331,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
||||
|
||||
@Override
|
||||
protected void generateSyntheticParts() {
|
||||
generateFieldForObjectInstance();
|
||||
generateFieldForClassObject();
|
||||
generateFieldForSingleton();
|
||||
|
||||
try {
|
||||
generatePrimaryConstructor();
|
||||
@@ -571,37 +571,15 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
||||
}
|
||||
}
|
||||
|
||||
private void generateFieldForObjectInstance() {
|
||||
if (isNonLiteralObject(myClass)) {
|
||||
Type type = typeMapper.mapType(descriptor);
|
||||
v.newField(myClass, ACC_PUBLIC | ACC_STATIC | ACC_FINAL, "$instance", type.getDescriptor(), null, null);
|
||||
private void generateFieldForSingleton() {
|
||||
if (!(isNonLiteralObject(myClass) || descriptor.getKind() == ClassKind.CLASS_OBJECT)) return;
|
||||
|
||||
staticInitializerChunks.add(new CodeChunk() {
|
||||
@Override
|
||||
public void generate(InstructionAdapter v) {
|
||||
String name = jvmName();
|
||||
v.anew(Type.getObjectType(name));
|
||||
v.dup();
|
||||
v.invokespecial(name, "<init>", "()V");
|
||||
v.putstatic(name, "$instance",
|
||||
typeMapper.mapType(descriptor).getDescriptor());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void generateFieldForClassObject() {
|
||||
if (descriptor.getKind() != ClassKind.CLASS_OBJECT) return;
|
||||
|
||||
v.newField(myClass, ACC_PUBLIC | ACC_STATIC | ACC_FINAL , "$instance", classAsmType.getDescriptor(), null, null);
|
||||
v.newField(myClass, ACC_PUBLIC | ACC_STATIC | ACC_FINAL, JvmAbi.INSTANCE_FIELD, classAsmType.getDescriptor(), null, null);
|
||||
|
||||
staticInitializerChunks.add(new CodeChunk() {
|
||||
@Override
|
||||
public void generate(InstructionAdapter v) {
|
||||
v.anew(classAsmType);
|
||||
v.dup();
|
||||
v.invokespecial(classAsmType.getInternalName(), "<init>", "()V");
|
||||
v.putstatic(typeMapper.mapType(descriptor).getInternalName(), "$instance", classAsmType.getDescriptor());
|
||||
public void generate(InstructionAdapter iv) {
|
||||
initSingletonField(myClass, classAsmType, v, iv);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ import org.jetbrains.jet.codegen.state.JetTypeMapper;
|
||||
import org.jetbrains.jet.lang.descriptors.*;
|
||||
import org.jetbrains.jet.lang.psi.JetExpression;
|
||||
import org.jetbrains.jet.lang.resolve.calls.ResolvedCall;
|
||||
import org.jetbrains.jet.lang.resolve.java.JvmAbi;
|
||||
import org.jetbrains.jet.lang.resolve.java.JvmClassName;
|
||||
import org.jetbrains.jet.lang.resolve.java.JvmPrimitiveType;
|
||||
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor;
|
||||
@@ -360,7 +361,7 @@ public abstract class StackValue {
|
||||
|
||||
final ClassKind kind = classDescriptor.getKind();
|
||||
if (kind == ClassKind.CLASS_OBJECT || kind == ClassKind.OBJECT) {
|
||||
return field(type, JvmClassName.byInternalName(type.getInternalName()), "$instance", true);
|
||||
return field(type, JvmClassName.byInternalName(type.getInternalName()), JvmAbi.INSTANCE_FIELD, true);
|
||||
}
|
||||
else if (kind == ClassKind.ENUM_ENTRY) {
|
||||
final JvmClassName owner = typeMapper.getBindingContext()
|
||||
|
||||
@@ -31,6 +31,8 @@ public class JvmAbi {
|
||||
public static final String CLASS_OBJECT_CLASS_NAME = "ClassObject$";
|
||||
public static final String CLASS_OBJECT_SUFFIX = "$" + CLASS_OBJECT_CLASS_NAME;
|
||||
|
||||
public static final String INSTANCE_FIELD = "$instance";
|
||||
|
||||
public static final JvmClassName JETBRAINS_NOT_NULL_ANNOTATION =
|
||||
JvmClassName.byFqNameWithoutInnerClasses("org.jetbrains.annotations.NotNull");
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ import org.jetbrains.jet.lang.psi.JetClass;
|
||||
import org.jetbrains.jet.lang.psi.JetFile;
|
||||
import org.jetbrains.jet.lang.psi.JetNamedFunction;
|
||||
import org.jetbrains.jet.lang.psi.JetPsiUtil;
|
||||
import org.jetbrains.jet.lang.resolve.java.JvmAbi;
|
||||
import org.jetbrains.jet.plugin.JetLightProjectDescriptor;
|
||||
import org.jetbrains.jet.plugin.PluginTestCaseBase;
|
||||
|
||||
@@ -114,7 +115,7 @@ public class JetJavaFacadeTest extends LightCodeInsightFixtureTestCase {
|
||||
assertEquals("foo.TheClass.ClassObject$", classObjectClass.getQualifiedName());
|
||||
assertTrue(classObjectClass.hasModifierProperty(PsiModifier.STATIC));
|
||||
|
||||
final PsiField instance = classObjectClass.findFieldByName("$instance", false);
|
||||
final PsiField instance = classObjectClass.findFieldByName(JvmAbi.INSTANCE_FIELD, false);
|
||||
assertNotNull(instance);
|
||||
assertEquals("foo.TheClass.ClassObject$", instance.getType().getCanonicalText());
|
||||
assertTrue(instance.hasModifierProperty(PsiModifier.PUBLIC));
|
||||
|
||||
Reference in New Issue
Block a user