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