KT-1157 class object instance access from constructor of class object

This commit is contained in:
Alex Tkachman
2012-01-27 15:40:17 +03:00
parent 13e8995d80
commit 51e4fc986a
7 changed files with 90 additions and 45 deletions
@@ -145,7 +145,7 @@ public class ClosureCodegen extends ObjectOrClosureCodegen {
private void generateConstInstance(PsiElement fun) {
String classDescr = "L" + name + ";";
cv.newField(fun, ACC_PRIVATE | ACC_STATIC, "$instance", classDescr, null, null);
cv.newField(fun, ACC_PRIVATE | ACC_STATIC | ACC_FINAL, "$instance", classDescr, null, null);
MethodVisitor mv = cv.newMethod(fun, ACC_PUBLIC | ACC_STATIC, "$getInstance", "()" + classDescr, null, new String[0]);
if (cv.generateCode()) {
@@ -3,6 +3,9 @@ package org.jetbrains.jet.codegen;
import gnu.trove.THashSet;
import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
import org.jetbrains.jet.lang.psi.JetClassObject;
import org.jetbrains.jet.lang.psi.JetClassOrObject;
import org.jetbrains.jet.lang.psi.JetObjectDeclaration;
import org.jetbrains.jet.lang.resolve.calls.ExpressionAsFunctionDescriptor;
import org.jetbrains.jet.lang.types.JetStandardClasses;
import org.jetbrains.jet.lang.types.JetType;
@@ -126,4 +129,8 @@ public class CodegenUtil {
}
}
static boolean isNonLiteralObject(JetClassOrObject myClass) {
return myClass instanceof JetObjectDeclaration && !((JetObjectDeclaration) myClass).isObjectLiteral() &&
!(myClass.getParent() instanceof JetClassObject);
}
}
@@ -1375,6 +1375,10 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
public StackValue generateThisOrOuter(ClassDescriptor calleeContainingClass) {
CodegenContext cur = context;
PsiElement psiElement = bindingContext.get(BindingContext.DESCRIPTOR_TO_DECLARATION, calleeContainingClass);
boolean isObject = psiElement instanceof JetClassOrObject && CodegenUtil.isNonLiteralObject((JetClassOrObject)psiElement);
cur = context;
StackValue result = StackValue.local(0, TYPE_OBJECT);
while (cur != null) {
if(cur instanceof CodegenContext.MethodContext && !(cur instanceof CodegenContext.ConstructorContext))
@@ -1382,8 +1386,13 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
if (CodegenUtil.isSubclass(cur.getThisDescriptor(), calleeContainingClass)) {
Type type = asmType(calleeContainingClass.getDefaultType());
result.put(TYPE_OBJECT, v);
return castToRequiredTypeOfInterfaceIfNeeded(StackValue.onStack(type), cur.getThisDescriptor(), calleeContainingClass);
if(!isObject || (cur.getThisDescriptor() == calleeContainingClass)) {
result.put(TYPE_OBJECT, v);
return castToRequiredTypeOfInterfaceIfNeeded(StackValue.onStack(type), cur.getThisDescriptor(), calleeContainingClass);
}
else {
v.getstatic(type.getInternalName(), "$instance", type.getDescriptor());
}
}
result = cur.getOuterExpression(result);
@@ -2345,7 +2354,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
@Override
public StackValue visitThrowExpression(JetThrowExpression expression, StackValue receiver) {
gen(expression.getThrownExpression(), TYPE_OBJECT);
gen(expression.getThrownExpression(), TYPE_THROWABLE);
doFinallyOnReturnOrThrow();
v.athrow();
return StackValue.none();
@@ -22,6 +22,7 @@ import org.objectweb.asm.commons.Method;
import java.util.*;
import static org.jetbrains.jet.codegen.JetTypeMapper.TYPE_OBJECT;
import static org.objectweb.asm.Opcodes.*;
/**
* @author max
@@ -70,20 +71,20 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
}
int access = 0;
access |= Opcodes.ACC_PUBLIC;
access |= ACC_PUBLIC;
if (isAbstract) {
access |= Opcodes.ACC_ABSTRACT;
access |= ACC_ABSTRACT;
}
if (isInterface) {
access |= Opcodes.ACC_INTERFACE; // ACC_SUPER
access |= ACC_INTERFACE; // ACC_SUPER
}
if (isFinal) {
access |= Opcodes.ACC_FINAL;
access |= ACC_FINAL;
}
if (isStatic) {
access |= Opcodes.ACC_STATIC;
access |= ACC_STATIC;
}
v.defineClass(myClass, Opcodes.V1_6,
v.defineClass(myClass, V1_6,
access,
signature.getName(),
signature.getJavaGenericSignature(),
@@ -99,11 +100,11 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
for (ClassDescriptor innerClass : descriptor.getInnerClassesAndObjects()) {
// TODO: proper access
int innerClassAccess = Opcodes.ACC_PUBLIC;
int innerClassAccess = ACC_PUBLIC;
if (innerClass.getModality() == Modality.FINAL) {
innerClassAccess |= Opcodes.ACC_FINAL;
innerClassAccess |= ACC_FINAL;
} else if (innerClass.getModality() == Modality.ABSTRACT) {
innerClassAccess |= Opcodes.ACC_ABSTRACT;
innerClassAccess |= ACC_ABSTRACT;
}
// TODO: cache internal names
String outerClassInernalName = typeMapper.mapType(descriptor.getDefaultType(), OwnerKind.IMPLEMENTATION).getInternalName();
@@ -242,7 +243,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
Method originalMethod = typeMapper.mapSignature(original.getName(), original).getAsmMethod();
Type[] argTypes = method.getArgumentTypes();
MethodVisitor mv = v.newMethod(null, Opcodes.ACC_PUBLIC|Opcodes.ACC_BRIDGE|Opcodes.ACC_FINAL, bridge.getName(), method.getDescriptor(), null, null);
MethodVisitor mv = v.newMethod(null, ACC_PUBLIC| ACC_BRIDGE| ACC_FINAL, bridge.getName(), method.getDescriptor(), null, null);
if (v.generateCode()) {
mv.visitCode();
@@ -269,7 +270,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
Method method = typeMapper.mapGetterSignature(bridge, OwnerKind.IMPLEMENTATION).getJvmMethodSignature().getAsmMethod();
JvmPropertyAccessorSignature originalSignature = typeMapper.mapGetterSignature(original, OwnerKind.IMPLEMENTATION);
Method originalMethod = originalSignature.getJvmMethodSignature().getAsmMethod();
MethodVisitor mv = v.newMethod(null, Opcodes.ACC_PUBLIC | Opcodes.ACC_BRIDGE | Opcodes.ACC_FINAL, method.getName(), method.getDescriptor(), null, null);
MethodVisitor mv = v.newMethod(null, ACC_PUBLIC | ACC_BRIDGE | ACC_FINAL, method.getName(), method.getDescriptor(), null, null);
PropertyCodegen.generateJetPropertyAnnotation(mv, originalSignature.getPropertyTypeKotlinSignature(), originalSignature.getJvmMethodSignature().getKotlinTypeParameter());
if (v.generateCode()) {
mv.visitCode();
@@ -292,7 +293,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
Method method = typeMapper.mapSetterSignature(bridge, OwnerKind.IMPLEMENTATION).getJvmMethodSignature().getAsmMethod();
JvmPropertyAccessorSignature originalSignature2 = typeMapper.mapSetterSignature(original, OwnerKind.IMPLEMENTATION);
Method originalMethod = originalSignature2.getJvmMethodSignature().getAsmMethod();
MethodVisitor mv = v.newMethod(null, Opcodes.ACC_PUBLIC | Opcodes.ACC_BRIDGE | Opcodes.ACC_FINAL, method.getName(), method.getDescriptor(), null, null);
MethodVisitor mv = v.newMethod(null, ACC_PUBLIC | ACC_BRIDGE | ACC_FINAL, method.getName(), method.getDescriptor(), null, null);
PropertyCodegen.generateJetPropertyAnnotation(mv, originalSignature2.getPropertyTypeKotlinSignature(), originalSignature2.getJvmMethodSignature().getKotlinTypeParameter());
if (v.generateCode()) {
mv.visitCode();
@@ -323,9 +324,9 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
}
private void generateFieldForObjectInstance() {
if (isNonLiteralObject()) {
if (CodegenUtil.isNonLiteralObject(myClass)) {
Type type = typeMapper.mapType(descriptor.getDefaultType(), OwnerKind.IMPLEMENTATION);
v.newField(myClass, Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, "$instance", type.getDescriptor(), null, null);
v.newField(myClass, ACC_PUBLIC | ACC_STATIC | ACC_FINAL, "$instance", type.getDescriptor(), null, null);
staticInitializerChunks.add(new CodeChunk() {
@Override
@@ -346,7 +347,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
if (classObject != null) {
final ClassDescriptor descriptor1 = bindingContext.get(BindingContext.CLASS, classObject.getObjectDeclaration());
Type type = Type.getObjectType(typeMapper.mapType(descriptor1.getDefaultType(), OwnerKind.IMPLEMENTATION).getInternalName());
v.newField(classObject, Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, "$classobj", type.getDescriptor(), null, null);
v.newField(classObject, ACC_PUBLIC | ACC_STATIC, "$classobj", type.getDescriptor(), null, null);
staticInitializerChunks.add(new CodeChunk() {
@Override
@@ -398,7 +399,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
signatureWriter.writeVoidReturn();
constructorMethod = signatureWriter.makeJvmMethodSignature("<init>");
callableMethod = new CallableMethod("", constructorMethod, Opcodes.INVOKESPECIAL);
callableMethod = new CallableMethod("", constructorMethod, INVOKESPECIAL);
}
else {
callableMethod = typeMapper.mapToCallableMethod(constructorDescriptor, kind);
@@ -450,7 +451,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
constructorMethod = JvmMethodSignature.simple("<init>", Type.VOID_TYPE, consArgTypes);
}
int flags = Opcodes.ACC_PUBLIC; // TODO
int flags = ACC_PUBLIC; // TODO
final MethodVisitor mv = v.newMethod(myClass, flags, constructorMethod.getName(), constructorMethod.getAsmMethod().getDescriptor(), constructorMethod.getGenericsSignature(), null);
if (!v.generateCode()) return;
@@ -553,7 +554,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
String delegateField = "$delegate_" + n;
Type fieldType = typeMapper.mapType(superClassDescriptor.getDefaultType(), OwnerKind.IMPLEMENTATION);
String fieldDesc = fieldType.getDescriptor();
v.newField(specifier, Opcodes.ACC_PRIVATE, delegateField, fieldDesc, /*TODO*/null, null);
v.newField(specifier, ACC_PRIVATE, delegateField, fieldDesc, /*TODO*/null, null);
iv.putfield(classname, delegateField, fieldDesc);
JetClass superClass = (JetClass) bindingContext.get(BindingContext.DESCRIPTOR_TO_DECLARATION, superClassDescriptor);
@@ -569,17 +570,17 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
final Type type = typeMapper.mapType(outerDescriptor.getDefaultType(), OwnerKind.IMPLEMENTATION);
String interfaceDesc = type.getDescriptor();
final String fieldName = "this$0";
v.newField(myClass, Opcodes.ACC_PRIVATE | Opcodes.ACC_FINAL, fieldName, interfaceDesc, null, null);
v.newField(myClass, ACC_PRIVATE | ACC_FINAL, fieldName, interfaceDesc, null, null);
iv.load(0, classType);
iv.load(frameMap.getOuterThisIndex(), type);
iv.putfield(classname, fieldName, interfaceDesc);
Type outerType = typeMapper.mapType(outerDescriptor.getDefaultType());
MethodVisitor outer = v.newMethod(myClass, Opcodes.ACC_PUBLIC, JvmStdlibNames.JET_OBJECT_GET_OUTER_OBJECT_METHOD, "()Ljet/JetObject;", null, null);
MethodVisitor outer = v.newMethod(myClass, ACC_PUBLIC, JvmStdlibNames.JET_OBJECT_GET_OUTER_OBJECT_METHOD, "()Ljet/JetObject;", null, null);
outer.visitCode();
outer.visitVarInsn(Opcodes.ALOAD, 0);
outer.visitFieldInsn(Opcodes.GETFIELD, classname, "this$0", outerType.getDescriptor());
outer.visitInsn(Opcodes.ARETURN);
outer.visitVarInsn(ALOAD, 0);
outer.visitFieldInsn(GETFIELD, classname, "this$0", outerType.getDescriptor());
outer.visitInsn(ARETURN);
FunctionCodegen.endVisit(outer, JvmStdlibNames.JET_OBJECT_GET_OUTER_OBJECT_METHOD, myClass);
}
@@ -631,7 +632,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
generateTraitMethods(codegen);
mv.visitInsn(Opcodes.RETURN);
mv.visitInsn(RETURN);
FunctionCodegen.endVisit(mv, "constructor", myClass);
FunctionCodegen.generateDefaultIfNeeded(constructorContext, state, v, constructorMethod.getAsmMethod(), constructorDescriptor, OwnerKind.IMPLEMENTATION);
@@ -651,7 +652,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
if(psiElement instanceof JetClass) {
JetClass jetClass = (JetClass) psiElement;
if(jetClass.isTrait()) {
int flags = Opcodes.ACC_PUBLIC; // TODO.
int flags = ACC_PUBLIC; // TODO.
Method function = typeMapper.mapSignature(fun.getName(), fun).getAsmMethod();
Method functionOriginal = typeMapper.mapSignature(fun.getName(), fun.getOriginal()).getAsmMethod();
@@ -745,7 +746,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
else if (declaration instanceof JetEnumEntry && !((JetEnumEntry) declaration).hasPrimaryConstructor()) {
String name = declaration.getName();
final String desc = "L" + typeMapper.mapType(descriptor.getDefaultType(), OwnerKind.IMPLEMENTATION).getInternalName() + ";";
v.newField(declaration, Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC | Opcodes.ACC_FINAL, name, desc, null, null);
v.newField(declaration, ACC_PUBLIC | ACC_STATIC | ACC_FINAL, name, desc, null, null);
if (myEnumConstants.isEmpty()) {
staticInitializerChunks.add(new CodeChunk() {
@Override
@@ -802,7 +803,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
throw new UnsupportedOperationException("failed to get descriptor for secondary constructor");
}
CallableMethod method = typeMapper.mapToCallableMethod(constructorDescriptor, kind);
int flags = Opcodes.ACC_PUBLIC; // TODO
int flags = ACC_PUBLIC; // TODO
final MethodVisitor mv = v.newMethod(constructor, flags, "<init>", method.getSignature().getAsmMethod().getDescriptor(), null, null);
if (v.generateCode()) {
mv.visitCode();
@@ -831,7 +832,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
codegen.gen(bodyExpression, Type.VOID_TYPE);
}
mv.visitInsn(Opcodes.RETURN);
mv.visitInsn(RETURN);
FunctionCodegen.endVisit(mv, "constructor", null);
}
}
@@ -908,9 +909,9 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
if (p.getValOrVarNode() != null) {
PropertyDescriptor propertyDescriptor = bindingContext.get(BindingContext.PRIMARY_CONSTRUCTOR_PARAMETER, p);
if (propertyDescriptor != null) {
propertyCodegen.generateDefaultGetter(propertyDescriptor, Opcodes.ACC_PUBLIC, p);
propertyCodegen.generateDefaultGetter(propertyDescriptor, ACC_PUBLIC, p);
if (propertyDescriptor.isVar()) {
propertyCodegen.generateDefaultSetter(propertyDescriptor, Opcodes.ACC_PUBLIC, p);
propertyCodegen.generateDefaultSetter(propertyDescriptor, ACC_PUBLIC, p);
}
}
}
@@ -922,11 +923,6 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
return myClass instanceof JetClass ? ((JetClass) myClass).getClassObject() : null;
}
private boolean isNonLiteralObject() {
return myClass instanceof JetObjectDeclaration && !((JetObjectDeclaration) myClass).isObjectLiteral() &&
!(myClass.getParent() instanceof JetClassObject);
}
private void generateGetTypeInfo() {
if(myClass instanceof JetClass && ((JetClass)myClass).isTrait())
return;
@@ -934,9 +930,9 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
JetType defaultType = descriptor.getDefaultType();
if(CodegenUtil.requireTypeInfoConstructorArg(defaultType)) {
if(!CodegenUtil.hasDerivedTypeInfoField(defaultType)) {
v.newField(myClass, Opcodes.ACC_PROTECTED, JvmAbi.TYPE_INFO_FIELD, "Ljet/TypeInfo;", null, null);
v.newField(myClass, ACC_PROTECTED, JvmAbi.TYPE_INFO_FIELD, "Ljet/TypeInfo;", null, null);
MethodVisitor mv = v.newMethod(myClass, Opcodes.ACC_PUBLIC, JvmStdlibNames.JET_OBJECT_GET_TYPEINFO_METHOD, "()Ljet/TypeInfo;", null, null);
MethodVisitor mv = v.newMethod(myClass, ACC_PUBLIC, JvmStdlibNames.JET_OBJECT_GET_TYPEINFO_METHOD, "()Ljet/TypeInfo;", null, null);
if (v.generateCode()) {
mv.visitCode();
InstructionAdapter iv = new InstructionAdapter(mv);
@@ -947,7 +943,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
FunctionCodegen.endVisit(iv, JvmStdlibNames.JET_OBJECT_GET_TYPEINFO_METHOD, myClass);
}
mv = v.newMethod(myClass, Opcodes.ACC_PROTECTED | Opcodes.ACC_FINAL, JvmAbi.SET_TYPE_INFO_METHOD, "(Ljet/TypeInfo;)V", null, null);
mv = v.newMethod(myClass, ACC_PROTECTED | ACC_FINAL, JvmAbi.SET_TYPE_INFO_METHOD, "(Ljet/TypeInfo;)V", null, null);
if (v.generateCode()) {
mv.visitCode();
InstructionAdapter iv = new InstructionAdapter(mv);
@@ -955,7 +951,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
iv.load(0, JetTypeMapper.TYPE_OBJECT);
iv.load(1, JetTypeMapper.TYPE_OBJECT);
iv.putfield(owner, JvmAbi.TYPE_INFO_FIELD, "Ljet/TypeInfo;");
mv.visitInsn(Opcodes.RETURN);
mv.visitInsn(RETURN);
FunctionCodegen.endVisit(iv, JvmAbi.SET_TYPE_INFO_METHOD, myClass);
}
}
@@ -967,7 +963,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
}
private void genGetStaticGetTypeInfoMethod() {
final MethodVisitor mv = v.newMethod(myClass, Opcodes.ACC_PUBLIC, JvmStdlibNames.JET_OBJECT_GET_TYPEINFO_METHOD, "()Ljet/TypeInfo;", null, null);
final MethodVisitor mv = v.newMethod(myClass, ACC_PUBLIC, JvmStdlibNames.JET_OBJECT_GET_TYPEINFO_METHOD, "()Ljet/TypeInfo;", null, null);
if (v.generateCode()) {
mv.visitCode();
InstructionAdapter v = new InstructionAdapter(mv);
@@ -979,7 +975,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
}
private void staticTypeInfoField() {
v.newField(myClass, Opcodes.ACC_PUBLIC | Opcodes.ACC_FINAL | Opcodes.ACC_STATIC, "$staticTypeInfo", "Ljet/TypeInfo;", null, null);
v.newField(myClass, ACC_PUBLIC | ACC_FINAL | ACC_STATIC, "$staticTypeInfo", "Ljet/TypeInfo;", null, null);
staticInitializerChunks.add(new CodeChunk() {
@Override
public void generate(InstructionAdapter v) {
@@ -31,6 +31,7 @@ import static org.objectweb.asm.Opcodes.*;
*/
public class JetTypeMapper {
public static final Type TYPE_OBJECT = Type.getObjectType("java/lang/Object");
public static final Type TYPE_THROWABLE = Type.getObjectType("java/lang/Throwable");
public static final Type TYPE_TYPEINFO = Type.getType(TypeInfo.class);
public static final Type TYPE_TYPEINFOPROJECTION = Type.getType(TypeInfoProjection.class);
public static final Type TYPE_JET_OBJECT = Type.getType(JetObject.class);
@@ -0,0 +1,28 @@
public object SomeClass {
var bug: Any = ""
private val workerThread = object : Thread() {
override fun run() {
try {
foo()
bug = "none"
}
catch(t: Throwable) {
bug = t
}
}
}
{
workerThread.start()
}
private fun foo() : Unit {
}
}
public fun box():String {
if(SomeClass.bug is Throwable)
throw SomeClass.bug
return "OK"
}
@@ -257,4 +257,8 @@ public class ClassGenTest extends CodegenTestCase {
public void testkt1134() throws Exception {
blackBoxFile("regressions/kt1134.kt");
}
public void testkt1157() throws Exception {
blackBoxFile("regressions/kt1157.kt");
}
}