This repository has been archived by the owner on Aug 2, 2022. It is now read-only.
/
wasm_interface_private.hpp
132 lines (107 loc) · 5.96 KB
/
wasm_interface_private.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
#pragma once
#include <eosio/chain/wasm_interface.hpp>
#include <eosio/chain/webassembly/wavm.hpp>
#include <eosio/chain/webassembly/wabt.hpp>
#include <eosio/chain/webassembly/runtime_interface.hpp>
#include <eosio/chain/wasm_eosio_injection.hpp>
#include <eosio/chain/transaction_context.hpp>
#include <eosio/chain/exceptions.hpp>
#include <fc/scoped_exit.hpp>
#include "IR/Module.h"
#include "Runtime/Intrinsics.h"
#include "Platform/Platform.h"
#include "WAST/WAST.h"
#include "IR/Validate.h"
using namespace fc;
using namespace eosio::chain::webassembly;
using namespace IR;
using namespace Runtime;
namespace eosio { namespace chain {
struct wasm_interface_impl {
wasm_interface_impl(wasm_interface::vm_type vm) {
if(vm == wasm_interface::vm_type::wavm)
runtime_interface = std::make_unique<webassembly::wavm::wavm_runtime>();
else if(vm == wasm_interface::vm_type::wabt)
runtime_interface = std::make_unique<webassembly::wabt_runtime::wabt_runtime>();
else
EOS_THROW(wasm_exception, "wasm_interface_impl fall through");
}
std::vector<uint8_t> parse_initial_memory(const Module& module) {
std::vector<uint8_t> mem_image;
for(const DataSegment& data_segment : module.dataSegments) {
EOS_ASSERT(data_segment.baseOffset.type == InitializerExpression::Type::i32_const, wasm_exception, "");
EOS_ASSERT(module.memories.defs.size(), wasm_exception, "");
const U32 base_offset = data_segment.baseOffset.i32;
const Uptr memory_size = (module.memories.defs[0].type.size.min << IR::numBytesPerPageLog2);
if(base_offset >= memory_size || base_offset + data_segment.data.size() > memory_size)
FC_THROW_EXCEPTION(wasm_execution_error, "WASM data segment outside of valid memory range");
if(base_offset + data_segment.data.size() > mem_image.size())
mem_image.resize(base_offset + data_segment.data.size(), 0x00);
memcpy(mem_image.data() + base_offset, data_segment.data.data(), data_segment.data.size());
}
return mem_image;
}
std::unique_ptr<wasm_instantiated_module_interface>& get_instantiated_module( const digest_type& code_id,
const shared_string& code,
transaction_context& trx_context )
{
auto it = instantiation_cache.find(code_id);
if(it == instantiation_cache.end()) {
auto timer_pause = fc::make_scoped_exit([&](){
trx_context.resume_billing_timer();
});
trx_context.pause_billing_timer();
IR::Module module;
try {
Serialization::MemoryInputStream stream((const U8*)code.data(), code.size());
WASM::serialize(stream, module);
module.userSections.clear();
} catch(const Serialization::FatalSerializationException& e) {
EOS_ASSERT(false, wasm_serialization_error, e.message.c_str());
} catch(const IR::ValidationException& e) {
EOS_ASSERT(false, wasm_serialization_error, e.message.c_str());
}
wasm_injections::wasm_binary_injection injector(module);
injector.inject();
std::vector<U8> bytes;
try {
Serialization::ArrayOutputStream outstream;
WASM::serialize(outstream, module);
bytes = outstream.getBytes();
} catch(const Serialization::FatalSerializationException& e) {
EOS_ASSERT(false, wasm_serialization_error, e.message.c_str());
} catch(const IR::ValidationException& e) {
EOS_ASSERT(false, wasm_serialization_error, e.message.c_str());
}
it = instantiation_cache.emplace(code_id, runtime_interface->instantiate_module((const char*)bytes.data(), bytes.size(), parse_initial_memory(module))).first;
}
return it->second;
}
std::unique_ptr<wasm_runtime_interface> runtime_interface;
map<digest_type, std::unique_ptr<wasm_instantiated_module_interface>> instantiation_cache;
};
#define _REGISTER_INTRINSIC_EXPLICIT(CLS, MOD, METHOD, WASM_SIG, NAME, SIG)\
_REGISTER_WAVM_INTRINSIC(CLS, MOD, METHOD, WASM_SIG, NAME, SIG)\
_REGISTER_WABT_INTRINSIC(CLS, MOD, METHOD, WASM_SIG, NAME, SIG)
#define _REGISTER_INTRINSIC4(CLS, MOD, METHOD, WASM_SIG, NAME, SIG)\
_REGISTER_INTRINSIC_EXPLICIT(CLS, MOD, METHOD, WASM_SIG, NAME, SIG )
#define _REGISTER_INTRINSIC3(CLS, MOD, METHOD, WASM_SIG, NAME)\
_REGISTER_INTRINSIC_EXPLICIT(CLS, MOD, METHOD, WASM_SIG, NAME, decltype(&CLS::METHOD) )
#define _REGISTER_INTRINSIC2(CLS, MOD, METHOD, WASM_SIG)\
_REGISTER_INTRINSIC_EXPLICIT(CLS, MOD, METHOD, WASM_SIG, BOOST_PP_STRINGIZE(METHOD), decltype(&CLS::METHOD) )
#define _REGISTER_INTRINSIC1(CLS, MOD, METHOD)\
static_assert(false, "Cannot register " BOOST_PP_STRINGIZE(CLS) ":" BOOST_PP_STRINGIZE(METHOD) " without a signature");
#define _REGISTER_INTRINSIC0(CLS, MOD, METHOD)\
static_assert(false, "Cannot register " BOOST_PP_STRINGIZE(CLS) ":<unknown> without a method name and signature");
#define _UNWRAP_SEQ(...) __VA_ARGS__
#define _EXPAND_ARGS(CLS, MOD, INFO)\
( CLS, MOD, _UNWRAP_SEQ INFO )
#define _REGISTER_INTRINSIC(R, CLS, INFO)\
BOOST_PP_CAT(BOOST_PP_OVERLOAD(_REGISTER_INTRINSIC, _UNWRAP_SEQ INFO) _EXPAND_ARGS(CLS, "env", INFO), BOOST_PP_EMPTY())
#define REGISTER_INTRINSICS(CLS, MEMBERS)\
BOOST_PP_SEQ_FOR_EACH(_REGISTER_INTRINSIC, CLS, _WRAPPED_SEQ(MEMBERS))
#define _REGISTER_INJECTED_INTRINSIC(R, CLS, INFO)\
BOOST_PP_CAT(BOOST_PP_OVERLOAD(_REGISTER_INTRINSIC, _UNWRAP_SEQ INFO) _EXPAND_ARGS(CLS, EOSIO_INJECTED_MODULE_NAME, INFO), BOOST_PP_EMPTY())
#define REGISTER_INJECTED_INTRINSICS(CLS, MEMBERS)\
BOOST_PP_SEQ_FOR_EACH(_REGISTER_INJECTED_INTRINSIC, CLS, _WRAPPED_SEQ(MEMBERS))
} } // eosio::chain