зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1146597 - Backout 02dad33cf2a0 for regressions on a CLOSED TREE.
This commit is contained in:
Родитель
b0d00c392a
Коммит
103c1aa5e2
|
@ -6430,7 +6430,7 @@ BytecodeEmitter::emitCallOrNew(ParseNode* pn)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!emitArray(pn2->pn_next, argc, JSOP_SPREADCALLARRAY))
|
if (!emitArray(pn2->pn_next, argc))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
emittingForInit = oldEmittingForInit;
|
emittingForInit = oldEmittingForInit;
|
||||||
|
@ -6897,7 +6897,7 @@ BytecodeEmitter::emitSpread()
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
BytecodeEmitter::emitArray(ParseNode* pn, uint32_t count, JSOp op)
|
BytecodeEmitter::emitArray(ParseNode* pn, uint32_t count)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Emit code for [a, b, c] that is equivalent to constructing a new
|
* Emit code for [a, b, c] that is equivalent to constructing a new
|
||||||
|
@ -6907,7 +6907,6 @@ BytecodeEmitter::emitArray(ParseNode* pn, uint32_t count, JSOp op)
|
||||||
* to avoid dup'ing and popping the array as each element is added, as
|
* to avoid dup'ing and popping the array as each element is added, as
|
||||||
* JSOP_SETELEM/JSOP_SETPROP would do.
|
* JSOP_SETELEM/JSOP_SETPROP would do.
|
||||||
*/
|
*/
|
||||||
MOZ_ASSERT(op == JSOP_NEWARRAY || op == JSOP_SPREADCALLARRAY);
|
|
||||||
|
|
||||||
int32_t nspread = 0;
|
int32_t nspread = 0;
|
||||||
for (ParseNode* elt = pn; elt; elt = elt->pn_next) {
|
for (ParseNode* elt = pn; elt; elt = elt->pn_next) {
|
||||||
|
@ -6916,9 +6915,9 @@ BytecodeEmitter::emitArray(ParseNode* pn, uint32_t count, JSOp op)
|
||||||
}
|
}
|
||||||
|
|
||||||
ptrdiff_t off;
|
ptrdiff_t off;
|
||||||
if (!emitN(op, 3, &off)) // ARRAY
|
if (!emitN(JSOP_NEWARRAY, 3, &off)) // ARRAY
|
||||||
return false;
|
return false;
|
||||||
checkTypeSet(op);
|
checkTypeSet(JSOP_NEWARRAY);
|
||||||
jsbytecode* pc = code(off);
|
jsbytecode* pc = code(off);
|
||||||
|
|
||||||
// For arrays with spread, this is a very pessimistic allocation, the
|
// For arrays with spread, this is a very pessimistic allocation, the
|
||||||
|
@ -7576,7 +7575,7 @@ BytecodeEmitter::emitTree(ParseNode* pn)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ok = emitArray(pn->pn_head, pn->pn_count, JSOP_NEWARRAY);
|
ok = emitArray(pn->pn_head, pn->pn_count);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PNK_ARRAYCOMP:
|
case PNK_ARRAYCOMP:
|
||||||
|
|
|
@ -427,7 +427,7 @@ struct BytecodeEmitter
|
||||||
bool emitAtomOp(JSAtom* atom, JSOp op);
|
bool emitAtomOp(JSAtom* atom, JSOp op);
|
||||||
bool emitAtomOp(ParseNode* pn, JSOp op);
|
bool emitAtomOp(ParseNode* pn, JSOp op);
|
||||||
|
|
||||||
bool emitArray(ParseNode* pn, uint32_t count, JSOp op);
|
bool emitArray(ParseNode* pn, uint32_t count);
|
||||||
bool emitArrayComp(ParseNode* pn);
|
bool emitArrayComp(ParseNode* pn);
|
||||||
|
|
||||||
bool emitInternedObjectOp(uint32_t index, JSOp op);
|
bool emitInternedObjectOp(uint32_t index, JSOp op);
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
// Ion eager fails the test below because we have not yet created any
|
// Ion eager fails the test below because we have not yet created any
|
||||||
// template object in baseline before running the content of the top-level
|
// template object in baseline before running the content of the top-level
|
||||||
// function.
|
// function.
|
||||||
if (getJitCompilerOptions()["ion.warmup.trigger"] <= 100)
|
if (getJitCompilerOptions()["ion.warmup.trigger"] <= 20)
|
||||||
setJitCompilerOption("ion.warmup.trigger", 100);
|
setJitCompilerOption("ion.warmup.trigger", 20);
|
||||||
|
|
||||||
// This function is used to force a bailout when it is inlined, and to recover
|
// This function is used to force a bailout when it is inlined, and to recover
|
||||||
// the frame which is inlining this function.
|
// the frame which is inlining this function.
|
||||||
|
|
|
@ -1740,11 +1740,23 @@ BaselineCompiler::emit_JSOP_NEWARRAY()
|
||||||
frame.syncStack(0);
|
frame.syncStack(0);
|
||||||
|
|
||||||
uint32_t length = GET_UINT24(pc);
|
uint32_t length = GET_UINT24(pc);
|
||||||
|
RootedObjectGroup group(cx);
|
||||||
|
if (!ObjectGroup::useSingletonForAllocationSite(script, pc, JSProto_Array)) {
|
||||||
|
group = ObjectGroup::allocationSiteGroup(cx, script, pc, JSProto_Array);
|
||||||
|
if (!group)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Pass length in R0.
|
// Pass length in R0, group in R1.
|
||||||
masm.move32(Imm32(length), R0.scratchReg());
|
masm.move32(Imm32(length), R0.scratchReg());
|
||||||
|
masm.movePtr(ImmGCPtr(group), R1.scratchReg());
|
||||||
|
|
||||||
ICNewArray_Fallback::Compiler stubCompiler(cx);
|
ArrayObject* templateObject = NewDenseUnallocatedArray(cx, length, NullPtr(), TenuredObject);
|
||||||
|
if (!templateObject)
|
||||||
|
return false;
|
||||||
|
templateObject->setGroup(group);
|
||||||
|
|
||||||
|
ICNewArray_Fallback::Compiler stubCompiler(cx, templateObject);
|
||||||
if (!emitOpIC(stubCompiler.getStub(&stubSpace_)))
|
if (!emitOpIC(stubCompiler.getStub(&stubSpace_)))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -1752,12 +1764,6 @@ BaselineCompiler::emit_JSOP_NEWARRAY()
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
|
||||||
BaselineCompiler::emit_JSOP_SPREADCALLARRAY()
|
|
||||||
{
|
|
||||||
return emit_JSOP_NEWARRAY();
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef JSObject* (*NewArrayCopyOnWriteFn)(JSContext*, HandleArrayObject, gc::InitialHeap);
|
typedef JSObject* (*NewArrayCopyOnWriteFn)(JSContext*, HandleArrayObject, gc::InitialHeap);
|
||||||
const VMFunction jit::NewArrayCopyOnWriteInfo =
|
const VMFunction jit::NewArrayCopyOnWriteInfo =
|
||||||
FunctionInfo<NewArrayCopyOnWriteFn>(js::NewDenseCopyOnWriteArray);
|
FunctionInfo<NewArrayCopyOnWriteFn>(js::NewDenseCopyOnWriteArray);
|
||||||
|
@ -1823,11 +1829,24 @@ BaselineCompiler::emit_JSOP_NEWINIT()
|
||||||
frame.syncStack(0);
|
frame.syncStack(0);
|
||||||
JSProtoKey key = JSProtoKey(GET_UINT8(pc));
|
JSProtoKey key = JSProtoKey(GET_UINT8(pc));
|
||||||
|
|
||||||
if (key == JSProto_Array) {
|
RootedObjectGroup group(cx);
|
||||||
// Pass length in R0.
|
if (!ObjectGroup::useSingletonForAllocationSite(script, pc, key)) {
|
||||||
masm.move32(Imm32(0), R0.scratchReg());
|
group = ObjectGroup::allocationSiteGroup(cx, script, pc, key);
|
||||||
|
if (!group)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
ICNewArray_Fallback::Compiler stubCompiler(cx);
|
if (key == JSProto_Array) {
|
||||||
|
// Pass length in R0, group in R1.
|
||||||
|
masm.move32(Imm32(0), R0.scratchReg());
|
||||||
|
masm.movePtr(ImmGCPtr(group), R1.scratchReg());
|
||||||
|
|
||||||
|
ArrayObject* templateObject = NewDenseUnallocatedArray(cx, 0, NullPtr(), TenuredObject);
|
||||||
|
if (!templateObject)
|
||||||
|
return false;
|
||||||
|
templateObject->setGroup(group);
|
||||||
|
|
||||||
|
ICNewArray_Fallback::Compiler stubCompiler(cx, templateObject);
|
||||||
if (!emitOpIC(stubCompiler.getStub(&stubSpace_)))
|
if (!emitOpIC(stubCompiler.getStub(&stubSpace_)))
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -93,7 +93,6 @@ namespace jit {
|
||||||
_(JSOP_BITNOT) \
|
_(JSOP_BITNOT) \
|
||||||
_(JSOP_NEG) \
|
_(JSOP_NEG) \
|
||||||
_(JSOP_NEWARRAY) \
|
_(JSOP_NEWARRAY) \
|
||||||
_(JSOP_SPREADCALLARRAY) \
|
|
||||||
_(JSOP_NEWARRAY_COPYONWRITE) \
|
_(JSOP_NEWARRAY_COPYONWRITE) \
|
||||||
_(JSOP_INITELEM_ARRAY) \
|
_(JSOP_INITELEM_ARRAY) \
|
||||||
_(JSOP_NEWOBJECT) \
|
_(JSOP_NEWOBJECT) \
|
||||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -397,13 +397,12 @@ class ICEntry
|
||||||
_(GetElem_NativePrototypeCallScripted) \
|
_(GetElem_NativePrototypeCallScripted) \
|
||||||
_(GetElem_String) \
|
_(GetElem_String) \
|
||||||
_(GetElem_Dense) \
|
_(GetElem_Dense) \
|
||||||
_(GetElem_UnboxedArray) \
|
|
||||||
_(GetElem_TypedArray) \
|
_(GetElem_TypedArray) \
|
||||||
_(GetElem_Arguments) \
|
_(GetElem_Arguments) \
|
||||||
\
|
\
|
||||||
_(SetElem_Fallback) \
|
_(SetElem_Fallback) \
|
||||||
_(SetElem_DenseOrUnboxedArray) \
|
_(SetElem_Dense) \
|
||||||
_(SetElem_DenseOrUnboxedArrayAdd) \
|
_(SetElem_DenseAdd) \
|
||||||
_(SetElem_TypedArray) \
|
_(SetElem_TypedArray) \
|
||||||
\
|
\
|
||||||
_(In_Fallback) \
|
_(In_Fallback) \
|
||||||
|
@ -429,7 +428,6 @@ class ICEntry
|
||||||
\
|
\
|
||||||
_(GetProp_Fallback) \
|
_(GetProp_Fallback) \
|
||||||
_(GetProp_ArrayLength) \
|
_(GetProp_ArrayLength) \
|
||||||
_(GetProp_UnboxedArrayLength) \
|
|
||||||
_(GetProp_Primitive) \
|
_(GetProp_Primitive) \
|
||||||
_(GetProp_StringLength) \
|
_(GetProp_StringLength) \
|
||||||
_(GetProp_Native) \
|
_(GetProp_Native) \
|
||||||
|
@ -1739,33 +1737,31 @@ class ICNewArray_Fallback : public ICFallbackStub
|
||||||
{
|
{
|
||||||
friend class ICStubSpace;
|
friend class ICStubSpace;
|
||||||
|
|
||||||
HeapPtrObject templateObject_;
|
HeapPtrArrayObject templateObject_;
|
||||||
|
|
||||||
explicit ICNewArray_Fallback(JitCode* stubCode)
|
ICNewArray_Fallback(JitCode* stubCode, ArrayObject* templateObject)
|
||||||
: ICFallbackStub(ICStub::NewArray_Fallback, stubCode), templateObject_(nullptr)
|
: ICFallbackStub(ICStub::NewArray_Fallback, stubCode), templateObject_(templateObject)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
class Compiler : public ICStubCompiler {
|
class Compiler : public ICStubCompiler {
|
||||||
|
RootedArrayObject templateObject;
|
||||||
bool generateStubCode(MacroAssembler& masm);
|
bool generateStubCode(MacroAssembler& masm);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit Compiler(JSContext* cx)
|
Compiler(JSContext* cx, ArrayObject* templateObject)
|
||||||
: ICStubCompiler(cx, ICStub::NewArray_Fallback)
|
: ICStubCompiler(cx, ICStub::NewArray_Fallback),
|
||||||
|
templateObject(cx, templateObject)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
ICStub* getStub(ICStubSpace* space) {
|
ICStub* getStub(ICStubSpace* space) {
|
||||||
return ICStub::New<ICNewArray_Fallback>(space, getStubCode());
|
return ICStub::New<ICNewArray_Fallback>(space, getStubCode(), templateObject);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
HeapPtrObject& templateObject() {
|
HeapPtrArrayObject& templateObject() {
|
||||||
return templateObject_;
|
return templateObject_;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setTemplateObject(JSObject* obj) {
|
|
||||||
templateObject_ = obj;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class ICNewObject_Fallback : public ICFallbackStub
|
class ICNewObject_Fallback : public ICFallbackStub
|
||||||
|
@ -3030,54 +3026,6 @@ class ICGetElem_Dense : public ICMonitoredStub
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
class ICGetElem_UnboxedArray : public ICMonitoredStub
|
|
||||||
{
|
|
||||||
friend class ICStubSpace;
|
|
||||||
|
|
||||||
HeapPtrObjectGroup group_;
|
|
||||||
|
|
||||||
ICGetElem_UnboxedArray(JitCode* stubCode, ICStub* firstMonitorStub, ObjectGroup* group);
|
|
||||||
|
|
||||||
public:
|
|
||||||
static ICGetElem_UnboxedArray* Clone(ICStubSpace* space, ICStub* firstMonitorStub,
|
|
||||||
ICGetElem_UnboxedArray& other);
|
|
||||||
|
|
||||||
static size_t offsetOfGroup() {
|
|
||||||
return offsetof(ICGetElem_UnboxedArray, group_);
|
|
||||||
}
|
|
||||||
|
|
||||||
HeapPtrObjectGroup& group() {
|
|
||||||
return group_;
|
|
||||||
}
|
|
||||||
|
|
||||||
class Compiler : public ICStubCompiler {
|
|
||||||
ICStub* firstMonitorStub_;
|
|
||||||
RootedObjectGroup group_;
|
|
||||||
JSValueType elementType_;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
bool generateStubCode(MacroAssembler& masm);
|
|
||||||
|
|
||||||
virtual int32_t getKey() const {
|
|
||||||
return static_cast<int32_t>(kind) |
|
|
||||||
(static_cast<int32_t>(elementType_) << 16);
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
Compiler(JSContext* cx, ICStub* firstMonitorStub, ObjectGroup* group)
|
|
||||||
: ICStubCompiler(cx, ICStub::GetElem_UnboxedArray),
|
|
||||||
firstMonitorStub_(firstMonitorStub),
|
|
||||||
group_(cx, group),
|
|
||||||
elementType_(group->unboxedLayout().elementType())
|
|
||||||
{}
|
|
||||||
|
|
||||||
ICStub* getStub(ICStubSpace* space) {
|
|
||||||
return ICStub::New<ICGetElem_UnboxedArray>(space, getStubCode(), firstMonitorStub_,
|
|
||||||
group_);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
// Enum for stubs handling a combination of typed arrays and typed objects.
|
// Enum for stubs handling a combination of typed arrays and typed objects.
|
||||||
enum TypedThingLayout {
|
enum TypedThingLayout {
|
||||||
Layout_TypedArray,
|
Layout_TypedArray,
|
||||||
|
@ -3235,21 +3183,21 @@ class ICSetElem_Fallback : public ICFallbackStub
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
class ICSetElem_DenseOrUnboxedArray : public ICUpdatedStub
|
class ICSetElem_Dense : public ICUpdatedStub
|
||||||
{
|
{
|
||||||
friend class ICStubSpace;
|
friend class ICStubSpace;
|
||||||
|
|
||||||
HeapPtrShape shape_; // null for unboxed arrays
|
HeapPtrShape shape_;
|
||||||
HeapPtrObjectGroup group_;
|
HeapPtrObjectGroup group_;
|
||||||
|
|
||||||
ICSetElem_DenseOrUnboxedArray(JitCode* stubCode, Shape* shape, ObjectGroup* group);
|
ICSetElem_Dense(JitCode* stubCode, Shape* shape, ObjectGroup* group);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static size_t offsetOfShape() {
|
static size_t offsetOfShape() {
|
||||||
return offsetof(ICSetElem_DenseOrUnboxedArray, shape_);
|
return offsetof(ICSetElem_Dense, shape_);
|
||||||
}
|
}
|
||||||
static size_t offsetOfGroup() {
|
static size_t offsetOfGroup() {
|
||||||
return offsetof(ICSetElem_DenseOrUnboxedArray, group_);
|
return offsetof(ICSetElem_Dense, group_);
|
||||||
}
|
}
|
||||||
|
|
||||||
HeapPtrShape& shape() {
|
HeapPtrShape& shape() {
|
||||||
|
@ -3261,41 +3209,33 @@ class ICSetElem_DenseOrUnboxedArray : public ICUpdatedStub
|
||||||
|
|
||||||
class Compiler : public ICStubCompiler {
|
class Compiler : public ICStubCompiler {
|
||||||
RootedShape shape_;
|
RootedShape shape_;
|
||||||
RootedObjectGroup group_;
|
|
||||||
JSValueType unboxedType_;
|
// Compiler is only live on stack during compilation, it should
|
||||||
|
// outlive any RootedObjectGroup it's passed. So it can just
|
||||||
|
// use the handle.
|
||||||
|
HandleObjectGroup group_;
|
||||||
|
|
||||||
bool generateStubCode(MacroAssembler& masm);
|
bool generateStubCode(MacroAssembler& masm);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual int32_t getKey() const {
|
|
||||||
return static_cast<int32_t>(kind) |
|
|
||||||
(static_cast<int32_t>(unboxedType_) << 16);
|
|
||||||
}
|
|
||||||
|
|
||||||
Compiler(JSContext* cx, Shape* shape, HandleObjectGroup group)
|
Compiler(JSContext* cx, Shape* shape, HandleObjectGroup group)
|
||||||
: ICStubCompiler(cx, ICStub::SetElem_DenseOrUnboxedArray),
|
: ICStubCompiler(cx, ICStub::SetElem_Dense),
|
||||||
shape_(cx, shape),
|
shape_(cx, shape),
|
||||||
group_(cx, group),
|
group_(group)
|
||||||
unboxedType_(shape ? JSVAL_TYPE_MAGIC : group->unboxedLayout().elementType())
|
|
||||||
{}
|
{}
|
||||||
|
|
||||||
ICUpdatedStub* getStub(ICStubSpace* space) {
|
ICUpdatedStub* getStub(ICStubSpace* space) {
|
||||||
ICSetElem_DenseOrUnboxedArray* stub =
|
ICSetElem_Dense* stub = ICStub::New<ICSetElem_Dense>(space, getStubCode(), shape_, group_);
|
||||||
ICStub::New<ICSetElem_DenseOrUnboxedArray>(space, getStubCode(), shape_, group_);
|
|
||||||
if (!stub || !stub->initUpdatingChain(cx, space))
|
if (!stub || !stub->initUpdatingChain(cx, space))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
return stub;
|
return stub;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool needsUpdateStubs() {
|
|
||||||
return unboxedType_ == JSVAL_TYPE_MAGIC || unboxedType_ == JSVAL_TYPE_OBJECT;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
template <size_t ProtoChainDepth> class ICSetElem_DenseOrUnboxedArrayAddImpl;
|
template <size_t ProtoChainDepth> class ICSetElem_DenseAddImpl;
|
||||||
|
|
||||||
class ICSetElem_DenseOrUnboxedArrayAdd : public ICUpdatedStub
|
class ICSetElem_DenseAdd : public ICUpdatedStub
|
||||||
{
|
{
|
||||||
friend class ICStubSpace;
|
friend class ICStubSpace;
|
||||||
|
|
||||||
|
@ -3305,11 +3245,11 @@ class ICSetElem_DenseOrUnboxedArrayAdd : public ICUpdatedStub
|
||||||
protected:
|
protected:
|
||||||
HeapPtrObjectGroup group_;
|
HeapPtrObjectGroup group_;
|
||||||
|
|
||||||
ICSetElem_DenseOrUnboxedArrayAdd(JitCode* stubCode, ObjectGroup* group, size_t protoChainDepth);
|
ICSetElem_DenseAdd(JitCode* stubCode, ObjectGroup* group, size_t protoChainDepth);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static size_t offsetOfGroup() {
|
static size_t offsetOfGroup() {
|
||||||
return offsetof(ICSetElem_DenseOrUnboxedArrayAdd, group_);
|
return offsetof(ICSetElem_DenseAdd, group_);
|
||||||
}
|
}
|
||||||
|
|
||||||
HeapPtrObjectGroup& group() {
|
HeapPtrObjectGroup& group() {
|
||||||
|
@ -3321,29 +3261,28 @@ class ICSetElem_DenseOrUnboxedArrayAdd : public ICUpdatedStub
|
||||||
}
|
}
|
||||||
|
|
||||||
template <size_t ProtoChainDepth>
|
template <size_t ProtoChainDepth>
|
||||||
ICSetElem_DenseOrUnboxedArrayAddImpl<ProtoChainDepth>* toImplUnchecked() {
|
ICSetElem_DenseAddImpl<ProtoChainDepth>* toImplUnchecked() {
|
||||||
return static_cast<ICSetElem_DenseOrUnboxedArrayAddImpl<ProtoChainDepth>*>(this);
|
return static_cast<ICSetElem_DenseAddImpl<ProtoChainDepth>*>(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <size_t ProtoChainDepth>
|
template <size_t ProtoChainDepth>
|
||||||
ICSetElem_DenseOrUnboxedArrayAddImpl<ProtoChainDepth>* toImpl() {
|
ICSetElem_DenseAddImpl<ProtoChainDepth>* toImpl() {
|
||||||
MOZ_ASSERT(ProtoChainDepth == protoChainDepth());
|
MOZ_ASSERT(ProtoChainDepth == protoChainDepth());
|
||||||
return toImplUnchecked<ProtoChainDepth>();
|
return toImplUnchecked<ProtoChainDepth>();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <size_t ProtoChainDepth>
|
template <size_t ProtoChainDepth>
|
||||||
class ICSetElem_DenseOrUnboxedArrayAddImpl : public ICSetElem_DenseOrUnboxedArrayAdd
|
class ICSetElem_DenseAddImpl : public ICSetElem_DenseAdd
|
||||||
{
|
{
|
||||||
friend class ICStubSpace;
|
friend class ICStubSpace;
|
||||||
|
|
||||||
// Note: for unboxed arrays, the first shape is null.
|
|
||||||
static const size_t NumShapes = ProtoChainDepth + 1;
|
static const size_t NumShapes = ProtoChainDepth + 1;
|
||||||
mozilla::Array<HeapPtrShape, NumShapes> shapes_;
|
mozilla::Array<HeapPtrShape, NumShapes> shapes_;
|
||||||
|
|
||||||
ICSetElem_DenseOrUnboxedArrayAddImpl(JitCode* stubCode, ObjectGroup* group,
|
ICSetElem_DenseAddImpl(JitCode* stubCode, ObjectGroup* group,
|
||||||
const AutoShapeVector* shapes)
|
const AutoShapeVector* shapes)
|
||||||
: ICSetElem_DenseOrUnboxedArrayAdd(stubCode, group, ProtoChainDepth)
|
: ICSetElem_DenseAdd(stubCode, group, ProtoChainDepth)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(shapes->length() == NumShapes);
|
MOZ_ASSERT(shapes->length() == NumShapes);
|
||||||
for (size_t i = 0; i < NumShapes; i++)
|
for (size_t i = 0; i < NumShapes; i++)
|
||||||
|
@ -3352,52 +3291,40 @@ class ICSetElem_DenseOrUnboxedArrayAddImpl : public ICSetElem_DenseOrUnboxedArra
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void traceShapes(JSTracer* trc) {
|
void traceShapes(JSTracer* trc) {
|
||||||
for (size_t i = 0; i < NumShapes; i++) {
|
for (size_t i = 0; i < NumShapes; i++)
|
||||||
if (shapes_[i])
|
TraceEdge(trc, &shapes_[i], "baseline-setelem-denseadd-stub-shape");
|
||||||
TraceEdge(trc, &shapes_[i], "baseline-setelem-denseadd-stub-shape");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Shape* shape(size_t i) const {
|
Shape* shape(size_t i) const {
|
||||||
MOZ_ASSERT(i < NumShapes);
|
MOZ_ASSERT(i < NumShapes);
|
||||||
return shapes_[i];
|
return shapes_[i];
|
||||||
}
|
}
|
||||||
static size_t offsetOfShape(size_t idx) {
|
static size_t offsetOfShape(size_t idx) {
|
||||||
return offsetof(ICSetElem_DenseOrUnboxedArrayAddImpl, shapes_) + idx * sizeof(HeapPtrShape);
|
return offsetof(ICSetElem_DenseAddImpl, shapes_) + idx * sizeof(HeapPtrShape);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class ICSetElemDenseOrUnboxedArrayAddCompiler : public ICStubCompiler {
|
class ICSetElemDenseAddCompiler : public ICStubCompiler {
|
||||||
RootedObject obj_;
|
RootedObject obj_;
|
||||||
size_t protoChainDepth_;
|
size_t protoChainDepth_;
|
||||||
JSValueType unboxedType_;
|
|
||||||
|
|
||||||
bool generateStubCode(MacroAssembler& masm);
|
bool generateStubCode(MacroAssembler& masm);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual int32_t getKey() const {
|
virtual int32_t getKey() const {
|
||||||
return static_cast<int32_t>(kind) |
|
return static_cast<int32_t>(kind) | (static_cast<int32_t>(protoChainDepth_) << 16);
|
||||||
(static_cast<int32_t>(protoChainDepth_) << 16) |
|
|
||||||
(static_cast<int32_t>(unboxedType_) << 19);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ICSetElemDenseOrUnboxedArrayAddCompiler(JSContext* cx, HandleObject obj, size_t protoChainDepth)
|
ICSetElemDenseAddCompiler(JSContext* cx, HandleObject obj, size_t protoChainDepth)
|
||||||
: ICStubCompiler(cx, ICStub::SetElem_DenseOrUnboxedArrayAdd),
|
: ICStubCompiler(cx, ICStub::SetElem_DenseAdd),
|
||||||
obj_(cx, obj),
|
obj_(cx, obj),
|
||||||
protoChainDepth_(protoChainDepth),
|
protoChainDepth_(protoChainDepth)
|
||||||
unboxedType_(obj->is<UnboxedArrayObject>()
|
|
||||||
? obj->as<UnboxedArrayObject>().elementType()
|
|
||||||
: JSVAL_TYPE_MAGIC)
|
|
||||||
{}
|
{}
|
||||||
|
|
||||||
template <size_t ProtoChainDepth>
|
template <size_t ProtoChainDepth>
|
||||||
ICUpdatedStub* getStubSpecific(ICStubSpace* space, const AutoShapeVector* shapes);
|
ICUpdatedStub* getStubSpecific(ICStubSpace* space, const AutoShapeVector* shapes);
|
||||||
|
|
||||||
ICUpdatedStub* getStub(ICStubSpace* space);
|
ICUpdatedStub* getStub(ICStubSpace* space);
|
||||||
|
|
||||||
bool needsUpdateStubs() {
|
|
||||||
return unboxedType_ == JSVAL_TYPE_MAGIC || unboxedType_ == JSVAL_TYPE_OBJECT;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Accesses scalar elements of a typed array or typed object.
|
// Accesses scalar elements of a typed array or typed object.
|
||||||
|
@ -4049,30 +3976,6 @@ class ICGetProp_ArrayLength : public ICStub
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
// Stub for accessing an unboxed array's length.
|
|
||||||
class ICGetProp_UnboxedArrayLength : public ICStub
|
|
||||||
{
|
|
||||||
friend class ICStubSpace;
|
|
||||||
|
|
||||||
explicit ICGetProp_UnboxedArrayLength(JitCode* stubCode)
|
|
||||||
: ICStub(GetProp_UnboxedArrayLength, stubCode)
|
|
||||||
{}
|
|
||||||
|
|
||||||
public:
|
|
||||||
class Compiler : public ICStubCompiler {
|
|
||||||
bool generateStubCode(MacroAssembler& masm);
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit Compiler(JSContext* cx)
|
|
||||||
: ICStubCompiler(cx, ICStub::GetProp_UnboxedArrayLength)
|
|
||||||
{}
|
|
||||||
|
|
||||||
ICStub* getStub(ICStubSpace* space) {
|
|
||||||
return ICStub::New<ICGetProp_UnboxedArrayLength>(space, getStubCode());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
// Stub for accessing a property on a primitive's prototype.
|
// Stub for accessing a property on a primitive's prototype.
|
||||||
class ICGetProp_Primitive : public ICMonitoredStub
|
class ICGetProp_Primitive : public ICMonitoredStub
|
||||||
{
|
{
|
||||||
|
|
|
@ -21,9 +21,9 @@ SetElemICInspector::sawOOBDenseWrite() const
|
||||||
if (!icEntry_)
|
if (!icEntry_)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Check for an element adding stub.
|
// Check for a SetElem_DenseAdd stub.
|
||||||
for (ICStub* stub = icEntry_->firstStub(); stub; stub = stub->next()) {
|
for (ICStub* stub = icEntry_->firstStub(); stub; stub = stub->next()) {
|
||||||
if (stub->isSetElem_DenseOrUnboxedArrayAdd())
|
if (stub->isSetElem_DenseAdd())
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,7 +59,7 @@ SetElemICInspector::sawDenseWrite() const
|
||||||
|
|
||||||
// Check for a SetElem_DenseAdd or SetElem_Dense stub.
|
// Check for a SetElem_DenseAdd or SetElem_Dense stub.
|
||||||
for (ICStub* stub = icEntry_->firstStub(); stub; stub = stub->next()) {
|
for (ICStub* stub = icEntry_->firstStub(); stub; stub = stub->next()) {
|
||||||
if (stub->isSetElem_DenseOrUnboxedArrayAdd() || stub->isSetElem_DenseOrUnboxedArray())
|
if (stub->isSetElem_DenseAdd() || stub->isSetElem_Dense())
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -2339,18 +2339,6 @@ CodeGenerator::visitGetPropertyPolymorphicT(LGetPropertyPolymorphicT* ins)
|
||||||
emitGetPropertyPolymorphic(ins, obj, temp, output);
|
emitGetPropertyPolymorphic(ins, obj, temp, output);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
static void
|
|
||||||
EmitUnboxedPreBarrier(MacroAssembler &masm, T address, JSValueType type)
|
|
||||||
{
|
|
||||||
if (type == JSVAL_TYPE_OBJECT)
|
|
||||||
masm.patchableCallPreBarrier(address, MIRType_Object);
|
|
||||||
else if (type == JSVAL_TYPE_STRING)
|
|
||||||
masm.patchableCallPreBarrier(address, MIRType_String);
|
|
||||||
else
|
|
||||||
MOZ_ASSERT(!UnboxedTypeNeedsPreBarrier(type));
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
CodeGenerator::emitSetPropertyPolymorphic(LInstruction* ins, Register obj, Register scratch,
|
CodeGenerator::emitSetPropertyPolymorphic(LInstruction* ins, Register obj, Register scratch,
|
||||||
const ConstantOrRegister& value)
|
const ConstantOrRegister& value)
|
||||||
|
@ -2389,7 +2377,13 @@ CodeGenerator::emitSetPropertyPolymorphic(LInstruction* ins, Register obj, Regis
|
||||||
receiver.group->unboxedLayout().lookup(mir->name());
|
receiver.group->unboxedLayout().lookup(mir->name());
|
||||||
Address propertyAddr(obj, UnboxedPlainObject::offsetOfData() + property->offset);
|
Address propertyAddr(obj, UnboxedPlainObject::offsetOfData() + property->offset);
|
||||||
|
|
||||||
EmitUnboxedPreBarrier(masm, propertyAddr, property->type);
|
if (property->type == JSVAL_TYPE_OBJECT)
|
||||||
|
masm.patchableCallPreBarrier(propertyAddr, MIRType_Object);
|
||||||
|
else if (property->type == JSVAL_TYPE_STRING)
|
||||||
|
masm.patchableCallPreBarrier(propertyAddr, MIRType_String);
|
||||||
|
else
|
||||||
|
MOZ_ASSERT(!UnboxedTypeNeedsPreBarrier(property->type));
|
||||||
|
|
||||||
masm.storeUnboxedProperty(propertyAddr, property->type, value, nullptr);
|
masm.storeUnboxedProperty(propertyAddr, property->type, value, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2431,9 +2425,7 @@ CodeGenerator::visitSetPropertyPolymorphicT(LSetPropertyPolymorphicT* ins)
|
||||||
void
|
void
|
||||||
CodeGenerator::visitElements(LElements* lir)
|
CodeGenerator::visitElements(LElements* lir)
|
||||||
{
|
{
|
||||||
Address elements(ToRegister(lir->object()),
|
Address elements(ToRegister(lir->object()), NativeObject::offsetOfElements());
|
||||||
lir->mir()->unboxed() ? UnboxedArrayObject::offsetOfElements()
|
|
||||||
: NativeObject::offsetOfElements());
|
|
||||||
masm.loadPtr(elements, ToRegister(lir->output()));
|
masm.loadPtr(elements, ToRegister(lir->output()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4064,11 +4056,6 @@ class OutOfLineNewArray : public OutOfLineCodeBase<CodeGenerator>
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef JSObject* (*NewArrayOperationFn)(JSContext*, HandleScript, jsbytecode*, uint32_t,
|
|
||||||
NewObjectKind);
|
|
||||||
static const VMFunction NewArrayOperationInfo =
|
|
||||||
FunctionInfo<NewArrayOperationFn>(NewArrayOperation);
|
|
||||||
|
|
||||||
typedef ArrayObject* (*NewDenseArrayFn)(ExclusiveContext*, uint32_t, HandleObjectGroup,
|
typedef ArrayObject* (*NewDenseArrayFn)(ExclusiveContext*, uint32_t, HandleObjectGroup,
|
||||||
AllocatingBehaviour, bool);
|
AllocatingBehaviour, bool);
|
||||||
static const VMFunction NewDenseArrayInfo = FunctionInfo<NewDenseArrayFn>(NewDenseArray);
|
static const VMFunction NewDenseArrayInfo = FunctionInfo<NewDenseArrayFn>(NewDenseArray);
|
||||||
|
@ -4082,22 +4069,15 @@ CodeGenerator::visitNewArrayCallVM(LNewArray* lir)
|
||||||
saveLive(lir);
|
saveLive(lir);
|
||||||
|
|
||||||
JSObject* templateObject = lir->mir()->templateObject();
|
JSObject* templateObject = lir->mir()->templateObject();
|
||||||
|
ObjectGroup* group =
|
||||||
|
templateObject->isSingleton() ? nullptr : templateObject->group();
|
||||||
|
|
||||||
if (templateObject && !templateObject->is<UnboxedArrayObject>()) {
|
pushArg(Imm32(lir->mir()->convertDoubleElements()));
|
||||||
pushArg(Imm32(lir->mir()->convertDoubleElements()));
|
pushArg(Imm32(lir->mir()->allocatingBehaviour()));
|
||||||
pushArg(Imm32(lir->mir()->allocatingBehaviour()));
|
pushArg(ImmGCPtr(group));
|
||||||
pushArg(ImmGCPtr(templateObject->group()));
|
pushArg(Imm32(lir->mir()->count()));
|
||||||
pushArg(Imm32(lir->mir()->count()));
|
|
||||||
|
|
||||||
callVM(NewDenseArrayInfo, lir);
|
callVM(NewDenseArrayInfo, lir);
|
||||||
} else {
|
|
||||||
pushArg(Imm32(GenericObject));
|
|
||||||
pushArg(Imm32(lir->mir()->count()));
|
|
||||||
pushArg(ImmPtr(lir->mir()->pc()));
|
|
||||||
pushArg(ImmGCPtr(lir->mir()->block()->info().script()));
|
|
||||||
|
|
||||||
callVM(NewArrayOperationInfo, lir);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ReturnReg != objReg)
|
if (ReturnReg != objReg)
|
||||||
masm.movePtr(ReturnReg, objReg);
|
masm.movePtr(ReturnReg, objReg);
|
||||||
|
@ -4167,7 +4147,7 @@ CodeGenerator::visitNewArray(LNewArray* lir)
|
||||||
{
|
{
|
||||||
Register objReg = ToRegister(lir->output());
|
Register objReg = ToRegister(lir->output());
|
||||||
Register tempReg = ToRegister(lir->temp());
|
Register tempReg = ToRegister(lir->temp());
|
||||||
JSObject* templateObject = lir->mir()->templateObject();
|
ArrayObject* templateObject = lir->mir()->templateObject();
|
||||||
DebugOnly<uint32_t> count = lir->mir()->count();
|
DebugOnly<uint32_t> count = lir->mir()->count();
|
||||||
|
|
||||||
MOZ_ASSERT(count < NativeObject::NELEMENTS_LIMIT);
|
MOZ_ASSERT(count < NativeObject::NELEMENTS_LIMIT);
|
||||||
|
@ -6296,30 +6276,6 @@ CodeGenerator::visitSetInitializedLength(LSetInitializedLength* lir)
|
||||||
masm.bumpKey(&index, -1);
|
masm.bumpKey(&index, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
CodeGenerator::visitUnboxedArrayLength(LUnboxedArrayLength* lir)
|
|
||||||
{
|
|
||||||
Register obj = ToRegister(lir->object());
|
|
||||||
Register result = ToRegister(lir->output());
|
|
||||||
masm.load32(Address(obj, UnboxedArrayObject::offsetOfLength()), result);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CodeGenerator::visitUnboxedArrayInitializedLength(LUnboxedArrayInitializedLength* lir)
|
|
||||||
{
|
|
||||||
Register obj = ToRegister(lir->object());
|
|
||||||
Register result = ToRegister(lir->output());
|
|
||||||
masm.load32(Address(obj, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength()), result);
|
|
||||||
masm.and32(Imm32(UnboxedArrayObject::InitializedLengthMask), result);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CodeGenerator::visitIncrementUnboxedArrayInitializedLength(LIncrementUnboxedArrayInitializedLength* lir)
|
|
||||||
{
|
|
||||||
Register obj = ToRegister(lir->object());
|
|
||||||
masm.add32(Imm32(1), Address(obj, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength()));
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
CodeGenerator::visitNotO(LNotO* lir)
|
CodeGenerator::visitNotO(LNotO* lir)
|
||||||
{
|
{
|
||||||
|
@ -6524,21 +6480,18 @@ CodeGenerator::emitStoreHoleCheck(Register elements, const LAllocation* index,
|
||||||
bailoutFrom(&bail, snapshot);
|
bailoutFrom(&bail, snapshot);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ConstantOrRegister
|
|
||||||
ToConstantOrRegister(const LAllocation* value, MIRType valueType)
|
|
||||||
{
|
|
||||||
if (value->isConstant())
|
|
||||||
return ConstantOrRegister(*value->toConstant());
|
|
||||||
return TypedOrValueRegister(valueType, ToAnyRegister(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
CodeGenerator::emitStoreElementTyped(const LAllocation* value,
|
CodeGenerator::emitStoreElementTyped(const LAllocation* value,
|
||||||
MIRType valueType, MIRType elementType,
|
MIRType valueType, MIRType elementType,
|
||||||
Register elements, const LAllocation* index,
|
Register elements, const LAllocation* index,
|
||||||
int32_t offsetAdjustment)
|
int32_t offsetAdjustment)
|
||||||
{
|
{
|
||||||
ConstantOrRegister v = ToConstantOrRegister(value, valueType);
|
ConstantOrRegister v;
|
||||||
|
if (value->isConstant())
|
||||||
|
v = ConstantOrRegister(*value->toConstant());
|
||||||
|
else
|
||||||
|
v = TypedOrValueRegister(valueType, ToAnyRegister(value));
|
||||||
|
|
||||||
if (index->isConstant()) {
|
if (index->isConstant()) {
|
||||||
Address dest(elements, ToInt32(index) * sizeof(js::Value) + offsetAdjustment);
|
Address dest(elements, ToInt32(index) * sizeof(js::Value) + offsetAdjustment);
|
||||||
masm.storeUnboxedValue(v, valueType, dest, elementType);
|
masm.storeUnboxedValue(v, valueType, dest, elementType);
|
||||||
|
@ -6595,45 +6548,19 @@ CodeGenerator::visitStoreElementHoleT(LStoreElementHoleT* lir)
|
||||||
OutOfLineStoreElementHole* ool = new(alloc()) OutOfLineStoreElementHole(lir);
|
OutOfLineStoreElementHole* ool = new(alloc()) OutOfLineStoreElementHole(lir);
|
||||||
addOutOfLineCode(ool, lir->mir());
|
addOutOfLineCode(ool, lir->mir());
|
||||||
|
|
||||||
Register obj = ToRegister(lir->object());
|
|
||||||
Register elements = ToRegister(lir->elements());
|
Register elements = ToRegister(lir->elements());
|
||||||
const LAllocation* index = lir->index();
|
const LAllocation* index = lir->index();
|
||||||
|
|
||||||
JSValueType unboxedType = lir->mir()->unboxedType();
|
// OOL path if index >= initializedLength.
|
||||||
if (unboxedType == JSVAL_TYPE_MAGIC) {
|
Address initLength(elements, ObjectElements::offsetOfInitializedLength());
|
||||||
Address initLength(elements, ObjectElements::offsetOfInitializedLength());
|
masm.branchKey(Assembler::BelowOrEqual, initLength, ToInt32Key(index), ool->entry());
|
||||||
masm.branchKey(Assembler::BelowOrEqual, initLength, ToInt32Key(index), ool->entry());
|
|
||||||
|
|
||||||
if (lir->mir()->needsBarrier())
|
if (lir->mir()->needsBarrier())
|
||||||
emitPreBarrier(elements, index);
|
emitPreBarrier(elements, index);
|
||||||
|
|
||||||
masm.bind(ool->rejoinStore());
|
masm.bind(ool->rejoinStore());
|
||||||
emitStoreElementTyped(lir->value(), lir->mir()->value()->type(), lir->mir()->elementType(),
|
emitStoreElementTyped(lir->value(), lir->mir()->value()->type(), lir->mir()->elementType(),
|
||||||
elements, index, 0);
|
elements, index, 0);
|
||||||
} else {
|
|
||||||
Register temp = ToRegister(lir->getTemp(0));
|
|
||||||
Address initLength(obj, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength());
|
|
||||||
masm.load32(initLength, temp);
|
|
||||||
masm.and32(Imm32(UnboxedArrayObject::InitializedLengthMask), temp);
|
|
||||||
masm.branchKey(Assembler::BelowOrEqual, temp, ToInt32Key(index), ool->entry());
|
|
||||||
|
|
||||||
ConstantOrRegister v = ToConstantOrRegister(lir->value(), lir->mir()->value()->type());
|
|
||||||
|
|
||||||
if (index->isConstant()) {
|
|
||||||
Address address(elements, ToInt32(index) * UnboxedTypeSize(unboxedType));
|
|
||||||
EmitUnboxedPreBarrier(masm, address, unboxedType);
|
|
||||||
|
|
||||||
masm.bind(ool->rejoinStore());
|
|
||||||
masm.storeUnboxedProperty(address, unboxedType, v, nullptr);
|
|
||||||
} else {
|
|
||||||
BaseIndex address(elements, ToRegister(index),
|
|
||||||
ScaleFromElemWidth(UnboxedTypeSize(unboxedType)));
|
|
||||||
EmitUnboxedPreBarrier(masm, address, unboxedType);
|
|
||||||
|
|
||||||
masm.bind(ool->rejoinStore());
|
|
||||||
masm.storeUnboxedProperty(address, unboxedType, v, nullptr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
masm.bind(ool->rejoin());
|
masm.bind(ool->rejoin());
|
||||||
}
|
}
|
||||||
|
@ -6644,54 +6571,29 @@ CodeGenerator::visitStoreElementHoleV(LStoreElementHoleV* lir)
|
||||||
OutOfLineStoreElementHole* ool = new(alloc()) OutOfLineStoreElementHole(lir);
|
OutOfLineStoreElementHole* ool = new(alloc()) OutOfLineStoreElementHole(lir);
|
||||||
addOutOfLineCode(ool, lir->mir());
|
addOutOfLineCode(ool, lir->mir());
|
||||||
|
|
||||||
Register obj = ToRegister(lir->object());
|
|
||||||
Register elements = ToRegister(lir->elements());
|
Register elements = ToRegister(lir->elements());
|
||||||
const LAllocation* index = lir->index();
|
const LAllocation* index = lir->index();
|
||||||
const ValueOperand value = ToValue(lir, LStoreElementHoleV::Value);
|
const ValueOperand value = ToValue(lir, LStoreElementHoleV::Value);
|
||||||
|
|
||||||
JSValueType unboxedType = lir->mir()->unboxedType();
|
// OOL path if index >= initializedLength.
|
||||||
if (unboxedType == JSVAL_TYPE_MAGIC) {
|
Address initLength(elements, ObjectElements::offsetOfInitializedLength());
|
||||||
Address initLength(elements, ObjectElements::offsetOfInitializedLength());
|
masm.branchKey(Assembler::BelowOrEqual, initLength, ToInt32Key(index), ool->entry());
|
||||||
masm.branchKey(Assembler::BelowOrEqual, initLength, ToInt32Key(index), ool->entry());
|
|
||||||
|
|
||||||
if (lir->mir()->needsBarrier())
|
if (lir->mir()->needsBarrier())
|
||||||
emitPreBarrier(elements, index);
|
emitPreBarrier(elements, index);
|
||||||
|
|
||||||
masm.bind(ool->rejoinStore());
|
masm.bind(ool->rejoinStore());
|
||||||
if (index->isConstant())
|
if (lir->index()->isConstant())
|
||||||
masm.storeValue(value, Address(elements, ToInt32(index) * sizeof(js::Value)));
|
masm.storeValue(value, Address(elements, ToInt32(lir->index()) * sizeof(js::Value)));
|
||||||
else
|
else
|
||||||
masm.storeValue(value, BaseIndex(elements, ToRegister(index), TimesEight));
|
masm.storeValue(value, BaseIndex(elements, ToRegister(lir->index()), TimesEight));
|
||||||
} else {
|
|
||||||
Register temp = ToRegister(lir->getTemp(0));
|
|
||||||
Address initLength(obj, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength());
|
|
||||||
masm.load32(initLength, temp);
|
|
||||||
masm.and32(Imm32(UnboxedArrayObject::InitializedLengthMask), temp);
|
|
||||||
masm.branchKey(Assembler::BelowOrEqual, temp, ToInt32Key(index), ool->entry());
|
|
||||||
|
|
||||||
if (index->isConstant()) {
|
|
||||||
Address address(elements, ToInt32(index) * UnboxedTypeSize(unboxedType));
|
|
||||||
EmitUnboxedPreBarrier(masm, address, unboxedType);
|
|
||||||
|
|
||||||
masm.bind(ool->rejoinStore());
|
|
||||||
masm.storeUnboxedProperty(address, unboxedType, ConstantOrRegister(value), nullptr);
|
|
||||||
} else {
|
|
||||||
BaseIndex address(elements, ToRegister(index),
|
|
||||||
ScaleFromElemWidth(UnboxedTypeSize(unboxedType)));
|
|
||||||
EmitUnboxedPreBarrier(masm, address, unboxedType);
|
|
||||||
|
|
||||||
masm.bind(ool->rejoinStore());
|
|
||||||
masm.storeUnboxedProperty(address, unboxedType, ConstantOrRegister(value), nullptr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
masm.bind(ool->rejoin());
|
masm.bind(ool->rejoin());
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef bool (*SetDenseOrUnboxedArrayElementFn)(JSContext*, HandleObject, int32_t,
|
typedef bool (*SetDenseElementFn)(JSContext*, HandleNativeObject, int32_t, HandleValue,
|
||||||
HandleValue, bool strict);
|
bool strict);
|
||||||
static const VMFunction SetDenseOrUnboxedArrayElementInfo =
|
static const VMFunction SetDenseElementInfo = FunctionInfo<SetDenseElementFn>(SetDenseElement);
|
||||||
FunctionInfo<SetDenseOrUnboxedArrayElementFn>(SetDenseOrUnboxedArrayElement);
|
|
||||||
|
|
||||||
void
|
void
|
||||||
CodeGenerator::visitOutOfLineStoreElementHole(OutOfLineStoreElementHole* ool)
|
CodeGenerator::visitOutOfLineStoreElementHole(OutOfLineStoreElementHole* ool)
|
||||||
|
@ -6701,8 +6603,6 @@ CodeGenerator::visitOutOfLineStoreElementHole(OutOfLineStoreElementHole* ool)
|
||||||
const LAllocation* index;
|
const LAllocation* index;
|
||||||
MIRType valueType;
|
MIRType valueType;
|
||||||
ConstantOrRegister value;
|
ConstantOrRegister value;
|
||||||
JSValueType unboxedType;
|
|
||||||
LDefinition *temp = nullptr;
|
|
||||||
|
|
||||||
if (ins->isStoreElementHoleV()) {
|
if (ins->isStoreElementHoleV()) {
|
||||||
LStoreElementHoleV* store = ins->toStoreElementHoleV();
|
LStoreElementHoleV* store = ins->toStoreElementHoleV();
|
||||||
|
@ -6711,8 +6611,6 @@ CodeGenerator::visitOutOfLineStoreElementHole(OutOfLineStoreElementHole* ool)
|
||||||
index = store->index();
|
index = store->index();
|
||||||
valueType = store->mir()->value()->type();
|
valueType = store->mir()->value()->type();
|
||||||
value = TypedOrValueRegister(ToValue(store, LStoreElementHoleV::Value));
|
value = TypedOrValueRegister(ToValue(store, LStoreElementHoleV::Value));
|
||||||
unboxedType = store->mir()->unboxedType();
|
|
||||||
temp = store->getTemp(0);
|
|
||||||
} else {
|
} else {
|
||||||
LStoreElementHoleT* store = ins->toStoreElementHoleT();
|
LStoreElementHoleT* store = ins->toStoreElementHoleT();
|
||||||
object = ToRegister(store->object());
|
object = ToRegister(store->object());
|
||||||
|
@ -6723,8 +6621,6 @@ CodeGenerator::visitOutOfLineStoreElementHole(OutOfLineStoreElementHole* ool)
|
||||||
value = ConstantOrRegister(*store->value()->toConstant());
|
value = ConstantOrRegister(*store->value()->toConstant());
|
||||||
else
|
else
|
||||||
value = TypedOrValueRegister(valueType, ToAnyRegister(store->value()));
|
value = TypedOrValueRegister(valueType, ToAnyRegister(store->value()));
|
||||||
unboxedType = store->mir()->unboxedType();
|
|
||||||
temp = store->getTemp(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If index == initializedLength, try to bump the initialized length inline.
|
// If index == initializedLength, try to bump the initialized length inline.
|
||||||
|
@ -6733,55 +6629,33 @@ CodeGenerator::visitOutOfLineStoreElementHole(OutOfLineStoreElementHole* ool)
|
||||||
Label callStub;
|
Label callStub;
|
||||||
#ifdef JS_CODEGEN_MIPS
|
#ifdef JS_CODEGEN_MIPS
|
||||||
// Had to reimplement for MIPS because there are no flags.
|
// Had to reimplement for MIPS because there are no flags.
|
||||||
if (unboxedType == JSVAL_TYPE_MAGIC) {
|
Address initLength(elements, ObjectElements::offsetOfInitializedLength());
|
||||||
Address initLength(elements, ObjectElements::offsetOfInitializedLength());
|
masm.branchKey(Assembler::NotEqual, initLength, ToInt32Key(index), &callStub);
|
||||||
masm.branchKey(Assembler::NotEqual, initLength, ToInt32Key(index), &callStub);
|
|
||||||
} else {
|
|
||||||
Address initLength(obj, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength());
|
|
||||||
masm.load32(initLength, ToRegister(temp));
|
|
||||||
masm.and32(Imm32(UnboxedArrayObject::InitializedLengthMask), ToRegister(temp));
|
|
||||||
masm.branchKey(Assembler::NotEqual, ToRegister(temp), ToInt32Key(index), &callStub);
|
|
||||||
}
|
|
||||||
#else
|
#else
|
||||||
masm.j(Assembler::NotEqual, &callStub);
|
masm.j(Assembler::NotEqual, &callStub);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
Int32Key key = ToInt32Key(index);
|
Int32Key key = ToInt32Key(index);
|
||||||
|
|
||||||
if (unboxedType == JSVAL_TYPE_MAGIC) {
|
// Check array capacity.
|
||||||
// Check array capacity.
|
masm.branchKey(Assembler::BelowOrEqual, Address(elements, ObjectElements::offsetOfCapacity()),
|
||||||
masm.branchKey(Assembler::BelowOrEqual, Address(elements, ObjectElements::offsetOfCapacity()),
|
key, &callStub);
|
||||||
key, &callStub);
|
|
||||||
|
|
||||||
// Update initialized length. The capacity guard above ensures this won't overflow,
|
// Update initialized length. The capacity guard above ensures this won't overflow,
|
||||||
// due to NELEMENTS_LIMIT.
|
// due to NELEMENTS_LIMIT.
|
||||||
masm.bumpKey(&key, 1);
|
masm.bumpKey(&key, 1);
|
||||||
masm.storeKey(key, Address(elements, ObjectElements::offsetOfInitializedLength()));
|
masm.storeKey(key, Address(elements, ObjectElements::offsetOfInitializedLength()));
|
||||||
|
|
||||||
// Update length if length < initializedLength.
|
// Update length if length < initializedLength.
|
||||||
Label dontUpdate;
|
Label dontUpdate;
|
||||||
masm.branchKey(Assembler::AboveOrEqual, Address(elements, ObjectElements::offsetOfLength()),
|
masm.branchKey(Assembler::AboveOrEqual, Address(elements, ObjectElements::offsetOfLength()),
|
||||||
key, &dontUpdate);
|
key, &dontUpdate);
|
||||||
masm.storeKey(key, Address(elements, ObjectElements::offsetOfLength()));
|
masm.storeKey(key, Address(elements, ObjectElements::offsetOfLength()));
|
||||||
masm.bind(&dontUpdate);
|
masm.bind(&dontUpdate);
|
||||||
|
|
||||||
masm.bumpKey(&key, -1);
|
masm.bumpKey(&key, -1);
|
||||||
} else {
|
|
||||||
// Check array capacity.
|
|
||||||
masm.checkUnboxedArrayCapacity(object, key, ToRegister(temp), &callStub);
|
|
||||||
|
|
||||||
// Update initialized length.
|
if (ins->isStoreElementHoleT() && valueType != MIRType_Double) {
|
||||||
masm.add32(Imm32(1), Address(object, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength()));
|
|
||||||
|
|
||||||
// Update length if length < initializedLength.
|
|
||||||
Address lengthAddr(object, UnboxedArrayObject::offsetOfLength());
|
|
||||||
Label dontUpdate;
|
|
||||||
masm.branchKey(Assembler::Above, lengthAddr, key, &dontUpdate);
|
|
||||||
masm.add32(Imm32(1), lengthAddr);
|
|
||||||
masm.bind(&dontUpdate);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ins->isStoreElementHoleT() && unboxedType == JSVAL_TYPE_MAGIC && valueType != MIRType_Double) {
|
|
||||||
// The inline path for StoreElementHoleT does not always store the type tag,
|
// The inline path for StoreElementHoleT does not always store the type tag,
|
||||||
// so we do the store on the OOL path. We use MIRType_None for the element type
|
// so we do the store on the OOL path. We use MIRType_None for the element type
|
||||||
// so that storeElementTyped will always store the type tag.
|
// so that storeElementTyped will always store the type tag.
|
||||||
|
@ -6803,7 +6677,7 @@ CodeGenerator::visitOutOfLineStoreElementHole(OutOfLineStoreElementHole* ool)
|
||||||
else
|
else
|
||||||
pushArg(ToRegister(index));
|
pushArg(ToRegister(index));
|
||||||
pushArg(object);
|
pushArg(object);
|
||||||
callVM(SetDenseOrUnboxedArrayElementInfo, ins);
|
callVM(SetDenseElementInfo, ins);
|
||||||
|
|
||||||
restoreLive(ins);
|
restoreLive(ins);
|
||||||
masm.jump(ool->rejoin());
|
masm.jump(ool->rejoin());
|
||||||
|
@ -8706,27 +8580,13 @@ CodeGenerator::visitLoadElementHole(LLoadElementHole* lir)
|
||||||
// If the index is out of bounds, load |undefined|. Otherwise, load the
|
// If the index is out of bounds, load |undefined|. Otherwise, load the
|
||||||
// value.
|
// value.
|
||||||
Label undefined, done;
|
Label undefined, done;
|
||||||
if (lir->index()->isConstant())
|
if (lir->index()->isConstant()) {
|
||||||
masm.branch32(Assembler::BelowOrEqual, initLength, Imm32(ToInt32(lir->index())), &undefined);
|
masm.branch32(Assembler::BelowOrEqual, initLength, Imm32(ToInt32(lir->index())), &undefined);
|
||||||
else
|
NativeObject::elementsSizeMustNotOverflow();
|
||||||
masm.branch32(Assembler::BelowOrEqual, initLength, ToRegister(lir->index()), &undefined);
|
masm.loadValue(Address(elements, ToInt32(lir->index()) * sizeof(Value)), out);
|
||||||
|
|
||||||
if (mir->unboxedType() != JSVAL_TYPE_MAGIC) {
|
|
||||||
size_t width = UnboxedTypeSize(mir->unboxedType());
|
|
||||||
if (lir->index()->isConstant()) {
|
|
||||||
Address addr(elements, ToInt32(lir->index()) * width);
|
|
||||||
masm.loadUnboxedProperty(addr, mir->unboxedType(), out);
|
|
||||||
} else {
|
|
||||||
BaseIndex addr(elements, ToRegister(lir->index()), ScaleFromElemWidth(width));
|
|
||||||
masm.loadUnboxedProperty(addr, mir->unboxedType(), out);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if (lir->index()->isConstant()) {
|
masm.branch32(Assembler::BelowOrEqual, initLength, ToRegister(lir->index()), &undefined);
|
||||||
NativeObject::elementsSizeMustNotOverflow();
|
masm.loadValue(BaseObjectElementIndex(elements, ToRegister(lir->index())), out);
|
||||||
masm.loadValue(Address(elements, ToInt32(lir->index()) * sizeof(Value)), out);
|
|
||||||
} else {
|
|
||||||
masm.loadValue(BaseObjectElementIndex(elements, ToRegister(lir->index())), out);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If a hole check is needed, and the value wasn't a hole, we're done.
|
// If a hole check is needed, and the value wasn't a hole, we're done.
|
||||||
|
|
|
@ -188,9 +188,6 @@ class CodeGenerator : public CodeGeneratorSpecific
|
||||||
void visitSubstr(LSubstr* lir);
|
void visitSubstr(LSubstr* lir);
|
||||||
void visitInitializedLength(LInitializedLength* lir);
|
void visitInitializedLength(LInitializedLength* lir);
|
||||||
void visitSetInitializedLength(LSetInitializedLength* lir);
|
void visitSetInitializedLength(LSetInitializedLength* lir);
|
||||||
void visitUnboxedArrayLength(LUnboxedArrayLength* lir);
|
|
||||||
void visitUnboxedArrayInitializedLength(LUnboxedArrayInitializedLength* lir);
|
|
||||||
void visitIncrementUnboxedArrayInitializedLength(LIncrementUnboxedArrayInitializedLength* lir);
|
|
||||||
void visitNotO(LNotO* ins);
|
void visitNotO(LNotO* ins);
|
||||||
void visitNotV(LNotV* ins);
|
void visitNotV(LNotV* ins);
|
||||||
void visitBoundsCheck(LBoundsCheck* lir);
|
void visitBoundsCheck(LBoundsCheck* lir);
|
||||||
|
|
|
@ -6477,20 +6477,35 @@ bool
|
||||||
IonBuilder::jsop_newarray(uint32_t count)
|
IonBuilder::jsop_newarray(uint32_t count)
|
||||||
{
|
{
|
||||||
JSObject* templateObject = inspector->getTemplateObject(pc);
|
JSObject* templateObject = inspector->getTemplateObject(pc);
|
||||||
gc::InitialHeap heap;
|
if (!templateObject) {
|
||||||
MConstant* templateConst;
|
if (info().analysisMode() == Analysis_ArgumentsUsage) {
|
||||||
|
MUnknownValue* unknown = MUnknownValue::New(alloc());
|
||||||
if (templateObject) {
|
current->add(unknown);
|
||||||
heap = templateObject->group()->initialHeap(constraints());
|
current->push(unknown);
|
||||||
templateConst = MConstant::NewConstraintlessObject(alloc(), templateObject);
|
return true;
|
||||||
} else {
|
}
|
||||||
heap = gc::DefaultHeap;
|
return abort("No template object for NEWARRAY");
|
||||||
templateConst = MConstant::New(alloc(), NullValue());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MOZ_ASSERT(templateObject->is<ArrayObject>());
|
||||||
|
if (templateObject->group()->unknownProperties()) {
|
||||||
|
if (info().analysisMode() == Analysis_ArgumentsUsage) {
|
||||||
|
MUnknownValue* unknown = MUnknownValue::New(alloc());
|
||||||
|
current->add(unknown);
|
||||||
|
current->push(unknown);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// We will get confused in jsop_initelem_array if we can't find the
|
||||||
|
// object group being initialized.
|
||||||
|
return abort("New array has unknown properties");
|
||||||
|
}
|
||||||
|
|
||||||
|
MConstant* templateConst = MConstant::NewConstraintlessObject(alloc(), templateObject);
|
||||||
current->add(templateConst);
|
current->add(templateConst);
|
||||||
|
|
||||||
MNewArray* ins = MNewArray::New(alloc(), constraints(), count, templateConst,
|
MNewArray* ins = MNewArray::New(alloc(), constraints(), count, templateConst,
|
||||||
heap, NewArray_FullyAllocating, pc);
|
templateObject->group()->initialHeap(constraints()),
|
||||||
|
NewArray_FullyAllocating);
|
||||||
current->add(ins);
|
current->add(ins);
|
||||||
current->push(ins);
|
current->push(ins);
|
||||||
return true;
|
return true;
|
||||||
|
@ -6566,20 +6581,10 @@ IonBuilder::jsop_initelem_array()
|
||||||
// intializer, and that arrays are marked as non-packed when writing holes
|
// intializer, and that arrays are marked as non-packed when writing holes
|
||||||
// to them during initialization.
|
// to them during initialization.
|
||||||
bool needStub = false;
|
bool needStub = false;
|
||||||
JSValueType unboxedType = JSVAL_TYPE_MAGIC;
|
if (obj->isUnknownValue() || shouldAbortOnPreliminaryGroups(obj)) {
|
||||||
if (shouldAbortOnPreliminaryGroups(obj)) {
|
|
||||||
needStub = true;
|
|
||||||
} else if (!obj->resultTypeSet() || obj->resultTypeSet()->getObjectCount() != 1) {
|
|
||||||
needStub = true;
|
needStub = true;
|
||||||
} else {
|
} else {
|
||||||
MOZ_ASSERT(obj->resultTypeSet()->getObjectCount() == 1);
|
|
||||||
TypeSet::ObjectKey* initializer = obj->resultTypeSet()->getObject(0);
|
TypeSet::ObjectKey* initializer = obj->resultTypeSet()->getObject(0);
|
||||||
if (initializer->clasp() == &UnboxedArrayObject::class_) {
|
|
||||||
if (initializer->group()->unboxedLayout().nativeGroup())
|
|
||||||
needStub = true;
|
|
||||||
else
|
|
||||||
unboxedType = initializer->group()->unboxedLayout().elementType();
|
|
||||||
}
|
|
||||||
if (value->type() == MIRType_MagicHole) {
|
if (value->type() == MIRType_MagicHole) {
|
||||||
if (!initializer->hasFlags(constraints(), OBJECT_FLAG_NON_PACKED))
|
if (!initializer->hasFlags(constraints(), OBJECT_FLAG_NON_PACKED))
|
||||||
needStub = true;
|
needStub = true;
|
||||||
|
@ -6592,6 +6597,9 @@ IonBuilder::jsop_initelem_array()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (NeedsPostBarrier(info(), value))
|
||||||
|
current->add(MPostWriteBarrier::New(alloc(), obj, value));
|
||||||
|
|
||||||
if (needStub) {
|
if (needStub) {
|
||||||
MCallInitElementArray* store = MCallInitElementArray::New(alloc(), obj, GET_UINT24(pc), value);
|
MCallInitElementArray* store = MCallInitElementArray::New(alloc(), obj, GET_UINT24(pc), value);
|
||||||
current->add(store);
|
current->add(store);
|
||||||
|
@ -6602,44 +6610,29 @@ IonBuilder::jsop_initelem_array()
|
||||||
current->add(id);
|
current->add(id);
|
||||||
|
|
||||||
// Get the elements vector.
|
// Get the elements vector.
|
||||||
MElements* elements = MElements::New(alloc(), obj, unboxedType != JSVAL_TYPE_MAGIC);
|
MElements* elements = MElements::New(alloc(), obj);
|
||||||
current->add(elements);
|
current->add(elements);
|
||||||
|
|
||||||
if (unboxedType != JSVAL_TYPE_MAGIC) {
|
if (obj->toNewArray()->convertDoubleElements()) {
|
||||||
// Note: storeUnboxedValue takes care of any post barriers on the value.
|
MInstruction* valueDouble = MToDouble::New(alloc(), value);
|
||||||
storeUnboxedValue(obj, elements, 0, id, unboxedType, value);
|
current->add(valueDouble);
|
||||||
|
value = valueDouble;
|
||||||
MInstruction* increment = MIncrementUnboxedArrayInitializedLength::New(alloc(), obj);
|
|
||||||
current->add(increment);
|
|
||||||
|
|
||||||
if (!resumeAfter(increment))
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
if (NeedsPostBarrier(info(), value))
|
|
||||||
current->add(MPostWriteBarrier::New(alloc(), obj, value));
|
|
||||||
|
|
||||||
if (obj->toNewArray()->convertDoubleElements()) {
|
|
||||||
MInstruction* valueDouble = MToDouble::New(alloc(), value);
|
|
||||||
current->add(valueDouble);
|
|
||||||
value = valueDouble;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Store the value.
|
|
||||||
MStoreElement* store = MStoreElement::New(alloc(), elements, id, value,
|
|
||||||
/* needsHoleCheck = */ false);
|
|
||||||
current->add(store);
|
|
||||||
|
|
||||||
// Update the initialized length. (The template object for this array has
|
|
||||||
// the array's ultimate length, so the length field is already correct: no
|
|
||||||
// updating needed.)
|
|
||||||
MSetInitializedLength* initLength = MSetInitializedLength::New(alloc(), elements, id);
|
|
||||||
current->add(initLength);
|
|
||||||
|
|
||||||
if (!resumeAfter(initLength))
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
// Store the value.
|
||||||
|
MStoreElement* store = MStoreElement::New(alloc(), elements, id, value, /* needsHoleCheck = */ false);
|
||||||
|
current->add(store);
|
||||||
|
|
||||||
|
// Update the initialized length. (The template object for this array has
|
||||||
|
// the array's ultimate length, so the length field is already correct: no
|
||||||
|
// updating needed.)
|
||||||
|
MSetInitializedLength* initLength = MSetInitializedLength::New(alloc(), elements, id);
|
||||||
|
current->add(initLength);
|
||||||
|
|
||||||
|
if (!resumeAfter(initLength))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
@ -8122,12 +8115,9 @@ IonBuilder::getElemTryDense(bool* emitted, MDefinition* obj, MDefinition* index)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(*emitted == false);
|
MOZ_ASSERT(*emitted == false);
|
||||||
|
|
||||||
JSValueType unboxedType = UnboxedArrayElementType(constraints(), obj, index);
|
if (!ElementAccessIsDenseNative(constraints(), obj, index)) {
|
||||||
if (unboxedType == JSVAL_TYPE_MAGIC) {
|
trackOptimizationOutcome(TrackedOutcome::AccessNotDense);
|
||||||
if (!ElementAccessIsDenseNative(constraints(), obj, index)) {
|
return true;
|
||||||
trackOptimizationOutcome(TrackedOutcome::AccessNotDense);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Don't generate a fast path if there have been bounds check failures
|
// Don't generate a fast path if there have been bounds check failures
|
||||||
|
@ -8144,7 +8134,8 @@ IonBuilder::getElemTryDense(bool* emitted, MDefinition* obj, MDefinition* index)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!jsop_getelem_dense(obj, index, unboxedType))
|
// Emit dense getelem variant.
|
||||||
|
if (!jsop_getelem_dense(obj, index))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
trackOptimizationSuccess();
|
trackOptimizationSuccess();
|
||||||
|
@ -8456,7 +8447,7 @@ IonBuilder::getElemTryCache(bool* emitted, MDefinition* obj, MDefinition* index)
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
IonBuilder::jsop_getelem_dense(MDefinition* obj, MDefinition* index, JSValueType unboxedType)
|
IonBuilder::jsop_getelem_dense(MDefinition* obj, MDefinition* index)
|
||||||
{
|
{
|
||||||
TemporaryTypeSet* types = bytecodeTypes(pc);
|
TemporaryTypeSet* types = bytecodeTypes(pc);
|
||||||
|
|
||||||
|
@ -8480,7 +8471,7 @@ IonBuilder::jsop_getelem_dense(MDefinition* obj, MDefinition* index, JSValueType
|
||||||
!ElementAccessHasExtraIndexedProperty(constraints(), obj);
|
!ElementAccessHasExtraIndexedProperty(constraints(), obj);
|
||||||
|
|
||||||
MIRType knownType = MIRType_Value;
|
MIRType knownType = MIRType_Value;
|
||||||
if (unboxedType == JSVAL_TYPE_MAGIC && barrier == BarrierKind::NoBarrier)
|
if (barrier == BarrierKind::NoBarrier)
|
||||||
knownType = GetElemKnownType(needsHoleCheck, types);
|
knownType = GetElemKnownType(needsHoleCheck, types);
|
||||||
|
|
||||||
// Ensure index is an integer.
|
// Ensure index is an integer.
|
||||||
|
@ -8489,24 +8480,19 @@ IonBuilder::jsop_getelem_dense(MDefinition* obj, MDefinition* index, JSValueType
|
||||||
index = idInt32;
|
index = idInt32;
|
||||||
|
|
||||||
// Get the elements vector.
|
// Get the elements vector.
|
||||||
MInstruction* elements = MElements::New(alloc(), obj, unboxedType != JSVAL_TYPE_MAGIC);
|
MInstruction* elements = MElements::New(alloc(), obj);
|
||||||
current->add(elements);
|
current->add(elements);
|
||||||
|
|
||||||
// Note: to help GVN, use the original MElements instruction and not
|
// Note: to help GVN, use the original MElements instruction and not
|
||||||
// MConvertElementsToDoubles as operand. This is fine because converting
|
// MConvertElementsToDoubles as operand. This is fine because converting
|
||||||
// elements to double does not change the initialized length.
|
// elements to double does not change the initialized length.
|
||||||
MInstruction* initLength;
|
MInitializedLength* initLength = MInitializedLength::New(alloc(), elements);
|
||||||
if (unboxedType != JSVAL_TYPE_MAGIC)
|
|
||||||
initLength = MUnboxedArrayInitializedLength::New(alloc(), obj);
|
|
||||||
else
|
|
||||||
initLength = MInitializedLength::New(alloc(), elements);
|
|
||||||
current->add(initLength);
|
current->add(initLength);
|
||||||
|
|
||||||
// If we can load the element as a definite double, make sure to check that
|
// If we can load the element as a definite double, make sure to check that
|
||||||
// the array has been converted to homogenous doubles first.
|
// the array has been converted to homogenous doubles first.
|
||||||
TemporaryTypeSet* objTypes = obj->resultTypeSet();
|
TemporaryTypeSet* objTypes = obj->resultTypeSet();
|
||||||
bool loadDouble =
|
bool loadDouble =
|
||||||
unboxedType == JSVAL_TYPE_MAGIC &&
|
|
||||||
barrier == BarrierKind::NoBarrier &&
|
barrier == BarrierKind::NoBarrier &&
|
||||||
loopDepth_ &&
|
loopDepth_ &&
|
||||||
!readOutOfBounds &&
|
!readOutOfBounds &&
|
||||||
|
@ -8526,18 +8512,13 @@ IonBuilder::jsop_getelem_dense(MDefinition* obj, MDefinition* index, JSValueType
|
||||||
// hoisting.
|
// hoisting.
|
||||||
index = addBoundsCheck(index, initLength);
|
index = addBoundsCheck(index, initLength);
|
||||||
|
|
||||||
if (unboxedType != JSVAL_TYPE_MAGIC) {
|
load = MLoadElement::New(alloc(), elements, index, needsHoleCheck, loadDouble);
|
||||||
load = loadUnboxedValue(elements, 0, index, unboxedType, barrier, types);
|
current->add(load);
|
||||||
} else {
|
|
||||||
load = MLoadElement::New(alloc(), elements, index, needsHoleCheck, loadDouble);
|
|
||||||
current->add(load);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// This load may return undefined, so assume that we *can* read holes,
|
// This load may return undefined, so assume that we *can* read holes,
|
||||||
// or that we can read out-of-bounds accesses. In this case, the bounds
|
// or that we can read out-of-bounds accesses. In this case, the bounds
|
||||||
// check is part of the opcode.
|
// check is part of the opcode.
|
||||||
load = MLoadElementHole::New(alloc(), elements, index, initLength,
|
load = MLoadElementHole::New(alloc(), elements, index, initLength, needsHoleCheck);
|
||||||
unboxedType, needsHoleCheck);
|
|
||||||
current->add(load);
|
current->add(load);
|
||||||
|
|
||||||
// If maybeUndefined was true, the typeset must have undefined, and
|
// If maybeUndefined was true, the typeset must have undefined, and
|
||||||
|
@ -8995,12 +8976,9 @@ IonBuilder::setElemTryDense(bool* emitted, MDefinition* object,
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(*emitted == false);
|
MOZ_ASSERT(*emitted == false);
|
||||||
|
|
||||||
JSValueType unboxedType = UnboxedArrayElementType(constraints(), object, index);
|
if (!ElementAccessIsDenseNative(constraints(), object, index)) {
|
||||||
if (unboxedType == JSVAL_TYPE_MAGIC) {
|
trackOptimizationOutcome(TrackedOutcome::AccessNotDense);
|
||||||
if (!ElementAccessIsDenseNative(constraints(), object, index)) {
|
return true;
|
||||||
trackOptimizationOutcome(TrackedOutcome::AccessNotDense);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (PropertyWriteNeedsTypeBarrier(alloc(), constraints(), current,
|
if (PropertyWriteNeedsTypeBarrier(alloc(), constraints(), current,
|
||||||
|
@ -9034,7 +9012,7 @@ IonBuilder::setElemTryDense(bool* emitted, MDefinition* object,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Emit dense setelem variant.
|
// Emit dense setelem variant.
|
||||||
if (!jsop_setelem_dense(conversion, SetElem_Normal, object, index, value, unboxedType))
|
if (!jsop_setelem_dense(conversion, SetElem_Normal, object, index, value))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
trackOptimizationSuccess();
|
trackOptimizationSuccess();
|
||||||
|
@ -9119,12 +9097,9 @@ IonBuilder::setElemTryCache(bool* emitted, MDefinition* object,
|
||||||
bool
|
bool
|
||||||
IonBuilder::jsop_setelem_dense(TemporaryTypeSet::DoubleConversion conversion,
|
IonBuilder::jsop_setelem_dense(TemporaryTypeSet::DoubleConversion conversion,
|
||||||
SetElemSafety safety,
|
SetElemSafety safety,
|
||||||
MDefinition* obj, MDefinition* id, MDefinition* value,
|
MDefinition* obj, MDefinition* id, MDefinition* value)
|
||||||
JSValueType unboxedType)
|
|
||||||
{
|
{
|
||||||
MIRType elementType = MIRType_None;
|
MIRType elementType = DenseNativeElementType(constraints(), obj);
|
||||||
if (unboxedType == JSVAL_TYPE_MAGIC)
|
|
||||||
elementType = DenseNativeElementType(constraints(), obj);
|
|
||||||
bool packed = ElementAccessIsPacked(constraints(), obj);
|
bool packed = ElementAccessIsPacked(constraints(), obj);
|
||||||
|
|
||||||
// Writes which are on holes in the object do not have to bail out if they
|
// Writes which are on holes in the object do not have to bail out if they
|
||||||
|
@ -9143,7 +9118,7 @@ IonBuilder::jsop_setelem_dense(TemporaryTypeSet::DoubleConversion conversion,
|
||||||
obj = addMaybeCopyElementsForWrite(obj);
|
obj = addMaybeCopyElementsForWrite(obj);
|
||||||
|
|
||||||
// Get the elements vector.
|
// Get the elements vector.
|
||||||
MElements* elements = MElements::New(alloc(), obj, unboxedType != JSVAL_TYPE_MAGIC);
|
MElements* elements = MElements::New(alloc(), obj);
|
||||||
current->add(elements);
|
current->add(elements);
|
||||||
|
|
||||||
// Ensure the value is a double, if double conversion might be needed.
|
// Ensure the value is a double, if double conversion might be needed.
|
||||||
|
@ -9181,23 +9156,20 @@ IonBuilder::jsop_setelem_dense(TemporaryTypeSet::DoubleConversion conversion,
|
||||||
// Use MStoreElementHole if this SETELEM has written to out-of-bounds
|
// Use MStoreElementHole if this SETELEM has written to out-of-bounds
|
||||||
// indexes in the past. Otherwise, use MStoreElement so that we can hoist
|
// indexes in the past. Otherwise, use MStoreElement so that we can hoist
|
||||||
// the initialized length and bounds check.
|
// the initialized length and bounds check.
|
||||||
MInstruction* store;
|
MStoreElementCommon* store;
|
||||||
MStoreElementCommon *common = nullptr;
|
|
||||||
if (writeHole && writeOutOfBounds) {
|
if (writeHole && writeOutOfBounds) {
|
||||||
MOZ_ASSERT(safety == SetElem_Normal);
|
MOZ_ASSERT(safety == SetElem_Normal);
|
||||||
|
|
||||||
MStoreElementHole* ins = MStoreElementHole::New(alloc(), obj, elements, id, newValue, unboxedType);
|
MStoreElementHole* ins = MStoreElementHole::New(alloc(), obj, elements, id, newValue);
|
||||||
store = ins;
|
store = ins;
|
||||||
common = ins;
|
|
||||||
|
|
||||||
current->add(ins);
|
current->add(ins);
|
||||||
current->push(value);
|
current->push(value);
|
||||||
|
|
||||||
|
if (!resumeAfter(ins))
|
||||||
|
return false;
|
||||||
} else {
|
} else {
|
||||||
MInstruction* initLength;
|
MInitializedLength* initLength = MInitializedLength::New(alloc(), elements);
|
||||||
if (unboxedType != JSVAL_TYPE_MAGIC)
|
|
||||||
initLength = MUnboxedArrayInitializedLength::New(alloc(), obj);
|
|
||||||
else
|
|
||||||
initLength = MInitializedLength::New(alloc(), elements);
|
|
||||||
current->add(initLength);
|
current->add(initLength);
|
||||||
|
|
||||||
bool needsHoleCheck;
|
bool needsHoleCheck;
|
||||||
|
@ -9208,31 +9180,24 @@ IonBuilder::jsop_setelem_dense(TemporaryTypeSet::DoubleConversion conversion,
|
||||||
needsHoleCheck = false;
|
needsHoleCheck = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (unboxedType != JSVAL_TYPE_MAGIC) {
|
MStoreElement* ins = MStoreElement::New(alloc(), elements, id, newValue, needsHoleCheck);
|
||||||
store = storeUnboxedValue(obj, elements, 0, id, unboxedType, newValue);
|
store = ins;
|
||||||
} else {
|
|
||||||
MStoreElement* ins = MStoreElement::New(alloc(), elements, id, newValue, needsHoleCheck);
|
|
||||||
store = ins;
|
|
||||||
common = ins;
|
|
||||||
|
|
||||||
current->add(store);
|
current->add(ins);
|
||||||
}
|
|
||||||
|
|
||||||
if (safety == SetElem_Normal)
|
if (safety == SetElem_Normal)
|
||||||
current->push(value);
|
current->push(value);
|
||||||
|
|
||||||
|
if (!resumeAfter(ins))
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!resumeAfter(store))
|
// Determine whether a write barrier is required.
|
||||||
return false;
|
if (obj->resultTypeSet()->propertyNeedsBarrier(constraints(), JSID_VOID))
|
||||||
|
store->setNeedsBarrier();
|
||||||
|
|
||||||
if (common) {
|
if (elementType != MIRType_None && packed)
|
||||||
// Determine whether a write barrier is required.
|
store->setElementType(elementType);
|
||||||
if (obj->resultTypeSet()->propertyNeedsBarrier(constraints(), JSID_VOID))
|
|
||||||
common->setNeedsBarrier();
|
|
||||||
|
|
||||||
if (elementType != MIRType_None && packed)
|
|
||||||
common->setElementType(elementType);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -9358,16 +9323,6 @@ IonBuilder::jsop_length_fastPath()
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compute the length for unboxed array objects.
|
|
||||||
if (UnboxedArrayElementType(constraints(), obj, nullptr) != JSVAL_TYPE_MAGIC) {
|
|
||||||
current->pop();
|
|
||||||
|
|
||||||
MUnboxedArrayLength* length = MUnboxedArrayLength::New(alloc(), obj);
|
|
||||||
current->add(length);
|
|
||||||
current->push(length);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Compute the length for array typed objects.
|
// Compute the length for array typed objects.
|
||||||
TypedObjectPrediction prediction = typedObjectPrediction(obj);
|
TypedObjectPrediction prediction = typedObjectPrediction(obj);
|
||||||
if (!prediction.isUseless()) {
|
if (!prediction.isUseless()) {
|
||||||
|
@ -9435,7 +9390,7 @@ IonBuilder::jsop_rest()
|
||||||
|
|
||||||
MNewArray* array = MNewArray::New(alloc(), constraints(), numRest, templateConst,
|
MNewArray* array = MNewArray::New(alloc(), constraints(), numRest, templateConst,
|
||||||
templateObject->group()->initialHeap(constraints()),
|
templateObject->group()->initialHeap(constraints()),
|
||||||
NewArray_FullyAllocating, pc);
|
NewArray_FullyAllocating);
|
||||||
current->add(array);
|
current->add(array);
|
||||||
|
|
||||||
if (numRest == 0) {
|
if (numRest == 0) {
|
||||||
|
@ -10561,39 +10516,33 @@ IonBuilder::loadUnboxedProperty(MDefinition* obj, size_t offset, JSValueType unb
|
||||||
MInstruction* scaledOffset = MConstant::New(alloc(), Int32Value(scaledOffsetConstant));
|
MInstruction* scaledOffset = MConstant::New(alloc(), Int32Value(scaledOffsetConstant));
|
||||||
current->add(scaledOffset);
|
current->add(scaledOffset);
|
||||||
|
|
||||||
return loadUnboxedValue(obj, UnboxedPlainObject::offsetOfData(),
|
|
||||||
scaledOffset, unboxedType, barrier, types);
|
|
||||||
}
|
|
||||||
|
|
||||||
MInstruction*
|
|
||||||
IonBuilder::loadUnboxedValue(MDefinition* elements, size_t elementsOffset,
|
|
||||||
MDefinition* scaledOffset, JSValueType unboxedType,
|
|
||||||
BarrierKind barrier, TemporaryTypeSet* types)
|
|
||||||
{
|
|
||||||
|
|
||||||
MInstruction* load;
|
MInstruction* load;
|
||||||
switch (unboxedType) {
|
switch (unboxedType) {
|
||||||
case JSVAL_TYPE_BOOLEAN:
|
case JSVAL_TYPE_BOOLEAN:
|
||||||
load = MLoadUnboxedScalar::New(alloc(), elements, scaledOffset, Scalar::Uint8,
|
load = MLoadUnboxedScalar::New(alloc(), obj, scaledOffset, Scalar::Uint8,
|
||||||
DoesNotRequireMemoryBarrier, elementsOffset);
|
DoesNotRequireMemoryBarrier,
|
||||||
|
UnboxedPlainObject::offsetOfData());
|
||||||
load->setResultType(MIRType_Boolean);
|
load->setResultType(MIRType_Boolean);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case JSVAL_TYPE_INT32:
|
case JSVAL_TYPE_INT32:
|
||||||
load = MLoadUnboxedScalar::New(alloc(), elements, scaledOffset, Scalar::Int32,
|
load = MLoadUnboxedScalar::New(alloc(), obj, scaledOffset, Scalar::Int32,
|
||||||
DoesNotRequireMemoryBarrier, elementsOffset);
|
DoesNotRequireMemoryBarrier,
|
||||||
|
UnboxedPlainObject::offsetOfData());
|
||||||
load->setResultType(MIRType_Int32);
|
load->setResultType(MIRType_Int32);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case JSVAL_TYPE_DOUBLE:
|
case JSVAL_TYPE_DOUBLE:
|
||||||
load = MLoadUnboxedScalar::New(alloc(), elements, scaledOffset, Scalar::Float64,
|
load = MLoadUnboxedScalar::New(alloc(), obj, scaledOffset, Scalar::Float64,
|
||||||
DoesNotRequireMemoryBarrier, elementsOffset,
|
DoesNotRequireMemoryBarrier,
|
||||||
|
UnboxedPlainObject::offsetOfData(),
|
||||||
/* canonicalizeDoubles = */ false);
|
/* canonicalizeDoubles = */ false);
|
||||||
load->setResultType(MIRType_Double);
|
load->setResultType(MIRType_Double);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case JSVAL_TYPE_STRING:
|
case JSVAL_TYPE_STRING:
|
||||||
load = MLoadUnboxedString::New(alloc(), elements, scaledOffset, elementsOffset);
|
load = MLoadUnboxedString::New(alloc(), obj, scaledOffset,
|
||||||
|
UnboxedPlainObject::offsetOfData());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case JSVAL_TYPE_OBJECT: {
|
case JSVAL_TYPE_OBJECT: {
|
||||||
|
@ -10602,8 +10551,8 @@ IonBuilder::loadUnboxedValue(MDefinition* elements, size_t elementsOffset,
|
||||||
nullBehavior = MLoadUnboxedObjectOrNull::HandleNull;
|
nullBehavior = MLoadUnboxedObjectOrNull::HandleNull;
|
||||||
else
|
else
|
||||||
nullBehavior = MLoadUnboxedObjectOrNull::NullNotPossible;
|
nullBehavior = MLoadUnboxedObjectOrNull::NullNotPossible;
|
||||||
load = MLoadUnboxedObjectOrNull::New(alloc(), elements, scaledOffset, nullBehavior,
|
load = MLoadUnboxedObjectOrNull::New(alloc(), obj, scaledOffset, nullBehavior,
|
||||||
elementsOffset);
|
UnboxedPlainObject::offsetOfData());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11486,39 +11435,34 @@ IonBuilder::storeUnboxedProperty(MDefinition* obj, size_t offset, JSValueType un
|
||||||
MInstruction* scaledOffset = MConstant::New(alloc(), Int32Value(scaledOffsetConstant));
|
MInstruction* scaledOffset = MConstant::New(alloc(), Int32Value(scaledOffsetConstant));
|
||||||
current->add(scaledOffset);
|
current->add(scaledOffset);
|
||||||
|
|
||||||
return storeUnboxedValue(obj, obj, UnboxedPlainObject::offsetOfData(),
|
|
||||||
scaledOffset, unboxedType, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
MInstruction*
|
|
||||||
IonBuilder::storeUnboxedValue(MDefinition* obj, MDefinition* elements, int32_t elementsOffset,
|
|
||||||
MDefinition* scaledOffset, JSValueType unboxedType,
|
|
||||||
MDefinition* value)
|
|
||||||
{
|
|
||||||
MInstruction* store;
|
MInstruction* store;
|
||||||
switch (unboxedType) {
|
switch (unboxedType) {
|
||||||
case JSVAL_TYPE_BOOLEAN:
|
case JSVAL_TYPE_BOOLEAN:
|
||||||
store = MStoreUnboxedScalar::New(alloc(), elements, scaledOffset, value, Scalar::Uint8,
|
store = MStoreUnboxedScalar::New(alloc(), obj, scaledOffset, value, Scalar::Uint8,
|
||||||
DoesNotRequireMemoryBarrier, elementsOffset);
|
DoesNotRequireMemoryBarrier,
|
||||||
|
UnboxedPlainObject::offsetOfData());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case JSVAL_TYPE_INT32:
|
case JSVAL_TYPE_INT32:
|
||||||
store = MStoreUnboxedScalar::New(alloc(), elements, scaledOffset, value, Scalar::Int32,
|
store = MStoreUnboxedScalar::New(alloc(), obj, scaledOffset, value, Scalar::Int32,
|
||||||
DoesNotRequireMemoryBarrier, elementsOffset);
|
DoesNotRequireMemoryBarrier,
|
||||||
|
UnboxedPlainObject::offsetOfData());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case JSVAL_TYPE_DOUBLE:
|
case JSVAL_TYPE_DOUBLE:
|
||||||
store = MStoreUnboxedScalar::New(alloc(), elements, scaledOffset, value, Scalar::Float64,
|
store = MStoreUnboxedScalar::New(alloc(), obj, scaledOffset, value, Scalar::Float64,
|
||||||
DoesNotRequireMemoryBarrier, elementsOffset);
|
DoesNotRequireMemoryBarrier,
|
||||||
|
UnboxedPlainObject::offsetOfData());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case JSVAL_TYPE_STRING:
|
case JSVAL_TYPE_STRING:
|
||||||
store = MStoreUnboxedString::New(alloc(), elements, scaledOffset, value, elementsOffset);
|
store = MStoreUnboxedString::New(alloc(), obj, scaledOffset, value,
|
||||||
|
UnboxedPlainObject::offsetOfData());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case JSVAL_TYPE_OBJECT:
|
case JSVAL_TYPE_OBJECT:
|
||||||
store = MStoreUnboxedObjectOrNull::New(alloc(), elements, scaledOffset, value, obj,
|
store = MStoreUnboxedObjectOrNull::New(alloc(), obj, scaledOffset, value, obj,
|
||||||
elementsOffset);
|
UnboxedPlainObject::offsetOfData());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -656,13 +656,12 @@ class IonBuilder
|
||||||
bool jsop_intrinsic(PropertyName* name);
|
bool jsop_intrinsic(PropertyName* name);
|
||||||
bool jsop_bindname(PropertyName* name);
|
bool jsop_bindname(PropertyName* name);
|
||||||
bool jsop_getelem();
|
bool jsop_getelem();
|
||||||
bool jsop_getelem_dense(MDefinition* obj, MDefinition* index, JSValueType unboxedType);
|
bool jsop_getelem_dense(MDefinition* obj, MDefinition* index);
|
||||||
bool jsop_getelem_typed(MDefinition* obj, MDefinition* index, ScalarTypeDescr::Type arrayType);
|
bool jsop_getelem_typed(MDefinition* obj, MDefinition* index, ScalarTypeDescr::Type arrayType);
|
||||||
bool jsop_setelem();
|
bool jsop_setelem();
|
||||||
bool jsop_setelem_dense(TemporaryTypeSet::DoubleConversion conversion,
|
bool jsop_setelem_dense(TemporaryTypeSet::DoubleConversion conversion,
|
||||||
SetElemSafety safety,
|
SetElemSafety safety,
|
||||||
MDefinition* object, MDefinition* index, MDefinition* value,
|
MDefinition* object, MDefinition* index, MDefinition* value);
|
||||||
JSValueType unboxedType);
|
|
||||||
bool jsop_setelem_typed(ScalarTypeDescr::Type arrayType,
|
bool jsop_setelem_typed(ScalarTypeDescr::Type arrayType,
|
||||||
SetElemSafety safety,
|
SetElemSafety safety,
|
||||||
MDefinition* object, MDefinition* index, MDefinition* value);
|
MDefinition* object, MDefinition* index, MDefinition* value);
|
||||||
|
@ -951,16 +950,8 @@ class IonBuilder
|
||||||
JSValueType* punboxedType);
|
JSValueType* punboxedType);
|
||||||
MInstruction* loadUnboxedProperty(MDefinition* obj, size_t offset, JSValueType unboxedType,
|
MInstruction* loadUnboxedProperty(MDefinition* obj, size_t offset, JSValueType unboxedType,
|
||||||
BarrierKind barrier, TemporaryTypeSet* types);
|
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,
|
MInstruction* storeUnboxedProperty(MDefinition* obj, size_t offset, JSValueType unboxedType,
|
||||||
MDefinition* value);
|
MDefinition* value);
|
||||||
MInstruction* storeUnboxedValue(MDefinition* obj,
|
|
||||||
MDefinition* elements, int32_t elementsOffset,
|
|
||||||
MDefinition* scaledOffset, JSValueType unboxedType,
|
|
||||||
MDefinition* value);
|
|
||||||
bool checkPreliminaryGroups(MDefinition *obj);
|
|
||||||
bool freezePropTypeSets(TemporaryTypeSet* types,
|
bool freezePropTypeSets(TemporaryTypeSet* types,
|
||||||
JSObject* foundProto, PropertyName* name);
|
JSObject* foundProto, PropertyName* name);
|
||||||
bool canInlinePropertyOpShapes(const BaselineInspector::ReceiverVector& receivers);
|
bool canInlinePropertyOpShapes(const BaselineInspector::ReceiverVector& receivers);
|
||||||
|
|
|
@ -4084,10 +4084,6 @@ class LElements : public LInstructionHelper<1, 1, 0>
|
||||||
const LAllocation* object() {
|
const LAllocation* object() {
|
||||||
return getOperand(0);
|
return getOperand(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
const MElements* mir() const {
|
|
||||||
return mir_->toElements();
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// If necessary, convert any int32 elements in a vector into doubles.
|
// If necessary, convert any int32 elements in a vector into doubles.
|
||||||
|
@ -4185,48 +4181,6 @@ class LSetInitializedLength : public LInstructionHelper<0, 2, 0>
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class LUnboxedArrayLength : public LInstructionHelper<1, 1, 0>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
LIR_HEADER(UnboxedArrayLength)
|
|
||||||
|
|
||||||
explicit LUnboxedArrayLength(const LAllocation& object) {
|
|
||||||
setOperand(0, object);
|
|
||||||
}
|
|
||||||
|
|
||||||
const LAllocation* object() {
|
|
||||||
return getOperand(0);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class LUnboxedArrayInitializedLength : public LInstructionHelper<1, 1, 0>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
LIR_HEADER(UnboxedArrayInitializedLength)
|
|
||||||
|
|
||||||
explicit LUnboxedArrayInitializedLength(const LAllocation& object) {
|
|
||||||
setOperand(0, object);
|
|
||||||
}
|
|
||||||
|
|
||||||
const LAllocation* object() {
|
|
||||||
return getOperand(0);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class LIncrementUnboxedArrayInitializedLength : public LInstructionHelper<0, 1, 0>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
LIR_HEADER(IncrementUnboxedArrayInitializedLength)
|
|
||||||
|
|
||||||
explicit LIncrementUnboxedArrayInitializedLength(const LAllocation& object) {
|
|
||||||
setOperand(0, object);
|
|
||||||
}
|
|
||||||
|
|
||||||
const LAllocation* object() {
|
|
||||||
return getOperand(0);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Load the length from an elements header.
|
// Load the length from an elements header.
|
||||||
class LArrayLength : public LInstructionHelper<1, 1, 0>
|
class LArrayLength : public LInstructionHelper<1, 1, 0>
|
||||||
{
|
{
|
||||||
|
@ -4693,17 +4647,16 @@ class LStoreElementT : public LInstructionHelper<0, 3, 0>
|
||||||
};
|
};
|
||||||
|
|
||||||
// Like LStoreElementV, but supports indexes >= initialized length.
|
// Like LStoreElementV, but supports indexes >= initialized length.
|
||||||
class LStoreElementHoleV : public LInstructionHelper<0, 3 + BOX_PIECES, 1>
|
class LStoreElementHoleV : public LInstructionHelper<0, 3 + BOX_PIECES, 0>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
LIR_HEADER(StoreElementHoleV)
|
LIR_HEADER(StoreElementHoleV)
|
||||||
|
|
||||||
LStoreElementHoleV(const LAllocation& object, const LAllocation& elements,
|
LStoreElementHoleV(const LAllocation& object, const LAllocation& elements,
|
||||||
const LAllocation& index, const LDefinition& temp) {
|
const LAllocation& index) {
|
||||||
setOperand(0, object);
|
setOperand(0, object);
|
||||||
setOperand(1, elements);
|
setOperand(1, elements);
|
||||||
setOperand(2, index);
|
setOperand(2, index);
|
||||||
setTemp(0, temp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const size_t Value = 3;
|
static const size_t Value = 3;
|
||||||
|
@ -4723,19 +4676,17 @@ class LStoreElementHoleV : public LInstructionHelper<0, 3 + BOX_PIECES, 1>
|
||||||
};
|
};
|
||||||
|
|
||||||
// Like LStoreElementT, but supports indexes >= initialized length.
|
// Like LStoreElementT, but supports indexes >= initialized length.
|
||||||
class LStoreElementHoleT : public LInstructionHelper<0, 4, 1>
|
class LStoreElementHoleT : public LInstructionHelper<0, 4, 0>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
LIR_HEADER(StoreElementHoleT)
|
LIR_HEADER(StoreElementHoleT)
|
||||||
|
|
||||||
LStoreElementHoleT(const LAllocation& object, const LAllocation& elements,
|
LStoreElementHoleT(const LAllocation& object, const LAllocation& elements,
|
||||||
const LAllocation& index, const LAllocation& value,
|
const LAllocation& index, const LAllocation& value) {
|
||||||
const LDefinition& temp) {
|
|
||||||
setOperand(0, object);
|
setOperand(0, object);
|
||||||
setOperand(1, elements);
|
setOperand(1, elements);
|
||||||
setOperand(2, index);
|
setOperand(2, index);
|
||||||
setOperand(3, value);
|
setOperand(3, value);
|
||||||
setTemp(0, temp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const MStoreElementHole* mir() const {
|
const MStoreElementHole* mir() const {
|
||||||
|
|
|
@ -214,9 +214,6 @@
|
||||||
_(PostWriteBarrierV) \
|
_(PostWriteBarrierV) \
|
||||||
_(InitializedLength) \
|
_(InitializedLength) \
|
||||||
_(SetInitializedLength) \
|
_(SetInitializedLength) \
|
||||||
_(UnboxedArrayLength) \
|
|
||||||
_(UnboxedArrayInitializedLength) \
|
|
||||||
_(IncrementUnboxedArrayInitializedLength) \
|
|
||||||
_(BoundsCheck) \
|
_(BoundsCheck) \
|
||||||
_(BoundsCheckRange) \
|
_(BoundsCheckRange) \
|
||||||
_(BoundsCheckLower) \
|
_(BoundsCheckLower) \
|
||||||
|
|
|
@ -2495,24 +2495,6 @@ LIRGenerator::visitSetInitializedLength(MSetInitializedLength* ins)
|
||||||
useRegisterOrConstant(ins->index())), ins);
|
useRegisterOrConstant(ins->index())), ins);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
LIRGenerator::visitUnboxedArrayLength(MUnboxedArrayLength* ins)
|
|
||||||
{
|
|
||||||
define(new(alloc()) LUnboxedArrayLength(useRegisterAtStart(ins->object())), ins);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
LIRGenerator::visitUnboxedArrayInitializedLength(MUnboxedArrayInitializedLength* ins)
|
|
||||||
{
|
|
||||||
define(new(alloc()) LUnboxedArrayInitializedLength(useRegisterAtStart(ins->object())), ins);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
LIRGenerator::visitIncrementUnboxedArrayInitializedLength(MIncrementUnboxedArrayInitializedLength* ins)
|
|
||||||
{
|
|
||||||
add(new(alloc()) LIncrementUnboxedArrayInitializedLength(useRegister(ins->object())), ins);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
LIRGenerator::visitNot(MNot* ins)
|
LIRGenerator::visitNot(MNot* ins)
|
||||||
{
|
{
|
||||||
|
@ -2755,22 +2737,17 @@ LIRGenerator::visitStoreElementHole(MStoreElementHole* ins)
|
||||||
const LUse elements = useRegister(ins->elements());
|
const LUse elements = useRegister(ins->elements());
|
||||||
const LAllocation index = useRegisterOrConstant(ins->index());
|
const LAllocation index = useRegisterOrConstant(ins->index());
|
||||||
|
|
||||||
// Use a temp register when adding new elements to unboxed arrays.
|
|
||||||
LDefinition tempDef = LDefinition::BogusTemp();
|
|
||||||
if (ins->unboxedType() != JSVAL_TYPE_MAGIC)
|
|
||||||
tempDef = temp();
|
|
||||||
|
|
||||||
LInstruction* lir;
|
LInstruction* lir;
|
||||||
switch (ins->value()->type()) {
|
switch (ins->value()->type()) {
|
||||||
case MIRType_Value:
|
case MIRType_Value:
|
||||||
lir = new(alloc()) LStoreElementHoleV(object, elements, index, tempDef);
|
lir = new(alloc()) LStoreElementHoleV(object, elements, index);
|
||||||
useBox(lir, LStoreElementHoleV::Value, ins->value());
|
useBox(lir, LStoreElementHoleV::Value, ins->value());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
const LAllocation value = useRegisterOrNonDoubleConstant(ins->value());
|
const LAllocation value = useRegisterOrNonDoubleConstant(ins->value());
|
||||||
lir = new(alloc()) LStoreElementHoleT(object, elements, index, value, tempDef);
|
lir = new(alloc()) LStoreElementHoleT(object, elements, index, value);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -187,9 +187,6 @@ class LIRGenerator : public LIRGeneratorSpecific
|
||||||
void visitTypedObjectDescr(MTypedObjectDescr* ins);
|
void visitTypedObjectDescr(MTypedObjectDescr* ins);
|
||||||
void visitInitializedLength(MInitializedLength* ins);
|
void visitInitializedLength(MInitializedLength* ins);
|
||||||
void visitSetInitializedLength(MSetInitializedLength* ins);
|
void visitSetInitializedLength(MSetInitializedLength* ins);
|
||||||
void visitUnboxedArrayLength(MUnboxedArrayLength* ins);
|
|
||||||
void visitUnboxedArrayInitializedLength(MUnboxedArrayInitializedLength* ins);
|
|
||||||
void visitIncrementUnboxedArrayInitializedLength(MIncrementUnboxedArrayInitializedLength* ins);
|
|
||||||
void visitNot(MNot* ins);
|
void visitNot(MNot* ins);
|
||||||
void visitBoundsCheck(MBoundsCheck* ins);
|
void visitBoundsCheck(MBoundsCheck* ins);
|
||||||
void visitBoundsCheckLower(MBoundsCheckLower* ins);
|
void visitBoundsCheckLower(MBoundsCheckLower* ins);
|
||||||
|
|
|
@ -597,7 +597,7 @@ IonBuilder::inlineArray(CallInfo& callInfo)
|
||||||
|
|
||||||
MNewArray* ins = MNewArray::New(alloc(), constraints(), initLength, templateConst,
|
MNewArray* ins = MNewArray::New(alloc(), constraints(), initLength, templateConst,
|
||||||
templateArray->group()->initialHeap(constraints()),
|
templateArray->group()->initialHeap(constraints()),
|
||||||
allocating, pc);
|
allocating);
|
||||||
current->add(ins);
|
current->add(ins);
|
||||||
current->push(ins);
|
current->push(ins);
|
||||||
|
|
||||||
|
@ -1590,7 +1590,7 @@ IonBuilder::inlineConstantStringSplit(CallInfo& callInfo)
|
||||||
|
|
||||||
MNewArray* ins = MNewArray::New(alloc(), constraints(), initLength, templateConst,
|
MNewArray* ins = MNewArray::New(alloc(), constraints(), initLength, templateConst,
|
||||||
templateObject->group()->initialHeap(constraints()),
|
templateObject->group()->initialHeap(constraints()),
|
||||||
NewArray_FullyAllocating, pc);
|
NewArray_FullyAllocating);
|
||||||
|
|
||||||
current->add(ins);
|
current->add(ins);
|
||||||
current->push(ins);
|
current->push(ins);
|
||||||
|
@ -2135,7 +2135,7 @@ IonBuilder::inlineUnsafeSetDenseArrayElement(CallInfo& callInfo, uint32_t base)
|
||||||
|
|
||||||
TemporaryTypeSet::DoubleConversion conversion =
|
TemporaryTypeSet::DoubleConversion conversion =
|
||||||
obj->resultTypeSet()->convertDoubleElements(constraints());
|
obj->resultTypeSet()->convertDoubleElements(constraints());
|
||||||
if (!jsop_setelem_dense(conversion, SetElem_Unsafe, obj, id, elem, JSVAL_TYPE_MAGIC))
|
if (!jsop_setelem_dense(conversion, SetElem_Unsafe, obj, id, elem))
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4018,17 +4018,17 @@ MArrayState::Copy(TempAllocator& alloc, MArrayState* state)
|
||||||
}
|
}
|
||||||
|
|
||||||
MNewArray::MNewArray(CompilerConstraintList* constraints, uint32_t count, MConstant* templateConst,
|
MNewArray::MNewArray(CompilerConstraintList* constraints, uint32_t count, MConstant* templateConst,
|
||||||
gc::InitialHeap initialHeap, AllocatingBehaviour allocating, jsbytecode* pc)
|
gc::InitialHeap initialHeap, AllocatingBehaviour allocating)
|
||||||
: MUnaryInstruction(templateConst),
|
: MUnaryInstruction(templateConst),
|
||||||
count_(count),
|
count_(count),
|
||||||
initialHeap_(initialHeap),
|
initialHeap_(initialHeap),
|
||||||
allocating_(allocating),
|
allocating_(allocating),
|
||||||
convertDoubleElements_(false),
|
convertDoubleElements_(false)
|
||||||
pc_(pc)
|
|
||||||
{
|
{
|
||||||
|
ArrayObject* obj = templateObject();
|
||||||
setResultType(MIRType_Object);
|
setResultType(MIRType_Object);
|
||||||
if (templateObject()) {
|
if (!obj->isSingleton()) {
|
||||||
TemporaryTypeSet* types = MakeSingletonTypeSet(constraints, templateObject());
|
TemporaryTypeSet* types = MakeSingletonTypeSet(constraints, obj);
|
||||||
setResultTypeSet(types);
|
setResultTypeSet(types);
|
||||||
if (types->convertDoubleElements(constraints) == TemporaryTypeSet::AlwaysConvertToDoubles)
|
if (types->convertDoubleElements(constraints) == TemporaryTypeSet::AlwaysConvertToDoubles)
|
||||||
convertDoubleElements_ = true;
|
convertDoubleElements_ = true;
|
||||||
|
@ -4038,25 +4038,16 @@ MNewArray::MNewArray(CompilerConstraintList* constraints, uint32_t count, MConst
|
||||||
bool
|
bool
|
||||||
MNewArray::shouldUseVM() const
|
MNewArray::shouldUseVM() const
|
||||||
{
|
{
|
||||||
if (!templateObject())
|
|
||||||
return true;
|
|
||||||
|
|
||||||
// Allocate space using the VMCall when mir hints it needs to get allocated
|
|
||||||
// immediately, but only when data doesn't fit the available array slots.
|
|
||||||
if (allocatingBehaviour() == NewArray_Unallocating)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (templateObject()->is<UnboxedArrayObject>()) {
|
|
||||||
MOZ_ASSERT(templateObject()->as<UnboxedArrayObject>().capacity() >= count());
|
|
||||||
return !templateObject()->as<UnboxedArrayObject>().hasInlineElements();
|
|
||||||
}
|
|
||||||
|
|
||||||
MOZ_ASSERT(count() < NativeObject::NELEMENTS_LIMIT);
|
MOZ_ASSERT(count() < NativeObject::NELEMENTS_LIMIT);
|
||||||
|
|
||||||
size_t arraySlots =
|
size_t arraySlots =
|
||||||
gc::GetGCKindSlots(templateObject()->asTenured().getAllocKind()) - ObjectElements::VALUES_PER_HEADER;
|
gc::GetGCKindSlots(templateObject()->asTenured().getAllocKind()) - ObjectElements::VALUES_PER_HEADER;
|
||||||
|
|
||||||
return count() > arraySlots;
|
// Allocate space using the VMCall when mir hints it needs to get allocated
|
||||||
|
// immediately, but only when data doesn't fit the available array slots.
|
||||||
|
bool allocating = allocatingBehaviour() != NewArray_Unallocating && count() > arraySlots;
|
||||||
|
|
||||||
|
return templateObject()->isSingleton() || allocating;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
@ -4705,48 +4696,6 @@ jit::ElementAccessIsDenseNative(CompilerConstraintList* constraints,
|
||||||
return clasp && clasp->isNative() && !IsAnyTypedArrayClass(clasp);
|
return clasp && clasp->isNative() && !IsAnyTypedArrayClass(clasp);
|
||||||
}
|
}
|
||||||
|
|
||||||
JSValueType
|
|
||||||
jit::UnboxedArrayElementType(CompilerConstraintList* constraints, MDefinition* obj,
|
|
||||||
MDefinition* id)
|
|
||||||
{
|
|
||||||
if (obj->mightBeType(MIRType_String))
|
|
||||||
return JSVAL_TYPE_MAGIC;
|
|
||||||
|
|
||||||
if (id && id->type() != MIRType_Int32 && id->type() != MIRType_Double)
|
|
||||||
return JSVAL_TYPE_MAGIC;
|
|
||||||
|
|
||||||
TemporaryTypeSet* types = obj->resultTypeSet();
|
|
||||||
if (!types || types->unknownObject())
|
|
||||||
return JSVAL_TYPE_MAGIC;
|
|
||||||
|
|
||||||
JSValueType elementType = JSVAL_TYPE_MAGIC;
|
|
||||||
for (unsigned i = 0; i < types->getObjectCount(); i++) {
|
|
||||||
TypeSet::ObjectKey* key = types->getObject(i);
|
|
||||||
if (!key)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (key->unknownProperties() || !key->isGroup())
|
|
||||||
return JSVAL_TYPE_MAGIC;
|
|
||||||
|
|
||||||
if (key->clasp() != &UnboxedArrayObject::class_)
|
|
||||||
return JSVAL_TYPE_MAGIC;
|
|
||||||
|
|
||||||
const UnboxedLayout &layout = key->group()->unboxedLayout();
|
|
||||||
|
|
||||||
if (layout.nativeGroup())
|
|
||||||
return JSVAL_TYPE_MAGIC;
|
|
||||||
|
|
||||||
if (elementType == layout.elementType() || elementType == JSVAL_TYPE_MAGIC)
|
|
||||||
elementType = layout.elementType();
|
|
||||||
else
|
|
||||||
return JSVAL_TYPE_MAGIC;
|
|
||||||
|
|
||||||
key->watchStateChangeForUnboxedConvertedToNative(constraints);
|
|
||||||
}
|
|
||||||
|
|
||||||
return elementType;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
jit::ElementAccessIsAnyTypedArray(CompilerConstraintList* constraints,
|
jit::ElementAccessIsAnyTypedArray(CompilerConstraintList* constraints,
|
||||||
MDefinition* obj, MDefinition* id,
|
MDefinition* obj, MDefinition* id,
|
||||||
|
|
182
js/src/jit/MIR.h
182
js/src/jit/MIR.h
|
@ -2917,29 +2917,25 @@ class MNewArray
|
||||||
// Whether values written to this array should be converted to double first.
|
// Whether values written to this array should be converted to double first.
|
||||||
bool convertDoubleElements_;
|
bool convertDoubleElements_;
|
||||||
|
|
||||||
jsbytecode* pc_;
|
|
||||||
|
|
||||||
MNewArray(CompilerConstraintList* constraints, uint32_t count, MConstant* templateConst,
|
MNewArray(CompilerConstraintList* constraints, uint32_t count, MConstant* templateConst,
|
||||||
gc::InitialHeap initialHeap, AllocatingBehaviour allocating, jsbytecode* pc);
|
gc::InitialHeap initialHeap, AllocatingBehaviour allocating);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
INSTRUCTION_HEADER(NewArray)
|
INSTRUCTION_HEADER(NewArray)
|
||||||
|
|
||||||
static MNewArray* New(TempAllocator& alloc, CompilerConstraintList* constraints,
|
static MNewArray* New(TempAllocator& alloc, CompilerConstraintList* constraints,
|
||||||
uint32_t count, MConstant* templateConst,
|
uint32_t count, MConstant* templateConst,
|
||||||
gc::InitialHeap initialHeap, AllocatingBehaviour allocating,
|
gc::InitialHeap initialHeap, AllocatingBehaviour allocating)
|
||||||
jsbytecode* pc)
|
|
||||||
{
|
{
|
||||||
return new(alloc) MNewArray(constraints, count, templateConst,
|
return new(alloc) MNewArray(constraints, count, templateConst, initialHeap, allocating);
|
||||||
initialHeap, allocating, pc);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t count() const {
|
uint32_t count() const {
|
||||||
return count_;
|
return count_;
|
||||||
}
|
}
|
||||||
|
|
||||||
JSObject* templateObject() const {
|
ArrayObject* templateObject() const {
|
||||||
return getOperand(0)->toConstant()->value().toObjectOrNull();
|
return &getOperand(0)->toConstant()->value().toObject().as<ArrayObject>();
|
||||||
}
|
}
|
||||||
|
|
||||||
gc::InitialHeap initialHeap() const {
|
gc::InitialHeap initialHeap() const {
|
||||||
|
@ -2950,10 +2946,6 @@ class MNewArray
|
||||||
return allocating_;
|
return allocating_;
|
||||||
}
|
}
|
||||||
|
|
||||||
jsbytecode* pc() const {
|
|
||||||
return pc_;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool convertDoubleElements() const {
|
bool convertDoubleElements() const {
|
||||||
return convertDoubleElements_;
|
return convertDoubleElements_;
|
||||||
}
|
}
|
||||||
|
@ -2976,7 +2968,7 @@ class MNewArray
|
||||||
bool canRecoverOnBailout() const override {
|
bool canRecoverOnBailout() const override {
|
||||||
// The template object can safely be used in the recover instruction
|
// The template object can safely be used in the recover instruction
|
||||||
// because it can never be mutated by any other function execution.
|
// because it can never be mutated by any other function execution.
|
||||||
return templateObject() != nullptr;
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -7599,10 +7591,8 @@ class MElements
|
||||||
: public MUnaryInstruction,
|
: public MUnaryInstruction,
|
||||||
public SingleObjectPolicy::Data
|
public SingleObjectPolicy::Data
|
||||||
{
|
{
|
||||||
bool unboxed_;
|
explicit MElements(MDefinition* object)
|
||||||
|
: MUnaryInstruction(object)
|
||||||
explicit MElements(MDefinition* object, bool unboxed)
|
|
||||||
: MUnaryInstruction(object), unboxed_(unboxed)
|
|
||||||
{
|
{
|
||||||
setResultType(MIRType_Elements);
|
setResultType(MIRType_Elements);
|
||||||
setMovable();
|
setMovable();
|
||||||
|
@ -7611,19 +7601,15 @@ class MElements
|
||||||
public:
|
public:
|
||||||
INSTRUCTION_HEADER(Elements)
|
INSTRUCTION_HEADER(Elements)
|
||||||
|
|
||||||
static MElements* New(TempAllocator& alloc, MDefinition* object, bool unboxed = false) {
|
static MElements* New(TempAllocator& alloc, MDefinition* object) {
|
||||||
return new(alloc) MElements(object, unboxed);
|
return new(alloc) MElements(object);
|
||||||
}
|
}
|
||||||
|
|
||||||
MDefinition* object() const {
|
MDefinition* object() const {
|
||||||
return getOperand(0);
|
return getOperand(0);
|
||||||
}
|
}
|
||||||
bool unboxed() const {
|
|
||||||
return unboxed_;
|
|
||||||
}
|
|
||||||
bool congruentTo(const MDefinition* ins) const override {
|
bool congruentTo(const MDefinition* ins) const override {
|
||||||
return congruentIfOperandsEqual(ins) &&
|
return congruentIfOperandsEqual(ins);
|
||||||
ins->toElements()->unboxed() == unboxed();
|
|
||||||
}
|
}
|
||||||
AliasSet getAliasSet() const override {
|
AliasSet getAliasSet() const override {
|
||||||
return AliasSet::Load(AliasSet::ObjectFields);
|
return AliasSet::Load(AliasSet::ObjectFields);
|
||||||
|
@ -7854,96 +7840,6 @@ class MSetInitializedLength
|
||||||
ALLOW_CLONE(MSetInitializedLength)
|
ALLOW_CLONE(MSetInitializedLength)
|
||||||
};
|
};
|
||||||
|
|
||||||
// Load the length from an unboxed array.
|
|
||||||
class MUnboxedArrayLength
|
|
||||||
: public MUnaryInstruction,
|
|
||||||
public SingleObjectPolicy::Data
|
|
||||||
{
|
|
||||||
explicit MUnboxedArrayLength(MDefinition* object)
|
|
||||||
: MUnaryInstruction(object)
|
|
||||||
{
|
|
||||||
setResultType(MIRType_Int32);
|
|
||||||
setMovable();
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
INSTRUCTION_HEADER(UnboxedArrayLength)
|
|
||||||
|
|
||||||
static MUnboxedArrayLength* New(TempAllocator& alloc, MDefinition* object) {
|
|
||||||
return new(alloc) MUnboxedArrayLength(object);
|
|
||||||
}
|
|
||||||
|
|
||||||
MDefinition* object() const {
|
|
||||||
return getOperand(0);
|
|
||||||
}
|
|
||||||
bool congruentTo(const MDefinition* ins) const override {
|
|
||||||
return congruentIfOperandsEqual(ins);
|
|
||||||
}
|
|
||||||
AliasSet getAliasSet() const override {
|
|
||||||
return AliasSet::Load(AliasSet::ObjectFields);
|
|
||||||
}
|
|
||||||
|
|
||||||
ALLOW_CLONE(MUnboxedArrayLength)
|
|
||||||
};
|
|
||||||
|
|
||||||
// Load the initialized length from an unboxed array.
|
|
||||||
class MUnboxedArrayInitializedLength
|
|
||||||
: public MUnaryInstruction,
|
|
||||||
public SingleObjectPolicy::Data
|
|
||||||
{
|
|
||||||
explicit MUnboxedArrayInitializedLength(MDefinition* object)
|
|
||||||
: MUnaryInstruction(object)
|
|
||||||
{
|
|
||||||
setResultType(MIRType_Int32);
|
|
||||||
setMovable();
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
INSTRUCTION_HEADER(UnboxedArrayInitializedLength)
|
|
||||||
|
|
||||||
static MUnboxedArrayInitializedLength* New(TempAllocator& alloc, MDefinition* object) {
|
|
||||||
return new(alloc) MUnboxedArrayInitializedLength(object);
|
|
||||||
}
|
|
||||||
|
|
||||||
MDefinition* object() const {
|
|
||||||
return getOperand(0);
|
|
||||||
}
|
|
||||||
bool congruentTo(const MDefinition* ins) const override {
|
|
||||||
return congruentIfOperandsEqual(ins);
|
|
||||||
}
|
|
||||||
AliasSet getAliasSet() const override {
|
|
||||||
return AliasSet::Load(AliasSet::ObjectFields);
|
|
||||||
}
|
|
||||||
|
|
||||||
ALLOW_CLONE(MUnboxedArrayInitializedLength)
|
|
||||||
};
|
|
||||||
|
|
||||||
// Increment the initialized length of an unboxed array object.
|
|
||||||
class MIncrementUnboxedArrayInitializedLength
|
|
||||||
: public MUnaryInstruction,
|
|
||||||
public SingleObjectPolicy::Data
|
|
||||||
{
|
|
||||||
explicit MIncrementUnboxedArrayInitializedLength(MDefinition* obj)
|
|
||||||
: MUnaryInstruction(obj)
|
|
||||||
{}
|
|
||||||
|
|
||||||
public:
|
|
||||||
INSTRUCTION_HEADER(IncrementUnboxedArrayInitializedLength)
|
|
||||||
|
|
||||||
static MIncrementUnboxedArrayInitializedLength* New(TempAllocator& alloc, MDefinition* obj) {
|
|
||||||
return new(alloc) MIncrementUnboxedArrayInitializedLength(obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
MDefinition* object() const {
|
|
||||||
return getOperand(0);
|
|
||||||
}
|
|
||||||
AliasSet getAliasSet() const override {
|
|
||||||
return AliasSet::Store(AliasSet::ObjectFields);
|
|
||||||
}
|
|
||||||
|
|
||||||
ALLOW_CLONE(MIncrementUnboxedArrayInitializedLength)
|
|
||||||
};
|
|
||||||
|
|
||||||
// Load the array length from an elements header.
|
// Load the array length from an elements header.
|
||||||
class MArrayLength
|
class MArrayLength
|
||||||
: public MUnaryInstruction,
|
: public MUnaryInstruction,
|
||||||
|
@ -8463,23 +8359,18 @@ class MLoadElement
|
||||||
ALLOW_CLONE(MLoadElement)
|
ALLOW_CLONE(MLoadElement)
|
||||||
};
|
};
|
||||||
|
|
||||||
// Load a value from the elements vector for a dense native or unboxed array.
|
// Load a value from a dense array's element vector. If the index is
|
||||||
// If the index is out-of-bounds, or the indexed slot has a hole, undefined is
|
// out-of-bounds, or the indexed slot has a hole, undefined is returned
|
||||||
// returned instead.
|
// instead.
|
||||||
class MLoadElementHole
|
class MLoadElementHole
|
||||||
: public MTernaryInstruction,
|
: public MTernaryInstruction,
|
||||||
public SingleObjectPolicy::Data
|
public SingleObjectPolicy::Data
|
||||||
{
|
{
|
||||||
// Unboxed element type, JSVAL_TYPE_MAGIC for dense native elements.
|
|
||||||
JSValueType unboxedType_;
|
|
||||||
|
|
||||||
bool needsNegativeIntCheck_;
|
bool needsNegativeIntCheck_;
|
||||||
bool needsHoleCheck_;
|
bool needsHoleCheck_;
|
||||||
|
|
||||||
MLoadElementHole(MDefinition* elements, MDefinition* index, MDefinition* initLength,
|
MLoadElementHole(MDefinition* elements, MDefinition* index, MDefinition* initLength, bool needsHoleCheck)
|
||||||
JSValueType unboxedType, bool needsHoleCheck)
|
|
||||||
: MTernaryInstruction(elements, index, initLength),
|
: MTernaryInstruction(elements, index, initLength),
|
||||||
unboxedType_(unboxedType),
|
|
||||||
needsNegativeIntCheck_(true),
|
needsNegativeIntCheck_(true),
|
||||||
needsHoleCheck_(needsHoleCheck)
|
needsHoleCheck_(needsHoleCheck)
|
||||||
{
|
{
|
||||||
|
@ -8500,10 +8391,8 @@ class MLoadElementHole
|
||||||
INSTRUCTION_HEADER(LoadElementHole)
|
INSTRUCTION_HEADER(LoadElementHole)
|
||||||
|
|
||||||
static MLoadElementHole* New(TempAllocator& alloc, MDefinition* elements, MDefinition* index,
|
static MLoadElementHole* New(TempAllocator& alloc, MDefinition* elements, MDefinition* index,
|
||||||
MDefinition* initLength, JSValueType unboxedType,
|
MDefinition* initLength, bool needsHoleCheck) {
|
||||||
bool needsHoleCheck) {
|
return new(alloc) MLoadElementHole(elements, index, initLength, needsHoleCheck);
|
||||||
return new(alloc) MLoadElementHole(elements, index, initLength,
|
|
||||||
unboxedType, needsHoleCheck);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MDefinition* elements() const {
|
MDefinition* elements() const {
|
||||||
|
@ -8515,9 +8404,6 @@ class MLoadElementHole
|
||||||
MDefinition* initLength() const {
|
MDefinition* initLength() const {
|
||||||
return getOperand(2);
|
return getOperand(2);
|
||||||
}
|
}
|
||||||
JSValueType unboxedType() const {
|
|
||||||
return unboxedType_;
|
|
||||||
}
|
|
||||||
bool needsNegativeIntCheck() const {
|
bool needsNegativeIntCheck() const {
|
||||||
return needsNegativeIntCheck_;
|
return needsNegativeIntCheck_;
|
||||||
}
|
}
|
||||||
|
@ -8528,8 +8414,6 @@ class MLoadElementHole
|
||||||
if (!ins->isLoadElementHole())
|
if (!ins->isLoadElementHole())
|
||||||
return false;
|
return false;
|
||||||
const MLoadElementHole* other = ins->toLoadElementHole();
|
const MLoadElementHole* other = ins->toLoadElementHole();
|
||||||
if (unboxedType() != other->unboxedType())
|
|
||||||
return false;
|
|
||||||
if (needsHoleCheck() != other->needsHoleCheck())
|
if (needsHoleCheck() != other->needsHoleCheck())
|
||||||
return false;
|
return false;
|
||||||
if (needsNegativeIntCheck() != other->needsNegativeIntCheck())
|
if (needsNegativeIntCheck() != other->needsNegativeIntCheck())
|
||||||
|
@ -8537,9 +8421,7 @@ class MLoadElementHole
|
||||||
return congruentIfOperandsEqual(other);
|
return congruentIfOperandsEqual(other);
|
||||||
}
|
}
|
||||||
AliasSet getAliasSet() const override {
|
AliasSet getAliasSet() const override {
|
||||||
return AliasSet::Load(unboxedType() == JSVAL_TYPE_MAGIC
|
return AliasSet::Load(AliasSet::Element);
|
||||||
? AliasSet::Element
|
|
||||||
: AliasSet::UnboxedElement);
|
|
||||||
}
|
}
|
||||||
void collectRangeInfoPreTrunc() override;
|
void collectRangeInfoPreTrunc() override;
|
||||||
|
|
||||||
|
@ -8749,21 +8631,17 @@ class MStoreElement
|
||||||
ALLOW_CLONE(MStoreElement)
|
ALLOW_CLONE(MStoreElement)
|
||||||
};
|
};
|
||||||
|
|
||||||
// Like MStoreElement, but supports indexes >= initialized length, and can
|
// Like MStoreElement, but supports indexes >= initialized length. The downside
|
||||||
// handle unboxed arrays. The downside is that we cannot hoist the elements
|
// is that we cannot hoist the elements vector and bounds check, since this
|
||||||
// vector and bounds check, since this instruction may update the (initialized)
|
// instruction may update the (initialized) length and reallocate the elements
|
||||||
// length and reallocate the elements vector.
|
// vector.
|
||||||
class MStoreElementHole
|
class MStoreElementHole
|
||||||
: public MAryInstruction<4>,
|
: public MAryInstruction<4>,
|
||||||
public MStoreElementCommon,
|
public MStoreElementCommon,
|
||||||
public MixPolicy<SingleObjectPolicy, NoFloatPolicy<3> >::Data
|
public MixPolicy<SingleObjectPolicy, NoFloatPolicy<3> >::Data
|
||||||
{
|
{
|
||||||
JSValueType unboxedType_;
|
|
||||||
|
|
||||||
MStoreElementHole(MDefinition* object, MDefinition* elements,
|
MStoreElementHole(MDefinition* object, MDefinition* elements,
|
||||||
MDefinition* index, MDefinition* value, JSValueType unboxedType)
|
MDefinition* index, MDefinition* value) {
|
||||||
: unboxedType_(unboxedType)
|
|
||||||
{
|
|
||||||
initOperand(0, object);
|
initOperand(0, object);
|
||||||
initOperand(1, elements);
|
initOperand(1, elements);
|
||||||
initOperand(2, index);
|
initOperand(2, index);
|
||||||
|
@ -8776,8 +8654,8 @@ class MStoreElementHole
|
||||||
INSTRUCTION_HEADER(StoreElementHole)
|
INSTRUCTION_HEADER(StoreElementHole)
|
||||||
|
|
||||||
static MStoreElementHole* New(TempAllocator& alloc, MDefinition* object, MDefinition* elements,
|
static MStoreElementHole* New(TempAllocator& alloc, MDefinition* object, MDefinition* elements,
|
||||||
MDefinition* index, MDefinition* value, JSValueType unboxedType) {
|
MDefinition* index, MDefinition* value) {
|
||||||
return new(alloc) MStoreElementHole(object, elements, index, value, unboxedType);
|
return new(alloc) MStoreElementHole(object, elements, index, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
MDefinition* object() const {
|
MDefinition* object() const {
|
||||||
|
@ -8792,16 +8670,10 @@ class MStoreElementHole
|
||||||
MDefinition* value() const {
|
MDefinition* value() const {
|
||||||
return getOperand(3);
|
return getOperand(3);
|
||||||
}
|
}
|
||||||
JSValueType unboxedType() const {
|
|
||||||
return unboxedType_;
|
|
||||||
}
|
|
||||||
AliasSet getAliasSet() const override {
|
AliasSet getAliasSet() const override {
|
||||||
// StoreElementHole can update the initialized length, the array length
|
// StoreElementHole can update the initialized length, the array length
|
||||||
// or reallocate obj->elements.
|
// or reallocate obj->elements.
|
||||||
return AliasSet::Store(AliasSet::ObjectFields |
|
return AliasSet::Store(AliasSet::Element | AliasSet::ObjectFields);
|
||||||
((unboxedType() == JSVAL_TYPE_MAGIC)
|
|
||||||
? AliasSet::Element
|
|
||||||
: AliasSet::UnboxedElement));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ALLOW_CLONE(MStoreElementHole)
|
ALLOW_CLONE(MStoreElementHole)
|
||||||
|
@ -13348,8 +13220,6 @@ MControlInstruction* MDefinition::toControlInstruction() {
|
||||||
|
|
||||||
bool ElementAccessIsDenseNative(CompilerConstraintList* constraints,
|
bool ElementAccessIsDenseNative(CompilerConstraintList* constraints,
|
||||||
MDefinition* obj, MDefinition* id);
|
MDefinition* obj, MDefinition* id);
|
||||||
JSValueType UnboxedArrayElementType(CompilerConstraintList* constraints, MDefinition* obj,
|
|
||||||
MDefinition* id);
|
|
||||||
bool ElementAccessIsAnyTypedArray(CompilerConstraintList* constraints,
|
bool ElementAccessIsAnyTypedArray(CompilerConstraintList* constraints,
|
||||||
MDefinition* obj, MDefinition* id,
|
MDefinition* obj, MDefinition* id,
|
||||||
Scalar::Type* arrayType);
|
Scalar::Type* arrayType);
|
||||||
|
|
|
@ -178,9 +178,6 @@ namespace jit {
|
||||||
_(SetTypedObjectOffset) \
|
_(SetTypedObjectOffset) \
|
||||||
_(InitializedLength) \
|
_(InitializedLength) \
|
||||||
_(SetInitializedLength) \
|
_(SetInitializedLength) \
|
||||||
_(UnboxedArrayLength) \
|
|
||||||
_(UnboxedArrayInitializedLength) \
|
|
||||||
_(IncrementUnboxedArrayInitializedLength) \
|
|
||||||
_(Not) \
|
_(Not) \
|
||||||
_(BoundsCheck) \
|
_(BoundsCheck) \
|
||||||
_(BoundsCheckLower) \
|
_(BoundsCheckLower) \
|
||||||
|
|
|
@ -1016,31 +1016,6 @@ template void
|
||||||
MacroAssembler::storeUnboxedProperty(BaseIndex address, JSValueType type,
|
MacroAssembler::storeUnboxedProperty(BaseIndex address, JSValueType type,
|
||||||
ConstantOrRegister value, Label* failure);
|
ConstantOrRegister value, Label* failure);
|
||||||
|
|
||||||
void
|
|
||||||
MacroAssembler::checkUnboxedArrayCapacity(Register obj, const Int32Key& index, Register temp,
|
|
||||||
Label* failure)
|
|
||||||
{
|
|
||||||
Address initLengthAddr(obj, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength());
|
|
||||||
Address lengthAddr(obj, UnboxedArrayObject::offsetOfLength());
|
|
||||||
|
|
||||||
Label capacityIsIndex, done;
|
|
||||||
load32(initLengthAddr, temp);
|
|
||||||
branchTest32(Assembler::NonZero, temp, Imm32(UnboxedArrayObject::CapacityMask), &capacityIsIndex);
|
|
||||||
branchKey(Assembler::BelowOrEqual, lengthAddr, index, failure);
|
|
||||||
jump(&done);
|
|
||||||
bind(&capacityIsIndex);
|
|
||||||
|
|
||||||
// Do a partial shift so that we can get an absolute offset from the base
|
|
||||||
// of CapacityArray to use.
|
|
||||||
JS_STATIC_ASSERT(sizeof(UnboxedArrayObject::CapacityArray[0]) == 4);
|
|
||||||
rshiftPtr(Imm32(UnboxedArrayObject::CapacityShift - 2), temp);
|
|
||||||
and32(Imm32(~0x3), temp);
|
|
||||||
|
|
||||||
addPtr(ImmPtr(&UnboxedArrayObject::CapacityArray), temp);
|
|
||||||
branchKey(Assembler::BelowOrEqual, Address(temp, 0), index, failure);
|
|
||||||
bind(&done);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Inlined version of gc::CheckAllocatorState that checks the bare essentials
|
// Inlined version of gc::CheckAllocatorState that checks the bare essentials
|
||||||
// and bails for anything that cannot be handled with our jit allocators.
|
// and bails for anything that cannot be handled with our jit allocators.
|
||||||
void
|
void
|
||||||
|
@ -1458,16 +1433,6 @@ MacroAssembler::initGCThing(Register obj, Register temp, JSObject* templateObj,
|
||||||
storePtr(ImmWord(0), Address(obj, UnboxedPlainObject::offsetOfExpando()));
|
storePtr(ImmWord(0), Address(obj, UnboxedPlainObject::offsetOfExpando()));
|
||||||
if (initContents)
|
if (initContents)
|
||||||
initUnboxedObjectContents(obj, &templateObj->as<UnboxedPlainObject>());
|
initUnboxedObjectContents(obj, &templateObj->as<UnboxedPlainObject>());
|
||||||
} else if (templateObj->is<UnboxedArrayObject>()) {
|
|
||||||
MOZ_ASSERT(templateObj->as<UnboxedArrayObject>().hasInlineElements());
|
|
||||||
int elementsOffset = UnboxedArrayObject::offsetOfInlineElements();
|
|
||||||
computeEffectiveAddress(Address(obj, elementsOffset), temp);
|
|
||||||
storePtr(temp, Address(obj, UnboxedArrayObject::offsetOfElements()));
|
|
||||||
store32(Imm32(templateObj->as<UnboxedArrayObject>().length()),
|
|
||||||
Address(obj, UnboxedArrayObject::offsetOfLength()));
|
|
||||||
uint32_t capacityIndex = templateObj->as<UnboxedArrayObject>().capacityIndex();
|
|
||||||
store32(Imm32(capacityIndex << UnboxedArrayObject::CapacityShift),
|
|
||||||
Address(obj, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength()));
|
|
||||||
} else {
|
} else {
|
||||||
MOZ_CRASH("Unknown object");
|
MOZ_CRASH("Unknown object");
|
||||||
}
|
}
|
||||||
|
|
|
@ -718,7 +718,7 @@ class MacroAssembler : public MacroAssemblerSpecific
|
||||||
void storeToTypedFloatArray(Scalar::Type arrayType, FloatRegister value, const Address& dest,
|
void storeToTypedFloatArray(Scalar::Type arrayType, FloatRegister value, const Address& dest,
|
||||||
unsigned numElems = 0);
|
unsigned numElems = 0);
|
||||||
|
|
||||||
// Load a property from an UnboxedPlainObject or UnboxedArrayObject.
|
// Load a property from an UnboxedPlainObject.
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void loadUnboxedProperty(T address, JSValueType type, TypedOrValueRegister output);
|
void loadUnboxedProperty(T address, JSValueType type, TypedOrValueRegister output);
|
||||||
|
|
||||||
|
@ -729,9 +729,6 @@ class MacroAssembler : public MacroAssemblerSpecific
|
||||||
void storeUnboxedProperty(T address, JSValueType type,
|
void storeUnboxedProperty(T address, JSValueType type,
|
||||||
ConstantOrRegister value, Label* failure);
|
ConstantOrRegister value, Label* failure);
|
||||||
|
|
||||||
void checkUnboxedArrayCapacity(Register obj, const Int32Key& index, Register temp,
|
|
||||||
Label* failure);
|
|
||||||
|
|
||||||
Register extractString(const Address& address, Register scratch) {
|
Register extractString(const Address& address, Register scratch) {
|
||||||
return extractObject(address, scratch);
|
return extractObject(address, scratch);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1214,6 +1214,10 @@ RNewArray::recover(JSContext* cx, SnapshotIterator& iter) const
|
||||||
RootedValue result(cx);
|
RootedValue result(cx);
|
||||||
RootedObjectGroup group(cx);
|
RootedObjectGroup group(cx);
|
||||||
|
|
||||||
|
// See CodeGenerator::visitNewArrayCallVM
|
||||||
|
if (!templateObject->isSingleton())
|
||||||
|
group = templateObject->group();
|
||||||
|
|
||||||
JSObject* resultObject = NewDenseArray(cx, count_, group, allocatingBehaviour_);
|
JSObject* resultObject = NewDenseArray(cx, count_, group, allocatingBehaviour_);
|
||||||
if (!resultObject)
|
if (!resultObject)
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -612,10 +612,6 @@ IsArrayEscaped(MInstruction* ins)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
JSObject* obj = ins->toNewArray()->templateObject();
|
|
||||||
if (!obj || obj->is<UnboxedArrayObject>())
|
|
||||||
return true;
|
|
||||||
|
|
||||||
if (count >= 16) {
|
if (count >= 16) {
|
||||||
JitSpewDef(JitSpew_Escape, "Array has too many elements\n", ins);
|
JitSpewDef(JitSpew_Escape, "Array has too many elements\n", ins);
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -1109,22 +1109,22 @@ Recompile(JSContext* cx)
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
SetDenseOrUnboxedArrayElement(JSContext* cx, HandleObject obj, int32_t index,
|
SetDenseElement(JSContext* cx, HandleNativeObject obj, int32_t index, HandleValue value,
|
||||||
HandleValue value, bool strict)
|
bool strict)
|
||||||
{
|
{
|
||||||
// This function is called from Ion code for StoreElementHole's OOL path.
|
// This function is called from Ion code for StoreElementHole's OOL path.
|
||||||
// In this case we know the object is native or an unboxed array and we can
|
// In this case we know the object is native and we can use setDenseElement
|
||||||
// use setDenseElement instead of setDenseElementWithType.
|
// instead of setDenseElementWithType.
|
||||||
|
|
||||||
NativeObject::EnsureDenseResult result = NativeObject::ED_SPARSE;
|
NativeObject::EnsureDenseResult result = NativeObject::ED_SPARSE;
|
||||||
do {
|
do {
|
||||||
if (index < 0 || obj->is<UnboxedArrayObject>())
|
if (index < 0)
|
||||||
break;
|
break;
|
||||||
bool isArray = obj->is<ArrayObject>();
|
bool isArray = obj->is<ArrayObject>();
|
||||||
if (isArray && !obj->as<ArrayObject>().lengthIsWritable())
|
if (isArray && !obj->as<ArrayObject>().lengthIsWritable())
|
||||||
break;
|
break;
|
||||||
uint32_t idx = uint32_t(index);
|
uint32_t idx = uint32_t(index);
|
||||||
result = obj->as<NativeObject>().ensureDenseElements(cx, idx, 1);
|
result = obj->ensureDenseElements(cx, idx, 1);
|
||||||
if (result != NativeObject::ED_OK)
|
if (result != NativeObject::ED_OK)
|
||||||
break;
|
break;
|
||||||
if (isArray) {
|
if (isArray) {
|
||||||
|
@ -1132,7 +1132,7 @@ SetDenseOrUnboxedArrayElement(JSContext* cx, HandleObject obj, int32_t index,
|
||||||
if (idx >= arr.length())
|
if (idx >= arr.length())
|
||||||
arr.setLengthInt32(idx + 1);
|
arr.setLengthInt32(idx + 1);
|
||||||
}
|
}
|
||||||
obj->as<NativeObject>().setDenseElement(idx, value);
|
obj->setDenseElement(idx, value);
|
||||||
return true;
|
return true;
|
||||||
} while (false);
|
} while (false);
|
||||||
|
|
||||||
|
|
|
@ -746,8 +746,8 @@ JSString* RegExpReplace(JSContext* cx, HandleString string, HandleObject regexp,
|
||||||
JSString* StringReplace(JSContext* cx, HandleString string, HandleString pattern,
|
JSString* StringReplace(JSContext* cx, HandleString string, HandleString pattern,
|
||||||
HandleString repl);
|
HandleString repl);
|
||||||
|
|
||||||
bool SetDenseOrUnboxedArrayElement(JSContext* cx, HandleObject obj, int32_t index,
|
bool SetDenseElement(JSContext* cx, HandleNativeObject obj, int32_t index, HandleValue value,
|
||||||
HandleValue value, bool strict);
|
bool strict);
|
||||||
|
|
||||||
void AssertValidObjectPtr(JSContext* cx, JSObject* obj);
|
void AssertValidObjectPtr(JSContext* cx, JSObject* obj);
|
||||||
void AssertValidObjectOrNullPtr(JSContext* cx, JSObject* obj);
|
void AssertValidObjectOrNullPtr(JSContext* cx, JSObject* obj);
|
||||||
|
|
|
@ -433,13 +433,6 @@ class MOZ_STACK_CLASS AutoValueVector : public AutoVectorRooter<Value>
|
||||||
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
||||||
}
|
}
|
||||||
|
|
||||||
explicit AutoValueVector(js::ContextFriendFields* cx
|
|
||||||
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
|
||||||
: AutoVectorRooter<Value>(cx, VALVECTOR)
|
|
||||||
{
|
|
||||||
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
|
||||||
}
|
|
||||||
|
|
||||||
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
|
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1190,7 +1183,6 @@ class JS_PUBLIC_API(RuntimeOptions) {
|
||||||
asmJS_(false),
|
asmJS_(false),
|
||||||
nativeRegExp_(false),
|
nativeRegExp_(false),
|
||||||
unboxedObjects_(false),
|
unboxedObjects_(false),
|
||||||
unboxedArrays_(false),
|
|
||||||
werror_(false),
|
werror_(false),
|
||||||
strictMode_(false),
|
strictMode_(false),
|
||||||
extraWarnings_(false),
|
extraWarnings_(false),
|
||||||
|
@ -1240,12 +1232,6 @@ class JS_PUBLIC_API(RuntimeOptions) {
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool unboxedArrays() const { return unboxedArrays_; }
|
|
||||||
RuntimeOptions& setUnboxedArrays(bool flag) {
|
|
||||||
unboxedArrays_ = flag;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool werror() const { return werror_; }
|
bool werror() const { return werror_; }
|
||||||
RuntimeOptions& setWerror(bool flag) {
|
RuntimeOptions& setWerror(bool flag) {
|
||||||
werror_ = flag;
|
werror_ = flag;
|
||||||
|
@ -1292,7 +1278,6 @@ class JS_PUBLIC_API(RuntimeOptions) {
|
||||||
bool asmJS_ : 1;
|
bool asmJS_ : 1;
|
||||||
bool nativeRegExp_ : 1;
|
bool nativeRegExp_ : 1;
|
||||||
bool unboxedObjects_ : 1;
|
bool unboxedObjects_ : 1;
|
||||||
bool unboxedArrays_ : 1;
|
|
||||||
bool werror_ : 1;
|
bool werror_ : 1;
|
||||||
bool strictMode_ : 1;
|
bool strictMode_ : 1;
|
||||||
bool extraWarnings_ : 1;
|
bool extraWarnings_ : 1;
|
||||||
|
|
|
@ -2287,13 +2287,8 @@ TryReuseArrayGroup(JSObject* obj, ArrayObject* narr)
|
||||||
*/
|
*/
|
||||||
MOZ_ASSERT(ObjectGroup::hasDefaultNewGroup(narr->getProto(), &ArrayObject::class_, narr->group()));
|
MOZ_ASSERT(ObjectGroup::hasDefaultNewGroup(narr->getProto(), &ArrayObject::class_, narr->group()));
|
||||||
|
|
||||||
if (obj->is<ArrayObject>() &&
|
if (obj->is<ArrayObject>() && !obj->isSingleton() && obj->getProto() == narr->getProto())
|
||||||
!obj->isSingleton() &&
|
|
||||||
!obj->group()->hasUnanalyzedPreliminaryObjects() &&
|
|
||||||
obj->getProto() == narr->getProto())
|
|
||||||
{
|
|
||||||
narr->setGroup(obj->group());
|
narr->setGroup(obj->group());
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -331,12 +331,6 @@ GetGCKindSlots(AllocKind thingKind, const Class* clasp)
|
||||||
return nslots;
|
return nslots;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline size_t
|
|
||||||
GetGCKindBytes(AllocKind thingKind)
|
|
||||||
{
|
|
||||||
return sizeof(JSObject_Slots0) + GetGCKindSlots(thingKind) * sizeof(Value);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Class to assist in triggering background chunk allocation. This cannot be done
|
// Class to assist in triggering background chunk allocation. This cannot be done
|
||||||
// while holding the GC or worker thread state lock due to lock ordering issues.
|
// while holding the GC or worker thread state lock due to lock ordering issues.
|
||||||
// As a result, the triggering is delayed using this class until neither of the
|
// As a result, the triggering is delayed using this class until neither of the
|
||||||
|
|
|
@ -283,20 +283,8 @@ Snapshot(JSContext* cx, HandleObject pobj_, unsigned flags, AutoIdVector* props)
|
||||||
if (!enumerate(cx, pobj, properties))
|
if (!enumerate(cx, pobj, properties))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
RootedId id(cx);
|
|
||||||
for (size_t n = 0; n < properties.length(); n++) {
|
for (size_t n = 0; n < properties.length(); n++) {
|
||||||
id = properties[n];
|
if (!Enumerate(cx, pobj, properties[n], true, flags, ht, props))
|
||||||
bool enumerable = true;
|
|
||||||
|
|
||||||
// The enumerate hook does not indicate whether the properties
|
|
||||||
// it returns are enumerable or not. There is no non-effectful
|
|
||||||
// way to determine this from the object, so carve out
|
|
||||||
// exceptions here for places where the property is not
|
|
||||||
// enumerable.
|
|
||||||
if (pobj->is<UnboxedArrayObject>() && id == NameToId(cx->names().length))
|
|
||||||
enumerable = false;
|
|
||||||
|
|
||||||
if (!Enumerate(cx, pobj, id, enumerable, flags, ht, props))
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,7 @@
|
||||||
inline js::Shape*
|
inline js::Shape*
|
||||||
JSObject::maybeShape() const
|
JSObject::maybeShape() const
|
||||||
{
|
{
|
||||||
if (is<js::UnboxedPlainObject>() || is<js::UnboxedArrayObject>())
|
if (is<js::UnboxedPlainObject>())
|
||||||
return nullptr;
|
return nullptr;
|
||||||
return *reinterpret_cast<js::Shape**>(uintptr_t(this) + offsetOfShape());
|
return *reinterpret_cast<js::Shape**>(uintptr_t(this) + offsetOfShape());
|
||||||
}
|
}
|
||||||
|
@ -268,8 +268,6 @@ JSObject::create(js::ExclusiveContext* cx, js::gc::AllocKind kind, js::gc::Initi
|
||||||
MOZ_ASSERT_IF(group->clasp()->finalize,
|
MOZ_ASSERT_IF(group->clasp()->finalize,
|
||||||
heap == js::gc::TenuredHeap ||
|
heap == js::gc::TenuredHeap ||
|
||||||
(group->clasp()->flags & JSCLASS_FINALIZE_FROM_NURSERY));
|
(group->clasp()->flags & JSCLASS_FINALIZE_FROM_NURSERY));
|
||||||
MOZ_ASSERT_IF(group->hasUnanalyzedPreliminaryObjects(),
|
|
||||||
heap == js::gc::TenuredHeap);
|
|
||||||
|
|
||||||
// Non-native classes cannot have reserved slots or private data, and the
|
// Non-native classes cannot have reserved slots or private data, and the
|
||||||
// objects can't have any fixed slots, for compatibility with
|
// objects can't have any fixed slots, for compatibility with
|
||||||
|
@ -771,11 +769,11 @@ ObjectClassIs(HandleObject obj, ESClassValue classValue, JSContext* cx)
|
||||||
return Proxy::objectClassIs(obj, classValue, cx);
|
return Proxy::objectClassIs(obj, classValue, cx);
|
||||||
|
|
||||||
switch (classValue) {
|
switch (classValue) {
|
||||||
case ESClass_Object: return obj->is<PlainObject>() || obj->is<UnboxedPlainObject>();
|
case ESClass_Object: return obj->is<PlainObject>();
|
||||||
case ESClass_Array:
|
case ESClass_Array:
|
||||||
case ESClass_IsArray:
|
case ESClass_IsArray:
|
||||||
// There difference between those is only relevant for proxies.
|
// There difference between those is only relevant for proxies.
|
||||||
return obj->is<ArrayObject>() || obj->is<UnboxedArrayObject>();
|
return obj->is<ArrayObject>();
|
||||||
case ESClass_Number: return obj->is<NumberObject>();
|
case ESClass_Number: return obj->is<NumberObject>();
|
||||||
case ESClass_String: return obj->is<StringObject>();
|
case ESClass_String: return obj->is<StringObject>();
|
||||||
case ESClass_Boolean: return obj->is<BooleanObject>();
|
case ESClass_Boolean: return obj->is<BooleanObject>();
|
||||||
|
@ -802,7 +800,7 @@ IsObjectWithClass(const Value& v, ESClassValue classValue, JSContext* cx)
|
||||||
inline bool
|
inline bool
|
||||||
IsArray(HandleObject obj, JSContext* cx)
|
IsArray(HandleObject obj, JSContext* cx)
|
||||||
{
|
{
|
||||||
if (obj->is<ArrayObject>() || obj->is<UnboxedArrayObject>())
|
if (obj->is<ArrayObject>())
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return ObjectClassIs(obj, ESClass_IsArray, cx);
|
return ObjectClassIs(obj, ESClass_IsArray, cx);
|
||||||
|
|
|
@ -143,7 +143,6 @@ static bool enableIon = false;
|
||||||
static bool enableAsmJS = false;
|
static bool enableAsmJS = false;
|
||||||
static bool enableNativeRegExp = false;
|
static bool enableNativeRegExp = false;
|
||||||
static bool enableUnboxedObjects = false;
|
static bool enableUnboxedObjects = false;
|
||||||
static bool enableUnboxedArrays = false;
|
|
||||||
#ifdef JS_GC_ZEAL
|
#ifdef JS_GC_ZEAL
|
||||||
static char gZealStr[128];
|
static char gZealStr[128];
|
||||||
#endif
|
#endif
|
||||||
|
@ -5815,14 +5814,12 @@ SetRuntimeOptions(JSRuntime* rt, const OptionParser& op)
|
||||||
enableAsmJS = !op.getBoolOption("no-asmjs");
|
enableAsmJS = !op.getBoolOption("no-asmjs");
|
||||||
enableNativeRegExp = !op.getBoolOption("no-native-regexp");
|
enableNativeRegExp = !op.getBoolOption("no-native-regexp");
|
||||||
enableUnboxedObjects = op.getBoolOption("unboxed-objects");
|
enableUnboxedObjects = op.getBoolOption("unboxed-objects");
|
||||||
enableUnboxedArrays = op.getBoolOption("unboxed-arrays");
|
|
||||||
|
|
||||||
JS::RuntimeOptionsRef(rt).setBaseline(enableBaseline)
|
JS::RuntimeOptionsRef(rt).setBaseline(enableBaseline)
|
||||||
.setIon(enableIon)
|
.setIon(enableIon)
|
||||||
.setAsmJS(enableAsmJS)
|
.setAsmJS(enableAsmJS)
|
||||||
.setNativeRegExp(enableNativeRegExp)
|
.setNativeRegExp(enableNativeRegExp)
|
||||||
.setUnboxedObjects(enableUnboxedObjects)
|
.setUnboxedObjects(enableUnboxedObjects);
|
||||||
.setUnboxedArrays(enableUnboxedArrays);
|
|
||||||
|
|
||||||
if (const char* str = op.getStringOption("ion-scalar-replacement")) {
|
if (const char* str = op.getStringOption("ion-scalar-replacement")) {
|
||||||
if (strcmp(str, "on") == 0)
|
if (strcmp(str, "on") == 0)
|
||||||
|
@ -6027,8 +6024,7 @@ SetWorkerRuntimeOptions(JSRuntime* rt)
|
||||||
.setIon(enableIon)
|
.setIon(enableIon)
|
||||||
.setAsmJS(enableAsmJS)
|
.setAsmJS(enableAsmJS)
|
||||||
.setNativeRegExp(enableNativeRegExp)
|
.setNativeRegExp(enableNativeRegExp)
|
||||||
.setUnboxedObjects(enableUnboxedObjects)
|
.setUnboxedObjects(enableUnboxedObjects);
|
||||||
.setUnboxedArrays(enableUnboxedArrays);
|
|
||||||
rt->setOffthreadIonCompilationEnabled(offthreadCompilation);
|
rt->setOffthreadIonCompilationEnabled(offthreadCompilation);
|
||||||
rt->profilingScripts = enableDisassemblyDumps;
|
rt->profilingScripts = enableDisassemblyDumps;
|
||||||
|
|
||||||
|
@ -6170,8 +6166,7 @@ main(int argc, char** argv, char** envp)
|
||||||
|| !op.addBoolOption('\0', "no-ion", "Disable IonMonkey")
|
|| !op.addBoolOption('\0', "no-ion", "Disable IonMonkey")
|
||||||
|| !op.addBoolOption('\0', "no-asmjs", "Disable asm.js compilation")
|
|| !op.addBoolOption('\0', "no-asmjs", "Disable asm.js compilation")
|
||||||
|| !op.addBoolOption('\0', "no-native-regexp", "Disable native regexp compilation")
|
|| !op.addBoolOption('\0', "no-native-regexp", "Disable native regexp compilation")
|
||||||
|| !op.addBoolOption('\0', "unboxed-objects", "Allow creating unboxed plain objects")
|
|| !op.addBoolOption('\0', "unboxed-objects", "Allow creating unboxed objects")
|
||||||
|| !op.addBoolOption('\0', "unboxed-arrays", "Allow creating unboxed arrays")
|
|
||||||
|| !op.addStringOption('\0', "ion-scalar-replacement", "on/off",
|
|| !op.addStringOption('\0', "ion-scalar-replacement", "on/off",
|
||||||
"Scalar Replacement (default: on, off to disable)")
|
"Scalar Replacement (default: on, off to disable)")
|
||||||
|| !op.addStringOption('\0', "ion-gvn", "[mode]",
|
|| !op.addStringOption('\0', "ion-gvn", "[mode]",
|
||||||
|
|
|
@ -38,8 +38,6 @@ ArrayObject::createArrayInternal(ExclusiveContext* cx, gc::AllocKind kind, gc::I
|
||||||
MOZ_ASSERT(group->clasp() == shape->getObjectClass());
|
MOZ_ASSERT(group->clasp() == shape->getObjectClass());
|
||||||
MOZ_ASSERT(group->clasp() == &ArrayObject::class_);
|
MOZ_ASSERT(group->clasp() == &ArrayObject::class_);
|
||||||
MOZ_ASSERT_IF(group->clasp()->finalize, heap == gc::TenuredHeap);
|
MOZ_ASSERT_IF(group->clasp()->finalize, heap == gc::TenuredHeap);
|
||||||
MOZ_ASSERT_IF(group->hasUnanalyzedPreliminaryObjects(),
|
|
||||||
heap == js::gc::TenuredHeap);
|
|
||||||
|
|
||||||
// Arrays can use their fixed slots to store elements, so can't have shapes
|
// Arrays can use their fixed slots to store elements, so can't have shapes
|
||||||
// which allow named properties to be stored in the fixed slots.
|
// which allow named properties to be stored in the fixed slots.
|
||||||
|
|
|
@ -626,7 +626,7 @@ InitArrayElemOperation(JSContext* cx, jsbytecode* pc, HandleObject obj, uint32_t
|
||||||
JSOp op = JSOp(*pc);
|
JSOp op = JSOp(*pc);
|
||||||
MOZ_ASSERT(op == JSOP_INITELEM_ARRAY || op == JSOP_INITELEM_INC);
|
MOZ_ASSERT(op == JSOP_INITELEM_ARRAY || op == JSOP_INITELEM_INC);
|
||||||
|
|
||||||
MOZ_ASSERT(obj->is<ArrayObject>() || obj->is<UnboxedArrayObject>());
|
MOZ_ASSERT(obj->is<ArrayObject>());
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If val is a hole, do not call DefineElement.
|
* If val is a hole, do not call DefineElement.
|
||||||
|
|
|
@ -1914,6 +1914,7 @@ CASE(EnableInterruptsPseudoOpcode)
|
||||||
/* Various 1-byte no-ops. */
|
/* Various 1-byte no-ops. */
|
||||||
CASE(JSOP_NOP)
|
CASE(JSOP_NOP)
|
||||||
CASE(JSOP_UNUSED2)
|
CASE(JSOP_UNUSED2)
|
||||||
|
CASE(JSOP_UNUSED126)
|
||||||
CASE(JSOP_UNUSED148)
|
CASE(JSOP_UNUSED148)
|
||||||
CASE(JSOP_BACKPATCH)
|
CASE(JSOP_BACKPATCH)
|
||||||
CASE(JSOP_UNUSED150)
|
CASE(JSOP_UNUSED150)
|
||||||
|
@ -3499,25 +3500,41 @@ CASE(JSOP_NEWINIT)
|
||||||
{
|
{
|
||||||
uint8_t i = GET_UINT8(REGS.pc);
|
uint8_t i = GET_UINT8(REGS.pc);
|
||||||
MOZ_ASSERT(i == JSProto_Array || i == JSProto_Object);
|
MOZ_ASSERT(i == JSProto_Array || i == JSProto_Object);
|
||||||
|
RootedObject& obj = rootObject0;
|
||||||
|
|
||||||
JSObject* obj;
|
if (i == JSProto_Array) {
|
||||||
if (i == JSProto_Array)
|
NewObjectKind newKind = GenericObject;
|
||||||
obj = NewArrayOperation(cx, script, REGS.pc, 0);
|
if (ObjectGroup::useSingletonForAllocationSite(script, REGS.pc, &ArrayObject::class_))
|
||||||
else
|
newKind = SingletonObject;
|
||||||
|
obj = NewDenseEmptyArray(cx, NullPtr(), newKind);
|
||||||
|
if (!obj || !ObjectGroup::setAllocationSiteObjectGroup(cx, script, REGS.pc, obj,
|
||||||
|
newKind == SingletonObject))
|
||||||
|
{
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
obj = NewObjectOperation(cx, script, REGS.pc);
|
obj = NewObjectOperation(cx, script, REGS.pc);
|
||||||
|
if (!obj)
|
||||||
if (!obj)
|
goto error;
|
||||||
goto error;
|
}
|
||||||
PUSH_OBJECT(*obj);
|
PUSH_OBJECT(*obj);
|
||||||
}
|
}
|
||||||
END_CASE(JSOP_NEWINIT)
|
END_CASE(JSOP_NEWINIT)
|
||||||
|
|
||||||
CASE(JSOP_NEWARRAY)
|
CASE(JSOP_NEWARRAY)
|
||||||
CASE(JSOP_SPREADCALLARRAY)
|
|
||||||
{
|
{
|
||||||
JSObject* obj = NewArrayOperation(cx, script, REGS.pc, GET_UINT24(REGS.pc));
|
unsigned count = GET_UINT24(REGS.pc);
|
||||||
if (!obj)
|
RootedObject& obj = rootObject0;
|
||||||
|
NewObjectKind newKind = GenericObject;
|
||||||
|
if (ObjectGroup::useSingletonForAllocationSite(script, REGS.pc, &ArrayObject::class_))
|
||||||
|
newKind = SingletonObject;
|
||||||
|
obj = NewDenseFullyAllocatedArray(cx, count, NullPtr(), newKind);
|
||||||
|
if (!obj || !ObjectGroup::setAllocationSiteObjectGroup(cx, script, REGS.pc, obj,
|
||||||
|
newKind == SingletonObject))
|
||||||
|
{
|
||||||
goto error;
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
PUSH_OBJECT(*obj);
|
PUSH_OBJECT(*obj);
|
||||||
}
|
}
|
||||||
END_CASE(JSOP_NEWARRAY)
|
END_CASE(JSOP_NEWARRAY)
|
||||||
|
@ -3620,6 +3637,8 @@ CASE(JSOP_INITELEM_ARRAY)
|
||||||
RootedObject& obj = rootObject0;
|
RootedObject& obj = rootObject0;
|
||||||
obj = ®S.sp[-2].toObject();
|
obj = ®S.sp[-2].toObject();
|
||||||
|
|
||||||
|
MOZ_ASSERT(obj->is<ArrayObject>());
|
||||||
|
|
||||||
uint32_t index = GET_UINT24(REGS.pc);
|
uint32_t index = GET_UINT24(REGS.pc);
|
||||||
if (!InitArrayElemOperation(cx, REGS.pc, obj, index, val))
|
if (!InitArrayElemOperation(cx, REGS.pc, obj, index, val))
|
||||||
goto error;
|
goto error;
|
||||||
|
@ -4684,7 +4703,10 @@ js::NewObjectOperationWithTemplate(JSContext* cx, HandleObject templateObject)
|
||||||
|
|
||||||
if (templateObject->group()->maybeUnboxedLayout()) {
|
if (templateObject->group()->maybeUnboxedLayout()) {
|
||||||
RootedObjectGroup group(cx, templateObject->group());
|
RootedObjectGroup group(cx, templateObject->group());
|
||||||
return UnboxedPlainObject::create(cx, group, newKind);
|
JSObject* obj = UnboxedPlainObject::create(cx, group, newKind);
|
||||||
|
if (!obj)
|
||||||
|
return nullptr;
|
||||||
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
JSObject* obj = CopyInitializerObject(cx, templateObject.as<PlainObject>(), newKind);
|
JSObject* obj = CopyInitializerObject(cx, templateObject.as<PlainObject>(), newKind);
|
||||||
|
@ -4695,68 +4717,6 @@ js::NewObjectOperationWithTemplate(JSContext* cx, HandleObject templateObject)
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
JSObject*
|
|
||||||
js::NewArrayOperation(JSContext* cx, HandleScript script, jsbytecode* pc, uint32_t length,
|
|
||||||
NewObjectKind newKind /* = GenericObject */)
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(newKind != SingletonObject);
|
|
||||||
|
|
||||||
RootedObjectGroup group(cx);
|
|
||||||
if (ObjectGroup::useSingletonForAllocationSite(script, pc, JSProto_Array)) {
|
|
||||||
newKind = SingletonObject;
|
|
||||||
} else {
|
|
||||||
group = ObjectGroup::allocationSiteGroup(cx, script, pc, JSProto_Array);
|
|
||||||
if (!group)
|
|
||||||
return nullptr;
|
|
||||||
if (group->maybePreliminaryObjects())
|
|
||||||
group->maybePreliminaryObjects()->maybeAnalyze(cx, group);
|
|
||||||
|
|
||||||
if (group->shouldPreTenure() || group->maybePreliminaryObjects())
|
|
||||||
newKind = TenuredObject;
|
|
||||||
|
|
||||||
if (group->maybeUnboxedLayout())
|
|
||||||
return UnboxedArrayObject::create(cx, group, length, newKind);
|
|
||||||
}
|
|
||||||
|
|
||||||
ArrayObject* obj = NewDenseFullyAllocatedArray(cx, length, NullPtr(), newKind);
|
|
||||||
if (!obj)
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
if (newKind == SingletonObject) {
|
|
||||||
MOZ_ASSERT(obj->isSingleton());
|
|
||||||
} else {
|
|
||||||
obj->setGroup(group);
|
|
||||||
|
|
||||||
if (PreliminaryObjectArray* preliminaryObjects = group->maybePreliminaryObjects())
|
|
||||||
preliminaryObjects->registerNewObject(obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
JSObject*
|
|
||||||
js::NewArrayOperationWithTemplate(JSContext* cx, HandleObject templateObject)
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(!templateObject->isSingleton());
|
|
||||||
|
|
||||||
NewObjectKind newKind = templateObject->group()->shouldPreTenure() ? TenuredObject : GenericObject;
|
|
||||||
|
|
||||||
if (templateObject->is<UnboxedArrayObject>()) {
|
|
||||||
uint32_t length = templateObject->as<UnboxedArrayObject>().length();
|
|
||||||
RootedObjectGroup group(cx, templateObject->group());
|
|
||||||
return UnboxedArrayObject::create(cx, group, length, newKind);
|
|
||||||
}
|
|
||||||
|
|
||||||
ArrayObject* obj = NewDenseFullyAllocatedArray(cx, templateObject->as<ArrayObject>().length(),
|
|
||||||
NullPtr(), newKind);
|
|
||||||
if (!obj)
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
MOZ_ASSERT(obj->lastProperty() == templateObject->as<ArrayObject>().lastProperty());
|
|
||||||
obj->setGroup(templateObject->group());
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
js::ReportUninitializedLexical(JSContext* cx, HandlePropertyName name)
|
js::ReportUninitializedLexical(JSContext* cx, HandlePropertyName name)
|
||||||
{
|
{
|
||||||
|
|
|
@ -445,13 +445,6 @@ NewObjectOperation(JSContext* cx, HandleScript script, jsbytecode* pc,
|
||||||
JSObject*
|
JSObject*
|
||||||
NewObjectOperationWithTemplate(JSContext* cx, HandleObject templateObject);
|
NewObjectOperationWithTemplate(JSContext* cx, HandleObject templateObject);
|
||||||
|
|
||||||
JSObject*
|
|
||||||
NewArrayOperation(JSContext* cx, HandleScript script, jsbytecode* pc, uint32_t length,
|
|
||||||
NewObjectKind newKind = GenericObject);
|
|
||||||
|
|
||||||
JSObject*
|
|
||||||
NewArrayOperationWithTemplate(JSContext* cx, HandleObject templateObject);
|
|
||||||
|
|
||||||
inline bool
|
inline bool
|
||||||
SetConstOperation(JSContext* cx, HandleObject varobj, HandlePropertyName name, HandleValue rval)
|
SetConstOperation(JSContext* cx, HandleObject varobj, HandlePropertyName name, HandleValue rval)
|
||||||
{
|
{
|
||||||
|
|
|
@ -329,11 +329,8 @@ NativeObject::setLastPropertyMakeNonNative(Shape* shape)
|
||||||
MOZ_ASSERT(shape->compartment() == compartment());
|
MOZ_ASSERT(shape->compartment() == compartment());
|
||||||
MOZ_ASSERT(shape->slotSpan() == 0);
|
MOZ_ASSERT(shape->slotSpan() == 0);
|
||||||
MOZ_ASSERT(shape->numFixedSlots() == 0);
|
MOZ_ASSERT(shape->numFixedSlots() == 0);
|
||||||
|
MOZ_ASSERT(!hasDynamicElements());
|
||||||
if (hasDynamicElements())
|
MOZ_ASSERT(!hasDynamicSlots());
|
||||||
js_free(getElementsHeader());
|
|
||||||
if (hasDynamicSlots())
|
|
||||||
js_free(slots_);
|
|
||||||
|
|
||||||
shape_ = shape;
|
shape_ = shape;
|
||||||
}
|
}
|
||||||
|
@ -714,9 +711,6 @@ ReallocateElements(ExclusiveContext* cx, JSObject* obj, ObjectElements* oldHeade
|
||||||
// exceptional resizings will at most triple the capacity, as opposed to the
|
// exceptional resizings will at most triple the capacity, as opposed to the
|
||||||
// usual doubling.
|
// usual doubling.
|
||||||
//
|
//
|
||||||
// Note: the structure and behavior of this method follow along with
|
|
||||||
// UnboxedArrayObject::chooseCapacityIndex. Changes to the allocation strategy
|
|
||||||
// in one should generally be matched by the other.
|
|
||||||
/* static */ uint32_t
|
/* static */ uint32_t
|
||||||
NativeObject::goodAllocated(uint32_t reqAllocated, uint32_t length = 0)
|
NativeObject::goodAllocated(uint32_t reqAllocated, uint32_t length = 0)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1161,15 +1161,6 @@ ObjectGroup::allocationSiteGroup(JSContext* cx, JSScript* script, jsbytecode* pc
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (JSOp(*pc) == JSOP_NEWARRAY) {
|
|
||||||
PreliminaryObjectArrayWithTemplate* preliminaryObjects =
|
|
||||||
cx->new_<PreliminaryObjectArrayWithTemplate>(nullptr);
|
|
||||||
if (preliminaryObjects)
|
|
||||||
res->setPreliminaryObjects(preliminaryObjects);
|
|
||||||
else
|
|
||||||
cx->recoverFromOutOfMemory();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!table->add(p, key, res))
|
if (!table->add(p, key, res))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
|
|
|
@ -833,8 +833,8 @@
|
||||||
* This opcode takes the kind of initializer (JSProto_Array or
|
* This opcode takes the kind of initializer (JSProto_Array or
|
||||||
* JSProto_Object).
|
* JSProto_Object).
|
||||||
*
|
*
|
||||||
* This opcode has three extra bytes so it can be exchanged with
|
* This opcode has an extra byte so it can be exchanged with JSOP_NEWOBJECT
|
||||||
* JSOP_NEWOBJECT during emit.
|
* during emit.
|
||||||
* Category: Literals
|
* Category: Literals
|
||||||
* Type: Object
|
* Type: Object
|
||||||
* Operands: uint8_t kind (, uint24_t extra)
|
* Operands: uint8_t kind (, uint24_t extra)
|
||||||
|
@ -1272,18 +1272,7 @@
|
||||||
* Stack: receiver, obj, propval => obj[propval]
|
* Stack: receiver, obj, propval => obj[propval]
|
||||||
*/ \
|
*/ \
|
||||||
macro(JSOP_GETELEM_SUPER, 125, "getelem-super", NULL, 1, 3, 1, JOF_BYTE |JOF_ELEM|JOF_LEFTASSOC) \
|
macro(JSOP_GETELEM_SUPER, 125, "getelem-super", NULL, 1, 3, 1, JOF_BYTE |JOF_ELEM|JOF_LEFTASSOC) \
|
||||||
/*
|
macro(JSOP_UNUSED126, 126, "unused126", NULL, 1, 0, 0, JOF_BYTE) \
|
||||||
* Pushes newly created array for a spread call onto the stack. This has
|
|
||||||
* the same semantics as JSOP_NEWARRAY, but is distinguished to avoid
|
|
||||||
* using unboxed arrays in spread calls, which would make compiling spread
|
|
||||||
* calls in baseline more complex.
|
|
||||||
*
|
|
||||||
* Category: Literals
|
|
||||||
* Type: Array
|
|
||||||
* Operands: uint24_t length
|
|
||||||
* Stack: => obj
|
|
||||||
*/ \
|
|
||||||
macro(JSOP_SPREADCALLARRAY, 126, "spreadcallarray", NULL, 4, 0, 1, JOF_UINT24) \
|
|
||||||
\
|
\
|
||||||
/*
|
/*
|
||||||
* Defines the given function on the current scope.
|
* Defines the given function on the current scope.
|
||||||
|
|
|
@ -52,8 +52,6 @@ NewObjectCache::newObjectFromHit(JSContext* cx, EntryIndex entryIndex, gc::Initi
|
||||||
// on the templateObj, which is not a GC thing and can't use runtimeFromAnyThread.
|
// on the templateObj, which is not a GC thing and can't use runtimeFromAnyThread.
|
||||||
ObjectGroup* group = templateObj->group_;
|
ObjectGroup* group = templateObj->group_;
|
||||||
|
|
||||||
MOZ_ASSERT(!group->hasUnanalyzedPreliminaryObjects());
|
|
||||||
|
|
||||||
if (group->shouldPreTenure())
|
if (group->shouldPreTenure())
|
||||||
heap = gc::TenuredHeap;
|
heap = gc::TenuredHeap;
|
||||||
|
|
||||||
|
|
|
@ -2381,8 +2381,6 @@ TemporaryTypeSet::propertyNeedsBarrier(CompilerConstraintList* constraints, jsid
|
||||||
bool
|
bool
|
||||||
js::ClassCanHaveExtraProperties(const Class* clasp)
|
js::ClassCanHaveExtraProperties(const Class* clasp)
|
||||||
{
|
{
|
||||||
if (clasp == &UnboxedPlainObject::class_ || clasp == &UnboxedArrayObject::class_)
|
|
||||||
return false;
|
|
||||||
return clasp->resolve
|
return clasp->resolve
|
||||||
|| clasp->ops.lookupProperty
|
|| clasp->ops.lookupProperty
|
||||||
|| clasp->ops.getProperty
|
|| clasp->ops.getProperty
|
||||||
|
@ -3339,19 +3337,16 @@ PreliminaryObjectArray::sweep()
|
||||||
void
|
void
|
||||||
PreliminaryObjectArrayWithTemplate::trace(JSTracer* trc)
|
PreliminaryObjectArrayWithTemplate::trace(JSTracer* trc)
|
||||||
{
|
{
|
||||||
if (shape_)
|
TraceEdge(trc, &shape_, "PreliminaryObjectArrayWithTemplate_shape");
|
||||||
TraceEdge(trc, &shape_, "PreliminaryObjectArrayWithTemplate_shape");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* static */ void
|
/* static */ void
|
||||||
PreliminaryObjectArrayWithTemplate::writeBarrierPre(PreliminaryObjectArrayWithTemplate* objects)
|
PreliminaryObjectArrayWithTemplate::writeBarrierPre(PreliminaryObjectArrayWithTemplate* objects)
|
||||||
{
|
{
|
||||||
Shape* shape = objects->shape();
|
if (!objects->shape()->runtimeFromAnyThread()->needsIncrementalBarrier())
|
||||||
|
|
||||||
if (!shape || !shape->runtimeFromAnyThread()->needsIncrementalBarrier())
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
JS::Zone* zone = shape->zoneFromAnyThread();
|
JS::Zone* zone = objects->shape()->zoneFromAnyThread();
|
||||||
if (zone->needsIncrementalBarrier())
|
if (zone->needsIncrementalBarrier())
|
||||||
objects->trace(zone->barrierTracer());
|
objects->trace(zone->barrierTracer());
|
||||||
}
|
}
|
||||||
|
@ -3411,37 +3406,33 @@ PreliminaryObjectArrayWithTemplate::maybeAnalyze(ExclusiveContext* cx, ObjectGro
|
||||||
ScopedJSDeletePtr<PreliminaryObjectArrayWithTemplate> preliminaryObjects(this);
|
ScopedJSDeletePtr<PreliminaryObjectArrayWithTemplate> preliminaryObjects(this);
|
||||||
group->detachPreliminaryObjects();
|
group->detachPreliminaryObjects();
|
||||||
|
|
||||||
if (shape()) {
|
MOZ_ASSERT(shape()->slotSpan() != 0);
|
||||||
MOZ_ASSERT(shape()->slotSpan() != 0);
|
MOZ_ASSERT(OnlyHasDataProperties(shape()));
|
||||||
MOZ_ASSERT(OnlyHasDataProperties(shape()));
|
|
||||||
|
|
||||||
// Make sure all the preliminary objects reflect the properties originally
|
// Make sure all the preliminary objects reflect the properties originally
|
||||||
// in the template object.
|
// in the template object.
|
||||||
for (size_t i = 0; i < PreliminaryObjectArray::COUNT; i++) {
|
for (size_t i = 0; i < PreliminaryObjectArray::COUNT; i++) {
|
||||||
JSObject* objBase = preliminaryObjects->get(i);
|
JSObject* objBase = preliminaryObjects->get(i);
|
||||||
if (!objBase)
|
if (!objBase)
|
||||||
continue;
|
continue;
|
||||||
PlainObject* obj = &objBase->as<PlainObject>();
|
PlainObject* obj = &objBase->as<PlainObject>();
|
||||||
|
|
||||||
if (obj->inDictionaryMode() || !OnlyHasDataProperties(obj->lastProperty()))
|
if (obj->inDictionaryMode() || !OnlyHasDataProperties(obj->lastProperty()))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (CommonPrefix(obj->lastProperty(), shape()) != shape())
|
if (CommonPrefix(obj->lastProperty(), shape()) != shape())
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TryConvertToUnboxedLayout(cx, shape(), group, preliminaryObjects);
|
TryConvertToUnboxedLayout(cx, shape(), group, preliminaryObjects);
|
||||||
if (group->maybeUnboxedLayout())
|
if (group->maybeUnboxedLayout())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (shape()) {
|
// We weren't able to use an unboxed layout, but since the preliminary
|
||||||
// We weren't able to use an unboxed layout, but since the preliminary
|
// still reflect the template object's properties, and all objects in the
|
||||||
// still reflect the template object's properties, and all objects in the
|
// future will be created with those properties, the properties can be
|
||||||
// future will be created with those properties, the properties can be
|
// marked as definite for objects in the group.
|
||||||
// marked as definite for objects in the group.
|
group->addDefiniteProperties(cx, shape());
|
||||||
group->addDefiniteProperties(cx, shape());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -35,7 +35,7 @@ UnboxedTypeNeedsPreBarrier(JSValueType type)
|
||||||
return type == JSVAL_TYPE_STRING || type == JSVAL_TYPE_OBJECT;
|
return type == JSVAL_TYPE_STRING || type == JSVAL_TYPE_OBJECT;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Class tracking information specific to unboxed objects.
|
// Class describing the layout of an UnboxedPlainObject.
|
||||||
class UnboxedLayout : public mozilla::LinkedListElement<UnboxedLayout>
|
class UnboxedLayout : public mozilla::LinkedListElement<UnboxedLayout>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -52,14 +52,6 @@ class UnboxedLayout : public mozilla::LinkedListElement<UnboxedLayout>
|
||||||
typedef Vector<Property, 0, SystemAllocPolicy> PropertyVector;
|
typedef Vector<Property, 0, SystemAllocPolicy> PropertyVector;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// If objects in this group have ever been converted to native objects,
|
|
||||||
// these store the corresponding native group and initial shape for such
|
|
||||||
// objects. Type information for this object is reflected in nativeGroup.
|
|
||||||
HeapPtrObjectGroup nativeGroup_;
|
|
||||||
HeapPtrShape nativeShape_;
|
|
||||||
|
|
||||||
// The following members are only used for unboxed plain objects.
|
|
||||||
|
|
||||||
// All properties on objects with this layout, in enumeration order.
|
// All properties on objects with this layout, in enumeration order.
|
||||||
PropertyVector properties_;
|
PropertyVector properties_;
|
||||||
|
|
||||||
|
@ -73,6 +65,12 @@ class UnboxedLayout : public mozilla::LinkedListElement<UnboxedLayout>
|
||||||
// structure as the trace list on a TypeDescr.
|
// structure as the trace list on a TypeDescr.
|
||||||
int32_t* traceList_;
|
int32_t* traceList_;
|
||||||
|
|
||||||
|
// If objects in this group have ever been converted to native objects,
|
||||||
|
// these store the corresponding native group and initial shape for such
|
||||||
|
// objects. Type information for this object is reflected in nativeGroup.
|
||||||
|
HeapPtrObjectGroup nativeGroup_;
|
||||||
|
HeapPtrShape nativeShape_;
|
||||||
|
|
||||||
// If nativeGroup is set and this object originally had a TypeNewScript,
|
// If nativeGroup is set and this object originally had a TypeNewScript,
|
||||||
// this points to the default 'new' group which replaced this one (and
|
// this points to the default 'new' group which replaced this one (and
|
||||||
// which might itself have been cleared since). This link is only needed to
|
// which might itself have been cleared since). This link is only needed to
|
||||||
|
@ -86,25 +84,13 @@ class UnboxedLayout : public mozilla::LinkedListElement<UnboxedLayout>
|
||||||
// from an array of values.
|
// from an array of values.
|
||||||
HeapPtrJitCode constructorCode_;
|
HeapPtrJitCode constructorCode_;
|
||||||
|
|
||||||
// The following members are only used for unboxed arrays.
|
|
||||||
|
|
||||||
// The type of array elements.
|
|
||||||
JSValueType elementType_;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
UnboxedLayout()
|
UnboxedLayout(const PropertyVector& properties, size_t size)
|
||||||
: nativeGroup_(nullptr), nativeShape_(nullptr), size_(0), newScript_(nullptr),
|
: size_(size), newScript_(nullptr), traceList_(nullptr),
|
||||||
traceList_(nullptr), replacementNewGroup_(nullptr), constructorCode_(nullptr),
|
nativeGroup_(nullptr), nativeShape_(nullptr), replacementNewGroup_(nullptr),
|
||||||
elementType_(JSVAL_TYPE_MAGIC)
|
constructorCode_(nullptr)
|
||||||
{}
|
{
|
||||||
|
properties_.appendAll(properties);
|
||||||
bool initProperties(const PropertyVector& properties, size_t size) {
|
|
||||||
size_ = size;
|
|
||||||
return properties_.appendAll(properties);
|
|
||||||
}
|
|
||||||
|
|
||||||
void initArray(JSValueType elementType) {
|
|
||||||
elementType_ = elementType;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
~UnboxedLayout() {
|
~UnboxedLayout() {
|
||||||
|
@ -112,10 +98,6 @@ class UnboxedLayout : public mozilla::LinkedListElement<UnboxedLayout>
|
||||||
js_free(traceList_);
|
js_free(traceList_);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isArray() {
|
|
||||||
return elementType_ != JSVAL_TYPE_MAGIC;
|
|
||||||
}
|
|
||||||
|
|
||||||
void detachFromCompartment();
|
void detachFromCompartment();
|
||||||
|
|
||||||
const PropertyVector& properties() const {
|
const PropertyVector& properties() const {
|
||||||
|
@ -170,10 +152,6 @@ class UnboxedLayout : public mozilla::LinkedListElement<UnboxedLayout>
|
||||||
constructorCode_ = code;
|
constructorCode_ = code;
|
||||||
}
|
}
|
||||||
|
|
||||||
JSValueType elementType() const {
|
|
||||||
return elementType_;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline gc::AllocKind getAllocKind() const;
|
inline gc::AllocKind getAllocKind() const;
|
||||||
|
|
||||||
void trace(JSTracer* trc);
|
void trace(JSTracer* trc);
|
||||||
|
@ -273,9 +251,6 @@ class UnboxedPlainObject : public JSObject
|
||||||
static JSObject* createWithProperties(ExclusiveContext* cx, HandleObjectGroup group,
|
static JSObject* createWithProperties(ExclusiveContext* cx, HandleObjectGroup group,
|
||||||
NewObjectKind newKind, IdValuePair* properties);
|
NewObjectKind newKind, IdValuePair* properties);
|
||||||
|
|
||||||
void fillAfterConvert(ExclusiveContext* cx,
|
|
||||||
const AutoValueVector& values, size_t* valueCursor);
|
|
||||||
|
|
||||||
static void trace(JSTracer* trc, JSObject* object);
|
static void trace(JSTracer* trc, JSObject* object);
|
||||||
|
|
||||||
static size_t offsetOfExpando() {
|
static size_t offsetOfExpando() {
|
||||||
|
@ -297,177 +272,9 @@ TryConvertToUnboxedLayout(ExclusiveContext* cx, Shape* templateShape,
|
||||||
inline gc::AllocKind
|
inline gc::AllocKind
|
||||||
UnboxedLayout::getAllocKind() const
|
UnboxedLayout::getAllocKind() const
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(size());
|
|
||||||
return gc::GetGCObjectKindForBytes(UnboxedPlainObject::offsetOfData() + size());
|
return gc::GetGCObjectKindForBytes(UnboxedPlainObject::offsetOfData() + size());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Class for an array object using an unboxed representation.
|
|
||||||
class UnboxedArrayObject : public JSObject
|
|
||||||
{
|
|
||||||
// Elements pointer for the object.
|
|
||||||
uint8_t* elements_;
|
|
||||||
|
|
||||||
// The nominal array length. This always fits in an int32_t.
|
|
||||||
uint32_t length_;
|
|
||||||
|
|
||||||
// Value indicating the allocated capacity and initialized length of the
|
|
||||||
// array. The top CapacityBits bits are an index into CapacityArray, which
|
|
||||||
// indicates the elements capacity. The low InitializedLengthBits store the
|
|
||||||
// initialized length of the array.
|
|
||||||
uint32_t capacityIndexAndInitializedLength_;
|
|
||||||
|
|
||||||
// If the elements are inline, they will point here.
|
|
||||||
uint8_t inlineElements_[1];
|
|
||||||
|
|
||||||
public:
|
|
||||||
static const uint32_t CapacityBits = 6;
|
|
||||||
static const uint32_t CapacityShift = 26;
|
|
||||||
|
|
||||||
static const uint32_t CapacityMask = uint32_t(-1) << CapacityShift;
|
|
||||||
static const uint32_t InitializedLengthMask = (1 << CapacityShift) - 1;
|
|
||||||
|
|
||||||
static const uint32_t MaximumCapacity = InitializedLengthMask;
|
|
||||||
static const uint32_t MinimumDynamicCapacity = 8;
|
|
||||||
|
|
||||||
static const uint32_t CapacityArray[];
|
|
||||||
|
|
||||||
// Capacity index which indicates the array's length is also its capacity.
|
|
||||||
static const uint32_t CapacityMatchesLengthIndex = 0;
|
|
||||||
|
|
||||||
private:
|
|
||||||
static inline uint32_t computeCapacity(uint32_t index, uint32_t length) {
|
|
||||||
if (index == CapacityMatchesLengthIndex)
|
|
||||||
return length;
|
|
||||||
return CapacityArray[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint32_t chooseCapacityIndex(uint32_t capacity, uint32_t length);
|
|
||||||
static uint32_t exactCapacityIndex(uint32_t capacity);
|
|
||||||
|
|
||||||
public:
|
|
||||||
static const Class class_;
|
|
||||||
|
|
||||||
static bool obj_lookupProperty(JSContext* cx, HandleObject obj,
|
|
||||||
HandleId id, MutableHandleObject objp,
|
|
||||||
MutableHandleShape propp);
|
|
||||||
|
|
||||||
static bool obj_defineProperty(JSContext* cx, HandleObject obj, HandleId id,
|
|
||||||
Handle<JSPropertyDescriptor> desc,
|
|
||||||
ObjectOpResult& result);
|
|
||||||
|
|
||||||
static bool obj_hasProperty(JSContext* cx, HandleObject obj, HandleId id, bool* foundp);
|
|
||||||
|
|
||||||
static bool obj_getProperty(JSContext* cx, HandleObject obj, HandleObject receiver,
|
|
||||||
HandleId id, MutableHandleValue vp);
|
|
||||||
|
|
||||||
static bool obj_setProperty(JSContext* cx, HandleObject obj, HandleId id, HandleValue v,
|
|
||||||
HandleValue receiver, ObjectOpResult& result);
|
|
||||||
|
|
||||||
static bool obj_getOwnPropertyDescriptor(JSContext* cx, HandleObject obj, HandleId id,
|
|
||||||
MutableHandle<JSPropertyDescriptor> desc);
|
|
||||||
|
|
||||||
static bool obj_deleteProperty(JSContext* cx, HandleObject obj, HandleId id,
|
|
||||||
ObjectOpResult& result);
|
|
||||||
|
|
||||||
static bool obj_enumerate(JSContext* cx, HandleObject obj, AutoIdVector& properties);
|
|
||||||
static bool obj_watch(JSContext* cx, HandleObject obj, HandleId id, HandleObject callable);
|
|
||||||
|
|
||||||
const UnboxedLayout& layout() const {
|
|
||||||
return group()->unboxedLayout();
|
|
||||||
}
|
|
||||||
|
|
||||||
const UnboxedLayout& layoutDontCheckGeneration() const {
|
|
||||||
return group()->unboxedLayoutDontCheckGeneration();
|
|
||||||
}
|
|
||||||
|
|
||||||
JSValueType elementType() const {
|
|
||||||
return layoutDontCheckGeneration().elementType();
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t elementSize() const {
|
|
||||||
return UnboxedTypeSize(elementType());
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool convertToNative(JSContext* cx, JSObject* obj);
|
|
||||||
static UnboxedArrayObject* create(ExclusiveContext* cx, HandleObjectGroup group,
|
|
||||||
uint32_t length, NewObjectKind newKind);
|
|
||||||
|
|
||||||
void fillAfterConvert(ExclusiveContext* cx,
|
|
||||||
const AutoValueVector& values, size_t* valueCursor);
|
|
||||||
|
|
||||||
static void trace(JSTracer* trc, JSObject* object);
|
|
||||||
static void objectMoved(JSObject* obj, const JSObject* old);
|
|
||||||
static void finalize(FreeOp* fop, JSObject* obj);
|
|
||||||
|
|
||||||
uint8_t* elements() {
|
|
||||||
return elements_;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool hasInlineElements() const {
|
|
||||||
return elements_ == &inlineElements_[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t length() const {
|
|
||||||
return length_;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t initializedLength() const {
|
|
||||||
return capacityIndexAndInitializedLength_ & InitializedLengthMask;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t capacityIndex() const {
|
|
||||||
return (capacityIndexAndInitializedLength_ & CapacityMask) >> CapacityShift;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t capacity() const {
|
|
||||||
return computeCapacity(capacityIndex(), length());
|
|
||||||
}
|
|
||||||
|
|
||||||
bool containsProperty(JSContext* cx, jsid id);
|
|
||||||
|
|
||||||
bool setElement(ExclusiveContext* cx, size_t index, const Value& v);
|
|
||||||
bool initElement(ExclusiveContext* cx, size_t index, const Value& v);
|
|
||||||
Value getElement(size_t index);
|
|
||||||
|
|
||||||
bool growElements(ExclusiveContext* cx, size_t cap);
|
|
||||||
void shrinkElements(ExclusiveContext* cx, size_t cap);
|
|
||||||
|
|
||||||
static uint32_t offsetOfElements() {
|
|
||||||
return offsetof(UnboxedArrayObject, elements_);
|
|
||||||
}
|
|
||||||
static uint32_t offsetOfLength() {
|
|
||||||
return offsetof(UnboxedArrayObject, length_);
|
|
||||||
}
|
|
||||||
static uint32_t offsetOfCapacityIndexAndInitializedLength() {
|
|
||||||
return offsetof(UnboxedArrayObject, capacityIndexAndInitializedLength_);
|
|
||||||
}
|
|
||||||
static uint32_t offsetOfInlineElements() {
|
|
||||||
return offsetof(UnboxedArrayObject, inlineElements_);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
void setInlineElements() {
|
|
||||||
elements_ = &inlineElements_[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
void setLength(uint32_t len) {
|
|
||||||
MOZ_ASSERT(len <= INT32_MAX);
|
|
||||||
length_ = len;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setInitializedLength(uint32_t initlen) {
|
|
||||||
MOZ_ASSERT(initlen <= InitializedLengthMask);
|
|
||||||
capacityIndexAndInitializedLength_ =
|
|
||||||
(capacityIndexAndInitializedLength_ & CapacityMask) | initlen;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setCapacityIndex(uint32_t index) {
|
|
||||||
MOZ_ASSERT(index <= (CapacityMask >> CapacityShift));
|
|
||||||
capacityIndexAndInitializedLength_ =
|
|
||||||
(index << CapacityShift) | initializedLength();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace js
|
} // namespace js
|
||||||
|
|
||||||
#endif /* vm_UnboxedObject_h */
|
#endif /* vm_UnboxedObject_h */
|
||||||
|
|
|
@ -29,7 +29,7 @@ namespace js {
|
||||||
*
|
*
|
||||||
* https://developer.mozilla.org/en-US/docs/SpiderMonkey/Internals/Bytecode
|
* https://developer.mozilla.org/en-US/docs/SpiderMonkey/Internals/Bytecode
|
||||||
*/
|
*/
|
||||||
static const uint32_t XDR_BYTECODE_VERSION_SUBTRAHEND = 282;
|
static const uint32_t XDR_BYTECODE_VERSION_SUBTRAHEND = 281;
|
||||||
static const uint32_t XDR_BYTECODE_VERSION =
|
static const uint32_t XDR_BYTECODE_VERSION =
|
||||||
uint32_t(0xb973c0de - XDR_BYTECODE_VERSION_SUBTRAHEND);
|
uint32_t(0xb973c0de - XDR_BYTECODE_VERSION_SUBTRAHEND);
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче