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 #if !defined(_WIN32) && !defined(_WIN64) | 7 #if !defined(_WIN32) && !defined(_WIN64) |
8 #include <unistd.h> // NOLINT | 8 #include <unistd.h> // NOLINT |
9 #endif // !defined(_WIN32) && !defined(_WIN64) | 9 #endif // !defined(_WIN32) && !defined(_WIN64) |
10 | 10 |
11 namespace { | 11 namespace { |
12 | 12 |
13 void ReportUncaughtException(v8::Isolate* isolate, | 13 void ReportUncaughtException(v8::Isolate* isolate, |
14 const v8::TryCatch& try_catch) { | 14 const v8::TryCatch& try_catch) { |
15 CHECK(try_catch.HasCaught()); | 15 CHECK(try_catch.HasCaught()); |
16 v8::HandleScope handle_scope(isolate); | 16 v8::HandleScope handle_scope(isolate); |
17 std::string message = *v8::String::Utf8Value(try_catch.Message()->Get()); | 17 std::string message = *v8::String::Utf8Value(try_catch.Message()->Get()); |
18 int line = try_catch.Message() | 18 int line = try_catch.Message() |
19 ->GetLineNumber(isolate->GetCurrentContext()) | 19 ->GetLineNumber(isolate->GetCurrentContext()) |
20 .FromJust(); | 20 .FromJust(); |
21 std::string source_line = | 21 std::string source_line = |
22 *v8::String::Utf8Value(try_catch.Message() | 22 *v8::String::Utf8Value(try_catch.Message() |
23 ->GetSourceLine(isolate->GetCurrentContext()) | 23 ->GetSourceLine(isolate->GetCurrentContext()) |
24 .ToLocalChecked()); | 24 .ToLocalChecked()); |
25 fprintf(stderr, "Unhandle exception: %s @%s[%d]\n", message.data(), | 25 fprintf(stderr, "Unhandle exception: %s @%s[%d]\n", message.data(), |
26 source_line.data(), line); | 26 source_line.data(), line); |
27 } | 27 } |
28 | 28 |
29 v8::internal::Vector<uint16_t> ToVector(v8::Local<v8::String> str) { | |
30 v8::internal::Vector<uint16_t> buffer = | |
31 v8::internal::Vector<uint16_t>::New(str->Length()); | |
32 str->Write(buffer.start(), 0, str->Length()); | |
33 return buffer; | |
34 } | |
35 | |
36 } // namespace | 29 } // namespace |
37 | 30 |
38 TaskRunner::TaskRunner(IsolateData::SetupGlobalTasks setup_global_tasks, | 31 TaskRunner::TaskRunner(IsolateData::SetupGlobalTasks setup_global_tasks, |
39 bool catch_exceptions, | 32 bool catch_exceptions, |
40 v8::base::Semaphore* ready_semaphore, | 33 v8::base::Semaphore* ready_semaphore, |
41 v8::StartupData* startup_data, | 34 v8::StartupData* startup_data, bool with_inspector) |
42 IsolateData::FrontendChannel* channel) | |
43 : Thread(Options("Task Runner")), | 35 : Thread(Options("Task Runner")), |
44 setup_global_tasks_(std::move(setup_global_tasks)), | 36 setup_global_tasks_(std::move(setup_global_tasks)), |
45 startup_data_(startup_data), | 37 startup_data_(startup_data), |
46 channel_(channel), | 38 with_inspector_(with_inspector), |
47 catch_exceptions_(catch_exceptions), | 39 catch_exceptions_(catch_exceptions), |
48 ready_semaphore_(ready_semaphore), | 40 ready_semaphore_(ready_semaphore), |
49 data_(nullptr), | 41 data_(nullptr), |
50 process_queue_semaphore_(0), | 42 process_queue_semaphore_(0), |
51 nested_loop_count_(0) { | 43 nested_loop_count_(0) { |
52 Start(); | 44 Start(); |
53 } | 45 } |
54 | 46 |
55 TaskRunner::~TaskRunner() { Join(); } | 47 TaskRunner::~TaskRunner() { Join(); } |
56 | 48 |
57 void TaskRunner::Run() { | 49 void TaskRunner::Run() { |
58 data_.reset(new IsolateData(this, std::move(setup_global_tasks_), | 50 data_.reset(new IsolateData(this, std::move(setup_global_tasks_), |
59 startup_data_, channel_)); | 51 startup_data_, with_inspector_)); |
60 if (ready_semaphore_) ready_semaphore_->Signal(); | 52 if (ready_semaphore_) ready_semaphore_->Signal(); |
61 RunMessageLoop(false); | 53 RunMessageLoop(false); |
62 } | 54 } |
63 | 55 |
64 void TaskRunner::RunMessageLoop(bool only_protocol) { | 56 void TaskRunner::RunMessageLoop(bool only_protocol) { |
65 int loop_number = ++nested_loop_count_; | 57 int loop_number = ++nested_loop_count_; |
66 while (nested_loop_count_ == loop_number && !is_terminated_.Value()) { | 58 while (nested_loop_count_ == loop_number && !is_terminated_.Value()) { |
67 TaskRunner::Task* task = GetNext(only_protocol); | 59 TaskRunner::Task* task = GetNext(only_protocol); |
68 if (!task) return; | 60 if (!task) return; |
69 v8::Isolate::Scope isolate_scope(isolate()); | 61 v8::Isolate::Scope isolate_scope(isolate()); |
70 if (catch_exceptions_) { | 62 if (catch_exceptions_) { |
71 v8::TryCatch try_catch(isolate()); | 63 v8::TryCatch try_catch(isolate()); |
72 task->RunOnIsolate(data_.get()); | 64 task->Run(data_.get()); |
73 delete task; | 65 delete task; |
74 if (try_catch.HasCaught()) { | 66 if (try_catch.HasCaught()) { |
75 ReportUncaughtException(isolate(), try_catch); | 67 ReportUncaughtException(isolate(), try_catch); |
76 fflush(stdout); | 68 fflush(stdout); |
77 fflush(stderr); | 69 fflush(stderr); |
78 _exit(0); | 70 _exit(0); |
79 } | 71 } |
80 } else { | 72 } else { |
81 task->RunOnIsolate(data_.get()); | 73 task->Run(data_.get()); |
82 delete task; | 74 delete task; |
83 } | 75 } |
84 } | 76 } |
85 } | 77 } |
86 | 78 |
87 void TaskRunner::QuitMessageLoop() { | 79 void TaskRunner::QuitMessageLoop() { |
88 DCHECK(nested_loop_count_ > 0); | 80 DCHECK(nested_loop_count_ > 0); |
89 --nested_loop_count_; | 81 --nested_loop_count_; |
90 } | 82 } |
91 | 83 |
92 void TaskRunner::Append(Task* task) { | 84 void TaskRunner::Append(Task* task) { |
93 queue_.Enqueue(task); | 85 queue_.Enqueue(task); |
94 process_queue_semaphore_.Signal(); | 86 process_queue_semaphore_.Signal(); |
95 } | 87 } |
96 | 88 |
97 void TaskRunner::Terminate() { | 89 void TaskRunner::Terminate() { |
98 is_terminated_.Increment(1); | 90 is_terminated_.Increment(1); |
99 process_queue_semaphore_.Signal(); | 91 process_queue_semaphore_.Signal(); |
100 } | 92 } |
101 | 93 |
102 TaskRunner::Task* TaskRunner::GetNext(bool only_protocol) { | 94 TaskRunner::Task* TaskRunner::GetNext(bool only_protocol) { |
103 for (;;) { | 95 for (;;) { |
104 if (is_terminated_.Value()) return nullptr; | 96 if (is_terminated_.Value()) return nullptr; |
105 if (only_protocol) { | 97 if (only_protocol) { |
106 Task* task = nullptr; | 98 Task* task = nullptr; |
107 if (queue_.Dequeue(&task)) { | 99 if (queue_.Dequeue(&task)) { |
108 if (task->is_inspector_task()) return task; | 100 if (task->is_priority_task()) return task; |
109 deffered_queue_.Enqueue(task); | 101 deffered_queue_.Enqueue(task); |
110 } | 102 } |
111 } else { | 103 } else { |
112 Task* task = nullptr; | 104 Task* task = nullptr; |
113 if (deffered_queue_.Dequeue(&task)) return task; | 105 if (deffered_queue_.Dequeue(&task)) return task; |
114 if (queue_.Dequeue(&task)) return task; | 106 if (queue_.Dequeue(&task)) return task; |
115 } | 107 } |
116 process_queue_semaphore_.Wait(); | 108 process_queue_semaphore_.Wait(); |
117 } | 109 } |
118 return nullptr; | 110 return nullptr; |
119 } | 111 } |
120 | |
121 AsyncTask::AsyncTask(IsolateData* data, const char* task_name) | |
122 : instrumenting_(data && task_name) { | |
123 if (!instrumenting_) return; | |
124 data->inspector()->asyncTaskScheduled( | |
125 v8_inspector::StringView(reinterpret_cast<const uint8_t*>(task_name), | |
126 strlen(task_name)), | |
127 this, false); | |
128 } | |
129 | |
130 void AsyncTask::Run() { | |
131 if (instrumenting_) data()->inspector()->asyncTaskStarted(this); | |
132 AsyncRun(); | |
133 if (instrumenting_) data()->inspector()->asyncTaskFinished(this); | |
134 } | |
135 | |
136 ExecuteStringTask::ExecuteStringTask( | |
137 IsolateData* data, int context_group_id, const char* task_name, | |
138 const v8::internal::Vector<uint16_t>& expression, | |
139 v8::Local<v8::String> name, v8::Local<v8::Integer> line_offset, | |
140 v8::Local<v8::Integer> column_offset, v8::Local<v8::Boolean> is_module) | |
141 : AsyncTask(data, task_name), | |
142 expression_(expression), | |
143 name_(ToVector(name)), | |
144 line_offset_(line_offset.As<v8::Int32>()->Value()), | |
145 column_offset_(column_offset.As<v8::Int32>()->Value()), | |
146 is_module_(is_module->Value()), | |
147 context_group_id_(context_group_id) {} | |
148 | |
149 ExecuteStringTask::ExecuteStringTask( | |
150 const v8::internal::Vector<const char>& expression, int context_group_id) | |
151 : AsyncTask(nullptr, nullptr), | |
152 expression_utf8_(expression), | |
153 context_group_id_(context_group_id) {} | |
154 | |
155 void ExecuteStringTask::AsyncRun() { | |
156 v8::MicrotasksScope microtasks_scope(isolate(), | |
157 v8::MicrotasksScope::kRunMicrotasks); | |
158 v8::HandleScope handle_scope(isolate()); | |
159 v8::Local<v8::Context> context = data()->GetContext(context_group_id_); | |
160 v8::Context::Scope context_scope(context); | |
161 | |
162 v8::Local<v8::String> name = | |
163 v8::String::NewFromTwoByte(isolate(), name_.start(), | |
164 v8::NewStringType::kNormal, name_.length()) | |
165 .ToLocalChecked(); | |
166 v8::Local<v8::Integer> line_offset = | |
167 v8::Integer::New(isolate(), line_offset_); | |
168 v8::Local<v8::Integer> column_offset = | |
169 v8::Integer::New(isolate(), column_offset_); | |
170 | |
171 v8::ScriptOrigin origin( | |
172 name, line_offset, column_offset, | |
173 /* resource_is_shared_cross_origin */ v8::Local<v8::Boolean>(), | |
174 /* script_id */ v8::Local<v8::Integer>(), | |
175 /* source_map_url */ v8::Local<v8::Value>(), | |
176 /* resource_is_opaque */ v8::Local<v8::Boolean>(), | |
177 /* is_wasm */ v8::Local<v8::Boolean>(), | |
178 v8::Boolean::New(isolate(), is_module_)); | |
179 v8::Local<v8::String> source; | |
180 if (expression_.length()) { | |
181 source = v8::String::NewFromTwoByte(isolate(), expression_.start(), | |
182 v8::NewStringType::kNormal, | |
183 expression_.length()) | |
184 .ToLocalChecked(); | |
185 } else { | |
186 source = v8::String::NewFromUtf8(isolate(), expression_utf8_.start(), | |
187 v8::NewStringType::kNormal, | |
188 expression_utf8_.length()) | |
189 .ToLocalChecked(); | |
190 } | |
191 | |
192 v8::ScriptCompiler::Source scriptSource(source, origin); | |
193 if (!is_module_) { | |
194 v8::Local<v8::Script> script; | |
195 if (!v8::ScriptCompiler::Compile(context, &scriptSource).ToLocal(&script)) | |
196 return; | |
197 v8::MaybeLocal<v8::Value> result; | |
198 result = script->Run(context); | |
199 } else { | |
200 data()->RegisterModule(context, name_, &scriptSource); | |
201 } | |
202 } | |
OLD | NEW |