Files
palemoon27/dom/bindings/DOMJSProxyHandler.cpp
T
roytam1 fed7084085 import changes from `dev' branch of rmottola/Arctic-Fox:
- Bug 1190733 - Test initializedLength() instead of length() during the fast path for reversing unboxed arrays, r=jandem. (b5dcbd0e3)
- Bug 1070767 - Enable {Array, %TypedArray%}.prototype.includes in all builds. r=lth (de595c002)
- Bug 1195298 - Fix NewDenseArray intrinsic to work when the first argument is a double. r=till (1f551ada2)
- Bug 1190727 - Make initialization of temporary results array resilient against Array.prototype setters in self-hosted Map#next implementation. r=jandem (d705c623c)
- Bug 1200108 - Remove NewDenseArray intrinsic, use std_Array instead. r=till (e5c4126c6)
- Bug 1199822 - Turn self-hosting's cycle-check into an assertion; r=till (804600283)
- Bug 1194148 - Self-host Array.prototype.toString. r=till (4ffb4712c)
- pointer style (7b1a9900c)
- Bug 1200809 part 5 - Convert self-hosting intrinsics to new InlinableNatives system. r=till (8dd5eb0b9)
- pointer style (7974610a2)
- Bug 1200809 part 6 - Convert various natives to new InlinableNatives system. r=nbp (81d75199c)
- Bug 1200809 part 7 - Convert SIMD natives to new InlinableNatives system. r=nbp (5e67097e0)
- Bug 1200809 part 8 - Don't call shouldAbortOnPreliminaryGroups if we have an uninlinable native. r=bhackett (bd20f201f)
- Bug 1114507 - Part 1: Add/release the appId's refcnt if frame is in main process. r=kanru (741889791)
- Bug 1190903 - Don't send StopIMEStateManagement message after TabParent has been destroyed (r=masayuki) (97bba211b)
- Bug 1166592 - Remove ParentIdleListener from idle service when ActorDestroy() to avoid leaking ContentParent. r=khuey (771549a18)
- Bug 1114507 - Part 3: Remove PContetBridge channel when grandchild-process is killed. r=kanru (a84f888b3)
- Bug 1114507 - Part 2: Add/release the appId's refcnt in oop case. r=kanru (1fdb788b0)
- Bug 1114507 - Part 4: Test cases. r=kanru (889a770c7)
- pointer style (80bd2082b)
- Bug 1159347 - Make BaseProxyHandler::getPropertyDescriptor not-pure virtual. r=efaust (56de51919)
- Bug 1166847 - Implement OpaqueCrossCompartmentWrapper;r=evilpies (d762e785e)
2021-11-04 09:20:44 +08:00

348 lines
9.3 KiB
C++

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/dom/DOMJSProxyHandler.h"
#include "xpcpublic.h"
#include "xpcprivate.h"
#include "XPCWrapper.h"
#include "WrapperFactory.h"
#include "nsDOMClassInfo.h"
#include "nsWrapperCacheInlines.h"
#include "mozilla/dom/BindingUtils.h"
#include "jsapi.h"
using namespace JS;
namespace mozilla {
namespace dom {
jsid s_length_id = JSID_VOID;
bool
DefineStaticJSVals(JSContext* cx)
{
return AtomizeAndPinJSString(cx, s_length_id, "length");
}
const char DOMProxyHandler::family = 0;
js::DOMProxyShadowsResult
DOMProxyShadows(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id)
{
JS::Rooted<JSObject*> expando(cx, DOMProxyHandler::GetExpandoObject(proxy));
JS::Value v = js::GetProxyExtra(proxy, JSPROXYSLOT_EXPANDO);
bool isOverrideBuiltins = !v.isObject() && !v.isUndefined();
if (expando) {
bool hasOwn;
if (!JS_AlreadyHasOwnPropertyById(cx, expando, id, &hasOwn))
return js::ShadowCheckFailed;
if (hasOwn) {
return isOverrideBuiltins ?
js::ShadowsViaIndirectExpando : js::ShadowsViaDirectExpando;
}
}
if (!isOverrideBuiltins) {
// Our expando, if any, didn't shadow, so we're not shadowing at all.
return js::DoesntShadow;
}
bool hasOwn;
if (!GetProxyHandler(proxy)->hasOwn(cx, proxy, id, &hasOwn))
return js::ShadowCheckFailed;
return hasOwn ? js::Shadows : js::DoesntShadowUnique;
}
// Store the information for the specialized ICs.
struct SetDOMProxyInformation
{
SetDOMProxyInformation() {
js::SetDOMProxyInformation((const void*) &DOMProxyHandler::family,
JSPROXYSLOT_EXPANDO, DOMProxyShadows);
}
};
SetDOMProxyInformation gSetDOMProxyInformation;
// static
JSObject*
DOMProxyHandler::GetAndClearExpandoObject(JSObject* obj)
{
MOZ_ASSERT(IsDOMProxy(obj), "expected a DOM proxy object");
JS::Value v = js::GetProxyExtra(obj, JSPROXYSLOT_EXPANDO);
if (v.isUndefined()) {
return nullptr;
}
if (v.isObject()) {
js::SetProxyExtra(obj, JSPROXYSLOT_EXPANDO, UndefinedValue());
xpc::ObjectScope(obj)->RemoveDOMExpandoObject(obj);
} else {
js::ExpandoAndGeneration* expandoAndGeneration =
static_cast<js::ExpandoAndGeneration*>(v.toPrivate());
v = expandoAndGeneration->expando;
if (v.isUndefined()) {
return nullptr;
}
expandoAndGeneration->expando = UndefinedValue();
}
return &v.toObject();
}
// static
JSObject*
DOMProxyHandler::EnsureExpandoObject(JSContext* cx, JS::Handle<JSObject*> obj)
{
NS_ASSERTION(IsDOMProxy(obj), "expected a DOM proxy object");
JS::Value v = js::GetProxyExtra(obj, JSPROXYSLOT_EXPANDO);
if (v.isObject()) {
return &v.toObject();
}
js::ExpandoAndGeneration* expandoAndGeneration;
if (!v.isUndefined()) {
expandoAndGeneration = static_cast<js::ExpandoAndGeneration*>(v.toPrivate());
if (expandoAndGeneration->expando.isObject()) {
return &expandoAndGeneration->expando.toObject();
}
} else {
expandoAndGeneration = nullptr;
}
JS::Rooted<JSObject*> expando(cx,
JS_NewObjectWithGivenProto(cx, nullptr, nullptr));
if (!expando) {
return nullptr;
}
nsISupports* native = UnwrapDOMObject<nsISupports>(obj);
nsWrapperCache* cache;
CallQueryInterface(native, &cache);
if (!cache) {
return expando;
}
if (expandoAndGeneration) {
cache->PreserveWrapper(native);
expandoAndGeneration->expando.setObject(*expando);
return expando;
}
if (!xpc::ObjectScope(obj)->RegisterDOMExpandoObject(obj)) {
return nullptr;
}
cache->SetPreservingWrapper(true);
js::SetProxyExtra(obj, JSPROXYSLOT_EXPANDO, ObjectValue(*expando));
return expando;
}
bool
DOMProxyHandler::preventExtensions(JSContext* cx, JS::Handle<JSObject*> proxy,
JS::ObjectOpResult& result) const
{
// always extensible per WebIDL
return result.failCantPreventExtensions();
}
bool
DOMProxyHandler::isExtensible(JSContext *cx, JS::Handle<JSObject*> proxy, bool *extensible) const
{
*extensible = true;
return true;
}
bool
BaseDOMProxyHandler::getOwnPropertyDescriptor(JSContext* cx,
JS::Handle<JSObject*> proxy,
JS::Handle<jsid> id,
MutableHandle<JSPropertyDescriptor> desc) const
{
return getOwnPropDescriptor(cx, proxy, id, /* ignoreNamedProps = */ false,
desc);
}
bool
DOMProxyHandler::defineProperty(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
Handle<JSPropertyDescriptor> desc,
JS::ObjectOpResult &result, bool *defined) const
{
if (desc.hasGetterObject() && desc.setter() == JS_StrictPropertyStub) {
return result.failGetterOnly();
}
if (xpc::WrapperFactory::IsXrayWrapper(proxy)) {
return result.succeed();
}
JS::Rooted<JSObject*> expando(cx, EnsureExpandoObject(cx, proxy));
if (!expando) {
return false;
}
if (!JS_DefinePropertyById(cx, expando, id, desc, result)) {
return false;
}
*defined = true;
return true;
}
bool
DOMProxyHandler::set(JSContext *cx, Handle<JSObject*> proxy, Handle<jsid> id,
Handle<JS::Value> v, Handle<JS::Value> receiver,
ObjectOpResult &result) const
{
MOZ_ASSERT(!xpc::WrapperFactory::IsXrayWrapper(proxy),
"Should not have a XrayWrapper here");
bool done;
if (!setCustom(cx, proxy, id, v, &done)) {
return false;
}
if (done) {
return result.succeed();
}
// Make sure to ignore our named properties when checking for own
// property descriptors for a set.
JS::Rooted<JSPropertyDescriptor> ownDesc(cx);
if (!getOwnPropDescriptor(cx, proxy, id, /* ignoreNamedProps = */ true,
&ownDesc)) {
return false;
}
return js::SetPropertyIgnoringNamedGetter(cx, proxy, id, v, receiver, ownDesc, result);
}
bool
DOMProxyHandler::delete_(JSContext* cx, JS::Handle<JSObject*> proxy,
JS::Handle<jsid> id, JS::ObjectOpResult &result) const
{
JS::Rooted<JSObject*> expando(cx);
if (!xpc::WrapperFactory::IsXrayWrapper(proxy) && (expando = GetExpandoObject(proxy))) {
return JS_DeletePropertyById(cx, expando, id, result);
}
return result.succeed();
}
bool
BaseDOMProxyHandler::watch(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
JS::Handle<JSObject*> callable) const
{
return js::WatchGuts(cx, proxy, id, callable);
}
bool
BaseDOMProxyHandler::unwatch(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id) const
{
return js::UnwatchGuts(cx, proxy, id);
}
bool
BaseDOMProxyHandler::ownPropertyKeys(JSContext* cx,
JS::Handle<JSObject*> proxy,
JS::AutoIdVector& props) const
{
return ownPropNames(cx, proxy, JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS, props);
}
bool
BaseDOMProxyHandler::getOwnEnumerablePropertyKeys(JSContext* cx,
JS::Handle<JSObject*> proxy,
JS::AutoIdVector& props) const
{
return ownPropNames(cx, proxy, JSITER_OWNONLY, props);
}
bool
BaseDOMProxyHandler::enumerate(JSContext *cx, JS::Handle<JSObject*> proxy,
JS::MutableHandle<JSObject*> objp) const
{
return BaseProxyHandler::enumerate(cx, proxy, objp);
}
bool
DOMProxyHandler::has(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id, bool* bp) const
{
if (!hasOwn(cx, proxy, id, bp)) {
return false;
}
if (*bp) {
// We have the property ourselves; no need to worry about our prototype
// chain.
return true;
}
// OK, now we have to look at the proto
JS::Rooted<JSObject*> proto(cx);
if (!js::GetObjectProto(cx, proxy, &proto)) {
return false;
}
if (!proto) {
return true;
}
bool protoHasProp;
bool ok = JS_HasPropertyById(cx, proto, id, &protoHasProp);
if (ok) {
*bp = protoHasProp;
}
return ok;
}
int32_t
IdToInt32(JSContext* cx, JS::Handle<jsid> id)
{
JS::Rooted<JS::Value> idval(cx);
double array_index;
int32_t i;
if (JSID_IS_SYMBOL(id) ||
!::JS_IdToValue(cx, id, &idval) ||
!JS::ToNumber(cx, idval, &array_index) ||
!::JS_DoubleIsInt32(array_index, &i)) {
return -1;
}
return i;
}
bool
DOMProxyHandler::setCustom(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
JS::Handle<JS::Value> v, bool *done) const
{
*done = false;
return true;
}
//static
JSObject *
DOMProxyHandler::GetExpandoObject(JSObject *obj)
{
MOZ_ASSERT(IsDOMProxy(obj), "expected a DOM proxy object");
JS::Value v = js::GetProxyExtra(obj, JSPROXYSLOT_EXPANDO);
if (v.isObject()) {
return &v.toObject();
}
if (v.isUndefined()) {
return nullptr;
}
js::ExpandoAndGeneration* expandoAndGeneration =
static_cast<js::ExpandoAndGeneration*>(v.toPrivate());
v = expandoAndGeneration->expando;
return v.isUndefined() ? nullptr : &v.toObject();
}
} // namespace dom
} // namespace mozilla