1548 lines
72 KiB
C++
1548 lines
72 KiB
C++
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
|
* 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_call(uint32_t argc, bool constructing, bool ignoresReturnValue);
|
|
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_setfunname(uint8_t prefixKind);
|
|
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_toasyncgen();
|
|
MOZ_MUST_USE bool jsop_toasynciter();
|
|
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_checkiscallable(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);
|
|
|
|
// 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 inlineGuardToClass(CallInfo& callInfo, const Class* clasp);
|
|
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<MDefinition*, 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_:1;
|
|
|
|
// True if the caller does not use the return value.
|
|
bool ignoresReturnValue_:1;
|
|
|
|
bool setter_:1;
|
|
|
|
public:
|
|
CallInfo(TempAllocator& alloc, bool constructing, bool ignoresReturnValue)
|
|
: fun_(nullptr),
|
|
thisArg_(nullptr),
|
|
newTargetArg_(nullptr),
|
|
args_(alloc),
|
|
constructing_(constructing),
|
|
ignoresReturnValue_(ignoresReturnValue),
|
|
setter_(false)
|
|
{ }
|
|
|
|
MOZ_MUST_USE bool init(CallInfo& callInfo) {
|
|
MOZ_ASSERT(constructing_ == callInfo.constructing());
|
|
|
|
fun_ = callInfo.fun();
|
|
thisArg_ = callInfo.thisArg();
|
|
ignoresReturnValue_ = callInfo.ignoresReturnValue();
|
|
|
|
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_;
|
|
}
|
|
|
|
bool ignoresReturnValue() const {
|
|
return ignoresReturnValue_;
|
|
}
|
|
|
|
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 */
|