[JS IR BE] Move IrSerializer from native to JS

* Fix issues
This commit is contained in:
Roman Artemev
2019-01-29 18:18:00 +03:00
committed by romanart
parent 5384f23f30
commit 3a444cd0f3
38 changed files with 62204 additions and 125 deletions
@@ -583,7 +583,7 @@ open class WrappedClassDescriptor(
private val _typeConstructor: TypeConstructor by lazy {
LazyTypeConstructor(
this,
{ emptyList() },
{ declaredTypeParameters },
{ owner.superTypes.map { it.toKotlinType() } },
LockBasedStorageManager.NO_LOCKS
)
@@ -36,6 +36,7 @@ import org.jetbrains.kotlin.ir.expressions.IrCall
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrExpressionBody
import org.jetbrains.kotlin.ir.expressions.IrFunctionReference
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.IrBlockBodyImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrDelegatingConstructorCallImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
@@ -386,6 +387,8 @@ fun IrClass.createImplicitParameterDeclarationWithWrappedDescriptor() {
assert(descriptor.declaredTypeParameters.isEmpty())
}
fun isElseBranch(branch: IrBranch) = branch is IrElseBranch || ((branch.condition as? IrConst<Boolean>)?.value == true)
fun IrSimpleFunction.isMethodOfAny() =
((valueParameters.size == 0 && name.asString().let { it == "hashCode" || it == "toString" }) ||
(valueParameters.size == 1 && name.asString() == "equals" && valueParameters[0].type.isNullableAny()))
@@ -34,6 +34,7 @@ import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.ir.types.IrSimpleType
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.classifierOrFail
import org.jetbrains.kotlin.ir.types.isAny
import org.jetbrains.kotlin.ir.util.defaultType
import org.jetbrains.kotlin.ir.visitors.IrElementTransformer
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
@@ -209,7 +210,9 @@ fun IrConstructor.callsSuper(irBuiltIns: IrBuiltIns): Boolean {
assert(++numberOfCalls == 1) { "More than one delegating constructor call: ${symbol.owner}" }
val delegatingClass = expression.symbol.owner.parent as IrClass
// TODO: figure out why Lazy IR multiplies Declarations for descriptors and fix it
if (delegatingClass.descriptor == superClass.classifierOrFail.descriptor)
if (delegatingClass.descriptor == superClass.classifierOrFail.descriptor || (
delegatingClass.defaultType.isAny() && superClass.isAny()
))
callsSuper = true
else if (delegatingClass.descriptor != constructedClass.descriptor)
throw AssertionError(
@@ -6,42 +6,42 @@
package org.jetbrains.kotlin.ir.backend.js
import com.intellij.openapi.project.Project
import com.intellij.openapi.util.io.FileUtil
import com.intellij.openapi.vfs.VfsUtilCore
import org.jetbrains.kotlin.backend.common.CompilerPhaseManager
import org.jetbrains.kotlin.backend.common.output.OutputFile
import org.jetbrains.kotlin.backend.common.output.OutputFileCollection
import org.jetbrains.kotlin.backend.common.output.SimpleOutputBinaryFile
import org.jetbrains.kotlin.backend.common.output.SimpleOutputFileCollection
import org.jetbrains.kotlin.backend.common.LoggingContext
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.builtins.functions.functionInterfacePackageFragmentProvider
import org.jetbrains.kotlin.config.CommonConfigurationKeys
import org.jetbrains.kotlin.backend.common.phaser.invokeToplevel
import org.jetbrains.kotlin.config.CommonConfigurationKeys
import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.config.languageVersionSettings
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.descriptors.impl.CompositePackageFragmentProvider
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
import org.jetbrains.kotlin.incremental.components.LookupTracker
import org.jetbrains.kotlin.ir.backend.js.lower.inline.replaceUnboundSymbols
import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.*
import org.jetbrains.kotlin.ir.backend.js.lower.serialization.metadata.*
import org.jetbrains.kotlin.ir.backend.js.lower.coroutines.CoroutineIntrinsicLowering
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.IrModuleToJsTransformer
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
import org.jetbrains.kotlin.ir.util.ConstantValueGenerator
import org.jetbrains.kotlin.ir.util.SymbolTable
import org.jetbrains.kotlin.ir.util.TypeTranslator
import org.jetbrains.kotlin.ir.util.deepCopyWithSymbols
import org.jetbrains.kotlin.js.analyze.TopDownAnalyzerFacadeForJS
import org.jetbrains.kotlin.js.resolve.JsPlatform
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.progress.ProgressIndicatorAndCompilationCanceledStatus
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi2ir.Psi2IrTranslator
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.CompilerDeserializationConfiguration
import org.jetbrains.kotlin.serialization.js.JsSerializerProtocol
import org.jetbrains.kotlin.storage.LockBasedStorageManager
import org.jetbrains.kotlin.utils.JsMetadataVersion
import org.jetbrains.kotlin.utils.KotlinJavascriptMetadataUtils
import java.io.File
import org.jetbrains.kotlin.utils.DFS
data class Result(val moduleDescriptor: ModuleDescriptor, val generatedCode: String, val moduleFragment: IrModuleFragment?)
enum class ModuleType {
TEST_RUNTIME,
SECONDARY,
@@ -59,13 +59,6 @@ class CompiledModule(
get() = moduleFragment!!.descriptor as ModuleDescriptorImpl
}
fun OutputFileCollection.writeAll(outputDir: File) {
for (file in asList()) {
val output = File(outputDir, file.relativePath)
FileUtil.writeToFile(output, file.asByteArray())
}
}
fun compile(
project: Project,
files: List<KtFile>,
@@ -92,7 +85,7 @@ fun compile(
TopDownAnalyzerFacadeForJS.checkForErrors(files, analysisResult.bindingContext)
val symbolTable = SymbolTable()
dependencies.forEach { symbolTable.loadModule(it.moduleFragment!!) }
// irDependencyModules.forEach { symbolTable.loadModule(it) }
val psi2IrTranslator = Psi2IrTranslator(configuration.languageVersionSettings)
val psi2IrContext = psi2IrTranslator.createGeneratorContext(analysisResult.moduleDescriptor, analysisResult.bindingContext, symbolTable)
@@ -111,82 +104,103 @@ fun compile(
if (isKlibCompilation) {
// val declarationTable = DeclarationTable(moduleFragment.irBuiltins, DescriptorTable())
// val serializedIr = IrModuleSerializer(context, declarationTable/*, onlyForInlines = false*/).serializedIrModule(moduleFragment)
// val serializer = KonanSerializationUtil(context, configuration.get(CommonConfigurationKeys.METADATA_VERSION)!!, declarationTable)
// val serializedData = serializer.serializeModule(analysisResult.moduleDescriptor, serializedIr)
// buildLibrary(serializedData)
//
val logggg = object : LoggingContext {
override fun log(message: () -> String) {}
}
// val declarationTable = DeclarationTable(moduleFragment.irBuiltins, DescriptorTable())
// val serializedIr = IrModuleSerializer(context, declarationTable/*, onlyForInlines = false*/).serializedIrModule(moduleFragment)
val declarationTable = DeclarationTable(moduleFragment.irBuiltins, DescriptorTable(), psi2IrContext.symbolTable)
val serializedIr = IrModuleSerializer(logggg, declarationTable/*, onlyForInlines = false*/).serializedIrModule(moduleFragment)
val serializer = JsKlibMetadataSerializationUtil
// val serializedData = serializer.serializeModule(analysisResult.moduleDescriptor, serializedIr)
val moduleName = configuration.get(CommonConfigurationKeys.MODULE_NAME) as String
val metadataVersion = configuration.get(CommonConfigurationKeys.METADATA_VERSION) as? JsKlibMetadataVersion
?: JsKlibMetadataVersion.INSTANCE
val moduleDescription =
JsKlibMetadataModuleDescriptor(moduleName, dependencies.map { it.name.asString() }, moduleFragment.descriptor)
var index = 0L
val serializedData = serializer.serializeMetadata(
psi2IrContext.bindingContext,
moduleDescription,
configuration.get(CommonConfigurationKeys.LANGUAGE_VERSION_SETTINGS)!!,
metadataVersion
) {
// val index = declarationTable.descriptorTable.get(it)
// index?.let { newDescriptorUniqId(it) }
JsKlibMetadataProtoBuf.DescriptorUniqId.newBuilder().setIndex(index++).build()
) { declarationDescriptor ->
val index = declarationTable.descriptorTable.get(declarationDescriptor)
index?.let { newDescriptorUniqId(it) }
}
// buildLibrary(serializedData)
//
val stdKlibDir = File("js/js.translator/testData/out/klibs/runtime/").also {
it.deleteRecursively()
it.mkdirs()
}
//
// val moduleFile = File(stdKlibDir, "module.kji")
// moduleFile.writeBytes(serializedIr.module)
//
// for ((id, data) in serializedIr.declarations) {
// val file = File(stdKlibDir, "${id.index}${if (id.isLocal) "L" else "G"}.kjd")
// file.writeBytes(data)
// }
//
//
// val debugFile = File(stdKlibDir, "debug.txt")
//
// for ((id, data) in serializedIr.debugIndex) {
// debugFile.appendText(id.toString())
// debugFile.appendText(" --- ")
// debugFile.appendText(data)
// debugFile.appendText("\n")
// }
val metadata = File(stdKlibDir, "${moduleDescription.name}${JsKlibMetadataSerializationUtil.CLASS_METADATA_FILE_EXTENSION}").also {
val moduleFile = File(stdKlibDir, "module.kji")
moduleFile.writeBytes(serializedIr.module)
val irDeclarationDir = File(stdKlibDir, "ir/").also { it.mkdir() }
for ((id, data) in serializedIr.declarations) {
val file = File(irDeclarationDir, id.declarationFileName)
file.writeBytes(data)
}
val debugFile = File(stdKlibDir, "debug.txt")
for ((id, data) in serializedIr.debugIndex) {
debugFile.appendText(id.toString())
debugFile.appendText(" --- ")
debugFile.appendText(data)
debugFile.appendText("\n")
}
val metadata = File(stdKlibDir, "${moduleDescription.name}.${JsKlibMetadataSerializationUtil.CLASS_METADATA_FILE_EXTENSION}").also {
it.writeBytes(serializedData.asByteArray())
}
val storageManager = LockBasedStorageManager("JsConfig")
// // CREATE NEW MODULE DESCRIPTOR HERE AND DESERIALIZE IT
val lookupTracker = configuration.get(CommonConfigurationKeys.LOOKUP_TRACKER, LookupTracker.DO_NOTHING)
val parts = serializer.readModuleAsProto(metadata.readBytes())
val md = ModuleDescriptorImpl(
Name.special("<$moduleName>"), storageManager, JsPlatform.builtIns
)
val provider = createJsKlibMetadataPackageFragmentProvider(
storageManager, md, parts.header, parts.body, metadataVersion,
CompilerDeserializationConfiguration(configuration.languageVersionSettings),
lookupTracker
val builtIns = object : KotlinBuiltIns(storageManager) {}//analysisResult.moduleDescriptor.builtIns
val md = ModuleDescriptorImpl(Name.special("<$moduleName>"), storageManager, builtIns)
builtIns.builtInsModule = md
val packageProviders = listOf(
functionInterfacePackageFragmentProvider(storageManager, md),
createJsKlibMetadataPackageFragmentProvider(
storageManager, md, parts.header, parts.body, metadataVersion,
CompilerDeserializationConfiguration(configuration.languageVersionSettings),
lookupTracker
)
)
md.initialize(provider)
md.setDependencies(listOf(md, md.builtIns.builtInsModule))
md.initialize(CompositePackageFragmentProvider(packageProviders))
md.setDependencies(listOf(md/*, builtIns.builtInsModule*/))
TODO("Implemenet IrSerialization")
val st = SymbolTable()
val typeTranslator = TypeTranslator(st, configuration.languageVersionSettings).also {
it.constantValueGenerator = ConstantValueGenerator(md, st)
}
val irBuiltIns = IrBuiltIns(md.builtIns, typeTranslator, st)
val deserializer = IrKlibProtoBufModuleDeserializer(
md,
logggg,
irBuiltIns,
stdKlibDir,
st,
null
)
val deserializedModuleFragment = deserializer.deserializeIrModule(md, moduleFile.readBytes(), true)
val context = JsIrBackendContext(md, irBuiltIns, st, deserializedModuleFragment, configuration, irDependencyModules)
deserializedModuleFragment.replaceUnboundSymbols(context)
jsPhases.invokeToplevel(context.phaseConfig, context, moduleFragment)
return Result(md, context.jsProgram.toString(), null)
} else {
// TODO: Split compilation into two steps: kt -> ir, ir -> js
@@ -211,9 +225,17 @@ fun compile(
}
}
jsPhases.invokeToplevel(context.phaseConfig, context, moduleFragment)
val context = JsIrBackendContext(
analysisResult.moduleDescriptor,
psi2IrContext.irBuiltIns,
psi2IrContext.symbolTable,
moduleFragment,
configuration,
irDependencyModules
)
val jsProgram = moduleFragment.accept(IrModuleToJsTransformer(context), null)
val jsProgram = moduleFragment.accept(IrModuleToJsTransformer(context), null)
return CompiledModule(moduleName, jsProgram.toString(), context.moduleFragmentCopy, moduleType, dependencies)
return CompiledModule(moduleName, jsProgram.toString(), context.moduleFragmentCopy, moduleType, dependencies)
}
}
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.ir.backend.js.lower
import org.jetbrains.kotlin.backend.common.DeclarationContainerLoweringPass
import org.jetbrains.kotlin.backend.common.ir.isElseBranch
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
@@ -366,8 +367,8 @@ class BlockDecomposerTransformer(private val context: JsIrBackendContext) : IrEl
if (compositeCount == 0) {
val branches = results.map { (cond, res, orig) ->
when (orig) {
is IrElseBranch -> IrElseBranchImpl(orig.startOffset, orig.endOffset, cond, res)
when {
isElseBranch(orig) -> IrElseBranchImpl(orig.startOffset, orig.endOffset, cond, res)
else /* IrBranch */ -> IrBranchImpl(orig.startOffset, orig.endOffset, cond, res)
}
}
@@ -384,7 +385,7 @@ class BlockDecomposerTransformer(private val context: JsIrBackendContext) : IrEl
appendBlock.statements += condStatements.run { subList(0, lastIndex) }
JsIrBuilder.buildBlock(unitType).also {
val elseBlock = if (orig is IrElseBranch) null else it
val elseBlock = if (isElseBranch(orig)) null else it
val ifElseNode =
JsIrBuilder.buildIfElse(orig.startOffset, orig.endOffset, unitType, condValue, res, elseBlock, expression.origin)
appendBlock.statements += ifElseNode
@@ -666,9 +667,9 @@ class BlockDecomposerTransformer(private val context: JsIrBackendContext) : IrEl
val newBranches = decomposedResults.map { (branch, condition, result) ->
val newResult = wrap(result, irVar)
when (branch) {
is IrElseBranch -> IrElseBranchImpl(branch.startOffset, branch.endOffset, condition, newResult)
else /* IrBranch */ -> IrBranchImpl(branch.startOffset, branch.endOffset, condition, newResult)
when {
isElseBranch(branch) -> IrElseBranchImpl(branch.startOffset, branch.endOffset, condition, newResult)
else /* IrBranch */ -> IrBranchImpl(branch.startOffset, branch.endOffset, condition, newResult)
}
}
@@ -679,9 +680,9 @@ class BlockDecomposerTransformer(private val context: JsIrBackendContext) : IrEl
return JsIrBuilder.buildComposite(expression.type, listOf(irVar, newWhen, JsIrBuilder.buildGetValue(irVar.symbol)))
} else {
val newBranches = decomposedResults.map { (branch, condition, result) ->
when (branch) {
is IrElseBranch -> IrElseBranchImpl(branch.startOffset, branch.endOffset, condition, result)
else /* IrBranch */ -> IrBranchImpl(branch.startOffset, branch.endOffset, condition, result)
when {
isElseBranch(branch) -> IrElseBranchImpl(branch.startOffset, branch.endOffset, condition, result)
else /* IrBranch */ -> IrBranchImpl(branch.startOffset, branch.endOffset, condition, result)
}
}
@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.ir.backend.js.lower.coroutines
import org.jetbrains.kotlin.backend.common.ir.isElseBranch
import org.jetbrains.kotlin.backend.common.ir.isSuspend
import org.jetbrains.kotlin.backend.common.peek
import org.jetbrains.kotlin.backend.common.pop
@@ -351,8 +352,8 @@ class StateMachineBuilder(
if (it.result in suspendableNodes) {
suspendableNodes += wrapped
}
when (it) {
is IrElseBranch -> IrElseBranchImpl(it.startOffset, it.endOffset, it.condition, wrapped)
when {
isElseBranch(it) -> IrElseBranchImpl(it.startOffset, it.endOffset, it.condition, wrapped)
else /* IrBranch */ -> IrBranchImpl(it.startOffset, it.endOffset, it.condition, wrapped)
}
}
@@ -365,7 +366,7 @@ class StateMachineBuilder(
val rootBlock = currentBlock
for (branch in branches) {
if (branch !is IrElseBranch) {
if (!isElseBranch(branch)) {
branch.condition.acceptVoid(this)
val branchBlock = JsIrBuilder.buildComposite(branch.result.type)
val elseBlock = JsIrBuilder.buildComposite(expression.type)
@@ -22,6 +22,7 @@ import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrReturnableBlockImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrVarargImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrReturnableBlockSymbolImpl
import org.jetbrains.kotlin.ir.types.irTypeKotlinBuiltIns
import org.jetbrains.kotlin.ir.types.toKotlinType
import org.jetbrains.kotlin.ir.util.file
import org.jetbrains.kotlin.ir.util.getArguments
@@ -124,6 +125,7 @@ internal class FunctionInlining(val context: Context): IrElementTransformerWithC
//-------------------------------------------------------------------------//
fun inline(irModule: IrModuleFragment): IrElement {
irTypeKotlinBuiltIns = irModule.irBuiltins.builtIns
val transformedModule = irModule.accept(this, Ref(false))
DescriptorSubstitutorForExternalScope(globalSubstituteMap, context).run(transformedModule) // Transform calls to object that might be returned from inline function call.
return transformedModule
@@ -371,7 +373,7 @@ private class Inliner(val globalSubstituteMap: MutableMap<DeclarationDescriptor,
override fun visitElement(element: IrElement) = element.accept(this, null)
}
private fun isLambdaCall(irCall: IrCall) = irCall.descriptor.isFunctionInvoke && irCall.dispatchReceiver is IrGetValue
private fun isLambdaCall(irCall: IrCall) = irCall.symbol.owner.isFunctionInvoke && irCall.dispatchReceiver is IrGetValue
private fun createTypeSubstitutor(irCall: IrCall): TypeSubstitutor? {
if (irCall.typeArgumentsCount == 0) return null
@@ -9,6 +9,10 @@ import org.jetbrains.kotlin.builtins.functions.FunctionClassDescriptor
import org.jetbrains.kotlin.builtins.getFunctionalClassKind
import org.jetbrains.kotlin.builtins.isFunctionType
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
import org.jetbrains.kotlin.ir.util.isFunctionOrKFunction
import org.jetbrains.kotlin.ir.util.isFunctionTypeOrSubtype
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.resolve.OverridingUtil
import org.jetbrains.kotlin.types.KotlinType
@@ -47,6 +51,15 @@ internal val FunctionDescriptor.isFunctionInvoke: Boolean
this.isOperator && this.name == OperatorNameConventions.INVOKE
}
internal val IrFunction.isFunctionInvoke: Boolean
get() {
val dispatchReceiver = dispatchReceiverParameter ?: return false
assert(!dispatchReceiver.type.isFunctionTypeOrSubtype())
return dispatchReceiver.type.isFunctionTypeOrSubtype() &&
/*this.isOperator &&*/ this.name == OperatorNameConventions.INVOKE
}
// It is possible to declare "external inline fun",
// but it doesn't have much sense for native,
// since externals don't have IR bodies.
@@ -0,0 +1,202 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. 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.lower.serialization.ir
import org.jetbrains.kotlin.backend.common.atMostOne
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrFieldImpl
import org.jetbrains.kotlin.ir.expressions.IrCall
import org.jetbrains.kotlin.ir.expressions.IrConst
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.classifierOrFail
import org.jetbrains.kotlin.ir.types.isMarkedNullable
import org.jetbrains.kotlin.ir.util.explicitParameters
import org.jetbrains.kotlin.ir.util.isFunction
import org.jetbrains.kotlin.ir.util.isInterface
import org.jetbrains.kotlin.ir.util.isSuspendFunction
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedPropertyDescriptor
val IrConstructor.constructedClass get() = this.parent as IrClass
val <T : IrDeclaration> T.original get() = this
val IrDeclaration.containingDeclaration get() = this.parent
val IrDeclarationParent.fqNameSafe: FqName
get() = when (this) {
is IrPackageFragment -> this.fqName
is IrDeclaration -> this.parent.fqNameSafe.child(this.name)
else -> error(this)
}
val IrClass.classId: ClassId?
get() {
val parent = this.parent
return when (parent) {
is IrClass -> parent.classId?.createNestedClassId(this.name)
is IrPackageFragment -> ClassId.topLevel(parent.fqName.child(this.name))
else -> null
}
}
val IrDeclaration.name: Name
get() = when (this) {
is IrSimpleFunction -> this.name
is IrClass -> this.name
is IrEnumEntry -> this.name
is IrProperty -> this.name
is IrLocalDelegatedProperty -> this.name
is IrField -> this.name
is IrVariable -> this.name
is IrConstructor -> SPECIAL_INIT_NAME
is IrValueParameter -> this.name
else -> error(this)
}
private val SPECIAL_INIT_NAME = Name.special("<init>")
val IrField.fqNameSafe: FqName get() = this.parent.fqNameSafe.child(this.name)
/**
* @return naturally-ordered list of all parameters available inside the function body.
*/
val IrFunction.allParameters: List<IrValueParameter>
get() = if (this is IrConstructor) {
listOf(this.constructedClass.thisReceiver
?: error(this.descriptor)
) + explicitParameters
} else {
explicitParameters
}
val IrValueParameter.isVararg get() = this.varargElementType != null
val IrFunction.isSuspend get() = this is IrSimpleFunction && this.isSuspend
fun IrClass.isUnit() = this.fqNameSafe == KotlinBuiltIns.FQ_NAMES.unit.toSafe()
fun IrClass.isKotlinArray() = this.fqNameSafe == KotlinBuiltIns.FQ_NAMES.array.toSafe()
val IrClass.superClasses get() = this.superTypes.map { it.classifierOrFail as IrClassSymbol }
fun IrClass.getSuperClassNotAny() = this.superClasses.map { it.owner }.atMostOne { !it.isInterface && !it.isAny() }
fun IrClass.isAny() = this.fqNameSafe == KotlinBuiltIns.FQ_NAMES.any.toSafe()
fun IrClass.isNothing() = this.fqNameSafe == KotlinBuiltIns.FQ_NAMES.nothing.toSafe()
fun IrClass.getSuperInterfaces() = this.superClasses.map { it.owner }.filter { it.isInterface }
val IrProperty.konanBackingField: IrField?
get() {
assert(this.isReal)
this.backingField?.let { return it }
// (this.descriptor as? DeserializedPropertyDescriptor)?.konanBackingField?.let { backingFieldDescriptor ->
// val result = IrFieldImpl(
// this.startOffset,
// this.endOffset,
// IrDeclarationOrigin.PROPERTY_BACKING_FIELD,
// backingFieldDescriptor,
// this.getter!!.returnType
// ).also {
// it.parent = this.parent
// }
// this.backingField = result
// return result
// }
return null
}
val IrField.containingClass get() = this.parent as? IrClass
val IrFunction.isReal get() = this.origin != IrDeclarationOrigin.FAKE_OVERRIDE
// Note: psi2ir doesn't set `origin = FAKE_OVERRIDE` for fields and properties yet.
val IrProperty.isReal: Boolean get() = this.descriptor.kind.isReal
val IrField.isReal: Boolean get() = this.descriptor.kind.isReal
val IrSimpleFunction.isOverridable: Boolean
get() = visibility != Visibilities.PRIVATE
&& modality != Modality.FINAL
&& (parent as? IrClass)?.isFinalClass != true
val IrFunction.isOverridable get() = this is IrSimpleFunction && this.isOverridable
val IrFunction.isOverridableOrOverrides
get() = this is IrSimpleFunction && (this.isOverridable || this.overriddenSymbols.isNotEmpty())
val IrClass.isFinalClass: Boolean
get() = modality == Modality.FINAL && kind != ClassKind.ENUM_CLASS
fun IrSimpleFunction.overrides(other: IrSimpleFunction): Boolean {
if (this == other) return true
this.overriddenSymbols.forEach {
if (it.owner.overrides(other)) {
return true
}
}
return false
}
fun IrClass.isSpecialClassWithNoSupertypes() = this.isAny() || this.isNothing()
internal val IrValueParameter.isValueParameter get() = this.index >= 0
private val IrCall.annotationClass
get() = (this.symbol.owner as IrConstructor).constructedClass
fun List<IrCall>.hasAnnotation(fqName: FqName): Boolean =
this.any { it.annotationClass.fqNameSafe == fqName }
fun IrAnnotationContainer.hasAnnotation(fqName: FqName) =
this.annotations.hasAnnotation(fqName)
fun List<IrCall>.findAnnotation(fqName: FqName): IrCall? = this.firstOrNull {
it.annotationClass.fqNameSafe == fqName
}
fun <T> IrDeclaration.getAnnotationArgumentValue(fqName: FqName, argumentName: String): T? {
val annotation = this.annotations.findAnnotation(fqName)
if (annotation == null) {
// As a last resort try searching the descriptor.
// This is needed for a period while we don't have IR for platform libraries.
return this.descriptor.annotations
.findAnnotation(fqName)
?.getArgumentValueOrNull<T>(argumentName)
}
for (index in 0 until annotation.valueArgumentsCount) {
val parameter = annotation.symbol.owner.valueParameters[index]
if (parameter.name == Name.identifier(argumentName)) {
val actual = annotation.getValueArgument(index) as? IrConst<T>
return actual?.value
}
}
return null
}
fun IrValueParameter.isInlineParameter(): Boolean =
!this.isNoinline && (this.type.isFunction() || this.type.isSuspendFunction()) && !this.type.isMarkedNullable()
val IrDeclaration.parentDeclarationsWithSelf: Sequence<IrDeclaration>
get() = generateSequence(this, { it.parent as? IrDeclaration })
fun IrClass.companionObject() = this.declarations.singleOrNull {it is IrClass && it.isCompanion }
val IrDeclaration.isGetter get() = this is IrSimpleFunction && this == this.correspondingProperty?.getter
val IrDeclaration.isSetter get() = this is IrSimpleFunction && this == this.correspondingProperty?.setter
val IrDeclaration.isAccessor get() = this.isGetter || this.isSetter
@@ -0,0 +1,169 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. 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.lower.serialization.ir
import org.jetbrains.kotlin.builtins.functions.FunctionInvokeDescriptor
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor
import org.jetbrains.kotlin.ir.SourceManager
import org.jetbrains.kotlin.ir.SourceRangeInfo
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
import org.jetbrains.kotlin.ir.declarations.IrField
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
import org.jetbrains.kotlin.ir.util.parentAsClass
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi2ir.findFirstFunction
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.descriptorUtil.module
import java.io.File
import java.util.regex.Pattern
internal val IrDeclaration.isAnonymousObject get() = DescriptorUtils.isAnonymousObject(this.descriptor)
internal val IrDeclaration.isLocal get() = DescriptorUtils.isLocal(this.descriptor)
internal val IrDeclaration.module get() = this.descriptor.module
@Deprecated("Do not call this method in the compiler front-end.")
internal val IrField.isDelegate
get() = @Suppress("DEPRECATION") this.descriptor.isDelegated
internal const val SYNTHETIC_OFFSET = -2
class NaiveSourceBasedFileEntryImpl(override val name: String) : SourceManager.FileEntry {
private val lineStartOffsets: IntArray
//-------------------------------------------------------------------------//
init {
val file = File(name)
if (file.isFile) {
// TODO: could be incorrect, if file is not in system's line terminator format.
// Maybe use (0..document.lineCount - 1)
// .map { document.getLineStartOffset(it) }
// .toIntArray()
// as in PSI.
val separatorLength = System.lineSeparator().length
val buffer = mutableListOf<Int>()
var currentOffset = 0
file.forEachLine { line ->
buffer.add(currentOffset)
currentOffset += line.length + separatorLength
}
buffer.add(currentOffset)
lineStartOffsets = buffer.toIntArray()
} else {
lineStartOffsets = IntArray(0)
}
}
//-------------------------------------------------------------------------//
override fun getLineNumber(offset: Int): Int {
assert(offset != UNDEFINED_OFFSET)
if (offset == SYNTHETIC_OFFSET) return 0
val index = lineStartOffsets.binarySearch(offset)
return if (index >= 0) index else -index - 2
}
//-------------------------------------------------------------------------//
override fun getColumnNumber(offset: Int): Int {
assert(offset != UNDEFINED_OFFSET)
if (offset == SYNTHETIC_OFFSET) return 0
var lineNumber = getLineNumber(offset)
return offset - lineStartOffsets[lineNumber]
}
//-------------------------------------------------------------------------//
override val maxOffset: Int
//get() = TODO("not implemented")
get() = UNDEFINED_OFFSET
override fun getSourceRangeInfo(beginOffset: Int, endOffset: Int): SourceRangeInfo {
//TODO("not implemented")
return SourceRangeInfo(name, beginOffset, -1, -1, endOffset, -1, -1)
}
}
private val functionPattern = Pattern.compile("^K?(Suspend)?Function\\d+$")
private val kotlinFqn = FqName("kotlin")
private val functionalPackages =
listOf(kotlinFqn, kotlinFqn.child(Name.identifier("coroutines")), kotlinFqn.child(Name.identifier("reflect")))
internal val BUILT_IN_FUNCTION_CLASS_COUNT = 4
internal val BUILT_IN_FUNCTION_ARITY_COUNT = 256
internal val BUILT_IN_UNIQ_ID_GAP = 2 * BUILT_IN_FUNCTION_ARITY_COUNT * BUILT_IN_FUNCTION_CLASS_COUNT
internal val BUILT_IN_UNIQ_ID_CLASS_OFFSET = BUILT_IN_FUNCTION_CLASS_COUNT * BUILT_IN_FUNCTION_ARITY_COUNT
internal fun isBuiltInFunction(value: IrDeclaration): Boolean = when (value) {
is IrSimpleFunction -> value.name.asString() == "invoke" && (value.parent as? IrClass)?.let { isBuiltInFunction(it) } == true
is IrClass -> {
val fqn = value.parent.fqNameSafe
functionalPackages.any { it == fqn } && value.name.asString().let { functionPattern.matcher(it).find() }
}
else -> false
}
private fun builtInOffset(function: IrSimpleFunction): Long {
val isK = function.parentAsClass.name.asString().startsWith("K")
return when {
isK && function.isSuspend -> 3
isK -> 2
function.isSuspend -> 1
else -> 0
}
}
internal fun builtInFunctionId(value: IrDeclaration): Long = when (value) {
is IrSimpleFunction -> {
value.run { valueParameters.size + builtInOffset(value) * BUILT_IN_FUNCTION_ARITY_COUNT }.toLong()
}
is IrClass -> {
BUILT_IN_UNIQ_ID_CLASS_OFFSET + builtInFunctionId(value.declarations.first { it.name.asString() == "invoke" })
}
else -> error("Only class or function is expected")
}
internal fun isBuiltInFunction(value: DeclarationDescriptor): Boolean = when (value) {
is FunctionInvokeDescriptor -> isBuiltInFunction(value.containingDeclaration)
is ClassDescriptor -> {
val fqn = (value.containingDeclaration as? PackageFragmentDescriptor)?.fqName
functionalPackages.any { it == fqn } && value.name.asString().let { functionPattern.matcher(it).find() }
}
else -> false
}
private fun builtInOffset(function: FunctionInvokeDescriptor): Long {
val isK = function.containingDeclaration.name.asString().startsWith("K")
return when {
isK && function.isSuspend -> 3
isK -> 2
function.isSuspend -> 1
else -> 0
}
}
internal fun builtInFunctionId(value: DeclarationDescriptor): Long = when (value) {
is FunctionInvokeDescriptor -> {
value.run { valueParameters.size + builtInOffset(value) * BUILT_IN_FUNCTION_ARITY_COUNT }.toLong()
}
is ClassDescriptor -> {
BUILT_IN_UNIQ_ID_CLASS_OFFSET + builtInFunctionId(value.findFirstFunction("invoke") { true })
}
else -> error("Only class or function is expected")
}
@@ -0,0 +1,252 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. 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.lower.serialization.ir
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.descriptors.PropertyAccessorDescriptor
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.descriptors.Visibility
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.util.isInlined
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
// This file describes the ABI for Kotlin descriptors of exported declarations.
// TODO: revise the naming scheme to ensure it produces unique names.
// TODO: do not serialize descriptors of non-exported declarations.
/**
* Defines whether the declaration is exported, i.e. visible from other modules.
*
* Exported declarations must have predictable and stable ABI
* that doesn't depend on any internal transformations (e.g. IR lowering),
* and so should be computable from the descriptor itself without checking a backend state.
*/
internal tailrec fun IrDeclaration.isExported(): Boolean {
// TODO: revise
val descriptorAnnotations = this.descriptor.annotations
// if (descriptorAnnotations.hasAnnotation(symbolNameAnnotation)) {
// // Treat any `@SymbolName` declaration as exported.
// return true
// }
// if (descriptorAnnotations.hasAnnotation(exportForCppRuntimeAnnotation)) {
// // Treat any `@ExportForCppRuntime` declaration as exported.
// return true
// }
// if (descriptorAnnotations.hasAnnotation(cnameAnnotation)) {
// // Treat `@CName` declaration as exported.
// return true
// }
// if (descriptorAnnotations.hasAnnotation(exportForCompilerAnnotation)) {
// return true
// }
if (descriptorAnnotations.hasAnnotation(publishedApiAnnotation)){
return true
}
if (this.isAnonymousObject)
return false
if (this is IrConstructor && constructedClass.kind.isSingleton) {
// Currently code generator can access the constructor of the singleton,
// so ignore visibility of the constructor itself.
return constructedClass.isExported()
}
if (this is IrFunction) {
val descriptor = this.descriptor
// TODO: this code is required because accessor doesn't have a reference to property.
if (descriptor is PropertyAccessorDescriptor) {
val property = descriptor.correspondingProperty
if (property.annotations.hasAnnotation(publishedApiAnnotation)) return true
}
}
val visibility = when (this) {
is IrClass -> this.visibility
is IrFunction -> this.visibility
is IrProperty -> this.visibility
is IrField -> this.visibility
else -> null
}
/**
* note: about INTERNAL - with support of friend modules we let frontend to deal with internal declarations.
*/
if (visibility != null && !visibility.isPublicAPI && visibility != Visibilities.INTERNAL) {
// If the declaration is explicitly marked as non-public,
// then it must not be accessible from other modules.
return false
}
val parent = this.parent
if (parent is IrDeclaration) {
return parent.isExported()
}
return true
}
private val publishedApiAnnotation = FqName("kotlin.PublishedApi")
private fun acyclicTypeMangler(visited: MutableSet<IrTypeParameter>, type: IrType): String {
val descriptor = (type.classifierOrNull as? IrTypeParameterSymbol)?.owner
if (descriptor != null) {
val upperBounds = if (visited.contains(descriptor)) "" else {
visited.add(descriptor)
descriptor.superTypes.map {
val bound = acyclicTypeMangler(visited, it)
if (bound == "kotlin.Any?") "" else "_$bound"
}.joinToString("")
}
return "#GENERIC${if (type.isMarkedNullable()) "?" else ""}$upperBounds"
}
var hashString = type.getClass()?.run { fqNameSafe.asString() } ?: "<dynamic>"
// if (type !is IrSimpleType) error(type)
when (type) {
is IrSimpleType -> {
if (!type.arguments.isEmpty()) {
hashString += "<${type.arguments.map {
when (it) {
is IrStarProjection -> "#STAR"
is IrTypeProjection -> {
val variance = it.variance.label
val projection = if (variance == "") "" else "${variance}_"
projection + acyclicTypeMangler(visited, it.type)
}
else -> error(it)
}
}.joinToString(",")}>"
}
if (type.hasQuestionMark) hashString += "?"
}
!is IrDynamicType -> { error(type) }
}
return hashString
}
private fun typeToHashString(type: IrType) = acyclicTypeMangler(mutableSetOf(), type)
internal val IrValueParameter.extensionReceiverNamePart: String
get() = "@${typeToHashString(this.type)}."
private val IrFunction.signature: String
get() {
val extensionReceiverPart = this.extensionReceiverParameter?.extensionReceiverNamePart ?: ""
val argsPart = this.valueParameters.map {
// TODO: there are clashes originating from ObjectiveC interop.
// kotlinx.cinterop.ObjCClassOf<T>.create(format: kotlin.String): T defined in platform.Foundation in file Foundation.kt
// and
// kotlinx.cinterop.ObjCClassOf<T>.create(string: kotlin.String): T defined in platform.Foundation in file Foundation.kt
val argName = /*if (this.hasObjCMethodAnnotation || this.hasObjCFactoryAnnotation || this.isObjCClassMethod()) "${it.name}:" else */""
"$argName${typeToHashString(it.type)}${if (it.isVararg) "_VarArg" else ""}"
}.joinToString(";")
// Distinguish value types and references - it's needed for calling virtual methods through bridges.
// Also is function has type arguments - frontend allows exactly matching overrides.
val signatureSuffix =
when {
this.typeParameters.isNotEmpty() -> "Generic"
returnType.isInlined() -> "ValueType"
!returnType.isUnitOrNullableUnit() -> typeToHashString(returnType)
else -> ""
}
return "$extensionReceiverPart($argsPart)$signatureSuffix"
}
// TODO: rename to indicate that it has signature included
internal val IrFunction.functionName: String
get() {
with(this.original) { // basic support for generics
// (if (this is IrConstructor && this.isObjCConstructor) this.getObjCInitMethod() else this)?.getObjCMethodInfo()?.let {
// return buildString {
// if (extensionReceiverParameter != null) {
// append(extensionReceiverParameter!!.type.getClass()!!.name)
// append(".")
// }
//
// append("objc:")
// append(it.selector)
// if (this@with is IrConstructor && this@with.isObjCConstructor) append("#Constructor")
//
// // We happen to have the clashing combinations such as
// //@ObjCMethod("issueChallengeToPlayers:message:", "objcKniBridge1165")
// //external fun GKScore.issueChallengeToPlayers(playerIDs: List<*>?, message: String?): Unit
// //@ObjCMethod("issueChallengeToPlayers:message:", "objcKniBridge1172")
// //external fun GKScore.issueChallengeToPlayers(playerIDs: List<*>?, message: String?): Unit
// // So disambiguate by the name of the bridge for now.
// // TODO: idealy we'd never generate such identical declarations.
//
// if (this@with is IrSimpleFunction && this@with.hasObjCMethodAnnotation()) {
// this@with.objCMethodArgValue("selector") ?.let { append("#$it") }
// this@with.objCMethodArgValue("bridge") ?.let { append("#$it") }
// }
// }
// }
val name = this.name.mangleIfInternal(this.module, this.visibility)
return "$name$signature"
}
}
private fun Name.mangleIfInternal(moduleDescriptor: ModuleDescriptor, visibility: Visibility): String =
if (visibility != Visibilities.INTERNAL) {
this.asString()
} else {
val moduleName = moduleDescriptor.name.asString()
.let { it.substring(1, it.lastIndex) } // Remove < and >.
"$this\$$moduleName"
}
internal val IrFunction.symbolName: String
get() {
if (!this.isExported()) {
throw AssertionError(this.descriptor.toString())
}
if (isExternal) {
this.descriptor.externalSymbolOrThrow()?.let {
return it
}
}
// this.descriptor.annotations.findAnnotation(exportForCppRuntimeAnnotation)?.let {
// val name = getAnnotationValue(it) ?: this.name.asString()
// return name // no wrapping currently required
// }
val parent = this.parent
val containingDeclarationPart = parent.fqNameSafe.let {
if (it.isRoot) "" else "$it."
}
return "kfun:$containingDeclarationPart$functionName"
}
internal val IrField.symbolName: String
get() {
val containingDeclarationPart = parent.fqNameSafe.let {
if (it.isRoot) "" else "$it."
}
return "kfield:$containingDeclarationPart$name"
}
internal val IrClass.typeInfoSymbolName: String
get() {
assert (this.isExported())
return "ktype:" + this.fqNameSafe.toString()
}
@@ -0,0 +1,91 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. 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.lower.serialization.ir
import org.jetbrains.kotlin.backend.common.descriptors.getFunction
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrAnonymousInitializerImpl
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
import org.jetbrains.kotlin.ir.util.SymbolTable
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.jvm.modules.KOTLIN_STDLIB_MODULE_NAME
import java.util.regex.Pattern
fun <K, V> MutableMap<K, V>.putOnce(k:K, v: V): Unit {
assert(!this.containsKey(k) || this[k] == v) {
"adding $v for $k, but it is already ${this[k]} for $k"
}
this.put(k, v)
}
class DescriptorTable {
private val descriptors = mutableMapOf<DeclarationDescriptor, Long>()
fun put(descriptor: DeclarationDescriptor, uniqId: UniqId) {
descriptors.putOnce(descriptor, uniqId.index)
}
fun get(descriptor: DeclarationDescriptor) = descriptors[descriptor]
}
// TODO: We don't manage id clashes anyhow now.
class DeclarationTable(val builtIns: IrBuiltIns, val descriptorTable: DescriptorTable, val symbolTable: SymbolTable) {
private val table = mutableMapOf<IrDeclaration, UniqId>()
val debugIndex = mutableMapOf<UniqId, String>()
val descriptors = descriptorTable
private var currentIndex = 0x1_0000_0000L
private val FUNCTION_INDEX_START: Long
init {
val known = builtIns.knownBuiltins
known.forEach {
table.put(it, UniqId(currentIndex++, false))
}
FUNCTION_INDEX_START = currentIndex
currentIndex += BUILT_IN_UNIQ_ID_GAP
}
fun uniqIdByDeclaration(value: IrDeclaration): UniqId {
val index = table.getOrPut(value) {
if (isBuiltInFunction(value)) {
UniqId(FUNCTION_INDEX_START + builtInFunctionId(value), false)
} else if (value.origin == IrDeclarationOrigin.FAKE_OVERRIDE ||
!value.isExported()
|| value is IrVariable
|| value is IrTypeParameter
|| value is IrValueParameter
|| value is IrAnonymousInitializerImpl
) {
val desc = value.descriptor
if (desc is CallableDescriptor) {
if (desc.visibility == Visibilities.PUBLIC || value.origin != IrDeclarationOrigin.FAKE_OVERRIDE) {
fun foo(){}
foo()
}
}
UniqId(currentIndex++, true)
} else {
UniqId(value.uniqIdIndex, false)
}
}
debugIndex.put(index, "${if (index.isLocal) "" else value.uniqSymbolName()} descriptor = ${value.descriptor}")
return index
}
}
// This is what we pre-populate tables with
val IrBuiltIns.knownBuiltins
get() = irBuiltInsExternalPackageFragment.declarations
@@ -0,0 +1,206 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. 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.lower.serialization.ir
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.types.isUnit
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperInterfaces
import org.jetbrains.kotlin.types.SimpleType
import org.jetbrains.kotlin.types.typeUtil.isUnit
/**
* List of all implemented interfaces (including those which implemented by a super class)
*/
internal val IrClass.implementedInterfaces: List<IrClass>
get() {
val superClassImplementedInterfaces = this.getSuperClassNotAny()?.implementedInterfaces ?: emptyList()
val superInterfaces = this.getSuperInterfaces()
val superInterfacesImplementedInterfaces = superInterfaces.flatMap { it.implementedInterfaces }
return (superClassImplementedInterfaces +
superInterfacesImplementedInterfaces +
superInterfaces).distinct()
}
/**
* Implementation of given method.
*
* TODO: this method is actually a part of resolve and probably duplicates another one
*/
internal fun IrSimpleFunction.resolveFakeOverride(allowAbstract: Boolean = false): IrSimpleFunction {
if (this.isReal) {
return this
}
val visited = mutableSetOf<IrSimpleFunction>()
val realSupers = mutableSetOf<IrSimpleFunction>()
fun findRealSupers(function: IrSimpleFunction) {
if (function in visited) return
visited += function
if (function.isReal) {
realSupers += function
} else {
function.overriddenSymbols.forEach { findRealSupers(it.owner) }
}
}
findRealSupers(this)
if (realSupers.size > 1) {
visited.clear()
fun excludeOverridden(function: IrSimpleFunction) {
if (function in visited) return
visited += function
function.overriddenSymbols.forEach {
realSupers.remove(it.owner)
excludeOverridden(it.owner)
}
}
realSupers.toList().forEach { excludeOverridden(it) }
}
return realSupers.first { allowAbstract || it.modality != Modality.ABSTRACT }
}
// TODO: don't forget to remove descriptor access here.
//internal val FunctionDescriptor.isTypedIntrinsic: Boolean
// get() = this.descriptor.isTypedIntrinsic
//
//internal val DeclarationDescriptor.isFrozen: Boolean
// get() = this.descriptor.isFrozen
internal val arrayTypes = setOf(
"kotlin.Array",
"kotlin.ByteArray",
"kotlin.CharArray",
"kotlin.ShortArray",
"kotlin.IntArray",
"kotlin.LongArray",
"kotlin.FloatArray",
"kotlin.DoubleArray",
"kotlin.BooleanArray",
"kotlin.native.ImmutableBlob",
"kotlin.native.internal.NativePtrArray"
)
internal val IrClass.isArray: Boolean
get() = this.fqNameSafe.asString() in arrayTypes
internal val IrClass.isInterface: Boolean
get() = (this.kind == ClassKind.INTERFACE)
fun IrClass.isAbstract() = this.modality == Modality.SEALED || this.modality == Modality.ABSTRACT
|| this.kind == ClassKind.ENUM_CLASS
//internal fun FunctionDescriptor.hasValueTypeAt(index: Int): Boolean {
// when (index) {
// 0 -> return !isSuspend && returnType.let { (it.isInlined() || it.isUnit()) }
// 1 -> return dispatchReceiverParameter.let { it != null && it.type.isInlined() }
// 2 -> return extensionReceiverParameter.let { it != null && it.type.isInlined() }
// else -> return this.valueParameters[index - 3].type.isInlined()
// }
//}
//
//internal fun FunctionDescriptor.hasReferenceAt(index: Int): Boolean {
// when (index) {
// 0 -> return isSuspend || returnType.let { !it.isInlined() && !it.isUnit() }
// 1 -> return dispatchReceiverParameter.let { it != null && !it.type.isInlined() }
// 2 -> return extensionReceiverParameter.let { it != null && !it.type.isInlined() }
// else -> return !this.valueParameters[index - 3].type.isInlined()
// }
//}
//private fun FunctionDescriptor.needBridgeToAt(target: FunctionDescriptor, index: Int)
// = hasValueTypeAt(index) xor target.hasValueTypeAt(index)
//internal fun FunctionDescriptor.needBridgeTo(target: FunctionDescriptor)
// = (0..this.valueParameters.size + 2).any { needBridgeToAt(target, it) }
internal val IrSimpleFunction.target: IrSimpleFunction
get() = (if (modality == Modality.ABSTRACT) this else resolveFakeOverride()).original
internal val IrFunction.target: IrFunction get() = when (this) {
is IrSimpleFunction -> this.target
is IrConstructor -> this
else -> error(this)
}
//private fun FunctionDescriptor.bridgeDirectionToAt(target: FunctionDescriptor, index: Int)
// = when {
// hasValueTypeAt(index) && target.hasReferenceAt(index) -> BridgeDirection.FROM_VALUE_TYPE
// hasReferenceAt(index) && target.hasValueTypeAt(index) -> BridgeDirection.TO_VALUE_TYPE
// else -> BridgeDirection.NOT_NEEDED
//}
val IrSimpleFunction.allOverriddenDescriptors: Set<IrSimpleFunction>
get() {
val result = mutableSetOf<IrSimpleFunction>()
fun traverse(function: IrSimpleFunction) {
if (function in result) return
result += function
function.overriddenSymbols.forEach { traverse(it.owner) }
}
traverse(this)
return result
}
//internal fun IrSimpleFunction.bridgeDirectionsTo(
// overriddenDescriptor: IrSimpleFunction
//): BridgeDirections {
// val ourDirections = BridgeDirections(this.valueParameters.size)
// for (index in ourDirections.array.indices)
// ourDirections.array[index] = this.bridgeDirectionToAt(overriddenDescriptor, index)
//
// val target = this.target
// if (!this.isReal && modality != Modality.ABSTRACT
// && target.overrides(overriddenDescriptor)
// && ourDirections == target.bridgeDirectionsTo(overriddenDescriptor)) {
// // Bridge is inherited from superclass.
// return BridgeDirections(this.valueParameters.size)
// }
//
// return ourDirections
//}
tailrec internal fun IrDeclaration.findPackage(): IrPackageFragment {
val parent = this.parent
return parent as? IrPackageFragment
?: (parent as IrDeclaration).findPackage()
}
fun IrFunction.isComparisonDescriptor(map: Map<SimpleType, IrSimpleFunction>): Boolean =
this in map.values
val IrDeclaration.isPropertyAccessor get() =
this is IrSimpleFunction && this.correspondingProperty != null
val IrDeclaration.isPropertyField get() =
this is IrField && this.correspondingProperty != null
val IrDeclaration.isTopLevelDeclaration get() =
parent !is IrDeclaration && !this.isPropertyAccessor && !this.isPropertyField
fun IrDeclaration.findTopLevelDeclaration(): IrDeclaration = when {
this.isTopLevelDeclaration ->
this
this.isPropertyAccessor ->
(this as IrSimpleFunction).correspondingProperty!!.findTopLevelDeclaration()
this.isPropertyField ->
(this as IrField).correspondingProperty!!.findTopLevelDeclaration()
else ->
(this.parent as IrDeclaration).findTopLevelDeclaration()
}
@@ -0,0 +1,94 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. 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.lower.serialization.ir
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedClassDescriptor
class DescriptorReferenceDeserializer(val currentModule: ModuleDescriptor, val resolvedForwardDeclarations: MutableMap<UniqIdKey, UniqIdKey>) {
fun deserializeDescriptorReference(
proto: IrKlibProtoBuf.DescriptorReference,
checkerDesc: (DeclarationDescriptor) -> Long?,
checkerID: (Long) -> Boolean,
descriptorResolver: (FqName) -> DeclarationDescriptor
): DeclarationDescriptor {
val packageFqName =
if (proto.packageFqName == "<root>") FqName.ROOT else FqName(proto.packageFqName) // TODO: whould we store an empty string in the protobuf?
val classFqName = FqName(proto.classFqName)
val protoIndex = if (proto.hasUniqId()) proto.uniqId.index else null
val (clazz, members) = if (proto.classFqName == "") {
Pair(null, currentModule.getPackage(packageFqName).memberScope.getContributedDescriptors())
} else {
val clazz = currentModule.findClassAcrossModuleDependencies(ClassId(packageFqName, classFqName, false))!!
Pair(clazz, clazz.unsubstitutedMemberScope.getContributedDescriptors() + clazz.getConstructors())
}
if (proto.packageFqName.startsWith("cnames.") || proto.packageFqName.startsWith("objcnames.")) {
val descriptor =
currentModule.findClassAcrossModuleDependencies(ClassId(packageFqName, FqName(proto.name), false))!!
if (!descriptor.fqNameUnsafe.asString().startsWith("cnames") && !descriptor.fqNameUnsafe.asString().startsWith(
"objcnames"
)
) {
if (descriptor is DeserializedClassDescriptor) {
val uniqId = UniqId(descriptor.getUniqId()!!.index, false)
val newKey = UniqIdKey(null, uniqId)
val oldKey = UniqIdKey(null, UniqId(protoIndex!!, false))
resolvedForwardDeclarations.put(oldKey, newKey)
} else {
/* ??? */
}
}
return descriptor
}
if (proto.isEnumEntry) {
val name = proto.name
val memberScope = (clazz as DeserializedClassDescriptor).getUnsubstitutedMemberScope()
return memberScope.getContributedClassifier(Name.identifier(name), NoLookupLocation.FROM_BACKEND)!!
}
if (proto.isEnumSpecial) {
val name = proto.name
return clazz!!.getStaticScope()
.getContributedFunctions(Name.identifier(name), NoLookupLocation.FROM_BACKEND).single()
}
if (protoIndex?.let { checkerID(it) } == true) {
return descriptorResolver(packageFqName.child(Name.identifier(proto.name)))
}
members.forEach { member ->
if (proto.isDefaultConstructor && member is ClassConstructorDescriptor) return member
val realMembers =
if (proto.isFakeOverride && member is CallableMemberDescriptor && member.kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE)
member.resolveFakeOverrideMaybeAbstract().map { it.original }
else
setOf(member)
val memberIndices = realMembers.map { it.getUniqId()?.index ?: checkerDesc(it) }.filterNotNull()
if (memberIndices.contains(protoIndex)) {
return when {
member is PropertyDescriptor && proto.isSetter -> member.setter!!
member is PropertyDescriptor && proto.isGetter -> member.getter!!
else -> member
}
}
}
error("Could not find serialized descriptor for index: ${proto.uniqId.index} ${proto.packageFqName},${proto.classFqName},${proto.name}")
}
}
@@ -0,0 +1,337 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. 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.lower.serialization.ir
import org.jetbrains.kotlin.backend.common.LoggingContext
import org.jetbrains.kotlin.backend.common.descriptors.*
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.impl.EmptyPackageFragmentDescriptor
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.backend.js.lower.serialization.metadata.JsKlibMetadataSerializerProtocol
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.*
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
import org.jetbrains.kotlin.ir.symbols.*
import org.jetbrains.kotlin.ir.symbols.impl.*
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.util.SymbolTable
import org.jetbrains.kotlin.ir.util.patchDeclarationParents
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedCallableMemberDescriptor
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedClassDescriptor
import java.io.File
class IrKlibProtoBufModuleDeserializer(
currentModule: ModuleDescriptor,
logger: LoggingContext,
builtIns: IrBuiltIns,
libraryDir: File,
symbolTable: SymbolTable,
val forwardModuleDescriptor: ModuleDescriptor?)
: IrModuleDeserializer(logger, builtIns, symbolTable) {
val deserializedSymbols = mutableMapOf<UniqIdKey, IrSymbol>()
val knownBuiltInsDescriptors = mutableMapOf<DeclarationDescriptor, UniqId>()
val reachableTopLevels = mutableSetOf<UniqIdKey>()
val deserializedTopLevels = mutableSetOf<UniqIdKey>()
val forwardDeclarations = mutableSetOf<IrSymbol>()
var deserializedModuleDescriptor: ModuleDescriptor? = null
var deserializedModuleProtoSymbolTables = mutableMapOf<ModuleDescriptor, IrKlibProtoBuf.IrSymbolTable>()
var deserializedModuleProtoTypeTables = mutableMapOf<ModuleDescriptor, IrKlibProtoBuf.IrTypeTable>()
val resolvedForwardDeclarations = mutableMapOf<UniqIdKey, UniqIdKey>()
val descriptorReferenceDeserializer = DescriptorReferenceDeserializer(currentModule, resolvedForwardDeclarations)
val moduleRoot = libraryDir
val irDirectory = File(libraryDir, "ir/")
private val FUNCTION_INDEX_START: Long
init {
var currentIndex = 0x1_0000_0000L
builtIns.knownBuiltins.forEach {
require(it is IrFunction)
deserializedSymbols.put(UniqIdKey(null, UniqId(currentIndex, isLocal = false)), it.symbol)
assert(symbolTable.referenceSimpleFunction(it.descriptor) == it.symbol)
currentIndex++
}
FUNCTION_INDEX_START = currentIndex
}
private fun referenceDeserializedSymbol(proto: IrKlibProtoBuf.IrSymbolData, descriptor: DeclarationDescriptor?): IrSymbol = when (proto.kind) {
IrKlibProtoBuf.IrSymbolKind.ANONYMOUS_INIT_SYMBOL ->
IrAnonymousInitializerSymbolImpl(
descriptor as ClassDescriptor?
?: WrappedClassDescriptor()
)
IrKlibProtoBuf.IrSymbolKind.CLASS_SYMBOL ->
symbolTable.referenceClass(
descriptor as ClassDescriptor?
?: WrappedClassDescriptor()
)
IrKlibProtoBuf.IrSymbolKind.CONSTRUCTOR_SYMBOL ->
symbolTable.referenceConstructor(
descriptor as ClassConstructorDescriptor?
?: WrappedClassConstructorDescriptor()
)
IrKlibProtoBuf.IrSymbolKind.TYPE_PARAMETER_SYMBOL ->
symbolTable.referenceTypeParameter(
descriptor as TypeParameterDescriptor?
?: WrappedTypeParameterDescriptor()
)
IrKlibProtoBuf.IrSymbolKind.ENUM_ENTRY_SYMBOL ->
symbolTable.referenceEnumEntry(
descriptor as ClassDescriptor?
?: WrappedEnumEntryDescriptor()
)
IrKlibProtoBuf.IrSymbolKind.STANDALONE_FIELD_SYMBOL ->
IrFieldSymbolImpl(WrappedFieldDescriptor())
IrKlibProtoBuf.IrSymbolKind.FIELD_SYMBOL ->
symbolTable.referenceField(
descriptor as PropertyDescriptor?
?: WrappedPropertyDescriptor()
)
IrKlibProtoBuf.IrSymbolKind.FUNCTION_SYMBOL ->
symbolTable.referenceSimpleFunction(
descriptor as FunctionDescriptor?
?: WrappedSimpleFunctionDescriptor()
)
IrKlibProtoBuf.IrSymbolKind.VARIABLE_SYMBOL ->
IrVariableSymbolImpl(
descriptor as VariableDescriptor?
?: WrappedVariableDescriptor()
)
IrKlibProtoBuf.IrSymbolKind.VALUE_PARAMETER_SYMBOL ->
IrValueParameterSymbolImpl(
descriptor as ParameterDescriptor?
?: WrappedValueParameterDescriptor()
)
IrKlibProtoBuf.IrSymbolKind.RECEIVER_PARAMETER_SYMBOL ->
IrValueParameterSymbolImpl(
descriptor as ParameterDescriptor? ?: WrappedReceiverParameterDescriptor()
)
else -> TODO("Unexpected classifier symbol kind: ${proto.kind}")
}
override fun deserializeIrSymbol(proto: IrKlibProtoBuf.IrSymbol): IrSymbol {
val symbolData =
deserializedModuleProtoSymbolTables[deserializedModuleDescriptor]!!.getSymbols(proto.index)
return deserializeIrSymbolData(symbolData)
}
override fun deserializeIrType(proto: IrKlibProtoBuf.IrTypeIndex): IrType {
val typeData =
deserializedModuleProtoTypeTables[deserializedModuleDescriptor]!!.getTypes(proto.index)
return deserializeIrTypeData(typeData)
}
fun deserializeIrSymbolData(proto: IrKlibProtoBuf.IrSymbolData): IrSymbol {
val key = proto.uniqId.uniqIdKey(deserializedModuleDescriptor!!)
val topLevelKey = proto.topLevelUniqId.uniqIdKey(deserializedModuleDescriptor!!)
if (!deserializedTopLevels.contains(topLevelKey)) reachableTopLevels.add(topLevelKey)
val symbol = deserializedSymbols.getOrPut(key) {
val descriptor = if (proto.hasDescriptorReference()) {
deserializeDescriptorReference(proto.descriptorReference)
} else {
null
}
resolvedForwardDeclarations[key]?.let {
if (!deserializedTopLevels.contains(it)) reachableTopLevels.add(it) // Assuming forward declarations are always top levels.
}
referenceDeserializedSymbol(proto, descriptor)
}
if (symbol.descriptor is ClassDescriptor &&
symbol.descriptor !is WrappedDeclarationDescriptor<*>/* &&
symbol.descriptor.module.isForwardDeclarationModule*/
) {
forwardDeclarations.add(symbol)
}
return symbol
}
override fun deserializeDescriptorReference(proto: IrKlibProtoBuf.DescriptorReference) =
descriptorReferenceDeserializer.deserializeDescriptorReference(proto, {
knownBuiltInsDescriptors[it]?.index ?: if (isBuiltInFunction(it)) FUNCTION_INDEX_START + builtInFunctionId(it) else null
}, { (FUNCTION_INDEX_START + BUILT_IN_UNIQ_ID_CLASS_OFFSET) <= it && it < (FUNCTION_INDEX_START + BUILT_IN_UNIQ_ID_GAP) }, {
builtIns.builtIns.getBuiltInClassByFqName(it)
})
private val ByteArray.codedInputStream: org.jetbrains.kotlin.protobuf.CodedInputStream
get() {
val codedInputStream = org.jetbrains.kotlin.protobuf.CodedInputStream.newInstance(this)
codedInputStream.setRecursionLimit(65535) // The default 64 is blatantly not enough for IR.
return codedInputStream
}
private val reversedFileIndex = mutableMapOf<UniqIdKey, IrFile>()
private val UniqIdKey.moduleOfOrigin get() =
this.moduleDescriptor ?: reversedFileIndex[this]?.packageFragmentDescriptor?.containingDeclaration
private fun deserializeTopLevelDeclaration(uniqIdKey: UniqIdKey): IrDeclaration {
val proto = loadTopLevelDeclarationProto(uniqIdKey)
return deserializeDeclaration(proto, reversedFileIndex[uniqIdKey]!!)
}
private fun loadTopLevelDeclarationProto(uniqIdKey: UniqIdKey): IrKlibProtoBuf.IrDeclaration {
val file = File(irDirectory, uniqIdKey.uniqId.declarationFileName)
return IrKlibProtoBuf.IrDeclaration.parseFrom(file.readBytes().codedInputStream, JsKlibMetadataSerializerProtocol.extensionRegistry)
}
private fun findDeserializedDeclarationForDescriptor(descriptor: DeclarationDescriptor): DeclarationDescriptor? {
val topLevelDescriptor = descriptor.findTopLevelDescriptor()
// if (topLevelDescriptor.module.isForwardDeclarationModule) return null
if (topLevelDescriptor !is DeserializedClassDescriptor && topLevelDescriptor !is DeserializedCallableMemberDescriptor) {
return null
}
val descriptorUniqId = topLevelDescriptor.getUniqId()
?: error("could not get descriptor uniq id for $topLevelDescriptor")
val uniqId = UniqId(descriptorUniqId.index, isLocal = false)
val topLevelKey = UniqIdKey(topLevelDescriptor.module, uniqId)
// This top level descriptor doesn't have a serialized IR declaration.
if (topLevelKey.moduleOfOrigin == null) return null
reachableTopLevels.add(topLevelKey)
do {
val key = reachableTopLevels.first()
if (deserializedSymbols[key]?.isBound == true ||
// The key.moduleOrigin is null for uniqIds that we haven't seen in any of the library headers.
// Just skip it for now and handle it elsewhere.
key.moduleOfOrigin == null) {
reachableTopLevels.remove(key)
deserializedTopLevels.add(key)
continue
}
deserializedModuleDescriptor = key.moduleOfOrigin
val reachable = deserializeTopLevelDeclaration(key)
reversedFileIndex[key]!!.declarations.add(reachable)
reachableTopLevels.remove(key)
deserializedTopLevels.add(key)
} while (reachableTopLevels.isNotEmpty())
return topLevelDescriptor
}
override fun findDeserializedDeclaration(symbol: IrSymbol): IrDeclaration? {
if (!symbol.isBound) {
val topLevelDesecriptor = findDeserializedDeclarationForDescriptor(symbol.descriptor)
if (topLevelDesecriptor == null) return null
}
assert(symbol.isBound) {
"findDeserializedDeclaration: symbol ${symbol} is unbound, descriptor = ${symbol.descriptor}, hash = ${symbol.descriptor.hashCode()}"
}
return symbol.owner as IrDeclaration
}
override fun findDeserializedDeclaration(propertyDescriptor: PropertyDescriptor): IrProperty? {
val topLevelDesecriptor = findDeserializedDeclarationForDescriptor(propertyDescriptor)
if (topLevelDesecriptor == null) return null
return symbolTable.propertyTable[propertyDescriptor]
?: error("findDeserializedDeclaration: property descriptor $propertyDescriptor} is not present in propertyTable after deserialization}")
}
override fun declareForwardDeclarations() {
if (forwardModuleDescriptor == null) return
val packageFragments = forwardDeclarations.map { it.descriptor.findPackage() }.distinct()
// We don't bother making a real IR module here, as we have no need in it any later.
// All we need is just to declare forward declarations in the symbol table
// In case you need a full fledged module, turn the forEach into a map and collect
// produced files into an IrModuleFragment.
packageFragments.forEach { packageFragment ->
val symbol = IrFileSymbolImpl(packageFragment)
val file = IrFileImpl(NaiveSourceBasedFileEntryImpl("forward declarations pseudo-file"), symbol)
val symbols = forwardDeclarations
.filter { !it.isBound }
.filter { it.descriptor.findPackage() == packageFragment }
val declarations = symbols.map {
val classDescriptor = it.descriptor as ClassDescriptor
val declaration = symbolTable.declareClass(UNDEFINED_OFFSET, UNDEFINED_OFFSET, irrelevantOrigin,
classDescriptor,
classDescriptor.modality
) { symbol: IrClassSymbol -> IrClassImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, irrelevantOrigin, symbol) }
declaration
}
file.declarations.addAll(declarations)
}
}
fun deserializeIrFile(fileProto: IrKlibProtoBuf.IrFile, moduleDescriptor: ModuleDescriptor, deserializeAllDeclarations: Boolean): IrFile {
val fileEntry = NaiveSourceBasedFileEntryImpl(fileProto.fileEntry.name)
// TODO: we need to store "" in protobuf, I suppose. Or better yet, reuse fqname storage from metadata.
val fqName = if (fileProto.fqName == "<root>") FqName.ROOT else FqName(fileProto.fqName)
val packageFragmentDescriptor = EmptyPackageFragmentDescriptor(moduleDescriptor, fqName)
val symbol = IrFileSymbolImpl(packageFragmentDescriptor)
val file = IrFileImpl(fileEntry, symbol, fqName)
fileProto.declarationIdList.forEach {
val uniqIdKey = it.uniqIdKey(moduleDescriptor)
reversedFileIndex.put(uniqIdKey, file)
if (deserializeAllDeclarations) {
file.declarations.add(deserializeTopLevelDeclaration(uniqIdKey))
}
}
return file
}
fun deserializeIrModule(proto: IrKlibProtoBuf.IrModule, moduleDescriptor: ModuleDescriptor, deserializeAllDeclarations: Boolean): IrModuleFragment {
deserializedModuleDescriptor = moduleDescriptor
deserializedModuleProtoSymbolTables.put(moduleDescriptor, proto.symbolTable)
deserializedModuleProtoTypeTables.put(moduleDescriptor, proto.typeTable)
var i = 0
val files = proto.fileList.map {
i++
// if (i >= 41)
// descriptorReferenceDeserializer.doCrash = true
deserializeIrFile(it, moduleDescriptor, deserializeAllDeclarations)
}
val module = IrModuleFragmentImpl(moduleDescriptor, builtIns, files)
module.patchDeclarationParents(null)
return module
}
fun deserializeIrModule(moduleDescriptor: ModuleDescriptor, byteArray: ByteArray, deserializeAllDeclarations: Boolean = false): IrModuleFragment {
val proto = IrKlibProtoBuf.IrModule.parseFrom(byteArray.codedInputStream, JsKlibMetadataSerializerProtocol.extensionRegistry)
return deserializeIrModule(proto, moduleDescriptor, deserializeAllDeclarations)
}
}
@@ -0,0 +1,40 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. 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.lower.serialization.ir
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.resolve.OverridingUtil
// TODO: move me somewhere
/**
* Implementation of given method.
*
* TODO: this method is actually a part of resolve and probably duplicates another one
*/
internal fun IrSimpleFunction.resolveFakeOverrideMaybeAbstract() = this.resolveFakeOverride(allowAbstract = true)
internal fun IrProperty.resolveFakeOverrideMaybeAbstract() = this.getter!!.resolveFakeOverrideMaybeAbstract().correspondingProperty!!
internal fun IrField.resolveFakeOverrideMaybeAbstract() = this.correspondingProperty!!.getter!!.resolveFakeOverrideMaybeAbstract().correspondingProperty!!.backingField
/**
* Implementation of given method.
*
* TODO: this method is actually a part of resolve and probably duplicates another one
*/
internal fun <T : CallableMemberDescriptor> T.resolveFakeOverrideMaybeAbstract(): Set<T> {
if (this.kind.isReal) {
return setOf(this)
} else {
val overridden = OverridingUtil.getOverriddenDeclarations(this)
val filtered = OverridingUtil.filterOutOverridden(overridden)
// TODO: is it correct to take first?
@Suppress("UNCHECKED_CAST")
return filtered as Set<T>
}
}
@@ -0,0 +1,12 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. 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.lower.serialization.ir
class SerializedIr (
val module: ByteArray,
val declarations: Map<UniqId, ByteArray>,
val debugIndex: Map<UniqId, String>
)
@@ -0,0 +1,53 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. 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.lower.serialization.ir
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.serialization.StringTableImpl
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.descriptorUtil.classId
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.resolve.descriptorUtil.getAllSuperClassifiers
import org.jetbrains.kotlin.resolve.descriptorUtil.module
import java.io.OutputStream
class KonanStringTable : StringTableImpl() {
fun getClassOrPackageFqNameIndex(descriptor: ClassOrPackageFragmentDescriptor): Int {
when (descriptor) {
is PackageFragmentDescriptor ->
return getPackageFqNameIndex(descriptor.fqName)
is ClassDescriptor ->
return getFqNameIndex(descriptor as ClassifierDescriptorWithTypeParameters)
else -> error("Can not get fqNameIndex for $descriptor")
}
}
override fun getLocalClassIdReplacement(descriptor: ClassifierDescriptorWithTypeParameters): ClassId? {
return if (descriptor.containingDeclaration is CallableMemberDescriptor) {
val superClassifiers = descriptor.getAllSuperClassifiers()
.mapNotNull { it as ClassifierDescriptorWithTypeParameters }
.filter { it != descriptor }
.toList()
if (superClassifiers.size == 1) {
superClassifiers[0].classId
} else {
val superClass = superClassifiers.find { !DescriptorUtils.isInterface(it) }
superClass?.classId ?: ClassId.topLevel(descriptor.module.builtIns.any.fqNameSafe)
}
} else {
super.getLocalClassIdReplacement(descriptor)
}
}
fun serializeTo(output: OutputStream) {
val (strings, qualifiedNames) = buildProto()
strings.writeDelimitedTo(output)
qualifiedNames.writeDelimitedTo(output)
}
}
@@ -0,0 +1,55 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. 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.lower.serialization.ir
import org.jetbrains.kotlin.backend.common.atMostOne
import org.jetbrains.kotlin.backend.common.descriptors.propertyIfAccessor
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.resolve.checkers.ExpectedActualDeclarationChecker
import org.jetbrains.kotlin.resolve.constants.StringValue
import org.jetbrains.kotlin.utils.addToStdlib.ifNotEmpty
internal val DeclarationDescriptor.isExpectMember: Boolean
get() = this is MemberDescriptor && this.isExpect
internal val DeclarationDescriptor.isSerializableExpectClass: Boolean
get() = this is ClassDescriptor && ExpectedActualDeclarationChecker.shouldGenerateExpectClass(this)
fun <T> AnnotationDescriptor.getArgumentValueOrNull(name: String): T? {
val constantValue = this.allValueArguments.entries.atMostOne {
it.key.asString() == name
}?.value
return constantValue?.value as T?
}
private val symbolNameAnnotation = FqName("kotlin.native.SymbolName")
fun getAnnotationValue(annotation: AnnotationDescriptor): String? {
return annotation.allValueArguments.values.ifNotEmpty {
val stringValue = single() as? StringValue
stringValue?.value
}
}
fun CallableMemberDescriptor.externalSymbolOrThrow(): String? {
this.annotations.findAnnotation(symbolNameAnnotation)?.let {
return getAnnotationValue(it)!!
}
throw Error("external function ${this} must have @TypedIntrinsic, @SymbolName or @ObjCMethod annotation")
}
tailrec internal fun DeclarationDescriptor.findPackage(): PackageFragmentDescriptor {
return if (this is PackageFragmentDescriptor) this
else this.containingDeclaration!!.findPackage()
}
fun DeclarationDescriptor.findTopLevelDescriptor(): DeclarationDescriptor {
return if (this.containingDeclaration is org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor) this.propertyIfAccessor
else this.containingDeclaration!!.findTopLevelDescriptor()
}
@@ -0,0 +1,108 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. 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.lower.serialization.ir
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.resolve.descriptorUtil.classId
class DescriptorReferenceSerializer(val declarationTable: DeclarationTable) {
// Not all exported descriptors are deserialized, some a synthesized anew during metadata deserialization.
// Those created descriptors can't carry the uniqIdIndex, since it is available only for deserialized descriptors.
// So we record the uniq id of some other "discoverable" descriptor for which we know for sure that it will be
// available as deserialized descriptor, plus the path to find the needed descriptor from that one.
fun serializeDescriptorReference(declaration: IrDeclaration): IrKlibProtoBuf.DescriptorReference? {
val descriptor = declaration.descriptor
if (!declaration.isExported() && !((declaration as? IrDeclarationWithVisibility)?.visibility == Visibilities.INVISIBLE_FAKE)) {
return null
}
if (declaration is IrAnonymousInitializer) return null
if (descriptor is ParameterDescriptor || (descriptor is VariableDescriptor && descriptor !is PropertyDescriptor) || descriptor is TypeParameterDescriptor) return null
val containingDeclaration = descriptor.containingDeclaration!!
val (packageFqName, classFqName) = when (containingDeclaration) {
is ClassDescriptor -> {
val classId = containingDeclaration.classId ?: return null
Pair(classId.packageFqName.toString(), classId.relativeClassName.toString())
}
is PackageFragmentDescriptor -> Pair(containingDeclaration.fqName.toString(), "")
else -> return null
}
val isAccessor = declaration.isAccessor
val isBackingField = declaration is IrField && declaration.correspondingProperty != null
val isFakeOverride = declaration.origin == IrDeclarationOrigin.FAKE_OVERRIDE
val isDefaultConstructor =
descriptor is ClassConstructorDescriptor && containingDeclaration is ClassDescriptor && containingDeclaration.kind == ClassKind.OBJECT
val isEnumEntry = descriptor is ClassDescriptor && descriptor.kind == ClassKind.ENUM_ENTRY
val isEnumSpecial = declaration.origin == IrDeclarationOrigin.ENUM_CLASS_SPECIAL_MEMBER
val realDeclaration = if (isFakeOverride) {
when (declaration) {
is IrSimpleFunction -> declaration.resolveFakeOverrideMaybeAbstract()
is IrField -> declaration.resolveFakeOverrideMaybeAbstract()
is IrProperty -> declaration.resolveFakeOverrideMaybeAbstract()
else -> error("Unexpected fake override declaration")
}
} else {
declaration
}
val discoverableDescriptorsDeclaration: IrDeclaration? = if (isAccessor) {
(realDeclaration as IrSimpleFunction).correspondingProperty!!
} else if (isBackingField) {
(realDeclaration as IrField).correspondingProperty!!
} else if (isDefaultConstructor || isEnumEntry) {
null
} else {
realDeclaration
}
val uniqId = discoverableDescriptorsDeclaration?.let { declarationTable.uniqIdByDeclaration(it) }
uniqId?.let { declarationTable.descriptors.put(discoverableDescriptorsDeclaration.descriptor, it) }
val proto = IrKlibProtoBuf.DescriptorReference.newBuilder()
.setPackageFqName(packageFqName)
.setClassFqName(classFqName)
.setName(descriptor.name.toString())
if (uniqId != null) proto.setUniqId(protoUniqId(uniqId))
if (isFakeOverride) {
proto.setIsFakeOverride(true)
}
if (isBackingField) {
proto.setIsBackingField(true)
}
if (isAccessor) {
if (declaration.isGetter)
proto.setIsGetter(true)
else if (declaration.isSetter)
proto.setIsSetter(true)
else
error("A property accessor which is neither a getter, nor a setter: $descriptor")
} else if (isDefaultConstructor) {
proto.setIsDefaultConstructor(true)
} else if (isEnumEntry) {
proto.setIsEnumEntry(true)
} else if (isEnumSpecial) {
proto.setIsEnumSpecial(true)
}
return proto.build()
}
}
@@ -0,0 +1,35 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. 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.lower.serialization.ir
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.metadata.ProtoBuf
import org.jetbrains.kotlin.metadata.ProtoBuf.QualifiedNameTable.QualifiedName
import org.jetbrains.kotlin.metadata.deserialization.NameResolverImpl
import org.jetbrains.kotlin.serialization.deserialization.getClassId
// TODO Come up with a better file name.
internal fun NameResolverImpl.getDescriptorByFqNameIndex(
module: ModuleDescriptor,
nameTable: ProtoBuf.QualifiedNameTable,
fqNameIndex: Int): DeclarationDescriptor {
if (fqNameIndex == -1) return module.getPackage(FqName.ROOT)
val packageName = this.getPackageFqName(fqNameIndex)
// TODO: Here we are using internals of NameresolverImpl.
// Consider extending NameResolver.
val proto = nameTable.getQualifiedName(fqNameIndex)
when (proto.kind!!) {
QualifiedName.Kind.CLASS,
QualifiedName.Kind.LOCAL ->
return module.findClassAcrossModuleDependencies(this.getClassId(fqNameIndex))!!
QualifiedName.Kind.PACKAGE ->
return module.getPackage(FqName(packageName))
}
}
@@ -0,0 +1,57 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. 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.lower.serialization.ir
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.ir.backend.js.lower.serialization.metadata.JsKlibMetadataProtoBuf
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
import org.jetbrains.kotlin.serialization.deserialization.descriptors.*
import org.jetbrains.kotlin.protobuf.GeneratedMessageLite
// This is an abstract uniqIdIndex any serialized IR declarations gets.
// It is either isLocal and then just gets and ordinary number within its module.
// Or is visible across modules and then gets a hash of mangled name as its index.
data class UniqId (
val index: Long,
val isLocal: Boolean
)
// isLocal=true in UniqId is good while we dealing with a single current module.
// To disambiguate module local declarations of different modules we use UniqIdKey.
// It has moduleDescriptor specified for isLocal=true uniqIds.
data class UniqIdKey private constructor(val uniqId: UniqId, val moduleDescriptor: ModuleDescriptor?) {
constructor(moduleDescriptor: ModuleDescriptor?, uniqId: UniqId)
: this(uniqId, if (uniqId.isLocal) moduleDescriptor!! else null)
}
internal val IrDeclaration.uniqIdIndex: Long
get() = this.uniqSymbolName().hashCode().toLong()
fun protoUniqId(uniqId: UniqId): IrKlibProtoBuf.UniqId =
IrKlibProtoBuf.UniqId.newBuilder()
.setIndex(uniqId.index)
.setIsLocal(uniqId.isLocal)
.build()
fun IrKlibProtoBuf.UniqId.uniqId(): UniqId = UniqId(this.index, this.isLocal)
fun IrKlibProtoBuf.UniqId.uniqIdKey(moduleDescriptor: ModuleDescriptor) =
UniqIdKey(moduleDescriptor, this.uniqId())
fun <T, M:GeneratedMessageLite.ExtendableMessage<M>> M.tryGetExtension(extension: GeneratedMessageLite.GeneratedExtension<M, T>)
= if (this.hasExtension(extension)) this.getExtension<T>(extension) else null
fun DeclarationDescriptor.getUniqId(): JsKlibMetadataProtoBuf.DescriptorUniqId? = when (this) {
is DeserializedClassDescriptor -> this.classProto.tryGetExtension(JsKlibMetadataProtoBuf.classUniqId)
is DeserializedSimpleFunctionDescriptor -> this.proto.tryGetExtension(JsKlibMetadataProtoBuf.functionUniqId)
is DeserializedPropertyDescriptor -> this.proto.tryGetExtension(JsKlibMetadataProtoBuf.propertyUniqId)
is DeserializedClassConstructorDescriptor -> this.proto.tryGetExtension(JsKlibMetadataProtoBuf.constructorUniqId)
else -> null
}
fun newDescriptorUniqId(index: Long): JsKlibMetadataProtoBuf.DescriptorUniqId =
JsKlibMetadataProtoBuf.DescriptorUniqId.newBuilder().setIndex(index).build()
val UniqId.declarationFileName: String get() = "$index${if (isLocal) "L" else "G"}.kjd"
@@ -0,0 +1,71 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. 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.lower.serialization.ir
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
// This is a little extension over what's used in real mangling
// since some declarations never appear in the bitcode symbols.
internal fun IrDeclaration.uniqSymbolName(): String = when (this) {
is IrFunction
-> this.uniqFunctionName
is IrProperty
-> this.symbolName
is IrClass
-> this.typeInfoSymbolName
is IrField
-> this.symbolName
is IrEnumEntry
-> this.symbolName
else -> error("Unexpected exported declaration: $this")
}
private val IrDeclarationParent.fqNameUnique: FqName
get() = when(this) {
is IrPackageFragment -> this.fqName
is IrDeclaration -> this.parent.fqNameUnique.child(this.uniqName)
else -> error(this)
}
private val IrDeclaration.uniqName: Name
get() = when (this) {
is IrSimpleFunction -> Name.special("<${this.uniqFunctionName}>")
else -> this.name
}
private val IrProperty.symbolName: String
get() {
val extensionReceiver: String = getter!!.extensionReceiverParameter ?. extensionReceiverNamePart ?: ""
val containingDeclarationPart = parent.fqNameSafe.let {
if (it.isRoot) "" else "$it."
}
return "kprop:$containingDeclarationPart$extensionReceiver$name"
}
private val IrEnumEntry.symbolName: String
get() {
val containingDeclarationPart = parent.fqNameSafe.let {
if (it.isRoot) "" else "$it."
}
return "kenumentry:$containingDeclarationPart$name"
}
// This is basicly the same as .symbolName, but disambiguates external functions with the same C name.
// In addition functions appearing in fq sequence appear as <full signature>.
private val IrFunction.uniqFunctionName: String
get() {
val parent = this.parent
val containingDeclarationPart = parent.fqNameUnique.let {
if (it.isRoot) "" else "$it."
}
return "kfun:$containingDeclarationPart#$functionName"
}
@@ -0,0 +1,606 @@
syntax = "proto2";
package org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir;
option java_outer_classname = "IrKlibProtoBuf";
option optimize_for = LITE_RUNTIME;
message DescriptorReference {
required string package_fq_name = 1;
required string class_fq_name = 2;
required string name = 3;
optional UniqId uniq_id = 4;
optional bool is_getter = 5 [default = false];
optional bool is_setter = 6 [default = false];
optional bool is_backing_field = 7 [default = false];
optional bool is_fake_override = 8 [default = false];
optional bool is_default_constructor = 9 [default = false];
optional bool is_enum_entry = 10 [default = false];
optional bool is_enum_special = 11 [default = false];
}
message UniqId {
required uint64 index = 1;
required bool isLocal = 2;
}
message Coordinates {
required int32 start_offset = 1;
required int32 end_offset = 2;
}
/* ------ Top Level---------------------------------------------- */
message IrDeclarationContainer {
repeated IrDeclaration declaration = 1;
}
message FileEntry { // TODO: extend me.
required string name = 1;
}
message IrFile {
repeated UniqId declaration_id = 1;
required FileEntry file_entry = 2;
// TODO: we need a better string management. See metadata serialization as an example.
required string fq_name = 3;
}
message IrModule {
required string name = 1;
repeated IrFile file = 2;
required IrSymbolTable symbol_table = 3;
required IrTypeTable type_table = 4;
}
/* ------ IrSymbols --------------------------------------------- */
enum IrSymbolKind {
FUNCTION_SYMBOL = 1;
CONSTRUCTOR_SYMBOL = 2;
ENUM_ENTRY_SYMBOL = 3;
FIELD_SYMBOL = 4;
VALUE_PARAMETER_SYMBOL = 5;
RETURNABLE_BLOCK_SYMBOL = 6;
CLASS_SYMBOL = 7;
TYPE_PARAMETER_SYMBOL = 8;
VARIABLE_SYMBOL = 9;
ANONYMOUS_INIT_SYMBOL = 10;
STANDALONE_FIELD_SYMBOL = 11; // For fields without properties. WrappedFieldDescriptor, rather than WrappedPropertyDescriptor.
RECEIVER_PARAMETER_SYMBOL = 12; // ReceiverParameterDescriptor rather than ValueParameterDescriptor.
}
message IrSymbolData {
required IrSymbolKind kind = 1;
required UniqId uniq_id = 2;
required UniqId top_level_uniq_id = 3;
optional string fqname = 4;
optional DescriptorReference descriptor_reference = 5;
}
message IrSymbol {
required int32 index = 1;
}
message IrSymbolTable {
repeated IrSymbolData symbols = 1;
}
/* ------ IrTypes --------------------------------------------- */
enum IrTypeVariance { // Should we import metadata variance, or better stay separate?
IN = 0;
OUT = 1;
INV = 2;
}
message Annotations {
repeated IrCall annotation = 1;
}
message TypeArguments {
repeated IrTypeIndex type_argument = 1;
}
message IrStarProjection {
optional bool void = 1;
}
message IrTypeProjection {
required IrTypeVariance variance = 1;
required IrTypeIndex type = 2;
}
message IrTypeArgument {
oneof kind {
IrStarProjection star = 1;
IrTypeProjection type = 2;
}
}
message IrSimpleType {
required Annotations annotations = 1;
required IrSymbol classifier = 2;
required bool has_question_mark = 3;
repeated IrTypeArgument argument = 4;
}
message IrDynamicType {
required Annotations annotations = 1;
}
message IrErrorType {
required Annotations annotations = 1;
}
message IrType {
oneof kind {
IrSimpleType simple = 1;
IrDynamicType dynamic = 2;
IrErrorType error = 3;
}
}
message IrTypeTable {
repeated IrType types = 1;
}
message IrTypeIndex {
required int32 index = 1;
}
/* ------ IrExpressions --------------------------------------------- */
message IrBreak {
required int32 loop_id = 1;
optional string label = 2;
}
message IrBlock {
required bool is_lambda_origin = 1;
repeated IrStatement statement = 2;
}
message MemberAccessCommon {
optional IrExpression dispatch_receiver = 1;
optional IrExpression extension_receiver = 2;
repeated NullableIrExpression value_argument = 3;
required TypeArguments type_arguments = 4;
}
message IrCall {
enum Primitive {
NOT_PRIMITIVE = 1;
NULLARY = 2;
UNARY = 3;
BINARY = 4;
}
required Primitive kind = 1;
required IrSymbol symbol = 2;
required MemberAccessCommon member_access = 3;
optional IrSymbol super = 4;
}
message IrFunctionReference {
required IrSymbol symbol = 1;
optional string origin = 2;
required MemberAccessCommon member_access = 3;
}
message IrPropertyReference {
optional IrSymbol field = 1;
optional IrSymbol getter = 2;
optional IrSymbol setter = 3;
optional string origin = 4;
required MemberAccessCommon member_access = 5;
}
message IrComposite {
repeated IrStatement statement = 1;
}
message IrClassReference {
required IrSymbol class_symbol = 1;
required IrTypeIndex class_type = 2;
}
message IrConst {
oneof value {
bool null = 1;
bool boolean = 2;
int32 char = 3;
int32 byte = 4;
int32 short = 5;
int32 int = 6;
int64 long = 7;
float float = 8;
double double = 9;
string string = 10;
}
}
message IrContinue {
required int32 loop_id = 1;
optional string label = 2;
}
message IrDelegatingConstructorCall {
required IrSymbol symbol = 1;
required MemberAccessCommon member_access = 2;
}
message IrDoWhile {
required Loop loop = 1;
}
message IrEnumConstructorCall {
required IrSymbol symbol = 1;
required MemberAccessCommon member_access = 2;
}
message IrGetClass {
required IrExpression argument = 1;
}
message IrGetEnumValue {
required IrSymbol symbol = 2;
}
message FieldAccessCommon {
required IrSymbol symbol = 1;
optional IrSymbol super = 2;
optional IrExpression receiver = 3;
}
message IrGetField {
required FieldAccessCommon field_access = 1;
}
message IrGetValue {
required IrSymbol symbol = 1;
}
message IrGetObject {
required IrSymbol symbol = 1;
}
message IrInstanceInitializerCall {
required IrSymbol symbol = 1;
}
message Loop {
required int32 loop_id = 1;
required IrExpression condition = 2;
optional string label = 3;
optional IrExpression body = 4;
}
message IrReturn {
required IrSymbol return_target = 1;
required IrExpression value = 2;
}
message IrSetField {
required FieldAccessCommon field_access = 1;
required IrExpression value = 2;
}
message IrSetVariable {
required IrSymbol symbol = 1;
required IrExpression value = 2;
}
message IrSpreadElement {
required IrExpression expression = 1;
required Coordinates coordinates = 2;
}
message IrStringConcat {
repeated IrExpression argument = 1;
}
message IrThrow {
required IrExpression value = 1;
}
message IrTry {
required IrExpression result = 1;
repeated IrStatement catch = 2;
optional IrExpression finally = 3;
}
message IrTypeOp {
required IrTypeOperator operator = 1;
required IrTypeIndex operand = 2;
required IrExpression argument = 3;
}
message IrVararg {
required IrTypeIndex element_type = 1;
repeated IrVarargElement element = 2;
}
message IrVarargElement {
oneof vararg_element {
IrExpression expression = 1;
IrSpreadElement spread_element = 2;
}
}
message IrWhen {
repeated IrStatement branch = 1;
}
message IrWhile {
required Loop loop = 1;
}
// TODO: we need an extension mechanism to accomodate new
// IR operators in upcoming releases.
message IrOperation {
oneof operation {
IrBlock block = 1;
IrBreak break = 2;
IrCall call = 3;
IrClassReference class_reference = 4;
IrComposite composite = 5;
IrConst const = 6;
IrContinue continue = 7;
IrDelegatingConstructorCall delegating_constructor_call = 8;
IrDoWhile do_while = 9;
IrEnumConstructorCall enum_constructor_call = 10;
IrFunctionReference function_reference = 11;
IrGetClass get_class = 12;
IrGetEnumValue get_enum_value = 13;
IrGetField get_field = 14;
IrGetObject get_object = 15;
IrGetValue get_value = 16;
IrInstanceInitializerCall instance_initializer_call = 17;
IrPropertyReference property_reference = 18;
IrReturn return = 19;
IrSetField set_field = 20;
IrSetVariable set_variable = 21;
IrStringConcat string_concat = 22;
IrThrow throw = 23;
IrTry try = 24;
IrTypeOp type_op = 25;
IrVararg vararg = 26;
IrWhen when = 27;
IrWhile while = 28;
}
}
enum IrTypeOperator {
CAST = 1;
IMPLICIT_CAST = 2;
IMPLICIT_NOTNULL = 3;
IMPLICIT_COERCION_TO_UNIT = 4;
IMPLICIT_INTEGER_COERCION = 5;
SAFE_CAST = 6;
INSTANCEOF = 7;
NOT_INSTANCEOF = 8;
SAM_CONVERSION = 9;
}
message IrExpression {
required IrOperation operation = 1;
required IrTypeIndex type = 2;
required Coordinates coordinates = 3;
}
message NullableIrExpression {
optional IrExpression expression = 1;
}
/* ------ Declarations --------------------------------------------- */
message IrTypeAlias {
// Nothing for now.
}
message IrFunction {
required IrSymbol symbol = 1;
required IrFunctionBase base = 2;
required ModalityKind modality = 3;
required bool is_tailrec = 4;
required bool is_suspend = 5;
repeated IrSymbol overridden = 6;
//optional UniqId corresponding_property = 7;
}
message IrFunctionBase {
required string name = 1;
required string visibility = 2;
required bool is_inline = 3;
required bool is_external = 4;
required IrTypeParameterContainer type_parameters = 5;
optional IrDeclaration dispatch_receiver = 6;
optional IrDeclaration extension_receiver = 7;
repeated IrDeclaration value_parameter = 8;
optional IrStatement body = 9;
required IrTypeIndex return_type = 10;
}
message IrConstructor {
required IrSymbol symbol = 1;
required IrFunctionBase base = 2;
required bool is_primary = 3;
}
message IrField {
required IrSymbol symbol = 1;
optional IrExpression initializer = 2;
required string name = 3;
required string visibility = 4;
required bool is_final = 5;
required bool is_external = 6;
required bool is_static = 7;
required IrTypeIndex type = 8;
}
message IrProperty {
optional DescriptorReference descriptor = 1; // IrProperty doesn't have a symbol at all. Preserve this rudiment for now.
required string name = 2;
required string visibility = 3;
required ModalityKind modality = 4;
required bool is_var = 5;
required bool is_const = 6;
required bool is_lateinit = 7;
required bool is_delegated = 8;
required bool is_external = 9;
optional IrField backing_field = 10;
optional IrFunction getter = 11;
optional IrFunction setter = 12;
}
message IrVariable {
required string name = 1;
required IrSymbol symbol = 2;
required IrTypeIndex type = 3;
required bool is_var = 4;
required bool is_const = 5;
required bool is_lateinit = 6;
optional IrExpression initializer = 7;
}
enum ClassKind {
CLASS = 1;
INTERFACE = 2;
ENUM_CLASS = 3;
ENUM_ENTRY = 4;
ANNOTATION_CLASS = 5;
OBJECT = 6;
}
enum ModalityKind { // It is ModalityKind to not clash with Modality in descriptor metadata.
FINAL_MODALITY = 1;
SEALED_MODALITY = 2;
OPEN_MODALITY = 3;
ABSTRACT_MODALITY = 4;
}
message IrValueParameter {
required IrSymbol symbol = 1;
required string name = 2;
required int32 index = 3;
required IrTypeIndex type = 4;
optional IrTypeIndex vararg_element_type = 5;
required bool is_crossinline = 6;
required bool is_noinline = 7;
optional IrExpression default_value = 8;
}
message IrTypeParameter {
required IrSymbol symbol = 1;
required string name = 2;
required int32 index = 3;
required IrTypeVariance variance = 4;
repeated IrTypeIndex super_type = 5;
required bool is_reified = 6;
}
message IrTypeParameterContainer {
repeated IrDeclaration type_parameter = 1;
}
message IrClass {
required IrSymbol symbol = 1;
required string name = 2;
required ClassKind kind = 3;
required string visibility = 4;
required ModalityKind modality = 5;
// TODO: consider using flags for the booleans.
required bool is_companion = 6;
required bool is_inner = 7;
required bool is_data = 8;
required bool is_external = 9;
required bool is_inline = 10;
optional IrDeclaration this_receiver = 11;
required IrTypeParameterContainer type_parameters = 12;
required IrDeclarationContainer declaration_container = 13;
repeated IrTypeIndex super_type = 14;
}
message IrEnumEntry {
required IrSymbol symbol = 1;
optional IrExpression initializer = 2;
optional IrDeclaration corresponding_class = 3;
required string name = 4;
}
message IrAnonymousInit {
required IrSymbol symbol = 1;
required IrStatement body = 2;
}
// TODO: we need an extension mechanism to accomodate new
// IR operators in upcoming releases.
message IrDeclarator {
oneof declarator {
IrAnonymousInit ir_anonymous_init = 1;
IrClass ir_class = 2;
IrConstructor ir_constructor = 3;
IrEnumEntry ir_enum_entry = 4;
IrField ir_field = 5;
IrFunction ir_function = 6;
IrProperty ir_property = 7;
IrTypeAlias ir_type_alias = 8;
IrTypeParameter ir_type_parameter = 9;
IrVariable ir_variable = 10;
IrValueParameter ir_value_parameter = 11;
}
}
message IrDeclarationOrigin {
required string name = 1;
}
message IrDeclaration {
required IrDeclarationOrigin origin = 1;
required Coordinates coordinates = 2;
required Annotations annotations = 3;
required IrDeclarator declarator = 4;
//repeated IrDeclaration nested = 5;
required string file_name = 5; // TODO: files should be communicated some other way, I suppose.
}
/* ------- IrStatements --------------------------------------------- */
message IrBranch {
required IrExpression condition = 1;
required IrExpression result = 2;
}
message IrBlockBody {
repeated IrStatement statement = 1;
}
message IrCatch {
required IrDeclaration catch_parameter = 1;
required IrExpression result = 2;
}
enum IrSyntheticBodyKind {
ENUM_VALUES = 1;
ENUM_VALUEOF = 2;
}
message IrSyntheticBody {
required IrSyntheticBodyKind kind = 1;
}
// Let's try to map IrElement as well as IrStatement to IrStatement.
message IrStatement {
required Coordinates coordinates = 1;
oneof statement {
IrDeclaration declaration = 2;
IrExpression expression = 3;
IrBlockBody block_body = 4;
IrBranch branch = 5;
IrCatch catch = 6;
IrSyntheticBody synthetic_body = 7;
}
}
@@ -64,7 +64,7 @@ fun createJsKlibMetadataPackageFragmentProvider(
emptyList(),
notFoundClasses,
ContractDeserializerImpl(configuration, storageManager),
platformDependentDeclarationFilter = PlatformDependentDeclarationFilter.NoPlatformDependent,
platformDependentDeclarationFilter = PlatformDependentDeclarationFilter.All,
extensionRegistryLite = JsKlibMetadataSerializerProtocol.extensionRegistry
)
@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs
import org.jetbrains.kotlin.backend.common.ir.isElseBranch
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
import org.jetbrains.kotlin.ir.backend.js.lower.coroutines.COROUTINE_SWITCH
import org.jetbrains.kotlin.ir.backend.js.utils.JsGenerationContext
@@ -99,7 +100,7 @@ class IrElementToJsStatementTransformer : BaseIrElementToJsNodeTransformer<JsSta
var expr: IrExpression? = null
val cases = expression.branches.map {
val body = it.result
val id = if (it is IrElseBranch) null else {
val id = if (isElseBranch(it)) null else {
val call = it.condition as IrCall
expr = call.getValueArgument(0) as IrExpression
call.getValueArgument(1)
@@ -102,8 +102,10 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
private fun generateThrowableProperties(): List<JsStatement> {
val functions = irClass.declarations.filterIsInstance<IrSimpleFunction>()
val messageGetter = functions.single { it.name == Name.special("<get-message>") }
val causeGetter = functions.single { it.name == Name.special("<get-cause>") }
// TODO: Fix `Name.special` deserialization
val messageGetter = functions.single { it.name.asString() == "<get-message>" }
val causeGetter = functions.single { it.name.asString() == "<get-cause>" }
val msgProperty = defineProperty(classPrototypeRef, "message", getter = buildGetterFunction(messageGetter))
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs
import org.jetbrains.kotlin.backend.common.descriptors.isSuspend
import org.jetbrains.kotlin.backend.common.ir.isElseBranch
import org.jetbrains.kotlin.ir.backend.js.utils.JsGenerationContext
import org.jetbrains.kotlin.ir.backend.js.utils.Namer
import org.jetbrains.kotlin.ir.declarations.IrFunction
@@ -24,7 +25,7 @@ fun <T : JsNode, D : JsGenerationContext> IrWhen.toJsNode(
): T? =
branches.foldRight<IrBranch, T?>(null) { br, n ->
val body = br.result.accept(tr, data)
if (br is IrElseBranch) body
if (isElseBranch(br)) body
else {
val condition = br.condition.accept(IrElementToJsExpressionTransformer(), data)
node(condition, body, n)
@@ -99,4 +99,6 @@ object Namer {
val THIS_SPECIAL_NAME = "<this>"
val SET_SPECIAL_NAME = "<set-?>"
val DYNAMIC_FILE_NAME = "<dynamicDeclarations>"
}
@@ -64,6 +64,7 @@ abstract class IrLazyDeclarationBase(
}
is ClassDescriptor -> stubGenerator.generateClassStub(containingDeclaration)
is FunctionDescriptor -> stubGenerator.generateFunctionStub(containingDeclaration)
is PropertyDescriptor -> stubGenerator.generateFunctionStub(containingDeclaration.run { getter ?: setter!! })
else -> throw AssertionError("Package or class expected: $containingDeclaration; for $currentDescriptor")
}
}
@@ -15,6 +15,12 @@ import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
import org.jetbrains.kotlin.ir.declarations.impl.IrExternalPackageFragmentImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrExternalPackageFragmentSymbolImpl
import org.jetbrains.kotlin.ir.types.IrSimpleType
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
import org.jetbrains.kotlin.ir.types.IrSimpleType
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
import org.jetbrains.kotlin.ir.types.withHasQuestionMark
import org.jetbrains.kotlin.ir.util.DeclarationStubGenerator
import org.jetbrains.kotlin.ir.util.SymbolTable
@@ -72,68 +78,97 @@ class IrBuiltIns(
private fun List<SimpleType>.defineComparisonOperatorForEachType(name: String) =
associate { it to defineComparisonOperator(name, it) }
private class IrTypeMapper(val type: () -> IrType, val nType: () -> IrType)
private fun buildNullableType(irType: IrType) = with(irType as IrSimpleType) {
IrSimpleTypeImpl(classifier, true, arguments, annotations)
}
private val primitiveTypesLazyMapping = mapOf<ClassifierDescriptor, IrTypeMapper>(
builtIns.any to IrTypeMapper({ anyType }, { anyNType }),
builtIns.boolean to IrTypeMapper({ booleanType }, { buildNullableType(booleanType) }),
builtIns.char to IrTypeMapper({ charType }, { buildNullableType(charType) }),
builtIns.number to IrTypeMapper({ numberType }, { buildNullableType(numberType) }),
builtIns.byte to IrTypeMapper({ byteType }, { buildNullableType(byteType) }),
builtIns.short to IrTypeMapper({ shortType }, { buildNullableType(shortType) }),
builtIns.int to IrTypeMapper({ intType }, { buildNullableType(intType) }),
builtIns.long to IrTypeMapper({ longType }, { buildNullableType(longType) }),
builtIns.float to IrTypeMapper({ floatType }, { buildNullableType(floatType) }),
builtIns.double to IrTypeMapper({ doubleType }, { buildNullableType(doubleType) }),
builtIns.nothing to IrTypeMapper({ nothingType }, { nothingNType }),
builtIns.unit to IrTypeMapper({ unitType }, { buildNullableType(unitType) }),
builtIns.string to IrTypeMapper({ stringType }, { buildNullableType(stringType) }),
builtIns.throwable to IrTypeMapper({ throwableType }, { buildNullableType(throwableType) })
// builtIns.array to { arrayClass.owner.defaultType }
)
fun getPrimitiveTypeOrNullByDescriptor(descriptor: ClassifierDescriptor, isNullable: Boolean) =
primitiveTypesLazyMapping[descriptor]?.let {
if (isNullable) it.nType() else it.type()
} as IrSimpleType?
val any = builtIns.anyType
val anyN = builtIns.nullableAnyType
val anyType = any.toIrType()
val anyClass = builtIns.any.toIrSymbol()
val anyNType = anyType.withHasQuestionMark(true)
val anyType by lazy { any.toIrType() }
val anyClass by lazy { builtIns.any.toIrSymbol() }
val anyNType by lazy { anyType.withHasQuestionMark(true) }
val bool = builtIns.booleanType
val booleanType = bool.toIrType()
val booleanClass = builtIns.boolean.toIrSymbol()
val booleanType by lazy { bool.toIrType() }
val booleanClass by lazy { builtIns.boolean.toIrSymbol() }
val char = builtIns.charType
val charType = char.toIrType()
val charClass = builtIns.char.toIrSymbol()
val charType by lazy { char.toIrType() }
val charClass by lazy { builtIns.char.toIrSymbol() }
val number = builtIns.number.defaultType
val numberType = number.toIrType()
val numberClass = builtIns.number.toIrSymbol()
val numberType by lazy { number.toIrType() }
val numberClass by lazy { builtIns.number.toIrSymbol() }
val byte = builtIns.byteType
val byteType = byte.toIrType()
val byteClass = builtIns.byte.toIrSymbol()
val byteType by lazy { byte.toIrType() }
val byteClass by lazy { builtIns.byte.toIrSymbol() }
val short = builtIns.shortType
val shortType = short.toIrType()
val shortClass = builtIns.short.toIrSymbol()
val shortType by lazy { short.toIrType() }
val shortClass by lazy { builtIns.short.toIrSymbol() }
val int = builtIns.intType
val intType = int.toIrType()
val intClass = builtIns.int.toIrSymbol()
val intType by lazy { int.toIrType() }
val intClass by lazy { builtIns.int.toIrSymbol() }
val long = builtIns.longType
val longType = long.toIrType()
val longClass = builtIns.long.toIrSymbol()
val longType by lazy { long.toIrType() }
val longClass by lazy { builtIns.long.toIrSymbol() }
val float = builtIns.floatType
val floatType = float.toIrType()
val floatClass = builtIns.float.toIrSymbol()
val floatType by lazy { float.toIrType() }
val floatClass by lazy { builtIns.float.toIrSymbol() }
val double = builtIns.doubleType
val doubleType = double.toIrType()
val doubleClass = builtIns.double.toIrSymbol()
val doubleType by lazy { double.toIrType() }
val doubleClass by lazy { builtIns.double.toIrSymbol() }
val nothing = builtIns.nothingType
val nothingN = builtIns.nullableNothingType
val nothingType = nothing.toIrType()
val nothingClass = builtIns.nothing.toIrSymbol()
val nothingNType = nothingType.withHasQuestionMark(true)
val nothingType by lazy { nothing.toIrType() }
val nothingClass by lazy { builtIns.nothing.toIrSymbol() }
val nothingNType by lazy { nothingType.withHasQuestionMark(true) }
val unit = builtIns.unitType
val unitType = unit.toIrType()
val unitClass = builtIns.unit.toIrSymbol()
val unitType by lazy { unit.toIrType() }
val unitClass by lazy { builtIns.unit.toIrSymbol() }
val string = builtIns.stringType
val stringType = string.toIrType()
val stringClass = builtIns.string.toIrSymbol()
val stringType by lazy { string.toIrType() }
val stringClass by lazy { builtIns.string.toIrSymbol() }
val collectionClass = builtIns.collection.toIrSymbol()
val collectionClass by lazy { builtIns.collection.toIrSymbol() }
val arrayClass = builtIns.array.toIrSymbol()
val arrayClass by lazy { builtIns.array.toIrSymbol() }
val throwableType = builtIns.throwable.defaultType.toIrType()
val throwableClass = builtIns.throwable.toIrSymbol()
val throwableType by lazy { builtIns.throwable.defaultType.toIrType() }
val throwableClass by lazy { builtIns.throwable.toIrSymbol() }
val kCallableClass = builtIns.getBuiltInClassByFqName(KotlinBuiltIns.FQ_NAMES.kCallable.toSafe()).toIrSymbol()
val kPropertyClass = builtIns.getBuiltInClassByFqName(KotlinBuiltIns.FQ_NAMES.kPropertyFqName.toSafe()).toIrSymbol()
@@ -5,9 +5,11 @@
package org.jetbrains.kotlin.ir.types
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ClassifierDescriptor
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrTypeParameter
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
@@ -68,6 +70,8 @@ fun IrType.makeNullable(addKotlinType:Boolean = true) =
else
this
var irTypeKotlinBuiltIns: KotlinBuiltIns? = null
fun IrType.toKotlinType(): KotlinType {
originalKotlinType?.let {
return it
@@ -75,6 +79,7 @@ fun IrType.toKotlinType(): KotlinType {
return when (this) {
is IrSimpleType -> makeKotlinType(classifier, arguments, hasQuestionMark)
is IrDynamicType -> createDynamicType(irTypeKotlinBuiltIns!!)
else -> TODO(toString())
}
}
@@ -21,16 +21,21 @@ import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrFieldImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrPropertyImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrValueParameterImpl
import org.jetbrains.kotlin.ir.declarations.lazy.*
import org.jetbrains.kotlin.ir.expressions.impl.IrErrorExpressionImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrExpressionBodyImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrValueParameterSymbolImpl
import org.jetbrains.kotlin.ir.types.impl.IrDynamicTypeImpl
import org.jetbrains.kotlin.load.java.descriptors.JavaCallableMemberDescriptor
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.hasBackingField
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.types.isDynamic
class DeclarationStubGenerator(
moduleDescriptor: ModuleDescriptor,
@@ -58,7 +58,8 @@ val PROTO_PATHS: List<ProtoPath> = listOf(
ProtoPath("core/metadata.jvm/src/jvm_metadata.proto"),
ProtoPath("core/metadata.jvm/src/jvm_module.proto"),
ProtoPath("build-common/src/java_descriptors.proto"),
ProtoPath("compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/serialization/metadata/js.proto")
// ProtoPath("compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/serialization/metadata/js.proto"),
ProtoPath("compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/serialization/ir/ir.proto")
)
private val EXT_OPTIONS_PROTO_PATH = ProtoPath("core/metadata/src/ext_options.proto")
@@ -15,6 +15,7 @@ import org.jetbrains.kotlin.config.*
import org.jetbrains.kotlin.ir.backend.js.compile
import org.jetbrains.kotlin.js.test.JsIrTestRuntime
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.test.KotlinTestUtils
import java.io.File
fun buildConfiguration(environment: KotlinCoreEnvironment): CompilerConfiguration {
@@ -38,6 +39,8 @@ fun buildConfiguration(environment: KotlinCoreEnvironment): CompilerConfiguratio
private val stdKlibFile = File("js/js.translator/testData/out/klibs/stdlib.klib")
private val resultJs = "js/js.translator/testData/out/klibs/result.js"
fun main() {
val environment = KotlinCoreEnvironment.createForTests(Disposable { }, CompilerConfiguration(), EnvironmentConfigFiles.JS_CONFIG_FILES)
@@ -53,7 +56,7 @@ fun main() {
val result = compile(
environment.project,
JsIrTestRuntime.FULL.sources.map(::createPsiFile),
(JsIrTestRuntime.FULL.sources).map(::createPsiFile),
buildConfiguration(environment),
null,
true,
@@ -61,5 +64,7 @@ fun main() {
emptyList()
)
TODO("Write library into $stdKlibFile")
File(resultJs).writeText(result.generatedCode)
// TODO("Write library into $stdKlibFile")
}