diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/BasicIrBoxTest.kt b/js/js.tests/test/org/jetbrains/kotlin/js/test/BasicIrBoxTest.kt index 28ddb7a5bae..bc87dcdb1dd 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/BasicIrBoxTest.kt +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/BasicIrBoxTest.kt @@ -16,6 +16,65 @@ import org.jetbrains.kotlin.test.TargetBackend import java.io.File private val runtimeSources = listOfKtFilesFrom( + "core/builtins/src/kotlin", + "libraries/stdlib/common/src", + "libraries/stdlib/src/kotlin/", + "libraries/stdlib/js/src/kotlin", + "libraries/stdlib/js/src/generated", + "libraries/stdlib/js/irRuntime", + "libraries/stdlib/js/runtime", + + "core/builtins/native/kotlin/Annotation.kt", + "core/builtins/native/kotlin/Number.kt", + "core/builtins/native/kotlin/Comparable.kt", + "core/builtins/native/kotlin/Collections.kt", + "core/builtins/native/kotlin/Iterator.kt", + "core/builtins/native/kotlin/CharSequence.kt", + + BasicBoxTest.COMMON_FILES_DIR_PATH +) - listOfKtFilesFrom( + // TODO: Unify exceptions + "libraries/stdlib/common/src/kotlin/ExceptionsH.kt", + + // Fails with: EXPERIMENTAL_IS_NOT_ENABLED + "libraries/stdlib/common/src/kotlin/annotations/Annotations.kt", + + // Conflicts with libraries/stdlib/js/src/kotlin/annotations.kt + "libraries/stdlib/js/runtime/hacks.kt", + + // TODO: Reuse in IR BE + "libraries/stdlib/js/runtime/Enum.kt", + + // JS-specific optimized version of emptyArray() already defined + "core/builtins/src/kotlin/ArrayIntrinsics.kt", + + // Unnecessary for now + "libraries/stdlib/js/src/kotlin/dom", + "libraries/stdlib/js/src/kotlin/browser", + + // TODO: Unify exceptions + "libraries/stdlib/js/src/kotlin/exceptions.kt", + + // TODO: fix compilation issues in arrayPlusCollection + // Replaced with irRuntime/kotlinHacks.kt + "libraries/stdlib/js/src/kotlin/kotlin.kt", + + // Full version is defined in stdlib + // This file is useful for smaller subset of runtime sources + "libraries/stdlib/js/irRuntime/rangeExtensions.kt", + + // TODO: Reuse coroutine code from common (and current JS BE?) + "libraries/stdlib/js/src/kotlin/coroutines.kt", + "libraries/stdlib/js/src/kotlin/coroutinesIntrinsics.kt", + "libraries/stdlib/src/kotlin/coroutines" +) + listOfKtFilesFrom( + "libraries/stdlib/src/kotlin/coroutines/experimental/SequenceBuilder.kt", + "libraries/stdlib/src/kotlin/coroutines/experimental/Coroutines.kt" +) + +// Smaller set of sources missing a big part of stdlib +// Intended to be used with coroutine tests where runtime is not cached +private val smallerRuntimeSources = listOfKtFilesFrom( "libraries/stdlib/js/src/kotlin/core.kt", "libraries/stdlib/js/src/kotlin/js.core.kt", "libraries/stdlib/js/src/kotlin/jsTypeOf.kt", @@ -30,6 +89,7 @@ private val runtimeSources = listOfKtFilesFrom( "libraries/stdlib/src/kotlin/contracts", "libraries/stdlib/src/kotlin/annotations/Experimental.kt", "libraries/stdlib/src/kotlin/util/Standard.kt", + "libraries/stdlib/src/kotlin/coroutines/experimental/Coroutines.kt", "core/builtins/native/kotlin/Annotation.kt", "core/builtins/native/kotlin/Number.kt", "core/builtins/native/kotlin/Comparable.kt", @@ -45,13 +105,19 @@ private val runtimeSources = listOfKtFilesFrom( "core/builtins/src/kotlin/reflect", "core/builtins/src/kotlin/Function.kt", + "core/builtins/native/kotlin/Collections.kt", "core/builtins/native/kotlin/Iterator.kt", "libraries/stdlib/common/src/kotlin/JsAnnotationsH.kt", + "libraries/stdlib/common/src/kotlin/CoroutinesH.kt", + "libraries/stdlib/common/src/kotlin/CoroutinesIntrinsicsH.kt", + "libraries/stdlib/js/irRuntime", BasicBoxTest.COMMON_FILES_DIR_PATH +) - listOfKtFilesFrom( + "libraries/stdlib/js/irRuntime/kotlinHacks.kt" ) private var runtimeResult: Result? = null @@ -144,7 +210,7 @@ private fun listOfKtFilesFrom(vararg paths: String): List { .filter { it.extension == "kt" } .map { it.relativeToOrSelf(currentDir).path } .asIterable() - } + }.distinct() } private fun File.write(text: String) { diff --git a/libraries/stdlib/js/irRuntime/coroutineIntrinsics.kt b/libraries/stdlib/js/irRuntime/coroutineIntrinsics.kt index a4c3fa1529f..df09bfd79ff 100644 --- a/libraries/stdlib/js/irRuntime/coroutineIntrinsics.kt +++ b/libraries/stdlib/js/irRuntime/coroutineIntrinsics.kt @@ -41,7 +41,7 @@ public val COROUTINE_SUSPENDED: Any = Any() @SinceKotlin("1.1") @Suppress("UNCHECKED_CAST") @kotlin.internal.InlineOnly -public inline fun (suspend () -> T).startCoroutineUninterceptedOrReturn( +public actual inline fun (suspend () -> T).startCoroutineUninterceptedOrReturn( completion: Continuation ): Any? { val self_0 = this @@ -54,7 +54,7 @@ public inline fun (suspend () -> T).startCoroutineUninterceptedOrReturn( @SinceKotlin("1.1") @Suppress("UNCHECKED_CAST") @kotlin.internal.InlineOnly -public inline fun (suspend R.() -> T).startCoroutineUninterceptedOrReturn( +public actual inline fun (suspend R.() -> T).startCoroutineUninterceptedOrReturn( receiver: R, completion: Continuation ): Any? { @@ -67,7 +67,7 @@ public inline fun (suspend R.() -> T).startCoroutineUninterceptedOrReturn } @SinceKotlin("1.1") -public fun (suspend R.() -> T).createCoroutineUnchecked( +public actual fun (suspend R.() -> T).createCoroutineUnchecked( receiver: R, completion: Continuation ): Continuation { @@ -81,7 +81,7 @@ public fun (suspend R.() -> T).createCoroutineUnchecked( } @SinceKotlin("1.1") -public fun (suspend () -> T).createCoroutineUnchecked( +public actual fun (suspend () -> T).createCoroutineUnchecked( completion: Continuation ): Continuation { return if (this !is CoroutineImpl) { diff --git a/libraries/stdlib/js/irRuntime/coroutines.kt b/libraries/stdlib/js/irRuntime/coroutines.kt index 2289bb6c328..ede34768513 100644 --- a/libraries/stdlib/js/irRuntime/coroutines.kt +++ b/libraries/stdlib/js/irRuntime/coroutines.kt @@ -63,10 +63,6 @@ public fun (suspend () -> T).createCoroutine( completion: Continuation ): Continuation = SafeContinuation(createCoroutineUnchecked(completion), COROUTINE_SUSPENDED) -// TODO: remove this once implemented in stdlib -inline fun T.let(f: (T) -> R) = f(this) -inline fun run(f: () -> R) = f() - public interface CoroutineContext { /** * Returns the element with the given [key] from this context or `null`. @@ -154,6 +150,7 @@ public interface ContinuationInterceptor : CoroutineContext.Element { public fun interceptContinuation(continuation: Continuation): Continuation } + internal class CombinedContext(val left: CoroutineContext, val element: CoroutineContext.Element) : CoroutineContext { override fun get(key: CoroutineContext.Key): E? { var cur = this @@ -217,38 +214,22 @@ public object EmptyCoroutineContext : CoroutineContext { public override fun toString(): String = "EmptyCoroutineContext" } -public interface Continuation { - /** - * Context of the coroutine that corresponds to this continuation. - */ - public val context: CoroutineContext - - /** - * Resumes the execution of the corresponding coroutine passing [value] as the return value of the last suspension point. - */ - public fun resume(value: T) - - /** - * Resumes the execution of the corresponding coroutine so that the [exception] is re-thrown right after the - * last suspension point. - */ - public fun resumeWithException(exception: Throwable) -} - -public class SafeContinuation -public constructor( +@PublishedApi +internal actual class SafeContinuation +internal actual constructor( private val delegate: Continuation, initialResult: Any? ) : Continuation { - public constructor(delegate: Continuation) : this(delegate, UNDECIDED) + @PublishedApi + internal actual constructor(delegate: Continuation) : this(delegate, UNDECIDED) - public override val context: CoroutineContext + public actual override val context: CoroutineContext get() = delegate.context private var result: Any? = initialResult - override fun resume(value: T) { + actual override fun resume(value: T) { when { result === UNDECIDED -> { result = value @@ -263,7 +244,7 @@ public constructor( } } - override fun resumeWithException(exception: Throwable) { + actual override fun resumeWithException(exception: Throwable) { when { result === UNDECIDED -> { result = Fail(exception) @@ -278,7 +259,8 @@ public constructor( } } - public fun getResult(): Any? { + @PublishedApi + internal actual fun getResult(): Any? { if (result === UNDECIDED) { result = COROUTINE_SUSPENDED } diff --git a/libraries/stdlib/js/irRuntime/kotlinHacks.kt b/libraries/stdlib/js/irRuntime/kotlinHacks.kt new file mode 100644 index 00000000000..128df622035 --- /dev/null +++ b/libraries/stdlib/js/irRuntime/kotlinHacks.kt @@ -0,0 +1,106 @@ +/* + * 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 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 emptyArray(): Array = js("[]") + +@library +public fun arrayOf(vararg elements: T): Array = definedExternally + +@library +public fun doubleArrayOf(vararg elements: Double): DoubleArray = definedExternally + +@library +public fun floatArrayOf(vararg elements: Float): FloatArray = definedExternally + +@library +public fun longArrayOf(vararg elements: Long): LongArray = definedExternally + +@library +public fun intArrayOf(vararg elements: Int): IntArray = definedExternally + +@library +public fun charArrayOf(vararg elements: Char): CharArray = definedExternally + +@library +public fun shortArrayOf(vararg elements: Short): ShortArray = definedExternally + +@library +public fun byteArrayOf(vararg elements: Byte): ByteArray = definedExternally + +@library +public fun booleanArrayOf(vararg elements: Boolean): BooleanArray = definedExternally + +/** + * Creates a new instance of the [Lazy] that uses the specified initialization function [initializer]. + */ +public actual fun lazy(initializer: () -> T): Lazy = UnsafeLazyImpl(initializer) + +/** + * Creates a new instance of the [Lazy] that uses the specified initialization function [initializer]. + * + * The [mode] parameter is ignored. */ +public actual fun lazy(mode: LazyThreadSafetyMode, initializer: () -> T): Lazy = UnsafeLazyImpl(initializer) + +/** + * Creates a new instance of the [Lazy] that uses the specified initialization function [initializer]. + * + * The [lock] parameter is ignored. + */ +public actual fun lazy(lock: Any?, initializer: () -> T): Lazy = UnsafeLazyImpl(initializer) + + +internal fun fillFrom(src: dynamic, dst: dynamic): dynamic { + val srcLen: Int = src.length + val dstLen: Int = dst.length + var index: Int = 0 + while (index < srcLen && index < dstLen) dst[index] = src[index++] + return dst +} + + +internal fun arrayCopyResize(source: dynamic, newSize: Int, defaultValue: Any?): dynamic { + val result = source.slice(0, newSize) + copyArrayType(source, result) + var index: Int = source.length + if (newSize > index) { + result.length = newSize + while (index < newSize) result[index++] = defaultValue + } + return result +} + +internal fun arrayPlusCollection(array: dynamic, collection: Collection): dynamic { + return TODO() + // val result = array.slice() + // result.length += collection.size + // copyArrayType(array, result) + // var index: Int = array.length + // for (element in collection) result[index++] = element + // return result +} + +internal fun fillFromCollection(dst: dynamic, startIndex: Int, collection: Collection): dynamic { + var index = startIndex + for (element in collection) dst[index++] = element + return dst +} + +internal inline fun copyArrayType(from: dynamic, to: dynamic) { + if (from.`$type$` !== undefined) { + to.`$type$` = from.`$type$` + } +} diff --git a/libraries/stdlib/js/irRuntime/longjs.kt b/libraries/stdlib/js/irRuntime/longjs.kt index cbf82e39a10..6ce379a3998 100644 --- a/libraries/stdlib/js/irRuntime/longjs.kt +++ b/libraries/stdlib/js/irRuntime/longjs.kt @@ -258,7 +258,10 @@ internal fun Long.divide(other: Long): Long { // 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() - val delta = if (log2 <= 48) 1.0 else js("Math.pow(2, log2 - 48)").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() // Decrease the approximation until it is smaller than the remainder. Note // that if it is too large, the product overflows and is negative.