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/Assertions.h" // MOZ_ASSERT
11 #include "mozilla/Maybe.h" // mozilla::Maybe, mozilla::Some
13 #include <algorithm> // std::max
14 #include <stdint.h> // uint32_t
16 #include "jit/CompileWrappers.h" // CompileRuntime
17 #include "jit/JitFrames.h" // MinJITStackSize
18 #include "jit/shared/Assembler-shared.h"
19 #include "js/TypeDecls.h" // jsbytecode
20 #include "vm/BindingKind.h" // BindingLocation
21 #include "vm/JSAtomState.h" // JSAtomState
22 #include "vm/JSFunction.h" // JSFunction
23 #include "vm/JSScript.h" // JSScript
24 #include "vm/Opcodes.h" // JSOp
25 #include "vm/Scope.h" // BindingIter
33 class InlineScriptTree
;
35 inline unsigned StartArgSlot(JSScript
* script
) {
37 // Slot 0: Environment chain.
38 // Slot 1: Return value.
41 // Slot 2: Argumentsobject.
43 // Note: when updating this, please also update the assert in
44 // SnapshotWriter::startFrame
45 return 2 + (script
->needsArgsObj() ? 1 : 0);
48 inline unsigned CountArgSlots(JSScript
* script
, JSFunction
* fun
) {
49 // Slot x + 0: This value.
50 // Slot x + 1: Argument 1.
52 // Slot x + n: Argument n.
54 // Note: when updating this, please also update the assert in
55 // SnapshotWriter::startFrame
56 return StartArgSlot(script
) + (fun
? fun
->nargs() + 1 : 0);
59 inline unsigned CountArgSlots(JSScript
* script
, bool hasFun
,
60 uint32_t funArgCount
) {
61 // Same as the previous function, for use when the JSFunction is not
63 return StartArgSlot(script
) + (hasFun
? funArgCount
+ 1 : 0);
66 // Contains information about the compilation source for IR being generated.
69 CompileInfo(CompileRuntime
* runtime
, JSScript
* script
, JSFunction
* fun
,
70 jsbytecode
* osrPc
, bool scriptNeedsArgsObj
,
71 InlineScriptTree
* inlineScriptTree
)
75 scriptNeedsArgsObj_(scriptNeedsArgsObj
),
76 hadEagerTruncationBailout_(script
->hadEagerTruncationBailout()),
77 hadSpeculativePhiBailout_(script
->hadSpeculativePhiBailout()),
78 hadLICMInvalidation_(script
->hadLICMInvalidation()),
79 hadReorderingBailout_(script
->hadReorderingBailout()),
80 hadBoundsCheckBailout_(script
->failedBoundsCheck()),
81 hadUnboxFoldingBailout_(script
->hadUnboxFoldingBailout()),
82 mayReadFrameArgsDirectly_(script
->mayReadFrameArgsDirectly()),
83 anyFormalIsForwarded_(script
->anyFormalIsForwarded()),
84 isDerivedClassConstructor_(script
->isDerivedClassConstructor()),
85 inlineScriptTree_(inlineScriptTree
),
86 hasSeenObjectEmulateUndefinedFuseIntact_(
87 runtime
->hasSeenObjectEmulateUndefinedFuseIntact()) {
88 MOZ_ASSERT_IF(osrPc
, JSOp(*osrPc
) == JSOp::LoopHead
);
90 // The function here can flow in from anywhere so look up the canonical
91 // function to ensure that we do not try to embed a nursery pointer in
92 // jit-code. Precisely because it can flow in from anywhere, it's not
93 // guaranteed to be non-lazy. Hence, don't access its script!
95 fun_
= fun_
->baseScript()->function();
96 MOZ_ASSERT(fun_
->isTenured());
99 nimplicit_
= StartArgSlot(script
) /* env chain and argument obj */
100 + (fun
? 1 : 0); /* this */
101 nargs_
= fun
? fun
->nargs() : 0;
102 nlocals_
= script
->nfixed();
104 // An extra slot is needed for global scopes because InitGLexical (stack
105 // depth 1) is compiled as a SetProp (stack depth 2) on the global lexical
107 uint32_t extra
= script
->isGlobalCode() ? 1 : 0;
108 nstack_
= std::max
<unsigned>(script
->nslots() - script
->nfixed(),
111 nslots_
= nimplicit_
+ nargs_
+ nlocals_
+ nstack_
;
113 // For derived class constructors, find and cache the frame slot for
114 // the .this binding. This slot is assumed to be always
115 // observable. See isObservableFrameSlot.
116 if (script
->isDerivedClassConstructor()) {
117 MOZ_ASSERT(script
->functionHasThisBinding());
118 for (BindingIter
bi(script
); bi
; bi
++) {
119 if (bi
.name() != runtime
->names().dot_this_
) {
122 BindingLocation loc
= bi
.location();
123 if (loc
.kind() == BindingLocation::Kind::Frame
) {
124 thisSlotForDerivedClassConstructor_
=
125 mozilla::Some(localSlot(loc
.slot()));
131 // If the script uses an environment in body, the environment chain
132 // will need to be observable.
133 needsBodyEnvironmentObject_
= script
->needsBodyEnvironment();
134 funNeedsSomeEnvironmentObject_
=
135 fun
? fun
->needsSomeEnvironmentObject() : false;
138 explicit CompileInfo(unsigned nlocals
)
142 scriptNeedsArgsObj_(false),
143 hadEagerTruncationBailout_(false),
144 hadSpeculativePhiBailout_(false),
145 hadLICMInvalidation_(false),
146 hadReorderingBailout_(false),
147 hadBoundsCheckBailout_(false),
148 hadUnboxFoldingBailout_(false),
149 mayReadFrameArgsDirectly_(false),
150 anyFormalIsForwarded_(false),
151 inlineScriptTree_(nullptr),
152 needsBodyEnvironmentObject_(false),
153 funNeedsSomeEnvironmentObject_(false),
154 hasSeenObjectEmulateUndefinedFuseIntact_(false) {
158 nstack_
= 1; /* For FunctionCompiler::pushPhiInput/popPhiOutput */
159 nslots_
= nlocals_
+ nstack_
;
162 JSScript
* script() const { return script_
; }
163 bool compilingWasm() const { return script() == nullptr; }
164 ModuleObject
* module() const { return script_
->module(); }
165 jsbytecode
* osrPc() const { return osrPc_
; }
166 InlineScriptTree
* inlineScriptTree() const { return inlineScriptTree_
; }
168 // It's not safe to access the JSFunction off main thread.
169 bool hasFunMaybeLazy() const { return fun_
; }
170 ImmGCPtr
funMaybeLazy() const { return ImmGCPtr(fun_
); }
172 const char* filename() const { return script_
->filename(); }
174 unsigned lineno() const { return script_
->lineno(); }
176 // Total number of slots: args, locals, and stack.
177 unsigned nslots() const { return nslots_
; }
179 // Number of slots needed for env chain, return value,
180 // maybe argumentsobject and this value.
181 unsigned nimplicit() const { return nimplicit_
; }
182 // Number of arguments (without counting this value).
183 unsigned nargs() const { return nargs_
; }
184 // Number of slots needed for all local variables. This includes "fixed
185 // vars" (see above) and also block-scoped locals.
186 unsigned nlocals() const { return nlocals_
; }
187 unsigned ninvoke() const { return nslots_
- nstack_
; }
189 uint32_t environmentChainSlot() const {
190 MOZ_ASSERT(script());
193 uint32_t returnValueSlot() const {
194 MOZ_ASSERT(script());
197 uint32_t argsObjSlot() const {
198 MOZ_ASSERT(needsArgsObj());
201 uint32_t thisSlot() const {
202 MOZ_ASSERT(hasFunMaybeLazy());
203 MOZ_ASSERT(nimplicit_
> 0);
204 return nimplicit_
- 1;
206 uint32_t firstArgSlot() const { return nimplicit_
; }
207 uint32_t argSlotUnchecked(uint32_t i
) const {
208 // During initialization, some routines need to get at arg
209 // slots regardless of how regular argument access is done.
210 MOZ_ASSERT(i
< nargs_
);
211 return nimplicit_
+ i
;
213 uint32_t argSlot(uint32_t i
) const {
214 // This should only be accessed when compiling functions for
215 // which argument accesses don't need to go through the
217 MOZ_ASSERT(!argsObjAliasesFormals());
218 return argSlotUnchecked(i
);
220 uint32_t firstLocalSlot() const { return nimplicit_
+ nargs_
; }
221 uint32_t localSlot(uint32_t i
) const { return firstLocalSlot() + i
; }
222 uint32_t firstStackSlot() const { return firstLocalSlot() + nlocals(); }
223 uint32_t stackSlot(uint32_t i
) const { return firstStackSlot() + i
; }
225 uint32_t totalSlots() const {
226 MOZ_ASSERT(script() && hasFunMaybeLazy());
227 return nimplicit() + nargs() + nlocals();
230 bool hasMappedArgsObj() const { return script()->hasMappedArgsObj(); }
231 bool needsArgsObj() const { return scriptNeedsArgsObj_
; }
232 bool argsObjAliasesFormals() const {
233 return scriptNeedsArgsObj_
&& script()->hasMappedArgsObj();
236 bool needsBodyEnvironmentObject() const {
237 return needsBodyEnvironmentObject_
;
240 enum class SlotObservableKind
{
241 // This slot must be preserved because it's observable outside SSA uses.
242 // It can't be recovered before or during bailout.
243 ObservableNotRecoverable
,
245 // This slot must be preserved because it's observable, but it can be
247 ObservableRecoverable
,
249 // This slot is not observable outside SSA uses.
253 inline SlotObservableKind
getSlotObservableKind(uint32_t slot
) const {
254 // Locals and expression stack slots.
255 if (slot
>= firstLocalSlot()) {
256 // The |this| slot for a derived class constructor is a local slot.
257 // It should never be optimized out, as a Debugger might need to perform
258 // TDZ checks on it via, e.g., an exceptionUnwind handler. The TDZ check
259 // is required for correctness if the handler decides to continue
261 if (thisSlotForDerivedClassConstructor_
&&
262 *thisSlotForDerivedClassConstructor_
== slot
) {
263 return SlotObservableKind::ObservableNotRecoverable
;
265 return SlotObservableKind::NotObservable
;
268 // Formal argument slots.
269 if (slot
>= firstArgSlot()) {
270 MOZ_ASSERT(hasFunMaybeLazy());
271 MOZ_ASSERT(slot
- firstArgSlot() < nargs());
273 // Preserve formal arguments if they might be read when creating a rest or
274 // arguments object. In non-strict scripts, Function.arguments can create
275 // an arguments object dynamically so we always preserve the arguments.
276 if (mayReadFrameArgsDirectly_
|| !script()->strict()) {
277 return SlotObservableKind::ObservableRecoverable
;
279 return SlotObservableKind::NotObservable
;
282 // |this| slot is observable but it can be recovered.
283 if (hasFunMaybeLazy() && slot
== thisSlot()) {
284 return SlotObservableKind::ObservableRecoverable
;
287 // Environment chain slot.
288 if (slot
== environmentChainSlot()) {
289 // If environments can be added in the body (after the prologue) we need
290 // to preserve the environment chain slot. It can't be recovered.
291 if (needsBodyEnvironmentObject()) {
292 return SlotObservableKind::ObservableNotRecoverable
;
294 // If the function may need an arguments object, also preserve the
295 // environment chain because it may be needed to reconstruct the arguments
296 // object during bailout.
297 if (funNeedsSomeEnvironmentObject_
|| needsArgsObj()) {
298 return SlotObservableKind::ObservableRecoverable
;
300 return SlotObservableKind::NotObservable
;
303 // The arguments object is observable. If it does not escape, it can
305 if (needsArgsObj() && slot
== argsObjSlot()) {
306 MOZ_ASSERT(hasFunMaybeLazy());
307 return SlotObservableKind::ObservableRecoverable
;
310 MOZ_ASSERT(slot
== returnValueSlot());
311 return SlotObservableKind::NotObservable
;
314 // Returns true if a slot can be observed out-side the current frame while
315 // the frame is active on the stack. This implies that these definitions
316 // would have to be executed and that they cannot be removed even if they
318 inline bool isObservableSlot(uint32_t slot
) const {
319 SlotObservableKind kind
= getSlotObservableKind(slot
);
320 return (kind
== SlotObservableKind::ObservableNotRecoverable
||
321 kind
== SlotObservableKind::ObservableRecoverable
);
324 // Returns true if a slot can be recovered before or during a bailout. A
325 // definition which can be observed and recovered, implies that this
326 // definition can be optimized away as long as we can compute its values.
327 bool isRecoverableOperand(uint32_t slot
) const {
328 SlotObservableKind kind
= getSlotObservableKind(slot
);
329 return (kind
== SlotObservableKind::ObservableRecoverable
||
330 kind
== SlotObservableKind::NotObservable
);
333 // Check previous bailout states to prevent doing the same bailout in the
335 bool hadEagerTruncationBailout() const { return hadEagerTruncationBailout_
; }
336 bool hadSpeculativePhiBailout() const { return hadSpeculativePhiBailout_
; }
337 bool hadLICMInvalidation() const { return hadLICMInvalidation_
; }
338 bool hadReorderingBailout() const { return hadReorderingBailout_
; }
339 bool hadBoundsCheckBailout() const { return hadBoundsCheckBailout_
; }
340 bool hadUnboxFoldingBailout() const { return hadUnboxFoldingBailout_
; }
342 bool mayReadFrameArgsDirectly() const { return mayReadFrameArgsDirectly_
; }
343 bool anyFormalIsForwarded() const { return anyFormalIsForwarded_
; }
345 bool isDerivedClassConstructor() const { return isDerivedClassConstructor_
; }
347 bool hasSeenObjectEmulateUndefinedFuseIntact() const {
348 return hasSeenObjectEmulateUndefinedFuseIntact_
;
357 mozilla::Maybe
<unsigned> thisSlotForDerivedClassConstructor_
;
362 bool scriptNeedsArgsObj_
;
364 // Record the state of previous bailouts in order to prevent compiling the
365 // same function identically the next time.
366 bool hadEagerTruncationBailout_
;
367 bool hadSpeculativePhiBailout_
;
368 bool hadLICMInvalidation_
;
369 bool hadReorderingBailout_
;
370 bool hadBoundsCheckBailout_
;
371 bool hadUnboxFoldingBailout_
;
373 bool mayReadFrameArgsDirectly_
;
374 bool anyFormalIsForwarded_
;
376 bool isDerivedClassConstructor_
;
378 InlineScriptTree
* inlineScriptTree_
;
380 // Whether a script needs environments within its body. This informs us
381 // that the environment chain is not easy to reconstruct.
382 bool needsBodyEnvironmentObject_
;
383 bool funNeedsSomeEnvironmentObject_
;
385 bool hasSeenObjectEmulateUndefinedFuseIntact_
;
391 #endif /* jit_CompileInfo_h */