From 9ad5910de9f4b5a0a2340d8b538a8741fc367da3 Mon Sep 17 00:00:00 2001 From: Artem Kobzar Date: Mon, 3 Jul 2023 13:19:43 +0000 Subject: [PATCH] [K/JS] Remove isObject check from runtime ^KT-57926 Fixed --- .../kotlin/ir/backend/js/JsIntrinsics.kt | 1 - .../backend/js/lower/TypeOperatorLowering.kt | 6 +- .../js/test/fir/FirJsBoxTestGenerated.java | 6 + .../js/test/ir/IrBoxJsES6TestGenerated.java | 6 + .../js/test/ir/IrBoxJsTestGenerated.java | 6 + .../testData/box/builtins/toString.kt | 7 + .../testData/box/char/charEquals.kt | 2 +- .../testData/box/dynamic/hashCode.kt | 172 ++++++++++++++++++ .../testData/box/standardClasses/any.kt | 9 +- libraries/stdlib/js-ir/runtime/coreRuntime.kt | 78 +++++++- .../stdlib/js-ir/runtime/typeCheckUtils.kt | 17 +- 11 files changed, 280 insertions(+), 30 deletions(-) create mode 100644 js/js.translator/testData/box/dynamic/hashCode.kt diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsIntrinsics.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsIntrinsics.kt index 99474073389..aefdc87f627 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsIntrinsics.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsIntrinsics.kt @@ -117,7 +117,6 @@ class JsIntrinsics(private val irBuiltIns: IrBuiltIns, val context: JsIrBackendC val isInterfaceSymbol = getInternalFunction("isInterface") val isArraySymbol = getInternalFunction("isArray") // val isCharSymbol = getInternalFunction("isChar") - val isObjectSymbol = getInternalFunction("isObject") val isSuspendFunctionSymbol = getInternalFunction("isSuspendFunction") val isNumberSymbol = getInternalFunction("isNumber") diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/TypeOperatorLowering.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/TypeOperatorLowering.kt index ede22505224..a5fa08b3c66 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/TypeOperatorLowering.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/TypeOperatorLowering.kt @@ -44,13 +44,13 @@ class TypeOperatorLowering(val context: JsIrBackendContext) : BodyLoweringPass { private val throwNPE = context.ir.symbols.throwNullPointerException private val eqeq = context.irBuiltIns.eqeqSymbol + private val booleanNot = context.irBuiltIns.booleanNotSymbol private val isInterfaceSymbol get() = context.intrinsics.isInterfaceSymbol private val isArraySymbol get() = context.intrinsics.isArraySymbol private val isSuspendFunctionSymbol = context.intrinsics.isSuspendFunctionSymbol // private val isCharSymbol get() = context.intrinsics.isCharSymbol - private val isObjectSymbol get() = context.intrinsics.isObjectSymbol private val instanceOfIntrinsicSymbol = context.intrinsics.jsInstanceOf private val isExternalObjectSymbol = context.intrinsics.isExternalObject @@ -276,8 +276,8 @@ class TypeOperatorLowering(val context: JsIrBackendContext) : BodyLoweringPass { } } - private fun generateIsObjectCheck(argument: IrExpression) = JsIrBuilder.buildCall(isObjectSymbol).apply { - putValueArgument(0, argument) + private fun generateIsObjectCheck(argument: IrExpression) = JsIrBuilder.buildCall(booleanNot).apply { + dispatchReceiver = nullCheck(argument) } private fun generateTypeCheckWithTypeParameter(argument: IrExpression, toType: IrType): IrExpression { diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/fir/FirJsBoxTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/fir/FirJsBoxTestGenerated.java index d06df3336ec..59e8d3aa9b5 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/fir/FirJsBoxTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/fir/FirJsBoxTestGenerated.java @@ -1720,6 +1720,12 @@ public class FirJsBoxTestGenerated extends AbstractFirJsBoxTest { runTest("js/js.translator/testData/box/dynamic/getByBrackets.kt"); } + @Test + @TestMetadata("hashCode.kt") + public void testHashCode() throws Exception { + runTest("js/js.translator/testData/box/dynamic/hashCode.kt"); + } + @Test @TestMetadata("identityEquals.kt") public void testIdentityEquals() throws Exception { diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrBoxJsES6TestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrBoxJsES6TestGenerated.java index dc5fc48e86f..380587ffb95 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrBoxJsES6TestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrBoxJsES6TestGenerated.java @@ -1720,6 +1720,12 @@ public class IrBoxJsES6TestGenerated extends AbstractIrBoxJsES6Test { runTest("js/js.translator/testData/box/dynamic/getByBrackets.kt"); } + @Test + @TestMetadata("hashCode.kt") + public void testHashCode() throws Exception { + runTest("js/js.translator/testData/box/dynamic/hashCode.kt"); + } + @Test @TestMetadata("identityEquals.kt") public void testIdentityEquals() throws Exception { diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrBoxJsTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrBoxJsTestGenerated.java index 19a07885c28..85862ab7f1d 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrBoxJsTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrBoxJsTestGenerated.java @@ -1720,6 +1720,12 @@ public class IrBoxJsTestGenerated extends AbstractIrBoxJsTest { runTest("js/js.translator/testData/box/dynamic/getByBrackets.kt"); } + @Test + @TestMetadata("hashCode.kt") + public void testHashCode() throws Exception { + runTest("js/js.translator/testData/box/dynamic/hashCode.kt"); + } + @Test @TestMetadata("identityEquals.kt") public void testIdentityEquals() throws Exception { diff --git a/js/js.translator/testData/box/builtins/toString.kt b/js/js.translator/testData/box/builtins/toString.kt index 14d29bf64e9..4cb95368284 100644 --- a/js/js.translator/testData/box/builtins/toString.kt +++ b/js/js.translator/testData/box/builtins/toString.kt @@ -28,5 +28,12 @@ fun box(): String { assertEquals((123 as Any).toString(), "123") assertEquals(null.toString(), "null") assertEquals(TokenEqualityParser(2).toString(), "2 [object Object]") + + if (!testUtils.isLegacyBackend()) { + assertEquals(js("Symbol()").unsafeCast().toString(), "Symbol()") + assertEquals(js("BigInt(44)").unsafeCast().toString(), "44") + assertEquals(js("Object.create(null)").unsafeCast().toString(), "[object Object]") + } + return "OK" } diff --git a/js/js.translator/testData/box/char/charEquals.kt b/js/js.translator/testData/box/char/charEquals.kt index a4c68ea35cb..19217e40dc4 100644 --- a/js/js.translator/testData/box/char/charEquals.kt +++ b/js/js.translator/testData/box/char/charEquals.kt @@ -1,7 +1,7 @@ // EXPECTED_REACHABLE_NODES: 1372 package foo -// CHECK_NEW_COUNT: function=box max=6 +// CHECK_NEW_COUNT: function=box max=10 fun box(): String { assertEquals(true, 'A' == 'A') assertEquals(false, 'A' != 'A') diff --git a/js/js.translator/testData/box/dynamic/hashCode.kt b/js/js.translator/testData/box/dynamic/hashCode.kt new file mode 100644 index 00000000000..601ae98768e --- /dev/null +++ b/js/js.translator/testData/box/dynamic/hashCode.kt @@ -0,0 +1,172 @@ +// IGNORE_BACKEND: JS + +fun jsNullUndefinedHashCode() { + assertEquals(js("null").unsafeCast().hashCode(), js("null").unsafeCast().hashCode()) + assertEquals(js("undefined").unsafeCast().hashCode(), js("undefined").unsafeCast().hashCode()) + assertEquals(js("null").unsafeCast().hashCode(), js("undefined").unsafeCast().hashCode()) +} + +fun jsObjectHashCode() { + val obj1 = js("{}").unsafeCast() + val obj2 = js("{}").unsafeCast() + val nullProtoObj1 = js("Object.create(null)").unsafeCast() + val nullProtoObj2 = js("Object.create(null)").unsafeCast() + val arr1 = js("[]").unsafeCast() + val arr2 = js("[]").unsafeCast() + + assertEquals(obj1.hashCode(), obj1.hashCode()) + assertEquals(obj2.hashCode(), obj2.hashCode()) + assertEquals(nullProtoObj1.hashCode(), nullProtoObj1.hashCode()) + + assertEquals(nullProtoObj2.hashCode(), nullProtoObj2.hashCode()) + assertEquals(arr1.hashCode(), arr1.hashCode()) + assertEquals(arr2.hashCode(), arr2.hashCode()) + + assertNotEquals(obj1.hashCode(), obj2.hashCode()) + assertNotEquals(obj1.hashCode(), nullProtoObj1.hashCode()) + assertNotEquals(obj1.hashCode(), nullProtoObj2.hashCode()) + assertNotEquals(obj1.hashCode(), arr1.hashCode()) + assertNotEquals(obj1.hashCode(), arr2.hashCode()) + + assertNotEquals(obj2.hashCode(), obj1.hashCode()) + assertNotEquals(obj2.hashCode(), nullProtoObj1.hashCode()) + assertNotEquals(obj2.hashCode(), nullProtoObj2.hashCode()) + assertNotEquals(obj2.hashCode(), arr1.hashCode()) + assertNotEquals(obj2.hashCode(), arr2.hashCode()) + + assertNotEquals(nullProtoObj1.hashCode(), obj1.hashCode()) + assertNotEquals(nullProtoObj1.hashCode(), obj2.hashCode()) + assertNotEquals(nullProtoObj1.hashCode(), nullProtoObj2.hashCode()) + assertNotEquals(nullProtoObj1.hashCode(), arr1.hashCode()) + assertNotEquals(nullProtoObj1.hashCode(), arr2.hashCode()) + + assertNotEquals(nullProtoObj2.hashCode(), obj1.hashCode()) + assertNotEquals(nullProtoObj2.hashCode(), obj2.hashCode()) + assertNotEquals(nullProtoObj2.hashCode(), nullProtoObj1.hashCode()) + assertNotEquals(nullProtoObj2.hashCode(), arr1.hashCode()) + assertNotEquals(nullProtoObj2.hashCode(), arr2.hashCode()) + + assertNotEquals(arr1.hashCode(), obj1.hashCode()) + assertNotEquals(arr1.hashCode(), obj2.hashCode()) + assertNotEquals(arr1.hashCode(), nullProtoObj1.hashCode()) + assertNotEquals(arr1.hashCode(), nullProtoObj2.hashCode()) + assertNotEquals(arr1.hashCode(), arr2.hashCode()) + + assertNotEquals(arr2.hashCode(), obj1.hashCode()) + assertNotEquals(arr2.hashCode(), obj2.hashCode()) + assertNotEquals(arr2.hashCode(), nullProtoObj1.hashCode()) + assertNotEquals(arr2.hashCode(), nullProtoObj2.hashCode()) + assertNotEquals(arr2.hashCode(), arr1.hashCode()) +} + +fun jsFunctionHashCode() { + val fun1 = js("function() {}").unsafeCast() + val fun2 = js("function() {}").unsafeCast() + val randomObject = js("{}").unsafeCast() + + assertEquals(fun1.hashCode(), fun1.hashCode()) + assertEquals(fun2.hashCode(), fun2.hashCode()) + assertEquals(randomObject.hashCode(), randomObject.hashCode()) + + assertNotEquals(fun1.hashCode(), fun2.hashCode()) + assertNotEquals(fun1.hashCode(), randomObject.hashCode()) + + assertNotEquals(fun2.hashCode(), fun1.hashCode()) + assertNotEquals(fun2.hashCode(), randomObject.hashCode()) + + assertNotEquals(randomObject.hashCode(), fun1.hashCode()) + assertNotEquals(randomObject.hashCode(), fun2.hashCode()) +} + +fun jsNumberHashCode() { + assertEquals(js("4").unsafeCast().hashCode(), js("4").unsafeCast().hashCode()) + assertEquals(js("5").unsafeCast().hashCode(), js("5").unsafeCast().hashCode()) + assertEquals(js("-4").unsafeCast().hashCode(), js("-4").unsafeCast().hashCode()) + assertEquals(js("0").unsafeCast().hashCode(), js("-0").unsafeCast().hashCode()) + assertEquals(js("NaN").unsafeCast().hashCode(), js("NaN").unsafeCast().hashCode()) + assertEquals(js("Infinity").unsafeCast().hashCode(), js("Infinity").unsafeCast().hashCode()) + assertEquals(js("-Infinity").unsafeCast().hashCode(), js("-Infinity").unsafeCast().hashCode()) + + assertNotEquals(js("-Infinity").unsafeCast().hashCode(), js("Infinity").unsafeCast().hashCode()) + + assertNotEquals(js("4").unsafeCast().hashCode(), js("5").unsafeCast().hashCode()) + assertNotEquals(js("4").unsafeCast().hashCode(), js("-4").unsafeCast().hashCode()) + + assertNotEquals(js("5").unsafeCast().hashCode(), js("4").unsafeCast().hashCode()) + assertNotEquals(js("5").unsafeCast().hashCode(), js("-4").unsafeCast().hashCode()) + + assertNotEquals(js("-4").unsafeCast().hashCode(), js("4").unsafeCast().hashCode()) + assertNotEquals(js("-4").unsafeCast().hashCode(), js("5").unsafeCast().hashCode()) +} + +fun jsBooleanHashCode() { + assertEquals(js("true").unsafeCast().hashCode(), js("true").unsafeCast().hashCode()) + assertEquals(js("false").unsafeCast().hashCode(), js("false").unsafeCast().hashCode()) + + assertNotEquals(js("true").unsafeCast().hashCode(), js("false").unsafeCast().hashCode()) +} + +fun jsStringHashCode() { + assertEquals(js("'Test'").unsafeCast().hashCode(), js("'Test'").unsafeCast().hashCode()) + assertEquals(js("'Test1'").unsafeCast().hashCode(), js("'Test1'").unsafeCast().hashCode()) + assertEquals(js("' Test'").unsafeCast().hashCode(), js("' Test'").unsafeCast().hashCode()) + + assertNotEquals(js("'Test'").unsafeCast().hashCode(), js("' Test'").unsafeCast().hashCode()) + assertNotEquals(js("'Test'").unsafeCast().hashCode(), js("'Test1'").unsafeCast().hashCode()) + + assertNotEquals(js("'Test1'").unsafeCast().hashCode(), js("'Test'").unsafeCast().hashCode()) + assertNotEquals(js("'Test1'").unsafeCast().hashCode(), js("' Test'").unsafeCast().hashCode()) + + assertNotEquals(js("' Test'").unsafeCast().hashCode(), js("'Test'").unsafeCast().hashCode()) + assertNotEquals(js("' Test'").unsafeCast().hashCode(), js("'Test1'").unsafeCast().hashCode()) +} + +fun jsBigIntHashCode() { + assertEquals(js("BigInt(4)").unsafeCast().hashCode(), js("BigInt(4)").unsafeCast().hashCode()) + assertEquals(js("BigInt(5)").unsafeCast().hashCode(), js("BigInt(5)").unsafeCast().hashCode()) + assertEquals(js("BigInt(-4)").unsafeCast().hashCode(), js("BigInt(-4)").unsafeCast().hashCode()) + + assertNotEquals(js("BigInt(4)").unsafeCast().hashCode(), js("BigInt(5)").unsafeCast().hashCode()) + assertNotEquals(js("BigInt(4)").unsafeCast().hashCode(), js("BigInt(-4)").unsafeCast().hashCode()) + + assertNotEquals(js("BigInt(5)").unsafeCast().hashCode(), js("BigInt(4)").unsafeCast().hashCode()) + assertNotEquals(js("BigInt(5)").unsafeCast().hashCode(), js("BigInt(-4)").unsafeCast().hashCode()) + + assertNotEquals(js("BigInt(-4)").unsafeCast().hashCode(), js("BigInt(4)").unsafeCast().hashCode()) + assertNotEquals(js("BigInt(-4)").unsafeCast().hashCode(), js("BigInt(5)").unsafeCast().hashCode()) +} + +fun jsSymbolHashCode() { + val symbol1 = js("Symbol()").unsafeCast() + val symbol2 = js("Symbol()").unsafeCast() + val symbol3 = js("Symbol.for('test')").unsafeCast() + + assertEquals(symbol1.hashCode(), symbol1.hashCode()) + assertEquals(symbol2.hashCode(), symbol2.hashCode()) + assertEquals(symbol3.hashCode(), symbol3.hashCode()) + assertEquals(symbol3.hashCode(), js("Symbol.for('test')").unsafeCast().hashCode()) + + assertNotEquals(symbol1.hashCode(), symbol2.hashCode()) + assertNotEquals(symbol1.hashCode(), symbol3.hashCode()) + assertNotEquals(symbol1.hashCode(), js("Symbol.for('test')").unsafeCast().hashCode()) + + assertNotEquals(symbol2.hashCode(), symbol1.hashCode()) + assertNotEquals(symbol2.hashCode(), symbol3.hashCode()) + assertNotEquals(symbol2.hashCode(), js("Symbol.for('test')").unsafeCast().hashCode()) + + assertNotEquals(symbol3.hashCode(), symbol1.hashCode()) + assertNotEquals(symbol3.hashCode(), symbol2.hashCode()) +} + +fun box(): String { + jsNullUndefinedHashCode() + jsObjectHashCode() + jsFunctionHashCode() + jsNumberHashCode() + jsBooleanHashCode() + jsStringHashCode() + jsBigIntHashCode() + jsSymbolHashCode() + + return "OK" +} \ No newline at end of file diff --git a/js/js.translator/testData/box/standardClasses/any.kt b/js/js.translator/testData/box/standardClasses/any.kt index 7fb71144b36..a4e127f6759 100644 --- a/js/js.translator/testData/box/standardClasses/any.kt +++ b/js/js.translator/testData/box/standardClasses/any.kt @@ -1,6 +1,5 @@ // EXPECTED_REACHABLE_NODES: 1285 // CHECK_CALLED_IN_SCOPE: function=isType scope=box TARGET_BACKENDS=JS -// CHECK_CALLED_IN_SCOPE: function=isObject scope=box IGNORED_BACKENDS=JS package foo class A : Any() @@ -16,7 +15,11 @@ fun box(): String { if (arrayOf(1, 2, 3).asAny() !is Any) return "fail3" - if (createNakedObject() is Any) return "fail4" + if (testUtils.isLegacyBackend()) { + if (createNakedObject() is Any) return "fail4" + } else { + if (createNakedObject() !is Any) return "fail4" + } if (({ }).asAny() !is Any) return "fail5" @@ -28,6 +31,8 @@ fun box(): String { if ("bar".asAny() !is Any) return "fail9" + if (null is Any) return "fail10" + return "OK" } diff --git a/libraries/stdlib/js-ir/runtime/coreRuntime.kt b/libraries/stdlib/js-ir/runtime/coreRuntime.kt index 844218ebff5..84a40d859d4 100644 --- a/libraries/stdlib/js-ir/runtime/coreRuntime.kt +++ b/libraries/stdlib/js-ir/runtime/coreRuntime.kt @@ -30,26 +30,25 @@ internal fun equals(obj1: dynamic, obj2: dynamic): Boolean { internal fun toString(o: dynamic): String = when { o == null -> "null" isArrayish(o) -> "[...]" - + jsTypeOf(o.toString) != "function" -> anyToString(o) else -> (o.toString)().unsafeCast() } internal fun anyToString(o: dynamic): String = js("Object").prototype.toString.call(o) -private fun hasOwnPrototypeProperty(o: Any, name: String): Boolean { - return JsObject.getPrototypeOf(o).hasOwnProperty(name).unsafeCast() -} - internal fun hashCode(obj: dynamic): Int { - if (obj == null) - return 0 + if (obj == null) return 0 - return when (jsTypeOf(obj)) { + @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()) - else -> getStringHashCode(js("String")(obj)) + "string" -> getStringHashCode(js("String")(obj)) + "bigint" -> getBigIntHashCode(obj) + "symbol" -> getSymbolHashCode(obj) + else -> js("throw new Error('Unexpected typeof `' + typeOf + '`')") } } @@ -57,12 +56,71 @@ 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() + 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 = jsBitwiseOr(js("Math").random() * POW_2_32, 0) // Make 32-bit singed integer. + var hash = calculateRandomHash() var descriptor = js("new Object()") descriptor.value = hash descriptor.enumerable = false diff --git a/libraries/stdlib/js-ir/runtime/typeCheckUtils.kt b/libraries/stdlib/js-ir/runtime/typeCheckUtils.kt index 52a536f696a..2e497a71cc1 100644 --- a/libraries/stdlib/js-ir/runtime/typeCheckUtils.kt +++ b/libraries/stdlib/js-ir/runtime/typeCheckUtils.kt @@ -69,18 +69,6 @@ internal fun isSuspendFunction(obj: dynamic, arity: Int): Boolean { return result } -internal fun isObject(obj: dynamic): Boolean { - val objTypeOf = jsTypeOf(obj) - - return when (objTypeOf) { - "string" -> true - "number" -> true - "boolean" -> true - "function" -> true - else -> jsInstanceOf(obj, js("Object")) - } -} - private fun isJsArray(obj: Any): Boolean { return js("Array").isArray(obj).unsafeCast() } @@ -89,6 +77,9 @@ 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 { @@ -109,7 +100,7 @@ internal fun jsGetPrototypeOf(jsClass: dynamic) = js("Object").getPrototypeOf(js internal fun jsIsType(obj: dynamic, jsClass: dynamic): Boolean { if (jsClass === js("Object")) { - return isObject(obj) + return obj != null } val objType = jsTypeOf(obj)