Bug 1890513: Directly invoke variadic native functions. r=jandem
[gecko.git] / js / src / jit / CompileInfo.h
blob1980a3d905679cb27b29311d4715089a3ae945f1
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
27 namespace js {
29 class ModuleObject;
31 namespace jit {
33 class InlineScriptTree;
35 inline unsigned StartArgSlot(JSScript* script) {
36 // Reserved slots:
37 // Slot 0: Environment chain.
38 // Slot 1: Return value.
40 // When needed:
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.
51 // ...
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
62 // available.
63 return StartArgSlot(script) + (hasFun ? funArgCount + 1 : 0);
66 // Contains information about the compilation source for IR being generated.
67 class CompileInfo {
68 public:
69 CompileInfo(CompileRuntime* runtime, JSScript* script, JSFunction* fun,
70 jsbytecode* osrPc, bool scriptNeedsArgsObj,
71 InlineScriptTree* inlineScriptTree)
72 : script_(script),
73 fun_(fun),
74 osrPc_(osrPc),
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!
94 if (fun_) {
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
106 // scope.
107 uint32_t extra = script->isGlobalCode() ? 1 : 0;
108 nstack_ = std::max<unsigned>(script->nslots() - script->nfixed(),
109 MinJITStackSize) +
110 extra;
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_) {
120 continue;
122 BindingLocation loc = bi.location();
123 if (loc.kind() == BindingLocation::Kind::Frame) {
124 thisSlotForDerivedClassConstructor_ =
125 mozilla::Some(localSlot(loc.slot()));
126 break;
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)
139 : script_(nullptr),
140 fun_(nullptr),
141 osrPc_(nullptr),
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) {
155 nimplicit_ = 0;
156 nargs_ = 0;
157 nlocals_ = nlocals;
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());
191 return 0;
193 uint32_t returnValueSlot() const {
194 MOZ_ASSERT(script());
195 return 1;
197 uint32_t argsObjSlot() const {
198 MOZ_ASSERT(needsArgsObj());
199 return 2;
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
216 // argument object.
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
246 // recovered.
247 ObservableRecoverable,
249 // This slot is not observable outside SSA uses.
250 NotObservable,
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
260 // execution.
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
304 // be recovered.
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
317 // are unused.
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
334 // next compilation.
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_;
351 private:
352 unsigned nimplicit_;
353 unsigned nargs_;
354 unsigned nlocals_;
355 unsigned nstack_;
356 unsigned nslots_;
357 mozilla::Maybe<unsigned> thisSlotForDerivedClassConstructor_;
358 JSScript* script_;
359 JSFunction* fun_;
360 jsbytecode* osrPc_;
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_;
388 } // namespace jit
389 } // namespace js
391 #endif /* jit_CompileInfo_h */