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