• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2009 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 #include <stdlib.h>
30 #include <errno.h>
31 
32 #include "d8.h"
33 #include "d8-debug.h"
34 #include "debug.h"
35 #include "api.h"
36 #include "natives.h"
37 #include "platform.h"
38 
39 
40 namespace v8 {
41 
42 
43 const char* Shell::kHistoryFileName = ".d8_history";
44 const char* Shell::kPrompt = "d8> ";
45 
46 
47 LineEditor *LineEditor::first_ = NULL;
48 
49 
LineEditor(Type type,const char * name)50 LineEditor::LineEditor(Type type, const char* name)
51     : type_(type),
52       name_(name),
53       next_(first_) {
54   first_ = this;
55 }
56 
57 
Get()58 LineEditor* LineEditor::Get() {
59   LineEditor* current = first_;
60   LineEditor* best = current;
61   while (current != NULL) {
62     if (current->type_ > best->type_)
63       best = current;
64     current = current->next_;
65   }
66   return best;
67 }
68 
69 
70 class DumbLineEditor: public LineEditor {
71  public:
DumbLineEditor()72   DumbLineEditor() : LineEditor(LineEditor::DUMB, "dumb") { }
73   virtual i::SmartPointer<char> Prompt(const char* prompt);
74 };
75 
76 
77 static DumbLineEditor dumb_line_editor;
78 
79 
Prompt(const char * prompt)80 i::SmartPointer<char> DumbLineEditor::Prompt(const char* prompt) {
81   static const int kBufferSize = 256;
82   char buffer[kBufferSize];
83   printf("%s", prompt);
84   char* str = fgets(buffer, kBufferSize, stdin);
85   return i::SmartPointer<char>(str ? i::StrDup(str) : str);
86 }
87 
88 
89 CounterMap* Shell::counter_map_;
90 i::OS::MemoryMappedFile* Shell::counters_file_ = NULL;
91 CounterCollection Shell::local_counters_;
92 CounterCollection* Shell::counters_ = &local_counters_;
93 Persistent<Context> Shell::utility_context_;
94 Persistent<Context> Shell::evaluation_context_;
95 
96 
Match(void * key1,void * key2)97 bool CounterMap::Match(void* key1, void* key2) {
98   const char* name1 = reinterpret_cast<const char*>(key1);
99   const char* name2 = reinterpret_cast<const char*>(key2);
100   return strcmp(name1, name2) == 0;
101 }
102 
103 
104 // Converts a V8 value to a C string.
ToCString(const v8::String::Utf8Value & value)105 const char* ToCString(const v8::String::Utf8Value& value) {
106   return *value ? *value : "<string conversion failed>";
107 }
108 
109 
110 // Executes a string within the current v8 context.
ExecuteString(Handle<String> source,Handle<Value> name,bool print_result,bool report_exceptions)111 bool Shell::ExecuteString(Handle<String> source,
112                           Handle<Value> name,
113                           bool print_result,
114                           bool report_exceptions) {
115   HandleScope handle_scope;
116   TryCatch try_catch;
117   if (i::FLAG_debugger) {
118     // When debugging make exceptions appear to be uncaught.
119     try_catch.SetVerbose(true);
120   }
121   Handle<Script> script = Script::Compile(source, name);
122   if (script.IsEmpty()) {
123     // Print errors that happened during compilation.
124     if (report_exceptions && !i::FLAG_debugger)
125       ReportException(&try_catch);
126     return false;
127   } else {
128     Handle<Value> result = script->Run();
129     if (result.IsEmpty()) {
130       // Print errors that happened during execution.
131       if (report_exceptions && !i::FLAG_debugger)
132         ReportException(&try_catch);
133       return false;
134     } else {
135       if (print_result && !result->IsUndefined()) {
136         // If all went well and the result wasn't undefined then print
137         // the returned value.
138         v8::String::Utf8Value str(result);
139         const char* cstr = ToCString(str);
140         printf("%s\n", cstr);
141       }
142       return true;
143     }
144   }
145 }
146 
147 
Print(const Arguments & args)148 Handle<Value> Shell::Print(const Arguments& args) {
149   Handle<Value> val = Write(args);
150   printf("\n");
151   return val;
152 }
153 
154 
Write(const Arguments & args)155 Handle<Value> Shell::Write(const Arguments& args) {
156   for (int i = 0; i < args.Length(); i++) {
157     HandleScope handle_scope;
158     if (i != 0) {
159       printf(" ");
160     }
161     v8::String::Utf8Value str(args[i]);
162     int n = fwrite(*str, sizeof(**str), str.length(), stdout);
163     if (n != str.length()) {
164       printf("Error in fwrite\n");
165       exit(1);
166     }
167   }
168   return Undefined();
169 }
170 
171 
Read(const Arguments & args)172 Handle<Value> Shell::Read(const Arguments& args) {
173   String::Utf8Value file(args[0]);
174   if (*file == NULL) {
175     return ThrowException(String::New("Error loading file"));
176   }
177   Handle<String> source = ReadFile(*file);
178   if (source.IsEmpty()) {
179     return ThrowException(String::New("Error loading file"));
180   }
181   return source;
182 }
183 
184 
ReadLine(const Arguments & args)185 Handle<Value> Shell::ReadLine(const Arguments& args) {
186   i::SmartPointer<char> line(i::ReadLine(""));
187   if (*line == NULL) {
188     return Null();
189   }
190   size_t len = strlen(*line);
191   if (len > 0 && line[len - 1] == '\n') {
192     --len;
193   }
194   return String::New(*line, len);
195 }
196 
197 
Load(const Arguments & args)198 Handle<Value> Shell::Load(const Arguments& args) {
199   for (int i = 0; i < args.Length(); i++) {
200     HandleScope handle_scope;
201     String::Utf8Value file(args[i]);
202     if (*file == NULL) {
203       return ThrowException(String::New("Error loading file"));
204     }
205     Handle<String> source = ReadFile(*file);
206     if (source.IsEmpty()) {
207       return ThrowException(String::New("Error loading file"));
208     }
209     if (!ExecuteString(source, String::New(*file), false, false)) {
210       return ThrowException(String::New("Error executing file"));
211     }
212   }
213   return Undefined();
214 }
215 
216 
Yield(const Arguments & args)217 Handle<Value> Shell::Yield(const Arguments& args) {
218   v8::Unlocker unlocker;
219   return Undefined();
220 }
221 
222 
Quit(const Arguments & args)223 Handle<Value> Shell::Quit(const Arguments& args) {
224   int exit_code = args[0]->Int32Value();
225   OnExit();
226   exit(exit_code);
227   return Undefined();
228 }
229 
230 
Version(const Arguments & args)231 Handle<Value> Shell::Version(const Arguments& args) {
232   return String::New(V8::GetVersion());
233 }
234 
235 
ReportException(v8::TryCatch * try_catch)236 void Shell::ReportException(v8::TryCatch* try_catch) {
237   HandleScope handle_scope;
238   v8::String::Utf8Value exception(try_catch->Exception());
239   const char* exception_string = ToCString(exception);
240   Handle<Message> message = try_catch->Message();
241   if (message.IsEmpty()) {
242     // V8 didn't provide any extra information about this error; just
243     // print the exception.
244     printf("%s\n", exception_string);
245   } else {
246     // Print (filename):(line number): (message).
247     v8::String::Utf8Value filename(message->GetScriptResourceName());
248     const char* filename_string = ToCString(filename);
249     int linenum = message->GetLineNumber();
250     printf("%s:%i: %s\n", filename_string, linenum, exception_string);
251     // Print line of source code.
252     v8::String::Utf8Value sourceline(message->GetSourceLine());
253     const char* sourceline_string = ToCString(sourceline);
254     printf("%s\n", sourceline_string);
255     // Print wavy underline (GetUnderline is deprecated).
256     int start = message->GetStartColumn();
257     for (int i = 0; i < start; i++) {
258       printf(" ");
259     }
260     int end = message->GetEndColumn();
261     for (int i = start; i < end; i++) {
262       printf("^");
263     }
264     printf("\n");
265   }
266 }
267 
268 
GetCompletions(Handle<String> text,Handle<String> full)269 Handle<Array> Shell::GetCompletions(Handle<String> text, Handle<String> full) {
270   HandleScope handle_scope;
271   Context::Scope context_scope(utility_context_);
272   Handle<Object> global = utility_context_->Global();
273   Handle<Value> fun = global->Get(String::New("GetCompletions"));
274   static const int kArgc = 3;
275   Handle<Value> argv[kArgc] = { evaluation_context_->Global(), text, full };
276   Handle<Value> val = Handle<Function>::Cast(fun)->Call(global, kArgc, argv);
277   return handle_scope.Close(Handle<Array>::Cast(val));
278 }
279 
280 
281 #ifdef ENABLE_DEBUGGER_SUPPORT
DebugMessageDetails(Handle<String> message)282 Handle<Object> Shell::DebugMessageDetails(Handle<String> message) {
283   Context::Scope context_scope(utility_context_);
284   Handle<Object> global = utility_context_->Global();
285   Handle<Value> fun = global->Get(String::New("DebugMessageDetails"));
286   static const int kArgc = 1;
287   Handle<Value> argv[kArgc] = { message };
288   Handle<Value> val = Handle<Function>::Cast(fun)->Call(global, kArgc, argv);
289   return Handle<Object>::Cast(val);
290 }
291 
292 
DebugCommandToJSONRequest(Handle<String> command)293 Handle<Value> Shell::DebugCommandToJSONRequest(Handle<String> command) {
294   Context::Scope context_scope(utility_context_);
295   Handle<Object> global = utility_context_->Global();
296   Handle<Value> fun = global->Get(String::New("DebugCommandToJSONRequest"));
297   static const int kArgc = 1;
298   Handle<Value> argv[kArgc] = { command };
299   Handle<Value> val = Handle<Function>::Cast(fun)->Call(global, kArgc, argv);
300   return val;
301 }
302 #endif
303 
304 
Bind(const char * name,bool is_histogram)305 int32_t* Counter::Bind(const char* name, bool is_histogram) {
306   int i;
307   for (i = 0; i < kMaxNameSize - 1 && name[i]; i++)
308     name_[i] = static_cast<char>(name[i]);
309   name_[i] = '\0';
310   is_histogram_ = is_histogram;
311   return ptr();
312 }
313 
314 
AddSample(int32_t sample)315 void Counter::AddSample(int32_t sample) {
316   count_++;
317   sample_total_ += sample;
318 }
319 
320 
CounterCollection()321 CounterCollection::CounterCollection() {
322   magic_number_ = 0xDEADFACE;
323   max_counters_ = kMaxCounters;
324   max_name_size_ = Counter::kMaxNameSize;
325   counters_in_use_ = 0;
326 }
327 
328 
GetNextCounter()329 Counter* CounterCollection::GetNextCounter() {
330   if (counters_in_use_ == kMaxCounters) return NULL;
331   return &counters_[counters_in_use_++];
332 }
333 
334 
MapCounters(const char * name)335 void Shell::MapCounters(const char* name) {
336   counters_file_ = i::OS::MemoryMappedFile::create(name,
337     sizeof(CounterCollection), &local_counters_);
338   void* memory = (counters_file_ == NULL) ?
339       NULL : counters_file_->memory();
340   if (memory == NULL) {
341     printf("Could not map counters file %s\n", name);
342     exit(1);
343   }
344   counters_ = static_cast<CounterCollection*>(memory);
345   V8::SetCounterFunction(LookupCounter);
346   V8::SetCreateHistogramFunction(CreateHistogram);
347   V8::SetAddHistogramSampleFunction(AddHistogramSample);
348 }
349 
350 
Hash(const char * name)351 int CounterMap::Hash(const char* name) {
352   int h = 0;
353   int c;
354   while ((c = *name++) != 0) {
355     h += h << 5;
356     h += c;
357   }
358   return h;
359 }
360 
361 
GetCounter(const char * name,bool is_histogram)362 Counter* Shell::GetCounter(const char* name, bool is_histogram) {
363   Counter* counter = counter_map_->Lookup(name);
364 
365   if (counter == NULL) {
366     counter = counters_->GetNextCounter();
367     if (counter != NULL) {
368       counter_map_->Set(name, counter);
369       counter->Bind(name, is_histogram);
370     }
371   } else {
372     ASSERT(counter->is_histogram() == is_histogram);
373   }
374   return counter;
375 }
376 
377 
LookupCounter(const char * name)378 int* Shell::LookupCounter(const char* name) {
379   Counter* counter = GetCounter(name, false);
380 
381   if (counter != NULL) {
382     return counter->ptr();
383   } else {
384     return NULL;
385   }
386 }
387 
388 
CreateHistogram(const char * name,int min,int max,size_t buckets)389 void* Shell::CreateHistogram(const char* name,
390                              int min,
391                              int max,
392                              size_t buckets) {
393   return GetCounter(name, true);
394 }
395 
396 
AddHistogramSample(void * histogram,int sample)397 void Shell::AddHistogramSample(void* histogram, int sample) {
398   Counter* counter = reinterpret_cast<Counter*>(histogram);
399   counter->AddSample(sample);
400 }
401 
402 
Initialize()403 void Shell::Initialize() {
404   Shell::counter_map_ = new CounterMap();
405   // Set up counters
406   if (i::FLAG_map_counters != NULL)
407     MapCounters(i::FLAG_map_counters);
408   if (i::FLAG_dump_counters) {
409     V8::SetCounterFunction(LookupCounter);
410     V8::SetCreateHistogramFunction(CreateHistogram);
411     V8::SetAddHistogramSampleFunction(AddHistogramSample);
412   }
413 
414   // Initialize the global objects
415   HandleScope scope;
416   Handle<ObjectTemplate> global_template = ObjectTemplate::New();
417   global_template->Set(String::New("print"), FunctionTemplate::New(Print));
418   global_template->Set(String::New("write"), FunctionTemplate::New(Write));
419   global_template->Set(String::New("read"), FunctionTemplate::New(Read));
420   global_template->Set(String::New("readline"),
421                        FunctionTemplate::New(ReadLine));
422   global_template->Set(String::New("load"), FunctionTemplate::New(Load));
423   global_template->Set(String::New("quit"), FunctionTemplate::New(Quit));
424   global_template->Set(String::New("version"), FunctionTemplate::New(Version));
425 
426   Handle<ObjectTemplate> os_templ = ObjectTemplate::New();
427   AddOSMethods(os_templ);
428   global_template->Set(String::New("os"), os_templ);
429 
430   utility_context_ = Context::New(NULL, global_template);
431   utility_context_->SetSecurityToken(Undefined());
432   Context::Scope utility_scope(utility_context_);
433 
434   i::JSArguments js_args = i::FLAG_js_arguments;
435   i::Handle<i::FixedArray> arguments_array =
436       i::Factory::NewFixedArray(js_args.argc());
437   for (int j = 0; j < js_args.argc(); j++) {
438     i::Handle<i::String> arg =
439         i::Factory::NewStringFromUtf8(i::CStrVector(js_args[j]));
440     arguments_array->set(j, *arg);
441   }
442   i::Handle<i::JSArray> arguments_jsarray =
443       i::Factory::NewJSArrayWithElements(arguments_array);
444   global_template->Set(String::New("arguments"),
445                        Utils::ToLocal(arguments_jsarray));
446 
447 #ifdef ENABLE_DEBUGGER_SUPPORT
448   // Install the debugger object in the utility scope
449   i::Debug::Load();
450   i::JSObject* debug = i::Debug::debug_context()->global();
451   utility_context_->Global()->Set(String::New("$debug"),
452                                   Utils::ToLocal(&debug));
453 #endif
454 
455   // Run the d8 shell utility script in the utility context
456   int source_index = i::NativesCollection<i::D8>::GetIndex("d8");
457   i::Vector<const char> shell_source
458       = i::NativesCollection<i::D8>::GetScriptSource(source_index);
459   i::Vector<const char> shell_source_name
460       = i::NativesCollection<i::D8>::GetScriptName(source_index);
461   Handle<String> source = String::New(shell_source.start(),
462                                       shell_source.length());
463   Handle<String> name = String::New(shell_source_name.start(),
464                                     shell_source_name.length());
465   Handle<Script> script = Script::Compile(source, name);
466   script->Run();
467 
468   // Mark the d8 shell script as native to avoid it showing up as normal source
469   // in the debugger.
470   i::Handle<i::JSFunction> script_fun = Utils::OpenHandle(*script);
471   i::Handle<i::Script> script_object =
472       i::Handle<i::Script>(i::Script::cast(script_fun->shared()->script()));
473   script_object->set_type(i::Smi::FromInt(i::Script::TYPE_NATIVE));
474 
475   // Create the evaluation context
476   evaluation_context_ = Context::New(NULL, global_template);
477   evaluation_context_->SetSecurityToken(Undefined());
478 
479 #ifdef ENABLE_DEBUGGER_SUPPORT
480   // Set the security token of the debug context to allow access.
481   i::Debug::debug_context()->set_security_token(i::Heap::undefined_value());
482 
483   // Start the debugger agent if requested.
484   if (i::FLAG_debugger_agent) {
485     v8::Debug::EnableAgent("d8 shell", i::FLAG_debugger_port);
486   }
487 
488   // Start the in-process debugger if requested.
489   if (i::FLAG_debugger && !i::FLAG_debugger_agent) {
490     v8::Debug::SetDebugEventListener(HandleDebugEvent);
491   }
492 #endif
493 }
494 
495 
OnExit()496 void Shell::OnExit() {
497   if (i::FLAG_dump_counters) {
498     ::printf("+----------------------------------------+-------------+\n");
499     ::printf("| Name                                   | Value       |\n");
500     ::printf("+----------------------------------------+-------------+\n");
501     for (CounterMap::Iterator i(counter_map_); i.More(); i.Next()) {
502       Counter* counter = i.CurrentValue();
503       if (counter->is_histogram()) {
504         ::printf("| c:%-36s | %11i |\n", i.CurrentKey(), counter->count());
505         ::printf("| t:%-36s | %11i |\n",
506                  i.CurrentKey(),
507                  counter->sample_total());
508       } else {
509         ::printf("| %-38s | %11i |\n", i.CurrentKey(), counter->count());
510       }
511     }
512     ::printf("+----------------------------------------+-------------+\n");
513   }
514   if (counters_file_ != NULL)
515     delete counters_file_;
516 }
517 
518 
ReadChars(const char * name,int * size_out)519 static char* ReadChars(const char* name, int* size_out) {
520   v8::Unlocker unlocker;  // Release the V8 lock while reading files.
521   FILE* file = i::OS::FOpen(name, "rb");
522   if (file == NULL) return NULL;
523 
524   fseek(file, 0, SEEK_END);
525   int size = ftell(file);
526   rewind(file);
527 
528   char* chars = new char[size + 1];
529   chars[size] = '\0';
530   for (int i = 0; i < size;) {
531     int read = fread(&chars[i], 1, size - i, file);
532     i += read;
533   }
534   fclose(file);
535   *size_out = size;
536   return chars;
537 }
538 
539 
ReadToken(char * data,char token)540 static char* ReadToken(char* data, char token) {
541   char* next = i::OS::StrChr(data, token);
542   if (next != NULL) {
543     *next = '\0';
544     return (next + 1);
545   }
546 
547   return NULL;
548 }
549 
550 
ReadLine(char * data)551 static char* ReadLine(char* data) {
552   return ReadToken(data, '\n');
553 }
554 
555 
ReadWord(char * data)556 static char* ReadWord(char* data) {
557   return ReadToken(data, ' ');
558 }
559 
560 
561 // Reads a file into a v8 string.
ReadFile(const char * name)562 Handle<String> Shell::ReadFile(const char* name) {
563   int size = 0;
564   char* chars = ReadChars(name, &size);
565   if (chars == NULL) return Handle<String>();
566   Handle<String> result = String::New(chars);
567   delete[] chars;
568   return result;
569 }
570 
571 
RunShell()572 void Shell::RunShell() {
573   LineEditor* editor = LineEditor::Get();
574   printf("V8 version %s [console: %s]\n", V8::GetVersion(), editor->name());
575   editor->Open();
576   while (true) {
577     Locker locker;
578     HandleScope handle_scope;
579     Context::Scope context_scope(evaluation_context_);
580     i::SmartPointer<char> input = editor->Prompt(Shell::kPrompt);
581     if (input.is_empty())
582       break;
583     editor->AddHistory(*input);
584     Handle<String> name = String::New("(d8)");
585     ExecuteString(String::New(*input), name, true, true);
586   }
587   editor->Close();
588   printf("\n");
589 }
590 
591 
592 class ShellThread : public i::Thread {
593  public:
ShellThread(int no,i::Vector<const char> files)594   ShellThread(int no, i::Vector<const char> files)
595     : no_(no), files_(files) { }
596   virtual void Run();
597  private:
598   int no_;
599   i::Vector<const char> files_;
600 };
601 
602 
Run()603 void ShellThread::Run() {
604   // Prepare the context for this thread.
605   Locker locker;
606   HandleScope scope;
607   Handle<ObjectTemplate> global_template = ObjectTemplate::New();
608   global_template->Set(String::New("print"),
609                        FunctionTemplate::New(Shell::Print));
610   global_template->Set(String::New("write"),
611                        FunctionTemplate::New(Shell::Write));
612   global_template->Set(String::New("read"),
613                        FunctionTemplate::New(Shell::Read));
614   global_template->Set(String::New("readline"),
615                        FunctionTemplate::New(Shell::ReadLine));
616   global_template->Set(String::New("load"),
617                        FunctionTemplate::New(Shell::Load));
618   global_template->Set(String::New("yield"),
619                        FunctionTemplate::New(Shell::Yield));
620   global_template->Set(String::New("version"),
621                        FunctionTemplate::New(Shell::Version));
622 
623   char* ptr = const_cast<char*>(files_.start());
624   while ((ptr != NULL) && (*ptr != '\0')) {
625     // For each newline-separated line.
626     char* next_line = ReadLine(ptr);
627 
628     if (*ptr == '#') {
629       // Skip comment lines.
630       ptr = next_line;
631       continue;
632     }
633 
634     Persistent<Context> thread_context = Context::New(NULL, global_template);
635     thread_context->SetSecurityToken(Undefined());
636     Context::Scope context_scope(thread_context);
637 
638     while ((ptr != NULL) && (*ptr != '\0')) {
639       char* filename = ptr;
640       ptr = ReadWord(ptr);
641 
642       // Skip empty strings.
643       if (strlen(filename) == 0) {
644         break;
645       }
646 
647       Handle<String> str = Shell::ReadFile(filename);
648       if (str.IsEmpty()) {
649         printf("WARNING: %s not found\n", filename);
650         break;
651       }
652 
653       Shell::ExecuteString(str, String::New(filename), false, false);
654     }
655 
656     thread_context.Dispose();
657     ptr = next_line;
658   }
659 }
660 
661 
Main(int argc,char * argv[])662 int Shell::Main(int argc, char* argv[]) {
663   i::FlagList::SetFlagsFromCommandLine(&argc, argv, true);
664   if (i::FLAG_help) {
665     return 1;
666   }
667   Initialize();
668   bool run_shell = (argc == 1);
669 
670   // Default use preemption if threads are created.
671   bool use_preemption = true;
672 
673   // Default to use lowest possible thread preemption interval to test as many
674   // edgecases as possible.
675   int preemption_interval = 1;
676 
677   i::List<i::Thread*> threads(1);
678 
679   {
680     // Acquire the V8 lock once initialization has finished. Since the thread
681     // below may spawn new threads accessing V8 holding the V8 lock here is
682     // mandatory.
683     Locker locker;
684     Context::Scope context_scope(evaluation_context_);
685     for (int i = 1; i < argc; i++) {
686       char* str = argv[i];
687       if (strcmp(str, "--shell") == 0) {
688         run_shell = true;
689       } else if (strcmp(str, "--preemption") == 0) {
690         use_preemption = true;
691       } else if (strcmp(str, "--no-preemption") == 0) {
692         use_preemption = false;
693       } else if (strcmp(str, "--preemption-interval") == 0) {
694         if (i + 1 < argc) {
695           char* end = NULL;
696           preemption_interval = strtol(argv[++i], &end, 10);  // NOLINT
697           if (preemption_interval <= 0 || *end != '\0' || errno == ERANGE) {
698             printf("Invalid value for --preemption-interval '%s'\n", argv[i]);
699             return 1;
700           }
701         } else {
702           printf("Missing value for --preemption-interval\n");
703           return 1;
704        }
705       } else if (strcmp(str, "-f") == 0) {
706         // Ignore any -f flags for compatibility with other stand-alone
707         // JavaScript engines.
708         continue;
709       } else if (strncmp(str, "--", 2) == 0) {
710         printf("Warning: unknown flag %s.\nTry --help for options\n", str);
711       } else if (strcmp(str, "-e") == 0 && i + 1 < argc) {
712         // Execute argument given to -e option directly.
713         v8::HandleScope handle_scope;
714         v8::Handle<v8::String> file_name = v8::String::New("unnamed");
715         v8::Handle<v8::String> source = v8::String::New(argv[i + 1]);
716         if (!ExecuteString(source, file_name, false, true)) {
717           OnExit();
718           return 1;
719         }
720         i++;
721       } else if (strcmp(str, "-p") == 0 && i + 1 < argc) {
722         int size = 0;
723         const char* files = ReadChars(argv[++i], &size);
724         if (files == NULL) return 1;
725         ShellThread* thread =
726             new ShellThread(threads.length(),
727                             i::Vector<const char>(files, size));
728         thread->Start();
729         threads.Add(thread);
730       } else {
731         // Use all other arguments as names of files to load and run.
732         HandleScope handle_scope;
733         Handle<String> file_name = v8::String::New(str);
734         Handle<String> source = ReadFile(str);
735         if (source.IsEmpty()) {
736           printf("Error reading '%s'\n", str);
737           return 1;
738         }
739         if (!ExecuteString(source, file_name, false, true)) {
740           OnExit();
741           return 1;
742         }
743       }
744     }
745 
746     // Start preemption if threads have been created and preemption is enabled.
747     if (threads.length() > 0 && use_preemption) {
748       Locker::StartPreemption(preemption_interval);
749     }
750 
751 #ifdef ENABLE_DEBUGGER_SUPPORT
752     // Run the remote debugger if requested.
753     if (i::FLAG_remote_debugger) {
754       RunRemoteDebugger(i::FLAG_debugger_port);
755       return 0;
756     }
757 #endif
758   }
759   if (run_shell)
760     RunShell();
761   for (int i = 0; i < threads.length(); i++) {
762     i::Thread* thread = threads[i];
763     thread->Join();
764     delete thread;
765   }
766   OnExit();
767   return 0;
768 }
769 
770 
771 }  // namespace v8
772 
773 
main(int argc,char * argv[])774 int main(int argc, char* argv[]) {
775   return v8::Shell::Main(argc, argv);
776 }
777