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