summaryrefslogtreecommitdiffstats
path: root/js/src/vm/TaggedProto.h
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
commit36d22d82aa202bb199967e9512281e9a53db42c9 (patch)
tree105e8c98ddea1c1e4784a60a5a6410fa416be2de /js/src/vm/TaggedProto.h
parentInitial commit. (diff)
downloadfirefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.tar.xz
firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.zip
Adding upstream version 115.7.0esr.upstream/115.7.0esrupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'js/src/vm/TaggedProto.h')
-rw-r--r--js/src/vm/TaggedProto.h173
1 files changed, 173 insertions, 0 deletions
diff --git a/js/src/vm/TaggedProto.h b/js/src/vm/TaggedProto.h
new file mode 100644
index 0000000000..42aecf998a
--- /dev/null
+++ b/js/src/vm/TaggedProto.h
@@ -0,0 +1,173 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim: set ts=8 sts=2 et sw=2 tw=80:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * 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/. */
+
+#ifndef vm_TaggedProto_h
+#define vm_TaggedProto_h
+
+#include "mozilla/Maybe.h"
+
+#include "gc/Barrier.h"
+#include "js/HashTable.h"
+#include "js/RootingAPI.h"
+
+class JSObject;
+
+namespace js {
+
+// Information about an object prototype, which can be either a particular
+// object, null, or a lazily generated object. The latter is only used by
+// certain kinds of proxies.
+class TaggedProto {
+ public:
+ static JSObject* const LazyProto;
+
+ TaggedProto() : proto(nullptr) {}
+ TaggedProto(const TaggedProto& other) = default;
+ explicit TaggedProto(JSObject* proto) : proto(proto) {}
+
+ bool isDynamic() const { return proto == LazyProto; }
+ bool isObject() const {
+ /* Skip nullptr and LazyProto. */
+ return uintptr_t(proto) > uintptr_t(TaggedProto::LazyProto);
+ }
+ JSObject* toObject() const {
+ MOZ_ASSERT(isObject());
+ return proto;
+ }
+ JSObject* toObjectOrNull() const {
+ MOZ_ASSERT(!proto || isObject());
+ return proto;
+ }
+ JSObject* raw() const { return proto; }
+
+ bool operator==(const TaggedProto& other) const {
+ return proto == other.proto;
+ }
+ bool operator!=(const TaggedProto& other) const {
+ return proto != other.proto;
+ }
+
+ HashNumber hashCode() const;
+
+ void trace(JSTracer* trc);
+
+ private:
+ JSObject* proto;
+};
+
+template <>
+struct StableCellHasher<TaggedProto> {
+ using Key = TaggedProto;
+ using Lookup = TaggedProto;
+
+ static bool maybeGetHash(const Lookup& l, HashNumber* hashOut) {
+ if (!l.isObject()) {
+ *hashOut = hash(l);
+ return true;
+ }
+
+ return StableCellHasher<JSObject*>::maybeGetHash(l.toObject(), hashOut);
+ }
+ static bool ensureHash(const Lookup& l, HashNumber* hashOut) {
+ if (!l.isObject()) {
+ *hashOut = hash(l);
+ return true;
+ }
+ return StableCellHasher<JSObject*>::ensureHash(l.toObject(), hashOut);
+ }
+ static HashNumber hash(const Lookup& l) {
+ if (l.isDynamic()) {
+ return uint64_t(1);
+ }
+ if (!l.isObject()) {
+ return uint64_t(0);
+ }
+ return StableCellHasher<JSObject*>::hash(l.toObject());
+ }
+ static bool match(const Key& k, const Lookup& l) {
+ return k.isDynamic() == l.isDynamic() && k.isObject() == l.isObject() &&
+ (!k.isObject() ||
+ StableCellHasher<JSObject*>::match(k.toObject(), l.toObject()));
+ }
+};
+
+#ifdef DEBUG
+MOZ_ALWAYS_INLINE void AssertTaggedProtoIsNotGray(const TaggedProto& proto) {
+ if (proto.isObject()) {
+ JS::AssertObjectIsNotGray(proto.toObject());
+ }
+}
+#endif
+
+template <>
+struct InternalBarrierMethods<TaggedProto> {
+ static void preBarrier(TaggedProto& proto);
+
+ static void postBarrier(TaggedProto* vp, TaggedProto prev, TaggedProto next);
+
+ static void readBarrier(const TaggedProto& proto);
+
+ static bool isMarkable(const TaggedProto& proto) { return proto.isObject(); }
+
+#ifdef DEBUG
+ static void assertThingIsNotGray(const TaggedProto& proto) {
+ AssertTaggedProtoIsNotGray(proto);
+ }
+#endif
+};
+
+template <class Wrapper>
+class WrappedPtrOperations<TaggedProto, Wrapper> {
+ const TaggedProto& value() const {
+ return static_cast<const Wrapper*>(this)->get();
+ }
+
+ public:
+ uintptr_t toWord() const { return value().toWord(); }
+ inline bool isDynamic() const { return value().isDynamic(); }
+ inline bool isObject() const { return value().isObject(); }
+ inline JSObject* toObject() const { return value().toObject(); }
+ inline JSObject* toObjectOrNull() const { return value().toObjectOrNull(); }
+ JSObject* raw() const { return value().raw(); }
+ HashNumber hashCode() const { return value().hashCode(); }
+ uint64_t uniqueId() const { return value().uniqueId(); }
+};
+
+// If the TaggedProto is a JSObject pointer, convert to that type and call |f|
+// with the pointer. If the TaggedProto is lazy, returns None().
+template <typename F>
+auto MapGCThingTyped(const TaggedProto& proto, F&& f) {
+ if (proto.isObject()) {
+ return mozilla::Some(f(proto.toObject()));
+ }
+ using ReturnType = decltype(f(static_cast<JSObject*>(nullptr)));
+ return mozilla::Maybe<ReturnType>();
+}
+
+template <typename F>
+bool ApplyGCThingTyped(const TaggedProto& proto, F&& f) {
+ return MapGCThingTyped(proto,
+ [&f](auto t) {
+ f(t);
+ return true;
+ })
+ .isSome();
+}
+
+// Since JSObject pointers are either nullptr or a valid object and since the
+// object layout of TaggedProto is identical to a bare object pointer, we can
+// safely treat a pointer to an already-rooted object (e.g. HandleObject) as a
+// pointer to a TaggedProto.
+inline Handle<TaggedProto> AsTaggedProto(HandleObject obj) {
+ static_assert(sizeof(JSObject*) == sizeof(TaggedProto),
+ "TaggedProto must be binary compatible with JSObject");
+ return Handle<TaggedProto>::fromMarkedLocation(
+ reinterpret_cast<TaggedProto const*>(obj.address()));
+}
+
+} // namespace js
+
+#endif // vm_TaggedProto_h