--- a/js/src/vm/NativeObject.cpp
+++ b/js/src/vm/NativeObject.cpp
@@ -1933,16 +1933,22 @@ MaybeReportUndeclaredVarAssignment(JSCon
JS_ReportErrorFlagsAndNumber(cx,
(JSREPORT_WARNING | JSREPORT_STRICT
| JSREPORT_STRICT_MODE_ERROR),
js_GetErrorMessage, nullptr,
JSMSG_UNDECLARED_VAR, bytes.ptr());
}
template <ExecutionMode mode>
+static bool
+SetPropertyByDefining(typename ExecutionModeTraits<mode>::ContextType cxArg,
+ Handle<NativeObject*> obj, HandleId id, unsigned attrs, HandleValue v,
+ bool strict);
+
+template <ExecutionMode mode>
bool
baseops::SetPropertyHelper(typename ExecutionModeTraits<mode>::ContextType cxArg,
HandleNativeObject obj, HandleObject receiver, HandleId id,
QualifiedBool qualified, MutableHandleValue vp, bool strict)
{
MOZ_ASSERT(cxArg->isThreadLocal(obj));
if (MOZ_UNLIKELY(obj->watched())) {
@@ -2119,60 +2125,77 @@ baseops::SetPropertyHelper(typename Exec
return true;
}
if (obj->is<ArrayObject>() && id == NameToId(cxArg->names().length)) {
Rooted<ArrayObject*> arr(cxArg, &obj->as<ArrayObject>());
return ArraySetLength<mode>(cxArg, arr, id, attrs, vp, strict);
}
- if (!shape) {
- bool extensible;
- if (mode == ParallelExecution) {
- if (obj->is<ProxyObject>())
- return false;
- extensible = obj->nonProxyIsExtensible();
- } else {
- if (!JSObject::isExtensible(cxArg->asJSContext(), obj, &extensible))
- return false;
- }
+ if (shape)
+ return NativeSet<mode>(cxArg, obj, receiver, shape, strict, vp);
+ return SetPropertyByDefining<mode>(cxArg, obj, id, attrs, vp, strict);
+}
- if (!extensible) {
- /* Error in strict mode code, warn with extra warnings option, otherwise do nothing. */
- if (strict)
- return obj->reportNotExtensible(cxArg);
- if (mode == SequentialExecution &&
- cxArg->asJSContext()->compartment()->options().extraWarnings(cxArg->asJSContext()))
- {
- return obj->reportNotExtensible(cxArg, JSREPORT_STRICT | JSREPORT_WARNING);
- }
- return true;
- }
-
- const Class *clasp = obj->getClass();
- if (mode == ParallelExecution) {
- if (obj->isDelegate())
- return false;
-
- if (clasp->getProperty != JS_PropertyStub || !types::HasTypePropertyId(obj, id, vp))
- return false;
- } else {
- JSContext *cx = cxArg->asJSContext();
-
- /* Purge the property cache of now-shadowed id in obj's scope chain. */
- if (!PurgeScopeChain(cx, obj, id))
- return false;
- }
-
- return DefinePropertyOrElement<mode>(cxArg, obj, id,
- clasp->getProperty, clasp->setProperty,
- attrs, vp, true, strict);
+/*
+ * When a [[Set]] operation finds no existing property with the given id
+ * or finds a writable data property on the prototype chain, we end up here.
+ * Finish the [[Set]] by defining a new property on obj.
+ *
+ * (FIXME: Should really define it on receiver, not obj.)
+ *
+ * This should follow ES6 draft rev 28, 9.1.9 [[Set]] steps 5.c-f, but it
+ * is really old code and we're not there yet.
+ */
+template <ExecutionMode mode>
+static bool
+SetPropertyByDefining(typename ExecutionModeTraits<mode>::ContextType cxArg,
+ Handle<NativeObject*> obj, HandleId id, unsigned attrs, HandleValue v,
+ bool strict)
+{
+ bool extensible;
+ if (mode == ParallelExecution) {
+ if (obj->is<ProxyObject>())
+ return false;
+ extensible = obj->nonProxyIsExtensible();
+ } else {
+ if (!JSObject::isExtensible(cxArg->asJSContext(), obj, &extensible))
+ return false;
}
- return NativeSet<mode>(cxArg, obj, receiver, shape, strict, vp);
+ if (!extensible) {
+ /* Error in strict mode code, warn with extra warnings option, otherwise do nothing. */
+ if (strict)
+ return obj->reportNotExtensible(cxArg);
+ if (mode == SequentialExecution &&
+ cxArg->asJSContext()->compartment()->options().extraWarnings(cxArg->asJSContext()))
+ {
+ return obj->reportNotExtensible(cxArg, JSREPORT_STRICT | JSREPORT_WARNING);
+ }
+ return true;
+ }
+
+ const Class *clasp = obj->getClass();
+ if (mode == ParallelExecution) {
+ if (obj->isDelegate())
+ return false;
+
+ if (clasp->getProperty != JS_PropertyStub || !types::HasTypePropertyId(obj, id, v))
+ return false;
+ } else {
+ JSContext *cx = cxArg->asJSContext();
+
+ /* Purge the property cache of now-shadowed id in obj's scope chain. */
+ if (!PurgeScopeChain(cx, obj, id))
+ return false;
+ }
+
+ return DefinePropertyOrElement<mode>(cxArg, obj, id,
+ clasp->getProperty, clasp->setProperty,
+ attrs, v, true, strict);
}
template bool
baseops::SetPropertyHelper<SequentialExecution>(JSContext *cx, HandleNativeObject obj,
HandleObject receiver, HandleId id,
QualifiedBool qualified,
MutableHandleValue vp, bool strict);
template bool