OLD | NEW |
1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 23 matching lines...) Expand all Loading... |
34 #include "macro-assembler.h" | 34 #include "macro-assembler.h" |
35 #include "zone-inl.h" | 35 #include "zone-inl.h" |
36 | 36 |
37 | 37 |
38 namespace v8 { | 38 namespace v8 { |
39 namespace internal { | 39 namespace internal { |
40 | 40 |
41 class FrameDescription; | 41 class FrameDescription; |
42 class TranslationIterator; | 42 class TranslationIterator; |
43 class DeoptimizingCodeListNode; | 43 class DeoptimizingCodeListNode; |
44 | 44 class DeoptimizedFrameInfo; |
45 | 45 |
46 class HeapNumberMaterializationDescriptor BASE_EMBEDDED { | 46 class HeapNumberMaterializationDescriptor BASE_EMBEDDED { |
47 public: | 47 public: |
48 HeapNumberMaterializationDescriptor(Address slot_address, double val) | 48 HeapNumberMaterializationDescriptor(Address slot_address, double val) |
49 : slot_address_(slot_address), val_(val) { } | 49 : slot_address_(slot_address), val_(val) { } |
50 | 50 |
51 Address slot_address() const { return slot_address_; } | 51 Address slot_address() const { return slot_address_; } |
52 double value() const { return val_; } | 52 double value() const { return val_; } |
53 | 53 |
54 private: | 54 private: |
(...skipping 19 matching lines...) Expand all Loading... |
74 | 74 |
75 | 75 |
76 class Deoptimizer; | 76 class Deoptimizer; |
77 | 77 |
78 | 78 |
79 class DeoptimizerData { | 79 class DeoptimizerData { |
80 public: | 80 public: |
81 DeoptimizerData(); | 81 DeoptimizerData(); |
82 ~DeoptimizerData(); | 82 ~DeoptimizerData(); |
83 | 83 |
| 84 #ifdef ENABLE_DEBUGGER_SUPPORT |
| 85 void Iterate(ObjectVisitor* v); |
| 86 #endif |
| 87 |
84 private: | 88 private: |
85 LargeObjectChunk* eager_deoptimization_entry_code_; | 89 LargeObjectChunk* eager_deoptimization_entry_code_; |
86 LargeObjectChunk* lazy_deoptimization_entry_code_; | 90 LargeObjectChunk* lazy_deoptimization_entry_code_; |
87 Deoptimizer* current_; | 91 Deoptimizer* current_; |
88 | 92 |
| 93 #ifdef ENABLE_DEBUGGER_SUPPORT |
| 94 DeoptimizedFrameInfo* deoptimized_frame_info_; |
| 95 #endif |
| 96 |
89 // List of deoptimized code which still have references from active stack | 97 // List of deoptimized code which still have references from active stack |
90 // frames. These code objects are needed by the deoptimizer when deoptimizing | 98 // frames. These code objects are needed by the deoptimizer when deoptimizing |
91 // a frame for which the code object for the function function has been | 99 // a frame for which the code object for the function function has been |
92 // changed from the code present when deoptimizing was done. | 100 // changed from the code present when deoptimizing was done. |
93 DeoptimizingCodeListNode* deoptimizing_code_list_; | 101 DeoptimizingCodeListNode* deoptimizing_code_list_; |
94 | 102 |
95 friend class Deoptimizer; | 103 friend class Deoptimizer; |
96 | 104 |
97 DISALLOW_COPY_AND_ASSIGN(DeoptimizerData); | 105 DISALLOW_COPY_AND_ASSIGN(DeoptimizerData); |
98 }; | 106 }; |
99 | 107 |
100 | 108 |
101 class Deoptimizer : public Malloced { | 109 class Deoptimizer : public Malloced { |
102 public: | 110 public: |
103 enum BailoutType { | 111 enum BailoutType { |
104 EAGER, | 112 EAGER, |
105 LAZY, | 113 LAZY, |
106 OSR | 114 OSR, |
| 115 // This last bailout type is not really a bailout, but used by the |
| 116 // debugger to deoptimize stack frames to allow inspection. |
| 117 DEBUGGER |
107 }; | 118 }; |
108 | 119 |
109 int output_count() const { return output_count_; } | 120 int output_count() const { return output_count_; } |
110 | 121 |
111 static Deoptimizer* New(JSFunction* function, | 122 static Deoptimizer* New(JSFunction* function, |
112 BailoutType type, | 123 BailoutType type, |
113 unsigned bailout_id, | 124 unsigned bailout_id, |
114 Address from, | 125 Address from, |
115 int fp_to_sp_delta, | 126 int fp_to_sp_delta, |
116 Isolate* isolate); | 127 Isolate* isolate); |
117 static Deoptimizer* Grab(Isolate* isolate); | 128 static Deoptimizer* Grab(Isolate* isolate); |
118 | 129 |
| 130 #ifdef ENABLE_DEBUGGER_SUPPORT |
| 131 // The returned object with information on the optimized frame needs to be |
| 132 // freed before another one can be generated. |
| 133 static DeoptimizedFrameInfo* DebuggerInspectableFrame(JavaScriptFrame* frame, |
| 134 int frame_index, |
| 135 Isolate* isolate); |
| 136 static void DeleteDebuggerInspectableFrame(DeoptimizedFrameInfo* info, |
| 137 Isolate* isolate); |
| 138 #endif |
| 139 |
119 // Makes sure that there is enough room in the relocation | 140 // Makes sure that there is enough room in the relocation |
120 // information of a code object to perform lazy deoptimization | 141 // information of a code object to perform lazy deoptimization |
121 // patching. If there is not enough room a new relocation | 142 // patching. If there is not enough room a new relocation |
122 // information object is allocated and comments are added until it | 143 // information object is allocated and comments are added until it |
123 // is big enough. | 144 // is big enough. |
124 static void EnsureRelocSpaceForLazyDeoptimization(Handle<Code> code); | 145 static void EnsureRelocSpaceForLazyDeoptimization(Handle<Code> code); |
125 | 146 |
126 // Deoptimize the function now. Its current optimized code will never be run | 147 // Deoptimize the function now. Its current optimized code will never be run |
127 // again and any activations of the optimized code will get deoptimized when | 148 // again and any activations of the optimized code will get deoptimized when |
128 // execution returns. | 149 // execution returns. |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
164 | 185 |
165 // Change all patched stack guard checks in the unoptimized code | 186 // Change all patched stack guard checks in the unoptimized code |
166 // back to a normal stack guard check. | 187 // back to a normal stack guard check. |
167 static void RevertStackCheckCodeAt(Address pc_after, | 188 static void RevertStackCheckCodeAt(Address pc_after, |
168 Code* check_code, | 189 Code* check_code, |
169 Code* replacement_code); | 190 Code* replacement_code); |
170 | 191 |
171 ~Deoptimizer(); | 192 ~Deoptimizer(); |
172 | 193 |
173 void MaterializeHeapNumbers(); | 194 void MaterializeHeapNumbers(); |
| 195 #ifdef ENABLE_DEBUGGER_SUPPORT |
| 196 void MaterializeHeapNumbersForDebuggerInspectableFrame( |
| 197 Address top, intptr_t size, DeoptimizedFrameInfo* info); |
| 198 #endif |
174 | 199 |
175 static void ComputeOutputFrames(Deoptimizer* deoptimizer); | 200 static void ComputeOutputFrames(Deoptimizer* deoptimizer); |
176 | 201 |
177 static Address GetDeoptimizationEntry(int id, BailoutType type); | 202 static Address GetDeoptimizationEntry(int id, BailoutType type); |
178 static int GetDeoptimizationId(Address addr, BailoutType type); | 203 static int GetDeoptimizationId(Address addr, BailoutType type); |
179 static int GetOutputInfo(DeoptimizationOutputData* data, | 204 static int GetOutputInfo(DeoptimizationOutputData* data, |
180 unsigned node_id, | 205 unsigned node_id, |
181 SharedFunctionInfo* shared); | 206 SharedFunctionInfo* shared); |
182 | 207 |
183 // Code generation support. | 208 // Code generation support. |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
226 }; | 251 }; |
227 | 252 |
228 private: | 253 private: |
229 static const int kNumberOfEntries = 4096; | 254 static const int kNumberOfEntries = 4096; |
230 | 255 |
231 Deoptimizer(Isolate* isolate, | 256 Deoptimizer(Isolate* isolate, |
232 JSFunction* function, | 257 JSFunction* function, |
233 BailoutType type, | 258 BailoutType type, |
234 unsigned bailout_id, | 259 unsigned bailout_id, |
235 Address from, | 260 Address from, |
236 int fp_to_sp_delta); | 261 int fp_to_sp_delta, |
| 262 Code* optimized_code); |
237 void DeleteFrameDescriptions(); | 263 void DeleteFrameDescriptions(); |
238 | 264 |
239 void DoComputeOutputFrames(); | 265 void DoComputeOutputFrames(); |
240 void DoComputeOsrOutputFrame(); | 266 void DoComputeOsrOutputFrame(); |
241 void DoComputeFrame(TranslationIterator* iterator, int frame_index); | 267 void DoComputeFrame(TranslationIterator* iterator, int frame_index); |
242 void DoTranslateCommand(TranslationIterator* iterator, | 268 void DoTranslateCommand(TranslationIterator* iterator, |
243 int frame_index, | 269 int frame_index, |
244 unsigned output_offset); | 270 unsigned output_offset); |
245 // Translate a command for OSR. Updates the input offset to be used for | 271 // Translate a command for OSR. Updates the input offset to be used for |
246 // the next command. Returns false if translation of the command failed | 272 // the next command. Returns false if translation of the command failed |
(...skipping 15 matching lines...) Expand all Loading... |
262 static LargeObjectChunk* CreateCode(BailoutType type); | 288 static LargeObjectChunk* CreateCode(BailoutType type); |
263 static void GenerateDeoptimizationEntries( | 289 static void GenerateDeoptimizationEntries( |
264 MacroAssembler* masm, int count, BailoutType type); | 290 MacroAssembler* masm, int count, BailoutType type); |
265 | 291 |
266 // Weak handle callback for deoptimizing code objects. | 292 // Weak handle callback for deoptimizing code objects. |
267 static void HandleWeakDeoptimizedCode( | 293 static void HandleWeakDeoptimizedCode( |
268 v8::Persistent<v8::Value> obj, void* data); | 294 v8::Persistent<v8::Value> obj, void* data); |
269 static Code* FindDeoptimizingCodeFromAddress(Address addr); | 295 static Code* FindDeoptimizingCodeFromAddress(Address addr); |
270 static void RemoveDeoptimizingCode(Code* code); | 296 static void RemoveDeoptimizingCode(Code* code); |
271 | 297 |
| 298 // Fill the input from from a JavaScript frame. This is used when |
| 299 // the debugger needs to inspect an optimized frame. For normal |
| 300 // deoptimizations the input frame is filled in generated code. |
| 301 void FillInputFrame(Address tos, JavaScriptFrame* frame); |
| 302 |
272 Isolate* isolate_; | 303 Isolate* isolate_; |
273 JSFunction* function_; | 304 JSFunction* function_; |
274 Code* optimized_code_; | 305 Code* optimized_code_; |
275 unsigned bailout_id_; | 306 unsigned bailout_id_; |
276 BailoutType bailout_type_; | 307 BailoutType bailout_type_; |
277 Address from_; | 308 Address from_; |
278 int fp_to_sp_delta_; | 309 int fp_to_sp_delta_; |
279 | 310 |
280 // Input frame description. | 311 // Input frame description. |
281 FrameDescription* input_; | 312 FrameDescription* input_; |
282 // Number of output frames. | 313 // Number of output frames. |
283 int output_count_; | 314 int output_count_; |
284 // Array of output frame descriptions. | 315 // Array of output frame descriptions. |
285 FrameDescription** output_; | 316 FrameDescription** output_; |
286 | 317 |
287 List<HeapNumberMaterializationDescriptor> deferred_heap_numbers_; | 318 List<HeapNumberMaterializationDescriptor> deferred_heap_numbers_; |
288 | 319 |
289 static int table_entry_size_; | 320 static int table_entry_size_; |
290 | 321 |
291 friend class FrameDescription; | 322 friend class FrameDescription; |
292 friend class DeoptimizingCodeListNode; | 323 friend class DeoptimizingCodeListNode; |
| 324 friend class DeoptimizedFrameInfo; |
293 }; | 325 }; |
294 | 326 |
295 | 327 |
296 class FrameDescription { | 328 class FrameDescription { |
297 public: | 329 public: |
298 FrameDescription(uint32_t frame_size, | 330 FrameDescription(uint32_t frame_size, |
299 JSFunction* function); | 331 JSFunction* function); |
300 | 332 |
301 void* operator new(size_t size, uint32_t frame_size) { | 333 void* operator new(size_t size, uint32_t frame_size) { |
302 // Subtracts kPointerSize, as the member frame_content_ already supplies | 334 // Subtracts kPointerSize, as the member frame_content_ already supplies |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
353 void SetPc(intptr_t pc) { pc_ = pc; } | 385 void SetPc(intptr_t pc) { pc_ = pc; } |
354 | 386 |
355 intptr_t GetFp() const { return fp_; } | 387 intptr_t GetFp() const { return fp_; } |
356 void SetFp(intptr_t fp) { fp_ = fp; } | 388 void SetFp(intptr_t fp) { fp_ = fp; } |
357 | 389 |
358 Smi* GetState() const { return state_; } | 390 Smi* GetState() const { return state_; } |
359 void SetState(Smi* state) { state_ = state; } | 391 void SetState(Smi* state) { state_ = state; } |
360 | 392 |
361 void SetContinuation(intptr_t pc) { continuation_ = pc; } | 393 void SetContinuation(intptr_t pc) { continuation_ = pc; } |
362 | 394 |
| 395 #ifdef DEBUG |
| 396 Code::Kind GetKind() const { return kind_; } |
| 397 void SetKind(Code::Kind kind) { kind_ = kind; } |
| 398 #endif |
| 399 |
| 400 // Get the expression stack height for a unoptimized frame. |
| 401 unsigned GetExpressionCount(Deoptimizer* deoptimizer); |
| 402 |
| 403 // Get the expression stack value for an unoptimized frame. |
| 404 Object* GetExpression(Deoptimizer* deoptimizer, int index); |
| 405 |
363 static int registers_offset() { | 406 static int registers_offset() { |
364 return OFFSET_OF(FrameDescription, registers_); | 407 return OFFSET_OF(FrameDescription, registers_); |
365 } | 408 } |
366 | 409 |
367 static int double_registers_offset() { | 410 static int double_registers_offset() { |
368 return OFFSET_OF(FrameDescription, double_registers_); | 411 return OFFSET_OF(FrameDescription, double_registers_); |
369 } | 412 } |
370 | 413 |
371 static int frame_size_offset() { | 414 static int frame_size_offset() { |
372 return OFFSET_OF(FrameDescription, frame_size_); | 415 return OFFSET_OF(FrameDescription, frame_size_); |
(...skipping 19 matching lines...) Expand all Loading... |
392 static const uint32_t kZapUint32 = 0xbeeddead; | 435 static const uint32_t kZapUint32 = 0xbeeddead; |
393 | 436 |
394 uintptr_t frame_size_; // Number of bytes. | 437 uintptr_t frame_size_; // Number of bytes. |
395 JSFunction* function_; | 438 JSFunction* function_; |
396 intptr_t registers_[Register::kNumRegisters]; | 439 intptr_t registers_[Register::kNumRegisters]; |
397 double double_registers_[DoubleRegister::kNumAllocatableRegisters]; | 440 double double_registers_[DoubleRegister::kNumAllocatableRegisters]; |
398 intptr_t top_; | 441 intptr_t top_; |
399 intptr_t pc_; | 442 intptr_t pc_; |
400 intptr_t fp_; | 443 intptr_t fp_; |
401 Smi* state_; | 444 Smi* state_; |
| 445 #ifdef DEBUG |
| 446 Code::Kind kind_; |
| 447 #endif |
402 | 448 |
403 // Continuation is the PC where the execution continues after | 449 // Continuation is the PC where the execution continues after |
404 // deoptimizing. | 450 // deoptimizing. |
405 intptr_t continuation_; | 451 intptr_t continuation_; |
406 | 452 |
407 // This must be at the end of the object as the object is allocated larger | 453 // This must be at the end of the object as the object is allocated larger |
408 // than it's definition indicate to extend this array. | 454 // than it's definition indicate to extend this array. |
409 intptr_t frame_content_[1]; | 455 intptr_t frame_content_[1]; |
410 | 456 |
411 intptr_t* GetFrameSlotPointer(unsigned offset) { | 457 intptr_t* GetFrameSlotPointer(unsigned offset) { |
(...skipping 178 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
590 return frame->fp() + offset - ((slot_index + 1) * kPointerSize); | 636 return frame->fp() + offset - ((slot_index + 1) * kPointerSize); |
591 } | 637 } |
592 } | 638 } |
593 | 639 |
594 static SlotRef ComputeSlotForNextArgument(TranslationIterator* iterator, | 640 static SlotRef ComputeSlotForNextArgument(TranslationIterator* iterator, |
595 DeoptimizationInputData* data, | 641 DeoptimizationInputData* data, |
596 JavaScriptFrame* frame); | 642 JavaScriptFrame* frame); |
597 }; | 643 }; |
598 | 644 |
599 | 645 |
| 646 #ifdef ENABLE_DEBUGGER_SUPPORT |
| 647 // Class used to represent an unoptimized frame when the debugger |
| 648 // needs to inspect a frame that is part of an optimized frame. The |
| 649 // internally used FrameDescription objects are not GC safe so for use |
| 650 // by the debugger frame information is copied to an object of this type. |
| 651 class DeoptimizedFrameInfo : public Malloced { |
| 652 public: |
| 653 DeoptimizedFrameInfo(Deoptimizer* deoptimizer, int frame_index); |
| 654 virtual ~DeoptimizedFrameInfo(); |
| 655 |
| 656 // GC support. |
| 657 void Iterate(ObjectVisitor* v); |
| 658 |
| 659 // Return the height of the expression stack. |
| 660 int expression_count() { return expression_count_; } |
| 661 |
| 662 // Get an expression from the expression stack. |
| 663 Object* GetExpression(int index) { |
| 664 ASSERT(0 <= index && index < expression_count()); |
| 665 return expression_stack_[index]; |
| 666 } |
| 667 |
| 668 private: |
| 669 // Set an expression on the expression stack. |
| 670 void SetExpression(int index, Object* obj) { |
| 671 ASSERT(0 <= index && index < expression_count()); |
| 672 expression_stack_[index] = obj; |
| 673 } |
| 674 |
| 675 int expression_count_; |
| 676 Object** expression_stack_; |
| 677 |
| 678 friend class Deoptimizer; |
| 679 }; |
| 680 #endif |
| 681 |
600 } } // namespace v8::internal | 682 } } // namespace v8::internal |
601 | 683 |
602 #endif // V8_DEOPTIMIZER_H_ | 684 #endif // V8_DEOPTIMIZER_H_ |
OLD | NEW |