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