mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #8237 from ethereum/i32TypesForWasm
I32 types for wasm
This commit is contained in:
commit
686b62b585
@ -311,7 +311,11 @@ bytes BinaryTransform::operator()(BuiltinCall const& _call)
|
||||
bytes args = visit(_call.arguments);
|
||||
|
||||
if (_call.functionName == "unreachable")
|
||||
return toBytes(Opcode::Unreachable);
|
||||
return toBytes(Opcode::Unreachable);
|
||||
else if (_call.functionName == "nop")
|
||||
return toBytes(Opcode::Nop);
|
||||
else if (_call.functionName == "drop")
|
||||
return toBytes(Opcode::Drop);
|
||||
else
|
||||
{
|
||||
yulAssert(builtins.count(_call.functionName), "Builtin " + _call.functionName + " not found");
|
||||
|
@ -48,25 +48,26 @@ using namespace solidity::langutil;
|
||||
|
||||
namespace
|
||||
{
|
||||
static string const polyfill{R"({
|
||||
function or_bool(a, b, c, d) -> r {
|
||||
r := i64.or(i64.or(a, b), i64.or(c, d))
|
||||
static string const polyfill{R"(
|
||||
{
|
||||
function or_bool(a, b, c, d) -> r:i32 {
|
||||
r := i32.eqz(i64.eqz(i64.or(i64.or(a, b), i64.or(c, d))))
|
||||
}
|
||||
function or_bool_320(a, b, c, d, e) -> r {
|
||||
r := i64.or(or_bool(a, b, c, d), e)
|
||||
function or_bool_320(a, b, c, d, e) -> r:i32 {
|
||||
r := i32.or(or_bool(a, b, c, 0), or_bool(d, e, 0, 0))
|
||||
}
|
||||
function or_bool_512(a, b, c, d, e, f, g, h) -> r {
|
||||
r := i64.or(or_bool(a, b, c, d), or_bool(e, f, g, h))
|
||||
function or_bool_512(a, b, c, d, e, f, g, h) -> r:i32 {
|
||||
r := i32.or(or_bool(a, b, c, d), or_bool(e, f, g, h))
|
||||
}
|
||||
// returns a + y + c plus carry value on 64 bit values.
|
||||
// c should be at most 1
|
||||
function add_carry(x, y, c) -> r, r_c {
|
||||
let t := i64.add(x, y)
|
||||
r := i64.add(t, c)
|
||||
r_c := i64.or(
|
||||
r_c := i64.extend_i32_u(i32.or(
|
||||
i64.lt_u(t, x),
|
||||
i64.lt_u(r, t)
|
||||
)
|
||||
))
|
||||
}
|
||||
function add(x1, x2, x3, x4, y1, y2, y3, y4) -> r1, r2, r3, r4 {
|
||||
let carry
|
||||
@ -254,8 +255,8 @@ function div(x1, x2, x3, x4, y1, y2, y3, y4) -> r1, r2, r3, r4 {
|
||||
let m3 := 0
|
||||
let m4 := 1
|
||||
|
||||
for {} 1 {} {
|
||||
if i64.or(i64.eqz(i64.clz(y1)), gte_256x256_64(y1, y2, y3, y4, x1, x2, x3, x4)) {
|
||||
for {} true {} {
|
||||
if i32.or(i64.eqz(i64.clz(y1)), gte_256x256_64(y1, y2, y3, y4, x1, x2, x3, x4)) {
|
||||
break
|
||||
}
|
||||
y1, y2, y3, y4 := shl_internal(1, y1, y2, y3, y4)
|
||||
@ -276,7 +277,7 @@ function div(x1, x2, x3, x4, y1, y2, y3, y4) -> r1, r2, r3, r4 {
|
||||
function sdiv(x1, x2, x3, x4, y1, y2, y3, y4) -> r1, r2, r3, r4 {
|
||||
// Based on https://github.com/ewasm/evm2wasm/blob/master/wasm/SDIV.wast
|
||||
|
||||
let sign := i64.shr_u(i64.xor(x1, y1), 63)
|
||||
let sign:i32 := i32.wrap_i64(i64.shr_u(i64.xor(x1, y1), 63))
|
||||
|
||||
if i64.eqz(i64.clz(x1)) {
|
||||
x1, x2, x3, x4 := xor(
|
||||
@ -320,8 +321,8 @@ function mod(x1, x2, x3, x4, y1, y2, y3, y4) -> r1, r2, r3, r4 {
|
||||
let m3 := 0
|
||||
let m4 := 1
|
||||
|
||||
for {} 1 {} {
|
||||
if i64.or(i64.eqz(i64.clz(y1)), gte_256x256_64(y1, y2, y3, y4, r1, r2, r3, r4)) {
|
||||
for {} true {} {
|
||||
if i32.or(i64.eqz(i64.clz(y1)), gte_256x256_64(y1, y2, y3, y4, r1, r2, r3, r4)) {
|
||||
break
|
||||
}
|
||||
|
||||
@ -356,8 +357,8 @@ function mod320(x1, x2, x3, x4, x5, y1, y2, y3, y4, y5) -> r1, r2, r3, r4, r5 {
|
||||
r4 := x4
|
||||
r5 := x5
|
||||
|
||||
for {} 1 {} {
|
||||
if i64.or(i64.eqz(i64.clz(y1)), gte_320x320_64(y1, y2, y3, y4, y5, r1, r2, r3, r4, r5)) {
|
||||
for {} true {} {
|
||||
if i32.or(i64.eqz(i64.clz(y1)), gte_320x320_64(y1, y2, y3, y4, y5, r1, r2, r3, r4, r5)) {
|
||||
break
|
||||
}
|
||||
y1, y2, y3, y4, y5 := shl320_internal(1, y1, y2, y3, y4, y5)
|
||||
@ -397,8 +398,8 @@ function mod512(x1, x2, x3, x4, x5, x6, x7, x8, y1, y2, y3, y4, y5, y6, y7, y8)
|
||||
r7 := x7
|
||||
r8 := x8
|
||||
|
||||
for {} 1 {} {
|
||||
if i64.or(
|
||||
for {} true {} {
|
||||
if i32.or(
|
||||
i64.eqz(i64.clz(y1)),
|
||||
gte_512x512_64(y1, y2, y3, y4, y5, y6, y7, y8, r1, r2, r3, r4, r5, r6, r7, r8)
|
||||
)
|
||||
@ -425,7 +426,7 @@ function smod(x1, x2, x3, x4, y1, y2, y3, y4) -> r1, r2, r3, r4 {
|
||||
let m3 := 0
|
||||
let m4 := 1
|
||||
|
||||
let sign := i64.shr_u(x1, 63)
|
||||
let sign:i32 := i32.wrap_i64(i64.shr_u(x1, 63))
|
||||
|
||||
if i64.eqz(i64.clz(x1)) {
|
||||
x1, x2, x3, x4 := xor(
|
||||
@ -456,7 +457,7 @@ function smod(x1, x2, x3, x4, y1, y2, y3, y4) -> r1, r2, r3, r4 {
|
||||
function exp(x1, x2, x3, x4, y1, y2, y3, y4) -> r1, r2, r3, r4 {
|
||||
r4 := 1
|
||||
for {} or_bool(y1, y2, y3, y4) {} {
|
||||
if i64.and(y4, 1) {
|
||||
if i32.wrap_i64(i64.and(y4, 1)) {
|
||||
r1, r2, r3, r4 := mul(r1, r2, r3, r4, x1, x2, x3, x4)
|
||||
}
|
||||
x1, x2, x3, x4 := mul(x1, x2, x3, x4, x1, x2, x3, x4)
|
||||
@ -499,17 +500,17 @@ function not(x1, x2, x3, x4) -> r1, r2, r3, r4 {
|
||||
let mask := 0xffffffffffffffff
|
||||
r1, r2, r3, r4 := xor(x1, x2, x3, x4, mask, mask, mask, mask)
|
||||
}
|
||||
function iszero(x1, x2, x3, x4) -> r1, r2, r3 ,r4 {
|
||||
r4 := iszero256(x1, x2, x3, x4)
|
||||
function iszero(x1, x2, x3, x4) -> r1, r2, r3, r4 {
|
||||
r4 := i64.extend_i32_u(iszero256(x1, x2, x3, x4))
|
||||
}
|
||||
function iszero256(x1, x2, x3, x4) -> r {
|
||||
function iszero256(x1, x2, x3, x4) -> r:i32 {
|
||||
r := i64.eqz(i64.or(i64.or(x1, x2), i64.or(x3, x4)))
|
||||
}
|
||||
function iszero320(x1, x2, x3, x4, x5) -> r {
|
||||
function iszero320(x1, x2, x3, x4, x5) -> r:i32 {
|
||||
r := i64.eqz(i64.or(i64.or(i64.or(x1, x2), i64.or(x3, x4)), x5))
|
||||
}
|
||||
function iszero512(x1, x2, x3, x4, x5, x6, x7, x8) -> r {
|
||||
r := i64.and(iszero256(x1, x2, x3, x4), iszero256(x5, x6, x7, x8))
|
||||
function iszero512(x1, x2, x3, x4, x5, x6, x7, x8) -> r:i32 {
|
||||
r := i32.and(iszero256(x1, x2, x3, x4), iszero256(x5, x6, x7, x8))
|
||||
}
|
||||
function eq(x1, x2, x3, x4, y1, y2, y3, y4) -> r1, r2, r3, r4 {
|
||||
if i64.eq(x1, y1) {
|
||||
@ -524,107 +525,108 @@ function eq(x1, x2, x3, x4, y1, y2, y3, y4) -> r1, r2, r3, r4 {
|
||||
}
|
||||
|
||||
// returns 0 if a == b, -1 if a < b and 1 if a > b
|
||||
function cmp(a, b) -> r {
|
||||
function cmp(a, b) -> r:i32 {
|
||||
switch i64.lt_u(a, b)
|
||||
case 1 { r := 0xffffffffffffffff }
|
||||
case 1:i32 { r := 0xffffffff:i32 }
|
||||
default {
|
||||
r := i64.ne(a, b)
|
||||
}
|
||||
}
|
||||
function lt_320x320_64(x1, x2, x3, x4, x5, y1, y2, y3, y4, y5) -> z {
|
||||
function lt_320x320_64(x1, x2, x3, x4, x5, y1, y2, y3, y4, y5) -> z:i32 {
|
||||
switch cmp(x1, y1)
|
||||
case 0 {
|
||||
case 0:i32 {
|
||||
switch cmp(x2, y2)
|
||||
case 0 {
|
||||
case 0:i32 {
|
||||
switch cmp(x3, y3)
|
||||
case 0 {
|
||||
case 0:i32 {
|
||||
switch cmp(x4, y4)
|
||||
case 0 {
|
||||
case 0:i32 {
|
||||
z := i64.lt_u(x5, y5)
|
||||
}
|
||||
case 1 { z := 0 }
|
||||
default { z := 1 }
|
||||
case 1:i32 { z := 0:i32 }
|
||||
default { z := 1:i32 }
|
||||
}
|
||||
case 1 { z := 0 }
|
||||
default { z := 1 }
|
||||
case 1:i32 { z := 0:i32 }
|
||||
default { z := 1:i32 }
|
||||
}
|
||||
case 1 { z := 0 }
|
||||
default { z := 1 }
|
||||
case 1:i32 { z := 0:i32 }
|
||||
default { z := 1:i32 }
|
||||
}
|
||||
case 1 { z := 0 }
|
||||
default { z := 1 }
|
||||
case 1:i32 { z := 0:i32 }
|
||||
default { z := 1:i32 }
|
||||
}
|
||||
function lt_512x512_64(x1, x2, x3, x4, x5, x6, x7, x8, y1, y2, y3, y4, y5, y6, y7, y8) -> z {
|
||||
function lt_512x512_64(x1, x2, x3, x4, x5, x6, x7, x8, y1, y2, y3, y4, y5, y6, y7, y8) -> z:i32 {
|
||||
switch cmp(x1, y1)
|
||||
case 0 {
|
||||
case 0:i32 {
|
||||
switch cmp(x2, y2)
|
||||
case 0 {
|
||||
case 0:i32 {
|
||||
switch cmp(x3, y3)
|
||||
case 0 {
|
||||
case 0:i32 {
|
||||
switch cmp(x4, y4)
|
||||
case 0 {
|
||||
case 0:i32 {
|
||||
switch cmp(x5, y5)
|
||||
case 0 {
|
||||
case 0:i32 {
|
||||
switch cmp(x6, y6)
|
||||
case 0 {
|
||||
case 0:i32 {
|
||||
switch cmp(x7, y7)
|
||||
case 0 {
|
||||
case 0:i32 {
|
||||
z := i64.lt_u(x8, y8)
|
||||
}
|
||||
case 1 { z := 0 }
|
||||
default { z := 1 }
|
||||
case 1:i32 { z := 0:i32 }
|
||||
default { z := 1:i32 }
|
||||
}
|
||||
case 1 { z := 0 }
|
||||
default { z := 1 }
|
||||
case 1:i32 { z := 0:i32 }
|
||||
default { z := 1:i32 }
|
||||
}
|
||||
case 1 { z := 0 }
|
||||
default { z := 1 }
|
||||
case 1:i32 { z := 0:i32 }
|
||||
default { z := 1:i32 }
|
||||
}
|
||||
case 1 { z := 0 }
|
||||
default { z := 1 }
|
||||
case 1:i32 { z := 0:i32 }
|
||||
default { z := 1:i32 }
|
||||
}
|
||||
case 1 { z := 0 }
|
||||
default { z := 1 }
|
||||
case 1:i32 { z := 0:i32 }
|
||||
default { z := 1:i32 }
|
||||
}
|
||||
case 1 { z := 0 }
|
||||
default { z := 1 }
|
||||
case 1:i32 { z := 0:i32 }
|
||||
default { z := 1:i32 }
|
||||
}
|
||||
case 1 { z := 0 }
|
||||
default { z := 1 }
|
||||
}
|
||||
case 1:i32 { z := 0:i32 }
|
||||
default { z := 1:i32 }
|
||||
}/*
|
||||
)"
|
||||
// Split long string to make it compilable on msvc
|
||||
// https://docs.microsoft.com/en-us/cpp/error-messages/compiler-errors-1/compiler-error-c2026?view=vs-2019
|
||||
R"(
|
||||
function lt_256x256_64(x1, x2, x3, x4, y1, y2, y3, y4) -> z {
|
||||
*/
|
||||
function lt_256x256_64(x1, x2, x3, x4, y1, y2, y3, y4) -> z:i32 {
|
||||
switch cmp(x1, y1)
|
||||
case 0 {
|
||||
case 0:i32 {
|
||||
switch cmp(x2, y2)
|
||||
case 0 {
|
||||
case 0:i32 {
|
||||
switch cmp(x3, y3)
|
||||
case 0 {
|
||||
case 0:i32 {
|
||||
z := i64.lt_u(x4, y4)
|
||||
}
|
||||
case 1 { z := 0 }
|
||||
default { z := 1 }
|
||||
case 1:i32 { z := 0:i32 }
|
||||
default { z := 1:i32 }
|
||||
}
|
||||
case 1 { z := 0 }
|
||||
default { z := 1 }
|
||||
case 1:i32 { z := 0:i32 }
|
||||
default { z := 1:i32 }
|
||||
}
|
||||
case 1 { z := 0 }
|
||||
default { z := 1 }
|
||||
case 1:i32 { z := 0:i32 }
|
||||
default { z := 1:i32 }
|
||||
}
|
||||
function lt(x1, x2, x3, x4, y1, y2, y3, y4) -> z1, z2, z3, z4 {
|
||||
z4 := lt_256x256_64(x1, x2, x3, x4, y1, y2, y3, y4)
|
||||
z4 := i64.extend_i32_u(lt_256x256_64(x1, x2, x3, x4, y1, y2, y3, y4))
|
||||
}
|
||||
function gte_256x256_64(x1, x2, x3, x4, y1, y2, y3, y4) -> z {
|
||||
z := i64.eqz(lt_256x256_64(x1, x2, x3, x4, y1, y2, y3, y4))
|
||||
function gte_256x256_64(x1, x2, x3, x4, y1, y2, y3, y4) -> z:i32 {
|
||||
z := i32.eqz(lt_256x256_64(x1, x2, x3, x4, y1, y2, y3, y4))
|
||||
}
|
||||
function gte_320x320_64(x1, x2, x3, x4, x5, y1, y2, y3, y4, y5) -> z {
|
||||
z := i64.eqz(lt_320x320_64(x1, x2, x3, x4, x5, y1, y2, y3, y4, y5))
|
||||
function gte_320x320_64(x1, x2, x3, x4, x5, y1, y2, y3, y4, y5) -> z:i32 {
|
||||
z := i32.eqz(lt_320x320_64(x1, x2, x3, x4, x5, y1, y2, y3, y4, y5))
|
||||
}
|
||||
function gte_512x512_64(x1, x2, x3, x4, x5, x6, x7, x8, y1, y2, y3, y4, y5, y6, y7, y8) -> z {
|
||||
z := i64.eqz(lt_512x512_64(x1, x2, x3, x4, x5, x6, x7, x8, y1, y2, y3, y4, y5, y6, y7, y8))
|
||||
function gte_512x512_64(x1, x2, x3, x4, x5, x6, x7, x8, y1, y2, y3, y4, y5, y6, y7, y8) -> z:i32 {
|
||||
z := i32.eqz(lt_512x512_64(x1, x2, x3, x4, x5, x6, x7, x8, y1, y2, y3, y4, y5, y6, y7, y8))
|
||||
}
|
||||
function gt(x1, x2, x3, x4, y1, y2, y3, y4) -> z1, z2, z3, z4 {
|
||||
z1, z2, z3, z4 := lt(y1, y2, y3, y4, x1, x2, x3, x4)
|
||||
@ -646,7 +648,7 @@ function shl_single(a, amount) -> x, y {
|
||||
}
|
||||
|
||||
function shl(x1, x2, x3, x4, y1, y2, y3, y4) -> z1, z2, z3, z4 {
|
||||
if i64.and(i64.eqz(x1), i64.eqz(x2)) {
|
||||
if i32.and(i64.eqz(x1), i64.eqz(x2)) {
|
||||
if i64.eqz(x3) {
|
||||
if i64.lt_u(x4, 256) {
|
||||
if i64.ge_u(x4, 128) {
|
||||
@ -683,7 +685,7 @@ function shr_single(a, amount) -> x, y {
|
||||
}
|
||||
|
||||
function shr(x1, x2, x3, x4, y1, y2, y3, y4) -> z1, z2, z3, z4 {
|
||||
if i64.and(i64.eqz(x1), i64.eqz(x2)) {
|
||||
if i32.and(i64.eqz(x1), i64.eqz(x2)) {
|
||||
if i64.eqz(x3) {
|
||||
if i64.lt_u(x4, 256) {
|
||||
if i64.ge_u(x4, 128) {
|
||||
@ -713,7 +715,7 @@ function shr(x1, x2, x3, x4, y1, y2, y3, y4) -> z1, z2, z3, z4 {
|
||||
}
|
||||
}
|
||||
function sar(x1, x2, x3, x4, y1, y2, y3, y4) -> z1, z2, z3, z4 {
|
||||
if i64.clz(y1) {
|
||||
if i64.gt_u(i64.clz(y1), 0) {
|
||||
z1, z2, z3, z4 := shr(x1, x2, x3, x4, y1, y2, y3, y4)
|
||||
leave
|
||||
}
|
||||
@ -773,10 +775,10 @@ function u256_to_i64(x1, x2, x3, x4) -> v {
|
||||
v := x4
|
||||
}
|
||||
|
||||
function u256_to_i32(x1, x2, x3, x4) -> v {
|
||||
function u256_to_i32(x1, x2, x3, x4) -> v:i32 {
|
||||
if i64.ne(0, i64.or(i64.or(x1, x2), x3)) { invalid() }
|
||||
if i64.ne(0, i64.shr_u(x4, 32)) { invalid() }
|
||||
v := x4
|
||||
v := i32.wrap_i64(x4)
|
||||
}
|
||||
|
||||
function u256_to_byte(x1, x2, x3, x4) -> v {
|
||||
@ -785,14 +787,14 @@ function u256_to_byte(x1, x2, x3, x4) -> v {
|
||||
v := x4
|
||||
}
|
||||
|
||||
function u256_to_i32ptr(x1, x2, x3, x4) -> v {
|
||||
function u256_to_i32ptr(x1, x2, x3, x4) -> v:i32 {
|
||||
v := u256_to_i32(x1, x2, x3, x4)
|
||||
}
|
||||
|
||||
function to_internal_i32ptr(x1, x2, x3, x4) -> r {
|
||||
let p := u256_to_i32ptr(x1, x2, x3, x4)
|
||||
r := i64.add(p, 64)
|
||||
if i64.lt_u(r, p) { invalid() }
|
||||
function to_internal_i32ptr(x1, x2, x3, x4) -> r:i32 {
|
||||
let p:i32 := u256_to_i32ptr(x1, x2, x3, x4)
|
||||
r := i32.add(p, 64:i32)
|
||||
if i32.lt_u(r, p) { invalid() }
|
||||
}
|
||||
|
||||
function u256_to_address(x1, x2, x3, x4) -> r1, r2, r3 {
|
||||
@ -809,13 +811,13 @@ function keccak256(x1, x2, x3, x4, y1, y2, y3, y4) -> z1, z2, z3, z4 {
|
||||
}
|
||||
|
||||
function address() -> z1, z2, z3, z4 {
|
||||
eth.getAddress(0)
|
||||
z1, z2, z3, z4 := mload_internal(0)
|
||||
eth.getAddress(0:i32)
|
||||
z1, z2, z3, z4 := mload_internal(0:i32)
|
||||
}
|
||||
function balance(x1, x2, x3, x4) -> z1, z2, z3, z4 {
|
||||
mstore_address(0, x1, x2, x3, x4)
|
||||
eth.getExternalBalance(12, 48)
|
||||
z1, z2, z3, z4 := mload_internal(32)
|
||||
mstore_address(0:i32, x1, x2, x3, x4)
|
||||
eth.getExternalBalance(12:i32, 48:i32)
|
||||
z1, z2, z3, z4 := mload_internal(32:i32)
|
||||
}
|
||||
function selfbalance() -> z1, z2, z3, z4 {
|
||||
// TODO: not part of current Ewasm spec
|
||||
@ -826,23 +828,23 @@ function chainid() -> z1, z2, z3, z4 {
|
||||
unreachable()
|
||||
}
|
||||
function origin() -> z1, z2, z3, z4 {
|
||||
eth.getTxOrigin(0)
|
||||
z1, z2, z3, z4 := mload_internal(0)
|
||||
eth.getTxOrigin(0:i32)
|
||||
z1, z2, z3, z4 := mload_internal(0:i32)
|
||||
}
|
||||
function caller() -> z1, z2, z3, z4 {
|
||||
eth.getCaller(0)
|
||||
z1, z2, z3, z4 := mload_internal(0)
|
||||
eth.getCaller(0:i32)
|
||||
z1, z2, z3, z4 := mload_internal(0:i32)
|
||||
}
|
||||
function callvalue() -> z1, z2, z3, z4 {
|
||||
eth.getCallValue(0)
|
||||
z1, z2, z3, z4 := mload_internal(0)
|
||||
eth.getCallValue(0:i32)
|
||||
z1, z2, z3, z4 := mload_internal(0:i32)
|
||||
}
|
||||
function calldataload(x1, x2, x3, x4) -> z1, z2, z3, z4 {
|
||||
eth.callDataCopy(0, u256_to_i32(x1, x2, x3, x4), 32)
|
||||
z1, z2, z3, z4 := mload_internal(0)
|
||||
eth.callDataCopy(0:i32, u256_to_i32(x1, x2, x3, x4), 32:i32)
|
||||
z1, z2, z3, z4 := mload_internal(0:i32)
|
||||
}
|
||||
function calldatasize() -> z1, z2, z3, z4 {
|
||||
z4 := eth.getCallDataSize()
|
||||
z4 := i64.extend_i32_u(eth.getCallDataSize())
|
||||
}
|
||||
function calldatacopy(x1, x2, x3, x4, y1, y2, y3, y4, z1, z2, z3, z4) {
|
||||
eth.callDataCopy(
|
||||
@ -854,7 +856,7 @@ function calldatacopy(x1, x2, x3, x4, y1, y2, y3, y4, z1, z2, z3, z4) {
|
||||
|
||||
// Needed?
|
||||
function codesize() -> z1, z2, z3, z4 {
|
||||
z4 := eth.getCodeSize()
|
||||
z4 := i64.extend_i32_u(eth.getCodeSize())
|
||||
}
|
||||
function codecopy(x1, x2, x3, x4, y1, y2, y3, y4, z1, z2, z3, z4) {
|
||||
eth.codeCopy(
|
||||
@ -869,29 +871,29 @@ function datacopy(x1, x2, x3, x4, y1, y2, y3, y4, z1, z2, z3, z4) {
|
||||
}
|
||||
|
||||
function gasprice() -> z1, z2, z3, z4 {
|
||||
eth.getTxGasPrice(0)
|
||||
z1, z2, z3, z4 := mload_internal(0)
|
||||
eth.getTxGasPrice(0:i32)
|
||||
z1, z2, z3, z4 := mload_internal(0:i32)
|
||||
}
|
||||
function extcodesize_internal(x1, x2, x3, x4) -> r {
|
||||
mstore_address(0, x1, x2, x3, x4)
|
||||
r := eth.getExternalCodeSize(12)
|
||||
function extcodesize_internal(x1, x2, x3, x4) -> r:i32 {
|
||||
mstore_address(0:i32, x1, x2, x3, x4)
|
||||
r := eth.getExternalCodeSize(12:i32)
|
||||
}
|
||||
function extcodesize(x1, x2, x3, x4) -> z1, z2, z3, z4 {
|
||||
z4 := extcodesize_internal(x1, x2, x3, x4)
|
||||
z4 := i64.extend_i32_u(extcodesize_internal(x1, x2, x3, x4))
|
||||
}
|
||||
function extcodehash(x1, x2, x3, x4) -> z1, z2, z3, z4 {
|
||||
// TODO: not part of current Ewasm spec
|
||||
unreachable()
|
||||
}
|
||||
function extcodecopy(a1, a2, a3, a4, p1, p2, p3, p4, o1, o2, o3, o4, l1, l2, l3, l4) {
|
||||
mstore_address(0, a1, a2, a3, a4)
|
||||
let codeOffset := u256_to_i32(o1, o2, o3, o4)
|
||||
let codeLength := u256_to_i32(l1, l2, l3, l4)
|
||||
eth.externalCodeCopy(12, to_internal_i32ptr(p1, p2, p3, p4), codeOffset, codeLength)
|
||||
mstore_address(0:i32, a1, a2, a3, a4)
|
||||
let codeOffset:i32 := u256_to_i32(o1, o2, o3, o4)
|
||||
let codeLength:i32 := u256_to_i32(l1, l2, l3, l4)
|
||||
eth.externalCodeCopy(12:i32, to_internal_i32ptr(p1, p2, p3, p4), codeOffset, codeLength)
|
||||
}
|
||||
|
||||
function returndatasize() -> z1, z2, z3, z4 {
|
||||
z4 := eth.getReturnDataSize()
|
||||
z4 := i64.extend_i32_u(eth.getReturnDataSize())
|
||||
}
|
||||
function returndatacopy(x1, x2, x3, x4, y1, y2, y3, y4, z1, z2, z3, z4) {
|
||||
eth.returnDataCopy(
|
||||
@ -902,14 +904,14 @@ function returndatacopy(x1, x2, x3, x4, y1, y2, y3, y4, z1, z2, z3, z4) {
|
||||
}
|
||||
|
||||
function blockhash(x1, x2, x3, x4) -> z1, z2, z3, z4 {
|
||||
let r := eth.getBlockHash(u256_to_i64(x1, x2, x3, x4), 0)
|
||||
if i64.eqz(r) {
|
||||
z1, z2, z3, z4 := mload_internal(0)
|
||||
let r:i32 := eth.getBlockHash(u256_to_i64(x1, x2, x3, x4), 0:i32)
|
||||
if i32.eqz(r) {
|
||||
z1, z2, z3, z4 := mload_internal(0:i32)
|
||||
}
|
||||
}
|
||||
function coinbase() -> z1, z2, z3, z4 {
|
||||
eth.getBlockCoinbase(0)
|
||||
z1, z2, z3, z4 := mload_internal(0)
|
||||
eth.getBlockCoinbase(0:i32)
|
||||
z1, z2, z3, z4 := mload_internal(0:i32)
|
||||
}
|
||||
function timestamp() -> z1, z2, z3, z4 {
|
||||
z4 := eth.getBlockTimestamp()
|
||||
@ -918,8 +920,8 @@ function number() -> z1, z2, z3, z4 {
|
||||
z4 := eth.getBlockNumber()
|
||||
}
|
||||
function difficulty() -> z1, z2, z3, z4 {
|
||||
eth.getBlockDifficulty(0)
|
||||
z1, z2, z3, z4 := mload_internal(0)
|
||||
eth.getBlockDifficulty(0:i32)
|
||||
z1, z2, z3, z4 := mload_internal(0:i32)
|
||||
}
|
||||
function gaslimit() -> z1, z2, z3, z4 {
|
||||
z4 := eth.getBlockGasLimit()
|
||||
@ -947,56 +949,56 @@ function endian_swap(x) -> y {
|
||||
y := i64.or(hi, lo)
|
||||
}
|
||||
function save_temp_mem_32() -> t1, t2, t3, t4 {
|
||||
t1 := i64.load(0)
|
||||
t2 := i64.load(8)
|
||||
t3 := i64.load(16)
|
||||
t4 := i64.load(24)
|
||||
t1 := i64.load(0:i32)
|
||||
t2 := i64.load(8:i32)
|
||||
t3 := i64.load(16:i32)
|
||||
t4 := i64.load(24:i32)
|
||||
}
|
||||
function restore_temp_mem_32(t1, t2, t3, t4) {
|
||||
i64.store(0, t1)
|
||||
i64.store(8, t2)
|
||||
i64.store(16, t3)
|
||||
i64.store(24, t4)
|
||||
i64.store(0:i32, t1)
|
||||
i64.store(8:i32, t2)
|
||||
i64.store(16:i32, t3)
|
||||
i64.store(24:i32, t4)
|
||||
}
|
||||
function save_temp_mem_64() -> t1, t2, t3, t4, t5, t6, t7, t8 {
|
||||
t1 := i64.load(0)
|
||||
t2 := i64.load(8)
|
||||
t3 := i64.load(16)
|
||||
t4 := i64.load(24)
|
||||
t5 := i64.load(32)
|
||||
t6 := i64.load(40)
|
||||
t7 := i64.load(48)
|
||||
t8 := i64.load(54)
|
||||
t1 := i64.load(0:i32)
|
||||
t2 := i64.load(8:i32)
|
||||
t3 := i64.load(16:i32)
|
||||
t4 := i64.load(24:i32)
|
||||
t5 := i64.load(32:i32)
|
||||
t6 := i64.load(40:i32)
|
||||
t7 := i64.load(48:i32)
|
||||
t8 := i64.load(54:i32)
|
||||
}
|
||||
function restore_temp_mem_64(t1, t2, t3, t4, t5, t6, t7, t8) {
|
||||
i64.store(0, t1)
|
||||
i64.store(8, t2)
|
||||
i64.store(16, t3)
|
||||
i64.store(24, t4)
|
||||
i64.store(32, t5)
|
||||
i64.store(40, t6)
|
||||
i64.store(48, t7)
|
||||
i64.store(54, t8)
|
||||
i64.store(0:i32, t1)
|
||||
i64.store(8:i32, t2)
|
||||
i64.store(16:i32, t3)
|
||||
i64.store(24:i32, t4)
|
||||
i64.store(32:i32, t5)
|
||||
i64.store(40:i32, t6)
|
||||
i64.store(48:i32, t7)
|
||||
i64.store(54:i32, t8)
|
||||
}
|
||||
function mload(x1, x2, x3, x4) -> z1, z2, z3, z4 {
|
||||
z1, z2, z3, z4 := mload_internal(to_internal_i32ptr(x1, x2, x3, x4))
|
||||
}
|
||||
function mload_internal(pos) -> z1, z2, z3, z4 {
|
||||
function mload_internal(pos:i32) -> z1, z2, z3, z4 {
|
||||
z1 := endian_swap(i64.load(pos))
|
||||
z2 := endian_swap(i64.load(i64.add(pos, 8)))
|
||||
z3 := endian_swap(i64.load(i64.add(pos, 16)))
|
||||
z4 := endian_swap(i64.load(i64.add(pos, 24)))
|
||||
z2 := endian_swap(i64.load(i32.add(pos, 8:i32)))
|
||||
z3 := endian_swap(i64.load(i32.add(pos, 16:i32)))
|
||||
z4 := endian_swap(i64.load(i32.add(pos, 24:i32)))
|
||||
}
|
||||
function mstore(x1, x2, x3, x4, y1, y2, y3, y4) {
|
||||
mstore_internal(to_internal_i32ptr(x1, x2, x3, x4), y1, y2, y3, y4)
|
||||
}
|
||||
function mstore_internal(pos, y1, y2, y3, y4) {
|
||||
function mstore_internal(pos:i32, y1, y2, y3, y4) {
|
||||
i64.store(pos, endian_swap(y1))
|
||||
i64.store(i64.add(pos, 8), endian_swap(y2))
|
||||
i64.store(i64.add(pos, 16), endian_swap(y3))
|
||||
i64.store(i64.add(pos, 24), endian_swap(y4))
|
||||
i64.store(i32.add(pos, 8:i32), endian_swap(y2))
|
||||
i64.store(i32.add(pos, 16:i32), endian_swap(y3))
|
||||
i64.store(i32.add(pos, 24:i32), endian_swap(y4))
|
||||
}
|
||||
function mstore_address(pos, a1, a2, a3, a4) {
|
||||
function mstore_address(pos:i32, a1, a2, a3, a4) {
|
||||
a1, a2, a3 := u256_to_address(a1, a2, a3, a4)
|
||||
mstore_internal(pos, 0, a1, a2, a3)
|
||||
}
|
||||
@ -1010,15 +1012,15 @@ function msize() -> z1, z2, z3, z4 {
|
||||
unreachable()
|
||||
}
|
||||
function sload(x1, x2, x3, x4) -> z1, z2, z3, z4 {
|
||||
mstore_internal(0, x1, x2, x3, x4)
|
||||
eth.storageLoad(0, 32)
|
||||
z1, z2, z3, z4 := mload_internal(32)
|
||||
mstore_internal(0:i32, x1, x2, x3, x4)
|
||||
eth.storageLoad(0:i32, 32:i32)
|
||||
z1, z2, z3, z4 := mload_internal(32:i32)
|
||||
}
|
||||
|
||||
function sstore(x1, x2, x3, x4, y1, y2, y3, y4) {
|
||||
mstore_internal(0, x1, x2, x3, x4)
|
||||
mstore_internal(32, y1, y2, y3, y4)
|
||||
eth.storageStore(0, 32)
|
||||
mstore_internal(0:i32, x1, x2, x3, x4)
|
||||
mstore_internal(32:i32, y1, y2, y3, y4)
|
||||
eth.storageStore(0:i32, 32:i32)
|
||||
}
|
||||
|
||||
// Needed?
|
||||
@ -1034,7 +1036,7 @@ function log0(p1, p2, p3, p4, s1, s2, s3, s4) {
|
||||
eth.log(
|
||||
to_internal_i32ptr(p1, p2, p3, p4),
|
||||
u256_to_i32(s1, s2, s3, s4),
|
||||
0, 0, 0, 0, 0
|
||||
0:i32, 0:i32, 0:i32, 0:i32, 0:i32
|
||||
)
|
||||
}
|
||||
function log1(
|
||||
@ -1044,9 +1046,9 @@ function log1(
|
||||
eth.log(
|
||||
to_internal_i32ptr(p1, p2, p3, p4),
|
||||
u256_to_i32(s1, s2, s3, s4),
|
||||
1,
|
||||
1:i32,
|
||||
to_internal_i32ptr(t1_1, t1_2, t1_3, t1_4),
|
||||
0, 0, 0
|
||||
0:i32, 0:i32, 0:i32
|
||||
)
|
||||
}
|
||||
function log2(
|
||||
@ -1057,10 +1059,10 @@ function log2(
|
||||
eth.log(
|
||||
to_internal_i32ptr(p1, p2, p3, p4),
|
||||
u256_to_i32(s1, s2, s3, s4),
|
||||
2,
|
||||
2:i32,
|
||||
to_internal_i32ptr(t1_1, t1_2, t1_3, t1_4),
|
||||
to_internal_i32ptr(t2_1, t2_2, t2_3, t2_4),
|
||||
0, 0
|
||||
0:i32, 0:i32
|
||||
)
|
||||
}
|
||||
function log3(
|
||||
@ -1072,11 +1074,11 @@ function log3(
|
||||
eth.log(
|
||||
to_internal_i32ptr(p1, p2, p3, p4),
|
||||
u256_to_i32(s1, s2, s3, s4),
|
||||
3,
|
||||
3:i32,
|
||||
to_internal_i32ptr(t1_1, t1_2, t1_3, t1_4),
|
||||
to_internal_i32ptr(t2_1, t2_2, t2_3, t2_4),
|
||||
to_internal_i32ptr(t3_1, t3_2, t3_3, t3_4),
|
||||
0
|
||||
0:i32
|
||||
)
|
||||
}
|
||||
function log4(
|
||||
@ -1089,7 +1091,7 @@ function log4(
|
||||
eth.log(
|
||||
to_internal_i32ptr(p1, p2, p3, p4),
|
||||
u256_to_i32(s1, s2, s3, s4),
|
||||
4,
|
||||
4:i32,
|
||||
to_internal_i32ptr(t1_1, t1_2, t1_3, t1_4),
|
||||
to_internal_i32ptr(t2_1, t2_2, t2_3, t2_4),
|
||||
to_internal_i32ptr(t3_1, t3_2, t3_3, t3_4),
|
||||
@ -1103,11 +1105,11 @@ function create(
|
||||
z1, z2, z3, z4
|
||||
) -> a1, a2, a3, a4 {
|
||||
let v1, v2 := u256_to_u128(x1, x2, x3, x4)
|
||||
mstore_internal(0, 0, 0, v1, v2)
|
||||
mstore_internal(0:i32, 0, 0, v1, v2)
|
||||
|
||||
let r := eth.create(0, to_internal_i32ptr(y1, y2, y3, y4), u256_to_i32(z1, z2, z3, z4), 32)
|
||||
if i64.eqz(r) {
|
||||
a1, a2, a3, a4 := mload_internal(32)
|
||||
let r:i32 := eth.create(0:i32, to_internal_i32ptr(y1, y2, y3, y4), u256_to_i32(z1, z2, z3, z4), 32:i32)
|
||||
if i32.eqz(r) {
|
||||
a1, a2, a3, a4 := mload_internal(32:i32)
|
||||
}
|
||||
}
|
||||
function call(
|
||||
@ -1120,12 +1122,12 @@ function call(
|
||||
g1, g2, g3, g4
|
||||
) -> x1, x2, x3, x4 {
|
||||
let g := u256_to_i64(a1, a2, a3, a4)
|
||||
mstore_address(0, b1, b2, b3, b4)
|
||||
mstore_address(0:i32, b1, b2, b3, b4)
|
||||
|
||||
let v1, v2 := u256_to_u128(c1, c2, c3, c4)
|
||||
mstore_internal(32, 0, 0, v1, v2)
|
||||
mstore_internal(32:i32, 0, 0, v1, v2)
|
||||
|
||||
x4 := eth.call(g, 12, 32, to_internal_i32ptr(d1, d2, d3, d4), u256_to_i32(e1, e2, e3, e4))
|
||||
x4 := i64.extend_i32_u(eth.call(g, 12:i32, 32:i32, to_internal_i32ptr(d1, d2, d3, d4), u256_to_i32(e1, e2, e3, e4)))
|
||||
}
|
||||
function callcode(
|
||||
a1, a2, a3, a4,
|
||||
@ -1136,18 +1138,18 @@ function callcode(
|
||||
f1, f2, f3, f4,
|
||||
g1, g2, g3, g4
|
||||
) -> x1, x2, x3, x4 {
|
||||
mstore_address(0, b1, b2, b3, b4)
|
||||
mstore_address(0:i32, b1, b2, b3, b4)
|
||||
|
||||
let v1, v2 := u256_to_u128(c1, c2, c3, c4)
|
||||
mstore_internal(32, 0, 0, v1, v2)
|
||||
mstore_internal(32:i32, 0, 0, v1, v2)
|
||||
|
||||
x4 := eth.callCode(
|
||||
x4 := i64.extend_i32_u(eth.callCode(
|
||||
u256_to_i64(a1, a2, a3, a4),
|
||||
12,
|
||||
32,
|
||||
12:i32,
|
||||
32:i32,
|
||||
to_internal_i32ptr(d1, d2, d3, d4),
|
||||
u256_to_i32(e1, e2, e3, e4)
|
||||
)
|
||||
))
|
||||
}
|
||||
function delegatecall(
|
||||
a1, a2, a3, a4,
|
||||
@ -1157,14 +1159,14 @@ function delegatecall(
|
||||
e1, e2, e3, e4,
|
||||
f1, f2, f3, f4
|
||||
) -> x1, x2, x3, x4 {
|
||||
mstore_address(0, b1, b2, b3, b4)
|
||||
mstore_address(0:i32, b1, b2, b3, b4)
|
||||
|
||||
x4 := eth.callDelegate(
|
||||
x4 := i64.extend_i32_u(eth.callDelegate(
|
||||
u256_to_i64(a1, a2, a3, a4),
|
||||
12,
|
||||
12:i32,
|
||||
to_internal_i32ptr(c1, c2, c3, c4),
|
||||
u256_to_i32(d1, d2, d3, d4)
|
||||
)
|
||||
))
|
||||
}
|
||||
function staticcall(
|
||||
a1, a2, a3, a4,
|
||||
@ -1174,14 +1176,14 @@ function staticcall(
|
||||
e1, e2, e3, e4,
|
||||
f1, f2, f3, f4
|
||||
) -> x1, x2, x3, x4 {
|
||||
mstore_address(0, b1, b2, b3, b4)
|
||||
mstore_address(0:i32, b1, b2, b3, b4)
|
||||
|
||||
x4 := eth.callStatic(
|
||||
x4 := i64.extend_i32_u(eth.callStatic(
|
||||
u256_to_i64(a1, a2, a3, a4),
|
||||
12,
|
||||
12:i32,
|
||||
to_internal_i32ptr(c1, c2, c3, c4),
|
||||
u256_to_i32(d1, d2, d3, d4)
|
||||
)
|
||||
))
|
||||
}
|
||||
function create2(
|
||||
a1, a2, a3, a4,
|
||||
@ -1193,9 +1195,9 @@ function create2(
|
||||
unreachable()
|
||||
}
|
||||
function selfdestruct(a1, a2, a3, a4) {
|
||||
mstore_address(0, a1, a2, a3, a4)
|
||||
mstore_address(0:i32, a1, a2, a3, a4)
|
||||
// In EVM, addresses are padded to 32 bytes, so discard the first 12.
|
||||
eth.selfDestruct(12)
|
||||
eth.selfDestruct(12:i32)
|
||||
}
|
||||
|
||||
function return(x1, x2, x3, x4, y1, y2, y3, y4) {
|
||||
@ -1213,7 +1215,8 @@ function revert(x1, x2, x3, x4, y1, y2, y3, y4) {
|
||||
function invalid() {
|
||||
unreachable()
|
||||
}
|
||||
})"};
|
||||
}
|
||||
)"};
|
||||
|
||||
}
|
||||
|
||||
|
@ -20,70 +20,87 @@
|
||||
|
||||
#include <libyul/backends/wasm/WasmDialect.h>
|
||||
|
||||
#include <libyul/Exceptions.h>
|
||||
|
||||
using namespace std;
|
||||
using namespace solidity::yul;
|
||||
|
||||
WasmDialect::WasmDialect()
|
||||
{
|
||||
defaultType = "i64"_yulstring;
|
||||
boolType = "i64"_yulstring;
|
||||
types = {"i64"_yulstring, "i32"_yulstring};
|
||||
YulString i64 = "i64"_yulstring;
|
||||
YulString i32 = "i32"_yulstring;
|
||||
defaultType = i64;
|
||||
boolType = i32;
|
||||
types = {i64, i32};
|
||||
|
||||
for (auto const& name: {
|
||||
"i64.add",
|
||||
"i64.sub",
|
||||
"i64.mul",
|
||||
"i64.div_u",
|
||||
"i64.rem_u",
|
||||
"i64.and",
|
||||
"i64.or",
|
||||
"i64.xor",
|
||||
"i64.shl",
|
||||
"i64.shr_u",
|
||||
"i64.eq",
|
||||
"i64.ne",
|
||||
"i64.lt_u",
|
||||
"i64.gt_u",
|
||||
"i64.le_u",
|
||||
"i64.ge_u"
|
||||
})
|
||||
addFunction(name, 2, 1);
|
||||
for (auto t: types)
|
||||
for (auto const& name: {
|
||||
"add",
|
||||
"sub",
|
||||
"mul",
|
||||
"div_u",
|
||||
"rem_u",
|
||||
"and",
|
||||
"or",
|
||||
"xor",
|
||||
"shl",
|
||||
"shr_u",
|
||||
})
|
||||
addFunction(t.str() + "." + name, {t, t}, {t});
|
||||
|
||||
m_functions["i64.lt_u"_yulstring].returns.front() = "i32"_yulstring;
|
||||
m_functions["i64.gt_u"_yulstring].returns.front() = "i32"_yulstring;
|
||||
m_functions["i64.le_u"_yulstring].returns.front() = "i32"_yulstring;
|
||||
m_functions["i64.ge_u"_yulstring].returns.front() = "i32"_yulstring;
|
||||
m_functions["i64.eq"_yulstring].returns.front() = "i32"_yulstring;
|
||||
m_functions["i64.ne"_yulstring].returns.front() = "i32"_yulstring;
|
||||
for (auto t: types)
|
||||
for (auto const& name: {
|
||||
"eq",
|
||||
"ne",
|
||||
"lt_u",
|
||||
"gt_u",
|
||||
"le_u",
|
||||
"ge_u"
|
||||
})
|
||||
addFunction(t.str() + "." + name, {t, t}, {i32});
|
||||
|
||||
addFunction("i64.eqz", 1, 1);
|
||||
m_functions["i64.eqz"_yulstring].returns.front() = "i32"_yulstring;
|
||||
addFunction("i32.eqz", {i32}, {i32});
|
||||
addFunction("i64.eqz", {i64}, {i32});
|
||||
|
||||
addFunction("i64.clz", 1, 1);
|
||||
addFunction("i32.clz", {i32}, {i32});
|
||||
addFunction("i64.clz", {i64}, {i64});
|
||||
|
||||
addFunction("i64.store", 2, 0, false);
|
||||
m_functions["i64.store"_yulstring].parameters.front() = "i32"_yulstring;
|
||||
addFunction("i32.wrap_i64", {i64}, {i32});
|
||||
|
||||
addFunction("i64.extend_i32_u", {i32}, {i64});
|
||||
|
||||
addFunction("i32.store", {i32, i32}, {}, false);
|
||||
m_functions["i32.store"_yulstring].sideEffects.invalidatesStorage = false;
|
||||
addFunction("i64.store", {i32, i64}, {}, false);
|
||||
m_functions["i64.store"_yulstring].sideEffects.invalidatesStorage = false;
|
||||
|
||||
addFunction("i64.store8", 2, 0, false);
|
||||
m_functions["i64.store8"_yulstring].parameters.front() = "i32"_yulstring;
|
||||
addFunction("i32.store8", {i32, i32}, {}, false);
|
||||
m_functions["i32.store8"_yulstring].sideEffects.invalidatesStorage = false;
|
||||
addFunction("i64.store8", {i32, i64}, {}, false);
|
||||
m_functions["i64.store8"_yulstring].sideEffects.invalidatesStorage = false;
|
||||
|
||||
addFunction("i64.load", 1, 1, false);
|
||||
m_functions["i64.load"_yulstring].parameters.front() = "i32"_yulstring;
|
||||
addFunction("i32.load", {i32}, {i32}, false);
|
||||
m_functions["i32.load"_yulstring].sideEffects.invalidatesStorage = false;
|
||||
m_functions["i32.load"_yulstring].sideEffects.invalidatesMemory = false;
|
||||
m_functions["i32.load"_yulstring].sideEffects.sideEffectFree = true;
|
||||
m_functions["i32.load"_yulstring].sideEffects.sideEffectFreeIfNoMSize = true;
|
||||
addFunction("i64.load", {i32}, {i64}, false);
|
||||
m_functions["i64.load"_yulstring].sideEffects.invalidatesStorage = false;
|
||||
m_functions["i64.load"_yulstring].sideEffects.invalidatesMemory = false;
|
||||
m_functions["i64.load"_yulstring].sideEffects.sideEffectFree = true;
|
||||
m_functions["i64.load"_yulstring].sideEffects.sideEffectFreeIfNoMSize = true;
|
||||
|
||||
addFunction("drop", 1, 0);
|
||||
// Drop is actually overloaded for all types, but Yul does not support that.
|
||||
// We could introduce "i32.drop".
|
||||
addFunction("drop", {i64}, {});
|
||||
|
||||
addFunction("unreachable", 0, 0, false);
|
||||
addFunction("nop", {}, {});
|
||||
addFunction("unreachable", {}, {}, false);
|
||||
m_functions["unreachable"_yulstring].sideEffects.invalidatesStorage = false;
|
||||
m_functions["unreachable"_yulstring].sideEffects.invalidatesMemory = false;
|
||||
|
||||
addFunction("datasize", 1, 1, true, true);
|
||||
addFunction("dataoffset", 1, 1, true, true);
|
||||
addFunction("datasize", {i64}, {i64}, true, true);
|
||||
addFunction("dataoffset", {i64}, {i64}, true, true);
|
||||
|
||||
addEthereumExternals();
|
||||
}
|
||||
@ -167,8 +184,8 @@ void WasmDialect::addEthereumExternals()
|
||||
|
||||
void WasmDialect::addFunction(
|
||||
string _name,
|
||||
size_t _params,
|
||||
size_t _returns,
|
||||
vector<YulString> _params,
|
||||
vector<YulString> _returns,
|
||||
bool _movable,
|
||||
bool _literalArguments
|
||||
)
|
||||
@ -176,8 +193,9 @@ void WasmDialect::addFunction(
|
||||
YulString name{move(_name)};
|
||||
BuiltinFunction& f = m_functions[name];
|
||||
f.name = name;
|
||||
f.parameters.resize(_params);
|
||||
f.returns.resize(_returns);
|
||||
f.parameters = std::move(_params);
|
||||
yulAssert(_returns.size() <= 1, "The Wasm 1.0 specification only allows up to 1 return value.");
|
||||
f.returns = std::move(_returns);
|
||||
f.sideEffects = _movable ? SideEffects{} : SideEffects::worst();
|
||||
f.isMSize = false;
|
||||
f.literalArguments = _literalArguments;
|
||||
|
@ -56,7 +56,13 @@ struct WasmDialect: public Dialect
|
||||
private:
|
||||
void addEthereumExternals();
|
||||
|
||||
void addFunction(std::string _name, size_t _params, size_t _returns, bool _movable = true, bool _literalArguments = false);
|
||||
void addFunction(
|
||||
std::string _name,
|
||||
std::vector<YulString> _params,
|
||||
std::vector<YulString> _returns,
|
||||
bool _movable = true,
|
||||
bool _literalArguments = false
|
||||
);
|
||||
|
||||
std::map<YulString, BuiltinFunction> m_functions;
|
||||
};
|
||||
|
@ -15,9 +15,9 @@ object "object" {
|
||||
function main()
|
||||
{
|
||||
let _1 := 0
|
||||
mstore_internal(_1, _1, _1, _1, _1)
|
||||
mstore_internal(32, _1, _1, _1, 1)
|
||||
eth.storageStore(_1, 32)
|
||||
mstore_internal(0:i32, _1, _1, _1, _1)
|
||||
mstore_internal(32:i32, _1, _1, _1, 1)
|
||||
eth.storageStore(0:i32, 32:i32)
|
||||
}
|
||||
function endian_swap_16(x) -> y
|
||||
{
|
||||
@ -33,19 +33,19 @@ object "object" {
|
||||
let hi := i64.shl(endian_swap_32(x), 32)
|
||||
y := i64.or(hi, endian_swap_32(i64.shr_u(x, 32)))
|
||||
}
|
||||
function mstore_internal(pos, y1, y2, y3, y4)
|
||||
function mstore_internal(pos:i32, y1, y2, y3, y4)
|
||||
{
|
||||
i64.store(pos, endian_swap(y1))
|
||||
i64.store(i64.add(pos, 8), endian_swap(y2))
|
||||
i64.store(i64.add(pos, 16), endian_swap(y3))
|
||||
i64.store(i64.add(pos, 24), endian_swap(y4))
|
||||
i64.store(i32.add(pos, 8:i32), endian_swap(y2))
|
||||
i64.store(i32.add(pos, 16:i32), endian_swap(y3))
|
||||
i64.store(i32.add(pos, 24:i32), endian_swap(y4))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Binary representation:
|
||||
0061736d0100000001160460000060017e017e60057e7e7e7e7e0060027f7f0002190108657468657265756d0c73746f7261676553746f7265000303060500010101020503010001060100071102066d656d6f72790200046d61696e00010ab501052801017e420021002000200020002000200010054220200020002000420110052000a74220a710000b1c01017e20004208864280fe0383200042088842ff018384210120010b1b01027e20001002421086210220022000421088100284210120010b1b01027e20001003422086210220022000422088100384210120010b3501007e2000a720011004370300200042087ca720021004370300200042107ca720031004370300200042187ca7200410043703000b
|
||||
0061736d0100000001160460000060017e017e60057e7e7e7e7e0060027f7f0002190108657468657265756d0c73746f7261676553746f7265000303060500010101020503010001060100071102066d656d6f72790200046d61696e00010abe01052801017e420021004200200020002000200010054220200020002000420110054200a74220a710000b1c01017e20004208864280fe0383200042088842ff018384210120010b1b01027e20001002421086210220022000421088100284210120010b1b01027e20001003422086210220022000422088100384210120010b3e01007e2000a7200110043703002000a74208a76aada7200210043703002000a74210a76aada7200310043703002000a74218a76aada7200410043703000b
|
||||
|
||||
Text representation:
|
||||
(module
|
||||
@ -56,9 +56,9 @@ Text representation:
|
||||
(func $main
|
||||
(local $_1 i64)
|
||||
(local.set $_1 (i64.const 0))
|
||||
(call $mstore_internal (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1))
|
||||
(call $mstore_internal (i64.const 0) (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1))
|
||||
(call $mstore_internal (i64.const 32) (local.get $_1) (local.get $_1) (local.get $_1) (i64.const 1))
|
||||
(call $eth.storageStore (i32.wrap_i64 (local.get $_1)) (i32.wrap_i64 (i64.const 32)))
|
||||
(call $eth.storageStore (i32.wrap_i64 (i64.const 0)) (i32.wrap_i64 (i64.const 32)))
|
||||
)
|
||||
|
||||
(func $endian_swap_16
|
||||
@ -96,9 +96,9 @@ Text representation:
|
||||
(param $y3 i64)
|
||||
(param $y4 i64)
|
||||
(i64.store (i32.wrap_i64 (local.get $pos)) (call $endian_swap (local.get $y1)))
|
||||
(i64.store (i32.wrap_i64 (i64.add (local.get $pos) (i64.const 8))) (call $endian_swap (local.get $y2)))
|
||||
(i64.store (i32.wrap_i64 (i64.add (local.get $pos) (i64.const 16))) (call $endian_swap (local.get $y3)))
|
||||
(i64.store (i32.wrap_i64 (i64.add (local.get $pos) (i64.const 24))) (call $endian_swap (local.get $y4)))
|
||||
(i64.store (i32.wrap_i64 (i64.extend_i32_u (i32.add (i32.wrap_i64 (local.get $pos)) (i32.wrap_i64 (i64.const 8))))) (call $endian_swap (local.get $y2)))
|
||||
(i64.store (i32.wrap_i64 (i64.extend_i32_u (i32.add (i32.wrap_i64 (local.get $pos)) (i32.wrap_i64 (i64.const 16))))) (call $endian_swap (local.get $y3)))
|
||||
(i64.store (i32.wrap_i64 (i64.extend_i32_u (i32.add (i32.wrap_i64 (local.get $pos)) (i32.wrap_i64 (i64.const 24))))) (call $endian_swap (local.get $y4)))
|
||||
)
|
||||
|
||||
)
|
||||
|
@ -10,21 +10,23 @@
|
||||
(local $p i64)
|
||||
(local $r i64)
|
||||
(local $hi i64)
|
||||
(local $y i64)
|
||||
(local $hi_1 i64)
|
||||
(local $y i64)
|
||||
(local $hi_2 i64)
|
||||
(local $_2 i64)
|
||||
(local.set $_1 (i64.const 0))
|
||||
(local.set $p (call $u256_to_i32 (local.get $_1) (local.get $_1) (local.get $_1) (i64.const 64)))
|
||||
(local.set $r (i64.add (local.get $p) (i64.const 64)))
|
||||
(if (i64.ne (i64.extend_i32_u (i64.lt_u (local.get $r) (local.get $p))) (i64.const 0)) (then
|
||||
(local.set $r (i64.extend_i32_u (i32.add (i32.wrap_i64 (local.get $p)) (i32.wrap_i64 (i64.const 64)))))
|
||||
(if (i64.ne (i64.extend_i32_u (i32.lt_u (i32.wrap_i64 (local.get $r)) (i32.wrap_i64 (local.get $p)))) (i64.const 0)) (then
|
||||
(unreachable)))
|
||||
(local.set $hi (i64.shl (i64.or (i64.shl (i64.or (i64.and (i64.shl (local.get $_1) (i64.const 8)) (i64.const 65280)) (i64.and (i64.shr_u (local.get $_1) (i64.const 8)) (i64.const 255))) (i64.const 16)) (call $endian_swap_16 (i64.shr_u (local.get $_1) (i64.const 16)))) (i64.const 32)))
|
||||
(local.set $y (i64.or (local.get $hi) (call $endian_swap_32 (i64.shr_u (local.get $_1) (i64.const 32)))))
|
||||
(local.set $hi (i64.shl (call $endian_swap_16 (local.get $_1)) (i64.const 16)))
|
||||
(local.set $hi_1 (i64.shl (i64.or (local.get $hi) (call $endian_swap_16 (i64.shr_u (local.get $_1) (i64.const 16)))) (i64.const 32)))
|
||||
(local.set $y (i64.or (local.get $hi_1) (call $endian_swap_32 (i64.shr_u (local.get $_1) (i64.const 32)))))
|
||||
(i64.store (i32.wrap_i64 (local.get $r)) (local.get $y))
|
||||
(i64.store (i32.wrap_i64 (i64.add (local.get $r) (i64.const 8))) (local.get $y))
|
||||
(i64.store (i32.wrap_i64 (i64.add (local.get $r) (i64.const 16))) (local.get $y))
|
||||
(local.set $hi_1 (i64.shl (call $endian_swap_32 (i64.const 128)) (i64.const 32)))
|
||||
(i64.store (i32.wrap_i64 (i64.add (local.get $r) (i64.const 24))) (i64.or (local.get $hi_1) (call $endian_swap_32 (i64.shr_u (i64.const 128) (i64.const 32)))))
|
||||
(i64.store (i32.wrap_i64 (i64.extend_i32_u (i32.add (i32.wrap_i64 (local.get $r)) (i32.wrap_i64 (i64.const 8))))) (local.get $y))
|
||||
(i64.store (i32.wrap_i64 (i64.extend_i32_u (i32.add (i32.wrap_i64 (local.get $r)) (i32.wrap_i64 (i64.const 16))))) (local.get $y))
|
||||
(local.set $hi_2 (i64.shl (call $endian_swap_32 (i64.const 128)) (i64.const 32)))
|
||||
(i64.store (i32.wrap_i64 (i64.extend_i32_u (i32.add (i32.wrap_i64 (local.get $r)) (i32.wrap_i64 (i64.const 24))))) (i64.or (local.get $hi_2) (call $endian_swap_32 (i64.shr_u (i64.const 128) (i64.const 32)))))
|
||||
(local.set $_2 (datasize \"C_2_deployed\"))
|
||||
(call $eth.codeCopy (i32.wrap_i64 (call $to_internal_i32ptr (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1))) (i32.wrap_i64 (call $u256_to_i32 (local.get $_1) (local.get $_1) (local.get $_1) (dataoffset \"C_2_deployed\"))) (i32.wrap_i64 (call $u256_to_i32 (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_2))))
|
||||
(call $eth.finish (i32.wrap_i64 (call $to_internal_i32ptr (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1))) (i32.wrap_i64 (call $u256_to_i32 (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_2))))
|
||||
@ -41,7 +43,7 @@
|
||||
(unreachable)))
|
||||
(if (i64.ne (i64.extend_i32_u (i64.ne (i64.const 0) (i64.shr_u (local.get $x4) (i64.const 32)))) (i64.const 0)) (then
|
||||
(unreachable)))
|
||||
(local.set $v (local.get $x4))
|
||||
(local.set $v (i64.extend_i32_u (i32.wrap_i64 (local.get $x4))))
|
||||
(local.get $v)
|
||||
)
|
||||
|
||||
@ -54,8 +56,8 @@
|
||||
(local $r i64)
|
||||
(local $p i64)
|
||||
(local.set $p (call $u256_to_i32 (local.get $x1) (local.get $x2) (local.get $x3) (local.get $x4)))
|
||||
(local.set $r (i64.add (local.get $p) (i64.const 64)))
|
||||
(if (i64.ne (i64.extend_i32_u (i64.lt_u (local.get $r) (local.get $p))) (i64.const 0)) (then
|
||||
(local.set $r (i64.extend_i32_u (i32.add (i32.wrap_i64 (local.get $p)) (i32.wrap_i64 (i64.const 64)))))
|
||||
(if (i64.ne (i64.extend_i32_u (i32.lt_u (i32.wrap_i64 (local.get $r)) (i32.wrap_i64 (local.get $p)))) (i64.const 0)) (then
|
||||
(unreachable)))
|
||||
(local.get $r)
|
||||
)
|
||||
|
@ -93,66 +93,25 @@ u256 EwasmBuiltinInterpreter::evalBuiltin(YulString _fun, vector<u256> const& _a
|
||||
);
|
||||
return 0;
|
||||
}
|
||||
else if (_fun == "drop"_yulstring)
|
||||
else if (_fun == "drop"_yulstring || _fun == "nop"_yulstring)
|
||||
return {};
|
||||
else if (_fun == "i32.wrap_i64"_yulstring)
|
||||
return arg.at(0) & uint32_t(-1);
|
||||
else if (_fun == "i64.extend_i32_u"_yulstring)
|
||||
// Return the same as above because everything is u256 anyway.
|
||||
return arg.at(0) & uint32_t(-1);
|
||||
else if (_fun == "unreachable"_yulstring)
|
||||
{
|
||||
logTrace(evmasm::Instruction::INVALID, {});
|
||||
throw ExplicitlyTerminated();
|
||||
}
|
||||
else if (_fun == "i64.add"_yulstring)
|
||||
return arg[0] + arg[1];
|
||||
else if (_fun == "i64.sub"_yulstring)
|
||||
return arg[0] - arg[1];
|
||||
else if (_fun == "i64.mul"_yulstring)
|
||||
return arg[0] * arg[1];
|
||||
else if (_fun == "i64.div_u"_yulstring)
|
||||
{
|
||||
if (arg[1] == 0)
|
||||
throw ExplicitlyTerminated();
|
||||
else
|
||||
return arg[0] / arg[1];
|
||||
}
|
||||
else if (_fun == "i64.rem_u"_yulstring)
|
||||
{
|
||||
if (arg[1] == 0)
|
||||
throw ExplicitlyTerminated();
|
||||
else
|
||||
return arg[0] % arg[1];
|
||||
}
|
||||
else if (_fun == "i64.and"_yulstring)
|
||||
return arg[0] & arg[1];
|
||||
else if (_fun == "i64.or"_yulstring)
|
||||
return arg[0] | arg[1];
|
||||
else if (_fun == "i64.xor"_yulstring)
|
||||
return arg[0] ^ arg[1];
|
||||
else if (_fun == "i64.shl"_yulstring)
|
||||
return arg[0] << arg[1];
|
||||
else if (_fun == "i64.shr_u"_yulstring)
|
||||
return arg[0] >> arg[1];
|
||||
else if (_fun == "i64.eq"_yulstring)
|
||||
return arg[0] == arg[1] ? 1 : 0;
|
||||
else if (_fun == "i64.ne"_yulstring)
|
||||
return arg[0] != arg[1] ? 1 : 0;
|
||||
else if (_fun == "i64.eqz"_yulstring)
|
||||
return arg[0] == 0 ? 1 : 0;
|
||||
else if (_fun == "i64.clz"_yulstring)
|
||||
return clz(arg[0]);
|
||||
else if (_fun == "i64.lt_u"_yulstring)
|
||||
return arg[0] < arg[1] ? 1 : 0;
|
||||
else if (_fun == "i64.gt_u"_yulstring)
|
||||
return arg[0] > arg[1] ? 1 : 0;
|
||||
else if (_fun == "i64.le_u"_yulstring)
|
||||
return arg[0] <= arg[1] ? 1 : 0;
|
||||
else if (_fun == "i64.ge_u"_yulstring)
|
||||
return arg[0] >= arg[1] ? 1 : 0;
|
||||
else if (_fun == "i64.store"_yulstring)
|
||||
{
|
||||
accessMemory(arg[0], 8);
|
||||
writeMemoryWord(arg[0], arg[1]);
|
||||
return 0;
|
||||
}
|
||||
else if (_fun == "i64.store8"_yulstring)
|
||||
else if (_fun == "i64.store8"_yulstring || _fun == "i32.store8"_yulstring)
|
||||
{
|
||||
accessMemory(arg[0], 1);
|
||||
writeMemoryByte(arg[0], static_cast<uint8_t>(arg[1] & 0xff));
|
||||
@ -163,12 +122,112 @@ u256 EwasmBuiltinInterpreter::evalBuiltin(YulString _fun, vector<u256> const& _a
|
||||
accessMemory(arg[0], 8);
|
||||
return readMemoryWord(arg[0]);
|
||||
}
|
||||
else if (_fun == "eth.getAddress"_yulstring)
|
||||
else if (_fun == "i32.store"_yulstring)
|
||||
{
|
||||
accessMemory(arg[0], 4);
|
||||
writeMemoryHalfWord(arg[0], arg[1]);
|
||||
return 0;
|
||||
}
|
||||
else if (_fun == "i32.load"_yulstring)
|
||||
{
|
||||
accessMemory(arg[0], 4);
|
||||
return readMemoryHalfWord(arg[0]);
|
||||
}
|
||||
|
||||
|
||||
string prefix = _fun.str();
|
||||
string suffix;
|
||||
auto dot = prefix.find(".");
|
||||
if (dot != string::npos)
|
||||
{
|
||||
suffix = prefix.substr(dot + 1);
|
||||
prefix.resize(dot);
|
||||
}
|
||||
|
||||
if (prefix == "i32")
|
||||
{
|
||||
vector<uint32_t> halfWordArgs;
|
||||
for (uint64_t a: arg)
|
||||
halfWordArgs.push_back(uint32_t(a & uint32_t(-1)));
|
||||
return evalWasmBuiltin(suffix, halfWordArgs);
|
||||
}
|
||||
else if (prefix == "i64")
|
||||
return evalWasmBuiltin(suffix, arg);
|
||||
else if (prefix == "eth")
|
||||
return evalEthBuiltin(suffix, arg);
|
||||
|
||||
yulAssert(false, "Unknown builtin: " + _fun.str() + " (or implementation did not return)");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <typename Word>
|
||||
u256 EwasmBuiltinInterpreter::evalWasmBuiltin(string const& _fun, vector<Word> const& _arguments)
|
||||
{
|
||||
vector<Word> const& arg = _arguments;
|
||||
|
||||
if (_fun == "add")
|
||||
return arg[0] + arg[1];
|
||||
else if (_fun == "sub")
|
||||
return arg[0] - arg[1];
|
||||
else if (_fun == "mul")
|
||||
return arg[0] * arg[1];
|
||||
else if (_fun == "div_u")
|
||||
{
|
||||
if (arg[1] == 0)
|
||||
throw ExplicitlyTerminated();
|
||||
else
|
||||
return arg[0] / arg[1];
|
||||
}
|
||||
else if (_fun == "rem_u")
|
||||
{
|
||||
if (arg[1] == 0)
|
||||
throw ExplicitlyTerminated();
|
||||
else
|
||||
return arg[0] % arg[1];
|
||||
}
|
||||
else if (_fun == "and")
|
||||
return arg[0] & arg[1];
|
||||
else if (_fun == "or")
|
||||
return arg[0] | arg[1];
|
||||
else if (_fun == "xor")
|
||||
return arg[0] ^ arg[1];
|
||||
else if (_fun == "shl")
|
||||
return arg[0] << arg[1];
|
||||
else if (_fun == "shr_u")
|
||||
return arg[0] >> arg[1];
|
||||
else if (_fun == "eq")
|
||||
return arg[0] == arg[1] ? 1 : 0;
|
||||
else if (_fun == "ne")
|
||||
return arg[0] != arg[1] ? 1 : 0;
|
||||
else if (_fun == "eqz")
|
||||
return arg[0] == 0 ? 1 : 0;
|
||||
else if (_fun == "clz")
|
||||
return clz(arg[0]);
|
||||
else if (_fun == "lt_u")
|
||||
return arg[0] < arg[1] ? 1 : 0;
|
||||
else if (_fun == "gt_u")
|
||||
return arg[0] > arg[1] ? 1 : 0;
|
||||
else if (_fun == "le_u")
|
||||
return arg[0] <= arg[1] ? 1 : 0;
|
||||
else if (_fun == "ge_u")
|
||||
return arg[0] >= arg[1] ? 1 : 0;
|
||||
|
||||
yulAssert(false, "Unknown builtin: " + _fun + " (or implementation did not return)");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u256 EwasmBuiltinInterpreter::evalEthBuiltin(string const& _fun, vector<uint64_t> const& _arguments)
|
||||
{
|
||||
vector<uint64_t> const& arg = _arguments;
|
||||
|
||||
if (_fun == "getAddress")
|
||||
{
|
||||
writeAddress(arg[0], m_state.address);
|
||||
return 0;
|
||||
}
|
||||
else if (_fun == "eth.getExternalBalance"_yulstring)
|
||||
else if (_fun == "getExternalBalance")
|
||||
{
|
||||
// TODO this does not read the address, but is consistent with
|
||||
// EVM interpreter implementation.
|
||||
@ -176,7 +235,7 @@ u256 EwasmBuiltinInterpreter::evalBuiltin(YulString _fun, vector<u256> const& _a
|
||||
writeU128(arg[1], m_state.balance);
|
||||
return 0;
|
||||
}
|
||||
else if (_fun == "eth.getBlockHash"_yulstring)
|
||||
else if (_fun == "getBlockHash")
|
||||
{
|
||||
if (arg[0] >= m_state.blockNumber || arg[0] + 256 < m_state.blockNumber)
|
||||
return 1;
|
||||
@ -186,14 +245,14 @@ u256 EwasmBuiltinInterpreter::evalBuiltin(YulString _fun, vector<u256> const& _a
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else if (_fun == "eth.call"_yulstring)
|
||||
else if (_fun == "call")
|
||||
{
|
||||
// TODO read args from memory
|
||||
// TODO use readAddress to read address.
|
||||
logTrace(evmasm::Instruction::CALL, {});
|
||||
return arg[0] & 1;
|
||||
}
|
||||
else if (_fun == "eth.callDataCopy"_yulstring)
|
||||
else if (_fun == "callDataCopy")
|
||||
{
|
||||
if (arg[1] + arg[2] < arg[1] || arg[1] + arg[2] > m_state.calldata.size())
|
||||
throw ExplicitlyTerminated();
|
||||
@ -204,51 +263,51 @@ u256 EwasmBuiltinInterpreter::evalBuiltin(YulString _fun, vector<u256> const& _a
|
||||
);
|
||||
return {};
|
||||
}
|
||||
else if (_fun == "eth.getCallDataSize"_yulstring)
|
||||
else if (_fun == "getCallDataSize")
|
||||
return m_state.calldata.size();
|
||||
else if (_fun == "eth.callCode"_yulstring)
|
||||
else if (_fun == "callCode")
|
||||
{
|
||||
// TODO read args from memory
|
||||
// TODO use readAddress to read address.
|
||||
logTrace(evmasm::Instruction::CALLCODE, {});
|
||||
return arg[0] & 1;
|
||||
}
|
||||
else if (_fun == "eth.callDelegate"_yulstring)
|
||||
else if (_fun == "callDelegate")
|
||||
{
|
||||
// TODO read args from memory
|
||||
// TODO use readAddress to read address.
|
||||
logTrace(evmasm::Instruction::DELEGATECALL, {});
|
||||
return arg[0] & 1;
|
||||
}
|
||||
else if (_fun == "eth.callStatic"_yulstring)
|
||||
else if (_fun == "callStatic")
|
||||
{
|
||||
// TODO read args from memory
|
||||
// TODO use readAddress to read address.
|
||||
logTrace(evmasm::Instruction::STATICCALL, {});
|
||||
return arg[0] & 1;
|
||||
}
|
||||
else if (_fun == "eth.storageStore"_yulstring)
|
||||
else if (_fun == "storageStore")
|
||||
{
|
||||
m_state.storage[h256(readU256(arg[0]))] = readU256((arg[1]));
|
||||
return 0;
|
||||
}
|
||||
else if (_fun == "eth.storageLoad"_yulstring)
|
||||
else if (_fun == "storageLoad")
|
||||
{
|
||||
writeU256(arg[1], m_state.storage[h256(readU256(arg[0]))]);
|
||||
return 0;
|
||||
}
|
||||
else if (_fun == "eth.getCaller"_yulstring)
|
||||
else if (_fun == "getCaller")
|
||||
{
|
||||
// TODO should this only write 20 bytes?
|
||||
writeAddress(arg[0], m_state.caller);
|
||||
return 0;
|
||||
}
|
||||
else if (_fun == "eth.getCallValue"_yulstring)
|
||||
else if (_fun == "getCallValue")
|
||||
{
|
||||
writeU128(arg[0], m_state.callvalue);
|
||||
return 0;
|
||||
}
|
||||
else if (_fun == "eth.codeCopy"_yulstring)
|
||||
else if (_fun == "codeCopy")
|
||||
{
|
||||
if (accessMemory(arg[0], arg[2]))
|
||||
copyZeroExtended(
|
||||
@ -257,26 +316,26 @@ u256 EwasmBuiltinInterpreter::evalBuiltin(YulString _fun, vector<u256> const& _a
|
||||
);
|
||||
return 0;
|
||||
}
|
||||
else if (_fun == "eth.getCodeSize"_yulstring)
|
||||
else if (_fun == "getCodeSize")
|
||||
return m_state.code.size();
|
||||
else if (_fun == "eth.getBlockCoinbase"_yulstring)
|
||||
else if (_fun == "getBlockCoinbase")
|
||||
{
|
||||
writeAddress(arg[0], m_state.coinbase);
|
||||
return 0;
|
||||
}
|
||||
else if (_fun == "eth.create"_yulstring)
|
||||
else if (_fun == "create")
|
||||
{
|
||||
// TODO access memory
|
||||
// TODO use writeAddress to store resulting address
|
||||
logTrace(evmasm::Instruction::CREATE, {});
|
||||
return 0xcccccc + arg[1];
|
||||
}
|
||||
else if (_fun == "eth.getBlockDifficulty"_yulstring)
|
||||
else if (_fun == "getBlockDifficulty")
|
||||
{
|
||||
writeU256(arg[0], m_state.difficulty);
|
||||
return 0;
|
||||
}
|
||||
else if (_fun == "eth.externalCodeCopy"_yulstring)
|
||||
else if (_fun == "externalCodeCopy")
|
||||
{
|
||||
// TODO use readAddress to read address.
|
||||
if (accessMemory(arg[1], arg[3]))
|
||||
@ -287,19 +346,19 @@ u256 EwasmBuiltinInterpreter::evalBuiltin(YulString _fun, vector<u256> const& _a
|
||||
);
|
||||
return 0;
|
||||
}
|
||||
else if (_fun == "eth.getExternalCodeSize"_yulstring)
|
||||
else if (_fun == "getExternalCodeSize")
|
||||
// Generate "random" code length. Make sure it fits the page size.
|
||||
return u256(keccak256(h256(readAddress(arg[0])))) & 0xfff;
|
||||
else if (_fun == "eth.getGasLeft"_yulstring)
|
||||
else if (_fun == "getGasLeft")
|
||||
return 0x99;
|
||||
else if (_fun == "eth.getBlockGasLimit"_yulstring)
|
||||
else if (_fun == "getBlockGasLimit")
|
||||
return uint64_t(m_state.gaslimit);
|
||||
else if (_fun == "eth.getTxGasPrice"_yulstring)
|
||||
else if (_fun == "getTxGasPrice")
|
||||
{
|
||||
writeU128(arg[0], m_state.gasprice);
|
||||
return 0;
|
||||
}
|
||||
else if (_fun == "eth.log"_yulstring)
|
||||
else if (_fun == "log")
|
||||
{
|
||||
uint64_t numberOfTopics = arg[2];
|
||||
if (numberOfTopics > 4)
|
||||
@ -307,14 +366,14 @@ u256 EwasmBuiltinInterpreter::evalBuiltin(YulString _fun, vector<u256> const& _a
|
||||
logTrace(evmasm::logInstruction(numberOfTopics), {});
|
||||
return 0;
|
||||
}
|
||||
else if (_fun == "eth.getBlockNumber"_yulstring)
|
||||
else if (_fun == "getBlockNumber")
|
||||
return m_state.blockNumber;
|
||||
else if (_fun == "eth.getTxOrigin"_yulstring)
|
||||
else if (_fun == "getTxOrigin")
|
||||
{
|
||||
writeAddress(arg[0], m_state.origin);
|
||||
return 0;
|
||||
}
|
||||
else if (_fun == "eth.finish"_yulstring)
|
||||
else if (_fun == "finish")
|
||||
{
|
||||
bytes data;
|
||||
if (accessMemory(arg[0], arg[1]))
|
||||
@ -322,7 +381,7 @@ u256 EwasmBuiltinInterpreter::evalBuiltin(YulString _fun, vector<u256> const& _a
|
||||
logTrace(evmasm::Instruction::RETURN, {}, data);
|
||||
throw ExplicitlyTerminated();
|
||||
}
|
||||
else if (_fun == "eth.revert"_yulstring)
|
||||
else if (_fun == "revert")
|
||||
{
|
||||
bytes data;
|
||||
if (accessMemory(arg[0], arg[1]))
|
||||
@ -330,9 +389,9 @@ u256 EwasmBuiltinInterpreter::evalBuiltin(YulString _fun, vector<u256> const& _a
|
||||
logTrace(evmasm::Instruction::REVERT, {}, data);
|
||||
throw ExplicitlyTerminated();
|
||||
}
|
||||
else if (_fun == "eth.getReturnDataSize"_yulstring)
|
||||
else if (_fun == "getReturnDataSize")
|
||||
return m_state.returndata.size();
|
||||
else if (_fun == "eth.returnDataCopy"_yulstring)
|
||||
else if (_fun == "returnDataCopy")
|
||||
{
|
||||
if (arg[1] + arg[2] < arg[1] || arg[1] + arg[2] > m_state.returndata.size())
|
||||
throw ExplicitlyTerminated();
|
||||
@ -343,16 +402,16 @@ u256 EwasmBuiltinInterpreter::evalBuiltin(YulString _fun, vector<u256> const& _a
|
||||
);
|
||||
return {};
|
||||
}
|
||||
else if (_fun == "eth.selfDestruct"_yulstring)
|
||||
else if (_fun == "selfDestruct")
|
||||
{
|
||||
// TODO use readAddress to read address.
|
||||
logTrace(evmasm::Instruction::SELFDESTRUCT, {});
|
||||
throw ExplicitlyTerminated();
|
||||
}
|
||||
else if (_fun == "eth.getBlockTimestamp"_yulstring)
|
||||
else if (_fun == "getBlockTimestamp")
|
||||
return m_state.timestamp;
|
||||
|
||||
yulAssert(false, "Unknown builtin: " + _fun.str() + " (or implementation did not return)");
|
||||
yulAssert(false, "Unknown builtin: " + _fun + " (or implementation did not return)");
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -388,12 +447,26 @@ uint64_t EwasmBuiltinInterpreter::readMemoryWord(uint64_t _offset)
|
||||
return r;
|
||||
}
|
||||
|
||||
uint32_t EwasmBuiltinInterpreter::readMemoryHalfWord(uint64_t _offset)
|
||||
{
|
||||
uint32_t r = 0;
|
||||
for (size_t i = 0; i < 4; i++)
|
||||
r |= uint64_t(m_state.memory[_offset + i]) << (i * 8);
|
||||
return r;
|
||||
}
|
||||
|
||||
void EwasmBuiltinInterpreter::writeMemoryWord(uint64_t _offset, uint64_t _value)
|
||||
{
|
||||
for (size_t i = 0; i < 8; i++)
|
||||
m_state.memory[_offset + i] = uint8_t((_value >> (i * 8)) & 0xff);
|
||||
}
|
||||
|
||||
void EwasmBuiltinInterpreter::writeMemoryHalfWord(uint64_t _offset, uint32_t _value)
|
||||
{
|
||||
for (size_t i = 0; i < 4; i++)
|
||||
m_state.memory[_offset + i] = uint8_t((_value >> (i * 8)) & 0xff);
|
||||
}
|
||||
|
||||
void EwasmBuiltinInterpreter::writeMemoryByte(uint64_t _offset, uint8_t _value)
|
||||
{
|
||||
m_state.memory[_offset] = _value;
|
||||
|
@ -71,6 +71,16 @@ public:
|
||||
u256 evalBuiltin(YulString _fun, std::vector<u256> const& _arguments);
|
||||
|
||||
private:
|
||||
template <typename Word>
|
||||
u256 evalWasmBuiltin(
|
||||
std::string const& _fun,
|
||||
std::vector<Word> const& _arguments
|
||||
);
|
||||
u256 evalEthBuiltin(
|
||||
std::string const& _fun,
|
||||
std::vector<uint64_t> const& _arguments
|
||||
);
|
||||
|
||||
/// Checks if the memory access is not too large for the interpreter and adjusts
|
||||
/// msize accordingly.
|
||||
/// @returns false if the amount of bytes read is lager than 0xffff
|
||||
@ -78,12 +88,18 @@ private:
|
||||
/// @returns the memory contents at the provided address.
|
||||
/// Does not adjust msize, use @a accessMemory for that
|
||||
bytes readMemory(uint64_t _offset, uint64_t _size = 32);
|
||||
/// @returns the memory contents at the provided address (little-endian).
|
||||
/// @returns the memory contents (8 bytes) at the provided address (little-endian).
|
||||
/// Does not adjust msize, use @a accessMemory for that
|
||||
uint64_t readMemoryWord(uint64_t _offset);
|
||||
/// @returns the memory contents (4 bytes) at the provided address (little-endian).
|
||||
/// Does not adjust msize, use @a accessMemory for that
|
||||
uint32_t readMemoryHalfWord(uint64_t _offset);
|
||||
/// Writes a word to memory (little-endian)
|
||||
/// Does not adjust msize, use @a accessMemory for that
|
||||
void writeMemoryWord(uint64_t _offset, uint64_t _value);
|
||||
/// Writes a 4-byte value to memory (little-endian)
|
||||
/// Does not adjust msize, use @a accessMemory for that
|
||||
void writeMemoryHalfWord(uint64_t _offset, uint32_t _value);
|
||||
/// Writes a byte to memory
|
||||
/// Does not adjust msize, use @a accessMemory for that
|
||||
void writeMemoryByte(uint64_t _offset, uint8_t _value);
|
||||
|
Loading…
Reference in New Issue
Block a user