From 88d365328a929f75c64a0232a5bb68fd82f00634 Mon Sep 17 00:00:00 2001 From: Roman Artemev Date: Mon, 4 Mar 2019 19:59:14 +0300 Subject: [PATCH] [JS IR BE] Run JS IR tests in V8 engine --- js/js.tests/build.gradle.kts | 7 ++ .../kotlin/js/test/BasicIrBoxTest.kt | 2 +- .../jetbrains/kotlin/js/test/JsTestChecker.kt | 70 ++++++++++++------- .../kotlin/js/test/interop/ScriptEngine.kt | 2 + .../js/test/interop/ScriptEngineNashorn.kt | 3 + .../kotlin/js/test/interop/ScriptEngineV8.kt | 55 +++++++++++++++ 6 files changed, 113 insertions(+), 26 deletions(-) create mode 100644 js/js.tests/test/org/jetbrains/kotlin/js/test/interop/ScriptEngineV8.kt diff --git a/js/js.tests/build.gradle.kts b/js/js.tests/build.gradle.kts index 0a2f709b7a7..94fe713c66a 100644 --- a/js/js.tests/build.gradle.kts +++ b/js/js.tests/build.gradle.kts @@ -42,6 +42,13 @@ dependencies { testRuntime(project(":kotlin-preloader")) // it's required for ant tests testRuntime(project(":compiler:backend-common")) testRuntime(commonDep("org.fusesource.jansi", "jansi")) + + when { + OperatingSystem.current().isWindows() -> testCompile("com.eclipsesource.j2v8:j2v8_win32_x86:4.6.0") + OperatingSystem.current().isLinux() -> testCompile("com.eclipsesource.j2v8:j2v8_linux_x86_64:4.8.0") + OperatingSystem.current().isMacOsX() -> testCompile("com.eclipsesource.j2v8:j2v8_macosx_x86_64:4.6.0") + else -> logger.error("unsupported platform - can not compile com.eclipsesource.j2v8 dependency") + } antLauncherJar(commonDep("org.apache.ant", "ant")) antLauncherJar(files(toolsJar())) 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 b81204a9870..e1fce96e09a 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 @@ -131,7 +131,7 @@ abstract class BasicIrBoxTest( // TODO: should we do anything special for module systems? // TODO: return list of js from translateFiles and provide then to this function with other js files - NashornIrJsTestChecker().check(jsFiles, testModuleName, null, testFunction, expectedResult, withModuleSystem) + V8IrJsTestChecker.check(jsFiles, testModuleName, null, testFunction, expectedResult, withModuleSystem) } } diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/JsTestChecker.kt b/js/js.tests/test/org/jetbrains/kotlin/js/test/JsTestChecker.kt index 884e1e7d16e..8da790dc18c 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/JsTestChecker.kt +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/JsTestChecker.kt @@ -9,6 +9,7 @@ import jdk.nashorn.internal.runtime.ScriptRuntime import org.jetbrains.kotlin.js.test.interop.GlobalRuntimeContext import org.jetbrains.kotlin.js.test.interop.ScriptEngine import org.jetbrains.kotlin.js.test.interop.ScriptEngineNashorn +import org.jetbrains.kotlin.js.test.interop.ScriptEngineV8 import org.junit.Assert fun createScriptEngine(): ScriptEngine { @@ -36,9 +37,36 @@ fun ScriptEngine.runTestFunction( } val testPackage = eval(script) - return callMethod(testPackage, testFunctionName) + return callMethod(testPackage, testFunctionName).also { + releaseObject(testPackage) + } } +abstract class AbstractJsTestChecker { + fun check( + files: List, + testModuleName: String?, + testPackageName: String?, + testFunctionName: String, + expectedResult: String, + withModuleSystem: Boolean + ) { + val actualResult = run(files, testModuleName, testPackageName, testFunctionName, withModuleSystem) + Assert.assertEquals(expectedResult, actualResult) + } + + private fun run( + files: List, + testModuleName: String?, + testPackageName: String?, + testFunctionName: String, + withModuleSystem: Boolean + ) = run(files) { + runTestFunction(testModuleName, testPackageName, testFunctionName, withModuleSystem) + } + + protected abstract fun run(files: List, f: ScriptEngine.() -> Any?): Any? +} fun ScriptEngine.runAndRestoreContext( globalObject: GlobalRuntimeContext = getGlobalContext(), @@ -54,7 +82,7 @@ fun ScriptEngine.runAndRestoreContext( } } -abstract class AbstractNashornJsTestChecker { +abstract class AbstractNashornJsTestChecker: AbstractJsTestChecker() { private var engineUsageCnt = 0 @@ -69,35 +97,13 @@ abstract class AbstractNashornJsTestChecker { originalState = globalObject?.toMap() } - fun check( - files: List, - testModuleName: String?, - testPackageName: String?, - testFunctionName: String, - expectedResult: String, - withModuleSystem: Boolean - ) { - val actualResult = run(files, testModuleName, testPackageName, testFunctionName, withModuleSystem) - Assert.assertEquals(expectedResult, actualResult) - } - fun run(files: List) { run(files) { null } } - private fun run( - files: List, - testModuleName: String?, - testPackageName: String?, - testFunctionName: String, - withModuleSystem: Boolean - ) = run(files) { - runTestFunction(testModuleName, testPackageName, testFunctionName, withModuleSystem) - } - protected open fun beforeRun() {} - private fun run( + override fun run( files: List, f: ScriptEngine.() -> Any? ): Any? { @@ -158,4 +164,18 @@ class NashornIrJsTestChecker : AbstractNashornJsTestChecker() { return engine } +} + +object V8IrJsTestChecker : AbstractJsTestChecker() { + override fun run(files: List, f: ScriptEngine.() -> Any?): Any? { + + val v8 = ScriptEngineV8() + + return try { + files.forEach { v8.loadFile(it) } + v8.f() + } finally { + v8.release() + } + } } \ No newline at end of file diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/interop/ScriptEngine.kt b/js/js.tests/test/org/jetbrains/kotlin/js/test/interop/ScriptEngine.kt index 450bb6f74de..a40b535b6ea 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/interop/ScriptEngine.kt +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/interop/ScriptEngine.kt @@ -11,4 +11,6 @@ interface ScriptEngine { fun evalVoid(script: String) fun callMethod(obj: Any, name: String, vararg args: Any?): T fun loadFile(path: String) + fun release() + fun releaseObject(t: T) } \ No newline at end of file diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/interop/ScriptEngineNashorn.kt b/js/js.tests/test/org/jetbrains/kotlin/js/test/interop/ScriptEngineNashorn.kt index a33be58982e..d8a234138d9 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/interop/ScriptEngineNashorn.kt +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/interop/ScriptEngineNashorn.kt @@ -33,4 +33,7 @@ class ScriptEngineNashorn : ScriptEngine { override fun loadFile(path: String) { evalVoid("load('${path.replace('\\', '/')}');") } + + override fun release() {} + override fun releaseObject(t: T) {} } \ No newline at end of file diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/interop/ScriptEngineV8.kt b/js/js.tests/test/org/jetbrains/kotlin/js/test/interop/ScriptEngineV8.kt new file mode 100644 index 00000000000..2c5fda375d1 --- /dev/null +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/interop/ScriptEngineV8.kt @@ -0,0 +1,55 @@ +/* + * 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. + */ + +package org.jetbrains.kotlin.js.test.interop + +import com.eclipsesource.v8.V8 +import com.eclipsesource.v8.V8Array +import com.eclipsesource.v8.V8Object +import com.eclipsesource.v8.utils.V8ObjectUtils +import java.io.File + +class ScriptEngineV8 : ScriptEngine { + override fun releaseObject(t: T) { + (t as? V8Object)?.release() + } + + override fun getGlobalContext(): GlobalRuntimeContext { + val v8result = eval("this") + val context = V8ObjectUtils.toMap(v8result) as GlobalRuntimeContext + return context.also { v8result.release() } + } + + private val myRuntime: V8 = V8.createV8Runtime("global") + + @Suppress("UNCHECKED_CAST") + override fun eval(script: String): T { + return myRuntime.executeScript(script) as T + } + + override fun evalVoid(script: String) { + return myRuntime.executeVoidScript(script) + } + + @Suppress("UNCHECKED_CAST") + override fun 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) { + evalVoid(File(path).bufferedReader().use { it.readText() }) + } + + override fun release() { + myRuntime.release() + } +} \ No newline at end of file