From 814665de9f7327be77ca144277fdb85ef80601b5 Mon Sep 17 00:00:00 2001 From: Brian Hackett Date: Thu, 7 Apr 2011 17:14:15 -0700 Subject: [PATCH] [INFER] Fix cases where dense arrays have initialized length < capacity with disabled inference, bug 648357. --- js/src/jit-test/tests/basic/bug648357.js | 3 ++ js/src/jsarray.cpp | 53 ++++++++++++++++-------- js/src/jsarray.h | 2 + js/src/jsobj.cpp | 6 ++- js/src/methodjit/FrameState.cpp | 2 +- 5 files changed, 46 insertions(+), 20 deletions(-) create mode 100644 js/src/jit-test/tests/basic/bug648357.js diff --git a/js/src/jit-test/tests/basic/bug648357.js b/js/src/jit-test/tests/basic/bug648357.js new file mode 100644 index 00000000000..9c2c939e08a --- /dev/null +++ b/js/src/jit-test/tests/basic/bug648357.js @@ -0,0 +1,3 @@ +var x = [1, 2, 3, 4, 5, 6, 7, 8]; +x.pop(); +x.push(9); diff --git a/js/src/jsarray.cpp b/js/src/jsarray.cpp index e20f21e951d..c71b402e339 100644 --- a/js/src/jsarray.cpp +++ b/js/src/jsarray.cpp @@ -1509,7 +1509,12 @@ InitArrayObject(JSContext *cx, JSObject *obj, jsuint length, const Value *vector /* Avoid ensureDenseArrayElements to skip sparse array checks there. */ if (!obj->ensureSlots(cx, length)) return false; - obj->setDenseArrayInitializedLength(length); + + if (cx->typeInferenceEnabled()) + obj->setDenseArrayInitializedLength(length); + else + obj->backfillDenseArrayHoles(); + bool hole = false; for (jsuint i = 0; i < length; i++) { obj->setDenseArrayElement(i, vector[i]); @@ -1517,6 +1522,7 @@ InitArrayObject(JSContext *cx, JSObject *obj, jsuint length, const Value *vector } if (hole && !obj->setDenseArrayNotPacked(cx)) return false; + return true; } @@ -1583,6 +1589,7 @@ array_reverse(JSContext *cx, uintN argc, Value *vp) /* Fill out the array's initialized length to its proper length. */ jsuint initlen = obj->getDenseArrayInitializedLength(); if (len > initlen) { + JS_ASSERT(cx->typeInferenceEnabled()); if (!obj->setDenseArrayNotPacked(cx)) return false; ClearValueRange(obj->getDenseArrayElements() + initlen, len - initlen, true); @@ -2169,9 +2176,13 @@ ArrayCompPushImpl(JSContext *cx, JSObject *obj, const Value &v) */ if (!obj->ensureSlots(cx, length + 1)) return false; + if (!cx->typeInferenceEnabled()) + obj->backfillDenseArrayHoles(); } + + if (cx->typeInferenceEnabled()) + obj->setDenseArrayInitializedLength(length + 1); obj->setDenseArrayLength(length + 1); - obj->setDenseArrayInitializedLength(length + 1); obj->setDenseArrayElement(length, v); return true; } @@ -2259,9 +2270,16 @@ array_pop_dense(JSContext *cx, JSObject* obj, Value *vp) return JS_FALSE; if (!hole && DeleteArrayElement(cx, obj, index, true) < 0) return JS_FALSE; + obj->setDenseArrayLength(index); - if (index == obj->getDenseArrayInitializedLength() - 1) - obj->setDenseArrayInitializedLength(index); + if (cx->typeInferenceEnabled()) { + JS_ASSERT(!obj->isPackedDenseArray()); + if (index == obj->getDenseArrayInitializedLength() - 1) + obj->setDenseArrayInitializedLength(index); + if (!cx->markTypeArrayShrank(obj->getType())) + return JS_FALSE; + } + return JS_TRUE; } @@ -2294,23 +2312,24 @@ array_shift(JSContext *cx, uintN argc, Value *vp) } else { length--; - if (obj->isDenseArray() && !js_PrototypeHasIndexedProperties(cx, obj)) { - Value *elems = obj->getDenseArrayElements(); - jsuint initlen = obj->getDenseArrayInitializedLength(); - if (initlen > 0) { - *vp = obj->getDenseArrayElement(0); - if (vp->isMagic(JS_ARRAY_HOLE)) { - vp->setUndefined(); - if (!cx->markTypeCallerUnexpected(TYPE_UNDEFINED)) - return JS_FALSE; - } - memmove(elems, elems + 1, (initlen - 1) * sizeof(jsval)); - obj->setDenseArrayInitializedLength(initlen - 1); - } else { + if (obj->isDenseArray() && !js_PrototypeHasIndexedProperties(cx, obj) && + length < obj->getDenseArrayCapacity() && + 0 < obj->getDenseArrayInitializedLength()) { + *vp = obj->getDenseArrayElement(0); + if (vp->isMagic(JS_ARRAY_HOLE)) { vp->setUndefined(); if (!cx->markTypeCallerUnexpected(TYPE_UNDEFINED)) return JS_FALSE; } + Value *elems = obj->getDenseArrayElements(); + memmove(elems, elems + 1, length * sizeof(jsval)); + if (cx->typeInferenceEnabled()) { + obj->setDenseArrayInitializedLength(obj->getDenseArrayInitializedLength() - 1); + if (!cx->markTypeArrayShrank(obj->getType())) + return JS_FALSE; + } else { + obj->setDenseArrayElement(length, MagicValue(JS_ARRAY_HOLE)); + } JS_ALWAYS_TRUE(obj->setArrayLength(cx, length)); if (!js_SuppressDeletedIndexProperties(cx, obj, length, length + 1)) return JS_FALSE; diff --git a/js/src/jsarray.h b/js/src/jsarray.h index 4f47c79637f..8799f3c9f92 100644 --- a/js/src/jsarray.h +++ b/js/src/jsarray.h @@ -105,6 +105,7 @@ JSObject::ensureDenseArrayElements(JSContext *cx, uintN index, uintN extra) if (index < initLength) return ED_OK; if (index < currentCapacity) { + JS_ASSERT(cx->typeInferenceEnabled()); if (index > initLength) { if (!setDenseArrayNotPacked(cx)) return ED_FAILED; @@ -127,6 +128,7 @@ JSObject::ensureDenseArrayElements(JSContext *cx, uintN index, uintN extra) if (requiredCapacity <= initLength) return ED_OK; if (requiredCapacity <= currentCapacity) { + JS_ASSERT(cx->typeInferenceEnabled()); if (index > initLength) { ClearValueRange(getSlots() + initLength, index - initLength, true); if (!setDenseArrayNotPacked(cx)) diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index b87452bd500..625d63771a7 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -4224,8 +4224,10 @@ JSObject::growSlots(JSContext *cx, size_t newcap) slots = tmpslots; capacity = actualCapacity; - /* Initialize the additional slots we added. */ - ClearValueRange(slots + oldcap, actualCapacity - oldcap, isDenseArray()); + if (!isDenseArray()) { + /* Initialize the additional slots we added. This is not required for dense arrays. */ + ClearValueRange(slots + oldcap, actualCapacity - oldcap, false); + } return true; } diff --git a/js/src/methodjit/FrameState.cpp b/js/src/methodjit/FrameState.cpp index bc26d0e0ae9..51494fd91f2 100644 --- a/js/src/methodjit/FrameState.cpp +++ b/js/src/methodjit/FrameState.cpp @@ -747,7 +747,7 @@ FrameState::computeAllocation(jsbytecode *target) continue; if (fe >= spBase && !isTemporary(fe)) continue; - if (isTemporary(fe) && target - script->code > loop->backedgeOffset()) + if (isTemporary(fe) && uint32(target - script->code) > loop->backedgeOffset()) continue; alloc->set(reg, indexOfFe(fe), fe->data.synced()); }