☠☠ backed out by 3c88f1fc617c ☠ ☠ | |
author | Shu-yu Guo <shu@rfrn.org> |
Tue, 04 Nov 2014 16:52:38 -0800 | |
changeset 214025 | 5e6d8b6023e32f464ac8595969531f40b5113c05 |
parent 214024 | d95e85773aa64e8efec26b623cbaf34e48d2aa8f |
child 214026 | 13d940a1c8a0953678ea05359d89ffbe22be7edd |
push id | 27771 |
push user | ryanvm@gmail.com |
push date | Wed, 05 Nov 2014 19:04:24 +0000 |
treeherder | mozilla-central@305b4fecce99 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | terrence |
bugs | 1092833 |
milestone | 36.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
new file mode 100644 --- /dev/null +++ b/js/src/jit-test/tests/ion/bug1092833.js @@ -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); +}
--- a/js/src/jit/IonMacroAssembler.cpp +++ b/js/src/jit/IonMacroAssembler.cpp @@ -22,16 +22,17 @@ #include "vm/ForkJoin.h" #include "vm/TraceLogging.h" #ifdef JSGC_GENERATIONAL # include "jsgcinlines.h" #endif #include "jsinferinlines.h" #include "jsobjinlines.h" +#include "vm/Interpreter-inl.h" using namespace js; using namespace js::jit; using JS::GenericNaN; namespace { @@ -951,49 +952,76 @@ MacroAssembler::copySlotsFromTemplate(Re uint32_t start, uint32_t end) { uint32_t nfixed = Min(templateObj->numFixedSlots(), end); for (unsigned i = start; i < nfixed; i++) storeValue(templateObj->getFixedSlot(i), Address(obj, NativeObject::getFixedSlotOffset(i))); } 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); for (unsigned i = start; i < end; ++i, addr.offset += sizeof(HeapValue)) store32(temp, ToPayload(addr)); addr = base; move32(Imm32(jv.s.tag), temp); 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 MacroAssembler::initGCSlots(Register obj, Register slots, NativeObject *templateObj, bool initFixedSlots) { // Slots of non-array objects are required to be initialized. // Use the values currently in the template object. @@ -1006,34 +1034,53 @@ MacroAssembler::initGCSlots(Register obj // Attempt to group slot writes such that we minimize the amount of // duplicated data we need to embed in code and load into registers. In // general, most template object slots will be undefined except for any // reserved slots. Since reserved slots come first, we split the object // 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) { // We are short one register to do this elegantly. Borrow the obj // 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); } } void MacroAssembler::initGCThing(Register obj, Register slots, JSObject *templateObj, bool initFixedSlots) {
--- a/js/src/jit/IonMacroAssembler.h +++ b/js/src/jit/IonMacroAssembler.h @@ -805,17 +805,20 @@ class MacroAssembler : public MacroAssem void nurseryAllocate(Register result, Register slots, gc::AllocKind allocKind, size_t nDynamicSlots, gc::InitialHeap initialHeap, Label *fail); void freeListAllocate(Register result, Register temp, gc::AllocKind allocKind, Label *fail); void allocateObject(Register result, Register slots, gc::AllocKind allocKind, uint32_t nDynamicSlots, gc::InitialHeap initialHeap, Label *fail); 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: void callMallocStub(size_t nbytes, Register result, Label *fail); void callFreeStub(Register slots); void createGCObject(Register result, Register temp, JSObject *templateObj, gc::InitialHeap initialHeap, Label *fail, bool initFixedSlots = true);