-
Notifications
You must be signed in to change notification settings - Fork 146
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
As K2 allows us to declare our own version of IrDeserializer, this cl is also fixing the orphaned node issue and the SOE in the inliner. PiperOrigin-RevId: 696305329
- Loading branch information
1 parent
da07252
commit d1de80c
Showing
8 changed files
with
2,500 additions
and
417 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
976 changes: 976 additions & 0 deletions
976
transpiler/java/com/google/j2cl/transpiler/frontend/kotlin/ir/IrBodyDeserializer.kt
Large diffs are not rendered by default.
Oops, something went wrong.
1,066 changes: 1,066 additions & 0 deletions
1,066
transpiler/java/com/google/j2cl/transpiler/frontend/kotlin/ir/IrDeclarationDeserializer.kt
Large diffs are not rendered by default.
Oops, something went wrong.
319 changes: 319 additions & 0 deletions
319
transpiler/java/com/google/j2cl/transpiler/frontend/kotlin/ir/deserializeLazyDeclarations.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,319 @@ | ||
/* | ||
* 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 com.google.j2cl.transpiler.frontend.kotlin.ir | ||
|
||
import org.jetbrains.kotlin.backend.common.linkage.partial.PartialLinkageSupportForLinker | ||
import org.jetbrains.kotlin.backend.common.overrides.FakeOverrideDeclarationTable | ||
import org.jetbrains.kotlin.backend.common.overrides.FileLocalAwareLinker | ||
import org.jetbrains.kotlin.backend.common.overrides.IrLinkerFakeOverrideProvider | ||
import org.jetbrains.kotlin.backend.common.serialization.* | ||
import org.jetbrains.kotlin.backend.common.serialization.encodings.BinarySymbolData | ||
import org.jetbrains.kotlin.backend.common.serialization.proto.IdSignature as ProtoIdSignature | ||
import org.jetbrains.kotlin.backend.common.serialization.proto.IrDeclaration as ProtoDeclaration | ||
import org.jetbrains.kotlin.backend.common.serialization.proto.IrExpression as ProtoExpression | ||
import org.jetbrains.kotlin.backend.common.serialization.proto.IrStatement as ProtoStatement | ||
import org.jetbrains.kotlin.backend.common.serialization.proto.IrType as ProtoType | ||
import org.jetbrains.kotlin.backend.common.serialization.signature.IdSignatureFactory | ||
import org.jetbrains.kotlin.backend.jvm.JvmGeneratorExtensions | ||
import org.jetbrains.kotlin.backend.jvm.JvmIrDeserializer | ||
import org.jetbrains.kotlin.backend.jvm.JvmIrTypeSystemContext | ||
import org.jetbrains.kotlin.backend.jvm.lower.SingletonObjectJvmStaticTransformer | ||
import org.jetbrains.kotlin.backend.jvm.serialization.proto.JvmIr | ||
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities | ||
import org.jetbrains.kotlin.ir.IrBuiltIns | ||
import org.jetbrains.kotlin.ir.IrElement | ||
import org.jetbrains.kotlin.ir.backend.jvm.serialization.JvmIrMangler | ||
import org.jetbrains.kotlin.ir.declarations.IrClass | ||
import org.jetbrains.kotlin.ir.declarations.IrDeclaration | ||
import org.jetbrains.kotlin.ir.declarations.impl.IrFileImpl | ||
import org.jetbrains.kotlin.ir.linkage.IrProvider | ||
import org.jetbrains.kotlin.ir.symbols.IrPropertySymbol | ||
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol | ||
import org.jetbrains.kotlin.ir.symbols.IrSymbol | ||
import org.jetbrains.kotlin.ir.symbols.impl.IrFileSymbolImpl | ||
import org.jetbrains.kotlin.ir.types.IrTypeSystemContext | ||
import org.jetbrains.kotlin.ir.util.* | ||
import org.jetbrains.kotlin.ir.util.SymbolTable | ||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid | ||
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid | ||
import org.jetbrains.kotlin.ir.visitors.acceptVoid | ||
import org.jetbrains.kotlin.load.kotlin.JvmPackagePartSource | ||
import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinarySourceElement | ||
|
||
// Copied and modified from org.jetbrains.kotlin.backend.jvm.JvmIrDeserializerImpl and | ||
// org.jetbrains.kotlin.backend.jvm.serialization.deserializeLazyDeclarations.kt | ||
class JvmIrDeserializerImpl : JvmIrDeserializer { | ||
override fun deserializeTopLevelClass( | ||
irClass: IrClass, | ||
irBuiltIns: IrBuiltIns, | ||
symbolTable: SymbolTable, | ||
irProviders: List<IrProvider>, | ||
extensions: JvmGeneratorExtensions, | ||
): Boolean { | ||
val serializedIr = | ||
when (val source = irClass.source) { | ||
is KotlinJvmBinarySourceElement -> source.binaryClass.classHeader.serializedIr | ||
is JvmPackagePartSource -> source.knownJvmBinaryClass?.classHeader?.serializedIr | ||
else -> null | ||
} ?: return false | ||
deserializeFromByteArray( | ||
serializedIr, | ||
irBuiltIns, | ||
symbolTable, | ||
irProviders, | ||
irClass, | ||
JvmIrTypeSystemContext(irBuiltIns), | ||
) | ||
|
||
irClass.transform( | ||
SingletonObjectJvmStaticTransformer(irBuiltIns, extensions.cachedFields), | ||
null, | ||
) | ||
|
||
return true | ||
} | ||
} | ||
|
||
fun deserializeFromByteArray( | ||
byteArray: ByteArray, | ||
irBuiltIns: IrBuiltIns, | ||
symbolTable: SymbolTable, | ||
irProviders: List<IrProvider>, | ||
toplevelParent: IrClass, | ||
typeSystemContext: IrTypeSystemContext, | ||
) { | ||
// MODIFIED BY GOOGLE | ||
// Ensure symbols of all class declarations are populated in the symbol table to avoid the | ||
// deserializer to create new IR nodes instead of modifying the existing ones. | ||
symbolTable.addSymbolsRecursively(toplevelParent.symbol) | ||
// END OF MODIFICATIONS | ||
|
||
val irInterner = IrInterningService() | ||
val irProto = JvmIr.ClassOrFile.parseFrom(byteArray.codedInputStream) | ||
val irLibraryFile = | ||
IrLibraryFileFromAnnotation( | ||
irProto.typeList, | ||
irProto.signatureList, | ||
irProto.stringList, | ||
irProto.bodyList, | ||
irProto.debugInfoList, | ||
) | ||
|
||
// Only needed for local signature computation. | ||
val dummyIrFile = | ||
IrFileImpl( | ||
NaiveSourceBasedFileEntryImpl("<unknown>"), | ||
IrFileSymbolImpl(), | ||
toplevelParent.packageFqName!!, | ||
) | ||
// On JVM, file-scope private declarations are uniquely identified by file facade's fq name. | ||
val dummyFileSignature = | ||
IdSignature.FileSignature(irProto.fileFacadeFqName, toplevelParent.packageFqName!!, "<unknown>") | ||
|
||
val symbolDeserializer = | ||
IrSymbolDeserializer( | ||
symbolTable, | ||
irLibraryFile, | ||
fileSymbol = dummyIrFile.symbol, | ||
fileSignature = dummyFileSignature, | ||
enqueueLocalTopLevelDeclaration = {}, // just link to it in symbolTable | ||
irInterner = irInterner, | ||
) { idSignature, symbolKind -> | ||
referencePublicSymbol(symbolTable, idSignature, symbolKind) | ||
} | ||
|
||
// We have to supply topLevelParent here, but this results in wrong values for parent fields in | ||
// deeply embedded declarations. | ||
// Patching will be needed. | ||
val deserializer = | ||
IrDeclarationDeserializer( | ||
irBuiltIns, | ||
symbolTable, | ||
irBuiltIns.irFactory, | ||
irLibraryFile, | ||
toplevelParent, | ||
allowAlreadyBoundSymbols = true, | ||
allowErrorNodes = false, | ||
deserializeInlineFunctions = true, | ||
deserializeBodies = true, | ||
symbolDeserializer, | ||
onDeserializedClass = { _, _ -> }, | ||
needToDeserializeFakeOverrides = { false }, | ||
specialProcessingForMismatchedSymbolKind = null, | ||
irInterner = irInterner, | ||
) | ||
for (declarationProto in irProto.declarationList) { | ||
// MODIFIED BY GOOGLE | ||
// Ensure that the deserializer set a parent for top level inline members. | ||
// original code: | ||
// deserializer.deserializeDeclaration(declarationProto, setParent = false) | ||
val unused = | ||
deserializer.deserializeDeclaration( | ||
declarationProto, | ||
setParent = toplevelParent.isFacadeClass, | ||
) | ||
// END OF MODIFICATION. | ||
} | ||
|
||
val signaturer = symbolTable.signaturer | ||
if (signaturer == null) { | ||
ExternalDependenciesGenerator(symbolTable, irProviders).generateUnboundSymbolsAsDependencies() | ||
} else { | ||
signaturer.withFileSignature(dummyFileSignature) { | ||
ExternalDependenciesGenerator(symbolTable, irProviders).generateUnboundSymbolsAsDependencies() | ||
} | ||
} | ||
|
||
toplevelParent.safelyInitializeAllLazyDescendants() | ||
toplevelParent.patchDeclarationParents() | ||
buildFakeOverridesForLocalClasses( | ||
symbolTable, | ||
typeSystemContext, | ||
symbolDeserializer, | ||
toplevelParent, | ||
) | ||
} | ||
|
||
private fun IrElement.safelyInitializeAllLazyDescendants() { | ||
// Traversal may trigger initialization of some child declaration, | ||
// which may trigger initialization of some other IR element (e.g., IrProperty -> its | ||
// getter/setter IrFunctions)., | ||
// which may trigger adding it to its parent element (e.g. JvmFileFacadeClass), | ||
// which may happen to be some element we are currently traversing, | ||
// which would throw ConcurrentModificationException. | ||
// The workaround is to traverse the subtree over snapshots first. | ||
|
||
acceptVoid( | ||
object : IrElementVisitorVoid { | ||
override fun visitElement(element: IrElement) { | ||
val directChildrenSnapshot = mutableListOf<IrElement>() | ||
element.acceptChildrenVoid( | ||
object : IrElementVisitorVoid { | ||
override fun visitElement(element: IrElement) { | ||
directChildrenSnapshot += element | ||
} | ||
} | ||
) | ||
|
||
for (child in directChildrenSnapshot) { | ||
child.acceptChildrenVoid(this) | ||
} | ||
} | ||
} | ||
) | ||
} | ||
|
||
private class IrLibraryFileFromAnnotation( | ||
private val types: List<ProtoType>, | ||
private val signatures: List<ProtoIdSignature>, | ||
private val strings: List<String>, | ||
private val bodies: List<JvmIr.XStatementOrExpression>, | ||
private val debugInfo: List<String>, | ||
) : IrLibraryFile() { | ||
override fun declaration(index: Int): ProtoDeclaration { | ||
error("This method is never supposed to be called") | ||
} | ||
|
||
override fun type(index: Int): ProtoType = types[index] | ||
|
||
override fun signature(index: Int): ProtoIdSignature = signatures[index] | ||
|
||
override fun string(index: Int): String = strings[index] | ||
|
||
override fun debugInfo(index: Int): String = debugInfo[index] | ||
|
||
override fun expressionBody(index: Int): ProtoExpression = | ||
bodies[index].also { require(it.hasExpression()) }.expression | ||
|
||
override fun statementBody(index: Int): ProtoStatement = | ||
bodies[index].also { require(it.hasStatement()) }.statement | ||
} | ||
|
||
// TODO: try to use plugin context here | ||
private fun referencePublicSymbol( | ||
symbolTable: SymbolTable, | ||
idSig: IdSignature, | ||
symbolKind: BinarySymbolData.SymbolKind, | ||
): IrSymbol { | ||
with(symbolTable) { | ||
return when (symbolKind) { | ||
BinarySymbolData.SymbolKind.CLASS_SYMBOL -> referenceClass(idSig) | ||
BinarySymbolData.SymbolKind.CONSTRUCTOR_SYMBOL -> referenceConstructor(idSig) | ||
BinarySymbolData.SymbolKind.ENUM_ENTRY_SYMBOL -> referenceEnumEntry(idSig) | ||
BinarySymbolData.SymbolKind.STANDALONE_FIELD_SYMBOL, | ||
BinarySymbolData.SymbolKind.FIELD_SYMBOL -> referenceField(idSig) | ||
BinarySymbolData.SymbolKind.FUNCTION_SYMBOL -> referenceSimpleFunction(idSig) | ||
BinarySymbolData.SymbolKind.TYPEALIAS_SYMBOL -> referenceTypeAlias(idSig) | ||
BinarySymbolData.SymbolKind.PROPERTY_SYMBOL -> referenceProperty(idSig) | ||
BinarySymbolData.SymbolKind.TYPE_PARAMETER_SYMBOL -> referenceTypeParameter(idSig) | ||
else -> error("Unexpected classifier symbol kind: $symbolKind for signature $idSig") | ||
} | ||
} | ||
} | ||
|
||
// TODO: implement properly | ||
fun makeSimpleFakeOverrideBuilder( | ||
symbolTable: SymbolTable, | ||
typeSystemContext: IrTypeSystemContext, | ||
symbolDeserializer: IrSymbolDeserializer, | ||
): IrLinkerFakeOverrideProvider { | ||
return IrLinkerFakeOverrideProvider( | ||
object : FileLocalAwareLinker { | ||
override fun tryReferencingPropertyByLocalSignature( | ||
parent: IrDeclaration, | ||
idSignature: IdSignature, | ||
): IrPropertySymbol = symbolDeserializer.referencePropertyByLocalSignature(idSignature) | ||
|
||
override fun tryReferencingSimpleFunctionByLocalSignature( | ||
parent: IrDeclaration, | ||
idSignature: IdSignature, | ||
): IrSimpleFunctionSymbol = | ||
symbolDeserializer.referenceSimpleFunctionByLocalSignature(idSignature) | ||
}, | ||
symbolTable, | ||
JvmIrMangler, | ||
typeSystemContext, | ||
fakeOverrideDeclarationTable = | ||
PrePopulatedDeclarationTable(symbolDeserializer.deserializedSymbols), | ||
friendModules = emptyMap(), // TODO: provide friend modules | ||
partialLinkageSupport = PartialLinkageSupportForLinker.DISABLED, | ||
) | ||
} | ||
|
||
private fun buildFakeOverridesForLocalClasses( | ||
symbolTable: SymbolTable, | ||
typeSystemContext: IrTypeSystemContext, | ||
symbolDeserializer: IrSymbolDeserializer, | ||
toplevel: IrClass, | ||
) { | ||
val builder = makeSimpleFakeOverrideBuilder(symbolTable, typeSystemContext, symbolDeserializer) | ||
toplevel.acceptChildrenVoid( | ||
object : IrElementVisitorVoid { | ||
override fun visitElement(element: IrElement) { | ||
element.acceptChildrenVoid(this) | ||
} | ||
|
||
override fun visitClass(declaration: IrClass) { | ||
if (declaration.visibility == DescriptorVisibilities.LOCAL) { | ||
builder.provideFakeOverrides(declaration, CompatibilityMode.CURRENT) | ||
} | ||
super.visitClass(declaration) | ||
} | ||
} | ||
) | ||
} | ||
|
||
class PrePopulatedDeclarationTable(sig2symbol: Map<IdSignature, IrSymbol>) : | ||
FakeOverrideDeclarationTable(JvmIrMangler, signatureSerializerFactory = ::IdSignatureFactory) { | ||
private val symbol2Sig = sig2symbol.entries.associate { (x, y) -> y to x } | ||
|
||
override fun tryComputeBackendSpecificSignature(declaration: IrDeclaration): IdSignature? { | ||
symbol2Sig[declaration.symbol]?.let { | ||
return it | ||
} | ||
return super.tryComputeBackendSpecificSignature(declaration) | ||
} | ||
} |
Oops, something went wrong.