bool BaseDOMProxyHandler::getPropertyDescriptor(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id, MutableHandle<JSPropertyDescriptor> desc, unsigned flags) { if (!getOwnPropertyDescriptor(cx, proxy, id, desc, flags)) { return false; } if (desc.object()) { return true; } JS::Rooted<JSObject*> proto(cx); if (!js::GetObjectProto(cx, proxy, &proto)) { return false; } if (!proto) { desc.object().set(nullptr); return true; } return JS_GetPropertyDescriptorById(cx, proto, id, 0, desc); }
bool ModuleNamespaceObject::ProxyHandler::getOwnPropertyDescriptor(JSContext* cx, HandleObject proxy, HandleId id, MutableHandle<PropertyDescriptor> desc) const { Rooted<ModuleNamespaceObject*> ns(cx, &proxy->as<ModuleNamespaceObject>()); if (JSID_IS_SYMBOL(id)) { Rooted<JS::Symbol*> symbol(cx, JSID_TO_SYMBOL(id)); if (symbol == cx->wellKnownSymbols().iterator) { RootedValue enumerateFun(cx, getEnumerateFunction(proxy)); desc.object().set(proxy); desc.setConfigurable(false); desc.setEnumerable(false); desc.setValue(enumerateFun); return true; } if (symbol == cx->wellKnownSymbols().toStringTag) { RootedValue value(cx, StringValue(cx->names().Module)); desc.object().set(proxy); desc.setWritable(false); desc.setEnumerable(false); desc.setConfigurable(true); desc.setValue(value); return true; } return true; } const IndirectBindingMap& bindings = ns->bindings(); ModuleEnvironmentObject* env; Shape* shape; if (!bindings.lookup(id, &env, &shape)) return true; RootedValue value(cx, env->getSlot(shape->slot())); if (value.isMagic(JS_UNINITIALIZED_LEXICAL)) { ReportRuntimeLexicalError(cx, JSMSG_UNINITIALIZED_LEXICAL, id); return false; } desc.object().set(env); desc.setConfigurable(false); desc.setEnumerable(true); desc.setValue(value); return true; }
bool JavaScriptShared::toDescriptor(JSContext* cx, const PPropertyDescriptor& in, MutableHandle<JSPropertyDescriptor> out) { out.setAttributes(in.attrs()); if (!fromVariant(cx, in.value(), out.value())) return false; out.object().set(fromObjectOrNullVariant(cx, in.obj())); if (in.getter().type() == GetterSetter::Tuint64_t && !in.getter().get_uint64_t()) { out.setGetter(nullptr); } else if (in.attrs() & JSPROP_GETTER) { Rooted<JSObject*> getter(cx); getter = fromObjectVariant(cx, in.getter().get_ObjectVariant()); if (!getter) return false; out.setGetter(JS_DATA_TO_FUNC_PTR(JSGetterOp, getter.get())); } else { out.setGetter(UnknownPropertyStub); } if (in.setter().type() == GetterSetter::Tuint64_t && !in.setter().get_uint64_t()) { out.setSetter(nullptr); } else if (in.attrs() & JSPROP_SETTER) { Rooted<JSObject*> setter(cx); setter = fromObjectVariant(cx, in.setter().get_ObjectVariant()); if (!setter) return false; out.setSetter(JS_DATA_TO_FUNC_PTR(JSSetterOp, setter.get())); } else { out.setSetter(UnknownStrictPropertyStub); } return true; }
bool OpaqueCrossCompartmentWrapper::getOwnPropertyDescriptor(JSContext* cx, HandleObject wrapper, HandleId id, MutableHandle<PropertyDescriptor> desc) const { desc.object().set(nullptr); 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. */ 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); }
bool BaseProxyHandler::getPropertyDescriptor(JSContext* cx, HandleObject proxy, HandleId id, MutableHandle<PropertyDescriptor> desc) const { assertEnteredPolicy(cx, proxy, id, GET | SET | GET_PROPERTY_DESCRIPTOR); if (!getOwnPropertyDescriptor(cx, proxy, id, desc)) return false; if (desc.object()) return true; RootedObject proto(cx); if (!GetPrototype(cx, proxy, &proto)) return false; if (!proto) { MOZ_ASSERT(!desc.object()); return true; } return GetPropertyDescriptor(cx, proto, id, desc); }
bool AddonWrapper<Base>::getOwnPropertyDescriptor(JSContext* cx, HandleObject wrapper, HandleId id, MutableHandle<JSPropertyDescriptor> desc) const { if (!InterposeProperty(cx, wrapper, nullptr, id, desc)) return false; if (desc.object()) return true; return Base::getOwnPropertyDescriptor(cx, wrapper, id, desc); }
bool Proxy::getOwnPropertyDescriptor(JSContext* cx, HandleObject proxy, HandleId id, MutableHandle<PropertyDescriptor> desc) { if (!CheckRecursionLimit(cx)) return false; const BaseProxyHandler* handler = proxy->as<ProxyObject>().handler(); desc.object().set(nullptr); // default result if we refuse to perform this action AutoEnterPolicy policy(cx, handler, proxy, id, BaseProxyHandler::GET_PROPERTY_DESCRIPTOR, true); if (!policy.allowed()) return policy.returnValue(); return handler->getOwnPropertyDescriptor(cx, proxy, id, desc); }
bool JSCompartment::wrap(JSContext* cx, MutableHandle<PropertyDescriptor> desc) { if (!wrap(cx, desc.object())) return false; if (desc.hasGetterObject()) { if (!wrap(cx, desc.getterObject())) return false; } if (desc.hasSetterObject()) { if (!wrap(cx, desc.setterObject())) return false; } return wrap(cx, desc.value()); }
bool JavaScriptShared::toDescriptor(JSContext *cx, const PPropertyDescriptor &in, MutableHandle<JSPropertyDescriptor> out) { out.setAttributes(in.attrs()); out.setShortId(in.shortid()); if (!toValue(cx, in.value(), out.value())) return false; Rooted<JSObject*> obj(cx); if (!unwrap(cx, in.objId(), &obj)) return false; out.object().set(obj); if (!in.getter()) { out.setGetter(nullptr); } else if (in.attrs() & JSPROP_GETTER) { Rooted<JSObject*> getter(cx); if (!unwrap(cx, in.getter(), &getter)) return false; out.setGetter(JS_DATA_TO_FUNC_PTR(JSPropertyOp, getter.get())); } else { if (in.getter() == DefaultPropertyOp) out.setGetter(JS_PropertyStub); else out.setGetter(UnknownPropertyStub); } if (!in.setter()) { out.setSetter(nullptr); } else if (in.attrs() & JSPROP_SETTER) { Rooted<JSObject*> setter(cx); if (!unwrap(cx, in.setter(), &setter)) return false; out.setSetter(JS_DATA_TO_FUNC_PTR(JSStrictPropertyOp, setter.get())); } else { if (in.setter() == DefaultPropertyOp) out.setSetter(JS_StrictPropertyStub); else if (in.setter() == GetterOnlyPropertyStub) out.setSetter(js_GetterOnlyPropertyStub); else out.setSetter(UnknownStrictPropertyStub); } return true; }
bool impl(JSContext *cx, HandleObject proxy, HandleId id, MutableHandle<JSPropertyDescriptor> desc, bool ownOnly) const { if (JSID_IS_STRING(id)) { bool match; if (!JS_StringEqualsAscii(cx, JSID_TO_STRING(id), "phantom", &match)) return false; if (match) { desc.object().set(proxy); desc.attributesRef() = JSPROP_READONLY | JSPROP_ENUMERATE; desc.value().setInt32(42); return true; } } if (ownOnly) return DirectProxyHandler::getOwnPropertyDescriptor(cx, proxy, id, desc); return DirectProxyHandler::getPropertyDescriptor(cx, proxy, id, desc); }
// ES6 (5 April 2014) 9.5.5 Proxy.[[GetOwnProperty]](P) bool ScriptedDirectProxyHandler::getOwnPropertyDescriptor(JSContext* cx, HandleObject proxy, HandleId id, MutableHandle<PropertyDescriptor> desc) const { // step 2 RootedObject handler(cx, GetDirectProxyHandlerObject(proxy)); // step 3 if (!handler) { JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_PROXY_REVOKED); return false; } // step 4 RootedObject target(cx, proxy->as<ProxyObject>().target()); // step 5-6 RootedValue trap(cx); if (!GetProperty(cx, handler, handler, cx->names().getOwnPropertyDescriptor, &trap)) return false; // step 7 if (trap.isUndefined()) return GetOwnPropertyDescriptor(cx, target, id, desc); // step 8-9 RootedValue propKey(cx); if (!IdToStringOrSymbol(cx, id, &propKey)) return false; Value argv[] = { ObjectValue(*target), propKey }; RootedValue trapResult(cx); if (!Invoke(cx, ObjectValue(*handler), trap, ArrayLength(argv), argv, &trapResult)) return false; // step 10 if (!trapResult.isUndefined() && !trapResult.isObject()) { JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_PROXY_GETOWN_OBJORUNDEF); return false; } //step 11-12 Rooted<PropertyDescriptor> targetDesc(cx); if (!GetOwnPropertyDescriptor(cx, target, id, &targetDesc)) return false; // step 13 if (trapResult.isUndefined()) { // substep a if (!targetDesc.object()) { desc.object().set(nullptr); return true; } // substep b if (!targetDesc.configurable()) { JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_CANT_REPORT_NC_AS_NE); return false; } // substep c-e bool extensibleTarget; if (!IsExtensible(cx, target, &extensibleTarget)) return false; if (!extensibleTarget) { JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_CANT_REPORT_E_AS_NE); return false; } // substep f desc.object().set(nullptr); return true; } // step 14-15 bool extensibleTarget; if (!IsExtensible(cx, target, &extensibleTarget)) return false; // step 16-17 Rooted<PropertyDescriptor> resultDesc(cx); if (!ToPropertyDescriptor(cx, trapResult, true, &resultDesc)) return false; // step 18 CompletePropertyDescriptor(&resultDesc); // step 19 bool valid; if (!ValidatePropertyDescriptor(cx, extensibleTarget, resultDesc, targetDesc, &valid)) return false; // step 20 if (!valid) { JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_CANT_REPORT_INVALID); return false; } // step 21 if (!resultDesc.configurable()) { if (!targetDesc.object()) { JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_CANT_REPORT_NE_AS_NC); return false; } if (targetDesc.configurable()) { JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_CANT_REPORT_C_AS_NC); return false; } } // step 22 desc.set(resultDesc); desc.object().set(proxy); 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); }
// ES8 rev 0c1bd3004329336774cbc90de727cd0cf5f11e93 9.5.5 Proxy.[[GetOwnProperty]](P) bool ScriptedProxyHandler::getOwnPropertyDescriptor(JSContext* cx, HandleObject proxy, HandleId id, MutableHandle<PropertyDescriptor> desc) const { // Steps 2-4. RootedObject handler(cx, ScriptedProxyHandler::handlerObject(proxy)); if (!handler) { JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_PROXY_REVOKED); return false; } // Step 5. RootedObject target(cx, proxy->as<ProxyObject>().target()); MOZ_ASSERT(target); // Step 6. RootedValue trap(cx); if (!GetProxyTrap(cx, handler, cx->names().getOwnPropertyDescriptor, &trap)) return false; // Step 7. if (trap.isUndefined()) return GetOwnPropertyDescriptor(cx, target, id, desc); // Step 8. RootedValue propKey(cx); if (!IdToStringOrSymbol(cx, id, &propKey)) return false; RootedValue trapResult(cx); RootedValue targetVal(cx, ObjectValue(*target)); if (!Call(cx, trap, handler, targetVal, propKey, &trapResult)) return false; // Step 9. if (!trapResult.isUndefined() && !trapResult.isObject()) return js::Throw(cx, id, JSMSG_PROXY_GETOWN_OBJORUNDEF); // Step 10. Rooted<PropertyDescriptor> targetDesc(cx); if (!GetOwnPropertyDescriptor(cx, target, id, &targetDesc)) return false; // Step 11. if (trapResult.isUndefined()) { // Step 11a. if (!targetDesc.object()) { desc.object().set(nullptr); return true; } // Step 11b. if (!targetDesc.configurable()) return js::Throw(cx, id, JSMSG_CANT_REPORT_NC_AS_NE); // Steps 11c-d. bool extensibleTarget; if (!IsExtensible(cx, target, &extensibleTarget)) return false; // Step 11e. if (!extensibleTarget) return js::Throw(cx, id, JSMSG_CANT_REPORT_E_AS_NE); // Step 11f. desc.object().set(nullptr); return true; } // Step 12. bool extensibleTarget; if (!IsExtensible(cx, target, &extensibleTarget)) return false; // Step 13. Rooted<PropertyDescriptor> resultDesc(cx); if (!ToPropertyDescriptor(cx, trapResult, true, &resultDesc)) return false; // Step 14. CompletePropertyDescriptor(&resultDesc); // Step 15. const char* errorDetails = nullptr; if (!IsCompatiblePropertyDescriptor(cx, extensibleTarget, resultDesc, targetDesc, &errorDetails)) return false; // Step 16. if (errorDetails) return js::Throw(cx, id, JSMSG_CANT_REPORT_INVALID, errorDetails); // Step 17. if (!resultDesc.configurable()) { if (!targetDesc.object()) return js::Throw(cx, id, JSMSG_CANT_REPORT_NE_AS_NC); if (targetDesc.configurable()) return js::Throw(cx, id, JSMSG_CANT_REPORT_C_AS_NC); } // Step 18. desc.set(resultDesc); desc.object().set(proxy); return true; }