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