Bug 829896 - Make typed array element accesses return undefined if the element is out of bounds, rather than accessing the prototype chain r=jandem

This commit is contained in:
Nicholas D. Matsakis 2013-07-09 15:29:39 -04:00
parent c92f991c16
commit 07257e7a4c
11 changed files with 20 additions and 87 deletions

View File

@ -6363,43 +6363,25 @@ CodeGenerator::visitLoadTypedArrayElement(LLoadTypedArrayElement *lir)
return true; return true;
} }
class OutOfLineLoadTypedArray : public OutOfLineCodeBase<CodeGenerator>
{
LLoadTypedArrayElementHole *ins_;
public:
OutOfLineLoadTypedArray(LLoadTypedArrayElementHole *ins)
: ins_(ins)
{ }
bool accept(CodeGenerator *codegen) {
return codegen->visitOutOfLineLoadTypedArray(this);
}
LLoadTypedArrayElementHole *ins() const {
return ins_;
}
};
bool bool
CodeGenerator::visitLoadTypedArrayElementHole(LLoadTypedArrayElementHole *lir) CodeGenerator::visitLoadTypedArrayElementHole(LLoadTypedArrayElementHole *lir)
{ {
Register object = ToRegister(lir->object()); Register object = ToRegister(lir->object());
const ValueOperand out = ToOutValue(lir); const ValueOperand out = ToOutValue(lir);
OutOfLineLoadTypedArray *ool = new OutOfLineLoadTypedArray(lir);
if (!addOutOfLineCode(ool))
return false;
// Load the length. // Load the length.
Register scratch = out.scratchReg(); Register scratch = out.scratchReg();
Int32Key key = ToInt32Key(lir->index()); Int32Key key = ToInt32Key(lir->index());
masm.unboxInt32(Address(object, TypedArrayObject::lengthOffset()), scratch); masm.unboxInt32(Address(object, TypedArrayObject::lengthOffset()), scratch);
// OOL path if index >= length. // Load undefined unless length > key.
masm.branchKey(Assembler::BelowOrEqual, scratch, key, ool->entry()); Label inbounds, done;
masm.branchKey(Assembler::Above, scratch, key, &inbounds);
masm.moveValue(UndefinedValue(), out);
masm.jump(&done);
// Load the elements vector. // Load the elements vector.
masm.bind(&inbounds);
masm.loadPtr(Address(object, TypedArrayObject::dataOffset()), scratch); masm.loadPtr(Address(object, TypedArrayObject::dataOffset()), scratch);
int arrayType = lir->mir()->arrayType(); int arrayType = lir->mir()->arrayType();
@ -6419,35 +6401,7 @@ CodeGenerator::visitLoadTypedArrayElementHole(LLoadTypedArrayElementHole *lir)
if (fail.used() && !bailoutFrom(&fail, lir->snapshot())) if (fail.used() && !bailoutFrom(&fail, lir->snapshot()))
return false; return false;
masm.bind(ool->rejoin()); masm.bind(&done);
return true;
}
typedef bool (*GetElementMonitoredFn)(JSContext *, MutableHandleValue, HandleValue, MutableHandleValue);
static const VMFunction GetElementMonitoredInfo =
FunctionInfo<GetElementMonitoredFn>(js::GetElementMonitored);
bool
CodeGenerator::visitOutOfLineLoadTypedArray(OutOfLineLoadTypedArray *ool)
{
LLoadTypedArrayElementHole *ins = ool->ins();
saveLive(ins);
Register object = ToRegister(ins->object());
ValueOperand out = ToOutValue(ins);
if (ins->index()->isConstant())
pushArg(*ins->index()->toConstant());
else
pushArg(TypedOrValueRegister(MIRType_Int32, ToAnyRegister(ins->index())));
pushArg(TypedOrValueRegister(MIRType_Object, AnyRegister(object)));
if (!callVM(GetElementMonitoredInfo, ins))
return false;
masm.storeCallResultValue(out);
restoreLive(ins);
masm.jump(ool->rejoin());
return true; return true;
} }

View File

@ -212,7 +212,6 @@ class CodeGenerator : public CodeGeneratorSpecific
bool visitClampIToUint8(LClampIToUint8 *lir); bool visitClampIToUint8(LClampIToUint8 *lir);
bool visitClampDToUint8(LClampDToUint8 *lir); bool visitClampDToUint8(LClampDToUint8 *lir);
bool visitClampVToUint8(LClampVToUint8 *lir); bool visitClampVToUint8(LClampVToUint8 *lir);
bool visitOutOfLineLoadTypedArray(OutOfLineLoadTypedArray *ool);
bool visitCallIteratorStart(LCallIteratorStart *lir); bool visitCallIteratorStart(LCallIteratorStart *lir);
bool visitIteratorStart(LIteratorStart *lir); bool visitIteratorStart(LIteratorStart *lir);
bool visitIteratorNext(LIteratorNext *lir); bool visitIteratorNext(LIteratorNext *lir);

View File

@ -6666,7 +6666,7 @@ IonBuilder::jsop_getelem_typed(int arrayType)
current->add(load); current->add(load);
current->push(load); current->push(load);
return resumeAfter(load) && pushTypeBarrier(load, types, needsBarrier); return pushTypeBarrier(load, types, needsBarrier);
} }
} }

View File

@ -5001,9 +5001,7 @@ class MLoadTypedArrayElementHole
return getOperand(1); return getOperand(1);
} }
AliasSet getAliasSet() const { AliasSet getAliasSet() const {
// Out-of-bounds accesses are handled using a VM call, this may return AliasSet::Load(AliasSet::TypedArrayElement);
// invoke getters on the prototype chain.
return AliasSet::Store(AliasSet::Any);
} }
}; };

View File

@ -14,6 +14,9 @@ function f1() {
f1(); f1();
function f2() { function f2() {
// Test that values on the prototype are ignored,
// even for OOB accesses. This behavior is new
// with ECMA 6 (see bug 829896).
Object.prototype[50] = 4.4; Object.prototype[50] = 4.4;
Object.prototype[55] = Math; Object.prototype[55] = Math;
@ -22,10 +25,6 @@ function f2() {
var x = a[i]; var x = a[i];
if (i < a.length) if (i < a.length)
assertEq(x, 0); assertEq(x, 0);
else if (i === 50)
assertEq(x, 4.4);
else if (i === 55)
assertEq(x, Math);
else else
assertEq(x, undefined); assertEq(x, undefined);
} }

View File

@ -5,7 +5,7 @@ function test()
for (var i = 0, sz = 9; i < sz; i++) for (var i = 0, sz = 9; i < sz; i++)
{ {
var ta = new Int8Array(); var ta = new Int8Array();
assertEq(ta[0], r); assertEq(ta[0], undefined);
} }
} }
test(); test();

View File

@ -11,8 +11,6 @@ function test1() {
assertEq(res, 0xffffee00); assertEq(res, 0xffffee00);
else if (i == 84) else if (i == 84)
assertEq(res, 444); assertEq(res, 444);
else if (i == 105)
assertEq(res, true);
else if (i >= 100) else if (i >= 100)
assertEq(res, undefined); assertEq(res, undefined);
} }

View File

@ -0,0 +1,4 @@
x = Uint8ClampedArray()
ParallelArray([320], function() {
return x[8]
})

View File

@ -3706,17 +3706,6 @@ js::GetElement(JSContext *cx, MutableHandleValue lref, HandleValue rref, Mutable
return GetElementOperation(cx, JSOP_GETELEM, lref, rref, vp); return GetElementOperation(cx, JSOP_GETELEM, lref, rref, vp);
} }
bool
js::GetElementMonitored(JSContext *cx, MutableHandleValue lref, HandleValue rref,
MutableHandleValue vp)
{
if (!GetElement(cx, lref, rref, vp))
return false;
TypeScript::Monitor(cx, vp);
return true;
}
bool bool
js::CallElement(JSContext *cx, MutableHandleValue lref, HandleValue rref, MutableHandleValue res) js::CallElement(JSContext *cx, MutableHandleValue lref, HandleValue rref, MutableHandleValue res)
{ {

View File

@ -415,9 +415,6 @@ Lambda(JSContext *cx, HandleFunction fun, HandleObject parent);
bool bool
GetElement(JSContext *cx, MutableHandleValue lref, HandleValue rref, MutableHandleValue res); GetElement(JSContext *cx, MutableHandleValue lref, HandleValue rref, MutableHandleValue res);
bool
GetElementMonitored(JSContext *cx, MutableHandleValue lref, HandleValue rref, MutableHandleValue res);
bool bool
CallElement(JSContext *cx, MutableHandleValue lref, HandleValue rref, MutableHandleValue res); CallElement(JSContext *cx, MutableHandleValue lref, HandleValue rref, MutableHandleValue res);

View File

@ -1442,13 +1442,8 @@ class TypedArrayObjectTemplate : public TypedArrayObject
return true; return true;
} }
RootedObject proto(cx, tarray->getProto()); vp.setUndefined();
if (!proto) { return true;
vp.setUndefined();
return true;
}
return JSObject::getElement(cx, proto, receiver, index, vp);
} }
static JSBool static JSBool