diff -r 10871af7350c js/src/js.msg --- a/js/src/js.msg Mon Aug 20 16:56:14 2012 +0200 +++ b/js/src/js.msg Mon Aug 20 16:58:28 2012 +0200 @@ -353,8 +353,11 @@ MSG_DEF(JSMSG_REST_WITH_DEFAULT, 29 MSG_DEF(JSMSG_NONDEFAULT_FORMAL_AFTER_DEFAULT, 300, 0, JSEXN_SYNTAXERR, "parameter(s) with default followed by parameter without default") MSG_DEF(JSMSG_YIELD_IN_DEFAULT, 301, 0, JSEXN_SYNTAXERR, "yield in default expression") MSG_DEF(JSMSG_INTRINSIC_NOT_DEFINED, 302, 1, JSEXN_REFERENCEERR, "no intrinsic function {0}") MSG_DEF(JSMSG_CANT_REPORT_NC_AS_NE, 303, 0, JSEXN_TYPEERR, "proxy can't report a non-configurable own property as non-existent") MSG_DEF(JSMSG_CANT_REPORT_E_AS_NE, 304, 0, JSEXN_TYPEERR, "proxy can't report an existing own property as non-existent on a non-extensible object") MSG_DEF(JSMSG_CANT_REPORT_NEW, 305, 0, JSEXN_TYPEERR, "proxy can't report a new property on a non-extensible object") MSG_DEF(JSMSG_CANT_REPORT_INVALID, 306, 0, JSEXN_TYPEERR, "proxy can't report an incompatible property descriptor") MSG_DEF(JSMSG_CANT_REPORT_NE_AS_NC, 307, 0, JSEXN_TYPEERR, "proxy can't report a non-existent property as non-configurable") +MSG_DEF(JSMSG_CANT_DEFINE_NEW, 308, 0, JSEXN_TYPEERR, "proxy can't define a new property on a non-extensible object") +MSG_DEF(JSMSG_CANT_DEFINE_INVALID, 309, 0, JSEXN_TYPEERR, "proxy can't define an incompatible property descriptor") +MSG_DEF(JSMSG_CANT_DEFINE_NE_AS_NC, 310, 0, JSEXN_TYPEERR, "proxy can't define a non-existent property as non-configurable") diff -r 10871af7350c js/src/jsobj.cpp --- a/js/src/jsobj.cpp Mon Aug 20 16:56:14 2012 +0200 +++ b/js/src/jsobj.cpp Mon Aug 20 16:58:28 2012 +0200 @@ -1877,16 +1877,20 @@ namespace js { bool DefineProperty(JSContext *cx, HandleObject obj, HandleId id, const PropDesc &desc, bool throwError, bool *rval) { if (obj->isArray()) return DefinePropertyOnArray(cx, obj, id, desc, throwError, rval); if (obj->getOps()->lookupGeneric) { + /* + * FIXME: Once ScriptedIndirectProxies are removed, this code should call + * TrapDefineOwnProperty directly + */ if (obj->isProxy()) return Proxy::defineProperty(cx, obj, id, desc.pd()); return Reject(cx, obj, JSMSG_OBJECT_NOT_EXTENSIBLE, throwError, rval); } return DefinePropertyOnObject(cx, obj, id, desc, throwError, rval); } diff -r 10871af7350c js/src/jsproxy.cpp --- a/js/src/jsproxy.cpp Mon Aug 20 16:56:14 2012 +0200 +++ b/js/src/jsproxy.cpp Mon Aug 20 16:58:28 2012 +0200 @@ -1378,16 +1378,99 @@ TrapGetOwnProperty(JSContext *cx, Handle return false; } // step 12 rval.set(trapResult); return true; } +// TrapDefineOwnProperty(O, P, DescObj, Throw) +static bool +TrapDefineOwnProperty(JSContext *cx, HandleObject proxy, HandleId id, MutableHandleValue vp) +{ + // step 1 + RootedObject handler(cx, GetDirectProxyHandlerObject(proxy)); + + // step 2 + RootedObject target(cx, GetProxyTargetObject(proxy)); + + // step 3 + RootedValue trap(cx); + if (!handler->getProperty(cx, ATOM(defineProperty), &trap)) + return false; + + // step 4 + if (trap.isUndefined()) { + AutoPropertyDescriptorRooter desc(cx); + if (!ParsePropertyDescriptorObject(cx, proxy, vp, &desc)) + return false; + return JS_DefinePropertyById(cx, target, id, desc.value, desc.getter, desc.setter, + desc.attrs); + } + + // step 5 + RootedValue normalizedDesc(cx, vp); + if (!NormalizePropertyDescriptor(cx, &normalizedDesc)) + return false; + + // step 6 + JSString *name = ToString(cx, IdToValue(id)); + if (!name) + return false; + Value argv[] = { + ObjectValue(*target), + StringValue(name), + normalizedDesc + }; + RootedValue trapResult(cx); + if (!Invoke(cx, ObjectValue(*handler), trap, 3, argv, trapResult.address())) + return false; + + // steps 7-8 + if (ToBoolean(trapResult)) { + bool isFixed; + if (!HasOwn(cx, target, id, &isFixed)) + return false; + + if (!target->isExtensible() && !isFixed) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_DEFINE_NEW); + return false; + } + + AutoPropDescArrayRooter descs(cx); + PropDesc *desc = descs.append(); + if (!desc || !desc->initialize(cx, normalizedDesc)) + return false; + + if (isFixed) { + bool valid; + if (!ValidateProperty(cx, target, id, desc, &valid)) + return false; + if (!valid) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_DEFINE_INVALID); + return false; + } + } + + if (!desc->configurable() && !isFixed) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_DEFINE_NE_AS_NC); + return false; + } + + vp.set(BooleanValue(true)); + return true; + } + + // step 9 + // FIXME: API does not include a Throw parameter + vp.set(BooleanValue(false)); + return true; +} + ScriptedDirectProxyHandler::ScriptedDirectProxyHandler() : DirectProxyHandler(&sScriptedDirectProxyHandlerFamily) { } ScriptedDirectProxyHandler::~ScriptedDirectProxyHandler() { } @@ -1429,21 +1512,32 @@ ScriptedDirectProxyHandler::getOwnProper return true; } // steps 3-4 return ParsePropertyDescriptorObject(cx, proxy, v, desc, true); } bool -ScriptedDirectProxyHandler::defineProperty(JSContext *cx, JSObject *proxy, jsid id, +ScriptedDirectProxyHandler::defineProperty(JSContext *cx, JSObject *proxy_, jsid id_, PropertyDescriptor *desc) { - JS_NOT_REACHED("not yet implemented"); - return false; + RootedObject proxy(cx, proxy_); + RootedId id(cx, id_); + + // step 1 + AutoPropDescArrayRooter descs(cx); + PropDesc *d = descs.append(); + d->initFromPropertyDescriptor(*desc); + RootedValue v(cx); + if (!FromGenericPropertyDescriptor(cx, d, &v)) + return false; + + // step 2 + return TrapDefineOwnProperty(cx, proxy, id, &v); } bool ScriptedDirectProxyHandler::getOwnPropertyNames(JSContext *cx, JSObject *proxy, AutoIdVector &props) { JS_NOT_REACHED("not yet implemented"); return false;