Bug 1867190 - Add prefs for PHC probablities r=glandium
[gecko.git] / js / src / vm / PromiseObject.h
blob72947245109e3f4d2a2f22221d99baefc8dc9c5f
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_PromiseObject_h
8 #define vm_PromiseObject_h
10 #include "mozilla/Assertions.h" // MOZ_ASSERT
12 #include <stdint.h> // int32_t, uint64_t
14 #include "js/Class.h" // JSClass
15 #include "js/Promise.h" // JS::PromiseState
16 #include "js/RootingAPI.h" // JS::{,Mutable}Handle
17 #include "js/Value.h" // JS::Value, JS::Int32Value, JS::UndefinedHandleValue
18 #include "vm/NativeObject.h" // js::NativeObject
20 class JS_PUBLIC_API JSObject;
22 namespace js {
24 class SavedFrame;
26 enum PromiseSlots {
27 // Int32 value with PROMISE_FLAG_* flags below.
28 PromiseSlot_Flags = 0,
30 // * if this promise is pending, reaction objects
31 // * undefined if there's no reaction
32 // * maybe-wrapped PromiseReactionRecord if there's only one reacion
33 // * dense array if there are two or more more reactions
34 // * if this promise is fulfilled, the resolution value
35 // * if this promise is rejected, the reason for the rejection
36 PromiseSlot_ReactionsOrResult,
38 // * if this promise is pending, resolve/reject functions.
39 // This slot holds only the reject function. The resolve function is
40 // reachable from the reject function's extended slot.
41 // * if this promise is either fulfilled or rejected, undefined
42 PromiseSlot_RejectFunction,
44 // Promise object's debug info, which is created on demand.
45 // * if this promise has no debug info, undefined
46 // * if this promise contains only its process-unique ID, the ID's number
47 // value
48 // * otherwise a PromiseDebugInfo object
49 PromiseSlot_DebugInfo,
51 PromiseSlots,
54 // This promise is either fulfilled or rejected.
55 // If this flag is not set, this promise is pending.
56 #define PROMISE_FLAG_RESOLVED 0x1
58 // If this flag and PROMISE_FLAG_RESOLVED are set, this promise is fulfilled.
59 // If only PROMISE_FLAG_RESOLVED is set, this promise is rejected.
60 #define PROMISE_FLAG_FULFILLED 0x2
62 // Indicates the promise has ever had a fulfillment or rejection handler;
63 // used in unhandled rejection tracking.
64 #define PROMISE_FLAG_HANDLED 0x4
66 // This promise uses the default resolving functions.
67 // The PromiseSlot_RejectFunction slot is not used.
68 #define PROMISE_FLAG_DEFAULT_RESOLVING_FUNCTIONS 0x08
70 // This promise's Promise Resolve Function's [[AlreadyResolved]].[[Value]] is
71 // set to true.
73 // Valid only for promises with PROMISE_FLAG_DEFAULT_RESOLVING_FUNCTIONS.
74 // For promises without PROMISE_FLAG_DEFAULT_RESOLVING_FUNCTIONS, Promise
75 // Resolve/Reject Function's "Promise" slot represents the value.
76 #define PROMISE_FLAG_DEFAULT_RESOLVING_FUNCTIONS_ALREADY_RESOLVED 0x10
78 // This promise is either the return value of an async function invocation or
79 // an async generator's method.
80 #define PROMISE_FLAG_ASYNC 0x20
82 // This promise knows how to propagate information required to keep track of
83 // whether an activation behavior was in progress when the original promise in
84 // the promise chain was created. This is a concept defined in the HTML spec:
85 // https://html.spec.whatwg.org/multipage/interaction.html#triggered-by-user-activation
86 // It is used by the embedder in order to request SpiderMonkey to keep track of
87 // this information in a Promise, and also to propagate it to newly created
88 // promises while processing Promise#then.
89 #define PROMISE_FLAG_REQUIRES_USER_INTERACTION_HANDLING 0x40
91 // This flag indicates whether an activation behavior was in progress when the
92 // original promise in the promise chain was created. Activation behavior is a
93 // concept defined by the HTML spec:
94 // https://html.spec.whatwg.org/multipage/interaction.html#triggered-by-user-activation
95 // This flag is only effective when the
96 // PROMISE_FLAG_REQUIRES_USER_INTERACTION_HANDLING is set.
97 #define PROMISE_FLAG_HAD_USER_INTERACTION_UPON_CREATION 0x80
99 struct PromiseReactionRecordBuilder;
101 class PromiseObject : public NativeObject {
102 public:
103 static const unsigned RESERVED_SLOTS = PromiseSlots;
104 static const JSClass class_;
105 static const JSClass protoClass_;
106 static PromiseObject* create(JSContext* cx, JS::Handle<JSObject*> executor,
107 JS::Handle<JSObject*> proto = nullptr,
108 bool needsWrapping = false);
110 static PromiseObject* createSkippingExecutor(JSContext* cx);
112 // Create an instance of the original Promise binding, rejected with the given
113 // value.
114 static PromiseObject* unforgeableReject(JSContext* cx,
115 JS::Handle<JS::Value> value);
117 // Create an instance of the original Promise binding, resolved with the given
118 // value.
120 // However, if |value| is itself a promise -- including from another realm --
121 // |value| itself will in some circumstances be returned. This sadly means
122 // this function must return |JSObject*| and can't return |PromiseObject*|.
123 static JSObject* unforgeableResolve(JSContext* cx,
124 JS::Handle<JS::Value> value);
126 // Create an instance of the original Promise binding, resolved with the given
127 // value *that is not a promise* -- from this realm/compartment or from any
128 // other.
130 // If you don't know for certain that your value will never be a promise, use
131 // |PromiseObject::unforgeableResolve| instead.
133 // Use |PromiseResolvedWithUndefined| (defined below) if your value is always
134 // |undefined|.
135 static PromiseObject* unforgeableResolveWithNonPromise(
136 JSContext* cx, JS::Handle<JS::Value> value);
138 int32_t flags() { return getFixedSlot(PromiseSlot_Flags).toInt32(); }
140 void setHandled() {
141 setFixedSlot(PromiseSlot_Flags,
142 JS::Int32Value(flags() | PROMISE_FLAG_HANDLED));
145 JS::PromiseState state() {
146 int32_t flags = this->flags();
147 if (!(flags & PROMISE_FLAG_RESOLVED)) {
148 MOZ_ASSERT(!(flags & PROMISE_FLAG_FULFILLED));
149 return JS::PromiseState::Pending;
151 if (flags & PROMISE_FLAG_FULFILLED) {
152 return JS::PromiseState::Fulfilled;
154 return JS::PromiseState::Rejected;
157 JS::Value reactions() {
158 MOZ_ASSERT(state() == JS::PromiseState::Pending);
159 return getFixedSlot(PromiseSlot_ReactionsOrResult);
162 JS::Value value() {
163 MOZ_ASSERT(state() == JS::PromiseState::Fulfilled);
164 return getFixedSlot(PromiseSlot_ReactionsOrResult);
167 JS::Value reason() {
168 MOZ_ASSERT(state() == JS::PromiseState::Rejected);
169 return getFixedSlot(PromiseSlot_ReactionsOrResult);
172 JS::Value valueOrReason() {
173 MOZ_ASSERT(state() != JS::PromiseState::Pending);
174 return getFixedSlot(PromiseSlot_ReactionsOrResult);
177 [[nodiscard]] static bool resolve(JSContext* cx,
178 JS::Handle<PromiseObject*> promise,
179 JS::Handle<JS::Value> resolutionValue);
180 [[nodiscard]] static bool reject(JSContext* cx,
181 JS::Handle<PromiseObject*> promise,
182 JS::Handle<JS::Value> rejectionValue);
184 static void onSettled(JSContext* cx, JS::Handle<PromiseObject*> promise,
185 JS::Handle<js::SavedFrame*> rejectionStack);
187 double allocationTime();
188 double resolutionTime();
189 JSObject* allocationSite();
190 JSObject* resolutionSite();
191 double lifetime();
192 double timeToResolution() {
193 MOZ_ASSERT(state() != JS::PromiseState::Pending);
194 return resolutionTime() - allocationTime();
197 [[nodiscard]] bool dependentPromises(
198 JSContext* cx, JS::MutableHandle<GCVector<Value>> values);
200 // Return the process-unique ID of this promise. Only used by the debugger.
201 uint64_t getID();
203 // Apply 'builder' to each reaction record in this promise's list. Used only
204 // by the Debugger API.
206 // The context cx need not be same-compartment with this promise. (In typical
207 // use, cx is in a debugger compartment, and this promise is in a debuggee
208 // compartment.) This function presents data to builder exactly as it appears
209 // in the reaction records, so the values passed to builder methods could
210 // potentially be cross-compartment with both cx and this promise.
212 // If this function encounters an error, it will report it to 'cx' and return
213 // false. If a builder call returns false, iteration stops, and this function
214 // returns false; the build should set an error on 'cx' as appropriate.
215 // Otherwise, this function returns true.
216 [[nodiscard]] bool forEachReactionRecord(
217 JSContext* cx, PromiseReactionRecordBuilder& builder);
219 bool isUnhandled() {
220 MOZ_ASSERT(state() == JS::PromiseState::Rejected);
221 return !(flags() & PROMISE_FLAG_HANDLED);
224 bool requiresUserInteractionHandling() {
225 return (flags() & PROMISE_FLAG_REQUIRES_USER_INTERACTION_HANDLING);
228 void setRequiresUserInteractionHandling(bool state);
230 bool hadUserInteractionUponCreation() {
231 return (flags() & PROMISE_FLAG_HAD_USER_INTERACTION_UPON_CREATION);
234 void setHadUserInteractionUponCreation(bool state);
236 void copyUserInteractionFlagsFrom(PromiseObject& rhs);
240 * Create an instance of the original Promise binding, resolved with the value
241 * |undefined|.
243 inline PromiseObject* PromiseResolvedWithUndefined(JSContext* cx) {
244 return PromiseObject::unforgeableResolveWithNonPromise(
245 cx, JS::UndefinedHandleValue);
248 } // namespace js
250 #endif // vm_PromiseObject_h