feat: 调整引擎初始化逻辑

Signed-off-by: MiaoWoo <admin@yumc.pw>
master
MiaoWoo 2022-06-01 17:52:55 +08:00
parent 3e4453a197
commit 9268ce9fee
13 changed files with 247 additions and 132 deletions

14
pom.xml
View File

@ -2,7 +2,7 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<groupId>pw.yumc</groupId> <groupId>pw.yumc</groupId>
<artifactId>MiaoScript</artifactId> <artifactId>MiaoScript</artifactId>
<version>0.22.0</version> <version>0.22.3</version>
<developers> <developers>
<developer> <developer>
<id>502647092</id> <id>502647092</id>
@ -50,6 +50,7 @@
<properties> <properties>
<env.GIT_COMMIT>DEV</env.GIT_COMMIT> <env.GIT_COMMIT>DEV</env.GIT_COMMIT>
<update.changes> <update.changes>
§622-05-25 §afeat: 兼容 1.7.10-1.18.2 版本;
§622-05-21 §afeat: 优化 框架加载逻辑; §622-05-21 §afeat: 优化 框架加载逻辑;
§622-05-20 §afeat: 调整 require 主包逻辑; §622-05-20 §afeat: 调整 require 主包逻辑;
§622-04-09 §afeat: 优化 引擎初始化逻辑; §622-04-09 §afeat: 优化 引擎初始化逻辑;
@ -196,7 +197,8 @@
<dependency> <dependency>
<groupId>org.projectlombok</groupId> <groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId> <artifactId>lombok</artifactId>
<version>1.18.22</version> <version>1.18.24</version>
<scope>compile</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.kamranzafar</groupId> <groupId>org.kamranzafar</groupId>
@ -219,6 +221,7 @@
<groupId>net.md-5</groupId> <groupId>net.md-5</groupId>
<artifactId>bungeecord-api</artifactId> <artifactId>bungeecord-api</artifactId>
<version>1.16-R0.4</version> <version>1.16-R0.4</version>
<scope>compile</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>cn.nukkit</groupId> <groupId>cn.nukkit</groupId>
@ -229,7 +232,7 @@
<dependency> <dependency>
<groupId>org.springframework</groupId> <groupId>org.springframework</groupId>
<artifactId>spring-websocket</artifactId> <artifactId>spring-websocket</artifactId>
<version>5.3.18</version> <version>5.3.19</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency> <dependency>
@ -238,10 +241,5 @@
<version>9.0.35</version> <version>9.0.35</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
<version>4.0.3</version>
</dependency>
</dependencies> </dependencies>
</project> </project>

View File

@ -2,6 +2,7 @@ package pw.yumc.MiaoScript;
import lombok.SneakyThrows; import lombok.SneakyThrows;
import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.plugin.java.JavaPlugin;
import pw.yumc.MiaoScript.api.MiaoScriptAPI;
import pw.yumc.MiaoScript.api.ScriptEngine; import pw.yumc.MiaoScript.api.ScriptEngine;
/** /**
@ -17,7 +18,7 @@ public class MiaoScriptBukkit extends JavaPlugin {
public MiaoScriptBukkit() { public MiaoScriptBukkit() {
ClassLoader origin = Thread.currentThread().getContextClassLoader(); ClassLoader origin = Thread.currentThread().getContextClassLoader();
Thread.currentThread().setContextClassLoader(getClassLoader()); Thread.currentThread().setContextClassLoader(getClassLoader());
engine = new ScriptEngine(getDataFolder().getCanonicalPath(), getLogger(), this); engine = MiaoScriptAPI.createEngine(getDataFolder().getCanonicalPath(), getLogger(), this);
Thread.currentThread().setContextClassLoader(origin); Thread.currentThread().setContextClassLoader(origin);
engine.loadEngine(); engine.loadEngine();
} }

View File

@ -2,6 +2,7 @@ package pw.yumc.MiaoScript;
import lombok.SneakyThrows; import lombok.SneakyThrows;
import net.md_5.bungee.api.plugin.Plugin; import net.md_5.bungee.api.plugin.Plugin;
import pw.yumc.MiaoScript.api.MiaoScriptAPI;
import pw.yumc.MiaoScript.api.ScriptEngine; import pw.yumc.MiaoScript.api.ScriptEngine;
/** /**
@ -16,7 +17,7 @@ public class MiaoScriptBungee extends Plugin {
@SneakyThrows @SneakyThrows
public MiaoScriptBungee() { public MiaoScriptBungee() {
Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader()); Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader());
engine = new ScriptEngine(getDataFolder().getCanonicalPath(), getLogger(), this); engine = MiaoScriptAPI.createEngine(getDataFolder().getCanonicalPath(), getLogger(), this);
engine.loadEngine(); engine.loadEngine();
} }

View File

@ -2,6 +2,7 @@ package pw.yumc.MiaoScript;
import cn.nukkit.plugin.PluginBase; import cn.nukkit.plugin.PluginBase;
import lombok.SneakyThrows; import lombok.SneakyThrows;
import pw.yumc.MiaoScript.api.MiaoScriptAPI;
import pw.yumc.MiaoScript.api.ScriptEngine; import pw.yumc.MiaoScript.api.ScriptEngine;
/** /**
@ -13,7 +14,7 @@ public class MiaoScriptNukkit extends PluginBase {
@SneakyThrows @SneakyThrows
public MiaoScriptNukkit() { public MiaoScriptNukkit() {
Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader()); Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader());
engine = new ScriptEngine(getDataFolder().getCanonicalPath(), super.getLogger(), this); engine = MiaoScriptAPI.createEngine(getDataFolder().getCanonicalPath(), super.getLogger(), this);
engine.loadEngine(); engine.loadEngine();
} }

View File

@ -6,8 +6,8 @@ import org.slf4j.Logger;
import org.spongepowered.api.config.ConfigDir; import org.spongepowered.api.config.ConfigDir;
import org.spongepowered.api.event.Listener; import org.spongepowered.api.event.Listener;
import org.spongepowered.api.event.game.GameReloadEvent; import org.spongepowered.api.event.game.GameReloadEvent;
import org.spongepowered.api.event.game.state.GamePreInitializationEvent;
import org.spongepowered.api.event.game.state.GameStartedServerEvent; import org.spongepowered.api.event.game.state.GameStartedServerEvent;
import org.spongepowered.api.event.game.state.GameStartingServerEvent;
import org.spongepowered.api.event.game.state.GameStoppingServerEvent; import org.spongepowered.api.event.game.state.GameStoppingServerEvent;
import org.spongepowered.api.plugin.Plugin; import org.spongepowered.api.plugin.Plugin;
import pw.yumc.MiaoScript.api.MiaoScriptAPI; import pw.yumc.MiaoScript.api.MiaoScriptAPI;
@ -33,14 +33,14 @@ public class MiaoScriptSponge {
@Listener @Listener
@SneakyThrows @SneakyThrows
public void onStarting(GameStartingServerEvent event) { public void onPreInitialization(GamePreInitializationEvent event) {
engine = new ScriptEngine(pluginConfigDir.getCanonicalPath(), logger, this); engine = MiaoScriptAPI.createEngine(pluginConfigDir.getCanonicalPath(), logger, this);
engine.loadEngine(); engine.loadEngine();
} }
@Listener @Listener
@SneakyThrows @SneakyThrows
public void onStart(GameStartedServerEvent event) { public void onStarted(GameStartedServerEvent event) {
engine.enableEngine(); engine.enableEngine();
} }
@ -55,7 +55,7 @@ public class MiaoScriptSponge {
@SneakyThrows @SneakyThrows
public void reload(GameReloadEvent event) { public void reload(GameReloadEvent event) {
engine.disableEngine(); engine.disableEngine();
engine = new ScriptEngine(pluginConfigDir.getCanonicalPath(), logger, this); System.gc();
engine.loadEngine(); engine.loadEngine();
engine.enableEngine(); engine.enableEngine();
} }

View File

@ -6,6 +6,7 @@ import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.web.socket.server.standard.ServerEndpointExporter; import org.springframework.web.socket.server.standard.ServerEndpointExporter;
import pw.yumc.MiaoScript.api.MiaoScriptAPI;
import pw.yumc.MiaoScript.api.ScriptEngine; import pw.yumc.MiaoScript.api.ScriptEngine;
import java.io.File; import java.io.File;
@ -16,7 +17,7 @@ public class MiaoScriptSpring {
@Bean @Bean
@SneakyThrows @SneakyThrows
public ScriptEngine buildScriptEngine(ApplicationContext applicationContext) { public ScriptEngine buildScriptEngine(ApplicationContext applicationContext) {
return new ScriptEngine(new File("MiaoScript").getCanonicalPath(), log, applicationContext); return MiaoScriptAPI.createEngine(new File("MiaoScript").getCanonicalPath(), log, applicationContext);
} }
@Bean @Bean

View File

@ -25,7 +25,15 @@ public class Base {
} }
public Class<?> getClass(String name) throws ClassNotFoundException { public Class<?> getClass(String name) throws ClassNotFoundException {
return Class.forName(name); try {
return Class.forName(name);
} catch (Throwable ignored) {
}
try {
return Class.forName(name, true, instance.getClass().getClassLoader());
} catch (Throwable ex) {
return Class.forName(name, true, instance.getClass().getClassLoader().getParent());
}
} }
public Object getInstance() { public Object getInstance() {
@ -44,6 +52,14 @@ public class Base {
return MiaoScriptAPI.loadMavenDepend(groupId, artifactId, version); return MiaoScriptAPI.loadMavenDepend(groupId, artifactId, version);
} }
public File[] loadMavenDepend(String groupId, String artifactId, String version, ClassLoader classLoader) {
return MiaoScriptAPI.loadMavenDepend(groupId, artifactId, version, classLoader);
}
public File[] parentLoadMavenDepend(String groupId, String artifactId, String version) {
return MiaoScriptAPI.parentLoadMavenDepend(groupId, artifactId, version);
}
public String read(String path) throws IOException { public String read(String path) throws IOException {
return read(Paths.get(path)); return read(Paths.get(path));
} }

View File

@ -14,6 +14,11 @@ public class MiaoScriptAPI {
private static ScriptEngine scriptEngine; private static ScriptEngine scriptEngine;
private static PluginManager pluginManager; private static PluginManager pluginManager;
public static ScriptEngine createEngine(String root, Object logger, Object instance) {
MiaoScriptAPI.scriptEngine = new ScriptEngine(root, logger, instance);
return MiaoScriptAPI.scriptEngine;
}
public static String getRoot() { public static String getRoot() {
return root; return root;
} }
@ -45,4 +50,18 @@ public class MiaoScriptAPI {
} }
return MavenDependLoader.load(MiaoScriptAPI.libPath, groupId, artifactId, version); return MavenDependLoader.load(MiaoScriptAPI.libPath, groupId, artifactId, version);
} }
public static File[] loadMavenDepend(String groupId, String artifactId, String version, ClassLoader classLoader) {
if (root == null || scriptEngine == null) {
throw new IllegalStateException("root can't be null before loadMavenDepend.");
}
return MavenDependLoader.load(MiaoScriptAPI.libPath, groupId, artifactId, version, classLoader);
}
public static File[] parentLoadMavenDepend(String groupId, String artifactId, String version) {
if (root == null || scriptEngine == null) {
throw new IllegalStateException("root can't be null before loadMavenDepend.");
}
return MavenDependLoader.parentLoad(MiaoScriptAPI.libPath, groupId, artifactId, version);
}
} }

View File

@ -20,7 +20,7 @@ public class ScriptEngine {
private MiaoScriptEngine engine; private MiaoScriptEngine engine;
private Object future; private Object future;
public ScriptEngine(String root, Object logger, Object instance) { ScriptEngine(String root, Object logger, Object instance) {
this.loader = Thread.currentThread().getContextClassLoader(); this.loader = Thread.currentThread().getContextClassLoader();
this.root = root; this.root = root;
this.logger = logger; this.logger = logger;
@ -32,7 +32,7 @@ public class ScriptEngine {
public void createEngine() { public void createEngine() {
synchronized (logger) { synchronized (logger) {
if (this.engine == null) { if (this.engine == null) {
this.engine = new MiaoScriptEngine("nashorn", root); this.engine = new MiaoScriptEngine(root);
this.engine.put("base", this.base); this.engine.put("base", this.base);
this.engine.put("ScriptEngineContextHolder", this); this.engine.put("ScriptEngineContextHolder", this);
} }

View File

@ -10,6 +10,9 @@ import java.lang.reflect.Method;
import java.net.URL; import java.net.URL;
public class JarLoader { public class JarLoader {
private static sun.misc.Unsafe unsafe;
private static long offset;
private static Object parentUcp;
private static Object ucp; private static Object ucp;
private static MethodHandle addURLMethodHandle; private static MethodHandle addURLMethodHandle;
@ -23,12 +26,26 @@ public class JarLoader {
return file; return file;
} }
@SneakyThrows
public static File parentLoad(File file) {
if (parentUcp == null)
throw new IllegalStateException("parentUcp is null.");
addURLMethodHandle.invoke(parentUcp, file.toURI().toURL());
return file;
}
@SneakyThrows
public static File load(File file, ClassLoader loader) {
addURLMethodHandle.invoke(unsafe.getObject(loader, offset), file.toURI().toURL());
return file;
}
private static void initReflect() { private static void initReflect() {
try { try {
ClassLoader loader = ClassLoader.getSystemClassLoader(); ClassLoader loader = JarLoader.class.getClassLoader();
Field theUnsafe = sun.misc.Unsafe.class.getDeclaredField("theUnsafe"); Field theUnsafe = sun.misc.Unsafe.class.getDeclaredField("theUnsafe");
theUnsafe.setAccessible(true); theUnsafe.setAccessible(true);
sun.misc.Unsafe unsafe = (sun.misc.Unsafe) theUnsafe.get(null); unsafe = (sun.misc.Unsafe) theUnsafe.get(null);
Field field = MethodHandles.Lookup.class.getDeclaredField("IMPL_LOOKUP"); Field field = MethodHandles.Lookup.class.getDeclaredField("IMPL_LOOKUP");
MethodHandles.Lookup lookup = (MethodHandles.Lookup) unsafe.getObject(unsafe.staticFieldBase(field), unsafe.staticFieldOffset(field)); MethodHandles.Lookup lookup = (MethodHandles.Lookup) unsafe.getObject(unsafe.staticFieldBase(field), unsafe.staticFieldOffset(field));
Field ucpField; Field ucpField;
@ -37,11 +54,13 @@ public class JarLoader {
} catch (NoSuchFieldException e) { } catch (NoSuchFieldException e) {
ucpField = loader.getClass().getSuperclass().getDeclaredField("ucp"); ucpField = loader.getClass().getSuperclass().getDeclaredField("ucp");
} }
long offset = unsafe.objectFieldOffset(ucpField); offset = unsafe.objectFieldOffset(ucpField);
ucp = unsafe.getObject(loader, offset); ucp = unsafe.getObject(loader, offset);
Method method = ucp.getClass().getDeclaredMethod("addURL", URL.class); Method method = ucp.getClass().getDeclaredMethod("addURL", URL.class);
addURLMethodHandle = lookup.unreflect(method); addURLMethodHandle = lookup.unreflect(method);
} catch (Exception e) { if (loader.getParent() != null)
parentUcp = unsafe.getObject(loader.getParent(), offset);
} catch (Throwable e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
} }

View File

@ -14,7 +14,7 @@ import java.nio.file.StandardCopyOption;
import java.security.MessageDigest; import java.security.MessageDigest;
public class MavenDependLoader { public class MavenDependLoader {
private static final String MavenRepo = "https://maven.aliyun.com/repository/public"; public static final String MavenRepo = "https://maven.aliyun.com/repository/public";
public static File[] load(String libPath, String groupId, String artifactId, String version) { public static File[] load(String libPath, String groupId, String artifactId, String version) {
return new File[]{ return new File[]{
@ -23,6 +23,20 @@ public class MavenDependLoader {
}; };
} }
public static File[] parentLoad(String libPath, String groupId, String artifactId, String version) {
return new File[]{
downloadAndCheckSha1(libPath, groupId, artifactId, version, "pom"),
JarLoader.parentLoad(downloadAndCheckSha1(libPath, groupId, artifactId, version, "jar"))
};
}
public static File[] load(String libPath, String groupId, String artifactId, String version, ClassLoader loader) {
return new File[]{
downloadAndCheckSha1(libPath, groupId, artifactId, version, "pom"),
JarLoader.load(downloadAndCheckSha1(libPath, groupId, artifactId, version, "jar"), loader)
};
}
@SneakyThrows @SneakyThrows
public static File downloadAndCheckSha1(String libPath, String groupId, String artifactId, String version, String ext) { public static File downloadAndCheckSha1(String libPath, String groupId, String artifactId, String version, String ext) {
File sha1 = getMavenFile(libPath, groupId, artifactId, version, ext + ".sha1"); File sha1 = getMavenFile(libPath, groupId, artifactId, version, ext + ".sha1");

View File

@ -5,12 +5,12 @@ import lombok.val;
import pw.yumc.MiaoScript.api.loader.JarLoader; import pw.yumc.MiaoScript.api.loader.JarLoader;
import pw.yumc.MiaoScript.api.loader.MavenDependLoader; import pw.yumc.MiaoScript.api.loader.MavenDependLoader;
import javax.script.ScriptEngine;
import javax.script.*; import javax.script.*;
import java.io.File; import java.io.File;
import java.io.Reader; import java.io.Reader;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.HashMap; import java.util.ArrayList;
import java.util.List;
/** /**
* *
@ -19,111 +19,143 @@ import java.util.HashMap;
* @since 2016829 7:51:43 * @since 2016829 7:51:43
*/ */
public class MiaoScriptEngine implements ScriptEngine, Invocable { public class MiaoScriptEngine implements ScriptEngine, Invocable {
private static MiaoScriptEngine DEFAULT;
private static final ScriptEngineManager manager;
private ScriptEngine engine; private ScriptEngine engine;
static { public MiaoScriptEngine(String engineRoot) {
manager = new ScriptEngineManager(ClassLoader.getSystemClassLoader()); if (new File(engineRoot, "debug").exists()) {
} System.setProperty("nashorn.debug", "true");
public static void setBindings(Bindings bindings) {
manager.setBindings(bindings);
}
public static Bindings getBindings() {
return manager.getBindings();
}
public MiaoScriptEngine() {
this("js");
}
public MiaoScriptEngine(final String engineType) {
this(manager, engineType, null);
}
public MiaoScriptEngine(ScriptEngineManager engineManager) {
this(engineManager, "js", null);
}
public MiaoScriptEngine(final String engineType, String engineRoot) {
this(manager, engineType, engineRoot);
}
public MiaoScriptEngine(ScriptEngineManager engineManager, final String engineType, String engineRoot) {
// JDK11 Polyfill 存在类效验问题 直接用OpenJDK的Nashorn
if (System.getProperty("java.version").startsWith("11.") && engineRoot != null) {
this.loadNetworkNashorn(engineRoot);
if (engine == null)
throw new UnsupportedOperationException("当前环境 JDK11 不支持 Nashorn 脚本类型!");
return;
} }
try { if (getJavaVersion() > 15) {
engine = engineManager.getEngineByName(engineType); this.loadGraalJS(engineRoot);
} catch (final NullPointerException ignored) { } else {
} this.loadNashorn(engineRoot);
if (engine == null) {
val extDirs = System.getProperty("java.ext.dirs");
if (extDirs != null) {
this.loadLocalNashorn(extDirs, engineType);
} else if (engineRoot != null) {
this.loadNetworkNashorn(engineRoot);
}
} }
if (engine == null) if (engine == null)
throw new UnsupportedOperationException("当前环境不支持 " + engineType + " 脚本类型!"); throw new UnsupportedOperationException("当前环境不支持 Nashorn 或 GraalJS 脚本引擎.");
} }
private void loadLocalNashorn(String extDirs, String engineType) { private void loadGraalJS(String engineRoot) {
this.engine = this.parentLoadNetworkNashorn(engineRoot);
if (this.engine == null) {
this.engine = this.loadNetworkGraalJS(engineRoot);
}
}
private void loadNashorn(String engineRoot) {
try {
this.createEngineByName();
} catch (final Throwable ex) {
ex.printStackTrace();
}
try {
val extDirs = System.getProperty("java.ext.dirs");
if (this.engine == null && extDirs != null) {
this.engine = this.loadLocalNashorn(extDirs);
}
} catch (final Throwable ex) {
ex.printStackTrace();
}
try {
if (this.engine == null && engineRoot != null) {
this.engine = this.loadNetworkNashorn(engineRoot);
}
} catch (final Throwable ex) {
ex.printStackTrace();
}
if (this.engine == null)
throw new UnsupportedOperationException("当前环境不支持 Nashorn 脚本引擎.");
}
private int getJavaVersion() {
String version = System.getProperty("java.version");
if (version.startsWith("1.")) {
version = version.substring(2, 3);
} else {
int dot = version.indexOf(".");
if (dot != -1) {
version = version.substring(0, dot);
}
}
return Integer.parseInt(version);
}
private ScriptEngine loadLocalNashorn(String extDirs) {
val dirs = extDirs.split(File.pathSeparator); val dirs = extDirs.split(File.pathSeparator);
for (String dir : dirs) { for (String dir : dirs) {
File nashorn = new File(dir, "nashorn.jar"); File nashorn = new File(dir, "nashorn.jar");
if (nashorn.exists()) { if (nashorn.exists()) {
JarLoader.load(nashorn); JarLoader.load(nashorn);
this.createEngineByName(engineType); return this.createEngineByName();
} }
} }
return null;
} }
@SneakyThrows @SneakyThrows
private void loadNetworkNashorn(String engineRoot) { private ScriptEngine loadNetworkNashorn(String engineRoot) {
File libRootFile = new File(engineRoot, "libs"); File libRootFile = new File(engineRoot, "libs");
libRootFile.mkdirs(); libRootFile.mkdirs();
String libRoot = libRootFile.getCanonicalPath(); String libRoot = libRootFile.getCanonicalPath();
MavenDependLoader.load(libRoot, "org.openjdk.nashorn", "nashorn-core", "15.3"); MavenDependLoader.load(libRoot, "org.openjdk.nashorn", "nashorn-core", "15.4");
MavenDependLoader.load(libRoot, "org.ow2.asm", "asm", "9.2"); MavenDependLoader.load(libRoot, "org.ow2.asm", "asm", "9.3");
MavenDependLoader.load(libRoot, "org.ow2.asm", "asm-commons", "9.2"); MavenDependLoader.load(libRoot, "org.ow2.asm", "asm-commons", "9.3");
MavenDependLoader.load(libRoot, "org.ow2.asm", "asm-tree", "9.2"); MavenDependLoader.load(libRoot, "org.ow2.asm", "asm-tree", "9.3");
MavenDependLoader.load(libRoot, "org.ow2.asm", "asm-util", "9.2"); MavenDependLoader.load(libRoot, "org.ow2.asm", "asm-util", "9.3");
Class<?> NashornScriptEngineFactory = Class.forName("org.openjdk.nashorn.api.scripting.NashornScriptEngineFactory"); return createEngineByFactoryClassName("org.openjdk.nashorn.api.scripting.NashornScriptEngineFactory", false);
Method getScriptEngine = NashornScriptEngineFactory.getMethod("getScriptEngine");
Object factory = NashornScriptEngineFactory.newInstance();
engine = (ScriptEngine) getScriptEngine.invoke(factory);
} }
private void createEngineByName(String engineType) { @SneakyThrows
try { private ScriptEngine parentLoadNetworkNashorn(String engineRoot) {
engine = new ScriptEngineManager(Thread.currentThread().getContextClassLoader()).getEngineByName(engineType); File libRootFile = new File(engineRoot, "libs");
} catch (NullPointerException ignored) { libRootFile.mkdirs();
String libRoot = libRootFile.getCanonicalPath();
MavenDependLoader.parentLoad(libRoot, "org.openjdk.nashorn", "nashorn-core", "15.4");
MavenDependLoader.parentLoad(libRoot, "org.ow2.asm", "asm", "9.3");
MavenDependLoader.parentLoad(libRoot, "org.ow2.asm", "asm-commons", "9.3");
MavenDependLoader.parentLoad(libRoot, "org.ow2.asm", "asm-tree", "9.3");
MavenDependLoader.parentLoad(libRoot, "org.ow2.asm", "asm-util", "9.3");
return createEngineByFactoryClassName("org.openjdk.nashorn.api.scripting.NashornScriptEngineFactory", false);
}
@SneakyThrows
private ScriptEngine loadNetworkGraalJS(String engineRoot) {
File libRootFile = new File(engineRoot, "libs");
libRootFile.mkdirs();
String libRoot = libRootFile.getCanonicalPath();
MavenDependLoader.load(libRoot, "org.graalvm.js", "js", "22.1.0.1");
MavenDependLoader.load(libRoot, "org.graalvm.js", "js-scriptengine", "22.1.0.1");
MavenDependLoader.load(libRoot, "org.graalvm.regex", "regex", "22.1.0.1");
MavenDependLoader.load(libRoot, "org.graalvm.sdk", "graal-sdk", "22.1.0.1");
MavenDependLoader.load(libRoot, "org.graalvm.truffle", "truffle-api", "22.1.0.1");
return createEngineByFactoryClassName("org.openjdk.nashorn.api.scripting.NashornScriptEngineFactory", false);
}
@SneakyThrows
private ScriptEngine createEngineByName() {
return createEngineByFactoryClassName("jdk.nashorn.api.scripting.NashornScriptEngineFactory", true);
}
@SneakyThrows
private ScriptEngine createEngineByFactoryClassName(String factoryClassName, boolean jdk) {
Class<?> NashornScriptEngineFactory = Class.forName(factoryClassName);
Method getScriptEngine = NashornScriptEngineFactory.getMethod("getScriptEngine", String[].class);
Object factory = NashornScriptEngineFactory.newInstance();
List<String> engineArgs = new ArrayList<>();
engineArgs.add("--language=es5");
engineArgs.add("--optimistic-types=false");
if (getJavaVersion() >= 11 && jdk) {
engineArgs.add("--no-deprecation-warning");
} }
return (ScriptEngine) getScriptEngine.invoke(factory, (Object) engineArgs.toArray(new String[]{}));
} }
public ScriptEngine getEngine() { public ScriptEngine getEngine() {
return this.engine; return this.engine;
} }
public static MiaoScriptEngine getDefault() {
if (DEFAULT == null) {
DEFAULT = new MiaoScriptEngine();
}
return DEFAULT;
}
@Override @Override
public Bindings createBindings() { public Bindings createBindings() {
return new SimpleBindings(new HashMap<>(engine.getBindings(ScriptContext.GLOBAL_SCOPE))); return engine.createBindings();
} }
@Override @Override
@ -177,13 +209,13 @@ public class MiaoScriptEngine implements ScriptEngine, Invocable {
} }
@Override @Override
public <T> T getInterface(final Class<T> clasz) { public <T> T getInterface(final Class<T> cls) {
return ((Invocable) engine).getInterface(clasz); return ((Invocable) engine).getInterface(cls);
} }
@Override @Override
public <T> T getInterface(final Object thiz, final Class<T> clasz) { public <T> T getInterface(final Object thiz, final Class<T> cls) {
return ((Invocable) engine).getInterface(thiz, clasz); return ((Invocable) engine).getInterface(thiz, cls);
} }
@Override @Override

View File

@ -28,9 +28,9 @@
// @ts-check // @ts-check
( (
/** /**
* @param {string} parent * @param {string} root
*/ */
function (parent) { function (root) {
'use strict' 'use strict'
var System = Java.type('java.lang.System') var System = Java.type('java.lang.System')
@ -181,7 +181,7 @@
try { try {
var json = JSON.parse(base.read(_package)) var json = JSON.parse(base.read(_package))
if (json.main) { if (json.main) {
return resolveAsFile(json.main, dir) return resolveAsFile(json.main, dir) || resolveAsFile('index.js', new File(dir, json.main))
} }
} catch (error) { } catch (error) {
throw __error('resolveAsDirectory ' + dir + ' package.json error ' + error) throw __error('resolveAsDirectory ' + dir + ' package.json error ' + error)
@ -239,18 +239,26 @@
if (!loader) { if (!loader) {
throw __error('Unsupported module ' + filename + '. require loader not found.') throw __error('Unsupported module ' + filename + '. require loader not found.')
} }
console.trace('Loading module', name + '(' + id + ')', 'Optional', JSON.stringify(optional)) /**
* @type any
*/
var module = { var module = {
id: id, id: id,
name: name, name: name,
ext: ext, ext: ext,
parent: optional.parent,
exports: {}, exports: {},
loaded: false, loaded: false,
loader: loader, loader: loader,
require: getRequire(file.parentFile, id), path: _absolute(file.parentFile),
__dirname: file.parentFile, filename: _absolute(file),
__filename: file children: []
} }
module.require = getRequire(module)
if (module.parent && module.parent.children) {
module.parent.children.push(module)
}
console.trace('Loading module', name + '(' + id + ')', 'Optional', JSON.stringify(__assign(optional, { parent: undefined })))
cacheModules[id] = module cacheModules[id] = module
return loader(module, file, __assign(optional, { id: id })) return loader(module, file, __assign(optional, { id: id }))
} }
@ -288,7 +296,7 @@
name: optional.id name: optional.id
}) })
compiledWrapper.apply(module.exports, [ compiledWrapper.apply(module.exports, [
module, module.exports, module.require, module.__dirname, module.__filename module, module.exports, module.require, module.path, module.filename
]) ])
module.loaded = true module.loaded = true
if (optional.afterCompile) { if (optional.afterCompile) {
@ -467,7 +475,7 @@
* 检查缓存模块 * 检查缓存模块
*/ */
function checkCacheModule(optional) { function checkCacheModule(optional) {
return optional.local ? cacheModuleIds[optional.parentId] && cacheModuleIds[optional.parentId][optional.path] : cacheModuleIds[optional.path] return optional.local ? cacheModuleIds[optional.parent.id] && cacheModuleIds[optional.parent.id][optional.path] : cacheModuleIds[optional.path]
} }
/** /**
@ -511,11 +519,11 @@
*/ */
function setCacheModule(file, optional) { function setCacheModule(file, optional) {
if (optional.local) { if (optional.local) {
var parent = cacheModuleIds[optional.parentId] var parent = cacheModuleIds[optional.parent.id]
if (!parent) { if (!parent) {
cacheModuleIds[optional.parentId] = {} cacheModuleIds[optional.parent.id] = {}
} }
return cacheModuleIds[optional.parentId][optional.path] = _canonical(file) return cacheModuleIds[optional.parent.id][optional.path] = _canonical(file)
} }
return cacheModuleIds[optional.path] = _canonical(file) return cacheModuleIds[optional.path] = _canonical(file)
} }
@ -527,11 +535,10 @@
/** /**
* 闭包方法 * 闭包方法
* @param {string} parent 父目录 * @param {any} parent 父模块
* @param {string} parentId
* @returns {Function} * @returns {Function}
*/ */
function exports(parent, parentId) { function exports(parent) {
/** /**
* @param {string} path * @param {string} path
* @param {any} optional * @param {any} optional
@ -540,13 +547,13 @@
if (!path) { if (!path) {
throw __error('require path can\'t be undefined or empty!') throw __error('require path can\'t be undefined or empty!')
} }
return _require(path, parent, __assign({ var optional = __assign({
cache: true, cache: true,
parentId: parentId,
parent: parent, parent: parent,
path: path, path: path,
local: path.startsWith('.') || path.startsWith('/') local: path.startsWith('.') || path.startsWith('/')
}, optional)).exports }, optional)
return _require(path, parent.path, optional).exports
} }
} }
@ -555,9 +562,8 @@
* @param {any} optional 附加选项 * @param {any} optional 附加选项
*/ */
function __DynamicResolve__(path, optional) { function __DynamicResolve__(path, optional) {
return _canonical(new File(resolve(path, parent, __assign({ return _canonical(new File(resolve(path, root, __assign({
cache: true, cache: true,
parent: parent,
local: path.startsWith('.') || path.startsWith('/') local: path.startsWith('.') || path.startsWith('/')
}, optional)))) }, optional))))
} }
@ -592,14 +598,13 @@
} }
/** /**
* @param {string} parent * @param {any} parent
* @param {string} parentId
*/ */
function getRequire(parent, parentId) { function getRequire(parent) {
/** /**
* @type {any} require * @type {any} require
*/ */
var require = exports(parent, parentId) var require = exports(parent)
require.resolve = __DynamicResolve__ require.resolve = __DynamicResolve__
require.clear = __DynamicClear__ require.clear = __DynamicClear__
require.disable = __DynamicDisable__ require.disable = __DynamicDisable__
@ -643,8 +648,9 @@
function printRequireInfo() { function printRequireInfo() {
console.info('Initialization require module.') console.info('Initialization require module.')
console.info('ParentDir:', _canonical(parent)) console.info('ParentDir:', root)
console.info('Require module env list:') console.info('Require module env list:')
console.info('- JAVA_VERSION: ', System.getProperty("java.version"))
console.info('- MS_NODE_PATH:', MS_NODE_PATH.startsWith(root) ? MS_NODE_PATH.split(root)[1] : MS_NODE_PATH) console.info('- MS_NODE_PATH:', MS_NODE_PATH.startsWith(root) ? MS_NODE_PATH.split(root)[1] : MS_NODE_PATH)
console.info('- MS_NODE_REGISTRY:', MS_NODE_REGISTRY) console.info('- MS_NODE_REGISTRY:', MS_NODE_REGISTRY)
console.info('- MS_FALLBACK_NODE_REGISTRY:', MS_FALLBACK_NODE_REGISTRY) console.info('- MS_FALLBACK_NODE_REGISTRY:', MS_FALLBACK_NODE_REGISTRY)
@ -676,7 +682,11 @@
console.warn("无法获取到最新的版本锁定信息 使用默认配置.") console.warn("无法获取到最新的版本锁定信息 使用默认配置.")
console.warn("InitVersionLock Error:", error) console.warn("InitVersionLock Error:", error)
console.debug(error) console.debug(error)
ModulesVersionLock = { "@babel/standalone": "7.12.18", "crypto-js": "3.3.0" } ModulesVersionLock = {
"@babel/standalone": "7.12.18",
"crypto-js": "3.3.0",
"core-js": "3.19.3"
}
} }
console.info('Lock module version List:') console.info('Lock module version List:')
for (var key in ModulesVersionLock) { for (var key in ModulesVersionLock) {
@ -731,5 +741,8 @@
initCacheModuleIds() initCacheModuleIds()
initVersionLock() initVersionLock()
return initRequireLoader(getRequire(parent, "")) return initRequireLoader(getRequire({
id: 'main',
path: root
}))
}) })