[JS] Reduce usage of 'js' function in stdlib
Function 'kotlin.js.js' is to be redesigned in JS IR backend, partially because it is a hard feature to support. Current implementation is unstable and can cause problems around inlining and name generator. Luckily most of its use-cases can be covered by simpler features like dynamic expressions and external declarations. Thus we are reducing it's usage in stdlib to make IR backend more stable in current state. JavaScript features that can't be covered by dynamic expression are implemented in 'jsOperators.kt' file respectively for each backend: - 'internal inline' function which calls 'js' function inside for current pre-IR backend - 'internal' function with '_hack' parameters for JS IR backend which will be later intinsicified in a compiler
This commit is contained in:
@@ -51,8 +51,7 @@ public inline class Char internal constructor (val value: Int) : Comparable<Char
|
||||
public fun toDouble(): Double = value.toDouble()
|
||||
|
||||
override fun toString(): String {
|
||||
val value = value
|
||||
return js("String.fromCharCode(value)").unsafeCast<String>()
|
||||
return js("String").fromCharCode(value).unsafeCast<String>()
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
@@ -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 <T> Array<out T>.contentDeepHashCodeInternal(): Int {
|
||||
|
||||
@@ -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 <T : Comparable<T>> compareToDoNotIntrinsicify(a: Comparable<T>, b:
|
||||
a.compareTo(b)
|
||||
|
||||
fun primitiveCompareTo(a: dynamic, b: dynamic): Int =
|
||||
js("a < b ? -1 : a > b ? 1 : 0").unsafeCast<Int>()
|
||||
|
||||
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<Int>()
|
||||
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
|
||||
}
|
||||
@@ -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<Boolean>()
|
||||
return obj1 === obj2
|
||||
}
|
||||
|
||||
fun toString(o: dynamic): String = when {
|
||||
js("o == null").unsafeCast<Boolean>() -> "null"
|
||||
o == null -> "null"
|
||||
isArrayish(o) -> "[...]"
|
||||
else -> js("o.toString()").unsafeCast<String>()
|
||||
|
||||
else -> (o.toString)().unsafeCast<String>()
|
||||
}
|
||||
|
||||
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<Boolean>()) 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<Int>();
|
||||
return obj[OBJECT_HASH_CODE_PROPERTY_NAME].unsafeCast<Int>();
|
||||
}
|
||||
|
||||
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<Int>()
|
||||
|
||||
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<Int>()
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
@@ -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<Double>())
|
||||
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<String>()
|
||||
var digits = intval.asDynamic().toString(radix).unsafeCast<String>()
|
||||
|
||||
rem = remDiv
|
||||
if (rem.isZero()) {
|
||||
return digits + result
|
||||
} else {
|
||||
while (js("digits.length").unsafeCast<Int>() < 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<Double>()
|
||||
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<Int>()
|
||||
|
||||
// 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<Double>()
|
||||
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<Boolean>() || !js("isFinite(value)").unsafeCast<Boolean>()) {
|
||||
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<Int>(),
|
||||
js("(value / twoPwr32) | 0").unsafeCast<Int>()
|
||||
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
|
||||
}
|
||||
|
||||
|
||||
@@ -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<Int>()
|
||||
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)
|
||||
}
|
||||
|
||||
@@ -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<Int>()
|
||||
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)
|
||||
@@ -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<String>()
|
||||
|
||||
fun jsTypeOf(obj: Any?): String = js("typeof obj").unsafeCast<String>()
|
||||
|
||||
fun instanceOf(obj: dynamic, jsClass_local: dynamic) = js("obj instanceof jsClass_local").unsafeCast<Boolean>()
|
||||
|
||||
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<Boolean>()
|
||||
else -> jsInstanceOf(obj, js("Object"))
|
||||
}
|
||||
}
|
||||
|
||||
private fun isJsArray(obj: Any): Boolean {
|
||||
return js("Array.isArray(obj)").unsafeCast<Boolean>()
|
||||
return js("Array").isArray(obj).unsafeCast<Boolean>()
|
||||
}
|
||||
|
||||
public fun isArray(obj: Any): Boolean {
|
||||
return isJsArray(obj) && js("!obj.\$type\$").unsafeCast<Boolean>()
|
||||
return isJsArray(obj) && !(obj.asDynamic().`$type$`)
|
||||
}
|
||||
|
||||
public fun isArrayish(o: dynamic) =
|
||||
isJsArray(o) || js("ArrayBuffer.isView(o)").unsafeCast<Boolean>()
|
||||
isJsArray(o) || js("ArrayBuffer").isView(o).unsafeCast<Boolean>()
|
||||
|
||||
|
||||
public fun isChar(c: Any): Boolean {
|
||||
return js("throw Error(\"isChar is not implemented\")").unsafeCast<Boolean>()
|
||||
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<Boolean>()
|
||||
public fun isShortArray(a: dynamic): Boolean = js("a instanceof Int16Array").unsafeCast<Boolean>()
|
||||
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<Boolean>()
|
||||
public fun isFloatArray(a: dynamic): Boolean = js("a instanceof Float32Array").unsafeCast<Boolean>()
|
||||
public fun isDoubleArray(a: dynamic): Boolean = js("a instanceof Float64Array").unsafeCast<Boolean>()
|
||||
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) {
|
||||
|
||||
@@ -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<String>()
|
||||
|
||||
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<Int>()
|
||||
|
||||
internal fun jsBitwiseAnd(lhs_hack: Any?, rhs_hack: Any?): Int =
|
||||
js("lhs_hack & rhs_hack").unsafeCast<Int>()
|
||||
|
||||
internal fun jsInstanceOf(obj_hack: Any?, jsClass_hack: Any?): Boolean =
|
||||
js("obj_hack instanceof jsClass_hack").unsafeCast<Boolean>()
|
||||
|
||||
// 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<Boolean>()
|
||||
|
||||
@@ -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]")
|
||||
}
|
||||
@@ -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<Int>()
|
||||
@@ -68,7 +68,7 @@ internal class InternalHashCodeMap<K, V>(override val equality: EqualityComparat
|
||||
if (chainOrEntry !is Array<*>) {
|
||||
val entry: MutableEntry<K, V> = 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<K, V>(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)
|
||||
|
||||
@@ -19,11 +19,10 @@ internal interface InternalMap<K, V> : MutableIterable<MutableMap.MutableEntry<K
|
||||
fun clear(): Unit
|
||||
|
||||
fun createJsMap(): dynamic {
|
||||
val newJsMap = js("Object.create(null)")
|
||||
val result = js("Object.create(null)")
|
||||
// force to switch object representation to dictionary mode
|
||||
// Using js-function due to JS_IR limitations
|
||||
js("newJsMap[\"foo\"] = 1")
|
||||
js("delete newJsMap[\"foo\"]")
|
||||
return newJsMap
|
||||
result["foo"] = 1
|
||||
jsDeleteProperty(result, "foo")
|
||||
return result
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,7 +62,7 @@ internal class InternalStringMap<K, V>(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<V>()
|
||||
|
||||
@@ -15,7 +15,7 @@ internal fun <T : Any> getKClass(jClass: JsClass<T>): KClass<T> = getOrCreateKCl
|
||||
internal fun <T : Any> getKClassFromExpression(e: T): KClass<T> =
|
||||
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 -> {
|
||||
|
||||
Reference in New Issue
Block a user