Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 : * vim: set ts=8 sts=4 et sw=4 tw=99:
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/. */
6 :
7 : #ifndef vm_TaggedProto_h
8 : #define vm_TaggedProto_h
9 :
10 : #include "gc/Tracer.h"
11 :
12 : namespace js {
13 :
14 : // Information about an object prototype, which can be either a particular
15 : // object, null, or a lazily generated object. The latter is only used by
16 : // certain kinds of proxies.
17 : class TaggedProto
18 : {
19 : public:
20 : static JSObject * const LazyProto;
21 :
22 114333 : TaggedProto() : proto(nullptr) {}
23 2487373 : TaggedProto(const TaggedProto& other) : proto(other.proto) {}
24 79395 : explicit TaggedProto(JSObject* proto) : proto(proto) {}
25 :
26 : uintptr_t toWord() const { return uintptr_t(proto); }
27 :
28 1091621 : bool isDynamic() const {
29 1091621 : return proto == LazyProto;
30 : }
31 3540055 : bool isObject() const {
32 : /* Skip nullptr and LazyProto. */
33 3540055 : return uintptr_t(proto) > uintptr_t(TaggedProto::LazyProto);
34 : }
35 1397589 : JSObject* toObject() const {
36 1397589 : MOZ_ASSERT(isObject());
37 1397577 : return proto;
38 : }
39 353806 : JSObject* toObjectOrNull() const {
40 353806 : MOZ_ASSERT(!proto || isObject());
41 353806 : return proto;
42 : }
43 5132 : JSObject* raw() const { return proto; }
44 :
45 170179 : bool operator ==(const TaggedProto& other) const { return proto == other.proto; }
46 0 : bool operator !=(const TaggedProto& other) const { return proto != other.proto; }
47 :
48 : HashNumber hashCode() const;
49 :
50 0 : void trace(JSTracer* trc) {
51 0 : if (isObject())
52 0 : TraceManuallyBarrieredEdge(trc, &proto, "TaggedProto");
53 0 : }
54 :
55 : private:
56 : JSObject* proto;
57 : };
58 :
59 : template <>
60 : struct MovableCellHasher<TaggedProto>
61 : {
62 : using Key = TaggedProto;
63 : using Lookup = TaggedProto;
64 :
65 915 : static bool hasHash(const Lookup& l) {
66 915 : return !l.isObject() || MovableCellHasher<JSObject*>::hasHash(l.toObject());
67 : }
68 114782 : static bool ensureHash(const Lookup& l) {
69 114782 : return !l.isObject() || MovableCellHasher<JSObject*>::ensureHash(l.toObject());
70 : }
71 274302 : static HashNumber hash(const Lookup& l) {
72 274302 : if (l.isDynamic())
73 622 : return uint64_t(1);
74 273681 : if (!l.isObject())
75 34752 : return uint64_t(0);
76 238930 : return MovableCellHasher<JSObject*>::hash(l.toObject());
77 : }
78 238860 : static bool match(const Key& k, const Lookup& l) {
79 477721 : return k.isDynamic() == l.isDynamic() &&
80 955439 : k.isObject() == l.isObject() &&
81 871335 : (!k.isObject() ||
82 871335 : MovableCellHasher<JSObject*>::match(k.toObject(), l.toObject()));
83 : }
84 : };
85 :
86 : template <>
87 : struct InternalBarrierMethods<TaggedProto>
88 : {
89 : static void preBarrier(TaggedProto& proto);
90 :
91 : static void postBarrier(TaggedProto* vp, TaggedProto prev, TaggedProto next);
92 :
93 : static void readBarrier(const TaggedProto& proto);
94 :
95 0 : static bool isMarkable(const TaggedProto& proto) {
96 0 : return proto.isObject();
97 : }
98 : };
99 :
100 : template <class Wrapper>
101 348535 : class WrappedPtrOperations<TaggedProto, Wrapper>
102 : {
103 217090 : const TaggedProto& value() const {
104 217090 : return static_cast<const Wrapper*>(this)->get();
105 : }
106 :
107 : public:
108 : uintptr_t toWord() const { return value().toWord(); }
109 : inline bool isDynamic() const { return value().isDynamic(); }
110 118112 : inline bool isObject() const { return value().isObject(); }
111 98900 : inline JSObject* toObject() const { return value().toObject(); }
112 69 : inline JSObject* toObjectOrNull() const { return value().toObjectOrNull(); }
113 : JSObject* raw() const { return value().raw(); }
114 : HashNumber hashCode() const { return value().hashCode(); }
115 : uint64_t uniqueId() const { return value().uniqueId(); }
116 : };
117 :
118 : // If the TaggedProto is a JSObject pointer, convert to that type and call |f|
119 : // with the pointer. If the TaggedProto is lazy, calls F::defaultValue.
120 : template <typename F, typename... Args>
121 : auto
122 0 : DispatchTyped(F f, const TaggedProto& proto, Args&&... args)
123 : -> decltype(f(static_cast<JSObject*>(nullptr), mozilla::Forward<Args>(args)...))
124 : {
125 0 : if (proto.isObject())
126 0 : return f(proto.toObject(), mozilla::Forward<Args>(args)...);
127 0 : return F::defaultValue(proto);
128 : }
129 :
130 : // Since JSObject pointers are either nullptr or a valid object and since the
131 : // object layout of TaggedProto is identical to a bare object pointer, we can
132 : // safely treat a pointer to an already-rooted object (e.g. HandleObject) as a
133 : // pointer to a TaggedProto.
134 : inline Handle<TaggedProto>
135 124656 : AsTaggedProto(HandleObject obj)
136 : {
137 : static_assert(sizeof(JSObject*) == sizeof(TaggedProto),
138 : "TaggedProto must be binary compatible with JSObject");
139 : return Handle<TaggedProto>::fromMarkedLocation(
140 124656 : reinterpret_cast<TaggedProto const*>(obj.address()));
141 : }
142 :
143 : } // namespace js
144 :
145 : #endif // vm_TaggedProto_h
|