Tue, 06 Jan 2015 21:39:09 +0100
Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.
1 /* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
2 /* vim: set ts=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 file,
5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #ifndef mozilla_dom_Promise_h
8 #define mozilla_dom_Promise_h
10 #include "mozilla/Attributes.h"
11 #include "mozilla/ErrorResult.h"
12 #include "mozilla/TypeTraits.h"
13 #include "mozilla/dom/BindingDeclarations.h"
14 #include "nsCycleCollectionParticipant.h"
15 #include "mozilla/dom/PromiseBinding.h"
16 #include "mozilla/dom/ToJSValue.h"
17 #include "nsWrapperCache.h"
18 #include "nsAutoPtr.h"
19 #include "js/TypeDecls.h"
21 #include "mozilla/dom/workers/bindings/WorkerFeature.h"
23 class nsIGlobalObject;
25 namespace mozilla {
26 namespace dom {
28 class AnyCallback;
29 class PromiseCallback;
30 class PromiseInit;
31 class PromiseNativeHandler;
33 class Promise;
34 class PromiseReportRejectFeature : public workers::WorkerFeature
35 {
36 // The Promise that owns this feature.
37 Promise* mPromise;
39 public:
40 PromiseReportRejectFeature(Promise* aPromise)
41 : mPromise(aPromise)
42 {
43 MOZ_ASSERT(mPromise);
44 }
46 virtual bool
47 Notify(JSContext* aCx, workers::Status aStatus) MOZ_OVERRIDE;
48 };
50 class Promise MOZ_FINAL : public nsISupports,
51 public nsWrapperCache
52 {
53 friend class NativePromiseCallback;
54 friend class PromiseResolverMixin;
55 friend class PromiseResolverTask;
56 friend class PromiseTask;
57 friend class PromiseReportRejectFeature;
58 friend class RejectPromiseCallback;
59 friend class ResolvePromiseCallback;
60 friend class WorkerPromiseResolverTask;
61 friend class WorkerPromiseTask;
62 friend class WrapperPromiseCallback;
64 ~Promise();
66 public:
67 NS_DECL_CYCLE_COLLECTING_ISUPPORTS
68 NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(Promise)
70 Promise(nsIGlobalObject* aGlobal);
72 typedef void (Promise::*MaybeFunc)(JSContext* aCx,
73 JS::Handle<JS::Value> aValue);
75 void MaybeResolve(JSContext* aCx,
76 JS::Handle<JS::Value> aValue);
77 void MaybeReject(JSContext* aCx,
78 JS::Handle<JS::Value> aValue);
80 // Helpers for using Promise from C++.
81 // Most DOM objects are handled already. To add a new type T, add a
82 // ToJSValue overload in ToJSValue.h.
83 // aArg is a const reference so we can pass rvalues like integer constants
84 template <typename T>
85 void MaybeResolve(const T& aArg) {
86 MaybeSomething(aArg, &Promise::MaybeResolve);
87 }
89 // aArg is a const reference so we can pass rvalues like NS_ERROR_*
90 template <typename T>
91 void MaybeReject(const T& aArg) {
92 MaybeSomething(aArg, &Promise::MaybeReject);
93 }
95 // WebIDL
97 nsIGlobalObject* GetParentObject() const
98 {
99 return mGlobal;
100 }
102 virtual JSObject*
103 WrapObject(JSContext* aCx) MOZ_OVERRIDE;
105 static already_AddRefed<Promise>
106 Constructor(const GlobalObject& aGlobal, PromiseInit& aInit,
107 ErrorResult& aRv);
109 static already_AddRefed<Promise>
110 Resolve(const GlobalObject& aGlobal, JSContext* aCx,
111 JS::Handle<JS::Value> aValue, ErrorResult& aRv);
113 static already_AddRefed<Promise>
114 Resolve(nsIGlobalObject* aGlobal, JSContext* aCx,
115 JS::Handle<JS::Value> aValue, ErrorResult& aRv);
117 static already_AddRefed<Promise>
118 Reject(const GlobalObject& aGlobal, JSContext* aCx,
119 JS::Handle<JS::Value> aValue, ErrorResult& aRv);
121 static already_AddRefed<Promise>
122 Reject(nsIGlobalObject* aGlobal, JSContext* aCx,
123 JS::Handle<JS::Value> aValue, ErrorResult& aRv);
125 already_AddRefed<Promise>
126 Then(JSContext* aCx, AnyCallback* aResolveCallback,
127 AnyCallback* aRejectCallback);
129 already_AddRefed<Promise>
130 Catch(JSContext* aCx, AnyCallback* aRejectCallback);
132 static already_AddRefed<Promise>
133 All(const GlobalObject& aGlobal, JSContext* aCx,
134 const Sequence<JS::Value>& aIterable, ErrorResult& aRv);
136 static already_AddRefed<Promise>
137 Race(const GlobalObject& aGlobal, JSContext* aCx,
138 const Sequence<JS::Value>& aIterable, ErrorResult& aRv);
140 void AppendNativeHandler(PromiseNativeHandler* aRunnable);
142 private:
143 enum PromiseState {
144 Pending,
145 Resolved,
146 Rejected
147 };
149 enum PromiseTaskSync {
150 SyncTask,
151 AsyncTask
152 };
154 void SetState(PromiseState aState)
155 {
156 MOZ_ASSERT(mState == Pending);
157 MOZ_ASSERT(aState != Pending);
158 mState = aState;
159 }
161 void SetResult(JS::Handle<JS::Value> aValue)
162 {
163 mResult = aValue;
164 }
166 // This method processes promise's resolve/reject callbacks with promise's
167 // result. It's executed when the resolver.resolve() or resolver.reject() is
168 // called or when the promise already has a result and new callbacks are
169 // appended by then(), catch() or done().
170 void RunTask();
172 void RunResolveTask(JS::Handle<JS::Value> aValue,
173 Promise::PromiseState aState,
174 PromiseTaskSync aAsynchronous);
176 void AppendCallbacks(PromiseCallback* aResolveCallback,
177 PromiseCallback* aRejectCallback);
179 // If we have been rejected and our mResult is a JS exception,
180 // report it to the error console.
181 // Use MaybeReportRejectedOnce() for actual calls.
182 void MaybeReportRejected();
184 void MaybeReportRejectedOnce() {
185 MaybeReportRejected();
186 RemoveFeature();
187 mResult = JS::UndefinedValue();
188 }
190 void MaybeResolveInternal(JSContext* aCx,
191 JS::Handle<JS::Value> aValue,
192 PromiseTaskSync aSync = AsyncTask);
193 void MaybeRejectInternal(JSContext* aCx,
194 JS::Handle<JS::Value> aValue,
195 PromiseTaskSync aSync = AsyncTask);
197 void ResolveInternal(JSContext* aCx,
198 JS::Handle<JS::Value> aValue,
199 PromiseTaskSync aSync = AsyncTask);
201 void RejectInternal(JSContext* aCx,
202 JS::Handle<JS::Value> aValue,
203 PromiseTaskSync aSync = AsyncTask);
205 // Helper methods for using Promises from C++
206 JSObject* GetOrCreateWrapper(JSContext* aCx);
208 template <typename T>
209 void MaybeSomething(T& aArgument, MaybeFunc aFunc) {
210 ThreadsafeAutoJSContext cx;
212 JSObject* wrapper = GetOrCreateWrapper(cx);
213 if (!wrapper) {
214 HandleException(cx);
215 return;
216 }
218 JSAutoCompartment ac(cx, wrapper);
219 JS::Rooted<JS::Value> val(cx);
220 if (!ToJSValue(cx, aArgument, &val)) {
221 HandleException(cx);
222 return;
223 }
225 (this->*aFunc)(cx, val);
226 }
228 // Static methods for the PromiseInit functions.
229 static bool
230 JSCallback(JSContext *aCx, unsigned aArgc, JS::Value *aVp);
232 static bool
233 ThenableResolverCommon(JSContext* aCx, uint32_t /* PromiseCallback::Task */ aTask,
234 unsigned aArgc, JS::Value* aVp);
235 static bool
236 JSCallbackThenableResolver(JSContext *aCx, unsigned aArgc, JS::Value *aVp);
237 static bool
238 JSCallbackThenableRejecter(JSContext *aCx, unsigned aArgc, JS::Value *aVp);
240 static JSObject*
241 CreateFunction(JSContext* aCx, JSObject* aParent, Promise* aPromise,
242 int32_t aTask);
244 static JSObject*
245 CreateThenableFunction(JSContext* aCx, Promise* aPromise, uint32_t aTask);
247 void HandleException(JSContext* aCx);
249 void RemoveFeature();
251 nsRefPtr<nsIGlobalObject> mGlobal;
253 nsTArray<nsRefPtr<PromiseCallback> > mResolveCallbacks;
254 nsTArray<nsRefPtr<PromiseCallback> > mRejectCallbacks;
256 JS::Heap<JS::Value> mResult;
257 PromiseState mState;
258 bool mTaskPending;
259 bool mHadRejectCallback;
261 bool mResolvePending;
263 // If a rejected promise on a worker has no reject callbacks attached, it
264 // needs to know when the worker is shutting down, to report the error on the
265 // console before the worker's context is deleted. This feature is used for
266 // that purpose.
267 nsAutoPtr<PromiseReportRejectFeature> mFeature;
268 };
270 } // namespace dom
271 } // namespace mozilla
273 #endif // mozilla_dom_Promise_h