diff --git a/js/src/jit-test/tests/basic/bug951213.js b/js/src/jit-test/tests/basic/bug951213.js new file mode 100644 index 00000000000..4f773cf03b7 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug951213.js @@ -0,0 +1,8 @@ + +setObjectMetadataCallback(function(obj) {}); +function foo(x, y) { + this.g = x + y; +} +var a = 0; +var b = { valueOf: function() Object.defineProperty(Object.prototype, 'g', {}) }; +var c = new foo(a, b); diff --git a/js/src/jsinfer.cpp b/js/src/jsinfer.cpp index 174b22e02aa..c0e203e9f77 100644 --- a/js/src/jsinfer.cpp +++ b/js/src/jsinfer.cpp @@ -3129,8 +3129,10 @@ TypeObject::clearNewScriptAddendum(ExclusiveContext *cx) } } - if (!finished) - obj->rollbackProperties(cx, numProperties); + if (!finished) { + if (!obj->rollbackProperties(cx, numProperties)) + cx->compartment()->types.setPendingNukeTypes(cx); + } } } else { // Threads with an ExclusiveContext are not allowed to run scripts. diff --git a/js/src/jsobj.h b/js/src/jsobj.h index f87c0189941..46fe7e8e5fd 100644 --- a/js/src/jsobj.h +++ b/js/src/jsobj.h @@ -416,7 +416,7 @@ class JSObject : public js::ObjectImpl elements[i].js::HeapSlot::~HeapSlot(); } - void rollbackProperties(js::ExclusiveContext *cx, uint32_t slotSpan); + bool rollbackProperties(js::ExclusiveContext *cx, uint32_t slotSpan); void nativeSetSlot(uint32_t slot, const js::Value &value) { JS_ASSERT(isNative()); diff --git a/js/src/vm/Shape.cpp b/js/src/vm/Shape.cpp index 7765e87b4cd..ca61fd65024 100644 --- a/js/src/vm/Shape.cpp +++ b/js/src/vm/Shape.cpp @@ -1156,7 +1156,7 @@ JSObject::clear(JSContext *cx, HandleObject obj) obj->checkShapeConsistency(); } -void +bool JSObject::rollbackProperties(ExclusiveContext *cx, uint32_t slotSpan) { /* @@ -1165,10 +1165,21 @@ JSObject::rollbackProperties(ExclusiveContext *cx, uint32_t slotSpan) * removal of the last properties. */ JS_ASSERT(!inDictionaryMode() && slotSpan <= this->slotSpan()); - while (this->slotSpan() != slotSpan) { - JS_ASSERT(lastProperty()->hasSlot() && getSlot(lastProperty()->slot()).isUndefined()); - removeLastProperty(cx); + while (true) { + if (lastProperty()->isEmptyShape()) { + JS_ASSERT(slotSpan == 0); + break; + } else { + uint32_t slot = lastProperty()->slot(); + if (slot < slotSpan) + break; + JS_ASSERT(getSlot(slot).isUndefined()); + } + if (!removeProperty(cx, lastProperty()->propid())) + return false; } + + return true; } Shape *