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