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
3 // found in the LICENSE file.
4
5
6 // Defined when linking against shared lib on Windows.
7 #if defined(USING_V8_SHARED) && !defined(V8_SHARED)
8 #define V8_SHARED
9 #endif
10
11 #include <errno.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <sys/stat.h>
15
16 #ifdef V8_SHARED
17 #include <assert.h>
18 #endif // V8_SHARED
19
20 #ifndef V8_SHARED
21 #include <algorithm>
22 #include <vector>
23 #endif // !V8_SHARED
24
25 #ifdef V8_SHARED
26 #include "include/v8-testing.h"
27 #endif // V8_SHARED
28
29 #if !defined(V8_SHARED) && defined(ENABLE_GDB_JIT_INTERFACE)
30 #include "src/gdb-jit.h"
31 #endif
32
33 #ifdef ENABLE_VTUNE_JIT_INTERFACE
34 #include "src/third_party/vtune/v8-vtune.h"
35 #endif
36
37 #include "src/d8.h"
38
39 #include "include/libplatform/libplatform.h"
40 #ifndef V8_SHARED
41 #include "src/api.h"
42 #include "src/base/cpu.h"
43 #include "src/base/logging.h"
44 #include "src/base/platform/platform.h"
45 #include "src/base/sys-info.h"
46 #include "src/basic-block-profiler.h"
47 #include "src/snapshot/natives.h"
48 #include "src/utils.h"
49 #include "src/v8.h"
50 #endif // !V8_SHARED
51
52 #if !defined(_WIN32) && !defined(_WIN64)
53 #include <unistd.h> // NOLINT
54 #else
55 #include <windows.h> // NOLINT
56 #if defined(_MSC_VER)
57 #include <crtdbg.h> // NOLINT
58 #endif // defined(_MSC_VER)
59 #endif // !defined(_WIN32) && !defined(_WIN64)
60
61 #ifndef DCHECK
62 #define DCHECK(condition) assert(condition)
63 #endif
64
65 #ifndef CHECK
66 #define CHECK(condition) assert(condition)
67 #endif
68
69 namespace v8 {
70
71 namespace {
72
73 const int MB = 1024 * 1024;
74 #ifndef V8_SHARED
75 const int kMaxWorkers = 50;
76 #endif
77
78
79 class ShellArrayBufferAllocator : public v8::ArrayBuffer::Allocator {
80 public:
Allocate(size_t length)81 virtual void* Allocate(size_t length) {
82 void* data = AllocateUninitialized(length);
83 return data == NULL ? data : memset(data, 0, length);
84 }
AllocateUninitialized(size_t length)85 virtual void* AllocateUninitialized(size_t length) { return malloc(length); }
Free(void * data,size_t)86 virtual void Free(void* data, size_t) { free(data); }
87 };
88
89
90 class MockArrayBufferAllocator : public v8::ArrayBuffer::Allocator {
91 public:
Allocate(size_t length)92 void* Allocate(size_t length) override {
93 size_t actual_length = length > 10 * MB ? 1 : length;
94 void* data = AllocateUninitialized(actual_length);
95 return data == NULL ? data : memset(data, 0, actual_length);
96 }
AllocateUninitialized(size_t length)97 void* AllocateUninitialized(size_t length) override {
98 return length > 10 * MB ? malloc(1) : malloc(length);
99 }
Free(void * p,size_t)100 void Free(void* p, size_t) override { free(p); }
101 };
102
103
104 #ifndef V8_SHARED
105 // Predictable v8::Platform implementation. All background and foreground
106 // tasks are run immediately, delayed tasks are not executed at all.
107 class PredictablePlatform : public Platform {
108 public:
PredictablePlatform()109 PredictablePlatform() {}
110
CallOnBackgroundThread(Task * task,ExpectedRuntime expected_runtime)111 void CallOnBackgroundThread(Task* task,
112 ExpectedRuntime expected_runtime) override {
113 task->Run();
114 delete task;
115 }
116
CallOnForegroundThread(v8::Isolate * isolate,Task * task)117 void CallOnForegroundThread(v8::Isolate* isolate, Task* task) override {
118 task->Run();
119 delete task;
120 }
121
CallDelayedOnForegroundThread(v8::Isolate * isolate,Task * task,double delay_in_seconds)122 void CallDelayedOnForegroundThread(v8::Isolate* isolate, Task* task,
123 double delay_in_seconds) override {
124 delete task;
125 }
126
CallIdleOnForegroundThread(v8::Isolate * isolate,IdleTask * task)127 void CallIdleOnForegroundThread(v8::Isolate* isolate,
128 IdleTask* task) override {
129 UNREACHABLE();
130 }
131
IdleTasksEnabled(v8::Isolate * isolate)132 bool IdleTasksEnabled(v8::Isolate* isolate) override { return false; }
133
MonotonicallyIncreasingTime()134 double MonotonicallyIncreasingTime() override {
135 return synthetic_time_in_sec_ += 0.00001;
136 }
137
AddTraceEvent(char phase,const uint8_t * categoryEnabledFlag,const char * name,uint64_t id,uint64_t bind_id,int numArgs,const char ** argNames,const uint8_t * argTypes,const uint64_t * argValues,unsigned int flags)138 uint64_t AddTraceEvent(char phase, const uint8_t* categoryEnabledFlag,
139 const char* name, uint64_t id, uint64_t bind_id,
140 int numArgs, const char** argNames,
141 const uint8_t* argTypes, const uint64_t* argValues,
142 unsigned int flags) override {
143 return 0;
144 }
145
UpdateTraceEventDuration(const uint8_t * categoryEnabledFlag,const char * name,uint64_t handle)146 void UpdateTraceEventDuration(const uint8_t* categoryEnabledFlag,
147 const char* name, uint64_t handle) override {}
148
GetCategoryGroupEnabled(const char * name)149 const uint8_t* GetCategoryGroupEnabled(const char* name) override {
150 static uint8_t no = 0;
151 return &no;
152 }
153
GetCategoryGroupName(const uint8_t * categoryEnabledFlag)154 const char* GetCategoryGroupName(
155 const uint8_t* categoryEnabledFlag) override {
156 static const char* dummy = "dummy";
157 return dummy;
158 }
159
160 private:
161 double synthetic_time_in_sec_ = 0.0;
162
163 DISALLOW_COPY_AND_ASSIGN(PredictablePlatform);
164 };
165 #endif // !V8_SHARED
166
167
168 v8::Platform* g_platform = NULL;
169
170
Throw(Isolate * isolate,const char * message)171 static Local<Value> Throw(Isolate* isolate, const char* message) {
172 return isolate->ThrowException(
173 String::NewFromUtf8(isolate, message, NewStringType::kNormal)
174 .ToLocalChecked());
175 }
176
177
178 #ifndef V8_SHARED
FindInObjectList(Local<Object> object,const Shell::ObjectList & list)179 bool FindInObjectList(Local<Object> object, const Shell::ObjectList& list) {
180 for (int i = 0; i < list.length(); ++i) {
181 if (list[i]->StrictEquals(object)) {
182 return true;
183 }
184 }
185 return false;
186 }
187
188
GetWorkerFromInternalField(Isolate * isolate,Local<Object> object)189 Worker* GetWorkerFromInternalField(Isolate* isolate, Local<Object> object) {
190 if (object->InternalFieldCount() != 1) {
191 Throw(isolate, "this is not a Worker");
192 return NULL;
193 }
194
195 Worker* worker =
196 static_cast<Worker*>(object->GetAlignedPointerFromInternalField(0));
197 if (worker == NULL) {
198 Throw(isolate, "Worker is defunct because main thread is terminating");
199 return NULL;
200 }
201
202 return worker;
203 }
204 #endif // !V8_SHARED
205
206
207 } // namespace
208
209
210 class PerIsolateData {
211 public:
PerIsolateData(Isolate * isolate)212 explicit PerIsolateData(Isolate* isolate) : isolate_(isolate), realms_(NULL) {
213 HandleScope scope(isolate);
214 isolate->SetData(0, this);
215 }
216
~PerIsolateData()217 ~PerIsolateData() {
218 isolate_->SetData(0, NULL); // Not really needed, just to be sure...
219 }
220
Get(Isolate * isolate)221 inline static PerIsolateData* Get(Isolate* isolate) {
222 return reinterpret_cast<PerIsolateData*>(isolate->GetData(0));
223 }
224
225 class RealmScope {
226 public:
227 explicit RealmScope(PerIsolateData* data);
228 ~RealmScope();
229 private:
230 PerIsolateData* data_;
231 };
232
233 private:
234 friend class Shell;
235 friend class RealmScope;
236 Isolate* isolate_;
237 int realm_count_;
238 int realm_current_;
239 int realm_switch_;
240 Global<Context>* realms_;
241 Global<Value> realm_shared_;
242
243 int RealmIndexOrThrow(const v8::FunctionCallbackInfo<v8::Value>& args,
244 int arg_offset);
245 int RealmFind(Local<Context> context);
246 };
247
248
249 #ifndef V8_SHARED
250 CounterMap* Shell::counter_map_;
251 base::OS::MemoryMappedFile* Shell::counters_file_ = NULL;
252 CounterCollection Shell::local_counters_;
253 CounterCollection* Shell::counters_ = &local_counters_;
254 base::LazyMutex Shell::context_mutex_;
255 const base::TimeTicks Shell::kInitialTicks =
256 base::TimeTicks::HighResolutionNow();
257 Global<Context> Shell::utility_context_;
258 base::LazyMutex Shell::workers_mutex_;
259 bool Shell::allow_new_workers_ = true;
260 i::List<Worker*> Shell::workers_;
261 i::List<SharedArrayBuffer::Contents> Shell::externalized_shared_contents_;
262 #endif // !V8_SHARED
263
264 Global<Context> Shell::evaluation_context_;
265 ArrayBuffer::Allocator* Shell::array_buffer_allocator;
266 ShellOptions Shell::options;
267 base::OnceType Shell::quit_once_ = V8_ONCE_INIT;
268
269 #ifndef V8_SHARED
Match(void * key1,void * key2)270 bool CounterMap::Match(void* key1, void* key2) {
271 const char* name1 = reinterpret_cast<const char*>(key1);
272 const char* name2 = reinterpret_cast<const char*>(key2);
273 return strcmp(name1, name2) == 0;
274 }
275 #endif // !V8_SHARED
276
277
278 // Converts a V8 value to a C string.
ToCString(const v8::String::Utf8Value & value)279 const char* Shell::ToCString(const v8::String::Utf8Value& value) {
280 return *value ? *value : "<string conversion failed>";
281 }
282
283
CompileForCachedData(Local<String> source,Local<Value> name,ScriptCompiler::CompileOptions compile_options)284 ScriptCompiler::CachedData* CompileForCachedData(
285 Local<String> source, Local<Value> name,
286 ScriptCompiler::CompileOptions compile_options) {
287 int source_length = source->Length();
288 uint16_t* source_buffer = new uint16_t[source_length];
289 source->Write(source_buffer, 0, source_length);
290 int name_length = 0;
291 uint16_t* name_buffer = NULL;
292 if (name->IsString()) {
293 Local<String> name_string = Local<String>::Cast(name);
294 name_length = name_string->Length();
295 name_buffer = new uint16_t[name_length];
296 name_string->Write(name_buffer, 0, name_length);
297 }
298 Isolate::CreateParams create_params;
299 create_params.array_buffer_allocator = Shell::array_buffer_allocator;
300 Isolate* temp_isolate = Isolate::New(create_params);
301 ScriptCompiler::CachedData* result = NULL;
302 {
303 Isolate::Scope isolate_scope(temp_isolate);
304 HandleScope handle_scope(temp_isolate);
305 Context::Scope context_scope(Context::New(temp_isolate));
306 Local<String> source_copy =
307 v8::String::NewFromTwoByte(temp_isolate, source_buffer,
308 v8::NewStringType::kNormal,
309 source_length).ToLocalChecked();
310 Local<Value> name_copy;
311 if (name_buffer) {
312 name_copy = v8::String::NewFromTwoByte(temp_isolate, name_buffer,
313 v8::NewStringType::kNormal,
314 name_length).ToLocalChecked();
315 } else {
316 name_copy = v8::Undefined(temp_isolate);
317 }
318 ScriptCompiler::Source script_source(source_copy, ScriptOrigin(name_copy));
319 if (!ScriptCompiler::CompileUnboundScript(temp_isolate, &script_source,
320 compile_options).IsEmpty() &&
321 script_source.GetCachedData()) {
322 int length = script_source.GetCachedData()->length;
323 uint8_t* cache = new uint8_t[length];
324 memcpy(cache, script_source.GetCachedData()->data, length);
325 result = new ScriptCompiler::CachedData(
326 cache, length, ScriptCompiler::CachedData::BufferOwned);
327 }
328 }
329 temp_isolate->Dispose();
330 delete[] source_buffer;
331 delete[] name_buffer;
332 return result;
333 }
334
335
336 // Compile a string within the current v8 context.
CompileString(Isolate * isolate,Local<String> source,Local<Value> name,ScriptCompiler::CompileOptions compile_options,SourceType source_type)337 MaybeLocal<Script> Shell::CompileString(
338 Isolate* isolate, Local<String> source, Local<Value> name,
339 ScriptCompiler::CompileOptions compile_options, SourceType source_type) {
340 Local<Context> context(isolate->GetCurrentContext());
341 ScriptOrigin origin(name);
342 if (compile_options == ScriptCompiler::kNoCompileOptions) {
343 ScriptCompiler::Source script_source(source, origin);
344 return source_type == SCRIPT
345 ? ScriptCompiler::Compile(context, &script_source,
346 compile_options)
347 : ScriptCompiler::CompileModule(context, &script_source,
348 compile_options);
349 }
350
351 ScriptCompiler::CachedData* data =
352 CompileForCachedData(source, name, compile_options);
353 ScriptCompiler::Source cached_source(source, origin, data);
354 if (compile_options == ScriptCompiler::kProduceCodeCache) {
355 compile_options = ScriptCompiler::kConsumeCodeCache;
356 } else if (compile_options == ScriptCompiler::kProduceParserCache) {
357 compile_options = ScriptCompiler::kConsumeParserCache;
358 } else {
359 DCHECK(false); // A new compile option?
360 }
361 if (data == NULL) compile_options = ScriptCompiler::kNoCompileOptions;
362 MaybeLocal<Script> result =
363 source_type == SCRIPT
364 ? ScriptCompiler::Compile(context, &cached_source, compile_options)
365 : ScriptCompiler::CompileModule(context, &cached_source,
366 compile_options);
367 CHECK(data == NULL || !data->rejected);
368 return result;
369 }
370
371
372 // Executes a string within the current v8 context.
ExecuteString(Isolate * isolate,Local<String> source,Local<Value> name,bool print_result,bool report_exceptions,SourceType source_type)373 bool Shell::ExecuteString(Isolate* isolate, Local<String> source,
374 Local<Value> name, bool print_result,
375 bool report_exceptions, SourceType source_type) {
376 HandleScope handle_scope(isolate);
377 TryCatch try_catch(isolate);
378
379 MaybeLocal<Value> maybe_result;
380 {
381 PerIsolateData* data = PerIsolateData::Get(isolate);
382 Local<Context> realm =
383 Local<Context>::New(isolate, data->realms_[data->realm_current_]);
384 Context::Scope context_scope(realm);
385 Local<Script> script;
386 if (!Shell::CompileString(isolate, source, name, options.compile_options,
387 source_type).ToLocal(&script)) {
388 // Print errors that happened during compilation.
389 if (report_exceptions) ReportException(isolate, &try_catch);
390 return false;
391 }
392 maybe_result = script->Run(realm);
393 EmptyMessageQueues(isolate);
394 data->realm_current_ = data->realm_switch_;
395 }
396 Local<Value> result;
397 if (!maybe_result.ToLocal(&result)) {
398 DCHECK(try_catch.HasCaught());
399 // Print errors that happened during execution.
400 if (report_exceptions) ReportException(isolate, &try_catch);
401 return false;
402 }
403 DCHECK(!try_catch.HasCaught());
404 if (print_result) {
405 #if !defined(V8_SHARED)
406 if (options.test_shell) {
407 #endif
408 if (!result->IsUndefined()) {
409 // If all went well and the result wasn't undefined then print
410 // the returned value.
411 v8::String::Utf8Value str(result);
412 fwrite(*str, sizeof(**str), str.length(), stdout);
413 printf("\n");
414 }
415 #if !defined(V8_SHARED)
416 } else {
417 v8::TryCatch try_catch(isolate);
418 v8::Local<v8::Context> context =
419 v8::Local<v8::Context>::New(isolate, utility_context_);
420 v8::Context::Scope context_scope(context);
421 Local<Object> global = context->Global();
422 Local<Value> fun =
423 global->Get(context, String::NewFromUtf8(isolate, "Stringify",
424 v8::NewStringType::kNormal)
425 .ToLocalChecked()).ToLocalChecked();
426 Local<Value> argv[1] = {result};
427 Local<Value> s;
428 if (!Local<Function>::Cast(fun)
429 ->Call(context, global, 1, argv)
430 .ToLocal(&s)) {
431 return true;
432 }
433 DCHECK(!try_catch.HasCaught());
434 v8::String::Utf8Value str(s);
435 fwrite(*str, sizeof(**str), str.length(), stdout);
436 printf("\n");
437 }
438 #endif
439 }
440 return true;
441 }
442
443
RealmScope(PerIsolateData * data)444 PerIsolateData::RealmScope::RealmScope(PerIsolateData* data) : data_(data) {
445 data_->realm_count_ = 1;
446 data_->realm_current_ = 0;
447 data_->realm_switch_ = 0;
448 data_->realms_ = new Global<Context>[1];
449 data_->realms_[0].Reset(data_->isolate_,
450 data_->isolate_->GetEnteredContext());
451 }
452
453
~RealmScope()454 PerIsolateData::RealmScope::~RealmScope() {
455 // Drop realms to avoid keeping them alive.
456 for (int i = 0; i < data_->realm_count_; ++i)
457 data_->realms_[i].Reset();
458 delete[] data_->realms_;
459 if (!data_->realm_shared_.IsEmpty())
460 data_->realm_shared_.Reset();
461 }
462
463
RealmFind(Local<Context> context)464 int PerIsolateData::RealmFind(Local<Context> context) {
465 for (int i = 0; i < realm_count_; ++i) {
466 if (realms_[i] == context) return i;
467 }
468 return -1;
469 }
470
471
RealmIndexOrThrow(const v8::FunctionCallbackInfo<v8::Value> & args,int arg_offset)472 int PerIsolateData::RealmIndexOrThrow(
473 const v8::FunctionCallbackInfo<v8::Value>& args,
474 int arg_offset) {
475 if (args.Length() < arg_offset || !args[arg_offset]->IsNumber()) {
476 Throw(args.GetIsolate(), "Invalid argument");
477 return -1;
478 }
479 int index = args[arg_offset]
480 ->Int32Value(args.GetIsolate()->GetCurrentContext())
481 .FromMaybe(-1);
482 if (index < 0 || index >= realm_count_ || realms_[index].IsEmpty()) {
483 Throw(args.GetIsolate(), "Invalid realm index");
484 return -1;
485 }
486 return index;
487 }
488
489
490 #ifndef V8_SHARED
491 // performance.now() returns a time stamp as double, measured in milliseconds.
492 // When FLAG_verify_predictable mode is enabled it returns result of
493 // v8::Platform::MonotonicallyIncreasingTime().
PerformanceNow(const v8::FunctionCallbackInfo<v8::Value> & args)494 void Shell::PerformanceNow(const v8::FunctionCallbackInfo<v8::Value>& args) {
495 if (i::FLAG_verify_predictable) {
496 args.GetReturnValue().Set(g_platform->MonotonicallyIncreasingTime());
497 } else {
498 base::TimeDelta delta =
499 base::TimeTicks::HighResolutionNow() - kInitialTicks;
500 args.GetReturnValue().Set(delta.InMillisecondsF());
501 }
502 }
503 #endif // !V8_SHARED
504
505
506 // Realm.current() returns the index of the currently active realm.
RealmCurrent(const v8::FunctionCallbackInfo<v8::Value> & args)507 void Shell::RealmCurrent(const v8::FunctionCallbackInfo<v8::Value>& args) {
508 Isolate* isolate = args.GetIsolate();
509 PerIsolateData* data = PerIsolateData::Get(isolate);
510 int index = data->RealmFind(isolate->GetEnteredContext());
511 if (index == -1) return;
512 args.GetReturnValue().Set(index);
513 }
514
515
516 // Realm.owner(o) returns the index of the realm that created o.
RealmOwner(const v8::FunctionCallbackInfo<v8::Value> & args)517 void Shell::RealmOwner(const v8::FunctionCallbackInfo<v8::Value>& args) {
518 Isolate* isolate = args.GetIsolate();
519 PerIsolateData* data = PerIsolateData::Get(isolate);
520 if (args.Length() < 1 || !args[0]->IsObject()) {
521 Throw(args.GetIsolate(), "Invalid argument");
522 return;
523 }
524 int index = data->RealmFind(args[0]
525 ->ToObject(isolate->GetCurrentContext())
526 .ToLocalChecked()
527 ->CreationContext());
528 if (index == -1) return;
529 args.GetReturnValue().Set(index);
530 }
531
532
533 // Realm.global(i) returns the global object of realm i.
534 // (Note that properties of global objects cannot be read/written cross-realm.)
RealmGlobal(const v8::FunctionCallbackInfo<v8::Value> & args)535 void Shell::RealmGlobal(const v8::FunctionCallbackInfo<v8::Value>& args) {
536 PerIsolateData* data = PerIsolateData::Get(args.GetIsolate());
537 int index = data->RealmIndexOrThrow(args, 0);
538 if (index == -1) return;
539 args.GetReturnValue().Set(
540 Local<Context>::New(args.GetIsolate(), data->realms_[index])->Global());
541 }
542
543
544 // Realm.create() creates a new realm and returns its index.
RealmCreate(const v8::FunctionCallbackInfo<v8::Value> & args)545 void Shell::RealmCreate(const v8::FunctionCallbackInfo<v8::Value>& args) {
546 Isolate* isolate = args.GetIsolate();
547 TryCatch try_catch(isolate);
548 PerIsolateData* data = PerIsolateData::Get(isolate);
549 Global<Context>* old_realms = data->realms_;
550 int index = data->realm_count_;
551 data->realms_ = new Global<Context>[++data->realm_count_];
552 for (int i = 0; i < index; ++i) {
553 data->realms_[i].Reset(isolate, old_realms[i]);
554 old_realms[i].Reset();
555 }
556 delete[] old_realms;
557 Local<ObjectTemplate> global_template = CreateGlobalTemplate(isolate);
558 Local<Context> context = Context::New(isolate, NULL, global_template);
559 if (context.IsEmpty()) {
560 DCHECK(try_catch.HasCaught());
561 try_catch.ReThrow();
562 return;
563 }
564 data->realms_[index].Reset(isolate, context);
565 args.GetReturnValue().Set(index);
566 }
567
568
569 // Realm.dispose(i) disposes the reference to the realm i.
RealmDispose(const v8::FunctionCallbackInfo<v8::Value> & args)570 void Shell::RealmDispose(const v8::FunctionCallbackInfo<v8::Value>& args) {
571 Isolate* isolate = args.GetIsolate();
572 PerIsolateData* data = PerIsolateData::Get(isolate);
573 int index = data->RealmIndexOrThrow(args, 0);
574 if (index == -1) return;
575 if (index == 0 ||
576 index == data->realm_current_ || index == data->realm_switch_) {
577 Throw(args.GetIsolate(), "Invalid realm index");
578 return;
579 }
580 data->realms_[index].Reset();
581 isolate->ContextDisposedNotification();
582 isolate->IdleNotificationDeadline(g_platform->MonotonicallyIncreasingTime());
583 }
584
585
586 // Realm.switch(i) switches to the realm i for consecutive interactive inputs.
RealmSwitch(const v8::FunctionCallbackInfo<v8::Value> & args)587 void Shell::RealmSwitch(const v8::FunctionCallbackInfo<v8::Value>& args) {
588 Isolate* isolate = args.GetIsolate();
589 PerIsolateData* data = PerIsolateData::Get(isolate);
590 int index = data->RealmIndexOrThrow(args, 0);
591 if (index == -1) return;
592 data->realm_switch_ = index;
593 }
594
595
596 // Realm.eval(i, s) evaluates s in realm i and returns the result.
RealmEval(const v8::FunctionCallbackInfo<v8::Value> & args)597 void Shell::RealmEval(const v8::FunctionCallbackInfo<v8::Value>& args) {
598 Isolate* isolate = args.GetIsolate();
599 PerIsolateData* data = PerIsolateData::Get(isolate);
600 int index = data->RealmIndexOrThrow(args, 0);
601 if (index == -1) return;
602 if (args.Length() < 2 || !args[1]->IsString()) {
603 Throw(args.GetIsolate(), "Invalid argument");
604 return;
605 }
606 ScriptCompiler::Source script_source(
607 args[1]->ToString(isolate->GetCurrentContext()).ToLocalChecked());
608 Local<UnboundScript> script;
609 if (!ScriptCompiler::CompileUnboundScript(isolate, &script_source)
610 .ToLocal(&script)) {
611 return;
612 }
613 Local<Context> realm = Local<Context>::New(isolate, data->realms_[index]);
614 realm->Enter();
615 Local<Value> result;
616 if (!script->BindToCurrentContext()->Run(realm).ToLocal(&result)) {
617 realm->Exit();
618 return;
619 }
620 realm->Exit();
621 args.GetReturnValue().Set(result);
622 }
623
624
625 // Realm.shared is an accessor for a single shared value across realms.
RealmSharedGet(Local<String> property,const PropertyCallbackInfo<Value> & info)626 void Shell::RealmSharedGet(Local<String> property,
627 const PropertyCallbackInfo<Value>& info) {
628 Isolate* isolate = info.GetIsolate();
629 PerIsolateData* data = PerIsolateData::Get(isolate);
630 if (data->realm_shared_.IsEmpty()) return;
631 info.GetReturnValue().Set(data->realm_shared_);
632 }
633
RealmSharedSet(Local<String> property,Local<Value> value,const PropertyCallbackInfo<void> & info)634 void Shell::RealmSharedSet(Local<String> property,
635 Local<Value> value,
636 const PropertyCallbackInfo<void>& info) {
637 Isolate* isolate = info.GetIsolate();
638 PerIsolateData* data = PerIsolateData::Get(isolate);
639 data->realm_shared_.Reset(isolate, value);
640 }
641
642
Print(const v8::FunctionCallbackInfo<v8::Value> & args)643 void Shell::Print(const v8::FunctionCallbackInfo<v8::Value>& args) {
644 Write(args);
645 printf("\n");
646 fflush(stdout);
647 }
648
649
Write(const v8::FunctionCallbackInfo<v8::Value> & args)650 void Shell::Write(const v8::FunctionCallbackInfo<v8::Value>& args) {
651 for (int i = 0; i < args.Length(); i++) {
652 HandleScope handle_scope(args.GetIsolate());
653 if (i != 0) {
654 printf(" ");
655 }
656
657 // Explicitly catch potential exceptions in toString().
658 v8::TryCatch try_catch(args.GetIsolate());
659 Local<Value> arg = args[i];
660 Local<String> str_obj;
661
662 if (arg->IsSymbol()) {
663 arg = Local<Symbol>::Cast(arg)->Name();
664 }
665 if (!arg->ToString(args.GetIsolate()->GetCurrentContext())
666 .ToLocal(&str_obj)) {
667 try_catch.ReThrow();
668 return;
669 }
670
671 v8::String::Utf8Value str(str_obj);
672 int n = static_cast<int>(fwrite(*str, sizeof(**str), str.length(), stdout));
673 if (n != str.length()) {
674 printf("Error in fwrite\n");
675 Exit(1);
676 }
677 }
678 }
679
680
Read(const v8::FunctionCallbackInfo<v8::Value> & args)681 void Shell::Read(const v8::FunctionCallbackInfo<v8::Value>& args) {
682 String::Utf8Value file(args[0]);
683 if (*file == NULL) {
684 Throw(args.GetIsolate(), "Error loading file");
685 return;
686 }
687 Local<String> source = ReadFile(args.GetIsolate(), *file);
688 if (source.IsEmpty()) {
689 Throw(args.GetIsolate(), "Error loading file");
690 return;
691 }
692 args.GetReturnValue().Set(source);
693 }
694
695
ReadFromStdin(Isolate * isolate)696 Local<String> Shell::ReadFromStdin(Isolate* isolate) {
697 static const int kBufferSize = 256;
698 char buffer[kBufferSize];
699 Local<String> accumulator =
700 String::NewFromUtf8(isolate, "", NewStringType::kNormal).ToLocalChecked();
701 int length;
702 while (true) {
703 // Continue reading if the line ends with an escape '\\' or the line has
704 // not been fully read into the buffer yet (does not end with '\n').
705 // If fgets gets an error, just give up.
706 char* input = NULL;
707 input = fgets(buffer, kBufferSize, stdin);
708 if (input == NULL) return Local<String>();
709 length = static_cast<int>(strlen(buffer));
710 if (length == 0) {
711 return accumulator;
712 } else if (buffer[length-1] != '\n') {
713 accumulator = String::Concat(
714 accumulator,
715 String::NewFromUtf8(isolate, buffer, NewStringType::kNormal, length)
716 .ToLocalChecked());
717 } else if (length > 1 && buffer[length-2] == '\\') {
718 buffer[length-2] = '\n';
719 accumulator = String::Concat(
720 accumulator,
721 String::NewFromUtf8(isolate, buffer, NewStringType::kNormal,
722 length - 1).ToLocalChecked());
723 } else {
724 return String::Concat(
725 accumulator,
726 String::NewFromUtf8(isolate, buffer, NewStringType::kNormal,
727 length - 1).ToLocalChecked());
728 }
729 }
730 }
731
732
Load(const v8::FunctionCallbackInfo<v8::Value> & args)733 void Shell::Load(const v8::FunctionCallbackInfo<v8::Value>& args) {
734 for (int i = 0; i < args.Length(); i++) {
735 HandleScope handle_scope(args.GetIsolate());
736 String::Utf8Value file(args[i]);
737 if (*file == NULL) {
738 Throw(args.GetIsolate(), "Error loading file");
739 return;
740 }
741 Local<String> source = ReadFile(args.GetIsolate(), *file);
742 if (source.IsEmpty()) {
743 Throw(args.GetIsolate(), "Error loading file");
744 return;
745 }
746 if (!ExecuteString(
747 args.GetIsolate(), source,
748 String::NewFromUtf8(args.GetIsolate(), *file,
749 NewStringType::kNormal).ToLocalChecked(),
750 false, true)) {
751 Throw(args.GetIsolate(), "Error executing file");
752 return;
753 }
754 }
755 }
756
757
758 #ifndef V8_SHARED
WorkerNew(const v8::FunctionCallbackInfo<v8::Value> & args)759 void Shell::WorkerNew(const v8::FunctionCallbackInfo<v8::Value>& args) {
760 Isolate* isolate = args.GetIsolate();
761 HandleScope handle_scope(isolate);
762 if (args.Length() < 1 || !args[0]->IsString()) {
763 Throw(args.GetIsolate(), "1st argument must be string");
764 return;
765 }
766
767 if (!args.IsConstructCall()) {
768 Throw(args.GetIsolate(), "Worker must be constructed with new");
769 return;
770 }
771
772 {
773 base::LockGuard<base::Mutex> lock_guard(workers_mutex_.Pointer());
774 if (workers_.length() >= kMaxWorkers) {
775 Throw(args.GetIsolate(), "Too many workers, I won't let you create more");
776 return;
777 }
778
779 // Initialize the internal field to NULL; if we return early without
780 // creating a new Worker (because the main thread is terminating) we can
781 // early-out from the instance calls.
782 args.Holder()->SetAlignedPointerInInternalField(0, NULL);
783
784 if (!allow_new_workers_) return;
785
786 Worker* worker = new Worker;
787 args.Holder()->SetAlignedPointerInInternalField(0, worker);
788 workers_.Add(worker);
789
790 String::Utf8Value script(args[0]);
791 if (!*script) {
792 Throw(args.GetIsolate(), "Can't get worker script");
793 return;
794 }
795 worker->StartExecuteInThread(*script);
796 }
797 }
798
799
WorkerPostMessage(const v8::FunctionCallbackInfo<v8::Value> & args)800 void Shell::WorkerPostMessage(const v8::FunctionCallbackInfo<v8::Value>& args) {
801 Isolate* isolate = args.GetIsolate();
802 HandleScope handle_scope(isolate);
803 Local<Context> context = isolate->GetCurrentContext();
804
805 if (args.Length() < 1) {
806 Throw(isolate, "Invalid argument");
807 return;
808 }
809
810 Worker* worker = GetWorkerFromInternalField(isolate, args.Holder());
811 if (!worker) {
812 return;
813 }
814
815 Local<Value> message = args[0];
816 ObjectList to_transfer;
817 if (args.Length() >= 2) {
818 if (!args[1]->IsArray()) {
819 Throw(isolate, "Transfer list must be an Array");
820 return;
821 }
822
823 Local<Array> transfer = Local<Array>::Cast(args[1]);
824 uint32_t length = transfer->Length();
825 for (uint32_t i = 0; i < length; ++i) {
826 Local<Value> element;
827 if (transfer->Get(context, i).ToLocal(&element)) {
828 if (!element->IsArrayBuffer() && !element->IsSharedArrayBuffer()) {
829 Throw(isolate,
830 "Transfer array elements must be an ArrayBuffer or "
831 "SharedArrayBuffer.");
832 break;
833 }
834
835 to_transfer.Add(Local<Object>::Cast(element));
836 }
837 }
838 }
839
840 ObjectList seen_objects;
841 SerializationData* data = new SerializationData;
842 if (SerializeValue(isolate, message, to_transfer, &seen_objects, data)) {
843 worker->PostMessage(data);
844 } else {
845 delete data;
846 }
847 }
848
849
WorkerGetMessage(const v8::FunctionCallbackInfo<v8::Value> & args)850 void Shell::WorkerGetMessage(const v8::FunctionCallbackInfo<v8::Value>& args) {
851 Isolate* isolate = args.GetIsolate();
852 HandleScope handle_scope(isolate);
853 Worker* worker = GetWorkerFromInternalField(isolate, args.Holder());
854 if (!worker) {
855 return;
856 }
857
858 SerializationData* data = worker->GetMessage();
859 if (data) {
860 int offset = 0;
861 Local<Value> data_value;
862 if (Shell::DeserializeValue(isolate, *data, &offset).ToLocal(&data_value)) {
863 args.GetReturnValue().Set(data_value);
864 }
865 delete data;
866 }
867 }
868
869
WorkerTerminate(const v8::FunctionCallbackInfo<v8::Value> & args)870 void Shell::WorkerTerminate(const v8::FunctionCallbackInfo<v8::Value>& args) {
871 Isolate* isolate = args.GetIsolate();
872 HandleScope handle_scope(isolate);
873 Worker* worker = GetWorkerFromInternalField(isolate, args.Holder());
874 if (!worker) {
875 return;
876 }
877
878 worker->Terminate();
879 }
880 #endif // !V8_SHARED
881
882
QuitOnce(v8::FunctionCallbackInfo<v8::Value> * args)883 void Shell::QuitOnce(v8::FunctionCallbackInfo<v8::Value>* args) {
884 int exit_code = (*args)[0]
885 ->Int32Value(args->GetIsolate()->GetCurrentContext())
886 .FromMaybe(0);
887 #ifndef V8_SHARED
888 CleanupWorkers();
889 #endif // !V8_SHARED
890 OnExit(args->GetIsolate());
891 Exit(exit_code);
892 }
893
894
Quit(const v8::FunctionCallbackInfo<v8::Value> & args)895 void Shell::Quit(const v8::FunctionCallbackInfo<v8::Value>& args) {
896 base::CallOnce(&quit_once_, &QuitOnce,
897 const_cast<v8::FunctionCallbackInfo<v8::Value>*>(&args));
898 }
899
900
Version(const v8::FunctionCallbackInfo<v8::Value> & args)901 void Shell::Version(const v8::FunctionCallbackInfo<v8::Value>& args) {
902 args.GetReturnValue().Set(
903 String::NewFromUtf8(args.GetIsolate(), V8::GetVersion(),
904 NewStringType::kNormal).ToLocalChecked());
905 }
906
907
ReportException(Isolate * isolate,v8::TryCatch * try_catch)908 void Shell::ReportException(Isolate* isolate, v8::TryCatch* try_catch) {
909 HandleScope handle_scope(isolate);
910 #ifndef V8_SHARED
911 Local<Context> utility_context;
912 bool enter_context = !isolate->InContext();
913 if (enter_context) {
914 utility_context = Local<Context>::New(isolate, utility_context_);
915 utility_context->Enter();
916 }
917 #endif // !V8_SHARED
918 v8::String::Utf8Value exception(try_catch->Exception());
919 const char* exception_string = ToCString(exception);
920 Local<Message> message = try_catch->Message();
921 if (message.IsEmpty()) {
922 // V8 didn't provide any extra information about this error; just
923 // print the exception.
924 printf("%s\n", exception_string);
925 } else {
926 // Print (filename):(line number): (message).
927 v8::String::Utf8Value filename(message->GetScriptOrigin().ResourceName());
928 const char* filename_string = ToCString(filename);
929 int linenum =
930 message->GetLineNumber(isolate->GetCurrentContext()).FromJust();
931 printf("%s:%i: %s\n", filename_string, linenum, exception_string);
932 // Print line of source code.
933 v8::String::Utf8Value sourceline(
934 message->GetSourceLine(isolate->GetCurrentContext()).ToLocalChecked());
935 const char* sourceline_string = ToCString(sourceline);
936 printf("%s\n", sourceline_string);
937 // Print wavy underline (GetUnderline is deprecated).
938 int start =
939 message->GetStartColumn(isolate->GetCurrentContext()).FromJust();
940 for (int i = 0; i < start; i++) {
941 printf(" ");
942 }
943 int end = message->GetEndColumn(isolate->GetCurrentContext()).FromJust();
944 for (int i = start; i < end; i++) {
945 printf("^");
946 }
947 printf("\n");
948 Local<Value> stack_trace_string;
949 if (try_catch->StackTrace(isolate->GetCurrentContext())
950 .ToLocal(&stack_trace_string) &&
951 stack_trace_string->IsString()) {
952 v8::String::Utf8Value stack_trace(
953 Local<String>::Cast(stack_trace_string));
954 printf("%s\n", ToCString(stack_trace));
955 }
956 }
957 printf("\n");
958 #ifndef V8_SHARED
959 if (enter_context) utility_context->Exit();
960 #endif // !V8_SHARED
961 }
962
963
964 #ifndef V8_SHARED
Bind(const char * name,bool is_histogram)965 int32_t* Counter::Bind(const char* name, bool is_histogram) {
966 int i;
967 for (i = 0; i < kMaxNameSize - 1 && name[i]; i++)
968 name_[i] = static_cast<char>(name[i]);
969 name_[i] = '\0';
970 is_histogram_ = is_histogram;
971 return ptr();
972 }
973
974
AddSample(int32_t sample)975 void Counter::AddSample(int32_t sample) {
976 count_++;
977 sample_total_ += sample;
978 }
979
980
CounterCollection()981 CounterCollection::CounterCollection() {
982 magic_number_ = 0xDEADFACE;
983 max_counters_ = kMaxCounters;
984 max_name_size_ = Counter::kMaxNameSize;
985 counters_in_use_ = 0;
986 }
987
988
GetNextCounter()989 Counter* CounterCollection::GetNextCounter() {
990 if (counters_in_use_ == kMaxCounters) return NULL;
991 return &counters_[counters_in_use_++];
992 }
993
994
MapCounters(v8::Isolate * isolate,const char * name)995 void Shell::MapCounters(v8::Isolate* isolate, const char* name) {
996 counters_file_ = base::OS::MemoryMappedFile::create(
997 name, sizeof(CounterCollection), &local_counters_);
998 void* memory = (counters_file_ == NULL) ?
999 NULL : counters_file_->memory();
1000 if (memory == NULL) {
1001 printf("Could not map counters file %s\n", name);
1002 Exit(1);
1003 }
1004 counters_ = static_cast<CounterCollection*>(memory);
1005 isolate->SetCounterFunction(LookupCounter);
1006 isolate->SetCreateHistogramFunction(CreateHistogram);
1007 isolate->SetAddHistogramSampleFunction(AddHistogramSample);
1008 }
1009
1010
Hash(const char * name)1011 int CounterMap::Hash(const char* name) {
1012 int h = 0;
1013 int c;
1014 while ((c = *name++) != 0) {
1015 h += h << 5;
1016 h += c;
1017 }
1018 return h;
1019 }
1020
1021
GetCounter(const char * name,bool is_histogram)1022 Counter* Shell::GetCounter(const char* name, bool is_histogram) {
1023 Counter* counter = counter_map_->Lookup(name);
1024
1025 if (counter == NULL) {
1026 counter = counters_->GetNextCounter();
1027 if (counter != NULL) {
1028 counter_map_->Set(name, counter);
1029 counter->Bind(name, is_histogram);
1030 }
1031 } else {
1032 DCHECK(counter->is_histogram() == is_histogram);
1033 }
1034 return counter;
1035 }
1036
1037
LookupCounter(const char * name)1038 int* Shell::LookupCounter(const char* name) {
1039 Counter* counter = GetCounter(name, false);
1040
1041 if (counter != NULL) {
1042 return counter->ptr();
1043 } else {
1044 return NULL;
1045 }
1046 }
1047
1048
CreateHistogram(const char * name,int min,int max,size_t buckets)1049 void* Shell::CreateHistogram(const char* name,
1050 int min,
1051 int max,
1052 size_t buckets) {
1053 return GetCounter(name, true);
1054 }
1055
1056
AddHistogramSample(void * histogram,int sample)1057 void Shell::AddHistogramSample(void* histogram, int sample) {
1058 Counter* counter = reinterpret_cast<Counter*>(histogram);
1059 counter->AddSample(sample);
1060 }
1061
1062
1063 class NoUseStrongForUtilityScriptScope {
1064 public:
NoUseStrongForUtilityScriptScope()1065 NoUseStrongForUtilityScriptScope() : flag_(i::FLAG_use_strong) {
1066 i::FLAG_use_strong = false;
1067 }
~NoUseStrongForUtilityScriptScope()1068 ~NoUseStrongForUtilityScriptScope() { i::FLAG_use_strong = flag_; }
1069
1070 private:
1071 bool flag_;
1072 };
1073
1074
InstallUtilityScript(Isolate * isolate)1075 void Shell::InstallUtilityScript(Isolate* isolate) {
1076 NoUseStrongForUtilityScriptScope no_use_strong;
1077 HandleScope scope(isolate);
1078 // If we use the utility context, we have to set the security tokens so that
1079 // utility, evaluation and debug context can all access each other.
1080 Local<ObjectTemplate> global_template = CreateGlobalTemplate(isolate);
1081 utility_context_.Reset(isolate, Context::New(isolate, NULL, global_template));
1082 v8::Local<v8::Context> utility_context =
1083 v8::Local<v8::Context>::New(isolate, utility_context_);
1084 v8::Local<v8::Context> evaluation_context =
1085 v8::Local<v8::Context>::New(isolate, evaluation_context_);
1086 utility_context->SetSecurityToken(Undefined(isolate));
1087 evaluation_context->SetSecurityToken(Undefined(isolate));
1088 v8::Context::Scope context_scope(utility_context);
1089
1090 // Run the d8 shell utility script in the utility context
1091 int source_index = i::NativesCollection<i::D8>::GetIndex("d8");
1092 i::Vector<const char> shell_source =
1093 i::NativesCollection<i::D8>::GetScriptSource(source_index);
1094 i::Vector<const char> shell_source_name =
1095 i::NativesCollection<i::D8>::GetScriptName(source_index);
1096 Local<String> source =
1097 String::NewFromUtf8(isolate, shell_source.start(), NewStringType::kNormal,
1098 shell_source.length()).ToLocalChecked();
1099 Local<String> name =
1100 String::NewFromUtf8(isolate, shell_source_name.start(),
1101 NewStringType::kNormal,
1102 shell_source_name.length()).ToLocalChecked();
1103 ScriptOrigin origin(name);
1104 Local<Script> script =
1105 Script::Compile(utility_context, source, &origin).ToLocalChecked();
1106 script->Run(utility_context).ToLocalChecked();
1107 // Mark the d8 shell script as native to avoid it showing up as normal source
1108 // in the debugger.
1109 i::Handle<i::Object> compiled_script = Utils::OpenHandle(*script);
1110 i::Handle<i::Script> script_object = compiled_script->IsJSFunction()
1111 ? i::Handle<i::Script>(i::Script::cast(
1112 i::JSFunction::cast(*compiled_script)->shared()->script()))
1113 : i::Handle<i::Script>(i::Script::cast(
1114 i::SharedFunctionInfo::cast(*compiled_script)->script()));
1115 script_object->set_type(i::Script::TYPE_EXTENSION);
1116 }
1117 #endif // !V8_SHARED
1118
1119
CreateGlobalTemplate(Isolate * isolate)1120 Local<ObjectTemplate> Shell::CreateGlobalTemplate(Isolate* isolate) {
1121 Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
1122 global_template->Set(
1123 String::NewFromUtf8(isolate, "print", NewStringType::kNormal)
1124 .ToLocalChecked(),
1125 FunctionTemplate::New(isolate, Print));
1126 global_template->Set(
1127 String::NewFromUtf8(isolate, "write", NewStringType::kNormal)
1128 .ToLocalChecked(),
1129 FunctionTemplate::New(isolate, Write));
1130 global_template->Set(
1131 String::NewFromUtf8(isolate, "read", NewStringType::kNormal)
1132 .ToLocalChecked(),
1133 FunctionTemplate::New(isolate, Read));
1134 global_template->Set(
1135 String::NewFromUtf8(isolate, "readbuffer", NewStringType::kNormal)
1136 .ToLocalChecked(),
1137 FunctionTemplate::New(isolate, ReadBuffer));
1138 global_template->Set(
1139 String::NewFromUtf8(isolate, "readline", NewStringType::kNormal)
1140 .ToLocalChecked(),
1141 FunctionTemplate::New(isolate, ReadLine));
1142 global_template->Set(
1143 String::NewFromUtf8(isolate, "load", NewStringType::kNormal)
1144 .ToLocalChecked(),
1145 FunctionTemplate::New(isolate, Load));
1146 // Some Emscripten-generated code tries to call 'quit', which in turn would
1147 // call C's exit(). This would lead to memory leaks, because there is no way
1148 // we can terminate cleanly then, so we need a way to hide 'quit'.
1149 if (!options.omit_quit) {
1150 global_template->Set(
1151 String::NewFromUtf8(isolate, "quit", NewStringType::kNormal)
1152 .ToLocalChecked(),
1153 FunctionTemplate::New(isolate, Quit));
1154 }
1155 global_template->Set(
1156 String::NewFromUtf8(isolate, "version", NewStringType::kNormal)
1157 .ToLocalChecked(),
1158 FunctionTemplate::New(isolate, Version));
1159
1160 // Bind the Realm object.
1161 Local<ObjectTemplate> realm_template = ObjectTemplate::New(isolate);
1162 realm_template->Set(
1163 String::NewFromUtf8(isolate, "current", NewStringType::kNormal)
1164 .ToLocalChecked(),
1165 FunctionTemplate::New(isolate, RealmCurrent));
1166 realm_template->Set(
1167 String::NewFromUtf8(isolate, "owner", NewStringType::kNormal)
1168 .ToLocalChecked(),
1169 FunctionTemplate::New(isolate, RealmOwner));
1170 realm_template->Set(
1171 String::NewFromUtf8(isolate, "global", NewStringType::kNormal)
1172 .ToLocalChecked(),
1173 FunctionTemplate::New(isolate, RealmGlobal));
1174 realm_template->Set(
1175 String::NewFromUtf8(isolate, "create", NewStringType::kNormal)
1176 .ToLocalChecked(),
1177 FunctionTemplate::New(isolate, RealmCreate));
1178 realm_template->Set(
1179 String::NewFromUtf8(isolate, "dispose", NewStringType::kNormal)
1180 .ToLocalChecked(),
1181 FunctionTemplate::New(isolate, RealmDispose));
1182 realm_template->Set(
1183 String::NewFromUtf8(isolate, "switch", NewStringType::kNormal)
1184 .ToLocalChecked(),
1185 FunctionTemplate::New(isolate, RealmSwitch));
1186 realm_template->Set(
1187 String::NewFromUtf8(isolate, "eval", NewStringType::kNormal)
1188 .ToLocalChecked(),
1189 FunctionTemplate::New(isolate, RealmEval));
1190 realm_template->SetAccessor(
1191 String::NewFromUtf8(isolate, "shared", NewStringType::kNormal)
1192 .ToLocalChecked(),
1193 RealmSharedGet, RealmSharedSet);
1194 global_template->Set(
1195 String::NewFromUtf8(isolate, "Realm", NewStringType::kNormal)
1196 .ToLocalChecked(),
1197 realm_template);
1198
1199 #ifndef V8_SHARED
1200 Local<ObjectTemplate> performance_template = ObjectTemplate::New(isolate);
1201 performance_template->Set(
1202 String::NewFromUtf8(isolate, "now", NewStringType::kNormal)
1203 .ToLocalChecked(),
1204 FunctionTemplate::New(isolate, PerformanceNow));
1205 global_template->Set(
1206 String::NewFromUtf8(isolate, "performance", NewStringType::kNormal)
1207 .ToLocalChecked(),
1208 performance_template);
1209
1210 Local<FunctionTemplate> worker_fun_template =
1211 FunctionTemplate::New(isolate, WorkerNew);
1212 Local<Signature> worker_signature =
1213 Signature::New(isolate, worker_fun_template);
1214 worker_fun_template->SetClassName(
1215 String::NewFromUtf8(isolate, "Worker", NewStringType::kNormal)
1216 .ToLocalChecked());
1217 worker_fun_template->ReadOnlyPrototype();
1218 worker_fun_template->PrototypeTemplate()->Set(
1219 String::NewFromUtf8(isolate, "terminate", NewStringType::kNormal)
1220 .ToLocalChecked(),
1221 FunctionTemplate::New(isolate, WorkerTerminate, Local<Value>(),
1222 worker_signature));
1223 worker_fun_template->PrototypeTemplate()->Set(
1224 String::NewFromUtf8(isolate, "postMessage", NewStringType::kNormal)
1225 .ToLocalChecked(),
1226 FunctionTemplate::New(isolate, WorkerPostMessage, Local<Value>(),
1227 worker_signature));
1228 worker_fun_template->PrototypeTemplate()->Set(
1229 String::NewFromUtf8(isolate, "getMessage", NewStringType::kNormal)
1230 .ToLocalChecked(),
1231 FunctionTemplate::New(isolate, WorkerGetMessage, Local<Value>(),
1232 worker_signature));
1233 worker_fun_template->InstanceTemplate()->SetInternalFieldCount(1);
1234 global_template->Set(
1235 String::NewFromUtf8(isolate, "Worker", NewStringType::kNormal)
1236 .ToLocalChecked(),
1237 worker_fun_template);
1238 #endif // !V8_SHARED
1239
1240 Local<ObjectTemplate> os_templ = ObjectTemplate::New(isolate);
1241 AddOSMethods(isolate, os_templ);
1242 global_template->Set(
1243 String::NewFromUtf8(isolate, "os", NewStringType::kNormal)
1244 .ToLocalChecked(),
1245 os_templ);
1246
1247 return global_template;
1248 }
1249
1250
Initialize(Isolate * isolate)1251 void Shell::Initialize(Isolate* isolate) {
1252 #ifndef V8_SHARED
1253 // Set up counters
1254 if (i::StrLength(i::FLAG_map_counters) != 0)
1255 MapCounters(isolate, i::FLAG_map_counters);
1256 #endif // !V8_SHARED
1257 }
1258
1259
CreateEvaluationContext(Isolate * isolate)1260 Local<Context> Shell::CreateEvaluationContext(Isolate* isolate) {
1261 #ifndef V8_SHARED
1262 // This needs to be a critical section since this is not thread-safe
1263 base::LockGuard<base::Mutex> lock_guard(context_mutex_.Pointer());
1264 #endif // !V8_SHARED
1265 // Initialize the global objects
1266 Local<ObjectTemplate> global_template = CreateGlobalTemplate(isolate);
1267 EscapableHandleScope handle_scope(isolate);
1268 Local<Context> context = Context::New(isolate, NULL, global_template);
1269 DCHECK(!context.IsEmpty());
1270 Context::Scope scope(context);
1271
1272 #ifndef V8_SHARED
1273 i::Factory* factory = reinterpret_cast<i::Isolate*>(isolate)->factory();
1274 i::JSArguments js_args = i::FLAG_js_arguments;
1275 i::Handle<i::FixedArray> arguments_array =
1276 factory->NewFixedArray(js_args.argc);
1277 for (int j = 0; j < js_args.argc; j++) {
1278 i::Handle<i::String> arg =
1279 factory->NewStringFromUtf8(i::CStrVector(js_args[j])).ToHandleChecked();
1280 arguments_array->set(j, *arg);
1281 }
1282 i::Handle<i::JSArray> arguments_jsarray =
1283 factory->NewJSArrayWithElements(arguments_array);
1284 context->Global()
1285 ->Set(context,
1286 String::NewFromUtf8(isolate, "arguments", NewStringType::kNormal)
1287 .ToLocalChecked(),
1288 Utils::ToLocal(arguments_jsarray))
1289 .FromJust();
1290 #endif // !V8_SHARED
1291 return handle_scope.Escape(context);
1292 }
1293
1294
Exit(int exit_code)1295 void Shell::Exit(int exit_code) {
1296 // Use _exit instead of exit to avoid races between isolate
1297 // threads and static destructors.
1298 fflush(stdout);
1299 fflush(stderr);
1300 _exit(exit_code);
1301 }
1302
1303
1304 #ifndef V8_SHARED
1305 struct CounterAndKey {
1306 Counter* counter;
1307 const char* key;
1308 };
1309
1310
operator <(const CounterAndKey & lhs,const CounterAndKey & rhs)1311 inline bool operator<(const CounterAndKey& lhs, const CounterAndKey& rhs) {
1312 return strcmp(lhs.key, rhs.key) < 0;
1313 }
1314 #endif // !V8_SHARED
1315
1316
OnExit(v8::Isolate * isolate)1317 void Shell::OnExit(v8::Isolate* isolate) {
1318 #ifndef V8_SHARED
1319 reinterpret_cast<i::Isolate*>(isolate)->DumpAndResetCompilationStats();
1320 if (i::FLAG_dump_counters) {
1321 int number_of_counters = 0;
1322 for (CounterMap::Iterator i(counter_map_); i.More(); i.Next()) {
1323 number_of_counters++;
1324 }
1325 CounterAndKey* counters = new CounterAndKey[number_of_counters];
1326 int j = 0;
1327 for (CounterMap::Iterator i(counter_map_); i.More(); i.Next(), j++) {
1328 counters[j].counter = i.CurrentValue();
1329 counters[j].key = i.CurrentKey();
1330 }
1331 std::sort(counters, counters + number_of_counters);
1332 printf("+----------------------------------------------------------------+"
1333 "-------------+\n");
1334 printf("| Name |"
1335 " Value |\n");
1336 printf("+----------------------------------------------------------------+"
1337 "-------------+\n");
1338 for (j = 0; j < number_of_counters; j++) {
1339 Counter* counter = counters[j].counter;
1340 const char* key = counters[j].key;
1341 if (counter->is_histogram()) {
1342 printf("| c:%-60s | %11i |\n", key, counter->count());
1343 printf("| t:%-60s | %11i |\n", key, counter->sample_total());
1344 } else {
1345 printf("| %-62s | %11i |\n", key, counter->count());
1346 }
1347 }
1348 printf("+----------------------------------------------------------------+"
1349 "-------------+\n");
1350 delete [] counters;
1351 }
1352 delete counters_file_;
1353 delete counter_map_;
1354 #endif // !V8_SHARED
1355 }
1356
1357
1358
FOpen(const char * path,const char * mode)1359 static FILE* FOpen(const char* path, const char* mode) {
1360 #if defined(_MSC_VER) && (defined(_WIN32) || defined(_WIN64))
1361 FILE* result;
1362 if (fopen_s(&result, path, mode) == 0) {
1363 return result;
1364 } else {
1365 return NULL;
1366 }
1367 #else
1368 FILE* file = fopen(path, mode);
1369 if (file == NULL) return NULL;
1370 struct stat file_stat;
1371 if (fstat(fileno(file), &file_stat) != 0) return NULL;
1372 bool is_regular_file = ((file_stat.st_mode & S_IFREG) != 0);
1373 if (is_regular_file) return file;
1374 fclose(file);
1375 return NULL;
1376 #endif
1377 }
1378
1379
ReadChars(Isolate * isolate,const char * name,int * size_out)1380 static char* ReadChars(Isolate* isolate, const char* name, int* size_out) {
1381 FILE* file = FOpen(name, "rb");
1382 if (file == NULL) return NULL;
1383
1384 fseek(file, 0, SEEK_END);
1385 size_t size = ftell(file);
1386 rewind(file);
1387
1388 char* chars = new char[size + 1];
1389 chars[size] = '\0';
1390 for (size_t i = 0; i < size;) {
1391 i += fread(&chars[i], 1, size - i, file);
1392 if (ferror(file)) {
1393 fclose(file);
1394 delete[] chars;
1395 return nullptr;
1396 }
1397 }
1398 fclose(file);
1399 *size_out = static_cast<int>(size);
1400 return chars;
1401 }
1402
1403
1404 struct DataAndPersistent {
1405 uint8_t* data;
1406 int byte_length;
1407 Global<ArrayBuffer> handle;
1408 };
1409
1410
ReadBufferWeakCallback(const v8::WeakCallbackInfo<DataAndPersistent> & data)1411 static void ReadBufferWeakCallback(
1412 const v8::WeakCallbackInfo<DataAndPersistent>& data) {
1413 int byte_length = data.GetParameter()->byte_length;
1414 data.GetIsolate()->AdjustAmountOfExternalAllocatedMemory(
1415 -static_cast<intptr_t>(byte_length));
1416
1417 delete[] data.GetParameter()->data;
1418 data.GetParameter()->handle.Reset();
1419 delete data.GetParameter();
1420 }
1421
1422
ReadBuffer(const v8::FunctionCallbackInfo<v8::Value> & args)1423 void Shell::ReadBuffer(const v8::FunctionCallbackInfo<v8::Value>& args) {
1424 DCHECK(sizeof(char) == sizeof(uint8_t)); // NOLINT
1425 String::Utf8Value filename(args[0]);
1426 int length;
1427 if (*filename == NULL) {
1428 Throw(args.GetIsolate(), "Error loading file");
1429 return;
1430 }
1431
1432 Isolate* isolate = args.GetIsolate();
1433 DataAndPersistent* data = new DataAndPersistent;
1434 data->data = reinterpret_cast<uint8_t*>(
1435 ReadChars(args.GetIsolate(), *filename, &length));
1436 if (data->data == NULL) {
1437 delete data;
1438 Throw(args.GetIsolate(), "Error reading file");
1439 return;
1440 }
1441 data->byte_length = length;
1442 Local<v8::ArrayBuffer> buffer = ArrayBuffer::New(isolate, data->data, length);
1443 data->handle.Reset(isolate, buffer);
1444 data->handle.SetWeak(data, ReadBufferWeakCallback,
1445 v8::WeakCallbackType::kParameter);
1446 data->handle.MarkIndependent();
1447 isolate->AdjustAmountOfExternalAllocatedMemory(length);
1448
1449 args.GetReturnValue().Set(buffer);
1450 }
1451
1452
1453 // Reads a file into a v8 string.
ReadFile(Isolate * isolate,const char * name)1454 Local<String> Shell::ReadFile(Isolate* isolate, const char* name) {
1455 int size = 0;
1456 char* chars = ReadChars(isolate, name, &size);
1457 if (chars == NULL) return Local<String>();
1458 Local<String> result =
1459 String::NewFromUtf8(isolate, chars, NewStringType::kNormal, size)
1460 .ToLocalChecked();
1461 delete[] chars;
1462 return result;
1463 }
1464
1465
RunShell(Isolate * isolate)1466 void Shell::RunShell(Isolate* isolate) {
1467 HandleScope outer_scope(isolate);
1468 v8::Local<v8::Context> context =
1469 v8::Local<v8::Context>::New(isolate, evaluation_context_);
1470 v8::Context::Scope context_scope(context);
1471 PerIsolateData::RealmScope realm_scope(PerIsolateData::Get(isolate));
1472 Local<String> name =
1473 String::NewFromUtf8(isolate, "(d8)", NewStringType::kNormal)
1474 .ToLocalChecked();
1475 printf("V8 version %s\n", V8::GetVersion());
1476 while (true) {
1477 HandleScope inner_scope(isolate);
1478 printf("d8> ");
1479 #if defined(__native_client__)
1480 // Native Client libc is used to being embedded in Chrome and
1481 // has trouble recognizing when to flush.
1482 fflush(stdout);
1483 #endif
1484 Local<String> input = Shell::ReadFromStdin(isolate);
1485 if (input.IsEmpty()) break;
1486 ExecuteString(isolate, input, name, true, true);
1487 }
1488 printf("\n");
1489 }
1490
1491
~SourceGroup()1492 SourceGroup::~SourceGroup() {
1493 #ifndef V8_SHARED
1494 delete thread_;
1495 thread_ = NULL;
1496 #endif // !V8_SHARED
1497 }
1498
1499
Execute(Isolate * isolate)1500 void SourceGroup::Execute(Isolate* isolate) {
1501 bool exception_was_thrown = false;
1502 for (int i = begin_offset_; i < end_offset_; ++i) {
1503 const char* arg = argv_[i];
1504 Shell::SourceType source_type = Shell::SCRIPT;
1505 if (strcmp(arg, "-e") == 0 && i + 1 < end_offset_) {
1506 // Execute argument given to -e option directly.
1507 HandleScope handle_scope(isolate);
1508 Local<String> file_name =
1509 String::NewFromUtf8(isolate, "unnamed", NewStringType::kNormal)
1510 .ToLocalChecked();
1511 Local<String> source =
1512 String::NewFromUtf8(isolate, argv_[i + 1], NewStringType::kNormal)
1513 .ToLocalChecked();
1514 Shell::options.script_executed = true;
1515 if (!Shell::ExecuteString(isolate, source, file_name, false, true)) {
1516 exception_was_thrown = true;
1517 break;
1518 }
1519 ++i;
1520 continue;
1521 } else if (strcmp(arg, "--module") == 0 && i + 1 < end_offset_) {
1522 // Treat the next file as a module.
1523 source_type = Shell::MODULE;
1524 arg = argv_[++i];
1525 } else if (arg[0] == '-') {
1526 // Ignore other options. They have been parsed already.
1527 continue;
1528 }
1529
1530 // Use all other arguments as names of files to load and run.
1531 HandleScope handle_scope(isolate);
1532 Local<String> file_name =
1533 String::NewFromUtf8(isolate, arg, NewStringType::kNormal)
1534 .ToLocalChecked();
1535 Local<String> source = ReadFile(isolate, arg);
1536 if (source.IsEmpty()) {
1537 printf("Error reading '%s'\n", arg);
1538 Shell::Exit(1);
1539 }
1540 Shell::options.script_executed = true;
1541 if (!Shell::ExecuteString(isolate, source, file_name, false, true,
1542 source_type)) {
1543 exception_was_thrown = true;
1544 break;
1545 }
1546 }
1547 if (exception_was_thrown != Shell::options.expected_to_throw) {
1548 Shell::Exit(1);
1549 }
1550 }
1551
1552
ReadFile(Isolate * isolate,const char * name)1553 Local<String> SourceGroup::ReadFile(Isolate* isolate, const char* name) {
1554 int size;
1555 char* chars = ReadChars(isolate, name, &size);
1556 if (chars == NULL) return Local<String>();
1557 Local<String> result =
1558 String::NewFromUtf8(isolate, chars, NewStringType::kNormal, size)
1559 .ToLocalChecked();
1560 delete[] chars;
1561 return result;
1562 }
1563
1564
1565 #ifndef V8_SHARED
GetThreadOptions()1566 base::Thread::Options SourceGroup::GetThreadOptions() {
1567 // On some systems (OSX 10.6) the stack size default is 0.5Mb or less
1568 // which is not enough to parse the big literal expressions used in tests.
1569 // The stack size should be at least StackGuard::kLimitSize + some
1570 // OS-specific padding for thread startup code. 2Mbytes seems to be enough.
1571 return base::Thread::Options("IsolateThread", 2 * MB);
1572 }
1573
1574
ExecuteInThread()1575 void SourceGroup::ExecuteInThread() {
1576 Isolate::CreateParams create_params;
1577 create_params.array_buffer_allocator = Shell::array_buffer_allocator;
1578 Isolate* isolate = Isolate::New(create_params);
1579 for (int i = 0; i < Shell::options.stress_runs; ++i) {
1580 next_semaphore_.Wait();
1581 {
1582 Isolate::Scope iscope(isolate);
1583 {
1584 HandleScope scope(isolate);
1585 PerIsolateData data(isolate);
1586 Local<Context> context = Shell::CreateEvaluationContext(isolate);
1587 {
1588 Context::Scope cscope(context);
1589 PerIsolateData::RealmScope realm_scope(PerIsolateData::Get(isolate));
1590 Execute(isolate);
1591 }
1592 }
1593 Shell::CollectGarbage(isolate);
1594 }
1595 done_semaphore_.Signal();
1596 }
1597
1598 isolate->Dispose();
1599 }
1600
1601
StartExecuteInThread()1602 void SourceGroup::StartExecuteInThread() {
1603 if (thread_ == NULL) {
1604 thread_ = new IsolateThread(this);
1605 thread_->Start();
1606 }
1607 next_semaphore_.Signal();
1608 }
1609
1610
WaitForThread()1611 void SourceGroup::WaitForThread() {
1612 if (thread_ == NULL) return;
1613 done_semaphore_.Wait();
1614 }
1615
1616
JoinThread()1617 void SourceGroup::JoinThread() {
1618 if (thread_ == NULL) return;
1619 thread_->Join();
1620 }
1621
1622
~SerializationData()1623 SerializationData::~SerializationData() {
1624 // Any ArrayBuffer::Contents are owned by this SerializationData object if
1625 // ownership hasn't been transferred out via ReadArrayBufferContents.
1626 // SharedArrayBuffer::Contents may be used by multiple threads, so must be
1627 // cleaned up by the main thread in Shell::CleanupWorkers().
1628 for (int i = 0; i < array_buffer_contents_.length(); ++i) {
1629 ArrayBuffer::Contents& contents = array_buffer_contents_[i];
1630 if (contents.Data()) {
1631 Shell::array_buffer_allocator->Free(contents.Data(),
1632 contents.ByteLength());
1633 }
1634 }
1635 }
1636
1637
WriteTag(SerializationTag tag)1638 void SerializationData::WriteTag(SerializationTag tag) { data_.Add(tag); }
1639
1640
WriteMemory(const void * p,int length)1641 void SerializationData::WriteMemory(const void* p, int length) {
1642 if (length > 0) {
1643 i::Vector<uint8_t> block = data_.AddBlock(0, length);
1644 memcpy(&block[0], p, length);
1645 }
1646 }
1647
1648
WriteArrayBufferContents(const ArrayBuffer::Contents & contents)1649 void SerializationData::WriteArrayBufferContents(
1650 const ArrayBuffer::Contents& contents) {
1651 array_buffer_contents_.Add(contents);
1652 WriteTag(kSerializationTagTransferredArrayBuffer);
1653 int index = array_buffer_contents_.length() - 1;
1654 Write(index);
1655 }
1656
1657
WriteSharedArrayBufferContents(const SharedArrayBuffer::Contents & contents)1658 void SerializationData::WriteSharedArrayBufferContents(
1659 const SharedArrayBuffer::Contents& contents) {
1660 shared_array_buffer_contents_.Add(contents);
1661 WriteTag(kSerializationTagTransferredSharedArrayBuffer);
1662 int index = shared_array_buffer_contents_.length() - 1;
1663 Write(index);
1664 }
1665
1666
ReadTag(int * offset) const1667 SerializationTag SerializationData::ReadTag(int* offset) const {
1668 return static_cast<SerializationTag>(Read<uint8_t>(offset));
1669 }
1670
1671
ReadMemory(void * p,int length,int * offset) const1672 void SerializationData::ReadMemory(void* p, int length, int* offset) const {
1673 if (length > 0) {
1674 memcpy(p, &data_[*offset], length);
1675 (*offset) += length;
1676 }
1677 }
1678
1679
ReadArrayBufferContents(ArrayBuffer::Contents * contents,int * offset) const1680 void SerializationData::ReadArrayBufferContents(ArrayBuffer::Contents* contents,
1681 int* offset) const {
1682 int index = Read<int>(offset);
1683 DCHECK(index < array_buffer_contents_.length());
1684 *contents = array_buffer_contents_[index];
1685 // Ownership of this ArrayBuffer::Contents is passed to the caller. Neuter
1686 // our copy so it won't be double-free'd when this SerializationData is
1687 // destroyed.
1688 array_buffer_contents_[index] = ArrayBuffer::Contents();
1689 }
1690
1691
ReadSharedArrayBufferContents(SharedArrayBuffer::Contents * contents,int * offset) const1692 void SerializationData::ReadSharedArrayBufferContents(
1693 SharedArrayBuffer::Contents* contents, int* offset) const {
1694 int index = Read<int>(offset);
1695 DCHECK(index < shared_array_buffer_contents_.length());
1696 *contents = shared_array_buffer_contents_[index];
1697 }
1698
1699
Enqueue(SerializationData * data)1700 void SerializationDataQueue::Enqueue(SerializationData* data) {
1701 base::LockGuard<base::Mutex> lock_guard(&mutex_);
1702 data_.Add(data);
1703 }
1704
1705
Dequeue(SerializationData ** data)1706 bool SerializationDataQueue::Dequeue(SerializationData** data) {
1707 base::LockGuard<base::Mutex> lock_guard(&mutex_);
1708 *data = NULL;
1709 if (data_.is_empty()) return false;
1710 *data = data_.Remove(0);
1711 return true;
1712 }
1713
1714
IsEmpty()1715 bool SerializationDataQueue::IsEmpty() {
1716 base::LockGuard<base::Mutex> lock_guard(&mutex_);
1717 return data_.is_empty();
1718 }
1719
1720
Clear()1721 void SerializationDataQueue::Clear() {
1722 base::LockGuard<base::Mutex> lock_guard(&mutex_);
1723 for (int i = 0; i < data_.length(); ++i) {
1724 delete data_[i];
1725 }
1726 data_.Clear();
1727 }
1728
1729
Worker()1730 Worker::Worker()
1731 : in_semaphore_(0),
1732 out_semaphore_(0),
1733 thread_(NULL),
1734 script_(NULL),
1735 running_(false) {}
1736
1737
~Worker()1738 Worker::~Worker() {
1739 delete thread_;
1740 thread_ = NULL;
1741 delete[] script_;
1742 script_ = NULL;
1743 in_queue_.Clear();
1744 out_queue_.Clear();
1745 }
1746
1747
StartExecuteInThread(const char * script)1748 void Worker::StartExecuteInThread(const char* script) {
1749 running_ = true;
1750 script_ = i::StrDup(script);
1751 thread_ = new WorkerThread(this);
1752 thread_->Start();
1753 }
1754
1755
PostMessage(SerializationData * data)1756 void Worker::PostMessage(SerializationData* data) {
1757 in_queue_.Enqueue(data);
1758 in_semaphore_.Signal();
1759 }
1760
1761
GetMessage()1762 SerializationData* Worker::GetMessage() {
1763 SerializationData* data = NULL;
1764 while (!out_queue_.Dequeue(&data)) {
1765 // If the worker is no longer running, and there are no messages in the
1766 // queue, don't expect any more messages from it.
1767 if (!base::NoBarrier_Load(&running_)) break;
1768 out_semaphore_.Wait();
1769 }
1770 return data;
1771 }
1772
1773
Terminate()1774 void Worker::Terminate() {
1775 base::NoBarrier_Store(&running_, false);
1776 // Post NULL to wake the Worker thread message loop, and tell it to stop
1777 // running.
1778 PostMessage(NULL);
1779 }
1780
1781
WaitForThread()1782 void Worker::WaitForThread() {
1783 Terminate();
1784 thread_->Join();
1785 }
1786
1787
ExecuteInThread()1788 void Worker::ExecuteInThread() {
1789 Isolate::CreateParams create_params;
1790 create_params.array_buffer_allocator = Shell::array_buffer_allocator;
1791 Isolate* isolate = Isolate::New(create_params);
1792 {
1793 Isolate::Scope iscope(isolate);
1794 {
1795 HandleScope scope(isolate);
1796 PerIsolateData data(isolate);
1797 Local<Context> context = Shell::CreateEvaluationContext(isolate);
1798 {
1799 Context::Scope cscope(context);
1800 PerIsolateData::RealmScope realm_scope(PerIsolateData::Get(isolate));
1801
1802 Local<Object> global = context->Global();
1803 Local<Value> this_value = External::New(isolate, this);
1804 Local<FunctionTemplate> postmessage_fun_template =
1805 FunctionTemplate::New(isolate, PostMessageOut, this_value);
1806
1807 Local<Function> postmessage_fun;
1808 if (postmessage_fun_template->GetFunction(context)
1809 .ToLocal(&postmessage_fun)) {
1810 global->Set(context, String::NewFromUtf8(isolate, "postMessage",
1811 NewStringType::kNormal)
1812 .ToLocalChecked(),
1813 postmessage_fun).FromJust();
1814 }
1815
1816 // First run the script
1817 Local<String> file_name =
1818 String::NewFromUtf8(isolate, "unnamed", NewStringType::kNormal)
1819 .ToLocalChecked();
1820 Local<String> source =
1821 String::NewFromUtf8(isolate, script_, NewStringType::kNormal)
1822 .ToLocalChecked();
1823 if (Shell::ExecuteString(isolate, source, file_name, false, true)) {
1824 // Get the message handler
1825 Local<Value> onmessage =
1826 global->Get(context, String::NewFromUtf8(isolate, "onmessage",
1827 NewStringType::kNormal)
1828 .ToLocalChecked()).ToLocalChecked();
1829 if (onmessage->IsFunction()) {
1830 Local<Function> onmessage_fun = Local<Function>::Cast(onmessage);
1831 // Now wait for messages
1832 while (true) {
1833 in_semaphore_.Wait();
1834 SerializationData* data;
1835 if (!in_queue_.Dequeue(&data)) continue;
1836 if (data == NULL) {
1837 break;
1838 }
1839 int offset = 0;
1840 Local<Value> data_value;
1841 if (Shell::DeserializeValue(isolate, *data, &offset)
1842 .ToLocal(&data_value)) {
1843 Local<Value> argv[] = {data_value};
1844 (void)onmessage_fun->Call(context, global, 1, argv);
1845 }
1846 delete data;
1847 }
1848 }
1849 }
1850 }
1851 }
1852 Shell::CollectGarbage(isolate);
1853 }
1854 isolate->Dispose();
1855
1856 // Post NULL to wake the thread waiting on GetMessage() if there is one.
1857 out_queue_.Enqueue(NULL);
1858 out_semaphore_.Signal();
1859 }
1860
1861
PostMessageOut(const v8::FunctionCallbackInfo<v8::Value> & args)1862 void Worker::PostMessageOut(const v8::FunctionCallbackInfo<v8::Value>& args) {
1863 Isolate* isolate = args.GetIsolate();
1864 HandleScope handle_scope(isolate);
1865
1866 if (args.Length() < 1) {
1867 Throw(isolate, "Invalid argument");
1868 return;
1869 }
1870
1871 Local<Value> message = args[0];
1872
1873 // TODO(binji): Allow transferring from worker to main thread?
1874 Shell::ObjectList to_transfer;
1875
1876 Shell::ObjectList seen_objects;
1877 SerializationData* data = new SerializationData;
1878 if (Shell::SerializeValue(isolate, message, to_transfer, &seen_objects,
1879 data)) {
1880 DCHECK(args.Data()->IsExternal());
1881 Local<External> this_value = Local<External>::Cast(args.Data());
1882 Worker* worker = static_cast<Worker*>(this_value->Value());
1883 worker->out_queue_.Enqueue(data);
1884 worker->out_semaphore_.Signal();
1885 } else {
1886 delete data;
1887 }
1888 }
1889 #endif // !V8_SHARED
1890
1891
SetFlagsFromString(const char * flags)1892 void SetFlagsFromString(const char* flags) {
1893 v8::V8::SetFlagsFromString(flags, static_cast<int>(strlen(flags)));
1894 }
1895
1896
SetOptions(int argc,char * argv[])1897 bool Shell::SetOptions(int argc, char* argv[]) {
1898 bool logfile_per_isolate = false;
1899 for (int i = 0; i < argc; i++) {
1900 if (strcmp(argv[i], "--stress-opt") == 0) {
1901 options.stress_opt = true;
1902 argv[i] = NULL;
1903 } else if (strcmp(argv[i], "--nostress-opt") == 0) {
1904 options.stress_opt = false;
1905 argv[i] = NULL;
1906 } else if (strcmp(argv[i], "--stress-deopt") == 0) {
1907 options.stress_deopt = true;
1908 argv[i] = NULL;
1909 } else if (strcmp(argv[i], "--mock-arraybuffer-allocator") == 0) {
1910 options.mock_arraybuffer_allocator = true;
1911 argv[i] = NULL;
1912 } else if (strcmp(argv[i], "--noalways-opt") == 0) {
1913 // No support for stressing if we can't use --always-opt.
1914 options.stress_opt = false;
1915 options.stress_deopt = false;
1916 } else if (strcmp(argv[i], "--logfile-per-isolate") == 0) {
1917 logfile_per_isolate = true;
1918 argv[i] = NULL;
1919 } else if (strcmp(argv[i], "--shell") == 0) {
1920 options.interactive_shell = true;
1921 argv[i] = NULL;
1922 } else if (strcmp(argv[i], "--test") == 0) {
1923 options.test_shell = true;
1924 argv[i] = NULL;
1925 } else if (strcmp(argv[i], "--notest") == 0 ||
1926 strcmp(argv[i], "--no-test") == 0) {
1927 options.test_shell = false;
1928 argv[i] = NULL;
1929 } else if (strcmp(argv[i], "--send-idle-notification") == 0) {
1930 options.send_idle_notification = true;
1931 argv[i] = NULL;
1932 } else if (strcmp(argv[i], "--invoke-weak-callbacks") == 0) {
1933 options.invoke_weak_callbacks = true;
1934 // TODO(jochen) See issue 3351
1935 options.send_idle_notification = true;
1936 argv[i] = NULL;
1937 } else if (strcmp(argv[i], "--omit-quit") == 0) {
1938 options.omit_quit = true;
1939 argv[i] = NULL;
1940 } else if (strcmp(argv[i], "-f") == 0) {
1941 // Ignore any -f flags for compatibility with other stand-alone
1942 // JavaScript engines.
1943 continue;
1944 } else if (strcmp(argv[i], "--isolate") == 0) {
1945 #ifdef V8_SHARED
1946 printf("D8 with shared library does not support multi-threading\n");
1947 return false;
1948 #endif // V8_SHARED
1949 options.num_isolates++;
1950 } else if (strcmp(argv[i], "--dump-heap-constants") == 0) {
1951 #ifdef V8_SHARED
1952 printf("D8 with shared library does not support constant dumping\n");
1953 return false;
1954 #else
1955 options.dump_heap_constants = true;
1956 argv[i] = NULL;
1957 #endif // V8_SHARED
1958 } else if (strcmp(argv[i], "--throws") == 0) {
1959 options.expected_to_throw = true;
1960 argv[i] = NULL;
1961 } else if (strncmp(argv[i], "--icu-data-file=", 16) == 0) {
1962 options.icu_data_file = argv[i] + 16;
1963 argv[i] = NULL;
1964 #ifdef V8_SHARED
1965 } else if (strcmp(argv[i], "--dump-counters") == 0) {
1966 printf("D8 with shared library does not include counters\n");
1967 return false;
1968 #endif // V8_SHARED
1969 #ifdef V8_USE_EXTERNAL_STARTUP_DATA
1970 } else if (strncmp(argv[i], "--natives_blob=", 15) == 0) {
1971 options.natives_blob = argv[i] + 15;
1972 argv[i] = NULL;
1973 } else if (strncmp(argv[i], "--snapshot_blob=", 16) == 0) {
1974 options.snapshot_blob = argv[i] + 16;
1975 argv[i] = NULL;
1976 #endif // V8_USE_EXTERNAL_STARTUP_DATA
1977 } else if (strcmp(argv[i], "--cache") == 0 ||
1978 strncmp(argv[i], "--cache=", 8) == 0) {
1979 const char* value = argv[i] + 7;
1980 if (!*value || strncmp(value, "=code", 6) == 0) {
1981 options.compile_options = v8::ScriptCompiler::kProduceCodeCache;
1982 } else if (strncmp(value, "=parse", 7) == 0) {
1983 options.compile_options = v8::ScriptCompiler::kProduceParserCache;
1984 } else if (strncmp(value, "=none", 6) == 0) {
1985 options.compile_options = v8::ScriptCompiler::kNoCompileOptions;
1986 } else {
1987 printf("Unknown option to --cache.\n");
1988 return false;
1989 }
1990 argv[i] = NULL;
1991 }
1992 }
1993
1994 v8::V8::SetFlagsFromCommandLine(&argc, argv, true);
1995
1996 bool enable_harmony_modules = false;
1997
1998 // Set up isolated source groups.
1999 options.isolate_sources = new SourceGroup[options.num_isolates];
2000 SourceGroup* current = options.isolate_sources;
2001 current->Begin(argv, 1);
2002 for (int i = 1; i < argc; i++) {
2003 const char* str = argv[i];
2004 if (strcmp(str, "--isolate") == 0) {
2005 current->End(i);
2006 current++;
2007 current->Begin(argv, i + 1);
2008 } else if (strcmp(str, "--module") == 0) {
2009 // Pass on to SourceGroup, which understands this option.
2010 enable_harmony_modules = true;
2011 } else if (strncmp(argv[i], "--", 2) == 0) {
2012 printf("Warning: unknown flag %s.\nTry --help for options\n", argv[i]);
2013 } else if (strcmp(str, "-e") == 0 && i + 1 < argc) {
2014 options.script_executed = true;
2015 } else if (strncmp(str, "-", 1) != 0) {
2016 // Not a flag, so it must be a script to execute.
2017 options.script_executed = true;
2018 }
2019 }
2020 current->End(argc);
2021
2022 if (!logfile_per_isolate && options.num_isolates) {
2023 SetFlagsFromString("--nologfile_per_isolate");
2024 }
2025
2026 if (enable_harmony_modules) {
2027 SetFlagsFromString("--harmony-modules");
2028 }
2029
2030 return true;
2031 }
2032
2033
RunMain(Isolate * isolate,int argc,char * argv[],bool last_run)2034 int Shell::RunMain(Isolate* isolate, int argc, char* argv[], bool last_run) {
2035 #ifndef V8_SHARED
2036 for (int i = 1; i < options.num_isolates; ++i) {
2037 options.isolate_sources[i].StartExecuteInThread();
2038 }
2039 #endif // !V8_SHARED
2040 {
2041 HandleScope scope(isolate);
2042 Local<Context> context = CreateEvaluationContext(isolate);
2043 if (last_run && options.use_interactive_shell()) {
2044 // Keep using the same context in the interactive shell.
2045 evaluation_context_.Reset(isolate, context);
2046 }
2047 {
2048 Context::Scope cscope(context);
2049 PerIsolateData::RealmScope realm_scope(PerIsolateData::Get(isolate));
2050 options.isolate_sources[0].Execute(isolate);
2051 }
2052 }
2053 CollectGarbage(isolate);
2054 #ifndef V8_SHARED
2055 for (int i = 1; i < options.num_isolates; ++i) {
2056 if (last_run) {
2057 options.isolate_sources[i].JoinThread();
2058 } else {
2059 options.isolate_sources[i].WaitForThread();
2060 }
2061 }
2062 CleanupWorkers();
2063 #endif // !V8_SHARED
2064 return 0;
2065 }
2066
2067
CollectGarbage(Isolate * isolate)2068 void Shell::CollectGarbage(Isolate* isolate) {
2069 if (options.send_idle_notification) {
2070 const double kLongIdlePauseInSeconds = 1.0;
2071 isolate->ContextDisposedNotification();
2072 isolate->IdleNotificationDeadline(
2073 g_platform->MonotonicallyIncreasingTime() + kLongIdlePauseInSeconds);
2074 }
2075 if (options.invoke_weak_callbacks) {
2076 // By sending a low memory notifications, we will try hard to collect all
2077 // garbage and will therefore also invoke all weak callbacks of actually
2078 // unreachable persistent handles.
2079 isolate->LowMemoryNotification();
2080 }
2081 }
2082
2083
EmptyMessageQueues(Isolate * isolate)2084 void Shell::EmptyMessageQueues(Isolate* isolate) {
2085 #ifndef V8_SHARED
2086 if (!i::FLAG_verify_predictable) {
2087 #endif
2088 while (v8::platform::PumpMessageLoop(g_platform, isolate)) continue;
2089 #ifndef V8_SHARED
2090 }
2091 #endif
2092 }
2093
2094
2095 #ifndef V8_SHARED
SerializeValue(Isolate * isolate,Local<Value> value,const ObjectList & to_transfer,ObjectList * seen_objects,SerializationData * out_data)2096 bool Shell::SerializeValue(Isolate* isolate, Local<Value> value,
2097 const ObjectList& to_transfer,
2098 ObjectList* seen_objects,
2099 SerializationData* out_data) {
2100 DCHECK(out_data);
2101 Local<Context> context = isolate->GetCurrentContext();
2102
2103 if (value->IsUndefined()) {
2104 out_data->WriteTag(kSerializationTagUndefined);
2105 } else if (value->IsNull()) {
2106 out_data->WriteTag(kSerializationTagNull);
2107 } else if (value->IsTrue()) {
2108 out_data->WriteTag(kSerializationTagTrue);
2109 } else if (value->IsFalse()) {
2110 out_data->WriteTag(kSerializationTagFalse);
2111 } else if (value->IsNumber()) {
2112 Local<Number> num = Local<Number>::Cast(value);
2113 double value = num->Value();
2114 out_data->WriteTag(kSerializationTagNumber);
2115 out_data->Write(value);
2116 } else if (value->IsString()) {
2117 v8::String::Utf8Value str(value);
2118 out_data->WriteTag(kSerializationTagString);
2119 out_data->Write(str.length());
2120 out_data->WriteMemory(*str, str.length());
2121 } else if (value->IsArray()) {
2122 Local<Array> array = Local<Array>::Cast(value);
2123 if (FindInObjectList(array, *seen_objects)) {
2124 Throw(isolate, "Duplicated arrays not supported");
2125 return false;
2126 }
2127 seen_objects->Add(array);
2128 out_data->WriteTag(kSerializationTagArray);
2129 uint32_t length = array->Length();
2130 out_data->Write(length);
2131 for (uint32_t i = 0; i < length; ++i) {
2132 Local<Value> element_value;
2133 if (array->Get(context, i).ToLocal(&element_value)) {
2134 if (!SerializeValue(isolate, element_value, to_transfer, seen_objects,
2135 out_data))
2136 return false;
2137 } else {
2138 Throw(isolate, "Failed to serialize array element.");
2139 return false;
2140 }
2141 }
2142 } else if (value->IsArrayBuffer()) {
2143 Local<ArrayBuffer> array_buffer = Local<ArrayBuffer>::Cast(value);
2144 if (FindInObjectList(array_buffer, *seen_objects)) {
2145 Throw(isolate, "Duplicated array buffers not supported");
2146 return false;
2147 }
2148 seen_objects->Add(array_buffer);
2149 if (FindInObjectList(array_buffer, to_transfer)) {
2150 // Transfer ArrayBuffer
2151 if (!array_buffer->IsNeuterable()) {
2152 Throw(isolate, "Attempting to transfer an un-neuterable ArrayBuffer");
2153 return false;
2154 }
2155
2156 ArrayBuffer::Contents contents = array_buffer->IsExternal()
2157 ? array_buffer->GetContents()
2158 : array_buffer->Externalize();
2159 array_buffer->Neuter();
2160 out_data->WriteArrayBufferContents(contents);
2161 } else {
2162 ArrayBuffer::Contents contents = array_buffer->GetContents();
2163 // Clone ArrayBuffer
2164 if (contents.ByteLength() > i::kMaxInt) {
2165 Throw(isolate, "ArrayBuffer is too big to clone");
2166 return false;
2167 }
2168
2169 int32_t byte_length = static_cast<int32_t>(contents.ByteLength());
2170 out_data->WriteTag(kSerializationTagArrayBuffer);
2171 out_data->Write(byte_length);
2172 out_data->WriteMemory(contents.Data(), byte_length);
2173 }
2174 } else if (value->IsSharedArrayBuffer()) {
2175 Local<SharedArrayBuffer> sab = Local<SharedArrayBuffer>::Cast(value);
2176 if (FindInObjectList(sab, *seen_objects)) {
2177 Throw(isolate, "Duplicated shared array buffers not supported");
2178 return false;
2179 }
2180 seen_objects->Add(sab);
2181 if (!FindInObjectList(sab, to_transfer)) {
2182 Throw(isolate, "SharedArrayBuffer must be transferred");
2183 return false;
2184 }
2185
2186 SharedArrayBuffer::Contents contents;
2187 if (sab->IsExternal()) {
2188 contents = sab->GetContents();
2189 } else {
2190 contents = sab->Externalize();
2191 base::LockGuard<base::Mutex> lock_guard(workers_mutex_.Pointer());
2192 externalized_shared_contents_.Add(contents);
2193 }
2194 out_data->WriteSharedArrayBufferContents(contents);
2195 } else if (value->IsObject()) {
2196 Local<Object> object = Local<Object>::Cast(value);
2197 if (FindInObjectList(object, *seen_objects)) {
2198 Throw(isolate, "Duplicated objects not supported");
2199 return false;
2200 }
2201 seen_objects->Add(object);
2202 Local<Array> property_names;
2203 if (!object->GetOwnPropertyNames(context).ToLocal(&property_names)) {
2204 Throw(isolate, "Unable to get property names");
2205 return false;
2206 }
2207
2208 uint32_t length = property_names->Length();
2209 out_data->WriteTag(kSerializationTagObject);
2210 out_data->Write(length);
2211 for (uint32_t i = 0; i < length; ++i) {
2212 Local<Value> name;
2213 Local<Value> property_value;
2214 if (property_names->Get(context, i).ToLocal(&name) &&
2215 object->Get(context, name).ToLocal(&property_value)) {
2216 if (!SerializeValue(isolate, name, to_transfer, seen_objects, out_data))
2217 return false;
2218 if (!SerializeValue(isolate, property_value, to_transfer, seen_objects,
2219 out_data))
2220 return false;
2221 } else {
2222 Throw(isolate, "Failed to serialize property.");
2223 return false;
2224 }
2225 }
2226 } else {
2227 Throw(isolate, "Don't know how to serialize object");
2228 return false;
2229 }
2230
2231 return true;
2232 }
2233
2234
DeserializeValue(Isolate * isolate,const SerializationData & data,int * offset)2235 MaybeLocal<Value> Shell::DeserializeValue(Isolate* isolate,
2236 const SerializationData& data,
2237 int* offset) {
2238 DCHECK(offset);
2239 EscapableHandleScope scope(isolate);
2240 // This function should not use utility_context_ because it is running on a
2241 // different thread.
2242 Local<Value> result;
2243 SerializationTag tag = data.ReadTag(offset);
2244
2245 switch (tag) {
2246 case kSerializationTagUndefined:
2247 result = Undefined(isolate);
2248 break;
2249 case kSerializationTagNull:
2250 result = Null(isolate);
2251 break;
2252 case kSerializationTagTrue:
2253 result = True(isolate);
2254 break;
2255 case kSerializationTagFalse:
2256 result = False(isolate);
2257 break;
2258 case kSerializationTagNumber:
2259 result = Number::New(isolate, data.Read<double>(offset));
2260 break;
2261 case kSerializationTagString: {
2262 int length = data.Read<int>(offset);
2263 CHECK(length >= 0);
2264 std::vector<char> buffer(length + 1); // + 1 so it is never empty.
2265 data.ReadMemory(&buffer[0], length, offset);
2266 MaybeLocal<String> str =
2267 String::NewFromUtf8(isolate, &buffer[0], NewStringType::kNormal,
2268 length).ToLocalChecked();
2269 if (!str.IsEmpty()) result = str.ToLocalChecked();
2270 break;
2271 }
2272 case kSerializationTagArray: {
2273 uint32_t length = data.Read<uint32_t>(offset);
2274 Local<Array> array = Array::New(isolate, length);
2275 for (uint32_t i = 0; i < length; ++i) {
2276 Local<Value> element_value;
2277 CHECK(DeserializeValue(isolate, data, offset).ToLocal(&element_value));
2278 array->Set(isolate->GetCurrentContext(), i, element_value).FromJust();
2279 }
2280 result = array;
2281 break;
2282 }
2283 case kSerializationTagObject: {
2284 int length = data.Read<int>(offset);
2285 Local<Object> object = Object::New(isolate);
2286 for (int i = 0; i < length; ++i) {
2287 Local<Value> property_name;
2288 CHECK(DeserializeValue(isolate, data, offset).ToLocal(&property_name));
2289 Local<Value> property_value;
2290 CHECK(DeserializeValue(isolate, data, offset).ToLocal(&property_value));
2291 object->Set(isolate->GetCurrentContext(), property_name, property_value)
2292 .FromJust();
2293 }
2294 result = object;
2295 break;
2296 }
2297 case kSerializationTagArrayBuffer: {
2298 int32_t byte_length = data.Read<int32_t>(offset);
2299 Local<ArrayBuffer> array_buffer = ArrayBuffer::New(isolate, byte_length);
2300 ArrayBuffer::Contents contents = array_buffer->GetContents();
2301 DCHECK(static_cast<size_t>(byte_length) == contents.ByteLength());
2302 data.ReadMemory(contents.Data(), byte_length, offset);
2303 result = array_buffer;
2304 break;
2305 }
2306 case kSerializationTagTransferredArrayBuffer: {
2307 ArrayBuffer::Contents contents;
2308 data.ReadArrayBufferContents(&contents, offset);
2309 result = ArrayBuffer::New(isolate, contents.Data(), contents.ByteLength(),
2310 ArrayBufferCreationMode::kInternalized);
2311 break;
2312 }
2313 case kSerializationTagTransferredSharedArrayBuffer: {
2314 SharedArrayBuffer::Contents contents;
2315 data.ReadSharedArrayBufferContents(&contents, offset);
2316 result = SharedArrayBuffer::New(isolate, contents.Data(),
2317 contents.ByteLength());
2318 break;
2319 }
2320 default:
2321 UNREACHABLE();
2322 }
2323
2324 return scope.Escape(result);
2325 }
2326
2327
CleanupWorkers()2328 void Shell::CleanupWorkers() {
2329 // Make a copy of workers_, because we don't want to call Worker::Terminate
2330 // while holding the workers_mutex_ lock. Otherwise, if a worker is about to
2331 // create a new Worker, it would deadlock.
2332 i::List<Worker*> workers_copy;
2333 {
2334 base::LockGuard<base::Mutex> lock_guard(workers_mutex_.Pointer());
2335 allow_new_workers_ = false;
2336 workers_copy.AddAll(workers_);
2337 workers_.Clear();
2338 }
2339
2340 for (int i = 0; i < workers_copy.length(); ++i) {
2341 Worker* worker = workers_copy[i];
2342 worker->WaitForThread();
2343 delete worker;
2344 }
2345
2346 // Now that all workers are terminated, we can re-enable Worker creation.
2347 base::LockGuard<base::Mutex> lock_guard(workers_mutex_.Pointer());
2348 allow_new_workers_ = true;
2349
2350 for (int i = 0; i < externalized_shared_contents_.length(); ++i) {
2351 const SharedArrayBuffer::Contents& contents =
2352 externalized_shared_contents_[i];
2353 Shell::array_buffer_allocator->Free(contents.Data(), contents.ByteLength());
2354 }
2355 externalized_shared_contents_.Clear();
2356 }
2357
2358
DumpHeapConstants(i::Isolate * isolate)2359 static void DumpHeapConstants(i::Isolate* isolate) {
2360 i::Heap* heap = isolate->heap();
2361
2362 // Dump the INSTANCE_TYPES table to the console.
2363 printf("# List of known V8 instance types.\n");
2364 #define DUMP_TYPE(T) printf(" %d: \"%s\",\n", i::T, #T);
2365 printf("INSTANCE_TYPES = {\n");
2366 INSTANCE_TYPE_LIST(DUMP_TYPE)
2367 printf("}\n");
2368 #undef DUMP_TYPE
2369
2370 // Dump the KNOWN_MAP table to the console.
2371 printf("\n# List of known V8 maps.\n");
2372 #define ROOT_LIST_CASE(type, name, camel_name) \
2373 if (n == NULL && o == heap->name()) n = #camel_name;
2374 #define STRUCT_LIST_CASE(upper_name, camel_name, name) \
2375 if (n == NULL && o == heap->name##_map()) n = #camel_name "Map";
2376 i::HeapObjectIterator it(heap->map_space());
2377 printf("KNOWN_MAPS = {\n");
2378 for (i::Object* o = it.Next(); o != NULL; o = it.Next()) {
2379 i::Map* m = i::Map::cast(o);
2380 const char* n = NULL;
2381 intptr_t p = reinterpret_cast<intptr_t>(m) & 0xfffff;
2382 int t = m->instance_type();
2383 ROOT_LIST(ROOT_LIST_CASE)
2384 STRUCT_LIST(STRUCT_LIST_CASE)
2385 if (n == NULL) continue;
2386 printf(" 0x%05" V8PRIxPTR ": (%d, \"%s\"),\n", p, t, n);
2387 }
2388 printf("}\n");
2389 #undef STRUCT_LIST_CASE
2390 #undef ROOT_LIST_CASE
2391
2392 // Dump the KNOWN_OBJECTS table to the console.
2393 printf("\n# List of known V8 objects.\n");
2394 #define ROOT_LIST_CASE(type, name, camel_name) \
2395 if (n == NULL && o == heap->name()) n = #camel_name;
2396 i::OldSpaces spit(heap);
2397 printf("KNOWN_OBJECTS = {\n");
2398 for (i::PagedSpace* s = spit.next(); s != NULL; s = spit.next()) {
2399 i::HeapObjectIterator it(s);
2400 const char* sname = AllocationSpaceName(s->identity());
2401 for (i::Object* o = it.Next(); o != NULL; o = it.Next()) {
2402 const char* n = NULL;
2403 intptr_t p = reinterpret_cast<intptr_t>(o) & 0xfffff;
2404 ROOT_LIST(ROOT_LIST_CASE)
2405 if (n == NULL) continue;
2406 printf(" (\"%s\", 0x%05" V8PRIxPTR "): \"%s\",\n", sname, p, n);
2407 }
2408 }
2409 printf("}\n");
2410 #undef ROOT_LIST_CASE
2411 }
2412 #endif // !V8_SHARED
2413
2414
Main(int argc,char * argv[])2415 int Shell::Main(int argc, char* argv[]) {
2416 #if (defined(_WIN32) || defined(_WIN64))
2417 UINT new_flags =
2418 SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX;
2419 UINT existing_flags = SetErrorMode(new_flags);
2420 SetErrorMode(existing_flags | new_flags);
2421 #if defined(_MSC_VER)
2422 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_DEBUG | _CRTDBG_MODE_FILE);
2423 _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
2424 _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_DEBUG | _CRTDBG_MODE_FILE);
2425 _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
2426 _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_DEBUG | _CRTDBG_MODE_FILE);
2427 _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR);
2428 _set_error_mode(_OUT_TO_STDERR);
2429 #endif // defined(_MSC_VER)
2430 #endif // defined(_WIN32) || defined(_WIN64)
2431 if (!SetOptions(argc, argv)) return 1;
2432 v8::V8::InitializeICU(options.icu_data_file);
2433 #ifndef V8_SHARED
2434 g_platform = i::FLAG_verify_predictable
2435 ? new PredictablePlatform()
2436 : v8::platform::CreateDefaultPlatform();
2437 #else
2438 g_platform = v8::platform::CreateDefaultPlatform();
2439 #endif // !V8_SHARED
2440
2441 v8::V8::InitializePlatform(g_platform);
2442 v8::V8::Initialize();
2443 if (options.natives_blob || options.snapshot_blob) {
2444 v8::V8::InitializeExternalStartupData(options.natives_blob,
2445 options.snapshot_blob);
2446 } else {
2447 v8::V8::InitializeExternalStartupData(argv[0]);
2448 }
2449 SetFlagsFromString("--trace-hydrogen-file=hydrogen.cfg");
2450 SetFlagsFromString("--trace-turbo-cfg-file=turbo.cfg");
2451 SetFlagsFromString("--redirect-code-traces-to=code.asm");
2452 int result = 0;
2453 Isolate::CreateParams create_params;
2454 ShellArrayBufferAllocator shell_array_buffer_allocator;
2455 MockArrayBufferAllocator mock_arraybuffer_allocator;
2456 if (options.mock_arraybuffer_allocator) {
2457 Shell::array_buffer_allocator = &mock_arraybuffer_allocator;
2458 } else {
2459 Shell::array_buffer_allocator = &shell_array_buffer_allocator;
2460 }
2461 create_params.array_buffer_allocator = Shell::array_buffer_allocator;
2462 #if !defined(V8_SHARED) && defined(ENABLE_GDB_JIT_INTERFACE)
2463 if (i::FLAG_gdbjit) {
2464 create_params.code_event_handler = i::GDBJITInterface::EventHandler;
2465 }
2466 #endif
2467 #ifdef ENABLE_VTUNE_JIT_INTERFACE
2468 create_params.code_event_handler = vTune::GetVtuneCodeEventHandler();
2469 #endif
2470 #ifndef V8_SHARED
2471 create_params.constraints.ConfigureDefaults(
2472 base::SysInfo::AmountOfPhysicalMemory(),
2473 base::SysInfo::AmountOfVirtualMemory());
2474
2475 Shell::counter_map_ = new CounterMap();
2476 if (i::FLAG_dump_counters || i::FLAG_track_gc_object_stats) {
2477 create_params.counter_lookup_callback = LookupCounter;
2478 create_params.create_histogram_callback = CreateHistogram;
2479 create_params.add_histogram_sample_callback = AddHistogramSample;
2480 }
2481 #endif
2482 Isolate* isolate = Isolate::New(create_params);
2483 {
2484 Isolate::Scope scope(isolate);
2485 Initialize(isolate);
2486 PerIsolateData data(isolate);
2487
2488 #ifndef V8_SHARED
2489 if (options.dump_heap_constants) {
2490 DumpHeapConstants(reinterpret_cast<i::Isolate*>(isolate));
2491 return 0;
2492 }
2493 #endif
2494
2495 if (options.stress_opt || options.stress_deopt) {
2496 Testing::SetStressRunType(options.stress_opt
2497 ? Testing::kStressTypeOpt
2498 : Testing::kStressTypeDeopt);
2499 options.stress_runs = Testing::GetStressRuns();
2500 for (int i = 0; i < options.stress_runs && result == 0; i++) {
2501 printf("============ Stress %d/%d ============\n", i + 1,
2502 options.stress_runs);
2503 Testing::PrepareStressRun(i);
2504 bool last_run = i == options.stress_runs - 1;
2505 result = RunMain(isolate, argc, argv, last_run);
2506 }
2507 printf("======== Full Deoptimization =======\n");
2508 Testing::DeoptimizeAll(isolate);
2509 #if !defined(V8_SHARED)
2510 } else if (i::FLAG_stress_runs > 0) {
2511 options.stress_runs = i::FLAG_stress_runs;
2512 for (int i = 0; i < options.stress_runs && result == 0; i++) {
2513 printf("============ Run %d/%d ============\n", i + 1,
2514 options.stress_runs);
2515 bool last_run = i == options.stress_runs - 1;
2516 result = RunMain(isolate, argc, argv, last_run);
2517 }
2518 #endif
2519 } else {
2520 bool last_run = true;
2521 result = RunMain(isolate, argc, argv, last_run);
2522 }
2523
2524 // Run interactive shell if explicitly requested or if no script has been
2525 // executed, but never on --test
2526 if (options.use_interactive_shell()) {
2527 #ifndef V8_SHARED
2528 InstallUtilityScript(isolate);
2529 #endif // !V8_SHARED
2530 RunShell(isolate);
2531 }
2532
2533 // Shut down contexts and collect garbage.
2534 evaluation_context_.Reset();
2535 #ifndef V8_SHARED
2536 utility_context_.Reset();
2537 #endif // !V8_SHARED
2538 CollectGarbage(isolate);
2539 }
2540 OnExit(isolate);
2541 #ifndef V8_SHARED
2542 // Dump basic block profiling data.
2543 if (i::BasicBlockProfiler* profiler =
2544 reinterpret_cast<i::Isolate*>(isolate)->basic_block_profiler()) {
2545 i::OFStream os(stdout);
2546 os << *profiler;
2547 }
2548 #endif // !V8_SHARED
2549 isolate->Dispose();
2550 V8::Dispose();
2551 V8::ShutdownPlatform();
2552 delete g_platform;
2553
2554 return result;
2555 }
2556
2557 } // namespace v8
2558
2559
2560 #ifndef GOOGLE3
main(int argc,char * argv[])2561 int main(int argc, char* argv[]) {
2562 return v8::Shell::Main(argc, argv);
2563 }
2564 #endif
2565