OLD | NEW |
1 // Copyright 2016 the V8 project authors. All rights reserved. | 1 // Copyright 2016 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "test/inspector/task-runner.h" | 5 #include "test/inspector/task-runner.h" |
6 | 6 |
7 #include "test/inspector/inspector-impl.h" | 7 #include "test/inspector/inspector-impl.h" |
8 | 8 |
9 #if !defined(_WIN32) && !defined(_WIN64) | 9 #if !defined(_WIN32) && !defined(_WIN64) |
10 #include <unistd.h> // NOLINT | 10 #include <unistd.h> // NOLINT |
11 #endif // !defined(_WIN32) && !defined(_WIN64) | 11 #endif // !defined(_WIN32) && !defined(_WIN64) |
12 | 12 |
13 namespace { | 13 namespace { |
14 | 14 |
15 const int kTaskRunnerIndex = 2; | 15 const int kIsolateDataIndex = 2; |
16 const int kContextGroupIdIndex = 3; | |
17 | 16 |
18 void ReportUncaughtException(v8::Isolate* isolate, | 17 void ReportUncaughtException(v8::Isolate* isolate, |
19 const v8::TryCatch& try_catch) { | 18 const v8::TryCatch& try_catch) { |
20 CHECK(try_catch.HasCaught()); | 19 CHECK(try_catch.HasCaught()); |
21 v8::HandleScope handle_scope(isolate); | 20 v8::HandleScope handle_scope(isolate); |
22 std::string message = *v8::String::Utf8Value(try_catch.Message()->Get()); | 21 std::string message = *v8::String::Utf8Value(try_catch.Message()->Get()); |
23 fprintf(stderr, "Unhandle exception: %s\n", message.data()); | 22 fprintf(stderr, "Unhandle exception: %s\n", message.data()); |
24 } | 23 } |
25 | 24 |
26 v8::internal::Vector<uint16_t> ToVector(v8::Local<v8::String> str) { | 25 v8::internal::Vector<uint16_t> ToVector(v8::Local<v8::String> str) { |
27 v8::internal::Vector<uint16_t> buffer = | 26 v8::internal::Vector<uint16_t> buffer = |
28 v8::internal::Vector<uint16_t>::New(str->Length()); | 27 v8::internal::Vector<uint16_t>::New(str->Length()); |
29 str->Write(buffer.start(), 0, str->Length()); | 28 str->Write(buffer.start(), 0, str->Length()); |
30 return buffer; | 29 return buffer; |
31 } | 30 } |
32 | 31 |
33 } // namespace | 32 } // namespace |
34 | 33 |
35 TaskRunner::TaskRunner(TaskRunner::SetupGlobalTasks setup_global_tasks, | 34 IsolateData::IsolateData(TaskRunner* task_runner, |
| 35 IsolateData::SetupGlobalTasks setup_global_tasks, |
| 36 v8::StartupData* startup_data) |
| 37 : task_runner_(task_runner), |
| 38 setup_global_tasks_(std::move(setup_global_tasks)) { |
| 39 v8::Isolate::CreateParams params; |
| 40 params.array_buffer_allocator = |
| 41 v8::ArrayBuffer::Allocator::NewDefaultAllocator(); |
| 42 params.snapshot_blob = startup_data; |
| 43 isolate_ = v8::Isolate::New(params); |
| 44 isolate_->SetMicrotasksPolicy(v8::MicrotasksPolicy::kScoped); |
| 45 } |
| 46 |
| 47 IsolateData* IsolateData::FromContext(v8::Local<v8::Context> context) { |
| 48 return static_cast<IsolateData*>( |
| 49 context->GetAlignedPointerFromEmbedderData(kIsolateDataIndex)); |
| 50 } |
| 51 |
| 52 int IsolateData::CreateContextGroup() { |
| 53 v8::Local<v8::ObjectTemplate> global_template = |
| 54 v8::ObjectTemplate::New(isolate_); |
| 55 for (auto it = setup_global_tasks_.begin(); it != setup_global_tasks_.end(); |
| 56 ++it) { |
| 57 (*it)->Run(isolate_, global_template); |
| 58 } |
| 59 v8::Local<v8::Context> context = |
| 60 v8::Context::New(isolate_, nullptr, global_template); |
| 61 context->SetAlignedPointerInEmbedderData(kIsolateDataIndex, this); |
| 62 int context_group_id = ++last_context_group_id_; |
| 63 contexts_[context_group_id].Reset(isolate_, context); |
| 64 return context_group_id; |
| 65 } |
| 66 |
| 67 v8::Local<v8::Context> IsolateData::GetContext(int context_group_id) { |
| 68 return contexts_[context_group_id].Get(isolate_); |
| 69 } |
| 70 |
| 71 void IsolateData::RegisterModule(v8::Local<v8::Context> context, |
| 72 v8::internal::Vector<uint16_t> name, |
| 73 v8::ScriptCompiler::Source* source) { |
| 74 v8::Local<v8::Module> module; |
| 75 if (!v8::ScriptCompiler::CompileModule(isolate(), source).ToLocal(&module)) |
| 76 return; |
| 77 if (!module->Instantiate(context, &IsolateData::ModuleResolveCallback)) |
| 78 return; |
| 79 v8::Local<v8::Value> result; |
| 80 if (!module->Evaluate(context).ToLocal(&result)) return; |
| 81 modules_[name] = v8::Global<v8::Module>(isolate_, module); |
| 82 } |
| 83 |
| 84 v8::MaybeLocal<v8::Module> IsolateData::ModuleResolveCallback( |
| 85 v8::Local<v8::Context> context, v8::Local<v8::String> specifier, |
| 86 v8::Local<v8::Module> referrer) { |
| 87 std::string str = *v8::String::Utf8Value(specifier); |
| 88 IsolateData* data = IsolateData::FromContext(context); |
| 89 return data->modules_[ToVector(specifier)].Get(data->isolate_); |
| 90 } |
| 91 |
| 92 TaskRunner::TaskRunner(IsolateData::SetupGlobalTasks setup_global_tasks, |
36 bool catch_exceptions, | 93 bool catch_exceptions, |
37 v8::base::Semaphore* ready_semaphore, | 94 v8::base::Semaphore* ready_semaphore, |
38 v8::StartupData* startup_data) | 95 v8::StartupData* startup_data) |
39 : Thread(Options("Task Runner")), | 96 : Thread(Options("Task Runner")), |
40 setup_global_tasks_(std::move(setup_global_tasks)), | 97 setup_global_tasks_(std::move(setup_global_tasks)), |
41 startup_data_(startup_data), | 98 startup_data_(startup_data), |
42 catch_exceptions_(catch_exceptions), | 99 catch_exceptions_(catch_exceptions), |
43 ready_semaphore_(ready_semaphore), | 100 ready_semaphore_(ready_semaphore), |
44 isolate_(nullptr), | 101 data_(nullptr), |
45 process_queue_semaphore_(0), | 102 process_queue_semaphore_(0), |
46 nested_loop_count_(0) { | 103 nested_loop_count_(0) { |
47 Start(); | 104 Start(); |
48 } | 105 } |
49 | 106 |
50 TaskRunner::~TaskRunner() { Join(); } | 107 TaskRunner::~TaskRunner() { Join(); } |
51 | 108 |
52 void TaskRunner::InitializeIsolate() { | 109 void TaskRunner::Run() { |
53 v8::Isolate::CreateParams params; | 110 data_.reset( |
54 params.array_buffer_allocator = | 111 new IsolateData(this, std::move(setup_global_tasks_), startup_data_)); |
55 v8::ArrayBuffer::Allocator::NewDefaultAllocator(); | 112 |
56 params.snapshot_blob = startup_data_; | 113 v8::Isolate::Scope isolate_scope(isolate()); |
57 isolate_ = v8::Isolate::New(params); | 114 v8::HandleScope handle_scope(isolate()); |
58 isolate_->SetMicrotasksPolicy(v8::MicrotasksPolicy::kScoped); | 115 default_context_group_id_ = data_->CreateContextGroup(); |
59 v8::Isolate::Scope isolate_scope(isolate_); | 116 |
60 v8::HandleScope handle_scope(isolate_); | |
61 NewContextGroup(setup_global_tasks_); | |
62 if (ready_semaphore_) ready_semaphore_->Signal(); | 117 if (ready_semaphore_) ready_semaphore_->Signal(); |
63 } | |
64 | |
65 v8::Local<v8::Context> TaskRunner::NewContextGroup( | |
66 const TaskRunner::SetupGlobalTasks& setup_global_tasks) { | |
67 v8::Local<v8::ObjectTemplate> global_template = | |
68 v8::ObjectTemplate::New(isolate_); | |
69 for (auto it = setup_global_tasks.begin(); it != setup_global_tasks.end(); | |
70 ++it) { | |
71 (*it)->Run(isolate_, global_template); | |
72 } | |
73 v8::Local<v8::Context> context = | |
74 v8::Context::New(isolate_, nullptr, global_template); | |
75 context->SetAlignedPointerInEmbedderData(kTaskRunnerIndex, this); | |
76 intptr_t context_group_id = ++last_context_group_id_; | |
77 // Should be 2-byte aligned. | |
78 context->SetAlignedPointerInEmbedderData( | |
79 kContextGroupIdIndex, reinterpret_cast<void*>(context_group_id * 2)); | |
80 contexts_[context_group_id].Reset(isolate_, context); | |
81 return context; | |
82 } | |
83 | |
84 v8::Local<v8::Context> TaskRunner::GetContext(int context_group_id) { | |
85 return contexts_[context_group_id].Get(isolate_); | |
86 } | |
87 | |
88 int TaskRunner::GetContextGroupId(v8::Local<v8::Context> context) { | |
89 return static_cast<int>( | |
90 reinterpret_cast<intptr_t>( | |
91 context->GetAlignedPointerFromEmbedderData(kContextGroupIdIndex)) / | |
92 2); | |
93 } | |
94 | |
95 void TaskRunner::Run() { | |
96 InitializeIsolate(); | |
97 RunMessageLoop(false); | 118 RunMessageLoop(false); |
98 } | 119 } |
99 | 120 |
100 void TaskRunner::RunMessageLoop(bool only_protocol) { | 121 void TaskRunner::RunMessageLoop(bool only_protocol) { |
101 int loop_number = ++nested_loop_count_; | 122 int loop_number = ++nested_loop_count_; |
102 while (nested_loop_count_ == loop_number && !is_terminated_.Value()) { | 123 while (nested_loop_count_ == loop_number && !is_terminated_.Value()) { |
103 TaskRunner::Task* task = GetNext(only_protocol); | 124 TaskRunner::Task* task = GetNext(only_protocol); |
104 if (!task) return; | 125 if (!task) return; |
105 v8::Isolate::Scope isolate_scope(isolate_); | 126 v8::Isolate::Scope isolate_scope(isolate()); |
106 if (catch_exceptions_) { | 127 if (catch_exceptions_) { |
107 v8::TryCatch try_catch(isolate_); | 128 v8::TryCatch try_catch(isolate()); |
108 task->RunOnTaskRunner(this); | 129 task->RunOnTaskRunner(this); |
109 delete task; | 130 delete task; |
110 if (try_catch.HasCaught()) { | 131 if (try_catch.HasCaught()) { |
111 ReportUncaughtException(isolate_, try_catch); | 132 ReportUncaughtException(isolate(), try_catch); |
112 fflush(stdout); | 133 fflush(stdout); |
113 fflush(stderr); | 134 fflush(stderr); |
114 _exit(0); | 135 _exit(0); |
115 } | 136 } |
116 } else { | 137 } else { |
117 task->RunOnTaskRunner(this); | 138 task->RunOnTaskRunner(this); |
118 delete task; | 139 delete task; |
119 } | 140 } |
120 } | 141 } |
121 } | 142 } |
122 | 143 |
123 void TaskRunner::QuitMessageLoop() { | 144 void TaskRunner::QuitMessageLoop() { |
124 DCHECK(nested_loop_count_ > 0); | 145 DCHECK(nested_loop_count_ > 0); |
125 --nested_loop_count_; | 146 --nested_loop_count_; |
126 } | 147 } |
127 | 148 |
128 void TaskRunner::Append(Task* task) { | 149 void TaskRunner::Append(Task* task) { |
129 queue_.Enqueue(task); | 150 queue_.Enqueue(task); |
130 process_queue_semaphore_.Signal(); | 151 process_queue_semaphore_.Signal(); |
131 } | 152 } |
132 | 153 |
133 void TaskRunner::Terminate() { | 154 void TaskRunner::Terminate() { |
134 is_terminated_.Increment(1); | 155 is_terminated_.Increment(1); |
135 process_queue_semaphore_.Signal(); | 156 process_queue_semaphore_.Signal(); |
136 } | 157 } |
137 | 158 |
138 void TaskRunner::RegisterModule(v8::internal::Vector<uint16_t> name, | |
139 v8::Local<v8::Module> module) { | |
140 modules_[name] = v8::Global<v8::Module>(isolate_, module); | |
141 } | |
142 | |
143 v8::MaybeLocal<v8::Module> TaskRunner::ModuleResolveCallback( | |
144 v8::Local<v8::Context> context, v8::Local<v8::String> specifier, | |
145 v8::Local<v8::Module> referrer) { | |
146 std::string str = *v8::String::Utf8Value(specifier); | |
147 TaskRunner* runner = TaskRunner::FromContext(context); | |
148 return runner->modules_[ToVector(specifier)].Get(runner->isolate_); | |
149 } | |
150 | |
151 TaskRunner::Task* TaskRunner::GetNext(bool only_protocol) { | 159 TaskRunner::Task* TaskRunner::GetNext(bool only_protocol) { |
152 for (;;) { | 160 for (;;) { |
153 if (is_terminated_.Value()) return nullptr; | 161 if (is_terminated_.Value()) return nullptr; |
154 if (only_protocol) { | 162 if (only_protocol) { |
155 Task* task = nullptr; | 163 Task* task = nullptr; |
156 if (queue_.Dequeue(&task)) { | 164 if (queue_.Dequeue(&task)) { |
157 if (task->is_inspector_task()) return task; | 165 if (task->is_inspector_task()) return task; |
158 deffered_queue_.Enqueue(task); | 166 deffered_queue_.Enqueue(task); |
159 } | 167 } |
160 } else { | 168 } else { |
161 Task* task = nullptr; | 169 Task* task = nullptr; |
162 if (deffered_queue_.Dequeue(&task)) return task; | 170 if (deffered_queue_.Dequeue(&task)) return task; |
163 if (queue_.Dequeue(&task)) return task; | 171 if (queue_.Dequeue(&task)) return task; |
164 } | 172 } |
165 process_queue_semaphore_.Wait(); | 173 process_queue_semaphore_.Wait(); |
166 } | 174 } |
167 return nullptr; | 175 return nullptr; |
168 } | 176 } |
169 | 177 |
170 TaskRunner* TaskRunner::FromContext(v8::Local<v8::Context> context) { | |
171 return static_cast<TaskRunner*>( | |
172 context->GetAlignedPointerFromEmbedderData(kTaskRunnerIndex)); | |
173 } | |
174 | |
175 AsyncTask::AsyncTask(const char* task_name, | 178 AsyncTask::AsyncTask(const char* task_name, |
176 v8_inspector::V8Inspector* inspector) | 179 v8_inspector::V8Inspector* inspector) |
177 : inspector_(task_name ? inspector : nullptr) { | 180 : inspector_(task_name ? inspector : nullptr) { |
178 if (inspector_) { | 181 if (inspector_) { |
179 inspector_->asyncTaskScheduled( | 182 inspector_->asyncTaskScheduled( |
180 v8_inspector::StringView(reinterpret_cast<const uint8_t*>(task_name), | 183 v8_inspector::StringView(reinterpret_cast<const uint8_t*>(task_name), |
181 strlen(task_name)), | 184 strlen(task_name)), |
182 this, false); | 185 this, false); |
183 } | 186 } |
184 } | 187 } |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
243 } | 246 } |
244 | 247 |
245 v8::ScriptCompiler::Source scriptSource(source, origin); | 248 v8::ScriptCompiler::Source scriptSource(source, origin); |
246 if (!is_module_) { | 249 if (!is_module_) { |
247 v8::Local<v8::Script> script; | 250 v8::Local<v8::Script> script; |
248 if (!v8::ScriptCompiler::Compile(context, &scriptSource).ToLocal(&script)) | 251 if (!v8::ScriptCompiler::Compile(context, &scriptSource).ToLocal(&script)) |
249 return; | 252 return; |
250 v8::MaybeLocal<v8::Value> result; | 253 v8::MaybeLocal<v8::Value> result; |
251 result = script->Run(context); | 254 result = script->Run(context); |
252 } else { | 255 } else { |
253 v8::Local<v8::Module> module; | 256 IsolateData::FromContext(context)->RegisterModule(context, name_, |
254 if (!v8::ScriptCompiler::CompileModule(isolate(), &scriptSource) | 257 &scriptSource); |
255 .ToLocal(&module)) { | |
256 return; | |
257 } | |
258 if (!module->Instantiate(context, &TaskRunner::ModuleResolveCallback)) | |
259 return; | |
260 v8::Local<v8::Value> result; | |
261 if (!module->Evaluate(context).ToLocal(&result)) return; | |
262 TaskRunner* runner = TaskRunner::FromContext(context); | |
263 runner->RegisterModule(name_, module); | |
264 } | 258 } |
265 } | 259 } |
OLD | NEW |