Home | History | Annotate | Download | only in src
      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 
     50 LineEditor::LineEditor(Type type, const char* name)
     51     : type_(type),
     52       name_(name),
     53       next_(first_) {
     54   first_ = this;
     55 }
     56 
     57 
     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:
     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 
     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 
     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.
    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.
    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 
    148 Handle<Value> Shell::Print(const Arguments& args) {
    149   Handle<Value> val = Write(args);
    150   printf("\n");
    151   return val;
    152 }
    153 
    154 
    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 
    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 
    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 
    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 
    217 Handle<Value> Shell::Yield(const Arguments& args) {
    218   v8::Unlocker unlocker;
    219   return Undefined();
    220 }
    221 
    222 
    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 
    231 Handle<Value> Shell::Version(const Arguments& args) {
    232   return String::New(V8::GetVersion());
    233 }
    234 
    235 
    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 
    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
    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 
    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 
    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 
    315 void Counter::AddSample(int32_t sample) {
    316   count_++;
    317   sample_total_ += sample;
    318 }
    319 
    320 
    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 
    329 Counter* CounterCollection::GetNextCounter() {
    330   if (counters_in_use_ == kMaxCounters) return NULL;
    331   return &counters_[counters_in_use_++];
    332 }
    333 
    334 
    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 
    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 
    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 
    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 
    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 
    397 void Shell::AddHistogramSample(void* histogram, int sample) {
    398   Counter* counter = reinterpret_cast<Counter*>(histogram);
    399   counter->AddSample(sample);
    400 }
    401 
    402 
    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 
    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 
    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 
    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 
    551 static char* ReadLine(char* data) {
    552   return ReadToken(data, '\n');
    553 }
    554 
    555 
    556 static char* ReadWord(char* data) {
    557   return ReadToken(data, ' ');
    558 }
    559 
    560 
    561 // Reads a file into a v8 string.
    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 
    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:
    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 
    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 
    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 
    774 int main(int argc, char* argv[]) {
    775   return v8::Shell::Main(argc, argv);
    776 }
    777