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