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_FRAMES_H_ |
6 | #define V8_FRAMES_H_ |
7 | |
8 | #include "src/handles.h" |
9 | #include "src/objects.h" |
10 | #include "src/objects/code.h" |
11 | #include "src/safepoint-table.h" |
12 | |
13 | namespace v8 { |
14 | namespace internal { |
15 | namespace wasm { |
16 | class WasmCode; |
17 | } |
18 | |
19 | // Forward declarations. |
20 | class AbstractCode; |
21 | class Debug; |
22 | class ExternalCallbackScope; |
23 | class InnerPointerToCodeCache; |
24 | class Isolate; |
25 | class ObjectVisitor; |
26 | class RootVisitor; |
27 | class StackFrameIteratorBase; |
28 | class StringStream; |
29 | class ThreadLocalTop; |
30 | class WasmDebugInfo; |
31 | class WasmInstanceObject; |
32 | class WasmModuleObject; |
33 | |
34 | class StackHandlerConstants : public AllStatic { |
35 | public: |
36 | static const int kNextOffset = 0 * kSystemPointerSize; |
37 | static const int kPaddingOffset = 1 * kSystemPointerSize; |
38 | |
39 | static const int kSize = kPaddingOffset + kSystemPointerSize; |
40 | static const int kSlotCount = kSize >> kSystemPointerSizeLog2; |
41 | }; |
42 | |
43 | class StackHandler { |
44 | public: |
45 | // Get the address of this stack handler. |
46 | inline Address address() const; |
47 | |
48 | // Get the next stack handler in the chain. |
49 | inline StackHandler* next() const; |
50 | |
51 | // Get the next stack handler, as an Address. This is safe to use even |
52 | // when the next handler is null. |
53 | inline Address next_address() const; |
54 | |
55 | // Conversion support. |
56 | static inline StackHandler* FromAddress(Address address); |
57 | |
58 | private: |
59 | DISALLOW_IMPLICIT_CONSTRUCTORS(StackHandler); |
60 | }; |
61 | |
62 | #define STACK_FRAME_TYPE_LIST(V) \ |
63 | V(ENTRY, EntryFrame) \ |
64 | V(CONSTRUCT_ENTRY, ConstructEntryFrame) \ |
65 | V(EXIT, ExitFrame) \ |
66 | V(OPTIMIZED, OptimizedFrame) \ |
67 | V(WASM_COMPILED, WasmCompiledFrame) \ |
68 | V(WASM_TO_JS, WasmToJsFrame) \ |
69 | V(JS_TO_WASM, JsToWasmFrame) \ |
70 | V(WASM_INTERPRETER_ENTRY, WasmInterpreterEntryFrame) \ |
71 | V(C_WASM_ENTRY, CWasmEntryFrame) \ |
72 | V(WASM_COMPILE_LAZY, WasmCompileLazyFrame) \ |
73 | V(INTERPRETED, InterpretedFrame) \ |
74 | V(STUB, StubFrame) \ |
75 | V(BUILTIN_CONTINUATION, BuiltinContinuationFrame) \ |
76 | V(JAVA_SCRIPT_BUILTIN_CONTINUATION, JavaScriptBuiltinContinuationFrame) \ |
77 | V(JAVA_SCRIPT_BUILTIN_CONTINUATION_WITH_CATCH, \ |
78 | JavaScriptBuiltinContinuationWithCatchFrame) \ |
79 | V(INTERNAL, InternalFrame) \ |
80 | V(CONSTRUCT, ConstructFrame) \ |
81 | V(ARGUMENTS_ADAPTOR, ArgumentsAdaptorFrame) \ |
82 | V(BUILTIN, BuiltinFrame) \ |
83 | V(BUILTIN_EXIT, BuiltinExitFrame) \ |
84 | V(NATIVE, NativeFrame) |
85 | |
86 | // Abstract base class for all stack frames. |
87 | class StackFrame { |
88 | public: |
89 | #define DECLARE_TYPE(type, ignore) type, |
90 | enum Type { |
91 | NONE = 0, |
92 | STACK_FRAME_TYPE_LIST(DECLARE_TYPE) |
93 | NUMBER_OF_TYPES, |
94 | // Used by FrameScope to indicate that the stack frame is constructed |
95 | // manually and the FrameScope does not need to emit code. |
96 | MANUAL |
97 | }; |
98 | #undef DECLARE_TYPE |
99 | |
100 | // Opaque data type for identifying stack frames. Used extensively |
101 | // by the debugger. |
102 | // ID_MIN_VALUE and ID_MAX_VALUE are specified to ensure that enumeration type |
103 | // has correct value range (see Issue 830 for more details). |
104 | enum Id { |
105 | ID_MIN_VALUE = kMinInt, |
106 | ID_MAX_VALUE = kMaxInt, |
107 | NO_ID = 0 |
108 | }; |
109 | |
110 | // Used to mark the outermost JS entry frame. |
111 | // |
112 | // The mark is an opaque value that should be pushed onto the stack directly, |
113 | // carefully crafted to not be interpreted as a tagged pointer. |
114 | enum JsFrameMarker { |
115 | INNER_JSENTRY_FRAME = (0 << kSmiTagSize) | kSmiTag, |
116 | OUTERMOST_JSENTRY_FRAME = (1 << kSmiTagSize) | kSmiTag |
117 | }; |
118 | STATIC_ASSERT((INNER_JSENTRY_FRAME & kHeapObjectTagMask) != kHeapObjectTag); |
119 | STATIC_ASSERT((OUTERMOST_JSENTRY_FRAME & kHeapObjectTagMask) != |
120 | kHeapObjectTag); |
121 | |
122 | struct State { |
123 | Address sp = kNullAddress; |
124 | Address fp = kNullAddress; |
125 | Address* pc_address = nullptr; |
126 | Address* callee_pc_address = nullptr; |
127 | Address* constant_pool_address = nullptr; |
128 | }; |
129 | |
130 | // Convert a stack frame type to a marker that can be stored on the stack. |
131 | // |
132 | // The marker is an opaque value, not intended to be interpreted in any way |
133 | // except being checked by IsTypeMarker or converted by MarkerToType. |
134 | // It has the same tagging as Smis, so any marker value that does not pass |
135 | // IsTypeMarker can instead be interpreted as a tagged pointer. |
136 | // |
137 | // Note that the marker is not a Smi: Smis on 64-bit architectures are stored |
138 | // in the top 32 bits of a 64-bit value, which in turn makes them expensive |
139 | // (in terms of code/instruction size) to push as immediates onto the stack. |
140 | static int32_t TypeToMarker(Type type) { |
141 | DCHECK_GE(type, 0); |
142 | return (type << kSmiTagSize) | kSmiTag; |
143 | } |
144 | |
145 | // Convert a marker back to a stack frame type. |
146 | // |
147 | // Unlike the return value of TypeToMarker, this takes an intptr_t, as that is |
148 | // the type of the value on the stack. |
149 | static Type MarkerToType(intptr_t marker) { |
150 | DCHECK(IsTypeMarker(marker)); |
151 | return static_cast<Type>(marker >> kSmiTagSize); |
152 | } |
153 | |
154 | // Check if a marker is a stack frame type marker or a tagged pointer. |
155 | // |
156 | // Returns true if the given marker is tagged as a stack frame type marker, |
157 | // and should be converted back to a stack frame type using MarkerToType. |
158 | // Otherwise, the value is a tagged function pointer. |
159 | static bool IsTypeMarker(intptr_t function_or_marker) { |
160 | return (function_or_marker & kSmiTagMask) == kSmiTag; |
161 | } |
162 | |
163 | // Copy constructor; it breaks the connection to host iterator |
164 | // (as an iterator usually lives on stack). |
165 | StackFrame(const StackFrame& original) V8_NOEXCEPT { |
166 | this->state_ = original.state_; |
167 | this->iterator_ = nullptr; |
168 | this->isolate_ = original.isolate_; |
169 | } |
170 | |
171 | // Type testers. |
172 | bool is_entry() const { return type() == ENTRY; } |
173 | bool is_construct_entry() const { return type() == CONSTRUCT_ENTRY; } |
174 | bool is_exit() const { return type() == EXIT; } |
175 | bool is_optimized() const { return type() == OPTIMIZED; } |
176 | bool is_interpreted() const { return type() == INTERPRETED; } |
177 | bool is_wasm_compiled() const { return type() == WASM_COMPILED; } |
178 | bool is_wasm_compile_lazy() const { return type() == WASM_COMPILE_LAZY; } |
179 | bool is_wasm_to_js() const { return type() == WASM_TO_JS; } |
180 | bool is_js_to_wasm() const { return type() == JS_TO_WASM; } |
181 | bool is_wasm_interpreter_entry() const { |
182 | return type() == WASM_INTERPRETER_ENTRY; |
183 | } |
184 | bool is_arguments_adaptor() const { return type() == ARGUMENTS_ADAPTOR; } |
185 | bool is_builtin() const { return type() == BUILTIN; } |
186 | bool is_internal() const { return type() == INTERNAL; } |
187 | bool is_builtin_continuation() const { |
188 | return type() == BUILTIN_CONTINUATION; |
189 | } |
190 | bool is_java_script_builtin_continuation() const { |
191 | return type() == JAVA_SCRIPT_BUILTIN_CONTINUATION; |
192 | } |
193 | bool is_java_script_builtin_with_catch_continuation() const { |
194 | return type() == JAVA_SCRIPT_BUILTIN_CONTINUATION_WITH_CATCH; |
195 | } |
196 | bool is_construct() const { return type() == CONSTRUCT; } |
197 | bool is_builtin_exit() const { return type() == BUILTIN_EXIT; } |
198 | virtual bool is_standard() const { return false; } |
199 | |
200 | bool is_java_script() const { |
201 | Type type = this->type(); |
202 | return (type == OPTIMIZED) || (type == INTERPRETED) || (type == BUILTIN) || |
203 | (type == JAVA_SCRIPT_BUILTIN_CONTINUATION) || |
204 | (type == JAVA_SCRIPT_BUILTIN_CONTINUATION_WITH_CATCH); |
205 | } |
206 | bool is_wasm() const { |
207 | Type type = this->type(); |
208 | return type == WASM_COMPILED || type == WASM_INTERPRETER_ENTRY; |
209 | } |
210 | |
211 | // Accessors. |
212 | Address sp() const { return state_.sp; } |
213 | Address fp() const { return state_.fp; } |
214 | Address callee_pc() const { |
215 | return state_.callee_pc_address ? *state_.callee_pc_address : kNullAddress; |
216 | } |
217 | Address caller_sp() const { return GetCallerStackPointer(); } |
218 | |
219 | // If this frame is optimized and was dynamically aligned return its old |
220 | // unaligned frame pointer. When the frame is deoptimized its FP will shift |
221 | // up one word and become unaligned. |
222 | Address UnpaddedFP() const; |
223 | |
224 | Address pc() const { return *pc_address(); } |
225 | void set_pc(Address pc) { *pc_address() = pc; } |
226 | |
227 | Address constant_pool() const { return *constant_pool_address(); } |
228 | void set_constant_pool(Address constant_pool) { |
229 | *constant_pool_address() = constant_pool; |
230 | } |
231 | |
232 | Address* pc_address() const { return state_.pc_address; } |
233 | |
234 | Address* constant_pool_address() const { |
235 | return state_.constant_pool_address; |
236 | } |
237 | |
238 | // Get the id of this stack frame. |
239 | Id id() const { return static_cast<Id>(caller_sp()); } |
240 | |
241 | // Get the top handler from the current stack iterator. |
242 | inline StackHandler* top_handler() const; |
243 | |
244 | // Get the type of this frame. |
245 | virtual Type type() const = 0; |
246 | |
247 | // Get the code associated with this frame. |
248 | // This method could be called during marking phase of GC. |
249 | virtual Code unchecked_code() const = 0; |
250 | |
251 | // Search for the code associated with this frame. |
252 | V8_EXPORT_PRIVATE Code LookupCode() const; |
253 | |
254 | virtual void Iterate(RootVisitor* v) const = 0; |
255 | static void IteratePc(RootVisitor* v, Address* pc_address, |
256 | Address* constant_pool_address, Code holder); |
257 | |
258 | // Sets a callback function for return-address rewriting profilers |
259 | // to resolve the location of a return address to the location of the |
260 | // profiler's stashed return address. |
261 | static void SetReturnAddressLocationResolver( |
262 | ReturnAddressLocationResolver resolver); |
263 | |
264 | // Resolves pc_address through the resolution address function if one is set. |
265 | static inline Address* ResolveReturnAddressLocation(Address* pc_address); |
266 | |
267 | // Printing support. |
268 | enum PrintMode { OVERVIEW, DETAILS }; |
269 | virtual void Print(StringStream* accumulator, PrintMode mode, |
270 | int index) const; |
271 | |
272 | Isolate* isolate() const { return isolate_; } |
273 | |
274 | void operator=(const StackFrame& original) = delete; |
275 | |
276 | protected: |
277 | inline explicit StackFrame(StackFrameIteratorBase* iterator); |
278 | virtual ~StackFrame() = default; |
279 | |
280 | // Compute the stack pointer for the calling frame. |
281 | virtual Address GetCallerStackPointer() const = 0; |
282 | |
283 | // Compute the stack frame type for the given state. |
284 | static Type ComputeType(const StackFrameIteratorBase* iterator, State* state); |
285 | |
286 | #ifdef DEBUG |
287 | bool can_access_heap_objects() const; |
288 | #endif |
289 | |
290 | private: |
291 | const StackFrameIteratorBase* iterator_; |
292 | Isolate* isolate_; |
293 | State state_; |
294 | |
295 | static ReturnAddressLocationResolver return_address_location_resolver_; |
296 | |
297 | // Fill in the state of the calling frame. |
298 | virtual void ComputeCallerState(State* state) const = 0; |
299 | |
300 | // Get the type and the state of the calling frame. |
301 | virtual Type GetCallerState(State* state) const; |
302 | |
303 | static const intptr_t kIsolateTag = 1; |
304 | |
305 | friend class StackFrameIterator; |
306 | friend class StackFrameIteratorBase; |
307 | friend class StackHandlerIterator; |
308 | friend class SafeStackFrameIterator; |
309 | }; |
310 | |
311 | class NativeFrame : public StackFrame { |
312 | public: |
313 | Type type() const override { return NATIVE; } |
314 | |
315 | Code unchecked_code() const override; |
316 | |
317 | // Garbage collection support. |
318 | void Iterate(RootVisitor* v) const override {} |
319 | |
320 | protected: |
321 | inline explicit NativeFrame(StackFrameIteratorBase* iterator); |
322 | |
323 | Address GetCallerStackPointer() const override; |
324 | |
325 | private: |
326 | void ComputeCallerState(State* state) const override; |
327 | |
328 | friend class StackFrameIteratorBase; |
329 | }; |
330 | |
331 | // Entry frames are used to enter JavaScript execution from C. |
332 | class EntryFrame: public StackFrame { |
333 | public: |
334 | Type type() const override { return ENTRY; } |
335 | |
336 | Code unchecked_code() const override; |
337 | |
338 | // Garbage collection support. |
339 | void Iterate(RootVisitor* v) const override; |
340 | |
341 | static EntryFrame* cast(StackFrame* frame) { |
342 | DCHECK(frame->is_entry()); |
343 | return static_cast<EntryFrame*>(frame); |
344 | } |
345 | |
346 | protected: |
347 | inline explicit EntryFrame(StackFrameIteratorBase* iterator); |
348 | |
349 | // The caller stack pointer for entry frames is always zero. The |
350 | // real information about the caller frame is available through the |
351 | // link to the top exit frame. |
352 | Address GetCallerStackPointer() const override { return 0; } |
353 | |
354 | private: |
355 | void ComputeCallerState(State* state) const override; |
356 | Type GetCallerState(State* state) const override; |
357 | |
358 | friend class StackFrameIteratorBase; |
359 | }; |
360 | |
361 | class ConstructEntryFrame : public EntryFrame { |
362 | public: |
363 | Type type() const override { return CONSTRUCT_ENTRY; } |
364 | |
365 | Code unchecked_code() const override; |
366 | |
367 | static ConstructEntryFrame* cast(StackFrame* frame) { |
368 | DCHECK(frame->is_construct_entry()); |
369 | return static_cast<ConstructEntryFrame*>(frame); |
370 | } |
371 | |
372 | protected: |
373 | inline explicit ConstructEntryFrame(StackFrameIteratorBase* iterator); |
374 | |
375 | private: |
376 | friend class StackFrameIteratorBase; |
377 | }; |
378 | |
379 | |
380 | // Exit frames are used to exit JavaScript execution and go to C. |
381 | class ExitFrame: public StackFrame { |
382 | public: |
383 | Type type() const override { return EXIT; } |
384 | |
385 | Code unchecked_code() const override; |
386 | |
387 | // Garbage collection support. |
388 | void Iterate(RootVisitor* v) const override; |
389 | |
390 | static ExitFrame* cast(StackFrame* frame) { |
391 | DCHECK(frame->is_exit()); |
392 | return static_cast<ExitFrame*>(frame); |
393 | } |
394 | |
395 | // Compute the state and type of an exit frame given a frame |
396 | // pointer. Used when constructing the first stack frame seen by an |
397 | // iterator and the frames following entry frames. |
398 | static Type GetStateForFramePointer(Address fp, State* state); |
399 | static Address ComputeStackPointer(Address fp); |
400 | static StackFrame::Type ComputeFrameType(Address fp); |
401 | static void FillState(Address fp, Address sp, State* state); |
402 | |
403 | protected: |
404 | inline explicit ExitFrame(StackFrameIteratorBase* iterator); |
405 | |
406 | Address GetCallerStackPointer() const override; |
407 | |
408 | private: |
409 | void ComputeCallerState(State* state) const override; |
410 | |
411 | friend class StackFrameIteratorBase; |
412 | }; |
413 | |
414 | // Builtin exit frames are a special case of exit frames, which are used |
415 | // whenever C++ builtins (e.g., Math.acos) are called. Their main purpose is |
416 | // to allow such builtins to appear in stack traces. |
417 | class BuiltinExitFrame : public ExitFrame { |
418 | public: |
419 | Type type() const override { return BUILTIN_EXIT; } |
420 | |
421 | static BuiltinExitFrame* cast(StackFrame* frame) { |
422 | DCHECK(frame->is_builtin_exit()); |
423 | return static_cast<BuiltinExitFrame*>(frame); |
424 | } |
425 | |
426 | JSFunction function() const; |
427 | Object receiver() const; |
428 | |
429 | bool IsConstructor() const; |
430 | |
431 | void Print(StringStream* accumulator, PrintMode mode, |
432 | int index) const override; |
433 | |
434 | protected: |
435 | inline explicit BuiltinExitFrame(StackFrameIteratorBase* iterator); |
436 | |
437 | private: |
438 | Object GetParameter(int i) const; |
439 | int ComputeParametersCount() const; |
440 | |
441 | inline Object receiver_slot_object() const; |
442 | inline Object argc_slot_object() const; |
443 | inline Object target_slot_object() const; |
444 | inline Object new_target_slot_object() const; |
445 | |
446 | friend class StackFrameIteratorBase; |
447 | friend class FrameArrayBuilder; |
448 | }; |
449 | |
450 | class StandardFrame; |
451 | |
452 | class V8_EXPORT_PRIVATE FrameSummary { |
453 | public: |
454 | // Subclasses for the different summary kinds: |
455 | #define FRAME_SUMMARY_VARIANTS(F) \ |
456 | F(JAVA_SCRIPT, JavaScriptFrameSummary, java_script_summary_, JavaScript) \ |
457 | F(WASM_COMPILED, WasmCompiledFrameSummary, wasm_compiled_summary_, \ |
458 | WasmCompiled) \ |
459 | F(WASM_INTERPRETED, WasmInterpretedFrameSummary, wasm_interpreted_summary_, \ |
460 | WasmInterpreted) |
461 | |
462 | #define FRAME_SUMMARY_KIND(kind, type, field, desc) kind, |
463 | enum Kind { FRAME_SUMMARY_VARIANTS(FRAME_SUMMARY_KIND) }; |
464 | #undef FRAME_SUMMARY_KIND |
465 | |
466 | class FrameSummaryBase { |
467 | public: |
468 | FrameSummaryBase(Isolate* isolate, Kind kind) |
469 | : isolate_(isolate), kind_(kind) {} |
470 | Isolate* isolate() const { return isolate_; } |
471 | Kind kind() const { return kind_; } |
472 | |
473 | private: |
474 | Isolate* isolate_; |
475 | Kind kind_; |
476 | }; |
477 | |
478 | class JavaScriptFrameSummary : public FrameSummaryBase { |
479 | public: |
480 | JavaScriptFrameSummary(Isolate* isolate, Object receiver, |
481 | JSFunction function, AbstractCode abstract_code, |
482 | int code_offset, bool is_constructor, |
483 | FixedArray parameters); |
484 | |
485 | void EnsureSourcePositionsAvailable(); |
486 | |
487 | Handle<Object> receiver() const { return receiver_; } |
488 | Handle<JSFunction> function() const { return function_; } |
489 | Handle<AbstractCode> abstract_code() const { return abstract_code_; } |
490 | int code_offset() const { return code_offset_; } |
491 | bool is_constructor() const { return is_constructor_; } |
492 | Handle<FixedArray> parameters() const { return parameters_; } |
493 | bool is_subject_to_debugging() const; |
494 | int SourcePosition() const; |
495 | int SourceStatementPosition() const; |
496 | Handle<Object> script() const; |
497 | Handle<String> FunctionName() const; |
498 | Handle<Context> native_context() const; |
499 | |
500 | private: |
501 | Handle<Object> receiver_; |
502 | Handle<JSFunction> function_; |
503 | Handle<AbstractCode> abstract_code_; |
504 | int code_offset_; |
505 | bool is_constructor_; |
506 | Handle<FixedArray> parameters_; |
507 | }; |
508 | |
509 | class WasmFrameSummary : public FrameSummaryBase { |
510 | protected: |
511 | WasmFrameSummary(Isolate*, Kind, Handle<WasmInstanceObject>, |
512 | bool at_to_number_conversion); |
513 | |
514 | public: |
515 | Handle<Object> receiver() const; |
516 | uint32_t function_index() const; |
517 | int byte_offset() const; |
518 | bool is_constructor() const { return false; } |
519 | bool is_subject_to_debugging() const { return true; } |
520 | int SourcePosition() const; |
521 | int SourceStatementPosition() const { return SourcePosition(); } |
522 | Handle<Script> script() const; |
523 | Handle<WasmInstanceObject> wasm_instance() const { return wasm_instance_; } |
524 | Handle<String> FunctionName() const; |
525 | Handle<Context> native_context() const; |
526 | bool at_to_number_conversion() const { return at_to_number_conversion_; } |
527 | |
528 | private: |
529 | Handle<WasmInstanceObject> wasm_instance_; |
530 | bool at_to_number_conversion_; |
531 | }; |
532 | |
533 | class WasmCompiledFrameSummary : public WasmFrameSummary { |
534 | public: |
535 | WasmCompiledFrameSummary(Isolate*, Handle<WasmInstanceObject>, |
536 | wasm::WasmCode*, int code_offset, |
537 | bool at_to_number_conversion); |
538 | uint32_t function_index() const; |
539 | wasm::WasmCode* code() const { return code_; } |
540 | int code_offset() const { return code_offset_; } |
541 | int byte_offset() const; |
542 | static int GetWasmSourcePosition(const wasm::WasmCode* code, int offset); |
543 | |
544 | private: |
545 | wasm::WasmCode* const code_; |
546 | int code_offset_; |
547 | }; |
548 | |
549 | class WasmInterpretedFrameSummary : public WasmFrameSummary { |
550 | public: |
551 | WasmInterpretedFrameSummary(Isolate*, Handle<WasmInstanceObject>, |
552 | uint32_t function_index, int byte_offset); |
553 | uint32_t function_index() const { return function_index_; } |
554 | int code_offset() const { return byte_offset_; } |
555 | int byte_offset() const { return byte_offset_; } |
556 | |
557 | private: |
558 | uint32_t function_index_; |
559 | int byte_offset_; |
560 | }; |
561 | |
562 | #define FRAME_SUMMARY_CONS(kind, type, field, desc) \ |
563 | FrameSummary(type summ) : field(summ) {} // NOLINT |
564 | FRAME_SUMMARY_VARIANTS(FRAME_SUMMARY_CONS) |
565 | #undef FRAME_SUMMARY_CONS |
566 | |
567 | ~FrameSummary(); |
568 | |
569 | static FrameSummary GetTop(const StandardFrame* frame); |
570 | static FrameSummary GetBottom(const StandardFrame* frame); |
571 | static FrameSummary GetSingle(const StandardFrame* frame); |
572 | static FrameSummary Get(const StandardFrame* frame, int index); |
573 | |
574 | void EnsureSourcePositionsAvailable(); |
575 | |
576 | // Dispatched accessors. |
577 | Handle<Object> receiver() const; |
578 | int code_offset() const; |
579 | bool is_constructor() const; |
580 | bool is_subject_to_debugging() const; |
581 | Handle<Object> script() const; |
582 | int SourcePosition() const; |
583 | int SourceStatementPosition() const; |
584 | Handle<String> FunctionName() const; |
585 | Handle<Context> native_context() const; |
586 | |
587 | #define FRAME_SUMMARY_CAST(kind_, type, field, desc) \ |
588 | bool Is##desc() const { return base_.kind() == kind_; } \ |
589 | const type& As##desc() const { \ |
590 | DCHECK_EQ(base_.kind(), kind_); \ |
591 | return field; \ |
592 | } |
593 | FRAME_SUMMARY_VARIANTS(FRAME_SUMMARY_CAST) |
594 | #undef FRAME_SUMMARY_CAST |
595 | |
596 | bool IsWasm() const { return IsWasmCompiled() || IsWasmInterpreted(); } |
597 | const WasmFrameSummary& AsWasm() const { |
598 | if (IsWasmCompiled()) return AsWasmCompiled(); |
599 | return AsWasmInterpreted(); |
600 | } |
601 | |
602 | private: |
603 | #define FRAME_SUMMARY_FIELD(kind, type, field, desc) type field; |
604 | union { |
605 | FrameSummaryBase base_; |
606 | FRAME_SUMMARY_VARIANTS(FRAME_SUMMARY_FIELD) |
607 | }; |
608 | #undef FRAME_SUMMARY_FIELD |
609 | }; |
610 | |
611 | class StandardFrame : public StackFrame { |
612 | public: |
613 | // Testers. |
614 | bool is_standard() const override { return true; } |
615 | |
616 | // Accessors. |
617 | virtual Object receiver() const; |
618 | virtual Script script() const; |
619 | virtual Object context() const; |
620 | virtual int position() const; |
621 | |
622 | // Access the expressions in the stack frame including locals. |
623 | inline Object GetExpression(int index) const; |
624 | inline void SetExpression(int index, Object value); |
625 | int ComputeExpressionsCount() const; |
626 | |
627 | // Access the parameters. |
628 | virtual Object GetParameter(int index) const; |
629 | virtual int ComputeParametersCount() const; |
630 | |
631 | // Check if this frame is a constructor frame invoked through 'new'. |
632 | virtual bool IsConstructor() const; |
633 | |
634 | // Build a list with summaries for this frame including all inlined frames. |
635 | // The functions are ordered bottom-to-top (i.e. summaries.last() is the |
636 | // top-most activation; caller comes before callee). |
637 | virtual void Summarize(std::vector<FrameSummary>* frames) const; |
638 | |
639 | static StandardFrame* cast(StackFrame* frame) { |
640 | DCHECK(frame->is_standard()); |
641 | return static_cast<StandardFrame*>(frame); |
642 | } |
643 | |
644 | protected: |
645 | inline explicit StandardFrame(StackFrameIteratorBase* iterator); |
646 | |
647 | void ComputeCallerState(State* state) const override; |
648 | |
649 | // Accessors. |
650 | inline Address caller_fp() const; |
651 | inline Address caller_pc() const; |
652 | |
653 | // Computes the address of the PC field in the standard frame given |
654 | // by the provided frame pointer. |
655 | static inline Address ComputePCAddress(Address fp); |
656 | |
657 | // Computes the address of the constant pool field in the standard |
658 | // frame given by the provided frame pointer. |
659 | static inline Address ComputeConstantPoolAddress(Address fp); |
660 | |
661 | // Iterate over expression stack including stack handlers, locals, |
662 | // and parts of the fixed part including context and code fields. |
663 | void IterateExpressions(RootVisitor* v) const; |
664 | |
665 | // Returns the address of the n'th expression stack element. |
666 | virtual Address GetExpressionAddress(int n) const; |
667 | |
668 | // Determines if the standard frame for the given frame pointer is |
669 | // an arguments adaptor frame. |
670 | static inline bool IsArgumentsAdaptorFrame(Address fp); |
671 | |
672 | // Determines if the standard frame for the given frame pointer is a |
673 | // construct frame. |
674 | static inline bool IsConstructFrame(Address fp); |
675 | |
676 | // Used by OptimizedFrames and StubFrames. |
677 | void IterateCompiledFrame(RootVisitor* v) const; |
678 | |
679 | private: |
680 | friend class StackFrame; |
681 | friend class SafeStackFrameIterator; |
682 | }; |
683 | |
684 | class JavaScriptFrame : public StandardFrame { |
685 | public: |
686 | Type type() const override = 0; |
687 | |
688 | void Summarize(std::vector<FrameSummary>* frames) const override; |
689 | |
690 | // Accessors. |
691 | virtual JSFunction function() const; |
692 | Object unchecked_function() const; |
693 | Object receiver() const override; |
694 | Object context() const override; |
695 | Script script() const override; |
696 | |
697 | inline void set_receiver(Object value); |
698 | |
699 | // Access the parameters. |
700 | inline Address GetParameterSlot(int index) const; |
701 | Object GetParameter(int index) const override; |
702 | int ComputeParametersCount() const override; |
703 | Handle<FixedArray> GetParameters() const; |
704 | |
705 | // Debugger access. |
706 | void SetParameterValue(int index, Object value) const; |
707 | |
708 | // Check if this frame is a constructor frame invoked through 'new'. |
709 | bool IsConstructor() const override; |
710 | |
711 | // Determines whether this frame includes inlined activations. To get details |
712 | // about the inlined frames use {GetFunctions} and {Summarize}. |
713 | bool HasInlinedFrames() const; |
714 | |
715 | // Check if this frame has "adapted" arguments in the sense that the |
716 | // actual passed arguments are available in an arguments adaptor |
717 | // frame below it on the stack. |
718 | inline bool has_adapted_arguments() const; |
719 | |
720 | // Garbage collection support. |
721 | void Iterate(RootVisitor* v) const override; |
722 | |
723 | // Printing support. |
724 | void Print(StringStream* accumulator, PrintMode mode, |
725 | int index) const override; |
726 | |
727 | // Determine the code for the frame. |
728 | Code unchecked_code() const override; |
729 | |
730 | // Return a list with {SharedFunctionInfo} objects of this frame. |
731 | virtual void GetFunctions(std::vector<SharedFunctionInfo>* functions) const; |
732 | |
733 | void GetFunctions(std::vector<Handle<SharedFunctionInfo>>* functions) const; |
734 | |
735 | // Lookup exception handler for current {pc}, returns -1 if none found. Also |
736 | // returns data associated with the handler site specific to the frame type: |
737 | // - OptimizedFrame : Data is the stack slot count of the entire frame. |
738 | // - InterpretedFrame: Data is the register index holding the context. |
739 | virtual int LookupExceptionHandlerInTable( |
740 | int* data, HandlerTable::CatchPrediction* prediction); |
741 | |
742 | // Architecture-specific register description. |
743 | static Register fp_register(); |
744 | static Register context_register(); |
745 | static Register constant_pool_pointer_register(); |
746 | |
747 | static JavaScriptFrame* cast(StackFrame* frame) { |
748 | DCHECK(frame->is_java_script()); |
749 | return static_cast<JavaScriptFrame*>(frame); |
750 | } |
751 | |
752 | static void PrintFunctionAndOffset(JSFunction function, AbstractCode code, |
753 | int code_offset, FILE* file, |
754 | bool print_line_number); |
755 | |
756 | static void PrintTop(Isolate* isolate, FILE* file, bool print_args, |
757 | bool print_line_number); |
758 | |
759 | static void CollectFunctionAndOffsetForICStats(JSFunction function, |
760 | AbstractCode code, |
761 | int code_offset); |
762 | |
763 | protected: |
764 | inline explicit JavaScriptFrame(StackFrameIteratorBase* iterator); |
765 | |
766 | Address GetCallerStackPointer() const override; |
767 | |
768 | virtual void PrintFrameKind(StringStream* accumulator) const {} |
769 | |
770 | private: |
771 | inline Object function_slot_object() const; |
772 | |
773 | friend class StackFrameIteratorBase; |
774 | }; |
775 | |
776 | |
777 | class StubFrame : public StandardFrame { |
778 | public: |
779 | Type type() const override { return STUB; } |
780 | |
781 | // GC support. |
782 | void Iterate(RootVisitor* v) const override; |
783 | |
784 | // Determine the code for the frame. |
785 | Code unchecked_code() const override; |
786 | |
787 | // Lookup exception handler for current {pc}, returns -1 if none found. Only |
788 | // TurboFan stub frames are supported. Also returns data associated with the |
789 | // handler site: |
790 | // - TurboFan stub: Data is the stack slot count of the entire frame. |
791 | int LookupExceptionHandlerInTable(int* data); |
792 | |
793 | protected: |
794 | inline explicit StubFrame(StackFrameIteratorBase* iterator); |
795 | |
796 | Address GetCallerStackPointer() const override; |
797 | |
798 | friend class StackFrameIteratorBase; |
799 | }; |
800 | |
801 | |
802 | class OptimizedFrame : public JavaScriptFrame { |
803 | public: |
804 | Type type() const override { return OPTIMIZED; } |
805 | |
806 | // GC support. |
807 | void Iterate(RootVisitor* v) const override; |
808 | |
809 | // Return a list with {SharedFunctionInfo} objects of this frame. |
810 | // The functions are ordered bottom-to-top (i.e. functions.last() |
811 | // is the top-most activation) |
812 | void GetFunctions(std::vector<SharedFunctionInfo>* functions) const override; |
813 | |
814 | void Summarize(std::vector<FrameSummary>* frames) const override; |
815 | |
816 | // Lookup exception handler for current {pc}, returns -1 if none found. |
817 | int LookupExceptionHandlerInTable( |
818 | int* data, HandlerTable::CatchPrediction* prediction) override; |
819 | |
820 | DeoptimizationData GetDeoptimizationData(int* deopt_index) const; |
821 | |
822 | Object receiver() const override; |
823 | int ComputeParametersCount() const override; |
824 | |
825 | static int StackSlotOffsetRelativeToFp(int slot_index); |
826 | |
827 | protected: |
828 | inline explicit OptimizedFrame(StackFrameIteratorBase* iterator); |
829 | |
830 | |
831 | private: |
832 | friend class StackFrameIteratorBase; |
833 | |
834 | Object StackSlotAt(int index) const; |
835 | }; |
836 | |
837 | |
838 | class InterpretedFrame : public JavaScriptFrame { |
839 | public: |
840 | Type type() const override { return INTERPRETED; } |
841 | |
842 | // Accessors. |
843 | int position() const override; |
844 | |
845 | // Lookup exception handler for current {pc}, returns -1 if none found. |
846 | int LookupExceptionHandlerInTable( |
847 | int* data, HandlerTable::CatchPrediction* prediction) override; |
848 | |
849 | // Returns the current offset into the bytecode stream. |
850 | int GetBytecodeOffset() const; |
851 | |
852 | // Updates the current offset into the bytecode stream, mainly used for stack |
853 | // unwinding to continue execution at a different bytecode offset. |
854 | void PatchBytecodeOffset(int new_offset); |
855 | |
856 | // Returns the frame's current bytecode array. |
857 | BytecodeArray GetBytecodeArray() const; |
858 | |
859 | // Updates the frame's BytecodeArray with |bytecode_array|. Used by the |
860 | // debugger to swap execution onto a BytecodeArray patched with breakpoints. |
861 | void PatchBytecodeArray(BytecodeArray bytecode_array); |
862 | |
863 | // Access to the interpreter register file for this frame. |
864 | Object ReadInterpreterRegister(int register_index) const; |
865 | void WriteInterpreterRegister(int register_index, Object value); |
866 | |
867 | // Build a list with summaries for this frame including all inlined frames. |
868 | void Summarize(std::vector<FrameSummary>* frames) const override; |
869 | |
870 | static int GetBytecodeOffset(Address fp); |
871 | |
872 | static InterpretedFrame* cast(StackFrame* frame) { |
873 | DCHECK(frame->is_interpreted()); |
874 | return static_cast<InterpretedFrame*>(frame); |
875 | } |
876 | |
877 | protected: |
878 | inline explicit InterpretedFrame(StackFrameIteratorBase* iterator); |
879 | |
880 | Address GetExpressionAddress(int n) const override; |
881 | |
882 | private: |
883 | friend class StackFrameIteratorBase; |
884 | }; |
885 | |
886 | |
887 | // Arguments adaptor frames are automatically inserted below |
888 | // JavaScript frames when the actual number of parameters does not |
889 | // match the formal number of parameters. |
890 | class ArgumentsAdaptorFrame: public JavaScriptFrame { |
891 | public: |
892 | Type type() const override { return ARGUMENTS_ADAPTOR; } |
893 | |
894 | // Determine the code for the frame. |
895 | Code unchecked_code() const override; |
896 | |
897 | static ArgumentsAdaptorFrame* cast(StackFrame* frame) { |
898 | DCHECK(frame->is_arguments_adaptor()); |
899 | return static_cast<ArgumentsAdaptorFrame*>(frame); |
900 | } |
901 | |
902 | int ComputeParametersCount() const override; |
903 | |
904 | // Printing support. |
905 | void Print(StringStream* accumulator, PrintMode mode, |
906 | int index) const override; |
907 | |
908 | protected: |
909 | inline explicit ArgumentsAdaptorFrame(StackFrameIteratorBase* iterator); |
910 | |
911 | |
912 | private: |
913 | friend class StackFrameIteratorBase; |
914 | }; |
915 | |
916 | // Builtin frames are built for builtins with JavaScript linkage, such as |
917 | // various standard library functions (i.e. Math.asin, Math.floor, etc.). |
918 | class BuiltinFrame final : public JavaScriptFrame { |
919 | public: |
920 | Type type() const final { return BUILTIN; } |
921 | |
922 | static BuiltinFrame* cast(StackFrame* frame) { |
923 | DCHECK(frame->is_builtin()); |
924 | return static_cast<BuiltinFrame*>(frame); |
925 | } |
926 | int ComputeParametersCount() const final; |
927 | |
928 | protected: |
929 | inline explicit BuiltinFrame(StackFrameIteratorBase* iterator); |
930 | |
931 | void PrintFrameKind(StringStream* accumulator) const override; |
932 | |
933 | private: |
934 | friend class StackFrameIteratorBase; |
935 | }; |
936 | |
937 | class WasmCompiledFrame final : public StandardFrame { |
938 | public: |
939 | Type type() const override { return WASM_COMPILED; } |
940 | |
941 | // GC support. |
942 | void Iterate(RootVisitor* v) const override; |
943 | |
944 | // Printing support. |
945 | void Print(StringStream* accumulator, PrintMode mode, |
946 | int index) const override; |
947 | |
948 | // Lookup exception handler for current {pc}, returns -1 if none found. Also |
949 | // returns the stack slot count of the entire frame. |
950 | int LookupExceptionHandlerInTable(int* data); |
951 | |
952 | // Determine the code for the frame. |
953 | Code unchecked_code() const override; |
954 | |
955 | // Accessors. |
956 | WasmInstanceObject wasm_instance() const; |
957 | wasm::WasmCode* wasm_code() const; |
958 | uint32_t function_index() const; |
959 | Script script() const override; |
960 | int position() const override; |
961 | bool at_to_number_conversion() const; |
962 | |
963 | void Summarize(std::vector<FrameSummary>* frames) const override; |
964 | |
965 | static WasmCompiledFrame* cast(StackFrame* frame) { |
966 | DCHECK(frame->is_wasm_compiled()); |
967 | return static_cast<WasmCompiledFrame*>(frame); |
968 | } |
969 | |
970 | protected: |
971 | inline explicit WasmCompiledFrame(StackFrameIteratorBase* iterator); |
972 | |
973 | Address GetCallerStackPointer() const override; |
974 | |
975 | private: |
976 | friend class StackFrameIteratorBase; |
977 | WasmModuleObject module_object() const; |
978 | }; |
979 | |
980 | class WasmInterpreterEntryFrame final : public StandardFrame { |
981 | public: |
982 | Type type() const override { return WASM_INTERPRETER_ENTRY; } |
983 | |
984 | // GC support. |
985 | void Iterate(RootVisitor* v) const override; |
986 | |
987 | // Printing support. |
988 | void Print(StringStream* accumulator, PrintMode mode, |
989 | int index) const override; |
990 | |
991 | void Summarize(std::vector<FrameSummary>* frames) const override; |
992 | |
993 | // Determine the code for the frame. |
994 | Code unchecked_code() const override; |
995 | |
996 | // Accessors. |
997 | WasmDebugInfo debug_info() const; |
998 | WasmInstanceObject wasm_instance() const; |
999 | |
1000 | Script script() const override; |
1001 | int position() const override; |
1002 | Object context() const override; |
1003 | |
1004 | static WasmInterpreterEntryFrame* cast(StackFrame* frame) { |
1005 | DCHECK(frame->is_wasm_interpreter_entry()); |
1006 | return static_cast<WasmInterpreterEntryFrame*>(frame); |
1007 | } |
1008 | |
1009 | protected: |
1010 | inline explicit WasmInterpreterEntryFrame(StackFrameIteratorBase* iterator); |
1011 | |
1012 | Address GetCallerStackPointer() const override; |
1013 | |
1014 | private: |
1015 | friend class StackFrameIteratorBase; |
1016 | WasmModuleObject module_object() const; |
1017 | }; |
1018 | |
1019 | class WasmToJsFrame : public StubFrame { |
1020 | public: |
1021 | Type type() const override { return WASM_TO_JS; } |
1022 | |
1023 | protected: |
1024 | inline explicit WasmToJsFrame(StackFrameIteratorBase* iterator); |
1025 | |
1026 | private: |
1027 | friend class StackFrameIteratorBase; |
1028 | }; |
1029 | |
1030 | class JsToWasmFrame : public StubFrame { |
1031 | public: |
1032 | Type type() const override { return JS_TO_WASM; } |
1033 | |
1034 | protected: |
1035 | inline explicit JsToWasmFrame(StackFrameIteratorBase* iterator); |
1036 | |
1037 | private: |
1038 | friend class StackFrameIteratorBase; |
1039 | }; |
1040 | |
1041 | class CWasmEntryFrame : public StubFrame { |
1042 | public: |
1043 | Type type() const override { return C_WASM_ENTRY; } |
1044 | |
1045 | protected: |
1046 | inline explicit CWasmEntryFrame(StackFrameIteratorBase* iterator); |
1047 | |
1048 | private: |
1049 | friend class StackFrameIteratorBase; |
1050 | }; |
1051 | |
1052 | class WasmCompileLazyFrame : public StandardFrame { |
1053 | public: |
1054 | Type type() const override { return WASM_COMPILE_LAZY; } |
1055 | |
1056 | Code unchecked_code() const override; |
1057 | WasmInstanceObject wasm_instance() const; |
1058 | FullObjectSlot wasm_instance_slot() const; |
1059 | |
1060 | // Garbage collection support. |
1061 | void Iterate(RootVisitor* v) const override; |
1062 | |
1063 | static WasmCompileLazyFrame* cast(StackFrame* frame) { |
1064 | DCHECK(frame->is_wasm_compile_lazy()); |
1065 | return static_cast<WasmCompileLazyFrame*>(frame); |
1066 | } |
1067 | |
1068 | protected: |
1069 | inline explicit WasmCompileLazyFrame(StackFrameIteratorBase* iterator); |
1070 | |
1071 | Address GetCallerStackPointer() const override; |
1072 | |
1073 | private: |
1074 | friend class StackFrameIteratorBase; |
1075 | }; |
1076 | |
1077 | class InternalFrame: public StandardFrame { |
1078 | public: |
1079 | Type type() const override { return INTERNAL; } |
1080 | |
1081 | // Garbage collection support. |
1082 | void Iterate(RootVisitor* v) const override; |
1083 | |
1084 | // Determine the code for the frame. |
1085 | Code unchecked_code() const override; |
1086 | |
1087 | static InternalFrame* cast(StackFrame* frame) { |
1088 | DCHECK(frame->is_internal()); |
1089 | return static_cast<InternalFrame*>(frame); |
1090 | } |
1091 | |
1092 | protected: |
1093 | inline explicit InternalFrame(StackFrameIteratorBase* iterator); |
1094 | |
1095 | Address GetCallerStackPointer() const override; |
1096 | |
1097 | private: |
1098 | friend class StackFrameIteratorBase; |
1099 | }; |
1100 | |
1101 | |
1102 | // Construct frames are special trampoline frames introduced to handle |
1103 | // function invocations through 'new'. |
1104 | class ConstructFrame: public InternalFrame { |
1105 | public: |
1106 | Type type() const override { return CONSTRUCT; } |
1107 | |
1108 | static ConstructFrame* cast(StackFrame* frame) { |
1109 | DCHECK(frame->is_construct()); |
1110 | return static_cast<ConstructFrame*>(frame); |
1111 | } |
1112 | |
1113 | protected: |
1114 | inline explicit ConstructFrame(StackFrameIteratorBase* iterator); |
1115 | |
1116 | private: |
1117 | friend class StackFrameIteratorBase; |
1118 | }; |
1119 | |
1120 | class BuiltinContinuationFrame : public InternalFrame { |
1121 | public: |
1122 | Type type() const override { return BUILTIN_CONTINUATION; } |
1123 | |
1124 | static BuiltinContinuationFrame* cast(StackFrame* frame) { |
1125 | DCHECK(frame->is_builtin_continuation()); |
1126 | return static_cast<BuiltinContinuationFrame*>(frame); |
1127 | } |
1128 | |
1129 | protected: |
1130 | inline explicit BuiltinContinuationFrame(StackFrameIteratorBase* iterator); |
1131 | |
1132 | private: |
1133 | friend class StackFrameIteratorBase; |
1134 | }; |
1135 | |
1136 | class JavaScriptBuiltinContinuationFrame : public JavaScriptFrame { |
1137 | public: |
1138 | Type type() const override { return JAVA_SCRIPT_BUILTIN_CONTINUATION; } |
1139 | |
1140 | static JavaScriptBuiltinContinuationFrame* cast(StackFrame* frame) { |
1141 | DCHECK(frame->is_java_script_builtin_continuation()); |
1142 | return static_cast<JavaScriptBuiltinContinuationFrame*>(frame); |
1143 | } |
1144 | |
1145 | int ComputeParametersCount() const override; |
1146 | intptr_t GetSPToFPDelta() const; |
1147 | |
1148 | Object context() const override; |
1149 | |
1150 | protected: |
1151 | inline explicit JavaScriptBuiltinContinuationFrame( |
1152 | StackFrameIteratorBase* iterator); |
1153 | |
1154 | private: |
1155 | friend class StackFrameIteratorBase; |
1156 | }; |
1157 | |
1158 | class JavaScriptBuiltinContinuationWithCatchFrame |
1159 | : public JavaScriptBuiltinContinuationFrame { |
1160 | public: |
1161 | Type type() const override { |
1162 | return JAVA_SCRIPT_BUILTIN_CONTINUATION_WITH_CATCH; |
1163 | } |
1164 | |
1165 | static JavaScriptBuiltinContinuationWithCatchFrame* cast(StackFrame* frame) { |
1166 | DCHECK(frame->is_java_script_builtin_with_catch_continuation()); |
1167 | return static_cast<JavaScriptBuiltinContinuationWithCatchFrame*>(frame); |
1168 | } |
1169 | |
1170 | // Patch in the exception object at the appropriate location into the stack |
1171 | // frame. |
1172 | void SetException(Object exception); |
1173 | |
1174 | protected: |
1175 | inline explicit JavaScriptBuiltinContinuationWithCatchFrame( |
1176 | StackFrameIteratorBase* iterator); |
1177 | |
1178 | private: |
1179 | friend class StackFrameIteratorBase; |
1180 | }; |
1181 | |
1182 | class StackFrameIteratorBase { |
1183 | public: |
1184 | Isolate* isolate() const { return isolate_; } |
1185 | |
1186 | bool done() const { return frame_ == nullptr; } |
1187 | |
1188 | protected: |
1189 | // An iterator that iterates over a given thread's stack. |
1190 | StackFrameIteratorBase(Isolate* isolate, bool can_access_heap_objects); |
1191 | |
1192 | Isolate* isolate_; |
1193 | #define DECLARE_SINGLETON(ignore, type) type type##_; |
1194 | STACK_FRAME_TYPE_LIST(DECLARE_SINGLETON) |
1195 | #undef DECLARE_SINGLETON |
1196 | StackFrame* frame_; |
1197 | StackHandler* handler_; |
1198 | const bool can_access_heap_objects_; |
1199 | |
1200 | StackHandler* handler() const { |
1201 | DCHECK(!done()); |
1202 | return handler_; |
1203 | } |
1204 | |
1205 | // Get the type-specific frame singleton in a given state. |
1206 | StackFrame* SingletonFor(StackFrame::Type type, StackFrame::State* state); |
1207 | // A helper function, can return a nullptr pointer. |
1208 | StackFrame* SingletonFor(StackFrame::Type type); |
1209 | |
1210 | private: |
1211 | friend class StackFrame; |
1212 | DISALLOW_COPY_AND_ASSIGN(StackFrameIteratorBase); |
1213 | }; |
1214 | |
1215 | |
1216 | class StackFrameIterator: public StackFrameIteratorBase { |
1217 | public: |
1218 | // An iterator that iterates over the isolate's current thread's stack, |
1219 | V8_EXPORT_PRIVATE explicit StackFrameIterator(Isolate* isolate); |
1220 | // An iterator that iterates over a given thread's stack. |
1221 | V8_EXPORT_PRIVATE StackFrameIterator(Isolate* isolate, ThreadLocalTop* t); |
1222 | |
1223 | StackFrame* frame() const { |
1224 | DCHECK(!done()); |
1225 | return frame_; |
1226 | } |
1227 | V8_EXPORT_PRIVATE void Advance(); |
1228 | |
1229 | private: |
1230 | // Go back to the first frame. |
1231 | void Reset(ThreadLocalTop* top); |
1232 | |
1233 | DISALLOW_COPY_AND_ASSIGN(StackFrameIterator); |
1234 | }; |
1235 | |
1236 | // Iterator that supports iterating through all JavaScript frames. |
1237 | class JavaScriptFrameIterator { |
1238 | public: |
1239 | inline explicit JavaScriptFrameIterator(Isolate* isolate); |
1240 | inline JavaScriptFrameIterator(Isolate* isolate, ThreadLocalTop* top); |
1241 | |
1242 | inline JavaScriptFrame* frame() const; |
1243 | |
1244 | bool done() const { return iterator_.done(); } |
1245 | V8_EXPORT_PRIVATE void Advance(); |
1246 | void AdvanceOneFrame() { iterator_.Advance(); } |
1247 | |
1248 | private: |
1249 | StackFrameIterator iterator_; |
1250 | }; |
1251 | |
1252 | // NOTE: The stack trace frame iterator is an iterator that only traverse proper |
1253 | // JavaScript frames that have proper JavaScript functions and WebAssembly |
1254 | // frames. |
1255 | class V8_EXPORT_PRIVATE StackTraceFrameIterator { |
1256 | public: |
1257 | explicit StackTraceFrameIterator(Isolate* isolate); |
1258 | // Skip frames until the frame with the given id is reached. |
1259 | StackTraceFrameIterator(Isolate* isolate, StackFrame::Id id); |
1260 | bool done() const { return iterator_.done(); } |
1261 | void Advance(); |
1262 | void AdvanceOneFrame() { iterator_.Advance(); } |
1263 | |
1264 | inline StandardFrame* frame() const; |
1265 | |
1266 | inline bool is_javascript() const; |
1267 | inline bool is_wasm() const; |
1268 | inline JavaScriptFrame* javascript_frame() const; |
1269 | |
1270 | private: |
1271 | StackFrameIterator iterator_; |
1272 | bool IsValidFrame(StackFrame* frame) const; |
1273 | }; |
1274 | |
1275 | class SafeStackFrameIterator: public StackFrameIteratorBase { |
1276 | public: |
1277 | SafeStackFrameIterator(Isolate* isolate, |
1278 | Address fp, Address sp, |
1279 | Address js_entry_sp); |
1280 | |
1281 | inline StackFrame* frame() const; |
1282 | void Advance(); |
1283 | |
1284 | StackFrame::Type top_frame_type() const { return top_frame_type_; } |
1285 | |
1286 | private: |
1287 | void AdvanceOneFrame(); |
1288 | |
1289 | bool IsValidStackAddress(Address addr) const { |
1290 | return low_bound_ <= addr && addr <= high_bound_; |
1291 | } |
1292 | bool IsValidFrame(StackFrame* frame) const; |
1293 | bool IsValidCaller(StackFrame* frame); |
1294 | bool IsValidExitFrame(Address fp) const; |
1295 | bool IsValidTop(ThreadLocalTop* top) const; |
1296 | |
1297 | const Address low_bound_; |
1298 | const Address high_bound_; |
1299 | StackFrame::Type top_frame_type_; |
1300 | ExternalCallbackScope* external_callback_scope_; |
1301 | }; |
1302 | } // namespace internal |
1303 | } // namespace v8 |
1304 | |
1305 | #endif // V8_FRAMES_H_ |
1306 | |