| /* | |
| * 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 | |
| } |