Browse Source

Merge branch 'develop-evmcc' of github.com:imapp-pl/ethereum into develop-evmcc

Conflicts:
	libevmjit/Compiler.cpp
cl-refactor
artur-zawlocki 10 years ago
parent
commit
0e0032e6ef
  1. 2
      libdevcore/Exceptions.h
  2. 6
      libethereum/Account.cpp
  3. 190
      libethereum/Account.h
  4. 94
      libethereum/AddressState.h
  5. 2
      libethereum/All.h
  6. 6
      libethereum/BlockChain.cpp
  7. 4
      libethereum/BlockChain.h
  8. 2
      libethereum/Executive.cpp
  9. 2
      libethereum/ExtVM.h
  10. 32
      libethereum/State.cpp
  11. 20
      libethereum/State.h
  12. 11
      libevmjit/Compiler.cpp
  13. 50
      libevmjit/Memory.cpp
  14. 4
      libevmjit/Memory.h
  15. 4
      libevmjit/Type.cpp
  16. 2
      libevmjit/Type.h
  17. 2
      test/vm.cpp
  18. 4
      windows/LibEthereum.vcxproj
  19. 12
      windows/LibEthereum.vcxproj.filters

2
libdevcore/Exceptions.h

@ -44,6 +44,6 @@ struct FileError: virtual Exception {};
// error information to be added to exceptions
typedef boost::error_info<struct tag_invalidSymbol, char> errinfo_invalidSymbol;
typedef boost::error_info<struct tag_comment, std::string> errinfo_wrongAddress;
typedef boost::error_info<struct tag_address, std::string> errinfo_wrongAddress;
typedef boost::error_info<struct tag_comment, std::string> errinfo_comment;
}

6
libethereum/AddressState.cpp → libethereum/Account.cpp

@ -14,17 +14,17 @@
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file AddressState.cpp
/** @file Account.cpp
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#include "AddressState.h"
#include "Account.h"
#include <libethcore/CommonEth.h>
using namespace std;
using namespace dev;
using namespace dev::eth;
#pragma GCC diagnostic ignored "-Wunused-variable"
namespace { char dummy; };
const h256 Account::c_contractConceptionCodeHash;

190
libethereum/Account.h

@ -0,0 +1,190 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file Account.h
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#pragma once
#include <libdevcore/Common.h>
#include <libdevcore/RLP.h>
#include <libdevcrypto/TrieDB.h>
#include <libdevcrypto/SHA3.h>
namespace dev
{
namespace eth
{
/**
* Models the state of a single Ethereum account.
* Used to cache a portion of the full Ethereum state. State keeps a mapping of Address's to Accounts.
*
* Aside from storing the nonce and balance, the account may also be "dead" (where isAlive() returns false).
* This allows State to explicitly store the notion of a deleted account in it's cache. kill() can be used
* for this.
*
* For the account's storage, the class operates a cache. baseRoot() specifies the base state of the storage
* given as the Trie root to be looked up in the state database. Alterations beyond this base are specified
* in the overlay, stored in this class and retrieved with storageOverlay(). setStorage allows the overlay
* to be altered.
*
* The code handling explicitly supports a two-stage commit model needed for contract-creation. When creating
* a contract (running the initialisation code), the code of the account is considered empty. The attribute
* of emptiness can be retrieved with codeBearing(). After initialisation one must set the code accordingly;
* the code of the Account can be set with setCode(). To validate a setCode() call, this class records the
* state of being in contract-creation (and thus in a state where setCode may validly be called). It can be
* determined through isFreshCode().
*
* The code can be retrieved through code(), and its hash through codeHash(). codeHash() is only valid when
* the account is not in the contract-creation phase (i.e. when isFreshCode() returns false). This class
* supports populating code on-demand from the state database. To determine if the code has been prepopulated
* call codeCacheValid(). To populate the code, look it up with codeHash() and populate with noteCode().
*
* @todo: need to make a noteCodeCommitted().
*
* The constructor allows you to create an one of a number of "types" of accounts. The default constructor
* makes a dead account (this is ignored by State when writing out the Trie). Another three allow a basic
* or contract account to be specified along with an initial balance. The fina two allow either a basic or
* a contract account to be created with arbitrary values.
*/
class Account
{
public:
/// Type of account to create.
enum NewAccountType
{
/// Normal account.
NormalCreation,
/// Contract account - we place this object into the contract-creation state (and as such we
/// expect setCode(), but codeHash() won't work).
ContractConception
};
/// Construct a dead Account.
Account() {}
/// Construct an alive Account, with given endowment, for either a normal (non-contract) account or for a
/// contract account in the
/// conception phase, where the code is not yet known.
Account(u256 _balance, NewAccountType _t): m_isAlive(true), m_balance(_balance), m_codeHash(_t == NormalCreation ? c_contractConceptionCodeHash : EmptySHA3) {}
/// Explicit constructor for wierd cases of construction of a normal account.
Account(u256 _nonce, u256 _balance): m_isAlive(true), m_nonce(_nonce), m_balance(_balance) {}
/// Explicit constructor for wierd cases of construction or a contract account.
Account(u256 _nonce, u256 _balance, h256 _contractRoot, h256 _codeHash): m_isAlive(true), m_nonce(_nonce), m_balance(_balance), m_storageRoot(_contractRoot), m_codeHash(_codeHash) { assert(_contractRoot); }
/// Kill this account. Useful for the suicide opcode. Following this call, isAlive() returns false.
void kill() { m_isAlive = false; m_storageOverlay.clear(); m_codeHash = EmptySHA3; m_storageRoot = EmptyTrie; m_balance = 0; m_nonce = 0; }
/// @returns true iff this object represents an account in the state. Returns false if this object
/// represents an account that should no longer exist in the trie (an account that never existed or was
/// suicided).
bool isAlive() const { return m_isAlive; }
/// @returns the balance of this account. Can be altered in place.
u256& balance() { return m_balance; }
/// @returns the balance of this account.
u256 const& balance() const { return m_balance; }
/// Increments the balance of this account by the given amount. It's a bigint, so can be negative.
void addBalance(bigint _i) { m_balance = (u256)((bigint)m_balance + _i); }
/// @returns the nonce of the account. Can be altered in place.
u256& nonce() { return m_nonce; }
/// @returns the nonce of the account.
u256 const& nonce() const { return m_nonce; }
/// Increment the nonce of the account by one.
void incNonce() { m_nonce++; }
/// @returns the root of the trie (whose nodes are stored in the state db externally to this class)
/// which encodes the base-state of the account's storage (upon which the storage is overlaid).
h256 baseRoot() const { assert(m_storageRoot); return m_storageRoot; }
/// @returns the storage overlay as a simple map.
std::map<u256, u256> const& storageOverlay() const { return m_storageOverlay; }
/// Set a key/value pair in the account's storage. This actually goes into the overlay, for committing
/// to the trie later.
void setStorage(u256 _p, u256 _v) { m_storageOverlay[_p] = _v; }
/// @returns true if we are in the contract-conception state and setCode is valid to call.
bool isFreshCode() const { return m_codeHash == c_contractConceptionCodeHash; }
/// @returns true if we are either in the contract-conception state or if the account's code is not
/// empty.
bool codeBearing() const { return m_codeHash != EmptySHA3; }
/// @returns the hash of the account's code. Must only be called when isFreshCode() returns false.
h256 codeHash() const { assert(!isFreshCode()); return m_codeHash; }
/// Sets the code of the account. Must only be called when isFreshCode() returns true.
void setCode(bytesConstRef _code) { assert(isFreshCode()); m_codeCache = _code.toBytes(); }
/// @returns true if the account's code is available through code().
bool codeCacheValid() const { return m_codeHash == EmptySHA3 || m_codeHash == c_contractConceptionCodeHash || m_codeCache.size(); }
/// Specify to the object what the actual code is for the account. @a _code must have a SHA3 equal to
/// codeHash() and must only be called when isFreshCode() returns false.
void noteCode(bytesConstRef _code) { assert(sha3(_code) == m_codeHash); m_codeCache = _code.toBytes(); }
/// @returns the account's code. Must only be called when codeCacheValid returns true.
bytes const& code() const { assert(codeCacheValid()); return m_codeCache; }
private:
/// Is this account existant? If not, it represents a deleted account.
bool m_isAlive = false;
/// Account's nonce.
u256 m_nonce = 0;
/// Account's balance.
u256 m_balance = 0;
/// The base storage root. Used with the state DB to give a base to the storage. m_storageOverlay is
/// overlaid on this and takes precedence for all values set.
h256 m_storageRoot = EmptyTrie;
/** If c_contractConceptionCodeHash then we're in the limbo where we're running the initialisation code.
* We expect a setCode() at some point later.
* If EmptySHA3, then m_code, which should be empty, is valid.
* If anything else, then m_code is valid iff it's not empty, otherwise, State::ensureCached() needs to
* be called with the correct args.
*/
h256 m_codeHash = EmptySHA3;
/// The map with is overlaid onto whatever storage is implied by the m_storageRoot in the trie.
std::map<u256, u256> m_storageOverlay;
/// The associated code for this account. The SHA3 of this should be equal to m_codeHash unless m_codeHash
/// equals c_contractConceptionCodeHash.
bytes m_codeCache;
/// Value for m_codeHash when this account is having its code determined.
static const h256 c_contractConceptionCodeHash;
};
}
}

94
libethereum/AddressState.h

@ -1,94 +0,0 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file AddressState.h
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#pragma once
#include <libdevcore/Common.h>
#include <libdevcore/RLP.h>
#include <libdevcrypto/TrieDB.h>
#include <libdevcrypto/SHA3.h>
namespace dev
{
namespace eth
{
// TODO: Document fully.
class AddressState
{
public:
enum NewAccountType { NormalCreation, ContractConception };
/// Construct a dead AddressState.
AddressState() {}
/// Construct an alive AddressState, with given endowment, for either a normal (non-contract) account or for a contract account in the
/// conception phase, where the code is not yet known.
AddressState(u256 _balance, NewAccountType _t): m_isAlive(true), m_balance(_balance), m_codeHash(_t == NormalCreation ? h256() : EmptySHA3) {}
/// Explicit constructor for wierd cases of construction of a normal account.
AddressState(u256 _nonce, u256 _balance): m_isAlive(true), m_nonce(_nonce), m_balance(_balance) {}
/// Explicit constructor for wierd cases of construction or a contract account.
AddressState(u256 _nonce, u256 _balance, h256 _contractRoot, h256 _codeHash): m_isAlive(true), m_nonce(_nonce), m_balance(_balance), m_storageRoot(_contractRoot), m_codeHash(_codeHash) {}
void kill() { m_isAlive = false; m_storageOverlay.clear(); m_codeHash = EmptySHA3; m_storageRoot = EmptyTrie; m_balance = 0; m_nonce = 0; }
bool isAlive() const { return m_isAlive; }
u256& balance() { return m_balance; }
u256 const& balance() const { return m_balance; }
void addBalance(bigint _i) { m_balance = (u256)((bigint)m_balance + _i); }
u256& nonce() { return m_nonce; }
u256 const& nonce() const { return m_nonce; }
void incNonce() { m_nonce++; }
h256 baseRoot() const { return m_storageRoot; }
std::map<u256, u256> const& storage() const { return m_storageOverlay; }
void setStorage(u256 _p, u256 _v) { m_storageOverlay[_p] = _v; }
bool isFreshCode() const { return !m_codeHash; }
bool codeBearing() const { return m_codeHash != EmptySHA3; }
bool codeCacheValid() const { return m_codeHash == EmptySHA3 || !m_codeHash || m_codeCache.size(); }
h256 codeHash() const { assert(m_codeHash); return m_codeHash; }
bytes const& code() const { assert(m_codeHash == EmptySHA3 || !m_codeHash || m_codeCache.size()); return m_codeCache; }
void setCode(bytesConstRef _code) { assert(!m_codeHash); m_codeCache = _code.toBytes(); }
void noteCode(bytesConstRef _code) { assert(sha3(_code) == m_codeHash); m_codeCache = _code.toBytes(); }
private:
bool m_isAlive = false;
u256 m_nonce = 0;
u256 m_balance = 0;
/// The base storage root. Used with the state DB to give a base to the storage. m_storageOverlay is overlaid on this and takes precedence for all values set.
h256 m_storageRoot = EmptyTrie;
/// If 0 then we're in the limbo where we're running the initialisation code. We expect a setCode() at some point later.
/// If EmptySHA3, then m_code, which should be empty, is valid.
/// If anything else, then m_code is valid iff it's not empty, otherwise, State::ensureCached() needs to be called with the correct args.
h256 m_codeHash = EmptySHA3;
// TODO: change to unordered_map.
std::map<u256, u256> m_storageOverlay;
bytes m_codeCache;
};
}
}

2
libethereum/All.h

@ -1,6 +1,6 @@
#pragma once
#include "AddressState.h"
#include "Account.h"
#include "BlockChain.h"
#include "Client.h"
#include "Defaults.h"

6
libethereum/BlockChain.cpp

@ -52,9 +52,9 @@ std::ostream& dev::eth::operator<<(std::ostream& _out, BlockChain const& _bc)
return _out;
}
std::map<Address, AddressState> const& dev::eth::genesisState()
std::map<Address, Account> const& dev::eth::genesisState()
{
static std::map<Address, AddressState> s_ret;
static std::map<Address, Account> s_ret;
if (s_ret.empty())
// Initialise.
for (auto i: vector<string>({
@ -67,7 +67,7 @@ std::map<Address, AddressState> const& dev::eth::genesisState()
"6c386a4b26f73c802f34673f7248bb118f97424a",
"e4157b34ea9615cfbde6b4fda419828124b70c78"
}))
s_ret[Address(fromHex(i))] = AddressState(u256(1) << 200, AddressState::NormalCreation);
s_ret[Address(fromHex(i))] = Account(u256(1) << 200, Account::NormalCreation);
return s_ret;
}

4
libethereum/BlockChain.h

@ -33,7 +33,7 @@
#include <libethcore/BlockInfo.h>
#include <libdevcore/Guards.h>
#include "BlockDetails.h"
#include "AddressState.h"
#include "Account.h"
#include "BlockQueue.h"
namespace ldb = leveldb;
@ -57,7 +57,7 @@ struct BlockChainChat: public LogChannel { static const char* name() { return "-
struct BlockChainNote: public LogChannel { static const char* name() { return "=B="; } static const int verbosity = 4; };
// TODO: Move all this Genesis stuff into Genesis.h/.cpp
std::map<Address, AddressState> const& genesisState();
std::map<Address, Account> const& genesisState();
ldb::Slice toSlice(h256 _h, unsigned _sub = 0);

2
libethereum/Executive.cpp

@ -138,7 +138,7 @@ bool Executive::create(Address _sender, u256 _endowment, u256 _gasPrice, u256 _g
m_newAddress = right160(sha3(rlpList(_sender, m_s.transactionsFrom(_sender) - 1)));
// Set up new account...
m_s.m_cache[m_newAddress] = AddressState(0, m_s.balance(m_newAddress) + _endowment, EmptyTrie, h256());
m_s.m_cache[m_newAddress] = Account(m_s.balance(m_newAddress) + _endowment, Account::ContractConception);
// Execute _init.
m_vm = VMFace::create(VMFace::JIT, _gas).release();

2
libethereum/ExtVM.h

@ -102,7 +102,7 @@ public:
private:
State& m_s; ///< A reference to the base state.
std::map<Address, AddressState> m_origCache; ///< The cache of the address states (i.e. the externalities) as-was prior to the execution.
std::map<Address, Account> m_origCache; ///< The cache of the address states (i.e. the externalities) as-was prior to the execution.
Manifest* m_ms;
};

32
libethereum/State.cpp

@ -226,7 +226,7 @@ Address State::nextActiveAddress(Address _a) const
// TODO: repot
struct CachedAddressState
{
CachedAddressState(std::string const& _rlp, AddressState const* _s, OverlayDB const* _o): rS(_rlp), r(rS), s(_s), o(_o) {}
CachedAddressState(std::string const& _rlp, Account const* _s, OverlayDB const* _o): rS(_rlp), r(rS), s(_s), o(_o) {}
bool exists() const
{
@ -261,7 +261,7 @@ struct CachedAddressState
ret[j.first] = RLP(j.second).toInt<u256>();
}
if (s)
for (auto const& j: s->storage())
for (auto const& j: s->storageOverlay())
if ((!ret.count(j.first) && j.second) || (ret.count(j.first) && ret.at(j.first) != j.second))
ret[j.first] = j.second;
return ret;
@ -302,7 +302,7 @@ struct CachedAddressState
std::string rS;
RLP r;
AddressState const* s;
Account const* s;
OverlayDB const* o;
};
@ -348,7 +348,7 @@ void State::ensureCached(Address _a, bool _requireCode, bool _forceCreate) const
ensureCached(m_cache, _a, _requireCode, _forceCreate);
}
void State::ensureCached(std::map<Address, AddressState>& _cache, Address _a, bool _requireCode, bool _forceCreate) const
void State::ensureCached(std::map<Address, Account>& _cache, Address _a, bool _requireCode, bool _forceCreate) const
{
auto it = _cache.find(_a);
if (it == _cache.end())
@ -358,11 +358,11 @@ void State::ensureCached(std::map<Address, AddressState>& _cache, Address _a, bo
if (stateBack.empty() && !_forceCreate)
return;
RLP state(stateBack);
AddressState s;
Account s;
if (state.isNull())
s = AddressState(0, AddressState::NormalCreation);
s = Account(0, Account::NormalCreation);
else
s = AddressState(state[0].toInt<u256>(), state[1].toInt<u256>(), state[2].toHash<h256>(), state[3].toHash<h256>());
s = Account(state[0].toInt<u256>(), state[1].toInt<u256>(), state[2].toHash<h256>(), state[3].toHash<h256>());
bool ok;
tie(it, ok) = _cache.insert(make_pair(_a, s));
}
@ -967,7 +967,7 @@ void State::noteSending(Address _id)
{
cwarn << "Sending from non-existant account. How did it pay!?!";
// this is impossible. but we'll continue regardless...
m_cache[_id] = AddressState(1, 0);
m_cache[_id] = Account(1, 0);
}
else
it->second.incNonce();
@ -978,7 +978,7 @@ void State::addBalance(Address _id, u256 _amount)
ensureCached(_id, false, false);
auto it = m_cache.find(_id);
if (it == m_cache.end())
m_cache[_id] = AddressState(_amount, AddressState::NormalCreation);
m_cache[_id] = Account(_amount, Account::NormalCreation);
else
it->second.addBalance(_amount);
}
@ -1013,8 +1013,8 @@ u256 State::storage(Address _id, u256 _memory) const
return 0;
// See if it's in the account's storage cache.
auto mit = it->second.storage().find(_memory);
if (mit != it->second.storage().end())
auto mit = it->second.storageOverlay().find(_memory);
if (mit != it->second.storageOverlay().end())
return mit->second;
// Not in the storage cache - go to the DB.
@ -1042,7 +1042,7 @@ map<u256, u256> State::storage(Address _id) const
}
// Then merge cached storage over the top.
for (auto const& i: it->second.storage())
for (auto const& i: it->second.storageOverlay())
if (i.second)
ret[i.first] = i.second;
else
@ -1059,7 +1059,7 @@ h256 State::storageRoot(Address _id) const
RLP r(s);
return r[2].toHash<h256>();
}
return h256();
return EmptyTrie;
}
bytes const& State::code(Address _contract) const
@ -1270,7 +1270,7 @@ h160 State::create(Address _sender, u256 _endowment, u256 _gasPrice, u256* _gas,
Address newAddress = right160(sha3(rlpList(_sender, transactionsFrom(_sender) - 1)));
// Set up new account...
m_cache[newAddress] = AddressState(balance(newAddress) + _endowment, AddressState::ContractConception);
m_cache[newAddress] = Account(balance(newAddress) + _endowment, Account::ContractConception);
// Execute init code.
auto vmObj = VMFace::create(getVMKind(), *_gas);
@ -1370,7 +1370,7 @@ std::ostream& dev::eth::operator<<(std::ostream& _out, State const& _s)
for (auto i: d)
{
auto it = _s.m_cache.find(i);
AddressState* cache = it != _s.m_cache.end() ? &it->second : nullptr;
Account* cache = it != _s.m_cache.end() ? &it->second : nullptr;
string rlpString = dtr.count(i) ? trie.at(i) : "";
RLP r(rlpString);
assert(cache || r);
@ -1398,7 +1398,7 @@ std::ostream& dev::eth::operator<<(std::ostream& _out, State const& _s)
mem[j.first] = RLP(j.second).toInt<u256>(), back.insert(j.first);
}
if (cache)
for (auto const& j: cache->storage())
for (auto const& j: cache->storageOverlay())
{
if ((!mem.count(j.first) && j.second) || (mem.count(j.first) && mem.at(j.first) != j.second))
mem[j.first] = j.second, delta.insert(j.first);

20
libethereum/State.h

@ -34,7 +34,7 @@
#include <libevm/ExtVMFace.h>
#include <libevm/VMFace.h>
#include "TransactionQueue.h"
#include "AddressState.h"
#include "Account.h"
#include "Transaction.h"
#include "Executive.h"
#include "AccountDiff.h"
@ -130,8 +130,10 @@ public:
/// @returns the set containing all addresses currently in use in Ethereum.
std::map<Address, u256> addresses() const;
/// @returns the address b such that b > @a _a .
Address nextActiveAddress(Address _a) const;
/// Get the header information on the present block.
BlockInfo const& info() const { return m_currentBlock; }
/// @brief Checks that mining the current object will result in a valid block.
@ -306,7 +308,7 @@ private:
void ensureCached(Address _a, bool _requireCode, bool _forceCreate) const;
/// Retrieve all information about a given address into a cache.
void ensureCached(std::map<Address, AddressState>& _cache, Address _a, bool _requireCode, bool _forceCreate) const;
void ensureCached(std::map<Address, Account>& _cache, Address _a, bool _requireCode, bool _forceCreate) const;
/// Commit all changes waiting in the address cache to the DB.
void commit();
@ -347,18 +349,18 @@ private:
std::set<h256> m_transactionSet; ///< The set of transaction hashes that we've included in the state.
OverlayDB m_lastTx;
mutable std::map<Address, AddressState> m_cache; ///< Our address cache. This stores the states of each address that has (or at least might have) been changed.
mutable std::map<Address, Account> m_cache; ///< Our address cache. This stores the states of each address that has (or at least might have) been changed.
BlockInfo m_previousBlock; ///< The previous block's information.
BlockInfo m_currentBlock; ///< The current block's information.
bytes m_currentBytes; ///< The current block.
bytes m_currentTxs;
bytes m_currentUncles;
bytes m_currentTxs; ///< The RLP-encoded block of transactions.
bytes m_currentUncles; ///< The RLP-encoded block of uncles.
Address m_ourAddress; ///< Our address (i.e. the address to which fees go).
ProofOfWork m_pow;
ProofOfWork m_pow; ///< The PoW mining class.
u256 m_blockReward;
@ -374,7 +376,7 @@ private:
std::ostream& operator<<(std::ostream& _out, State const& _s);
template <class DB>
void commit(std::map<Address, AddressState> const& _cache, DB& _db, TrieDB<Address, DB>& _state)
void commit(std::map<Address, Account> const& _cache, DB& _db, TrieDB<Address, DB>& _state)
{
for (auto const& i: _cache)
if (!i.second.isAlive())
@ -384,7 +386,7 @@ void commit(std::map<Address, AddressState> const& _cache, DB& _db, TrieDB<Addre
RLPStream s(4);
s << i.second.nonce() << i.second.balance();
if (i.second.storage().empty())
if (i.second.storageOverlay().empty())
{
assert(i.second.baseRoot());
s.append(i.second.baseRoot());
@ -392,7 +394,7 @@ void commit(std::map<Address, AddressState> const& _cache, DB& _db, TrieDB<Addre
else
{
TrieDB<h256, DB> storageDB(&_db, i.second.baseRoot());
for (auto const& j: i.second.storage())
for (auto const& j: i.second.storageOverlay())
if (j.second)
storageDB.insert(j.first, rlp(j.second));
else

11
libevmjit/Compiler.cpp

@ -345,7 +345,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytesConstRef _bytecod
case Instruction::BNOT:
{
auto value = stack.pop();
auto ret = m_builder.CreateXor(value, llvm::APInt(256, -1, true), "bnot");
auto ret = m_builder.CreateXor(value, Constant::get(-1), "bnot");
stack.push(ret);
break;
}
@ -760,12 +760,9 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytesConstRef _bytecod
_gasMeter.commitCostBlock(gas);
// Require _memory for the max of in and out buffers
auto inSizeReq = m_builder.CreateAdd(inOff, inSize, "inSizeReq");
auto outSizeReq = m_builder.CreateAdd(outOff, outSize, "outSizeReq");
auto cmp = m_builder.CreateICmpUGT(inSizeReq, outSizeReq);
auto sizeReq = m_builder.CreateSelect(cmp, inSizeReq, outSizeReq, "sizeReq");
_memory.require(sizeReq);
// Require memory for in and out buffers
memory.require(outOff, outSize); // Out buffer first as we guess it will be after the in one
memory.require(inOff, inSize);
auto receiveAddress = codeAddress;
if (inst == Instruction::CALLCODE)

50
libevmjit/Memory.cpp

@ -8,6 +8,7 @@
#include <llvm/IR/GlobalVariable.h>
#include <llvm/IR/Function.h>
#include <llvm/IR/IntrinsicInst.h>
#include <libdevcore/Common.h>
@ -28,8 +29,7 @@ Memory::Memory(RuntimeManager& _runtimeManager, GasMeter& _gasMeter):
RuntimeHelper(_runtimeManager)
{
auto module = getModule();
auto i64Ty = m_builder.getInt64Ty();
llvm::Type* argTypes[] = {i64Ty, i64Ty};
llvm::Type* argTypes[] = {Type::i256, Type::i256};
auto dumpTy = llvm::FunctionType::get(m_builder.getVoidTy(), llvm::ArrayRef<llvm::Type*>(argTypes), false);
m_memDump = llvm::Function::Create(dumpTy, llvm::GlobalValue::LinkageTypes::ExternalLinkage,
"evmccrt_memory_dump", module);
@ -54,28 +54,41 @@ Memory::Memory(RuntimeManager& _runtimeManager, GasMeter& _gasMeter):
llvm::Function* Memory::createRequireFunc(GasMeter& _gasMeter, RuntimeManager& _runtimeManager)
{
auto func = llvm::Function::Create(llvm::FunctionType::get(Type::Void, Type::i256, false), llvm::Function::PrivateLinkage, "mem.require", getModule());
llvm::Type* argTypes[] = {Type::i256, Type::i256};
auto func = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argTypes, false), llvm::Function::PrivateLinkage, "mem.require", getModule());
auto offset = func->arg_begin();
offset->setName("offset");
auto size = offset->getNextNode();
size->setName("size");
auto checkBB = llvm::BasicBlock::Create(func->getContext(), "check", func);
auto resizeBB = llvm::BasicBlock::Create(func->getContext(), "resize", func);
auto returnBB = llvm::BasicBlock::Create(func->getContext(), "return", func);
auto checkBB = llvm::BasicBlock::Create(func->getContext(), "Check", func);
auto resizeBB = llvm::BasicBlock::Create(func->getContext(), "Resize", func);
auto returnBB = llvm::BasicBlock::Create(func->getContext(), "Return", func);
InsertPointGuard guard(m_builder); // Restores insert point at function exit
// BB "check"
m_builder.SetInsertPoint(checkBB);
llvm::Value* sizeRequired = func->arg_begin();
sizeRequired->setName("sizeRequired");
auto size = m_builder.CreateLoad(m_size, "size");
auto resizeNeeded = m_builder.CreateICmpULE(size, sizeRequired, "resizeNeeded");
auto uaddWO = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::uadd_with_overflow, Type::i256);
auto uaddRes = m_builder.CreateCall2(uaddWO, offset, size, "res");
auto sizeRequired = m_builder.CreateExtractValue(uaddRes, 0, "sizeReq");
auto overflow1 = m_builder.CreateExtractValue(uaddRes, 1, "overflow1");
auto currSize = m_builder.CreateLoad(m_size, "currSize");
auto tooSmall = m_builder.CreateICmpULE(size, sizeRequired, "tooSmall");
auto resizeNeeded = m_builder.CreateOr(tooSmall, overflow1, "resizeNeeded");
m_builder.CreateCondBr(resizeNeeded, resizeBB, returnBB); // OPT branch weights?
// BB "resize"
m_builder.SetInsertPoint(resizeBB);
// Check gas first
auto wordsRequired = m_builder.CreateUDiv(m_builder.CreateAdd(sizeRequired, Constant::get(31)), Constant::get(32), "wordsRequired");
sizeRequired = m_builder.CreateMul(wordsRequired, Constant::get(32), "roundedSizeRequired");
auto words = m_builder.CreateUDiv(size, Constant::get(32), "words"); // size is always 32*k
uaddRes = m_builder.CreateCall2(uaddWO, sizeRequired, Constant::get(31), "res");
auto wordsRequired = m_builder.CreateExtractValue(uaddRes, 0);
auto overflow2 = m_builder.CreateExtractValue(uaddRes, 1, "overflow2");
auto overflow = m_builder.CreateOr(overflow1, overflow2, "overflow");
wordsRequired = m_builder.CreateSelect(overflow, Constant::get(-1), wordsRequired);
wordsRequired = m_builder.CreateUDiv(wordsRequired, Constant::get(32), "wordsReq");
sizeRequired = m_builder.CreateMul(wordsRequired, Constant::get(32), "roundedSizeReq");
auto words = m_builder.CreateUDiv(currSize, Constant::get(32), "words"); // size is always 32*k
auto newWords = m_builder.CreateSub(wordsRequired, words, "addtionalWords");
_gasMeter.checkMemory(newWords, m_builder);
// Resize
@ -164,15 +177,9 @@ llvm::Value* Memory::getSize()
return m_builder.CreateLoad(m_size);
}
void Memory::require(llvm::Value* _size)
{
m_builder.CreateCall(m_require, _size);
}
void Memory::require(llvm::Value* _offset, llvm::Value* _size)
{
auto sizeRequired = m_builder.CreateAdd(_offset, _size, "sizeRequired");
require(sizeRequired);
m_builder.CreateCall2(m_require, _offset, _size);
}
void Memory::copyBytes(llvm::Value* _srcPtr, llvm::Value* _srcSize, llvm::Value* _srcIdx,
@ -180,8 +187,7 @@ void Memory::copyBytes(llvm::Value* _srcPtr, llvm::Value* _srcSize, llvm::Value*
{
auto zero256 = llvm::ConstantInt::get(Type::i256, 0);
auto reqMemSize = m_builder.CreateAdd(_destMemIdx, _reqBytes, "req_mem_size");
require(reqMemSize);
require(_destMemIdx, _reqBytes);
auto srcPtr = m_builder.CreateGEP(_srcPtr, _srcIdx, "src_idx");

4
libevmjit/Memory.h

@ -24,9 +24,6 @@ public:
void copyBytes(llvm::Value* _srcPtr, llvm::Value* _srcSize, llvm::Value* _srcIndex,
llvm::Value* _destMemIdx, llvm::Value* _byteCount);
/// Requires this amount of memory. And counts gas fee for that memory.
void require(llvm::Value* _size);
/// Requires the amount of memory to for data defined by offset and size. And counts gas fee for that memory.
void require(llvm::Value* _offset, llvm::Value* _size);
@ -36,7 +33,6 @@ private:
llvm::Function* createFunc(bool _isStore, llvm::Type* _type, GasMeter& _gasMeter);
llvm::Function* createRequireFunc(GasMeter& _gasMeter, RuntimeManager& _runtimeManager);
private:
llvm::GlobalVariable* m_data;
llvm::GlobalVariable* m_size;

4
libevmjit/Type.cpp

@ -36,9 +36,9 @@ void Type::init(llvm::LLVMContext& _context)
RuntimePtr = RuntimeData::getType()->getPointerTo();
}
llvm::ConstantInt* Constant::get(uint64_t _n)
llvm::ConstantInt* Constant::get(int64_t _n)
{
return llvm::ConstantInt::get(Type::i256, _n);
return llvm::ConstantInt::getSigned(Type::i256, _n);
}
llvm::ConstantInt* Constant::get(u256 _n)

2
libevmjit/Type.h

@ -51,7 +51,7 @@ enum class ReturnCode
struct Constant
{
/// Returns word-size constant
static llvm::ConstantInt* get(uint64_t _n);
static llvm::ConstantInt* get(int64_t _n);
static llvm::ConstantInt* get(u256 _n);
static llvm::ConstantInt* get(ReturnCode _returnCode);

2
test/vm.cpp

@ -471,7 +471,7 @@ h160 FakeState::createNewAddress(Address _newAddress, Address _sender, u256 _end
}
// Set up new account...
m_cache[_newAddress] = AddressState(0, balance(_newAddress) + _endowment, h256(), h256());
m_cache[_newAddress] = Account(0, balance(_newAddress) + _endowment, h256(), h256());
// Execute init code.
auto vmObj = VMFace::create(getVMKind(), *_gas);

4
windows/LibEthereum.vcxproj

@ -103,8 +103,8 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\libethcore\_libethcore.cpp" />
<ClCompile Include="..\libethereum\Account.cpp" />
<ClCompile Include="..\libethereum\AccountDiff.cpp" />
<ClCompile Include="..\libethereum\AddressState.cpp" />
<ClCompile Include="..\libethereum\BlockChain.cpp" />
<ClCompile Include="..\libethereum\BlockDetails.cpp" />
<ClCompile Include="..\libethereum\BlockQueue.cpp" />
@ -319,8 +319,8 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClInclude>
<ClInclude Include="..\libethereum\Account.h" />
<ClInclude Include="..\libethereum\AccountDiff.h" />
<ClInclude Include="..\libethereum\AddressState.h" />
<ClInclude Include="..\libethereum\All.h" />
<ClInclude Include="..\libethereum\BlockChain.h" />
<ClInclude Include="..\libethereum\BlockDetails.h" />

12
windows/LibEthereum.vcxproj.filters

@ -4,9 +4,6 @@
<ClCompile Include="stdafx.cpp">
<Filter>Windows</Filter>
</ClCompile>
<ClCompile Include="..\libethereum\AddressState.cpp">
<Filter>libethereum</Filter>
</ClCompile>
<ClCompile Include="..\libethereum\BlockChain.cpp">
<Filter>libethereum</Filter>
</ClCompile>
@ -205,14 +202,14 @@
<ClCompile Include="..\libdevcrypto\SHA3MAC.cpp">
<Filter>libdevcrypto</Filter>
</ClCompile>
<ClCompile Include="..\libethereum\Account.cpp">
<Filter>libethereum</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="stdafx.h">
<Filter>Windows</Filter>
</ClInclude>
<ClInclude Include="..\libethereum\AddressState.h">
<Filter>libethereum</Filter>
</ClInclude>
<ClInclude Include="..\libethereum\BlockChain.h">
<Filter>libethereum</Filter>
</ClInclude>
@ -441,6 +438,9 @@
<ClInclude Include="..\libdevcrypto\SHA3MAC.h">
<Filter>libdevcrypto</Filter>
</ClInclude>
<ClInclude Include="..\libethereum\Account.h">
<Filter>libethereum</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Filter Include="Windows">

Loading…
Cancel
Save