blob: 5fd9d27281a135435e4a8ff6d7d368e4dd6165e6 [file] [log] [blame]
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001// Copyright 2011 the V8 project authors. All rights reserved.
Steve Blocka7e24c12009-10-30 11:49:00 +00002// 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
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000029#ifdef V8_SHARED
30#define USING_V8_SHARED
31#endif
Steve Blocka7e24c12009-10-30 11:49:00 +000032
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000033#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
41#ifdef USING_V8_SHARED
42#include <assert.h>
43#include "../include/v8-testing.h"
44#endif // USING_V8_SHARED
Steve Block44f0eee2011-05-26 01:26:41 +010045
Steve Blocka7e24c12009-10-30 11:49:00 +000046#include "d8.h"
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000047
48#ifndef USING_V8_SHARED
49#include "api.h"
50#include "checks.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000051#include "d8-debug.h"
52#include "debug.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000053#include "natives.h"
54#include "platform.h"
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000055#include "v8.h"
56#endif // USING_V8_SHARED
Steve Blocka7e24c12009-10-30 11:49:00 +000057
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000058#if !defined(_WIN32) && !defined(_WIN64)
59#include <unistd.h> // NOLINT
60#endif
61
62#ifdef USING_V8_SHARED
63#define ASSERT(condition) assert(condition)
64#endif // USING_V8_SHARED
Steve Blocka7e24c12009-10-30 11:49:00 +000065
66namespace v8 {
67
68
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000069#ifndef USING_V8_SHARED
Steve Blocka7e24c12009-10-30 11:49:00 +000070LineEditor *LineEditor::first_ = NULL;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000071const char* Shell::kHistoryFileName = ".d8_history";
Steve Blocka7e24c12009-10-30 11:49:00 +000072
73
74LineEditor::LineEditor(Type type, const char* name)
75 : type_(type),
76 name_(name),
77 next_(first_) {
78 first_ = this;
79}
80
81
82LineEditor* LineEditor::Get() {
83 LineEditor* current = first_;
84 LineEditor* best = current;
85 while (current != NULL) {
86 if (current->type_ > best->type_)
87 best = current;
88 current = current->next_;
89 }
90 return best;
91}
92
93
94class DumbLineEditor: public LineEditor {
95 public:
96 DumbLineEditor() : LineEditor(LineEditor::DUMB, "dumb") { }
97 virtual i::SmartPointer<char> Prompt(const char* prompt);
98};
99
100
101static DumbLineEditor dumb_line_editor;
102
103
104i::SmartPointer<char> DumbLineEditor::Prompt(const char* prompt) {
105 static const int kBufferSize = 256;
106 char buffer[kBufferSize];
107 printf("%s", prompt);
108 char* str = fgets(buffer, kBufferSize, stdin);
109 return i::SmartPointer<char>(str ? i::StrDup(str) : str);
110}
111
112
113CounterMap* Shell::counter_map_;
114i::OS::MemoryMappedFile* Shell::counters_file_ = NULL;
115CounterCollection Shell::local_counters_;
116CounterCollection* Shell::counters_ = &local_counters_;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000117i::Mutex* Shell::context_mutex_(i::OS::CreateMutex());
Steve Blocka7e24c12009-10-30 11:49:00 +0000118Persistent<Context> Shell::utility_context_;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000119#endif // USING_V8_SHARED
120
Steve Blocka7e24c12009-10-30 11:49:00 +0000121Persistent<Context> Shell::evaluation_context_;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000122ShellOptions Shell::options;
123const char* Shell::kPrompt = "d8> ";
Steve Blocka7e24c12009-10-30 11:49:00 +0000124
125
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000126#ifndef USING_V8_SHARED
Steve Blocka7e24c12009-10-30 11:49:00 +0000127bool 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}
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000132#endif // USING_V8_SHARED
Steve Blocka7e24c12009-10-30 11:49:00 +0000133
134
135// Converts a V8 value to a C string.
Steve Block6ded16b2010-05-10 14:33:55 +0100136const char* Shell::ToCString(const v8::String::Utf8Value& value) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000137 return *value ? *value : "<string conversion failed>";
138}
139
140
141// Executes a string within the current v8 context.
142bool Shell::ExecuteString(Handle<String> source,
143 Handle<Value> name,
144 bool print_result,
145 bool report_exceptions) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000146#ifndef USING_V8_SHARED
147 bool FLAG_debugger = i::FLAG_debugger;
148#else
149 bool FLAG_debugger = false;
150#endif // USING_V8_SHARED
Steve Blocka7e24c12009-10-30 11:49:00 +0000151 HandleScope handle_scope;
152 TryCatch try_catch;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000153 options.script_executed = true;
154 if (FLAG_debugger) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000155 // 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.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000161 if (report_exceptions && !FLAG_debugger)
Steve Blocka7e24c12009-10-30 11:49:00 +0000162 ReportException(&try_catch);
163 return false;
164 } else {
165 Handle<Value> result = script->Run();
166 if (result.IsEmpty()) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100167 ASSERT(try_catch.HasCaught());
Steve Blocka7e24c12009-10-30 11:49:00 +0000168 // Print errors that happened during execution.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000169 if (report_exceptions && !FLAG_debugger)
Steve Blocka7e24c12009-10-30 11:49:00 +0000170 ReportException(&try_catch);
171 return false;
172 } else {
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100173 ASSERT(!try_catch.HasCaught());
Steve Blocka7e24c12009-10-30 11:49:00 +0000174 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 const char* cstr = ToCString(str);
179 printf("%s\n", cstr);
180 }
181 return true;
182 }
183 }
184}
185
186
187Handle<Value> Shell::Print(const Arguments& args) {
188 Handle<Value> val = Write(args);
189 printf("\n");
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000190 fflush(stdout);
Steve Blocka7e24c12009-10-30 11:49:00 +0000191 return val;
192}
193
194
195Handle<Value> Shell::Write(const Arguments& args) {
196 for (int i = 0; i < args.Length(); i++) {
197 HandleScope handle_scope;
198 if (i != 0) {
199 printf(" ");
200 }
201 v8::String::Utf8Value str(args[i]);
Steve Blockd0582a62009-12-15 09:54:21 +0000202 int n = fwrite(*str, sizeof(**str), str.length(), stdout);
203 if (n != str.length()) {
204 printf("Error in fwrite\n");
205 exit(1);
206 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000207 }
208 return Undefined();
209}
210
211
212Handle<Value> Shell::Read(const Arguments& args) {
213 String::Utf8Value file(args[0]);
214 if (*file == NULL) {
215 return ThrowException(String::New("Error loading file"));
216 }
217 Handle<String> source = ReadFile(*file);
218 if (source.IsEmpty()) {
219 return ThrowException(String::New("Error loading file"));
220 }
221 return source;
222}
223
224
225Handle<Value> Shell::ReadLine(const Arguments& args) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000226 static const int kBufferSize = 256;
227 char buffer[kBufferSize];
228 Handle<String> accumulator = String::New("");
229 bool linebreak;
230 int length;
231 do { // Repeat if the line ends with an escape '\'.
232 // fgets got an error. Just give up.
233 if (fgets(buffer, kBufferSize, stdin) == NULL) return Null();
234 length = strlen(buffer);
235 linebreak = (length > 1 && buffer[length-2] == '\\');
236 if (linebreak) buffer[length-2] = '\n';
237 accumulator = String::Concat(accumulator, String::New(buffer, length-1));
238 } while (linebreak);
239 return accumulator;
Steve Blocka7e24c12009-10-30 11:49:00 +0000240}
241
242
243Handle<Value> Shell::Load(const Arguments& args) {
244 for (int i = 0; i < args.Length(); i++) {
245 HandleScope handle_scope;
246 String::Utf8Value file(args[i]);
247 if (*file == NULL) {
248 return ThrowException(String::New("Error loading file"));
249 }
250 Handle<String> source = ReadFile(*file);
251 if (source.IsEmpty()) {
252 return ThrowException(String::New("Error loading file"));
253 }
254 if (!ExecuteString(source, String::New(*file), false, false)) {
Steve Blockd0582a62009-12-15 09:54:21 +0000255 return ThrowException(String::New("Error executing file"));
Steve Blocka7e24c12009-10-30 11:49:00 +0000256 }
257 }
258 return Undefined();
259}
260
261
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000262Handle<Value> Shell::CreateExternalArray(const Arguments& args,
263 ExternalArrayType type,
264 size_t element_size) {
265 ASSERT(element_size == 1 || element_size == 2 || element_size == 4 ||
266 element_size == 8);
267 if (args.Length() != 1) {
268 return ThrowException(
269 String::New("Array constructor needs one parameter."));
270 }
271 static const int kMaxLength = 0x3fffffff;
272#ifndef USING_V8_SHARED
273 ASSERT(kMaxLength == i::ExternalArray::kMaxLength);
274#endif // USING_V8_SHARED
275 size_t length = 0;
276 if (args[0]->IsUint32()) {
277 length = args[0]->Uint32Value();
278 } else if (args[0]->IsNumber()) {
279 double raw_length = args[0]->NumberValue();
280 if (raw_length < 0) {
281 return ThrowException(String::New("Array length must not be negative."));
282 }
283 if (raw_length > kMaxLength) {
284 return ThrowException(
285 String::New("Array length exceeds maximum length."));
286 }
287 length = static_cast<size_t>(raw_length);
288 } else {
289 return ThrowException(String::New("Array length must be a number."));
290 }
291 if (length > static_cast<size_t>(kMaxLength)) {
292 return ThrowException(String::New("Array length exceeds maximum length."));
293 }
294 void* data = calloc(length, element_size);
295 if (data == NULL) {
296 return ThrowException(String::New("Memory allocation failed."));
297 }
298 Handle<Object> array = Object::New();
299 Persistent<Object> persistent_array = Persistent<Object>::New(array);
300 persistent_array.MakeWeak(data, ExternalArrayWeakCallback);
301 persistent_array.MarkIndependent();
302 array->SetIndexedPropertiesToExternalArrayData(data, type, length);
303 array->Set(String::New("length"), Int32::New(length), ReadOnly);
304 array->Set(String::New("BYTES_PER_ELEMENT"), Int32::New(element_size));
305 return array;
306}
307
308
309void Shell::ExternalArrayWeakCallback(Persistent<Value> object, void* data) {
310 free(data);
311 object.Dispose();
312}
313
314
315Handle<Value> Shell::Int8Array(const Arguments& args) {
316 return CreateExternalArray(args, v8::kExternalByteArray, sizeof(int8_t));
317}
318
319
320Handle<Value> Shell::Uint8Array(const Arguments& args) {
321 return CreateExternalArray(args, kExternalUnsignedByteArray, sizeof(uint8_t));
322}
323
324
325Handle<Value> Shell::Int16Array(const Arguments& args) {
326 return CreateExternalArray(args, kExternalShortArray, sizeof(int16_t));
327}
328
329
330Handle<Value> Shell::Uint16Array(const Arguments& args) {
331 return CreateExternalArray(args, kExternalUnsignedShortArray,
332 sizeof(uint16_t));
333}
334
335
336Handle<Value> Shell::Int32Array(const Arguments& args) {
337 return CreateExternalArray(args, kExternalIntArray, sizeof(int32_t));
338}
339
340
341Handle<Value> Shell::Uint32Array(const Arguments& args) {
342 return CreateExternalArray(args, kExternalUnsignedIntArray, sizeof(uint32_t));
343}
344
345
346Handle<Value> Shell::Float32Array(const Arguments& args) {
347 return CreateExternalArray(args, kExternalFloatArray,
348 sizeof(float)); // NOLINT
349}
350
351
352Handle<Value> Shell::Float64Array(const Arguments& args) {
353 return CreateExternalArray(args, kExternalDoubleArray,
354 sizeof(double)); // NOLINT
355}
356
357
358Handle<Value> Shell::PixelArray(const Arguments& args) {
359 return CreateExternalArray(args, kExternalPixelArray, sizeof(uint8_t));
360}
361
362
Steve Blocka7e24c12009-10-30 11:49:00 +0000363Handle<Value> Shell::Yield(const Arguments& args) {
364 v8::Unlocker unlocker;
365 return Undefined();
366}
367
368
369Handle<Value> Shell::Quit(const Arguments& args) {
370 int exit_code = args[0]->Int32Value();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000371#ifndef USING_V8_SHARED
Steve Blocka7e24c12009-10-30 11:49:00 +0000372 OnExit();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000373#endif // USING_V8_SHARED
Steve Blocka7e24c12009-10-30 11:49:00 +0000374 exit(exit_code);
375 return Undefined();
376}
377
378
379Handle<Value> Shell::Version(const Arguments& args) {
380 return String::New(V8::GetVersion());
381}
382
383
384void Shell::ReportException(v8::TryCatch* try_catch) {
385 HandleScope handle_scope;
386 v8::String::Utf8Value exception(try_catch->Exception());
387 const char* exception_string = ToCString(exception);
388 Handle<Message> message = try_catch->Message();
389 if (message.IsEmpty()) {
390 // V8 didn't provide any extra information about this error; just
391 // print the exception.
392 printf("%s\n", exception_string);
393 } else {
394 // Print (filename):(line number): (message).
395 v8::String::Utf8Value filename(message->GetScriptResourceName());
396 const char* filename_string = ToCString(filename);
397 int linenum = message->GetLineNumber();
398 printf("%s:%i: %s\n", filename_string, linenum, exception_string);
399 // Print line of source code.
400 v8::String::Utf8Value sourceline(message->GetSourceLine());
401 const char* sourceline_string = ToCString(sourceline);
402 printf("%s\n", sourceline_string);
403 // Print wavy underline (GetUnderline is deprecated).
404 int start = message->GetStartColumn();
405 for (int i = 0; i < start; i++) {
406 printf(" ");
407 }
408 int end = message->GetEndColumn();
409 for (int i = start; i < end; i++) {
410 printf("^");
411 }
412 printf("\n");
Ben Murdoch257744e2011-11-30 15:57:28 +0000413 v8::String::Utf8Value stack_trace(try_catch->StackTrace());
414 if (stack_trace.length() > 0) {
415 const char* stack_trace_string = ToCString(stack_trace);
416 printf("%s\n", stack_trace_string);
417 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000418 }
419}
420
421
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000422#ifndef USING_V8_SHARED
Steve Blocka7e24c12009-10-30 11:49:00 +0000423Handle<Array> Shell::GetCompletions(Handle<String> text, Handle<String> full) {
424 HandleScope handle_scope;
425 Context::Scope context_scope(utility_context_);
426 Handle<Object> global = utility_context_->Global();
427 Handle<Value> fun = global->Get(String::New("GetCompletions"));
428 static const int kArgc = 3;
429 Handle<Value> argv[kArgc] = { evaluation_context_->Global(), text, full };
430 Handle<Value> val = Handle<Function>::Cast(fun)->Call(global, kArgc, argv);
431 return handle_scope.Close(Handle<Array>::Cast(val));
432}
433
434
435#ifdef ENABLE_DEBUGGER_SUPPORT
436Handle<Object> Shell::DebugMessageDetails(Handle<String> message) {
437 Context::Scope context_scope(utility_context_);
438 Handle<Object> global = utility_context_->Global();
439 Handle<Value> fun = global->Get(String::New("DebugMessageDetails"));
440 static const int kArgc = 1;
441 Handle<Value> argv[kArgc] = { message };
442 Handle<Value> val = Handle<Function>::Cast(fun)->Call(global, kArgc, argv);
443 return Handle<Object>::Cast(val);
444}
445
446
447Handle<Value> Shell::DebugCommandToJSONRequest(Handle<String> command) {
448 Context::Scope context_scope(utility_context_);
449 Handle<Object> global = utility_context_->Global();
450 Handle<Value> fun = global->Get(String::New("DebugCommandToJSONRequest"));
451 static const int kArgc = 1;
452 Handle<Value> argv[kArgc] = { command };
453 Handle<Value> val = Handle<Function>::Cast(fun)->Call(global, kArgc, argv);
454 return val;
455}
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000456#endif // ENABLE_DEBUGGER_SUPPORT
457#endif // USING_V8_SHARED
Steve Blocka7e24c12009-10-30 11:49:00 +0000458
459
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000460#ifndef USING_V8_SHARED
Steve Blocka7e24c12009-10-30 11:49:00 +0000461int32_t* Counter::Bind(const char* name, bool is_histogram) {
462 int i;
463 for (i = 0; i < kMaxNameSize - 1 && name[i]; i++)
464 name_[i] = static_cast<char>(name[i]);
465 name_[i] = '\0';
466 is_histogram_ = is_histogram;
467 return ptr();
468}
469
470
471void Counter::AddSample(int32_t sample) {
472 count_++;
473 sample_total_ += sample;
474}
475
476
477CounterCollection::CounterCollection() {
478 magic_number_ = 0xDEADFACE;
479 max_counters_ = kMaxCounters;
480 max_name_size_ = Counter::kMaxNameSize;
481 counters_in_use_ = 0;
482}
483
484
485Counter* CounterCollection::GetNextCounter() {
486 if (counters_in_use_ == kMaxCounters) return NULL;
487 return &counters_[counters_in_use_++];
488}
489
490
491void Shell::MapCounters(const char* name) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000492 counters_file_ = i::OS::MemoryMappedFile::create(
493 name, sizeof(CounterCollection), &local_counters_);
Steve Blocka7e24c12009-10-30 11:49:00 +0000494 void* memory = (counters_file_ == NULL) ?
495 NULL : counters_file_->memory();
496 if (memory == NULL) {
497 printf("Could not map counters file %s\n", name);
498 exit(1);
499 }
500 counters_ = static_cast<CounterCollection*>(memory);
501 V8::SetCounterFunction(LookupCounter);
502 V8::SetCreateHistogramFunction(CreateHistogram);
503 V8::SetAddHistogramSampleFunction(AddHistogramSample);
504}
505
506
507int CounterMap::Hash(const char* name) {
508 int h = 0;
509 int c;
510 while ((c = *name++) != 0) {
511 h += h << 5;
512 h += c;
513 }
514 return h;
515}
516
517
518Counter* Shell::GetCounter(const char* name, bool is_histogram) {
519 Counter* counter = counter_map_->Lookup(name);
520
521 if (counter == NULL) {
522 counter = counters_->GetNextCounter();
523 if (counter != NULL) {
524 counter_map_->Set(name, counter);
525 counter->Bind(name, is_histogram);
526 }
527 } else {
528 ASSERT(counter->is_histogram() == is_histogram);
529 }
530 return counter;
531}
532
533
534int* Shell::LookupCounter(const char* name) {
535 Counter* counter = GetCounter(name, false);
536
537 if (counter != NULL) {
538 return counter->ptr();
539 } else {
540 return NULL;
541 }
542}
543
544
545void* Shell::CreateHistogram(const char* name,
546 int min,
547 int max,
548 size_t buckets) {
549 return GetCounter(name, true);
550}
551
552
553void Shell::AddHistogramSample(void* histogram, int sample) {
554 Counter* counter = reinterpret_cast<Counter*>(histogram);
555 counter->AddSample(sample);
556}
557
558
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000559void Shell::InstallUtilityScript() {
560 Locker lock;
Steve Blocka7e24c12009-10-30 11:49:00 +0000561 HandleScope scope;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000562 // If we use the utility context, we have to set the security tokens so that
563 // utility, evaluation and debug context can all access each other.
Steve Blocka7e24c12009-10-30 11:49:00 +0000564 utility_context_->SetSecurityToken(Undefined());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000565 evaluation_context_->SetSecurityToken(Undefined());
Steve Blocka7e24c12009-10-30 11:49:00 +0000566 Context::Scope utility_scope(utility_context_);
567
Steve Blocka7e24c12009-10-30 11:49:00 +0000568#ifdef ENABLE_DEBUGGER_SUPPORT
569 // Install the debugger object in the utility scope
Steve Block44f0eee2011-05-26 01:26:41 +0100570 i::Debug* debug = i::Isolate::Current()->debug();
571 debug->Load();
572 i::Handle<i::JSObject> js_debug
573 = i::Handle<i::JSObject>(debug->debug_context()->global());
Steve Blocka7e24c12009-10-30 11:49:00 +0000574 utility_context_->Global()->Set(String::New("$debug"),
Steve Block44f0eee2011-05-26 01:26:41 +0100575 Utils::ToLocal(js_debug));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000576 debug->debug_context()->set_security_token(HEAP->undefined_value());
577#endif // ENABLE_DEBUGGER_SUPPORT
Steve Blocka7e24c12009-10-30 11:49:00 +0000578
579 // Run the d8 shell utility script in the utility context
580 int source_index = i::NativesCollection<i::D8>::GetIndex("d8");
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000581 i::Vector<const char> shell_source =
582 i::NativesCollection<i::D8>::GetRawScriptSource(source_index);
583 i::Vector<const char> shell_source_name =
584 i::NativesCollection<i::D8>::GetScriptName(source_index);
Steve Blocka7e24c12009-10-30 11:49:00 +0000585 Handle<String> source = String::New(shell_source.start(),
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000586 shell_source.length());
Steve Blocka7e24c12009-10-30 11:49:00 +0000587 Handle<String> name = String::New(shell_source_name.start(),
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000588 shell_source_name.length());
Steve Blocka7e24c12009-10-30 11:49:00 +0000589 Handle<Script> script = Script::Compile(source, name);
590 script->Run();
Steve Blocka7e24c12009-10-30 11:49:00 +0000591 // Mark the d8 shell script as native to avoid it showing up as normal source
592 // in the debugger.
Steve Block6ded16b2010-05-10 14:33:55 +0100593 i::Handle<i::Object> compiled_script = Utils::OpenHandle(*script);
594 i::Handle<i::Script> script_object = compiled_script->IsJSFunction()
595 ? i::Handle<i::Script>(i::Script::cast(
596 i::JSFunction::cast(*compiled_script)->shared()->script()))
597 : i::Handle<i::Script>(i::Script::cast(
598 i::SharedFunctionInfo::cast(*compiled_script)->script()));
Steve Blocka7e24c12009-10-30 11:49:00 +0000599 script_object->set_type(i::Smi::FromInt(i::Script::TYPE_NATIVE));
600
Steve Blocka7e24c12009-10-30 11:49:00 +0000601#ifdef ENABLE_DEBUGGER_SUPPORT
Steve Blocka7e24c12009-10-30 11:49:00 +0000602 // Start the in-process debugger if requested.
603 if (i::FLAG_debugger && !i::FLAG_debugger_agent) {
604 v8::Debug::SetDebugEventListener(HandleDebugEvent);
605 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000606#endif // ENABLE_DEBUGGER_SUPPORT
607}
608#endif // USING_V8_SHARED
609
610
611#ifdef COMPRESS_STARTUP_DATA_BZ2
612class BZip2Decompressor : public v8::StartupDataDecompressor {
613 public:
614 virtual ~BZip2Decompressor() { }
615
616 protected:
617 virtual int DecompressData(char* raw_data,
618 int* raw_data_size,
619 const char* compressed_data,
620 int compressed_data_size) {
621 ASSERT_EQ(v8::StartupData::kBZip2,
622 v8::V8::GetCompressedStartupDataAlgorithm());
623 unsigned int decompressed_size = *raw_data_size;
624 int result =
625 BZ2_bzBuffToBuffDecompress(raw_data,
626 &decompressed_size,
627 const_cast<char*>(compressed_data),
628 compressed_data_size,
629 0, 1);
630 if (result == BZ_OK) {
631 *raw_data_size = decompressed_size;
632 }
633 return result;
634 }
635};
Steve Blocka7e24c12009-10-30 11:49:00 +0000636#endif
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000637
638Handle<ObjectTemplate> Shell::CreateGlobalTemplate() {
639 Handle<ObjectTemplate> global_template = ObjectTemplate::New();
640 global_template->Set(String::New("print"), FunctionTemplate::New(Print));
641 global_template->Set(String::New("write"), FunctionTemplate::New(Write));
642 global_template->Set(String::New("read"), FunctionTemplate::New(Read));
643 global_template->Set(String::New("readline"),
644 FunctionTemplate::New(ReadLine));
645 global_template->Set(String::New("load"), FunctionTemplate::New(Load));
646 global_template->Set(String::New("quit"), FunctionTemplate::New(Quit));
647 global_template->Set(String::New("version"), FunctionTemplate::New(Version));
648
649 // Bind the handlers for external arrays.
650 global_template->Set(String::New("Int8Array"),
651 FunctionTemplate::New(Int8Array));
652 global_template->Set(String::New("Uint8Array"),
653 FunctionTemplate::New(Uint8Array));
654 global_template->Set(String::New("Int16Array"),
655 FunctionTemplate::New(Int16Array));
656 global_template->Set(String::New("Uint16Array"),
657 FunctionTemplate::New(Uint16Array));
658 global_template->Set(String::New("Int32Array"),
659 FunctionTemplate::New(Int32Array));
660 global_template->Set(String::New("Uint32Array"),
661 FunctionTemplate::New(Uint32Array));
662 global_template->Set(String::New("Float32Array"),
663 FunctionTemplate::New(Float32Array));
664 global_template->Set(String::New("Float64Array"),
665 FunctionTemplate::New(Float64Array));
666 global_template->Set(String::New("PixelArray"),
667 FunctionTemplate::New(PixelArray));
668
669#ifdef LIVE_OBJECT_LIST
670 global_template->Set(String::New("lol_is_enabled"), Boolean::New(true));
671#else
672 global_template->Set(String::New("lol_is_enabled"), Boolean::New(false));
673#endif
674
675#ifndef USING_V8_SHARED
676 Handle<ObjectTemplate> os_templ = ObjectTemplate::New();
677 AddOSMethods(os_templ);
678 global_template->Set(String::New("os"), os_templ);
679#endif // USING_V8_SHARED
680
681 return global_template;
Steve Blocka7e24c12009-10-30 11:49:00 +0000682}
683
684
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000685void Shell::Initialize() {
686#ifdef COMPRESS_STARTUP_DATA_BZ2
687 BZip2Decompressor startup_data_decompressor;
688 int bz2_result = startup_data_decompressor.Decompress();
689 if (bz2_result != BZ_OK) {
690 fprintf(stderr, "bzip error code: %d\n", bz2_result);
691 exit(1);
692 }
693#endif
694
695#ifndef USING_V8_SHARED
696 Shell::counter_map_ = new CounterMap();
697 // Set up counters
698 if (i::StrLength(i::FLAG_map_counters) != 0)
699 MapCounters(i::FLAG_map_counters);
700 if (i::FLAG_dump_counters) {
701 V8::SetCounterFunction(LookupCounter);
702 V8::SetCreateHistogramFunction(CreateHistogram);
703 V8::SetAddHistogramSampleFunction(AddHistogramSample);
704 }
705#endif // USING_V8_SHARED
706 if (options.test_shell) return;
707
708#ifndef USING_V8_SHARED
709 Locker lock;
710 HandleScope scope;
711 Handle<ObjectTemplate> global_template = CreateGlobalTemplate();
712 utility_context_ = Context::New(NULL, global_template);
713
714#ifdef ENABLE_DEBUGGER_SUPPORT
715 // Start the debugger agent if requested.
716 if (i::FLAG_debugger_agent) {
717 v8::Debug::EnableAgent("d8 shell", i::FLAG_debugger_port, true);
718 }
719#endif // ENABLE_DEBUGGER_SUPPORT
720#endif // USING_V8_SHARED
721}
722
723
724Persistent<Context> Shell::CreateEvaluationContext() {
725#ifndef USING_V8_SHARED
726 // This needs to be a critical section since this is not thread-safe
727 i::ScopedLock lock(context_mutex_);
728#endif // USING_V8_SHARED
729 // Initialize the global objects
730 Handle<ObjectTemplate> global_template = CreateGlobalTemplate();
731 Persistent<Context> context = Context::New(NULL, global_template);
732 Context::Scope scope(context);
733
734#ifndef USING_V8_SHARED
735 i::JSArguments js_args = i::FLAG_js_arguments;
736 i::Handle<i::FixedArray> arguments_array =
737 FACTORY->NewFixedArray(js_args.argc());
738 for (int j = 0; j < js_args.argc(); j++) {
739 i::Handle<i::String> arg =
740 FACTORY->NewStringFromUtf8(i::CStrVector(js_args[j]));
741 arguments_array->set(j, *arg);
742 }
743 i::Handle<i::JSArray> arguments_jsarray =
744 FACTORY->NewJSArrayWithElements(arguments_array);
745 context->Global()->Set(String::New("arguments"),
746 Utils::ToLocal(arguments_jsarray));
747#endif // USING_V8_SHARED
748 return context;
749}
750
751
752#ifndef USING_V8_SHARED
Steve Blocka7e24c12009-10-30 11:49:00 +0000753void Shell::OnExit() {
754 if (i::FLAG_dump_counters) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000755 printf("+----------------------------------------+-------------+\n");
756 printf("| Name | Value |\n");
757 printf("+----------------------------------------+-------------+\n");
Steve Blocka7e24c12009-10-30 11:49:00 +0000758 for (CounterMap::Iterator i(counter_map_); i.More(); i.Next()) {
759 Counter* counter = i.CurrentValue();
760 if (counter->is_histogram()) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000761 printf("| c:%-36s | %11i |\n", i.CurrentKey(), counter->count());
762 printf("| t:%-36s | %11i |\n", i.CurrentKey(), counter->sample_total());
Steve Blocka7e24c12009-10-30 11:49:00 +0000763 } else {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000764 printf("| %-38s | %11i |\n", i.CurrentKey(), counter->count());
Steve Blocka7e24c12009-10-30 11:49:00 +0000765 }
766 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000767 printf("+----------------------------------------+-------------+\n");
Steve Blocka7e24c12009-10-30 11:49:00 +0000768 }
769 if (counters_file_ != NULL)
770 delete counters_file_;
771}
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000772#endif // USING_V8_SHARED
Steve Blocka7e24c12009-10-30 11:49:00 +0000773
774
775static char* ReadChars(const char* name, int* size_out) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000776 // Release the V8 lock while reading files.
777 v8::Unlocker unlocker(Isolate::GetCurrent());
778#ifndef USING_V8_SHARED
Steve Blocka7e24c12009-10-30 11:49:00 +0000779 FILE* file = i::OS::FOpen(name, "rb");
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000780#else
781 // TODO(yangguo@chromium.org): reading from a directory hangs!
782 FILE* file = fopen(name, "rb");
783#endif // USING_V8_SHARED
Steve Blocka7e24c12009-10-30 11:49:00 +0000784 if (file == NULL) return NULL;
785
786 fseek(file, 0, SEEK_END);
787 int size = ftell(file);
788 rewind(file);
789
790 char* chars = new char[size + 1];
791 chars[size] = '\0';
792 for (int i = 0; i < size;) {
793 int read = fread(&chars[i], 1, size - i, file);
794 i += read;
795 }
796 fclose(file);
797 *size_out = size;
798 return chars;
799}
800
801
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000802#ifndef USING_V8_SHARED
Steve Blocka7e24c12009-10-30 11:49:00 +0000803static char* ReadToken(char* data, char token) {
804 char* next = i::OS::StrChr(data, token);
805 if (next != NULL) {
806 *next = '\0';
807 return (next + 1);
808 }
809
810 return NULL;
811}
812
813
814static char* ReadLine(char* data) {
815 return ReadToken(data, '\n');
816}
817
818
819static char* ReadWord(char* data) {
820 return ReadToken(data, ' ');
821}
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000822#endif // USING_V8_SHARED
Steve Blocka7e24c12009-10-30 11:49:00 +0000823
824
825// Reads a file into a v8 string.
826Handle<String> Shell::ReadFile(const char* name) {
827 int size = 0;
828 char* chars = ReadChars(name, &size);
829 if (chars == NULL) return Handle<String>();
830 Handle<String> result = String::New(chars);
831 delete[] chars;
832 return result;
833}
834
835
836void Shell::RunShell() {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000837 Locker locker;
838 Context::Scope context_scope(evaluation_context_);
839 HandleScope handle_scope;
840 Handle<String> name = String::New("(d8)");
841#ifndef USING_V8_SHARED
Steve Blocka7e24c12009-10-30 11:49:00 +0000842 LineEditor* editor = LineEditor::Get();
843 printf("V8 version %s [console: %s]\n", V8::GetVersion(), editor->name());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100844 if (i::FLAG_debugger) {
845 printf("JavaScript debugger enabled\n");
846 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000847 editor->Open();
848 while (true) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000849 i::SmartPointer<char> input = editor->Prompt(Shell::kPrompt);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000850 if (input.is_empty()) break;
Steve Blocka7e24c12009-10-30 11:49:00 +0000851 editor->AddHistory(*input);
Steve Blocka7e24c12009-10-30 11:49:00 +0000852 ExecuteString(String::New(*input), name, true, true);
853 }
854 editor->Close();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000855#else
856 printf("V8 version %s [D8 light using shared library]\n", V8::GetVersion());
857 static const int kBufferSize = 256;
858 while (true) {
859 char buffer[kBufferSize];
860 printf("%s", Shell::kPrompt);
861 if (fgets(buffer, kBufferSize, stdin) == NULL) break;
862 ExecuteString(String::New(buffer), name, true, true);
863 }
864#endif // USING_V8_SHARED
Steve Blocka7e24c12009-10-30 11:49:00 +0000865 printf("\n");
866}
867
868
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000869#ifndef USING_V8_SHARED
Steve Blocka7e24c12009-10-30 11:49:00 +0000870class ShellThread : public i::Thread {
871 public:
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000872 ShellThread(int no, i::Vector<const char> files)
873 : Thread("d8:ShellThread"),
874 no_(no), files_(files) { }
Steve Blocka7e24c12009-10-30 11:49:00 +0000875 virtual void Run();
876 private:
877 int no_;
878 i::Vector<const char> files_;
879};
880
881
882void ShellThread::Run() {
Steve Blocka7e24c12009-10-30 11:49:00 +0000883 char* ptr = const_cast<char*>(files_.start());
884 while ((ptr != NULL) && (*ptr != '\0')) {
885 // For each newline-separated line.
886 char* next_line = ReadLine(ptr);
887
888 if (*ptr == '#') {
889 // Skip comment lines.
890 ptr = next_line;
891 continue;
892 }
893
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000894 // Prepare the context for this thread.
895 Locker locker;
896 HandleScope scope;
897 Persistent<Context> thread_context = Shell::CreateEvaluationContext();
Steve Blocka7e24c12009-10-30 11:49:00 +0000898 Context::Scope context_scope(thread_context);
899
900 while ((ptr != NULL) && (*ptr != '\0')) {
901 char* filename = ptr;
902 ptr = ReadWord(ptr);
903
904 // Skip empty strings.
905 if (strlen(filename) == 0) {
906 break;
907 }
908
909 Handle<String> str = Shell::ReadFile(filename);
910 if (str.IsEmpty()) {
911 printf("WARNING: %s not found\n", filename);
912 break;
913 }
914
915 Shell::ExecuteString(str, String::New(filename), false, false);
916 }
917
918 thread_context.Dispose();
919 ptr = next_line;
920 }
921}
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000922#endif // USING_V8_SHARED
Steve Blocka7e24c12009-10-30 11:49:00 +0000923
924
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000925void SourceGroup::ExitShell(int exit_code) {
926 // Use _exit instead of exit to avoid races between isolate
927 // threads and static destructors.
928 fflush(stdout);
929 fflush(stderr);
930 _exit(exit_code);
931}
Steve Blocka7e24c12009-10-30 11:49:00 +0000932
Steve Blocka7e24c12009-10-30 11:49:00 +0000933
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000934void SourceGroup::Execute() {
935 for (int i = begin_offset_; i < end_offset_; ++i) {
936 const char* arg = argv_[i];
937 if (strcmp(arg, "-e") == 0 && i + 1 < end_offset_) {
938 // Execute argument given to -e option directly.
939 HandleScope handle_scope;
940 Handle<String> file_name = String::New("unnamed");
941 Handle<String> source = String::New(argv_[i + 1]);
942 if (!Shell::ExecuteString(source, file_name, false, true)) {
943 ExitShell(1);
944 return;
945 }
946 ++i;
947 } else if (arg[0] == '-') {
948 // Ignore other options. They have been parsed already.
949 } else {
950 // Use all other arguments as names of files to load and run.
951 HandleScope handle_scope;
952 Handle<String> file_name = String::New(arg);
953 Handle<String> source = ReadFile(arg);
954 if (source.IsEmpty()) {
955 printf("Error reading '%s'\n", arg);
956 ExitShell(1);
957 return;
958 }
959 if (!Shell::ExecuteString(source, file_name, false, true)) {
960 ExitShell(1);
961 return;
Steve Blocka7e24c12009-10-30 11:49:00 +0000962 }
963 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000964 }
965}
Steve Blocka7e24c12009-10-30 11:49:00 +0000966
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000967
968Handle<String> SourceGroup::ReadFile(const char* name) {
969#ifndef USING_V8_SHARED
970 FILE* file = i::OS::FOpen(name, "rb");
971#else
972 // TODO(yangguo@chromium.org): reading from a directory hangs!
973 FILE* file = fopen(name, "rb");
974#endif // USING_V8_SHARED
975 if (file == NULL) return Handle<String>();
976
977 fseek(file, 0, SEEK_END);
978 int size = ftell(file);
979 rewind(file);
980
981 char* chars = new char[size + 1];
982 chars[size] = '\0';
983 for (int i = 0; i < size;) {
984 int read = fread(&chars[i], 1, size - i, file);
985 i += read;
986 }
987 fclose(file);
988 Handle<String> result = String::New(chars, size);
989 delete[] chars;
990 return result;
991}
992
993
994#ifndef USING_V8_SHARED
995i::Thread::Options SourceGroup::GetThreadOptions() {
996 i::Thread::Options options;
997 options.name = "IsolateThread";
998 // On some systems (OSX 10.6) the stack size default is 0.5Mb or less
999 // which is not enough to parse the big literal expressions used in tests.
1000 // The stack size should be at least StackGuard::kLimitSize + some
1001 // OS-specific padding for thread startup code.
1002 options.stack_size = 2 << 20; // 2 Mb seems to be enough
1003 return options;
1004}
1005
1006
1007void SourceGroup::ExecuteInThread() {
1008 Isolate* isolate = Isolate::New();
1009 do {
1010 if (next_semaphore_ != NULL) next_semaphore_->Wait();
1011 {
1012 Isolate::Scope iscope(isolate);
1013 Locker lock(isolate);
1014 HandleScope scope;
1015 Persistent<Context> context = Shell::CreateEvaluationContext();
1016 {
1017 Context::Scope cscope(context);
1018 Execute();
1019 }
1020 context.Dispose();
1021 }
1022 if (done_semaphore_ != NULL) done_semaphore_->Signal();
1023 } while (!Shell::options.last_run);
1024 isolate->Dispose();
1025}
1026
1027
1028void SourceGroup::StartExecuteInThread() {
1029 if (thread_ == NULL) {
1030 thread_ = new IsolateThread(this);
1031 thread_->Start();
1032 }
1033 next_semaphore_->Signal();
1034}
1035
1036
1037void SourceGroup::WaitForThread() {
1038 if (thread_ == NULL) return;
1039 if (Shell::options.last_run) {
1040 thread_->Join();
1041 thread_ = NULL;
1042 } else {
1043 done_semaphore_->Wait();
1044 }
1045}
1046#endif // USING_V8_SHARED
1047
1048
1049bool Shell::SetOptions(int argc, char* argv[]) {
1050 for (int i = 0; i < argc; i++) {
1051 if (strcmp(argv[i], "--stress-opt") == 0) {
1052 options.stress_opt = true;
1053 argv[i] = NULL;
1054 } else if (strcmp(argv[i], "--stress-deopt") == 0) {
1055 options.stress_deopt = true;
1056 argv[i] = NULL;
1057 } else if (strcmp(argv[i], "--noalways-opt") == 0) {
1058 // No support for stressing if we can't use --always-opt.
1059 options.stress_opt = false;
1060 options.stress_deopt = false;
1061 } else if (strcmp(argv[i], "--shell") == 0) {
1062 options.interactive_shell = true;
1063 argv[i] = NULL;
1064 } else if (strcmp(argv[i], "--test") == 0) {
1065 options.test_shell = true;
1066 argv[i] = NULL;
1067 } else if (strcmp(argv[i], "--preemption") == 0) {
1068#ifdef USING_V8_SHARED
1069 printf("D8 with shared library does not support multi-threading\n");
1070 return false;
1071#else
1072 options.use_preemption = true;
1073 argv[i] = NULL;
1074#endif // USING_V8_SHARED
1075 } else if (strcmp(argv[i], "--no-preemption") == 0) {
1076#ifdef USING_V8_SHARED
1077 printf("D8 with shared library does not support multi-threading\n");
1078 return false;
1079#else
1080 options.use_preemption = false;
1081 argv[i] = NULL;
1082#endif // USING_V8_SHARED
1083 } else if (strcmp(argv[i], "--preemption-interval") == 0) {
1084#ifdef USING_V8_SHARED
1085 printf("D8 with shared library does not support multi-threading\n");
1086 return false;
1087#else
1088 if (++i < argc) {
1089 argv[i-1] = NULL;
1090 char* end = NULL;
1091 options.preemption_interval = strtol(argv[i], &end, 10); // NOLINT
1092 if (options.preemption_interval <= 0
1093 || *end != '\0'
1094 || errno == ERANGE) {
1095 printf("Invalid value for --preemption-interval '%s'\n", argv[i]);
1096 return false;
1097 }
1098 argv[i] = NULL;
1099 } else {
1100 printf("Missing value for --preemption-interval\n");
1101 return false;
1102 }
1103#endif // USING_V8_SHARED
1104 } else if (strcmp(argv[i], "-f") == 0) {
1105 // Ignore any -f flags for compatibility with other stand-alone
1106 // JavaScript engines.
1107 continue;
1108 } else if (strcmp(argv[i], "--isolate") == 0) {
1109#ifdef USING_V8_SHARED
1110 printf("D8 with shared library does not support multi-threading\n");
1111 return false;
1112#endif // USING_V8_SHARED
1113 options.num_isolates++;
1114 }
1115#ifdef USING_V8_SHARED
1116 else if (strcmp(argv[i], "--dump-counters") == 0) {
1117 printf("D8 with shared library does not include counters\n");
1118 return false;
1119 } else if (strcmp(argv[i], "-p") == 0) {
1120 printf("D8 with shared library does not support multi-threading\n");
1121 return false;
1122 } else if (strcmp(argv[i], "--debugger") == 0) {
1123 printf("Javascript debugger not included\n");
1124 return false;
1125 }
1126#endif // USING_V8_SHARED
1127 }
1128
1129#ifndef USING_V8_SHARED
1130 // Run parallel threads if we are not using --isolate
1131 for (int i = 1; i < argc; i++) {
1132 if (argv[i] == NULL) continue;
1133 if (strcmp(argv[i], "-p") == 0 && i + 1 < argc) {
1134 if (options.num_isolates > 1) {
1135 printf("-p is not compatible with --isolate\n");
1136 return false;
1137 }
1138 argv[i] = NULL;
1139 if (options.parallel_files == NULL) {
1140 options.parallel_files = new i::List<i::Vector<const char> >();
1141 }
1142 int size = 0;
1143 const char* files = ReadChars(argv[++i], &size);
1144 if (files == NULL) {
1145 printf("-p option incomplete\n");
1146 return false;
1147 }
1148 argv[i] = NULL;
1149 options.parallel_files->Add(i::Vector<const char>(files, size));
1150 }
1151 }
1152#endif // USING_V8_SHARED
1153
1154 v8::V8::SetFlagsFromCommandLine(&argc, argv, true);
1155
1156 // set up isolated source groups
1157 options.isolate_sources = new SourceGroup[options.num_isolates];
1158 SourceGroup* current = options.isolate_sources;
1159 current->Begin(argv, 1);
1160 for (int i = 1; i < argc; i++) {
1161 const char* str = argv[i];
1162 if (strcmp(str, "--isolate") == 0) {
1163 current->End(i);
1164 current++;
1165 current->Begin(argv, i + 1);
1166 } else if (strncmp(argv[i], "--", 2) == 0) {
1167 printf("Warning: unknown flag %s.\nTry --help for options\n", argv[i]);
1168 }
1169 }
1170 current->End(argc);
1171
1172 return true;
1173}
1174
1175
1176int Shell::RunMain(int argc, char* argv[]) {
1177#ifndef USING_V8_SHARED
1178 i::List<i::Thread*> threads(1);
1179 if (options.parallel_files != NULL)
1180 for (int i = 0; i < options.parallel_files->length(); i++) {
1181 i::Vector<const char> files = options.parallel_files->at(i);
1182 ShellThread* thread = new ShellThread(threads.length(), files);
1183 thread->Start();
1184 threads.Add(thread);
1185 }
1186
1187 for (int i = 1; i < options.num_isolates; ++i) {
1188 options.isolate_sources[i].StartExecuteInThread();
1189 }
1190#endif // USING_V8_SHARED
1191 { // NOLINT
1192 Locker lock;
1193 HandleScope scope;
1194 Persistent<Context> context = CreateEvaluationContext();
1195 if (options.last_run) {
1196 // Keep using the same context in the interactive shell.
1197 evaluation_context_ = context;
1198#ifndef V8_SHARED
1199 // If the interactive debugger is enabled make sure to activate
1200 // it before running the files passed on the command line.
1201 if (i::FLAG_debugger) {
1202 InstallUtilityScript();
1203 }
1204#endif // V8_SHARED
1205 }
1206 {
1207 Context::Scope cscope(context);
1208 options.isolate_sources[0].Execute();
1209 }
1210 if (!options.last_run) {
1211 context.Dispose();
1212 }
1213
1214#ifndef USING_V8_SHARED
Steve Blocka7e24c12009-10-30 11:49:00 +00001215 // Start preemption if threads have been created and preemption is enabled.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001216 if (options.parallel_files != NULL
1217 && threads.length() > 0
1218 && options.use_preemption) {
1219 Locker::StartPreemption(options.preemption_interval);
1220 }
1221#endif // USING_V8_SHARED
1222 }
1223
1224#ifndef USING_V8_SHARED
1225 for (int i = 1; i < options.num_isolates; ++i) {
1226 options.isolate_sources[i].WaitForThread();
1227 }
1228
1229 if (options.parallel_files != NULL)
1230 for (int i = 0; i < threads.length(); i++) {
1231 i::Thread* thread = threads[i];
1232 thread->Join();
1233 delete thread;
Steve Blocka7e24c12009-10-30 11:49:00 +00001234 }
1235
Steve Blocka7e24c12009-10-30 11:49:00 +00001236 OnExit();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001237#endif // USING_V8_SHARED
Steve Blocka7e24c12009-10-30 11:49:00 +00001238 return 0;
1239}
1240
1241
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001242int Shell::Main(int argc, char* argv[]) {
1243 if (!SetOptions(argc, argv)) return 1;
1244 Initialize();
1245
1246 int result = 0;
1247 if (options.stress_opt || options.stress_deopt) {
1248 Testing::SetStressRunType(
1249 options.stress_opt ? Testing::kStressTypeOpt
1250 : Testing::kStressTypeDeopt);
1251 int stress_runs = Testing::GetStressRuns();
1252 for (int i = 0; i < stress_runs && result == 0; i++) {
1253 printf("============ Stress %d/%d ============\n", i + 1, stress_runs);
1254 Testing::PrepareStressRun(i);
1255 options.last_run = (i == stress_runs - 1);
1256 result = RunMain(argc, argv);
1257 }
1258 printf("======== Full Deoptimization =======\n");
1259 Testing::DeoptimizeAll();
1260 } else {
1261 result = RunMain(argc, argv);
1262 }
1263
1264
1265#if !defined(USING_V8_SHARED) && defined(ENABLE_DEBUGGER_SUPPORT)
1266 // Run remote debugger if requested, but never on --test
1267 if (i::FLAG_remote_debugger && !options.test_shell) {
1268 InstallUtilityScript();
1269 RunRemoteDebugger(i::FLAG_debugger_port);
1270 return 0;
1271 }
1272#endif // !USING_V8_SHARED && ENABLE_DEBUGGER_SUPPORT
1273
1274 // Run interactive shell if explicitly requested or if no script has been
1275 // executed, but never on --test
1276
1277 if (( options.interactive_shell
1278 || !options.script_executed )
1279 && !options.test_shell ) {
1280#ifndef USING_V8_SHARED
1281 if (!i::FLAG_debugger) {
1282 InstallUtilityScript();
1283 }
1284#endif // USING_V8_SHARED
1285 RunShell();
1286 }
1287
1288 V8::Dispose();
1289
1290 return result;
1291}
1292
Steve Blocka7e24c12009-10-30 11:49:00 +00001293} // namespace v8
1294
1295
Ben Murdoch257744e2011-11-30 15:57:28 +00001296#ifndef GOOGLE3
Steve Blocka7e24c12009-10-30 11:49:00 +00001297int main(int argc, char* argv[]) {
1298 return v8::Shell::Main(argc, argv);
1299}
Ben Murdoch257744e2011-11-30 15:57:28 +00001300#endif