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