bool js::SetPropertyIgnoringNamedGetter(JSContext* cx, const BaseProxyHandler* handler, HandleObject proxy, HandleObject receiver, HandleId id, MutableHandle<PropertyDescriptor> desc, bool descIsOwn, bool strict, MutableHandleValue vp) { /* The control-flow here differs from ::get() because of the fall-through case below. */ MOZ_ASSERT_IF(descIsOwn, desc.object()); if (desc.object()) { MOZ_ASSERT(desc.getter() != JS_PropertyStub); MOZ_ASSERT(desc.setter() != JS_StrictPropertyStub); // Check for read-only properties. if (desc.isReadonly()) { if (strict) return Throw(cx, id, descIsOwn ? JSMSG_READ_ONLY : JSMSG_CANT_REDEFINE_PROP); return true; } if (desc.hasSetterObject() || desc.setter()) { if (!CallSetter(cx, receiver, id, desc.setter(), desc.attributes(), strict, vp)) return false; if (!proxy->is<ProxyObject>() || proxy->as<ProxyObject>().handler() != handler) return true; if (desc.isShared()) return true; } desc.value().set(vp.get()); if (descIsOwn) { MOZ_ASSERT(desc.object() == proxy); return handler->defineProperty(cx, proxy, id, desc); } return DefineProperty(cx, receiver, id, desc.value(), desc.getter(), desc.setter(), desc.attributes()); } desc.object().set(receiver); desc.value().set(vp.get()); desc.setAttributes(JSPROP_ENUMERATE); desc.setGetter(nullptr); desc.setSetter(nullptr); // Pick up the class getter/setter. return DefineProperty(cx, receiver, id, desc.value(), nullptr, nullptr, JSPROP_ENUMERATE); }
static bool PreprocessValue(JSContext* cx, HandleObject holder, KeyType key, MutableHandleValue vp, StringifyContext* scx) { RootedString keyStr(cx); /* Step 2. */ if (vp.isObject()) { RootedValue toJSON(cx); RootedObject obj(cx, &vp.toObject()); if (!GetProperty(cx, obj, obj, cx->names().toJSON, &toJSON)) return false; if (IsCallable(toJSON)) { keyStr = KeyStringifier<KeyType>::toString(cx, key); if (!keyStr) return false; InvokeArgs args(cx); if (!args.init(1)) return false; args.setCallee(toJSON); args.setThis(vp); args[0].setString(keyStr); if (!Invoke(cx, args)) return false; vp.set(args.rval()); } } /* Step 3. */ if (scx->replacer && scx->replacer->isCallable()) { if (!keyStr) { keyStr = KeyStringifier<KeyType>::toString(cx, key); if (!keyStr) return false; } InvokeArgs args(cx); if (!args.init(2)) return false; args.setCallee(ObjectValue(*scx->replacer)); args.setThis(ObjectValue(*holder)); args[0].setString(keyStr); args[1].set(vp); if (!Invoke(cx, args)) return false; vp.set(args.rval()); } /* Step 4. */ if (vp.get().isObject()) { RootedObject obj(cx, &vp.get().toObject()); if (ObjectClassIs(obj, ESClass_Number, cx)) { double d; if (!ToNumber(cx, vp, &d)) return false; vp.setNumber(d); } else if (ObjectClassIs(obj, ESClass_String, cx)) { JSString* str = ToStringSlow<CanGC>(cx, vp); if (!str) return false; vp.setString(str); } else if (ObjectClassIs(obj, ESClass_Boolean, cx)) { if (!Unbox(cx, obj, vp)) return false; } } return true; }
static bool PreprocessValue(JSContext *cx, JSObject *holder, KeyType key, MutableHandleValue vp, StringifyContext *scx) { JSString *keyStr = NULL; /* Step 2. */ if (vp.get().isObject()) { Value toJSON; RootedId id(cx, NameToId(cx->runtime->atomState.toJSONAtom)); Rooted<JSObject*> obj(cx, &vp.get().toObject()); if (!GetMethod(cx, obj, id, 0, &toJSON)) return false; if (js_IsCallable(toJSON)) { keyStr = KeyStringifier<KeyType>::toString(cx, key); if (!keyStr) return false; InvokeArgsGuard args; if (!cx->stack.pushInvokeArgs(cx, 1, &args)) return false; args.calleev() = toJSON; args.thisv() = vp; args[0] = StringValue(keyStr); if (!Invoke(cx, args)) return false; vp.set(args.rval()); } } /* Step 3. */ if (scx->replacer && scx->replacer->isCallable()) { if (!keyStr) { keyStr = KeyStringifier<KeyType>::toString(cx, key); if (!keyStr) return false; } InvokeArgsGuard args; if (!cx->stack.pushInvokeArgs(cx, 2, &args)) return false; args.calleev() = ObjectValue(*scx->replacer); args.thisv() = ObjectValue(*holder); args[0] = StringValue(keyStr); args[1] = vp; if (!Invoke(cx, args)) return false; vp.set(args.rval()); } /* Step 4. */ if (vp.get().isObject()) { JSObject &obj = vp.get().toObject(); if (ObjectClassIs(obj, ESClass_Number, cx)) { double d; if (!ToNumber(cx, vp, &d)) return false; vp.set(NumberValue(d)); } else if (ObjectClassIs(obj, ESClass_String, cx)) { JSString *str = ToStringSlow(cx, vp); if (!str) return false; vp.set(StringValue(str)); } else if (ObjectClassIs(obj, ESClass_Boolean, cx)) { if (!BooleanGetPrimitiveValue(cx, obj, vp.address())) return false; JS_ASSERT(vp.get().isBoolean()); } } return true; }
bool js::SetPropertyIgnoringNamedGetter(JSContext *cx, const BaseProxyHandler *handler, HandleObject proxy, HandleObject receiver, HandleId id, MutableHandle<PropertyDescriptor> desc, bool descIsOwn, bool strict, MutableHandleValue vp) { /* The control-flow here differs from ::get() because of the fall-through case below. */ if (descIsOwn) { MOZ_ASSERT(desc.object()); // Check for read-only properties. if (desc.isReadonly()) return strict ? Throw(cx, id, JSMSG_READ_ONLY) : true; if (!desc.setter()) { // Be wary of the odd explicit undefined setter case possible through // Object.defineProperty. if (!desc.hasSetterObject()) desc.setSetter(JS_StrictPropertyStub); } else if (desc.hasSetterObject() || desc.setter() != JS_StrictPropertyStub) { if (!CallSetter(cx, receiver, id, desc.setter(), desc.attributes(), strict, vp)) return false; if (!proxy->is<ProxyObject>() || proxy->as<ProxyObject>().handler() != handler) return true; if (desc.isShared()) return true; } if (!desc.getter()) { // Same as above for the null setter case. if (!desc.hasGetterObject()) desc.setGetter(JS_PropertyStub); } desc.value().set(vp.get()); return handler->defineProperty(cx, receiver, id, desc); } if (desc.object()) { // Check for read-only properties. if (desc.isReadonly()) return strict ? Throw(cx, id, JSMSG_CANT_REDEFINE_PROP) : true; if (!desc.setter()) { // Be wary of the odd explicit undefined setter case possible through // Object.defineProperty. if (!desc.hasSetterObject()) desc.setSetter(JS_StrictPropertyStub); } else if (desc.hasSetterObject() || desc.setter() != JS_StrictPropertyStub) { if (!CallSetter(cx, receiver, id, desc.setter(), desc.attributes(), strict, vp)) return false; if (!proxy->is<ProxyObject>() || proxy->as<ProxyObject>().handler() != handler) return true; if (desc.isShared()) return true; } if (!desc.getter()) { // Same as above for the null setter case. if (!desc.hasGetterObject()) desc.setGetter(JS_PropertyStub); } desc.value().set(vp.get()); return JSObject::defineGeneric(cx, receiver, id, desc.value(), desc.getter(), desc.setter(), desc.attributes()); } desc.object().set(receiver); desc.value().set(vp.get()); desc.setAttributes(JSPROP_ENUMERATE); desc.setGetter(nullptr); desc.setSetter(nullptr); // Pick up the class getter/setter. return JSObject::defineGeneric(cx, receiver, id, desc.value(), nullptr, nullptr, JSPROP_ENUMERATE); }
static bool PreprocessValue(JSContext *cx, HandleObject holder, KeyType key, MutableHandleValue vp, StringifyContext *scx) { RootedString keyStr(cx); /* Step 2. */ if (vp.isObject()) { RootedValue toJSON(cx); RootedObject obj(cx, &vp.toObject()); if (!JSObject::getProperty(cx, obj, obj, cx->names().toJSON, &toJSON)) return false; if (js_IsCallable(toJSON)) { keyStr = KeyStringifier<KeyType>::toString(cx, key); if (!keyStr) return false; InvokeArgsGuard args; if (!cx->stack.pushInvokeArgs(cx, 1, &args)) return false; args.setCallee(toJSON); args.setThis(vp); args[0] = StringValue(keyStr); if (!Invoke(cx, args)) return false; vp.set(args.rval()); } } /* Step 3. */ if (scx->replacer && scx->replacer->isCallable()) { if (!keyStr) { keyStr = KeyStringifier<KeyType>::toString(cx, key); if (!keyStr) return false; } InvokeArgsGuard args; if (!cx->stack.pushInvokeArgs(cx, 2, &args)) return false; args.setCallee(ObjectValue(*scx->replacer)); args.setThis(ObjectValue(*holder)); args[0] = StringValue(keyStr); args[1] = vp; if (!Invoke(cx, args)) return false; vp.set(args.rval()); } /* Step 4. */ if (vp.get().isObject()) { RootedObject obj(cx, &vp.get().toObject()); if (ObjectClassIs(obj, ESClass_Number, cx)) { double d; if (!ToNumber(cx, vp, &d)) return false; vp.set(NumberValue(d)); } else if (ObjectClassIs(obj, ESClass_String, cx)) { JSString *str = ToStringSlow<CanGC>(cx, vp); if (!str) return false; vp.set(StringValue(str)); } else if (ObjectClassIs(obj, ESClass_Boolean, cx)) { if (!BooleanGetPrimitiveValue(cx, obj, vp.address())) return false; JS_ASSERT(vp.get().isBoolean()); } } return true; }
static bool PreprocessValue(JSContext* cx, HandleObject holder, KeyType key, MutableHandleValue vp, StringifyContext* scx) { // We don't want to do any preprocessing here if scx->maybeSafely, // since the stuff we do here can have side-effects. if (scx->maybeSafely) return true; RootedString keyStr(cx); /* Step 2. */ if (vp.isObject()) { RootedValue toJSON(cx); RootedObject obj(cx, &vp.toObject()); if (!GetProperty(cx, obj, obj, cx->names().toJSON, &toJSON)) return false; if (IsCallable(toJSON)) { keyStr = KeyStringifier<KeyType>::toString(cx, key); if (!keyStr) return false; RootedValue arg0(cx, StringValue(keyStr)); if (!js::Call(cx, toJSON, vp, arg0, vp)) return false; } } /* Step 3. */ if (scx->replacer && scx->replacer->isCallable()) { if (!keyStr) { keyStr = KeyStringifier<KeyType>::toString(cx, key); if (!keyStr) return false; } RootedValue arg0(cx, StringValue(keyStr)); RootedValue replacerVal(cx, ObjectValue(*scx->replacer)); if (!js::Call(cx, replacerVal, holder, arg0, vp, vp)) return false; } /* Step 4. */ if (vp.get().isObject()) { RootedObject obj(cx, &vp.get().toObject()); ESClass cls; if (!GetBuiltinClass(cx, obj, &cls)) return false; if (cls == ESClass::Number) { double d; if (!ToNumber(cx, vp, &d)) return false; vp.setNumber(d); } else if (cls == ESClass::String) { JSString* str = ToStringSlow<CanGC>(cx, vp); if (!str) return false; vp.setString(str); } else if (cls == ESClass::Boolean) { if (!Unbox(cx, obj, vp)) return false; } } return true; }