#ifndef vm_ProxyObject_h
#define vm_ProxyObject_h
#include "js/Proxy.h"
#include "vm/ShapedObject.h"
namespace js {
class ProxyObject : public ShapedObject {
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(shadow::Object, slots),
"Proxy reservedSlots must overlay native object slots field");
}
static JS::Result<ProxyObject*, JS::OOM&> create(JSContext* cx,
const js::Class* clasp,
Handle<TaggedProto> proto,
js::gc::AllocKind allocKind,
js::NewObjectKind newKind);
public:
static ProxyObject* New(JSContext* cx, const BaseProxyHandler* handler,
HandleValue priv, TaggedProto proto_,
const ProxyOptions& options);
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, const AutoValueVector& values);
const Value& private_() const { return GetProxyPrivate(this); }
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);
}
void setPrivate(const Value& priv);
static bool isValidProxyClass(const Class* clasp) {
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 Class* clasp) { return clasp->isProxy(); }
bool IsDerivedProxyObject(const JSObject* obj,
const js::BaseProxyHandler* handler);
}
template <>
inline bool JSObject::is<js::ProxyObject>() const {
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