blob: e96a5f3a408bbd6a7c779312bafe55e44300efe6 [file] [log] [blame]
/* -*- 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
#ifdef JS_ION
// This file declares the data structures for building a MIRGraph from a
// JSScript.
#include "MIR.h"
#include "MIRGraph.h"
namespace js {
namespace jit {
class CodeGenerator;
class CallInfo;
class BaselineInspector;
class IonBuilder : public MIRGenerator
{
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.
};
enum SetElemSafety {
// Normal write like a[b] = c.
SetElem_Normal,
// Write due to UnsafeSetElement:
// - assumed to be in bounds,
// - not checked for data races
SetElem_Unsafe,
};
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
};
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.
} 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 NULL.
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;
};
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, MBasicBlock *ifFalse);
static CFGState IfElse(jsbytecode *trueEnd, jsbytecode *falseEnd, MBasicBlock *ifFalse);
static CFGState AndOr(jsbytecode *join, MBasicBlock *joinStart);
static CFGState TableSwitch(jsbytecode *exitpc, MTableSwitch *ins);
static CFGState CondSwitch(jsbytecode *exitpc, jsbytecode *defaultTarget);
static CFGState Label(jsbytecode *exitpc);
};
static int CmpSuccessors(const void *a, const void *b);
public:
IonBuilder(JSContext *cx, TempAllocator *temp, MIRGraph *graph,
BaselineInspector *inspector, CompileInfo *info, BaselineFrame *baselineFrame,
size_t inliningDepth = 0, uint32_t loopDepth = 0);
bool build();
bool buildInline(IonBuilder *callerBuilder, MResumePoint *callerResumePoint,
CallInfo &callInfo);
private:
bool traverseBytecode();
ControlStatus snoopControlFlow(JSOp op);
bool processIterators();
bool inspectOpcode(JSOp op);
uint32_t readIndex(jsbytecode *pc);
JSAtom *readAtom(jsbytecode *pc);
bool abort(const char *message, ...);
void spew(const char *message);
static bool inliningEnabled() {
return js_IonOptions.inlining;
}
JSFunction *getSingleCallTarget(types::StackTypeSet *calleeTypes);
bool getPolyCallTargets(types::StackTypeSet *calleeTypes,
AutoObjectVector &targets,
uint32_t maxTargets,
bool *gotLambda);
bool canInlineTarget(JSFunction *target);
void popCfgStack();
DeferredEdge *filterDeadDeferredEdges(DeferredEdge *edge);
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 processReturn(JSOp op);
ControlStatus processThrow();
ControlStatus processContinue(JSOp op);
ControlStatus processBreak(JSOp op, jssrcnote *sn);
ControlStatus maybeLoop(JSOp op, jssrcnote *sn);
bool pushLoop(CFGState::State state, jsbytecode *stopAt, MBasicBlock *entry, bool osr,
jsbytecode *loopHead, jsbytecode *initialPc,
jsbytecode *bodyStart, jsbytecode *bodyEnd, jsbytecode *exitpc,
jsbytecode *continuepc = NULL);
void 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);
MBasicBlock *newPendingLoopHeader(MBasicBlock *predecessor, jsbytecode *pc, bool osr);
MBasicBlock *newBlock(jsbytecode *pc) {
return newBlock(NULL, pc);
}
MBasicBlock *newBlockAfter(MBasicBlock *at, jsbytecode *pc) {
return newBlockAfter(at, NULL, pc);
}
// 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 or
// returns.
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.
bool addOsrValueTypeBarrier(uint32_t slot, MInstruction **def,
MIRType type, types::StackTypeSet *typeSet);
bool maybeAddOsrTypeBarriers();
// Restarts processing of a loop if the type information at its header was
// incomplete.
ControlStatus restartLoop(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.
bool resume(MInstruction *ins, jsbytecode *pc, MResumePoint::Mode mode);
bool resumeAt(MInstruction *ins, jsbytecode *pc);
bool resumeAfter(MInstruction *ins);
bool maybeInsertResume();
bool initParameters();
void rewriteParameter(uint32_t slotIdx, MDefinition *param, int32_t argIndex);
void rewriteParameters();
bool initScopeChain(MDefinition *callee = NULL);
bool initArgumentsObject();
bool pushConstant(const Value &v);
// Add a guard which ensure that the set of type which goes through this
// generated code correspond to the observed types for the bytecode.
bool pushTypeBarrier(MInstruction *ins, types::StackTypeSet *observed, bool needBarrier);
JSObject *getSingletonPrototype(JSFunction *target);
MDefinition *createThisScripted(MDefinition *callee);
MDefinition *createThisScriptedSingleton(HandleFunction target, MDefinition *callee);
MDefinition *createThis(HandleFunction target, MDefinition *callee);
MInstruction *createDeclEnvObject(MDefinition *callee, MDefinition *scopeObj);
MInstruction *createCallObject(MDefinition *callee, MDefinition *scopeObj);
MDefinition *walkScopeChain(unsigned hops);
MInstruction *addConvertElementsToDoubles(MDefinition *elements);
MInstruction *addBoundsCheck(MDefinition *index, MDefinition *length);
MInstruction *addShapeGuard(MDefinition *obj, Shape *const shape, BailoutKind bailoutKind);
JSObject *getNewArrayTemplateObject(uint32_t count);
MDefinition *convertShiftToMaskForStaticTypedArray(MDefinition *id,
ArrayBufferView::ViewType viewType);
bool invalidatedIdempotentCache();
bool hasStaticScopeObject(ScopeCoordinate sc, MutableHandleObject pcall);
bool loadSlot(MDefinition *obj, Shape *shape, MIRType rvalType,
bool barrier, types::StackTypeSet *types);
bool storeSlot(MDefinition *obj, Shape *shape, MDefinition *value, bool needsBarrier,
MIRType slotType = MIRType_None);
// jsop_getprop() helpers.
bool getPropTryArgumentsLength(bool *emitted);
bool getPropTryConstant(bool *emitted, HandleId id, types::StackTypeSet *types);
bool getPropTryDefiniteSlot(bool *emitted, HandlePropertyName name,
bool barrier, types::StackTypeSet *types);
bool getPropTryCommonGetter(bool *emitted, HandleId id,
bool barrier, types::StackTypeSet *types);
bool getPropTryInlineAccess(bool *emitted, HandlePropertyName name, HandleId id,
bool barrier, types::StackTypeSet *types);
bool getPropTryCache(bool *emitted, HandlePropertyName name, HandleId id,
bool barrier, types::StackTypeSet *types);
// Typed array helpers.
MInstruction *getTypedArrayLength(MDefinition *obj);
MInstruction *getTypedArrayElements(MDefinition *obj);
bool jsop_add(MDefinition *left, MDefinition *right);
bool jsop_bitnot();
bool jsop_bitop(JSOp op);
bool jsop_binary(JSOp op);
bool jsop_binary(JSOp op, MDefinition *left, MDefinition *right);
bool jsop_pos();
bool jsop_neg();
bool jsop_defvar(uint32_t index);
bool jsop_deffun(uint32_t index);
bool jsop_notearg();
bool jsop_funcall(uint32_t argc);
bool jsop_funapply(uint32_t argc);
bool jsop_funapplyarguments(uint32_t argc);
bool jsop_call(uint32_t argc, bool constructing);
bool jsop_eval(uint32_t argc);
bool jsop_ifeq(JSOp op);
bool jsop_label();
bool jsop_condswitch();
bool jsop_andor(JSOp op);
bool jsop_dup2();
bool jsop_loophead(jsbytecode *pc);
bool jsop_compare(JSOp op);
bool getStaticName(HandleObject staticObject, HandlePropertyName name, bool *psucceeded);
bool setStaticName(HandleObject staticObject, HandlePropertyName name);
bool jsop_getname(HandlePropertyName name);
bool jsop_intrinsic(HandlePropertyName name);
bool jsop_bindname(PropertyName *name);
bool jsop_getelem();
bool jsop_getelem_dense();
bool jsop_getelem_typed(int arrayType);
bool jsop_getelem_typed_static(bool *psucceeded);
bool jsop_getelem_string();
bool jsop_setelem();
bool jsop_setelem_dense(types::StackTypeSet::DoubleConversion conversion,
SetElemSafety safety,
MDefinition *object, MDefinition *index, MDefinition *value);
bool jsop_setelem_typed(int arrayType,
SetElemSafety safety,
MDefinition *object, MDefinition *index, MDefinition *value);
bool jsop_setelem_typed_static(MDefinition *object, MDefinition *index, MDefinition *value,
bool *psucceeded);
bool jsop_length();
bool jsop_length_fastPath();
bool jsop_arguments();
bool jsop_arguments_length();
bool jsop_arguments_getelem();
bool jsop_arguments_setelem(MDefinition *object, MDefinition *index, MDefinition *value);
bool jsop_runonce();
bool jsop_rest();
bool jsop_not();
bool jsop_getprop(HandlePropertyName name);
bool jsop_setprop(HandlePropertyName name);
bool jsop_delprop(HandlePropertyName name);
bool jsop_newarray(uint32_t count);
bool jsop_newobject(HandleObject baseObj);
bool jsop_initelem();
bool jsop_initelem_array();
bool jsop_initprop(HandlePropertyName name);
bool jsop_regexp(RegExpObject *reobj);
bool jsop_object(JSObject *obj);
bool jsop_lambda(JSFunction *fun);
bool jsop_this();
bool jsop_typeof();
bool jsop_toid();
bool jsop_iter(uint8_t flags);
bool jsop_iternext();
bool jsop_itermore();
bool jsop_iterend();
bool jsop_in();
bool jsop_in_dense();
bool jsop_instanceof();
bool jsop_getaliasedvar(ScopeCoordinate sc);
bool jsop_setaliasedvar(ScopeCoordinate sc);
/* Inlining. */
enum InliningStatus
{
InliningStatus_Error,
InliningStatus_NotInlined,
InliningStatus_Inlined
};
// Oracles.
bool canEnterInlinedFunction(JSFunction *target);
bool makeInliningDecision(JSFunction *target, CallInfo &callInfo);
uint32_t selectInliningTargets(AutoObjectVector &targets, CallInfo &callInfo, Vector<bool> &choiceSet);
// Native inlining helpers.
types::StackTypeSet *getInlineReturnTypeSet();
MIRType getInlineReturnType();
// Array natives.
InliningStatus inlineArray(CallInfo &callInfo);
InliningStatus inlineArrayPopShift(CallInfo &callInfo, MArrayPopShift::Mode mode);
InliningStatus inlineArrayPush(CallInfo &callInfo);
InliningStatus inlineArrayConcat(CallInfo &callInfo);
// Math natives.
InliningStatus inlineMathAbs(CallInfo &callInfo);
InliningStatus inlineMathFloor(CallInfo &callInfo);
InliningStatus inlineMathRound(CallInfo &callInfo);
InliningStatus inlineMathSqrt(CallInfo &callInfo);
InliningStatus inlineMathAtan2(CallInfo &callInfo);
InliningStatus inlineMathMinMax(CallInfo &callInfo, bool max);
InliningStatus inlineMathPow(CallInfo &callInfo);
InliningStatus inlineMathRandom(CallInfo &callInfo);
InliningStatus inlineMathImul(CallInfo &callInfo);
InliningStatus inlineMathFunction(CallInfo &callInfo, MMathFunction::Function function);
// String natives.
InliningStatus inlineStringObject(CallInfo &callInfo);
InliningStatus inlineStrCharCodeAt(CallInfo &callInfo);
InliningStatus inlineStrFromCharCode(CallInfo &callInfo);
InliningStatus inlineStrCharAt(CallInfo &callInfo);
// RegExp natives.
InliningStatus inlineRegExpTest(CallInfo &callInfo);
// Array intrinsics.
InliningStatus inlineUnsafeSetElement(CallInfo &callInfo);
bool inlineUnsafeSetDenseArrayElement(CallInfo &callInfo, uint32_t base);
bool inlineUnsafeSetTypedArrayElement(CallInfo &callInfo, uint32_t base, int arrayType);
InliningStatus inlineNewDenseArray(CallInfo &callInfo);
InliningStatus inlineNewDenseArrayForSequentialExecution(CallInfo &callInfo);
InliningStatus inlineNewDenseArrayForParallelExecution(CallInfo &callInfo);
// Slot intrinsics.
InliningStatus inlineUnsafeSetReservedSlot(CallInfo &callInfo);
InliningStatus inlineUnsafeGetReservedSlot(CallInfo &callInfo);
// Parallel intrinsics.
InliningStatus inlineForceSequentialOrInParallelSection(CallInfo &callInfo);
InliningStatus inlineNewParallelArray(CallInfo &callInfo);
InliningStatus inlineParallelArray(CallInfo &callInfo);
InliningStatus inlineParallelArrayTail(CallInfo &callInfo,
HandleFunction target,
MDefinition *ctor,
types::StackTypeSet *ctorTypes,
uint32_t discards);
// Utility intrinsics.
InliningStatus inlineThrowError(CallInfo &callInfo);
InliningStatus inlineIsCallable(CallInfo &callInfo);
InliningStatus inlineNewObjectWithClassPrototype(CallInfo &callInfo);
InliningStatus inlineHaveSameClass(CallInfo &callInfo);
InliningStatus inlineToObject(CallInfo &callInfo);
InliningStatus inlineDump(CallInfo &callInfo);
// Main inlining functions
InliningStatus inlineNativeCall(CallInfo &callInfo, JSNative native);
bool inlineScriptedCall(CallInfo &callInfo, JSFunction *target);
InliningStatus inlineSingleCall(CallInfo &callInfo, JSFunction *target);
// Call functions
InliningStatus inlineCallsite(AutoObjectVector &targets, AutoObjectVector &originals,
bool lambda, CallInfo &callInfo);
bool inlineCalls(CallInfo &callInfo, AutoObjectVector &targets, AutoObjectVector &originals,
Vector<bool> &choiceSet, MGetPropertyCache *maybeCache);
// Inlining helpers.
bool inlineGenericFallback(JSFunction *target, CallInfo &callInfo, MBasicBlock *dispatchBlock,
bool clonedAtCallsite);
bool inlineTypeObjectFallback(CallInfo &callInfo, MBasicBlock *dispatchBlock,
MTypeObjectDispatch *dispatch, MGetPropertyCache *cache,
MBasicBlock **fallbackTarget);
bool anyFunctionIsCloneAtCallsite(types::StackTypeSet *funTypes);
MDefinition *makeCallsiteClone(HandleFunction target, MDefinition *fun);
MCall *makeCallHelper(HandleFunction target, CallInfo &callInfo, bool cloneAtCallsite);
bool makeCall(HandleFunction target, CallInfo &callInfo, bool cloneAtCallsite);
MDefinition *patchInlinedReturn(CallInfo &callInfo, MBasicBlock *exit, MBasicBlock *bottom);
MDefinition *patchInlinedReturns(CallInfo &callInfo, MIRGraphExits &exits, MBasicBlock *bottom);
inline bool TestCommonPropFunc(JSContext *cx, types::StackTypeSet *types,
HandleId id, JSFunction **funcp,
bool isGetter, bool *isDOM,
MDefinition **guardOut);
bool annotateGetPropertyCache(JSContext *cx, MDefinition *obj, MGetPropertyCache *getPropCache,
types::StackTypeSet *objTypes, types::StackTypeSet *pushedTypes);
MGetPropertyCache *getInlineableGetPropertyCache(CallInfo &callInfo);
MPolyInlineDispatch *
makePolyInlineDispatch(JSContext *cx, CallInfo &callInfo,
MGetPropertyCache *getPropCache, MBasicBlock *bottom,
Vector<MDefinition *, 8, IonAllocPolicy> &retvalDefns);
types::StackTypeSet *cloneTypeSet(types::StackTypeSet *types);
// 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.
void setCurrentAndSpecializePhis(MBasicBlock *block) {
if (block)
block->specializePhis();
setCurrent(block);
}
void setCurrent(MBasicBlock *block) {
current = block;
}
// A builder is inextricably tied to a particular script.
HeapPtrScript script_;
// 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_;
public:
// Compilation index for this attempt.
types::RecompileInfo const recompileInfo;
void clearForBackEnd();
JSScript *script() const { return script_.get(); }
CodeGenerator *backgroundCodegen() const { return backgroundCodegen_; }
void setBackgroundCodegen(CodeGenerator *codegen) { backgroundCodegen_ = codegen; }
AbortReason abortReason() { return abortReason_; }
private:
JSContext *cx;
BaselineFrame *baselineFrame_;
AbortReason abortReason_;
jsbytecode *pc;
MBasicBlock *current;
uint32_t loopDepth_;
/* Information used for inline-call builders. */
MResumePoint *callerResumePoint_;
jsbytecode *callerPC() {
return callerResumePoint_ ? callerResumePoint_->pc() : NULL;
}
IonBuilder *callerBuilder_;
Vector<CFGState, 8, IonAllocPolicy> cfgStack_;
Vector<ControlFlowInfo, 4, IonAllocPolicy> loops_;
Vector<ControlFlowInfo, 0, IonAllocPolicy> switches_;
Vector<ControlFlowInfo, 2, IonAllocPolicy> labels_;
Vector<MInstruction *, 2, IonAllocPolicy> iterators_;
BaselineInspector *inspector;
size_t inliningDepth_;
// 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 = 20;
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_;
// 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_;
};
class CallInfo
{
MDefinition *fun_;
MDefinition *thisArg_;
Vector<MDefinition *> args_;
bool constructing_;
bool lambda_;
public:
CallInfo(JSContext *cx, bool constructing)
: fun_(NULL),
thisArg_(NULL),
args_(cx),
constructing_(constructing)
{ }
bool init(CallInfo &callInfo) {
JS_ASSERT(constructing_ == callInfo.constructing());
fun_ = callInfo.fun();
thisArg_ = callInfo.thisArg();
if (!args_.append(callInfo.argv().begin(), callInfo.argv().end()))
return false;
return true;
}
bool init(MBasicBlock *current, uint32_t argc) {
JS_ASSERT(args_.length() == 0);
// Get the arguments in the right order
if (!args_.reserve(argc))
return false;
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));
}
uint32_t argc() const {
return args_.length();
}
uint32_t numFormals() const {
return argc() + 2;
}
void setArgs(Vector<MDefinition *> *args) {
JS_ASSERT(args_.length() == 0);
args_.append(args->begin(), args->end());
}
Vector<MDefinition *> &argv() {
return args_;
}
const Vector<MDefinition *> &argv() const {
return args_;
}
MDefinition *getArg(uint32_t i) {
JS_ASSERT(i < argc());
return args_[i];
}
void setArg(uint32_t i, MDefinition *def) {
JS_ASSERT(i < argc());
args_[i] = def;
}
MDefinition *thisArg() {
JS_ASSERT(thisArg_);
return thisArg_;
}
void setThis(MDefinition *thisArg) {
thisArg_ = thisArg;
}
bool constructing() {
return constructing_;
}
bool isLambda() const {
return lambda_;
}
void setLambda(bool lambda) {
lambda_ = lambda;
}
void wrapArgs(MBasicBlock *current) {
thisArg_ = wrap(current, thisArg_);
for (uint32_t i = 0; i < argc(); i++)
args_[i] = wrap(current, args_[i]);
}
void unwrapArgs() {
thisArg_ = unwrap(thisArg_);
for (uint32_t i = 0; i < argc(); i++)
args_[i] = unwrap(args_[i]);
}
MDefinition *fun() const {
JS_ASSERT(fun_);
return fun_;
}
void setFun(MDefinition *fun) {
JS_ASSERT(!fun->isPassArg());
fun_ = fun;
}
bool isWrapped() {
bool wrapped = thisArg()->isPassArg();
#if DEBUG
for (uint32_t i = 0; i < argc(); i++)
JS_ASSERT(args_[i]->isPassArg() == wrapped);
#endif
return wrapped;
}
private:
static MDefinition *unwrap(MDefinition *arg) {
JS_ASSERT(arg->isPassArg());
MPassArg *passArg = arg->toPassArg();
MBasicBlock *block = passArg->block();
MDefinition *wrapped = passArg->getArgument();
wrapped->setFoldedUnchecked();
passArg->replaceAllUsesWith(wrapped);
block->discard(passArg);
return wrapped;
}
static MDefinition *wrap(MBasicBlock *current, MDefinition *arg) {
JS_ASSERT(!arg->isPassArg());
MPassArg *passArg = MPassArg::New(arg);
current->add(passArg);
return passArg;
}
};
bool TypeSetIncludes(types::TypeSet *types, MIRType input, types::TypeSet *inputTypes);
bool NeedsPostBarrier(CompileInfo &info, MDefinition *value);
} // namespace jit
} // namespace js
#endif // JS_ION
#endif /* jit_IonBuilder_h */