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 |