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