#include "jit/Jit.h"
#include "jit/BaselineJIT.h"
#include "jit/Ion.h"
#include "jit/JitCommon.h"
#include "jit/JitRealm.h"
#include "vm/Interpreter.h"
#include "vm/Stack-inl.h"
using namespace js;
using namespace js::jit;
static EnterJitStatus JS_HAZ_JSNATIVE_CALLER EnterJit(JSContext* cx,
RunState& state,
uint8_t* code) {
MOZ_ASSERT(state.script()->hasBaselineScript());
MOZ_ASSERT(code);
MOZ_ASSERT(IsBaselineEnabled(cx));
if (!CheckRecursionLimit(cx)) {
return EnterJitStatus::Error;
}
#ifdef DEBUG
mozilla::Maybe<JS::AutoAssertNoGC> nogc;
nogc.emplace(cx);
#endif
JSScript* script = state.script();
size_t numActualArgs;
bool constructing;
size_t maxArgc;
Value* maxArgv;
JSObject* envChain;
CalleeToken calleeToken;
if (state.isInvoke()) {
const CallArgs& args = state.asInvoke()->args();
numActualArgs = args.length();
if (TooManyActualArguments(numActualArgs)) {
if (numActualArgs > BASELINE_MAX_ARGS_LENGTH) {
return EnterJitStatus::NotEntered;
}
code = script->baselineScript()->method()->raw();
}
constructing = state.asInvoke()->constructing();
maxArgc = args.length() + 1;
maxArgv = args.array() - 1; envChain = nullptr;
calleeToken = CalleeToToken(&args.callee().as<JSFunction>(), constructing);
unsigned numFormals = script->functionNonDelazifying()->nargs();
if (numFormals > numActualArgs) {
code = cx->runtime()->jitRuntime()->getArgumentsRectifier().value;
}
} else {
numActualArgs = 0;
constructing = false;
if (script->isDirectEvalInFunction()) {
if (state.asExecute()->newTarget().isNull()) {
ScriptFrameIter iter(cx);
state.asExecute()->setNewTarget(iter.newTarget());
}
maxArgc = 1;
maxArgv = state.asExecute()->addressOfNewTarget();
} else {
maxArgc = 0;
maxArgv = nullptr;
}
envChain = state.asExecute()->environmentChain();
calleeToken = CalleeToToken(state.script());
}
MOZ_ASSERT_IF(constructing, maxArgv[0].isObject() ||
maxArgv[0].isMagic(JS_UNINITIALIZED_LEXICAL));
RootedValue result(cx, Int32Value(numActualArgs));
{
AssertRealmUnchanged aru(cx);
ActivationEntryMonitor entryMonitor(cx, calleeToken);
JitActivation activation(cx);
EnterJitCode enter = cx->runtime()->jitRuntime()->enterJit();
#ifdef DEBUG
nogc.reset();
#endif
CALL_GENERATED_CODE(enter, code, maxArgc, maxArgv, nullptr,
calleeToken, envChain, 0,
result.address());
}
MOZ_ASSERT(!cx->hasIonReturnOverride());
cx->freeOsrTempData();
if (result.isMagic()) {
MOZ_ASSERT(result.isMagic(JS_ION_ERROR));
return EnterJitStatus::Error;
}
if (constructing && result.isPrimitive()) {
MOZ_ASSERT(maxArgv[0].isObject());
result = maxArgv[0];
}
state.setReturnValue(result);
return EnterJitStatus::Ok;
}
EnterJitStatus js::jit::MaybeEnterJit(JSContext* cx, RunState& state) {
JSScript* script = state.script();
uint8_t* code = script->jitCodeRaw();
do {
if (script->hasBaselineScript()) {
break;
}
if (jit::IsIonEnabled(cx)) {
jit::MethodStatus status = jit::CanEnterIon(cx, state);
if (status == jit::Method_Error) {
return EnterJitStatus::Error;
}
if (status == jit::Method_Compiled) {
code = script->jitCodeRaw();
break;
}
}
if (jit::IsBaselineEnabled(cx)) {
jit::MethodStatus status = jit::CanEnterBaselineMethod(cx, state);
if (status == jit::Method_Error) {
return EnterJitStatus::Error;
}
if (status == jit::Method_Compiled) {
code = script->jitCodeRaw();
break;
}
}
return EnterJitStatus::NotEntered;
} while (false);
return EnterJit(cx, state, code);
}