v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
stacks.h
Go to the documentation of this file.
1// Copyright 2021 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_WASM_STACKS_H_
6#define V8_WASM_STACKS_H_
7
8#if !V8_ENABLE_WEBASSEMBLY
9#error This header should only be included if WebAssembly is enabled.
10#endif // !V8_ENABLE_WEBASSEMBLY
11
12#include <optional>
13
14#include "src/common/globals.h"
16
17namespace v8 {
18class Isolate;
19}
20
21namespace v8::internal::wasm {
22
23class StackMemory;
24
25struct JumpBuffer {
30 StackMemory* parent = nullptr;
31 // We track the state below to prevent stack corruptions under the sandbox
32 // security model.
33 // Assuming that the external pointer to the jump buffer has been corrupted
34 // and replaced with a different jump buffer, we check its state before
35 // resuming it to verify that it is not Active or Retired.
36 // The distinction between Suspended and Inactive may not be strictly
37 // necessary since we currently always pass a single JS value in the return
38 // register across stacks (either the Promise, the result of the Promise, or
39 // the result of the export). However adding a state does not cost anything
40 // and is more robust against potential changes in the calling conventions.
41 enum StackState : int32_t {
42 Active, // The (unique) active stack. The jump buffer is invalid in that
43 // state.
44 Suspended, // A stack suspended by WasmSuspend.
45 Inactive, // A parent/ancestor of the active stack. In other words, a
46 // stack that either called or resumed a suspendable stack.
47 Retired // A finished stack. The jump buffer is invalid in that state.
48 };
50};
51
53 public:
54 static std::unique_ptr<StackMemory> New() {
55 return std::unique_ptr<StackMemory>(new StackMemory());
56 }
57
58 // Returns a non-owning view of the central stack. This may be
59 // the simulator's stack when running on the simulator.
60 static StackMemory* GetCentralStackView(Isolate* isolate);
61
63 void* jslimit() const;
64 Address base() const {
65 Address memory_limit = active_segment_
67 : reinterpret_cast<Address>(limit_ + size_);
68#ifdef USE_SIMULATOR
69 // To perform runtime calls with different signatures, some simulators
70 // prepare a fixed number of arguments which is an upper bound of the actual
71 // parameter count. The extra stack slots contain arbitrary data and are
72 // never used, but with stack-switching this can happen close to the stack
73 // start, so we need to reserve a safety gap to ensure that the addresses
74 // are at least mapped to prevent a crash.
75 constexpr int kStackBaseSafetyOffset = 20 * kSystemPointerSize;
76#else
77 constexpr int kStackBaseSafetyOffset = 0;
78#endif
79 return memory_limit - kStackBaseSafetyOffset;
80 }
81 JumpBuffer* jmpbuf() { return &jmpbuf_; }
82 bool Contains(Address addr) {
83 if (!owned_) {
84 return reinterpret_cast<Address>(jslimit()) <= addr && addr < base();
85 }
86 for (auto segment = first_segment_; segment;
87 segment = segment->next_segment_) {
88 if (reinterpret_cast<Address>(segment->limit_) <= addr &&
89 addr < segment->base()) {
90 return true;
91 }
92 if (segment == active_segment_) break;
93 }
94 return false;
95 }
96 int id() { return id_; }
98 void set_index(size_t index) { index_ = index; }
99 size_t index() { return index_; }
100 size_t allocated_size() {
101 size_t size = 0;
102 auto segment = first_segment_;
103 while (segment) {
104 size += segment->size_;
105 segment = segment->next_segment_;
106 }
107 return size;
108 }
109 void FillWith(uint8_t value) {
110 auto segment = first_segment_;
111 while (segment) {
112 memset(segment->limit_, value, segment->size_);
113 segment = segment->next_segment_;
114 }
115 }
117 bool Grow(Address current_fp);
118 Address Shrink();
119 void ShrinkTo(Address stack_address);
120 void Reset();
121
123 public:
124 Address base() const { return reinterpret_cast<Address>(limit_ + size_); }
125
126 private:
127 explicit StackSegment(size_t size);
129 uint8_t* limit_;
130 size_t size_;
131
132 // References to segments of segmented stack
136
137 friend class StackMemory;
138 };
139
141 // Source FP and target SP of the frame that switched to the central stack.
142 // The source FP is in the secondary stack, the target SP is in the central
143 // stack.
144 // The stack cannot be suspended while it is on the central stack, so there
145 // can be at most one switch for a given stack.
148 bool has_value() const { return source_fp != kNullAddress; }
149 };
151 return stack_switch_info_;
152 }
159
160#ifdef DEBUG
161 static constexpr int kJSLimitOffsetKB = 80;
162#else
163 static constexpr int kJSLimitOffsetKB = 40;
164#endif
165
166 friend class StackPool;
167
168 constexpr static uint32_t stack_switch_source_fp_offset() {
171 }
172 constexpr static uint32_t stack_switch_target_sp_offset() {
175 }
176 constexpr static uint32_t jmpbuf_offset() {
178 }
179
180 private:
181 // This constructor allocates a new stack segment.
182 StackMemory();
183
184 // Overload to represent a view of the libc stack.
185 StackMemory(uint8_t* limit, size_t size);
186
187 uint8_t* limit_;
188 size_t size_;
189 bool owned_;
191 // Stable ID.
192 int id_;
193 // Index of this stack in the global Isolate::wasm_stacks() vector. This
194 // allows us to add and remove from the vector in constant time (see
195 // return_switch()).
196 size_t index_;
200};
201
202constexpr int kStackSpOffset =
204constexpr int kStackFpOffset =
206constexpr int kStackPcOffset =
208constexpr int kStackLimitOffset =
209 wasm::StackMemory::jmpbuf_offset() + offsetof(JumpBuffer, stack_limit);
210constexpr int kStackParentOffset =
211 wasm::StackMemory::jmpbuf_offset() + offsetof(JumpBuffer, parent);
212constexpr int kStackStateOffset =
213 wasm::StackMemory::jmpbuf_offset() + offsetof(JumpBuffer, state);
214
215// A pool of "finished" stacks, i.e. stacks whose last frame have returned and
216// whose memory can be reused for new suspendable computations.
218 public:
219 // Gets a stack from the free list if one exists, else allocates it.
220 std::unique_ptr<StackMemory> GetOrAllocate();
221 // Adds a finished stack to the free list.
222 void Add(std::unique_ptr<StackMemory> stack);
223 // Decommit the stack memories and empty the freelist.
225 size_t Size() const;
226
227 private:
228 std::vector<std::unique_ptr<StackMemory>> freelist_;
229 size_t size_ = 0;
230 // If the next finished stack would move the total size above this limit, the
231 // stack is freed instead of being added to the free list.
232 static constexpr int kMaxSize = 4 * MB;
233};
234
235} // namespace v8::internal::wasm
236
237#endif // V8_WASM_STACKS_H_
static std::unique_ptr< StackMemory > New()
Definition stacks.h:54
static constexpr uint32_t stack_switch_target_sp_offset()
Definition stacks.h:172
bool Contains(Address addr)
Definition stacks.h:82
void ShrinkTo(Address stack_address)
Definition stacks.cc:133
static constexpr uint32_t jmpbuf_offset()
Definition stacks.h:176
void set_index(size_t index)
Definition stacks.h:98
const StackSwitchInfo & stack_switch_info() const
Definition stacks.h:150
void FillWith(uint8_t value)
Definition stacks.h:109
StackSegment * first_segment_
Definition stacks.h:198
void set_stack_switch_info(Address fp, Address sp)
Definition stacks.h:153
StackSegment * active_segment_
Definition stacks.h:199
static constexpr int kJSLimitOffsetKB
Definition stacks.h:163
StackSwitchInfo stack_switch_info_
Definition stacks.h:197
bool Grow(Address current_fp)
Definition stacks.cc:85
static constexpr uint32_t stack_switch_source_fp_offset()
Definition stacks.h:168
static StackMemory * GetCentralStackView(Isolate *isolate)
Definition stacks.cc:14
std::unique_ptr< StackMemory > GetOrAllocate()
Definition stacks.cc:150
std::vector< std::unique_ptr< StackMemory > > freelist_
Definition stacks.h:228
void Add(std::unique_ptr< StackMemory > stack)
Definition stacks.cc:170
static constexpr int kMaxSize
Definition stacks.h:232
constexpr int kStackStateOffset
Definition stacks.h:212
constexpr int kStackSpOffset
Definition stacks.h:202
constexpr int kStackFpOffset
Definition stacks.h:204
constexpr int kStackParentOffset
Definition stacks.h:210
constexpr int kStackLimitOffset
Definition stacks.h:208
constexpr int kStackPcOffset
Definition stacks.h:206
constexpr int kSystemPointerSize
Definition globals.h:410
static constexpr Address kNullAddress
Definition v8-internal.h:53
too high values may cause the compiler to set high thresholds for inlining to as much as possible avoid inlined allocation of objects that cannot escape trace load stores from virtual maglev objects use TurboFan fast string builder analyze liveness of environment slots and zap dead values trace TurboFan load elimination emit data about basic block usage in builtins to this enable builtin reordering when run mksnapshot flag for emit warnings when applying builtin profile data verify register allocation in TurboFan randomly schedule instructions to stress dependency tracking enable store store elimination in TurboFan rewrite far to near simulate GC compiler thread race related to allow float parameters to be passed in simulator mode JS Wasm Run additional turbo_optimize_inlined_js_wasm_wrappers enable experimental feedback collection in generic lowering enable Turboshaft s WasmLoadElimination enable Turboshaft s low level load elimination for JS enable Turboshaft s escape analysis for string concatenation use enable Turbolev features that we want to ship in the not too far future trace individual Turboshaft reduction steps trace intermediate Turboshaft reduction steps invocation count threshold for early optimization Enables optimizations which favor memory size over execution speed Enables sampling allocation profiler with X as a sample interval min size of a semi the new space consists of two semi spaces max size of the Collect garbage after Collect garbage after keeps maps alive for< n > old space garbage collections print one detailed trace line in allocation gc speed threshold for starting incremental marking via a task in percent of available threshold for starting incremental marking immediately in percent of available Use a single schedule for determining a marking schedule between JS and C objects schedules the minor GC task with kUserVisible priority max worker number of concurrent for NumberOfWorkerThreads start background threads that allocate memory concurrent_array_buffer_sweeping use parallel threads to clear weak refs in the atomic pause trace progress of the incremental marking trace object counts and memory usage * MB
Definition flags.cc:2197
#define OFFSET_OF(type, field)
Definition macros.h:57