Chromium Code Reviews| Index: src/d8.cc |
| diff --git a/src/d8.cc b/src/d8.cc |
| index c46df53851a5fef9e39d1b02c829d8d7073a4308..e025826042f0ccf5e9482c5f2560a01bcf873952 100644 |
| --- a/src/d8.cc |
| +++ b/src/d8.cc |
| @@ -145,6 +145,7 @@ class PerIsolateData { |
| int realm_switch_; |
| Persistent<Context>* realms_; |
| Persistent<Value> realm_shared_; |
| + ArrayBuffer::Allocator* array_buffer_allocator_; |
| int RealmIndexOrThrow(const v8::FunctionCallbackInfo<v8::Value>& args, |
| int arg_offset); |
| @@ -191,6 +192,8 @@ base::Mutex Shell::context_mutex_; |
| const base::TimeTicks Shell::kInitialTicks = |
| base::TimeTicks::HighResolutionNow(); |
| Persistent<Context> Shell::utility_context_; |
| +Worker Shell::worker_; |
| +i::List<v8::SharedArrayBuffer::Contents> Shell::externalized_shared_contents_; |
| #endif // !V8_SHARED |
| Persistent<Context> Shell::evaluation_context_; |
| @@ -661,6 +664,39 @@ void Shell::Load(const v8::FunctionCallbackInfo<v8::Value>& args) { |
| } |
| +#ifndef V8_SHARED |
| +void Shell::WorkerNew(const v8::FunctionCallbackInfo<v8::Value>& args) { |
| + Isolate* isolate = args.GetIsolate(); |
| + HandleScope handle_scope(isolate); |
| + if (args.Length() < 1 || !args[0]->IsFunction()) { |
| + Throw(args.GetIsolate(), "1st argument must be function"); |
| + return; |
| + } |
| + if (args.Length() >= 2 && !args[1]->IsSharedArrayBuffer()) { |
| + Throw(args.GetIsolate(), "2nd argument must be SharedArrayBuffer"); |
| + return; |
| + } |
| + |
| + String::Utf8Value function_string(args[0]->ToString()); |
| + v8::SharedArrayBuffer::Contents contents; |
| + if (args.Length() >= 2) { |
| + Handle<SharedArrayBuffer> sab = Handle<SharedArrayBuffer>::Cast(args[1]); |
| + contents = sab->Externalize(); |
| + externalized_shared_contents_.Add(contents); |
| + } |
| + worker_.StartExecuteInThread(isolate, *function_string, contents); |
| +} |
| + |
| + |
| +void Shell::WorkerJoin(const v8::FunctionCallbackInfo<v8::Value>& args) { |
| + Isolate* isolate = args.GetIsolate(); |
| + HandleScope handle_scope(isolate); |
| + Handle<Value> result = worker_.WaitForThread(isolate); |
| + args.GetReturnValue().Set(result); |
| +} |
| +#endif // !V8_SHARED |
| + |
| + |
| void Shell::Quit(const v8::FunctionCallbackInfo<v8::Value>& args) { |
| int exit_code = args[0]->Int32Value(); |
| OnExit(args.GetIsolate()); |
| @@ -992,6 +1028,13 @@ Handle<ObjectTemplate> Shell::CreateGlobalTemplate(Isolate* isolate) { |
| FunctionTemplate::New(isolate, PerformanceNow)); |
| global_template->Set(String::NewFromUtf8(isolate, "performance"), |
| performance_template); |
| + |
| + Handle<ObjectTemplate> worker_template = ObjectTemplate::New(isolate); |
| + worker_template->Set(String::NewFromUtf8(isolate, "new"), |
| + FunctionTemplate::New(isolate, WorkerNew)); |
| + worker_template->Set(String::NewFromUtf8(isolate, "join"), |
| + FunctionTemplate::New(isolate, WorkerJoin)); |
| + global_template->Set(String::NewFromUtf8(isolate, "Worker"), worker_template); |
| #endif // !V8_SHARED |
| Handle<ObjectTemplate> os_templ = ObjectTemplate::New(isolate); |
| @@ -1369,6 +1412,117 @@ void SourceGroup::WaitForThread() { |
| done_semaphore_.Wait(); |
| } |
| } |
| + |
| + |
| +Worker::Worker() : thread_(NULL), script_(NULL), result_json_(NULL) {} |
| + |
| + |
| +Worker::~Worker() { Cleanup(); } |
| + |
| + |
| +void Worker::StartExecuteInThread( |
| + Isolate* isolate, const char* function_string, |
| + const v8::SharedArrayBuffer::Contents& contents) { |
| + if (thread_) { |
| + Throw(isolate, "Only one worker allowed"); |
| + return; |
| + } |
| + |
| + static const char format[] = "JSON.stringify((%s).call(this, sab));"; |
|
binji
2015/06/15 19:11:48
Better way to do this?
|
| + size_t len = strlen(function_string) + sizeof(format); |
| + |
| + script_ = new char[len + 1]; |
| + snprintf(script_, len, format, function_string); |
| + script_[len] = 0; |
| + |
| + contents_ = contents; |
| + |
| + thread_ = new WorkerThread(this); |
| + thread_->Start(); |
| +} |
| + |
| + |
| +Handle<Value> Worker::WaitForThread(Isolate* isolate) { |
| + EscapableHandleScope handle_scope(isolate); |
| + Handle<Value> result; |
| + |
| + if (thread_ == NULL) return result; |
| + thread_->Join(); |
| + |
| + if (result_json_) { |
| + Local<String> result_json = String::NewFromUtf8(isolate, result_json_); |
| + MaybeLocal<Value> maybe_result = JSON::Parse(isolate, result_json); |
| + if (!maybe_result.IsEmpty()) { |
| + result = maybe_result.ToLocalChecked(); |
| + } |
| + } |
| + |
| + Cleanup(); |
| + return handle_scope.Escape(Local<Value>::Cast(result)); |
| +} |
| + |
| + |
| +void Worker::ExecuteInThread() { |
|
binji
2015/06/15 19:11:48
A lot of this function is copy/paste from other pl
|
| + ShellArrayBufferAllocator allocator; |
| + Isolate::CreateParams create_params; |
| + create_params.array_buffer_allocator = &allocator; |
| + Isolate* isolate = Isolate::New(create_params); |
| + { |
| + Isolate::Scope iscope(isolate); |
| + { |
| + HandleScope scope(isolate); |
| + PerIsolateData data(isolate); |
| + Local<Context> context = Shell::CreateEvaluationContext(isolate); |
| + { |
| + Context::Scope cscope(context); |
| + PerIsolateData::RealmScope realm_scope(PerIsolateData::Get(isolate)); |
| + |
| + Handle<String> sab_name = String::NewFromUtf8(isolate, "sab"); |
| + if (contents_.Data()) { |
| + Handle<v8::SharedArrayBuffer> sab = v8::SharedArrayBuffer::New( |
| + isolate, contents_.Data(), contents_.ByteLength()); |
| + context->Global()->Set(sab_name, sab); |
| + } else { |
| + context->Global()->Set(sab_name, v8::Undefined(isolate)); |
| + } |
| + |
| + Handle<String> file_name = String::NewFromUtf8(isolate, "unnamed"); |
| + Handle<String> source = String::NewFromUtf8(isolate, script_); |
| + |
| + TryCatch try_catch(isolate); |
| + Handle<Script> script = |
| + Shell::CompileString(isolate, source, file_name, |
| + Shell::options.compile_options, Shell::SCRIPT); |
| + result_json_ = NULL; |
| + if (script.IsEmpty()) { |
| + // Print errors that happened during compilation. |
| + // TODO(binji): support debugger? |
| + Shell::ReportException(isolate, &try_catch); |
| + } else { |
| + Handle<Value> result = script->Run(); |
| + if (result->IsString()) { |
| + Handle<String> str_result = Handle<String>::Cast(result); |
| + v8::String::Utf8Value str(str_result); |
| + result_json_ = new char[str.length() + 1]; |
| + memcpy(result_json_, *str, str.length() + 1); |
| + } |
| + } |
| + } |
| + } |
| + } |
| + Shell::CollectGarbage(isolate); |
| + isolate->Dispose(); |
| +} |
| + |
| + |
| +void Worker::Cleanup() { |
| + delete thread_; |
| + thread_ = NULL; |
| + delete[] script_; |
| + script_ = NULL; |
| + delete[] result_json_; |
| + result_json_ = NULL; |
| +} |
| #endif // !V8_SHARED |
| @@ -1543,6 +1697,7 @@ int Shell::RunMain(Isolate* isolate, int argc, char* argv[]) { |
| for (int i = 1; i < options.num_isolates; ++i) { |
| options.isolate_sources[i].WaitForThread(); |
| } |
| + CleanupWorker(isolate); |
| #endif // !V8_SHARED |
| return 0; |
| } |
| @@ -1565,6 +1720,22 @@ void Shell::CollectGarbage(Isolate* isolate) { |
| #ifndef V8_SHARED |
| +void Shell::CleanupWorker(Isolate* isolate) { |
| + { |
| + HandleScope scope(isolate); |
| + worker_.WaitForThread(isolate); |
| + } |
| + PerIsolateData* data = PerIsolateData::Get(isolate); |
| + |
| + for (int i = 0; i < externalized_shared_contents_.length(); ++i) { |
| + const v8::SharedArrayBuffer::Contents& contents = |
| + externalized_shared_contents_[i]; |
| + data->array_buffer_allocator_->Free(contents.Data(), contents.ByteLength()); |
| + } |
| + externalized_shared_contents_.Clear(); |
| +} |
| + |
| + |
| static void DumpHeapConstants(i::Isolate* isolate) { |
| i::Heap* heap = isolate->heap(); |
| @@ -1684,6 +1855,7 @@ int Shell::Main(int argc, char* argv[]) { |
| Isolate::Scope scope(isolate); |
| Initialize(isolate); |
| PerIsolateData data(isolate); |
| + data.array_buffer_allocator_ = create_params.array_buffer_allocator; |
| InitializeDebugger(isolate); |
| #ifndef V8_SHARED |