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