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; }
static bool PreprocessValue(JSContext *cx, JSObject *holder, KeyType key, Value *vp, StringifyContext *scx) { JSString *keyStr = NULL; /* Step 2. */ if (vp->isObject()) { Value toJSON; jsid id = ATOM_TO_JSID(cx->runtime->atomState.toJSONAtom); if (!js_GetMethod(cx, &vp->toObject(), id, JSGET_NO_METHOD_BARRIER, &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 = 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 = args.rval(); } /* Step 4. */ if (vp->isObject()) { JSObject &obj = vp->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(cx, *vp); if (!str) return false; vp->setString(str); } else if (ObjectClassIs(obj, ESClass_Boolean, cx)) { if (!BooleanGetPrimitiveValue(cx, obj, vp)) return false; JS_ASSERT(vp->isBoolean()); } } return true; }
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; }
bool js::GetElement(JSContext *cx, Handle<ObjectImpl*> obj, Handle<ObjectImpl*> receiver, uint32_t index, unsigned resolveFlags, Value *vp) { NEW_OBJECT_REPRESENTATION_ONLY(); Rooted<ObjectImpl*> current(cx, obj); RootedValue getter(cx); do { MOZ_ASSERT(current); if (Downcast(current)->isProxy()) { MOZ_NOT_REACHED("NYI: proxy [[GetP]]"); return false; } PropDesc desc; if (!GetOwnElement(cx, current, index, resolveFlags, &desc)) return false; /* No property? Recur or bottom out. */ if (desc.isUndefined()) { current = current->getProto(); if (current) continue; vp->setUndefined(); return true; } /* If it's a data property, return the value. */ if (desc.isDataDescriptor()) { *vp = desc.value(); return true; } /* If it's an accessor property, call its [[Get]] with the receiver. */ if (desc.isAccessorDescriptor()) { getter = desc.getterValue(); if (getter.isUndefined()) { vp->setUndefined(); return true; } InvokeArgsGuard args; if (!cx->stack.pushInvokeArgs(cx, 0, &args)) return false; /* Push getter, receiver, and no args. */ args.setCallee(getter); args.setThis(ObjectValue(*current)); bool ok = Invoke(cx, args); *vp = args.rval(); return ok; } /* Otherwise it's a PropertyOp-based property. XXX handle this! */ MOZ_NOT_REACHED("NYI: handle PropertyOp'd properties here"); return false; } while (false); MOZ_NOT_REACHED("buggy control flow"); return false; }
bool js::GetProperty(JSContext *cx, Handle<ObjectImpl*> obj, Handle<ObjectImpl*> receiver, Handle<PropertyId> pid, unsigned resolveFlags, MutableHandle<Value> vp) { NEW_OBJECT_REPRESENTATION_ONLY(); MOZ_ASSERT(receiver); Rooted<ObjectImpl*> current(cx, obj); do { MOZ_ASSERT(obj); if (Downcast(current)->isProxy()) { MOZ_NOT_REACHED("NYI: proxy [[GetP]]"); return false; } PropDesc desc; PropDesc::AutoRooter rootDesc(cx, &desc); if (!GetOwnProperty(cx, current, pid, resolveFlags, &desc)) return false; /* No property? Recur or bottom out. */ if (desc.isUndefined()) { current = current->getProto(); if (current) continue; vp.setUndefined(); return true; } /* If it's a data property, return the value. */ if (desc.isDataDescriptor()) { vp.set(desc.value()); return true; } /* If it's an accessor property, call its [[Get]] with the receiver. */ if (desc.isAccessorDescriptor()) { Rooted<Value> get(cx, desc.getterValue()); if (get.isUndefined()) { vp.setUndefined(); return true; } InvokeArgsGuard args; if (!cx->stack.pushInvokeArgs(cx, 0, &args)) return false; args.setCallee(get); args.setThis(ObjectValue(*receiver)); bool ok = Invoke(cx, args); vp.set(args.rval()); return ok; } /* Otherwise it's a PropertyOp-based property. XXX handle this! */ MOZ_NOT_REACHED("NYI: handle PropertyOp'd properties here"); return false; } while (false); MOZ_NOT_REACHED("buggy control flow"); return false; }
bool js::GetElement(JSContext *cx, ObjectImpl *obj, ObjectImpl *receiver, uint32_t index, Value *vp) { NEW_OBJECT_REPRESENTATION_ONLY(); do { MOZ_ASSERT(obj); if (static_cast<JSObject *>(obj)->isProxy()) { // XXX MOZ_NOT_REACHED("NYI: proxy [[GetP]]"); return false; } PropDesc desc; if (!GetOwnElement(cx, obj, index, &desc)) return false; /* No property? Recur or bottom out. */ if (desc.isUndefined()) { obj = obj->getProto(); if (obj) continue; vp->setUndefined(); return true; } /* If it's a data property, return the value. */ if (desc.isDataDescriptor()) { *vp = desc.value(); return true; } /* If it's an accessor property, call its [[Get]] with the receiver. */ if (desc.isAccessorDescriptor()) { Value get = desc.getterValue(); if (get.isUndefined()) { vp->setUndefined(); return true; } InvokeArgsGuard args; if (!cx->stack.pushInvokeArgs(cx, 0, &args)) return false; /* Push get, receiver, and no args. */ args.calleev() = get; args.thisv() = ObjectValue(*receiver); bool ok = Invoke(cx, args); *vp = args.rval(); return ok; } /* Otherwise it's a PropertyOp-based property. XXX handle this! */ MOZ_NOT_REACHED("NYI: handle PropertyOp'd properties here"); return false; } while (false); MOZ_NOT_REACHED("buggy control flow"); return false; }
/* * ES5 15.12.3 Str, steps 2-4, extracted to enable preprocessing of property * values when stringifying objects in JO. */ static bool PreprocessValue(JSContext *cx, JSObject *holder, jsid key, Value *vp, StringifyContext *scx) { JSString *keyStr = NULL; /* Step 2. */ if (vp->isObject()) { Value toJSON; jsid id = ATOM_TO_JSID(cx->runtime->atomState.toJSONAtom); if (!js_GetMethod(cx, &vp->toObject(), id, JSGET_NO_METHOD_BARRIER, &toJSON)) return false; if (js_IsCallable(toJSON)) { keyStr = IdToString(cx, key); if (!keyStr) return false; LeaveTrace(cx); 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 = args.rval(); } } /* Step 3. */ if (scx->replacer && scx->replacer->isCallable()) { if (!keyStr) { keyStr = IdToString(cx, key); if (!keyStr) return false; } LeaveTrace(cx); 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 = args.rval(); } /* Step 4. */ if (vp->isObject()) { JSObject *obj = &vp->toObject(); Class *clasp = obj->getClass(); if (clasp == &js_NumberClass) { double d; if (!ValueToNumber(cx, *vp, &d)) return false; vp->setNumber(d); } else if (clasp == &js_StringClass) { JSString *str = js_ValueToString(cx, *vp); if (!str) return false; vp->setString(str); } else if (clasp == &js_BooleanClass) { *vp = obj->getPrimitiveThis(); JS_ASSERT(vp->isBoolean()); } } return true; }