| OLD | NEW |
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 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 | 5 |
| 6 // Defined when linking against shared lib on Windows. | 6 // Defined when linking against shared lib on Windows. |
| 7 #if defined(USING_V8_SHARED) && !defined(V8_SHARED) | 7 #if defined(USING_V8_SHARED) && !defined(V8_SHARED) |
| 8 #define V8_SHARED | 8 #define V8_SHARED |
| 9 #endif | 9 #endif |
| 10 | 10 |
| (...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 198 | 198 |
| 199 #ifndef V8_SHARED | 199 #ifndef V8_SHARED |
| 200 CounterMap* Shell::counter_map_; | 200 CounterMap* Shell::counter_map_; |
| 201 base::OS::MemoryMappedFile* Shell::counters_file_ = NULL; | 201 base::OS::MemoryMappedFile* Shell::counters_file_ = NULL; |
| 202 CounterCollection Shell::local_counters_; | 202 CounterCollection Shell::local_counters_; |
| 203 CounterCollection* Shell::counters_ = &local_counters_; | 203 CounterCollection* Shell::counters_ = &local_counters_; |
| 204 base::Mutex Shell::context_mutex_; | 204 base::Mutex Shell::context_mutex_; |
| 205 const base::TimeTicks Shell::kInitialTicks = | 205 const base::TimeTicks Shell::kInitialTicks = |
| 206 base::TimeTicks::HighResolutionNow(); | 206 base::TimeTicks::HighResolutionNow(); |
| 207 Persistent<Context> Shell::utility_context_; | 207 Persistent<Context> Shell::utility_context_; |
| 208 base::Mutex Shell::workers_mutex_; |
| 209 bool Shell::allow_new_workers_ = true; |
| 208 i::List<Worker*> Shell::workers_; | 210 i::List<Worker*> Shell::workers_; |
| 209 i::List<SharedArrayBuffer::Contents> Shell::externalized_shared_contents_; | 211 i::List<SharedArrayBuffer::Contents> Shell::externalized_shared_contents_; |
| 210 #endif // !V8_SHARED | 212 #endif // !V8_SHARED |
| 211 | 213 |
| 212 Persistent<Context> Shell::evaluation_context_; | 214 Persistent<Context> Shell::evaluation_context_; |
| 213 ArrayBuffer::Allocator* Shell::array_buffer_allocator; | 215 ArrayBuffer::Allocator* Shell::array_buffer_allocator; |
| 214 ShellOptions Shell::options; | 216 ShellOptions Shell::options; |
| 215 const char* Shell::kPrompt = "d8> "; | 217 const char* Shell::kPrompt = "d8> "; |
| 216 | 218 |
| 217 #ifndef V8_SHARED | 219 #ifndef V8_SHARED |
| (...skipping 468 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 686 | 688 |
| 687 #ifndef V8_SHARED | 689 #ifndef V8_SHARED |
| 688 void Shell::WorkerNew(const v8::FunctionCallbackInfo<v8::Value>& args) { | 690 void Shell::WorkerNew(const v8::FunctionCallbackInfo<v8::Value>& args) { |
| 689 Isolate* isolate = args.GetIsolate(); | 691 Isolate* isolate = args.GetIsolate(); |
| 690 HandleScope handle_scope(isolate); | 692 HandleScope handle_scope(isolate); |
| 691 if (args.Length() < 1 || !args[0]->IsFunction()) { | 693 if (args.Length() < 1 || !args[0]->IsFunction()) { |
| 692 Throw(args.GetIsolate(), "1st argument must be function"); | 694 Throw(args.GetIsolate(), "1st argument must be function"); |
| 693 return; | 695 return; |
| 694 } | 696 } |
| 695 | 697 |
| 696 Worker* worker = new Worker; | 698 { |
| 697 args.This()->SetInternalField(0, External::New(isolate, worker)); | 699 base::LockGuard<base::Mutex> lock_guard(&workers_mutex_); |
| 698 workers_.Add(worker); | 700 if (!allow_new_workers_) return; |
| 699 | 701 |
| 700 String::Utf8Value function_string(args[0]->ToString()); | 702 Worker* worker = new Worker; |
| 701 worker->StartExecuteInThread(isolate, *function_string); | 703 args.This()->SetInternalField(0, External::New(isolate, worker)); |
| 704 workers_.Add(worker); |
| 705 |
| 706 String::Utf8Value function_string(args[0]->ToString()); |
| 707 worker->StartExecuteInThread(isolate, *function_string); |
| 708 } |
| 702 } | 709 } |
| 703 | 710 |
| 704 | 711 |
| 705 void Shell::WorkerPostMessage(const v8::FunctionCallbackInfo<v8::Value>& args) { | 712 void Shell::WorkerPostMessage(const v8::FunctionCallbackInfo<v8::Value>& args) { |
| 706 Isolate* isolate = args.GetIsolate(); | 713 Isolate* isolate = args.GetIsolate(); |
| 707 HandleScope handle_scope(isolate); | 714 HandleScope handle_scope(isolate); |
| 708 Local<Context> context = isolate->GetCurrentContext(); | 715 Local<Context> context = isolate->GetCurrentContext(); |
| 709 | 716 |
| 710 if (args.Length() < 1) { | 717 if (args.Length() < 1) { |
| 711 Throw(isolate, "Invalid argument"); | 718 Throw(isolate, "Invalid argument"); |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 786 HandleScope handle_scope(isolate); | 793 HandleScope handle_scope(isolate); |
| 787 Local<Value> this_value = args.This()->GetInternalField(0); | 794 Local<Value> this_value = args.This()->GetInternalField(0); |
| 788 if (!this_value->IsExternal()) { | 795 if (!this_value->IsExternal()) { |
| 789 Throw(isolate, "this is not a Worker"); | 796 Throw(isolate, "this is not a Worker"); |
| 790 return; | 797 return; |
| 791 } | 798 } |
| 792 | 799 |
| 793 Worker* worker = | 800 Worker* worker = |
| 794 static_cast<Worker*>(Local<External>::Cast(this_value)->Value()); | 801 static_cast<Worker*>(Local<External>::Cast(this_value)->Value()); |
| 795 worker->Terminate(); | 802 worker->Terminate(); |
| 796 workers_.RemoveElement(worker); | |
| 797 delete worker; | |
| 798 } | 803 } |
| 799 #endif // !V8_SHARED | 804 #endif // !V8_SHARED |
| 800 | 805 |
| 801 | 806 |
| 802 void Shell::Quit(const v8::FunctionCallbackInfo<v8::Value>& args) { | 807 void Shell::Quit(const v8::FunctionCallbackInfo<v8::Value>& args) { |
| 803 int exit_code = args[0]->Int32Value(); | 808 int exit_code = args[0]->Int32Value(); |
| 804 OnExit(args.GetIsolate()); | 809 OnExit(args.GetIsolate()); |
| 805 exit(exit_code); | 810 exit(exit_code); |
| 806 } | 811 } |
| 807 | 812 |
| (...skipping 805 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1613 void SerializationDataQueue::Clear() { | 1618 void SerializationDataQueue::Clear() { |
| 1614 base::LockGuard<base::Mutex> lock_guard(&mutex_); | 1619 base::LockGuard<base::Mutex> lock_guard(&mutex_); |
| 1615 for (int i = 0; i < data_.length(); ++i) { | 1620 for (int i = 0; i < data_.length(); ++i) { |
| 1616 delete data_[i]; | 1621 delete data_[i]; |
| 1617 } | 1622 } |
| 1618 data_.Clear(); | 1623 data_.Clear(); |
| 1619 } | 1624 } |
| 1620 | 1625 |
| 1621 | 1626 |
| 1622 Worker::Worker() | 1627 Worker::Worker() |
| 1623 : in_semaphore_(0), out_semaphore_(0), thread_(NULL), script_(NULL) {} | 1628 : in_semaphore_(0), |
| 1629 out_semaphore_(0), |
| 1630 thread_(NULL), |
| 1631 script_(NULL), |
| 1632 state_(IDLE) {} |
| 1624 | 1633 |
| 1625 | 1634 |
| 1626 Worker::~Worker() { Cleanup(); } | 1635 Worker::~Worker() { Cleanup(); } |
| 1627 | 1636 |
| 1628 | 1637 |
| 1629 void Worker::StartExecuteInThread(Isolate* isolate, | 1638 void Worker::StartExecuteInThread(Isolate* isolate, |
| 1630 const char* function_string) { | 1639 const char* function_string) { |
| 1631 if (thread_) { | 1640 DCHECK(base::NoBarrier_Load(&state_) == IDLE); |
| 1632 Throw(isolate, "Only one worker allowed"); | |
| 1633 return; | |
| 1634 } | |
| 1635 | |
| 1636 static const char format[] = "(%s).call(this);"; | 1641 static const char format[] = "(%s).call(this);"; |
| 1637 size_t len = strlen(function_string) + sizeof(format); | 1642 size_t len = strlen(function_string) + sizeof(format); |
| 1638 | 1643 |
| 1639 script_ = new char[len + 1]; | 1644 script_ = new char[len + 1]; |
| 1640 i::Vector<char> vec(script_, static_cast<int>(len + 1)); | 1645 i::Vector<char> vec(script_, static_cast<int>(len + 1)); |
| 1641 i::SNPrintF(vec, format, function_string); | 1646 i::SNPrintF(vec, format, function_string); |
| 1642 | 1647 |
| 1648 base::NoBarrier_Store(&state_, RUNNING); |
| 1643 thread_ = new WorkerThread(this); | 1649 thread_ = new WorkerThread(this); |
| 1644 thread_->Start(); | 1650 thread_->Start(); |
| 1645 } | 1651 } |
| 1646 | 1652 |
| 1647 | 1653 |
| 1648 void Worker::PostMessage(SerializationData* data) { | 1654 void Worker::PostMessage(SerializationData* data) { |
| 1649 in_queue_.Enqueue(data); | 1655 in_queue_.Enqueue(data); |
| 1650 in_semaphore_.Signal(); | 1656 in_semaphore_.Signal(); |
| 1651 } | 1657 } |
| 1652 | 1658 |
| 1653 | 1659 |
| 1654 SerializationData* Worker::GetMessage() { | 1660 SerializationData* Worker::GetMessage() { |
| 1655 SerializationData* data; | 1661 SerializationData* data = NULL; |
| 1656 while (!out_queue_.Dequeue(&data)) { | 1662 while (!out_queue_.Dequeue(&data)) { |
| 1663 if (base::NoBarrier_Load(&state_) != RUNNING) break; |
| 1657 out_semaphore_.Wait(); | 1664 out_semaphore_.Wait(); |
| 1658 } | 1665 } |
| 1659 | 1666 |
| 1660 return data; | 1667 return data; |
| 1661 } | 1668 } |
| 1662 | 1669 |
| 1663 | 1670 |
| 1664 void Worker::Terminate() { | 1671 void Worker::Terminate() { |
| 1665 if (thread_ == NULL) return; | 1672 if (base::NoBarrier_CompareAndSwap(&state_, RUNNING, TERMINATED) == RUNNING) { |
| 1666 PostMessage(NULL); | 1673 // Post NULL to wake the Worker thread message loop. |
| 1667 thread_->Join(); | 1674 PostMessage(NULL); |
| 1668 Cleanup(); | 1675 thread_->Join(); |
| 1676 } |
| 1669 } | 1677 } |
| 1670 | 1678 |
| 1671 | 1679 |
| 1672 void Worker::ExecuteInThread() { | 1680 void Worker::ExecuteInThread() { |
| 1673 Isolate::CreateParams create_params; | 1681 Isolate::CreateParams create_params; |
| 1674 create_params.array_buffer_allocator = Shell::array_buffer_allocator; | 1682 create_params.array_buffer_allocator = Shell::array_buffer_allocator; |
| 1675 Isolate* isolate = Isolate::New(create_params); | 1683 Isolate* isolate = Isolate::New(create_params); |
| 1676 { | 1684 { |
| 1677 Isolate::Scope iscope(isolate); | 1685 Isolate::Scope iscope(isolate); |
| 1678 { | 1686 { |
| (...skipping 12 matching lines...) Expand all Loading... |
| 1691 Handle<Function> postmessage_fun; | 1699 Handle<Function> postmessage_fun; |
| 1692 if (postmessage_fun_template->GetFunction(context) | 1700 if (postmessage_fun_template->GetFunction(context) |
| 1693 .ToLocal(&postmessage_fun)) { | 1701 .ToLocal(&postmessage_fun)) { |
| 1694 global->Set(String::NewFromUtf8(isolate, "postMessage"), | 1702 global->Set(String::NewFromUtf8(isolate, "postMessage"), |
| 1695 postmessage_fun); | 1703 postmessage_fun); |
| 1696 } | 1704 } |
| 1697 | 1705 |
| 1698 // First run the script | 1706 // First run the script |
| 1699 Handle<String> file_name = String::NewFromUtf8(isolate, "unnamed"); | 1707 Handle<String> file_name = String::NewFromUtf8(isolate, "unnamed"); |
| 1700 Handle<String> source = String::NewFromUtf8(isolate, script_); | 1708 Handle<String> source = String::NewFromUtf8(isolate, script_); |
| 1701 Shell::ExecuteString(isolate, source, file_name, false, true); | 1709 if (Shell::ExecuteString(isolate, source, file_name, true, true)) { |
| 1702 | 1710 // Get the message handler |
| 1703 // Get the message handler | 1711 Handle<Value> onmessage = |
| 1704 Handle<Value> onmessage = | 1712 global->Get(String::NewFromUtf8(isolate, "onmessage")); |
| 1705 global->Get(String::NewFromUtf8(isolate, "onmessage")); | 1713 if (onmessage->IsFunction()) { |
| 1706 if (onmessage->IsFunction()) { | 1714 Handle<Function> onmessage_fun = Handle<Function>::Cast(onmessage); |
| 1707 Handle<Function> onmessage_fun = Handle<Function>::Cast(onmessage); | 1715 // Now wait for messages |
| 1708 // Now wait for messages | 1716 bool done = false; |
| 1709 bool done = false; | 1717 while (!done) { |
| 1710 while (!done) { | 1718 in_semaphore_.Wait(); |
| 1711 in_semaphore_.Wait(); | 1719 SerializationData* data; |
| 1712 SerializationData* data; | 1720 if (!in_queue_.Dequeue(&data)) continue; |
| 1713 if (!in_queue_.Dequeue(&data)) continue; | 1721 if (data == NULL) { |
| 1714 if (data == NULL) { | 1722 done = true; |
| 1715 done = true; | 1723 break; |
| 1716 break; | 1724 } |
| 1725 int offset = 0; |
| 1726 Local<Value> data_value; |
| 1727 if (Shell::DeserializeValue(isolate, *data, &offset) |
| 1728 .ToLocal(&data_value)) { |
| 1729 Handle<Value> argv[] = {data_value}; |
| 1730 (void)onmessage_fun->Call(context, global, 1, argv); |
| 1731 } |
| 1732 delete data; |
| 1717 } | 1733 } |
| 1718 int offset = 0; | |
| 1719 Local<Value> data_value; | |
| 1720 if (Shell::DeserializeValue(isolate, *data, &offset) | |
| 1721 .ToLocal(&data_value)) { | |
| 1722 Handle<Value> argv[] = {data_value}; | |
| 1723 (void)onmessage_fun->Call(context, global, 1, argv); | |
| 1724 } | |
| 1725 delete data; | |
| 1726 } | 1734 } |
| 1727 } | 1735 } |
| 1728 } | 1736 } |
| 1729 } | 1737 } |
| 1730 Shell::CollectGarbage(isolate); | 1738 Shell::CollectGarbage(isolate); |
| 1731 } | 1739 } |
| 1732 isolate->Dispose(); | 1740 isolate->Dispose(); |
| 1741 |
| 1742 if (base::NoBarrier_CompareAndSwap(&state_, RUNNING, TERMINATED) == RUNNING) { |
| 1743 // Post NULL to wake the thread waiting on GetMessage() if there is one. |
| 1744 out_queue_.Enqueue(NULL); |
| 1745 out_semaphore_.Signal(); |
| 1746 } |
| 1733 } | 1747 } |
| 1734 | 1748 |
| 1735 | 1749 |
| 1736 void Worker::Cleanup() { | 1750 void Worker::Cleanup() { |
| 1737 delete thread_; | 1751 delete thread_; |
| 1738 thread_ = NULL; | 1752 thread_ = NULL; |
| 1739 delete[] script_; | 1753 delete[] script_; |
| 1740 script_ = NULL; | 1754 script_ = NULL; |
| 1741 in_queue_.Clear(); | 1755 in_queue_.Clear(); |
| 1742 out_queue_.Clear(); | 1756 out_queue_.Clear(); |
| (...skipping 442 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2185 } | 2199 } |
| 2186 default: | 2200 default: |
| 2187 UNREACHABLE(); | 2201 UNREACHABLE(); |
| 2188 } | 2202 } |
| 2189 | 2203 |
| 2190 return scope.Escape(result); | 2204 return scope.Escape(result); |
| 2191 } | 2205 } |
| 2192 | 2206 |
| 2193 | 2207 |
| 2194 void Shell::CleanupWorkers() { | 2208 void Shell::CleanupWorkers() { |
| 2195 for (int i = 0; i < workers_.length(); ++i) { | 2209 // Make a copy of workers_, because we don't want to call Worker::Terminate |
| 2196 Worker* worker = workers_[i]; | 2210 // while holding the workers_mutex_ lock. Otherwise, if a worker is about to |
| 2211 // create a new Worker, it would deadlock. |
| 2212 i::List<Worker*> workers_copy; |
| 2213 { |
| 2214 base::LockGuard<base::Mutex> lock_guard(&workers_mutex_); |
| 2215 allow_new_workers_ = false; |
| 2216 workers_copy.AddAll(workers_); |
| 2217 workers_.Clear(); |
| 2218 } |
| 2219 |
| 2220 for (int i = 0; i < workers_copy.length(); ++i) { |
| 2221 Worker* worker = workers_copy[i]; |
| 2197 worker->Terminate(); | 2222 worker->Terminate(); |
| 2198 delete worker; | 2223 delete worker; |
| 2199 } | 2224 } |
| 2200 workers_.Clear(); | 2225 |
| 2226 // Now that all workers are terminated, we can re-enable Worker creation. |
| 2227 { |
| 2228 base::LockGuard<base::Mutex> lock_guard(&workers_mutex_); |
| 2229 allow_new_workers_ = true; |
| 2230 } |
| 2201 | 2231 |
| 2202 for (int i = 0; i < externalized_shared_contents_.length(); ++i) { | 2232 for (int i = 0; i < externalized_shared_contents_.length(); ++i) { |
| 2203 const SharedArrayBuffer::Contents& contents = | 2233 const SharedArrayBuffer::Contents& contents = |
| 2204 externalized_shared_contents_[i]; | 2234 externalized_shared_contents_[i]; |
| 2205 Shell::array_buffer_allocator->Free(contents.Data(), contents.ByteLength()); | 2235 Shell::array_buffer_allocator->Free(contents.Data(), contents.ByteLength()); |
| 2206 } | 2236 } |
| 2207 externalized_shared_contents_.Clear(); | 2237 externalized_shared_contents_.Clear(); |
| 2208 } | 2238 } |
| 2209 | 2239 |
| 2210 | 2240 |
| (...skipping 188 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2399 } | 2429 } |
| 2400 | 2430 |
| 2401 } // namespace v8 | 2431 } // namespace v8 |
| 2402 | 2432 |
| 2403 | 2433 |
| 2404 #ifndef GOOGLE3 | 2434 #ifndef GOOGLE3 |
| 2405 int main(int argc, char* argv[]) { | 2435 int main(int argc, char* argv[]) { |
| 2406 return v8::Shell::Main(argc, argv); | 2436 return v8::Shell::Main(argc, argv); |
| 2407 } | 2437 } |
| 2408 #endif | 2438 #endif |
| OLD | NEW |