diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java index 6650d907bfb..a125ab0f0f2 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java @@ -72,8 +72,7 @@ import static org.jetbrains.jet.codegen.binding.CodegenBinding.*; import static org.jetbrains.jet.descriptors.serialization.NameSerializationUtil.createNameResolver; import static org.jetbrains.jet.lang.resolve.BindingContextUtils.descriptorToDeclaration; import static org.jetbrains.jet.lang.resolve.DescriptorUtils.*; -import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.JAVA_STRING_TYPE; -import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.OBJECT_TYPE; +import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.*; import static org.jetbrains.jet.lang.resolve.java.JvmAnnotationNames.KotlinSyntheticClass; import static org.jetbrains.jet.lang.resolve.java.diagnostics.DiagnosticsPackage.DelegationToTraitImpl; import static org.jetbrains.jet.lang.resolve.java.diagnostics.DiagnosticsPackage.OtherOrigin; @@ -429,7 +428,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { @Override protected void generateSyntheticParts() { - generateDelegatedPropertyMetadataArray(); + generateStaticSyntheticFields(); generateFieldForSingleton(); @@ -463,10 +462,20 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { generateToArray(); - genClosureFields(context.closure, v, state.getTypeMapper()); + genClosureFields(context.closure, v, typeMapper); } - private void generateDelegatedPropertyMetadataArray() { + private void generateStaticSyntheticFields() { + if (isAnnotationClass(descriptor)) { + // There's a bug in JDK 6 and 7 that prevents us from generating a static field in an annotation class: + // http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6857918 + // TODO: make reflection work on annotation classes somehow + return; + } + + generateReflectionObjectField(state, classAsmType, v, K_CLASS_IMPL_TYPE, JvmAbi.KOTLIN_CLASS_FIELD_NAME, + createOrGetClInitCodegen().v); + generatePropertyMetadataArrayFieldIfNeeded(classAsmType); } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/MemberCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/MemberCodegen.java index b491052aabb..622b710fe57 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/MemberCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/MemberCodegen.java @@ -50,12 +50,12 @@ import java.util.List; import static org.jetbrains.jet.codegen.AsmUtil.boxType; import static org.jetbrains.jet.codegen.AsmUtil.isPrimitive; -import static org.jetbrains.jet.lang.resolve.java.diagnostics.DiagnosticsPackage.OtherOrigin; -import static org.jetbrains.jet.lang.resolve.java.diagnostics.DiagnosticsPackage.TraitImpl; -import static org.jetbrains.jet.lang.resolve.java.diagnostics.JvmDeclarationOrigin.NO_ORIGIN; import static org.jetbrains.jet.lang.descriptors.CallableMemberDescriptor.Kind.SYNTHESIZED; import static org.jetbrains.jet.lang.resolve.BindingContext.VARIABLE; import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.*; +import static org.jetbrains.jet.lang.resolve.java.diagnostics.DiagnosticsPackage.OtherOrigin; +import static org.jetbrains.jet.lang.resolve.java.diagnostics.DiagnosticsPackage.TraitImpl; +import static org.jetbrains.jet.lang.resolve.java.diagnostics.JvmDeclarationOrigin.NO_ORIGIN; import static org.jetbrains.org.objectweb.asm.Opcodes.*; public abstract class MemberCodegen extends ParentCodegenAware { @@ -316,6 +316,27 @@ public abstract class MemberCodegen", "(Ljava/lang/Class;)V", false); + v.putstatic(thisAsmType.getInternalName(), fieldName, kImplType.getDescriptor()); + } + protected void generatePropertyMetadataArrayFieldIfNeeded(@NotNull Type thisAsmType) { List delegatedProperties = new ArrayList(); for (JetDeclaration declaration : ((JetDeclarationContainer) element).getDeclarations()) { diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/PackageCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/PackageCodegen.java index c46ae090f6b..24a8e07baf2 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/PackageCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/PackageCodegen.java @@ -56,27 +56,32 @@ import org.jetbrains.jet.lang.resolve.name.FqName; import org.jetbrains.org.objectweb.asm.AnnotationVisitor; import org.jetbrains.org.objectweb.asm.MethodVisitor; import org.jetbrains.org.objectweb.asm.Type; +import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter; import java.util.*; import static org.jetbrains.jet.codegen.AsmUtil.asmDescByFqNameWithoutInnerClasses; import static org.jetbrains.jet.descriptors.serialization.NameSerializationUtil.createNameResolver; +import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.K_PACKAGE_IMPL_TYPE; import static org.jetbrains.jet.lang.resolve.java.PackageClassUtils.getPackageClassFqName; import static org.jetbrains.jet.lang.resolve.java.diagnostics.DiagnosticsPackage.*; +import static org.jetbrains.jet.lang.resolve.java.diagnostics.JvmDeclarationOrigin.NO_ORIGIN; import static org.jetbrains.org.objectweb.asm.Opcodes.*; public class PackageCodegen { - private final GenerationState state; private final ClassBuilderOnDemand v; + private final GenerationState state; private final Collection files; + private final Type packageClassType; private final PackageFragmentDescriptor packageFragment; private final PackageFragmentDescriptor compiledPackageFragment; private final List previouslyCompiledCallables; - public PackageCodegen(@NotNull GenerationState state, @NotNull Collection files, @NotNull final FqName fqName) { + public PackageCodegen(@NotNull GenerationState state, @NotNull Collection files, @NotNull FqName fqName) { this.state = state; this.files = files; this.packageFragment = getOnlyPackageFragment(fqName); + this.packageClassType = AsmUtil.asmTypeByFqNameWithoutInnerClasses(getPackageClassFqName(fqName)); this.compiledPackageFragment = getCompiledPackageFragment(fqName); this.previouslyCompiledCallables = filterDeserializedCallables(compiledPackageFragment); @@ -88,14 +93,13 @@ public class PackageCodegen { Collection files = PackageCodegen.this.files; JetFile sourceFile = getRepresentativePackageFile(files); - String className = AsmUtil.internalNameByFqNameWithoutInnerClasses(getPackageClassFqName(fqName)); - ClassBuilder v = PackageCodegen.this.state.getFactory() - .newVisitor( - PackageFacade(packageFragment == null ? compiledPackageFragment : packageFragment), - Type.getObjectType(className), PackagePartClassUtils.getPackageFilesWithCallables(files)); + ClassBuilder v = PackageCodegen.this.state.getFactory().newVisitor( + PackageFacade(packageFragment == null ? compiledPackageFragment : packageFragment), + packageClassType, PackagePartClassUtils.getPackageFilesWithCallables(files) + ); v.defineClass(sourceFile, V1_6, ACC_PUBLIC | ACC_FINAL, - className, + packageClassType.getInternalName(), null, "java/lang/Object", ArrayUtil.EMPTY_STRING_ARRAY @@ -216,18 +220,35 @@ public class PackageCodegen { } } - generateDelegationsToPreviouslyCompiled(generateCallableMemberTasks); + if (!generateCallableMemberTasks.isEmpty()) { + generatePackageFacadeClass(generateCallableMemberTasks, bindings); + } + } - if (generateCallableMemberTasks.isEmpty()) return; + private void generatePackageFacadeClass( + @NotNull Map tasks, + @NotNull List bindings + ) { + generateKotlinPackageReflectionField(); - for (CallableMemberDescriptor member : Ordering.from(MemberComparator.INSTANCE).sortedCopy(generateCallableMemberTasks.keySet())) { - generateCallableMemberTasks.get(member).run(); + generateDelegationsToPreviouslyCompiled(tasks); + + for (CallableMemberDescriptor member : Ordering.from(MemberComparator.INSTANCE).sortedCopy(tasks.keySet())) { + tasks.get(member).run(); } bindings.add(v.getSerializationBindings()); writeKotlinPackageAnnotationIfNeeded(JvmSerializationBindings.union(bindings)); } + private void generateKotlinPackageReflectionField() { + MethodVisitor mv = v.newMethod(NO_ORIGIN, ACC_STATIC, "", "()V", null, null); + MemberCodegen.generateReflectionObjectField(state, packageClassType, v, K_PACKAGE_IMPL_TYPE, JvmAbi.KOTLIN_PACKAGE_FIELD_NAME, + new InstructionAdapter(mv)); + mv.visitInsn(RETURN); + FunctionCodegen.endVisit(mv, "static initializer", null); + } + private void writeKotlinPackageAnnotationIfNeeded(@NotNull JvmSerializationBindings bindings) { if (state.getClassBuilderMode() != ClassBuilderMode.FULL) { return; diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/inline/InlineCodegenUtil.java b/compiler/backend/src/org/jetbrains/jet/codegen/inline/InlineCodegenUtil.java index 4cbaceed56b..c1871be9e64 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/inline/InlineCodegenUtil.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/inline/InlineCodegenUtil.java @@ -266,6 +266,9 @@ public class InlineCodegenUtil { } public static boolean isCapturedFieldName(@NotNull String fieldName) { - return fieldName.startsWith(CAPTURED_FIELD_PREFIX) || THIS$0.equals(fieldName) || RECEIVER$0.equals(fieldName); + // TODO: improve this heuristic + return (fieldName.startsWith(CAPTURED_FIELD_PREFIX) && !fieldName.equals(JvmAbi.KOTLIN_CLASS_FIELD_NAME)) || + THIS$0.equals(fieldName) || + RECEIVER$0.equals(fieldName); } } diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/AsmTypeConstants.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/AsmTypeConstants.java index 873dff87312..d9a1f950fcc 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/AsmTypeConstants.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/AsmTypeConstants.java @@ -38,6 +38,9 @@ public class AsmTypeConstants { public static final Type PROPERTY_METADATA_TYPE = Type.getObjectType(BUILT_INS_PACKAGE_FQ_NAME + "/PropertyMetadata"); public static final Type PROPERTY_METADATA_IMPL_TYPE = Type.getObjectType(BUILT_INS_PACKAGE_FQ_NAME + "/PropertyMetadataImpl"); + public static final Type K_CLASS_IMPL_TYPE = Type.getObjectType("kotlin/reflect/jvm/internal/KClassImpl"); + public static final Type K_PACKAGE_IMPL_TYPE = Type.getObjectType("kotlin/reflect/jvm/internal/KPackageImpl"); + public static final Type OBJECT_REF_TYPE = Type.getObjectType("kotlin/jvm/internal/Ref$ObjectRef"); public static Type getType(@NotNull Class javaClass) { diff --git a/compiler/integration-tests/src/org/jetbrains/kotlin/CompilerSmokeTest.java b/compiler/integration-tests/src/org/jetbrains/kotlin/CompilerSmokeTest.java index f9c87e96f20..6b544d4500e 100644 --- a/compiler/integration-tests/src/org/jetbrains/kotlin/CompilerSmokeTest.java +++ b/compiler/integration-tests/src/org/jetbrains/kotlin/CompilerSmokeTest.java @@ -20,15 +20,14 @@ import org.junit.Test; import java.io.File; -import static junit.framework.Assert.*; +import static org.junit.Assert.assertEquals; public class CompilerSmokeTest extends KotlinIntegrationTestBase { - @Test public void compileAndRunHelloApp() throws Exception { String jar = tmpdir.getTmpDir().getAbsolutePath() + File.separator + "hello.jar"; - assertEquals("compilation failed", 0, runCompiler("hello.compile", "-src", "hello.kt", "-jar", jar)); + assertEquals("compilation failed", 0, runCompiler("hello.compile", "-includeRuntime", "hello.kt", "-jar", jar)); runJava("hello.run", "-cp", jar, "Hello.HelloPackage"); } @@ -36,7 +35,7 @@ public class CompilerSmokeTest extends KotlinIntegrationTestBase { public void compileAndRunHelloAppFQMain() throws Exception { String jar = tmpdir.getTmpDir().getAbsolutePath() + File.separator + "hello.jar"; - assertEquals("compilation failed", 0, runCompiler("hello.compile", "-src", "hello.kt", "-jar", jar)); + assertEquals("compilation failed", 0, runCompiler("hello.compile", "-includeRuntime", "hello.kt", "-jar", jar)); runJava("hello.run", "-cp", jar, "Hello.HelloPackage"); } @@ -44,7 +43,7 @@ public class CompilerSmokeTest extends KotlinIntegrationTestBase { public void compileAndRunHelloAppVarargMain() throws Exception { String jar = tmpdir.getTmpDir().getAbsolutePath() + File.separator + "hello.jar"; - assertEquals("compilation failed", 0, runCompiler("hello.compile", "-src", "hello.kt", "-jar", jar)); + assertEquals("compilation failed", 0, runCompiler("hello.compile", "-includeRuntime", "hello.kt", "-jar", jar)); runJava("hello.run", "-cp", jar, "Hello.HelloPackage"); } diff --git a/compiler/testData/codegen/bytecodeText/kt2202.kt b/compiler/testData/codegen/bytecodeText/kt2202.kt index 2d62a6e896b..e2bc119b688 100644 --- a/compiler/testData/codegen/bytecodeText/kt2202.kt +++ b/compiler/testData/codegen/bytecodeText/kt2202.kt @@ -18,4 +18,4 @@ class B { } // 0 INVOKEVIRTUAL -// 4 INVOKESPECIAL +// 2 INVOKESPECIAL [AB]\. diff --git a/compiler/testData/codegen/bytecodeText/privateDefaultArgs.kt b/compiler/testData/codegen/bytecodeText/privateDefaultArgs.kt index 699df18dff9..633b067a1be 100644 --- a/compiler/testData/codegen/bytecodeText/privateDefaultArgs.kt +++ b/compiler/testData/codegen/bytecodeText/privateDefaultArgs.kt @@ -13,4 +13,4 @@ fun box(): String { } // 0 INVOKEVIRTUAL -// 3 INVOKESPECIAL +// 2 INVOKESPECIAL B\.foo diff --git a/compiler/tests/org/jetbrains/jet/codegen/PropertyGenTest.java b/compiler/tests/org/jetbrains/jet/codegen/PropertyGenTest.java index a03cf5e89e4..242c52c6794 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/PropertyGenTest.java +++ b/compiler/tests/org/jetbrains/jet/codegen/PropertyGenTest.java @@ -40,11 +40,7 @@ public class PropertyGenTest extends CodegenTestCase { public void testPrivateVal() throws Exception { loadFile(); - Class aClass = generateClass("PrivateVal"); - Field[] fields = aClass.getDeclaredFields(); - assertEquals(1, fields.length); // prop - Field field = fields[0]; - assertEquals("prop", field.getName()); + generateClass("PrivateVal").getDeclaredField("prop"); } public void testPrivateVar() throws Exception { diff --git a/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/java/JvmAbi.java b/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/java/JvmAbi.java index 49e8d8f3874..4cb17862e6c 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/java/JvmAbi.java +++ b/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/java/JvmAbi.java @@ -45,6 +45,8 @@ public final class JvmAbi { public static final String CLASS_OBJECT_FIELD = "object$"; public static final FqName K_OBJECT = new FqName("kotlin.jvm.internal.KObject"); + public static final String KOTLIN_CLASS_FIELD_NAME = "$kotlinClass"; + public static final String KOTLIN_PACKAGE_FIELD_NAME = "$kotlinPackage"; public static boolean isClassObjectFqName(@NotNull FqName fqName) { return fqName.lastSegmentIs(Name.identifier(CLASS_OBJECT_CLASS_NAME)); diff --git a/idea/testData/debugger/tinyApp/outs/memberFunFromTopLevel.out b/idea/testData/debugger/tinyApp/outs/memberFunFromTopLevel.out index c2e52ded0b3..4f55a285f35 100644 --- a/idea/testData/debugger/tinyApp/outs/memberFunFromTopLevel.out +++ b/idea/testData/debugger/tinyApp/outs/memberFunFromTopLevel.out @@ -1,7 +1,7 @@ -LineBreakpoint created at memberFunFromTopLevel.kt:11 +LineBreakpoint created at memberFunFromTopLevel.kt:13 !JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !APP_PATH!\classes;!KOTLIN_RUNTIME!;!RT_JAR! memberFunFromTopLevel.MemberFunFromTopLevelPackage Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' -memberFunFromTopLevel.kt:10 +memberFunFromTopLevel.kt:12 memberFunFromTopLevel.kt:4 Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' diff --git a/idea/testData/debugger/tinyApp/outs/memberGetterFromTopLevel.out b/idea/testData/debugger/tinyApp/outs/memberGetterFromTopLevel.out index 72ee47c8875..7699e7232f3 100644 --- a/idea/testData/debugger/tinyApp/outs/memberGetterFromTopLevel.out +++ b/idea/testData/debugger/tinyApp/outs/memberGetterFromTopLevel.out @@ -1,7 +1,7 @@ -LineBreakpoint created at memberGetterFromTopLevel.kt:13 +LineBreakpoint created at memberGetterFromTopLevel.kt:15 !JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !APP_PATH!\classes;!KOTLIN_RUNTIME!;!RT_JAR! memberGetterFromTopLevel.MemberGetterFromTopLevelPackage Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' -memberGetterFromTopLevel.kt:12 +memberGetterFromTopLevel.kt:14 memberGetterFromTopLevel.kt:5 Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' diff --git a/idea/testData/debugger/tinyApp/src/stepInto/memberFunFromTopLevel.kt b/idea/testData/debugger/tinyApp/src/stepInto/memberFunFromTopLevel.kt index 0ab3d10e410..6dfc6d4cb91 100644 --- a/idea/testData/debugger/tinyApp/src/stepInto/memberFunFromTopLevel.kt +++ b/idea/testData/debugger/tinyApp/src/stepInto/memberFunFromTopLevel.kt @@ -7,6 +7,8 @@ class A { } fun main(args: Array) { + A() + //Breakpoint! A().bar() } diff --git a/idea/testData/debugger/tinyApp/src/stepInto/memberGetterFromTopLevel.kt b/idea/testData/debugger/tinyApp/src/stepInto/memberGetterFromTopLevel.kt index 328316b07ef..13f8d06f27a 100644 --- a/idea/testData/debugger/tinyApp/src/stepInto/memberGetterFromTopLevel.kt +++ b/idea/testData/debugger/tinyApp/src/stepInto/memberGetterFromTopLevel.kt @@ -9,6 +9,8 @@ class A { } fun main(args: Array) { + A() + //Breakpoint! A().bar } diff --git a/jps-plugin/test/org/jetbrains/jet/jps/build/KotlinJpsBuildTest.java b/jps-plugin/test/org/jetbrains/jet/jps/build/KotlinJpsBuildTest.java index 92ed4cf7664..695ef09e8c5 100644 --- a/jps-plugin/test/org/jetbrains/jet/jps/build/KotlinJpsBuildTest.java +++ b/jps-plugin/test/org/jetbrains/jet/jps/build/KotlinJpsBuildTest.java @@ -220,8 +220,8 @@ public class KotlinJpsBuildTest extends AbstractKotlinJpsBuildTestCase { // Check that outputs are located properly File facadeWithA = findFileInOutputDir(findModule("module1"), "test/TestPackage.class"); File facadeWithB = findFileInOutputDir(findModule("module2"), "test/TestPackage.class"); - assertSameElements(getMethodsOfClass(facadeWithA), "a", "getA"); - assertSameElements(getMethodsOfClass(facadeWithB), "b", "getB", "setB"); + assertSameElements(getMethodsOfClass(facadeWithA), "", "a", "getA"); + assertSameElements(getMethodsOfClass(facadeWithB), "", "b", "getB", "setB"); checkPackageDeletedFromOutputWhen(Operation.CHANGE, "module1", "module1/src/a.kt", "test.TestPackage"); checkPackageDeletedFromOutputWhen(Operation.CHANGE, "module2", "module2/src/b.kt", "test.TestPackage"); diff --git a/jps-plugin/testData/general/CircularDependenciesSamePackage/module1/src/a.kt b/jps-plugin/testData/general/CircularDependenciesSamePackage/module1/src/a.kt index 4987d3f36ec..8311da66012 100644 --- a/jps-plugin/testData/general/CircularDependenciesSamePackage/module1/src/a.kt +++ b/jps-plugin/testData/general/CircularDependenciesSamePackage/module1/src/a.kt @@ -4,4 +4,4 @@ fun a() { } -val a = "" \ No newline at end of file +val a = "" diff --git a/jps-plugin/testData/general/CircularDependenciesSamePackage/module2/src/b.kt b/jps-plugin/testData/general/CircularDependenciesSamePackage/module2/src/b.kt index 1dcef1df913..b04c387135d 100644 --- a/jps-plugin/testData/general/CircularDependenciesSamePackage/module2/src/b.kt +++ b/jps-plugin/testData/general/CircularDependenciesSamePackage/module2/src/b.kt @@ -4,4 +4,4 @@ fun b() { } -var b = "" \ No newline at end of file +var b = b()