/* * 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 // 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 private fun generateInterfaceId(): Int { if (globalInterfaceId === VOID) { globalInterfaceId = 0 } globalInterfaceId = globalInterfaceId.unsafeCast() + 1 return globalInterfaceId.unsafeCast() } internal const val METADATA_KIND_INTERFACE = "interface" internal const val METADATA_KIND_OBJECT = "object" internal const val METADATA_KIND_CLASS = "class" internal fun initMetadataFor( kind: String, ctor: Ctor, name: String?, defaultConstructor: dynamic, parent: Ctor?, interfaces: Array?, suspendArity: Array?, 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 if (interfaces != null) { val receiver = if (metadata.iid != VOID) ctor else ctor.prototype receiver.`$imask$` = implement(interfaces) } } internal fun initMetadataForClass( ctor: Ctor, name: String?, defaultConstructor: dynamic, parent: Ctor?, interfaces: Array?, suspendArity: Array?, associatedObjectKey: Number?, associatedObjects: dynamic ) { val kind = METADATA_KIND_CLASS initMetadataFor(kind, ctor, name, defaultConstructor, parent, interfaces, suspendArity, associatedObjectKey, associatedObjects) } internal fun initMetadataForObject( ctor: Ctor, name: String?, defaultConstructor: dynamic, parent: Ctor?, interfaces: Array?, suspendArity: Array?, associatedObjectKey: Number?, associatedObjects: dynamic ) { val kind = METADATA_KIND_OBJECT initMetadataFor(kind, ctor, name, defaultConstructor, parent, interfaces, suspendArity, associatedObjectKey, associatedObjects) } internal fun initMetadataForInterface( ctor: Ctor, name: String?, defaultConstructor: dynamic, parent: Ctor?, interfaces: Array?, suspendArity: Array?, associatedObjectKey: Number?, associatedObjects: dynamic ) { val kind = METADATA_KIND_INTERFACE initMetadataFor(kind, ctor, name, defaultConstructor, parent, interfaces, suspendArity, associatedObjectKey, associatedObjects) } internal fun initMetadataForLambda(ctor: Ctor, parent: Ctor?, interfaces: Array?, suspendArity: Array?) { initMetadataForClass(ctor, "Lambda", VOID, parent, interfaces, suspendArity, VOID, VOID) } internal fun initMetadataForFunctionReference(ctor: Ctor, parent: Ctor?, interfaces: Array?, suspendArity: Array?) { initMetadataForClass(ctor, "FunctionReference", VOID, parent, interfaces, suspendArity, VOID, VOID) } internal fun initMetadataForCoroutine(ctor: Ctor, parent: Ctor?, interfaces: Array?, suspendArity: Array?) { initMetadataForClass(ctor, "Coroutine", VOID, parent, interfaces, suspendArity, VOID, VOID) } internal fun initMetadataForCompanion(ctor: Ctor, parent: Ctor?, interfaces: Array?, suspendArity: Array?) { 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?, ): Metadata { val undef = VOID val iid = if (kind == METADATA_KIND_INTERFACE) generateInterfaceId() else VOID return js("""({ kind: kind, simpleName: name, associatedObjectKey: associatedObjectKey, associatedObjects: associatedObjects, suspendArity: suspendArity, ${'$'}kClass$: undef, defaultConstructor: defaultConstructor, iid: iid })""") } internal external interface Metadata { // TODO: This field can be used from user libs, e.g. kotlinx.serialization: // https://github.com/Kotlin/kotlinx.serialization/blob/b8de86f0e351f1099d2afb03ff92e2ef6256cbc7/core/jsMain/src/kotlinx/serialization/internal/Platform.kt#L74 // This must be reworked 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? val iid: Int? var `$kClass$`: dynamic val defaultConstructor: dynamic var errorInfo: Int? // Bits set for overridden properties: "message" => 0x1, "cause" => 0x2 }