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 <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 :
27 : namespace v8 {
28 : namespace internal {
29 :
30 : class FrameDescription;
31 : class TranslationIterator;
32 : class DeoptimizedFrameInfo;
33 : class TranslatedState;
34 : class RegisterValues;
35 : class MacroAssembler;
36 :
37 : class 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 21448322 : : 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 56402 : void set_storage(Handle<HeapObject> storage) { storage_ = storage; }
105 : void set_initialized_storage(Handle<Object> storage);
106 56402 : void mark_finished() { materialization_state_ = kFinished; }
107 56402 : 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 :
158 7923624 : class 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 63553 : CHECK(!raw_shared_info_.is_null());
181 : return raw_shared_info_;
182 : }
183 :
184 254117 : class iterator {
185 : public:
186 : iterator& operator++() {
187 579066 : ++input_index_;
188 579066 : AdvanceIterator(&position_);
189 : return *this;
190 : }
191 :
192 : iterator operator++(int) {
193 3689524 : iterator original(position_, input_index_);
194 3690357 : ++input_index_;
195 3690357 : 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 1818481 : : 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 3961812 : return_value_count_(return_value_count) {}
269 :
270 21448322 : 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 :
303 1398056 : class TranslatedState {
304 : public:
305 162717 : 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 :
407 : class OptimizedFunctionVisitor {
408 : public:
409 : virtual ~OptimizedFunctionVisitor() = default;
410 : virtual void VisitFunction(JSFunction function) = 0;
411 : };
412 :
413 : class 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 32505 : 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 :
620 113650 : class 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 110638 : return registers_[n];
633 : }
634 :
635 : Float32 GetFloatRegister(unsigned n) const {
636 : DCHECK(n < arraysize(float_registers_));
637 91 : return float_registers_[n];
638 : }
639 :
640 : Float64 GetDoubleRegister(unsigned n) const {
641 : DCHECK(n < arraysize(double_registers_));
642 427 : return double_registers_[n];
643 : }
644 :
645 : void SetRegister(unsigned n, intptr_t value) {
646 : DCHECK(n < arraysize(registers_));
647 1982136 : 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 :
671 : class 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 113650 : 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 113650 : free(description);
687 : }
688 :
689 : uint32_t GetFrameSize() const {
690 : USE(frame_content_);
691 : DCHECK(static_cast<uint32_t>(frame_size_) == frame_size_);
692 167889 : 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 108478 : return GetFrameSize() - parameter_slots * kSystemPointerSize;
703 : }
704 :
705 : Address GetFramePointerAddress() {
706 : int fp_offset =
707 108478 : GetLastArgumentSlotOffset() - StandardFrameConstants::kCallerSPOffset;
708 : return reinterpret_cast<Address>(GetFrameSlotPointer(fp_offset));
709 : }
710 :
711 54239 : RegisterValues* GetRegisterValues() { return ®ister_values_; }
712 :
713 : void SetFrameSlot(unsigned offset, intptr_t value) {
714 2383585 : *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 59411 : void SetTop(intptr_t top) { top_ = top; }
741 :
742 : intptr_t GetPc() const { return pc_; }
743 59411 : void SetPc(intptr_t pc) { pc_ = pc; }
744 :
745 : intptr_t GetFp() const { return fp_; }
746 59411 : void SetFp(intptr_t fp) { fp_ = fp; }
747 :
748 : intptr_t GetContext() const { return context_; }
749 58042 : 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 54633 : 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 2492063 : reinterpret_cast<Address>(this) + frame_content_offset() + offset);
814 : }
815 : };
816 :
817 :
818 : class 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 :
847 : class TranslationBuffer {
848 : public:
849 : explicit TranslationBuffer(Zone* zone) : contents_(zone) {}
850 :
851 3793718 : 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 :
860 : class 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 578990 : 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 :
906 : class 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 3329972 : Translation(TranslationBuffer* buffer, int frame_count, int jsframe_count,
916 : int update_feedback_count, Zone* zone)
917 6659944 : : buffer_(buffer), index_(buffer->CurrentIndex()), zone_(zone) {
918 3329972 : buffer_->Add(BEGIN);
919 3329973 : buffer_->Add(frame_count);
920 3329981 : buffer_->Add(jsframe_count);
921 3329977 : buffer_->Add(update_feedback_count);
922 3329979 : }
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 :
977 62427 : class MaterializedObjectStore {
978 : public:
979 62442 : 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.
1004 49910 : class 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 0 : 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 24524 : 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 18604 : 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 82530 : 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 230516 : 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_
|