Wire Sysio Wire Sysion 1.0.0
Loading...
Searching...
No Matches
sysio::vm::jit_execution_context< Host, EnableBacktrace > Class Template Reference

#include <execution_context.hpp>

Inheritance diagram for sysio::vm::jit_execution_context< Host, EnableBacktrace >:
Collaboration diagram for sysio::vm::jit_execution_context< Host, EnableBacktrace >:

Public Member Functions

 jit_execution_context (module &m, std::uint32_t max_call_depth)
 
void set_max_call_depth (std::uint32_t max_call_depth)
 
native_value call_host_function (native_value *stack, uint32_t index)
 
void reset ()
 
template<typename... Args>
std::optional< operand_stack_elemexecute (host_type *host, jit_visitor, uint32_t func_index, Args... args)
 
 jit_execution_context (module &m, std::uint32_t max_call_depth)
 
void set_max_call_depth (std::uint32_t max_call_depth)
 
native_value call_host_function (native_value *stack, uint32_t index)
 
void reset ()
 
template<typename... Args>
std::optional< operand_stack_elemexecute (host_type *host, jit_visitor, uint32_t func_index, Args... args)
 
template<typename Visitor , typename... Args>
std::optional< operand_stack_elemexecute (host_type *host, Visitor &&visitor, const std::string_view func, Args... args)
 
auto & get_operand_stack ()
 
const auto & get_operand_stack () const
 
char * linear_memory ()
 
auto get_interface ()
 
- Public Member Functions inherited from sysio::vm::execution_context_base< jit_execution_context< Host, false >, Host >
jit_execution_context< Host, false > & derived ()
 
jit_execution_context< Host, false > & derived ()
 
 execution_context_base (module &m)
 
 execution_context_base (module &m)
 
int32_t grow_linear_memory (int32_t pages)
 
int32_t grow_linear_memory (int32_t pages)
 
int32_t current_linear_memory () const
 
int32_t current_linear_memory () const
 
void exit (std::error_code err=std::error_code())
 
void exit (std::error_code err=std::error_code())
 
moduleget_module ()
 
moduleget_module ()
 
void set_wasm_allocator (wasm_allocator *alloc)
 
void set_wasm_allocator (wasm_allocator *alloc)
 
auto get_wasm_allocator ()
 
auto get_wasm_allocator ()
 
char * linear_memory ()
 
char * linear_memory ()
 
auto & get_operand_stack ()
 
const auto & get_operand_stack () const
 
auto & get_operand_stack ()
 
const auto & get_operand_stack () const
 
auto get_interface ()
 
auto get_interface ()
 
void set_max_pages (std::uint32_t max_pages)
 
void set_max_pages (std::uint32_t max_pages)
 
std::error_code get_error_code () const
 
std::error_code get_error_code () const
 
void reset ()
 
void reset ()
 
std::optional< operand_stack_elemexecute (host_type *host, Visitor &&visitor, const std::string_view func, Args... args)
 
std::optional< operand_stack_elemexecute (host_type *host, Visitor &&visitor, const std::string_view func, Args... args)
 
void execute_start (host_type *host, Visitor &&visitor)
 
void execute_start (host_type *host, Visitor &&visitor)
 

Static Public Member Functions

static void handle_signal (int sig)
 

Public Attributes

module_mod
 
detail::host_invoker_t< Host > _rhf
 
std::error_code _error_code
 

Protected Member Functions

template<typename T >
native_value transform_arg (T &&value)
 
template<typename T >
native_value transform_arg (T &&value)
 

Protected Attributes

host_type * _host = nullptr
 
uint32_t _remaining_call_depth
 
- Protected Attributes inherited from sysio::vm::execution_context_base< jit_execution_context< Host, false >, Host >
char * _linear_memory
 
module_mod
 
wasm_allocator_wasm_alloc
 
uint32_t _max_pages
 
detail::host_invoker_t< Host > _rhf
 
std::error_code _error_code
 
operand_stack _os
 

Additional Inherited Members

- Static Protected Member Functions inherited from sysio::vm::execution_context_base< jit_execution_context< Host, false >, Host >
static void type_check_args (const func_type &ft, Args &&...)
 
static void type_check_args (const func_type &ft, Args &&...)
 
static void handle_signal (int sig)
 
static void handle_signal (int sig)
 

Detailed Description

template<typename Host, bool EnableBacktrace = false>
class sysio::vm::jit_execution_context< Host, EnableBacktrace >

Definition at line 212 of file execution_context.hpp.

Constructor & Destructor Documentation

◆ jit_execution_context() [1/2]

template<typename Host , bool EnableBacktrace = false>
sysio::vm::jit_execution_context< Host, EnableBacktrace >::jit_execution_context ( module & m,
std::uint32_t max_call_depth )
inline

Definition at line 226 of file execution_context.hpp.

◆ jit_execution_context() [2/2]

template<typename Host , bool EnableBacktrace = false>
sysio::vm::jit_execution_context< Host, EnableBacktrace >::jit_execution_context ( module & m,
std::uint32_t max_call_depth )
inline

Definition at line 226 of file execution_context.hpp.

226: base_type(m), _remaining_call_depth(max_call_depth) {}

Member Function Documentation

◆ call_host_function() [1/2]

template<typename Host , bool EnableBacktrace = false>
native_value sysio::vm::jit_execution_context< Host, EnableBacktrace >::call_host_function ( native_value * stack,
uint32_t index )
inline

Definition at line 232 of file execution_context.hpp.

232 {
233 const auto& ft = _mod.get_function_type(index);
234 uint32_t num_params = ft.param_types.size();
235#ifndef NDEBUG
236 uint32_t original_operands = get_operand_stack().size();
237#endif
238 for(uint32_t i = 0; i < ft.param_types.size(); ++i) {
239 switch(ft.param_types[i]) {
240 case i32: get_operand_stack().push(i32_const_t{stack[num_params - i - 1].i32}); break;
241 case i64: get_operand_stack().push(i64_const_t{stack[num_params - i - 1].i64}); break;
242 case f32: get_operand_stack().push(f32_const_t{stack[num_params - i - 1].f32}); break;
243 case f64: get_operand_stack().push(f64_const_t{stack[num_params - i - 1].f64}); break;
244 default: assert(!"Unexpected type in param_types.");
245 }
246 }
248 native_value result{uint64_t{0}};
249 // guarantee that the junk bits are zero, to avoid problems.
250 auto set_result = [&result](auto val) { std::memcpy(&result, &val, sizeof(val)); };
251 if(ft.return_count) {
252 operand_stack_elem el = get_operand_stack().pop();
253 switch(ft.return_type) {
254 case i32: set_result(el.to_ui32()); break;
255 case i64: set_result(el.to_ui64()); break;
256 case f32: set_result(el.to_f32()); break;
257 case f64: set_result(el.to_f64()); break;
258 default: assert(!"Unexpected function return type.");
259 }
260 }
261
262 assert(get_operand_stack().size() == original_operands);
263 return result;
264 }
detail::host_invoker_t< Host > _rhf
unsigned int uint32_t
Definition stdint.h:126
unsigned __int64 uint64_t
Definition stdint.h:136
guarded_vector< uint32_t > import_functions
Definition types.hpp:184
auto & get_function_type(uint32_t index) const
Definition types.hpp:221
Here is the call graph for this function:

◆ call_host_function() [2/2]

template<typename Host , bool EnableBacktrace = false>
native_value sysio::vm::jit_execution_context< Host, EnableBacktrace >::call_host_function ( native_value * stack,
uint32_t index )
inline

Definition at line 232 of file execution_context.hpp.

232 {
233 const auto& ft = _mod.get_function_type(index);
234 uint32_t num_params = ft.param_types.size();
235#ifndef NDEBUG
236 uint32_t original_operands = get_operand_stack().size();
237#endif
238 for(uint32_t i = 0; i < ft.param_types.size(); ++i) {
239 switch(ft.param_types[i]) {
240 case i32: get_operand_stack().push(i32_const_t{stack[num_params - i - 1].i32}); break;
241 case i64: get_operand_stack().push(i64_const_t{stack[num_params - i - 1].i64}); break;
242 case f32: get_operand_stack().push(f32_const_t{stack[num_params - i - 1].f32}); break;
243 case f64: get_operand_stack().push(f64_const_t{stack[num_params - i - 1].f64}); break;
244 default: assert(!"Unexpected type in param_types.");
245 }
246 }
248 native_value result{uint64_t{0}};
249 // guarantee that the junk bits are zero, to avoid problems.
250 auto set_result = [&result](auto val) { std::memcpy(&result, &val, sizeof(val)); };
251 if(ft.return_count) {
252 operand_stack_elem el = get_operand_stack().pop();
253 switch(ft.return_type) {
254 case i32: set_result(el.to_ui32()); break;
255 case i64: set_result(el.to_ui64()); break;
256 case f32: set_result(el.to_f32()); break;
257 case f64: set_result(el.to_f64()); break;
258 default: assert(!"Unexpected function return type.");
259 }
260 }
261
262 assert(get_operand_stack().size() == original_operands);
263 return result;
264 }
Here is the call graph for this function:

◆ execute() [1/3]

template<typename Host , bool EnableBacktrace = false>
template<typename... Args>
std::optional< operand_stack_elem > sysio::vm::jit_execution_context< Host, EnableBacktrace >::execute ( host_type * host,
jit_visitor ,
uint32_t func_index,
Args... args )
inline

Definition at line 272 of file execution_context.hpp.

272 {
273 auto saved_host = _host;
274 auto saved_os_size = get_operand_stack().size();
275 auto g = scope_guard([&](){ _host = saved_host; get_operand_stack().eat(saved_os_size); });
276
277 _host = host;
278
279 const func_type& ft = _mod.get_function_type(func_index);
280 this->type_check_args(ft, static_cast<Args&&>(args)...);
281 native_value result;
282 native_value args_raw[] = { transform_arg(static_cast<Args&&>(args))... };
283
284 try {
285 if (func_index < _mod.get_imported_functions_size()) {
286 std::reverse(args_raw + 0, args_raw + sizeof...(Args));
287 result = call_host_function(args_raw, func_index);
288 } else {
289 std::size_t maximum_stack_usage =
290 (_mod.maximum_stack + 2 /*frame ptr + return ptr*/) * (_remaining_call_depth + 1) +
291 sizeof...(Args) + 4 /* scratch space */;
292 stack_allocator alt_stack(maximum_stack_usage * sizeof(native_value));
293 // reserve 24 bytes for data accessed by inline assembly
294 void* stack = alt_stack.top();
295 if(stack) {
296 stack = static_cast<char*>(stack) - 24;
297 }
298 auto fn = reinterpret_cast<native_value (*)(void*, void*)>(_mod.code[func_index - _mod.get_imported_functions_size()].jit_code_offset + _mod.allocator._code_base);
299
300 if constexpr(EnableBacktrace) {
301 sigset_t block_mask;
302 sigemptyset(&block_mask);
303 sigaddset(&block_mask, SIGPROF);
304 pthread_sigmask(SIG_BLOCK, &block_mask, nullptr);
305 auto restore = scope_guard{[this, &block_mask] {
306 this->_top_frame = nullptr;
307 this->_bottom_frame = nullptr;
308 pthread_sigmask(SIG_UNBLOCK, &block_mask, nullptr);
309 }};
310
312 result = execute<sizeof...(Args)>(args_raw, fn, this, base_type::linear_memory(), stack);
313 }, &handle_signal);
314 } else {
316 result = execute<sizeof...(Args)>(args_raw, fn, this, base_type::linear_memory(), stack);
317 }, &handle_signal);
318 }
319 }
320 } catch(wasm_exit_exception&) {
321 return {};
322 }
323
324 if(!ft.return_count)
325 return {};
326 else switch (ft.return_type) {
327 case i32: return {i32_const_t{result.i32}};
328 case i64: return {i64_const_t{result.i64}};
329 case f32: return {f32_const_t{result.f32}};
330 case f64: return {f64_const_t{result.f64}};
331 default: assert(!"Unexpected function return type");
332 }
333 __builtin_unreachable();
334 }
native_value call_host_function(native_value *stack, uint32_t index)
native_value transform_arg(T &&value)
auto invoke_with_signal_handler(F &&f, E &&e)
Definition signals.hpp:123
schedule config_dir_name data_dir_name p2p_port http_port file_size name host(p2p_endpoint)) FC_REFLECT(tn_node_def
uint32_t get_imported_functions_size() const
Definition types.hpp:197
growable_allocator allocator
Definition types.hpp:167
guarded_vector< function_body > code
Definition types.hpp:177
uint64_t maximum_stack
Definition types.hpp:187
Here is the call graph for this function:

◆ execute() [2/3]

template<typename Host , bool EnableBacktrace = false>
template<typename... Args>
std::optional< operand_stack_elem > sysio::vm::jit_execution_context< Host, EnableBacktrace >::execute ( host_type * host,
jit_visitor ,
uint32_t func_index,
Args... args )
inline

Definition at line 272 of file execution_context.hpp.

272 {
273 auto saved_host = _host;
274 auto saved_os_size = get_operand_stack().size();
275 auto g = scope_guard([&](){ _host = saved_host; get_operand_stack().eat(saved_os_size); });
276
277 _host = host;
278
279 const func_type& ft = _mod.get_function_type(func_index);
280 this->type_check_args(ft, static_cast<Args&&>(args)...);
281 native_value result;
282 native_value args_raw[] = { transform_arg(static_cast<Args&&>(args))... };
283
284 try {
285 if (func_index < _mod.get_imported_functions_size()) {
286 std::reverse(args_raw + 0, args_raw + sizeof...(Args));
287 result = call_host_function(args_raw, func_index);
288 } else {
289 std::size_t maximum_stack_usage =
290 (_mod.maximum_stack + 2 /*frame ptr + return ptr*/) * (_remaining_call_depth + 1) +
291 sizeof...(Args) + 4 /* scratch space */;
292 stack_allocator alt_stack(maximum_stack_usage * sizeof(native_value));
293 // reserve 24 bytes for data accessed by inline assembly
294 void* stack = alt_stack.top();
295 if(stack) {
296 stack = static_cast<char*>(stack) - 24;
297 }
298 auto fn = reinterpret_cast<native_value (*)(void*, void*)>(_mod.code[func_index - _mod.get_imported_functions_size()].jit_code_offset + _mod.allocator._code_base);
299
300 if constexpr(EnableBacktrace) {
301 sigset_t block_mask;
302 sigemptyset(&block_mask);
303 sigaddset(&block_mask, SIGPROF);
304 pthread_sigmask(SIG_BLOCK, &block_mask, nullptr);
305 auto restore = scope_guard{[this, &block_mask] {
306 this->_top_frame = nullptr;
307 this->_bottom_frame = nullptr;
308 pthread_sigmask(SIG_UNBLOCK, &block_mask, nullptr);
309 }};
310
312 result = execute<sizeof...(Args)>(args_raw, fn, this, base_type::linear_memory(), stack);
313 }, &handle_signal);
314 } else {
316 result = execute<sizeof...(Args)>(args_raw, fn, this, base_type::linear_memory(), stack);
317 }, &handle_signal);
318 }
319 }
320 } catch(wasm_exit_exception&) {
321 return {};
322 }
323
324 if(!ft.return_count)
325 return {};
326 else switch (ft.return_type) {
327 case i32: return {i32_const_t{result.i32}};
328 case i64: return {i64_const_t{result.i64}};
329 case f32: return {f32_const_t{result.f32}};
330 case f64: return {f64_const_t{result.f64}};
331 default: assert(!"Unexpected function return type");
332 }
333 __builtin_unreachable();
334 }
Here is the call graph for this function:

◆ execute() [3/3]

template<typename Host , bool EnableBacktrace = false>
template<typename Visitor , typename... Args>
std::optional< operand_stack_elem > sysio::vm::execution_context_base< Derived, Host >::execute ( host_type * host,
Visitor && visitor,
const std::string_view func,
Args... args )
inline

Definition at line 151 of file execution_context.hpp.

152 {
154 return derived().execute(host, std::forward<Visitor>(visitor), func_index, std::forward<Args>(args)...);
155 }
uint32_t get_exported_function(const std::string_view str)
Definition types.hpp:227

◆ get_interface()

template<typename Host , bool EnableBacktrace = false>
auto sysio::vm::execution_context_base< Derived, Host >::get_interface ( )
inline

◆ get_operand_stack() [1/2]

template<typename Host , bool EnableBacktrace = false>
auto & sysio::vm::execution_context_base< Derived, Host >::get_operand_stack ( )
inline

Definition at line 116 of file execution_context.hpp.

116{ return _os; }

◆ get_operand_stack() [2/2]

template<typename Host , bool EnableBacktrace = false>
const auto & sysio::vm::execution_context_base< Derived, Host >::get_operand_stack ( ) const
inline

Definition at line 117 of file execution_context.hpp.

117{ return _os; }

◆ handle_signal()

template<typename Host , bool EnableBacktrace = false>
static void sysio::vm::execution_context_base< Derived, Host >::handle_signal ( int sig)
inlinestatic

Definition at line 172 of file execution_context.hpp.

172 {
173 switch(sig) {
174 case SIGSEGV:
175 case SIGBUS:
176 case SIGFPE:
177 break;
178 default:
179 /* TODO fix this */
180 assert(!"??????");
181 }
182 throw wasm_memory_exception{ "wasm memory out-of-bounds" };
183 }

◆ linear_memory()

template<typename Host , bool EnableBacktrace = false>
char * sysio::vm::execution_context_base< Derived, Host >::linear_memory ( )
inline

Definition at line 115 of file execution_context.hpp.

115{ return _linear_memory; }

◆ reset() [1/2]

template<typename Host , bool EnableBacktrace = false>
void sysio::vm::jit_execution_context< Host, EnableBacktrace >::reset ( )
inline

Definition at line 266 of file execution_context.hpp.

◆ reset() [2/2]

template<typename Host , bool EnableBacktrace = false>
void sysio::vm::jit_execution_context< Host, EnableBacktrace >::reset ( )
inline

Definition at line 266 of file execution_context.hpp.

266 {
268 get_operand_stack().eat(0);
269 }

◆ set_max_call_depth() [1/2]

template<typename Host , bool EnableBacktrace = false>
void sysio::vm::jit_execution_context< Host, EnableBacktrace >::set_max_call_depth ( std::uint32_t max_call_depth)
inline

Definition at line 228 of file execution_context.hpp.

◆ set_max_call_depth() [2/2]

template<typename Host , bool EnableBacktrace = false>
void sysio::vm::jit_execution_context< Host, EnableBacktrace >::set_max_call_depth ( std::uint32_t max_call_depth)
inline

Definition at line 228 of file execution_context.hpp.

◆ transform_arg() [1/2]

template<typename Host , bool EnableBacktrace = false>
template<typename T >
native_value sysio::vm::jit_execution_context< Host, EnableBacktrace >::transform_arg ( T && value)
inlineprotected

Definition at line 400 of file execution_context.hpp.

400 {
401 // make sure that the garbage bits are always zero.
402 native_value result;
403 std::memset(&result, 0, sizeof(result));
405 auto transformed_value = detail::resolve_result(tc, static_cast<T&&>(value)).data;
406 std::memcpy(&result, &transformed_value, sizeof(transformed_value));
407 return result;
408 }
typename type_converter< HF >::type type_converter_t
constexpr auto resolve_result(Type_Converter &tc, T &&val)
#define value
Definition pkcs11.h:157
#define T(meth, val, expected)

◆ transform_arg() [2/2]

template<typename Host , bool EnableBacktrace = false>
template<typename T >
native_value sysio::vm::jit_execution_context< Host, EnableBacktrace >::transform_arg ( T && value)
inlineprotected

Definition at line 400 of file execution_context.hpp.

400 {
401 // make sure that the garbage bits are always zero.
402 native_value result;
403 std::memset(&result, 0, sizeof(result));
405 auto transformed_value = detail::resolve_result(tc, static_cast<T&&>(value)).data;
406 std::memcpy(&result, &transformed_value, sizeof(transformed_value));
407 return result;
408 }

Member Data Documentation

◆ _error_code

template<typename Host , bool EnableBacktrace = false>
std::error_code sysio::vm::execution_context_base< Derived, Host >::_error_code

Definition at line 190 of file execution_context.hpp.

◆ _host

template<typename Host , bool EnableBacktrace = false>
host_type * sysio::vm::jit_execution_context< Host, EnableBacktrace >::_host = nullptr
protected

Definition at line 478 of file execution_context.hpp.

◆ _mod

template<typename Host , bool EnableBacktrace = false>
module & sysio::vm::execution_context_base< Derived, Host >::_mod

Definition at line 186 of file execution_context.hpp.

◆ _remaining_call_depth

template<typename Host , bool EnableBacktrace = false>
uint32_t sysio::vm::jit_execution_context< Host, EnableBacktrace >::_remaining_call_depth
protected

Definition at line 479 of file execution_context.hpp.

◆ _rhf

template<typename Host , bool EnableBacktrace = false>
detail::host_invoker_t< Host > sysio::vm::execution_context_base< Derived, Host >::_rhf

Definition at line 189 of file execution_context.hpp.


The documentation for this class was generated from the following files: