summaryrefslogtreecommitdiff
path: root/src/third_party/mozjs-60/extract/js/src/proxy
diff options
context:
space:
mode:
Diffstat (limited to 'src/third_party/mozjs-60/extract/js/src/proxy')
-rw-r--r--src/third_party/mozjs-60/extract/js/src/proxy/BaseProxyHandler.cpp430
-rw-r--r--src/third_party/mozjs-60/extract/js/src/proxy/CrossCompartmentWrapper.cpp734
-rw-r--r--src/third_party/mozjs-60/extract/js/src/proxy/DeadObjectProxy.cpp189
-rw-r--r--src/third_party/mozjs-60/extract/js/src/proxy/DeadObjectProxy.h95
-rw-r--r--src/third_party/mozjs-60/extract/js/src/proxy/OpaqueCrossCompartmentWrapper.cpp193
-rw-r--r--src/third_party/mozjs-60/extract/js/src/proxy/Proxy.cpp867
-rw-r--r--src/third_party/mozjs-60/extract/js/src/proxy/Proxy.h107
-rw-r--r--src/third_party/mozjs-60/extract/js/src/proxy/ScriptedProxyHandler.cpp1430
-rw-r--r--src/third_party/mozjs-60/extract/js/src/proxy/ScriptedProxyHandler.h106
-rw-r--r--src/third_party/mozjs-60/extract/js/src/proxy/SecurityWrapper.cpp130
-rw-r--r--src/third_party/mozjs-60/extract/js/src/proxy/Wrapper.cpp464
11 files changed, 4745 insertions, 0 deletions
diff --git a/src/third_party/mozjs-60/extract/js/src/proxy/BaseProxyHandler.cpp b/src/third_party/mozjs-60/extract/js/src/proxy/BaseProxyHandler.cpp
new file mode 100644
index 00000000000..c8eca3e524b
--- /dev/null
+++ b/src/third_party/mozjs-60/extract/js/src/proxy/BaseProxyHandler.cpp
@@ -0,0 +1,430 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * 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 "js/Proxy.h"
+#include "vm/ProxyObject.h"
+
+#include "vm/JSContext-inl.h"
+#include "vm/JSObject-inl.h"
+
+using namespace js;
+
+using JS::IsArrayAnswer;
+
+bool
+BaseProxyHandler::enter(JSContext* cx, HandleObject wrapper, HandleId id, Action act, bool mayThrow,
+ bool* bp) const
+{
+ *bp = true;
+ return true;
+}
+
+bool
+BaseProxyHandler::has(JSContext* cx, HandleObject proxy, HandleId id, bool* bp) const
+{
+ assertEnteredPolicy(cx, proxy, id, GET);
+
+ // This method is not covered by any spec, but we follow ES 2016
+ // (February 11, 2016) 9.1.7.1 fairly closely.
+
+ // Step 2. (Step 1 is a superfluous assertion.)
+ // Non-standard: Use our faster hasOwn trap.
+ if (!hasOwn(cx, proxy, id, bp))
+ return false;
+
+ // Step 3.
+ if (*bp)
+ return true;
+
+ // The spec calls this variable "parent", but that word has weird
+ // connotations in SpiderMonkey, so let's go with "proto".
+ // Step 4.
+ RootedObject proto(cx);
+ if (!GetPrototype(cx, proxy, &proto))
+ return false;
+
+ // Step 5.,5.a.
+ if (proto)
+ return HasProperty(cx, proto, id, bp);
+
+ // Step 6.
+ *bp = false;
+ return true;
+}
+
+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
+BaseProxyHandler::hasOwn(JSContext* cx, HandleObject proxy, HandleId id, bool* bp) const
+{
+ assertEnteredPolicy(cx, proxy, id, GET);
+ Rooted<PropertyDescriptor> desc(cx);
+ if (!getOwnPropertyDescriptor(cx, proxy, id, &desc))
+ return false;
+ *bp = !!desc.object();
+ return true;
+}
+
+bool
+BaseProxyHandler::get(JSContext* cx, HandleObject proxy, HandleValue receiver,
+ HandleId id, MutableHandleValue vp) const
+{
+ assertEnteredPolicy(cx, proxy, id, GET);
+
+ // This method is not covered by any spec, but we follow ES 2016
+ // (January 21, 2016) 9.1.8 fairly closely.
+
+ // Step 2. (Step 1 is a superfluous assertion.)
+ Rooted<PropertyDescriptor> desc(cx);
+ if (!getOwnPropertyDescriptor(cx, proxy, id, &desc))
+ return false;
+ desc.assertCompleteIfFound();
+
+ // Step 3.
+ if (!desc.object()) {
+ // The spec calls this variable "parent", but that word has weird
+ // connotations in SpiderMonkey, so let's go with "proto".
+ // Step 3.a.
+ RootedObject proto(cx);
+ if (!GetPrototype(cx, proxy, &proto))
+ return false;
+
+ // Step 3.b.
+ if (!proto) {
+ vp.setUndefined();
+ return true;
+ }
+
+ // Step 3.c.
+ return GetProperty(cx, proto, receiver, id, vp);
+ }
+
+ // Step 4.
+ if (desc.isDataDescriptor()) {
+ vp.set(desc.value());
+ return true;
+ }
+
+ // Step 5.
+ MOZ_ASSERT(desc.isAccessorDescriptor());
+ RootedObject getter(cx, desc.getterObject());
+
+ // Step 6.
+ if (!getter) {
+ vp.setUndefined();
+ return true;
+ }
+
+ // Step 7.
+ RootedValue getterFunc(cx, ObjectValue(*getter));
+ return CallGetter(cx, receiver, getterFunc, vp);
+}
+
+bool
+BaseProxyHandler::set(JSContext* cx, HandleObject proxy, HandleId id, HandleValue v,
+ HandleValue receiver, ObjectOpResult& result) const
+{
+ assertEnteredPolicy(cx, proxy, id, SET);
+
+ // This method is not covered by any spec, but we follow ES6 draft rev 28
+ // (2014 Oct 14) 9.1.9 fairly closely, adapting it slightly for
+ // SpiderMonkey's particular foibles.
+
+ // Steps 2-3. (Step 1 is a superfluous assertion.)
+ Rooted<PropertyDescriptor> ownDesc(cx);
+ if (!getOwnPropertyDescriptor(cx, proxy, id, &ownDesc))
+ return false;
+ ownDesc.assertCompleteIfFound();
+
+ // The rest is factored out into a separate function with a weird name.
+ // This algorithm continues just below.
+ return SetPropertyIgnoringNamedGetter(cx, proxy, id, v, receiver, ownDesc, result);
+}
+
+bool
+js::SetPropertyIgnoringNamedGetter(JSContext* cx, HandleObject obj, HandleId id, HandleValue v,
+ HandleValue receiver, Handle<PropertyDescriptor> ownDesc_,
+ ObjectOpResult& result)
+{
+ Rooted<PropertyDescriptor> ownDesc(cx, ownDesc_);
+
+ // Step 4.
+ if (!ownDesc.object()) {
+ // The spec calls this variable "parent", but that word has weird
+ // connotations in SpiderMonkey, so let's go with "proto".
+ RootedObject proto(cx);
+ if (!GetPrototype(cx, obj, &proto))
+ return false;
+ if (proto)
+ return SetProperty(cx, proto, id, v, receiver, result);
+
+ // Step 4.d.
+ ownDesc.setDataDescriptor(UndefinedHandleValue, JSPROP_ENUMERATE);
+ }
+
+ // Step 5.
+ if (ownDesc.isDataDescriptor()) {
+ // Steps 5.a-b.
+ if (!ownDesc.writable())
+ return result.fail(JSMSG_READ_ONLY);
+ if (!receiver.isObject())
+ return result.fail(JSMSG_SET_NON_OBJECT_RECEIVER);
+ RootedObject receiverObj(cx, &receiver.toObject());
+
+ // Nonstandard SpiderMonkey special case: setter ops.
+ if (SetterOp setter = ownDesc.setter())
+ return CallJSSetterOp(cx, setter, receiverObj, id, v, result);
+
+ // Steps 5.c-d.
+ Rooted<PropertyDescriptor> existingDescriptor(cx);
+ if (!GetOwnPropertyDescriptor(cx, receiverObj, id, &existingDescriptor))
+ return false;
+
+ // Step 5.e.
+ if (existingDescriptor.object()) {
+ // Step 5.e.i.
+ if (existingDescriptor.isAccessorDescriptor())
+ return result.fail(JSMSG_OVERWRITING_ACCESSOR);
+
+ // Step 5.e.ii.
+ if (!existingDescriptor.writable())
+ return result.fail(JSMSG_READ_ONLY);
+ }
+
+
+ // Steps 5.e.iii-iv. and 5.f.i.
+ unsigned attrs =
+ existingDescriptor.object()
+ ? JSPROP_IGNORE_ENUMERATE | JSPROP_IGNORE_READONLY | JSPROP_IGNORE_PERMANENT
+ : JSPROP_ENUMERATE;
+
+ return DefineDataProperty(cx, receiverObj, id, v, attrs, result);
+ }
+
+ // Step 6.
+ MOZ_ASSERT(ownDesc.isAccessorDescriptor());
+ RootedObject setter(cx);
+ if (ownDesc.hasSetterObject())
+ setter = ownDesc.setterObject();
+ if (!setter)
+ return result.fail(JSMSG_GETTER_ONLY);
+ RootedValue setterValue(cx, ObjectValue(*setter));
+ if (!CallSetter(cx, receiver, setterValue, v))
+ return false;
+ return result.succeed();
+}
+
+bool
+BaseProxyHandler::getOwnEnumerablePropertyKeys(JSContext* cx, HandleObject proxy,
+ AutoIdVector& props) const
+{
+ assertEnteredPolicy(cx, proxy, JSID_VOID, ENUMERATE);
+ MOZ_ASSERT(props.length() == 0);
+
+ if (!ownPropertyKeys(cx, proxy, props))
+ return false;
+
+ /* Select only the enumerable properties through in-place iteration. */
+ RootedId id(cx);
+ size_t i = 0;
+ for (size_t j = 0, len = props.length(); j < len; j++) {
+ MOZ_ASSERT(i <= j);
+ id = props[j];
+ if (JSID_IS_SYMBOL(id))
+ continue;
+
+ AutoWaivePolicy policy(cx, proxy, id, BaseProxyHandler::GET);
+ Rooted<PropertyDescriptor> desc(cx);
+ if (!getOwnPropertyDescriptor(cx, proxy, id, &desc))
+ return false;
+ desc.assertCompleteIfFound();
+
+ if (desc.object() && desc.enumerable())
+ props[i++].set(id);
+ }
+
+ MOZ_ASSERT(i <= props.length());
+ if (!props.resize(i))
+ return false;
+
+ return true;
+}
+
+JSObject*
+BaseProxyHandler::enumerate(JSContext* cx, HandleObject proxy) const
+{
+ assertEnteredPolicy(cx, proxy, JSID_VOID, ENUMERATE);
+
+ // GetPropertyKeys will invoke getOwnEnumerablePropertyKeys along the proto
+ // chain for us.
+ AutoIdVector props(cx);
+ if (!GetPropertyKeys(cx, proxy, 0, &props))
+ return nullptr;
+
+ return EnumeratedIdVectorToIterator(cx, proxy, props);
+}
+
+bool
+BaseProxyHandler::call(JSContext* cx, HandleObject proxy, const CallArgs& args) const
+{
+ MOZ_CRASH("callable proxies should implement call trap");
+}
+
+bool
+BaseProxyHandler::construct(JSContext* cx, HandleObject proxy, const CallArgs& args) const
+{
+ MOZ_CRASH("callable proxies should implement construct trap");
+}
+
+const char*
+BaseProxyHandler::className(JSContext* cx, HandleObject proxy) const
+{
+ return proxy->isCallable() ? "Function" : "Object";
+}
+
+JSString*
+BaseProxyHandler::fun_toString(JSContext* cx, HandleObject proxy, bool isToSource) const
+{
+ if (proxy->isCallable())
+ return JS_NewStringCopyZ(cx, "function () {\n [native code]\n}");
+ RootedValue v(cx, ObjectValue(*proxy));
+ ReportIsNotFunction(cx, v);
+ return nullptr;
+}
+
+RegExpShared*
+BaseProxyHandler::regexp_toShared(JSContext* cx, HandleObject proxy) const
+{
+ MOZ_CRASH("This should have been a wrapped regexp");
+}
+
+bool
+BaseProxyHandler::boxedValue_unbox(JSContext* cx, HandleObject proxy, MutableHandleValue vp) const
+{
+ vp.setUndefined();
+ return true;
+}
+
+bool
+BaseProxyHandler::nativeCall(JSContext* cx, IsAcceptableThis test, NativeImpl impl,
+ const CallArgs& args) const
+{
+ ReportIncompatible(cx, args);
+ return false;
+}
+
+bool
+BaseProxyHandler::hasInstance(JSContext* cx, HandleObject proxy, MutableHandleValue v,
+ bool* bp) const
+{
+ assertEnteredPolicy(cx, proxy, JSID_VOID, GET);
+ RootedValue val(cx, ObjectValue(*proxy.get()));
+ ReportValueError(cx, JSMSG_BAD_INSTANCEOF_RHS,
+ JSDVG_SEARCH_STACK, val, nullptr);
+ return false;
+}
+
+bool
+BaseProxyHandler::getBuiltinClass(JSContext* cx, HandleObject proxy, ESClass* cls) const
+{
+ *cls = ESClass::Other;
+ return true;
+}
+
+bool
+BaseProxyHandler::isArray(JSContext* cx, HandleObject proxy, IsArrayAnswer* answer) const
+{
+ *answer = IsArrayAnswer::NotArray;
+ return true;
+}
+
+void
+BaseProxyHandler::trace(JSTracer* trc, JSObject* proxy) const
+{
+}
+
+void
+BaseProxyHandler::finalize(JSFreeOp* fop, JSObject* proxy) const
+{
+}
+
+size_t
+BaseProxyHandler::objectMoved(JSObject* proxy, JSObject* old) const
+{
+ return 0;
+}
+
+JSObject*
+BaseProxyHandler::weakmapKeyDelegate(JSObject* proxy) const
+{
+ return nullptr;
+}
+
+bool
+BaseProxyHandler::getPrototype(JSContext* cx, HandleObject proxy, MutableHandleObject protop) const
+{
+ MOZ_CRASH("must override getPrototype with dynamic prototype");
+}
+
+bool
+BaseProxyHandler::setPrototype(JSContext* cx, HandleObject proxy, HandleObject proto,
+ ObjectOpResult& result) const
+{
+ // Disallow sets of protos on proxies with dynamic prototypes but no hook.
+ // This keeps us away from the footgun of having the first proto set opt
+ // you out of having dynamic protos altogether.
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_CANT_SET_PROTO_OF,
+ "incompatible Proxy");
+ return false;
+}
+
+bool
+BaseProxyHandler::setImmutablePrototype(JSContext* cx, HandleObject proxy, bool* succeeded) const
+{
+ *succeeded = false;
+ return true;
+}
+
+bool
+BaseProxyHandler::getElements(JSContext* cx, HandleObject proxy, uint32_t begin, uint32_t end,
+ ElementAdder* adder) const
+{
+ assertEnteredPolicy(cx, proxy, JSID_VOID, GET);
+
+ return js::GetElementsWithAdder(cx, proxy, proxy, begin, end, adder);
+}
+
+bool
+BaseProxyHandler::isCallable(JSObject* obj) const
+{
+ return false;
+}
+
+bool
+BaseProxyHandler::isConstructor(JSObject* obj) const
+{
+ return false;
+}
diff --git a/src/third_party/mozjs-60/extract/js/src/proxy/CrossCompartmentWrapper.cpp b/src/third_party/mozjs-60/extract/js/src/proxy/CrossCompartmentWrapper.cpp
new file mode 100644
index 00000000000..1b1f5fec5cc
--- /dev/null
+++ b/src/third_party/mozjs-60/extract/js/src/proxy/CrossCompartmentWrapper.cpp
@@ -0,0 +1,734 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * 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 "gc/PublicIterators.h"
+#include "js/Wrapper.h"
+#include "proxy/DeadObjectProxy.h"
+#include "vm/Iteration.h"
+#include "vm/WrapperObject.h"
+
+#include "gc/Nursery-inl.h"
+#include "vm/JSCompartment-inl.h"
+#include "vm/JSObject-inl.h"
+
+using namespace js;
+
+#define PIERCE(cx, wrapper, pre, op, post) \
+ JS_BEGIN_MACRO \
+ bool ok; \
+ { \
+ AutoCompartment call(cx, wrappedObject(wrapper)); \
+ ok = (pre) && (op); \
+ } \
+ return ok && (post); \
+ JS_END_MACRO
+
+#define NOTHING (true)
+
+static bool
+MarkAtoms(JSContext* cx, jsid id)
+{
+ cx->markId(id);
+ return true;
+}
+
+static bool
+MarkAtoms(JSContext* cx, const AutoIdVector& ids)
+{
+ for (size_t i = 0; i < ids.length(); i++)
+ cx->markId(ids[i]);
+ return true;
+}
+
+bool
+CrossCompartmentWrapper::getPropertyDescriptor(JSContext* cx, HandleObject wrapper, HandleId id,
+ MutableHandle<PropertyDescriptor> desc) const
+{
+ PIERCE(cx, wrapper,
+ MarkAtoms(cx, id),
+ Wrapper::getPropertyDescriptor(cx, wrapper, id, desc),
+ cx->compartment()->wrap(cx, desc));
+}
+
+bool
+CrossCompartmentWrapper::getOwnPropertyDescriptor(JSContext* cx, HandleObject wrapper, HandleId id,
+ MutableHandle<PropertyDescriptor> desc) const
+{
+ PIERCE(cx, wrapper,
+ MarkAtoms(cx, id),
+ Wrapper::getOwnPropertyDescriptor(cx, wrapper, id, desc),
+ cx->compartment()->wrap(cx, desc));
+}
+
+bool
+CrossCompartmentWrapper::defineProperty(JSContext* cx, HandleObject wrapper, HandleId id,
+ Handle<PropertyDescriptor> desc,
+ ObjectOpResult& result) const
+{
+ Rooted<PropertyDescriptor> desc2(cx, desc);
+ PIERCE(cx, wrapper,
+ MarkAtoms(cx, id) && cx->compartment()->wrap(cx, &desc2),
+ Wrapper::defineProperty(cx, wrapper, id, desc2, result),
+ NOTHING);
+}
+
+bool
+CrossCompartmentWrapper::ownPropertyKeys(JSContext* cx, HandleObject wrapper,
+ AutoIdVector& props) const
+{
+ PIERCE(cx, wrapper,
+ NOTHING,
+ Wrapper::ownPropertyKeys(cx, wrapper, props),
+ MarkAtoms(cx, props));
+}
+
+bool
+CrossCompartmentWrapper::delete_(JSContext* cx, HandleObject wrapper, HandleId id,
+ ObjectOpResult& result) const
+{
+ PIERCE(cx, wrapper,
+ MarkAtoms(cx, id),
+ Wrapper::delete_(cx, wrapper, id, result),
+ NOTHING);
+}
+
+bool
+CrossCompartmentWrapper::getPrototype(JSContext* cx, HandleObject wrapper,
+ MutableHandleObject protop) const
+{
+ {
+ RootedObject wrapped(cx, wrappedObject(wrapper));
+ AutoCompartment call(cx, wrapped);
+ if (!GetPrototype(cx, wrapped, protop))
+ return false;
+ if (protop) {
+ if (!JSObject::setDelegate(cx, protop))
+ return false;
+ }
+ }
+
+ return cx->compartment()->wrap(cx, protop);
+}
+
+bool
+CrossCompartmentWrapper::setPrototype(JSContext* cx, HandleObject wrapper,
+ HandleObject proto, ObjectOpResult& result) const
+{
+ RootedObject protoCopy(cx, proto);
+ PIERCE(cx, wrapper,
+ cx->compartment()->wrap(cx, &protoCopy),
+ Wrapper::setPrototype(cx, wrapper, protoCopy, result),
+ NOTHING);
+}
+
+bool
+CrossCompartmentWrapper::getPrototypeIfOrdinary(JSContext* cx, HandleObject wrapper,
+ bool* isOrdinary, MutableHandleObject protop) const
+{
+ {
+ RootedObject wrapped(cx, wrappedObject(wrapper));
+ AutoCompartment call(cx, wrapped);
+ if (!GetPrototypeIfOrdinary(cx, wrapped, isOrdinary, protop))
+ return false;
+
+ if (!*isOrdinary)
+ return true;
+
+ if (protop) {
+ if (!JSObject::setDelegate(cx, protop))
+ return false;
+ }
+ }
+
+ return cx->compartment()->wrap(cx, protop);
+}
+
+bool
+CrossCompartmentWrapper::setImmutablePrototype(JSContext* cx, HandleObject wrapper, bool* succeeded) const
+{
+ PIERCE(cx, wrapper,
+ NOTHING,
+ Wrapper::setImmutablePrototype(cx, wrapper, succeeded),
+ NOTHING);
+}
+
+bool
+CrossCompartmentWrapper::preventExtensions(JSContext* cx, HandleObject wrapper,
+ ObjectOpResult& result) const
+{
+ PIERCE(cx, wrapper,
+ NOTHING,
+ Wrapper::preventExtensions(cx, wrapper, result),
+ NOTHING);
+}
+
+bool
+CrossCompartmentWrapper::isExtensible(JSContext* cx, HandleObject wrapper, bool* extensible) const
+{
+ PIERCE(cx, wrapper,
+ NOTHING,
+ Wrapper::isExtensible(cx, wrapper, extensible),
+ NOTHING);
+}
+
+bool
+CrossCompartmentWrapper::has(JSContext* cx, HandleObject wrapper, HandleId id, bool* bp) const
+{
+ PIERCE(cx, wrapper,
+ MarkAtoms(cx, id),
+ Wrapper::has(cx, wrapper, id, bp),
+ NOTHING);
+}
+
+bool
+CrossCompartmentWrapper::hasOwn(JSContext* cx, HandleObject wrapper, HandleId id, bool* bp) const
+{
+ PIERCE(cx, wrapper,
+ MarkAtoms(cx, id),
+ Wrapper::hasOwn(cx, wrapper, id, bp),
+ NOTHING);
+}
+
+static bool
+WrapReceiver(JSContext* cx, HandleObject wrapper, MutableHandleValue receiver)
+{
+ // Usually the receiver is the wrapper and we can just unwrap it. If the
+ // wrapped object is also a wrapper, things are more complicated and we
+ // fall back to the slow path (it calls UncheckedUnwrap to unwrap all
+ // wrappers).
+ if (ObjectValue(*wrapper) == receiver) {
+ JSObject* wrapped = Wrapper::wrappedObject(wrapper);
+ if (!IsWrapper(wrapped)) {
+ MOZ_ASSERT(wrapped->compartment() == cx->compartment());
+ MOZ_ASSERT(!IsWindow(wrapped));
+ receiver.setObject(*wrapped);
+ return true;
+ }
+ }
+
+ return cx->compartment()->wrap(cx, receiver);
+}
+
+bool
+CrossCompartmentWrapper::get(JSContext* cx, HandleObject wrapper, HandleValue receiver,
+ HandleId id, MutableHandleValue vp) const
+{
+ RootedValue receiverCopy(cx, receiver);
+ {
+ AutoCompartment call(cx, wrappedObject(wrapper));
+ if (!MarkAtoms(cx, id) || !WrapReceiver(cx, wrapper, &receiverCopy))
+ return false;
+
+ if (!Wrapper::get(cx, wrapper, receiverCopy, id, vp))
+ return false;
+ }
+ return cx->compartment()->wrap(cx, vp);
+}
+
+bool
+CrossCompartmentWrapper::set(JSContext* cx, HandleObject wrapper, HandleId id, HandleValue v,
+ HandleValue receiver, ObjectOpResult& result) const
+{
+ RootedValue valCopy(cx, v);
+ RootedValue receiverCopy(cx, receiver);
+ PIERCE(cx, wrapper,
+ MarkAtoms(cx, id) &&
+ cx->compartment()->wrap(cx, &valCopy) &&
+ WrapReceiver(cx, wrapper, &receiverCopy),
+ Wrapper::set(cx, wrapper, id, valCopy, receiverCopy, result),
+ NOTHING);
+}
+
+bool
+CrossCompartmentWrapper::getOwnEnumerablePropertyKeys(JSContext* cx, HandleObject wrapper,
+ AutoIdVector& props) const
+{
+ PIERCE(cx, wrapper,
+ NOTHING,
+ Wrapper::getOwnEnumerablePropertyKeys(cx, wrapper, props),
+ MarkAtoms(cx, props));
+}
+
+/*
+ * We can reify non-escaping iterator objects instead of having to wrap them. This
+ * allows fast iteration over objects across a compartment boundary.
+ */
+static bool
+CanReify(HandleObject obj)
+{
+ return obj->is<PropertyIteratorObject>();
+}
+
+struct AutoCloseIterator
+{
+ AutoCloseIterator(JSContext* cx, PropertyIteratorObject* obj) : obj(cx, obj) {}
+
+ ~AutoCloseIterator() {
+ if (obj)
+ CloseIterator(obj);
+ }
+
+ void clear() { obj = nullptr; }
+
+ private:
+ Rooted<PropertyIteratorObject*> obj;
+};
+
+static JSObject*
+Reify(JSContext* cx, JSCompartment* origin, HandleObject objp)
+{
+ Rooted<PropertyIteratorObject*> iterObj(cx, &objp->as<PropertyIteratorObject>());
+ NativeIterator* ni = iterObj->getNativeIterator();
+
+ RootedObject obj(cx, ni->obj);
+ {
+ AutoCloseIterator close(cx, iterObj);
+
+ /* Wrap the iteratee. */
+ if (!origin->wrap(cx, &obj))
+ return nullptr;
+
+ /*
+ * Wrap the elements in the iterator's snapshot.
+ * N.B. the order of closing/creating iterators is important due to the
+ * implicit cx->enumerators state.
+ */
+ size_t length = ni->numKeys();
+ AutoIdVector keys(cx);
+ if (length > 0) {
+ if (!keys.reserve(length))
+ return nullptr;
+ RootedId id(cx);
+ RootedValue v(cx);
+ for (size_t i = 0; i < length; ++i) {
+ v.setString(ni->begin()[i]);
+ if (!ValueToId<CanGC>(cx, v, &id))
+ return nullptr;
+ cx->markId(id);
+ keys.infallibleAppend(id);
+ }
+ }
+
+ close.clear();
+ CloseIterator(iterObj);
+
+ obj = EnumeratedIdVectorToIterator(cx, obj, keys);
+ }
+ return obj;
+}
+
+JSObject*
+CrossCompartmentWrapper::enumerate(JSContext* cx, HandleObject wrapper) const
+{
+ RootedObject res(cx);
+ {
+ AutoCompartment call(cx, wrappedObject(wrapper));
+ res = Wrapper::enumerate(cx, wrapper);
+ if (!res)
+ return nullptr;
+ }
+
+ if (CanReify(res))
+ return Reify(cx, cx->compartment(), res);
+ if (!cx->compartment()->wrap(cx, &res))
+ return nullptr;
+ return res;
+}
+
+bool
+CrossCompartmentWrapper::call(JSContext* cx, HandleObject wrapper, const CallArgs& args) const
+{
+ RootedObject wrapped(cx, wrappedObject(wrapper));
+
+ {
+ AutoCompartment call(cx, wrapped);
+
+ args.setCallee(ObjectValue(*wrapped));
+ if (!cx->compartment()->wrap(cx, args.mutableThisv()))
+ return false;
+
+ for (size_t n = 0; n < args.length(); ++n) {
+ if (!cx->compartment()->wrap(cx, args[n]))
+ return false;
+ }
+
+ if (!Wrapper::call(cx, wrapper, args))
+ return false;
+ }
+
+ return cx->compartment()->wrap(cx, args.rval());
+}
+
+bool
+CrossCompartmentWrapper::construct(JSContext* cx, HandleObject wrapper, const CallArgs& args) const
+{
+ RootedObject wrapped(cx, wrappedObject(wrapper));
+ {
+ AutoCompartment call(cx, wrapped);
+
+ for (size_t n = 0; n < args.length(); ++n) {
+ if (!cx->compartment()->wrap(cx, args[n]))
+ return false;
+ }
+ if (!cx->compartment()->wrap(cx, args.newTarget()))
+ return false;
+ if (!Wrapper::construct(cx, wrapper, args))
+ return false;
+ }
+ return cx->compartment()->wrap(cx, args.rval());
+}
+
+bool
+CrossCompartmentWrapper::nativeCall(JSContext* cx, IsAcceptableThis test, NativeImpl impl,
+ const CallArgs& srcArgs) const
+{
+ RootedObject wrapper(cx, &srcArgs.thisv().toObject());
+ MOZ_ASSERT(srcArgs.thisv().isMagic(JS_IS_CONSTRUCTING) ||
+ !UncheckedUnwrap(wrapper)->is<CrossCompartmentWrapperObject>());
+
+ RootedObject wrapped(cx, wrappedObject(wrapper));
+ {
+ AutoCompartment call(cx, wrapped);
+ InvokeArgs dstArgs(cx);
+ if (!dstArgs.init(cx, srcArgs.length()))
+ return false;
+
+ Value* src = srcArgs.base();
+ Value* srcend = srcArgs.array() + srcArgs.length();
+ Value* dst = dstArgs.base();
+
+ RootedValue source(cx);
+ for (; src < srcend; ++src, ++dst) {
+ source = *src;
+ if (!cx->compartment()->wrap(cx, &source))
+ return false;
+ *dst = source.get();
+
+ // Handle |this| specially. When we rewrap on the other side of the
+ // membrane, we might apply a same-compartment security wrapper that
+ // will stymie this whole process. If that happens, unwrap the wrapper.
+ // This logic can go away when same-compartment security wrappers go away.
+ if ((src == srcArgs.base() + 1) && dst->isObject()) {
+ RootedObject thisObj(cx, &dst->toObject());
+ if (thisObj->is<WrapperObject>() &&
+ Wrapper::wrapperHandler(thisObj)->hasSecurityPolicy())
+ {
+ MOZ_ASSERT(!thisObj->is<CrossCompartmentWrapperObject>());
+ *dst = ObjectValue(*Wrapper::wrappedObject(thisObj));
+ }
+ }
+ }
+
+ if (!CallNonGenericMethod(cx, test, impl, dstArgs))
+ return false;
+
+ srcArgs.rval().set(dstArgs.rval());
+ }
+ return cx->compartment()->wrap(cx, srcArgs.rval());
+}
+
+bool
+CrossCompartmentWrapper::hasInstance(JSContext* cx, HandleObject wrapper, MutableHandleValue v,
+ bool* bp) const
+{
+ AutoCompartment call(cx, wrappedObject(wrapper));
+ if (!cx->compartment()->wrap(cx, v))
+ return false;
+ return Wrapper::hasInstance(cx, wrapper, v, bp);
+}
+
+const char*
+CrossCompartmentWrapper::className(JSContext* cx, HandleObject wrapper) const
+{
+ AutoCompartment call(cx, wrappedObject(wrapper));
+ return Wrapper::className(cx, wrapper);
+}
+
+JSString*
+CrossCompartmentWrapper::fun_toString(JSContext* cx, HandleObject wrapper, bool isToSource) const
+{
+ RootedString str(cx);
+ {
+ AutoCompartment call(cx, wrappedObject(wrapper));
+ str = Wrapper::fun_toString(cx, wrapper, isToSource);
+ if (!str)
+ return nullptr;
+ }
+ if (!cx->compartment()->wrap(cx, &str))
+ return nullptr;
+ return str;
+}
+
+RegExpShared*
+CrossCompartmentWrapper::regexp_toShared(JSContext* cx, HandleObject wrapper) const
+{
+ RootedRegExpShared re(cx);
+ {
+ AutoCompartment call(cx, wrappedObject(wrapper));
+ re = Wrapper::regexp_toShared(cx, wrapper);
+ if (!re)
+ return nullptr;
+ }
+
+ // Get an equivalent RegExpShared associated with the current compartment.
+ RootedAtom source(cx, re->getSource());
+ cx->markAtom(source);
+ return cx->zone()->regExps.get(cx, source, re->getFlags());
+}
+
+bool
+CrossCompartmentWrapper::boxedValue_unbox(JSContext* cx, HandleObject wrapper, MutableHandleValue vp) const
+{
+ PIERCE(cx, wrapper,
+ NOTHING,
+ Wrapper::boxedValue_unbox(cx, wrapper, vp),
+ cx->compartment()->wrap(cx, vp));
+}
+
+const CrossCompartmentWrapper CrossCompartmentWrapper::singleton(0u);
+
+bool
+js::IsCrossCompartmentWrapper(JSObject* obj)
+{
+ return IsWrapper(obj) &&
+ !!(Wrapper::wrapperHandler(obj)->flags() & Wrapper::CROSS_COMPARTMENT);
+}
+
+static void
+NukeRemovedCrossCompartmentWrapper(JSContext* cx, JSObject* wrapper)
+{
+ MOZ_ASSERT(wrapper->is<CrossCompartmentWrapperObject>());
+
+ NotifyGCNukeWrapper(wrapper);
+
+ wrapper->as<ProxyObject>().nuke();
+
+ MOZ_ASSERT(IsDeadProxyObject(wrapper));
+}
+
+JS_FRIEND_API(void)
+js::NukeCrossCompartmentWrapper(JSContext* cx, JSObject* wrapper)
+{
+ JSCompartment* comp = wrapper->compartment();
+ auto ptr = comp->lookupWrapper(Wrapper::wrappedObject(wrapper));
+ if (ptr)
+ comp->removeWrapper(ptr);
+ NukeRemovedCrossCompartmentWrapper(cx, wrapper);
+}
+
+/*
+ * NukeChromeCrossCompartmentWrappersForGlobal reaches into chrome and cuts
+ * all of the cross-compartment wrappers that point to objects parented to
+ * obj's global. The snag here is that we need to avoid cutting wrappers that
+ * point to the window object on page navigation (inner window destruction)
+ * and only do that on tab close (outer window destruction). Thus the
+ * option of how to handle the global object.
+ */
+JS_FRIEND_API(bool)
+js::NukeCrossCompartmentWrappers(JSContext* cx,
+ const CompartmentFilter& sourceFilter,
+ JSCompartment* target,
+ js::NukeReferencesToWindow nukeReferencesToWindow,
+ js::NukeReferencesFromTarget nukeReferencesFromTarget)
+{
+ CHECK_REQUEST(cx);
+ JSRuntime* rt = cx->runtime();
+
+ for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next()) {
+ if (!sourceFilter.match(c))
+ continue;
+
+ // If the compartment matches both the source and target filter, we may
+ // want to cut both incoming and outgoing wrappers.
+ bool nukeAll = (nukeReferencesFromTarget == NukeAllReferences &&
+ target == c.get());
+
+ // Iterate only the wrappers that have target compartment matched unless
+ // |nukeAll| is true. The string wrappers that we're not interested in
+ // won't be iterated, we can exclude them easily because they have
+ // compartment nullptr. Use Maybe to avoid copying from conditionally
+ // initializing NonStringWrapperEnum.
+ mozilla::Maybe<JSCompartment::NonStringWrapperEnum> e;
+ if (MOZ_LIKELY(!nukeAll))
+ e.emplace(c, target);
+ else
+ e.emplace(c);
+ for (; !e->empty(); e->popFront()) {
+ // Skip debugger references because NukeCrossCompartmentWrapper()
+ // doesn't know how to nuke them yet, see bug 1084626 for more
+ // information.
+ const CrossCompartmentKey& k = e->front().key();
+ if (!k.is<JSObject*>())
+ continue;
+
+ AutoWrapperRooter wobj(cx, WrapperValue(*e));
+
+ // Unwrap from the wrapped object in CrossCompartmentKey instead of
+ // the wrapper, this could save us a bit of time.
+ JSObject* wrapped = UncheckedUnwrap(k.as<JSObject*>());
+
+ // We never nuke script source objects, since only ever used internally by the JS
+ // engine, and are expected to remain valid throughout a scripts lifetime.
+ if (MOZ_UNLIKELY(wrapped->is<ScriptSourceObject>())) {
+ continue;
+ }
+
+ // We only skip nuking window references that point to a target
+ // compartment, not the ones that belong to it.
+ if (nukeReferencesToWindow == DontNukeWindowReferences &&
+ MOZ_LIKELY(!nukeAll) && IsWindowProxy(wrapped))
+ {
+ continue;
+ }
+
+ // Now this is the wrapper we want to nuke.
+ e->removeFront();
+ NukeRemovedCrossCompartmentWrapper(cx, wobj);
+ }
+ }
+
+ return true;
+}
+
+// Given a cross-compartment wrapper |wobj|, update it to point to
+// |newTarget|. This recomputes the wrapper with JS_WrapValue, and thus can be
+// useful even if wrapper already points to newTarget.
+// This operation crashes on failure rather than leaving the heap in an
+// inconsistent state.
+void
+js::RemapWrapper(JSContext* cx, JSObject* wobjArg, JSObject* newTargetArg)
+{
+ MOZ_ASSERT(!IsInsideNursery(wobjArg));
+ MOZ_ASSERT(!IsInsideNursery(newTargetArg));
+
+ RootedObject wobj(cx, wobjArg);
+ RootedObject newTarget(cx, newTargetArg);
+ MOZ_ASSERT(wobj->is<CrossCompartmentWrapperObject>());
+ MOZ_ASSERT(!newTarget->is<CrossCompartmentWrapperObject>());
+ JSObject* origTarget = Wrapper::wrappedObject(wobj);
+ MOZ_ASSERT(origTarget);
+ MOZ_ASSERT(!JS_IsDeadWrapper(origTarget),
+ "We don't want a dead proxy in the wrapper map");
+ Value origv = ObjectValue(*origTarget);
+ JSCompartment* wcompartment = wobj->compartment();
+
+ AutoDisableProxyCheck adpc;
+
+ // If we're mapping to a different target (as opposed to just recomputing
+ // for the same target), we must not have an existing wrapper for the new
+ // target, otherwise this will break.
+ MOZ_ASSERT_IF(origTarget != newTarget,
+ !wcompartment->lookupWrapper(ObjectValue(*newTarget)));
+
+ // The old value should still be in the cross-compartment wrapper map, and
+ // the lookup should return wobj.
+ WrapperMap::Ptr p = wcompartment->lookupWrapper(origv);
+ MOZ_ASSERT(&p->value().unsafeGet()->toObject() == wobj);
+ wcompartment->removeWrapper(p);
+
+ // When we remove origv from the wrapper map, its wrapper, wobj, must
+ // immediately cease to be a cross-compartment wrapper. Nuke it.
+ NukeCrossCompartmentWrapper(cx, wobj);
+
+ // First, we wrap it in the new compartment. We try to use the existing
+ // wrapper, |wobj|, since it's been nuked anyway. The wrap() function has
+ // the choice to reuse |wobj| or not.
+ RootedObject tobj(cx, newTarget);
+ AutoCompartmentUnchecked ac(cx, wcompartment);
+ if (!wcompartment->rewrap(cx, &tobj, wobj))
+ MOZ_CRASH();
+
+ // If wrap() reused |wobj|, it will have overwritten it and returned with
+ // |tobj == wobj|. Otherwise, |tobj| will point to a new wrapper and |wobj|
+ // will still be nuked. In the latter case, we replace |wobj| with the
+ // contents of the new wrapper in |tobj|.
+ if (tobj != wobj) {
+ // Now, because we need to maintain object identity, we do a brain
+ // transplant on the old object so that it contains the contents of the
+ // new one.
+ if (!JSObject::swap(cx, wobj, tobj))
+ MOZ_CRASH();
+ }
+
+ // Before swapping, this wrapper came out of wrap(), which enforces the
+ // invariant that the wrapper in the map points directly to the key.
+ MOZ_ASSERT(Wrapper::wrappedObject(wobj) == newTarget);
+
+ // Update the entry in the compartment's wrapper map to point to the old
+ // wrapper, which has now been updated (via reuse or swap).
+ MOZ_ASSERT(wobj->is<WrapperObject>());
+ if (!wcompartment->putWrapper(cx, CrossCompartmentKey(newTarget), ObjectValue(*wobj)))
+ MOZ_CRASH();
+}
+
+// Remap all cross-compartment wrappers pointing to |oldTarget| to point to
+// |newTarget|. All wrappers are recomputed.
+JS_FRIEND_API(bool)
+js::RemapAllWrappersForObject(JSContext* cx, JSObject* oldTargetArg,
+ JSObject* newTargetArg)
+{
+ MOZ_ASSERT(!IsInsideNursery(oldTargetArg));
+ MOZ_ASSERT(!IsInsideNursery(newTargetArg));
+
+ RootedValue origv(cx, ObjectValue(*oldTargetArg));
+ RootedObject newTarget(cx, newTargetArg);
+
+ AutoWrapperVector toTransplant(cx);
+ if (!toTransplant.reserve(cx->runtime()->numCompartments))
+ return false;
+
+ for (CompartmentsIter c(cx->runtime(), SkipAtoms); !c.done(); c.next()) {
+ if (WrapperMap::Ptr wp = c->lookupWrapper(origv)) {
+ // We found a wrapper. Remember and root it.
+ toTransplant.infallibleAppend(WrapperValue(wp));
+ }
+ }
+
+ for (const WrapperValue& v : toTransplant)
+ RemapWrapper(cx, &v.toObject(), newTarget);
+
+ return true;
+}
+
+JS_FRIEND_API(bool)
+js::RecomputeWrappers(JSContext* cx, const CompartmentFilter& sourceFilter,
+ const CompartmentFilter& targetFilter)
+{
+ bool evictedNursery = false;
+
+ AutoWrapperVector toRecompute(cx);
+ for (CompartmentsIter c(cx->runtime(), SkipAtoms); !c.done(); c.next()) {
+ // Filter by source compartment.
+ if (!sourceFilter.match(c))
+ continue;
+
+ if (!evictedNursery && c->hasNurseryAllocatedWrapperEntries(targetFilter)) {
+ EvictAllNurseries(cx->runtime());
+ evictedNursery = true;
+ }
+
+ // Iterate over the wrappers, filtering appropriately.
+ for (JSCompartment::NonStringWrapperEnum e(c, targetFilter); !e.empty(); e.popFront()) {
+ // Filter out non-objects.
+ CrossCompartmentKey& k = e.front().mutableKey();
+ if (!k.is<JSObject*>())
+ continue;
+
+ // Add it to the list.
+ if (!toRecompute.append(WrapperValue(e)))
+ return false;
+ }
+ }
+
+ // Recompute all the wrappers in the list.
+ for (const WrapperValue& v : toRecompute) {
+ JSObject* wrapper = &v.toObject();
+ JSObject* wrapped = Wrapper::wrappedObject(wrapper);
+ RemapWrapper(cx, wrapper, wrapped);
+ }
+
+ return true;
+}
diff --git a/src/third_party/mozjs-60/extract/js/src/proxy/DeadObjectProxy.cpp b/src/third_party/mozjs-60/extract/js/src/proxy/DeadObjectProxy.cpp
new file mode 100644
index 00000000000..f75ca2d3b45
--- /dev/null
+++ b/src/third_party/mozjs-60/extract/js/src/proxy/DeadObjectProxy.cpp
@@ -0,0 +1,189 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * 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 "proxy/DeadObjectProxy.h"
+
+#include "jsapi.h"
+
+#include "vm/JSFunction.h" // XXXefaust Bug 1064662
+#include "vm/ProxyObject.h"
+
+using namespace js;
+using namespace js::gc;
+
+const DeadObjectProxy DeadObjectProxy::singleton;
+const char DeadObjectProxy::family = 0;
+
+static void
+ReportDead(JSContext *cx)
+{
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_DEAD_OBJECT);
+}
+
+bool
+DeadObjectProxy::getOwnPropertyDescriptor(JSContext* cx, HandleObject wrapper, HandleId id,
+ MutableHandle<PropertyDescriptor> desc) const
+{
+ ReportDead(cx);
+ return false;
+}
+
+bool
+DeadObjectProxy::defineProperty(JSContext* cx, HandleObject wrapper, HandleId id,
+ Handle<PropertyDescriptor> desc,
+ ObjectOpResult& result) const
+{
+ ReportDead(cx);
+ return false;
+}
+
+bool
+DeadObjectProxy::ownPropertyKeys(JSContext* cx, HandleObject wrapper,
+ AutoIdVector& props) const
+{
+ ReportDead(cx);
+ return false;
+}
+
+bool
+DeadObjectProxy::delete_(JSContext* cx, HandleObject wrapper, HandleId id,
+ ObjectOpResult& result) const
+{
+ ReportDead(cx);
+ return false;
+}
+
+bool
+DeadObjectProxy::getPrototype(JSContext* cx, HandleObject proxy,
+ MutableHandleObject protop) const
+{
+ protop.set(nullptr);
+ return true;
+}
+
+bool
+DeadObjectProxy::getPrototypeIfOrdinary(JSContext* cx, HandleObject proxy, bool* isOrdinary,
+ MutableHandleObject protop) const
+{
+ *isOrdinary = false;
+ return true;
+}
+
+bool
+DeadObjectProxy::preventExtensions(JSContext* cx, HandleObject proxy,
+ ObjectOpResult& result) const
+{
+ ReportDead(cx);
+ return false;
+}
+
+bool
+DeadObjectProxy::isExtensible(JSContext* cx, HandleObject proxy, bool* extensible) const
+{
+ // This is kind of meaningless, but dead-object semantics aside,
+ // [[Extensible]] always being true is consistent with other proxy types.
+ *extensible = true;
+ return true;
+}
+
+bool
+DeadObjectProxy::call(JSContext* cx, HandleObject wrapper, const CallArgs& args) const
+{
+ ReportDead(cx);
+ return false;
+}
+
+bool
+DeadObjectProxy::construct(JSContext* cx, HandleObject wrapper, const CallArgs& args) const
+{
+ ReportDead(cx);
+ return false;
+}
+
+bool
+DeadObjectProxy::nativeCall(JSContext* cx, IsAcceptableThis test, NativeImpl impl,
+ const CallArgs& args) const
+{
+ ReportDead(cx);
+ return false;
+}
+
+bool
+DeadObjectProxy::hasInstance(JSContext* cx, HandleObject proxy, MutableHandleValue v,
+ bool* bp) const
+{
+ ReportDead(cx);
+ return false;
+}
+
+bool
+DeadObjectProxy::getBuiltinClass(JSContext* cx, HandleObject proxy, ESClass* cls) const
+{
+ ReportDead(cx);
+ return false;
+}
+
+bool
+DeadObjectProxy::isArray(JSContext* cx, HandleObject obj, JS::IsArrayAnswer* answer) const
+{
+ ReportDead(cx);
+ return false;
+}
+
+const char*
+DeadObjectProxy::className(JSContext* cx, HandleObject wrapper) const
+{
+ return "DeadObject";
+}
+
+JSString*
+DeadObjectProxy::fun_toString(JSContext* cx, HandleObject proxy, bool isToSource) const
+{
+ ReportDead(cx);
+ return nullptr;
+}
+
+RegExpShared*
+DeadObjectProxy::regexp_toShared(JSContext* cx, HandleObject proxy) const
+{
+ ReportDead(cx);
+ return nullptr;
+}
+
+bool
+js::IsDeadProxyObject(JSObject* obj)
+{
+ return IsDerivedProxyObject(obj, &DeadObjectProxy::singleton);
+}
+
+Value
+js::DeadProxyTargetValue(ProxyObject* obj)
+{
+ // When nuking scripted proxies, isCallable and isConstructor values for
+ // the proxy needs to be preserved. So does background-finalization status.
+ int32_t flags = 0;
+ if (obj->handler()->isCallable(obj))
+ flags |= DeadObjectProxyIsCallable;
+ if (obj->handler()->isConstructor(obj))
+ flags |= DeadObjectProxyIsConstructor;
+ if (obj->handler()->finalizeInBackground(obj->private_()))
+ flags |= DeadObjectProxyIsBackgroundFinalized;
+ return Int32Value(flags);
+}
+
+JSObject*
+js::NewDeadProxyObject(JSContext* cx, JSObject* origObj)
+{
+ MOZ_ASSERT_IF(origObj, origObj->is<ProxyObject>());
+
+ RootedValue target(cx);
+ if (origObj && origObj->is<ProxyObject>())
+ target = DeadProxyTargetValue(&origObj->as<ProxyObject>());
+ else
+ target = Int32Value(DeadObjectProxyIsBackgroundFinalized);
+
+ return NewProxyObject(cx, &DeadObjectProxy::singleton, target, nullptr, ProxyOptions());
+}
diff --git a/src/third_party/mozjs-60/extract/js/src/proxy/DeadObjectProxy.h b/src/third_party/mozjs-60/extract/js/src/proxy/DeadObjectProxy.h
new file mode 100644
index 00000000000..c936c90ee39
--- /dev/null
+++ b/src/third_party/mozjs-60/extract/js/src/proxy/DeadObjectProxy.h
@@ -0,0 +1,95 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * 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/. */
+
+#ifndef proxy_DeadObjectProxy_h
+#define proxy_DeadObjectProxy_h
+
+#include "js/Proxy.h"
+
+namespace js {
+
+class ProxyObject;
+
+enum DeadObjectProxyFlags
+{
+ DeadObjectProxyIsCallable = 1 << 0,
+ DeadObjectProxyIsConstructor = 1 << 1,
+ DeadObjectProxyIsBackgroundFinalized = 1 << 2
+};
+
+class DeadObjectProxy : public BaseProxyHandler
+{
+ public:
+ explicit constexpr DeadObjectProxy()
+ : BaseProxyHandler(&family)
+ { }
+
+ /* Standard internal methods. */
+ virtual bool getOwnPropertyDescriptor(JSContext* cx, HandleObject wrapper, HandleId id,
+ MutableHandle<PropertyDescriptor> desc) const override;
+ virtual bool defineProperty(JSContext* cx, HandleObject wrapper, HandleId id,
+ Handle<PropertyDescriptor> desc,
+ ObjectOpResult& result) const override;
+ virtual bool ownPropertyKeys(JSContext* cx, HandleObject wrapper,
+ AutoIdVector& props) const override;
+ virtual bool delete_(JSContext* cx, HandleObject wrapper, HandleId id,
+ ObjectOpResult& result) const override;
+ virtual bool getPrototype(JSContext* cx, HandleObject proxy,
+ MutableHandleObject protop) const override;
+ virtual bool getPrototypeIfOrdinary(JSContext* cx, HandleObject proxy, bool* isOrdinary,
+ MutableHandleObject protop) const override;
+ virtual bool preventExtensions(JSContext* cx, HandleObject proxy,
+ ObjectOpResult& result) const override;
+ virtual bool isExtensible(JSContext* cx, HandleObject proxy, bool* extensible) const override;
+ virtual bool call(JSContext* cx, HandleObject proxy, const CallArgs& args) const override;
+ virtual bool construct(JSContext* cx, HandleObject proxy, const CallArgs& args) const override;
+
+ /* SpiderMonkey extensions. */
+ // BaseProxyHandler::getPropertyDescriptor will throw by calling getOwnPropertyDescriptor.
+ // BaseProxyHandler::enumerate will throw by calling ownKeys.
+ virtual bool nativeCall(JSContext* cx, IsAcceptableThis test, NativeImpl impl,
+ const CallArgs& args) const override;
+ virtual bool hasInstance(JSContext* cx, HandleObject proxy, MutableHandleValue v,
+ bool* bp) const override;
+ virtual bool getBuiltinClass(JSContext* cx, HandleObject proxy, ESClass* cls) const override;
+ virtual bool isArray(JSContext* cx, HandleObject proxy, JS::IsArrayAnswer* answer) const override;
+ virtual const char* className(JSContext* cx, HandleObject proxy) const override;
+ virtual JSString* fun_toString(JSContext* cx, HandleObject proxy,
+ bool isToSource) const override;
+ virtual RegExpShared* regexp_toShared(JSContext* cx, HandleObject proxy) const override;
+
+ virtual bool isCallable(JSObject* obj) const override {
+ return flags(obj) & DeadObjectProxyIsCallable;
+ }
+ virtual bool isConstructor(JSObject* obj) const override {
+ return flags(obj) & DeadObjectProxyIsConstructor;
+ }
+
+ virtual bool finalizeInBackground(const JS::Value& priv) const override {
+ return priv.toInt32() & DeadObjectProxyIsBackgroundFinalized;
+ }
+
+ static const DeadObjectProxy singleton;
+ static const char family;
+
+ private:
+ static int32_t flags(JSObject* obj) {
+ return GetProxyPrivate(obj).toInt32();
+ }
+};
+
+bool
+IsDeadProxyObject(JSObject* obj);
+
+Value
+DeadProxyTargetValue(ProxyObject* obj);
+
+JSObject*
+NewDeadProxyObject(JSContext* cx, JSObject* origObj = nullptr);
+
+} /* namespace js */
+
+#endif /* proxy_DeadObjectProxy_h */
diff --git a/src/third_party/mozjs-60/extract/js/src/proxy/OpaqueCrossCompartmentWrapper.cpp b/src/third_party/mozjs-60/extract/js/src/proxy/OpaqueCrossCompartmentWrapper.cpp
new file mode 100644
index 00000000000..d155b812697
--- /dev/null
+++ b/src/third_party/mozjs-60/extract/js/src/proxy/OpaqueCrossCompartmentWrapper.cpp
@@ -0,0 +1,193 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * 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 "js/Wrapper.h"
+
+#include "vm/JSObject-inl.h"
+
+using namespace js;
+
+bool
+OpaqueCrossCompartmentWrapper::getOwnPropertyDescriptor(JSContext* cx,
+ HandleObject wrapper,
+ HandleId id,
+ MutableHandle<PropertyDescriptor> desc) const
+{
+ desc.object().set(nullptr);
+ return true;
+}
+
+bool
+OpaqueCrossCompartmentWrapper::defineProperty(JSContext* cx, HandleObject wrapper, HandleId id,
+ Handle<PropertyDescriptor> desc,
+ ObjectOpResult& result) const
+{
+ return result.succeed();
+}
+
+bool
+OpaqueCrossCompartmentWrapper::ownPropertyKeys(JSContext* cx, HandleObject wrapper,
+ AutoIdVector& props) const
+{
+ return true;
+}
+
+bool
+OpaqueCrossCompartmentWrapper::delete_(JSContext* cx, HandleObject wrapper, HandleId id,
+ ObjectOpResult& result) const
+{
+ return result.succeed();
+}
+
+JSObject*
+OpaqueCrossCompartmentWrapper::enumerate(JSContext* cx, HandleObject wrapper) const
+{
+ return BaseProxyHandler::enumerate(cx, wrapper);
+}
+
+bool
+OpaqueCrossCompartmentWrapper::getPrototype(JSContext* cx, HandleObject proxy,
+ MutableHandleObject protop) const
+{
+ protop.set(nullptr);
+ return true;
+}
+
+bool
+OpaqueCrossCompartmentWrapper::setPrototype(JSContext* cx, HandleObject proxy, HandleObject proto,
+ ObjectOpResult& result) const
+{
+ return result.succeed();
+}
+
+bool
+OpaqueCrossCompartmentWrapper::getPrototypeIfOrdinary(JSContext* cx, HandleObject proxy,
+ bool* isOrdinary,
+ MutableHandleObject protop) const
+{
+ *isOrdinary = false;
+ return true;
+}
+
+bool
+OpaqueCrossCompartmentWrapper::setImmutablePrototype(JSContext* cx, HandleObject proxy,
+ bool* succeeded) const
+{
+ *succeeded = false;
+ return true;
+}
+
+bool
+OpaqueCrossCompartmentWrapper::preventExtensions(JSContext* cx, HandleObject wrapper,
+ ObjectOpResult& result) const
+{
+ return result.failCantPreventExtensions();
+}
+
+bool
+OpaqueCrossCompartmentWrapper::isExtensible(JSContext* cx, HandleObject wrapper,
+ bool* extensible) const
+{
+ *extensible = true;
+ return true;
+}
+
+bool
+OpaqueCrossCompartmentWrapper::has(JSContext* cx, HandleObject wrapper, HandleId id,
+ bool* bp) const
+{
+ return BaseProxyHandler::has(cx, wrapper, id, bp);
+}
+
+bool
+OpaqueCrossCompartmentWrapper::get(JSContext* cx, HandleObject wrapper, HandleValue receiver,
+ HandleId id, MutableHandleValue vp) const
+{
+ return BaseProxyHandler::get(cx, wrapper, receiver, id, vp);
+}
+
+bool
+OpaqueCrossCompartmentWrapper::set(JSContext* cx, HandleObject wrapper, HandleId id,
+ HandleValue v, HandleValue receiver,
+ ObjectOpResult& result) const
+{
+ return BaseProxyHandler::set(cx, wrapper, id, v, receiver, result);
+}
+
+bool
+OpaqueCrossCompartmentWrapper::call(JSContext* cx, HandleObject wrapper,
+ const CallArgs& args) const
+{
+ RootedValue v(cx, ObjectValue(*wrapper));
+ ReportIsNotFunction(cx, v);
+ return false;
+}
+
+bool
+OpaqueCrossCompartmentWrapper::construct(JSContext* cx, HandleObject wrapper,
+ const CallArgs& args) const
+{
+ RootedValue v(cx, ObjectValue(*wrapper));
+ ReportIsNotFunction(cx, v);
+ return false;
+}
+
+bool
+OpaqueCrossCompartmentWrapper::getPropertyDescriptor(JSContext* cx,
+ HandleObject wrapper,
+ HandleId id,
+ MutableHandle<PropertyDescriptor> desc) const
+{
+ return BaseProxyHandler::getPropertyDescriptor(cx, wrapper, id, desc);
+}
+
+bool
+OpaqueCrossCompartmentWrapper::hasOwn(JSContext* cx, HandleObject wrapper, HandleId id,
+ bool* bp) const
+{
+ return BaseProxyHandler::hasOwn(cx, wrapper, id, bp);
+}
+
+bool
+OpaqueCrossCompartmentWrapper::getOwnEnumerablePropertyKeys(JSContext* cx, HandleObject wrapper,
+ AutoIdVector& props) const
+{
+ return BaseProxyHandler::getOwnEnumerablePropertyKeys(cx, wrapper, props);
+}
+
+bool
+OpaqueCrossCompartmentWrapper::getBuiltinClass(JSContext* cx, HandleObject wrapper,
+ ESClass* cls) const
+{
+ *cls = ESClass::Other;
+ return true;
+}
+
+bool
+OpaqueCrossCompartmentWrapper::isArray(JSContext* cx, HandleObject obj,
+ JS::IsArrayAnswer* answer) const
+{
+ *answer = JS::IsArrayAnswer::NotArray;
+ return true;
+}
+
+const char*
+OpaqueCrossCompartmentWrapper::className(JSContext* cx,
+ HandleObject proxy) const
+{
+ return "Opaque";
+}
+
+JSString*
+OpaqueCrossCompartmentWrapper::fun_toString(JSContext* cx, HandleObject proxy,
+ bool isToSource) const
+{
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_INCOMPATIBLE_PROTO,
+ js_Function_str, js_toString_str, "object");
+ return nullptr;
+}
+
+const OpaqueCrossCompartmentWrapper OpaqueCrossCompartmentWrapper::singleton;
diff --git a/src/third_party/mozjs-60/extract/js/src/proxy/Proxy.cpp b/src/third_party/mozjs-60/extract/js/src/proxy/Proxy.cpp
new file mode 100644
index 00000000000..30c754b3433
--- /dev/null
+++ b/src/third_party/mozjs-60/extract/js/src/proxy/Proxy.cpp
@@ -0,0 +1,867 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * 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 "js/Proxy.h"
+
+#include "mozilla/Attributes.h"
+
+#include <string.h>
+
+#include "jsapi.h"
+
+#include "js/Wrapper.h"
+#include "proxy/DeadObjectProxy.h"
+#include "proxy/ScriptedProxyHandler.h"
+#include "vm/JSContext.h"
+#include "vm/JSFunction.h"
+#include "vm/WrapperObject.h"
+
+#include "gc/Marking-inl.h"
+#include "vm/JSAtom-inl.h"
+#include "vm/JSObject-inl.h"
+#include "vm/NativeObject-inl.h"
+
+using namespace js;
+using namespace js::gc;
+
+void
+js::AutoEnterPolicy::reportErrorIfExceptionIsNotPending(JSContext* cx, jsid id)
+{
+ if (JS_IsExceptionPending(cx))
+ return;
+
+ if (JSID_IS_VOID(id)) {
+ ReportAccessDenied(cx);
+ } else {
+ RootedValue idVal(cx, IdToValue(id));
+ JSString* str = ValueToSource(cx, idVal);
+ if (!str) {
+ return;
+ }
+ AutoStableStringChars chars(cx);
+ const char16_t* prop = nullptr;
+ if (str->ensureFlat(cx) && chars.initTwoByte(cx, str))
+ prop = chars.twoByteChars();
+
+ JS_ReportErrorNumberUC(cx, GetErrorMessage, nullptr, JSMSG_PROPERTY_ACCESS_DENIED,
+ prop);
+ }
+}
+
+#ifdef DEBUG
+void
+js::AutoEnterPolicy::recordEnter(JSContext* cx, HandleObject proxy, HandleId id, Action act)
+{
+ if (allowed()) {
+ context = cx;
+ enteredProxy.emplace(proxy);
+ enteredId.emplace(id);
+ enteredAction = act;
+ prev = cx->enteredPolicy;
+ cx->enteredPolicy = this;
+ }
+}
+
+void
+js::AutoEnterPolicy::recordLeave()
+{
+ if (enteredProxy) {
+ MOZ_ASSERT(context->enteredPolicy == this);
+ context->enteredPolicy = prev;
+ }
+}
+
+JS_FRIEND_API(void)
+js::assertEnteredPolicy(JSContext* cx, JSObject* proxy, jsid id,
+ BaseProxyHandler::Action act)
+{
+ MOZ_ASSERT(proxy->is<ProxyObject>());
+ MOZ_ASSERT(cx->enteredPolicy);
+ MOZ_ASSERT(cx->enteredPolicy->enteredProxy->get() == proxy);
+ MOZ_ASSERT(cx->enteredPolicy->enteredId->get() == id);
+ MOZ_ASSERT(cx->enteredPolicy->enteredAction & act);
+}
+#endif
+
+bool
+Proxy::getPropertyDescriptor(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();
+
+ // Special case. See the comment on BaseProxyHandler::mHasPrototype.
+ if (handler->hasPrototype())
+ return handler->BaseProxyHandler::getPropertyDescriptor(cx, proxy, id, desc);
+
+ return handler->getPropertyDescriptor(cx, proxy, 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
+Proxy::defineProperty(JSContext* cx, HandleObject proxy, HandleId id,
+ Handle<PropertyDescriptor> desc, ObjectOpResult& result)
+{
+ if (!CheckRecursionLimit(cx))
+ return false;
+ const BaseProxyHandler* handler = proxy->as<ProxyObject>().handler();
+ AutoEnterPolicy policy(cx, handler, proxy, id, BaseProxyHandler::SET, true);
+ if (!policy.allowed()) {
+ if (!policy.returnValue())
+ return false;
+ return result.succeed();
+ }
+ return proxy->as<ProxyObject>().handler()->defineProperty(cx, proxy, id, desc, result);
+}
+
+bool
+Proxy::ownPropertyKeys(JSContext* cx, HandleObject proxy, AutoIdVector& props)
+{
+ if (!CheckRecursionLimit(cx))
+ return false;
+ const BaseProxyHandler* handler = proxy->as<ProxyObject>().handler();
+ AutoEnterPolicy policy(cx, handler, proxy, JSID_VOIDHANDLE, BaseProxyHandler::ENUMERATE, true);
+ if (!policy.allowed())
+ return policy.returnValue();
+ return proxy->as<ProxyObject>().handler()->ownPropertyKeys(cx, proxy, props);
+}
+
+bool
+Proxy::delete_(JSContext* cx, HandleObject proxy, HandleId id, ObjectOpResult& result)
+{
+ if (!CheckRecursionLimit(cx))
+ return false;
+ const BaseProxyHandler* handler = proxy->as<ProxyObject>().handler();
+ AutoEnterPolicy policy(cx, handler, proxy, id, BaseProxyHandler::SET, true);
+ if (!policy.allowed()) {
+ bool ok = policy.returnValue();
+ if (ok)
+ result.succeed();
+ return ok;
+ }
+ return proxy->as<ProxyObject>().handler()->delete_(cx, proxy, id, result);
+}
+
+JS_FRIEND_API(bool)
+js::AppendUnique(JSContext* cx, AutoIdVector& base, AutoIdVector& others)
+{
+ AutoIdVector uniqueOthers(cx);
+ if (!uniqueOthers.reserve(others.length()))
+ return false;
+ for (size_t i = 0; i < others.length(); ++i) {
+ bool unique = true;
+ for (size_t j = 0; j < base.length(); ++j) {
+ if (others[i].get() == base[j]) {
+ unique = false;
+ break;
+ }
+ }
+ if (unique) {
+ if (!uniqueOthers.append(others[i]))
+ return false;
+ }
+ }
+ return base.appendAll(uniqueOthers);
+}
+
+/* static */ bool
+Proxy::getPrototype(JSContext* cx, HandleObject proxy, MutableHandleObject proto)
+{
+ MOZ_ASSERT(proxy->hasDynamicPrototype());
+ if (!CheckRecursionLimit(cx))
+ return false;
+ return proxy->as<ProxyObject>().handler()->getPrototype(cx, proxy, proto);
+}
+
+/* static */ bool
+Proxy::setPrototype(JSContext* cx, HandleObject proxy, HandleObject proto, ObjectOpResult& result)
+{
+ MOZ_ASSERT(proxy->hasDynamicPrototype());
+ if (!CheckRecursionLimit(cx))
+ return false;
+ return proxy->as<ProxyObject>().handler()->setPrototype(cx, proxy, proto, result);
+}
+
+/* static */ bool
+Proxy::getPrototypeIfOrdinary(JSContext* cx, HandleObject proxy, bool* isOrdinary,
+ MutableHandleObject proto)
+{
+ if (!CheckRecursionLimit(cx))
+ return false;
+ return proxy->as<ProxyObject>().handler()->getPrototypeIfOrdinary(cx, proxy, isOrdinary,
+ proto);
+}
+
+/* static */ bool
+Proxy::setImmutablePrototype(JSContext* cx, HandleObject proxy, bool* succeeded)
+{
+ if (!CheckRecursionLimit(cx))
+ return false;
+ const BaseProxyHandler* handler = proxy->as<ProxyObject>().handler();
+ return handler->setImmutablePrototype(cx, proxy, succeeded);
+}
+
+/* static */ bool
+Proxy::preventExtensions(JSContext* cx, HandleObject proxy, ObjectOpResult& result)
+{
+ if (!CheckRecursionLimit(cx))
+ return false;
+ const BaseProxyHandler* handler = proxy->as<ProxyObject>().handler();
+ return handler->preventExtensions(cx, proxy, result);
+}
+
+/* static */ bool
+Proxy::isExtensible(JSContext* cx, HandleObject proxy, bool* extensible)
+{
+ if (!CheckRecursionLimit(cx))
+ return false;
+ return proxy->as<ProxyObject>().handler()->isExtensible(cx, proxy, extensible);
+}
+
+bool
+Proxy::has(JSContext* cx, HandleObject proxy, HandleId id, bool* bp)
+{
+ if (!CheckRecursionLimit(cx))
+ return false;
+ const BaseProxyHandler* handler = proxy->as<ProxyObject>().handler();
+ *bp = false; // default result if we refuse to perform this action
+ AutoEnterPolicy policy(cx, handler, proxy, id, BaseProxyHandler::GET, true);
+ if (!policy.allowed())
+ return policy.returnValue();
+
+ if (handler->hasPrototype()) {
+ if (!handler->hasOwn(cx, proxy, id, bp))
+ return false;
+ if (*bp)
+ return true;
+
+ RootedObject proto(cx);
+ if (!GetPrototype(cx, proxy, &proto))
+ return false;
+ if (!proto)
+ return true;
+
+ return HasProperty(cx, proto, id, bp);
+ }
+
+ return handler->has(cx, proxy, id, bp);
+}
+
+bool
+js::ProxyHas(JSContext* cx, HandleObject proxy, HandleValue idVal, MutableHandleValue result)
+{
+ RootedId id(cx);
+ if (!ValueToId<CanGC>(cx, idVal, &id))
+ return false;
+
+ bool has;
+ if (!Proxy::has(cx, proxy, id, &has))
+ return false;
+
+ result.setBoolean(has);
+ return true;
+}
+
+bool
+Proxy::hasOwn(JSContext* cx, HandleObject proxy, HandleId id, bool* bp)
+{
+ if (!CheckRecursionLimit(cx))
+ return false;
+ const BaseProxyHandler* handler = proxy->as<ProxyObject>().handler();
+ *bp = false; // default result if we refuse to perform this action
+ AutoEnterPolicy policy(cx, handler, proxy, id, BaseProxyHandler::GET, true);
+ if (!policy.allowed())
+ return policy.returnValue();
+ return handler->hasOwn(cx, proxy, id, bp);
+}
+
+bool
+js::ProxyHasOwn(JSContext* cx, HandleObject proxy, HandleValue idVal, MutableHandleValue result)
+{
+ RootedId id(cx);
+ if (!ValueToId<CanGC>(cx, idVal, &id))
+ return false;
+
+ bool hasOwn;
+ if (!Proxy::hasOwn(cx, proxy, id, &hasOwn))
+ return false;
+
+ result.setBoolean(hasOwn);
+ return true;
+}
+
+static MOZ_ALWAYS_INLINE Value
+ValueToWindowProxyIfWindow(const Value& v, JSObject* proxy)
+{
+ if (v.isObject() && v != ObjectValue(*proxy))
+ return ObjectValue(*ToWindowProxyIfWindow(&v.toObject()));
+ return v;
+}
+
+MOZ_ALWAYS_INLINE bool
+Proxy::getInternal(JSContext* cx, HandleObject proxy, HandleValue receiver,
+ HandleId id, MutableHandleValue vp)
+{
+ MOZ_ASSERT_IF(receiver.isObject(), !IsWindow(&receiver.toObject()));
+
+ if (!CheckRecursionLimit(cx))
+ return false;
+ const BaseProxyHandler* handler = proxy->as<ProxyObject>().handler();
+ vp.setUndefined(); // default result if we refuse to perform this action
+ AutoEnterPolicy policy(cx, handler, proxy, id, BaseProxyHandler::GET, true);
+ if (!policy.allowed())
+ return policy.returnValue();
+
+ if (handler->hasPrototype()) {
+ bool own;
+ if (!handler->hasOwn(cx, proxy, id, &own))
+ return false;
+ if (!own) {
+ RootedObject proto(cx);
+ if (!GetPrototype(cx, proxy, &proto))
+ return false;
+ if (!proto)
+ return true;
+ return GetProperty(cx, proto, receiver, id, vp);
+ }
+ }
+
+ return handler->get(cx, proxy, receiver, id, vp);
+}
+
+bool
+Proxy::get(JSContext* cx, HandleObject proxy, HandleValue receiver_, HandleId id,
+ MutableHandleValue vp)
+{
+ // Use the WindowProxy as receiver if receiver_ is a Window. Proxy handlers
+ // shouldn't have to know about the Window/WindowProxy distinction.
+ RootedValue receiver(cx, ValueToWindowProxyIfWindow(receiver_, proxy));
+ return getInternal(cx, proxy, receiver, id, vp);
+}
+
+bool
+js::ProxyGetProperty(JSContext* cx, HandleObject proxy, HandleId id, MutableHandleValue vp)
+{
+ RootedValue receiver(cx, ObjectValue(*proxy));
+ return Proxy::getInternal(cx, proxy, receiver, id, vp);
+}
+
+bool
+js::ProxyGetPropertyByValue(JSContext* cx, HandleObject proxy, HandleValue idVal,
+ MutableHandleValue vp)
+{
+ RootedId id(cx);
+ if (!ValueToId<CanGC>(cx, idVal, &id))
+ return false;
+
+ RootedValue receiver(cx, ObjectValue(*proxy));
+ return Proxy::getInternal(cx, proxy, receiver, id, vp);
+}
+
+MOZ_ALWAYS_INLINE bool
+Proxy::setInternal(JSContext* cx, HandleObject proxy, HandleId id, HandleValue v,
+ HandleValue receiver, ObjectOpResult& result)
+{
+ MOZ_ASSERT_IF(receiver.isObject(), !IsWindow(&receiver.toObject()));
+
+ if (!CheckRecursionLimit(cx))
+ return false;
+ const BaseProxyHandler* handler = proxy->as<ProxyObject>().handler();
+ AutoEnterPolicy policy(cx, handler, proxy, id, BaseProxyHandler::SET, true);
+ if (!policy.allowed()) {
+ if (!policy.returnValue())
+ return false;
+ return result.succeed();
+ }
+
+ // Special case. See the comment on BaseProxyHandler::mHasPrototype.
+ if (handler->hasPrototype())
+ return handler->BaseProxyHandler::set(cx, proxy, id, v, receiver, result);
+
+ return handler->set(cx, proxy, id, v, receiver, result);
+}
+
+bool
+Proxy::set(JSContext* cx, HandleObject proxy, HandleId id, HandleValue v, HandleValue receiver_,
+ ObjectOpResult& result)
+{
+ // Use the WindowProxy as receiver if receiver_ is a Window. Proxy handlers
+ // shouldn't have to know about the Window/WindowProxy distinction.
+ RootedValue receiver(cx, ValueToWindowProxyIfWindow(receiver_, proxy));
+ return setInternal(cx, proxy, id, v, receiver, result);
+}
+
+bool
+js::ProxySetProperty(JSContext* cx, HandleObject proxy, HandleId id, HandleValue val, bool strict)
+{
+ ObjectOpResult result;
+ RootedValue receiver(cx, ObjectValue(*proxy));
+ if (!Proxy::setInternal(cx, proxy, id, val, receiver, result))
+ return false;
+ return result.checkStrictErrorOrWarning(cx, proxy, id, strict);
+}
+
+bool
+js::ProxySetPropertyByValue(JSContext* cx, HandleObject proxy, HandleValue idVal, HandleValue val,
+ bool strict)
+{
+ RootedId id(cx);
+ if (!ValueToId<CanGC>(cx, idVal, &id))
+ return false;
+
+ ObjectOpResult result;
+ RootedValue receiver(cx, ObjectValue(*proxy));
+ if (!Proxy::setInternal(cx, proxy, id, val, receiver, result))
+ return false;
+ return result.checkStrictErrorOrWarning(cx, proxy, id, strict);
+}
+
+bool
+Proxy::getOwnEnumerablePropertyKeys(JSContext* cx, HandleObject proxy, AutoIdVector& props)
+{
+ if (!CheckRecursionLimit(cx))
+ return false;
+ const BaseProxyHandler* handler = proxy->as<ProxyObject>().handler();
+ AutoEnterPolicy policy(cx, handler, proxy, JSID_VOIDHANDLE, BaseProxyHandler::ENUMERATE, true);
+ if (!policy.allowed())
+ return policy.returnValue();
+ return handler->getOwnEnumerablePropertyKeys(cx, proxy, props);
+}
+
+JSObject*
+Proxy::enumerate(JSContext* cx, HandleObject proxy)
+{
+ if (!CheckRecursionLimit(cx))
+ return nullptr;
+
+ const BaseProxyHandler* handler = proxy->as<ProxyObject>().handler();
+ if (handler->hasPrototype()) {
+ AutoIdVector props(cx);
+ if (!Proxy::getOwnEnumerablePropertyKeys(cx, proxy, props))
+ return nullptr;
+
+ RootedObject proto(cx);
+ if (!GetPrototype(cx, proxy, &proto))
+ return nullptr;
+ if (!proto)
+ return EnumeratedIdVectorToIterator(cx, proxy, props);
+ assertSameCompartment(cx, proxy, proto);
+
+ AutoIdVector protoProps(cx);
+ if (!GetPropertyKeys(cx, proto, 0, &protoProps))
+ return nullptr;
+ if (!AppendUnique(cx, props, protoProps))
+ return nullptr;
+ return EnumeratedIdVectorToIterator(cx, proxy, props);
+ }
+
+ AutoEnterPolicy policy(cx, handler, proxy, JSID_VOIDHANDLE,
+ BaseProxyHandler::ENUMERATE, true);
+
+ // If the policy denies access but wants us to return true, we need
+ // to hand a valid (empty) iterator object to the caller.
+ if (!policy.allowed()) {
+ if (!policy.returnValue())
+ return nullptr;
+ return NewEmptyPropertyIterator(cx);
+ }
+ return handler->enumerate(cx, proxy);
+}
+
+bool
+Proxy::call(JSContext* cx, HandleObject proxy, const CallArgs& args)
+{
+ if (!CheckRecursionLimit(cx))
+ return false;
+ const BaseProxyHandler* handler = proxy->as<ProxyObject>().handler();
+
+ // Because vp[0] is JS_CALLEE on the way in and JS_RVAL on the way out, we
+ // can only set our default value once we're sure that we're not calling the
+ // trap.
+ AutoEnterPolicy policy(cx, handler, proxy, JSID_VOIDHANDLE,
+ BaseProxyHandler::CALL, true);
+ if (!policy.allowed()) {
+ args.rval().setUndefined();
+ return policy.returnValue();
+ }
+
+ return handler->call(cx, proxy, args);
+}
+
+bool
+Proxy::construct(JSContext* cx, HandleObject proxy, const CallArgs& args)
+{
+ if (!CheckRecursionLimit(cx))
+ return false;
+ const BaseProxyHandler* handler = proxy->as<ProxyObject>().handler();
+
+ // Because vp[0] is JS_CALLEE on the way in and JS_RVAL on the way out, we
+ // can only set our default value once we're sure that we're not calling the
+ // trap.
+ AutoEnterPolicy policy(cx, handler, proxy, JSID_VOIDHANDLE,
+ BaseProxyHandler::CALL, true);
+ if (!policy.allowed()) {
+ args.rval().setUndefined();
+ return policy.returnValue();
+ }
+
+ return handler->construct(cx, proxy, args);
+}
+
+bool
+Proxy::nativeCall(JSContext* cx, IsAcceptableThis test, NativeImpl impl, const CallArgs& args)
+{
+ if (!CheckRecursionLimit(cx))
+ return false;
+ RootedObject proxy(cx, &args.thisv().toObject());
+ // Note - we don't enter a policy here because our security architecture
+ // guards against nativeCall by overriding the trap itself in the right
+ // circumstances.
+ return proxy->as<ProxyObject>().handler()->nativeCall(cx, test, impl, args);
+}
+
+bool
+Proxy::hasInstance(JSContext* cx, HandleObject proxy, MutableHandleValue v, bool* bp)
+{
+ if (!CheckRecursionLimit(cx))
+ return false;
+ const BaseProxyHandler* handler = proxy->as<ProxyObject>().handler();
+ *bp = false; // default result if we refuse to perform this action
+ AutoEnterPolicy policy(cx, handler, proxy, JSID_VOIDHANDLE, BaseProxyHandler::GET, true);
+ if (!policy.allowed())
+ return policy.returnValue();
+ return proxy->as<ProxyObject>().handler()->hasInstance(cx, proxy, v, bp);
+}
+
+bool
+Proxy::getBuiltinClass(JSContext* cx, HandleObject proxy, ESClass* cls)
+{
+ if (!CheckRecursionLimit(cx))
+ return false;
+ return proxy->as<ProxyObject>().handler()->getBuiltinClass(cx, proxy, cls);
+}
+
+bool
+Proxy::isArray(JSContext* cx, HandleObject proxy, JS::IsArrayAnswer* answer)
+{
+ if (!CheckRecursionLimit(cx))
+ return false;
+ return proxy->as<ProxyObject>().handler()->isArray(cx, proxy, answer);
+}
+
+const char*
+Proxy::className(JSContext* cx, HandleObject proxy)
+{
+ // Check for unbounded recursion, but don't signal an error; className
+ // needs to be infallible.
+ int stackDummy;
+ if (!JS_CHECK_STACK_SIZE(GetNativeStackLimit(cx), &stackDummy))
+ return "too much recursion";
+
+ const BaseProxyHandler* handler = proxy->as<ProxyObject>().handler();
+ AutoEnterPolicy policy(cx, handler, proxy, JSID_VOIDHANDLE,
+ BaseProxyHandler::GET, /* mayThrow = */ false);
+ // Do the safe thing if the policy rejects.
+ if (!policy.allowed()) {
+ return handler->BaseProxyHandler::className(cx, proxy);
+ }
+ return handler->className(cx, proxy);
+}
+
+JSString*
+Proxy::fun_toString(JSContext* cx, HandleObject proxy, bool isToSource)
+{
+ if (!CheckRecursionLimit(cx))
+ return nullptr;
+ const BaseProxyHandler* handler = proxy->as<ProxyObject>().handler();
+ AutoEnterPolicy policy(cx, handler, proxy, JSID_VOIDHANDLE,
+ BaseProxyHandler::GET, /* mayThrow = */ false);
+ // Do the safe thing if the policy rejects.
+ if (!policy.allowed())
+ return handler->BaseProxyHandler::fun_toString(cx, proxy, isToSource);
+ return handler->fun_toString(cx, proxy, isToSource);
+}
+
+RegExpShared*
+Proxy::regexp_toShared(JSContext* cx, HandleObject proxy)
+{
+ if (!CheckRecursionLimit(cx))
+ return nullptr;
+ return proxy->as<ProxyObject>().handler()->regexp_toShared(cx, proxy);
+}
+
+bool
+Proxy::boxedValue_unbox(JSContext* cx, HandleObject proxy, MutableHandleValue vp)
+{
+ if (!CheckRecursionLimit(cx))
+ return false;
+ return proxy->as<ProxyObject>().handler()->boxedValue_unbox(cx, proxy, vp);
+}
+
+JSObject * const TaggedProto::LazyProto = reinterpret_cast<JSObject*>(0x1);
+
+/* static */ bool
+Proxy::getElements(JSContext* cx, HandleObject proxy, uint32_t begin, uint32_t end,
+ ElementAdder* adder)
+{
+ if (!CheckRecursionLimit(cx))
+ return false;
+ const BaseProxyHandler* handler = proxy->as<ProxyObject>().handler();
+ AutoEnterPolicy policy(cx, handler, proxy, JSID_VOIDHANDLE, BaseProxyHandler::GET,
+ /* mayThrow = */ true);
+ if (!policy.allowed()) {
+ if (policy.returnValue()) {
+ MOZ_ASSERT(!cx->isExceptionPending());
+ return js::GetElementsWithAdder(cx, proxy, proxy, begin, end, adder);
+ }
+ return false;
+ }
+ return handler->getElements(cx, proxy, begin, end, adder);
+}
+
+/* static */ void
+Proxy::trace(JSTracer* trc, JSObject* proxy)
+{
+ const BaseProxyHandler* handler = proxy->as<ProxyObject>().handler();
+ handler->trace(trc, proxy);
+}
+
+static bool
+proxy_LookupProperty(JSContext* cx, HandleObject obj, HandleId id,
+ MutableHandleObject objp, MutableHandle<JS::PropertyResult> propp)
+{
+ bool found;
+ if (!Proxy::has(cx, obj, id, &found))
+ return false;
+
+ if (found) {
+ propp.setNonNativeProperty();
+ objp.set(obj);
+ } else {
+ propp.setNotFound();
+ objp.set(nullptr);
+ }
+ return true;
+}
+
+static bool
+proxy_DeleteProperty(JSContext* cx, HandleObject obj, HandleId id, ObjectOpResult& result)
+{
+ if (!Proxy::delete_(cx, obj, id, result))
+ return false;
+ return SuppressDeletedProperty(cx, obj, id); // XXX is this necessary?
+}
+
+/* static */ void
+ProxyObject::traceEdgeToTarget(JSTracer* trc, ProxyObject* obj)
+{
+ TraceCrossCompartmentEdge(trc, obj, obj->slotOfPrivate(), "proxy target");
+}
+
+/* static */ void
+ProxyObject::trace(JSTracer* trc, JSObject* obj)
+{
+ ProxyObject* proxy = &obj->as<ProxyObject>();
+
+ TraceEdge(trc, proxy->shapePtr(), "ProxyObject_shape");
+
+#ifdef DEBUG
+ if (TlsContext.get()->isStrictProxyCheckingEnabled() && proxy->is<WrapperObject>()) {
+ JSObject* referent = MaybeForwarded(proxy->target());
+ if (referent->compartment() != proxy->compartment()) {
+ /*
+ * Assert that this proxy is tracked in the wrapper map. We maintain
+ * the invariant that the wrapped object is the key in the wrapper map.
+ */
+ Value key = ObjectValue(*referent);
+ WrapperMap::Ptr p = proxy->compartment()->lookupWrapper(key);
+ MOZ_ASSERT(p);
+ MOZ_ASSERT(*p->value().unsafeGet() == ObjectValue(*proxy));
+ }
+ }
+#endif
+
+ // Note: If you add new slots here, make sure to change
+ // nuke() to cope.
+
+ traceEdgeToTarget(trc, proxy);
+
+ size_t nreserved = proxy->numReservedSlots();
+ for (size_t i = 0; i < nreserved; i++) {
+ /*
+ * The GC can use the second reserved slot to link the cross compartment
+ * wrappers into a linked list, in which case we don't want to trace it.
+ */
+ if (proxy->is<CrossCompartmentWrapperObject>() &&
+ i == CrossCompartmentWrapperObject::GrayLinkReservedSlot)
+ {
+ continue;
+ }
+ TraceEdge(trc, proxy->reservedSlotPtr(i), "proxy_reserved");
+ }
+
+ Proxy::trace(trc, obj);
+}
+
+JSObject*
+js::proxy_WeakmapKeyDelegate(JSObject* obj)
+{
+ MOZ_ASSERT(obj->is<ProxyObject>());
+ return obj->as<ProxyObject>().handler()->weakmapKeyDelegate(obj);
+}
+
+static void
+proxy_Finalize(FreeOp* fop, JSObject* obj)
+{
+ // Suppress a bogus warning about finalize().
+ JS::AutoSuppressGCAnalysis nogc;
+
+ MOZ_ASSERT(obj->is<ProxyObject>());
+ obj->as<ProxyObject>().handler()->finalize(fop, obj);
+
+ if (!obj->as<ProxyObject>().usingInlineValueArray())
+ js_free(js::detail::GetProxyDataLayout(obj)->values());
+}
+
+size_t
+js::proxy_ObjectMoved(JSObject* obj, JSObject* old)
+{
+ ProxyObject& proxy = obj->as<ProxyObject>();
+
+ if (IsInsideNursery(old)) {
+ // Objects in the nursery are never swapped so the proxy must have an
+ // inline ProxyValueArray.
+ MOZ_ASSERT(old->as<ProxyObject>().usingInlineValueArray());
+ proxy.setInlineValueArray();
+ }
+
+ return proxy.handler()->objectMoved(obj, old);
+}
+
+bool
+js::proxy_Call(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ RootedObject proxy(cx, &args.callee());
+ MOZ_ASSERT(proxy->is<ProxyObject>());
+ return Proxy::call(cx, proxy, args);
+}
+
+bool
+js::proxy_Construct(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ RootedObject proxy(cx, &args.callee());
+ MOZ_ASSERT(proxy->is<ProxyObject>());
+ return Proxy::construct(cx, proxy, args);
+}
+
+const ClassOps js::ProxyClassOps = {
+ nullptr, /* addProperty */
+ nullptr, /* delProperty */
+ nullptr, /* enumerate */
+ nullptr, /* newEnumerate */
+ nullptr, /* resolve */
+ nullptr, /* mayResolve */
+ proxy_Finalize, /* finalize */
+ nullptr, /* call */
+ Proxy::hasInstance, /* hasInstance */
+ nullptr, /* construct */
+ ProxyObject::trace, /* trace */
+};
+
+const ClassExtension js::ProxyClassExtension = {
+ proxy_WeakmapKeyDelegate,
+ proxy_ObjectMoved
+};
+
+const ObjectOps js::ProxyObjectOps = {
+ proxy_LookupProperty,
+ Proxy::defineProperty,
+ Proxy::has,
+ Proxy::get,
+ Proxy::set,
+ Proxy::getOwnPropertyDescriptor,
+ proxy_DeleteProperty,
+ Proxy::getElements,
+ Proxy::fun_toString
+};
+
+const Class js::ProxyObject::proxyClass =
+ PROXY_CLASS_DEF("Proxy",
+ JSCLASS_HAS_CACHED_PROTO(JSProto_Proxy) |
+ JSCLASS_HAS_RESERVED_SLOTS(2));
+
+const Class* const js::ProxyClassPtr = &js::ProxyObject::proxyClass;
+
+JS_FRIEND_API(JSObject*)
+js::NewProxyObject(JSContext* cx, const BaseProxyHandler* handler, HandleValue priv, JSObject* proto_,
+ const ProxyOptions& options)
+{
+ if (options.lazyProto()) {
+ MOZ_ASSERT(!proto_);
+ proto_ = TaggedProto::LazyProto;
+ }
+
+ return ProxyObject::New(cx, handler, priv, TaggedProto(proto_), options);
+}
+
+void
+ProxyObject::renew(const BaseProxyHandler* handler, const Value& priv)
+{
+ MOZ_ASSERT(!IsInsideNursery(this));
+ MOZ_ASSERT_IF(IsCrossCompartmentWrapper(this), IsDeadProxyObject(this));
+ MOZ_ASSERT(getClass() == &ProxyObject::proxyClass);
+ MOZ_ASSERT(!IsWindowProxy(this));
+ MOZ_ASSERT(hasDynamicPrototype());
+
+ setHandler(handler);
+ setCrossCompartmentPrivate(priv);
+ for (size_t i = 0; i < numReservedSlots(); i++)
+ setReservedSlot(i, UndefinedValue());
+}
+
+JS_FRIEND_API(JSObject*)
+js::InitProxyClass(JSContext* cx, HandleObject obj)
+{
+ static const JSFunctionSpec static_methods[] = {
+ JS_FN("revocable", proxy_revocable, 2, 0),
+ JS_FS_END
+ };
+
+ Handle<GlobalObject*> global = obj.as<GlobalObject>();
+ RootedFunction ctor(cx);
+ ctor = GlobalObject::createConstructor(cx, proxy, cx->names().Proxy, 2);
+ if (!ctor)
+ return nullptr;
+
+ if (!JS_DefineFunctions(cx, ctor, static_methods))
+ return nullptr;
+ if (!JS_DefineProperty(cx, obj, "Proxy", ctor, JSPROP_RESOLVING))
+ return nullptr;
+
+ global->setConstructor(JSProto_Proxy, ObjectValue(*ctor));
+ return ctor;
+}
diff --git a/src/third_party/mozjs-60/extract/js/src/proxy/Proxy.h b/src/third_party/mozjs-60/extract/js/src/proxy/Proxy.h
new file mode 100644
index 00000000000..027098cf4fb
--- /dev/null
+++ b/src/third_party/mozjs-60/extract/js/src/proxy/Proxy.h
@@ -0,0 +1,107 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * 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/. */
+
+#ifndef proxy_Proxy_h
+#define proxy_Proxy_h
+
+#include "NamespaceImports.h"
+
+#include "js/Class.h"
+
+namespace js {
+
+/*
+ * Dispatch point for handlers that executes the appropriate C++ or scripted traps.
+ *
+ * Important: All proxy methods need either (a) an AutoEnterPolicy in their
+ * Proxy::foo entry point below or (b) an override in SecurityWrapper. See bug
+ * 945826 comment 0.
+ */
+class Proxy
+{
+ public:
+ /* Standard internal methods. */
+ static bool getOwnPropertyDescriptor(JSContext* cx, HandleObject proxy, HandleId id,
+ MutableHandle<JS::PropertyDescriptor> desc);
+ static bool defineProperty(JSContext* cx, HandleObject proxy, HandleId id,
+ Handle<JS::PropertyDescriptor> desc, ObjectOpResult& result);
+ static bool ownPropertyKeys(JSContext* cx, HandleObject proxy, AutoIdVector& props);
+ static bool delete_(JSContext* cx, HandleObject proxy, HandleId id, ObjectOpResult& result);
+ static JSObject* enumerate(JSContext* cx, HandleObject proxy);
+ static bool isExtensible(JSContext* cx, HandleObject proxy, bool* extensible);
+ static bool preventExtensions(JSContext* cx, HandleObject proxy, ObjectOpResult& result);
+ static bool getPrototype(JSContext* cx, HandleObject proxy, MutableHandleObject protop);
+ static bool setPrototype(JSContext* cx, HandleObject proxy, HandleObject proto,
+ ObjectOpResult& result);
+ static bool getPrototypeIfOrdinary(JSContext* cx, HandleObject proxy, bool* isOrdinary,
+ MutableHandleObject protop);
+ static bool setImmutablePrototype(JSContext* cx, HandleObject proxy, bool* succeeded);
+ static bool has(JSContext* cx, HandleObject proxy, HandleId id, bool* bp);
+ static bool get(JSContext* cx, HandleObject proxy, HandleValue receiver, HandleId id,
+ MutableHandleValue vp);
+ static bool getInternal(JSContext* cx, HandleObject proxy, HandleValue receiver,
+ HandleId id, MutableHandleValue vp);
+ static bool set(JSContext* cx, HandleObject proxy, HandleId id, HandleValue v,
+ HandleValue receiver, ObjectOpResult& result);
+ static bool setInternal(JSContext* cx, HandleObject proxy, HandleId id, HandleValue v,
+ HandleValue receiver, ObjectOpResult& result);
+ static bool call(JSContext* cx, HandleObject proxy, const CallArgs& args);
+ static bool construct(JSContext* cx, HandleObject proxy, const CallArgs& args);
+
+ /* SpiderMonkey extensions. */
+ static bool getPropertyDescriptor(JSContext* cx, HandleObject proxy, HandleId id,
+ MutableHandle<JS::PropertyDescriptor> desc);
+ static bool hasOwn(JSContext* cx, HandleObject proxy, HandleId id, bool* bp);
+ static bool getOwnEnumerablePropertyKeys(JSContext* cx, HandleObject proxy,
+ AutoIdVector& props);
+ static bool nativeCall(JSContext* cx, IsAcceptableThis test, NativeImpl impl,
+ const CallArgs& args);
+ static bool hasInstance(JSContext* cx, HandleObject proxy, MutableHandleValue v, bool* bp);
+ static bool getBuiltinClass(JSContext* cx, HandleObject proxy, ESClass* cls);
+ static bool isArray(JSContext* cx, HandleObject proxy, JS::IsArrayAnswer* answer);
+ static const char* className(JSContext* cx, HandleObject proxy);
+ static JSString* fun_toString(JSContext* cx, HandleObject proxy, bool isToSource);
+ static RegExpShared* regexp_toShared(JSContext* cx, HandleObject proxy);
+ static bool boxedValue_unbox(JSContext* cx, HandleObject proxy, MutableHandleValue vp);
+
+ static bool getElements(JSContext* cx, HandleObject obj, uint32_t begin, uint32_t end,
+ ElementAdder* adder);
+
+ static void trace(JSTracer* trc, JSObject* obj);
+};
+
+bool
+proxy_Call(JSContext* cx, unsigned argc, Value* vp);
+bool
+proxy_Construct(JSContext* cx, unsigned argc, Value* vp);
+size_t
+proxy_ObjectMoved(JSObject* obj, JSObject* old);
+
+// These functions are used by JIT code
+
+bool
+ProxyHas(JSContext* cx, HandleObject proxy, HandleValue idVal, MutableHandleValue result);
+
+bool
+ProxyHasOwn(JSContext* cx, HandleObject proxy, HandleValue idVal, MutableHandleValue result);
+
+bool
+ProxyGetProperty(JSContext* cx, HandleObject proxy, HandleId id, MutableHandleValue vp);
+
+bool
+ProxyGetPropertyByValue(JSContext* cx, HandleObject proxy, HandleValue idVal,
+ MutableHandleValue vp);
+
+bool
+ProxySetProperty(JSContext* cx, HandleObject proxy, HandleId id, HandleValue val, bool strict);
+
+bool
+ProxySetPropertyByValue(JSContext* cx, HandleObject proxy, HandleValue idVal, HandleValue val,
+ bool strict);
+
+} /* namespace js */
+
+#endif /* proxy_Proxy_h */
diff --git a/src/third_party/mozjs-60/extract/js/src/proxy/ScriptedProxyHandler.cpp b/src/third_party/mozjs-60/extract/js/src/proxy/ScriptedProxyHandler.cpp
new file mode 100644
index 00000000000..a4d6919e9be
--- /dev/null
+++ b/src/third_party/mozjs-60/extract/js/src/proxy/ScriptedProxyHandler.cpp
@@ -0,0 +1,1430 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * 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 "proxy/ScriptedProxyHandler.h"
+
+#include "jsapi.h"
+
+#include "vm/Interpreter.h" // For InstanceOfOperator
+
+#include "vm/JSObject-inl.h"
+#include "vm/NativeObject-inl.h"
+
+using namespace js;
+
+using JS::IsArrayAnswer;
+
+// ES8 rev 0c1bd3004329336774cbc90de727cd0cf5f11e93
+// 9.1.6.2 IsCompatiblePropertyDescriptor. BUT that method just calls
+// 9.1.6.3 ValidateAndApplyPropertyDescriptor with two additional constant
+// arguments. Therefore step numbering is from the latter method, and
+// resulting dead code has been removed.
+
+// If an exception should be thrown, we will set errorDetails.
+static bool
+IsCompatiblePropertyDescriptor(JSContext* cx, bool extensible, Handle<PropertyDescriptor> desc,
+ Handle<PropertyDescriptor> current, const char** errorDetails)
+{
+ // precondition: we won't set details if checks pass, so it must be null here.
+ MOZ_ASSERT(*errorDetails == nullptr);
+
+ // Step 2.
+ if (!current.object()) {
+ // Step 2a-b,e. As |O| is always undefined, steps 2c-d fall away.
+ if (!extensible) {
+ static const char* DETAILS_NOT_EXTENSIBLE =
+ "proxy can't report an extensible object as non-extensible";
+ *errorDetails = DETAILS_NOT_EXTENSIBLE;
+ }
+ return true;
+ }
+
+ // Step 3.
+ if (!desc.hasValue() && !desc.hasWritable() &&
+ !desc.hasGetterObject() && !desc.hasSetterObject() &&
+ !desc.hasEnumerable() && !desc.hasConfigurable())
+ {
+ return true;
+ }
+
+ // Step 4.
+ if ((!desc.hasWritable() ||
+ (current.hasWritable() && desc.writable() == current.writable())) &&
+ (!desc.hasGetterObject() || desc.getter() == current.getter()) &&
+ (!desc.hasSetterObject() || desc.setter() == current.setter()) &&
+ (!desc.hasEnumerable() || desc.enumerable() == current.enumerable()) &&
+ (!desc.hasConfigurable() || desc.configurable() == current.configurable()))
+ {
+ if (!desc.hasValue())
+ return true;
+
+ bool same = false;
+ if (!SameValue(cx, desc.value(), current.value(), &same))
+ return false;
+
+ if (same)
+ return true;
+ }
+
+ // Step 5.
+ if (!current.configurable()) {
+ // Step 5a.
+ if (desc.hasConfigurable() && desc.configurable()) {
+ static const char* DETAILS_CANT_REPORT_NC_AS_C =
+ "proxy can't report an existing non-configurable property as configurable";
+ *errorDetails = DETAILS_CANT_REPORT_NC_AS_C;
+ return true;
+ }
+
+ // Step 5b.
+ if (desc.hasEnumerable() && desc.enumerable() != current.enumerable()) {
+ static const char* DETAILS_ENUM_DIFFERENT =
+ "proxy can't report a different 'enumerable' from target when target is not configurable";
+ *errorDetails = DETAILS_ENUM_DIFFERENT;
+ return true;
+ }
+ }
+
+ // Step 6.
+ if (desc.isGenericDescriptor())
+ return true;
+
+ // Step 7.
+ if (current.isDataDescriptor() != desc.isDataDescriptor()) {
+ // Steps 7a, 11. As |O| is always undefined, steps 2b-c fall away.
+ if (!current.configurable()) {
+ static const char* DETAILS_CURRENT_NC_DIFF_TYPE =
+ "proxy can't report a different descriptor type when target is not configurable";
+ *errorDetails = DETAILS_CURRENT_NC_DIFF_TYPE;
+ }
+ return true;
+ }
+
+ // Step 8.
+ if (current.isDataDescriptor()) {
+ MOZ_ASSERT(desc.isDataDescriptor()); // by step 7
+ if (!current.configurable() && !current.writable()) {
+ if (desc.hasWritable() && desc.writable()) {
+ static const char* DETAILS_CANT_REPORT_NW_AS_W =
+ "proxy can't report a non-configurable, non-writable property as writable";
+ *errorDetails = DETAILS_CANT_REPORT_NW_AS_W;
+ return true;
+ }
+
+ if (desc.hasValue()) {
+ bool same;
+ if (!SameValue(cx, desc.value(), current.value(), &same))
+ return false;
+ if (!same) {
+ static const char* DETAILS_DIFFERENT_VALUE =
+ "proxy must report the same value for the non-writable, non-configurable property";
+ *errorDetails = DETAILS_DIFFERENT_VALUE;
+ return true;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ // Step 9.
+ MOZ_ASSERT(current.isAccessorDescriptor()); // by step 8
+ MOZ_ASSERT(desc.isAccessorDescriptor()); // by step 7
+
+ if (current.configurable())
+ return true;
+ if (desc.hasSetterObject() && (desc.setter() != current.setter())) {
+ static const char* DETAILS_SETTERS_DIFFERENT =
+ "proxy can't report different setters for a currently non-configurable property";
+ *errorDetails = DETAILS_SETTERS_DIFFERENT;
+ }
+ else if (desc.hasGetterObject() && (desc.getter() != current.getter())) {
+ static const char* DETAILS_GETTERS_DIFFERENT =
+ "proxy can't report different getters for a currently non-configurable property";
+ *errorDetails = DETAILS_GETTERS_DIFFERENT;
+ }
+ return true;
+}
+
+// Get the [[ProxyHandler]] of a scripted proxy.
+/* static */ JSObject*
+ScriptedProxyHandler::handlerObject(const JSObject* proxy)
+{
+ MOZ_ASSERT(proxy->as<ProxyObject>().handler() == &ScriptedProxyHandler::singleton);
+ return proxy->as<ProxyObject>().reservedSlot(ScriptedProxyHandler::HANDLER_EXTRA).toObjectOrNull();
+}
+
+// ES8 rev 0c1bd3004329336774cbc90de727cd0cf5f11e93 7.3.9 GetMethod,
+// reimplemented for proxy handler trap-getting to produce better error
+// messages.
+static bool
+GetProxyTrap(JSContext* cx, HandleObject handler, HandlePropertyName name, MutableHandleValue func)
+{
+ // Steps 2, 5.
+ if (!GetProperty(cx, handler, handler, name, func))
+ return false;
+
+ // Step 3.
+ if (func.isUndefined())
+ return true;
+
+ if (func.isNull()) {
+ func.setUndefined();
+ return true;
+ }
+
+ // Step 4.
+ if (!IsCallable(func)) {
+ JSAutoByteString bytes(cx, name);
+ if (!bytes)
+ return false;
+
+ JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr, JSMSG_BAD_TRAP, bytes.ptr());
+ return false;
+ }
+
+ return true;
+}
+
+// ES8 rev 0c1bd3004329336774cbc90de727cd0cf5f11e93 9.5.1 Proxy.[[GetPrototypeOf]].
+bool
+ScriptedProxyHandler::getPrototype(JSContext* cx, HandleObject proxy,
+ MutableHandleObject protop) const
+{
+ // Steps 1-3.
+ RootedObject handler(cx, ScriptedProxyHandler::handlerObject(proxy));
+ if (!handler) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_PROXY_REVOKED);
+ return false;
+ }
+
+ // Step 4.
+ RootedObject target(cx, proxy->as<ProxyObject>().target());
+ MOZ_ASSERT(target);
+
+ // Step 5.
+ RootedValue trap(cx);
+ if (!GetProxyTrap(cx, handler, cx->names().getPrototypeOf, &trap))
+ return false;
+
+ // Step 6.
+ if (trap.isUndefined())
+ return GetPrototype(cx, target, protop);
+
+ // Step 7.
+ RootedValue handlerProto(cx);
+ {
+ FixedInvokeArgs<1> args(cx);
+
+ args[0].setObject(*target);
+
+ handlerProto.setObject(*handler);
+
+ if (!js::Call(cx, trap, handlerProto, args, &handlerProto))
+ return false;
+ }
+
+ // Step 8.
+ if (!handlerProto.isObjectOrNull()) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
+ JSMSG_BAD_GETPROTOTYPEOF_TRAP_RETURN);
+ return false;
+ }
+
+ // Step 9.
+ bool extensibleTarget;
+ if (!IsExtensible(cx, target, &extensibleTarget))
+ return false;
+
+ // Step 10.
+ if (extensibleTarget) {
+ protop.set(handlerProto.toObjectOrNull());
+ return true;
+ }
+
+ // Step 11.
+ RootedObject targetProto(cx);
+ if (!GetPrototype(cx, target, &targetProto))
+ return false;
+
+ // Step 12.
+ if (handlerProto.toObjectOrNull() != targetProto) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
+ JSMSG_INCONSISTENT_GETPROTOTYPEOF_TRAP);
+ return false;
+ }
+
+ // Step 13.
+ protop.set(handlerProto.toObjectOrNull());
+ return true;
+}
+
+// ES8 rev 0c1bd3004329336774cbc90de727cd0cf5f11e93 9.5.2 Proxy.[[SetPrototypeOf]].
+bool
+ScriptedProxyHandler::setPrototype(JSContext* cx, HandleObject proxy, HandleObject proto,
+ ObjectOpResult& result) const
+{
+ // Steps 1-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().setPrototypeOf, &trap))
+ return false;
+
+ // Step 7.
+ if (trap.isUndefined())
+ return SetPrototype(cx, target, proto, result);
+
+ // Step 8.
+ bool booleanTrapResult;
+ {
+ FixedInvokeArgs<2> args(cx);
+
+ args[0].setObject(*target);
+ args[1].setObjectOrNull(proto);
+
+ RootedValue hval(cx, ObjectValue(*handler));
+ if (!js::Call(cx, trap, hval, args, &hval))
+ return false;
+
+ booleanTrapResult = ToBoolean(hval);
+ }
+
+ // Step 9.
+ if (!booleanTrapResult)
+ return result.fail(JSMSG_PROXY_SETPROTOTYPEOF_RETURNED_FALSE);
+
+ // Step 10.
+ bool extensibleTarget;
+ if (!IsExtensible(cx, target, &extensibleTarget))
+ return false;
+
+ // Step 11.
+ if (extensibleTarget)
+ return result.succeed();
+
+ // Step 12.
+ RootedObject targetProto(cx);
+ if (!GetPrototype(cx, target, &targetProto))
+ return false;
+
+ // Step 13.
+ if (proto != targetProto) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
+ JSMSG_INCONSISTENT_SETPROTOTYPEOF_TRAP);
+ return false;
+ }
+
+ // Step 14.
+ return result.succeed();
+}
+
+bool
+ScriptedProxyHandler::getPrototypeIfOrdinary(JSContext* cx, HandleObject proxy, bool* isOrdinary,
+ MutableHandleObject protop) const
+{
+ *isOrdinary = false;
+ return true;
+}
+
+// Not yet part of ES6, but hopefully to be standards-tracked -- and needed to
+// handle revoked proxies in any event.
+bool
+ScriptedProxyHandler::setImmutablePrototype(JSContext* cx, HandleObject proxy,
+ bool* succeeded) const
+{
+ RootedObject target(cx, proxy->as<ProxyObject>().target());
+ if (!target) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_PROXY_REVOKED);
+ return false;
+ }
+
+ return SetImmutablePrototype(cx, target, succeeded);
+}
+
+// ES8 rev 0c1bd3004329336774cbc90de727cd0cf5f11e93 9.5.4 Proxy.[[PreventExtensions]]()
+bool
+ScriptedProxyHandler::preventExtensions(JSContext* cx, HandleObject proxy,
+ ObjectOpResult& result) const
+{
+ // Steps 1-3.
+ RootedObject handler(cx, ScriptedProxyHandler::handlerObject(proxy));
+ if (!handler) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_PROXY_REVOKED);
+ return false;
+ }
+
+ // Step 4.
+ RootedObject target(cx, proxy->as<ProxyObject>().target());
+ MOZ_ASSERT(target);
+
+ // Step 5.
+ RootedValue trap(cx);
+ if (!GetProxyTrap(cx, handler, cx->names().preventExtensions, &trap))
+ return false;
+
+ // Step 6.
+ if (trap.isUndefined())
+ return PreventExtensions(cx, target, result);
+
+ // Step 7.
+ bool booleanTrapResult;
+ {
+ RootedValue arg(cx, ObjectValue(*target));
+ RootedValue trapResult(cx);
+ if (!Call(cx, trap, handler, arg, &trapResult))
+ return false;
+
+ booleanTrapResult = ToBoolean(trapResult);
+ }
+
+ // Step 8.
+ if (booleanTrapResult) {
+ // Step 8a.
+ bool targetIsExtensible;
+ if (!IsExtensible(cx, target, &targetIsExtensible))
+ return false;
+
+ if (targetIsExtensible) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
+ JSMSG_CANT_REPORT_AS_NON_EXTENSIBLE);
+ return false;
+ }
+
+ // Step 9.
+ return result.succeed();
+ }
+
+ // Also step 9.
+ return result.fail(JSMSG_PROXY_PREVENTEXTENSIONS_RETURNED_FALSE);
+}
+
+// ES8 rev 0c1bd3004329336774cbc90de727cd0cf5f11e93 9.5.3 Proxy.[[IsExtensible]]()
+bool
+ScriptedProxyHandler::isExtensible(JSContext* cx, HandleObject proxy, bool* extensible) const
+{
+ // Steps 1-3.
+ RootedObject handler(cx, ScriptedProxyHandler::handlerObject(proxy));
+ if (!handler) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_PROXY_REVOKED);
+ return false;
+ }
+
+ // Step 4.
+ RootedObject target(cx, proxy->as<ProxyObject>().target());
+ MOZ_ASSERT(target);
+
+ // Step 5.
+ RootedValue trap(cx);
+ if (!GetProxyTrap(cx, handler, cx->names().isExtensible, &trap))
+ return false;
+
+ // Step 6.
+ if (trap.isUndefined())
+ return IsExtensible(cx, target, extensible);
+
+ // Step 7.
+ bool booleanTrapResult;
+ {
+ RootedValue arg(cx, ObjectValue(*target));
+ RootedValue trapResult(cx);
+ if (!Call(cx, trap, handler, arg, &trapResult))
+ return false;
+
+ booleanTrapResult = ToBoolean(trapResult);
+ }
+
+ // Steps 8.
+ bool targetResult;
+ if (!IsExtensible(cx, target, &targetResult))
+ return false;
+
+ // Step 9.
+ if (targetResult != booleanTrapResult) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_PROXY_EXTENSIBILITY);
+ return false;
+ }
+
+ // Step 10.
+ *extensible = booleanTrapResult;
+ return true;
+}
+
+// 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;
+}
+
+// ES8 rev 0c1bd3004329336774cbc90de727cd0cf5f11e93 9.5.6 Proxy.[[DefineOwnProperty]](P, Desc)
+bool
+ScriptedProxyHandler::defineProperty(JSContext* cx, HandleObject proxy, HandleId id,
+ Handle<PropertyDescriptor> desc, ObjectOpResult& result) 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().defineProperty, &trap))
+ return false;
+
+ // Step 7.
+ if (trap.isUndefined())
+ return DefineProperty(cx, target, id, desc, result);
+
+ // Step 8.
+ RootedValue descObj(cx);
+ if (!FromPropertyDescriptorToObject(cx, desc, &descObj))
+ return false;
+
+ // Step 9.
+ RootedValue propKey(cx);
+ if (!IdToStringOrSymbol(cx, id, &propKey))
+ return false;
+
+ RootedValue trapResult(cx);
+ {
+ FixedInvokeArgs<3> args(cx);
+
+ args[0].setObject(*target);
+ args[1].set(propKey);
+ args[2].set(descObj);
+
+ RootedValue thisv(cx, ObjectValue(*handler));
+ if (!Call(cx, trap, thisv, args, &trapResult))
+ return false;
+ }
+
+ // Step 10.
+ if (!ToBoolean(trapResult))
+ return result.fail(JSMSG_PROXY_DEFINE_RETURNED_FALSE);
+
+ // Step 11.
+ Rooted<PropertyDescriptor> targetDesc(cx);
+ if (!GetOwnPropertyDescriptor(cx, target, id, &targetDesc))
+ return false;
+
+ // Step 12.
+ bool extensibleTarget;
+ if (!IsExtensible(cx, target, &extensibleTarget))
+ return false;
+
+ // Steps 13-14.
+ bool settingConfigFalse = desc.hasConfigurable() && !desc.configurable();
+
+ // Steps 15-16.
+ if (!targetDesc.object()) {
+ // Step 15a.
+ if (!extensibleTarget)
+ return js::Throw(cx, id, JSMSG_CANT_DEFINE_NEW);
+
+ // Step 15b.
+ if (settingConfigFalse)
+ return js::Throw(cx, id, JSMSG_CANT_DEFINE_NE_AS_NC);
+ } else {
+ // Step 16a.
+ const char* errorDetails = nullptr;
+ if (!IsCompatiblePropertyDescriptor(cx, extensibleTarget, desc, targetDesc,
+ &errorDetails))
+ return false;
+
+ if (errorDetails)
+ return js::Throw(cx, id, JSMSG_CANT_DEFINE_INVALID, errorDetails);
+
+ // Step 16b.
+ if (settingConfigFalse && targetDesc.configurable()) {
+ static const char* DETAILS_CANT_REPORT_C_AS_NC =
+ "proxy can't define an existing configurable property as non-configurable";
+ return js::Throw(cx, id, JSMSG_CANT_DEFINE_INVALID, DETAILS_CANT_REPORT_C_AS_NC);
+ }
+ }
+
+ // Step 17.
+ return result.succeed();
+}
+
+// ES8 rev 0c1bd3004329336774cbc90de727cd0cf5f11e93
+// 7.3.17 CreateListFromArrayLike with elementTypes fixed to symbol/string.
+static bool
+CreateFilteredListFromArrayLike(JSContext* cx, HandleValue v, AutoIdVector& props)
+{
+ // Step 2.
+ RootedObject obj(cx, NonNullObjectWithName(cx, "return value of the ownKeys trap", v));
+ if (!obj)
+ return false;
+
+ // Step 3.
+ uint32_t len;
+ if (!GetLengthProperty(cx, obj, &len))
+ return false;
+
+ // Steps 4-6.
+ RootedValue next(cx);
+ RootedId id(cx);
+ uint32_t index = 0;
+ while (index < len) {
+ // Steps 6a-b.
+ if (!GetElement(cx, obj, obj, index, &next))
+ return false;
+
+ // Step 6c.
+ if (!next.isString() && !next.isSymbol()) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_OWNKEYS_STR_SYM);
+ return false;
+ }
+
+ if (!ValueToId<CanGC>(cx, next, &id))
+ return false;
+
+ // Step 6d.
+ if (!props.append(id))
+ return false;
+
+ // Step 6e.
+ index++;
+ }
+
+ // Step 7.
+ return true;
+}
+
+
+// ES2018 draft rev aab1ea3bd4d03c85d6f4a91503b4169346ab7271
+// 9.5.11 Proxy.[[OwnPropertyKeys]]()
+bool
+ScriptedProxyHandler::ownPropertyKeys(JSContext* cx, HandleObject proxy, AutoIdVector& props) const
+{
+ // Steps 1-3.
+ RootedObject handler(cx, ScriptedProxyHandler::handlerObject(proxy));
+ if (!handler) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_PROXY_REVOKED);
+ return false;
+ }
+
+ // Step 4.
+ RootedObject target(cx, proxy->as<ProxyObject>().target());
+ MOZ_ASSERT(target);
+
+ // Step 5.
+ RootedValue trap(cx);
+ if (!GetProxyTrap(cx, handler, cx->names().ownKeys, &trap))
+ return false;
+
+ // Step 6.
+ if (trap.isUndefined())
+ return GetPropertyKeys(cx, target, JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS, &props);
+
+ // Step 7.
+ RootedValue trapResultArray(cx);
+ RootedValue targetVal(cx, ObjectValue(*target));
+ if (!Call(cx, trap, handler, targetVal, &trapResultArray))
+ return false;
+
+ // Step 8.
+ AutoIdVector trapResult(cx);
+ if (!CreateFilteredListFromArrayLike(cx, trapResultArray, trapResult))
+ return false;
+
+ // Steps 9, 18.
+ Rooted<GCHashSet<jsid>> uncheckedResultKeys(cx, GCHashSet<jsid>(cx));
+ if (!uncheckedResultKeys.init(trapResult.length()))
+ return false;
+
+ for (size_t i = 0, len = trapResult.length(); i < len; i++) {
+ MOZ_ASSERT(!JSID_IS_VOID(trapResult[i]));
+
+ auto ptr = uncheckedResultKeys.lookupForAdd(trapResult[i]);
+ if (ptr)
+ return js::Throw(cx, trapResult[i], JSMSG_OWNKEYS_DUPLICATE);
+
+ if (!uncheckedResultKeys.add(ptr, trapResult[i]))
+ return false;
+ }
+
+ // Step 10.
+ bool extensibleTarget;
+ if (!IsExtensible(cx, target, &extensibleTarget))
+ return false;
+
+ // Steps 11-13.
+ AutoIdVector targetKeys(cx);
+ if (!GetPropertyKeys(cx, target, JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS, &targetKeys))
+ return false;
+
+ // Steps 14-15.
+ AutoIdVector targetConfigurableKeys(cx);
+ AutoIdVector targetNonconfigurableKeys(cx);
+
+ // Step 16.
+ Rooted<PropertyDescriptor> desc(cx);
+ for (size_t i = 0; i < targetKeys.length(); ++i) {
+ // Step 16.a.
+ if (!GetOwnPropertyDescriptor(cx, target, targetKeys[i], &desc))
+ return false;
+
+ // Steps 16.b-c.
+ if (desc.object() && !desc.configurable()) {
+ if (!targetNonconfigurableKeys.append(targetKeys[i]))
+ return false;
+ } else {
+ if (!targetConfigurableKeys.append(targetKeys[i]))
+ return false;
+ }
+ }
+
+ // Step 17.
+ if (extensibleTarget && targetNonconfigurableKeys.empty())
+ return props.appendAll(trapResult);
+
+ // Step 19.
+ for (size_t i = 0; i < targetNonconfigurableKeys.length(); ++i) {
+ MOZ_ASSERT(!JSID_IS_VOID(targetNonconfigurableKeys[i]));
+
+ auto ptr = uncheckedResultKeys.lookup(targetNonconfigurableKeys[i]);
+
+ // Step 19.a.
+ if (!ptr)
+ return js::Throw(cx, targetNonconfigurableKeys[i], JSMSG_CANT_SKIP_NC);
+
+ // Step 19.b.
+ uncheckedResultKeys.remove(ptr);
+ }
+
+ // Step 20.
+ if (extensibleTarget)
+ return props.appendAll(trapResult);
+
+ // Step 21.
+ for (size_t i = 0; i < targetConfigurableKeys.length(); ++i) {
+ MOZ_ASSERT(!JSID_IS_VOID(targetConfigurableKeys[i]));
+
+ auto ptr = uncheckedResultKeys.lookup(targetConfigurableKeys[i]);
+
+ // Step 21.a.
+ if (!ptr)
+ return js::Throw(cx, targetConfigurableKeys[i], JSMSG_CANT_REPORT_E_AS_NE);
+
+ // Step 21.b.
+ uncheckedResultKeys.remove(ptr);
+ }
+
+ // Step 22.
+ if (!uncheckedResultKeys.empty())
+ return js::Throw(cx, uncheckedResultKeys.all().front(), JSMSG_CANT_REPORT_NEW);
+
+ // Step 23.
+ return props.appendAll(trapResult);
+}
+
+// ES8 rev 0c1bd3004329336774cbc90de727cd0cf5f11e93 9.5.10 Proxy.[[Delete]](P)
+bool
+ScriptedProxyHandler::delete_(JSContext* cx, HandleObject proxy, HandleId id,
+ ObjectOpResult& result) 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().deleteProperty, &trap))
+ return false;
+
+ // Step 7.
+ if (trap.isUndefined())
+ return DeleteProperty(cx, target, id, result);
+
+ // Step 8.
+ bool booleanTrapResult;
+ {
+ RootedValue value(cx);
+ if (!IdToStringOrSymbol(cx, id, &value))
+ return false;
+
+ RootedValue targetVal(cx, ObjectValue(*target));
+ RootedValue trapResult(cx);
+ if (!Call(cx, trap, handler, targetVal, value, &trapResult))
+ return false;
+
+ booleanTrapResult = ToBoolean(trapResult);
+ }
+
+ // Step 9.
+ if (!booleanTrapResult)
+ return result.fail(JSMSG_PROXY_DELETE_RETURNED_FALSE);
+
+ // Step 10.
+ Rooted<PropertyDescriptor> desc(cx);
+ if (!GetOwnPropertyDescriptor(cx, target, id, &desc))
+ return false;
+
+ // Step 12.
+ if (desc.object() && !desc.configurable()) {
+ RootedValue v(cx, IdToValue(id));
+ ReportValueError(cx, JSMSG_CANT_DELETE, JSDVG_IGNORE_STACK, v, nullptr);
+ return false;
+ }
+
+ // Steps 11,13.
+ return result.succeed();
+}
+
+// ES8 rev 0c1bd3004329336774cbc90de727cd0cf5f11e93 9.5.7 Proxy.[[HasProperty]](P)
+bool
+ScriptedProxyHandler::has(JSContext* cx, HandleObject proxy, HandleId id, bool* bp) 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().has, &trap))
+ return false;
+
+ // Step 7.
+ if (trap.isUndefined())
+ return HasProperty(cx, target, id, bp);
+
+ // Step 8.
+ RootedValue value(cx);
+ if (!IdToStringOrSymbol(cx, id, &value))
+ return false;
+
+ RootedValue trapResult(cx);
+ RootedValue targetVal(cx, ObjectValue(*target));
+ if (!Call(cx, trap, handler, targetVal, value, &trapResult))
+ return false;
+
+ bool booleanTrapResult = ToBoolean(trapResult);
+
+ // Step 9.
+ if (!booleanTrapResult) {
+ // Step 9a.
+ Rooted<PropertyDescriptor> desc(cx);
+ if (!GetOwnPropertyDescriptor(cx, target, id, &desc))
+ return false;
+
+ // Step 9b.
+ if (desc.object()) {
+ // Step 9b(i).
+ if (!desc.configurable())
+ return js::Throw(cx, id, JSMSG_CANT_REPORT_NC_AS_NE);
+
+ // Step 9b(ii).
+ bool extensible;
+ if (!IsExtensible(cx, target, &extensible))
+ return false;
+
+ // Step 9b(iii).
+ if (!extensible)
+ return js::Throw(cx, id, JSMSG_CANT_REPORT_E_AS_NE);
+ }
+ }
+
+ // Step 10.
+ *bp = booleanTrapResult;
+ return true;
+}
+
+// ES8 rev 0c1bd3004329336774cbc90de727cd0cf5f11e93 9.5.8 Proxy.[[GetP]](P, Receiver)
+bool
+ScriptedProxyHandler::get(JSContext* cx, HandleObject proxy, HandleValue receiver, HandleId id,
+ MutableHandleValue vp) 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);
+
+ // Steps 6.
+ RootedValue trap(cx);
+ if (!GetProxyTrap(cx, handler, cx->names().get, &trap))
+ return false;
+
+ // Step 7.
+ if (trap.isUndefined())
+ return GetProperty(cx, target, receiver, id, vp);
+
+ // Step 8.
+ RootedValue value(cx);
+ if (!IdToStringOrSymbol(cx, id, &value))
+ return false;
+
+ RootedValue trapResult(cx);
+ {
+ FixedInvokeArgs<3> args(cx);
+
+ args[0].setObject(*target);
+ args[1].set(value);
+ args[2].set(receiver);
+
+ RootedValue thisv(cx, ObjectValue(*handler));
+ if (!Call(cx, trap, thisv, args, &trapResult))
+ return false;
+ }
+
+ // Step 9.
+ Rooted<PropertyDescriptor> desc(cx);
+ if (!GetOwnPropertyDescriptor(cx, target, id, &desc))
+ return false;
+
+ // Step 10.
+ if (desc.object()) {
+ // Step 10a.
+ if (desc.isDataDescriptor() && !desc.configurable() && !desc.writable()) {
+ bool same;
+ if (!SameValue(cx, trapResult, desc.value(), &same))
+ return false;
+ if (!same)
+ return js::Throw(cx, id, JSMSG_MUST_REPORT_SAME_VALUE);
+ }
+
+ // Step 10b.
+ if (desc.isAccessorDescriptor() &&
+ !desc.configurable() &&
+ (desc.getterObject() == nullptr) &&
+ !trapResult.isUndefined())
+ {
+ return js::Throw(cx, id, JSMSG_MUST_REPORT_UNDEFINED);
+ }
+ }
+
+ // Step 11.
+ vp.set(trapResult);
+ return true;
+}
+
+// ES8 rev 0c1bd3004329336774cbc90de727cd0cf5f11e93 9.5.9 Proxy.[[Set]](P, V, Receiver)
+bool
+ScriptedProxyHandler::set(JSContext* cx, HandleObject proxy, HandleId id, HandleValue v,
+ HandleValue receiver, ObjectOpResult& result) 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().set, &trap))
+ return false;
+
+ // Step 7.
+ if (trap.isUndefined())
+ return SetProperty(cx, target, id, v, receiver, result);
+
+ // Step 8.
+ RootedValue value(cx);
+ if (!IdToStringOrSymbol(cx, id, &value))
+ return false;
+
+ RootedValue trapResult(cx);
+ {
+ FixedInvokeArgs<4> args(cx);
+
+ args[0].setObject(*target);
+ args[1].set(value);
+ args[2].set(v);
+ args[3].set(receiver);
+
+ RootedValue thisv(cx, ObjectValue(*handler));
+ if (!Call(cx, trap, thisv, args, &trapResult))
+ return false;
+ }
+
+ // Step 9.
+ if (!ToBoolean(trapResult))
+ return result.fail(JSMSG_PROXY_SET_RETURNED_FALSE);
+
+ // Step 10.
+ Rooted<PropertyDescriptor> desc(cx);
+ if (!GetOwnPropertyDescriptor(cx, target, id, &desc))
+ return false;
+
+ // Step 11.
+ if (desc.object()) {
+ // Step 11a.
+ if (desc.isDataDescriptor() && !desc.configurable() && !desc.writable()) {
+ bool same;
+ if (!SameValue(cx, v, desc.value(), &same))
+ return false;
+ if (!same)
+ return js::Throw(cx, id, JSMSG_CANT_SET_NW_NC);
+ }
+
+ // Step 11b.
+ if (desc.isAccessorDescriptor() && !desc.configurable() && desc.setterObject() == nullptr)
+ return js::Throw(cx, id, JSMSG_CANT_SET_WO_SETTER);
+ }
+
+ // Step 12.
+ return result.succeed();
+}
+
+// ES7 0c1bd3004329336774cbc90de727cd0cf5f11e93 9.5.13 Proxy.[[Call]]
+bool
+ScriptedProxyHandler::call(JSContext* cx, HandleObject proxy, const CallArgs& args) const
+{
+ // Steps 1-3.
+ RootedObject handler(cx, ScriptedProxyHandler::handlerObject(proxy));
+ if (!handler) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_PROXY_REVOKED);
+ return false;
+ }
+
+ // Step 4.
+ RootedObject target(cx, proxy->as<ProxyObject>().target());
+ MOZ_ASSERT(target);
+ MOZ_ASSERT(target->isCallable());
+
+ // Step 5.
+ RootedValue trap(cx);
+ if (!GetProxyTrap(cx, handler, cx->names().apply, &trap))
+ return false;
+
+ // Step 6.
+ if (trap.isUndefined()) {
+ InvokeArgs iargs(cx);
+ if (!FillArgumentsFromArraylike(cx, iargs, args))
+ return false;
+
+ RootedValue fval(cx, ObjectValue(*target));
+ return js::Call(cx, fval, args.thisv(), iargs, args.rval());
+ }
+
+ // Step 7.
+ RootedObject argArray(cx, NewDenseCopiedArray(cx, args.length(), args.array()));
+ if (!argArray)
+ return false;
+
+ // Step 8.
+ FixedInvokeArgs<3> iargs(cx);
+
+ iargs[0].setObject(*target);
+ iargs[1].set(args.thisv());
+ iargs[2].setObject(*argArray);
+
+ RootedValue thisv(cx, ObjectValue(*handler));
+ return js::Call(cx, trap, thisv, iargs, args.rval());
+}
+
+// ES7 0c1bd3004329336774cbc90de727cd0cf5f11e93 9.5.14 Proxy.[[Construct]]
+bool
+ScriptedProxyHandler::construct(JSContext* cx, HandleObject proxy, const CallArgs& args) const
+{
+ // Steps 1-3.
+ RootedObject handler(cx, ScriptedProxyHandler::handlerObject(proxy));
+ if (!handler) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_PROXY_REVOKED);
+ return false;
+ }
+
+ // Step 4.
+ RootedObject target(cx, proxy->as<ProxyObject>().target());
+ MOZ_ASSERT(target);
+ MOZ_ASSERT(target->isConstructor());
+
+ // Step 5.
+ RootedValue trap(cx);
+ if (!GetProxyTrap(cx, handler, cx->names().construct, &trap))
+ return false;
+
+ // Step 6.
+ if (trap.isUndefined()) {
+ ConstructArgs cargs(cx);
+ if (!FillArgumentsFromArraylike(cx, cargs, args))
+ return false;
+
+ RootedValue targetv(cx, ObjectValue(*target));
+ RootedObject obj(cx);
+ if (!Construct(cx, targetv, cargs, args.newTarget(), &obj))
+ return false;
+
+ args.rval().setObject(*obj);
+ return true;
+ }
+
+ // Step 7.
+ RootedObject argArray(cx, NewDenseCopiedArray(cx, args.length(), args.array()));
+ if (!argArray)
+ return false;
+
+ // Steps 8, 10.
+ {
+ FixedInvokeArgs<3> iargs(cx);
+
+ iargs[0].setObject(*target);
+ iargs[1].setObject(*argArray);
+ iargs[2].set(args.newTarget());
+
+ RootedValue thisv(cx, ObjectValue(*handler));
+ if (!Call(cx, trap, thisv, iargs, args.rval()))
+ return false;
+ }
+
+ // Step 9.
+ if (!args.rval().isObject()) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_PROXY_CONSTRUCT_OBJECT);
+ return false;
+ }
+
+ return true;
+}
+
+bool
+ScriptedProxyHandler::nativeCall(JSContext* cx, IsAcceptableThis test, NativeImpl impl,
+ const CallArgs& args) const
+{
+ ReportIncompatible(cx, args);
+ return false;
+}
+
+bool
+ScriptedProxyHandler::hasInstance(JSContext* cx, HandleObject proxy, MutableHandleValue v,
+ bool* bp) const
+{
+ return InstanceOfOperator(cx, proxy, v, bp);
+}
+
+bool
+ScriptedProxyHandler::getBuiltinClass(JSContext* cx, HandleObject proxy,
+ ESClass* cls) const
+{
+ *cls = ESClass::Other;
+ return true;
+}
+
+bool
+ScriptedProxyHandler::isArray(JSContext* cx, HandleObject proxy, IsArrayAnswer* answer) const
+{
+ RootedObject target(cx, proxy->as<ProxyObject>().target());
+ if (target)
+ return JS::IsArray(cx, target, answer);
+
+ *answer = IsArrayAnswer::RevokedProxy;
+ return true;
+}
+
+const char*
+ScriptedProxyHandler::className(JSContext* cx, HandleObject proxy) const
+{
+ // Right now the caller is not prepared to handle failures.
+ return BaseProxyHandler::className(cx, proxy);
+}
+
+JSString*
+ScriptedProxyHandler::fun_toString(JSContext* cx, HandleObject proxy, bool isToSource) const
+{
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_INCOMPATIBLE_PROTO,
+ js_Function_str, js_toString_str, "object");
+ return nullptr;
+}
+
+RegExpShared*
+ScriptedProxyHandler::regexp_toShared(JSContext* cx, HandleObject proxy) const
+{
+ MOZ_CRASH("Should not end up in ScriptedProxyHandler::regexp_toShared");
+}
+
+bool
+ScriptedProxyHandler::boxedValue_unbox(JSContext* cx, HandleObject proxy,
+ MutableHandleValue vp) const
+{
+ MOZ_CRASH("Should not end up in ScriptedProxyHandler::boxedValue_unbox");
+ return false;
+}
+
+bool
+ScriptedProxyHandler::isCallable(JSObject* obj) const
+{
+ MOZ_ASSERT(obj->as<ProxyObject>().handler() == &ScriptedProxyHandler::singleton);
+ uint32_t callConstruct = obj->as<ProxyObject>().reservedSlot(IS_CALLCONSTRUCT_EXTRA).toPrivateUint32();
+ return !!(callConstruct & IS_CALLABLE);
+}
+
+bool
+ScriptedProxyHandler::isConstructor(JSObject* obj) const
+{
+ MOZ_ASSERT(obj->as<ProxyObject>().handler() == &ScriptedProxyHandler::singleton);
+ uint32_t callConstruct = obj->as<ProxyObject>().reservedSlot(IS_CALLCONSTRUCT_EXTRA).toPrivateUint32();
+ return !!(callConstruct & IS_CONSTRUCTOR);
+}
+
+const char ScriptedProxyHandler::family = 0;
+const ScriptedProxyHandler ScriptedProxyHandler::singleton;
+
+bool
+IsRevokedScriptedProxy(JSObject* obj)
+{
+ obj = CheckedUnwrap(obj);
+ return obj && IsScriptedProxy(obj) && !obj->as<ProxyObject>().target();
+}
+
+// ES8 rev 0c1bd3004329336774cbc90de727cd0cf5f11e93 9.5.14 ProxyCreate.
+static bool
+ProxyCreate(JSContext* cx, CallArgs& args, const char* callerName)
+{
+ if (args.length() < 2) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_MORE_ARGS_NEEDED,
+ callerName, "1", "s");
+ return false;
+ }
+
+ // Step 1.
+ RootedObject target(cx, NonNullObjectArg(cx, "`target`", callerName, args[0]));
+ if (!target)
+ return false;
+
+ // Step 2.
+ if (IsRevokedScriptedProxy(target)) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_PROXY_ARG_REVOKED, "1");
+ return false;
+ }
+
+ // Step 3.
+ RootedObject handler(cx, NonNullObjectArg(cx, "`handler`", callerName, args[1]));
+ if (!handler)
+ return false;
+
+ // Step 4.
+ if (IsRevokedScriptedProxy(handler)) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_PROXY_ARG_REVOKED, "2");
+ return false;
+ }
+
+ // Steps 5-6, 8.
+ RootedValue priv(cx, ObjectValue(*target));
+ JSObject* proxy_ =
+ NewProxyObject(cx, &ScriptedProxyHandler::singleton, priv, TaggedProto::LazyProto);
+ if (!proxy_)
+ return false;
+
+ // Step 9 (reordered).
+ Rooted<ProxyObject*> proxy(cx, &proxy_->as<ProxyObject>());
+ proxy->setReservedSlot(ScriptedProxyHandler::HANDLER_EXTRA, ObjectValue(*handler));
+
+ // Step 7.
+ uint32_t callable = target->isCallable() ? ScriptedProxyHandler::IS_CALLABLE : 0;
+ uint32_t constructor = target->isConstructor() ? ScriptedProxyHandler::IS_CONSTRUCTOR : 0;
+ proxy->setReservedSlot(ScriptedProxyHandler::IS_CALLCONSTRUCT_EXTRA,
+ PrivateUint32Value(callable | constructor));
+
+ // Step 10.
+ args.rval().setObject(*proxy);
+ return true;
+}
+
+bool
+js::proxy(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+
+ if (!ThrowIfNotConstructing(cx, args, "Proxy"))
+ return false;
+
+ return ProxyCreate(cx, args, "Proxy");
+}
+
+static bool
+RevokeProxy(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+
+ RootedFunction func(cx, &args.callee().as<JSFunction>());
+ RootedObject p(cx, func->getExtendedSlot(ScriptedProxyHandler::REVOKE_SLOT).toObjectOrNull());
+
+ if (p) {
+ func->setExtendedSlot(ScriptedProxyHandler::REVOKE_SLOT, NullValue());
+
+ MOZ_ASSERT(p->is<ProxyObject>());
+
+ p->as<ProxyObject>().setSameCompartmentPrivate(NullValue());
+ p->as<ProxyObject>().setReservedSlot(ScriptedProxyHandler::HANDLER_EXTRA, NullValue());
+ }
+
+ args.rval().setUndefined();
+ return true;
+}
+
+bool
+js::proxy_revocable(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+
+ if (!ProxyCreate(cx, args, "Proxy.revocable"))
+ return false;
+
+ RootedValue proxyVal(cx, args.rval());
+ MOZ_ASSERT(proxyVal.toObject().is<ProxyObject>());
+
+ RootedObject revoker(cx, NewFunctionByIdWithReserved(cx, RevokeProxy, 0, 0,
+ NameToId(cx->names().revoke)));
+ if (!revoker)
+ return false;
+
+ revoker->as<JSFunction>().initExtendedSlot(ScriptedProxyHandler::REVOKE_SLOT, proxyVal);
+
+ RootedPlainObject result(cx, NewBuiltinClassInstance<PlainObject>(cx));
+ if (!result)
+ return false;
+
+ RootedValue revokeVal(cx, ObjectValue(*revoker));
+ if (!DefineDataProperty(cx, result, cx->names().proxy, proxyVal) ||
+ !DefineDataProperty(cx, result, cx->names().revoke, revokeVal))
+ {
+ return false;
+ }
+
+ args.rval().setObject(*result);
+ return true;
+}
diff --git a/src/third_party/mozjs-60/extract/js/src/proxy/ScriptedProxyHandler.h b/src/third_party/mozjs-60/extract/js/src/proxy/ScriptedProxyHandler.h
new file mode 100644
index 00000000000..58d9cf753c5
--- /dev/null
+++ b/src/third_party/mozjs-60/extract/js/src/proxy/ScriptedProxyHandler.h
@@ -0,0 +1,106 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * 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/. */
+
+#ifndef proxy_ScriptedProxyHandler_h
+#define proxy_ScriptedProxyHandler_h
+
+#include "js/Proxy.h"
+
+namespace js {
+
+/* Derived class for all scripted proxy handlers. */
+class ScriptedProxyHandler : public BaseProxyHandler
+{
+ public:
+ constexpr ScriptedProxyHandler()
+ : BaseProxyHandler(&family)
+ { }
+
+ /* Standard internal methods. */
+ virtual bool getOwnPropertyDescriptor(JSContext* cx, HandleObject proxy, HandleId id,
+ MutableHandle<PropertyDescriptor> desc) const override;
+ virtual bool defineProperty(JSContext* cx, HandleObject proxy, HandleId id,
+ Handle<PropertyDescriptor> desc,
+ ObjectOpResult& result) const override;
+ virtual bool ownPropertyKeys(JSContext* cx, HandleObject proxy,
+ AutoIdVector& props) const override;
+ virtual bool delete_(JSContext* cx, HandleObject proxy, HandleId id,
+ ObjectOpResult& result) const override;
+
+ virtual bool getPrototype(JSContext* cx, HandleObject proxy,
+ MutableHandleObject protop) const override;
+ virtual bool setPrototype(JSContext* cx, HandleObject proxy, HandleObject proto,
+ ObjectOpResult& result) const override;
+ /* Non-standard, but needed to correctly implement OrdinaryGetPrototypeOf. */
+ virtual bool getPrototypeIfOrdinary(JSContext* cx, HandleObject proxy, bool* isOrdinary,
+ MutableHandleObject protop) const override;
+ /* Non-standard, but needed to handle revoked proxies. */
+ virtual bool setImmutablePrototype(JSContext* cx, HandleObject proxy,
+ bool* succeeded) const override;
+
+ virtual bool preventExtensions(JSContext* cx, HandleObject proxy,
+ ObjectOpResult& result) const override;
+ virtual bool isExtensible(JSContext* cx, HandleObject proxy, bool* extensible) const override;
+
+ virtual bool has(JSContext* cx, HandleObject proxy, HandleId id, bool* bp) const override;
+ virtual bool get(JSContext* cx, HandleObject proxy, HandleValue receiver, HandleId id,
+ MutableHandleValue vp) const override;
+ virtual bool set(JSContext* cx, HandleObject proxy, HandleId id, HandleValue v,
+ HandleValue receiver, ObjectOpResult& result) const override;
+ virtual bool call(JSContext* cx, HandleObject proxy, const CallArgs& args) const override;
+ virtual bool construct(JSContext* cx, HandleObject proxy, const CallArgs& args) const override;
+
+ /* SpiderMonkey extensions. */
+ virtual bool hasOwn(JSContext* cx, HandleObject proxy, HandleId id, bool* bp) const override {
+ return BaseProxyHandler::hasOwn(cx, proxy, id, bp);
+ }
+
+ // A scripted proxy should not be treated as generic in most contexts.
+ virtual bool nativeCall(JSContext* cx, IsAcceptableThis test, NativeImpl impl,
+ const CallArgs& args) const override;
+ virtual bool hasInstance(JSContext* cx, HandleObject proxy, MutableHandleValue v,
+ bool* bp) const override;
+ virtual bool getBuiltinClass(JSContext* cx, HandleObject proxy, ESClass* cls) const override;
+ virtual bool isArray(JSContext* cx, HandleObject proxy,
+ JS::IsArrayAnswer* answer) const override;
+ virtual const char* className(JSContext* cx, HandleObject proxy) const override;
+ virtual JSString* fun_toString(JSContext* cx, HandleObject proxy,
+ bool isToSource) const override;
+ virtual RegExpShared* regexp_toShared(JSContext* cx, HandleObject proxy) const override;
+ virtual bool boxedValue_unbox(JSContext* cx, HandleObject proxy,
+ MutableHandleValue vp) const override;
+
+ virtual bool isCallable(JSObject* obj) const override;
+ virtual bool isConstructor(JSObject* obj) const override;
+
+ virtual bool isScripted() const override { return true; }
+
+ static const char family;
+ static const ScriptedProxyHandler singleton;
+
+ // The "proxy extra" slot index in which the handler is stored. Revocable proxies need to set
+ // this at revocation time.
+ static const int HANDLER_EXTRA = 0;
+ static const int IS_CALLCONSTRUCT_EXTRA = 1;
+ // Bitmasks for the "call/construct" slot
+ static const int IS_CALLABLE = 1 << 0;
+ static const int IS_CONSTRUCTOR = 1 << 1;
+ // The "function extended" slot index in which the revocation object is stored. Per spec, this
+ // is to be cleared during the first revocation.
+ static const int REVOKE_SLOT = 0;
+
+ static JSObject* handlerObject(const JSObject* proxy);
+};
+
+bool
+proxy(JSContext* cx, unsigned argc, Value* vp);
+
+bool
+proxy_revocable(JSContext* cx, unsigned argc, Value* vp);
+
+} /* namespace js */
+
+#endif /* proxy_ScriptedProxyHandler_h */
diff --git a/src/third_party/mozjs-60/extract/js/src/proxy/SecurityWrapper.cpp b/src/third_party/mozjs-60/extract/js/src/proxy/SecurityWrapper.cpp
new file mode 100644
index 00000000000..5b326f97dae
--- /dev/null
+++ b/src/third_party/mozjs-60/extract/js/src/proxy/SecurityWrapper.cpp
@@ -0,0 +1,130 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * 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 "jsapi.h"
+#include "jsfriendapi.h"
+#include "NamespaceImports.h"
+
+#include "js/Wrapper.h"
+#include "vm/StringType.h"
+
+using namespace js;
+
+template <class Base>
+bool
+SecurityWrapper<Base>::enter(JSContext* cx, HandleObject wrapper, HandleId id,
+ Wrapper::Action act, bool mayThrow, bool* bp) const
+{
+ ReportAccessDenied(cx);
+ *bp = false;
+ return false;
+}
+
+template <class Base>
+bool
+SecurityWrapper<Base>::nativeCall(JSContext* cx, IsAcceptableThis test, NativeImpl impl,
+ const CallArgs& args) const
+{
+ ReportAccessDenied(cx);
+ return false;
+}
+
+template <class Base>
+bool
+SecurityWrapper<Base>::setPrototype(JSContext* cx, HandleObject wrapper, HandleObject proto,
+ ObjectOpResult& result) const
+{
+ ReportAccessDenied(cx);
+ return false;
+}
+
+template <class Base>
+bool
+SecurityWrapper<Base>::setImmutablePrototype(JSContext* cx, HandleObject wrapper,
+ bool* succeeded) const
+{
+ ReportAccessDenied(cx);
+ return false;
+}
+
+template <class Base>
+bool
+SecurityWrapper<Base>::preventExtensions(JSContext* cx, HandleObject wrapper,
+ ObjectOpResult& result) const
+{
+ // Just like BaseProxyHandler, SecurityWrappers claim by default to always
+ // be extensible, so as not to leak information about the state of the
+ // underlying wrapped thing.
+ return result.fail(JSMSG_CANT_CHANGE_EXTENSIBILITY);
+}
+
+template <class Base>
+bool
+SecurityWrapper<Base>::isExtensible(JSContext* cx, HandleObject wrapper, bool* extensible) const
+{
+ // See above.
+ *extensible = true;
+ return true;
+}
+
+template <class Base>
+bool
+SecurityWrapper<Base>::getBuiltinClass(JSContext* cx, HandleObject wrapper,
+ ESClass* cls) const
+{
+ *cls = ESClass::Other;
+ return true;
+}
+
+template <class Base>
+bool
+SecurityWrapper<Base>::isArray(JSContext* cx, HandleObject obj, JS::IsArrayAnswer* answer) const
+{
+ // This should ReportAccessDenied(cx), but bug 849730 disagrees. :-(
+ *answer = JS::IsArrayAnswer::NotArray;
+ return true;
+}
+
+template <class Base>
+RegExpShared*
+SecurityWrapper<Base>::regexp_toShared(JSContext* cx, HandleObject obj) const
+{
+ return Base::regexp_toShared(cx, obj);
+}
+
+template <class Base>
+bool
+SecurityWrapper<Base>::boxedValue_unbox(JSContext* cx, HandleObject obj, MutableHandleValue vp) const
+{
+ vp.setUndefined();
+ return true;
+}
+
+template <class Base>
+bool
+SecurityWrapper<Base>::defineProperty(JSContext* cx, HandleObject wrapper, HandleId id,
+ Handle<PropertyDescriptor> desc,
+ ObjectOpResult& result) const
+{
+ if (desc.getter() || desc.setter()) {
+ RootedValue idVal(cx, IdToValue(id));
+ JSString* str = ValueToSource(cx, idVal);
+ if (!str)
+ return false;
+ AutoStableStringChars chars(cx);
+ const char16_t* prop = nullptr;
+ if (str->ensureFlat(cx) && chars.initTwoByte(cx, str))
+ prop = chars.twoByteChars();
+ JS_ReportErrorNumberUC(cx, GetErrorMessage, nullptr,
+ JSMSG_ACCESSOR_DEF_DENIED, prop);
+ return false;
+ }
+
+ return Base::defineProperty(cx, wrapper, id, desc, result);
+}
+
+template class js::SecurityWrapper<Wrapper>;
+template class js::SecurityWrapper<CrossCompartmentWrapper>;
diff --git a/src/third_party/mozjs-60/extract/js/src/proxy/Wrapper.cpp b/src/third_party/mozjs-60/extract/js/src/proxy/Wrapper.cpp
new file mode 100644
index 00000000000..5c421a51281
--- /dev/null
+++ b/src/third_party/mozjs-60/extract/js/src/proxy/Wrapper.cpp
@@ -0,0 +1,464 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * 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 "js/Wrapper.h"
+
+#include "jsexn.h"
+
+#include "js/Proxy.h"
+#include "vm/ErrorObject.h"
+#include "vm/JSCompartment.h"
+#include "vm/JSContext.h"
+#include "vm/ProxyObject.h"
+#include "vm/RegExpObject.h"
+#include "vm/WrapperObject.h"
+
+#include "gc/Marking-inl.h"
+#include "vm/JSObject-inl.h"
+#include "vm/NativeObject-inl.h"
+
+using namespace js;
+
+bool
+Wrapper::finalizeInBackground(const Value& priv) const
+{
+ if (!priv.isObject())
+ return true;
+
+ /*
+ * Make the 'background-finalized-ness' of the wrapper the same as the
+ * wrapped object, to allow transplanting between them.
+ */
+ JSObject* wrapped = MaybeForwarded(&priv.toObject());
+ gc::AllocKind wrappedKind;
+ if (IsInsideNursery(wrapped)) {
+ JSRuntime *rt = wrapped->runtimeFromActiveCooperatingThread();
+ wrappedKind = wrapped->allocKindForTenure(rt->gc.nursery());
+ } else {
+ wrappedKind = wrapped->asTenured().getAllocKind();
+ }
+ return IsBackgroundFinalized(wrappedKind);
+}
+
+bool
+ForwardingProxyHandler::getOwnPropertyDescriptor(JSContext* cx, HandleObject proxy, HandleId id,
+ MutableHandle<PropertyDescriptor> desc) const
+{
+ assertEnteredPolicy(cx, proxy, id, GET | SET | GET_PROPERTY_DESCRIPTOR);
+ RootedObject target(cx, proxy->as<ProxyObject>().target());
+ return GetOwnPropertyDescriptor(cx, target, id, desc);
+}
+
+bool
+ForwardingProxyHandler::defineProperty(JSContext* cx, HandleObject proxy, HandleId id,
+ Handle<PropertyDescriptor> desc,
+ ObjectOpResult& result) const
+{
+ assertEnteredPolicy(cx, proxy, id, SET);
+ RootedObject target(cx, proxy->as<ProxyObject>().target());
+ return DefineProperty(cx, target, id, desc, result);
+}
+
+bool
+ForwardingProxyHandler::ownPropertyKeys(JSContext* cx, HandleObject proxy,
+ AutoIdVector& props) const
+{
+ assertEnteredPolicy(cx, proxy, JSID_VOID, ENUMERATE);
+ RootedObject target(cx, proxy->as<ProxyObject>().target());
+ return GetPropertyKeys(cx, target, JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS, &props);
+}
+
+bool
+ForwardingProxyHandler::delete_(JSContext* cx, HandleObject proxy, HandleId id,
+ ObjectOpResult& result) const
+{
+ assertEnteredPolicy(cx, proxy, id, SET);
+ RootedObject target(cx, proxy->as<ProxyObject>().target());
+ return DeleteProperty(cx, target, id, result);
+}
+
+JSObject*
+ForwardingProxyHandler::enumerate(JSContext* cx, HandleObject proxy) const
+{
+ assertEnteredPolicy(cx, proxy, JSID_VOID, ENUMERATE);
+ MOZ_ASSERT(!hasPrototype()); // Should never be called if there's a prototype.
+ RootedObject target(cx, proxy->as<ProxyObject>().target());
+ return GetIterator(cx, target);
+}
+
+bool
+ForwardingProxyHandler::getPrototype(JSContext* cx, HandleObject proxy,
+ MutableHandleObject protop) const
+{
+ RootedObject target(cx, proxy->as<ProxyObject>().target());
+ return GetPrototype(cx, target, protop);
+}
+
+bool
+ForwardingProxyHandler::setPrototype(JSContext* cx, HandleObject proxy, HandleObject proto,
+ ObjectOpResult& result) const
+{
+ RootedObject target(cx, proxy->as<ProxyObject>().target());
+ return SetPrototype(cx, target, proto, result);
+}
+
+bool
+ForwardingProxyHandler::getPrototypeIfOrdinary(JSContext* cx, HandleObject proxy,
+ bool* isOrdinary, MutableHandleObject protop) const
+{
+ RootedObject target(cx, proxy->as<ProxyObject>().target());
+ return GetPrototypeIfOrdinary(cx, target, isOrdinary, protop);
+}
+
+bool
+ForwardingProxyHandler::setImmutablePrototype(JSContext* cx, HandleObject proxy,
+ bool* succeeded) const
+{
+ RootedObject target(cx, proxy->as<ProxyObject>().target());
+ return SetImmutablePrototype(cx, target, succeeded);
+}
+
+bool
+ForwardingProxyHandler::preventExtensions(JSContext* cx, HandleObject proxy,
+ ObjectOpResult& result) const
+{
+ RootedObject target(cx, proxy->as<ProxyObject>().target());
+ return PreventExtensions(cx, target, result);
+}
+
+bool
+ForwardingProxyHandler::isExtensible(JSContext* cx, HandleObject proxy, bool* extensible) const
+{
+ RootedObject target(cx, proxy->as<ProxyObject>().target());
+ return IsExtensible(cx, target, extensible);
+}
+
+bool
+ForwardingProxyHandler::has(JSContext* cx, HandleObject proxy, HandleId id, bool* bp) const
+{
+ assertEnteredPolicy(cx, proxy, id, GET);
+ MOZ_ASSERT(!hasPrototype()); // Should never be called if there's a prototype.
+ RootedObject target(cx, proxy->as<ProxyObject>().target());
+ return HasProperty(cx, target, id, bp);
+}
+
+bool
+ForwardingProxyHandler::get(JSContext* cx, HandleObject proxy, HandleValue receiver, HandleId id,
+ MutableHandleValue vp) const
+{
+ assertEnteredPolicy(cx, proxy, id, GET);
+ RootedObject target(cx, proxy->as<ProxyObject>().target());
+ return GetProperty(cx, target, receiver, id, vp);
+}
+
+bool
+ForwardingProxyHandler::set(JSContext* cx, HandleObject proxy, HandleId id, HandleValue v,
+ HandleValue receiver, ObjectOpResult& result) const
+{
+ assertEnteredPolicy(cx, proxy, id, SET);
+ RootedObject target(cx, proxy->as<ProxyObject>().target());
+ return SetProperty(cx, target, id, v, receiver, result);
+}
+
+bool
+ForwardingProxyHandler::call(JSContext* cx, HandleObject proxy, const CallArgs& args) const
+{
+ assertEnteredPolicy(cx, proxy, JSID_VOID, CALL);
+ RootedValue target(cx, proxy->as<ProxyObject>().private_());
+
+ InvokeArgs iargs(cx);
+ if (!FillArgumentsFromArraylike(cx, iargs, args))
+ return false;
+
+ return js::Call(cx, target, args.thisv(), iargs, args.rval());
+}
+
+bool
+ForwardingProxyHandler::construct(JSContext* cx, HandleObject proxy, const CallArgs& args) const
+{
+ assertEnteredPolicy(cx, proxy, JSID_VOID, CALL);
+
+ RootedValue target(cx, proxy->as<ProxyObject>().private_());
+ if (!IsConstructor(target)) {
+ ReportValueError(cx, JSMSG_NOT_CONSTRUCTOR, JSDVG_IGNORE_STACK, target, nullptr);
+ return false;
+ }
+
+ ConstructArgs cargs(cx);
+ if (!FillArgumentsFromArraylike(cx, cargs, args))
+ return false;
+
+ RootedObject obj(cx);
+ if (!Construct(cx, target, cargs, args.newTarget(), &obj))
+ return false;
+
+ args.rval().setObject(*obj);
+ return true;
+}
+
+bool
+ForwardingProxyHandler::getPropertyDescriptor(JSContext* cx, HandleObject proxy, HandleId id,
+ MutableHandle<PropertyDescriptor> desc) const
+{
+ assertEnteredPolicy(cx, proxy, id, GET | SET | GET_PROPERTY_DESCRIPTOR);
+ MOZ_ASSERT(!hasPrototype()); // Should never be called if there's a prototype.
+ RootedObject target(cx, proxy->as<ProxyObject>().target());
+ return GetPropertyDescriptor(cx, target, id, desc);
+}
+
+bool
+ForwardingProxyHandler::hasOwn(JSContext* cx, HandleObject proxy, HandleId id, bool* bp) const
+{
+ assertEnteredPolicy(cx, proxy, id, GET);
+ RootedObject target(cx, proxy->as<ProxyObject>().target());
+ return HasOwnProperty(cx, target, id, bp);
+}
+
+bool
+ForwardingProxyHandler::getOwnEnumerablePropertyKeys(JSContext* cx, HandleObject proxy,
+ AutoIdVector& props) const
+{
+ assertEnteredPolicy(cx, proxy, JSID_VOID, ENUMERATE);
+ RootedObject target(cx, proxy->as<ProxyObject>().target());
+ return GetPropertyKeys(cx, target, JSITER_OWNONLY, &props);
+}
+
+bool
+ForwardingProxyHandler::nativeCall(JSContext* cx, IsAcceptableThis test, NativeImpl impl,
+ const CallArgs& args) const
+{
+ args.setThis(ObjectValue(*args.thisv().toObject().as<ProxyObject>().target()));
+ if (!test(args.thisv())) {
+ ReportIncompatible(cx, args);
+ return false;
+ }
+
+ return CallNativeImpl(cx, impl, args);
+}
+
+bool
+ForwardingProxyHandler::hasInstance(JSContext* cx, HandleObject proxy, MutableHandleValue v,
+ bool* bp) const
+{
+ assertEnteredPolicy(cx, proxy, JSID_VOID, GET);
+ RootedObject target(cx, proxy->as<ProxyObject>().target());
+ return HasInstance(cx, target, v, bp);
+}
+
+bool
+ForwardingProxyHandler::getBuiltinClass(JSContext* cx, HandleObject proxy, ESClass* cls) const
+{
+ RootedObject target(cx, proxy->as<ProxyObject>().target());
+ return GetBuiltinClass(cx, target, cls);
+}
+
+bool
+ForwardingProxyHandler::isArray(JSContext* cx, HandleObject proxy, JS::IsArrayAnswer* answer) const
+{
+ RootedObject target(cx, proxy->as<ProxyObject>().target());
+ return IsArray(cx, target, answer);
+}
+
+const char*
+ForwardingProxyHandler::className(JSContext* cx, HandleObject proxy) const
+{
+ assertEnteredPolicy(cx, proxy, JSID_VOID, GET);
+ RootedObject target(cx, proxy->as<ProxyObject>().target());
+ return GetObjectClassName(cx, target);
+}
+
+JSString*
+ForwardingProxyHandler::fun_toString(JSContext* cx, HandleObject proxy, bool isToSource) const
+{
+ assertEnteredPolicy(cx, proxy, JSID_VOID, GET);
+ RootedObject target(cx, proxy->as<ProxyObject>().target());
+ return fun_toStringHelper(cx, target, isToSource);
+}
+
+RegExpShared*
+ForwardingProxyHandler::regexp_toShared(JSContext* cx, HandleObject proxy) const
+{
+ RootedObject target(cx, proxy->as<ProxyObject>().target());
+ return RegExpToShared(cx, target);
+}
+
+bool
+ForwardingProxyHandler::boxedValue_unbox(JSContext* cx, HandleObject proxy,
+ MutableHandleValue vp) const
+{
+ RootedObject target(cx, proxy->as<ProxyObject>().target());
+ return Unbox(cx, target, vp);
+}
+
+bool
+ForwardingProxyHandler::isCallable(JSObject* obj) const
+{
+ JSObject* target = obj->as<ProxyObject>().target();
+ return target->isCallable();
+}
+
+bool
+ForwardingProxyHandler::isConstructor(JSObject* obj) const
+{
+ JSObject* target = obj->as<ProxyObject>().target();
+ return target->isConstructor();
+}
+
+JSObject*
+Wrapper::weakmapKeyDelegate(JSObject* proxy) const
+{
+ // This may be called during GC.
+ return UncheckedUnwrapWithoutExpose(proxy);
+}
+
+JSObject*
+Wrapper::New(JSContext* cx, JSObject* obj, const Wrapper* handler,
+ const WrapperOptions& options)
+{
+ RootedValue priv(cx, ObjectValue(*obj));
+ return NewProxyObject(cx, handler, priv, options.proto(), options);
+}
+
+JSObject*
+Wrapper::Renew(JSObject* existing, JSObject* obj, const Wrapper* handler)
+{
+ existing->as<ProxyObject>().renew(handler, ObjectValue(*obj));
+ return existing;
+}
+
+const Wrapper*
+Wrapper::wrapperHandler(JSObject* wrapper)
+{
+ MOZ_ASSERT(wrapper->is<WrapperObject>());
+ return static_cast<const Wrapper*>(wrapper->as<ProxyObject>().handler());
+}
+
+JSObject*
+Wrapper::wrappedObject(JSObject* wrapper)
+{
+ MOZ_ASSERT(wrapper->is<WrapperObject>());
+ JSObject* target = wrapper->as<ProxyObject>().target();
+
+ // Eagerly unmark gray wrapper targets so we can assert that we don't create
+ // black to gray edges. An incremental GC will eventually mark the targets
+ // of black wrappers black but while it is in progress we can observe gray
+ // targets. Expose rather than returning a gray object in this case.
+ if (target) {
+ if (wrapper->isMarkedBlack())
+ MOZ_ASSERT(JS::ObjectIsNotGray(target));
+ if (!wrapper->isMarkedGray())
+ JS::ExposeObjectToActiveJS(target);
+ }
+
+ return target;
+}
+
+JS_FRIEND_API(JSObject*)
+js::UncheckedUnwrapWithoutExpose(JSObject* wrapped)
+{
+ while (true) {
+ if (!wrapped->is<WrapperObject>() || MOZ_UNLIKELY(IsWindowProxy(wrapped)))
+ break;
+ wrapped = wrapped->as<WrapperObject>().target();
+
+ // This can be called from Wrapper::weakmapKeyDelegate() on a wrapper
+ // whose referent has been moved while it is still unmarked.
+ if (wrapped)
+ wrapped = MaybeForwarded(wrapped);
+ }
+ return wrapped;
+}
+
+JS_FRIEND_API(JSObject*)
+js::UncheckedUnwrap(JSObject* wrapped, bool stopAtWindowProxy, unsigned* flagsp)
+{
+ MOZ_ASSERT(!JS::CurrentThreadIsHeapCollecting());
+ MOZ_ASSERT(CurrentThreadCanAccessRuntime(wrapped->runtimeFromAnyThread()));
+
+ unsigned flags = 0;
+ while (true) {
+ if (!wrapped->is<WrapperObject>() ||
+ MOZ_UNLIKELY(stopAtWindowProxy && IsWindowProxy(wrapped)))
+ {
+ break;
+ }
+ flags |= Wrapper::wrapperHandler(wrapped)->flags();
+ wrapped = Wrapper::wrappedObject(wrapped);
+ }
+ if (flagsp)
+ *flagsp = flags;
+ return wrapped;
+}
+
+JS_FRIEND_API(JSObject*)
+js::CheckedUnwrap(JSObject* obj, bool stopAtWindowProxy)
+{
+ while (true) {
+ JSObject* wrapper = obj;
+ obj = UnwrapOneChecked(obj, stopAtWindowProxy);
+ if (!obj || obj == wrapper)
+ return obj;
+ }
+}
+
+JS_FRIEND_API(JSObject*)
+js::UnwrapOneChecked(JSObject* obj, bool stopAtWindowProxy)
+{
+ MOZ_ASSERT(!JS::CurrentThreadIsHeapCollecting());
+ MOZ_ASSERT(CurrentThreadCanAccessRuntime(obj->runtimeFromAnyThread()));
+
+ if (!obj->is<WrapperObject>() ||
+ MOZ_UNLIKELY(stopAtWindowProxy && IsWindowProxy(obj)))
+ {
+ return obj;
+ }
+
+ const Wrapper* handler = Wrapper::wrapperHandler(obj);
+ return handler->hasSecurityPolicy() ? nullptr : Wrapper::wrappedObject(obj);
+}
+
+void
+js::ReportAccessDenied(JSContext* cx)
+{
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_OBJECT_ACCESS_DENIED);
+}
+
+const char Wrapper::family = 0;
+const Wrapper Wrapper::singleton((unsigned)0);
+const Wrapper Wrapper::singletonWithPrototype((unsigned)0, true);
+JSObject* Wrapper::defaultProto = TaggedProto::LazyProto;
+
+/* Compartments. */
+
+JSObject*
+js::TransparentObjectWrapper(JSContext* cx, HandleObject existing, HandleObject obj)
+{
+ // Allow wrapping outer window proxies.
+ MOZ_ASSERT(!obj->is<WrapperObject>() || IsWindowProxy(obj));
+ return Wrapper::New(cx, obj, &CrossCompartmentWrapper::singleton);
+}
+
+ErrorCopier::~ErrorCopier()
+{
+ JSContext* cx = ac->context();
+
+ // The provenance of Debugger.DebuggeeWouldRun is the topmost locking
+ // debugger compartment; it should not be copied around.
+ if (ac->origin() != cx->compartment() &&
+ cx->isExceptionPending() &&
+ !cx->isThrowingDebuggeeWouldRun())
+ {
+ RootedValue exc(cx);
+ if (cx->getPendingException(&exc) && exc.isObject() && exc.toObject().is<ErrorObject>()) {
+ cx->clearPendingException();
+ ac.reset();
+ Rooted<ErrorObject*> errObj(cx, &exc.toObject().as<ErrorObject>());
+ JSObject* copyobj = CopyErrorObject(cx, errObj);
+ if (copyobj)
+ cx->setPendingException(ObjectValue(*copyobj));
+ }
+ }
+}