Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /* This Source Code Form is subject to the terms of the Mozilla Public
3 : * License, v. 2.0. If a copy of the MPL was not distributed with this
4 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 :
6 : /* Implementation of xptiInterfaceEntry and xptiInterfaceInfo. */
7 :
8 : #include "xptiprivate.h"
9 : #include "mozilla/dom/ScriptSettings.h"
10 : #include "mozilla/DebugOnly.h"
11 : #include "mozilla/XPTInterfaceInfoManager.h"
12 : #include "mozilla/PodOperations.h"
13 : #include "jsapi.h"
14 :
15 : using namespace mozilla;
16 :
17 : /* static */ xptiInterfaceEntry*
18 3849 : xptiInterfaceEntry::Create(const char* name, const nsID& iid,
19 : XPTInterfaceDescriptor* aDescriptor,
20 : xptiTypelibGuts* aTypelib)
21 : {
22 3849 : int namelen = strlen(name);
23 : void* place =
24 3849 : XPT_CALLOC8(gXPTIStructArena, sizeof(xptiInterfaceEntry) + namelen);
25 3849 : if (!place) {
26 0 : return nullptr;
27 : }
28 : return new (place) xptiInterfaceEntry(name, namelen, iid, aDescriptor,
29 3849 : aTypelib);
30 : }
31 :
32 3849 : xptiInterfaceEntry::xptiInterfaceEntry(const char* name,
33 : size_t nameLength,
34 : const nsID& iid,
35 : XPTInterfaceDescriptor* aDescriptor,
36 3849 : xptiTypelibGuts* aTypelib)
37 : : mIID(iid)
38 : , mDescriptor(aDescriptor)
39 : , mTypelib(aTypelib)
40 : , mParent(nullptr)
41 : , mInfo(nullptr)
42 : , mMethodBaseIndex(0)
43 : , mConstantBaseIndex(0)
44 3849 : , mFlags(0)
45 : {
46 3849 : memcpy(mName, name, nameLength);
47 3849 : SetResolvedState(PARTIALLY_RESOLVED);
48 3849 : }
49 :
50 : bool
51 386 : xptiInterfaceEntry::Resolve()
52 : {
53 772 : MutexAutoLock lock(XPTInterfaceInfoManager::GetResolveLock());
54 772 : return ResolveLocked();
55 : }
56 :
57 : bool
58 430 : xptiInterfaceEntry::ResolveLocked()
59 : {
60 430 : int resolvedState = GetResolveState();
61 :
62 430 : if(resolvedState == FULLY_RESOLVED)
63 0 : return true;
64 430 : if(resolvedState == RESOLVE_FAILED)
65 0 : return false;
66 :
67 430 : NS_ASSERTION(GetResolveState() == PARTIALLY_RESOLVED, "bad state!");
68 :
69 : // Finish out resolution by finding parent and Resolving it so
70 : // we can set the info we get from it.
71 :
72 430 : uint16_t parent_index = mDescriptor->parent_interface;
73 :
74 430 : if(parent_index)
75 : {
76 : xptiInterfaceEntry* parent =
77 427 : mTypelib->GetEntryAt(parent_index - 1);
78 :
79 427 : if(!parent || !parent->EnsureResolvedLocked())
80 : {
81 0 : SetResolvedState(RESOLVE_FAILED);
82 0 : return false;
83 : }
84 :
85 427 : mParent = parent;
86 427 : if (parent->GetHasNotXPCOMFlag()) {
87 23 : SetHasNotXPCOMFlag();
88 : } else {
89 3864 : for (uint16_t idx = 0; idx < mDescriptor->num_methods; ++idx) {
90 : nsXPTMethodInfo* method = reinterpret_cast<nsXPTMethodInfo*>(
91 3486 : mDescriptor->method_descriptors + idx);
92 3486 : if (method->IsNotXPCOM()) {
93 26 : SetHasNotXPCOMFlag();
94 26 : break;
95 : }
96 : }
97 : }
98 :
99 :
100 427 : mMethodBaseIndex =
101 854 : parent->mMethodBaseIndex +
102 427 : parent->mDescriptor->num_methods;
103 :
104 427 : mConstantBaseIndex =
105 854 : parent->mConstantBaseIndex +
106 427 : parent->mDescriptor->num_constants;
107 :
108 : }
109 : LOG_RESOLVE(("+ complete resolve of %s\n", mName));
110 :
111 430 : SetResolvedState(FULLY_RESOLVED);
112 430 : return true;
113 : }
114 :
115 : /**************************************************/
116 : // These non-virtual methods handle the delegated nsIInterfaceInfo methods.
117 :
118 : nsresult
119 1171 : xptiInterfaceEntry::GetName(char **name)
120 : {
121 : // It is not necessary to Resolve because this info is read from manifest.
122 1171 : *name = (char*) nsMemory::Clone(mName, strlen(mName)+1);
123 1171 : return *name ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
124 : }
125 :
126 : nsresult
127 0 : xptiInterfaceEntry::GetIID(nsIID **iid)
128 : {
129 : // It is not necessary to Resolve because this info is read from manifest.
130 0 : *iid = (nsIID*) nsMemory::Clone(&mIID, sizeof(nsIID));
131 0 : return *iid ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
132 : }
133 :
134 : nsresult
135 2869 : xptiInterfaceEntry::IsScriptable(bool* result)
136 : {
137 : // It is not necessary to Resolve because this info is read from manifest.
138 2869 : *result = GetScriptableFlag();
139 2869 : return NS_OK;
140 : }
141 :
142 : nsresult
143 758 : xptiInterfaceEntry::IsFunction(bool* result)
144 : {
145 758 : if(!EnsureResolved())
146 0 : return NS_ERROR_UNEXPECTED;
147 :
148 758 : *result = XPT_ID_IS_FUNCTION(mDescriptor->flags);
149 758 : return NS_OK;
150 : }
151 :
152 : nsresult
153 1915 : xptiInterfaceEntry::GetMethodCount(uint16_t* count)
154 : {
155 1915 : if(!EnsureResolved())
156 0 : return NS_ERROR_UNEXPECTED;
157 :
158 3830 : *count = mMethodBaseIndex +
159 1915 : mDescriptor->num_methods;
160 1915 : return NS_OK;
161 : }
162 :
163 : nsresult
164 1823 : xptiInterfaceEntry::GetConstantCount(uint16_t* count)
165 : {
166 1823 : if(!EnsureResolved())
167 0 : return NS_ERROR_UNEXPECTED;
168 :
169 1823 : if(!count)
170 0 : return NS_ERROR_UNEXPECTED;
171 :
172 3646 : *count = mConstantBaseIndex +
173 1823 : mDescriptor->num_constants;
174 1823 : return NS_OK;
175 : }
176 :
177 : nsresult
178 37034 : xptiInterfaceEntry::GetMethodInfo(uint16_t index, const nsXPTMethodInfo** info)
179 : {
180 37034 : if(!EnsureResolved())
181 0 : return NS_ERROR_UNEXPECTED;
182 :
183 37034 : if(index < mMethodBaseIndex)
184 8084 : return mParent->GetMethodInfo(index, info);
185 :
186 57900 : if(index >= mMethodBaseIndex +
187 28950 : mDescriptor->num_methods)
188 : {
189 0 : NS_ERROR("bad param");
190 0 : *info = nullptr;
191 0 : return NS_ERROR_INVALID_ARG;
192 : }
193 :
194 : // else...
195 28950 : *info = reinterpret_cast<nsXPTMethodInfo*>
196 28950 : (&mDescriptor->method_descriptors[index - mMethodBaseIndex]);
197 28950 : return NS_OK;
198 : }
199 :
200 : nsresult
201 0 : xptiInterfaceEntry::GetMethodInfoForName(const char* methodName, uint16_t *index,
202 : const nsXPTMethodInfo** result)
203 : {
204 0 : if(!EnsureResolved())
205 0 : return NS_ERROR_UNEXPECTED;
206 :
207 : // This is a slow algorithm, but this is not expected to be called much.
208 0 : for(uint16_t i = 0; i < mDescriptor->num_methods; ++i)
209 : {
210 : const nsXPTMethodInfo* info;
211 0 : info = reinterpret_cast<nsXPTMethodInfo*>
212 0 : (&mDescriptor->
213 0 : method_descriptors[i]);
214 0 : if (PL_strcmp(methodName, info->GetName()) == 0) {
215 0 : *index = i + mMethodBaseIndex;
216 0 : *result = info;
217 0 : return NS_OK;
218 : }
219 : }
220 :
221 0 : if(mParent)
222 0 : return mParent->GetMethodInfoForName(methodName, index, result);
223 : else
224 : {
225 0 : *index = 0;
226 0 : *result = 0;
227 0 : return NS_ERROR_INVALID_ARG;
228 : }
229 : }
230 :
231 : nsresult
232 4608 : xptiInterfaceEntry::GetConstant(uint16_t index, JS::MutableHandleValue constant,
233 : char** name)
234 : {
235 4608 : if(!EnsureResolved())
236 0 : return NS_ERROR_UNEXPECTED;
237 :
238 4608 : if(index < mConstantBaseIndex)
239 594 : return mParent->GetConstant(index, constant, name);
240 :
241 8028 : if(index >= mConstantBaseIndex +
242 4014 : mDescriptor->num_constants)
243 : {
244 0 : NS_PRECONDITION(0, "bad param");
245 0 : return NS_ERROR_INVALID_ARG;
246 : }
247 :
248 4014 : const auto& c = mDescriptor->const_descriptors[index - mConstantBaseIndex];
249 8028 : AutoJSContext cx;
250 8028 : JS::Rooted<JS::Value> v(cx);
251 4014 : v.setUndefined();
252 :
253 4014 : switch (c.type.prefix.flags) {
254 : case nsXPTType::T_I8:
255 : {
256 0 : v.setInt32(c.value.i8);
257 0 : break;
258 : }
259 : case nsXPTType::T_U8:
260 : {
261 0 : v.setInt32(c.value.ui8);
262 0 : break;
263 : }
264 : case nsXPTType::T_I16:
265 : {
266 168 : v.setInt32(c.value.i16);
267 168 : break;
268 : }
269 : case nsXPTType::T_U16:
270 : {
271 449 : v.setInt32(c.value.ui16);
272 449 : break;
273 : }
274 : case nsXPTType::T_I32:
275 : {
276 656 : v = JS_NumberValue(c.value.i32);
277 656 : break;
278 : }
279 : case nsXPTType::T_U32:
280 : {
281 2741 : v = JS_NumberValue(c.value.ui32);
282 2741 : break;
283 : }
284 : default:
285 : {
286 : #ifdef DEBUG
287 0 : NS_ERROR("Non-numeric constant found in interface.");
288 : #endif
289 : }
290 : }
291 :
292 4014 : constant.set(v);
293 4014 : *name = ToNewCString(nsDependentCString(c.name));
294 :
295 4014 : return NS_OK;
296 : }
297 :
298 : // this is a private helper
299 :
300 : nsresult
301 5676 : xptiInterfaceEntry::GetInterfaceIndexForParam(uint16_t methodIndex,
302 : const nsXPTParamInfo* param,
303 : uint16_t* interfaceIndex)
304 : {
305 5676 : if(!EnsureResolved())
306 0 : return NS_ERROR_UNEXPECTED;
307 :
308 5676 : if(methodIndex < mMethodBaseIndex)
309 0 : return mParent->GetInterfaceIndexForParam(methodIndex, param,
310 0 : interfaceIndex);
311 :
312 11352 : if(methodIndex >= mMethodBaseIndex +
313 5676 : mDescriptor->num_methods)
314 : {
315 0 : NS_ERROR("bad param");
316 0 : return NS_ERROR_INVALID_ARG;
317 : }
318 :
319 5676 : const XPTTypeDescriptor *td = ¶m->type;
320 :
321 5688 : while (XPT_TDP_TAG(td->prefix) == TD_ARRAY) {
322 6 : td = &mDescriptor->additional_types[td->u.array.additional_type];
323 : }
324 :
325 5676 : if(XPT_TDP_TAG(td->prefix) != TD_INTERFACE_TYPE) {
326 0 : NS_ERROR("not an interface");
327 0 : return NS_ERROR_INVALID_ARG;
328 : }
329 :
330 5676 : *interfaceIndex = (td->u.iface.iface_hi8 << 8) | td->u.iface.iface_lo8;
331 5676 : return NS_OK;
332 : }
333 :
334 : nsresult
335 6401 : xptiInterfaceEntry::GetEntryForParam(uint16_t methodIndex,
336 : const nsXPTParamInfo * param,
337 : xptiInterfaceEntry** entry)
338 : {
339 6401 : if(!EnsureResolved())
340 0 : return NS_ERROR_UNEXPECTED;
341 :
342 6401 : if(methodIndex < mMethodBaseIndex)
343 791 : return mParent->GetEntryForParam(methodIndex, param, entry);
344 :
345 5610 : uint16_t interfaceIndex = 0;
346 5610 : nsresult rv = GetInterfaceIndexForParam(methodIndex, param,
347 5610 : &interfaceIndex);
348 5610 : if (NS_FAILED(rv)) {
349 0 : return rv;
350 : }
351 :
352 5610 : xptiInterfaceEntry* theEntry = mTypelib->GetEntryAt(interfaceIndex - 1);
353 :
354 : // This can happen if a declared interface is not available at runtime.
355 5610 : if(!theEntry)
356 : {
357 66 : *entry = nullptr;
358 66 : return NS_ERROR_FAILURE;
359 : }
360 :
361 5544 : *entry = theEntry;
362 5544 : return NS_OK;
363 : }
364 :
365 : already_AddRefed<ShimInterfaceInfo>
366 66 : xptiInterfaceEntry::GetShimForParam(uint16_t methodIndex,
367 : const nsXPTParamInfo* param)
368 : {
369 66 : if(methodIndex < mMethodBaseIndex) {
370 0 : return mParent->GetShimForParam(methodIndex, param);
371 : }
372 :
373 66 : uint16_t interfaceIndex = 0;
374 66 : nsresult rv = GetInterfaceIndexForParam(methodIndex, param,
375 66 : &interfaceIndex);
376 66 : if (NS_FAILED(rv)) {
377 0 : return nullptr;
378 : }
379 :
380 66 : const char* shimName = mTypelib->GetEntryNameAt(interfaceIndex - 1);
381 : RefPtr<ShimInterfaceInfo> shim =
382 132 : ShimInterfaceInfo::MaybeConstruct(shimName, nullptr);
383 66 : return shim.forget();
384 : }
385 :
386 : nsresult
387 0 : xptiInterfaceEntry::GetInfoForParam(uint16_t methodIndex,
388 : const nsXPTParamInfo *param,
389 : nsIInterfaceInfo** info)
390 : {
391 : xptiInterfaceEntry* entry;
392 0 : nsresult rv = GetEntryForParam(methodIndex, param, &entry);
393 0 : if (NS_FAILED(rv)) {
394 0 : RefPtr<ShimInterfaceInfo> shim = GetShimForParam(methodIndex, param);
395 0 : if (!shim) {
396 0 : return rv;
397 : }
398 :
399 0 : shim.forget(info);
400 0 : return NS_OK;
401 : }
402 :
403 0 : *info = entry->InterfaceInfo().take();
404 :
405 0 : return NS_OK;
406 : }
407 :
408 : nsresult
409 0 : xptiInterfaceEntry::GetIIDForParam(uint16_t methodIndex,
410 : const nsXPTParamInfo* param, nsIID** iid)
411 : {
412 : xptiInterfaceEntry* entry;
413 0 : nsresult rv = GetEntryForParam(methodIndex, param, &entry);
414 0 : if (NS_FAILED(rv)) {
415 0 : RefPtr<ShimInterfaceInfo> shim = GetShimForParam(methodIndex, param);
416 0 : if (!shim) {
417 0 : return rv;
418 : }
419 :
420 0 : return shim->GetInterfaceIID(iid);
421 : }
422 0 : return entry->GetIID(iid);
423 : }
424 :
425 : nsresult
426 5610 : xptiInterfaceEntry::GetIIDForParamNoAlloc(uint16_t methodIndex,
427 : const nsXPTParamInfo * param,
428 : nsIID *iid)
429 : {
430 : xptiInterfaceEntry* entry;
431 5610 : nsresult rv = GetEntryForParam(methodIndex, param, &entry);
432 5610 : if (NS_FAILED(rv)) {
433 132 : RefPtr<ShimInterfaceInfo> shim = GetShimForParam(methodIndex, param);
434 66 : if (!shim) {
435 0 : return rv;
436 : }
437 :
438 : const nsIID* shimIID;
439 132 : DebugOnly<nsresult> rv2 = shim->GetIIDShared(&shimIID);
440 66 : MOZ_ASSERT(NS_SUCCEEDED(rv2));
441 66 : *iid = *shimIID;
442 66 : return NS_OK;
443 : }
444 5544 : *iid = entry->mIID;
445 5544 : return NS_OK;
446 : }
447 :
448 : // this is a private helper
449 : nsresult
450 90 : xptiInterfaceEntry::GetTypeInArray(const nsXPTParamInfo* param,
451 : uint16_t dimension,
452 : const XPTTypeDescriptor** type)
453 : {
454 90 : NS_ASSERTION(IsFullyResolved(), "bad state");
455 :
456 90 : const XPTTypeDescriptor *td = ¶m->type;
457 : const XPTTypeDescriptor *additional_types =
458 90 : mDescriptor->additional_types;
459 :
460 180 : for (uint16_t i = 0; i < dimension; i++) {
461 90 : if(XPT_TDP_TAG(td->prefix) != TD_ARRAY) {
462 0 : NS_ERROR("bad dimension");
463 0 : return NS_ERROR_INVALID_ARG;
464 : }
465 90 : td = &additional_types[td->u.array.additional_type];
466 : }
467 :
468 90 : *type = td;
469 90 : return NS_OK;
470 : }
471 :
472 : nsresult
473 96 : xptiInterfaceEntry::GetTypeForParam(uint16_t methodIndex,
474 : const nsXPTParamInfo* param,
475 : uint16_t dimension,
476 : nsXPTType* type)
477 : {
478 96 : if(!EnsureResolved())
479 0 : return NS_ERROR_UNEXPECTED;
480 :
481 96 : if(methodIndex < mMethodBaseIndex)
482 6 : return mParent->
483 12 : GetTypeForParam(methodIndex, param, dimension, type);
484 :
485 180 : if(methodIndex >= mMethodBaseIndex +
486 90 : mDescriptor->num_methods)
487 : {
488 0 : NS_ERROR("bad index");
489 0 : return NS_ERROR_INVALID_ARG;
490 : }
491 :
492 : const XPTTypeDescriptor *td;
493 :
494 90 : if(dimension) {
495 90 : nsresult rv = GetTypeInArray(param, dimension, &td);
496 90 : if(NS_FAILED(rv))
497 0 : return rv;
498 : }
499 : else
500 0 : td = ¶m->type;
501 :
502 90 : *type = nsXPTType(td->prefix);
503 90 : return NS_OK;
504 : }
505 :
506 : nsresult
507 71 : xptiInterfaceEntry::GetSizeIsArgNumberForParam(uint16_t methodIndex,
508 : const nsXPTParamInfo* param,
509 : uint16_t dimension,
510 : uint8_t* argnum)
511 : {
512 71 : if(!EnsureResolved())
513 0 : return NS_ERROR_UNEXPECTED;
514 :
515 71 : if(methodIndex < mMethodBaseIndex)
516 6 : return mParent->
517 12 : GetSizeIsArgNumberForParam(methodIndex, param, dimension, argnum);
518 :
519 130 : if(methodIndex >= mMethodBaseIndex +
520 65 : mDescriptor->num_methods)
521 : {
522 0 : NS_ERROR("bad index");
523 0 : return NS_ERROR_INVALID_ARG;
524 : }
525 :
526 : const XPTTypeDescriptor *td;
527 :
528 65 : if(dimension) {
529 0 : nsresult rv = GetTypeInArray(param, dimension, &td);
530 0 : if(NS_FAILED(rv))
531 0 : return rv;
532 : }
533 : else
534 65 : td = ¶m->type;
535 :
536 : // verify that this is a type that has size_is
537 65 : switch (XPT_TDP_TAG(td->prefix)) {
538 : case TD_ARRAY:
539 65 : *argnum = td->u.array.argnum;
540 65 : break;
541 : case TD_PSTRING_SIZE_IS:
542 : case TD_PWSTRING_SIZE_IS:
543 0 : *argnum = td->u.pstring_is.argnum;
544 0 : break;
545 : default:
546 0 : NS_ERROR("not a size_is");
547 0 : return NS_ERROR_INVALID_ARG;
548 : }
549 :
550 65 : return NS_OK;
551 : }
552 :
553 : nsresult
554 105 : xptiInterfaceEntry::GetInterfaceIsArgNumberForParam(uint16_t methodIndex,
555 : const nsXPTParamInfo* param,
556 : uint8_t* argnum)
557 : {
558 105 : if(!EnsureResolved())
559 0 : return NS_ERROR_UNEXPECTED;
560 :
561 105 : if(methodIndex < mMethodBaseIndex)
562 0 : return mParent->
563 0 : GetInterfaceIsArgNumberForParam(methodIndex, param, argnum);
564 :
565 210 : if(methodIndex >= mMethodBaseIndex +
566 105 : mDescriptor->num_methods)
567 : {
568 0 : NS_ERROR("bad index");
569 0 : return NS_ERROR_INVALID_ARG;
570 : }
571 :
572 105 : const XPTTypeDescriptor *td = ¶m->type;
573 :
574 105 : while (XPT_TDP_TAG(td->prefix) == TD_ARRAY) {
575 0 : td = &mDescriptor->additional_types[td->u.array.additional_type];
576 : }
577 :
578 105 : if(XPT_TDP_TAG(td->prefix) != TD_INTERFACE_IS_TYPE) {
579 0 : NS_ERROR("not an iid_is");
580 0 : return NS_ERROR_INVALID_ARG;
581 : }
582 :
583 105 : *argnum = td->u.interface_is.argnum;
584 105 : return NS_OK;
585 : }
586 :
587 : nsresult
588 482 : xptiInterfaceEntry::IsIID(const nsIID * iid, bool *_retval)
589 : {
590 : // It is not necessary to Resolve because this info is read from manifest.
591 482 : *_retval = mIID.Equals(*iid);
592 482 : return NS_OK;
593 : }
594 :
595 : nsresult
596 3838 : xptiInterfaceEntry::GetNameShared(const char **name)
597 : {
598 : // It is not necessary to Resolve because this info is read from manifest.
599 3838 : *name = mName;
600 3838 : return NS_OK;
601 : }
602 :
603 : nsresult
604 22957 : xptiInterfaceEntry::GetIIDShared(const nsIID * *iid)
605 : {
606 : // It is not necessary to Resolve because this info is read from manifest.
607 22957 : *iid = &mIID;
608 22957 : return NS_OK;
609 : }
610 :
611 : nsresult
612 2433 : xptiInterfaceEntry::HasAncestor(const nsIID * iid, bool *_retval)
613 : {
614 2433 : *_retval = false;
615 :
616 5408 : for(xptiInterfaceEntry* current = this;
617 5408 : current;
618 2975 : current = current->mParent)
619 : {
620 4890 : if(current->mIID.Equals(*iid))
621 : {
622 1915 : *_retval = true;
623 1915 : break;
624 : }
625 2975 : if(!current->EnsureResolved())
626 0 : return NS_ERROR_UNEXPECTED;
627 : }
628 :
629 2433 : return NS_OK;
630 : }
631 :
632 : /***************************************************/
633 :
634 : already_AddRefed<xptiInterfaceInfo>
635 1539 : xptiInterfaceEntry::InterfaceInfo()
636 : {
637 : #ifdef DEBUG
638 1539 : XPTInterfaceInfoManager::GetSingleton()->mWorkingSet.mTableReentrantMonitor.
639 1539 : AssertCurrentThreadIn();
640 : #endif
641 :
642 1539 : if(!mInfo)
643 : {
644 458 : mInfo = new xptiInterfaceInfo(this);
645 : }
646 :
647 3078 : RefPtr<xptiInterfaceInfo> info = mInfo;
648 3078 : return info.forget();
649 : }
650 :
651 : void
652 0 : xptiInterfaceEntry::LockedInvalidateInterfaceInfo()
653 : {
654 0 : if(mInfo)
655 : {
656 0 : mInfo->Invalidate();
657 0 : mInfo = nullptr;
658 : }
659 0 : }
660 :
661 : bool
662 21 : xptiInterfaceInfo::BuildParent()
663 : {
664 21 : mozilla::ReentrantMonitorAutoEnter monitor(XPTInterfaceInfoManager::GetSingleton()->
665 42 : mWorkingSet.mTableReentrantMonitor);
666 21 : NS_ASSERTION(mEntry &&
667 : mEntry->IsFullyResolved() &&
668 : !mParent &&
669 : mEntry->Parent(),
670 : "bad BuildParent call");
671 21 : mParent = mEntry->Parent()->InterfaceInfo();
672 42 : return true;
673 : }
674 :
675 : /***************************************************************************/
676 :
677 4190 : NS_IMPL_QUERY_INTERFACE(xptiInterfaceInfo, nsIInterfaceInfo)
678 :
679 458 : xptiInterfaceInfo::xptiInterfaceInfo(xptiInterfaceEntry* entry)
680 458 : : mEntry(entry)
681 : {
682 458 : }
683 :
684 130 : xptiInterfaceInfo::~xptiInterfaceInfo()
685 : {
686 65 : NS_ASSERTION(!mEntry, "bad state in dtor");
687 65 : }
688 :
689 : void
690 0 : xptiInterfaceInfo::Invalidate()
691 : {
692 0 : mParent = nullptr;
693 0 : mEntry = nullptr;
694 0 : }
695 :
696 : MozExternalRefCountType
697 8422 : xptiInterfaceInfo::AddRef(void)
698 : {
699 8422 : nsrefcnt cnt = ++mRefCnt;
700 8422 : NS_LOG_ADDREF(this, cnt, "xptiInterfaceInfo", sizeof(*this));
701 8422 : return cnt;
702 : }
703 :
704 : MozExternalRefCountType
705 7352 : xptiInterfaceInfo::Release(void)
706 : {
707 7352 : xptiInterfaceEntry* entry = mEntry;
708 7352 : nsrefcnt cnt = --mRefCnt;
709 7352 : NS_LOG_RELEASE(this, cnt, "xptiInterfaceInfo");
710 7352 : if(!cnt)
711 : {
712 : mozilla::ReentrantMonitorAutoEnter monitor(XPTInterfaceInfoManager::
713 65 : GetSingleton()->mWorkingSet.
714 130 : mTableReentrantMonitor);
715 :
716 : // If InterfaceInfo added and *released* a reference before we
717 : // acquired the monitor then 'this' might already be dead. In that
718 : // case we would not want to try to access any instance data. We
719 : // would want to bail immediately. If 'this' is already dead then the
720 : // entry will no longer have a pointer to 'this'. So, we can protect
721 : // ourselves from danger without more aggressive locking.
722 65 : if(entry && !entry->InterfaceInfoEquals(this))
723 0 : return 0;
724 :
725 : // If InterfaceInfo added a reference before we acquired the monitor
726 : // then we want to bail out of here without destorying the object.
727 65 : if(mRefCnt)
728 0 : return 1;
729 :
730 65 : if(mEntry)
731 : {
732 65 : mEntry->LockedInterfaceInfoDeathNotification();
733 65 : mEntry = nullptr;
734 : }
735 :
736 65 : delete this;
737 65 : return 0;
738 : }
739 7287 : return cnt;
740 : }
741 :
742 : /***************************************************************************/
|