• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
LineEditor(Type type,const char * name)72 LineEditor::LineEditor(Type type, const char* name)
73     : type_(type),
74       name_(name),
75       next_(first_) {
76   first_ = this;
77 }
78 
79 
Get()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:
DumbLineEditor()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 
Prompt(const char * prompt)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
Match(void * key1,void * key2)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.
ToCString(const v8::String::Utf8Value & value)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.
ExecuteString(Handle<String> source,Handle<Value> name,bool print_result,bool report_exceptions)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 
Print(const Arguments & args)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 
Write(const Arguments & args)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 
EnableProfiler(const Arguments & args)213 Handle<Value> Shell::EnableProfiler(const Arguments& args) {
214   V8::ResumeProfiler();
215   return Undefined();
216 }
217 
218 
DisableProfiler(const Arguments & args)219 Handle<Value> Shell::DisableProfiler(const Arguments& args) {
220   V8::PauseProfiler();
221   return Undefined();
222 }
223 
224 
Read(const Arguments & args)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 
ReadFromStdin()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 
Load(const Arguments & args)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 
convertToUint(Local<Value> value_in,TryCatch * try_catch)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 
CreateExternalArray(const Arguments & args,ExternalArrayType type,size_t element_size)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 
ExternalArrayWeakCallback(Persistent<Value> object,void * data)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 
ArrayBuffer(const Arguments & args)461 Handle<Value> Shell::ArrayBuffer(const Arguments& args) {
462   return CreateExternalArray(args, v8::kExternalByteArray, 0);
463 }
464 
465 
Int8Array(const Arguments & args)466 Handle<Value> Shell::Int8Array(const Arguments& args) {
467   return CreateExternalArray(args, v8::kExternalByteArray, sizeof(int8_t));
468 }
469 
470 
Uint8Array(const Arguments & args)471 Handle<Value> Shell::Uint8Array(const Arguments& args) {
472   return CreateExternalArray(args, kExternalUnsignedByteArray, sizeof(uint8_t));
473 }
474 
475 
Int16Array(const Arguments & args)476 Handle<Value> Shell::Int16Array(const Arguments& args) {
477   return CreateExternalArray(args, kExternalShortArray, sizeof(int16_t));
478 }
479 
480 
Uint16Array(const Arguments & args)481 Handle<Value> Shell::Uint16Array(const Arguments& args) {
482   return CreateExternalArray(args, kExternalUnsignedShortArray,
483                              sizeof(uint16_t));
484 }
485 
486 
Int32Array(const Arguments & args)487 Handle<Value> Shell::Int32Array(const Arguments& args) {
488   return CreateExternalArray(args, kExternalIntArray, sizeof(int32_t));
489 }
490 
491 
Uint32Array(const Arguments & args)492 Handle<Value> Shell::Uint32Array(const Arguments& args) {
493   return CreateExternalArray(args, kExternalUnsignedIntArray, sizeof(uint32_t));
494 }
495 
496 
Float32Array(const Arguments & args)497 Handle<Value> Shell::Float32Array(const Arguments& args) {
498   return CreateExternalArray(args, kExternalFloatArray,
499                              sizeof(float));  // NOLINT
500 }
501 
502 
Float64Array(const Arguments & args)503 Handle<Value> Shell::Float64Array(const Arguments& args) {
504   return CreateExternalArray(args, kExternalDoubleArray,
505                              sizeof(double));  // NOLINT
506 }
507 
508 
PixelArray(const Arguments & args)509 Handle<Value> Shell::PixelArray(const Arguments& args) {
510   return CreateExternalArray(args, kExternalPixelArray, sizeof(uint8_t));
511 }
512 
513 
Yield(const Arguments & args)514 Handle<Value> Shell::Yield(const Arguments& args) {
515   v8::Unlocker unlocker;
516   return Undefined();
517 }
518 
519 
Quit(const Arguments & args)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 
Version(const Arguments & args)530 Handle<Value> Shell::Version(const Arguments& args) {
531   return String::New(V8::GetVersion());
532 }
533 
534 
ReportException(v8::TryCatch * try_catch)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
GetCompletions(Handle<String> text,Handle<String> full)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
DebugMessageDetails(Handle<String> message)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 
DebugCommandToJSONRequest(Handle<String> command)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 
DispatchDebugMessages()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
Bind(const char * name,bool is_histogram)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 
AddSample(int32_t sample)636 void Counter::AddSample(int32_t sample) {
637   count_++;
638   sample_total_ += sample;
639 }
640 
641 
CounterCollection()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 
GetNextCounter()650 Counter* CounterCollection::GetNextCounter() {
651   if (counters_in_use_ == kMaxCounters) return NULL;
652   return &counters_[counters_in_use_++];
653 }
654 
655 
MapCounters(const char * name)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 
Hash(const char * name)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 
GetCounter(const char * name,bool is_histogram)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 
LookupCounter(const char * name)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 
CreateHistogram(const char * name,int min,int max,size_t buckets)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 
AddHistogramSample(void * histogram,int sample)718 void Shell::AddHistogramSample(void* histogram, int sample) {
719   Counter* counter = reinterpret_cast<Counter*>(histogram);
720   counter->AddSample(sample);
721 }
722 
723 
InstallUtilityScript()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:
~BZip2Decompressor()780   virtual ~BZip2Decompressor() { }
781 
782  protected:
DecompressData(char * raw_data,int * raw_data_size,const char * compressed_data,int compressed_data_size)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 
CreateGlobalTemplate()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 
Initialize()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 
CreateEvaluationContext()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 
Exit(int exit_code)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 
CompareKeys(const void * a,const void * b)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 
OnExit()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 
FOpen(const char * path,const char * mode)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 
ReadChars(const char * name,int * size_out)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 
ReadBinary(const Arguments & args)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
ReadToken(char * data,char token)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 
ReadLine(char * data)1058 static char* ReadLine(char* data) {
1059   return ReadToken(data, '\n');
1060 }
1061 
1062 
ReadWord(char * data)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.
ReadFile(const char * name)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 
RunShell()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|.
ShellThread(int no,char * files)1102   ShellThread(int no, char* files)
1103       : Thread("d8:ShellThread"),
1104         no_(no), files_(files) { }
1105 
~ShellThread()1106   ~ShellThread() {
1107     delete[] files_;
1108   }
1109 
1110   virtual void Run();
1111  private:
1112   int no_;
1113   char* files_;
1114 };
1115 
1116 
Run()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 
~SourceGroup()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 
Execute()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 
ReadFile(const char * name)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
GetThreadOptions()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 
ExecuteInThread()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 
StartExecuteInThread()1245 void SourceGroup::StartExecuteInThread() {
1246   if (thread_ == NULL) {
1247     thread_ = new IsolateThread(this);
1248     thread_->Start();
1249   }
1250   next_semaphore_->Signal();
1251 }
1252 
1253 
WaitForThread()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 
SetOptions(int argc,char * argv[])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 
RunMain(int argc,char * argv[])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 
Main(int argc,char * argv[])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
main(int argc,char * argv[])1545 int main(int argc, char* argv[]) {
1546   return v8::Shell::Main(argc, argv);
1547 }
1548 #endif
1549