#ifndef jit_CacheIR_h
#define jit_CacheIR_h
#include "mozilla/Maybe.h"
#include "NamespaceImports.h"
#include "gc/Rooting.h"
#include "jit/CompactBuffer.h"
#include "jit/ICState.h"
#include "jit/MacroAssembler.h"
#include "vm/Iteration.h"
#include "vm/Shape.h"
namespace js {
namespace jit {
enum class BaselineCacheIRStubKind;
class OperandId {
protected:
static const uint16_t InvalidId = UINT16_MAX;
uint16_t id_;
OperandId() : id_(InvalidId) {}
explicit OperandId(uint16_t id) : id_(id) {}
public:
uint16_t id() const { return id_; }
bool valid() const { return id_ != InvalidId; }
};
class ValOperandId : public OperandId {
public:
ValOperandId() = default;
explicit ValOperandId(uint16_t id) : OperandId(id) {}
};
class ValueTagOperandId : public OperandId {
public:
ValueTagOperandId() = default;
explicit ValueTagOperandId(uint16_t id) : OperandId(id) {}
};
class ObjOperandId : public OperandId {
public:
ObjOperandId() = default;
explicit ObjOperandId(uint16_t id) : OperandId(id) {}
bool operator==(const ObjOperandId& other) const { return id_ == other.id_; }
bool operator!=(const ObjOperandId& other) const { return id_ != other.id_; }
};
class StringOperandId : public OperandId {
public:
StringOperandId() = default;
explicit StringOperandId(uint16_t id) : OperandId(id) {}
};
class SymbolOperandId : public OperandId {
public:
SymbolOperandId() = default;
explicit SymbolOperandId(uint16_t id) : OperandId(id) {}
};
class BigIntOperandId : public OperandId {
public:
BigIntOperandId() = default;
explicit BigIntOperandId(uint16_t id) : OperandId(id) {}
};
class Int32OperandId : public OperandId {
public:
Int32OperandId() = default;
explicit Int32OperandId(uint16_t id) : OperandId(id) {}
};
class TypedOperandId : public OperandId {
JSValueType type_;
public:
MOZ_IMPLICIT TypedOperandId(ObjOperandId id)
: OperandId(id.id()), type_(JSVAL_TYPE_OBJECT) {}
MOZ_IMPLICIT TypedOperandId(StringOperandId id)
: OperandId(id.id()), type_(JSVAL_TYPE_STRING) {}
MOZ_IMPLICIT TypedOperandId(SymbolOperandId id)
: OperandId(id.id()), type_(JSVAL_TYPE_SYMBOL) {}
MOZ_IMPLICIT TypedOperandId(BigIntOperandId id)
: OperandId(id.id()), type_(JSVAL_TYPE_BIGINT) {}
MOZ_IMPLICIT TypedOperandId(Int32OperandId id)
: OperandId(id.id()), type_(JSVAL_TYPE_INT32) {}
MOZ_IMPLICIT TypedOperandId(ValueTagOperandId val)
: OperandId(val.id()), type_(JSVAL_TYPE_UNKNOWN) {}
TypedOperandId(ValOperandId val, JSValueType type)
: OperandId(val.id()), type_(type) {}
JSValueType type() const { return type_; }
};
#define CACHE_IR_KINDS(_) \
_(GetProp) \
_(GetElem) \
_(GetName) \
_(GetPropSuper) \
_(GetElemSuper) \
_(GetIntrinsic) \
_(SetProp) \
_(SetElem) \
_(BindName) \
_(In) \
_(HasOwn) \
_(TypeOf) \
_(InstanceOf) \
_(GetIterator) \
_(Compare) \
_(ToBool) \
_(Call) \
_(UnaryArith) \
_(BinaryArith) \
_(NewObject)
enum class CacheKind : uint8_t {
#define DEFINE_KIND(kind) kind,
CACHE_IR_KINDS(DEFINE_KIND)
#undef DEFINE_KIND
};
extern const char* const CacheKindNames[];
namespace CacheIROpFormat {
enum ArgType {
None,
Id,
Field,
Byte,
Int32,
UInt32,
Word,
};
extern const uint32_t OpLengths[];
}
#define CACHE_IR_OPS(_) \
_(GuardIsObject, Id) \
_(GuardIsObjectOrNull, Id) \
_(GuardIsNullOrUndefined, Id) \
_(GuardIsNotNullOrUndefined, Id) \
_(GuardIsNull, Id) \
_(GuardIsUndefined, Id) \
_(GuardIsBoolean, Id, Id) \
_(GuardIsString, Id) \
_(GuardIsSymbol, Id) \
_(GuardIsBigInt, Id) \
_(GuardIsNumber, Id) \
_(GuardIsInt32, Id, Id) \
_(GuardIsInt32Index, Id, Id) \
_(GuardType, Id, Byte) \
_(GuardShape, Id, Field) \
_(GuardGroup, Id, Field) \
_(GuardProto, Id, Field) \
_(GuardClass, Id, Byte) \
_(GuardAnyClass, Id, Field) \
_(GuardCompartment, Id, Field, Field) \
_(GuardIsExtensible, Id) \
_(GuardIsNativeFunction, Id, Word) \
_(GuardIsNativeObject, Id) \
_(GuardIsProxy, Id) \
_(GuardHasProxyHandler, Id, Field) \
_(GuardNotDOMProxy, Id) \
_(GuardSpecificObject, Id, Field) \
_(GuardSpecificAtom, Id, Field) \
_(GuardSpecificSymbol, Id, Field) \
_(GuardSpecificInt32Immediate, Id, Int32, Byte) \
_(GuardNoDetachedTypedObjects, None) \
_(GuardMagicValue, Id, Byte) \
_(GuardFrameHasNoArgumentsObject, None) \
_(GuardNoDenseElements, Id) \
_(GuardNoUnboxedExpando, Id) \
_(GuardAndLoadUnboxedExpando, Id, Id) \
_(GuardAndGetIndexFromString, Id, Id) \
_(GuardAndGetNumberFromString, Id, Id) \
_(GuardAndGetIterator, Id, Id, Field, Field) \
_(GuardHasGetterSetter, Id, Field) \
_(GuardGroupHasUnanalyzedNewScript, Field) \
_(GuardIndexIsNonNegative, Id) \
_(GuardIndexGreaterThanDenseCapacity, Id, Id) \
_(GuardIndexGreaterThanArrayLength, Id, Id) \
_(GuardIndexIsValidUpdateOrAdd, Id, Id) \
_(GuardIndexGreaterThanDenseInitLength, Id, Id) \
_(GuardTagNotEqual, Id, Id) \
_(GuardXrayExpandoShapeAndDefaultProto, Id, Byte, Field) \
_(GuardFunctionPrototype, Id, Id, Field) \
_(GuardNoAllocationMetadataBuilder, None) \
_(GuardObjectGroupNotPretenured, Field) \
_(LoadStackValue, Id, UInt32) \
_(LoadObject, Id, Field) \
_(LoadProto, Id, Id) \
_(LoadEnclosingEnvironment, Id, Id) \
_(LoadWrapperTarget, Id, Id) \
_(LoadValueTag, Id, Id) \
\
_(TruncateDoubleToUInt32, Id, Id) \
\
_(MegamorphicLoadSlotResult, Id, Field, Byte) \
_(MegamorphicLoadSlotByValueResult, Id, Id, Byte) \
_(MegamorphicStoreSlot, Id, Field, Id, Byte) \
_(MegamorphicSetElement, Id, Id, Id, Byte) \
_(MegamorphicHasPropResult, Id, Id, Byte) \
\
\
_(LoadDOMExpandoValue, Id, Id) \
_(LoadDOMExpandoValueGuardGeneration, Id, Field, Field, Id) \
_(LoadDOMExpandoValueIgnoreGeneration, Id, Id) \
_(GuardDOMExpandoMissingOrGuardShape, Id, Field) \
\
_(StoreFixedSlot, Id, Field, Id) \
_(StoreDynamicSlot, Id, Field, Id) \
_(AddAndStoreFixedSlot, Id, Field, Id, Byte, Field, Field) \
_(AddAndStoreDynamicSlot, Id, Field, Id, Byte, Field, Field) \
_(AllocateAndStoreDynamicSlot, Id, Field, Id, Byte, Field, Field, Field) \
_(StoreTypedObjectReferenceProperty, Id, Field, Byte, Byte, Id) \
_(StoreTypedObjectScalarProperty, Id, Field, Byte, Byte, Id) \
_(StoreUnboxedProperty, Id, Byte, Field, Id) \
_(StoreDenseElement, Id, Id, Id) \
_(StoreDenseElementHole, Id, Id, Id, Byte) \
_(ArrayPush, Id, Id) \
_(ArrayJoinResult, Id) \
_(StoreTypedElement, Id, Id, Id, Byte, Byte, Byte) \
_(CallNativeSetter, Id, Id, Field) \
_(CallScriptedSetter, Id, Field, Id, Byte) \
_(CallSetArrayLength, Id, Byte, Id) \
_(CallProxySet, Id, Id, Field, Byte) \
_(CallProxySetByValue, Id, Id, Id, Byte) \
_(CallAddOrUpdateSparseElementHelper, Id, Id, Id, Byte) \
_(CallInt32ToString, Id, Id) \
_(CallNumberToString, Id, Id) \
\
\
_(LoadFixedSlotResult, Id, Field) \
_(LoadDynamicSlotResult, Id, Field) \
_(LoadUnboxedPropertyResult, Id, Byte, Field) \
_(LoadTypedObjectResult, Id, Byte, Byte, Field) \
_(LoadDenseElementResult, Id, Id) \
_(LoadDenseElementHoleResult, Id, Id) \
_(CallGetSparseElementResult, Id, Id) \
_(LoadDenseElementExistsResult, Id, Id) \
_(LoadTypedElementExistsResult, Id, Id, Byte) \
_(LoadDenseElementHoleExistsResult, Id, Id) \
_(LoadTypedElementResult, Id, Id, Byte, Byte) \
_(LoadInt32ArrayLengthResult, Id) \
_(LoadArgumentsObjectArgResult, Id, Id) \
_(LoadArgumentsObjectLengthResult, Id) \
_(LoadFunctionLengthResult, Id) \
_(LoadStringCharResult, Id, Id) \
_(LoadStringLengthResult, Id) \
_(LoadFrameCalleeResult, None) \
_(LoadFrameNumActualArgsResult, None) \
_(LoadFrameArgumentResult, Id) \
_(LoadEnvironmentFixedSlotResult, Id, Field) \
_(LoadEnvironmentDynamicSlotResult, Id, Field) \
_(LoadObjectResult, Id) \
_(CallScriptedGetterResult, Id, Field, Byte) \
_(CallNativeGetterResult, Id, Field) \
_(CallProxyGetResult, Id, Field) \
_(CallProxyGetByValueResult, Id, Id) \
_(CallProxyHasPropResult, Id, Id, Byte) \
_(CallObjectHasSparseElementResult, Id, Id) \
_(CallNativeGetElementResult, Id, Id) \
_(LoadUndefinedResult, None) \
_(LoadBooleanResult, Byte) \
_(LoadStringResult, Field) \
_(LoadInstanceOfObjectResult, Id, Id) \
_(LoadTypeOfObjectResult, Id) \
_(DoubleAddResult, Id, Id) \
_(DoubleSubResult, Id, Id) \
_(DoubleMulResult, Id, Id) \
_(DoubleDivResult, Id, Id) \
_(DoubleModResult, Id, Id) \
_(Int32AddResult, Id, Id) \
_(Int32SubResult, Id, Id) \
_(Int32MulResult, Id, Id) \
_(Int32DivResult, Id, Id) \
_(Int32ModResult, Id, Id) \
_(Int32BitOrResult, Id, Id) \
_(Int32BitXorResult, Id, Id) \
_(Int32BitAndResult, Id, Id) \
_(Int32LeftShiftResult, Id, Id) \
_(Int32RightShiftResult, Id, Id) \
_(Int32URightShiftResult, Id, Id, Byte) \
_(Int32NotResult, Id) \
_(Int32NegationResult, Id) \
_(DoubleNegationResult, Id) \
_(Int32IncResult, Id) \
_(Int32DecResult, Id) \
_(DoubleIncResult, Id) \
_(DoubleDecResult, Id) \
_(LoadInt32TruthyResult, Id) \
_(LoadDoubleTruthyResult, Id) \
_(LoadStringTruthyResult, Id) \
_(LoadObjectTruthyResult, Id) \
_(LoadValueResult, Field) \
_(LoadNewObjectFromTemplateResult, Field, UInt32, UInt32) \
\
_(CallStringSplitResult, Id, Id, Field) \
_(CallStringConcatResult, Id, Id) \
_(CallStringObjectConcatResult, Id, Id) \
_(CallIsSuspendedGeneratorResult, Id) \
\
_(CompareStringResult, Id, Id, Byte) \
_(CompareObjectResult, Id, Id, Byte) \
_(CompareSymbolResult, Id, Id, Byte) \
_(CompareInt32Result, Id, Id, Byte) \
_(CompareDoubleResult, Id, Id, Byte) \
_(CompareObjectUndefinedNullResult, Id, Byte) \
\
_(CallPrintString, Word) \
_(Breakpoint, None) \
\
_(TypeMonitorResult, None) \
_(ReturnFromIC, None) \
_(WrapResult, None)
enum class CacheOp {
#define DEFINE_OP(op, ...) op,
CACHE_IR_OPS(DEFINE_OP)
#undef DEFINE_OP
};
const char* const CacheIrOpNames[] = {
#define OPNAME(op, ...) #op,
CACHE_IR_OPS(OPNAME)
#undef OPNAME
};
class StubField {
public:
enum class Type : uint8_t {
RawWord,
Shape,
ObjectGroup,
JSObject,
Symbol,
String,
Id,
RawInt64,
First64BitType = RawInt64,
DOMExpandoGeneration,
Value,
Limit
};
static bool sizeIsWord(Type type) {
MOZ_ASSERT(type != Type::Limit);
return type < Type::First64BitType;
}
static bool sizeIsInt64(Type type) {
MOZ_ASSERT(type != Type::Limit);
return type >= Type::First64BitType;
}
static size_t sizeInBytes(Type type) {
if (sizeIsWord(type)) {
return sizeof(uintptr_t);
}
MOZ_ASSERT(sizeIsInt64(type));
return sizeof(int64_t);
}
private:
uint64_t data_;
Type type_;
public:
StubField(uint64_t data, Type type) : data_(data), type_(type) {
MOZ_ASSERT_IF(sizeIsWord(), data <= UINTPTR_MAX);
}
Type type() const { return type_; }
bool sizeIsWord() const { return sizeIsWord(type_); }
bool sizeIsInt64() const { return sizeIsInt64(type_); }
uintptr_t asWord() const {
MOZ_ASSERT(sizeIsWord());
return uintptr_t(data_);
}
uint64_t asInt64() const {
MOZ_ASSERT(sizeIsInt64());
return data_;
}
} JS_HAZ_GC_POINTER;
enum class GuardClassKind : uint8_t {
Array,
MappedArguments,
UnmappedArguments,
WindowProxy,
JSFunction,
};
JSObject* NewWrapperWithObjectShape(JSContext* cx, HandleNativeObject obj);
enum TypedThingLayout {
Layout_TypedArray,
Layout_OutlineTypedObject,
Layout_InlineTypedObject
};
void LoadShapeWrapperContents(MacroAssembler& masm, Register obj, Register dst,
Label* failure);
class MOZ_RAII CacheIRWriter : public JS::CustomAutoRooter {
JSContext* cx_;
CompactBufferWriter buffer_;
uint32_t nextOperandId_;
uint32_t nextInstructionId_;
uint32_t numInputOperands_;
Vector<StubField, 8, SystemAllocPolicy> stubFields_;
size_t stubDataSize_;
Vector<uint32_t, 8, SystemAllocPolicy> operandLastUsed_;
static const size_t MaxOperandIds = 20;
static const size_t MaxStubDataSizeInBytes = 20 * sizeof(uintptr_t);
bool tooLarge_;
mutable uint32_t lastOffset_;
mutable uint32_t lastIndex_;
void assertSameCompartment(JSObject*);
void writeOp(CacheOp op) {
MOZ_ASSERT(uint32_t(op) <= UINT8_MAX);
buffer_.writeByte(uint32_t(op));
nextInstructionId_++;
}
void writeOperandId(OperandId opId) {
if (opId.id() < MaxOperandIds) {
static_assert(MaxOperandIds <= UINT8_MAX,
"operand id must fit in a single byte");
buffer_.writeByte(opId.id());
} else {
tooLarge_ = true;
return;
}
if (opId.id() >= operandLastUsed_.length()) {
buffer_.propagateOOM(operandLastUsed_.resize(opId.id() + 1));
if (buffer_.oom()) {
return;
}
}
MOZ_ASSERT(nextInstructionId_ > 0);
operandLastUsed_[opId.id()] = nextInstructionId_ - 1;
}
void writeInt32Immediate(int32_t i32) { buffer_.writeFixedUint32_t(i32); }
void writeUint32Immediate(uint32_t u32) { buffer_.writeFixedUint32_t(u32); }
void writePointer(void* ptr) { buffer_.writeRawPointer(ptr); }
void writeOpWithOperandId(CacheOp op, OperandId opId) {
writeOp(op);
writeOperandId(opId);
}
void addStubField(uint64_t value, StubField::Type fieldType) {
size_t newStubDataSize = stubDataSize_ + StubField::sizeInBytes(fieldType);
if (newStubDataSize < MaxStubDataSizeInBytes) {
buffer_.propagateOOM(stubFields_.append(StubField(value, fieldType)));
MOZ_ASSERT((stubDataSize_ % sizeof(uintptr_t)) == 0);
buffer_.writeByte(stubDataSize_ / sizeof(uintptr_t));
stubDataSize_ = newStubDataSize;
} else {
tooLarge_ = true;
}
}
CacheIRWriter(const CacheIRWriter&) = delete;
CacheIRWriter& operator=(const CacheIRWriter&) = delete;
public:
explicit CacheIRWriter(JSContext* cx)
: CustomAutoRooter(cx),
cx_(cx),
nextOperandId_(0),
nextInstructionId_(0),
numInputOperands_(0),
stubDataSize_(0),
tooLarge_(false),
lastOffset_(0),
lastIndex_(0) {}
bool failed() const { return buffer_.oom() || tooLarge_; }
uint32_t numInputOperands() const { return numInputOperands_; }
uint32_t numOperandIds() const { return nextOperandId_; }
uint32_t numInstructions() const { return nextInstructionId_; }
size_t numStubFields() const { return stubFields_.length(); }
StubField::Type stubFieldType(uint32_t i) const {
return stubFields_[i].type();
}
uint32_t setInputOperandId(uint32_t op) {
MOZ_ASSERT(op == nextOperandId_);
nextOperandId_++;
numInputOperands_++;
return op;
}
void trace(JSTracer* trc) override {
MOZ_RELEASE_ASSERT(stubFields_.empty());
}
size_t stubDataSize() const { return stubDataSize_; }
void copyStubData(uint8_t* dest) const;
bool stubDataEqualsMaybeUpdate(uint8_t* stubData, bool* updated) const;
bool operandIsDead(uint32_t operandId, uint32_t currentInstruction) const {
if (operandId >= operandLastUsed_.length()) {
return false;
}
return currentInstruction > operandLastUsed_[operandId];
}
const uint8_t* codeStart() const {
MOZ_ASSERT(!failed());
return buffer_.buffer();
}
const uint8_t* codeEnd() const {
MOZ_ASSERT(!failed());
return buffer_.buffer() + buffer_.length();
}
uint32_t codeLength() const {
MOZ_ASSERT(!failed());
return buffer_.length();
}
StubField readStubFieldForIon(uint32_t offset, StubField::Type type) const;
ObjOperandId guardIsObject(ValOperandId val) {
writeOpWithOperandId(CacheOp::GuardIsObject, val);
return ObjOperandId(val.id());
}
Int32OperandId guardIsBoolean(ValOperandId val) {
Int32OperandId res(nextOperandId_++);
writeOpWithOperandId(CacheOp::GuardIsBoolean, val);
writeOperandId(res);
return res;
}
StringOperandId guardIsString(ValOperandId val) {
writeOpWithOperandId(CacheOp::GuardIsString, val);
return StringOperandId(val.id());
}
SymbolOperandId guardIsSymbol(ValOperandId val) {
writeOpWithOperandId(CacheOp::GuardIsSymbol, val);
return SymbolOperandId(val.id());
}
BigIntOperandId guardIsBigInt(ValOperandId val) {
writeOpWithOperandId(CacheOp::GuardIsBigInt, val);
return BigIntOperandId(val.id());
}
Int32OperandId guardIsInt32(ValOperandId val) {
Int32OperandId res(nextOperandId_++);
writeOpWithOperandId(CacheOp::GuardIsInt32, val);
writeOperandId(res);
return res;
}
Int32OperandId guardIsInt32Index(ValOperandId val) {
Int32OperandId res(nextOperandId_++);
writeOpWithOperandId(CacheOp::GuardIsInt32Index, val);
writeOperandId(res);
return res;
}
void guardIsNumber(ValOperandId val) {
writeOpWithOperandId(CacheOp::GuardIsNumber, val);
}
void guardType(ValOperandId val, ValueType type) {
writeOpWithOperandId(CacheOp::GuardType, val);
static_assert(sizeof(type) == sizeof(uint8_t),
"JS::ValueType should fit in a byte");
buffer_.writeByte(uint32_t(type));
}
void guardIsObjectOrNull(ValOperandId val) {
writeOpWithOperandId(CacheOp::GuardIsObjectOrNull, val);
}
void guardIsNullOrUndefined(ValOperandId val) {
writeOpWithOperandId(CacheOp::GuardIsNullOrUndefined, val);
}
void guardIsNotNullOrUndefined(ValOperandId val) {
writeOpWithOperandId(CacheOp::GuardIsNotNullOrUndefined, val);
}
void guardIsNull(ValOperandId val) {
writeOpWithOperandId(CacheOp::GuardIsNull, val);
}
void guardIsUndefined(ValOperandId val) {
writeOpWithOperandId(CacheOp::GuardIsUndefined, val);
}
void guardShape(ObjOperandId obj, Shape* shape) {
MOZ_ASSERT(shape);
writeOpWithOperandId(CacheOp::GuardShape, obj);
addStubField(uintptr_t(shape), StubField::Type::Shape);
}
void guardShapeForClass(ObjOperandId obj, Shape* shape) {
guardShape(obj, shape);
}
void guardShapeForOwnProperties(ObjOperandId obj, Shape* shape) {
MOZ_ASSERT(shape->getObjectClass()->isNative());
guardShape(obj, shape);
}
void guardXrayExpandoShapeAndDefaultProto(ObjOperandId obj,
JSObject* shapeWrapper) {
assertSameCompartment(shapeWrapper);
writeOpWithOperandId(CacheOp::GuardXrayExpandoShapeAndDefaultProto, obj);
buffer_.writeByte(uint32_t(!!shapeWrapper));
addStubField(uintptr_t(shapeWrapper), StubField::Type::JSObject);
}
void guardFunctionPrototype(ObjOperandId rhs, uint32_t slot,
ObjOperandId protoId) {
writeOpWithOperandId(CacheOp::GuardFunctionPrototype, rhs);
writeOperandId(protoId);
addStubField(slot, StubField::Type::RawWord);
}
void guardNoAllocationMetadataBuilder() {
writeOp(CacheOp::GuardNoAllocationMetadataBuilder);
}
void guardObjectGroupNotPretenured(ObjectGroup* group) {
writeOp(CacheOp::GuardObjectGroupNotPretenured);
addStubField(uintptr_t(group), StubField::Type::ObjectGroup);
}
public:
void guardGroup(ObjOperandId obj, ObjectGroup* group) {
writeOpWithOperandId(CacheOp::GuardGroup, obj);
addStubField(uintptr_t(group), StubField::Type::ObjectGroup);
}
void guardGroupForProto(ObjOperandId obj, ObjectGroup* group) {
MOZ_ASSERT(!group->hasUncacheableProto());
guardGroup(obj, group);
}
void guardGroupForTypeBarrier(ObjOperandId obj, ObjectGroup* group) {
guardGroup(obj, group);
}
void guardGroupForLayout(ObjOperandId obj, ObjectGroup* group) {
MOZ_ASSERT(!group->hasUncacheableClass());
MOZ_ASSERT(IsUnboxedObjectClass(group->clasp()) ||
IsTypedObjectClass(group->clasp()));
guardGroup(obj, group);
}
void guardProto(ObjOperandId obj, JSObject* proto) {
assertSameCompartment(proto);
writeOpWithOperandId(CacheOp::GuardProto, obj);
addStubField(uintptr_t(proto), StubField::Type::JSObject);
}
void guardClass(ObjOperandId obj, GuardClassKind kind) {
static_assert(sizeof(GuardClassKind) == sizeof(uint8_t),
"GuardClassKind must fit in a byte");
writeOpWithOperandId(CacheOp::GuardClass, obj);
buffer_.writeByte(uint32_t(kind));
}
void guardAnyClass(ObjOperandId obj, const Class* clasp) {
writeOpWithOperandId(CacheOp::GuardAnyClass, obj);
addStubField(uintptr_t(clasp), StubField::Type::RawWord);
}
void guardIsNativeFunction(ObjOperandId obj, JSNative nativeFunc) {
writeOpWithOperandId(CacheOp::GuardIsNativeFunction, obj);
writePointer(JS_FUNC_TO_DATA_PTR(void*, nativeFunc));
}
void guardIsNativeObject(ObjOperandId obj) {
writeOpWithOperandId(CacheOp::GuardIsNativeObject, obj);
}
void guardIsProxy(ObjOperandId obj) {
writeOpWithOperandId(CacheOp::GuardIsProxy, obj);
}
void guardHasProxyHandler(ObjOperandId obj, const void* handler) {
writeOpWithOperandId(CacheOp::GuardHasProxyHandler, obj);
addStubField(uintptr_t(handler), StubField::Type::RawWord);
}
void guardNotDOMProxy(ObjOperandId obj) {
writeOpWithOperandId(CacheOp::GuardNotDOMProxy, obj);
}
void guardSpecificObject(ObjOperandId obj, JSObject* expected) {
assertSameCompartment(expected);
writeOpWithOperandId(CacheOp::GuardSpecificObject, obj);
addStubField(uintptr_t(expected), StubField::Type::JSObject);
}
void guardSpecificAtom(StringOperandId str, JSAtom* expected) {
writeOpWithOperandId(CacheOp::GuardSpecificAtom, str);
addStubField(uintptr_t(expected), StubField::Type::String);
}
void guardSpecificSymbol(SymbolOperandId sym, JS::Symbol* expected) {
writeOpWithOperandId(CacheOp::GuardSpecificSymbol, sym);
addStubField(uintptr_t(expected), StubField::Type::Symbol);
}
void guardSpecificInt32Immediate(
Int32OperandId operand, int32_t expected,
Assembler::Condition cond = Assembler::Equal) {
writeOpWithOperandId(CacheOp::GuardSpecificInt32Immediate, operand);
writeInt32Immediate(expected);
buffer_.writeByte(uint32_t(cond));
}
void guardMagicValue(ValOperandId val, JSWhyMagic magic) {
writeOpWithOperandId(CacheOp::GuardMagicValue, val);
buffer_.writeByte(uint32_t(magic));
}
void guardCompartment(ObjOperandId obj, JSObject* global,
JS::Compartment* compartment) {
assertSameCompartment(global);
writeOpWithOperandId(CacheOp::GuardCompartment, obj);
addStubField(uintptr_t(global), StubField::Type::JSObject);
addStubField(uintptr_t(compartment), StubField::Type::RawWord);
}
void guardIsExtensible(ObjOperandId obj) {
writeOpWithOperandId(CacheOp::GuardIsExtensible, obj);
}
void guardNoDetachedTypedObjects() {
writeOp(CacheOp::GuardNoDetachedTypedObjects);
}
void guardFrameHasNoArgumentsObject() {
writeOp(CacheOp::GuardFrameHasNoArgumentsObject);
}
Int32OperandId guardAndGetIndexFromString(StringOperandId str) {
Int32OperandId res(nextOperandId_++);
writeOpWithOperandId(CacheOp::GuardAndGetIndexFromString, str);
writeOperandId(res);
return res;
}
ValOperandId guardAndGetNumberFromString(StringOperandId str) {
ValOperandId res(nextOperandId_++);
writeOpWithOperandId(CacheOp::GuardAndGetNumberFromString, str);
writeOperandId(res);
return res;
}
ObjOperandId guardAndGetIterator(ObjOperandId obj,
PropertyIteratorObject* iter,
NativeIterator** enumeratorsAddr) {
ObjOperandId res(nextOperandId_++);
writeOpWithOperandId(CacheOp::GuardAndGetIterator, obj);
addStubField(uintptr_t(iter), StubField::Type::JSObject);
addStubField(uintptr_t(enumeratorsAddr), StubField::Type::RawWord);
writeOperandId(res);
return res;
}
void guardHasGetterSetter(ObjOperandId obj, Shape* shape) {
writeOpWithOperandId(CacheOp::GuardHasGetterSetter, obj);
addStubField(uintptr_t(shape), StubField::Type::Shape);
}
void guardGroupHasUnanalyzedNewScript(ObjectGroup* group) {
writeOp(CacheOp::GuardGroupHasUnanalyzedNewScript);
addStubField(uintptr_t(group), StubField::Type::ObjectGroup);
}
void guardIndexIsNonNegative(Int32OperandId index) {
writeOpWithOperandId(CacheOp::GuardIndexIsNonNegative, index);
}
void guardIndexGreaterThanDenseInitLength(ObjOperandId obj,
Int32OperandId index) {
writeOpWithOperandId(CacheOp::GuardIndexGreaterThanDenseInitLength, obj);
writeOperandId(index);
}
void guardIndexGreaterThanDenseCapacity(ObjOperandId obj,
Int32OperandId index) {
writeOpWithOperandId(CacheOp::GuardIndexGreaterThanDenseCapacity, obj);
writeOperandId(index);
}
void guardIndexGreaterThanArrayLength(ObjOperandId obj,
Int32OperandId index) {
writeOpWithOperandId(CacheOp::GuardIndexGreaterThanArrayLength, obj);
writeOperandId(index);
}
void guardIndexIsValidUpdateOrAdd(ObjOperandId obj, Int32OperandId index) {
writeOpWithOperandId(CacheOp::GuardIndexIsValidUpdateOrAdd, obj);
writeOperandId(index);
}
void guardTagNotEqual(ValueTagOperandId lhs, ValueTagOperandId rhs) {
writeOpWithOperandId(CacheOp::GuardTagNotEqual, lhs);
writeOperandId(rhs);
}
void loadFrameCalleeResult() { writeOp(CacheOp::LoadFrameCalleeResult); }
void loadFrameNumActualArgsResult() {
writeOp(CacheOp::LoadFrameNumActualArgsResult);
}
void loadFrameArgumentResult(Int32OperandId index) {
writeOpWithOperandId(CacheOp::LoadFrameArgumentResult, index);
}
void guardNoDenseElements(ObjOperandId obj) {
writeOpWithOperandId(CacheOp::GuardNoDenseElements, obj);
}
void guardNoUnboxedExpando(ObjOperandId obj) {
writeOpWithOperandId(CacheOp::GuardNoUnboxedExpando, obj);
}
ObjOperandId guardAndLoadUnboxedExpando(ObjOperandId obj) {
ObjOperandId res(nextOperandId_++);
writeOpWithOperandId(CacheOp::GuardAndLoadUnboxedExpando, obj);
writeOperandId(res);
return res;
}
ValOperandId loadStackValue(uint32_t idx) {
ValOperandId res(nextOperandId_++);
writeOpWithOperandId(CacheOp::LoadStackValue, res);
writeUint32Immediate(idx);
return res;
}
ObjOperandId loadObject(JSObject* obj) {
assertSameCompartment(obj);
ObjOperandId res(nextOperandId_++);
writeOpWithOperandId(CacheOp::LoadObject, res);
addStubField(uintptr_t(obj), StubField::Type::JSObject);
return res;
}
ObjOperandId loadProto(ObjOperandId obj) {
ObjOperandId res(nextOperandId_++);
writeOpWithOperandId(CacheOp::LoadProto, obj);
writeOperandId(res);
return res;
}
ObjOperandId loadEnclosingEnvironment(ObjOperandId obj) {
ObjOperandId res(nextOperandId_++);
writeOpWithOperandId(CacheOp::LoadEnclosingEnvironment, obj);
writeOperandId(res);
return res;
}
ObjOperandId loadWrapperTarget(ObjOperandId obj) {
ObjOperandId res(nextOperandId_++);
writeOpWithOperandId(CacheOp::LoadWrapperTarget, obj);
writeOperandId(res);
return res;
}
Int32OperandId truncateDoubleToUInt32(ValOperandId val) {
Int32OperandId res(nextOperandId_++);
writeOpWithOperandId(CacheOp::TruncateDoubleToUInt32, val);
writeOperandId(res);
return res;
}
ValueTagOperandId loadValueTag(ValOperandId val) {
ValueTagOperandId res(nextOperandId_++);
writeOpWithOperandId(CacheOp::LoadValueTag, val);
writeOperandId(res);
return res;
}
ValOperandId loadDOMExpandoValue(ObjOperandId obj) {
ValOperandId res(nextOperandId_++);
writeOpWithOperandId(CacheOp::LoadDOMExpandoValue, obj);
writeOperandId(res);
return res;
}
void guardDOMExpandoMissingOrGuardShape(ValOperandId expando, Shape* shape) {
writeOpWithOperandId(CacheOp::GuardDOMExpandoMissingOrGuardShape, expando);
addStubField(uintptr_t(shape), StubField::Type::Shape);
}
ValOperandId loadDOMExpandoValueGuardGeneration(
ObjOperandId obj, ExpandoAndGeneration* expandoAndGeneration) {
ValOperandId res(nextOperandId_++);
writeOpWithOperandId(CacheOp::LoadDOMExpandoValueGuardGeneration, obj);
addStubField(uintptr_t(expandoAndGeneration), StubField::Type::RawWord);
addStubField(expandoAndGeneration->generation,
StubField::Type::DOMExpandoGeneration);
writeOperandId(res);
return res;
}
ValOperandId loadDOMExpandoValueIgnoreGeneration(ObjOperandId obj) {
ValOperandId res(nextOperandId_++);
writeOpWithOperandId(CacheOp::LoadDOMExpandoValueIgnoreGeneration, obj);
writeOperandId(res);
return res;
}
void storeFixedSlot(ObjOperandId obj, size_t offset, ValOperandId rhs) {
writeOpWithOperandId(CacheOp::StoreFixedSlot, obj);
addStubField(offset, StubField::Type::RawWord);
writeOperandId(rhs);
}
void storeDynamicSlot(ObjOperandId obj, size_t offset, ValOperandId rhs) {
writeOpWithOperandId(CacheOp::StoreDynamicSlot, obj);
addStubField(offset, StubField::Type::RawWord);
writeOperandId(rhs);
}
void addAndStoreFixedSlot(ObjOperandId obj, size_t offset, ValOperandId rhs,
Shape* newShape, bool changeGroup,
ObjectGroup* newGroup) {
writeOpWithOperandId(CacheOp::AddAndStoreFixedSlot, obj);
addStubField(offset, StubField::Type::RawWord);
writeOperandId(rhs);
buffer_.writeByte(changeGroup);
addStubField(uintptr_t(newGroup), StubField::Type::ObjectGroup);
addStubField(uintptr_t(newShape), StubField::Type::Shape);
}
void addAndStoreDynamicSlot(ObjOperandId obj, size_t offset, ValOperandId rhs,
Shape* newShape, bool changeGroup,
ObjectGroup* newGroup) {
writeOpWithOperandId(CacheOp::AddAndStoreDynamicSlot, obj);
addStubField(offset, StubField::Type::RawWord);
writeOperandId(rhs);
buffer_.writeByte(changeGroup);
addStubField(uintptr_t(newGroup), StubField::Type::ObjectGroup);
addStubField(uintptr_t(newShape), StubField::Type::Shape);
}
void allocateAndStoreDynamicSlot(ObjOperandId obj, size_t offset,
ValOperandId rhs, Shape* newShape,
bool changeGroup, ObjectGroup* newGroup,
uint32_t numNewSlots) {
writeOpWithOperandId(CacheOp::AllocateAndStoreDynamicSlot, obj);
addStubField(offset, StubField::Type::RawWord);
writeOperandId(rhs);
buffer_.writeByte(changeGroup);
addStubField(uintptr_t(newGroup), StubField::Type::ObjectGroup);
addStubField(uintptr_t(newShape), StubField::Type::Shape);
addStubField(numNewSlots, StubField::Type::RawWord);
}
void storeTypedObjectReferenceProperty(ObjOperandId obj, uint32_t offset,
TypedThingLayout layout,
ReferenceType type, ValOperandId rhs) {
writeOpWithOperandId(CacheOp::StoreTypedObjectReferenceProperty, obj);
addStubField(offset, StubField::Type::RawWord);
buffer_.writeByte(uint32_t(layout));
buffer_.writeByte(uint32_t(type));
writeOperandId(rhs);
}
void storeTypedObjectScalarProperty(ObjOperandId obj, uint32_t offset,
TypedThingLayout layout,
Scalar::Type type, ValOperandId rhs) {
writeOpWithOperandId(CacheOp::StoreTypedObjectScalarProperty, obj);
addStubField(offset, StubField::Type::RawWord);
buffer_.writeByte(uint32_t(layout));
buffer_.writeByte(uint32_t(type));
writeOperandId(rhs);
}
void storeUnboxedProperty(ObjOperandId obj, JSValueType type, size_t offset,
ValOperandId rhs) {
writeOpWithOperandId(CacheOp::StoreUnboxedProperty, obj);
buffer_.writeByte(uint32_t(type));
addStubField(offset, StubField::Type::RawWord);
writeOperandId(rhs);
}
void storeDenseElement(ObjOperandId obj, Int32OperandId index,
ValOperandId rhs) {
writeOpWithOperandId(CacheOp::StoreDenseElement, obj);
writeOperandId(index);
writeOperandId(rhs);
}
void storeTypedElement(ObjOperandId obj, Int32OperandId index,
ValOperandId rhs, TypedThingLayout layout,
Scalar::Type elementType, bool handleOOB) {
writeOpWithOperandId(CacheOp::StoreTypedElement, obj);
writeOperandId(index);
writeOperandId(rhs);
buffer_.writeByte(uint32_t(layout));
buffer_.writeByte(uint32_t(elementType));
buffer_.writeByte(uint32_t(handleOOB));
}
void storeDenseElementHole(ObjOperandId obj, Int32OperandId index,
ValOperandId rhs, bool handleAdd) {
writeOpWithOperandId(CacheOp::StoreDenseElementHole, obj);
writeOperandId(index);
writeOperandId(rhs);
buffer_.writeByte(handleAdd);
}
void arrayPush(ObjOperandId obj, ValOperandId rhs) {
writeOpWithOperandId(CacheOp::ArrayPush, obj);
writeOperandId(rhs);
}
void arrayJoinResult(ObjOperandId obj) {
writeOpWithOperandId(CacheOp::ArrayJoinResult, obj);
}
void callScriptedSetter(ObjOperandId obj, JSFunction* setter,
ValOperandId rhs) {
writeOpWithOperandId(CacheOp::CallScriptedSetter, obj);
addStubField(uintptr_t(setter), StubField::Type::JSObject);
writeOperandId(rhs);
buffer_.writeByte(cx_->realm() != setter->realm());
}
void callNativeSetter(ObjOperandId obj, JSFunction* setter,
ValOperandId rhs) {
writeOpWithOperandId(CacheOp::CallNativeSetter, obj);
addStubField(uintptr_t(setter), StubField::Type::JSObject);
writeOperandId(rhs);
}
void callSetArrayLength(ObjOperandId obj, bool strict, ValOperandId rhs) {
writeOpWithOperandId(CacheOp::CallSetArrayLength, obj);
buffer_.writeByte(uint32_t(strict));
writeOperandId(rhs);
}
void callProxySet(ObjOperandId obj, jsid id, ValOperandId rhs, bool strict) {
writeOpWithOperandId(CacheOp::CallProxySet, obj);
writeOperandId(rhs);
addStubField(uintptr_t(JSID_BITS(id)), StubField::Type::Id);
buffer_.writeByte(uint32_t(strict));
}
void callProxySetByValue(ObjOperandId obj, ValOperandId id, ValOperandId rhs,
bool strict) {
writeOpWithOperandId(CacheOp::CallProxySetByValue, obj);
writeOperandId(id);
writeOperandId(rhs);
buffer_.writeByte(uint32_t(strict));
}
void callAddOrUpdateSparseElementHelper(ObjOperandId obj, Int32OperandId id,
ValOperandId rhs, bool strict) {
writeOpWithOperandId(CacheOp::CallAddOrUpdateSparseElementHelper, obj);
writeOperandId(id);
writeOperandId(rhs);
buffer_.writeByte(uint32_t(strict));
}
StringOperandId callInt32ToString(Int32OperandId id) {
StringOperandId res(nextOperandId_++);
writeOpWithOperandId(CacheOp::CallInt32ToString, id);
writeOperandId(res);
return res;
}
StringOperandId callNumberToString(ValOperandId id) {
StringOperandId res(nextOperandId_++);
writeOpWithOperandId(CacheOp::CallNumberToString, id);
writeOperandId(res);
return res;
}
void megamorphicLoadSlotResult(ObjOperandId obj, PropertyName* name,
bool handleMissing) {
writeOpWithOperandId(CacheOp::MegamorphicLoadSlotResult, obj);
addStubField(uintptr_t(name), StubField::Type::String);
buffer_.writeByte(uint32_t(handleMissing));
}
void megamorphicLoadSlotByValueResult(ObjOperandId obj, ValOperandId id,
bool handleMissing) {
writeOpWithOperandId(CacheOp::MegamorphicLoadSlotByValueResult, obj);
writeOperandId(id);
buffer_.writeByte(uint32_t(handleMissing));
}
void megamorphicStoreSlot(ObjOperandId obj, PropertyName* name,
ValOperandId rhs, bool needsTypeBarrier) {
writeOpWithOperandId(CacheOp::MegamorphicStoreSlot, obj);
addStubField(uintptr_t(name), StubField::Type::String);
writeOperandId(rhs);
buffer_.writeByte(needsTypeBarrier);
}
void megamorphicSetElement(ObjOperandId obj, ValOperandId id,
ValOperandId rhs, bool strict) {
writeOpWithOperandId(CacheOp::MegamorphicSetElement, obj);
writeOperandId(id);
writeOperandId(rhs);
buffer_.writeByte(uint32_t(strict));
}
void megamorphicHasPropResult(ObjOperandId obj, ValOperandId id,
bool hasOwn) {
writeOpWithOperandId(CacheOp::MegamorphicHasPropResult, obj);
writeOperandId(id);
buffer_.writeByte(uint32_t(hasOwn));
}
void doubleAddResult(ValOperandId lhsId, ValOperandId rhsId) {
writeOpWithOperandId(CacheOp::DoubleAddResult, lhsId);
writeOperandId(rhsId);
}
void doubleSubResult(ValOperandId lhsId, ValOperandId rhsId) {
writeOpWithOperandId(CacheOp::DoubleSubResult, lhsId);
writeOperandId(rhsId);
}
void doubleMulResult(ValOperandId lhsId, ValOperandId rhsId) {
writeOpWithOperandId(CacheOp::DoubleMulResult, lhsId);
writeOperandId(rhsId);
}
void doubleDivResult(ValOperandId lhsId, ValOperandId rhsId) {
writeOpWithOperandId(CacheOp::DoubleDivResult, lhsId);
writeOperandId(rhsId);
}
void doubleModResult(ValOperandId lhsId, ValOperandId rhsId) {
writeOpWithOperandId(CacheOp::DoubleModResult, lhsId);
writeOperandId(rhsId);
}
void int32AddResult(Int32OperandId lhs, Int32OperandId rhs) {
writeOpWithOperandId(CacheOp::Int32AddResult, lhs);
writeOperandId(rhs);
}
void int32SubResult(Int32OperandId lhs, Int32OperandId rhs) {
writeOpWithOperandId(CacheOp::Int32SubResult, lhs);
writeOperandId(rhs);
}
void int32MulResult(Int32OperandId lhs, Int32OperandId rhs) {
writeOpWithOperandId(CacheOp::Int32MulResult, lhs);
writeOperandId(rhs);
}
void int32DivResult(Int32OperandId lhs, Int32OperandId rhs) {
writeOpWithOperandId(CacheOp::Int32DivResult, lhs);
writeOperandId(rhs);
}
void int32ModResult(Int32OperandId lhs, Int32OperandId rhs) {
writeOpWithOperandId(CacheOp::Int32ModResult, lhs);
writeOperandId(rhs);
}
void int32BitOrResult(Int32OperandId lhs, Int32OperandId rhs) {
writeOpWithOperandId(CacheOp::Int32BitOrResult, lhs);
writeOperandId(rhs);
}
void int32BitXOrResult(Int32OperandId lhs, Int32OperandId rhs) {
writeOpWithOperandId(CacheOp::Int32BitXorResult, lhs);
writeOperandId(rhs);
}
void int32BitAndResult(Int32OperandId lhs, Int32OperandId rhs) {
writeOpWithOperandId(CacheOp::Int32BitAndResult, lhs);
writeOperandId(rhs);
}
void int32LeftShiftResult(Int32OperandId lhs, Int32OperandId rhs) {
writeOpWithOperandId(CacheOp::Int32LeftShiftResult, lhs);
writeOperandId(rhs);
}
void int32RightShiftResult(Int32OperandId lhs, Int32OperandId rhs) {
writeOpWithOperandId(CacheOp::Int32RightShiftResult, lhs);
writeOperandId(rhs);
}
void int32URightShiftResult(Int32OperandId lhs, Int32OperandId rhs,
bool allowDouble) {
writeOpWithOperandId(CacheOp::Int32URightShiftResult, lhs);
writeOperandId(rhs);
buffer_.writeByte(uint32_t(allowDouble));
}
void int32NotResult(Int32OperandId id) {
writeOpWithOperandId(CacheOp::Int32NotResult, id);
}
void int32NegationResult(Int32OperandId id) {
writeOpWithOperandId(CacheOp::Int32NegationResult, id);
}
void int32IncResult(Int32OperandId id) {
writeOpWithOperandId(CacheOp::Int32IncResult, id);
}
void int32DecResult(Int32OperandId id) {
writeOpWithOperandId(CacheOp::Int32DecResult, id);
}
void doubleNegationResult(ValOperandId val) {
writeOpWithOperandId(CacheOp::DoubleNegationResult, val);
}
void doubleIncResult(ValOperandId val) {
writeOpWithOperandId(CacheOp::DoubleIncResult, val);
}
void doubleDecResult(ValOperandId val) {
writeOpWithOperandId(CacheOp::DoubleDecResult, val);
}
void loadBooleanResult(bool val) {
writeOp(CacheOp::LoadBooleanResult);
buffer_.writeByte(uint32_t(val));
}
void loadUndefinedResult() { writeOp(CacheOp::LoadUndefinedResult); }
void loadStringResult(JSString* str) {
writeOp(CacheOp::LoadStringResult);
addStubField(uintptr_t(str), StubField::Type::String);
}
void loadFixedSlotResult(ObjOperandId obj, size_t offset) {
writeOpWithOperandId(CacheOp::LoadFixedSlotResult, obj);
addStubField(offset, StubField::Type::RawWord);
}
void loadDynamicSlotResult(ObjOperandId obj, size_t offset) {
writeOpWithOperandId(CacheOp::LoadDynamicSlotResult, obj);
addStubField(offset, StubField::Type::RawWord);
}
void loadUnboxedPropertyResult(ObjOperandId obj, JSValueType type,
size_t offset) {
writeOpWithOperandId(CacheOp::LoadUnboxedPropertyResult, obj);
buffer_.writeByte(uint32_t(type));
addStubField(offset, StubField::Type::RawWord);
}
void loadTypedObjectResult(ObjOperandId obj, uint32_t offset,
TypedThingLayout layout, uint32_t typeDescr) {
MOZ_ASSERT(uint32_t(layout) <= UINT8_MAX);
MOZ_ASSERT(typeDescr <= UINT8_MAX);
writeOpWithOperandId(CacheOp::LoadTypedObjectResult, obj);
buffer_.writeByte(uint32_t(layout));
buffer_.writeByte(typeDescr);
addStubField(offset, StubField::Type::RawWord);
}
void loadInt32ArrayLengthResult(ObjOperandId obj) {
writeOpWithOperandId(CacheOp::LoadInt32ArrayLengthResult, obj);
}
void loadArgumentsObjectLengthResult(ObjOperandId obj) {
writeOpWithOperandId(CacheOp::LoadArgumentsObjectLengthResult, obj);
}
void loadFunctionLengthResult(ObjOperandId obj) {
writeOpWithOperandId(CacheOp::LoadFunctionLengthResult, obj);
}
void loadArgumentsObjectArgResult(ObjOperandId obj, Int32OperandId index) {
writeOpWithOperandId(CacheOp::LoadArgumentsObjectArgResult, obj);
writeOperandId(index);
}
void loadDenseElementResult(ObjOperandId obj, Int32OperandId index) {
writeOpWithOperandId(CacheOp::LoadDenseElementResult, obj);
writeOperandId(index);
}
void loadDenseElementHoleResult(ObjOperandId obj, Int32OperandId index) {
writeOpWithOperandId(CacheOp::LoadDenseElementHoleResult, obj);
writeOperandId(index);
}
void callGetSparseElementResult(ObjOperandId obj, Int32OperandId index) {
writeOpWithOperandId(CacheOp::CallGetSparseElementResult, obj);
writeOperandId(index);
}
void loadDenseElementExistsResult(ObjOperandId obj, Int32OperandId index) {
writeOpWithOperandId(CacheOp::LoadDenseElementExistsResult, obj);
writeOperandId(index);
}
void loadTypedElementExistsResult(ObjOperandId obj, Int32OperandId index,
TypedThingLayout layout) {
writeOpWithOperandId(CacheOp::LoadTypedElementExistsResult, obj);
writeOperandId(index);
buffer_.writeByte(uint32_t(layout));
}
void loadDenseElementHoleExistsResult(ObjOperandId obj,
Int32OperandId index) {
writeOpWithOperandId(CacheOp::LoadDenseElementHoleExistsResult, obj);
writeOperandId(index);
}
void loadTypedElementResult(ObjOperandId obj, Int32OperandId index,
TypedThingLayout layout,
Scalar::Type elementType) {
writeOpWithOperandId(CacheOp::LoadTypedElementResult, obj);
writeOperandId(index);
buffer_.writeByte(uint32_t(layout));
buffer_.writeByte(uint32_t(elementType));
}
void loadStringLengthResult(StringOperandId str) {
writeOpWithOperandId(CacheOp::LoadStringLengthResult, str);
}
void loadStringCharResult(StringOperandId str, Int32OperandId index) {
writeOpWithOperandId(CacheOp::LoadStringCharResult, str);
writeOperandId(index);
}
void callScriptedGetterResult(ObjOperandId obj, JSFunction* getter) {
writeOpWithOperandId(CacheOp::CallScriptedGetterResult, obj);
addStubField(uintptr_t(getter), StubField::Type::JSObject);
buffer_.writeByte(cx_->realm() != getter->realm());
}
void callNativeGetterResult(ObjOperandId obj, JSFunction* getter) {
writeOpWithOperandId(CacheOp::CallNativeGetterResult, obj);
addStubField(uintptr_t(getter), StubField::Type::JSObject);
}
void callProxyGetResult(ObjOperandId obj, jsid id) {
writeOpWithOperandId(CacheOp::CallProxyGetResult, obj);
addStubField(uintptr_t(JSID_BITS(id)), StubField::Type::Id);
}
void callProxyGetByValueResult(ObjOperandId obj, ValOperandId idVal) {
writeOpWithOperandId(CacheOp::CallProxyGetByValueResult, obj);
writeOperandId(idVal);
}
void callProxyHasPropResult(ObjOperandId obj, ValOperandId idVal,
bool hasOwn) {
writeOpWithOperandId(CacheOp::CallProxyHasPropResult, obj);
writeOperandId(idVal);
buffer_.writeByte(uint32_t(hasOwn));
}
void callObjectHasSparseElementResult(ObjOperandId obj,
Int32OperandId index) {
writeOpWithOperandId(CacheOp::CallObjectHasSparseElementResult, obj);
writeOperandId(index);
}
void callNativeGetElementResult(ObjOperandId obj, Int32OperandId index) {
writeOpWithOperandId(CacheOp::CallNativeGetElementResult, obj);
writeOperandId(index);
}
void callIsSuspendedGeneratorResult(ValOperandId val) {
writeOpWithOperandId(CacheOp::CallIsSuspendedGeneratorResult, val);
}
void loadEnvironmentFixedSlotResult(ObjOperandId obj, size_t offset) {
writeOpWithOperandId(CacheOp::LoadEnvironmentFixedSlotResult, obj);
addStubField(offset, StubField::Type::RawWord);
}
void loadEnvironmentDynamicSlotResult(ObjOperandId obj, size_t offset) {
writeOpWithOperandId(CacheOp::LoadEnvironmentDynamicSlotResult, obj);
addStubField(offset, StubField::Type::RawWord);
}
void loadObjectResult(ObjOperandId obj) {
writeOpWithOperandId(CacheOp::LoadObjectResult, obj);
}
void loadInstanceOfObjectResult(ValOperandId lhs, ObjOperandId protoId,
uint32_t slot) {
writeOpWithOperandId(CacheOp::LoadInstanceOfObjectResult, lhs);
writeOperandId(protoId);
}
void loadTypeOfObjectResult(ObjOperandId obj) {
writeOpWithOperandId(CacheOp::LoadTypeOfObjectResult, obj);
}
void loadInt32TruthyResult(ValOperandId integer) {
writeOpWithOperandId(CacheOp::LoadInt32TruthyResult, integer);
}
void loadDoubleTruthyResult(ValOperandId dbl) {
writeOpWithOperandId(CacheOp::LoadDoubleTruthyResult, dbl);
}
void loadStringTruthyResult(StringOperandId str) {
writeOpWithOperandId(CacheOp::LoadStringTruthyResult, str);
}
void loadObjectTruthyResult(ObjOperandId obj) {
writeOpWithOperandId(CacheOp::LoadObjectTruthyResult, obj);
}
void loadValueResult(const Value& val) {
writeOp(CacheOp::LoadValueResult);
addStubField(val.asRawBits(), StubField::Type::Value);
}
void loadNewObjectFromTemplateResult(JSObject* templateObj) {
writeOp(CacheOp::LoadNewObjectFromTemplateResult);
addStubField(uintptr_t(templateObj), StubField::Type::JSObject);
uint64_t id = cx_->runtime()->jitRuntime()->nextDisambiguationId();
writeUint32Immediate(id & UINT32_MAX);
writeUint32Immediate(id >> 32);
}
void callStringConcatResult(StringOperandId lhs, StringOperandId rhs) {
writeOpWithOperandId(CacheOp::CallStringConcatResult, lhs);
writeOperandId(rhs);
}
void callStringObjectConcatResult(ValOperandId lhs, ValOperandId rhs) {
writeOpWithOperandId(CacheOp::CallStringObjectConcatResult, lhs);
writeOperandId(rhs);
}
void callStringSplitResult(StringOperandId str, StringOperandId sep,
ObjectGroup* group) {
writeOpWithOperandId(CacheOp::CallStringSplitResult, str);
writeOperandId(sep);
addStubField(uintptr_t(group), StubField::Type::ObjectGroup);
}
void compareStringResult(uint32_t op, StringOperandId lhs,
StringOperandId rhs) {
writeOpWithOperandId(CacheOp::CompareStringResult, lhs);
writeOperandId(rhs);
buffer_.writeByte(uint32_t(op));
}
void compareObjectResult(uint32_t op, ObjOperandId lhs, ObjOperandId rhs) {
writeOpWithOperandId(CacheOp::CompareObjectResult, lhs);
writeOperandId(rhs);
buffer_.writeByte(uint32_t(op));
}
void compareObjectUndefinedNullResult(uint32_t op, ObjOperandId object) {
writeOpWithOperandId(CacheOp::CompareObjectUndefinedNullResult, object);
buffer_.writeByte(uint32_t(op));
}
void compareSymbolResult(uint32_t op, SymbolOperandId lhs,
SymbolOperandId rhs) {
writeOpWithOperandId(CacheOp::CompareSymbolResult, lhs);
writeOperandId(rhs);
buffer_.writeByte(uint32_t(op));
}
void compareInt32Result(uint32_t op, Int32OperandId lhs, Int32OperandId rhs) {
writeOpWithOperandId(CacheOp::CompareInt32Result, lhs);
writeOperandId(rhs);
buffer_.writeByte(uint32_t(op));
}
void compareDoubleResult(uint32_t op, ValOperandId lhs, ValOperandId rhs) {
writeOpWithOperandId(CacheOp::CompareDoubleResult, lhs);
writeOperandId(rhs);
buffer_.writeByte(uint32_t(op));
}
void callPrintString(const char* str) {
writeOp(CacheOp::CallPrintString);
writePointer(const_cast<char*>(str));
}
void breakpoint() { writeOp(CacheOp::Breakpoint); }
void typeMonitorResult() { writeOp(CacheOp::TypeMonitorResult); }
void returnFromIC() { writeOp(CacheOp::ReturnFromIC); }
void wrapResult() { writeOp(CacheOp::WrapResult); }
};
class CacheIRStubInfo;
class MOZ_RAII CacheIRReader {
CompactBufferReader buffer_;
CacheIRReader(const CacheIRReader&) = delete;
CacheIRReader& operator=(const CacheIRReader&) = delete;
public:
CacheIRReader(const uint8_t* start, const uint8_t* end)
: buffer_(start, end) {}
explicit CacheIRReader(const CacheIRWriter& writer)
: CacheIRReader(writer.codeStart(), writer.codeEnd()) {}
explicit CacheIRReader(const CacheIRStubInfo* stubInfo);
bool more() const { return buffer_.more(); }
CacheOp readOp() { return CacheOp(buffer_.readByte()); }
void skip() { buffer_.readByte(); }
ValOperandId valOperandId() { return ValOperandId(buffer_.readByte()); }
ValueTagOperandId valueTagOperandId() {
return ValueTagOperandId(buffer_.readByte());
}
ObjOperandId objOperandId() { return ObjOperandId(buffer_.readByte()); }
StringOperandId stringOperandId() {
return StringOperandId(buffer_.readByte());
}
SymbolOperandId symbolOperandId() {
return SymbolOperandId(buffer_.readByte());
}
Int32OperandId int32OperandId() { return Int32OperandId(buffer_.readByte()); }
uint32_t stubOffset() { return buffer_.readByte() * sizeof(uintptr_t); }
GuardClassKind guardClassKind() { return GuardClassKind(buffer_.readByte()); }
JSValueType jsValueType() { return JSValueType(buffer_.readByte()); }
ValueType valueType() { return ValueType(buffer_.readByte()); }
TypedThingLayout typedThingLayout() {
return TypedThingLayout(buffer_.readByte());
}
Scalar::Type scalarType() { return Scalar::Type(buffer_.readByte()); }
uint32_t typeDescrKey() { return buffer_.readByte(); }
JSWhyMagic whyMagic() { return JSWhyMagic(buffer_.readByte()); }
JSOp jsop() { return JSOp(buffer_.readByte()); }
int32_t int32Immediate() { return int32_t(buffer_.readFixedUint32_t()); }
uint32_t uint32Immediate() { return buffer_.readFixedUint32_t(); }
void* pointer() { return buffer_.readRawPointer(); }
ReferenceType referenceTypeDescrType() {
return ReferenceType(buffer_.readByte());
}
uint8_t readByte() { return buffer_.readByte(); }
bool readBool() {
uint8_t b = buffer_.readByte();
MOZ_ASSERT(b <= 1);
return bool(b);
}
bool matchOp(CacheOp op) {
const uint8_t* pos = buffer_.currentPosition();
if (readOp() == op) {
return true;
}
buffer_.seek(pos, 0);
return false;
}
bool matchOp(CacheOp op, OperandId id) {
const uint8_t* pos = buffer_.currentPosition();
if (readOp() == op && buffer_.readByte() == id.id()) {
return true;
}
buffer_.seek(pos, 0);
return false;
}
bool matchOpEither(CacheOp op1, CacheOp op2) {
const uint8_t* pos = buffer_.currentPosition();
CacheOp op = readOp();
if (op == op1 || op == op2) {
return true;
}
buffer_.seek(pos, 0);
return false;
}
const uint8_t* currentPosition() const { return buffer_.currentPosition(); }
};
class MOZ_RAII IRGenerator {
protected:
CacheIRWriter writer;
JSContext* cx_;
HandleScript script_;
jsbytecode* pc_;
CacheKind cacheKind_;
ICState::Mode mode_;
IRGenerator(const IRGenerator&) = delete;
IRGenerator& operator=(const IRGenerator&) = delete;
bool maybeGuardInt32Index(const Value& index, ValOperandId indexId,
uint32_t* int32Index, Int32OperandId* int32IndexId);
ObjOperandId guardDOMProxyExpandoObjectAndShape(JSObject* obj,
ObjOperandId objId,
const Value& expandoVal,
JSObject* expandoObj);
void emitIdGuard(ValOperandId valId, jsid id);
friend class CacheIRSpewer;
public:
explicit IRGenerator(JSContext* cx, HandleScript script, jsbytecode* pc,
CacheKind cacheKind, ICState::Mode mode);
const CacheIRWriter& writerRef() const { return writer; }
CacheKind cacheKind() const { return cacheKind_; }
static constexpr char* NotAttached = nullptr;
};
enum class GetPropertyResultFlags {
None = 0,
Monitored = 1 << 0,
AllowUndefined = 1 << 1,
AllowInt32 = 1 << 2,
AllowDouble = 1 << 3,
All = Monitored | AllowUndefined | AllowInt32 | AllowDouble
};
static inline bool operator&(GetPropertyResultFlags a,
GetPropertyResultFlags b) {
return static_cast<int>(a) & static_cast<int>(b);
}
static inline GetPropertyResultFlags operator|(GetPropertyResultFlags a,
GetPropertyResultFlags b) {
return static_cast<GetPropertyResultFlags>(static_cast<int>(a) |
static_cast<int>(b));
}
static inline GetPropertyResultFlags& operator|=(GetPropertyResultFlags& lhs,
GetPropertyResultFlags b) {
lhs = lhs | b;
return lhs;
}
class MOZ_RAII GetPropIRGenerator : public IRGenerator {
HandleValue val_;
HandleValue idVal_;
HandleValue receiver_;
bool* isTemporarilyUnoptimizable_;
GetPropertyResultFlags resultFlags_;
enum class PreliminaryObjectAction { None, Unlink, NotePreliminary };
PreliminaryObjectAction preliminaryObjectAction_;
bool tryAttachNative(HandleObject obj, ObjOperandId objId, HandleId id);
bool tryAttachUnboxed(HandleObject obj, ObjOperandId objId, HandleId id);
bool tryAttachUnboxedExpando(HandleObject obj, ObjOperandId objId,
HandleId id);
bool tryAttachTypedObject(HandleObject obj, ObjOperandId objId, HandleId id);
bool tryAttachObjectLength(HandleObject obj, ObjOperandId objId, HandleId id);
bool tryAttachModuleNamespace(HandleObject obj, ObjOperandId objId,
HandleId id);
bool tryAttachWindowProxy(HandleObject obj, ObjOperandId objId, HandleId id);
bool tryAttachCrossCompartmentWrapper(HandleObject obj, ObjOperandId objId,
HandleId id);
bool tryAttachXrayCrossCompartmentWrapper(HandleObject obj,
ObjOperandId objId, HandleId id);
bool tryAttachFunction(HandleObject obj, ObjOperandId objId, HandleId id);
bool tryAttachGenericProxy(HandleObject obj, ObjOperandId objId, HandleId id,
bool handleDOMProxies);
bool tryAttachDOMProxyExpando(HandleObject obj, ObjOperandId objId,
HandleId id);
bool tryAttachDOMProxyShadowed(HandleObject obj, ObjOperandId objId,
HandleId id);
bool tryAttachDOMProxyUnshadowed(HandleObject obj, ObjOperandId objId,
HandleId id);
bool tryAttachProxy(HandleObject obj, ObjOperandId objId, HandleId id);
bool tryAttachPrimitive(ValOperandId valId, HandleId id);
bool tryAttachStringChar(ValOperandId valId, ValOperandId indexId);
bool tryAttachStringLength(ValOperandId valId, HandleId id);
bool tryAttachMagicArgumentsName(ValOperandId valId, HandleId id);
bool tryAttachMagicArgument(ValOperandId valId, ValOperandId indexId);
bool tryAttachArgumentsObjectArg(HandleObject obj, ObjOperandId objId,
Int32OperandId indexId);
bool tryAttachDenseElement(HandleObject obj, ObjOperandId objId,
uint32_t index, Int32OperandId indexId);
bool tryAttachDenseElementHole(HandleObject obj, ObjOperandId objId,
uint32_t index, Int32OperandId indexId);
bool tryAttachSparseElement(HandleObject obj, ObjOperandId objId,
uint32_t index, Int32OperandId indexId);
bool tryAttachTypedElement(HandleObject obj, ObjOperandId objId,
uint32_t index, Int32OperandId indexId);
bool tryAttachUnboxedElementHole(HandleObject obj, ObjOperandId objId,
uint32_t index, Int32OperandId indexId);
bool tryAttachGenericElement(HandleObject obj, ObjOperandId objId,
uint32_t index, Int32OperandId indexId);
bool tryAttachProxyElement(HandleObject obj, ObjOperandId objId);
void attachMegamorphicNativeSlot(ObjOperandId objId, jsid id,
bool handleMissing);
ValOperandId getElemKeyValueId() const {
MOZ_ASSERT(cacheKind_ == CacheKind::GetElem ||
cacheKind_ == CacheKind::GetElemSuper);
return ValOperandId(1);
}
ValOperandId getSuperReceiverValueId() const {
if (cacheKind_ == CacheKind::GetPropSuper) {
return ValOperandId(1);
}
MOZ_ASSERT(cacheKind_ == CacheKind::GetElemSuper);
return ValOperandId(2);
}
bool isSuper() const {
return (cacheKind_ == CacheKind::GetPropSuper ||
cacheKind_ == CacheKind::GetElemSuper);
}
bool idempotent() const { return pc_ == nullptr; }
void maybeEmitIdGuard(jsid id);
void trackAttached(const char* name);
public:
GetPropIRGenerator(JSContext* cx, HandleScript script, jsbytecode* pc,
CacheKind cacheKind, ICState::Mode mode,
bool* isTemporarilyUnoptimizable, HandleValue val,
HandleValue idVal, HandleValue receiver,
GetPropertyResultFlags resultFlags);
bool tryAttachStub();
bool tryAttachIdempotentStub();
bool shouldUnlinkPreliminaryObjectStubs() const {
return preliminaryObjectAction_ == PreliminaryObjectAction::Unlink;
}
bool shouldNotePreliminaryObjectStub() const {
return preliminaryObjectAction_ == PreliminaryObjectAction::NotePreliminary;
}
};
class MOZ_RAII GetNameIRGenerator : public IRGenerator {
HandleObject env_;
HandlePropertyName name_;
bool tryAttachGlobalNameValue(ObjOperandId objId, HandleId id);
bool tryAttachGlobalNameGetter(ObjOperandId objId, HandleId id);
bool tryAttachEnvironmentName(ObjOperandId objId, HandleId id);
void trackAttached(const char* name);
public:
GetNameIRGenerator(JSContext* cx, HandleScript script, jsbytecode* pc,
ICState::Mode mode, HandleObject env,
HandlePropertyName name);
bool tryAttachStub();
};
class MOZ_RAII BindNameIRGenerator : public IRGenerator {
HandleObject env_;
HandlePropertyName name_;
bool tryAttachGlobalName(ObjOperandId objId, HandleId id);
bool tryAttachEnvironmentName(ObjOperandId objId, HandleId id);
void trackAttached(const char* name);
public:
BindNameIRGenerator(JSContext* cx, HandleScript script, jsbytecode* pc,
ICState::Mode mode, HandleObject env,
HandlePropertyName name);
bool tryAttachStub();
};
class MOZ_RAII PropertyTypeCheckInfo {
RootedObjectGroup group_;
RootedId id_;
bool needsTypeBarrier_;
PropertyTypeCheckInfo(const PropertyTypeCheckInfo&) = delete;
void operator=(const PropertyTypeCheckInfo&) = delete;
public:
PropertyTypeCheckInfo(JSContext* cx, bool needsTypeBarrier)
: group_(cx), id_(cx), needsTypeBarrier_(needsTypeBarrier) {}
bool needsTypeBarrier() const { return needsTypeBarrier_; }
bool isSet() const { return group_ != nullptr; }
ObjectGroup* group() const {
MOZ_ASSERT(isSet());
return group_;
}
jsid id() const {
MOZ_ASSERT(isSet());
return id_;
}
void set(ObjectGroup* group, jsid id) {
MOZ_ASSERT(!group_);
MOZ_ASSERT(group);
if (needsTypeBarrier_) {
group_ = group;
id_ = id;
}
}
};
class MOZ_RAII SetPropIRGenerator : public IRGenerator {
HandleValue lhsVal_;
HandleValue idVal_;
HandleValue rhsVal_;
bool* isTemporarilyUnoptimizable_;
bool* canAddSlot_;
PropertyTypeCheckInfo typeCheckInfo_;
enum class PreliminaryObjectAction { None, Unlink, NotePreliminary };
PreliminaryObjectAction preliminaryObjectAction_;
bool attachedTypedArrayOOBStub_;
bool maybeHasExtraIndexedProps_;
ValOperandId setElemKeyValueId() const {
MOZ_ASSERT(cacheKind_ == CacheKind::SetElem);
return ValOperandId(1);
}
ValOperandId rhsValueId() const {
if (cacheKind_ == CacheKind::SetProp) {
return ValOperandId(1);
}
MOZ_ASSERT(cacheKind_ == CacheKind::SetElem);
return ValOperandId(2);
}
void maybeEmitIdGuard(jsid id);
bool tryAttachNativeSetSlot(HandleObject obj, ObjOperandId objId, HandleId id,
ValOperandId rhsId);
bool tryAttachUnboxedExpandoSetSlot(HandleObject obj, ObjOperandId objId,
HandleId id, ValOperandId rhsId);
bool tryAttachUnboxedProperty(HandleObject obj, ObjOperandId objId,
HandleId id, ValOperandId rhsId);
bool tryAttachTypedObjectProperty(HandleObject obj, ObjOperandId objId,
HandleId id, ValOperandId rhsId);
bool tryAttachSetter(HandleObject obj, ObjOperandId objId, HandleId id,
ValOperandId rhsId);
bool tryAttachSetArrayLength(HandleObject obj, ObjOperandId objId,
HandleId id, ValOperandId rhsId);
bool tryAttachWindowProxy(HandleObject obj, ObjOperandId objId, HandleId id,
ValOperandId rhsId);
bool tryAttachSetDenseElement(HandleObject obj, ObjOperandId objId,
uint32_t index, Int32OperandId indexId,
ValOperandId rhsId);
bool tryAttachSetTypedElement(HandleObject obj, ObjOperandId objId,
uint32_t index, Int32OperandId indexId,
ValOperandId rhsId);
bool tryAttachSetDenseElementHole(HandleObject obj, ObjOperandId objId,
uint32_t index, Int32OperandId indexId,
ValOperandId rhsId);
bool tryAttachAddOrUpdateSparseElement(HandleObject obj, ObjOperandId objId,
uint32_t index, Int32OperandId indexId,
ValOperandId rhsId);
bool tryAttachGenericProxy(HandleObject obj, ObjOperandId objId, HandleId id,
ValOperandId rhsId, bool handleDOMProxies);
bool tryAttachDOMProxyShadowed(HandleObject obj, ObjOperandId objId,
HandleId id, ValOperandId rhsId);
bool tryAttachDOMProxyUnshadowed(HandleObject obj, ObjOperandId objId,
HandleId id, ValOperandId rhsId);
bool tryAttachDOMProxyExpando(HandleObject obj, ObjOperandId objId,
HandleId id, ValOperandId rhsId);
bool tryAttachProxy(HandleObject obj, ObjOperandId objId, HandleId id,
ValOperandId rhsId);
bool tryAttachProxyElement(HandleObject obj, ObjOperandId objId,
ValOperandId rhsId);
bool tryAttachMegamorphicSetElement(HandleObject obj, ObjOperandId objId,
ValOperandId rhsId);
bool canAttachAddSlotStub(HandleObject obj, HandleId id);
public:
SetPropIRGenerator(JSContext* cx, HandleScript script, jsbytecode* pc,
CacheKind cacheKind, ICState::Mode mode,
bool* isTemporarilyUnoptimizable, bool* canAddSlot,
HandleValue lhsVal, HandleValue idVal, HandleValue rhsVal,
bool needsTypeBarrier = true,
bool maybeHasExtraIndexedProps = true);
bool tryAttachStub();
bool tryAttachAddSlotStub(HandleObjectGroup oldGroup, HandleShape oldShape);
void trackAttached(const char* name);
bool shouldUnlinkPreliminaryObjectStubs() const {
return preliminaryObjectAction_ == PreliminaryObjectAction::Unlink;
}
bool shouldNotePreliminaryObjectStub() const {
return preliminaryObjectAction_ == PreliminaryObjectAction::NotePreliminary;
}
const PropertyTypeCheckInfo* typeCheckInfo() const { return &typeCheckInfo_; }
bool attachedTypedArrayOOBStub() const { return attachedTypedArrayOOBStub_; }
};
class MOZ_RAII HasPropIRGenerator : public IRGenerator {
HandleValue val_;
HandleValue idVal_;
bool tryAttachDense(HandleObject obj, ObjOperandId objId, uint32_t index,
Int32OperandId indexId);
bool tryAttachDenseHole(HandleObject obj, ObjOperandId objId, uint32_t index,
Int32OperandId indexId);
bool tryAttachTypedArray(HandleObject obj, ObjOperandId objId,
Int32OperandId indexId);
bool tryAttachSparse(HandleObject obj, ObjOperandId objId,
Int32OperandId indexId);
bool tryAttachNamedProp(HandleObject obj, ObjOperandId objId, HandleId key,
ValOperandId keyId);
bool tryAttachMegamorphic(ObjOperandId objId, ValOperandId keyId);
bool tryAttachNative(JSObject* obj, ObjOperandId objId, jsid key,
ValOperandId keyId, PropertyResult prop,
JSObject* holder);
bool tryAttachUnboxed(JSObject* obj, ObjOperandId objId, jsid key,
ValOperandId keyId);
bool tryAttachUnboxedExpando(JSObject* obj, ObjOperandId objId, jsid key,
ValOperandId keyId);
bool tryAttachTypedObject(JSObject* obj, ObjOperandId objId, jsid key,
ValOperandId keyId);
bool tryAttachSlotDoesNotExist(JSObject* obj, ObjOperandId objId, jsid key,
ValOperandId keyId);
bool tryAttachDoesNotExist(HandleObject obj, ObjOperandId objId, HandleId key,
ValOperandId keyId);
bool tryAttachProxyElement(HandleObject obj, ObjOperandId objId,
ValOperandId keyId);
void trackAttached(const char* name);
public:
HasPropIRGenerator(JSContext* cx, HandleScript script, jsbytecode* pc,
ICState::Mode mode, CacheKind cacheKind, HandleValue idVal,
HandleValue val);
bool tryAttachStub();
};
class MOZ_RAII InstanceOfIRGenerator : public IRGenerator {
HandleValue lhsVal_;
HandleObject rhsObj_;
void trackAttached(const char* name);
public:
InstanceOfIRGenerator(JSContext*, HandleScript, jsbytecode*, ICState::Mode,
HandleValue, HandleObject);
bool tryAttachStub();
};
class MOZ_RAII TypeOfIRGenerator : public IRGenerator {
HandleValue val_;
bool tryAttachPrimitive(ValOperandId valId);
bool tryAttachObject(ValOperandId valId);
void trackAttached(const char* name);
public:
TypeOfIRGenerator(JSContext* cx, HandleScript, jsbytecode* pc,
ICState::Mode mode, HandleValue value);
bool tryAttachStub();
};
class MOZ_RAII GetIteratorIRGenerator : public IRGenerator {
HandleValue val_;
bool tryAttachNativeIterator(ObjOperandId objId, HandleObject obj);
public:
GetIteratorIRGenerator(JSContext* cx, HandleScript, jsbytecode* pc,
ICState::Mode mode, HandleValue value);
bool tryAttachStub();
void trackAttached(const char* name);
};
class MOZ_RAII CallIRGenerator : public IRGenerator {
private:
JSOp op_;
uint32_t argc_;
HandleValue callee_;
HandleValue thisval_;
HandleValueArray args_;
PropertyTypeCheckInfo typeCheckInfo_;
BaselineCacheIRStubKind cacheIRStubKind_;
bool tryAttachStringSplit();
bool tryAttachArrayPush();
bool tryAttachArrayJoin();
bool tryAttachIsSuspendedGenerator();
void trackAttached(const char* name);
public:
CallIRGenerator(JSContext* cx, HandleScript script, jsbytecode* pc, JSOp op,
ICState::Mode mode, uint32_t argc, HandleValue callee,
HandleValue thisval, HandleValueArray args);
bool tryAttachStub();
BaselineCacheIRStubKind cacheIRStubKind() const { return cacheIRStubKind_; }
const PropertyTypeCheckInfo* typeCheckInfo() const { return &typeCheckInfo_; }
};
class MOZ_RAII CompareIRGenerator : public IRGenerator {
JSOp op_;
HandleValue lhsVal_;
HandleValue rhsVal_;
bool tryAttachString(ValOperandId lhsId, ValOperandId rhsId);
bool tryAttachObject(ValOperandId lhsId, ValOperandId rhsId);
bool tryAttachSymbol(ValOperandId lhsId, ValOperandId rhsId);
bool tryAttachStrictDifferentTypes(ValOperandId lhsId, ValOperandId rhsId);
bool tryAttachInt32(ValOperandId lhsId, ValOperandId rhsId);
bool tryAttachNumber(ValOperandId lhsId, ValOperandId rhsId);
bool tryAttachNumberUndefined(ValOperandId lhsId, ValOperandId rhsId);
bool tryAttachPrimitiveUndefined(ValOperandId lhsId, ValOperandId rhsId);
bool tryAttachObjectUndefined(ValOperandId lhsId, ValOperandId rhsId);
bool tryAttachNullUndefined(ValOperandId lhsId, ValOperandId rhsId);
bool tryAttachStringNumber(ValOperandId lhsId, ValOperandId rhsId);
void trackAttached(const char* name);
public:
CompareIRGenerator(JSContext* cx, HandleScript, jsbytecode* pc,
ICState::Mode mode, JSOp op, HandleValue lhsVal,
HandleValue rhsVal);
bool tryAttachStub();
};
class MOZ_RAII ToBoolIRGenerator : public IRGenerator {
HandleValue val_;
bool tryAttachInt32();
bool tryAttachDouble();
bool tryAttachString();
bool tryAttachSymbol();
bool tryAttachNullOrUndefined();
bool tryAttachObject();
void trackAttached(const char* name);
public:
ToBoolIRGenerator(JSContext* cx, HandleScript, jsbytecode* pc,
ICState::Mode mode, HandleValue val);
bool tryAttachStub();
};
class MOZ_RAII GetIntrinsicIRGenerator : public IRGenerator {
HandleValue val_;
void trackAttached(const char* name);
public:
GetIntrinsicIRGenerator(JSContext* cx, HandleScript, jsbytecode* pc,
ICState::Mode, HandleValue val);
bool tryAttachStub();
};
class MOZ_RAII UnaryArithIRGenerator : public IRGenerator {
JSOp op_;
HandleValue val_;
HandleValue res_;
bool tryAttachInt32();
bool tryAttachNumber();
void trackAttached(const char* name);
public:
UnaryArithIRGenerator(JSContext* cx, HandleScript, jsbytecode* pc,
ICState::Mode mode, JSOp op, HandleValue val,
HandleValue res);
bool tryAttachStub();
};
class MOZ_RAII BinaryArithIRGenerator : public IRGenerator {
JSOp op_;
HandleValue lhs_;
HandleValue rhs_;
HandleValue res_;
void trackAttached(const char* name);
bool tryAttachInt32();
bool tryAttachDouble();
bool tryAttachBitwise();
bool tryAttachStringConcat();
bool tryAttachStringObjectConcat();
bool tryAttachStringNumberConcat();
public:
BinaryArithIRGenerator(JSContext* cx, HandleScript, jsbytecode* pc,
ICState::Mode, JSOp op, HandleValue lhs,
HandleValue rhs, HandleValue res);
bool tryAttachStub();
};
class MOZ_RAII NewObjectIRGenerator : public IRGenerator {
#ifdef JS_CACHEIR_SPEW
JSOp op_;
#endif
HandleObject templateObject_;
void trackAttached(const char* name);
public:
NewObjectIRGenerator(JSContext* cx, HandleScript, jsbytecode* pc,
ICState::Mode, JSOp op, HandleObject templateObj);
bool tryAttachStub();
};
static inline uint32_t SimpleTypeDescrKey(SimpleTypeDescr* descr) {
if (descr->is<ScalarTypeDescr>()) {
return uint32_t(descr->as<ScalarTypeDescr>().type()) << 1;
}
return (uint32_t(descr->as<ReferenceTypeDescr>().type()) << 1) | 1;
}
inline bool SimpleTypeDescrKeyIsScalar(uint32_t key) { return !(key & 1); }
inline ScalarTypeDescr::Type ScalarTypeFromSimpleTypeDescrKey(uint32_t key) {
MOZ_ASSERT(SimpleTypeDescrKeyIsScalar(key));
return ScalarTypeDescr::Type(key >> 1);
}
inline ReferenceType ReferenceTypeFromSimpleTypeDescrKey(uint32_t key) {
MOZ_ASSERT(!SimpleTypeDescrKeyIsScalar(key));
return ReferenceType(key >> 1);
}
extern bool IsWindowProxyForScriptGlobal(JSScript* script, JSObject* obj);
} }
#endif