mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-05 16:46:26 +00:00
Bug 848743 - Change SetElem_DenseAdd stub to check all shapes on the proto chain. r=djvj
This commit is contained in:
parent
79ce500da2
commit
2aaefce85a
@ -805,8 +805,7 @@ InitFromBailout(JSContext *cx, HandleScript caller, jsbytecode *callerPC,
|
||||
// Calculate and write out return address.
|
||||
// The icEntry in question MUST have a ICCall_Fallback as its fallback stub.
|
||||
ICEntry &icEntry = baselineScript->icEntryFromPCOffset(pcOff);
|
||||
ICFallbackStub *fallbackStub = icEntry.firstStub()->getChainFallback();
|
||||
JS_ASSERT(fallbackStub->isCall_Fallback());
|
||||
JS_ASSERT(icEntry.firstStub()->getChainFallback()->isCall_Fallback());
|
||||
if (!builder.writePtr(baselineScript->returnAddressForIC(icEntry), "ReturnAddr"))
|
||||
return false;
|
||||
|
||||
|
@ -212,8 +212,17 @@ ICStub::trace(JSTracer *trc)
|
||||
ICSetElem_DenseAdd *setElemStub = toSetElem_DenseAdd();
|
||||
MarkShape(trc, &setElemStub->shape(), "baseline-getelem-denseadd-shape");
|
||||
MarkTypeObject(trc, &setElemStub->type(), "baseline-setelem-denseadd-type");
|
||||
MarkObject(trc, &setElemStub->lastProto(), "baseline-setelem-denseadd-lastproto");
|
||||
MarkShape(trc, &setElemStub->lastProtoShape(), "baseline-setelem-denseadd-lastprotoshape");
|
||||
|
||||
JS_STATIC_ASSERT(ICSetElem_DenseAdd::MAX_PROTO_CHAIN_DEPTH == 4);
|
||||
|
||||
switch (setElemStub->protoChainDepth()) {
|
||||
case 0: setElemStub->toImpl<0>()->traceProtoShapes(trc); break;
|
||||
case 1: setElemStub->toImpl<1>()->traceProtoShapes(trc); break;
|
||||
case 2: setElemStub->toImpl<2>()->traceProtoShapes(trc); break;
|
||||
case 3: setElemStub->toImpl<3>()->traceProtoShapes(trc); break;
|
||||
case 4: setElemStub->toImpl<4>()->traceProtoShapes(trc); break;
|
||||
default: JS_NOT_REACHED("Invalid proto stub.");
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ICStub::SetElem_TypedArray: {
|
||||
@ -896,7 +905,7 @@ DoProfilerFallback(JSContext *cx, BaselineFrame *frame, ICProfiler_Fallback *stu
|
||||
{
|
||||
RootedScript script(cx, frame->script());
|
||||
RootedFunction func(cx, frame->maybeFun());
|
||||
ICEntry *icEntry = stub->icEntry();
|
||||
mozilla::DebugOnly<ICEntry *> icEntry = stub->icEntry();
|
||||
|
||||
FallbackICSpew(cx, stub, "Profiler");
|
||||
|
||||
@ -3593,13 +3602,13 @@ RemoveExistingTypedArraySetElemStub(JSContext *cx, ICSetElem_Fallback *stub, Han
|
||||
static bool
|
||||
CanOptimizeDenseSetElem(JSContext *cx, HandleObject obj, uint32_t index,
|
||||
HandleShape oldShape, uint32_t oldCapacity, uint32_t oldInitLength,
|
||||
bool *isAddingCaseOut, MutableHandleObject lastProtoOut)
|
||||
bool *isAddingCaseOut, size_t *protoDepthOut)
|
||||
{
|
||||
uint32_t initLength = obj->getDenseInitializedLength();
|
||||
uint32_t capacity = obj->getDenseCapacity();
|
||||
|
||||
*isAddingCaseOut = false;
|
||||
lastProtoOut.set(NULL);
|
||||
*protoDepthOut = 0;
|
||||
|
||||
// Some initial sanity checks.
|
||||
if (initLength < oldInitLength || capacity < oldCapacity)
|
||||
@ -3640,7 +3649,6 @@ CanOptimizeDenseSetElem(JSContext *cx, HandleObject obj, uint32_t index,
|
||||
// which is a proxy, that handles a particular integer write.
|
||||
// Scan the prototype and shape chain to make sure that this is not the case.
|
||||
RootedObject curObj(cx, obj);
|
||||
RootedObject lastObj(cx);
|
||||
while (curObj) {
|
||||
// Ensure object is native.
|
||||
if (!curObj->isNative())
|
||||
@ -3650,14 +3658,15 @@ CanOptimizeDenseSetElem(JSContext *cx, HandleObject obj, uint32_t index,
|
||||
if (curObj->isIndexed())
|
||||
return false;
|
||||
|
||||
if (!curObj->getProto())
|
||||
lastObj = curObj;
|
||||
|
||||
curObj = curObj->getProto();
|
||||
if (curObj)
|
||||
++*protoDepthOut;
|
||||
}
|
||||
|
||||
if (*protoDepthOut > ICSetProp_NativeAdd::MAX_PROTO_CHAIN_DEPTH)
|
||||
return false;
|
||||
|
||||
*isAddingCaseOut = true;
|
||||
lastProtoOut.set(lastObj);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -3695,7 +3704,7 @@ DoSetElemFallback(JSContext *cx, BaselineFrame *frame, ICSetElem_Fallback *stub,
|
||||
if (!InitElemOperation(cx, obj, &nindex, rhs))
|
||||
return false;
|
||||
} else if (op == JSOP_INITELEM_ARRAY) {
|
||||
JS_ASSERT(index.toInt32() == GET_UINT24(pc));
|
||||
JS_ASSERT(uint32_t(index.toInt32()) == GET_UINT24(pc));
|
||||
if (!InitArrayElemOperation(cx, pc, obj, index.toInt32(), rhs))
|
||||
return false;
|
||||
} else {
|
||||
@ -3721,21 +3730,20 @@ DoSetElemFallback(JSContext *cx, BaselineFrame *frame, ICSetElem_Fallback *stub,
|
||||
JS_ASSERT(!obj->isTypedArray());
|
||||
|
||||
bool addingCase;
|
||||
RootedObject lastProto(cx);
|
||||
size_t protoDepth;
|
||||
|
||||
if (CanOptimizeDenseSetElem(cx, obj, index.toInt32(), oldShape, oldCapacity, oldInitLength,
|
||||
&addingCase, &lastProto))
|
||||
&addingCase, &protoDepth))
|
||||
{
|
||||
RootedTypeObject type(cx, obj->getType(cx));
|
||||
RootedShape shape(cx, obj->lastProperty());
|
||||
|
||||
if (addingCase && !DenseSetElemStubExists(cx, ICStub::SetElem_DenseAdd, stub, obj)) {
|
||||
RootedShape lastProtoShape(cx, lastProto->lastProperty());
|
||||
IonSpew(IonSpew_BaselineIC,
|
||||
" Generating SetElem_DenseAdd stub "
|
||||
"(shape=%p, type=%p, lastProto=%p, lastProtoShape=%p)",
|
||||
obj->lastProperty(), type.get(), lastProto.get(), lastProtoShape.get());
|
||||
ICSetElem_DenseAdd::Compiler compiler(cx, shape, type, lastProto, lastProtoShape);
|
||||
"(shape=%p, type=%p, protoDepth=%u)",
|
||||
obj->lastProperty(), type.get(), protoDepth);
|
||||
ICSetElemDenseAddCompiler compiler(cx, obj, protoDepth);
|
||||
ICUpdatedStub *denseStub = compiler.getStub(compiler.getStubSpace(script));
|
||||
if (!denseStub)
|
||||
return false;
|
||||
@ -3850,7 +3858,7 @@ ICSetElem_Dense::Compiler::generateStubCode(MacroAssembler &masm)
|
||||
GeneralRegisterSet regs(availableGeneralRegs(2));
|
||||
Register scratchReg = regs.takeAny();
|
||||
|
||||
// Unbox R0 and guard it's a dense array.
|
||||
// Unbox R0 and guard on its shape.
|
||||
Register obj = masm.extractObject(R0, ExtractTemp0);
|
||||
masm.loadPtr(Address(BaselineStubReg, ICSetElem_Dense::offsetOfShape()), scratchReg);
|
||||
masm.branchTestObjShape(Assembler::NotEqual, obj, scratchReg, &failure);
|
||||
@ -3931,12 +3939,49 @@ ICSetElem_Dense::Compiler::generateStubCode(MacroAssembler &masm)
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
GetProtoShapes(JSObject *obj, size_t protoChainDepth, AutoShapeVector *protoShapes)
|
||||
{
|
||||
JS_ASSERT(protoShapes->empty());
|
||||
JSObject *curProto = obj->getProto();
|
||||
for (size_t i = 0; i < protoChainDepth; i++) {
|
||||
if (!protoShapes->append(curProto->lastProperty()))
|
||||
return false;
|
||||
curProto = curProto->getProto();
|
||||
}
|
||||
JS_ASSERT(!curProto);
|
||||
return true;
|
||||
}
|
||||
|
||||
//
|
||||
// SetElem_DenseAdd
|
||||
//
|
||||
|
||||
ICUpdatedStub *
|
||||
ICSetElemDenseAddCompiler::getStub(ICStubSpace *space)
|
||||
{
|
||||
AutoShapeVector protoShapes(cx);
|
||||
if (!GetProtoShapes(obj_, protoChainDepth_, &protoShapes))
|
||||
return NULL;
|
||||
|
||||
JS_STATIC_ASSERT(ICSetElem_DenseAdd::MAX_PROTO_CHAIN_DEPTH == 4);
|
||||
|
||||
ICUpdatedStub *stub = NULL;
|
||||
switch (protoChainDepth_) {
|
||||
case 0: stub = getStubSpecific<0>(space, &protoShapes); break;
|
||||
case 1: stub = getStubSpecific<1>(space, &protoShapes); break;
|
||||
case 2: stub = getStubSpecific<2>(space, &protoShapes); break;
|
||||
case 3: stub = getStubSpecific<3>(space, &protoShapes); break;
|
||||
case 4: stub = getStubSpecific<4>(space, &protoShapes); break;
|
||||
default: JS_NOT_REACHED("ProtoChainDepth too high.");
|
||||
}
|
||||
if (!stub || !stub->initUpdatingChain(cx, space))
|
||||
return NULL;
|
||||
return stub;
|
||||
}
|
||||
|
||||
bool
|
||||
ICSetElem_DenseAdd::Compiler::generateStubCode(MacroAssembler &masm)
|
||||
ICSetElemDenseAddCompiler::generateStubCode(MacroAssembler &masm)
|
||||
{
|
||||
// R0 = object
|
||||
// R1 = key
|
||||
@ -3949,13 +3994,7 @@ ICSetElem_DenseAdd::Compiler::generateStubCode(MacroAssembler &masm)
|
||||
GeneralRegisterSet regs(availableGeneralRegs(2));
|
||||
Register scratchReg = regs.takeAny();
|
||||
|
||||
// Guard on the shape of the last prototype object.
|
||||
masm.loadPtr(Address(BaselineStubReg, ICSetElem_DenseAdd::offsetOfLastProto()), scratchReg);
|
||||
masm.loadPtr(Address(scratchReg, JSObject::offsetOfShape()), scratchReg);
|
||||
Address lastProtoShape(BaselineStubReg, ICSetElem_DenseAdd::offsetOfLastProtoShape());
|
||||
masm.branchPtr(Assembler::NotEqual, lastProtoShape, scratchReg, &failure);
|
||||
|
||||
// Unbox R0 and guard it's a dense array.
|
||||
// Unbox R0 and guard on its shape.
|
||||
Register obj = masm.extractObject(R0, ExtractTemp0);
|
||||
masm.loadPtr(Address(BaselineStubReg, ICSetElem_DenseAdd::offsetOfShape()), scratchReg);
|
||||
masm.branchTestObjShape(Assembler::NotEqual, obj, scratchReg, &failure);
|
||||
@ -3975,6 +4014,18 @@ ICSetElem_DenseAdd::Compiler::generateStubCode(MacroAssembler &masm)
|
||||
&failureUnstow);
|
||||
regs.add(typeReg);
|
||||
|
||||
// Shape guard objects on the proto chain.
|
||||
scratchReg = regs.takeAny();
|
||||
Register protoReg = regs.takeAny();
|
||||
for (size_t i = 0; i < protoChainDepth_; i++) {
|
||||
masm.loadObjProto(i == 0 ? obj : protoReg, protoReg);
|
||||
masm.loadPtr(Address(BaselineStubReg, ICSetElem_DenseAddImpl<0>::offsetOfProtoShape(i)),
|
||||
scratchReg);
|
||||
masm.branchTestObjShape(Assembler::NotEqual, protoReg, scratchReg, &failureUnstow);
|
||||
}
|
||||
regs.add(protoReg);
|
||||
regs.add(scratchReg);
|
||||
|
||||
// Stack is now: { ..., rhs-value, object-value, key-value, maybe?-RET-ADDR }
|
||||
// Load rhs-value in to R0
|
||||
masm.loadValue(Address(BaselineStackReg, 2 * sizeof(Value) + ICStackValueOffset), R0);
|
||||
@ -4412,6 +4463,9 @@ ICGetName_Scope<NumHops>::Compiler::generateStubCode(MacroAssembler &masm)
|
||||
Register walker = regs.takeAny();
|
||||
Register scratch = regs.takeAny();
|
||||
|
||||
// Use a local to silence Clang tautological-compare warning if NumHops is 0.
|
||||
size_t numHops = NumHops;
|
||||
|
||||
for (size_t index = 0; index < NumHops + 1; index++) {
|
||||
Register scope = index ? walker : obj;
|
||||
|
||||
@ -4419,7 +4473,7 @@ ICGetName_Scope<NumHops>::Compiler::generateStubCode(MacroAssembler &masm)
|
||||
masm.loadPtr(Address(BaselineStubReg, ICGetName_Scope::offsetOfShape(index)), scratch);
|
||||
masm.branchTestObjShape(Assembler::NotEqual, scope, scratch, &failure);
|
||||
|
||||
if (index < NumHops)
|
||||
if (index < numHops)
|
||||
masm.extractObject(Address(scope, ScopeObject::offsetOfEnclosingScope()), walker);
|
||||
}
|
||||
|
||||
@ -5282,6 +5336,29 @@ ICSetProp_Native::Compiler::generateStubCode(MacroAssembler &masm)
|
||||
return true;
|
||||
}
|
||||
|
||||
ICUpdatedStub *
|
||||
ICSetPropNativeAddCompiler::getStub(ICStubSpace *space)
|
||||
{
|
||||
AutoShapeVector protoShapes(cx);
|
||||
if (!GetProtoShapes(obj_, protoChainDepth_, &protoShapes))
|
||||
return NULL;
|
||||
|
||||
JS_STATIC_ASSERT(ICSetProp_NativeAdd::MAX_PROTO_CHAIN_DEPTH == 4);
|
||||
|
||||
ICUpdatedStub *stub = NULL;
|
||||
switch(protoChainDepth_) {
|
||||
case 0: stub = getStubSpecific<0>(space, &protoShapes); break;
|
||||
case 1: stub = getStubSpecific<1>(space, &protoShapes); break;
|
||||
case 2: stub = getStubSpecific<2>(space, &protoShapes); break;
|
||||
case 3: stub = getStubSpecific<3>(space, &protoShapes); break;
|
||||
case 4: stub = getStubSpecific<4>(space, &protoShapes); break;
|
||||
default: JS_NOT_REACHED("ProtoChainDepth too high.");
|
||||
}
|
||||
if (!stub || !stub->initUpdatingChain(cx, space))
|
||||
return NULL;
|
||||
return stub;
|
||||
}
|
||||
|
||||
bool
|
||||
ICSetPropNativeAddCompiler::generateStubCode(MacroAssembler &masm)
|
||||
{
|
||||
|
@ -1129,6 +1129,7 @@ class ICProfiler_PushFunction : public ICStub
|
||||
{
|
||||
friend class ICStubSpace;
|
||||
|
||||
protected:
|
||||
const char *str_;
|
||||
HeapPtrScript script_;
|
||||
|
||||
@ -3155,46 +3156,36 @@ class ICSetElem_Dense : public ICUpdatedStub
|
||||
};
|
||||
};
|
||||
|
||||
template <size_t ProtoChainDepth> class ICSetElem_DenseAddImpl;
|
||||
|
||||
class ICSetElem_DenseAdd : public ICUpdatedStub
|
||||
{
|
||||
friend class ICStubSpace;
|
||||
|
||||
public:
|
||||
static const size_t MAX_PROTO_CHAIN_DEPTH = 4;
|
||||
|
||||
protected:
|
||||
HeapPtrShape shape_;
|
||||
HeapPtrTypeObject type_;
|
||||
HeapPtrObject lastProto_;
|
||||
HeapPtrShape lastProtoShape_;
|
||||
|
||||
ICSetElem_DenseAdd(IonCode *stubCode, HandleShape shape, HandleTypeObject type,
|
||||
HandleObject lastProto, HandleShape lastProtoShape)
|
||||
ICSetElem_DenseAdd(IonCode *stubCode, RawShape shape, types::TypeObject *type,
|
||||
size_t protoChainDepth)
|
||||
: ICUpdatedStub(SetElem_DenseAdd, stubCode),
|
||||
shape_(shape),
|
||||
type_(type),
|
||||
lastProto_(lastProto),
|
||||
lastProtoShape_(lastProtoShape)
|
||||
{}
|
||||
|
||||
public:
|
||||
static inline ICSetElem_DenseAdd *New(ICStubSpace *space, IonCode *code,
|
||||
HandleShape shape, HandleTypeObject type,
|
||||
HandleObject lastProto, HandleShape lastProtoShape)
|
||||
type_(type)
|
||||
{
|
||||
if (!code)
|
||||
return NULL;
|
||||
return space->allocate<ICSetElem_DenseAdd>(code, shape, type, lastProto, lastProtoShape);
|
||||
JS_ASSERT(protoChainDepth <= MAX_PROTO_CHAIN_DEPTH);
|
||||
extra_ = protoChainDepth;
|
||||
}
|
||||
|
||||
public:
|
||||
static size_t offsetOfShape() {
|
||||
return offsetof(ICSetElem_DenseAdd, shape_);
|
||||
}
|
||||
static size_t offsetOfType() {
|
||||
return offsetof(ICSetElem_DenseAdd, type_);
|
||||
}
|
||||
static size_t offsetOfLastProto() {
|
||||
return offsetof(ICSetElem_DenseAdd, lastProto_);
|
||||
}
|
||||
static size_t offsetOfLastProtoShape() {
|
||||
return offsetof(ICSetElem_DenseAdd, lastProtoShape_);
|
||||
}
|
||||
|
||||
HeapPtrShape &shape() {
|
||||
return shape_;
|
||||
@ -3202,44 +3193,86 @@ class ICSetElem_DenseAdd : public ICUpdatedStub
|
||||
HeapPtrTypeObject &type() {
|
||||
return type_;
|
||||
}
|
||||
HeapPtrObject &lastProto() {
|
||||
return lastProto_;
|
||||
}
|
||||
HeapPtrShape &lastProtoShape() {
|
||||
return lastProtoShape_;
|
||||
size_t protoChainDepth() const {
|
||||
return extra_;
|
||||
}
|
||||
|
||||
class Compiler : public ICStubCompiler {
|
||||
RootedShape shape_;
|
||||
template <size_t ProtoChainDepth>
|
||||
ICSetElem_DenseAddImpl<ProtoChainDepth> *toImpl() {
|
||||
JS_ASSERT(ProtoChainDepth == protoChainDepth());
|
||||
return static_cast<ICSetElem_DenseAddImpl<ProtoChainDepth> *>(this);
|
||||
}
|
||||
};
|
||||
|
||||
// Compiler is only live on stack during compilation, it should
|
||||
// outlive any RootedTypeObject it's passed. So it can just
|
||||
// use the handle.
|
||||
HandleTypeObject type_;
|
||||
template <size_t ProtoChainDepth>
|
||||
class ICSetElem_DenseAddImpl : public ICSetElem_DenseAdd
|
||||
{
|
||||
friend class ICStubSpace;
|
||||
|
||||
RootedObject lastProto_;
|
||||
RootedShape lastProtoShape_;
|
||||
HeapPtrShape protoShapes_[ProtoChainDepth];
|
||||
|
||||
bool generateStubCode(MacroAssembler &masm);
|
||||
ICSetElem_DenseAddImpl(IonCode *stubCode, RawShape shape, types::TypeObject *type,
|
||||
const AutoShapeVector *protoShapes)
|
||||
: ICSetElem_DenseAdd(stubCode, shape, type, ProtoChainDepth)
|
||||
{
|
||||
JS_ASSERT(protoShapes->length() == ProtoChainDepth);
|
||||
for (size_t i = 0; i < protoChainDepth(); i++)
|
||||
protoShapes_[i].init((*protoShapes)[i]);
|
||||
}
|
||||
|
||||
public:
|
||||
Compiler(JSContext *cx, RawShape shape, HandleTypeObject type,
|
||||
RawObject lastProto, RawShape lastProtoShape)
|
||||
: ICStubCompiler(cx, ICStub::SetElem_DenseAdd),
|
||||
shape_(cx, shape),
|
||||
type_(type),
|
||||
lastProto_(cx, lastProto),
|
||||
lastProtoShape_(cx, lastProtoShape)
|
||||
{}
|
||||
// Used to silence Clang tautological-compare warning for
|
||||
// ProtoChainDepth == 0.
|
||||
size_t protoChainDepth() const {
|
||||
return ProtoChainDepth;
|
||||
}
|
||||
|
||||
ICUpdatedStub *getStub(ICStubSpace *space) {
|
||||
ICSetElem_DenseAdd *stub = ICSetElem_DenseAdd::New(space, getStubCode(), shape_, type_,
|
||||
lastProto_, lastProtoShape_);
|
||||
if (!stub || !stub->initUpdatingChain(cx, space))
|
||||
return NULL;
|
||||
return stub;
|
||||
}
|
||||
};
|
||||
public:
|
||||
static inline ICSetElem_DenseAddImpl *New(ICStubSpace *space, IonCode *code, RawShape shape,
|
||||
types::TypeObject *type,
|
||||
const AutoShapeVector *protoShapes)
|
||||
{
|
||||
if (!code)
|
||||
return NULL;
|
||||
return space->allocate<ICSetElem_DenseAddImpl<ProtoChainDepth> >(code, shape, type,
|
||||
protoShapes);
|
||||
}
|
||||
|
||||
void traceProtoShapes(JSTracer *trc) {
|
||||
for (size_t i = 0; i < protoChainDepth(); i++)
|
||||
MarkShape(trc, &protoShapes_[i], "baseline-setelem-denseadd-stub-protoshape");
|
||||
}
|
||||
|
||||
static size_t offsetOfProtoShape(size_t idx) {
|
||||
return offsetof(ICSetElem_DenseAddImpl, protoShapes_) + idx * sizeof(HeapPtrShape);
|
||||
}
|
||||
};
|
||||
|
||||
class ICSetElemDenseAddCompiler : public ICStubCompiler {
|
||||
RootedObject obj_;
|
||||
size_t protoChainDepth_;
|
||||
|
||||
bool generateStubCode(MacroAssembler &masm);
|
||||
|
||||
protected:
|
||||
virtual int32_t getKey() const {
|
||||
return static_cast<int32_t>(kind) | (static_cast<int32_t>(protoChainDepth_) << 16);
|
||||
}
|
||||
|
||||
public:
|
||||
ICSetElemDenseAddCompiler(JSContext *cx, HandleObject obj, size_t protoChainDepth)
|
||||
: ICStubCompiler(cx, ICStub::SetElem_DenseAdd),
|
||||
obj_(cx, obj),
|
||||
protoChainDepth_(protoChainDepth)
|
||||
{}
|
||||
|
||||
template <size_t ProtoChainDepth>
|
||||
ICUpdatedStub *getStubSpecific(ICStubSpace *space, const AutoShapeVector *protoShapes) {
|
||||
return ICSetElem_DenseAddImpl<ProtoChainDepth>::New(space, getStubCode(),
|
||||
obj_->lastProperty(), obj_->getType(cx),
|
||||
protoShapes);
|
||||
}
|
||||
|
||||
ICUpdatedStub *getStub(ICStubSpace *space);
|
||||
};
|
||||
|
||||
class ICSetElem_TypedArray : public ICStub
|
||||
@ -3480,7 +3513,7 @@ class ICGetName_Scope : public ICMonitoredStub
|
||||
}
|
||||
|
||||
void traceScopes(JSTracer *trc) {
|
||||
for (size_t i = 0; i <= NumHops; i++)
|
||||
for (size_t i = 0; i < NumHops + 1; i++)
|
||||
MarkShape(trc, &shapes_[i], "baseline-scope-stub-shape");
|
||||
}
|
||||
|
||||
@ -3980,6 +4013,7 @@ class ICGetProp_CallScripted : public ICMonitoredStub
|
||||
{
|
||||
friend class ICStubSpace;
|
||||
|
||||
protected:
|
||||
// Object shape (lastProperty).
|
||||
HeapPtrShape shape_;
|
||||
|
||||
@ -4266,9 +4300,16 @@ class ICSetProp_NativeAddImpl : public ICSetProp_NativeAdd
|
||||
: ICSetProp_NativeAdd(stubCode, type, oldShape, ProtoChainDepth, newShape, offset)
|
||||
{
|
||||
JS_ASSERT(protoShapes->length() == ProtoChainDepth);
|
||||
for (size_t i = 0; i < ProtoChainDepth; i++)
|
||||
for (size_t i = 0; i < protoChainDepth(); i++)
|
||||
protoShapes_[i].init((*protoShapes)[i]);
|
||||
}
|
||||
|
||||
// Used to silence Clang tautological-compare warning for
|
||||
// ProtoChainDepth == 0.
|
||||
size_t protoChainDepth() const {
|
||||
return ProtoChainDepth;
|
||||
}
|
||||
|
||||
public:
|
||||
static inline ICSetProp_NativeAddImpl *New(
|
||||
ICStubSpace *space, IonCode *code, HandleTypeObject type, HandleShape oldShape,
|
||||
@ -4281,7 +4322,7 @@ class ICSetProp_NativeAddImpl : public ICSetProp_NativeAdd
|
||||
}
|
||||
|
||||
void traceProtoShapes(JSTracer *trc) {
|
||||
for (size_t i = 0; i < ProtoChainDepth; i++)
|
||||
for (size_t i = 0; i < protoChainDepth(); i++)
|
||||
MarkShape(trc, &protoShapes_[i], "baseline-setpropnativeadd-stub-protoshape");
|
||||
}
|
||||
|
||||
@ -4328,28 +4369,7 @@ class ICSetPropNativeAddCompiler : public ICStubCompiler {
|
||||
space, getStubCode(), type, oldShape_, protoShapes, newShape, offset_);
|
||||
}
|
||||
|
||||
ICUpdatedStub *getStub(ICStubSpace *space) {
|
||||
AutoShapeVector protoShapes(cx);
|
||||
RootedObject curProto(cx, obj_->getProto());
|
||||
for (size_t i = 0; i < protoChainDepth_; i++) {
|
||||
JS_ASSERT(curProto);
|
||||
protoShapes.append(curProto->lastProperty());
|
||||
curProto = curProto->getProto();
|
||||
}
|
||||
JS_STATIC_ASSERT(ICSetProp_NativeAdd::MAX_PROTO_CHAIN_DEPTH == 4);
|
||||
ICUpdatedStub *stub = NULL;
|
||||
switch(protoChainDepth_) {
|
||||
case 0: stub = getStubSpecific<0>(space, &protoShapes); break;
|
||||
case 1: stub = getStubSpecific<1>(space, &protoShapes); break;
|
||||
case 2: stub = getStubSpecific<2>(space, &protoShapes); break;
|
||||
case 3: stub = getStubSpecific<3>(space, &protoShapes); break;
|
||||
case 4: stub = getStubSpecific<4>(space, &protoShapes); break;
|
||||
default: JS_NOT_REACHED("ProtoChainDepth too high.");
|
||||
}
|
||||
if (!stub || !stub->initUpdatingChain(cx, space))
|
||||
return NULL;
|
||||
return stub;
|
||||
}
|
||||
ICUpdatedStub *getStub(ICStubSpace *space);
|
||||
};
|
||||
|
||||
// Stub for calling a scripted setter on a native object.
|
||||
@ -4357,6 +4377,7 @@ class ICSetProp_CallScripted : public ICStub
|
||||
{
|
||||
friend class ICStubSpace;
|
||||
|
||||
protected:
|
||||
// Object shape (lastProperty).
|
||||
HeapPtrShape shape_;
|
||||
|
||||
@ -4538,6 +4559,7 @@ class ICCall_Scripted : public ICMonitoredStub
|
||||
{
|
||||
friend class ICStubSpace;
|
||||
|
||||
protected:
|
||||
HeapPtrScript calleeScript_;
|
||||
uint32_t pcOffset_;
|
||||
|
||||
@ -4574,6 +4596,7 @@ class ICCall_AnyScripted : public ICMonitoredStub
|
||||
{
|
||||
friend class ICStubSpace;
|
||||
|
||||
protected:
|
||||
uint32_t pcOffset_;
|
||||
|
||||
ICCall_AnyScripted(IonCode *stubCode, ICStub *firstMonitorStub, uint32_t pcOffset)
|
||||
@ -4628,7 +4651,6 @@ class ICCallScriptedCompiler : public ICCallStubCompiler {
|
||||
{ }
|
||||
|
||||
ICStub *getStub(ICStubSpace *space) {
|
||||
ICStub *stub = NULL;
|
||||
if (calleeScript_) {
|
||||
return ICCall_Scripted::New(space, getStubCode(), firstMonitorStub_, calleeScript_,
|
||||
pcOffset_);
|
||||
@ -4641,6 +4663,7 @@ class ICCall_Native : public ICMonitoredStub
|
||||
{
|
||||
friend class ICStubSpace;
|
||||
|
||||
protected:
|
||||
HeapPtrFunction callee_;
|
||||
uint32_t pcOffset_;
|
||||
|
||||
|
@ -1282,8 +1282,7 @@ SetPropertyIC::attachNativeAdding(JSContext *cx, IonScript *ion, JSObject *obj,
|
||||
masm.loadPtr(Address(protoReg, JSObject::offsetOfType()), protoReg);
|
||||
masm.loadPtr(Address(protoReg, offsetof(types::TypeObject, proto)), protoReg);
|
||||
|
||||
// ensure that the prototype is not NULL and that its shape matches
|
||||
masm.branchTestPtr(Assembler::Zero, protoReg, protoReg, &protoFailures);
|
||||
// Ensure that its shape matches.
|
||||
masm.branchTestObjShape(Assembler::NotEqual, protoReg, protoShape, &protoFailures);
|
||||
|
||||
proto = proto->getProto();
|
||||
|
@ -1410,6 +1410,14 @@ IonFrameIterator::dump() const
|
||||
fprintf(stderr, " Entry frame\n");
|
||||
fprintf(stderr, " Frame size: %u\n", unsigned(current()->prevFrameLocalSize()));
|
||||
break;
|
||||
case IonFrame_BaselineJS:
|
||||
dumpBaseline();
|
||||
break;
|
||||
case IonFrame_BaselineStub:
|
||||
case IonFrame_Unwound_BaselineStub:
|
||||
fprintf(stderr, " Baseline stub frame\n");
|
||||
fprintf(stderr, " Frame size: %u\n", unsigned(current()->prevFrameLocalSize()));
|
||||
break;
|
||||
case IonFrame_OptimizedJS:
|
||||
{
|
||||
InlineFrameIterator frames(GetIonContext()->cx, this);
|
||||
|
42
js/src/jit-test/tests/baseline/bug848743-1.js
Normal file
42
js/src/jit-test/tests/baseline/bug848743-1.js
Normal file
@ -0,0 +1,42 @@
|
||||
function A() {};
|
||||
A.prototype = [];
|
||||
|
||||
function B() {};
|
||||
B.prototype = new A();
|
||||
|
||||
function C() {};
|
||||
C.prototype = new B();
|
||||
|
||||
function D() {};
|
||||
D.prototype = new C();
|
||||
|
||||
function E() {};
|
||||
E.prototype = new D();
|
||||
|
||||
function f() {
|
||||
var o = new B();
|
||||
for (var i=0; i<10; i++)
|
||||
o[i] = i;
|
||||
|
||||
var expected = '{"0":0,"1":1,"2":2,"3":3,"4":4,"5":5,"6":6,"7":7,"8":8,"9":9}';
|
||||
assertEq(JSON.stringify(o), expected);
|
||||
|
||||
var o = new A();
|
||||
for (var i=0; i<10; i++)
|
||||
o[i] = i;
|
||||
|
||||
assertEq(JSON.stringify(o), expected);
|
||||
|
||||
var o = new D();
|
||||
for (var i=0; i<10; i++)
|
||||
o[i] = i;
|
||||
|
||||
assertEq(JSON.stringify(o), expected);
|
||||
|
||||
var o = new E();
|
||||
for (var i=0; i<10; i++)
|
||||
o[i] = i;
|
||||
|
||||
assertEq(JSON.stringify(o), expected);
|
||||
}
|
||||
f();
|
14
js/src/jit-test/tests/baseline/bug848743-2.js
Normal file
14
js/src/jit-test/tests/baseline/bug848743-2.js
Normal file
@ -0,0 +1,14 @@
|
||||
var gTestcases = new Array();
|
||||
var gTc = gTestcases.length;
|
||||
var setterCalled = false;
|
||||
function TestCase() {
|
||||
gTestcases[gTc++] = this;
|
||||
}
|
||||
for(var i = 0; i < 13; ++i) {
|
||||
var testcase = new TestCase();
|
||||
}
|
||||
Array.prototype.__defineSetter__(32, function() { setterCalled = true; });
|
||||
for(var i = 0; i < 20; ++i) {
|
||||
var testcase = new TestCase();
|
||||
}
|
||||
assertEq(setterCalled, true);
|
Loading…
Reference in New Issue
Block a user