refactored generation of static initializer

This commit is contained in:
Dmitry Jemerov
2011-07-12 17:34:05 +02:00
parent 2f3c5b0912
commit 57f4f664ba
3 changed files with 95 additions and 55 deletions
@@ -4,8 +4,11 @@ import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
import org.jetbrains.jet.lang.descriptors.PropertyDescriptor;
import org.jetbrains.jet.lang.psi.*;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.commons.InstructionAdapter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -22,6 +25,8 @@ public abstract class ClassBodyCodegen {
protected final ClassVisitor v;
protected final ClassContext context;
protected final List<CodeChunk> staticInitializerChunks = new ArrayList<CodeChunk>();
public ClassBodyCodegen(JetClassOrObject aClass, ClassContext context, ClassVisitor v, GenerationState state) {
this.state = state;
descriptor = state.getBindingContext().getClassDescriptor(aClass);
@@ -38,6 +43,8 @@ public abstract class ClassBodyCodegen {
generateClassBody();
generateStaticInitializer();
v.visitEnd();
}
@@ -95,4 +102,23 @@ public abstract class ClassBodyCodegen {
}
return Collections.emptyList();
}
private void generateStaticInitializer() {
if (staticInitializerChunks.size() > 0) {
final MethodVisitor mv = v.visitMethod(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC,
"<clinit>", "()V", null, null);
mv.visitCode();
InstructionAdapter v = new InstructionAdapter(mv);
for (CodeChunk chunk : staticInitializerChunks) {
chunk.generate(v);
}
mv.visitInsn(Opcodes.RETURN);
mv.visitMaxs(0, 0);
mv.visitEnd();
}
}
}
@@ -0,0 +1,10 @@
package org.jetbrains.jet.codegen;
import org.objectweb.asm.commons.InstructionAdapter;
/**
* @author yole
*/
public interface CodeChunk {
void generate(InstructionAdapter v);
}
@@ -74,20 +74,9 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
@Override
protected void generateSyntheticParts() {
int typeinfoStatic = descriptor.getTypeConstructor().getParameters().size() > 0 ? 0 : Opcodes.ACC_STATIC;
v.visitField(Opcodes.ACC_PRIVATE | typeinfoStatic, "$typeInfo", "Ljet/typeinfo/TypeInfo;", null, null);
if (isNonLiteralObject()) {
Type type = JetTypeMapper.jetImplementationType(descriptor);
v.visitField(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, "$instance", type.getDescriptor(), null, null);
}
final JetClassObject classObject = getClassObject();
if (classObject != null) {
Type type = Type.getObjectType(state.getTypeMapper().jvmName(classObject));
v.visitField(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, "$classobj", type.getDescriptor(), null, null);
}
generateStaticInitializer();
generateFieldForTypeInfo();
generateFieldForObjectInstance();
generateFieldForClassObject();
try {
generatePrimaryConstructor();
@@ -99,6 +88,62 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
generateGetTypeInfo();
}
private void generateFieldForTypeInfo() {
final boolean typeInfoIsStatic = descriptor.getTypeConstructor().getParameters().size() == 0;
v.visitField(Opcodes.ACC_PRIVATE | (typeInfoIsStatic ? Opcodes.ACC_STATIC : 0), "$typeInfo",
"Ljet/typeinfo/TypeInfo;", null, null);
if (typeInfoIsStatic) {
staticInitializerChunks.add(new CodeChunk() {
@Override
public void generate(InstructionAdapter v) {
JetTypeMapper typeMapper = state.getTypeMapper();
ClassCodegen.newTypeInfo(v, false, typeMapper.jvmType(descriptor, OwnerKind.INTERFACE));
v.putstatic(typeMapper.jvmName(descriptor, kind), "$typeInfo", "Ljet/typeinfo/TypeInfo;");
}
});
}
}
private void generateFieldForObjectInstance() {
if (isNonLiteralObject()) {
Type type = JetTypeMapper.jetImplementationType(descriptor);
v.visitField(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, "$instance", type.getDescriptor(), null, null);
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", JetTypeMapper.jetImplementationType(descriptor).getDescriptor());
}
});
}
}
private void generateFieldForClassObject() {
final JetClassObject classObject = getClassObject();
if (classObject != null) {
Type type = Type.getObjectType(state.getTypeMapper().jvmName(classObject));
v.visitField(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, "$classobj", type.getDescriptor(), null, null);
staticInitializerChunks.add(new CodeChunk() {
@Override
public void generate(InstructionAdapter v) {
String name = state.getTypeMapper().jvmName(classObject);
final Type classObjectType = Type.getObjectType(name);
v.anew(classObjectType);
v.dup();
v.invokespecial(name, "<init>", "()V");
v.putstatic(state.getTypeMapper().jvmName(descriptor, OwnerKind.IMPLEMENTATION), "$classobj",
classObjectType.getDescriptor());
}
});
}
}
protected void generatePrimaryConstructor() {
ConstructorDescriptor constructorDescriptor = state.getBindingContext().getConstructorDescriptor((JetElement) myClass);
if (constructorDescriptor == null && !(myClass instanceof JetObjectDeclaration)) return;
@@ -409,47 +454,6 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
}
}
private void generateStaticInitializer() {
boolean needTypeInfo = descriptor.getTypeConstructor().getParameters().size() == 0;
boolean needInstance = isNonLiteralObject();
JetClassObject classObject = getClassObject();
if (!needTypeInfo && !needInstance && classObject == null) {
return;
}
final MethodVisitor mv = v.visitMethod(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC,
"<clinit>", "()V", null, null);
mv.visitCode();
InstructionAdapter v = new InstructionAdapter(mv);
if (needTypeInfo) {
JetTypeMapper typeMapper = state.getTypeMapper();
ClassCodegen.newTypeInfo(v, false, typeMapper.jvmType(descriptor, OwnerKind.INTERFACE));
v.putstatic(typeMapper.jvmName(descriptor, kind), "$typeInfo", "Ljet/typeinfo/TypeInfo;");
}
if (needInstance) {
String name = jvmName();
v.anew(Type.getObjectType(name));
v.dup();
v.invokespecial(name, "<init>", "()V");
v.putstatic(name, "$instance", JetTypeMapper.jetImplementationType(descriptor).getDescriptor());
}
if (classObject != null) {
String name = state.getTypeMapper().jvmName(classObject);
final Type classObjectType = Type.getObjectType(name);
v.anew(classObjectType);
v.dup();
v.invokespecial(name, "<init>", "()V");
v.putstatic(state.getTypeMapper().jvmName(descriptor, OwnerKind.IMPLEMENTATION), "$classobj",
classObjectType.getDescriptor());
}
mv.visitInsn(Opcodes.RETURN);
mv.visitMaxs(0, 0);
mv.visitEnd();
}
@Nullable
private JetClassObject getClassObject() {
return myClass instanceof JetClass ? ((JetClass) myClass).getClassObject() : null;