This commit is contained in:
Jan de Mooij 2013-03-06 16:18:58 +01:00
commit 1b0d8c9b07
2 changed files with 80 additions and 23 deletions

View File

@ -3416,14 +3416,39 @@ DenseSetElemStubExists(JSContext *cx, ICStub::Kind kind, ICSetElem_Fallback *stu
} }
static bool static bool
TypedArraySetElemStubExists(ICSetElem_Fallback *stub, HandleObject obj) TypedArraySetElemStubExists(ICSetElem_Fallback *stub, HandleObject obj, bool expectOutOfBounds)
{ {
for (ICStub *cur = stub->icEntry()->firstStub(); cur != stub; cur = cur->next()) { for (ICStub *cur = stub->icEntry()->firstStub(); cur != stub; cur = cur->next()) {
if (!cur->isSetElem_TypedArray()) if (!cur->isSetElem_TypedArray())
continue; continue;
if (obj->lastProperty() == cur->toSetElem_TypedArray()->shape()) ICSetElem_TypedArray *taStub = cur->toSetElem_TypedArray();
if (obj->lastProperty() == taStub->shape() &&
taStub->expectOutOfBounds() == expectOutOfBounds)
{
return true; return true;
} }
}
return false;
}
static bool
RemoveExistingTypedArraySetElemStub(JSContext *cx, ICSetElem_Fallback *stub, HandleObject obj)
{
ICStub *prev = NULL;
ICStub *cur = stub->icEntry()->firstStub();
while (cur != stub) {
if (cur->isSetElem_TypedArray() &&
obj->lastProperty() == cur->toSetElem_TypedArray()->shape())
{
// TypedArraySetElem stubs are only removed using this procedure if
// being replaced with one that expects out of bounds index.
JS_ASSERT(!cur->toSetElem_TypedArray()->expectOutOfBounds());
stub->unlinkStub(cx->zone(), prev, cur);
return true;
}
prev = cur;
cur = cur->next();
}
return false; return false;
} }
@ -3600,13 +3625,22 @@ DoSetElemFallback(JSContext *cx, BaselineFrame *frame, ICSetElem_Fallback *stub,
return true; return true;
} }
if (obj->isTypedArray() && if (obj->isTypedArray() && index.isInt32() && rhs.isNumber()) {
index.isInt32() && rhs.isNumber() && uint32_t len = TypedArray::length(obj);
!TypedArraySetElemStubExists(stub, obj)) int32_t idx = index.toInt32();
{ bool expectOutOfBounds = (idx < 0) || (static_cast<uint32_t>(idx) >= len);
IonSpew(IonSpew_BaselineIC, " Generating SetElem_TypedArray stub (shape=%p, type=%u)",
obj->lastProperty(), TypedArray::type(obj)); if (!TypedArraySetElemStubExists(stub, obj, expectOutOfBounds)) {
ICSetElem_TypedArray::Compiler compiler(cx, obj->lastProperty(), TypedArray::type(obj)); // Remove any existing TypedArraySetElemStub that doesn't handle out-of-bounds
if (expectOutOfBounds)
RemoveExistingTypedArraySetElemStub(cx, stub, obj);
IonSpew(IonSpew_BaselineIC,
" Generating SetElem_TypedArray stub (shape=%p, type=%u, oob=%s)",
obj->lastProperty(), TypedArray::type(obj),
expectOutOfBounds ? "yes" : "no");
ICSetElem_TypedArray::Compiler compiler(cx, obj->lastProperty(), TypedArray::type(obj),
expectOutOfBounds);
ICStub *typedArrayStub = compiler.getStub(compiler.getStubSpace(script)); ICStub *typedArrayStub = compiler.getStub(compiler.getStubSpace(script));
if (!typedArrayStub) if (!typedArrayStub)
return false; return false;
@ -3614,6 +3648,7 @@ DoSetElemFallback(JSContext *cx, BaselineFrame *frame, ICSetElem_Fallback *stub,
stub->addNewStub(typedArrayStub); stub->addNewStub(typedArrayStub);
return true; return true;
} }
}
return true; return true;
} }
@ -3897,8 +3932,10 @@ ICSetElem_TypedArray::Compiler::generateStubCode(MacroAssembler &masm)
Register key = masm.extractInt32(R1, ExtractTemp1); Register key = masm.extractInt32(R1, ExtractTemp1);
// Bounds check. // Bounds check.
Label oobWrite;
masm.unboxInt32(Address(obj, TypedArray::lengthOffset()), scratchReg); masm.unboxInt32(Address(obj, TypedArray::lengthOffset()), scratchReg);
masm.branch32(Assembler::BelowOrEqual, scratchReg, key, &failure); masm.branch32(Assembler::BelowOrEqual, scratchReg, key,
expectOutOfBounds_ ? &oobWrite : &failure);
// Load the elements vector. // Load the elements vector.
masm.loadPtr(Address(obj, TypedArray::dataOffset()), scratchReg); masm.loadPtr(Address(obj, TypedArray::dataOffset()), scratchReg);
@ -3965,6 +4002,11 @@ ICSetElem_TypedArray::Compiler::generateStubCode(MacroAssembler &masm)
// Failure case - jump to next stub // Failure case - jump to next stub
masm.bind(&failure); masm.bind(&failure);
EmitStubGuardFailure(masm); EmitStubGuardFailure(masm);
if (expectOutOfBounds_) {
masm.bind(&oobWrite);
EmitReturnFromIC(masm);
}
return true; return true;
} }

View File

@ -3046,21 +3046,32 @@ class ICSetElem_TypedArray : public ICStub
protected: // Protected to silence Clang warning. protected: // Protected to silence Clang warning.
HeapPtrShape shape_; HeapPtrShape shape_;
ICSetElem_TypedArray(IonCode *stubCode, HandleShape shape, uint32_t type) ICSetElem_TypedArray(IonCode *stubCode, HandleShape shape, uint32_t type,
bool expectOutOfBounds)
: ICStub(SetElem_TypedArray, stubCode), : ICStub(SetElem_TypedArray, stubCode),
shape_(shape) shape_(shape)
{ {
extra_ = uint16_t(type); extra_ = uint8_t(type);
JS_ASSERT(extra_ == type); JS_ASSERT(extra_ == type);
extra_ |= (static_cast<uint16_t>(expectOutOfBounds) << 8);
} }
public: public:
static inline ICSetElem_TypedArray *New(ICStubSpace *space, IonCode *code, static inline ICSetElem_TypedArray *New(ICStubSpace *space, IonCode *code,
HandleShape shape, uint32_t type) HandleShape shape, uint32_t type,
bool expectOutOfBounds)
{ {
if (!code) if (!code)
return NULL; return NULL;
return space->allocate<ICSetElem_TypedArray>(code, shape, type); return space->allocate<ICSetElem_TypedArray>(code, shape, type, expectOutOfBounds);
}
uint32_t type() const {
return extra_ & 0xff;
}
bool expectOutOfBounds() const {
return (extra_ >> 8) & 1;
} }
static size_t offsetOfShape() { static size_t offsetOfShape() {
@ -3074,23 +3085,27 @@ class ICSetElem_TypedArray : public ICStub
class Compiler : public ICStubCompiler { class Compiler : public ICStubCompiler {
RootedShape shape_; RootedShape shape_;
uint32_t type_; uint32_t type_;
bool expectOutOfBounds_;
protected: protected:
bool generateStubCode(MacroAssembler &masm); bool generateStubCode(MacroAssembler &masm);
virtual int32_t getKey() const { virtual int32_t getKey() const {
return static_cast<int32_t>(kind) | (static_cast<int32_t>(type_) << 16); return static_cast<int32_t>(kind) | (static_cast<int32_t>(type_) << 16) |
(static_cast<int32_t>(expectOutOfBounds_) << 24);
} }
public: public:
Compiler(JSContext *cx, UnrootedShape shape, uint32_t type) Compiler(JSContext *cx, UnrootedShape shape, uint32_t type, bool expectOutOfBounds)
: ICStubCompiler(cx, ICStub::SetElem_TypedArray), : ICStubCompiler(cx, ICStub::SetElem_TypedArray),
shape_(cx, shape), shape_(cx, shape),
type_(type) type_(type),
expectOutOfBounds_(expectOutOfBounds)
{} {}
ICStub *getStub(ICStubSpace *space) { ICStub *getStub(ICStubSpace *space) {
return ICSetElem_TypedArray::New(space, getStubCode(), shape_, type_); return ICSetElem_TypedArray::New(space, getStubCode(), shape_, type_,
expectOutOfBounds_);
} }
}; };
}; };