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