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