nsXBLMaybeCompiled.h 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  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. #ifndef nsXBLMaybeCompiled_h__
  6. #define nsXBLMaybeCompiled_h__
  7. #include "js/GCAPI.h"
  8. /*
  9. * A union containing either a pointer representing uncompiled source or a
  10. * JSObject* representing the compiled result. The class is templated on the
  11. * source object type.
  12. *
  13. * The purpose of abstracting this as a separate class is to allow it to be
  14. * wrapped in a JS::Heap<T> to correctly handle post-barriering of the JSObject
  15. * pointer, when present.
  16. *
  17. * No implementation of rootKind() is provided, which prevents
  18. * Root<nsXBLMaybeCompiled<UncompiledT>> from being used.
  19. */
  20. template <class UncompiledT>
  21. class nsXBLMaybeCompiled
  22. {
  23. public:
  24. nsXBLMaybeCompiled() : mUncompiled(BIT_UNCOMPILED) {}
  25. explicit nsXBLMaybeCompiled(UncompiledT* uncompiled)
  26. : mUncompiled(reinterpret_cast<uintptr_t>(uncompiled) | BIT_UNCOMPILED) {}
  27. explicit nsXBLMaybeCompiled(JSObject* compiled) : mCompiled(compiled) {}
  28. bool IsCompiled() const
  29. {
  30. return !(mUncompiled & BIT_UNCOMPILED);
  31. }
  32. UncompiledT* GetUncompiled() const
  33. {
  34. MOZ_ASSERT(!IsCompiled(), "Attempt to get compiled function as uncompiled");
  35. uintptr_t unmasked = mUncompiled & ~BIT_UNCOMPILED;
  36. return reinterpret_cast<UncompiledT*>(unmasked);
  37. }
  38. JSObject* GetJSFunction() const
  39. {
  40. MOZ_ASSERT(IsCompiled(), "Attempt to get uncompiled function as compiled");
  41. if (mCompiled) {
  42. JS::ExposeObjectToActiveJS(mCompiled);
  43. }
  44. return mCompiled;
  45. }
  46. // This is appropriate for use in tracing methods, etc.
  47. JSObject* GetJSFunctionPreserveColor() const
  48. {
  49. MOZ_ASSERT(IsCompiled(), "Attempt to get uncompiled function as compiled");
  50. return mCompiled;
  51. }
  52. private:
  53. JSObject*& UnsafeGetJSFunction()
  54. {
  55. MOZ_ASSERT(IsCompiled(), "Attempt to get uncompiled function as compiled");
  56. return mCompiled;
  57. }
  58. enum { BIT_UNCOMPILED = 1 << 0 };
  59. union
  60. {
  61. // An pointer that represents the function before being compiled, with
  62. // BIT_UNCOMPILED set.
  63. uintptr_t mUncompiled;
  64. // The JS object for the compiled result.
  65. JSObject* mCompiled;
  66. };
  67. friend struct js::BarrierMethods<nsXBLMaybeCompiled<UncompiledT>>;
  68. };
  69. /* Add support for JS::Heap<nsXBLMaybeCompiled>. */
  70. namespace JS {
  71. template <class UncompiledT>
  72. struct GCPolicy<nsXBLMaybeCompiled<UncompiledT>>
  73. {
  74. static nsXBLMaybeCompiled<UncompiledT> initial() { return nsXBLMaybeCompiled<UncompiledT>(); }
  75. };
  76. } // namespace JS
  77. namespace js {
  78. template <class UncompiledT>
  79. struct BarrierMethods<nsXBLMaybeCompiled<UncompiledT>>
  80. {
  81. typedef struct BarrierMethods<JSObject *> Base;
  82. static void postBarrier(nsXBLMaybeCompiled<UncompiledT>* functionp,
  83. nsXBLMaybeCompiled<UncompiledT> prev,
  84. nsXBLMaybeCompiled<UncompiledT> next)
  85. {
  86. if (next.IsCompiled()) {
  87. Base::postBarrier(&functionp->UnsafeGetJSFunction(),
  88. prev.IsCompiled() ? prev.UnsafeGetJSFunction() : nullptr,
  89. next.UnsafeGetJSFunction());
  90. } else if (prev.IsCompiled()) {
  91. Base::postBarrier(&prev.UnsafeGetJSFunction(),
  92. prev.UnsafeGetJSFunction(),
  93. nullptr);
  94. }
  95. }
  96. static void exposeToJS(nsXBLMaybeCompiled<UncompiledT> fun) {
  97. if (fun.IsCompiled()) {
  98. JS::ExposeObjectToActiveJS(fun.UnsafeGetJSFunction());
  99. }
  100. }
  101. };
  102. template <class T>
  103. struct IsHeapConstructibleType<nsXBLMaybeCompiled<T>>
  104. { // Yes, this is the exception to the rule. Sorry.
  105. static const bool value = true;
  106. };
  107. template <class UncompiledT>
  108. class HeapBase<nsXBLMaybeCompiled<UncompiledT>>
  109. {
  110. const JS::Heap<nsXBLMaybeCompiled<UncompiledT>>& wrapper() const {
  111. return *static_cast<const JS::Heap<nsXBLMaybeCompiled<UncompiledT>>*>(this);
  112. }
  113. JS::Heap<nsXBLMaybeCompiled<UncompiledT>>& wrapper() {
  114. return *static_cast<JS::Heap<nsXBLMaybeCompiled<UncompiledT>>*>(this);
  115. }
  116. const nsXBLMaybeCompiled<UncompiledT>* extract() const {
  117. return wrapper().address();
  118. }
  119. nsXBLMaybeCompiled<UncompiledT>* extract() {
  120. return wrapper().unsafeGet();
  121. }
  122. public:
  123. bool IsCompiled() const { return extract()->IsCompiled(); }
  124. UncompiledT* GetUncompiled() const { return extract()->GetUncompiled(); }
  125. JSObject* GetJSFunction() const { return extract()->GetJSFunction(); }
  126. JSObject* GetJSFunctionPreserveColor() const { return extract()->GetJSFunctionPreserveColor(); }
  127. void SetUncompiled(UncompiledT* source) {
  128. wrapper() = nsXBLMaybeCompiled<UncompiledT>(source);
  129. }
  130. void SetJSFunction(JSObject* function) {
  131. wrapper() = nsXBLMaybeCompiled<UncompiledT>(function);
  132. }
  133. JS::Heap<JSObject*>& AsHeapObject()
  134. {
  135. MOZ_ASSERT(extract()->IsCompiled());
  136. return *reinterpret_cast<JS::Heap<JSObject*>*>(this);
  137. }
  138. };
  139. } /* namespace js */
  140. #endif // nsXBLMaybeCompiled_h__