Bug 1639153 - Part 6.2: Establish dependency from tls for x86 callWithABI div/mod...
[gecko.git] / js / src / jit / Jit.cpp
blobd06a637360d6972174fc04cd11f5e0e11e79d6a9
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/. */
7 #include "jit/Jit.h"
9 #include "jit/BaselineJIT.h"
10 #include "jit/Ion.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"
18 using namespace js;
19 using namespace js::jit;
21 static EnterJitStatus JS_HAZ_JSNATIVE_CALLER EnterJit(JSContext* cx,
22 RunState& state,
23 uint8_t* code) {
24 // We don't want to call the interpreter stub here (because
25 // C++ -> interpreterStub -> C++ is slower than staying in C++).
26 MOZ_ASSERT(code);
27 MOZ_ASSERT(code != cx->runtime()->jitRuntime()->interpreterStub().value);
28 MOZ_ASSERT(IsBaselineInterpreterEnabled());
30 if (!CheckRecursionLimit(cx)) {
31 return EnterJitStatus::Error;
34 #ifdef DEBUG
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;
40 nogc.emplace(cx);
41 #endif
43 JSScript* script = state.script();
44 size_t numActualArgs;
45 bool constructing;
46 size_t maxArgc;
47 Value* maxArgv;
48 JSObject* envChain;
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();
63 } else {
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|
71 envChain = nullptr;
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;
78 } else {
79 numActualArgs = 0;
80 constructing = false;
81 if (script->isDirectEvalInFunction()) {
82 maxArgc = 1;
83 maxArgv = state.asExecute()->addressOfNewTarget();
84 } else {
85 maxArgc = 0;
86 maxArgv = nullptr;
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();
103 #ifdef DEBUG
104 nogc.reset();
105 #endif
106 CALL_GENERATED_CODE(enter, code, maxArgc, maxArgv, /* osrFrame = */ nullptr,
107 calleeToken, envChain, /* osrNumStackValues = */ 0,
108 result.address());
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());
125 result = maxArgv[0];
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();
147 do {
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()) {
151 break;
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();
164 break;
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();
177 break;
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();
190 break;
194 return EnterJitStatus::NotEntered;
195 } while (false);
197 return EnterJit(cx, state, code);