[K/JS] Remove isObject check from runtime ^KT-57926 Fixed
This commit is contained in:
@@ -117,7 +117,6 @@ class JsIntrinsics(private val irBuiltIns: IrBuiltIns, val context: JsIrBackendC
|
|||||||
val isInterfaceSymbol = getInternalFunction("isInterface")
|
val isInterfaceSymbol = getInternalFunction("isInterface")
|
||||||
val isArraySymbol = getInternalFunction("isArray")
|
val isArraySymbol = getInternalFunction("isArray")
|
||||||
// val isCharSymbol = getInternalFunction("isChar")
|
// val isCharSymbol = getInternalFunction("isChar")
|
||||||
val isObjectSymbol = getInternalFunction("isObject")
|
|
||||||
val isSuspendFunctionSymbol = getInternalFunction("isSuspendFunction")
|
val isSuspendFunctionSymbol = getInternalFunction("isSuspendFunction")
|
||||||
|
|
||||||
val isNumberSymbol = getInternalFunction("isNumber")
|
val isNumberSymbol = getInternalFunction("isNumber")
|
||||||
|
|||||||
+3
-3
@@ -44,13 +44,13 @@ class TypeOperatorLowering(val context: JsIrBackendContext) : BodyLoweringPass {
|
|||||||
private val throwNPE = context.ir.symbols.throwNullPointerException
|
private val throwNPE = context.ir.symbols.throwNullPointerException
|
||||||
|
|
||||||
private val eqeq = context.irBuiltIns.eqeqSymbol
|
private val eqeq = context.irBuiltIns.eqeqSymbol
|
||||||
|
private val booleanNot = context.irBuiltIns.booleanNotSymbol
|
||||||
|
|
||||||
private val isInterfaceSymbol get() = context.intrinsics.isInterfaceSymbol
|
private val isInterfaceSymbol get() = context.intrinsics.isInterfaceSymbol
|
||||||
private val isArraySymbol get() = context.intrinsics.isArraySymbol
|
private val isArraySymbol get() = context.intrinsics.isArraySymbol
|
||||||
private val isSuspendFunctionSymbol = context.intrinsics.isSuspendFunctionSymbol
|
private val isSuspendFunctionSymbol = context.intrinsics.isSuspendFunctionSymbol
|
||||||
|
|
||||||
// private val isCharSymbol get() = context.intrinsics.isCharSymbol
|
// private val isCharSymbol get() = context.intrinsics.isCharSymbol
|
||||||
private val isObjectSymbol get() = context.intrinsics.isObjectSymbol
|
|
||||||
|
|
||||||
private val instanceOfIntrinsicSymbol = context.intrinsics.jsInstanceOf
|
private val instanceOfIntrinsicSymbol = context.intrinsics.jsInstanceOf
|
||||||
private val isExternalObjectSymbol = context.intrinsics.isExternalObject
|
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 {
|
private fun generateIsObjectCheck(argument: IrExpression) = JsIrBuilder.buildCall(booleanNot).apply {
|
||||||
putValueArgument(0, argument)
|
dispatchReceiver = nullCheck(argument)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun generateTypeCheckWithTypeParameter(argument: IrExpression, toType: IrType): IrExpression {
|
private fun generateTypeCheckWithTypeParameter(argument: IrExpression, toType: IrType): IrExpression {
|
||||||
|
|||||||
+6
@@ -1720,6 +1720,12 @@ public class FirJsBoxTestGenerated extends AbstractFirJsBoxTest {
|
|||||||
runTest("js/js.translator/testData/box/dynamic/getByBrackets.kt");
|
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
|
@Test
|
||||||
@TestMetadata("identityEquals.kt")
|
@TestMetadata("identityEquals.kt")
|
||||||
public void testIdentityEquals() throws Exception {
|
public void testIdentityEquals() throws Exception {
|
||||||
|
|||||||
+6
@@ -1720,6 +1720,12 @@ public class IrBoxJsES6TestGenerated extends AbstractIrBoxJsES6Test {
|
|||||||
runTest("js/js.translator/testData/box/dynamic/getByBrackets.kt");
|
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
|
@Test
|
||||||
@TestMetadata("identityEquals.kt")
|
@TestMetadata("identityEquals.kt")
|
||||||
public void testIdentityEquals() throws Exception {
|
public void testIdentityEquals() throws Exception {
|
||||||
|
|||||||
+6
@@ -1720,6 +1720,12 @@ public class IrBoxJsTestGenerated extends AbstractIrBoxJsTest {
|
|||||||
runTest("js/js.translator/testData/box/dynamic/getByBrackets.kt");
|
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
|
@Test
|
||||||
@TestMetadata("identityEquals.kt")
|
@TestMetadata("identityEquals.kt")
|
||||||
public void testIdentityEquals() throws Exception {
|
public void testIdentityEquals() throws Exception {
|
||||||
|
|||||||
@@ -28,5 +28,12 @@ fun box(): String {
|
|||||||
assertEquals((123 as Any).toString(), "123")
|
assertEquals((123 as Any).toString(), "123")
|
||||||
assertEquals(null.toString(), "null")
|
assertEquals(null.toString(), "null")
|
||||||
assertEquals(TokenEqualityParser(2).toString(), "2 [object Object]")
|
assertEquals(TokenEqualityParser(2).toString(), "2 [object Object]")
|
||||||
|
|
||||||
|
if (!testUtils.isLegacyBackend()) {
|
||||||
|
assertEquals(js("Symbol()").unsafeCast<Any>().toString(), "Symbol()")
|
||||||
|
assertEquals(js("BigInt(44)").unsafeCast<Any>().toString(), "44")
|
||||||
|
assertEquals(js("Object.create(null)").unsafeCast<Any>().toString(), "[object Object]")
|
||||||
|
}
|
||||||
|
|
||||||
return "OK"
|
return "OK"
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
// EXPECTED_REACHABLE_NODES: 1372
|
// EXPECTED_REACHABLE_NODES: 1372
|
||||||
package foo
|
package foo
|
||||||
|
|
||||||
// CHECK_NEW_COUNT: function=box max=6
|
// CHECK_NEW_COUNT: function=box max=10
|
||||||
fun box(): String {
|
fun box(): String {
|
||||||
assertEquals(true, 'A' == 'A')
|
assertEquals(true, 'A' == 'A')
|
||||||
assertEquals(false, 'A' != 'A')
|
assertEquals(false, 'A' != 'A')
|
||||||
|
|||||||
+172
@@ -0,0 +1,172 @@
|
|||||||
|
// IGNORE_BACKEND: JS
|
||||||
|
|
||||||
|
fun jsNullUndefinedHashCode() {
|
||||||
|
assertEquals(js("null").unsafeCast<Any>().hashCode(), js("null").unsafeCast<Any>().hashCode())
|
||||||
|
assertEquals(js("undefined").unsafeCast<Any>().hashCode(), js("undefined").unsafeCast<Any>().hashCode())
|
||||||
|
assertEquals(js("null").unsafeCast<Any>().hashCode(), js("undefined").unsafeCast<Any>().hashCode())
|
||||||
|
}
|
||||||
|
|
||||||
|
fun jsObjectHashCode() {
|
||||||
|
val obj1 = js("{}").unsafeCast<Any>()
|
||||||
|
val obj2 = js("{}").unsafeCast<Any>()
|
||||||
|
val nullProtoObj1 = js("Object.create(null)").unsafeCast<Any>()
|
||||||
|
val nullProtoObj2 = js("Object.create(null)").unsafeCast<Any>()
|
||||||
|
val arr1 = js("[]").unsafeCast<Any>()
|
||||||
|
val arr2 = js("[]").unsafeCast<Any>()
|
||||||
|
|
||||||
|
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<Any>()
|
||||||
|
val fun2 = js("function() {}").unsafeCast<Any>()
|
||||||
|
val randomObject = js("{}").unsafeCast<Any>()
|
||||||
|
|
||||||
|
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<Any>().hashCode(), js("4").unsafeCast<Any>().hashCode())
|
||||||
|
assertEquals(js("5").unsafeCast<Any>().hashCode(), js("5").unsafeCast<Any>().hashCode())
|
||||||
|
assertEquals(js("-4").unsafeCast<Any>().hashCode(), js("-4").unsafeCast<Any>().hashCode())
|
||||||
|
assertEquals(js("0").unsafeCast<Any>().hashCode(), js("-0").unsafeCast<Any>().hashCode())
|
||||||
|
assertEquals(js("NaN").unsafeCast<Any>().hashCode(), js("NaN").unsafeCast<Any>().hashCode())
|
||||||
|
assertEquals(js("Infinity").unsafeCast<Any>().hashCode(), js("Infinity").unsafeCast<Any>().hashCode())
|
||||||
|
assertEquals(js("-Infinity").unsafeCast<Any>().hashCode(), js("-Infinity").unsafeCast<Any>().hashCode())
|
||||||
|
|
||||||
|
assertNotEquals(js("-Infinity").unsafeCast<Any>().hashCode(), js("Infinity").unsafeCast<Any>().hashCode())
|
||||||
|
|
||||||
|
assertNotEquals(js("4").unsafeCast<Any>().hashCode(), js("5").unsafeCast<Any>().hashCode())
|
||||||
|
assertNotEquals(js("4").unsafeCast<Any>().hashCode(), js("-4").unsafeCast<Any>().hashCode())
|
||||||
|
|
||||||
|
assertNotEquals(js("5").unsafeCast<Any>().hashCode(), js("4").unsafeCast<Any>().hashCode())
|
||||||
|
assertNotEquals(js("5").unsafeCast<Any>().hashCode(), js("-4").unsafeCast<Any>().hashCode())
|
||||||
|
|
||||||
|
assertNotEquals(js("-4").unsafeCast<Any>().hashCode(), js("4").unsafeCast<Any>().hashCode())
|
||||||
|
assertNotEquals(js("-4").unsafeCast<Any>().hashCode(), js("5").unsafeCast<Any>().hashCode())
|
||||||
|
}
|
||||||
|
|
||||||
|
fun jsBooleanHashCode() {
|
||||||
|
assertEquals(js("true").unsafeCast<Any>().hashCode(), js("true").unsafeCast<Any>().hashCode())
|
||||||
|
assertEquals(js("false").unsafeCast<Any>().hashCode(), js("false").unsafeCast<Any>().hashCode())
|
||||||
|
|
||||||
|
assertNotEquals(js("true").unsafeCast<Any>().hashCode(), js("false").unsafeCast<Any>().hashCode())
|
||||||
|
}
|
||||||
|
|
||||||
|
fun jsStringHashCode() {
|
||||||
|
assertEquals(js("'Test'").unsafeCast<Any>().hashCode(), js("'Test'").unsafeCast<Any>().hashCode())
|
||||||
|
assertEquals(js("'Test1'").unsafeCast<Any>().hashCode(), js("'Test1'").unsafeCast<Any>().hashCode())
|
||||||
|
assertEquals(js("' Test'").unsafeCast<Any>().hashCode(), js("' Test'").unsafeCast<Any>().hashCode())
|
||||||
|
|
||||||
|
assertNotEquals(js("'Test'").unsafeCast<Any>().hashCode(), js("' Test'").unsafeCast<Any>().hashCode())
|
||||||
|
assertNotEquals(js("'Test'").unsafeCast<Any>().hashCode(), js("'Test1'").unsafeCast<Any>().hashCode())
|
||||||
|
|
||||||
|
assertNotEquals(js("'Test1'").unsafeCast<Any>().hashCode(), js("'Test'").unsafeCast<Any>().hashCode())
|
||||||
|
assertNotEquals(js("'Test1'").unsafeCast<Any>().hashCode(), js("' Test'").unsafeCast<Any>().hashCode())
|
||||||
|
|
||||||
|
assertNotEquals(js("' Test'").unsafeCast<Any>().hashCode(), js("'Test'").unsafeCast<Any>().hashCode())
|
||||||
|
assertNotEquals(js("' Test'").unsafeCast<Any>().hashCode(), js("'Test1'").unsafeCast<Any>().hashCode())
|
||||||
|
}
|
||||||
|
|
||||||
|
fun jsBigIntHashCode() {
|
||||||
|
assertEquals(js("BigInt(4)").unsafeCast<Any>().hashCode(), js("BigInt(4)").unsafeCast<Any>().hashCode())
|
||||||
|
assertEquals(js("BigInt(5)").unsafeCast<Any>().hashCode(), js("BigInt(5)").unsafeCast<Any>().hashCode())
|
||||||
|
assertEquals(js("BigInt(-4)").unsafeCast<Any>().hashCode(), js("BigInt(-4)").unsafeCast<Any>().hashCode())
|
||||||
|
|
||||||
|
assertNotEquals(js("BigInt(4)").unsafeCast<Any>().hashCode(), js("BigInt(5)").unsafeCast<Any>().hashCode())
|
||||||
|
assertNotEquals(js("BigInt(4)").unsafeCast<Any>().hashCode(), js("BigInt(-4)").unsafeCast<Any>().hashCode())
|
||||||
|
|
||||||
|
assertNotEquals(js("BigInt(5)").unsafeCast<Any>().hashCode(), js("BigInt(4)").unsafeCast<Any>().hashCode())
|
||||||
|
assertNotEquals(js("BigInt(5)").unsafeCast<Any>().hashCode(), js("BigInt(-4)").unsafeCast<Any>().hashCode())
|
||||||
|
|
||||||
|
assertNotEquals(js("BigInt(-4)").unsafeCast<Any>().hashCode(), js("BigInt(4)").unsafeCast<Any>().hashCode())
|
||||||
|
assertNotEquals(js("BigInt(-4)").unsafeCast<Any>().hashCode(), js("BigInt(5)").unsafeCast<Any>().hashCode())
|
||||||
|
}
|
||||||
|
|
||||||
|
fun jsSymbolHashCode() {
|
||||||
|
val symbol1 = js("Symbol()").unsafeCast<Any>()
|
||||||
|
val symbol2 = js("Symbol()").unsafeCast<Any>()
|
||||||
|
val symbol3 = js("Symbol.for('test')").unsafeCast<Any>()
|
||||||
|
|
||||||
|
assertEquals(symbol1.hashCode(), symbol1.hashCode())
|
||||||
|
assertEquals(symbol2.hashCode(), symbol2.hashCode())
|
||||||
|
assertEquals(symbol3.hashCode(), symbol3.hashCode())
|
||||||
|
assertEquals(symbol3.hashCode(), js("Symbol.for('test')").unsafeCast<Any>().hashCode())
|
||||||
|
|
||||||
|
assertNotEquals(symbol1.hashCode(), symbol2.hashCode())
|
||||||
|
assertNotEquals(symbol1.hashCode(), symbol3.hashCode())
|
||||||
|
assertNotEquals(symbol1.hashCode(), js("Symbol.for('test')").unsafeCast<Any>().hashCode())
|
||||||
|
|
||||||
|
assertNotEquals(symbol2.hashCode(), symbol1.hashCode())
|
||||||
|
assertNotEquals(symbol2.hashCode(), symbol3.hashCode())
|
||||||
|
assertNotEquals(symbol2.hashCode(), js("Symbol.for('test')").unsafeCast<Any>().hashCode())
|
||||||
|
|
||||||
|
assertNotEquals(symbol3.hashCode(), symbol1.hashCode())
|
||||||
|
assertNotEquals(symbol3.hashCode(), symbol2.hashCode())
|
||||||
|
}
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
jsNullUndefinedHashCode()
|
||||||
|
jsObjectHashCode()
|
||||||
|
jsFunctionHashCode()
|
||||||
|
jsNumberHashCode()
|
||||||
|
jsBooleanHashCode()
|
||||||
|
jsStringHashCode()
|
||||||
|
jsBigIntHashCode()
|
||||||
|
jsSymbolHashCode()
|
||||||
|
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
+7
-2
@@ -1,6 +1,5 @@
|
|||||||
// EXPECTED_REACHABLE_NODES: 1285
|
// EXPECTED_REACHABLE_NODES: 1285
|
||||||
// CHECK_CALLED_IN_SCOPE: function=isType scope=box TARGET_BACKENDS=JS
|
// CHECK_CALLED_IN_SCOPE: function=isType scope=box TARGET_BACKENDS=JS
|
||||||
// CHECK_CALLED_IN_SCOPE: function=isObject scope=box IGNORED_BACKENDS=JS
|
|
||||||
package foo
|
package foo
|
||||||
|
|
||||||
class A : Any()
|
class A : Any()
|
||||||
@@ -16,7 +15,11 @@ fun box(): String {
|
|||||||
|
|
||||||
if (arrayOf(1, 2, 3).asAny() !is Any) return "fail3"
|
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"
|
if (({ }).asAny() !is Any) return "fail5"
|
||||||
|
|
||||||
@@ -28,6 +31,8 @@ fun box(): String {
|
|||||||
|
|
||||||
if ("bar".asAny() !is Any) return "fail9"
|
if ("bar".asAny() !is Any) return "fail9"
|
||||||
|
|
||||||
|
if (null is Any) return "fail10"
|
||||||
|
|
||||||
return "OK"
|
return "OK"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -30,26 +30,25 @@ internal fun equals(obj1: dynamic, obj2: dynamic): Boolean {
|
|||||||
internal fun toString(o: dynamic): String = when {
|
internal fun toString(o: dynamic): String = when {
|
||||||
o == null -> "null"
|
o == null -> "null"
|
||||||
isArrayish(o) -> "[...]"
|
isArrayish(o) -> "[...]"
|
||||||
|
jsTypeOf(o.toString) != "function" -> anyToString(o)
|
||||||
else -> (o.toString)().unsafeCast<String>()
|
else -> (o.toString)().unsafeCast<String>()
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun anyToString(o: dynamic): String = js("Object").prototype.toString.call(o)
|
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<Boolean>()
|
|
||||||
}
|
|
||||||
|
|
||||||
internal fun hashCode(obj: dynamic): Int {
|
internal fun hashCode(obj: dynamic): Int {
|
||||||
if (obj == null)
|
if (obj == null) return 0
|
||||||
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)
|
"object" -> if ("function" === jsTypeOf(obj.hashCode)) (obj.hashCode)() else getObjectHashCode(obj)
|
||||||
"function" -> getObjectHashCode(obj)
|
"function" -> getObjectHashCode(obj)
|
||||||
"number" -> getNumberHashCode(obj)
|
"number" -> getNumberHashCode(obj)
|
||||||
"boolean" -> getBooleanHashCode(obj.unsafeCast<Boolean>())
|
"boolean" -> getBooleanHashCode(obj.unsafeCast<Boolean>())
|
||||||
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
|
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 POW_2_32 = 4294967296.0
|
||||||
private const val OBJECT_HASH_CODE_PROPERTY_NAME = "kotlinHashCodeValue$"
|
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 {
|
internal fun getObjectHashCode(obj: dynamic): Int {
|
||||||
if (!jsIn(OBJECT_HASH_CODE_PROPERTY_NAME, obj)) {
|
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()")
|
var descriptor = js("new Object()")
|
||||||
descriptor.value = hash
|
descriptor.value = hash
|
||||||
descriptor.enumerable = false
|
descriptor.enumerable = false
|
||||||
|
|||||||
@@ -69,18 +69,6 @@ internal fun isSuspendFunction(obj: dynamic, arity: Int): Boolean {
|
|||||||
return result
|
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 {
|
private fun isJsArray(obj: Any): Boolean {
|
||||||
return js("Array").isArray(obj).unsafeCast<Boolean>()
|
return js("Array").isArray(obj).unsafeCast<Boolean>()
|
||||||
}
|
}
|
||||||
@@ -89,6 +77,9 @@ internal fun isArray(obj: Any): Boolean {
|
|||||||
return isJsArray(obj) && !(obj.asDynamic().`$type$`)
|
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 isArrayish(o: dynamic) = isJsArray(o) || arrayBufferIsView(o)
|
||||||
|
|
||||||
internal fun isChar(@Suppress("UNUSED_PARAMETER") c: Any): Boolean {
|
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 {
|
internal fun jsIsType(obj: dynamic, jsClass: dynamic): Boolean {
|
||||||
if (jsClass === js("Object")) {
|
if (jsClass === js("Object")) {
|
||||||
return isObject(obj)
|
return obj != null
|
||||||
}
|
}
|
||||||
|
|
||||||
val objType = jsTypeOf(obj)
|
val objType = jsTypeOf(obj)
|
||||||
|
|||||||
Reference in New Issue
Block a user