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,13 +3416,38 @@ DenseSetElemStubExists(JSContext *cx, ICStub::Kind kind, ICSetElem_Fallback *stu
}
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()) {
if (!cur->isSetElem_TypedArray())
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 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;
}
@ -3600,19 +3625,29 @@ DoSetElemFallback(JSContext *cx, BaselineFrame *frame, ICSetElem_Fallback *stub,
return true;
}
if (obj->isTypedArray() &&
index.isInt32() && rhs.isNumber() &&
!TypedArraySetElemStubExists(stub, obj))
{
IonSpew(IonSpew_BaselineIC, " Generating SetElem_TypedArray stub (shape=%p, type=%u)",
obj->lastProperty(), TypedArray::type(obj));
ICSetElem_TypedArray::Compiler compiler(cx, obj->lastProperty(), TypedArray::type(obj));
ICStub *typedArrayStub = compiler.getStub(compiler.getStubSpace(script));
if (!typedArrayStub)
return false;
if (obj->isTypedArray() && index.isInt32() && rhs.isNumber()) {
uint32_t len = TypedArray::length(obj);
int32_t idx = index.toInt32();
bool expectOutOfBounds = (idx < 0) || (static_cast<uint32_t>(idx) >= len);
stub->addNewStub(typedArrayStub);
return true;
if (!TypedArraySetElemStubExists(stub, obj, expectOutOfBounds)) {
// 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));
if (!typedArrayStub)
return false;
stub->addNewStub(typedArrayStub);
return true;
}
}
return true;
@ -3897,8 +3932,10 @@ ICSetElem_TypedArray::Compiler::generateStubCode(MacroAssembler &masm)
Register key = masm.extractInt32(R1, ExtractTemp1);
// Bounds check.
Label oobWrite;
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.
masm.loadPtr(Address(obj, TypedArray::dataOffset()), scratchReg);
@ -3965,6 +4002,11 @@ ICSetElem_TypedArray::Compiler::generateStubCode(MacroAssembler &masm)
// Failure case - jump to next stub
masm.bind(&failure);
EmitStubGuardFailure(masm);
if (expectOutOfBounds_) {
masm.bind(&oobWrite);
EmitReturnFromIC(masm);
}
return true;
}

View File

@ -3046,21 +3046,32 @@ class ICSetElem_TypedArray : public ICStub
protected: // Protected to silence Clang warning.
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),
shape_(shape)
{
extra_ = uint16_t(type);
extra_ = uint8_t(type);
JS_ASSERT(extra_ == type);
extra_ |= (static_cast<uint16_t>(expectOutOfBounds) << 8);
}
public:
static inline ICSetElem_TypedArray *New(ICStubSpace *space, IonCode *code,
HandleShape shape, uint32_t type)
HandleShape shape, uint32_t type,
bool expectOutOfBounds)
{
if (!code)
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() {
@ -3074,23 +3085,27 @@ class ICSetElem_TypedArray : public ICStub
class Compiler : public ICStubCompiler {
RootedShape shape_;
uint32_t type_;
bool expectOutOfBounds_;
protected:
bool generateStubCode(MacroAssembler &masm);
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:
Compiler(JSContext *cx, UnrootedShape shape, uint32_t type)
Compiler(JSContext *cx, UnrootedShape shape, uint32_t type, bool expectOutOfBounds)
: ICStubCompiler(cx, ICStub::SetElem_TypedArray),
shape_(cx, shape),
type_(type)
type_(type),
expectOutOfBounds_(expectOutOfBounds)
{}
ICStub *getStub(ICStubSpace *space) {
return ICSetElem_TypedArray::New(space, getStubCode(), shape_, type_);
return ICSetElem_TypedArray::New(space, getStubCode(), shape_, type_,
expectOutOfBounds_);
}
};
};