1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: set ts=8 sts=2 et sw=2 tw=80:
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
9 #include "jit/BaselineJIT.h"
11 #include "jit/JitCommon.h"
12 #include "jit/JitRealm.h"
13 #include "js/friend/StackLimits.h" // js::CheckRecursionLimit
14 #include "vm/Interpreter.h"
16 #include "vm/Stack-inl.h"
19 using namespace js::jit
;
21 static EnterJitStatus JS_HAZ_JSNATIVE_CALLER
EnterJit(JSContext
* cx
,
24 // We don't want to call the interpreter stub here (because
25 // C++ -> interpreterStub -> C++ is slower than staying in C++).
27 MOZ_ASSERT(code
!= cx
->runtime()->jitRuntime()->interpreterStub().value
);
28 MOZ_ASSERT(IsBaselineInterpreterEnabled());
30 if (!CheckRecursionLimit(cx
)) {
31 return EnterJitStatus::Error
;
35 // Assert we don't GC before entering JIT code. A GC could discard JIT code
36 // or move the function stored in the CalleeToken (it won't be traced at
37 // this point). We use Maybe<> here so we can call reset() to call the
38 // AutoAssertNoGC destructor before we enter JIT code.
39 mozilla::Maybe
<JS::AutoAssertNoGC
> nogc
;
43 JSScript
* script
= state
.script();
49 CalleeToken calleeToken
;
51 if (state
.isInvoke()) {
52 const CallArgs
& args
= state
.asInvoke()->args();
53 numActualArgs
= args
.length();
55 if (TooManyActualArguments(numActualArgs
)) {
56 // Too many arguments for Ion. Baseline supports more actual
57 // arguments, so in that case force Baseline code.
58 if (numActualArgs
> BASELINE_MAX_ARGS_LENGTH
) {
59 return EnterJitStatus::NotEntered
;
61 if (script
->hasBaselineScript()) {
62 code
= script
->baselineScript()->method()->raw();
64 code
= cx
->runtime()->jitRuntime()->baselineInterpreter().codeRaw();
68 constructing
= state
.asInvoke()->constructing();
69 maxArgc
= args
.length() + 1;
70 maxArgv
= args
.array() - 1; // -1 to include |this|
72 calleeToken
= CalleeToToken(&args
.callee().as
<JSFunction
>(), constructing
);
74 unsigned numFormals
= script
->function()->nargs();
75 if (numFormals
> numActualArgs
) {
76 code
= cx
->runtime()->jitRuntime()->getArgumentsRectifier().value
;
81 if (script
->isDirectEvalInFunction()) {
83 maxArgv
= state
.asExecute()->addressOfNewTarget();
88 envChain
= state
.asExecute()->environmentChain();
89 calleeToken
= CalleeToToken(state
.script());
92 // Caller must construct |this| before invoking the function.
93 MOZ_ASSERT_IF(constructing
, maxArgv
[0].isObject() ||
94 maxArgv
[0].isMagic(JS_UNINITIALIZED_LEXICAL
));
96 RootedValue
result(cx
, Int32Value(numActualArgs
));
98 AssertRealmUnchanged
aru(cx
);
99 ActivationEntryMonitor
entryMonitor(cx
, calleeToken
);
100 JitActivation
activation(cx
);
101 EnterJitCode enter
= cx
->runtime()->jitRuntime()->enterJit();
106 CALL_GENERATED_CODE(enter
, code
, maxArgc
, maxArgv
, /* osrFrame = */ nullptr,
107 calleeToken
, envChain
, /* osrNumStackValues = */ 0,
111 MOZ_ASSERT(!cx
->hasIonReturnOverride());
113 // Release temporary buffer used for OSR into Ion.
114 cx
->runtime()->jitRuntime()->freeIonOsrTempData();
116 if (result
.isMagic()) {
117 MOZ_ASSERT(result
.isMagic(JS_ION_ERROR
));
118 return EnterJitStatus::Error
;
121 // Jit callers wrap primitive constructor return, except for derived
122 // class constructors, which are forced to do it themselves.
123 if (constructing
&& result
.isPrimitive()) {
124 MOZ_ASSERT(maxArgv
[0].isObject());
128 state
.setReturnValue(result
);
129 return EnterJitStatus::Ok
;
132 EnterJitStatus
js::jit::MaybeEnterJit(JSContext
* cx
, RunState
& state
) {
133 if (!IsBaselineInterpreterEnabled()) {
134 // All JITs are disabled.
135 return EnterJitStatus::NotEntered
;
138 // JITs do not respect the debugger's OnNativeCall hook, so JIT execution is
139 // disabled if this hook might need to be called.
140 if (cx
->insideDebuggerEvaluationWithOnNativeCallHook
) {
141 return EnterJitStatus::NotEntered
;
144 JSScript
* script
= state
.script();
146 uint8_t* code
= script
->jitCodeRaw();
148 // Make sure we can enter Baseline Interpreter code. Note that the prologue
149 // has warm-up checks to tier up if needed.
150 if (script
->hasJitScript()) {
154 script
->incWarmUpCounter();
156 // Try to Ion-compile.
157 if (jit::IsIonEnabled(cx
)) {
158 jit::MethodStatus status
= jit::CanEnterIon(cx
, state
);
159 if (status
== jit::Method_Error
) {
160 return EnterJitStatus::Error
;
162 if (status
== jit::Method_Compiled
) {
163 code
= script
->jitCodeRaw();
168 // Try to Baseline-compile.
169 if (jit::IsBaselineJitEnabled(cx
)) {
170 jit::MethodStatus status
=
171 jit::CanEnterBaselineMethod
<BaselineTier::Compiler
>(cx
, state
);
172 if (status
== jit::Method_Error
) {
173 return EnterJitStatus::Error
;
175 if (status
== jit::Method_Compiled
) {
176 code
= script
->jitCodeRaw();
181 // Try to enter the Baseline Interpreter.
182 if (IsBaselineInterpreterEnabled()) {
183 jit::MethodStatus status
=
184 jit::CanEnterBaselineMethod
<BaselineTier::Interpreter
>(cx
, state
);
185 if (status
== jit::Method_Error
) {
186 return EnterJitStatus::Error
;
188 if (status
== jit::Method_Compiled
) {
189 code
= script
->jitCodeRaw();
194 return EnterJitStatus::NotEntered
;
197 return EnterJit(cx
, state
, code
);