summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatt A. Tobin <email@mattatobin.com>2022-05-29 00:47:25 -0500
committerMatt A. Tobin <email@mattatobin.com>2022-05-29 00:47:25 -0500
commitf11b40c3ab4a5a766b0b71ab1e9a6199b23bbfeb (patch)
tree7b10fdf57c04235448662d0256ef76fa48a1d076
parent5310bcfbad6c8687d0bdbe5e49fb73858dcc1631 (diff)
downloadaura-central-f11b40c3ab4a5a766b0b71ab1e9a6199b23bbfeb.tar.gz
[JS:Engine] Remove the use of tagged shape pointers
-rw-r--r--dom/bindings/RootedOwningNonNull.h15
-rw-r--r--dom/bindings/RootedRefPtr.h13
-rw-r--r--dom/plugins/base/nsJSNPRuntime.cpp2
-rw-r--r--dom/xbl/nsXBLMaybeCompiled.h12
-rw-r--r--js/ipc/JavaScriptShared.cpp2
-rw-r--r--js/public/Class.h113
-rw-r--r--js/public/GCHashTable.h76
-rw-r--r--js/public/GCVariant.h36
-rw-r--r--js/public/GCVector.h36
-rw-r--r--js/public/RootingAPI.h283
-rw-r--r--js/public/SweepingAPI.h7
-rw-r--r--js/public/Value.h52
-rw-r--r--js/src/NamespaceImports.h2
-rw-r--r--js/src/builtin/MapObject.h20
-rw-r--r--js/src/builtin/Object.cpp14
-rw-r--r--js/src/builtin/TypedObject.cpp6
-rw-r--r--js/src/builtin/TypedObject.h2
-rw-r--r--js/src/ds/TraceableFifo.h54
-rw-r--r--js/src/gc/Barrier.h79
-rw-r--r--js/src/gc/Heap.h7
-rw-r--r--js/src/gc/Marking.cpp2
-rw-r--r--js/src/gc/Marking.h8
-rw-r--r--js/src/jit/BaselineIC.cpp40
-rw-r--r--js/src/jit/CacheIR.cpp6
-rw-r--r--js/src/jit/IonCaches.cpp93
-rw-r--r--js/src/jit/IonCaches.h4
-rw-r--r--js/src/jit/SharedIC.cpp15
-rw-r--r--js/src/jit/SharedIC.h2
-rw-r--r--js/src/jit/VMFunctions.cpp6
-rw-r--r--js/src/jsapi-tests/testGCExactRooting.cpp17
-rw-r--r--js/src/jsapi-tests/testGCHeapPostBarriers.cpp108
-rw-r--r--js/src/jsapi.cpp4
-rw-r--r--js/src/jsapi.h44
-rw-r--r--js/src/jscompartment.cpp5
-rw-r--r--js/src/jsfriendapi.h2
-rw-r--r--js/src/jsobj.cpp104
-rw-r--r--js/src/jsobj.h31
-rw-r--r--js/src/jsobjinlines.h6
-rw-r--r--js/src/json.cpp4
-rw-r--r--js/src/proxy/Proxy.cpp6
-rw-r--r--js/src/vm/ArrayBufferObject.cpp4
-rw-r--r--js/src/vm/ArrayBufferObject.h17
-rw-r--r--js/src/vm/Debugger.cpp8
-rw-r--r--js/src/vm/EnvironmentObject.cpp12
-rw-r--r--js/src/vm/EnvironmentObject.h2
-rw-r--r--js/src/vm/GeneratorObject.cpp10
-rw-r--r--js/src/vm/Interpreter-inl.h32
-rw-r--r--js/src/vm/Interpreter.cpp57
-rw-r--r--js/src/vm/JSONParser.h9
-rw-r--r--js/src/vm/NativeObject-inl.h55
-rw-r--r--js/src/vm/NativeObject.cpp142
-rw-r--r--js/src/vm/NativeObject.h2
-rw-r--r--js/src/vm/ObjectGroup.cpp2
-rw-r--r--js/src/vm/SavedStacks.h51
-rw-r--r--js/src/vm/Scope.h96
-rw-r--r--js/src/vm/Shape-inl.h8
-rw-r--r--js/src/vm/Shape.cpp7
-rw-r--r--js/src/vm/Shape.h65
-rw-r--r--js/src/vm/SharedMem.h4
-rw-r--r--js/src/vm/String.h2
-rw-r--r--js/src/vm/TaggedProto.h22
-rw-r--r--js/src/vm/UnboxedObject.cpp12
-rw-r--r--js/src/vm/UnboxedObject.h4
-rw-r--r--js/xpconnect/src/XPCInlines.h2
-rw-r--r--js/xpconnect/src/XPCWrappedNative.cpp2
-rw-r--r--js/xpconnect/src/XPCWrappedNativeProto.cpp4
66 files changed, 1066 insertions, 903 deletions
diff --git a/dom/bindings/RootedOwningNonNull.h b/dom/bindings/RootedOwningNonNull.h
index 13424d155..387a70734 100644
--- a/dom/bindings/RootedOwningNonNull.h
+++ b/dom/bindings/RootedOwningNonNull.h
@@ -50,21 +50,12 @@ struct GCPolicy<mozilla::OwningNonNull<T>>
} // namespace JS
namespace js {
-template<typename T>
-struct RootedBase<mozilla::OwningNonNull<T>>
+template<typename T, typename Wrapper>
+struct WrappedPtrOperations<mozilla::OwningNonNull<T>, Wrapper>
{
- typedef mozilla::OwningNonNull<T> SmartPtrType;
-
- operator SmartPtrType& () const
- {
- auto& self = *static_cast<const JS::Rooted<SmartPtrType>*>(this);
- return self.get();
- }
-
operator T& () const
{
- auto& self = *static_cast<const JS::Rooted<SmartPtrType>*>(this);
- return self.get();
+ return static_cast<const Wrapper*>(this)->get();
}
};
} // namespace js
diff --git a/dom/bindings/RootedRefPtr.h b/dom/bindings/RootedRefPtr.h
index 34f2da5c9..2563d4649 100644
--- a/dom/bindings/RootedRefPtr.h
+++ b/dom/bindings/RootedRefPtr.h
@@ -38,19 +38,12 @@ struct GCPolicy<RefPtr<T>>
} // namespace JS
namespace js {
-template<typename T>
-struct RootedBase<RefPtr<T>>
+template<typename T, typename Wrapper>
+struct WrappedPtrOperations<RefPtr<T>, Wrapper>
{
- operator RefPtr<T>& () const
- {
- auto& self = *static_cast<const JS::Rooted<RefPtr<T>>*>(this);
- return self.get();
- }
-
operator T*() const
{
- auto& self = *static_cast<const JS::Rooted<RefPtr<T>>*>(this);
- return self.get();
+ return static_cast<const Wrapper*>(this)->get();
}
};
} // namespace js
diff --git a/dom/plugins/base/nsJSNPRuntime.cpp b/dom/plugins/base/nsJSNPRuntime.cpp
index 1d42c18d6..7a118cae3 100644
--- a/dom/plugins/base/nsJSNPRuntime.cpp
+++ b/dom/plugins/base/nsJSNPRuntime.cpp
@@ -1747,7 +1747,7 @@ NPObjWrapper_ObjectMoved(JSObject *obj, const JSObject *old)
auto entry =
static_cast<NPObjWrapperHashEntry*>(sNPObjWrappers->Search(npobj));
MOZ_ASSERT(entry && entry->mJSObj);
- MOZ_ASSERT(entry->mJSObj.unbarrieredGetPtr() == old);
+ MOZ_ASSERT(entry->mJSObj == old);
entry->mJSObj = obj;
}
diff --git a/dom/xbl/nsXBLMaybeCompiled.h b/dom/xbl/nsXBLMaybeCompiled.h
index 4bd7f8396..d9d16fdfb 100644
--- a/dom/xbl/nsXBLMaybeCompiled.h
+++ b/dom/xbl/nsXBLMaybeCompiled.h
@@ -126,15 +126,15 @@ struct IsHeapConstructibleType<nsXBLMaybeCompiled<T>>
static const bool value = true;
};
-template <class UncompiledT>
-class HeapBase<nsXBLMaybeCompiled<UncompiledT>>
+template <class UncompiledT, class Wrapper>
+class HeapBase<nsXBLMaybeCompiled<UncompiledT>, Wrapper>
{
- const JS::Heap<nsXBLMaybeCompiled<UncompiledT>>& wrapper() const {
- return *static_cast<const JS::Heap<nsXBLMaybeCompiled<UncompiledT>>*>(this);
+ const Wrapper& wrapper() const {
+ return *static_cast<const Wrapper*>(this);
}
- JS::Heap<nsXBLMaybeCompiled<UncompiledT>>& wrapper() {
- return *static_cast<JS::Heap<nsXBLMaybeCompiled<UncompiledT>>*>(this);
+ Wrapper& wrapper() {
+ return *static_cast<Wrapper*>(this);
}
const nsXBLMaybeCompiled<UncompiledT>* extract() const {
diff --git a/js/ipc/JavaScriptShared.cpp b/js/ipc/JavaScriptShared.cpp
index 6ec339e49..6dfb00bc5 100644
--- a/js/ipc/JavaScriptShared.cpp
+++ b/js/ipc/JavaScriptShared.cpp
@@ -100,7 +100,7 @@ IdToObjectMap::has(const ObjectId& id, const JSObject* obj) const
auto p = table_.lookup(id);
if (!p)
return false;
- return p->value().unbarrieredGet() == obj;
+ return p->value() == obj;
}
#endif
diff --git a/js/public/Class.h b/js/public/Class.h
index 6f1960a30..1dd03a182 100644
--- a/js/public/Class.h
+++ b/js/public/Class.h
@@ -271,8 +271,119 @@ class ObjectOpResult
}
};
+class PropertyResult
+{
+ union {
+ js::Shape* shape_;
+ uintptr_t bits_;
+ };
+
+ static const uintptr_t NotFound = 0;
+ static const uintptr_t NonNativeProperty = 1;
+ static const uintptr_t DenseOrTypedArrayElement = 1;
+
+ public:
+ PropertyResult() : bits_(NotFound) {}
+
+ explicit PropertyResult(js::Shape* propertyShape)
+ : shape_(propertyShape)
+ {
+ MOZ_ASSERT(!isFound() || isNativeProperty());
+ }
+
+ explicit operator bool() const {
+ return isFound();
+ }
+
+ bool isFound() const {
+ return bits_ != NotFound;
+ }
+
+ bool isNonNativeProperty() const {
+ return bits_ == NonNativeProperty;
+ }
+
+ bool isDenseOrTypedArrayElement() const {
+ return bits_ == DenseOrTypedArrayElement;
+ }
+
+ bool isNativeProperty() const {
+ return isFound() && !isNonNativeProperty();
+ }
+
+ js::Shape* maybeShape() const {
+ MOZ_ASSERT(!isNonNativeProperty());
+ return isFound() ? shape_ : nullptr;
+ }
+
+ js::Shape* shape() const {
+ MOZ_ASSERT(isNativeProperty());
+ return shape_;
+ }
+
+ void setNotFound() {
+ bits_ = NotFound;
+ }
+
+ void setNativeProperty(js::Shape* propertyShape) {
+ shape_ = propertyShape;
+ MOZ_ASSERT(isNativeProperty());
+ }
+
+ void setNonNativeProperty() {
+ bits_ = NonNativeProperty;
+ }
+
+ void setDenseOrTypedArrayElement() {
+ bits_ = DenseOrTypedArrayElement;
+ }
+
+ void trace(JSTracer* trc);
+};
+
} // namespace JS
+namespace js {
+
+template <class Wrapper>
+class WrappedPtrOperations<JS::PropertyResult, Wrapper>
+{
+ const JS::PropertyResult& value() const { return static_cast<const Wrapper*>(this)->get(); }
+
+ public:
+ bool isFound() const { return value().isFound(); }
+ explicit operator bool() const { return bool(value()); }
+ js::Shape* maybeShape() const { return value().maybeShape(); }
+ js::Shape* shape() const { return value().shape(); }
+ bool isNativeProperty() const { return value().isNativeProperty(); }
+ bool isNonNativeProperty() const { return value().isNonNativeProperty(); }
+ bool isDenseOrTypedArrayElement() const { return value().isDenseOrTypedArrayElement(); }
+ js::Shape* asTaggedShape() const { return value().asTaggedShape(); }
+};
+
+template <class Wrapper>
+class MutableWrappedPtrOperations<JS::PropertyResult, Wrapper>
+ : public WrappedPtrOperations<JS::PropertyResult, Wrapper>
+{
+ JS::PropertyResult& value() { return static_cast<Wrapper*>(this)->get(); }
+
+ public:
+ void setNotFound() {
+ value().setNotFound();
+ }
+ void setNativeProperty(js::Shape* shape) {
+ value().setNativeProperty(shape);
+ }
+ void setNonNativeProperty() {
+ value().setNonNativeProperty();
+ }
+ void setDenseOrTypedArrayElement() {
+ value().setDenseOrTypedArrayElement();
+ }
+};
+
+} // namespace js
+
// JSClass operation signatures.
/**
@@ -428,7 +539,7 @@ namespace js {
typedef bool
(* LookupPropertyOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id,
- JS::MutableHandleObject objp, JS::MutableHandle<Shape*> propp);
+ JS::MutableHandleObject objp, JS::MutableHandle<JS::PropertyResult> propp);
typedef bool
(* DefinePropertyOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id,
JS::Handle<JS::PropertyDescriptor> desc,
diff --git a/js/public/GCHashTable.h b/js/public/GCHashTable.h
index 4de1c39a8..3e647ed10 100644
--- a/js/public/GCHashTable.h
+++ b/js/public/GCHashTable.h
@@ -133,13 +133,13 @@ class GCRekeyableHashMap : public JS::GCHashMap<Key, Value, HashPolicy, AllocPol
}
};
-template <typename Outer, typename... Args>
-class GCHashMapOperations
+template <typename Wrapper, typename... Args>
+class WrappedPtrOperations<JS::GCHashMap<Args...>, Wrapper>
{
using Map = JS::GCHashMap<Args...>;
using Lookup = typename Map::Lookup;
- const Map& map() const { return static_cast<const Outer*>(this)->get(); }
+ const Map& map() const { return static_cast<const Wrapper*>(this)->get(); }
public:
using AddPtr = typename Map::AddPtr;
@@ -162,18 +162,18 @@ class GCHashMapOperations
}
};
-template <typename Outer, typename... Args>
-class MutableGCHashMapOperations
- : public GCHashMapOperations<Outer, Args...>
+template <typename Wrapper, typename... Args>
+class MutableWrappedPtrOperations<JS::GCHashMap<Args...>, Wrapper>
+ : public WrappedPtrOperations<JS::GCHashMap<Args...>, Wrapper>
{
using Map = JS::GCHashMap<Args...>;
using Lookup = typename Map::Lookup;
- Map& map() { return static_cast<Outer*>(this)->get(); }
+ Map& map() { return static_cast<Wrapper*>(this)->get(); }
public:
using AddPtr = typename Map::AddPtr;
- struct Enum : public Map::Enum { explicit Enum(Outer& o) : Map::Enum(o.map()) {} };
+ struct Enum : public Map::Enum { explicit Enum(Wrapper& o) : Map::Enum(o.map()) {} };
using Ptr = typename Map::Ptr;
using Range = typename Map::Range;
@@ -210,26 +210,6 @@ class MutableGCHashMapOperations
}
};
-template <typename A, typename B, typename C, typename D, typename E>
-class RootedBase<JS::GCHashMap<A,B,C,D,E>>
- : public MutableGCHashMapOperations<JS::Rooted<JS::GCHashMap<A,B,C,D,E>>, A,B,C,D,E>
-{};
-
-template <typename A, typename B, typename C, typename D, typename E>
-class MutableHandleBase<JS::GCHashMap<A,B,C,D,E>>
- : public MutableGCHashMapOperations<JS::MutableHandle<JS::GCHashMap<A,B,C,D,E>>, A,B,C,D,E>
-{};
-
-template <typename A, typename B, typename C, typename D, typename E>
-class HandleBase<JS::GCHashMap<A,B,C,D,E>>
- : public GCHashMapOperations<JS::Handle<JS::GCHashMap<A,B,C,D,E>>, A,B,C,D,E>
-{};
-
-template <typename A, typename B, typename C, typename D, typename E>
-class WeakCacheBase<JS::GCHashMap<A,B,C,D,E>>
- : public MutableGCHashMapOperations<JS::WeakCache<JS::GCHashMap<A,B,C,D,E>>, A,B,C,D,E>
-{};
-
} // namespace js
namespace JS {
@@ -291,13 +271,13 @@ class GCHashSet : public js::HashSet<T, HashPolicy, AllocPolicy>
namespace js {
-template <typename Outer, typename... Args>
-class GCHashSetOperations
+template <typename Wrapper, typename... Args>
+class WrappedPtrOperations<JS::GCHashSet<Args...>, Wrapper>
{
using Set = JS::GCHashSet<Args...>;
using Lookup = typename Set::Lookup;
- const Set& set() const { return static_cast<const Outer*>(this)->get(); }
+ const Set& set() const { return static_cast<const Wrapper*>(this)->get(); }
public:
using AddPtr = typename Set::AddPtr;
@@ -321,19 +301,19 @@ class GCHashSetOperations
}
};
-template <typename Outer, typename... Args>
-class MutableGCHashSetOperations
- : public GCHashSetOperations<Outer, Args...>
+template <typename Wrapper, typename... Args>
+class MutableWrappedPtrOperations<JS::GCHashSet<Args...>, Wrapper>
+ : public WrappedPtrOperations<JS::GCHashSet<Args...>, Wrapper>
{
using Set = JS::GCHashSet<Args...>;
using Lookup = typename Set::Lookup;
- Set& set() { return static_cast<Outer*>(this)->get(); }
+ Set& set() { return static_cast<Wrapper*>(this)->get(); }
public:
using AddPtr = typename Set::AddPtr;
using Entry = typename Set::Entry;
- struct Enum : public Set::Enum { explicit Enum(Outer& o) : Set::Enum(o.set()) {} };
+ struct Enum : public Set::Enum { explicit Enum(Wrapper& o) : Set::Enum(o.set()) {} };
using Ptr = typename Set::Ptr;
using Range = typename Set::Range;
@@ -369,30 +349,6 @@ class MutableGCHashSetOperations
}
};
-template <typename T, typename HP, typename AP>
-class RootedBase<JS::GCHashSet<T, HP, AP>>
- : public MutableGCHashSetOperations<JS::Rooted<JS::GCHashSet<T, HP, AP>>, T, HP, AP>
-{
-};
-
-template <typename T, typename HP, typename AP>
-class MutableHandleBase<JS::GCHashSet<T, HP, AP>>
- : public MutableGCHashSetOperations<JS::MutableHandle<JS::GCHashSet<T, HP, AP>>, T, HP, AP>
-{
-};
-
-template <typename T, typename HP, typename AP>
-class HandleBase<JS::GCHashSet<T, HP, AP>>
- : public GCHashSetOperations<JS::Handle<JS::GCHashSet<T, HP, AP>>, T, HP, AP>
-{
-};
-
-template <typename T, typename HP, typename AP>
-class WeakCacheBase<JS::GCHashSet<T, HP, AP>>
- : public MutableGCHashSetOperations<JS::WeakCache<JS::GCHashSet<T, HP, AP>>, T, HP, AP>
-{
-};
-
} /* namespace js */
#endif /* GCHashTable_h */
diff --git a/js/public/GCVariant.h b/js/public/GCVariant.h
index 43f2957fe..3ec40df5c 100644
--- a/js/public/GCVariant.h
+++ b/js/public/GCVariant.h
@@ -123,13 +123,13 @@ struct GCPolicy<mozilla::Variant<Ts...>>
namespace js {
-template <typename Outer, typename... Ts>
-class GCVariantOperations
+template <typename Wrapper, typename... Ts>
+class WrappedPtrOperations<mozilla::Variant<Ts...>, Wrapper>
{
using Impl = JS::detail::GCVariantImplementation<Ts...>;
using Variant = mozilla::Variant<Ts...>;
- const Variant& variant() const { return static_cast<const Outer*>(this)->get(); }
+ const Variant& variant() const { return static_cast<const Wrapper*>(this)->get(); }
public:
template <typename T>
@@ -149,15 +149,15 @@ class GCVariantOperations
}
};
-template <typename Outer, typename... Ts>
-class MutableGCVariantOperations
- : public GCVariantOperations<Outer, Ts...>
+template <typename Wrapper, typename... Ts>
+class MutableWrappedPtrOperations<mozilla::Variant<Ts...>, Wrapper>
+ : public WrappedPtrOperations<mozilla::Variant<Ts...>, Wrapper>
{
using Impl = JS::detail::GCVariantImplementation<Ts...>;
using Variant = mozilla::Variant<Ts...>;
- const Variant& variant() const { return static_cast<const Outer*>(this)->get(); }
- Variant& variant() { return static_cast<Outer*>(this)->get(); }
+ const Variant& variant() const { return static_cast<const Wrapper*>(this)->get(); }
+ Variant& variant() { return static_cast<Wrapper*>(this)->get(); }
public:
template <typename T>
@@ -172,26 +172,6 @@ class MutableGCVariantOperations
}
};
-template <typename... Ts>
-class RootedBase<mozilla::Variant<Ts...>>
- : public MutableGCVariantOperations<JS::Rooted<mozilla::Variant<Ts...>>, Ts...>
-{ };
-
-template <typename... Ts>
-class MutableHandleBase<mozilla::Variant<Ts...>>
- : public MutableGCVariantOperations<JS::MutableHandle<mozilla::Variant<Ts...>>, Ts...>
-{ };
-
-template <typename... Ts>
-class HandleBase<mozilla::Variant<Ts...>>
- : public GCVariantOperations<JS::Handle<mozilla::Variant<Ts...>>, Ts...>
-{ };
-
-template <typename... Ts>
-class PersistentRootedBase<mozilla::Variant<Ts...>>
- : public MutableGCVariantOperations<JS::PersistentRooted<mozilla::Variant<Ts...>>, Ts...>
-{ };
-
} // namespace js
#endif // js_GCVariant_h
diff --git a/js/public/GCVector.h b/js/public/GCVector.h
index 1c9925261..4acf0d1fc 100644
--- a/js/public/GCVector.h
+++ b/js/public/GCVector.h
@@ -134,11 +134,11 @@ class GCVector
namespace js {
-template <typename Outer, typename T, size_t Capacity, typename AllocPolicy>
-class GCVectorOperations
+template <typename Wrapper, typename T, size_t Capacity, typename AllocPolicy>
+class WrappedPtrOperations<JS::GCVector<T, Capacity, AllocPolicy>, Wrapper>
{
using Vec = JS::GCVector<T, Capacity, AllocPolicy>;
- const Vec& vec() const { return static_cast<const Outer*>(this)->get(); }
+ const Vec& vec() const { return static_cast<const Wrapper*>(this)->get(); }
public:
const AllocPolicy& allocPolicy() const { return vec().allocPolicy(); }
@@ -154,13 +154,13 @@ class GCVectorOperations
}
};
-template <typename Outer, typename T, size_t Capacity, typename AllocPolicy>
-class MutableGCVectorOperations
- : public GCVectorOperations<Outer, T, Capacity, AllocPolicy>
+template <typename Wrapper, typename T, size_t Capacity, typename AllocPolicy>
+class MutableWrappedPtrOperations<JS::GCVector<T, Capacity, AllocPolicy>, Wrapper>
+ : public WrappedPtrOperations<JS::GCVector<T, Capacity, AllocPolicy>, Wrapper>
{
using Vec = JS::GCVector<T, Capacity, AllocPolicy>;
- const Vec& vec() const { return static_cast<const Outer*>(this)->get(); }
- Vec& vec() { return static_cast<Outer*>(this)->get(); }
+ const Vec& vec() const { return static_cast<const Wrapper*>(this)->get(); }
+ Vec& vec() { return static_cast<Wrapper*>(this)->get(); }
public:
const AllocPolicy& allocPolicy() const { return vec().allocPolicy(); }
@@ -223,26 +223,6 @@ class MutableGCVectorOperations
void erase(T* aBegin, T* aEnd) { vec().erase(aBegin, aEnd); }
};
-template <typename T, size_t N, typename AP>
-class RootedBase<JS::GCVector<T,N,AP>>
- : public MutableGCVectorOperations<JS::Rooted<JS::GCVector<T,N,AP>>, T,N,AP>
-{};
-
-template <typename T, size_t N, typename AP>
-class MutableHandleBase<JS::GCVector<T,N,AP>>
- : public MutableGCVectorOperations<JS::MutableHandle<JS::GCVector<T,N,AP>>, T,N,AP>
-{};
-
-template <typename T, size_t N, typename AP>
-class HandleBase<JS::GCVector<T,N,AP>>
- : public GCVectorOperations<JS::Handle<JS::GCVector<T,N,AP>>, T,N,AP>
-{};
-
-template <typename T, size_t N, typename AP>
-class PersistentRootedBase<JS::GCVector<T,N,AP>>
- : public MutableGCVectorOperations<JS::PersistentRooted<JS::GCVector<T,N,AP>>, T,N,AP>
-{};
-
} // namespace js
#endif // js_GCVector_h
diff --git a/js/public/RootingAPI.h b/js/public/RootingAPI.h
index 5f0740d53..aec25b0ff 100644
--- a/js/public/RootingAPI.h
+++ b/js/public/RootingAPI.h
@@ -112,17 +112,23 @@ template <typename T>
struct BarrierMethods {
};
-template <typename T>
-class RootedBase {};
+template <typename Element, typename Wrapper>
+class WrappedPtrOperations {};
-template <typename T>
-class HandleBase {};
+template <typename Element, typename Wrapper>
+class MutableWrappedPtrOperations : public WrappedPtrOperations<Element, Wrapper> {};
-template <typename T>
-class MutableHandleBase {};
+template <typename T, typename Wrapper>
+class RootedBase : public MutableWrappedPtrOperations<T, Wrapper> {};
-template <typename T>
-class HeapBase {};
+template <typename T, typename Wrapper>
+class HandleBase : public WrappedPtrOperations<T, Wrapper> {};
+
+template <typename T, typename Wrapper>
+class MutableHandleBase : public MutableWrappedPtrOperations<T, Wrapper> {};
+
+template <typename T, typename Wrapper>
+class HeapBase : public MutableWrappedPtrOperations<T, Wrapper> {};
// Cannot use FOR_EACH_HEAP_ABLE_GC_POINTER_TYPE, as this would import too many macros into scope
template <typename T> struct IsHeapConstructibleType { static constexpr bool value = false; };
@@ -132,8 +138,8 @@ FOR_EACH_PUBLIC_GC_POINTER_TYPE(DECLARE_IS_HEAP_CONSTRUCTIBLE_TYPE)
FOR_EACH_PUBLIC_TAGGED_GC_POINTER_TYPE(DECLARE_IS_HEAP_CONSTRUCTIBLE_TYPE)
#undef DECLARE_IS_HEAP_CONSTRUCTIBLE_TYPE
-template <typename T>
-class PersistentRootedBase {};
+template <typename T, typename Wrapper>
+class PersistentRootedBase : public MutableWrappedPtrOperations<T, Wrapper> {};
static void* const ConstNullValue = nullptr;
@@ -143,10 +149,6 @@ template<typename T>
struct PersistentRootedMarker;
} /* namespace gc */
-#define DECLARE_POINTER_COMPARISON_OPS(T) \
- bool operator==(const T& other) const { return get() == other; } \
- bool operator!=(const T& other) const { return get() != other; }
-
// Important: Return a reference so passing a Rooted<T>, etc. to
// something that takes a |const T&| is not a GC hazard.
#define DECLARE_POINTER_CONSTREF_OPS(T) \
@@ -230,12 +232,14 @@ AssertGCThingIsNotAnObjectSubclass(js::gc::Cell* cell) {}
* Type T must be a public GC pointer type.
*/
template <typename T>
-class MOZ_NON_MEMMOVABLE Heap : public js::HeapBase<T>
+class MOZ_NON_MEMMOVABLE Heap : public js::HeapBase<T, Heap<T>>
{
// Please note: this can actually also be used by nsXBLMaybeCompiled<T>, for legacy reasons.
static_assert(js::IsHeapConstructibleType<T>::value,
"Type T must be a public GC pointer type");
public:
+ using ElementType = T;
+
Heap() {
static_assert(sizeof(T) == sizeof(Heap<T>),
"Heap<T> must be binary compatible with T.");
@@ -367,9 +371,11 @@ ScriptIsMarkedGray(const Heap<JSScript*>& script)
* - It is not possible to store flag bits in a Heap<T>.
*/
template <typename T>
-class TenuredHeap : public js::HeapBase<T>
+class TenuredHeap : public js::HeapBase<T, TenuredHeap<T>>
{
public:
+ using ElementType = T;
+
TenuredHeap() : bits(0) {
static_assert(sizeof(T) == sizeof(TenuredHeap<T>),
"TenuredHeap<T> must be binary compatible with T.");
@@ -377,9 +383,6 @@ class TenuredHeap : public js::HeapBase<T>
explicit TenuredHeap(T p) : bits(0) { setPtr(p); }
explicit TenuredHeap(const TenuredHeap<T>& p) : bits(0) { setPtr(p.getPtr()); }
- bool operator==(const TenuredHeap<T>& other) { return bits == other.bits; }
- bool operator!=(const TenuredHeap<T>& other) { return bits != other.bits; }
-
void setPtr(T newPtr) {
MOZ_ASSERT((reinterpret_cast<uintptr_t>(newPtr) & flagsMask) == 0);
if (newPtr)
@@ -451,11 +454,13 @@ class TenuredHeap : public js::HeapBase<T>
* specialization, define a HandleBase<T> specialization containing them.
*/
template <typename T>
-class MOZ_NONHEAP_CLASS Handle : public js::HandleBase<T>
+class MOZ_NONHEAP_CLASS Handle : public js::HandleBase<T, Handle<T>>
{
friend class JS::MutableHandle<T>;
public:
+ using ElementType = T;
+
/* Creates a handle from a handle of a type convertible to T. */
template <typename S>
MOZ_IMPLICIT Handle(Handle<S> handle,
@@ -516,7 +521,6 @@ class MOZ_NONHEAP_CLASS Handle : public js::HandleBase<T>
MOZ_IMPLICIT Handle(MutableHandle<S>& root,
typename mozilla::EnableIf<mozilla::IsConvertible<S, T>::value, int>::Type dummy = 0);
- DECLARE_POINTER_COMPARISON_OPS(T);
DECLARE_POINTER_CONSTREF_OPS(T);
DECLARE_NONPOINTER_ACCESSOR_METHODS(*ptr);
@@ -540,9 +544,11 @@ class MOZ_NONHEAP_CLASS Handle : public js::HandleBase<T>
* them.
*/
template <typename T>
-class MOZ_STACK_CLASS MutableHandle : public js::MutableHandleBase<T>
+class MOZ_STACK_CLASS MutableHandle : public js::MutableHandleBase<T, MutableHandle<T>>
{
public:
+ using ElementType = T;
+
inline MOZ_IMPLICIT MutableHandle(Rooted<T>* root);
inline MOZ_IMPLICIT MutableHandle(PersistentRooted<T>* root);
@@ -753,7 +759,7 @@ namespace JS {
* specialization, define a RootedBase<T> specialization containing them.
*/
template <typename T>
-class MOZ_RAII Rooted : public js::RootedBase<T>
+class MOZ_RAII Rooted : public js::RootedBase<T, Rooted<T>>
{
inline void registerWithRootLists(js::RootedListHeads& roots) {
this->stack = &roots[JS::MapTypeToRootKind<T>::kind];
@@ -775,6 +781,8 @@ class MOZ_RAII Rooted : public js::RootedBase<T>
}
public:
+ using ElementType = T;
+
template <typename RootingContext>
explicit Rooted(const RootingContext& cx)
: ptr(GCPolicy<T>::initial())
@@ -807,7 +815,6 @@ class MOZ_RAII Rooted : public js::RootedBase<T>
ptr = mozilla::Move(value);
}
- DECLARE_POINTER_COMPARISON_OPS(T);
DECLARE_POINTER_CONSTREF_OPS(T);
DECLARE_POINTER_ASSIGN_OPS(Rooted, T);
DECLARE_NONPOINTER_ACCESSOR_METHODS(ptr);
@@ -853,8 +860,8 @@ namespace js {
* Rooted<StringObject*> rooted(cx, &obj->as<StringObject*>());
* Handle<StringObject*> h = rooted;
*/
-template <>
-class RootedBase<JSObject*>
+template <typename Container>
+class RootedBase<JSObject*, Container> : public MutableWrappedPtrOperations<JSObject*, Container>
{
public:
template <class U>
@@ -871,8 +878,8 @@ class RootedBase<JSObject*>
* Rooted<StringObject*> rooted(cx, &obj->as<StringObject*>());
* Handle<StringObject*> h = rooted;
*/
-template <>
-class HandleBase<JSObject*>
+template <typename Container>
+class HandleBase<JSObject*, Container> : public WrappedPtrOperations<JSObject*, Container>
{
public:
template <class U>
@@ -881,16 +888,17 @@ class HandleBase<JSObject*>
/** Interface substitute for Rooted<T> which does not root the variable's memory. */
template <typename T>
-class MOZ_RAII FakeRooted : public RootedBase<T>
+class MOZ_RAII FakeRooted : public RootedBase<T, FakeRooted<T>>
{
public:
+ using ElementType = T;
+
template <typename CX>
explicit FakeRooted(CX* cx) : ptr(JS::GCPolicy<T>::initial()) {}
template <typename CX>
FakeRooted(CX* cx, T initial) : ptr(initial) {}
- DECLARE_POINTER_COMPARISON_OPS(T);
DECLARE_POINTER_CONSTREF_OPS(T);
DECLARE_POINTER_ASSIGN_OPS(FakeRooted, T);
DECLARE_NONPOINTER_ACCESSOR_METHODS(ptr);
@@ -908,9 +916,11 @@ class MOZ_RAII FakeRooted : public RootedBase<T>
/** Interface substitute for MutableHandle<T> which is not required to point to rooted memory. */
template <typename T>
-class FakeMutableHandle : public js::MutableHandleBase<T>
+class FakeMutableHandle : public js::MutableHandleBase<T, FakeMutableHandle<T>>
{
public:
+ using ElementType = T;
+
MOZ_IMPLICIT FakeMutableHandle(T* t) {
ptr = t;
}
@@ -1075,7 +1085,7 @@ MutableHandle<T>::MutableHandle(PersistentRooted<T>* root)
* marked when the object itself is marked.
*/
template<typename T>
-class PersistentRooted : public js::PersistentRootedBase<T>,
+class PersistentRooted : public js::RootedBase<T, PersistentRooted<T>>,
private mozilla::LinkedListElement<PersistentRooted<T>>
{
using ListBase = mozilla::LinkedListElement<PersistentRooted<T>>;
@@ -1101,6 +1111,8 @@ class PersistentRooted : public js::PersistentRootedBase<T>,
js::RootLists& rootLists(js::ContextFriendFields* cx) = delete;
public:
+ using ElementType = T;
+
PersistentRooted() : ptr(GCPolicy<T>::initial()) {}
template <typename RootingContext>
@@ -1154,7 +1166,6 @@ class PersistentRooted : public js::PersistentRootedBase<T>,
}
}
- DECLARE_POINTER_COMPARISON_OPS(T);
DECLARE_POINTER_CONSTREF_OPS(T);
DECLARE_POINTER_ASSIGN_OPS(PersistentRooted, T);
DECLARE_NONPOINTER_ACCESSOR_METHODS(ptr);
@@ -1191,6 +1202,8 @@ class JS_PUBLIC_API(ObjectPtr)
Heap<JSObject*> value;
public:
+ using ElementType = JSObject*;
+
ObjectPtr() : value(nullptr) {}
explicit ObjectPtr(JSObject* obj) : value(obj) {}
@@ -1240,10 +1253,10 @@ class JS_PUBLIC_API(ObjectPtr)
namespace js {
-template <typename Outer, typename T, typename D>
-class UniquePtrOperations
+template <typename T, typename D, typename Container>
+class WrappedPtrOperations<UniquePtr<T, D>, Container>
{
- const UniquePtr<T, D>& uniquePtr() const { return static_cast<const Outer*>(this)->get(); }
+ const UniquePtr<T, D>& uniquePtr() const { return static_cast<const Container*>(this)->get(); }
public:
explicit operator bool() const { return !!uniquePtr(); }
@@ -1252,36 +1265,17 @@ class UniquePtrOperations
T& operator*() const { return *uniquePtr(); }
};
-template <typename Outer, typename T, typename D>
-class MutableUniquePtrOperations : public UniquePtrOperations<Outer, T, D>
+template <typename T, typename D, typename Container>
+class MutableWrappedPtrOperations<UniquePtr<T, D>, Container>
+ : public WrappedPtrOperations<UniquePtr<T, D>, Container>
{
- UniquePtr<T, D>& uniquePtr() { return static_cast<Outer*>(this)->get(); }
+ UniquePtr<T, D>& uniquePtr() { return static_cast<Container*>(this)->get(); }
public:
MOZ_MUST_USE typename UniquePtr<T, D>::Pointer release() { return uniquePtr().release(); }
void reset(T* ptr = T()) { uniquePtr().reset(ptr); }
};
-template <typename T, typename D>
-class RootedBase<UniquePtr<T, D>>
- : public MutableUniquePtrOperations<JS::Rooted<UniquePtr<T, D>>, T, D>
-{ };
-
-template <typename T, typename D>
-class MutableHandleBase<UniquePtr<T, D>>
- : public MutableUniquePtrOperations<JS::MutableHandle<UniquePtr<T, D>>, T, D>
-{ };
-
-template <typename T, typename D>
-class HandleBase<UniquePtr<T, D>>
- : public UniquePtrOperations<JS::Handle<UniquePtr<T, D>>, T, D>
-{ };
-
-template <typename T, typename D>
-class PersistentRootedBase<UniquePtr<T, D>>
- : public MutableUniquePtrOperations<JS::PersistentRooted<UniquePtr<T, D>>, T, D>
-{ };
-
namespace gc {
template <typename T, typename TraceCallbacks>
@@ -1324,6 +1318,177 @@ Swap(JS::TenuredHeap<T>& aX, JS::TenuredHeap<T>& aY)
} /* namespace mozilla */
+namespace js {
+namespace detail {
+
+// DefineComparisonOps is a trait which selects which wrapper classes to define
+// operator== and operator!= for. It supplies a getter function to extract the
+// value to compare. This is used to avoid triggering the automatic read
+// barriers where appropriate.
+//
+// If DefineComparisonOps is not specialized for a particular wrapper you may
+// get errors such as 'invalid operands to binary expression' or 'no match for
+// operator==' when trying to compare against instances of the wrapper.
+
+template <typename T>
+struct DefineComparisonOps : mozilla::FalseType {};
+
+template <typename T>
+struct DefineComparisonOps<JS::Heap<T>> : mozilla::TrueType {
+ static const T& get(const JS::Heap<T>& v) { return v.unbarrieredGet(); }
+};
+
+template <typename T>
+struct DefineComparisonOps<JS::TenuredHeap<T>> : mozilla::TrueType {
+ static const T get(const JS::TenuredHeap<T>& v) { return v.unbarrieredGetPtr(); }
+};
+
+template <>
+struct DefineComparisonOps<JS::ObjectPtr> : mozilla::TrueType {
+ static const JSObject* get(const JS::ObjectPtr& v) { return v.unbarrieredGet(); }
+};
+
+template <typename T>
+struct DefineComparisonOps<JS::Rooted<T>> : mozilla::TrueType {
+ static const T& get(const JS::Rooted<T>& v) { return v.get(); }
+};
+
+template <typename T>
+struct DefineComparisonOps<JS::Handle<T>> : mozilla::TrueType {
+ static const T& get(const JS::Handle<T>& v) { return v.get(); }
+};
+
+template <typename T>
+struct DefineComparisonOps<JS::MutableHandle<T>> : mozilla::TrueType {
+ static const T& get(const JS::MutableHandle<T>& v) { return v.get(); }
+};
+
+template <typename T>
+struct DefineComparisonOps<JS::PersistentRooted<T>> : mozilla::TrueType {
+ static const T& get(const JS::PersistentRooted<T>& v) { return v.get(); }
+};
+
+template <typename T>
+struct DefineComparisonOps<js::FakeRooted<T>> : mozilla::TrueType {
+ static const T& get(const js::FakeRooted<T>& v) { return v.get(); }
+};
+
+template <typename T>
+struct DefineComparisonOps<js::FakeMutableHandle<T>> : mozilla::TrueType {
+ static const T& get(const js::FakeMutableHandle<T>& v) { return v.get(); }
+};
+
+} /* namespace detail */
+} /* namespace js */
+
+// Overload operator== and operator!= for all types with the DefineComparisonOps
+// trait using the supplied getter.
+//
+// There are four cases:
+
+// Case 1: comparison between two wrapper objects.
+
+template <typename T, typename U>
+typename mozilla::EnableIf<js::detail::DefineComparisonOps<T>::value &&
+ js::detail::DefineComparisonOps<U>::value, bool>::Type
+operator==(const T& a, const U& b) {
+ return js::detail::DefineComparisonOps<T>::get(a) == js::detail::DefineComparisonOps<U>::get(b);
+}
+
+template <typename T, typename U>
+typename mozilla::EnableIf<js::detail::DefineComparisonOps<T>::value &&
+ js::detail::DefineComparisonOps<U>::value, bool>::Type
+operator!=(const T& a, const U& b) {
+ return !(a == b);
+}
+
+// Case 2: comparison between a wrapper object and its unwrapped element type.
+
+template <typename T>
+typename mozilla::EnableIf<js::detail::DefineComparisonOps<T>::value, bool>::Type
+operator==(const T& a, const typename T::ElementType& b) {
+ return js::detail::DefineComparisonOps<T>::get(a) == b;
+}
+
+template <typename T>
+typename mozilla::EnableIf<js::detail::DefineComparisonOps<T>::value, bool>::Type
+operator!=(const T& a, const typename T::ElementType& b) {
+ return !(a == b);
+}
+
+template <typename T>
+typename mozilla::EnableIf<js::detail::DefineComparisonOps<T>::value, bool>::Type
+operator==(const typename T::ElementType& a, const T& b) {
+ return a == js::detail::DefineComparisonOps<T>::get(b);
+}
+
+template <typename T>
+typename mozilla::EnableIf<js::detail::DefineComparisonOps<T>::value, bool>::Type
+operator!=(const typename T::ElementType& a, const T& b) {
+ return !(a == b);
+}
+
+// Case 3: For pointer wrappers, comparison between the wrapper and a const
+// element pointer.
+
+template <typename T>
+typename mozilla::EnableIf<js::detail::DefineComparisonOps<T>::value &&
+ mozilla::IsPointer<typename T::ElementType>::value, bool>::Type
+operator==(const typename mozilla::RemovePointer<typename T::ElementType>::Type* a, const T& b) {
+ return a == js::detail::DefineComparisonOps<T>::get(b);
+}
+
+template <typename T>
+typename mozilla::EnableIf<js::detail::DefineComparisonOps<T>::value &&
+ mozilla::IsPointer<typename T::ElementType>::value, bool>::Type
+operator!=(const typename mozilla::RemovePointer<typename T::ElementType>::Type* a, const T& b) {
+ return !(a == b);
+}
+
+template <typename T>
+typename mozilla::EnableIf<js::detail::DefineComparisonOps<T>::value &&
+ mozilla::IsPointer<typename T::ElementType>::value, bool>::Type
+operator==(const T& a, const typename mozilla::RemovePointer<typename T::ElementType>::Type* b) {
+ return js::detail::DefineComparisonOps<T>::get(a) == b;
+}
+
+template <typename T>
+typename mozilla::EnableIf<js::detail::DefineComparisonOps<T>::value &&
+ mozilla::IsPointer<typename T::ElementType>::value, bool>::Type
+operator!=(const T& a, const typename mozilla::RemovePointer<typename T::ElementType>::Type* b) {
+ return !(a == b);
+}
+
+// Case 4: For pointer wrappers, comparison between the wrapper and nullptr.
+
+template <typename T>
+typename mozilla::EnableIf<js::detail::DefineComparisonOps<T>::value &&
+ mozilla::IsPointer<typename T::ElementType>::value, bool>::Type
+operator==(std::nullptr_t a, const T& b) {
+ return a == js::detail::DefineComparisonOps<T>::get(b);
+}
+
+template <typename T>
+typename mozilla::EnableIf<js::detail::DefineComparisonOps<T>::value &&
+ mozilla::IsPointer<typename T::ElementType>::value, bool>::Type
+operator!=(std::nullptr_t a, const T& b) {
+ return !(a == b);
+}
+
+template <typename T>
+typename mozilla::EnableIf<js::detail::DefineComparisonOps<T>::value &&
+ mozilla::IsPointer<typename T::ElementType>::value, bool>::Type
+operator==(const T& a, std::nullptr_t b) {
+ return js::detail::DefineComparisonOps<T>::get(a) == b;
+}
+
+template <typename T>
+typename mozilla::EnableIf<js::detail::DefineComparisonOps<T>::value &&
+ mozilla::IsPointer<typename T::ElementType>::value, bool>::Type
+operator!=(const T& a, std::nullptr_t b) {
+ return !(a == b);
+}
+
#undef DELETE_ASSIGNMENT_OPS
#endif /* js_RootingAPI_h */
diff --git a/js/public/SweepingAPI.h b/js/public/SweepingAPI.h
index 39abb0fc0..bbc1ec279 100644
--- a/js/public/SweepingAPI.h
+++ b/js/public/SweepingAPI.h
@@ -8,11 +8,6 @@
#include "js/HeapAPI.h"
-namespace js {
-template <typename T>
-class WeakCacheBase {};
-} // namespace js
-
namespace JS {
template <typename T> class WeakCache;
@@ -24,7 +19,7 @@ RegisterWeakCache(JS::Zone* zone, JS::WeakCache<void*>* cachep);
// A WeakCache stores the given Sweepable container and links itself into a
// list of such caches that are swept during each GC.
template <typename T>
-class WeakCache : public js::WeakCacheBase<T>,
+class WeakCache : public js::MutableWrappedPtrOperations<T, WeakCache<T>>,
private mozilla::LinkedListElement<WeakCache<T>>
{
friend class mozilla::LinkedListElement<WeakCache<T>>;
diff --git a/js/public/Value.h b/js/public/Value.h
index 087d178ef..c645f0773 100644
--- a/js/public/Value.h
+++ b/js/public/Value.h
@@ -1340,20 +1340,18 @@ struct BarrierMethods<JS::Value>
}
};
-template <class Outer> class MutableValueOperations;
+template <class Wrapper> class MutableValueOperations;
/**
* A class designed for CRTP use in implementing the non-mutating parts of the
- * Value interface in Value-like classes. Outer must be a class inheriting
- * ValueOperations<Outer> with a visible get() method returning a const
- * reference to the Value abstracted by Outer.
+ * Value interface in Value-like classes. Wrapper must be a class inheriting
+ * ValueOperations<Wrapper> with a visible get() method returning a const
+ * reference to the Value abstracted by Wrapper.
*/
-template <class Outer>
-class ValueOperations
+template <class Wrapper>
+class WrappedPtrOperations<JS::Value, Wrapper>
{
- friend class MutableValueOperations<Outer>;
-
- const JS::Value& value() const { return static_cast<const Outer*>(this)->get(); }
+ const JS::Value& value() const { return static_cast<const Wrapper*>(this)->get(); }
public:
bool isUndefined() const { return value().isUndefined(); }
@@ -1398,17 +1396,17 @@ class ValueOperations
/**
* A class designed for CRTP use in implementing all the mutating parts of the
- * Value interface in Value-like classes. Outer must be a class inheriting
- * MutableValueOperations<Outer> with visible get() methods returning const and
- * non-const references to the Value abstracted by Outer.
+ * Value interface in Value-like classes. Wrapper must be a class inheriting
+ * MutableWrappedPtrOperations<Wrapper> with visible get() methods returning const and
+ * non-const references to the Value abstracted by Wrapper.
*/
-template <class Outer>
-class MutableValueOperations : public ValueOperations<Outer>
+template <class Wrapper>
+class MutableWrappedPtrOperations<JS::Value, Wrapper> : public WrappedPtrOperations<JS::Value, Wrapper>
{
protected:
void set(const JS::Value& v) {
// Call Outer::set to trigger any barriers.
- static_cast<Outer*>(this)->set(v);
+ static_cast<Wrapper*>(this)->set(v);
}
public:
@@ -1434,13 +1432,9 @@ class MutableValueOperations : public ValueOperations<Outer>
* Augment the generic Heap<T> interface when T = Value with
* type-querying, value-extracting, and mutating operations.
*/
-template <>
-class HeapBase<JS::Value> : public MutableValueOperations<JS::Heap<JS::Value> >
+template <typename Wrapper>
+class HeapBase<JS::Value, Wrapper> : public MutableWrappedPtrOperations<JS::Value, Wrapper>
{
- typedef JS::Heap<JS::Value> Outer;
-
- friend class ValueOperations<Outer>;
-
public:
void setNumber(uint32_t ui) {
if (ui > JSVAL_INT_MAX) {
@@ -1460,22 +1454,6 @@ class HeapBase<JS::Value> : public MutableValueOperations<JS::Heap<JS::Value> >
}
};
-template <>
-class HandleBase<JS::Value> : public ValueOperations<JS::Handle<JS::Value> >
-{};
-
-template <>
-class MutableHandleBase<JS::Value> : public MutableValueOperations<JS::MutableHandle<JS::Value> >
-{};
-
-template <>
-class RootedBase<JS::Value> : public MutableValueOperations<JS::Rooted<JS::Value> >
-{};
-
-template <>
-class PersistentRootedBase<JS::Value> : public MutableValueOperations<JS::PersistentRooted<JS::Value>>
-{};
-
/*
* If the Value is a GC pointer type, convert to that type and call |f| with
* the pointer. If the Value is not a GC type, calls F::defaultValue.
diff --git a/js/src/NamespaceImports.h b/js/src/NamespaceImports.h
index de8e3a6f2..2b7a1f0e8 100644
--- a/js/src/NamespaceImports.h
+++ b/js/src/NamespaceImports.h
@@ -45,6 +45,7 @@ class MOZ_STACK_CLASS SourceBufferHolder;
class HandleValueArray;
class ObjectOpResult;
+class PropertyResult;
class Symbol;
enum class SymbolCode: uint32_t;
@@ -150,6 +151,7 @@ using JS::FalseHandleValue;
using JS::HandleValueArray;
using JS::ObjectOpResult;
+using JS::PropertyResult;
using JS::Zone;
diff --git a/js/src/builtin/MapObject.h b/js/src/builtin/MapObject.h
index 5382adfd2..a9f685ea0 100644
--- a/js/src/builtin/MapObject.h
+++ b/js/src/builtin/MapObject.h
@@ -52,14 +52,22 @@ class HashableValue
}
};
-template <>
-class RootedBase<HashableValue> {
+template <typename Wrapper>
+class WrappedPtrOperations<HashableValue, Wrapper>
+{
public:
- MOZ_MUST_USE bool setValue(JSContext* cx, HandleValue v) {
- return static_cast<JS::Rooted<HashableValue>*>(this)->get().setValue(cx, v);
- }
Value value() const {
- return static_cast<const JS::Rooted<HashableValue>*>(this)->get().get();
+ return static_cast<const Wrapper*>(this)->get().get();
+ }
+};
+
+template <typename Wrapper>
+class MutableWrappedPtrOperations<HashableValue, Wrapper>
+ : public WrappedPtrOperations<HashableValue, Wrapper>
+{
+ public:
+ MOZ_MUST_USE bool setValue(JSContext* cx, HandleValue v) {
+ return static_cast<Wrapper*>(this)->get().setValue(cx, v);
}
};
diff --git a/js/src/builtin/Object.cpp b/js/src/builtin/Object.cpp
index 1221d2daf..d661a222e 100644
--- a/js/src/builtin/Object.cpp
+++ b/js/src/builtin/Object.cpp
@@ -69,18 +69,18 @@ js::obj_propertyIsEnumerable(JSContext* cx, unsigned argc, Value* vp)
JSObject* obj = &args.thisv().toObject();
/* Step 3. */
- Shape* shape;
+ PropertyResult prop;
if (obj->isNative() &&
- NativeLookupOwnProperty<NoGC>(cx, &obj->as<NativeObject>(), id, &shape))
+ NativeLookupOwnProperty<NoGC>(cx, &obj->as<NativeObject>(), id, &prop))
{
/* Step 4. */
- if (!shape) {
+ if (!prop) {
args.rval().setBoolean(false);
return true;
}
/* Step 5. */
- unsigned attrs = GetShapeAttributes(obj, shape);
+ unsigned attrs = GetPropertyAttributes(obj, prop);
args.rval().setBoolean((attrs & JSPROP_ENUMERATE) != 0);
return true;
}
@@ -582,11 +582,11 @@ js::obj_hasOwnProperty(JSContext* cx, unsigned argc, Value* vp)
jsid id;
if (args.thisv().isObject() && ValueToId<NoGC>(cx, idValue, &id)) {
JSObject* obj = &args.thisv().toObject();
- Shape* prop;
+ PropertyResult prop;
if (obj->isNative() &&
NativeLookupOwnProperty<NoGC>(cx, &obj->as<NativeObject>(), id, &prop))
{
- args.rval().setBoolean(!!prop);
+ args.rval().setBoolean(prop.isFound());
return true;
}
}
@@ -839,7 +839,7 @@ EnumerableOwnProperties(JSContext* cx, const JS::CallArgs& args, EnumerableOwnPr
value = nobj->getDenseOrTypedArrayElement(JSID_TO_INT(id));
} else {
shape = nobj->lookup(cx, id);
- if (!shape || !(GetShapeAttributes(nobj, shape) & JSPROP_ENUMERATE))
+ if (!shape || !(shape->attributes() & JSPROP_ENUMERATE))
continue;
if (!shape->isAccessorShape()) {
if (!NativeGetExistingProperty(cx, nobj, nobj, shape, &value))
diff --git a/js/src/builtin/TypedObject.cpp b/js/src/builtin/TypedObject.cpp
index 4c938568f..2796848c0 100644
--- a/js/src/builtin/TypedObject.cpp
+++ b/js/src/builtin/TypedObject.cpp
@@ -1671,10 +1671,10 @@ TypeDescr::hasProperty(const JSAtomState& names, jsid id)
/* static */ bool
TypedObject::obj_lookupProperty(JSContext* cx, HandleObject obj, HandleId id,
- MutableHandleObject objp, MutableHandleShape propp)
+ MutableHandleObject objp, MutableHandle<PropertyResult> propp)
{
if (obj->as<TypedObject>().typeDescr().hasProperty(cx->names(), id)) {
- MarkNonNativePropertyFound<CanGC>(propp);
+ propp.setNonNativeProperty();
objp.set(obj);
return true;
}
@@ -1682,7 +1682,7 @@ TypedObject::obj_lookupProperty(JSContext* cx, HandleObject obj, HandleId id,
RootedObject proto(cx, obj->staticPrototype());
if (!proto) {
objp.set(nullptr);
- propp.set(nullptr);
+ propp.setNotFound();
return true;
}
diff --git a/js/src/builtin/TypedObject.h b/js/src/builtin/TypedObject.h
index 4fcd30cb0..83700001d 100644
--- a/js/src/builtin/TypedObject.h
+++ b/js/src/builtin/TypedObject.h
@@ -509,7 +509,7 @@ class TypedObject : public ShapedObject
static MOZ_MUST_USE bool obj_lookupProperty(JSContext* cx, HandleObject obj,
HandleId id, MutableHandleObject objp,
- MutableHandleShape propp);
+ MutableHandle<PropertyResult> propp);
static MOZ_MUST_USE bool obj_defineProperty(JSContext* cx, HandleObject obj, HandleId id,
Handle<PropertyDescriptor> desc,
diff --git a/js/src/ds/TraceableFifo.h b/js/src/ds/TraceableFifo.h
index 04f67da15..0f94b93cb 100644
--- a/js/src/ds/TraceableFifo.h
+++ b/js/src/ds/TraceableFifo.h
@@ -51,11 +51,11 @@ class TraceableFifo : public js::Fifo<T, MinInlineCapacity, AllocPolicy>
}
};
-template <typename Outer, typename T, size_t Capacity, typename AllocPolicy>
-class TraceableFifoOperations
+template <typename Wrapper, typename T, size_t Capacity, typename AllocPolicy>
+class WrappedPtrOperations<TraceableFifo<T, Capacity, AllocPolicy>, Wrapper>
{
using TF = TraceableFifo<T, Capacity, AllocPolicy>;
- const TF& fifo() const { return static_cast<const Outer*>(this)->extract(); }
+ const TF& fifo() const { return static_cast<const Wrapper*>(this)->get(); }
public:
size_t length() const { return fifo().length(); }
@@ -63,12 +63,12 @@ class TraceableFifoOperations
const T& front() const { return fifo().front(); }
};
-template <typename Outer, typename T, size_t Capacity, typename AllocPolicy>
-class MutableTraceableFifoOperations
- : public TraceableFifoOperations<Outer, T, Capacity, AllocPolicy>
+template <typename Wrapper, typename T, size_t Capacity, typename AllocPolicy>
+class MutableWrappedPtrOperations<TraceableFifo<T, Capacity, AllocPolicy>, Wrapper>
+ : public WrappedPtrOperations<TraceableFifo<T, Capacity, AllocPolicy>, Wrapper>
{
using TF = TraceableFifo<T, Capacity, AllocPolicy>;
- TF& fifo() { return static_cast<Outer*>(this)->extract(); }
+ TF& fifo() { return static_cast<Wrapper*>(this)->get(); }
public:
T& front() { return fifo().front(); }
@@ -82,46 +82,6 @@ class MutableTraceableFifoOperations
void clear() { fifo().clear(); }
};
-template <typename A, size_t B, typename C>
-class RootedBase<TraceableFifo<A,B,C>>
- : public MutableTraceableFifoOperations<JS::Rooted<TraceableFifo<A,B,C>>, A,B,C>
-{
- using TF = TraceableFifo<A,B,C>;
-
- friend class TraceableFifoOperations<JS::Rooted<TF>, A,B,C>;
- const TF& extract() const { return *static_cast<const JS::Rooted<TF>*>(this)->address(); }
-
- friend class MutableTraceableFifoOperations<JS::Rooted<TF>, A,B,C>;
- TF& extract() { return *static_cast<JS::Rooted<TF>*>(this)->address(); }
-};
-
-template <typename A, size_t B, typename C>
-class MutableHandleBase<TraceableFifo<A,B,C>>
- : public MutableTraceableFifoOperations<JS::MutableHandle<TraceableFifo<A,B,C>>, A,B,C>
-{
- using TF = TraceableFifo<A,B,C>;
-
- friend class TraceableFifoOperations<JS::MutableHandle<TF>, A,B,C>;
- const TF& extract() const {
- return *static_cast<const JS::MutableHandle<TF>*>(this)->address();
- }
-
- friend class MutableTraceableFifoOperations<JS::MutableHandle<TF>, A,B,C>;
- TF& extract() { return *static_cast<JS::MutableHandle<TF>*>(this)->address(); }
-};
-
-template <typename A, size_t B, typename C>
-class HandleBase<TraceableFifo<A,B,C>>
- : public TraceableFifoOperations<JS::Handle<TraceableFifo<A,B,C>>, A,B,C>
-{
- using TF = TraceableFifo<A,B,C>;
-
- friend class TraceableFifoOperations<JS::Handle<TF>, A,B,C>;
- const TF& extract() const {
- return *static_cast<const JS::Handle<TF>*>(this)->address();
- }
-};
-
} // namespace js
#endif // js_TraceableFifo_h
diff --git a/js/src/gc/Barrier.h b/js/src/gc/Barrier.h
index 681ccc9c4..345131a29 100644
--- a/js/src/gc/Barrier.h
+++ b/js/src/gc/Barrier.h
@@ -261,8 +261,6 @@ struct InternalBarrierMethods<T*>
{
static bool isMarkable(T* v) { return v != nullptr; }
- static bool isMarkableTaggedPointer(T* v) { return !IsNullTaggedPointer(v); }
-
static void preBarrier(T* v) { T::writeBarrierPre(v); }
static void postBarrier(T** vp, T* prev, T* next) { T::writeBarrierPost(vp, prev, next); }
@@ -282,7 +280,6 @@ template <>
struct InternalBarrierMethods<Value>
{
static bool isMarkable(const Value& v) { return v.isGCThing(); }
- static bool isMarkableTaggedPointer(const Value& v) { return isMarkable(v); }
static void preBarrier(const Value& v) {
DispatchTyped(PreBarrierFunctor<Value>(), v);
@@ -318,24 +315,17 @@ template <>
struct InternalBarrierMethods<jsid>
{
static bool isMarkable(jsid id) { return JSID_IS_GCTHING(id); }
- static bool isMarkableTaggedPointer(jsid id) { return isMarkable(id); }
static void preBarrier(jsid id) { DispatchTyped(PreBarrierFunctor<jsid>(), id); }
static void postBarrier(jsid* idp, jsid prev, jsid next) {}
};
-// Barrier classes can use Mixins to add methods to a set of barrier
-// instantiations, to make the barriered thing look and feel more like the
-// thing itself.
-template <typename T>
-class BarrieredBaseMixins {};
-
// Base class of all barrier types.
//
// This is marked non-memmovable since post barriers added by derived classes
// can add pointers to class instances to the store buffer.
template <typename T>
-class MOZ_NON_MEMMOVABLE BarrieredBase : public BarrieredBaseMixins<T>
+class MOZ_NON_MEMMOVABLE BarrieredBase
{
protected:
// BarrieredBase is not directly instantiable.
@@ -356,14 +346,18 @@ class MOZ_NON_MEMMOVABLE BarrieredBase : public BarrieredBaseMixins<T>
// Base class for barriered pointer types that intercept only writes.
template <class T>
-class WriteBarrieredBase : public BarrieredBase<T>
+class WriteBarrieredBase : public BarrieredBase<T>,
+ public WrappedPtrOperations<T, WriteBarrieredBase<T>>
{
protected:
+ using BarrieredBase<T>::value;
+
// WriteBarrieredBase is not directly instantiable.
explicit WriteBarrieredBase(const T& v) : BarrieredBase<T>(v) {}
public:
- DECLARE_POINTER_COMPARISON_OPS(T);
+ using ElementType = T;
+
DECLARE_POINTER_CONSTREF_OPS(T);
// Use this if the automatic coercion to T isn't working.
@@ -460,10 +454,6 @@ class GCPtr : public WriteBarrieredBase<T>
DECLARE_POINTER_ASSIGN_OPS(GCPtr, T);
- T unbarrieredGet() const {
- return this->value;
- }
-
private:
void set(const T& v) {
this->pre();
@@ -580,8 +570,12 @@ class ReadBarrieredBase : public BarrieredBase<T>
// insert manual post-barriers on the table for rekeying if the key is based in
// any way on the address of the object.
template <typename T>
-class ReadBarriered : public ReadBarrieredBase<T>
+class ReadBarriered : public ReadBarrieredBase<T>,
+ public WrappedPtrOperations<T, ReadBarriered<T>>
{
+ protected:
+ using ReadBarrieredBase<T>::value;
+
public:
ReadBarriered() : ReadBarrieredBase<T>(JS::GCPolicy<T>::initial()) {}
@@ -614,14 +608,13 @@ class ReadBarriered : public ReadBarrieredBase<T>
return *this;
}
- const T get() const {
- if (!InternalBarrierMethods<T>::isMarkable(this->value))
- return JS::GCPolicy<T>::initial();
- this->read();
+ const T& get() const {
+ if (InternalBarrierMethods<T>::isMarkable(this->value))
+ this->read();
return this->value;
}
- const T unbarrieredGet() const {
+ const T& unbarrieredGet() const {
return this->value;
}
@@ -629,9 +622,9 @@ class ReadBarriered : public ReadBarrieredBase<T>
return bool(this->value);
}
- operator const T() const { return get(); }
+ operator const T&() const { return get(); }
- const T operator->() const { return get(); }
+ const T& operator->() const { return get(); }
T* unsafeGet() { return &this->value; }
T const* unsafeGet() const { return &this->value; }
@@ -649,12 +642,6 @@ class ReadBarriered : public ReadBarrieredBase<T>
template <typename T>
using WeakRef = ReadBarriered<T>;
-// Add Value operations to all Barrier types. Note, this must be defined before
-// HeapSlot for HeapSlot's base to get these operations.
-template <>
-class BarrieredBaseMixins<JS::Value> : public ValueOperations<WriteBarrieredBase<JS::Value>>
-{};
-
// A pre- and post-barriered Value that is specialized to be aware that it
// resides in a slots or elements vector. This allows it to be relocated in
// memory, but with substantially less overhead than a HeapPtr.
@@ -943,6 +930,36 @@ typedef ReadBarriered<WasmTableObject*> ReadBarrieredWasmTableObject;
typedef ReadBarriered<Value> ReadBarrieredValue;
+namespace detail {
+
+template <typename T>
+struct DefineComparisonOps<PreBarriered<T>> : mozilla::TrueType {
+ static const T& get(const PreBarriered<T>& v) { return v.get(); }
+};
+
+template <typename T>
+struct DefineComparisonOps<GCPtr<T>> : mozilla::TrueType {
+ static const T& get(const GCPtr<T>& v) { return v.get(); }
+};
+
+template <typename T>
+struct DefineComparisonOps<HeapPtr<T>> : mozilla::TrueType {
+ static const T& get(const HeapPtr<T>& v) { return v.get(); }
+};
+
+template <typename T>
+struct DefineComparisonOps<ReadBarriered<T>> : mozilla::TrueType {
+ static const T& get(const ReadBarriered<T>& v) { return v.unbarrieredGet(); }
+};
+
+template <>
+struct DefineComparisonOps<HeapSlot> : mozilla::TrueType {
+ static const Value& get(const HeapSlot& v) { return v.get(); }
+};
+
+} /* namespace detail */
+
+
} /* namespace js */
#endif /* gc_Barrier_h */
diff --git a/js/src/gc/Heap.h b/js/src/gc/Heap.h
index 2a1042094..e97aec746 100644
--- a/js/src/gc/Heap.h
+++ b/js/src/gc/Heap.h
@@ -315,10 +315,6 @@ class TenuredCell : public Cell
MOZ_ALWAYS_INLINE void unmark(uint32_t color) const;
MOZ_ALWAYS_INLINE void copyMarkBitsFrom(const TenuredCell* src);
- // Note: this is in TenuredCell because JSObject subclasses are sometimes
- // used tagged.
- static MOZ_ALWAYS_INLINE bool isNullLike(const Cell* thing) { return !thing; }
-
// Access to the arena.
inline Arena* arena() const;
inline AllocKind getAllocKind() const;
@@ -1300,7 +1296,7 @@ TenuredCell::isInsideZone(JS::Zone* zone) const
TenuredCell::readBarrier(TenuredCell* thing)
{
MOZ_ASSERT(!CurrentThreadIsIonCompiling());
- MOZ_ASSERT(!isNullLike(thing));
+ MOZ_ASSERT(thing);
// It would be good if barriers were never triggered during collection, but
// at the moment this can happen e.g. when rekeying tables containing
@@ -1333,7 +1329,6 @@ AssertSafeToSkipBarrier(TenuredCell* thing);
TenuredCell::writeBarrierPre(TenuredCell* thing)
{
MOZ_ASSERT(!CurrentThreadIsIonCompiling());
- MOZ_ASSERT_IF(thing, !isNullLike(thing));
if (!thing)
return;
diff --git a/js/src/gc/Marking.cpp b/js/src/gc/Marking.cpp
index 241a1df20..da8da5c6b 100644
--- a/js/src/gc/Marking.cpp
+++ b/js/src/gc/Marking.cpp
@@ -501,7 +501,7 @@ void
js::TraceNullableRoot(JSTracer* trc, T* thingp, const char* name)
{
AssertRootMarkingPhase(trc);
- if (InternalBarrierMethods<T>::isMarkableTaggedPointer(*thingp))
+ if (InternalBarrierMethods<T>::isMarkable(*thingp))
DispatchToTracer(trc, ConvertToBase(thingp), name);
}
diff --git a/js/src/gc/Marking.h b/js/src/gc/Marking.h
index 2b9e7ace1..40b331b31 100644
--- a/js/src/gc/Marking.h
+++ b/js/src/gc/Marking.h
@@ -414,14 +414,6 @@ ToMarkable(Cell* cell)
return cell;
}
-// Return true if the pointer is nullptr, or if it is a tagged pointer to
-// nullptr.
-MOZ_ALWAYS_INLINE bool
-IsNullTaggedPointer(void* p)
-{
- return uintptr_t(p) <= LargestTaggedNullCellPointer;
-}
-
// Wrap a GC thing pointer into a new Value or jsid. The type system enforces
// that the thing pointer is a wrappable type.
template <typename S, typename T>
diff --git a/js/src/jit/BaselineIC.cpp b/js/src/jit/BaselineIC.cpp
index f5dcd2a10..7dbe239a7 100644
--- a/js/src/jit/BaselineIC.cpp
+++ b/js/src/jit/BaselineIC.cpp
@@ -1145,9 +1145,9 @@ TryAttachNativeOrUnboxedGetValueElemStub(JSContext* cx, HandleScript script, jsb
return true;
bool needsAtomize = checkAtomize<T>(keyVal);
- RootedShape shape(cx);
+ Rooted<PropertyResult> prop(cx);
RootedObject holder(cx);
- if (!EffectlesslyLookupProperty(cx, obj, id, &holder, &shape))
+ if (!EffectlesslyLookupProperty(cx, obj, id, &holder, &prop))
return false;
if (!holder || (holder != obj && !holder->isNative()))
return true;
@@ -1214,6 +1214,8 @@ TryAttachNativeOrUnboxedGetValueElemStub(JSContext* cx, HandleScript script, jsb
if (!holder->isNative())
return true;
+ RootedShape shape(cx, prop.shape());
+
if (IsCacheableGetPropReadSlot(obj, holder, shape)) {
bool isFixedSlot;
uint32_t offset;
@@ -1264,13 +1266,14 @@ TryAttachNativeGetAccessorElemStub(JSContext* cx, HandleScript script, jsbytecod
return true;
bool needsAtomize = checkAtomize<T>(keyVal);
- RootedShape shape(cx);
+ Rooted<PropertyResult> prop(cx);
RootedObject baseHolder(cx);
- if (!EffectlesslyLookupProperty(cx, obj, id, &baseHolder, &shape))
+ if (!EffectlesslyLookupProperty(cx, obj, id, &baseHolder, &prop))
return false;
if (!baseHolder || !baseHolder->isNative())
return true;
+ RootedShape shape(cx, prop.shape());
HandleNativeObject holder = baseHolder.as<NativeObject>();
bool getterIsScripted = false;
@@ -3348,11 +3351,17 @@ TryAttachNativeInStub(JSContext* cx, HandleScript outerScript, ICIn_Fallback* st
return true;
RootedPropertyName name(cx, JSID_TO_ATOM(id)->asPropertyName());
- RootedShape shape(cx);
+ Rooted<PropertyResult> prop(cx);
RootedObject holder(cx);
- if (!EffectlesslyLookupProperty(cx, obj, id, &holder, &shape))
+ if (!EffectlesslyLookupProperty(cx, obj, id, &holder, &prop))
return false;
+ if (prop.isNonNativeProperty()) {
+ MOZ_ASSERT(!IsCacheableProtoChain(obj, holder, false));
+ return true;
+ }
+
+ RootedShape shape(cx, prop.maybeShape());
if (IsCacheableGetPropReadSlot(obj, holder, shape)) {
ICStub::Kind kind = (obj == holder) ? ICStub::In_Native
: ICStub::In_NativePrototype;
@@ -4259,14 +4268,17 @@ TryAttachSetValuePropStub(JSContext* cx, HandleScript script, jsbytecode* pc, IC
{
MOZ_ASSERT(!*attached);
- RootedShape shape(cx);
+ Rooted<PropertyResult> prop(cx);
RootedObject holder(cx);
- if (!EffectlesslyLookupProperty(cx, obj, id, &holder, &shape))
+ if (!EffectlesslyLookupProperty(cx, obj, id, &holder, &prop))
return false;
if (obj != holder)
return true;
- if (!obj->isNative()) {
+ RootedShape shape(cx);
+ if (obj->isNative()) {
+ shape = prop.shape();
+ } else {
if (obj->is<UnboxedPlainObject>()) {
UnboxedExpandoObject* expando = obj->as<UnboxedPlainObject>().maybeExpando();
if (expando) {
@@ -4365,11 +4377,17 @@ TryAttachSetAccessorPropStub(JSContext* cx, HandleScript script, jsbytecode* pc,
MOZ_ASSERT(!*attached);
MOZ_ASSERT(!*isTemporarilyUnoptimizable);
- RootedShape shape(cx);
+ Rooted<PropertyResult> prop(cx);
RootedObject holder(cx);
- if (!EffectlesslyLookupProperty(cx, obj, id, &holder, &shape))
+ if (!EffectlesslyLookupProperty(cx, obj, id, &holder, &prop))
return false;
+ if (prop.isNonNativeProperty()) {
+ MOZ_ASSERT(!IsCacheableProtoChain(obj, holder));
+ return true;
+ }
+
+ RootedShape shape(cx, prop.maybeShape());
bool isScripted = false;
bool cacheableCall = IsCacheableSetPropCall(cx, obj, holder, shape,
&isScripted, isTemporarilyUnoptimizable);
diff --git a/js/src/jit/CacheIR.cpp b/js/src/jit/CacheIR.cpp
index fc58bdb98..9168a344e 100644
--- a/js/src/jit/CacheIR.cpp
+++ b/js/src/jit/CacheIR.cpp
@@ -109,7 +109,8 @@ CanAttachNativeGetProp(JSContext* cx, HandleObject obj, HandleId id,
// only miss out on shape hashification, which is only a temporary perf cost.
// The limits were arbitrarily set, anyways.
JSObject* baseHolder = nullptr;
- if (!LookupPropertyPure(cx, obj, id, &baseHolder, shape.address()))
+ PropertyResult prop;
+ if (!LookupPropertyPure(cx, obj, id, &baseHolder, &prop))
return CanAttachNone;
MOZ_ASSERT(!holder);
@@ -118,8 +119,9 @@ CanAttachNativeGetProp(JSContext* cx, HandleObject obj, HandleId id,
return CanAttachNone;
holder.set(&baseHolder->as<NativeObject>());
}
+ shape.set(prop.maybeShape());
- if (IsCacheableGetPropReadSlotForIonOrCacheIR(obj, holder, shape) ||
+ if (IsCacheableGetPropReadSlotForIonOrCacheIR(obj, holder, prop) ||
IsCacheableNoProperty(cx, obj, holder, shape, id, pc))
{
return CanAttachReadSlot;
diff --git a/js/src/jit/IonCaches.cpp b/js/src/jit/IonCaches.cpp
index 0a0c7ac22..5a7e43728 100644
--- a/js/src/jit/IonCaches.cpp
+++ b/js/src/jit/IonCaches.cpp
@@ -468,11 +468,12 @@ jit::IsCacheableProtoChainForIonOrCacheIR(JSObject* obj, JSObject* holder)
}
bool
-jit::IsCacheableGetPropReadSlotForIonOrCacheIR(JSObject* obj, JSObject* holder, Shape* shape)
+jit::IsCacheableGetPropReadSlotForIonOrCacheIR(JSObject* obj, JSObject* holder, PropertyResult prop)
{
- if (!shape || !IsCacheableProtoChainForIonOrCacheIR(obj, holder))
+ if (!prop || !IsCacheableProtoChainForIonOrCacheIR(obj, holder))
return false;
+ Shape* shape = prop.shape();
if (!shape->hasSlot() || !shape->hasDefaultGetter())
return false;
@@ -480,10 +481,10 @@ jit::IsCacheableGetPropReadSlotForIonOrCacheIR(JSObject* obj, JSObject* holder,
}
static bool
-IsCacheableNoProperty(JSObject* obj, JSObject* holder, Shape* shape, jsbytecode* pc,
+IsCacheableNoProperty(JSObject* obj, JSObject* holder, PropertyResult prop, jsbytecode* pc,
const TypedOrValueRegister& output)
{
- if (shape)
+ if (prop)
return false;
MOZ_ASSERT(!holder);
@@ -751,7 +752,7 @@ CheckDOMProxyExpandoDoesNotShadow(JSContext* cx, MacroAssembler& masm, JSObject*
static void
GenerateReadSlot(JSContext* cx, IonScript* ion, MacroAssembler& masm,
IonCache::StubAttacher& attacher, MaybeCheckTDZ checkTDZ,
- JSObject* obj, JSObject* holder, Shape* shape, Register object,
+ JSObject* obj, JSObject* holder, PropertyResult prop, Register object,
TypedOrValueRegister output, Label* failures = nullptr)
{
// If there's a single jump to |failures|, we can patch the shape guard
@@ -778,7 +779,7 @@ GenerateReadSlot(JSContext* cx, IonScript* ion, MacroAssembler& masm,
if (obj != holder ||
obj->is<UnboxedPlainObject>() ||
- !holder->as<NativeObject>().isFixedSlot(shape->slot()))
+ !holder->as<NativeObject>().isFixedSlot(prop.shape()->slot()))
{
if (output.hasValue()) {
scratchReg = output.valueReg().scratchReg();
@@ -793,7 +794,7 @@ GenerateReadSlot(JSContext* cx, IonScript* ion, MacroAssembler& masm,
// Fast path: single failure jump, no prototype guards.
if (!multipleFailureJumps) {
- EmitLoadSlot(masm, &holder->as<NativeObject>(), shape, object, output, scratchReg);
+ EmitLoadSlot(masm, &holder->as<NativeObject>(), prop.shape(), object, output, scratchReg);
if (restoreScratch)
masm.pop(scratchReg);
attacher.jumpRejoin(masm);
@@ -848,7 +849,8 @@ GenerateReadSlot(JSContext* cx, IonScript* ion, MacroAssembler& masm,
// Slot access.
if (holder) {
- EmitLoadSlot(masm, &holder->as<NativeObject>(), shape, holderReg, output, scratchReg);
+ EmitLoadSlot(masm, &holder->as<NativeObject>(), prop.shape(), holderReg, output,
+ scratchReg);
if (checkTDZ && output.hasValue())
masm.branchTestMagic(Assembler::Equal, output.valueReg(), failures);
} else {
@@ -1294,7 +1296,8 @@ CanAttachNativeGetProp(JSContext* cx, const GetPropCache& cache,
// only miss out on shape hashification, which is only a temporary perf cost.
// The limits were arbitrarily set, anyways.
JSObject* baseHolder = nullptr;
- if (!LookupPropertyPure(cx, obj, id, &baseHolder, shape.address()))
+ PropertyResult prop;
+ if (!LookupPropertyPure(cx, obj, id, &baseHolder, &prop))
return GetPropertyIC::CanAttachNone;
MOZ_ASSERT(!holder);
@@ -1303,12 +1306,13 @@ CanAttachNativeGetProp(JSContext* cx, const GetPropCache& cache,
return GetPropertyIC::CanAttachNone;
holder.set(&baseHolder->as<NativeObject>());
}
+ shape.set(prop.maybeShape());
RootedScript script(cx);
jsbytecode* pc;
cache.getScriptedLocation(&script, &pc);
- if (IsCacheableGetPropReadSlotForIonOrCacheIR(obj, holder, shape) ||
- IsCacheableNoProperty(obj, holder, shape, pc, cache.output()))
+ if (IsCacheableGetPropReadSlotForIonOrCacheIR(obj, holder, prop) ||
+ IsCacheableNoProperty(obj, holder, prop, pc, cache.output()))
{
return GetPropertyIC::CanAttachReadSlot;
}
@@ -1505,7 +1509,7 @@ GetPropertyIC::tryAttachNative(JSContext* cx, HandleScript outerScript, IonScrip
switch (type) {
case CanAttachReadSlot:
GenerateReadSlot(cx, ion, masm, attacher, DontCheckTDZ, obj, holder,
- shape, object(), output(), maybeFailures);
+ PropertyResult(shape), object(), output(), maybeFailures);
attachKind = idempotent() ? "idempotent reading"
: "non idempotent reading";
outcome = JS::TrackedOutcome::ICGetPropStub_ReadSlot;
@@ -1588,7 +1592,7 @@ GetPropertyIC::tryAttachUnboxedExpando(JSContext* cx, HandleScript outerScript,
StubAttacher attacher(*this);
GenerateReadSlot(cx, ion, masm, attacher, DontCheckTDZ, obj, obj,
- shape, object(), output(), maybeFailures);
+ PropertyResult(shape), object(), output(), maybeFailures);
return linkAndAttachStub(cx, masm, attacher, ion, "read unboxed expando",
JS::TrackedOutcome::ICGetPropStub_UnboxedReadExpando);
}
@@ -2927,12 +2931,14 @@ IsCacheableDOMProxyUnshadowedSetterCall(JSContext* cx, HandleObject obj, HandleI
if (!checkObj)
return false;
- if (!LookupPropertyPure(cx, obj, id, holder.address(), shape.address()))
+ PropertyResult prop;
+ if (!LookupPropertyPure(cx, obj, id, holder.address(), &prop))
return false;
- if (!holder)
+ if (!holder || !holder->isNative())
return false;
+ shape.set(prop.shape());
return IsCacheableSetPropCallNative(checkObj, holder, shape) ||
IsCacheableSetPropCallPropertyOp(checkObj, holder, shape) ||
IsCacheableSetPropCallScripted(checkObj, holder, shape);
@@ -3344,22 +3350,26 @@ CanAttachNativeSetProp(JSContext* cx, HandleObject obj, HandleId id, const Const
// If we couldn't find the property on the object itself, do a full, but
// still pure lookup for setters.
- if (!LookupPropertyPure(cx, obj, id, holder.address(), shape.address()))
+ Rooted<PropertyResult> prop(cx);
+ if (!LookupPropertyPure(cx, obj, id, holder.address(), prop.address()))
return SetPropertyIC::CanAttachNone;
// If the object doesn't have the property, we don't know if we can attach
// a stub to add the property until we do the VM call to add. If the
// property exists as a data property on the prototype, we should add
// a new, shadowing property.
- if (obj->isNative() && (!shape || (obj != holder && holder->isNative() &&
- shape->hasDefaultSetter() && shape->hasSlot())))
+ if (obj->isNative() &&
+ (!prop || (obj != holder && holder->isNative() &&
+ prop.shape()->hasDefaultSetter() && prop.shape()->hasSlot())))
{
+ shape.set(prop.maybeShape());
return SetPropertyIC::MaybeCanAttachAddSlot;
}
- if (IsImplicitNonNativeProperty(shape))
+ if (prop.isNonNativeProperty())
return SetPropertyIC::CanAttachNone;
+ shape.set(prop.maybeShape());
if (IsCacheableSetPropCallPropertyOp(obj, holder, shape) ||
IsCacheableSetPropCallNative(obj, holder, shape) ||
IsCacheableSetPropCallScripted(obj, holder, shape))
@@ -4836,7 +4846,7 @@ BindNameIC::update(JSContext* cx, HandleScript outerScript, size_t cacheIndex,
bool
NameIC::attachReadSlot(JSContext* cx, HandleScript outerScript, IonScript* ion,
HandleObject envChain, HandleObject holderBase,
- HandleNativeObject holder, HandleShape shape)
+ HandleNativeObject holder, Handle<PropertyResult> prop)
{
MacroAssembler masm(cx, ion, outerScript, profilerLeavePc_);
Label failures;
@@ -4854,7 +4864,7 @@ NameIC::attachReadSlot(JSContext* cx, HandleScript outerScript, IonScript* ion,
// doesn't generate the extra guard.
//
// NAME ops must do their own TDZ checks.
- GenerateReadSlot(cx, ion, masm, attacher, CheckTDZ, holderBase, holder, shape, scratchReg,
+ GenerateReadSlot(cx, ion, masm, attacher, CheckTDZ, holderBase, holder, prop, scratchReg,
outputReg(), failures.used() ? &failures : nullptr);
return linkAndAttachStub(cx, masm, attacher, ion, "generic",
@@ -4880,26 +4890,26 @@ IsCacheableEnvironmentChain(JSObject* envChain, JSObject* obj)
}
static bool
-IsCacheableNameReadSlot(HandleObject envChain, HandleObject obj,
- HandleObject holder, HandleShape shape, jsbytecode* pc,
+IsCacheableNameReadSlot(JSContext* cx, HandleObject envChain, HandleObject obj,
+ HandleObject holder, Handle<PropertyResult> prop, jsbytecode* pc,
const TypedOrValueRegister& output)
{
- if (!shape)
+ if (!prop)
return false;
if (!obj->isNative())
return false;
if (obj->is<GlobalObject>()) {
// Support only simple property lookups.
- if (!IsCacheableGetPropReadSlotForIonOrCacheIR(obj, holder, shape) &&
- !IsCacheableNoProperty(obj, holder, shape, pc, output))
+ if (!IsCacheableGetPropReadSlotForIonOrCacheIR(obj, holder, prop) &&
+ !IsCacheableNoProperty(obj, holder, prop, pc, output))
return false;
} else if (obj->is<ModuleEnvironmentObject>()) {
// We don't yet support lookups in a module environment.
return false;
} else if (obj->is<CallObject>()) {
MOZ_ASSERT(obj == holder);
- if (!shape->hasDefaultGetter())
+ if (!prop.shape()->hasDefaultGetter())
return false;
} else {
// We don't yet support lookups on Block or DeclEnv objects.
@@ -4942,9 +4952,9 @@ NameIC::attachCallGetter(JSContext* cx, HandleScript outerScript, IonScript* ion
static bool
IsCacheableNameCallGetter(HandleObject envChain, HandleObject obj, HandleObject holder,
- HandleShape shape)
+ Handle<PropertyResult> prop)
{
- if (!shape)
+ if (!prop)
return false;
if (!obj->is<GlobalObject>())
return false;
@@ -4952,6 +4962,10 @@ IsCacheableNameCallGetter(HandleObject envChain, HandleObject obj, HandleObject
if (!IsCacheableEnvironmentChain(envChain, obj))
return false;
+ if (!prop || !IsCacheableProtoChainForIonOrCacheIR(obj, holder))
+ return false;
+
+ Shape* shape = prop.shape();
return IsCacheableGetPropCallNative(obj, holder, shape) ||
IsCacheableGetPropCallPropertyOp(obj, holder, shape) ||
IsCacheableGetPropCallScripted(obj, holder, shape);
@@ -4996,10 +5010,10 @@ NameIC::attachTypeOfNoProperty(JSContext* cx, HandleScript outerScript, IonScrip
static bool
IsCacheableNameNoProperty(HandleObject envChain, HandleObject obj,
- HandleObject holder, HandleShape shape, jsbytecode* pc,
+ HandleObject holder, Handle<PropertyResult> prop, jsbytecode* pc,
NameIC& cache)
{
- if (cache.isTypeOf() && !shape) {
+ if (cache.isTypeOf() && !prop) {
MOZ_ASSERT(!obj);
MOZ_ASSERT(!holder);
MOZ_ASSERT(envChain);
@@ -5029,34 +5043,35 @@ NameIC::update(JSContext* cx, HandleScript outerScript, size_t cacheIndex, Handl
RootedObject obj(cx);
RootedObject holder(cx);
- RootedShape shape(cx);
- if (!LookupName(cx, name, envChain, &obj, &holder, &shape))
+ Rooted<PropertyResult> prop(cx);
+ if (!LookupName(cx, name, envChain, &obj, &holder, &prop))
return false;
// Look first. Don't generate cache entries if the lookup fails.
if (cache.isTypeOf()) {
- if (!FetchName<true>(cx, obj, holder, name, shape, vp))
+ if (!FetchName<true>(cx, obj, holder, name, prop, vp))
return false;
} else {
- if (!FetchName<false>(cx, obj, holder, name, shape, vp))
+ if (!FetchName<false>(cx, obj, holder, name, prop, vp))
return false;
}
if (cache.canAttachStub()) {
- if (IsCacheableNameReadSlot(envChain, obj, holder, shape, pc, cache.outputReg())) {
+ if (IsCacheableNameReadSlot(cx, envChain, obj, holder, prop, pc, cache.outputReg())) {
if (!cache.attachReadSlot(cx, outerScript, ion, envChain, obj,
- holder.as<NativeObject>(), shape))
+ holder.as<NativeObject>(), prop))
{
return false;
}
- } else if (IsCacheableNameCallGetter(envChain, obj, holder, shape)) {
+ } else if (IsCacheableNameCallGetter(envChain, obj, holder, prop)) {
void* returnAddr = GetReturnAddressToIonCode(cx);
+ RootedShape shape(cx, prop.shape());
if (!cache.attachCallGetter(cx, outerScript, ion, envChain, obj, holder, shape,
returnAddr))
{
return false;
}
- } else if (IsCacheableNameNoProperty(envChain, obj, holder, shape, pc, cache)) {
+ } else if (IsCacheableNameNoProperty(envChain, obj, holder, prop, pc, cache)) {
if (!cache.attachTypeOfNoProperty(cx, outerScript, ion, envChain))
return false;
}
diff --git a/js/src/jit/IonCaches.h b/js/src/jit/IonCaches.h
index a7135000e..914965055 100644
--- a/js/src/jit/IonCaches.h
+++ b/js/src/jit/IonCaches.h
@@ -806,7 +806,7 @@ class NameIC : public IonCache
MOZ_MUST_USE bool attachReadSlot(JSContext* cx, HandleScript outerScript, IonScript* ion,
HandleObject envChain, HandleObject holderBase,
- HandleNativeObject holder, HandleShape shape);
+ HandleNativeObject holder, Handle<PropertyResult> prop);
MOZ_MUST_USE bool attachCallGetter(JSContext* cx, HandleScript outerScript, IonScript* ion,
HandleObject envChain, HandleObject obj,
@@ -839,7 +839,7 @@ IONCACHE_KIND_LIST(CACHE_CASTS)
#undef OPCODE_CASTS
bool IsCacheableProtoChainForIonOrCacheIR(JSObject* obj, JSObject* holder);
-bool IsCacheableGetPropReadSlotForIonOrCacheIR(JSObject* obj, JSObject* holder, Shape* shape);
+bool IsCacheableGetPropReadSlotForIonOrCacheIR(JSObject* obj, JSObject* holder, PropertyResult prop);
} // namespace jit
} // namespace js
diff --git a/js/src/jit/SharedIC.cpp b/js/src/jit/SharedIC.cpp
index 143489419..f8f4433af 100644
--- a/js/src/jit/SharedIC.cpp
+++ b/js/src/jit/SharedIC.cpp
@@ -2192,12 +2192,12 @@ GetDOMProxyProto(JSObject* obj)
// existence of the property on the object.
bool
EffectlesslyLookupProperty(JSContext* cx, HandleObject obj, HandleId id,
- MutableHandleObject holder, MutableHandleShape shape,
+ MutableHandleObject holder, MutableHandle<PropertyResult> prop,
bool* checkDOMProxy,
DOMProxyShadowsResult* shadowsResult,
bool* domProxyHasGeneration)
{
- shape.set(nullptr);
+ prop.setNotFound();
holder.set(nullptr);
if (checkDOMProxy) {
@@ -2231,11 +2231,11 @@ EffectlesslyLookupProperty(JSContext* cx, HandleObject obj, HandleId id,
return true;
}
- if (LookupPropertyPure(cx, checkObj, id, holder.address(), shape.address()))
+ if (LookupPropertyPure(cx, checkObj, id, holder.address(), prop.address()))
return true;
holder.set(nullptr);
- shape.set(nullptr);
+ prop.setNotFound();
return true;
}
@@ -2421,15 +2421,16 @@ TryAttachNativeGetAccessorPropStub(JSContext* cx, SharedStubInfo* info,
bool isDOMProxy;
bool domProxyHasGeneration;
DOMProxyShadowsResult domProxyShadowsResult;
- RootedShape shape(cx);
+ Rooted<PropertyResult> prop(cx);
RootedObject holder(cx);
RootedId id(cx, NameToId(name));
- if (!EffectlesslyLookupProperty(cx, obj, id, &holder, &shape, &isDOMProxy,
+ if (!EffectlesslyLookupProperty(cx, obj, id, &holder, &prop, &isDOMProxy,
&domProxyShadowsResult, &domProxyHasGeneration))
{
return false;
}
+ RootedShape shape(cx, prop.maybeShape());
ICStub* monitorStub = stub->fallbackMonitorStub()->firstMonitorStub();
bool isScripted = false;
@@ -2492,7 +2493,7 @@ TryAttachNativeGetAccessorPropStub(JSContext* cx, SharedStubInfo* info,
MOZ_ASSERT(ToWindowIfWindowProxy(obj) == cx->global());
obj = cx->global();
- if (!EffectlesslyLookupProperty(cx, obj, id, &holder, &shape, &isDOMProxy,
+ if (!EffectlesslyLookupProperty(cx, obj, id, &holder, &prop, &isDOMProxy,
&domProxyShadowsResult, &domProxyHasGeneration))
{
return false;
diff --git a/js/src/jit/SharedIC.h b/js/src/jit/SharedIC.h
index 8ad8fd495..d0038c937 100644
--- a/js/src/jit/SharedIC.h
+++ b/js/src/jit/SharedIC.h
@@ -2249,7 +2249,7 @@ StripPreliminaryObjectStubs(JSContext* cx, ICFallbackStub* stub);
MOZ_MUST_USE bool
EffectlesslyLookupProperty(JSContext* cx, HandleObject obj, HandleId name,
- MutableHandleObject holder, MutableHandleShape shape,
+ MutableHandleObject holder, MutableHandle<PropertyResult> prop,
bool* checkDOMProxy=nullptr,
DOMProxyShadowsResult* shadowsResult=nullptr,
bool* domProxyHasGeneration=nullptr);
diff --git a/js/src/jit/VMFunctions.cpp b/js/src/jit/VMFunctions.cpp
index fd41f6fbc..fbe6977bf 100644
--- a/js/src/jit/VMFunctions.cpp
+++ b/js/src/jit/VMFunctions.cpp
@@ -583,11 +583,11 @@ GetDynamicName(JSContext* cx, JSObject* envChain, JSString* str, Value* vp)
return;
}
- Shape* shape = nullptr;
+ PropertyResult prop;
JSObject* scope = nullptr;
JSObject* pobj = nullptr;
- if (LookupNameNoGC(cx, atom->asPropertyName(), envChain, &scope, &pobj, &shape)) {
- if (FetchNameNoGC(pobj, shape, MutableHandleValue::fromMarkedLocation(vp)))
+ if (LookupNameNoGC(cx, atom->asPropertyName(), envChain, &scope, &pobj, &prop)) {
+ if (FetchNameNoGC(pobj, prop, MutableHandleValue::fromMarkedLocation(vp)))
return;
}
diff --git a/js/src/jsapi-tests/testGCExactRooting.cpp b/js/src/jsapi-tests/testGCExactRooting.cpp
index aff65014a..6d41d374b 100644
--- a/js/src/jsapi-tests/testGCExactRooting.cpp
+++ b/js/src/jsapi-tests/testGCExactRooting.cpp
@@ -56,19 +56,10 @@ struct MyContainer
};
namespace js {
-template <>
-struct RootedBase<MyContainer> {
- HeapPtr<JSObject*>& obj() { return static_cast<Rooted<MyContainer>*>(this)->get().obj; }
- HeapPtr<JSString*>& str() { return static_cast<Rooted<MyContainer>*>(this)->get().str; }
-};
-template <>
-struct PersistentRootedBase<MyContainer> {
- HeapPtr<JSObject*>& obj() {
- return static_cast<PersistentRooted<MyContainer>*>(this)->get().obj;
- }
- HeapPtr<JSString*>& str() {
- return static_cast<PersistentRooted<MyContainer>*>(this)->get().str;
- }
+template <typename Wrapper>
+struct MutableWrappedPtrOperations<MyContainer, Wrapper> {
+ HeapPtr<JSObject*>& obj() { return static_cast<Wrapper*>(this)->get().obj; }
+ HeapPtr<JSString*>& str() { return static_cast<Wrapper*>(this)->get().str; }
};
} // namespace js
diff --git a/js/src/jsapi-tests/testGCHeapPostBarriers.cpp b/js/src/jsapi-tests/testGCHeapPostBarriers.cpp
index ccc986972..2353f9ae4 100644
--- a/js/src/jsapi-tests/testGCHeapPostBarriers.cpp
+++ b/js/src/jsapi-tests/testGCHeapPostBarriers.cpp
@@ -4,6 +4,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+#include "mozilla/TypeTraits.h"
#include "mozilla/UniquePtr.h"
#include "js/RootingAPI.h"
@@ -146,3 +147,110 @@ TestHeapPostBarrierInitFailure()
}
END_TEST(testGCHeapPostBarriers)
+
+BEGIN_TEST(testUnbarrieredEquality)
+{
+ // Use ArrayBuffers because they have finalizers, which allows using them
+ // in ObjectPtr without awkward conversations about nursery allocatability.
+ JS::RootedObject robj(cx, JS_NewArrayBuffer(cx, 20));
+ JS::RootedObject robj2(cx, JS_NewArrayBuffer(cx, 30));
+ cx->gc.evictNursery(); // Need tenured objects
+
+ // Need some bare pointers to compare against.
+ JSObject* obj = robj;
+ JSObject* obj2 = robj2;
+ const JSObject* constobj = robj;
+ const JSObject* constobj2 = robj2;
+
+ // Make them gray. We will make sure they stay gray. (For most reads, the
+ // barrier will unmark gray.)
+ using namespace js::gc;
+ TenuredCell* cell = &obj->asTenured();
+ TenuredCell* cell2 = &obj2->asTenured();
+ cell->markIfUnmarked(GRAY);
+ cell2->markIfUnmarked(GRAY);
+ MOZ_ASSERT(cell->isMarked(GRAY));
+ MOZ_ASSERT(cell2->isMarked(GRAY));
+
+ {
+ JS::Heap<JSObject*> heap(obj);
+ JS::Heap<JSObject*> heap2(obj2);
+ CHECK(TestWrapper(obj, obj2, heap, heap2));
+ CHECK(TestWrapper(constobj, constobj2, heap, heap2));
+ }
+
+ {
+ JS::TenuredHeap<JSObject*> heap(obj);
+ JS::TenuredHeap<JSObject*> heap2(obj2);
+ CHECK(TestWrapper(obj, obj2, heap, heap2));
+ CHECK(TestWrapper(constobj, constobj2, heap, heap2));
+ }
+
+ {
+ JS::ObjectPtr objptr(obj);
+ JS::ObjectPtr objptr2(obj2);
+ CHECK(TestWrapper(obj, obj2, objptr, objptr2));
+ CHECK(TestWrapper(constobj, constobj2, objptr, objptr2));
+ objptr.finalize(cx);
+ objptr2.finalize(cx);
+ }
+ // Sanity check that the barriers normally mark things black.
+ {
+ JS::Heap<JSObject*> heap(obj);
+ JS::Heap<JSObject*> heap2(obj2);
+ heap.get();
+ heap2.get();
+ CHECK(cell->isMarked(BLACK));
+ CHECK(cell2->isMarked(BLACK));
+ }
+
+ return true;
+}
+
+template <typename ObjectT, typename WrapperT>
+bool
+TestWrapper(ObjectT obj, ObjectT obj2, WrapperT& wrapper, WrapperT& wrapper2)
+{
+ using namespace js::gc;
+
+ const TenuredCell& cell = obj->asTenured();
+ const TenuredCell& cell2 = obj2->asTenured();
+
+ int x = 0;
+
+ CHECK(cell.isMarked(GRAY));
+ CHECK(cell2.isMarked(GRAY));
+ x += obj == obj2;
+ CHECK(cell.isMarked(GRAY));
+ CHECK(cell2.isMarked(GRAY));
+ x += obj == wrapper2;
+ CHECK(cell.isMarked(GRAY));
+ CHECK(cell2.isMarked(GRAY));
+ x += wrapper == obj2;
+ CHECK(cell.isMarked(GRAY));
+ CHECK(cell2.isMarked(GRAY));
+ x += wrapper == wrapper2;
+ CHECK(cell.isMarked(GRAY));
+ CHECK(cell2.isMarked(GRAY));
+
+ CHECK(x == 0);
+
+ x += obj != obj2;
+ CHECK(cell.isMarked(GRAY));
+ CHECK(cell2.isMarked(GRAY));
+ x += obj != wrapper2;
+ CHECK(cell.isMarked(GRAY));
+ CHECK(cell2.isMarked(GRAY));
+ x += wrapper != obj2;
+ CHECK(cell.isMarked(GRAY));
+ CHECK(cell2.isMarked(GRAY));
+ x += wrapper != wrapper2;
+ CHECK(cell.isMarked(GRAY));
+ CHECK(cell2.isMarked(GRAY));
+
+ CHECK(x == 4);
+
+ return true;
+}
+
+END_TEST(testUnbarrieredEquality)
diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp
index f4b3c9854..3901a0e63 100644
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -2947,9 +2947,9 @@ JS_AlreadyHasOwnPropertyById(JSContext* cx, HandleObject obj, HandleId id, bool*
return js::HasOwnProperty(cx, obj, id, foundp);
RootedNativeObject nativeObj(cx, &obj->as<NativeObject>());
- RootedShape prop(cx);
+ Rooted<PropertyResult> prop(cx);
NativeLookupOwnPropertyNoResolve(cx, nativeObj, id, &prop);
- *foundp = !!prop;
+ *foundp = prop.isFound();
return true;
}
diff --git a/js/src/jsapi.h b/js/src/jsapi.h
index 1eecdbf74..8e70cc152 100644
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -2546,10 +2546,14 @@ struct JS_PUBLIC_API(PropertyDescriptor) {
void trace(JSTracer* trc);
};
-template <typename Outer>
-class PropertyDescriptorOperations
+} // namespace JS
+
+namespace js {
+
+template <typename Wrapper>
+class WrappedPtrOperations<JS::PropertyDescriptor, Wrapper>
{
- const PropertyDescriptor& desc() const { return static_cast<const Outer*>(this)->get(); }
+ const JS::PropertyDescriptor& desc() const { return static_cast<const Wrapper*>(this)->get(); }
bool has(unsigned bit) const {
MOZ_ASSERT(bit != 0);
@@ -2678,10 +2682,11 @@ class PropertyDescriptorOperations
}
};
-template <typename Outer>
-class MutablePropertyDescriptorOperations : public PropertyDescriptorOperations<Outer>
+template <typename Wrapper>
+class MutableWrappedPtrOperations<JS::PropertyDescriptor, Wrapper>
+ : public js::WrappedPtrOperations<JS::PropertyDescriptor, Wrapper>
{
- PropertyDescriptor& desc() { return static_cast<Outer*>(this)->get(); }
+ JS::PropertyDescriptor& desc() { return static_cast<Wrapper*>(this)->get(); }
public:
void clear() {
@@ -2692,7 +2697,7 @@ class MutablePropertyDescriptorOperations : public PropertyDescriptorOperations<
value().setUndefined();
}
- void initFields(HandleObject obj, HandleValue v, unsigned attrs,
+ void initFields(JS::HandleObject obj, JS::HandleValue v, unsigned attrs,
JSGetterOp getterOp, JSSetterOp setterOp) {
MOZ_ASSERT(getterOp != JS_PropertyStub);
MOZ_ASSERT(setterOp != JS_StrictPropertyStub);
@@ -2704,7 +2709,7 @@ class MutablePropertyDescriptorOperations : public PropertyDescriptorOperations<
setSetter(setterOp);
}
- void assign(PropertyDescriptor& other) {
+ void assign(JS::PropertyDescriptor& other) {
object().set(other.obj);
setAttributes(other.attrs);
setGetter(other.getter);
@@ -2712,7 +2717,7 @@ class MutablePropertyDescriptorOperations : public PropertyDescriptorOperations<
value().set(other.value);
}
- void setDataDescriptor(HandleValue v, unsigned attrs) {
+ void setDataDescriptor(JS::HandleValue v, unsigned attrs) {
MOZ_ASSERT((attrs & ~(JSPROP_ENUMERATE |
JSPROP_PERMANENT |
JSPROP_READONLY |
@@ -2787,26 +2792,7 @@ class MutablePropertyDescriptorOperations : public PropertyDescriptorOperations<
}
};
-} /* namespace JS */
-
-namespace js {
-
-template <>
-class RootedBase<JS::PropertyDescriptor>
- : public JS::MutablePropertyDescriptorOperations<JS::Rooted<JS::PropertyDescriptor>>
-{};
-
-template <>
-class HandleBase<JS::PropertyDescriptor>
- : public JS::PropertyDescriptorOperations<JS::Handle<JS::PropertyDescriptor>>
-{};
-
-template <>
-class MutableHandleBase<JS::PropertyDescriptor>
- : public JS::MutablePropertyDescriptorOperations<JS::MutableHandle<JS::PropertyDescriptor>>
-{};
-
-} /* namespace js */
+} // namespace js
namespace JS {
diff --git a/js/src/jscompartment.cpp b/js/src/jscompartment.cpp
index ebf2d178f..5e33f27f7 100644
--- a/js/src/jscompartment.cpp
+++ b/js/src/jscompartment.cpp
@@ -722,8 +722,9 @@ JSCompartment::sweepAfterMinorGC(JSTracer* trc)
{
globalWriteBarriered = 0;
- if (innerViews.needsSweepAfterMinorGC())
- innerViews.sweepAfterMinorGC();
+ InnerViewTable& table = innerViews.get();
+ if (table.needsSweepAfterMinorGC())
+ table.sweepAfterMinorGC();
crossCompartmentWrappers.sweepAfterMinorGC(trc);
}
diff --git a/js/src/jsfriendapi.h b/js/src/jsfriendapi.h
index 95f49b35e..494bcb042 100644
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -331,7 +331,7 @@ extern JS_FRIEND_DATA(const js::ObjectOps) ProxyObjectOps;
extern JS_FRIEND_API(bool)
proxy_LookupProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::MutableHandleObject objp,
- JS::MutableHandle<Shape*> propp);
+ JS::MutableHandle<JS::PropertyResult> propp);
extern JS_FRIEND_API(bool)
proxy_DefineProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id,
JS::Handle<JS::PropertyDescriptor> desc,
diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp
index a243f4468..a23ac6336 100644
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -2116,7 +2116,7 @@ JSObject::constructHook() const
bool
js::LookupProperty(JSContext* cx, HandleObject obj, js::HandleId id,
- MutableHandleObject objp, MutableHandleShape propp)
+ MutableHandleObject objp, MutableHandle<PropertyResult> propp)
{
/* NB: The logic of lookupProperty is implicitly reflected in
* BaselineIC.cpp's |EffectlesslyLookupProperty| logic.
@@ -2129,7 +2129,7 @@ js::LookupProperty(JSContext* cx, HandleObject obj, js::HandleId id,
bool
js::LookupName(JSContext* cx, HandlePropertyName name, HandleObject envChain,
- MutableHandleObject objp, MutableHandleObject pobjp, MutableHandleShape propp)
+ MutableHandleObject objp, MutableHandleObject pobjp, MutableHandle<PropertyResult> propp)
{
RootedId id(cx, NameToId(name));
@@ -2144,13 +2144,13 @@ js::LookupName(JSContext* cx, HandlePropertyName name, HandleObject envChain,
objp.set(nullptr);
pobjp.set(nullptr);
- propp.set(nullptr);
+ propp.setNotFound();
return true;
}
bool
js::LookupNameNoGC(JSContext* cx, PropertyName* name, JSObject* envChain,
- JSObject** objp, JSObject** pobjp, Shape** propp)
+ JSObject** objp, JSObject** pobjp, PropertyResult* propp)
{
AutoAssertNoException nogc(cx);
@@ -2177,13 +2177,13 @@ js::LookupNameWithGlobalDefault(JSContext* cx, HandlePropertyName name, HandleOb
RootedId id(cx, NameToId(name));
RootedObject pobj(cx);
- RootedShape shape(cx);
+ Rooted<PropertyResult> prop(cx);
RootedObject env(cx, envChain);
for (; !env->is<GlobalObject>(); env = env->enclosingEnvironment()) {
- if (!LookupProperty(cx, env, id, &pobj, &shape))
+ if (!LookupProperty(cx, env, id, &pobj, &prop))
return false;
- if (shape)
+ if (prop)
break;
}
@@ -2198,20 +2198,20 @@ js::LookupNameUnqualified(JSContext* cx, HandlePropertyName name, HandleObject e
RootedId id(cx, NameToId(name));
RootedObject pobj(cx);
- RootedShape shape(cx);
+ Rooted<PropertyResult> prop(cx);
RootedObject env(cx, envChain);
for (; !env->isUnqualifiedVarObj(); env = env->enclosingEnvironment()) {
- if (!LookupProperty(cx, env, id, &pobj, &shape))
+ if (!LookupProperty(cx, env, id, &pobj, &prop))
return false;
- if (shape)
+ if (prop)
break;
}
// See note above RuntimeLexicalErrorObject.
if (pobj == env) {
bool isTDZ = false;
- if (shape && name != cx->names().dotThis) {
+ if (prop && name != cx->names().dotThis) {
// Treat Debugger environments specially for TDZ checks, as they
// look like non-native environments but in fact wrap native
// environments.
@@ -2222,7 +2222,7 @@ js::LookupNameUnqualified(JSContext* cx, HandlePropertyName name, HandleObject e
return false;
isTDZ = IsUninitializedLexical(v);
} else {
- isTDZ = IsUninitializedLexicalSlot(env, shape);
+ isTDZ = IsUninitializedLexicalSlot(env, prop);
}
}
@@ -2230,7 +2230,7 @@ js::LookupNameUnqualified(JSContext* cx, HandlePropertyName name, HandleObject e
env = RuntimeLexicalErrorObject::create(cx, env, JSMSG_UNINITIALIZED_LEXICAL);
if (!env)
return false;
- } else if (env->is<LexicalEnvironmentObject>() && !shape->writable()) {
+ } else if (env->is<LexicalEnvironmentObject>() && !prop.shape()->writable()) {
// Assigning to a named lambda callee name is a no-op in sloppy mode.
Rooted<LexicalEnvironmentObject*> lexicalEnv(cx, &env->as<LexicalEnvironmentObject>());
if (lexicalEnv->isExtensible() ||
@@ -2262,16 +2262,16 @@ js::HasOwnProperty(JSContext* cx, HandleObject obj, HandleId id, bool* result)
return true;
}
- RootedShape shape(cx);
- if (!NativeLookupOwnProperty<CanGC>(cx, obj.as<NativeObject>(), id, &shape))
+ Rooted<PropertyResult> prop(cx);
+ if (!NativeLookupOwnProperty<CanGC>(cx, obj.as<NativeObject>(), id, &prop))
return false;
- *result = (shape != nullptr);
+ *result = prop.isFound();
return true;
}
bool
js::LookupPropertyPure(ExclusiveContext* cx, JSObject* obj, jsid id, JSObject** objp,
- Shape** propp)
+ PropertyResult* propp)
{
bool isTypedArrayOutOfRange = false;
do {
@@ -2292,12 +2292,12 @@ js::LookupPropertyPure(ExclusiveContext* cx, JSObject* obj, jsid id, JSObject**
} while (obj);
*objp = nullptr;
- *propp = nullptr;
+ propp->setNotFound();
return true;
}
bool
-js::LookupOwnPropertyPure(ExclusiveContext* cx, JSObject* obj, jsid id, Shape** propp,
+js::LookupOwnPropertyPure(ExclusiveContext* cx, JSObject* obj, jsid id, PropertyResult* propp,
bool* isTypedArrayOutOfRange /* = nullptr */)
{
JS::AutoCheckCannotGC nogc;
@@ -2308,7 +2308,7 @@ js::LookupOwnPropertyPure(ExclusiveContext* cx, JSObject* obj, jsid id, Shape**
// Search for a native dense element, typed array element, or property.
if (JSID_IS_INT(id) && obj->as<NativeObject>().containsDenseElement(JSID_TO_INT(id))) {
- MarkDenseOrTypedArrayElementFound<NoGC>(propp);
+ propp->setDenseOrTypedArrayElement();
return true;
}
@@ -2316,9 +2316,9 @@ js::LookupOwnPropertyPure(ExclusiveContext* cx, JSObject* obj, jsid id, Shape**
uint64_t index;
if (IsTypedArrayIndex(id, &index)) {
if (index < obj->as<TypedArrayObject>().length()) {
- MarkDenseOrTypedArrayElementFound<NoGC>(propp);
+ propp->setDenseOrTypedArrayElement();
} else {
- *propp = nullptr;
+ propp->setNotFound();
if (isTypedArrayOutOfRange)
*isTypedArrayOutOfRange = true;
}
@@ -2327,7 +2327,7 @@ js::LookupOwnPropertyPure(ExclusiveContext* cx, JSObject* obj, jsid id, Shape**
}
if (Shape* shape = obj->as<NativeObject>().lookupPure(id)) {
- *propp = shape;
+ propp->setNativeProperty(shape);
return true;
}
@@ -2337,31 +2337,31 @@ js::LookupOwnPropertyPure(ExclusiveContext* cx, JSObject* obj, jsid id, Shape**
return false;
} else if (obj->is<UnboxedPlainObject>()) {
if (obj->as<UnboxedPlainObject>().containsUnboxedOrExpandoProperty(cx, id)) {
- MarkNonNativePropertyFound<NoGC>(propp);
+ propp->setNonNativeProperty();
return true;
}
} else if (obj->is<UnboxedArrayObject>()) {
if (obj->as<UnboxedArrayObject>().containsProperty(cx, id)) {
- MarkNonNativePropertyFound<NoGC>(propp);
+ propp->setNonNativeProperty();
return true;
}
} else if (obj->is<TypedObject>()) {
if (obj->as<TypedObject>().typeDescr().hasProperty(cx->names(), id)) {
- MarkNonNativePropertyFound<NoGC>(propp);
+ propp->setNonNativeProperty();
return true;
}
} else {
return false;
}
- *propp = nullptr;
+ propp->setNotFound();
return true;
}
static inline bool
-NativeGetPureInline(NativeObject* pobj, jsid id, Shape* shape, Value* vp)
+NativeGetPureInline(NativeObject* pobj, jsid id, PropertyResult prop, Value* vp)
{
- if (IsImplicitDenseOrTypedArrayElement(shape)) {
+ if (prop.isDenseOrTypedArrayElement()) {
// For simplicity we ignore the TypedArray with string index case.
if (!JSID_IS_INT(id))
return false;
@@ -2371,6 +2371,7 @@ NativeGetPureInline(NativeObject* pobj, jsid id, Shape* shape, Value* vp)
}
// Fail if we have a custom getter.
+ Shape* shape = prop.shape();
if (!shape->hasDefaultGetter())
return false;
@@ -2388,22 +2389,23 @@ bool
js::GetPropertyPure(ExclusiveContext* cx, JSObject* obj, jsid id, Value* vp)
{
JSObject* pobj;
- Shape* shape;
- if (!LookupPropertyPure(cx, obj, id, &pobj, &shape))
+ PropertyResult prop;
+ if (!LookupPropertyPure(cx, obj, id, &pobj, &prop))
return false;
- if (!shape) {
+ if (!prop) {
vp->setUndefined();
return true;
}
- return pobj->isNative() && NativeGetPureInline(&pobj->as<NativeObject>(), id, shape, vp);
+ return pobj->isNative() && NativeGetPureInline(&pobj->as<NativeObject>(), id, prop, vp);
}
static inline bool
-NativeGetGetterPureInline(Shape* shape, JSFunction** fp)
+NativeGetGetterPureInline(PropertyResult prop, JSFunction** fp)
{
- if (!IsImplicitDenseOrTypedArrayElement(shape) && shape->hasGetterObject()) {
+ if (!prop.isDenseOrTypedArrayElement() && prop.shape()->hasGetterObject()) {
+ Shape* shape = prop.shape();
if (shape->getterObject()->is<JSFunction>()) {
*fp = &shape->getterObject()->as<JSFunction>();
return true;
@@ -2420,32 +2422,32 @@ js::GetGetterPure(ExclusiveContext* cx, JSObject* obj, jsid id, JSFunction** fp)
/* Just like GetPropertyPure, but get getter function, without invoking
* it. */
JSObject* pobj;
- Shape* shape;
- if (!LookupPropertyPure(cx, obj, id, &pobj, &shape))
+ PropertyResult prop;
+ if (!LookupPropertyPure(cx, obj, id, &pobj, &prop))
return false;
- if (!shape) {
+ if (!prop) {
*fp = nullptr;
return true;
}
- return pobj->isNative() && NativeGetGetterPureInline(shape, fp);
+ return prop.isNativeProperty() && NativeGetGetterPureInline(prop, fp);
}
bool
js::GetOwnGetterPure(ExclusiveContext* cx, JSObject* obj, jsid id, JSFunction** fp)
{
JS::AutoCheckCannotGC nogc;
- Shape* shape;
- if (!LookupOwnPropertyPure(cx, obj, id, &shape))
+ PropertyResult prop;
+ if (!LookupOwnPropertyPure(cx, obj, id, &prop))
return false;
- if (!shape) {
+ if (!prop) {
*fp = nullptr;
return true;
}
- return NativeGetGetterPureInline(shape, fp);
+ return prop.isNativeProperty() && NativeGetGetterPureInline(prop, fp);
}
bool
@@ -2453,14 +2455,14 @@ js::GetOwnNativeGetterPure(JSContext* cx, JSObject* obj, jsid id, JSNative* nati
{
JS::AutoCheckCannotGC nogc;
*native = nullptr;
- Shape* shape;
- if (!LookupOwnPropertyPure(cx, obj, id, &shape))
+ PropertyResult prop;
+ if (!LookupOwnPropertyPure(cx, obj, id, &prop))
return false;
- if (!shape || IsImplicitDenseOrTypedArrayElement(shape) || !shape->hasGetterObject())
+ if (!prop || prop.isDenseOrTypedArrayElement() || !prop.shape()->hasGetterObject())
return true;
- JSObject* getterObj = shape->getterObject();
+ JSObject* getterObj = prop.shape()->getterObject();
if (!getterObj->is<JSFunction>())
return true;
@@ -2475,12 +2477,12 @@ js::GetOwnNativeGetterPure(JSContext* cx, JSObject* obj, jsid id, JSNative* nati
bool
js::HasOwnDataPropertyPure(JSContext* cx, JSObject* obj, jsid id, bool* result)
{
- Shape* shape = nullptr;
- if (!LookupOwnPropertyPure(cx, obj, id, &shape))
+ PropertyResult prop;
+ if (!LookupOwnPropertyPure(cx, obj, id, &prop))
return false;
- *result = shape && !IsImplicitDenseOrTypedArrayElement(shape) && shape->hasDefaultGetter() &&
- shape->hasSlot();
+ *result = prop && !prop.isDenseOrTypedArrayElement() && prop.shape()->hasDefaultGetter() &&
+ prop.shape()->hasSlot();
return true;
}
diff --git a/js/src/jsobj.h b/js/src/jsobj.h
index ca48f8de7..5e0cc347f 100644
--- a/js/src/jsobj.h
+++ b/js/src/jsobj.h
@@ -299,7 +299,6 @@ class JSObject : public js::gc::Cell
static const JS::TraceKind TraceKind = JS::TraceKind::Object;
static const size_t MaxTagBits = 3;
- static bool isNullLike(const JSObject* obj) { return uintptr_t(obj) < (1 << MaxTagBits); }
MOZ_ALWAYS_INLINE JS::Zone* zone() const {
return group_->zone();
@@ -587,21 +586,23 @@ class JSObject : public js::gc::Cell
void operator=(const JSObject& other) = delete;
};
-template <class U>
+template <typename Wrapper>
+template <typename U>
MOZ_ALWAYS_INLINE JS::Handle<U*>
-js::RootedBase<JSObject*>::as() const
+js::RootedBase<JSObject*, Wrapper>::as() const
{
- const JS::Rooted<JSObject*>& self = *static_cast<const JS::Rooted<JSObject*>*>(this);
- MOZ_ASSERT(self->is<U>());
+ const Wrapper& self = *static_cast<const Wrapper*>(this);
+ MOZ_ASSERT(self->template is<U>());
return Handle<U*>::fromMarkedLocation(reinterpret_cast<U* const*>(self.address()));
}
+template <typename Wrapper>
template <class U>
MOZ_ALWAYS_INLINE JS::Handle<U*>
-js::HandleBase<JSObject*>::as() const
+js::HandleBase<JSObject*, Wrapper>::as() const
{
const JS::Handle<JSObject*>& self = *static_cast<const JS::Handle<JSObject*>*>(this);
- MOZ_ASSERT(self->is<U>());
+ MOZ_ASSERT(self->template is<U>());
return Handle<U*>::fromMarkedLocation(reinterpret_cast<U* const*>(self.address()));
}
@@ -633,7 +634,6 @@ struct JSObject_Slots16 : JSObject { void* data[3]; js::Value fslots[16]; };
/* static */ MOZ_ALWAYS_INLINE void
JSObject::readBarrier(JSObject* obj)
{
- MOZ_ASSERT_IF(obj, !isNullLike(obj));
if (obj && obj->isTenured())
obj->asTenured().readBarrier(&obj->asTenured());
}
@@ -641,7 +641,6 @@ JSObject::readBarrier(JSObject* obj)
/* static */ MOZ_ALWAYS_INLINE void
JSObject::writeBarrierPre(JSObject* obj)
{
- MOZ_ASSERT_IF(obj, !isNullLike(obj));
if (obj && obj->isTenured())
obj->asTenured().writeBarrierPre(&obj->asTenured());
}
@@ -650,8 +649,6 @@ JSObject::writeBarrierPre(JSObject* obj)
JSObject::writeBarrierPost(void* cellp, JSObject* prev, JSObject* next)
{
MOZ_ASSERT(cellp);
- MOZ_ASSERT_IF(next, !IsNullTaggedPointer(next));
- MOZ_ASSERT_IF(prev, !IsNullTaggedPointer(prev));
// If the target needs an entry, add it.
js::gc::StoreBuffer* buffer;
@@ -997,11 +994,11 @@ GetPropertyDescriptor(JSContext* cx, HandleObject obj, HandleId id,
*/
extern bool
LookupProperty(JSContext* cx, HandleObject obj, HandleId id,
- MutableHandleObject objp, MutableHandleShape propp);
+ MutableHandleObject objp, MutableHandle<PropertyResult> propp);
inline bool
LookupProperty(JSContext* cx, HandleObject obj, PropertyName* name,
- MutableHandleObject objp, MutableHandleShape propp)
+ MutableHandleObject objp, MutableHandle<PropertyResult> propp)
{
RootedId id(cx, NameToId(name));
return LookupProperty(cx, obj, id, objp, propp);
@@ -1193,11 +1190,11 @@ ReadPropertyDescriptors(JSContext* cx, HandleObject props, bool checkAccessors,
/* Read the name using a dynamic lookup on the scopeChain. */
extern bool
LookupName(JSContext* cx, HandlePropertyName name, HandleObject scopeChain,
- MutableHandleObject objp, MutableHandleObject pobjp, MutableHandleShape propp);
+ MutableHandleObject objp, MutableHandleObject pobjp, MutableHandle<PropertyResult> propp);
extern bool
LookupNameNoGC(JSContext* cx, PropertyName* name, JSObject* scopeChain,
- JSObject** objp, JSObject** pobjp, Shape** propp);
+ JSObject** objp, JSObject** pobjp, PropertyResult* propp);
/*
* Like LookupName except returns the global object if 'name' is not found in
@@ -1231,10 +1228,10 @@ FindVariableScope(JSContext* cx, JSFunction** funp);
bool
LookupPropertyPure(ExclusiveContext* cx, JSObject* obj, jsid id, JSObject** objp,
- Shape** propp);
+ PropertyResult* propp);
bool
-LookupOwnPropertyPure(ExclusiveContext* cx, JSObject* obj, jsid id, Shape** propp,
+LookupOwnPropertyPure(ExclusiveContext* cx, JSObject* obj, jsid id, PropertyResult* propp,
bool* isTypedArrayOutOfRange = nullptr);
bool
diff --git a/js/src/jsobjinlines.h b/js/src/jsobjinlines.h
index 8a55cd435..07eeff655 100644
--- a/js/src/jsobjinlines.h
+++ b/js/src/jsobjinlines.h
@@ -585,11 +585,11 @@ HasNoToPrimitiveMethodPure(JSObject* obj, JSContext* cx)
{
jsid id = SYMBOL_TO_JSID(cx->wellKnownSymbols().toPrimitive);
JSObject* pobj;
- Shape* shape;
- if (!LookupPropertyPure(cx, obj, id, &pobj, &shape))
+ PropertyResult prop;
+ if (!LookupPropertyPure(cx, obj, id, &pobj, &prop))
return false;
- return !shape;
+ return !prop;
}
/* ES6 draft rev 28 (2014 Oct 14) 7.1.14 */
diff --git a/js/src/json.cpp b/js/src/json.cpp
index e32994e90..f3cf22dac 100644
--- a/js/src/json.cpp
+++ b/js/src/json.cpp
@@ -445,9 +445,9 @@ JO(JSContext* cx, HandleObject obj, StringifyContext* scx)
#ifdef DEBUG
if (scx->maybeSafely) {
RootedNativeObject nativeObj(cx, &obj->as<NativeObject>());
- RootedShape prop(cx);
+ Rooted<PropertyResult> prop(cx);
NativeLookupOwnPropertyNoResolve(cx, nativeObj, id, &prop);
- MOZ_ASSERT(prop && prop->isDataDescriptor());
+ MOZ_ASSERT(prop && prop.isNativeProperty() && prop.shape()->isDataDescriptor());
}
#endif // DEBUG
if (!GetProperty(cx, obj, obj, id, &outputValue))
diff --git a/js/src/proxy/Proxy.cpp b/js/src/proxy/Proxy.cpp
index 376bbcdda..6f91dfb10 100644
--- a/js/src/proxy/Proxy.cpp
+++ b/js/src/proxy/Proxy.cpp
@@ -530,18 +530,18 @@ Proxy::trace(JSTracer* trc, JSObject* proxy)
bool
js::proxy_LookupProperty(JSContext* cx, HandleObject obj, HandleId id,
- MutableHandleObject objp, MutableHandleShape propp)
+ MutableHandleObject objp, MutableHandle<JS::PropertyResult> propp)
{
bool found;
if (!Proxy::has(cx, obj, id, &found))
return false;
if (found) {
- MarkNonNativePropertyFound<CanGC>(propp);
+ propp.setNonNativeProperty();
objp.set(obj);
} else {
+ propp.setNotFound();
objp.set(nullptr);
- propp.set(nullptr);
}
return true;
}
diff --git a/js/src/vm/ArrayBufferObject.cpp b/js/src/vm/ArrayBufferObject.cpp
index 1de3d3b1e..5d355ada9 100644
--- a/js/src/vm/ArrayBufferObject.cpp
+++ b/js/src/vm/ArrayBufferObject.cpp
@@ -352,7 +352,7 @@ ArrayBufferObject::detach(JSContext* cx, Handle<ArrayBufferObject*> buffer,
// Update all views of the buffer to account for the buffer having been
// detached, and clear the buffer's data and list of views.
- auto& innerViews = cx->compartment()->innerViews;
+ auto& innerViews = cx->compartment()->innerViews.get();
if (InnerViewTable::ViewVector* views = innerViews.maybeViewsUnbarriered(buffer)) {
for (size_t i = 0; i < views->length(); i++)
NoteViewBufferWasDetached((*views)[i], newContents, cx);
@@ -427,7 +427,7 @@ ArrayBufferObject::changeContents(JSContext* cx, BufferContents newContents,
setNewData(cx->runtime()->defaultFreeOp(), newContents, ownsState);
// Update all views.
- auto& innerViews = cx->compartment()->innerViews;
+ auto& innerViews = cx->compartment()->innerViews.get();
if (InnerViewTable::ViewVector* views = innerViews.maybeViewsUnbarriered(this)) {
for (size_t i = 0; i < views->length(); i++)
changeViewContents(cx, (*views)[i], oldDataPointer, newContents);
diff --git a/js/src/vm/ArrayBufferObject.h b/js/src/vm/ArrayBufferObject.h
index e6dbd3096..87dce34ba 100644
--- a/js/src/vm/ArrayBufferObject.h
+++ b/js/src/vm/ArrayBufferObject.h
@@ -541,7 +541,6 @@ class InnerViewTable
typedef Vector<ArrayBufferViewObject*, 1, SystemAllocPolicy> ViewVector;
friend class ArrayBufferObject;
- friend class WeakCacheBase<InnerViewTable>;
private:
struct MapGCPolicy {
@@ -602,23 +601,15 @@ class InnerViewTable
size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf);
};
-template <>
-class WeakCacheBase<InnerViewTable>
+template <typename Wrapper>
+class MutableWrappedPtrOperations<InnerViewTable, Wrapper>
+ : public WrappedPtrOperations<InnerViewTable, Wrapper>
{
InnerViewTable& table() {
- return static_cast<JS::WeakCache<InnerViewTable>*>(this)->get();
- }
- const InnerViewTable& table() const {
- return static_cast<const JS::WeakCache<InnerViewTable>*>(this)->get();
+ return static_cast<Wrapper*>(this)->get();
}
public:
- InnerViewTable::ViewVector* maybeViewsUnbarriered(ArrayBufferObject* obj) {
- return table().maybeViewsUnbarriered(obj);
- }
- void removeViews(ArrayBufferObject* obj) { table().removeViews(obj); }
- void sweepAfterMinorGC() { table().sweepAfterMinorGC(); }
- bool needsSweepAfterMinorGC() const { return table().needsSweepAfterMinorGC(); }
size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) {
return table().sizeOfExcludingThis(mallocSizeOf);
}
diff --git a/js/src/vm/Debugger.cpp b/js/src/vm/Debugger.cpp
index 1c875c606..0c021ff0e 100644
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -10098,12 +10098,14 @@ DebuggerObject::forceLexicalInitializationByName(JSContext* cx, HandleDebuggerOb
RootedObject globalLexical(cx, &referent->lexicalEnvironment());
RootedObject pobj(cx);
- RootedShape shape(cx);
- if (!LookupProperty(cx, globalLexical, id, &pobj, &shape))
+ Rooted<PropertyResult> prop(cx);
+ if (!LookupProperty(cx, globalLexical, id, &pobj, &prop))
return false;
result = false;
- if (shape) {
+ if (prop) {
+ MOZ_ASSERT(prop.isNativeProperty());
+ Shape* shape = prop.shape();
Value v = globalLexical->as<NativeObject>().getSlot(shape->slot());
if (shape->hasSlot() && v.isMagic() && v.whyMagic() == JS_UNINITIALIZED_LEXICAL) {
globalLexical->as<NativeObject>().setSlot(shape->slot(), UndefinedValue());
diff --git a/js/src/vm/EnvironmentObject.cpp b/js/src/vm/EnvironmentObject.cpp
index bffa32f6b..4e74b95ab 100644
--- a/js/src/vm/EnvironmentObject.cpp
+++ b/js/src/vm/EnvironmentObject.cpp
@@ -518,14 +518,14 @@ ModuleEnvironmentObject::fixEnclosingEnvironmentAfterCompartmentMerge(GlobalObje
/* static */ bool
ModuleEnvironmentObject::lookupProperty(JSContext* cx, HandleObject obj, HandleId id,
- MutableHandleObject objp, MutableHandleShape propp)
+ MutableHandleObject objp, MutableHandle<PropertyResult> propp)
{
const IndirectBindingMap& bindings = obj->as<ModuleEnvironmentObject>().importBindings();
Shape* shape;
ModuleEnvironmentObject* env;
if (bindings.lookup(id, &env, &shape)) {
objp.set(env);
- propp.set(shape);
+ propp.setNativeProperty(shape);
return true;
}
@@ -688,13 +688,13 @@ CheckUnscopables(JSContext *cx, HandleObject obj, HandleId id, bool *scopable)
static bool
with_LookupProperty(JSContext* cx, HandleObject obj, HandleId id,
- MutableHandleObject objp, MutableHandleShape propp)
+ MutableHandleObject objp, MutableHandle<PropertyResult> propp)
{
// SpiderMonkey-specific: consider internal '.generator' and '.this' names
// to be unscopable.
if (IsUnscopableDotName(cx, id)) {
objp.set(nullptr);
- propp.set(nullptr);
+ propp.setNotFound();
return true;
}
@@ -708,7 +708,7 @@ with_LookupProperty(JSContext* cx, HandleObject obj, HandleId id,
return false;
if (!scopable) {
objp.set(nullptr);
- propp.set(nullptr);
+ propp.setNotFound();
}
}
return true;
@@ -1104,7 +1104,7 @@ ReportRuntimeLexicalErrorId(JSContext* cx, unsigned errorNumber, HandleId id)
static bool
lexicalError_LookupProperty(JSContext* cx, HandleObject obj, HandleId id,
- MutableHandleObject objp, MutableHandleShape propp)
+ MutableHandleObject objp, MutableHandle<PropertyResult> propp)
{
ReportRuntimeLexicalErrorId(cx, obj->as<RuntimeLexicalErrorObject>().errorNumber(), id);
return false;
diff --git a/js/src/vm/EnvironmentObject.h b/js/src/vm/EnvironmentObject.h
index 0277e7c65..752eb5c65 100644
--- a/js/src/vm/EnvironmentObject.h
+++ b/js/src/vm/EnvironmentObject.h
@@ -407,7 +407,7 @@ class ModuleEnvironmentObject : public EnvironmentObject
private:
static bool lookupProperty(JSContext* cx, HandleObject obj, HandleId id,
- MutableHandleObject objp, MutableHandleShape propp);
+ MutableHandleObject objp, MutableHandle<PropertyResult> propp);
static bool hasProperty(JSContext* cx, HandleObject obj, HandleId id, bool* foundp);
static bool getProperty(JSContext* cx, HandleObject obj, HandleValue receiver, HandleId id,
MutableHandleValue vp);
diff --git a/js/src/vm/GeneratorObject.cpp b/js/src/vm/GeneratorObject.cpp
index 018e5a481..9265a1b62 100644
--- a/js/src/vm/GeneratorObject.cpp
+++ b/js/src/vm/GeneratorObject.cpp
@@ -363,12 +363,14 @@ js::CheckStarGeneratorResumptionValue(JSContext* cx, HandleValue v)
// It should have `value` data property, but the type doesn't matter
JSObject* ignored;
- Shape* shape;
- if (!LookupPropertyPure(cx, obj, NameToId(cx->names().value), &ignored, &shape))
+ PropertyResult prop;
+ if (!LookupPropertyPure(cx, obj, NameToId(cx->names().value), &ignored, &prop))
return false;
- if (!shape)
+ if (!prop)
return false;
- if (!shape->hasDefaultGetter())
+ if (!prop.isNativeProperty())
+ return false;
+ if (!prop.shape()->hasDefaultGetter())
return false;
return true;
diff --git a/js/src/vm/Interpreter-inl.h b/js/src/vm/Interpreter-inl.h
index 2e94a2ab2..5c2320d3f 100644
--- a/js/src/vm/Interpreter-inl.h
+++ b/js/src/vm/Interpreter-inl.h
@@ -78,17 +78,18 @@ IsUninitializedLexical(const Value& val)
}
static inline bool
-IsUninitializedLexicalSlot(HandleObject obj, HandleShape shape)
+IsUninitializedLexicalSlot(HandleObject obj, Handle<PropertyResult> prop)
{
- MOZ_ASSERT(shape);
+ MOZ_ASSERT(prop);
if (obj->is<WithEnvironmentObject>())
return false;
- // We check for IsImplicitDenseOrTypedArrayElement even though the shape
- // is always a non-indexed property because proxy hooks may return a
- // "non-native property found" shape, which happens to be encoded in the
- // same way as the "dense element" shape. See MarkNonNativePropertyFound.
- if (IsImplicitDenseOrTypedArrayElement(shape) ||
- !shape->hasSlot() ||
+
+ // Proxy hooks may return a non-native property.
+ if (prop.isNonNativeProperty())
+ return false;
+
+ Shape* shape = prop.shape();
+ if (!shape->hasSlot() ||
!shape->hasDefaultGetter() ||
!shape->hasDefaultSetter())
{
@@ -174,9 +175,9 @@ GetLengthProperty(const Value& lval, MutableHandleValue vp)
template <bool TypeOf> inline bool
FetchName(JSContext* cx, HandleObject obj, HandleObject obj2, HandlePropertyName name,
- HandleShape shape, MutableHandleValue vp)
+ Handle<PropertyResult> prop, MutableHandleValue vp)
{
- if (!shape) {
+ if (!prop) {
if (TypeOf) {
vp.setUndefined();
return true;
@@ -190,6 +191,7 @@ FetchName(JSContext* cx, HandleObject obj, HandleObject obj2, HandlePropertyName
if (!GetProperty(cx, obj, obj, id, vp))
return false;
} else {
+ RootedShape shape(cx, prop.shape());
RootedObject normalized(cx, obj);
if (normalized->is<WithEnvironmentObject>() && !shape->hasDefaultGetter())
normalized = &normalized->as<WithEnvironmentObject>().object();
@@ -213,9 +215,13 @@ FetchName(JSContext* cx, HandleObject obj, HandleObject obj2, HandlePropertyName
}
inline bool
-FetchNameNoGC(JSObject* pobj, Shape* shape, MutableHandleValue vp)
+FetchNameNoGC(JSObject* pobj, PropertyResult prop, MutableHandleValue vp)
{
- if (!shape || !pobj->isNative() || !shape->isDataDescriptor() || !shape->hasDefaultGetter())
+ if (!prop || !pobj->isNative())
+ return false;
+
+ Shape* shape = prop.shape();
+ if (!shape->isDataDescriptor() || !shape->hasDefaultGetter())
return false;
vp.set(pobj->as<NativeObject>().getSlot(shape->slot()));
@@ -361,7 +367,7 @@ DefVarOperation(JSContext* cx, HandleObject varobj, HandlePropertyName dn, unsig
}
#endif
- RootedShape prop(cx);
+ Rooted<PropertyResult> prop(cx);
RootedObject obj2(cx);
if (!LookupProperty(cx, varobj, dn, &obj2, &prop))
return false;
diff --git a/js/src/vm/Interpreter.cpp b/js/src/vm/Interpreter.cpp
index 56f715e2b..cf58e2d60 100644
--- a/js/src/vm/Interpreter.cpp
+++ b/js/src/vm/Interpreter.cpp
@@ -210,27 +210,27 @@ GetNameOperation(JSContext* cx, InterpreterFrame* fp, jsbytecode* pc, MutableHan
if (IsGlobalOp(JSOp(*pc)) && !fp->script()->hasNonSyntacticScope())
obj = &obj->global().lexicalEnvironment();
- Shape* shape = nullptr;
+ PropertyResult prop;
JSObject* env = nullptr;
JSObject* pobj = nullptr;
- if (LookupNameNoGC(cx, name, obj, &env, &pobj, &shape)) {
- if (FetchNameNoGC(pobj, shape, vp))
+ if (LookupNameNoGC(cx, name, obj, &env, &pobj, &prop)) {
+ if (FetchNameNoGC(pobj, prop, vp))
return true;
}
RootedObject objRoot(cx, obj), envRoot(cx), pobjRoot(cx);
RootedPropertyName nameRoot(cx, name);
- RootedShape shapeRoot(cx);
+ Rooted<PropertyResult> propRoot(cx);
- if (!LookupName(cx, nameRoot, objRoot, &envRoot, &pobjRoot, &shapeRoot))
+ if (!LookupName(cx, nameRoot, objRoot, &envRoot, &pobjRoot, &propRoot))
return false;
/* Kludge to allow (typeof foo == "undefined") tests. */
JSOp op2 = JSOp(pc[JSOP_GETNAME_LENGTH]);
if (op2 == JSOP_TYPEOF)
- return FetchName<true>(cx, envRoot, pobjRoot, nameRoot, shapeRoot, vp);
+ return FetchName<true>(cx, envRoot, pobjRoot, nameRoot, propRoot, vp);
- return FetchName<false>(cx, envRoot, pobjRoot, nameRoot, shapeRoot, vp);
+ return FetchName<false>(cx, envRoot, pobjRoot, nameRoot, propRoot, vp);
}
static inline bool
@@ -238,12 +238,12 @@ GetImportOperation(JSContext* cx, InterpreterFrame* fp, jsbytecode* pc, MutableH
{
RootedObject obj(cx, fp->environmentChain()), env(cx), pobj(cx);
RootedPropertyName name(cx, fp->script()->getName(pc));
- RootedShape shape(cx);
+ Rooted<PropertyResult> prop(cx);
- MOZ_ALWAYS_TRUE(LookupName(cx, name, obj, &env, &pobj, &shape));
+ MOZ_ALWAYS_TRUE(LookupName(cx, name, obj, &env, &pobj, &prop));
MOZ_ASSERT(env && env->is<ModuleEnvironmentObject>());
MOZ_ASSERT(env->as<ModuleEnvironmentObject>().hasImportBinding(name));
- return FetchName<false>(cx, env, pobj, name, shape, vp);
+ return FetchName<false>(cx, env, pobj, name, prop, vp);
}
static bool
@@ -1613,11 +1613,7 @@ GetSuperEnvFunction(JSContext* cx, InterpreterRegs& regs)
*/
template<typename T>
-class ReservedRootedBase {
-};
-
-template<typename T>
-class ReservedRooted : public ReservedRootedBase<T>
+class ReservedRooted : public RootedBase<T, ReservedRooted<T>>
{
Rooted<T>* savedRoot;
@@ -1645,14 +1641,6 @@ class ReservedRooted : public ReservedRootedBase<T>
DECLARE_POINTER_ASSIGN_OPS(ReservedRooted, T)
};
-template <>
-class ReservedRootedBase<Value> : public ValueOperations<ReservedRooted<Value>>
-{};
-
-template <>
-class ReservedRootedBase<Scope*> : public ScopeCastOperation<ReservedRooted<Scope*>>
-{};
-
static MOZ_NEVER_INLINE bool
Interpret(JSContext* cx, RunState& state)
{
@@ -4400,12 +4388,12 @@ bool
js::GetEnvironmentName(JSContext* cx, HandleObject envChain, HandlePropertyName name,
MutableHandleValue vp)
{
- RootedShape shape(cx);
+ Rooted<PropertyResult> prop(cx);
RootedObject obj(cx), pobj(cx);
- if (!LookupName(cx, name, envChain, &obj, &pobj, &shape))
+ if (!LookupName(cx, name, envChain, &obj, &pobj, &prop))
return false;
- if (!shape)
+ if (!prop)
return ReportIsNotDefined(cx, name);
if (!GetProperty(cx, obj, obj, name, vp))
@@ -4427,12 +4415,12 @@ bool
js::GetEnvironmentNameForTypeOf(JSContext* cx, HandleObject envChain, HandlePropertyName name,
MutableHandleValue vp)
{
- RootedShape shape(cx);
+ Rooted<PropertyResult> prop(cx);
RootedObject obj(cx), pobj(cx);
- if (!LookupName(cx, name, envChain, &obj, &pobj, &shape))
+ if (!LookupName(cx, name, envChain, &obj, &pobj, &prop))
return false;
- if (!shape) {
+ if (!prop) {
vp.set(UndefinedValue());
return true;
}
@@ -4490,9 +4478,9 @@ js::DefFunOperation(JSContext* cx, HandleScript script, HandleObject envChain,
/* ES5 10.5 (NB: with subsequent errata). */
RootedPropertyName name(cx, fun->explicitName()->asPropertyName());
- RootedShape shape(cx);
+ Rooted<PropertyResult> prop(cx);
RootedObject pobj(cx);
- if (!LookupProperty(cx, parent, name, &pobj, &shape))
+ if (!LookupProperty(cx, parent, name, &pobj, &prop))
return false;
RootedValue rval(cx, ObjectValue(*fun));
@@ -4506,7 +4494,7 @@ js::DefFunOperation(JSContext* cx, HandleScript script, HandleObject envChain,
: JSPROP_ENUMERATE | JSPROP_PERMANENT;
/* Steps 5d, 5f. */
- if (!shape || pobj != parent) {
+ if (!prop || pobj != parent) {
if (!DefineProperty(cx, parent, name, rval, nullptr, nullptr, attrs))
return false;
@@ -4524,6 +4512,7 @@ js::DefFunOperation(JSContext* cx, HandleScript script, HandleObject envChain,
*/
MOZ_ASSERT(parent->isNative() || parent->is<DebugEnvironmentProxy>());
if (parent->is<GlobalObject>()) {
+ Shape* shape = prop.shape();
if (shape->configurable()) {
if (!DefineProperty(cx, parent, name, rval, nullptr, nullptr, attrs))
return false;
@@ -4728,8 +4717,8 @@ js::DeleteNameOperation(JSContext* cx, HandlePropertyName name, HandleObject sco
MutableHandleValue res)
{
RootedObject scope(cx), pobj(cx);
- RootedShape shape(cx);
- if (!LookupName(cx, name, scopeObj, &scope, &pobj, &shape))
+ Rooted<PropertyResult> prop(cx);
+ if (!LookupName(cx, name, scopeObj, &scope, &pobj, &prop))
return false;
if (!scope) {
diff --git a/js/src/vm/JSONParser.h b/js/src/vm/JSONParser.h
index 6f91391db..70ed86f58 100644
--- a/js/src/vm/JSONParser.h
+++ b/js/src/vm/JSONParser.h
@@ -255,10 +255,13 @@ class MOZ_STACK_CLASS JSONParser : public JSONParserBase
void operator=(const JSONParser& other) = delete;
};
-template <typename CharT>
-struct RootedBase<JSONParser<CharT>> {
+template <typename CharT, typename Wrapper>
+class MutableWrappedPtrOperations<JSONParser<CharT>, Wrapper>
+ : public WrappedPtrOperations<JSONParser<CharT>, Wrapper>
+{
+ public:
bool parse(MutableHandleValue vp) {
- return static_cast<Rooted<JSONParser<CharT>>*>(this)->get().parse(vp);
+ return static_cast<Wrapper*>(this)->get().parse(vp);
}
};
diff --git a/js/src/vm/NativeObject-inl.h b/js/src/vm/NativeObject-inl.h
index 2bb70b7d9..004b308f0 100644
--- a/js/src/vm/NativeObject-inl.h
+++ b/js/src/vm/NativeObject-inl.h
@@ -290,7 +290,7 @@ NativeObject::setSlotWithType(ExclusiveContext* cx, Shape* shape,
inline void
NativeObject::updateShapeAfterMovingGC()
{
- Shape* shape = shape_.unbarrieredGet();
+ Shape* shape = shape_;
if (IsForwarded(shape))
shape_.unsafeSet(Forwarded(shape));
}
@@ -382,8 +382,8 @@ NewNativeObjectWithClassProto(ExclusiveContext* cx, const Class* clasp, HandleOb
* *recursedp = false and return true.
*/
static MOZ_ALWAYS_INLINE bool
-CallResolveOp(JSContext* cx, HandleNativeObject obj, HandleId id, MutableHandleShape propp,
- bool* recursedp)
+CallResolveOp(JSContext* cx, HandleNativeObject obj, HandleId id,
+ MutableHandle<PropertyResult> propp, bool* recursedp)
{
// Avoid recursion on (obj, id) already being resolved on cx.
AutoResolving resolving(cx, obj, id);
@@ -407,13 +407,18 @@ CallResolveOp(JSContext* cx, HandleNativeObject obj, HandleId id, MutableHandleS
obj->getClass()->getMayResolve()(cx->names(), id, obj));
if (JSID_IS_INT(id) && obj->containsDenseElement(JSID_TO_INT(id))) {
- MarkDenseOrTypedArrayElementFound<CanGC>(propp);
+ propp.setDenseOrTypedArrayElement();
return true;
}
MOZ_ASSERT(!obj->is<TypedArrayObject>());
- propp.set(obj->lookup(cx, id));
+ RootedShape shape(cx, obj->lookup(cx, id));
+ if (shape)
+ propp.setNativeProperty(shape);
+ else
+ propp.setNotFound();
+
return true;
}
@@ -444,12 +449,12 @@ static MOZ_ALWAYS_INLINE bool
LookupOwnPropertyInline(ExclusiveContext* cx,
typename MaybeRooted<NativeObject*, allowGC>::HandleType obj,
typename MaybeRooted<jsid, allowGC>::HandleType id,
- typename MaybeRooted<Shape*, allowGC>::MutableHandleType propp,
+ typename MaybeRooted<PropertyResult, allowGC>::MutableHandleType propp,
bool* donep)
{
// Check for a native dense element.
if (JSID_IS_INT(id) && obj->containsDenseElement(JSID_TO_INT(id))) {
- MarkDenseOrTypedArrayElementFound<allowGC>(propp);
+ propp.setDenseOrTypedArrayElement();
*donep = true;
return true;
}
@@ -460,11 +465,10 @@ LookupOwnPropertyInline(ExclusiveContext* cx,
if (obj->template is<TypedArrayObject>()) {
uint64_t index;
if (IsTypedArrayIndex(id, &index)) {
- if (index < obj->template as<TypedArrayObject>().length()) {
- MarkDenseOrTypedArrayElementFound<allowGC>(propp);
- } else {
- propp.set(nullptr);
- }
+ if (index < obj->template as<TypedArrayObject>().length())
+ propp.setDenseOrTypedArrayElement();
+ else
+ propp.setNotFound();
*donep = true;
return true;
}
@@ -472,7 +476,7 @@ LookupOwnPropertyInline(ExclusiveContext* cx,
// Check for a native property.
if (Shape* shape = obj->lookup(cx, id)) {
- propp.set(shape);
+ propp.setNativeProperty(shape);
*donep = true;
return true;
}
@@ -486,14 +490,14 @@ LookupOwnPropertyInline(ExclusiveContext* cx,
if (!CallResolveOp(cx->asJSContext(),
MaybeRooted<NativeObject*, allowGC>::toHandle(obj),
MaybeRooted<jsid, allowGC>::toHandle(id),
- MaybeRooted<Shape*, allowGC>::toMutableHandle(propp),
+ MaybeRooted<PropertyResult, allowGC>::toMutableHandle(propp),
&recursed))
{
return false;
}
if (recursed) {
- propp.set(nullptr);
+ propp.setNotFound();
*donep = true;
return true;
}
@@ -504,7 +508,7 @@ LookupOwnPropertyInline(ExclusiveContext* cx,
}
}
- propp.set(nullptr);
+ propp.setNotFound();
*donep = false;
return true;
}
@@ -515,11 +519,11 @@ LookupOwnPropertyInline(ExclusiveContext* cx,
*/
static inline void
NativeLookupOwnPropertyNoResolve(ExclusiveContext* cx, HandleNativeObject obj, HandleId id,
- MutableHandleShape result)
+ MutableHandle<PropertyResult> result)
{
// Check for a native dense element.
if (JSID_IS_INT(id) && obj->containsDenseElement(JSID_TO_INT(id))) {
- MarkDenseOrTypedArrayElementFound<CanGC>(result);
+ result.setDenseOrTypedArrayElement();
return;
}
@@ -528,15 +532,18 @@ NativeLookupOwnPropertyNoResolve(ExclusiveContext* cx, HandleNativeObject obj, H
uint64_t index;
if (IsTypedArrayIndex(id, &index)) {
if (index < obj->as<TypedArrayObject>().length())
- MarkDenseOrTypedArrayElementFound<CanGC>(result);
+ result.setDenseOrTypedArrayElement();
else
- result.set(nullptr);
+ result.setNotFound();
return;
}
}
// Check for a native property.
- result.set(obj->lookup(cx, id));
+ if (Shape* shape = obj->lookup(cx, id))
+ result.setNativeProperty(shape);
+ else
+ result.setNotFound();
}
template <AllowGC allowGC>
@@ -545,7 +552,7 @@ LookupPropertyInline(ExclusiveContext* cx,
typename MaybeRooted<NativeObject*, allowGC>::HandleType obj,
typename MaybeRooted<jsid, allowGC>::HandleType id,
typename MaybeRooted<JSObject*, allowGC>::MutableHandleType objp,
- typename MaybeRooted<Shape*, allowGC>::MutableHandleType propp)
+ typename MaybeRooted<PropertyResult, allowGC>::MutableHandleType propp)
{
/* NB: The logic of this procedure is implicitly reflected in
* BaselineIC.cpp's |EffectlesslyLookupProperty| logic.
@@ -578,14 +585,14 @@ LookupPropertyInline(ExclusiveContext* cx,
MaybeRooted<JSObject*, allowGC>::toHandle(proto),
MaybeRooted<jsid, allowGC>::toHandle(id),
MaybeRooted<JSObject*, allowGC>::toMutableHandle(objp),
- MaybeRooted<Shape*, allowGC>::toMutableHandle(propp));
+ MaybeRooted<PropertyResult, allowGC>::toMutableHandle(propp));
}
current = &proto->template as<NativeObject>();
}
objp.set(nullptr);
- propp.set(nullptr);
+ propp.setNotFound();
return true;
}
diff --git a/js/src/vm/NativeObject.cpp b/js/src/vm/NativeObject.cpp
index 3625d86f5..53f7c0bfa 100644
--- a/js/src/vm/NativeObject.cpp
+++ b/js/src/vm/NativeObject.cpp
@@ -1044,7 +1044,7 @@ bool
js::NativeLookupOwnProperty(ExclusiveContext* cx,
typename MaybeRooted<NativeObject*, allowGC>::HandleType obj,
typename MaybeRooted<jsid, allowGC>::HandleType id,
- typename MaybeRooted<Shape*, allowGC>::MutableHandleType propp)
+ typename MaybeRooted<PropertyResult, allowGC>::MutableHandleType propp)
{
bool done;
return LookupOwnPropertyInline<allowGC>(cx, obj, id, propp, &done);
@@ -1052,11 +1052,11 @@ js::NativeLookupOwnProperty(ExclusiveContext* cx,
template bool
js::NativeLookupOwnProperty<CanGC>(ExclusiveContext* cx, HandleNativeObject obj, HandleId id,
- MutableHandleShape propp);
+ MutableHandle<PropertyResult> propp);
template bool
js::NativeLookupOwnProperty<NoGC>(ExclusiveContext* cx, NativeObject* const& obj, const jsid& id,
- FakeMutableHandle<Shape*> propp);
+ FakeMutableHandle<PropertyResult> propp);
/*** [[DefineOwnProperty]] ***********************************************************************/
@@ -1279,19 +1279,20 @@ GetExistingProperty(JSContext* cx,
static bool
GetExistingPropertyValue(ExclusiveContext* cx, HandleNativeObject obj, HandleId id,
- HandleShape shape, MutableHandleValue vp)
+ Handle<PropertyResult> prop, MutableHandleValue vp)
{
- if (IsImplicitDenseOrTypedArrayElement(shape)) {
+ if (prop.isDenseOrTypedArrayElement()) {
vp.set(obj->getDenseOrTypedArrayElement(JSID_TO_INT(id)));
return true;
}
if (!cx->shouldBeJSContext())
return false;
- MOZ_ASSERT(shape->propid() == id);
- MOZ_ASSERT(obj->contains(cx, shape));
+ MOZ_ASSERT(prop.shape()->propid() == id);
+ MOZ_ASSERT(obj->contains(cx, prop.shape()));
RootedValue receiver(cx, ObjectValue(*obj));
+ RootedShape shape(cx, prop.shape());
return GetExistingProperty<CanGC>(cx->asJSContext(), receiver, obj, shape, vp);
}
@@ -1302,7 +1303,7 @@ GetExistingPropertyValue(ExclusiveContext* cx, HandleNativeObject obj, HandleId
*/
static bool
DefinePropertyIsRedundant(ExclusiveContext* cx, HandleNativeObject obj, HandleId id,
- HandleShape shape, unsigned shapeAttrs,
+ Handle<PropertyResult> prop, unsigned shapeAttrs,
Handle<PropertyDescriptor> desc, bool *redundant)
{
*redundant = false;
@@ -1319,16 +1320,16 @@ DefinePropertyIsRedundant(ExclusiveContext* cx, HandleNativeObject obj, HandleId
if (desc.hasValue()) {
// Get the current value of the existing property.
RootedValue currentValue(cx);
- if (!IsImplicitDenseOrTypedArrayElement(shape) &&
- shape->hasSlot() &&
- shape->hasDefaultGetter())
+ if (!prop.isDenseOrTypedArrayElement() &&
+ prop.shape()->hasSlot() &&
+ prop.shape()->hasDefaultGetter())
{
// Inline GetExistingPropertyValue in order to omit a type
// correctness assertion that's too strict for this particular
// call site. For details, see bug 1125624 comments 13-16.
- currentValue.set(obj->getSlot(shape->slot()));
+ currentValue.set(obj->getSlot(prop.shape()->slot()));
} else {
- if (!GetExistingPropertyValue(cx, obj, id, shape, &currentValue))
+ if (!GetExistingPropertyValue(cx, obj, id, prop, &currentValue))
return false;
}
@@ -1339,22 +1340,24 @@ DefinePropertyIsRedundant(ExclusiveContext* cx, HandleNativeObject obj, HandleId
}
GetterOp existingGetterOp =
- IsImplicitDenseOrTypedArrayElement(shape) ? nullptr : shape->getter();
+ prop.isDenseOrTypedArrayElement() ? nullptr : prop.shape()->getter();
if (desc.getter() != existingGetterOp)
return true;
SetterOp existingSetterOp =
- IsImplicitDenseOrTypedArrayElement(shape) ? nullptr : shape->setter();
+ prop.isDenseOrTypedArrayElement() ? nullptr : prop.shape()->setter();
if (desc.setter() != existingSetterOp)
return true;
} else {
- if (desc.hasGetterObject()) {
- if (!(shapeAttrs & JSPROP_GETTER) || desc.getterObject() != shape->getterObject())
- return true;
+ if (desc.hasGetterObject() &&
+ (!(shapeAttrs & JSPROP_GETTER) || desc.getterObject() != prop.shape()->getterObject()))
+ {
+ return true;
}
- if (desc.hasSetterObject()) {
- if (!(shapeAttrs & JSPROP_SETTER) || desc.setterObject() != shape->setterObject())
- return true;
+ if (desc.hasSetterObject() &&
+ (!(shapeAttrs & JSPROP_SETTER) || desc.setterObject() != prop.shape()->setterObject()))
+ {
+ return true;
}
}
@@ -1421,14 +1424,14 @@ js::NativeDefineProperty(ExclusiveContext* cx, HandleNativeObject obj, HandleId
}
// 9.1.6.1 OrdinaryDefineOwnProperty steps 1-2.
- RootedShape shape(cx);
+ Rooted<PropertyResult> prop(cx);
if (desc_.attributes() & JSPROP_RESOLVING) {
// We are being called from a resolve or enumerate hook to reify a
// lazily-resolved property. To avoid reentering the resolve hook and
// recursing forever, skip the resolve hook when doing this lookup.
- NativeLookupOwnPropertyNoResolve(cx, obj, id, &shape);
+ NativeLookupOwnPropertyNoResolve(cx, obj, id, &prop);
} else {
- if (!NativeLookupOwnProperty<CanGC>(cx, obj, id, &shape))
+ if (!NativeLookupOwnProperty<CanGC>(cx, obj, id, &prop))
return false;
}
@@ -1443,7 +1446,7 @@ js::NativeDefineProperty(ExclusiveContext* cx, HandleNativeObject obj, HandleId
Rooted<PropertyDescriptor> desc(cx, desc_);
// Step 2.
- if (!shape) {
+ if (!prop) {
if (!obj->nonProxyIsExtensible())
return result.fail(JSMSG_CANT_DEFINE_PROP_OBJECT_NOT_EXTENSIBLE);
@@ -1455,21 +1458,20 @@ js::NativeDefineProperty(ExclusiveContext* cx, HandleNativeObject obj, HandleId
return result.succeed();
}
- MOZ_ASSERT(shape);
-
// Steps 3-4. (Step 3 is a special case of step 4.) We use shapeAttrs as a
// stand-in for shape in many places below, since shape might not be a
// pointer to a real Shape (see IsImplicitDenseOrTypedArrayElement).
- unsigned shapeAttrs = GetShapeAttributes(obj, shape);
+ unsigned shapeAttrs = GetPropertyAttributes(obj, prop);
bool redundant;
- if (!DefinePropertyIsRedundant(cx, obj, id, shape, shapeAttrs, desc, &redundant))
+ if (!DefinePropertyIsRedundant(cx, obj, id, prop, shapeAttrs, desc, &redundant))
return false;
if (redundant) {
// In cases involving JSOP_NEWOBJECT and JSOP_INITPROP, obj can have a
// type for this property that doesn't match the value in the slot.
// Update the type here, even though this DefineProperty call is
// otherwise a no-op. (See bug 1125624 comment 13.)
- if (!IsImplicitDenseOrTypedArrayElement(shape) && desc.hasValue()) {
+ if (!prop.isDenseOrTypedArrayElement() && desc.hasValue()) {
+ RootedShape shape(cx, prop.shape());
if (!UpdateShapeTypeAndValue(cx, obj, shape, desc.value()))
return false;
}
@@ -1512,24 +1514,24 @@ js::NativeDefineProperty(ExclusiveContext* cx, HandleNativeObject obj, HandleId
MOZ_ASSERT(!desc.hasSetterObject());
if (IsDataDescriptor(shapeAttrs)) {
RootedValue currentValue(cx);
- if (!GetExistingPropertyValue(cx, obj, id, shape, &currentValue))
+ if (!GetExistingPropertyValue(cx, obj, id, prop, &currentValue))
return false;
desc.setValue(currentValue);
desc.setWritable(IsWritable(shapeAttrs));
} else {
- desc.setGetterObject(shape->getterObject());
- desc.setSetterObject(shape->setterObject());
+ desc.setGetterObject(prop.shape()->getterObject());
+ desc.setSetterObject(prop.shape()->setterObject());
}
} else if (desc.isDataDescriptor() != IsDataDescriptor(shapeAttrs)) {
// Step 7.
if (!IsConfigurable(shapeAttrs) && !skipRedefineChecks)
return result.fail(JSMSG_CANT_REDEFINE_PROP);
- if (IsImplicitDenseOrTypedArrayElement(shape)) {
+ if (prop.isDenseOrTypedArrayElement()) {
MOZ_ASSERT(!obj->is<TypedArrayObject>());
if (!NativeObject::sparsifyDenseElement(cx, obj, JSID_TO_INT(id)))
return false;
- shape = obj->lookup(cx, id);
+ prop.setNativeProperty(obj->lookup(cx, id));
}
// Fill in desc fields with default values (steps 7.b.i and 7.c.i).
@@ -1541,15 +1543,15 @@ js::NativeDefineProperty(ExclusiveContext* cx, HandleNativeObject obj, HandleId
return result.fail(JSMSG_CANT_REDEFINE_PROP);
if (frozen || !desc.hasValue()) {
- if (IsImplicitDenseOrTypedArrayElement(shape)) {
+ if (prop.isDenseOrTypedArrayElement()) {
MOZ_ASSERT(!obj->is<TypedArrayObject>());
if (!NativeObject::sparsifyDenseElement(cx, obj, JSID_TO_INT(id)))
return false;
- shape = obj->lookup(cx, id);
+ prop.setNativeProperty(obj->lookup(cx, id));
}
RootedValue currentValue(cx);
- if (!GetExistingPropertyValue(cx, obj, id, shape, &currentValue))
+ if (!GetExistingPropertyValue(cx, obj, id, prop, &currentValue))
return false;
if (!desc.hasValue()) {
@@ -1571,32 +1573,32 @@ js::NativeDefineProperty(ExclusiveContext* cx, HandleNativeObject obj, HandleId
desc.setWritable(IsWritable(shapeAttrs));
} else {
// Step 9.
- MOZ_ASSERT(shape->isAccessorDescriptor());
+ MOZ_ASSERT(prop.shape()->isAccessorDescriptor());
MOZ_ASSERT(desc.isAccessorDescriptor());
// The spec says to use SameValue, but since the values in
// question are objects, we can just compare pointers.
if (desc.hasSetterObject()) {
if (!IsConfigurable(shapeAttrs) &&
- desc.setterObject() != shape->setterObject() &&
+ desc.setterObject() != prop.shape()->setterObject() &&
!skipRedefineChecks)
{
return result.fail(JSMSG_CANT_REDEFINE_PROP);
}
} else {
// Fill in desc.[[Set]] from shape.
- desc.setSetterObject(shape->setterObject());
+ desc.setSetterObject(prop.shape()->setterObject());
}
if (desc.hasGetterObject()) {
if (!IsConfigurable(shapeAttrs) &&
- desc.getterObject() != shape->getterObject() &&
+ desc.getterObject() != prop.shape()->getterObject() &&
!skipRedefineChecks)
{
return result.fail(JSMSG_CANT_REDEFINE_PROP);
}
} else {
// Fill in desc.[[Get]] from shape.
- desc.setGetterObject(shape->getterObject());
+ desc.setGetterObject(prop.shape()->getterObject());
}
}
@@ -1681,18 +1683,18 @@ bool
js::NativeHasProperty(JSContext* cx, HandleNativeObject obj, HandleId id, bool* foundp)
{
RootedNativeObject pobj(cx, obj);
- RootedShape shape(cx);
+ Rooted<PropertyResult> prop(cx);
// This loop isn't explicit in the spec algorithm. See the comment on step
// 7.a. below.
for (;;) {
// Steps 2-3. ('done' is a SpiderMonkey-specific thing, used below.)
bool done;
- if (!LookupOwnPropertyInline<CanGC>(cx, pobj, id, &shape, &done))
+ if (!LookupOwnPropertyInline<CanGC>(cx, pobj, id, &prop, &done))
return false;
// Step 4.
- if (shape) {
+ if (prop) {
*foundp = true;
return true;
}
@@ -1733,15 +1735,15 @@ bool
js::NativeGetOwnPropertyDescriptor(JSContext* cx, HandleNativeObject obj, HandleId id,
MutableHandle<PropertyDescriptor> desc)
{
- RootedShape shape(cx);
- if (!NativeLookupOwnProperty<CanGC>(cx, obj, id, &shape))
+ Rooted<PropertyResult> prop(cx);
+ if (!NativeLookupOwnProperty<CanGC>(cx, obj, id, &prop))
return false;
- if (!shape) {
+ if (!prop) {
desc.object().set(nullptr);
return true;
}
- desc.setAttributes(GetShapeAttributes(obj, shape));
+ desc.setAttributes(GetPropertyAttributes(obj, prop));
if (desc.isAccessorDescriptor()) {
MOZ_ASSERT(desc.isShared());
@@ -1754,13 +1756,13 @@ js::NativeGetOwnPropertyDescriptor(JSContext* cx, HandleNativeObject obj, Handle
// than return true with desc incomplete, we fill out the missing
// getter or setter with a null, following CompletePropertyDescriptor.
if (desc.hasGetterObject()) {
- desc.setGetterObject(shape->getterObject());
+ desc.setGetterObject(prop.shape()->getterObject());
} else {
desc.setGetterObject(nullptr);
desc.attributesRef() |= JSPROP_GETTER;
}
if (desc.hasSetterObject()) {
- desc.setSetterObject(shape->setterObject());
+ desc.setSetterObject(prop.shape()->setterObject());
} else {
desc.setSetterObject(nullptr);
desc.attributesRef() |= JSPROP_SETTER;
@@ -1776,9 +1778,10 @@ js::NativeGetOwnPropertyDescriptor(JSContext* cx, HandleNativeObject obj, Handle
desc.setSetter(nullptr);
desc.attributesRef() &= ~JSPROP_SHARED;
- if (IsImplicitDenseOrTypedArrayElement(shape)) {
+ if (prop.isDenseOrTypedArrayElement()) {
desc.value().set(obj->getDenseOrTypedArrayElement(JSID_TO_INT(id)));
} else {
+ RootedShape shape(cx, prop.shape());
if (!NativeGetExistingProperty(cx, obj, obj, shape, desc.value()))
return false;
}
@@ -2058,23 +2061,25 @@ NativeGetPropertyInline(JSContext* cx,
typename MaybeRooted<Value, allowGC>::MutableHandleType vp)
{
typename MaybeRooted<NativeObject*, allowGC>::RootType pobj(cx, obj);
- typename MaybeRooted<Shape*, allowGC>::RootType shape(cx);
+ typename MaybeRooted<PropertyResult, allowGC>::RootType prop(cx);
// This loop isn't explicit in the spec algorithm. See the comment on step
// 4.d below.
for (;;) {
// Steps 2-3. ('done' is a SpiderMonkey-specific thing, used below.)
bool done;
- if (!LookupOwnPropertyInline<allowGC>(cx, pobj, id, &shape, &done))
+ if (!LookupOwnPropertyInline<allowGC>(cx, pobj, id, &prop, &done))
return false;
- if (shape) {
+ if (prop) {
// Steps 5-8. Special case for dense elements because
// GetExistingProperty doesn't support those.
- if (IsImplicitDenseOrTypedArrayElement(shape)) {
+ if (prop.isDenseOrTypedArrayElement()) {
vp.set(pobj->getDenseOrTypedArrayElement(JSID_TO_INT(id)));
return true;
}
+
+ typename MaybeRooted<Shape*, allowGC>::RootType shape(cx, prop.shape());
return GetExistingProperty<allowGC>(cx, receiver, pobj, shape, vp);
}
@@ -2366,11 +2371,11 @@ SetDenseOrTypedArrayElement(JSContext* cx, HandleNativeObject obj, uint32_t inde
*/
static bool
SetExistingProperty(JSContext* cx, HandleNativeObject obj, HandleId id, HandleValue v,
- HandleValue receiver, HandleNativeObject pobj, HandleShape shape,
+ HandleValue receiver, HandleNativeObject pobj, Handle<PropertyResult> prop,
ObjectOpResult& result)
{
// Step 5 for dense elements.
- if (IsImplicitDenseOrTypedArrayElement(shape)) {
+ if (prop.isDenseOrTypedArrayElement()) {
// Step 5.a.
if (pobj->getElementsHeader()->isFrozen())
return result.fail(JSMSG_READ_ONLY);
@@ -2384,6 +2389,7 @@ SetExistingProperty(JSContext* cx, HandleNativeObject obj, HandleId id, HandleVa
}
// Step 5 for all other properties.
+ RootedShape shape(cx, prop.shape());
if (shape->isDataDescriptor()) {
// Step 5.a.
if (!shape->writable())
@@ -2441,7 +2447,7 @@ js::NativeSetProperty(JSContext* cx, HandleNativeObject obj, HandleId id, Handle
// Step numbers below reference ES6 rev 27 9.1.9, the [[Set]] internal
// method for ordinary objects. We substitute our own names for these names
// used in the spec: O -> pobj, P -> id, ownDesc -> shape.
- RootedShape shape(cx);
+ Rooted<PropertyResult> prop(cx);
RootedNativeObject pobj(cx, obj);
// This loop isn't explicit in the spec algorithm. See the comment on step
@@ -2450,12 +2456,12 @@ js::NativeSetProperty(JSContext* cx, HandleNativeObject obj, HandleId id, Handle
for (;;) {
// Steps 2-3. ('done' is a SpiderMonkey-specific thing, used below.)
bool done;
- if (!LookupOwnPropertyInline<CanGC>(cx, pobj, id, &shape, &done))
+ if (!LookupOwnPropertyInline<CanGC>(cx, pobj, id, &prop, &done))
return false;
- if (shape) {
+ if (prop) {
// Steps 5-6.
- return SetExistingProperty(cx, obj, id, v, receiver, pobj, shape, result);
+ return SetExistingProperty(cx, obj, id, v, receiver, pobj, prop, result);
}
// Steps 4.a-b. The check for 'done' on this next line is tricky.
@@ -2513,12 +2519,12 @@ js::NativeDeleteProperty(JSContext* cx, HandleNativeObject obj, HandleId id,
ObjectOpResult& result)
{
// Steps 2-3.
- RootedShape shape(cx);
- if (!NativeLookupOwnProperty<CanGC>(cx, obj, id, &shape))
+ Rooted<PropertyResult> prop(cx);
+ if (!NativeLookupOwnProperty<CanGC>(cx, obj, id, &prop))
return false;
// Step 4.
- if (!shape) {
+ if (!prop) {
// If no property call the class's delProperty hook, passing succeeded
// as the result parameter. This always succeeds when there is no hook.
return CallJSDeletePropertyOp(cx, obj->getClass()->getDelProperty(), obj, id, result);
@@ -2527,7 +2533,7 @@ js::NativeDeleteProperty(JSContext* cx, HandleNativeObject obj, HandleId id,
cx->runtime()->gc.poke();
// Step 6. Non-configurable property.
- if (GetShapeAttributes(obj, shape) & JSPROP_PERMANENT)
+ if (GetPropertyAttributes(obj, prop) & JSPROP_PERMANENT)
return result.failCantDelete();
if (!CallJSDeletePropertyOp(cx, obj->getClass()->getDelProperty(), obj, id, result))
@@ -2536,7 +2542,7 @@ js::NativeDeleteProperty(JSContext* cx, HandleNativeObject obj, HandleId id,
return true;
// Step 5.
- if (IsImplicitDenseOrTypedArrayElement(shape)) {
+ if (prop.isDenseOrTypedArrayElement()) {
// Typed array elements are non-configurable.
MOZ_ASSERT(!obj->is<TypedArrayObject>());
diff --git a/js/src/vm/NativeObject.h b/js/src/vm/NativeObject.h
index 657fc8d57..abc84c9fd 100644
--- a/js/src/vm/NativeObject.h
+++ b/js/src/vm/NativeObject.h
@@ -1459,7 +1459,7 @@ extern bool
NativeLookupOwnProperty(ExclusiveContext* cx,
typename MaybeRooted<NativeObject*, allowGC>::HandleType obj,
typename MaybeRooted<jsid, allowGC>::HandleType id,
- typename MaybeRooted<Shape*, allowGC>::MutableHandleType propp);
+ typename MaybeRooted<PropertyResult, allowGC>::MutableHandleType propp);
/*
* Get a property from `receiver`, after having already done a lookup and found
diff --git a/js/src/vm/ObjectGroup.cpp b/js/src/vm/ObjectGroup.cpp
index f2a3305cf..741531f01 100644
--- a/js/src/vm/ObjectGroup.cpp
+++ b/js/src/vm/ObjectGroup.cpp
@@ -421,7 +421,7 @@ struct ObjectGroupCompartment::NewEntry
}
static inline bool match(const ObjectGroupCompartment::NewEntry& key, const Lookup& lookup) {
- TaggedProto proto = key.group.unbarrieredGet()->proto().unbarrieredGet();
+ TaggedProto proto = key.group.unbarrieredGet()->proto();
JSObject* assoc = key.associated;
MOZ_ASSERT(proto.hasUniqueId());
MOZ_ASSERT_IF(assoc, assoc->zone()->hasUniqueId(assoc));
diff --git a/js/src/vm/SavedStacks.h b/js/src/vm/SavedStacks.h
index c6bda2831..3ea6c4087 100644
--- a/js/src/vm/SavedStacks.h
+++ b/js/src/vm/SavedStacks.h
@@ -265,24 +265,6 @@ class SavedStacks {
uint32_t column;
};
- template <typename Outer>
- struct LocationValueOperations {
- JSAtom* source() const { return loc().source; }
- size_t line() const { return loc().line; }
- uint32_t column() const { return loc().column; }
- private:
- const LocationValue& loc() const { return static_cast<const Outer*>(this)->get(); }
- };
-
- template <typename Outer>
- struct MutableLocationValueOperations : public LocationValueOperations<Outer> {
- void setSource(JSAtom* v) { loc().source = v; }
- void setLine(size_t v) { loc().line = v; }
- void setColumn(uint32_t v) { loc().column = v; }
- private:
- LocationValue& loc() { return static_cast<Outer*>(this)->get(); }
- };
-
private:
struct PCLocationHasher : public DefaultHasher<PCKey> {
using ScriptPtrHasher = DefaultHasher<JSScript*>;
@@ -313,15 +295,32 @@ class SavedStacks {
MutableHandle<LocationValue> locationp);
};
-template <>
-class RootedBase<SavedStacks::LocationValue>
- : public SavedStacks::MutableLocationValueOperations<JS::Rooted<SavedStacks::LocationValue>>
-{};
+template <typename Wrapper>
+struct WrappedPtrOperations<SavedStacks::LocationValue, Wrapper>
+{
+ JSAtom* source() const { return loc().source; }
+ size_t line() const { return loc().line; }
+ uint32_t column() const { return loc().column; }
+
+ private:
+ const SavedStacks::LocationValue& loc() const {
+ return static_cast<const Wrapper*>(this)->get();
+ }
+};
+
+template <typename Wrapper>
+struct MutableWrappedPtrOperations<SavedStacks::LocationValue, Wrapper>
+ : public WrappedPtrOperations<SavedStacks::LocationValue, Wrapper>
+{
+ void setSource(JSAtom* v) { loc().source = v; }
+ void setLine(size_t v) { loc().line = v; }
+ void setColumn(uint32_t v) { loc().column = v; }
-template <>
-class MutableHandleBase<SavedStacks::LocationValue>
- : public SavedStacks::MutableLocationValueOperations<JS::MutableHandle<SavedStacks::LocationValue>>
-{};
+ private:
+ SavedStacks::LocationValue& loc() {
+ return static_cast<Wrapper*>(this)->get();
+ }
+};
UTF8CharsZ
BuildUTF8StackString(JSContext* cx, HandleObject stack);
diff --git a/js/src/vm/Scope.h b/js/src/vm/Scope.h
index 4f0edcc13..fc1419bb8 100644
--- a/js/src/vm/Scope.h
+++ b/js/src/vm/Scope.h
@@ -22,6 +22,7 @@
namespace js {
class ModuleObject;
+class Scope;
enum class BindingKind : uint8_t
{
@@ -224,6 +225,21 @@ class BindingLocation
};
//
+// Allow using is<T> and as<T> on Rooted<Scope*> and Handle<Scope*>.
+//
+template <typename Wrapper>
+class WrappedPtrOperations<Scope*, Wrapper>
+{
+ public:
+ template <class U>
+ JS::Handle<U*> as() const {
+ const Wrapper& self = *static_cast<const Wrapper*>(this);
+ MOZ_ASSERT_IF(self, self->template is<U>());
+ return Handle<U*>::fromMarkedLocation(reinterpret_cast<U* const*>(self.address()));
+ }
+};
+
+//
// The base class of all Scopes.
//
class Scope : public js::gc::TenuredCell
@@ -1338,10 +1354,10 @@ class MOZ_STACK_CLASS ScopeIter
// Specializations of Rooted containers for the iterators.
//
-template <typename Outer>
-class BindingIterOperations
+template <typename Wrapper>
+class WrappedPtrOperations<BindingIter, Wrapper>
{
- const BindingIter& iter() const { return static_cast<const Outer*>(this)->get(); }
+ const BindingIter& iter() const { return static_cast<const Wrapper*>(this)->get(); }
public:
bool done() const { return iter().done(); }
@@ -1361,19 +1377,20 @@ class BindingIterOperations
uint32_t nextEnvironmentSlot() const { return iter().nextEnvironmentSlot(); }
};
-template <typename Outer>
-class MutableBindingIterOperations : public BindingIterOperations<Outer>
+template <typename Wrapper>
+class MutableWrappedPtrOperations<BindingIter, Wrapper>
+ : public WrappedPtrOperations<BindingIter, Wrapper>
{
- BindingIter& iter() { return static_cast<Outer*>(this)->get(); }
+ BindingIter& iter() { return static_cast<Wrapper*>(this)->get(); }
public:
void operator++(int) { iter().operator++(1); }
};
-template <typename Outer>
-class ScopeIterOperations
+template <typename Wrapper>
+class WrappedPtrOperations<ScopeIter, Wrapper>
{
- const ScopeIter& iter() const { return static_cast<const Outer*>(this)->get(); }
+ const ScopeIter& iter() const { return static_cast<const Wrapper*>(this)->get(); }
public:
bool done() const { return iter().done(); }
@@ -1384,69 +1401,16 @@ class ScopeIterOperations
bool hasSyntacticEnvironment() const { return iter().hasSyntacticEnvironment(); }
};
-template <typename Outer>
-class MutableScopeIterOperations : public ScopeIterOperations<Outer>
+template <typename Wrapper>
+class MutableWrappedPtrOperations<ScopeIter, Wrapper>
+ : public WrappedPtrOperations<ScopeIter, Wrapper>
{
- ScopeIter& iter() { return static_cast<Outer*>(this)->get(); }
+ ScopeIter& iter() { return static_cast<Wrapper*>(this)->get(); }
public:
void operator++(int) { iter().operator++(1); }
};
-#define SPECIALIZE_ROOTING_CONTAINERS(Iter, BaseIter) \
- template <> \
- class RootedBase<Iter> \
- : public Mutable##BaseIter##Operations<JS::Rooted<Iter>> \
- { }; \
- \
- template <> \
- class MutableHandleBase<Iter> \
- : public Mutable##BaseIter##Operations<JS::MutableHandle<Iter>> \
- { }; \
- \
- template <> \
- class HandleBase<Iter> \
- : public BaseIter##Operations<JS::Handle<Iter>> \
- { }; \
- \
- template <> \
- class PersistentRootedBase<Iter> \
- : public Mutable##BaseIter##Operations<JS::PersistentRooted<Iter>> \
- { }
-
-SPECIALIZE_ROOTING_CONTAINERS(BindingIter, BindingIter);
-SPECIALIZE_ROOTING_CONTAINERS(PositionalFormalParameterIter, BindingIter);
-SPECIALIZE_ROOTING_CONTAINERS(ScopeIter, ScopeIter);
-
-#undef SPECIALIZE_ROOTING_CONTAINERS
-
-//
-// Allow using is<T> and as<T> on Rooted<Scope*> and Handle<Scope*>.
-//
-
-template <typename Outer>
-struct ScopeCastOperation
-{
- template <class U>
- JS::Handle<U*> as() const {
- const Outer& self = *static_cast<const Outer*>(this);
- MOZ_ASSERT_IF(self, self->template is<U>());
- return Handle<U*>::fromMarkedLocation(reinterpret_cast<U* const*>(self.address()));
- }
-};
-
-template <>
-class RootedBase<Scope*> : public ScopeCastOperation<JS::Rooted<Scope*>>
-{ };
-
-template <>
-class HandleBase<Scope*> : public ScopeCastOperation<JS::Handle<Scope*>>
-{ };
-
-template <>
-class MutableHandleBase<Scope*> : public ScopeCastOperation<JS::MutableHandle<Scope*>>
-{ };
-
} // namespace js
namespace JS {
diff --git a/js/src/vm/Shape-inl.h b/js/src/vm/Shape-inl.h
index 32754740a..7b7561220 100644
--- a/js/src/vm/Shape-inl.h
+++ b/js/src/vm/Shape-inl.h
@@ -123,7 +123,7 @@ Shape::new_(ExclusiveContext* cx, Handle<StackShape> other, uint32_t nfixed)
inline void
Shape::updateBaseShapeAfterMovingGC()
{
- BaseShape* base = base_.unbarrieredGet();
+ BaseShape* base = base_;
if (IsForwarded(base))
base_.unsafeSet(Forwarded(base));
}
@@ -191,17 +191,17 @@ AutoRooterGetterSetter::AutoRooterGetterSetter(ExclusiveContext* cx, uint8_t att
}
static inline uint8_t
-GetShapeAttributes(JSObject* obj, Shape* shape)
+GetPropertyAttributes(JSObject* obj, PropertyResult prop)
{
MOZ_ASSERT(obj->isNative());
- if (IsImplicitDenseOrTypedArrayElement(shape)) {
+ if (prop.isDenseOrTypedArrayElement()) {
if (obj->is<TypedArrayObject>())
return JSPROP_ENUMERATE | JSPROP_PERMANENT;
return obj->as<NativeObject>().getElementsHeader()->elementAttributes();
}
- return shape->attributes();
+ return prop.shape()->attributes();
}
} /* namespace js */
diff --git a/js/src/vm/Shape.cpp b/js/src/vm/Shape.cpp
index 7cdf382ed..c71cef5a7 100644
--- a/js/src/vm/Shape.cpp
+++ b/js/src/vm/Shape.cpp
@@ -1771,3 +1771,10 @@ JS::ubi::Concrete<js::BaseShape>::size(mozilla::MallocSizeOf mallocSizeOf) const
{
return js::gc::Arena::thingSize(get().asTenured().getAllocKind());
}
+
+void
+PropertyResult::trace(JSTracer* trc)
+{
+ if (isNativeProperty())
+ TraceRoot(trc, &shape_, "PropertyResult::shape_");
+}
diff --git a/js/src/vm/Shape.h b/js/src/vm/Shape.h
index 52b9197da..bb813997f 100644
--- a/js/src/vm/Shape.h
+++ b/js/src/vm/Shape.h
@@ -1264,9 +1264,10 @@ struct InitialShapeEntry
bool needsSweep() {
Shape* ushape = shape.unbarrieredGet();
- JSObject* protoObj = proto.proto().raw();
+ TaggedProto uproto = proto.proto().unbarrieredGet();
+ JSObject* protoObj = uproto.raw();
return (gc::IsAboutToBeFinalizedUnbarriered(&ushape) ||
- (proto.proto().isObject() && gc::IsAboutToBeFinalizedUnbarriered(&protoObj)));
+ (uproto.isObject() && gc::IsAboutToBeFinalizedUnbarriered(&protoObj)));
}
};
@@ -1356,9 +1357,10 @@ struct StackShape
void trace(JSTracer* trc);
};
-template <typename Outer>
-class StackShapeOperations {
- const StackShape& ss() const { return static_cast<const Outer*>(this)->get(); }
+template <typename Wrapper>
+class WrappedPtrOperations<StackShape, Wrapper>
+{
+ const StackShape& ss() const { return static_cast<const Wrapper*>(this)->get(); }
public:
bool hasSlot() const { return ss().hasSlot(); }
@@ -1370,9 +1372,11 @@ class StackShapeOperations {
uint8_t attrs() const { return ss().attrs; }
};
-template <typename Outer>
-class MutableStackShapeOperations : public StackShapeOperations<Outer> {
- StackShape& ss() { return static_cast<Outer*>(this)->get(); }
+template <typename Wrapper>
+class MutableWrappedPtrOperations<StackShape, Wrapper>
+ : public WrappedPtrOperations<StackShape, Wrapper>
+{
+ StackShape& ss() { return static_cast<Wrapper*>(this)->get(); }
public:
void updateGetterSetter(GetterOp rawGetter, SetterOp rawSetter) {
@@ -1383,19 +1387,6 @@ class MutableStackShapeOperations : public StackShapeOperations<Outer> {
void setAttrs(uint8_t attrs) { ss().attrs = attrs; }
};
-template <>
-class RootedBase<StackShape> : public MutableStackShapeOperations<JS::Rooted<StackShape>>
-{};
-
-template <>
-class HandleBase<StackShape> : public StackShapeOperations<JS::Handle<StackShape>>
-{};
-
-template <>
-class MutableHandleBase<StackShape>
- : public MutableStackShapeOperations<JS::MutableHandle<StackShape>>
-{};
-
inline
Shape::Shape(const StackShape& other, uint32_t nfixed)
: base_(other.base),
@@ -1550,38 +1541,6 @@ Shape::matches(const StackShape& other) const
other.rawGetter, other.rawSetter);
}
-// Property lookup hooks on objects are required to return a non-nullptr shape
-// to signify that the property has been found. For cases where the property is
-// not actually represented by a Shape, use a dummy value. This includes all
-// properties of non-native objects, and dense elements for native objects.
-// Use separate APIs for these two cases.
-
-template <AllowGC allowGC>
-static inline void
-MarkNonNativePropertyFound(typename MaybeRooted<Shape*, allowGC>::MutableHandleType propp)
-{
- propp.set(reinterpret_cast<Shape*>(1));
-}
-
-template <AllowGC allowGC>
-static inline void
-MarkDenseOrTypedArrayElementFound(typename MaybeRooted<Shape*, allowGC>::MutableHandleType propp)
-{
- propp.set(reinterpret_cast<Shape*>(1));
-}
-
-static inline bool
-IsImplicitDenseOrTypedArrayElement(Shape* prop)
-{
- return prop == reinterpret_cast<Shape*>(1);
-}
-
-static inline bool
-IsImplicitNonNativeProperty(Shape* prop)
-{
- return prop == reinterpret_cast<Shape*>(1);
-}
-
Shape*
ReshapeForAllocKind(JSContext* cx, Shape* shape, TaggedProto proto,
gc::AllocKind allocKind);
diff --git a/js/src/vm/SharedMem.h b/js/src/vm/SharedMem.h
index fe8dad304..8e5bae492 100644
--- a/js/src/vm/SharedMem.h
+++ b/js/src/vm/SharedMem.h
@@ -11,8 +11,8 @@
template<typename T>
class SharedMem
{
- static_assert(mozilla::IsPointer<T>::value,
- "SharedMem encapsulates pointer types");
+ // static_assert(mozilla::IsPointer<T>::value,
+ // "SharedMem encapsulates pointer types");
enum Sharedness {
IsUnshared,
diff --git a/js/src/vm/String.h b/js/src/vm/String.h
index 0937ac24d..4c43439cd 100644
--- a/js/src/vm/String.h
+++ b/js/src/vm/String.h
@@ -521,7 +521,7 @@ class JSString : public js::gc::TenuredCell
}
static MOZ_ALWAYS_INLINE void writeBarrierPre(JSString* thing) {
- if (isNullLike(thing) || thing->isPermanentAtom())
+ if (!thing || thing->isPermanentAtom())
return;
TenuredCell::writeBarrierPre(thing);
diff --git a/js/src/vm/TaggedProto.h b/js/src/vm/TaggedProto.h
index de3e86a7f..10b8c1171 100644
--- a/js/src/vm/TaggedProto.h
+++ b/js/src/vm/TaggedProto.h
@@ -68,20 +68,16 @@ struct InternalBarrierMethods<TaggedProto>
static void readBarrier(const TaggedProto& proto);
- static bool isMarkableTaggedPointer(TaggedProto proto) {
- return proto.isObject();
- }
-
static bool isMarkable(TaggedProto proto) {
return proto.isObject();
}
};
-template<class Outer>
-class TaggedProtoOperations
+template <class Wrapper>
+class WrappedPtrOperations<TaggedProto, Wrapper>
{
const TaggedProto& value() const {
- return static_cast<const Outer*>(this)->get();
+ return static_cast<const Wrapper*>(this)->get();
}
public:
@@ -95,18 +91,6 @@ class TaggedProtoOperations
uint64_t uniqueId() const { return value().uniqueId(); }
};
-template <>
-class HandleBase<TaggedProto> : public TaggedProtoOperations<Handle<TaggedProto>>
-{};
-
-template <>
-class RootedBase<TaggedProto> : public TaggedProtoOperations<Rooted<TaggedProto>>
-{};
-
-template <>
-class BarrieredBaseMixins<TaggedProto> : public TaggedProtoOperations<GCPtr<TaggedProto>>
-{};
-
// If the TaggedProto is a JSObject pointer, convert to that type and call |f|
// with the pointer. If the TaggedProto is lazy, calls F::defaultValue.
template <typename F, typename... Args>
diff --git a/js/src/vm/UnboxedObject.cpp b/js/src/vm/UnboxedObject.cpp
index 4912e65db..a28f6a95a 100644
--- a/js/src/vm/UnboxedObject.cpp
+++ b/js/src/vm/UnboxedObject.cpp
@@ -720,10 +720,10 @@ UnboxedPlainObject::createWithProperties(ExclusiveContext* cx, HandleObjectGroup
/* static */ bool
UnboxedPlainObject::obj_lookupProperty(JSContext* cx, HandleObject obj,
HandleId id, MutableHandleObject objp,
- MutableHandleShape propp)
+ MutableHandle<PropertyResult> propp)
{
if (obj->as<UnboxedPlainObject>().containsUnboxedOrExpandoProperty(cx, id)) {
- MarkNonNativePropertyFound<CanGC>(propp);
+ propp.setNonNativeProperty();
objp.set(obj);
return true;
}
@@ -731,7 +731,7 @@ UnboxedPlainObject::obj_lookupProperty(JSContext* cx, HandleObject obj,
RootedObject proto(cx, obj->staticPrototype());
if (!proto) {
objp.set(nullptr);
- propp.set(nullptr);
+ propp.setNotFound();
return true;
}
@@ -1411,10 +1411,10 @@ UnboxedArrayObject::containsProperty(ExclusiveContext* cx, jsid id)
/* static */ bool
UnboxedArrayObject::obj_lookupProperty(JSContext* cx, HandleObject obj,
HandleId id, MutableHandleObject objp,
- MutableHandleShape propp)
+ MutableHandle<PropertyResult> propp)
{
if (obj->as<UnboxedArrayObject>().containsProperty(cx, id)) {
- MarkNonNativePropertyFound<CanGC>(propp);
+ propp.setNonNativeProperty();
objp.set(obj);
return true;
}
@@ -1422,7 +1422,7 @@ UnboxedArrayObject::obj_lookupProperty(JSContext* cx, HandleObject obj,
RootedObject proto(cx, obj->staticPrototype());
if (!proto) {
objp.set(nullptr);
- propp.set(nullptr);
+ propp.setNotFound();
return true;
}
diff --git a/js/src/vm/UnboxedObject.h b/js/src/vm/UnboxedObject.h
index 8622be8a7..6fc482ec7 100644
--- a/js/src/vm/UnboxedObject.h
+++ b/js/src/vm/UnboxedObject.h
@@ -242,7 +242,7 @@ class UnboxedPlainObject : public JSObject
static bool obj_lookupProperty(JSContext* cx, HandleObject obj,
HandleId id, MutableHandleObject objp,
- MutableHandleShape propp);
+ MutableHandle<PropertyResult> propp);
static bool obj_defineProperty(JSContext* cx, HandleObject obj, HandleId id,
Handle<PropertyDescriptor> desc,
@@ -378,7 +378,7 @@ class UnboxedArrayObject : public JSObject
static bool obj_lookupProperty(JSContext* cx, HandleObject obj,
HandleId id, MutableHandleObject objp,
- MutableHandleShape propp);
+ MutableHandle<PropertyResult> propp);
static bool obj_defineProperty(JSContext* cx, HandleObject obj, HandleId id,
Handle<PropertyDescriptor> desc,
diff --git a/js/xpconnect/src/XPCInlines.h b/js/xpconnect/src/XPCInlines.h
index ad3d0c784..e60fac824 100644
--- a/js/xpconnect/src/XPCInlines.h
+++ b/js/xpconnect/src/XPCInlines.h
@@ -470,7 +470,7 @@ inline
void XPCWrappedNativeTearOff::JSObjectMoved(JSObject* obj, const JSObject* old)
{
MOZ_ASSERT(!IsMarked());
- MOZ_ASSERT(mJSObject.unbarrieredGetPtr() == old);
+ MOZ_ASSERT(mJSObject == old);
mJSObject = obj;
}
diff --git a/js/xpconnect/src/XPCWrappedNative.cpp b/js/xpconnect/src/XPCWrappedNative.cpp
index 96f825f05..2e3419f28 100644
--- a/js/xpconnect/src/XPCWrappedNative.cpp
+++ b/js/xpconnect/src/XPCWrappedNative.cpp
@@ -935,7 +935,7 @@ void
XPCWrappedNative::FlatJSObjectMoved(JSObject* obj, const JSObject* old)
{
JS::AutoAssertGCCallback inCallback(obj);
- MOZ_ASSERT(mFlatJSObject.unbarrieredGetPtr() == old);
+ MOZ_ASSERT(mFlatJSObject == old);
nsWrapperCache* cache = nullptr;
CallQueryInterface(mIdentity, &cache);
diff --git a/js/xpconnect/src/XPCWrappedNativeProto.cpp b/js/xpconnect/src/XPCWrappedNativeProto.cpp
index 6aa023432..7515ce3f0 100644
--- a/js/xpconnect/src/XPCWrappedNativeProto.cpp
+++ b/js/xpconnect/src/XPCWrappedNativeProto.cpp
@@ -114,7 +114,7 @@ XPCWrappedNativeProto::CallPostCreatePrototype()
void
XPCWrappedNativeProto::JSProtoObjectFinalized(js::FreeOp* fop, JSObject* obj)
{
- MOZ_ASSERT(obj == mJSProtoObject.unbarrieredGet(), "huh?");
+ MOZ_ASSERT(obj == mJSProtoObject, "huh?");
// Only remove this proto from the map if it is the one in the map.
ClassInfo2WrappedNativeProtoMap* map = GetScope()->GetWrappedNativeProtoMap();
@@ -129,7 +129,7 @@ XPCWrappedNativeProto::JSProtoObjectFinalized(js::FreeOp* fop, JSObject* obj)
void
XPCWrappedNativeProto::JSProtoObjectMoved(JSObject* obj, const JSObject* old)
{
- MOZ_ASSERT(mJSProtoObject.unbarrieredGet() == old);
+ MOZ_ASSERT(mJSProtoObject == old);
mJSProtoObject.init(obj); // Update without triggering barriers.
}