• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_DEOPTIMIZER_H_
6 #define V8_DEOPTIMIZER_DEOPTIMIZER_H_
7 
8 #include <vector>
9 
10 #include "src/builtins/builtins.h"
11 #include "src/codegen/source-position.h"
12 #include "src/deoptimizer/deoptimize-reason.h"
13 #include "src/deoptimizer/frame-description.h"
14 #include "src/deoptimizer/translated-state.h"
15 #include "src/diagnostics/code-tracer.h"
16 #include "src/objects/js-function.h"
17 
18 #if V8_ENABLE_WEBASSEMBLY
19 #include "src/wasm/value-type.h"
20 #endif  // V8_ENABLE_WEBASSEMBLY
21 
22 namespace v8 {
23 namespace internal {
24 
25 enum class BuiltinContinuationMode;
26 
27 class DeoptimizedFrameInfo;
28 class Isolate;
29 
30 class Deoptimizer : public Malloced {
31  public:
32   struct DeoptInfo {
DeoptInfoDeoptInfo33     DeoptInfo(SourcePosition position, DeoptimizeReason deopt_reason,
34               uint32_t node_id, int deopt_id)
35         : position(position),
36           deopt_reason(deopt_reason),
37           node_id(node_id),
38           deopt_id(deopt_id) {}
39 
40     const SourcePosition position;
41     const DeoptimizeReason deopt_reason;
42     const uint32_t node_id;
43     const int deopt_id;
44   };
45 
46   static DeoptInfo GetDeoptInfo(Code code, Address from);
47 
48   static int ComputeSourcePositionFromBytecodeArray(
49       Isolate* isolate, SharedFunctionInfo shared,
50       BytecodeOffset bytecode_offset);
51 
52   static const char* MessageFor(DeoptimizeKind kind);
53 
54   Handle<JSFunction> function() const;
55   Handle<Code> compiled_code() const;
deopt_kind()56   DeoptimizeKind deopt_kind() const { return deopt_kind_; }
57 
58   static Deoptimizer* New(Address raw_function, DeoptimizeKind kind,
59                           Address from, int fp_to_sp_delta, Isolate* isolate);
60   static Deoptimizer* Grab(Isolate* isolate);
61 
62   // The returned object with information on the optimized frame needs to be
63   // freed before another one can be generated.
64   static DeoptimizedFrameInfo* DebuggerInspectableFrame(JavaScriptFrame* frame,
65                                                         int jsframe_index,
66                                                         Isolate* isolate);
67 
68   // Deoptimize the function now. Its current optimized code will never be run
69   // again and any activations of the optimized code will get deoptimized when
70   // execution returns. If {code} is specified then the given code is targeted
71   // instead of the function code (e.g. OSR code not installed on function).
72   static void DeoptimizeFunction(JSFunction function, Code code = Code());
73 
74   // Deoptimize all code in the given isolate.
75   V8_EXPORT_PRIVATE static void DeoptimizeAll(Isolate* isolate);
76 
77   // Deoptimizes all optimized code that has been previously marked
78   // (via code->set_marked_for_deoptimization) and unlinks all functions that
79   // refer to that code.
80   static void DeoptimizeMarkedCode(Isolate* isolate);
81 
82   // Check the given address against a list of allowed addresses, to prevent a
83   // potential attacker from using the frame creation process in the
84   // deoptimizer, in particular the signing process, to gain control over the
85   // program.
86   // When building mksnapshot, always return false.
87   static bool IsValidReturnAddress(Address address);
88 
89   ~Deoptimizer();
90 
91   void MaterializeHeapObjects();
92 
93   static void ComputeOutputFrames(Deoptimizer* deoptimizer);
94 
95   V8_EXPORT_PRIVATE static Builtin GetDeoptimizationEntry(DeoptimizeKind kind);
96 
97   // Returns true if {addr} is a deoptimization entry and stores its type in
98   // {type_out}. Returns false if {addr} is not a deoptimization entry.
99   static bool IsDeoptimizationEntry(Isolate* isolate, Address addr,
100                                     DeoptimizeKind* type_out);
101 
102   // Code generation support.
input_offset()103   static int input_offset() { return offsetof(Deoptimizer, input_); }
output_count_offset()104   static int output_count_offset() {
105     return offsetof(Deoptimizer, output_count_);
106   }
output_offset()107   static int output_offset() { return offsetof(Deoptimizer, output_); }
108 
caller_frame_top_offset()109   static int caller_frame_top_offset() {
110     return offsetof(Deoptimizer, caller_frame_top_);
111   }
112 
113   V8_EXPORT_PRIVATE static int GetDeoptimizedCodeCount(Isolate* isolate);
114 
isolate()115   Isolate* isolate() const { return isolate_; }
116 
117   static constexpr int kMaxNumberOfEntries = 16384;
118 
119   // This marker is passed to Deoptimizer::New as {deopt_exit_index} on
120   // platforms that have fixed deopt sizes. The actual deoptimization id is then
121   // calculated from the return address.
122   static constexpr unsigned kFixedExitSizeMarker = kMaxUInt32;
123 
124   // Size of deoptimization exit sequence.
125   V8_EXPORT_PRIVATE static const int kEagerDeoptExitSize;
126   V8_EXPORT_PRIVATE static const int kLazyDeoptExitSize;
127 
128   // Tracing.
129   static void TraceMarkForDeoptimization(Code code, const char* reason);
130   static void TraceEvictFromOptimizedCodeCache(SharedFunctionInfo sfi,
131                                                const char* reason);
132 
133  private:
134   void QueueValueForMaterialization(Address output_address, Object obj,
135                                     const TranslatedFrame::iterator& iterator);
136 
137   Deoptimizer(Isolate* isolate, JSFunction function, DeoptimizeKind kind,
138               Address from, int fp_to_sp_delta);
139   Code FindOptimizedCode();
140   void DeleteFrameDescriptions();
141 
142   void DoComputeOutputFrames();
143   void DoComputeUnoptimizedFrame(TranslatedFrame* translated_frame,
144                                  int frame_index, bool goto_catch_handler);
145   void DoComputeArgumentsAdaptorFrame(TranslatedFrame* translated_frame,
146                                       int frame_index);
147   void DoComputeConstructStubFrame(TranslatedFrame* translated_frame,
148                                    int frame_index);
149 
150   static Builtin TrampolineForBuiltinContinuation(BuiltinContinuationMode mode,
151                                                   bool must_handle_result);
152 
153 #if V8_ENABLE_WEBASSEMBLY
154   TranslatedValue TranslatedValueForWasmReturnKind(
155       base::Optional<wasm::ValueKind> wasm_call_return_kind);
156 #endif  // V8_ENABLE_WEBASSEMBLY
157 
158   void DoComputeBuiltinContinuation(TranslatedFrame* translated_frame,
159                                     int frame_index,
160                                     BuiltinContinuationMode mode);
161 
162   unsigned ComputeInputFrameAboveFpFixedSize() const;
163   unsigned ComputeInputFrameSize() const;
164 
165   static unsigned ComputeIncomingArgumentSize(SharedFunctionInfo shared);
166 
167   static void MarkAllCodeForContext(NativeContext native_context);
168   static void DeoptimizeMarkedCodeForContext(NativeContext native_context);
169   // Searches the list of known deoptimizing code for a Code object
170   // containing the given address (which is supposedly faster than
171   // searching all code objects).
172   Code FindDeoptimizingCode(Address addr);
173 
174   // Tracing.
tracing_enabled()175   bool tracing_enabled() const { return trace_scope_ != nullptr; }
verbose_tracing_enabled()176   bool verbose_tracing_enabled() const {
177     return FLAG_trace_deopt_verbose && tracing_enabled();
178   }
trace_scope()179   CodeTracer::Scope* trace_scope() const { return trace_scope_; }
verbose_trace_scope()180   CodeTracer::Scope* verbose_trace_scope() const {
181     return FLAG_trace_deopt_verbose ? trace_scope() : nullptr;
182   }
183   void TraceDeoptBegin(int optimization_id, BytecodeOffset bytecode_offset);
184   void TraceDeoptEnd(double deopt_duration);
185 #ifdef DEBUG
186   static void TraceFoundActivation(Isolate* isolate, JSFunction function);
187 #endif
188   static void TraceDeoptAll(Isolate* isolate);
189   static void TraceDeoptMarked(Isolate* isolate);
190 
191   Isolate* isolate_;
192   JSFunction function_;
193   Code compiled_code_;
194   unsigned deopt_exit_index_;
195   DeoptimizeKind deopt_kind_;
196   Address from_;
197   int fp_to_sp_delta_;
198   bool deoptimizing_throw_;
199   int catch_handler_data_;
200   int catch_handler_pc_offset_;
201 
202   // Input frame description.
203   FrameDescription* input_;
204   // Number of output frames.
205   int output_count_;
206   // Array of output frame descriptions.
207   FrameDescription** output_;
208 
209   // Caller frame details computed from input frame.
210   intptr_t caller_frame_top_;
211   intptr_t caller_fp_;
212   intptr_t caller_pc_;
213   intptr_t caller_constant_pool_;
214 
215   // The argument count of the bottom most frame.
216   int actual_argument_count_;
217 
218   // Key for lookup of previously materialized objects.
219   intptr_t stack_fp_;
220 
221   TranslatedState translated_state_;
222   struct ValueToMaterialize {
223     Address output_slot_address_;
224     TranslatedFrame::iterator value_;
225   };
226   std::vector<ValueToMaterialize> values_to_materialize_;
227 
228 #ifdef DEBUG
229   DisallowGarbageCollection* disallow_garbage_collection_;
230 #endif  // DEBUG
231 
232   // Note: This is intentionally not a unique_ptr s.t. the Deoptimizer
233   // satisfies is_standard_layout, needed for offsetof().
234   CodeTracer::Scope* const trace_scope_;
235 
236   friend class DeoptimizedFrameInfo;
237   friend class FrameDescription;
238   friend class FrameWriter;
239 };
240 
241 }  // namespace internal
242 }  // namespace v8
243 
244 #endif  // V8_DEOPTIMIZER_DEOPTIMIZER_H_
245