Bug 1639153 - Part 6.2: Establish dependency from tls for x86 callWithABI div/mod...
[gecko.git] / js / src / jit / CompileInfo.h
blob6f4699b8330eee4816418cfdc9edbefa6313cb7d
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 #ifndef jit_CompileInfo_h
8 #define jit_CompileInfo_h
10 #include "mozilla/Maybe.h"
12 #include <algorithm>
14 #include "jit/JitAllocPolicy.h"
15 #include "jit/JitFrames.h"
16 #include "jit/Registers.h"
17 #include "vm/EnvironmentObject.h"
18 #include "vm/JSFunction.h"
20 namespace js {
21 namespace jit {
23 class TrackedOptimizations;
25 inline unsigned StartArgSlot(JSScript* script) {
26 // Reserved slots:
27 // Slot 0: Environment chain.
28 // Slot 1: Return value.
30 // When needed:
31 // Slot 2: Argumentsobject.
33 // Note: when updating this, please also update the assert in
34 // SnapshotWriter::startFrame
35 return 2 + (script->argumentsHasVarBinding() ? 1 : 0);
38 inline unsigned CountArgSlots(JSScript* script, JSFunction* fun) {
39 // Slot x + 0: This value.
40 // Slot x + 1: Argument 1.
41 // ...
42 // Slot x + n: Argument n.
44 // Note: when updating this, please also update the assert in
45 // SnapshotWriter::startFrame
46 return StartArgSlot(script) + (fun ? fun->nargs() + 1 : 0);
49 // The compiler at various points needs to be able to store references to the
50 // current inline path (the sequence of scripts and call-pcs that lead to the
51 // current function being inlined).
53 // To support this, the top-level IonBuilder keeps a tree that records the
54 // inlinings done during compilation.
55 class InlineScriptTree {
56 // InlineScriptTree for the caller
57 InlineScriptTree* caller_;
59 // PC in the caller corresponding to this script.
60 jsbytecode* callerPc_;
62 // Script for this entry.
63 JSScript* script_;
65 // Child entries (linked together by nextCallee pointer)
66 InlineScriptTree* children_;
67 InlineScriptTree* nextCallee_;
69 public:
70 InlineScriptTree(InlineScriptTree* caller, jsbytecode* callerPc,
71 JSScript* script)
72 : caller_(caller),
73 callerPc_(callerPc),
74 script_(script),
75 children_(nullptr),
76 nextCallee_(nullptr) {}
78 static InlineScriptTree* New(TempAllocator* allocator,
79 InlineScriptTree* caller, jsbytecode* callerPc,
80 JSScript* script);
82 InlineScriptTree* addCallee(TempAllocator* allocator, jsbytecode* callerPc,
83 JSScript* calleeScript);
84 void removeCallee(InlineScriptTree* callee);
86 InlineScriptTree* caller() const { return caller_; }
88 bool isOutermostCaller() const { return caller_ == nullptr; }
89 bool hasCaller() const { return caller_ != nullptr; }
90 InlineScriptTree* outermostCaller() {
91 if (isOutermostCaller()) {
92 return this;
94 return caller_->outermostCaller();
97 jsbytecode* callerPc() const { return callerPc_; }
99 JSScript* script() const { return script_; }
101 bool hasChildren() const { return children_ != nullptr; }
102 InlineScriptTree* firstChild() const {
103 MOZ_ASSERT(hasChildren());
104 return children_;
107 bool hasNextCallee() const { return nextCallee_ != nullptr; }
108 InlineScriptTree* nextCallee() const {
109 MOZ_ASSERT(hasNextCallee());
110 return nextCallee_;
113 unsigned depth() const {
114 if (isOutermostCaller()) {
115 return 1;
117 return 1 + caller_->depth();
121 class BytecodeSite : public TempObject {
122 // InlineScriptTree identifying innermost active function at site.
123 InlineScriptTree* tree_;
125 // Bytecode address within innermost active function.
126 jsbytecode* pc_;
128 public:
129 BytecodeSite() : tree_(nullptr), pc_(nullptr) {}
131 BytecodeSite(InlineScriptTree* tree, jsbytecode* pc) : tree_(tree), pc_(pc) {
132 MOZ_ASSERT(tree_ != nullptr);
133 MOZ_ASSERT(pc_ != nullptr);
136 InlineScriptTree* tree() const { return tree_; }
138 jsbytecode* pc() const { return pc_; }
140 JSScript* script() const { return tree_ ? tree_->script() : nullptr; }
143 enum AnalysisMode {
144 /* JavaScript execution, not analysis. */
145 Analysis_None,
148 * MIR analysis performed when invoking 'new' on a script, to determine
149 * definite properties. Used by the optimizing JIT.
151 Analysis_DefiniteProperties,
154 * MIR analysis performed when executing a script which uses its arguments,
155 * when it is not known whether a lazy arguments value can be used.
157 Analysis_ArgumentsUsage
160 // Contains information about the compilation source for IR being generated.
161 class CompileInfo {
162 public:
163 CompileInfo(CompileRuntime* runtime, JSScript* script, JSFunction* fun,
164 jsbytecode* osrPc, AnalysisMode analysisMode,
165 bool scriptNeedsArgsObj, InlineScriptTree* inlineScriptTree)
166 : script_(script),
167 fun_(fun),
168 osrPc_(osrPc),
169 analysisMode_(analysisMode),
170 scriptNeedsArgsObj_(scriptNeedsArgsObj),
171 hadOverflowBailout_(script->hadOverflowBailout()),
172 hadFrequentBailouts_(script->hadFrequentBailouts()),
173 mayReadFrameArgsDirectly_(script->mayReadFrameArgsDirectly()),
174 inlineScriptTree_(inlineScriptTree) {
175 MOZ_ASSERT_IF(osrPc, JSOp(*osrPc) == JSOp::LoopHead);
177 // The function here can flow in from anywhere so look up the canonical
178 // function to ensure that we do not try to embed a nursery pointer in
179 // jit-code. Precisely because it can flow in from anywhere, it's not
180 // guaranteed to be non-lazy. Hence, don't access its script!
181 if (fun_) {
182 fun_ = fun_->baseScript()->function();
183 MOZ_ASSERT(fun_->isTenured());
186 nimplicit_ = StartArgSlot(script) /* env chain and argument obj */
187 + (fun ? 1 : 0); /* this */
188 nargs_ = fun ? fun->nargs() : 0;
189 nlocals_ = script->nfixed();
191 // An extra slot is needed for global scopes because InitGLexical (stack
192 // depth 1) is compiled as a SetProp (stack depth 2) on the global lexical
193 // scope.
194 uint32_t extra = script->isGlobalCode() ? 1 : 0;
195 nstack_ = std::max<unsigned>(script->nslots() - script->nfixed(),
196 MinJITStackSize) +
197 extra;
198 nslots_ = nimplicit_ + nargs_ + nlocals_ + nstack_;
200 // For derived class constructors, find and cache the frame slot for
201 // the .this binding. This slot is assumed to be always
202 // observable. See isObservableFrameSlot.
203 if (script->isDerivedClassConstructor()) {
204 MOZ_ASSERT(script->functionHasThisBinding());
205 for (BindingIter bi(script); bi; bi++) {
206 if (bi.name() != runtime->names().dotThis) {
207 continue;
209 BindingLocation loc = bi.location();
210 if (loc.kind() == BindingLocation::Kind::Frame) {
211 thisSlotForDerivedClassConstructor_ =
212 mozilla::Some(localSlot(loc.slot()));
213 break;
218 // If the script uses an environment in body, the environment chain
219 // will need to be observable.
220 needsBodyEnvironmentObject_ = script->needsBodyEnvironment();
221 funNeedsSomeEnvironmentObject_ =
222 fun ? fun->needsSomeEnvironmentObject() : false;
225 explicit CompileInfo(unsigned nlocals)
226 : script_(nullptr),
227 fun_(nullptr),
228 osrPc_(nullptr),
229 analysisMode_(Analysis_None),
230 scriptNeedsArgsObj_(false),
231 hadOverflowBailout_(false),
232 hadFrequentBailouts_(false),
233 mayReadFrameArgsDirectly_(false),
234 inlineScriptTree_(nullptr),
235 needsBodyEnvironmentObject_(false),
236 funNeedsSomeEnvironmentObject_(false) {
237 nimplicit_ = 0;
238 nargs_ = 0;
239 nlocals_ = nlocals;
240 nstack_ = 1; /* For FunctionCompiler::pushPhiInput/popPhiOutput */
241 nslots_ = nlocals_ + nstack_;
244 JSScript* script() const { return script_; }
245 bool compilingWasm() const { return script() == nullptr; }
246 JSFunction* funMaybeLazy() const { return fun_; }
247 ModuleObject* module() const { return script_->module(); }
248 jsbytecode* osrPc() const { return osrPc_; }
249 InlineScriptTree* inlineScriptTree() const { return inlineScriptTree_; }
251 bool hasOsrAt(jsbytecode* pc) const {
252 MOZ_ASSERT(JSOp(*pc) == JSOp::LoopHead);
253 return pc == osrPc();
256 jsbytecode* startPC() const { return script_->code(); }
257 jsbytecode* limitPC() const { return script_->codeEnd(); }
259 const char* filename() const { return script_->filename(); }
261 unsigned lineno() const { return script_->lineno(); }
262 unsigned lineno(jsbytecode* pc) const { return PCToLineNumber(script_, pc); }
264 // Script accessors based on PC.
266 JSAtom* getAtom(jsbytecode* pc) const { return script_->getAtom(pc); }
268 PropertyName* getName(jsbytecode* pc) const { return script_->getName(pc); }
270 inline RegExpObject* getRegExp(jsbytecode* pc) const;
272 JSObject* getObject(jsbytecode* pc) const { return script_->getObject(pc); }
274 inline JSFunction* getFunction(jsbytecode* pc) const;
276 BigInt* getBigInt(jsbytecode* pc) const { return script_->getBigInt(pc); }
278 // Total number of slots: args, locals, and stack.
279 unsigned nslots() const { return nslots_; }
281 // Number of slots needed for env chain, return value,
282 // maybe argumentsobject and this value.
283 unsigned nimplicit() const { return nimplicit_; }
284 // Number of arguments (without counting this value).
285 unsigned nargs() const { return nargs_; }
286 // Number of slots needed for all local variables. This includes "fixed
287 // vars" (see above) and also block-scoped locals.
288 unsigned nlocals() const { return nlocals_; }
289 unsigned ninvoke() const { return nslots_ - nstack_; }
291 uint32_t environmentChainSlot() const {
292 MOZ_ASSERT(script());
293 return 0;
295 uint32_t returnValueSlot() const {
296 MOZ_ASSERT(script());
297 return 1;
299 uint32_t argsObjSlot() const {
300 MOZ_ASSERT(hasArguments());
301 return 2;
303 uint32_t thisSlot() const {
304 MOZ_ASSERT(funMaybeLazy());
305 MOZ_ASSERT(nimplicit_ > 0);
306 return nimplicit_ - 1;
308 uint32_t firstArgSlot() const { return nimplicit_; }
309 uint32_t argSlotUnchecked(uint32_t i) const {
310 // During initialization, some routines need to get at arg
311 // slots regardless of how regular argument access is done.
312 MOZ_ASSERT(i < nargs_);
313 return nimplicit_ + i;
315 uint32_t argSlot(uint32_t i) const {
316 // This should only be accessed when compiling functions for
317 // which argument accesses don't need to go through the
318 // argument object.
319 MOZ_ASSERT(!argsObjAliasesFormals());
320 return argSlotUnchecked(i);
322 uint32_t firstLocalSlot() const { return nimplicit_ + nargs_; }
323 uint32_t localSlot(uint32_t i) const { return firstLocalSlot() + i; }
324 uint32_t firstStackSlot() const { return firstLocalSlot() + nlocals(); }
325 uint32_t stackSlot(uint32_t i) const { return firstStackSlot() + i; }
327 uint32_t startArgSlot() const {
328 MOZ_ASSERT(script());
329 return StartArgSlot(script());
331 uint32_t endArgSlot() const {
332 MOZ_ASSERT(script());
333 return CountArgSlots(script(), funMaybeLazy());
336 uint32_t totalSlots() const {
337 MOZ_ASSERT(script() && funMaybeLazy());
338 return nimplicit() + nargs() + nlocals();
341 bool isSlotAliased(uint32_t index) const {
342 MOZ_ASSERT(index >= startArgSlot());
343 uint32_t arg = index - firstArgSlot();
344 if (arg < nargs()) {
345 return script()->formalIsAliased(arg);
347 return false;
350 bool hasArguments() const { return script()->argumentsHasVarBinding(); }
351 bool argumentsAliasesFormals() const {
352 return script()->argumentsAliasesFormals();
354 bool hasMappedArgsObj() const { return script()->hasMappedArgsObj(); }
355 bool needsArgsObj() const { return scriptNeedsArgsObj_; }
356 bool argsObjAliasesFormals() const {
357 return scriptNeedsArgsObj_ && script()->hasMappedArgsObj();
360 AnalysisMode analysisMode() const { return analysisMode_; }
362 bool isAnalysis() const { return analysisMode_ != Analysis_None; }
364 bool needsBodyEnvironmentObject() const {
365 return needsBodyEnvironmentObject_;
368 enum class SlotObservableKind {
369 // This slot must be preserved because it's observable outside SSA uses.
370 // It can't be recovered before or during bailout.
371 ObservableNotRecoverable,
373 // This slot must be preserved because it's observable, but it can be
374 // recovered.
375 ObservableRecoverable,
377 // This slot is not observable outside SSA uses.
378 NotObservable,
381 inline SlotObservableKind getSlotObservableKind(uint32_t slot) const {
382 // Locals and expression stack slots.
383 if (slot >= firstLocalSlot()) {
384 // The |this| slot for a derived class constructor is a local slot.
385 // It should never be optimized out, as a Debugger might need to perform
386 // TDZ checks on it via, e.g., an exceptionUnwind handler. The TDZ check
387 // is required for correctness if the handler decides to continue
388 // execution.
389 if (thisSlotForDerivedClassConstructor_ &&
390 *thisSlotForDerivedClassConstructor_ == slot) {
391 return SlotObservableKind::ObservableNotRecoverable;
393 return SlotObservableKind::NotObservable;
396 // Formal argument slots.
397 if (slot >= firstArgSlot()) {
398 MOZ_ASSERT(funMaybeLazy());
399 MOZ_ASSERT(slot - firstArgSlot() < nargs());
401 // Preserve formal arguments if they might be read when creating a rest or
402 // arguments object. In non-strict scripts, Function.arguments can create
403 // an arguments object dynamically so we always preserve the arguments.
404 if (mayReadFrameArgsDirectly_ || !script()->strict()) {
405 return SlotObservableKind::ObservableRecoverable;
407 return SlotObservableKind::NotObservable;
410 // |this| slot is observable but it can be recovered.
411 if (funMaybeLazy() && slot == thisSlot()) {
412 return SlotObservableKind::ObservableRecoverable;
415 // Environment chain slot.
416 if (slot == environmentChainSlot()) {
417 // If environments can be added in the body (after the prologue) we need
418 // to preserve the environment chain slot. It can't be recovered.
419 if (needsBodyEnvironmentObject()) {
420 return SlotObservableKind::ObservableNotRecoverable;
422 // If the function may need an arguments object, also preserve the
423 // environment chain because it may be needed to reconstruct the arguments
424 // object during bailout.
425 if (funNeedsSomeEnvironmentObject_ || hasArguments()) {
426 return SlotObservableKind::ObservableRecoverable;
428 return SlotObservableKind::NotObservable;
431 // The arguments object is observable and not recoverable.
432 if (hasArguments() && slot == argsObjSlot()) {
433 MOZ_ASSERT(funMaybeLazy());
434 return SlotObservableKind::ObservableNotRecoverable;
437 MOZ_ASSERT(slot == returnValueSlot());
438 return SlotObservableKind::NotObservable;
441 // Returns true if a slot can be observed out-side the current frame while
442 // the frame is active on the stack. This implies that these definitions
443 // would have to be executed and that they cannot be removed even if they
444 // are unused.
445 inline bool isObservableSlot(uint32_t slot) const {
446 SlotObservableKind kind = getSlotObservableKind(slot);
447 return (kind == SlotObservableKind::ObservableNotRecoverable ||
448 kind == SlotObservableKind::ObservableRecoverable);
451 // Returns true if a slot can be recovered before or during a bailout. A
452 // definition which can be observed and recovered, implies that this
453 // definition can be optimized away as long as we can compute its values.
454 bool isRecoverableOperand(uint32_t slot) const {
455 SlotObservableKind kind = getSlotObservableKind(slot);
456 return (kind == SlotObservableKind::ObservableRecoverable ||
457 kind == SlotObservableKind::NotObservable);
460 // Check previous bailout states to prevent doing the same bailout in the
461 // next compilation.
462 bool hadOverflowBailout() const { return hadOverflowBailout_; }
463 bool hadFrequentBailouts() const { return hadFrequentBailouts_; }
464 bool mayReadFrameArgsDirectly() const { return mayReadFrameArgsDirectly_; }
466 private:
467 unsigned nimplicit_;
468 unsigned nargs_;
469 unsigned nlocals_;
470 unsigned nstack_;
471 unsigned nslots_;
472 mozilla::Maybe<unsigned> thisSlotForDerivedClassConstructor_;
473 JSScript* script_;
474 JSFunction* fun_;
475 jsbytecode* osrPc_;
476 AnalysisMode analysisMode_;
478 // Whether a script needs an arguments object is unstable over compilation
479 // since the arguments optimization could be marked as failed on the active
480 // thread, so cache a value here and use it throughout for consistency.
481 bool scriptNeedsArgsObj_;
483 // Record the state of previous bailouts in order to prevent compiling the
484 // same function identically the next time.
485 bool hadOverflowBailout_;
486 bool hadFrequentBailouts_;
488 bool mayReadFrameArgsDirectly_;
490 InlineScriptTree* inlineScriptTree_;
492 // Whether a script needs environments within its body. This informs us
493 // that the environment chain is not easy to reconstruct.
494 bool needsBodyEnvironmentObject_;
495 bool funNeedsSomeEnvironmentObject_;
498 } // namespace jit
499 } // namespace js
501 #endif /* jit_CompileInfo_h */