Skip to content

Commit

Permalink
nashornを使用したIScriptRuntimeを追加
Browse files Browse the repository at this point in the history
  • Loading branch information
anatawa12 committed Jun 3, 2020
1 parent ce6a43a commit ad595cf
Show file tree
Hide file tree
Showing 6 changed files with 231 additions and 1 deletion.
4 changes: 4 additions & 0 deletions src/main/java/com/anatawa12/fixRtm/FixRtm.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import com.anatawa12.fixRtm.io.FIXFileLoader
import com.anatawa12.fixRtm.network.NetworkHandler
import com.anatawa12.fixRtm.rtm.modelpack.modelset.dummies.*
import com.anatawa12.fixRtm.scripting.loadFIXScriptUtil
import com.anatawa12.fixRtm.scripting.nashorn.CompiledImportedScriptCache
import com.anatawa12.fixRtm.scripting.rhino.ExecutedScriptCache
import com.anatawa12.fixRtm.scripting.rhino.PrimitiveJavaHelper
import com.anatawa12.fixRtm.scripting.rhino.RhinoHooks
Expand All @@ -15,6 +16,7 @@ import net.minecraft.block.Block
import net.minecraft.client.Minecraft
import net.minecraft.client.resources.IReloadableResourceManager
import net.minecraft.item.Item
import net.minecraft.launchwrapper.Launch
import net.minecraft.util.ResourceLocation
import net.minecraftforge.client.event.ModelRegistryEvent
import net.minecraftforge.common.MinecraftForge
Expand Down Expand Up @@ -54,6 +56,8 @@ object FixRtm {
RhinoHooks.load()// load
}
MainConfig.ScriptingMode.BetterWithNashorn -> {
Launch.classLoader.addClassLoaderExclusion("jdk.nashorn.")
CompiledImportedScriptCache.load() // load
}
MainConfig.ScriptingMode.UseRtmNormal -> {
// nop
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@ package com.anatawa12.fixRtm.scripting

import com.anatawa12.fixRtm.asm.config.MainConfig
import com.anatawa12.fixRtm.io.FIXFileLoader
import com.anatawa12.fixRtm.scripting.nashorn.NashornScriptRuntimeImpl
import com.anatawa12.fixRtm.scripting.rhino.RhinoScriptRuntimeImpl
import jp.ngt.rtm.modelpack.ModelPackManager
import net.minecraft.util.ResourceLocation
import javax.script.ScriptEngine

val scriptRuntime: IScriptRuntime<*, *> = when (MainConfig.scriptingMode) {
MainConfig.ScriptingMode.CacheWithRhino -> RhinoScriptRuntimeImpl
MainConfig.ScriptingMode.BetterWithNashorn -> TODO()
MainConfig.ScriptingMode.BetterWithNashorn -> NashornScriptRuntimeImpl
MainConfig.ScriptingMode.UseRtmNormal -> IScriptRuntime.AssertingRuntime
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package com.anatawa12.fixRtm.scripting.nashorn

import com.anatawa12.fixRtm.utils.DigestUtils
import jdk.nashorn.api.scripting.NashornScriptEngine
import jdk.nashorn.api.scripting.NashornScriptEngineFactory
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.CopyOnWriteArraySet
import javax.script.CompiledScript
import javax.script.ScriptContext

//*
object CompiledImportedScriptCache {
private val local = ThreadLocal.withInitial { Threaded() }
private val threaded get() = local.get()!!
private val threadedByEngine = ConcurrentHashMap<NashornScriptEngine, Threaded>()

private fun threadedByEngine(engine: NashornScriptEngine?): Threaded {
if (engine == null) return threaded
else return threadedByEngine[engine] ?: throw IllegalArgumentException("the engine is not threaded")
}

val engineFactory = NashornScriptEngineFactory()
val engines = CopyOnWriteArraySet<NashornScriptEngine>()

val engine get() = threaded.engine

fun makeCompiled(script: String, fileName: String): CompiledScript
= threaded.makeCompiled(script, fileName)

fun makeCompiled(engine: NashornScriptEngine?, script: String, fileName: String): CompiledScript
= threadedByEngine(engine).makeCompiled(script, fileName)

fun load() {
// load
}

private class Threaded {
val engine = engineFactory.scriptEngine as NashornScriptEngine

init {
engines.add(engine)
threadedByEngine[engine] = this
}

private val compiledScripts = mutableMapOf<String, CompiledScript>()

fun makeCompiled(script: String, fileName: String): CompiledScript {
engine.context.setAttribute("javax.script.filename", fileName, ScriptContext.ENGINE_SCOPE)
val compile = engine.compile(script)
compiledScripts[DigestUtils.sha1Hex(script)] = compile
engine.context.removeAttribute("javax.script.filename", ScriptContext.ENGINE_SCOPE)
return compile
}

}
}
// */
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package com.anatawa12.fixRtm.scripting.nashorn

import jdk.nashorn.api.scripting.NashornScriptEngine
import java.io.Reader
import javax.script.*

class FIXNashornScriptEngine(
val baseEngine: NashornScriptEngine,
private val context: ScriptContext
) : ScriptEngine by baseEngine, Compilable, Invocable {

override fun getFactory(): ScriptEngineFactory {
TODO("Not yet implemented")
}

override fun setContext(context: ScriptContext) {
throw UnsupportedOperationException("setContext is not supported by FIXNashornScriptEngine")
}

override fun eval(script: String): Any? = baseEngine.eval(script, context)

override fun eval(reader: Reader): Any? = baseEngine.eval(reader, context)

override fun getBindings(scope: Int): Bindings = context.getBindings(scope)

override fun put(name: String, value: Any?) {
context.getBindings(ScriptContext.ENGINE_SCOPE)?.put(name, value)
}

override fun get(name: String): Any? = context.getBindings(ScriptContext.ENGINE_SCOPE)?.get(name)

override fun setBindings(bindings: Bindings?, scope: Int) {
context.setBindings(bindings, scope)
}

override fun getContext(): ScriptContext = context

override fun compile(script: String): CompiledScript {
val compiled = baseEngine.compile(script)
return object : CompiledScript() {
override fun eval(context: ScriptContext): Any = compiled.eval(context)

override fun getEngine(): ScriptEngine = this@FIXNashornScriptEngine
}
}

override fun compile(script: Reader): CompiledScript {
val compiled = baseEngine.compile(script)
return object : CompiledScript() {
override fun eval(context: ScriptContext): Any = compiled.eval(context)

override fun getEngine(): ScriptEngine = this@FIXNashornScriptEngine
}
}

override fun <T : Any> getInterface(clasz: Class<T>): T? {
throw UnsupportedOperationException("getInterface is not supported by FIXNashornScriptEngine")
}

override fun <T : Any> getInterface(thiz: Any, clasz: Class<T>): T? {
throw UnsupportedOperationException("getInterface is not supported by FIXNashornScriptEngine")
}

override fun invokeMethod(thiz: Any, name: String, vararg args: Any?): Any? {
return baseEngine.invokeMethod(thiz, name, *args)
}

override fun invokeFunction(name: String, vararg args: Any?): Any? {
return baseEngine.invokeMethod(context.getBindings(ScriptContext.ENGINE_SCOPE), name, *args)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package com.anatawa12.fixRtm.scripting.nashorn

import com.anatawa12.fixRtm.io.FIXFileLoader
import jdk.nashorn.api.scripting.AbstractJSObject
import jdk.nashorn.api.scripting.NashornScriptEngine
import jdk.nashorn.api.scripting.ScriptObjectMirror
import net.minecraft.util.ResourceLocation
import javax.script.CompiledScript
import javax.script.ScriptContext
import javax.script.SimpleScriptContext

//*
object ImportScriptNashornFunctionImpl : AbstractJSObject() {
override fun isStrictFunction(): Boolean = false

private val ctx = SimpleScriptContext()

private fun getCompiled(engine: NashornScriptEngine?, name: String): CompiledScript {
val resourceLocation = ResourceLocation(name)
val resource = FIXFileLoader.getResource(resourceLocation)
val script = resource.inputStream.reader().use { it.readText() }
return NashornScriptRuntimeImpl.compile(resourceLocation, script, resource.pack,
engine = engine?.let { FIXNashornScriptEngine(it, ctx) })
}

override fun call(thiz: Any?, vararg args: Any?): Any? {
val str = args.getOrNull(0)

if (str !is String) throw IllegalArgumentException("argument#1 must be string")
if (thiz !is ScriptObjectMirror) throw IllegalArgumentException("this must be a scope")

val engine = thiz.getMember("engine") as? NashornScriptEngine

if (engine != null && engine !in CompiledImportedScriptCache.engines)
throw IllegalStateException("current engine is not current thread engine")

val compiled = getCompiled(engine, str.toString())

val context = SimpleScriptContext()
context.setBindings(thiz, ScriptContext.ENGINE_SCOPE)

return compiled.eval(context)
}

override fun isFunction(): Boolean = true

override fun getClassName(): String = "Function"

override fun isArray(): Boolean = false
}
// */
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
@file:JvmName("FIXScriptUtil")

package com.anatawa12.fixRtm.scripting.nashorn

import com.anatawa12.fixRtm.io.FIXModelPack
import com.anatawa12.fixRtm.io.FIXResource
import com.anatawa12.fixRtm.scripting.IScriptRuntime
import com.anatawa12.fixRtm.scripting.ScriptImporter
import net.minecraft.util.ResourceLocation
import javax.script.CompiledScript
import javax.script.ScriptContext
import javax.script.SimpleScriptContext

object NashornScriptRuntimeImpl : IScriptRuntime<CompiledScript, FIXNashornScriptEngine> {
/**
* nashorn does not support executed cache so always return null.
* @return always null
*/
override fun getCachedEngine(filePath: ResourceLocation, resource: FIXResource, dependencies: Map<ResourceLocation, String>): FIXNashornScriptEngine? {
return null
}

override fun compile(script: String, fileName: String, engine: FIXNashornScriptEngine?): CompiledScript {
return CompiledImportedScriptCache.makeCompiled(engine?.baseEngine, script, fileName)
}

override fun exec(script: CompiledScript): FIXNashornScriptEngine {
val engine = CompiledImportedScriptCache.engine

val context = SimpleScriptContext()
val bindings = engine.createBindings()
context.setBindings(bindings, ScriptContext.ENGINE_SCOPE)

engine.eval("""load("nashorn:mozilla_compat.js");""", context)

bindings[ScriptImporter.importScriptFunctionName] = ImportScriptNashornFunctionImpl

script.eval(context)

return FIXNashornScriptEngine(engine, context)
}

override fun cache(pack: FIXModelPack, filePath: ResourceLocation, dependencies: Map<ResourceLocation, String>, engine: FIXNashornScriptEngine) {
// not supported so nop
}
}

0 comments on commit ad595cf

Please sign in to comment.