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