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 #ifndef V8_DEOPTIMIZER_H_ 6 #define V8_DEOPTIMIZER_H_ 7 8 #include "src/v8.h" 9 10 #include "src/allocation.h" 11 #include "src/macro-assembler.h" 12 #include "src/zone-inl.h" 13 14 15 namespace v8 { 16 namespace internal { 17 18 19 static inline double read_double_value(Address p) { 20 double d; 21 memcpy(&d, p, sizeof(d)); 22 return d; 23 } 24 25 26 class FrameDescription; 27 class TranslationIterator; 28 class DeoptimizedFrameInfo; 29 30 template<typename T> 31 class HeapNumberMaterializationDescriptor BASE_EMBEDDED { 32 public: 33 HeapNumberMaterializationDescriptor(T destination, double value) 34 : destination_(destination), value_(value) { } 35 36 T destination() const { return destination_; } 37 double value() const { return value_; } 38 39 private: 40 T destination_; 41 double value_; 42 }; 43 44 45 class ObjectMaterializationDescriptor BASE_EMBEDDED { 46 public: 47 ObjectMaterializationDescriptor( 48 Address slot_address, int frame, int length, int duplicate, bool is_args) 49 : slot_address_(slot_address), 50 jsframe_index_(frame), 51 object_length_(length), 52 duplicate_object_(duplicate), 53 is_arguments_(is_args) { } 54 55 Address slot_address() const { return slot_address_; } 56 int jsframe_index() const { return jsframe_index_; } 57 int object_length() const { return object_length_; } 58 int duplicate_object() const { return duplicate_object_; } 59 bool is_arguments() const { return is_arguments_; } 60 61 // Only used for allocated receivers in DoComputeConstructStubFrame. 62 void patch_slot_address(intptr_t slot) { 63 slot_address_ = reinterpret_cast<Address>(slot); 64 } 65 66 private: 67 Address slot_address_; 68 int jsframe_index_; 69 int object_length_; 70 int duplicate_object_; 71 bool is_arguments_; 72 }; 73 74 75 class OptimizedFunctionVisitor BASE_EMBEDDED { 76 public: 77 virtual ~OptimizedFunctionVisitor() {} 78 79 // Function which is called before iteration of any optimized functions 80 // from given native context. 81 virtual void EnterContext(Context* context) = 0; 82 83 virtual void VisitFunction(JSFunction* function) = 0; 84 85 // Function which is called after iteration of all optimized functions 86 // from given native context. 87 virtual void LeaveContext(Context* context) = 0; 88 }; 89 90 91 class Deoptimizer : public Malloced { 92 public: 93 enum BailoutType { 94 EAGER, 95 LAZY, 96 SOFT, 97 // This last bailout type is not really a bailout, but used by the 98 // debugger to deoptimize stack frames to allow inspection. 99 DEBUGGER 100 }; 101 102 static const int kBailoutTypesWithCodeEntry = SOFT + 1; 103 104 struct Reason { 105 Reason(int r, const char* m, const char* d) 106 : raw_position(r), mnemonic(m), detail(d) {} 107 108 bool operator==(const Reason& other) const { 109 return raw_position == other.raw_position && 110 CStringEquals(mnemonic, other.mnemonic) && 111 CStringEquals(detail, other.detail); 112 } 113 114 bool operator!=(const Reason& other) const { return !(*this == other); } 115 116 int raw_position; 117 const char* mnemonic; 118 const char* detail; 119 }; 120 121 struct JumpTableEntry : public ZoneObject { 122 inline JumpTableEntry(Address entry, const Reason& the_reason, 123 Deoptimizer::BailoutType type, bool frame) 124 : label(), 125 address(entry), 126 reason(the_reason), 127 bailout_type(type), 128 needs_frame(frame) {} 129 130 bool IsEquivalentTo(const JumpTableEntry& other) const { 131 return address == other.address && bailout_type == other.bailout_type && 132 needs_frame == other.needs_frame && 133 (!FLAG_trace_deopt || reason == other.reason); 134 } 135 136 Label label; 137 Address address; 138 Reason reason; 139 Deoptimizer::BailoutType bailout_type; 140 bool needs_frame; 141 }; 142 143 static bool TraceEnabledFor(BailoutType deopt_type, 144 StackFrame::Type frame_type); 145 static const char* MessageFor(BailoutType type); 146 147 int output_count() const { return output_count_; } 148 149 Handle<JSFunction> function() const { return Handle<JSFunction>(function_); } 150 Handle<Code> compiled_code() const { return Handle<Code>(compiled_code_); } 151 BailoutType bailout_type() const { return bailout_type_; } 152 153 // Number of created JS frames. Not all created frames are necessarily JS. 154 int jsframe_count() const { return jsframe_count_; } 155 156 static Deoptimizer* New(JSFunction* function, 157 BailoutType type, 158 unsigned bailout_id, 159 Address from, 160 int fp_to_sp_delta, 161 Isolate* isolate); 162 static Deoptimizer* Grab(Isolate* isolate); 163 164 // The returned object with information on the optimized frame needs to be 165 // freed before another one can be generated. 166 static DeoptimizedFrameInfo* DebuggerInspectableFrame(JavaScriptFrame* frame, 167 int jsframe_index, 168 Isolate* isolate); 169 static void DeleteDebuggerInspectableFrame(DeoptimizedFrameInfo* info, 170 Isolate* isolate); 171 172 // Makes sure that there is enough room in the relocation 173 // information of a code object to perform lazy deoptimization 174 // patching. If there is not enough room a new relocation 175 // information object is allocated and comments are added until it 176 // is big enough. 177 static void EnsureRelocSpaceForLazyDeoptimization(Handle<Code> code); 178 179 // Deoptimize the function now. Its current optimized code will never be run 180 // again and any activations of the optimized code will get deoptimized when 181 // execution returns. 182 static void DeoptimizeFunction(JSFunction* function); 183 184 // Deoptimize all code in the given isolate. 185 static void DeoptimizeAll(Isolate* isolate); 186 187 // Deoptimize code associated with the given global object. 188 static void DeoptimizeGlobalObject(JSObject* object); 189 190 // Deoptimizes all optimized code that has been previously marked 191 // (via code->set_marked_for_deoptimization) and unlinks all functions that 192 // refer to that code. 193 static void DeoptimizeMarkedCode(Isolate* isolate); 194 195 // Visit all the known optimized functions in a given isolate. 196 static void VisitAllOptimizedFunctions( 197 Isolate* isolate, OptimizedFunctionVisitor* visitor); 198 199 // The size in bytes of the code required at a lazy deopt patch site. 200 static int patch_size(); 201 202 ~Deoptimizer(); 203 204 void MaterializeHeapObjects(JavaScriptFrameIterator* it); 205 206 void MaterializeHeapNumbersForDebuggerInspectableFrame( 207 Address parameters_top, 208 uint32_t parameters_size, 209 Address expressions_top, 210 uint32_t expressions_size, 211 DeoptimizedFrameInfo* info); 212 213 static void ComputeOutputFrames(Deoptimizer* deoptimizer); 214 215 216 enum GetEntryMode { 217 CALCULATE_ENTRY_ADDRESS, 218 ENSURE_ENTRY_CODE 219 }; 220 221 222 static Address GetDeoptimizationEntry( 223 Isolate* isolate, 224 int id, 225 BailoutType type, 226 GetEntryMode mode = ENSURE_ENTRY_CODE); 227 static int GetDeoptimizationId(Isolate* isolate, 228 Address addr, 229 BailoutType type); 230 static int GetOutputInfo(DeoptimizationOutputData* data, 231 BailoutId node_id, 232 SharedFunctionInfo* shared); 233 234 // Code generation support. 235 static int input_offset() { return OFFSET_OF(Deoptimizer, input_); } 236 static int output_count_offset() { 237 return OFFSET_OF(Deoptimizer, output_count_); 238 } 239 static int output_offset() { return OFFSET_OF(Deoptimizer, output_); } 240 241 static int has_alignment_padding_offset() { 242 return OFFSET_OF(Deoptimizer, has_alignment_padding_); 243 } 244 245 static int GetDeoptimizedCodeCount(Isolate* isolate); 246 247 static const int kNotDeoptimizationEntry = -1; 248 249 // Generators for the deoptimization entry code. 250 class EntryGenerator BASE_EMBEDDED { 251 public: 252 EntryGenerator(MacroAssembler* masm, BailoutType type) 253 : masm_(masm), type_(type) { } 254 virtual ~EntryGenerator() { } 255 256 void Generate(); 257 258 protected: 259 MacroAssembler* masm() const { return masm_; } 260 BailoutType type() const { return type_; } 261 Isolate* isolate() const { return masm_->isolate(); } 262 263 virtual void GeneratePrologue() { } 264 265 private: 266 MacroAssembler* masm_; 267 Deoptimizer::BailoutType type_; 268 }; 269 270 class TableEntryGenerator : public EntryGenerator { 271 public: 272 TableEntryGenerator(MacroAssembler* masm, BailoutType type, int count) 273 : EntryGenerator(masm, type), count_(count) { } 274 275 protected: 276 virtual void GeneratePrologue(); 277 278 private: 279 int count() const { return count_; } 280 281 int count_; 282 }; 283 284 int ConvertJSFrameIndexToFrameIndex(int jsframe_index); 285 286 static size_t GetMaxDeoptTableSize(); 287 288 static void EnsureCodeForDeoptimizationEntry(Isolate* isolate, 289 BailoutType type, 290 int max_entry_id); 291 292 Isolate* isolate() const { return isolate_; } 293 294 private: 295 static const int kMinNumberOfEntries = 64; 296 static const int kMaxNumberOfEntries = 16384; 297 298 Deoptimizer(Isolate* isolate, 299 JSFunction* function, 300 BailoutType type, 301 unsigned bailout_id, 302 Address from, 303 int fp_to_sp_delta, 304 Code* optimized_code); 305 Code* FindOptimizedCode(JSFunction* function, Code* optimized_code); 306 void PrintFunctionName(); 307 void DeleteFrameDescriptions(); 308 309 void DoComputeOutputFrames(); 310 void DoComputeJSFrame(TranslationIterator* iterator, int frame_index); 311 void DoComputeArgumentsAdaptorFrame(TranslationIterator* iterator, 312 int frame_index); 313 void DoComputeConstructStubFrame(TranslationIterator* iterator, 314 int frame_index); 315 void DoComputeAccessorStubFrame(TranslationIterator* iterator, 316 int frame_index, 317 bool is_setter_stub_frame); 318 void DoComputeCompiledStubFrame(TranslationIterator* iterator, 319 int frame_index); 320 321 // Translate object, store the result into an auxiliary array 322 // (deferred_objects_tagged_values_). 323 void DoTranslateObject(TranslationIterator* iterator, 324 int object_index, 325 int field_index); 326 327 // Translate value, store the result into the given frame slot. 328 void DoTranslateCommand(TranslationIterator* iterator, 329 int frame_index, 330 unsigned output_offset); 331 332 // Translate object, do not store the result anywhere (but do update 333 // the deferred materialization array). 334 void DoTranslateObjectAndSkip(TranslationIterator* iterator); 335 336 unsigned ComputeInputFrameSize() const; 337 unsigned ComputeFixedSize(JSFunction* function) const; 338 339 unsigned ComputeIncomingArgumentSize(JSFunction* function) const; 340 unsigned ComputeOutgoingArgumentSize() const; 341 342 Object* ComputeLiteral(int index) const; 343 344 void AddObjectStart(intptr_t slot_address, int argc, bool is_arguments); 345 void AddObjectDuplication(intptr_t slot, int object_index); 346 void AddObjectTaggedValue(intptr_t value); 347 void AddObjectDoubleValue(double value); 348 void AddDoubleValue(intptr_t slot_address, double value); 349 350 bool ArgumentsObjectIsAdapted(int object_index) { 351 ObjectMaterializationDescriptor desc = deferred_objects_.at(object_index); 352 int reverse_jsframe_index = jsframe_count_ - desc.jsframe_index() - 1; 353 return jsframe_has_adapted_arguments_[reverse_jsframe_index]; 354 } 355 356 Handle<JSFunction> ArgumentsObjectFunction(int object_index) { 357 ObjectMaterializationDescriptor desc = deferred_objects_.at(object_index); 358 int reverse_jsframe_index = jsframe_count_ - desc.jsframe_index() - 1; 359 return jsframe_functions_[reverse_jsframe_index]; 360 } 361 362 // Helper function for heap object materialization. 363 Handle<Object> MaterializeNextHeapObject(); 364 Handle<Object> MaterializeNextValue(); 365 366 static void GenerateDeoptimizationEntries( 367 MacroAssembler* masm, int count, BailoutType type); 368 369 // Marks all the code in the given context for deoptimization. 370 static void MarkAllCodeForContext(Context* native_context); 371 372 // Visit all the known optimized functions in a given context. 373 static void VisitAllOptimizedFunctionsForContext( 374 Context* context, OptimizedFunctionVisitor* visitor); 375 376 // Deoptimizes all code marked in the given context. 377 static void DeoptimizeMarkedCodeForContext(Context* native_context); 378 379 // Patch the given code so that it will deoptimize itself. 380 static void PatchCodeForDeoptimization(Isolate* isolate, Code* code); 381 382 // Searches the list of known deoptimizing code for a Code object 383 // containing the given address (which is supposedly faster than 384 // searching all code objects). 385 Code* FindDeoptimizingCode(Address addr); 386 387 // Fill the input from from a JavaScript frame. This is used when 388 // the debugger needs to inspect an optimized frame. For normal 389 // deoptimizations the input frame is filled in generated code. 390 void FillInputFrame(Address tos, JavaScriptFrame* frame); 391 392 // Fill the given output frame's registers to contain the failure handler 393 // address and the number of parameters for a stub failure trampoline. 394 void SetPlatformCompiledStubRegisters(FrameDescription* output_frame, 395 CodeStubDescriptor* desc); 396 397 // Fill the given output frame's double registers with the original values 398 // from the input frame's double registers. 399 void CopyDoubleRegisters(FrameDescription* output_frame); 400 401 // Determines whether the input frame contains alignment padding by looking 402 // at the dynamic alignment state slot inside the frame. 403 bool HasAlignmentPadding(JSFunction* function); 404 405 Isolate* isolate_; 406 JSFunction* function_; 407 Code* compiled_code_; 408 unsigned bailout_id_; 409 BailoutType bailout_type_; 410 Address from_; 411 int fp_to_sp_delta_; 412 int has_alignment_padding_; 413 414 // Input frame description. 415 FrameDescription* input_; 416 // Number of output frames. 417 int output_count_; 418 // Number of output js frames. 419 int jsframe_count_; 420 // Array of output frame descriptions. 421 FrameDescription** output_; 422 423 // Deferred values to be materialized. 424 List<Object*> deferred_objects_tagged_values_; 425 List<HeapNumberMaterializationDescriptor<int> > 426 deferred_objects_double_values_; 427 List<ObjectMaterializationDescriptor> deferred_objects_; 428 List<HeapNumberMaterializationDescriptor<Address> > deferred_heap_numbers_; 429 430 // Key for lookup of previously materialized objects 431 Address stack_fp_; 432 Handle<FixedArray> previously_materialized_objects_; 433 int prev_materialized_count_; 434 435 // Output frame information. Only used during heap object materialization. 436 List<Handle<JSFunction> > jsframe_functions_; 437 List<bool> jsframe_has_adapted_arguments_; 438 439 // Materialized objects. Only used during heap object materialization. 440 List<Handle<Object> >* materialized_values_; 441 List<Handle<Object> >* materialized_objects_; 442 int materialization_value_index_; 443 int materialization_object_index_; 444 445 #ifdef DEBUG 446 DisallowHeapAllocation* disallow_heap_allocation_; 447 #endif // DEBUG 448 449 CodeTracer::Scope* trace_scope_; 450 451 static const int table_entry_size_; 452 453 friend class FrameDescription; 454 friend class DeoptimizedFrameInfo; 455 }; 456 457 458 class FrameDescription { 459 public: 460 FrameDescription(uint32_t frame_size, 461 JSFunction* function); 462 463 void* operator new(size_t size, uint32_t frame_size) { 464 // Subtracts kPointerSize, as the member frame_content_ already supplies 465 // the first element of the area to store the frame. 466 return malloc(size + frame_size - kPointerSize); 467 } 468 469 void operator delete(void* pointer, uint32_t frame_size) { 470 free(pointer); 471 } 472 473 void operator delete(void* description) { 474 free(description); 475 } 476 477 uint32_t GetFrameSize() const { 478 DCHECK(static_cast<uint32_t>(frame_size_) == frame_size_); 479 return static_cast<uint32_t>(frame_size_); 480 } 481 482 JSFunction* GetFunction() const { return function_; } 483 484 unsigned GetOffsetFromSlotIndex(int slot_index); 485 486 intptr_t GetFrameSlot(unsigned offset) { 487 return *GetFrameSlotPointer(offset); 488 } 489 490 double GetDoubleFrameSlot(unsigned offset) { 491 intptr_t* ptr = GetFrameSlotPointer(offset); 492 return read_double_value(reinterpret_cast<Address>(ptr)); 493 } 494 495 void SetFrameSlot(unsigned offset, intptr_t value) { 496 *GetFrameSlotPointer(offset) = value; 497 } 498 499 void SetCallerPc(unsigned offset, intptr_t value); 500 501 void SetCallerFp(unsigned offset, intptr_t value); 502 503 void SetCallerConstantPool(unsigned offset, intptr_t value); 504 505 intptr_t GetRegister(unsigned n) const { 506 #if DEBUG 507 // This convoluted DCHECK is needed to work around a gcc problem that 508 // improperly detects an array bounds overflow in optimized debug builds 509 // when using a plain DCHECK. 510 if (n >= arraysize(registers_)) { 511 DCHECK(false); 512 return 0; 513 } 514 #endif 515 return registers_[n]; 516 } 517 518 double GetDoubleRegister(unsigned n) const { 519 DCHECK(n < arraysize(double_registers_)); 520 return double_registers_[n]; 521 } 522 523 void SetRegister(unsigned n, intptr_t value) { 524 DCHECK(n < arraysize(registers_)); 525 registers_[n] = value; 526 } 527 528 void SetDoubleRegister(unsigned n, double value) { 529 DCHECK(n < arraysize(double_registers_)); 530 double_registers_[n] = value; 531 } 532 533 intptr_t GetTop() const { return top_; } 534 void SetTop(intptr_t top) { top_ = top; } 535 536 intptr_t GetPc() const { return pc_; } 537 void SetPc(intptr_t pc) { pc_ = pc; } 538 539 intptr_t GetFp() const { return fp_; } 540 void SetFp(intptr_t fp) { fp_ = fp; } 541 542 intptr_t GetContext() const { return context_; } 543 void SetContext(intptr_t context) { context_ = context; } 544 545 intptr_t GetConstantPool() const { return constant_pool_; } 546 void SetConstantPool(intptr_t constant_pool) { 547 constant_pool_ = constant_pool; 548 } 549 550 Smi* GetState() const { return state_; } 551 void SetState(Smi* state) { state_ = state; } 552 553 void SetContinuation(intptr_t pc) { continuation_ = pc; } 554 555 StackFrame::Type GetFrameType() const { return type_; } 556 void SetFrameType(StackFrame::Type type) { type_ = type; } 557 558 // Get the incoming arguments count. 559 int ComputeParametersCount(); 560 561 // Get a parameter value for an unoptimized frame. 562 Object* GetParameter(int index); 563 564 // Get the expression stack height for a unoptimized frame. 565 unsigned GetExpressionCount(); 566 567 // Get the expression stack value for an unoptimized frame. 568 Object* GetExpression(int index); 569 570 static int registers_offset() { 571 return OFFSET_OF(FrameDescription, registers_); 572 } 573 574 static int double_registers_offset() { 575 return OFFSET_OF(FrameDescription, double_registers_); 576 } 577 578 static int frame_size_offset() { 579 return OFFSET_OF(FrameDescription, frame_size_); 580 } 581 582 static int pc_offset() { 583 return OFFSET_OF(FrameDescription, pc_); 584 } 585 586 static int state_offset() { 587 return OFFSET_OF(FrameDescription, state_); 588 } 589 590 static int continuation_offset() { 591 return OFFSET_OF(FrameDescription, continuation_); 592 } 593 594 static int frame_content_offset() { 595 return OFFSET_OF(FrameDescription, frame_content_); 596 } 597 598 private: 599 static const uint32_t kZapUint32 = 0xbeeddead; 600 601 // Frame_size_ must hold a uint32_t value. It is only a uintptr_t to 602 // keep the variable-size array frame_content_ of type intptr_t at 603 // the end of the structure aligned. 604 uintptr_t frame_size_; // Number of bytes. 605 JSFunction* function_; 606 intptr_t registers_[Register::kNumRegisters]; 607 double double_registers_[DoubleRegister::kMaxNumRegisters]; 608 intptr_t top_; 609 intptr_t pc_; 610 intptr_t fp_; 611 intptr_t context_; 612 intptr_t constant_pool_; 613 StackFrame::Type type_; 614 Smi* state_; 615 616 // Continuation is the PC where the execution continues after 617 // deoptimizing. 618 intptr_t continuation_; 619 620 // This must be at the end of the object as the object is allocated larger 621 // than it's definition indicate to extend this array. 622 intptr_t frame_content_[1]; 623 624 intptr_t* GetFrameSlotPointer(unsigned offset) { 625 DCHECK(offset < frame_size_); 626 return reinterpret_cast<intptr_t*>( 627 reinterpret_cast<Address>(this) + frame_content_offset() + offset); 628 } 629 630 int ComputeFixedSize(); 631 }; 632 633 634 class DeoptimizerData { 635 public: 636 explicit DeoptimizerData(MemoryAllocator* allocator); 637 ~DeoptimizerData(); 638 639 void Iterate(ObjectVisitor* v); 640 641 private: 642 MemoryAllocator* allocator_; 643 int deopt_entry_code_entries_[Deoptimizer::kBailoutTypesWithCodeEntry]; 644 MemoryChunk* deopt_entry_code_[Deoptimizer::kBailoutTypesWithCodeEntry]; 645 646 DeoptimizedFrameInfo* deoptimized_frame_info_; 647 648 Deoptimizer* current_; 649 650 friend class Deoptimizer; 651 652 DISALLOW_COPY_AND_ASSIGN(DeoptimizerData); 653 }; 654 655 656 class TranslationBuffer BASE_EMBEDDED { 657 public: 658 explicit TranslationBuffer(Zone* zone) : contents_(256, zone) { } 659 660 int CurrentIndex() const { return contents_.length(); } 661 void Add(int32_t value, Zone* zone); 662 663 Handle<ByteArray> CreateByteArray(Factory* factory); 664 665 private: 666 ZoneList<uint8_t> contents_; 667 }; 668 669 670 class TranslationIterator BASE_EMBEDDED { 671 public: 672 TranslationIterator(ByteArray* buffer, int index) 673 : buffer_(buffer), index_(index) { 674 DCHECK(index >= 0 && index < buffer->length()); 675 } 676 677 int32_t Next(); 678 679 bool HasNext() const { return index_ < buffer_->length(); } 680 681 void Skip(int n) { 682 for (int i = 0; i < n; i++) Next(); 683 } 684 685 private: 686 ByteArray* buffer_; 687 int index_; 688 }; 689 690 691 #define TRANSLATION_OPCODE_LIST(V) \ 692 V(BEGIN) \ 693 V(JS_FRAME) \ 694 V(CONSTRUCT_STUB_FRAME) \ 695 V(GETTER_STUB_FRAME) \ 696 V(SETTER_STUB_FRAME) \ 697 V(ARGUMENTS_ADAPTOR_FRAME) \ 698 V(COMPILED_STUB_FRAME) \ 699 V(DUPLICATED_OBJECT) \ 700 V(ARGUMENTS_OBJECT) \ 701 V(CAPTURED_OBJECT) \ 702 V(REGISTER) \ 703 V(INT32_REGISTER) \ 704 V(UINT32_REGISTER) \ 705 V(DOUBLE_REGISTER) \ 706 V(STACK_SLOT) \ 707 V(INT32_STACK_SLOT) \ 708 V(UINT32_STACK_SLOT) \ 709 V(DOUBLE_STACK_SLOT) \ 710 V(LITERAL) 711 712 713 class Translation BASE_EMBEDDED { 714 public: 715 #define DECLARE_TRANSLATION_OPCODE_ENUM(item) item, 716 enum Opcode { 717 TRANSLATION_OPCODE_LIST(DECLARE_TRANSLATION_OPCODE_ENUM) 718 LAST = LITERAL 719 }; 720 #undef DECLARE_TRANSLATION_OPCODE_ENUM 721 722 Translation(TranslationBuffer* buffer, int frame_count, int jsframe_count, 723 Zone* zone) 724 : buffer_(buffer), 725 index_(buffer->CurrentIndex()), 726 zone_(zone) { 727 buffer_->Add(BEGIN, zone); 728 buffer_->Add(frame_count, zone); 729 buffer_->Add(jsframe_count, zone); 730 } 731 732 int index() const { return index_; } 733 734 // Commands. 735 void BeginJSFrame(BailoutId node_id, int literal_id, unsigned height); 736 void BeginCompiledStubFrame(); 737 void BeginArgumentsAdaptorFrame(int literal_id, unsigned height); 738 void BeginConstructStubFrame(int literal_id, unsigned height); 739 void BeginGetterStubFrame(int literal_id); 740 void BeginSetterStubFrame(int literal_id); 741 void BeginArgumentsObject(int args_length); 742 void BeginCapturedObject(int length); 743 void DuplicateObject(int object_index); 744 void StoreRegister(Register reg); 745 void StoreInt32Register(Register reg); 746 void StoreUint32Register(Register reg); 747 void StoreDoubleRegister(DoubleRegister reg); 748 void StoreStackSlot(int index); 749 void StoreInt32StackSlot(int index); 750 void StoreUint32StackSlot(int index); 751 void StoreDoubleStackSlot(int index); 752 void StoreLiteral(int literal_id); 753 void StoreArgumentsObject(bool args_known, int args_index, int args_length); 754 755 Zone* zone() const { return zone_; } 756 757 static int NumberOfOperandsFor(Opcode opcode); 758 759 #if defined(OBJECT_PRINT) || defined(ENABLE_DISASSEMBLER) 760 static const char* StringFor(Opcode opcode); 761 #endif 762 763 // A literal id which refers to the JSFunction itself. 764 static const int kSelfLiteralId = -239; 765 766 private: 767 TranslationBuffer* buffer_; 768 int index_; 769 Zone* zone_; 770 }; 771 772 773 class SlotRef BASE_EMBEDDED { 774 public: 775 enum SlotRepresentation { 776 UNKNOWN, 777 TAGGED, 778 INT32, 779 UINT32, 780 DOUBLE, 781 LITERAL, 782 DEFERRED_OBJECT, // Object captured by the escape analysis. 783 // The number of nested objects can be obtained 784 // with the DeferredObjectLength() method 785 // (the SlotRefs of the nested objects follow 786 // this SlotRef in the depth-first order.) 787 DUPLICATE_OBJECT, // Duplicated object of a deferred object. 788 ARGUMENTS_OBJECT // Arguments object - only used to keep indexing 789 // in sync, it should not be materialized. 790 }; 791 792 SlotRef() 793 : addr_(NULL), representation_(UNKNOWN) { } 794 795 SlotRef(Address addr, SlotRepresentation representation) 796 : addr_(addr), representation_(representation) { } 797 798 SlotRef(Isolate* isolate, Object* literal) 799 : literal_(literal, isolate), representation_(LITERAL) { } 800 801 static SlotRef NewArgumentsObject(int length) { 802 SlotRef slot; 803 slot.representation_ = ARGUMENTS_OBJECT; 804 slot.deferred_object_length_ = length; 805 return slot; 806 } 807 808 static SlotRef NewDeferredObject(int length) { 809 SlotRef slot; 810 slot.representation_ = DEFERRED_OBJECT; 811 slot.deferred_object_length_ = length; 812 return slot; 813 } 814 815 SlotRepresentation Representation() { return representation_; } 816 817 static SlotRef NewDuplicateObject(int id) { 818 SlotRef slot; 819 slot.representation_ = DUPLICATE_OBJECT; 820 slot.duplicate_object_id_ = id; 821 return slot; 822 } 823 824 int GetChildrenCount() { 825 if (representation_ == DEFERRED_OBJECT || 826 representation_ == ARGUMENTS_OBJECT) { 827 return deferred_object_length_; 828 } else { 829 return 0; 830 } 831 } 832 833 int DuplicateObjectId() { return duplicate_object_id_; } 834 835 Handle<Object> GetValue(Isolate* isolate); 836 837 private: 838 Address addr_; 839 Handle<Object> literal_; 840 SlotRepresentation representation_; 841 int deferred_object_length_; 842 int duplicate_object_id_; 843 }; 844 845 class SlotRefValueBuilder BASE_EMBEDDED { 846 public: 847 SlotRefValueBuilder( 848 JavaScriptFrame* frame, 849 int inlined_frame_index, 850 int formal_parameter_count); 851 852 void Prepare(Isolate* isolate); 853 Handle<Object> GetNext(Isolate* isolate, int level); 854 void Finish(Isolate* isolate); 855 856 int args_length() { return args_length_; } 857 858 private: 859 List<Handle<Object> > materialized_objects_; 860 Handle<FixedArray> previously_materialized_objects_; 861 int prev_materialized_count_; 862 Address stack_frame_id_; 863 List<SlotRef> slot_refs_; 864 int current_slot_; 865 int args_length_; 866 int first_slot_index_; 867 868 static SlotRef ComputeSlotForNextArgument( 869 Translation::Opcode opcode, 870 TranslationIterator* iterator, 871 DeoptimizationInputData* data, 872 JavaScriptFrame* frame); 873 874 Handle<Object> GetPreviouslyMaterialized(Isolate* isolate, int length); 875 876 static Address SlotAddress(JavaScriptFrame* frame, int slot_index) { 877 if (slot_index >= 0) { 878 const int offset = JavaScriptFrameConstants::kLocal0Offset; 879 return frame->fp() + offset - (slot_index * kPointerSize); 880 } else { 881 const int offset = JavaScriptFrameConstants::kLastParameterOffset; 882 return frame->fp() + offset - ((slot_index + 1) * kPointerSize); 883 } 884 } 885 886 Handle<Object> GetDeferredObject(Isolate* isolate); 887 }; 888 889 class MaterializedObjectStore { 890 public: 891 explicit MaterializedObjectStore(Isolate* isolate) : isolate_(isolate) { 892 } 893 894 Handle<FixedArray> Get(Address fp); 895 void Set(Address fp, Handle<FixedArray> materialized_objects); 896 void Remove(Address fp); 897 898 private: 899 Isolate* isolate() { return isolate_; } 900 Handle<FixedArray> GetStackEntries(); 901 Handle<FixedArray> EnsureStackEntries(int size); 902 903 int StackIdToIndex(Address fp); 904 905 Isolate* isolate_; 906 List<Address> frame_fps_; 907 }; 908 909 910 // Class used to represent an unoptimized frame when the debugger 911 // needs to inspect a frame that is part of an optimized frame. The 912 // internally used FrameDescription objects are not GC safe so for use 913 // by the debugger frame information is copied to an object of this type. 914 // Represents parameters in unadapted form so their number might mismatch 915 // formal parameter count. 916 class DeoptimizedFrameInfo : public Malloced { 917 public: 918 DeoptimizedFrameInfo(Deoptimizer* deoptimizer, 919 int frame_index, 920 bool has_arguments_adaptor, 921 bool has_construct_stub); 922 virtual ~DeoptimizedFrameInfo(); 923 924 // GC support. 925 void Iterate(ObjectVisitor* v); 926 927 // Return the number of incoming arguments. 928 int parameters_count() { return parameters_count_; } 929 930 // Return the height of the expression stack. 931 int expression_count() { return expression_count_; } 932 933 // Get the frame function. 934 JSFunction* GetFunction() { 935 return function_; 936 } 937 938 // Get the frame context. 939 Object* GetContext() { return context_; } 940 941 // Check if this frame is preceded by construct stub frame. The bottom-most 942 // inlined frame might still be called by an uninlined construct stub. 943 bool HasConstructStub() { 944 return has_construct_stub_; 945 } 946 947 // Get an incoming argument. 948 Object* GetParameter(int index) { 949 DCHECK(0 <= index && index < parameters_count()); 950 return parameters_[index]; 951 } 952 953 // Get an expression from the expression stack. 954 Object* GetExpression(int index) { 955 DCHECK(0 <= index && index < expression_count()); 956 return expression_stack_[index]; 957 } 958 959 int GetSourcePosition() { 960 return source_position_; 961 } 962 963 private: 964 // Set an incoming argument. 965 void SetParameter(int index, Object* obj) { 966 DCHECK(0 <= index && index < parameters_count()); 967 parameters_[index] = obj; 968 } 969 970 // Set an expression on the expression stack. 971 void SetExpression(int index, Object* obj) { 972 DCHECK(0 <= index && index < expression_count()); 973 expression_stack_[index] = obj; 974 } 975 976 JSFunction* function_; 977 Object* context_; 978 bool has_construct_stub_; 979 int parameters_count_; 980 int expression_count_; 981 Object** parameters_; 982 Object** expression_stack_; 983 int source_position_; 984 985 friend class Deoptimizer; 986 }; 987 988 } } // namespace v8::internal 989 990 #endif // V8_DEOPTIMIZER_H_ 991