mirror of
https://github.com/GravitLauncher/Launcher
synced 2024-11-15 03:31:15 +03:00
[FEATURE] Support modular start
This commit is contained in:
parent
6cd5a69149
commit
44bc8b0bbc
11 changed files with 165 additions and 24 deletions
|
@ -49,6 +49,7 @@ public void run(String[] args) {
|
||||||
String compatClasses = System.getProperty("launcher.runtime.launch.compat", null);
|
String compatClasses = System.getProperty("launcher.runtime.launch.compat", null);
|
||||||
String nativesDir = System.getProperty("launcher.runtime.launch.natives", "natives");
|
String nativesDir = System.getProperty("launcher.runtime.launch.natives", "natives");
|
||||||
String launcherOptionsPath = System.getProperty("launcher.runtime.launch.options", null);
|
String launcherOptionsPath = System.getProperty("launcher.runtime.launch.options", null);
|
||||||
|
boolean enableHacks = Boolean.getBoolean("launcher.runtime.launch.enablehacks");
|
||||||
ClientPermissions permissions = new ClientPermissions();
|
ClientPermissions permissions = new ClientPermissions();
|
||||||
if(mainClass == null) {
|
if(mainClass == null) {
|
||||||
throw new NullPointerException("Add `-Dlauncher.runtime.mainclass=YOUR_MAIN_CLASS` to jvmArgs");
|
throw new NullPointerException("Add `-Dlauncher.runtime.mainclass=YOUR_MAIN_CLASS` to jvmArgs");
|
||||||
|
@ -130,6 +131,7 @@ public void run(String[] args) {
|
||||||
} else {
|
} else {
|
||||||
options = new LaunchOptions();
|
options = new LaunchOptions();
|
||||||
}
|
}
|
||||||
|
options.enableHacks = enableHacks;
|
||||||
ClassLoaderControl classLoaderControl = launch.init(classpath, nativesDir, options);
|
ClassLoaderControl classLoaderControl = launch.init(classpath, nativesDir, options);
|
||||||
ClientService.classLoaderControl = classLoaderControl;
|
ClientService.classLoaderControl = classLoaderControl;
|
||||||
if(compatClasses != null) {
|
if(compatClasses != null) {
|
||||||
|
|
|
@ -460,7 +460,7 @@ public enum ClassLoaderConfig {
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum CompatibilityFlags {
|
public enum CompatibilityFlags {
|
||||||
LEGACY_NATIVES_DIR, CLASS_CONTROL_API
|
LEGACY_NATIVES_DIR, CLASS_CONTROL_API, ENABLE_HACKS
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Version implements Comparable<Version> {
|
public static class Version implements Comparable<Version> {
|
||||||
|
|
|
@ -62,12 +62,20 @@ private static ClientParams readParams(SocketAddress address) throws IOException
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void main(String[] args) throws Throwable {
|
public static void main(String[] args) {
|
||||||
JVMHelper.verifySystemProperties(ClientLauncherEntryPoint.class, true);
|
JVMHelper.verifySystemProperties(ClientLauncherEntryPoint.class, true);
|
||||||
EnvHelper.checkDangerousParams();
|
EnvHelper.checkDangerousParams();
|
||||||
JVMHelper.checkStackTrace(ClientLauncherEntryPoint.class);
|
JVMHelper.checkStackTrace(ClientLauncherEntryPoint.class);
|
||||||
LogHelper.printVersion("Client Launcher");
|
LogHelper.printVersion("Client Launcher");
|
||||||
ClientLauncherMethods.checkClass(ClientLauncherEntryPoint.class);
|
ClientLauncherMethods.checkClass(ClientLauncherEntryPoint.class);
|
||||||
|
try {
|
||||||
|
realMain(args);
|
||||||
|
} catch (Throwable e) {
|
||||||
|
LogHelper.error(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void realMain(String[] args) throws Throwable {
|
||||||
modulesManager = new ClientModuleManager();
|
modulesManager = new ClientModuleManager();
|
||||||
modulesManager.loadModule(new ClientLauncherCoreModule());
|
modulesManager.loadModule(new ClientLauncherCoreModule());
|
||||||
LauncherConfig.initModules(modulesManager); //INIT
|
LauncherConfig.initModules(modulesManager); //INIT
|
||||||
|
@ -132,6 +140,7 @@ public static void main(String[] args) throws Throwable {
|
||||||
LogHelper.debug("Natives dir %s", params.nativesDir);
|
LogHelper.debug("Natives dir %s", params.nativesDir);
|
||||||
ClientProfile.ClassLoaderConfig classLoaderConfig = profile.getClassLoaderConfig();
|
ClientProfile.ClassLoaderConfig classLoaderConfig = profile.getClassLoaderConfig();
|
||||||
LaunchOptions options = new LaunchOptions();
|
LaunchOptions options = new LaunchOptions();
|
||||||
|
options.enableHacks = profile.hasFlag(ClientProfile.CompatibilityFlags.ENABLE_HACKS);
|
||||||
options.moduleConf = profile.getModuleConf();
|
options.moduleConf = profile.getModuleConf();
|
||||||
if (classLoaderConfig == ClientProfile.ClassLoaderConfig.LAUNCHER) {
|
if (classLoaderConfig == ClientProfile.ClassLoaderConfig.LAUNCHER) {
|
||||||
if(JVMHelper.JVM_VERSION <= 11) {
|
if(JVMHelper.JVM_VERSION <= 11) {
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
package pro.gravit.utils.helper;
|
||||||
|
|
||||||
|
import java.lang.invoke.MethodHandles;
|
||||||
|
import java.lang.reflect.Constructor;
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
public class HackHelper {
|
||||||
|
|
||||||
|
private static MethodHandles.Lookup createHackLookupImpl(Class<?> lookupClass) {
|
||||||
|
try {
|
||||||
|
Field trusted = MethodHandles.Lookup.class.getDeclaredField("TRUSTED");
|
||||||
|
trusted.setAccessible(true);
|
||||||
|
int value = (int) trusted.get(null);
|
||||||
|
Constructor<MethodHandles.Lookup> constructor = MethodHandles.Lookup.class.getDeclaredConstructor(Class.class, Class.class,int.class);
|
||||||
|
constructor.setAccessible(true);
|
||||||
|
return constructor.newInstance(lookupClass, null, value);
|
||||||
|
} catch (Throwable e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MethodHandles.Lookup createHackLookup(Class<?> lookupClass) {
|
||||||
|
Exception e = new Exception();
|
||||||
|
StackTraceElement[] elements = e.getStackTrace();
|
||||||
|
String className = elements[elements.length-1].getClassName();
|
||||||
|
if(!className.startsWith("pro.gravit.launcher.") && !className.startsWith("pro.gravit.utils.")) {
|
||||||
|
throw new SecurityException(String.format("Untrusted class %s", className));
|
||||||
|
}
|
||||||
|
return createHackLookupImpl(lookupClass);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
package pro.gravit.utils.launch;
|
package pro.gravit.utils.launch;
|
||||||
|
|
||||||
|
import pro.gravit.utils.helper.HackHelper;
|
||||||
import pro.gravit.utils.helper.JVMHelper;
|
import pro.gravit.utils.helper.JVMHelper;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
@ -23,6 +24,7 @@
|
||||||
public class BasicLaunch implements Launch {
|
public class BasicLaunch implements Launch {
|
||||||
|
|
||||||
private Instrumentation instrumentation;
|
private Instrumentation instrumentation;
|
||||||
|
private MethodHandles.Lookup hackLookup;
|
||||||
|
|
||||||
public BasicLaunch(Instrumentation instrumentation) {
|
public BasicLaunch(Instrumentation instrumentation) {
|
||||||
this.instrumentation = instrumentation;
|
this.instrumentation = instrumentation;
|
||||||
|
@ -33,6 +35,9 @@ public BasicLaunch() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ClassLoaderControl init(List<Path> files, String nativePath, LaunchOptions options) {
|
public ClassLoaderControl init(List<Path> files, String nativePath, LaunchOptions options) {
|
||||||
|
if(options.enableHacks) {
|
||||||
|
hackLookup = HackHelper.createHackLookup(BasicLaunch.class);
|
||||||
|
}
|
||||||
return new BasicClassLoaderControl();
|
return new BasicClassLoaderControl();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,7 +46,7 @@ public void launch(String mainClass, String mainModule, Collection<String> args)
|
||||||
Class<?> mainClazz = Class.forName(mainClass);
|
Class<?> mainClazz = Class.forName(mainClass);
|
||||||
MethodHandle mainMethod = MethodHandles.lookup().findStatic(mainClazz, "main", MethodType.methodType(void.class, String[].class)).asFixedArity();
|
MethodHandle mainMethod = MethodHandles.lookup().findStatic(mainClazz, "main", MethodType.methodType(void.class, String[].class)).asFixedArity();
|
||||||
JVMHelper.fullGC();
|
JVMHelper.fullGC();
|
||||||
mainMethod.invokeWithArguments((Object) args.toArray(new String[0]));
|
mainMethod.asFixedArity().invokeWithArguments((Object) args.toArray(new String[0]));
|
||||||
}
|
}
|
||||||
|
|
||||||
private class BasicClassLoaderControl implements ClassLoaderControl {
|
private class BasicClassLoaderControl implements ClassLoaderControl {
|
||||||
|
@ -120,5 +125,10 @@ public ClassLoader getClassLoader() {
|
||||||
public Object getJava9ModuleController() {
|
public Object getJava9ModuleController() {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MethodHandles.Lookup getHackLookup() {
|
||||||
|
return hackLookup;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package pro.gravit.utils.launch;
|
package pro.gravit.utils.launch;
|
||||||
|
|
||||||
|
import java.lang.invoke.MethodHandles;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.security.ProtectionDomain;
|
import java.security.ProtectionDomain;
|
||||||
|
@ -16,6 +17,8 @@ public interface ClassLoaderControl {
|
||||||
ClassLoader getClassLoader();
|
ClassLoader getClassLoader();
|
||||||
|
|
||||||
Object getJava9ModuleController();
|
Object getJava9ModuleController();
|
||||||
|
|
||||||
|
MethodHandles.Lookup getHackLookup();
|
||||||
interface ClassTransformer {
|
interface ClassTransformer {
|
||||||
boolean filter(String moduleName, String name);
|
boolean filter(String moduleName, String name);
|
||||||
byte[] transform(String moduleName, String name, ProtectionDomain protectionDomain, byte[] data);
|
byte[] transform(String moduleName, String name, ProtectionDomain protectionDomain, byte[] data);
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
public class LaunchOptions {
|
public class LaunchOptions {
|
||||||
|
public boolean enableHacks;
|
||||||
public ModuleConf moduleConf;
|
public ModuleConf moduleConf;
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package pro.gravit.utils.launch;
|
package pro.gravit.utils.launch;
|
||||||
|
|
||||||
|
import pro.gravit.utils.helper.HackHelper;
|
||||||
import pro.gravit.utils.helper.IOHelper;
|
import pro.gravit.utils.helper.IOHelper;
|
||||||
import pro.gravit.utils.helper.JVMHelper;
|
import pro.gravit.utils.helper.JVMHelper;
|
||||||
|
|
||||||
|
@ -20,6 +21,7 @@
|
||||||
|
|
||||||
public class LegacyLaunch implements Launch {
|
public class LegacyLaunch implements Launch {
|
||||||
private LegacyClassLoader legacyClassLoader;
|
private LegacyClassLoader legacyClassLoader;
|
||||||
|
private MethodHandles.Lookup hackLookup;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ClassLoaderControl init(List<Path> files, String nativePath, LaunchOptions options) {
|
public ClassLoaderControl init(List<Path> files, String nativePath, LaunchOptions options) {
|
||||||
|
@ -31,6 +33,9 @@ public ClassLoaderControl init(List<Path> files, String nativePath, LaunchOption
|
||||||
}
|
}
|
||||||
}).toArray(URL[]::new), BasicLaunch.class.getClassLoader());
|
}).toArray(URL[]::new), BasicLaunch.class.getClassLoader());
|
||||||
legacyClassLoader.nativePath = nativePath;
|
legacyClassLoader.nativePath = nativePath;
|
||||||
|
if(options.enableHacks) {
|
||||||
|
hackLookup = HackHelper.createHackLookup(BasicLaunch.class);
|
||||||
|
}
|
||||||
return legacyClassLoader.makeControl();
|
return legacyClassLoader.makeControl();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,10 +45,10 @@ public void launch(String mainClass, String mainModule, Collection<String> args)
|
||||||
Class<?> mainClazz = Class.forName(mainClass, true, legacyClassLoader);
|
Class<?> mainClazz = Class.forName(mainClass, true, legacyClassLoader);
|
||||||
MethodHandle mainMethod = MethodHandles.lookup().findStatic(mainClazz, "main", MethodType.methodType(void.class, String[].class)).asFixedArity();
|
MethodHandle mainMethod = MethodHandles.lookup().findStatic(mainClazz, "main", MethodType.methodType(void.class, String[].class)).asFixedArity();
|
||||||
JVMHelper.fullGC();
|
JVMHelper.fullGC();
|
||||||
mainMethod.invokeWithArguments((Object) args.toArray(new String[0]));
|
mainMethod.asFixedArity().invokeWithArguments((Object) args.toArray(new String[0]));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class LegacyClassLoader extends URLClassLoader {
|
private class LegacyClassLoader extends URLClassLoader {
|
||||||
private final ClassLoader SYSTEM_CLASS_LOADER = ClassLoader.getSystemClassLoader();
|
private final ClassLoader SYSTEM_CLASS_LOADER = ClassLoader.getSystemClassLoader();
|
||||||
private final List<ClassLoaderControl.ClassTransformer> transformers = new ArrayList<>();
|
private final List<ClassLoaderControl.ClassTransformer> transformers = new ArrayList<>();
|
||||||
private final Map<String, Class<?>> classMap = new ConcurrentHashMap<>();
|
private final Map<String, Class<?>> classMap = new ConcurrentHashMap<>();
|
||||||
|
@ -170,6 +175,11 @@ public ClassLoader getClassLoader() {
|
||||||
public Object getJava9ModuleController() {
|
public Object getJava9ModuleController() {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MethodHandles.Lookup getHackLookup() {
|
||||||
|
return hackLookup;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
package pro.gravit.utils.launch;
|
||||||
|
|
||||||
|
import java.lang.invoke.MethodHandles;
|
||||||
|
import java.lang.invoke.MethodType;
|
||||||
|
|
||||||
|
public class ModuleHacks {
|
||||||
|
|
||||||
|
public static ModuleLayer.Controller createController(MethodHandles.Lookup lookup, ModuleLayer layer) {
|
||||||
|
try {
|
||||||
|
return (ModuleLayer.Controller) lookup.findConstructor(ModuleLayer.Controller.class, MethodType.methodType(void.class, ModuleLayer.class)).invoke(layer);
|
||||||
|
} catch (Throwable e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
package pro.gravit.utils.launch;
|
package pro.gravit.utils.launch;
|
||||||
|
|
||||||
|
import pro.gravit.utils.helper.HackHelper;
|
||||||
import pro.gravit.utils.helper.IOHelper;
|
import pro.gravit.utils.helper.IOHelper;
|
||||||
import pro.gravit.utils.helper.JVMHelper;
|
import pro.gravit.utils.helper.JVMHelper;
|
||||||
import pro.gravit.utils.helper.LogHelper;
|
import pro.gravit.utils.helper.LogHelper;
|
||||||
|
@ -12,6 +13,7 @@
|
||||||
import java.lang.module.Configuration;
|
import java.lang.module.Configuration;
|
||||||
import java.lang.module.ModuleFinder;
|
import java.lang.module.ModuleFinder;
|
||||||
import java.net.MalformedURLException;
|
import java.net.MalformedURLException;
|
||||||
|
import java.net.URI;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.net.URLClassLoader;
|
import java.net.URLClassLoader;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
@ -28,6 +30,7 @@ public class ModuleLaunch implements Launch {
|
||||||
private ModuleLayer.Controller controller;
|
private ModuleLayer.Controller controller;
|
||||||
private ModuleFinder moduleFinder;
|
private ModuleFinder moduleFinder;
|
||||||
private ModuleLayer layer;
|
private ModuleLayer layer;
|
||||||
|
private MethodHandles.Lookup hackLookup;
|
||||||
@Override
|
@Override
|
||||||
public ClassLoaderControl init(List<Path> files, String nativePath, LaunchOptions options) {
|
public ClassLoaderControl init(List<Path> files, String nativePath, LaunchOptions options) {
|
||||||
moduleClassLoader = new ModuleClassLoader(files.stream().map((e) -> {
|
moduleClassLoader = new ModuleClassLoader(files.stream().map((e) -> {
|
||||||
|
@ -39,37 +42,87 @@ public ClassLoaderControl init(List<Path> files, String nativePath, LaunchOption
|
||||||
}).toArray(URL[]::new), BasicLaunch.class.getClassLoader());
|
}).toArray(URL[]::new), BasicLaunch.class.getClassLoader());
|
||||||
moduleClassLoader.nativePath = nativePath;
|
moduleClassLoader.nativePath = nativePath;
|
||||||
{
|
{
|
||||||
|
if(options.enableHacks) {
|
||||||
|
hackLookup = HackHelper.createHackLookup(ModuleLaunch.class);
|
||||||
|
}
|
||||||
if(options.moduleConf != null) {
|
if(options.moduleConf != null) {
|
||||||
// Create Module Layer
|
// Create Module Layer
|
||||||
moduleFinder = ModuleFinder.of(options.moduleConf.modulePath.stream().map(Paths::get).toArray(Path[]::new));
|
moduleFinder = ModuleFinder.of(options.moduleConf.modulePath.stream().map(Paths::get).map(Path::toAbsolutePath).toArray(Path[]::new));
|
||||||
ModuleLayer bootLayer = ModuleLayer.boot();
|
ModuleLayer bootLayer = ModuleLayer.boot();
|
||||||
|
if(options.moduleConf.modules.contains("ALL-MODULE-PATH")) {
|
||||||
|
var set = moduleFinder.findAll();
|
||||||
|
if(LogHelper.isDevEnabled()) {
|
||||||
|
for(var m : set) {
|
||||||
|
LogHelper.dev("Found module %s in %s", m.descriptor().name(), m.location().map(URI::toString).orElse("unknown"));
|
||||||
|
}
|
||||||
|
LogHelper.dev("Found %d modules", set.size());
|
||||||
|
}
|
||||||
|
for(var m : set) {
|
||||||
|
options.moduleConf.modules.add(m.descriptor().name());
|
||||||
|
}
|
||||||
|
options.moduleConf.modules.remove("ALL-MODULE-PATH");
|
||||||
|
}
|
||||||
configuration = bootLayer.configuration()
|
configuration = bootLayer.configuration()
|
||||||
.resolveAndBind(ModuleFinder.of(), moduleFinder, options.moduleConf.modules);
|
.resolveAndBind(moduleFinder, ModuleFinder.of(), options.moduleConf.modules);
|
||||||
controller = ModuleLayer.defineModulesWithOneLoader(configuration, List.of(bootLayer), moduleClassLoader);
|
controller = ModuleLayer.defineModulesWithOneLoader(configuration, List.of(bootLayer), moduleClassLoader);
|
||||||
moduleClassLoader.controller = controller;
|
|
||||||
layer = controller.layer();
|
layer = controller.layer();
|
||||||
// Configure exports / opens
|
// Configure exports / opens
|
||||||
for(var e : options.moduleConf.exports.entrySet()) {
|
for(var e : options.moduleConf.exports.entrySet()) {
|
||||||
String[] split = e.getKey().split("\\\\");
|
String[] split = e.getKey().split("/");
|
||||||
Module source = layer.findModule(split[0]).orElseThrow();
|
String moduleName = split[0];
|
||||||
String pkg = split[1];
|
String pkg = split[1];
|
||||||
Module target = layer.findModule(e.getValue()).orElseThrow();
|
LogHelper.dev("Export module: %s package: %s to %s", moduleName, pkg, e.getValue());
|
||||||
|
Module source = layer.findModule(split[0]).orElse(null);
|
||||||
|
if(source == null) {
|
||||||
|
throw new RuntimeException(String.format("Module %s not found", moduleName));
|
||||||
|
}
|
||||||
|
Module target = layer.findModule(e.getValue()).orElse(null);
|
||||||
|
if(target == null) {
|
||||||
|
throw new RuntimeException(String.format("Module %s not found", e.getValue()));
|
||||||
|
}
|
||||||
|
if(options.enableHacks && source.getLayer() != layer) {
|
||||||
|
ModuleHacks.createController(hackLookup, source.getLayer()).addExports(source, pkg, target);
|
||||||
|
} else {
|
||||||
controller.addExports(source, pkg, target);
|
controller.addExports(source, pkg, target);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
for(var e : options.moduleConf.opens.entrySet()) {
|
for(var e : options.moduleConf.opens.entrySet()) {
|
||||||
String[] split = e.getKey().split("\\\\");
|
String[] split = e.getKey().split("/");
|
||||||
Module source = layer.findModule(split[0]).orElseThrow();
|
String moduleName = split[0];
|
||||||
String pkg = split[1];
|
String pkg = split[1];
|
||||||
Module target = layer.findModule(e.getValue()).orElseThrow();
|
LogHelper.dev("Open module: %s package: %s to %s", moduleName, pkg, e.getValue());
|
||||||
|
Module source = layer.findModule(split[0]).orElse(null);
|
||||||
|
if(source == null) {
|
||||||
|
throw new RuntimeException(String.format("Module %s not found", moduleName));
|
||||||
|
}
|
||||||
|
Module target = layer.findModule(e.getValue()).orElse(null);
|
||||||
|
if(target == null) {
|
||||||
|
throw new RuntimeException(String.format("Module %s not found", e.getValue()));
|
||||||
|
}
|
||||||
|
if(options.enableHacks && source.getLayer() != layer) {
|
||||||
|
ModuleHacks.createController(hackLookup, source.getLayer()).addOpens(source, pkg, target);
|
||||||
|
} else {
|
||||||
controller.addOpens(source, pkg, target);
|
controller.addOpens(source, pkg, target);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
for(var e : options.moduleConf.reads.entrySet()) {
|
for(var e : options.moduleConf.reads.entrySet()) {
|
||||||
Module source = layer.findModule(e.getKey()).orElseThrow();
|
LogHelper.dev("Read module %s to %s", e.getKey(), e.getValue());
|
||||||
Module target = layer.findModule(e.getValue()).orElseThrow();
|
Module source = layer.findModule(e.getKey()).orElse(null);
|
||||||
|
if(source == null) {
|
||||||
|
throw new RuntimeException(String.format("Module %s not found", e.getKey()));
|
||||||
|
}
|
||||||
|
Module target = layer.findModule(e.getValue()).orElse(null);
|
||||||
|
if(target == null) {
|
||||||
|
throw new RuntimeException(String.format("Module %s not found", e.getValue()));
|
||||||
|
}
|
||||||
|
if(options.enableHacks && source.getLayer() != layer) {
|
||||||
|
ModuleHacks.createController(hackLookup, source.getLayer()).addReads(source, target);
|
||||||
|
} else {
|
||||||
controller.addReads(source, target);
|
controller.addReads(source, target);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return moduleClassLoader.makeControl();
|
return moduleClassLoader.makeControl();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,7 +133,7 @@ public void launch(String mainClass, String mainModuleName, Collection<String> a
|
||||||
Class<?> mainClazz = Class.forName(mainClass, true, moduleClassLoader);
|
Class<?> mainClazz = Class.forName(mainClass, true, moduleClassLoader);
|
||||||
MethodHandle mainMethod = MethodHandles.lookup().findStatic(mainClazz, "main", MethodType.methodType(void.class, String[].class)).asFixedArity();
|
MethodHandle mainMethod = MethodHandles.lookup().findStatic(mainClazz, "main", MethodType.methodType(void.class, String[].class)).asFixedArity();
|
||||||
JVMHelper.fullGC();
|
JVMHelper.fullGC();
|
||||||
mainMethod.invokeWithArguments((Object) args.toArray(new String[0]));
|
mainMethod.asFixedArity().invokeWithArguments((Object) args.toArray(new String[0]));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Module mainModule = layer.findModule(mainModuleName).orElseThrow();
|
Module mainModule = layer.findModule(mainModuleName).orElseThrow();
|
||||||
|
@ -92,7 +145,7 @@ public void launch(String mainClass, String mainModuleName, Collection<String> a
|
||||||
ClassLoader loader = mainModule.getClassLoader();
|
ClassLoader loader = mainModule.getClassLoader();
|
||||||
Class<?> mainClazz = Class.forName(mainClass, true, loader);
|
Class<?> mainClazz = Class.forName(mainClass, true, loader);
|
||||||
MethodHandle mainMethod = MethodHandles.lookup().findStatic(mainClazz, "main", MethodType.methodType(void.class, String[].class));
|
MethodHandle mainMethod = MethodHandles.lookup().findStatic(mainClazz, "main", MethodType.methodType(void.class, String[].class));
|
||||||
mainMethod.invoke((Object) args.toArray(new String[0]));
|
mainMethod.asFixedArity().invokeWithArguments((Object) args.toArray(new String[0]));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String getPackageFromClass(String clazz) {
|
private static String getPackageFromClass(String clazz) {
|
||||||
|
@ -103,14 +156,12 @@ private static String getPackageFromClass(String clazz) {
|
||||||
return clazz;
|
return clazz;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class ModuleClassLoader extends URLClassLoader {
|
private class ModuleClassLoader extends URLClassLoader {
|
||||||
private final ClassLoader SYSTEM_CLASS_LOADER = ClassLoader.getSystemClassLoader();
|
private final ClassLoader SYSTEM_CLASS_LOADER = ClassLoader.getSystemClassLoader();
|
||||||
private final List<ClassLoaderControl.ClassTransformer> transformers = new ArrayList<>();
|
private final List<ClassLoaderControl.ClassTransformer> transformers = new ArrayList<>();
|
||||||
private final Map<String, Class<?>> classMap = new ConcurrentHashMap<>();
|
private final Map<String, Class<?>> classMap = new ConcurrentHashMap<>();
|
||||||
private String nativePath;
|
private String nativePath;
|
||||||
|
|
||||||
private ModuleLayer.Controller controller;
|
|
||||||
|
|
||||||
private final List<String> packages = new ArrayList<>();
|
private final List<String> packages = new ArrayList<>();
|
||||||
public ModuleClassLoader(URL[] urls) {
|
public ModuleClassLoader(URL[] urls) {
|
||||||
super(urls);
|
super(urls);
|
||||||
|
@ -245,6 +296,11 @@ public ClassLoader getClassLoader() {
|
||||||
public Object getJava9ModuleController() {
|
public Object getJava9ModuleController() {
|
||||||
return controller;
|
return controller;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MethodHandles.Lookup getHackLookup() {
|
||||||
|
return hackLookup;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -189,6 +189,7 @@ public void run(String... args) throws Throwable {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
LaunchOptions options = new LaunchOptions();
|
LaunchOptions options = new LaunchOptions();
|
||||||
|
options.enableHacks = config.enableHacks;
|
||||||
options.moduleConf = config.moduleConf;
|
options.moduleConf = config.moduleConf;
|
||||||
classLoaderControl = launch.init(config.classpath.stream().map(Paths::get).collect(Collectors.toCollection(ArrayList::new)), config.nativesDir, options);
|
classLoaderControl = launch.init(config.classpath.stream().map(Paths::get).collect(Collectors.toCollection(ArrayList::new)), config.nativesDir, options);
|
||||||
LogHelper.info("Start Minecraft Server");
|
LogHelper.info("Start Minecraft Server");
|
||||||
|
@ -263,6 +264,7 @@ public static final class Config {
|
||||||
public byte[] encodedServerRsaPublicKey;
|
public byte[] encodedServerRsaPublicKey;
|
||||||
|
|
||||||
public byte[] encodedServerEcPublicKey;
|
public byte[] encodedServerEcPublicKey;
|
||||||
|
public boolean enableHacks;
|
||||||
|
|
||||||
public Map<String, String> properties;
|
public Map<String, String> properties;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue