1// Copyright 2012 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#ifdef USING_V8_SHARED // Defined when linking against shared lib on Windows. 30#define V8_SHARED 31#endif 32 33#ifdef COMPRESS_STARTUP_DATA_BZ2 34#include <bzlib.h> 35#endif 36 37#include <errno.h> 38#include <stdlib.h> 39#include <string.h> 40#include <sys/stat.h> 41 42#ifdef V8_SHARED 43#include <assert.h> 44#include "../include/v8-testing.h" 45#endif // V8_SHARED 46 47#include "d8.h" 48 49#ifndef V8_SHARED 50#include "api.h" 51#include "checks.h" 52#include "d8-debug.h" 53#include "debug.h" 54#include "natives.h" 55#include "platform.h" 56#include "v8.h" 57#endif // V8_SHARED 58 59#if !defined(_WIN32) && !defined(_WIN64) 60#include <unistd.h> // NOLINT 61#endif 62 63#ifndef ASSERT 64#define ASSERT(condition) assert(condition) 65#endif 66 67namespace v8 { 68 69LineEditor *LineEditor::first_ = NULL; 70 71 72LineEditor::LineEditor(Type type, const char* name) 73 : type_(type), 74 name_(name), 75 next_(first_) { 76 first_ = this; 77} 78 79 80LineEditor* LineEditor::Get() { 81 LineEditor* current = first_; 82 LineEditor* best = current; 83 while (current != NULL) { 84 if (current->type_ > best->type_) 85 best = current; 86 current = current->next_; 87 } 88 return best; 89} 90 91 92class DumbLineEditor: public LineEditor { 93 public: 94 DumbLineEditor() : LineEditor(LineEditor::DUMB, "dumb") { } 95 virtual Handle<String> Prompt(const char* prompt); 96}; 97 98 99static DumbLineEditor dumb_line_editor; 100 101 102Handle<String> DumbLineEditor::Prompt(const char* prompt) { 103 printf("%s", prompt); 104 return Shell::ReadFromStdin(); 105} 106 107 108#ifndef V8_SHARED 109CounterMap* Shell::counter_map_; 110i::OS::MemoryMappedFile* Shell::counters_file_ = NULL; 111CounterCollection Shell::local_counters_; 112CounterCollection* Shell::counters_ = &local_counters_; 113i::Mutex* Shell::context_mutex_(i::OS::CreateMutex()); 114Persistent<Context> Shell::utility_context_; 115#endif // V8_SHARED 116 117LineEditor* Shell::console = NULL; 118Persistent<Context> Shell::evaluation_context_; 119ShellOptions Shell::options; 120const char* Shell::kPrompt = "d8> "; 121 122 123const int MB = 1024 * 1024; 124 125 126#ifndef V8_SHARED 127bool CounterMap::Match(void* key1, void* key2) { 128 const char* name1 = reinterpret_cast<const char*>(key1); 129 const char* name2 = reinterpret_cast<const char*>(key2); 130 return strcmp(name1, name2) == 0; 131} 132#endif // V8_SHARED 133 134 135// Converts a V8 value to a C string. 136const char* Shell::ToCString(const v8::String::Utf8Value& value) { 137 return *value ? *value : "<string conversion failed>"; 138} 139 140 141// Executes a string within the current v8 context. 142bool Shell::ExecuteString(Handle<String> source, 143 Handle<Value> name, 144 bool print_result, 145 bool report_exceptions) { 146#if !defined(V8_SHARED) && defined(ENABLE_DEBUGGER_SUPPORT) 147 bool FLAG_debugger = i::FLAG_debugger; 148#else 149 bool FLAG_debugger = false; 150#endif // !V8_SHARED && ENABLE_DEBUGGER_SUPPORT 151 HandleScope handle_scope; 152 TryCatch try_catch; 153 options.script_executed = true; 154 if (FLAG_debugger) { 155 // When debugging make exceptions appear to be uncaught. 156 try_catch.SetVerbose(true); 157 } 158 Handle<Script> script = Script::Compile(source, name); 159 if (script.IsEmpty()) { 160 // Print errors that happened during compilation. 161 if (report_exceptions && !FLAG_debugger) 162 ReportException(&try_catch); 163 return false; 164 } else { 165 Handle<Value> result = script->Run(); 166 if (result.IsEmpty()) { 167 ASSERT(try_catch.HasCaught()); 168 // Print errors that happened during execution. 169 if (report_exceptions && !FLAG_debugger) 170 ReportException(&try_catch); 171 return false; 172 } else { 173 ASSERT(!try_catch.HasCaught()); 174 if (print_result && !result->IsUndefined()) { 175 // If all went well and the result wasn't undefined then print 176 // the returned value. 177 v8::String::Utf8Value str(result); 178 size_t count = fwrite(*str, sizeof(**str), str.length(), stdout); 179 (void) count; // Silence GCC-4.5.x "unused result" warning. 180 printf("\n"); 181 } 182 return true; 183 } 184 } 185} 186 187 188Handle<Value> Shell::Print(const Arguments& args) { 189 Handle<Value> val = Write(args); 190 printf("\n"); 191 fflush(stdout); 192 return val; 193} 194 195 196Handle<Value> Shell::Write(const Arguments& args) { 197 for (int i = 0; i < args.Length(); i++) { 198 HandleScope handle_scope; 199 if (i != 0) { 200 printf(" "); 201 } 202 v8::String::Utf8Value str(args[i]); 203 int n = static_cast<int>(fwrite(*str, sizeof(**str), str.length(), stdout)); 204 if (n != str.length()) { 205 printf("Error in fwrite\n"); 206 Exit(1); 207 } 208 } 209 return Undefined(); 210} 211 212 213Handle<Value> Shell::EnableProfiler(const Arguments& args) { 214 V8::ResumeProfiler(); 215 return Undefined(); 216} 217 218 219Handle<Value> Shell::DisableProfiler(const Arguments& args) { 220 V8::PauseProfiler(); 221 return Undefined(); 222} 223 224 225Handle<Value> Shell::Read(const Arguments& args) { 226 String::Utf8Value file(args[0]); 227 if (*file == NULL) { 228 return ThrowException(String::New("Error loading file")); 229 } 230 Handle<String> source = ReadFile(*file); 231 if (source.IsEmpty()) { 232 return ThrowException(String::New("Error loading file")); 233 } 234 return source; 235} 236 237 238Handle<String> Shell::ReadFromStdin() { 239 static const int kBufferSize = 256; 240 char buffer[kBufferSize]; 241 Handle<String> accumulator = String::New(""); 242 int length; 243 while (true) { 244 // Continue reading if the line ends with an escape '\\' or the line has 245 // not been fully read into the buffer yet (does not end with '\n'). 246 // If fgets gets an error, just give up. 247 char* input = NULL; 248 { // Release lock for blocking input. 249 Unlocker unlock(Isolate::GetCurrent()); 250 input = fgets(buffer, kBufferSize, stdin); 251 } 252 if (input == NULL) return Handle<String>(); 253 length = static_cast<int>(strlen(buffer)); 254 if (length == 0) { 255 return accumulator; 256 } else if (buffer[length-1] != '\n') { 257 accumulator = String::Concat(accumulator, String::New(buffer, length)); 258 } else if (length > 1 && buffer[length-2] == '\\') { 259 buffer[length-2] = '\n'; 260 accumulator = String::Concat(accumulator, String::New(buffer, length-1)); 261 } else { 262 return String::Concat(accumulator, String::New(buffer, length-1)); 263 } 264 } 265} 266 267 268Handle<Value> Shell::Load(const Arguments& args) { 269 for (int i = 0; i < args.Length(); i++) { 270 HandleScope handle_scope; 271 String::Utf8Value file(args[i]); 272 if (*file == NULL) { 273 return ThrowException(String::New("Error loading file")); 274 } 275 Handle<String> source = ReadFile(*file); 276 if (source.IsEmpty()) { 277 return ThrowException(String::New("Error loading file")); 278 } 279 if (!ExecuteString(source, String::New(*file), false, true)) { 280 return ThrowException(String::New("Error executing file")); 281 } 282 } 283 return Undefined(); 284} 285 286static size_t convertToUint(Local<Value> value_in, TryCatch* try_catch) { 287 if (value_in->IsUint32()) { 288 return value_in->Uint32Value(); 289 } 290 291 Local<Value> number = value_in->ToNumber(); 292 if (try_catch->HasCaught()) return 0; 293 294 ASSERT(number->IsNumber()); 295 Local<Int32> int32 = number->ToInt32(); 296 if (try_catch->HasCaught() || int32.IsEmpty()) return 0; 297 298 int32_t raw_value = int32->Int32Value(); 299 if (try_catch->HasCaught()) return 0; 300 301 if (raw_value < 0) { 302 ThrowException(String::New("Array length must not be negative.")); 303 return 0; 304 } 305 306 static const int kMaxLength = 0x3fffffff; 307#ifndef V8_SHARED 308 ASSERT(kMaxLength == i::ExternalArray::kMaxLength); 309#endif // V8_SHARED 310 if (raw_value > static_cast<int32_t>(kMaxLength)) { 311 ThrowException( 312 String::New("Array length exceeds maximum length.")); 313 } 314 return static_cast<size_t>(raw_value); 315} 316 317 318const char kArrayBufferReferencePropName[] = "_is_array_buffer_"; 319const char kArrayBufferMarkerPropName[] = "_array_buffer_ref_"; 320 321 322Handle<Value> Shell::CreateExternalArray(const Arguments& args, 323 ExternalArrayType type, 324 size_t element_size) { 325 TryCatch try_catch; 326 bool is_array_buffer_construct = element_size == 0; 327 if (is_array_buffer_construct) { 328 type = v8::kExternalByteArray; 329 element_size = 1; 330 } 331 ASSERT(element_size == 1 || element_size == 2 || element_size == 4 || 332 element_size == 8); 333 if (args.Length() == 0) { 334 return ThrowException( 335 String::New("Array constructor must have at least one " 336 "parameter.")); 337 } 338 bool first_arg_is_array_buffer = 339 args[0]->IsObject() && 340 args[0]->ToObject()->Get( 341 String::New(kArrayBufferMarkerPropName))->IsTrue(); 342 // Currently, only the following constructors are supported: 343 // TypedArray(unsigned long length) 344 // TypedArray(ArrayBuffer buffer, 345 // optional unsigned long byteOffset, 346 // optional unsigned long length) 347 if (args.Length() > 3) { 348 return ThrowException( 349 String::New("Array constructor from ArrayBuffer must " 350 "have 1-3 parameters.")); 351 } 352 353 Local<Value> length_value = (args.Length() < 3) 354 ? (first_arg_is_array_buffer 355 ? args[0]->ToObject()->Get(String::New("length")) 356 : args[0]) 357 : args[2]; 358 size_t length = convertToUint(length_value, &try_catch); 359 if (try_catch.HasCaught()) return try_catch.Exception(); 360 361 void* data = NULL; 362 size_t offset = 0; 363 364 Handle<Object> array = Object::New(); 365 if (first_arg_is_array_buffer) { 366 Handle<Object> derived_from = args[0]->ToObject(); 367 data = derived_from->GetIndexedPropertiesExternalArrayData(); 368 369 size_t array_buffer_length = convertToUint( 370 derived_from->Get(String::New("length")), 371 &try_catch); 372 if (try_catch.HasCaught()) return try_catch.Exception(); 373 374 if (data == NULL && array_buffer_length != 0) { 375 return ThrowException( 376 String::New("ArrayBuffer doesn't have data")); 377 } 378 379 if (args.Length() > 1) { 380 offset = convertToUint(args[1], &try_catch); 381 if (try_catch.HasCaught()) return try_catch.Exception(); 382 383 // The given byteOffset must be a multiple of the element size of the 384 // specific type, otherwise an exception is raised. 385 if (offset % element_size != 0) { 386 return ThrowException( 387 String::New("offset must be multiple of element_size")); 388 } 389 } 390 391 if (offset > array_buffer_length) { 392 return ThrowException( 393 String::New("byteOffset must be less than ArrayBuffer length.")); 394 } 395 396 if (args.Length() == 2) { 397 // If length is not explicitly specified, the length of the ArrayBuffer 398 // minus the byteOffset must be a multiple of the element size of the 399 // specific type, or an exception is raised. 400 length = array_buffer_length - offset; 401 } 402 403 if (args.Length() != 3) { 404 if (length % element_size != 0) { 405 return ThrowException( 406 String::New("ArrayBuffer length minus the byteOffset must be a " 407 "multiple of the element size")); 408 } 409 length /= element_size; 410 } 411 412 // If a given byteOffset and length references an area beyond the end of 413 // the ArrayBuffer an exception is raised. 414 if (offset + (length * element_size) > array_buffer_length) { 415 return ThrowException( 416 String::New("length references an area beyond the end of the " 417 "ArrayBuffer")); 418 } 419 420 // Hold a reference to the ArrayBuffer so its buffer doesn't get collected. 421 array->Set(String::New(kArrayBufferReferencePropName), args[0], ReadOnly); 422 } 423 424 if (is_array_buffer_construct) { 425 array->Set(String::New(kArrayBufferMarkerPropName), True(), ReadOnly); 426 } 427 428 Persistent<Object> persistent_array = Persistent<Object>::New(array); 429 persistent_array.MakeWeak(data, ExternalArrayWeakCallback); 430 persistent_array.MarkIndependent(); 431 if (data == NULL && length != 0) { 432 data = calloc(length, element_size); 433 if (data == NULL) { 434 return ThrowException(String::New("Memory allocation failed.")); 435 } 436 } 437 438 array->SetIndexedPropertiesToExternalArrayData( 439 reinterpret_cast<uint8_t*>(data) + offset, type, 440 static_cast<int>(length)); 441 array->Set(String::New("length"), 442 Int32::New(static_cast<int32_t>(length)), ReadOnly); 443 array->Set(String::New("BYTES_PER_ELEMENT"), 444 Int32::New(static_cast<int32_t>(element_size))); 445 return array; 446} 447 448 449void Shell::ExternalArrayWeakCallback(Persistent<Value> object, void* data) { 450 HandleScope scope; 451 Handle<String> prop_name = String::New(kArrayBufferReferencePropName); 452 Handle<Object> converted_object = object->ToObject(); 453 Local<Value> prop_value = converted_object->Get(prop_name); 454 if (data != NULL && !prop_value->IsObject()) { 455 free(data); 456 } 457 object.Dispose(); 458} 459 460 461Handle<Value> Shell::ArrayBuffer(const Arguments& args) { 462 return CreateExternalArray(args, v8::kExternalByteArray, 0); 463} 464 465 466Handle<Value> Shell::Int8Array(const Arguments& args) { 467 return CreateExternalArray(args, v8::kExternalByteArray, sizeof(int8_t)); 468} 469 470 471Handle<Value> Shell::Uint8Array(const Arguments& args) { 472 return CreateExternalArray(args, kExternalUnsignedByteArray, sizeof(uint8_t)); 473} 474 475 476Handle<Value> Shell::Int16Array(const Arguments& args) { 477 return CreateExternalArray(args, kExternalShortArray, sizeof(int16_t)); 478} 479 480 481Handle<Value> Shell::Uint16Array(const Arguments& args) { 482 return CreateExternalArray(args, kExternalUnsignedShortArray, 483 sizeof(uint16_t)); 484} 485 486 487Handle<Value> Shell::Int32Array(const Arguments& args) { 488 return CreateExternalArray(args, kExternalIntArray, sizeof(int32_t)); 489} 490 491 492Handle<Value> Shell::Uint32Array(const Arguments& args) { 493 return CreateExternalArray(args, kExternalUnsignedIntArray, sizeof(uint32_t)); 494} 495 496 497Handle<Value> Shell::Float32Array(const Arguments& args) { 498 return CreateExternalArray(args, kExternalFloatArray, 499 sizeof(float)); // NOLINT 500} 501 502 503Handle<Value> Shell::Float64Array(const Arguments& args) { 504 return CreateExternalArray(args, kExternalDoubleArray, 505 sizeof(double)); // NOLINT 506} 507 508 509Handle<Value> Shell::PixelArray(const Arguments& args) { 510 return CreateExternalArray(args, kExternalPixelArray, sizeof(uint8_t)); 511} 512 513 514Handle<Value> Shell::Yield(const Arguments& args) { 515 v8::Unlocker unlocker; 516 return Undefined(); 517} 518 519 520Handle<Value> Shell::Quit(const Arguments& args) { 521 int exit_code = args[0]->Int32Value(); 522#ifndef V8_SHARED 523 OnExit(); 524#endif // V8_SHARED 525 exit(exit_code); 526 return Undefined(); 527} 528 529 530Handle<Value> Shell::Version(const Arguments& args) { 531 return String::New(V8::GetVersion()); 532} 533 534 535void Shell::ReportException(v8::TryCatch* try_catch) { 536 HandleScope handle_scope; 537#if !defined(V8_SHARED) && defined(ENABLE_DEBUGGER_SUPPORT) 538 bool enter_context = !Context::InContext(); 539 if (enter_context) utility_context_->Enter(); 540#endif // !V8_SHARED && ENABLE_DEBUGGER_SUPPORT 541 v8::String::Utf8Value exception(try_catch->Exception()); 542 const char* exception_string = ToCString(exception); 543 Handle<Message> message = try_catch->Message(); 544 if (message.IsEmpty()) { 545 // V8 didn't provide any extra information about this error; just 546 // print the exception. 547 printf("%s\n", exception_string); 548 } else { 549 // Print (filename):(line number): (message). 550 v8::String::Utf8Value filename(message->GetScriptResourceName()); 551 const char* filename_string = ToCString(filename); 552 int linenum = message->GetLineNumber(); 553 printf("%s:%i: %s\n", filename_string, linenum, exception_string); 554 // Print line of source code. 555 v8::String::Utf8Value sourceline(message->GetSourceLine()); 556 const char* sourceline_string = ToCString(sourceline); 557 printf("%s\n", sourceline_string); 558 // Print wavy underline (GetUnderline is deprecated). 559 int start = message->GetStartColumn(); 560 for (int i = 0; i < start; i++) { 561 printf(" "); 562 } 563 int end = message->GetEndColumn(); 564 for (int i = start; i < end; i++) { 565 printf("^"); 566 } 567 printf("\n"); 568 v8::String::Utf8Value stack_trace(try_catch->StackTrace()); 569 if (stack_trace.length() > 0) { 570 const char* stack_trace_string = ToCString(stack_trace); 571 printf("%s\n", stack_trace_string); 572 } 573 } 574 printf("\n"); 575#if !defined(V8_SHARED) && defined(ENABLE_DEBUGGER_SUPPORT) 576 if (enter_context) utility_context_->Exit(); 577#endif // !V8_SHARED && ENABLE_DEBUGGER_SUPPORT 578} 579 580 581#ifndef V8_SHARED 582Handle<Array> Shell::GetCompletions(Handle<String> text, Handle<String> full) { 583 HandleScope handle_scope; 584 Context::Scope context_scope(utility_context_); 585 Handle<Object> global = utility_context_->Global(); 586 Handle<Value> fun = global->Get(String::New("GetCompletions")); 587 static const int kArgc = 3; 588 Handle<Value> argv[kArgc] = { evaluation_context_->Global(), text, full }; 589 Handle<Value> val = Handle<Function>::Cast(fun)->Call(global, kArgc, argv); 590 return handle_scope.Close(Handle<Array>::Cast(val)); 591} 592 593 594#ifdef ENABLE_DEBUGGER_SUPPORT 595Handle<Object> Shell::DebugMessageDetails(Handle<String> message) { 596 Context::Scope context_scope(utility_context_); 597 Handle<Object> global = utility_context_->Global(); 598 Handle<Value> fun = global->Get(String::New("DebugMessageDetails")); 599 static const int kArgc = 1; 600 Handle<Value> argv[kArgc] = { message }; 601 Handle<Value> val = Handle<Function>::Cast(fun)->Call(global, kArgc, argv); 602 return Handle<Object>::Cast(val); 603} 604 605 606Handle<Value> Shell::DebugCommandToJSONRequest(Handle<String> command) { 607 Context::Scope context_scope(utility_context_); 608 Handle<Object> global = utility_context_->Global(); 609 Handle<Value> fun = global->Get(String::New("DebugCommandToJSONRequest")); 610 static const int kArgc = 1; 611 Handle<Value> argv[kArgc] = { command }; 612 Handle<Value> val = Handle<Function>::Cast(fun)->Call(global, kArgc, argv); 613 return val; 614} 615 616 617void Shell::DispatchDebugMessages() { 618 v8::Context::Scope scope(Shell::evaluation_context_); 619 v8::Debug::ProcessDebugMessages(); 620} 621#endif // ENABLE_DEBUGGER_SUPPORT 622#endif // V8_SHARED 623 624 625#ifndef V8_SHARED 626int32_t* Counter::Bind(const char* name, bool is_histogram) { 627 int i; 628 for (i = 0; i < kMaxNameSize - 1 && name[i]; i++) 629 name_[i] = static_cast<char>(name[i]); 630 name_[i] = '\0'; 631 is_histogram_ = is_histogram; 632 return ptr(); 633} 634 635 636void Counter::AddSample(int32_t sample) { 637 count_++; 638 sample_total_ += sample; 639} 640 641 642CounterCollection::CounterCollection() { 643 magic_number_ = 0xDEADFACE; 644 max_counters_ = kMaxCounters; 645 max_name_size_ = Counter::kMaxNameSize; 646 counters_in_use_ = 0; 647} 648 649 650Counter* CounterCollection::GetNextCounter() { 651 if (counters_in_use_ == kMaxCounters) return NULL; 652 return &counters_[counters_in_use_++]; 653} 654 655 656void Shell::MapCounters(const char* name) { 657 counters_file_ = i::OS::MemoryMappedFile::create( 658 name, sizeof(CounterCollection), &local_counters_); 659 void* memory = (counters_file_ == NULL) ? 660 NULL : counters_file_->memory(); 661 if (memory == NULL) { 662 printf("Could not map counters file %s\n", name); 663 Exit(1); 664 } 665 counters_ = static_cast<CounterCollection*>(memory); 666 V8::SetCounterFunction(LookupCounter); 667 V8::SetCreateHistogramFunction(CreateHistogram); 668 V8::SetAddHistogramSampleFunction(AddHistogramSample); 669} 670 671 672int CounterMap::Hash(const char* name) { 673 int h = 0; 674 int c; 675 while ((c = *name++) != 0) { 676 h += h << 5; 677 h += c; 678 } 679 return h; 680} 681 682 683Counter* Shell::GetCounter(const char* name, bool is_histogram) { 684 Counter* counter = counter_map_->Lookup(name); 685 686 if (counter == NULL) { 687 counter = counters_->GetNextCounter(); 688 if (counter != NULL) { 689 counter_map_->Set(name, counter); 690 counter->Bind(name, is_histogram); 691 } 692 } else { 693 ASSERT(counter->is_histogram() == is_histogram); 694 } 695 return counter; 696} 697 698 699int* Shell::LookupCounter(const char* name) { 700 Counter* counter = GetCounter(name, false); 701 702 if (counter != NULL) { 703 return counter->ptr(); 704 } else { 705 return NULL; 706 } 707} 708 709 710void* Shell::CreateHistogram(const char* name, 711 int min, 712 int max, 713 size_t buckets) { 714 return GetCounter(name, true); 715} 716 717 718void Shell::AddHistogramSample(void* histogram, int sample) { 719 Counter* counter = reinterpret_cast<Counter*>(histogram); 720 counter->AddSample(sample); 721} 722 723 724void Shell::InstallUtilityScript() { 725 Locker lock; 726 HandleScope scope; 727 // If we use the utility context, we have to set the security tokens so that 728 // utility, evaluation and debug context can all access each other. 729 utility_context_->SetSecurityToken(Undefined()); 730 evaluation_context_->SetSecurityToken(Undefined()); 731 Context::Scope utility_scope(utility_context_); 732 733#ifdef ENABLE_DEBUGGER_SUPPORT 734 if (i::FLAG_debugger) printf("JavaScript debugger enabled\n"); 735 // Install the debugger object in the utility scope 736 i::Debug* debug = i::Isolate::Current()->debug(); 737 debug->Load(); 738 i::Handle<i::JSObject> js_debug 739 = i::Handle<i::JSObject>(debug->debug_context()->global()); 740 utility_context_->Global()->Set(String::New("$debug"), 741 Utils::ToLocal(js_debug)); 742 debug->debug_context()->set_security_token(HEAP->undefined_value()); 743#endif // ENABLE_DEBUGGER_SUPPORT 744 745 // Run the d8 shell utility script in the utility context 746 int source_index = i::NativesCollection<i::D8>::GetIndex("d8"); 747 i::Vector<const char> shell_source = 748 i::NativesCollection<i::D8>::GetRawScriptSource(source_index); 749 i::Vector<const char> shell_source_name = 750 i::NativesCollection<i::D8>::GetScriptName(source_index); 751 Handle<String> source = String::New(shell_source.start(), 752 shell_source.length()); 753 Handle<String> name = String::New(shell_source_name.start(), 754 shell_source_name.length()); 755 Handle<Script> script = Script::Compile(source, name); 756 script->Run(); 757 // Mark the d8 shell script as native to avoid it showing up as normal source 758 // in the debugger. 759 i::Handle<i::Object> compiled_script = Utils::OpenHandle(*script); 760 i::Handle<i::Script> script_object = compiled_script->IsJSFunction() 761 ? i::Handle<i::Script>(i::Script::cast( 762 i::JSFunction::cast(*compiled_script)->shared()->script())) 763 : i::Handle<i::Script>(i::Script::cast( 764 i::SharedFunctionInfo::cast(*compiled_script)->script())); 765 script_object->set_type(i::Smi::FromInt(i::Script::TYPE_NATIVE)); 766 767#ifdef ENABLE_DEBUGGER_SUPPORT 768 // Start the in-process debugger if requested. 769 if (i::FLAG_debugger && !i::FLAG_debugger_agent) { 770 v8::Debug::SetDebugEventListener(HandleDebugEvent); 771 } 772#endif // ENABLE_DEBUGGER_SUPPORT 773} 774#endif // V8_SHARED 775 776 777#ifdef COMPRESS_STARTUP_DATA_BZ2 778class BZip2Decompressor : public v8::StartupDataDecompressor { 779 public: 780 virtual ~BZip2Decompressor() { } 781 782 protected: 783 virtual int DecompressData(char* raw_data, 784 int* raw_data_size, 785 const char* compressed_data, 786 int compressed_data_size) { 787 ASSERT_EQ(v8::StartupData::kBZip2, 788 v8::V8::GetCompressedStartupDataAlgorithm()); 789 unsigned int decompressed_size = *raw_data_size; 790 int result = 791 BZ2_bzBuffToBuffDecompress(raw_data, 792 &decompressed_size, 793 const_cast<char*>(compressed_data), 794 compressed_data_size, 795 0, 1); 796 if (result == BZ_OK) { 797 *raw_data_size = decompressed_size; 798 } 799 return result; 800 } 801}; 802#endif 803 804Handle<ObjectTemplate> Shell::CreateGlobalTemplate() { 805 Handle<ObjectTemplate> global_template = ObjectTemplate::New(); 806 global_template->Set(String::New("print"), FunctionTemplate::New(Print)); 807 global_template->Set(String::New("write"), FunctionTemplate::New(Write)); 808 global_template->Set(String::New("read"), FunctionTemplate::New(Read)); 809 global_template->Set(String::New("readbinary"), 810 FunctionTemplate::New(ReadBinary)); 811 global_template->Set(String::New("readline"), 812 FunctionTemplate::New(ReadLine)); 813 global_template->Set(String::New("load"), FunctionTemplate::New(Load)); 814 global_template->Set(String::New("quit"), FunctionTemplate::New(Quit)); 815 global_template->Set(String::New("version"), FunctionTemplate::New(Version)); 816 global_template->Set(String::New("enableProfiler"), 817 FunctionTemplate::New(EnableProfiler)); 818 global_template->Set(String::New("disableProfiler"), 819 FunctionTemplate::New(DisableProfiler)); 820 821 // Bind the handlers for external arrays. 822 global_template->Set(String::New("ArrayBuffer"), 823 FunctionTemplate::New(ArrayBuffer)); 824 global_template->Set(String::New("Int8Array"), 825 FunctionTemplate::New(Int8Array)); 826 global_template->Set(String::New("Uint8Array"), 827 FunctionTemplate::New(Uint8Array)); 828 global_template->Set(String::New("Int16Array"), 829 FunctionTemplate::New(Int16Array)); 830 global_template->Set(String::New("Uint16Array"), 831 FunctionTemplate::New(Uint16Array)); 832 global_template->Set(String::New("Int32Array"), 833 FunctionTemplate::New(Int32Array)); 834 global_template->Set(String::New("Uint32Array"), 835 FunctionTemplate::New(Uint32Array)); 836 global_template->Set(String::New("Float32Array"), 837 FunctionTemplate::New(Float32Array)); 838 global_template->Set(String::New("Float64Array"), 839 FunctionTemplate::New(Float64Array)); 840 global_template->Set(String::New("PixelArray"), 841 FunctionTemplate::New(PixelArray)); 842 843#ifdef LIVE_OBJECT_LIST 844 global_template->Set(String::New("lol_is_enabled"), True()); 845#else 846 global_template->Set(String::New("lol_is_enabled"), False()); 847#endif 848 849#if !defined(V8_SHARED) && !defined(_WIN32) && !defined(_WIN64) 850 Handle<ObjectTemplate> os_templ = ObjectTemplate::New(); 851 AddOSMethods(os_templ); 852 global_template->Set(String::New("os"), os_templ); 853#endif // V8_SHARED 854 855 return global_template; 856} 857 858 859void Shell::Initialize() { 860#ifdef COMPRESS_STARTUP_DATA_BZ2 861 BZip2Decompressor startup_data_decompressor; 862 int bz2_result = startup_data_decompressor.Decompress(); 863 if (bz2_result != BZ_OK) { 864 fprintf(stderr, "bzip error code: %d\n", bz2_result); 865 Exit(1); 866 } 867#endif 868 869#ifndef V8_SHARED 870 Shell::counter_map_ = new CounterMap(); 871 // Set up counters 872 if (i::StrLength(i::FLAG_map_counters) != 0) 873 MapCounters(i::FLAG_map_counters); 874 if (i::FLAG_dump_counters) { 875 V8::SetCounterFunction(LookupCounter); 876 V8::SetCreateHistogramFunction(CreateHistogram); 877 V8::SetAddHistogramSampleFunction(AddHistogramSample); 878 } 879#endif // V8_SHARED 880 if (options.test_shell) return; 881 882#ifndef V8_SHARED 883 Locker lock; 884 HandleScope scope; 885 Handle<ObjectTemplate> global_template = CreateGlobalTemplate(); 886 utility_context_ = Context::New(NULL, global_template); 887 888#ifdef ENABLE_DEBUGGER_SUPPORT 889 // Start the debugger agent if requested. 890 if (i::FLAG_debugger_agent) { 891 v8::Debug::EnableAgent("d8 shell", i::FLAG_debugger_port, true); 892 v8::Debug::SetDebugMessageDispatchHandler(DispatchDebugMessages, true); 893 } 894#endif // ENABLE_DEBUGGER_SUPPORT 895#endif // V8_SHARED 896} 897 898 899Persistent<Context> Shell::CreateEvaluationContext() { 900#ifndef V8_SHARED 901 // This needs to be a critical section since this is not thread-safe 902 i::ScopedLock lock(context_mutex_); 903#endif // V8_SHARED 904 // Initialize the global objects 905 Handle<ObjectTemplate> global_template = CreateGlobalTemplate(); 906 Persistent<Context> context = Context::New(NULL, global_template); 907 ASSERT(!context.IsEmpty()); 908 Context::Scope scope(context); 909 910#ifndef V8_SHARED 911 i::JSArguments js_args = i::FLAG_js_arguments; 912 i::Handle<i::FixedArray> arguments_array = 913 FACTORY->NewFixedArray(js_args.argc()); 914 for (int j = 0; j < js_args.argc(); j++) { 915 i::Handle<i::String> arg = 916 FACTORY->NewStringFromUtf8(i::CStrVector(js_args[j])); 917 arguments_array->set(j, *arg); 918 } 919 i::Handle<i::JSArray> arguments_jsarray = 920 FACTORY->NewJSArrayWithElements(arguments_array); 921 context->Global()->Set(String::New("arguments"), 922 Utils::ToLocal(arguments_jsarray)); 923#endif // V8_SHARED 924 return context; 925} 926 927 928void Shell::Exit(int exit_code) { 929 // Use _exit instead of exit to avoid races between isolate 930 // threads and static destructors. 931 fflush(stdout); 932 fflush(stderr); 933 _exit(exit_code); 934} 935 936 937#ifndef V8_SHARED 938struct CounterAndKey { 939 Counter* counter; 940 const char* key; 941}; 942 943 944int CompareKeys(const void* a, const void* b) { 945 return strcmp(static_cast<const CounterAndKey*>(a)->key, 946 static_cast<const CounterAndKey*>(b)->key); 947} 948 949 950void Shell::OnExit() { 951 if (console != NULL) console->Close(); 952 if (i::FLAG_dump_counters) { 953 int number_of_counters = 0; 954 for (CounterMap::Iterator i(counter_map_); i.More(); i.Next()) { 955 number_of_counters++; 956 } 957 CounterAndKey* counters = new CounterAndKey[number_of_counters]; 958 int j = 0; 959 for (CounterMap::Iterator i(counter_map_); i.More(); i.Next(), j++) { 960 counters[j].counter = i.CurrentValue(); 961 counters[j].key = i.CurrentKey(); 962 } 963 qsort(counters, number_of_counters, sizeof(counters[0]), CompareKeys); 964 printf("+--------------------------------------------+-------------+\n"); 965 printf("| Name | Value |\n"); 966 printf("+--------------------------------------------+-------------+\n"); 967 for (j = 0; j < number_of_counters; j++) { 968 Counter* counter = counters[j].counter; 969 const char* key = counters[j].key; 970 if (counter->is_histogram()) { 971 printf("| c:%-40s | %11i |\n", key, counter->count()); 972 printf("| t:%-40s | %11i |\n", key, counter->sample_total()); 973 } else { 974 printf("| %-42s | %11i |\n", key, counter->count()); 975 } 976 } 977 printf("+--------------------------------------------+-------------+\n"); 978 delete [] counters; 979 } 980 if (counters_file_ != NULL) 981 delete counters_file_; 982} 983#endif // V8_SHARED 984 985 986static FILE* FOpen(const char* path, const char* mode) { 987#if defined(_MSC_VER) && (defined(_WIN32) || defined(_WIN64)) 988 FILE* result; 989 if (fopen_s(&result, path, mode) == 0) { 990 return result; 991 } else { 992 return NULL; 993 } 994#else 995 FILE* file = fopen(path, mode); 996 if (file == NULL) return NULL; 997 struct stat file_stat; 998 if (fstat(fileno(file), &file_stat) != 0) return NULL; 999 bool is_regular_file = ((file_stat.st_mode & S_IFREG) != 0); 1000 if (is_regular_file) return file; 1001 fclose(file); 1002 return NULL; 1003#endif 1004} 1005 1006 1007static char* ReadChars(const char* name, int* size_out) { 1008 // Release the V8 lock while reading files. 1009 v8::Unlocker unlocker(Isolate::GetCurrent()); 1010 FILE* file = FOpen(name, "rb"); 1011 if (file == NULL) return NULL; 1012 1013 fseek(file, 0, SEEK_END); 1014 int size = ftell(file); 1015 rewind(file); 1016 1017 char* chars = new char[size + 1]; 1018 chars[size] = '\0'; 1019 for (int i = 0; i < size;) { 1020 int read = static_cast<int>(fread(&chars[i], 1, size - i, file)); 1021 i += read; 1022 } 1023 fclose(file); 1024 *size_out = size; 1025 return chars; 1026} 1027 1028 1029Handle<Value> Shell::ReadBinary(const Arguments& args) { 1030 String::Utf8Value filename(args[0]); 1031 int size; 1032 if (*filename == NULL) { 1033 return ThrowException(String::New("Error loading file")); 1034 } 1035 char* chars = ReadChars(*filename, &size); 1036 if (chars == NULL) { 1037 return ThrowException(String::New("Error reading file")); 1038 } 1039 // We skip checking the string for UTF8 characters and use it raw as 1040 // backing store for the external string with 8-bit characters. 1041 BinaryResource* resource = new BinaryResource(chars, size); 1042 return String::NewExternal(resource); 1043} 1044 1045 1046#ifndef V8_SHARED 1047static char* ReadToken(char* data, char token) { 1048 char* next = i::OS::StrChr(data, token); 1049 if (next != NULL) { 1050 *next = '\0'; 1051 return (next + 1); 1052 } 1053 1054 return NULL; 1055} 1056 1057 1058static char* ReadLine(char* data) { 1059 return ReadToken(data, '\n'); 1060} 1061 1062 1063static char* ReadWord(char* data) { 1064 return ReadToken(data, ' '); 1065} 1066#endif // V8_SHARED 1067 1068 1069// Reads a file into a v8 string. 1070Handle<String> Shell::ReadFile(const char* name) { 1071 int size = 0; 1072 char* chars = ReadChars(name, &size); 1073 if (chars == NULL) return Handle<String>(); 1074 Handle<String> result = String::New(chars); 1075 delete[] chars; 1076 return result; 1077} 1078 1079 1080void Shell::RunShell() { 1081 Locker locker; 1082 Context::Scope context_scope(evaluation_context_); 1083 HandleScope outer_scope; 1084 Handle<String> name = String::New("(d8)"); 1085 console = LineEditor::Get(); 1086 printf("V8 version %s [console: %s]\n", V8::GetVersion(), console->name()); 1087 console->Open(); 1088 while (true) { 1089 HandleScope inner_scope; 1090 Handle<String> input = console->Prompt(Shell::kPrompt); 1091 if (input.IsEmpty()) break; 1092 ExecuteString(input, name, true, true); 1093 } 1094 printf("\n"); 1095} 1096 1097 1098#ifndef V8_SHARED 1099class ShellThread : public i::Thread { 1100 public: 1101 // Takes ownership of the underlying char array of |files|. 1102 ShellThread(int no, char* files) 1103 : Thread("d8:ShellThread"), 1104 no_(no), files_(files) { } 1105 1106 ~ShellThread() { 1107 delete[] files_; 1108 } 1109 1110 virtual void Run(); 1111 private: 1112 int no_; 1113 char* files_; 1114}; 1115 1116 1117void ShellThread::Run() { 1118 char* ptr = files_; 1119 while ((ptr != NULL) && (*ptr != '\0')) { 1120 // For each newline-separated line. 1121 char* next_line = ReadLine(ptr); 1122 1123 if (*ptr == '#') { 1124 // Skip comment lines. 1125 ptr = next_line; 1126 continue; 1127 } 1128 1129 // Prepare the context for this thread. 1130 Locker locker; 1131 HandleScope outer_scope; 1132 Persistent<Context> thread_context = Shell::CreateEvaluationContext(); 1133 Context::Scope context_scope(thread_context); 1134 1135 while ((ptr != NULL) && (*ptr != '\0')) { 1136 HandleScope inner_scope; 1137 char* filename = ptr; 1138 ptr = ReadWord(ptr); 1139 1140 // Skip empty strings. 1141 if (strlen(filename) == 0) { 1142 continue; 1143 } 1144 1145 Handle<String> str = Shell::ReadFile(filename); 1146 if (str.IsEmpty()) { 1147 printf("File '%s' not found\n", filename); 1148 Shell::Exit(1); 1149 } 1150 1151 Shell::ExecuteString(str, String::New(filename), false, false); 1152 } 1153 1154 thread_context.Dispose(); 1155 ptr = next_line; 1156 } 1157} 1158#endif // V8_SHARED 1159 1160 1161SourceGroup::~SourceGroup() { 1162#ifndef V8_SHARED 1163 delete next_semaphore_; 1164 next_semaphore_ = NULL; 1165 delete done_semaphore_; 1166 done_semaphore_ = NULL; 1167 delete thread_; 1168 thread_ = NULL; 1169#endif // V8_SHARED 1170} 1171 1172 1173void SourceGroup::Execute() { 1174 for (int i = begin_offset_; i < end_offset_; ++i) { 1175 const char* arg = argv_[i]; 1176 if (strcmp(arg, "-e") == 0 && i + 1 < end_offset_) { 1177 // Execute argument given to -e option directly. 1178 HandleScope handle_scope; 1179 Handle<String> file_name = String::New("unnamed"); 1180 Handle<String> source = String::New(argv_[i + 1]); 1181 if (!Shell::ExecuteString(source, file_name, false, true)) { 1182 Shell::Exit(1); 1183 } 1184 ++i; 1185 } else if (arg[0] == '-') { 1186 // Ignore other options. They have been parsed already. 1187 } else { 1188 // Use all other arguments as names of files to load and run. 1189 HandleScope handle_scope; 1190 Handle<String> file_name = String::New(arg); 1191 Handle<String> source = ReadFile(arg); 1192 if (source.IsEmpty()) { 1193 printf("Error reading '%s'\n", arg); 1194 Shell::Exit(1); 1195 } 1196 if (!Shell::ExecuteString(source, file_name, false, true)) { 1197 Shell::Exit(1); 1198 } 1199 } 1200 } 1201} 1202 1203 1204Handle<String> SourceGroup::ReadFile(const char* name) { 1205 int size; 1206 const char* chars = ReadChars(name, &size); 1207 if (chars == NULL) return Handle<String>(); 1208 Handle<String> result = String::New(chars, size); 1209 delete[] chars; 1210 return result; 1211} 1212 1213 1214#ifndef V8_SHARED 1215i::Thread::Options SourceGroup::GetThreadOptions() { 1216 // On some systems (OSX 10.6) the stack size default is 0.5Mb or less 1217 // which is not enough to parse the big literal expressions used in tests. 1218 // The stack size should be at least StackGuard::kLimitSize + some 1219 // OS-specific padding for thread startup code. 2Mbytes seems to be enough. 1220 return i::Thread::Options("IsolateThread", 2 * MB); 1221} 1222 1223 1224void SourceGroup::ExecuteInThread() { 1225 Isolate* isolate = Isolate::New(); 1226 do { 1227 if (next_semaphore_ != NULL) next_semaphore_->Wait(); 1228 { 1229 Isolate::Scope iscope(isolate); 1230 Locker lock(isolate); 1231 HandleScope scope; 1232 Persistent<Context> context = Shell::CreateEvaluationContext(); 1233 { 1234 Context::Scope cscope(context); 1235 Execute(); 1236 } 1237 context.Dispose(); 1238 } 1239 if (done_semaphore_ != NULL) done_semaphore_->Signal(); 1240 } while (!Shell::options.last_run); 1241 isolate->Dispose(); 1242} 1243 1244 1245void SourceGroup::StartExecuteInThread() { 1246 if (thread_ == NULL) { 1247 thread_ = new IsolateThread(this); 1248 thread_->Start(); 1249 } 1250 next_semaphore_->Signal(); 1251} 1252 1253 1254void SourceGroup::WaitForThread() { 1255 if (thread_ == NULL) return; 1256 if (Shell::options.last_run) { 1257 thread_->Join(); 1258 } else { 1259 done_semaphore_->Wait(); 1260 } 1261} 1262#endif // V8_SHARED 1263 1264 1265bool Shell::SetOptions(int argc, char* argv[]) { 1266 for (int i = 0; i < argc; i++) { 1267 if (strcmp(argv[i], "--stress-opt") == 0) { 1268 options.stress_opt = true; 1269 argv[i] = NULL; 1270 } else if (strcmp(argv[i], "--stress-deopt") == 0) { 1271 options.stress_deopt = true; 1272 argv[i] = NULL; 1273 } else if (strcmp(argv[i], "--noalways-opt") == 0) { 1274 // No support for stressing if we can't use --always-opt. 1275 options.stress_opt = false; 1276 options.stress_deopt = false; 1277 } else if (strcmp(argv[i], "--shell") == 0) { 1278 options.interactive_shell = true; 1279 argv[i] = NULL; 1280 } else if (strcmp(argv[i], "--test") == 0) { 1281 options.test_shell = true; 1282 argv[i] = NULL; 1283 } else if (strcmp(argv[i], "--preemption") == 0) { 1284#ifdef V8_SHARED 1285 printf("D8 with shared library does not support multi-threading\n"); 1286 return false; 1287#else 1288 options.use_preemption = true; 1289 argv[i] = NULL; 1290#endif // V8_SHARED 1291 } else if (strcmp(argv[i], "--nopreemption") == 0) { 1292#ifdef V8_SHARED 1293 printf("D8 with shared library does not support multi-threading\n"); 1294 return false; 1295#else 1296 options.use_preemption = false; 1297 argv[i] = NULL; 1298#endif // V8_SHARED 1299 } else if (strcmp(argv[i], "--preemption-interval") == 0) { 1300#ifdef V8_SHARED 1301 printf("D8 with shared library does not support multi-threading\n"); 1302 return false; 1303#else 1304 if (++i < argc) { 1305 argv[i-1] = NULL; 1306 char* end = NULL; 1307 options.preemption_interval = strtol(argv[i], &end, 10); // NOLINT 1308 if (options.preemption_interval <= 0 1309 || *end != '\0' 1310 || errno == ERANGE) { 1311 printf("Invalid value for --preemption-interval '%s'\n", argv[i]); 1312 return false; 1313 } 1314 argv[i] = NULL; 1315 } else { 1316 printf("Missing value for --preemption-interval\n"); 1317 return false; 1318 } 1319#endif // V8_SHARED 1320 } else if (strcmp(argv[i], "-f") == 0) { 1321 // Ignore any -f flags for compatibility with other stand-alone 1322 // JavaScript engines. 1323 continue; 1324 } else if (strcmp(argv[i], "--isolate") == 0) { 1325#ifdef V8_SHARED 1326 printf("D8 with shared library does not support multi-threading\n"); 1327 return false; 1328#endif // V8_SHARED 1329 options.num_isolates++; 1330 } else if (strcmp(argv[i], "-p") == 0) { 1331#ifdef V8_SHARED 1332 printf("D8 with shared library does not support multi-threading\n"); 1333 return false; 1334#else 1335 options.num_parallel_files++; 1336#endif // V8_SHARED 1337 } 1338#ifdef V8_SHARED 1339 else if (strcmp(argv[i], "--dump-counters") == 0) { 1340 printf("D8 with shared library does not include counters\n"); 1341 return false; 1342 } else if (strcmp(argv[i], "--debugger") == 0) { 1343 printf("Javascript debugger not included\n"); 1344 return false; 1345 } 1346#endif // V8_SHARED 1347 } 1348 1349#ifndef V8_SHARED 1350 // Run parallel threads if we are not using --isolate 1351 options.parallel_files = new char*[options.num_parallel_files]; 1352 int parallel_files_set = 0; 1353 for (int i = 1; i < argc; i++) { 1354 if (argv[i] == NULL) continue; 1355 if (strcmp(argv[i], "-p") == 0 && i + 1 < argc) { 1356 if (options.num_isolates > 1) { 1357 printf("-p is not compatible with --isolate\n"); 1358 return false; 1359 } 1360 argv[i] = NULL; 1361 i++; 1362 options.parallel_files[parallel_files_set] = argv[i]; 1363 parallel_files_set++; 1364 argv[i] = NULL; 1365 } 1366 } 1367 if (parallel_files_set != options.num_parallel_files) { 1368 printf("-p requires a file containing a list of files as parameter\n"); 1369 return false; 1370 } 1371#endif // V8_SHARED 1372 1373 v8::V8::SetFlagsFromCommandLine(&argc, argv, true); 1374 1375 // Set up isolated source groups. 1376 options.isolate_sources = new SourceGroup[options.num_isolates]; 1377 SourceGroup* current = options.isolate_sources; 1378 current->Begin(argv, 1); 1379 for (int i = 1; i < argc; i++) { 1380 const char* str = argv[i]; 1381 if (strcmp(str, "--isolate") == 0) { 1382 current->End(i); 1383 current++; 1384 current->Begin(argv, i + 1); 1385 } else if (strncmp(argv[i], "--", 2) == 0) { 1386 printf("Warning: unknown flag %s.\nTry --help for options\n", argv[i]); 1387 } 1388 } 1389 current->End(argc); 1390 1391 return true; 1392} 1393 1394 1395int Shell::RunMain(int argc, char* argv[]) { 1396#ifndef V8_SHARED 1397 i::List<i::Thread*> threads(1); 1398 if (options.parallel_files != NULL) { 1399 for (int i = 0; i < options.num_parallel_files; i++) { 1400 char* files = NULL; 1401 { Locker lock(Isolate::GetCurrent()); 1402 int size = 0; 1403 files = ReadChars(options.parallel_files[i], &size); 1404 } 1405 if (files == NULL) { 1406 printf("File list '%s' not found\n", options.parallel_files[i]); 1407 Exit(1); 1408 } 1409 ShellThread* thread = new ShellThread(threads.length(), files); 1410 thread->Start(); 1411 threads.Add(thread); 1412 } 1413 } 1414 for (int i = 1; i < options.num_isolates; ++i) { 1415 options.isolate_sources[i].StartExecuteInThread(); 1416 } 1417#endif // V8_SHARED 1418 { // NOLINT 1419 Locker lock; 1420 HandleScope scope; 1421 Persistent<Context> context = CreateEvaluationContext(); 1422 if (options.last_run) { 1423 // Keep using the same context in the interactive shell. 1424 evaluation_context_ = context; 1425#if !defined(V8_SHARED) && defined(ENABLE_DEBUGGER_SUPPORT) 1426 // If the interactive debugger is enabled make sure to activate 1427 // it before running the files passed on the command line. 1428 if (i::FLAG_debugger) { 1429 InstallUtilityScript(); 1430 } 1431#endif // !V8_SHARED && ENABLE_DEBUGGER_SUPPORT 1432 } 1433 { 1434 Context::Scope cscope(context); 1435 options.isolate_sources[0].Execute(); 1436 } 1437 if (!options.last_run) { 1438 context.Dispose(); 1439#if !defined(V8_SHARED) 1440 if (i::FLAG_send_idle_notification) { 1441 const int kLongIdlePauseInMs = 1000; 1442 V8::ContextDisposedNotification(); 1443 V8::IdleNotification(kLongIdlePauseInMs); 1444 } 1445#endif // !V8_SHARED 1446 } 1447 1448#ifndef V8_SHARED 1449 // Start preemption if threads have been created and preemption is enabled. 1450 if (threads.length() > 0 1451 && options.use_preemption) { 1452 Locker::StartPreemption(options.preemption_interval); 1453 } 1454#endif // V8_SHARED 1455 } 1456 1457#ifndef V8_SHARED 1458 for (int i = 1; i < options.num_isolates; ++i) { 1459 options.isolate_sources[i].WaitForThread(); 1460 } 1461 1462 for (int i = 0; i < threads.length(); i++) { 1463 i::Thread* thread = threads[i]; 1464 thread->Join(); 1465 delete thread; 1466 } 1467 1468 if (threads.length() > 0 && options.use_preemption) { 1469 Locker lock; 1470 Locker::StopPreemption(); 1471 } 1472#endif // V8_SHARED 1473 return 0; 1474} 1475 1476 1477int Shell::Main(int argc, char* argv[]) { 1478 if (!SetOptions(argc, argv)) return 1; 1479 Initialize(); 1480 1481 int result = 0; 1482 if (options.stress_opt || options.stress_deopt) { 1483 Testing::SetStressRunType( 1484 options.stress_opt ? Testing::kStressTypeOpt 1485 : Testing::kStressTypeDeopt); 1486 int stress_runs = Testing::GetStressRuns(); 1487 for (int i = 0; i < stress_runs && result == 0; i++) { 1488 printf("============ Stress %d/%d ============\n", i + 1, stress_runs); 1489 Testing::PrepareStressRun(i); 1490 options.last_run = (i == stress_runs - 1); 1491 result = RunMain(argc, argv); 1492 } 1493 printf("======== Full Deoptimization =======\n"); 1494 Testing::DeoptimizeAll(); 1495#if !defined(V8_SHARED) 1496 } else if (i::FLAG_stress_runs > 0) { 1497 int stress_runs = i::FLAG_stress_runs; 1498 for (int i = 0; i < stress_runs && result == 0; i++) { 1499 printf("============ Run %d/%d ============\n", i + 1, stress_runs); 1500 options.last_run = (i == stress_runs - 1); 1501 result = RunMain(argc, argv); 1502 } 1503#endif 1504 } else { 1505 result = RunMain(argc, argv); 1506 } 1507 1508 1509#if !defined(V8_SHARED) && defined(ENABLE_DEBUGGER_SUPPORT) 1510 // Run remote debugger if requested, but never on --test 1511 if (i::FLAG_remote_debugger && !options.test_shell) { 1512 InstallUtilityScript(); 1513 RunRemoteDebugger(i::FLAG_debugger_port); 1514 return 0; 1515 } 1516#endif // !V8_SHARED && ENABLE_DEBUGGER_SUPPORT 1517 1518 // Run interactive shell if explicitly requested or if no script has been 1519 // executed, but never on --test 1520 1521 if (( options.interactive_shell 1522 || !options.script_executed ) 1523 && !options.test_shell ) { 1524#if !defined(V8_SHARED) && defined(ENABLE_DEBUGGER_SUPPORT) 1525 if (!i::FLAG_debugger) { 1526 InstallUtilityScript(); 1527 } 1528#endif // !V8_SHARED && ENABLE_DEBUGGER_SUPPORT 1529 RunShell(); 1530 } 1531 1532 V8::Dispose(); 1533 1534#ifndef V8_SHARED 1535 OnExit(); 1536#endif // V8_SHARED 1537 1538 return result; 1539} 1540 1541} // namespace v8 1542 1543 1544#ifndef GOOGLE3 1545int main(int argc, char* argv[]) { 1546 return v8::Shell::Main(argc, argv); 1547} 1548#endif 1549