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