summaryrefslogtreecommitdiffstats
path: root/js/src/jit/IonBuilder.h
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/jit/IonBuilder.h')
-rw-r--r--js/src/jit/IonBuilder.h1533
1 files changed, 1533 insertions, 0 deletions
diff --git a/js/src/jit/IonBuilder.h b/js/src/jit/IonBuilder.h
new file mode 100644
index 000000000..38647a88f
--- /dev/null
+++ b/js/src/jit/IonBuilder.h
@@ -0,0 +1,1533 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef jit_IonBuilder_h
+#define jit_IonBuilder_h
+
+// This file declares the data structures for building a MIRGraph from a
+// JSScript.
+
+#include "mozilla/LinkedList.h"
+
+#include "jit/BaselineInspector.h"
+#include "jit/BytecodeAnalysis.h"
+#include "jit/IonAnalysis.h"
+#include "jit/IonOptimizationLevels.h"
+#include "jit/MIR.h"
+#include "jit/MIRGenerator.h"
+#include "jit/MIRGraph.h"
+#include "jit/OptimizationTracking.h"
+
+namespace js {
+namespace jit {
+
+class CodeGenerator;
+class CallInfo;
+class BaselineFrameInspector;
+
+enum class InlinableNative : uint16_t;
+
+// Records information about a baseline frame for compilation that is stable
+// when later used off thread.
+BaselineFrameInspector*
+NewBaselineFrameInspector(TempAllocator* temp, BaselineFrame* frame, CompileInfo* info);
+
+class IonBuilder
+ : public MIRGenerator,
+ public mozilla::LinkedListElement<IonBuilder>
+{
+ enum ControlStatus {
+ ControlStatus_Error,
+ ControlStatus_Abort,
+ ControlStatus_Ended, // There is no continuation/join point.
+ ControlStatus_Joined, // Created a join node.
+ ControlStatus_Jumped, // Parsing another branch at the same level.
+ ControlStatus_None // No control flow.
+ };
+
+ struct DeferredEdge : public TempObject
+ {
+ MBasicBlock* block;
+ DeferredEdge* next;
+
+ DeferredEdge(MBasicBlock* block, DeferredEdge* next)
+ : block(block), next(next)
+ { }
+ };
+
+ struct ControlFlowInfo {
+ // Entry in the cfgStack.
+ uint32_t cfgEntry;
+
+ // Label that continues go to.
+ jsbytecode* continuepc;
+
+ ControlFlowInfo(uint32_t cfgEntry, jsbytecode* continuepc)
+ : cfgEntry(cfgEntry),
+ continuepc(continuepc)
+ { }
+ };
+
+ // To avoid recursion, the bytecode analyzer uses a stack where each entry
+ // is a small state machine. As we encounter branches or jumps in the
+ // bytecode, we push information about the edges on the stack so that the
+ // CFG can be built in a tree-like fashion.
+ struct CFGState {
+ enum State {
+ IF_TRUE, // if() { }, no else.
+ IF_TRUE_EMPTY_ELSE, // if() { }, empty else
+ IF_ELSE_TRUE, // if() { X } else { }
+ IF_ELSE_FALSE, // if() { } else { X }
+ DO_WHILE_LOOP_BODY, // do { x } while ()
+ DO_WHILE_LOOP_COND, // do { } while (x)
+ WHILE_LOOP_COND, // while (x) { }
+ WHILE_LOOP_BODY, // while () { x }
+ FOR_LOOP_COND, // for (; x;) { }
+ FOR_LOOP_BODY, // for (; ;) { x }
+ FOR_LOOP_UPDATE, // for (; ; x) { }
+ TABLE_SWITCH, // switch() { x }
+ COND_SWITCH_CASE, // switch() { case X: ... }
+ COND_SWITCH_BODY, // switch() { case ...: X }
+ AND_OR, // && x, || x
+ LABEL, // label: x
+ TRY // try { x } catch(e) { }
+ };
+
+ State state; // Current state of this control structure.
+ jsbytecode* stopAt; // Bytecode at which to stop the processing loop.
+
+ // For if structures, this contains branch information.
+ union {
+ struct {
+ MBasicBlock* ifFalse;
+ jsbytecode* falseEnd;
+ MBasicBlock* ifTrue; // Set when the end of the true path is reached.
+ MTest* test;
+ } branch;
+ struct {
+ // Common entry point.
+ MBasicBlock* entry;
+
+ // Whether OSR is being performed for this loop.
+ bool osr;
+
+ // Position of where the loop body starts and ends.
+ jsbytecode* bodyStart;
+ jsbytecode* bodyEnd;
+
+ // pc immediately after the loop exits.
+ jsbytecode* exitpc;
+
+ // pc for 'continue' jumps.
+ jsbytecode* continuepc;
+
+ // Common exit point. Created lazily, so it may be nullptr.
+ MBasicBlock* successor;
+
+ // Deferred break and continue targets.
+ DeferredEdge* breaks;
+ DeferredEdge* continues;
+
+ // Initial state, in case loop processing is restarted.
+ State initialState;
+ jsbytecode* initialPc;
+ jsbytecode* initialStopAt;
+ jsbytecode* loopHead;
+
+ // For-loops only.
+ jsbytecode* condpc;
+ jsbytecode* updatepc;
+ jsbytecode* updateEnd;
+ } loop;
+ struct {
+ // pc immediately after the switch.
+ jsbytecode* exitpc;
+
+ // Deferred break and continue targets.
+ DeferredEdge* breaks;
+
+ // MIR instruction
+ MTableSwitch* ins;
+
+ // The number of current successor that get mapped into a block.
+ uint32_t currentBlock;
+
+ } tableswitch;
+ struct {
+ // Vector of body blocks to process after the cases.
+ FixedList<MBasicBlock*>* bodies;
+
+ // When processing case statements, this counter points at the
+ // last uninitialized body. When processing bodies, this
+ // counter targets the next body to process.
+ uint32_t currentIdx;
+
+ // Remember the block index of the default case.
+ jsbytecode* defaultTarget;
+ uint32_t defaultIdx;
+
+ // Block immediately after the switch.
+ jsbytecode* exitpc;
+ DeferredEdge* breaks;
+ } condswitch;
+ struct {
+ DeferredEdge* breaks;
+ } label;
+ struct {
+ MBasicBlock* successor;
+ } try_;
+ };
+
+ inline bool isLoop() const {
+ switch (state) {
+ case DO_WHILE_LOOP_COND:
+ case DO_WHILE_LOOP_BODY:
+ case WHILE_LOOP_COND:
+ case WHILE_LOOP_BODY:
+ case FOR_LOOP_COND:
+ case FOR_LOOP_BODY:
+ case FOR_LOOP_UPDATE:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ static CFGState If(jsbytecode* join, MTest* test);
+ static CFGState IfElse(jsbytecode* trueEnd, jsbytecode* falseEnd, MTest* test);
+ static CFGState AndOr(jsbytecode* join, MBasicBlock* lhs);
+ static CFGState TableSwitch(jsbytecode* exitpc, MTableSwitch* ins);
+ static CFGState CondSwitch(IonBuilder* builder, jsbytecode* exitpc, jsbytecode* defaultTarget);
+ static CFGState Label(jsbytecode* exitpc);
+ static CFGState Try(jsbytecode* exitpc, MBasicBlock* successor);
+ };
+
+ static int CmpSuccessors(const void* a, const void* b);
+
+ public:
+ IonBuilder(JSContext* analysisContext, CompileCompartment* comp,
+ const JitCompileOptions& options, TempAllocator* temp,
+ MIRGraph* graph, CompilerConstraintList* constraints,
+ BaselineInspector* inspector, CompileInfo* info,
+ const OptimizationInfo* optimizationInfo, BaselineFrameInspector* baselineFrame,
+ size_t inliningDepth = 0, uint32_t loopDepth = 0);
+
+ // Callers of build() and buildInline() should always check whether the
+ // call overrecursed, if false is returned. Overrecursion is not
+ // signaled as OOM and will not in general be caught by OOM paths.
+ MOZ_MUST_USE bool build();
+ MOZ_MUST_USE bool buildInline(IonBuilder* callerBuilder, MResumePoint* callerResumePoint,
+ CallInfo& callInfo);
+
+ private:
+ MOZ_MUST_USE bool traverseBytecode();
+ ControlStatus snoopControlFlow(JSOp op);
+ MOZ_MUST_USE bool processIterators();
+ MOZ_MUST_USE bool inspectOpcode(JSOp op);
+ uint32_t readIndex(jsbytecode* pc);
+ JSAtom* readAtom(jsbytecode* pc);
+ bool abort(const char* message, ...) MOZ_FORMAT_PRINTF(2, 3);
+ void trackActionableAbort(const char* message);
+ void spew(const char* message);
+
+ JSFunction* getSingleCallTarget(TemporaryTypeSet* calleeTypes);
+ MOZ_MUST_USE bool getPolyCallTargets(TemporaryTypeSet* calleeTypes, bool constructing,
+ ObjectVector& targets, uint32_t maxTargets);
+
+ void popCfgStack();
+ DeferredEdge* filterDeadDeferredEdges(DeferredEdge* edge);
+ MOZ_MUST_USE bool processDeferredContinues(CFGState& state);
+ ControlStatus processControlEnd();
+ ControlStatus processCfgStack();
+ ControlStatus processCfgEntry(CFGState& state);
+ ControlStatus processIfEnd(CFGState& state);
+ ControlStatus processIfElseTrueEnd(CFGState& state);
+ ControlStatus processIfElseFalseEnd(CFGState& state);
+ ControlStatus processDoWhileBodyEnd(CFGState& state);
+ ControlStatus processDoWhileCondEnd(CFGState& state);
+ ControlStatus processWhileCondEnd(CFGState& state);
+ ControlStatus processWhileBodyEnd(CFGState& state);
+ ControlStatus processForCondEnd(CFGState& state);
+ ControlStatus processForBodyEnd(CFGState& state);
+ ControlStatus processForUpdateEnd(CFGState& state);
+ ControlStatus processNextTableSwitchCase(CFGState& state);
+ ControlStatus processCondSwitchCase(CFGState& state);
+ ControlStatus processCondSwitchBody(CFGState& state);
+ ControlStatus processSwitchBreak(JSOp op);
+ ControlStatus processSwitchEnd(DeferredEdge* breaks, jsbytecode* exitpc);
+ ControlStatus processAndOrEnd(CFGState& state);
+ ControlStatus processLabelEnd(CFGState& state);
+ ControlStatus processTryEnd(CFGState& state);
+ ControlStatus processReturn(JSOp op);
+ ControlStatus processThrow();
+ ControlStatus processContinue(JSOp op);
+ ControlStatus processBreak(JSOp op, jssrcnote* sn);
+ ControlStatus maybeLoop(JSOp op, jssrcnote* sn);
+ MOZ_MUST_USE bool pushLoop(CFGState::State state, jsbytecode* stopAt, MBasicBlock* entry,
+ bool osr, jsbytecode* loopHead, jsbytecode* initialPc,
+ jsbytecode* bodyStart, jsbytecode* bodyEnd,
+ jsbytecode* exitpc, jsbytecode* continuepc);
+ MOZ_MUST_USE bool analyzeNewLoopTypes(MBasicBlock* entry, jsbytecode* start, jsbytecode* end);
+
+ MBasicBlock* addBlock(MBasicBlock* block, uint32_t loopDepth);
+ MBasicBlock* newBlock(MBasicBlock* predecessor, jsbytecode* pc);
+ MBasicBlock* newBlock(MBasicBlock* predecessor, jsbytecode* pc, uint32_t loopDepth);
+ MBasicBlock* newBlock(MBasicBlock* predecessor, jsbytecode* pc, MResumePoint* priorResumePoint);
+ MBasicBlock* newBlockPopN(MBasicBlock* predecessor, jsbytecode* pc, uint32_t popped);
+ MBasicBlock* newBlockAfter(MBasicBlock* at, MBasicBlock* predecessor, jsbytecode* pc);
+ MBasicBlock* newOsrPreheader(MBasicBlock* header, jsbytecode* loopEntry,
+ jsbytecode* beforeLoopEntry);
+ MBasicBlock* newPendingLoopHeader(MBasicBlock* predecessor, jsbytecode* pc, bool osr, bool canOsr,
+ unsigned stackPhiCount);
+ MBasicBlock* newBlock(jsbytecode* pc) {
+ return newBlock(nullptr, pc);
+ }
+ MBasicBlock* newBlockAfter(MBasicBlock* at, jsbytecode* pc) {
+ return newBlockAfter(at, nullptr, pc);
+ }
+
+ // We want to make sure that our MTest instructions all check whether the
+ // thing being tested might emulate undefined. So we funnel their creation
+ // through this method, to make sure that happens. We don't want to just do
+ // the check in MTest::New, because that can run on background compilation
+ // threads, and we're not sure it's safe to touch that part of the typeset
+ // from a background thread.
+ MTest* newTest(MDefinition* ins, MBasicBlock* ifTrue, MBasicBlock* ifFalse);
+
+ // Given a list of pending breaks, creates a new block and inserts a Goto
+ // linking each break to the new block.
+ MBasicBlock* createBreakCatchBlock(DeferredEdge* edge, jsbytecode* pc);
+
+ // Finishes loops that do not actually loop, containing only breaks and
+ // returns or a do while loop with a condition that is constant false.
+ ControlStatus processBrokenLoop(CFGState& state);
+
+ // Computes loop phis, places them in all successors of a loop, then
+ // handles any pending breaks.
+ ControlStatus finishLoop(CFGState& state, MBasicBlock* successor);
+
+ // Incorporates a type/typeSet into an OSR value for a loop, after the loop
+ // body has been processed.
+ MOZ_MUST_USE bool addOsrValueTypeBarrier(uint32_t slot, MInstruction** def,
+ MIRType type, TemporaryTypeSet* typeSet);
+ MOZ_MUST_USE bool maybeAddOsrTypeBarriers();
+
+ // Restarts processing of a loop if the type information at its header was
+ // incomplete.
+ ControlStatus restartLoop(const CFGState& state);
+
+ void assertValidLoopHeadOp(jsbytecode* pc);
+
+ ControlStatus forLoop(JSOp op, jssrcnote* sn);
+ ControlStatus whileOrForInLoop(jssrcnote* sn);
+ ControlStatus doWhileLoop(JSOp op, jssrcnote* sn);
+ ControlStatus tableSwitch(JSOp op, jssrcnote* sn);
+ ControlStatus condSwitch(JSOp op, jssrcnote* sn);
+
+ // Please see the Big Honkin' Comment about how resume points work in
+ // IonBuilder.cpp, near the definition for this function.
+ MOZ_MUST_USE bool resume(MInstruction* ins, jsbytecode* pc, MResumePoint::Mode mode);
+ MOZ_MUST_USE bool resumeAt(MInstruction* ins, jsbytecode* pc);
+ MOZ_MUST_USE bool resumeAfter(MInstruction* ins);
+ MOZ_MUST_USE bool maybeInsertResume();
+
+ void insertRecompileCheck();
+
+ MOZ_MUST_USE bool initParameters();
+ void initLocals();
+ void rewriteParameter(uint32_t slotIdx, MDefinition* param, int32_t argIndex);
+ MOZ_MUST_USE bool rewriteParameters();
+ MOZ_MUST_USE bool initEnvironmentChain(MDefinition* callee = nullptr);
+ MOZ_MUST_USE bool initArgumentsObject();
+ void pushConstant(const Value& v);
+
+ MConstant* constant(const Value& v);
+ MConstant* constantInt(int32_t i);
+ MInstruction* initializedLength(MDefinition* obj, MDefinition* elements,
+ JSValueType unboxedType);
+ MInstruction* setInitializedLength(MDefinition* obj, JSValueType unboxedType, size_t count);
+
+ // Improve the type information at tests
+ MOZ_MUST_USE bool improveTypesAtTest(MDefinition* ins, bool trueBranch, MTest* test);
+ MOZ_MUST_USE bool improveTypesAtCompare(MCompare* ins, bool trueBranch, MTest* test);
+ MOZ_MUST_USE bool improveTypesAtNullOrUndefinedCompare(MCompare* ins, bool trueBranch,
+ MTest* test);
+ MOZ_MUST_USE bool improveTypesAtTypeOfCompare(MCompare* ins, bool trueBranch, MTest* test);
+
+ // Used to detect triangular structure at test.
+ MOZ_MUST_USE bool detectAndOrStructure(MPhi* ins, bool* branchIsTrue);
+ MOZ_MUST_USE bool replaceTypeSet(MDefinition* subject, TemporaryTypeSet* type, MTest* test);
+
+ // Add a guard which ensure that the set of type which goes through this
+ // generated code correspond to the observed types for the bytecode.
+ MDefinition* addTypeBarrier(MDefinition* def, TemporaryTypeSet* observed,
+ BarrierKind kind, MTypeBarrier** pbarrier = nullptr);
+ MOZ_MUST_USE bool pushTypeBarrier(MDefinition* def, TemporaryTypeSet* observed,
+ BarrierKind kind);
+
+ // As pushTypeBarrier, but will compute the needBarrier boolean itself based
+ // on observed and the JSFunction that we're planning to call. The
+ // JSFunction must be a DOM method or getter.
+ MOZ_MUST_USE bool pushDOMTypeBarrier(MInstruction* ins, TemporaryTypeSet* observed,
+ JSFunction* func);
+
+ // If definiteType is not known or def already has the right type, just
+ // returns def. Otherwise, returns an MInstruction that has that definite
+ // type, infallibly unboxing ins as needed. The new instruction will be
+ // added to |current| in this case.
+ MDefinition* ensureDefiniteType(MDefinition* def, MIRType definiteType);
+
+ // Creates a MDefinition based on the given def improved with type as TypeSet.
+ MDefinition* ensureDefiniteTypeSet(MDefinition* def, TemporaryTypeSet* types);
+
+ void maybeMarkEmpty(MDefinition* ins);
+
+ JSObject* getSingletonPrototype(JSFunction* target);
+
+ MDefinition* createThisScripted(MDefinition* callee, MDefinition* newTarget);
+ MDefinition* createThisScriptedSingleton(JSFunction* target, MDefinition* callee);
+ MDefinition* createThisScriptedBaseline(MDefinition* callee);
+ MDefinition* createThis(JSFunction* target, MDefinition* callee, MDefinition* newTarget);
+ MInstruction* createNamedLambdaObject(MDefinition* callee, MDefinition* envObj);
+ MInstruction* createCallObject(MDefinition* callee, MDefinition* envObj);
+
+ MDefinition* walkEnvironmentChain(unsigned hops);
+
+ MInstruction* addConvertElementsToDoubles(MDefinition* elements);
+ MDefinition* addMaybeCopyElementsForWrite(MDefinition* object, bool checkNative);
+ MInstruction* addBoundsCheck(MDefinition* index, MDefinition* length);
+ MInstruction* addShapeGuard(MDefinition* obj, Shape* const shape, BailoutKind bailoutKind);
+ MInstruction* addGroupGuard(MDefinition* obj, ObjectGroup* group, BailoutKind bailoutKind);
+ MInstruction* addUnboxedExpandoGuard(MDefinition* obj, bool hasExpando, BailoutKind bailoutKind);
+ MInstruction* addSharedTypedArrayGuard(MDefinition* obj);
+
+ MInstruction*
+ addGuardReceiverPolymorphic(MDefinition* obj, const BaselineInspector::ReceiverVector& receivers);
+
+ MDefinition* convertShiftToMaskForStaticTypedArray(MDefinition* id,
+ Scalar::Type viewType);
+
+ bool invalidatedIdempotentCache();
+
+ bool hasStaticEnvironmentObject(EnvironmentCoordinate ec, JSObject** pcall);
+ MOZ_MUST_USE bool loadSlot(MDefinition* obj, size_t slot, size_t nfixed, MIRType rvalType,
+ BarrierKind barrier, TemporaryTypeSet* types);
+ MOZ_MUST_USE bool loadSlot(MDefinition* obj, Shape* shape, MIRType rvalType,
+ BarrierKind barrier, TemporaryTypeSet* types);
+ MOZ_MUST_USE bool storeSlot(MDefinition* obj, size_t slot, size_t nfixed, MDefinition* value,
+ bool needsBarrier, MIRType slotType = MIRType::None);
+ MOZ_MUST_USE bool storeSlot(MDefinition* obj, Shape* shape, MDefinition* value,
+ bool needsBarrier, MIRType slotType = MIRType::None);
+ bool shouldAbortOnPreliminaryGroups(MDefinition *obj);
+
+ MDefinition* tryInnerizeWindow(MDefinition* obj);
+ MDefinition* maybeUnboxForPropertyAccess(MDefinition* def);
+
+ // jsop_getprop() helpers.
+ MOZ_MUST_USE bool checkIsDefinitelyOptimizedArguments(MDefinition* obj, bool* isOptimizedArgs);
+ MOZ_MUST_USE bool getPropTryInferredConstant(bool* emitted, MDefinition* obj,
+ PropertyName* name, TemporaryTypeSet* types);
+ MOZ_MUST_USE bool getPropTryArgumentsLength(bool* emitted, MDefinition* obj);
+ MOZ_MUST_USE bool getPropTryArgumentsCallee(bool* emitted, MDefinition* obj,
+ PropertyName* name);
+ MOZ_MUST_USE bool getPropTryConstant(bool* emitted, MDefinition* obj, jsid id,
+ TemporaryTypeSet* types);
+ MOZ_MUST_USE bool getPropTryNotDefined(bool* emitted, MDefinition* obj, jsid id,
+ TemporaryTypeSet* types);
+ MOZ_MUST_USE bool getPropTryDefiniteSlot(bool* emitted, MDefinition* obj, PropertyName* name,
+ BarrierKind barrier, TemporaryTypeSet* types);
+ MOZ_MUST_USE bool getPropTryModuleNamespace(bool* emitted, MDefinition* obj, PropertyName* name,
+ BarrierKind barrier, TemporaryTypeSet* types);
+ MOZ_MUST_USE bool getPropTryUnboxed(bool* emitted, MDefinition* obj, PropertyName* name,
+ BarrierKind barrier, TemporaryTypeSet* types);
+ MOZ_MUST_USE bool getPropTryCommonGetter(bool* emitted, MDefinition* obj, PropertyName* name,
+ TemporaryTypeSet* types);
+ MOZ_MUST_USE bool getPropTryInlineAccess(bool* emitted, MDefinition* obj, PropertyName* name,
+ BarrierKind barrier, TemporaryTypeSet* types);
+ MOZ_MUST_USE bool getPropTryTypedObject(bool* emitted, MDefinition* obj, PropertyName* name);
+ MOZ_MUST_USE bool getPropTryScalarPropOfTypedObject(bool* emitted, MDefinition* typedObj,
+ int32_t fieldOffset,
+ TypedObjectPrediction fieldTypeReprs);
+ MOZ_MUST_USE bool getPropTryReferencePropOfTypedObject(bool* emitted, MDefinition* typedObj,
+ int32_t fieldOffset,
+ TypedObjectPrediction fieldPrediction,
+ PropertyName* name);
+ MOZ_MUST_USE bool getPropTryComplexPropOfTypedObject(bool* emitted, MDefinition* typedObj,
+ int32_t fieldOffset,
+ TypedObjectPrediction fieldTypeReprs,
+ size_t fieldIndex);
+ MOZ_MUST_USE bool getPropTryInnerize(bool* emitted, MDefinition* obj, PropertyName* name,
+ TemporaryTypeSet* types);
+ MOZ_MUST_USE bool getPropTryCache(bool* emitted, MDefinition* obj, PropertyName* name,
+ BarrierKind barrier, TemporaryTypeSet* types);
+ MOZ_MUST_USE bool getPropTrySharedStub(bool* emitted, MDefinition* obj,
+ TemporaryTypeSet* types);
+
+ // jsop_setprop() helpers.
+ MOZ_MUST_USE bool setPropTryCommonSetter(bool* emitted, MDefinition* obj,
+ PropertyName* name, MDefinition* value);
+ MOZ_MUST_USE bool setPropTryCommonDOMSetter(bool* emitted, MDefinition* obj,
+ MDefinition* value, JSFunction* setter,
+ TemporaryTypeSet* objTypes);
+ MOZ_MUST_USE bool setPropTryDefiniteSlot(bool* emitted, MDefinition* obj,
+ PropertyName* name, MDefinition* value,
+ bool barrier, TemporaryTypeSet* objTypes);
+ MOZ_MUST_USE bool setPropTryUnboxed(bool* emitted, MDefinition* obj,
+ PropertyName* name, MDefinition* value,
+ bool barrier, TemporaryTypeSet* objTypes);
+ MOZ_MUST_USE bool setPropTryInlineAccess(bool* emitted, MDefinition* obj,
+ PropertyName* name, MDefinition* value,
+ bool barrier, TemporaryTypeSet* objTypes);
+ MOZ_MUST_USE bool setPropTryTypedObject(bool* emitted, MDefinition* obj,
+ PropertyName* name, MDefinition* value);
+ MOZ_MUST_USE bool setPropTryReferencePropOfTypedObject(bool* emitted, MDefinition* obj,
+ int32_t fieldOffset, MDefinition* value,
+ TypedObjectPrediction fieldPrediction,
+ PropertyName* name);
+ MOZ_MUST_USE bool setPropTryScalarPropOfTypedObject(bool* emitted,
+ MDefinition* obj,
+ int32_t fieldOffset,
+ MDefinition* value,
+ TypedObjectPrediction fieldTypeReprs);
+ MOZ_MUST_USE bool setPropTryCache(bool* emitted, MDefinition* obj,
+ PropertyName* name, MDefinition* value,
+ bool barrier, TemporaryTypeSet* objTypes);
+
+ // jsop_binary_arith helpers.
+ MBinaryArithInstruction* binaryArithInstruction(JSOp op, MDefinition* left, MDefinition* right);
+ MOZ_MUST_USE bool binaryArithTryConcat(bool* emitted, JSOp op, MDefinition* left,
+ MDefinition* right);
+ MOZ_MUST_USE bool binaryArithTrySpecialized(bool* emitted, JSOp op, MDefinition* left,
+ MDefinition* right);
+ MOZ_MUST_USE bool binaryArithTrySpecializedOnBaselineInspector(bool* emitted, JSOp op,
+ MDefinition* left,
+ MDefinition* right);
+ MOZ_MUST_USE bool arithTrySharedStub(bool* emitted, JSOp op, MDefinition* left,
+ MDefinition* right);
+
+ // jsop_bitnot helpers.
+ MOZ_MUST_USE bool bitnotTrySpecialized(bool* emitted, MDefinition* input);
+
+ // jsop_pow helpers.
+ MOZ_MUST_USE bool powTrySpecialized(bool* emitted, MDefinition* base, MDefinition* power,
+ MIRType outputType);
+
+ // jsop_compare helpers.
+ MOZ_MUST_USE bool compareTrySpecialized(bool* emitted, JSOp op, MDefinition* left,
+ MDefinition* right);
+ MOZ_MUST_USE bool compareTryBitwise(bool* emitted, JSOp op, MDefinition* left,
+ MDefinition* right);
+ MOZ_MUST_USE bool compareTrySpecializedOnBaselineInspector(bool* emitted, JSOp op,
+ MDefinition* left,
+ MDefinition* right);
+ MOZ_MUST_USE bool compareTrySharedStub(bool* emitted, JSOp op, MDefinition* left,
+ MDefinition* right);
+
+ // jsop_newarray helpers.
+ MOZ_MUST_USE bool newArrayTrySharedStub(bool* emitted);
+ MOZ_MUST_USE bool newArrayTryTemplateObject(bool* emitted, JSObject* templateObject,
+ uint32_t length);
+ MOZ_MUST_USE bool newArrayTryVM(bool* emitted, JSObject* templateObject, uint32_t length);
+
+ // jsop_newobject helpers.
+ MOZ_MUST_USE bool newObjectTrySharedStub(bool* emitted);
+ MOZ_MUST_USE bool newObjectTryTemplateObject(bool* emitted, JSObject* templateObject);
+ MOZ_MUST_USE bool newObjectTryVM(bool* emitted, JSObject* templateObject);
+
+ // jsop_in helpers.
+ MOZ_MUST_USE bool inTryDense(bool* emitted, MDefinition* obj, MDefinition* id);
+ MOZ_MUST_USE bool inTryFold(bool* emitted, MDefinition* obj, MDefinition* id);
+
+ // binary data lookup helpers.
+ TypedObjectPrediction typedObjectPrediction(MDefinition* typedObj);
+ TypedObjectPrediction typedObjectPrediction(TemporaryTypeSet* types);
+ MOZ_MUST_USE bool typedObjectHasField(MDefinition* typedObj,
+ PropertyName* name,
+ size_t* fieldOffset,
+ TypedObjectPrediction* fieldTypeReprs,
+ size_t* fieldIndex);
+ MDefinition* loadTypedObjectType(MDefinition* value);
+ void loadTypedObjectData(MDefinition* typedObj,
+ MDefinition** owner,
+ LinearSum* ownerOffset);
+ void loadTypedObjectElements(MDefinition* typedObj,
+ const LinearSum& byteOffset,
+ uint32_t scale,
+ MDefinition** ownerElements,
+ MDefinition** ownerScaledOffset,
+ int32_t* ownerByteAdjustment);
+ MDefinition* typeObjectForElementFromArrayStructType(MDefinition* typedObj);
+ MDefinition* typeObjectForFieldFromStructType(MDefinition* type,
+ size_t fieldIndex);
+ MOZ_MUST_USE bool storeReferenceTypedObjectValue(MDefinition* typedObj,
+ const LinearSum& byteOffset,
+ ReferenceTypeDescr::Type type,
+ MDefinition* value,
+ PropertyName* name);
+ MOZ_MUST_USE bool storeScalarTypedObjectValue(MDefinition* typedObj,
+ const LinearSum& byteOffset,
+ ScalarTypeDescr::Type type,
+ MDefinition* value);
+ MOZ_MUST_USE bool checkTypedObjectIndexInBounds(uint32_t elemSize,
+ MDefinition* obj,
+ MDefinition* index,
+ TypedObjectPrediction objTypeDescrs,
+ LinearSum* indexAsByteOffset);
+ MOZ_MUST_USE bool pushDerivedTypedObject(bool* emitted,
+ MDefinition* obj,
+ const LinearSum& byteOffset,
+ TypedObjectPrediction derivedTypeDescrs,
+ MDefinition* derivedTypeObj);
+ MOZ_MUST_USE bool pushScalarLoadFromTypedObject(MDefinition* obj,
+ const LinearSum& byteoffset,
+ ScalarTypeDescr::Type type);
+ MOZ_MUST_USE bool pushReferenceLoadFromTypedObject(MDefinition* typedObj,
+ const LinearSum& byteOffset,
+ ReferenceTypeDescr::Type type,
+ PropertyName* name);
+ JSObject* getStaticTypedArrayObject(MDefinition* obj, MDefinition* index);
+
+ // jsop_setelem() helpers.
+ MOZ_MUST_USE bool setElemTryTypedArray(bool* emitted, MDefinition* object,
+ MDefinition* index, MDefinition* value);
+ MOZ_MUST_USE bool setElemTryTypedObject(bool* emitted, MDefinition* obj,
+ MDefinition* index, MDefinition* value);
+ MOZ_MUST_USE bool setElemTryTypedStatic(bool* emitted, MDefinition* object,
+ MDefinition* index, MDefinition* value);
+ MOZ_MUST_USE bool setElemTryDense(bool* emitted, MDefinition* object,
+ MDefinition* index, MDefinition* value, bool writeHole);
+ MOZ_MUST_USE bool setElemTryArguments(bool* emitted, MDefinition* object,
+ MDefinition* index, MDefinition* value);
+ MOZ_MUST_USE bool setElemTryCache(bool* emitted, MDefinition* object,
+ MDefinition* index, MDefinition* value);
+ MOZ_MUST_USE bool setElemTryReferenceElemOfTypedObject(bool* emitted,
+ MDefinition* obj,
+ MDefinition* index,
+ TypedObjectPrediction objPrediction,
+ MDefinition* value,
+ TypedObjectPrediction elemPrediction);
+ MOZ_MUST_USE bool setElemTryScalarElemOfTypedObject(bool* emitted,
+ MDefinition* obj,
+ MDefinition* index,
+ TypedObjectPrediction objTypeReprs,
+ MDefinition* value,
+ TypedObjectPrediction elemTypeReprs,
+ uint32_t elemSize);
+ MOZ_MUST_USE bool initializeArrayElement(MDefinition* obj, size_t index, MDefinition* value,
+ JSValueType unboxedType,
+ bool addResumePointAndIncrementInitializedLength);
+
+ // jsop_getelem() helpers.
+ MOZ_MUST_USE bool getElemTryDense(bool* emitted, MDefinition* obj, MDefinition* index);
+ MOZ_MUST_USE bool getElemTryGetProp(bool* emitted, MDefinition* obj, MDefinition* index);
+ MOZ_MUST_USE bool getElemTryTypedStatic(bool* emitted, MDefinition* obj, MDefinition* index);
+ MOZ_MUST_USE bool getElemTryTypedArray(bool* emitted, MDefinition* obj, MDefinition* index);
+ MOZ_MUST_USE bool getElemTryTypedObject(bool* emitted, MDefinition* obj, MDefinition* index);
+ MOZ_MUST_USE bool getElemTryString(bool* emitted, MDefinition* obj, MDefinition* index);
+ MOZ_MUST_USE bool getElemTryArguments(bool* emitted, MDefinition* obj, MDefinition* index);
+ MOZ_MUST_USE bool getElemTryArgumentsInlined(bool* emitted, MDefinition* obj,
+ MDefinition* index);
+ MOZ_MUST_USE bool getElemTryCache(bool* emitted, MDefinition* obj, MDefinition* index);
+ MOZ_MUST_USE bool getElemTryScalarElemOfTypedObject(bool* emitted,
+ MDefinition* obj,
+ MDefinition* index,
+ TypedObjectPrediction objTypeReprs,
+ TypedObjectPrediction elemTypeReprs,
+ uint32_t elemSize);
+ MOZ_MUST_USE bool getElemTryReferenceElemOfTypedObject(bool* emitted,
+ MDefinition* obj,
+ MDefinition* index,
+ TypedObjectPrediction objPrediction,
+ TypedObjectPrediction elemPrediction);
+ MOZ_MUST_USE bool getElemTryComplexElemOfTypedObject(bool* emitted,
+ MDefinition* obj,
+ MDefinition* index,
+ TypedObjectPrediction objTypeReprs,
+ TypedObjectPrediction elemTypeReprs,
+ uint32_t elemSize);
+ TemporaryTypeSet* computeHeapType(const TemporaryTypeSet* objTypes, const jsid id);
+
+ enum BoundsChecking { DoBoundsCheck, SkipBoundsCheck };
+
+ MInstruction* addArrayBufferByteLength(MDefinition* obj);
+
+ // Add instructions to compute a typed array's length and data. Also
+ // optionally convert |*index| into a bounds-checked definition, if
+ // requested.
+ //
+ // If you only need the array's length, use addTypedArrayLength below.
+ void addTypedArrayLengthAndData(MDefinition* obj,
+ BoundsChecking checking,
+ MDefinition** index,
+ MInstruction** length, MInstruction** elements);
+
+ // Add an instruction to compute a typed array's length to the current
+ // block. If you also need the typed array's data, use the above method
+ // instead.
+ MInstruction* addTypedArrayLength(MDefinition* obj) {
+ MInstruction* length;
+ addTypedArrayLengthAndData(obj, SkipBoundsCheck, nullptr, &length, nullptr);
+ return length;
+ }
+
+ MOZ_MUST_USE bool improveThisTypesForCall();
+
+ MDefinition* getCallee();
+ MDefinition* getAliasedVar(EnvironmentCoordinate ec);
+ MDefinition* addLexicalCheck(MDefinition* input);
+
+ MDefinition* convertToBoolean(MDefinition* input);
+
+ MOZ_MUST_USE bool tryFoldInstanceOf(MDefinition* lhs, JSObject* protoObject);
+ MOZ_MUST_USE bool hasOnProtoChain(TypeSet::ObjectKey* key, JSObject* protoObject,
+ bool* hasOnProto);
+
+ MOZ_MUST_USE bool jsop_add(MDefinition* left, MDefinition* right);
+ MOZ_MUST_USE bool jsop_bitnot();
+ MOZ_MUST_USE bool jsop_bitop(JSOp op);
+ MOZ_MUST_USE bool jsop_binary_arith(JSOp op);
+ MOZ_MUST_USE bool jsop_binary_arith(JSOp op, MDefinition* left, MDefinition* right);
+ MOZ_MUST_USE bool jsop_pow();
+ MOZ_MUST_USE bool jsop_pos();
+ MOZ_MUST_USE bool jsop_neg();
+ MOZ_MUST_USE bool jsop_tostring();
+ MOZ_MUST_USE bool jsop_setarg(uint32_t arg);
+ MOZ_MUST_USE bool jsop_defvar(uint32_t index);
+ MOZ_MUST_USE bool jsop_deflexical(uint32_t index);
+ MOZ_MUST_USE bool jsop_deffun(uint32_t index);
+ MOZ_MUST_USE bool jsop_notearg();
+ MOZ_MUST_USE bool jsop_throwsetconst();
+ MOZ_MUST_USE bool jsop_checklexical();
+ MOZ_MUST_USE bool jsop_checkaliasedlexical(EnvironmentCoordinate ec);
+ MOZ_MUST_USE bool jsop_funcall(uint32_t argc);
+ MOZ_MUST_USE bool jsop_funapply(uint32_t argc);
+ MOZ_MUST_USE bool jsop_funapplyarguments(uint32_t argc);
+ MOZ_MUST_USE bool jsop_funapplyarray(uint32_t argc);
+ MOZ_MUST_USE bool jsop_call(uint32_t argc, bool constructing);
+ MOZ_MUST_USE bool jsop_eval(uint32_t argc);
+ MOZ_MUST_USE bool jsop_ifeq(JSOp op);
+ MOZ_MUST_USE bool jsop_try();
+ MOZ_MUST_USE bool jsop_label();
+ MOZ_MUST_USE bool jsop_condswitch();
+ MOZ_MUST_USE bool jsop_andor(JSOp op);
+ MOZ_MUST_USE bool jsop_dup2();
+ MOZ_MUST_USE bool jsop_loophead(jsbytecode* pc);
+ MOZ_MUST_USE bool jsop_compare(JSOp op);
+ MOZ_MUST_USE bool jsop_compare(JSOp op, MDefinition* left, MDefinition* right);
+ MOZ_MUST_USE bool getStaticName(JSObject* staticObject, PropertyName* name, bool* psucceeded,
+ MDefinition* lexicalCheck = nullptr);
+ MOZ_MUST_USE bool loadStaticSlot(JSObject* staticObject, BarrierKind barrier,
+ TemporaryTypeSet* types, uint32_t slot);
+ MOZ_MUST_USE bool setStaticName(JSObject* staticObject, PropertyName* name);
+ MOZ_MUST_USE bool jsop_getgname(PropertyName* name);
+ MOZ_MUST_USE bool jsop_getname(PropertyName* name);
+ MOZ_MUST_USE bool jsop_intrinsic(PropertyName* name);
+ MOZ_MUST_USE bool jsop_getimport(PropertyName* name);
+ MOZ_MUST_USE bool jsop_bindname(PropertyName* name);
+ MOZ_MUST_USE bool jsop_bindvar();
+ MOZ_MUST_USE bool jsop_getelem();
+ MOZ_MUST_USE bool jsop_getelem_dense(MDefinition* obj, MDefinition* index,
+ JSValueType unboxedType);
+ MOZ_MUST_USE bool jsop_getelem_typed(MDefinition* obj, MDefinition* index,
+ ScalarTypeDescr::Type arrayType);
+ MOZ_MUST_USE bool jsop_setelem();
+ MOZ_MUST_USE bool jsop_setelem_dense(TemporaryTypeSet::DoubleConversion conversion,
+ MDefinition* object, MDefinition* index,
+ MDefinition* value, JSValueType unboxedType,
+ bool writeHole, bool* emitted);
+ MOZ_MUST_USE bool jsop_setelem_typed(ScalarTypeDescr::Type arrayType,
+ MDefinition* object, MDefinition* index,
+ MDefinition* value);
+ MOZ_MUST_USE bool jsop_length();
+ MOZ_MUST_USE bool jsop_length_fastPath();
+ MOZ_MUST_USE bool jsop_arguments();
+ MOZ_MUST_USE bool jsop_arguments_getelem();
+ MOZ_MUST_USE bool jsop_runonce();
+ MOZ_MUST_USE bool jsop_rest();
+ MOZ_MUST_USE bool jsop_not();
+ MOZ_MUST_USE bool jsop_getprop(PropertyName* name);
+ MOZ_MUST_USE bool jsop_setprop(PropertyName* name);
+ MOZ_MUST_USE bool jsop_delprop(PropertyName* name);
+ MOZ_MUST_USE bool jsop_delelem();
+ MOZ_MUST_USE bool jsop_newarray(uint32_t length);
+ MOZ_MUST_USE bool jsop_newarray(JSObject* templateObject, uint32_t length);
+ MOZ_MUST_USE bool jsop_newarray_copyonwrite();
+ MOZ_MUST_USE bool jsop_newobject();
+ MOZ_MUST_USE bool jsop_initelem();
+ MOZ_MUST_USE bool jsop_initelem_array();
+ MOZ_MUST_USE bool jsop_initelem_getter_setter();
+ MOZ_MUST_USE bool jsop_mutateproto();
+ MOZ_MUST_USE bool jsop_initprop(PropertyName* name);
+ MOZ_MUST_USE bool jsop_initprop_getter_setter(PropertyName* name);
+ MOZ_MUST_USE bool jsop_regexp(RegExpObject* reobj);
+ MOZ_MUST_USE bool jsop_object(JSObject* obj);
+ MOZ_MUST_USE bool jsop_lambda(JSFunction* fun);
+ MOZ_MUST_USE bool jsop_lambda_arrow(JSFunction* fun);
+ MOZ_MUST_USE bool jsop_functionthis();
+ MOZ_MUST_USE bool jsop_globalthis();
+ MOZ_MUST_USE bool jsop_typeof();
+ MOZ_MUST_USE bool jsop_toasync();
+ MOZ_MUST_USE bool jsop_toid();
+ MOZ_MUST_USE bool jsop_iter(uint8_t flags);
+ MOZ_MUST_USE bool jsop_itermore();
+ MOZ_MUST_USE bool jsop_isnoiter();
+ MOZ_MUST_USE bool jsop_iterend();
+ MOZ_MUST_USE bool jsop_in();
+ MOZ_MUST_USE bool jsop_instanceof();
+ MOZ_MUST_USE bool jsop_getaliasedvar(EnvironmentCoordinate ec);
+ MOZ_MUST_USE bool jsop_setaliasedvar(EnvironmentCoordinate ec);
+ MOZ_MUST_USE bool jsop_debugger();
+ MOZ_MUST_USE bool jsop_newtarget();
+ MOZ_MUST_USE bool jsop_checkisobj(uint8_t kind);
+ MOZ_MUST_USE bool jsop_checkobjcoercible();
+ MOZ_MUST_USE bool jsop_pushcallobj();
+
+ /* Inlining. */
+
+ enum InliningStatus
+ {
+ InliningStatus_Error,
+ InliningStatus_NotInlined,
+ InliningStatus_WarmUpCountTooLow,
+ InliningStatus_Inlined
+ };
+
+ enum InliningDecision
+ {
+ InliningDecision_Error,
+ InliningDecision_Inline,
+ InliningDecision_DontInline,
+ InliningDecision_WarmUpCountTooLow
+ };
+
+ static InliningDecision DontInline(JSScript* targetScript, const char* reason);
+
+ // Helper function for canInlineTarget
+ bool hasCommonInliningPath(const JSScript* scriptToInline);
+
+ // Oracles.
+ InliningDecision canInlineTarget(JSFunction* target, CallInfo& callInfo);
+ InliningDecision makeInliningDecision(JSObject* target, CallInfo& callInfo);
+ MOZ_MUST_USE bool selectInliningTargets(const ObjectVector& targets, CallInfo& callInfo,
+ BoolVector& choiceSet, uint32_t* numInlineable);
+
+ // Native inlining helpers.
+ // The typeset for the return value of our function. These are
+ // the types it's been observed returning in the past.
+ TemporaryTypeSet* getInlineReturnTypeSet();
+ // The known MIR type of getInlineReturnTypeSet.
+ MIRType getInlineReturnType();
+
+ // Array natives.
+ InliningStatus inlineArray(CallInfo& callInfo);
+ InliningStatus inlineArrayIsArray(CallInfo& callInfo);
+ InliningStatus inlineArrayPopShift(CallInfo& callInfo, MArrayPopShift::Mode mode);
+ InliningStatus inlineArrayPush(CallInfo& callInfo);
+ InliningStatus inlineArraySlice(CallInfo& callInfo);
+ InliningStatus inlineArrayJoin(CallInfo& callInfo);
+ InliningStatus inlineArraySplice(CallInfo& callInfo);
+
+ // Math natives.
+ InliningStatus inlineMathAbs(CallInfo& callInfo);
+ InliningStatus inlineMathFloor(CallInfo& callInfo);
+ InliningStatus inlineMathCeil(CallInfo& callInfo);
+ InliningStatus inlineMathClz32(CallInfo& callInfo);
+ InliningStatus inlineMathRound(CallInfo& callInfo);
+ InliningStatus inlineMathSqrt(CallInfo& callInfo);
+ InliningStatus inlineMathAtan2(CallInfo& callInfo);
+ InliningStatus inlineMathHypot(CallInfo& callInfo);
+ InliningStatus inlineMathMinMax(CallInfo& callInfo, bool max);
+ InliningStatus inlineMathPow(CallInfo& callInfo);
+ InliningStatus inlineMathRandom(CallInfo& callInfo);
+ InliningStatus inlineMathImul(CallInfo& callInfo);
+ InliningStatus inlineMathFRound(CallInfo& callInfo);
+ InliningStatus inlineMathFunction(CallInfo& callInfo, MMathFunction::Function function);
+
+ // String natives.
+ InliningStatus inlineStringObject(CallInfo& callInfo);
+ InliningStatus inlineStrCharCodeAt(CallInfo& callInfo);
+ InliningStatus inlineConstantCharCodeAt(CallInfo& callInfo);
+ InliningStatus inlineStrFromCharCode(CallInfo& callInfo);
+ InliningStatus inlineStrFromCodePoint(CallInfo& callInfo);
+ InliningStatus inlineStrCharAt(CallInfo& callInfo);
+
+ // String intrinsics.
+ InliningStatus inlineStringReplaceString(CallInfo& callInfo);
+ InliningStatus inlineConstantStringSplitString(CallInfo& callInfo);
+ InliningStatus inlineStringSplitString(CallInfo& callInfo);
+
+ // RegExp intrinsics.
+ InliningStatus inlineRegExpMatcher(CallInfo& callInfo);
+ InliningStatus inlineRegExpSearcher(CallInfo& callInfo);
+ InliningStatus inlineRegExpTester(CallInfo& callInfo);
+ InliningStatus inlineIsRegExpObject(CallInfo& callInfo);
+ InliningStatus inlineRegExpPrototypeOptimizable(CallInfo& callInfo);
+ InliningStatus inlineRegExpInstanceOptimizable(CallInfo& callInfo);
+ InliningStatus inlineGetFirstDollarIndex(CallInfo& callInfo);
+
+ // Object natives and intrinsics.
+ InliningStatus inlineObjectCreate(CallInfo& callInfo);
+ InliningStatus inlineDefineDataProperty(CallInfo& callInfo);
+
+ // Atomics natives.
+ InliningStatus inlineAtomicsCompareExchange(CallInfo& callInfo);
+ InliningStatus inlineAtomicsExchange(CallInfo& callInfo);
+ InliningStatus inlineAtomicsLoad(CallInfo& callInfo);
+ InliningStatus inlineAtomicsStore(CallInfo& callInfo);
+ InliningStatus inlineAtomicsBinop(CallInfo& callInfo, InlinableNative target);
+ InliningStatus inlineAtomicsIsLockFree(CallInfo& callInfo);
+
+ // Slot intrinsics.
+ InliningStatus inlineUnsafeSetReservedSlot(CallInfo& callInfo);
+ InliningStatus inlineUnsafeGetReservedSlot(CallInfo& callInfo,
+ MIRType knownValueType);
+
+ // Map and Set intrinsics.
+ InliningStatus inlineGetNextEntryForIterator(CallInfo& callInfo,
+ MGetNextEntryForIterator::Mode mode);
+
+ // ArrayBuffer intrinsics.
+ InliningStatus inlineArrayBufferByteLength(CallInfo& callInfo);
+ InliningStatus inlinePossiblyWrappedArrayBufferByteLength(CallInfo& callInfo);
+
+ // TypedArray intrinsics.
+ enum WrappingBehavior { AllowWrappedTypedArrays, RejectWrappedTypedArrays };
+ InliningStatus inlineTypedArray(CallInfo& callInfo, Native native);
+ InliningStatus inlineIsTypedArrayHelper(CallInfo& callInfo, WrappingBehavior wrappingBehavior);
+ InliningStatus inlineIsTypedArray(CallInfo& callInfo);
+ InliningStatus inlineIsPossiblyWrappedTypedArray(CallInfo& callInfo);
+ InliningStatus inlineTypedArrayLength(CallInfo& callInfo);
+ InliningStatus inlinePossiblyWrappedTypedArrayLength(CallInfo& callInfo);
+ InliningStatus inlineSetDisjointTypedElements(CallInfo& callInfo);
+
+ // TypedObject intrinsics and natives.
+ InliningStatus inlineObjectIsTypeDescr(CallInfo& callInfo);
+ InliningStatus inlineSetTypedObjectOffset(CallInfo& callInfo);
+ InliningStatus inlineConstructTypedObject(CallInfo& callInfo, TypeDescr* target);
+
+ // SIMD intrinsics and natives.
+ InliningStatus inlineConstructSimdObject(CallInfo& callInfo, SimdTypeDescr* target);
+
+ // SIMD helpers.
+ bool canInlineSimd(CallInfo& callInfo, JSNative native, unsigned numArgs,
+ InlineTypedObject** templateObj);
+ MDefinition* unboxSimd(MDefinition* ins, SimdType type);
+ IonBuilder::InliningStatus boxSimd(CallInfo& callInfo, MDefinition* ins,
+ InlineTypedObject* templateObj);
+ MDefinition* convertToBooleanSimdLane(MDefinition* scalar);
+
+ InliningStatus inlineSimd(CallInfo& callInfo, JSFunction* target, SimdType type);
+
+ InliningStatus inlineSimdBinaryArith(CallInfo& callInfo, JSNative native,
+ MSimdBinaryArith::Operation op, SimdType type);
+ InliningStatus inlineSimdBinaryBitwise(CallInfo& callInfo, JSNative native,
+ MSimdBinaryBitwise::Operation op, SimdType type);
+ InliningStatus inlineSimdBinarySaturating(CallInfo& callInfo, JSNative native,
+ MSimdBinarySaturating::Operation op, SimdType type);
+ InliningStatus inlineSimdShift(CallInfo& callInfo, JSNative native, MSimdShift::Operation op,
+ SimdType type);
+ InliningStatus inlineSimdComp(CallInfo& callInfo, JSNative native,
+ MSimdBinaryComp::Operation op, SimdType type);
+ InliningStatus inlineSimdUnary(CallInfo& callInfo, JSNative native,
+ MSimdUnaryArith::Operation op, SimdType type);
+ InliningStatus inlineSimdExtractLane(CallInfo& callInfo, JSNative native, SimdType type);
+ InliningStatus inlineSimdReplaceLane(CallInfo& callInfo, JSNative native, SimdType type);
+ InliningStatus inlineSimdSplat(CallInfo& callInfo, JSNative native, SimdType type);
+ InliningStatus inlineSimdShuffle(CallInfo& callInfo, JSNative native, SimdType type,
+ unsigned numVectors);
+ InliningStatus inlineSimdCheck(CallInfo& callInfo, JSNative native, SimdType type);
+ InliningStatus inlineSimdConvert(CallInfo& callInfo, JSNative native, bool isCast,
+ SimdType from, SimdType to);
+ InliningStatus inlineSimdSelect(CallInfo& callInfo, JSNative native, SimdType type);
+
+ MOZ_MUST_USE bool prepareForSimdLoadStore(CallInfo& callInfo, Scalar::Type simdType,
+ MInstruction** elements, MDefinition** index,
+ Scalar::Type* arrayType);
+ InliningStatus inlineSimdLoad(CallInfo& callInfo, JSNative native, SimdType type,
+ unsigned numElems);
+ InliningStatus inlineSimdStore(CallInfo& callInfo, JSNative native, SimdType type,
+ unsigned numElems);
+
+ InliningStatus inlineSimdAnyAllTrue(CallInfo& callInfo, bool IsAllTrue, JSNative native,
+ SimdType type);
+
+ // Utility intrinsics.
+ InliningStatus inlineIsCallable(CallInfo& callInfo);
+ InliningStatus inlineIsConstructor(CallInfo& callInfo);
+ InliningStatus inlineIsObject(CallInfo& callInfo);
+ InliningStatus inlineToObject(CallInfo& callInfo);
+ InliningStatus inlineIsWrappedArrayConstructor(CallInfo& callInfo);
+ InliningStatus inlineToInteger(CallInfo& callInfo);
+ InliningStatus inlineToString(CallInfo& callInfo);
+ InliningStatus inlineDump(CallInfo& callInfo);
+ InliningStatus inlineHasClass(CallInfo& callInfo, const Class* clasp,
+ const Class* clasp2 = nullptr,
+ const Class* clasp3 = nullptr,
+ const Class* clasp4 = nullptr);
+ InliningStatus inlineIsConstructing(CallInfo& callInfo);
+ InliningStatus inlineSubstringKernel(CallInfo& callInfo);
+ InliningStatus inlineObjectHasPrototype(CallInfo& callInfo);
+
+ // Testing functions.
+ InliningStatus inlineBailout(CallInfo& callInfo);
+ InliningStatus inlineAssertFloat32(CallInfo& callInfo);
+ InliningStatus inlineAssertRecoveredOnBailout(CallInfo& callInfo);
+
+ // Bind function.
+ InliningStatus inlineBoundFunction(CallInfo& callInfo, JSFunction* target);
+
+ // Main inlining functions
+ InliningStatus inlineNativeCall(CallInfo& callInfo, JSFunction* target);
+ InliningStatus inlineNativeGetter(CallInfo& callInfo, JSFunction* target);
+ InliningStatus inlineNonFunctionCall(CallInfo& callInfo, JSObject* target);
+ InliningStatus inlineScriptedCall(CallInfo& callInfo, JSFunction* target);
+ InliningStatus inlineSingleCall(CallInfo& callInfo, JSObject* target);
+
+ // Call functions
+ InliningStatus inlineCallsite(const ObjectVector& targets, CallInfo& callInfo);
+ MOZ_MUST_USE bool inlineCalls(CallInfo& callInfo, const ObjectVector& targets,
+ BoolVector& choiceSet, MGetPropertyCache* maybeCache);
+
+ // Inlining helpers.
+ MOZ_MUST_USE bool inlineGenericFallback(JSFunction* target, CallInfo& callInfo,
+ MBasicBlock* dispatchBlock);
+ MOZ_MUST_USE bool inlineObjectGroupFallback(CallInfo& callInfo, MBasicBlock* dispatchBlock,
+ MObjectGroupDispatch* dispatch,
+ MGetPropertyCache* cache,
+ MBasicBlock** fallbackTarget);
+
+ enum AtomicCheckResult {
+ DontCheckAtomicResult,
+ DoCheckAtomicResult
+ };
+
+ MOZ_MUST_USE bool atomicsMeetsPreconditions(CallInfo& callInfo, Scalar::Type* arrayElementType,
+ bool* requiresDynamicCheck,
+ AtomicCheckResult checkResult=DoCheckAtomicResult);
+ void atomicsCheckBounds(CallInfo& callInfo, MInstruction** elements, MDefinition** index);
+
+ MOZ_MUST_USE bool testNeedsArgumentCheck(JSFunction* target, CallInfo& callInfo);
+
+ MCall* makeCallHelper(JSFunction* target, CallInfo& callInfo);
+ MOZ_MUST_USE bool makeCall(JSFunction* target, CallInfo& callInfo);
+
+ MDefinition* patchInlinedReturn(CallInfo& callInfo, MBasicBlock* exit, MBasicBlock* bottom);
+ MDefinition* patchInlinedReturns(CallInfo& callInfo, MIRGraphReturns& returns,
+ MBasicBlock* bottom);
+ MDefinition* specializeInlinedReturn(MDefinition* rdef, MBasicBlock* exit);
+
+ MOZ_MUST_USE bool objectsHaveCommonPrototype(TemporaryTypeSet* types, PropertyName* name,
+ bool isGetter, JSObject* foundProto,
+ bool* guardGlobal);
+ void freezePropertiesForCommonPrototype(TemporaryTypeSet* types, PropertyName* name,
+ JSObject* foundProto, bool allowEmptyTypesForGlobal = false);
+ /*
+ * Callers must pass a non-null globalGuard if they pass a non-null globalShape.
+ */
+ MOZ_MUST_USE bool testCommonGetterSetter(TemporaryTypeSet* types, PropertyName* name,
+ bool isGetter, JSObject* foundProto,
+ Shape* lastProperty, JSFunction* getterOrSetter,
+ MDefinition** guard, Shape* globalShape = nullptr,
+ MDefinition** globalGuard = nullptr);
+ MOZ_MUST_USE bool testShouldDOMCall(TypeSet* inTypes,
+ JSFunction* func, JSJitInfo::OpType opType);
+
+ MDefinition*
+ addShapeGuardsForGetterSetter(MDefinition* obj, JSObject* holder, Shape* holderShape,
+ const BaselineInspector::ReceiverVector& receivers,
+ const BaselineInspector::ObjectGroupVector& convertUnboxedGroups,
+ bool isOwnProperty);
+
+ MOZ_MUST_USE bool annotateGetPropertyCache(MDefinition* obj, PropertyName* name,
+ MGetPropertyCache* getPropCache,
+ TemporaryTypeSet* objTypes,
+ TemporaryTypeSet* pushedTypes);
+
+ MGetPropertyCache* getInlineableGetPropertyCache(CallInfo& callInfo);
+
+ JSObject* testGlobalLexicalBinding(PropertyName* name);
+
+ JSObject* testSingletonProperty(JSObject* obj, jsid id);
+ JSObject* testSingletonPropertyTypes(MDefinition* obj, jsid id);
+
+ ResultWithOOM<bool> testNotDefinedProperty(MDefinition* obj, jsid id);
+
+ uint32_t getDefiniteSlot(TemporaryTypeSet* types, PropertyName* name, uint32_t* pnfixed);
+ MDefinition* convertUnboxedObjects(MDefinition* obj);
+ MDefinition* convertUnboxedObjects(MDefinition* obj,
+ const BaselineInspector::ObjectGroupVector& list);
+ uint32_t getUnboxedOffset(TemporaryTypeSet* types, PropertyName* name,
+ JSValueType* punboxedType);
+ MInstruction* loadUnboxedProperty(MDefinition* obj, size_t offset, JSValueType unboxedType,
+ BarrierKind barrier, TemporaryTypeSet* types);
+ MInstruction* loadUnboxedValue(MDefinition* elements, size_t elementsOffset,
+ MDefinition* scaledOffset, JSValueType unboxedType,
+ BarrierKind barrier, TemporaryTypeSet* types);
+ MInstruction* storeUnboxedProperty(MDefinition* obj, size_t offset, JSValueType unboxedType,
+ MDefinition* value);
+ MInstruction* storeUnboxedValue(MDefinition* obj,
+ MDefinition* elements, int32_t elementsOffset,
+ MDefinition* scaledOffset, JSValueType unboxedType,
+ MDefinition* value, bool preBarrier = true);
+ MOZ_MUST_USE bool checkPreliminaryGroups(MDefinition *obj);
+ MOZ_MUST_USE bool freezePropTypeSets(TemporaryTypeSet* types,
+ JSObject* foundProto, PropertyName* name);
+ bool canInlinePropertyOpShapes(const BaselineInspector::ReceiverVector& receivers);
+
+ TemporaryTypeSet* bytecodeTypes(jsbytecode* pc);
+
+ // Use one of the below methods for updating the current block, rather than
+ // updating |current| directly. setCurrent() should only be used in cases
+ // where the block cannot have phis whose type needs to be computed.
+
+ MOZ_MUST_USE bool setCurrentAndSpecializePhis(MBasicBlock* block) {
+ if (block) {
+ if (!block->specializePhis(alloc()))
+ return false;
+ }
+ setCurrent(block);
+ return true;
+ }
+
+ void setCurrent(MBasicBlock* block) {
+ current = block;
+ }
+
+ // A builder is inextricably tied to a particular script.
+ JSScript* script_;
+
+ // script->hasIonScript() at the start of the compilation. Used to avoid
+ // calling hasIonScript() from background compilation threads.
+ bool scriptHasIonScript_;
+
+ // If off thread compilation is successful, the final code generator is
+ // attached here. Code has been generated, but not linked (there is not yet
+ // an IonScript). This is heap allocated, and must be explicitly destroyed,
+ // performed by FinishOffThreadBuilder().
+ CodeGenerator* backgroundCodegen_;
+
+ // Some aborts are actionable (e.g., using an unsupported bytecode). When
+ // optimization tracking is enabled, the location and message of the abort
+ // are recorded here so they may be propagated to the script's
+ // corresponding JitcodeGlobalEntry::BaselineEntry.
+ JSScript* actionableAbortScript_;
+ jsbytecode* actionableAbortPc_;
+ const char* actionableAbortMessage_;
+
+ MRootList* rootList_;
+
+ public:
+ void setRootList(MRootList& rootList) {
+ MOZ_ASSERT(!rootList_);
+ rootList_ = &rootList;
+ }
+ void clearForBackEnd();
+ JSObject* checkNurseryObject(JSObject* obj);
+
+ JSScript* script() const { return script_; }
+ bool scriptHasIonScript() const { return scriptHasIonScript_; }
+
+ CodeGenerator* backgroundCodegen() const { return backgroundCodegen_; }
+ void setBackgroundCodegen(CodeGenerator* codegen) { backgroundCodegen_ = codegen; }
+
+ CompilerConstraintList* constraints() {
+ return constraints_;
+ }
+
+ bool isInlineBuilder() const {
+ return callerBuilder_ != nullptr;
+ }
+
+ const JSAtomState& names() { return compartment->runtime()->names(); }
+
+ bool hadActionableAbort() const {
+ MOZ_ASSERT(!actionableAbortScript_ ||
+ (actionableAbortPc_ && actionableAbortMessage_));
+ return actionableAbortScript_ != nullptr;
+ }
+
+ TraceLoggerThread *traceLogger() {
+ // Currently ionbuilder only runs on the main thread.
+ return TraceLoggerForMainThread(compartment->runtime()->mainThread()->runtimeFromMainThread());
+ }
+
+ void actionableAbortLocationAndMessage(JSScript** abortScript, jsbytecode** abortPc,
+ const char** abortMessage)
+ {
+ MOZ_ASSERT(hadActionableAbort());
+ *abortScript = actionableAbortScript_;
+ *abortPc = actionableAbortPc_;
+ *abortMessage = actionableAbortMessage_;
+ }
+
+ void trace(JSTracer* trc);
+
+ private:
+ MOZ_MUST_USE bool init();
+
+ JSContext* analysisContext;
+ BaselineFrameInspector* baselineFrame_;
+
+ // Constraints for recording dependencies on type information.
+ CompilerConstraintList* constraints_;
+
+ // Basic analysis information about the script.
+ BytecodeAnalysis analysis_;
+ BytecodeAnalysis& analysis() {
+ return analysis_;
+ }
+
+ TemporaryTypeSet* thisTypes;
+ TemporaryTypeSet* argTypes;
+ TemporaryTypeSet* typeArray;
+ uint32_t typeArrayHint;
+ uint32_t* bytecodeTypeMap;
+
+ GSNCache gsn;
+ EnvironmentCoordinateNameCache envCoordinateNameCache;
+
+ jsbytecode* pc;
+ MBasicBlock* current;
+ uint32_t loopDepth_;
+
+ Vector<BytecodeSite*, 0, JitAllocPolicy> trackedOptimizationSites_;
+
+ BytecodeSite* bytecodeSite(jsbytecode* pc) {
+ MOZ_ASSERT(info().inlineScriptTree()->script()->containsPC(pc));
+ // See comment in maybeTrackedOptimizationSite.
+ if (isOptimizationTrackingEnabled()) {
+ if (BytecodeSite* site = maybeTrackedOptimizationSite(pc))
+ return site;
+ }
+ return new(alloc()) BytecodeSite(info().inlineScriptTree(), pc);
+ }
+
+ BytecodeSite* maybeTrackedOptimizationSite(jsbytecode* pc);
+
+ MDefinition* lexicalCheck_;
+
+ void setLexicalCheck(MDefinition* lexical) {
+ MOZ_ASSERT(!lexicalCheck_);
+ lexicalCheck_ = lexical;
+ }
+ MDefinition* takeLexicalCheck() {
+ MDefinition* lexical = lexicalCheck_;
+ lexicalCheck_ = nullptr;
+ return lexical;
+ }
+
+ /* Information used for inline-call builders. */
+ MResumePoint* callerResumePoint_;
+ jsbytecode* callerPC() {
+ return callerResumePoint_ ? callerResumePoint_->pc() : nullptr;
+ }
+ IonBuilder* callerBuilder_;
+
+ IonBuilder* outermostBuilder();
+
+ struct LoopHeader {
+ jsbytecode* pc;
+ MBasicBlock* header;
+
+ LoopHeader(jsbytecode* pc, MBasicBlock* header)
+ : pc(pc), header(header)
+ {}
+ };
+
+ Vector<CFGState, 8, JitAllocPolicy> cfgStack_;
+ Vector<ControlFlowInfo, 4, JitAllocPolicy> loops_;
+ Vector<ControlFlowInfo, 0, JitAllocPolicy> switches_;
+ Vector<ControlFlowInfo, 2, JitAllocPolicy> labels_;
+ Vector<MInstruction*, 2, JitAllocPolicy> iterators_;
+ Vector<LoopHeader, 0, JitAllocPolicy> loopHeaders_;
+ BaselineInspector* inspector;
+
+ size_t inliningDepth_;
+
+ // Total bytecode length of all inlined scripts. Only tracked for the
+ // outermost builder.
+ size_t inlinedBytecodeLength_;
+
+ // Cutoff to disable compilation if excessive time is spent reanalyzing
+ // loop bodies to compute a fixpoint of the types for loop variables.
+ static const size_t MAX_LOOP_RESTARTS = 40;
+ size_t numLoopRestarts_;
+
+ // True if script->failedBoundsCheck is set for the current script or
+ // an outer script.
+ bool failedBoundsCheck_;
+
+ // True if script->failedShapeGuard is set for the current script or
+ // an outer script.
+ bool failedShapeGuard_;
+
+ // True if script->failedLexicalCheck_ is set for the current script or
+ // an outer script.
+ bool failedLexicalCheck_;
+
+ // Has an iterator other than 'for in'.
+ bool nonStringIteration_;
+
+ // If this script can use a lazy arguments object, it will be pre-created
+ // here.
+ MInstruction* lazyArguments_;
+
+ // If this is an inline builder, the call info for the builder.
+ const CallInfo* inlineCallInfo_;
+
+ // When compiling a call with multiple targets, we are first creating a
+ // MGetPropertyCache. This MGetPropertyCache is following the bytecode, and
+ // is used to recover the JSFunction. In some cases, the Type of the object
+ // which own the property is enough for dispatching to the right function.
+ // In such cases we do not have read the property, except when the type
+ // object is unknown.
+ //
+ // As an optimization, we can dispatch a call based on the object group,
+ // without doing the MGetPropertyCache. This is what is achieved by
+ // |IonBuilder::inlineCalls|. As we might not know all the functions, we
+ // are adding a fallback path, where this MGetPropertyCache would be moved
+ // into.
+ //
+ // In order to build the fallback path, we have to capture a resume point
+ // ahead, for the potential fallback path. This resume point is captured
+ // while building MGetPropertyCache. It is capturing the state of Baseline
+ // before the execution of the MGetPropertyCache, such as we can safely do
+ // it in the fallback path.
+ //
+ // This field is used to discard the resume point if it is not used for
+ // building a fallback path.
+
+ // Discard the prior resume point while setting a new MGetPropertyCache.
+ void replaceMaybeFallbackFunctionGetter(MGetPropertyCache* cache);
+
+ // Discard the MGetPropertyCache if it is handled by WrapMGetPropertyCache.
+ void keepFallbackFunctionGetter(MGetPropertyCache* cache) {
+ if (cache == maybeFallbackFunctionGetter_)
+ maybeFallbackFunctionGetter_ = nullptr;
+ }
+
+ MGetPropertyCache* maybeFallbackFunctionGetter_;
+
+ // Used in tracking outcomes of optimization strategies for devtools.
+ void startTrackingOptimizations();
+
+ // The track* methods below are called often. Do not combine them with the
+ // unchecked variants, despite the unchecked variants having no other
+ // callers.
+ void trackTypeInfo(JS::TrackedTypeSite site, MIRType mirType,
+ TemporaryTypeSet* typeSet)
+ {
+ if (MOZ_UNLIKELY(current->trackedSite()->hasOptimizations()))
+ trackTypeInfoUnchecked(site, mirType, typeSet);
+ }
+ void trackTypeInfo(JS::TrackedTypeSite site, JSObject* obj) {
+ if (MOZ_UNLIKELY(current->trackedSite()->hasOptimizations()))
+ trackTypeInfoUnchecked(site, obj);
+ }
+ void trackTypeInfo(CallInfo& callInfo) {
+ if (MOZ_UNLIKELY(current->trackedSite()->hasOptimizations()))
+ trackTypeInfoUnchecked(callInfo);
+ }
+ void trackOptimizationAttempt(JS::TrackedStrategy strategy) {
+ if (MOZ_UNLIKELY(current->trackedSite()->hasOptimizations()))
+ trackOptimizationAttemptUnchecked(strategy);
+ }
+ void amendOptimizationAttempt(uint32_t index) {
+ if (MOZ_UNLIKELY(current->trackedSite()->hasOptimizations()))
+ amendOptimizationAttemptUnchecked(index);
+ }
+ void trackOptimizationOutcome(JS::TrackedOutcome outcome) {
+ if (MOZ_UNLIKELY(current->trackedSite()->hasOptimizations()))
+ trackOptimizationOutcomeUnchecked(outcome);
+ }
+ void trackOptimizationSuccess() {
+ if (MOZ_UNLIKELY(current->trackedSite()->hasOptimizations()))
+ trackOptimizationSuccessUnchecked();
+ }
+ void trackInlineSuccess(InliningStatus status = InliningStatus_Inlined) {
+ if (MOZ_UNLIKELY(current->trackedSite()->hasOptimizations()))
+ trackInlineSuccessUnchecked(status);
+ }
+
+ bool forceInlineCaches() {
+ return MOZ_UNLIKELY(JitOptions.forceInlineCaches);
+ }
+
+ // Out-of-line variants that don't check if optimization tracking is
+ // enabled.
+ void trackTypeInfoUnchecked(JS::TrackedTypeSite site, MIRType mirType,
+ TemporaryTypeSet* typeSet);
+ void trackTypeInfoUnchecked(JS::TrackedTypeSite site, JSObject* obj);
+ void trackTypeInfoUnchecked(CallInfo& callInfo);
+ void trackOptimizationAttemptUnchecked(JS::TrackedStrategy strategy);
+ void amendOptimizationAttemptUnchecked(uint32_t index);
+ void trackOptimizationOutcomeUnchecked(JS::TrackedOutcome outcome);
+ void trackOptimizationSuccessUnchecked();
+ void trackInlineSuccessUnchecked(InliningStatus status);
+};
+
+class CallInfo
+{
+ MDefinition* fun_;
+ MDefinition* thisArg_;
+ MDefinition* newTargetArg_;
+ MDefinitionVector args_;
+
+ bool constructing_;
+ bool setter_;
+
+ public:
+ CallInfo(TempAllocator& alloc, bool constructing)
+ : fun_(nullptr),
+ thisArg_(nullptr),
+ newTargetArg_(nullptr),
+ args_(alloc),
+ constructing_(constructing),
+ setter_(false)
+ { }
+
+ MOZ_MUST_USE bool init(CallInfo& callInfo) {
+ MOZ_ASSERT(constructing_ == callInfo.constructing());
+
+ fun_ = callInfo.fun();
+ thisArg_ = callInfo.thisArg();
+
+ if (constructing())
+ newTargetArg_ = callInfo.getNewTarget();
+
+ if (!args_.appendAll(callInfo.argv()))
+ return false;
+
+ return true;
+ }
+
+ MOZ_MUST_USE bool init(MBasicBlock* current, uint32_t argc) {
+ MOZ_ASSERT(args_.empty());
+
+ // Get the arguments in the right order
+ if (!args_.reserve(argc))
+ return false;
+
+ if (constructing())
+ setNewTarget(current->pop());
+
+ for (int32_t i = argc; i > 0; i--)
+ args_.infallibleAppend(current->peek(-i));
+ current->popn(argc);
+
+ // Get |this| and |fun|
+ setThis(current->pop());
+ setFun(current->pop());
+
+ return true;
+ }
+
+ void popFormals(MBasicBlock* current) {
+ current->popn(numFormals());
+ }
+
+ void pushFormals(MBasicBlock* current) {
+ current->push(fun());
+ current->push(thisArg());
+
+ for (uint32_t i = 0; i < argc(); i++)
+ current->push(getArg(i));
+
+ if (constructing())
+ current->push(getNewTarget());
+ }
+
+ uint32_t argc() const {
+ return args_.length();
+ }
+ uint32_t numFormals() const {
+ return argc() + 2 + constructing();
+ }
+
+ MOZ_MUST_USE bool setArgs(const MDefinitionVector& args) {
+ MOZ_ASSERT(args_.empty());
+ return args_.appendAll(args);
+ }
+
+ MDefinitionVector& argv() {
+ return args_;
+ }
+
+ const MDefinitionVector& argv() const {
+ return args_;
+ }
+
+ MDefinition* getArg(uint32_t i) const {
+ MOZ_ASSERT(i < argc());
+ return args_[i];
+ }
+
+ MDefinition* getArgWithDefault(uint32_t i, MDefinition* defaultValue) const {
+ if (i < argc())
+ return args_[i];
+
+ return defaultValue;
+ }
+
+ void setArg(uint32_t i, MDefinition* def) {
+ MOZ_ASSERT(i < argc());
+ args_[i] = def;
+ }
+
+ MDefinition* thisArg() const {
+ MOZ_ASSERT(thisArg_);
+ return thisArg_;
+ }
+
+ void setThis(MDefinition* thisArg) {
+ thisArg_ = thisArg;
+ }
+
+ bool constructing() const {
+ return constructing_;
+ }
+
+ void setNewTarget(MDefinition* newTarget) {
+ MOZ_ASSERT(constructing());
+ newTargetArg_ = newTarget;
+ }
+ MDefinition* getNewTarget() const {
+ MOZ_ASSERT(newTargetArg_);
+ return newTargetArg_;
+ }
+
+ bool isSetter() const {
+ return setter_;
+ }
+ void markAsSetter() {
+ setter_ = true;
+ }
+
+ MDefinition* fun() const {
+ MOZ_ASSERT(fun_);
+ return fun_;
+ }
+
+ void setFun(MDefinition* fun) {
+ fun_ = fun;
+ }
+
+ void setImplicitlyUsedUnchecked() {
+ fun_->setImplicitlyUsedUnchecked();
+ thisArg_->setImplicitlyUsedUnchecked();
+ if (newTargetArg_)
+ newTargetArg_->setImplicitlyUsedUnchecked();
+ for (uint32_t i = 0; i < argc(); i++)
+ getArg(i)->setImplicitlyUsedUnchecked();
+ }
+};
+
+bool NeedsPostBarrier(MDefinition* value);
+
+} // namespace jit
+} // namespace js
+
+#endif /* jit_IonBuilder_h */