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 21457535 : : 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 43871 : void set_storage(Handle<HeapObject> storage) { storage_ = storage; }
105 : void set_initialized_storage(Handle<Object> storage);
106 43871 : void mark_finished() { materialization_state_ = kFinished; }
107 43871 : 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 4008126 : 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 149887 : SharedFunctionInfo raw_shared_info() const {
180 149887 : CHECK(!raw_shared_info_.is_null());
181 149887 : return raw_shared_info_;
182 : }
183 :
184 231677 : class iterator {
185 : public:
186 : iterator& operator++() {
187 1022202 : ++input_index_;
188 1022202 : AdvanceIterator(&position_);
189 : return *this;
190 : }
191 :
192 3441491 : iterator operator++(int) {
193 3732122 : iterator original(position_, input_index_);
194 3732990 : ++input_index_;
195 3732990 : AdvanceIterator(&position_);
196 3441491 : return original;
197 : }
198 :
199 146530 : bool operator==(const iterator& other) const {
200 : // Ignore {input_index_} for equality.
201 317904 : return position_ == other.position_;
202 : }
203 : bool operator!=(const iterator& other) const { return !(*this == other); }
204 :
205 : TranslatedValue& operator*() { return (*position_); }
206 2113360 : TranslatedValue* operator->() { return &(*position_); }
207 : const TranslatedValue& operator*() const { return (*position_); }
208 1197989 : 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 5603298 : : 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 4008126 : return_value_count_(return_value_count) {}
269 :
270 21457535 : 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 1470068 : class TranslatedState {
304 : public:
305 282462 : 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 : struct JumpTableEntry : public ZoneObject {
433 : inline JumpTableEntry(Address entry, const DeoptInfo& deopt_info,
434 : DeoptimizeKind kind, bool frame)
435 : : label(),
436 : address(entry),
437 : deopt_info(deopt_info),
438 : deopt_kind(kind),
439 : needs_frame(frame) {}
440 :
441 : bool IsEquivalentTo(const JumpTableEntry& other) const {
442 : return address == other.address && deopt_kind == other.deopt_kind &&
443 : needs_frame == other.needs_frame;
444 : }
445 :
446 : Label label;
447 : Address address;
448 : DeoptInfo deopt_info;
449 : DeoptimizeKind deopt_kind;
450 : bool needs_frame;
451 : };
452 :
453 : static const char* MessageFor(DeoptimizeKind kind);
454 :
455 : int output_count() const { return output_count_; }
456 :
457 : Handle<JSFunction> function() const;
458 : Handle<Code> compiled_code() const;
459 141231 : DeoptimizeKind deopt_kind() const { return deopt_kind_; }
460 :
461 : // Number of created JS frames. Not all created frames are necessarily JS.
462 : int jsframe_count() const { return jsframe_count_; }
463 :
464 : static Deoptimizer* New(Address raw_function, DeoptimizeKind kind,
465 : unsigned bailout_id, Address from, int fp_to_sp_delta,
466 : Isolate* isolate);
467 : static Deoptimizer* Grab(Isolate* isolate);
468 :
469 : // The returned object with information on the optimized frame needs to be
470 : // freed before another one can be generated.
471 : static DeoptimizedFrameInfo* DebuggerInspectableFrame(JavaScriptFrame* frame,
472 : int jsframe_index,
473 : Isolate* isolate);
474 :
475 : // Deoptimize the function now. Its current optimized code will never be run
476 : // again and any activations of the optimized code will get deoptimized when
477 : // execution returns. If {code} is specified then the given code is targeted
478 : // instead of the function code (e.g. OSR code not installed on function).
479 : static void DeoptimizeFunction(JSFunction function, Code code = Code());
480 :
481 : // Deoptimize all code in the given isolate.
482 : static void DeoptimizeAll(Isolate* isolate);
483 :
484 : // Deoptimizes all optimized code that has been previously marked
485 : // (via code->set_marked_for_deoptimization) and unlinks all functions that
486 : // refer to that code.
487 : static void DeoptimizeMarkedCode(Isolate* isolate);
488 :
489 : ~Deoptimizer();
490 :
491 : void MaterializeHeapObjects();
492 :
493 : static void ComputeOutputFrames(Deoptimizer* deoptimizer);
494 :
495 : static Address GetDeoptimizationEntry(Isolate* isolate, DeoptimizeKind kind);
496 :
497 : // Returns true if {addr} is a deoptimization entry and stores its type in
498 : // {type}. Returns false if {addr} is not a deoptimization entry.
499 : static bool IsDeoptimizationEntry(Isolate* isolate, Address addr,
500 : DeoptimizeKind* type);
501 :
502 : // Code generation support.
503 : static int input_offset() { return OFFSET_OF(Deoptimizer, input_); }
504 : static int output_count_offset() {
505 : return OFFSET_OF(Deoptimizer, output_count_);
506 : }
507 : static int output_offset() { return OFFSET_OF(Deoptimizer, output_); }
508 :
509 : static int caller_frame_top_offset() {
510 : return OFFSET_OF(Deoptimizer, caller_frame_top_);
511 : }
512 :
513 : static int GetDeoptimizedCodeCount(Isolate* isolate);
514 :
515 : static const int kNotDeoptimizationEntry = -1;
516 :
517 : static void EnsureCodeForDeoptimizationEntry(Isolate* isolate,
518 : DeoptimizeKind kind);
519 : static void EnsureCodeForDeoptimizationEntries(Isolate* isolate);
520 :
521 : Isolate* isolate() const { return isolate_; }
522 :
523 : static const int kMaxNumberOfEntries = 16384;
524 :
525 : private:
526 : friend class FrameWriter;
527 : void QueueValueForMaterialization(Address output_address, Object obj,
528 : const TranslatedFrame::iterator& iterator);
529 :
530 :
531 : Deoptimizer(Isolate* isolate, JSFunction function, DeoptimizeKind kind,
532 : unsigned bailout_id, Address from, int fp_to_sp_delta);
533 : Code FindOptimizedCode();
534 : void PrintFunctionName();
535 : void DeleteFrameDescriptions();
536 :
537 : static bool IsDeoptimizationEntry(Isolate* isolate, Address addr,
538 : DeoptimizeKind type);
539 :
540 : void DoComputeOutputFrames();
541 : void DoComputeInterpretedFrame(TranslatedFrame* translated_frame,
542 : int frame_index, bool goto_catch_handler);
543 : void DoComputeArgumentsAdaptorFrame(TranslatedFrame* translated_frame,
544 : int frame_index);
545 : void DoComputeConstructStubFrame(TranslatedFrame* translated_frame,
546 : int frame_index);
547 :
548 : enum class BuiltinContinuationMode {
549 : STUB,
550 : JAVASCRIPT,
551 : JAVASCRIPT_WITH_CATCH,
552 : JAVASCRIPT_HANDLE_EXCEPTION
553 : };
554 : static bool BuiltinContinuationModeIsWithCatch(BuiltinContinuationMode mode);
555 : static bool BuiltinContinuationModeIsJavaScript(BuiltinContinuationMode mode);
556 : static StackFrame::Type BuiltinContinuationModeToFrameType(
557 : BuiltinContinuationMode mode);
558 : static Builtins::Name TrampolineForBuiltinContinuation(
559 : BuiltinContinuationMode mode, bool must_handle_result);
560 :
561 : void DoComputeBuiltinContinuation(TranslatedFrame* translated_frame,
562 : int frame_index,
563 : BuiltinContinuationMode mode);
564 :
565 : unsigned ComputeInputFrameAboveFpFixedSize() const;
566 : unsigned ComputeInputFrameSize() const;
567 : static unsigned ComputeInterpretedFixedSize(SharedFunctionInfo shared);
568 :
569 : static unsigned ComputeIncomingArgumentSize(SharedFunctionInfo shared);
570 : static unsigned ComputeOutgoingArgumentSize(Code code, unsigned bailout_id);
571 :
572 : static void GenerateDeoptimizationEntries(MacroAssembler* masm,
573 : Isolate* isolate,
574 : DeoptimizeKind kind);
575 :
576 : // Marks all the code in the given context for deoptimization.
577 : static void MarkAllCodeForContext(Context native_context);
578 :
579 : // Deoptimizes all code marked in the given context.
580 : static void DeoptimizeMarkedCodeForContext(Context native_context);
581 :
582 : // Some architectures need to push padding together with the TOS register
583 : // in order to maintain stack alignment.
584 : static bool PadTopOfStackRegister();
585 :
586 : // Searches the list of known deoptimizing code for a Code object
587 : // containing the given address (which is supposedly faster than
588 : // searching all code objects).
589 : Code FindDeoptimizingCode(Address addr);
590 :
591 : Isolate* isolate_;
592 : JSFunction function_;
593 : Code compiled_code_;
594 : unsigned bailout_id_;
595 : DeoptimizeKind deopt_kind_;
596 : Address from_;
597 : int fp_to_sp_delta_;
598 : bool deoptimizing_throw_;
599 : int catch_handler_data_;
600 : int catch_handler_pc_offset_;
601 :
602 : // Input frame description.
603 : FrameDescription* input_;
604 : // Number of output frames.
605 : int output_count_;
606 : // Number of output js frames.
607 : int jsframe_count_;
608 : // Array of output frame descriptions.
609 : FrameDescription** output_;
610 :
611 : // Caller frame details computed from input frame.
612 : intptr_t caller_frame_top_;
613 : intptr_t caller_fp_;
614 : intptr_t caller_pc_;
615 : intptr_t caller_constant_pool_;
616 : intptr_t input_frame_context_;
617 :
618 : // Key for lookup of previously materialized objects
619 : intptr_t stack_fp_;
620 :
621 : TranslatedState translated_state_;
622 20706 : struct ValueToMaterialize {
623 : Address output_slot_address_;
624 : TranslatedFrame::iterator value_;
625 : };
626 : std::vector<ValueToMaterialize> values_to_materialize_;
627 :
628 : #ifdef DEBUG
629 : DisallowHeapAllocation* disallow_heap_allocation_;
630 : #endif // DEBUG
631 :
632 : CodeTracer::Scope* trace_scope_;
633 :
634 : static const int table_entry_size_;
635 :
636 : friend class FrameDescription;
637 : friend class DeoptimizedFrameInfo;
638 : };
639 :
640 :
641 9496113 : class RegisterValues {
642 : public:
643 : intptr_t GetRegister(unsigned n) const {
644 : #if DEBUG
645 : // This convoluted DCHECK is needed to work around a gcc problem that
646 : // improperly detects an array bounds overflow in optimized debug builds
647 : // when using a plain DCHECK.
648 : if (n >= arraysize(registers_)) {
649 : DCHECK(false);
650 : return 0;
651 : }
652 : #endif
653 283262 : return registers_[n];
654 : }
655 :
656 : Float32 GetFloatRegister(unsigned n) const {
657 : DCHECK(n < arraysize(float_registers_));
658 91 : return float_registers_[n];
659 : }
660 :
661 : Float64 GetDoubleRegister(unsigned n) const {
662 : DCHECK(n < arraysize(double_registers_));
663 464 : return double_registers_[n];
664 : }
665 :
666 : void SetRegister(unsigned n, intptr_t value) {
667 : DCHECK(n < arraysize(registers_));
668 5029001 : registers_[n] = value;
669 : }
670 :
671 : void SetFloatRegister(unsigned n, Float32 value) {
672 : DCHECK(n < arraysize(float_registers_));
673 : float_registers_[n] = value;
674 : }
675 :
676 : void SetDoubleRegister(unsigned n, Float64 value) {
677 : DCHECK(n < arraysize(double_registers_));
678 : double_registers_[n] = value;
679 : }
680 :
681 : // Generated code is writing directly into the below arrays, make sure their
682 : // element sizes fit what the machine instructions expect.
683 : static_assert(sizeof(Float32) == kFloatSize, "size mismatch");
684 : static_assert(sizeof(Float64) == kDoubleSize, "size mismatch");
685 :
686 : intptr_t registers_[Register::kNumRegisters];
687 : Float32 float_registers_[FloatRegister::kNumRegisters];
688 : Float64 double_registers_[DoubleRegister::kNumRegisters];
689 : };
690 :
691 :
692 : class FrameDescription {
693 : public:
694 : explicit FrameDescription(uint32_t frame_size, int parameter_count = 0);
695 :
696 : void* operator new(size_t size, uint32_t frame_size) {
697 : // Subtracts kSystemPointerSize, as the member frame_content_ already
698 : // supplies the first element of the area to store the frame.
699 287761 : return malloc(size + frame_size - kSystemPointerSize);
700 : }
701 :
702 : void operator delete(void* pointer, uint32_t frame_size) {
703 : free(pointer);
704 : }
705 :
706 : void operator delete(void* description) {
707 287761 : free(description);
708 : }
709 :
710 : uint32_t GetFrameSize() const {
711 : USE(frame_content_);
712 : DCHECK(static_cast<uint32_t>(frame_size_) == frame_size_);
713 428992 : return static_cast<uint32_t>(frame_size_);
714 : }
715 :
716 : intptr_t GetFrameSlot(unsigned offset) {
717 : return *GetFrameSlotPointer(offset);
718 : }
719 :
720 282462 : unsigned GetLastArgumentSlotOffset() {
721 : int parameter_slots = parameter_count();
722 : if (kPadArguments) parameter_slots = RoundUp(parameter_slots, 2);
723 282462 : return GetFrameSize() - parameter_slots * kSystemPointerSize;
724 : }
725 :
726 : Address GetFramePointerAddress() {
727 : int fp_offset =
728 282462 : GetLastArgumentSlotOffset() - StandardFrameConstants::kCallerSPOffset;
729 : return reinterpret_cast<Address>(GetFrameSlotPointer(fp_offset));
730 : }
731 :
732 : RegisterValues* GetRegisterValues() { return ®ister_values_; }
733 :
734 : void SetFrameSlot(unsigned offset, intptr_t value) {
735 4949939 : *GetFrameSlotPointer(offset) = value;
736 : }
737 :
738 : void SetCallerPc(unsigned offset, intptr_t value);
739 :
740 : void SetCallerFp(unsigned offset, intptr_t value);
741 :
742 : void SetCallerConstantPool(unsigned offset, intptr_t value);
743 :
744 : intptr_t GetRegister(unsigned n) const {
745 : return register_values_.GetRegister(n);
746 : }
747 :
748 : Float64 GetDoubleRegister(unsigned n) const {
749 : return register_values_.GetDoubleRegister(n);
750 : }
751 :
752 : void SetRegister(unsigned n, intptr_t value) {
753 : register_values_.SetRegister(n, value);
754 : }
755 :
756 : void SetDoubleRegister(unsigned n, Float64 value) {
757 : register_values_.SetDoubleRegister(n, value);
758 : }
759 :
760 : intptr_t GetTop() const { return top_; }
761 146530 : void SetTop(intptr_t top) { top_ = top; }
762 :
763 : intptr_t GetPc() const { return pc_; }
764 146530 : void SetPc(intptr_t pc) { pc_ = pc; }
765 :
766 : intptr_t GetFp() const { return fp_; }
767 146530 : void SetFp(intptr_t fp) { fp_ = fp; }
768 :
769 : intptr_t GetContext() const { return context_; }
770 145122 : void SetContext(intptr_t context) { context_ = context; }
771 :
772 : intptr_t GetConstantPool() const { return constant_pool_; }
773 : void SetConstantPool(intptr_t constant_pool) {
774 : constant_pool_ = constant_pool;
775 : }
776 :
777 141670 : void SetContinuation(intptr_t pc) { continuation_ = pc; }
778 :
779 : // Argument count, including receiver.
780 : int parameter_count() { return parameter_count_; }
781 :
782 : static int registers_offset() {
783 : return OFFSET_OF(FrameDescription, register_values_.registers_);
784 : }
785 :
786 : static int double_registers_offset() {
787 : return OFFSET_OF(FrameDescription, register_values_.double_registers_);
788 : }
789 :
790 : static int float_registers_offset() {
791 : return OFFSET_OF(FrameDescription, register_values_.float_registers_);
792 : }
793 :
794 : static int frame_size_offset() {
795 : return offsetof(FrameDescription, frame_size_);
796 : }
797 :
798 : static int pc_offset() { return offsetof(FrameDescription, pc_); }
799 :
800 : static int continuation_offset() {
801 : return offsetof(FrameDescription, continuation_);
802 : }
803 :
804 : static int frame_content_offset() {
805 : return offsetof(FrameDescription, frame_content_);
806 : }
807 :
808 : private:
809 : static const uint32_t kZapUint32 = 0xbeeddead;
810 :
811 : // Frame_size_ must hold a uint32_t value. It is only a uintptr_t to
812 : // keep the variable-size array frame_content_ of type intptr_t at
813 : // the end of the structure aligned.
814 : uintptr_t frame_size_; // Number of bytes.
815 : int parameter_count_;
816 : RegisterValues register_values_;
817 : intptr_t top_;
818 : intptr_t pc_;
819 : intptr_t fp_;
820 : intptr_t context_;
821 : intptr_t constant_pool_;
822 :
823 : // Continuation is the PC where the execution continues after
824 : // deoptimizing.
825 : intptr_t continuation_;
826 :
827 : // This must be at the end of the object as the object is allocated larger
828 : // than it's definition indicate to extend this array.
829 : intptr_t frame_content_[1];
830 :
831 : intptr_t* GetFrameSlotPointer(unsigned offset) {
832 : DCHECK(offset < frame_size_);
833 : return reinterpret_cast<intptr_t*>(
834 5232401 : reinterpret_cast<Address>(this) + frame_content_offset() + offset);
835 : }
836 : };
837 :
838 :
839 : class DeoptimizerData {
840 : public:
841 : explicit DeoptimizerData(Heap* heap);
842 : ~DeoptimizerData();
843 :
844 : private:
845 : Heap* heap_;
846 : static const int kLastDeoptimizeKind =
847 : static_cast<int>(DeoptimizeKind::kLastDeoptimizeKind);
848 : Code deopt_entry_code_[kLastDeoptimizeKind + 1];
849 : Code deopt_entry_code(DeoptimizeKind kind);
850 : void set_deopt_entry_code(DeoptimizeKind kind, Code code);
851 :
852 : Deoptimizer* current_;
853 :
854 : friend class Deoptimizer;
855 :
856 : DISALLOW_COPY_AND_ASSIGN(DeoptimizerData);
857 : };
858 :
859 : class TranslationBuffer {
860 : public:
861 : explicit TranslationBuffer(Zone* zone) : contents_(zone) {}
862 :
863 3454746 : int CurrentIndex() const { return static_cast<int>(contents_.size()); }
864 : void Add(int32_t value);
865 :
866 : Handle<ByteArray> CreateByteArray(Factory* factory);
867 :
868 : private:
869 : ZoneChunkList<uint8_t> contents_;
870 : };
871 :
872 : class TranslationIterator {
873 : public:
874 : TranslationIterator(ByteArray buffer, int index);
875 :
876 : int32_t Next();
877 :
878 : bool HasNext() const;
879 :
880 : void Skip(int n) {
881 28801 : for (int i = 0; i < n; i++) Next();
882 : }
883 :
884 : private:
885 : ByteArray buffer_;
886 : int index_;
887 : };
888 :
889 : #define TRANSLATION_OPCODE_LIST(V) \
890 : V(BEGIN) \
891 : V(INTERPRETED_FRAME) \
892 : V(BUILTIN_CONTINUATION_FRAME) \
893 : V(JAVA_SCRIPT_BUILTIN_CONTINUATION_FRAME) \
894 : V(JAVA_SCRIPT_BUILTIN_CONTINUATION_WITH_CATCH_FRAME) \
895 : V(CONSTRUCT_STUB_FRAME) \
896 : V(ARGUMENTS_ADAPTOR_FRAME) \
897 : V(DUPLICATED_OBJECT) \
898 : V(ARGUMENTS_ELEMENTS) \
899 : V(ARGUMENTS_LENGTH) \
900 : V(CAPTURED_OBJECT) \
901 : V(REGISTER) \
902 : V(INT32_REGISTER) \
903 : V(INT64_REGISTER) \
904 : V(UINT32_REGISTER) \
905 : V(BOOL_REGISTER) \
906 : V(FLOAT_REGISTER) \
907 : V(DOUBLE_REGISTER) \
908 : V(STACK_SLOT) \
909 : V(INT32_STACK_SLOT) \
910 : V(INT64_STACK_SLOT) \
911 : V(UINT32_STACK_SLOT) \
912 : V(BOOL_STACK_SLOT) \
913 : V(FLOAT_STACK_SLOT) \
914 : V(DOUBLE_STACK_SLOT) \
915 : V(LITERAL) \
916 : V(UPDATE_FEEDBACK)
917 :
918 : class Translation {
919 : public:
920 : #define DECLARE_TRANSLATION_OPCODE_ENUM(item) item,
921 : enum Opcode {
922 : TRANSLATION_OPCODE_LIST(DECLARE_TRANSLATION_OPCODE_ENUM)
923 : LAST = LITERAL
924 : };
925 : #undef DECLARE_TRANSLATION_OPCODE_ENUM
926 :
927 2998777 : Translation(TranslationBuffer* buffer, int frame_count, int jsframe_count,
928 : int update_feedback_count, Zone* zone)
929 5997554 : : buffer_(buffer), index_(buffer->CurrentIndex()), zone_(zone) {
930 2998777 : buffer_->Add(BEGIN);
931 2998765 : buffer_->Add(frame_count);
932 2998773 : buffer_->Add(jsframe_count);
933 2998800 : buffer_->Add(update_feedback_count);
934 2998795 : }
935 :
936 : int index() const { return index_; }
937 :
938 : // Commands.
939 : void BeginInterpretedFrame(BailoutId bytecode_offset, int literal_id,
940 : unsigned height, int return_value_offset,
941 : int return_value_count);
942 : void BeginArgumentsAdaptorFrame(int literal_id, unsigned height);
943 : void BeginConstructStubFrame(BailoutId bailout_id, int literal_id,
944 : unsigned height);
945 : void BeginBuiltinContinuationFrame(BailoutId bailout_id, int literal_id,
946 : unsigned height);
947 : void BeginJavaScriptBuiltinContinuationFrame(BailoutId bailout_id,
948 : int literal_id, unsigned height);
949 : void BeginJavaScriptBuiltinContinuationWithCatchFrame(BailoutId bailout_id,
950 : int literal_id,
951 : unsigned height);
952 : void ArgumentsElements(CreateArgumentsType type);
953 : void ArgumentsLength(CreateArgumentsType type);
954 : void BeginCapturedObject(int length);
955 : void AddUpdateFeedback(int vector_literal, int slot);
956 : void DuplicateObject(int object_index);
957 : void StoreRegister(Register reg);
958 : void StoreInt32Register(Register reg);
959 : void StoreInt64Register(Register reg);
960 : void StoreUint32Register(Register reg);
961 : void StoreBoolRegister(Register reg);
962 : void StoreFloatRegister(FloatRegister reg);
963 : void StoreDoubleRegister(DoubleRegister reg);
964 : void StoreStackSlot(int index);
965 : void StoreInt32StackSlot(int index);
966 : void StoreInt64StackSlot(int index);
967 : void StoreUint32StackSlot(int index);
968 : void StoreBoolStackSlot(int index);
969 : void StoreFloatStackSlot(int index);
970 : void StoreDoubleStackSlot(int index);
971 : void StoreLiteral(int literal_id);
972 : void StoreJSFrameFunction();
973 :
974 : Zone* zone() const { return zone_; }
975 :
976 : static int NumberOfOperandsFor(Opcode opcode);
977 :
978 : #if defined(OBJECT_PRINT) || defined(ENABLE_DISASSEMBLER)
979 : static const char* StringFor(Opcode opcode);
980 : #endif
981 :
982 : private:
983 : TranslationBuffer* buffer_;
984 : int index_;
985 : Zone* zone_;
986 : };
987 :
988 :
989 : class MaterializedObjectStore {
990 : public:
991 62883 : explicit MaterializedObjectStore(Isolate* isolate) : isolate_(isolate) {
992 : }
993 :
994 : Handle<FixedArray> Get(Address fp);
995 : void Set(Address fp, Handle<FixedArray> materialized_objects);
996 : bool Remove(Address fp);
997 :
998 : private:
999 : Isolate* isolate() const { return isolate_; }
1000 : Handle<FixedArray> GetStackEntries();
1001 : Handle<FixedArray> EnsureStackEntries(int size);
1002 :
1003 : int StackIdToIndex(Address fp);
1004 :
1005 : Isolate* isolate_;
1006 : std::vector<Address> frame_fps_;
1007 : };
1008 :
1009 :
1010 : // Class used to represent an unoptimized frame when the debugger
1011 : // needs to inspect a frame that is part of an optimized frame. The
1012 : // internally used FrameDescription objects are not GC safe so for use
1013 : // by the debugger frame information is copied to an object of this type.
1014 : // Represents parameters in unadapted form so their number might mismatch
1015 : // formal parameter count.
1016 49688 : class DeoptimizedFrameInfo : public Malloced {
1017 : public:
1018 : DeoptimizedFrameInfo(TranslatedState* state,
1019 : TranslatedState::iterator frame_it, Isolate* isolate);
1020 :
1021 : // Return the number of incoming arguments.
1022 0 : int parameters_count() { return static_cast<int>(parameters_.size()); }
1023 :
1024 : // Return the height of the expression stack.
1025 : int expression_count() { return static_cast<int>(expression_stack_.size()); }
1026 :
1027 : // Get the frame function.
1028 : Handle<JSFunction> GetFunction() { return function_; }
1029 :
1030 : // Get the frame context.
1031 : Handle<Object> GetContext() { return context_; }
1032 :
1033 : // Get an incoming argument.
1034 : Handle<Object> GetParameter(int index) {
1035 : DCHECK(0 <= index && index < parameters_count());
1036 24480 : return parameters_[index];
1037 : }
1038 :
1039 : // Get an expression from the expression stack.
1040 : Handle<Object> GetExpression(int index) {
1041 : DCHECK(0 <= index && index < expression_count());
1042 18592 : return expression_stack_[index];
1043 : }
1044 :
1045 : int GetSourcePosition() {
1046 : return source_position_;
1047 : }
1048 :
1049 : private:
1050 : // Set an incoming argument.
1051 : void SetParameter(int index, Handle<Object> obj) {
1052 : DCHECK(0 <= index && index < parameters_count());
1053 82510 : parameters_[index] = obj;
1054 : }
1055 :
1056 : // Set an expression on the expression stack.
1057 : void SetExpression(int index, Handle<Object> obj) {
1058 : DCHECK(0 <= index && index < expression_count());
1059 229926 : expression_stack_[index] = obj;
1060 : }
1061 :
1062 : Handle<JSFunction> function_;
1063 : Handle<Object> context_;
1064 : std::vector<Handle<Object> > parameters_;
1065 : std::vector<Handle<Object> > expression_stack_;
1066 : int source_position_;
1067 :
1068 : friend class Deoptimizer;
1069 : };
1070 :
1071 : } // namespace internal
1072 : } // namespace v8
1073 :
1074 : #endif // V8_DEOPTIMIZER_H_
|