package com.oracle.svm.core.graal.snippets;
import static com.oracle.svm.core.SubstrateOptions.MultiThreaded;
import static com.oracle.svm.core.SubstrateOptions.SpawnIsolates;
import static com.oracle.svm.core.SubstrateOptions.UseDedicatedVMOperationThread;
import static com.oracle.svm.core.graal.nodes.WriteCurrentVMThreadNode.writeCurrentVMThread;
import static com.oracle.svm.core.graal.nodes.WriteHeapBaseNode.writeCurrentVMHeapBase;
import static com.oracle.svm.core.util.VMError.shouldNotReachHere;
import java.util.Map;
import org.graalvm.compiler.api.replacements.Fold;
import org.graalvm.compiler.api.replacements.Snippet;
import org.graalvm.compiler.api.replacements.Snippet.ConstantParameter;
import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
import org.graalvm.compiler.core.common.CompressEncoding;
import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
import org.graalvm.compiler.debug.DebugHandlersFactory;
import org.graalvm.compiler.graph.Node;
import org.graalvm.compiler.graph.Node.ConstantNodeParameter;
import org.graalvm.compiler.graph.Node.NodeIntrinsic;
import org.graalvm.compiler.nodes.extended.ForeignCallNode;
import org.graalvm.compiler.nodes.spi.LoweringTool;
import org.graalvm.compiler.options.OptionValues;
import org.graalvm.compiler.phases.util.Providers;
import org.graalvm.compiler.replacements.SnippetTemplate;
import org.graalvm.compiler.replacements.SnippetTemplate.Arguments;
import org.graalvm.compiler.replacements.SnippetTemplate.SnippetInfo;
import org.graalvm.compiler.replacements.Snippets;
import org.graalvm.compiler.serviceprovider.GraalUnsafeAccess;
import org.graalvm.compiler.word.Word;
import org.graalvm.nativeimage.CurrentIsolate;
import org.graalvm.nativeimage.ImageSingletons;
import org.graalvm.nativeimage.Isolate;
import org.graalvm.nativeimage.IsolateThread;
import org.graalvm.nativeimage.LogHandler;
import org.graalvm.nativeimage.StackValue;
import org.graalvm.nativeimage.c.type.CCharPointer;
import org.graalvm.nativeimage.c.type.WordPointer;
import org.graalvm.word.LocationIdentity;
import org.graalvm.word.PointerBase;
import org.graalvm.word.WordFactory;
import com.oracle.svm.core.Isolates;
import com.oracle.svm.core.JavaMainWrapper.JavaMainSupport;
import com.oracle.svm.core.RuntimeAssertionsSupport;
import com.oracle.svm.core.SubstrateUtil;
import com.oracle.svm.core.annotate.RestrictHeapAccess;
import com.oracle.svm.core.annotate.Uninterruptible;
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.CEntryPointErrors;
import com.oracle.svm.core.c.function.CEntryPointNativeFunctions;
import com.oracle.svm.core.c.function.CEntryPointSetup;
import com.oracle.svm.core.code.CodeInfoTable;
import com.oracle.svm.core.graal.meta.SubstrateForeignCallsProvider;
import com.oracle.svm.core.graal.nodes.CEntryPointEnterNode;
import com.oracle.svm.core.graal.nodes.CEntryPointLeaveNode;
import com.oracle.svm.core.graal.nodes.CEntryPointUtilityNode;
import com.oracle.svm.core.jdk.PlatformNativeLibrarySupport;
import com.oracle.svm.core.jdk.RuntimeSupport;
import com.oracle.svm.core.log.Log;
import com.oracle.svm.core.option.RuntimeOptionParser;
import com.oracle.svm.core.os.MemoryProtectionKeyProvider;
import com.oracle.svm.core.snippets.SnippetRuntime;
import com.oracle.svm.core.snippets.SnippetRuntime.SubstrateForeignCallDescriptor;
import com.oracle.svm.core.snippets.SubstrateForeignCallTarget;
import com.oracle.svm.core.stack.StackOverflowCheck;
import com.oracle.svm.core.thread.JavaThreads;
import com.oracle.svm.core.thread.Safepoint;
import com.oracle.svm.core.thread.VMOperationControl;
import com.oracle.svm.core.thread.VMThreads;
import com.oracle.svm.core.util.VMError;
import sun.misc.Unsafe;
public final class CEntryPointSnippets extends SubstrateTemplates implements Snippets {
public static final SubstrateForeignCallDescriptor CREATE_ISOLATE = SnippetRuntime.findForeignCall(CEntryPointSnippets.class, "createIsolate", false, LocationIdentity.any());
public static final SubstrateForeignCallDescriptor INITIALIZE_ISOLATE = SnippetRuntime.findForeignCall(CEntryPointSnippets.class, "initializeIsolate", false, LocationIdentity.any());
public static final SubstrateForeignCallDescriptor ATTACH_THREAD = SnippetRuntime.findForeignCall(CEntryPointSnippets.class, "attachThread", false, LocationIdentity.any());
public static final SubstrateForeignCallDescriptor ENSURE_JAVA_THREAD = SnippetRuntime.findForeignCall(CEntryPointSnippets.class, "ensureJavaThread", false, LocationIdentity.any());
public static final SubstrateForeignCallDescriptor ENTER_ISOLATE_MT = SnippetRuntime.findForeignCall(CEntryPointSnippets.class, "enterIsolateMT", false, LocationIdentity.any());
public static final SubstrateForeignCallDescriptor DETACH_THREAD_MT = SnippetRuntime.findForeignCall(CEntryPointSnippets.class, "detachThreadMT", false, LocationIdentity.any());
public static final SubstrateForeignCallDescriptor REPORT_EXCEPTION = SnippetRuntime.findForeignCall(CEntryPointSnippets.class, "reportException", false, LocationIdentity.any());
public static final SubstrateForeignCallDescriptor TEAR_DOWN_ISOLATE = SnippetRuntime.findForeignCall(CEntryPointSnippets.class, "tearDownIsolate", false, LocationIdentity.any());
public static final SubstrateForeignCallDescriptor IS_ATTACHED_MT = SnippetRuntime.findForeignCall(CEntryPointSnippets.class, "isAttachedMT", false, LocationIdentity.any());
public static final SubstrateForeignCallDescriptor FAIL_FATALLY = SnippetRuntime.findForeignCall(CEntryPointSnippets.class, "failFatally", false, LocationIdentity.any());
public static final SubstrateForeignCallDescriptor VERIFY_ISOLATE_THREAD = SnippetRuntime.findForeignCall(CEntryPointSnippets.class, "verifyIsolateThread", false, LocationIdentity.any());
public static final SubstrateForeignCallDescriptor[] FOREIGN_CALLS = {CREATE_ISOLATE, INITIALIZE_ISOLATE, ATTACH_THREAD, ENSURE_JAVA_THREAD, ENTER_ISOLATE_MT,
DETACH_THREAD_MT, REPORT_EXCEPTION, TEAR_DOWN_ISOLATE, IS_ATTACHED_MT, FAIL_FATALLY, VERIFY_ISOLATE_THREAD};
@NodeIntrinsic(value = ForeignCallNode.class)
public static native int runtimeCall(@ConstantNodeParameter ForeignCallDescriptor descriptor, CEntryPointCreateIsolateParameters parameters, int vmThreadSize);
@NodeIntrinsic(value = ForeignCallNode.class)
public static native int runtimeCall(@ConstantNodeParameter ForeignCallDescriptor descriptor, Isolate isolate, int vmThreadSize);
@NodeIntrinsic(value = ForeignCallNode.class)
public static native int runtimeCall(@ConstantNodeParameter ForeignCallDescriptor descriptor, Isolate isolate, boolean inCrashHandler);
@NodeIntrinsic(value = ForeignCallNode.class)
public static native int runtimeCall(@ConstantNodeParameter ForeignCallDescriptor descriptor, IsolateThread thread);
@NodeIntrinsic(value = ForeignCallNode.class)
public static native int runtimeCall(@ConstantNodeParameter ForeignCallDescriptor descriptor, Throwable exception);
@NodeIntrinsic(value = ForeignCallNode.class)
public static native int runtimeCallInitializeIsolate(@ConstantNodeParameter ForeignCallDescriptor descriptor, CEntryPointCreateIsolateParameters parameters);
@NodeIntrinsic(value = ForeignCallNode.class)
public static native int runtimeCallTearDownIsolate(@ConstantNodeParameter ForeignCallDescriptor descriptor);
@NodeIntrinsic(value = ForeignCallNode.class)
public static native boolean runtimeCallIsAttached(@ConstantNodeParameter ForeignCallDescriptor descriptor, Isolate isolate);
@NodeIntrinsic(value = ForeignCallNode.class)
public static native void runtimeCallFailFatally(@ConstantNodeParameter ForeignCallDescriptor descriptor, int code, CCharPointer message);
@Fold
static boolean hasHeapBase() {
return ImageSingletons.lookup(CompressEncoding.class).hasBase();
}
@Uninterruptible(reason = "Called by an uninterruptible method.", mayBeInlined = true)
public static void setHeapBase(PointerBase heapBase) {
if (hasHeapBase()) {
writeCurrentVMHeapBase(heapBase);
if (MemoryProtectionKeyProvider.isAvailable()) {
MemoryProtectionKeyProvider.singleton().unlockCurrentIsolate();
}
} else {
writeCurrentVMHeapBase(WordFactory.nullPointer());
}
}
public interface IsolateCreationWatcher {
void registerIsolate(Isolate isolate);
}
@Snippet
public static int createIsolateSnippet(CEntryPointCreateIsolateParameters parameters, @ConstantParameter int vmThreadSize) {
if (MultiThreaded.getValue()) {
writeCurrentVMThread(WordFactory.nullPointer());
}
int result = runtimeCall(CREATE_ISOLATE, parameters, vmThreadSize);
if (result != CEntryPointErrors.NO_ERROR) {
return result;
}
if (MultiThreaded.getValue()) {
Safepoint.transitionNativeToJava();
}
result = runtimeCallInitializeIsolate(INITIALIZE_ISOLATE, parameters);
return result;
}
@Uninterruptible(reason = "Thread state not yet set up.")
@SubstrateForeignCallTarget(stubCallingConvention = false)
private static int createIsolate(CEntryPointCreateIsolateParameters parameters, int vmThreadSize) {
WordPointer isolate = StackValue.get(WordPointer.class);
isolate.write(WordFactory.nullPointer());
int error = Isolates.create(isolate, parameters);
if (error != CEntryPointErrors.NO_ERROR) {
return error;
}
if (SpawnIsolates.getValue()) {
setHeapBase(Isolates.getHeapBase(isolate.read()));
}
if (ImageSingletons.contains(IsolateCreationWatcher.class)) {
ImageSingletons.lookup(IsolateCreationWatcher.class).registerIsolate(isolate.read());
}
CodeInfoTable.prepareImageCodeInfo();
if (MultiThreaded.getValue()) {
if (!VMThreads.ensureInitialized()) {
return CEntryPointErrors.THREADING_INITIALIZATION_FAILED;
}
}
error = attachThread(isolate.read(), vmThreadSize);
if (error != CEntryPointErrors.NO_ERROR) {
return error;
}
JavaThreads.singleton().initializeIsolate();
return CEntryPointErrors.NO_ERROR;
}
private static final class FirstIsolateInitStates {
static final int UNINITIALIZED = 0;
static final int IN_PROGRESS = 1;
static final int SUCCESSFUL = 2;
static final int FAILED = -1;
}
private static final CGlobalData<PointerBase> FIRST_ISOLATE_INIT_STATE = CGlobalDataFactory.createWord();
private static boolean isolateInitialized;
public static boolean isIsolateInitialized() {
return isolateInitialized;
}
@SubstrateForeignCallTarget(stubCallingConvention = false)
private static int initializeIsolate(CEntryPointCreateIsolateParameters parameters) {
boolean firstIsolate = false;
final long initStateAddr = FIRST_ISOLATE_INIT_STATE.get().rawValue();
final Unsafe unsafe = GraalUnsafeAccess.getUnsafe();
int state = unsafe.getInt(initStateAddr);
if (state != FirstIsolateInitStates.SUCCESSFUL) {
firstIsolate = unsafe.compareAndSwapInt(null, initStateAddr, FirstIsolateInitStates.UNINITIALIZED, FirstIsolateInitStates.IN_PROGRESS);
if (firstIsolate) {
PlatformNativeLibrarySupport.singleton().setIsFirstIsolate();
} else {
while (state == FirstIsolateInitStates.IN_PROGRESS) {
state = unsafe.getIntVolatile(null, initStateAddr);
}
if (state == FirstIsolateInitStates.FAILED) {
return CEntryPointErrors.ISOLATE_INITIALIZATION_FAILED;
}
}
}
if (UseDedicatedVMOperationThread.getValue()) {
VMOperationControl.startVMOperationThread();
}
if (parameters.isNonNull() && parameters.version() >= 3 && parameters.getArgv().isNonNull()) {
String[] args = SubstrateUtil.getArgs(parameters.getArgc(), parameters.getArgv());
args = RuntimeOptionParser.parseAndConsumeAllOptions(args);
if (ImageSingletons.contains(JavaMainSupport.class)) {
ImageSingletons.lookup(JavaMainSupport.class).mainArgs = args;
}
}
boolean success = PlatformNativeLibrarySupport.singleton().initializeBuiltinLibraries();
if (firstIsolate) {
state = success ? FirstIsolateInitStates.SUCCESSFUL : FirstIsolateInitStates.FAILED;
unsafe.putIntVolatile(null, initStateAddr, state);
}
if (!success) {
return CEntryPointErrors.ISOLATE_INITIALIZATION_FAILED;
}
assert !isolateInitialized;
isolateInitialized = true;
RuntimeSupport.executeInitializationHooks();
return CEntryPointErrors.NO_ERROR;
}
@Snippet
public static int attachThreadSnippet(Isolate isolate, boolean ensureJavaThread, @ConstantParameter int vmThreadSize) {
if (MultiThreaded.getValue()) {
writeCurrentVMThread(WordFactory.nullPointer());
}
int error = runtimeCall(ATTACH_THREAD, isolate, vmThreadSize);
if (error != CEntryPointErrors.NO_ERROR) {
return error;
}
if (MultiThreaded.getValue()) {
Safepoint.transitionNativeToJava();
}
if (ensureJavaThread) {
runtimeCallEnsureJavaThread(ENSURE_JAVA_THREAD);
}
return CEntryPointErrors.NO_ERROR;
}
@Uninterruptible(reason = "Thread state not yet set up.")
@SubstrateForeignCallTarget(stubCallingConvention = false)
private static int attachThread(Isolate isolate, int vmThreadSize) {
int sanityError = Isolates.checkSanity(isolate);
if (sanityError != CEntryPointErrors.NO_ERROR) {
return sanityError;
}
if (SpawnIsolates.getValue()) {
setHeapBase(Isolates.getHeapBase(isolate));
}
if (MultiThreaded.getValue()) {
if (!VMThreads.isInitialized()) {
return CEntryPointErrors.UNINITIALIZED_ISOLATE;
}
IsolateThread thread = VMThreads.singleton().findIsolateThreadForCurrentOSThread(false);
if (thread.isNull()) {
thread = VMThreads.singleton().allocateIsolateThread(vmThreadSize);
if (thread.isNull()) {
return CEntryPointErrors.THREADING_INITIALIZATION_FAILED;
}
StackOverflowCheck.singleton().initialize(thread);
writeCurrentVMThread(thread);
int error = VMThreads.singleton().attachThread(thread);
if (error != CEntryPointErrors.NO_ERROR) {
VMThreads.singleton().freeIsolateThread(thread);
return error;
}
VMThreads.IsolateTL.set(thread, isolate);
} else {
writeCurrentVMThread(thread);
}
} else {
StackOverflowCheck.singleton().initialize(WordFactory.nullPointer());
}
return CEntryPointErrors.NO_ERROR;
}
@NodeIntrinsic(value = ForeignCallNode.class)
public static native void runtimeCallEnsureJavaThread(@ConstantNodeParameter ForeignCallDescriptor descriptor);
@SubstrateForeignCallTarget(stubCallingConvention = false)
private static void ensureJavaThread() {
JavaThreads.ensureJavaThread();
}
@Snippet
public static int detachThreadSnippet() {
int result = CEntryPointErrors.NO_ERROR;
if (MultiThreaded.getValue()) {
IsolateThread thread = CurrentIsolate.getCurrentThread();
result = runtimeCall(DETACH_THREAD_MT, thread);
}
return result;
}
@SubstrateForeignCallTarget(stubCallingConvention = false)
@Uninterruptible(reason = "Thread state going away.")
@RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Must not (thread-local) allocate while detaching a thread.")
private static int detachThreadMT(IsolateThread currentThread) {
try {
VMThreads.singleton().detachThread(currentThread);
} catch (Throwable t) {
return CEntryPointErrors.UNCAUGHT_EXCEPTION;
}
return CEntryPointErrors.NO_ERROR;
}
@Snippet
public static int tearDownIsolateSnippet() {
return runtimeCallTearDownIsolate(TEAR_DOWN_ISOLATE);
}
@SubstrateForeignCallTarget(stubCallingConvention = false)
private static int tearDownIsolate() {
try {
RuntimeSupport.executeTearDownHooks();
if (!JavaThreads.singleton().tearDown()) {
return CEntryPointErrors.UNSPECIFIED;
}
VMThreads.singleton().tearDown();
return Isolates.tearDownCurrent();
} catch (Throwable t) {
logException(t);
return CEntryPointErrors.UNCAUGHT_EXCEPTION;
}
}
@Snippet
public static int enterIsolateSnippet(Isolate isolate, boolean inCrashHandler) {
int result;
if (MultiThreaded.getValue()) {
writeCurrentVMThread(WordFactory.nullPointer());
result = runtimeCall(ENTER_ISOLATE_MT, isolate, inCrashHandler);
if (result == CEntryPointErrors.NO_ERROR) {
if (!inCrashHandler || VMThreads.StatusSupport.isStatusNativeOrSafepoint()) {
Safepoint.transitionNativeToJava();
}
}
} else {
result = Isolates.checkSanity(isolate);
if (result == CEntryPointErrors.NO_ERROR && SpawnIsolates.getValue()) {
setHeapBase(Isolates.getHeapBase(isolate));
}
}
return result;
}
@Uninterruptible(reason = "Thread state not set up yet")
@SubstrateForeignCallTarget(stubCallingConvention = false)
private static int enterIsolateMT(Isolate isolate, boolean inCrashHandler) {
int sanityError = Isolates.checkSanity(isolate);
if (sanityError != CEntryPointErrors.NO_ERROR) {
return sanityError;
}
if (SpawnIsolates.getValue()) {
setHeapBase(Isolates.getHeapBase(isolate));
}
if (!VMThreads.isInitialized()) {
return CEntryPointErrors.UNINITIALIZED_ISOLATE;
}
IsolateThread thread = VMThreads.singleton().findIsolateThreadForCurrentOSThread(inCrashHandler);
if (thread.isNull()) {
return CEntryPointErrors.UNATTACHED_THREAD;
}
writeCurrentVMThread(thread);
return CEntryPointErrors.NO_ERROR;
}
@Snippet
public static int enterSnippet(IsolateThread thread) {
Isolate isolate;
if (MultiThreaded.getValue()) {
if (thread.isNull()) {
return CEntryPointErrors.NULL_ARGUMENT;
}
writeCurrentVMThread(thread);
isolate = VMThreads.IsolateTL.get(thread);
} else {
if (SpawnIsolates.getValue()) {
if (thread.isNull()) {
return CEntryPointErrors.NULL_ARGUMENT;
}
} else if (!thread.equal(CEntryPointSetup.SINGLE_THREAD_SENTINEL)) {
return CEntryPointErrors.UNATTACHED_THREAD;
}
isolate = (Isolate) ((Word) thread).subtract(CEntryPointSetup.SINGLE_ISOLATE_TO_SINGLE_THREAD_ADDEND);
}
if (SpawnIsolates.getValue()) {
setHeapBase(Isolates.getHeapBase(isolate));
}
if (MultiThreaded.getValue()) {
if (runtimeAssertionsEnabled()) {
runtimeCall(VERIFY_ISOLATE_THREAD, thread);
}
Safepoint.transitionNativeToJava();
}
return CEntryPointErrors.NO_ERROR;
}
@Fold
static boolean runtimeAssertionsEnabled() {
return RuntimeAssertionsSupport.singleton().desiredAssertionStatus(CEntryPointSnippets.class);
}
@Uninterruptible(reason = "Thread state not set up yet")
@SubstrateForeignCallTarget(stubCallingConvention = false)
private static int verifyIsolateThread(IsolateThread thread) {
VMError.guarantee(CurrentIsolate.getCurrentThread() == thread, "Threads must match for the call below");
if (!VMThreads.singleton().verifyIsCurrentThread(thread) || !VMThreads.singleton().verifyThreadIsAttached(thread)) {
throw VMError.shouldNotReachHere("A call from native code to Java code provided the wrong JNI environment or the wrong IsolateThread. " +
"The JNI environment / IsolateThread is a thread-local data structure and must not be shared between threads.");
}
return CEntryPointErrors.NO_ERROR;
}
@Snippet
public static int reportExceptionSnippet(Throwable exception) {
return runtimeCall(REPORT_EXCEPTION, exception);
}
@Uninterruptible(reason = "Avoid StackOverflowError and safepoints until they are disabled permanently", calleeMustBe = false)
@SubstrateForeignCallTarget(stubCallingConvention = false)
private static int reportException(Throwable exception) {
VMThreads.StatusSupport.setStatusIgnoreSafepoints();
StackOverflowCheck.singleton().disableStackOverflowChecksForFatalError();
logException(exception);
ImageSingletons.lookup(LogHandler.class).fatalError();
return CEntryPointErrors.UNSPECIFIED;
}
private static void logException(Throwable exception) {
try {
Log.log().exception(exception);
} catch (Throwable ex) {
}
}
@Snippet
public static int returnFromJavaToCSnippet() {
if (MultiThreaded.getValue()) {
VMThreads.StatusSupport.setStatusNative();
}
return CEntryPointErrors.NO_ERROR;
}
@Snippet
public static boolean isAttachedSnippet(Isolate isolate) {
return Isolates.checkSanity(isolate) == CEntryPointErrors.NO_ERROR &&
(!MultiThreaded.getValue() || runtimeCallIsAttached(IS_ATTACHED_MT, isolate));
}
@Uninterruptible(reason = "Thread state not yet set up.")
@SubstrateForeignCallTarget(stubCallingConvention = false)
private static boolean isAttachedMT(Isolate isolate) {
if (SpawnIsolates.getValue()) {
setHeapBase(Isolates.getHeapBase(isolate));
}
return VMThreads.isInitialized() && VMThreads.singleton().findIsolateThreadForCurrentOSThread(false).isNonNull();
}
@Snippet
public static void failFatallySnippet(int code, CCharPointer message) {
runtimeCallFailFatally(FAIL_FATALLY, code, message);
}
@Uninterruptible(reason = "Unknown thread state.")
@SubstrateForeignCallTarget(stubCallingConvention = false)
private static void failFatally(int code, CCharPointer message) {
VMThreads.singleton().failFatally(code, message);
}
public static void registerForeignCalls(Providers providers, SubstrateForeignCallsProvider foreignCalls) {
foreignCalls.register(providers, FOREIGN_CALLS);
}
@SuppressWarnings("unused")
public static void registerLowerings(OptionValues options, Iterable<DebugHandlersFactory> factories, Providers providers, SnippetReflectionProvider snippetReflection, int vmThreadSize,
Map<Class<? extends Node>, NodeLoweringProvider<?>> lowerings) {
new CEntryPointSnippets(options, factories, providers, snippetReflection, vmThreadSize, lowerings);
}
private CEntryPointSnippets(OptionValues options, Iterable<DebugHandlersFactory> factories, Providers providers, SnippetReflectionProvider snippetReflection, int vmThreadSize,
Map<Class<? extends Node>, NodeLoweringProvider<?>> lowerings) {
super(options, factories, providers, snippetReflection);
lowerings.put(CEntryPointEnterNode.class, new EnterLowering(vmThreadSize));
lowerings.put(CEntryPointLeaveNode.class, new LeaveLowering());
lowerings.put(CEntryPointUtilityNode.class, new UtilityLowering());
}
protected class EnterLowering implements NodeLoweringProvider<CEntryPointEnterNode> {
private final SnippetInfo createIsolate = snippet(CEntryPointSnippets.class, "createIsolateSnippet");
private final SnippetInfo attachThread = snippet(CEntryPointSnippets.class, "attachThreadSnippet");
private final SnippetInfo enter = snippet(CEntryPointSnippets.class, "enterSnippet");
private final SnippetInfo enterThreadFromTL = snippet(CEntryPointSnippets.class, "enterIsolateSnippet");
private final int vmThreadSize;
EnterLowering(int vmThreadSize) {
this.vmThreadSize = vmThreadSize;
}
@Override
public void lower(CEntryPointEnterNode node, LoweringTool tool) {
if (tool.getLoweringStage() != LoweringTool.StandardLoweringStage.LOW_TIER) {
return;
}
Arguments args;
switch (node.getEnterAction()) {
case CreateIsolate:
args = new Arguments(createIsolate, node.graph().getGuardsStage(), tool.getLoweringStage());
args.add("parameters", node.getParameter());
args.addConst("vmThreadSize", vmThreadSize);
break;
case AttachThread:
args = new Arguments(attachThread, node.graph().getGuardsStage(), tool.getLoweringStage());
args.add("isolate", node.getParameter());
args.add("ensureJavaThread", node.getEnsureJavaThread());
args.addConst("vmThreadSize", vmThreadSize);
break;
case EnterIsolate:
args = new Arguments(enterThreadFromTL, node.graph().getGuardsStage(), tool.getLoweringStage());
args.add("isolate", node.getParameter());
args.add("inCrashHandler", node.isCrashHandler());
break;
case Enter:
args = new Arguments(enter, node.graph().getGuardsStage(), tool.getLoweringStage());
assert node.getParameter() != null;
args.add("thread", node.getParameter());
break;
default:
throw shouldNotReachHere();
}
SnippetTemplate template = template(node, args);
template.setMayRemoveLocation(true);
template.instantiate(providers.getMetaAccess(), node, SnippetTemplate.DEFAULT_REPLACER, args);
}
}
protected class LeaveLowering implements NodeLoweringProvider<CEntryPointLeaveNode> {
private final SnippetInfo returnFromJavaToC = snippet(CEntryPointSnippets.class, "returnFromJavaToCSnippet");
private final SnippetInfo detachThread = snippet(CEntryPointSnippets.class, "detachThreadSnippet");
private final SnippetInfo reportException = snippet(CEntryPointSnippets.class, "reportExceptionSnippet");
private final SnippetInfo tearDownIsolate = snippet(CEntryPointSnippets.class, "tearDownIsolateSnippet");
@Override
public void lower(CEntryPointLeaveNode node, LoweringTool tool) {
if (tool.getLoweringStage() != LoweringTool.StandardLoweringStage.LOW_TIER) {
return;
}
Arguments args;
switch (node.getLeaveAction()) {
case Leave:
args = new Arguments(returnFromJavaToC, node.graph().getGuardsStage(), tool.getLoweringStage());
break;
case DetachThread:
args = new Arguments(detachThread, node.graph().getGuardsStage(), tool.getLoweringStage());
break;
case TearDownIsolate:
args = new Arguments(tearDownIsolate, node.graph().getGuardsStage(), tool.getLoweringStage());
break;
case ExceptionAbort:
args = new Arguments(reportException, node.graph().getGuardsStage(), tool.getLoweringStage());
args.add("exception", node.getException());
break;
default:
throw shouldNotReachHere();
}
template(node, args).instantiate(providers.getMetaAccess(), node, SnippetTemplate.DEFAULT_REPLACER, args);
}
}
protected class UtilityLowering implements NodeLoweringProvider<CEntryPointUtilityNode> {
private final SnippetInfo isAttached = snippet(CEntryPointSnippets.class, "isAttachedSnippet");
private final SnippetInfo failFatally = snippet(CEntryPointSnippets.class, "failFatallySnippet");
@Override
public void lower(CEntryPointUtilityNode node, LoweringTool tool) {
if (tool.getLoweringStage() != LoweringTool.StandardLoweringStage.LOW_TIER) {
return;
}
Arguments args;
switch (node.getUtilityAction()) {
case IsAttached:
args = new Arguments(isAttached, node.graph().getGuardsStage(), tool.getLoweringStage());
args.add("isolate", node.getParameter0());
break;
case FailFatally:
args = new Arguments(failFatally, node.graph().getGuardsStage(), tool.getLoweringStage());
args.add("code", node.getParameter0());
args.add("message", node.getParameter1());
break;
default:
throw shouldNotReachHere();
}
template(node, args).instantiate(providers.getMetaAccess(), node, SnippetTemplate.DEFAULT_REPLACER, args);
}
}
}