diff --git a/compiler/backend/backend.iml b/compiler/backend/backend.iml index e1b68dd0487..d6c4b6e6622 100644 --- a/compiler/backend/backend.iml +++ b/compiler/backend/backend.iml @@ -12,6 +12,8 @@ + + diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java index 637425c0180..3eb787227b9 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java @@ -41,6 +41,7 @@ import org.jetbrains.jet.codegen.signature.kotlin.JetMethodAnnotationWriter; import org.jetbrains.jet.codegen.state.GenerationState; import org.jetbrains.jet.codegen.state.JetTypeMapper; import org.jetbrains.jet.codegen.state.JetTypeMapperMode; +import org.jetbrains.jet.descriptors.serialization.*; import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.descriptors.impl.MutableClassDescriptor; import org.jetbrains.jet.lang.psi.*; @@ -60,17 +61,20 @@ import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lang.types.TypeUtils; import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; import org.jetbrains.jet.lexer.JetTokens; +import org.jetbrains.jet.utils.ExceptionUtils; +import java.io.ByteArrayOutputStream; +import java.io.IOException; import java.util.*; import static org.jetbrains.asm4.Opcodes.*; import static org.jetbrains.jet.codegen.AsmUtil.*; import static org.jetbrains.jet.codegen.CodegenUtil.*; import static org.jetbrains.jet.codegen.binding.CodegenBinding.*; +import static org.jetbrains.jet.descriptors.serialization.ClassSerializationUtil.constantSerializer; import static org.jetbrains.jet.lang.resolve.BindingContextUtils.callableDescriptorToDeclaration; import static org.jetbrains.jet.lang.resolve.BindingContextUtils.descriptorToDeclaration; import static org.jetbrains.jet.lang.resolve.DescriptorUtils.*; -import static org.jetbrains.jet.lang.resolve.DescriptorUtils.isKindOf; import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.JAVA_STRING_TYPE; import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.OBJECT_TYPE; @@ -209,9 +213,31 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { AnnotationCodegen.forClass(v.getVisitor(), typeMapper).genAnnotations(descriptor); + writeKotlinInfoIfNeeded(); + writeClassSignatureIfNeeded(signature); } + private void writeKotlinInfoIfNeeded() { + if (!(descriptor.getContainingDeclaration() instanceof ClassOrNamespaceDescriptor)) return; + + final AnnotationVisitor av = v.getVisitor().visitAnnotation("Ljet/KotlinInfo;", true); + DescriptorSerializer serializer = new DescriptorSerializer(DescriptorNamer.DEFAULT); + + ClassSerializationUtil.serializeClass(descriptor, constantSerializer(serializer), new ClassSerializationUtil.Sink() { + @Override + public void writeClass(@NotNull ClassDescriptor classDescriptor, @NotNull ProtoBuf.Class classProto) { + av.visit("data", classProto.toByteArray()); + } + }); + + ByteArrayOutputStream nameTable = new ByteArrayOutputStream(); + NameSerializationUtil.serializeNameTable(nameTable, serializer.getNameTable()); + av.visit("nameTable", nameTable.toByteArray()); + + av.visitEnd(); + } + private void writeEnclosingMethod() { //JVMS7: A class must have an EnclosingMethod attribute if and only if it is a local class or an anonymous class. DeclarationDescriptor parentDescriptor = descriptor.getContainingDeclaration(); diff --git a/compiler/frontend/serialization/src/org/jetbrains/jet/descriptors/serialization/NameSerializationUtil.java b/compiler/frontend/serialization/src/org/jetbrains/jet/descriptors/serialization/NameSerializationUtil.java index 39222cd44f2..52ff83a7ce6 100644 --- a/compiler/frontend/serialization/src/org/jetbrains/jet/descriptors/serialization/NameSerializationUtil.java +++ b/compiler/frontend/serialization/src/org/jetbrains/jet/descriptors/serialization/NameSerializationUtil.java @@ -17,25 +17,39 @@ package org.jetbrains.jet.descriptors.serialization; import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.utils.ExceptionUtils; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; public class NameSerializationUtil { - @NotNull - public static NameResolver deserializeNameResolver(@NotNull InputStream in) throws IOException { - ProtoBuf.SimpleNameTable simpleNames = ProtoBuf.SimpleNameTable.parseDelimitedFrom(in); - ProtoBuf.QualifiedNameTable qualifiedNames = ProtoBuf.QualifiedNameTable.parseDelimitedFrom(in); - return new NameResolver(simpleNames, qualifiedNames); + private NameSerializationUtil() { } - public static void serializeNameTable(@NotNull OutputStream out, @NotNull NameTable nameTable) throws IOException { - ProtoBuf.SimpleNameTable simpleNamesProto = toSimpleNameTable(nameTable); - simpleNamesProto.writeDelimitedTo(out); + @NotNull + public static NameResolver deserializeNameResolver(@NotNull InputStream in) { + try { + ProtoBuf.SimpleNameTable simpleNames = ProtoBuf.SimpleNameTable.parseDelimitedFrom(in); + ProtoBuf.QualifiedNameTable qualifiedNames = ProtoBuf.QualifiedNameTable.parseDelimitedFrom(in); + return new NameResolver(simpleNames, qualifiedNames); + } + catch (IOException e) { + throw ExceptionUtils.rethrow(e); + } + } - ProtoBuf.QualifiedNameTable qualifiedNameTable = toQualifiedNameTable(nameTable); - qualifiedNameTable.writeDelimitedTo(out); + public static void serializeNameTable(@NotNull OutputStream out, @NotNull NameTable nameTable) { + try { + ProtoBuf.SimpleNameTable simpleNamesProto = toSimpleNameTable(nameTable); + simpleNamesProto.writeDelimitedTo(out); + + ProtoBuf.QualifiedNameTable qualifiedNameTable = toQualifiedNameTable(nameTable); + qualifiedNameTable.writeDelimitedTo(out); + } + catch (IOException e) { + throw ExceptionUtils.rethrow(e); + } } @NotNull diff --git a/compiler/frontend/serialization/src/org/jetbrains/jet/descriptors/serialization/NameTable.java b/compiler/frontend/serialization/src/org/jetbrains/jet/descriptors/serialization/NameTable.java index ae325c2da87..3fbade6e3f4 100644 --- a/compiler/frontend/serialization/src/org/jetbrains/jet/descriptors/serialization/NameTable.java +++ b/compiler/frontend/serialization/src/org/jetbrains/jet/descriptors/serialization/NameTable.java @@ -84,10 +84,13 @@ public class NameTable { NamespaceDescriptor namespaceDescriptor = (NamespaceDescriptor) containingDeclaration; builder.setParentQualifiedName(getFqNameIndex(namespaceDescriptor)); } - else { + else if (containingDeclaration instanceof ClassDescriptor) { ClassDescriptor outerClass = (ClassDescriptor) containingDeclaration; builder.setParentQualifiedName(getFqNameIndex(outerClass)); } + else { + throw new IllegalStateException("FQ names are only stored for top-level or inner classes: " + classDescriptor); + } return qualifiedNames.intern(builder); } diff --git a/compiler/tests/org/jetbrains/jet/JetTestUtils.java b/compiler/tests/org/jetbrains/jet/JetTestUtils.java index e672fe628f1..cd638b1fa22 100644 --- a/compiler/tests/org/jetbrains/jet/JetTestUtils.java +++ b/compiler/tests/org/jetbrains/jet/JetTestUtils.java @@ -43,19 +43,27 @@ import org.jetbrains.jet.config.CompilerConfiguration; import org.jetbrains.jet.lang.ModuleConfiguration; import org.jetbrains.jet.lang.PlatformToKotlinClassMap; import org.jetbrains.jet.lang.descriptors.ModuleDescriptorImpl; +import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; +import org.jetbrains.jet.lang.descriptors.impl.NamespaceDescriptorImpl; import org.jetbrains.jet.lang.diagnostics.Diagnostic; import org.jetbrains.jet.lang.diagnostics.Errors; import org.jetbrains.jet.lang.diagnostics.Severity; import org.jetbrains.jet.lang.diagnostics.rendering.DefaultErrorMessages; import org.jetbrains.jet.lang.psi.JetFile; import org.jetbrains.jet.lang.psi.JetPsiFactory; +import org.jetbrains.jet.lang.psi.JetPsiUtil; import org.jetbrains.jet.lang.resolve.AnalyzerScriptParameter; import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.BindingTrace; import org.jetbrains.jet.lang.resolve.ImportPath; import org.jetbrains.jet.lang.resolve.java.AnalyzerFacadeForJVM; +import org.jetbrains.jet.lang.resolve.java.JavaBridgeConfiguration; +import org.jetbrains.jet.lang.resolve.java.JavaToKotlinClassMap; import org.jetbrains.jet.lang.resolve.lazy.LazyResolveTestUtil; import org.jetbrains.jet.lang.resolve.name.Name; +import org.jetbrains.jet.lang.resolve.scopes.JetScope; +import org.jetbrains.jet.lang.resolve.scopes.RedeclarationHandler; +import org.jetbrains.jet.lang.resolve.scopes.WritableScopeImpl; import org.jetbrains.jet.plugin.JetLanguage; import org.jetbrains.jet.test.InnerTestClasses; import org.jetbrains.jet.test.TestMetadata; @@ -614,4 +622,17 @@ public class JetTestUtils { descriptor.setModuleConfiguration(ModuleConfiguration.EMPTY); return descriptor; } + + @NotNull + public static NamespaceDescriptorImpl createTestNamespace(@NotNull String testPackageName) { + ModuleDescriptorImpl module = new ModuleDescriptorImpl(Name.special(""), JavaBridgeConfiguration.ALL_JAVA_IMPORTS, + JavaToKotlinClassMap.getInstance()); + NamespaceDescriptorImpl rootNamespace = + new NamespaceDescriptorImpl(module, Collections.emptyList(), JetPsiUtil.ROOT_NAMESPACE_NAME); + module.setRootNamespace(rootNamespace); + NamespaceDescriptorImpl test = + new NamespaceDescriptorImpl(rootNamespace, Collections.emptyList(), Name.identifier(testPackageName)); + test.initialize(new WritableScopeImpl(JetScope.EMPTY, test, RedeclarationHandler.DO_NOTHING, "members of test namespace")); + return test; + } } diff --git a/compiler/tests/org/jetbrains/jet/descriptors/serialization/BuiltinsDeserializationTest.java b/compiler/tests/org/jetbrains/jet/descriptors/serialization/BuiltinsDeserializationTest.java index df8b1a24bd4..2a14c3aac34 100644 --- a/compiler/tests/org/jetbrains/jet/descriptors/serialization/BuiltinsDeserializationTest.java +++ b/compiler/tests/org/jetbrains/jet/descriptors/serialization/BuiltinsDeserializationTest.java @@ -21,31 +21,28 @@ import com.google.common.collect.Maps; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.ConfigurationKind; +import org.jetbrains.jet.JetTestUtils; import org.jetbrains.jet.TestJdkKind; import org.jetbrains.jet.cli.jvm.compiler.JetCoreEnvironment; import org.jetbrains.jet.descriptors.serialization.descriptors.AnnotationDeserializer; import org.jetbrains.jet.jvm.compiler.ExpectedLoadErrorsUtil; import org.jetbrains.jet.lang.descriptors.*; -import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; import org.jetbrains.jet.lang.descriptors.impl.NamespaceDescriptorImpl; -import org.jetbrains.jet.lang.psi.JetPsiUtil; import org.jetbrains.jet.lang.resolve.DescriptorUtils; -import org.jetbrains.jet.lang.resolve.java.JavaBridgeConfiguration; -import org.jetbrains.jet.lang.resolve.java.JavaToKotlinClassMap; import org.jetbrains.jet.lang.resolve.lazy.KotlinTestWithEnvironment; import org.jetbrains.jet.lang.resolve.lazy.storage.LockBasedStorageManager; import org.jetbrains.jet.lang.resolve.name.FqName; import org.jetbrains.jet.lang.resolve.name.Name; -import org.jetbrains.jet.lang.resolve.scopes.JetScope; -import org.jetbrains.jet.lang.resolve.scopes.RedeclarationHandler; import org.jetbrains.jet.lang.resolve.scopes.WritableScope; -import org.jetbrains.jet.lang.resolve.scopes.WritableScopeImpl; import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; import org.jetbrains.jet.renderer.DescriptorRenderer; import org.jetbrains.jet.renderer.DescriptorRendererBuilder; import org.jetbrains.jet.test.util.NamespaceComparator; -import java.util.*; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.Map; import static org.jetbrains.jet.descriptors.serialization.ClassSerializationUtil.constantSerializer; @@ -95,7 +92,8 @@ public class BuiltinsDeserializationTest extends KotlinTestWithEnvironment { List callableProtos = serializeCallables(serializer, allDescriptors); - final NamespaceDescriptorImpl actualNamespace = createTestNamespace(KotlinBuiltIns.BUILT_INS_PACKAGE_FQ_NAME.shortName().asString()); + final NamespaceDescriptorImpl actualNamespace = JetTestUtils + .createTestNamespace(KotlinBuiltIns.BUILT_INS_PACKAGE_FQ_NAME.shortName().asString()); final NameResolver nameResolver = NameSerializationUtil.createNameResolver(serializer.getNameTable()); @@ -215,16 +213,4 @@ public class BuiltinsDeserializationTest extends KotlinTestWithEnvironment { private static ClassId getClassId(ClassDescriptor classDescriptor) { return ClassSerializationUtil.getClassId(classDescriptor, NAMER); } - - private static NamespaceDescriptorImpl createTestNamespace(String testPackageName) { - ModuleDescriptorImpl module = new ModuleDescriptorImpl(Name.special(""), JavaBridgeConfiguration.ALL_JAVA_IMPORTS, - JavaToKotlinClassMap.getInstance()); - NamespaceDescriptorImpl rootNamespace = - new NamespaceDescriptorImpl(module, Collections.emptyList(), JetPsiUtil.ROOT_NAMESPACE_NAME); - module.setRootNamespace(rootNamespace); - NamespaceDescriptorImpl test = - new NamespaceDescriptorImpl(rootNamespace, Collections.emptyList(), Name.identifier(testPackageName)); - test.initialize(new WritableScopeImpl(JetScope.EMPTY, test, RedeclarationHandler.DO_NOTHING, "members of test namespace")); - return test; - } } diff --git a/compiler/tests/org/jetbrains/jet/descriptors/serialization/WriteSerializedInfoTest.java b/compiler/tests/org/jetbrains/jet/descriptors/serialization/WriteSerializedInfoTest.java new file mode 100644 index 00000000000..f5bbac3e51b --- /dev/null +++ b/compiler/tests/org/jetbrains/jet/descriptors/serialization/WriteSerializedInfoTest.java @@ -0,0 +1,110 @@ +/* + * Copyright 2010-2013 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.jet.descriptors.serialization; + +import com.google.protobuf.InvalidProtocolBufferException; +import jet.KotlinInfo; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.ConfigurationKind; +import org.jetbrains.jet.JetTestUtils; +import org.jetbrains.jet.codegen.CodegenTestCase; +import org.jetbrains.jet.descriptors.serialization.descriptors.AnnotationDeserializer; +import org.jetbrains.jet.lang.descriptors.ClassDescriptor; +import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; +import org.jetbrains.jet.lang.descriptors.impl.NamespaceDescriptorImpl; +import org.jetbrains.jet.lang.resolve.lazy.storage.LockBasedStorageManager; +import org.jetbrains.jet.lang.resolve.name.FqName; +import org.jetbrains.jet.lang.resolve.name.FqNameUnsafe; +import org.jetbrains.jet.lang.resolve.name.Name; + +import java.io.ByteArrayInputStream; + +public class WriteSerializedInfoTest extends CodegenTestCase { + public static final FqName NAMESPACE_NAME = new FqName("test"); + public static final FqNameUnsafe CLASS_NAME = new FqNameUnsafe("A"); + + @Override + protected void setUp() throws Exception { + super.setUp(); + createEnvironmentWithMockJdkAndIdeaAnnotations(ConfigurationKind.ALL); + } + + public void testKotlinInfo() throws Exception { + loadText("package " + NAMESPACE_NAME + "\n" + + "\n" + + "class " + CLASS_NAME + " {\n" + + " fun foo() {}\n" + + " fun bar() = 42\n" + + "}\n"); + Class aClass = generateClass(NAMESPACE_NAME + "." + CLASS_NAME); + + assertTrue(aClass.isAnnotationPresent(KotlinInfo.class)); + KotlinInfo kotlinInfo = (KotlinInfo) aClass.getAnnotation(KotlinInfo.class); + + AbstractClassResolver classResolver = new KotlinInfoBasedClassResolver(kotlinInfo); + + ClassDescriptor descriptor = classResolver.findClass(new ClassId(NAMESPACE_NAME, CLASS_NAME)); + assertNotNull(descriptor); + assertEquals(CLASS_NAME.asString(), descriptor.getName().asString()); + } + + private static class KotlinInfoBasedClassResolver extends AbstractClassResolver { + private final NameResolver nameResolver; + private final ProtoBuf.Class classProto; + private final NamespaceDescriptorImpl namespace; + + public KotlinInfoBasedClassResolver(@NotNull KotlinInfo kotlinInfo) throws InvalidProtocolBufferException { + super(new LockBasedStorageManager(), AnnotationDeserializer.UNSUPPORTED); + + this.nameResolver = NameSerializationUtil.deserializeNameResolver(new ByteArrayInputStream(kotlinInfo.nameTable())); + this.classProto = ProtoBuf.Class.parseFrom(kotlinInfo.data()); + this.namespace = JetTestUtils.createTestNamespace(NAMESPACE_NAME.asString()); + } + + @Nullable + @Override + protected ClassData getClassData(@NotNull ClassId classId) { + assert classId.getPackageFqName().equals(NAMESPACE_NAME) && + classId.getRelativeClassName().equals(CLASS_NAME) : "Unsupported classId: " + classId; + return new ClassData(nameResolver, classProto); + } + + @NotNull + @Override + protected DeclarationDescriptor getPackage(@NotNull FqName fqName) { + assert fqName.equals(NAMESPACE_NAME) : "Unsupported namespace: " + fqName; + return namespace; + } + + @NotNull + @Override + protected ClassId getClassId(@NotNull ClassDescriptor classDescriptor) { + return ClassSerializationUtil.getClassId(classDescriptor, DescriptorNamer.DEFAULT); + } + + @NotNull + @Override + protected Name getClassObjectName(@NotNull ClassDescriptor outerClass) { + return Name.special(""); + } + + @Override + protected void classDescriptorCreated(@NotNull ClassDescriptor classDescriptor) { + } + } +} diff --git a/runtime/src/jet/KotlinInfo.java b/runtime/src/jet/KotlinInfo.java new file mode 100644 index 00000000000..cbbd5bd8dde --- /dev/null +++ b/runtime/src/jet/KotlinInfo.java @@ -0,0 +1,27 @@ +/* + * Copyright 2010-2013 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package jet; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +@Retention(RetentionPolicy.RUNTIME) +public @interface KotlinInfo { + byte[] data(); + + byte[] nameTable(); +}