blob: ebc864759a45ff1d5d386cea1eab2c40316702f6 [file]
/*
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package kotlin.js
import kotlin.internal.UsedFromCompilerGeneratedCode
// There was a problem with per-module compilation (KT-55758) when the top-level state (globalInterfaceId) was reinitialized during stdlib module initialization
// As a result we miss already incremented globalInterfaceId and had the same interfaceIds in two different modules
// So, to keep the state consistent it was moved into the variable without initializer and function
@Suppress("MUST_BE_INITIALIZED")
private var globalInterfaceId: dynamic
// TODO: Merge the following two functions into one after the next boostrap
@UsedFromCompilerGeneratedCode
internal fun generateInterfaceId(): Int {
if (globalInterfaceId === VOID) {
globalInterfaceId = 0
}
globalInterfaceId = globalInterfaceId.unsafeCast<Int>() + 1
return globalInterfaceId
}
@UsedFromCompilerGeneratedCode
internal fun generateInterfaceSymbolById(): String {
return "#__interface_${generateInterfaceId()}"
}
@Suppress("MUST_BE_INITIALIZED")
private var globalAssociatedObjectId: dynamic
/**
* Calls to this function are only emitted when compiling incrementally.
*/
@UsedFromCompilerGeneratedCode
internal fun nextAssociatedObjectId(): Int {
if (globalAssociatedObjectId === VOID) {
globalAssociatedObjectId = 0
}
globalAssociatedObjectId = globalAssociatedObjectId.unsafeCast<Int>() + 1
return globalAssociatedObjectId.unsafeCast<Int>()
}
internal const val METADATA_KIND_INTERFACE = "interface"
internal const val METADATA_KIND_OBJECT = "object"
internal const val METADATA_KIND_CLASS = "class"
@OptIn(JsIntrinsic::class)
internal fun initMetadataFor(
kind: String,
ctor: Ctor,
name: String?,
defaultConstructor: dynamic,
parent: Ctor?,
interfaces: Array<dynamic>?,
suspendArity: Array<Int>?,
associatedObjectKey: Number?,
associatedObjects: dynamic
) {
if (parent != null) {
js("""
ctor.prototype = Object.create(parent.prototype)
ctor.prototype.constructor = ctor;
""")
}
val metadata = createMetadata(kind, name, defaultConstructor, associatedObjectKey, associatedObjects, suspendArity)
ctor.`$metadata$` = metadata
val prototype = ctor.prototype
if (interfaces != null) {
for (i in interfaces) {
js("Object.assign(prototype, i.prototype)")
prototype[i.Symbol] = true
}
}
if (kind === METADATA_KIND_INTERFACE) {
ctor.Symbol = jsGenerateInterfaceSymbol()
}
}
@UsedFromCompilerGeneratedCode
internal fun initMetadataForClass(
ctor: Ctor,
name: String?,
defaultConstructor: dynamic,
parent: Ctor?,
interfaces: Array<dynamic>?,
suspendArity: Array<Int>?,
associatedObjectKey: Number?,
associatedObjects: dynamic
) {
val kind = METADATA_KIND_CLASS
initMetadataFor(kind, ctor, name, defaultConstructor, parent, interfaces, suspendArity, associatedObjectKey, associatedObjects)
}
@UsedFromCompilerGeneratedCode
internal fun initMetadataForObject(
ctor: Ctor,
name: String?,
defaultConstructor: dynamic,
parent: Ctor?,
interfaces: Array<dynamic>?,
suspendArity: Array<Int>?,
associatedObjectKey: Number?,
associatedObjects: dynamic
) {
val kind = METADATA_KIND_OBJECT
initMetadataFor(kind, ctor, name, defaultConstructor, parent, interfaces, suspendArity, associatedObjectKey, associatedObjects)
}
@UsedFromCompilerGeneratedCode
internal fun initMetadataForInterface(
ctor: Ctor,
name: String?,
defaultConstructor: dynamic,
parent: Ctor?,
interfaces: Array<dynamic>?,
suspendArity: Array<Int>?,
associatedObjectKey: Number?,
associatedObjects: dynamic
) {
val kind = METADATA_KIND_INTERFACE
initMetadataFor(kind, ctor, name, defaultConstructor, parent, interfaces, suspendArity, associatedObjectKey, associatedObjects)
}
@UsedFromCompilerGeneratedCode
internal fun initMetadataForLambda(ctor: Ctor, parent: Ctor?, interfaces: Array<dynamic>?, suspendArity: Array<Int>?) {
initMetadataForClass(ctor, "Lambda", VOID, parent, interfaces, suspendArity, VOID, VOID)
}
@UsedFromCompilerGeneratedCode
internal fun initMetadataForFunctionReference(ctor: Ctor, parent: Ctor?, interfaces: Array<dynamic>?, suspendArity: Array<Int>?) {
initMetadataForClass(ctor, "FunctionReference", VOID, parent, interfaces, suspendArity, VOID, VOID)
}
@UsedFromCompilerGeneratedCode
internal fun initMetadataForCoroutine(ctor: Ctor, parent: Ctor?, interfaces: Array<dynamic>?, suspendArity: Array<Int>?) {
initMetadataForClass(ctor, "Coroutine", VOID, parent, interfaces, suspendArity, VOID, VOID)
}
@UsedFromCompilerGeneratedCode
internal fun initMetadataForCompanion(ctor: Ctor, parent: Ctor?, interfaces: Array<dynamic>?, suspendArity: Array<Int>?) {
initMetadataForObject(ctor, "Companion", VOID, parent, interfaces, suspendArity, VOID, VOID)
}
// Seems like we need to disable this check if variables are used inside js annotation
@Suppress("UNUSED_PARAMETER", "UNUSED_VARIABLE")
internal fun createMetadata(
kind: String,
name: String?,
defaultConstructor: dynamic,
associatedObjectKey: Number?,
associatedObjects: dynamic,
suspendArity: Array<Int>?,
): Metadata {
val undef = VOID
return js("""({
kind: kind,
simpleName: name,
associatedObjectKey: associatedObjectKey,
associatedObjects: associatedObjects,
suspendArity: suspendArity,
${'$'}kClass$: undef,
defaultConstructor: defaultConstructor
})""")
}
internal external interface Metadata {
val kind: String
// This field gives fast access to the prototype of metadata owner (Object.getPrototypeOf())
// Can be pre-initialized or lazy initialized and then should be immutable
val simpleName: String?
val associatedObjectKey: Number?
val associatedObjects: dynamic
val suspendArity: Array<Int>?
var `$kClass$`: dynamic
val defaultConstructor: dynamic
var errorInfo: Int? // Bits set for overridden properties: "message" => 0x1, "cause" => 0x2
}