package com.oracle.svm.core.deopt;
import java.util.Objects;
import org.graalvm.compiler.graph.NodeSourcePosition;
import org.graalvm.nativeimage.c.function.CodePointer;
import org.graalvm.word.LocationIdentity;
import org.graalvm.word.Pointer;
import com.oracle.svm.core.annotate.NeverInline;
import com.oracle.svm.core.code.CodeInfoTable;
import com.oracle.svm.core.code.DeoptimizationSourcePositionDecoder;
import com.oracle.svm.core.log.Log;
import com.oracle.svm.core.snippets.KnownIntrinsics;
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 jdk.vm.ci.meta.DeoptimizationAction;
import jdk.vm.ci.meta.DeoptimizationReason;
import jdk.vm.ci.meta.SpeculationLog.SpeculationReason;
public class DeoptimizationRuntime {
public static final SubstrateForeignCallDescriptor DEOPTIMIZE = SnippetRuntime.findForeignCall(DeoptimizationRuntime.class, "deoptimize", true, LocationIdentity.any());
@SubstrateForeignCallTarget(stubCallingConvention = true)
@NeverInline("Access of caller frame")
private static void deoptimize(long actionAndReason, SpeculationReason speculation) {
StackOverflowCheck.singleton().makeYellowZoneAvailable();
try {
Pointer sp = KnownIntrinsics.readCallerStackPointer();
DeoptimizationAction action = Deoptimizer.decodeDeoptAction(actionAndReason);
if (Deoptimizer.Options.TraceDeoptimization.getValue()) {
CodePointer ip = KnownIntrinsics.readReturnAddress();
traceDeoptimization(actionAndReason, speculation, action, sp, ip);
}
if (action.doesInvalidateCompilation()) {
Deoptimizer.invalidateMethodOfFrame(sp, speculation);
} else {
Deoptimizer.deoptimizeFrame(sp, false, speculation);
}
if (Deoptimizer.Options.TraceDeoptimization.getValue()) {
Log.log().string("]").newline();
}
} finally {
StackOverflowCheck.singleton().protectYellowZone();
}
}
private static void traceDeoptimization(long actionAndReason, SpeculationReason speculation, DeoptimizationAction action, Pointer sp, CodePointer ip) {
Log log = Log.log().string("[Deoptimization initiated").newline();
SubstrateInstalledCode installedCode = CodeInfoTable.lookupInstalledCode(ip);
if (installedCode != null) {
log.string(" name: ").string(installedCode.getName()).newline();
}
log.string(" sp: ").hex(sp).string(" ip: ").hex(ip).newline();
DeoptimizationReason reason = Deoptimizer.decodeDeoptReason(actionAndReason);
log.string(" reason: ").string(reason.toString()).string(" action: ").string(action.toString()).newline();
int debugId = Deoptimizer.decodeDebugId(actionAndReason);
log.string(" debugId: ").signed(debugId).string(" speculation: ").string(Objects.toString(speculation)).newline();
NodeSourcePosition sourcePosition = DeoptimizationSourcePositionDecoder.decode(debugId, ip);
if (sourcePosition != null) {
log.string(" stack trace that triggered deoptimization:").newline();
NodeSourcePosition cur = sourcePosition;
while (cur != null) {
log.string(" at ");
if (cur.getMethod() != null) {
StackTraceElement element = cur.getMethod().asStackTraceElement(cur.getBCI());
if (element.getFileName() != null && element.getLineNumber() >= 0) {
log.string(element.toString());
} else {
log.string(cur.getMethod().format("%H.%n(%p)")).string(" bci ").signed(cur.getBCI());
}
} else {
log.string("[unknown method]");
}
log.newline();
cur = cur.getCaller();
}
}
}
}