| 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 |