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 28 matching lines...) Expand all Loading... |
39 #ifndef V8_SHARED | 39 #ifndef V8_SHARED |
40 #include "src/api.h" | 40 #include "src/api.h" |
41 #include "src/base/cpu.h" | 41 #include "src/base/cpu.h" |
42 #include "src/base/logging.h" | 42 #include "src/base/logging.h" |
43 #include "src/base/platform/platform.h" | 43 #include "src/base/platform/platform.h" |
44 #include "src/base/sys-info.h" | 44 #include "src/base/sys-info.h" |
45 #include "src/basic-block-profiler.h" | 45 #include "src/basic-block-profiler.h" |
46 #include "src/d8-debug.h" | 46 #include "src/d8-debug.h" |
47 #include "src/debug.h" | 47 #include "src/debug.h" |
48 #include "src/snapshot/natives.h" | 48 #include "src/snapshot/natives.h" |
49 #include "src/utils.h" | |
50 #include "src/v8.h" | 49 #include "src/v8.h" |
51 #endif // !V8_SHARED | 50 #endif // !V8_SHARED |
52 | 51 |
53 #ifdef V8_USE_EXTERNAL_STARTUP_DATA | 52 #ifdef V8_USE_EXTERNAL_STARTUP_DATA |
54 #include "src/startup-data-util.h" | 53 #include "src/startup-data-util.h" |
55 #endif // V8_USE_EXTERNAL_STARTUP_DATA | 54 #endif // V8_USE_EXTERNAL_STARTUP_DATA |
56 | 55 |
57 #if !defined(_WIN32) && !defined(_WIN64) | 56 #if !defined(_WIN32) && !defined(_WIN64) |
58 #include <unistd.h> // NOLINT | 57 #include <unistd.h> // NOLINT |
59 #else | 58 #else |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
98 } | 97 } |
99 void* AllocateUninitialized(size_t length) override { | 98 void* AllocateUninitialized(size_t length) override { |
100 return length > 10 * MB ? malloc(1) : malloc(length); | 99 return length > 10 * MB ? malloc(1) : malloc(length); |
101 } | 100 } |
102 void Free(void* p, size_t) override { free(p); } | 101 void Free(void* p, size_t) override { free(p); } |
103 }; | 102 }; |
104 | 103 |
105 | 104 |
106 v8::Platform* g_platform = NULL; | 105 v8::Platform* g_platform = NULL; |
107 | 106 |
108 | |
109 #ifndef V8_SHARED | |
110 bool FindInObjectList(Handle<Object> object, const Shell::ObjectList& list) { | |
111 for (int i = 0; i < list.length(); ++i) { | |
112 if (list[i]->StrictEquals(object)) { | |
113 return true; | |
114 } | |
115 } | |
116 return false; | |
117 } | |
118 #endif // !V8_SHARED | |
119 | |
120 | |
121 } // namespace | 107 } // namespace |
122 | 108 |
123 | 109 |
124 static Handle<Value> Throw(Isolate* isolate, const char* message) { | 110 static Handle<Value> Throw(Isolate* isolate, const char* message) { |
125 return isolate->ThrowException(String::NewFromUtf8(isolate, message)); | 111 return isolate->ThrowException(String::NewFromUtf8(isolate, message)); |
126 } | 112 } |
127 | 113 |
128 | 114 |
129 | 115 |
130 class PerIsolateData { | 116 class PerIsolateData { |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
198 | 184 |
199 #ifndef V8_SHARED | 185 #ifndef V8_SHARED |
200 CounterMap* Shell::counter_map_; | 186 CounterMap* Shell::counter_map_; |
201 base::OS::MemoryMappedFile* Shell::counters_file_ = NULL; | 187 base::OS::MemoryMappedFile* Shell::counters_file_ = NULL; |
202 CounterCollection Shell::local_counters_; | 188 CounterCollection Shell::local_counters_; |
203 CounterCollection* Shell::counters_ = &local_counters_; | 189 CounterCollection* Shell::counters_ = &local_counters_; |
204 base::Mutex Shell::context_mutex_; | 190 base::Mutex Shell::context_mutex_; |
205 const base::TimeTicks Shell::kInitialTicks = | 191 const base::TimeTicks Shell::kInitialTicks = |
206 base::TimeTicks::HighResolutionNow(); | 192 base::TimeTicks::HighResolutionNow(); |
207 Persistent<Context> Shell::utility_context_; | 193 Persistent<Context> Shell::utility_context_; |
208 Worker Shell::worker_; | |
209 i::List<SharedArrayBuffer::Contents> Shell::externalized_shared_contents_; | |
210 #endif // !V8_SHARED | 194 #endif // !V8_SHARED |
211 | 195 |
212 Persistent<Context> Shell::evaluation_context_; | 196 Persistent<Context> Shell::evaluation_context_; |
213 ArrayBuffer::Allocator* Shell::array_buffer_allocator; | |
214 ShellOptions Shell::options; | 197 ShellOptions Shell::options; |
215 const char* Shell::kPrompt = "d8> "; | 198 const char* Shell::kPrompt = "d8> "; |
216 | 199 |
217 #ifndef V8_SHARED | 200 #ifndef V8_SHARED |
218 bool CounterMap::Match(void* key1, void* key2) { | 201 bool CounterMap::Match(void* key1, void* key2) { |
219 const char* name1 = reinterpret_cast<const char*>(key1); | 202 const char* name1 = reinterpret_cast<const char*>(key1); |
220 const char* name2 = reinterpret_cast<const char*>(key2); | 203 const char* name2 = reinterpret_cast<const char*>(key2); |
221 return strcmp(name1, name2) == 0; | 204 return strcmp(name1, name2) == 0; |
222 } | 205 } |
223 #endif // !V8_SHARED | 206 #endif // !V8_SHARED |
(...skipping 12 matching lines...) Expand all Loading... |
236 uint16_t* source_buffer = new uint16_t[source_length]; | 219 uint16_t* source_buffer = new uint16_t[source_length]; |
237 source->Write(source_buffer, 0, source_length); | 220 source->Write(source_buffer, 0, source_length); |
238 int name_length = 0; | 221 int name_length = 0; |
239 uint16_t* name_buffer = NULL; | 222 uint16_t* name_buffer = NULL; |
240 if (name->IsString()) { | 223 if (name->IsString()) { |
241 Local<String> name_string = Local<String>::Cast(name); | 224 Local<String> name_string = Local<String>::Cast(name); |
242 name_length = name_string->Length(); | 225 name_length = name_string->Length(); |
243 name_buffer = new uint16_t[name_length]; | 226 name_buffer = new uint16_t[name_length]; |
244 name_string->Write(name_buffer, 0, name_length); | 227 name_string->Write(name_buffer, 0, name_length); |
245 } | 228 } |
| 229 ShellArrayBufferAllocator allocator; |
246 Isolate::CreateParams create_params; | 230 Isolate::CreateParams create_params; |
247 create_params.array_buffer_allocator = Shell::array_buffer_allocator; | 231 create_params.array_buffer_allocator = &allocator; |
248 Isolate* temp_isolate = Isolate::New(create_params); | 232 Isolate* temp_isolate = Isolate::New(create_params); |
249 ScriptCompiler::CachedData* result = NULL; | 233 ScriptCompiler::CachedData* result = NULL; |
250 { | 234 { |
251 Isolate::Scope isolate_scope(temp_isolate); | 235 Isolate::Scope isolate_scope(temp_isolate); |
252 HandleScope handle_scope(temp_isolate); | 236 HandleScope handle_scope(temp_isolate); |
253 Context::Scope context_scope(Context::New(temp_isolate)); | 237 Context::Scope context_scope(Context::New(temp_isolate)); |
254 Local<String> source_copy = v8::String::NewFromTwoByte( | 238 Local<String> source_copy = v8::String::NewFromTwoByte( |
255 temp_isolate, source_buffer, v8::String::kNormalString, source_length); | 239 temp_isolate, source_buffer, v8::String::kNormalString, source_length); |
256 Local<Value> name_copy; | 240 Local<Value> name_copy; |
257 if (name_buffer) { | 241 if (name_buffer) { |
(...skipping 412 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
670 String::NewFromUtf8(args.GetIsolate(), *file), | 654 String::NewFromUtf8(args.GetIsolate(), *file), |
671 false, | 655 false, |
672 true)) { | 656 true)) { |
673 Throw(args.GetIsolate(), "Error executing file"); | 657 Throw(args.GetIsolate(), "Error executing file"); |
674 return; | 658 return; |
675 } | 659 } |
676 } | 660 } |
677 } | 661 } |
678 | 662 |
679 | 663 |
680 #ifndef V8_SHARED | |
681 void Shell::WorkerNew(const v8::FunctionCallbackInfo<v8::Value>& args) { | |
682 Isolate* isolate = args.GetIsolate(); | |
683 HandleScope handle_scope(isolate); | |
684 if (args.Length() < 1 || !args[0]->IsFunction()) { | |
685 Throw(args.GetIsolate(), "1st argument must be function"); | |
686 return; | |
687 } | |
688 | |
689 String::Utf8Value function_string(args[0]->ToString()); | |
690 worker_.StartExecuteInThread(isolate, *function_string); | |
691 } | |
692 | |
693 | |
694 void Shell::WorkerPostMessage(const v8::FunctionCallbackInfo<v8::Value>& args) { | |
695 Isolate* isolate = args.GetIsolate(); | |
696 HandleScope handle_scope(isolate); | |
697 Local<Context> context = isolate->GetCurrentContext(); | |
698 | |
699 if (args.Length() < 1) { | |
700 Throw(isolate, "Invalid argument"); | |
701 return; | |
702 } | |
703 | |
704 Handle<Value> message = args[0]; | |
705 ObjectList to_transfer; | |
706 if (args.Length() >= 2) { | |
707 if (!args[1]->IsArray()) { | |
708 Throw(isolate, "Transfer list must be an Array"); | |
709 return; | |
710 } | |
711 | |
712 Handle<Array> transfer = Handle<Array>::Cast(args[1]); | |
713 uint32_t length = transfer->Length(); | |
714 for (uint32_t i = 0; i < length; ++i) { | |
715 Handle<Value> element; | |
716 if (transfer->Get(context, i).ToLocal(&element)) { | |
717 if (!element->IsArrayBuffer() && !element->IsSharedArrayBuffer()) { | |
718 Throw(isolate, | |
719 "Transfer array elements must be an ArrayBuffer or " | |
720 "SharedArrayBuffer."); | |
721 break; | |
722 } | |
723 | |
724 to_transfer.Add(Handle<Object>::Cast(element)); | |
725 } | |
726 } | |
727 } | |
728 | |
729 ObjectList seen_objects; | |
730 SerializationData* data = new SerializationData; | |
731 if (SerializeValue(isolate, message, to_transfer, &seen_objects, data)) { | |
732 worker_.PostMessage(data); | |
733 } else { | |
734 delete data; | |
735 } | |
736 } | |
737 | |
738 | |
739 void Shell::WorkerGetMessage(const v8::FunctionCallbackInfo<v8::Value>& args) { | |
740 Isolate* isolate = args.GetIsolate(); | |
741 HandleScope handle_scope(isolate); | |
742 SerializationData* data = worker_.GetMessage(); | |
743 if (data) { | |
744 int offset = 0; | |
745 Local<Value> data_value; | |
746 if (Shell::DeserializeValue(isolate, *data, &offset).ToLocal(&data_value)) { | |
747 args.GetReturnValue().Set(data_value); | |
748 } | |
749 delete data; | |
750 } | |
751 } | |
752 | |
753 | |
754 void Shell::WorkerTerminate(const v8::FunctionCallbackInfo<v8::Value>& args) { | |
755 worker_.Terminate(); | |
756 } | |
757 #endif // !V8_SHARED | |
758 | |
759 | |
760 void Shell::Quit(const v8::FunctionCallbackInfo<v8::Value>& args) { | 664 void Shell::Quit(const v8::FunctionCallbackInfo<v8::Value>& args) { |
761 int exit_code = args[0]->Int32Value(); | 665 int exit_code = args[0]->Int32Value(); |
762 OnExit(args.GetIsolate()); | 666 OnExit(args.GetIsolate()); |
763 exit(exit_code); | 667 exit(exit_code); |
764 } | 668 } |
765 | 669 |
766 | 670 |
767 void Shell::Version(const v8::FunctionCallbackInfo<v8::Value>& args) { | 671 void Shell::Version(const v8::FunctionCallbackInfo<v8::Value>& args) { |
768 args.GetReturnValue().Set( | 672 args.GetReturnValue().Set( |
769 String::NewFromUtf8(args.GetIsolate(), V8::GetVersion())); | 673 String::NewFromUtf8(args.GetIsolate(), V8::GetVersion())); |
(...skipping 311 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1081 realm_template->SetAccessor(String::NewFromUtf8(isolate, "shared"), | 985 realm_template->SetAccessor(String::NewFromUtf8(isolate, "shared"), |
1082 RealmSharedGet, RealmSharedSet); | 986 RealmSharedGet, RealmSharedSet); |
1083 global_template->Set(String::NewFromUtf8(isolate, "Realm"), realm_template); | 987 global_template->Set(String::NewFromUtf8(isolate, "Realm"), realm_template); |
1084 | 988 |
1085 #ifndef V8_SHARED | 989 #ifndef V8_SHARED |
1086 Handle<ObjectTemplate> performance_template = ObjectTemplate::New(isolate); | 990 Handle<ObjectTemplate> performance_template = ObjectTemplate::New(isolate); |
1087 performance_template->Set(String::NewFromUtf8(isolate, "now"), | 991 performance_template->Set(String::NewFromUtf8(isolate, "now"), |
1088 FunctionTemplate::New(isolate, PerformanceNow)); | 992 FunctionTemplate::New(isolate, PerformanceNow)); |
1089 global_template->Set(String::NewFromUtf8(isolate, "performance"), | 993 global_template->Set(String::NewFromUtf8(isolate, "performance"), |
1090 performance_template); | 994 performance_template); |
1091 | |
1092 Handle<FunctionTemplate> worker_fun_template = | |
1093 FunctionTemplate::New(isolate, WorkerNew); | |
1094 worker_fun_template->PrototypeTemplate()->Set( | |
1095 String::NewFromUtf8(isolate, "terminate"), | |
1096 FunctionTemplate::New(isolate, WorkerTerminate)); | |
1097 worker_fun_template->PrototypeTemplate()->Set( | |
1098 String::NewFromUtf8(isolate, "postMessage"), | |
1099 FunctionTemplate::New(isolate, WorkerPostMessage)); | |
1100 worker_fun_template->PrototypeTemplate()->Set( | |
1101 String::NewFromUtf8(isolate, "getMessage"), | |
1102 FunctionTemplate::New(isolate, WorkerGetMessage)); | |
1103 global_template->Set(String::NewFromUtf8(isolate, "Worker"), | |
1104 worker_fun_template); | |
1105 #endif // !V8_SHARED | 995 #endif // !V8_SHARED |
1106 | 996 |
1107 Handle<ObjectTemplate> os_templ = ObjectTemplate::New(isolate); | 997 Handle<ObjectTemplate> os_templ = ObjectTemplate::New(isolate); |
1108 AddOSMethods(isolate, os_templ); | 998 AddOSMethods(isolate, os_templ); |
1109 global_template->Set(String::NewFromUtf8(isolate, "os"), os_templ); | 999 global_template->Set(String::NewFromUtf8(isolate, "os"), os_templ); |
1110 | 1000 |
1111 return global_template; | 1001 return global_template; |
1112 } | 1002 } |
1113 | 1003 |
1114 | 1004 |
(...skipping 313 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1428 base::Thread::Options SourceGroup::GetThreadOptions() { | 1318 base::Thread::Options SourceGroup::GetThreadOptions() { |
1429 // On some systems (OSX 10.6) the stack size default is 0.5Mb or less | 1319 // On some systems (OSX 10.6) the stack size default is 0.5Mb or less |
1430 // which is not enough to parse the big literal expressions used in tests. | 1320 // which is not enough to parse the big literal expressions used in tests. |
1431 // The stack size should be at least StackGuard::kLimitSize + some | 1321 // The stack size should be at least StackGuard::kLimitSize + some |
1432 // OS-specific padding for thread startup code. 2Mbytes seems to be enough. | 1322 // OS-specific padding for thread startup code. 2Mbytes seems to be enough. |
1433 return base::Thread::Options("IsolateThread", 2 * MB); | 1323 return base::Thread::Options("IsolateThread", 2 * MB); |
1434 } | 1324 } |
1435 | 1325 |
1436 | 1326 |
1437 void SourceGroup::ExecuteInThread() { | 1327 void SourceGroup::ExecuteInThread() { |
| 1328 ShellArrayBufferAllocator allocator; |
1438 Isolate::CreateParams create_params; | 1329 Isolate::CreateParams create_params; |
1439 create_params.array_buffer_allocator = Shell::array_buffer_allocator; | 1330 create_params.array_buffer_allocator = &allocator; |
1440 Isolate* isolate = Isolate::New(create_params); | 1331 Isolate* isolate = Isolate::New(create_params); |
1441 do { | 1332 do { |
1442 next_semaphore_.Wait(); | 1333 next_semaphore_.Wait(); |
1443 { | 1334 { |
1444 Isolate::Scope iscope(isolate); | 1335 Isolate::Scope iscope(isolate); |
1445 { | 1336 { |
1446 HandleScope scope(isolate); | 1337 HandleScope scope(isolate); |
1447 PerIsolateData data(isolate); | 1338 PerIsolateData data(isolate); |
1448 Local<Context> context = Shell::CreateEvaluationContext(isolate); | 1339 Local<Context> context = Shell::CreateEvaluationContext(isolate); |
1449 { | 1340 { |
(...skipping 21 matching lines...) Expand all Loading... |
1471 | 1362 |
1472 | 1363 |
1473 void SourceGroup::WaitForThread() { | 1364 void SourceGroup::WaitForThread() { |
1474 if (thread_ == NULL) return; | 1365 if (thread_ == NULL) return; |
1475 if (Shell::options.last_run) { | 1366 if (Shell::options.last_run) { |
1476 thread_->Join(); | 1367 thread_->Join(); |
1477 } else { | 1368 } else { |
1478 done_semaphore_.Wait(); | 1369 done_semaphore_.Wait(); |
1479 } | 1370 } |
1480 } | 1371 } |
1481 | |
1482 | |
1483 SerializationData::~SerializationData() { | |
1484 // Any ArrayBuffer::Contents are owned by this SerializationData object. | |
1485 // SharedArrayBuffer::Contents may be used by other threads, so must be | |
1486 // cleaned up by the main thread in Shell::CleanupWorkers(). | |
1487 for (int i = 0; i < array_buffer_contents.length(); ++i) { | |
1488 ArrayBuffer::Contents& contents = array_buffer_contents[i]; | |
1489 Shell::array_buffer_allocator->Free(contents.Data(), contents.ByteLength()); | |
1490 } | |
1491 } | |
1492 | |
1493 | |
1494 void SerializationData::WriteTag(SerializationTag tag) { data.Add(tag); } | |
1495 | |
1496 | |
1497 void SerializationData::WriteMemory(const void* p, int length) { | |
1498 i::Vector<uint8_t> block = data.AddBlock(0, length); | |
1499 memcpy(&block[0], p, length); | |
1500 } | |
1501 | |
1502 | |
1503 void SerializationData::WriteArrayBufferContents( | |
1504 const ArrayBuffer::Contents& contents) { | |
1505 array_buffer_contents.Add(contents); | |
1506 WriteTag(kSerializationTagTransferredArrayBuffer); | |
1507 int index = array_buffer_contents.length() - 1; | |
1508 Write(index); | |
1509 } | |
1510 | |
1511 | |
1512 void SerializationData::WriteSharedArrayBufferContents( | |
1513 const SharedArrayBuffer::Contents& contents) { | |
1514 shared_array_buffer_contents.Add(contents); | |
1515 WriteTag(kSerializationTagTransferredSharedArrayBuffer); | |
1516 int index = shared_array_buffer_contents.length() - 1; | |
1517 Write(index); | |
1518 } | |
1519 | |
1520 | |
1521 SerializationTag SerializationData::ReadTag(int* offset) const { | |
1522 return static_cast<SerializationTag>(Read<uint8_t>(offset)); | |
1523 } | |
1524 | |
1525 | |
1526 void SerializationData::ReadMemory(void* p, int length, int* offset) const { | |
1527 memcpy(p, &data[*offset], length); | |
1528 (*offset) += length; | |
1529 } | |
1530 | |
1531 | |
1532 void SerializationData::ReadArrayBufferContents(ArrayBuffer::Contents* contents, | |
1533 int* offset) const { | |
1534 int index = Read<int>(offset); | |
1535 DCHECK(index < array_buffer_contents.length()); | |
1536 *contents = array_buffer_contents[index]; | |
1537 } | |
1538 | |
1539 | |
1540 void SerializationData::ReadSharedArrayBufferContents( | |
1541 SharedArrayBuffer::Contents* contents, int* offset) const { | |
1542 int index = Read<int>(offset); | |
1543 DCHECK(index < shared_array_buffer_contents.length()); | |
1544 *contents = shared_array_buffer_contents[index]; | |
1545 } | |
1546 | |
1547 | |
1548 void SerializationDataQueue::Enqueue(SerializationData* data) { | |
1549 base::LockGuard<base::Mutex> lock_guard(&mutex_); | |
1550 data_.Add(data); | |
1551 } | |
1552 | |
1553 | |
1554 bool SerializationDataQueue::Dequeue(SerializationData** data) { | |
1555 base::LockGuard<base::Mutex> lock_guard(&mutex_); | |
1556 if (data_.is_empty()) return false; | |
1557 *data = data_.Remove(0); | |
1558 return true; | |
1559 } | |
1560 | |
1561 | |
1562 bool SerializationDataQueue::IsEmpty() { | |
1563 base::LockGuard<base::Mutex> lock_guard(&mutex_); | |
1564 return data_.is_empty(); | |
1565 } | |
1566 | |
1567 | |
1568 void SerializationDataQueue::Clear() { | |
1569 base::LockGuard<base::Mutex> lock_guard(&mutex_); | |
1570 for (int i = 0; i < data_.length(); ++i) { | |
1571 delete data_[i]; | |
1572 } | |
1573 data_.Clear(); | |
1574 } | |
1575 | |
1576 | |
1577 Worker::Worker() | |
1578 : in_semaphore_(0), out_semaphore_(0), thread_(NULL), script_(NULL) {} | |
1579 | |
1580 | |
1581 Worker::~Worker() { Cleanup(); } | |
1582 | |
1583 | |
1584 void Worker::StartExecuteInThread(Isolate* isolate, | |
1585 const char* function_string) { | |
1586 if (thread_) { | |
1587 Throw(isolate, "Only one worker allowed"); | |
1588 return; | |
1589 } | |
1590 | |
1591 static const char format[] = "(%s).call(this);"; | |
1592 size_t len = strlen(function_string) + sizeof(format); | |
1593 | |
1594 script_ = new char[len + 1]; | |
1595 i::Vector<char> vec(script_, static_cast<int>(len + 1)); | |
1596 i::SNPrintF(vec, format, function_string); | |
1597 | |
1598 thread_ = new WorkerThread(this); | |
1599 thread_->Start(); | |
1600 } | |
1601 | |
1602 | |
1603 void Worker::PostMessage(SerializationData* data) { | |
1604 in_queue_.Enqueue(data); | |
1605 in_semaphore_.Signal(); | |
1606 } | |
1607 | |
1608 | |
1609 SerializationData* Worker::GetMessage() { | |
1610 SerializationData* data; | |
1611 while (!out_queue_.Dequeue(&data)) { | |
1612 out_semaphore_.Wait(); | |
1613 } | |
1614 | |
1615 return data; | |
1616 } | |
1617 | |
1618 | |
1619 void Worker::Terminate() { | |
1620 if (thread_ == NULL) return; | |
1621 PostMessage(NULL); | |
1622 thread_->Join(); | |
1623 Cleanup(); | |
1624 } | |
1625 | |
1626 | |
1627 void Worker::ExecuteInThread() { | |
1628 Isolate::CreateParams create_params; | |
1629 create_params.array_buffer_allocator = Shell::array_buffer_allocator; | |
1630 Isolate* isolate = Isolate::New(create_params); | |
1631 { | |
1632 Isolate::Scope iscope(isolate); | |
1633 { | |
1634 HandleScope scope(isolate); | |
1635 PerIsolateData data(isolate); | |
1636 Local<Context> context = Shell::CreateEvaluationContext(isolate); | |
1637 { | |
1638 Context::Scope cscope(context); | |
1639 PerIsolateData::RealmScope realm_scope(PerIsolateData::Get(isolate)); | |
1640 | |
1641 Handle<Object> global = context->Global(); | |
1642 Handle<Value> this_value = External::New(isolate, this); | |
1643 Handle<FunctionTemplate> postmessage_fun_template = | |
1644 FunctionTemplate::New(isolate, PostMessageOut, this_value); | |
1645 | |
1646 Handle<Function> postmessage_fun; | |
1647 if (postmessage_fun_template->GetFunction(context) | |
1648 .ToLocal(&postmessage_fun)) { | |
1649 global->Set(String::NewFromUtf8(isolate, "postMessage"), | |
1650 postmessage_fun); | |
1651 } | |
1652 | |
1653 // First run the script | |
1654 Handle<String> file_name = String::NewFromUtf8(isolate, "unnamed"); | |
1655 Handle<String> source = String::NewFromUtf8(isolate, script_); | |
1656 Shell::ExecuteString(isolate, source, file_name, false, true); | |
1657 | |
1658 // Get the message handler | |
1659 Handle<Value> onmessage = | |
1660 global->Get(String::NewFromUtf8(isolate, "onmessage")); | |
1661 if (onmessage->IsFunction()) { | |
1662 Handle<Function> onmessage_fun = Handle<Function>::Cast(onmessage); | |
1663 // Now wait for messages | |
1664 bool done = false; | |
1665 while (!done) { | |
1666 in_semaphore_.Wait(); | |
1667 SerializationData* data; | |
1668 if (!in_queue_.Dequeue(&data)) continue; | |
1669 if (data == NULL) { | |
1670 done = true; | |
1671 break; | |
1672 } | |
1673 int offset = 0; | |
1674 Local<Value> data_value; | |
1675 if (Shell::DeserializeValue(isolate, *data, &offset) | |
1676 .ToLocal(&data_value)) { | |
1677 Handle<Value> argv[] = {data_value}; | |
1678 (void)onmessage_fun->Call(context, global, 1, argv); | |
1679 } | |
1680 delete data; | |
1681 } | |
1682 } | |
1683 } | |
1684 } | |
1685 } | |
1686 Shell::CollectGarbage(isolate); | |
1687 isolate->Dispose(); | |
1688 } | |
1689 | |
1690 | |
1691 void Worker::Cleanup() { | |
1692 delete thread_; | |
1693 thread_ = NULL; | |
1694 delete[] script_; | |
1695 script_ = NULL; | |
1696 in_queue_.Clear(); | |
1697 out_queue_.Clear(); | |
1698 } | |
1699 | |
1700 | |
1701 void Worker::PostMessageOut(const v8::FunctionCallbackInfo<v8::Value>& args) { | |
1702 Isolate* isolate = args.GetIsolate(); | |
1703 HandleScope handle_scope(isolate); | |
1704 | |
1705 if (args.Length() < 1) { | |
1706 Throw(isolate, "Invalid argument"); | |
1707 return; | |
1708 } | |
1709 | |
1710 Handle<Value> message = args[0]; | |
1711 | |
1712 // TODO(binji): Allow transferring from worker to main thread? | |
1713 Shell::ObjectList to_transfer; | |
1714 | |
1715 Shell::ObjectList seen_objects; | |
1716 SerializationData* data = new SerializationData; | |
1717 if (Shell::SerializeValue(isolate, message, to_transfer, &seen_objects, | |
1718 data)) { | |
1719 DCHECK(args.Data()->IsExternal()); | |
1720 Handle<External> this_value = Handle<External>::Cast(args.Data()); | |
1721 Worker* worker = static_cast<Worker*>(this_value->Value()); | |
1722 worker->out_queue_.Enqueue(data); | |
1723 worker->out_semaphore_.Signal(); | |
1724 } else { | |
1725 delete data; | |
1726 } | |
1727 } | |
1728 #endif // !V8_SHARED | 1372 #endif // !V8_SHARED |
1729 | 1373 |
1730 | 1374 |
1731 void SetFlagsFromString(const char* flags) { | 1375 void SetFlagsFromString(const char* flags) { |
1732 v8::V8::SetFlagsFromString(flags, static_cast<int>(strlen(flags))); | 1376 v8::V8::SetFlagsFromString(flags, static_cast<int>(strlen(flags))); |
1733 } | 1377 } |
1734 | 1378 |
1735 | 1379 |
1736 bool Shell::SetOptions(int argc, char* argv[]) { | 1380 bool Shell::SetOptions(int argc, char* argv[]) { |
1737 bool logfile_per_isolate = false; | 1381 bool logfile_per_isolate = false; |
(...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1892 Context::Scope cscope(context); | 1536 Context::Scope cscope(context); |
1893 PerIsolateData::RealmScope realm_scope(PerIsolateData::Get(isolate)); | 1537 PerIsolateData::RealmScope realm_scope(PerIsolateData::Get(isolate)); |
1894 options.isolate_sources[0].Execute(isolate); | 1538 options.isolate_sources[0].Execute(isolate); |
1895 } | 1539 } |
1896 } | 1540 } |
1897 CollectGarbage(isolate); | 1541 CollectGarbage(isolate); |
1898 #ifndef V8_SHARED | 1542 #ifndef V8_SHARED |
1899 for (int i = 1; i < options.num_isolates; ++i) { | 1543 for (int i = 1; i < options.num_isolates; ++i) { |
1900 options.isolate_sources[i].WaitForThread(); | 1544 options.isolate_sources[i].WaitForThread(); |
1901 } | 1545 } |
1902 CleanupWorkers(); | |
1903 #endif // !V8_SHARED | 1546 #endif // !V8_SHARED |
1904 return 0; | 1547 return 0; |
1905 } | 1548 } |
1906 | 1549 |
1907 | 1550 |
1908 void Shell::CollectGarbage(Isolate* isolate) { | 1551 void Shell::CollectGarbage(Isolate* isolate) { |
1909 if (options.send_idle_notification) { | 1552 if (options.send_idle_notification) { |
1910 const double kLongIdlePauseInSeconds = 1.0; | 1553 const double kLongIdlePauseInSeconds = 1.0; |
1911 isolate->ContextDisposedNotification(); | 1554 isolate->ContextDisposedNotification(); |
1912 isolate->IdleNotificationDeadline( | 1555 isolate->IdleNotificationDeadline( |
1913 g_platform->MonotonicallyIncreasingTime() + kLongIdlePauseInSeconds); | 1556 g_platform->MonotonicallyIncreasingTime() + kLongIdlePauseInSeconds); |
1914 } | 1557 } |
1915 if (options.invoke_weak_callbacks) { | 1558 if (options.invoke_weak_callbacks) { |
1916 // By sending a low memory notifications, we will try hard to collect all | 1559 // By sending a low memory notifications, we will try hard to collect all |
1917 // garbage and will therefore also invoke all weak callbacks of actually | 1560 // garbage and will therefore also invoke all weak callbacks of actually |
1918 // unreachable persistent handles. | 1561 // unreachable persistent handles. |
1919 isolate->LowMemoryNotification(); | 1562 isolate->LowMemoryNotification(); |
1920 } | 1563 } |
1921 } | 1564 } |
1922 | 1565 |
1923 | 1566 |
1924 #ifndef V8_SHARED | 1567 #ifndef V8_SHARED |
1925 bool Shell::SerializeValue(Isolate* isolate, Handle<Value> value, | |
1926 const ObjectList& to_transfer, | |
1927 ObjectList* seen_objects, | |
1928 SerializationData* out_data) { | |
1929 DCHECK(out_data); | |
1930 HandleScope scope(isolate); | |
1931 Local<Context> context = isolate->GetCurrentContext(); | |
1932 | |
1933 if (value->IsUndefined()) { | |
1934 out_data->WriteTag(kSerializationTagUndefined); | |
1935 } else if (value->IsNull()) { | |
1936 out_data->WriteTag(kSerializationTagNull); | |
1937 } else if (value->IsTrue()) { | |
1938 out_data->WriteTag(kSerializationTagTrue); | |
1939 } else if (value->IsFalse()) { | |
1940 out_data->WriteTag(kSerializationTagFalse); | |
1941 } else if (value->IsNumber()) { | |
1942 Handle<Number> num = Handle<Number>::Cast(value); | |
1943 double value = num->Value(); | |
1944 out_data->WriteTag(kSerializationTagNumber); | |
1945 out_data->Write(value); | |
1946 } else if (value->IsString()) { | |
1947 v8::String::Utf8Value str(value); | |
1948 out_data->WriteTag(kSerializationTagString); | |
1949 out_data->Write(str.length()); | |
1950 out_data->WriteMemory(*str, str.length()); | |
1951 } else if (value->IsArray()) { | |
1952 Handle<Array> array = Handle<Array>::Cast(value); | |
1953 if (FindInObjectList(array, *seen_objects)) { | |
1954 Throw(isolate, "Duplicated arrays not supported"); | |
1955 return false; | |
1956 } | |
1957 seen_objects->Add(array); | |
1958 out_data->WriteTag(kSerializationTagArray); | |
1959 uint32_t length = array->Length(); | |
1960 out_data->Write(length); | |
1961 for (uint32_t i = 0; i < length; ++i) { | |
1962 Local<Value> element_value; | |
1963 if (array->Get(context, i).ToLocal(&element_value)) { | |
1964 if (!SerializeValue(isolate, element_value, to_transfer, seen_objects, | |
1965 out_data)) | |
1966 return false; | |
1967 } | |
1968 } | |
1969 } else if (value->IsArrayBuffer()) { | |
1970 Handle<ArrayBuffer> array_buffer = Handle<ArrayBuffer>::Cast(value); | |
1971 if (FindInObjectList(array_buffer, *seen_objects)) { | |
1972 Throw(isolate, "Duplicated array buffers not supported"); | |
1973 return false; | |
1974 } | |
1975 seen_objects->Add(array_buffer); | |
1976 if (FindInObjectList(array_buffer, to_transfer)) { | |
1977 // Transfer ArrayBuffer | |
1978 if (!array_buffer->IsNeuterable()) { | |
1979 Throw(isolate, "Attempting to transfer an un-neuterable ArrayBuffer"); | |
1980 return false; | |
1981 } | |
1982 | |
1983 ArrayBuffer::Contents contents = array_buffer->Externalize(); | |
1984 array_buffer->Neuter(); | |
1985 out_data->WriteArrayBufferContents(contents); | |
1986 } else { | |
1987 ArrayBuffer::Contents contents = array_buffer->GetContents(); | |
1988 // Clone ArrayBuffer | |
1989 if (contents.ByteLength() > i::kMaxUInt32) { | |
1990 Throw(isolate, "ArrayBuffer is too big to clone"); | |
1991 return false; | |
1992 } | |
1993 | |
1994 int byte_length = static_cast<int>(contents.ByteLength()); | |
1995 out_data->WriteTag(kSerializationTagArrayBuffer); | |
1996 out_data->Write(byte_length); | |
1997 out_data->WriteMemory(contents.Data(), | |
1998 static_cast<int>(contents.ByteLength())); | |
1999 } | |
2000 } else if (value->IsSharedArrayBuffer()) { | |
2001 Handle<SharedArrayBuffer> sab = Handle<SharedArrayBuffer>::Cast(value); | |
2002 if (FindInObjectList(sab, *seen_objects)) { | |
2003 Throw(isolate, "Duplicated shared array buffers not supported"); | |
2004 return false; | |
2005 } | |
2006 seen_objects->Add(sab); | |
2007 if (!FindInObjectList(sab, to_transfer)) { | |
2008 Throw(isolate, "SharedArrayBuffer must be transferred"); | |
2009 return false; | |
2010 } | |
2011 | |
2012 SharedArrayBuffer::Contents contents = sab->Externalize(); | |
2013 out_data->WriteSharedArrayBufferContents(contents); | |
2014 externalized_shared_contents_.Add(contents); | |
2015 } else if (value->IsObject()) { | |
2016 Handle<Object> object = Handle<Object>::Cast(value); | |
2017 if (FindInObjectList(object, *seen_objects)) { | |
2018 Throw(isolate, "Duplicated objects not supported"); | |
2019 return false; | |
2020 } | |
2021 seen_objects->Add(object); | |
2022 Local<Array> property_names; | |
2023 if (!object->GetOwnPropertyNames(context).ToLocal(&property_names)) { | |
2024 Throw(isolate, "Unable to get property names"); | |
2025 return false; | |
2026 } | |
2027 | |
2028 uint32_t length = property_names->Length(); | |
2029 out_data->WriteTag(kSerializationTagObject); | |
2030 out_data->Write(length); | |
2031 for (uint32_t i = 0; i < length; ++i) { | |
2032 Handle<Value> name; | |
2033 Handle<Value> property_value; | |
2034 if (property_names->Get(context, i).ToLocal(&name) && | |
2035 object->Get(context, name).ToLocal(&property_value)) { | |
2036 if (!SerializeValue(isolate, name, to_transfer, seen_objects, out_data)) | |
2037 return false; | |
2038 if (!SerializeValue(isolate, property_value, to_transfer, seen_objects, | |
2039 out_data)) | |
2040 return false; | |
2041 } | |
2042 } | |
2043 } else { | |
2044 Throw(isolate, "Don't know how to serialize object"); | |
2045 return false; | |
2046 } | |
2047 | |
2048 return true; | |
2049 } | |
2050 | |
2051 | |
2052 MaybeLocal<Value> Shell::DeserializeValue(Isolate* isolate, | |
2053 const SerializationData& data, | |
2054 int* offset) { | |
2055 DCHECK(offset); | |
2056 EscapableHandleScope scope(isolate); | |
2057 // This function should not use utility_context_ because it is running on a | |
2058 // different thread. | |
2059 Local<Value> result; | |
2060 SerializationTag tag = data.ReadTag(offset); | |
2061 | |
2062 switch (tag) { | |
2063 case kSerializationTagUndefined: | |
2064 result = Undefined(isolate); | |
2065 break; | |
2066 case kSerializationTagNull: | |
2067 result = Null(isolate); | |
2068 break; | |
2069 case kSerializationTagTrue: | |
2070 result = True(isolate); | |
2071 break; | |
2072 case kSerializationTagFalse: | |
2073 result = False(isolate); | |
2074 break; | |
2075 case kSerializationTagNumber: | |
2076 result = Number::New(isolate, data.Read<double>(offset)); | |
2077 break; | |
2078 case kSerializationTagString: { | |
2079 int length = data.Read<int>(offset); | |
2080 static char s_buffer[128]; | |
2081 char* p = s_buffer; | |
2082 bool allocated = false; | |
2083 if (length > static_cast<int>(sizeof(s_buffer))) { | |
2084 p = new char[length]; | |
2085 allocated = true; | |
2086 } | |
2087 data.ReadMemory(p, length, offset); | |
2088 MaybeLocal<String> str = | |
2089 String::NewFromUtf8(isolate, p, String::kNormalString, length); | |
2090 if (!str.IsEmpty()) result = str.ToLocalChecked(); | |
2091 if (allocated) delete[] p; | |
2092 break; | |
2093 } | |
2094 case kSerializationTagArray: { | |
2095 uint32_t length = data.Read<uint32_t>(offset); | |
2096 Handle<Array> array = Array::New(isolate, length); | |
2097 for (uint32_t i = 0; i < length; ++i) { | |
2098 Local<Value> element_value; | |
2099 CHECK(DeserializeValue(isolate, data, offset).ToLocal(&element_value)); | |
2100 array->Set(i, element_value); | |
2101 } | |
2102 result = array; | |
2103 break; | |
2104 } | |
2105 case kSerializationTagObject: { | |
2106 int length = data.Read<int>(offset); | |
2107 Handle<Object> object = Object::New(isolate); | |
2108 for (int i = 0; i < length; ++i) { | |
2109 Local<Value> property_name; | |
2110 CHECK(DeserializeValue(isolate, data, offset).ToLocal(&property_name)); | |
2111 DCHECK(property_name->IsString()); | |
2112 Local<Value> property_value; | |
2113 CHECK(DeserializeValue(isolate, data, offset).ToLocal(&property_value)); | |
2114 object->Set(property_name, property_value); | |
2115 } | |
2116 result = object; | |
2117 break; | |
2118 } | |
2119 case kSerializationTagArrayBuffer: { | |
2120 int byte_length = data.Read<int>(offset); | |
2121 Handle<ArrayBuffer> array_buffer = ArrayBuffer::New(isolate, byte_length); | |
2122 ArrayBuffer::Contents contents = array_buffer->GetContents(); | |
2123 DCHECK(static_cast<size_t>(byte_length) == contents.ByteLength()); | |
2124 data.ReadMemory(contents.Data(), byte_length, offset); | |
2125 result = array_buffer; | |
2126 break; | |
2127 } | |
2128 case kSerializationTagTransferredArrayBuffer: { | |
2129 ArrayBuffer::Contents contents; | |
2130 data.ReadArrayBufferContents(&contents, offset); | |
2131 result = | |
2132 ArrayBuffer::New(isolate, contents.Data(), contents.ByteLength()); | |
2133 break; | |
2134 } | |
2135 case kSerializationTagTransferredSharedArrayBuffer: { | |
2136 SharedArrayBuffer::Contents contents; | |
2137 data.ReadSharedArrayBufferContents(&contents, offset); | |
2138 result = SharedArrayBuffer::New(isolate, contents.Data(), | |
2139 contents.ByteLength()); | |
2140 break; | |
2141 } | |
2142 default: | |
2143 UNREACHABLE(); | |
2144 } | |
2145 | |
2146 return scope.Escape(result); | |
2147 } | |
2148 | |
2149 | |
2150 void Shell::CleanupWorkers() { | |
2151 worker_.Terminate(); | |
2152 for (int i = 0; i < externalized_shared_contents_.length(); ++i) { | |
2153 const SharedArrayBuffer::Contents& contents = | |
2154 externalized_shared_contents_[i]; | |
2155 Shell::array_buffer_allocator->Free(contents.Data(), contents.ByteLength()); | |
2156 } | |
2157 externalized_shared_contents_.Clear(); | |
2158 } | |
2159 | |
2160 | |
2161 static void DumpHeapConstants(i::Isolate* isolate) { | 1568 static void DumpHeapConstants(i::Isolate* isolate) { |
2162 i::Heap* heap = isolate->heap(); | 1569 i::Heap* heap = isolate->heap(); |
2163 | 1570 |
2164 // Dump the INSTANCE_TYPES table to the console. | 1571 // Dump the INSTANCE_TYPES table to the console. |
2165 printf("# List of known V8 instance types.\n"); | 1572 printf("# List of known V8 instance types.\n"); |
2166 #define DUMP_TYPE(T) printf(" %d: \"%s\",\n", i::T, #T); | 1573 #define DUMP_TYPE(T) printf(" %d: \"%s\",\n", i::T, #T); |
2167 printf("INSTANCE_TYPES = {\n"); | 1574 printf("INSTANCE_TYPES = {\n"); |
2168 INSTANCE_TYPE_LIST(DUMP_TYPE) | 1575 INSTANCE_TYPE_LIST(DUMP_TYPE) |
2169 printf("}\n"); | 1576 printf("}\n"); |
2170 #undef DUMP_TYPE | 1577 #undef DUMP_TYPE |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2237 v8::V8::Initialize(); | 1644 v8::V8::Initialize(); |
2238 #ifdef V8_USE_EXTERNAL_STARTUP_DATA | 1645 #ifdef V8_USE_EXTERNAL_STARTUP_DATA |
2239 v8::StartupDataHandler startup_data(argv[0], options.natives_blob, | 1646 v8::StartupDataHandler startup_data(argv[0], options.natives_blob, |
2240 options.snapshot_blob); | 1647 options.snapshot_blob); |
2241 #endif | 1648 #endif |
2242 SetFlagsFromString("--trace-hydrogen-file=hydrogen.cfg"); | 1649 SetFlagsFromString("--trace-hydrogen-file=hydrogen.cfg"); |
2243 SetFlagsFromString("--trace-turbo-cfg-file=turbo.cfg"); | 1650 SetFlagsFromString("--trace-turbo-cfg-file=turbo.cfg"); |
2244 SetFlagsFromString("--redirect-code-traces-to=code.asm"); | 1651 SetFlagsFromString("--redirect-code-traces-to=code.asm"); |
2245 int result = 0; | 1652 int result = 0; |
2246 Isolate::CreateParams create_params; | 1653 Isolate::CreateParams create_params; |
2247 ShellArrayBufferAllocator shell_array_buffer_allocator; | 1654 ShellArrayBufferAllocator array_buffer_allocator; |
2248 MockArrayBufferAllocator mock_arraybuffer_allocator; | 1655 MockArrayBufferAllocator mock_arraybuffer_allocator; |
2249 if (options.mock_arraybuffer_allocator) { | 1656 if (options.mock_arraybuffer_allocator) { |
2250 Shell::array_buffer_allocator = &mock_arraybuffer_allocator; | 1657 create_params.array_buffer_allocator = &mock_arraybuffer_allocator; |
2251 } else { | 1658 } else { |
2252 Shell::array_buffer_allocator = &shell_array_buffer_allocator; | 1659 create_params.array_buffer_allocator = &array_buffer_allocator; |
2253 } | 1660 } |
2254 create_params.array_buffer_allocator = Shell::array_buffer_allocator; | |
2255 #if !defined(V8_SHARED) && defined(ENABLE_GDB_JIT_INTERFACE) | 1661 #if !defined(V8_SHARED) && defined(ENABLE_GDB_JIT_INTERFACE) |
2256 if (i::FLAG_gdbjit) { | 1662 if (i::FLAG_gdbjit) { |
2257 create_params.code_event_handler = i::GDBJITInterface::EventHandler; | 1663 create_params.code_event_handler = i::GDBJITInterface::EventHandler; |
2258 } | 1664 } |
2259 #endif | 1665 #endif |
2260 #ifdef ENABLE_VTUNE_JIT_INTERFACE | 1666 #ifdef ENABLE_VTUNE_JIT_INTERFACE |
2261 create_params.code_event_handler = vTune::GetVtuneCodeEventHandler(); | 1667 create_params.code_event_handler = vTune::GetVtuneCodeEventHandler(); |
2262 #endif | 1668 #endif |
2263 #ifndef V8_SHARED | 1669 #ifndef V8_SHARED |
2264 create_params.constraints.ConfigureDefaults( | 1670 create_params.constraints.ConfigureDefaults( |
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2349 } | 1755 } |
2350 | 1756 |
2351 } // namespace v8 | 1757 } // namespace v8 |
2352 | 1758 |
2353 | 1759 |
2354 #ifndef GOOGLE3 | 1760 #ifndef GOOGLE3 |
2355 int main(int argc, char* argv[]) { | 1761 int main(int argc, char* argv[]) { |
2356 return v8::Shell::Main(argc, argv); | 1762 return v8::Shell::Main(argc, argv); |
2357 } | 1763 } |
2358 #endif | 1764 #endif |
OLD | NEW |