[JS IR] JS AST serialization
This commit is contained in:
committed by
teamcityserver
parent
95ab5e1b7e
commit
b1b88a0d11
+3
-2
@@ -175,7 +175,8 @@ class IrElementToJsStatementTransformer : BaseIrElementToJsNodeTransformer<JsSta
|
||||
override fun visitWhileLoop(loop: IrWhileLoop, context: JsGenerationContext): JsStatement {
|
||||
//TODO what if body null?
|
||||
val label = context.getNameForLoop(loop)
|
||||
val loopStatement = JsWhile(loop.condition.accept(IrElementToJsExpressionTransformer(), context), loop.body?.accept(this, context))
|
||||
val loopStatement = JsWhile(loop.condition.accept(IrElementToJsExpressionTransformer(), context),
|
||||
loop.body?.accept(this, context) ?: JsEmpty)
|
||||
return label?.let { JsLabel(it, loopStatement) } ?: loopStatement
|
||||
}
|
||||
|
||||
@@ -183,7 +184,7 @@ class IrElementToJsStatementTransformer : BaseIrElementToJsNodeTransformer<JsSta
|
||||
//TODO what if body null?
|
||||
val label = context.getNameForLoop(loop)
|
||||
val loopStatement =
|
||||
JsDoWhile(loop.condition.accept(IrElementToJsExpressionTransformer(), context), loop.body?.accept(this, context))
|
||||
JsDoWhile(loop.condition.accept(IrElementToJsExpressionTransformer(), context), loop.body?.accept(this, context) ?: JsEmpty)
|
||||
return label?.let { JsLabel(it, loopStatement) } ?: loopStatement
|
||||
}
|
||||
}
|
||||
|
||||
+25
-1
@@ -13,6 +13,8 @@ import org.jetbrains.kotlin.ir.backend.js.eliminateDeadDeclarations
|
||||
import org.jetbrains.kotlin.ir.backend.js.export.*
|
||||
import org.jetbrains.kotlin.ir.backend.js.lower.StaticMembersLowering
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.*
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.serialization.JsIrAstDeserializer
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.serialization.JsIrAstSerializer
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.util.isEffectivelyExternal
|
||||
import org.jetbrains.kotlin.ir.util.isInterface
|
||||
@@ -26,6 +28,9 @@ import org.jetbrains.kotlin.js.sourceMap.SourceFilePathResolver
|
||||
import org.jetbrains.kotlin.js.sourceMap.SourceMap3Builder
|
||||
import org.jetbrains.kotlin.js.sourceMap.SourceMapBuilderConsumer
|
||||
import org.jetbrains.kotlin.js.util.TextOutputImpl
|
||||
import org.jetbrains.kotlin.serialization.js.ast.JsAstSerializer
|
||||
import java.io.ByteArrayInputStream
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.io.File
|
||||
|
||||
class IrModuleToJsTransformer(
|
||||
@@ -84,7 +89,26 @@ class IrModuleToJsTransformer(
|
||||
}
|
||||
}
|
||||
|
||||
return fragments
|
||||
// TODO remove serialization -> deserialization work
|
||||
val serialized = mutableListOf<Pair<IrFile, ByteArray>>()
|
||||
|
||||
val serializer = JsIrAstSerializer()
|
||||
fragments.entries.forEach { (file, fragment) ->
|
||||
val output = ByteArrayOutputStream()
|
||||
serializer.serialize(fragment, output)
|
||||
val binaryAst = output.toByteArray()
|
||||
serialized += file to binaryAst
|
||||
}
|
||||
|
||||
val restoredMap = mutableMapOf<IrFile, JsIrProgramFragment>()
|
||||
|
||||
val deserializer = JsIrAstDeserializer()
|
||||
|
||||
serialized.forEach { (file, binaryAst) ->
|
||||
restoredMap[file] = deserializer.deserialize(ByteArrayInputStream(binaryAst))
|
||||
}
|
||||
|
||||
return restoredMap
|
||||
}
|
||||
|
||||
private fun generateWrappedModuleBody(
|
||||
|
||||
+98
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.ir.backend.js.utils.serialization
|
||||
|
||||
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.JsIrClassModel
|
||||
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.JsIrProgramFragment
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.emptyScope
|
||||
import org.jetbrains.kotlin.js.backend.ast.*
|
||||
import org.jetbrains.kotlin.js.backend.ast.JsImportedModule
|
||||
import org.jetbrains.kotlin.protobuf.CodedInputStream
|
||||
import org.jetbrains.kotlin.serialization.js.ast.JsAstDeserializerBase
|
||||
import org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.*
|
||||
import java.io.InputStream
|
||||
|
||||
class JsIrAstDeserializer : JsAstDeserializerBase() {
|
||||
override val scope = emptyScope
|
||||
|
||||
fun deserialize(input: InputStream): JsIrProgramFragment {
|
||||
return deserialize(Chunk.parseFrom(CodedInputStream.newInstance(input).apply { setRecursionLimit(4096) }))
|
||||
}
|
||||
|
||||
fun deserialize(proto: Chunk): JsIrProgramFragment {
|
||||
stringTable += proto.stringTable.entryList
|
||||
nameTable += proto.nameTable.entryList
|
||||
nameCache += nameTable.map { null }
|
||||
try {
|
||||
return deserialize(proto.fragment)
|
||||
} finally {
|
||||
stringTable.clear()
|
||||
nameTable.clear()
|
||||
nameCache.clear()
|
||||
}
|
||||
}
|
||||
|
||||
private fun deserialize(proto: Fragment): JsIrProgramFragment {
|
||||
val fragment = JsIrProgramFragment(proto.packageFqn)
|
||||
|
||||
fragment.importedModules += proto.importedModuleList.map { importedModuleProto ->
|
||||
JsImportedModule(
|
||||
deserializeString(importedModuleProto.externalNameId),
|
||||
deserializeName(importedModuleProto.internalNameId),
|
||||
if (importedModuleProto.hasPlainReference()) deserialize(importedModuleProto.plainReference) else null
|
||||
)
|
||||
}
|
||||
|
||||
proto.importEntryList.associateTo(fragment.imports) { importProto ->
|
||||
deserializeString(importProto.signatureId) to deserialize(importProto.expression)
|
||||
}
|
||||
|
||||
if (proto.hasDeclarationBlock()) {
|
||||
fragment.declarations.statements += deserializeGlobalBlock(proto.declarationBlock).statements
|
||||
}
|
||||
if (proto.hasInitializerBlock()) {
|
||||
fragment.initializers.statements += deserializeGlobalBlock(proto.initializerBlock).statements
|
||||
}
|
||||
if (proto.hasExportBlock()) {
|
||||
fragment.exports.statements += deserializeGlobalBlock(proto.exportBlock).statements
|
||||
}
|
||||
|
||||
proto.nameBindingList.associateTo(fragment.nameBindings) { nameBindingProto ->
|
||||
deserializeString(nameBindingProto.signatureId) to deserializeName(nameBindingProto.nameId)
|
||||
}
|
||||
|
||||
proto.irClassModelList.associateTo(fragment.classes) { clsProto -> deserialize(clsProto) }
|
||||
|
||||
if (proto.hasTestsInvocation()) {
|
||||
fragment.testFunInvocation = deserialize(proto.testsInvocation)
|
||||
}
|
||||
|
||||
if (proto.hasMainInvocation()) {
|
||||
fragment.mainFunction = deserialize(proto.mainInvocation)
|
||||
}
|
||||
|
||||
if (proto.hasSuiteFunction()) {
|
||||
fragment.suiteFn = deserializeName(proto.suiteFunction)
|
||||
}
|
||||
|
||||
fragment.dts = proto.dts
|
||||
|
||||
return fragment
|
||||
}
|
||||
|
||||
private fun deserialize(proto: IrClassModel): Pair<JsName, JsIrClassModel> {
|
||||
return deserializeName(proto.nameId) to JsIrClassModel(proto.superClassesList.map { deserializeName(it) }).apply {
|
||||
if (proto.hasPreDeclarationBlock()) {
|
||||
preDeclarationBlock.statements += deserializeGlobalBlock(proto.preDeclarationBlock).statements
|
||||
}
|
||||
if (proto.hasPostDeclarationBlock()) {
|
||||
postDeclarationBlock.statements += deserializeGlobalBlock(proto.postDeclarationBlock).statements
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun embedSources(deserializedLocation: JsLocation, file: String): JsLocationWithSource? = null
|
||||
}
|
||||
+107
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.ir.backend.js.utils.serialization
|
||||
|
||||
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.JsIrClassModel
|
||||
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.JsIrProgramFragment
|
||||
import org.jetbrains.kotlin.js.backend.ast.*
|
||||
import org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.*
|
||||
import org.jetbrains.kotlin.serialization.js.ast.JsAstSerializerBase
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
import java.io.OutputStream
|
||||
|
||||
class JsIrAstSerializer: JsAstSerializerBase() {
|
||||
|
||||
fun serialize(fragment: JsIrProgramFragment, output: OutputStream) {
|
||||
importedNames.clear()
|
||||
importedNames += fragment.imports.map { fragment.nameBindings[it.key]!! }
|
||||
serialize(fragment).writeTo(output)
|
||||
}
|
||||
|
||||
fun serialize(fragment: JsIrProgramFragment): Chunk {
|
||||
try {
|
||||
val chunkBuilder = Chunk.newBuilder()
|
||||
chunkBuilder.fragment = serializeFragment(fragment)
|
||||
chunkBuilder.nameTable = nameTableBuilder.build()
|
||||
chunkBuilder.stringTable = stringTableBuilder.build()
|
||||
return chunkBuilder.build()
|
||||
} finally {
|
||||
nameTableBuilder.clear()
|
||||
stringTableBuilder.clear()
|
||||
nameMap.clear()
|
||||
stringMap.clear()
|
||||
}
|
||||
}
|
||||
|
||||
private fun serializeFragment(fragment: JsIrProgramFragment): Fragment {
|
||||
val fragmentBuilder = Fragment.newBuilder()
|
||||
|
||||
fragmentBuilder.packageFqn = fragment.packageFqn
|
||||
|
||||
for (importedModule in fragment.importedModules) {
|
||||
val importedModuleBuilder = ImportedModule.newBuilder()
|
||||
importedModuleBuilder.externalNameId = serialize(importedModule.externalName)
|
||||
importedModuleBuilder.internalNameId = serialize(importedModule.internalName)
|
||||
importedModule.plainReference?.let { importedModuleBuilder.plainReference = serialize(it) }
|
||||
fragmentBuilder.addImportedModule(importedModuleBuilder)
|
||||
}
|
||||
|
||||
for ((signature, expression) in fragment.imports) {
|
||||
val importBuilder = Import.newBuilder()
|
||||
importBuilder.signatureId = serialize(signature)
|
||||
importBuilder.expression = serialize(expression)
|
||||
fragmentBuilder.addImportEntry(importBuilder)
|
||||
}
|
||||
|
||||
fragmentBuilder.declarationBlock = serializeBlock(fragment.declarations)
|
||||
fragmentBuilder.initializerBlock = serializeBlock(fragment.initializers)
|
||||
fragmentBuilder.exportBlock = serializeBlock(fragment.exports)
|
||||
|
||||
for ((key, name) in fragment.nameBindings.entries) {
|
||||
val nameBindingBuilder = NameBinding.newBuilder()
|
||||
nameBindingBuilder.signatureId = serialize(key)
|
||||
nameBindingBuilder.nameId = serialize(name)
|
||||
fragmentBuilder.addNameBinding(nameBindingBuilder)
|
||||
}
|
||||
|
||||
fragment.classes.entries.forEach { (name, model) -> fragmentBuilder.addIrClassModel(serialize(name, model)) }
|
||||
|
||||
fragment.testFunInvocation?.let {
|
||||
fragmentBuilder.setTestsInvocation(serialize(it))
|
||||
}
|
||||
|
||||
fragment.mainFunction?.let {
|
||||
fragmentBuilder.setMainInvocation(serialize(it))
|
||||
}
|
||||
|
||||
fragment.dts?.let {
|
||||
fragmentBuilder.dts = it
|
||||
}
|
||||
|
||||
fragment.suiteFn?.let {
|
||||
fragmentBuilder.setSuiteFunction(serialize(it))
|
||||
}
|
||||
|
||||
return fragmentBuilder.build()
|
||||
}
|
||||
|
||||
private fun serialize(name: JsName, classModel: JsIrClassModel): IrClassModel {
|
||||
val builder = IrClassModel.newBuilder()
|
||||
builder.nameId = serialize(name)
|
||||
classModel.superClasses.forEach { builder.addSuperClasses(serialize(it)) }
|
||||
if (classModel.preDeclarationBlock.statements.isNotEmpty()) {
|
||||
builder.preDeclarationBlock = serializeBlock(classModel.preDeclarationBlock)
|
||||
}
|
||||
if (classModel.postDeclarationBlock.statements.isNotEmpty()) {
|
||||
builder.postDeclarationBlock = serializeBlock(classModel.postDeclarationBlock)
|
||||
}
|
||||
return builder.build()
|
||||
}
|
||||
|
||||
override fun extractLocation(node: JsNode): JsLocation? {
|
||||
return node.source.safeAs<JsLocationWithSource>()?.asSimpleLocation()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user