Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
YottaChain
YTBP
提交
7ea3f14c
Y
YTBP
项目概览
YottaChain
/
YTBP
通知
0
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
Y
YTBP
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
7ea3f14c
编写于
2月 12, 2018
作者:
B
Bart Wyatt
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
move jit into its own isolated space (mostly)
上级
6b14e60f
变更
6
隐藏空白更改
内联
并排
Showing
6 changed file
with
775 addition
and
710 deletion
+775
-710
libraries/chain/CMakeLists.txt
libraries/chain/CMakeLists.txt
+11
-2
libraries/chain/include/eosio/chain/wasm_interface.hpp
libraries/chain/include/eosio/chain/wasm_interface.hpp
+5
-6
libraries/chain/include/eosio/chain/wasm_interface_private.hpp
...ries/chain/include/eosio/chain/wasm_interface_private.hpp
+13
-693
libraries/chain/include/eosio/chain/webassembly/common.hpp
libraries/chain/include/eosio/chain/webassembly/common.hpp
+100
-0
libraries/chain/include/eosio/chain/webassembly/jit.hpp
libraries/chain/include/eosio/chain/webassembly/jit.hpp
+623
-0
libraries/chain/wasm_interface.cpp
libraries/chain/wasm_interface.cpp
+23
-9
未找到文件。
libraries/chain/CMakeLists.txt
浏览文件 @
7ea3f14c
...
...
@@ -31,10 +31,19 @@ add_library( eosio_chain
${
HEADERS
}
transaction_metadata.cpp
)
target_link_libraries
(
eosio_chain eos_utilities fc chainbase Logging IR WAST WASM Runtime
)
target_link_libraries
(
eosio_chain eos_utilities fc chainbase Logging IR WAST WASM Runtime
"/usr/local/share/binaryen/lib/libwasm.a"
"/usr/local/share/binaryen/lib/libasmjs.a"
"/usr/local/share/binaryen/lib/libpasses.a"
"/usr/local/share/binaryen/lib/libcfg.a"
"/usr/local/share/binaryen/lib/libast.a"
"/usr/local/share/binaryen/lib/libemscripten-optimizer.a"
"/usr/local/share/binaryen/lib/libsupport.a"
)
target_include_directories
(
eosio_chain
PUBLIC
"
${
CMAKE_CURRENT_SOURCE_DIR
}
/include"
"
${
CMAKE_CURRENT_BINARY_DIR
}
/include"
"
${
CMAKE_CURRENT_SOURCE_DIR
}
/../wasm-jit/Include"
"
${
CMAKE_CURRENT_SOURCE_DIR
}
/../wasm-jit/Include"
"/usr/local/share/binaryen/src"
)
if
(
MSVC
)
...
...
libraries/chain/include/eosio/chain/wasm_interface.hpp
浏览文件 @
7ea3f14c
...
...
@@ -2,14 +2,13 @@
#include <eosio/chain/exceptions.hpp>
#include <eosio/chain/types.hpp>
namespace
Runtime
{
struct
MemoryInstance
;
}
namespace
eosio
{
namespace
chain
{
class
apply_context
;
class
intrinsics_accessor
;
namespace
webassembly
{
namespace
common
{
class
intrinsics_accessor
;
}
}
/**
* @class wasm_cache
...
...
@@ -115,7 +114,7 @@ namespace eosio { namespace chain {
private:
wasm_interface
();
unique_ptr
<
struct
wasm_interface_impl
>
my
;
friend
class
eosio
::
chain
::
intrinsics_accessor
;
friend
class
eosio
::
chain
::
webassembly
::
common
::
intrinsics_accessor
;
};
}
}
// eosio::chain
libraries/chain/include/eosio/chain/wasm_interface_private.hpp
浏览文件 @
7ea3f14c
#pragma once
#include <eosio/chain/wasm_interface.hpp>
#include <fc/optional.hpp>
#include "Runtime/Runtime.h"
#include "IR/Types.h"
#include <eosio/chain/webassembly/jit.hpp>
#include <boost/multiprecision/cpp_dec_float.hpp>
using
namespace
IR
;
using
namespace
Runtime
;
using
namespace
fc
;
using
namespace
eosio
::
chain
::
webassembly
;
namespace
eosio
{
namespace
chain
{
using
wasm_double
=
boost
::
multiprecision
::
cpp_dec_float_50
;
struct
wasm_cache
::
entry
{
entry
(
ModuleInstance
*
instance
,
Module
*
module
)
:
instance
(
instance
),
module
(
module
)
{
}
ModuleInstance
*
instance
;
Module
*
module
;
};
struct
wasm_context
{
wasm_context
(
wasm_cache
::
entry
&
code
,
apply_context
&
ctx
)
:
code
(
code
),
context
(
ctx
)
{
MemoryInstance
*
default_mem
=
Runtime
::
getDefaultMemory
(
code
.
instance
);
sbrk_bytes
=
default_mem
?
Runtime
::
getMemoryNumPages
(
default_mem
)
<<
IR
::
numBytesPerPageLog2
:
0
;
}
wasm_cache
::
entry
&
code
;
apply_context
&
context
;
uint32_t
sbrk_bytes
;
};
struct
wasm_interface_impl
{
optional
<
wasm_context
>
current_context
;
void
call
(
const
string
&
entry_point
,
const
vector
<
Value
>
&
args
,
wasm_cache
::
entry
&
code
,
apply_context
&
context
);
};
class
intrinsics_accessor
{
public:
static
wasm_context
&
get_context
(
wasm_interface
&
wasm
)
{
FC_ASSERT
(
wasm
.
my
->
current_context
.
valid
());
return
*
wasm
.
my
->
current_context
;
}
};
template
<
typename
T
>
struct
class_from_wasm
{
/**
* by default this is just constructing an object
* @param wasm - the wasm_interface to use
* @return
*/
static
auto
value
(
wasm_interface
&
wasm
)
{
return
T
(
wasm
);
}
};
template
<
>
struct
class_from_wasm
<
apply_context
>
{
/**
* Don't construct a new apply_context, just return a reference to the existing ont
* @param wasm
* @return
*/
static
auto
&
value
(
wasm_interface
&
wasm
)
{
return
intrinsics_accessor
::
get_context
(
wasm
).
context
;
}
};
/**
* class to represent an in-wasm-memory array
* it is a hint to the transcriber that the next parameter will
* be a size (data bytes length) and that the pair are validated together
* This triggers the template specialization of intrinsic_invoker_impl
* @tparam T
*/
template
<
typename
T
>
struct
array_ptr
{
explicit
array_ptr
(
wasm_interface
&
wasm
,
U32
ptr
,
size_t
length
)
:
value
(
validated_ptr
(
wasm
,
ptr
,
length
)){
}
static
T
*
validated_ptr
(
wasm_interface
&
wasm
,
U32
ptr
,
size_t
length
)
{
auto
mem
=
getDefaultMemory
(
intrinsics_accessor
::
get_context
(
wasm
).
code
.
instance
);
if
(
!
mem
||
ptr
+
length
>
IR
::
numBytesPerPage
*
Runtime
::
getMemoryNumPages
(
mem
))
Runtime
::
causeException
(
Exception
::
Cause
::
accessViolation
);
return
(
T
*
)(
getMemoryBaseAddress
(
mem
)
+
ptr
);
}
typename
std
::
add_lvalue_reference
<
T
>::
type
operator
*
()
const
{
return
*
value
;
}
T
*
operator
->
()
const
noexcept
{
return
value
;
}
template
<
typename
U
>
operator
U
*
()
const
{
return
static_cast
<
U
*>
(
value
);
}
T
*
value
;
};
/**
* class to represent an in-wasm-memory char array that must be null terminated
*/
struct
null_terminated_ptr
{
explicit
null_terminated_ptr
(
wasm_interface
&
wasm
,
U32
ptr
)
{
auto
mem
=
getDefaultMemory
(
intrinsics_accessor
::
get_context
(
wasm
).
code
.
instance
);
if
(
!
mem
)
Runtime
::
causeException
(
Exception
::
Cause
::
accessViolation
);
value
=
(
char
*
)(
getMemoryBaseAddress
(
mem
)
+
ptr
);
const
char
*
p
=
value
;
const
char
*
const
top_of_memory
=
(
char
*
)(
getMemoryBaseAddress
(
mem
)
+
IR
::
numBytesPerPage
*
Runtime
::
getMemoryNumPages
(
mem
));
while
(
p
<
top_of_memory
)
if
(
*
p
++
==
'\0'
)
return
;
Runtime
::
causeException
(
Exception
::
Cause
::
accessViolation
);
}
typename
std
::
add_lvalue_reference
<
char
>::
type
operator
*
()
const
{
return
*
value
;
}
char
*
operator
->
()
const
noexcept
{
return
value
;
}
template
<
typename
U
>
operator
U
*
()
const
{
return
static_cast
<
U
*>
(
value
);
}
char
*
value
;
};
/**
* template that maps native types to WASM VM types
* @tparam T the native type
*/
template
<
typename
T
>
struct
native_to_wasm
{
using
type
=
void
;
};
/**
* specialization for mapping pointers to int32's
*/
template
<
typename
T
>
struct
native_to_wasm
<
T
*>
{
using
type
=
I32
;
};
/**
* Mappings for native types
*/
template
<
>
struct
native_to_wasm
<
int32_t
>
{
using
type
=
I32
;
};
template
<
>
struct
native_to_wasm
<
uint32_t
>
{
using
type
=
I32
;
};
template
<
>
struct
native_to_wasm
<
int64_t
>
{
using
type
=
I64
;
};
template
<
>
struct
native_to_wasm
<
uint64_t
>
{
using
type
=
I64
;
};
template
<
>
struct
native_to_wasm
<
bool
>
{
using
type
=
I32
;
};
template
<
>
struct
native_to_wasm
<
const
name
&>
{
using
type
=
I64
;
};
template
<
>
struct
native_to_wasm
<
name
>
{
using
type
=
I64
;
};
template
<
>
struct
native_to_wasm
<
wasm_double
>
{
using
type
=
I64
;
};
template
<
>
struct
native_to_wasm
<
const
fc
::
time_point_sec
&>
{
using
type
=
I32
;
};
template
<
>
struct
native_to_wasm
<
fc
::
time_point_sec
>
{
using
type
=
I32
;
};
// convenience alias
template
<
typename
T
>
using
native_to_wasm_t
=
typename
native_to_wasm
<
T
>::
type
;
template
<
typename
T
>
auto
convert_native_to_wasm
(
const
wasm_interface
&
wasm
,
T
val
)
{
return
native_to_wasm_t
<
T
>
(
val
);
}
auto
convert_native_to_wasm
(
const
wasm_interface
&
wasm
,
const
name
&
val
)
{
return
native_to_wasm_t
<
const
name
&>
(
val
.
value
);
}
auto
convert_native_to_wasm
(
const
wasm_interface
&
wasm
,
const
fc
::
time_point_sec
&
val
)
{
return
native_to_wasm_t
<
const
fc
::
time_point_sec
&>
(
val
.
sec_since_epoch
());
}
auto
convert_native_to_wasm
(
wasm_interface
&
wasm
,
char
*
ptr
)
{
auto
mem
=
getDefaultMemory
(
intrinsics_accessor
::
get_context
(
wasm
).
code
.
instance
);
if
(
!
mem
)
Runtime
::
causeException
(
Exception
::
Cause
::
accessViolation
);
char
*
base
=
(
char
*
)
getMemoryBaseAddress
(
mem
);
char
*
top_of_memory
=
base
+
IR
::
numBytesPerPage
*
Runtime
::
getMemoryNumPages
(
mem
);
if
(
ptr
<
base
||
ptr
>=
top_of_memory
)
Runtime
::
causeException
(
Exception
::
Cause
::
accessViolation
);
return
(
int
)(
ptr
-
base
);
}
template
<
typename
T
>
auto
convert_wasm_to_native
(
native_to_wasm_t
<
T
>
val
)
{
return
T
(
val
);
}
template
<
>
auto
convert_wasm_to_native
<
wasm_double
>
(
I64
val
)
{
return
wasm_double
(
*
reinterpret_cast
<
wasm_double
*>
(
&
val
));
}
template
<
typename
T
>
struct
wasm_to_value_type
;
template
<
>
struct
wasm_to_value_type
<
I32
>
{
static
constexpr
auto
value
=
ValueType
::
i32
;
};
template
<
>
struct
wasm_to_value_type
<
I64
>
{
static
constexpr
auto
value
=
ValueType
::
i64
;
};
template
<
typename
T
>
constexpr
auto
wasm_to_value_type_v
=
wasm_to_value_type
<
T
>::
value
;
template
<
typename
T
>
struct
wasm_to_rvalue_type
;
template
<
>
struct
wasm_to_rvalue_type
<
I32
>
{
static
constexpr
auto
value
=
ResultType
::
i32
;
};
template
<
>
struct
wasm_to_rvalue_type
<
I64
>
{
static
constexpr
auto
value
=
ResultType
::
i64
;
};
template
<
>
struct
wasm_to_rvalue_type
<
void
>
{
static
constexpr
auto
value
=
ResultType
::
none
;
};
template
<
>
struct
wasm_to_rvalue_type
<
const
name
&>
{
static
constexpr
auto
value
=
ResultType
::
i64
;
};
template
<
>
struct
wasm_to_rvalue_type
<
name
>
{
static
constexpr
auto
value
=
ResultType
::
i64
;
};
template
<
>
struct
wasm_to_rvalue_type
<
char
*>
{
static
constexpr
auto
value
=
ResultType
::
i32
;
};
template
<
>
struct
wasm_to_rvalue_type
<
fc
::
time_point_sec
>
{
static
constexpr
auto
value
=
ResultType
::
i32
;
};
template
<
typename
T
>
constexpr
auto
wasm_to_rvalue_type_v
=
wasm_to_rvalue_type
<
T
>::
value
;
template
<
typename
T
>
struct
is_reference_from_value
{
static
constexpr
bool
value
=
false
;
};
template
<
>
struct
is_reference_from_value
<
name
>
{
static
constexpr
bool
value
=
true
;
};
template
<
>
struct
is_reference_from_value
<
fc
::
time_point_sec
>
{
static
constexpr
bool
value
=
true
;
};
template
<
typename
T
>
constexpr
bool
is_reference_from_value_v
=
is_reference_from_value
<
T
>::
value
;
struct
void_type
{
};
/**
* Forward declaration of provider for FunctionType given a desired C ABI signature
*/
template
<
typename
>
struct
wasm_function_type_provider
;
struct
wasm_cache
::
entry
{
entry
(
jit
::
entry
&&
jit
,
uint32_t
default_sbrk_bytes
)
:
jit
(
std
::
forward
<
jit
::
entry
>
(
jit
)),
default_sbrk_bytes
(
default_sbrk_bytes
)
{
}
/**
* specialization to destructure return and arguments
*/
template
<
typename
Ret
,
typename
...
Args
>
struct
wasm_function_type_provider
<
Ret
(
Args
...)
>
{
static
const
FunctionType
*
type
()
{
return
FunctionType
::
get
(
wasm_to_rvalue_type_v
<
Ret
>
,
{
wasm_to_value_type_v
<
Args
>
...});
}
};
/**
* Forward declaration of the invoker type which transcribes arguments to/from a native method
* and injects the appropriate checks
*
* @tparam Ret - the return type of the native function
* @tparam NativeParameters - a std::tuple of the remaining native parameters to transcribe
* @tparam WasmParameters - a std::tuple of the transribed parameters
*/
template
<
typename
Ret
,
typename
NativeParameters
,
typename
WasmParameters
>
struct
intrinsic_invoker_impl
;
/**
* Specialization for the fully transcribed signature
* @tparam Ret - the return type of the native function
* @tparam Translated - the arguments to the wasm function
*/
template
<
typename
Ret
,
typename
...
Translated
>
struct
intrinsic_invoker_impl
<
Ret
,
std
::
tuple
<>
,
std
::
tuple
<
Translated
...
>>
{
using
next_method_type
=
Ret
(
*
)(
wasm_interface
&
,
Translated
...);
template
<
next_method_type
Method
>
static
native_to_wasm_t
<
Ret
>
invoke
(
Translated
...
translated
)
{
wasm_interface
&
wasm
=
wasm_interface
::
get
();
return
convert_native_to_wasm
(
wasm
,
Method
(
wasm
,
translated
...));
}
template
<
next_method_type
Method
>
static
const
auto
fn
()
{
return
invoke
<
Method
>
;
}
};
/**
* specialization of the fully transcribed signature for void return values
* @tparam Translated - the arguments to the wasm function
*/
template
<
typename
...
Translated
>
struct
intrinsic_invoker_impl
<
void_type
,
std
::
tuple
<>
,
std
::
tuple
<
Translated
...
>>
{
using
next_method_type
=
void_type
(
*
)(
wasm_interface
&
,
Translated
...);
template
<
next_method_type
Method
>
static
void
invoke
(
Translated
...
translated
)
{
wasm_interface
&
wasm
=
wasm_interface
::
get
();
Method
(
wasm
,
translated
...);
}
template
<
next_method_type
Method
>
static
const
auto
fn
()
{
return
invoke
<
Method
>
;
}
};
/**
* Sepcialization for transcribing a simple type in the native method signature
* @tparam Ret - the return type of the native method
* @tparam Input - the type of the native parameter to transcribe
* @tparam Inputs - the remaining native parameters to transcribe
* @tparam Translated - the list of transcribed wasm parameters
*/
template
<
typename
Ret
,
typename
Input
,
typename
...
Inputs
,
typename
...
Translated
>
struct
intrinsic_invoker_impl
<
Ret
,
std
::
tuple
<
Input
,
Inputs
...
>
,
std
::
tuple
<
Translated
...
>>
{
using
translated_type
=
native_to_wasm_t
<
Input
>
;
using
next_step
=
intrinsic_invoker_impl
<
Ret
,
std
::
tuple
<
Inputs
...
>
,
std
::
tuple
<
Translated
...,
translated_type
>>
;
using
then_type
=
Ret
(
*
)(
wasm_interface
&
,
Input
,
Inputs
...,
Translated
...);
template
<
then_type
Then
>
static
Ret
translate_one
(
wasm_interface
&
wasm
,
Inputs
...
rest
,
Translated
...
translated
,
translated_type
last
)
{
auto
native
=
convert_wasm_to_native
<
Input
>
(
last
);
return
Then
(
wasm
,
native
,
rest
...,
translated
...);
};
template
<
then_type
Then
>
static
const
auto
fn
()
{
return
next_step
::
template
fn
<
translate_one
<
Then
>
>
();
}
};
/**
* Specialization for transcribing a array_ptr type in the native method signature
* This type transcribes into 2 wasm parameters: a pointer and byte length and checks the validity of that memory
* range before dispatching to the native method
*
* @tparam Ret - the return type of the native method
* @tparam Inputs - the remaining native parameters to transcribe
* @tparam Translated - the list of transcribed wasm parameters
*/
template
<
typename
T
,
typename
Ret
,
typename
...
Inputs
,
typename
...
Translated
>
struct
intrinsic_invoker_impl
<
Ret
,
std
::
tuple
<
array_ptr
<
T
>
,
size_t
,
Inputs
...
>
,
std
::
tuple
<
Translated
...
>>
{
using
next_step
=
intrinsic_invoker_impl
<
Ret
,
std
::
tuple
<
Inputs
...
>
,
std
::
tuple
<
Translated
...,
I32
,
I32
>>
;
using
then_type
=
Ret
(
*
)(
wasm_interface
&
,
array_ptr
<
T
>
,
size_t
,
Inputs
...,
Translated
...);
template
<
then_type
Then
>
static
Ret
translate_one
(
wasm_interface
&
wasm
,
Inputs
...
rest
,
Translated
...
translated
,
I32
ptr
,
I32
size
)
{
const
auto
length
=
size_t
(
size
);
return
Then
(
wasm
,
array_ptr
<
T
>
(
wasm
,
ptr
,
length
),
length
,
rest
...,
translated
...);
jit
::
entry
jit
;
uint32_t
default_sbrk_bytes
;
};
template
<
then_type
Then
>
static
const
auto
fn
()
{
return
next_step
::
template
fn
<
translate_one
<
Then
>
>
();
}
};
/**
* Specialization for transcribing a null_terminated_ptr type in the native method signature
* This type transcribes 1 wasm parameters: a char pointer which is validated to contain
* a null value before the end of the allocated memory.
*
* @tparam Ret - the return type of the native method
* @tparam Inputs - the remaining native parameters to transcribe
* @tparam Translated - the list of transcribed wasm parameters
*/
template
<
typename
Ret
,
typename
...
Inputs
,
typename
...
Translated
>
struct
intrinsic_invoker_impl
<
Ret
,
std
::
tuple
<
null_terminated_ptr
,
Inputs
...
>
,
std
::
tuple
<
Translated
...
>>
{
using
next_step
=
intrinsic_invoker_impl
<
Ret
,
std
::
tuple
<
Inputs
...
>
,
std
::
tuple
<
Translated
...,
I32
>>
;
using
then_type
=
Ret
(
*
)(
wasm_interface
&
,
null_terminated_ptr
,
Inputs
...,
Translated
...);
template
<
then_type
Then
>
static
Ret
translate_one
(
wasm_interface
&
wasm
,
Inputs
...
rest
,
Translated
...
translated
,
I32
ptr
)
{
return
Then
(
wasm
,
null_terminated_ptr
(
wasm
,
ptr
),
rest
...,
translated
...);
};
template
<
then_type
Then
>
static
const
auto
fn
()
{
return
next_step
::
template
fn
<
translate_one
<
Then
>
>
();
}
};
/**
* Specialization for transcribing a pair of array_ptr types in the native method signature that share size
* This type transcribes into 3 wasm parameters: 2 pointers and byte length and checks the validity of those memory
* ranges before dispatching to the native method
*
* @tparam Ret - the return type of the native method
* @tparam Inputs - the remaining native parameters to transcribe
* @tparam Translated - the list of transcribed wasm parameters
*/
template
<
typename
T
,
typename
U
,
typename
Ret
,
typename
...
Inputs
,
typename
...
Translated
>
struct
intrinsic_invoker_impl
<
Ret
,
std
::
tuple
<
array_ptr
<
T
>
,
array_ptr
<
U
>
,
size_t
,
Inputs
...
>
,
std
::
tuple
<
Translated
...
>>
{
using
next_step
=
intrinsic_invoker_impl
<
Ret
,
std
::
tuple
<
Inputs
...
>
,
std
::
tuple
<
Translated
...,
I32
,
I32
,
I32
>>
;
using
then_type
=
Ret
(
*
)(
wasm_interface
&
,
array_ptr
<
T
>
,
array_ptr
<
U
>
,
size_t
,
Inputs
...,
Translated
...);
template
<
then_type
Then
>
static
Ret
translate_one
(
wasm_interface
&
wasm
,
Inputs
...
rest
,
Translated
...
translated
,
I32
ptr_t
,
I32
ptr_u
,
I32
size
)
{
const
auto
length
=
size_t
(
size
);
return
Then
(
wasm
,
array_ptr
<
T
>
(
wasm
,
ptr_t
,
length
),
array_ptr
<
U
>
(
wasm
,
ptr_u
,
length
),
length
,
rest
...,
translated
...);
};
template
<
then_type
Then
>
static
const
auto
fn
()
{
return
next_step
::
template
fn
<
translate_one
<
Then
>
>
();
}
};
/**
* Specialization for transcribing memset parameters
*
* @tparam Ret - the return type of the native method
* @tparam Inputs - the remaining native parameters to transcribe
* @tparam Translated - the list of transcribed wasm parameters
*/
template
<
typename
Ret
>
struct
intrinsic_invoker_impl
<
Ret
,
std
::
tuple
<
array_ptr
<
char
>
,
int
,
size_t
>
,
std
::
tuple
<>>
{
using
next_step
=
intrinsic_invoker_impl
<
Ret
,
std
::
tuple
<>
,
std
::
tuple
<
I32
,
I32
,
I32
>>
;
using
then_type
=
Ret
(
*
)(
wasm_interface
&
,
array_ptr
<
char
>
,
int
,
size_t
);
template
<
then_type
Then
>
static
Ret
translate_one
(
wasm_interface
&
wasm
,
I32
ptr
,
I32
value
,
I32
size
)
{
const
auto
length
=
size_t
(
size
);
return
Then
(
wasm
,
array_ptr
<
char
>
(
wasm
,
ptr
,
length
),
value
,
length
);
};
template
<
then_type
Then
>
static
const
auto
fn
()
{
return
next_step
::
template
fn
<
translate_one
<
Then
>
>
();
}
};
/**
* Specialization for transcribing a pointer type in the native method signature
* This type transcribes into an int32 pointer checks the validity of that memory
* range before dispatching to the native method
*
* @tparam Ret - the return type of the native method
* @tparam Inputs - the remaining native parameters to transcribe
* @tparam Translated - the list of transcribed wasm parameters
*/
template
<
typename
T
,
typename
Ret
,
typename
...
Inputs
,
typename
...
Translated
>
struct
intrinsic_invoker_impl
<
Ret
,
std
::
tuple
<
T
*
,
Inputs
...
>
,
std
::
tuple
<
Translated
...
>>
{
using
next_step
=
intrinsic_invoker_impl
<
Ret
,
std
::
tuple
<
Inputs
...
>
,
std
::
tuple
<
Translated
...,
I32
>>
;
using
then_type
=
Ret
(
*
)(
wasm_interface
&
,
T
*
,
Inputs
...,
Translated
...);
struct
wasm_interface_impl
{
optional
<
common
::
wasm_context
>
current_context
;
template
<
then_type
Then
>
static
Ret
translate_one
(
wasm_interface
&
wasm
,
Inputs
...
rest
,
Translated
...
translated
,
I32
ptr
)
{
T
*
base
=
array_ptr
<
T
>::
validated_ptr
(
wasm
,
ptr
,
sizeof
(
T
));
return
Then
(
wasm
,
base
,
rest
...,
translated
...);
void
call
(
const
string
&
entry_point
,
const
vector
<
Value
>
&
args
,
wasm_cache
::
entry
&
code
,
apply_context
&
context
);
};
template
<
then_type
Then
>
static
const
auto
fn
()
{
return
next_step
::
template
fn
<
translate_one
<
Then
>
>
();
}
};
/**
* Specialization for transcribing a reference to a name which can be passed as a native value
* This type transcribes into a native type which is loaded by value into a
* variable on the stack and then passed by reference to the intrinsic.
*
* @tparam Ret - the return type of the native method
* @tparam Inputs - the remaining native parameters to transcribe
* @tparam Translated - the list of transcribed wasm parameters
*/
template
<
typename
Ret
,
typename
...
Inputs
,
typename
...
Translated
>
struct
intrinsic_invoker_impl
<
Ret
,
std
::
tuple
<
const
name
&
,
Inputs
...
>
,
std
::
tuple
<
Translated
...
>>
{
using
next_step
=
intrinsic_invoker_impl
<
Ret
,
std
::
tuple
<
Inputs
...
>
,
std
::
tuple
<
Translated
...,
native_to_wasm_t
<
const
name
&>
>>
;
using
then_type
=
Ret
(
*
)(
wasm_interface
&
,
const
name
&
,
Inputs
...,
Translated
...);
template
<
then_type
Then
>
static
Ret
translate_one
(
wasm_interface
&
wasm
,
Inputs
...
rest
,
Translated
...
translated
,
native_to_wasm_t
<
const
name
&>
wasm_value
)
{
auto
value
=
name
(
wasm_value
);
return
Then
(
wasm
,
value
,
rest
...,
translated
...);
}
template
<
then_type
Then
>
static
const
auto
fn
()
{
return
next_step
::
template
fn
<
translate_one
<
Then
>
>
();
}
};
/**
* Specialization for transcribing a reference to a fc::time_point_sec which can be passed as a native value
* This type transcribes into a native type which is loaded by value into a
* variable on the stack and then passed by reference to the intrinsic.
*
* @tparam Ret - the return type of the native method
* @tparam Inputs - the remaining native parameters to transcribe
* @tparam Translated - the list of transcribed wasm parameters
*/
template
<
typename
Ret
,
typename
...
Inputs
,
typename
...
Translated
>
struct
intrinsic_invoker_impl
<
Ret
,
std
::
tuple
<
const
fc
::
time_point_sec
&
,
Inputs
...
>
,
std
::
tuple
<
Translated
...
>>
{
using
next_step
=
intrinsic_invoker_impl
<
Ret
,
std
::
tuple
<
Inputs
...
>
,
std
::
tuple
<
Translated
...,
native_to_wasm_t
<
const
fc
::
time_point_sec
&>
>>
;
using
then_type
=
Ret
(
*
)(
wasm_interface
&
,
const
fc
::
time_point_sec
&
,
Inputs
...,
Translated
...);
template
<
then_type
Then
>
static
Ret
translate_one
(
wasm_interface
&
wasm
,
Inputs
...
rest
,
Translated
...
translated
,
native_to_wasm_t
<
const
fc
::
time_point_sec
&>
wasm_value
)
{
auto
value
=
fc
::
time_point_sec
(
wasm_value
);
return
Then
(
wasm
,
value
,
rest
...,
translated
...);
}
template
<
then_type
Then
>
static
const
auto
fn
()
{
return
next_step
::
template
fn
<
translate_one
<
Then
>
>
();
}
};
/**
* Specialization for transcribing a reference type in the native method signature
* This type transcribes into an int32 pointer checks the validity of that memory
* range before dispatching to the native method
*
* @tparam Ret - the return type of the native method
* @tparam Inputs - the remaining native parameters to transcribe
* @tparam Translated - the list of transcribed wasm parameters
*/
template
<
typename
T
,
typename
Ret
,
typename
...
Inputs
,
typename
...
Translated
>
struct
intrinsic_invoker_impl
<
Ret
,
std
::
tuple
<
T
&
,
Inputs
...
>
,
std
::
tuple
<
Translated
...
>>
{
using
next_step
=
intrinsic_invoker_impl
<
Ret
,
std
::
tuple
<
Inputs
...
>
,
std
::
tuple
<
Translated
...,
I32
>>
;
using
then_type
=
Ret
(
*
)(
wasm_interface
&
,
T
&
,
Inputs
...,
Translated
...);
template
<
then_type
Then
>
static
Ret
translate_one
(
wasm_interface
&
wasm
,
Inputs
...
rest
,
Translated
...
translated
,
I32
ptr
)
{
// references cannot be created for null pointers
FC_ASSERT
(
ptr
!=
0
);
auto
mem
=
getDefaultMemory
(
intrinsics_accessor
::
get_context
(
wasm
).
code
.
instance
);
if
(
!
mem
||
ptr
+
sizeof
(
T
)
>=
IR
::
numBytesPerPage
*
Runtime
::
getMemoryNumPages
(
mem
))
Runtime
::
causeException
(
Exception
::
Cause
::
accessViolation
);
T
&
base
=
*
(
T
*
)(
getMemoryBaseAddress
(
mem
)
+
ptr
);
return
Then
(
wasm
,
base
,
rest
...,
translated
...);
}
template
<
then_type
Then
>
static
const
auto
fn
()
{
return
next_step
::
template
fn
<
translate_one
<
Then
>
>
();
}
};
/**
* forward declaration of a wrapper class to call methods of the class
*/
template
<
typename
WasmSig
,
typename
Ret
,
typename
MethodSig
,
typename
Cls
,
typename
...
Params
>
struct
intrinsic_function_invoker
{
using
impl
=
intrinsic_invoker_impl
<
Ret
,
std
::
tuple
<
Params
...
>
,
std
::
tuple
<>>
;
template
<
MethodSig
Method
>
static
Ret
wrapper
(
wasm_interface
&
wasm
,
Params
...
params
)
{
return
(
class_from_wasm
<
Cls
>::
value
(
wasm
).
*
Method
)(
params
...);
}
template
<
MethodSig
Method
>
static
const
WasmSig
*
fn
()
{
auto
fn
=
impl
::
template
fn
<
wrapper
<
Method
>
>
();
static_assert
(
std
::
is_same
<
WasmSig
*
,
decltype
(
fn
)
>::
value
,
"Intrinsic function signature does not match the ABI"
);
return
fn
;
}
};
template
<
typename
WasmSig
,
typename
MethodSig
,
typename
Cls
,
typename
...
Params
>
struct
intrinsic_function_invoker
<
WasmSig
,
void
,
MethodSig
,
Cls
,
Params
...
>
{
using
impl
=
intrinsic_invoker_impl
<
void_type
,
std
::
tuple
<
Params
...
>
,
std
::
tuple
<>>
;
template
<
MethodSig
Method
>
static
void_type
wrapper
(
wasm_interface
&
wasm
,
Params
...
params
)
{
(
class_from_wasm
<
Cls
>::
value
(
wasm
).
*
Method
)(
params
...);
return
void_type
();
}
template
<
MethodSig
Method
>
static
const
WasmSig
*
fn
()
{
auto
fn
=
impl
::
template
fn
<
wrapper
<
Method
>
>
();
static_assert
(
std
::
is_same
<
WasmSig
*
,
decltype
(
fn
)
>::
value
,
"Intrinsic function signature does not match the ABI"
);
return
fn
;
}
};
template
<
typename
,
typename
>
struct
intrinsic_function_invoker_wrapper
;
template
<
typename
WasmSig
,
typename
Cls
,
typename
Ret
,
typename
...
Params
>
struct
intrinsic_function_invoker_wrapper
<
WasmSig
,
Ret
(
Cls
::*
)(
Params
...)
>
{
using
type
=
intrinsic_function_invoker
<
WasmSig
,
Ret
,
Ret
(
Cls
::*
)(
Params
...),
Cls
,
Params
...
>
;
};
template
<
typename
WasmSig
,
typename
Cls
,
typename
Ret
,
typename
...
Params
>
struct
intrinsic_function_invoker_wrapper
<
WasmSig
,
Ret
(
Cls
::*
)(
Params
...)
const
>
{
using
type
=
intrinsic_function_invoker
<
WasmSig
,
Ret
,
Ret
(
Cls
::*
)(
Params
...)
const
,
Cls
,
Params
...
>
;
};
template
<
typename
WasmSig
,
typename
Cls
,
typename
Ret
,
typename
...
Params
>
struct
intrinsic_function_invoker_wrapper
<
WasmSig
,
Ret
(
Cls
::*
)(
Params
...)
volatile
>
{
using
type
=
intrinsic_function_invoker
<
WasmSig
,
Ret
,
Ret
(
Cls
::*
)(
Params
...)
volatile
,
Cls
,
Params
...
>
;
};
template
<
typename
WasmSig
,
typename
Cls
,
typename
Ret
,
typename
...
Params
>
struct
intrinsic_function_invoker_wrapper
<
WasmSig
,
Ret
(
Cls
::*
)(
Params
...)
const
volatile
>
{
using
type
=
intrinsic_function_invoker
<
WasmSig
,
Ret
,
Ret
(
Cls
::*
)(
Params
...)
const
volatile
,
Cls
,
Params
...
>
;
};
#define _ADD_PAREN_1(...) ((__VA_ARGS__)) _ADD_PAREN_2
#define _ADD_PAREN_2(...) ((__VA_ARGS__)) _ADD_PAREN_1
#define _ADD_PAREN_1_END
#define _ADD_PAREN_2_END
#define _WRAPPED_SEQ(SEQ) BOOST_PP_CAT(_ADD_PAREN_1 SEQ, _END)
#define __INTRINSIC_NAME(LABEL, SUFFIX) LABEL##SUFFIX
#define _INTRINSIC_NAME(LABEL, SUFFIX) __INTRINSIC_NAME(LABEL,SUFFIX)
#define _REGISTER_INTRINSIC_EXPLICIT(CLS, METHOD, WASM_SIG, NAME, SIG)\
static Intrinsics::Function _INTRINSIC_NAME(__intrinsic_fn, __COUNTER__) (\
"env." NAME,\
eosio::chain::wasm_function_type_provider<WASM_SIG>::type(),\
(void *)eosio::chain::intrinsic_function_invoker_wrapper<WASM_SIG, SIG>::type::fn<&CLS::METHOD>()\
);\
_REGISTER_JIT_INTRINSIC(CLS, METHOD, WASM_SIG, NAME, SIG)
#define _REGISTER_INTRINSIC4(CLS, METHOD, WASM_SIG, NAME, SIG)\
_REGISTER_INTRINSIC_EXPLICIT(CLS, METHOD, WASM_SIG, NAME, SIG )
...
...
libraries/chain/include/eosio/chain/webassembly/common.hpp
0 → 100644
浏览文件 @
7ea3f14c
#pragma once
#include <eosio/chain/wasm_interface.hpp>
#include <boost/multiprecision/cpp_dec_float.hpp>
using
namespace
fc
;
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
,
uint32_t
sbrk_bytes
)
:
code
(
code
),
context
(
ctx
)
{
}
eosio
::
chain
::
wasm_cache
::
entry
&
code
;
apply_context
&
context
;
uint32_t
sbrk_bytes
;
};
class
intrinsics_accessor
{
public:
static
wasm_context
&
get_context
(
wasm_interface
&
wasm
);
};
template
<
typename
T
>
struct
class_from_wasm
{
/**
* by default this is just constructing an object
* @param wasm - the wasm_interface to use
* @return
*/
static
auto
value
(
wasm_interface
&
wasm
)
{
return
T
(
wasm
);
}
};
template
<
>
struct
class_from_wasm
<
apply_context
>
{
/**
* Don't construct a new apply_context, just return a reference to the existing ont
* @param wasm
* @return
*/
static
auto
&
value
(
wasm_interface
&
wasm
)
{
return
intrinsics_accessor
::
get_context
(
wasm
).
context
;
}
};
/**
* class to represent an in-wasm-memory array
* it is a hint to the transcriber that the next parameter will
* be a size (data bytes length) and that the pair are validated together
* This triggers the template specialization of intrinsic_invoker_impl
* @tparam T
*/
template
<
typename
T
>
struct
array_ptr
{
explicit
array_ptr
(
T
*
value
)
:
value
(
value
)
{}
typename
std
::
add_lvalue_reference
<
T
>::
type
operator
*
()
const
{
return
*
value
;
}
T
*
operator
->
()
const
noexcept
{
return
value
;
}
template
<
typename
U
>
operator
U
*
()
const
{
return
static_cast
<
U
*>
(
value
);
}
T
*
value
;
};
/**
* class to represent an in-wasm-memory char array that must be null terminated
*/
struct
null_terminated_ptr
{
explicit
null_terminated_ptr
(
char
*
value
)
:
value
(
value
)
{}
typename
std
::
add_lvalue_reference
<
char
>::
type
operator
*
()
const
{
return
*
value
;
}
char
*
operator
->
()
const
noexcept
{
return
value
;
}
template
<
typename
U
>
operator
U
*
()
const
{
return
static_cast
<
U
*>
(
value
);
}
char
*
value
;
};
}
}
}
}
// eosio::chain
libraries/chain/include/eosio/chain/webassembly/jit.hpp
0 → 100644
浏览文件 @
7ea3f14c
#pragma once
#include <eosio/chain/webassembly/common.hpp>
#include "Runtime/Runtime.h"
#include "IR/Types.h"
using
namespace
IR
;
using
namespace
Runtime
;
using
namespace
fc
;
using
namespace
eosio
::
chain
::
webassembly
::
common
;
namespace
eosio
{
namespace
chain
{
namespace
webassembly
{
namespace
jit
{
struct
entry
{
entry
(
ModuleInstance
*
instance
,
Module
*
module
)
:
instance
(
instance
),
module
(
module
)
{
}
ModuleInstance
*
instance
;
Module
*
module
;
static
const
entry
&
get
(
wasm_interface
&
wasm
);
};
/**
* class to represent an in-wasm-memory array
* it is a hint to the transcriber that the next parameter will
* be a size (data bytes length) and that the pair are validated together
* This triggers the template specialization of intrinsic_invoker_impl
* @tparam T
*/
template
<
typename
T
>
array_ptr
<
T
>
array_ptr_impl
(
wasm_interface
&
wasm
,
U32
ptr
,
size_t
length
)
{
auto
mem
=
getDefaultMemory
(
entry
::
get
(
wasm
).
instance
);
if
(
!
mem
||
ptr
+
length
>
IR
::
numBytesPerPage
*
Runtime
::
getMemoryNumPages
(
mem
))
Runtime
::
causeException
(
Exception
::
Cause
::
accessViolation
);
return
array_ptr
<
T
>
((
T
*
)(
getMemoryBaseAddress
(
mem
)
+
ptr
));
}
/**
* class to represent an in-wasm-memory char array that must be null terminated
*/
null_terminated_ptr
null_terminated_ptr_impl
(
wasm_interface
&
wasm
,
U32
ptr
)
{
auto
mem
=
getDefaultMemory
(
entry
::
get
(
wasm
).
instance
);
if
(
!
mem
)
Runtime
::
causeException
(
Exception
::
Cause
::
accessViolation
);
char
*
value
=
(
char
*
)(
getMemoryBaseAddress
(
mem
)
+
ptr
);
const
char
*
p
=
value
;
const
char
*
const
top_of_memory
=
(
char
*
)(
getMemoryBaseAddress
(
mem
)
+
IR
::
numBytesPerPage
*
Runtime
::
getMemoryNumPages
(
mem
));
while
(
p
<
top_of_memory
)
if
(
*
p
++
==
'\0'
)
return
null_terminated_ptr
(
value
);
Runtime
::
causeException
(
Exception
::
Cause
::
accessViolation
);
}
/**
* template that maps native types to WASM VM types
* @tparam T the native type
*/
template
<
typename
T
>
struct
native_to_wasm
{
using
type
=
void
;
};
/**
* specialization for mapping pointers to int32's
*/
template
<
typename
T
>
struct
native_to_wasm
<
T
*>
{
using
type
=
I32
;
};
/**
* Mappings for native types
*/
template
<
>
struct
native_to_wasm
<
int32_t
>
{
using
type
=
I32
;
};
template
<
>
struct
native_to_wasm
<
uint32_t
>
{
using
type
=
I32
;
};
template
<
>
struct
native_to_wasm
<
int64_t
>
{
using
type
=
I64
;
};
template
<
>
struct
native_to_wasm
<
uint64_t
>
{
using
type
=
I64
;
};
template
<
>
struct
native_to_wasm
<
bool
>
{
using
type
=
I32
;
};
template
<
>
struct
native_to_wasm
<
const
name
&>
{
using
type
=
I64
;
};
template
<
>
struct
native_to_wasm
<
name
>
{
using
type
=
I64
;
};
template
<
>
struct
native_to_wasm
<
wasm_double
>
{
using
type
=
I64
;
};
template
<
>
struct
native_to_wasm
<
const
fc
::
time_point_sec
&>
{
using
type
=
I32
;
};
template
<
>
struct
native_to_wasm
<
fc
::
time_point_sec
>
{
using
type
=
I32
;
};
// convenience alias
template
<
typename
T
>
using
native_to_wasm_t
=
typename
native_to_wasm
<
T
>::
type
;
template
<
typename
T
>
auto
convert_native_to_wasm
(
const
wasm_interface
&
wasm
,
T
val
)
{
return
native_to_wasm_t
<
T
>
(
val
);
}
auto
convert_native_to_wasm
(
const
wasm_interface
&
wasm
,
const
name
&
val
)
{
return
native_to_wasm_t
<
const
name
&>
(
val
.
value
);
}
auto
convert_native_to_wasm
(
const
wasm_interface
&
wasm
,
const
fc
::
time_point_sec
&
val
)
{
return
native_to_wasm_t
<
const
fc
::
time_point_sec
&>
(
val
.
sec_since_epoch
());
}
auto
convert_native_to_wasm
(
wasm_interface
&
wasm
,
char
*
ptr
)
{
auto
mem
=
getDefaultMemory
(
entry
::
get
(
wasm
).
instance
);
if
(
!
mem
)
Runtime
::
causeException
(
Exception
::
Cause
::
accessViolation
);
char
*
base
=
(
char
*
)
getMemoryBaseAddress
(
mem
);
char
*
top_of_memory
=
base
+
IR
::
numBytesPerPage
*
Runtime
::
getMemoryNumPages
(
mem
);
if
(
ptr
<
base
||
ptr
>=
top_of_memory
)
Runtime
::
causeException
(
Exception
::
Cause
::
accessViolation
);
return
(
int
)(
ptr
-
base
);
}
template
<
typename
T
>
auto
convert_wasm_to_native
(
native_to_wasm_t
<
T
>
val
)
{
return
T
(
val
);
}
template
<
>
auto
convert_wasm_to_native
<
wasm_double
>
(
I64
val
)
{
return
wasm_double
(
*
reinterpret_cast
<
wasm_double
*>
(
&
val
));
}
template
<
typename
T
>
struct
wasm_to_value_type
;
template
<
>
struct
wasm_to_value_type
<
I32
>
{
static
constexpr
auto
value
=
ValueType
::
i32
;
};
template
<
>
struct
wasm_to_value_type
<
I64
>
{
static
constexpr
auto
value
=
ValueType
::
i64
;
};
template
<
typename
T
>
constexpr
auto
wasm_to_value_type_v
=
wasm_to_value_type
<
T
>::
value
;
template
<
typename
T
>
struct
wasm_to_rvalue_type
;
template
<
>
struct
wasm_to_rvalue_type
<
I32
>
{
static
constexpr
auto
value
=
ResultType
::
i32
;
};
template
<
>
struct
wasm_to_rvalue_type
<
I64
>
{
static
constexpr
auto
value
=
ResultType
::
i64
;
};
template
<
>
struct
wasm_to_rvalue_type
<
void
>
{
static
constexpr
auto
value
=
ResultType
::
none
;
};
template
<
>
struct
wasm_to_rvalue_type
<
const
name
&>
{
static
constexpr
auto
value
=
ResultType
::
i64
;
};
template
<
>
struct
wasm_to_rvalue_type
<
name
>
{
static
constexpr
auto
value
=
ResultType
::
i64
;
};
template
<
>
struct
wasm_to_rvalue_type
<
char
*>
{
static
constexpr
auto
value
=
ResultType
::
i32
;
};
template
<
>
struct
wasm_to_rvalue_type
<
fc
::
time_point_sec
>
{
static
constexpr
auto
value
=
ResultType
::
i32
;
};
template
<
typename
T
>
constexpr
auto
wasm_to_rvalue_type_v
=
wasm_to_rvalue_type
<
T
>::
value
;
template
<
typename
T
>
struct
is_reference_from_value
{
static
constexpr
bool
value
=
false
;
};
template
<
>
struct
is_reference_from_value
<
name
>
{
static
constexpr
bool
value
=
true
;
};
template
<
>
struct
is_reference_from_value
<
fc
::
time_point_sec
>
{
static
constexpr
bool
value
=
true
;
};
template
<
typename
T
>
constexpr
bool
is_reference_from_value_v
=
is_reference_from_value
<
T
>::
value
;
struct
void_type
{
};
/**
* Forward declaration of provider for FunctionType given a desired C ABI signature
*/
template
<
typename
>
struct
wasm_function_type_provider
;
/**
* specialization to destructure return and arguments
*/
template
<
typename
Ret
,
typename
...
Args
>
struct
wasm_function_type_provider
<
Ret
(
Args
...)
>
{
static
const
FunctionType
*
type
()
{
return
FunctionType
::
get
(
wasm_to_rvalue_type_v
<
Ret
>
,
{
wasm_to_value_type_v
<
Args
>
...});
}
};
/**
* Forward declaration of the invoker type which transcribes arguments to/from a native method
* and injects the appropriate checks
*
* @tparam Ret - the return type of the native function
* @tparam NativeParameters - a std::tuple of the remaining native parameters to transcribe
* @tparam WasmParameters - a std::tuple of the transribed parameters
*/
template
<
typename
Ret
,
typename
NativeParameters
,
typename
WasmParameters
>
struct
intrinsic_invoker_impl
;
/**
* Specialization for the fully transcribed signature
* @tparam Ret - the return type of the native function
* @tparam Translated - the arguments to the wasm function
*/
template
<
typename
Ret
,
typename
...
Translated
>
struct
intrinsic_invoker_impl
<
Ret
,
std
::
tuple
<>
,
std
::
tuple
<
Translated
...
>>
{
using
next_method_type
=
Ret
(
*
)(
wasm_interface
&
,
Translated
...);
template
<
next_method_type
Method
>
static
native_to_wasm_t
<
Ret
>
invoke
(
Translated
...
translated
)
{
wasm_interface
&
wasm
=
wasm_interface
::
get
();
return
convert_native_to_wasm
(
wasm
,
Method
(
wasm
,
translated
...));
}
template
<
next_method_type
Method
>
static
const
auto
fn
()
{
return
invoke
<
Method
>
;
}
};
/**
* specialization of the fully transcribed signature for void return values
* @tparam Translated - the arguments to the wasm function
*/
template
<
typename
...
Translated
>
struct
intrinsic_invoker_impl
<
void_type
,
std
::
tuple
<>
,
std
::
tuple
<
Translated
...
>>
{
using
next_method_type
=
void_type
(
*
)(
wasm_interface
&
,
Translated
...);
template
<
next_method_type
Method
>
static
void
invoke
(
Translated
...
translated
)
{
wasm_interface
&
wasm
=
wasm_interface
::
get
();
Method
(
wasm
,
translated
...);
}
template
<
next_method_type
Method
>
static
const
auto
fn
()
{
return
invoke
<
Method
>
;
}
};
/**
* Sepcialization for transcribing a simple type in the native method signature
* @tparam Ret - the return type of the native method
* @tparam Input - the type of the native parameter to transcribe
* @tparam Inputs - the remaining native parameters to transcribe
* @tparam Translated - the list of transcribed wasm parameters
*/
template
<
typename
Ret
,
typename
Input
,
typename
...
Inputs
,
typename
...
Translated
>
struct
intrinsic_invoker_impl
<
Ret
,
std
::
tuple
<
Input
,
Inputs
...
>
,
std
::
tuple
<
Translated
...
>>
{
using
translated_type
=
native_to_wasm_t
<
Input
>
;
using
next_step
=
intrinsic_invoker_impl
<
Ret
,
std
::
tuple
<
Inputs
...
>
,
std
::
tuple
<
Translated
...,
translated_type
>>
;
using
then_type
=
Ret
(
*
)(
wasm_interface
&
,
Input
,
Inputs
...,
Translated
...);
template
<
then_type
Then
>
static
Ret
translate_one
(
wasm_interface
&
wasm
,
Inputs
...
rest
,
Translated
...
translated
,
translated_type
last
)
{
auto
native
=
convert_wasm_to_native
<
Input
>
(
last
);
return
Then
(
wasm
,
native
,
rest
...,
translated
...);
};
template
<
then_type
Then
>
static
const
auto
fn
()
{
return
next_step
::
template
fn
<
translate_one
<
Then
>
>
();
}
};
/**
* Specialization for transcribing a array_ptr type in the native method signature
* This type transcribes into 2 wasm parameters: a pointer and byte length and checks the validity of that memory
* range before dispatching to the native method
*
* @tparam Ret - the return type of the native method
* @tparam Inputs - the remaining native parameters to transcribe
* @tparam Translated - the list of transcribed wasm parameters
*/
template
<
typename
T
,
typename
Ret
,
typename
...
Inputs
,
typename
...
Translated
>
struct
intrinsic_invoker_impl
<
Ret
,
std
::
tuple
<
array_ptr
<
T
>
,
size_t
,
Inputs
...
>
,
std
::
tuple
<
Translated
...
>>
{
using
next_step
=
intrinsic_invoker_impl
<
Ret
,
std
::
tuple
<
Inputs
...
>
,
std
::
tuple
<
Translated
...,
I32
,
I32
>>
;
using
then_type
=
Ret
(
*
)(
wasm_interface
&
,
array_ptr
<
T
>
,
size_t
,
Inputs
...,
Translated
...);
template
<
then_type
Then
>
static
Ret
translate_one
(
wasm_interface
&
wasm
,
Inputs
...
rest
,
Translated
...
translated
,
I32
ptr
,
I32
size
)
{
const
auto
length
=
size_t
(
size
);
return
Then
(
wasm
,
array_ptr_impl
<
T
>
(
wasm
,
ptr
,
length
),
length
,
rest
...,
translated
...);
};
template
<
then_type
Then
>
static
const
auto
fn
()
{
return
next_step
::
template
fn
<
translate_one
<
Then
>
>
();
}
};
/**
* Specialization for transcribing a null_terminated_ptr type in the native method signature
* This type transcribes 1 wasm parameters: a char pointer which is validated to contain
* a null value before the end of the allocated memory.
*
* @tparam Ret - the return type of the native method
* @tparam Inputs - the remaining native parameters to transcribe
* @tparam Translated - the list of transcribed wasm parameters
*/
template
<
typename
Ret
,
typename
...
Inputs
,
typename
...
Translated
>
struct
intrinsic_invoker_impl
<
Ret
,
std
::
tuple
<
null_terminated_ptr
,
Inputs
...
>
,
std
::
tuple
<
Translated
...
>>
{
using
next_step
=
intrinsic_invoker_impl
<
Ret
,
std
::
tuple
<
Inputs
...
>
,
std
::
tuple
<
Translated
...,
I32
>>
;
using
then_type
=
Ret
(
*
)(
wasm_interface
&
,
null_terminated_ptr
,
Inputs
...,
Translated
...);
template
<
then_type
Then
>
static
Ret
translate_one
(
wasm_interface
&
wasm
,
Inputs
...
rest
,
Translated
...
translated
,
I32
ptr
)
{
return
Then
(
wasm
,
null_terminated_ptr_impl
(
wasm
,
ptr
),
rest
...,
translated
...);
};
template
<
then_type
Then
>
static
const
auto
fn
()
{
return
next_step
::
template
fn
<
translate_one
<
Then
>
>
();
}
};
/**
* Specialization for transcribing a pair of array_ptr types in the native method signature that share size
* This type transcribes into 3 wasm parameters: 2 pointers and byte length and checks the validity of those memory
* ranges before dispatching to the native method
*
* @tparam Ret - the return type of the native method
* @tparam Inputs - the remaining native parameters to transcribe
* @tparam Translated - the list of transcribed wasm parameters
*/
template
<
typename
T
,
typename
U
,
typename
Ret
,
typename
...
Inputs
,
typename
...
Translated
>
struct
intrinsic_invoker_impl
<
Ret
,
std
::
tuple
<
array_ptr
<
T
>
,
array_ptr
<
U
>
,
size_t
,
Inputs
...
>
,
std
::
tuple
<
Translated
...
>>
{
using
next_step
=
intrinsic_invoker_impl
<
Ret
,
std
::
tuple
<
Inputs
...
>
,
std
::
tuple
<
Translated
...,
I32
,
I32
,
I32
>>
;
using
then_type
=
Ret
(
*
)(
wasm_interface
&
,
array_ptr
<
T
>
,
array_ptr
<
U
>
,
size_t
,
Inputs
...,
Translated
...);
template
<
then_type
Then
>
static
Ret
translate_one
(
wasm_interface
&
wasm
,
Inputs
...
rest
,
Translated
...
translated
,
I32
ptr_t
,
I32
ptr_u
,
I32
size
)
{
const
auto
length
=
size_t
(
size
);
return
Then
(
wasm
,
array_ptr_impl
<
T
>
(
wasm
,
ptr_t
,
length
),
array_ptr_impl
<
U
>
(
wasm
,
ptr_u
,
length
),
length
,
rest
...,
translated
...);
};
template
<
then_type
Then
>
static
const
auto
fn
()
{
return
next_step
::
template
fn
<
translate_one
<
Then
>
>
();
}
};
/**
* Specialization for transcribing memset parameters
*
* @tparam Ret - the return type of the native method
* @tparam Inputs - the remaining native parameters to transcribe
* @tparam Translated - the list of transcribed wasm parameters
*/
template
<
typename
Ret
>
struct
intrinsic_invoker_impl
<
Ret
,
std
::
tuple
<
array_ptr
<
char
>
,
int
,
size_t
>
,
std
::
tuple
<>>
{
using
next_step
=
intrinsic_invoker_impl
<
Ret
,
std
::
tuple
<>
,
std
::
tuple
<
I32
,
I32
,
I32
>>
;
using
then_type
=
Ret
(
*
)(
wasm_interface
&
,
array_ptr
<
char
>
,
int
,
size_t
);
template
<
then_type
Then
>
static
Ret
translate_one
(
wasm_interface
&
wasm
,
I32
ptr
,
I32
value
,
I32
size
)
{
const
auto
length
=
size_t
(
size
);
return
Then
(
wasm
,
array_ptr_impl
<
char
>
(
wasm
,
ptr
,
length
),
value
,
length
);
};
template
<
then_type
Then
>
static
const
auto
fn
()
{
return
next_step
::
template
fn
<
translate_one
<
Then
>
>
();
}
};
/**
* Specialization for transcribing a pointer type in the native method signature
* This type transcribes into an int32 pointer checks the validity of that memory
* range before dispatching to the native method
*
* @tparam Ret - the return type of the native method
* @tparam Inputs - the remaining native parameters to transcribe
* @tparam Translated - the list of transcribed wasm parameters
*/
template
<
typename
T
,
typename
Ret
,
typename
...
Inputs
,
typename
...
Translated
>
struct
intrinsic_invoker_impl
<
Ret
,
std
::
tuple
<
T
*
,
Inputs
...
>
,
std
::
tuple
<
Translated
...
>>
{
using
next_step
=
intrinsic_invoker_impl
<
Ret
,
std
::
tuple
<
Inputs
...
>
,
std
::
tuple
<
Translated
...,
I32
>>
;
using
then_type
=
Ret
(
*
)(
wasm_interface
&
,
T
*
,
Inputs
...,
Translated
...);
template
<
then_type
Then
>
static
Ret
translate_one
(
wasm_interface
&
wasm
,
Inputs
...
rest
,
Translated
...
translated
,
I32
ptr
)
{
T
*
base
=
array_ptr_impl
<
T
>
(
wasm
,
ptr
,
sizeof
(
T
));
return
Then
(
wasm
,
base
,
rest
...,
translated
...);
};
template
<
then_type
Then
>
static
const
auto
fn
()
{
return
next_step
::
template
fn
<
translate_one
<
Then
>
>
();
}
};
/**
* Specialization for transcribing a reference to a name which can be passed as a native value
* This type transcribes into a native type which is loaded by value into a
* variable on the stack and then passed by reference to the intrinsic.
*
* @tparam Ret - the return type of the native method
* @tparam Inputs - the remaining native parameters to transcribe
* @tparam Translated - the list of transcribed wasm parameters
*/
template
<
typename
Ret
,
typename
...
Inputs
,
typename
...
Translated
>
struct
intrinsic_invoker_impl
<
Ret
,
std
::
tuple
<
const
name
&
,
Inputs
...
>
,
std
::
tuple
<
Translated
...
>>
{
using
next_step
=
intrinsic_invoker_impl
<
Ret
,
std
::
tuple
<
Inputs
...
>
,
std
::
tuple
<
Translated
...,
native_to_wasm_t
<
const
name
&>
>>
;
using
then_type
=
Ret
(
*
)(
wasm_interface
&
,
const
name
&
,
Inputs
...,
Translated
...);
template
<
then_type
Then
>
static
Ret
translate_one
(
wasm_interface
&
wasm
,
Inputs
...
rest
,
Translated
...
translated
,
native_to_wasm_t
<
const
name
&>
wasm_value
)
{
auto
value
=
name
(
wasm_value
);
return
Then
(
wasm
,
value
,
rest
...,
translated
...);
}
template
<
then_type
Then
>
static
const
auto
fn
()
{
return
next_step
::
template
fn
<
translate_one
<
Then
>
>
();
}
};
/**
* Specialization for transcribing a reference to a fc::time_point_sec which can be passed as a native value
* This type transcribes into a native type which is loaded by value into a
* variable on the stack and then passed by reference to the intrinsic.
*
* @tparam Ret - the return type of the native method
* @tparam Inputs - the remaining native parameters to transcribe
* @tparam Translated - the list of transcribed wasm parameters
*/
template
<
typename
Ret
,
typename
...
Inputs
,
typename
...
Translated
>
struct
intrinsic_invoker_impl
<
Ret
,
std
::
tuple
<
const
fc
::
time_point_sec
&
,
Inputs
...
>
,
std
::
tuple
<
Translated
...
>>
{
using
next_step
=
intrinsic_invoker_impl
<
Ret
,
std
::
tuple
<
Inputs
...
>
,
std
::
tuple
<
Translated
...,
native_to_wasm_t
<
const
fc
::
time_point_sec
&>
>>
;
using
then_type
=
Ret
(
*
)(
wasm_interface
&
,
const
fc
::
time_point_sec
&
,
Inputs
...,
Translated
...);
template
<
then_type
Then
>
static
Ret
translate_one
(
wasm_interface
&
wasm
,
Inputs
...
rest
,
Translated
...
translated
,
native_to_wasm_t
<
const
fc
::
time_point_sec
&>
wasm_value
)
{
auto
value
=
fc
::
time_point_sec
(
wasm_value
);
return
Then
(
wasm
,
value
,
rest
...,
translated
...);
}
template
<
then_type
Then
>
static
const
auto
fn
()
{
return
next_step
::
template
fn
<
translate_one
<
Then
>
>
();
}
};
/**
* Specialization for transcribing a reference type in the native method signature
* This type transcribes into an int32 pointer checks the validity of that memory
* range before dispatching to the native method
*
* @tparam Ret - the return type of the native method
* @tparam Inputs - the remaining native parameters to transcribe
* @tparam Translated - the list of transcribed wasm parameters
*/
template
<
typename
T
,
typename
Ret
,
typename
...
Inputs
,
typename
...
Translated
>
struct
intrinsic_invoker_impl
<
Ret
,
std
::
tuple
<
T
&
,
Inputs
...
>
,
std
::
tuple
<
Translated
...
>>
{
using
next_step
=
intrinsic_invoker_impl
<
Ret
,
std
::
tuple
<
Inputs
...
>
,
std
::
tuple
<
Translated
...,
I32
>>
;
using
then_type
=
Ret
(
*
)(
wasm_interface
&
,
T
&
,
Inputs
...,
Translated
...);
template
<
then_type
Then
>
static
Ret
translate_one
(
wasm_interface
&
wasm
,
Inputs
...
rest
,
Translated
...
translated
,
I32
ptr
)
{
// references cannot be created for null pointers
FC_ASSERT
(
ptr
!=
0
);
auto
mem
=
getDefaultMemory
(
entry
::
get
(
wasm
).
instance
);
if
(
!
mem
||
ptr
+
sizeof
(
T
)
>=
IR
::
numBytesPerPage
*
Runtime
::
getMemoryNumPages
(
mem
))
Runtime
::
causeException
(
Exception
::
Cause
::
accessViolation
);
T
&
base
=
*
(
T
*
)(
getMemoryBaseAddress
(
mem
)
+
ptr
);
return
Then
(
wasm
,
base
,
rest
...,
translated
...);
}
template
<
then_type
Then
>
static
const
auto
fn
()
{
return
next_step
::
template
fn
<
translate_one
<
Then
>
>
();
}
};
/**
* forward declaration of a wrapper class to call methods of the class
*/
template
<
typename
WasmSig
,
typename
Ret
,
typename
MethodSig
,
typename
Cls
,
typename
...
Params
>
struct
intrinsic_function_invoker
{
using
impl
=
intrinsic_invoker_impl
<
Ret
,
std
::
tuple
<
Params
...
>
,
std
::
tuple
<>>
;
template
<
MethodSig
Method
>
static
Ret
wrapper
(
wasm_interface
&
wasm
,
Params
...
params
)
{
return
(
class_from_wasm
<
Cls
>::
value
(
wasm
).
*
Method
)(
params
...);
}
template
<
MethodSig
Method
>
static
const
WasmSig
*
fn
()
{
auto
fn
=
impl
::
template
fn
<
wrapper
<
Method
>
>
();
static_assert
(
std
::
is_same
<
WasmSig
*
,
decltype
(
fn
)
>::
value
,
"Intrinsic function signature does not match the ABI"
);
return
fn
;
}
};
template
<
typename
WasmSig
,
typename
MethodSig
,
typename
Cls
,
typename
...
Params
>
struct
intrinsic_function_invoker
<
WasmSig
,
void
,
MethodSig
,
Cls
,
Params
...
>
{
using
impl
=
intrinsic_invoker_impl
<
void_type
,
std
::
tuple
<
Params
...
>
,
std
::
tuple
<>>
;
template
<
MethodSig
Method
>
static
void_type
wrapper
(
wasm_interface
&
wasm
,
Params
...
params
)
{
(
class_from_wasm
<
Cls
>::
value
(
wasm
).
*
Method
)(
params
...);
return
void_type
();
}
template
<
MethodSig
Method
>
static
const
WasmSig
*
fn
()
{
auto
fn
=
impl
::
template
fn
<
wrapper
<
Method
>
>
();
static_assert
(
std
::
is_same
<
WasmSig
*
,
decltype
(
fn
)
>::
value
,
"Intrinsic function signature does not match the ABI"
);
return
fn
;
}
};
template
<
typename
,
typename
>
struct
intrinsic_function_invoker_wrapper
;
template
<
typename
WasmSig
,
typename
Cls
,
typename
Ret
,
typename
...
Params
>
struct
intrinsic_function_invoker_wrapper
<
WasmSig
,
Ret
(
Cls
::*
)(
Params
...)
>
{
using
type
=
intrinsic_function_invoker
<
WasmSig
,
Ret
,
Ret
(
Cls
::*
)(
Params
...),
Cls
,
Params
...
>
;
};
template
<
typename
WasmSig
,
typename
Cls
,
typename
Ret
,
typename
...
Params
>
struct
intrinsic_function_invoker_wrapper
<
WasmSig
,
Ret
(
Cls
::*
)(
Params
...)
const
>
{
using
type
=
intrinsic_function_invoker
<
WasmSig
,
Ret
,
Ret
(
Cls
::*
)(
Params
...)
const
,
Cls
,
Params
...
>
;
};
template
<
typename
WasmSig
,
typename
Cls
,
typename
Ret
,
typename
...
Params
>
struct
intrinsic_function_invoker_wrapper
<
WasmSig
,
Ret
(
Cls
::*
)(
Params
...)
volatile
>
{
using
type
=
intrinsic_function_invoker
<
WasmSig
,
Ret
,
Ret
(
Cls
::*
)(
Params
...)
volatile
,
Cls
,
Params
...
>
;
};
template
<
typename
WasmSig
,
typename
Cls
,
typename
Ret
,
typename
...
Params
>
struct
intrinsic_function_invoker_wrapper
<
WasmSig
,
Ret
(
Cls
::*
)(
Params
...)
const
volatile
>
{
using
type
=
intrinsic_function_invoker
<
WasmSig
,
Ret
,
Ret
(
Cls
::*
)(
Params
...)
const
volatile
,
Cls
,
Params
...
>
;
};
#define _ADD_PAREN_1(...) ((__VA_ARGS__)) _ADD_PAREN_2
#define _ADD_PAREN_2(...) ((__VA_ARGS__)) _ADD_PAREN_1
#define _ADD_PAREN_1_END
#define _ADD_PAREN_2_END
#define _WRAPPED_SEQ(SEQ) BOOST_PP_CAT(_ADD_PAREN_1 SEQ, _END)
#define __INTRINSIC_NAME(LABEL, SUFFIX) LABEL##SUFFIX
#define _INTRINSIC_NAME(LABEL, SUFFIX) __INTRINSIC_NAME(LABEL,SUFFIX)
#define _REGISTER_JIT_INTRINSIC(CLS, METHOD, WASM_SIG, NAME, SIG)\
static Intrinsics::Function _INTRINSIC_NAME(__intrinsic_fn, __COUNTER__) (\
"env." NAME,\
eosio::chain::webassembly::jit::wasm_function_type_provider<WASM_SIG>::type(),\
(void *)eosio::chain::webassembly::jit::intrinsic_function_invoker_wrapper<WASM_SIG, SIG>::type::fn<&CLS::METHOD>()\
);\
}
}
}
}
// eosio::chain::webassembly::jit
libraries/chain/wasm_interface.cpp
浏览文件 @
7ea3f14c
...
...
@@ -69,6 +69,8 @@ using boost::asio::io_service;
namespace
eosio
{
namespace
chain
{
using
namespace
contracts
;
using
namespace
webassembly
;
using
namespace
webassembly
::
common
;
/**
* Integration with the WASM Linker to resolve our intrinsics
...
...
@@ -251,7 +253,10 @@ namespace eosio { namespace chain {
// find or create a new entry
auto
iter
=
_cache
.
emplace
(
code_id
,
code_info
(
mem_end
,
std
::
move
(
mem_image
))).
first
;
iter
->
second
.
instances
.
emplace_back
(
std
::
make_unique
<
wasm_cache
::
entry
>
(
instance
,
module
));
MemoryInstance
*
default_mem
=
Runtime
::
getDefaultMemory
(
instance
);
uint32_t
default_sbrk_bytes
=
default_mem
?
Runtime
::
getMemoryNumPages
(
default_mem
)
<<
IR
::
numBytesPerPageLog2
:
0
;
iter
->
second
.
instances
.
emplace_back
(
std
::
make_unique
<
wasm_cache
::
entry
>
(
jit
::
entry
{
instance
,
module
},
default_sbrk_bytes
));
pending_result
=
optional_entry_ref
(
*
iter
->
second
.
instances
.
back
().
get
());
});
}
...
...
@@ -286,12 +291,12 @@ namespace eosio { namespace chain {
void
return_entry
(
const
digest_type
&
code_id
,
wasm_cache
::
entry
&
entry
)
{
// sanitize by reseting the memory that may now be dirty
auto
&
info
=
(
*
fetch_info
(
code_id
)).
get
();
if
(
getDefaultMemory
(
entry
.
instance
))
{
char
*
memstart
=
&
memoryRef
<
char
>
(
getDefaultMemory
(
entry
.
instance
),
0
);
if
(
getDefaultMemory
(
entry
.
jit
.
instance
))
{
char
*
memstart
=
&
memoryRef
<
char
>
(
getDefaultMemory
(
entry
.
jit
.
instance
),
0
);
memset
(
memstart
+
info
.
mem_end
,
0
,
((
1
<<
16
)
-
info
.
mem_end
)
);
memcpy
(
memstart
,
info
.
mem_image
.
data
(),
info
.
mem_end
);
}
resetGlobalInstances
(
entry
.
instance
);
resetGlobalInstances
(
entry
.
jit
.
instance
);
// under a lock, put this entry back in the available instances side of the instances vector
with_lock
(
_cache_lock
,
[
&
,
this
](){
...
...
@@ -336,7 +341,7 @@ namespace eosio { namespace chain {
void
wasm_cache
::
checkin
(
const
digest_type
&
code_id
,
entry
&
code
)
{
MemoryInstance
*
default_mem
=
Runtime
::
getDefaultMemory
(
code
.
instance
);
MemoryInstance
*
default_mem
=
Runtime
::
getDefaultMemory
(
code
.
jit
.
instance
);
if
(
default_mem
)
Runtime
::
shrinkMemory
(
default_mem
,
Runtime
::
getMemoryNumPages
(
default_mem
)
-
1
);
_my
->
return_entry
(
code_id
,
code
);
...
...
@@ -362,15 +367,15 @@ namespace eosio { namespace chain {
void
wasm_interface_impl
::
call
(
const
string
&
entry_point
,
const
vector
<
Value
>&
args
,
wasm_cache
::
entry
&
code
,
apply_context
&
context
)
try
{
FunctionInstance
*
call
=
asFunctionNullable
(
getInstanceExport
(
code
.
instance
,
entry_point
)
);
FunctionInstance
*
call
=
asFunctionNullable
(
getInstanceExport
(
code
.
jit
.
instance
,
entry_point
)
);
if
(
!
call
)
{
return
;
}
FC_ASSERT
(
getFunctionType
(
call
)
->
parameters
.
size
()
==
args
.
size
()
);
auto
context_guard
=
scoped_context
(
current_context
,
code
,
context
);
runInstanceStartFunc
(
code
.
instance
);
auto
context_guard
=
scoped_context
(
current_context
,
code
,
context
,
code
.
default_sbrk_bytes
);
runInstanceStartFunc
(
code
.
jit
.
instance
);
Runtime
::
invokeFunction
(
call
,
args
);
}
catch
(
const
Runtime
::
Exception
&
e
)
{
FC_THROW_EXCEPTION
(
wasm_execution_error
,
...
...
@@ -402,6 +407,15 @@ namespace eosio { namespace chain {
my
->
call
(
"error"
,
args
,
code
,
context
);
}
wasm_context
&
common
::
intrinsics_accessor
::
get_context
(
wasm_interface
&
wasm
)
{
FC_ASSERT
(
wasm
.
my
->
current_context
.
valid
());
return
*
wasm
.
my
->
current_context
;
}
const
jit
::
entry
&
jit
::
entry
::
get
(
wasm_interface
&
wasm
)
{
return
common
::
intrinsics_accessor
::
get_context
(
wasm
).
code
.
jit
;
}
#if defined(assert)
#undef assert
#endif
...
...
@@ -932,7 +946,7 @@ class memory_api : public context_aware_api {
constexpr
uint32_t
NBPPL2
=
IR
::
numBytesPerPageLog2
;
constexpr
uint32_t
MAX_MEM
=
1024
*
1024
;
MemoryInstance
*
default_mem
=
Runtime
::
getDefaultMemory
(
code
.
instance
);
MemoryInstance
*
default_mem
=
Runtime
::
getDefaultMemory
(
code
.
jit
.
instance
);
if
(
!
default_mem
)
throw
eosio
::
chain
::
page_memory_error
();
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录