Bug 1874684 - Part 10: Replace BigInt with Int128 in RoundNumberToIncrement. r=mgaudet
[gecko.git] / js / src / builtin / temporal / Wrapped.h
blob904a9b3ac927e89c8ce4a6d8f744c87db2cc9e3c
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 builtin_temporal_Wrapped_h
8 #define builtin_temporal_Wrapped_h
10 #include "mozilla/Assertions.h"
11 #include "mozilla/Attributes.h"
13 #include <type_traits>
15 #include "gc/Tracer.h"
16 #include "js/RootingAPI.h"
17 #include "vm/JSObject.h"
18 #include "vm/NativeObject.h"
20 namespace js::temporal {
22 /**
23 * Type to represent possibly wrapped objects from a different compartment.
25 * This can be used to represent specific JSObject sub-classes in return types
26 * without having to pass unwrapped objects around.
28 template <class T>
29 class MOZ_STACK_CLASS Wrapped final {
30 static_assert(std::is_pointer_v<T>);
31 static_assert(std::is_convertible_v<T, NativeObject*>);
33 using U = std::remove_pointer_t<T>;
35 JSObject* ptr_ = nullptr;
37 public:
38 Wrapped() = default;
40 MOZ_IMPLICIT Wrapped(decltype(nullptr)) : ptr_(nullptr) {}
42 MOZ_IMPLICIT Wrapped(T ptr) : ptr_(ptr) {
43 // No assertion needed when the object already has the correct type.
46 MOZ_IMPLICIT Wrapped(JSObject* ptr) : ptr_(ptr) {
47 // Ensure the caller passed a valid pointer.
48 MOZ_ASSERT_IF(ptr_, ptr_->canUnwrapAs<U>());
51 template <typename S>
52 MOZ_IMPLICIT Wrapped(
53 const JS::Rooted<S>& root,
54 std::enable_if_t<std::is_convertible_v<S, T>, int> dummy = 0)
55 : Wrapped(root.get()) {}
57 MOZ_IMPLICIT Wrapped(const JS::Rooted<JSObject*>& root)
58 : Wrapped(root.get()) {}
60 template <typename S>
61 MOZ_IMPLICIT Wrapped(
62 const JS::Handle<S>& root,
63 std::enable_if_t<std::is_convertible_v<S, T>, int> dummy = 0)
64 : Wrapped(root.get()) {}
66 MOZ_IMPLICIT Wrapped(const JS::Handle<JSObject*>& root)
67 : Wrapped(root.get()) {}
69 template <typename S>
70 MOZ_IMPLICIT Wrapped(
71 const JS::MutableHandle<S>& root,
72 std::enable_if_t<std::is_convertible_v<S, T>, int> dummy = 0)
73 : Wrapped(root.get()) {}
75 MOZ_IMPLICIT Wrapped(const JS::MutableHandle<JSObject*>& root)
76 : Wrapped(root.get()) {}
78 Wrapped& operator=(decltype(nullptr)) {
79 ptr_ = nullptr;
80 return *this;
83 Wrapped& operator=(T ptr) {
84 ptr_ = ptr;
85 return *this;
88 explicit operator bool() const { return !!ptr_; }
90 JSObject* operator->() const { return ptr_; }
92 JSObject& operator*() const { return *ptr_; }
94 JSObject* get() const { return ptr_; }
96 operator JSObject*() const { return get(); }
98 auto address() const { return &ptr_; }
100 U& unwrap() const {
101 MOZ_ASSERT(ptr_);
103 // Direct unwrap because the constructor already verified the object can be
104 // unwrapped.
106 // We use JSObject::unwrapAs() instead of JSObject::maybeUnwrapIf(), because
107 // this is an unrooted Wrapped, so hazard analysis will ensure that no
108 // wrappers have been invalidated, because wrapper invalidation generally
109 // only happens in the same case as GC.
111 // Rooted Wrapped are accessed through their WrappedPtrOperations
112 // specialization, which uses JSObject::maybeUnwrapIf() to handle the
113 // wrapper invalidation case correctly.
114 return ptr_->unwrapAs<U>();
117 U* unwrapOrNull() const {
118 // Direct unwrap because the constructor already verified the object can be
119 // unwrapped.
121 // See Wrapped::unwrap() for why we don't call maybeUnwrapIf() here.
122 return ptr_ ? &ptr_->unwrapAs<U>() : nullptr;
125 void trace(JSTracer* trc) { TraceNullableRoot(trc, &ptr_, "Wrapped::ptr_"); }
128 void ReportDeadWrapperOrAccessDenied(JSContext* cx, JSObject* obj);
130 } /* namespace js::temporal */
132 namespace js {
133 template <typename T, typename Container>
134 class WrappedPtrOperations<temporal::Wrapped<T>, Container> {
135 using U = std::remove_pointer_t<T>;
137 const auto& wrapped() const {
138 return static_cast<const Container*>(this)->get();
141 public:
142 explicit operator bool() const { return !!wrapped(); }
144 JSObject* operator->() const { return wrapped().get(); }
146 JSObject& operator*() const { return *wrapped().get(); }
148 JS::Handle<JSObject*> object() const {
149 return JS::Handle<JSObject*>::fromMarkedLocation(wrapped().address());
152 operator JS::Handle<JSObject*>() const { return object(); }
154 [[nodiscard]] U* unwrap(JSContext* cx) const {
155 JSObject* obj = wrapped().get();
157 // Call JSObject::maybeUnwrapIf() instead of JSObject::unwrapAs() in case
158 // |obj| is an invalidated wrapper.
159 if (auto* unwrapped = obj->maybeUnwrapIf<U>()) {
160 return unwrapped;
163 temporal::ReportDeadWrapperOrAccessDenied(cx, obj);
164 return nullptr;
167 } // namespace js
169 #endif /* builtin_temporal_Wrapped_h */