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