[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:
@@ -32,8 +32,7 @@ import org.jetbrains.kotlin.js.config.*
|
||||
import org.jetbrains.kotlin.js.dce.DeadCodeElimination
|
||||
import org.jetbrains.kotlin.js.dce.InputFile
|
||||
import org.jetbrains.kotlin.js.dce.InputResource
|
||||
import org.jetbrains.kotlin.js.engine.ScriptEngineNashorn
|
||||
import org.jetbrains.kotlin.js.engine.ScriptEngineV8Lazy
|
||||
import org.jetbrains.kotlin.js.engine.loadFiles
|
||||
import org.jetbrains.kotlin.js.facade.*
|
||||
import org.jetbrains.kotlin.js.parser.parse
|
||||
import org.jetbrains.kotlin.js.parser.sourcemaps.SourceMapError
|
||||
@@ -878,9 +877,9 @@ abstract class BasicBoxTest(
|
||||
runList += allJsFiles.map { filesToMinify[it]?.outputPath ?: it }
|
||||
|
||||
val result = engineForMinifier.runAndRestoreContext {
|
||||
runList.forEach(this::loadFile)
|
||||
loadFiles(runList)
|
||||
overrideAsserter()
|
||||
eval<String>(SETUP_KOTLIN_OUTPUT)
|
||||
eval(SETUP_KOTLIN_OUTPUT)
|
||||
runTestFunction(testModuleName, testPackage, testFunction, withModuleSystem)
|
||||
}
|
||||
TestCase.assertEquals(expectedResult, result)
|
||||
@@ -1047,9 +1046,7 @@ abstract class BasicBoxTest(
|
||||
private const val OLD_MODULE_SUFFIX = "-old"
|
||||
|
||||
const val KOTLIN_TEST_INTERNAL = "\$kotlin_test_internal\$"
|
||||
private val engineForMinifier =
|
||||
if (runTestInNashorn) ScriptEngineNashorn()
|
||||
else ScriptEngineV8Lazy(KotlinTestUtils.tmpDirForReusableFolder("j2v8_library_path").path)
|
||||
private val engineForMinifier = createScriptEngine()
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
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.ScriptEngineNashorn
|
||||
import org.jetbrains.kotlin.js.engine.ScriptEngineV8
|
||||
import org.jetbrains.kotlin.test.KotlinTestUtils
|
||||
import org.jetbrains.kotlin.js.engine.loadFiles
|
||||
import org.junit.Assert
|
||||
|
||||
fun createScriptEngine(): ScriptEngine {
|
||||
return ScriptEngineNashorn()
|
||||
return if (java.lang.Boolean.getBoolean("kotlin.js.useNashorn")) ScriptEngineNashorn() else ScriptEngineV8()
|
||||
}
|
||||
|
||||
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(
|
||||
@@ -24,7 +25,7 @@ fun ScriptEngine.runTestFunction(
|
||||
testPackageName: String?,
|
||||
testFunctionName: String,
|
||||
withModuleSystem: Boolean
|
||||
): String? {
|
||||
): String {
|
||||
var script = when {
|
||||
withModuleSystem -> BasicBoxTest.KOTLIN_TEST_INTERNAL + ".require('" + testModuleName!! + "')"
|
||||
testModuleName === null -> "this"
|
||||
@@ -35,10 +36,9 @@ fun ScriptEngine.runTestFunction(
|
||||
script += ".$testPackageName"
|
||||
}
|
||||
|
||||
val testPackage = eval<Any>(script)
|
||||
return callMethod<String?>(testPackage, testFunctionName).also {
|
||||
releaseObject(testPackage)
|
||||
}
|
||||
script += ".$testFunctionName()"
|
||||
|
||||
return eval(script)
|
||||
}
|
||||
|
||||
abstract class AbstractJsTestChecker {
|
||||
@@ -51,7 +51,7 @@ abstract class AbstractJsTestChecker {
|
||||
withModuleSystem: Boolean
|
||||
) {
|
||||
val actualResult = run(files, testModuleName, testPackageName, testFunctionName, withModuleSystem)
|
||||
Assert.assertEquals(expectedResult, actualResult)
|
||||
Assert.assertEquals(expectedResult, actualResult.normalize())
|
||||
}
|
||||
|
||||
private fun run(
|
||||
@@ -66,20 +66,28 @@ abstract class AbstractJsTestChecker {
|
||||
|
||||
|
||||
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 {
|
||||
saveState()
|
||||
saveGlobalState()
|
||||
f()
|
||||
} finally {
|
||||
restoreState()
|
||||
restoreGlobalState()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,7 +104,7 @@ abstract class AbstractNashornJsTestChecker : AbstractJsTestChecker() {
|
||||
|
||||
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
|
||||
if (engineUsageCnt++ > 100) {
|
||||
engineUsageCnt = 0
|
||||
@@ -106,23 +114,17 @@ abstract class AbstractNashornJsTestChecker : AbstractJsTestChecker() {
|
||||
beforeRun()
|
||||
|
||||
return engine.runAndRestoreContext {
|
||||
files.forEach { loadFile(it) }
|
||||
loadFiles(files)
|
||||
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 open fun createScriptEngineForTest(): ScriptEngineNashorn {
|
||||
val engine = ScriptEngineNashorn()
|
||||
|
||||
preloadedScripts.forEach { engine.loadFile(it) }
|
||||
engine.loadFiles(preloadedScripts)
|
||||
|
||||
return engine
|
||||
}
|
||||
@@ -134,7 +136,7 @@ const val GET_KOTLIN_OUTPUT = "kotlin.kotlin.io.output.buffer;"
|
||||
object NashornJsTestChecker : AbstractNashornJsTestChecker() {
|
||||
|
||||
override fun beforeRun() {
|
||||
engine.evalVoid(SETUP_KOTLIN_OUTPUT)
|
||||
engine.eval(SETUP_KOTLIN_OUTPUT)
|
||||
}
|
||||
|
||||
override val preloadedScripts = listOf(
|
||||
@@ -159,69 +161,50 @@ class NashornIrJsTestChecker : AbstractNashornJsTestChecker() {
|
||||
)
|
||||
}
|
||||
|
||||
abstract class AbstractV8JsTestChecker : AbstractJsTestChecker() {
|
||||
protected abstract val engine: ScriptEngineV8
|
||||
object V8JsTestChecker : AbstractJsTestChecker() {
|
||||
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) {
|
||||
run(files) {
|
||||
val actualResult = engine.eval<String>(GET_KOTLIN_OUTPUT)
|
||||
Assert.assertEquals(expectedResult, actualResult)
|
||||
}
|
||||
}
|
||||
}
|
||||
overrideAsserter()
|
||||
}
|
||||
|
||||
object V8JsTestChecker : AbstractV8JsTestChecker() {
|
||||
override val engine get() = tlsEngine.get()
|
||||
|
||||
private val tlsEngine = object : ThreadLocal<ScriptEngineV8>() {
|
||||
override fun initialValue() = createV8Engine()
|
||||
override fun remove() {
|
||||
get().release()
|
||||
}
|
||||
}
|
||||
|
||||
private fun createV8Engine(): ScriptEngineV8 {
|
||||
val v8 = ScriptEngineV8(KotlinTestUtils.tmpDirForReusableFolder("j2v8_library_path").path)
|
||||
private val engine get() = engineTL.get()
|
||||
|
||||
listOf(
|
||||
BasicBoxTest.DIST_DIR_JS_PATH + "kotlin.js",
|
||||
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)
|
||||
override fun run(files: List<String>, f: ScriptEngine.() -> String): String {
|
||||
engine.eval(SETUP_KOTLIN_OUTPUT)
|
||||
return engine.runAndRestoreContext {
|
||||
files.forEach { loadFile(it) }
|
||||
loadFiles(files)
|
||||
f()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object V8IrJsTestChecker : AbstractV8JsTestChecker() {
|
||||
override val engine get() = ScriptEngineV8(KotlinTestUtils.tmpDirForReusableFolder("j2v8_library_path").path)
|
||||
|
||||
override fun run(files: List<String>, f: ScriptEngine.() -> Any?): Any? {
|
||||
|
||||
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
|
||||
}
|
||||
object V8IrJsTestChecker : AbstractJsTestChecker() {
|
||||
private val engineTL = object : ThreadLocal<ScriptEngineV8>() {
|
||||
override fun initialValue() = ScriptEngineV8()
|
||||
override fun remove() {
|
||||
get().release()
|
||||
}
|
||||
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.
|
||||
*
|
||||
* 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.
|
||||
* 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.test.optimizer
|
||||
@@ -128,8 +117,8 @@ abstract class BasicOptimizerTest(private var basePath: String) {
|
||||
|
||||
private fun runScript(fileName: String, code: String) {
|
||||
val engine = createScriptEngine()
|
||||
engine.evalVoid(code)
|
||||
val result = engine.eval<String>("box()")
|
||||
engine.eval(code)
|
||||
val result = engine.eval("box()")
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.js.test.semantics
|
||||
|
||||
import com.eclipsesource.v8.V8ScriptException
|
||||
import com.google.common.collect.Lists
|
||||
import com.intellij.openapi.util.text.StringUtil
|
||||
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 javax.script.ScriptException
|
||||
|
||||
@@ -29,7 +28,7 @@ abstract class AbstractWebDemoExamplesTest(relativePath: String) : BasicBoxTest(
|
||||
testChecker.checkStdout(jsFiles, expectedResult)
|
||||
}
|
||||
|
||||
@Throws(ScriptException::class, V8ScriptException::class)
|
||||
@Throws(ScriptException::class)
|
||||
protected fun runMainAndCheckOutput(fileName: String, expectedResult: String, vararg args: String) {
|
||||
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())
|
||||
doTest(pathToTestDir + testName + ".kt", expectedResult, MainCallParameters.mainWithArguments(Lists.newArrayList(*args)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,22 +1,10 @@
|
||||
/*
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
*
|
||||
* 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.
|
||||
* 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.test.semantics
|
||||
|
||||
import com.eclipsesource.v8.V8ScriptException
|
||||
import org.jetbrains.kotlin.js.test.BasicBoxTest
|
||||
import java.io.File
|
||||
import javax.script.ScriptException
|
||||
@@ -47,7 +35,7 @@ class MultiModuleOrderTest : BasicBoxTest(pathToTestGroupDir, testGroupDir) {
|
||||
testChecker.run(listOf(mainJsFile, libJsFile))
|
||||
}
|
||||
catch (e: RuntimeException) {
|
||||
assertTrue(e is ScriptException || e is V8ScriptException)
|
||||
assertTrue(e is ScriptException || e is IllegalStateException)
|
||||
val message = e.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)
|
||||
|
||||
+7
-19
@@ -1,22 +1,10 @@
|
||||
/*
|
||||
* Copyright 2010-2015 JetBrains s.r.o.
|
||||
*
|
||||
* 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.
|
||||
* 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.test.semantics;
|
||||
|
||||
import com.eclipsesource.v8.V8ScriptException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.script.ScriptException;
|
||||
@@ -55,16 +43,16 @@ public final class WebDemoCanvasExamplesTest extends AbstractWebDemoExamplesTest
|
||||
catch (ScriptException e) {
|
||||
verifyException("\"" + firstUnknownSymbolEncountered + "\"", e.getMessage());
|
||||
}
|
||||
catch (V8ScriptException e) {
|
||||
verifyException(firstUnknownSymbolEncountered, e.getJSMessage());
|
||||
catch (IllegalStateException e) {
|
||||
verifyException(firstUnknownSymbolEncountered, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private static void verifyException(@NotNull String firstUnknownSymbolEncountered, @NotNull String message) {
|
||||
String expectedErrorMessage = "ReferenceError: " + firstUnknownSymbolEncountered + " is not defined";
|
||||
assertTrue("Unexpected error when running compiled canvas examples with rhino.\n" +
|
||||
"Expected: " + expectedErrorMessage + "\n" +
|
||||
"Actual: " + message,
|
||||
message.startsWith(expectedErrorMessage));
|
||||
"Expected message contains \"" + expectedErrorMessage + "\".\n" +
|
||||
"Message: " + message,
|
||||
message.contains(expectedErrorMessage));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user