Skip to content

Commit

Permalink
Merge pull request #327 from ethereum/32-bit
Browse files Browse the repository at this point in the history
Add support for 32-bit architectures
  • Loading branch information
chfast authored Jun 27, 2019
2 parents a6a98d1 + 4a8de9e commit f905aa8
Show file tree
Hide file tree
Showing 6 changed files with 71 additions and 23 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
E.g. `./modules/vm.so,engine=compiler,trace,verbosity=2`.
A VM can be loaded, created and configured atomically with
new `evmc_load_and_configure()` function.
- Added: [[#327](https://github.com/ethereum/evmc/pull/327)]
Full support for 32-bit architectures has been added.
- Changed: [[#293](https://github.com/ethereum/evmc/pull/293)]
In C++ API `evmc::result::raw()` renamed to `evmc::result::release_raw()`.
- Changed: [[#311](https://github.com/ethereum/evmc/pull/311)]
Expand Down
4 changes: 3 additions & 1 deletion appveyor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@ configuration:
- Release
environment:
matrix:
- VS: 2015
- VS: 2017
- VS: 2017-32bit
- VS: 2015
- GO: true
cache:
- C:\.hunter\_Base\Cache -> cmake\Hunter\init.cmake
Expand All @@ -20,6 +21,7 @@ before_build:
# Add ninja to PATH. This is done for VS2017 by vsdevcmd, but not for VS2015.
- set PATH=%PATH%;%ProgramFiles(x86)%\Microsoft Visual Studio\2017\Community\Common7\IDE\CommonExtensions\Microsoft\CMake\Ninja
- if "%VS%" == "2017" (call "%ProgramFiles(x86)%\Microsoft Visual Studio\2017\Community\Common7\Tools\vsdevcmd" -arch=amd64)
- if "%VS%" == "2017-32bit" (call "%ProgramFiles(x86)%\Microsoft Visual Studio\2017\Community\Common7\Tools\vsdevcmd" -arch=x86)
- if "%VS%" == "2015" (call "%ProgramFiles(x86)%\Microsoft Visual Studio 14.0\VC\vcvarsall" x64)
- if defined VS cmake -S . -B build -G Ninja -Wno-dev -DCMAKE_INSTALL_PREFIX=C:\install -DTOOLCHAIN=cxx17-pic -DEVMC_TESTING=ON

Expand Down
11 changes: 11 additions & 0 deletions circle.yml
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,16 @@ jobs:
steps:
- build_and_test

build-32bit:
executor: linux
environment:
CMAKE_OPTIONS: -DTOOLCHAIN=cxx11-32bit
steps:
- run:
name: "Install GCC 32-bit"
command: sudo apt -q update && sudo apt -qy install g++-multilib
- build_and_test

bindings-go-latest:
docker:
- image: circleci/golang
Expand Down Expand Up @@ -225,6 +235,7 @@ workflows:
- build-cxx14-asan
- build-gcc6
- build-clang38
- build-32bit
- bindings-go-latest
- bindings-go-min
- bindings-rust:
Expand Down
48 changes: 36 additions & 12 deletions include/evmc/helpers.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,17 +53,43 @@ inline bool is_zero(const evmc_bytes32& x) noexcept
return x == evmc_bytes32{};
}

/// FNV1a hash function with 64-bit result.
inline uint64_t fnv1a_64(const uint8_t* ptr, size_t len)
/// Parameters for the fnv1a hash function, specialized by the hash result size (size_t).
///
/// The values for the matching size are taken from
/// https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function#FNV_hash_parameters.
///
/// @tparam size The size of the hash result (size_t).
template <size_t size>
struct fnv1_params
{
constexpr uint64_t prime = 1099511628211ULL;
constexpr uint64_t offset_basis = 14695981039346656037ULL;
};

/// Parameters for the fnv1a hash function, specialized for the hash result of 4 bytes.
template <>
struct fnv1_params<4>
{
static constexpr auto prime = 0x1000193; ///< The FNV prime.
static constexpr auto offset_basis = 0x811c9dc5; ///< The FNV offset basis.
};

/// Parameters for the fnv1a hash function, specialized for the hash result of 8 bytes.
template <>
struct fnv1_params<8>
{
static constexpr auto prime = 0x100000001b3; ///< The FNV prime.
static constexpr auto offset_basis = 0xcbf29ce484222325; ///< The FNV offset basis.
};

/// FNV1a hash function.
inline size_t fnv1a(const uint8_t* ptr, size_t len) noexcept
{
using params = fnv1_params<sizeof(size_t)>;

uint64_t ret = offset_basis;
auto ret = size_t{params::offset_basis};
for (size_t i = 0; i < len; i++)
{
ret ^= ptr[i];
ret *= prime;
ret *= params::prime;
}
return ret;
}
Expand All @@ -75,10 +101,9 @@ template <>
struct hash<evmc_address>
{
/// Hash operator using FNV1a.
std::enable_if<sizeof(size_t) == 8, std::size_t>::type operator()(const evmc_address& s) const
noexcept
size_t operator()(const evmc_address& s) const noexcept
{
return fnv1a_64(s.bytes, sizeof(s.bytes));
return fnv1a(s.bytes, sizeof(s.bytes));
}
};

Expand All @@ -87,10 +112,9 @@ template <>
struct hash<evmc_bytes32>
{
/// Hash operator using FNV1a.
std::enable_if<sizeof(size_t) == 8, std::size_t>::type operator()(const evmc_bytes32& s) const
noexcept
size_t operator()(const evmc_bytes32& s) const noexcept
{
return fnv1a_64(s.bytes, sizeof(s.bytes));
return fnv1a(s.bytes, sizeof(s.bytes));
}
};
} // namespace std
Expand Down
13 changes: 11 additions & 2 deletions test/unittests/test_helpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ static_assert(sizeof(evmc_bytes32) == 32, "evmc_bytes32 is too big");
static_assert(sizeof(evmc_address) == 20, "evmc_address is too big");
static_assert(sizeof(evmc_result) <= 64, "evmc_result does not fit cache line");
static_assert(sizeof(evmc_instance) <= 64, "evmc_instance does not fit cache line");
static_assert(offsetof(evmc_message, value) % 8 == 0, "evmc_message.value not aligned");
static_assert(offsetof(evmc_message, value) % sizeof(size_t) == 0,
"evmc_message.value not aligned");

// Check enums match int size.
// On GCC/clang the underlying type should be unsigned int, on MSVC int
Expand All @@ -27,9 +28,17 @@ static_assert(sizeof(evmc_revision) == sizeof(int), "Enum `evmc_revision` is not

static constexpr size_t optionalDataSize =
sizeof(evmc_result) - offsetof(evmc_result, create_address);
static_assert(optionalDataSize == sizeof(evmc_result_optional_storage), "");
static_assert(optionalDataSize >= sizeof(evmc_result_optional_storage),
"evmc_result's optional data space is too small");


TEST(helpers, fnv1a)
{
const uint8_t text[] = {'E', 'V', 'M', 'C'};
const auto h = fnv1a(text, sizeof(text));
EXPECT_EQ(h, sizeof(size_t) == 8 ? 0x15e05d6d22fed89a : 0xffaa6a9a);
}

TEST(helpers, maps)
{
std::map<evmc_address, bool> addresses;
Expand Down
16 changes: 8 additions & 8 deletions test/vmtester/tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,13 @@ TEST_F(evmc_vm_test, abi_version_match)
TEST_F(evmc_vm_test, name)
{
ASSERT_TRUE(vm->name != nullptr);
EXPECT_GT(std::strlen(vm->name), 0) << "VM name cannot be empty";
EXPECT_NE(std::strlen(vm->name), size_t{0}) << "VM name cannot be empty";
}

TEST_F(evmc_vm_test, version)
{
ASSERT_TRUE(vm->version != nullptr);
EXPECT_GT(std::strlen(vm->version), 0) << "VM name cannot be empty";
EXPECT_NE(std::strlen(vm->version), size_t{0}) << "VM version cannot be empty";
}

TEST_F(evmc_vm_test, capabilities)
Expand All @@ -69,13 +69,13 @@ TEST_F(evmc_vm_test, execute_call)
EXPECT_EQ(result.gas_left, 0);
}

if (result.output_data == NULL)
if (result.output_data == nullptr)
{
EXPECT_EQ(result.output_size, 0);
}
else
{
EXPECT_NE(result.output_size, 0);
EXPECT_NE(result.output_size, size_t{0});
read_buffer(result.output_data, result.output_size);
}

Expand Down Expand Up @@ -110,7 +110,7 @@ TEST_F(evmc_vm_test, execute_create)
}
else
{
EXPECT_NE(result.output_size, 0);
EXPECT_NE(result.output_size, size_t{0});
read_buffer(result.output_data, result.output_size);
}

Expand Down Expand Up @@ -184,7 +184,7 @@ TEST_F(evmc_vm_test, precompile_test)
destination.bytes[19] = static_cast<uint8_t>(i & 0xff);

evmc_message msg{
EVMC_CALL, 0, 0, 65536, destination, evmc_address{}, NULL, 0, evmc_uint256be{},
EVMC_CALL, 0, 0, 65536, destination, evmc_address{}, nullptr, 0, evmc_uint256be{},
evmc_bytes32{}};

evmc_result result = vm->execute(vm, nullptr, EVMC_MAX_REVISION, &msg, nullptr, 0);
Expand All @@ -201,13 +201,13 @@ TEST_F(evmc_vm_test, precompile_test)
EXPECT_EQ(result.gas_left, 0);
}

if (result.output_data == NULL)
if (result.output_data == nullptr)
{
EXPECT_EQ(result.output_size, 0);
}
else
{
EXPECT_NE(result.output_size, 0);
EXPECT_NE(result.output_size, size_t{0});
read_buffer(result.output_data, result.output_size);
}

Expand Down

0 comments on commit f905aa8

Please sign in to comment.