Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 : * vim: set ts=8 sts=4 et sw=4 tw=99:
3 : * This Source Code Form is subject to the terms of the Mozilla Public
4 : * License, v. 2.0. If a copy of the MPL was not distributed with this
5 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : #ifndef vm_ProxyObject_h
8 : #define vm_ProxyObject_h
9 :
10 : #include "js/Proxy.h"
11 : #include "vm/ShapedObject.h"
12 :
13 : namespace js {
14 :
15 : /**
16 : * This is the base class for the various kinds of proxy objects. It's never
17 : * instantiated.
18 : *
19 : * Proxy objects use ShapedObject::shape_ primarily to record flags. Property
20 : * information, &c. is all dynamically computed.
21 : */
22 : class ProxyObject : public ShapedObject
23 : {
24 : // GetProxyDataLayout computes the address of this field.
25 : detail::ProxyDataLayout data;
26 :
27 : void static_asserts() {
28 : static_assert(sizeof(ProxyObject) == sizeof(JSObject_Slots0),
29 : "proxy object size must match GC thing size");
30 : static_assert(offsetof(ProxyObject, data) == detail::ProxyDataOffset,
31 : "proxy object layout must match shadow interface");
32 : static_assert(offsetof(ProxyObject, data.reservedSlots) == offsetof(shadow::Object, slots),
33 : "Proxy reservedSlots must overlay native object slots field");
34 : }
35 :
36 : static JS::Result<ProxyObject*, JS::OOM&>
37 : create(JSContext* cx, const js::Class* clasp, Handle<TaggedProto> proto,
38 : js::gc::AllocKind allocKind, js::NewObjectKind newKind);
39 :
40 : public:
41 : static ProxyObject* New(JSContext* cx, const BaseProxyHandler* handler, HandleValue priv,
42 : TaggedProto proto_, const ProxyOptions& options);
43 :
44 : // Proxies usually store their ProxyValueArray inline in the object.
45 : // There's one unfortunate exception: when a proxy is swapped with another
46 : // object, and the sizes don't match, we malloc the ProxyValueArray.
47 15662 : void* inlineDataStart() const {
48 15662 : return (void*)(uintptr_t(this) + sizeof(ProxyObject));
49 : }
50 4222 : bool usingInlineValueArray() const {
51 4222 : return data.values() == inlineDataStart();
52 : }
53 11440 : void setInlineValueArray() {
54 11440 : data.reservedSlots = &reinterpret_cast<detail::ProxyValueArray*>(inlineDataStart())->reservedSlots;
55 11440 : }
56 : MOZ_MUST_USE bool initExternalValueArrayAfterSwap(JSContext* cx, const Vector<Value>& values);
57 :
58 83524 : const Value& private_() {
59 83524 : return GetProxyPrivate(this);
60 : }
61 :
62 : void setCrossCompartmentPrivate(const Value& priv);
63 : void setSameCompartmentPrivate(const Value& priv);
64 :
65 11500 : GCPtrValue* slotOfPrivate() {
66 11500 : return reinterpret_cast<GCPtrValue*>(&detail::GetProxyDataLayout(this)->values()->privateSlot);
67 : }
68 :
69 76318 : JSObject* target() const {
70 76318 : return const_cast<ProxyObject*>(this)->private_().toObjectOrNull();
71 : }
72 :
73 77790 : const BaseProxyHandler* handler() const {
74 77790 : return GetProxyHandler(const_cast<ProxyObject*>(this));
75 : }
76 :
77 54 : void setHandler(const BaseProxyHandler* handler) {
78 54 : SetProxyHandler(this, handler);
79 54 : }
80 :
81 19 : static size_t offsetOfReservedSlots() {
82 19 : return offsetof(ProxyObject, data.reservedSlots);
83 : }
84 24 : static size_t offsetOfHandler() {
85 24 : return offsetof(ProxyObject, data.handler);
86 : }
87 :
88 11476 : size_t numReservedSlots() const {
89 11476 : return JSCLASS_RESERVED_SLOTS(getClass());
90 : }
91 71 : const Value& reservedSlot(size_t n) const {
92 71 : return GetProxyReservedSlot(const_cast<ProxyObject*>(this), n);
93 : }
94 :
95 28 : void setReservedSlot(size_t n, const Value& extra) {
96 28 : SetProxyReservedSlot(this, n, extra);
97 28 : }
98 :
99 : gc::AllocKind allocKindForTenure() const;
100 :
101 : private:
102 2113 : GCPtrValue* reservedSlotPtr(size_t n) {
103 2113 : return reinterpret_cast<GCPtrValue*>(&detail::GetProxyDataLayout(this)->reservedSlots->slots[n]);
104 : }
105 :
106 9333 : static bool isValidProxyClass(const Class* clasp) {
107 : // Since we can take classes from the outside, make sure that they
108 : // are "sane". They have to quack enough like proxies for us to belive
109 : // they should be treated as such.
110 :
111 : // Proxy classes are not allowed to have call or construct hooks directly. Their
112 : // callability is instead decided by handler()->isCallable().
113 18666 : return clasp->isProxy() &&
114 18666 : clasp->isTrace(ProxyObject::trace) &&
115 27999 : !clasp->getCall() && !clasp->getConstruct();
116 : }
117 :
118 : public:
119 : static unsigned grayLinkReservedSlot(JSObject* obj);
120 :
121 : void renew(const BaseProxyHandler* handler, const Value& priv);
122 :
123 : static void trace(JSTracer* trc, JSObject* obj);
124 :
125 : void nuke();
126 :
127 : // There is no class_ member to force specialization of JSObject::is<T>().
128 : // The implementation in JSObject is incorrect for proxies since it doesn't
129 : // take account of the handler type.
130 : static const Class proxyClass;
131 : };
132 :
133 : inline bool
134 0 : IsProxyClass(const Class* clasp)
135 : {
136 0 : return clasp->isProxy();
137 : }
138 :
139 : bool IsDerivedProxyObject(const JSObject* obj, const js::BaseProxyHandler* handler);
140 :
141 : } // namespace js
142 :
143 : template<>
144 : inline bool
145 638790 : JSObject::is<js::ProxyObject>() const
146 : {
147 : // Note: this method is implemented in terms of the IsProxy() friend API
148 : // functions to ensure the implementations are tied together.
149 : // Note 2: this specialization isn't used for subclasses of ProxyObject
150 : // which must supply their own implementation.
151 638790 : return js::IsProxy(const_cast<JSObject*>(this));
152 : }
153 :
154 : inline bool
155 118409 : js::IsDerivedProxyObject(const JSObject* obj, const js::BaseProxyHandler* handler) {
156 118409 : return obj->is<js::ProxyObject>() && obj->as<js::ProxyObject>().handler() == handler;
157 : }
158 :
159 : #endif /* vm_ProxyObject_h */
|