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