d8.cc revision 9fac840a46e8b7e26894f4792ba26dde14c56b04
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 // 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 148Handle<Value> Shell::Print(const Arguments& args) { 149 Handle<Value> val = Write(args); 150 printf("\n"); 151 return val; 152} 153 154 155Handle<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 172Handle<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 185Handle<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 198Handle<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 217Handle<Value> Shell::Yield(const Arguments& args) { 218 v8::Unlocker unlocker; 219 return Undefined(); 220} 221 222 223Handle<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 231Handle<Value> Shell::Version(const Arguments& args) { 232 return String::New(V8::GetVersion()); 233} 234 235 236void 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 269Handle<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 282Handle<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 293Handle<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 305int32_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 315void Counter::AddSample(int32_t sample) { 316 count_++; 317 sample_total_ += sample; 318} 319 320 321CounterCollection::CounterCollection() { 322 magic_number_ = 0xDEADFACE; 323 max_counters_ = kMaxCounters; 324 max_name_size_ = Counter::kMaxNameSize; 325 counters_in_use_ = 0; 326} 327 328 329Counter* CounterCollection::GetNextCounter() { 330 if (counters_in_use_ == kMaxCounters) return NULL; 331 return &counters_[counters_in_use_++]; 332} 333 334 335void 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 351int 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 362Counter* 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 378int* 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 389void* Shell::CreateHistogram(const char* name, 390 int min, 391 int max, 392 size_t buckets) { 393 return GetCounter(name, true); 394} 395 396 397void Shell::AddHistogramSample(void* histogram, int sample) { 398 Counter* counter = reinterpret_cast<Counter*>(histogram); 399 counter->AddSample(sample); 400} 401 402 403void 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::Handle<i::JSObject> debug 451 = i::Handle<i::JSObject>(i::Debug::debug_context()->global()); 452 utility_context_->Global()->Set(String::New("$debug"), 453 Utils::ToLocal(debug)); 454#endif 455 456 // Run the d8 shell utility script in the utility context 457 int source_index = i::NativesCollection<i::D8>::GetIndex("d8"); 458 i::Vector<const char> shell_source 459 = i::NativesCollection<i::D8>::GetScriptSource(source_index); 460 i::Vector<const char> shell_source_name 461 = i::NativesCollection<i::D8>::GetScriptName(source_index); 462 Handle<String> source = String::New(shell_source.start(), 463 shell_source.length()); 464 Handle<String> name = String::New(shell_source_name.start(), 465 shell_source_name.length()); 466 Handle<Script> script = Script::Compile(source, name); 467 script->Run(); 468 469 // Mark the d8 shell script as native to avoid it showing up as normal source 470 // in the debugger. 471 i::Handle<i::Object> compiled_script = Utils::OpenHandle(*script); 472 i::Handle<i::Script> script_object = compiled_script->IsJSFunction() 473 ? i::Handle<i::Script>(i::Script::cast( 474 i::JSFunction::cast(*compiled_script)->shared()->script())) 475 : i::Handle<i::Script>(i::Script::cast( 476 i::SharedFunctionInfo::cast(*compiled_script)->script())); 477 script_object->set_type(i::Smi::FromInt(i::Script::TYPE_NATIVE)); 478 479 // Create the evaluation context 480 evaluation_context_ = Context::New(NULL, global_template); 481 evaluation_context_->SetSecurityToken(Undefined()); 482 483#ifdef ENABLE_DEBUGGER_SUPPORT 484 // Set the security token of the debug context to allow access. 485 i::Debug::debug_context()->set_security_token(i::Heap::undefined_value()); 486 487 // Start the debugger agent if requested. 488 if (i::FLAG_debugger_agent) { 489 v8::Debug::EnableAgent("d8 shell", i::FLAG_debugger_port, true); 490 } 491 492 // Start the in-process debugger if requested. 493 if (i::FLAG_debugger && !i::FLAG_debugger_agent) { 494 v8::Debug::SetDebugEventListener(HandleDebugEvent); 495 } 496#endif 497} 498 499 500void Shell::OnExit() { 501 if (i::FLAG_dump_counters) { 502 ::printf("+----------------------------------------+-------------+\n"); 503 ::printf("| Name | Value |\n"); 504 ::printf("+----------------------------------------+-------------+\n"); 505 for (CounterMap::Iterator i(counter_map_); i.More(); i.Next()) { 506 Counter* counter = i.CurrentValue(); 507 if (counter->is_histogram()) { 508 ::printf("| c:%-36s | %11i |\n", i.CurrentKey(), counter->count()); 509 ::printf("| t:%-36s | %11i |\n", 510 i.CurrentKey(), 511 counter->sample_total()); 512 } else { 513 ::printf("| %-38s | %11i |\n", i.CurrentKey(), counter->count()); 514 } 515 } 516 ::printf("+----------------------------------------+-------------+\n"); 517 } 518 if (counters_file_ != NULL) 519 delete counters_file_; 520} 521 522 523static char* ReadChars(const char* name, int* size_out) { 524 v8::Unlocker unlocker; // Release the V8 lock while reading files. 525 FILE* file = i::OS::FOpen(name, "rb"); 526 if (file == NULL) return NULL; 527 528 fseek(file, 0, SEEK_END); 529 int size = ftell(file); 530 rewind(file); 531 532 char* chars = new char[size + 1]; 533 chars[size] = '\0'; 534 for (int i = 0; i < size;) { 535 int read = fread(&chars[i], 1, size - i, file); 536 i += read; 537 } 538 fclose(file); 539 *size_out = size; 540 return chars; 541} 542 543 544static char* ReadToken(char* data, char token) { 545 char* next = i::OS::StrChr(data, token); 546 if (next != NULL) { 547 *next = '\0'; 548 return (next + 1); 549 } 550 551 return NULL; 552} 553 554 555static char* ReadLine(char* data) { 556 return ReadToken(data, '\n'); 557} 558 559 560static char* ReadWord(char* data) { 561 return ReadToken(data, ' '); 562} 563 564 565// Reads a file into a v8 string. 566Handle<String> Shell::ReadFile(const char* name) { 567 int size = 0; 568 char* chars = ReadChars(name, &size); 569 if (chars == NULL) return Handle<String>(); 570 Handle<String> result = String::New(chars); 571 delete[] chars; 572 return result; 573} 574 575 576void Shell::RunShell() { 577 LineEditor* editor = LineEditor::Get(); 578 printf("V8 version %s [console: %s]\n", V8::GetVersion(), editor->name()); 579 if (i::FLAG_debugger) { 580 printf("JavaScript debugger enabled\n"); 581 } 582 editor->Open(); 583 while (true) { 584 Locker locker; 585 HandleScope handle_scope; 586 Context::Scope context_scope(evaluation_context_); 587 i::SmartPointer<char> input = editor->Prompt(Shell::kPrompt); 588 if (input.is_empty()) 589 break; 590 editor->AddHistory(*input); 591 Handle<String> name = String::New("(d8)"); 592 ExecuteString(String::New(*input), name, true, true); 593 } 594 editor->Close(); 595 printf("\n"); 596} 597 598 599class ShellThread : public i::Thread { 600 public: 601 ShellThread(int no, i::Vector<const char> files) 602 : Thread("d8:ShellThread"), 603 no_(no), files_(files) { } 604 virtual void Run(); 605 private: 606 int no_; 607 i::Vector<const char> files_; 608}; 609 610 611void ShellThread::Run() { 612 // Prepare the context for this thread. 613 Locker locker; 614 HandleScope scope; 615 Handle<ObjectTemplate> global_template = ObjectTemplate::New(); 616 global_template->Set(String::New("print"), 617 FunctionTemplate::New(Shell::Print)); 618 global_template->Set(String::New("write"), 619 FunctionTemplate::New(Shell::Write)); 620 global_template->Set(String::New("read"), 621 FunctionTemplate::New(Shell::Read)); 622 global_template->Set(String::New("readline"), 623 FunctionTemplate::New(Shell::ReadLine)); 624 global_template->Set(String::New("load"), 625 FunctionTemplate::New(Shell::Load)); 626 global_template->Set(String::New("yield"), 627 FunctionTemplate::New(Shell::Yield)); 628 global_template->Set(String::New("version"), 629 FunctionTemplate::New(Shell::Version)); 630 631 char* ptr = const_cast<char*>(files_.start()); 632 while ((ptr != NULL) && (*ptr != '\0')) { 633 // For each newline-separated line. 634 char* next_line = ReadLine(ptr); 635 636 if (*ptr == '#') { 637 // Skip comment lines. 638 ptr = next_line; 639 continue; 640 } 641 642 Persistent<Context> thread_context = Context::New(NULL, global_template); 643 thread_context->SetSecurityToken(Undefined()); 644 Context::Scope context_scope(thread_context); 645 646 while ((ptr != NULL) && (*ptr != '\0')) { 647 char* filename = ptr; 648 ptr = ReadWord(ptr); 649 650 // Skip empty strings. 651 if (strlen(filename) == 0) { 652 break; 653 } 654 655 Handle<String> str = Shell::ReadFile(filename); 656 if (str.IsEmpty()) { 657 printf("WARNING: %s not found\n", filename); 658 break; 659 } 660 661 Shell::ExecuteString(str, String::New(filename), false, false); 662 } 663 664 thread_context.Dispose(); 665 ptr = next_line; 666 } 667} 668 669 670int Shell::Main(int argc, char* argv[]) { 671 i::FlagList::SetFlagsFromCommandLine(&argc, argv, true); 672 if (i::FLAG_help) { 673 return 1; 674 } 675 Initialize(); 676 bool run_shell = (argc == 1); 677 678 // Default use preemption if threads are created. 679 bool use_preemption = true; 680 681 // Default to use lowest possible thread preemption interval to test as many 682 // edgecases as possible. 683 int preemption_interval = 1; 684 685 i::List<i::Thread*> threads(1); 686 687 { 688 // Acquire the V8 lock once initialization has finished. Since the thread 689 // below may spawn new threads accessing V8 holding the V8 lock here is 690 // mandatory. 691 Locker locker; 692 Context::Scope context_scope(evaluation_context_); 693 for (int i = 1; i < argc; i++) { 694 char* str = argv[i]; 695 if (strcmp(str, "--shell") == 0) { 696 run_shell = true; 697 } else if (strcmp(str, "--preemption") == 0) { 698 use_preemption = true; 699 } else if (strcmp(str, "--no-preemption") == 0) { 700 use_preemption = false; 701 } else if (strcmp(str, "--preemption-interval") == 0) { 702 if (i + 1 < argc) { 703 char* end = NULL; 704 preemption_interval = strtol(argv[++i], &end, 10); // NOLINT 705 if (preemption_interval <= 0 || *end != '\0' || errno == ERANGE) { 706 printf("Invalid value for --preemption-interval '%s'\n", argv[i]); 707 return 1; 708 } 709 } else { 710 printf("Missing value for --preemption-interval\n"); 711 return 1; 712 } 713 } else if (strcmp(str, "-f") == 0) { 714 // Ignore any -f flags for compatibility with other stand-alone 715 // JavaScript engines. 716 continue; 717 } else if (strncmp(str, "--", 2) == 0) { 718 printf("Warning: unknown flag %s.\nTry --help for options\n", str); 719 } else if (strcmp(str, "-e") == 0 && i + 1 < argc) { 720 // Execute argument given to -e option directly. 721 v8::HandleScope handle_scope; 722 v8::Handle<v8::String> file_name = v8::String::New("unnamed"); 723 v8::Handle<v8::String> source = v8::String::New(argv[i + 1]); 724 if (!ExecuteString(source, file_name, false, true)) { 725 OnExit(); 726 return 1; 727 } 728 i++; 729 } else if (strcmp(str, "-p") == 0 && i + 1 < argc) { 730 int size = 0; 731 const char* files = ReadChars(argv[++i], &size); 732 if (files == NULL) return 1; 733 ShellThread* thread = 734 new ShellThread(threads.length(), 735 i::Vector<const char>(files, size)); 736 thread->Start(); 737 threads.Add(thread); 738 } else { 739 // Use all other arguments as names of files to load and run. 740 HandleScope handle_scope; 741 Handle<String> file_name = v8::String::New(str); 742 Handle<String> source = ReadFile(str); 743 if (source.IsEmpty()) { 744 printf("Error reading '%s'\n", str); 745 return 1; 746 } 747 if (!ExecuteString(source, file_name, false, true)) { 748 OnExit(); 749 return 1; 750 } 751 } 752 } 753 754 // Start preemption if threads have been created and preemption is enabled. 755 if (threads.length() > 0 && use_preemption) { 756 Locker::StartPreemption(preemption_interval); 757 } 758 759#ifdef ENABLE_DEBUGGER_SUPPORT 760 // Run the remote debugger if requested. 761 if (i::FLAG_remote_debugger) { 762 RunRemoteDebugger(i::FLAG_debugger_port); 763 return 0; 764 } 765#endif 766 } 767 if (run_shell) 768 RunShell(); 769 for (int i = 0; i < threads.length(); i++) { 770 i::Thread* thread = threads[i]; 771 thread->Join(); 772 delete thread; 773 } 774 OnExit(); 775 return 0; 776} 777 778 779} // namespace v8 780 781 782int main(int argc, char* argv[]) { 783 return v8::Shell::Main(argc, argv); 784} 785