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/allocation.h" 9 #include "src/deoptimize-reason.h" 10 #include "src/macro-assembler.h" 11 #include "src/source-position.h" 12 #include "src/zone/zone-chunk-list.h" 13 14 namespace v8 { 15 namespace internal { 16 17 class FrameDescription; 18 class TranslationIterator; 19 class DeoptimizedFrameInfo; 20 class TranslatedState; 21 class RegisterValues; 22 23 class TranslatedValue { 24 public: 25 // Allocation-less getter of the value. 26 // Returns heap()->arguments_marker() if allocation would be 27 // necessary to get the value. 28 Object* GetRawValue() const; 29 Handle<Object> GetValue(); 30 31 bool IsMaterializedObject() const; 32 bool IsMaterializableByDebugger() const; 33 34 private: 35 friend class TranslatedState; 36 friend class TranslatedFrame; 37 38 enum Kind { 39 kInvalid, 40 kTagged, 41 kInt32, 42 kUInt32, 43 kBoolBit, 44 kFloat, 45 kDouble, 46 kCapturedObject, // Object captured by the escape analysis. 47 // The number of nested objects can be obtained 48 // with the DeferredObjectLength() method 49 // (the values of the nested objects follow 50 // this value in the depth-first order.) 51 kDuplicatedObject, // Duplicated object of a deferred object. 52 kArgumentsObject // Arguments object - only used to keep indexing 53 // in sync, it should not be materialized. 54 }; 55 TranslatedValue(TranslatedState * container,Kind kind)56 TranslatedValue(TranslatedState* container, Kind kind) 57 : kind_(kind), container_(container) {} kind()58 Kind kind() const { return kind_; } 59 void Handlify(); 60 int GetChildrenCount() const; 61 62 static TranslatedValue NewArgumentsObject(TranslatedState* container, 63 int length, int object_index); 64 static TranslatedValue NewDeferredObject(TranslatedState* container, 65 int length, int object_index); 66 static TranslatedValue NewDuplicateObject(TranslatedState* container, int id); 67 static TranslatedValue NewFloat(TranslatedState* container, float value); 68 static TranslatedValue NewDouble(TranslatedState* container, double value); 69 static TranslatedValue NewInt32(TranslatedState* container, int32_t value); 70 static TranslatedValue NewUInt32(TranslatedState* container, uint32_t value); 71 static TranslatedValue NewBool(TranslatedState* container, uint32_t value); 72 static TranslatedValue NewTagged(TranslatedState* container, Object* literal); 73 static TranslatedValue NewInvalid(TranslatedState* container); 74 75 Isolate* isolate() const; 76 void MaterializeSimple(); 77 78 Kind kind_; 79 TranslatedState* container_; // This is only needed for materialization of 80 // objects and constructing handles (to get 81 // to the isolate). 82 83 MaybeHandle<Object> value_; // Before handlification, this is always null, 84 // after materialization it is never null, 85 // in between it is only null if the value needs 86 // to be materialized. 87 88 struct MaterializedObjectInfo { 89 int id_; 90 int length_; // Applies only to kArgumentsObject or kCapturedObject kinds. 91 }; 92 93 union { 94 // kind kTagged. After handlification it is always nullptr. 95 Object* raw_literal_; 96 // kind is kUInt32 or kBoolBit. 97 uint32_t uint32_value_; 98 // kind is kInt32. 99 int32_t int32_value_; 100 // kind is kFloat 101 float float_value_; 102 // kind is kDouble 103 double double_value_; 104 // kind is kDuplicatedObject or kArgumentsObject or kCapturedObject. 105 MaterializedObjectInfo materialization_info_; 106 }; 107 108 // Checked accessors for the union members. 109 Object* raw_literal() const; 110 int32_t int32_value() const; 111 uint32_t uint32_value() const; 112 float float_value() const; 113 double double_value() const; 114 int object_length() const; 115 int object_index() const; 116 }; 117 118 119 class TranslatedFrame { 120 public: 121 enum Kind { 122 kFunction, 123 kInterpretedFunction, 124 kGetter, 125 kSetter, 126 kTailCallerFunction, 127 kArgumentsAdaptor, 128 kConstructStub, 129 kCompiledStub, 130 kInvalid 131 }; 132 133 int GetValueCount(); 134 kind()135 Kind kind() const { return kind_; } node_id()136 BailoutId node_id() const { return node_id_; } shared_info()137 Handle<SharedFunctionInfo> shared_info() const { return shared_info_; } height()138 int height() const { return height_; } 139 raw_shared_info()140 SharedFunctionInfo* raw_shared_info() const { 141 CHECK_NOT_NULL(raw_shared_info_); 142 return raw_shared_info_; 143 } 144 145 class iterator { 146 public: 147 iterator& operator++() { 148 AdvanceIterator(&position_); 149 return *this; 150 } 151 152 iterator operator++(int) { 153 iterator original(position_); 154 AdvanceIterator(&position_); 155 return original; 156 } 157 158 bool operator==(const iterator& other) const { 159 return position_ == other.position_; 160 } 161 bool operator!=(const iterator& other) const { return !(*this == other); } 162 163 TranslatedValue& operator*() { return (*position_); } 164 TranslatedValue* operator->() { return &(*position_); } 165 166 private: 167 friend TranslatedFrame; 168 iterator(std::deque<TranslatedValue>::iterator position)169 explicit iterator(std::deque<TranslatedValue>::iterator position) 170 : position_(position) {} 171 172 std::deque<TranslatedValue>::iterator position_; 173 }; 174 175 typedef TranslatedValue& reference; 176 typedef TranslatedValue const& const_reference; 177 begin()178 iterator begin() { return iterator(values_.begin()); } end()179 iterator end() { return iterator(values_.end()); } 180 front()181 reference front() { return values_.front(); } front()182 const_reference front() const { return values_.front(); } 183 184 private: 185 friend class TranslatedState; 186 187 // Constructor static methods. 188 static TranslatedFrame JSFrame(BailoutId node_id, 189 SharedFunctionInfo* shared_info, int height); 190 static TranslatedFrame InterpretedFrame(BailoutId bytecode_offset, 191 SharedFunctionInfo* shared_info, 192 int height); 193 static TranslatedFrame AccessorFrame(Kind kind, 194 SharedFunctionInfo* shared_info); 195 static TranslatedFrame ArgumentsAdaptorFrame(SharedFunctionInfo* shared_info, 196 int height); 197 static TranslatedFrame TailCallerFrame(SharedFunctionInfo* shared_info); 198 static TranslatedFrame ConstructStubFrame(SharedFunctionInfo* shared_info, 199 int height); CompiledStubFrame(int height,Isolate * isolate)200 static TranslatedFrame CompiledStubFrame(int height, Isolate* isolate) { 201 return TranslatedFrame(kCompiledStub, isolate, nullptr, height); 202 } InvalidFrame()203 static TranslatedFrame InvalidFrame() { 204 return TranslatedFrame(kInvalid, nullptr); 205 } 206 207 static void AdvanceIterator(std::deque<TranslatedValue>::iterator* iter); 208 209 TranslatedFrame(Kind kind, Isolate* isolate, 210 SharedFunctionInfo* shared_info = nullptr, int height = 0) kind_(kind)211 : kind_(kind), 212 node_id_(BailoutId::None()), 213 raw_shared_info_(shared_info), 214 height_(height), 215 isolate_(isolate) {} 216 217 Add(const TranslatedValue & value)218 void Add(const TranslatedValue& value) { values_.push_back(value); } 219 void Handlify(); 220 221 Kind kind_; 222 BailoutId node_id_; 223 SharedFunctionInfo* raw_shared_info_; 224 Handle<SharedFunctionInfo> shared_info_; 225 int height_; 226 Isolate* isolate_; 227 228 typedef std::deque<TranslatedValue> ValuesContainer; 229 230 ValuesContainer values_; 231 }; 232 233 234 // Auxiliary class for translating deoptimization values. 235 // Typical usage sequence: 236 // 237 // 1. Construct the instance. This will involve reading out the translations 238 // and resolving them to values using the supplied frame pointer and 239 // machine state (registers). This phase is guaranteed not to allocate 240 // and not to use any HandleScope. Any object pointers will be stored raw. 241 // 242 // 2. Handlify pointers. This will convert all the raw pointers to handles. 243 // 244 // 3. Reading out the frame values. 245 // 246 // Note: After the instance is constructed, it is possible to iterate over 247 // the values eagerly. 248 249 class TranslatedState { 250 public: 251 TranslatedState(); 252 explicit TranslatedState(JavaScriptFrame* frame); 253 254 void Prepare(bool has_adapted_arguments, Address stack_frame_pointer); 255 256 // Store newly materialized values into the isolate. 257 void StoreMaterializedValuesAndDeopt(); 258 259 typedef std::vector<TranslatedFrame>::iterator iterator; begin()260 iterator begin() { return frames_.begin(); } end()261 iterator end() { return frames_.end(); } 262 263 typedef std::vector<TranslatedFrame>::const_iterator const_iterator; begin()264 const_iterator begin() const { return frames_.begin(); } end()265 const_iterator end() const { return frames_.end(); } 266 frames()267 std::vector<TranslatedFrame>& frames() { return frames_; } 268 269 TranslatedFrame* GetArgumentsInfoFromJSFrameIndex(int jsframe_index, 270 int* arguments_count); 271 isolate()272 Isolate* isolate() { return isolate_; } 273 274 void Init(Address input_frame_pointer, TranslationIterator* iterator, 275 FixedArray* literal_array, RegisterValues* registers, 276 FILE* trace_file); 277 278 private: 279 friend TranslatedValue; 280 281 TranslatedFrame CreateNextTranslatedFrame(TranslationIterator* iterator, 282 FixedArray* literal_array, 283 Address fp, 284 FILE* trace_file); 285 TranslatedValue CreateNextTranslatedValue(int frame_index, int value_index, 286 TranslationIterator* iterator, 287 FixedArray* literal_array, 288 Address fp, 289 RegisterValues* registers, 290 FILE* trace_file); 291 292 void UpdateFromPreviouslyMaterializedObjects(); 293 Handle<Object> MaterializeAt(int frame_index, int* value_index); 294 Handle<Object> MaterializeObjectAt(int object_index); 295 bool GetAdaptedArguments(Handle<JSObject>* result, int frame_index); 296 297 static uint32_t GetUInt32Slot(Address fp, int slot_index); 298 299 std::vector<TranslatedFrame> frames_; 300 Isolate* isolate_; 301 Address stack_frame_pointer_; 302 bool has_adapted_arguments_; 303 304 struct ObjectPosition { 305 int frame_index_; 306 int value_index_; 307 }; 308 std::deque<ObjectPosition> object_positions_; 309 }; 310 311 312 class OptimizedFunctionVisitor BASE_EMBEDDED { 313 public: ~OptimizedFunctionVisitor()314 virtual ~OptimizedFunctionVisitor() {} 315 316 // Function which is called before iteration of any optimized functions 317 // from given native context. 318 virtual void EnterContext(Context* context) = 0; 319 320 virtual void VisitFunction(JSFunction* function) = 0; 321 322 // Function which is called after iteration of all optimized functions 323 // from given native context. 324 virtual void LeaveContext(Context* context) = 0; 325 }; 326 327 class Deoptimizer : public Malloced { 328 public: 329 enum BailoutType { EAGER, LAZY, SOFT, kLastBailoutType = SOFT }; 330 331 enum class BailoutState { 332 NO_REGISTERS, 333 TOS_REGISTER, 334 }; 335 BailoutStateToString(BailoutState state)336 static const char* BailoutStateToString(BailoutState state) { 337 switch (state) { 338 case BailoutState::NO_REGISTERS: 339 return "NO_REGISTERS"; 340 case BailoutState::TOS_REGISTER: 341 return "TOS_REGISTER"; 342 } 343 UNREACHABLE(); 344 return nullptr; 345 } 346 347 struct DeoptInfo { DeoptInfoDeoptInfo348 DeoptInfo(SourcePosition position, DeoptimizeReason deopt_reason, 349 int deopt_id) 350 : position(position), deopt_reason(deopt_reason), deopt_id(deopt_id) {} 351 352 SourcePosition position; 353 DeoptimizeReason deopt_reason; 354 int deopt_id; 355 356 static const int kNoDeoptId = -1; 357 }; 358 359 static DeoptInfo GetDeoptInfo(Code* code, byte* from); 360 361 static int ComputeSourcePositionFromBaselineCode(SharedFunctionInfo* shared, 362 BailoutId node_id); 363 static int ComputeSourcePositionFromBytecodeArray(SharedFunctionInfo* shared, 364 BailoutId node_id); 365 366 struct JumpTableEntry : public ZoneObject { JumpTableEntryJumpTableEntry367 inline JumpTableEntry(Address entry, const DeoptInfo& deopt_info, 368 Deoptimizer::BailoutType type, bool frame) 369 : label(), 370 address(entry), 371 deopt_info(deopt_info), 372 bailout_type(type), 373 needs_frame(frame) {} 374 IsEquivalentToJumpTableEntry375 bool IsEquivalentTo(const JumpTableEntry& other) const { 376 return address == other.address && bailout_type == other.bailout_type && 377 needs_frame == other.needs_frame; 378 } 379 380 Label label; 381 Address address; 382 DeoptInfo deopt_info; 383 Deoptimizer::BailoutType bailout_type; 384 bool needs_frame; 385 }; 386 387 static bool TraceEnabledFor(StackFrame::Type frame_type); 388 static const char* MessageFor(BailoutType type); 389 output_count()390 int output_count() const { return output_count_; } 391 function()392 Handle<JSFunction> function() const { return Handle<JSFunction>(function_); } compiled_code()393 Handle<Code> compiled_code() const { return Handle<Code>(compiled_code_); } bailout_type()394 BailoutType bailout_type() const { return bailout_type_; } 395 396 // Number of created JS frames. Not all created frames are necessarily JS. jsframe_count()397 int jsframe_count() const { return jsframe_count_; } 398 399 static Deoptimizer* New(JSFunction* function, 400 BailoutType type, 401 unsigned bailout_id, 402 Address from, 403 int fp_to_sp_delta, 404 Isolate* isolate); 405 static Deoptimizer* Grab(Isolate* isolate); 406 407 // The returned object with information on the optimized frame needs to be 408 // freed before another one can be generated. 409 static DeoptimizedFrameInfo* DebuggerInspectableFrame(JavaScriptFrame* frame, 410 int jsframe_index, 411 Isolate* isolate); 412 413 // Makes sure that there is enough room in the relocation 414 // information of a code object to perform lazy deoptimization 415 // patching. If there is not enough room a new relocation 416 // information object is allocated and comments are added until it 417 // is big enough. 418 static void EnsureRelocSpaceForLazyDeoptimization(Handle<Code> code); 419 420 // Deoptimize the function now. Its current optimized code will never be run 421 // again and any activations of the optimized code will get deoptimized when 422 // execution returns. 423 static void DeoptimizeFunction(JSFunction* function); 424 425 // Deoptimize all code in the given isolate. 426 static void DeoptimizeAll(Isolate* isolate); 427 428 // Deoptimizes all optimized code that has been previously marked 429 // (via code->set_marked_for_deoptimization) and unlinks all functions that 430 // refer to that code. 431 static void DeoptimizeMarkedCode(Isolate* isolate); 432 433 // Visit all the known optimized functions in a given isolate. 434 static void VisitAllOptimizedFunctions( 435 Isolate* isolate, OptimizedFunctionVisitor* visitor); 436 437 // The size in bytes of the code required at a lazy deopt patch site. 438 static int patch_size(); 439 440 ~Deoptimizer(); 441 442 void MaterializeHeapObjects(JavaScriptFrameIterator* it); 443 444 static void ComputeOutputFrames(Deoptimizer* deoptimizer); 445 446 447 enum GetEntryMode { 448 CALCULATE_ENTRY_ADDRESS, 449 ENSURE_ENTRY_CODE 450 }; 451 452 453 static Address GetDeoptimizationEntry( 454 Isolate* isolate, 455 int id, 456 BailoutType type, 457 GetEntryMode mode = ENSURE_ENTRY_CODE); 458 static int GetDeoptimizationId(Isolate* isolate, 459 Address addr, 460 BailoutType type); 461 static int GetOutputInfo(DeoptimizationOutputData* data, 462 BailoutId node_id, 463 SharedFunctionInfo* shared); 464 465 // Code generation support. input_offset()466 static int input_offset() { return OFFSET_OF(Deoptimizer, input_); } output_count_offset()467 static int output_count_offset() { 468 return OFFSET_OF(Deoptimizer, output_count_); 469 } output_offset()470 static int output_offset() { return OFFSET_OF(Deoptimizer, output_); } 471 caller_frame_top_offset()472 static int caller_frame_top_offset() { 473 return OFFSET_OF(Deoptimizer, caller_frame_top_); 474 } 475 476 static int GetDeoptimizedCodeCount(Isolate* isolate); 477 478 static const int kNotDeoptimizationEntry = -1; 479 480 // Generators for the deoptimization entry code. 481 class TableEntryGenerator BASE_EMBEDDED { 482 public: TableEntryGenerator(MacroAssembler * masm,BailoutType type,int count)483 TableEntryGenerator(MacroAssembler* masm, BailoutType type, int count) 484 : masm_(masm), type_(type), count_(count) {} 485 486 void Generate(); 487 488 protected: masm()489 MacroAssembler* masm() const { return masm_; } type()490 BailoutType type() const { return type_; } isolate()491 Isolate* isolate() const { return masm_->isolate(); } 492 493 void GeneratePrologue(); 494 495 private: count()496 int count() const { return count_; } 497 498 MacroAssembler* masm_; 499 Deoptimizer::BailoutType type_; 500 int count_; 501 }; 502 503 static size_t GetMaxDeoptTableSize(); 504 505 static void EnsureCodeForDeoptimizationEntry(Isolate* isolate, 506 BailoutType type, 507 int max_entry_id); 508 isolate()509 Isolate* isolate() const { return isolate_; } 510 511 private: 512 static const int kMinNumberOfEntries = 64; 513 static const int kMaxNumberOfEntries = 16384; 514 515 Deoptimizer(Isolate* isolate, JSFunction* function, BailoutType type, 516 unsigned bailout_id, Address from, int fp_to_sp_delta); 517 Code* FindOptimizedCode(JSFunction* function); 518 void PrintFunctionName(); 519 void DeleteFrameDescriptions(); 520 521 void DoComputeOutputFrames(); 522 void DoComputeJSFrame(TranslatedFrame* translated_frame, int frame_index, 523 bool goto_catch_handler); 524 void DoComputeInterpretedFrame(TranslatedFrame* translated_frame, 525 int frame_index, bool goto_catch_handler); 526 void DoComputeArgumentsAdaptorFrame(TranslatedFrame* translated_frame, 527 int frame_index); 528 void DoComputeTailCallerFrame(TranslatedFrame* translated_frame, 529 int frame_index); 530 void DoComputeConstructStubFrame(TranslatedFrame* translated_frame, 531 int frame_index); 532 void DoComputeAccessorStubFrame(TranslatedFrame* translated_frame, 533 int frame_index, bool is_setter_stub_frame); 534 void DoComputeCompiledStubFrame(TranslatedFrame* translated_frame, 535 int frame_index); 536 537 void WriteTranslatedValueToOutput( 538 TranslatedFrame::iterator* iterator, int* input_index, int frame_index, 539 unsigned output_offset, const char* debug_hint_string = nullptr, 540 Address output_address_for_materialization = nullptr); 541 void WriteValueToOutput(Object* value, int input_index, int frame_index, 542 unsigned output_offset, 543 const char* debug_hint_string); 544 void DebugPrintOutputSlot(intptr_t value, int frame_index, 545 unsigned output_offset, 546 const char* debug_hint_string); 547 548 unsigned ComputeInputFrameAboveFpFixedSize() const; 549 unsigned ComputeInputFrameSize() const; 550 static unsigned ComputeJavascriptFixedSize(SharedFunctionInfo* shared); 551 static unsigned ComputeInterpretedFixedSize(SharedFunctionInfo* shared); 552 553 static unsigned ComputeIncomingArgumentSize(SharedFunctionInfo* shared); 554 static unsigned ComputeOutgoingArgumentSize(Code* code, unsigned bailout_id); 555 556 static void GenerateDeoptimizationEntries( 557 MacroAssembler* masm, int count, BailoutType type); 558 559 // Marks all the code in the given context for deoptimization. 560 static void MarkAllCodeForContext(Context* native_context); 561 562 // Visit all the known optimized functions in a given context. 563 static void VisitAllOptimizedFunctionsForContext( 564 Context* context, OptimizedFunctionVisitor* visitor); 565 566 // Deoptimizes all code marked in the given context. 567 static void DeoptimizeMarkedCodeForContext(Context* native_context); 568 569 // Patch the given code so that it will deoptimize itself. 570 static void PatchCodeForDeoptimization(Isolate* isolate, Code* code); 571 572 // Searches the list of known deoptimizing code for a Code object 573 // containing the given address (which is supposedly faster than 574 // searching all code objects). 575 Code* FindDeoptimizingCode(Address addr); 576 577 // Fill the given output frame's registers to contain the failure handler 578 // address and the number of parameters for a stub failure trampoline. 579 void SetPlatformCompiledStubRegisters(FrameDescription* output_frame, 580 CodeStubDescriptor* desc); 581 582 // Fill the given output frame's double registers with the original values 583 // from the input frame's double registers. 584 void CopyDoubleRegisters(FrameDescription* output_frame); 585 586 Isolate* isolate_; 587 JSFunction* function_; 588 Code* compiled_code_; 589 unsigned bailout_id_; 590 BailoutType bailout_type_; 591 Address from_; 592 int fp_to_sp_delta_; 593 bool deoptimizing_throw_; 594 int catch_handler_data_; 595 int catch_handler_pc_offset_; 596 597 // Input frame description. 598 FrameDescription* input_; 599 // Number of output frames. 600 int output_count_; 601 // Number of output js frames. 602 int jsframe_count_; 603 // Array of output frame descriptions. 604 FrameDescription** output_; 605 606 // Caller frame details computed from input frame. 607 intptr_t caller_frame_top_; 608 intptr_t caller_fp_; 609 intptr_t caller_pc_; 610 intptr_t caller_constant_pool_; 611 intptr_t input_frame_context_; 612 613 // Key for lookup of previously materialized objects 614 intptr_t stack_fp_; 615 616 TranslatedState translated_state_; 617 struct ValueToMaterialize { 618 Address output_slot_address_; 619 TranslatedFrame::iterator value_; 620 }; 621 std::vector<ValueToMaterialize> values_to_materialize_; 622 623 #ifdef DEBUG 624 DisallowHeapAllocation* disallow_heap_allocation_; 625 #endif // DEBUG 626 627 CodeTracer::Scope* trace_scope_; 628 629 static const int table_entry_size_; 630 631 friend class FrameDescription; 632 friend class DeoptimizedFrameInfo; 633 }; 634 635 636 class RegisterValues { 637 public: GetRegister(unsigned n)638 intptr_t GetRegister(unsigned n) const { 639 #if DEBUG 640 // This convoluted DCHECK is needed to work around a gcc problem that 641 // improperly detects an array bounds overflow in optimized debug builds 642 // when using a plain DCHECK. 643 if (n >= arraysize(registers_)) { 644 DCHECK(false); 645 return 0; 646 } 647 #endif 648 return registers_[n]; 649 } 650 GetFloatRegister(unsigned n)651 float GetFloatRegister(unsigned n) const { 652 DCHECK(n < arraysize(float_registers_)); 653 return float_registers_[n]; 654 } 655 GetDoubleRegister(unsigned n)656 double GetDoubleRegister(unsigned n) const { 657 DCHECK(n < arraysize(double_registers_)); 658 return double_registers_[n]; 659 } 660 SetRegister(unsigned n,intptr_t value)661 void SetRegister(unsigned n, intptr_t value) { 662 DCHECK(n < arraysize(registers_)); 663 registers_[n] = value; 664 } 665 SetFloatRegister(unsigned n,float value)666 void SetFloatRegister(unsigned n, float value) { 667 DCHECK(n < arraysize(float_registers_)); 668 float_registers_[n] = value; 669 } 670 SetDoubleRegister(unsigned n,double value)671 void SetDoubleRegister(unsigned n, double value) { 672 DCHECK(n < arraysize(double_registers_)); 673 double_registers_[n] = value; 674 } 675 676 intptr_t registers_[Register::kNumRegisters]; 677 float float_registers_[FloatRegister::kMaxNumRegisters]; 678 double double_registers_[DoubleRegister::kMaxNumRegisters]; 679 }; 680 681 682 class FrameDescription { 683 public: 684 explicit FrameDescription(uint32_t frame_size, int parameter_count = 0); 685 new(size_t size,uint32_t frame_size)686 void* operator new(size_t size, uint32_t frame_size) { 687 // Subtracts kPointerSize, as the member frame_content_ already supplies 688 // the first element of the area to store the frame. 689 return malloc(size + frame_size - kPointerSize); 690 } 691 delete(void * pointer,uint32_t frame_size)692 void operator delete(void* pointer, uint32_t frame_size) { 693 free(pointer); 694 } 695 delete(void * description)696 void operator delete(void* description) { 697 free(description); 698 } 699 GetFrameSize()700 uint32_t GetFrameSize() const { 701 DCHECK(static_cast<uint32_t>(frame_size_) == frame_size_); 702 return static_cast<uint32_t>(frame_size_); 703 } 704 GetFrameSlot(unsigned offset)705 intptr_t GetFrameSlot(unsigned offset) { 706 return *GetFrameSlotPointer(offset); 707 } 708 GetFramePointerAddress()709 Address GetFramePointerAddress() { 710 int fp_offset = GetFrameSize() - parameter_count() * kPointerSize - 711 StandardFrameConstants::kCallerSPOffset; 712 return reinterpret_cast<Address>(GetFrameSlotPointer(fp_offset)); 713 } 714 GetRegisterValues()715 RegisterValues* GetRegisterValues() { return ®ister_values_; } 716 SetFrameSlot(unsigned offset,intptr_t value)717 void SetFrameSlot(unsigned offset, intptr_t value) { 718 *GetFrameSlotPointer(offset) = value; 719 } 720 721 void SetCallerPc(unsigned offset, intptr_t value); 722 723 void SetCallerFp(unsigned offset, intptr_t value); 724 725 void SetCallerConstantPool(unsigned offset, intptr_t value); 726 GetRegister(unsigned n)727 intptr_t GetRegister(unsigned n) const { 728 return register_values_.GetRegister(n); 729 } 730 GetDoubleRegister(unsigned n)731 double GetDoubleRegister(unsigned n) const { 732 return register_values_.GetDoubleRegister(n); 733 } 734 SetRegister(unsigned n,intptr_t value)735 void SetRegister(unsigned n, intptr_t value) { 736 register_values_.SetRegister(n, value); 737 } 738 SetDoubleRegister(unsigned n,double value)739 void SetDoubleRegister(unsigned n, double value) { 740 register_values_.SetDoubleRegister(n, value); 741 } 742 GetTop()743 intptr_t GetTop() const { return top_; } SetTop(intptr_t top)744 void SetTop(intptr_t top) { top_ = top; } 745 GetPc()746 intptr_t GetPc() const { return pc_; } SetPc(intptr_t pc)747 void SetPc(intptr_t pc) { pc_ = pc; } 748 GetFp()749 intptr_t GetFp() const { return fp_; } SetFp(intptr_t fp)750 void SetFp(intptr_t fp) { fp_ = fp; } 751 GetContext()752 intptr_t GetContext() const { return context_; } SetContext(intptr_t context)753 void SetContext(intptr_t context) { context_ = context; } 754 GetConstantPool()755 intptr_t GetConstantPool() const { return constant_pool_; } SetConstantPool(intptr_t constant_pool)756 void SetConstantPool(intptr_t constant_pool) { 757 constant_pool_ = constant_pool; 758 } 759 GetState()760 Smi* GetState() const { return state_; } SetState(Smi * state)761 void SetState(Smi* state) { state_ = state; } 762 SetContinuation(intptr_t pc)763 void SetContinuation(intptr_t pc) { continuation_ = pc; } 764 GetFrameType()765 StackFrame::Type GetFrameType() const { return type_; } SetFrameType(StackFrame::Type type)766 void SetFrameType(StackFrame::Type type) { type_ = type; } 767 768 // Argument count, including receiver. parameter_count()769 int parameter_count() { return parameter_count_; } 770 registers_offset()771 static int registers_offset() { 772 return OFFSET_OF(FrameDescription, register_values_.registers_); 773 } 774 double_registers_offset()775 static int double_registers_offset() { 776 return OFFSET_OF(FrameDescription, register_values_.double_registers_); 777 } 778 frame_size_offset()779 static int frame_size_offset() { 780 return offsetof(FrameDescription, frame_size_); 781 } 782 pc_offset()783 static int pc_offset() { return offsetof(FrameDescription, pc_); } 784 state_offset()785 static int state_offset() { return offsetof(FrameDescription, state_); } 786 continuation_offset()787 static int continuation_offset() { 788 return offsetof(FrameDescription, continuation_); 789 } 790 frame_content_offset()791 static int frame_content_offset() { 792 return offsetof(FrameDescription, frame_content_); 793 } 794 795 private: 796 static const uint32_t kZapUint32 = 0xbeeddead; 797 798 // Frame_size_ must hold a uint32_t value. It is only a uintptr_t to 799 // keep the variable-size array frame_content_ of type intptr_t at 800 // the end of the structure aligned. 801 uintptr_t frame_size_; // Number of bytes. 802 int parameter_count_; 803 RegisterValues register_values_; 804 intptr_t top_; 805 intptr_t pc_; 806 intptr_t fp_; 807 intptr_t context_; 808 intptr_t constant_pool_; 809 StackFrame::Type type_; 810 Smi* state_; 811 812 // Continuation is the PC where the execution continues after 813 // deoptimizing. 814 intptr_t continuation_; 815 816 // This must be at the end of the object as the object is allocated larger 817 // than it's definition indicate to extend this array. 818 intptr_t frame_content_[1]; 819 GetFrameSlotPointer(unsigned offset)820 intptr_t* GetFrameSlotPointer(unsigned offset) { 821 DCHECK(offset < frame_size_); 822 return reinterpret_cast<intptr_t*>( 823 reinterpret_cast<Address>(this) + frame_content_offset() + offset); 824 } 825 }; 826 827 828 class DeoptimizerData { 829 public: 830 explicit DeoptimizerData(MemoryAllocator* allocator); 831 ~DeoptimizerData(); 832 833 private: 834 MemoryAllocator* allocator_; 835 int deopt_entry_code_entries_[Deoptimizer::kLastBailoutType + 1]; 836 MemoryChunk* deopt_entry_code_[Deoptimizer::kLastBailoutType + 1]; 837 838 Deoptimizer* current_; 839 840 friend class Deoptimizer; 841 842 DISALLOW_COPY_AND_ASSIGN(DeoptimizerData); 843 }; 844 845 846 class TranslationBuffer BASE_EMBEDDED { 847 public: TranslationBuffer(Zone * zone)848 explicit TranslationBuffer(Zone* zone) : contents_(zone) {} 849 CurrentIndex()850 int CurrentIndex() const { return static_cast<int>(contents_.size()); } 851 void Add(int32_t value); 852 853 Handle<ByteArray> CreateByteArray(Factory* factory); 854 855 private: 856 ZoneChunkList<uint8_t> contents_; 857 }; 858 859 860 class TranslationIterator BASE_EMBEDDED { 861 public: TranslationIterator(ByteArray * buffer,int index)862 TranslationIterator(ByteArray* buffer, int index) 863 : buffer_(buffer), index_(index) { 864 DCHECK(index >= 0 && index < buffer->length()); 865 } 866 867 int32_t Next(); 868 HasNext()869 bool HasNext() const { return index_ < buffer_->length(); } 870 Skip(int n)871 void Skip(int n) { 872 for (int i = 0; i < n; i++) Next(); 873 } 874 875 private: 876 ByteArray* buffer_; 877 int index_; 878 }; 879 880 #define TRANSLATION_OPCODE_LIST(V) \ 881 V(BEGIN) \ 882 V(JS_FRAME) \ 883 V(INTERPRETED_FRAME) \ 884 V(CONSTRUCT_STUB_FRAME) \ 885 V(GETTER_STUB_FRAME) \ 886 V(SETTER_STUB_FRAME) \ 887 V(ARGUMENTS_ADAPTOR_FRAME) \ 888 V(TAIL_CALLER_FRAME) \ 889 V(COMPILED_STUB_FRAME) \ 890 V(DUPLICATED_OBJECT) \ 891 V(ARGUMENTS_OBJECT) \ 892 V(CAPTURED_OBJECT) \ 893 V(REGISTER) \ 894 V(INT32_REGISTER) \ 895 V(UINT32_REGISTER) \ 896 V(BOOL_REGISTER) \ 897 V(FLOAT_REGISTER) \ 898 V(DOUBLE_REGISTER) \ 899 V(STACK_SLOT) \ 900 V(INT32_STACK_SLOT) \ 901 V(UINT32_STACK_SLOT) \ 902 V(BOOL_STACK_SLOT) \ 903 V(FLOAT_STACK_SLOT) \ 904 V(DOUBLE_STACK_SLOT) \ 905 V(LITERAL) 906 907 class Translation BASE_EMBEDDED { 908 public: 909 #define DECLARE_TRANSLATION_OPCODE_ENUM(item) item, 910 enum Opcode { 911 TRANSLATION_OPCODE_LIST(DECLARE_TRANSLATION_OPCODE_ENUM) 912 LAST = LITERAL 913 }; 914 #undef DECLARE_TRANSLATION_OPCODE_ENUM 915 Translation(TranslationBuffer * buffer,int frame_count,int jsframe_count,Zone * zone)916 Translation(TranslationBuffer* buffer, int frame_count, int jsframe_count, 917 Zone* zone) 918 : buffer_(buffer), 919 index_(buffer->CurrentIndex()), 920 zone_(zone) { 921 buffer_->Add(BEGIN); 922 buffer_->Add(frame_count); 923 buffer_->Add(jsframe_count); 924 } 925 index()926 int index() const { return index_; } 927 928 // Commands. 929 void BeginJSFrame(BailoutId node_id, int literal_id, unsigned height); 930 void BeginInterpretedFrame(BailoutId bytecode_offset, int literal_id, 931 unsigned height); 932 void BeginCompiledStubFrame(int height); 933 void BeginArgumentsAdaptorFrame(int literal_id, unsigned height); 934 void BeginTailCallerFrame(int literal_id); 935 void BeginConstructStubFrame(int literal_id, unsigned height); 936 void BeginGetterStubFrame(int literal_id); 937 void BeginSetterStubFrame(int literal_id); 938 void BeginArgumentsObject(int args_length); 939 void BeginCapturedObject(int length); 940 void DuplicateObject(int object_index); 941 void StoreRegister(Register reg); 942 void StoreInt32Register(Register reg); 943 void StoreUint32Register(Register reg); 944 void StoreBoolRegister(Register reg); 945 void StoreFloatRegister(FloatRegister reg); 946 void StoreDoubleRegister(DoubleRegister reg); 947 void StoreStackSlot(int index); 948 void StoreInt32StackSlot(int index); 949 void StoreUint32StackSlot(int index); 950 void StoreBoolStackSlot(int index); 951 void StoreFloatStackSlot(int index); 952 void StoreDoubleStackSlot(int index); 953 void StoreLiteral(int literal_id); 954 void StoreArgumentsObject(bool args_known, int args_index, int args_length); 955 void StoreJSFrameFunction(); 956 zone()957 Zone* zone() const { return zone_; } 958 959 static int NumberOfOperandsFor(Opcode opcode); 960 961 #if defined(OBJECT_PRINT) || defined(ENABLE_DISASSEMBLER) 962 static const char* StringFor(Opcode opcode); 963 #endif 964 965 private: 966 TranslationBuffer* buffer_; 967 int index_; 968 Zone* zone_; 969 }; 970 971 972 class MaterializedObjectStore { 973 public: MaterializedObjectStore(Isolate * isolate)974 explicit MaterializedObjectStore(Isolate* isolate) : isolate_(isolate) { 975 } 976 977 Handle<FixedArray> Get(Address fp); 978 void Set(Address fp, Handle<FixedArray> materialized_objects); 979 bool Remove(Address fp); 980 981 private: isolate()982 Isolate* isolate() { return isolate_; } 983 Handle<FixedArray> GetStackEntries(); 984 Handle<FixedArray> EnsureStackEntries(int size); 985 986 int StackIdToIndex(Address fp); 987 988 Isolate* isolate_; 989 List<Address> frame_fps_; 990 }; 991 992 993 // Class used to represent an unoptimized frame when the debugger 994 // needs to inspect a frame that is part of an optimized frame. The 995 // internally used FrameDescription objects are not GC safe so for use 996 // by the debugger frame information is copied to an object of this type. 997 // Represents parameters in unadapted form so their number might mismatch 998 // formal parameter count. 999 class DeoptimizedFrameInfo : public Malloced { 1000 public: 1001 DeoptimizedFrameInfo(TranslatedState* state, 1002 TranslatedState::iterator frame_it, Isolate* isolate); 1003 1004 // Return the number of incoming arguments. parameters_count()1005 int parameters_count() { return static_cast<int>(parameters_.size()); } 1006 1007 // Return the height of the expression stack. expression_count()1008 int expression_count() { return static_cast<int>(expression_stack_.size()); } 1009 1010 // Get the frame function. GetFunction()1011 Handle<JSFunction> GetFunction() { return function_; } 1012 1013 // Get the frame context. GetContext()1014 Handle<Object> GetContext() { return context_; } 1015 1016 // Check if this frame is preceded by construct stub frame. The bottom-most 1017 // inlined frame might still be called by an uninlined construct stub. HasConstructStub()1018 bool HasConstructStub() { 1019 return has_construct_stub_; 1020 } 1021 1022 // Get an incoming argument. GetParameter(int index)1023 Handle<Object> GetParameter(int index) { 1024 DCHECK(0 <= index && index < parameters_count()); 1025 return parameters_[index]; 1026 } 1027 1028 // Get an expression from the expression stack. GetExpression(int index)1029 Handle<Object> GetExpression(int index) { 1030 DCHECK(0 <= index && index < expression_count()); 1031 return expression_stack_[index]; 1032 } 1033 GetSourcePosition()1034 int GetSourcePosition() { 1035 return source_position_; 1036 } 1037 1038 private: 1039 // Set an incoming argument. SetParameter(int index,Handle<Object> obj)1040 void SetParameter(int index, Handle<Object> obj) { 1041 DCHECK(0 <= index && index < parameters_count()); 1042 parameters_[index] = obj; 1043 } 1044 1045 // Set an expression on the expression stack. SetExpression(int index,Handle<Object> obj)1046 void SetExpression(int index, Handle<Object> obj) { 1047 DCHECK(0 <= index && index < expression_count()); 1048 expression_stack_[index] = obj; 1049 } 1050 1051 Handle<JSFunction> function_; 1052 Handle<Object> context_; 1053 bool has_construct_stub_; 1054 std::vector<Handle<Object> > parameters_; 1055 std::vector<Handle<Object> > expression_stack_; 1056 int source_position_; 1057 1058 friend class Deoptimizer; 1059 }; 1060 1061 } // namespace internal 1062 } // namespace v8 1063 1064 #endif // V8_DEOPTIMIZER_H_ 1065