Bug 1092833 - Deal with uninitialized slots in MacroAssembler::initGCSlots. r=terrence

This commit is contained in:
Shu-yu Guo 2014-11-05 08:12:44 -05:00
parent b80158ee9e
commit 0a14cd0584
3 changed files with 111 additions and 12 deletions

View File

@ -0,0 +1,49 @@
// Test that lexicals work with functions with many bindings.
(function() {
var a01
var b02
var c03
var d04
var e05
var f06
var g07
var h08
let i09
var j10
var k11
var l12
var m13
var n14
var o15
(function n14() {
assertEq(i09, undefined);
})()
})();
try {
(function() {
var a01
var b02
var c03
var d04
var e05
var f06
var g07
var h08
let i09
var j10
var k11
var l12
var m13
var n14
var o15
(function n14() {
i12++
})()
let i12
})()
} catch (e) {
assertEq(e instanceof ReferenceError, true);
assertEq(e.message.indexOf("i12") > 0, true);
}

View File

@ -27,6 +27,7 @@
#endif
#include "jsinferinlines.h"
#include "jsobjinlines.h"
#include "vm/Interpreter-inl.h"
using namespace js;
using namespace js::jit;
@ -956,12 +957,18 @@ MacroAssembler::copySlotsFromTemplate(Register obj, const NativeObject *template
}
void
MacroAssembler::fillSlotsWithUndefined(Address base, Register temp, uint32_t start, uint32_t end)
MacroAssembler::fillSlotsWithConstantValue(Address base, Register temp,
uint32_t start, uint32_t end, const Value &v)
{
MOZ_ASSERT(v.isUndefined() || IsUninitializedLexical(v));
if (start >= end)
return;
#ifdef JS_NUNBOX32
// We only have a single spare register, so do the initialization as two
// strided writes of the tag and body.
jsval_layout jv = JSVAL_TO_IMPL(UndefinedValue());
jsval_layout jv = JSVAL_TO_IMPL(v);
Address addr = base;
move32(Imm32(jv.s.payload.i32), temp);
@ -973,22 +980,43 @@ MacroAssembler::fillSlotsWithUndefined(Address base, Register temp, uint32_t sta
for (unsigned i = start; i < end; ++i, addr.offset += sizeof(HeapValue))
store32(temp, ToType(addr));
#else
moveValue(UndefinedValue(), temp);
moveValue(v, temp);
for (uint32_t i = start; i < end; ++i, base.offset += sizeof(HeapValue))
storePtr(temp, base);
#endif
}
static uint32_t
FindStartOfUndefinedSlots(NativeObject *templateObj, uint32_t nslots)
void
MacroAssembler::fillSlotsWithUndefined(Address base, Register temp, uint32_t start, uint32_t end)
{
fillSlotsWithConstantValue(base, temp, start, end, UndefinedValue());
}
void
MacroAssembler::fillSlotsWithUninitialized(Address base, Register temp, uint32_t start, uint32_t end)
{
fillSlotsWithConstantValue(base, temp, start, end, MagicValue(JS_UNINITIALIZED_LEXICAL));
}
static void
FindStartOfUndefinedAndUninitializedSlots(NativeObject *templateObj, uint32_t nslots,
uint32_t *startOfUndefined, uint32_t *startOfUninitialized)
{
MOZ_ASSERT(nslots == templateObj->lastProperty()->slotSpan(templateObj->getClass()));
MOZ_ASSERT(nslots > 0);
for (uint32_t first = nslots; first != 0; --first) {
if (templateObj->getSlot(first - 1) != UndefinedValue())
return first;
uint32_t first = nslots;
for (; first != 0; --first) {
if (!IsUninitializedLexical(templateObj->getSlot(first - 1)))
break;
}
return 0;
*startOfUninitialized = first;
for (; first != 0; --first) {
if (templateObj->getSlot(first - 1) != UndefinedValue()) {
*startOfUndefined = first;
return;
}
}
*startOfUndefined = 0;
}
void
@ -1011,16 +1039,28 @@ MacroAssembler::initGCSlots(Register obj, Register slots, NativeObject *template
// logically into independent non-UndefinedValue writes to the head and
// duplicated writes of UndefinedValue to the tail. For the majority of
// objects, the "tail" will be the entire slot range.
uint32_t startOfUndefined = FindStartOfUndefinedSlots(templateObj, nslots);
//
// The template object may be a CallObject, in which case we need to
// account for uninitialized lexical slots as well as undefined
// slots. Unitialized lexical slots always appear at the very end of
// slots, after undefined.
uint32_t startOfUndefined = nslots;
uint32_t startOfUninitialized = nslots;
FindStartOfUndefinedAndUninitializedSlots(templateObj, nslots,
&startOfUndefined, &startOfUninitialized);
MOZ_ASSERT(startOfUndefined <= nfixed); // Reserved slots must be fixed.
MOZ_ASSERT_IF(startOfUndefined != nfixed, startOfUndefined <= startOfUninitialized);
MOZ_ASSERT_IF(!templateObj->is<CallObject>(), startOfUninitialized == nslots);
// Copy over any preserved reserved slots.
copySlotsFromTemplate(obj, templateObj, 0, startOfUndefined);
// Fill the rest of the fixed slots with undefined.
// Fill the rest of the fixed slots with undefined and uninitialized.
if (initFixedSlots) {
fillSlotsWithUndefined(Address(obj, NativeObject::getFixedSlotOffset(startOfUndefined)), slots,
startOfUndefined, nfixed);
startOfUndefined, Min(startOfUninitialized, nfixed));
size_t offset = NativeObject::getFixedSlotOffset(startOfUninitialized);
fillSlotsWithUninitialized(Address(obj, offset), slots, startOfUninitialized, nfixed);
}
if (ndynamic) {
@ -1028,7 +1068,14 @@ MacroAssembler::initGCSlots(Register obj, Register slots, NativeObject *template
// register briefly for our slots base address.
push(obj);
loadPtr(Address(obj, NativeObject::offsetOfSlots()), obj);
// Initially fill all dynamic slots with undefined.
fillSlotsWithUndefined(Address(obj, 0), slots, 0, ndynamic);
// Fill uninitialized slots if necessary.
fillSlotsWithUninitialized(Address(obj, 0), slots, startOfUninitialized - nfixed,
nslots - startOfUninitialized);
pop(obj);
}
}

View File

@ -810,7 +810,10 @@ class MacroAssembler : public MacroAssemblerSpecific
void allocateNonObject(Register result, Register temp, gc::AllocKind allocKind, Label *fail);
void copySlotsFromTemplate(Register obj, const NativeObject *templateObj,
uint32_t start, uint32_t end);
void fillSlotsWithConstantValue(Address addr, Register temp, uint32_t start, uint32_t end,
const Value &v);
void fillSlotsWithUndefined(Address addr, Register temp, uint32_t start, uint32_t end);
void fillSlotsWithUninitialized(Address addr, Register temp, uint32_t start, uint32_t end);
void initGCSlots(Register obj, Register temp, NativeObject *templateObj, bool initFixedSlots);
public: