[JS] Replace J2V8 based ScriptEngine with a process-based version
The main advantage of this is that we can use a newer and official build of V8. Also, with new infra, we can use other JS engines. Other changes: * ScriptEngine API is simplified and documented. * Introduce ScriptEngineWithTypedResult with typed `eval`, mostly for JsReplEvaluator and JsScriptEvaluator. * J2V8 version is completely removed. * Use new ScriptEngineV8 everywhere by default. * System property `kotlin.js.useNashorn` switches to Nashorn in all tests.
This commit is contained in:
@@ -8,7 +8,7 @@ dependencies {
|
|||||||
compile(project(":compiler:util"))
|
compile(project(":compiler:util"))
|
||||||
compile(project(":js:js.ast"))
|
compile(project(":js:js.ast"))
|
||||||
compile(project(":js:js.translator"))
|
compile(project(":js:js.translator"))
|
||||||
compileOnly(intellijCoreDep()) { includeJars("intellij-core") }
|
compile(intellijCoreDep()) { includeJars("intellij-core") }
|
||||||
}
|
}
|
||||||
|
|
||||||
sourceSets {
|
sourceSets {
|
||||||
|
|||||||
@@ -0,0 +1,96 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2020 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 org.jetbrains.kotlin.js.engine
|
||||||
|
|
||||||
|
import com.intellij.openapi.util.text.StringUtil
|
||||||
|
|
||||||
|
private val LINE_SEPARATOR = System.getProperty("line.separator")!!
|
||||||
|
private val END_MARKER = "<END>$LINE_SEPARATOR"
|
||||||
|
|
||||||
|
abstract class ProcessBasedScriptEngine(
|
||||||
|
private val executablePath: String
|
||||||
|
) : ScriptEngine {
|
||||||
|
|
||||||
|
private var process: Process? = null
|
||||||
|
private val buffer = ByteArray(1024)
|
||||||
|
|
||||||
|
override fun eval(script: String): String {
|
||||||
|
val vm = getOrCreateProcess()
|
||||||
|
|
||||||
|
val stdin = vm.outputStream
|
||||||
|
val stdout = vm.inputStream
|
||||||
|
val stderr = vm.errorStream
|
||||||
|
|
||||||
|
val writer = stdin.writer()
|
||||||
|
writer.write(StringUtil.convertLineSeparators(script, "\\n") + "\n")
|
||||||
|
writer.flush()
|
||||||
|
|
||||||
|
val out = StringBuilder()
|
||||||
|
|
||||||
|
while (vm.isAlive) {
|
||||||
|
val n = stdout.available()
|
||||||
|
if (n == 0) continue
|
||||||
|
|
||||||
|
val count = stdout.read(buffer)
|
||||||
|
|
||||||
|
val s = String(buffer, 0, count)
|
||||||
|
out.append(s)
|
||||||
|
|
||||||
|
if (out.endsWith(END_MARKER)) break
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stderr.available() > 0) {
|
||||||
|
val err = StringBuilder()
|
||||||
|
|
||||||
|
while (vm.isAlive && stderr.available() > 0) {
|
||||||
|
val count = stderr.read(buffer)
|
||||||
|
val s = String(buffer, 0, count)
|
||||||
|
err.append(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
error("ERROR:\n$err\nOUTPUT:\n$out")
|
||||||
|
}
|
||||||
|
|
||||||
|
return out.removeSuffix(END_MARKER).removeSuffix(LINE_SEPARATOR).toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun loadFile(path: String) {
|
||||||
|
eval("load('${path.replace('\\', '/')}');")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun reset() {
|
||||||
|
eval("!reset")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun saveGlobalState() {
|
||||||
|
eval("!saveGlobalState")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun restoreGlobalState() {
|
||||||
|
eval("!restoreGlobalState")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun release() {
|
||||||
|
process?.destroy()
|
||||||
|
process = null
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getOrCreateProcess(): Process {
|
||||||
|
val p = process
|
||||||
|
|
||||||
|
if (p != null && p.isAlive) return p
|
||||||
|
|
||||||
|
process = null
|
||||||
|
|
||||||
|
val builder = ProcessBuilder(
|
||||||
|
executablePath,
|
||||||
|
"js/js.engines/src/org/jetbrains/kotlin/js/engine/repl.js",
|
||||||
|
)
|
||||||
|
return builder.start().also {
|
||||||
|
process = it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,18 +1,48 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
* Copyright 2010-2020 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.
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.jetbrains.kotlin.js.engine
|
package org.jetbrains.kotlin.js.engine
|
||||||
|
|
||||||
interface ScriptEngine {
|
interface ScriptEngine {
|
||||||
fun <T> eval(script: String): T
|
fun eval(script: String): String
|
||||||
fun evalVoid(script: String)
|
|
||||||
fun <T> callMethod(obj: Any, name: String, vararg args: Any?): T
|
|
||||||
fun loadFile(path: String)
|
|
||||||
fun release()
|
|
||||||
fun <T> releaseObject(t: T)
|
|
||||||
|
|
||||||
fun saveState()
|
// TODO Add API to load few files at once?
|
||||||
fun restoreState()
|
fun loadFile(path: String)
|
||||||
}
|
|
||||||
|
/**
|
||||||
|
* Performs truly reset of the engine state.
|
||||||
|
* */
|
||||||
|
fun reset()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saves current state of global object.
|
||||||
|
*
|
||||||
|
* See also [restoreGlobalState]
|
||||||
|
*/
|
||||||
|
fun saveGlobalState()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Restores global object from the last saved state.
|
||||||
|
*
|
||||||
|
* See also [saveGlobalState]
|
||||||
|
*/
|
||||||
|
fun restoreGlobalState()
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Release held resources.
|
||||||
|
*
|
||||||
|
* Must be called explicitly before an object is garbage collected to avoid leaking resources.
|
||||||
|
*/
|
||||||
|
fun release()
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ScriptEngineWithTypedResult : ScriptEngine {
|
||||||
|
fun <R> evalWithTypedResult(script: String): R
|
||||||
|
}
|
||||||
|
|
||||||
|
fun ScriptEngine.loadFiles(files: List<String>) {
|
||||||
|
files.forEach { loadFile(it) }
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,53 +1,49 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
* Copyright 2010-2020 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.
|
* 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("JAVA_MODULE_DOES_NOT_EXPORT_PACKAGE")
|
@file:Suppress("JAVA_MODULE_DOES_NOT_EXPORT_PACKAGE")
|
||||||
package org.jetbrains.kotlin.js.engine
|
package org.jetbrains.kotlin.js.engine
|
||||||
|
|
||||||
|
import jdk.nashorn.api.scripting.NashornScriptEngine
|
||||||
import jdk.nashorn.api.scripting.NashornScriptEngineFactory
|
import jdk.nashorn.api.scripting.NashornScriptEngineFactory
|
||||||
import jdk.nashorn.internal.runtime.ScriptRuntime
|
import jdk.nashorn.internal.runtime.ScriptRuntime
|
||||||
import javax.script.Invocable
|
|
||||||
|
|
||||||
class ScriptEngineNashorn : ScriptEngine {
|
class ScriptEngineNashorn : ScriptEngineWithTypedResult {
|
||||||
private var savedState: Map<String, Any?>? = null
|
private var savedState: Map<String, Any?>? = null
|
||||||
|
|
||||||
// TODO use "-strict"
|
// TODO use "-strict"
|
||||||
private val myEngine = NashornScriptEngineFactory().getScriptEngine("--language=es5", "--no-java", "--no-syntax-extensions")
|
private val myEngine = NashornScriptEngineFactory().getScriptEngine("--language=es5", "--no-java", "--no-syntax-extensions")
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
override fun eval(script: String): String = evalWithTypedResult<Any?>(script).toString()
|
||||||
override fun <T> eval(script: String): T {
|
|
||||||
return myEngine.eval(script) as T
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun evalVoid(script: String) {
|
|
||||||
myEngine.eval(script)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
override fun <T> callMethod(obj: Any, name: String, vararg args: Any?): T {
|
override fun <R> evalWithTypedResult(script: String): R {
|
||||||
return (myEngine as Invocable).invokeMethod(obj, name, *args) as T
|
return myEngine.eval(script) as R
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun loadFile(path: String) {
|
override fun loadFile(path: String) {
|
||||||
evalVoid("load('${path.replace('\\', '/')}');")
|
eval("load('${path.replace('\\', '/')}');")
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun release() {}
|
override fun reset() {
|
||||||
override fun <T> releaseObject(t: T) {}
|
throw UnsupportedOperationException()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getGlobalState(): MutableMap<String, Any?> = evalWithTypedResult("this")
|
||||||
|
|
||||||
private fun getGlobalState(): MutableMap<String, Any?> = eval("this")
|
override fun saveGlobalState() {
|
||||||
|
|
||||||
override fun saveState() {
|
|
||||||
savedState = getGlobalState().toMap()
|
savedState = getGlobalState().toMap()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun restoreState() {
|
override fun restoreGlobalState() {
|
||||||
val globalState = getGlobalState()
|
val globalState = getGlobalState()
|
||||||
val originalState = savedState!!
|
val originalState = savedState!!
|
||||||
for (key in globalState.keys) {
|
for (key in globalState.keys) {
|
||||||
globalState[key] = originalState[key] ?: ScriptRuntime.UNDEFINED
|
globalState[key] = originalState[key] ?: ScriptRuntime.UNDEFINED
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
override fun release() {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,98 +1,23 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
* Copyright 2010-2020 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.
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.jetbrains.kotlin.js.engine
|
package org.jetbrains.kotlin.js.engine
|
||||||
|
|
||||||
import com.eclipsesource.v8.V8
|
class ScriptEngineV8 : ProcessBasedScriptEngine(System.getProperty("javascript.engine.path.V8"))
|
||||||
import com.eclipsesource.v8.V8Array
|
|
||||||
import com.eclipsesource.v8.V8Object
|
|
||||||
import com.eclipsesource.v8.utils.V8ObjectUtils
|
|
||||||
import java.io.File
|
|
||||||
|
|
||||||
class ScriptEngineV8(LIBRARY_PATH_BASE: String) : ScriptEngine {
|
fun main() {
|
||||||
|
// System.setProperty("javascript.engine.path.V8", "<path-to-d8>")
|
||||||
override fun <T> releaseObject(t: T) {
|
val vm = ScriptEngineV8()
|
||||||
(t as? V8Object)?.release()
|
println("Welcome!")
|
||||||
}
|
while (true) {
|
||||||
|
print("> ")
|
||||||
private var savedState: List<String>? = null
|
val t = readLine()
|
||||||
|
try {
|
||||||
override fun restoreState() {
|
println(vm.eval(t!!))
|
||||||
val scriptBuilder = StringBuilder()
|
} catch (e: Throwable) {
|
||||||
|
System.err.println(e)
|
||||||
val globalState = getGlobalPropertyNames()
|
|
||||||
val originalState = savedState!!
|
|
||||||
for (key in globalState) {
|
|
||||||
if (key !in originalState) {
|
|
||||||
scriptBuilder.append("this['$key'] = void 0;\n")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
evalVoid(scriptBuilder.toString())
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getGlobalPropertyNames(): List<String> {
|
|
||||||
val v8Array = eval<V8Array>("Object.getOwnPropertyNames(this)")
|
|
||||||
@Suppress("UNCHECKED_CAST") val javaArray = V8ObjectUtils.toList(v8Array) as List<String>
|
|
||||||
v8Array.release()
|
|
||||||
return javaArray
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun saveState() {
|
|
||||||
if (savedState == null) {
|
|
||||||
savedState = getGlobalPropertyNames()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private val myRuntime: V8 = V8.createV8Runtime("global", LIBRARY_PATH_BASE)
|
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
|
||||||
override fun <T> eval(script: String): T {
|
|
||||||
return myRuntime.executeScript(script) as T
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun evalVoid(script: String) {
|
|
||||||
return myRuntime.executeVoidScript(script)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
|
||||||
override fun <T> callMethod(obj: Any, name: String, vararg args: Any?): T {
|
|
||||||
if (obj !is V8Object) {
|
|
||||||
throw Exception("InteropV8 can deal only with V8Object")
|
|
||||||
}
|
|
||||||
|
|
||||||
val runtimeArray = V8Array(myRuntime)
|
|
||||||
val result = obj.executeFunction(name, runtimeArray) as T
|
|
||||||
runtimeArray.release()
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun loadFile(path: String) {
|
|
||||||
myRuntime.executeVoidScript(File(path).bufferedReader().use { it.readText() }, path, 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun release() {
|
|
||||||
myRuntime.release()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ScriptEngineV8Lazy(LIBRARY_PATH_BASE: String) : ScriptEngine {
|
|
||||||
override fun <T> eval(script: String) = engine.eval<T>(script)
|
|
||||||
|
|
||||||
override fun saveState() = engine.saveState()
|
|
||||||
|
|
||||||
override fun evalVoid(script: String) = engine.evalVoid(script)
|
|
||||||
|
|
||||||
override fun <T> callMethod(obj: Any, name: String, vararg args: Any?) = engine.callMethod<T>(obj, name, args)
|
|
||||||
|
|
||||||
override fun loadFile(path: String) = engine.loadFile(path)
|
|
||||||
|
|
||||||
override fun release() = engine.release()
|
|
||||||
|
|
||||||
override fun <T> releaseObject(t: T) = engine.releaseObject(t)
|
|
||||||
|
|
||||||
override fun restoreState() = engine.restoreState()
|
|
||||||
|
|
||||||
private val engine by lazy { ScriptEngineV8(LIBRARY_PATH_BASE) }
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,101 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2020 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// <path-to-v8> js/js.engines/src/org/jetbrains/kotlin/js/engine/repl.js
|
||||||
|
|
||||||
|
/*
|
||||||
|
Some of non-standard APIs available in standalone JS engines:
|
||||||
|
|
||||||
|
v8 sm jsc
|
||||||
|
load + + + load and evaluate a file
|
||||||
|
print + + + print to stdout
|
||||||
|
printErr + + + print to stderr
|
||||||
|
read + + + read a file as a text (v8, sm, jsc) or binary (sm, jsc)
|
||||||
|
readline + + + read line from stdin
|
||||||
|
readbuffer + - - read a binary file in v8
|
||||||
|
quit + + + stop the process
|
||||||
|
|
||||||
|
V8:
|
||||||
|
https://v8.dev/docs/d8
|
||||||
|
https://github.com/v8/v8/blob/4b9b23521e6fd42373ebbcb20ebe03bf445494f9/src/d8.cc
|
||||||
|
https://riptutorial.com/v8/example/25393/useful-built-in-functions-and-objects-in-d8
|
||||||
|
|
||||||
|
SpiderMonkey:
|
||||||
|
https://developer.mozilla.org/en-US/docs/Mozilla/Projects/SpiderMonkey/Introduction_to_the_JavaScript_shell
|
||||||
|
|
||||||
|
JavaScriptCore:
|
||||||
|
https://trac.webkit.org/wiki/JSC
|
||||||
|
https://github.com/WebKit/webkit/blob/master/Source/JavaScriptCore/jsc.cpp
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {number}
|
||||||
|
*/
|
||||||
|
let currentRealmIndex = Realm.current();
|
||||||
|
|
||||||
|
function resetRealm() {
|
||||||
|
if (currentRealmIndex !== 0) Realm.dispose(currentRealmIndex);
|
||||||
|
currentRealmIndex = Realm.createAllowCrossRealmAccess()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {?Map<string, ?any>}
|
||||||
|
*/
|
||||||
|
let globalState = null;
|
||||||
|
|
||||||
|
function saveGlobalState() {
|
||||||
|
globalState = new Map();
|
||||||
|
const currentGlobal = Realm.global(currentRealmIndex)
|
||||||
|
for (const k in currentGlobal) {
|
||||||
|
globalState.set(k, currentGlobal[k]);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(Array.from(globalState.entries()))
|
||||||
|
}
|
||||||
|
|
||||||
|
function restoreGlobalState() {
|
||||||
|
if (globalState === null) throw Error("There is no saved state!")
|
||||||
|
|
||||||
|
const currentGlobal = Realm.global(currentRealmIndex)
|
||||||
|
|
||||||
|
console.log(Array.from(globalState.entries()))
|
||||||
|
|
||||||
|
for (const k in currentGlobal) {
|
||||||
|
let prev = globalState.get(k);
|
||||||
|
if (prev !== currentGlobal[k]) {
|
||||||
|
currentGlobal[k] = prev;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
globalState = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// To prevent accessing to current global state
|
||||||
|
resetRealm();
|
||||||
|
|
||||||
|
// noinspection InfiniteLoopJS
|
||||||
|
while (true) {
|
||||||
|
let code = readline().replace(/\\n/g, '\n');
|
||||||
|
|
||||||
|
try {
|
||||||
|
switch (code) {
|
||||||
|
case "!reset":
|
||||||
|
resetRealm()
|
||||||
|
break;
|
||||||
|
case "!saveGlobalState":
|
||||||
|
saveGlobalState();
|
||||||
|
break;
|
||||||
|
case "!restoreGlobalState":
|
||||||
|
restoreGlobalState();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
print(Realm.eval(currentRealmIndex, code));
|
||||||
|
}
|
||||||
|
} catch(e) {
|
||||||
|
printErr(e.stack != null ? e.stack : e.toString());
|
||||||
|
printErr('\nCODE:\n' + code);
|
||||||
|
}
|
||||||
|
|
||||||
|
print('<END>');
|
||||||
|
}
|
||||||
@@ -32,8 +32,7 @@ import org.jetbrains.kotlin.js.config.*
|
|||||||
import org.jetbrains.kotlin.js.dce.DeadCodeElimination
|
import org.jetbrains.kotlin.js.dce.DeadCodeElimination
|
||||||
import org.jetbrains.kotlin.js.dce.InputFile
|
import org.jetbrains.kotlin.js.dce.InputFile
|
||||||
import org.jetbrains.kotlin.js.dce.InputResource
|
import org.jetbrains.kotlin.js.dce.InputResource
|
||||||
import org.jetbrains.kotlin.js.engine.ScriptEngineNashorn
|
import org.jetbrains.kotlin.js.engine.loadFiles
|
||||||
import org.jetbrains.kotlin.js.engine.ScriptEngineV8Lazy
|
|
||||||
import org.jetbrains.kotlin.js.facade.*
|
import org.jetbrains.kotlin.js.facade.*
|
||||||
import org.jetbrains.kotlin.js.parser.parse
|
import org.jetbrains.kotlin.js.parser.parse
|
||||||
import org.jetbrains.kotlin.js.parser.sourcemaps.SourceMapError
|
import org.jetbrains.kotlin.js.parser.sourcemaps.SourceMapError
|
||||||
@@ -878,9 +877,9 @@ abstract class BasicBoxTest(
|
|||||||
runList += allJsFiles.map { filesToMinify[it]?.outputPath ?: it }
|
runList += allJsFiles.map { filesToMinify[it]?.outputPath ?: it }
|
||||||
|
|
||||||
val result = engineForMinifier.runAndRestoreContext {
|
val result = engineForMinifier.runAndRestoreContext {
|
||||||
runList.forEach(this::loadFile)
|
loadFiles(runList)
|
||||||
overrideAsserter()
|
overrideAsserter()
|
||||||
eval<String>(SETUP_KOTLIN_OUTPUT)
|
eval(SETUP_KOTLIN_OUTPUT)
|
||||||
runTestFunction(testModuleName, testPackage, testFunction, withModuleSystem)
|
runTestFunction(testModuleName, testPackage, testFunction, withModuleSystem)
|
||||||
}
|
}
|
||||||
TestCase.assertEquals(expectedResult, result)
|
TestCase.assertEquals(expectedResult, result)
|
||||||
@@ -1047,9 +1046,7 @@ abstract class BasicBoxTest(
|
|||||||
private const val OLD_MODULE_SUFFIX = "-old"
|
private const val OLD_MODULE_SUFFIX = "-old"
|
||||||
|
|
||||||
const val KOTLIN_TEST_INTERNAL = "\$kotlin_test_internal\$"
|
const val KOTLIN_TEST_INTERNAL = "\$kotlin_test_internal\$"
|
||||||
private val engineForMinifier =
|
private val engineForMinifier = createScriptEngine()
|
||||||
if (runTestInNashorn) ScriptEngineNashorn()
|
|
||||||
else ScriptEngineV8Lazy(KotlinTestUtils.tmpDirForReusableFolder("j2v8_library_path").path)
|
|
||||||
|
|
||||||
const val overwriteReachableNodesProperty = "kotlin.js.overwriteReachableNodes"
|
const val overwriteReachableNodesProperty = "kotlin.js.overwriteReachableNodes"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,22 +1,23 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
* Copyright 2010-2020 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.
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.jetbrains.kotlin.js.test
|
package org.jetbrains.kotlin.js.test
|
||||||
|
|
||||||
|
import com.intellij.openapi.util.text.StringUtil
|
||||||
import org.jetbrains.kotlin.js.engine.ScriptEngine
|
import org.jetbrains.kotlin.js.engine.ScriptEngine
|
||||||
import org.jetbrains.kotlin.js.engine.ScriptEngineNashorn
|
import org.jetbrains.kotlin.js.engine.ScriptEngineNashorn
|
||||||
import org.jetbrains.kotlin.js.engine.ScriptEngineV8
|
import org.jetbrains.kotlin.js.engine.ScriptEngineV8
|
||||||
import org.jetbrains.kotlin.test.KotlinTestUtils
|
import org.jetbrains.kotlin.js.engine.loadFiles
|
||||||
import org.junit.Assert
|
import org.junit.Assert
|
||||||
|
|
||||||
fun createScriptEngine(): ScriptEngine {
|
fun createScriptEngine(): ScriptEngine {
|
||||||
return ScriptEngineNashorn()
|
return if (java.lang.Boolean.getBoolean("kotlin.js.useNashorn")) ScriptEngineNashorn() else ScriptEngineV8()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun ScriptEngine.overrideAsserter() {
|
fun ScriptEngine.overrideAsserter() {
|
||||||
evalVoid("this['kotlin-test'].kotlin.test.overrideAsserter_wbnzx$(this['kotlin-test'].kotlin.test.DefaultAsserter);")
|
eval("this['kotlin-test'].kotlin.test.overrideAsserter_wbnzx$(this['kotlin-test'].kotlin.test.DefaultAsserter);")
|
||||||
}
|
}
|
||||||
|
|
||||||
fun ScriptEngine.runTestFunction(
|
fun ScriptEngine.runTestFunction(
|
||||||
@@ -24,7 +25,7 @@ fun ScriptEngine.runTestFunction(
|
|||||||
testPackageName: String?,
|
testPackageName: String?,
|
||||||
testFunctionName: String,
|
testFunctionName: String,
|
||||||
withModuleSystem: Boolean
|
withModuleSystem: Boolean
|
||||||
): String? {
|
): String {
|
||||||
var script = when {
|
var script = when {
|
||||||
withModuleSystem -> BasicBoxTest.KOTLIN_TEST_INTERNAL + ".require('" + testModuleName!! + "')"
|
withModuleSystem -> BasicBoxTest.KOTLIN_TEST_INTERNAL + ".require('" + testModuleName!! + "')"
|
||||||
testModuleName === null -> "this"
|
testModuleName === null -> "this"
|
||||||
@@ -35,10 +36,9 @@ fun ScriptEngine.runTestFunction(
|
|||||||
script += ".$testPackageName"
|
script += ".$testPackageName"
|
||||||
}
|
}
|
||||||
|
|
||||||
val testPackage = eval<Any>(script)
|
script += ".$testFunctionName()"
|
||||||
return callMethod<String?>(testPackage, testFunctionName).also {
|
|
||||||
releaseObject(testPackage)
|
return eval(script)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class AbstractJsTestChecker {
|
abstract class AbstractJsTestChecker {
|
||||||
@@ -51,7 +51,7 @@ abstract class AbstractJsTestChecker {
|
|||||||
withModuleSystem: Boolean
|
withModuleSystem: Boolean
|
||||||
) {
|
) {
|
||||||
val actualResult = run(files, testModuleName, testPackageName, testFunctionName, withModuleSystem)
|
val actualResult = run(files, testModuleName, testPackageName, testFunctionName, withModuleSystem)
|
||||||
Assert.assertEquals(expectedResult, actualResult)
|
Assert.assertEquals(expectedResult, actualResult.normalize())
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun run(
|
private fun run(
|
||||||
@@ -66,20 +66,28 @@ abstract class AbstractJsTestChecker {
|
|||||||
|
|
||||||
|
|
||||||
fun run(files: List<String>) {
|
fun run(files: List<String>) {
|
||||||
run(files) { null }
|
run(files) { "" }
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract fun checkStdout(files: List<String>, expectedResult: String)
|
fun checkStdout(files: List<String>, expectedResult: String) {
|
||||||
|
run(files) {
|
||||||
|
val actualResult = eval(GET_KOTLIN_OUTPUT)
|
||||||
|
Assert.assertEquals(expectedResult, actualResult.normalize())
|
||||||
|
""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected abstract fun run(files: List<String>, f: ScriptEngine.() -> Any?): Any?
|
private fun String.normalize() = StringUtil.convertLineSeparators(this)
|
||||||
|
|
||||||
|
protected abstract fun run(files: List<String>, f: ScriptEngine.() -> String): String
|
||||||
}
|
}
|
||||||
|
|
||||||
fun ScriptEngine.runAndRestoreContext(f: ScriptEngine.() -> Any?): Any? {
|
fun ScriptEngine.runAndRestoreContext(f: ScriptEngine.() -> String): String {
|
||||||
return try {
|
return try {
|
||||||
saveState()
|
saveGlobalState()
|
||||||
f()
|
f()
|
||||||
} finally {
|
} finally {
|
||||||
restoreState()
|
restoreGlobalState()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -96,7 +104,7 @@ abstract class AbstractNashornJsTestChecker : AbstractJsTestChecker() {
|
|||||||
|
|
||||||
protected open fun beforeRun() {}
|
protected open fun beforeRun() {}
|
||||||
|
|
||||||
override fun run(files: List<String>, f: ScriptEngine.() -> Any?): Any? {
|
override fun run(files: List<String>, f: ScriptEngine.() -> String): String {
|
||||||
// Recreate the engine once in a while
|
// Recreate the engine once in a while
|
||||||
if (engineUsageCnt++ > 100) {
|
if (engineUsageCnt++ > 100) {
|
||||||
engineUsageCnt = 0
|
engineUsageCnt = 0
|
||||||
@@ -106,23 +114,17 @@ abstract class AbstractNashornJsTestChecker : AbstractJsTestChecker() {
|
|||||||
beforeRun()
|
beforeRun()
|
||||||
|
|
||||||
return engine.runAndRestoreContext {
|
return engine.runAndRestoreContext {
|
||||||
files.forEach { loadFile(it) }
|
loadFiles(files)
|
||||||
f()
|
f()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun checkStdout(files: List<String>, expectedResult: String) {
|
|
||||||
run(files)
|
|
||||||
val actualResult = engine.eval<String>(GET_KOTLIN_OUTPUT)
|
|
||||||
Assert.assertEquals(expectedResult, actualResult)
|
|
||||||
}
|
|
||||||
|
|
||||||
protected abstract val preloadedScripts: List<String>
|
protected abstract val preloadedScripts: List<String>
|
||||||
|
|
||||||
protected open fun createScriptEngineForTest(): ScriptEngineNashorn {
|
protected open fun createScriptEngineForTest(): ScriptEngineNashorn {
|
||||||
val engine = ScriptEngineNashorn()
|
val engine = ScriptEngineNashorn()
|
||||||
|
|
||||||
preloadedScripts.forEach { engine.loadFile(it) }
|
engine.loadFiles(preloadedScripts)
|
||||||
|
|
||||||
return engine
|
return engine
|
||||||
}
|
}
|
||||||
@@ -134,7 +136,7 @@ const val GET_KOTLIN_OUTPUT = "kotlin.kotlin.io.output.buffer;"
|
|||||||
object NashornJsTestChecker : AbstractNashornJsTestChecker() {
|
object NashornJsTestChecker : AbstractNashornJsTestChecker() {
|
||||||
|
|
||||||
override fun beforeRun() {
|
override fun beforeRun() {
|
||||||
engine.evalVoid(SETUP_KOTLIN_OUTPUT)
|
engine.eval(SETUP_KOTLIN_OUTPUT)
|
||||||
}
|
}
|
||||||
|
|
||||||
override val preloadedScripts = listOf(
|
override val preloadedScripts = listOf(
|
||||||
@@ -159,69 +161,50 @@ class NashornIrJsTestChecker : AbstractNashornJsTestChecker() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class AbstractV8JsTestChecker : AbstractJsTestChecker() {
|
object V8JsTestChecker : AbstractJsTestChecker() {
|
||||||
protected abstract val engine: ScriptEngineV8
|
private val engineTL = object : ThreadLocal<ScriptEngineV8>() {
|
||||||
|
override fun initialValue() =
|
||||||
|
ScriptEngineV8().apply {
|
||||||
|
val preloadedScripts = listOf(
|
||||||
|
BasicBoxTest.DIST_DIR_JS_PATH + "kotlin.js",
|
||||||
|
BasicBoxTest.DIST_DIR_JS_PATH + "kotlin-test.js"
|
||||||
|
)
|
||||||
|
loadFiles(preloadedScripts)
|
||||||
|
|
||||||
override fun checkStdout(files: List<String>, expectedResult: String) {
|
overrideAsserter()
|
||||||
run(files) {
|
}
|
||||||
val actualResult = engine.eval<String>(GET_KOTLIN_OUTPUT)
|
|
||||||
Assert.assertEquals(expectedResult, actualResult)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
object V8JsTestChecker : AbstractV8JsTestChecker() {
|
|
||||||
override val engine get() = tlsEngine.get()
|
|
||||||
|
|
||||||
private val tlsEngine = object : ThreadLocal<ScriptEngineV8>() {
|
|
||||||
override fun initialValue() = createV8Engine()
|
|
||||||
override fun remove() {
|
override fun remove() {
|
||||||
get().release()
|
get().release()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createV8Engine(): ScriptEngineV8 {
|
private val engine get() = engineTL.get()
|
||||||
val v8 = ScriptEngineV8(KotlinTestUtils.tmpDirForReusableFolder("j2v8_library_path").path)
|
|
||||||
|
|
||||||
listOf(
|
override fun run(files: List<String>, f: ScriptEngine.() -> String): String {
|
||||||
BasicBoxTest.DIST_DIR_JS_PATH + "kotlin.js",
|
engine.eval(SETUP_KOTLIN_OUTPUT)
|
||||||
BasicBoxTest.DIST_DIR_JS_PATH + "kotlin-test.js"
|
|
||||||
).forEach { v8.loadFile(it) }
|
|
||||||
|
|
||||||
v8.overrideAsserter()
|
|
||||||
|
|
||||||
return v8
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun run(files: List<String>, f: ScriptEngine.() -> Any?): Any? {
|
|
||||||
engine.evalVoid(SETUP_KOTLIN_OUTPUT)
|
|
||||||
return engine.runAndRestoreContext {
|
return engine.runAndRestoreContext {
|
||||||
files.forEach { loadFile(it) }
|
loadFiles(files)
|
||||||
f()
|
f()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
object V8IrJsTestChecker : AbstractV8JsTestChecker() {
|
object V8IrJsTestChecker : AbstractJsTestChecker() {
|
||||||
override val engine get() = ScriptEngineV8(KotlinTestUtils.tmpDirForReusableFolder("j2v8_library_path").path)
|
private val engineTL = object : ThreadLocal<ScriptEngineV8>() {
|
||||||
|
override fun initialValue() = ScriptEngineV8()
|
||||||
override fun run(files: List<String>, f: ScriptEngine.() -> Any?): Any? {
|
override fun remove() {
|
||||||
|
get().release()
|
||||||
val v8 = engine
|
|
||||||
|
|
||||||
val v = try {
|
|
||||||
files.forEach { v8.loadFile(it) }
|
|
||||||
v8.f()
|
|
||||||
} catch (t: Throwable) {
|
|
||||||
try {
|
|
||||||
v8.release()
|
|
||||||
} finally {
|
|
||||||
// Don't mask the original exception
|
|
||||||
throw t
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
v8.release()
|
|
||||||
|
|
||||||
return v
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
override fun run(files: List<String>, f: ScriptEngine.() -> String): String {
|
||||||
|
val engine = engineTL.get()
|
||||||
|
return try {
|
||||||
|
engine.loadFiles(files)
|
||||||
|
engine.f()
|
||||||
|
} finally {
|
||||||
|
engine.reset()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,17 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2016 JetBrains s.r.o.
|
* Copyright 2010-2020 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.
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.jetbrains.kotlin.js.test.optimizer
|
package org.jetbrains.kotlin.js.test.optimizer
|
||||||
@@ -128,8 +117,8 @@ abstract class BasicOptimizerTest(private var basePath: String) {
|
|||||||
|
|
||||||
private fun runScript(fileName: String, code: String) {
|
private fun runScript(fileName: String, code: String) {
|
||||||
val engine = createScriptEngine()
|
val engine = createScriptEngine()
|
||||||
engine.evalVoid(code)
|
engine.eval(code)
|
||||||
val result = engine.eval<String>("box()")
|
val result = engine.eval("box()")
|
||||||
|
|
||||||
Assert.assertEquals("$fileName: box() function must return 'OK'", "OK", result)
|
Assert.assertEquals("$fileName: box() function must return 'OK'", "OK", result)
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-5
@@ -1,15 +1,14 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
* Copyright 2010-2020 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.
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.jetbrains.kotlin.js.test.semantics
|
package org.jetbrains.kotlin.js.test.semantics
|
||||||
|
|
||||||
import com.eclipsesource.v8.V8ScriptException
|
|
||||||
import com.google.common.collect.Lists
|
import com.google.common.collect.Lists
|
||||||
import com.intellij.openapi.util.text.StringUtil
|
import com.intellij.openapi.util.text.StringUtil
|
||||||
import org.jetbrains.kotlin.js.facade.MainCallParameters
|
import org.jetbrains.kotlin.js.facade.MainCallParameters
|
||||||
import org.jetbrains.kotlin.js.test.*
|
import org.jetbrains.kotlin.js.test.BasicBoxTest
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import javax.script.ScriptException
|
import javax.script.ScriptException
|
||||||
|
|
||||||
@@ -29,7 +28,7 @@ abstract class AbstractWebDemoExamplesTest(relativePath: String) : BasicBoxTest(
|
|||||||
testChecker.checkStdout(jsFiles, expectedResult)
|
testChecker.checkStdout(jsFiles, expectedResult)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Throws(ScriptException::class, V8ScriptException::class)
|
@Throws(ScriptException::class)
|
||||||
protected fun runMainAndCheckOutput(fileName: String, expectedResult: String, vararg args: String) {
|
protected fun runMainAndCheckOutput(fileName: String, expectedResult: String, vararg args: String) {
|
||||||
doTest(pathToTestDir + fileName, expectedResult, MainCallParameters.mainWithArguments(Lists.newArrayList(*args)))
|
doTest(pathToTestDir + fileName, expectedResult, MainCallParameters.mainWithArguments(Lists.newArrayList(*args)))
|
||||||
}
|
}
|
||||||
@@ -38,4 +37,4 @@ abstract class AbstractWebDemoExamplesTest(relativePath: String) : BasicBoxTest(
|
|||||||
val expectedResult = StringUtil.convertLineSeparators(File(pathToTestDir + testName + testId + ".out").readText())
|
val expectedResult = StringUtil.convertLineSeparators(File(pathToTestDir + testName + testId + ".out").readText())
|
||||||
doTest(pathToTestDir + testName + ".kt", expectedResult, MainCallParameters.mainWithArguments(Lists.newArrayList(*args)))
|
doTest(pathToTestDir + testName + ".kt", expectedResult, MainCallParameters.mainWithArguments(Lists.newArrayList(*args)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,22 +1,10 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2016 JetBrains s.r.o.
|
* Copyright 2010-2020 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.
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.jetbrains.kotlin.js.test.semantics
|
package org.jetbrains.kotlin.js.test.semantics
|
||||||
|
|
||||||
import com.eclipsesource.v8.V8ScriptException
|
|
||||||
import org.jetbrains.kotlin.js.test.BasicBoxTest
|
import org.jetbrains.kotlin.js.test.BasicBoxTest
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import javax.script.ScriptException
|
import javax.script.ScriptException
|
||||||
@@ -47,7 +35,7 @@ class MultiModuleOrderTest : BasicBoxTest(pathToTestGroupDir, testGroupDir) {
|
|||||||
testChecker.run(listOf(mainJsFile, libJsFile))
|
testChecker.run(listOf(mainJsFile, libJsFile))
|
||||||
}
|
}
|
||||||
catch (e: RuntimeException) {
|
catch (e: RuntimeException) {
|
||||||
assertTrue(e is ScriptException || e is V8ScriptException)
|
assertTrue(e is ScriptException || e is IllegalStateException)
|
||||||
val message = e.message!!
|
val message = e.message!!
|
||||||
assertTrue("Exception message should contain reference to dependency (lib)", "'lib'" in message)
|
assertTrue("Exception message should contain reference to dependency (lib)", "'lib'" in message)
|
||||||
assertTrue("Exception message should contain reference to module that failed to load (main)", "'main'" in message)
|
assertTrue("Exception message should contain reference to module that failed to load (main)", "'main'" in message)
|
||||||
|
|||||||
+7
-19
@@ -1,22 +1,10 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2015 JetBrains s.r.o.
|
* Copyright 2010-2020 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.
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.jetbrains.kotlin.js.test.semantics;
|
package org.jetbrains.kotlin.js.test.semantics;
|
||||||
|
|
||||||
import com.eclipsesource.v8.V8ScriptException;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import javax.script.ScriptException;
|
import javax.script.ScriptException;
|
||||||
@@ -55,16 +43,16 @@ public final class WebDemoCanvasExamplesTest extends AbstractWebDemoExamplesTest
|
|||||||
catch (ScriptException e) {
|
catch (ScriptException e) {
|
||||||
verifyException("\"" + firstUnknownSymbolEncountered + "\"", e.getMessage());
|
verifyException("\"" + firstUnknownSymbolEncountered + "\"", e.getMessage());
|
||||||
}
|
}
|
||||||
catch (V8ScriptException e) {
|
catch (IllegalStateException e) {
|
||||||
verifyException(firstUnknownSymbolEncountered, e.getJSMessage());
|
verifyException(firstUnknownSymbolEncountered, e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void verifyException(@NotNull String firstUnknownSymbolEncountered, @NotNull String message) {
|
private static void verifyException(@NotNull String firstUnknownSymbolEncountered, @NotNull String message) {
|
||||||
String expectedErrorMessage = "ReferenceError: " + firstUnknownSymbolEncountered + " is not defined";
|
String expectedErrorMessage = "ReferenceError: " + firstUnknownSymbolEncountered + " is not defined";
|
||||||
assertTrue("Unexpected error when running compiled canvas examples with rhino.\n" +
|
assertTrue("Unexpected error when running compiled canvas examples with rhino.\n" +
|
||||||
"Expected: " + expectedErrorMessage + "\n" +
|
"Expected message contains \"" + expectedErrorMessage + "\".\n" +
|
||||||
"Actual: " + message,
|
"Message: " + message,
|
||||||
message.startsWith(expectedErrorMessage));
|
message.contains(expectedErrorMessage));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
* Copyright 2010-2020 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.
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -21,7 +21,7 @@ class JsReplEvaluator : ReplEvaluator {
|
|||||||
): ReplEvalResult {
|
): ReplEvalResult {
|
||||||
return try {
|
return try {
|
||||||
val evaluationState = state.asState(JsEvaluationState::class.java)
|
val evaluationState = state.asState(JsEvaluationState::class.java)
|
||||||
val evalResult = evaluationState.engine.eval<Any?>(compileResult.data as String)
|
val evalResult = evaluationState.engine.evalWithTypedResult<Any?>(compileResult.data as String)
|
||||||
ReplEvalResult.ValueResult("result", evalResult, "Any?")
|
ReplEvalResult.ValueResult("result", evalResult, "Any?")
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
ReplEvalResult.Error.Runtime("Error while evaluating", e)
|
ReplEvalResult.Error.Runtime("Error while evaluating", e)
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
* Copyright 2010-2020 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.
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -9,7 +9,7 @@ import org.jetbrains.kotlin.cli.common.repl.*
|
|||||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.ScriptDescriptor
|
import org.jetbrains.kotlin.descriptors.ScriptDescriptor
|
||||||
import org.jetbrains.kotlin.ir.backend.js.utils.NameTables
|
import org.jetbrains.kotlin.ir.backend.js.utils.NameTables
|
||||||
import org.jetbrains.kotlin.js.engine.ScriptEngine
|
import org.jetbrains.kotlin.js.engine.ScriptEngineWithTypedResult
|
||||||
import java.util.concurrent.locks.ReentrantReadWriteLock
|
import java.util.concurrent.locks.ReentrantReadWriteLock
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
import kotlin.script.experimental.api.CompiledScript
|
import kotlin.script.experimental.api.CompiledScript
|
||||||
@@ -31,9 +31,9 @@ abstract class JsCompilationState(
|
|||||||
val nameTables: NameTables,
|
val nameTables: NameTables,
|
||||||
val dependencies: List<ModuleDescriptor>) : JsState(lock)
|
val dependencies: List<ModuleDescriptor>) : JsState(lock)
|
||||||
|
|
||||||
class JsEvaluationState(lock: ReentrantReadWriteLock, val engine: ScriptEngine) : JsState(lock) {
|
class JsEvaluationState(lock: ReentrantReadWriteLock, val engine: ScriptEngineWithTypedResult) : JsState(lock) {
|
||||||
override fun dispose() {
|
override fun dispose() {
|
||||||
engine.release()
|
engine.reset()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
* Copyright 2010-2020 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.
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -17,7 +17,7 @@ class JsScriptEvaluator : ScriptEvaluator {
|
|||||||
scriptEvaluationConfiguration: ScriptEvaluationConfiguration
|
scriptEvaluationConfiguration: ScriptEvaluationConfiguration
|
||||||
): ResultWithDiagnostics<EvaluationResult> {
|
): ResultWithDiagnostics<EvaluationResult> {
|
||||||
return try {
|
return try {
|
||||||
val evalResult = engine.eval<Any?>((compiledScript as JsCompiledScript).jsCode)
|
val evalResult = engine.evalWithTypedResult<Any?>((compiledScript as JsCompiledScript).jsCode)
|
||||||
ResultWithDiagnostics.Success(
|
ResultWithDiagnostics.Success(
|
||||||
EvaluationResult(
|
EvaluationResult(
|
||||||
ResultValue.Value(
|
ResultValue.Value(
|
||||||
|
|||||||
Reference in New Issue
Block a user