Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(18)

Side by Side Diff: src/d8.cc

Issue 2643723010: [d8] Use ValueSerializer for postMessage (instead of ad-hoc serializer) (Closed)
Patch Set: starting to work on switching to value serializer Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 #include <errno.h> 5 #include <errno.h>
6 #include <stdlib.h> 6 #include <stdlib.h>
7 #include <string.h> 7 #include <string.h>
8 #include <sys/stat.h> 8 #include <sys/stat.h>
9 9
10 #include <algorithm> 10 #include <algorithm>
(...skipping 13 matching lines...) Expand all
24 #include "include/libplatform/v8-tracing.h" 24 #include "include/libplatform/v8-tracing.h"
25 #include "src/api.h" 25 #include "src/api.h"
26 #include "src/base/cpu.h" 26 #include "src/base/cpu.h"
27 #include "src/base/debug/stack_trace.h" 27 #include "src/base/debug/stack_trace.h"
28 #include "src/base/logging.h" 28 #include "src/base/logging.h"
29 #include "src/base/platform/platform.h" 29 #include "src/base/platform/platform.h"
30 #include "src/base/platform/time.h" 30 #include "src/base/platform/time.h"
31 #include "src/base/sys-info.h" 31 #include "src/base/sys-info.h"
32 #include "src/basic-block-profiler.h" 32 #include "src/basic-block-profiler.h"
33 #include "src/interpreter/interpreter.h" 33 #include "src/interpreter/interpreter.h"
34 #include "src/list-inl.h"
34 #include "src/msan.h" 35 #include "src/msan.h"
35 #include "src/objects-inl.h" 36 #include "src/objects-inl.h"
36 #include "src/snapshot/natives.h" 37 #include "src/snapshot/natives.h"
37 #include "src/utils.h" 38 #include "src/utils.h"
38 #include "src/v8.h" 39 #include "src/v8.h"
39 40
40 #ifdef V8_INSPECTOR_ENABLED 41 #ifdef V8_INSPECTOR_ENABLED
41 #include "include/v8-inspector.h" 42 #include "include/v8-inspector.h"
42 #endif // V8_INSPECTOR_ENABLED 43 #endif // V8_INSPECTOR_ENABLED
43 44
44 #if !defined(_WIN32) && !defined(_WIN64) 45 #if !defined(_WIN32) && !defined(_WIN64)
45 #include <unistd.h> // NOLINT 46 #include <unistd.h> // NOLINT
46 #else 47 #else
47 #include <windows.h> // NOLINT 48 #include <windows.h> // NOLINT
48 #if defined(_MSC_VER) 49 #if defined(_MSC_VER)
49 #include <crtdbg.h> // NOLINT 50 #include <crtdbg.h> // NOLINT
50 #endif // defined(_MSC_VER) 51 #endif // defined(_MSC_VER)
51 #endif // !defined(_WIN32) && !defined(_WIN64) 52 #endif // !defined(_WIN32) && !defined(_WIN64)
52 53
53 #ifndef DCHECK 54 #ifndef DCHECK
54 #define DCHECK(condition) assert(condition) 55 #define DCHECK(condition) assert(condition)
55 #endif 56 #endif
56 57
57 #ifndef CHECK 58 #ifndef CHECK
58 #define CHECK(condition) assert(condition) 59 #define CHECK(condition) assert(condition)
59 #endif 60 #endif
60 61
62 namespace std {
63
64 template <>
65 struct hash<v8::SharedArrayBuffer::Contents> {
jbroman 2017/01/24 18:53:43 (I'm not a V8 owner, but...) 1. The Chromium/Goog
binji 2017/01/25 00:31:35 Done.
66 size_t operator()(const v8::SharedArrayBuffer::Contents& contents) const {
67 return std::hash<void*>()(contents.Data()) ^
68 std::hash<size_t>()(contents.ByteLength());
69 }
70 };
71
72 } // namespace std
73
61 namespace v8 { 74 namespace v8 {
62 75
76 bool operator==(const SharedArrayBuffer::Contents& a,
77 const SharedArrayBuffer::Contents& b) {
78 return a.Data() == b.Data() && a.ByteLength() == b.ByteLength();
79 }
80
63 namespace { 81 namespace {
64 82
65 const int MB = 1024 * 1024; 83 const int MB = 1024 * 1024;
66 const int kMaxWorkers = 50; 84 const int kMaxWorkers = 50;
67 85
68 #define USE_VM 1 86 #define USE_VM 1
69 #define VM_THRESHOLD 65536 87 #define VM_THRESHOLD 65536
70 // TODO(titzer): allocations should fail if >= 2gb because of 88 // TODO(titzer): allocations should fail if >= 2gb because of
71 // array buffers storing the lengths as a SMI internally. 89 // array buffers storing the lengths as a SMI internally.
72 #define TWO_GB (2u * 1024u * 1024u * 1024u) 90 #define TWO_GB (2u * 1024u * 1024u * 1024u)
(...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after
211 229
212 v8::Platform* g_platform = NULL; 230 v8::Platform* g_platform = NULL;
213 231
214 static Local<Value> Throw(Isolate* isolate, const char* message) { 232 static Local<Value> Throw(Isolate* isolate, const char* message) {
215 return isolate->ThrowException( 233 return isolate->ThrowException(
216 String::NewFromUtf8(isolate, message, NewStringType::kNormal) 234 String::NewFromUtf8(isolate, message, NewStringType::kNormal)
217 .ToLocalChecked()); 235 .ToLocalChecked());
218 } 236 }
219 237
220 238
221 bool FindInObjectList(Local<Object> object, const Shell::ObjectList& list) {
222 for (int i = 0; i < list.length(); ++i) {
223 if (list[i]->StrictEquals(object)) {
224 return true;
225 }
226 }
227 return false;
228 }
229
230
231 Worker* GetWorkerFromInternalField(Isolate* isolate, Local<Object> object) { 239 Worker* GetWorkerFromInternalField(Isolate* isolate, Local<Object> object) {
232 if (object->InternalFieldCount() != 1) { 240 if (object->InternalFieldCount() != 1) {
233 Throw(isolate, "this is not a Worker"); 241 Throw(isolate, "this is not a Worker");
234 return NULL; 242 return NULL;
235 } 243 }
236 244
237 Worker* worker = 245 Worker* worker =
238 static_cast<Worker*>(object->GetAlignedPointerFromInternalField(0)); 246 static_cast<Worker*>(object->GetAlignedPointerFromInternalField(0));
239 if (worker == NULL) { 247 if (worker == NULL) {
240 Throw(isolate, "Worker is defunct because main thread is terminating"); 248 Throw(isolate, "Worker is defunct because main thread is terminating");
(...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after
403 base::OS::MemoryMappedFile* Shell::counters_file_ = NULL; 411 base::OS::MemoryMappedFile* Shell::counters_file_ = NULL;
404 CounterCollection Shell::local_counters_; 412 CounterCollection Shell::local_counters_;
405 CounterCollection* Shell::counters_ = &local_counters_; 413 CounterCollection* Shell::counters_ = &local_counters_;
406 base::LazyMutex Shell::context_mutex_; 414 base::LazyMutex Shell::context_mutex_;
407 const base::TimeTicks Shell::kInitialTicks = 415 const base::TimeTicks Shell::kInitialTicks =
408 base::TimeTicks::HighResolutionNow(); 416 base::TimeTicks::HighResolutionNow();
409 Global<Function> Shell::stringify_function_; 417 Global<Function> Shell::stringify_function_;
410 base::LazyMutex Shell::workers_mutex_; 418 base::LazyMutex Shell::workers_mutex_;
411 bool Shell::allow_new_workers_ = true; 419 bool Shell::allow_new_workers_ = true;
412 i::List<Worker*> Shell::workers_; 420 i::List<Worker*> Shell::workers_;
413 i::List<SharedArrayBuffer::Contents> Shell::externalized_shared_contents_; 421 std::unordered_set<SharedArrayBuffer::Contents>
422 Shell::externalized_shared_contents_;
414 423
415 Global<Context> Shell::evaluation_context_; 424 Global<Context> Shell::evaluation_context_;
416 ArrayBuffer::Allocator* Shell::array_buffer_allocator; 425 ArrayBuffer::Allocator* Shell::array_buffer_allocator;
417 ShellOptions Shell::options; 426 ShellOptions Shell::options;
418 base::OnceType Shell::quit_once_ = V8_ONCE_INIT; 427 base::OnceType Shell::quit_once_ = V8_ONCE_INIT;
419 428
420 bool CounterMap::Match(void* key1, void* key2) { 429 bool CounterMap::Match(void* key1, void* key2) {
421 const char* name1 = reinterpret_cast<const char*>(key1); 430 const char* name1 = reinterpret_cast<const char*>(key1);
422 const char* name2 = reinterpret_cast<const char*>(key2); 431 const char* name2 = reinterpret_cast<const char*>(key2);
423 return strcmp(name1, name2) == 0; 432 return strcmp(name1, name2) == 0;
(...skipping 732 matching lines...) Expand 10 before | Expand all | Expand 10 after
1156 Throw(isolate, "Invalid argument"); 1165 Throw(isolate, "Invalid argument");
1157 return; 1166 return;
1158 } 1167 }
1159 1168
1160 Worker* worker = GetWorkerFromInternalField(isolate, args.Holder()); 1169 Worker* worker = GetWorkerFromInternalField(isolate, args.Holder());
1161 if (!worker) { 1170 if (!worker) {
1162 return; 1171 return;
1163 } 1172 }
1164 1173
1165 Local<Value> message = args[0]; 1174 Local<Value> message = args[0];
1166 ObjectList to_transfer; 1175 Local<Value> transfer =
1167 if (args.Length() >= 2) { 1176 args.Length() >= 2 ? args[1] : Local<Value>::Cast(Undefined(isolate));
jbroman 2017/01/24 18:53:43 nit: is the Local<Value> cast necessary; I think i
binji 2017/01/25 00:31:36 The two arms of the conditional have different typ
jbroman 2017/01/25 16:34:54 OK, sorry. Ordinarily the compiler would still ad
1168 if (!args[1]->IsArray()) { 1177 SerializationData* data;
1169 Throw(isolate, "Transfer list must be an Array"); 1178 if (Shell::SerializeValue(isolate, message, transfer).To(&data)) {
1170 return;
1171 }
1172
1173 Local<Array> transfer = Local<Array>::Cast(args[1]);
1174 uint32_t length = transfer->Length();
1175 for (uint32_t i = 0; i < length; ++i) {
1176 Local<Value> element;
1177 if (transfer->Get(context, i).ToLocal(&element)) {
1178 if (!element->IsArrayBuffer() && !element->IsSharedArrayBuffer()) {
1179 Throw(isolate,
1180 "Transfer array elements must be an ArrayBuffer or "
1181 "SharedArrayBuffer.");
1182 break;
1183 }
1184
1185 to_transfer.Add(Local<Object>::Cast(element));
1186 }
1187 }
1188 }
1189
1190 ObjectList seen_objects;
1191 SerializationData* data = new SerializationData;
1192 if (SerializeValue(isolate, message, to_transfer, &seen_objects, data)) {
1193 worker->PostMessage(data); 1179 worker->PostMessage(data);
1194 } else {
1195 delete data;
1196 } 1180 }
1197 } 1181 }
1198 1182
1199 1183
1200 void Shell::WorkerGetMessage(const v8::FunctionCallbackInfo<v8::Value>& args) { 1184 void Shell::WorkerGetMessage(const v8::FunctionCallbackInfo<v8::Value>& args) {
1201 Isolate* isolate = args.GetIsolate(); 1185 Isolate* isolate = args.GetIsolate();
1202 HandleScope handle_scope(isolate); 1186 HandleScope handle_scope(isolate);
1203 Worker* worker = GetWorkerFromInternalField(isolate, args.Holder()); 1187 Worker* worker = GetWorkerFromInternalField(isolate, args.Holder());
1204 if (!worker) { 1188 if (!worker) {
1205 return; 1189 return;
1206 } 1190 }
1207 1191
1208 SerializationData* data = worker->GetMessage(); 1192 SerializationData* data = worker->GetMessage();
1209 if (data) { 1193 if (data) {
1210 int offset = 0; 1194 Local<Value> value;
1211 Local<Value> data_value; 1195 if (Shell::DeserializeValue(isolate, data).ToLocal(&value)) {
jbroman 2017/01/24 18:53:43 nit: Just checking, if this fails (i.e. an excepti
binji 2017/01/25 00:31:35 Yeah, it definitely will break the tests (or perha
1212 if (Shell::DeserializeValue(isolate, *data, &offset).ToLocal(&data_value)) { 1196 args.GetReturnValue().Set(value);
1213 args.GetReturnValue().Set(data_value);
1214 } 1197 }
1215 delete data;
1216 } 1198 }
1217 } 1199 }
1218 1200
1219 1201
1220 void Shell::WorkerTerminate(const v8::FunctionCallbackInfo<v8::Value>& args) { 1202 void Shell::WorkerTerminate(const v8::FunctionCallbackInfo<v8::Value>& args) {
1221 Isolate* isolate = args.GetIsolate(); 1203 Isolate* isolate = args.GetIsolate();
1222 HandleScope handle_scope(isolate); 1204 HandleScope handle_scope(isolate);
1223 Worker* worker = GetWorkerFromInternalField(isolate, args.Holder()); 1205 Worker* worker = GetWorkerFromInternalField(isolate, args.Holder());
1224 if (!worker) { 1206 if (!worker) {
1225 return; 1207 return;
(...skipping 915 matching lines...) Expand 10 before | Expand all | Expand 10 after
2141 if (thread_ == NULL) return; 2123 if (thread_ == NULL) return;
2142 done_semaphore_.Wait(); 2124 done_semaphore_.Wait();
2143 } 2125 }
2144 2126
2145 2127
2146 void SourceGroup::JoinThread() { 2128 void SourceGroup::JoinThread() {
2147 if (thread_ == NULL) return; 2129 if (thread_ == NULL) return;
2148 thread_->Join(); 2130 thread_->Join();
2149 } 2131 }
2150 2132
2151
2152 SerializationData::~SerializationData() { 2133 SerializationData::~SerializationData() {
2153 // Any ArrayBuffer::Contents are owned by this SerializationData object if 2134 // Any ArrayBuffer::Contents are owned by this SerializationData object if
2154 // ownership hasn't been transferred out via ReadArrayBufferContents. 2135 // ownership hasn't been transferred out.
2155 // SharedArrayBuffer::Contents may be used by multiple threads, so must be 2136 // SharedArrayBuffer::Contents may be used by multiple threads, so must be
2156 // cleaned up by the main thread in Shell::CleanupWorkers(). 2137 // cleaned up by the main thread in Shell::CleanupWorkers().
2157 for (int i = 0; i < array_buffer_contents_.length(); ++i) { 2138 for (const auto& contents : array_buffer_contents_) {
2158 ArrayBuffer::Contents& contents = array_buffer_contents_[i];
2159 if (contents.Data()) { 2139 if (contents.Data()) {
2160 Shell::array_buffer_allocator->Free(contents.Data(), 2140 Shell::array_buffer_allocator->Free(contents.Data(),
2161 contents.ByteLength()); 2141 contents.ByteLength());
2162 } 2142 }
2163 } 2143 }
2164 } 2144 }
2165 2145
2166 2146 void SerializationData::ClearTransferredArrayBuffers() {
2167 void SerializationData::WriteTag(SerializationTag tag) { data_.Add(tag); } 2147 array_buffer_contents_.clear();
2168
2169
2170 void SerializationData::WriteMemory(const void* p, int length) {
2171 if (length > 0) {
2172 i::Vector<uint8_t> block = data_.AddBlock(0, length);
2173 memcpy(&block[0], p, length);
2174 }
2175 } 2148 }
2176 2149
2177 2150
2178 void SerializationData::WriteArrayBufferContents(
2179 const ArrayBuffer::Contents& contents) {
2180 array_buffer_contents_.Add(contents);
2181 WriteTag(kSerializationTagTransferredArrayBuffer);
2182 int index = array_buffer_contents_.length() - 1;
2183 Write(index);
2184 }
2185
2186
2187 void SerializationData::WriteSharedArrayBufferContents(
2188 const SharedArrayBuffer::Contents& contents) {
2189 shared_array_buffer_contents_.Add(contents);
2190 WriteTag(kSerializationTagTransferredSharedArrayBuffer);
2191 int index = shared_array_buffer_contents_.length() - 1;
2192 Write(index);
2193 }
2194
2195
2196 SerializationTag SerializationData::ReadTag(int* offset) const {
2197 return static_cast<SerializationTag>(Read<uint8_t>(offset));
2198 }
2199
2200
2201 void SerializationData::ReadMemory(void* p, int length, int* offset) const {
2202 if (length > 0) {
2203 memcpy(p, &data_[*offset], length);
2204 (*offset) += length;
2205 }
2206 }
2207
2208
2209 void SerializationData::ReadArrayBufferContents(ArrayBuffer::Contents* contents,
2210 int* offset) const {
2211 int index = Read<int>(offset);
2212 DCHECK(index < array_buffer_contents_.length());
2213 *contents = array_buffer_contents_[index];
2214 // Ownership of this ArrayBuffer::Contents is passed to the caller. Neuter
2215 // our copy so it won't be double-free'd when this SerializationData is
2216 // destroyed.
2217 array_buffer_contents_[index] = ArrayBuffer::Contents();
2218 }
2219
2220
2221 void SerializationData::ReadSharedArrayBufferContents(
2222 SharedArrayBuffer::Contents* contents, int* offset) const {
2223 int index = Read<int>(offset);
2224 DCHECK(index < shared_array_buffer_contents_.length());
2225 *contents = shared_array_buffer_contents_[index];
2226 }
2227
2228
2229 void SerializationDataQueue::Enqueue(SerializationData* data) { 2151 void SerializationDataQueue::Enqueue(SerializationData* data) {
2230 base::LockGuard<base::Mutex> lock_guard(&mutex_); 2152 base::LockGuard<base::Mutex> lock_guard(&mutex_);
2231 data_.Add(data); 2153 data_.Add(data);
2232 } 2154 }
2233 2155
2234 2156
2235 bool SerializationDataQueue::Dequeue(SerializationData** data) { 2157 bool SerializationDataQueue::Dequeue(SerializationData** data) {
2236 base::LockGuard<base::Mutex> lock_guard(&mutex_); 2158 base::LockGuard<base::Mutex> lock_guard(&mutex_);
2237 *data = NULL; 2159 *data = NULL;
2238 if (data_.is_empty()) return false; 2160 if (data_.is_empty()) return false;
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after
2358 if (onmessage->IsFunction()) { 2280 if (onmessage->IsFunction()) {
2359 Local<Function> onmessage_fun = Local<Function>::Cast(onmessage); 2281 Local<Function> onmessage_fun = Local<Function>::Cast(onmessage);
2360 // Now wait for messages 2282 // Now wait for messages
2361 while (true) { 2283 while (true) {
2362 in_semaphore_.Wait(); 2284 in_semaphore_.Wait();
2363 SerializationData* data; 2285 SerializationData* data;
2364 if (!in_queue_.Dequeue(&data)) continue; 2286 if (!in_queue_.Dequeue(&data)) continue;
2365 if (data == NULL) { 2287 if (data == NULL) {
2366 break; 2288 break;
2367 } 2289 }
2368 int offset = 0; 2290 Local<Value> value;
2369 Local<Value> data_value; 2291 if (Shell::DeserializeValue(isolate, data).ToLocal(&value)) {
jbroman 2017/01/24 18:53:43 If an exception is thrown from DeserializeValue, d
binji 2017/01/25 00:31:35 Done.
2370 if (Shell::DeserializeValue(isolate, *data, &offset) 2292 Local<Value> argv[] = {value};
2371 .ToLocal(&data_value)) { 2293 v8::TryCatch try_catch(isolate);
2372 Local<Value> argv[] = {data_value};
2373 (void)onmessage_fun->Call(context, global, 1, argv); 2294 (void)onmessage_fun->Call(context, global, 1, argv);
2295 if (try_catch.HasCaught()) {
2296 Shell::ReportException(isolate, &try_catch);
2297 }
2374 } 2298 }
2375 delete data;
2376 } 2299 }
2377 } 2300 }
2378 } 2301 }
2379 } 2302 }
2380 DisposeModuleEmbedderData(context); 2303 DisposeModuleEmbedderData(context);
2381 } 2304 }
2382 Shell::CollectGarbage(isolate); 2305 Shell::CollectGarbage(isolate);
2383 } 2306 }
2384 isolate->Dispose(); 2307 isolate->Dispose();
2385 2308
2386 // Post NULL to wake the thread waiting on GetMessage() if there is one. 2309 // Post NULL to wake the thread waiting on GetMessage() if there is one.
2387 out_queue_.Enqueue(NULL); 2310 out_queue_.Enqueue(NULL);
2388 out_semaphore_.Signal(); 2311 out_semaphore_.Signal();
2389 } 2312 }
2390 2313
2391 2314
2392 void Worker::PostMessageOut(const v8::FunctionCallbackInfo<v8::Value>& args) { 2315 void Worker::PostMessageOut(const v8::FunctionCallbackInfo<v8::Value>& args) {
2393 Isolate* isolate = args.GetIsolate(); 2316 Isolate* isolate = args.GetIsolate();
2394 HandleScope handle_scope(isolate); 2317 HandleScope handle_scope(isolate);
2395 2318
2396 if (args.Length() < 1) { 2319 if (args.Length() < 1) {
2397 Throw(isolate, "Invalid argument"); 2320 Throw(isolate, "Invalid argument");
2398 return; 2321 return;
2399 } 2322 }
2400 2323
2324 SerializationData* data;
jbroman 2017/01/24 18:53:43 Here and elsewhere: managing this memory by hand m
binji 2017/01/25 00:31:35 At the time when I originally wrote some of this,
2401 Local<Value> message = args[0]; 2325 Local<Value> message = args[0];
2402 2326 Local<Value> transfer = Undefined(isolate);
2403 // TODO(binji): Allow transferring from worker to main thread? 2327 if (Shell::SerializeValue(isolate, message, transfer).To(&data)) {
2404 Shell::ObjectList to_transfer;
2405
2406 Shell::ObjectList seen_objects;
2407 SerializationData* data = new SerializationData;
2408 if (Shell::SerializeValue(isolate, message, to_transfer, &seen_objects,
2409 data)) {
2410 DCHECK(args.Data()->IsExternal()); 2328 DCHECK(args.Data()->IsExternal());
2411 Local<External> this_value = Local<External>::Cast(args.Data()); 2329 Local<External> this_value = Local<External>::Cast(args.Data());
2412 Worker* worker = static_cast<Worker*>(this_value->Value()); 2330 Worker* worker = static_cast<Worker*>(this_value->Value());
2413 worker->out_queue_.Enqueue(data); 2331 worker->out_queue_.Enqueue(data);
2414 worker->out_semaphore_.Signal(); 2332 worker->out_semaphore_.Signal();
2415 } else {
2416 delete data;
2417 } 2333 }
2418 } 2334 }
2419 2335
2420 2336
2421 void SetFlagsFromString(const char* flags) { 2337 void SetFlagsFromString(const char* flags) {
2422 v8::V8::SetFlagsFromString(flags, static_cast<int>(strlen(flags))); 2338 v8::V8::SetFlagsFromString(flags, static_cast<int>(strlen(flags)));
2423 } 2339 }
2424 2340
2425 2341
2426 bool Shell::SetOptions(int argc, char* argv[]) { 2342 bool Shell::SetOptions(int argc, char* argv[]) {
(...skipping 170 matching lines...) Expand 10 before | Expand all | Expand 10 after
2597 2513
2598 2514
2599 void Shell::EmptyMessageQueues(Isolate* isolate) { 2515 void Shell::EmptyMessageQueues(Isolate* isolate) {
2600 if (!i::FLAG_verify_predictable) { 2516 if (!i::FLAG_verify_predictable) {
2601 while (v8::platform::PumpMessageLoop(g_platform, isolate)) continue; 2517 while (v8::platform::PumpMessageLoop(g_platform, isolate)) continue;
2602 v8::platform::RunIdleTasks(g_platform, isolate, 2518 v8::platform::RunIdleTasks(g_platform, isolate,
2603 50.0 / base::Time::kMillisecondsPerSecond); 2519 50.0 / base::Time::kMillisecondsPerSecond);
2604 } 2520 }
2605 } 2521 }
2606 2522
2607 2523 class Serializer : public ValueSerializer::Delegate {
2608 bool Shell::SerializeValue(Isolate* isolate, Local<Value> value, 2524 public:
2609 const ObjectList& to_transfer, 2525 explicit Serializer(Isolate* isolate)
2610 ObjectList* seen_objects, 2526 : isolate_(isolate), serializer_(isolate, this), data_(nullptr) {}
2611 SerializationData* out_data) { 2527
2612 DCHECK(out_data); 2528 ~Serializer() { delete data_; }
2529
2530 Maybe<bool> WriteValue(Local<Context> context, Local<Value> value,
2531 Local<Value> transfer) {
2532 bool ok;
2533 DCHECK(data_ == nullptr);
2534 data_ = new SerializationData;
2535 if (!PrepareTransfer(context, transfer).To(&ok)) {
2536 return Nothing<bool>();
2537 }
2538 serializer_.WriteHeader();
2539
2540 if (serializer_.WriteValue(context, value).To(&ok)) {
2541 if (!FinalizeTransfer().To(&ok)) {
2542 return Nothing<bool>();
2543 }
2544
2545 std::pair<uint8_t*, size_t> pair = serializer_.Release();
2546 data_->data_ = pair.first;
2547 data_->size_ = pair.second;
2548 return Just(true);
2549 } else {
2550 delete data_;
2551 data_ = nullptr;
2552 }
2553 return Nothing<bool>();
2554 }
2555
2556 SerializationData* Release() {
2557 SerializationData* result = data_;
2558 data_ = nullptr;
2559 return result;
2560 }
2561
2562 protected:
2563 // Implements ValueSerializer::Delegate.
2564 void ThrowDataCloneError(Local<String> message) override {
2565 isolate_->ThrowException(Exception::Error(message));
2566 }
2567
2568 Maybe<uint32_t> GetSharedArrayBufferId(
2569 Isolate* isolate, Local<SharedArrayBuffer> shared_array_buffer) override {
2570 DCHECK(data_ != nullptr);
2571 for (size_t index = 0; index < shared_array_buffers_.size(); ++index) {
2572 if (shared_array_buffers_[index] == shared_array_buffer) {
2573 return Just<uint32_t>(static_cast<uint32_t>(index));
2574 }
2575 }
2576
2577 size_t index = shared_array_buffers_.size();
2578 shared_array_buffers_.emplace_back(isolate_, shared_array_buffer);
2579 return Just<uint32_t>(static_cast<uint32_t>(index));
2580 }
2581
2582 void* ReallocateBufferMemory(void* old_buffer, size_t size,
2583 size_t* actual_size) override {
2584 *actual_size = size;
2585 return realloc(old_buffer, size);
2586 }
2587
2588 void FreeBufferMemory(void* buffer) override { free(buffer); }
2589
2590 private:
2591 Maybe<bool> PrepareTransfer(Local<Context> context, Local<Value> transfer) {
2592 if (transfer->IsArray()) {
2593 Local<Array> transfer_array = Local<Array>::Cast(transfer);
2594 uint32_t length = transfer_array->Length();
2595 for (uint32_t i = 0; i < length; ++i) {
2596 Local<Value> element;
2597 if (transfer_array->Get(context, i).ToLocal(&element)) {
jbroman 2017/01/24 18:53:43 Not new, but this isn't very resilient against cod
binji 2017/01/25 00:31:35 Good point, added a TryCatch.
2598 if (!element->IsArrayBuffer()) {
2599 Throw(isolate_, "Transfer array elements must be an ArrayBuffer");
2600 break;
2601 }
2602
2603 Local<ArrayBuffer> array_buffer = Local<ArrayBuffer>::Cast(element);
2604 serializer_.TransferArrayBuffer(
2605 static_cast<uint32_t>(array_buffers_.size()), array_buffer);
2606 array_buffers_.emplace_back(isolate_, array_buffer);
2607 }
2608 }
2609 return Just(true);
2610 } else if (transfer->IsUndefined()) {
2611 return Just(true);
2612 } else {
2613 Throw(isolate_, "Transfer list must be an Array or undefined");
2614 return Nothing<bool>();
2615 }
2616 }
2617
2618 Maybe<bool> FinalizeTransfer() {
2619 for (const auto& global_array_buffer : array_buffers_) {
2620 Local<ArrayBuffer> array_buffer =
2621 Local<ArrayBuffer>::New(isolate_, global_array_buffer);
2622 if (!array_buffer->IsNeuterable()) {
2623 Throw(isolate_, "ArrayBuffer could not be transferred");
2624 return Nothing<bool>();
2625 }
2626
2627 if (!array_buffer->IsExternal()) {
2628 array_buffer->Externalize();
2629 }
2630 ArrayBuffer::Contents contents = array_buffer->GetContents();
2631 array_buffer->Neuter();
2632 data_->array_buffer_contents_.push_back(contents);
2633 }
2634
2635 for (const auto& global_shared_array_buffer : shared_array_buffers_) {
2636 Local<SharedArrayBuffer> shared_array_buffer =
2637 Local<SharedArrayBuffer>::New(isolate_, global_shared_array_buffer);
2638 if (!shared_array_buffer->IsExternal()) {
2639 shared_array_buffer->Externalize();
2640 }
2641 data_->shared_array_buffer_contents_.push_back(
2642 shared_array_buffer->GetContents());
2643 }
2644
2645 return Just(true);
2646 }
2647
2648 Isolate* isolate_;
2649 ValueSerializer serializer_;
2650 SerializationData* data_;
2651 std::vector<Global<ArrayBuffer>> array_buffers_;
2652 std::vector<Global<SharedArrayBuffer>> shared_array_buffers_;
2653
2654 DISALLOW_COPY_AND_ASSIGN(Serializer);
2655 };
2656
2657 class Deserializer : public ValueDeserializer::Delegate {
2658 public:
2659 Deserializer(Isolate* isolate, SerializationData* data)
2660 : isolate_(isolate),
2661 deserializer_(isolate, data->data(), data->size(), this),
2662 data_(data) {
2663 deserializer_.SetSupportsLegacyWireFormat(true);
2664 }
2665
2666 ~Deserializer() { delete data_; }
2667
2668 MaybeLocal<Value> ReadValue(Local<Context> context) {
2669 bool read_header;
2670 if (!deserializer_.ReadHeader(context).To(&read_header)) {
2671 return MaybeLocal<Value>();
2672 }
2673
2674 uint32_t index = 0;
2675 for (const auto& contents : data_->array_buffer_contents()) {
2676 Local<ArrayBuffer> array_buffer =
2677 ArrayBuffer::New(isolate_, contents.Data(), contents.ByteLength());
2678 deserializer_.TransferArrayBuffer(index++, array_buffer);
2679 }
2680
2681 index = 0;
2682 for (const auto& contents : data_->shared_array_buffer_contents()) {
2683 Local<SharedArrayBuffer> shared_array_buffer = SharedArrayBuffer::New(
2684 isolate_, contents.Data(), contents.ByteLength());
2685 deserializer_.TransferSharedArrayBuffer(index++, shared_array_buffer);
2686 }
2687
2688 MaybeLocal<Value> result = deserializer_.ReadValue(context);
2689 if (!result.IsEmpty()) {
2690 data_->ClearTransferredArrayBuffers();
2691 }
2692 return result;
2693 }
2694
2695 private:
2696 Isolate* isolate_;
2697 ValueDeserializer deserializer_;
2698 SerializationData* data_;
2699
2700 DISALLOW_COPY_AND_ASSIGN(Deserializer);
2701 };
2702
2703 Maybe<SerializationData*> Shell::SerializeValue(Isolate* isolate,
2704 Local<Value> value,
2705 Local<Value> transfer) {
2706 bool ok;
2613 Local<Context> context = isolate->GetCurrentContext(); 2707 Local<Context> context = isolate->GetCurrentContext();
2614 2708 Serializer serializer(isolate);
2615 if (value->IsUndefined()) { 2709 if (serializer.WriteValue(context, value, transfer).To(&ok)) {
2616 out_data->WriteTag(kSerializationTagUndefined); 2710 SerializationData* data = serializer.Release();
2617 } else if (value->IsNull()) { 2711 base::LockGuard<base::Mutex> lock_guard(workers_mutex_.Pointer());
2618 out_data->WriteTag(kSerializationTagNull); 2712 for (const auto& contents : data->shared_array_buffer_contents()) {
2619 } else if (value->IsTrue()) { 2713 externalized_shared_contents_.insert(contents);
2620 out_data->WriteTag(kSerializationTagTrue); 2714 }
2621 } else if (value->IsFalse()) { 2715 return Just(data);
2622 out_data->WriteTag(kSerializationTagFalse); 2716 }
2623 } else if (value->IsNumber()) { 2717 return Nothing<SerializationData*>();
2624 Local<Number> num = Local<Number>::Cast(value);
2625 double value = num->Value();
2626 out_data->WriteTag(kSerializationTagNumber);
2627 out_data->Write(value);
2628 } else if (value->IsString()) {
2629 v8::String::Utf8Value str(value);
2630 out_data->WriteTag(kSerializationTagString);
2631 out_data->Write(str.length());
2632 out_data->WriteMemory(*str, str.length());
2633 } else if (value->IsArray()) {
2634 Local<Array> array = Local<Array>::Cast(value);
2635 if (FindInObjectList(array, *seen_objects)) {
2636 Throw(isolate, "Duplicated arrays not supported");
2637 return false;
2638 }
2639 seen_objects->Add(array);
2640 out_data->WriteTag(kSerializationTagArray);
2641 uint32_t length = array->Length();
2642 out_data->Write(length);
2643 for (uint32_t i = 0; i < length; ++i) {
2644 Local<Value> element_value;
2645 if (array->Get(context, i).ToLocal(&element_value)) {
2646 if (!SerializeValue(isolate, element_value, to_transfer, seen_objects,
2647 out_data))
2648 return false;
2649 } else {
2650 Throw(isolate, "Failed to serialize array element.");
2651 return false;
2652 }
2653 }
2654 } else if (value->IsArrayBuffer()) {
2655 Local<ArrayBuffer> array_buffer = Local<ArrayBuffer>::Cast(value);
2656 if (FindInObjectList(array_buffer, *seen_objects)) {
2657 Throw(isolate, "Duplicated array buffers not supported");
2658 return false;
2659 }
2660 seen_objects->Add(array_buffer);
2661 if (FindInObjectList(array_buffer, to_transfer)) {
2662 // Transfer ArrayBuffer
2663 if (!array_buffer->IsNeuterable()) {
2664 Throw(isolate, "Attempting to transfer an un-neuterable ArrayBuffer");
2665 return false;
2666 }
2667
2668 ArrayBuffer::Contents contents = array_buffer->IsExternal()
2669 ? array_buffer->GetContents()
2670 : array_buffer->Externalize();
2671 array_buffer->Neuter();
2672 out_data->WriteArrayBufferContents(contents);
2673 } else {
2674 ArrayBuffer::Contents contents = array_buffer->GetContents();
2675 // Clone ArrayBuffer
2676 if (contents.ByteLength() > i::kMaxInt) {
2677 Throw(isolate, "ArrayBuffer is too big to clone");
2678 return false;
2679 }
2680
2681 int32_t byte_length = static_cast<int32_t>(contents.ByteLength());
2682 out_data->WriteTag(kSerializationTagArrayBuffer);
2683 out_data->Write(byte_length);
2684 out_data->WriteMemory(contents.Data(), byte_length);
2685 }
2686 } else if (value->IsSharedArrayBuffer()) {
2687 Local<SharedArrayBuffer> sab = Local<SharedArrayBuffer>::Cast(value);
2688 if (FindInObjectList(sab, *seen_objects)) {
2689 Throw(isolate, "Duplicated shared array buffers not supported");
2690 return false;
2691 }
2692 seen_objects->Add(sab);
2693 if (!FindInObjectList(sab, to_transfer)) {
2694 Throw(isolate, "SharedArrayBuffer must be transferred");
2695 return false;
2696 }
2697
2698 SharedArrayBuffer::Contents contents;
2699 if (sab->IsExternal()) {
2700 contents = sab->GetContents();
2701 } else {
2702 contents = sab->Externalize();
2703 base::LockGuard<base::Mutex> lock_guard(workers_mutex_.Pointer());
2704 externalized_shared_contents_.Add(contents);
2705 }
2706 out_data->WriteSharedArrayBufferContents(contents);
2707 } else if (value->IsObject()) {
2708 Local<Object> object = Local<Object>::Cast(value);
2709 if (FindInObjectList(object, *seen_objects)) {
2710 Throw(isolate, "Duplicated objects not supported");
2711 return false;
2712 }
2713 seen_objects->Add(object);
2714 Local<Array> property_names;
2715 if (!object->GetOwnPropertyNames(context).ToLocal(&property_names)) {
2716 Throw(isolate, "Unable to get property names");
2717 return false;
2718 }
2719
2720 uint32_t length = property_names->Length();
2721 out_data->WriteTag(kSerializationTagObject);
2722 out_data->Write(length);
2723 for (uint32_t i = 0; i < length; ++i) {
2724 Local<Value> name;
2725 Local<Value> property_value;
2726 if (property_names->Get(context, i).ToLocal(&name) &&
2727 object->Get(context, name).ToLocal(&property_value)) {
2728 if (!SerializeValue(isolate, name, to_transfer, seen_objects, out_data))
2729 return false;
2730 if (!SerializeValue(isolate, property_value, to_transfer, seen_objects,
2731 out_data))
2732 return false;
2733 } else {
2734 Throw(isolate, "Failed to serialize property.");
2735 return false;
2736 }
2737 }
2738 } else {
2739 Throw(isolate, "Don't know how to serialize object");
2740 return false;
2741 }
2742
2743 return true;
2744 } 2718 }
2745 2719
2746
2747 MaybeLocal<Value> Shell::DeserializeValue(Isolate* isolate, 2720 MaybeLocal<Value> Shell::DeserializeValue(Isolate* isolate,
2748 const SerializationData& data, 2721 SerializationData* data) {
2749 int* offset) { 2722 Local<Value> value;
2750 DCHECK(offset); 2723 Local<Context> context = isolate->GetCurrentContext();
2751 EscapableHandleScope scope(isolate); 2724 Deserializer deserializer(isolate, data);
2752 Local<Value> result; 2725 if (deserializer.ReadValue(context).ToLocal(&value)) {
2753 SerializationTag tag = data.ReadTag(offset); 2726 return MaybeLocal<Value>(value);
2754 2727 }
2755 switch (tag) { 2728 return MaybeLocal<Value>();
2756 case kSerializationTagUndefined:
2757 result = Undefined(isolate);
2758 break;
2759 case kSerializationTagNull:
2760 result = Null(isolate);
2761 break;
2762 case kSerializationTagTrue:
2763 result = True(isolate);
2764 break;
2765 case kSerializationTagFalse:
2766 result = False(isolate);
2767 break;
2768 case kSerializationTagNumber:
2769 result = Number::New(isolate, data.Read<double>(offset));
2770 break;
2771 case kSerializationTagString: {
2772 int length = data.Read<int>(offset);
2773 CHECK(length >= 0);
2774 std::vector<char> buffer(length + 1); // + 1 so it is never empty.
2775 data.ReadMemory(&buffer[0], length, offset);
2776 MaybeLocal<String> str =
2777 String::NewFromUtf8(isolate, &buffer[0], NewStringType::kNormal,
2778 length).ToLocalChecked();
2779 if (!str.IsEmpty()) result = str.ToLocalChecked();
2780 break;
2781 }
2782 case kSerializationTagArray: {
2783 uint32_t length = data.Read<uint32_t>(offset);
2784 Local<Array> array = Array::New(isolate, length);
2785 for (uint32_t i = 0; i < length; ++i) {
2786 Local<Value> element_value;
2787 CHECK(DeserializeValue(isolate, data, offset).ToLocal(&element_value));
2788 array->Set(isolate->GetCurrentContext(), i, element_value).FromJust();
2789 }
2790 result = array;
2791 break;
2792 }
2793 case kSerializationTagObject: {
2794 int length = data.Read<int>(offset);
2795 Local<Object> object = Object::New(isolate);
2796 for (int i = 0; i < length; ++i) {
2797 Local<Value> property_name;
2798 CHECK(DeserializeValue(isolate, data, offset).ToLocal(&property_name));
2799 Local<Value> property_value;
2800 CHECK(DeserializeValue(isolate, data, offset).ToLocal(&property_value));
2801 object->Set(isolate->GetCurrentContext(), property_name, property_value)
2802 .FromJust();
2803 }
2804 result = object;
2805 break;
2806 }
2807 case kSerializationTagArrayBuffer: {
2808 int32_t byte_length = data.Read<int32_t>(offset);
2809 Local<ArrayBuffer> array_buffer = ArrayBuffer::New(isolate, byte_length);
2810 ArrayBuffer::Contents contents = array_buffer->GetContents();
2811 DCHECK(static_cast<size_t>(byte_length) == contents.ByteLength());
2812 data.ReadMemory(contents.Data(), byte_length, offset);
2813 result = array_buffer;
2814 break;
2815 }
2816 case kSerializationTagTransferredArrayBuffer: {
2817 ArrayBuffer::Contents contents;
2818 data.ReadArrayBufferContents(&contents, offset);
2819 result = ArrayBuffer::New(isolate, contents.Data(), contents.ByteLength(),
2820 ArrayBufferCreationMode::kInternalized);
2821 break;
2822 }
2823 case kSerializationTagTransferredSharedArrayBuffer: {
2824 SharedArrayBuffer::Contents contents;
2825 data.ReadSharedArrayBufferContents(&contents, offset);
2826 result = SharedArrayBuffer::New(isolate, contents.Data(),
2827 contents.ByteLength());
2828 break;
2829 }
2830 default:
2831 UNREACHABLE();
2832 }
2833
2834 return scope.Escape(result);
2835 } 2729 }
2836 2730
2837 2731
2838 void Shell::CleanupWorkers() { 2732 void Shell::CleanupWorkers() {
2839 // Make a copy of workers_, because we don't want to call Worker::Terminate 2733 // Make a copy of workers_, because we don't want to call Worker::Terminate
2840 // while holding the workers_mutex_ lock. Otherwise, if a worker is about to 2734 // while holding the workers_mutex_ lock. Otherwise, if a worker is about to
2841 // create a new Worker, it would deadlock. 2735 // create a new Worker, it would deadlock.
2842 i::List<Worker*> workers_copy; 2736 i::List<Worker*> workers_copy;
2843 { 2737 {
2844 base::LockGuard<base::Mutex> lock_guard(workers_mutex_.Pointer()); 2738 base::LockGuard<base::Mutex> lock_guard(workers_mutex_.Pointer());
2845 allow_new_workers_ = false; 2739 allow_new_workers_ = false;
2846 workers_copy.AddAll(workers_); 2740 workers_copy.AddAll(workers_);
2847 workers_.Clear(); 2741 workers_.Clear();
2848 } 2742 }
2849 2743
2850 for (int i = 0; i < workers_copy.length(); ++i) { 2744 for (int i = 0; i < workers_copy.length(); ++i) {
2851 Worker* worker = workers_copy[i]; 2745 Worker* worker = workers_copy[i];
2852 worker->WaitForThread(); 2746 worker->WaitForThread();
2853 delete worker; 2747 delete worker;
2854 } 2748 }
2855 2749
2856 // Now that all workers are terminated, we can re-enable Worker creation. 2750 // Now that all workers are terminated, we can re-enable Worker creation.
2857 base::LockGuard<base::Mutex> lock_guard(workers_mutex_.Pointer()); 2751 base::LockGuard<base::Mutex> lock_guard(workers_mutex_.Pointer());
2858 allow_new_workers_ = true; 2752 allow_new_workers_ = true;
2859 2753
2860 for (int i = 0; i < externalized_shared_contents_.length(); ++i) { 2754 for (const auto& contents : externalized_shared_contents_) {
2861 const SharedArrayBuffer::Contents& contents =
2862 externalized_shared_contents_[i];
2863 Shell::array_buffer_allocator->Free(contents.Data(), contents.ByteLength()); 2755 Shell::array_buffer_allocator->Free(contents.Data(), contents.ByteLength());
2864 } 2756 }
2865 externalized_shared_contents_.Clear(); 2757 externalized_shared_contents_.clear();
2866 } 2758 }
2867 2759
2868 2760
2869 static void DumpHeapConstants(i::Isolate* isolate) { 2761 static void DumpHeapConstants(i::Isolate* isolate) {
2870 i::Heap* heap = isolate->heap(); 2762 i::Heap* heap = isolate->heap();
2871 2763
2872 // Dump the INSTANCE_TYPES table to the console. 2764 // Dump the INSTANCE_TYPES table to the console.
2873 printf("# List of known V8 instance types.\n"); 2765 printf("# List of known V8 instance types.\n");
2874 #define DUMP_TYPE(T) printf(" %d: \"%s\",\n", i::T, #T); 2766 #define DUMP_TYPE(T) printf(" %d: \"%s\",\n", i::T, #T);
2875 printf("INSTANCE_TYPES = {\n"); 2767 printf("INSTANCE_TYPES = {\n");
(...skipping 207 matching lines...) Expand 10 before | Expand all | Expand 10 after
3083 } 2975 }
3084 2976
3085 } // namespace v8 2977 } // namespace v8
3086 2978
3087 2979
3088 #ifndef GOOGLE3 2980 #ifndef GOOGLE3
3089 int main(int argc, char* argv[]) { 2981 int main(int argc, char* argv[]) {
3090 return v8::Shell::Main(argc, argv); 2982 return v8::Shell::Main(argc, argv);
3091 } 2983 }
3092 #endif 2984 #endif
OLDNEW
« src/d8.h ('K') | « src/d8.h ('k') | test/mjsunit/d8-worker.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698