提交 0978f345 编写于 作者: B Bart Wyatt

all tests pass with interpreter, soft switch to retire individual actions with...

all tests pass with interpreter, soft switch to retire individual actions with interpreter or jitter
上级 f7a979d2
......@@ -97,6 +97,11 @@ namespace eosio { namespace chain {
*/
class wasm_interface {
public:
enum class vm_type {
wavm,
binaryen,
};
static wasm_interface& get();
/**
......@@ -105,11 +110,11 @@ namespace eosio { namespace chain {
* @param context - the interface by which the contract can interact
* with blockchain state.
*/
void apply( wasm_cache::entry& code, apply_context& context );
void apply( wasm_cache::entry& code, apply_context& context, vm_type vm = vm_type::wavm );
/**
*/
void error( wasm_cache::entry& code, apply_context& context );
void error( wasm_cache::entry& code, apply_context& context, vm_type vm = vm_type::wavm );
private:
wasm_interface();
......
......@@ -29,6 +29,16 @@ struct intrinsic_registrator {
}
};
// create own module instance to access memorySize
class interpreter_instance : public ModuleInstance {
public:
using ModuleInstance::ModuleInstance;
void set_accessible_pages(uint32_t num_pages) {
memorySize = num_pages;
}
};
struct interpreter_interface : ModuleInstance::ExternalInterface {
interpreter_interface(linear_memory_type& memory, call_indirect_table_type& table, const uint32_t& sbrk_bytes)
:memory(memory),table(table), sbrk_bytes(sbrk_bytes)
......@@ -47,7 +57,8 @@ struct interpreter_interface : ModuleInstance::ExternalInterface {
{
// TODO: build a LUT based on Import * as that is stable from the module->
if (import->module == "env") {
return intrinsic_registrator::get_map()[string(import->name.c_str())](args);
auto& intrinsic_map = intrinsic_registrator::get_map();
return intrinsic_map[string(import->base.c_str())](args);
}
FC_THROW_EXCEPTION(wasm_execution_error, "unknown import ${m}:${n}", ("m", import->module.c_str())("n", import->module.c_str()));
......@@ -138,6 +149,7 @@ public:
linear_memory_type memory;
call_indirect_table_type table;
interpreter_interface* interface;
interpreter_instance* instance;
uint32_t sbrk_bytes;
void reset(const info& );
......@@ -287,7 +299,7 @@ inline auto convert_native_to_literal(wasm_interface &wasm, char* ptr) {
const auto& mem = entry::get(wasm).interface->memory;
const char* base = mem.data;
const char* top_of_memory = base + mem.size();
EOS_ASSERT(ptr < base || ptr >= top_of_memory, wasm_execution_error, "returning pointer not in linear memory");
EOS_ASSERT(ptr >= base && ptr < top_of_memory, wasm_execution_error, "returning pointer not in linear memory");
return Literal((int)(ptr - base));
}
......@@ -386,7 +398,7 @@ struct intrinsic_invoker_impl<Ret, std::tuple<array_ptr<T>, size_t, Inputs...>>
template<then_type Then>
static Ret translate_one(wasm_interface &wasm, Inputs... rest, LiteralList& args, int offset) {
uint32_t ptr = args.at(offset - 1).geti32();
size_t length = args.at(offset).geti64();
size_t length = args.at(offset).geti32();
return Then(wasm, array_ptr_impl<T>(wasm, ptr, length), length, rest..., args, offset - 2);
};
......@@ -438,7 +450,7 @@ struct intrinsic_invoker_impl<Ret, std::tuple<array_ptr<T>, array_ptr<U>, size_t
static Ret translate_one(wasm_interface &wasm, Inputs... rest, LiteralList& args, int offset) {
uint32_t ptr_t = args.at(offset - 2).geti32();
uint32_t ptr_u = args.at(offset - 1).geti32();
size_t length = args.at(offset).geti64();
size_t length = args.at(offset).geti32();
return Then(wasm, array_ptr_impl<T>(wasm, ptr_t, length), array_ptr_impl<U>(wasm, ptr_u, length), length, args, offset - 3);
};
......@@ -463,7 +475,7 @@ struct intrinsic_invoker_impl<Ret, std::tuple<array_ptr<char>, int, size_t>> {
static Ret translate_one(wasm_interface &wasm, LiteralList& args, int offset) {
uint32_t ptr = args.at(offset - 2).geti32();
uint32_t value = args.at(offset - 1).geti32();
size_t length = args.at(offset).geti64();
size_t length = args.at(offset).geti32();
return Then(wasm, array_ptr_impl<char>(wasm, ptr, length), value, length, args, offset - 3);
};
......
......@@ -12,13 +12,15 @@ namespace eosio { namespace chain { namespace webassembly { namespace common {
using wasm_double = boost::multiprecision::cpp_dec_float_50;
struct wasm_context {
wasm_context(wasm_cache::entry &code, apply_context& ctx)
wasm_context(wasm_cache::entry &code, apply_context& ctx, wasm_interface::vm_type vm)
: code(code)
, context(ctx)
, vm(vm)
{
}
eosio::chain::wasm_cache::entry& code;
apply_context& context;
wasm_interface::vm_type vm;
};
class intrinsics_accessor {
......
......@@ -294,14 +294,28 @@ namespace eosio { namespace chain {
return *single;
}
void wasm_interface::apply( wasm_cache::entry& code, apply_context& context ) {
auto context_guard = scoped_context(my->current_context, code, context);
code.wavm.call_apply(context);
void wasm_interface::apply( wasm_cache::entry& code, apply_context& context, vm_type vm ) {
auto context_guard = scoped_context(my->current_context, code, context, vm);
switch (vm) {
case vm_type::wavm:
code.wavm.call_apply(context);
break;
case vm_type::binaryen:
code.binaryen.call_apply(context);
break;
}
}
void wasm_interface::error( wasm_cache::entry& code, apply_context& context ) {
auto context_guard = scoped_context(my->current_context, code, context);
code.wavm.call_error(context);
void wasm_interface::error( wasm_cache::entry& code, apply_context& context, vm_type vm ) {
auto context_guard = scoped_context(my->current_context, code, context, vm);
switch (vm) {
case vm_type::wavm:
code.wavm.call_error(context);
break;
case vm_type::binaryen:
code.binaryen.call_error(context);
break;
}
}
wasm_context& common::intrinsics_accessor::get_context(wasm_interface &wasm) {
......@@ -325,12 +339,15 @@ namespace eosio { namespace chain {
class context_aware_api {
public:
context_aware_api(wasm_interface& wasm)
:context(intrinsics_accessor::get_context(wasm).context), code(intrinsics_accessor::get_context(wasm).code)
:context(intrinsics_accessor::get_context(wasm).context)
,code(intrinsics_accessor::get_context(wasm).code)
,vm(intrinsics_accessor::get_context(wasm).vm)
{}
protected:
wasm_cache::entry& code;
apply_context& context;
wasm_cache::entry& code;
apply_context& context;
wasm_interface::vm_type vm;
};
class privileged_api : public context_aware_api {
......@@ -842,7 +859,12 @@ class memory_api : public context_aware_api {
}
uint32_t sbrk(int num_bytes) {
return code.wavm.sbrk(num_bytes);
switch(vm) {
case wasm_interface::vm_type::wavm:
return (uint32_t)code.wavm.sbrk(num_bytes);
case wasm_interface::vm_type::binaryen:
return (uint32_t)code.binaryen.sbrk(num_bytes);
}
}
};
......
......@@ -10,8 +10,9 @@ void entry::call(const string &entry_point, LiteralList& args, apply_context &co
{
interpreter_interface local_interface(memory, table, sbrk_bytes);
interface = &local_interface;
ModuleInstance instance(*module.get(), interface);
instance.callExport(Name(entry_point), args);
interpreter_instance local_instance(*module.get(), interface);
instance = &local_instance;
local_instance.callExport(Name(entry_point), args);
}
void entry::call_apply(apply_context& context)
......@@ -45,6 +46,8 @@ int entry::sbrk(int num_bytes) {
// update the number of bytes allocated, and compute the number of pages needed
sbrk_bytes += num_bytes;
auto num_accessible_pages = (sbrk_bytes + Memory::kPageSize - 1) >> NBPPL2;
instance->set_accessible_pages(num_accessible_pages);
return prev_num_bytes;
}
......@@ -59,6 +62,92 @@ void entry::reset(const info& base_info) {
interface = nullptr;
}
static Expression* create_call_checktime(Import *checktime, Module &module) {
// create a calling expression
CallImport *call = module.allocator.alloc<CallImport>();
Const *value = module.allocator.alloc<Const>();
value->finalize();
value->set(Literal(11));
call->target = checktime->name;
call->operands.resize(1);
call->operands[0] = value;
call->type = WasmType::none;
call->finalize();
return call;
}
static Block* convert_to_injected_block(Expression *expr, Import *checktime, Module &module) {
Block *block = module.allocator.alloc<Block>();
block->list.push_back(create_call_checktime(checktime, module));
block->list.push_back(expr);
block->finalize();
return block;
}
static void inject_checktime_block(Block *block, Import *checktime, Module &module)
{
auto old_size = block->list.size();
block->list.resize(block->list.size() + 1);
if (old_size > 0) {
memmove(&block->list[1], &block->list[0], old_size * sizeof(Expression *));
}
block->list[0] = create_call_checktime(checktime, module);
for (int i = 1; i < block->list.size(); i++) {
auto* expr = block->list[i];
if (expr->is<Block>()) {
inject_checktime_block(expr->cast<Block>(), checktime, module);
} else if (expr->is<Loop>()) {
Loop *loop = expr->cast<Loop>();
if (loop->body->is<Block>()) {
inject_checktime_block(loop->body->cast<Block>(), checktime, module);
} else {
loop->body = convert_to_injected_block(loop->body, checktime, module);
}
}
}
}
static void inject_checktime(Module& module)
{
// find an appropriate function type
FunctionType* type = nullptr;
for (auto &t: module.functionTypes) {
if (t->result == WasmType::none && t->params.size() == 1 && t->params.at(0) == WasmType::i32) {
type = t.get();
}
}
if (!type) {
// create the type
type = new FunctionType();
type->name = Name(string("checktime-injected"));
type->params.push_back(WasmType::i32);
type->result = WasmType::none;
module.addFunctionType(type);
}
// inject the import
Import *import = new Import();
import->name = Name(string("checktime"));
import->module = Name(string("env"));
import->base = Name(string("checktime"));
import->kind = ExternalKind::Function;
import->functionType = type->name;
module.addImport(import);
// walk the ops and inject the callImport on function bodies, blocks and loops
for(auto &fn: module.functions) {
if (fn->body->is<Block>()) {
inject_checktime_block(fn->body->cast<Block>(), import, module);
} else {
fn->body = convert_to_injected_block(fn->body, import, module);
}
}
}
entry entry::build(const char* wasm_binary, size_t wasm_binary_size) {
try {
......@@ -67,6 +156,8 @@ entry entry::build(const char* wasm_binary, size_t wasm_binary_size) {
WasmBinaryBuilder builder(*module, code, false);
builder.read();
inject_checktime(*module.get());
linear_memory_type memory;
call_indirect_table_type table;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册