summaryrefslogtreecommitdiffstats
path: root/js/src/vm/ProxyObject.h
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
commit2aa4a82499d4becd2284cdb482213d541b8804dd (patch)
treeb80bf8bf13c3766139fbacc530efd0dd9d54394c /js/src/vm/ProxyObject.h
parentInitial commit. (diff)
downloadfirefox-upstream.tar.xz
firefox-upstream.zip
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'js/src/vm/ProxyObject.h')
-rw-r--r--js/src/vm/ProxyObject.h163
1 files changed, 163 insertions, 0 deletions
diff --git a/js/src/vm/ProxyObject.h b/js/src/vm/ProxyObject.h
new file mode 100644
index 0000000000..e1a1ac02ab
--- /dev/null
+++ b/js/src/vm/ProxyObject.h
@@ -0,0 +1,163 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim: set ts=8 sts=2 et sw=2 tw=80:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef vm_ProxyObject_h
+#define vm_ProxyObject_h
+
+#include "js/Proxy.h"
+#include "js/shadow/Object.h" // JS::shadow::Object
+#include "vm/JSObject.h"
+
+namespace js {
+
+/**
+ * This is the base class for the various kinds of proxy objects. It's never
+ * instantiated.
+ *
+ * Proxy objects use their shape primarily to record flags. Property
+ * information, &c. is all dynamically computed.
+ *
+ * There is no class_ member to force specialization of JSObject::is<T>().
+ * The implementation in JSObject is incorrect for proxies since it doesn't
+ * take account of the handler type.
+ */
+class ProxyObject : public JSObject {
+ // GetProxyDataLayout computes the address of this field.
+ detail::ProxyDataLayout data;
+
+ void static_asserts() {
+ static_assert(sizeof(ProxyObject) == sizeof(JSObject_Slots0),
+ "proxy object size must match GC thing size");
+ static_assert(offsetof(ProxyObject, data) == detail::ProxyDataOffset,
+ "proxy object layout must match shadow interface");
+ static_assert(offsetof(ProxyObject, data.reservedSlots) ==
+ offsetof(JS::shadow::Object, slots),
+ "Proxy reservedSlots must overlay native object slots field");
+ }
+
+ public:
+ static ProxyObject* New(JSContext* cx, const BaseProxyHandler* handler,
+ HandleValue priv, TaggedProto proto_,
+ const JSClass* clasp);
+
+ void init(const BaseProxyHandler* handler, HandleValue priv, JSContext* cx);
+
+ // Proxies usually store their ProxyValueArray inline in the object.
+ // There's one unfortunate exception: when a proxy is swapped with another
+ // object, and the sizes don't match, we malloc the ProxyValueArray.
+ void* inlineDataStart() const {
+ return (void*)(uintptr_t(this) + sizeof(ProxyObject));
+ }
+ bool usingInlineValueArray() const {
+ return data.values() == inlineDataStart();
+ }
+ void setInlineValueArray() {
+ data.reservedSlots =
+ &reinterpret_cast<detail::ProxyValueArray*>(inlineDataStart())
+ ->reservedSlots;
+ }
+
+ MOZ_MUST_USE bool initExternalValueArrayAfterSwap(JSContext* cx,
+ HandleValueVector values);
+
+ const Value& private_() const { return GetProxyPrivate(this); }
+ const Value& expando() const { return GetProxyExpando(this); }
+
+ void setExpando(JSObject* expando);
+
+ void setCrossCompartmentPrivate(const Value& priv);
+ void setSameCompartmentPrivate(const Value& priv);
+
+ JSObject* target() const { return private_().toObjectOrNull(); }
+
+ const BaseProxyHandler* handler() const { return GetProxyHandler(this); }
+
+ void setHandler(const BaseProxyHandler* handler) {
+ SetProxyHandler(this, handler);
+ }
+
+ static size_t offsetOfReservedSlots() {
+ return offsetof(ProxyObject, data.reservedSlots);
+ }
+ static size_t offsetOfHandler() {
+ return offsetof(ProxyObject, data.handler);
+ }
+
+ size_t numReservedSlots() const { return JSCLASS_RESERVED_SLOTS(getClass()); }
+ const Value& reservedSlot(size_t n) const {
+ return GetProxyReservedSlot(this, n);
+ }
+
+ void setReservedSlot(size_t n, const Value& extra) {
+ SetProxyReservedSlot(this, n, extra);
+ }
+
+ gc::AllocKind allocKindForTenure() const;
+
+ private:
+ GCPtrValue* reservedSlotPtr(size_t n) {
+ return reinterpret_cast<GCPtrValue*>(
+ &detail::GetProxyDataLayout(this)->reservedSlots->slots[n]);
+ }
+
+ GCPtrValue* slotOfPrivate() {
+ return reinterpret_cast<GCPtrValue*>(
+ &detail::GetProxyDataLayout(this)->values()->privateSlot);
+ }
+
+ GCPtrValue* slotOfExpando() {
+ return reinterpret_cast<GCPtrValue*>(
+ &detail::GetProxyDataLayout(this)->values()->expandoSlot);
+ }
+
+ void setPrivate(const Value& priv);
+
+ static bool isValidProxyClass(const JSClass* clasp) {
+ // Since we can take classes from the outside, make sure that they
+ // are "sane". They have to quack enough like proxies for us to belive
+ // they should be treated as such.
+
+ // Proxy classes are not allowed to have call or construct hooks directly.
+ // Their callability is instead decided by handler()->isCallable().
+ return clasp->isProxy() && clasp->isTrace(ProxyObject::trace) &&
+ !clasp->getCall() && !clasp->getConstruct();
+ }
+
+ public:
+ static unsigned grayLinkReservedSlot(JSObject* obj);
+
+ void renew(const BaseProxyHandler* handler, const Value& priv);
+
+ static void trace(JSTracer* trc, JSObject* obj);
+
+ static void traceEdgeToTarget(JSTracer* trc, ProxyObject* obj);
+
+ void nuke();
+};
+
+inline bool IsProxyClass(const JSClass* clasp) { return clasp->isProxy(); }
+
+bool IsDerivedProxyObject(const JSObject* obj,
+ const js::BaseProxyHandler* handler);
+
+} // namespace js
+
+template <>
+inline bool JSObject::is<js::ProxyObject>() const {
+ // Note: this method is implemented in terms of the IsProxy() friend API
+ // functions to ensure the implementations are tied together.
+ // Note 2: this specialization isn't used for subclasses of ProxyObject
+ // which must supply their own implementation.
+ return js::IsProxy(this);
+}
+
+inline bool js::IsDerivedProxyObject(const JSObject* obj,
+ const js::BaseProxyHandler* handler) {
+ return obj->is<js::ProxyObject>() &&
+ obj->as<js::ProxyObject>().handler() == handler;
+}
+
+#endif /* vm_ProxyObject_h */