Bug 855264 part 1 - Avoid storing zero-sized arrays in stubs. r=djvj

This commit is contained in:
Jan de Mooij 2013-03-28 11:09:27 +01:00
parent c54687dee3
commit c0fa622930
2 changed files with 93 additions and 108 deletions

View File

@ -210,17 +210,16 @@ ICStub::trace(JSTracer *trc)
}
case ICStub::SetElem_DenseAdd: {
ICSetElem_DenseAdd *setElemStub = toSetElem_DenseAdd();
MarkShape(trc, &setElemStub->shape(), "baseline-getelem-denseadd-shape");
MarkTypeObject(trc, &setElemStub->type(), "baseline-setelem-denseadd-type");
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;
case 0: setElemStub->toImpl<0>()->traceShapes(trc); break;
case 1: setElemStub->toImpl<1>()->traceShapes(trc); break;
case 2: setElemStub->toImpl<2>()->traceShapes(trc); break;
case 3: setElemStub->toImpl<3>()->traceShapes(trc); break;
case 4: setElemStub->toImpl<4>()->traceShapes(trc); break;
default: JS_NOT_REACHED("Invalid proto stub.");
}
break;
@ -320,15 +319,14 @@ ICStub::trace(JSTracer *trc)
case ICStub::SetProp_NativeAdd: {
ICSetProp_NativeAdd *propStub = toSetProp_NativeAdd();
MarkTypeObject(trc, &propStub->type(), "baseline-setpropnativeadd-stub-type");
MarkShape(trc, &propStub->oldShape(), "baseline-setpropnativeadd-stub-oldshape");
MarkShape(trc, &propStub->newShape(), "baseline-setpropnativeadd-stub-newshape");
JS_STATIC_ASSERT(ICSetProp_NativeAdd::MAX_PROTO_CHAIN_DEPTH == 4);
switch (propStub->protoChainDepth()) {
case 0: propStub->toImpl<0>()->traceProtoShapes(trc); break;
case 1: propStub->toImpl<1>()->traceProtoShapes(trc); break;
case 2: propStub->toImpl<2>()->traceProtoShapes(trc); break;
case 3: propStub->toImpl<3>()->traceProtoShapes(trc); break;
case 4: propStub->toImpl<4>()->traceProtoShapes(trc); break;
case 0: propStub->toImpl<0>()->traceShapes(trc); break;
case 1: propStub->toImpl<1>()->traceShapes(trc); break;
case 2: propStub->toImpl<2>()->traceShapes(trc); break;
case 3: propStub->toImpl<3>()->traceShapes(trc); break;
case 4: propStub->toImpl<4>()->traceShapes(trc); break;
default: JS_NOT_REACHED("Invalid proto stub.");
}
break;
@ -3573,8 +3571,11 @@ DenseSetElemStubExists(JSContext *cx, ICStub::Kind kind, ICSetElem_Fallback *stu
if (kind == ICStub::SetElem_DenseAdd && iter->isSetElem_DenseAdd()) {
ICSetElem_DenseAdd *dense = iter->toSetElem_DenseAdd();
if (obj->lastProperty() == dense->shape() && obj->getType(cx) == dense->type())
if (obj->lastProperty() == dense->toImplUnchecked<0>()->shape(0) &&
obj->getType(cx) == dense->type())
{
return true;
}
}
}
return false;
@ -3676,7 +3677,7 @@ CanOptimizeDenseSetElem(JSContext *cx, HandleObject obj, uint32_t index,
++*protoDepthOut;
}
if (*protoDepthOut > ICSetProp_NativeAdd::MAX_PROTO_CHAIN_DEPTH)
if (*protoDepthOut > ICSetElem_DenseAdd::MAX_PROTO_CHAIN_DEPTH)
return false;
*isAddingCaseOut = true;
@ -3953,12 +3954,12 @@ ICSetElem_Dense::Compiler::generateStubCode(MacroAssembler &masm)
}
static bool
GetProtoShapes(JSObject *obj, size_t protoChainDepth, AutoShapeVector *protoShapes)
GetProtoShapes(JSObject *obj, size_t protoChainDepth, AutoShapeVector *shapes)
{
JS_ASSERT(protoShapes->empty());
JS_ASSERT(shapes->length() == 1);
JSObject *curProto = obj->getProto();
for (size_t i = 0; i < protoChainDepth; i++) {
if (!protoShapes->append(curProto->lastProperty()))
if (!shapes->append(curProto->lastProperty()))
return false;
curProto = curProto->getProto();
}
@ -3973,19 +3974,22 @@ GetProtoShapes(JSObject *obj, size_t protoChainDepth, AutoShapeVector *protoShap
ICUpdatedStub *
ICSetElemDenseAddCompiler::getStub(ICStubSpace *space)
{
AutoShapeVector protoShapes(cx);
if (!GetProtoShapes(obj_, protoChainDepth_, &protoShapes))
AutoShapeVector shapes(cx);
if (!shapes.append(obj_->lastProperty()))
return NULL;
if (!GetProtoShapes(obj_, protoChainDepth_, &shapes))
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;
case 0: stub = getStubSpecific<0>(space, &shapes); break;
case 1: stub = getStubSpecific<1>(space, &shapes); break;
case 2: stub = getStubSpecific<2>(space, &shapes); break;
case 3: stub = getStubSpecific<3>(space, &shapes); break;
case 4: stub = getStubSpecific<4>(space, &shapes); break;
default: JS_NOT_REACHED("ProtoChainDepth too high.");
}
if (!stub || !stub->initUpdatingChain(cx, space))
@ -4009,7 +4013,8 @@ ICSetElemDenseAddCompiler::generateStubCode(MacroAssembler &masm)
// Unbox R0 and guard on its shape.
Register obj = masm.extractObject(R0, ExtractTemp0);
masm.loadPtr(Address(BaselineStubReg, ICSetElem_DenseAdd::offsetOfShape()), scratchReg);
masm.loadPtr(Address(BaselineStubReg, ICSetElem_DenseAddImpl<0>::offsetOfShape(0)),
scratchReg);
masm.branchTestObjShape(Assembler::NotEqual, obj, scratchReg, &failure);
// Stow both R0 and R1 (object and key)
@ -4032,7 +4037,7 @@ ICSetElemDenseAddCompiler::generateStubCode(MacroAssembler &masm)
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)),
masm.loadPtr(Address(BaselineStubReg, ICSetElem_DenseAddImpl<0>::offsetOfShape(i + 1)),
scratchReg);
masm.branchTestObjShape(Assembler::NotEqual, protoReg, scratchReg, &failureUnstow);
}
@ -5353,19 +5358,22 @@ ICSetProp_Native::Compiler::generateStubCode(MacroAssembler &masm)
ICUpdatedStub *
ICSetPropNativeAddCompiler::getStub(ICStubSpace *space)
{
AutoShapeVector protoShapes(cx);
if (!GetProtoShapes(obj_, protoChainDepth_, &protoShapes))
AutoShapeVector shapes(cx);
if (!shapes.append(oldShape_))
return NULL;
if (!GetProtoShapes(obj_, protoChainDepth_, &shapes))
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;
case 0: stub = getStubSpecific<0>(space, &shapes); break;
case 1: stub = getStubSpecific<1>(space, &shapes); break;
case 2: stub = getStubSpecific<2>(space, &shapes); break;
case 3: stub = getStubSpecific<3>(space, &shapes); break;
case 4: stub = getStubSpecific<4>(space, &shapes); break;
default: JS_NOT_REACHED("ProtoChainDepth too high.");
}
if (!stub || !stub->initUpdatingChain(cx, space))
@ -5387,7 +5395,7 @@ ICSetPropNativeAddCompiler::generateStubCode(MacroAssembler &masm)
// Unbox and guard against old shape.
Register objReg = masm.extractObject(R0, ExtractTemp0);
masm.loadPtr(Address(BaselineStubReg, ICSetProp_NativeAdd::offsetOfOldShape()), scratch);
masm.loadPtr(Address(BaselineStubReg, ICSetProp_NativeAddImpl<0>::offsetOfShape(0)), scratch);
masm.branchTestObjShape(Assembler::NotEqual, objReg, scratch, &failure);
// Guard that the type object matches.
@ -5404,9 +5412,7 @@ ICSetPropNativeAddCompiler::generateStubCode(MacroAssembler &masm)
// Check the proto chain.
for (size_t i = 0; i < protoChainDepth_; i++) {
masm.loadObjProto(i == 0 ? objReg : protoReg, protoReg);
masm.branchTestPtr(Assembler::Zero, protoReg, protoReg, &failureUnstow);
masm.loadPtr(Address(BaselineStubReg, ICSetProp_NativeAddImpl<0>::offsetOfProtoShape(i)),
masm.loadPtr(Address(BaselineStubReg, ICSetProp_NativeAddImpl<0>::offsetOfShape(i + 1)),
scratch);
masm.branchTestObjShape(Assembler::NotEqual, protoReg, scratch, &failureUnstow);
}

View File

@ -3167,13 +3167,10 @@ class ICSetElem_DenseAdd : public ICUpdatedStub
static const size_t MAX_PROTO_CHAIN_DEPTH = 4;
protected:
HeapPtrShape shape_;
HeapPtrTypeObject type_;
ICSetElem_DenseAdd(IonCode *stubCode, RawShape shape, types::TypeObject *type,
size_t protoChainDepth)
ICSetElem_DenseAdd(IonCode *stubCode, types::TypeObject *type, size_t protoChainDepth)
: ICUpdatedStub(SetElem_DenseAdd, stubCode),
shape_(shape),
type_(type)
{
JS_ASSERT(protoChainDepth <= MAX_PROTO_CHAIN_DEPTH);
@ -3181,16 +3178,10 @@ class ICSetElem_DenseAdd : public ICUpdatedStub
}
public:
static size_t offsetOfShape() {
return offsetof(ICSetElem_DenseAdd, shape_);
}
static size_t offsetOfType() {
return offsetof(ICSetElem_DenseAdd, type_);
}
HeapPtrShape &shape() {
return shape_;
}
HeapPtrTypeObject &type() {
return type_;
}
@ -3198,10 +3189,15 @@ class ICSetElem_DenseAdd : public ICUpdatedStub
return extra_;
}
template <size_t ProtoChainDepth>
ICSetElem_DenseAddImpl<ProtoChainDepth> *toImplUnchecked() {
return static_cast<ICSetElem_DenseAddImpl<ProtoChainDepth> *>(this);
}
template <size_t ProtoChainDepth>
ICSetElem_DenseAddImpl<ProtoChainDepth> *toImpl() {
JS_ASSERT(ProtoChainDepth == protoChainDepth());
return static_cast<ICSetElem_DenseAddImpl<ProtoChainDepth> *>(this);
return toImplUnchecked<ProtoChainDepth>();
}
};
@ -3210,41 +3206,38 @@ class ICSetElem_DenseAddImpl : public ICSetElem_DenseAdd
{
friend class ICStubSpace;
HeapPtrShape protoShapes_[ProtoChainDepth];
static const size_t NumShapes = ProtoChainDepth + 1;
HeapPtrShape shapes_[NumShapes];
ICSetElem_DenseAddImpl(IonCode *stubCode, RawShape shape, types::TypeObject *type,
const AutoShapeVector *protoShapes)
: ICSetElem_DenseAdd(stubCode, shape, type, ProtoChainDepth)
ICSetElem_DenseAddImpl(IonCode *stubCode, types::TypeObject *type,
const AutoShapeVector *shapes)
: ICSetElem_DenseAdd(stubCode, type, ProtoChainDepth)
{
JS_ASSERT(protoShapes->length() == ProtoChainDepth);
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;
JS_ASSERT(shapes->length() == NumShapes);
for (size_t i = 0; i < NumShapes; i++)
shapes_[i].init((*shapes)[i]);
}
public:
static inline ICSetElem_DenseAddImpl *New(ICStubSpace *space, IonCode *code, RawShape shape,
static inline ICSetElem_DenseAddImpl *New(ICStubSpace *space, IonCode *code,
types::TypeObject *type,
const AutoShapeVector *protoShapes)
const AutoShapeVector *shapes)
{
if (!code)
return NULL;
return space->allocate<ICSetElem_DenseAddImpl<ProtoChainDepth> >(code, shape, type,
protoShapes);
return space->allocate<ICSetElem_DenseAddImpl<ProtoChainDepth> >(code, type, shapes);
}
void traceProtoShapes(JSTracer *trc) {
for (size_t i = 0; i < protoChainDepth(); i++)
MarkShape(trc, &protoShapes_[i], "baseline-setelem-denseadd-stub-protoshape");
void traceShapes(JSTracer *trc) {
for (size_t i = 0; i < NumShapes; i++)
MarkShape(trc, &shapes_[i], "baseline-setelem-denseadd-stub-shape");
}
static size_t offsetOfProtoShape(size_t idx) {
return offsetof(ICSetElem_DenseAddImpl, protoShapes_) + idx * sizeof(HeapPtrShape);
Shape *shape(size_t i) const {
JS_ASSERT(i < NumShapes);
return shapes_[i];
}
static size_t offsetOfShape(size_t idx) {
return offsetof(ICSetElem_DenseAddImpl, shapes_) + idx * sizeof(HeapPtrShape);
}
};
@ -3267,10 +3260,9 @@ class ICSetElemDenseAddCompiler : public ICStubCompiler {
{}
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 *getStubSpecific(ICStubSpace *space, const AutoShapeVector *shapes) {
return ICSetElem_DenseAddImpl<ProtoChainDepth>::New(space, getStubCode(), obj_->getType(cx),
shapes);
}
ICUpdatedStub *getStub(ICStubSpace *space);
@ -4238,15 +4230,13 @@ class ICSetProp_NativeAdd : public ICUpdatedStub
protected: // Protected to silence Clang warning.
HeapPtrTypeObject type_;
HeapPtrShape oldShape_;
HeapPtrShape newShape_;
uint32_t offset_;
ICSetProp_NativeAdd(IonCode *stubCode, HandleTypeObject type, HandleShape oldShape,
size_t protoChainDepth, HandleShape newShape, uint32_t offset)
ICSetProp_NativeAdd(IonCode *stubCode, HandleTypeObject type, size_t protoChainDepth,
HandleShape newShape, uint32_t offset)
: ICUpdatedStub(SetProp_NativeAdd, stubCode),
type_(type),
oldShape_(oldShape),
newShape_(newShape),
offset_(offset)
{
@ -4261,9 +4251,6 @@ class ICSetProp_NativeAdd : public ICUpdatedStub
HeapPtrTypeObject &type() {
return type_;
}
HeapPtrShape &oldShape() {
return oldShape_;
}
HeapPtrShape &newShape() {
return newShape_;
}
@ -4277,9 +4264,6 @@ class ICSetProp_NativeAdd : public ICUpdatedStub
static size_t offsetOfType() {
return offsetof(ICSetProp_NativeAdd, type_);
}
static size_t offsetOfOldShape() {
return offsetof(ICSetProp_NativeAdd, oldShape_);
}
static size_t offsetOfNewShape() {
return offsetof(ICSetProp_NativeAdd, newShape_);
}
@ -4293,42 +4277,37 @@ class ICSetProp_NativeAddImpl : public ICSetProp_NativeAdd
{
friend class ICStubSpace;
HeapPtrShape protoShapes_[ProtoChainDepth];
static const size_t NumShapes = ProtoChainDepth + 1;
HeapPtrShape shapes_[NumShapes];
ICSetProp_NativeAddImpl(IonCode *stubCode, HandleTypeObject type, HandleShape oldShape,
const AutoShapeVector *protoShapes,
ICSetProp_NativeAddImpl(IonCode *stubCode, HandleTypeObject type,
const AutoShapeVector *shapes,
HandleShape newShape, uint32_t offset)
: ICSetProp_NativeAdd(stubCode, type, oldShape, ProtoChainDepth, newShape, offset)
: ICSetProp_NativeAdd(stubCode, type, ProtoChainDepth, newShape, offset)
{
JS_ASSERT(protoShapes->length() == ProtoChainDepth);
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;
JS_ASSERT(shapes->length() == NumShapes);
for (size_t i = 0; i < NumShapes; i++)
shapes_[i].init((*shapes)[i]);
}
public:
static inline ICSetProp_NativeAddImpl *New(
ICStubSpace *space, IonCode *code, HandleTypeObject type, HandleShape oldShape,
const AutoShapeVector *protoShapes, HandleShape newShape, uint32_t offset)
ICStubSpace *space, IonCode *code, HandleTypeObject type,
const AutoShapeVector *shapes, HandleShape newShape, uint32_t offset)
{
if (!code)
return NULL;
return space->allocate<ICSetProp_NativeAddImpl<ProtoChainDepth> >(
code, type, oldShape, protoShapes, newShape, offset);
code, type, shapes, newShape, offset);
}
void traceProtoShapes(JSTracer *trc) {
for (size_t i = 0; i < protoChainDepth(); i++)
MarkShape(trc, &protoShapes_[i], "baseline-setpropnativeadd-stub-protoshape");
void traceShapes(JSTracer *trc) {
for (size_t i = 0; i < NumShapes; i++)
MarkShape(trc, &shapes_[i], "baseline-setpropnativeadd-stub-shape");
}
static size_t offsetOfProtoShape(size_t idx) {
return offsetof(ICSetProp_NativeAddImpl, protoShapes_) + (idx * sizeof(HeapPtrShape));
static size_t offsetOfShape(size_t idx) {
return offsetof(ICSetProp_NativeAddImpl, shapes_) + (idx * sizeof(HeapPtrShape));
}
};
@ -4361,13 +4340,13 @@ class ICSetPropNativeAddCompiler : public ICStubCompiler {
}
template <size_t ProtoChainDepth>
ICUpdatedStub *getStubSpecific(ICStubSpace *space, const AutoShapeVector *protoShapes)
ICUpdatedStub *getStubSpecific(ICStubSpace *space, const AutoShapeVector *shapes)
{
RootedTypeObject type(cx, obj_->getType(cx));
RootedShape newShape(cx, obj_->lastProperty());
return ICSetProp_NativeAddImpl<ProtoChainDepth>::New(
space, getStubCode(), type, oldShape_, protoShapes, newShape, offset_);
space, getStubCode(), type, shapes, newShape, offset_);
}
ICUpdatedStub *getStub(ICStubSpace *space);