Merge remote branch 'origin/master'

This commit is contained in:
Andrey Breslav
2011-07-12 21:55:50 +04:00
8 changed files with 195 additions and 75 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();
}
}
}
@@ -25,13 +25,15 @@ public class ClassCodegen {
else {
generateInterface(parentContext, aClass);
generateImplementation(parentContext, aClass, OwnerKind.IMPLEMENTATION);
generateImplementation(parentContext, aClass, OwnerKind.DELEGATING_IMPLEMENTATION);
if (!ImplementationBodyCodegen.isEnum(aClass)) {
generateImplementation(parentContext, aClass, OwnerKind.DELEGATING_IMPLEMENTATION);
}
}
ClassDescriptor descriptor = state.getBindingContext().getClassDescriptor(aClass);
final ClassContext contextForInners = parentContext.intoClass(descriptor, OwnerKind.IMPLEMENTATION);
for (JetDeclaration declaration : aClass.getDeclarations()) {
if (declaration instanceof JetClass) {
if (declaration instanceof JetClass && !(declaration instanceof JetEnumEntry)) {
generate(contextForInners, (JetClass) declaration);
}
}
@@ -0,0 +1,10 @@
package org.jetbrains.jet.codegen;
import org.objectweb.asm.commons.InstructionAdapter;
/**
* @author yole
*/
public interface CodeChunk {
void generate(InstructionAdapter v);
}
@@ -896,11 +896,11 @@ public class ExpressionCodegen extends JetVisitor {
return funDescriptor;
}
private void invokeMethodWithArguments(CallableMethod callableMethod, JetCallExpression expression) {
public void invokeMethodWithArguments(CallableMethod callableMethod, JetCall expression) {
invokeMethodWithArguments(callableMethod, expression, false);
}
private void invokeMethodWithArguments(CallableMethod callableMethod, JetCallExpression expression, final boolean haveReceiver) {
private void invokeMethodWithArguments(CallableMethod callableMethod, JetCall expression, final boolean haveReceiver) {
if (callableMethod.isOwnerFromCall()) {
setOwnerFromCall(callableMethod, expression);
}
@@ -914,7 +914,7 @@ public class ExpressionCodegen extends JetVisitor {
callableMethod.invoke(v);
}
private void setOwnerFromCall(CallableMethod callableMethod, JetCallExpression expression) {
private void setOwnerFromCall(CallableMethod callableMethod, JetCall expression) {
if (expression.getParent() instanceof JetQualifiedExpression) {
final JetExpression receiver = ((JetQualifiedExpression) expression.getParent()).getReceiverExpression();
JetType expressionType = bindingContext.getExpressionType(receiver);
@@ -926,7 +926,7 @@ public class ExpressionCodegen extends JetVisitor {
}
}
private JetExpression getReceiverForSelector(JetElement expression) {
private static JetExpression getReceiverForSelector(PsiElement expression) {
if (expression.getParent() instanceof JetDotQualifiedExpression && !isReceiver(expression)) {
final JetDotQualifiedExpression parent = (JetDotQualifiedExpression) expression.getParent();
return parent.getReceiverExpression();
@@ -934,7 +934,7 @@ public class ExpressionCodegen extends JetVisitor {
return null;
}
private void ensureReceiverOnStack(JetElement expression, @Nullable ClassDescriptor calleeContainingClass) {
private void ensureReceiverOnStack(PsiElement expression, @Nullable ClassDescriptor calleeContainingClass) {
JetExpression receiver = getReceiverForSelector(expression);
if (receiver != null) {
if (!resolvesToClassOrPackage(receiver)) {
@@ -1013,7 +1013,7 @@ public class ExpressionCodegen extends JetVisitor {
}
}
private static boolean isReceiver(JetElement expression) {
private static boolean isReceiver(PsiElement expression) {
final PsiElement parent = expression.getParent();
if (parent instanceof JetQualifiedExpression) {
final JetExpression receiverExpression = ((JetQualifiedExpression) parent).getReceiverExpression();
@@ -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,13 +88,69 @@ 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;
if (constructorDescriptor == null && !(myClass instanceof JetObjectDeclaration) && !isEnum(myClass)) return;
Method method;
CallableMethod callableMethod;
if (myClass instanceof JetObjectDeclaration) {
if (constructorDescriptor == null) {
method = new Method("<init>", Type.VOID_TYPE, new Type[0]);
callableMethod = new CallableMethod("", method, Opcodes.INVOKESPECIAL, Collections.<Type>emptyList());
}
@@ -233,6 +278,11 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
mv.visitEnd();
}
static boolean isEnum(JetClassOrObject myClass) {
final JetModifierList modifierList = myClass.getModifierList();
return modifierList != null && modifierList.hasModifier(JetTokens.ENUM_KEYWORD);
}
@Nullable
private ClassDescriptor getOuterClassDescriptor() {
if (myClass.getParent() instanceof JetClassObject) {
@@ -280,13 +330,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
}
CallableMethod method = state.getTypeMapper().mapToCallableMethod(constructorDescriptor, kind);
List<JetArgument> args = constructorCall.getValueArguments();
for (int i = 0, argsSize = args.size(); i < argsSize; i++) {
JetArgument arg = args.get(i);
codegen.gen(arg.getArgumentExpression(), method.getValueParameterTypes().get(i));
}
method.invoke(iv);
codegen.invokeMethodWithArguments(method, constructorCall);
}
@Override
@@ -409,47 +453,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;
@@ -3,13 +3,16 @@ package org.jetbrains.jet.codegen;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiElement;
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
import org.jetbrains.jet.lang.psi.JetClassOrObject;
import org.jetbrains.jet.lang.psi.JetDelegationSpecifier;
import org.jetbrains.jet.lang.descriptors.ConstructorDescriptor;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.types.JetType;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.commons.InstructionAdapter;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
@@ -18,6 +21,8 @@ import java.util.Set;
* @author yole
*/
public class InterfaceBodyCodegen extends ClassBodyCodegen {
private final List<JetEnumEntry> myEnumConstants = new ArrayList<JetEnumEntry>();
public InterfaceBodyCodegen(JetClassOrObject aClass, ClassContext context, ClassVisitor v, GenerationState state) {
super(aClass, context, v, state);
assert context.getContextKind() == OwnerKind.INTERFACE;
@@ -73,4 +78,59 @@ public class InterfaceBodyCodegen extends ClassBodyCodegen {
}
return superInterfaces;
}
@Override
protected void generateDeclaration(PropertyCodegen propertyCodegen, JetDeclaration declaration, FunctionCodegen functionCodegen) {
if (declaration instanceof JetEnumEntry && !((JetEnumEntry) declaration).hasPrimaryConstructor()) {
String name = declaration.getName();
final String desc = "L" + state.getTypeMapper().jvmName(descriptor, OwnerKind.INTERFACE) + ";";
v.visitField(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC | Opcodes.ACC_FINAL, name, desc, null, null);
if (myEnumConstants.isEmpty()) {
staticInitializerChunks.add(new CodeChunk() {
@Override
public void generate(InstructionAdapter v) {
initializeEnumConstants(v);
}
});
}
myEnumConstants.add((JetEnumEntry) declaration);
}
else {
super.generateDeclaration(propertyCodegen, declaration, functionCodegen);
}
}
private void initializeEnumConstants(InstructionAdapter v) {
ExpressionCodegen codegen = new ExpressionCodegen(v, new FrameMap(), Type.VOID_TYPE, context, state);
for (JetEnumEntry enumConstant : myEnumConstants) {
// TODO type and constructor parameters
String intfClass = state.getTypeMapper().jvmName(descriptor, OwnerKind.INTERFACE);
String implClass = state.getTypeMapper().jvmName(descriptor, OwnerKind.IMPLEMENTATION);
final List<JetDelegationSpecifier> delegationSpecifiers = enumConstant.getDelegationSpecifiers();
if (delegationSpecifiers.size() > 1) {
throw new UnsupportedOperationException("multiple delegation specifiers for enum constant not supported");
}
v.anew(Type.getObjectType(implClass));
v.dup();
if (delegationSpecifiers.size() == 1) {
final JetDelegationSpecifier specifier = delegationSpecifiers.get(0);
if (specifier instanceof JetDelegatorToSuperCall) {
final JetDelegatorToSuperCall superCall = (JetDelegatorToSuperCall) specifier;
ConstructorDescriptor constructorDescriptor = state.getBindingContext().resolveSuperConstructor(superCall);
CallableMethod method = state.getTypeMapper().mapToCallableMethod(constructorDescriptor, OwnerKind.IMPLEMENTATION);
codegen.invokeMethodWithArguments(method, superCall);
}
else {
throw new UnsupportedOperationException("unsupported type of enum constant initializer: " + specifier);
}
}
else {
v.invokespecial(implClass, "<init>", "()V");
}
v.putstatic(intfClass, enumConstant.getName(), "L" + intfClass + ";");
}
}
}
@@ -1,5 +1,6 @@
package org.jetbrains.jet.lang.psi;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -8,7 +9,7 @@ import java.util.List;
/**
* @author abreslav
*/
public interface JetCall {
public interface JetCall extends PsiElement {
@Nullable
JetArgumentList getValueArgumentList();
@@ -1,5 +1,6 @@
package org.jetbrains.jet.codegen;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.List;
@@ -130,4 +131,21 @@ public class ClassGenTest extends CodegenTestCase {
Object result = method.invoke(null);
assertInstanceOf(result, Runnable.class);
}
public void testEnumClass() throws Exception {
loadText("enum class Direction { NORTH; SOUTH; EAST; WEST }");
final Class direction = loadAllClasses(generateClassesInFile()).get("Direction");
final Field north = direction.getField("NORTH");
assertEquals(direction, north.getType());
assertInstanceOf(north.get(null), direction);
}
public void testEnumConstantConstructors() throws Exception {
loadText("enum class Color(val rgb: Int) { RED: Color(0xFF0000); GREEN: Color(0x00FF00); }");
final Class colorClass = loadAllClasses(generateClassesInFile()).get("Color");
final Field redField = colorClass.getField("RED");
final Object redValue = redField.get(null);
final Method rgbMethod = colorClass.getMethod("getRgb");
assertEquals(0xFF0000, rgbMethod.invoke(redValue));
}
}