#ifndef jit_IonBuilder_h
#define jit_IonBuilder_h
#include "mozilla/LinkedList.h"
#include "mozilla/Maybe.h"
#include "jit/BaselineInspector.h"
#include "jit/BytecodeAnalysis.h"
#include "jit/IonAnalysis.h"
#include "jit/IonControlFlow.h"
#include "jit/IonOptimizationLevels.h"
#include "jit/MIR.h"
#include "jit/MIRGenerator.h"
#include "jit/MIRGraph.h"
#include "jit/OptimizationTracking.h"
namespace js {
class TypedArrayObject;
namespace jit {
class CodeGenerator;
class CallInfo;
class BaselineFrameInspector;
enum class InlinableNative : uint16_t;
BaselineFrameInspector* NewBaselineFrameInspector(TempAllocator* temp,
BaselineFrame* frame);
using CallTargets = Vector<JSFunction*, 6, JitAllocPolicy>;
class IonBuilder : public MIRGenerator,
public mozilla::LinkedListElement<IonBuilder> {
public:
IonBuilder(JSContext* analysisContext, CompileRealm* realm,
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);
AbortReasonOr<Ok> build();
AbortReasonOr<Ok> buildInline(IonBuilder* callerBuilder,
MResumePoint* callerResumePoint,
CallInfo& callInfo);
mozilla::GenericErrorResult<AbortReason> abort(AbortReason r);
mozilla::GenericErrorResult<AbortReason> abort(AbortReason r,
const char* message, ...)
MOZ_FORMAT_PRINTF(3, 4);
private:
AbortReasonOr<Ok> traverseBytecode();
AbortReasonOr<Ok> processIterators();
AbortReasonOr<Ok> inspectOpcode(JSOp op);
uint32_t readIndex(jsbytecode* pc);
JSAtom* readAtom(jsbytecode* pc);
void trackActionableAbort(const char* message);
void spew(const char* message);
JSFunction* getSingleCallTarget(TemporaryTypeSet* calleeTypes);
AbortReasonOr<Ok> getPolyCallTargets(TemporaryTypeSet* calleeTypes,
bool constructing,
InliningTargets& targets,
uint32_t maxTargets);
AbortReasonOr<Ok> analyzeNewLoopTypes(const CFGBlock* loopEntryBlock);
AbortReasonOr<MBasicBlock*> newBlock(size_t stackDepth, jsbytecode* pc,
MBasicBlock* maybePredecessor = nullptr);
AbortReasonOr<MBasicBlock*> newBlock(MBasicBlock* predecessor, jsbytecode* pc,
MResumePoint* priorResumePoint);
AbortReasonOr<MBasicBlock*> newBlockPopN(MBasicBlock* predecessor,
jsbytecode* pc, uint32_t popped);
AbortReasonOr<MBasicBlock*> newBlockAfter(
MBasicBlock* at, size_t stackDepth, jsbytecode* pc,
MBasicBlock* maybePredecessor = nullptr);
AbortReasonOr<MBasicBlock*> newOsrPreheader(MBasicBlock* header,
jsbytecode* loopEntry,
jsbytecode* beforeLoopEntry);
AbortReasonOr<MBasicBlock*> newPendingLoopHeader(MBasicBlock* predecessor,
jsbytecode* pc, bool osr,
bool canOsr,
unsigned stackPhiCount);
AbortReasonOr<MBasicBlock*> newBlock(MBasicBlock* predecessor,
jsbytecode* pc) {
return newBlock(predecessor->stackDepth(), pc, predecessor);
}
AbortReasonOr<Ok> visitBlock(const CFGBlock* hblock, MBasicBlock* mblock);
AbortReasonOr<Ok> visitControlInstruction(CFGControlInstruction* ins,
bool* restarted);
AbortReasonOr<Ok> visitTest(CFGTest* test);
AbortReasonOr<Ok> visitCondSwitchCase(CFGCondSwitchCase* switchCase);
AbortReasonOr<Ok> visitLoopEntry(CFGLoopEntry* loopEntry);
AbortReasonOr<Ok> visitReturn(CFGControlInstruction* ins);
AbortReasonOr<Ok> visitGoto(CFGGoto* ins);
AbortReasonOr<Ok> visitBackEdge(CFGBackEdge* ins, bool* restarted);
AbortReasonOr<Ok> visitTry(CFGTry* test);
AbortReasonOr<Ok> visitThrow(CFGThrow* ins);
AbortReasonOr<Ok> visitTableSwitch(CFGTableSwitch* ins);
MTest* newTest(MDefinition* ins, MBasicBlock* ifTrue, MBasicBlock* ifFalse);
AbortReasonOr<Ok> addOsrValueTypeBarrier(uint32_t slot, MInstruction** def,
MIRType type,
TemporaryTypeSet* typeSet);
AbortReasonOr<Ok> maybeAddOsrTypeBarriers();
AbortReasonOr<Ok> restartLoop(const CFGBlock* header);
AbortReasonOr<Ok> resume(MInstruction* ins, jsbytecode* pc,
MResumePoint::Mode mode);
AbortReasonOr<Ok> resumeAt(MInstruction* ins, jsbytecode* pc);
AbortReasonOr<Ok> resumeAfter(MInstruction* ins);
AbortReasonOr<Ok> maybeInsertResume();
AbortReasonOr<Ok> emitGoto(CFGBlock* successor, size_t popAmount);
void insertRecompileCheck();
bool usesEnvironmentChain();
AbortReasonOr<Ok> initParameters();
void initLocals();
void rewriteParameter(uint32_t slotIdx, MDefinition* param);
AbortReasonOr<Ok> rewriteParameters();
AbortReasonOr<Ok> initEnvironmentChain(MDefinition* callee = nullptr);
void initArgumentsObject();
void pushConstant(const Value& v);
MConstant* constant(const Value& v);
MConstant* constantInt(int32_t i);
MInstruction* initializedLength(MDefinition* elements);
MInstruction* setInitializedLength(MDefinition* obj, size_t count);
AbortReasonOr<Ok> improveTypesAtTest(MDefinition* ins, bool trueBranch,
MTest* test);
AbortReasonOr<Ok> improveTypesAtCompare(MCompare* ins, bool trueBranch,
MTest* test);
AbortReasonOr<Ok> improveTypesAtNullOrUndefinedCompare(MCompare* ins,
bool trueBranch,
MTest* test);
AbortReasonOr<Ok> improveTypesAtTypeOfCompare(MCompare* ins, bool trueBranch,
MTest* test);
bool detectAndOrStructure(MPhi* ins, bool* branchIsTrue);
AbortReasonOr<Ok> replaceTypeSet(MDefinition* subject, TemporaryTypeSet* type,
MTest* test);
MDefinition* addTypeBarrier(MDefinition* def, TemporaryTypeSet* observed,
BarrierKind kind,
MTypeBarrier** pbarrier = nullptr);
AbortReasonOr<Ok> pushTypeBarrier(MDefinition* def,
TemporaryTypeSet* observed,
BarrierKind kind);
AbortReasonOr<Ok> pushDOMTypeBarrier(MInstruction* ins,
TemporaryTypeSet* observed,
JSFunction* func);
MDefinition* ensureDefiniteType(MDefinition* def, MIRType definiteType);
void maybeMarkEmpty(MDefinition* ins);
JSObject* getSingletonPrototype(JSFunction* target);
MDefinition* createThisScripted(MDefinition* callee, MDefinition* newTarget);
MDefinition* createThisScriptedSingleton(JSFunction* target);
MDefinition* createThisScriptedBaseline(MDefinition* callee);
MDefinition* createThis(JSFunction* target, MDefinition* callee,
MDefinition* newTarget);
MInstruction* createNamedLambdaObject(MDefinition* callee,
MDefinition* envObj);
AbortReasonOr<MInstruction*> createCallObject(MDefinition* callee,
MDefinition* envObj);
bool propertyIsConstantFunction(NativeObject* nobj, jsid id,
bool (*test)(IonBuilder* builder,
JSFunction* fun));
bool ensureArrayPrototypeIteratorNotModified();
bool ensureArrayIteratorPrototypeNextNotModified();
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);
bool invalidatedIdempotentCache();
AbortReasonOr<Ok> loadSlot(MDefinition* obj, size_t slot, size_t nfixed,
MIRType rvalType, BarrierKind barrier,
TemporaryTypeSet* types);
AbortReasonOr<Ok> loadSlot(MDefinition* obj, Shape* shape, MIRType rvalType,
BarrierKind barrier, TemporaryTypeSet* types);
AbortReasonOr<Ok> storeSlot(MDefinition* obj, size_t slot, size_t nfixed,
MDefinition* value, bool needsBarrier,
MIRType slotType = MIRType::None);
AbortReasonOr<Ok> 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);
AbortReasonOr<Ok> checkIsDefinitelyOptimizedArguments(MDefinition* obj,
bool* isOptimizedArgs);
AbortReasonOr<Ok> getPropTryInferredConstant(bool* emitted, MDefinition* obj,
PropertyName* name,
TemporaryTypeSet* types);
AbortReasonOr<Ok> getPropTryArgumentsLength(bool* emitted, MDefinition* obj);
AbortReasonOr<Ok> getPropTryArgumentsCallee(bool* emitted, MDefinition* obj,
PropertyName* name);
AbortReasonOr<Ok> getPropTryConstant(bool* emitted, MDefinition* obj, jsid id,
TemporaryTypeSet* types);
AbortReasonOr<Ok> getPropTryNotDefined(bool* emitted, MDefinition* obj,
jsid id, TemporaryTypeSet* types);
AbortReasonOr<Ok> getPropTryDefiniteSlot(bool* emitted, MDefinition* obj,
PropertyName* name,
BarrierKind barrier,
TemporaryTypeSet* types);
AbortReasonOr<Ok> getPropTryModuleNamespace(bool* emitted, MDefinition* obj,
PropertyName* name,
BarrierKind barrier,
TemporaryTypeSet* types);
AbortReasonOr<Ok> getPropTryUnboxed(bool* emitted, MDefinition* obj,
PropertyName* name, BarrierKind barrier,
TemporaryTypeSet* types);
AbortReasonOr<Ok> getPropTryCommonGetter(bool* emitted, MDefinition* obj,
jsid id, TemporaryTypeSet* types,
bool innerized = false);
AbortReasonOr<Ok> getPropTryInlineAccess(bool* emitted, MDefinition* obj,
PropertyName* name,
BarrierKind barrier,
TemporaryTypeSet* types);
AbortReasonOr<Ok> getPropTryInlineProtoAccess(bool* emitted, MDefinition* obj,
PropertyName* name,
TemporaryTypeSet* types);
AbortReasonOr<Ok> getPropTryTypedObject(bool* emitted, MDefinition* obj,
PropertyName* name);
AbortReasonOr<Ok> getPropTryScalarPropOfTypedObject(
bool* emitted, MDefinition* typedObj, int32_t fieldOffset,
TypedObjectPrediction fieldTypeReprs);
AbortReasonOr<Ok> getPropTryReferencePropOfTypedObject(
bool* emitted, MDefinition* typedObj, int32_t fieldOffset,
TypedObjectPrediction fieldPrediction, PropertyName* name);
AbortReasonOr<Ok> getPropTryComplexPropOfTypedObject(
bool* emitted, MDefinition* typedObj, int32_t fieldOffset,
TypedObjectPrediction fieldTypeReprs, size_t fieldIndex);
AbortReasonOr<Ok> getPropTryInnerize(bool* emitted, MDefinition* obj,
PropertyName* name,
TemporaryTypeSet* types);
AbortReasonOr<Ok> getPropAddCache(MDefinition* obj, PropertyName* name,
BarrierKind barrier,
TemporaryTypeSet* types);
AbortReasonOr<Ok> setPropTryCommonSetter(bool* emitted, MDefinition* obj,
PropertyName* name,
MDefinition* value);
AbortReasonOr<Ok> setPropTryCommonDOMSetter(bool* emitted, MDefinition* obj,
MDefinition* value,
JSFunction* setter,
TemporaryTypeSet* objTypes);
AbortReasonOr<Ok> setPropTryDefiniteSlot(bool* emitted, MDefinition* obj,
PropertyName* name,
MDefinition* value, bool barrier);
AbortReasonOr<Ok> setPropTryUnboxed(bool* emitted, MDefinition* obj,
PropertyName* name, MDefinition* value,
bool barrier);
AbortReasonOr<Ok> setPropTryInlineAccess(bool* emitted, MDefinition* obj,
PropertyName* name,
MDefinition* value, bool barrier,
TemporaryTypeSet* objTypes);
AbortReasonOr<Ok> setPropTryTypedObject(bool* emitted, MDefinition* obj,
PropertyName* name,
MDefinition* value);
AbortReasonOr<Ok> setPropTryReferencePropOfTypedObject(
bool* emitted, MDefinition* obj, int32_t fieldOffset, MDefinition* value,
TypedObjectPrediction fieldPrediction, PropertyName* name);
AbortReasonOr<Ok> setPropTryReferenceTypedObjectValue(
bool* emitted, MDefinition* typedObj, const LinearSum& byteOffset,
ReferenceType type, MDefinition* value, PropertyName* name);
AbortReasonOr<Ok> setPropTryScalarPropOfTypedObject(
bool* emitted, MDefinition* obj, int32_t fieldOffset, MDefinition* value,
TypedObjectPrediction fieldTypeReprs);
AbortReasonOr<Ok> setPropTryScalarTypedObjectValue(
bool* emitted, MDefinition* typedObj, const LinearSum& byteOffset,
ScalarTypeDescr::Type type, MDefinition* value);
AbortReasonOr<Ok> setPropTryCache(bool* emitted, MDefinition* obj,
PropertyName* name, MDefinition* value,
bool barrier);
MBinaryArithInstruction* binaryArithInstruction(JSOp op, MDefinition* left,
MDefinition* right);
MIRType binaryArithNumberSpecialization(MDefinition* left,
MDefinition* right);
AbortReasonOr<Ok> binaryArithTryConcat(bool* emitted, JSOp op,
MDefinition* left, MDefinition* right);
AbortReasonOr<MBinaryArithInstruction*> binaryArithEmitSpecialized(
MDefinition::Opcode op, MIRType specialization, MDefinition* left,
MDefinition* right);
AbortReasonOr<Ok> binaryArithTrySpecialized(bool* emitted, JSOp op,
MDefinition* left,
MDefinition* right);
AbortReasonOr<Ok> binaryArithTrySpecializedOnBaselineInspector(
bool* emitted, JSOp op, MDefinition* left, MDefinition* right);
AbortReasonOr<Ok> arithTryBinaryStub(bool* emitted, JSOp op,
MDefinition* left, MDefinition* right);
AbortReasonOr<Ok> bitnotTrySpecialized(bool* emitted, MDefinition* input);
MDefinition* unaryArithConvertToBinary(JSOp op, MDefinition::Opcode* defOp);
AbortReasonOr<Ok> unaryArithTrySpecialized(bool* emitted, JSOp op,
MDefinition* value);
AbortReasonOr<Ok> unaryArithTrySpecializedOnBaselineInspector(
bool* emitted, JSOp op, MDefinition* value);
AbortReasonOr<Ok> powTrySpecialized(bool* emitted, MDefinition* base,
MDefinition* power, MIRType outputType);
AbortReasonOr<Ok> compareTrySpecialized(bool* emitted, JSOp op,
MDefinition* left,
MDefinition* right);
AbortReasonOr<Ok> compareTryBitwise(bool* emitted, JSOp op, MDefinition* left,
MDefinition* right);
AbortReasonOr<Ok> compareTrySpecializedOnBaselineInspector(
bool* emitted, JSOp op, MDefinition* left, MDefinition* right);
AbortReasonOr<Ok> compareTryBinaryStub(bool* emitted, MDefinition* left,
MDefinition* right);
AbortReasonOr<Ok> compareTryCharacter(bool* emitted, JSOp op,
MDefinition* left, MDefinition* right);
AbortReasonOr<Ok> newArrayTryTemplateObject(bool* emitted,
JSObject* templateObject,
uint32_t length);
AbortReasonOr<Ok> newArrayTryVM(bool* emitted, JSObject* templateObject,
uint32_t length);
AbortReasonOr<Ok> newObjectTryTemplateObject(bool* emitted,
JSObject* templateObject);
AbortReasonOr<Ok> newObjectTryVM(bool* emitted, JSObject* templateObject);
AbortReasonOr<Ok> inTryDense(bool* emitted, MDefinition* obj,
MDefinition* id);
AbortReasonOr<Ok> hasTryNotDefined(bool* emitted, MDefinition* obj,
MDefinition* id, bool ownProperty);
AbortReasonOr<Ok> hasTryDefiniteSlotOrUnboxed(bool* emitted, MDefinition* obj,
MDefinition* id);
TypedObjectPrediction typedObjectPrediction(MDefinition* typedObj);
TypedObjectPrediction typedObjectPrediction(TemporaryTypeSet* types);
bool typedObjectHasField(MDefinition* typedObj, PropertyName* name,
size_t* fieldOffset,
TypedObjectPrediction* fieldTypeReprs,
size_t* fieldIndex, bool* fieldMutable);
MDefinition* loadTypedObjectType(MDefinition* value);
AbortReasonOr<Ok> loadTypedObjectData(MDefinition* typedObj,
MDefinition** owner,
LinearSum* ownerOffset);
AbortReasonOr<Ok> 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);
bool checkTypedObjectIndexInBounds(uint32_t elemSize, MDefinition* index,
TypedObjectPrediction objTypeDescrs,
LinearSum* indexAsByteOffset);
AbortReasonOr<Ok> pushDerivedTypedObject(
bool* emitted, MDefinition* obj, const LinearSum& byteOffset,
TypedObjectPrediction derivedTypeDescrs, MDefinition* derivedTypeObj);
AbortReasonOr<Ok> pushScalarLoadFromTypedObject(MDefinition* obj,
const LinearSum& byteoffset,
ScalarTypeDescr::Type type);
AbortReasonOr<Ok> pushReferenceLoadFromTypedObject(
MDefinition* typedObj, const LinearSum& byteOffset, ReferenceType type,
PropertyName* name);
AbortReasonOr<Ok> setElemTryTypedArray(bool* emitted, MDefinition* object,
MDefinition* index,
MDefinition* value);
AbortReasonOr<Ok> setElemTryTypedObject(bool* emitted, MDefinition* obj,
MDefinition* index,
MDefinition* value);
AbortReasonOr<Ok> initOrSetElemTryDense(bool* emitted, MDefinition* object,
MDefinition* index,
MDefinition* value, bool writeHole);
AbortReasonOr<Ok> setElemTryArguments(bool* emitted, MDefinition* object);
AbortReasonOr<Ok> initOrSetElemTryCache(bool* emitted, MDefinition* object,
MDefinition* index,
MDefinition* value);
AbortReasonOr<Ok> setElemTryReferenceElemOfTypedObject(
bool* emitted, MDefinition* obj, MDefinition* index,
TypedObjectPrediction objPrediction, MDefinition* value,
TypedObjectPrediction elemPrediction);
AbortReasonOr<Ok> setElemTryScalarElemOfTypedObject(
bool* emitted, MDefinition* obj, MDefinition* index,
TypedObjectPrediction objTypeReprs, MDefinition* value,
TypedObjectPrediction elemTypeReprs, uint32_t elemSize);
AbortReasonOr<Ok> initializeArrayElement(
MDefinition* obj, size_t index, MDefinition* value,
bool addResumePointAndIncrementInitializedLength);
AbortReasonOr<Ok> getElemTryDense(bool* emitted, MDefinition* obj,
MDefinition* index);
AbortReasonOr<Ok> getElemTryGetProp(bool* emitted, MDefinition* obj,
MDefinition* index);
AbortReasonOr<Ok> getElemTryTypedArray(bool* emitted, MDefinition* obj,
MDefinition* index);
AbortReasonOr<Ok> getElemTryCallSiteObject(bool* emitted, MDefinition* obj,
MDefinition* index);
AbortReasonOr<Ok> getElemTryTypedObject(bool* emitted, MDefinition* obj,
MDefinition* index);
AbortReasonOr<Ok> getElemTryString(bool* emitted, MDefinition* obj,
MDefinition* index);
AbortReasonOr<Ok> getElemTryArguments(bool* emitted, MDefinition* obj,
MDefinition* index);
AbortReasonOr<Ok> getElemTryArgumentsInlinedConstant(bool* emitted,
MDefinition* obj,
MDefinition* index);
AbortReasonOr<Ok> getElemTryArgumentsInlinedIndex(bool* emitted,
MDefinition* obj,
MDefinition* index);
AbortReasonOr<Ok> getElemAddCache(MDefinition* obj, MDefinition* index);
AbortReasonOr<Ok> getElemTryScalarElemOfTypedObject(
bool* emitted, MDefinition* obj, MDefinition* index,
TypedObjectPrediction objTypeReprs, TypedObjectPrediction elemTypeReprs,
uint32_t elemSize);
AbortReasonOr<Ok> getElemTryReferenceElemOfTypedObject(
bool* emitted, MDefinition* obj, MDefinition* index,
TypedObjectPrediction objPrediction,
TypedObjectPrediction elemPrediction);
AbortReasonOr<Ok> 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);
TypedArrayObject* tryTypedArrayEmbedConstantElements(MDefinition* obj);
void addTypedArrayLengthAndData(MDefinition* obj, BoundsChecking checking,
MDefinition** index, MInstruction** length,
MInstruction** elements);
MInstruction* addTypedArrayLength(MDefinition* obj) {
MInstruction* length;
addTypedArrayLengthAndData(obj, SkipBoundsCheck, nullptr, &length, nullptr);
return length;
}
MInstruction* addTypedArrayByteOffset(MDefinition* obj);
AbortReasonOr<Ok> improveThisTypesForCall();
MDefinition* getCallee();
MDefinition* getAliasedVar(EnvironmentCoordinate ec);
AbortReasonOr<MDefinition*> addLexicalCheck(MDefinition* input);
MDefinition* convertToBoolean(MDefinition* input);
AbortReasonOr<Ok> tryFoldInstanceOf(bool* emitted, MDefinition* lhs,
JSObject* protoObject);
AbortReasonOr<bool> hasOnProtoChain(TypeSet::ObjectKey* key,
JSObject* protoObject, bool* onProto);
AbortReasonOr<Ok> jsop_add(MDefinition* left, MDefinition* right);
AbortReasonOr<Ok> jsop_bitnot();
AbortReasonOr<Ok> jsop_bitop(JSOp op);
AbortReasonOr<Ok> jsop_binary_arith(JSOp op);
AbortReasonOr<Ok> jsop_binary_arith(JSOp op, MDefinition* left,
MDefinition* right);
AbortReasonOr<Ok> jsop_pow();
AbortReasonOr<Ok> jsop_pos();
AbortReasonOr<Ok> jsop_neg();
AbortReasonOr<Ok> jsop_tonumeric();
AbortReasonOr<Ok> jsop_inc_or_dec(JSOp op);
AbortReasonOr<Ok> jsop_tostring();
AbortReasonOr<Ok> jsop_setarg(uint32_t arg);
AbortReasonOr<Ok> jsop_defvar();
AbortReasonOr<Ok> jsop_deflexical();
AbortReasonOr<Ok> jsop_deffun();
AbortReasonOr<Ok> jsop_notearg();
AbortReasonOr<Ok> jsop_throwsetconst();
AbortReasonOr<Ok> jsop_checklexical();
AbortReasonOr<Ok> jsop_checkaliasedlexical(EnvironmentCoordinate ec);
AbortReasonOr<Ok> jsop_funcall(uint32_t argc);
AbortReasonOr<Ok> jsop_funapply(uint32_t argc);
AbortReasonOr<Ok> jsop_funapplyarguments(uint32_t argc);
AbortReasonOr<Ok> jsop_funapplyarray(uint32_t argc);
AbortReasonOr<Ok> jsop_spreadcall();
AbortReasonOr<Ok> jsop_optimize_spreadcall();
AbortReasonOr<Ok> jsop_call(uint32_t argc, bool constructing,
bool ignoresReturnValue);
AbortReasonOr<Ok> jsop_eval(uint32_t argc);
AbortReasonOr<Ok> jsop_label();
AbortReasonOr<Ok> jsop_andor(JSOp op);
AbortReasonOr<Ok> jsop_dup2();
AbortReasonOr<Ok> jsop_loopentry();
AbortReasonOr<Ok> jsop_loophead(jsbytecode* pc);
AbortReasonOr<Ok> jsop_compare(JSOp op);
AbortReasonOr<Ok> jsop_compare(JSOp op, MDefinition* left,
MDefinition* right);
AbortReasonOr<Ok> getStaticName(bool* emitted, JSObject* staticObject,
PropertyName* name,
MDefinition* lexicalCheck = nullptr);
AbortReasonOr<Ok> loadStaticSlot(JSObject* staticObject, BarrierKind barrier,
TemporaryTypeSet* types, uint32_t slot);
AbortReasonOr<Ok> setStaticName(JSObject* staticObject, PropertyName* name);
AbortReasonOr<Ok> jsop_getgname(PropertyName* name);
AbortReasonOr<Ok> jsop_getname(PropertyName* name);
AbortReasonOr<Ok> jsop_intrinsic(PropertyName* name);
AbortReasonOr<Ok> jsop_getimport(PropertyName* name);
AbortReasonOr<Ok> jsop_bindname(PropertyName* name);
AbortReasonOr<Ok> jsop_bindvar();
AbortReasonOr<Ok> jsop_getelem();
AbortReasonOr<Ok> jsop_getelem_dense(MDefinition* obj, MDefinition* index);
AbortReasonOr<Ok> jsop_getelem_typed(MDefinition* obj, MDefinition* index,
ScalarTypeDescr::Type arrayType);
AbortReasonOr<Ok> jsop_setelem();
AbortReasonOr<Ok> initOrSetElemDense(
TemporaryTypeSet::DoubleConversion conversion, MDefinition* object,
MDefinition* index, MDefinition* value, bool writeHole, bool* emitted);
AbortReasonOr<Ok> jsop_setelem_typed(ScalarTypeDescr::Type arrayType,
MDefinition* object, MDefinition* index,
MDefinition* value);
AbortReasonOr<Ok> jsop_length();
bool jsop_length_fastPath();
AbortReasonOr<Ok> jsop_arguments();
AbortReasonOr<Ok> jsop_arguments_getelem();
AbortReasonOr<Ok> jsop_rest();
AbortReasonOr<Ok> jsop_not();
AbortReasonOr<Ok> jsop_envcallee();
AbortReasonOr<Ok> jsop_superbase();
AbortReasonOr<Ok> jsop_getprop_super(PropertyName* name);
AbortReasonOr<Ok> jsop_getelem_super();
AbortReasonOr<Ok> jsop_getprop(PropertyName* name);
AbortReasonOr<Ok> jsop_setprop(PropertyName* name);
AbortReasonOr<Ok> jsop_delprop(PropertyName* name);
AbortReasonOr<Ok> jsop_delelem();
AbortReasonOr<Ok> jsop_newarray(uint32_t length);
AbortReasonOr<Ok> jsop_newarray(JSObject* templateObject, uint32_t length);
AbortReasonOr<Ok> jsop_newarray_copyonwrite();
AbortReasonOr<Ok> jsop_newobject();
AbortReasonOr<Ok> jsop_initelem();
AbortReasonOr<Ok> jsop_initelem_inc();
AbortReasonOr<Ok> jsop_initelem_array();
AbortReasonOr<Ok> jsop_initelem_getter_setter();
AbortReasonOr<Ok> jsop_mutateproto();
AbortReasonOr<Ok> jsop_initprop(PropertyName* name);
AbortReasonOr<Ok> jsop_initprop_getter_setter(PropertyName* name);
AbortReasonOr<Ok> jsop_regexp(RegExpObject* reobj);
AbortReasonOr<Ok> jsop_object(JSObject* obj);
AbortReasonOr<Ok> jsop_classconstructor();
AbortReasonOr<Ok> jsop_lambda(JSFunction* fun);
AbortReasonOr<Ok> jsop_lambda_arrow(JSFunction* fun);
AbortReasonOr<Ok> jsop_setfunname(uint8_t prefixKind);
AbortReasonOr<Ok> jsop_pushlexicalenv(uint32_t index);
AbortReasonOr<Ok> jsop_copylexicalenv(bool copySlots);
AbortReasonOr<Ok> jsop_functionthis();
AbortReasonOr<Ok> jsop_globalthis();
AbortReasonOr<Ok> jsop_typeof();
AbortReasonOr<Ok> jsop_toasync();
AbortReasonOr<Ok> jsop_toasynciter();
AbortReasonOr<Ok> jsop_toid();
AbortReasonOr<Ok> jsop_iter();
AbortReasonOr<Ok> jsop_itermore();
AbortReasonOr<Ok> jsop_isnoiter();
AbortReasonOr<Ok> jsop_iterend();
AbortReasonOr<Ok> jsop_iternext();
AbortReasonOr<Ok> jsop_in();
AbortReasonOr<Ok> jsop_hasown();
AbortReasonOr<Ok> jsop_instanceof();
AbortReasonOr<Ok> jsop_getaliasedvar(EnvironmentCoordinate ec);
AbortReasonOr<Ok> jsop_setaliasedvar(EnvironmentCoordinate ec);
AbortReasonOr<Ok> jsop_debugger();
AbortReasonOr<Ok> jsop_newtarget();
AbortReasonOr<Ok> jsop_checkisobj(uint8_t kind);
AbortReasonOr<Ok> jsop_checkiscallable(uint8_t kind);
AbortReasonOr<Ok> jsop_checkobjcoercible();
AbortReasonOr<Ok> jsop_pushcallobj();
AbortReasonOr<Ok> jsop_implicitthis(PropertyName* name);
AbortReasonOr<Ok> jsop_importmeta();
AbortReasonOr<Ok> jsop_dynamic_import();
enum InliningStatus {
InliningStatus_NotInlined,
InliningStatus_WarmUpCountTooLow,
InliningStatus_Inlined
};
using InliningResult = AbortReasonOr<InliningStatus>;
enum InliningDecision {
InliningDecision_Error,
InliningDecision_Inline,
InliningDecision_DontInline,
InliningDecision_WarmUpCountTooLow
};
static InliningDecision DontInline(JSScript* targetScript,
const char* reason);
bool hasCommonInliningPath(const JSScript* scriptToInline);
InliningDecision canInlineTarget(JSFunction* target, CallInfo& callInfo);
InliningDecision makeInliningDecision(JSObject* target, CallInfo& callInfo);
AbortReasonOr<Ok> selectInliningTargets(const InliningTargets& targets,
CallInfo& callInfo,
BoolVector& choiceSet,
uint32_t* numInlineable);
OptimizationLevel optimizationLevel() const {
return optimizationInfo().level();
}
bool isHighestOptimizationLevel() const {
return IonOptimizations.isLastLevel(optimizationLevel());
}
TemporaryTypeSet* getInlineReturnTypeSet();
MIRType getInlineReturnType();
InliningResult inlineArray(CallInfo& callInfo, Realm* targetRealm);
InliningResult inlineArrayIsArray(CallInfo& callInfo);
InliningResult inlineArrayPopShift(CallInfo& callInfo,
MArrayPopShift::Mode mode);
InliningResult inlineArrayPush(CallInfo& callInfo);
InliningResult inlineArraySlice(CallInfo& callInfo);
InliningResult inlineArrayJoin(CallInfo& callInfo);
InliningResult inlineBoolean(CallInfo& callInfo);
InliningResult inlineNewIterator(CallInfo& callInfo, MNewIterator::Type type);
InliningResult inlineArrayIteratorPrototypeOptimizable(CallInfo& callInfo);
InliningResult inlineMathAbs(CallInfo& callInfo);
InliningResult inlineMathFloor(CallInfo& callInfo);
InliningResult inlineMathCeil(CallInfo& callInfo);
InliningResult inlineMathClz32(CallInfo& callInfo);
InliningResult inlineMathRound(CallInfo& callInfo);
InliningResult inlineMathSqrt(CallInfo& callInfo);
InliningResult inlineMathAtan2(CallInfo& callInfo);
InliningResult inlineMathHypot(CallInfo& callInfo);
InliningResult inlineMathMinMax(CallInfo& callInfo, bool max);
InliningResult inlineMathPow(CallInfo& callInfo);
InliningResult inlineMathRandom(CallInfo& callInfo);
InliningResult inlineMathImul(CallInfo& callInfo);
InliningResult inlineMathFRound(CallInfo& callInfo);
InliningResult inlineMathTrunc(CallInfo& callInfo);
InliningResult inlineMathSign(CallInfo& callInfo);
InliningResult inlineMathFunction(CallInfo& callInfo,
MMathFunction::Function function);
InliningResult inlineStringObject(CallInfo& callInfo);
InliningResult inlineStrCharCodeAt(CallInfo& callInfo);
InliningResult inlineConstantCharCodeAt(CallInfo& callInfo);
InliningResult inlineStrFromCharCode(CallInfo& callInfo);
InliningResult inlineStrFromCodePoint(CallInfo& callInfo);
InliningResult inlineStrCharAt(CallInfo& callInfo);
InliningResult inlineStringConvertCase(CallInfo& callInfo,
MStringConvertCase::Mode mode);
InliningResult inlineStringReplaceString(CallInfo& callInfo);
InliningResult inlineConstantStringSplitString(CallInfo& callInfo);
InliningResult inlineStringSplitString(CallInfo& callInfo);
InliningResult inlineReflectGetPrototypeOf(CallInfo& callInfo);
InliningResult inlineRegExpMatcher(CallInfo& callInfo);
InliningResult inlineRegExpSearcher(CallInfo& callInfo);
InliningResult inlineRegExpTester(CallInfo& callInfo);
InliningResult inlineIsRegExpObject(CallInfo& callInfo);
InliningResult inlineRegExpPrototypeOptimizable(CallInfo& callInfo);
InliningResult inlineRegExpInstanceOptimizable(CallInfo& callInfo);
InliningResult inlineGetFirstDollarIndex(CallInfo& callInfo);
InliningResult inlineObject(CallInfo& callInfo);
InliningResult inlineObjectCreate(CallInfo& callInfo);
InliningResult inlineObjectIs(CallInfo& callInfo);
InliningResult inlineObjectToString(CallInfo& callInfo);
InliningResult inlineDefineDataProperty(CallInfo& callInfo);
InliningResult inlineAtomicsCompareExchange(CallInfo& callInfo);
InliningResult inlineAtomicsExchange(CallInfo& callInfo);
InliningResult inlineAtomicsLoad(CallInfo& callInfo);
InliningResult inlineAtomicsStore(CallInfo& callInfo);
InliningResult inlineAtomicsBinop(CallInfo& callInfo, InlinableNative target);
InliningResult inlineAtomicsIsLockFree(CallInfo& callInfo);
InliningResult inlineUnsafeSetReservedSlot(CallInfo& callInfo);
InliningResult inlineUnsafeGetReservedSlot(CallInfo& callInfo,
MIRType knownValueType);
InliningResult inlineGetNextEntryForIterator(
CallInfo& callInfo, MGetNextEntryForIterator::Mode mode);
InliningResult inlineArrayBufferByteLength(CallInfo& callInfo);
InliningResult inlinePossiblyWrappedArrayBufferByteLength(CallInfo& callInfo);
enum WrappingBehavior { AllowWrappedTypedArrays, RejectWrappedTypedArrays };
InliningResult inlineTypedArray(CallInfo& callInfo, Native native);
InliningResult inlineIsTypedArrayConstructor(CallInfo& callInfo);
InliningResult inlineIsTypedArrayHelper(CallInfo& callInfo,
WrappingBehavior wrappingBehavior);
InliningResult inlineIsTypedArray(CallInfo& callInfo);
InliningResult inlineIsPossiblyWrappedTypedArray(CallInfo& callInfo);
InliningResult inlineTypedArrayLength(CallInfo& callInfo);
InliningResult inlinePossiblyWrappedTypedArrayLength(CallInfo& callInfo);
InliningResult inlineTypedArrayByteOffset(CallInfo& callInfo);
InliningResult inlineTypedArrayElementShift(CallInfo& callInfo);
InliningResult inlineSetDisjointTypedElements(CallInfo& callInfo);
InliningResult inlineObjectIsTypeDescr(CallInfo& callInfo);
InliningResult inlineSetTypedObjectOffset(CallInfo& callInfo);
InliningResult inlineConstructTypedObject(CallInfo& callInfo,
TypeDescr* target);
InliningResult inlineIsCallable(CallInfo& callInfo);
InliningResult inlineIsConstructor(CallInfo& callInfo);
InliningResult inlineIsObject(CallInfo& callInfo);
InliningResult inlineToObject(CallInfo& callInfo);
InliningResult inlineIsCrossRealmArrayConstructor(CallInfo& callInfo);
InliningResult inlineToInteger(CallInfo& callInfo);
InliningResult inlineToString(CallInfo& callInfo);
InliningResult inlineDump(CallInfo& callInfo);
InliningResult inlineHasClass(CallInfo& callInfo, const Class* clasp,
const Class* clasp2 = nullptr,
const Class* clasp3 = nullptr,
const Class* clasp4 = nullptr);
InliningResult inlineGuardToClass(CallInfo& callInfo, const Class* clasp);
InliningResult inlineIsConstructing(CallInfo& callInfo);
InliningResult inlineSubstringKernel(CallInfo& callInfo);
InliningResult inlineObjectHasPrototype(CallInfo& callInfo);
InliningResult inlineFinishBoundFunctionInit(CallInfo& callInfo);
InliningResult inlineIsPackedArray(CallInfo& callInfo);
InliningResult inlineWasmCall(CallInfo& callInfo, JSFunction* target);
InliningResult inlineBailout(CallInfo& callInfo);
InliningResult inlineAssertFloat32(CallInfo& callInfo);
InliningResult inlineAssertRecoveredOnBailout(CallInfo& callInfo);
InliningResult inlineBoundFunction(CallInfo& callInfo, JSFunction* target);
InliningResult inlineNativeCall(CallInfo& callInfo, JSFunction* target);
InliningResult inlineNativeGetter(CallInfo& callInfo, JSFunction* target);
InliningResult inlineNonFunctionCall(CallInfo& callInfo, JSObject* target);
InliningResult inlineScriptedCall(CallInfo& callInfo, JSFunction* target);
InliningResult inlineSingleCall(CallInfo& callInfo, JSObject* target);
InliningResult inlineCallsite(const InliningTargets& targets,
CallInfo& callInfo);
AbortReasonOr<Ok> inlineCalls(CallInfo& callInfo,
const InliningTargets& targets,
BoolVector& choiceSet,
MGetPropertyCache* maybeCache);
AbortReasonOr<Ok> inlineGenericFallback(
const mozilla::Maybe<CallTargets>& targets, CallInfo& callInfo,
MBasicBlock* dispatchBlock);
AbortReasonOr<Ok> inlineObjectGroupFallback(
const mozilla::Maybe<CallTargets>& targets, CallInfo& callInfo,
MBasicBlock* dispatchBlock, MObjectGroupDispatch* dispatch,
MGetPropertyCache* cache, MBasicBlock** fallbackTarget);
enum AtomicCheckResult { DontCheckAtomicResult, DoCheckAtomicResult };
bool atomicsMeetsPreconditions(
CallInfo& callInfo, Scalar::Type* arrayElementType,
bool* requiresDynamicCheck,
AtomicCheckResult checkResult = DoCheckAtomicResult);
void atomicsCheckBounds(CallInfo& callInfo, MInstruction** elements,
MDefinition** index);
bool testNeedsArgumentCheck(JSFunction* target, CallInfo& callInfo);
AbortReasonOr<MCall*> makeCallHelper(
const mozilla::Maybe<CallTargets>& targets, CallInfo& callInfo);
AbortReasonOr<Ok> makeCall(const mozilla::Maybe<CallTargets>& targets,
CallInfo& callInfo);
AbortReasonOr<Ok> 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);
NativeObject* commonPrototypeWithGetterSetter(TemporaryTypeSet* types,
jsid id, bool isGetter,
JSFunction* getterOrSetter,
bool* guardGlobal);
AbortReasonOr<Ok> freezePropertiesForCommonPrototype(
TemporaryTypeSet* types, jsid id, JSObject* foundProto,
bool allowEmptyTypesForGlobal);
AbortReasonOr<bool> testCommonGetterSetter(
TemporaryTypeSet* types, jsid id, bool isGetter,
JSFunction* getterOrSetter, MDefinition** guard,
Shape* globalShape = nullptr, MDefinition** globalGuard = nullptr);
AbortReasonOr<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);
AbortReasonOr<Ok> 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);
AbortReasonOr<bool> testNotDefinedProperty(MDefinition* obj, jsid id,
bool ownProperty = false);
uint32_t getDefiniteSlot(TemporaryTypeSet* types, jsid id, uint32_t* pnfixed);
MDefinition* convertUnboxedObjects(MDefinition* obj);
MDefinition* convertUnboxedObjects(
MDefinition* obj, const BaselineInspector::ObjectGroupVector& list);
uint32_t getUnboxedOffset(TemporaryTypeSet* types, jsid id,
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);
AbortReasonOr<Ok> checkPreliminaryGroups(MDefinition* obj);
AbortReasonOr<Ok> freezePropTypeSets(TemporaryTypeSet* types,
JSObject* foundProto,
PropertyName* name);
bool canInlinePropertyOpShapes(
const BaselineInspector::ReceiverVector& receivers);
TemporaryTypeSet* bytecodeTypes(jsbytecode* pc);
AbortReasonOr<Ok> setCurrentAndSpecializePhis(MBasicBlock* block) {
if (block) {
if (!block->specializePhis(alloc())) {
return abort(AbortReason::Alloc);
}
}
setCurrent(block);
return Ok();
}
void setCurrent(MBasicBlock* block) { current = block; }
JSScript* script_;
bool scriptHasIonScript_;
CodeGenerator* backgroundCodegen_;
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 realm->runtime()->names(); }
bool hadActionableAbort() const {
MOZ_ASSERT(!actionableAbortScript_ ||
(actionableAbortPc_ && actionableAbortMessage_));
return actionableAbortScript_ != nullptr;
}
TraceLoggerThread* traceLogger() { return TraceLoggerForCurrentThread(); }
void actionableAbortLocationAndMessage(JSScript** abortScript,
jsbytecode** abortPc,
const char** abortMessage) {
MOZ_ASSERT(hadActionableAbort());
*abortScript = actionableAbortScript_;
*abortPc = actionableAbortPc_;
*abortMessage = actionableAbortMessage_;
}
void trace(JSTracer* trc);
private:
AbortReasonOr<Ok> init();
JSContext* analysisContext;
BaselineFrameInspector* baselineFrame_;
CompilerConstraintList* constraints_;
TemporaryTypeSet* thisTypes;
TemporaryTypeSet* argTypes;
TemporaryTypeSet* typeArray;
uint32_t typeArrayHint;
uint32_t* bytecodeTypeMap;
jsbytecode* pc;
MBasicBlock* current;
uint32_t loopDepth_;
Vector<MBasicBlock*, 0, JitAllocPolicy> blockWorklist;
const CFGBlock* cfgCurrent;
const ControlFlowGraph* cfg;
Vector<BytecodeSite*, 0, JitAllocPolicy> trackedOptimizationSites_;
BytecodeSite* bytecodeSite(jsbytecode* pc) {
MOZ_ASSERT(info().inlineScriptTree()->script()->containsPC(pc));
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;
}
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<MDefinition*, 2, JitAllocPolicy> iterators_;
Vector<LoopHeader, 0, JitAllocPolicy> loopHeaders_;
Vector<MBasicBlock*, 0, JitAllocPolicy> loopHeaderStack_;
#ifdef DEBUG
Vector<const CFGBlock*, 0, JitAllocPolicy> cfgLoopHeaderStack_;
#endif
BaselineInspector* inspector;
size_t inliningDepth_;
size_t inlinedBytecodeLength_;
static const size_t MAX_LOOP_RESTARTS = 40;
size_t numLoopRestarts_;
bool failedBoundsCheck_;
bool failedShapeGuard_;
bool failedLexicalCheck_;
#ifdef DEBUG
bool hasLazyArguments_;
#endif
const CallInfo* inlineCallInfo_;
void replaceMaybeFallbackFunctionGetter(MGetPropertyCache* cache);
void keepFallbackFunctionGetter(MGetPropertyCache* cache) {
if (cache == maybeFallbackFunctionGetter_) {
maybeFallbackFunctionGetter_ = nullptr;
}
}
MGetPropertyCache* maybeFallbackFunctionGetter_;
bool needsPostBarrier(MDefinition* value);
void startTrackingOptimizations();
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);
}
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);
public:
size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
};
class CallInfo {
MDefinition* fun_;
MDefinition* thisArg_;
MDefinition* newTargetArg_;
MDefinitionVector args_;
MDefinitionVector priorArgs_;
bool constructing_ : 1;
bool ignoresReturnValue_ : 1;
bool setter_ : 1;
bool apply_ : 1;
public:
CallInfo(TempAllocator& alloc, jsbytecode* pc, bool constructing,
bool ignoresReturnValue)
: fun_(nullptr),
thisArg_(nullptr),
newTargetArg_(nullptr),
args_(alloc),
priorArgs_(alloc),
constructing_(constructing),
ignoresReturnValue_(ignoresReturnValue),
setter_(false),
apply_(JSOp(*pc) == JSOP_FUNAPPLY) {}
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());
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);
setThis(current->pop());
setFun(current->pop());
return true;
}
AbortReasonOr<Ok> savePriorCallStack(MIRGenerator* mir, MBasicBlock* current,
size_t peekDepth);
void popPriorCallStack(MBasicBlock* current) {
if (priorArgs_.empty()) {
popCallStack(current);
} else {
current->popn(priorArgs_.length());
}
}
AbortReasonOr<Ok> pushPriorCallStack(MIRGenerator* mir,
MBasicBlock* current) {
if (priorArgs_.empty()) {
return pushCallStack(mir, current);
}
for (MDefinition* def : priorArgs_) {
current->push(def);
}
return Ok();
}
void popCallStack(MBasicBlock* current) { current->popn(numFormals()); }
AbortReasonOr<Ok> pushCallStack(MIRGenerator* mir, MBasicBlock* current) {
if (apply_) {
uint32_t depth = current->stackDepth() + numFormals();
if (depth > current->nslots()) {
if (!current->increaseSlots(depth - current->nslots())) {
return mir->abort(AbortReason::Alloc);
}
}
}
current->push(fun());
current->push(thisArg());
for (uint32_t i = 0; i < argc(); i++) {
current->push(getArg(i));
}
if (constructing()) {
current->push(getNewTarget());
}
return Ok();
}
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();
}
}
};
} }
#endif