diff --git a/libraries/stdlib/js-ir/builtins/Char.kt b/libraries/stdlib/js-ir/builtins/Char.kt index 5c6e1efbe65..135d82b29ca 100644 --- a/libraries/stdlib/js-ir/builtins/Char.kt +++ b/libraries/stdlib/js-ir/builtins/Char.kt @@ -51,8 +51,7 @@ public inline class Char internal constructor (val value: Int) : Comparable() + return js("String").fromCharCode(value).unsafeCast() } companion object { diff --git a/libraries/stdlib/js-ir/runtime/collectionsHacks.kt b/libraries/stdlib/js-ir/runtime/collectionsHacks.kt index 925bea018e5..a79c2c28032 100644 --- a/libraries/stdlib/js-ir/runtime/collectionsHacks.kt +++ b/libraries/stdlib/js-ir/runtime/collectionsHacks.kt @@ -7,13 +7,6 @@ package kotlin.collections import kotlin.js.* -// Copied from libraries/stdlib/js/src/kotlin/collections/utils.kt -// Current inliner doesn't rename symbols inside `js` fun -@Suppress("UNUSED_PARAMETER") -internal fun deleteProperty(obj: Any, property: Any) { - js("delete obj[property]") -} - internal fun arrayToString(array: Array<*>) = array.joinToString(", ", "[", "]") { toString(it) } internal fun Array.contentDeepHashCodeInternal(): Int { diff --git a/libraries/stdlib/js-ir/runtime/compareTo.kt b/libraries/stdlib/js-ir/runtime/compareTo.kt index d40d928a843..dc1e1f53f08 100644 --- a/libraries/stdlib/js-ir/runtime/compareTo.kt +++ b/libraries/stdlib/js-ir/runtime/compareTo.kt @@ -8,9 +8,9 @@ package kotlin.js // Adopted from misc.js -fun compareTo(a: dynamic, b: dynamic): Int = when (typeOf(a)) { +fun compareTo(a: dynamic, b: dynamic): Int = when (jsTypeOf(a)) { "number" -> when { - typeOf(b) == "number" -> + jsTypeOf(b) == "number" -> doubleCompareTo(a, b) b is Long -> doubleCompareTo(a, b.toDouble()) @@ -28,19 +28,34 @@ private fun > compareToDoNotIntrinsicify(a: Comparable, b: a.compareTo(b) fun primitiveCompareTo(a: dynamic, b: dynamic): Int = - js("a < b ? -1 : a > b ? 1 : 0").unsafeCast() - -fun doubleCompareTo(a: dynamic, b: dynamic): Int = - js(""" - if (a < b) return -1; - if (a > b) return 1; - - if (a === b) { - if (a !== 0) return 0; - - var ia = 1 / a; - return ia === 1 / b ? 0 : (ia < 0 ? -1 : 1); + when { + a < b -> -1 + a > b -> 1 + else -> 0 } - return a !== a ? (b !== b ? 0 : 1) : -1 - """).unsafeCast() \ No newline at end of file +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 + } \ No newline at end of file diff --git a/libraries/stdlib/js-ir/runtime/core.kt b/libraries/stdlib/js-ir/runtime/core.kt index 38bceccbde0..e8c5e430e6a 100644 --- a/libraries/stdlib/js-ir/runtime/core.kt +++ b/libraries/stdlib/js-ir/runtime/core.kt @@ -13,36 +13,35 @@ fun equals(obj1: dynamic, obj2: dynamic): Boolean { return false } - return js(""" - if (typeof obj1 === "object" && typeof obj1.equals === "function") { - return obj1.equals(obj2); + if (jsTypeOf(obj1) == "object" && jsTypeOf(obj1.equals) == "function") { + return (obj1.equals)(obj2) } if (obj1 !== obj1) { - return obj2 !== obj2; + return obj2 !== obj2 } - if (typeof obj1 === "number" && typeof obj2 === "number") { - return obj1 === obj2 && (obj1 !== 0 || 1 / obj1 === 1 / obj2) + if (jsTypeOf(obj1) == "number" && jsTypeOf(obj2) == "number") { + return obj1 === obj2 && (obj1 !== 0 || 1.asDynamic() / obj1 === 1.asDynamic() / obj2) } - return obj1 === obj2; - """).unsafeCast() + return obj1 === obj2 } fun toString(o: dynamic): String = when { - js("o == null").unsafeCast() -> "null" + o == null -> "null" isArrayish(o) -> "[...]" - else -> js("o.toString()").unsafeCast() + + else -> (o.toString)().unsafeCast() } -fun anyToString(o: dynamic): String = js("Object.prototype.toString.call(o)") +fun anyToString(o: dynamic): String = js("Object").prototype.toString.call(o) fun hashCode(obj: dynamic): Int { if (obj == null) return 0 - return when (typeOf(obj)) { - "object" -> if ("function" === js("typeof obj.hashCode")) js("obj.hashCode()") else getObjectHashCode(obj) + return when (jsTypeOf(obj)) { + "object" -> if ("function" === jsTypeOf(obj.hashCode)) (obj.hashCode)() else getObjectHashCode(obj) "function" -> getObjectHashCode(obj) "number" -> getNumberHashCode(obj) "boolean" -> if(obj.unsafeCast()) 1 else 0 @@ -50,42 +49,47 @@ fun hashCode(obj: dynamic): Int { } } -fun getObjectHashCode(obj: dynamic) = js(""" - var POW_2_32 = 4294967296; - var OBJECT_HASH_CODE_PROPERTY_NAME = "kotlinHashCodeValue${"$"}"; +private var POW_2_32 = 4294967296 +private var OBJECT_HASH_CODE_PROPERTY_NAME = "kotlinHashCodeValue$" - if (!(OBJECT_HASH_CODE_PROPERTY_NAME in obj)) { - var hash = (Math.random() * POW_2_32) | 0; // Make 32-bit singed integer. - Object.defineProperty(obj, OBJECT_HASH_CODE_PROPERTY_NAME, { value: hash, enumerable: false }); +fun getObjectHashCode(obj: dynamic): Int { + if (!jsIn(OBJECT_HASH_CODE_PROPERTY_NAME, obj)) { + var hash = jsBitwiseOr(js("Math").random() * POW_2_32, 0) // Make 32-bit singed integer. + 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(); + return obj[OBJECT_HASH_CODE_PROPERTY_NAME].unsafeCast(); +} fun getStringHashCode(str: String): Int { var hash = 0 - val length: Int = js("str.length") // TODO: Implement WString.length + val length: Int = str.length // TODO: Implement WString.length for (i in 0..length-1) { - val code: Int = js("str.charCodeAt(i)") + val code: Int = str.asDynamic().charCodeAt(i) hash = hash * 31 + code } return hash } -fun getNumberHashCode(obj: dynamic) = js(""" - if ((obj | 0) === obj) { - return obj | 0; - } - else { - var byteBuffer = new ArrayBuffer (8); - var bufFloat64 = new Float64Array (byteBuffer); - var bufInt32 = new Int32Array (byteBuffer); +private external class ArrayBuffer(size: Int) +private external class Float64Array(buffer: ArrayBuffer) +private external class Int32Array(buffer: ArrayBuffer) - bufFloat64[0] = obj; - return (bufInt32[1] * 31 | 0)+bufInt32[0] | 0; +fun getNumberHashCode(obj: Any?): Int { + if (jsBitwiseOr(obj, 0) === obj) { + return obj } -""").unsafeCast() -fun identityHashCode(obj: dynamic): Int = getObjectHashCode(obj) + var byteBuffer = ArrayBuffer(8) + var bufFloat64 = Float64Array(byteBuffer).asDynamic() + var bufInt32 = Int32Array(byteBuffer).asDynamic() + bufFloat64[0] = obj + return jsBitwiseOr(bufInt32[1] * 31, 0) + bufInt32[0].unsafeCast() +} + +fun identityHashCode(obj: Any?): Int = getObjectHashCode(obj) @JsName("captureStack") @@ -101,7 +105,7 @@ internal fun captureStack(instance: Throwable) { internal fun newThrowable(message: String?, cause: Throwable?): Throwable { val throwable = js("new Error()") throwable.message = if (message == null) { - if (cause != null) js("cause.toString()") else null + if (cause != null) (cause.asDynamic().toString)() else null } else { message } diff --git a/libraries/stdlib/js-ir/runtime/longjs.kt b/libraries/stdlib/js-ir/runtime/longjs.kt index cb776e3b0f1..1d24d674b46 100644 --- a/libraries/stdlib/js-ir/runtime/longjs.kt +++ b/libraries/stdlib/js-ir/runtime/longjs.kt @@ -48,20 +48,20 @@ internal fun Long.toString(radix: Int): String { // Do several (6) digits each time through the loop, so as to // minimize the calls to the very expensive emulated div. - val radixToPower = fromNumber(js("Math.pow(radix, 6)").unsafeCast()) + val radixToPower = fromNumber(JsMath.pow(radix.toDouble(), 6.0)) var rem = this var result = "" while (true) { val remDiv = rem.div(radixToPower) val intval = rem.subtract(remDiv.multiply(radixToPower)).toInt() - var digits = js("intval.toString(radix)").unsafeCast() + var digits = intval.asDynamic().toString(radix).unsafeCast() rem = remDiv if (rem.isZero()) { return digits + result } else { - while (js("digits.length").unsafeCast() < 6) { + while (digits.length < 6) { digits = "0" + digits } result = digits + result @@ -253,15 +253,12 @@ internal fun Long.divide(other: Long): Long { // 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 = js("Math.max(1, Math.floor(approxDouble))").unsafeCast() + 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 = js("Math.ceil(Math.log(approx2) / Math.LN2)").unsafeCast() - - // TODO: log2 is renamed but usage in js() functions is not - val log2_minus48 = log2 - 48 - val delta = if (log2 <= 48) 1.0 else js("Math.pow(2, log2_minus48)").unsafeCast() + val log2 = JsMath.ceil(JsMath.log(approx2) / JsMath.LN2) + val delta = if (log2 <= 48) 1.0 else JsMath.pow(2, 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. @@ -343,7 +340,7 @@ internal fun fromInt(value: Int) = Long(value, if (value < 0) -1 else 0) * @return {!Kotlin.Long} The corresponding Long value. */ internal fun fromNumber(value: Double): Long { - if (js("isNaN(value)").unsafeCast() || !js("isFinite(value)").unsafeCast()) { + if (value.isNaN() || !value.isFinite()) { return ZERO; } else if (value <= -TWO_PWR_63_DBL_) { return MIN_VALUE; @@ -354,8 +351,8 @@ internal fun fromNumber(value: Double): Long { } else { val twoPwr32 = TWO_PWR_32_DBL_ return Long( - js("(value % twoPwr32) | 0").unsafeCast(), - js("(value / twoPwr32) | 0").unsafeCast() + jsBitwiseOr(value.rem(twoPwr32), 0), + jsBitwiseOr(value / twoPwr32, 0) ) } } @@ -384,3 +381,14 @@ 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) + +@JsName("Math") +external object JsMath { + fun max(lhs: Number, rhs: Number): Double + fun floor(x: Number): Double + fun ceil(x: Number): Double + fun log(x: Number): Double + fun pow(base: Number, exponent: Number): Double + val LN2: Double +} + diff --git a/libraries/stdlib/js-ir/runtime/misc.kt b/libraries/stdlib/js-ir/runtime/misc.kt index 9d4692e23a6..3eb9122d156 100644 --- a/libraries/stdlib/js-ir/runtime/misc.kt +++ b/libraries/stdlib/js-ir/runtime/misc.kt @@ -1,10 +1,13 @@ /* - * 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. + * 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. */ package kotlin.js // TODO: Polyfill -internal fun imul(a_local: Int, b_local: Int) = - js("((a_local & 0xffff0000) * (b_local & 0xffff) + (a_local & 0xffff) * (b_local | 0)) | 0").unsafeCast() \ No newline at end of file +internal fun imul(a_local: Int, b_local: Int): Int { + val lhs = jsBitwiseAnd(a_local, js("0xffff0000")).toDouble() * jsBitwiseAnd(b_local, 0xffff).toDouble() + val rhs = jsBitwiseAnd(a_local, 0xffff).toDouble() * b_local.toDouble() + return jsBitwiseOr(lhs + rhs, 0) +} diff --git a/libraries/stdlib/js-ir/runtime/numberConversion.kt b/libraries/stdlib/js-ir/runtime/numberConversion.kt index 4103a02b484..70ee5076da7 100644 --- a/libraries/stdlib/js-ir/runtime/numberConversion.kt +++ b/libraries/stdlib/js-ir/runtime/numberConversion.kt @@ -21,10 +21,10 @@ fun numberToLong(a: dynamic): Long = if (a is Long) a else fromNumber(a) fun toLong(a: dynamic): Long = fromInt(a) -fun doubleToInt(a: dynamic) = js(""" - if (a > 2147483647) return 2147483647; - if (a < -2147483648) return -2147483648; - return a | 0; -""").unsafeCast() +fun doubleToInt(a: Double): Int = when { + a > 2147483647 -> 2147483647 + a < -2147483648 -> -2147483648 + else -> jsBitwiseOr(a, 0) +} fun numberToChar(a: dynamic) = Char(numberToInt(a) and 0xFFFF) \ No newline at end of file diff --git a/libraries/stdlib/js-ir/runtime/typeCheckUtils.kt b/libraries/stdlib/js-ir/runtime/typeCheckUtils.kt index 2d09282d2e5..f1708583a74 100644 --- a/libraries/stdlib/js-ir/runtime/typeCheckUtils.kt +++ b/libraries/stdlib/js-ir/runtime/typeCheckUtils.kt @@ -33,8 +33,7 @@ private fun isInterfaceImpl(ctor: Ctor, iface: dynamic): Boolean { } public fun isInterface(obj: dynamic, iface: dynamic): Boolean { - //TODO: val ctor = obj.constructor - val ctor = js("obj.constructor") + val ctor = obj.constructor if (ctor == null) return false @@ -76,52 +75,46 @@ public fun isInterface(ctor: dynamic, IType: dynamic): Boolean { } */ -fun typeOf(obj: dynamic): String = js("typeof obj").unsafeCast() - -fun jsTypeOf(obj: Any?): String = js("typeof obj").unsafeCast() - -fun instanceOf(obj: dynamic, jsClass_local: dynamic) = js("obj instanceof jsClass_local").unsafeCast() fun isObject(obj: dynamic): Boolean { - val objTypeOf = typeOf(obj) + val objTypeOf = jsTypeOf(obj) return when (objTypeOf) { "string" -> true "number" -> true "boolean" -> true "function" -> true - else -> js("obj instanceof Object").unsafeCast() + else -> jsInstanceOf(obj, js("Object")) } } private fun isJsArray(obj: Any): Boolean { - return js("Array.isArray(obj)").unsafeCast() + return js("Array").isArray(obj).unsafeCast() } public fun isArray(obj: Any): Boolean { - return isJsArray(obj) && js("!obj.\$type\$").unsafeCast() + return isJsArray(obj) && !(obj.asDynamic().`$type$`) } public fun isArrayish(o: dynamic) = - isJsArray(o) || js("ArrayBuffer.isView(o)").unsafeCast() + isJsArray(o) || js("ArrayBuffer").isView(o).unsafeCast() public fun isChar(c: Any): Boolean { - return js("throw Error(\"isChar is not implemented\")").unsafeCast() + error("isChar is not implemented") } // TODO: Distinguish Boolean/Byte and Short/Char public fun isBooleanArray(a: dynamic): Boolean = isJsArray(a) && a.`$type$` === "BooleanArray" -public fun isByteArray(a: dynamic): Boolean = js("a instanceof Int8Array").unsafeCast() -public fun isShortArray(a: dynamic): Boolean = js("a instanceof Int16Array").unsafeCast() +public fun isByteArray(a: dynamic): Boolean = jsInstanceOf(a, js("Int8Array")) +public fun isShortArray(a: dynamic): Boolean = jsInstanceOf(a, js("Int16Array")) public fun isCharArray(a: dynamic): Boolean = isJsArray(a) && a.`$type$` === "CharArray" -public fun isIntArray(a: dynamic): Boolean = js("a instanceof Int32Array").unsafeCast() -public fun isFloatArray(a: dynamic): Boolean = js("a instanceof Float32Array").unsafeCast() -public fun isDoubleArray(a: dynamic): Boolean = js("a instanceof Float64Array").unsafeCast() +public fun isIntArray(a: dynamic): Boolean = jsInstanceOf(a, js("Int32Array")) +public fun isFloatArray(a: dynamic): Boolean = jsInstanceOf(a, js("Float32Array")) +public fun isDoubleArray(a: dynamic): Boolean = jsInstanceOf(a, js("Float64Array")) public fun isLongArray(a: dynamic): Boolean = isJsArray(a) && a.`$type$` === "LongArray" -internal fun jsIn(x: String, y: dynamic): Boolean = js("x in y") internal fun jsGetPrototypeOf(jsClass: dynamic) = js("Object").getPrototypeOf(jsClass) public fun jsIsType(obj: dynamic, jsClass: dynamic): Boolean { @@ -129,11 +122,11 @@ public fun jsIsType(obj: dynamic, jsClass: dynamic): Boolean { return isObject(obj) } - if (obj == null || jsClass == null || (typeOf(obj) != "object" && typeOf(obj) != "function")) { + if (obj == null || jsClass == null || (jsTypeOf(obj) != "object" && jsTypeOf(obj) != "function")) { return false } - if (typeOf(jsClass) == "function" && instanceOf(obj, jsClass)) { + if (jsTypeOf(jsClass) == "function" && jsInstanceOf(obj, jsClass)) { return true } @@ -150,7 +143,7 @@ public fun jsIsType(obj: dynamic, jsClass: dynamic): Boolean { // In WebKit (JavaScriptCore) for some interfaces from DOM typeof returns "object", nevertheless they can be used in RHS of instanceof if (klassMetadata == null) { - return instanceOf(obj, jsClass) + return jsInstanceOf(obj, jsClass) } if (klassMetadata.kind === "interface" && obj.constructor != null) { diff --git a/libraries/stdlib/js-ir/src/kotlin/jsOperators.kt b/libraries/stdlib/js-ir/src/kotlin/jsOperators.kt new file mode 100644 index 00000000000..a97d5e9f464 --- /dev/null +++ b/libraries/stdlib/js-ir/src/kotlin/jsOperators.kt @@ -0,0 +1,35 @@ +/* + * Copyright 2010-2019 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:Suppress("UNUSED_PARAMETER") + +package kotlin.js + +// Parameters are suffixed with `_hack` as a workaround for Namer. +// TODO: Implemet as compiler intrinsics + +/** + * Function corresponding to JavaScript's `typeof` operator + */ +public fun jsTypeOf(value_hack: Any?): String = + js("typeof value_hack").unsafeCast() + +internal fun jsDeleteProperty(obj_hack: Any, property_hack: Any) { + js("delete obj_hack[property_hack]") +} + +internal fun jsBitwiseOr(lhs_hack: Any?, rhs_hack: Any?): Int = + js("lhs_hack | rhs_hack").unsafeCast() + +internal fun jsBitwiseAnd(lhs_hack: Any?, rhs_hack: Any?): Int = + js("lhs_hack & rhs_hack").unsafeCast() + +internal fun jsInstanceOf(obj_hack: Any?, jsClass_hack: Any?): Boolean = + js("obj_hack instanceof jsClass_hack").unsafeCast() + +// Returns true if the specified property is in the specified object or its prototype chain. +internal fun jsIn(lhs_hack: Any?, rhs_hack: Any): Boolean = + js("lhs_hack in rhs_hack").unsafeCast() + diff --git a/libraries/stdlib/js-v1/src/kotlin/collections/utils.kt b/libraries/stdlib/js-v1/src/kotlin/collections/utils.kt deleted file mode 100644 index c29c40c159a..00000000000 --- a/libraries/stdlib/js-v1/src/kotlin/collections/utils.kt +++ /dev/null @@ -1,12 +0,0 @@ -/* - * 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 - -@kotlin.internal.InlineOnly -@Suppress("UNUSED_PARAMETER") -internal inline fun deleteProperty(obj: Any, property: Any) { - js("delete obj[property]") -} diff --git a/libraries/stdlib/js-v1/src/kotlin/jsOperators.kt b/libraries/stdlib/js-v1/src/kotlin/jsOperators.kt new file mode 100644 index 00000000000..2c9c4adb780 --- /dev/null +++ b/libraries/stdlib/js-v1/src/kotlin/jsOperators.kt @@ -0,0 +1,18 @@ +/* + * Copyright 2010-2019 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:Suppress("UNUSED_PARAMETER") + +package kotlin.js + +@kotlin.internal.InlineOnly +internal inline fun jsDeleteProperty(obj: Any, property: Any) { + js("delete obj[property]") +} + +@kotlin.internal.InlineOnly +internal inline fun jsBitwiseOr(lhs: Any?, rhs: Any?): Int = + js("lhs | rhs").unsafeCast() \ No newline at end of file diff --git a/libraries/stdlib/js/src/kotlin/collections/InternalHashCodeMap.kt b/libraries/stdlib/js/src/kotlin/collections/InternalHashCodeMap.kt index 8e778030365..f94c7ea8284 100644 --- a/libraries/stdlib/js/src/kotlin/collections/InternalHashCodeMap.kt +++ b/libraries/stdlib/js/src/kotlin/collections/InternalHashCodeMap.kt @@ -68,7 +68,7 @@ internal class InternalHashCodeMap(override val equality: EqualityComparat if (chainOrEntry !is Array<*>) { val entry: MutableEntry = chainOrEntry if (equality.equals(entry.key, key)) { - deleteProperty(backingMap, hashCode) + jsDeleteProperty(backingMap, hashCode) size-- return entry.value } else { @@ -82,7 +82,7 @@ internal class InternalHashCodeMap(override val equality: EqualityComparat if (chain.size == 1) { chain.asDynamic().length = 0 // remove the whole array - deleteProperty(backingMap, hashCode) + jsDeleteProperty(backingMap, hashCode) } else { // splice out the entry we're removing chain.asDynamic().splice(index, 1) diff --git a/libraries/stdlib/js/src/kotlin/collections/InternalMap.kt b/libraries/stdlib/js/src/kotlin/collections/InternalMap.kt index ea505320578..6c92894b3cc 100644 --- a/libraries/stdlib/js/src/kotlin/collections/InternalMap.kt +++ b/libraries/stdlib/js/src/kotlin/collections/InternalMap.kt @@ -19,11 +19,10 @@ internal interface InternalMap : MutableIterable(override val equality: EqualityComparator if (key !is String) return null val value = backingMap[key] if (value !== undefined) { - deleteProperty(backingMap, key) + jsDeleteProperty(backingMap, key) size-- // structureChanged(host) return value.unsafeCast() diff --git a/libraries/stdlib/js/src/kotlin/reflect/reflection.kt b/libraries/stdlib/js/src/kotlin/reflect/reflection.kt index 30c29b96643..df5d548d4a2 100644 --- a/libraries/stdlib/js/src/kotlin/reflect/reflection.kt +++ b/libraries/stdlib/js/src/kotlin/reflect/reflection.kt @@ -15,7 +15,7 @@ internal fun getKClass(jClass: JsClass): KClass = getOrCreateKCl internal fun getKClassFromExpression(e: T): KClass = when (jsTypeOf(e)) { "string" -> PrimitiveClasses.stringClass - "number" -> if (js("e | 0") === e) PrimitiveClasses.intClass else PrimitiveClasses.doubleClass + "number" -> if (jsBitwiseOr(e, 0).asDynamic() === e) PrimitiveClasses.intClass else PrimitiveClasses.doubleClass "boolean" -> PrimitiveClasses.booleanClass "function" -> PrimitiveClasses.functionClass(e.asDynamic().length) else -> {