Shaka Player Embedded
js_engine.cc
Go to the documentation of this file.
1 // Copyright 2016 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 // Derived from:
16 // https://chromium.googlesource.com/v8/v8/+/branch-heads/4.8/samples/hello-world.cc
17 
18 #include "src/mapping/js_engine.h"
19 
20 #include <libplatform/libplatform.h>
21 
22 #include <cstring>
23 
24 namespace shaka {
25 
26 #ifdef V8_EMBEDDED_SNAPSHOT
27 // Defined in generated code by //shaka/tools/embed_v8_snapshot.py
28 void SetupV8Snapshots();
29 #endif
30 
31 namespace {
32 
33 void OnPromiseReject(v8::PromiseRejectMessage message) {
34  JsEngine::Instance()->OnPromiseReject(message);
35 }
36 
37 void InitializeV8IfNeeded() {
38  static v8::Platform* platform = nullptr;
39  if (platform)
40  return;
41 
42  v8::V8::InitializeICU();
43 
44 #ifdef V8_EMBEDDED_SNAPSHOT
45  SetupV8Snapshots();
46 #endif
47 
48  platform = v8::platform::NewDefaultPlatform().release();
49  v8::V8::InitializePlatform(platform);
50  v8::V8::Initialize();
51 }
52 
53 } // namespace
54 
55 // \cond Doxygen_Skip
56 
57 JsEngine::JsEngine() : isolate_(CreateIsolate()), context_(CreateContext()) {}
58 
60  context_.Reset();
61  isolate_->Dispose();
62 }
63 
64 v8::Local<v8::Object> JsEngine::global_handle() {
65  return context_.Get(isolate_)->Global();
66 }
67 
68 v8::Local<v8::Value> JsEngine::global_value() {
69  return context_.Get(isolate_)->Global();
70 }
71 
72 void JsEngine::OnPromiseReject(v8::PromiseRejectMessage message) {
73  // When a Promise gets rejected, we immediately get a
74  // kPromiseRejectWithNoHandler event. Then, once JavaScript adds a rejection
75  // handler, we will get a kPromiseHandlerAddedAfterReject event.
76  if (message.GetEvent() == v8::PromiseRejectEvent::kPromiseRejectWithNoHandler)
77  promise_handler_.AddPromise(message.GetPromise(), message.GetValue());
78  else
79  promise_handler_.RemovePromise(message.GetPromise());
80 }
81 
82 void JsEngine::AddDestructor(void* object,
83  std::function<void(void*)> destruct) {
84  destructors_.emplace(object, destruct);
85 }
86 
88  : locker(Instance()->isolate_),
89  handles(Instance()->isolate_),
90  isolate_scope(Instance()->isolate_),
91  context_scope(Instance()->context_.Get(Instance()->isolate_)) {}
92 
94 
95 void* JsEngine::ArrayBufferAllocator::Allocate(size_t length) {
96  void* data = AllocateUninitialized(length);
97  return !data ? data : std::memset(data, 0, length);
98 }
99 
100 void* JsEngine::ArrayBufferAllocator::AllocateUninitialized(size_t length) {
101  return std::malloc(length); // NOLINT
102 }
103 
104 void JsEngine::ArrayBufferAllocator::Free(void* data, size_t /* length */) {
105  auto* destructors = &Instance()->destructors_;
106  if (destructors->count(data) > 0) {
107  destructors->at(data)(data);
108  destructors->erase(data);
109  }
110  std::free(data); // NOLINT
111 }
112 
113 v8::Isolate* JsEngine::CreateIsolate() {
114  InitializeV8IfNeeded();
115 
116  v8::Isolate::CreateParams create_params;
117  create_params.array_buffer_allocator = &allocator_;
118 
119  v8::Isolate* isolate = v8::Isolate::New(create_params);
120  CHECK(isolate);
121  isolate->SetCaptureStackTraceForUncaughtExceptions(true);
122  isolate->SetPromiseRejectCallback(&::shaka::OnPromiseReject);
123 
124  return isolate;
125 }
126 
127 v8::Global<v8::Context> JsEngine::CreateContext() {
128  v8::Locker locker(isolate_);
129  v8::HandleScope handles(isolate_);
130  v8::Local<v8::Context> context = v8::Context::New(isolate_);
131  return v8::Global<v8::Context>(isolate_, context);
132 }
133 
134 // \endcond Doxygen_Skip
135 
136 } // namespace shaka
Handle< JsObject > global_handle()
void AddPromise(Handle< JsPromise > promise, Handle< JsValue > value)
ReturnVal< JsValue > global_value()
const char * message
void RemovePromise(Handle< JsPromise > promise)