Wire Sysio Wire Sysion 1.0.0
Loading...
Searching...
No Matches
sys-vm-oc.hpp
Go to the documentation of this file.
1#pragma once
2
7#include <softfloat.hpp>
8#include "IR/Types.h"
9
16
17#include <boost/hana/string.hpp>
18
19namespace sysio { namespace chain { namespace webassembly { namespace eosvmoc {
20
21using namespace IR;
22using namespace Runtime;
23using namespace fc;
24
25using namespace sysio::chain::eosvmoc;
26
28
30 public:
31 eosvmoc_runtime(const boost::filesystem::path data_dir, const eosvmoc::config& eosvmoc_config, const chainbase::database& db);
33 std::unique_ptr<wasm_instantiated_module_interface> instantiate_module(const char* code_bytes, size_t code_size, std::vector<uint8_t> initial_memory,
34 const digest_type& code_hash, const uint8_t& vm_type, const uint8_t& vm_version) override;
35
37
42};
43
62template<typename T>
63inline void* array_ptr_impl (size_t ptr, size_t length)
64{
65 constexpr int cb_full_linear_memory_start_segment_offset = OFFSET_OF_CONTROL_BLOCK_MEMBER(full_linear_memory_start);
66 constexpr int cb_first_invalid_memory_address_segment_offset = OFFSET_OF_CONTROL_BLOCK_MEMBER(first_invalid_memory_address);
67
68 size_t end = ptr + length*sizeof(T);
69
70 asm volatile("cmp %%gs:%c[firstInvalidMemory], %[End]\n"
71 "jle 1f\n"
72 "mov %%gs:%c[firstInvalidMemory], %[End]\n" // sets End with a known failing address
73 "add %[sizeOfOneWASMPage], %[End]\n" // see above comment
74 "mov %%gs:(%[End]), %[Ptr]\n" // loads from the known failing address
75 "1:\n"
76 "add %%gs:%c[linearMemoryStart], %[Ptr]\n"
77 : [Ptr] "+r" (ptr),
78 [End] "+r" (end)
79 : [linearMemoryStart] "i" (cb_full_linear_memory_start_segment_offset),
80 [firstInvalidMemory] "i" (cb_first_invalid_memory_address_segment_offset),
81 [sizeOfOneWASMPage] "i" (wasm_constraints::wasm_page_size)
82 : "cc"
83 );
84
85
86 return (void*)ptr;
87}
88
93{
94 constexpr int cb_full_linear_memory_start_segment_offset = OFFSET_OF_CONTROL_BLOCK_MEMBER(full_linear_memory_start);
95 constexpr int cb_first_invalid_memory_address_segment_offset = OFFSET_OF_CONTROL_BLOCK_MEMBER(first_invalid_memory_address);
96
97 char dumpster;
98 uint64_t scratch;
99
100 asm volatile("mov %%gs:(%[Ptr]), %[Dumpster]\n" //probe memory location at ptr to see if valid
101 "mov %%gs:%c[firstInvalidMemory], %[Scratch]\n" //get first invalid memory address
102 "cmpb $0, %%gs:-1(%[Scratch])\n" //is last byte in valid linear memory 0?
103 "je 2f\n" //if so, this will be a null terminated string one way or another
104 "mov %[Ptr],%[Scratch]\n"
105 "1:\n" //start loop looking for either 0, or until we SEGV
106 "inc %[Scratch]\n"
107 "cmpb $0,%%gs:-1(%[Scratch])\n"
108 "jne 1b\n"
109 "2:\n"
110 "add %%gs:%c[linearMemoryStart], %[Ptr]\n" //add address of linear memory 0 to ptr
111 : [Ptr] "+r" (ptr),
112 [Dumpster] "=r" (dumpster),
113 [Scratch] "=r" (scratch)
114 : [linearMemoryStart] "i" (cb_full_linear_memory_start_segment_offset),
115 [firstInvalidMemory] "i" (cb_first_invalid_memory_address_segment_offset)
116 : "cc"
117 );
118
119 return (char*)ptr;
120}
121
122inline auto convert_native_to_wasm(char* ptr) {
123 constexpr int cb_full_linear_memory_start_offset = OFFSET_OF_CONTROL_BLOCK_MEMBER(full_linear_memory_start);
124 char* full_linear_memory_start;
125 asm("mov %%gs:%c[fullLinearMemOffset], %[fullLinearMem]\n"
126 : [fullLinearMem] "=r" (full_linear_memory_start)
127 : [fullLinearMemOffset] "i" (cb_full_linear_memory_start_offset)
128 );
129 U64 delta = (U64)(ptr - full_linear_memory_start);
130 return (U32)delta;
131}
132
133
134template<typename T>
136
137template<>
139 static constexpr auto value = ValueType::f32;
140};
141
142template<>
144 static constexpr auto value = ValueType::f64;
145};
146template<>
148 static constexpr auto value = ValueType::i32;
149};
150template<>
152 static constexpr auto value = ValueType::i64;
153};
154
155template<typename T>
157
158template<typename T>
160template<>
162 static constexpr auto value = ResultType::f32;
163};
164template<>
166 static constexpr auto value = ResultType::f64;
167};
168template<>
170 static constexpr auto value = ResultType::i32;
171};
172template<>
174 static constexpr auto value = ResultType::i64;
175};
176template<>
178 static constexpr auto value = ResultType::none;
179};
180
181
182template<typename T>
184
185
189template<typename>
191
195template<typename Ret, typename ...Args>
201
203 inline const auto& operand_from_back(std::size_t index) const { return *(os - index - 1); }
205};
206
207struct eos_vm_oc_type_converter : public sysio::vm::type_converter<webassembly::interface, eos_vm_oc_execution_interface> {
209 using base_type::type_converter;
210 using base_type::to_wasm;
213
214 SYS_VM_FROM_WASM(bool, (uint32_t value)) { return value ? 1 : 0; }
215
217 auto d = array_ptr_impl<char>(dst, size);
218 auto s = array_ptr_impl<char>(src, size);
219 array_ptr_impl<char>(dst, 1);
220 return { d, s, size };
221 }
222
224 auto l = array_ptr_impl<char>(lhs, size);
225 auto r = array_ptr_impl<char>(rhs, size);
226 return { l, r, size };
227 }
228
230 auto d = array_ptr_impl<char>(dst, size);
231 array_ptr_impl<char>(dst, 1);
232 return { d, val, size };
233 }
234
235 template <typename T>
236 auto from_wasm(vm::wasm_ptr_t ptr) const
237 -> std::enable_if_t< std::is_pointer_v<T>,
240 return {p};
241 }
242
243 template <typename T>
245 -> std::enable_if_t<vm::is_span_type_v<T>, T> {
247 return {static_cast<typename T::pointer>(p), len};
248 }
249
250 template <typename T>
252 -> std::enable_if_t< vm::is_argument_proxy_type_v<T> &&
253 vm::is_span_type_v<typename T::proxy_type>, T> {
255 return {p, len};
256 }
257
258 template <typename T>
259 auto from_wasm(vm::wasm_ptr_t ptr, vm::tag<T> = {}) const
260 -> std::enable_if_t< vm::is_argument_proxy_type_v<T> &&
261 std::is_pointer_v<typename T::proxy_type>, T> {
262 if constexpr(T::is_legacy()) {
263 SYS_ASSERT(ptr != 0, wasm_execution_error, "references cannot be created for null pointers");
264 }
266 return {p};
267 }
268
270 auto p = null_terminated_ptr_impl(ptr);
271 return {static_cast<const char*>(p)};
272 }
273 SYS_VM_FROM_WASM(name, (uint64_t e)) { return name{e}; }
274 uint64_t to_wasm(name&& n) { return n.to_uint64_t(); }
275 vm::wasm_ptr_t to_wasm(void*&& ptr) {
276 return convert_native_to_wasm(static_cast<char*>(ptr));
277 }
278 SYS_VM_FROM_WASM(float32_t, (float f)) { return ::to_softfloat32(f); }
279 SYS_VM_FROM_WASM(float64_t, (double f)) { return ::to_softfloat64(f); }
280
281 template<typename T>
282 inline decltype(auto) as_value(const vm::native_value& val) const {
283 if constexpr (std::is_integral_v<T> && sizeof(T) == 4)
284 return static_cast<T>(val.i32);
285 else if constexpr (std::is_integral_v<T> && sizeof(T) == 8)
286 return static_cast<T>(val.i64);
287 else if constexpr (std::is_floating_point_v<T> && sizeof(T) == 4)
288 return static_cast<T>(val.f32);
289 else if constexpr (std::is_floating_point_v<T> && sizeof(T) == 8)
290 return static_cast<T>(val.f64);
291 // No direct pointer support
292 else
293 return vm::no_match_t{};
294 }
295};
296
297template<typename Args, std::size_t... Is>
298auto get_ct_args(std::index_sequence<Is...>);
299
300inline uint32_t make_native_type(vm::i32_const_t x) { return x.data.ui; }
301inline uint64_t make_native_type(vm::i64_const_t x) { return x.data.ui; }
302inline float make_native_type(vm::f32_const_t x) { return x.data.f; }
303inline double make_native_type(vm::f64_const_t x) { return x.data.f; }
304
305template<typename TC, typename Args, std::size_t... Is>
306auto get_ct_args_one(std::index_sequence<Is...>) {
307 return std::tuple<decltype(make_native_type(std::declval<TC>().as_result(std::declval<std::tuple_element_t<Is, Args>>())))...>();
308}
309
310template<typename TC, typename T>
312 if constexpr (vm::detail::has_from_wasm_v<T, TC>) {
314 return get_ct_args_one<TC, args_tuple>(std::make_index_sequence<std::tuple_size_v<args_tuple>>());
315 } else {
316 return std::tuple<decltype(make_native_type(std::declval<TC>().as_result(std::declval<T>())))>();
317 }
318}
319
320template<typename Args, std::size_t... Is>
321auto get_ct_args(std::index_sequence<Is...>) {
322 return std::tuple_cat(get_ct_args_i<eos_vm_oc_type_converter, std::tuple_element_t<Is, Args>>()...);
323}
324
326 // Suppress "expression result unused" warnings
328 template<typename T>
329 auto operator,(T&& res) {
330 return make_native_type(vm::detail::resolve_result(tc, static_cast<T&&>(res)));
331 }
333};
334
335template<auto F, typename Interface, typename Preconditions, bool is_injected, typename... A>
336auto fn(A... a) {
337 try {
338 if constexpr(!is_injected) {
339 constexpr int cb_current_call_depth_remaining_segment_offset = OFFSET_OF_CONTROL_BLOCK_MEMBER(current_call_depth_remaining);
340 constexpr int depth_assertion_intrinsic_offset = OFFSET_OF_FIRST_INTRINSIC - (int) find_intrinsic_index("eosvmoc_internal.depth_assert") * 8;
341
342 asm volatile("cmpl $1,%%gs:%c[callDepthRemainOffset]\n"
343 "jne 1f\n"
344 "callq *%%gs:%c[depthAssertionIntrinsicOffset]\n"
345 "1:\n"
346 :
347 : [callDepthRemainOffset] "i" (cb_current_call_depth_remaining_segment_offset),
348 [depthAssertionIntrinsicOffset] "i" (depth_assertion_intrinsic_offset)
349 : "cc");
350 }
351 using native_args = vm::flatten_parameters_t<AUTO_PARAM_WORKAROUND(F)>;
352 sysio::vm::native_value stack[] = { a... };
353 constexpr int cb_ctx_ptr_offset = OFFSET_OF_CONTROL_BLOCK_MEMBER(ctx);
354 apply_context* ctx;
355 asm("mov %%gs:%c[applyContextOffset], %[cPtr]\n"
356 : [cPtr] "=r" (ctx)
357 : [applyContextOffset] "i" (cb_ctx_ptr_offset)
358 );
359 Interface host(*ctx);
361 return result_resolver{tc}, sysio::vm::invoke_with_host<F, Preconditions, native_args>(tc, &host, std::make_index_sequence<sizeof...(A)>());
362 }
363 catch(...) {
364 *reinterpret_cast<std::exception_ptr*>(eos_vm_oc_get_exception_ptr()) = std::current_exception();
365 }
367 __builtin_unreachable();
368}
369
370template<auto F, typename Preconditions, typename Args, bool is_injected, std::size_t... Is>
374
375template<auto F, typename Preconditions, bool is_injected>
376constexpr auto create_function() {
377 using native_args = vm::flatten_parameters_t<AUTO_PARAM_WORKAROUND(F)>;
378 using wasm_args = decltype(get_ct_args<native_args>(std::make_index_sequence<std::tuple_size_v<native_args>>()));
379 return create_function<F, Preconditions, wasm_args, is_injected>(std::make_index_sequence<std::tuple_size_v<wasm_args>>());
380}
381
382template<auto F, bool injected, typename Preconditions, typename Name>
383void register_eosvm_oc(Name n) {
384 // Has special handling
385 if(n == BOOST_HANA_STRING("env.sysio_exit")) return;
387 constexpr auto index = find_intrinsic_index(n.c_str());
388 intrinsic the_intrinsic(
389 n.c_str(),
390 wasm_function_type_provider<std::remove_pointer_t<decltype(fn)>>::type(),
391 reinterpret_cast<void*>(fn),
392 index
393 );
394}
395
396} } } }// sysio::chain::webassembly::eosvmoc
uint64_t U64
Definition BasicTypes.h:11
uint32_t U32
Definition BasicTypes.h:9
float F32
Definition BasicTypes.h:13
double F64
Definition BasicTypes.h:14
const mie::Vuint & p
Definition bn.cpp:27
const mie::Vuint & r
Definition bn.cpp:28
#define SYS_ASSERT(expr, exc_type, FORMAT,...)
Definition exceptions.hpp:7
#define OFFSET_OF_CONTROL_BLOCK_MEMBER(M)
Definition memory.hpp:66
#define OFFSET_OF_FIRST_INTRINSIC
Definition memory.hpp:67
eosvmoc_runtime(const boost::filesystem::path data_dir, const eosvmoc::config &eosvmoc_config, const chainbase::database &db)
Definition sys-vm-oc.cpp:39
std::unique_ptr< wasm_instantiated_module_interface > instantiate_module(const char *code_bytes, size_t code_size, std::vector< uint8_t > initial_memory, const digest_type &code_hash, const uint8_t &vm_type, const uint8_t &vm_version) override
Definition sys-vm-oc.cpp:46
sigjmp_buf * eos_vm_oc_get_jmp_buf()
void * eos_vm_oc_get_exception_ptr()
namespace sysio::chain
Definition authority.cpp:3
constexpr std::size_t find_intrinsic_index(std::string_view hf)
void * array_ptr_impl(size_t ptr, size_t length)
Definition sys-vm-oc.hpp:63
uint32_t make_native_type(vm::i32_const_t x)
char * null_terminated_ptr_impl(uint64_t ptr)
Definition sys-vm-oc.hpp:92
auto get_ct_args(std::index_sequence< Is... >)
auto get_ct_args_one(std::index_sequence< Is... >)
constexpr auto resolve_result(Type_Converter &tc, T &&val)
strip_tag< flatten_parameters_t<&TC::template from_wasm< T > > > from_wasm_type_deducer_t
decltype(auto) invoke_with_host(Type_Converter &tc, Host *host, std::index_sequence< Is... >)
std::uint32_t wasm_ptr_t
Definition types.hpp:149
decltype(flatten_parameters(AUTO_PARAM_WORKAROUND(FN))) flatten_parameters_t
std::uint32_t wasm_size_t
Definition types.hpp:150
#define value
Definition pkcs11.h:157
const GenericPointer< typename T::ValueType > T2 T::AllocatorType & a
Definition pointer.h:1181
#define T(meth, val, expected)
schedule config_dir_name data_dir_name p2p_port http_port file_size name host(p2p_endpoint)) FC_REFLECT(tn_node_def
unsigned int uint32_t
Definition stdint.h:126
signed int int32_t
Definition stdint.h:123
unsigned char uint8_t
Definition stdint.h:124
unsigned __int64 uint64_t
Definition stdint.h:136
static IR_API const FunctionType * get(ResultType ret, const std::initializer_list< ValueType > &parameters)
Definition Types.cpp:38
Immutable except for fc::from_variant.
Definition name.hpp:43
auto from_wasm(vm::wasm_ptr_t ptr, vm::wasm_size_t len, vm::tag< T >={}) const -> std::enable_if_t< vm::is_argument_proxy_type_v< T > &&vm::is_span_type_v< typename T::proxy_type >, T >
SYS_VM_FROM_WASM(null_terminated_ptr,(vm::wasm_ptr_t ptr))
SYS_VM_FROM_WASM(memcmp_params,(vm::wasm_ptr_t lhs, vm::wasm_ptr_t rhs, vm::wasm_size_t size))
decltype(auto) as_value(const vm::native_value &val) const
auto from_wasm(vm::wasm_ptr_t ptr) const -> std::enable_if_t< std::is_pointer_v< T >, vm::argument_proxy< T > >
auto from_wasm(vm::wasm_ptr_t ptr, vm::wasm_size_t len, vm::tag< T >={}) const -> std::enable_if_t< vm::is_span_type_v< T >, T >
auto from_wasm(vm::wasm_ptr_t ptr, vm::tag< T >={}) const -> std::enable_if_t< vm::is_argument_proxy_type_v< T > &&std::is_pointer_v< typename T::proxy_type >, T >
SYS_VM_FROM_WASM(memset_params,(vm::wasm_ptr_t dst, int32_t val, vm::wasm_size_t size))
SYS_VM_FROM_WASM(memcpy_params,(vm::wasm_ptr_t dst, vm::wasm_ptr_t src, vm::wasm_size_t size))
#define AUTO_PARAM_WORKAROUND(X)
CK_ULONG d
char * s
size_t len
int l