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 21179680 : : 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 46866 : void set_storage(Handle<HeapObject> storage) { storage_ = storage; }
105 : void set_initialized_storage(Handle<Object> storage);
106 46866 : void mark_finished() { materialization_state_ = kFinished; }
107 46866 : 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 3937764 : 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 54462 : SharedFunctionInfo raw_shared_info() const {
180 54462 : CHECK(!raw_shared_info_.is_null());
181 54462 : return raw_shared_info_;
182 : }
183 :
184 236393 : class iterator {
185 : public:
186 : iterator& operator++() {
187 506960 : ++input_index_;
188 506960 : AdvanceIterator(&position_);
189 : return *this;
190 : }
191 :
192 3578384 : iterator operator++(int) {
193 3676709 : iterator original(position_, input_index_);
194 3677543 : ++input_index_;
195 3677543 : AdvanceIterator(&position_);
196 3578384 : return original;
197 : }
198 :
199 50303 : bool operator==(const iterator& other) const {
200 : // Ignore {input_index_} for equality.
201 125526 : return position_ == other.position_;
202 : }
203 : bool operator!=(const iterator& other) const { return !(*this == other); }
204 :
205 : TranslatedValue& operator*() { return (*position_); }
206 2088587 : TranslatedValue* operator->() { return &(*position_); }
207 : const TranslatedValue& operator*() const { return (*position_); }
208 583999 : 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 5422822 : : 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 3937764 : return_value_count_(return_value_count) {}
269 :
270 21179680 : 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 1396026 : class TranslatedState {
304 : public:
305 90342 : 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 45171 : 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 23472 : 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 3150642 : 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 92788 : 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 424 : return double_registers_[n];
664 : }
665 :
666 : void SetRegister(unsigned n, intptr_t value) {
667 : DCHECK(n < arraysize(registers_));
668 1664104 : 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 95474 : 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 95474 : free(description);
708 : }
709 :
710 : uint32_t GetFrameSize() const {
711 : USE(frame_content_);
712 : DCHECK(static_cast<uint32_t>(frame_size_) == frame_size_);
713 140645 : return static_cast<uint32_t>(frame_size_);
714 : }
715 :
716 : intptr_t GetFrameSlot(unsigned offset) {
717 : return *GetFrameSlotPointer(offset);
718 : }
719 :
720 90342 : unsigned GetLastArgumentSlotOffset() {
721 : int parameter_slots = parameter_count();
722 : if (kPadArguments) parameter_slots = RoundUp(parameter_slots, 2);
723 90342 : return GetFrameSize() - parameter_slots * kSystemPointerSize;
724 : }
725 :
726 : Address GetFramePointerAddress() {
727 : int fp_offset =
728 90342 : 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 2067600 : *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 50303 : void SetTop(intptr_t top) { top_ = top; }
762 :
763 : intptr_t GetPc() const { return pc_; }
764 50303 : void SetPc(intptr_t pc) { pc_ = pc; }
765 :
766 : intptr_t GetFp() const { return fp_; }
767 50303 : void SetFp(intptr_t fp) { fp_ = fp; }
768 :
769 : intptr_t GetContext() const { return context_; }
770 48935 : 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 45565 : 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 2157942 : 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 : #ifdef DEBUG
845 : bool IsDeoptEntryCode(Code code) const {
846 : for (int i = 0; i < kLastDeoptimizeKind + 1; i++) {
847 : if (code == deopt_entry_code_[i]) return true;
848 : }
849 : return false;
850 : }
851 : #endif // DEBUG
852 :
853 : private:
854 : Heap* heap_;
855 : static const int kLastDeoptimizeKind =
856 : static_cast<int>(DeoptimizeKind::kLastDeoptimizeKind);
857 : Code deopt_entry_code_[kLastDeoptimizeKind + 1];
858 : Code deopt_entry_code(DeoptimizeKind kind);
859 : void set_deopt_entry_code(DeoptimizeKind kind, Code code);
860 :
861 : Deoptimizer* current_;
862 :
863 : friend class Deoptimizer;
864 :
865 : DISALLOW_COPY_AND_ASSIGN(DeoptimizerData);
866 : };
867 :
868 : class TranslationBuffer {
869 : public:
870 : explicit TranslationBuffer(Zone* zone) : contents_(zone) {}
871 :
872 4025605 : int CurrentIndex() const { return static_cast<int>(contents_.size()); }
873 : void Add(int32_t value);
874 :
875 : Handle<ByteArray> CreateByteArray(Factory* factory);
876 :
877 : private:
878 : ZoneChunkList<uint8_t> contents_;
879 : };
880 :
881 : class TranslationIterator {
882 : public:
883 : TranslationIterator(ByteArray buffer, int index);
884 :
885 : int32_t Next();
886 :
887 : bool HasNext() const;
888 :
889 : void Skip(int n) {
890 323244 : for (int i = 0; i < n; i++) Next();
891 : }
892 :
893 : private:
894 : ByteArray buffer_;
895 : int index_;
896 : };
897 :
898 : #define TRANSLATION_OPCODE_LIST(V) \
899 : V(BEGIN) \
900 : V(INTERPRETED_FRAME) \
901 : V(BUILTIN_CONTINUATION_FRAME) \
902 : V(JAVA_SCRIPT_BUILTIN_CONTINUATION_FRAME) \
903 : V(JAVA_SCRIPT_BUILTIN_CONTINUATION_WITH_CATCH_FRAME) \
904 : V(CONSTRUCT_STUB_FRAME) \
905 : V(ARGUMENTS_ADAPTOR_FRAME) \
906 : V(DUPLICATED_OBJECT) \
907 : V(ARGUMENTS_ELEMENTS) \
908 : V(ARGUMENTS_LENGTH) \
909 : V(CAPTURED_OBJECT) \
910 : V(REGISTER) \
911 : V(INT32_REGISTER) \
912 : V(INT64_REGISTER) \
913 : V(UINT32_REGISTER) \
914 : V(BOOL_REGISTER) \
915 : V(FLOAT_REGISTER) \
916 : V(DOUBLE_REGISTER) \
917 : V(STACK_SLOT) \
918 : V(INT32_STACK_SLOT) \
919 : V(INT64_STACK_SLOT) \
920 : V(UINT32_STACK_SLOT) \
921 : V(BOOL_STACK_SLOT) \
922 : V(FLOAT_STACK_SLOT) \
923 : V(DOUBLE_STACK_SLOT) \
924 : V(LITERAL) \
925 : V(UPDATE_FEEDBACK)
926 :
927 : class Translation {
928 : public:
929 : #define DECLARE_TRANSLATION_OPCODE_ENUM(item) item,
930 : enum Opcode {
931 : TRANSLATION_OPCODE_LIST(DECLARE_TRANSLATION_OPCODE_ENUM)
932 : LAST = LITERAL
933 : };
934 : #undef DECLARE_TRANSLATION_OPCODE_ENUM
935 :
936 3569034 : Translation(TranslationBuffer* buffer, int frame_count, int jsframe_count,
937 : int update_feedback_count, Zone* zone)
938 7138068 : : buffer_(buffer), index_(buffer->CurrentIndex()), zone_(zone) {
939 3569034 : buffer_->Add(BEGIN);
940 3569025 : buffer_->Add(frame_count);
941 3569031 : buffer_->Add(jsframe_count);
942 3569038 : buffer_->Add(update_feedback_count);
943 3569039 : }
944 :
945 : int index() const { return index_; }
946 :
947 : // Commands.
948 : void BeginInterpretedFrame(BailoutId bytecode_offset, int literal_id,
949 : unsigned height, int return_value_offset,
950 : int return_value_count);
951 : void BeginArgumentsAdaptorFrame(int literal_id, unsigned height);
952 : void BeginConstructStubFrame(BailoutId bailout_id, int literal_id,
953 : unsigned height);
954 : void BeginBuiltinContinuationFrame(BailoutId bailout_id, int literal_id,
955 : unsigned height);
956 : void BeginJavaScriptBuiltinContinuationFrame(BailoutId bailout_id,
957 : int literal_id, unsigned height);
958 : void BeginJavaScriptBuiltinContinuationWithCatchFrame(BailoutId bailout_id,
959 : int literal_id,
960 : unsigned height);
961 : void ArgumentsElements(CreateArgumentsType type);
962 : void ArgumentsLength(CreateArgumentsType type);
963 : void BeginCapturedObject(int length);
964 : void AddUpdateFeedback(int vector_literal, int slot);
965 : void DuplicateObject(int object_index);
966 : void StoreRegister(Register reg);
967 : void StoreInt32Register(Register reg);
968 : void StoreInt64Register(Register reg);
969 : void StoreUint32Register(Register reg);
970 : void StoreBoolRegister(Register reg);
971 : void StoreFloatRegister(FloatRegister reg);
972 : void StoreDoubleRegister(DoubleRegister reg);
973 : void StoreStackSlot(int index);
974 : void StoreInt32StackSlot(int index);
975 : void StoreInt64StackSlot(int index);
976 : void StoreUint32StackSlot(int index);
977 : void StoreBoolStackSlot(int index);
978 : void StoreFloatStackSlot(int index);
979 : void StoreDoubleStackSlot(int index);
980 : void StoreLiteral(int literal_id);
981 : void StoreJSFrameFunction();
982 :
983 : Zone* zone() const { return zone_; }
984 :
985 : static int NumberOfOperandsFor(Opcode opcode);
986 :
987 : #if defined(OBJECT_PRINT) || defined(ENABLE_DISASSEMBLER)
988 : static const char* StringFor(Opcode opcode);
989 : #endif
990 :
991 : private:
992 : TranslationBuffer* buffer_;
993 : int index_;
994 : Zone* zone_;
995 : };
996 :
997 :
998 : class MaterializedObjectStore {
999 : public:
1000 61049 : explicit MaterializedObjectStore(Isolate* isolate) : isolate_(isolate) {
1001 : }
1002 :
1003 : Handle<FixedArray> Get(Address fp);
1004 : void Set(Address fp, Handle<FixedArray> materialized_objects);
1005 : bool Remove(Address fp);
1006 :
1007 : private:
1008 : Isolate* isolate() const { return isolate_; }
1009 : Handle<FixedArray> GetStackEntries();
1010 : Handle<FixedArray> EnsureStackEntries(int size);
1011 :
1012 : int StackIdToIndex(Address fp);
1013 :
1014 : Isolate* isolate_;
1015 : std::vector<Address> frame_fps_;
1016 : };
1017 :
1018 :
1019 : // Class used to represent an unoptimized frame when the debugger
1020 : // needs to inspect a frame that is part of an optimized frame. The
1021 : // internally used FrameDescription objects are not GC safe so for use
1022 : // by the debugger frame information is copied to an object of this type.
1023 : // Represents parameters in unadapted form so their number might mismatch
1024 : // formal parameter count.
1025 49840 : class DeoptimizedFrameInfo : public Malloced {
1026 : public:
1027 : DeoptimizedFrameInfo(TranslatedState* state,
1028 : TranslatedState::iterator frame_it, Isolate* isolate);
1029 :
1030 : // Return the number of incoming arguments.
1031 0 : int parameters_count() { return static_cast<int>(parameters_.size()); }
1032 :
1033 : // Return the height of the expression stack.
1034 : int expression_count() { return static_cast<int>(expression_stack_.size()); }
1035 :
1036 : // Get the frame function.
1037 : Handle<JSFunction> GetFunction() { return function_; }
1038 :
1039 : // Get the frame context.
1040 : Handle<Object> GetContext() { return context_; }
1041 :
1042 : // Get an incoming argument.
1043 : Handle<Object> GetParameter(int index) {
1044 : DCHECK(0 <= index && index < parameters_count());
1045 24524 : return parameters_[index];
1046 : }
1047 :
1048 : // Get an expression from the expression stack.
1049 : Handle<Object> GetExpression(int index) {
1050 : DCHECK(0 <= index && index < expression_count());
1051 18606 : return expression_stack_[index];
1052 : }
1053 :
1054 : int GetSourcePosition() {
1055 : return source_position_;
1056 : }
1057 :
1058 : private:
1059 : // Set an incoming argument.
1060 : void SetParameter(int index, Handle<Object> obj) {
1061 : DCHECK(0 <= index && index < parameters_count());
1062 82530 : parameters_[index] = obj;
1063 : }
1064 :
1065 : // Set an expression on the expression stack.
1066 : void SetExpression(int index, Handle<Object> obj) {
1067 : DCHECK(0 <= index && index < expression_count());
1068 230428 : expression_stack_[index] = obj;
1069 : }
1070 :
1071 : Handle<JSFunction> function_;
1072 : Handle<Object> context_;
1073 : std::vector<Handle<Object> > parameters_;
1074 : std::vector<Handle<Object> > expression_stack_;
1075 : int source_position_;
1076 :
1077 : friend class Deoptimizer;
1078 : };
1079 :
1080 : } // namespace internal
1081 : } // namespace v8
1082 :
1083 : #endif // V8_DEOPTIMIZER_H_
|