Kagome
Polkadot Runtime Engine in C++17
module_instance.cpp
Go to the documentation of this file.
1 
7 
8 #include <WAVM/Runtime/Runtime.h>
9 #include <WAVM/RuntimeABI/RuntimeABI.h>
10 
11 #include "host_api/host_api.hpp"
12 #include "log/profiling_logger.hpp"
19 
20 static WAVM::IR::Value evaluateInitializer(
21  WAVM::IR::InitializerExpression expression) {
22  using WAVM::IR::InitializerExpression;
23  switch (expression.type) {
24  case InitializerExpression::Type::i32_const:
25  return expression.i32;
26  case InitializerExpression::Type::i64_const:
27  return expression.i64;
28  case InitializerExpression::Type::f32_const:
29  return expression.f32;
30  case InitializerExpression::Type::f64_const:
31  return expression.f64;
32  case InitializerExpression::Type::v128_const:
33  return expression.v128;
34  case InitializerExpression::Type::global_get: {
35  throw std::runtime_error{"Not implemented on WAVM yet"};
36  }
37  case InitializerExpression::Type::ref_null:
38  return WAVM::IR::Value(asValueType(expression.nullReferenceType),
39  WAVM::IR::UntaggedValue());
40 
41  case InitializerExpression::Type::ref_func:
42  // instantiateModule delays evaluating ref.func initializers until the
43  // module is loaded and we have addresses for its functions.
44 
45  case InitializerExpression::Type::invalid:
46  default:
47  WAVM_UNREACHABLE();
48  };
49 }
50 
51 static WAVM::Uptr getIndexValue(const WAVM::IR::Value &value,
52  WAVM::IR::IndexType indexType) {
53  switch (indexType) {
54  case WAVM::IR::IndexType::i32:
55  WAVM_ASSERT(value.type == WAVM::IR::ValueType::i32);
56  return value.u32;
57  case WAVM::IR::IndexType::i64:
58  WAVM_ASSERT(value.type == WAVM::IR::ValueType::i64);
59  return value.u64;
60  default:
61  WAVM_UNREACHABLE();
62  };
63 }
64 
67  e) {
69  switch (e) {
70  case E::WRONG_ARG_COUNT:
71  return "The provided function argument count should equal to 2";
72  case E::FUNC_NOT_FOUND:
73  return "The requested function not found";
74  case E::EXECUTION_ERROR:
75  return "An error occurred during wasm call execution; Check the logs for "
76  "more information";
77  case E::WRONG_RETURN_TYPE:
78  return "Runtime function returned result of unsupported type";
79  }
80  return "Unknown error in ModuleInstance";
81 }
82 
83 namespace kagome::runtime::wavm {
84 
87  WAVM::Runtime::GCPointer<WAVM::Runtime::Instance> instance,
88  WAVM::Runtime::ModuleRef module,
89  std::shared_ptr<const CompartmentWrapper> compartment,
90  const common::Hash256 &code_hash)
91  : env_{std::move(env)},
92  instance_{std::move(instance)},
93  module_{std::move(module)},
94  compartment_{std::move(compartment)},
95  code_hash_(code_hash),
96  logger_{log::createLogger("ModuleInstance", "wavm")} {
97  BOOST_ASSERT(instance_ != nullptr);
98  BOOST_ASSERT(compartment_ != nullptr);
99  BOOST_ASSERT(module_ != nullptr);
100  }
101 
102  outcome::result<PtrSize> ModuleInstanceImpl::callExportFunction(
103  std::string_view name, common::BufferView encoded_args) const {
104  auto memory = env_.memory_provider->getCurrentMemory().value();
105 
106  PtrSize args_span{memory.get().storeBuffer(encoded_args)};
107 
108  auto res = [this, name, args_span]() -> outcome::result<PtrSize> {
109  WAVM::Runtime::GCPointer<WAVM::Runtime::Context> context =
110  WAVM::Runtime::createContext(compartment_->getCompartment());
111  WAVM::Runtime::Function *function = WAVM::Runtime::asFunctionNullable(
112  WAVM::Runtime::getInstanceExport(instance_, name.data()));
113  if (!function) {
114  SL_DEBUG(logger_, "The requested function {} not found", name);
115  return Error::FUNC_NOT_FOUND;
116  }
117  const WAVM::IR::FunctionType functionType =
118  WAVM::Runtime::getFunctionType(function);
119  if (functionType.params().size() != 2) { // address and size
120  SL_DEBUG(
121  logger_,
122  "The provided function argument count should equal to 2, got {} "
123  "instead",
124  functionType.params().size());
125  return Error::WRONG_ARG_COUNT;
126  }
127  WAVM_ASSERT(function)
128 
129  WAVM::IR::TypeTuple invokeArgTypes{WAVM::IR::ValueType::i32,
130  WAVM::IR::ValueType::i32};
131  // Infer the expected type of the function from the number and type of the
132  // invocation arguments and the function's actual result types.
133  const WAVM::IR::FunctionType invokeSig(
134  WAVM::Runtime::getFunctionType(function).results(),
135  std::move(invokeArgTypes));
136  // Allocate an array to receive the invocation results.
137  BOOST_ASSERT(invokeSig.results().size() == 1);
138  std::array<WAVM::IR::UntaggedValue, 1> untaggedInvokeResults;
140  std::const_pointer_cast<ModuleInstanceImpl>(shared_from_this()));
141  const auto pop = gsl::finally(&popBorrowedRuntimeInstance);
142  try {
143  WAVM::Runtime::unwindSignalsAsExceptions(
144  [&context,
145  &function,
146  &invokeSig,
147  args = args_span,
148  resultsDestination = untaggedInvokeResults.data()] {
149  std::array<WAVM::IR::UntaggedValue, 2> untaggedInvokeArgs{
150  static_cast<WAVM::U32>(args.ptr),
151  static_cast<WAVM::U32>(args.size)};
152  WAVM::Runtime::invokeFunction(context,
153  function,
154  invokeSig,
155  untaggedInvokeArgs.data(),
156  resultsDestination);
157  });
158  return PtrSize{untaggedInvokeResults[0].u64};
159  } catch (WAVM::Runtime::Exception *e) {
160  const auto desc = WAVM::Runtime::describeException(e);
161  logger_->error(desc);
162  WAVM::Runtime::destroyException(e);
163  return Error::EXECUTION_ERROR;
164  }
165  }();
166  WAVM::Runtime::collectCompartmentGarbage(compartment_->getCompartment());
167  return res;
168  }
169 
170  outcome::result<std::optional<WasmValue>> ModuleInstanceImpl::getGlobal(
171  std::string_view name) const {
172  auto global = WAVM::Runtime::asGlobalNullable(
173  WAVM::Runtime::getInstanceExport(instance_, name.data()));
174  if (global == nullptr) return std::nullopt;
175  WAVM::Runtime::GCPointer<WAVM::Runtime::Context> context =
176  WAVM::Runtime::createContext(compartment_->getCompartment());
177  auto value = WAVM::Runtime::getGlobalValue(context, global);
178  switch (value.type) {
179  case WAVM::IR::ValueType::i32:
180  return WasmValue{static_cast<int32_t>(value.i32)};
181  case WAVM::IR::ValueType::i64:
182  return WasmValue{static_cast<int64_t>(value.i64)};
183  case WAVM::IR::ValueType::f32:
184  return WasmValue{static_cast<float>(value.f32)};
185  case WAVM::IR::ValueType::f64:
186  return WasmValue{static_cast<double>(value.f64)};
187  default:
188  SL_DEBUG(logger_,
189  "Runtime function returned result of unsupported type: {}",
190  asString(value));
192  }
193  }
194 
196  DataSegmentProcessor const &callback) const {
197  using WAVM::Uptr;
198  using WAVM::IR::DataSegment;
199  using WAVM::IR::MemoryType;
200  using WAVM::IR::Value;
201  auto ir = getModuleIR(module_);
202 
203  for (Uptr segmentIndex = 0; segmentIndex < ir.dataSegments.size();
204  ++segmentIndex) {
205  const DataSegment &dataSegment = ir.dataSegments[segmentIndex];
206  if (dataSegment.isActive) {
207  const Value baseOffsetValue =
208  evaluateInitializer(dataSegment.baseOffset);
209  const MemoryType &memoryType =
210  ir.memories.getType(dataSegment.memoryIndex);
211  Uptr baseOffset = getIndexValue(baseOffsetValue, memoryType.indexType);
212  callback(baseOffset, *dataSegment.data);
213  }
214  }
215  }
216 
218  return env_;
219  }
220 
221  outcome::result<void> ModuleInstanceImpl::resetEnvironment() {
222  env_.host_api->reset();
223  return outcome::success();
224  }
225 } // namespace kagome::runtime::wavm
std::function< void(SegmentOffset, SegmentData)> DataSegmentProcessor
InstanceEnvironment const & getEnvironment() const override
static WAVM::IR::Value evaluateInitializer(WAVM::IR::InitializerExpression expression)
static WAVM::Uptr getIndexValue(const WAVM::IR::Value &value, WAVM::IR::IndexType indexType)
outcome::result< PtrSize > callExportFunction(std::string_view name, common::BufferView encoded_args) const override
void forDataSegment(DataSegmentProcessor const &callback) const override
std::shared_ptr< const CompartmentWrapper > compartment_
std::shared_ptr< MemoryProvider > memory_provider
ModuleInstanceImpl(InstanceEnvironment &&env, WAVM::Runtime::GCPointer< WAVM::Runtime::Instance > instance, WAVM::Runtime::ModuleRef module, std::shared_ptr< const CompartmentWrapper > compartment, const common::Hash256 &code_hash)
boost::variant< int32_t, int64_t, float, double > WasmValue
std::shared_ptr< host_api::HostApi > host_api
WAVM::Runtime::GCPointer< WAVM::Runtime::Instance > instance_
OUTCOME_CPP_DEFINE_CATEGORY(kagome::runtime::wavm, ModuleInstanceImpl::Error, e)
Logger createLogger(const std::string &tag)
Definition: logger.cpp:112
outcome::result< void > resetEnvironment() override
outcome::result< std::optional< WasmValue > > getGlobal(std::string_view name) const override
void pushBorrowedRuntimeInstance(std::shared_ptr< ModuleInstance > borrowed_runtime_instance)