Shaka Player Embedded
promise.cc
Go to the documentation of this file.
1 // Copyright 2017 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "src/mapping/promise.h"
16 
17 #include <utility>
18 
19 #include "src/mapping/callback.h"
21 #include "src/memory/heap_tracer.h"
22 
23 namespace shaka {
24 
25 namespace {
26 #if defined(USING_V8)
27 v8::Local<v8::Promise::Resolver> NewPromiseResolver() {
28  return v8::Promise::Resolver::New(GetIsolate()->GetCurrentContext())
29  .ToLocalChecked();
30 }
31 
32 v8::Local<v8::Promise> GetPromise(v8::Local<v8::Promise::Resolver> resolver) {
33  return resolver->GetPromise();
34 }
35 #elif defined(USING_JSC)
36 Handle<JSObjectRef> NewPromise(WeakJsPtr<JsObject>* resolve,
37  WeakJsPtr<JsObject>* reject) {
38  auto callback = [&](Callback on_resolve, Callback on_reject) {
39  *resolve = UnsafeJsCast<JsObject>(on_resolve.ToJsValue());
40  *reject = UnsafeJsCast<JsObject>(on_reject.ToJsValue());
41  };
42 
43  JSValueRef ctor =
44  GetMemberRaw(JSContextGetGlobalObject(GetContext()), "Promise");
45  DCHECK_EQ(GetValueType(ctor), proto::ValueType::Function);
46  LocalVar<JsFunction> ctor_obj = UnsafeJsCast<JsFunction>(ctor);
47 
48  LocalVar<JsValue> ret;
49  LocalVar<JsValue> args[] = {
50  CreateStaticFunction("", "", std::move(callback))};
51  CHECK(InvokeConstructor(ctor_obj, 1, args, &ret));
52  return UnsafeJsCast<JsObject>(ret);
53 }
54 #endif
55 } // namespace
56 
57 #ifdef USING_JSC
58 Promise::Promise(bool unused) : promise_(NewPromise(&resolve_, &reject_)) {}
59 #else
60 Promise::Promise(bool unused)
61  : resolver_(NewPromiseResolver()),
62  promise_(GetPromise(resolver_.handle())) {}
63 #endif
64 
67 
68 Promise::Promise(const Promise&) = default;
69 Promise::Promise(Promise&&) = default;
70 Promise& Promise::operator=(const Promise&) = default;
71 Promise& Promise::operator=(Promise&&) = default;
72 
73 bool Promise::TryConvert(Handle<JsValue> value) {
75  return false;
76 
77 #ifdef USING_JSC
78  resolve_ = nullptr;
79  reject_ = nullptr;
80 #else
81  resolver_ = nullptr;
82 #endif
83  promise_ = UnsafeJsCast<JsPromise>(value);
84  return true;
85 }
86 
87 ReturnVal<JsValue> Promise::ToJsValue() const {
88  return promise_.value();
89 }
90 
91 void Promise::Trace(memory::HeapTracer* tracer) const {
92  tracer->Trace(&promise_);
93 #ifdef USING_JSC
94  tracer->Trace(&resolve_);
95  tracer->Trace(&reject_);
96 #else
97  tracer->Trace(&resolver_);
98 #endif
99 }
100 
101 void Promise::ResolveWith(Handle<JsValue> value, bool run_events) {
102  CHECK(CanResolve()) << "Can't reject JavaScript created Promises.";
103 #if defined(USING_V8)
104  (void)resolver_.handle()->Resolve(GetIsolate()->GetCurrentContext(), value);
105  // In V8, Promises are invoked automatically, but *after* executing some
106  // JavaScript. If we resolve it now, the handlers won't be invoked until we
107  // call into JavaScript again, and then only after that JavaScript runs. For
108  // example, if the next JavaScript is a timer, the timer will run first, then
109  // the Promise handlers will be invoked, which is not the correct order.
110  if (run_events)
111  GetIsolate()->RunMicrotasks();
112 #elif defined(USING_JSC)
113  LocalVar<JsValue> except;
114  if (!InvokeMethod(resolve_.handle(), Handle<JsObject>(), 1, &value,
115  &except)) {
116  OnUncaughtException(except, /* in_promise */ false);
117  }
118 #endif
119 }
120 
121 void Promise::RejectWith(const js::JsError& error, bool run_events) {
122  CHECK(CanResolve()) << "Can't reject JavaScript created Promises.";
123 #if defined(USING_V8)
124  (void)resolver_.handle()->Reject(GetIsolate()->GetCurrentContext(),
125  error.error());
126  // See comment in ResolveWith().
127  if (run_events)
128  GetIsolate()->RunMicrotasks();
129 #elif defined(USING_JSC)
130  LocalVar<JsValue> except;
131  LocalVar<JsValue> rooted(error.error());
132  if (!InvokeMethod(reject_.handle(), Handle<JsObject>(), 1, &rooted,
133  &except)) {
134  OnUncaughtException(except, /* in_promise */ false);
135  }
136 #endif
137 }
138 
139 void Promise::Then(std::function<void(Any)> on_resolve,
140  std::function<void(Any)> on_reject) {
141  // Note this will get from the prototype chain too.
142  LocalVar<JsValue> member_val = GetMemberRaw(promise_.handle(), "then");
143  LocalVar<JsFunction> member = UnsafeJsCast<JsFunction>(member_val);
144 
145  LocalVar<JsValue> except;
146  LocalVar<JsFunction> on_resolve_js =
147  CreateStaticFunction("", "", std::move(on_resolve));
148  LocalVar<JsFunction> on_reject_js =
149  CreateStaticFunction("", "", std::move(on_reject));
150  LocalVar<JsValue> arguments[] = {RawToJsValue(on_resolve_js),
151  RawToJsValue(on_reject_js)};
152  CHECK(InvokeMethod(member, promise_.handle(), 2, arguments, &except))
153  << ConvertToString(except);
154 }
155 
156 } // namespace shaka
ReturnVal< JsFunction > CreateStaticFunction(const std::string &target, const std::string &name, Func &&callback)
Definition: any.h:31
Promise & operator=(const Promise &)
bool InvokeMethod(Handle< JsFunction > method, Handle< JsObject > that, int argc, LocalVar< JsValue > *argv, LocalVar< JsValue > *result_or_except)
Definition: js_wrappers.cc:182
void Trace(memory::HeapTracer *tracer) const override
Definition: promise.cc:91
void RejectWith(const js::JsError &error, bool run_events=true)
Definition: promise.cc:121
ReturnVal< JsValue > ToJsValue() const override
Definition: promise.cc:87
ReturnVal< JsValue > RawToJsValue(Handle< T > source)
Definition: js_wrappers.h:405
void ResolveWith(Handle< JsValue > value, bool run_events=true)
Definition: promise.cc:101
void Trace(const Traceable *ptr)
Definition: heap_tracer.cc:43
ReturnVal< JsValue > error() const
Definition: js_error.h:52
proto::ValueType GetValueType(Handle< JsValue > value)
Definition: js_wrappers.cc:329
bool TryConvert(Handle< JsValue > value) override
Definition: promise.cc:73
~Promise() override
Definition: promise.cc:66
void Then(std::function< void(Any)> on_resolve, std::function< void(Any)> on_reject)
Definition: promise.cc:139
std::string ConvertToString(Handle< JsValue > value)
Definition: js_wrappers.cc:203
JSContextRef GetContext()
Definition: jsc_utils.cc:24
void OnUncaughtException(JSValueRef exception, bool in_promise)
Definition: jsc_utils.cc:28
bool InvokeConstructor(Handle< JsFunction > ctor, int argc, LocalVar< JsValue > *argv, LocalVar< JsValue > *result_or_except)
Definition: js_wrappers.cc:165
v8::Isolate * GetIsolate()
Definition: v8_utils.cc:27
ReturnVal< JsValue > GetMemberRaw(Handle< JsObject > object, const std::string &name, LocalVar< JsValue > *exception=nullptr)
Definition: js_wrappers.cc:136