From c036e81169d82dde519e994f0049ed2e4f8c68c0 Mon Sep 17 00:00:00 2001 From: Jeff Walden Date: Fri, 12 Nov 2010 16:15:55 -0800 Subject: [PATCH] Bug 599464 - Object.preventExtensions should be idempotent. r=brendan --- js/src/jsobj.cpp | 7 +++-- js/src/jsobj.h | 10 ++++--- js/src/tests/ecma_5/Object/jstests.list | 1 + .../Object/preventExtensions-idempotent.js | 30 +++++++++++++++++++ 4 files changed, 42 insertions(+), 6 deletions(-) create mode 100644 js/src/tests/ecma_5/Object/preventExtensions-idempotent.js diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index 5ccb9558ba9f..e8b1062f437c 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -2542,15 +2542,18 @@ obj_preventExtensions(JSContext *cx, uintN argc, Value *vp) return false; vp->setObject(*obj); + if (!obj->isExtensible()) + return true; AutoIdVector props(cx); return obj->preventExtensions(cx, &props); } bool -JSObject::sealOrFreeze(JSContext *cx, bool freeze) +JSObject::sealOrFreeze(JSContext *cx, ImmutabilityType it) { assertSameCompartment(cx, this); + JS_ASSERT(it == SEAL || it == FREEZE); AutoIdVector props(cx); if (isExtensible()) { @@ -2573,7 +2576,7 @@ JSObject::sealOrFreeze(JSContext *cx, bool freeze) /* Make all attributes permanent; if freezing, make data attributes read-only. */ uintN new_attrs; - if (freeze && !(attrs & (JSPROP_GETTER | JSPROP_SETTER))) + if (it == FREEZE && !(attrs & (JSPROP_GETTER | JSPROP_SETTER))) new_attrs = JSPROP_PERMANENT | JSPROP_READONLY; else new_attrs = JSPROP_PERMANENT; diff --git a/js/src/jsobj.h b/js/src/jsobj.h index c60c942b427e..89da8ba9a67f 100644 --- a/js/src/jsobj.h +++ b/js/src/jsobj.h @@ -708,22 +708,24 @@ struct JSObject : js::gc::Cell { */ private: + enum ImmutabilityType { SEAL, FREEZE }; + /* * The guts of Object.seal (ES5 15.2.3.8) and Object.freeze (ES5 15.2.3.9): mark the * object as non-extensible, and adjust each property's attributes appropriately: each * property becomes non-configurable, and if |freeze|, data properties become * read-only as well. */ - bool sealOrFreeze(JSContext *cx, bool freeze = false); + bool sealOrFreeze(JSContext *cx, ImmutabilityType it); public: bool isExtensible() const { return !(flags & NOT_EXTENSIBLE); } bool preventExtensions(JSContext *cx, js::AutoIdVector *props); - + /* ES5 15.2.3.8: non-extensible, all props non-configurable */ - inline bool seal(JSContext *cx) { return sealOrFreeze(cx); } + inline bool seal(JSContext *cx) { return sealOrFreeze(cx, SEAL); } /* ES5 15.2.3.9: non-extensible, all properties non-configurable, all data props read-only */ - bool freeze(JSContext *cx) { return sealOrFreeze(cx, true); } + bool freeze(JSContext *cx) { return sealOrFreeze(cx, FREEZE); } /* * Primitive-specific getters and setters. diff --git a/js/src/tests/ecma_5/Object/jstests.list b/js/src/tests/ecma_5/Object/jstests.list index 4c11d45682c7..019cfe990360 100644 --- a/js/src/tests/ecma_5/Object/jstests.list +++ b/js/src/tests/ecma_5/Object/jstests.list @@ -41,3 +41,4 @@ script object-toString-01.js script vacuous-accessor-unqualified-name.js script add-property-non-extensible.js skip-if(!xulRuntime.shell) script freeze-global-eval-const.js # uses evalcx +script preventExtensions-idempotent.js diff --git a/js/src/tests/ecma_5/Object/preventExtensions-idempotent.js b/js/src/tests/ecma_5/Object/preventExtensions-idempotent.js new file mode 100644 index 000000000000..c0b16d890f6c --- /dev/null +++ b/js/src/tests/ecma_5/Object/preventExtensions-idempotent.js @@ -0,0 +1,30 @@ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + * Contributor: + * Jeff Walden + */ + +var gTestfile = 'preventExtensions-idempotent.js'; +//----------------------------------------------------------------------------- +var BUGNUMBER = 599459; +var summary = 'Object.preventExtensions should be idempotent'; + +print(BUGNUMBER + ": " + summary); + +/************** + * BEGIN TEST * + **************/ + +var obj = {}; +assertEq(Object.preventExtensions(obj), obj); +assertEq(Object.isExtensible(obj), false); +assertEq(Object.preventExtensions(obj), obj); +assertEq(Object.isExtensible(obj), false); + +/******************************************************************************/ + +if (typeof reportCompare === "function") + reportCompare(true, true); + +print("All tests passed!");