Rework BuiltInsSerializer

BuiltInsSerializer will be distributed with Kotlin compiler from now on. This
will allow to serialize binary data of built-ins on 'ant dist', as opposed to
storing all *.kotlin_class files in the repository: ant dist will just invoke
this serializer from bootstrap-compiler.jar
This commit is contained in:
Alexander Udalov
2014-01-20 22:36:34 +04:00
parent d4c98ec18c
commit db9d0e381b
12 changed files with 288 additions and 251 deletions
@@ -1,168 +0,0 @@
/*
* 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.generators.builtins;
import com.google.common.collect.ImmutableSet;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.io.FileUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.JetTestUtils;
import org.jetbrains.jet.cli.jvm.compiler.JetCoreEnvironment;
import org.jetbrains.jet.config.CompilerConfiguration;
import org.jetbrains.jet.descriptors.serialization.*;
import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
import org.jetbrains.jet.lang.resolve.lazy.LazyResolveTestUtil;
import org.jetbrains.jet.lang.resolve.name.Name;
import org.jetbrains.jet.lang.types.lang.BuiltInsSerializationUtil;
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
import org.jetbrains.jet.test.util.DescriptorValidator;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;
public class BuiltInsSerializer {
private static final String BUILT_INS_SRC_DIR = "idea/builtinsSrc";
public static final String DEST_DIR = "compiler/frontend/builtins";
private static int totalSize = 0;
private static int totalFiles = 0;
private BuiltInsSerializer() {
}
public static void main(String[] args) throws IOException {
System.setProperty("java.awt.headless", "true");
serializeToDir(new File(DEST_DIR), System.out);
}
public static void serializeToDir(final File destDir, @Nullable final PrintStream out) throws IOException {
Disposable rootDisposable = Disposer.newDisposable();
try {
List<File> sourceFiles = FileUtil.findFilesByMask(Pattern.compile(".*\\.kt"), new File(BUILT_INS_SRC_DIR));
CompilerConfiguration configuration = new CompilerConfiguration();
JetCoreEnvironment environment = JetCoreEnvironment.createForTests(rootDisposable, configuration);
List<JetFile> files = JetTestUtils.loadToJetFiles(environment, sourceFiles);
ModuleDescriptor module = LazyResolveTestUtil.resolveLazily(files, environment, false);
PackageViewDescriptor packageView = module.getPackage(KotlinBuiltIns.BUILT_INS_PACKAGE_FQ_NAME);
assert packageView != null : "Package not found: " + KotlinBuiltIns.BUILT_INS_PACKAGE_FQ_NAME;
DescriptorValidator.validate(packageView);
if (!FileUtil.delete(destDir)) {
System.err.println("Could not delete: " + destDir);
}
if (!destDir.mkdirs()) {
System.err.println("Could not make directories: " + destDir);
}
DescriptorSerializer serializer = new DescriptorSerializer(new SerializerExtension() {
private final ImmutableSet<String> set = ImmutableSet.of("Any", "Nothing");
@Override
public boolean hasSupertypes(@NotNull ClassDescriptor classDescriptor) {
return !set.contains(classDescriptor.getName().asString());
}
});
final List<Name> classNames = new ArrayList<Name>();
List<DeclarationDescriptor> allDescriptors = DescriptorSerializer.sort(packageView.getMemberScope().getAllDescriptors());
ClassSerializationUtil.serializeClasses(allDescriptors, serializer, new ClassSerializationUtil.Sink() {
@Override
public void writeClass(@NotNull ClassDescriptor classDescriptor, @NotNull ProtoBuf.Class classProto) {
try {
ByteArrayOutputStream stream = new ByteArrayOutputStream();
classProto.writeTo(stream);
write(destDir, getFileName(classDescriptor), stream, out);
if (DescriptorUtils.isTopLevelDeclaration(classDescriptor)) {
classNames.add(classDescriptor.getName());
}
}
catch (IOException e) {
throw new AssertionError(e);
}
}
});
ByteArrayOutputStream classNamesStream = new ByteArrayOutputStream();
writeClassNames(serializer, classNames, classNamesStream);
write(destDir, BuiltInsSerializationUtil.getClassNamesFilePath(packageView.getFqName()), classNamesStream, out);
ByteArrayOutputStream packageStream = new ByteArrayOutputStream();
List<PackageFragmentDescriptor> fragments =
module.getPackageFragmentProvider().getPackageFragments(packageView.getFqName());
ProtoBuf.Package packageProto = serializer.packageProto(fragments).build();
packageProto.writeTo(packageStream);
write(destDir, BuiltInsSerializationUtil.getPackageFilePath(packageView.getFqName()), packageStream, out);
ByteArrayOutputStream nameStream = new ByteArrayOutputStream();
NameSerializationUtil.serializeNameTable(nameStream, serializer.getNameTable());
write(destDir, BuiltInsSerializationUtil.getNameTableFilePath(packageView.getFqName()), nameStream, out);
if (out != null) {
out.println("Total bytes written: " + totalSize + " to " + totalFiles + " files");
}
}
finally {
Disposer.dispose(rootDisposable);
}
}
private static void writeClassNames(
@NotNull DescriptorSerializer serializer,
@NotNull List<Name> classNames,
@NotNull ByteArrayOutputStream stream
) throws IOException {
DataOutputStream data = new DataOutputStream(stream);
try {
data.writeInt(classNames.size());
for (Name className : classNames) {
int index = serializer.getNameTable().getSimpleNameIndex(className);
data.writeInt(index);
}
}
finally {
data.close();
}
}
private static void write(
@NotNull File destDir,
@NotNull String fileName,
@NotNull ByteArrayOutputStream stream,
@Nullable PrintStream out
) throws IOException {
totalSize += stream.size();
totalFiles++;
FileUtil.writeToFile(new File(destDir, fileName), stream.toByteArray());
if (out != null) {
out.println(stream.size() + " bytes written to " + fileName);
}
}
@NotNull
private static String getFileName(@NotNull ClassDescriptor classDescriptor) {
return BuiltInsSerializationUtil.getClassMetadataPath(ClassSerializationUtil.getClassId(classDescriptor));
}
}
@@ -1,61 +0,0 @@
/*
* 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.generators.builtins
import com.intellij.openapi.util.io.FileUtil
import com.intellij.testFramework.UsefulTestCase
import com.intellij.util.Function
import com.intellij.util.containers.ContainerUtil
import org.jetbrains.jet.JetTestUtils
import java.io.File
import java.util.Arrays
import java.util.HashSet
import java.util.regex.Pattern
import junit.framework.Assert
public open class BuiltInsSerializerTest() : UsefulTestCase() {
public fun testBuiltIns() {
val actual = JetTestUtils.tmpDir("builtins")
BuiltInsSerializer.serializeToDir(actual, null)
val expected = File(BuiltInsSerializer.DEST_DIR)
val actualFiles = getAllFiles(actual)
val expectedFiles = getAllFiles(expected)
val actualNames = getFileNames(actualFiles)
val expectedNames = getFileNames(expectedFiles)
Assert.assertEquals("File name sets differ. Re-run BuiltInsSerializer", expectedNames, actualNames)
for (actualFile in actualFiles) {
if (actualFile.isDirectory()) continue
val relativePath = FileUtil.getRelativePath(actual, actualFile)!!
val expectedFile = File(expected, relativePath)
val expectedBytes = FileUtil.loadFileBytes(expectedFile)
val actualBytes = FileUtil.loadFileBytes(actualFile)
Assert.assertTrue("File contents differ for $expectedFile and $actualFile. Re-run BuiltInsSerializer",
Arrays.equals(expectedBytes, actualBytes))
}
println("${actualFiles.size()} files checked")
}
private fun getAllFiles(actual: File): List<File> = FileUtil.findFilesByMask(Pattern.compile(".*"), actual)
private fun getFileNames(actualFiles: List<File>): Set<String> = HashSet(ContainerUtil.map(actualFiles, {f -> f!!.getName()}))
}