1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2  * vim: set ts=8 sts=4 et sw=4 tw=99:
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/. */
6 
7 #ifndef jit_IonBuilder_h
8 #define jit_IonBuilder_h
9 
10 // This file declares the data structures for building a MIRGraph from a
11 // JSScript.
12 
13 #include "mozilla/LinkedList.h"
14 
15 #include "jit/BaselineInspector.h"
16 #include "jit/BytecodeAnalysis.h"
17 #include "jit/IonAnalysis.h"
18 #include "jit/IonOptimizationLevels.h"
19 #include "jit/MIR.h"
20 #include "jit/MIRGenerator.h"
21 #include "jit/MIRGraph.h"
22 #include "jit/OptimizationTracking.h"
23 
24 namespace js {
25 namespace jit {
26 
27 class CodeGenerator;
28 class CallInfo;
29 class BaselineFrameInspector;
30 
31 enum class InlinableNative : uint16_t;
32 
33 // Records information about a baseline frame for compilation that is stable
34 // when later used off thread.
35 BaselineFrameInspector*
36 NewBaselineFrameInspector(TempAllocator* temp, BaselineFrame* frame, CompileInfo* info);
37 
38 class IonBuilder
39   : public MIRGenerator,
40     public mozilla::LinkedListElement<IonBuilder>
41 {
42     enum ControlStatus {
43         ControlStatus_Error,
44         ControlStatus_Abort,
45         ControlStatus_Ended,        // There is no continuation/join point.
46         ControlStatus_Joined,       // Created a join node.
47         ControlStatus_Jumped,       // Parsing another branch at the same level.
48         ControlStatus_None          // No control flow.
49     };
50 
51     struct DeferredEdge : public TempObject
52     {
53         MBasicBlock* block;
54         DeferredEdge* next;
55 
DeferredEdgeDeferredEdge56         DeferredEdge(MBasicBlock* block, DeferredEdge* next)
57           : block(block), next(next)
58         { }
59     };
60 
61     struct ControlFlowInfo {
62         // Entry in the cfgStack.
63         uint32_t cfgEntry;
64 
65         // Label that continues go to.
66         jsbytecode* continuepc;
67 
ControlFlowInfoControlFlowInfo68         ControlFlowInfo(uint32_t cfgEntry, jsbytecode* continuepc)
69           : cfgEntry(cfgEntry),
70             continuepc(continuepc)
71         { }
72     };
73 
74     // To avoid recursion, the bytecode analyzer uses a stack where each entry
75     // is a small state machine. As we encounter branches or jumps in the
76     // bytecode, we push information about the edges on the stack so that the
77     // CFG can be built in a tree-like fashion.
78     struct CFGState {
79         enum State {
80             IF_TRUE,            // if() { }, no else.
81             IF_TRUE_EMPTY_ELSE, // if() { }, empty else
82             IF_ELSE_TRUE,       // if() { X } else { }
83             IF_ELSE_FALSE,      // if() { } else { X }
84             DO_WHILE_LOOP_BODY, // do { x } while ()
85             DO_WHILE_LOOP_COND, // do { } while (x)
86             WHILE_LOOP_COND,    // while (x) { }
87             WHILE_LOOP_BODY,    // while () { x }
88             FOR_LOOP_COND,      // for (; x;) { }
89             FOR_LOOP_BODY,      // for (; ;) { x }
90             FOR_LOOP_UPDATE,    // for (; ; x) { }
91             TABLE_SWITCH,       // switch() { x }
92             COND_SWITCH_CASE,   // switch() { case X: ... }
93             COND_SWITCH_BODY,   // switch() { case ...: X }
94             AND_OR,             // && x, || x
95             LABEL,              // label: x
96             TRY                 // try { x } catch(e) { }
97         };
98 
99         State state;            // Current state of this control structure.
100         jsbytecode* stopAt;     // Bytecode at which to stop the processing loop.
101 
102         // For if structures, this contains branch information.
103         union {
104             struct {
105                 MBasicBlock* ifFalse;
106                 jsbytecode* falseEnd;
107                 MBasicBlock* ifTrue;    // Set when the end of the true path is reached.
108                 MTest* test;
109             } branch;
110             struct {
111                 // Common entry point.
112                 MBasicBlock* entry;
113 
114                 // Whether OSR is being performed for this loop.
115                 bool osr;
116 
117                 // Position of where the loop body starts and ends.
118                 jsbytecode* bodyStart;
119                 jsbytecode* bodyEnd;
120 
121                 // pc immediately after the loop exits.
122                 jsbytecode* exitpc;
123 
124                 // pc for 'continue' jumps.
125                 jsbytecode* continuepc;
126 
127                 // Common exit point. Created lazily, so it may be nullptr.
128                 MBasicBlock* successor;
129 
130                 // Deferred break and continue targets.
131                 DeferredEdge* breaks;
132                 DeferredEdge* continues;
133 
134                 // Initial state, in case loop processing is restarted.
135                 State initialState;
136                 jsbytecode* initialPc;
137                 jsbytecode* initialStopAt;
138                 jsbytecode* loopHead;
139 
140                 // For-loops only.
141                 jsbytecode* condpc;
142                 jsbytecode* updatepc;
143                 jsbytecode* updateEnd;
144             } loop;
145             struct {
146                 // pc immediately after the switch.
147                 jsbytecode* exitpc;
148 
149                 // Deferred break and continue targets.
150                 DeferredEdge* breaks;
151 
152                 // MIR instruction
153                 MTableSwitch* ins;
154 
155                 // The number of current successor that get mapped into a block.
156                 uint32_t currentBlock;
157 
158             } tableswitch;
159             struct {
160                 // Vector of body blocks to process after the cases.
161                 FixedList<MBasicBlock*>* bodies;
162 
163                 // When processing case statements, this counter points at the
164                 // last uninitialized body.  When processing bodies, this
165                 // counter targets the next body to process.
166                 uint32_t currentIdx;
167 
168                 // Remember the block index of the default case.
169                 jsbytecode* defaultTarget;
170                 uint32_t defaultIdx;
171 
172                 // Block immediately after the switch.
173                 jsbytecode* exitpc;
174                 DeferredEdge* breaks;
175             } condswitch;
176             struct {
177                 DeferredEdge* breaks;
178             } label;
179             struct {
180                 MBasicBlock* successor;
181             } try_;
182         };
183 
isLoopCFGState184         inline bool isLoop() const {
185             switch (state) {
186               case DO_WHILE_LOOP_COND:
187               case DO_WHILE_LOOP_BODY:
188               case WHILE_LOOP_COND:
189               case WHILE_LOOP_BODY:
190               case FOR_LOOP_COND:
191               case FOR_LOOP_BODY:
192               case FOR_LOOP_UPDATE:
193                 return true;
194               default:
195                 return false;
196             }
197         }
198 
199         static CFGState If(jsbytecode* join, MTest* test);
200         static CFGState IfElse(jsbytecode* trueEnd, jsbytecode* falseEnd, MTest* test);
201         static CFGState AndOr(jsbytecode* join, MBasicBlock* lhs);
202         static CFGState TableSwitch(jsbytecode* exitpc, MTableSwitch* ins);
203         static CFGState CondSwitch(IonBuilder* builder, jsbytecode* exitpc, jsbytecode* defaultTarget);
204         static CFGState Label(jsbytecode* exitpc);
205         static CFGState Try(jsbytecode* exitpc, MBasicBlock* successor);
206     };
207 
208     static int CmpSuccessors(const void* a, const void* b);
209 
210   public:
211     IonBuilder(JSContext* analysisContext, CompileCompartment* comp,
212                const JitCompileOptions& options, TempAllocator* temp,
213                MIRGraph* graph, CompilerConstraintList* constraints,
214                BaselineInspector* inspector, CompileInfo* info,
215                const OptimizationInfo* optimizationInfo, BaselineFrameInspector* baselineFrame,
216                size_t inliningDepth = 0, uint32_t loopDepth = 0);
217 
218     // Callers of build() and buildInline() should always check whether the
219     // call overrecursed, if false is returned.  Overrecursion is not
220     // signaled as OOM and will not in general be caught by OOM paths.
221     bool build();
222     bool buildInline(IonBuilder* callerBuilder, MResumePoint* callerResumePoint,
223                      CallInfo& callInfo);
224 
225   private:
226     bool traverseBytecode();
227     ControlStatus snoopControlFlow(JSOp op);
228     bool processIterators();
229     bool inspectOpcode(JSOp op);
230     uint32_t readIndex(jsbytecode* pc);
231     JSAtom* readAtom(jsbytecode* pc);
232     bool abort(const char* message, ...);
233     void trackActionableAbort(const char* message);
234     void spew(const char* message);
235 
236     JSFunction* getSingleCallTarget(TemporaryTypeSet* calleeTypes);
237     bool getPolyCallTargets(TemporaryTypeSet* calleeTypes, bool constructing,
238                             ObjectVector& targets, uint32_t maxTargets);
239 
240     void popCfgStack();
241     DeferredEdge* filterDeadDeferredEdges(DeferredEdge* edge);
242     bool processDeferredContinues(CFGState& state);
243     ControlStatus processControlEnd();
244     ControlStatus processCfgStack();
245     ControlStatus processCfgEntry(CFGState& state);
246     ControlStatus processIfEnd(CFGState& state);
247     ControlStatus processIfElseTrueEnd(CFGState& state);
248     ControlStatus processIfElseFalseEnd(CFGState& state);
249     ControlStatus processDoWhileBodyEnd(CFGState& state);
250     ControlStatus processDoWhileCondEnd(CFGState& state);
251     ControlStatus processWhileCondEnd(CFGState& state);
252     ControlStatus processWhileBodyEnd(CFGState& state);
253     ControlStatus processForCondEnd(CFGState& state);
254     ControlStatus processForBodyEnd(CFGState& state);
255     ControlStatus processForUpdateEnd(CFGState& state);
256     ControlStatus processNextTableSwitchCase(CFGState& state);
257     ControlStatus processCondSwitchCase(CFGState& state);
258     ControlStatus processCondSwitchBody(CFGState& state);
259     ControlStatus processSwitchBreak(JSOp op);
260     ControlStatus processSwitchEnd(DeferredEdge* breaks, jsbytecode* exitpc);
261     ControlStatus processAndOrEnd(CFGState& state);
262     ControlStatus processLabelEnd(CFGState& state);
263     ControlStatus processTryEnd(CFGState& state);
264     ControlStatus processReturn(JSOp op);
265     ControlStatus processThrow();
266     ControlStatus processContinue(JSOp op);
267     ControlStatus processBreak(JSOp op, jssrcnote* sn);
268     ControlStatus maybeLoop(JSOp op, jssrcnote* sn);
269     bool pushLoop(CFGState::State state, jsbytecode* stopAt, MBasicBlock* entry, bool osr,
270                   jsbytecode* loopHead, jsbytecode* initialPc,
271                   jsbytecode* bodyStart, jsbytecode* bodyEnd,
272                   jsbytecode* exitpc, jsbytecode* continuepc);
273     bool analyzeNewLoopTypes(MBasicBlock* entry, jsbytecode* start, jsbytecode* end);
274 
275     MBasicBlock* addBlock(MBasicBlock* block, uint32_t loopDepth);
276     MBasicBlock* newBlock(MBasicBlock* predecessor, jsbytecode* pc);
277     MBasicBlock* newBlock(MBasicBlock* predecessor, jsbytecode* pc, uint32_t loopDepth);
278     MBasicBlock* newBlock(MBasicBlock* predecessor, jsbytecode* pc, MResumePoint* priorResumePoint);
279     MBasicBlock* newBlockPopN(MBasicBlock* predecessor, jsbytecode* pc, uint32_t popped);
280     MBasicBlock* newBlockAfter(MBasicBlock* at, MBasicBlock* predecessor, jsbytecode* pc);
281     MBasicBlock* newOsrPreheader(MBasicBlock* header, jsbytecode* loopEntry,
282                                  jsbytecode* beforeLoopEntry);
283     MBasicBlock* newPendingLoopHeader(MBasicBlock* predecessor, jsbytecode* pc, bool osr, bool canOsr,
284                                       unsigned stackPhiCount);
newBlock(jsbytecode * pc)285     MBasicBlock* newBlock(jsbytecode* pc) {
286         return newBlock(nullptr, pc);
287     }
newBlockAfter(MBasicBlock * at,jsbytecode * pc)288     MBasicBlock* newBlockAfter(MBasicBlock* at, jsbytecode* pc) {
289         return newBlockAfter(at, nullptr, pc);
290     }
291 
292     // We want to make sure that our MTest instructions all check whether the
293     // thing being tested might emulate undefined.  So we funnel their creation
294     // through this method, to make sure that happens.  We don't want to just do
295     // the check in MTest::New, because that can run on background compilation
296     // threads, and we're not sure it's safe to touch that part of the typeset
297     // from a background thread.
298     MTest* newTest(MDefinition* ins, MBasicBlock* ifTrue, MBasicBlock* ifFalse);
299 
300     // Given a list of pending breaks, creates a new block and inserts a Goto
301     // linking each break to the new block.
302     MBasicBlock* createBreakCatchBlock(DeferredEdge* edge, jsbytecode* pc);
303 
304     // Finishes loops that do not actually loop, containing only breaks and
305     // returns or a do while loop with a condition that is constant false.
306     ControlStatus processBrokenLoop(CFGState& state);
307 
308     // Computes loop phis, places them in all successors of a loop, then
309     // handles any pending breaks.
310     ControlStatus finishLoop(CFGState& state, MBasicBlock* successor);
311 
312     // Incorporates a type/typeSet into an OSR value for a loop, after the loop
313     // body has been processed.
314     bool addOsrValueTypeBarrier(uint32_t slot, MInstruction** def,
315                                 MIRType type, TemporaryTypeSet* typeSet);
316     bool maybeAddOsrTypeBarriers();
317 
318     // Restarts processing of a loop if the type information at its header was
319     // incomplete.
320     ControlStatus restartLoop(CFGState state);
321 
322     void assertValidLoopHeadOp(jsbytecode* pc);
323 
324     ControlStatus forLoop(JSOp op, jssrcnote* sn);
325     ControlStatus whileOrForInLoop(jssrcnote* sn);
326     ControlStatus doWhileLoop(JSOp op, jssrcnote* sn);
327     ControlStatus tableSwitch(JSOp op, jssrcnote* sn);
328     ControlStatus condSwitch(JSOp op, jssrcnote* sn);
329 
330     // Please see the Big Honkin' Comment about how resume points work in
331     // IonBuilder.cpp, near the definition for this function.
332     bool resume(MInstruction* ins, jsbytecode* pc, MResumePoint::Mode mode);
333     bool resumeAt(MInstruction* ins, jsbytecode* pc);
334     bool resumeAfter(MInstruction* ins);
335     bool maybeInsertResume();
336 
337     void insertRecompileCheck();
338 
339     void initParameters();
340     void initLocals();
341     void rewriteParameter(uint32_t slotIdx, MDefinition* param, int32_t argIndex);
342     void rewriteParameters();
343     bool initScopeChain(MDefinition* callee = nullptr);
344     bool initArgumentsObject();
345     bool pushConstant(const Value& v);
346 
347     MConstant* constant(const Value& v);
348     MConstant* constantInt(int32_t i);
349     MInstruction* initializedLength(MDefinition* obj, MDefinition* elements,
350                                     JSValueType unboxedType);
351     MInstruction* setInitializedLength(MDefinition* obj, JSValueType unboxedType, size_t count);
352 
353     // Improve the type information at tests
354     bool improveTypesAtTest(MDefinition* ins, bool trueBranch, MTest* test);
355     bool improveTypesAtCompare(MCompare* ins, bool trueBranch, MTest* test);
356     bool improveTypesAtNullOrUndefinedCompare(MCompare* ins, bool trueBranch, MTest* test);
357     bool improveTypesAtTypeOfCompare(MCompare* ins, bool trueBranch, MTest* test);
358 
359     // Used to detect triangular structure at test.
360     bool detectAndOrStructure(MPhi* ins, bool* branchIsTrue);
361     bool replaceTypeSet(MDefinition* subject, TemporaryTypeSet* type, MTest* test);
362 
363     // Add a guard which ensure that the set of type which goes through this
364     // generated code correspond to the observed types for the bytecode.
365     MDefinition* addTypeBarrier(MDefinition* def, TemporaryTypeSet* observed,
366                                 BarrierKind kind, MTypeBarrier** pbarrier = nullptr);
367     bool pushTypeBarrier(MDefinition* def, TemporaryTypeSet* observed, BarrierKind kind);
368 
369     // As pushTypeBarrier, but will compute the needBarrier boolean itself based
370     // on observed and the JSFunction that we're planning to call. The
371     // JSFunction must be a DOM method or getter.
372     bool pushDOMTypeBarrier(MInstruction* ins, TemporaryTypeSet* observed, JSFunction* func);
373 
374     // If definiteType is not known or def already has the right type, just
375     // returns def.  Otherwise, returns an MInstruction that has that definite
376     // type, infallibly unboxing ins as needed.  The new instruction will be
377     // added to |current| in this case.
378     MDefinition* ensureDefiniteType(MDefinition* def, MIRType definiteType);
379 
380     // Creates a MDefinition based on the given def improved with type as TypeSet.
381     MDefinition* ensureDefiniteTypeSet(MDefinition* def, TemporaryTypeSet* types);
382 
383     void maybeMarkEmpty(MDefinition* ins);
384 
385     JSObject* getSingletonPrototype(JSFunction* target);
386 
387     MDefinition* createThisScripted(MDefinition* callee, MDefinition* newTarget);
388     MDefinition* createThisScriptedSingleton(JSFunction* target, MDefinition* callee);
389     MDefinition* createThisScriptedBaseline(MDefinition* callee);
390     MDefinition* createThis(JSFunction* target, MDefinition* callee, MDefinition* newTarget);
391     MInstruction* createDeclEnvObject(MDefinition* callee, MDefinition* scopeObj);
392     MInstruction* createCallObject(MDefinition* callee, MDefinition* scopeObj);
393 
394     MDefinition* walkScopeChain(unsigned hops);
395 
396     MInstruction* addConvertElementsToDoubles(MDefinition* elements);
397     MDefinition* addMaybeCopyElementsForWrite(MDefinition* object, bool checkNative);
398     MInstruction* addBoundsCheck(MDefinition* index, MDefinition* length);
399     MInstruction* addShapeGuard(MDefinition* obj, Shape* const shape, BailoutKind bailoutKind);
400     MInstruction* addGroupGuard(MDefinition* obj, ObjectGroup* group, BailoutKind bailoutKind);
401     MInstruction* addUnboxedExpandoGuard(MDefinition* obj, bool hasExpando, BailoutKind bailoutKind);
402     MInstruction* addSharedTypedArrayGuard(MDefinition* obj);
403 
404     MInstruction*
405     addGuardReceiverPolymorphic(MDefinition* obj, const BaselineInspector::ReceiverVector& receivers);
406 
407     MDefinition* convertShiftToMaskForStaticTypedArray(MDefinition* id,
408                                                        Scalar::Type viewType);
409 
410     bool invalidatedIdempotentCache();
411 
412     bool hasStaticScopeObject(ScopeCoordinate sc, JSObject** pcall);
413     bool loadSlot(MDefinition* obj, size_t slot, size_t nfixed, MIRType rvalType,
414                   BarrierKind barrier, TemporaryTypeSet* types);
415     bool loadSlot(MDefinition* obj, Shape* shape, MIRType rvalType,
416                   BarrierKind barrier, TemporaryTypeSet* types);
417     bool storeSlot(MDefinition* obj, size_t slot, size_t nfixed,
418                    MDefinition* value, bool needsBarrier,
419                    MIRType slotType = MIRType_None);
420     bool storeSlot(MDefinition* obj, Shape* shape, MDefinition* value, bool needsBarrier,
421                    MIRType slotType = MIRType_None);
422     bool shouldAbortOnPreliminaryGroups(MDefinition *obj);
423 
424     MDefinition* tryInnerizeWindow(MDefinition* obj);
425     MDefinition* maybeUnboxForPropertyAccess(MDefinition* def);
426 
427     // jsop_getprop() helpers.
428     bool checkIsDefinitelyOptimizedArguments(MDefinition* obj, bool* isOptimizedArgs);
429     bool getPropTryInferredConstant(bool* emitted, MDefinition* obj, PropertyName* name,
430                                     TemporaryTypeSet* types);
431     bool getPropTryArgumentsLength(bool* emitted, MDefinition* obj);
432     bool getPropTryArgumentsCallee(bool* emitted, MDefinition* obj, PropertyName* name);
433     bool getPropTryConstant(bool* emitted, MDefinition* obj, jsid id, TemporaryTypeSet* types);
434     bool getPropTryDefiniteSlot(bool* emitted, MDefinition* obj, PropertyName* name,
435                                 BarrierKind barrier, TemporaryTypeSet* types);
436     bool getPropTryModuleNamespace(bool* emitted, MDefinition* obj, PropertyName* name,
437                                    BarrierKind barrier, TemporaryTypeSet* types);
438     bool getPropTryUnboxed(bool* emitted, MDefinition* obj, PropertyName* name,
439                            BarrierKind barrier, TemporaryTypeSet* types);
440     bool getPropTryCommonGetter(bool* emitted, MDefinition* obj, PropertyName* name,
441                                 TemporaryTypeSet* types);
442     bool getPropTryInlineAccess(bool* emitted, MDefinition* obj, PropertyName* name,
443                                 BarrierKind barrier, TemporaryTypeSet* types);
444     bool getPropTrySimdGetter(bool* emitted, MDefinition* obj, PropertyName* name);
445     bool getPropTryTypedObject(bool* emitted, MDefinition* obj, PropertyName* name);
446     bool getPropTryScalarPropOfTypedObject(bool* emitted, MDefinition* typedObj,
447                                            int32_t fieldOffset,
448                                            TypedObjectPrediction fieldTypeReprs);
449     bool getPropTryReferencePropOfTypedObject(bool* emitted, MDefinition* typedObj,
450                                               int32_t fieldOffset,
451                                               TypedObjectPrediction fieldPrediction,
452                                               PropertyName* name);
453     bool getPropTryComplexPropOfTypedObject(bool* emitted, MDefinition* typedObj,
454                                             int32_t fieldOffset,
455                                             TypedObjectPrediction fieldTypeReprs,
456                                             size_t fieldIndex);
457     bool getPropTryInnerize(bool* emitted, MDefinition* obj, PropertyName* name,
458                             TemporaryTypeSet* types);
459     bool getPropTryCache(bool* emitted, MDefinition* obj, PropertyName* name,
460                          BarrierKind barrier, TemporaryTypeSet* types);
461     bool getPropTrySharedStub(bool* emitted, MDefinition* obj);
462 
463     // jsop_setprop() helpers.
464     bool setPropTryCommonSetter(bool* emitted, MDefinition* obj,
465                                 PropertyName* name, MDefinition* value);
466     bool setPropTryCommonDOMSetter(bool* emitted, MDefinition* obj,
467                                    MDefinition* value, JSFunction* setter,
468                                    TemporaryTypeSet* objTypes);
469     bool setPropTryDefiniteSlot(bool* emitted, MDefinition* obj,
470                                 PropertyName* name, MDefinition* value,
471                                 bool barrier, TemporaryTypeSet* objTypes);
472     bool setPropTryUnboxed(bool* emitted, MDefinition* obj,
473                            PropertyName* name, MDefinition* value,
474                            bool barrier, TemporaryTypeSet* objTypes);
475     bool setPropTryInlineAccess(bool* emitted, MDefinition* obj,
476                                 PropertyName* name, MDefinition* value,
477                                 bool barrier, TemporaryTypeSet* objTypes);
478     bool setPropTryTypedObject(bool* emitted, MDefinition* obj,
479                                PropertyName* name, MDefinition* value);
480     bool setPropTryReferencePropOfTypedObject(bool* emitted,
481                                               MDefinition* obj,
482                                               int32_t fieldOffset,
483                                               MDefinition* value,
484                                               TypedObjectPrediction fieldPrediction,
485                                               PropertyName* name);
486     bool setPropTryScalarPropOfTypedObject(bool* emitted,
487                                            MDefinition* obj,
488                                            int32_t fieldOffset,
489                                            MDefinition* value,
490                                            TypedObjectPrediction fieldTypeReprs);
491     bool setPropTryCache(bool* emitted, MDefinition* obj,
492                          PropertyName* name, MDefinition* value,
493                          bool barrier, TemporaryTypeSet* objTypes);
494 
495     // jsop_binary_arith helpers.
496     MBinaryArithInstruction* binaryArithInstruction(JSOp op, MDefinition* left, MDefinition* right);
497     bool binaryArithTryConcat(bool* emitted, JSOp op, MDefinition* left, MDefinition* right);
498     bool binaryArithTrySpecialized(bool* emitted, JSOp op, MDefinition* left, MDefinition* right);
499     bool binaryArithTrySpecializedOnBaselineInspector(bool* emitted, JSOp op, MDefinition* left,
500                                                       MDefinition* right);
501     bool arithTrySharedStub(bool* emitted, JSOp op, MDefinition* left, MDefinition* right);
502 
503     // jsop_bitnot helpers.
504     bool bitnotTrySpecialized(bool* emitted, MDefinition* input);
505 
506     // jsop_compare helpes.
507     bool compareTrySpecialized(bool* emitted, JSOp op, MDefinition* left, MDefinition* right);
508     bool compareTryBitwise(bool* emitted, JSOp op, MDefinition* left, MDefinition* right);
509     bool compareTrySpecializedOnBaselineInspector(bool* emitted, JSOp op, MDefinition* left,
510                                                   MDefinition* right);
511     bool compareTrySharedStub(bool* emitted, JSOp op, MDefinition* left, MDefinition* right);
512 
513     // binary data lookup helpers.
514     TypedObjectPrediction typedObjectPrediction(MDefinition* typedObj);
515     TypedObjectPrediction typedObjectPrediction(TemporaryTypeSet* types);
516     bool typedObjectHasField(MDefinition* typedObj,
517                              PropertyName* name,
518                              size_t* fieldOffset,
519                              TypedObjectPrediction* fieldTypeReprs,
520                              size_t* fieldIndex);
521     MDefinition* loadTypedObjectType(MDefinition* value);
522     void loadTypedObjectData(MDefinition* typedObj,
523                              MDefinition** owner,
524                              LinearSum* ownerOffset);
525     void loadTypedObjectElements(MDefinition* typedObj,
526                                  const LinearSum& byteOffset,
527                                  int32_t scale,
528                                  MDefinition** ownerElements,
529                                  MDefinition** ownerScaledOffset,
530                                  int32_t* ownerByteAdjustment);
531     MDefinition* typeObjectForElementFromArrayStructType(MDefinition* typedObj);
532     MDefinition* typeObjectForFieldFromStructType(MDefinition* type,
533                                                   size_t fieldIndex);
534     bool storeReferenceTypedObjectValue(MDefinition* typedObj,
535                                         const LinearSum& byteOffset,
536                                         ReferenceTypeDescr::Type type,
537                                         MDefinition* value,
538                                         PropertyName* name);
539     bool storeScalarTypedObjectValue(MDefinition* typedObj,
540                                      const LinearSum& byteOffset,
541                                      ScalarTypeDescr::Type type,
542                                      MDefinition* value);
543     bool checkTypedObjectIndexInBounds(int32_t elemSize,
544                                        MDefinition* obj,
545                                        MDefinition* index,
546                                        TypedObjectPrediction objTypeDescrs,
547                                        LinearSum* indexAsByteOffset);
548     bool pushDerivedTypedObject(bool* emitted,
549                                 MDefinition* obj,
550                                 const LinearSum& byteOffset,
551                                 TypedObjectPrediction derivedTypeDescrs,
552                                 MDefinition* derivedTypeObj);
553     bool pushScalarLoadFromTypedObject(MDefinition* obj,
554                                        const LinearSum& byteoffset,
555                                        ScalarTypeDescr::Type type);
556     bool pushReferenceLoadFromTypedObject(MDefinition* typedObj,
557                                           const LinearSum& byteOffset,
558                                           ReferenceTypeDescr::Type type,
559                                           PropertyName* name);
560     MDefinition* neuterCheck(MDefinition* obj);
561     JSObject* getStaticTypedArrayObject(MDefinition* obj, MDefinition* index);
562 
563     // jsop_setelem() helpers.
564     bool setElemTryTypedArray(bool* emitted, MDefinition* object,
565                          MDefinition* index, MDefinition* value);
566     bool setElemTryTypedObject(bool* emitted, MDefinition* obj,
567                                MDefinition* index, MDefinition* value);
568     bool setElemTryTypedStatic(bool* emitted, MDefinition* object,
569                                MDefinition* index, MDefinition* value);
570     bool setElemTryDense(bool* emitted, MDefinition* object,
571                          MDefinition* index, MDefinition* value, bool writeHole);
572     bool setElemTryArguments(bool* emitted, MDefinition* object,
573                              MDefinition* index, MDefinition* value);
574     bool setElemTryCache(bool* emitted, MDefinition* object,
575                          MDefinition* index, MDefinition* value);
576     bool setElemTryReferenceElemOfTypedObject(bool* emitted,
577                                               MDefinition* obj,
578                                               MDefinition* index,
579                                               TypedObjectPrediction objPrediction,
580                                               MDefinition* value,
581                                               TypedObjectPrediction elemPrediction);
582     bool setElemTryScalarElemOfTypedObject(bool* emitted,
583                                            MDefinition* obj,
584                                            MDefinition* index,
585                                            TypedObjectPrediction objTypeReprs,
586                                            MDefinition* value,
587                                            TypedObjectPrediction elemTypeReprs,
588                                            int32_t elemSize);
589     bool initializeArrayElement(MDefinition* obj, size_t index, MDefinition* value,
590                                 JSValueType unboxedType,
591                                 bool addResumePointAndIncrementInitializedLength);
592 
593     // jsop_getelem() helpers.
594     bool getElemTryDense(bool* emitted, MDefinition* obj, MDefinition* index);
595     bool getElemTryGetProp(bool* emitted, MDefinition* obj, MDefinition* index);
596     bool getElemTryTypedStatic(bool* emitted, MDefinition* obj, MDefinition* index);
597     bool getElemTryTypedArray(bool* emitted, MDefinition* obj, MDefinition* index);
598     bool getElemTryTypedObject(bool* emitted, MDefinition* obj, MDefinition* index);
599     bool getElemTryString(bool* emitted, MDefinition* obj, MDefinition* index);
600     bool getElemTryArguments(bool* emitted, MDefinition* obj, MDefinition* index);
601     bool getElemTryArgumentsInlined(bool* emitted, MDefinition* obj, MDefinition* index);
602     bool getElemTryCache(bool* emitted, MDefinition* obj, MDefinition* index);
603     bool getElemTryScalarElemOfTypedObject(bool* emitted,
604                                            MDefinition* obj,
605                                            MDefinition* index,
606                                            TypedObjectPrediction objTypeReprs,
607                                            TypedObjectPrediction elemTypeReprs,
608                                            int32_t elemSize);
609     bool getElemTryReferenceElemOfTypedObject(bool* emitted,
610                                               MDefinition* obj,
611                                               MDefinition* index,
612                                               TypedObjectPrediction objPrediction,
613                                               TypedObjectPrediction elemPrediction);
614     bool getElemTryComplexElemOfTypedObject(bool* emitted,
615                                             MDefinition* obj,
616                                             MDefinition* index,
617                                             TypedObjectPrediction objTypeReprs,
618                                             TypedObjectPrediction elemTypeReprs,
619                                             int32_t elemSize);
620     TemporaryTypeSet* computeHeapType(const TemporaryTypeSet* objTypes, const jsid id);
621 
622     enum BoundsChecking { DoBoundsCheck, SkipBoundsCheck };
623 
624     // Add instructions to compute a typed array's length and data.  Also
625     // optionally convert |*index| into a bounds-checked definition, if
626     // requested.
627     //
628     // If you only need the array's length, use addTypedArrayLength below.
629     void addTypedArrayLengthAndData(MDefinition* obj,
630                                     BoundsChecking checking,
631                                     MDefinition** index,
632                                     MInstruction** length, MInstruction** elements);
633 
634     // Add an instruction to compute a typed array's length to the current
635     // block.  If you also need the typed array's data, use the above method
636     // instead.
addTypedArrayLength(MDefinition * obj)637     MInstruction* addTypedArrayLength(MDefinition* obj) {
638         MInstruction* length;
639         addTypedArrayLengthAndData(obj, SkipBoundsCheck, nullptr, &length, nullptr);
640         return length;
641     }
642 
643     bool improveThisTypesForCall();
644 
645     MDefinition* getCallee();
646     MDefinition* getAliasedVar(ScopeCoordinate sc);
647     MDefinition* addLexicalCheck(MDefinition* input);
648 
649     bool tryFoldInstanceOf(MDefinition* lhs, JSObject* protoObject);
650     bool hasOnProtoChain(TypeSet::ObjectKey* key, JSObject* protoObject, bool* hasOnProto);
651 
652     bool jsop_add(MDefinition* left, MDefinition* right);
653     bool jsop_bitnot();
654     bool jsop_bitop(JSOp op);
655     bool jsop_binary_arith(JSOp op);
656     bool jsop_binary_arith(JSOp op, MDefinition* left, MDefinition* right);
657     bool jsop_pow();
658     bool jsop_pos();
659     bool jsop_neg();
660     bool jsop_tostring();
661     bool jsop_setarg(uint32_t arg);
662     bool jsop_defvar(uint32_t index);
663     bool jsop_deflexical(uint32_t index);
664     bool jsop_deffun(uint32_t index);
665     bool jsop_notearg();
666     bool jsop_throwsetconst();
667     bool jsop_checklexical();
668     bool jsop_checkaliasedlet(ScopeCoordinate sc);
669     bool jsop_funcall(uint32_t argc);
670     bool jsop_funapply(uint32_t argc);
671     bool jsop_funapplyarguments(uint32_t argc);
672     bool jsop_funapplyarray(uint32_t argc);
673     bool jsop_call(uint32_t argc, bool constructing);
674     bool jsop_eval(uint32_t argc);
675     bool jsop_ifeq(JSOp op);
676     bool jsop_try();
677     bool jsop_label();
678     bool jsop_condswitch();
679     bool jsop_andor(JSOp op);
680     bool jsop_dup2();
681     bool jsop_loophead(jsbytecode* pc);
682     bool jsop_compare(JSOp op);
683     bool jsop_compare(JSOp op, MDefinition* left, MDefinition* right);
684     bool getStaticName(JSObject* staticObject, PropertyName* name, bool* psucceeded,
685                        MDefinition* lexicalCheck = nullptr);
686     bool setStaticName(JSObject* staticObject, PropertyName* name);
687     bool jsop_getgname(PropertyName* name);
688     bool jsop_getname(PropertyName* name);
689     bool jsop_intrinsic(PropertyName* name);
690     bool jsop_getimport(PropertyName* name);
691     bool jsop_bindname(PropertyName* name);
692     bool jsop_getelem();
693     bool jsop_getelem_dense(MDefinition* obj, MDefinition* index, JSValueType unboxedType);
694     bool jsop_getelem_typed(MDefinition* obj, MDefinition* index, ScalarTypeDescr::Type arrayType);
695     bool jsop_setelem();
696     bool jsop_setelem_dense(TemporaryTypeSet::DoubleConversion conversion,
697                             MDefinition* object, MDefinition* index, MDefinition* value,
698                             JSValueType unboxedType, bool writeHole);
699     bool jsop_setelem_typed(ScalarTypeDescr::Type arrayType,
700                             MDefinition* object, MDefinition* index, MDefinition* value);
701     bool jsop_length();
702     bool jsop_length_fastPath();
703     bool jsop_arguments();
704     bool jsop_arguments_getelem();
705     bool jsop_runonce();
706     bool jsop_rest();
707     bool jsop_not();
708     bool jsop_getprop(PropertyName* name);
709     bool jsop_setprop(PropertyName* name);
710     bool jsop_delprop(PropertyName* name);
711     bool jsop_delelem();
712     bool jsop_newarray(uint32_t length);
713     bool jsop_newarray_copyonwrite();
714     bool jsop_newobject();
715     bool jsop_initelem();
716     bool jsop_initelem_array();
717     bool jsop_initelem_getter_setter();
718     bool jsop_mutateproto();
719     bool jsop_initprop(PropertyName* name);
720     bool jsop_initprop_getter_setter(PropertyName* name);
721     bool jsop_regexp(RegExpObject* reobj);
722     bool jsop_object(JSObject* obj);
723     bool jsop_lambda(JSFunction* fun);
724     bool jsop_lambda_arrow(JSFunction* fun);
725     bool jsop_functionthis();
726     bool jsop_globalthis();
727     bool jsop_typeof();
728     bool jsop_toid();
729     bool jsop_iter(uint8_t flags);
730     bool jsop_itermore();
731     bool jsop_isnoiter();
732     bool jsop_iterend();
733     bool jsop_in();
734     bool jsop_in_dense(MDefinition* obj, MDefinition* id, JSValueType unboxedType);
735     bool jsop_instanceof();
736     bool jsop_getaliasedvar(ScopeCoordinate sc);
737     bool jsop_setaliasedvar(ScopeCoordinate sc);
738     bool jsop_debugger();
739     bool jsop_newtarget();
740     bool jsop_checkobjcoercible();
741 
742     /* Inlining. */
743 
744     enum InliningStatus
745     {
746         InliningStatus_Error,
747         InliningStatus_NotInlined,
748         InliningStatus_WarmUpCountTooLow,
749         InliningStatus_Inlined
750     };
751 
752     enum InliningDecision
753     {
754         InliningDecision_Error,
755         InliningDecision_Inline,
756         InliningDecision_DontInline,
757         InliningDecision_WarmUpCountTooLow
758     };
759 
760     static InliningDecision DontInline(JSScript* targetScript, const char* reason);
761 
762     // Helper function for canInlineTarget
763     bool hasCommonInliningPath(const JSScript* scriptToInline);
764 
765     // Oracles.
766     InliningDecision canInlineTarget(JSFunction* target, CallInfo& callInfo);
767     InliningDecision makeInliningDecision(JSObject* target, CallInfo& callInfo);
768     bool selectInliningTargets(const ObjectVector& targets, CallInfo& callInfo,
769                                BoolVector& choiceSet, uint32_t* numInlineable);
770 
771     // Native inlining helpers.
772     // The typeset for the return value of our function.  These are
773     // the types it's been observed returning in the past.
774     TemporaryTypeSet* getInlineReturnTypeSet();
775     // The known MIR type of getInlineReturnTypeSet.
776     MIRType getInlineReturnType();
777 
778     // Array natives.
779     InliningStatus inlineArray(CallInfo& callInfo);
780     InliningStatus inlineArrayIsArray(CallInfo& callInfo);
781     InliningStatus inlineArrayPopShift(CallInfo& callInfo, MArrayPopShift::Mode mode);
782     InliningStatus inlineArrayPush(CallInfo& callInfo);
783     InliningStatus inlineArrayConcat(CallInfo& callInfo);
784     InliningStatus inlineArraySlice(CallInfo& callInfo);
785     InliningStatus inlineArrayJoin(CallInfo& callInfo);
786     InliningStatus inlineArraySplice(CallInfo& callInfo);
787 
788     // Math natives.
789     InliningStatus inlineMathAbs(CallInfo& callInfo);
790     InliningStatus inlineMathFloor(CallInfo& callInfo);
791     InliningStatus inlineMathCeil(CallInfo& callInfo);
792     InliningStatus inlineMathClz32(CallInfo& callInfo);
793     InliningStatus inlineMathRound(CallInfo& callInfo);
794     InliningStatus inlineMathSqrt(CallInfo& callInfo);
795     InliningStatus inlineMathAtan2(CallInfo& callInfo);
796     InliningStatus inlineMathHypot(CallInfo& callInfo);
797     InliningStatus inlineMathMinMax(CallInfo& callInfo, bool max);
798     InliningStatus inlineMathPow(CallInfo& callInfo);
799     InliningStatus inlineMathPowHelper(MDefinition* lhs, MDefinition* rhs, MIRType outputType);
800     InliningStatus inlineMathRandom(CallInfo& callInfo);
801     InliningStatus inlineMathImul(CallInfo& callInfo);
802     InliningStatus inlineMathFRound(CallInfo& callInfo);
803     InliningStatus inlineMathFunction(CallInfo& callInfo, MMathFunction::Function function);
804 
805     // String natives.
806     InliningStatus inlineStringObject(CallInfo& callInfo);
807     InliningStatus inlineConstantStringSplit(CallInfo& callInfo);
808     InliningStatus inlineStringSplit(CallInfo& callInfo);
809     InliningStatus inlineStrCharCodeAt(CallInfo& callInfo);
810     InliningStatus inlineConstantCharCodeAt(CallInfo& callInfo);
811     InliningStatus inlineStrFromCharCode(CallInfo& callInfo);
812     InliningStatus inlineStrCharAt(CallInfo& callInfo);
813     InliningStatus inlineStrReplace(CallInfo& callInfo);
814 
815     // RegExp natives.
816     InliningStatus inlineRegExpExec(CallInfo& callInfo);
817     InliningStatus inlineRegExpTest(CallInfo& callInfo);
818 
819     // Object natives and intrinsics.
820     InliningStatus inlineObjectCreate(CallInfo& callInfo);
821     InliningStatus inlineDefineDataProperty(CallInfo& callInfo);
822 
823     // Atomics natives.
824     InliningStatus inlineAtomicsCompareExchange(CallInfo& callInfo);
825     InliningStatus inlineAtomicsExchange(CallInfo& callInfo);
826     InliningStatus inlineAtomicsLoad(CallInfo& callInfo);
827     InliningStatus inlineAtomicsStore(CallInfo& callInfo);
828     InliningStatus inlineAtomicsFence(CallInfo& callInfo);
829     InliningStatus inlineAtomicsBinop(CallInfo& callInfo, InlinableNative target);
830     InliningStatus inlineAtomicsIsLockFree(CallInfo& callInfo);
831 
832     // Slot intrinsics.
833     InliningStatus inlineUnsafeSetReservedSlot(CallInfo& callInfo);
834     InliningStatus inlineUnsafeGetReservedSlot(CallInfo& callInfo,
835                                                MIRType knownValueType);
836 
837     // TypedArray intrinsics.
838     enum WrappingBehavior { AllowWrappedTypedArrays, RejectWrappedTypedArrays };
839     InliningStatus inlineIsTypedArrayHelper(CallInfo& callInfo, WrappingBehavior wrappingBehavior);
840     InliningStatus inlineIsTypedArray(CallInfo& callInfo);
841     InliningStatus inlineIsPossiblyWrappedTypedArray(CallInfo& callInfo);
842     InliningStatus inlineTypedArrayLength(CallInfo& callInfo);
843     InliningStatus inlineSetDisjointTypedElements(CallInfo& callInfo);
844 
845     // TypedObject intrinsics and natives.
846     InliningStatus inlineObjectIsTypeDescr(CallInfo& callInfo);
847     InliningStatus inlineSetTypedObjectOffset(CallInfo& callInfo);
848     InliningStatus inlineConstructTypedObject(CallInfo& callInfo, TypeDescr* target);
849 
850     // SIMD intrinsics and natives.
851     InliningStatus inlineConstructSimdObject(CallInfo& callInfo, SimdTypeDescr* target);
852 
853     //  helpers
854     static MIRType SimdTypeDescrToMIRType(SimdTypeDescr::Type type);
855     bool checkInlineSimd(CallInfo& callInfo, JSNative native, SimdTypeDescr::Type type,
856                          unsigned numArgs, InlineTypedObject** templateObj);
857     IonBuilder::InliningStatus boxSimd(CallInfo& callInfo, MInstruction* ins,
858                                        InlineTypedObject* templateObj);
859 
860     InliningStatus inlineSimdInt32x4(CallInfo& callInfo, JSNative native);
861     InliningStatus inlineSimdFloat32x4(CallInfo& callInfo, JSNative native);
862 
863     template <typename T>
864     InliningStatus inlineBinarySimd(CallInfo& callInfo, JSNative native,
865                                     typename T::Operation op, SimdTypeDescr::Type type);
866     InliningStatus inlineCompSimd(CallInfo& callInfo, JSNative native,
867                                   MSimdBinaryComp::Operation op, SimdTypeDescr::Type compType);
868     InliningStatus inlineUnarySimd(CallInfo& callInfo, JSNative native,
869                                    MSimdUnaryArith::Operation op, SimdTypeDescr::Type type);
870     InliningStatus inlineSimdExtractLane(CallInfo& callInfo, JSNative native,
871                                          SimdTypeDescr::Type type);
872     InliningStatus inlineSimdReplaceLane(CallInfo& callInfo, JSNative native,
873                                          SimdTypeDescr::Type type);
874     InliningStatus inlineSimdSplat(CallInfo& callInfo, JSNative native, SimdTypeDescr::Type type);
875     InliningStatus inlineSimdShuffle(CallInfo& callInfo, JSNative native, SimdTypeDescr::Type type,
876                                      unsigned numVectors, unsigned numLanes);
877     InliningStatus inlineSimdCheck(CallInfo& callInfo, JSNative native, SimdTypeDescr::Type type);
878     InliningStatus inlineSimdConvert(CallInfo& callInfo, JSNative native, bool isCast,
879                                      SimdTypeDescr::Type from, SimdTypeDescr::Type to);
880     InliningStatus inlineSimdSelect(CallInfo& callInfo, JSNative native, bool isElementWise,
881                                     SimdTypeDescr::Type type);
882 
883     bool prepareForSimdLoadStore(CallInfo& callInfo, Scalar::Type simdType, MInstruction** elements,
884                                  MDefinition** index, Scalar::Type* arrayType);
885     InliningStatus inlineSimdLoad(CallInfo& callInfo, JSNative native, SimdTypeDescr::Type type,
886                                   unsigned numElems);
887     InliningStatus inlineSimdStore(CallInfo& callInfo, JSNative native, SimdTypeDescr::Type type,
888                                    unsigned numElems);
889 
890     // Utility intrinsics.
891     InliningStatus inlineIsCallable(CallInfo& callInfo);
892     InliningStatus inlineIsObject(CallInfo& callInfo);
893     InliningStatus inlineToObject(CallInfo& callInfo);
894     InliningStatus inlineToInteger(CallInfo& callInfo);
895     InliningStatus inlineToString(CallInfo& callInfo);
896     InliningStatus inlineDump(CallInfo& callInfo);
897     InliningStatus inlineHasClass(CallInfo& callInfo, const Class* clasp,
898                                   const Class* clasp2 = nullptr,
899                                   const Class* clasp3 = nullptr,
900                                   const Class* clasp4 = nullptr);
901     InliningStatus inlineIsConstructing(CallInfo& callInfo);
902     InliningStatus inlineSubstringKernel(CallInfo& callInfo);
903 
904     // Testing functions.
905     InliningStatus inlineBailout(CallInfo& callInfo);
906     InliningStatus inlineAssertFloat32(CallInfo& callInfo);
907     InliningStatus inlineAssertRecoveredOnBailout(CallInfo& callInfo);
908 
909     // Bind function.
910     InliningStatus inlineBoundFunction(CallInfo& callInfo, JSFunction* target);
911 
912     // Main inlining functions
913     InliningStatus inlineNativeCall(CallInfo& callInfo, JSFunction* target);
914     InliningStatus inlineNativeGetter(CallInfo& callInfo, JSFunction* target);
915     InliningStatus inlineNonFunctionCall(CallInfo& callInfo, JSObject* target);
916     bool inlineScriptedCall(CallInfo& callInfo, JSFunction* target);
917     InliningStatus inlineSingleCall(CallInfo& callInfo, JSObject* target);
918 
919     // Call functions
920     InliningStatus inlineCallsite(const ObjectVector& targets, CallInfo& callInfo);
921     bool inlineCalls(CallInfo& callInfo, const ObjectVector& targets, BoolVector& choiceSet,
922                      MGetPropertyCache* maybeCache);
923 
924     // Inlining helpers.
925     bool inlineGenericFallback(JSFunction* target, CallInfo& callInfo, MBasicBlock* dispatchBlock);
926     bool inlineObjectGroupFallback(CallInfo& callInfo, MBasicBlock* dispatchBlock,
927                                    MObjectGroupDispatch* dispatch, MGetPropertyCache* cache,
928                                    MBasicBlock** fallbackTarget);
929 
930     enum AtomicCheckResult {
931         DontCheckAtomicResult,
932         DoCheckAtomicResult
933     };
934 
935     bool atomicsMeetsPreconditions(CallInfo& callInfo, Scalar::Type* arrayElementType,
936                                    bool* requiresDynamicCheck,
937                                    AtomicCheckResult checkResult=DoCheckAtomicResult);
938     void atomicsCheckBounds(CallInfo& callInfo, MInstruction** elements, MDefinition** index);
939 
940     bool testNeedsArgumentCheck(JSFunction* target, CallInfo& callInfo);
941 
942     MCall* makeCallHelper(JSFunction* target, CallInfo& callInfo);
943     bool makeCall(JSFunction* target, CallInfo& callInfo);
944 
945     MDefinition* patchInlinedReturn(CallInfo& callInfo, MBasicBlock* exit, MBasicBlock* bottom);
946     MDefinition* patchInlinedReturns(CallInfo& callInfo, MIRGraphReturns& returns,
947                                      MBasicBlock* bottom);
948     MDefinition* specializeInlinedReturn(MDefinition* rdef, MBasicBlock* exit);
949 
950     bool objectsHaveCommonPrototype(TemporaryTypeSet* types, PropertyName* name,
951                                     bool isGetter, JSObject* foundProto, bool* guardGlobal);
952     void freezePropertiesForCommonPrototype(TemporaryTypeSet* types, PropertyName* name,
953                                             JSObject* foundProto, bool allowEmptyTypesForGlobal = false);
954     /*
955      * Callers must pass a non-null globalGuard if they pass a non-null globalShape.
956      */
957     bool testCommonGetterSetter(TemporaryTypeSet* types, PropertyName* name,
958                                 bool isGetter, JSObject* foundProto, Shape* lastProperty,
959                                 JSFunction* getterOrSetter,
960                                 MDefinition** guard, Shape* globalShape = nullptr,
961                                 MDefinition** globalGuard = nullptr);
962     bool testShouldDOMCall(TypeSet* inTypes,
963                            JSFunction* func, JSJitInfo::OpType opType);
964 
965     MDefinition*
966     addShapeGuardsForGetterSetter(MDefinition* obj, JSObject* holder, Shape* holderShape,
967                                   const BaselineInspector::ReceiverVector& receivers,
968                                   const BaselineInspector::ObjectGroupVector& convertUnboxedGroups,
969                                   bool isOwnProperty);
970 
971     bool annotateGetPropertyCache(MDefinition* obj, PropertyName* name,
972                                   MGetPropertyCache* getPropCache, TemporaryTypeSet* objTypes,
973                                   TemporaryTypeSet* pushedTypes);
974 
975     MGetPropertyCache* getInlineableGetPropertyCache(CallInfo& callInfo);
976 
977     JSObject* testGlobalLexicalBinding(PropertyName* name);
978 
979     JSObject* testSingletonProperty(JSObject* obj, jsid id);
980     JSObject* testSingletonPropertyTypes(MDefinition* obj, jsid id);
981 
982     uint32_t getDefiniteSlot(TemporaryTypeSet* types, PropertyName* name, uint32_t* pnfixed);
983     MDefinition* convertUnboxedObjects(MDefinition* obj);
984     MDefinition* convertUnboxedObjects(MDefinition* obj,
985                                        const BaselineInspector::ObjectGroupVector& list);
986     uint32_t getUnboxedOffset(TemporaryTypeSet* types, PropertyName* name,
987                               JSValueType* punboxedType);
988     MInstruction* loadUnboxedProperty(MDefinition* obj, size_t offset, JSValueType unboxedType,
989                                       BarrierKind barrier, TemporaryTypeSet* types);
990     MInstruction* loadUnboxedValue(MDefinition* elements, size_t elementsOffset,
991                                    MDefinition* scaledOffset, JSValueType unboxedType,
992                                    BarrierKind barrier, TemporaryTypeSet* types);
993     MInstruction* storeUnboxedProperty(MDefinition* obj, size_t offset, JSValueType unboxedType,
994                                        MDefinition* value);
995     MInstruction* storeUnboxedValue(MDefinition* obj,
996                                     MDefinition* elements, int32_t elementsOffset,
997                                     MDefinition* scaledOffset, JSValueType unboxedType,
998                                     MDefinition* value, bool preBarrier = true);
999     bool checkPreliminaryGroups(MDefinition *obj);
1000     bool freezePropTypeSets(TemporaryTypeSet* types,
1001                             JSObject* foundProto, PropertyName* name);
1002     bool canInlinePropertyOpShapes(const BaselineInspector::ReceiverVector& receivers);
1003 
1004     TemporaryTypeSet* bytecodeTypes(jsbytecode* pc);
1005 
1006     // Use one of the below methods for updating the current block, rather than
1007     // updating |current| directly. setCurrent() should only be used in cases
1008     // where the block cannot have phis whose type needs to be computed.
1009 
setCurrentAndSpecializePhis(MBasicBlock * block)1010     bool setCurrentAndSpecializePhis(MBasicBlock* block) {
1011         if (block) {
1012             if (!block->specializePhis())
1013                 return false;
1014         }
1015         setCurrent(block);
1016         return true;
1017     }
1018 
setCurrent(MBasicBlock * block)1019     void setCurrent(MBasicBlock* block) {
1020         current = block;
1021     }
1022 
1023     // A builder is inextricably tied to a particular script.
1024     JSScript* script_;
1025 
1026     // script->hasIonScript() at the start of the compilation. Used to avoid
1027     // calling hasIonScript() from background compilation threads.
1028     bool scriptHasIonScript_;
1029 
1030     // If off thread compilation is successful, the final code generator is
1031     // attached here. Code has been generated, but not linked (there is not yet
1032     // an IonScript). This is heap allocated, and must be explicitly destroyed,
1033     // performed by FinishOffThreadBuilder().
1034     CodeGenerator* backgroundCodegen_;
1035 
1036     // Some aborts are actionable (e.g., using an unsupported bytecode). When
1037     // optimization tracking is enabled, the location and message of the abort
1038     // are recorded here so they may be propagated to the script's
1039     // corresponding JitcodeGlobalEntry::BaselineEntry.
1040     JSScript* actionableAbortScript_;
1041     jsbytecode* actionableAbortPc_;
1042     const char* actionableAbortMessage_;
1043 
1044     MRootList* rootList_;
1045 
1046   public:
setRootList(MRootList & rootList)1047     void setRootList(MRootList& rootList) {
1048         MOZ_ASSERT(!rootList_);
1049         rootList_ = &rootList;
1050     }
1051     void clearForBackEnd();
1052     JSObject* checkNurseryObject(JSObject* obj);
1053 
script()1054     JSScript* script() const { return script_; }
scriptHasIonScript()1055     bool scriptHasIonScript() const { return scriptHasIonScript_; }
1056 
backgroundCodegen()1057     CodeGenerator* backgroundCodegen() const { return backgroundCodegen_; }
setBackgroundCodegen(CodeGenerator * codegen)1058     void setBackgroundCodegen(CodeGenerator* codegen) { backgroundCodegen_ = codegen; }
1059 
constraints()1060     CompilerConstraintList* constraints() {
1061         return constraints_;
1062     }
1063 
isInlineBuilder()1064     bool isInlineBuilder() const {
1065         return callerBuilder_ != nullptr;
1066     }
1067 
names()1068     const JSAtomState& names() { return compartment->runtime()->names(); }
1069 
hadActionableAbort()1070     bool hadActionableAbort() const {
1071         MOZ_ASSERT(!actionableAbortScript_ ||
1072                    (actionableAbortPc_ && actionableAbortMessage_));
1073         return actionableAbortScript_ != nullptr;
1074     }
1075 
actionableAbortLocationAndMessage(JSScript ** abortScript,jsbytecode ** abortPc,const char ** abortMessage)1076     void actionableAbortLocationAndMessage(JSScript** abortScript, jsbytecode** abortPc,
1077                                            const char** abortMessage)
1078     {
1079         MOZ_ASSERT(hadActionableAbort());
1080         *abortScript = actionableAbortScript_;
1081         *abortPc = actionableAbortPc_;
1082         *abortMessage = actionableAbortMessage_;
1083     }
1084 
1085     void trace(JSTracer* trc);
1086 
1087   private:
1088     bool init();
1089 
1090     JSContext* analysisContext;
1091     BaselineFrameInspector* baselineFrame_;
1092 
1093     // Constraints for recording dependencies on type information.
1094     CompilerConstraintList* constraints_;
1095 
1096     // Basic analysis information about the script.
1097     BytecodeAnalysis analysis_;
analysis()1098     BytecodeAnalysis& analysis() {
1099         return analysis_;
1100     }
1101 
1102     TemporaryTypeSet* thisTypes;
1103     TemporaryTypeSet* argTypes;
1104     TemporaryTypeSet* typeArray;
1105     uint32_t typeArrayHint;
1106     uint32_t* bytecodeTypeMap;
1107 
1108     GSNCache gsn;
1109     ScopeCoordinateNameCache scopeCoordinateNameCache;
1110 
1111     jsbytecode* pc;
1112     MBasicBlock* current;
1113     uint32_t loopDepth_;
1114 
1115     Vector<BytecodeSite*, 0, JitAllocPolicy> trackedOptimizationSites_;
1116 
bytecodeSite(jsbytecode * pc)1117     BytecodeSite* bytecodeSite(jsbytecode* pc) {
1118         MOZ_ASSERT(info().inlineScriptTree()->script()->containsPC(pc));
1119         // See comment in maybeTrackedOptimizationSite.
1120         if (isOptimizationTrackingEnabled()) {
1121             if (BytecodeSite* site = maybeTrackedOptimizationSite(pc))
1122                 return site;
1123         }
1124         return new(alloc()) BytecodeSite(info().inlineScriptTree(), pc);
1125     }
1126 
1127     BytecodeSite* maybeTrackedOptimizationSite(jsbytecode* pc);
1128 
1129     MDefinition* lexicalCheck_;
1130 
setLexicalCheck(MDefinition * lexical)1131     void setLexicalCheck(MDefinition* lexical) {
1132         MOZ_ASSERT(!lexicalCheck_);
1133         lexicalCheck_ = lexical;
1134     }
takeLexicalCheck()1135     MDefinition* takeLexicalCheck() {
1136         MDefinition* lexical = lexicalCheck_;
1137         lexicalCheck_ = nullptr;
1138         return lexical;
1139     }
1140 
1141     /* Information used for inline-call builders. */
1142     MResumePoint* callerResumePoint_;
callerPC()1143     jsbytecode* callerPC() {
1144         return callerResumePoint_ ? callerResumePoint_->pc() : nullptr;
1145     }
1146     IonBuilder* callerBuilder_;
1147 
1148     IonBuilder* outermostBuilder();
1149 
oom()1150     bool oom() {
1151         abortReason_ = AbortReason_Alloc;
1152         return false;
1153     }
1154 
1155     struct LoopHeader {
1156         jsbytecode* pc;
1157         MBasicBlock* header;
1158 
LoopHeaderLoopHeader1159         LoopHeader(jsbytecode* pc, MBasicBlock* header)
1160           : pc(pc), header(header)
1161         {}
1162     };
1163 
1164     Vector<CFGState, 8, JitAllocPolicy> cfgStack_;
1165     Vector<ControlFlowInfo, 4, JitAllocPolicy> loops_;
1166     Vector<ControlFlowInfo, 0, JitAllocPolicy> switches_;
1167     Vector<ControlFlowInfo, 2, JitAllocPolicy> labels_;
1168     Vector<MInstruction*, 2, JitAllocPolicy> iterators_;
1169     Vector<LoopHeader, 0, JitAllocPolicy> loopHeaders_;
1170     BaselineInspector* inspector;
1171 
1172     size_t inliningDepth_;
1173 
1174     // Total bytecode length of all inlined scripts. Only tracked for the
1175     // outermost builder.
1176     size_t inlinedBytecodeLength_;
1177 
1178     // Cutoff to disable compilation if excessive time is spent reanalyzing
1179     // loop bodies to compute a fixpoint of the types for loop variables.
1180     static const size_t MAX_LOOP_RESTARTS = 40;
1181     size_t numLoopRestarts_;
1182 
1183     // True if script->failedBoundsCheck is set for the current script or
1184     // an outer script.
1185     bool failedBoundsCheck_;
1186 
1187     // True if script->failedShapeGuard is set for the current script or
1188     // an outer script.
1189     bool failedShapeGuard_;
1190 
1191     // True if script->failedLexicalCheck_ is set for the current script or
1192     // an outer script.
1193     bool failedLexicalCheck_;
1194 
1195     // Has an iterator other than 'for in'.
1196     bool nonStringIteration_;
1197 
1198     // If this script can use a lazy arguments object, it will be pre-created
1199     // here.
1200     MInstruction* lazyArguments_;
1201 
1202     // If this is an inline builder, the call info for the builder.
1203     const CallInfo* inlineCallInfo_;
1204 
1205     // When compiling a call with multiple targets, we are first creating a
1206     // MGetPropertyCache.  This MGetPropertyCache is following the bytecode, and
1207     // is used to recover the JSFunction.  In some cases, the Type of the object
1208     // which own the property is enough for dispatching to the right function.
1209     // In such cases we do not have read the property, except when the type
1210     // object is unknown.
1211     //
1212     // As an optimization, we can dispatch a call based on the object group,
1213     // without doing the MGetPropertyCache.  This is what is achieved by
1214     // |IonBuilder::inlineCalls|.  As we might not know all the functions, we
1215     // are adding a fallback path, where this MGetPropertyCache would be moved
1216     // into.
1217     //
1218     // In order to build the fallback path, we have to capture a resume point
1219     // ahead, for the potential fallback path.  This resume point is captured
1220     // while building MGetPropertyCache.  It is capturing the state of Baseline
1221     // before the execution of the MGetPropertyCache, such as we can safely do
1222     // it in the fallback path.
1223     //
1224     // This field is used to discard the resume point if it is not used for
1225     // building a fallback path.
1226 
1227     // Discard the prior resume point while setting a new MGetPropertyCache.
1228     void replaceMaybeFallbackFunctionGetter(MGetPropertyCache* cache);
1229 
1230     // Discard the MGetPropertyCache if it is handled by WrapMGetPropertyCache.
keepFallbackFunctionGetter(MGetPropertyCache * cache)1231     void keepFallbackFunctionGetter(MGetPropertyCache* cache) {
1232         if (cache == maybeFallbackFunctionGetter_)
1233             maybeFallbackFunctionGetter_ = nullptr;
1234     }
1235 
1236     MGetPropertyCache* maybeFallbackFunctionGetter_;
1237 
1238     // Used in tracking outcomes of optimization strategies for devtools.
1239     void startTrackingOptimizations();
1240 
1241     // The track* methods below are called often. Do not combine them with the
1242     // unchecked variants, despite the unchecked variants having no other
1243     // callers.
trackTypeInfo(JS::TrackedTypeSite site,MIRType mirType,TemporaryTypeSet * typeSet)1244     void trackTypeInfo(JS::TrackedTypeSite site, MIRType mirType,
1245                        TemporaryTypeSet* typeSet)
1246     {
1247         if (MOZ_UNLIKELY(current->trackedSite()->hasOptimizations()))
1248             trackTypeInfoUnchecked(site, mirType, typeSet);
1249     }
trackTypeInfo(JS::TrackedTypeSite site,JSObject * obj)1250     void trackTypeInfo(JS::TrackedTypeSite site, JSObject* obj) {
1251         if (MOZ_UNLIKELY(current->trackedSite()->hasOptimizations()))
1252             trackTypeInfoUnchecked(site, obj);
1253     }
trackTypeInfo(CallInfo & callInfo)1254     void trackTypeInfo(CallInfo& callInfo) {
1255         if (MOZ_UNLIKELY(current->trackedSite()->hasOptimizations()))
1256             trackTypeInfoUnchecked(callInfo);
1257     }
trackOptimizationAttempt(JS::TrackedStrategy strategy)1258     void trackOptimizationAttempt(JS::TrackedStrategy strategy) {
1259         if (MOZ_UNLIKELY(current->trackedSite()->hasOptimizations()))
1260             trackOptimizationAttemptUnchecked(strategy);
1261     }
amendOptimizationAttempt(uint32_t index)1262     void amendOptimizationAttempt(uint32_t index) {
1263         if (MOZ_UNLIKELY(current->trackedSite()->hasOptimizations()))
1264             amendOptimizationAttemptUnchecked(index);
1265     }
trackOptimizationOutcome(JS::TrackedOutcome outcome)1266     void trackOptimizationOutcome(JS::TrackedOutcome outcome) {
1267         if (MOZ_UNLIKELY(current->trackedSite()->hasOptimizations()))
1268             trackOptimizationOutcomeUnchecked(outcome);
1269     }
trackOptimizationSuccess()1270     void trackOptimizationSuccess() {
1271         if (MOZ_UNLIKELY(current->trackedSite()->hasOptimizations()))
1272             trackOptimizationSuccessUnchecked();
1273     }
1274     void trackInlineSuccess(InliningStatus status = InliningStatus_Inlined) {
1275         if (MOZ_UNLIKELY(current->trackedSite()->hasOptimizations()))
1276             trackInlineSuccessUnchecked(status);
1277     }
1278 
forceInlineCaches()1279     bool forceInlineCaches() {
1280         return MOZ_UNLIKELY(JitOptions.forceInlineCaches);
1281     }
1282 
1283     // Out-of-line variants that don't check if optimization tracking is
1284     // enabled.
1285     void trackTypeInfoUnchecked(JS::TrackedTypeSite site, MIRType mirType,
1286                                 TemporaryTypeSet* typeSet);
1287     void trackTypeInfoUnchecked(JS::TrackedTypeSite site, JSObject* obj);
1288     void trackTypeInfoUnchecked(CallInfo& callInfo);
1289     void trackOptimizationAttemptUnchecked(JS::TrackedStrategy strategy);
1290     void amendOptimizationAttemptUnchecked(uint32_t index);
1291     void trackOptimizationOutcomeUnchecked(JS::TrackedOutcome outcome);
1292     void trackOptimizationSuccessUnchecked();
1293     void trackInlineSuccessUnchecked(InliningStatus status);
1294 };
1295 
1296 class CallInfo
1297 {
1298     MDefinition* fun_;
1299     MDefinition* thisArg_;
1300     MDefinition* newTargetArg_;
1301     MDefinitionVector args_;
1302 
1303     bool constructing_;
1304     bool setter_;
1305 
1306   public:
CallInfo(TempAllocator & alloc,bool constructing)1307     CallInfo(TempAllocator& alloc, bool constructing)
1308       : fun_(nullptr),
1309         thisArg_(nullptr),
1310         newTargetArg_(nullptr),
1311         args_(alloc),
1312         constructing_(constructing),
1313         setter_(false)
1314     { }
1315 
init(CallInfo & callInfo)1316     bool init(CallInfo& callInfo) {
1317         MOZ_ASSERT(constructing_ == callInfo.constructing());
1318 
1319         fun_ = callInfo.fun();
1320         thisArg_ = callInfo.thisArg();
1321 
1322         if (constructing())
1323             newTargetArg_ = callInfo.getNewTarget();
1324 
1325         if (!args_.appendAll(callInfo.argv()))
1326             return false;
1327 
1328         return true;
1329     }
1330 
init(MBasicBlock * current,uint32_t argc)1331     bool init(MBasicBlock* current, uint32_t argc) {
1332         MOZ_ASSERT(args_.empty());
1333 
1334         // Get the arguments in the right order
1335         if (!args_.reserve(argc))
1336             return false;
1337 
1338         if (constructing())
1339             setNewTarget(current->pop());
1340 
1341         for (int32_t i = argc; i > 0; i--)
1342             args_.infallibleAppend(current->peek(-i));
1343         current->popn(argc);
1344 
1345         // Get |this| and |fun|
1346         setThis(current->pop());
1347         setFun(current->pop());
1348 
1349         return true;
1350     }
1351 
popFormals(MBasicBlock * current)1352     void popFormals(MBasicBlock* current) {
1353         current->popn(numFormals());
1354     }
1355 
pushFormals(MBasicBlock * current)1356     void pushFormals(MBasicBlock* current) {
1357         current->push(fun());
1358         current->push(thisArg());
1359 
1360         for (uint32_t i = 0; i < argc(); i++)
1361             current->push(getArg(i));
1362 
1363         if (constructing())
1364             current->push(getNewTarget());
1365     }
1366 
argc()1367     uint32_t argc() const {
1368         return args_.length();
1369     }
numFormals()1370     uint32_t numFormals() const {
1371         return argc() + 2 + constructing();
1372     }
1373 
setArgs(const MDefinitionVector & args)1374     bool setArgs(const MDefinitionVector& args) {
1375         MOZ_ASSERT(args_.empty());
1376         return args_.appendAll(args);
1377     }
1378 
argv()1379     MDefinitionVector& argv() {
1380         return args_;
1381     }
1382 
argv()1383     const MDefinitionVector& argv() const {
1384         return args_;
1385     }
1386 
getArg(uint32_t i)1387     MDefinition* getArg(uint32_t i) const {
1388         MOZ_ASSERT(i < argc());
1389         return args_[i];
1390     }
1391 
getArgWithDefault(uint32_t i,MDefinition * defaultValue)1392     MDefinition* getArgWithDefault(uint32_t i, MDefinition* defaultValue) const {
1393         if (i < argc())
1394             return args_[i];
1395 
1396         return defaultValue;
1397     }
1398 
setArg(uint32_t i,MDefinition * def)1399     void setArg(uint32_t i, MDefinition* def) {
1400         MOZ_ASSERT(i < argc());
1401         args_[i] = def;
1402     }
1403 
thisArg()1404     MDefinition* thisArg() const {
1405         MOZ_ASSERT(thisArg_);
1406         return thisArg_;
1407     }
1408 
setThis(MDefinition * thisArg)1409     void setThis(MDefinition* thisArg) {
1410         thisArg_ = thisArg;
1411     }
1412 
constructing()1413     bool constructing() const {
1414         return constructing_;
1415     }
1416 
setNewTarget(MDefinition * newTarget)1417     void setNewTarget(MDefinition* newTarget) {
1418         MOZ_ASSERT(constructing());
1419         newTargetArg_ = newTarget;
1420     }
getNewTarget()1421     MDefinition* getNewTarget() const {
1422         MOZ_ASSERT(newTargetArg_);
1423         return newTargetArg_;
1424     }
1425 
isSetter()1426     bool isSetter() const {
1427         return setter_;
1428     }
markAsSetter()1429     void markAsSetter() {
1430         setter_ = true;
1431     }
1432 
fun()1433     MDefinition* fun() const {
1434         MOZ_ASSERT(fun_);
1435         return fun_;
1436     }
1437 
setFun(MDefinition * fun)1438     void setFun(MDefinition* fun) {
1439         fun_ = fun;
1440     }
1441 
setImplicitlyUsedUnchecked()1442     void setImplicitlyUsedUnchecked() {
1443         fun_->setImplicitlyUsedUnchecked();
1444         thisArg_->setImplicitlyUsedUnchecked();
1445         if (newTargetArg_)
1446             newTargetArg_->setImplicitlyUsedUnchecked();
1447         for (uint32_t i = 0; i < argc(); i++)
1448             getArg(i)->setImplicitlyUsedUnchecked();
1449     }
1450 };
1451 
1452 bool NeedsPostBarrier(MDefinition* value);
1453 
1454 } // namespace jit
1455 } // namespace js
1456 
1457 #endif /* jit_IonBuilder_h */
1458