Line data Source code
1 : /* THIS FILE IS AUTOGENERATED FROM DOMStringMap.webidl BY Codegen.py - DO NOT EDIT */
2 :
3 : #include "DOMStringMapBinding.h"
4 : #include "WrapperFactory.h"
5 : #include "mozilla/OwningNonNull.h"
6 : #include "mozilla/dom/BindingUtils.h"
7 : #include "mozilla/dom/CustomElementRegistry.h"
8 : #include "mozilla/dom/DOMJSClass.h"
9 : #include "mozilla/dom/DOMJSProxyHandler.h"
10 : #include "mozilla/dom/NonRefcountedDOMObject.h"
11 : #include "mozilla/dom/XrayExpandoClass.h"
12 : #include "nsDOMStringMap.h"
13 : #include "nsISupports.h"
14 : #include "xpcjsid.h"
15 :
16 : namespace mozilla {
17 : namespace dom {
18 :
19 : namespace DOMStringMapBinding {
20 :
21 : static void
22 0 : _objectMoved(JSObject* obj, const JSObject* old)
23 : {
24 0 : nsDOMStringMap* self = UnwrapPossiblyNotInitializedDOMObject<nsDOMStringMap>(obj);
25 0 : if (self) {
26 0 : UpdateWrapper(self, self, obj, old);
27 : }
28 0 : }
29 :
30 : // We deliberately use brace-elision to make Visual Studio produce better initalization code.
31 : #if defined(__clang__)
32 : #pragma clang diagnostic push
33 : #pragma clang diagnostic ignored "-Wmissing-braces"
34 : #endif
35 : static const JSFunctionSpec sMethods_specs[] = {
36 : JS_FNSPEC("QueryInterface", QueryInterface, nullptr, 1, 0, nullptr),
37 : JS_FS_END
38 : };
39 : #if defined(__clang__)
40 : #pragma clang diagnostic pop
41 : #endif
42 :
43 : static PrefableDisablers sMethods_disablers0 = {
44 : true, false, 0, &WantsQueryInterface<nsDOMStringMap>::Enabled
45 : };
46 :
47 : // Can't be const because the pref-enabled boolean needs to be writable
48 : static Prefable<const JSFunctionSpec> sMethods[] = {
49 : { &sMethods_disablers0, &sMethods_specs[0] },
50 : { nullptr, nullptr }
51 : };
52 :
53 : static_assert(1 <= 1ull << NUM_BITS_PROPERTY_INFO_PREF_INDEX,
54 : "We have a prefable index that is >= (1 << NUM_BITS_PROPERTY_INFO_PREF_INDEX)");
55 : static_assert(1 <= 1ull << NUM_BITS_PROPERTY_INFO_SPEC_INDEX,
56 : "We have a spec index that is >= (1 << NUM_BITS_PROPERTY_INFO_SPEC_INDEX)");
57 :
58 :
59 : static uint16_t sNativeProperties_sortedPropertyIndices[1];
60 : static PropertyInfo sNativeProperties_propertyInfos[1];
61 :
62 : static const NativePropertiesN<1> sNativeProperties = {
63 : false, 0,
64 : false, 0,
65 : true, 0 /* sMethods */,
66 : false, 0,
67 : false, 0,
68 : false, 0,
69 : false, 0,
70 : -1,
71 : 1,
72 : sNativeProperties_sortedPropertyIndices,
73 : {
74 : { sMethods, &sNativeProperties_propertyInfos[0] }
75 : }
76 : };
77 : static_assert(1 < 1ull << CHAR_BIT * sizeof(sNativeProperties.propertyInfoCount),
78 : "We have a property info count that is oversized");
79 :
80 : static const DOMIfaceAndProtoJSClass sInterfaceObjectClass = {
81 : {
82 : "Function",
83 : JSCLASS_IS_DOMIFACEANDPROTOJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(DOM_INTERFACE_SLOTS_BASE),
84 : &sBoringInterfaceObjectClassClassOps,
85 : JS_NULL_CLASS_SPEC,
86 : JS_NULL_CLASS_EXT,
87 : &sInterfaceObjectClassObjectOps
88 : },
89 : eInterface,
90 : true,
91 : prototypes::id::DOMStringMap,
92 : PrototypeTraits<prototypes::id::DOMStringMap>::Depth,
93 : sNativePropertyHooks,
94 : "function DOMStringMap() {\n [native code]\n}",
95 : JS::GetRealmFunctionPrototype
96 : };
97 :
98 : static const DOMIfaceAndProtoJSClass sPrototypeClass = {
99 : {
100 : "DOMStringMapPrototype",
101 : JSCLASS_IS_DOMIFACEANDPROTOJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(DOM_INTERFACE_PROTO_SLOTS_BASE),
102 : JS_NULL_CLASS_OPS,
103 : JS_NULL_CLASS_SPEC,
104 : JS_NULL_CLASS_EXT,
105 : JS_NULL_OBJECT_OPS
106 : },
107 : eInterfacePrototype,
108 : false,
109 : prototypes::id::DOMStringMap,
110 : PrototypeTraits<prototypes::id::DOMStringMap>::Depth,
111 : sNativePropertyHooks,
112 : "[object DOMStringMapPrototype]",
113 : JS::GetRealmObjectPrototype
114 : };
115 :
116 : JSObject*
117 0 : DefineDOMInterface(JSContext* aCx, JS::Handle<JSObject*> aGlobal, JS::Handle<jsid> id, bool aDefineOnGlobal)
118 : {
119 0 : return GetConstructorObjectHandle(aCx, aDefineOnGlobal);
120 : }
121 :
122 : static_assert(IsBaseOf<nsISupports, nsDOMStringMap >::value,
123 : "We don't support non-nsISupports native classes for "
124 : "proxy-based bindings yet");
125 :
126 :
127 : class DOMProxyHandler : public ShadowingDOMProxyHandler
128 : {
129 : public:
130 : explicit constexpr DOMProxyHandler()
131 : {
132 : }
133 :
134 : virtual bool
135 : getOwnPropDescriptor(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id, bool ignoreNamedProps, JS::MutableHandle<JS::PropertyDescriptor> desc) const override;
136 :
137 : virtual bool
138 : defineProperty(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id, JS::Handle<JS::PropertyDescriptor> desc, JS::ObjectOpResult& opresult, bool* defined) const override;
139 :
140 : using mozilla::dom::DOMProxyHandler::defineProperty;
141 :
142 : virtual bool
143 : ownPropNames(JSContext* cx, JS::Handle<JSObject*> proxy, unsigned flags, JS::AutoIdVector& props) const override;
144 :
145 : virtual bool
146 : hasOwn(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id, bool* bp) const override;
147 :
148 : virtual bool
149 : get(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<JS::Value> receiver, JS::Handle<jsid> id, JS::MutableHandle<JS::Value> vp) const override;
150 :
151 : virtual const char*
152 : className(JSContext* cx, JS::Handle<JSObject*> proxy) const override;
153 :
154 : virtual bool
155 : finalizeInBackground(const JS::Value& priv) const override;
156 :
157 : virtual void
158 : finalize(JSFreeOp* fop, JSObject* proxy) const override;
159 :
160 : static const DOMProxyHandler*
161 : getInstance();
162 :
163 : virtual bool
164 : delete_(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id, JS::ObjectOpResult& opresult) const override;
165 :
166 : virtual bool
167 : setCustom(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id, JS::Handle<JS::Value> v, bool* done) const override;
168 : };
169 :
170 : MOZ_ALWAYS_INLINE bool
171 0 : IsProxy(JSObject* obj)
172 : {
173 0 : return js::IsProxy(obj) && js::GetProxyHandler(obj) == DOMProxyHandler::getInstance();
174 : }
175 :
176 : MOZ_ALWAYS_INLINE nsDOMStringMap*
177 0 : UnwrapProxy(JSObject* obj)
178 : {
179 0 : MOZ_ASSERT(js::IsProxy(obj));
180 0 : if (js::GetProxyHandler(obj) != DOMProxyHandler::getInstance()) {
181 0 : MOZ_ASSERT(xpc::WrapperFactory::IsXrayWrapper(obj));
182 0 : obj = js::UncheckedUnwrap(obj);
183 : }
184 0 : MOZ_ASSERT(IsProxy(obj));
185 0 : return static_cast<nsDOMStringMap*>(js::GetProxyReservedSlot(obj, DOM_OBJECT_SLOT).toPrivate());
186 : }
187 :
188 : bool
189 0 : DOMProxyHandler::getOwnPropDescriptor(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id, bool ignoreNamedProps, JS::MutableHandle<JS::PropertyDescriptor> desc) const
190 : {
191 0 : bool isXray = xpc::WrapperFactory::IsXrayWrapper(proxy);
192 0 : JS::Rooted<JSObject*> expando(cx);
193 0 : if (!isXray && (expando = GetExpandoObject(proxy))) {
194 0 : if (!JS_GetOwnPropertyDescriptorById(cx, expando, id, desc)) {
195 0 : return false;
196 : }
197 0 : if (desc.object()) {
198 : // Pretend the property lives on the wrapper.
199 0 : desc.object().set(proxy);
200 0 : return true;
201 : }
202 : }
203 :
204 0 : bool callNamedGetter = false;
205 0 : if (!ignoreNamedProps) {
206 0 : if (!isXray) {
207 0 : callNamedGetter = true;
208 : } else {
209 : bool hasOnProto;
210 0 : if (!HasPropertyOnPrototype(cx, proxy, id, &hasOnProto)) {
211 0 : return false;
212 : }
213 0 : callNamedGetter = !hasOnProto;
214 : }
215 : }
216 0 : if (callNamedGetter) {
217 0 : binding_detail::FakeString name;
218 : bool isSymbol;
219 0 : if (!ConvertIdToString(cx, id, name, isSymbol)) {
220 0 : return false;
221 : }
222 0 : if (!isSymbol) {
223 0 : nsDOMStringMap* self = UnwrapProxy(proxy);
224 0 : bool found = false;
225 0 : DOMString result;
226 0 : self->NamedGetter(NonNullHelper(Constify(name)), found, result);
227 0 : MOZ_ASSERT(!JS_IsExceptionPending(cx));
228 :
229 0 : if (found) {
230 0 : if (!xpc::NonVoidStringToJsval(cx, result, desc.value())) {
231 0 : return false;
232 : }
233 0 : FillPropertyDescriptor(desc, proxy, false, true);
234 0 : return true;
235 : }
236 : }
237 : }
238 :
239 0 : desc.object().set(nullptr);
240 0 : return true;
241 : }
242 :
243 : bool
244 0 : DOMProxyHandler::defineProperty(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id, JS::Handle<JS::PropertyDescriptor> desc, JS::ObjectOpResult& opresult, bool* defined) const
245 : {
246 0 : *defined = true;
247 0 : binding_detail::FakeString name;
248 : bool isSymbol;
249 0 : if (!ConvertIdToString(cx, id, name, isSymbol)) {
250 0 : return false;
251 : }
252 0 : if (!isSymbol) {
253 0 : nsDOMStringMap* self = UnwrapProxy(proxy);
254 0 : JS::Rooted<JS::Value> rootedValue(cx, desc.value());
255 0 : binding_detail::FakeString value;
256 0 : if (!ConvertJSValueToString(cx, desc.value(), eStringify, eStringify, value)) {
257 0 : return false;
258 : }
259 0 : CustomElementReactionsStack* reactionsStack = GetCustomElementReactionsStack(proxy);
260 0 : Maybe<AutoCEReaction> ceReaction;
261 0 : if (reactionsStack) {
262 0 : ceReaction.emplace(reactionsStack);
263 : }
264 0 : binding_detail::FastErrorResult rv;
265 0 : self->NamedSetter(NonNullHelper(Constify(name)), NonNullHelper(Constify(value)), rv);
266 0 : if (MOZ_UNLIKELY(rv.MaybeSetPendingException(cx))) {
267 0 : return false;
268 : }
269 0 : MOZ_ASSERT(!JS_IsExceptionPending(cx));
270 : }
271 :
272 0 : return opresult.succeed();
273 : }
274 :
275 :
276 : bool
277 0 : DOMProxyHandler::ownPropNames(JSContext* cx, JS::Handle<JSObject*> proxy, unsigned flags, JS::AutoIdVector& props) const
278 : {
279 0 : bool isXray = xpc::WrapperFactory::IsXrayWrapper(proxy);
280 :
281 0 : nsTArray<nsString> names;
282 0 : UnwrapProxy(proxy)->GetSupportedNames(names);
283 0 : if (!AppendNamedPropertyIds(cx, proxy, names, !isXray, props)) {
284 0 : return false;
285 : }
286 :
287 0 : JS::Rooted<JSObject*> expando(cx);
288 0 : if (!isXray && (expando = DOMProxyHandler::GetExpandoObject(proxy)) &&
289 0 : !js::GetPropertyKeys(cx, expando, flags, &props)) {
290 0 : return false;
291 : }
292 :
293 0 : return true;
294 : }
295 :
296 : bool
297 0 : DOMProxyHandler::hasOwn(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id, bool* bp) const
298 : {
299 0 : MOZ_ASSERT(!xpc::WrapperFactory::IsXrayWrapper(proxy),
300 : "Should not have a XrayWrapper here");
301 :
302 :
303 0 : JS::Rooted<JSObject*> expando(cx, GetExpandoObject(proxy));
304 0 : if (expando) {
305 0 : bool b = true;
306 0 : bool ok = JS_HasPropertyById(cx, expando, id, &b);
307 0 : *bp = !!b;
308 0 : if (!ok || *bp) {
309 0 : return ok;
310 : }
311 : }
312 :
313 0 : bool found = false;
314 0 : binding_detail::FakeString name;
315 : bool isSymbol;
316 0 : if (!ConvertIdToString(cx, id, name, isSymbol)) {
317 0 : return false;
318 : }
319 0 : if (!isSymbol) {
320 0 : nsDOMStringMap* self = UnwrapProxy(proxy);
321 0 : DOMString result;
322 0 : self->NamedGetter(NonNullHelper(Constify(name)), found, result);
323 0 : MOZ_ASSERT(!JS_IsExceptionPending(cx));
324 : (void)result;
325 : }
326 :
327 0 : *bp = found;
328 :
329 0 : return true;
330 : }
331 :
332 : bool
333 0 : DOMProxyHandler::get(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<JS::Value> receiver, JS::Handle<jsid> id, JS::MutableHandle<JS::Value> vp) const
334 : {
335 0 : MOZ_ASSERT(!xpc::WrapperFactory::IsXrayWrapper(proxy),
336 : "Should not have a XrayWrapper here");
337 :
338 : { // Scope for expando
339 0 : JS::Rooted<JSObject*> expando(cx, DOMProxyHandler::GetExpandoObject(proxy));
340 0 : if (expando) {
341 : bool hasProp;
342 0 : if (!JS_HasPropertyById(cx, expando, id, &hasProp)) {
343 0 : return false;
344 : }
345 :
346 0 : if (hasProp) {
347 : // Forward the get to the expando object, but our receiver is whatever our
348 : // receiver is.
349 0 : return JS_ForwardGetPropertyTo(cx, expando, id, receiver, vp);
350 : }
351 : }
352 : }
353 :
354 0 : binding_detail::FakeString name;
355 : bool isSymbol;
356 0 : if (!ConvertIdToString(cx, id, name, isSymbol)) {
357 0 : return false;
358 : }
359 0 : if (!isSymbol) {
360 0 : nsDOMStringMap* self = UnwrapProxy(proxy);
361 0 : bool found = false;
362 0 : DOMString result;
363 0 : self->NamedGetter(NonNullHelper(Constify(name)), found, result);
364 0 : MOZ_ASSERT(!JS_IsExceptionPending(cx));
365 :
366 0 : if (found) {
367 0 : if (!xpc::NonVoidStringToJsval(cx, result, vp)) {
368 0 : return false;
369 : }
370 0 : return true;
371 : }
372 : }
373 :
374 : bool foundOnPrototype;
375 0 : if (!GetPropertyOnPrototype(cx, proxy, receiver, id, &foundOnPrototype, vp)) {
376 0 : return false;
377 : }
378 :
379 0 : if (foundOnPrototype) {
380 0 : return true;
381 : }
382 :
383 0 : vp.setUndefined();
384 0 : return true;
385 : }
386 :
387 : const char*
388 0 : DOMProxyHandler::className(JSContext* cx, JS::Handle<JSObject*> proxy) const
389 : {
390 0 : return "DOMStringMap";
391 : }
392 :
393 : bool
394 0 : DOMProxyHandler::finalizeInBackground(const JS::Value& priv) const
395 : {
396 0 : return false;
397 : }
398 :
399 : void
400 0 : DOMProxyHandler::finalize(JSFreeOp* fop, JSObject* proxy) const
401 : {
402 0 : nsDOMStringMap* self = UnwrapPossiblyNotInitializedDOMObject<nsDOMStringMap>(proxy);
403 0 : if (self) {
404 : // Either our proxy created an expando object or not. If it did,
405 : // then we would have preserved ourselves, and hence if we're going
406 : // away so is our C++ object and we should reset its expando value.
407 : // It's possible that in this situation the C++ object's reflector
408 : // pointer has been nulled out, but if not it's pointing to us. If
409 : // our proxy did _not_ create an expando object then it's possible
410 : // that we're no longer the reflector for our C++ object (and
411 : // incremental finalization is finally getting to us), and that in
412 : // the meantime the new reflector has created an expando object.
413 : // In that case we do NOT want to clear the expando pointer in the
414 : // C++ object.
415 : //
416 : // It's important to do this before we ClearWrapper, of course.
417 0 : JSObject* reflector = self->GetWrapperMaybeDead();
418 0 : if (!reflector || reflector == proxy) {
419 0 : self->mExpandoAndGeneration.expando = JS::UndefinedValue();
420 : }
421 0 : ClearWrapper(self, self, proxy);
422 0 : AddForDeferredFinalization<nsDOMStringMap>(self);
423 : }
424 0 : }
425 :
426 : const DOMProxyHandler*
427 0 : DOMProxyHandler::getInstance()
428 : {
429 : static const DOMProxyHandler instance;
430 0 : return &instance;
431 : }
432 :
433 : bool
434 0 : DOMProxyHandler::delete_(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id, JS::ObjectOpResult& opresult) const
435 : {
436 0 : MOZ_ASSERT(!xpc::WrapperFactory::IsXrayWrapper(proxy),
437 : "Should not have a XrayWrapper here");
438 :
439 : // Try named delete only if the named property visibility
440 : // algorithm says the property is visible.
441 0 : bool tryNamedDelete = true;
442 : { // Scope for expando
443 0 : JS::Rooted<JSObject*> expando(cx, DOMProxyHandler::GetExpandoObject(proxy));
444 0 : if (expando) {
445 : bool hasProp;
446 0 : if (!JS_HasPropertyById(cx, expando, id, &hasProp)) {
447 0 : return false;
448 : }
449 0 : tryNamedDelete = !hasProp;
450 : }
451 : }
452 0 : if (tryNamedDelete) {
453 0 : bool found = false;
454 : bool deleteSucceeded;
455 0 : binding_detail::FakeString name;
456 : bool isSymbol;
457 0 : if (!ConvertIdToString(cx, id, name, isSymbol)) {
458 0 : return false;
459 : }
460 0 : if (!isSymbol) {
461 0 : nsDOMStringMap* self = UnwrapProxy(proxy);
462 0 : CustomElementReactionsStack* reactionsStack = GetCustomElementReactionsStack(proxy);
463 0 : Maybe<AutoCEReaction> ceReaction;
464 0 : if (reactionsStack) {
465 0 : ceReaction.emplace(reactionsStack);
466 : }
467 0 : self->NamedDeleter(NonNullHelper(Constify(name)), found);
468 0 : MOZ_ASSERT(!JS_IsExceptionPending(cx));
469 : }
470 0 : deleteSucceeded = true;
471 0 : if (found) {
472 0 : return deleteSucceeded ? opresult.succeed() : opresult.failCantDelete();
473 : }
474 : }
475 :
476 0 : return dom::DOMProxyHandler::delete_(cx, proxy, id, opresult);
477 : }
478 :
479 : bool
480 0 : DOMProxyHandler::setCustom(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id, JS::Handle<JS::Value> v, bool* done) const
481 : {
482 0 : MOZ_ASSERT(!xpc::WrapperFactory::IsXrayWrapper(proxy),
483 : "Should not have a XrayWrapper here");
484 0 : binding_detail::FakeString name;
485 : bool isSymbol;
486 0 : if (!ConvertIdToString(cx, id, name, isSymbol)) {
487 0 : return false;
488 : }
489 0 : if (!isSymbol) {
490 0 : nsDOMStringMap* self = UnwrapProxy(proxy);
491 0 : JS::Rooted<JS::Value> rootedValue(cx, v);
492 0 : binding_detail::FakeString value;
493 0 : if (!ConvertJSValueToString(cx, v, eStringify, eStringify, value)) {
494 0 : return false;
495 : }
496 0 : CustomElementReactionsStack* reactionsStack = GetCustomElementReactionsStack(proxy);
497 0 : Maybe<AutoCEReaction> ceReaction;
498 0 : if (reactionsStack) {
499 0 : ceReaction.emplace(reactionsStack);
500 : }
501 0 : binding_detail::FastErrorResult rv;
502 0 : self->NamedSetter(NonNullHelper(Constify(name)), NonNullHelper(Constify(value)), rv);
503 0 : if (MOZ_UNLIKELY(rv.MaybeSetPendingException(cx))) {
504 0 : return false;
505 : }
506 0 : MOZ_ASSERT(!JS_IsExceptionPending(cx));
507 : }
508 0 : *done = true;
509 0 : return true;
510 : }
511 :
512 : static const js::ClassExtension sClassExtension = PROXY_MAKE_EXT(
513 : _objectMoved
514 : );
515 :
516 : static const DOMJSClass sClass = {
517 : PROXY_CLASS_WITH_EXT("DOMStringMap",
518 : JSCLASS_IS_DOMJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(1),
519 : &sClassExtension),
520 : { prototypes::id::DOMStringMap, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count },
521 : IsBaseOf<nsISupports, nsDOMStringMap >::value,
522 : sNativePropertyHooks,
523 : FindAssociatedGlobalForNative<nsDOMStringMap>::Get,
524 : GetProtoObjectHandle,
525 : GetCCParticipant<nsDOMStringMap>::Get()
526 : };
527 :
528 : bool
529 0 : Wrap(JSContext* aCx, nsDOMStringMap* aObject, nsWrapperCache* aCache, JS::Handle<JSObject*> aGivenProto, JS::MutableHandle<JSObject*> aReflector)
530 : {
531 : MOZ_ASSERT(static_cast<nsDOMStringMap*>(aObject) ==
532 : reinterpret_cast<nsDOMStringMap*>(aObject),
533 : "Multiple inheritance for nsDOMStringMap is broken.");
534 0 : MOZ_ASSERT(ToSupportsIsCorrect(aObject));
535 0 : MOZ_ASSERT_IF(aGivenProto, js::IsObjectInContextCompartment(aGivenProto, aCx));
536 0 : MOZ_ASSERT(!aCache->GetWrapper(),
537 : "You should probably not be using Wrap() directly; use "
538 : "GetOrCreateDOMReflector instead");
539 :
540 0 : MOZ_ASSERT(ToSupportsIsOnPrimaryInheritanceChain(aObject, aCache),
541 : "nsISupports must be on our primary inheritance chain");
542 :
543 0 : JS::Rooted<JSObject*> global(aCx, FindAssociatedGlobal(aCx, aObject->GetParentObject()));
544 0 : if (!global) {
545 0 : return false;
546 : }
547 0 : MOZ_ASSERT(JS_IsGlobalObject(global));
548 0 : MOZ_ASSERT(JS::ObjectIsNotGray(global));
549 :
550 : // That might have ended up wrapping us already, due to the wonders
551 : // of XBL. Check for that, and bail out as needed.
552 0 : aReflector.set(aCache->GetWrapper());
553 0 : if (aReflector) {
554 : #ifdef DEBUG
555 0 : binding_detail::AssertReflectorHasGivenProto(aCx, aReflector, aGivenProto);
556 : #endif // DEBUG
557 0 : return true;
558 : }
559 :
560 0 : JSAutoCompartment ac(aCx, global);
561 0 : JS::Handle<JSObject*> canonicalProto = GetProtoObjectHandle(aCx);
562 0 : if (!canonicalProto) {
563 0 : return false;
564 : }
565 0 : JS::Rooted<JSObject*> proto(aCx);
566 0 : if (aGivenProto) {
567 0 : proto = aGivenProto;
568 : // Unfortunately, while aGivenProto was in the compartment of aCx
569 : // coming in, we changed compartments to that of "parent" so may need
570 : // to wrap the proto here.
571 0 : if (js::GetContextCompartment(aCx) != js::GetObjectCompartment(proto)) {
572 0 : if (!JS_WrapObject(aCx, &proto)) {
573 0 : return false;
574 : }
575 : }
576 : } else {
577 0 : proto = canonicalProto;
578 : }
579 :
580 0 : BindingJSObjectCreator<nsDOMStringMap> creator(aCx);
581 0 : JS::Rooted<JS::Value> expandoValue(aCx, JS::PrivateValue(&aObject->mExpandoAndGeneration));
582 0 : creator.CreateProxyObject(aCx, &sClass.mBase, DOMProxyHandler::getInstance(),
583 0 : proto, aObject, expandoValue, aReflector);
584 0 : if (!aReflector) {
585 0 : return false;
586 : }
587 :
588 :
589 0 : aCache->SetWrapper(aReflector);
590 0 : creator.InitializationSucceeded();
591 :
592 0 : MOZ_ASSERT(aCache->GetWrapperPreserveColor() &&
593 : aCache->GetWrapperPreserveColor() == aReflector);
594 : // If proto != canonicalProto, we have to preserve our wrapper;
595 : // otherwise we won't be able to properly recreate it later, since
596 : // we won't know what proto to use. Note that we don't check
597 : // aGivenProto here, since it's entirely possible (and even
598 : // somewhat common) to have a non-null aGivenProto which is the
599 : // same as canonicalProto.
600 0 : if (proto != canonicalProto) {
601 0 : PreserveWrapper(aObject);
602 : }
603 :
604 0 : return true;
605 : }
606 :
607 : static bool
608 0 : ResolveOwnProperty(JSContext* cx, JS::Handle<JSObject*> wrapper, JS::Handle<JSObject*> obj, JS::Handle<jsid> id, JS::MutableHandle<JS::PropertyDescriptor> desc)
609 : {
610 0 : return js::GetProxyHandler(obj)->getOwnPropertyDescriptor(cx, wrapper, id, desc);
611 : }
612 :
613 : static bool
614 0 : EnumerateOwnProperties(JSContext* cx, JS::Handle<JSObject*> wrapper, JS::Handle<JSObject*> obj, JS::AutoIdVector& props)
615 : {
616 0 : return js::GetProxyHandler(obj)->ownPropertyKeys(cx, wrapper, props);
617 : }
618 :
619 : static bool
620 0 : DeleteNamedProperty(JSContext* cx, JS::Handle<JSObject*> xray, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id, JS::ObjectOpResult& opresult)
621 : {
622 0 : MOZ_ASSERT(xpc::WrapperFactory::IsXrayWrapper(xray));
623 0 : MOZ_ASSERT(js::IsProxy(proxy));
624 0 : MOZ_ASSERT(!xpc::WrapperFactory::IsXrayWrapper(proxy));
625 0 : JSAutoCompartment ac(cx, proxy);
626 : bool deleteSucceeded;
627 0 : bool found = false;
628 0 : binding_detail::FakeString name;
629 : bool isSymbol;
630 0 : if (!ConvertIdToString(cx, id, name, isSymbol)) {
631 0 : return false;
632 : }
633 0 : if (!isSymbol) {
634 0 : nsDOMStringMap* self = UnwrapProxy(proxy);
635 0 : CustomElementReactionsStack* reactionsStack = GetCustomElementReactionsStack(proxy);
636 0 : Maybe<AutoCEReaction> ceReaction;
637 0 : if (reactionsStack) {
638 0 : ceReaction.emplace(reactionsStack);
639 : }
640 0 : self->NamedDeleter(NonNullHelper(Constify(name)), found);
641 0 : MOZ_ASSERT(!JS_IsExceptionPending(cx));
642 : }
643 0 : deleteSucceeded = true;
644 0 : if (!found || deleteSucceeded) {
645 0 : return opresult.succeed();
646 : }
647 0 : return opresult.failCantDelete();
648 : }
649 :
650 : const NativePropertyHooks sNativePropertyHooks[] = { {
651 : ResolveOwnProperty,
652 : EnumerateOwnProperties,
653 : DeleteNamedProperty,
654 : { sNativeProperties.Upcast(), nullptr },
655 : prototypes::id::DOMStringMap,
656 : constructors::id::DOMStringMap,
657 : nullptr,
658 : &DefaultXrayExpandoObjectClass
659 : } };
660 :
661 : void
662 0 : CreateInterfaceObjects(JSContext* aCx, JS::Handle<JSObject*> aGlobal, ProtoAndIfaceCache& aProtoAndIfaceCache, bool aDefineOnGlobal)
663 : {
664 0 : JS::Rooted<JSObject*> parentProto(aCx, JS::GetRealmObjectPrototype(aCx));
665 0 : if (!parentProto) {
666 0 : return;
667 : }
668 :
669 0 : JS::Rooted<JSObject*> constructorProto(aCx, JS::GetRealmFunctionPrototype(aCx));
670 0 : if (!constructorProto) {
671 0 : return;
672 : }
673 :
674 : static bool sIdsInited = false;
675 0 : if (!sIdsInited && NS_IsMainThread()) {
676 0 : if (!InitIds(aCx, sNativeProperties.Upcast())) {
677 0 : return;
678 : }
679 0 : sIdsInited = true;
680 : }
681 :
682 0 : JS::Heap<JSObject*>* protoCache = &aProtoAndIfaceCache.EntrySlotOrCreate(prototypes::id::DOMStringMap);
683 0 : JS::Heap<JSObject*>* interfaceCache = &aProtoAndIfaceCache.EntrySlotOrCreate(constructors::id::DOMStringMap);
684 0 : dom::CreateInterfaceObjects(aCx, aGlobal, parentProto,
685 : &sPrototypeClass.mBase, protoCache,
686 : constructorProto, &sInterfaceObjectClass.mBase, 0, nullptr,
687 : interfaceCache,
688 : sNativeProperties.Upcast(),
689 : nullptr,
690 : "DOMStringMap", aDefineOnGlobal,
691 : nullptr,
692 0 : false);
693 : }
694 :
695 : JS::Handle<JSObject*>
696 0 : GetProtoObjectHandle(JSContext* aCx)
697 : {
698 : /* Get the interface prototype object for this class. This will create the
699 : object as needed. */
700 0 : bool aDefineOnGlobal = true;
701 :
702 : /* Make sure our global is sane. Hopefully we can remove this sometime */
703 0 : JSObject* global = JS::CurrentGlobalOrNull(aCx);
704 0 : if (!(js::GetObjectClass(global)->flags & JSCLASS_DOM_GLOBAL)) {
705 0 : return nullptr;
706 : }
707 :
708 : /* Check to see whether the interface objects are already installed */
709 0 : ProtoAndIfaceCache& protoAndIfaceCache = *GetProtoAndIfaceCache(global);
710 0 : if (!protoAndIfaceCache.HasEntryInSlot(prototypes::id::DOMStringMap)) {
711 0 : JS::Rooted<JSObject*> rootedGlobal(aCx, global);
712 0 : CreateInterfaceObjects(aCx, rootedGlobal, protoAndIfaceCache, aDefineOnGlobal);
713 : }
714 :
715 : /*
716 : * The object might _still_ be null, but that's OK.
717 : *
718 : * Calling fromMarkedLocation() is safe because protoAndIfaceCache is
719 : * traced by TraceProtoAndIfaceCache() and its contents are never
720 : * changed after they have been set.
721 : *
722 : * Calling address() avoids the read read barrier that does gray
723 : * unmarking, but it's not possible for the object to be gray here.
724 : */
725 :
726 0 : const JS::Heap<JSObject*>& entrySlot = protoAndIfaceCache.EntrySlotMustExist(prototypes::id::DOMStringMap);
727 0 : MOZ_ASSERT(JS::ObjectIsNotGray(entrySlot));
728 0 : return JS::Handle<JSObject*>::fromMarkedLocation(entrySlot.address());
729 : }
730 :
731 : JS::Handle<JSObject*>
732 0 : GetConstructorObjectHandle(JSContext* aCx, bool aDefineOnGlobal)
733 : {
734 : /* Get the interface object for this class. This will create the object as
735 : needed. */
736 :
737 : /* Make sure our global is sane. Hopefully we can remove this sometime */
738 0 : JSObject* global = JS::CurrentGlobalOrNull(aCx);
739 0 : if (!(js::GetObjectClass(global)->flags & JSCLASS_DOM_GLOBAL)) {
740 0 : return nullptr;
741 : }
742 :
743 : /* Check to see whether the interface objects are already installed */
744 0 : ProtoAndIfaceCache& protoAndIfaceCache = *GetProtoAndIfaceCache(global);
745 0 : if (!protoAndIfaceCache.HasEntryInSlot(constructors::id::DOMStringMap)) {
746 0 : JS::Rooted<JSObject*> rootedGlobal(aCx, global);
747 0 : CreateInterfaceObjects(aCx, rootedGlobal, protoAndIfaceCache, aDefineOnGlobal);
748 : }
749 :
750 : /*
751 : * The object might _still_ be null, but that's OK.
752 : *
753 : * Calling fromMarkedLocation() is safe because protoAndIfaceCache is
754 : * traced by TraceProtoAndIfaceCache() and its contents are never
755 : * changed after they have been set.
756 : *
757 : * Calling address() avoids the read read barrier that does gray
758 : * unmarking, but it's not possible for the object to be gray here.
759 : */
760 :
761 0 : const JS::Heap<JSObject*>& entrySlot = protoAndIfaceCache.EntrySlotMustExist(constructors::id::DOMStringMap);
762 0 : MOZ_ASSERT(JS::ObjectIsNotGray(entrySlot));
763 0 : return JS::Handle<JSObject*>::fromMarkedLocation(entrySlot.address());
764 : }
765 :
766 : JSObject*
767 0 : GetConstructorObject(JSContext* aCx)
768 : {
769 0 : return GetConstructorObjectHandle(aCx);
770 : }
771 :
772 : } // namespace DOMStringMapBinding
773 :
774 :
775 :
776 : } // namespace dom
777 : } // namespace mozilla
|