[stdlib] Merge js-ir specific sources into common js sources

This commit is contained in:
Ilya Gorbunov
2023-10-06 22:20:58 +02:00
committed by Space Team
parent f00d4022c4
commit 911fa3bbbb
55 changed files with 54 additions and 65 deletions
+66
View File
@@ -0,0 +1,66 @@
/*
* Copyright 2010-2022 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
internal typealias BitMask = IntArray
private fun bitMaskWith(activeBit: Int): BitMask {
val numberIndex = activeBit shr 5
val intArray = IntArray(numberIndex + 1)
val positionInNumber = activeBit and 31
val numberWithSettledBit = 1 shl positionInNumber
intArray[numberIndex] = intArray[numberIndex] or numberWithSettledBit
return intArray
}
internal fun BitMask.isBitSet(possibleActiveBit: Int): Boolean {
val numberIndex = possibleActiveBit shr 5
if (numberIndex > size) return false
val positionInNumber = possibleActiveBit and 31
val numberWithSettledBit = 1 shl positionInNumber
return get(numberIndex) and numberWithSettledBit != 0
}
private fun compositeBitMask(capacity: Int, masks: Array<BitMask>): BitMask {
return IntArray(capacity) { i ->
var result = 0
for (mask in masks) {
if (i < mask.size) {
result = result or mask[i]
}
}
result
}
}
internal fun implement(interfaces: Array<dynamic>): BitMask {
var maxSize = 1
val masks = js("[]")
for (i in interfaces) {
var currentSize = maxSize
val imask: BitMask? = i.prototype.`$imask$` ?: i.`$imask$`
if (imask != null) {
masks.push(imask)
currentSize = imask.size
}
val iid: Int? = i.`$metadata$`.iid
val iidImask: BitMask? = iid?.let { bitMaskWith(it) }
if (iidImask != null) {
masks.push(iidImask)
currentSize = JsMath.max(currentSize, iidImask.size)
}
if (currentSize > maxSize) {
maxSize = currentSize
}
}
return compositeBitMask(maxSize, masks)
}
@@ -0,0 +1,8 @@
/*
* Copyright 2010-2018 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
internal object DefaultConstructorMarker
+7
View File
@@ -0,0 +1,7 @@
/*
* Copyright 2010-2021 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.
*/
@JsName("Error")
internal open external class JsError(message: String) : Throwable
+99
View File
@@ -0,0 +1,99 @@
/*
* Copyright 2010-2018 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 withType
@PublishedApi
internal external fun <T> Array(size: Int): Array<T>
@PublishedApi
internal fun <T> fillArrayVal(array: Array<T>, initValue: T): Array<T> {
for (i in 0..array.size - 1) {
array[i] = initValue
}
return array
}
internal inline fun <T> arrayWithFun(size: Int, init: (Int) -> T) = fillArrayFun(Array<T>(size), init)
internal inline fun <T> fillArrayFun(array: dynamic, init: (Int) -> T): Array<T> {
val result = array.unsafeCast<Array<T>>()
var i = 0
while (i != result.size) {
result[i] = init(i)
++i
}
return result
}
internal fun booleanArray(size: Int): BooleanArray = withType("BooleanArray", fillArrayVal(Array<Boolean>(size), false)).unsafeCast<BooleanArray>()
internal fun booleanArrayOf(arr: Array<Boolean>): BooleanArray = withType("BooleanArray", arr.asDynamic().slice()).unsafeCast<BooleanArray>()
@Suppress("UNUSED_PARAMETER")
internal fun charArray(size: Int): CharArray = withType("CharArray", js("new Uint16Array(size)")).unsafeCast<CharArray>()
@Suppress("UNUSED_PARAMETER")
internal fun charArrayOf(arr: Array<Char>): CharArray = withType("CharArray", js("new Uint16Array(arr)")).unsafeCast<CharArray>()
internal fun longArray(size: Int): LongArray = withType("LongArray", fillArrayVal(Array<Long>(size), 0L)).unsafeCast<LongArray>()
internal fun longArrayOf(arr: Array<Long>): LongArray = withType("LongArray", arr.asDynamic().slice()).unsafeCast<LongArray>()
internal fun <T> arrayIterator(array: Array<T>) = object : Iterator<T> {
var index = 0
override fun hasNext() = index != array.size
override fun next() = if (index != array.size) array[index++] else throw NoSuchElementException("$index")
}
internal fun booleanArrayIterator(array: BooleanArray) = object : BooleanIterator() {
var index = 0
override fun hasNext() = index != array.size
override fun nextBoolean() = if (index != array.size) array[index++] else throw NoSuchElementException("$index")
}
internal fun byteArrayIterator(array: ByteArray) = object : ByteIterator() {
var index = 0
override fun hasNext() = index != array.size
override fun nextByte() = if (index != array.size) array[index++] else throw NoSuchElementException("$index")
}
internal fun shortArrayIterator(array: ShortArray) = object : ShortIterator() {
var index = 0
override fun hasNext() = index != array.size
override fun nextShort() = if (index != array.size) array[index++] else throw NoSuchElementException("$index")
}
internal fun charArrayIterator(array: CharArray) = object : CharIterator() {
var index = 0
override fun hasNext() = index != array.size
override fun nextChar() = if (index != array.size) array[index++] else throw NoSuchElementException("$index")
}
internal fun intArrayIterator(array: IntArray) = object : IntIterator() {
var index = 0
override fun hasNext() = index != array.size
override fun nextInt() = if (index != array.size) array[index++] else throw NoSuchElementException("$index")
}
internal fun floatArrayIterator(array: FloatArray) = object : FloatIterator() {
var index = 0
override fun hasNext() = index != array.size
override fun nextFloat() = if (index != array.size) array[index++] else throw NoSuchElementException("$index")
}
internal fun doubleArrayIterator(array: DoubleArray) = object : DoubleIterator() {
var index = 0
override fun hasNext() = index != array.size
override fun nextDouble() = if (index != array.size) array[index++] else throw NoSuchElementException("$index")
}
internal fun longArrayIterator(array: LongArray) = object : LongIterator() {
var index = 0
override fun hasNext() = index != array.size
override fun nextLong() = if (index != array.size) array[index++] else throw NoSuchElementException("$index")
}
+63
View File
@@ -0,0 +1,63 @@
/*
* Copyright 2010-2020 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
// TODO use declarations from stdlib
private external class ArrayBuffer(size: Int)
private external class Float64Array(buffer: ArrayBuffer)
private external class Float32Array(buffer: ArrayBuffer)
private external class Int32Array(buffer: ArrayBuffer)
private val buf = ArrayBuffer(8)
// TODO use one DataView instead of bunch of typed views.
private val bufFloat64 = Float64Array(buf).unsafeCast<DoubleArray>()
private val bufFloat32 = Float32Array(buf).unsafeCast<FloatArray>()
private val bufInt32 = Int32Array(buf).unsafeCast<IntArray>()
private val lowIndex = run {
bufFloat64[0] = -1.0 // bff00000_00000000
if (bufInt32[0] != 0) 1 else 0
}
private val highIndex = 1 - lowIndex
internal fun doubleToRawBits(value: Double): Long {
bufFloat64[0] = value
return Long(bufInt32[lowIndex], bufInt32[highIndex])
}
@PublishedApi
internal fun doubleFromBits(value: Long): Double {
bufInt32[lowIndex] = value.low
bufInt32[highIndex] = value.high
return bufFloat64[0]
}
internal fun floatToRawBits(value: Float): Int {
bufFloat32[0] = value
return bufInt32[0]
}
@PublishedApi
internal fun floatFromBits(value: Int): Float {
bufInt32[0] = value
return bufFloat32[0]
}
// returns zero value for number with positive sign bit and non-zero value for number with negative sign bit.
internal fun doubleSignBit(value: Double): Int {
bufFloat64[0] = value
return bufInt32[highIndex] and Int.MIN_VALUE
}
internal fun getNumberHashCode(obj: Double): Int {
@Suppress("DEPRECATED_IDENTITY_EQUALS")
if (jsBitwiseOr(obj, 0).unsafeCast<Double>() === obj) {
return obj.toInt()
}
bufFloat64[0] = obj
return bufInt32[highIndex] * 31 + bufInt32[lowIndex]
}
@@ -0,0 +1,23 @@
/*
* Copyright 2010-2021 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 JsError
@JsName("Boolean")
internal external fun nativeBoolean(obj: Any?): Boolean
internal fun booleanInExternalLog(name: String, obj: dynamic) {
if (jsTypeOf(obj) != "boolean") {
console.asDynamic().error("Boolean expected for '$name', but actual:", obj)
}
}
internal fun booleanInExternalException(name: String, obj: dynamic) {
if (jsTypeOf(obj) != "boolean") {
throw JsError("Boolean expected for '$name', but actual: $obj")
}
}
@@ -0,0 +1,41 @@
/*
* Copyright 2010-2018 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
internal annotation class DoNotIntrinsify
@PublishedApi
@DoNotIntrinsify
internal fun charSequenceGet(a: CharSequence, index: Int): Char {
return if (isString(a)) {
Char(a.asDynamic().charCodeAt(index).unsafeCast<Int>())
} else {
a[index]
}
}
@PublishedApi
@DoNotIntrinsify
internal fun charSequenceLength(a: CharSequence): Int {
return if (isString(a)) {
a.asDynamic().length.unsafeCast<Int>()
} else {
a.length
}
}
@PublishedApi
@DoNotIntrinsify
internal fun charSequenceSubSequence(a: CharSequence, startIndex: Int, endIndex: Int): CharSequence {
return if (isString(a)) {
a.asDynamic().substring(startIndex, endIndex).unsafeCast<String>()
} else {
a.subSequence(startIndex, endIndex)
}
}
// Keeping this function as separate non-inline to intrincify `is` operator
internal fun isString(a: CharSequence) = a is String
@@ -0,0 +1,61 @@
/*
* Copyright 2010-2018 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.collections
import kotlin.js.*
internal fun arrayToString(array: Array<*>) = array.joinToString(", ", "[", "]") { toString(it) }
@OptIn(ExperimentalUnsignedTypes::class)
internal fun <T> Array<out T>?.contentDeepHashCodeInternal(): Int {
if (this == null) return 0
var result = 1
for (element in this) {
val elementHash = when {
element == null -> 0
isArrayish(element) -> (element.unsafeCast<Array<*>>()).contentDeepHashCodeInternal()
element is UByteArray -> element.contentHashCode()
element is UShortArray -> element.contentHashCode()
element is UIntArray -> element.contentHashCode()
element is ULongArray -> element.contentHashCode()
else -> element.hashCode()
}
result = 31 * result + elementHash
}
return result
}
internal fun <T> T.contentEqualsInternal(other: T): Boolean {
val a = this.asDynamic()
val b = other.asDynamic()
if (a === b) return true
if (a == null || b == null || !isArrayish(b) || a.length != b.length) return false
for (i in 0 until a.length) {
if (!equals(a[i], b[i])) {
return false
}
}
return true
}
internal fun <T> T.contentHashCodeInternal(): Int {
val a = this.asDynamic()
if (a == null) return 0
var result = 1
for (i in 0 until a.length) {
result = result * 31 + hashCode(a[i])
}
return result
}
+61
View File
@@ -0,0 +1,61 @@
/*
* Copyright 2010-2018 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
// Adopted from misc.js
internal fun compareTo(a: dynamic, b: dynamic): Int = when (jsTypeOf(a)) {
"number" -> when {
jsTypeOf(b) == "number" ->
doubleCompareTo(a, b)
b is Long ->
doubleCompareTo(a, b.toDouble())
else ->
primitiveCompareTo(a, b)
}
"string", "boolean" -> primitiveCompareTo(a, b)
else -> compareToDoNotIntrinsicify(a, b)
}
@DoNotIntrinsify
private fun <T : Comparable<T>> compareToDoNotIntrinsicify(a: Comparable<T>, b: T) =
a.compareTo(b)
internal fun primitiveCompareTo(a: dynamic, b: dynamic): Int =
when {
a < b -> -1
a > b -> 1
else -> 0
}
internal fun doubleCompareTo(a: dynamic, b: dynamic): Int =
when {
a < b -> -1
a > b -> 1
a === b -> {
if (a !== 0)
0
else {
val ia = 1.asDynamic() / a
if (ia === 1.asDynamic() / b) {
0
} else if (ia < 0) {
-1
} else {
1
}
}
}
a !== a ->
if (b !== b) 0 else 1
else -> -1
}
@@ -0,0 +1,13 @@
/*
* Copyright 2010-2020 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
/**
* @param CT is return type of calling constructor (uses in DCE)
*/
internal fun <CT> construct(constructorType: dynamic, resultType: dynamic, vararg args: Any?): Any {
return js("Reflect").construct(constructorType, args, resultType)
}
+247
View File
@@ -0,0 +1,247 @@
/*
* Copyright 2010-2020 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
internal fun equals(obj1: dynamic, obj2: dynamic): Boolean {
if (obj1 == null) {
return obj2 == null
}
if (obj2 == null) {
return false
}
if (jsTypeOf(obj1) == "object" && jsTypeOf(obj1.equals) == "function") {
return (obj1.equals)(obj2)
}
if (obj1 !== obj1) {
return obj2 !== obj2
}
if (jsTypeOf(obj1) == "number" && jsTypeOf(obj2) == "number") {
return obj1 === obj2 && (obj1 !== 0 || 1.asDynamic() / obj1 === 1.asDynamic() / obj2)
}
return obj1 === obj2
}
internal fun toString(o: dynamic): String = when {
o == null -> "null"
isArrayish(o) -> "[...]"
jsTypeOf(o.toString) != "function" -> anyToString(o)
else -> (o.toString)().unsafeCast<String>()
}
internal fun anyToString(o: dynamic): String = js("Object").prototype.toString.call(o)
internal fun hashCode(obj: dynamic): Int {
if (obj == null) return 0
@Suppress("UNUSED_VARIABLE")
return when (val typeOf = jsTypeOf(obj)) {
"object" -> if ("function" === jsTypeOf(obj.hashCode)) (obj.hashCode)() else getObjectHashCode(obj)
"function" -> getObjectHashCode(obj)
"number" -> getNumberHashCode(obj)
"boolean" -> getBooleanHashCode(obj.unsafeCast<Boolean>())
"string" -> getStringHashCode(js("String")(obj))
"bigint" -> getBigIntHashCode(obj)
"symbol" -> getSymbolHashCode(obj)
else -> js("throw new Error('Unexpected typeof `' + typeOf + '`')")
}
}
internal fun getBooleanHashCode(value: Boolean): Int {
return if (value) 1231 else 1237
}
private fun getBigIntHashCode(value: dynamic): Int {
@Suppress("UNUSED_VARIABLE")
val shiftNumber = js("BigInt(32)");
@Suppress("UNUSED_VARIABLE")
val MASK = js("BigInt(0xffffffff)");
@Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE")
var bigNumber = if (value < 0) -value else value
var hashCode = 0
val signum = if (value < 0) -1 else 1
while (bigNumber != 0) {
val chunk = js("Number(bigNumber & MASK)").unsafeCast<Int>()
hashCode = 31 * hashCode + chunk
@Suppress("UNUSED_VALUE")
bigNumber = js("bigNumber >> shiftNumber")
}
return hashCode * signum
}
@Suppress("MUST_BE_INITIALIZED")
private var symbolWeakMap: dynamic
@Suppress("MUST_BE_INITIALIZED")
private var symbolMap: dynamic
private fun getSymbolWeakMap(): dynamic {
if (symbolWeakMap === VOID) {
symbolWeakMap = js("new WeakMap()")
}
return symbolWeakMap
}
private fun getSymbolMap(): dynamic {
if (symbolMap === VOID) {
symbolMap = js("new Map()")
}
return symbolMap
}
@Suppress("UNUSED_PARAMETER")
private fun symbolIsSharable(symbol: dynamic) = js("Symbol.keyFor(symbol)") != VOID
private fun getSymbolHashCode(value: dynamic): Int {
val hashCodeMap = if (symbolIsSharable(value)) getSymbolMap() else getSymbolWeakMap()
val cachedHashCode = hashCodeMap.get(value)
if (cachedHashCode !== VOID) return cachedHashCode
val hash = calculateRandomHash()
hashCodeMap.set(value, hash)
return hash
}
private const val POW_2_32 = 4294967296.0
private const val OBJECT_HASH_CODE_PROPERTY_NAME = "kotlinHashCodeValue$"
private fun calculateRandomHash(): Int {
return jsBitwiseOr(js("Math").random() * POW_2_32, 0) // Make 32-bit singed integer.
}
internal fun getObjectHashCode(obj: dynamic): Int {
if (!jsIn(OBJECT_HASH_CODE_PROPERTY_NAME, obj)) {
var hash = calculateRandomHash()
var descriptor = js("new Object()")
descriptor.value = hash
descriptor.enumerable = false
js("Object").defineProperty(obj, OBJECT_HASH_CODE_PROPERTY_NAME, descriptor)
}
return obj[OBJECT_HASH_CODE_PROPERTY_NAME].unsafeCast<Int>();
}
internal fun getStringHashCode(str: String): Int {
var hash = 0
val length: Int = str.length // TODO: Implement WString.length
for (i in 0..length-1) {
val code: Int = str.asDynamic().charCodeAt(i)
hash = hash * 31 + code
}
return hash
}
internal fun identityHashCode(obj: Any?): Int = getObjectHashCode(obj)
internal fun captureStack(instance: Throwable, constructorFunction: Any) {
if (js("Error").captureStackTrace != null) {
js("Error").captureStackTrace(instance, constructorFunction)
} else {
instance.asDynamic().stack = js("new Error()").stack
}
}
internal fun newThrowable(message: String?, cause: Throwable?): Throwable {
val throwable = js("new Error()")
throwable.message = if (isUndefined(message)) {
if (isUndefined(cause)) message else cause?.toString() ?: VOID
} else message ?: VOID
throwable.cause = cause
throwable.name = "Throwable"
return throwable.unsafeCast<Throwable>()
}
internal fun extendThrowable(this_: dynamic, message: String?, cause: Throwable?) {
js("Error").call(this_)
setPropertiesToThrowableInstance(this_, message, cause)
}
internal fun setPropertiesToThrowableInstance(this_: dynamic, message: String?, cause: Throwable?) {
val errorInfo = calculateErrorInfo(JsObject.getPrototypeOf(this_))
if ((errorInfo and 0x1) == 0) {
@Suppress("IfThenToElvis")
this_.message = if (message == null) {
@Suppress("SENSELESS_COMPARISON")
if (message !== null) {
// undefined
cause?.toString() ?: VOID
} else {
// real null
VOID
}
} else message
}
if ((errorInfo and 0x2) == 0) {
this_.cause = cause
}
this_.name = JsObject.getPrototypeOf(this_).constructor.name
}
@JsName("Object")
internal external class JsObject {
companion object {
fun getPrototypeOf(obj: Any?): dynamic
}
}
// Note: once some error-compilation design happened consider to distinguish a special exception for error-code.
internal fun errorCode(description: String): Nothing {
throw IllegalStateException(description)
}
@Suppress("SENSELESS_COMPARISON")
internal fun isUndefined(value: dynamic): Boolean = value === VOID
internal fun <T, R> boxIntrinsic(@Suppress("UNUSED_PARAMETER") x: T): R = error("Should be lowered")
internal fun <T, R> unboxIntrinsic(@Suppress("UNUSED_PARAMETER") x: T): R = error("Should be lowered")
@Suppress("UNUSED_PARAMETER")
internal fun protoOf(constructor: Any) =
js("constructor.prototype")
@Suppress("UNUSED_PARAMETER")
internal fun <T> objectCreate(proto: T?) =
js("Object.create(proto)")
@Suppress("UNUSED_PARAMETER")
internal fun createThis(ctor: Ctor, box: dynamic): dynamic {
val self = js("Object.create(ctor.prototype)")
boxApply(self, box)
return self
}
@Suppress("UNUSED_PARAMETER")
internal fun boxApply(self: dynamic, box: dynamic) {
if (box !== VOID) js("Object.assign(self, box)")
}
@OptIn(JsIntrinsic::class)
@Suppress("UNUSED_PARAMETER", "UNUSED_VARIABLE", "REIFIED_TYPE_PARAMETER_NO_INLINE")
internal fun <reified T : Any> createExternalThis(
ctor: JsClass<T>,
superExternalCtor: JsClass<T>,
parameters: Array<Any?>,
box: dynamic
): T {
val selfCtor = if (box === VOID) {
ctor
} else {
val newCtor: dynamic = jsNewAnonymousClass(ctor)
js("Object.assign(newCtor.prototype, box)")
newCtor.constructor = ctor
newCtor
}
return js("Reflect.construct(superExternalCtor, parameters, selfCtor)")
}
@Suppress("UNUSED_PARAMETER")
internal fun defineProp(obj: Any, name: String, getter: Any?, setter: Any?) =
js("Object.defineProperty(obj, name, { configurable: true, get: getter, set: setter })")
@@ -0,0 +1,38 @@
/*
* Copyright 2010-2018 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.coroutines.*
@PublishedApi
internal fun <T> getContinuation(): Continuation<T> { throw Exception("Implemented as intrinsic") }
// Do we really need this intrinsic in JS?
@PublishedApi
@Suppress("UNCHECKED_CAST")
internal suspend fun <T> returnIfSuspended(argument: Any?): T {
return argument as T
}
@PublishedApi
internal fun <T> interceptContinuationIfNeeded(
context: CoroutineContext,
continuation: Continuation<T>
) = context[ContinuationInterceptor]?.interceptContinuation(continuation) ?: continuation
@SinceKotlin("1.2")
@PublishedApi
internal inline suspend fun getCoroutineContext(): CoroutineContext = getContinuation<Any?>().context
// TODO: remove `JS` suffix oncec `NameGenerator` is implemented
@PublishedApi
internal inline suspend fun <T> suspendCoroutineUninterceptedOrReturnJS(block: (Continuation<T>) -> Any?): T =
returnIfSuspended<T>(block(getContinuation<T>()))
+16
View File
@@ -0,0 +1,16 @@
/*
* Copyright 2010-2021 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 JsError
internal fun unreachableDeclarationLog() {
console.asDynamic().trace("Unreachable declaration")
}
internal fun unreachableDeclarationException() {
throw JsError("Unreachable declaration")
}
+21
View File
@@ -0,0 +1,21 @@
/*
* Copyright 2010-2021 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
@JsPolyfill("""
(function() {
if (typeof globalThis === 'object') return;
Object.defineProperty(Object.prototype, '__magic__', {
get: function() {
return this;
},
configurable: true
});
__magic__.globalThis = __magic__;
delete Object.prototype.__magic__;
}());
""")
internal external val globalThis: dynamic
+34
View File
@@ -0,0 +1,34 @@
/*
* Copyright 2010-2018 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
@PublishedApi
internal fun throwUninitializedPropertyAccessException(name: String): Nothing =
throw UninitializedPropertyAccessException("lateinit property $name has not been initialized")
@PublishedApi
internal fun throwKotlinNothingValueException(): Nothing =
throw KotlinNothingValueException()
internal fun noWhenBranchMatchedException(): Nothing = throw NoWhenBranchMatchedException()
internal fun THROW_ISE(): Nothing {
throw IllegalStateException()
}
internal fun THROW_CCE(): Nothing {
throw ClassCastException()
}
internal fun THROW_NPE(): Nothing {
throw NullPointerException()
}
internal fun THROW_IAE(msg: String): Nothing {
throw IllegalArgumentException(msg)
}
internal fun <T:Any> ensureNotNull(v: T?): T = if (v == null) THROW_NPE() else v
+233
View File
@@ -0,0 +1,233 @@
/*
* Copyright 2010-2021 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.
*/
@file:Suppress("NON_MEMBER_FUNCTION_NO_BODY", "UNUSED_PARAMETER", "unused")
package kotlin.js
@RequiresOptIn(message = "Here be dragons! This is a compiler intrinsic, proceed with care!")
@Retention(AnnotationRetention.BINARY)
@Target(AnnotationTarget.FUNCTION)
internal annotation class JsIntrinsic
@JsIntrinsic
internal fun jsEqeq(a: Any?, b: Any?): Boolean
@JsIntrinsic
internal fun jsNotEq(a: Any?, b: Any?): Boolean
@JsIntrinsic
internal fun jsUndefined(): Nothing?
@JsIntrinsic
internal fun jsEqeqeq(a: Any?, b: Any?): Boolean
@JsIntrinsic
internal fun jsNotEqeq(a: Any?, b: Any?): Boolean
@JsIntrinsic
internal fun jsGt(a: Any?, b: Any?): Boolean
@JsIntrinsic
internal fun jsGtEq(a: Any?, b: Any?): Boolean
@JsIntrinsic
internal fun jsLt(a: Any?, b: Any?): Boolean
@JsIntrinsic
internal fun jsLtEq(a: Any?, b: Any?): Boolean
@JsIntrinsic
internal fun jsNot(a: Any?): Boolean
@JsIntrinsic
internal fun jsUnaryPlus(a: Any?): Any?
@JsIntrinsic
internal fun jsUnaryMinus(a: Any?): Any?
@JsIntrinsic
internal fun jsPrefixInc(a: Any?): Any?
@JsIntrinsic
internal fun jsPostfixInc(a: Any?): Any?
@JsIntrinsic
internal fun jsPrefixDec(a: Any?): Any?
@JsIntrinsic
internal fun jsPostfixDec(a: Any?): Any?
@JsIntrinsic
internal fun jsPlus(a: Any?, b: Any?): Any?
@JsIntrinsic
internal fun jsMinus(a: Any?, b: Any?): Any?
@JsIntrinsic
internal fun jsMult(a: Any?, b: Any?): Any?
@JsIntrinsic
internal fun jsDiv(a: Any?, b: Any?): Any?
@JsIntrinsic
internal fun jsMod(a: Any?, b: Any?): Any?
@JsIntrinsic
internal fun jsPlusAssign(a: Any?, b: Any?): Any?
@JsIntrinsic
internal fun jsMinusAssign(a: Any?, b: Any?): Any?
@JsIntrinsic
internal fun jsMultAssign(a: Any?, b: Any?): Any?
@JsIntrinsic
internal fun jsDivAssign(a: Any?, b: Any?): Any?
@JsIntrinsic
internal fun jsModAssign(a: Any?, b: Any?): Any?
@JsIntrinsic
internal fun jsAnd(a: Any?, b: Any?): Any?
@JsIntrinsic
internal fun jsOr(a: Any?, b: Any?): Any?
@JsIntrinsic
internal fun jsBitAnd(a: Any?, b: Any?): Int
@JsIntrinsic
internal fun jsBitOr(a: Any?, b: Any?): Int
@JsIntrinsic
internal fun jsBitXor(a: Any?, b: Any?): Int
@JsIntrinsic
internal fun jsBitNot(a: Any?): Int
@JsIntrinsic
internal fun jsBitShiftR(a: Any?, b: Any?): Int
@JsIntrinsic
internal fun jsBitShiftRU(a: Any?, b: Any?): Int
@JsIntrinsic
internal fun jsBitShiftL(a: Any?, b: Any?): Int
@JsIntrinsic
internal fun jsInstanceOfIntrinsic(a: Any?, b: Any?): Boolean
// @JsIntrinsic
// To prevent people to insert @OptIn every time
public external fun jsTypeOf(a: Any?): String
@JsIntrinsic
internal fun jsNewTarget(a: Any?): Any?
@JsIntrinsic
internal fun emptyObject(a: Any?): Any?
@JsIntrinsic
internal fun openInitializerBox(a: Any?, b: Any?): Any?
@JsIntrinsic
internal fun jsArrayLength(a: Any?): Any?
@JsIntrinsic
internal fun jsArrayGet(a: Any?, b: Any?): Any?
@JsIntrinsic
internal fun jsArraySet(a: Any?, b: Any?, c: Any?): Any?
@JsIntrinsic
internal fun arrayLiteral(a: Any?): Any?
@JsIntrinsic
internal fun int8Array(a: Any?): Any?
@JsIntrinsic
internal fun int16Array(a: Any?): Any?
@JsIntrinsic
internal fun int32Array(a: Any?): Any?
@JsIntrinsic
internal fun float32Array(a: Any?): Any?
@JsIntrinsic
internal fun float64Array(a: Any?): Any?
@JsIntrinsic
internal fun int8ArrayOf(a: Any?): Any?
@JsIntrinsic
internal fun int16ArrayOf(a: Any?): Any?
@JsIntrinsic
internal fun int32ArrayOf(a: Any?): Any?
@JsIntrinsic
internal fun float32ArrayOf(a: Any?): Any?
@JsIntrinsic
internal fun float64ArrayOf(a: Any?): Any?
@JsIntrinsic
internal fun <T> sharedBoxCreate(v: T?): dynamic
@JsIntrinsic
internal fun <T> sharedBoxRead(box: dynamic): T?
@JsIntrinsic
internal fun <T> sharedBoxWrite(box: dynamic, nv: T?)
@JsIntrinsic
internal fun <T> DefaultType(): T
@JsIntrinsic
internal fun jsBind(receiver: Any?, target: Any?): Any?
@JsIntrinsic
internal fun jsCall(receiver: Any?, target: Any?, vararg args: Any?): Any?
@JsIntrinsic
internal fun <A> slice(a: A): A
@JsIntrinsic
internal fun <T> jsArrayLike2Array(arrayLike: Any?): Array<T>
@JsIntrinsic
internal fun <T> jsSliceArrayLikeFromIndex(arrayLike: Any?, start: Int): Array<T>
@JsIntrinsic
internal fun <T> jsSliceArrayLikeFromIndexToIndex(arrayLike: Any?, start: Int, end: Int): Array<T>
@JsIntrinsic
internal fun unreachable(): Nothing
@JsIntrinsic
internal fun jsArguments(): Any?
@JsIntrinsic
@Suppress("REIFIED_TYPE_PARAMETER_NO_INLINE")
internal fun <reified T : Any> jsNewAnonymousClass(superClass: JsClass<T>): JsClass<T>
@JsIntrinsic
@Suppress("REIFIED_TYPE_PARAMETER_NO_INLINE") // TODO: mark `inline` and skip in inliner
internal fun <reified T : Any> jsClassIntrinsic(): JsClass<T>
// Returns true if the specified property is in the specified object or its prototype chain.
@JsIntrinsic
internal fun jsInIntrinsic(lhs: Any?, rhs: Any): Boolean
@JsIntrinsic
internal fun jsDelete(e: Any?)
@JsIntrinsic
internal fun jsContextfulRef(context: dynamic, fn: dynamic): dynamic
@JsIntrinsic
internal fun jsIsEs6(): Boolean
@@ -0,0 +1,75 @@
/*
* Copyright 2010-2018 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.
*/
// File is a copy of stdlib/js/src/kotlin/kotlin.kt
// TODO: Compile arrayPlusCollection
// TODO: implement a copy of jsIsType for both JS backends
@file:Suppress("UNUSED_PARAMETER", "NOTHING_TO_INLINE")
package kotlin
/**
* Returns an empty array of the specified type [T].
*/
public inline fun <T> emptyArray(): Array<T> = js("[]")
/**
* Creates a new instance of the [Lazy] that uses the specified initialization function [initializer].
*/
public actual fun <T> lazy(initializer: () -> T): Lazy<T> = UnsafeLazyImpl(initializer)
/**
* Creates a new instance of the [Lazy] that uses the specified initialization function [initializer].
*
* The [mode] parameter is ignored. */
public actual fun <T> lazy(mode: LazyThreadSafetyMode, initializer: () -> T): Lazy<T> = UnsafeLazyImpl(initializer)
/**
* Creates a new instance of the [Lazy] that uses the specified initialization function [initializer].
*
* The [lock] parameter is ignored.
*/
@Deprecated("Synchronization on Any? object is not supported.", ReplaceWith("lazy(initializer)"))
@DeprecatedSinceKotlin(warningSince = "1.9")
public actual fun <T> lazy(lock: Any?, initializer: () -> T): Lazy<T> = UnsafeLazyImpl(initializer)
internal fun fillFrom(src: dynamic, dst: dynamic): dynamic {
val srcLen: Int = src.length
val dstLen: Int = dst.length
var index: Int = 0
val arr = dst.unsafeCast<Array<Any?>>()
while (index < srcLen && index < dstLen) arr[index] = src[index++]
return dst
}
internal fun arrayCopyResize(source: dynamic, newSize: Int, defaultValue: Any?): dynamic {
val result = source.slice(0, newSize).unsafeCast<Array<Any?>>()
copyArrayType(source, result)
var index: Int = source.length
if (newSize > index) {
result.asDynamic().length = newSize
while (index < newSize) result[index++] = defaultValue
}
return result
}
internal fun <T> arrayPlusCollection(array: dynamic, collection: Collection<T>): dynamic {
val result = array.slice().unsafeCast<Array<T>>()
result.asDynamic().length = result.size + collection.size
copyArrayType(array, result)
var index: Int = array.length
for (element in collection) result[index++] = element
return result
}
internal inline fun copyArrayType(from: dynamic, to: dynamic) {
if (from.`$type$` !== undefined) {
to.`$type$` = from.`$type$`
}
}
@@ -0,0 +1,53 @@
/*
* Copyright 2010-2018 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
@PublishedApi
internal fun <T : Enum<T>> enumValuesIntrinsic(): Array<T> =
throw IllegalStateException("Should be replaced by compiler")
@PublishedApi
internal fun <T : Enum<T>> enumValueOfIntrinsic(@Suppress("UNUSED_PARAMETER") name: String): T =
throw IllegalStateException("Should be replaced by compiler")
// These were necessary for legacy-property-access functionality in IR
// But this functionality is not required anymore, so these methods are redundant
// But they can't be removed because if old version of compiler will compile against new version of stdlib
// (when these methods are removed) compiler will fail with Internal error
@Deprecated("This is an intrinsic for removed functionality", level = DeprecationLevel.HIDDEN)
internal fun safePropertyGet(self: dynamic, getterName: String, propName: String): dynamic {
val getter = self[getterName]
return if (getter != null) getter.call(self) else self[propName]
}
@Deprecated("This is an intrinsic for removed functionality", level = DeprecationLevel.HIDDEN)
internal fun safePropertySet(self: dynamic, setterName: String, propName: String, value: dynamic) {
val setter = self[setterName]
if (setter != null) setter.call(self, value) else self[propName] = value
}
/**
* Implements annotated function in JavaScript.
* [code] string must contain JS expression that evaluates to JS function with signature that matches annotated kotlin function
*
* For example, a function that adds two Doubles:
*
* @JsFun("(x, y) => x + y")
* fun jsAdd(x: Double, y: Double): Double =
* error("...")
*
* Code gets inserted as is without syntax verification.
*/
@Target(AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER)
internal annotation class JsFun(val code: String)
/**
* The annotation is needed for annotating class declarations and type alias which are used inside exported declarations, but
* doesn't contain @JsExport annotation
* This information is used for generating special tagged types inside d.ts files, for more strict usage of implicitly exported entities
*/
@Target(AnnotationTarget.CLASS)
internal annotation class JsImplicitExport
+395
View File
@@ -0,0 +1,395 @@
/*
* Copyright 2010-2021 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.
*/
// Copyright 2009 The Closure Library Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
package kotlin
internal fun Long.toNumber() = high * TWO_PWR_32_DBL_ + getLowBitsUnsigned()
internal fun Long.getLowBitsUnsigned() = if (low >= 0) low.toDouble() else TWO_PWR_32_DBL_ + low
internal fun hashCode(l: Long) = l.low xor l.high
internal fun Long.toStringImpl(radix: Int): String {
if (radix < 2 || 36 < radix) {
throw Exception("radix out of range: $radix")
}
if (isZero()) {
return "0"
}
if (isNegative()) {
if (equalsLong(MIN_VALUE)) {
// We need to change the Long value before it can be negated, so we remove
// the bottom-most digit in this base and then recurse to do the rest.
val radixLong = fromInt(radix)
val div = div(radixLong)
val rem = div.multiply(radixLong).subtract(this).toInt()
// Using rem.asDynamic() to break dependency on "kotlin.text" package
return div.toStringImpl(radix) + rem.asDynamic().toString(radix).unsafeCast<String>()
} else {
return "-${negate().toStringImpl(radix)}"
}
}
// Do several digits each time through the loop, so as to
// minimize the calls to the very expensive emulated div.
val digitsPerTime = when {
radix == 2 -> 31
radix <= 10 -> 9
radix <= 21 -> 7
radix <= 35 -> 6
else -> 5
}
val radixToPower = fromNumber(JsMath.pow(radix.toDouble(), digitsPerTime.toDouble()))
var rem = this
var result = ""
while (true) {
val remDiv = rem.div(radixToPower)
val intval = rem.subtract(remDiv.multiply(radixToPower)).toInt()
var digits = intval.asDynamic().toString(radix).unsafeCast<String>()
rem = remDiv
if (rem.isZero()) {
return digits + result
} else {
while (digits.length < digitsPerTime) {
digits = "0" + digits
}
result = digits + result
}
}
}
internal fun Long.negate() = unaryMinus()
internal fun Long.isZero() = high == 0 && low == 0
internal fun Long.isNegative() = high < 0
internal fun Long.isOdd() = low and 1 == 1
internal fun Long.equalsLong(other: Long) = high == other.high && low == other.low
internal fun Long.lessThan(other: Long) = compare(other) < 0
internal fun Long.lessThanOrEqual(other: Long) = compare(other) <= 0
internal fun Long.greaterThan(other: Long) = compare(other) > 0
internal fun Long.greaterThanOrEqual(other: Long) = compare(other) >= 0
internal fun Long.compare(other: Long): Int {
if (equalsLong(other)) {
return 0;
}
val thisNeg = isNegative();
val otherNeg = other.isNegative();
return when {
thisNeg && !otherNeg -> -1
!thisNeg && otherNeg -> 1
// at this point, the signs are the same, so subtraction will not overflow
subtract(other).isNegative() -> -1
else -> 1
}
}
internal fun Long.add(other: Long): Long {
// Divide each number into 4 chunks of 16 bits, and then sum the chunks.
val a48 = high ushr 16
val a32 = high and 0xFFFF
val a16 = low ushr 16
val a00 = low and 0xFFFF
val b48 = other.high ushr 16
val b32 = other.high and 0xFFFF
val b16 = other.low ushr 16
val b00 = other.low and 0xFFFF
var c48 = 0
var c32 = 0
var c16 = 0
var c00 = 0
c00 += a00 + b00
c16 += c00 ushr 16
c00 = c00 and 0xFFFF
c16 += a16 + b16
c32 += c16 ushr 16
c16 = c16 and 0xFFFF
c32 += a32 + b32
c48 += c32 ushr 16
c32 = c32 and 0xFFFF
c48 += a48 + b48
c48 = c48 and 0xFFFF
return Long((c16 shl 16) or c00, (c48 shl 16) or c32)
}
internal fun Long.subtract(other: Long) = add(other.unaryMinus())
internal fun Long.multiply(other: Long): Long {
if (isZero()) {
return ZERO
} else if (other.isZero()) {
return ZERO
}
if (equalsLong(MIN_VALUE)) {
return if (other.isOdd()) MIN_VALUE else ZERO
} else if (other.equalsLong(MIN_VALUE)) {
return if (isOdd()) MIN_VALUE else ZERO
}
if (isNegative()) {
return if (other.isNegative()) {
negate().multiply(other.negate())
} else {
negate().multiply(other).negate()
}
} else if (other.isNegative()) {
return multiply(other.negate()).negate()
}
// If both longs are small, use float multiplication
if (lessThan(TWO_PWR_24_) && other.lessThan(TWO_PWR_24_)) {
return fromNumber(toNumber() * other.toNumber())
}
// Divide each long into 4 chunks of 16 bits, and then add up 4x4 products.
// We can skip products that would overflow.
val a48 = high ushr 16
val a32 = high and 0xFFFF
val a16 = low ushr 16
val a00 = low and 0xFFFF
val b48 = other.high ushr 16
val b32 = other.high and 0xFFFF
val b16 = other.low ushr 16
val b00 = other.low and 0xFFFF
var c48 = 0
var c32 = 0
var c16 = 0
var c00 = 0
c00 += a00 * b00
c16 += c00 ushr 16
c00 = c00 and 0xFFFF
c16 += a16 * b00
c32 += c16 ushr 16
c16 = c16 and 0xFFFF
c16 += a00 * b16
c32 += c16 ushr 16
c16 = c16 and 0xFFFF
c32 += a32 * b00
c48 += c32 ushr 16
c32 = c32 and 0xFFFF
c32 += a16 * b16
c48 += c32 ushr 16
c32 = c32 and 0xFFFF
c32 += a00 * b32
c48 += c32 ushr 16
c32 = c32 and 0xFFFF
c48 += a48 * b00 + a32 * b16 + a16 * b32 + a00 * b48
c48 = c48 and 0xFFFF
return Long(c16 shl 16 or c00, c48 shl 16 or c32)
}
internal fun Long.divide(other: Long): Long {
if (other.isZero()) {
throw Exception("division by zero")
} else if (isZero()) {
return ZERO
}
if (equalsLong(MIN_VALUE)) {
if (other.equalsLong(ONE) || other.equalsLong(NEG_ONE)) {
return MIN_VALUE // recall that -MIN_VALUE == MIN_VALUE
} else if (other.equalsLong(MIN_VALUE)) {
return ONE
} else {
// At this point, we have |other| >= 2, so |this/other| < |MIN_VALUE|.
val halfThis = shiftRight(1)
val approx = halfThis.div(other).shiftLeft(1)
if (approx.equalsLong(ZERO)) {
return if (other.isNegative()) ONE else NEG_ONE
} else {
val rem = subtract(other.multiply(approx))
return approx.add(rem.div(other))
}
}
} else if (other.equalsLong(MIN_VALUE)) {
return ZERO
}
if (isNegative()) {
return if (other.isNegative()) {
negate().div(other.negate())
} else {
negate().div(other).negate()
}
} else if (other.isNegative()) {
return div(other.negate()).negate()
}
// Repeat the following until the remainder is less than other: find a
// floating-point that approximates remainder / other *from below*, add this
// into the result, and subtract it from the remainder. It is critical that
// the approximate value is less than or equal to the real value so that the
// remainder never becomes negative.
var res = ZERO
var rem = this
while (rem.greaterThanOrEqual(other)) {
// Approximate the result of division. This may be a little greater or
// smaller than the actual value.
val approxDouble = rem.toNumber() / other.toNumber()
var approx2 = JsMath.max(1.0, JsMath.floor(approxDouble))
// We will tweak the approximate result by changing it in the 48-th digit or
// the smallest non-fractional digit, whichever is larger.
val log2 = JsMath.ceil(JsMath.log(approx2) / JsMath.LN2)
val delta = if (log2 <= 48) 1.0 else JsMath.pow(2.0, log2 - 48)
// Decrease the approximation until it is smaller than the remainder. Note
// that if it is too large, the product overflows and is negative.
var approxRes = fromNumber(approx2)
var approxRem = approxRes.multiply(other)
while (approxRem.isNegative() || approxRem.greaterThan(rem)) {
approx2 -= delta
approxRes = fromNumber(approx2)
approxRem = approxRes.multiply(other)
}
// We know the answer can't be zero... and actually, zero would cause
// infinite recursion since we would make no progress.
if (approxRes.isZero()) {
approxRes = ONE
}
res = res.add(approxRes)
rem = rem.subtract(approxRem)
}
return res
}
internal fun Long.modulo(other: Long) = subtract(div(other).multiply(other))
internal fun Long.shiftLeft(numBits: Int): Long {
@Suppress("NAME_SHADOWING")
val numBits = numBits and 63
if (numBits == 0) {
return this
} else {
if (numBits < 32) {
return Long(low shl numBits, (high shl numBits) or (low ushr (32 - numBits)))
} else {
return Long(0, low shl (numBits - 32))
}
}
}
internal fun Long.shiftRight(numBits: Int): Long {
@Suppress("NAME_SHADOWING")
val numBits = numBits and 63
if (numBits == 0) {
return this
} else {
if (numBits < 32) {
return Long((low ushr numBits) or (high shl (32 - numBits)), high shr numBits)
} else {
return Long(high shr (numBits - 32), if (high >= 0) 0 else -1)
}
}
}
internal fun Long.shiftRightUnsigned(numBits: Int): Long {
@Suppress("NAME_SHADOWING")
val numBits = numBits and 63
if (numBits == 0) {
return this
} else {
if (numBits < 32) {
return Long((low ushr numBits) or (high shl (32 - numBits)), high ushr numBits)
} else return if (numBits == 32) {
Long(high, 0)
} else {
Long(high ushr (numBits - 32), 0)
}
}
}
/**
* Returns a Long representing the given (32-bit) integer value.
* @param {number} value The 32-bit integer in question.
* @return {!Kotlin.Long} The corresponding Long value.
*/
// TODO: cache
internal fun fromInt(value: Int) = Long(value, if (value < 0) -1 else 0)
/**
* Converts this [Double] value to [Long].
* The fractional part, if any, is rounded down towards zero.
* Returns zero if this `Double` value is `NaN`, [Long.MIN_VALUE] if it's less than `Long.MIN_VALUE`,
* [Long.MAX_VALUE] if it's bigger than `Long.MAX_VALUE`.
*/
internal fun fromNumber(value: Double): Long {
if (value.isNaN()) {
return ZERO;
} else if (value <= -TWO_PWR_63_DBL_) {
return MIN_VALUE;
} else if (value + 1 >= TWO_PWR_63_DBL_) {
return MAX_VALUE;
} else if (value < 0) {
return fromNumber(-value).negate();
} else {
val twoPwr32 = TWO_PWR_32_DBL_
return Long(
jsBitwiseOr(value.rem(twoPwr32), 0),
jsBitwiseOr(value / twoPwr32, 0)
)
}
}
private const val TWO_PWR_16_DBL_ = (1 shl 16).toDouble()
private const val TWO_PWR_24_DBL_ = (1 shl 24).toDouble()
//private val TWO_PWR_32_DBL_ = TWO_PWR_16_DBL_ * TWO_PWR_16_DBL_
private const val TWO_PWR_32_DBL_ = (1 shl 16).toDouble() * (1 shl 16).toDouble()
//private val TWO_PWR_64_DBL_ = TWO_PWR_32_DBL_ * TWO_PWR_32_DBL_
private const val TWO_PWR_64_DBL_ = ((1 shl 16).toDouble() * (1 shl 16).toDouble()) * ((1 shl 16).toDouble() * (1 shl 16).toDouble())
//private val TWO_PWR_63_DBL_ = TWO_PWR_64_DBL_ / 2
private const val TWO_PWR_63_DBL_ = (((1 shl 16).toDouble() * (1 shl 16).toDouble()) * ((1 shl 16).toDouble() * (1 shl 16).toDouble())) / 2
private val ZERO = fromInt(0)
private val ONE = fromInt(1)
private val NEG_ONE = fromInt(-1)
private val MAX_VALUE = Long(-1, -1 ushr 1)
private val MIN_VALUE = Long(0, 1 shl 31)
private val TWO_PWR_24_ = fromInt(1 shl 24)
+15
View File
@@ -0,0 +1,15 @@
/*
* Copyright 2010-2018 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.
*/
@file:JsQualifier("Math")
package kotlin.js
@JsPolyfill("""
if (typeof Math.imul === "undefined") {
Math.imul = function imul(a, b) {
return ((a & 0xffff0000) * (b & 0xffff) + (a & 0xffff) * (b | 0)) | 0;
}
}
""")
internal external fun imul(a_local: Int, b_local: Int): Int
@@ -0,0 +1,117 @@
/*
* 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
internal fun setMetadataFor(
ctor: Ctor,
name: String?,
metadataConstructor: (name: String?, defaultConstructor: dynamic, associatedObjectKey: Number?, associatedObjects: dynamic, suspendArity: Array<Int>?) -> Metadata,
parent: Ctor?,
interfaces: Array<dynamic>?,
defaultConstructor: dynamic,
associatedObjectKey: Number?,
associatedObjects: dynamic,
suspendArity: Array<Int>?
) {
if (parent != null) {
js("""
ctor.prototype = Object.create(parent.prototype)
ctor.prototype.constructor = ctor;
""")
}
val metadata = metadataConstructor(name, defaultConstructor, associatedObjectKey, associatedObjects, suspendArity ?: js("[]"))
ctor.`$metadata$` = metadata
if (interfaces != null) {
val receiver = if (metadata.iid != null) ctor else ctor.prototype
receiver.`$imask$` = implement(interfaces)
}
}
// There was a problem with per-module compilation (KT-55758) when the top-level state (iid) was reinitialized during stdlib module initialization
// As a result we miss already incremented iid and had the same iids 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 iid: dynamic
private fun generateInterfaceId(): Int {
if (iid === VOID) {
iid = 0
}
iid = iid.unsafeCast<Int>() + 1
return iid.unsafeCast<Int>()
}
internal fun interfaceMeta(
name: String?,
defaultConstructor: dynamic,
associatedObjectKey: Number?,
associatedObjects: dynamic,
suspendArity: Array<Int>?
): Metadata {
return createMetadata("interface", name, defaultConstructor, associatedObjectKey, associatedObjects, suspendArity, generateInterfaceId())
}
internal fun objectMeta(
name: String?,
defaultConstructor: dynamic,
associatedObjectKey: Number?,
associatedObjects: dynamic,
suspendArity: Array<Int>?
): Metadata {
return createMetadata("object", name, defaultConstructor, associatedObjectKey, associatedObjects, suspendArity, null)
}
internal fun classMeta(
name: String?,
defaultConstructor: dynamic,
associatedObjectKey: Number?,
associatedObjects: dynamic,
suspendArity: Array<Int>?
): Metadata {
return createMetadata("class", name, defaultConstructor, associatedObjectKey, associatedObjects, suspendArity, null)
}
// Seems like we need to disable this check if variables are used inside js annotation
@Suppress("UNUSED_PARAMETER", "UNUSED_VARIABLE")
private fun createMetadata(
kind: String,
name: String?,
defaultConstructor: dynamic,
associatedObjectKey: Number?,
associatedObjects: dynamic,
suspendArity: Array<Int>?,
iid: Int?
): Metadata {
val undef = VOID
return js("""({
kind: kind,
simpleName: name,
associatedObjectKey: associatedObjectKey,
associatedObjects: associatedObjects,
suspendArity: suspendArity,
${'$'}kClass$: undef,
defaultConstructor: defaultConstructor,
iid: iid
})""")
}
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>?
val iid: Int?
var `$kClass$`: dynamic
val defaultConstructor: dynamic
var errorInfo: Int? // Bits set for overridden properties: "message" => 0x1, "cause" => 0x2
}
@@ -0,0 +1,58 @@
/*
* Copyright 2010-2018 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.
*/
/** Concat regular Array's and TypedArray's into an Array.
*/
@PublishedApi
internal fun <T> arrayConcat(vararg args: T): T {
val len = args.size
val typed = js("Array(len)").unsafeCast<Array<T>>()
for (i in 0 .. (len - 1)) {
val arr = args[i]
if (arr !is Array<*>) {
typed[i] = js("[]").slice.call(arr)
} else {
typed[i] = arr
}
}
return js("[]").concat.apply(js("[]"), typed);
}
/** Concat primitive arrays. Main use: prepare vararg arguments.
*/
@PublishedApi
internal fun <T> primitiveArrayConcat(vararg args: T): T {
var size_local = 0
for (i in 0 .. (args.size - 1)) {
size_local += args[i].unsafeCast<Array<Any?>>().size
}
val a = args[0]
val result = js("new a.constructor(size_local)").unsafeCast<Array<Any?>>()
if (a.asDynamic().`$type$` != null) {
withType(a.asDynamic().`$type$`, result)
}
size_local = 0
for (i in 0 .. (args.size - 1)) {
val arr = args[i].unsafeCast<Array<Any?>>()
for (j in 0 .. (arr.size - 1)) {
result[size_local++] = arr[j]
}
}
return result.unsafeCast<T>()
}
internal fun <T> taggedArrayCopy(array: dynamic): T {
val res = array.slice()
res.`$type$` = array.`$type$`
return res.unsafeCast<T>()
}
@PublishedApi
@Suppress("NOTHING_TO_INLINE")
internal inline fun withType(type: String, array: dynamic): dynamic {
array.`$type$` = type
return array
}
@@ -0,0 +1,30 @@
/*
* Copyright 2010-2021 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
internal fun numberToByte(a: dynamic): Byte = toByte(numberToInt(a))
internal fun numberToDouble(@Suppress("UNUSED_PARAMETER") a: dynamic): Double = js("+a").unsafeCast<Double>()
internal fun numberToInt(a: dynamic): Int = if (a is Long) a.toInt() else doubleToInt(a)
internal fun numberToShort(a: dynamic): Short = toShort(numberToInt(a))
// << and >> shifts are used to preserve sign of the number
internal fun toByte(@Suppress("UNUSED_PARAMETER") a: dynamic): Byte = js("a << 24 >> 24").unsafeCast<Byte>()
internal fun toShort(@Suppress("UNUSED_PARAMETER") a: dynamic): Short = js("a << 16 >> 16").unsafeCast<Short>()
internal fun numberToLong(a: dynamic): Long = if (a is Long) a else fromNumber(a)
internal fun toLong(a: dynamic): Long = fromInt(a)
internal fun doubleToInt(a: Double): Int = when {
a > 2147483647 -> 2147483647
a < -2147483648 -> -2147483648
else -> jsBitwiseOr(a, 0)
}
internal fun numberToChar(a: dynamic) = Char(numberToInt(a).toUShort())
+15
View File
@@ -0,0 +1,15 @@
/*
* Copyright 2010-2018 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
// Creates IntRange for {Byte, Short, Int}.rangeTo(x: {Byte, Short, Int})
internal fun numberRangeToNumber(start: dynamic, endInclusive: dynamic) =
IntRange(start, endInclusive)
// Create LongRange for {Byte, Short, Int}.rangeTo(x: Long)
// Long.rangeTo(x: *) should be implemented in Long class
internal fun numberRangeToLong(start: dynamic, endInclusive: dynamic) =
LongRange(numberToLong(start), endInclusive)
@@ -0,0 +1,56 @@
/*
* Copyright 2010-2020 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.reflect.KProperty
internal fun getPropertyCallableRef(
name: String,
paramCount: Int,
superType: dynamic,
getter: dynamic,
setter: dynamic
): KProperty<*> {
getter.get = getter
getter.set = setter
getter.callableName = name
return getPropertyRefClass(
getter,
getKPropMetadata(paramCount, setter),
getInterfaceMaskFor(getter, superType)
).unsafeCast<KProperty<*>>()
}
internal fun getLocalDelegateReference(name: String, superType: dynamic, mutable: Boolean, lambda: dynamic): KProperty<*> {
return getPropertyCallableRef(name, 0, superType, lambda, if (mutable) lambda else null)
}
private fun getPropertyRefClass(obj: Ctor, metadata: Metadata, imask: BitMask): dynamic {
obj.`$metadata$` = metadata
obj.constructor = obj
obj.`$imask$` = imask
return obj;
}
private fun getInterfaceMaskFor(obj: Ctor, superType: dynamic): BitMask =
obj.`$imask$` ?: implement(arrayOf(superType))
@Suppress("UNUSED_PARAMETER")
private fun getKPropMetadata(paramCount: Int, setter: Any?): dynamic {
return propertyRefClassMetadataCache[paramCount][if (setter == null) 0 else 1]
}
private fun metadataObject(): Metadata {
return classMeta(VOID, VOID, VOID, VOID, VOID)
}
private val propertyRefClassMetadataCache: Array<Array<dynamic>> = arrayOf<Array<dynamic>>(
// immutable , mutable
arrayOf<dynamic>(metadataObject(), metadataObject()), // 0
arrayOf<dynamic>(metadataObject(), metadataObject()), // 1
arrayOf<dynamic>(metadataObject(), metadataObject()) // 2
)
@@ -0,0 +1,26 @@
/*
* Copyright 2010-2022 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
// Inlined intrinsics for backward compatibility with already implemented functions in stdlib for old JS backend
@OptIn(JsIntrinsic::class)
@kotlin.internal.InlineOnly
internal inline fun jsDeleteProperty(obj: dynamic, property: Any) = jsDelete(obj[property])
@OptIn(JsIntrinsic::class)
@kotlin.internal.InlineOnly
internal inline fun jsBitwiseOr(lhs: Any?, rhs: Any?): Int = jsBitOr(lhs, rhs)
@OptIn(JsIntrinsic::class)
@kotlin.internal.InlineOnly
internal inline fun jsBitwiseAnd(lhs: Any?, rhs: Any?): Int = jsBitAnd(lhs, rhs)
@OptIn(JsIntrinsic::class)
@kotlin.internal.InlineOnly
internal inline fun jsInstanceOf(obj: Any?, jsClass: Any?): Boolean = jsInstanceOfIntrinsic(obj, jsClass)
@OptIn(JsIntrinsic::class)
@kotlin.internal.InlineOnly
internal inline fun jsIn(lhs: Any?, rhs: Any): Boolean = jsInIntrinsic(lhs, rhs)
@@ -0,0 +1,144 @@
/*
* Copyright 2010-2018 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
internal external interface Ctor {
var `$imask$`: BitMask?
var `$metadata$`: Metadata
var constructor: Ctor?
val prototype: dynamic
}
private fun hasProp(proto: dynamic, propName: String): Boolean = proto.hasOwnProperty(propName)
internal fun calculateErrorInfo(proto: dynamic): Int {
val metadata: Metadata? = proto.constructor?.`$metadata$`
metadata?.errorInfo?.let { return it } // cached
var result = 0
if (hasProp(proto, "message")) result = result or 0x1
if (hasProp(proto, "cause")) result = result or 0x2
if (result != 0x3) { //
val parentProto = getPrototypeOf(proto)
if (parentProto != js("Error").prototype) {
result = result or calculateErrorInfo(parentProto)
}
}
if (metadata != null) {
metadata.errorInfo = result
}
return result
}
private fun getPrototypeOf(obj: dynamic) = JsObject.getPrototypeOf(obj)
private fun isInterfaceImpl(obj: dynamic, iface: Int): Boolean {
val mask: BitMask = obj.`$imask$`.unsafeCast<BitMask?>() ?: return false
return mask.isBitSet(iface)
}
internal fun isInterface(obj: dynamic, iface: dynamic): Boolean {
return isInterfaceImpl(obj, iface.`$metadata$`.iid)
}
internal fun isSuspendFunction(obj: dynamic, arity: Int): Boolean {
val objTypeOf = jsTypeOf(obj)
if (objTypeOf == "function") {
@Suppress("DEPRECATED_IDENTITY_EQUALS")
return obj.`$arity`.unsafeCast<Int>() === arity
}
val suspendArity = obj?.constructor.unsafeCast<Ctor?>()?.`$metadata$`?.suspendArity ?: return false
@Suppress("IMPLICIT_BOXING_IN_IDENTITY_EQUALS")
var result = false
for (item in suspendArity) {
if (arity == item) {
result = true
break
}
}
return result
}
private fun isJsArray(obj: Any): Boolean {
return js("Array").isArray(obj).unsafeCast<Boolean>()
}
internal fun isArray(obj: Any): Boolean {
return isJsArray(obj) && !(obj.asDynamic().`$type$`)
}
// TODO: Remove after the next bootstrap
internal fun isObject(o: dynamic): Boolean = o != null
internal fun isArrayish(o: dynamic) = isJsArray(o) || arrayBufferIsView(o)
internal fun isChar(@Suppress("UNUSED_PARAMETER") c: Any): Boolean {
error("isChar is not implemented")
}
// TODO: Distinguish Boolean/Byte and Short/Char
internal fun isBooleanArray(a: dynamic): Boolean = isJsArray(a) && a.`$type$` === "BooleanArray"
internal fun isByteArray(a: dynamic): Boolean = jsInstanceOf(a, js("Int8Array"))
internal fun isShortArray(a: dynamic): Boolean = jsInstanceOf(a, js("Int16Array"))
internal fun isCharArray(a: dynamic): Boolean = jsInstanceOf(a, js("Uint16Array")) && a.`$type$` === "CharArray"
internal fun isIntArray(a: dynamic): Boolean = jsInstanceOf(a, js("Int32Array"))
internal fun isFloatArray(a: dynamic): Boolean = jsInstanceOf(a, js("Float32Array"))
internal fun isDoubleArray(a: dynamic): Boolean = jsInstanceOf(a, js("Float64Array"))
internal fun isLongArray(a: dynamic): Boolean = isJsArray(a) && a.`$type$` === "LongArray"
internal fun jsGetPrototypeOf(jsClass: dynamic) = js("Object").getPrototypeOf(jsClass)
internal fun jsIsType(obj: dynamic, jsClass: dynamic): Boolean {
if (jsClass === js("Object")) {
return obj != null
}
val objType = jsTypeOf(obj)
val jsClassType = jsTypeOf(jsClass)
if (obj == null || jsClass == null || (objType != "object" && objType != "function")) {
return false
}
// In WebKit (JavaScriptCore) for some interfaces from DOM typeof returns "object", nevertheless they can be used in RHS of instanceof
val constructor = if (jsClassType == "object") jsGetPrototypeOf(jsClass) else jsClass
val klassMetadata = constructor.`$metadata$`
if (klassMetadata?.kind === "interface") {
val iid = klassMetadata.iid.unsafeCast<Int?>() ?: return false
return isInterfaceImpl(obj, iid)
}
return jsInstanceOf(obj, constructor)
}
internal fun isNumber(a: dynamic) = jsTypeOf(a) == "number" || a is Long
@OptIn(JsIntrinsic::class)
internal fun isComparable(value: dynamic): Boolean {
val type = jsTypeOf(value)
return type == "string" ||
type == "boolean" ||
isNumber(value) ||
isInterface(value, jsClassIntrinsic<Comparable<*>>())
}
@OptIn(JsIntrinsic::class)
internal fun isCharSequence(value: dynamic): Boolean =
jsTypeOf(value) == "string" || isInterface(value, jsClassIntrinsic<CharSequence>())
@OptIn(JsIntrinsic::class)
internal fun isExternalObject(value: dynamic, ktExternalObject: dynamic) =
jsEqeqeq(value, ktExternalObject) || (jsTypeOf(ktExternalObject) == "function" && jsInstanceOf(value, ktExternalObject))
+12
View File
@@ -0,0 +1,12 @@
/*
* Copyright 2010-2021 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
internal class IrLinkageError(message: String?) : Error(message)
internal fun throwLinkageError(message: String?): Nothing {
throw IrLinkageError(message)
}
+7
View File
@@ -0,0 +1,7 @@
/*
* Copyright 2010-2022 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
internal val VOID: Nothing? = js("void 0")