Bug 492849 - Implement Object.preventExtensions, Object.isExtensible. a=waldo,jimb, r=brendan

--HG--
rename : js/src/jsapi-tests/testSeal.cpp => js/src/jsapi-tests/testDeepFreeze.cpp
This commit is contained in:
Jim Blandy 2010-09-21 11:35:29 -07:00
Родитель ff464b7c97
Коммит 1623508e26
37 изменённых файлов: 489 добавлений и 257 удалений

Просмотреть файл

@ -561,8 +561,7 @@ InitCTypeClass(JSContext* cx, JSObject* parent)
!JS_DefineFunctions(cx, prototype, sCTypeFunctions))
return NULL;
if (!JS_SealObject(cx, ctor, JS_FALSE) ||
!JS_SealObject(cx, prototype, JS_FALSE))
if (!JS_FreezeObject(cx, ctor) || !JS_FreezeObject(cx, prototype))
return NULL;
return prototype;
@ -603,8 +602,8 @@ InitCDataClass(JSContext* cx, JSObject* parent, JSObject* CTypeProto)
!JS_DefineFunctions(cx, prototype, sCDataFunctions))
return NULL;
if (//!JS_SealObject(cx, prototype, JS_FALSE) || // XXX fixme - see bug 541212!
!JS_SealObject(cx, ctor, JS_FALSE))
if (//!JS_FreezeObject(cx, prototype) || // XXX fixme - see bug 541212!
!JS_FreezeObject(cx, ctor))
return NULL;
return prototype;
@ -622,7 +621,7 @@ DefineABIConstant(JSContext* cx,
return false;
if (!JS_SetReservedSlot(cx, obj, SLOT_ABICODE, INT_TO_JSVAL(code)))
return false;
return JS_SealObject(cx, obj, JS_FALSE);
return JS_FreezeObject(cx, obj);
}
// Set up a single type constructor for
@ -692,9 +691,9 @@ InitTypeConstructor(JSContext* cx,
if (instanceProps && !JS_DefineProperties(cx, dataProto, instanceProps))
return false;
if (!JS_SealObject(cx, obj, JS_FALSE) ||
//!JS_SealObject(cx, dataProto, JS_FALSE) || // XXX fixme - see bug 541212!
!JS_SealObject(cx, typeProto, JS_FALSE))
if (!JS_FreezeObject(cx, obj) ||
//!JS_FreezeObject(cx, dataProto) || // XXX fixme - see bug 541212!
!JS_FreezeObject(cx, typeProto))
return false;
return true;
@ -717,7 +716,7 @@ InitInt64Class(JSContext* cx,
JSObject* ctor = JS_GetConstructor(cx, prototype);
if (!ctor)
return NULL;
if (!JS_SealObject(cx, ctor, JS_FALSE))
if (!JS_FreezeObject(cx, ctor))
return NULL;
// Stash ctypes.{Int64,UInt64}.prototype on a reserved slot of the 'join'
@ -728,7 +727,7 @@ InitInt64Class(JSContext* cx,
OBJECT_TO_JSVAL(prototype)))
return NULL;
if (!JS_SealObject(cx, prototype, JS_FALSE))
if (!JS_FreezeObject(cx, prototype))
return NULL;
return prototype;
@ -958,7 +957,7 @@ JS_InitCTypesClass(JSContext* cx, JSObject* global)
return false;
// Seal the ctypes object, to prevent modification.
return JS_SealObject(cx, ctypes, JS_FALSE);
return JS_FreezeObject(cx, ctypes);
}
JS_PUBLIC_API(JSBool)
@ -2638,12 +2637,12 @@ CType::Create(JSContext* cx,
return NULL;
// Set the 'prototype' object.
if (//!JS_SealObject(cx, prototype, JS_FALSE) || // XXX fixme - see bug 541212!
if (//!JS_FreezeObject(cx, prototype) || // XXX fixme - see bug 541212!
!JS_SetReservedSlot(cx, typeObj, SLOT_PROTO, OBJECT_TO_JSVAL(prototype)))
return NULL;
}
if (!JS_SealObject(cx, typeObj, JS_FALSE))
if (!JS_FreezeObject(cx, typeObj))
return NULL;
// Assert a sanity check on size and alignment: size % alignment should always
@ -3953,7 +3952,7 @@ AddFieldToArray(JSContext* cx,
JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT))
return false;
return JS_SealObject(cx, fieldObj, JS_FALSE);
return JS_FreezeObject(cx, fieldObj);
}
JSBool
@ -4114,7 +4113,7 @@ StructType::DefineInternal(JSContext* cx, JSObject* typeObj, JSObject* fieldsObj
if (!JS_SetReservedSlot(cx, typeObj, SLOT_SIZE, sizeVal) ||
!JS_SetReservedSlot(cx, typeObj, SLOT_ALIGN, INT_TO_JSVAL(structAlign)) ||
//!JS_SealObject(cx, prototype, JS_FALSE) || // XXX fixme - see bug 541212!
//!JS_FreezeObject(cx, prototype) || // XXX fixme - see bug 541212!
!JS_SetReservedSlot(cx, typeObj, SLOT_PROTO, OBJECT_TO_JSVAL(prototype)))
return JS_FALSE;
@ -4363,7 +4362,7 @@ StructType::BuildFieldsArray(JSContext* cx, JSObject* obj)
return NULL;
// Seal the fields array.
if (!JS_SealObject(cx, fieldsProp, JS_FALSE))
if (!JS_FreezeObject(cx, fieldsProp))
return NULL;
return fieldsProp;
@ -4901,8 +4900,8 @@ FunctionType::ConstructData(JSContext* cx,
// having to do things like reset SLOT_REFERENT when someone tries to
// change the pointer value.
// XXX This will need to change when bug 541212 is fixed -- CData::ValueSetter
// could be called on a sealed object.
return JS_SealObject(cx, dataObj, JS_FALSE);
// could be called on a frozen object.
return JS_FreezeObject(cx, dataObj);
}
typedef Array<AutoValue, 16> AutoValueAutoArray;
@ -5118,7 +5117,7 @@ FunctionType::ArgTypesGetter(JSContext* cx, JSObject* obj, jsid idval, jsval* vp
return JS_FALSE;
// Seal and cache it.
if (!JS_SealObject(cx, argTypes, JS_FALSE) ||
if (!JS_FreezeObject(cx, argTypes) ||
!JS_SetReservedSlot(cx, obj, SLOT_ARGS_T, OBJECT_TO_JSVAL(argTypes)))
return JS_FALSE;
@ -5818,7 +5817,7 @@ Int64Base::Construct(JSContext* cx,
return NULL;
}
if (!JS_SealObject(cx, result, JS_FALSE))
if (!JS_FreezeObject(cx, result))
return NULL;
return result;

Просмотреть файл

@ -373,7 +373,7 @@ Library::Declare(JSContext* cx, uintN argc, jsval* vp)
// change the pointer value.
// XXX This will need to change when bug 541212 is fixed -- CData::ValueSetter
// could be called on a sealed object.
if (isFunction && !JS_SealObject(cx, result, JS_FALSE))
if (isFunction && !JS_FreezeObject(cx, result))
return JS_FALSE;
return JS_TRUE;

Просмотреть файл

@ -338,3 +338,4 @@ MSG_DEF(JSMSG_NOT_EXPECTED_TYPE, 255, 3, JSEXN_TYPEERR, "{0}: expected {1},
MSG_DEF(JSMSG_CALLER_IS_STRICT, 256, 0, JSEXN_TYPEERR, "access to strict mode caller function is censored")
MSG_DEF(JSMSG_NEED_DEBUG_MODE, 257, 0, JSEXN_ERR, "function can be called only in debug mode")
MSG_DEF(JSMSG_STRICT_CODE_LET_EXPR_STMT, 258, 0, JSEXN_ERR, "strict mode code may not contain unparenthesized let expression statements")
MSG_DEF(JSMSG_CANT_CHANGE_EXTENSIBILITY, 259, 0, JSEXN_TYPEERR, "can't change object's extensibility")

Просмотреть файл

@ -53,23 +53,23 @@ CPPSRCS = \
testConservativeGC.cpp \
testContexts.cpp \
testDebugger.cpp \
testDeepFreeze.cpp \
testDefineGetterSetterNonEnumerable.cpp \
testDefineProperty.cpp \
testExtendedEq.cpp \
testGCChunkAlloc.cpp \
testFuncCallback.cpp \
testGCChunkAlloc.cpp \
testIntString.cpp \
testIsAboutToBeFinalized.cpp \
testLookup.cpp \
testNewObject.cpp \
testOps.cpp \
testPropCache.cpp \
testTrap.cpp \
testSameValue.cpp \
testSeal.cpp \
testXDR.cpp \
testSetPropertyWithNativeGetterStubSetter.cpp \
testScriptObject.cpp \
testSetPropertyWithNativeGetterStubSetter.cpp \
testTrap.cpp \
testXDR.cpp \
$(NULL)
DEFINES += -DEXPORT_JS_API

Просмотреть файл

@ -4,11 +4,11 @@
#include "tests.h"
BEGIN_TEST(testSeal_bug535703)
BEGIN_TEST(testDeepFreeze_bug535703)
{
JSObject *obj = JS_NewObject(cx, NULL, NULL, NULL);
CHECK(obj);
JS_SealObject(cx, obj, JS_TRUE); // don't crash
JS_DeepFreezeObject(cx, obj); // don't crash
return true;
}
END_TEST(testSeal_bug535703)
END_TEST(testDeepFreeze_bug535703)

Просмотреть файл

@ -3007,51 +3007,38 @@ JS_NewObjectForConstructor(JSContext *cx, const jsval *vp)
}
JS_PUBLIC_API(JSBool)
JS_SealObject(JSContext *cx, JSObject *obj, JSBool deep)
JS_FreezeObject(JSContext *cx, JSObject *obj)
{
CHECK_REQUEST(cx);
assertSameCompartment(cx, obj);
/* Nothing to do if obj is already sealed. */
if (obj->sealed())
return obj->freeze(cx);
}
JS_PUBLIC_API(JSBool)
JS_DeepFreezeObject(JSContext *cx, JSObject *obj)
{
CHECK_REQUEST(cx);
assertSameCompartment(cx, obj);
/* Assume that non-extensible objects are already deep-frozen, to avoid divergence. */
if (obj->isExtensible())
return true;
if (obj->isDenseArray() && !obj->makeDenseArraySlow(cx))
if (!obj->freeze(cx))
return false;
if (!obj->isNative()) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
JSMSG_CANT_SEAL_OBJECT,
obj->getClass()->name);
return false;
}
#ifdef JS_THREADSAFE
/* Insist on scope being used exclusively by cx's thread. */
JS_ASSERT(obj->title.ownercx == cx);
#endif
/* XXX Enumerate lazy properties now, as they can't be added later. */
JSIdArray *ida = JS_Enumerate(cx, obj);
if (!ida)
return false;
JS_DestroyIdArray(cx, ida);
/* If not sealing an entire object graph, we're done after sealing obj. */
obj->seal(cx);
if (!deep)
return true;
/* Walk slots in obj and if any value is a non-null object, seal it. */
for (uint32 i = 0, n = obj->slotSpan(); i != n; ++i) {
for (uint32 i = 0, n = obj->slotSpan(); i < n; ++i) {
const Value &v = obj->getSlot(i);
if (i == JSSLOT_PRIVATE && (obj->getClass()->flags & JSCLASS_HAS_PRIVATE))
continue;
if (v.isPrimitive())
continue;
if (!JS_SealObject(cx, &v.toObject(), deep))
if (!JS_DeepFreezeObject(cx, &v.toObject()))
return false;
}
return true;
}

Просмотреть файл

@ -1928,8 +1928,19 @@ extern JS_PUBLIC_API(JSObject *)
JS_NewObjectWithGivenProto(JSContext *cx, JSClass *clasp, JSObject *proto,
JSObject *parent);
/*
* Freeze obj, and all objects it refers to, recursively. This will not recurse
* through non-extensible objects, on the assumption that those are already
* deep-frozen.
*/
extern JS_PUBLIC_API(JSBool)
JS_SealObject(JSContext *cx, JSObject *obj, JSBool deep);
JS_DeepFreezeObject(JSContext *cx, JSObject *obj);
/*
* Freezes an object; see ES5's Object.freeze(obj) method.
*/
extern JS_PUBLIC_API(JSBool)
JS_FreezeObject(JSContext *cx, JSObject *obj);
extern JS_PUBLIC_API(JSObject *)
JS_ConstructObject(JSContext *cx, JSClass *clasp, JSObject *proto,

Просмотреть файл

@ -630,7 +630,7 @@ array_length_setter(JSContext *cx, JSObject *obj, jsid id, Value *vp, JSBool str
Value junk;
/* Check for a sealed object first. */
if (obj->sealed()) {
if (!obj->isExtensible()) {
return js_ReportValueErrorFlags(cx, JSREPORT_ERROR, JSMSG_READ_ONLY,
JSDVG_IGNORE_STACK, IdToValue(id), NULL,
NULL, NULL);
@ -1003,6 +1003,27 @@ array_trace(JSTracer *trc, JSObject *obj)
}
}
namespace {
JSBool
array_fix(JSContext *cx, JSObject *obj, bool *success, AutoIdVector *props)
{
JS_ASSERT(obj->isDenseArray());
/*
* We must slowify dense arrays; otherwise, we'd need to detect assignments to holes,
* since that is effectively adding a new property to the array.
*/
if (!obj->makeDenseArraySlow(cx) ||
!GetPropertyNames(cx, obj, JSITER_HIDDEN | JSITER_OWNONLY, props))
return false;
*success = true;
return true;
}
} // namespace
Class js_ArrayClass = {
"Array",
Class::NON_NATIVE |
@ -1035,6 +1056,7 @@ Class js_ArrayClass = {
NULL, /* enumerate */
array_typeOf,
array_trace,
array_fix,
NULL, /* thisObject */
NULL, /* clear */
}

Просмотреть файл

@ -4046,7 +4046,7 @@ BEGIN_CASE(JSOP_SETMETHOD)
JSObject *obj2;
JSAtom *atom;
if (cache->testForSet(cx, regs.pc, obj, &entry, &obj2, &atom)) {
JS_ASSERT(!obj->sealed());
JS_ASSERT(obj->isExtensible());
/*
* Fast property cache hit, only partially confirmed by
@ -4155,7 +4155,7 @@ BEGIN_CASE(JSOP_SETMETHOD)
if (obj == obj2) {
shape = entry->vword.toShape();
JS_ASSERT(shape->writable());
JS_ASSERT(!obj2->sealed());
JS_ASSERT(obj2->isExtensible());
NATIVE_SET(cx, obj, shape, entry, &rval);
}
if (shape)

Просмотреть файл

@ -676,13 +676,13 @@ js_GetSlotThreadSafe(JSContext *cx, JSObject *obj, uint32 slot)
JS_ASSERT(obj->containsSlot(slot));
/*
* Avoid locking if called from the GC. Also avoid locking a sealed
* Avoid locking if called from the GC. Also avoid locking a non-extensible
* object. If neither of those special cases applies, try to claim obj's
* flyweight lock from whatever context may have had it in an earlier
* request.
*/
if (CX_THREAD_IS_RUNNING_GC(cx) ||
obj->sealed() ||
!obj->isExtensible() ||
(obj->title.ownercx && ClaimTitle(&obj->title, cx))) {
return Jsvalify(obj->getSlot(slot));
}
@ -754,13 +754,13 @@ js_SetSlotThreadSafe(JSContext *cx, JSObject *obj, uint32 slot, jsval v)
JS_ASSERT(obj->containsSlot(slot));
/*
* Avoid locking if called from the GC. Also avoid locking a sealed
* Avoid locking if called from the GC. Also avoid locking a non-extensible
* object. If neither of those special cases applies, try to claim obj's
* flyweight lock from whatever context may have had it in an earlier
* request.
*/
if (CX_THREAD_IS_RUNNING_GC(cx) ||
obj->sealed() ||
!obj->isExtensible() ||
(obj->title.ownercx && ClaimTitle(&obj->title, cx))) {
obj->lockedSetSlot(slot, Valueify(v));
return;
@ -1245,7 +1245,7 @@ js_LockObj(JSContext *cx, JSObject *obj)
if (CX_THREAD_IS_RUNNING_GC(cx))
return;
if (obj->sealed() && !cx->thread->lockedSealedTitle) {
if (!obj->isExtensible() && !cx->thread->lockedSealedTitle) {
cx->thread->lockedSealedTitle = &obj->title;
return;
}
@ -1311,7 +1311,7 @@ js_IsTitleLocked(JSContext *cx, JSTitle *title)
if (CX_THREAD_IS_RUNNING_GC(cx))
return JS_TRUE;
/* Special case: locked object is sealed (ES5 frozen) -- see js_LockObj. */
/* Special case: locked object is not extensible -- see js_LockObj. */
if (cx->thread->lockedSealedTitle == title)
return JS_TRUE;

Просмотреть файл

@ -150,6 +150,12 @@ obj_getProto(JSContext *cx, JSObject *obj, jsid id, Value *vp)
static JSBool
obj_setProto(JSContext *cx, JSObject *obj, jsid id, Value *vp)
{
/* ECMAScript 5 8.6.2 forbids changing [[Prototype]] if not [[Extensible]]. */
if (!obj->isExtensible()) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_OBJECT_NOT_EXTENSIBLE);
return false;
}
if (!vp->isObjectOrNull())
return JS_TRUE;
@ -1999,7 +2005,7 @@ DefinePropertyOnObject(JSContext *cx, JSObject *obj, const PropDesc &desc,
/* 8.12.9 steps 2-4. */
if (!current) {
if (obj->sealed())
if (!obj->isExtensible())
return Reject(cx, JSMSG_OBJECT_NOT_EXTENSIBLE, throwError, rval);
*rval = true;
@ -2519,6 +2525,72 @@ obj_getOwnPropertyNames(JSContext *cx, uintN argc, Value *vp)
return true;
}
static JSBool
obj_isExtensible(JSContext *cx, uintN argc, Value *vp)
{
JSObject *obj;
if (!GetFirstArgumentAsObject(cx, argc, vp, "Object.isExtensible", &obj))
return false;
vp->setBoolean(obj->isExtensible());
return true;
}
static JSBool
obj_preventExtensions(JSContext *cx, uintN argc, Value *vp)
{
JSObject *obj;
if (!GetFirstArgumentAsObject(cx, argc, vp, "Object.preventExtensions", &obj))
return false;
vp->setObject(*obj);
AutoIdVector props(cx);
return obj->preventExtensions(cx, &props);
}
bool
JSObject::sealOrFreeze(JSContext *cx, bool freeze)
{
assertSameCompartment(cx, this);
AutoIdVector props(cx);
if (isExtensible()) {
if (!preventExtensions(cx, &props))
return false;
} else {
if (!GetPropertyNames(cx, this, JSITER_HIDDEN | JSITER_OWNONLY, &props))
return false;
}
/* preventExtensions must slowify dense arrays, so we can assign to holes without checks. */
JS_ASSERT(!isDenseArray());
for (size_t i = 0, len = props.length(); i < len; i++) {
jsid id = props[i];
uintN attrs;
if (!getAttributes(cx, id, &attrs))
return false;
/* Make all attributes permanent; if freezing, make data attributes read-only. */
uintN new_attrs;
if (freeze && !(attrs & (JSPROP_GETTER | JSPROP_SETTER)))
new_attrs = JSPROP_PERMANENT | JSPROP_READONLY;
else
new_attrs = JSPROP_PERMANENT;
/* If we already have the attributes we need, skip the setAttributes call. */
if ((attrs | new_attrs) == attrs)
continue;
attrs |= new_attrs;
if (!setAttributes(cx, id, &attrs))
return false;
}
return true;
}
#if JS_HAS_OBJ_WATCHPOINT
const char js_watch_str[] = "watch";
@ -2559,6 +2631,8 @@ static JSFunctionSpec object_static_methods[] = {
JS_FN("defineProperties", obj_defineProperties, 2,0),
JS_FN("create", obj_create, 2,0),
JS_FN("getOwnPropertyNames", obj_getOwnPropertyNames, 1,0),
JS_FN("isExtensible", obj_isExtensible, 1,0),
JS_FN("preventExtensions", obj_preventExtensions, 1,0),
JS_FS_END
};
@ -2914,9 +2988,10 @@ Class js_WithClass = {
with_DeleteProperty,
with_Enumerate,
with_TypeOf,
NULL, /* trace */
NULL, /* trace */
NULL, /* fix */
with_ThisObject,
NULL, /* clear */
NULL, /* clear */
}
};
@ -3631,6 +3706,7 @@ bool
SetProto(JSContext *cx, JSObject *obj, JSObject *proto, bool checkForCycles)
{
JS_ASSERT_IF(!checkForCycles, obj != proto);
JS_ASSERT(obj->isExtensible());
if (obj->isNative()) {
JS_LOCK_OBJ(cx, obj);
@ -4948,6 +5024,13 @@ ReportNotConfigurable(JSContext* cx, jsid id, uintN flags)
NULL, NULL);
}
JSBool
ReportNotExtensible(JSContext* cx, uintN flags)
{
return JS_ReportErrorFlagsAndNumber(cx, flags, js_GetErrorMessage, NULL,
JSMSG_OBJECT_NOT_EXTENSIBLE);
}
}
/*
@ -4977,10 +5060,6 @@ js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, uintN defineHow,
/* Convert string indices to integers if appropriate. */
id = js_CheckForStringIndex(id);
/* Check for a sealed object first (now that id has been normalized). */
if (obj->sealed())
return ReportReadOnly(cx, id, JSREPORT_ERROR);
protoIndex = js_LookupPropertyWithFlags(cx, obj, id, cx->resolveFlags,
&pobj, &prop);
if (protoIndex < 0)
@ -5049,10 +5128,6 @@ js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, uintN defineHow,
#endif
}
}
if (pobj->sealed() && !shape->hasSlot()) {
JS_UNLOCK_OBJ(cx, pobj);
return ReportReadOnly(cx, id, JSREPORT_ERROR);
}
attrs = shape->attributes();
if (pobj != obj) {
@ -5127,6 +5202,16 @@ js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, uintN defineHow,
added = false;
if (!shape) {
if (!obj->isExtensible()) {
/* Error in strict mode code, warn with strict option, otherwise do nothing. */
if (strict)
return ReportNotExtensible(cx, 0);
if (JS_HAS_STRICT_OPTION(cx))
return ReportNotExtensible(cx, JSREPORT_STRICT | JSREPORT_WARNING);
else
return JS_TRUE;
}
/*
* Purge the property cache of now-shadowed id in obj's scope chain.
* Do this early, before locking obj to avoid nesting locks.
@ -6315,12 +6400,13 @@ js_DumpObject(JSObject *obj)
uint32 flags = obj->flags;
if (flags & JSObject::DELEGATE) fprintf(stderr, " delegate");
if (flags & JSObject::SYSTEM) fprintf(stderr, " system");
if (flags & JSObject::SEALED) fprintf(stderr, " sealed");
if (flags & JSObject::NOT_EXTENSIBLE) fprintf(stderr, " not extensible");
if (flags & JSObject::BRANDED) fprintf(stderr, " branded");
if (flags & JSObject::GENERIC) fprintf(stderr, " generic");
if (flags & JSObject::METHOD_BARRIER) fprintf(stderr, " method_barrier");
if (flags & JSObject::INDEXED) fprintf(stderr, " indexed");
if (flags & JSObject::OWN_SHAPE) fprintf(stderr, " own_shape");
bool anyFlags = flags != 0;
if (obj->isNative()) {
if (obj->inDictionaryMode()) {
@ -6349,9 +6435,6 @@ js_DumpObject(JSObject *obj)
}
if (obj->isNative()) {
if (obj->sealed())
fprintf(stderr, "sealed\n");
fprintf(stderr, "properties:\n");
for (Shape::Range r = obj->lastProperty()->all(); !r.empty(); r.popFront())
DumpShape(r.front());

Просмотреть файл

@ -321,12 +321,12 @@ struct JSObject {
inline bool nativeContains(const js::Shape &shape);
enum {
DELEGATE = 0x01,
SYSTEM = 0x02,
SEALED = 0x04,
BRANDED = 0x08,
GENERIC = 0x10,
METHOD_BARRIER = 0x20,
DELEGATE = 0x01,
SYSTEM = 0x02,
NOT_EXTENSIBLE = 0x04,
BRANDED = 0x08,
GENERIC = 0x10,
METHOD_BARRIER = 0x20,
INDEXED = 0x40,
OWN_SHAPE = 0x80,
BOUND_FUNCTION = 0x100
@ -399,14 +399,6 @@ struct JSObject {
bool isSystem() const { return !!(flags & SYSTEM); }
void setSystem() { flags |= SYSTEM; }
/*
* Don't define clearSealed, as it can't be done safely because JS_LOCK_OBJ
* will avoid taking the lock if the object owns its scope and the scope is
* sealed.
*/
bool sealed() { return !!(flags & SEALED); }
void seal(JSContext *cx);
/*
* A branded object contains plain old methods (function-valued properties
* without magic getters and setters), and its shape evolves whenever a
@ -448,6 +440,11 @@ struct JSObject {
void shadowingShapeChange(JSContext *cx, const js::Shape &shape);
bool globalObjectOwnShapeChange(JSContext *cx);
void extensibleShapeChange(JSContext *cx) {
/* This will do for now. */
generateOwnShape(cx);
}
/*
* A scope has a method barrier when some compiler-created "null closure"
* function objects (functions that do not use lexical bindings above their
@ -673,6 +670,29 @@ struct JSObject {
*(void **)&fslots[JSSLOT_PRIVATE] = data;
}
/*
* ES5 meta-object properties and operations.
*/
private:
/*
* 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);
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); }
/* ES5 15.2.3.9: non-extensible, all properties non-configurable, all data props read-only */
bool freeze(JSContext *cx) { return sealOrFreeze(cx, true); }
/*
* Primitive-specific getters and setters.
*/

Просмотреть файл

@ -68,13 +68,29 @@ JSObject::dropProperty(JSContext *cx, JSProperty *prop)
JS_UNLOCK_OBJ(cx, this);
}
inline void
JSObject::seal(JSContext *cx)
inline bool
JSObject::preventExtensions(JSContext *cx, js::AutoIdVector *props)
{
JS_ASSERT(!sealed());
JS_ASSERT(isExtensible());
if (js::FixOp fix = getOps()->fix) {
bool success;
if (!fix(cx, this, &success, props))
return false;
if (!success) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_CHANGE_EXTENSIBILITY);
return false;
}
} else {
if (!GetPropertyNames(cx, this, JSITER_HIDDEN | JSITER_OWNONLY, props))
return false;
}
if (isNative())
generateOwnShape(cx);
flags |= SEALED;
extensibleShapeChange(cx);
flags |= NOT_EXTENSIBLE;
return true;
}
inline bool

Просмотреть файл

@ -134,7 +134,7 @@ PropertyCache::testForInit(JSRuntime *rt, jsbytecode *pc, JSObject *obj,
const js::Shape **shapep, PropertyCacheEntry **entryp)
{
JS_ASSERT(obj->slotSpan() >= JSSLOT_FREE(obj->getClass()));
JS_ASSERT(!obj->sealed());
JS_ASSERT(obj->isExtensible());
uint32 kshape = obj->shape();
PropertyCacheEntry *entry = &table[hash(pc, kshape)];
*entryp = entry;

Просмотреть файл

@ -945,6 +945,7 @@ JS_FRIEND_API(Class) ObjectProxyClass = {
NULL, /* enumerate */
NULL, /* typeof */
proxy_TraceObject,
NULL, /* fix */
NULL, /* thisObject */
proxy_Finalize, /* clear */
}
@ -985,6 +986,7 @@ JS_FRIEND_API(Class) OuterWindowProxyClass = {
NULL, /* enumerate */
NULL, /* typeof */
proxy_TraceObject,
NULL, /* fix */
NULL, /* thisObject */
proxy_Finalize, /* clear */
}
@ -1047,6 +1049,7 @@ JS_FRIEND_API(Class) FunctionProxyClass = {
NULL, /* enumerate */
proxy_TypeOf_fun,
proxy_TraceObject,
NULL, /* fix */
NULL, /* thisObject */
NULL, /* clear */
}

Просмотреть файл

@ -720,17 +720,6 @@ JSObject::addProperty(JSContext *cx, jsid id,
{
JS_ASSERT(!JSID_IS_VOID(id));
/*
* You can't add properties to a sealed object. But note well that you can
* change property attributes in a sealed object, even though that replaces
* a Shape * in the scope's hash table -- but no id is added, so the object
* remains sealed.
*/
if (sealed()) {
reportReadOnlyScope(cx);
return NULL;
}
NormalizeGetterAndSetter(cx, this, id, attrs, flags, getter, setter);
/* Search for id with adding = true in order to claim its entry. */
@ -746,6 +735,15 @@ JSObject::addPropertyCommon(JSContext *cx, jsid id,
uintN flags, intN shortid,
Shape **spp)
{
/*
* You can't add properties to a non-extensible object, but you can change
* attributes of properties in such objects.
*/
if (!isExtensible()) {
reportReadOnlyScope(cx);
return NULL;
}
PropertyTable *table = NULL;
if (!inDictionaryMode()) {
if (lastProp->entryCount() >= PropertyTree::MAX_HEIGHT) {
@ -828,11 +826,6 @@ JSObject::putProperty(JSContext *cx, jsid id,
JS_ASSERT(!JSID_IS_VOID(id));
if (sealed()) {
reportReadOnlyScope(cx);
return NULL;
}
NormalizeGetterAndSetter(cx, this, id, attrs, flags, getter, setter);
/* Search for id in order to claim its entry if table has been allocated. */
@ -1041,11 +1034,6 @@ JSObject::changeProperty(JSContext *cx, const Shape *shape, uintN attrs, uintN m
bool
JSObject::removeProperty(JSContext *cx, jsid id)
{
if (sealed()) {
reportReadOnlyScope(cx);
return false;
}
Shape **spp = nativeSearch(id);
Shape *shape = SHAPE_FETCH(spp);
if (!shape) {

Просмотреть файл

@ -786,9 +786,8 @@ class TypedArrayTemplate
return false;
}
makeFastWithPrivate(cx, obj, tarray);
rval->setObject(*obj);
return true;
return makeFastWithPrivate(cx, obj, tarray);
}
static void
@ -868,10 +867,8 @@ class TypedArrayTemplate
return false;
}
makeFastWithPrivate(cx, nobj, ntarray);
vp->setObject(*nobj);
return true;
return makeFastWithPrivate(cx, nobj, ntarray);
}
/* set(array[, offset]) */
@ -962,13 +959,16 @@ class TypedArrayTemplate
}
// helper used by both the constructor and Slice()
static void
static bool
makeFastWithPrivate(JSContext *cx, JSObject *obj, ThisTypeArray *tarray)
{
JS_ASSERT(obj->getClass() == slowClass());
obj->setSharedNonNativeMap();
obj->clasp = fastClass();
obj->setPrivate(tarray);
AutoIdVector props(cx);
return obj->preventExtensions(cx, &props);
}
public:

Просмотреть файл

@ -882,6 +882,18 @@ typedef JSBool
typedef JSBool
(* CallOp)(JSContext *cx, uintN argc, Value *vp);
class AutoIdVector;
/*
* Prepare to make |obj| non-extensible; in particular, fully resolve its properties.
* On error, return false.
* If |obj| is now ready to become non-extensible, set |*fixed| to true and return true.
* If |obj| refuses to become non-extensible, set |*fixed| to false and return true; the
* caller will throw an appropriate error.
*/
typedef JSBool
(* FixOp)(JSContext *cx, JSObject *obj, bool *fixed, AutoIdVector *props);
static inline Native Valueify(JSNative f) { return (Native)f; }
static inline JSNative Jsvalify(Native f) { return (JSNative)f; }
static inline PropertyOp Valueify(JSPropertyOp f) { return (PropertyOp)f; }
@ -957,6 +969,7 @@ struct ObjectOps {
js::NewEnumerateOp enumerate;
JSTypeOfOp typeOf;
JSTraceOp trace;
js::FixOp fix;
JSObjectOp thisObject;
JSFinalizeOp clear;
};

Просмотреть файл

@ -4881,6 +4881,14 @@ xml_trace(JSTracer *trc, JSObject *obj)
JS_CALL_TRACER(trc, xml, JSTRACE_XML, "private");
}
static JSBool
xml_fix(JSContext *cx, JSObject *obj, bool *success, AutoIdVector *props)
{
JS_ASSERT(obj->isExtensible());
*success = false;
return true;
}
static void
xml_clear(JSContext *cx, JSObject *obj)
{
@ -5100,6 +5108,7 @@ JS_FRIEND_DATA(Class) js_XMLClass = {
xml_enumerate,
xml_typeOf,
NULL, /* trace */
xml_fix,
NULL, /* thisObject */
xml_clear
}

Просмотреть файл

@ -559,8 +559,6 @@ class SetPropCompiler : public PICStubCompiler
return disable("dense array");
if (!obj->isNative())
return disable("non-native");
if (obj->sealed())
return disable("sealed");
Class *clasp = obj->getClass();
@ -590,8 +588,6 @@ class SetPropCompiler : public PICStubCompiler
if (!holder->isNative())
return disable("non-native holder");
if (holder->sealed())
return disable("sealed holder");
if (!shape->writable())
return disable("readonly");

Просмотреть файл

@ -141,7 +141,7 @@ stubs::SetName(VMFrame &f, JSAtom *origAtom)
JSObject *obj2;
JSAtom *atom;
if (cache->testForSet(cx, f.regs.pc, obj, &entry, &obj2, &atom)) {
JS_ASSERT(!obj->sealed());
JS_ASSERT(obj->isExtensible());
/*
* Fast property cache hit, only partially confirmed by
@ -248,7 +248,7 @@ stubs::SetName(VMFrame &f, JSAtom *origAtom)
if (obj == obj2) {
shape = entry->vword.toShape();
JS_ASSERT(shape->writable());
JS_ASSERT(!obj2->sealed());
JS_ASSERT(obj2->isExtensible());
NATIVE_SET(cx, obj, shape, entry, &rval);
}
if (shape)

Просмотреть файл

@ -60,7 +60,7 @@ pm_construct(JSContext* cx, uintN argc, jsval* vp)
if (!obj)
return JS_FALSE;
if (!JS_SealObject(cx, obj, JS_FALSE))
if (!JS_FreezeObject(cx, obj))
return JS_FALSE;
PerfMeasurement* p = new PerfMeasurement(PerfMeasurement::EventMask(mask));
@ -269,8 +269,8 @@ RegisterPerfMeasurement(JSContext *cx, JSObject *global)
return 0;
}
if (!JS_SealObject(cx, prototype, JS_FALSE) ||
!JS_SealObject(cx, ctor, JS_FALSE)) {
if (!JS_FreezeObject(cx, prototype) ||
!JS_FreezeObject(cx, ctor)) {
return 0;
}

Просмотреть файл

@ -761,7 +761,7 @@ ProcessArgs(JSContext *cx, JSObject *obj, char **argv, int argc)
if (JS_GET_CLASS(cx, JS_GetPrototype(cx, obj)) != &global_class) {
JSObject *gobj;
if (!JS_SealObject(cx, obj, JS_TRUE))
if (!JS_DeepFreezeObject(cx, obj))
return JS_FALSE;
gobj = JS_NewGlobalObject(cx, &global_class);
if (!gobj)
@ -2564,20 +2564,6 @@ Clone(JSContext *cx, uintN argc, jsval *vp)
return JS_TRUE;
}
static JSBool
Seal(JSContext *cx, uintN argc, jsval *vp)
{
JSObject *target;
JSBool deep = JS_FALSE;
if (!JS_ConvertArguments(cx, argc, JS_ARGV(cx, vp), "o/b", &target, &deep))
return JS_FALSE;
JS_SET_RVAL(cx, vp, JSVAL_VOID);
if (!target)
return JS_TRUE;
return JS_SealObject(cx, target, deep);
}
static JSBool
GetPDA(JSContext *cx, uintN argc, jsval *vp)
{
@ -3025,6 +3011,7 @@ static Class split_global_class = {
NULL, /* enumerate */
NULL, /* typeOf */
NULL, /* trace */
NULL, /* fix */
split_thisObject,
NULL, /* clear */
},
@ -4182,7 +4169,6 @@ static JSFunctionSpec shell_functions[] = {
JS_FN("clear", Clear, 0,0),
JS_FN("intern", Intern, 1,0),
JS_FN("clone", Clone, 1,0),
JS_FN("seal", Seal, 1,0),
JS_FN("getpda", GetPDA, 1,0),
JS_FN("getslx", GetSLX, 1,0),
JS_FN("toint32", ToInt32, 1,0),
@ -4300,7 +4286,6 @@ static const char *const shell_help_messages[] = {
"clear([obj]) Clear properties of object",
"intern(str) Internalize str in the atom table",
"clone(fun[, scope]) Clone function object",
"seal(obj[, deep]) Seal object, or object graph if deep",
"getpda(obj) Get the property descriptors for obj",
"getslx(obj) Get script line extent",
"toint32(n) Testing hook for JS_ValueToInt32",

Просмотреть файл

@ -0,0 +1,42 @@
/*
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/licenses/publicdomain/
* Contributor:
* Jeff Walden <jwalden+code@mit.edu>
*/
var gTestfile = 'extensibility.js';
//-----------------------------------------------------------------------------
var BUGNUMBER = 492849;
var summary = 'XML values cannot have their [[Extensible]] property changed';
print(BUGNUMBER + ": " + summary);
/**************
* BEGIN TEST *
**************/
var x = <foo/>;
assertEq(Object.isExtensible(x), true);
try
{
Object.preventExtensions(x);
throw new Error("didn't throw");
}
catch (e)
{
assertEq(e instanceof TypeError, true,
"xmlValue.[[Extensible]] cannot be changed");
}
assertEq(Object.isExtensible(x), true);
/******************************************************************************/
if (typeof reportCompare === "function")
reportCompare(true, true);
print("All tests passed!");

Просмотреть файл

@ -20,4 +20,5 @@ script regress-410192.js
script regress-450871-01.js
script regress-450871-02.js
script regress-462734-01.js
script extensibility.js
script regress-595207.js

Просмотреть файл

@ -0,0 +1,103 @@
/*
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/licenses/publicdomain/
* Contributor:
* Jeff Walden <jwalden+code@mit.edu>
*/
var gTestfile = '15.2.3.10-01.js';
//-----------------------------------------------------------------------------
var BUGNUMBER = 492849;
var summary = 'ES5: Implement Object.preventExtensions, Object.isExtensible';
print(BUGNUMBER + ": " + summary);
/**************
* BEGIN TEST *
**************/
function trySetProperty(o, p, v, strict)
{
function strictSetProperty()
{
"use strict";
o[p] = v;
}
function setProperty()
{
o[p] = v;
}
assertEq(Object.prototype.hasOwnProperty.call(o, p), false);
try
{
if (strict)
strictSetProperty();
else
setProperty();
if (o[p] === v)
return "set";
if (p in o)
return "set-converted";
return "swallowed";
}
catch (e)
{
return "throw";
}
}
function tryDefineProperty(o, p, v)
{
assertEq(Object.prototype.hasOwnProperty.call(o, p), false);
try
{
Object.defineProperty(o, p, { value: v });
if (o[p] === v)
return "set";
if (p in o)
return "set-converted";
return "swallowed";
}
catch (e)
{
return "throw";
}
}
assertEq(typeof Object.preventExtensions, "function");
assertEq(Object.preventExtensions.length, 1);
var slowArray = [1, 2, 3];
slowArray.slow = 5;
var objs =
[{}, { 1: 2 }, { a: 3 }, [], [1], [, 1], slowArray, function a(){}, /a/];
for (var i = 0, sz = objs.length; i < sz; i++)
{
var o = objs[i];
assertEq(Object.isExtensible(o), true, "object " + i + " not extensible?");
var o2 = Object.preventExtensions(o);
assertEq(o, o2);
assertEq(Object.isExtensible(o), false, "object " + i + " is extensible?");
assertEq(trySetProperty(o, "baz", 17, true), "throw",
"unexpected behavior for strict-mode property-addition to " +
"object " + i);
assertEq(trySetProperty(o, "baz", 17, false), "swallowed",
"unexpected behavior for property-addition to object " + i);
assertEq(tryDefineProperty(o, "baz", 17), "throw",
"unexpected behavior for new property definition on object " + i);
}
/******************************************************************************/
reportCompare(true, true);
print("All tests passed!");

Просмотреть файл

@ -0,0 +1,42 @@
/*
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/licenses/publicdomain/
* Contributor:
* Jeff Walden <jwalden+code@mit.edu>
*/
var gTestfile = '15.2.3.4-01.js';
//-----------------------------------------------------------------------------
var BUGNUMBER = 492849;
var summary = 'ES5: Implement Object.preventExtensions, Object.isExtensible';
print(BUGNUMBER + ": " + summary);
/**************
* BEGIN TEST *
**************/
assertEq(typeof Object.isExtensible, "function");
assertEq(Object.isExtensible.length, 1);
var slowArray = [1, 2, 3];
slowArray.slow = 5;
var objs =
[{}, { 1: 2 }, { a: 3 }, [], [1], [, 1], slowArray, function a(){}, /a/];
for (var i = 0, sz = objs.length; i < sz; i++)
{
var o = objs[i];
assertEq(Object.isExtensible(o), true, "object " + i + " not extensible?");
var o2 = Object.preventExtensions(o);
assertEq(o, o2);
assertEq(Object.isExtensible(o), false, "object " + i + " is extensible?");
}
/******************************************************************************/
reportCompare(true, true);
print("All tests passed!");

Просмотреть файл

@ -14,6 +14,8 @@ skip-if(!xulRuntime.shell) script 15.2.3.6-redefinition-2-of-4.js # uses shell l
skip-if(!xulRuntime.shell) script 15.2.3.6-redefinition-3-of-4.js # uses shell load() function
skip-if(!xulRuntime.shell) script 15.2.3.6-redefinition-4-of-4.js # uses shell load() function
script 15.2.3.7-01.js
script extensibility-01.js
script extensibility-02.js
script 15.2.3.14-01.js # does not use reportCompare
skip-if(!xulRuntime.shell) script 15.2.3.6-middle-redefinition-1-of-8.js # uses shell load() function
skip-if(!xulRuntime.shell) script 15.2.3.6-middle-redefinition-2-of-8.js # uses shell load() function

Просмотреть файл

@ -189,7 +189,6 @@ skip script regress-437288-01.js # obsolete test
script regress-44009.js
script regress-443569.js
script regress-446386.js
script regress-449657.js
script regress-452168.js
script regress-452178.js
script regress-452329.js

Просмотреть файл

@ -1,91 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is JavaScript Engine testing utilities.
*
* The Initial Developer of the Original Code is
* Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2008
* the Initial Developer. All Rights Reserved.
*
* Contributor(s): Christopher Lenz
* ash_mozilla
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
//-----------------------------------------------------------------------------
var BUGNUMBER = 449657;
var summary = 'JS_SealObject on Arrays';
var actual = '';
var expect = '';
//-----------------------------------------------------------------------------
test();
//-----------------------------------------------------------------------------
function test()
{
enterFunc ('test');
printBugNumber(BUGNUMBER);
printStatus (summary);
if (typeof seal != 'function')
{
expect = actual = 'JS_SealObject not supported, test skipped.';
reportCompare(expect, actual, summary);
}
else
{
try
{
var a= [1, 2, 3];
seal(a);
}
catch(ex)
{
actual = ex + '';
}
reportCompare(expect, actual, summary + ': 1');
expect = 'TypeError: a.length is read-only';
actual = '';
try
{
a = [1,2,3];
a[4] = 2;
seal(a);
a.length = 5;
}
catch(ex)
{
actual = ex + '';
}
reportCompare(expect, actual, summary + ': 2');
}
exitFunc ('test');
}

Просмотреть файл

@ -1263,7 +1263,7 @@ ProcessArgs(JSContext *cx, JSObject *obj, char **argv, int argc)
if (JS_GET_CLASS(cx, JS_GetPrototype(cx, obj)) != &global_class) {
JSObject *gobj;
if (!JS_SealObject(cx, obj, JS_TRUE))
if (!JS_DeepFreezeObject(cx, obj))
return JS_FALSE;
gobj = JS_NewGlobalObject(cx, &global_class);
if (!gobj)

Просмотреть файл

@ -1035,7 +1035,7 @@ XPCNativeWrapper::AttachNewConstructorObject(XPCCallContext &ccx,
// Make sure our prototype chain is empty and that people can't mess
// with XPCNativeWrapper.prototype.
::JS_SetPrototype(ccx, class_obj, nsnull);
if (!::JS_SealObject(ccx, class_obj, JS_FALSE)) {
if (!::JS_FreezeObject(ccx, class_obj)) {
NS_WARNING("Failed to seal XPCNativeWrapper.prototype");
return PR_FALSE;
}

Просмотреть файл

@ -370,7 +370,7 @@ AttachNewConstructorObject(XPCCallContext &ccx, JSObject *aGlobalObject)
// Make sure our prototype chain is empty and that people can't mess
// with XPCSafeJSObjectWrapper.prototype.
::JS_SetPrototype(ccx, class_obj, nsnull);
if (!::JS_SealObject(ccx, class_obj, JS_FALSE)) {
if (!::JS_FreezeObject(ccx, class_obj)) {
NS_WARNING("Failed to seal XPCSafeJSObjectWrapper.prototype");
return PR_FALSE;
}

Просмотреть файл

@ -1317,6 +1317,7 @@ XPC_WN_JSOp_ThisObject(JSContext *cx, JSObject *obj);
js::Valueify(XPC_WN_JSOp_Enumerate), \
XPC_WN_JSOp_TypeOf_Function, \
nsnull, /* trace */ \
nsnull, /* fix */ \
XPC_WN_JSOp_ThisObject, \
XPC_WN_JSOp_Clear \
}
@ -1333,6 +1334,7 @@ XPC_WN_JSOp_ThisObject(JSContext *cx, JSObject *obj);
js::Valueify(XPC_WN_JSOp_Enumerate), \
XPC_WN_JSOp_TypeOf_Object, \
nsnull, /* trace */ \
nsnull, /* fix */ \
XPC_WN_JSOp_ThisObject, \
XPC_WN_JSOp_Clear \
}

Просмотреть файл

@ -964,6 +964,7 @@ js::Class XPC_WN_NoHelper_JSClass = {
js::Valueify(XPC_WN_JSOp_Enumerate),
XPC_WN_JSOp_TypeOf_Object,
nsnull, // trace
nsnull, // fix
XPC_WN_JSOp_ThisObject,
XPC_WN_JSOp_Clear
}

Просмотреть файл

@ -107,8 +107,7 @@ SealObjectAndPrototype(JSContext* cx, JSObject* parent, const char* name)
return false;
JSObject* prototype = JSVAL_TO_OBJECT(prop);
return JS_SealObject(cx, obj, JS_FALSE) &&
JS_SealObject(cx, prototype, JS_FALSE);
return JS_FreezeObject(cx, obj) && JS_FreezeObject(cx, prototype);
}
static JSBool
@ -133,7 +132,7 @@ InitAndSealCTypesClass(JSContext* cx, JSObject* global)
// Finally, seal the global object, for good measure. (But not recursively;
// this breaks things.)
return JS_SealObject(cx, global, JS_FALSE);
return JS_FreezeObject(cx, global);
}
NS_IMETHODIMP

Просмотреть файл

@ -81,8 +81,7 @@ SealObjectAndPrototype(JSContext* cx, JSObject* parent, const char* name)
return false;
JSObject* prototype = JSVAL_TO_OBJECT(prop);
return JS_SealObject(cx, obj, JS_FALSE) &&
JS_SealObject(cx, prototype, JS_FALSE);
return JS_FreezeObject(cx, obj) && JS_FreezeObject(cx, prototype);
}
static JSBool
@ -101,7 +100,7 @@ InitAndSealPerfMeasurementClass(JSContext* cx, JSObject* global)
// Finally, seal the global object, for good measure. (But not recursively;
// this breaks things.)
return JS_SealObject(cx, global, JS_FALSE);
return JS_FreezeObject(cx, global);
}
NS_IMETHODIMP