michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- michael@0: * vim: set ts=8 sts=4 et sw=4 tw=99: michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef jit_IonBuilder_h michael@0: #define jit_IonBuilder_h michael@0: michael@0: #ifdef JS_ION michael@0: michael@0: // This file declares the data structures for building a MIRGraph from a michael@0: // JSScript. michael@0: michael@0: #include "jit/BytecodeAnalysis.h" michael@0: #include "jit/IonOptimizationLevels.h" michael@0: #include "jit/MIR.h" michael@0: #include "jit/MIRGenerator.h" michael@0: #include "jit/MIRGraph.h" michael@0: #include "jit/TypeDescrSet.h" michael@0: michael@0: namespace js { michael@0: namespace jit { michael@0: michael@0: class CodeGenerator; michael@0: class CallInfo; michael@0: class BaselineInspector; michael@0: class BaselineFrameInspector; michael@0: michael@0: // Records information about a baseline frame for compilation that is stable michael@0: // when later used off thread. michael@0: BaselineFrameInspector * michael@0: NewBaselineFrameInspector(TempAllocator *temp, BaselineFrame *frame, CompileInfo *info); michael@0: michael@0: class IonBuilder : public MIRGenerator michael@0: { michael@0: enum ControlStatus { michael@0: ControlStatus_Error, michael@0: ControlStatus_Abort, michael@0: ControlStatus_Ended, // There is no continuation/join point. michael@0: ControlStatus_Joined, // Created a join node. michael@0: ControlStatus_Jumped, // Parsing another branch at the same level. michael@0: ControlStatus_None // No control flow. michael@0: }; michael@0: michael@0: enum SetElemSafety { michael@0: // Normal write like a[b] = c. michael@0: SetElem_Normal, michael@0: michael@0: // Write due to UnsafePutElements: michael@0: // - assumed to be in bounds, michael@0: // - not checked for data races michael@0: SetElem_Unsafe, michael@0: }; michael@0: michael@0: struct DeferredEdge : public TempObject michael@0: { michael@0: MBasicBlock *block; michael@0: DeferredEdge *next; michael@0: michael@0: DeferredEdge(MBasicBlock *block, DeferredEdge *next) michael@0: : block(block), next(next) michael@0: { } michael@0: }; michael@0: michael@0: struct ControlFlowInfo { michael@0: // Entry in the cfgStack. michael@0: uint32_t cfgEntry; michael@0: michael@0: // Label that continues go to. michael@0: jsbytecode *continuepc; michael@0: michael@0: ControlFlowInfo(uint32_t cfgEntry, jsbytecode *continuepc) michael@0: : cfgEntry(cfgEntry), michael@0: continuepc(continuepc) michael@0: { } michael@0: }; michael@0: michael@0: // To avoid recursion, the bytecode analyzer uses a stack where each entry michael@0: // is a small state machine. As we encounter branches or jumps in the michael@0: // bytecode, we push information about the edges on the stack so that the michael@0: // CFG can be built in a tree-like fashion. michael@0: struct CFGState { michael@0: enum State { michael@0: IF_TRUE, // if() { }, no else. michael@0: IF_TRUE_EMPTY_ELSE, // if() { }, empty else michael@0: IF_ELSE_TRUE, // if() { X } else { } michael@0: IF_ELSE_FALSE, // if() { } else { X } michael@0: DO_WHILE_LOOP_BODY, // do { x } while () michael@0: DO_WHILE_LOOP_COND, // do { } while (x) michael@0: WHILE_LOOP_COND, // while (x) { } michael@0: WHILE_LOOP_BODY, // while () { x } michael@0: FOR_LOOP_COND, // for (; x;) { } michael@0: FOR_LOOP_BODY, // for (; ;) { x } michael@0: FOR_LOOP_UPDATE, // for (; ; x) { } michael@0: TABLE_SWITCH, // switch() { x } michael@0: COND_SWITCH_CASE, // switch() { case X: ... } michael@0: COND_SWITCH_BODY, // switch() { case ...: X } michael@0: AND_OR, // && x, || x michael@0: LABEL, // label: x michael@0: TRY // try { x } catch(e) { } michael@0: }; michael@0: michael@0: State state; // Current state of this control structure. michael@0: jsbytecode *stopAt; // Bytecode at which to stop the processing loop. michael@0: michael@0: // For if structures, this contains branch information. michael@0: union { michael@0: struct { michael@0: MBasicBlock *ifFalse; michael@0: jsbytecode *falseEnd; michael@0: MBasicBlock *ifTrue; // Set when the end of the true path is reached. michael@0: MTest *test; michael@0: } branch; michael@0: struct { michael@0: // Common entry point. michael@0: MBasicBlock *entry; michael@0: michael@0: // Whether OSR is being performed for this loop. michael@0: bool osr; michael@0: michael@0: // Position of where the loop body starts and ends. michael@0: jsbytecode *bodyStart; michael@0: jsbytecode *bodyEnd; michael@0: michael@0: // pc immediately after the loop exits. michael@0: jsbytecode *exitpc; michael@0: michael@0: // pc for 'continue' jumps. michael@0: jsbytecode *continuepc; michael@0: michael@0: // Common exit point. Created lazily, so it may be nullptr. michael@0: MBasicBlock *successor; michael@0: michael@0: // Deferred break and continue targets. michael@0: DeferredEdge *breaks; michael@0: DeferredEdge *continues; michael@0: michael@0: // Initial state, in case loop processing is restarted. michael@0: State initialState; michael@0: jsbytecode *initialPc; michael@0: jsbytecode *initialStopAt; michael@0: jsbytecode *loopHead; michael@0: michael@0: // For-loops only. michael@0: jsbytecode *condpc; michael@0: jsbytecode *updatepc; michael@0: jsbytecode *updateEnd; michael@0: } loop; michael@0: struct { michael@0: // pc immediately after the switch. michael@0: jsbytecode *exitpc; michael@0: michael@0: // Deferred break and continue targets. michael@0: DeferredEdge *breaks; michael@0: michael@0: // MIR instruction michael@0: MTableSwitch *ins; michael@0: michael@0: // The number of current successor that get mapped into a block. michael@0: uint32_t currentBlock; michael@0: michael@0: } tableswitch; michael@0: struct { michael@0: // Vector of body blocks to process after the cases. michael@0: FixedList *bodies; michael@0: michael@0: // When processing case statements, this counter points at the michael@0: // last uninitialized body. When processing bodies, this michael@0: // counter targets the next body to process. michael@0: uint32_t currentIdx; michael@0: michael@0: // Remember the block index of the default case. michael@0: jsbytecode *defaultTarget; michael@0: uint32_t defaultIdx; michael@0: michael@0: // Block immediately after the switch. michael@0: jsbytecode *exitpc; michael@0: DeferredEdge *breaks; michael@0: } condswitch; michael@0: struct { michael@0: DeferredEdge *breaks; michael@0: } label; michael@0: struct { michael@0: MBasicBlock *successor; michael@0: } try_; michael@0: }; michael@0: michael@0: inline bool isLoop() const { michael@0: switch (state) { michael@0: case DO_WHILE_LOOP_COND: michael@0: case DO_WHILE_LOOP_BODY: michael@0: case WHILE_LOOP_COND: michael@0: case WHILE_LOOP_BODY: michael@0: case FOR_LOOP_COND: michael@0: case FOR_LOOP_BODY: michael@0: case FOR_LOOP_UPDATE: michael@0: return true; michael@0: default: michael@0: return false; michael@0: } michael@0: } michael@0: michael@0: static CFGState If(jsbytecode *join, MTest *test); michael@0: static CFGState IfElse(jsbytecode *trueEnd, jsbytecode *falseEnd, MTest *test); michael@0: static CFGState AndOr(jsbytecode *join, MBasicBlock *joinStart); michael@0: static CFGState TableSwitch(jsbytecode *exitpc, MTableSwitch *ins); michael@0: static CFGState CondSwitch(IonBuilder *builder, jsbytecode *exitpc, jsbytecode *defaultTarget); michael@0: static CFGState Label(jsbytecode *exitpc); michael@0: static CFGState Try(jsbytecode *exitpc, MBasicBlock *successor); michael@0: }; michael@0: michael@0: static int CmpSuccessors(const void *a, const void *b); michael@0: michael@0: public: michael@0: IonBuilder(JSContext *analysisContext, CompileCompartment *comp, michael@0: const JitCompileOptions &options, TempAllocator *temp, michael@0: MIRGraph *graph, types::CompilerConstraintList *constraints, michael@0: BaselineInspector *inspector, CompileInfo *info, michael@0: const OptimizationInfo *optimizationInfo, BaselineFrameInspector *baselineFrame, michael@0: size_t inliningDepth = 0, uint32_t loopDepth = 0); michael@0: michael@0: bool build(); michael@0: bool buildInline(IonBuilder *callerBuilder, MResumePoint *callerResumePoint, michael@0: CallInfo &callInfo); michael@0: michael@0: private: michael@0: bool traverseBytecode(); michael@0: ControlStatus snoopControlFlow(JSOp op); michael@0: bool processIterators(); michael@0: bool inspectOpcode(JSOp op); michael@0: uint32_t readIndex(jsbytecode *pc); michael@0: JSAtom *readAtom(jsbytecode *pc); michael@0: bool abort(const char *message, ...); michael@0: void spew(const char *message); michael@0: michael@0: JSFunction *getSingleCallTarget(types::TemporaryTypeSet *calleeTypes); michael@0: bool getPolyCallTargets(types::TemporaryTypeSet *calleeTypes, bool constructing, michael@0: ObjectVector &targets, uint32_t maxTargets, bool *gotLambda); michael@0: michael@0: void popCfgStack(); michael@0: DeferredEdge *filterDeadDeferredEdges(DeferredEdge *edge); michael@0: bool processDeferredContinues(CFGState &state); michael@0: ControlStatus processControlEnd(); michael@0: ControlStatus processCfgStack(); michael@0: ControlStatus processCfgEntry(CFGState &state); michael@0: ControlStatus processIfEnd(CFGState &state); michael@0: ControlStatus processIfElseTrueEnd(CFGState &state); michael@0: ControlStatus processIfElseFalseEnd(CFGState &state); michael@0: ControlStatus processDoWhileBodyEnd(CFGState &state); michael@0: ControlStatus processDoWhileCondEnd(CFGState &state); michael@0: ControlStatus processWhileCondEnd(CFGState &state); michael@0: ControlStatus processWhileBodyEnd(CFGState &state); michael@0: ControlStatus processForCondEnd(CFGState &state); michael@0: ControlStatus processForBodyEnd(CFGState &state); michael@0: ControlStatus processForUpdateEnd(CFGState &state); michael@0: ControlStatus processNextTableSwitchCase(CFGState &state); michael@0: ControlStatus processCondSwitchCase(CFGState &state); michael@0: ControlStatus processCondSwitchBody(CFGState &state); michael@0: ControlStatus processSwitchBreak(JSOp op); michael@0: ControlStatus processSwitchEnd(DeferredEdge *breaks, jsbytecode *exitpc); michael@0: ControlStatus processAndOrEnd(CFGState &state); michael@0: ControlStatus processLabelEnd(CFGState &state); michael@0: ControlStatus processTryEnd(CFGState &state); michael@0: ControlStatus processReturn(JSOp op); michael@0: ControlStatus processThrow(); michael@0: ControlStatus processContinue(JSOp op); michael@0: ControlStatus processBreak(JSOp op, jssrcnote *sn); michael@0: ControlStatus maybeLoop(JSOp op, jssrcnote *sn); michael@0: bool pushLoop(CFGState::State state, jsbytecode *stopAt, MBasicBlock *entry, bool osr, michael@0: jsbytecode *loopHead, jsbytecode *initialPc, michael@0: jsbytecode *bodyStart, jsbytecode *bodyEnd, jsbytecode *exitpc, michael@0: jsbytecode *continuepc = nullptr); michael@0: bool analyzeNewLoopTypes(MBasicBlock *entry, jsbytecode *start, jsbytecode *end); michael@0: michael@0: MBasicBlock *addBlock(MBasicBlock *block, uint32_t loopDepth); michael@0: MBasicBlock *newBlock(MBasicBlock *predecessor, jsbytecode *pc); michael@0: MBasicBlock *newBlock(MBasicBlock *predecessor, jsbytecode *pc, uint32_t loopDepth); michael@0: MBasicBlock *newBlock(MBasicBlock *predecessor, jsbytecode *pc, MResumePoint *priorResumePoint); michael@0: MBasicBlock *newBlockPopN(MBasicBlock *predecessor, jsbytecode *pc, uint32_t popped); michael@0: MBasicBlock *newBlockAfter(MBasicBlock *at, MBasicBlock *predecessor, jsbytecode *pc); michael@0: MBasicBlock *newOsrPreheader(MBasicBlock *header, jsbytecode *loopEntry); michael@0: MBasicBlock *newPendingLoopHeader(MBasicBlock *predecessor, jsbytecode *pc, bool osr, bool canOsr, michael@0: unsigned stackPhiCount); michael@0: MBasicBlock *newBlock(jsbytecode *pc) { michael@0: return newBlock(nullptr, pc); michael@0: } michael@0: MBasicBlock *newBlockAfter(MBasicBlock *at, jsbytecode *pc) { michael@0: return newBlockAfter(at, nullptr, pc); michael@0: } michael@0: michael@0: // Given a list of pending breaks, creates a new block and inserts a Goto michael@0: // linking each break to the new block. michael@0: MBasicBlock *createBreakCatchBlock(DeferredEdge *edge, jsbytecode *pc); michael@0: michael@0: // Finishes loops that do not actually loop, containing only breaks and michael@0: // returns or a do while loop with a condition that is constant false. michael@0: ControlStatus processBrokenLoop(CFGState &state); michael@0: michael@0: // Computes loop phis, places them in all successors of a loop, then michael@0: // handles any pending breaks. michael@0: ControlStatus finishLoop(CFGState &state, MBasicBlock *successor); michael@0: michael@0: // Incorporates a type/typeSet into an OSR value for a loop, after the loop michael@0: // body has been processed. michael@0: bool addOsrValueTypeBarrier(uint32_t slot, MInstruction **def, michael@0: MIRType type, types::TemporaryTypeSet *typeSet); michael@0: bool maybeAddOsrTypeBarriers(); michael@0: michael@0: // Restarts processing of a loop if the type information at its header was michael@0: // incomplete. michael@0: ControlStatus restartLoop(CFGState state); michael@0: michael@0: void assertValidLoopHeadOp(jsbytecode *pc); michael@0: michael@0: ControlStatus forLoop(JSOp op, jssrcnote *sn); michael@0: ControlStatus whileOrForInLoop(jssrcnote *sn); michael@0: ControlStatus doWhileLoop(JSOp op, jssrcnote *sn); michael@0: ControlStatus tableSwitch(JSOp op, jssrcnote *sn); michael@0: ControlStatus condSwitch(JSOp op, jssrcnote *sn); michael@0: michael@0: // Please see the Big Honkin' Comment about how resume points work in michael@0: // IonBuilder.cpp, near the definition for this function. michael@0: bool resume(MInstruction *ins, jsbytecode *pc, MResumePoint::Mode mode); michael@0: bool resumeAt(MInstruction *ins, jsbytecode *pc); michael@0: bool resumeAfter(MInstruction *ins); michael@0: bool maybeInsertResume(); michael@0: michael@0: void insertRecompileCheck(); michael@0: michael@0: void initParameters(); michael@0: void rewriteParameter(uint32_t slotIdx, MDefinition *param, int32_t argIndex); michael@0: void rewriteParameters(); michael@0: bool initScopeChain(MDefinition *callee = nullptr); michael@0: bool initArgumentsObject(); michael@0: bool pushConstant(const Value &v); michael@0: michael@0: MConstant *constant(const Value &v); michael@0: MConstant *constantInt(int32_t i); michael@0: michael@0: // Filter the type information at tests michael@0: bool filterTypesAtTest(MTest *test); michael@0: michael@0: // Add a guard which ensure that the set of type which goes through this michael@0: // generated code correspond to the observed types for the bytecode. michael@0: bool pushTypeBarrier(MDefinition *def, types::TemporaryTypeSet *observed, bool needBarrier); michael@0: michael@0: // As pushTypeBarrier, but will compute the needBarrier boolean itself based michael@0: // on observed and the JSFunction that we're planning to call. The michael@0: // JSFunction must be a DOM method or getter. michael@0: bool pushDOMTypeBarrier(MInstruction *ins, types::TemporaryTypeSet *observed, JSFunction* func); michael@0: michael@0: // If definiteType is not known or def already has the right type, just michael@0: // returns def. Otherwise, returns an MInstruction that has that definite michael@0: // type, infallibly unboxing ins as needed. The new instruction will be michael@0: // added to |current| in this case. michael@0: MDefinition *ensureDefiniteType(MDefinition* def, MIRType definiteType); michael@0: michael@0: // Creates a MDefinition based on the given def improved with type as TypeSet. michael@0: MDefinition *ensureDefiniteTypeSet(MDefinition* def, types::TemporaryTypeSet *types); michael@0: michael@0: JSObject *getSingletonPrototype(JSFunction *target); michael@0: michael@0: MDefinition *createThisScripted(MDefinition *callee); michael@0: MDefinition *createThisScriptedSingleton(JSFunction *target, MDefinition *callee); michael@0: MDefinition *createThis(JSFunction *target, MDefinition *callee); michael@0: MInstruction *createDeclEnvObject(MDefinition *callee, MDefinition *scopeObj); michael@0: MInstruction *createCallObject(MDefinition *callee, MDefinition *scopeObj); michael@0: michael@0: MDefinition *walkScopeChain(unsigned hops); michael@0: michael@0: MInstruction *addConvertElementsToDoubles(MDefinition *elements); michael@0: MInstruction *addBoundsCheck(MDefinition *index, MDefinition *length); michael@0: MInstruction *addShapeGuard(MDefinition *obj, Shape *const shape, BailoutKind bailoutKind); michael@0: michael@0: MDefinition *convertShiftToMaskForStaticTypedArray(MDefinition *id, michael@0: ArrayBufferView::ViewType viewType); michael@0: michael@0: bool invalidatedIdempotentCache(); michael@0: michael@0: bool hasStaticScopeObject(ScopeCoordinate sc, JSObject **pcall); michael@0: bool loadSlot(MDefinition *obj, size_t slot, size_t nfixed, MIRType rvalType, michael@0: bool barrier, types::TemporaryTypeSet *types); michael@0: bool loadSlot(MDefinition *obj, Shape *shape, MIRType rvalType, michael@0: bool barrier, types::TemporaryTypeSet *types); michael@0: bool storeSlot(MDefinition *obj, size_t slot, size_t nfixed, michael@0: MDefinition *value, bool needsBarrier, michael@0: MIRType slotType = MIRType_None); michael@0: bool storeSlot(MDefinition *obj, Shape *shape, MDefinition *value, bool needsBarrier, michael@0: MIRType slotType = MIRType_None); michael@0: michael@0: // jsop_getprop() helpers. michael@0: bool getPropTryArgumentsLength(bool *emitted); michael@0: bool getPropTryConstant(bool *emitted, PropertyName *name, michael@0: types::TemporaryTypeSet *types); michael@0: bool getPropTryDefiniteSlot(bool *emitted, PropertyName *name, michael@0: bool barrier, types::TemporaryTypeSet *types); michael@0: bool getPropTryCommonGetter(bool *emitted, PropertyName *name, michael@0: types::TemporaryTypeSet *types); michael@0: bool getPropTryInlineAccess(bool *emitted, PropertyName *name, michael@0: bool barrier, types::TemporaryTypeSet *types); michael@0: bool getPropTryTypedObject(bool *emitted, PropertyName *name, michael@0: types::TemporaryTypeSet *resultTypes); michael@0: bool getPropTryScalarPropOfTypedObject(bool *emitted, michael@0: int32_t fieldOffset, michael@0: TypeDescrSet fieldTypeReprs, michael@0: types::TemporaryTypeSet *resultTypes); michael@0: bool getPropTryComplexPropOfTypedObject(bool *emitted, michael@0: int32_t fieldOffset, michael@0: TypeDescrSet fieldTypeReprs, michael@0: size_t fieldIndex, michael@0: types::TemporaryTypeSet *resultTypes); michael@0: bool getPropTryCache(bool *emitted, PropertyName *name, michael@0: bool barrier, types::TemporaryTypeSet *types); michael@0: bool needsToMonitorMissingProperties(types::TemporaryTypeSet *types); michael@0: michael@0: // jsop_setprop() helpers. michael@0: bool setPropTryCommonSetter(bool *emitted, MDefinition *obj, michael@0: PropertyName *name, MDefinition *value); michael@0: bool setPropTryCommonDOMSetter(bool *emitted, MDefinition *obj, michael@0: MDefinition *value, JSFunction *setter, michael@0: bool isDOM); michael@0: bool setPropTryDefiniteSlot(bool *emitted, MDefinition *obj, michael@0: PropertyName *name, MDefinition *value, michael@0: bool barrier, types::TemporaryTypeSet *objTypes); michael@0: bool setPropTryInlineAccess(bool *emitted, MDefinition *obj, michael@0: PropertyName *name, MDefinition *value, bool barrier, michael@0: types::TemporaryTypeSet *objTypes); michael@0: bool setPropTryTypedObject(bool *emitted, MDefinition *obj, michael@0: PropertyName *name, MDefinition *value); michael@0: bool setPropTryScalarPropOfTypedObject(bool *emitted, michael@0: MDefinition *obj, michael@0: int32_t fieldOffset, michael@0: MDefinition *value, michael@0: TypeDescrSet fieldTypeReprs); michael@0: bool setPropTryCache(bool *emitted, MDefinition *obj, michael@0: PropertyName *name, MDefinition *value, michael@0: bool barrier, types::TemporaryTypeSet *objTypes); michael@0: michael@0: // binary data lookup helpers. michael@0: bool lookupTypeDescrSet(MDefinition *typedObj, michael@0: TypeDescrSet *out); michael@0: bool typeSetToTypeDescrSet(types::TemporaryTypeSet *types, michael@0: TypeDescrSet *out); michael@0: bool lookupTypedObjectField(MDefinition *typedObj, michael@0: PropertyName *name, michael@0: int32_t *fieldOffset, michael@0: TypeDescrSet *fieldTypeReprs, michael@0: size_t *fieldIndex); michael@0: MDefinition *loadTypedObjectType(MDefinition *value); michael@0: void loadTypedObjectData(MDefinition *typedObj, michael@0: MDefinition *offset, michael@0: bool canBeNeutered, michael@0: MDefinition **owner, michael@0: MDefinition **ownerOffset); michael@0: void loadTypedObjectElements(MDefinition *typedObj, michael@0: MDefinition *offset, michael@0: int32_t unit, michael@0: bool canBeNeutered, michael@0: MDefinition **ownerElements, michael@0: MDefinition **ownerScaledOffset); michael@0: MDefinition *typeObjectForElementFromArrayStructType(MDefinition *typedObj); michael@0: MDefinition *typeObjectForFieldFromStructType(MDefinition *type, michael@0: size_t fieldIndex); michael@0: bool storeScalarTypedObjectValue(MDefinition *typedObj, michael@0: MDefinition *offset, michael@0: ScalarTypeDescr::Type type, michael@0: bool canBeNeutered, michael@0: bool racy, michael@0: MDefinition *value); michael@0: bool checkTypedObjectIndexInBounds(int32_t elemSize, michael@0: MDefinition *obj, michael@0: MDefinition *index, michael@0: TypeDescrSet objTypeDescrs, michael@0: MDefinition **indexAsByteOffset, michael@0: bool *canBeNeutered); michael@0: bool pushDerivedTypedObject(bool *emitted, michael@0: MDefinition *obj, michael@0: MDefinition *offset, michael@0: TypeDescrSet derivedTypeDescrs, michael@0: MDefinition *derivedTypeObj, michael@0: bool canBeNeutered); michael@0: bool pushScalarLoadFromTypedObject(bool *emitted, michael@0: MDefinition *obj, michael@0: MDefinition *offset, michael@0: ScalarTypeDescr::Type type, michael@0: bool canBeNeutered); michael@0: MDefinition *neuterCheck(MDefinition *obj); michael@0: michael@0: // jsop_setelem() helpers. michael@0: bool setElemTryTypedArray(bool *emitted, MDefinition *object, michael@0: MDefinition *index, MDefinition *value); michael@0: bool setElemTryTypedObject(bool *emitted, MDefinition *obj, michael@0: MDefinition *index, MDefinition *value); michael@0: bool setElemTryTypedStatic(bool *emitted, MDefinition *object, michael@0: MDefinition *index, MDefinition *value); michael@0: bool setElemTryDense(bool *emitted, MDefinition *object, michael@0: MDefinition *index, MDefinition *value); michael@0: bool setElemTryArguments(bool *emitted, MDefinition *object, michael@0: MDefinition *index, MDefinition *value); michael@0: bool setElemTryCache(bool *emitted, MDefinition *object, michael@0: MDefinition *index, MDefinition *value); michael@0: bool setElemTryScalarElemOfTypedObject(bool *emitted, michael@0: MDefinition *obj, michael@0: MDefinition *index, michael@0: TypeDescrSet objTypeReprs, michael@0: MDefinition *value, michael@0: TypeDescrSet elemTypeReprs, michael@0: int32_t elemSize); michael@0: michael@0: // jsop_getelem() helpers. michael@0: bool getElemTryDense(bool *emitted, MDefinition *obj, MDefinition *index); michael@0: bool getElemTryTypedStatic(bool *emitted, MDefinition *obj, MDefinition *index); michael@0: bool getElemTryTypedArray(bool *emitted, MDefinition *obj, MDefinition *index); michael@0: bool getElemTryTypedObject(bool *emitted, MDefinition *obj, MDefinition *index); michael@0: bool getElemTryString(bool *emitted, MDefinition *obj, MDefinition *index); michael@0: bool getElemTryArguments(bool *emitted, MDefinition *obj, MDefinition *index); michael@0: bool getElemTryArgumentsInlined(bool *emitted, MDefinition *obj, MDefinition *index); michael@0: bool getElemTryCache(bool *emitted, MDefinition *obj, MDefinition *index); michael@0: bool getElemTryScalarElemOfTypedObject(bool *emitted, michael@0: MDefinition *obj, michael@0: MDefinition *index, michael@0: TypeDescrSet objTypeReprs, michael@0: TypeDescrSet elemTypeReprs, michael@0: int32_t elemSize); michael@0: bool getElemTryComplexElemOfTypedObject(bool *emitted, michael@0: MDefinition *obj, michael@0: MDefinition *index, michael@0: TypeDescrSet objTypeReprs, michael@0: TypeDescrSet elemTypeReprs, michael@0: int32_t elemSize); michael@0: michael@0: enum BoundsChecking { DoBoundsCheck, SkipBoundsCheck }; michael@0: michael@0: // Add instructions to compute a typed array's length and data. Also michael@0: // optionally convert |*index| into a bounds-checked definition, if michael@0: // requested. michael@0: // michael@0: // If you only need the array's length, use addTypedArrayLength below. michael@0: void addTypedArrayLengthAndData(MDefinition *obj, michael@0: BoundsChecking checking, michael@0: MDefinition **index, michael@0: MInstruction **length, MInstruction **elements); michael@0: michael@0: // Add an instruction to compute a typed array's length to the current michael@0: // block. If you also need the typed array's data, use the above method michael@0: // instead. michael@0: MInstruction *addTypedArrayLength(MDefinition *obj) { michael@0: MInstruction *length; michael@0: addTypedArrayLengthAndData(obj, SkipBoundsCheck, nullptr, &length, nullptr); michael@0: return length; michael@0: } michael@0: michael@0: michael@0: MDefinition *getCallee(); michael@0: michael@0: bool jsop_add(MDefinition *left, MDefinition *right); michael@0: bool jsop_bitnot(); michael@0: bool jsop_bitop(JSOp op); michael@0: bool jsop_binary(JSOp op); michael@0: bool jsop_binary(JSOp op, MDefinition *left, MDefinition *right); michael@0: bool jsop_pos(); michael@0: bool jsop_neg(); michael@0: bool jsop_setarg(uint32_t arg); michael@0: bool jsop_defvar(uint32_t index); michael@0: bool jsop_deffun(uint32_t index); michael@0: bool jsop_notearg(); michael@0: bool jsop_funcall(uint32_t argc); michael@0: bool jsop_funapply(uint32_t argc); michael@0: bool jsop_funapplyarguments(uint32_t argc); michael@0: bool jsop_call(uint32_t argc, bool constructing); michael@0: bool jsop_eval(uint32_t argc); michael@0: bool jsop_ifeq(JSOp op); michael@0: bool jsop_try(); michael@0: bool jsop_label(); michael@0: bool jsop_condswitch(); michael@0: bool jsop_andor(JSOp op); michael@0: bool jsop_dup2(); michael@0: bool jsop_loophead(jsbytecode *pc); michael@0: bool jsop_compare(JSOp op); michael@0: bool getStaticName(JSObject *staticObject, PropertyName *name, bool *psucceeded); michael@0: bool setStaticName(JSObject *staticObject, PropertyName *name); michael@0: bool jsop_getgname(PropertyName *name); michael@0: bool jsop_getname(PropertyName *name); michael@0: bool jsop_intrinsic(PropertyName *name); michael@0: bool jsop_bindname(PropertyName *name); michael@0: bool jsop_getelem(); michael@0: bool jsop_getelem_dense(MDefinition *obj, MDefinition *index); michael@0: bool jsop_getelem_typed(MDefinition *obj, MDefinition *index, ScalarTypeDescr::Type arrayType); michael@0: bool jsop_setelem(); michael@0: bool jsop_setelem_dense(types::TemporaryTypeSet::DoubleConversion conversion, michael@0: SetElemSafety safety, michael@0: MDefinition *object, MDefinition *index, MDefinition *value); michael@0: bool jsop_setelem_typed(ScalarTypeDescr::Type arrayType, michael@0: SetElemSafety safety, michael@0: MDefinition *object, MDefinition *index, MDefinition *value); michael@0: bool jsop_setelem_typed_object(ScalarTypeDescr::Type arrayType, michael@0: SetElemSafety safety, bool racy, michael@0: MDefinition *object, MDefinition *index, MDefinition *value); michael@0: bool jsop_length(); michael@0: bool jsop_length_fastPath(); michael@0: bool jsop_arguments(); michael@0: bool jsop_arguments_length(); michael@0: bool jsop_arguments_getelem(); michael@0: bool jsop_runonce(); michael@0: bool jsop_rest(); michael@0: bool jsop_not(); michael@0: bool jsop_getprop(PropertyName *name); michael@0: bool jsop_setprop(PropertyName *name); michael@0: bool jsop_delprop(PropertyName *name); michael@0: bool jsop_delelem(); michael@0: bool jsop_newarray(uint32_t count); michael@0: bool jsop_newobject(); michael@0: bool jsop_initelem(); michael@0: bool jsop_initelem_array(); michael@0: bool jsop_initelem_getter_setter(); michael@0: bool jsop_mutateproto(); michael@0: bool jsop_initprop(PropertyName *name); michael@0: bool jsop_initprop_getter_setter(PropertyName *name); michael@0: bool jsop_regexp(RegExpObject *reobj); michael@0: bool jsop_object(JSObject *obj); michael@0: bool jsop_lambda(JSFunction *fun); michael@0: bool jsop_lambda_arrow(JSFunction *fun); michael@0: bool jsop_this(); michael@0: bool jsop_typeof(); michael@0: bool jsop_toid(); michael@0: bool jsop_iter(uint8_t flags); michael@0: bool jsop_iternext(); michael@0: bool jsop_itermore(); michael@0: bool jsop_iterend(); michael@0: bool jsop_in(); michael@0: bool jsop_in_dense(); michael@0: bool jsop_instanceof(); michael@0: bool jsop_getaliasedvar(ScopeCoordinate sc); michael@0: bool jsop_setaliasedvar(ScopeCoordinate sc); michael@0: michael@0: /* Inlining. */ michael@0: michael@0: enum InliningStatus michael@0: { michael@0: InliningStatus_Error, michael@0: InliningStatus_NotInlined, michael@0: InliningStatus_Inlined michael@0: }; michael@0: michael@0: enum InliningDecision michael@0: { michael@0: InliningDecision_Error, michael@0: InliningDecision_Inline, michael@0: InliningDecision_DontInline michael@0: }; michael@0: michael@0: static InliningDecision DontInline(JSScript *targetScript, const char *reason); michael@0: michael@0: // Oracles. michael@0: InliningDecision canInlineTarget(JSFunction *target, CallInfo &callInfo); michael@0: InliningDecision makeInliningDecision(JSFunction *target, CallInfo &callInfo); michael@0: bool selectInliningTargets(ObjectVector &targets, CallInfo &callInfo, michael@0: BoolVector &choiceSet, uint32_t *numInlineable); michael@0: michael@0: // Native inlining helpers. michael@0: types::TemporaryTypeSet *getInlineReturnTypeSet(); michael@0: MIRType getInlineReturnType(); michael@0: michael@0: // Array natives. michael@0: InliningStatus inlineArray(CallInfo &callInfo); michael@0: InliningStatus inlineArrayPopShift(CallInfo &callInfo, MArrayPopShift::Mode mode); michael@0: InliningStatus inlineArrayPush(CallInfo &callInfo); michael@0: InliningStatus inlineArrayConcat(CallInfo &callInfo); michael@0: InliningStatus inlineArraySplice(CallInfo &callInfo); michael@0: michael@0: // Math natives. michael@0: InliningStatus inlineMathAbs(CallInfo &callInfo); michael@0: InliningStatus inlineMathFloor(CallInfo &callInfo); michael@0: InliningStatus inlineMathCeil(CallInfo &callInfo); michael@0: InliningStatus inlineMathRound(CallInfo &callInfo); michael@0: InliningStatus inlineMathSqrt(CallInfo &callInfo); michael@0: InliningStatus inlineMathAtan2(CallInfo &callInfo); michael@0: InliningStatus inlineMathHypot(CallInfo &callInfo); michael@0: InliningStatus inlineMathMinMax(CallInfo &callInfo, bool max); michael@0: InliningStatus inlineMathPow(CallInfo &callInfo); michael@0: InliningStatus inlineMathRandom(CallInfo &callInfo); michael@0: InliningStatus inlineMathImul(CallInfo &callInfo); michael@0: InliningStatus inlineMathFRound(CallInfo &callInfo); michael@0: InliningStatus inlineMathFunction(CallInfo &callInfo, MMathFunction::Function function); michael@0: michael@0: // String natives. michael@0: InliningStatus inlineStringObject(CallInfo &callInfo); michael@0: InliningStatus inlineStringSplit(CallInfo &callInfo); michael@0: InliningStatus inlineStrCharCodeAt(CallInfo &callInfo); michael@0: InliningStatus inlineStrFromCharCode(CallInfo &callInfo); michael@0: InliningStatus inlineStrCharAt(CallInfo &callInfo); michael@0: InliningStatus inlineStrReplace(CallInfo &callInfo); michael@0: michael@0: // RegExp natives. michael@0: InliningStatus inlineRegExpExec(CallInfo &callInfo); michael@0: InliningStatus inlineRegExpTest(CallInfo &callInfo); michael@0: michael@0: // Array intrinsics. michael@0: InliningStatus inlineUnsafePutElements(CallInfo &callInfo); michael@0: bool inlineUnsafeSetDenseArrayElement(CallInfo &callInfo, uint32_t base); michael@0: bool inlineUnsafeSetTypedArrayElement(CallInfo &callInfo, uint32_t base, michael@0: ScalarTypeDescr::Type arrayType); michael@0: bool inlineUnsafeSetTypedObjectArrayElement(CallInfo &callInfo, uint32_t base, michael@0: ScalarTypeDescr::Type arrayType); michael@0: InliningStatus inlineNewDenseArray(CallInfo &callInfo); michael@0: InliningStatus inlineNewDenseArrayForSequentialExecution(CallInfo &callInfo); michael@0: InliningStatus inlineNewDenseArrayForParallelExecution(CallInfo &callInfo); michael@0: michael@0: // Slot intrinsics. michael@0: InliningStatus inlineUnsafeSetReservedSlot(CallInfo &callInfo); michael@0: InliningStatus inlineUnsafeGetReservedSlot(CallInfo &callInfo); michael@0: michael@0: // ForkJoin intrinsics michael@0: InliningStatus inlineForkJoinGetSlice(CallInfo &callInfo); michael@0: michael@0: // TypedObject intrinsics. michael@0: InliningStatus inlineObjectIsTypeDescr(CallInfo &callInfo); michael@0: InliningStatus inlineSetTypedObjectOffset(CallInfo &callInfo); michael@0: bool elementAccessIsTypedObjectArrayOfScalarType(MDefinition* obj, MDefinition* id, michael@0: ScalarTypeDescr::Type *arrayType); michael@0: michael@0: // Utility intrinsics. michael@0: InliningStatus inlineIsCallable(CallInfo &callInfo); michael@0: InliningStatus inlineHaveSameClass(CallInfo &callInfo); michael@0: InliningStatus inlineToObject(CallInfo &callInfo); michael@0: InliningStatus inlineDump(CallInfo &callInfo); michael@0: InliningStatus inlineHasClass(CallInfo &callInfo, const Class *clasp) { michael@0: return inlineHasClasses(callInfo, clasp, nullptr); michael@0: } michael@0: InliningStatus inlineHasClasses(CallInfo &callInfo, const Class *clasp1, const Class *clasp2); michael@0: michael@0: // Testing functions. michael@0: InliningStatus inlineForceSequentialOrInParallelSection(CallInfo &callInfo); michael@0: InliningStatus inlineBailout(CallInfo &callInfo); michael@0: InliningStatus inlineAssertFloat32(CallInfo &callInfo); michael@0: michael@0: // Bind function. michael@0: InliningStatus inlineBoundFunction(CallInfo &callInfo, JSFunction *target); michael@0: michael@0: // Main inlining functions michael@0: InliningStatus inlineNativeCall(CallInfo &callInfo, JSFunction *target); michael@0: bool inlineScriptedCall(CallInfo &callInfo, JSFunction *target); michael@0: InliningStatus inlineSingleCall(CallInfo &callInfo, JSFunction *target); michael@0: michael@0: // Call functions michael@0: InliningStatus inlineCallsite(ObjectVector &targets, ObjectVector &originals, michael@0: bool lambda, CallInfo &callInfo); michael@0: bool inlineCalls(CallInfo &callInfo, ObjectVector &targets, ObjectVector &originals, michael@0: BoolVector &choiceSet, MGetPropertyCache *maybeCache); michael@0: michael@0: // Inlining helpers. michael@0: bool inlineGenericFallback(JSFunction *target, CallInfo &callInfo, MBasicBlock *dispatchBlock, michael@0: bool clonedAtCallsite); michael@0: bool inlineTypeObjectFallback(CallInfo &callInfo, MBasicBlock *dispatchBlock, michael@0: MTypeObjectDispatch *dispatch, MGetPropertyCache *cache, michael@0: MBasicBlock **fallbackTarget); michael@0: michael@0: bool testNeedsArgumentCheck(JSFunction *target, CallInfo &callInfo); michael@0: michael@0: MDefinition *makeCallsiteClone(JSFunction *target, MDefinition *fun); michael@0: MCall *makeCallHelper(JSFunction *target, CallInfo &callInfo, bool cloneAtCallsite); michael@0: bool makeCall(JSFunction *target, CallInfo &callInfo, bool cloneAtCallsite); michael@0: michael@0: MDefinition *patchInlinedReturn(CallInfo &callInfo, MBasicBlock *exit, MBasicBlock *bottom); michael@0: MDefinition *patchInlinedReturns(CallInfo &callInfo, MIRGraphReturns &returns, michael@0: MBasicBlock *bottom); michael@0: michael@0: bool objectsHaveCommonPrototype(types::TemporaryTypeSet *types, PropertyName *name, michael@0: bool isGetter, JSObject *foundProto); michael@0: void freezePropertiesForCommonPrototype(types::TemporaryTypeSet *types, PropertyName *name, michael@0: JSObject *foundProto); michael@0: MDefinition *testCommonGetterSetter(types::TemporaryTypeSet *types, PropertyName *name, michael@0: bool isGetter, JSObject *foundProto, Shape *lastProperty); michael@0: bool testShouldDOMCall(types::TypeSet *inTypes, michael@0: JSFunction *func, JSJitInfo::OpType opType); michael@0: michael@0: bool annotateGetPropertyCache(MDefinition *obj, MGetPropertyCache *getPropCache, michael@0: types::TemporaryTypeSet *objTypes, michael@0: types::TemporaryTypeSet *pushedTypes); michael@0: michael@0: MGetPropertyCache *getInlineableGetPropertyCache(CallInfo &callInfo); michael@0: michael@0: JSObject *testSingletonProperty(JSObject *obj, PropertyName *name); michael@0: bool testSingletonPropertyTypes(MDefinition *obj, JSObject *singleton, PropertyName *name, michael@0: bool *testObject, bool *testString); michael@0: bool getDefiniteSlot(types::TemporaryTypeSet *types, PropertyName *name, michael@0: types::HeapTypeSetKey *property); michael@0: bool freezePropTypeSets(types::TemporaryTypeSet *types, michael@0: JSObject *foundProto, PropertyName *name); michael@0: michael@0: types::TemporaryTypeSet *bytecodeTypes(jsbytecode *pc); michael@0: michael@0: // Use one of the below methods for updating the current block, rather than michael@0: // updating |current| directly. setCurrent() should only be used in cases michael@0: // where the block cannot have phis whose type needs to be computed. michael@0: michael@0: bool setCurrentAndSpecializePhis(MBasicBlock *block) { michael@0: if (block) { michael@0: if (!block->specializePhis()) michael@0: return false; michael@0: } michael@0: setCurrent(block); michael@0: return true; michael@0: } michael@0: michael@0: void setCurrent(MBasicBlock *block) { michael@0: current = block; michael@0: } michael@0: michael@0: // A builder is inextricably tied to a particular script. michael@0: JSScript *script_; michael@0: michael@0: // If off thread compilation is successful, the final code generator is michael@0: // attached here. Code has been generated, but not linked (there is not yet michael@0: // an IonScript). This is heap allocated, and must be explicitly destroyed, michael@0: // performed by FinishOffThreadBuilder(). michael@0: CodeGenerator *backgroundCodegen_; michael@0: michael@0: public: michael@0: void clearForBackEnd(); michael@0: michael@0: JSScript *script() const { return script_; } michael@0: michael@0: CodeGenerator *backgroundCodegen() const { return backgroundCodegen_; } michael@0: void setBackgroundCodegen(CodeGenerator *codegen) { backgroundCodegen_ = codegen; } michael@0: michael@0: AbortReason abortReason() { return abortReason_; } michael@0: michael@0: TypeDescrSetHash *getOrCreateDescrSetHash(); // fallible michael@0: michael@0: types::CompilerConstraintList *constraints() { michael@0: return constraints_; michael@0: } michael@0: michael@0: bool isInlineBuilder() const { michael@0: return callerBuilder_ != nullptr; michael@0: } michael@0: michael@0: const JSAtomState &names() { return compartment->runtime()->names(); } michael@0: michael@0: private: michael@0: bool init(); michael@0: michael@0: JSContext *analysisContext; michael@0: BaselineFrameInspector *baselineFrame_; michael@0: AbortReason abortReason_; michael@0: TypeDescrSetHash *descrSetHash_; michael@0: michael@0: // Constraints for recording dependencies on type information. michael@0: types::CompilerConstraintList *constraints_; michael@0: michael@0: // Basic analysis information about the script. michael@0: BytecodeAnalysis analysis_; michael@0: BytecodeAnalysis &analysis() { michael@0: return analysis_; michael@0: } michael@0: michael@0: types::TemporaryTypeSet *thisTypes, *argTypes, *typeArray; michael@0: uint32_t typeArrayHint; michael@0: uint32_t *bytecodeTypeMap; michael@0: michael@0: GSNCache gsn; michael@0: ScopeCoordinateNameCache scopeCoordinateNameCache; michael@0: michael@0: jsbytecode *pc; michael@0: MBasicBlock *current; michael@0: uint32_t loopDepth_; michael@0: michael@0: /* Information used for inline-call builders. */ michael@0: MResumePoint *callerResumePoint_; michael@0: jsbytecode *callerPC() { michael@0: return callerResumePoint_ ? callerResumePoint_->pc() : nullptr; michael@0: } michael@0: IonBuilder *callerBuilder_; michael@0: michael@0: bool oom() { michael@0: abortReason_ = AbortReason_Alloc; michael@0: return false; michael@0: } michael@0: michael@0: struct LoopHeader { michael@0: jsbytecode *pc; michael@0: MBasicBlock *header; michael@0: michael@0: LoopHeader(jsbytecode *pc, MBasicBlock *header) michael@0: : pc(pc), header(header) michael@0: {} michael@0: }; michael@0: michael@0: Vector cfgStack_; michael@0: Vector loops_; michael@0: Vector switches_; michael@0: Vector labels_; michael@0: Vector iterators_; michael@0: Vector loopHeaders_; michael@0: BaselineInspector *inspector; michael@0: michael@0: size_t inliningDepth_; michael@0: michael@0: // Cutoff to disable compilation if excessive time is spent reanalyzing michael@0: // loop bodies to compute a fixpoint of the types for loop variables. michael@0: static const size_t MAX_LOOP_RESTARTS = 40; michael@0: size_t numLoopRestarts_; michael@0: michael@0: // True if script->failedBoundsCheck is set for the current script or michael@0: // an outer script. michael@0: bool failedBoundsCheck_; michael@0: michael@0: // True if script->failedShapeGuard is set for the current script or michael@0: // an outer script. michael@0: bool failedShapeGuard_; michael@0: michael@0: // Has an iterator other than 'for in'. michael@0: bool nonStringIteration_; michael@0: michael@0: // If this script can use a lazy arguments object, it will be pre-created michael@0: // here. michael@0: MInstruction *lazyArguments_; michael@0: michael@0: // If this is an inline builder, the call info for the builder. michael@0: const CallInfo *inlineCallInfo_; michael@0: }; michael@0: michael@0: class CallInfo michael@0: { michael@0: MDefinition *fun_; michael@0: MDefinition *thisArg_; michael@0: MDefinitionVector args_; michael@0: michael@0: bool constructing_; michael@0: bool setter_; michael@0: michael@0: public: michael@0: CallInfo(TempAllocator &alloc, bool constructing) michael@0: : fun_(nullptr), michael@0: thisArg_(nullptr), michael@0: args_(alloc), michael@0: constructing_(constructing), michael@0: setter_(false) michael@0: { } michael@0: michael@0: bool init(CallInfo &callInfo) { michael@0: JS_ASSERT(constructing_ == callInfo.constructing()); michael@0: michael@0: fun_ = callInfo.fun(); michael@0: thisArg_ = callInfo.thisArg(); michael@0: michael@0: if (!args_.appendAll(callInfo.argv())) michael@0: return false; michael@0: michael@0: return true; michael@0: } michael@0: michael@0: bool init(MBasicBlock *current, uint32_t argc) { michael@0: JS_ASSERT(args_.empty()); michael@0: michael@0: // Get the arguments in the right order michael@0: if (!args_.reserve(argc)) michael@0: return false; michael@0: for (int32_t i = argc; i > 0; i--) michael@0: args_.infallibleAppend(current->peek(-i)); michael@0: current->popn(argc); michael@0: michael@0: // Get |this| and |fun| michael@0: setThis(current->pop()); michael@0: setFun(current->pop()); michael@0: michael@0: return true; michael@0: } michael@0: michael@0: void popFormals(MBasicBlock *current) { michael@0: current->popn(numFormals()); michael@0: } michael@0: michael@0: void pushFormals(MBasicBlock *current) { michael@0: current->push(fun()); michael@0: current->push(thisArg()); michael@0: michael@0: for (uint32_t i = 0; i < argc(); i++) michael@0: current->push(getArg(i)); michael@0: } michael@0: michael@0: uint32_t argc() const { michael@0: return args_.length(); michael@0: } michael@0: uint32_t numFormals() const { michael@0: return argc() + 2; michael@0: } michael@0: michael@0: void setArgs(MDefinitionVector *args) { michael@0: JS_ASSERT(args_.empty()); michael@0: args_.appendAll(*args); michael@0: } michael@0: michael@0: MDefinitionVector &argv() { michael@0: return args_; michael@0: } michael@0: michael@0: const MDefinitionVector &argv() const { michael@0: return args_; michael@0: } michael@0: michael@0: MDefinition *getArg(uint32_t i) const { michael@0: JS_ASSERT(i < argc()); michael@0: return args_[i]; michael@0: } michael@0: michael@0: void setArg(uint32_t i, MDefinition *def) { michael@0: JS_ASSERT(i < argc()); michael@0: args_[i] = def; michael@0: } michael@0: michael@0: MDefinition *thisArg() const { michael@0: JS_ASSERT(thisArg_); michael@0: return thisArg_; michael@0: } michael@0: michael@0: void setThis(MDefinition *thisArg) { michael@0: thisArg_ = thisArg; michael@0: } michael@0: michael@0: bool constructing() const { michael@0: return constructing_; michael@0: } michael@0: michael@0: bool isSetter() const { michael@0: return setter_; michael@0: } michael@0: void markAsSetter() { michael@0: setter_ = true; michael@0: } michael@0: michael@0: MDefinition *fun() const { michael@0: JS_ASSERT(fun_); michael@0: return fun_; michael@0: } michael@0: michael@0: void setFun(MDefinition *fun) { michael@0: fun_ = fun; michael@0: } michael@0: michael@0: void setImplicitlyUsedUnchecked() { michael@0: fun_->setImplicitlyUsedUnchecked(); michael@0: thisArg_->setImplicitlyUsedUnchecked(); michael@0: for (uint32_t i = 0; i < argc(); i++) michael@0: getArg(i)->setImplicitlyUsedUnchecked(); michael@0: } michael@0: }; michael@0: michael@0: bool TypeSetIncludes(types::TypeSet *types, MIRType input, types::TypeSet *inputTypes); michael@0: michael@0: bool NeedsPostBarrier(CompileInfo &info, MDefinition *value); michael@0: michael@0: } // namespace jit michael@0: } // namespace js michael@0: michael@0: #endif // JS_ION michael@0: michael@0: #endif /* jit_IonBuilder_h */