661307f0dfebb306d7db20293ab3c50f2716067d
[platform/framework/web/crosswalk.git] / src / v8 / src / d8.cc
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 #ifdef COMPRESS_STARTUP_DATA_BZ2
12 #include <bzlib.h>
13 #endif
14
15 #include <errno.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <sys/stat.h>
19
20 #ifdef V8_SHARED
21 #include <assert.h>
22 #endif  // V8_SHARED
23
24 #ifndef V8_SHARED
25 #include <algorithm>
26 #endif  // !V8_SHARED
27
28 #ifdef V8_SHARED
29 #include "include/v8-testing.h"
30 #endif  // V8_SHARED
31
32 #ifdef ENABLE_VTUNE_JIT_INTERFACE
33 #include "src/third_party/vtune/v8-vtune.h"
34 #endif
35
36 #include "src/d8.h"
37
38 #ifndef V8_SHARED
39 #include "src/api.h"
40 #include "src/checks.h"
41 #include "src/cpu.h"
42 #include "src/d8-debug.h"
43 #include "src/debug.h"
44 #include "src/natives.h"
45 #include "src/platform.h"
46 #include "src/v8.h"
47 #endif  // !V8_SHARED
48
49 #if !defined(_WIN32) && !defined(_WIN64)
50 #include <unistd.h>  // NOLINT
51 #endif
52
53 #ifndef ASSERT
54 #define ASSERT(condition) assert(condition)
55 #endif
56
57 namespace v8 {
58
59
60 static Handle<Value> Throw(Isolate* isolate, const char* message) {
61   return isolate->ThrowException(String::NewFromUtf8(isolate, message));
62 }
63
64
65
66 class PerIsolateData {
67  public:
68   explicit PerIsolateData(Isolate* isolate) : isolate_(isolate), realms_(NULL) {
69     HandleScope scope(isolate);
70     isolate->SetData(0, this);
71   }
72
73   ~PerIsolateData() {
74     isolate_->SetData(0, NULL);  // Not really needed, just to be sure...
75   }
76
77   inline static PerIsolateData* Get(Isolate* isolate) {
78     return reinterpret_cast<PerIsolateData*>(isolate->GetData(0));
79   }
80
81   class RealmScope {
82    public:
83     explicit RealmScope(PerIsolateData* data);
84     ~RealmScope();
85    private:
86     PerIsolateData* data_;
87   };
88
89  private:
90   friend class Shell;
91   friend class RealmScope;
92   Isolate* isolate_;
93   int realm_count_;
94   int realm_current_;
95   int realm_switch_;
96   Persistent<Context>* realms_;
97   Persistent<Value> realm_shared_;
98
99   int RealmIndexOrThrow(const v8::FunctionCallbackInfo<v8::Value>& args,
100                         int arg_offset);
101   int RealmFind(Handle<Context> context);
102 };
103
104
105 LineEditor *LineEditor::current_ = NULL;
106
107
108 LineEditor::LineEditor(Type type, const char* name)
109     : type_(type), name_(name) {
110   if (current_ == NULL || current_->type_ < type) current_ = this;
111 }
112
113
114 class DumbLineEditor: public LineEditor {
115  public:
116   explicit DumbLineEditor(Isolate* isolate)
117       : LineEditor(LineEditor::DUMB, "dumb"), isolate_(isolate) { }
118   virtual Handle<String> Prompt(const char* prompt);
119  private:
120   Isolate* isolate_;
121 };
122
123
124 Handle<String> DumbLineEditor::Prompt(const char* prompt) {
125   printf("%s", prompt);
126 #if defined(__native_client__)
127   // Native Client libc is used to being embedded in Chrome and
128   // has trouble recognizing when to flush.
129   fflush(stdout);
130 #endif
131   return Shell::ReadFromStdin(isolate_);
132 }
133
134
135 #ifndef V8_SHARED
136 CounterMap* Shell::counter_map_;
137 i::OS::MemoryMappedFile* Shell::counters_file_ = NULL;
138 CounterCollection Shell::local_counters_;
139 CounterCollection* Shell::counters_ = &local_counters_;
140 i::Mutex Shell::context_mutex_;
141 const i::TimeTicks Shell::kInitialTicks = i::TimeTicks::HighResolutionNow();
142 Persistent<Context> Shell::utility_context_;
143 #endif  // !V8_SHARED
144
145 Persistent<Context> Shell::evaluation_context_;
146 ShellOptions Shell::options;
147 const char* Shell::kPrompt = "d8> ";
148
149
150 #ifndef V8_SHARED
151 const int MB = 1024 * 1024;
152
153 bool CounterMap::Match(void* key1, void* key2) {
154   const char* name1 = reinterpret_cast<const char*>(key1);
155   const char* name2 = reinterpret_cast<const char*>(key2);
156   return strcmp(name1, name2) == 0;
157 }
158 #endif  // !V8_SHARED
159
160
161 // Converts a V8 value to a C string.
162 const char* Shell::ToCString(const v8::String::Utf8Value& value) {
163   return *value ? *value : "<string conversion failed>";
164 }
165
166
167 // Executes a string within the current v8 context.
168 bool Shell::ExecuteString(Isolate* isolate,
169                           Handle<String> source,
170                           Handle<Value> name,
171                           bool print_result,
172                           bool report_exceptions) {
173 #ifndef V8_SHARED
174   bool FLAG_debugger = i::FLAG_debugger;
175 #else
176   bool FLAG_debugger = false;
177 #endif  // !V8_SHARED
178   HandleScope handle_scope(isolate);
179   TryCatch try_catch;
180   options.script_executed = true;
181   if (FLAG_debugger) {
182     // When debugging make exceptions appear to be uncaught.
183     try_catch.SetVerbose(true);
184   }
185   ScriptOrigin origin(name);
186   ScriptCompiler::Source script_source(source, origin);
187   Handle<UnboundScript> script =
188       ScriptCompiler::CompileUnbound(isolate, &script_source);
189   if (script.IsEmpty()) {
190     // Print errors that happened during compilation.
191     if (report_exceptions && !FLAG_debugger)
192       ReportException(isolate, &try_catch);
193     return false;
194   } else {
195     PerIsolateData* data = PerIsolateData::Get(isolate);
196     Local<Context> realm =
197         Local<Context>::New(isolate, data->realms_[data->realm_current_]);
198     realm->Enter();
199     Handle<Value> result = script->BindToCurrentContext()->Run();
200     realm->Exit();
201     data->realm_current_ = data->realm_switch_;
202     if (result.IsEmpty()) {
203       ASSERT(try_catch.HasCaught());
204       // Print errors that happened during execution.
205       if (report_exceptions && !FLAG_debugger)
206         ReportException(isolate, &try_catch);
207       return false;
208     } else {
209       ASSERT(!try_catch.HasCaught());
210       if (print_result) {
211 #if !defined(V8_SHARED)
212         if (options.test_shell) {
213 #endif
214           if (!result->IsUndefined()) {
215             // If all went well and the result wasn't undefined then print
216             // the returned value.
217             v8::String::Utf8Value str(result);
218             fwrite(*str, sizeof(**str), str.length(), stdout);
219             printf("\n");
220           }
221 #if !defined(V8_SHARED)
222         } else {
223           v8::TryCatch try_catch;
224           v8::Local<v8::Context> context =
225               v8::Local<v8::Context>::New(isolate, utility_context_);
226           v8::Context::Scope context_scope(context);
227           Handle<Object> global = context->Global();
228           Handle<Value> fun =
229               global->Get(String::NewFromUtf8(isolate, "Stringify"));
230           Handle<Value> argv[1] = { result };
231           Handle<Value> s = Handle<Function>::Cast(fun)->Call(global, 1, argv);
232           if (try_catch.HasCaught()) return true;
233           v8::String::Utf8Value str(s);
234           fwrite(*str, sizeof(**str), str.length(), stdout);
235           printf("\n");
236         }
237 #endif
238       }
239       return true;
240     }
241   }
242 }
243
244
245 PerIsolateData::RealmScope::RealmScope(PerIsolateData* data) : data_(data) {
246   data_->realm_count_ = 1;
247   data_->realm_current_ = 0;
248   data_->realm_switch_ = 0;
249   data_->realms_ = new Persistent<Context>[1];
250   data_->realms_[0].Reset(data_->isolate_,
251                           data_->isolate_->GetEnteredContext());
252 }
253
254
255 PerIsolateData::RealmScope::~RealmScope() {
256   // Drop realms to avoid keeping them alive.
257   for (int i = 0; i < data_->realm_count_; ++i)
258     data_->realms_[i].Reset();
259   delete[] data_->realms_;
260   if (!data_->realm_shared_.IsEmpty())
261     data_->realm_shared_.Reset();
262 }
263
264
265 int PerIsolateData::RealmFind(Handle<Context> context) {
266   for (int i = 0; i < realm_count_; ++i) {
267     if (realms_[i] == context) return i;
268   }
269   return -1;
270 }
271
272
273 int PerIsolateData::RealmIndexOrThrow(
274     const v8::FunctionCallbackInfo<v8::Value>& args,
275     int arg_offset) {
276   if (args.Length() < arg_offset || !args[arg_offset]->IsNumber()) {
277     Throw(args.GetIsolate(), "Invalid argument");
278     return -1;
279   }
280   int index = args[arg_offset]->Int32Value();
281   if (index < 0 ||
282       index >= realm_count_ ||
283       realms_[index].IsEmpty()) {
284     Throw(args.GetIsolate(), "Invalid realm index");
285     return -1;
286   }
287   return index;
288 }
289
290
291 #ifndef V8_SHARED
292 // performance.now() returns a time stamp as double, measured in milliseconds.
293 void Shell::PerformanceNow(const v8::FunctionCallbackInfo<v8::Value>& args) {
294   i::TimeDelta delta = i::TimeTicks::HighResolutionNow() - kInitialTicks;
295   args.GetReturnValue().Set(delta.InMillisecondsF());
296 }
297 #endif  // !V8_SHARED
298
299
300 // Realm.current() returns the index of the currently active realm.
301 void Shell::RealmCurrent(const v8::FunctionCallbackInfo<v8::Value>& args) {
302   Isolate* isolate = args.GetIsolate();
303   PerIsolateData* data = PerIsolateData::Get(isolate);
304   int index = data->RealmFind(isolate->GetEnteredContext());
305   if (index == -1) return;
306   args.GetReturnValue().Set(index);
307 }
308
309
310 // Realm.owner(o) returns the index of the realm that created o.
311 void Shell::RealmOwner(const v8::FunctionCallbackInfo<v8::Value>& args) {
312   Isolate* isolate = args.GetIsolate();
313   PerIsolateData* data = PerIsolateData::Get(isolate);
314   if (args.Length() < 1 || !args[0]->IsObject()) {
315     Throw(args.GetIsolate(), "Invalid argument");
316     return;
317   }
318   int index = data->RealmFind(args[0]->ToObject()->CreationContext());
319   if (index == -1) return;
320   args.GetReturnValue().Set(index);
321 }
322
323
324 // Realm.global(i) returns the global object of realm i.
325 // (Note that properties of global objects cannot be read/written cross-realm.)
326 void Shell::RealmGlobal(const v8::FunctionCallbackInfo<v8::Value>& args) {
327   PerIsolateData* data = PerIsolateData::Get(args.GetIsolate());
328   int index = data->RealmIndexOrThrow(args, 0);
329   if (index == -1) return;
330   args.GetReturnValue().Set(
331       Local<Context>::New(args.GetIsolate(), data->realms_[index])->Global());
332 }
333
334
335 // Realm.create() creates a new realm and returns its index.
336 void Shell::RealmCreate(const v8::FunctionCallbackInfo<v8::Value>& args) {
337   Isolate* isolate = args.GetIsolate();
338   PerIsolateData* data = PerIsolateData::Get(isolate);
339   Persistent<Context>* old_realms = data->realms_;
340   int index = data->realm_count_;
341   data->realms_ = new Persistent<Context>[++data->realm_count_];
342   for (int i = 0; i < index; ++i) {
343     data->realms_[i].Reset(isolate, old_realms[i]);
344   }
345   delete[] old_realms;
346   Handle<ObjectTemplate> global_template = CreateGlobalTemplate(isolate);
347   data->realms_[index].Reset(
348       isolate, Context::New(isolate, NULL, global_template));
349   args.GetReturnValue().Set(index);
350 }
351
352
353 // Realm.dispose(i) disposes the reference to the realm i.
354 void Shell::RealmDispose(const v8::FunctionCallbackInfo<v8::Value>& args) {
355   Isolate* isolate = args.GetIsolate();
356   PerIsolateData* data = PerIsolateData::Get(isolate);
357   int index = data->RealmIndexOrThrow(args, 0);
358   if (index == -1) return;
359   if (index == 0 ||
360       index == data->realm_current_ || index == data->realm_switch_) {
361     Throw(args.GetIsolate(), "Invalid realm index");
362     return;
363   }
364   data->realms_[index].Reset();
365 }
366
367
368 // Realm.switch(i) switches to the realm i for consecutive interactive inputs.
369 void Shell::RealmSwitch(const v8::FunctionCallbackInfo<v8::Value>& args) {
370   Isolate* isolate = args.GetIsolate();
371   PerIsolateData* data = PerIsolateData::Get(isolate);
372   int index = data->RealmIndexOrThrow(args, 0);
373   if (index == -1) return;
374   data->realm_switch_ = index;
375 }
376
377
378 // Realm.eval(i, s) evaluates s in realm i and returns the result.
379 void Shell::RealmEval(const v8::FunctionCallbackInfo<v8::Value>& args) {
380   Isolate* isolate = args.GetIsolate();
381   PerIsolateData* data = PerIsolateData::Get(isolate);
382   int index = data->RealmIndexOrThrow(args, 0);
383   if (index == -1) return;
384   if (args.Length() < 2 || !args[1]->IsString()) {
385     Throw(args.GetIsolate(), "Invalid argument");
386     return;
387   }
388   ScriptCompiler::Source script_source(args[1]->ToString());
389   Handle<UnboundScript> script = ScriptCompiler::CompileUnbound(
390       isolate, &script_source);
391   if (script.IsEmpty()) return;
392   Local<Context> realm = Local<Context>::New(isolate, data->realms_[index]);
393   realm->Enter();
394   Handle<Value> result = script->BindToCurrentContext()->Run();
395   realm->Exit();
396   args.GetReturnValue().Set(result);
397 }
398
399
400 // Realm.shared is an accessor for a single shared value across realms.
401 void Shell::RealmSharedGet(Local<String> property,
402                            const PropertyCallbackInfo<Value>& info) {
403   Isolate* isolate = info.GetIsolate();
404   PerIsolateData* data = PerIsolateData::Get(isolate);
405   if (data->realm_shared_.IsEmpty()) return;
406   info.GetReturnValue().Set(data->realm_shared_);
407 }
408
409 void Shell::RealmSharedSet(Local<String> property,
410                            Local<Value> value,
411                            const PropertyCallbackInfo<void>& info) {
412   Isolate* isolate = info.GetIsolate();
413   PerIsolateData* data = PerIsolateData::Get(isolate);
414   data->realm_shared_.Reset(isolate, value);
415 }
416
417
418 void Shell::Print(const v8::FunctionCallbackInfo<v8::Value>& args) {
419   Write(args);
420   printf("\n");
421   fflush(stdout);
422 }
423
424
425 void Shell::Write(const v8::FunctionCallbackInfo<v8::Value>& args) {
426   for (int i = 0; i < args.Length(); i++) {
427     HandleScope handle_scope(args.GetIsolate());
428     if (i != 0) {
429       printf(" ");
430     }
431
432     // Explicitly catch potential exceptions in toString().
433     v8::TryCatch try_catch;
434     Handle<String> str_obj = args[i]->ToString();
435     if (try_catch.HasCaught()) {
436       try_catch.ReThrow();
437       return;
438     }
439
440     v8::String::Utf8Value str(str_obj);
441     int n = static_cast<int>(fwrite(*str, sizeof(**str), str.length(), stdout));
442     if (n != str.length()) {
443       printf("Error in fwrite\n");
444       Exit(1);
445     }
446   }
447 }
448
449
450 void Shell::Read(const v8::FunctionCallbackInfo<v8::Value>& args) {
451   String::Utf8Value file(args[0]);
452   if (*file == NULL) {
453     Throw(args.GetIsolate(), "Error loading file");
454     return;
455   }
456   Handle<String> source = ReadFile(args.GetIsolate(), *file);
457   if (source.IsEmpty()) {
458     Throw(args.GetIsolate(), "Error loading file");
459     return;
460   }
461   args.GetReturnValue().Set(source);
462 }
463
464
465 Handle<String> Shell::ReadFromStdin(Isolate* isolate) {
466   static const int kBufferSize = 256;
467   char buffer[kBufferSize];
468   Handle<String> accumulator = String::NewFromUtf8(isolate, "");
469   int length;
470   while (true) {
471     // Continue reading if the line ends with an escape '\\' or the line has
472     // not been fully read into the buffer yet (does not end with '\n').
473     // If fgets gets an error, just give up.
474     char* input = NULL;
475     input = fgets(buffer, kBufferSize, stdin);
476     if (input == NULL) return Handle<String>();
477     length = static_cast<int>(strlen(buffer));
478     if (length == 0) {
479       return accumulator;
480     } else if (buffer[length-1] != '\n') {
481       accumulator = String::Concat(
482           accumulator,
483           String::NewFromUtf8(isolate, buffer, String::kNormalString, length));
484     } else if (length > 1 && buffer[length-2] == '\\') {
485       buffer[length-2] = '\n';
486       accumulator = String::Concat(
487           accumulator, String::NewFromUtf8(isolate, buffer,
488                                            String::kNormalString, length - 1));
489     } else {
490       return String::Concat(
491           accumulator, String::NewFromUtf8(isolate, buffer,
492                                            String::kNormalString, length - 1));
493     }
494   }
495 }
496
497
498 void Shell::Load(const v8::FunctionCallbackInfo<v8::Value>& args) {
499   for (int i = 0; i < args.Length(); i++) {
500     HandleScope handle_scope(args.GetIsolate());
501     String::Utf8Value file(args[i]);
502     if (*file == NULL) {
503       Throw(args.GetIsolate(), "Error loading file");
504       return;
505     }
506     Handle<String> source = ReadFile(args.GetIsolate(), *file);
507     if (source.IsEmpty()) {
508       Throw(args.GetIsolate(), "Error loading file");
509       return;
510     }
511     if (!ExecuteString(args.GetIsolate(),
512                        source,
513                        String::NewFromUtf8(args.GetIsolate(), *file),
514                        false,
515                        true)) {
516       Throw(args.GetIsolate(), "Error executing file");
517       return;
518     }
519   }
520 }
521
522
523 void Shell::Quit(const v8::FunctionCallbackInfo<v8::Value>& args) {
524   int exit_code = args[0]->Int32Value();
525   OnExit();
526   exit(exit_code);
527 }
528
529
530 void Shell::Version(const v8::FunctionCallbackInfo<v8::Value>& args) {
531   args.GetReturnValue().Set(
532       String::NewFromUtf8(args.GetIsolate(), V8::GetVersion()));
533 }
534
535
536 void Shell::ReportException(Isolate* isolate, v8::TryCatch* try_catch) {
537   HandleScope handle_scope(isolate);
538 #ifndef V8_SHARED
539   Handle<Context> utility_context;
540   bool enter_context = !isolate->InContext();
541   if (enter_context) {
542     utility_context = Local<Context>::New(isolate, utility_context_);
543     utility_context->Enter();
544   }
545 #endif  // !V8_SHARED
546   v8::String::Utf8Value exception(try_catch->Exception());
547   const char* exception_string = ToCString(exception);
548   Handle<Message> message = try_catch->Message();
549   if (message.IsEmpty()) {
550     // V8 didn't provide any extra information about this error; just
551     // print the exception.
552     printf("%s\n", exception_string);
553   } else {
554     // Print (filename):(line number): (message).
555     v8::String::Utf8Value filename(message->GetScriptResourceName());
556     const char* filename_string = ToCString(filename);
557     int linenum = message->GetLineNumber();
558     printf("%s:%i: %s\n", filename_string, linenum, exception_string);
559     // Print line of source code.
560     v8::String::Utf8Value sourceline(message->GetSourceLine());
561     const char* sourceline_string = ToCString(sourceline);
562     printf("%s\n", sourceline_string);
563     // Print wavy underline (GetUnderline is deprecated).
564     int start = message->GetStartColumn();
565     for (int i = 0; i < start; i++) {
566       printf(" ");
567     }
568     int end = message->GetEndColumn();
569     for (int i = start; i < end; i++) {
570       printf("^");
571     }
572     printf("\n");
573     v8::String::Utf8Value stack_trace(try_catch->StackTrace());
574     if (stack_trace.length() > 0) {
575       const char* stack_trace_string = ToCString(stack_trace);
576       printf("%s\n", stack_trace_string);
577     }
578   }
579   printf("\n");
580 #ifndef V8_SHARED
581   if (enter_context) utility_context->Exit();
582 #endif  // !V8_SHARED
583 }
584
585
586 #ifndef V8_SHARED
587 Handle<Array> Shell::GetCompletions(Isolate* isolate,
588                                     Handle<String> text,
589                                     Handle<String> full) {
590   EscapableHandleScope handle_scope(isolate);
591   v8::Local<v8::Context> utility_context =
592       v8::Local<v8::Context>::New(isolate, utility_context_);
593   v8::Context::Scope context_scope(utility_context);
594   Handle<Object> global = utility_context->Global();
595   Local<Value> fun =
596       global->Get(String::NewFromUtf8(isolate, "GetCompletions"));
597   static const int kArgc = 3;
598   v8::Local<v8::Context> evaluation_context =
599       v8::Local<v8::Context>::New(isolate, evaluation_context_);
600   Handle<Value> argv[kArgc] = { evaluation_context->Global(), text, full };
601   Local<Value> val = Local<Function>::Cast(fun)->Call(global, kArgc, argv);
602   return handle_scope.Escape(Local<Array>::Cast(val));
603 }
604
605
606 Local<Object> Shell::DebugMessageDetails(Isolate* isolate,
607                                          Handle<String> message) {
608   EscapableHandleScope handle_scope(isolate);
609   v8::Local<v8::Context> context =
610       v8::Local<v8::Context>::New(isolate, utility_context_);
611   v8::Context::Scope context_scope(context);
612   Handle<Object> global = context->Global();
613   Handle<Value> fun =
614       global->Get(String::NewFromUtf8(isolate, "DebugMessageDetails"));
615   static const int kArgc = 1;
616   Handle<Value> argv[kArgc] = { message };
617   Handle<Value> val = Handle<Function>::Cast(fun)->Call(global, kArgc, argv);
618   return handle_scope.Escape(Local<Object>(Handle<Object>::Cast(val)));
619 }
620
621
622 Local<Value> Shell::DebugCommandToJSONRequest(Isolate* isolate,
623                                               Handle<String> command) {
624   EscapableHandleScope handle_scope(isolate);
625   v8::Local<v8::Context> context =
626       v8::Local<v8::Context>::New(isolate, utility_context_);
627   v8::Context::Scope context_scope(context);
628   Handle<Object> global = context->Global();
629   Handle<Value> fun =
630       global->Get(String::NewFromUtf8(isolate, "DebugCommandToJSONRequest"));
631   static const int kArgc = 1;
632   Handle<Value> argv[kArgc] = { command };
633   Handle<Value> val = Handle<Function>::Cast(fun)->Call(global, kArgc, argv);
634   return handle_scope.Escape(Local<Value>(val));
635 }
636
637
638 int32_t* Counter::Bind(const char* name, bool is_histogram) {
639   int i;
640   for (i = 0; i < kMaxNameSize - 1 && name[i]; i++)
641     name_[i] = static_cast<char>(name[i]);
642   name_[i] = '\0';
643   is_histogram_ = is_histogram;
644   return ptr();
645 }
646
647
648 void Counter::AddSample(int32_t sample) {
649   count_++;
650   sample_total_ += sample;
651 }
652
653
654 CounterCollection::CounterCollection() {
655   magic_number_ = 0xDEADFACE;
656   max_counters_ = kMaxCounters;
657   max_name_size_ = Counter::kMaxNameSize;
658   counters_in_use_ = 0;
659 }
660
661
662 Counter* CounterCollection::GetNextCounter() {
663   if (counters_in_use_ == kMaxCounters) return NULL;
664   return &counters_[counters_in_use_++];
665 }
666
667
668 void Shell::MapCounters(v8::Isolate* isolate, const char* name) {
669   counters_file_ = i::OS::MemoryMappedFile::create(
670       name, sizeof(CounterCollection), &local_counters_);
671   void* memory = (counters_file_ == NULL) ?
672       NULL : counters_file_->memory();
673   if (memory == NULL) {
674     printf("Could not map counters file %s\n", name);
675     Exit(1);
676   }
677   counters_ = static_cast<CounterCollection*>(memory);
678   isolate->SetCounterFunction(LookupCounter);
679   isolate->SetCreateHistogramFunction(CreateHistogram);
680   isolate->SetAddHistogramSampleFunction(AddHistogramSample);
681 }
682
683
684 int CounterMap::Hash(const char* name) {
685   int h = 0;
686   int c;
687   while ((c = *name++) != 0) {
688     h += h << 5;
689     h += c;
690   }
691   return h;
692 }
693
694
695 Counter* Shell::GetCounter(const char* name, bool is_histogram) {
696   Counter* counter = counter_map_->Lookup(name);
697
698   if (counter == NULL) {
699     counter = counters_->GetNextCounter();
700     if (counter != NULL) {
701       counter_map_->Set(name, counter);
702       counter->Bind(name, is_histogram);
703     }
704   } else {
705     ASSERT(counter->is_histogram() == is_histogram);
706   }
707   return counter;
708 }
709
710
711 int* Shell::LookupCounter(const char* name) {
712   Counter* counter = GetCounter(name, false);
713
714   if (counter != NULL) {
715     return counter->ptr();
716   } else {
717     return NULL;
718   }
719 }
720
721
722 void* Shell::CreateHistogram(const char* name,
723                              int min,
724                              int max,
725                              size_t buckets) {
726   return GetCounter(name, true);
727 }
728
729
730 void Shell::AddHistogramSample(void* histogram, int sample) {
731   Counter* counter = reinterpret_cast<Counter*>(histogram);
732   counter->AddSample(sample);
733 }
734
735
736 void Shell::InstallUtilityScript(Isolate* isolate) {
737   HandleScope scope(isolate);
738   // If we use the utility context, we have to set the security tokens so that
739   // utility, evaluation and debug context can all access each other.
740   v8::Local<v8::Context> utility_context =
741       v8::Local<v8::Context>::New(isolate, utility_context_);
742   v8::Local<v8::Context> evaluation_context =
743       v8::Local<v8::Context>::New(isolate, evaluation_context_);
744   utility_context->SetSecurityToken(Undefined(isolate));
745   evaluation_context->SetSecurityToken(Undefined(isolate));
746   v8::Context::Scope context_scope(utility_context);
747
748   if (i::FLAG_debugger) printf("JavaScript debugger enabled\n");
749   // Install the debugger object in the utility scope
750   i::Debug* debug = reinterpret_cast<i::Isolate*>(isolate)->debug();
751   debug->Load();
752   i::Handle<i::Context> debug_context = debug->debug_context();
753   i::Handle<i::JSObject> js_debug
754       = i::Handle<i::JSObject>(debug_context->global_object());
755   utility_context->Global()->Set(String::NewFromUtf8(isolate, "$debug"),
756                                  Utils::ToLocal(js_debug));
757   debug_context->set_security_token(
758       reinterpret_cast<i::Isolate*>(isolate)->heap()->undefined_value());
759
760   // Run the d8 shell utility script in the utility context
761   int source_index = i::NativesCollection<i::D8>::GetIndex("d8");
762   i::Vector<const char> shell_source =
763       i::NativesCollection<i::D8>::GetRawScriptSource(source_index);
764   i::Vector<const char> shell_source_name =
765       i::NativesCollection<i::D8>::GetScriptName(source_index);
766   Handle<String> source =
767       String::NewFromUtf8(isolate, shell_source.start(), String::kNormalString,
768                           shell_source.length());
769   Handle<String> name =
770       String::NewFromUtf8(isolate, shell_source_name.start(),
771                           String::kNormalString, shell_source_name.length());
772   ScriptOrigin origin(name);
773   Handle<Script> script = Script::Compile(source, &origin);
774   script->Run();
775   // Mark the d8 shell script as native to avoid it showing up as normal source
776   // in the debugger.
777   i::Handle<i::Object> compiled_script = Utils::OpenHandle(*script);
778   i::Handle<i::Script> script_object = compiled_script->IsJSFunction()
779       ? i::Handle<i::Script>(i::Script::cast(
780           i::JSFunction::cast(*compiled_script)->shared()->script()))
781       : i::Handle<i::Script>(i::Script::cast(
782           i::SharedFunctionInfo::cast(*compiled_script)->script()));
783   script_object->set_type(i::Smi::FromInt(i::Script::TYPE_NATIVE));
784
785   // Start the in-process debugger if requested.
786   if (i::FLAG_debugger) v8::Debug::SetDebugEventListener(HandleDebugEvent);
787 }
788 #endif  // !V8_SHARED
789
790
791 #ifdef COMPRESS_STARTUP_DATA_BZ2
792 class BZip2Decompressor : public v8::StartupDataDecompressor {
793  public:
794   virtual ~BZip2Decompressor() { }
795
796  protected:
797   virtual int DecompressData(char* raw_data,
798                              int* raw_data_size,
799                              const char* compressed_data,
800                              int compressed_data_size) {
801     ASSERT_EQ(v8::StartupData::kBZip2,
802               v8::V8::GetCompressedStartupDataAlgorithm());
803     unsigned int decompressed_size = *raw_data_size;
804     int result =
805         BZ2_bzBuffToBuffDecompress(raw_data,
806                                    &decompressed_size,
807                                    const_cast<char*>(compressed_data),
808                                    compressed_data_size,
809                                    0, 1);
810     if (result == BZ_OK) {
811       *raw_data_size = decompressed_size;
812     }
813     return result;
814   }
815 };
816 #endif
817
818
819 Handle<ObjectTemplate> Shell::CreateGlobalTemplate(Isolate* isolate) {
820   Handle<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
821   global_template->Set(String::NewFromUtf8(isolate, "print"),
822                        FunctionTemplate::New(isolate, Print));
823   global_template->Set(String::NewFromUtf8(isolate, "write"),
824                        FunctionTemplate::New(isolate, Write));
825   global_template->Set(String::NewFromUtf8(isolate, "read"),
826                        FunctionTemplate::New(isolate, Read));
827   global_template->Set(String::NewFromUtf8(isolate, "readbuffer"),
828                        FunctionTemplate::New(isolate, ReadBuffer));
829   global_template->Set(String::NewFromUtf8(isolate, "readline"),
830                        FunctionTemplate::New(isolate, ReadLine));
831   global_template->Set(String::NewFromUtf8(isolate, "load"),
832                        FunctionTemplate::New(isolate, Load));
833   global_template->Set(String::NewFromUtf8(isolate, "quit"),
834                        FunctionTemplate::New(isolate, Quit));
835   global_template->Set(String::NewFromUtf8(isolate, "version"),
836                        FunctionTemplate::New(isolate, Version));
837
838   // Bind the Realm object.
839   Handle<ObjectTemplate> realm_template = ObjectTemplate::New(isolate);
840   realm_template->Set(String::NewFromUtf8(isolate, "current"),
841                       FunctionTemplate::New(isolate, RealmCurrent));
842   realm_template->Set(String::NewFromUtf8(isolate, "owner"),
843                       FunctionTemplate::New(isolate, RealmOwner));
844   realm_template->Set(String::NewFromUtf8(isolate, "global"),
845                       FunctionTemplate::New(isolate, RealmGlobal));
846   realm_template->Set(String::NewFromUtf8(isolate, "create"),
847                       FunctionTemplate::New(isolate, RealmCreate));
848   realm_template->Set(String::NewFromUtf8(isolate, "dispose"),
849                       FunctionTemplate::New(isolate, RealmDispose));
850   realm_template->Set(String::NewFromUtf8(isolate, "switch"),
851                       FunctionTemplate::New(isolate, RealmSwitch));
852   realm_template->Set(String::NewFromUtf8(isolate, "eval"),
853                       FunctionTemplate::New(isolate, RealmEval));
854   realm_template->SetAccessor(String::NewFromUtf8(isolate, "shared"),
855                               RealmSharedGet, RealmSharedSet);
856   global_template->Set(String::NewFromUtf8(isolate, "Realm"), realm_template);
857
858 #ifndef V8_SHARED
859   Handle<ObjectTemplate> performance_template = ObjectTemplate::New(isolate);
860   performance_template->Set(String::NewFromUtf8(isolate, "now"),
861                             FunctionTemplate::New(isolate, PerformanceNow));
862   global_template->Set(String::NewFromUtf8(isolate, "performance"),
863                        performance_template);
864 #endif  // !V8_SHARED
865
866 #if !defined(V8_SHARED) && !defined(_WIN32) && !defined(_WIN64)
867   Handle<ObjectTemplate> os_templ = ObjectTemplate::New(isolate);
868   AddOSMethods(isolate, os_templ);
869   global_template->Set(String::NewFromUtf8(isolate, "os"), os_templ);
870 #endif  // !V8_SHARED && !_WIN32 && !_WIN64
871
872   return global_template;
873 }
874
875
876 void Shell::Initialize(Isolate* isolate) {
877 #ifdef COMPRESS_STARTUP_DATA_BZ2
878   BZip2Decompressor startup_data_decompressor;
879   int bz2_result = startup_data_decompressor.Decompress();
880   if (bz2_result != BZ_OK) {
881     fprintf(stderr, "bzip error code: %d\n", bz2_result);
882     Exit(1);
883   }
884 #endif
885
886 #ifndef V8_SHARED
887   Shell::counter_map_ = new CounterMap();
888   // Set up counters
889   if (i::StrLength(i::FLAG_map_counters) != 0)
890     MapCounters(isolate, i::FLAG_map_counters);
891   if (i::FLAG_dump_counters || i::FLAG_track_gc_object_stats) {
892     V8::SetCounterFunction(LookupCounter);
893     V8::SetCreateHistogramFunction(CreateHistogram);
894     V8::SetAddHistogramSampleFunction(AddHistogramSample);
895   }
896 #endif  // !V8_SHARED
897 }
898
899
900 void Shell::InitializeDebugger(Isolate* isolate) {
901   if (options.test_shell) return;
902 #ifndef V8_SHARED
903   HandleScope scope(isolate);
904   Handle<ObjectTemplate> global_template = CreateGlobalTemplate(isolate);
905   utility_context_.Reset(isolate,
906                          Context::New(isolate, NULL, global_template));
907 #endif  // !V8_SHARED
908 }
909
910
911 Local<Context> Shell::CreateEvaluationContext(Isolate* isolate) {
912 #ifndef V8_SHARED
913   // This needs to be a critical section since this is not thread-safe
914   i::LockGuard<i::Mutex> lock_guard(&context_mutex_);
915 #endif  // !V8_SHARED
916   // Initialize the global objects
917   Handle<ObjectTemplate> global_template = CreateGlobalTemplate(isolate);
918   EscapableHandleScope handle_scope(isolate);
919   Local<Context> context = Context::New(isolate, NULL, global_template);
920   ASSERT(!context.IsEmpty());
921   Context::Scope scope(context);
922
923 #ifndef V8_SHARED
924   i::Factory* factory = reinterpret_cast<i::Isolate*>(isolate)->factory();
925   i::JSArguments js_args = i::FLAG_js_arguments;
926   i::Handle<i::FixedArray> arguments_array =
927       factory->NewFixedArray(js_args.argc);
928   for (int j = 0; j < js_args.argc; j++) {
929     i::Handle<i::String> arg =
930         factory->NewStringFromUtf8(i::CStrVector(js_args[j])).ToHandleChecked();
931     arguments_array->set(j, *arg);
932   }
933   i::Handle<i::JSArray> arguments_jsarray =
934       factory->NewJSArrayWithElements(arguments_array);
935   context->Global()->Set(String::NewFromUtf8(isolate, "arguments"),
936                          Utils::ToLocal(arguments_jsarray));
937 #endif  // !V8_SHARED
938   return handle_scope.Escape(context);
939 }
940
941
942 void Shell::Exit(int exit_code) {
943   // Use _exit instead of exit to avoid races between isolate
944   // threads and static destructors.
945   fflush(stdout);
946   fflush(stderr);
947   _exit(exit_code);
948 }
949
950
951 #ifndef V8_SHARED
952 struct CounterAndKey {
953   Counter* counter;
954   const char* key;
955 };
956
957
958 inline bool operator<(const CounterAndKey& lhs, const CounterAndKey& rhs) {
959   return strcmp(lhs.key, rhs.key) < 0;
960 }
961 #endif  // !V8_SHARED
962
963
964 void Shell::OnExit() {
965   LineEditor* line_editor = LineEditor::Get();
966   if (line_editor) line_editor->Close();
967 #ifndef V8_SHARED
968   if (i::FLAG_dump_counters) {
969     int number_of_counters = 0;
970     for (CounterMap::Iterator i(counter_map_); i.More(); i.Next()) {
971       number_of_counters++;
972     }
973     CounterAndKey* counters = new CounterAndKey[number_of_counters];
974     int j = 0;
975     for (CounterMap::Iterator i(counter_map_); i.More(); i.Next(), j++) {
976       counters[j].counter = i.CurrentValue();
977       counters[j].key = i.CurrentKey();
978     }
979     std::sort(counters, counters + number_of_counters);
980     printf("+----------------------------------------------------------------+"
981            "-------------+\n");
982     printf("| Name                                                           |"
983            " Value       |\n");
984     printf("+----------------------------------------------------------------+"
985            "-------------+\n");
986     for (j = 0; j < number_of_counters; j++) {
987       Counter* counter = counters[j].counter;
988       const char* key = counters[j].key;
989       if (counter->is_histogram()) {
990         printf("| c:%-60s | %11i |\n", key, counter->count());
991         printf("| t:%-60s | %11i |\n", key, counter->sample_total());
992       } else {
993         printf("| %-62s | %11i |\n", key, counter->count());
994       }
995     }
996     printf("+----------------------------------------------------------------+"
997            "-------------+\n");
998     delete [] counters;
999   }
1000   delete counters_file_;
1001   delete counter_map_;
1002 #endif  // !V8_SHARED
1003 }
1004
1005
1006
1007 static FILE* FOpen(const char* path, const char* mode) {
1008 #if defined(_MSC_VER) && (defined(_WIN32) || defined(_WIN64))
1009   FILE* result;
1010   if (fopen_s(&result, path, mode) == 0) {
1011     return result;
1012   } else {
1013     return NULL;
1014   }
1015 #else
1016   FILE* file = fopen(path, mode);
1017   if (file == NULL) return NULL;
1018   struct stat file_stat;
1019   if (fstat(fileno(file), &file_stat) != 0) return NULL;
1020   bool is_regular_file = ((file_stat.st_mode & S_IFREG) != 0);
1021   if (is_regular_file) return file;
1022   fclose(file);
1023   return NULL;
1024 #endif
1025 }
1026
1027
1028 static char* ReadChars(Isolate* isolate, const char* name, int* size_out) {
1029   FILE* file = FOpen(name, "rb");
1030   if (file == NULL) return NULL;
1031
1032   fseek(file, 0, SEEK_END);
1033   int size = ftell(file);
1034   rewind(file);
1035
1036   char* chars = new char[size + 1];
1037   chars[size] = '\0';
1038   for (int i = 0; i < size;) {
1039     int read = static_cast<int>(fread(&chars[i], 1, size - i, file));
1040     i += read;
1041   }
1042   fclose(file);
1043   *size_out = size;
1044   return chars;
1045 }
1046
1047
1048 struct DataAndPersistent {
1049   uint8_t* data;
1050   Persistent<ArrayBuffer> handle;
1051 };
1052
1053
1054 static void ReadBufferWeakCallback(
1055     const v8::WeakCallbackData<ArrayBuffer, DataAndPersistent>& data) {
1056   size_t byte_length = data.GetValue()->ByteLength();
1057   data.GetIsolate()->AdjustAmountOfExternalAllocatedMemory(
1058       -static_cast<intptr_t>(byte_length));
1059
1060   delete[] data.GetParameter()->data;
1061   data.GetParameter()->handle.Reset();
1062   delete data.GetParameter();
1063 }
1064
1065
1066 void Shell::ReadBuffer(const v8::FunctionCallbackInfo<v8::Value>& args) {
1067   ASSERT(sizeof(char) == sizeof(uint8_t));  // NOLINT
1068   String::Utf8Value filename(args[0]);
1069   int length;
1070   if (*filename == NULL) {
1071     Throw(args.GetIsolate(), "Error loading file");
1072     return;
1073   }
1074
1075   Isolate* isolate = args.GetIsolate();
1076   DataAndPersistent* data = new DataAndPersistent;
1077   data->data = reinterpret_cast<uint8_t*>(
1078       ReadChars(args.GetIsolate(), *filename, &length));
1079   if (data->data == NULL) {
1080     delete data;
1081     Throw(args.GetIsolate(), "Error reading file");
1082     return;
1083   }
1084   Handle<v8::ArrayBuffer> buffer =
1085       ArrayBuffer::New(isolate, data->data, length);
1086   data->handle.Reset(isolate, buffer);
1087   data->handle.SetWeak(data, ReadBufferWeakCallback);
1088   data->handle.MarkIndependent();
1089   isolate->AdjustAmountOfExternalAllocatedMemory(length);
1090
1091   args.GetReturnValue().Set(buffer);
1092 }
1093
1094
1095 // Reads a file into a v8 string.
1096 Handle<String> Shell::ReadFile(Isolate* isolate, const char* name) {
1097   int size = 0;
1098   char* chars = ReadChars(isolate, name, &size);
1099   if (chars == NULL) return Handle<String>();
1100   Handle<String> result =
1101       String::NewFromUtf8(isolate, chars, String::kNormalString, size);
1102   delete[] chars;
1103   return result;
1104 }
1105
1106
1107 void Shell::RunShell(Isolate* isolate) {
1108   HandleScope outer_scope(isolate);
1109   v8::Local<v8::Context> context =
1110       v8::Local<v8::Context>::New(isolate, evaluation_context_);
1111   v8::Context::Scope context_scope(context);
1112   PerIsolateData::RealmScope realm_scope(PerIsolateData::Get(isolate));
1113   Handle<String> name = String::NewFromUtf8(isolate, "(d8)");
1114   LineEditor* console = LineEditor::Get();
1115   printf("V8 version %s [console: %s]\n", V8::GetVersion(), console->name());
1116   console->Open(isolate);
1117   while (true) {
1118     HandleScope inner_scope(isolate);
1119     Handle<String> input = console->Prompt(Shell::kPrompt);
1120     if (input.IsEmpty()) break;
1121     ExecuteString(isolate, input, name, true, true);
1122   }
1123   printf("\n");
1124 }
1125
1126
1127 SourceGroup::~SourceGroup() {
1128 #ifndef V8_SHARED
1129   delete thread_;
1130   thread_ = NULL;
1131 #endif  // !V8_SHARED
1132 }
1133
1134
1135 void SourceGroup::Execute(Isolate* isolate) {
1136   bool exception_was_thrown = false;
1137   for (int i = begin_offset_; i < end_offset_; ++i) {
1138     const char* arg = argv_[i];
1139     if (strcmp(arg, "-e") == 0 && i + 1 < end_offset_) {
1140       // Execute argument given to -e option directly.
1141       HandleScope handle_scope(isolate);
1142       Handle<String> file_name = String::NewFromUtf8(isolate, "unnamed");
1143       Handle<String> source = String::NewFromUtf8(isolate, argv_[i + 1]);
1144       if (!Shell::ExecuteString(isolate, source, file_name, false, true)) {
1145         exception_was_thrown = true;
1146         break;
1147       }
1148       ++i;
1149     } else if (arg[0] == '-') {
1150       // Ignore other options. They have been parsed already.
1151     } else {
1152       // Use all other arguments as names of files to load and run.
1153       HandleScope handle_scope(isolate);
1154       Handle<String> file_name = String::NewFromUtf8(isolate, arg);
1155       Handle<String> source = ReadFile(isolate, arg);
1156       if (source.IsEmpty()) {
1157         printf("Error reading '%s'\n", arg);
1158         Shell::Exit(1);
1159       }
1160       if (!Shell::ExecuteString(isolate, source, file_name, false, true)) {
1161         exception_was_thrown = true;
1162         break;
1163       }
1164     }
1165   }
1166   if (exception_was_thrown != Shell::options.expected_to_throw) {
1167     Shell::Exit(1);
1168   }
1169 }
1170
1171
1172 Handle<String> SourceGroup::ReadFile(Isolate* isolate, const char* name) {
1173   int size;
1174   char* chars = ReadChars(isolate, name, &size);
1175   if (chars == NULL) return Handle<String>();
1176   Handle<String> result =
1177       String::NewFromUtf8(isolate, chars, String::kNormalString, size);
1178   delete[] chars;
1179   return result;
1180 }
1181
1182
1183 #ifndef V8_SHARED
1184 i::Thread::Options SourceGroup::GetThreadOptions() {
1185   // On some systems (OSX 10.6) the stack size default is 0.5Mb or less
1186   // which is not enough to parse the big literal expressions used in tests.
1187   // The stack size should be at least StackGuard::kLimitSize + some
1188   // OS-specific padding for thread startup code.  2Mbytes seems to be enough.
1189   return i::Thread::Options("IsolateThread", 2 * MB);
1190 }
1191
1192
1193 void SourceGroup::ExecuteInThread() {
1194   Isolate* isolate = Isolate::New();
1195   do {
1196     next_semaphore_.Wait();
1197     {
1198       Isolate::Scope iscope(isolate);
1199       {
1200         HandleScope scope(isolate);
1201         PerIsolateData data(isolate);
1202         Local<Context> context = Shell::CreateEvaluationContext(isolate);
1203         {
1204           Context::Scope cscope(context);
1205           PerIsolateData::RealmScope realm_scope(PerIsolateData::Get(isolate));
1206           Execute(isolate);
1207         }
1208       }
1209       if (Shell::options.send_idle_notification) {
1210         const int kLongIdlePauseInMs = 1000;
1211         V8::ContextDisposedNotification();
1212         V8::IdleNotification(kLongIdlePauseInMs);
1213       }
1214       if (Shell::options.invoke_weak_callbacks) {
1215         // By sending a low memory notifications, we will try hard to collect
1216         // all garbage and will therefore also invoke all weak callbacks of
1217         // actually unreachable persistent handles.
1218         V8::LowMemoryNotification();
1219       }
1220     }
1221     done_semaphore_.Signal();
1222   } while (!Shell::options.last_run);
1223
1224   isolate->Dispose();
1225 }
1226
1227
1228 void SourceGroup::StartExecuteInThread() {
1229   if (thread_ == NULL) {
1230     thread_ = new IsolateThread(this);
1231     thread_->Start();
1232   }
1233   next_semaphore_.Signal();
1234 }
1235
1236
1237 void SourceGroup::WaitForThread() {
1238   if (thread_ == NULL) return;
1239   if (Shell::options.last_run) {
1240     thread_->Join();
1241   } else {
1242     done_semaphore_.Wait();
1243   }
1244 }
1245 #endif  // !V8_SHARED
1246
1247
1248 void SetFlagsFromString(const char* flags) {
1249   v8::V8::SetFlagsFromString(flags, static_cast<int>(strlen(flags)));
1250 }
1251
1252
1253 bool Shell::SetOptions(int argc, char* argv[]) {
1254   bool logfile_per_isolate = false;
1255   for (int i = 0; i < argc; i++) {
1256     if (strcmp(argv[i], "--stress-opt") == 0) {
1257       options.stress_opt = true;
1258       argv[i] = NULL;
1259     } else if (strcmp(argv[i], "--nostress-opt") == 0) {
1260       options.stress_opt = false;
1261       argv[i] = NULL;
1262     } else if (strcmp(argv[i], "--stress-deopt") == 0) {
1263       options.stress_deopt = true;
1264       argv[i] = NULL;
1265     } else if (strcmp(argv[i], "--mock-arraybuffer-allocator") == 0) {
1266       options.mock_arraybuffer_allocator = true;
1267       argv[i] = NULL;
1268     } else if (strcmp(argv[i], "--noalways-opt") == 0) {
1269       // No support for stressing if we can't use --always-opt.
1270       options.stress_opt = false;
1271       options.stress_deopt = false;
1272     } else if (strcmp(argv[i], "--logfile-per-isolate") == 0) {
1273       logfile_per_isolate = true;
1274       argv[i] = NULL;
1275     } else if (strcmp(argv[i], "--shell") == 0) {
1276       options.interactive_shell = true;
1277       argv[i] = NULL;
1278     } else if (strcmp(argv[i], "--test") == 0) {
1279       options.test_shell = true;
1280       argv[i] = NULL;
1281     } else if (strcmp(argv[i], "--send-idle-notification") == 0) {
1282       options.send_idle_notification = true;
1283       argv[i] = NULL;
1284     } else if (strcmp(argv[i], "--invoke-weak-callbacks") == 0) {
1285       options.invoke_weak_callbacks = true;
1286       // TODO(jochen) See issue 3351
1287       options.send_idle_notification = true;
1288       argv[i] = NULL;
1289     } else if (strcmp(argv[i], "-f") == 0) {
1290       // Ignore any -f flags for compatibility with other stand-alone
1291       // JavaScript engines.
1292       continue;
1293     } else if (strcmp(argv[i], "--isolate") == 0) {
1294 #ifdef V8_SHARED
1295       printf("D8 with shared library does not support multi-threading\n");
1296       return false;
1297 #endif  // V8_SHARED
1298       options.num_isolates++;
1299     } else if (strcmp(argv[i], "--dump-heap-constants") == 0) {
1300 #ifdef V8_SHARED
1301       printf("D8 with shared library does not support constant dumping\n");
1302       return false;
1303 #else
1304       options.dump_heap_constants = true;
1305       argv[i] = NULL;
1306 #endif  // V8_SHARED
1307     } else if (strcmp(argv[i], "--throws") == 0) {
1308       options.expected_to_throw = true;
1309       argv[i] = NULL;
1310     } else if (strncmp(argv[i], "--icu-data-file=", 16) == 0) {
1311       options.icu_data_file = argv[i] + 16;
1312       argv[i] = NULL;
1313 #ifdef V8_SHARED
1314     } else if (strcmp(argv[i], "--dump-counters") == 0) {
1315       printf("D8 with shared library does not include counters\n");
1316       return false;
1317     } else if (strcmp(argv[i], "--debugger") == 0) {
1318       printf("Javascript debugger not included\n");
1319       return false;
1320 #endif  // V8_SHARED
1321     }
1322   }
1323
1324   v8::V8::SetFlagsFromCommandLine(&argc, argv, true);
1325
1326   // Set up isolated source groups.
1327   options.isolate_sources = new SourceGroup[options.num_isolates];
1328   SourceGroup* current = options.isolate_sources;
1329   current->Begin(argv, 1);
1330   for (int i = 1; i < argc; i++) {
1331     const char* str = argv[i];
1332     if (strcmp(str, "--isolate") == 0) {
1333       current->End(i);
1334       current++;
1335       current->Begin(argv, i + 1);
1336     } else if (strncmp(argv[i], "--", 2) == 0) {
1337       printf("Warning: unknown flag %s.\nTry --help for options\n", argv[i]);
1338     }
1339   }
1340   current->End(argc);
1341
1342   if (!logfile_per_isolate && options.num_isolates) {
1343     SetFlagsFromString("--nologfile_per_isolate");
1344   }
1345
1346   return true;
1347 }
1348
1349
1350 int Shell::RunMain(Isolate* isolate, int argc, char* argv[]) {
1351 #ifndef V8_SHARED
1352   for (int i = 1; i < options.num_isolates; ++i) {
1353     options.isolate_sources[i].StartExecuteInThread();
1354   }
1355 #endif  // !V8_SHARED
1356   {
1357     HandleScope scope(isolate);
1358     Local<Context> context = CreateEvaluationContext(isolate);
1359     if (options.last_run && options.use_interactive_shell()) {
1360       // Keep using the same context in the interactive shell.
1361       evaluation_context_.Reset(isolate, context);
1362 #ifndef V8_SHARED
1363       // If the interactive debugger is enabled make sure to activate
1364       // it before running the files passed on the command line.
1365       if (i::FLAG_debugger) {
1366         InstallUtilityScript(isolate);
1367       }
1368 #endif  // !V8_SHARED
1369     }
1370     {
1371       Context::Scope cscope(context);
1372       PerIsolateData::RealmScope realm_scope(PerIsolateData::Get(isolate));
1373       options.isolate_sources[0].Execute(isolate);
1374     }
1375   }
1376   if (options.send_idle_notification) {
1377     const int kLongIdlePauseInMs = 1000;
1378     V8::ContextDisposedNotification();
1379     V8::IdleNotification(kLongIdlePauseInMs);
1380   }
1381   if (options.invoke_weak_callbacks) {
1382     // By sending a low memory notifications, we will try hard to collect all
1383     // garbage and will therefore also invoke all weak callbacks of actually
1384     // unreachable persistent handles.
1385     V8::LowMemoryNotification();
1386   }
1387
1388 #ifndef V8_SHARED
1389   for (int i = 1; i < options.num_isolates; ++i) {
1390     options.isolate_sources[i].WaitForThread();
1391   }
1392 #endif  // !V8_SHARED
1393   return 0;
1394 }
1395
1396
1397 #ifndef V8_SHARED
1398 static void DumpHeapConstants(i::Isolate* isolate) {
1399   i::Heap* heap = isolate->heap();
1400
1401   // Dump the INSTANCE_TYPES table to the console.
1402   printf("# List of known V8 instance types.\n");
1403 #define DUMP_TYPE(T) printf("  %d: \"%s\",\n", i::T, #T);
1404   printf("INSTANCE_TYPES = {\n");
1405   INSTANCE_TYPE_LIST(DUMP_TYPE)
1406   printf("}\n");
1407 #undef DUMP_TYPE
1408
1409   // Dump the KNOWN_MAP table to the console.
1410   printf("\n# List of known V8 maps.\n");
1411 #define ROOT_LIST_CASE(type, name, camel_name) \
1412   if (n == NULL && o == heap->name()) n = #camel_name;
1413 #define STRUCT_LIST_CASE(upper_name, camel_name, name) \
1414   if (n == NULL && o == heap->name##_map()) n = #camel_name "Map";
1415   i::HeapObjectIterator it(heap->map_space());
1416   printf("KNOWN_MAPS = {\n");
1417   for (i::Object* o = it.Next(); o != NULL; o = it.Next()) {
1418     i::Map* m = i::Map::cast(o);
1419     const char* n = NULL;
1420     intptr_t p = reinterpret_cast<intptr_t>(m) & 0xfffff;
1421     int t = m->instance_type();
1422     ROOT_LIST(ROOT_LIST_CASE)
1423     STRUCT_LIST(STRUCT_LIST_CASE)
1424     if (n == NULL) continue;
1425     printf("  0x%05" V8PRIxPTR ": (%d, \"%s\"),\n", p, t, n);
1426   }
1427   printf("}\n");
1428 #undef STRUCT_LIST_CASE
1429 #undef ROOT_LIST_CASE
1430
1431   // Dump the KNOWN_OBJECTS table to the console.
1432   printf("\n# List of known V8 objects.\n");
1433 #define ROOT_LIST_CASE(type, name, camel_name) \
1434   if (n == NULL && o == heap->name()) n = #camel_name;
1435   i::OldSpaces spit(heap);
1436   printf("KNOWN_OBJECTS = {\n");
1437   for (i::PagedSpace* s = spit.next(); s != NULL; s = spit.next()) {
1438     i::HeapObjectIterator it(s);
1439     const char* sname = AllocationSpaceName(s->identity());
1440     for (i::Object* o = it.Next(); o != NULL; o = it.Next()) {
1441       const char* n = NULL;
1442       intptr_t p = reinterpret_cast<intptr_t>(o) & 0xfffff;
1443       ROOT_LIST(ROOT_LIST_CASE)
1444       if (n == NULL) continue;
1445       printf("  (\"%s\", 0x%05" V8PRIxPTR "): \"%s\",\n", sname, p, n);
1446     }
1447   }
1448   printf("}\n");
1449 #undef ROOT_LIST_CASE
1450 }
1451 #endif  // !V8_SHARED
1452
1453
1454 class ShellArrayBufferAllocator : public v8::ArrayBuffer::Allocator {
1455  public:
1456   virtual void* Allocate(size_t length) {
1457     void* data = AllocateUninitialized(length);
1458     return data == NULL ? data : memset(data, 0, length);
1459   }
1460   virtual void* AllocateUninitialized(size_t length) { return malloc(length); }
1461   virtual void Free(void* data, size_t) { free(data); }
1462 };
1463
1464
1465 class MockArrayBufferAllocator : public v8::ArrayBuffer::Allocator {
1466  public:
1467   virtual void* Allocate(size_t) V8_OVERRIDE {
1468     return malloc(0);
1469   }
1470   virtual void* AllocateUninitialized(size_t length) V8_OVERRIDE {
1471     return malloc(0);
1472   }
1473   virtual void Free(void* p, size_t) V8_OVERRIDE {
1474     free(p);
1475   }
1476 };
1477
1478
1479 int Shell::Main(int argc, char* argv[]) {
1480   if (!SetOptions(argc, argv)) return 1;
1481   v8::V8::InitializeICU(options.icu_data_file);
1482   SetFlagsFromString("--trace-hydrogen-file=hydrogen.cfg");
1483   SetFlagsFromString("--redirect-code-traces-to=code.asm");
1484   ShellArrayBufferAllocator array_buffer_allocator;
1485   MockArrayBufferAllocator mock_arraybuffer_allocator;
1486   if (options.mock_arraybuffer_allocator) {
1487     v8::V8::SetArrayBufferAllocator(&mock_arraybuffer_allocator);
1488   } else {
1489     v8::V8::SetArrayBufferAllocator(&array_buffer_allocator);
1490   }
1491   int result = 0;
1492   Isolate* isolate = Isolate::New();
1493 #ifndef V8_SHARED
1494   v8::ResourceConstraints constraints;
1495   constraints.ConfigureDefaults(i::OS::TotalPhysicalMemory(),
1496                                 i::OS::MaxVirtualMemory(),
1497                                 i::OS::NumberOfProcessorsOnline());
1498   v8::SetResourceConstraints(isolate, &constraints);
1499 #endif
1500   DumbLineEditor dumb_line_editor(isolate);
1501   {
1502     Isolate::Scope scope(isolate);
1503     Initialize(isolate);
1504 #ifdef ENABLE_VTUNE_JIT_INTERFACE
1505     vTune::InitializeVtuneForV8();
1506 #endif
1507     PerIsolateData data(isolate);
1508     InitializeDebugger(isolate);
1509
1510 #ifndef V8_SHARED
1511     if (options.dump_heap_constants) {
1512       DumpHeapConstants(reinterpret_cast<i::Isolate*>(isolate));
1513       return 0;
1514     }
1515 #endif
1516
1517     if (options.stress_opt || options.stress_deopt) {
1518       Testing::SetStressRunType(options.stress_opt
1519                                 ? Testing::kStressTypeOpt
1520                                 : Testing::kStressTypeDeopt);
1521       int stress_runs = Testing::GetStressRuns();
1522       for (int i = 0; i < stress_runs && result == 0; i++) {
1523         printf("============ Stress %d/%d ============\n", i + 1, stress_runs);
1524         Testing::PrepareStressRun(i);
1525         options.last_run = (i == stress_runs - 1);
1526         result = RunMain(isolate, argc, argv);
1527       }
1528       printf("======== Full Deoptimization =======\n");
1529       Testing::DeoptimizeAll();
1530 #if !defined(V8_SHARED)
1531     } else if (i::FLAG_stress_runs > 0) {
1532       int stress_runs = i::FLAG_stress_runs;
1533       for (int i = 0; i < stress_runs && result == 0; i++) {
1534         printf("============ Run %d/%d ============\n", i + 1, stress_runs);
1535         options.last_run = (i == stress_runs - 1);
1536         result = RunMain(isolate, argc, argv);
1537       }
1538 #endif
1539     } else {
1540       result = RunMain(isolate, argc, argv);
1541     }
1542
1543     // Run interactive shell if explicitly requested or if no script has been
1544     // executed, but never on --test
1545     if (options.use_interactive_shell()) {
1546 #ifndef V8_SHARED
1547       if (!i::FLAG_debugger) {
1548         InstallUtilityScript(isolate);
1549       }
1550 #endif  // !V8_SHARED
1551       RunShell(isolate);
1552     }
1553   }
1554   isolate->Dispose();
1555   V8::Dispose();
1556
1557   OnExit();
1558
1559   return result;
1560 }
1561
1562 }  // namespace v8
1563
1564
1565 #ifndef GOOGLE3
1566 int main(int argc, char* argv[]) {
1567   return v8::Shell::Main(argc, argv);
1568 }
1569 #endif