unification of codegen for singletons between object declarations, classobjects and const closures

This commit is contained in:
Alex Tkachman
2012-09-15 22:54:38 +03:00
parent f8983d8516
commit 99196c187b
7 changed files with 35 additions and 58 deletions
@@ -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));