package com.oracle.svm.graal.hotspot.libgraal;
import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.runtime;
import static sun.misc.Unsafe.ARRAY_BYTE_BASE_OFFSET;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.util.Arrays;
import java.util.Map;
import org.graalvm.collections.EconomicMap;
import org.graalvm.compiler.debug.GlobalMetrics;
import org.graalvm.compiler.hotspot.CompilationContext;
import org.graalvm.compiler.hotspot.CompilationTask;
import org.graalvm.compiler.hotspot.HotSpotGraalCompiler;
import org.graalvm.compiler.hotspot.HotSpotGraalRuntime;
import org.graalvm.compiler.hotspot.HotSpotGraalServices;
import org.graalvm.compiler.options.OptionDescriptors;
import org.graalvm.compiler.options.OptionKey;
import org.graalvm.compiler.options.OptionValues;
import org.graalvm.compiler.options.OptionsParser;
import org.graalvm.compiler.serviceprovider.GraalUnsafeAccess;
import org.graalvm.compiler.serviceprovider.IsolateUtil;
import org.graalvm.libgraal.LibGraal;
import org.graalvm.libgraal.LibGraalScope;
import org.graalvm.nativeimage.Isolate;
import org.graalvm.nativeimage.IsolateThread;
import org.graalvm.nativeimage.ObjectHandles;
import org.graalvm.nativeimage.c.function.CEntryPoint;
import org.graalvm.nativeimage.c.function.CEntryPoint.Builtin;
import org.graalvm.nativeimage.c.function.CEntryPoint.IsolateContext;
import org.graalvm.util.OptionsEncoder;
import org.graalvm.word.Pointer;
import org.graalvm.word.PointerBase;
import org.graalvm.word.WordFactory;
import com.oracle.svm.core.c.CGlobalData;
import com.oracle.svm.core.c.CGlobalDataFactory;
import com.oracle.svm.core.c.function.CEntryPointOptions;
import jdk.vm.ci.code.InstalledCode;
import jdk.vm.ci.hotspot.HotSpotCompilationRequest;
import jdk.vm.ci.hotspot.HotSpotInstalledCode;
import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime;
import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod;
import jdk.vm.ci.runtime.JVMCICompiler;
import sun.misc.Unsafe;
public final class LibGraalEntryPoints {
private static final Unsafe UNSAFE = GraalUnsafeAccess.getUnsafe();
static final CGlobalData<Pointer> LOG_FILE_BARRIER = CGlobalDataFactory.createWord((Pointer) WordFactory.zero());
static final CGlobalData<Pointer> MANAGEMENT_BARRIER = CGlobalDataFactory.createWord((Pointer) WordFactory.zero());
@CEntryPoint(builtin = Builtin.GET_CURRENT_THREAD, name = "Java_org_graalvm_libgraal_LibGraalScope_getIsolateThreadIn")
private static native IsolateThread getIsolateThreadIn(PointerBase env, PointerBase hsClazz, @IsolateContext Isolate isolate);
@CEntryPoint(name = "Java_org_graalvm_libgraal_LibGraalScope_attachThreadTo", builtin = CEntryPoint.Builtin.ATTACH_THREAD)
static native long attachThreadTo(PointerBase env, PointerBase hsClazz, @CEntryPoint.IsolateContext long isolate);
@CEntryPoint(name = "Java_org_graalvm_libgraal_LibGraalScope_detachThreadFrom", builtin = CEntryPoint.Builtin.DETACH_THREAD)
static native void detachThreadFrom(PointerBase env, PointerBase hsClazz, @CEntryPoint.IsolateThreadContext long isolateThread);
static class CachedOptions {
final OptionValues options;
final long hash;
CachedOptions(OptionValues options, long hash) {
this.options = options;
this.hash = hash;
}
}
private static final ThreadLocal<CachedOptions> cachedOptions = new ThreadLocal<>();
public static boolean hasLibGraalIsolatePeer() {
return hasLibGraalIsolatePeer;
}
private static boolean hasLibGraalIsolatePeer;
private static OptionValues decodeOptions(long address, int size, int hash) {
CachedOptions options = cachedOptions.get();
if (options == null || options.hash != hash) {
byte[] buffer = new byte[size];
UNSAFE.copyMemory(null, address, buffer, Unsafe.ARRAY_BYTE_BASE_OFFSET, size);
int actualHash = Arrays.hashCode(buffer);
if (actualHash != hash) {
throw new IllegalArgumentException(actualHash + " != " + hash);
}
Map<String, Object> srcMap = OptionsEncoder.decode(buffer);
final EconomicMap<OptionKey<?>, Object> dstMap = OptionValues.newOptionMap();
final Iterable<OptionDescriptors> loader = OptionsParser.getOptionsLoader();
for (Map.Entry<String, Object> e : srcMap.entrySet()) {
final String optionName = e.getKey();
final Object optionValue = e.getValue();
OptionsParser.parseOption(optionName, optionValue, dstMap, loader);
}
options = new CachedOptions(new OptionValues(dstMap), hash);
cachedOptions.set(options);
}
return options.options;
}
@SuppressWarnings({"unused"})
@CEntryPoint(name = "Java_org_graalvm_libgraal_LibGraalObject_releaseHandle")
public static boolean releaseHandle(PointerBase jniEnv,
PointerBase jclass,
@CEntryPoint.IsolateThreadContext long isolateThreadId,
long handle) {
try {
ObjectHandles.getGlobal().destroy(WordFactory.pointer(handle));
return true;
} catch (Throwable t) {
return false;
}
}
@SuppressWarnings({"unused"})
@CEntryPoint(name = "Java_org_graalvm_libgraal_LibGraalScope_getIsolateId")
public static long getIsolateId(PointerBase jniEnv,
PointerBase jclass,
@CEntryPoint.IsolateThreadContext long isolateThreadId) {
try {
hasLibGraalIsolatePeer = true;
return IsolateUtil.getIsolateID();
} catch (Throwable t) {
return 0L;
}
}
@SuppressWarnings({"unused", "try"})
@CEntryPoint(name = "Java_org_graalvm_compiler_hotspot_test_CompileTheWorld_compileMethodInLibgraal")
@CEntryPointOptions(include = LibGraalFeature.IsEnabled.class)
private static long compileMethod(PointerBase jniEnv,
PointerBase jclass,
@CEntryPoint.IsolateThreadContext long isolateThread,
long methodHandle,
boolean useProfilingInfo,
boolean installAsDefault,
boolean printMetrics,
long optionsAddress,
int optionsSize,
int optionsHash,
long stackTraceAddress,
int stackTraceCapacity) {
try {
HotSpotJVMCIRuntime runtime = runtime();
HotSpotResolvedJavaMethod method = LibGraal.unhand(HotSpotResolvedJavaMethod.class, methodHandle);
int entryBCI = JVMCICompiler.INVOCATION_ENTRY_BCI;
HotSpotCompilationRequest request = new HotSpotCompilationRequest(method, entryBCI, 0L);
HotSpotGraalCompiler compiler = (HotSpotGraalCompiler) runtime.getCompiler();
try (CompilationContext scope = HotSpotGraalServices.openLocalCompilationContext(request)) {
OptionValues options = decodeOptions(optionsAddress, optionsSize, optionsHash);
CompilationTask task = new CompilationTask(runtime, compiler, request, useProfilingInfo, installAsDefault);
task.runCompilation(options);
HotSpotInstalledCode installedCode = task.getInstalledCode();
if (printMetrics) {
GlobalMetrics metricValues = ((HotSpotGraalRuntime) compiler.getGraalRuntime()).getMetricValues();
metricValues.print(options);
metricValues.clear();
}
return LibGraal.translate(installedCode);
}
} catch (Throwable t) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
t.printStackTrace(new PrintStream(baos));
byte[] stackTrace = baos.toByteArray();
int length = Math.min(stackTraceCapacity - Integer.BYTES, stackTrace.length);
UNSAFE.putInt(stackTraceAddress, length);
UNSAFE.copyMemory(stackTrace, ARRAY_BYTE_BASE_OFFSET, null, stackTraceAddress + Integer.BYTES, length);
return 0L;
}
}
}