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"
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.
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());
40 JSObject
* toObjectOrNull() const {
41 MOZ_ASSERT(!proto
|| isObject());
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
);
62 struct StableCellHasher
<TaggedProto
> {
63 using Key
= TaggedProto
;
64 using Lookup
= TaggedProto
;
66 static bool maybeGetHash(const Lookup
& l
, HashNumber
* hashOut
) {
72 return StableCellHasher
<JSObject
*>::maybeGetHash(l
.toObject(), hashOut
);
74 static bool ensureHash(const Lookup
& l
, HashNumber
* hashOut
) {
79 return StableCellHasher
<JSObject
*>::ensureHash(l
.toObject(), hashOut
);
81 static HashNumber
hash(const Lookup
& l
) {
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() &&
93 StableCellHasher
<JSObject
*>::match(k
.toObject(), l
.toObject()));
98 MOZ_ALWAYS_INLINE
void AssertTaggedProtoIsNotGray(const TaggedProto
& proto
) {
99 if (proto
.isObject()) {
100 JS::AssertObjectIsNotGray(proto
.toObject());
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(); }
116 static void assertThingIsNotGray(const TaggedProto
& proto
) {
117 AssertTaggedProtoIsNotGray(proto
);
122 template <class Wrapper
>
123 class WrappedPtrOperations
<TaggedProto
, Wrapper
> {
124 const TaggedProto
& value() const {
125 return static_cast<const Wrapper
*>(this)->get();
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
,
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()));
173 #endif // vm_TaggedProto_h