Bug 1865597 - Add error checking when initializing parallel marking and disable on...
[gecko.git] / js / src / vm / TaggedProto.h
blob42aecf998aa5f560881a1bd62fe01022b6728f26
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: set ts=8 sts=2 et sw=2 tw=80:
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #ifndef vm_TaggedProto_h
8 #define vm_TaggedProto_h
10 #include "mozilla/Maybe.h"
12 #include "gc/Barrier.h"
13 #include "js/HashTable.h"
14 #include "js/RootingAPI.h"
16 class JSObject;
18 namespace js {
20 // Information about an object prototype, which can be either a particular
21 // object, null, or a lazily generated object. The latter is only used by
22 // certain kinds of proxies.
23 class TaggedProto {
24 public:
25 static JSObject* const LazyProto;
27 TaggedProto() : proto(nullptr) {}
28 TaggedProto(const TaggedProto& other) = default;
29 explicit TaggedProto(JSObject* proto) : proto(proto) {}
31 bool isDynamic() const { return proto == LazyProto; }
32 bool isObject() const {
33 /* Skip nullptr and LazyProto. */
34 return uintptr_t(proto) > uintptr_t(TaggedProto::LazyProto);
36 JSObject* toObject() const {
37 MOZ_ASSERT(isObject());
38 return proto;
40 JSObject* toObjectOrNull() const {
41 MOZ_ASSERT(!proto || isObject());
42 return proto;
44 JSObject* raw() const { return proto; }
46 bool operator==(const TaggedProto& other) const {
47 return proto == other.proto;
49 bool operator!=(const TaggedProto& other) const {
50 return proto != other.proto;
53 HashNumber hashCode() const;
55 void trace(JSTracer* trc);
57 private:
58 JSObject* proto;
61 template <>
62 struct StableCellHasher<TaggedProto> {
63 using Key = TaggedProto;
64 using Lookup = TaggedProto;
66 static bool maybeGetHash(const Lookup& l, HashNumber* hashOut) {
67 if (!l.isObject()) {
68 *hashOut = hash(l);
69 return true;
72 return StableCellHasher<JSObject*>::maybeGetHash(l.toObject(), hashOut);
74 static bool ensureHash(const Lookup& l, HashNumber* hashOut) {
75 if (!l.isObject()) {
76 *hashOut = hash(l);
77 return true;
79 return StableCellHasher<JSObject*>::ensureHash(l.toObject(), hashOut);
81 static HashNumber hash(const Lookup& l) {
82 if (l.isDynamic()) {
83 return uint64_t(1);
85 if (!l.isObject()) {
86 return uint64_t(0);
88 return StableCellHasher<JSObject*>::hash(l.toObject());
90 static bool match(const Key& k, const Lookup& l) {
91 return k.isDynamic() == l.isDynamic() && k.isObject() == l.isObject() &&
92 (!k.isObject() ||
93 StableCellHasher<JSObject*>::match(k.toObject(), l.toObject()));
97 #ifdef DEBUG
98 MOZ_ALWAYS_INLINE void AssertTaggedProtoIsNotGray(const TaggedProto& proto) {
99 if (proto.isObject()) {
100 JS::AssertObjectIsNotGray(proto.toObject());
103 #endif
105 template <>
106 struct InternalBarrierMethods<TaggedProto> {
107 static void preBarrier(TaggedProto& proto);
109 static void postBarrier(TaggedProto* vp, TaggedProto prev, TaggedProto next);
111 static void readBarrier(const TaggedProto& proto);
113 static bool isMarkable(const TaggedProto& proto) { return proto.isObject(); }
115 #ifdef DEBUG
116 static void assertThingIsNotGray(const TaggedProto& proto) {
117 AssertTaggedProtoIsNotGray(proto);
119 #endif
122 template <class Wrapper>
123 class WrappedPtrOperations<TaggedProto, Wrapper> {
124 const TaggedProto& value() const {
125 return static_cast<const Wrapper*>(this)->get();
128 public:
129 uintptr_t toWord() const { return value().toWord(); }
130 inline bool isDynamic() const { return value().isDynamic(); }
131 inline bool isObject() const { return value().isObject(); }
132 inline JSObject* toObject() const { return value().toObject(); }
133 inline JSObject* toObjectOrNull() const { return value().toObjectOrNull(); }
134 JSObject* raw() const { return value().raw(); }
135 HashNumber hashCode() const { return value().hashCode(); }
136 uint64_t uniqueId() const { return value().uniqueId(); }
139 // If the TaggedProto is a JSObject pointer, convert to that type and call |f|
140 // with the pointer. If the TaggedProto is lazy, returns None().
141 template <typename F>
142 auto MapGCThingTyped(const TaggedProto& proto, F&& f) {
143 if (proto.isObject()) {
144 return mozilla::Some(f(proto.toObject()));
146 using ReturnType = decltype(f(static_cast<JSObject*>(nullptr)));
147 return mozilla::Maybe<ReturnType>();
150 template <typename F>
151 bool ApplyGCThingTyped(const TaggedProto& proto, F&& f) {
152 return MapGCThingTyped(proto,
153 [&f](auto t) {
154 f(t);
155 return true;
157 .isSome();
160 // Since JSObject pointers are either nullptr or a valid object and since the
161 // object layout of TaggedProto is identical to a bare object pointer, we can
162 // safely treat a pointer to an already-rooted object (e.g. HandleObject) as a
163 // pointer to a TaggedProto.
164 inline Handle<TaggedProto> AsTaggedProto(HandleObject obj) {
165 static_assert(sizeof(JSObject*) == sizeof(TaggedProto),
166 "TaggedProto must be binary compatible with JSObject");
167 return Handle<TaggedProto>::fromMarkedLocation(
168 reinterpret_cast<TaggedProto const*>(obj.address()));
171 } // namespace js
173 #endif // vm_TaggedProto_h