package com.oracle.svm.core;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.graalvm.compiler.word.Word;
import org.graalvm.nativeimage.ImageSingletons;
import org.graalvm.nativeimage.Platform;
import org.graalvm.nativeimage.Platforms;
import org.graalvm.nativeimage.c.function.CEntryPoint;
import org.graalvm.nativeimage.c.struct.SizeOf;
import org.graalvm.nativeimage.c.type.CCharPointer;
import org.graalvm.nativeimage.c.type.CCharPointerPointer;
import org.graalvm.nativeimage.c.type.CTypeConversion;
import org.graalvm.nativeimage.c.type.CTypeConversion.CCharPointerHolder;
import org.graalvm.word.Pointer;
import org.graalvm.word.UnsignedWord;
import org.graalvm.word.WordFactory;
import com.oracle.svm.core.annotate.AlwaysInline;
import com.oracle.svm.core.c.CGlobalData;
import com.oracle.svm.core.c.CGlobalDataFactory;
import com.oracle.svm.core.c.function.CEntryPointActions;
import com.oracle.svm.core.c.function.CEntryPointCreateIsolateParameters;
import com.oracle.svm.core.c.function.CEntryPointOptions;
import com.oracle.svm.core.jdk.InternalVMMethod;
import com.oracle.svm.core.jdk.RuntimeSupport;
import com.oracle.svm.core.thread.JavaThreads;
import com.oracle.svm.core.util.Counter;
import jdk.vm.ci.code.Architecture;
@InternalVMMethod
public class JavaMainWrapper {
public static final CGlobalData<CEntryPointCreateIsolateParameters> MAIN_ISOLATE_PARAMETERS = CGlobalDataFactory.createBytes(() -> SizeOf.get(CEntryPointCreateIsolateParameters.class));
static {
Word.ensureInitialized();
}
private static UnsignedWord argvLength = WordFactory.zero();
public static class JavaMainSupport {
final MethodHandle javaMainHandle;
final String javaMainClassName;
public String[] mainArgs;
@Platforms(Platform.HOSTED_ONLY.class)
public JavaMainSupport(Method javaMainMethod) throws IllegalAccessException {
this.javaMainHandle = MethodHandles.lookup().unreflect(javaMainMethod);
this.javaMainClassName = javaMainMethod.getDeclaringClass().getName();
}
public String getJavaCommand() {
if (mainArgs != null) {
StringBuilder commandLine = new StringBuilder(javaMainClassName);
for (String arg : mainArgs) {
commandLine.append(' ');
commandLine.append(arg);
}
return commandLine.toString();
}
return null;
}
public List<String> getInputArguments() {
CEntryPointCreateIsolateParameters args = MAIN_ISOLATE_PARAMETERS.get();
if (args.getArgv().isNonNull() && args.getArgc() > 0) {
String[] unmodifiedArgs = SubstrateUtil.getArgs(args.getArgc(), args.getArgv());
List<String> inputArgs = new ArrayList<>(Arrays.asList(unmodifiedArgs));
if (mainArgs != null) {
inputArgs.removeAll(Arrays.asList(mainArgs));
}
return Collections.unmodifiableList(inputArgs);
}
return Collections.emptyList();
}
}
@AlwaysInline(value = "Single callee from the main entry point.")
public static int runCore() {
Architecture imageArchitecture = ImageSingletons.lookup(SubstrateTargetDescription.class).arch;
CPUFeatureAccess cpuFeatureAccess = ImageSingletons.lookup(CPUFeatureAccess.class);
cpuFeatureAccess.verifyHostSupportsArchitecture(imageArchitecture);
int exitCode;
try {
if (SubstrateOptions.ParseRuntimeOptions.getValue()) {
RuntimeSupport.getRuntimeSupport().executeStartupHooks();
}
JavaMainSupport mainSupport = ImageSingletons.lookup(JavaMainSupport.class);
mainSupport.javaMainHandle.invokeExact(mainSupport.mainArgs);
exitCode = 0;
} catch (Throwable ex) {
JavaThreads.dispatchUncaughtException(Thread.currentThread(), ex);
exitCode = 1;
} finally {
JavaThreads.singleton().joinAllNonDaemons();
RuntimeSupport.getRuntimeSupport().shutdown();
Counter.logValues();
}
return exitCode;
}
@CEntryPoint
@CEntryPointOptions(prologue = EnterCreateIsolateWithCArgumentsPrologue.class, include = CEntryPointOptions.NotIncludedAutomatically.class)
@SuppressWarnings("unused")
public static int run(int argc, CCharPointerPointer argv) {
return runCore();
}
private static boolean isArgumentBlockSupported() {
if (!Platform.includedIn(Platform.LINUX.class) && !Platform.includedIn(Platform.DARWIN.class)) {
return false;
}
CEntryPointCreateIsolateParameters args = MAIN_ISOLATE_PARAMETERS.get();
if (args.getArgv().isNull() || args.getArgc() <= 0) {
return false;
}
return true;
}
public static int getCRuntimeArgumentBlockLength() {
if (!isArgumentBlockSupported()) {
return -1;
}
CEntryPointCreateIsolateParameters args = MAIN_ISOLATE_PARAMETERS.get();
CCharPointer firstArgPos = args.getArgv().read(0);
if (argvLength.equal(WordFactory.zero())) {
CCharPointer lastArgPos = args.getArgv().read(args.getArgc() - 1);
UnsignedWord lastArgLength = SubstrateUtil.strlen(lastArgPos);
argvLength = WordFactory.unsigned(lastArgPos.rawValue()).add(lastArgLength).subtract(WordFactory.unsigned(firstArgPos.rawValue()));
}
return Math.toIntExact(argvLength.rawValue());
}
public static boolean setCRuntimeArgument0(String arg0) {
if (!isArgumentBlockSupported()) {
throw new UnsupportedOperationException("Argument vector support not available");
}
boolean arg0truncation = false;
try (CCharPointerHolder arg0Pin = CTypeConversion.toCString(arg0)) {
CCharPointer arg0Pointer = arg0Pin.get();
UnsignedWord arg0Length = SubstrateUtil.strlen(arg0Pointer);
UnsignedWord origLength = WordFactory.unsigned(getCRuntimeArgumentBlockLength());
UnsignedWord newArgLength = origLength;
if (arg0Length.add(1).belowThan(origLength)) {
newArgLength = arg0Length.add(1);
}
arg0truncation = arg0Length.aboveThan(origLength);
CCharPointer firstArgPos = MAIN_ISOLATE_PARAMETERS.get().getArgv().read(0);
MemoryUtil.copyConjointMemoryAtomic(WordFactory.pointer(arg0Pointer.rawValue()), WordFactory.pointer(firstArgPos.rawValue()), newArgLength);
MemoryUtil.fillToMemoryAtomic((Pointer) WordFactory.unsigned(firstArgPos.rawValue()).add(newArgLength), origLength.subtract(newArgLength), (byte) 0);
}
return arg0truncation;
}
public static String getCRuntimeArgument0() {
if (!isArgumentBlockSupported()) {
throw new UnsupportedOperationException("Argument vector support not available");
}
return CTypeConversion.toJavaString(MAIN_ISOLATE_PARAMETERS.get().getArgv().read(0));
}
private static class EnterCreateIsolateWithCArgumentsPrologue {
private static final CGlobalData<CCharPointer> errorMessage = CGlobalDataFactory.createCString(
"Failed to create the main Isolate.");
@SuppressWarnings("unused")
public static void enter(int paramArgc, CCharPointerPointer paramArgv) {
CEntryPointCreateIsolateParameters args = MAIN_ISOLATE_PARAMETERS.get();
args.setVersion(3);
args.setArgc(paramArgc);
args.setArgv(paramArgv);
int code = CEntryPointActions.enterCreateIsolate(args);
if (code != 0) {
CEntryPointActions.failFatally(code, errorMessage.get());
}
}
}
}