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