Initial EVM1.5 assembly implementation.

This commit is contained in:
chriseth
2017-06-08 15:52:44 +02:00
parent 21e0b69dcb
commit 97cc968a13
20 changed files with 907 additions and 189 deletions
+3 -1
View File
@@ -21,11 +21,13 @@
#include "../TestHelper.h"
#include <test/libsolidity/ErrorCheck.h>
#include <libsolidity/inlineasm/AsmParser.h>
#include <libsolidity/inlineasm/AsmAnalysis.h>
#include <libsolidity/inlineasm/AsmAnalysisInfo.h>
#include <libsolidity/parsing/Scanner.h>
#include <test/libsolidity/ErrorCheck.h>
#include <libsolidity/interface/ErrorReporter.h>
#include <boost/optional.hpp>
#include <boost/algorithm/string/replace.hpp>
+36
View File
@@ -481,6 +481,42 @@ BOOST_AUTO_TEST_CASE(revert)
BOOST_CHECK(successAssemble("{ revert(0, 0) }"));
}
BOOST_AUTO_TEST_CASE(function_calls)
{
BOOST_CHECK(successAssemble("{ function f() {} }"));
BOOST_CHECK(successAssemble("{ function f() { let y := 2 } }"));
BOOST_CHECK(successAssemble("{ function f() -> z { let y := 2 } }"));
BOOST_CHECK(successAssemble("{ function f(a) { let y := 2 } }"));
BOOST_CHECK(successAssemble("{ function f(a) { let y := a } }"));
BOOST_CHECK(successAssemble("{ function f() -> x, y, z {} }"));
BOOST_CHECK(successAssemble("{ function f(x, y, z) {} }"));
BOOST_CHECK(successAssemble("{ function f(a, b) -> x, y, z { y := a } }"));
BOOST_CHECK(successAssemble("{ function f() {} f() }"));
BOOST_CHECK(successAssemble("{ function f() -> x, y { x := 1 y := 2} let a, b := f() }"));
BOOST_CHECK(successAssemble("{ function f(a, b) -> x, y { x := b y := a } let a, b := f(2, 3) }"));
BOOST_CHECK(successAssemble("{ function rec(a) { rec(sub(a, 1)) } rec(2) }"));
BOOST_CHECK(successAssemble("{ let r := 2 function f() -> x, y { x := 1 y := 2} let a, b := f() b := r }"));
}
BOOST_AUTO_TEST_CASE(switch_statement)
{
BOOST_CHECK(successAssemble("{ switch 1 default {} }"));
BOOST_CHECK(successAssemble("{ switch 1 case 1 {} default {} }"));
BOOST_CHECK(successAssemble("{ switch 1 case 1 {} }"));
BOOST_CHECK(successAssemble("{ let a := 3 switch a case 1 { a := 1 } case 2 { a := 5 } a := 9}"));
BOOST_CHECK(successAssemble("{ let a := 2 switch calldataload(0) case 1 { a := 1 } case 2 { a := 5 } }"));
}
BOOST_AUTO_TEST_CASE(large_constant)
{
auto source = R"({
switch mul(1, 2)
case 0x0000000000000000000000000000000000000000000000000000000026121ff0 {
}
})";
BOOST_CHECK(successAssemble(source));
}
BOOST_AUTO_TEST_CASE(keccak256)
{
BOOST_CHECK(successAssemble("{ 0 0 keccak256 pop }"));
+96
View File
@@ -7535,6 +7535,102 @@ BOOST_AUTO_TEST_CASE(inline_assembly_function_access)
BOOST_CHECK(callContractFunction("x()") == encodeArgs(u256(10)));
}
BOOST_AUTO_TEST_CASE(inline_assembly_function_call)
{
char const* sourceCode = R"(
contract C {
function f() {
assembly {
function asmfun(a, b, c) -> x, y, z {
x := a
y := b
z := 7
}
let a1, b1, c1 := asmfun(1, 2, 3)
mstore(0x00, a1)
mstore(0x20, b1)
mstore(0x40, c1)
return(0, 0x60)
}
}
}
)";
compileAndRun(sourceCode, 0, "C");
BOOST_CHECK(callContractFunction("f()") == encodeArgs(u256(1), u256(2), u256(7)));
}
BOOST_AUTO_TEST_CASE(inline_assembly_function_call2)
{
char const* sourceCode = R"(
contract C {
function f() {
assembly {
let d := 0x10
function asmfun(a, b, c) -> x, y, z {
x := a
y := b
z := 7
}
let a1, b1, c1 := asmfun(1, 2, 3)
mstore(0x00, a1)
mstore(0x20, b1)
mstore(0x40, c1)
mstore(0x60, d)
return(0, 0x80)
}
}
}
)";
compileAndRun(sourceCode, 0, "C");
BOOST_CHECK(callContractFunction("f()") == encodeArgs(u256(1), u256(2), u256(7), u256(0x10)));
}
BOOST_AUTO_TEST_CASE(inline_assembly_switch)
{
char const* sourceCode = R"(
contract C {
function f(uint a) returns (uint b) {
assembly {
switch a
case 1 { b := 8 }
case 2 { b := 9 }
default { b := 2 }
}
}
}
)";
compileAndRun(sourceCode, 0, "C");
BOOST_CHECK(callContractFunction("f(uint256)", u256(0)) == encodeArgs(u256(2)));
BOOST_CHECK(callContractFunction("f(uint256)", u256(1)) == encodeArgs(u256(8)));
BOOST_CHECK(callContractFunction("f(uint256)", u256(2)) == encodeArgs(u256(9)));
BOOST_CHECK(callContractFunction("f(uint256)", u256(3)) == encodeArgs(u256(2)));
}
BOOST_AUTO_TEST_CASE(inline_assembly_recursion)
{
char const* sourceCode = R"(
contract C {
function f(uint a) returns (uint b) {
assembly {
function fac(n) -> nf {
switch n
case 0 { nf := 1 }
case 1 { nf := 1 }
default { nf := mul(n, fac(sub(n, 1))) }
}
b := fac(a)
}
}
}
)";
compileAndRun(sourceCode, 0, "C");
BOOST_CHECK(callContractFunction("f(uint256)", u256(0)) == encodeArgs(u256(1)));
BOOST_CHECK(callContractFunction("f(uint256)", u256(1)) == encodeArgs(u256(1)));
BOOST_CHECK(callContractFunction("f(uint256)", u256(2)) == encodeArgs(u256(2)));
BOOST_CHECK(callContractFunction("f(uint256)", u256(3)) == encodeArgs(u256(6)));
BOOST_CHECK(callContractFunction("f(uint256)", u256(4)) == encodeArgs(u256(24)));
}
BOOST_AUTO_TEST_CASE(index_access_with_type_conversion)
{
// Test for a bug where higher order bits cleanup was not done for array index access.
@@ -5159,6 +5159,21 @@ BOOST_AUTO_TEST_CASE(inline_assembly_constant_access)
CHECK_ERROR(text, TypeError, "Constant variables not supported by inline assembly");
}
BOOST_AUTO_TEST_CASE(inline_assembly_variable_access_out_of_functions)
{
char const* text = R"(
contract test {
function f() {
uint a;
assembly {
function g() -> x { x := a }
}
}
}
)";
CHECK_ERROR(text, DeclarationError, "Inline assembly functions cannot access their outer scope.");
}
BOOST_AUTO_TEST_CASE(invalid_mobile_type)
{
char const* text = R"(