mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-12-11 16:32:59 +00:00
Fix shape vs. slot management under putProperty, plus related layering and error reporting fixes (596805, r=jorendorff).
This commit is contained in:
parent
6cd6f4d73e
commit
d66fd134da
@ -100,7 +100,7 @@ MSG_DEF(JSMSG_NEED_DIET, 17, 1, JSEXN_INTERNALERR, "{0} too large"
|
||||
MSG_DEF(JSMSG_TOO_MANY_LOCAL_ROOTS, 18, 0, JSEXN_ERR, "out of local root space")
|
||||
MSG_DEF(JSMSG_READ_ONLY, 19, 1, JSEXN_TYPEERR, "{0} is read-only")
|
||||
MSG_DEF(JSMSG_BAD_FORMAL, 20, 0, JSEXN_SYNTAXERR, "malformed formal parameter")
|
||||
MSG_DEF(JSMSG_CANT_DELETE, 21, 1, JSEXN_TYPEERR, "property '{0}' is non-configurable and cannot be deleted")
|
||||
MSG_DEF(JSMSG_CANT_DELETE, 21, 1, JSEXN_TYPEERR, "property {0} is non-configurable and can't be deleted")
|
||||
MSG_DEF(JSMSG_NOT_FUNCTION, 22, 1, JSEXN_TYPEERR, "{0} is not a function")
|
||||
MSG_DEF(JSMSG_NOT_CONSTRUCTOR, 23, 1, JSEXN_TYPEERR, "{0} is not a constructor")
|
||||
MSG_DEF(JSMSG_SCRIPT_STACK_QUOTA, 24, 0, JSEXN_INTERNALERR, "script stack space quota is exhausted")
|
||||
@ -116,7 +116,7 @@ MSG_DEF(JSMSG_BAD_RADIX, 33, 1, JSEXN_ERR, "illegal radix {0}")
|
||||
MSG_DEF(JSMSG_PAREN_BEFORE_LET, 34, 0, JSEXN_SYNTAXERR, "missing ( before let head")
|
||||
MSG_DEF(JSMSG_CANT_CONVERT, 35, 1, JSEXN_ERR, "can't convert {0} to an integer")
|
||||
MSG_DEF(JSMSG_CYCLIC_VALUE, 36, 1, JSEXN_TYPEERR, "cyclic {0} value")
|
||||
MSG_DEF(JSMSG_COMPILE_EXECED_SCRIPT, 37, 0, JSEXN_TYPEERR, "cannot compile over a script that is currently executing")
|
||||
MSG_DEF(JSMSG_COMPILE_EXECED_SCRIPT, 37, 0, JSEXN_TYPEERR, "can't compile over a script that is currently executing")
|
||||
MSG_DEF(JSMSG_CANT_CONVERT_TO, 38, 2, JSEXN_TYPEERR, "can't convert {0} to {1}")
|
||||
MSG_DEF(JSMSG_NO_PROPERTIES, 39, 1, JSEXN_TYPEERR, "{0} has no properties")
|
||||
MSG_DEF(JSMSG_CANT_FIND_CLASS, 40, 1, JSEXN_TYPEERR, "can't find class id {0}")
|
||||
@ -158,7 +158,7 @@ MSG_DEF(JSMSG_PAREN_AFTER_COND, 75, 0, JSEXN_SYNTAXERR, "missing ) after
|
||||
MSG_DEF(JSMSG_DESTRUCT_DUP_ARG, 76, 0, JSEXN_SYNTAXERR, "duplicate argument is mixed with destructuring pattern")
|
||||
MSG_DEF(JSMSG_NAME_AFTER_DOT, 77, 0, JSEXN_SYNTAXERR, "missing name after . operator")
|
||||
MSG_DEF(JSMSG_BRACKET_IN_INDEX, 78, 0, JSEXN_SYNTAXERR, "missing ] in index expression")
|
||||
MSG_DEF(JSMSG_XML_WHOLE_PROGRAM, 79, 0, JSEXN_SYNTAXERR, "XML cannot be the whole program")
|
||||
MSG_DEF(JSMSG_XML_WHOLE_PROGRAM, 79, 0, JSEXN_SYNTAXERR, "XML can't be the whole program")
|
||||
MSG_DEF(JSMSG_PAREN_BEFORE_SWITCH, 80, 0, JSEXN_SYNTAXERR, "missing ( before switch expression")
|
||||
MSG_DEF(JSMSG_PAREN_AFTER_SWITCH, 81, 0, JSEXN_SYNTAXERR, "missing ) after switch expression")
|
||||
MSG_DEF(JSMSG_CURLY_BEFORE_SWITCH, 82, 0, JSEXN_SYNTAXERR, "missing { before switch body")
|
||||
@ -192,7 +192,7 @@ MSG_DEF(JSMSG_SEMI_BEFORE_STMNT, 109, 0, JSEXN_SYNTAXERR, "missing ; before
|
||||
MSG_DEF(JSMSG_NO_RETURN_VALUE, 110, 1, JSEXN_TYPEERR, "function {0} does not always return a value")
|
||||
MSG_DEF(JSMSG_DUPLICATE_FORMAL, 111, 1, JSEXN_SYNTAXERR, "duplicate formal argument {0}")
|
||||
MSG_DEF(JSMSG_EQUAL_AS_ASSIGN, 112, 1, JSEXN_SYNTAXERR, "test for equality (==) mistyped as assignment (=)?{0}")
|
||||
MSG_DEF(JSMSG_OPTIMIZED_CLOSURE_LEAK, 113, 0, JSEXN_INTERNALERR, "cannot access optimized closure")
|
||||
MSG_DEF(JSMSG_OPTIMIZED_CLOSURE_LEAK, 113, 0, JSEXN_INTERNALERR, "can't access optimized closure")
|
||||
MSG_DEF(JSMSG_TOO_MANY_DEFAULTS, 114, 0, JSEXN_SYNTAXERR, "more than one switch default")
|
||||
MSG_DEF(JSMSG_TOO_MANY_CASES, 115, 0, JSEXN_INTERNALERR, "too many switch cases")
|
||||
MSG_DEF(JSMSG_BAD_SWITCH, 116, 0, JSEXN_SYNTAXERR, "invalid switch statement")
|
||||
@ -298,7 +298,7 @@ MSG_DEF(JSMSG_BAD_GENERATOR_SYNTAX, 215, 1, JSEXN_SYNTAXERR, "{0} expression m
|
||||
MSG_DEF(JSMSG_ARRAY_COMP_LEFTSIDE, 216, 0, JSEXN_SYNTAXERR, "invalid array comprehension left-hand side")
|
||||
MSG_DEF(JSMSG_NON_XML_FILTER, 217, 1, JSEXN_TYPEERR, "XML filter is applied to non-XML value {0}")
|
||||
MSG_DEF(JSMSG_EMPTY_ARRAY_REDUCE, 218, 0, JSEXN_TYPEERR, "reduce of empty array with no initial value")
|
||||
MSG_DEF(JSMSG_NON_LIST_XML_METHOD, 219, 2, JSEXN_TYPEERR, "cannot call {0} method on an XML list with {1} elements")
|
||||
MSG_DEF(JSMSG_NON_LIST_XML_METHOD, 219, 2, JSEXN_TYPEERR, "can't call {0} method on an XML list with {1} elements")
|
||||
MSG_DEF(JSMSG_BAD_DELETE_OPERAND, 220, 0, JSEXN_SYNTAXERR, "invalid delete operand")
|
||||
MSG_DEF(JSMSG_BAD_INCOP_OPERAND, 221, 0, JSEXN_SYNTAXERR, "invalid increment/decrement operand")
|
||||
MSG_DEF(JSMSG_UNEXPECTED_TYPE, 222, 2, JSEXN_TYPEERR, "{0} is {1}")
|
||||
@ -318,10 +318,10 @@ MSG_DEF(JSMSG_DEPRECATED_DELETE_OPERAND, 235, 0, JSEXN_SYNTAXERR, "Applying the
|
||||
MSG_DEF(JSMSG_DEPRECATED_ASSIGN, 236, 1, JSEXN_SYNTAXERR, "assignment to {0} is deprecated")
|
||||
MSG_DEF(JSMSG_BAD_BINDING, 237, 1, JSEXN_SYNTAXERR, "redefining {0} is deprecated")
|
||||
MSG_DEF(JSMSG_INVALID_DESCRIPTOR, 238, 0, JSEXN_TYPEERR, "property descriptors must not specify a value or be writable when a getter or setter has been specified")
|
||||
MSG_DEF(JSMSG_OBJECT_NOT_EXTENSIBLE, 239, 0, JSEXN_TYPEERR, "object is not extensible")
|
||||
MSG_DEF(JSMSG_CANT_REDEFINE_UNCONFIGURABLE_PROP, 240, 1, JSEXN_TYPEERR, "can't redefine non-configurable property '{0}'")
|
||||
MSG_DEF(JSMSG_CANT_APPEND_PROPERTIES_TO_UNWRITABLE_LENGTH_ARRAY, 241, 0, JSEXN_TYPEERR, "Can't add elements past the end of an array if its length property is unwritable")
|
||||
MSG_DEF(JSMSG_DEFINE_ARRAY_LENGTH_UNSUPPORTED, 242, 0, JSEXN_INTERNALERR, "defining the length property on an array is not currently supported")
|
||||
MSG_DEF(JSMSG_OBJECT_NOT_EXTENSIBLE, 239, 1, JSEXN_TYPEERR, "{0} is not extensible")
|
||||
MSG_DEF(JSMSG_CANT_REDEFINE_PROP, 240, 1, JSEXN_TYPEERR, "can't redefine non-configurable property '{0}'")
|
||||
MSG_DEF(JSMSG_CANT_APPEND_TO_ARRAY, 241, 0, JSEXN_TYPEERR, "can't add elements past the end of an array if its length property is unwritable")
|
||||
MSG_DEF(JSMSG_CANT_DEFINE_ARRAY_LENGTH,242, 0, JSEXN_INTERNALERR, "defining the length property on an array is not currently supported")
|
||||
MSG_DEF(JSMSG_CANT_DEFINE_ARRAY_INDEX,243, 0, JSEXN_TYPEERR, "can't define array index property")
|
||||
MSG_DEF(JSMSG_TYPED_ARRAY_BAD_INDEX, 244, 0, JSEXN_ERR, "invalid or out-of-range index")
|
||||
MSG_DEF(JSMSG_TYPED_ARRAY_NEGATIVE_ARG, 245, 1, JSEXN_ERR, "argument {0} must be >= 0")
|
||||
|
@ -152,7 +152,7 @@ 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);
|
||||
obj->reportNotExtensible(cx);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1971,10 +1971,17 @@ Reject(JSContext *cx, uintN errorNumber, bool throwError, jsid id, bool *rval)
|
||||
}
|
||||
|
||||
static JSBool
|
||||
Reject(JSContext *cx, uintN errorNumber, bool throwError, bool *rval)
|
||||
Reject(JSContext *cx, JSObject *obj, uintN errorNumber, bool throwError, bool *rval)
|
||||
{
|
||||
if (throwError) {
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, errorNumber);
|
||||
if (js_ErrorFormatString[errorNumber].argCount == 1) {
|
||||
js_ReportValueErrorFlags(cx, JSREPORT_ERROR, errorNumber,
|
||||
JSDVG_IGNORE_STACK, ObjectValue(*obj),
|
||||
NULL, NULL, NULL);
|
||||
} else {
|
||||
JS_ASSERT(js_ErrorFormatString[errorNumber].argCount == 0);
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, errorNumber);
|
||||
}
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
@ -2006,7 +2013,7 @@ DefinePropertyOnObject(JSContext *cx, JSObject *obj, const PropDesc &desc,
|
||||
/* 8.12.9 steps 2-4. */
|
||||
if (!current) {
|
||||
if (!obj->isExtensible())
|
||||
return Reject(cx, JSMSG_OBJECT_NOT_EXTENSIBLE, throwError, rval);
|
||||
return Reject(cx, obj, JSMSG_OBJECT_NOT_EXTENSIBLE, throwError, rval);
|
||||
|
||||
*rval = true;
|
||||
|
||||
@ -2094,8 +2101,8 @@ DefinePropertyOnObject(JSContext *cx, JSObject *obj, const PropDesc &desc,
|
||||
*/
|
||||
if (!shape->configurable() &&
|
||||
(!shape->hasDefaultGetter() || !shape->hasDefaultSetter())) {
|
||||
return Reject(cx, obj2, current, JSMSG_CANT_REDEFINE_UNCONFIGURABLE_PROP,
|
||||
throwError, desc.id, rval);
|
||||
return Reject(cx, obj2, current, JSMSG_CANT_REDEFINE_PROP, throwError,
|
||||
desc.id, rval);
|
||||
}
|
||||
|
||||
if (!js_NativeGet(cx, obj, obj2, shape, JSGET_NO_METHOD_BARRIER, &v)) {
|
||||
@ -2141,8 +2148,7 @@ DefinePropertyOnObject(JSContext *cx, JSObject *obj, const PropDesc &desc,
|
||||
JS_ASSERT_IF(!desc.hasConfigurable, !desc.configurable());
|
||||
if (desc.configurable() ||
|
||||
(desc.hasEnumerable && desc.enumerable() != shape->enumerable())) {
|
||||
return Reject(cx, obj2, current, JSMSG_CANT_REDEFINE_UNCONFIGURABLE_PROP, throwError,
|
||||
desc.id, rval);
|
||||
return Reject(cx, obj2, current, JSMSG_CANT_REDEFINE_PROP, throwError, desc.id, rval);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2150,18 +2156,16 @@ DefinePropertyOnObject(JSContext *cx, JSObject *obj, const PropDesc &desc,
|
||||
/* 8.12.9 step 8, no validation required */
|
||||
} else if (desc.isDataDescriptor() != shape->isDataDescriptor()) {
|
||||
/* 8.12.9 step 9. */
|
||||
if (!shape->configurable()) {
|
||||
return Reject(cx, obj2, current, JSMSG_CANT_REDEFINE_UNCONFIGURABLE_PROP,
|
||||
throwError, desc.id, rval);
|
||||
}
|
||||
if (!shape->configurable())
|
||||
return Reject(cx, obj2, current, JSMSG_CANT_REDEFINE_PROP, throwError, desc.id, rval);
|
||||
} else if (desc.isDataDescriptor()) {
|
||||
/* 8.12.9 step 10. */
|
||||
JS_ASSERT(shape->isDataDescriptor());
|
||||
if (!shape->configurable() && !shape->writable()) {
|
||||
if ((desc.hasWritable && desc.writable()) ||
|
||||
(desc.hasValue && !SameValue(desc.value, v, cx))) {
|
||||
return Reject(cx, obj2, current, JSMSG_CANT_REDEFINE_UNCONFIGURABLE_PROP,
|
||||
throwError, desc.id, rval);
|
||||
return Reject(cx, obj2, current, JSMSG_CANT_REDEFINE_PROP, throwError, desc.id,
|
||||
rval);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -2172,8 +2176,8 @@ DefinePropertyOnObject(JSContext *cx, JSObject *obj, const PropDesc &desc,
|
||||
!SameValue(desc.setterValue(), shape->setterOrUndefined(), cx)) ||
|
||||
(desc.hasGet &&
|
||||
!SameValue(desc.getterValue(), shape->getterOrUndefined(), cx))) {
|
||||
return Reject(cx, obj2, current, JSMSG_CANT_REDEFINE_UNCONFIGURABLE_PROP,
|
||||
throwError, desc.id, rval);
|
||||
return Reject(cx, obj2, current, JSMSG_CANT_REDEFINE_PROP, throwError, desc.id,
|
||||
rval);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2281,7 +2285,7 @@ DefinePropertyOnArray(JSContext *cx, JSObject *obj, const PropDesc &desc,
|
||||
* to define the "length" property, rather than attempting to implement
|
||||
* some difficult-for-authors-to-grasp subset of that functionality.
|
||||
*/
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_DEFINE_ARRAY_LENGTH_UNSUPPORTED);
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_DEFINE_ARRAY_LENGTH);
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
@ -2290,12 +2294,12 @@ DefinePropertyOnArray(JSContext *cx, JSObject *obj, const PropDesc &desc,
|
||||
/*
|
||||
// Disabled until we support defining "length":
|
||||
if (index >= oldLen && lengthPropertyNotWritable())
|
||||
return ThrowTypeError(cx, JSMSG_CANT_APPEND_PROPERTIES_TO_UNWRITABLE_LENGTH_ARRAY);
|
||||
return ThrowTypeError(cx, JSMSG_CANT_APPEND_TO_ARRAY);
|
||||
*/
|
||||
if (!DefinePropertyOnObject(cx, obj, desc, false, rval))
|
||||
return JS_FALSE;
|
||||
if (!*rval)
|
||||
return Reject(cx, JSMSG_CANT_DEFINE_ARRAY_INDEX, throwError, rval);
|
||||
return Reject(cx, obj, JSMSG_CANT_DEFINE_ARRAY_INDEX, throwError, rval);
|
||||
|
||||
if (index >= oldLen) {
|
||||
JS_ASSERT(index != UINT32_MAX);
|
||||
@ -2319,7 +2323,7 @@ DefineProperty(JSContext *cx, JSObject *obj, const PropDesc &desc, bool throwErr
|
||||
if (obj->getOps()->lookupProperty) {
|
||||
if (obj->isProxy())
|
||||
return JSProxy::defineProperty(cx, obj, desc.id, desc.pd);
|
||||
return Reject(cx, JSMSG_OBJECT_NOT_EXTENSIBLE, throwError, rval);
|
||||
return Reject(cx, obj, JSMSG_OBJECT_NOT_EXTENSIBLE, throwError, rval);
|
||||
}
|
||||
|
||||
return DefinePropertyOnObject(cx, obj, desc, throwError, rval);
|
||||
@ -5101,31 +5105,28 @@ js_CheckUndeclaredVarAssignment(JSContext *cx, JSString *propname)
|
||||
JSMSG_UNDECLARED_VAR, bytes);
|
||||
}
|
||||
|
||||
namespace js {
|
||||
|
||||
JSBool
|
||||
ReportReadOnly(JSContext* cx, jsid id, uintN flags)
|
||||
bool
|
||||
JSObject::reportReadOnly(JSContext* cx, jsid id, uintN report)
|
||||
{
|
||||
return js_ReportValueErrorFlags(cx, flags, JSMSG_READ_ONLY,
|
||||
return js_ReportValueErrorFlags(cx, report, JSMSG_READ_ONLY,
|
||||
JSDVG_IGNORE_STACK, IdToValue(id), NULL,
|
||||
NULL, NULL);
|
||||
}
|
||||
|
||||
JSBool
|
||||
ReportNotConfigurable(JSContext* cx, jsid id, uintN flags)
|
||||
bool
|
||||
JSObject::reportNotConfigurable(JSContext* cx, jsid id, uintN report)
|
||||
{
|
||||
return js_ReportValueErrorFlags(cx, flags, JSMSG_CANT_DELETE,
|
||||
return js_ReportValueErrorFlags(cx, report, JSMSG_CANT_DELETE,
|
||||
JSDVG_IGNORE_STACK, IdToValue(id), NULL,
|
||||
NULL, NULL);
|
||||
}
|
||||
|
||||
JSBool
|
||||
ReportNotExtensible(JSContext* cx, uintN flags)
|
||||
bool
|
||||
JSObject::reportNotExtensible(JSContext *cx, uintN report)
|
||||
{
|
||||
return JS_ReportErrorFlagsAndNumber(cx, flags, js_GetErrorMessage, NULL,
|
||||
JSMSG_OBJECT_NOT_EXTENSIBLE);
|
||||
}
|
||||
|
||||
return js_ReportValueErrorFlags(cx, report, JSMSG_OBJECT_NOT_EXTENSIBLE,
|
||||
JSDVG_IGNORE_STACK, ObjectValue(*this),
|
||||
NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -5212,9 +5213,9 @@ js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, uintN defineHow,
|
||||
|
||||
/* Error in strict mode code, warn with strict option, otherwise do nothing. */
|
||||
if (strict)
|
||||
return ReportReadOnly(cx, id, 0);
|
||||
return obj->reportReadOnly(cx, id);
|
||||
if (JS_HAS_STRICT_OPTION(cx))
|
||||
return ReportReadOnly(cx, id, JSREPORT_STRICT | JSREPORT_WARNING);
|
||||
return obj->reportReadOnly(cx, id, JSREPORT_STRICT | JSREPORT_WARNING);
|
||||
return JS_TRUE;
|
||||
|
||||
#ifdef JS_TRACER
|
||||
@ -5300,11 +5301,10 @@ js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, uintN defineHow,
|
||||
if (!obj->isExtensible()) {
|
||||
/* Error in strict mode code, warn with strict option, otherwise do nothing. */
|
||||
if (strict)
|
||||
return ReportNotExtensible(cx, 0);
|
||||
return obj->reportNotExtensible(cx);
|
||||
if (JS_HAS_STRICT_OPTION(cx))
|
||||
return ReportNotExtensible(cx, JSREPORT_STRICT | JSREPORT_WARNING);
|
||||
else
|
||||
return JS_TRUE;
|
||||
return obj->reportNotExtensible(cx, JSREPORT_STRICT | JSREPORT_WARNING);
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -5451,7 +5451,7 @@ js_DeleteProperty(JSContext *cx, JSObject *obj, jsid id, Value *rval, JSBool str
|
||||
if (shape->isSharedPermanent()) {
|
||||
JS_UNLOCK_OBJ(cx, proto);
|
||||
if (strict)
|
||||
return ReportNotConfigurable(cx, id, 0);
|
||||
return obj->reportNotConfigurable(cx, id);
|
||||
rval->setBoolean(false);
|
||||
return true;
|
||||
}
|
||||
@ -5470,7 +5470,7 @@ js_DeleteProperty(JSContext *cx, JSObject *obj, jsid id, Value *rval, JSBool str
|
||||
if (!shape->configurable()) {
|
||||
JS_UNLOCK_OBJ(cx, obj);
|
||||
if (strict)
|
||||
return ReportNotConfigurable(cx, id, 0);
|
||||
return obj->reportNotConfigurable(cx, id);
|
||||
rval->setBoolean(false);
|
||||
return true;
|
||||
}
|
||||
|
@ -1005,16 +1005,25 @@ struct JSObject {
|
||||
bool allocSlot(JSContext *cx, uint32 *slotp);
|
||||
void freeSlot(JSContext *cx, uint32 slot);
|
||||
|
||||
private:
|
||||
void reportReadOnlyScope(JSContext *cx);
|
||||
bool reportReadOnly(JSContext* cx, jsid id, uintN report = JSREPORT_ERROR);
|
||||
bool reportNotConfigurable(JSContext* cx, jsid id, uintN report = JSREPORT_ERROR);
|
||||
bool reportNotExtensible(JSContext *cx, uintN report = JSREPORT_ERROR);
|
||||
|
||||
private:
|
||||
js::Shape *getChildProperty(JSContext *cx, js::Shape *parent, js::Shape &child);
|
||||
|
||||
const js::Shape *addPropertyCommon(JSContext *cx, jsid id,
|
||||
js::PropertyOp getter, js::PropertyOp setter,
|
||||
uint32 slot, uintN attrs,
|
||||
uintN flags, intN shortid,
|
||||
js::Shape **spp);
|
||||
/*
|
||||
* Internal helper that adds a shape not yet mapped by this object.
|
||||
*
|
||||
* Notes:
|
||||
* 1. getter and setter must be normalized based on flags (see jsscope.cpp).
|
||||
* 2. !isExtensible() checking must be done by callers.
|
||||
*/
|
||||
const js::Shape *addPropertyInternal(JSContext *cx, jsid id,
|
||||
js::PropertyOp getter, js::PropertyOp setter,
|
||||
uint32 slot, uintN attrs,
|
||||
uintN flags, intN shortid,
|
||||
js::Shape **spp);
|
||||
|
||||
bool toDictionaryMode(JSContext *cx);
|
||||
|
||||
@ -1041,7 +1050,7 @@ struct JSObject {
|
||||
const js::Shape *changeProperty(JSContext *cx, const js::Shape *shape, uintN attrs, uintN mask,
|
||||
js::PropertyOp getter, js::PropertyOp setter);
|
||||
|
||||
/* Remove id from this object. */
|
||||
/* Remove the property named by id from this object. */
|
||||
bool removeProperty(JSContext *cx, jsid id);
|
||||
|
||||
/* Clear the scope, making it empty. */
|
||||
|
@ -513,21 +513,6 @@ JSObject::getChildProperty(JSContext *cx, Shape *parent, Shape &child)
|
||||
return shape;
|
||||
}
|
||||
|
||||
void
|
||||
JSObject::reportReadOnlyScope(JSContext *cx)
|
||||
{
|
||||
JSString *str;
|
||||
const char *bytes;
|
||||
|
||||
str = js_ValueToString(cx, ObjectValue(*this));
|
||||
if (!str)
|
||||
return;
|
||||
bytes = js_GetStringBytes(cx, str);
|
||||
if (!bytes)
|
||||
return;
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_READ_ONLY, bytes);
|
||||
}
|
||||
|
||||
Shape *
|
||||
Shape::newDictionaryShape(JSContext *cx, const Shape &child, Shape **listp)
|
||||
{
|
||||
@ -720,29 +705,27 @@ JSObject::addProperty(JSContext *cx, jsid id,
|
||||
{
|
||||
JS_ASSERT(!JSID_IS_VOID(id));
|
||||
|
||||
if (!isExtensible()) {
|
||||
reportNotExtensible(cx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
NormalizeGetterAndSetter(cx, this, id, attrs, flags, getter, setter);
|
||||
|
||||
/* Search for id with adding = true in order to claim its entry. */
|
||||
Shape **spp = nativeSearch(id, true);
|
||||
JS_ASSERT(!SHAPE_FETCH(spp));
|
||||
return addPropertyCommon(cx, id, getter, setter, slot, attrs, flags, shortid, spp);
|
||||
return addPropertyInternal(cx, id, getter, setter, slot, attrs, flags, shortid, spp);
|
||||
}
|
||||
|
||||
const Shape *
|
||||
JSObject::addPropertyCommon(JSContext *cx, jsid id,
|
||||
PropertyOp getter, PropertyOp setter,
|
||||
uint32 slot, uintN attrs,
|
||||
uintN flags, intN shortid,
|
||||
Shape **spp)
|
||||
JSObject::addPropertyInternal(JSContext *cx, jsid id,
|
||||
PropertyOp getter, PropertyOp setter,
|
||||
uint32 slot, uintN attrs,
|
||||
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;
|
||||
}
|
||||
JS_ASSERT_IF(inDictionaryMode(), !lastProp->frozen());
|
||||
|
||||
PropertyTable *table = NULL;
|
||||
if (!inDictionaryMode()) {
|
||||
@ -822,137 +805,182 @@ JSObject::putProperty(JSContext *cx, jsid id,
|
||||
uint32 slot, uintN attrs,
|
||||
uintN flags, intN shortid)
|
||||
{
|
||||
Shape **spp, *shape, *overwriting;
|
||||
|
||||
JS_ASSERT(!JSID_IS_VOID(id));
|
||||
|
||||
/*
|
||||
* Horrid non-strict eval, debuggers, and |default xml namespace ...| may
|
||||
* extend Call objects.
|
||||
*/
|
||||
if (lastProp->frozen()) {
|
||||
if (!Shape::newDictionaryList(cx, &lastProp))
|
||||
return NULL;
|
||||
JS_ASSERT(!lastProp->frozen());
|
||||
}
|
||||
|
||||
NormalizeGetterAndSetter(cx, this, id, attrs, flags, getter, setter);
|
||||
|
||||
/* Search for id in order to claim its entry if table has been allocated. */
|
||||
spp = nativeSearch(id, true);
|
||||
shape = SHAPE_FETCH(spp);
|
||||
if (!shape)
|
||||
return addPropertyCommon(cx, id, getter, setter, slot, attrs, flags, shortid, spp);
|
||||
Shape **spp = nativeSearch(id, true);
|
||||
Shape *shape = SHAPE_FETCH(spp);
|
||||
if (!shape) {
|
||||
/*
|
||||
* You can't add properties to a non-extensible object, but you can change
|
||||
* attributes of properties in such objects.
|
||||
*/
|
||||
if (!isExtensible()) {
|
||||
reportNotExtensible(cx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return addPropertyInternal(cx, id, getter, setter, slot, attrs, flags, shortid, spp);
|
||||
}
|
||||
|
||||
/* Property exists: search must have returned a valid *spp. */
|
||||
JS_ASSERT(!SHAPE_IS_REMOVED(*spp));
|
||||
overwriting = shape;
|
||||
|
||||
/*
|
||||
* If all property members match, this is a redundant add and we can
|
||||
* return early. If the caller wants to allocate a slot, but doesn't
|
||||
* care which slot, copy shape->slot into slot so we can match shape,
|
||||
* if all other members match.
|
||||
* If the caller wants to allocate a slot, but doesn't care which slot,
|
||||
* copy the existing shape's slot into slot so we can match shape, if all
|
||||
* other members match.
|
||||
*/
|
||||
bool hadSlot = !shape->isAlias() && containsSlot(shape->slot);
|
||||
bool hadSlot = !shape->isAlias() && shape->hasSlot();
|
||||
uint32 oldSlot = shape->slot;
|
||||
if (!(attrs & JSPROP_SHARED) && slot == SHAPE_INVALID_SLOT && hadSlot)
|
||||
slot = oldSlot;
|
||||
|
||||
/*
|
||||
* Now that we've possibly preserved slot, check whether all members match.
|
||||
* If so, this is a redundant "put" and we can return without more work.
|
||||
*/
|
||||
if (shape->matchesParamsAfterId(getter, setter, slot, attrs, flags, shortid)) {
|
||||
METER(redundantPuts);
|
||||
return shape;
|
||||
}
|
||||
|
||||
PropertyTable *table = inDictionaryMode() ? lastProp->table : NULL;
|
||||
/*
|
||||
* Overwriting a non-last property requires switching to dictionary mode.
|
||||
* The shape tree is shared immutable, and we can't removeProperty and then
|
||||
* addPropertyInternal because a failure under add would lose data.
|
||||
*/
|
||||
if (shape != lastProp && !inDictionaryMode()) {
|
||||
if (!toDictionaryMode(cx))
|
||||
return false;
|
||||
spp = nativeSearch(shape->id);
|
||||
shape = SHAPE_FETCH(spp);
|
||||
}
|
||||
|
||||
/*
|
||||
* If we are clearing shape to force the existing property that it
|
||||
* describes to be overwritten, then we have to unlink shape from the
|
||||
* ancestor line at lastProp->lastProp.
|
||||
* Now that we have passed the lastProp->frozen() check at the top of this
|
||||
* method, and the non-last-property conditioning just above, we are ready
|
||||
* to overwrite.
|
||||
*
|
||||
* If shape is not lastProp and this scope is not in dictionary mode,
|
||||
* we must switch to dictionary mode so we can unlink the non-terminal
|
||||
* shape without breaking anyone sharing the property lineage via our
|
||||
* prototype's property tree.
|
||||
* Optimize the case of a non-frozen dictionary-mode object based on the
|
||||
* property that dictionaries exclusively own their mutable shape structs,
|
||||
* each of which has a unique shape number (not shared via a shape tree).
|
||||
*/
|
||||
Shape *oldLastProp = lastProp;
|
||||
if (shape == lastProp && !inDictionaryMode()) {
|
||||
removeLastProperty();
|
||||
} else {
|
||||
if (!inDictionaryMode()) {
|
||||
if (!toDictionaryMode(cx))
|
||||
if (inDictionaryMode()) {
|
||||
/* FIXME bug 593129 -- slot allocation and JSObject *this must move out of here! */
|
||||
if (slot == SHAPE_INVALID_SLOT && !(attrs & JSPROP_SHARED) && !(flags & Shape::ALIAS)) {
|
||||
if (!allocSlot(cx, &slot))
|
||||
return NULL;
|
||||
|
||||
spp = nativeSearch(id);
|
||||
shape = SHAPE_FETCH(spp);
|
||||
table = lastProp->table;
|
||||
oldLastProp = lastProp;
|
||||
}
|
||||
shape->removeFromDictionary(this);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
if (shape == oldLastProp) {
|
||||
JS_ASSERT(lastProp->slotSpan <= shape->slotSpan);
|
||||
if (shape->hasSlot())
|
||||
JS_ASSERT(shape->slot < shape->slotSpan);
|
||||
if (lastProp->slotSpan < numSlots())
|
||||
getSlotRef(lastProp->slotSpan).setUndefined();
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* If we fail later on trying to find or create a new shape, we will
|
||||
* restore *spp from |overwriting|. Note that we don't bother to keep
|
||||
* table->removedCount in sync, because we will fix up both *spp and
|
||||
* table->entryCount shortly.
|
||||
*/
|
||||
if (table)
|
||||
SHAPE_STORE_PRESERVING_COLLISION(spp, NULL);
|
||||
|
||||
{
|
||||
/* Find or create a property tree node labeled by our arguments. */
|
||||
Shape child(id, getter, setter, slot, attrs, flags, shortid);
|
||||
shape = getChildProperty(cx, lastProp, child);
|
||||
}
|
||||
|
||||
if (shape) {
|
||||
JS_ASSERT(shape == lastProp);
|
||||
|
||||
if (table) {
|
||||
/* Store the tree node pointer in the table entry for id. */
|
||||
SHAPE_STORE_PRESERVING_COLLISION(spp, shape);
|
||||
|
||||
/* Move table from oldLastProp to the new lastProp, aka shape. */
|
||||
JS_ASSERT(oldLastProp->table == table);
|
||||
oldLastProp->setTable(NULL);
|
||||
shape->setTable(table);
|
||||
}
|
||||
|
||||
if (!lastProp->table) {
|
||||
/* See comment in JSObject::addPropertyCommon about ignoring OOM here. */
|
||||
lastProp->maybeHash(cx);
|
||||
}
|
||||
|
||||
/*
|
||||
* Can't fail now, so free the previous incarnation's slot if the new
|
||||
* shape has no slot. But we do not need to free oldSlot (and must not,
|
||||
* as trying to will botch an assertion in JSObject::freeSlot) if the
|
||||
* new lastProp (shape here) has a slotSpan that does not cover it.
|
||||
* We are going to mutate shape and move it to be lastProp if it isn't
|
||||
* already, so we must regenerate its shape.
|
||||
*/
|
||||
if (hadSlot && !shape->hasSlot() && oldSlot < shape->slotSpan) {
|
||||
freeSlot(cx, oldSlot);
|
||||
JS_ATOMIC_INCREMENT(&cx->runtime->propertyRemovals);
|
||||
shape->shape = js_GenerateShape(cx, false);
|
||||
|
||||
/*
|
||||
* Set shape->slot before calling shape->insertIntoDictionary, which
|
||||
* uses it under shape->setParent.
|
||||
*/
|
||||
shape->slot = slot;
|
||||
|
||||
if (shape != lastProp) {
|
||||
if (PropertyTable *table = lastProp->table) {
|
||||
shape->table = table;
|
||||
lastProp->table = NULL;
|
||||
}
|
||||
shape->removeFromDictionary(this);
|
||||
shape->insertIntoDictionary(&lastProp);
|
||||
} else {
|
||||
if (slot != SHAPE_INVALID_SLOT && slot >= shape->slotSpan)
|
||||
shape->slotSpan = slot + 1;
|
||||
}
|
||||
|
||||
CHECK_SHAPE_CONSISTENCY(this);
|
||||
METER(puts);
|
||||
return shape;
|
||||
shape->rawGetter = getter;
|
||||
shape->rawSetter = setter;
|
||||
shape->attrs = attrs;
|
||||
shape->flags = flags | Shape::IN_DICTIONARY;
|
||||
shape->shortid = shortid;
|
||||
|
||||
/*
|
||||
* We are done updating shape and lastProp. Now we may need to update
|
||||
* flags and objShape. In the last non-dictionary property case in the
|
||||
* else clause just below, getChildProperty handles this for us.
|
||||
*/
|
||||
updateFlags(shape);
|
||||
updateShape(cx);
|
||||
} else {
|
||||
/*
|
||||
* Updating lastProp in a non-dictionary-mode object. Such objects
|
||||
* share their shapes via a tree rooted at a prototype emptyShape, or
|
||||
* perhaps a well-known compartment-wide singleton emptyShape.
|
||||
*
|
||||
* If any shape in the tree has a property hashtable, it is shared and
|
||||
* immutable too, therefore we must not update *spp.
|
||||
*/
|
||||
JS_ASSERT(shape == lastProp);
|
||||
removeLastProperty();
|
||||
|
||||
/* Find or create a property tree node labeled by our arguments. */
|
||||
Shape child(id, getter, setter, slot, attrs, flags, shortid);
|
||||
|
||||
Shape *newShape = getChildProperty(cx, lastProp, child);
|
||||
if (!newShape) {
|
||||
setLastProperty(shape);
|
||||
CHECK_SHAPE_CONSISTENCY(this);
|
||||
METER(putFails);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
shape = newShape;
|
||||
}
|
||||
|
||||
JS_ASSERT(shape == lastProp);
|
||||
|
||||
if (!shape->table) {
|
||||
/* See JSObject::addPropertyInternal comment about ignoring OOM. */
|
||||
shape->maybeHash(cx);
|
||||
}
|
||||
|
||||
/*
|
||||
* Can't fail now, so free the previous incarnation's slot if the new shape
|
||||
* has no slot. But we do not need to free oldSlot (and must not, as trying
|
||||
* to will botch an assertion in JSObject::freeSlot) if the new lastProp
|
||||
* (shape here) has a slotSpan that does not cover it.
|
||||
*/
|
||||
if (hadSlot && !shape->hasSlot()) {
|
||||
if (oldSlot < shape->slotSpan)
|
||||
freeSlot(cx, oldSlot);
|
||||
#ifdef DEBUG
|
||||
else
|
||||
getSlotRef(oldSlot).setUndefined();
|
||||
#endif
|
||||
JS_ATOMIC_INCREMENT(&cx->runtime->propertyRemovals);
|
||||
}
|
||||
|
||||
if (table)
|
||||
SHAPE_STORE_PRESERVING_COLLISION(spp, overwriting);
|
||||
CHECK_SHAPE_CONSISTENCY(this);
|
||||
METER(putFails);
|
||||
return NULL;
|
||||
METER(puts);
|
||||
return shape;
|
||||
}
|
||||
|
||||
const Shape *
|
||||
JSObject::changeProperty(JSContext *cx, const Shape *shape, uintN attrs, uintN mask,
|
||||
PropertyOp getter, PropertyOp setter)
|
||||
{
|
||||
const Shape *newShape;
|
||||
|
||||
JS_ASSERT_IF(inDictionaryMode(), !lastProp->frozen());
|
||||
JS_ASSERT(!JSID_IS_VOID(shape->id));
|
||||
JS_ASSERT(nativeContains(*shape));
|
||||
|
||||
@ -974,6 +1002,8 @@ JSObject::changeProperty(JSContext *cx, const Shape *shape, uintN attrs, uintN m
|
||||
|
||||
Shape child(shape->id, getter, setter, shape->slot, attrs, shape->flags, shape->shortid);
|
||||
|
||||
const Shape *newShape;
|
||||
|
||||
if (inDictionaryMode()) {
|
||||
shape->removeFromDictionary(this);
|
||||
newShape = Shape::newDictionaryShape(cx, child, &lastProp);
|
||||
@ -1014,11 +1044,15 @@ JSObject::changeProperty(JSContext *cx, const Shape *shape, uintN attrs, uintN m
|
||||
/*
|
||||
* Let JSObject::putProperty handle this |overwriting| case, including
|
||||
* the conservation of shape->slot (if it's valid). We must not call
|
||||
* JSObject::removeProperty because it will free a valid shape->slot and
|
||||
* JSObject::putProperty won't re-allocate it.
|
||||
* removeProperty because it will free an allocated shape->slot, and
|
||||
* putProperty won't re-allocate it.
|
||||
*/
|
||||
newShape = putProperty(cx, child.id, child.rawGetter, child.rawSetter, child.slot,
|
||||
child.attrs, child.flags, child.shortid);
|
||||
#ifdef DEBUG
|
||||
if (newShape)
|
||||
METER(changePuts);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
@ -1041,27 +1075,26 @@ JSObject::removeProperty(JSContext *cx, jsid id)
|
||||
return true;
|
||||
}
|
||||
|
||||
/* If shape is not the last property added, switch to dictionary mode. */
|
||||
if (shape != lastProp) {
|
||||
if (!inDictionaryMode()) {
|
||||
if (!toDictionaryMode(cx))
|
||||
return false;
|
||||
spp = nativeSearch(shape->id);
|
||||
shape = SHAPE_FETCH(spp);
|
||||
}
|
||||
JS_ASSERT(SHAPE_FETCH(spp) == shape);
|
||||
}
|
||||
|
||||
/* First, if shape is unshared and not cleared, free its slot number. */
|
||||
bool hadSlot = !shape->isAlias() && containsSlot(shape->slot);
|
||||
/* First, if shape is unshared and not has a slot, free its slot number. */
|
||||
bool hadSlot = !shape->isAlias() && shape->hasSlot();
|
||||
if (hadSlot) {
|
||||
freeSlot(cx, shape->slot);
|
||||
JS_ATOMIC_INCREMENT(&cx->runtime->propertyRemovals);
|
||||
}
|
||||
|
||||
|
||||
/* If shape is not the last property added, switch to dictionary mode. */
|
||||
if (shape != lastProp && !inDictionaryMode()) {
|
||||
if (!toDictionaryMode(cx))
|
||||
return false;
|
||||
spp = nativeSearch(shape->id);
|
||||
shape = SHAPE_FETCH(spp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Next, consider removing id from lastProp->table if in dictionary mode,
|
||||
* by setting its entry to a removed or free sentinel.
|
||||
* A dictionary-mode object owns mutable, unique shapes on a non-circular
|
||||
* doubly linked list, optionally hashed by lastProp->table. So we can edit
|
||||
* the list and hash in place.
|
||||
*/
|
||||
if (inDictionaryMode()) {
|
||||
PropertyTable *table = lastProp->table;
|
||||
@ -1092,12 +1125,13 @@ JSObject::removeProperty(JSContext *cx, jsid id)
|
||||
|
||||
/*
|
||||
* Remove shape from its non-circular doubly linked list, setting this
|
||||
* object's shape first so the updateShape(cx) after this if-else will
|
||||
* generate a fresh shape for this scope. We need a fresh shape for all
|
||||
* deletions, even of lastProp. Otherwise, a shape number can replay
|
||||
* and caches may return get deleted DictionaryShapes! See bug 595365.
|
||||
* object's OWN_SHAPE flag so the updateShape(cx) further below will
|
||||
* generate a fresh shape id for this object, distinct from the id of
|
||||
* any shape in the list. We need a fresh shape for all deletions, even
|
||||
* of lastProp. Otherwise, a shape number could replay and caches might
|
||||
* return get deleted DictionaryShapes! See bug 595365.
|
||||
*/
|
||||
setOwnShape(lastProp->shape);
|
||||
flags |= OWN_SHAPE;
|
||||
|
||||
Shape *oldLastProp = lastProp;
|
||||
shape->removeFromDictionary(this);
|
||||
@ -1132,7 +1166,7 @@ JSObject::removeProperty(JSContext *cx, jsid id)
|
||||
}
|
||||
updateShape(cx);
|
||||
|
||||
/* Last, consider shrinking table if its load factor is <= .25. */
|
||||
/* On the way out, consider shrinking table if its load factor is <= .25. */
|
||||
if (PropertyTable *table = lastProp->table) {
|
||||
uint32 size = table->capacity();
|
||||
if (size > PropertyTable::MIN_SIZE && table->entryCount <= size >> 2) {
|
||||
|
@ -808,6 +808,7 @@ struct JSScopeStats {
|
||||
jsrefcount redundantPuts;
|
||||
jsrefcount putFails;
|
||||
jsrefcount changes;
|
||||
jsrefcount changePuts;
|
||||
jsrefcount changeFails;
|
||||
jsrefcount compresses;
|
||||
jsrefcount grows;
|
||||
|
@ -47,8 +47,7 @@ START(summary);
|
||||
|
||||
try
|
||||
{
|
||||
expect = 'TypeError: cannot call namespace method on an XML list with ' +
|
||||
'0 elements';
|
||||
expect = "TypeError: can't call namespace method on an XML list with 0 elements";
|
||||
XML.prototype.function::namespace.call(new XMLList());
|
||||
}
|
||||
catch(ex)
|
||||
|
@ -101,7 +101,7 @@ reportCompare('abc', value, summary + ': push');
|
||||
|
||||
// pop
|
||||
value = 'abc';
|
||||
expect = "TypeError: property 'Array.prototype.pop.call(value)' is non-configurable and cannot be deleted";
|
||||
expect = "TypeError: property Array.prototype.pop.call(value) is non-configurable and can't be deleted";
|
||||
try
|
||||
{
|
||||
actual = Array.prototype.pop.call(value);
|
||||
|
@ -23,6 +23,7 @@ script regress-566549.js
|
||||
script regress-566914.js
|
||||
script regress-567152.js
|
||||
script regress-569306.js
|
||||
script regress-569464.js
|
||||
script regress-571014.js
|
||||
script regress-577648-1.js
|
||||
script regress-577648-2.js
|
||||
@ -37,8 +38,9 @@ fails-if(!xulRuntime.shell) script regress-595230-1.js
|
||||
fails-if(!xulRuntime.shell) script regress-595230-2.js
|
||||
script regress-595365-1.js
|
||||
fails-if(!xulRuntime.shell) script regress-595365-2.js
|
||||
script regress-569464.js
|
||||
script regress-596103.js
|
||||
script regress-596805-1.js
|
||||
script regress-596805-2.js
|
||||
script regress-597870.js
|
||||
fails-if(!xulRuntime.shell) script regress-597945-1.js
|
||||
script regress-597945-2.js
|
||||
|
14
js/src/tests/js1_8_5/regress/regress-596805-1.js
Normal file
14
js/src/tests/js1_8_5/regress/regress-596805-1.js
Normal file
@ -0,0 +1,14 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/*
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/licenses/publicdomain/
|
||||
*/
|
||||
|
||||
var f = function(){};
|
||||
for (var y in f);
|
||||
f.j = 0;
|
||||
Object.defineProperty(f, "k", ({configurable: true}));
|
||||
delete f.j;
|
||||
Object.defineProperty(f, "k", ({get: function() {}}));
|
||||
|
||||
reportCompare(0, 0, "ok");
|
27
js/src/tests/js1_8_5/regress/regress-596805-2.js
Normal file
27
js/src/tests/js1_8_5/regress/regress-596805-2.js
Normal file
@ -0,0 +1,27 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/*
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/licenses/publicdomain/
|
||||
*/
|
||||
|
||||
for each(let c in [0, 0, 0, 0, 0]) {
|
||||
try { (function() {
|
||||
this.c = this;
|
||||
this.e = arguments;
|
||||
Object.defineProperty(this, "d", {
|
||||
get: Math.pow,
|
||||
configurable: true
|
||||
});
|
||||
delete this.e;
|
||||
delete this.c;
|
||||
Object.defineProperty(this, "d", {
|
||||
writable: true
|
||||
});
|
||||
if (Math.tan( - 1)) {
|
||||
Object.defineProperty(this, {});
|
||||
}
|
||||
} (c));
|
||||
} catch(e) {}
|
||||
}
|
||||
|
||||
reportCompare(0, 0, "ok");
|
Loading…
Reference in New Issue
Block a user