mirror of
				https://github.com/ethereum/solidity
				synced 2023-10-03 13:03:40 +00:00 
			
		
		
		
	Merge pull request #471 from winsvega/libevmcore
move libevmcore to solidity
This commit is contained in:
		
						commit
						737623cd0c
					
				| @ -26,7 +26,7 @@ | ||||
| #include <libdevcore/Common.h> | ||||
| #include <libdevcore/Assertions.h> | ||||
| #include <libdevcore/SHA3.h> | ||||
| #include <libevmcore/Instruction.h> | ||||
| #include <libevmasm/Instruction.h> | ||||
| #include <libevmasm/SourceLocation.h> | ||||
| #include <libevmasm/AssemblyItem.h> | ||||
| #include <libevmasm/LinkerObject.h> | ||||
| @ -69,10 +69,10 @@ public: | ||||
| 	void appendProgramSize() { append(AssemblyItem(PushProgramSize)); } | ||||
| 	void appendLibraryAddress(std::string const& _identifier) { append(newPushLibraryAddress(_identifier)); } | ||||
| 
 | ||||
| 	AssemblyItem appendJump() { auto ret = append(newPushTag()); append(Instruction::JUMP); return ret; } | ||||
| 	AssemblyItem appendJumpI() { auto ret = append(newPushTag()); append(Instruction::JUMPI); return ret; } | ||||
| 	AssemblyItem appendJump(AssemblyItem const& _tag) { auto ret = append(_tag.pushTag()); append(Instruction::JUMP); return ret; } | ||||
| 	AssemblyItem appendJumpI(AssemblyItem const& _tag) { auto ret = append(_tag.pushTag()); append(Instruction::JUMPI); return ret; } | ||||
| 	AssemblyItem appendJump() { auto ret = append(newPushTag()); append(solidity::Instruction::JUMP); return ret; } | ||||
| 	AssemblyItem appendJumpI() { auto ret = append(newPushTag()); append(solidity::Instruction::JUMPI); return ret; } | ||||
| 	AssemblyItem appendJump(AssemblyItem const& _tag) { auto ret = append(_tag.pushTag()); append(solidity::Instruction::JUMP); return ret; } | ||||
| 	AssemblyItem appendJumpI(AssemblyItem const& _tag) { auto ret = append(_tag.pushTag()); append(solidity::Instruction::JUMPI); return ret; } | ||||
| 	AssemblyItem errorTag() { return AssemblyItem(PushTag, 0); } | ||||
| 
 | ||||
| 	template <class T> Assembly& operator<<(T const& _d) { append(_d); return *this; } | ||||
| @ -86,7 +86,7 @@ public: | ||||
| 	void ignored() { m_baseDeposit = m_deposit; } | ||||
| 	void endIgnored() { m_deposit = m_baseDeposit; m_baseDeposit = 0; } | ||||
| 
 | ||||
| 	void popTo(int _deposit) { while (m_deposit > _deposit) append(Instruction::POP); } | ||||
| 	void popTo(int _deposit) { while (m_deposit > _deposit) append(solidity::Instruction::POP); } | ||||
| 
 | ||||
| 	void injectStart(AssemblyItem const& _i); | ||||
| 	std::string out() const; | ||||
|  | ||||
| @ -94,7 +94,7 @@ ostream& dev::eth::operator<<(ostream& _out, AssemblyItem const& _item) | ||||
| 	{ | ||||
| 	case Operation: | ||||
| 		_out << " " << instructionInfo(_item.instruction()).name; | ||||
| 		if (_item.instruction() == eth::Instruction::JUMP || _item.instruction() == eth::Instruction::JUMPI) | ||||
| 		if (_item.instruction() == solidity::Instruction::JUMP || _item.instruction() == solidity::Instruction::JUMPI) | ||||
| 			_out << "\t" << _item.getJumpTypeAsString(); | ||||
| 		break; | ||||
| 	case Push: | ||||
|  | ||||
| @ -25,9 +25,10 @@ | ||||
| #include <sstream> | ||||
| #include <libdevcore/Common.h> | ||||
| #include <libdevcore/Assertions.h> | ||||
| #include <libevmcore/Instruction.h> | ||||
| #include <libevmasm/Instruction.h> | ||||
| #include <libevmasm/SourceLocation.h> | ||||
| #include "Exceptions.h" | ||||
| using namespace dev::solidity; | ||||
| 
 | ||||
| namespace dev | ||||
| { | ||||
| @ -57,7 +58,7 @@ public: | ||||
| 
 | ||||
| 	AssemblyItem(u256 _push, SourceLocation const& _location = SourceLocation()): | ||||
| 		AssemblyItem(Push, _push, _location) { } | ||||
| 	AssemblyItem(Instruction _i, SourceLocation const& _location = SourceLocation()): | ||||
| 	AssemblyItem(solidity::Instruction _i, SourceLocation const& _location = SourceLocation()): | ||||
| 		AssemblyItem(Operation, byte(_i), _location) { } | ||||
| 	AssemblyItem(AssemblyItemType _type, u256 _data = 0, SourceLocation const& _location = SourceLocation()): | ||||
| 		m_type(_type), | ||||
|  | ||||
| @ -106,7 +106,7 @@ BlockDeduplicator::BlockIterator& BlockDeduplicator::BlockIterator::operator++() | ||||
| { | ||||
| 	if (it == end) | ||||
| 		return *this; | ||||
| 	if (SemanticInformation::altersControlFlow(*it) && *it != AssemblyItem(eth::Instruction::JUMPI)) | ||||
| 	if (SemanticInformation::altersControlFlow(*it) && *it != AssemblyItem(Instruction::JUMPI)) | ||||
| 		it = end; | ||||
| 	else | ||||
| 	{ | ||||
|  | ||||
| @ -8,7 +8,7 @@ file(GLOB HEADERS "*.h") | ||||
| 
 | ||||
| include_directories(BEFORE ..) | ||||
| add_library(${EXECUTABLE} ${SRC_LIST} ${HEADERS}) | ||||
| eth_use(${EXECUTABLE} REQUIRED Eth::evmcore) | ||||
| eth_use(${EXECUTABLE} REQUIRED Dev::devcore Eth::ethcore) | ||||
| 
 | ||||
| install( TARGETS ${EXECUTABLE} RUNTIME DESTINATION bin ARCHIVE DESTINATION lib LIBRARY DESTINATION lib ) | ||||
| install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} ) | ||||
|  | ||||
| @ -84,13 +84,13 @@ GasMeter::GasConsumption GasMeter::estimateMax(AssemblyItem const& _item) | ||||
| 			break; | ||||
| 		case Instruction::MLOAD: | ||||
| 		case Instruction::MSTORE: | ||||
| 			gas += memoryGas(classes.find(eth::Instruction::ADD, { | ||||
| 			gas += memoryGas(classes.find(Instruction::ADD, { | ||||
| 				m_state->relativeStackElement(0), | ||||
| 				classes.find(AssemblyItem(32)) | ||||
| 			})); | ||||
| 			break; | ||||
| 		case Instruction::MSTORE8: | ||||
| 			gas += memoryGas(classes.find(eth::Instruction::ADD, { | ||||
| 			gas += memoryGas(classes.find(Instruction::ADD, { | ||||
| 				m_state->relativeStackElement(0), | ||||
| 				classes.find(AssemblyItem(1)) | ||||
| 			})); | ||||
| @ -198,7 +198,7 @@ GasMeter::GasConsumption GasMeter::memoryGas(int _stackPosOffset, int _stackPosS | ||||
| 	if (classes.knownZero(m_state->relativeStackElement(_stackPosSize))) | ||||
| 		return GasConsumption(0); | ||||
| 	else | ||||
| 		return memoryGas(classes.find(eth::Instruction::ADD, { | ||||
| 		return memoryGas(classes.find(Instruction::ADD, { | ||||
| 			m_state->relativeStackElement(_stackPosOffset), | ||||
| 			m_state->relativeStackElement(_stackPosSize) | ||||
| 		})); | ||||
|  | ||||
							
								
								
									
										354
									
								
								libevmasm/Instruction.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										354
									
								
								libevmasm/Instruction.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,354 @@ | ||||
| /*
 | ||||
| 	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 Instruction.cpp
 | ||||
|  * @author Gav Wood <i@gavwood.com> | ||||
|  * @date 2014 | ||||
|  */ | ||||
| 
 | ||||
| #include "./Instruction.h" | ||||
| 
 | ||||
| #include <functional> | ||||
| #include <libdevcore/Common.h> | ||||
| #include <libdevcore/CommonIO.h> | ||||
| #include <libdevcore/Log.h> | ||||
| using namespace std; | ||||
| using namespace dev; | ||||
| using namespace dev::solidity; | ||||
| 
 | ||||
| const std::map<std::string, Instruction> dev::solidity::c_instructions = | ||||
| { | ||||
| 	{ "STOP", Instruction::STOP }, | ||||
| 	{ "ADD", Instruction::ADD }, | ||||
| 	{ "SUB", Instruction::SUB }, | ||||
| 	{ "MUL", Instruction::MUL }, | ||||
| 	{ "DIV", Instruction::DIV }, | ||||
| 	{ "SDIV", Instruction::SDIV }, | ||||
| 	{ "MOD", Instruction::MOD }, | ||||
| 	{ "SMOD", Instruction::SMOD }, | ||||
| 	{ "EXP", Instruction::EXP }, | ||||
| 	{ "BNOT", Instruction::NOT }, | ||||
| 	{ "LT", Instruction::LT }, | ||||
| 	{ "GT", Instruction::GT }, | ||||
| 	{ "SLT", Instruction::SLT }, | ||||
| 	{ "SGT", Instruction::SGT }, | ||||
| 	{ "EQ", Instruction::EQ }, | ||||
| 	{ "NOT", Instruction::ISZERO }, | ||||
| 	{ "AND", Instruction::AND }, | ||||
| 	{ "OR", Instruction::OR }, | ||||
| 	{ "XOR", Instruction::XOR }, | ||||
| 	{ "BYTE", Instruction::BYTE }, | ||||
| 	{ "ADDMOD", Instruction::ADDMOD }, | ||||
| 	{ "MULMOD", Instruction::MULMOD }, | ||||
| 	{ "SIGNEXTEND", Instruction::SIGNEXTEND }, | ||||
| 	{ "SHA3", Instruction::SHA3 }, | ||||
| 	{ "ADDRESS", Instruction::ADDRESS }, | ||||
| 	{ "BALANCE", Instruction::BALANCE }, | ||||
| 	{ "ORIGIN", Instruction::ORIGIN }, | ||||
| 	{ "CALLER", Instruction::CALLER }, | ||||
| 	{ "CALLVALUE", Instruction::CALLVALUE }, | ||||
| 	{ "CALLDATALOAD", Instruction::CALLDATALOAD }, | ||||
| 	{ "CALLDATASIZE", Instruction::CALLDATASIZE }, | ||||
| 	{ "CALLDATACOPY", Instruction::CALLDATACOPY }, | ||||
| 	{ "CODESIZE", Instruction::CODESIZE }, | ||||
| 	{ "CODECOPY", Instruction::CODECOPY }, | ||||
| 	{ "GASPRICE", Instruction::GASPRICE }, | ||||
| 	{ "EXTCODESIZE", Instruction::EXTCODESIZE }, | ||||
| 	{ "EXTCODECOPY", Instruction::EXTCODECOPY }, | ||||
| 	{ "BLOCKHASH", Instruction::BLOCKHASH }, | ||||
| 	{ "COINBASE", Instruction::COINBASE }, | ||||
| 	{ "TIMESTAMP", Instruction::TIMESTAMP }, | ||||
| 	{ "NUMBER", Instruction::NUMBER }, | ||||
| 	{ "DIFFICULTY", Instruction::DIFFICULTY }, | ||||
| 	{ "GASLIMIT", Instruction::GASLIMIT }, | ||||
| 	{ "POP", Instruction::POP }, | ||||
| 	{ "MLOAD", Instruction::MLOAD }, | ||||
| 	{ "MSTORE", Instruction::MSTORE }, | ||||
| 	{ "MSTORE8", Instruction::MSTORE8 }, | ||||
| 	{ "SLOAD", Instruction::SLOAD }, | ||||
| 	{ "SSTORE", Instruction::SSTORE }, | ||||
| 	{ "JUMP", Instruction::JUMP }, | ||||
| 	{ "JUMPI", Instruction::JUMPI }, | ||||
| 	{ "PC", Instruction::PC }, | ||||
| 	{ "MSIZE", Instruction::MSIZE }, | ||||
| 	{ "GAS", Instruction::GAS }, | ||||
| 	{ "JUMPDEST", Instruction::JUMPDEST }, | ||||
| 	{ "PUSH1", Instruction::PUSH1 }, | ||||
| 	{ "PUSH2", Instruction::PUSH2 }, | ||||
| 	{ "PUSH3", Instruction::PUSH3 }, | ||||
| 	{ "PUSH4", Instruction::PUSH4 }, | ||||
| 	{ "PUSH5", Instruction::PUSH5 }, | ||||
| 	{ "PUSH6", Instruction::PUSH6 }, | ||||
| 	{ "PUSH7", Instruction::PUSH7 }, | ||||
| 	{ "PUSH8", Instruction::PUSH8 }, | ||||
| 	{ "PUSH9", Instruction::PUSH9 }, | ||||
| 	{ "PUSH10", Instruction::PUSH10 }, | ||||
| 	{ "PUSH11", Instruction::PUSH11 }, | ||||
| 	{ "PUSH12", Instruction::PUSH12 }, | ||||
| 	{ "PUSH13", Instruction::PUSH13 }, | ||||
| 	{ "PUSH14", Instruction::PUSH14 }, | ||||
| 	{ "PUSH15", Instruction::PUSH15 }, | ||||
| 	{ "PUSH16", Instruction::PUSH16 }, | ||||
| 	{ "PUSH17", Instruction::PUSH17 }, | ||||
| 	{ "PUSH18", Instruction::PUSH18 }, | ||||
| 	{ "PUSH19", Instruction::PUSH19 }, | ||||
| 	{ "PUSH20", Instruction::PUSH20 }, | ||||
| 	{ "PUSH21", Instruction::PUSH21 }, | ||||
| 	{ "PUSH22", Instruction::PUSH22 }, | ||||
| 	{ "PUSH23", Instruction::PUSH23 }, | ||||
| 	{ "PUSH24", Instruction::PUSH24 }, | ||||
| 	{ "PUSH25", Instruction::PUSH25 }, | ||||
| 	{ "PUSH26", Instruction::PUSH26 }, | ||||
| 	{ "PUSH27", Instruction::PUSH27 }, | ||||
| 	{ "PUSH28", Instruction::PUSH28 }, | ||||
| 	{ "PUSH29", Instruction::PUSH29 }, | ||||
| 	{ "PUSH30", Instruction::PUSH30 }, | ||||
| 	{ "PUSH31", Instruction::PUSH31 }, | ||||
| 	{ "PUSH32", Instruction::PUSH32 }, | ||||
| 	{ "DUP1", Instruction::DUP1 }, | ||||
| 	{ "DUP2", Instruction::DUP2 }, | ||||
| 	{ "DUP3", Instruction::DUP3 }, | ||||
| 	{ "DUP4", Instruction::DUP4 }, | ||||
| 	{ "DUP5", Instruction::DUP5 }, | ||||
| 	{ "DUP6", Instruction::DUP6 }, | ||||
| 	{ "DUP7", Instruction::DUP7 }, | ||||
| 	{ "DUP8", Instruction::DUP8 }, | ||||
| 	{ "DUP9", Instruction::DUP9 }, | ||||
| 	{ "DUP10", Instruction::DUP10 }, | ||||
| 	{ "DUP11", Instruction::DUP11 }, | ||||
| 	{ "DUP12", Instruction::DUP12 }, | ||||
| 	{ "DUP13", Instruction::DUP13 }, | ||||
| 	{ "DUP14", Instruction::DUP14 }, | ||||
| 	{ "DUP15", Instruction::DUP15 }, | ||||
| 	{ "DUP16", Instruction::DUP16 }, | ||||
| 	{ "SWAP1", Instruction::SWAP1 }, | ||||
| 	{ "SWAP2", Instruction::SWAP2 }, | ||||
| 	{ "SWAP3", Instruction::SWAP3 }, | ||||
| 	{ "SWAP4", Instruction::SWAP4 }, | ||||
| 	{ "SWAP5", Instruction::SWAP5 }, | ||||
| 	{ "SWAP6", Instruction::SWAP6 }, | ||||
| 	{ "SWAP7", Instruction::SWAP7 }, | ||||
| 	{ "SWAP8", Instruction::SWAP8 }, | ||||
| 	{ "SWAP9", Instruction::SWAP9 }, | ||||
| 	{ "SWAP10", Instruction::SWAP10 }, | ||||
| 	{ "SWAP11", Instruction::SWAP11 }, | ||||
| 	{ "SWAP12", Instruction::SWAP12 }, | ||||
| 	{ "SWAP13", Instruction::SWAP13 }, | ||||
| 	{ "SWAP14", Instruction::SWAP14 }, | ||||
| 	{ "SWAP15", Instruction::SWAP15 }, | ||||
| 	{ "SWAP16", Instruction::SWAP16 }, | ||||
| 	{ "LOG0", Instruction::LOG0 }, | ||||
| 	{ "LOG1", Instruction::LOG1 }, | ||||
| 	{ "LOG2", Instruction::LOG2 }, | ||||
| 	{ "LOG3", Instruction::LOG3 }, | ||||
| 	{ "LOG4", Instruction::LOG4 }, | ||||
| 	{ "CREATE", Instruction::CREATE }, | ||||
| 	{ "CALL", Instruction::CALL }, | ||||
| 	{ "CALLCODE", Instruction::CALLCODE }, | ||||
| 	{ "RETURN", Instruction::RETURN }, | ||||
| 	{ "DELEGATECALL", Instruction::DELEGATECALL }, | ||||
| 	{ "SUICIDE", Instruction::SUICIDE } | ||||
| }; | ||||
| 
 | ||||
| static const std::map<Instruction, InstructionInfo> c_instructionInfo = | ||||
| { //												Add, Args, Ret, SideEffects, GasPriceTier
 | ||||
| 	{ Instruction::STOP,		{ "STOP",			0, 0, 0, true, ZeroTier } }, | ||||
| 	{ Instruction::ADD,			{ "ADD",			0, 2, 1, false, VeryLowTier } }, | ||||
| 	{ Instruction::SUB,			{ "SUB",			0, 2, 1, false, VeryLowTier } }, | ||||
| 	{ Instruction::MUL,			{ "MUL",			0, 2, 1, false, LowTier } }, | ||||
| 	{ Instruction::DIV,			{ "DIV",			0, 2, 1, false, LowTier } }, | ||||
| 	{ Instruction::SDIV,		{ "SDIV",			0, 2, 1, false, LowTier } }, | ||||
| 	{ Instruction::MOD,			{ "MOD",			0, 2, 1, false, LowTier } }, | ||||
| 	{ Instruction::SMOD,		{ "SMOD",			0, 2, 1, false, LowTier } }, | ||||
| 	{ Instruction::EXP,			{ "EXP",			0, 2, 1, false, SpecialTier } }, | ||||
| 	{ Instruction::NOT,			{ "NOT",			0, 1, 1, false, VeryLowTier } }, | ||||
| 	{ Instruction::LT,			{ "LT",				0, 2, 1, false, VeryLowTier } }, | ||||
| 	{ Instruction::GT,			{ "GT",				0, 2, 1, false, VeryLowTier } }, | ||||
| 	{ Instruction::SLT,			{ "SLT",			0, 2, 1, false, VeryLowTier } }, | ||||
| 	{ Instruction::SGT,			{ "SGT",			0, 2, 1, false, VeryLowTier } }, | ||||
| 	{ Instruction::EQ,			{ "EQ",				0, 2, 1, false, VeryLowTier } }, | ||||
| 	{ Instruction::ISZERO,		{ "ISZERO",			0, 1, 1, false, VeryLowTier } }, | ||||
| 	{ Instruction::AND,			{ "AND",			0, 2, 1, false, VeryLowTier } }, | ||||
| 	{ Instruction::OR,			{ "OR",				0, 2, 1, false, VeryLowTier } }, | ||||
| 	{ Instruction::XOR,			{ "XOR",			0, 2, 1, false, VeryLowTier } }, | ||||
| 	{ Instruction::BYTE,		{ "BYTE",			0, 2, 1, false, VeryLowTier } }, | ||||
| 	{ Instruction::ADDMOD,		{ "ADDMOD",			0, 3, 1, false, MidTier } }, | ||||
| 	{ Instruction::MULMOD,		{ "MULMOD",			0, 3, 1, false, MidTier } }, | ||||
| 	{ Instruction::SIGNEXTEND,	{ "SIGNEXTEND",		0, 2, 1, false, LowTier } }, | ||||
| 	{ Instruction::SHA3,		{ "SHA3",			0, 2, 1, false, SpecialTier } }, | ||||
| 	{ Instruction::ADDRESS,		{ "ADDRESS",		0, 0, 1, false, BaseTier } }, | ||||
| 	{ Instruction::BALANCE,		{ "BALANCE",		0, 1, 1, false, ExtTier } }, | ||||
| 	{ Instruction::ORIGIN,		{ "ORIGIN",			0, 0, 1, false, BaseTier } }, | ||||
| 	{ Instruction::CALLER,		{ "CALLER",			0, 0, 1, false, BaseTier } }, | ||||
| 	{ Instruction::CALLVALUE,	{ "CALLVALUE",		0, 0, 1, false, BaseTier } }, | ||||
| 	{ Instruction::CALLDATALOAD,{ "CALLDATALOAD",	0, 1, 1, false, VeryLowTier } }, | ||||
| 	{ Instruction::CALLDATASIZE,{ "CALLDATASIZE",	0, 0, 1, false, BaseTier } }, | ||||
| 	{ Instruction::CALLDATACOPY,{ "CALLDATACOPY",	0, 3, 0, true, VeryLowTier } }, | ||||
| 	{ Instruction::CODESIZE,	{ "CODESIZE",		0, 0, 1, false, BaseTier } }, | ||||
| 	{ Instruction::CODECOPY,	{ "CODECOPY",		0, 3, 0, true, VeryLowTier } }, | ||||
| 	{ Instruction::GASPRICE,	{ "GASPRICE",		0, 0, 1, false, BaseTier } }, | ||||
| 	{ Instruction::EXTCODESIZE,	{ "EXTCODESIZE",	0, 1, 1, false, ExtTier } }, | ||||
| 	{ Instruction::EXTCODECOPY,	{ "EXTCODECOPY",	0, 4, 0, true, ExtTier } }, | ||||
| 	{ Instruction::BLOCKHASH,	{ "BLOCKHASH",		0, 1, 1, false, ExtTier } }, | ||||
| 	{ Instruction::COINBASE,	{ "COINBASE",		0, 0, 1, false, BaseTier } }, | ||||
| 	{ Instruction::TIMESTAMP,	{ "TIMESTAMP",		0, 0, 1, false, BaseTier } }, | ||||
| 	{ Instruction::NUMBER,		{ "NUMBER",			0, 0, 1, false, BaseTier } }, | ||||
| 	{ Instruction::DIFFICULTY,	{ "DIFFICULTY",		0, 0, 1, false, BaseTier } }, | ||||
| 	{ Instruction::GASLIMIT,	{ "GASLIMIT",		0, 0, 1, false, BaseTier } }, | ||||
| 	{ Instruction::POP,			{ "POP",			0, 1, 0, false, BaseTier } }, | ||||
| 	{ Instruction::MLOAD,		{ "MLOAD",			0, 1, 1, false, VeryLowTier } }, | ||||
| 	{ Instruction::MSTORE,		{ "MSTORE",			0, 2, 0, true, VeryLowTier } }, | ||||
| 	{ Instruction::MSTORE8,		{ "MSTORE8",		0, 2, 0, true, VeryLowTier } }, | ||||
| 	{ Instruction::SLOAD,		{ "SLOAD",			0, 1, 1, false, SpecialTier } }, | ||||
| 	{ Instruction::SSTORE,		{ "SSTORE",			0, 2, 0, true, SpecialTier } }, | ||||
| 	{ Instruction::JUMP,		{ "JUMP",			0, 1, 0, true, MidTier } }, | ||||
| 	{ Instruction::JUMPI,		{ "JUMPI",			0, 2, 0, true, HighTier } }, | ||||
| 	{ Instruction::PC,			{ "PC",				0, 0, 1, false, BaseTier } }, | ||||
| 	{ Instruction::MSIZE,		{ "MSIZE",			0, 0, 1, false, BaseTier } }, | ||||
| 	{ Instruction::GAS,			{ "GAS",			0, 0, 1, false, BaseTier } }, | ||||
| 	{ Instruction::JUMPDEST,	{ "JUMPDEST",		0, 0, 0, true, SpecialTier } }, | ||||
| 	{ Instruction::PUSH1,		{ "PUSH1",			1, 0, 1, false, VeryLowTier } }, | ||||
| 	{ Instruction::PUSH2,		{ "PUSH2",			2, 0, 1, false, VeryLowTier } }, | ||||
| 	{ Instruction::PUSH3,		{ "PUSH3",			3, 0, 1, false, VeryLowTier } }, | ||||
| 	{ Instruction::PUSH4,		{ "PUSH4",			4, 0, 1, false, VeryLowTier } }, | ||||
| 	{ Instruction::PUSH5,		{ "PUSH5",			5, 0, 1, false, VeryLowTier } }, | ||||
| 	{ Instruction::PUSH6,		{ "PUSH6",			6, 0, 1, false, VeryLowTier } }, | ||||
| 	{ Instruction::PUSH7,		{ "PUSH7",			7, 0, 1, false, VeryLowTier } }, | ||||
| 	{ Instruction::PUSH8,		{ "PUSH8",			8, 0, 1, false, VeryLowTier } }, | ||||
| 	{ Instruction::PUSH9,		{ "PUSH9",			9, 0, 1, false, VeryLowTier } }, | ||||
| 	{ Instruction::PUSH10,		{ "PUSH10",			10, 0, 1, false, VeryLowTier } }, | ||||
| 	{ Instruction::PUSH11,		{ "PUSH11",			11, 0, 1, false, VeryLowTier } }, | ||||
| 	{ Instruction::PUSH12,		{ "PUSH12",			12, 0, 1, false, VeryLowTier } }, | ||||
| 	{ Instruction::PUSH13,		{ "PUSH13",			13, 0, 1, false, VeryLowTier } }, | ||||
| 	{ Instruction::PUSH14,		{ "PUSH14",			14, 0, 1, false, VeryLowTier } }, | ||||
| 	{ Instruction::PUSH15,		{ "PUSH15",			15, 0, 1, false, VeryLowTier } }, | ||||
| 	{ Instruction::PUSH16,		{ "PUSH16",			16, 0, 1, false, VeryLowTier } }, | ||||
| 	{ Instruction::PUSH17,		{ "PUSH17",			17, 0, 1, false, VeryLowTier } }, | ||||
| 	{ Instruction::PUSH18,		{ "PUSH18",			18, 0, 1, false, VeryLowTier } }, | ||||
| 	{ Instruction::PUSH19,		{ "PUSH19",			19, 0, 1, false, VeryLowTier } }, | ||||
| 	{ Instruction::PUSH20,		{ "PUSH20",			20, 0, 1, false, VeryLowTier } }, | ||||
| 	{ Instruction::PUSH21,		{ "PUSH21",			21, 0, 1, false, VeryLowTier } }, | ||||
| 	{ Instruction::PUSH22,		{ "PUSH22",			22, 0, 1, false, VeryLowTier } }, | ||||
| 	{ Instruction::PUSH23,		{ "PUSH23",			23, 0, 1, false, VeryLowTier } }, | ||||
| 	{ Instruction::PUSH24,		{ "PUSH24",			24, 0, 1, false, VeryLowTier } }, | ||||
| 	{ Instruction::PUSH25,		{ "PUSH25",			25, 0, 1, false, VeryLowTier } }, | ||||
| 	{ Instruction::PUSH26,		{ "PUSH26",			26, 0, 1, false, VeryLowTier } }, | ||||
| 	{ Instruction::PUSH27,		{ "PUSH27",			27, 0, 1, false, VeryLowTier } }, | ||||
| 	{ Instruction::PUSH28,		{ "PUSH28",			28, 0, 1, false, VeryLowTier } }, | ||||
| 	{ Instruction::PUSH29,		{ "PUSH29",			29, 0, 1, false, VeryLowTier } }, | ||||
| 	{ Instruction::PUSH30,		{ "PUSH30",			30, 0, 1, false, VeryLowTier } }, | ||||
| 	{ Instruction::PUSH31,		{ "PUSH31",			31, 0, 1, false, VeryLowTier } }, | ||||
| 	{ Instruction::PUSH32,		{ "PUSH32",			32, 0, 1, false, VeryLowTier } }, | ||||
| 	{ Instruction::DUP1,		{ "DUP1",			0, 1, 2, false, VeryLowTier } }, | ||||
| 	{ Instruction::DUP2,		{ "DUP2",			0, 2, 3, false, VeryLowTier } }, | ||||
| 	{ Instruction::DUP3,		{ "DUP3",			0, 3, 4, false, VeryLowTier } }, | ||||
| 	{ Instruction::DUP4,		{ "DUP4",			0, 4, 5, false, VeryLowTier } }, | ||||
| 	{ Instruction::DUP5,		{ "DUP5",			0, 5, 6, false, VeryLowTier } }, | ||||
| 	{ Instruction::DUP6,		{ "DUP6",			0, 6, 7, false, VeryLowTier } }, | ||||
| 	{ Instruction::DUP7,		{ "DUP7",			0, 7, 8, false, VeryLowTier } }, | ||||
| 	{ Instruction::DUP8,		{ "DUP8",			0, 8, 9, false, VeryLowTier } }, | ||||
| 	{ Instruction::DUP9,		{ "DUP9",			0, 9, 10, false, VeryLowTier } }, | ||||
| 	{ Instruction::DUP10,		{ "DUP10",			0, 10, 11, false, VeryLowTier } }, | ||||
| 	{ Instruction::DUP11,		{ "DUP11",			0, 11, 12, false, VeryLowTier } }, | ||||
| 	{ Instruction::DUP12,		{ "DUP12",			0, 12, 13, false, VeryLowTier } }, | ||||
| 	{ Instruction::DUP13,		{ "DUP13",			0, 13, 14, false, VeryLowTier } }, | ||||
| 	{ Instruction::DUP14,		{ "DUP14",			0, 14, 15, false, VeryLowTier } }, | ||||
| 	{ Instruction::DUP15,		{ "DUP15",			0, 15, 16, false, VeryLowTier } }, | ||||
| 	{ Instruction::DUP16,		{ "DUP16",			0, 16, 17, false, VeryLowTier } }, | ||||
| 	{ Instruction::SWAP1,		{ "SWAP1",			0, 2, 2, false, VeryLowTier } }, | ||||
| 	{ Instruction::SWAP2,		{ "SWAP2",			0, 3, 3, false, VeryLowTier } }, | ||||
| 	{ Instruction::SWAP3,		{ "SWAP3",			0, 4, 4, false, VeryLowTier } }, | ||||
| 	{ Instruction::SWAP4,		{ "SWAP4",			0, 5, 5, false, VeryLowTier } }, | ||||
| 	{ Instruction::SWAP5,		{ "SWAP5",			0, 6, 6, false, VeryLowTier } }, | ||||
| 	{ Instruction::SWAP6,		{ "SWAP6",			0, 7, 7, false, VeryLowTier } }, | ||||
| 	{ Instruction::SWAP7,		{ "SWAP7",			0, 8, 8, false, VeryLowTier } }, | ||||
| 	{ Instruction::SWAP8,		{ "SWAP8",			0, 9, 9, false, VeryLowTier } }, | ||||
| 	{ Instruction::SWAP9,		{ "SWAP9",			0, 10, 10, false, VeryLowTier } }, | ||||
| 	{ Instruction::SWAP10,		{ "SWAP10",			0, 11, 11, false, VeryLowTier } }, | ||||
| 	{ Instruction::SWAP11,		{ "SWAP11",			0, 12, 12, false, VeryLowTier } }, | ||||
| 	{ Instruction::SWAP12,		{ "SWAP12",			0, 13, 13, false, VeryLowTier } }, | ||||
| 	{ Instruction::SWAP13,		{ "SWAP13",			0, 14, 14, false, VeryLowTier } }, | ||||
| 	{ Instruction::SWAP14,		{ "SWAP14",			0, 15, 15, false, VeryLowTier } }, | ||||
| 	{ Instruction::SWAP15,		{ "SWAP15",			0, 16, 16, false, VeryLowTier } }, | ||||
| 	{ Instruction::SWAP16,		{ "SWAP16",			0, 17, 17, false, VeryLowTier } }, | ||||
| 	{ Instruction::LOG0,		{ "LOG0",			0, 2, 0, true, SpecialTier } }, | ||||
| 	{ Instruction::LOG1,		{ "LOG1",			0, 3, 0, true, SpecialTier } }, | ||||
| 	{ Instruction::LOG2,		{ "LOG2",			0, 4, 0, true, SpecialTier } }, | ||||
| 	{ Instruction::LOG3,		{ "LOG3",			0, 5, 0, true, SpecialTier } }, | ||||
| 	{ Instruction::LOG4,		{ "LOG4",			0, 6, 0, true, SpecialTier } }, | ||||
| 	{ Instruction::CREATE,		{ "CREATE",			0, 3, 1, true, SpecialTier } }, | ||||
| 	{ Instruction::CALL,		{ "CALL",			0, 7, 1, true, SpecialTier } }, | ||||
| 	{ Instruction::CALLCODE,	{ "CALLCODE",		0, 7, 1, true, SpecialTier } }, | ||||
| 	{ Instruction::RETURN,		{ "RETURN",			0, 2, 0, true, ZeroTier } }, | ||||
| 	{ Instruction::DELEGATECALL,{ "DELEGATECALL",	0, 6, 1, true, SpecialTier } }, | ||||
| 	{ Instruction::SUICIDE,		{ "SUICIDE",		0, 1, 0, true, ZeroTier } } | ||||
| }; | ||||
| 
 | ||||
| void dev::solidity::eachInstruction( | ||||
| 	bytes const& _mem, | ||||
| 	function<void(Instruction,u256 const&)> const& _onInstruction | ||||
| ) | ||||
| { | ||||
| 	for (auto it = _mem.begin(); it < _mem.end(); ++it) | ||||
| 	{ | ||||
| 		Instruction instr = Instruction(*it); | ||||
| 		size_t additional = 0; | ||||
| 		if (isValidInstruction(instr)) | ||||
| 			additional = instructionInfo(instr).additional; | ||||
| 		u256 data; | ||||
| 		for (size_t i = 0; i < additional; ++i) | ||||
| 		{ | ||||
| 			data <<= 8; | ||||
| 			if (++it < _mem.end()) | ||||
| 				data |= *it; | ||||
| 		} | ||||
| 		_onInstruction(instr, data); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| string dev::solidity::disassemble(bytes const& _mem) | ||||
| { | ||||
| 	stringstream ret; | ||||
| 	eachInstruction(_mem, [&](Instruction _instr, u256 const& _data) { | ||||
| 		if (!isValidInstruction(_instr)) | ||||
| 			ret << "0x" << hex << int(_instr) << " "; | ||||
| 		else | ||||
| 		{ | ||||
| 			InstructionInfo info = instructionInfo(_instr); | ||||
| 			ret << info.name << " "; | ||||
| 			if (info.additional) | ||||
| 				ret << "0x" << hex << _data << " "; | ||||
| 		} | ||||
| 	}); | ||||
| 	return ret.str(); | ||||
| } | ||||
| 
 | ||||
| InstructionInfo dev::solidity::instructionInfo(Instruction _inst) | ||||
| { | ||||
| 	try | ||||
| 	{ | ||||
| 		return c_instructionInfo.at(_inst); | ||||
| 	} | ||||
| 	catch (...) | ||||
| 	{ | ||||
| 		return InstructionInfo({"<INVALID_INSTRUCTION: " + toString((unsigned)_inst) + ">", 0, 0, 0, false, InvalidTier}); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| bool dev::solidity::isValidInstruction(Instruction _inst) | ||||
| { | ||||
| 	return !!c_instructionInfo.count(_inst); | ||||
| } | ||||
							
								
								
									
										268
									
								
								libevmasm/Instruction.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										268
									
								
								libevmasm/Instruction.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,268 @@ | ||||
| /*
 | ||||
| 	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 Instruction.h
 | ||||
|  * @author Gav Wood <i@gavwood.com> | ||||
|  * @date 2014 | ||||
|  */ | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include <functional> | ||||
| #include <libdevcore/Common.h> | ||||
| #include <libdevcore/Assertions.h> | ||||
| #include "Exceptions.h" | ||||
| 
 | ||||
| namespace dev | ||||
| { | ||||
| namespace solidity | ||||
| { | ||||
| 
 | ||||
| DEV_SIMPLE_EXCEPTION(InvalidDeposit); | ||||
| DEV_SIMPLE_EXCEPTION(InvalidOpcode); | ||||
| 
 | ||||
| /// Virtual machine bytecode instruction.
 | ||||
| enum class Instruction: uint8_t | ||||
| { | ||||
| 	STOP = 0x00,		///< halts execution
 | ||||
| 	ADD,				///< addition operation
 | ||||
| 	MUL,				///< mulitplication operation
 | ||||
| 	SUB,				///< subtraction operation
 | ||||
| 	DIV,				///< integer division operation
 | ||||
| 	SDIV,				///< signed integer division operation
 | ||||
| 	MOD,				///< modulo remainder operation
 | ||||
| 	SMOD,				///< signed modulo remainder operation
 | ||||
| 	ADDMOD,				///< unsigned modular addition
 | ||||
| 	MULMOD,				///< unsigned modular multiplication
 | ||||
| 	EXP,				///< exponential operation
 | ||||
| 	SIGNEXTEND,			///< extend length of signed integer
 | ||||
| 
 | ||||
| 	LT = 0x10,			///< less-than comparision
 | ||||
| 	GT,					///< greater-than comparision
 | ||||
| 	SLT,				///< signed less-than comparision
 | ||||
| 	SGT,				///< signed greater-than comparision
 | ||||
| 	EQ,					///< equality comparision
 | ||||
| 	ISZERO,				///< simple not operator
 | ||||
| 	AND,				///< bitwise AND operation
 | ||||
| 	OR,					///< bitwise OR operation
 | ||||
| 	XOR,				///< bitwise XOR operation
 | ||||
| 	NOT,				///< bitwise NOT opertation
 | ||||
| 	BYTE,				///< retrieve single byte from word
 | ||||
| 
 | ||||
| 	SHA3 = 0x20,		///< compute SHA3-256 hash
 | ||||
| 
 | ||||
| 	ADDRESS = 0x30,		///< get address of currently executing account
 | ||||
| 	BALANCE,			///< get balance of the given account
 | ||||
| 	ORIGIN,				///< get execution origination address
 | ||||
| 	CALLER,				///< get caller address
 | ||||
| 	CALLVALUE,			///< get deposited value by the instruction/transaction responsible for this execution
 | ||||
| 	CALLDATALOAD,		///< get input data of current environment
 | ||||
| 	CALLDATASIZE,		///< get size of input data in current environment
 | ||||
| 	CALLDATACOPY,		///< copy input data in current environment to memory
 | ||||
| 	CODESIZE,			///< get size of code running in current environment
 | ||||
| 	CODECOPY,			///< copy code running in current environment to memory
 | ||||
| 	GASPRICE,			///< get price of gas in current environment
 | ||||
| 	EXTCODESIZE,		///< get external code size (from another contract)
 | ||||
| 	EXTCODECOPY,		///< copy external code (from another contract)
 | ||||
| 
 | ||||
| 	BLOCKHASH = 0x40,	///< get hash of most recent complete block
 | ||||
| 	COINBASE,			///< get the block's coinbase address
 | ||||
| 	TIMESTAMP,			///< get the block's timestamp
 | ||||
| 	NUMBER,				///< get the block's number
 | ||||
| 	DIFFICULTY,			///< get the block's difficulty
 | ||||
| 	GASLIMIT,			///< get the block's gas limit
 | ||||
| 
 | ||||
| 	POP = 0x50,			///< remove item from stack
 | ||||
| 	MLOAD,				///< load word from memory
 | ||||
| 	MSTORE,				///< save word to memory
 | ||||
| 	MSTORE8,			///< save byte to memory
 | ||||
| 	SLOAD,				///< load word from storage
 | ||||
| 	SSTORE,				///< save word to storage
 | ||||
| 	JUMP,				///< alter the program counter
 | ||||
| 	JUMPI,				///< conditionally alter the program counter
 | ||||
| 	PC,					///< get the program counter
 | ||||
| 	MSIZE,				///< get the size of active memory
 | ||||
| 	GAS,				///< get the amount of available gas
 | ||||
| 	JUMPDEST,			///< set a potential jump destination
 | ||||
| 
 | ||||
| 	PUSH1 = 0x60,		///< place 1 byte item on stack
 | ||||
| 	PUSH2,				///< place 2 byte item on stack
 | ||||
| 	PUSH3,				///< place 3 byte item on stack
 | ||||
| 	PUSH4,				///< place 4 byte item on stack
 | ||||
| 	PUSH5,				///< place 5 byte item on stack
 | ||||
| 	PUSH6,				///< place 6 byte item on stack
 | ||||
| 	PUSH7,				///< place 7 byte item on stack
 | ||||
| 	PUSH8,				///< place 8 byte item on stack
 | ||||
| 	PUSH9,				///< place 9 byte item on stack
 | ||||
| 	PUSH10,				///< place 10 byte item on stack
 | ||||
| 	PUSH11,				///< place 11 byte item on stack
 | ||||
| 	PUSH12,				///< place 12 byte item on stack
 | ||||
| 	PUSH13,				///< place 13 byte item on stack
 | ||||
| 	PUSH14,				///< place 14 byte item on stack
 | ||||
| 	PUSH15,				///< place 15 byte item on stack
 | ||||
| 	PUSH16,				///< place 16 byte item on stack
 | ||||
| 	PUSH17,				///< place 17 byte item on stack
 | ||||
| 	PUSH18,				///< place 18 byte item on stack
 | ||||
| 	PUSH19,				///< place 19 byte item on stack
 | ||||
| 	PUSH20,				///< place 20 byte item on stack
 | ||||
| 	PUSH21,				///< place 21 byte item on stack
 | ||||
| 	PUSH22,				///< place 22 byte item on stack
 | ||||
| 	PUSH23,				///< place 23 byte item on stack
 | ||||
| 	PUSH24,				///< place 24 byte item on stack
 | ||||
| 	PUSH25,				///< place 25 byte item on stack
 | ||||
| 	PUSH26,				///< place 26 byte item on stack
 | ||||
| 	PUSH27,				///< place 27 byte item on stack
 | ||||
| 	PUSH28,				///< place 28 byte item on stack
 | ||||
| 	PUSH29,				///< place 29 byte item on stack
 | ||||
| 	PUSH30,				///< place 30 byte item on stack
 | ||||
| 	PUSH31,				///< place 31 byte item on stack
 | ||||
| 	PUSH32,				///< place 32 byte item on stack
 | ||||
| 
 | ||||
| 	DUP1 = 0x80,		///< copies the highest item in the stack to the top of the stack
 | ||||
| 	DUP2,				///< copies the second highest item in the stack to the top of the stack
 | ||||
| 	DUP3,				///< copies the third highest item in the stack to the top of the stack
 | ||||
| 	DUP4,				///< copies the 4th highest item in the stack to the top of the stack
 | ||||
| 	DUP5,				///< copies the 5th highest item in the stack to the top of the stack
 | ||||
| 	DUP6,				///< copies the 6th highest item in the stack to the top of the stack
 | ||||
| 	DUP7,				///< copies the 7th highest item in the stack to the top of the stack
 | ||||
| 	DUP8,				///< copies the 8th highest item in the stack to the top of the stack
 | ||||
| 	DUP9,				///< copies the 9th highest item in the stack to the top of the stack
 | ||||
| 	DUP10,				///< copies the 10th highest item in the stack to the top of the stack
 | ||||
| 	DUP11,				///< copies the 11th highest item in the stack to the top of the stack
 | ||||
| 	DUP12,				///< copies the 12th highest item in the stack to the top of the stack
 | ||||
| 	DUP13,				///< copies the 13th highest item in the stack to the top of the stack
 | ||||
| 	DUP14,				///< copies the 14th highest item in the stack to the top of the stack
 | ||||
| 	DUP15,				///< copies the 15th highest item in the stack to the top of the stack
 | ||||
| 	DUP16,				///< copies the 16th highest item in the stack to the top of the stack
 | ||||
| 
 | ||||
| 	SWAP1 = 0x90,		///< swaps the highest and second highest value on the stack
 | ||||
| 	SWAP2,				///< swaps the highest and third highest value on the stack
 | ||||
| 	SWAP3,				///< swaps the highest and 4th highest value on the stack
 | ||||
| 	SWAP4,				///< swaps the highest and 5th highest value on the stack
 | ||||
| 	SWAP5,				///< swaps the highest and 6th highest value on the stack
 | ||||
| 	SWAP6,				///< swaps the highest and 7th highest value on the stack
 | ||||
| 	SWAP7,				///< swaps the highest and 8th highest value on the stack
 | ||||
| 	SWAP8,				///< swaps the highest and 9th highest value on the stack
 | ||||
| 	SWAP9,				///< swaps the highest and 10th highest value on the stack
 | ||||
| 	SWAP10,				///< swaps the highest and 11th highest value on the stack
 | ||||
| 	SWAP11,				///< swaps the highest and 12th highest value on the stack
 | ||||
| 	SWAP12,				///< swaps the highest and 13th highest value on the stack
 | ||||
| 	SWAP13,				///< swaps the highest and 14th highest value on the stack
 | ||||
| 	SWAP14,				///< swaps the highest and 15th highest value on the stack
 | ||||
| 	SWAP15,				///< swaps the highest and 16th highest value on the stack
 | ||||
| 	SWAP16,				///< swaps the highest and 17th highest value on the stack
 | ||||
| 
 | ||||
| 	LOG0 = 0xa0,		///< Makes a log entry; no topics.
 | ||||
| 	LOG1,				///< Makes a log entry; 1 topic.
 | ||||
| 	LOG2,				///< Makes a log entry; 2 topics.
 | ||||
| 	LOG3,				///< Makes a log entry; 3 topics.
 | ||||
| 	LOG4,				///< Makes a log entry; 4 topics.
 | ||||
| 
 | ||||
| 	CREATE = 0xf0,		///< create a new account with associated code
 | ||||
| 	CALL,				///< message-call into an account
 | ||||
| 	CALLCODE,			///< message-call with another account's code only
 | ||||
| 	RETURN,				///< halt execution returning output data
 | ||||
| 	DELEGATECALL,		///< like CALLCODE but keeps caller's value and sender
 | ||||
| 	SUICIDE = 0xff		///< halt execution and register account for later deletion
 | ||||
| }; | ||||
| 
 | ||||
| /// @returns the number of PUSH Instruction _inst
 | ||||
| inline unsigned getPushNumber(Instruction _inst) | ||||
| { | ||||
| 	return (byte)_inst - unsigned(Instruction::PUSH1) + 1; | ||||
| } | ||||
| 
 | ||||
| /// @returns the number of DUP Instruction _inst
 | ||||
| inline unsigned getDupNumber(Instruction _inst) | ||||
| { | ||||
| 	return (byte)_inst - unsigned(Instruction::DUP1) + 1; | ||||
| } | ||||
| 
 | ||||
| /// @returns the number of SWAP Instruction _inst
 | ||||
| inline unsigned getSwapNumber(Instruction _inst) | ||||
| { | ||||
| 	return (byte)_inst - unsigned(Instruction::SWAP1) + 1; | ||||
| } | ||||
| 
 | ||||
| /// @returns the PUSH<_number> instruction
 | ||||
| inline Instruction pushInstruction(unsigned _number) | ||||
| { | ||||
| 	assertThrow(1 <= _number && _number <= 32, InvalidOpcode, "Invalid PUSH instruction requested."); | ||||
| 	return Instruction(unsigned(Instruction::PUSH1) + _number - 1); | ||||
| } | ||||
| 
 | ||||
| /// @returns the DUP<_number> instruction
 | ||||
| inline Instruction dupInstruction(unsigned _number) | ||||
| { | ||||
| 	assertThrow(1 <= _number && _number <= 16, InvalidOpcode, "Invalid DUP instruction requested."); | ||||
| 	return Instruction(unsigned(Instruction::DUP1) + _number - 1); | ||||
| } | ||||
| 
 | ||||
| /// @returns the SWAP<_number> instruction
 | ||||
| inline Instruction swapInstruction(unsigned _number) | ||||
| { | ||||
| 	assertThrow(1 <= _number && _number <= 16, InvalidOpcode, "Invalid SWAP instruction requested."); | ||||
| 	return Instruction(unsigned(Instruction::SWAP1) + _number - 1); | ||||
| } | ||||
| 
 | ||||
| /// @returns the LOG<_number> instruction
 | ||||
| inline Instruction logInstruction(unsigned _number) | ||||
| { | ||||
| 	assertThrow(_number <= 4, InvalidOpcode, "Invalid LOG instruction requested."); | ||||
| 	return Instruction(unsigned(Instruction::LOG0) + _number); | ||||
| } | ||||
| 
 | ||||
| enum Tier | ||||
| { | ||||
| 	ZeroTier = 0,	// 0, Zero
 | ||||
| 	BaseTier,		// 2, Quick
 | ||||
| 	VeryLowTier,	// 3, Fastest
 | ||||
| 	LowTier,		// 5, Fast
 | ||||
| 	MidTier,		// 8, Mid
 | ||||
| 	HighTier,		// 10, Slow
 | ||||
| 	ExtTier,		// 20, Ext
 | ||||
| 	SpecialTier,	// multiparam or otherwise special
 | ||||
| 	InvalidTier		// Invalid.
 | ||||
| }; | ||||
| 
 | ||||
| /// Information structure for a particular instruction.
 | ||||
| struct InstructionInfo | ||||
| { | ||||
| 	std::string name;	///< The name of the instruction.
 | ||||
| 	int additional;		///< Additional items required in memory for this instructions (only for PUSH).
 | ||||
| 	int args;			///< Number of items required on the stack for this instruction (and, for the purposes of ret, the number taken from the stack).
 | ||||
| 	int ret;			///< Number of items placed (back) on the stack by this instruction, assuming args items were removed.
 | ||||
| 	bool sideEffects;	///< false if the only effect on the execution environment (apart from gas usage) is a change to a topmost segment of the stack
 | ||||
| 	int gasPriceTier;	///< Tier for gas pricing.
 | ||||
| }; | ||||
| 
 | ||||
| /// Information on all the instructions.
 | ||||
| InstructionInfo instructionInfo(Instruction _inst); | ||||
| 
 | ||||
| /// check whether instructions exists
 | ||||
| bool isValidInstruction(Instruction _inst); | ||||
| 
 | ||||
| /// Convert from string mnemonic to Instruction type.
 | ||||
| extern const std::map<std::string, Instruction> c_instructions; | ||||
| 
 | ||||
| /// Iterate through EVM code and call a function on each instruction.
 | ||||
| void eachInstruction(bytes const& _mem, std::function<void(Instruction,u256 const&)> const& _onInstruction); | ||||
| 
 | ||||
| /// Convert from EVM code to simple EVM assembly language.
 | ||||
| std::string disassemble(bytes const& _mem); | ||||
| 
 | ||||
| } | ||||
| } | ||||
| @ -76,7 +76,7 @@ GasMeter::GasConsumption PathGasMeter::handleQueueItem() | ||||
| 		bool branchStops = false; | ||||
| 		jumpTags.clear(); | ||||
| 		AssemblyItem const& item = m_items.at(index); | ||||
| 		if (item.type() == Tag || item == AssemblyItem(eth::Instruction::JUMPDEST)) | ||||
| 		if (item.type() == Tag || item == AssemblyItem(Instruction::JUMPDEST)) | ||||
| 		{ | ||||
| 			// Do not allow any backwards jump. This is quite restrictive but should work for
 | ||||
| 			// the simplest things.
 | ||||
| @ -84,14 +84,14 @@ GasMeter::GasConsumption PathGasMeter::handleQueueItem() | ||||
| 				return GasMeter::GasConsumption::infinite(); | ||||
| 			path->visitedJumpdests.insert(index); | ||||
| 		} | ||||
| 		else if (item == AssemblyItem(eth::Instruction::JUMP)) | ||||
| 		else if (item == AssemblyItem(Instruction::JUMP)) | ||||
| 		{ | ||||
| 			branchStops = true; | ||||
| 			jumpTags = state->tagsInExpression(state->relativeStackElement(0)); | ||||
| 			if (jumpTags.empty()) // unknown jump destination
 | ||||
| 				return GasMeter::GasConsumption::infinite(); | ||||
| 		} | ||||
| 		else if (item == AssemblyItem(eth::Instruction::JUMPI)) | ||||
| 		else if (item == AssemblyItem(Instruction::JUMPI)) | ||||
| 		{ | ||||
| 			ExpressionClasses::Id condition = state->relativeStackElement(-1); | ||||
| 			if (classes.knownNonZero(condition) || !classes.knownZero(condition)) | ||||
|  | ||||
| @ -23,7 +23,7 @@ | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include <libevmcore/Instruction.h> | ||||
| #include <libevmasm/Instruction.h> | ||||
| 
 | ||||
| namespace dev | ||||
| { | ||||
| @ -50,9 +50,9 @@ struct SemanticInformation | ||||
| 	/// the information in the current block header, memory, storage or stack.
 | ||||
| 	static bool isDeterministic(AssemblyItem const& _item); | ||||
| 	/// @returns true if the given instruction modifies memory.
 | ||||
| 	static bool invalidatesMemory(Instruction _instruction); | ||||
| 	static bool invalidatesMemory(solidity::Instruction _instruction); | ||||
| 	/// @returns true if the given instruction modifies storage (even indirectly).
 | ||||
| 	static bool invalidatesStorage(Instruction _instruction); | ||||
| 	static bool invalidatesStorage(solidity::Instruction _instruction); | ||||
| }; | ||||
| 
 | ||||
| } | ||||
|  | ||||
| @ -30,7 +30,7 @@ | ||||
| #pragma GCC diagnostic pop | ||||
| #include <libdevcore/Log.h> | ||||
| #include <libdevcore/CommonIO.h> | ||||
| #include <libevmcore/Instruction.h> | ||||
| #include <libevmasm/Instruction.h> | ||||
| #include "CompilerState.h" | ||||
| #include "Parser.h" | ||||
| using namespace std; | ||||
|  | ||||
| @ -22,7 +22,7 @@ | ||||
| #pragma once | ||||
| 
 | ||||
| #include <libdevcore/Common.h> | ||||
| #include <libevmcore/Instruction.h> | ||||
| #include <libevmasm/Instruction.h> | ||||
| #include <libevmasm/Assembly.h> | ||||
| #include "Exceptions.h" | ||||
| 
 | ||||
|  | ||||
| @ -595,7 +595,7 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly) | ||||
| 				if (!varDecl->isLocalVariable()) | ||||
| 					return false; // only local variables are inline-assemlby lvalues
 | ||||
| 				for (unsigned i = 0; i < declaration->type()->sizeOnStack(); ++i) | ||||
| 					_assembly.append(eth::Instruction::POP); // remove value just to verify the stack height
 | ||||
| 					_assembly.append(Instruction::POP); // remove value just to verify the stack height
 | ||||
| 			} | ||||
| 			else | ||||
| 				return false; | ||||
|  | ||||
| @ -28,7 +28,7 @@ | ||||
| #include <memory> | ||||
| #include <boost/noncopyable.hpp> | ||||
| #include <libevmasm/SourceLocation.h> | ||||
| #include <libevmcore/Instruction.h> | ||||
| #include <libevmasm/Instruction.h> | ||||
| #include <libsolidity/interface/Utils.h> | ||||
| #include <libsolidity/ast/ASTForward.h> | ||||
| #include <libsolidity/parsing/Token.h> | ||||
|  | ||||
| @ -21,7 +21,7 @@ | ||||
|  */ | ||||
| 
 | ||||
| #include <libsolidity/codegen/ArrayUtils.h> | ||||
| #include <libevmcore/Instruction.h> | ||||
| #include <libevmasm/Instruction.h> | ||||
| #include <libsolidity/codegen/CompilerContext.h> | ||||
| #include <libsolidity/codegen/CompilerUtils.h> | ||||
| #include <libsolidity/ast/Types.h> | ||||
| @ -56,7 +56,7 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons | ||||
| 	// stack: source_ref [source_length] target_ref
 | ||||
| 	// store target_ref
 | ||||
| 	for (unsigned i = _sourceType.sizeOnStack(); i > 0; --i) | ||||
| 		m_context << eth::swapInstruction(i); | ||||
| 		m_context << swapInstruction(i); | ||||
| 	// stack: target_ref source_ref [source_length]
 | ||||
| 	// stack: target_ref source_ref [source_length]
 | ||||
| 	// retrieve source length
 | ||||
| @ -65,12 +65,12 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons | ||||
| 	if (_sourceType.location() == DataLocation::Memory && _sourceType.isDynamicallySized()) | ||||
| 	{ | ||||
| 		// increment source pointer to point to data
 | ||||
| 		m_context << eth::Instruction::SWAP1 << u256(0x20); | ||||
| 		m_context << eth::Instruction::ADD << eth::Instruction::SWAP1; | ||||
| 		m_context << Instruction::SWAP1 << u256(0x20); | ||||
| 		m_context << Instruction::ADD << Instruction::SWAP1; | ||||
| 	} | ||||
| 
 | ||||
| 	// stack: target_ref source_ref source_length
 | ||||
| 	m_context << eth::Instruction::DUP3; | ||||
| 	m_context << Instruction::DUP3; | ||||
| 	// stack: target_ref source_ref source_length target_ref
 | ||||
| 	retrieveLength(_targetType); | ||||
| 	// stack: target_ref source_ref source_length target_ref target_length
 | ||||
| @ -78,28 +78,28 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons | ||||
| 		// store new target length
 | ||||
| 		if (!_targetType.isByteArray()) | ||||
| 			// Otherwise, length will be stored below.
 | ||||
| 			m_context << eth::Instruction::DUP3 << eth::Instruction::DUP3 << eth::Instruction::SSTORE; | ||||
| 			m_context << Instruction::DUP3 << Instruction::DUP3 << Instruction::SSTORE; | ||||
| 	if (sourceBaseType->category() == Type::Category::Mapping) | ||||
| 	{ | ||||
| 		solAssert(targetBaseType->category() == Type::Category::Mapping, ""); | ||||
| 		solAssert(_sourceType.location() == DataLocation::Storage, ""); | ||||
| 		// nothing to copy
 | ||||
| 		m_context | ||||
| 			<< eth::Instruction::POP << eth::Instruction::POP | ||||
| 			<< eth::Instruction::POP << eth::Instruction::POP; | ||||
| 			<< Instruction::POP << Instruction::POP | ||||
| 			<< Instruction::POP << Instruction::POP; | ||||
| 		return; | ||||
| 	} | ||||
| 	// stack: target_ref source_ref source_length target_ref target_length
 | ||||
| 	// compute hashes (data positions)
 | ||||
| 	m_context << eth::Instruction::SWAP1; | ||||
| 	m_context << Instruction::SWAP1; | ||||
| 	if (_targetType.isDynamicallySized()) | ||||
| 		CompilerUtils(m_context).computeHashStatic(); | ||||
| 	// stack: target_ref source_ref source_length target_length target_data_pos
 | ||||
| 	m_context << eth::Instruction::SWAP1; | ||||
| 	m_context << Instruction::SWAP1; | ||||
| 	convertLengthToSize(_targetType); | ||||
| 	m_context << eth::Instruction::DUP2 << eth::Instruction::ADD; | ||||
| 	m_context << Instruction::DUP2 << Instruction::ADD; | ||||
| 	// stack: target_ref source_ref source_length target_data_pos target_data_end
 | ||||
| 	m_context << eth::Instruction::SWAP3; | ||||
| 	m_context << Instruction::SWAP3; | ||||
| 	// stack: target_ref target_data_end source_length target_data_pos source_ref
 | ||||
| 
 | ||||
| 	eth::AssemblyItem copyLoopEndWithoutByteOffset = m_context.newTag(); | ||||
| @ -108,47 +108,47 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons | ||||
| 	if (_targetType.isByteArray()) | ||||
| 	{ | ||||
| 		// stack: target_ref target_data_end source_length target_data_pos source_ref
 | ||||
| 		m_context << eth::Instruction::DUP3 << u256(31) << eth::Instruction::LT; | ||||
| 		m_context << Instruction::DUP3 << u256(31) << Instruction::LT; | ||||
| 		eth::AssemblyItem longByteArray = m_context.appendConditionalJump(); | ||||
| 		// store the short byte array
 | ||||
| 		solAssert(_sourceType.isByteArray(), ""); | ||||
| 		if (_sourceType.location() == DataLocation::Storage) | ||||
| 		{ | ||||
| 			// just copy the slot, it contains length and data
 | ||||
| 			m_context << eth::Instruction::DUP1 << eth::Instruction::SLOAD; | ||||
| 			m_context << eth::Instruction::DUP6 << eth::Instruction::SSTORE; | ||||
| 			m_context << Instruction::DUP1 << Instruction::SLOAD; | ||||
| 			m_context << Instruction::DUP6 << Instruction::SSTORE; | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			m_context << eth::Instruction::DUP1; | ||||
| 			m_context << Instruction::DUP1; | ||||
| 			CompilerUtils(m_context).loadFromMemoryDynamic(*sourceBaseType, fromCalldata, true, false); | ||||
| 			// stack: target_ref target_data_end source_length target_data_pos source_ref value
 | ||||
| 			// clear the lower-order byte - which will hold the length
 | ||||
| 			m_context << u256(0xff) << eth::Instruction::NOT << eth::Instruction::AND; | ||||
| 			m_context << u256(0xff) << Instruction::NOT << Instruction::AND; | ||||
| 			// fetch the length and shift it left by one
 | ||||
| 			m_context << eth::Instruction::DUP4 << eth::Instruction::DUP1 << eth::Instruction::ADD; | ||||
| 			m_context << Instruction::DUP4 << Instruction::DUP1 << Instruction::ADD; | ||||
| 			// combine value and length and store them
 | ||||
| 			m_context << eth::Instruction::OR << eth::Instruction::DUP6 << eth::Instruction::SSTORE; | ||||
| 			m_context << Instruction::OR << Instruction::DUP6 << Instruction::SSTORE; | ||||
| 		} | ||||
| 		// end of special case, jump right into cleaning target data area
 | ||||
| 		m_context.appendJumpTo(copyLoopEndWithoutByteOffset); | ||||
| 		m_context << longByteArray; | ||||
| 		// Store length (2*length+1)
 | ||||
| 		m_context << eth::Instruction::DUP3 << eth::Instruction::DUP1 << eth::Instruction::ADD; | ||||
| 		m_context << u256(1) << eth::Instruction::ADD; | ||||
| 		m_context << eth::Instruction::DUP6 << eth::Instruction::SSTORE; | ||||
| 		m_context << Instruction::DUP3 << Instruction::DUP1 << Instruction::ADD; | ||||
| 		m_context << u256(1) << Instruction::ADD; | ||||
| 		m_context << Instruction::DUP6 << Instruction::SSTORE; | ||||
| 	} | ||||
| 
 | ||||
| 	// skip copying if source length is zero
 | ||||
| 	m_context << eth::Instruction::DUP3 << eth::Instruction::ISZERO; | ||||
| 	m_context << Instruction::DUP3 << Instruction::ISZERO; | ||||
| 	m_context.appendConditionalJumpTo(copyLoopEndWithoutByteOffset); | ||||
| 
 | ||||
| 	if (_sourceType.location() == DataLocation::Storage && _sourceType.isDynamicallySized()) | ||||
| 		CompilerUtils(m_context).computeHashStatic(); | ||||
| 	// stack: target_ref target_data_end source_length target_data_pos source_data_pos
 | ||||
| 	m_context << eth::Instruction::SWAP2; | ||||
| 	m_context << Instruction::SWAP2; | ||||
| 	convertLengthToSize(_sourceType); | ||||
| 	m_context << eth::Instruction::DUP3 << eth::Instruction::ADD; | ||||
| 	m_context << Instruction::DUP3 << Instruction::ADD; | ||||
| 	// stack: target_ref target_data_end source_data_pos target_data_pos source_data_end
 | ||||
| 	if (haveByteOffsetTarget) | ||||
| 		m_context << u256(0); | ||||
| @ -159,8 +159,8 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons | ||||
| 	m_context << copyLoopStart; | ||||
| 	// check for loop condition
 | ||||
| 	m_context | ||||
| 		<< eth::dupInstruction(3 + byteOffsetSize) << eth::dupInstruction(2 + byteOffsetSize) | ||||
| 		<< eth::Instruction::GT << eth::Instruction::ISZERO; | ||||
| 		<< dupInstruction(3 + byteOffsetSize) << dupInstruction(2 + byteOffsetSize) | ||||
| 		<< Instruction::GT << Instruction::ISZERO; | ||||
| 	eth::AssemblyItem copyLoopEnd = m_context.appendConditionalJump(); | ||||
| 	// stack: target_ref target_data_end source_data_pos target_data_pos source_data_end [target_byte_offset] [source_byte_offset]
 | ||||
| 	// copy
 | ||||
| @ -168,19 +168,19 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons | ||||
| 	{ | ||||
| 		solAssert(byteOffsetSize == 0, "Byte offset for array as base type."); | ||||
| 		auto const& sourceBaseArrayType = dynamic_cast<ArrayType const&>(*sourceBaseType); | ||||
| 		m_context << eth::Instruction::DUP3; | ||||
| 		m_context << Instruction::DUP3; | ||||
| 		if (sourceBaseArrayType.location() == DataLocation::Memory) | ||||
| 			m_context << eth::Instruction::MLOAD; | ||||
| 		m_context << eth::Instruction::DUP3; | ||||
| 			m_context << Instruction::MLOAD; | ||||
| 		m_context << Instruction::DUP3; | ||||
| 		copyArrayToStorage(dynamic_cast<ArrayType const&>(*targetBaseType), sourceBaseArrayType); | ||||
| 		m_context << eth::Instruction::POP; | ||||
| 		m_context << Instruction::POP; | ||||
| 	} | ||||
| 	else if (directCopy) | ||||
| 	{ | ||||
| 		solAssert(byteOffsetSize == 0, "Byte offset for direct copy."); | ||||
| 		m_context | ||||
| 			<< eth::Instruction::DUP3 << eth::Instruction::SLOAD | ||||
| 			<< eth::Instruction::DUP3 << eth::Instruction::SSTORE; | ||||
| 			<< Instruction::DUP3 << Instruction::SLOAD | ||||
| 			<< Instruction::DUP3 << Instruction::SSTORE; | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| @ -188,11 +188,11 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons | ||||
| 		// We might copy too much if there is padding at the last element, but this way end
 | ||||
| 		// checking is easier.
 | ||||
| 		// stack: target_ref target_data_end source_data_pos target_data_pos source_data_end [target_byte_offset] [source_byte_offset]
 | ||||
| 		m_context << eth::dupInstruction(3 + byteOffsetSize); | ||||
| 		m_context << dupInstruction(3 + byteOffsetSize); | ||||
| 		if (_sourceType.location() == DataLocation::Storage) | ||||
| 		{ | ||||
| 			if (haveByteOffsetSource) | ||||
| 				m_context << eth::Instruction::DUP2; | ||||
| 				m_context << Instruction::DUP2; | ||||
| 			else | ||||
| 				m_context << u256(0); | ||||
| 			StorageItem(m_context, *sourceBaseType).retrieveValue(SourceLocation(), true); | ||||
| @ -207,9 +207,9 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons | ||||
| 			"Stack too deep, try removing local variables." | ||||
| 		); | ||||
| 		// fetch target storage reference
 | ||||
| 		m_context << eth::dupInstruction(2 + byteOffsetSize + sourceBaseType->sizeOnStack()); | ||||
| 		m_context << dupInstruction(2 + byteOffsetSize + sourceBaseType->sizeOnStack()); | ||||
| 		if (haveByteOffsetTarget) | ||||
| 			m_context << eth::dupInstruction(1 + byteOffsetSize + sourceBaseType->sizeOnStack()); | ||||
| 			m_context << dupInstruction(1 + byteOffsetSize + sourceBaseType->sizeOnStack()); | ||||
| 		else | ||||
| 			m_context << u256(0); | ||||
| 		StorageItem(m_context, *targetBaseType).storeValue(*sourceBaseType, SourceLocation(), true); | ||||
| @ -220,7 +220,7 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons | ||||
| 		incrementByteOffset(sourceBaseType->storageBytes(), 1, haveByteOffsetTarget ? 5 : 4); | ||||
| 	else | ||||
| 	{ | ||||
| 		m_context << eth::swapInstruction(2 + byteOffsetSize); | ||||
| 		m_context << swapInstruction(2 + byteOffsetSize); | ||||
| 		if (sourceIsStorage) | ||||
| 			m_context << sourceBaseType->storageSize(); | ||||
| 		else if (_sourceType.location() == DataLocation::Memory) | ||||
| @ -228,44 +228,44 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons | ||||
| 		else | ||||
| 			m_context << sourceBaseType->calldataEncodedSize(true); | ||||
| 		m_context | ||||
| 			<< eth::Instruction::ADD | ||||
| 			<< eth::swapInstruction(2 + byteOffsetSize); | ||||
| 			<< Instruction::ADD | ||||
| 			<< swapInstruction(2 + byteOffsetSize); | ||||
| 	} | ||||
| 	// increment target
 | ||||
| 	if (haveByteOffsetTarget) | ||||
| 		incrementByteOffset(targetBaseType->storageBytes(), byteOffsetSize, byteOffsetSize + 2); | ||||
| 	else | ||||
| 		m_context | ||||
| 			<< eth::swapInstruction(1 + byteOffsetSize) | ||||
| 			<< swapInstruction(1 + byteOffsetSize) | ||||
| 			<< targetBaseType->storageSize() | ||||
| 			<< eth::Instruction::ADD | ||||
| 			<< eth::swapInstruction(1 + byteOffsetSize); | ||||
| 			<< Instruction::ADD | ||||
| 			<< swapInstruction(1 + byteOffsetSize); | ||||
| 	m_context.appendJumpTo(copyLoopStart); | ||||
| 	m_context << copyLoopEnd; | ||||
| 	if (haveByteOffsetTarget) | ||||
| 	{ | ||||
| 		// clear elements that might be left over in the current slot in target
 | ||||
| 		// stack: target_ref target_data_end source_data_pos target_data_pos source_data_end target_byte_offset [source_byte_offset]
 | ||||
| 		m_context << eth::dupInstruction(byteOffsetSize) << eth::Instruction::ISZERO; | ||||
| 		m_context << dupInstruction(byteOffsetSize) << Instruction::ISZERO; | ||||
| 		eth::AssemblyItem copyCleanupLoopEnd = m_context.appendConditionalJump(); | ||||
| 		m_context << eth::dupInstruction(2 + byteOffsetSize) << eth::dupInstruction(1 + byteOffsetSize); | ||||
| 		m_context << dupInstruction(2 + byteOffsetSize) << dupInstruction(1 + byteOffsetSize); | ||||
| 		StorageItem(m_context, *targetBaseType).setToZero(SourceLocation(), true); | ||||
| 		incrementByteOffset(targetBaseType->storageBytes(), byteOffsetSize, byteOffsetSize + 2); | ||||
| 		m_context.appendJumpTo(copyLoopEnd); | ||||
| 
 | ||||
| 		m_context << copyCleanupLoopEnd; | ||||
| 		m_context << eth::Instruction::POP; // might pop the source, but then target is popped next
 | ||||
| 		m_context << Instruction::POP; // might pop the source, but then target is popped next
 | ||||
| 	} | ||||
| 	if (haveByteOffsetSource) | ||||
| 		m_context << eth::Instruction::POP; | ||||
| 		m_context << Instruction::POP; | ||||
| 	m_context << copyLoopEndWithoutByteOffset; | ||||
| 
 | ||||
| 	// zero-out leftovers in target
 | ||||
| 	// stack: target_ref target_data_end source_data_pos target_data_pos_updated source_data_end
 | ||||
| 	m_context << eth::Instruction::POP << eth::Instruction::SWAP1 << eth::Instruction::POP; | ||||
| 	m_context << Instruction::POP << Instruction::SWAP1 << Instruction::POP; | ||||
| 	// stack: target_ref target_data_end target_data_pos_updated
 | ||||
| 	clearStorageLoop(*targetBaseType); | ||||
| 	m_context << eth::Instruction::POP; | ||||
| 	m_context << Instruction::POP; | ||||
| } | ||||
| 
 | ||||
| void ArrayUtils::copyArrayToMemory(ArrayType const& _sourceType, bool _padToWordBoundaries) const | ||||
| @ -285,13 +285,13 @@ void ArrayUtils::copyArrayToMemory(ArrayType const& _sourceType, bool _padToWord | ||||
| 		if (!_sourceType.isDynamicallySized()) | ||||
| 			m_context << _sourceType.length(); | ||||
| 		if (baseSize > 1) | ||||
| 			m_context << u256(baseSize) << eth::Instruction::MUL; | ||||
| 			m_context << u256(baseSize) << Instruction::MUL; | ||||
| 		// stack: target source_offset source_len
 | ||||
| 		m_context << eth::Instruction::DUP1 << eth::Instruction::DUP3 << eth::Instruction::DUP5; | ||||
| 		m_context << Instruction::DUP1 << Instruction::DUP3 << Instruction::DUP5; | ||||
| 		// stack: target source_offset source_len source_len source_offset target
 | ||||
| 		m_context << eth::Instruction::CALLDATACOPY; | ||||
| 		m_context << eth::Instruction::DUP3 << eth::Instruction::ADD; | ||||
| 		m_context << eth::Instruction::SWAP2 << eth::Instruction::POP << eth::Instruction::POP; | ||||
| 		m_context << Instruction::CALLDATACOPY; | ||||
| 		m_context << Instruction::DUP3 << Instruction::ADD; | ||||
| 		m_context << Instruction::SWAP2 << Instruction::POP << Instruction::POP; | ||||
| 	} | ||||
| 	else if (_sourceType.location() == DataLocation::Memory) | ||||
| 	{ | ||||
| @ -300,25 +300,25 @@ void ArrayUtils::copyArrayToMemory(ArrayType const& _sourceType, bool _padToWord | ||||
| 		if (!_sourceType.baseType()->isValueType()) | ||||
| 		{ | ||||
| 			// copy using a loop
 | ||||
| 			m_context << u256(0) << eth::Instruction::SWAP3; | ||||
| 			m_context << u256(0) << Instruction::SWAP3; | ||||
| 			// stack: counter source length target
 | ||||
| 			auto repeat = m_context.newTag(); | ||||
| 			m_context << repeat; | ||||
| 			m_context << eth::Instruction::DUP2 << eth::Instruction::DUP5; | ||||
| 			m_context << eth::Instruction::LT << eth::Instruction::ISZERO; | ||||
| 			m_context << Instruction::DUP2 << Instruction::DUP5; | ||||
| 			m_context << Instruction::LT << Instruction::ISZERO; | ||||
| 			auto loopEnd = m_context.appendConditionalJump(); | ||||
| 			m_context << eth::Instruction::DUP3 << eth::Instruction::DUP5; | ||||
| 			m_context << Instruction::DUP3 << Instruction::DUP5; | ||||
| 			accessIndex(_sourceType, false); | ||||
| 			MemoryItem(m_context, *_sourceType.baseType(), true).retrieveValue(SourceLocation(), true); | ||||
| 			if (auto baseArray = dynamic_cast<ArrayType const*>(_sourceType.baseType().get())) | ||||
| 				copyArrayToMemory(*baseArray, _padToWordBoundaries); | ||||
| 			else | ||||
| 				utils.storeInMemoryDynamic(*_sourceType.baseType()); | ||||
| 			m_context << eth::Instruction::SWAP3 << u256(1) << eth::Instruction::ADD; | ||||
| 			m_context << eth::Instruction::SWAP3; | ||||
| 			m_context << Instruction::SWAP3 << u256(1) << Instruction::ADD; | ||||
| 			m_context << Instruction::SWAP3; | ||||
| 			m_context.appendJumpTo(repeat); | ||||
| 			m_context << loopEnd; | ||||
| 			m_context << eth::Instruction::SWAP3; | ||||
| 			m_context << Instruction::SWAP3; | ||||
| 			utils.popStackSlots(3); | ||||
| 			// stack: updated_target_pos
 | ||||
| 			return; | ||||
| @ -328,18 +328,18 @@ void ArrayUtils::copyArrayToMemory(ArrayType const& _sourceType, bool _padToWord | ||||
| 		if (_sourceType.isDynamicallySized()) | ||||
| 		{ | ||||
| 			// change pointer to data part
 | ||||
| 			m_context << eth::Instruction::SWAP1 << u256(32) << eth::Instruction::ADD; | ||||
| 			m_context << eth::Instruction::SWAP1; | ||||
| 			m_context << Instruction::SWAP1 << u256(32) << Instruction::ADD; | ||||
| 			m_context << Instruction::SWAP1; | ||||
| 		} | ||||
| 		// convert length to size
 | ||||
| 		if (baseSize > 1) | ||||
| 			m_context << u256(baseSize) << eth::Instruction::MUL; | ||||
| 			m_context << u256(baseSize) << Instruction::MUL; | ||||
| 		// stack: <target> <source> <size>
 | ||||
| 		//@TODO do not use ::CALL if less than 32 bytes?
 | ||||
| 		m_context << eth::Instruction::DUP1 << eth::Instruction::DUP4 << eth::Instruction::DUP4; | ||||
| 		m_context << Instruction::DUP1 << Instruction::DUP4 << Instruction::DUP4; | ||||
| 		utils.memoryCopy(); | ||||
| 
 | ||||
| 		m_context << eth::Instruction::SWAP1 << eth::Instruction::POP; | ||||
| 		m_context << Instruction::SWAP1 << Instruction::POP; | ||||
| 		// stack: <target> <size>
 | ||||
| 
 | ||||
| 		bool paddingNeeded = false; | ||||
| @ -350,43 +350,43 @@ void ArrayUtils::copyArrayToMemory(ArrayType const& _sourceType, bool _padToWord | ||||
| 		if (paddingNeeded) | ||||
| 		{ | ||||
| 			// stack: <target> <size>
 | ||||
| 			m_context << eth::Instruction::SWAP1 << eth::Instruction::DUP2 << eth::Instruction::ADD; | ||||
| 			m_context << Instruction::SWAP1 << Instruction::DUP2 << Instruction::ADD; | ||||
| 			// stack: <length> <target + size>
 | ||||
| 			m_context << eth::Instruction::SWAP1 << u256(31) << eth::Instruction::AND; | ||||
| 			m_context << Instruction::SWAP1 << u256(31) << Instruction::AND; | ||||
| 			// stack: <target + size> <remainder = size % 32>
 | ||||
| 			eth::AssemblyItem skip = m_context.newTag(); | ||||
| 			if (_sourceType.isDynamicallySized()) | ||||
| 			{ | ||||
| 				m_context << eth::Instruction::DUP1 << eth::Instruction::ISZERO; | ||||
| 				m_context << Instruction::DUP1 << Instruction::ISZERO; | ||||
| 				m_context.appendConditionalJumpTo(skip); | ||||
| 			} | ||||
| 			// round off, load from there.
 | ||||
| 			// stack <target + size> <remainder = size % 32>
 | ||||
| 			m_context << eth::Instruction::DUP1 << eth::Instruction::DUP3; | ||||
| 			m_context << eth::Instruction::SUB; | ||||
| 			m_context << Instruction::DUP1 << Instruction::DUP3; | ||||
| 			m_context << Instruction::SUB; | ||||
| 			// stack: target+size remainder <target + size - remainder>
 | ||||
| 			m_context << eth::Instruction::DUP1 << eth::Instruction::MLOAD; | ||||
| 			m_context << Instruction::DUP1 << Instruction::MLOAD; | ||||
| 			// Now we AND it with ~(2**(8 * (32 - remainder)) - 1)
 | ||||
| 			m_context << u256(1); | ||||
| 			m_context << eth::Instruction::DUP4 << u256(32) << eth::Instruction::SUB; | ||||
| 			m_context << Instruction::DUP4 << u256(32) << Instruction::SUB; | ||||
| 			// stack: ...<v> 1 <32 - remainder>
 | ||||
| 			m_context << u256(0x100) << eth::Instruction::EXP << eth::Instruction::SUB; | ||||
| 			m_context << eth::Instruction::NOT << eth::Instruction::AND; | ||||
| 			m_context << u256(0x100) << Instruction::EXP << Instruction::SUB; | ||||
| 			m_context << Instruction::NOT << Instruction::AND; | ||||
| 			// stack: target+size remainder target+size-remainder <v & ...>
 | ||||
| 			m_context << eth::Instruction::DUP2 << eth::Instruction::MSTORE; | ||||
| 			m_context << Instruction::DUP2 << Instruction::MSTORE; | ||||
| 			// stack: target+size remainder target+size-remainder
 | ||||
| 			m_context << u256(32) << eth::Instruction::ADD; | ||||
| 			m_context << u256(32) << Instruction::ADD; | ||||
| 			// stack: target+size remainder <new_padded_end>
 | ||||
| 			m_context << eth::Instruction::SWAP2 << eth::Instruction::POP; | ||||
| 			m_context << Instruction::SWAP2 << Instruction::POP; | ||||
| 
 | ||||
| 			if (_sourceType.isDynamicallySized()) | ||||
| 				m_context << skip.tag(); | ||||
| 			// stack <target + "size"> <remainder = size % 32>
 | ||||
| 			m_context << eth::Instruction::POP; | ||||
| 			m_context << Instruction::POP; | ||||
| 		} | ||||
| 		else | ||||
| 			// stack: <target> <size>
 | ||||
| 			m_context << eth::Instruction::ADD; | ||||
| 			m_context << Instruction::ADD; | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| @ -398,48 +398,48 @@ void ArrayUtils::copyArrayToMemory(ArrayType const& _sourceType, bool _padToWord | ||||
| 		retrieveLength(_sourceType); | ||||
| 		// stack here: memory_offset storage_offset length
 | ||||
| 		// jump to end if length is zero
 | ||||
| 		m_context << eth::Instruction::DUP1 << eth::Instruction::ISZERO; | ||||
| 		m_context << Instruction::DUP1 << Instruction::ISZERO; | ||||
| 		eth::AssemblyItem loopEnd = m_context.appendConditionalJump(); | ||||
| 		// Special case for tightly-stored byte arrays
 | ||||
| 		if (_sourceType.isByteArray()) | ||||
| 		{ | ||||
| 			// stack here: memory_offset storage_offset length
 | ||||
| 			m_context << eth::Instruction::DUP1 << u256(31) << eth::Instruction::LT; | ||||
| 			m_context << Instruction::DUP1 << u256(31) << Instruction::LT; | ||||
| 			eth::AssemblyItem longByteArray = m_context.appendConditionalJump(); | ||||
| 			// store the short byte array (discard lower-order byte)
 | ||||
| 			m_context << u256(0x100) << eth::Instruction::DUP1; | ||||
| 			m_context << eth::Instruction::DUP4 << eth::Instruction::SLOAD; | ||||
| 			m_context << eth::Instruction::DIV << eth::Instruction::MUL; | ||||
| 			m_context << eth::Instruction::DUP4 << eth::Instruction::MSTORE; | ||||
| 			m_context << u256(0x100) << Instruction::DUP1; | ||||
| 			m_context << Instruction::DUP4 << Instruction::SLOAD; | ||||
| 			m_context << Instruction::DIV << Instruction::MUL; | ||||
| 			m_context << Instruction::DUP4 << Instruction::MSTORE; | ||||
| 			// stack here: memory_offset storage_offset length
 | ||||
| 			// add 32 or length to memory offset
 | ||||
| 			m_context << eth::Instruction::SWAP2; | ||||
| 			m_context << Instruction::SWAP2; | ||||
| 			if (_padToWordBoundaries) | ||||
| 				m_context << u256(32); | ||||
| 			else | ||||
| 				m_context << eth::Instruction::DUP3; | ||||
| 			m_context << eth::Instruction::ADD; | ||||
| 			m_context << eth::Instruction::SWAP2; | ||||
| 				m_context << Instruction::DUP3; | ||||
| 			m_context << Instruction::ADD; | ||||
| 			m_context << Instruction::SWAP2; | ||||
| 			m_context.appendJumpTo(loopEnd); | ||||
| 			m_context << longByteArray; | ||||
| 		} | ||||
| 		// compute memory end offset
 | ||||
| 		if (baseSize > 1) | ||||
| 			// convert length to memory size
 | ||||
| 			m_context << u256(baseSize) << eth::Instruction::MUL; | ||||
| 		m_context << eth::Instruction::DUP3 << eth::Instruction::ADD << eth::Instruction::SWAP2; | ||||
| 			m_context << u256(baseSize) << Instruction::MUL; | ||||
| 		m_context << Instruction::DUP3 << Instruction::ADD << Instruction::SWAP2; | ||||
| 		if (_sourceType.isDynamicallySized()) | ||||
| 		{ | ||||
| 			// actual array data is stored at SHA3(storage_offset)
 | ||||
| 			m_context << eth::Instruction::SWAP1; | ||||
| 			m_context << Instruction::SWAP1; | ||||
| 			utils.computeHashStatic(); | ||||
| 			m_context << eth::Instruction::SWAP1; | ||||
| 			m_context << Instruction::SWAP1; | ||||
| 		} | ||||
| 
 | ||||
| 		// stack here: memory_end_offset storage_data_offset memory_offset
 | ||||
| 		bool haveByteOffset = !_sourceType.isByteArray() && storageBytes <= 16; | ||||
| 		if (haveByteOffset) | ||||
| 			m_context << u256(0) << eth::Instruction::SWAP1; | ||||
| 			m_context << u256(0) << Instruction::SWAP1; | ||||
| 		// stack here: memory_end_offset storage_data_offset [storage_byte_offset] memory_offset
 | ||||
| 		eth::AssemblyItem loopStart = m_context.newTag(); | ||||
| 		m_context << loopStart; | ||||
| @ -447,20 +447,20 @@ void ArrayUtils::copyArrayToMemory(ArrayType const& _sourceType, bool _padToWord | ||||
| 		if (_sourceType.isByteArray()) | ||||
| 		{ | ||||
| 			// Packed both in storage and memory.
 | ||||
| 			m_context << eth::Instruction::DUP2 << eth::Instruction::SLOAD; | ||||
| 			m_context << eth::Instruction::DUP2 << eth::Instruction::MSTORE; | ||||
| 			m_context << Instruction::DUP2 << Instruction::SLOAD; | ||||
| 			m_context << Instruction::DUP2 << Instruction::MSTORE; | ||||
| 			// increment storage_data_offset by 1
 | ||||
| 			m_context << eth::Instruction::SWAP1 << u256(1) << eth::Instruction::ADD; | ||||
| 			m_context << Instruction::SWAP1 << u256(1) << Instruction::ADD; | ||||
| 			// increment memory offset by 32
 | ||||
| 			m_context << eth::Instruction::SWAP1 << u256(32) << eth::Instruction::ADD; | ||||
| 			m_context << Instruction::SWAP1 << u256(32) << Instruction::ADD; | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			// stack here: memory_end_offset storage_data_offset [storage_byte_offset] memory_offset
 | ||||
| 			if (haveByteOffset) | ||||
| 				m_context << eth::Instruction::DUP3 << eth::Instruction::DUP3; | ||||
| 				m_context << Instruction::DUP3 << Instruction::DUP3; | ||||
| 			else | ||||
| 				m_context << eth::Instruction::DUP2 << u256(0); | ||||
| 				m_context << Instruction::DUP2 << u256(0); | ||||
| 			StorageItem(m_context, *_sourceType.baseType()).retrieveValue(SourceLocation(), true); | ||||
| 			if (auto baseArray = dynamic_cast<ArrayType const*>(_sourceType.baseType().get())) | ||||
| 				copyArrayToMemory(*baseArray, _padToWordBoundaries); | ||||
| @ -471,29 +471,29 @@ void ArrayUtils::copyArrayToMemory(ArrayType const& _sourceType, bool _padToWord | ||||
| 				incrementByteOffset(storageBytes, 2, 3); | ||||
| 			else | ||||
| 			{ | ||||
| 				m_context << eth::Instruction::SWAP1; | ||||
| 				m_context << storageSize << eth::Instruction::ADD; | ||||
| 				m_context << eth::Instruction::SWAP1; | ||||
| 				m_context << Instruction::SWAP1; | ||||
| 				m_context << storageSize << Instruction::ADD; | ||||
| 				m_context << Instruction::SWAP1; | ||||
| 			} | ||||
| 		} | ||||
| 		// check for loop condition
 | ||||
| 		m_context << eth::Instruction::DUP1 << eth::dupInstruction(haveByteOffset ? 5 : 4); | ||||
| 		m_context << eth::Instruction::GT; | ||||
| 		m_context << Instruction::DUP1 << dupInstruction(haveByteOffset ? 5 : 4); | ||||
| 		m_context << Instruction::GT; | ||||
| 		m_context.appendConditionalJumpTo(loopStart); | ||||
| 		// stack here: memory_end_offset storage_data_offset [storage_byte_offset] memory_offset
 | ||||
| 		if (haveByteOffset) | ||||
| 			m_context << eth::Instruction::SWAP1 << eth::Instruction::POP; | ||||
| 			m_context << Instruction::SWAP1 << Instruction::POP; | ||||
| 		if (_padToWordBoundaries && baseSize % 32 != 0) | ||||
| 		{ | ||||
| 			// memory_end_offset - start is the actual length (we want to compute the ceil of).
 | ||||
| 			// memory_offset - start is its next multiple of 32, but it might be off by 32.
 | ||||
| 			// so we compute: memory_end_offset += (memory_offset - memory_end_offest) & 31
 | ||||
| 			m_context << eth::Instruction::DUP3 << eth::Instruction::SWAP1 << eth::Instruction::SUB; | ||||
| 			m_context << u256(31) << eth::Instruction::AND; | ||||
| 			m_context << eth::Instruction::DUP3 << eth::Instruction::ADD; | ||||
| 			m_context << eth::Instruction::SWAP2; | ||||
| 			m_context << Instruction::DUP3 << Instruction::SWAP1 << Instruction::SUB; | ||||
| 			m_context << u256(31) << Instruction::AND; | ||||
| 			m_context << Instruction::DUP3 << Instruction::ADD; | ||||
| 			m_context << Instruction::SWAP2; | ||||
| 		} | ||||
| 		m_context << loopEnd << eth::Instruction::POP << eth::Instruction::POP; | ||||
| 		m_context << loopEnd << Instruction::POP << Instruction::POP; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| @ -509,20 +509,20 @@ void ArrayUtils::clearArray(ArrayType const& _type) const | ||||
| 	if (_type.baseType()->isValueType()) | ||||
| 		solAssert(_type.baseType()->storageSize() <= 1, "Invalid size for value type."); | ||||
| 
 | ||||
| 	m_context << eth::Instruction::POP; // remove byte offset
 | ||||
| 	m_context << Instruction::POP; // remove byte offset
 | ||||
| 	if (_type.isDynamicallySized()) | ||||
| 		clearDynamicArray(_type); | ||||
| 	else if (_type.length() == 0 || _type.baseType()->category() == Type::Category::Mapping) | ||||
| 		m_context << eth::Instruction::POP; | ||||
| 		m_context << Instruction::POP; | ||||
| 	else if (_type.baseType()->isValueType() && _type.storageSize() <= 5) | ||||
| 	{ | ||||
| 		// unroll loop for small arrays @todo choose a good value
 | ||||
| 		// Note that we loop over storage slots here, not elements.
 | ||||
| 		for (unsigned i = 1; i < _type.storageSize(); ++i) | ||||
| 			m_context | ||||
| 				<< u256(0) << eth::Instruction::DUP2 << eth::Instruction::SSTORE | ||||
| 				<< u256(1) << eth::Instruction::ADD; | ||||
| 		m_context << u256(0) << eth::Instruction::SWAP1 << eth::Instruction::SSTORE; | ||||
| 				<< u256(0) << Instruction::DUP2 << Instruction::SSTORE | ||||
| 				<< u256(1) << Instruction::ADD; | ||||
| 		m_context << u256(0) << Instruction::SWAP1 << Instruction::SSTORE; | ||||
| 	} | ||||
| 	else if (!_type.baseType()->isValueType() && _type.length() <= 4) | ||||
| 	{ | ||||
| @ -533,22 +533,22 @@ void ArrayUtils::clearArray(ArrayType const& _type) const | ||||
| 			m_context << u256(0); | ||||
| 			StorageItem(m_context, *_type.baseType()).setToZero(SourceLocation(), false); | ||||
| 			m_context | ||||
| 				<< eth::Instruction::POP | ||||
| 				<< u256(_type.baseType()->storageSize()) << eth::Instruction::ADD; | ||||
| 				<< Instruction::POP | ||||
| 				<< u256(_type.baseType()->storageSize()) << Instruction::ADD; | ||||
| 		} | ||||
| 		m_context << u256(0); | ||||
| 		StorageItem(m_context, *_type.baseType()).setToZero(SourceLocation(), true); | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		m_context << eth::Instruction::DUP1 << _type.length(); | ||||
| 		m_context << Instruction::DUP1 << _type.length(); | ||||
| 		convertLengthToSize(_type); | ||||
| 		m_context << eth::Instruction::ADD << eth::Instruction::SWAP1; | ||||
| 		m_context << Instruction::ADD << Instruction::SWAP1; | ||||
| 		if (_type.baseType()->storageBytes() < 32) | ||||
| 			clearStorageLoop(IntegerType(256)); | ||||
| 		else | ||||
| 			clearStorageLoop(*_type.baseType()); | ||||
| 		m_context << eth::Instruction::POP; | ||||
| 		m_context << Instruction::POP; | ||||
| 	} | ||||
| 	solAssert(m_context.stackHeight() == stackHeightStart - 2, ""); | ||||
| } | ||||
| @ -561,15 +561,15 @@ void ArrayUtils::clearDynamicArray(ArrayType const& _type) const | ||||
| 	// fetch length
 | ||||
| 	retrieveLength(_type); | ||||
| 	// set length to zero
 | ||||
| 	m_context << u256(0) << eth::Instruction::DUP3 << eth::Instruction::SSTORE; | ||||
| 	m_context << u256(0) << Instruction::DUP3 << Instruction::SSTORE; | ||||
| 	// Special case: short byte arrays are stored togeher with their length
 | ||||
| 	eth::AssemblyItem endTag = m_context.newTag(); | ||||
| 	if (_type.isByteArray()) | ||||
| 	{ | ||||
| 		// stack: ref old_length
 | ||||
| 		m_context << eth::Instruction::DUP1 << u256(31) << eth::Instruction::LT; | ||||
| 		m_context << Instruction::DUP1 << u256(31) << Instruction::LT; | ||||
| 		eth::AssemblyItem longByteArray = m_context.appendConditionalJump(); | ||||
| 		m_context << eth::Instruction::POP; | ||||
| 		m_context << Instruction::POP; | ||||
| 		m_context.appendJumpTo(endTag); | ||||
| 		m_context.adjustStackOffset(1); // needed because of jump
 | ||||
| 		m_context << longByteArray; | ||||
| @ -577,11 +577,11 @@ void ArrayUtils::clearDynamicArray(ArrayType const& _type) const | ||||
| 	// stack: ref old_length
 | ||||
| 	convertLengthToSize(_type); | ||||
| 	// compute data positions
 | ||||
| 	m_context << eth::Instruction::SWAP1; | ||||
| 	m_context << Instruction::SWAP1; | ||||
| 	CompilerUtils(m_context).computeHashStatic(); | ||||
| 	// stack: len data_pos
 | ||||
| 	m_context << eth::Instruction::SWAP1 << eth::Instruction::DUP2 << eth::Instruction::ADD | ||||
| 		<< eth::Instruction::SWAP1; | ||||
| 	m_context << Instruction::SWAP1 << Instruction::DUP2 << Instruction::ADD | ||||
| 		<< Instruction::SWAP1; | ||||
| 	// stack: data_pos_end data_pos
 | ||||
| 	if (_type.isByteArray() || _type.baseType()->storageBytes() < 32) | ||||
| 		clearStorageLoop(IntegerType(256)); | ||||
| @ -589,7 +589,7 @@ void ArrayUtils::clearDynamicArray(ArrayType const& _type) const | ||||
| 		clearStorageLoop(*_type.baseType()); | ||||
| 	// cleanup
 | ||||
| 	m_context << endTag; | ||||
| 	m_context << eth::Instruction::POP; | ||||
| 	m_context << Instruction::POP; | ||||
| } | ||||
| 
 | ||||
| void ArrayUtils::resizeDynamicArray(ArrayType const& _type) const | ||||
| @ -614,13 +614,13 @@ void ArrayUtils::resizeDynamicArray(ArrayType const& _type) const | ||||
| 		eth::AssemblyItem regularPath = m_context.newTag(); | ||||
| 		// We start by a large case-distinction about the old and new length of the byte array.
 | ||||
| 
 | ||||
| 		m_context << eth::Instruction::DUP3 << eth::Instruction::SLOAD; | ||||
| 		m_context << Instruction::DUP3 << Instruction::SLOAD; | ||||
| 		// stack: ref new_length current_length ref_value
 | ||||
| 
 | ||||
| 		solAssert(m_context.stackHeight() - stackHeightStart == 4 - 2, "3"); | ||||
| 		m_context << eth::Instruction::DUP2 << u256(31) << eth::Instruction::LT; | ||||
| 		m_context << Instruction::DUP2 << u256(31) << Instruction::LT; | ||||
| 		eth::AssemblyItem currentIsLong = m_context.appendConditionalJump(); | ||||
| 		m_context << eth::Instruction::DUP3 << u256(31) << eth::Instruction::LT; | ||||
| 		m_context << Instruction::DUP3 << u256(31) << Instruction::LT; | ||||
| 		eth::AssemblyItem newIsLong = m_context.appendConditionalJump(); | ||||
| 
 | ||||
| 		// Here: short -> short
 | ||||
| @ -628,17 +628,17 @@ void ArrayUtils::resizeDynamicArray(ArrayType const& _type) const | ||||
| 		// Compute 1 << (256 - 8 * new_size)
 | ||||
| 		eth::AssemblyItem shortToShort = m_context.newTag(); | ||||
| 		m_context << shortToShort; | ||||
| 		m_context << eth::Instruction::DUP3 << u256(8) << eth::Instruction::MUL; | ||||
| 		m_context << u256(0x100) << eth::Instruction::SUB; | ||||
| 		m_context << u256(2) << eth::Instruction::EXP; | ||||
| 		m_context << Instruction::DUP3 << u256(8) << Instruction::MUL; | ||||
| 		m_context << u256(0x100) << Instruction::SUB; | ||||
| 		m_context << u256(2) << Instruction::EXP; | ||||
| 		// Divide and multiply by that value, clearing bits.
 | ||||
| 		m_context << eth::Instruction::DUP1 << eth::Instruction::SWAP2; | ||||
| 		m_context << eth::Instruction::DIV << eth::Instruction::MUL; | ||||
| 		m_context << Instruction::DUP1 << Instruction::SWAP2; | ||||
| 		m_context << Instruction::DIV << Instruction::MUL; | ||||
| 		// Insert 2*length.
 | ||||
| 		m_context << eth::Instruction::DUP3 << eth::Instruction::DUP1 << eth::Instruction::ADD; | ||||
| 		m_context << eth::Instruction::OR; | ||||
| 		m_context << Instruction::DUP3 << Instruction::DUP1 << Instruction::ADD; | ||||
| 		m_context << Instruction::OR; | ||||
| 		// Store.
 | ||||
| 		m_context << eth::Instruction::DUP4 << eth::Instruction::SSTORE; | ||||
| 		m_context << Instruction::DUP4 << Instruction::SSTORE; | ||||
| 		solAssert(m_context.stackHeight() - stackHeightStart == 3 - 2, "3"); | ||||
| 		m_context.appendJumpTo(resizeEnd); | ||||
| 
 | ||||
| @ -649,24 +649,24 @@ void ArrayUtils::resizeDynamicArray(ArrayType const& _type) const | ||||
| 		// stack: ref new_length current_length ref_value
 | ||||
| 		solAssert(m_context.stackHeight() - stackHeightStart == 4 - 2, "3"); | ||||
| 		// Zero out lower-order byte.
 | ||||
| 		m_context << u256(0xff) << eth::Instruction::NOT << eth::Instruction::AND; | ||||
| 		m_context << u256(0xff) << Instruction::NOT << Instruction::AND; | ||||
| 		// Store at data location.
 | ||||
| 		m_context << eth::Instruction::DUP4; | ||||
| 		m_context << Instruction::DUP4; | ||||
| 		CompilerUtils(m_context).computeHashStatic(); | ||||
| 		m_context << eth::Instruction::SSTORE; | ||||
| 		m_context << Instruction::SSTORE; | ||||
| 		// stack: ref new_length current_length
 | ||||
| 		// Store new length: Compule 2*length + 1 and store it.
 | ||||
| 		m_context << eth::Instruction::DUP2 << eth::Instruction::DUP1 << eth::Instruction::ADD; | ||||
| 		m_context << u256(1) << eth::Instruction::ADD; | ||||
| 		m_context << Instruction::DUP2 << Instruction::DUP1 << Instruction::ADD; | ||||
| 		m_context << u256(1) << Instruction::ADD; | ||||
| 		// stack: ref new_length current_length 2*new_length+1
 | ||||
| 		m_context << eth::Instruction::DUP4 << eth::Instruction::SSTORE; | ||||
| 		m_context << Instruction::DUP4 << Instruction::SSTORE; | ||||
| 		solAssert(m_context.stackHeight() - stackHeightStart == 3 - 2, "3"); | ||||
| 		m_context.appendJumpTo(resizeEnd); | ||||
| 
 | ||||
| 		m_context.adjustStackOffset(1); // we have to do that because of the jumps
 | ||||
| 
 | ||||
| 		m_context << currentIsLong; | ||||
| 		m_context << eth::Instruction::DUP3 << u256(31) << eth::Instruction::LT; | ||||
| 		m_context << Instruction::DUP3 << u256(31) << Instruction::LT; | ||||
| 		m_context.appendConditionalJumpTo(regularPath); | ||||
| 
 | ||||
| 		// Here: long -> short
 | ||||
| @ -675,51 +675,51 @@ void ArrayUtils::resizeDynamicArray(ArrayType const& _type) const | ||||
| 
 | ||||
| 		// stack: ref new_length current_length ref_value
 | ||||
| 		solAssert(m_context.stackHeight() - stackHeightStart == 4 - 2, "3"); | ||||
| 		m_context << eth::Instruction::POP << eth::Instruction::DUP3; | ||||
| 		m_context << Instruction::POP << Instruction::DUP3; | ||||
| 		CompilerUtils(m_context).computeHashStatic(); | ||||
| 		m_context << eth::Instruction::DUP1 << eth::Instruction::SLOAD << eth::Instruction::SWAP1; | ||||
| 		m_context << Instruction::DUP1 << Instruction::SLOAD << Instruction::SWAP1; | ||||
| 		// stack: ref new_length current_length first_word data_location
 | ||||
| 		m_context << eth::Instruction::DUP3; | ||||
| 		m_context << Instruction::DUP3; | ||||
| 		convertLengthToSize(_type); | ||||
| 		m_context << eth::Instruction::DUP2 << eth::Instruction::ADD << eth::Instruction::SWAP1; | ||||
| 		m_context << Instruction::DUP2 << Instruction::ADD << Instruction::SWAP1; | ||||
| 		// stack: ref new_length current_length first_word data_location_end data_location
 | ||||
| 		clearStorageLoop(IntegerType(256)); | ||||
| 		m_context << eth::Instruction::POP; | ||||
| 		m_context << Instruction::POP; | ||||
| 		// stack: ref new_length current_length first_word
 | ||||
| 		solAssert(m_context.stackHeight() - stackHeightStart == 4 - 2, "3"); | ||||
| 		m_context.appendJumpTo(shortToShort); | ||||
| 
 | ||||
| 		m_context << regularPath; | ||||
| 		// stack: ref new_length current_length ref_value
 | ||||
| 		m_context << eth::Instruction::POP; | ||||
| 		m_context << Instruction::POP; | ||||
| 	} | ||||
| 
 | ||||
| 	// Change of length for a regular array (i.e. length at location, data at sha3(location)).
 | ||||
| 	// stack: ref new_length old_length
 | ||||
| 	// store new length
 | ||||
| 	m_context << eth::Instruction::DUP2; | ||||
| 	m_context << Instruction::DUP2; | ||||
| 	if (_type.isByteArray()) | ||||
| 		// For a "long" byte array, store length as 2*length+1
 | ||||
| 		m_context << eth::Instruction::DUP1 << eth::Instruction::ADD << u256(1) << eth::Instruction::ADD; | ||||
| 	m_context<< eth::Instruction::DUP4 << eth::Instruction::SSTORE; | ||||
| 		m_context << Instruction::DUP1 << Instruction::ADD << u256(1) << Instruction::ADD; | ||||
| 	m_context<< Instruction::DUP4 << Instruction::SSTORE; | ||||
| 	// skip if size is not reduced
 | ||||
| 	m_context << eth::Instruction::DUP2 << eth::Instruction::DUP2 | ||||
| 		<< eth::Instruction::ISZERO << eth::Instruction::GT; | ||||
| 	m_context << Instruction::DUP2 << Instruction::DUP2 | ||||
| 		<< Instruction::ISZERO << Instruction::GT; | ||||
| 	m_context.appendConditionalJumpTo(resizeEnd); | ||||
| 
 | ||||
| 	// size reduced, clear the end of the array
 | ||||
| 	// stack: ref new_length old_length
 | ||||
| 	convertLengthToSize(_type); | ||||
| 	m_context << eth::Instruction::DUP2; | ||||
| 	m_context << Instruction::DUP2; | ||||
| 	convertLengthToSize(_type); | ||||
| 	// stack: ref new_length old_size new_size
 | ||||
| 	// compute data positions
 | ||||
| 	m_context << eth::Instruction::DUP4; | ||||
| 	m_context << Instruction::DUP4; | ||||
| 	CompilerUtils(m_context).computeHashStatic(); | ||||
| 	// stack: ref new_length old_size new_size data_pos
 | ||||
| 	m_context << eth::Instruction::SWAP2 << eth::Instruction::DUP3 << eth::Instruction::ADD; | ||||
| 	m_context << Instruction::SWAP2 << Instruction::DUP3 << Instruction::ADD; | ||||
| 	// stack: ref new_length data_pos new_size delete_end
 | ||||
| 	m_context << eth::Instruction::SWAP2 << eth::Instruction::ADD; | ||||
| 	m_context << Instruction::SWAP2 << Instruction::ADD; | ||||
| 	// stack: ref new_length delete_end delete_start
 | ||||
| 	if (_type.isByteArray() || _type.baseType()->storageBytes() < 32) | ||||
| 		clearStorageLoop(IntegerType(256)); | ||||
| @ -728,7 +728,7 @@ void ArrayUtils::resizeDynamicArray(ArrayType const& _type) const | ||||
| 
 | ||||
| 	m_context << resizeEnd; | ||||
| 	// cleanup
 | ||||
| 	m_context << eth::Instruction::POP << eth::Instruction::POP << eth::Instruction::POP; | ||||
| 	m_context << Instruction::POP << Instruction::POP << Instruction::POP; | ||||
| 	solAssert(m_context.stackHeight() == stackHeightStart - 2, ""); | ||||
| } | ||||
| 
 | ||||
| @ -737,35 +737,35 @@ void ArrayUtils::clearStorageLoop(Type const& _type) const | ||||
| 	unsigned stackHeightStart = m_context.stackHeight(); | ||||
| 	if (_type.category() == Type::Category::Mapping) | ||||
| 	{ | ||||
| 		m_context << eth::Instruction::POP; | ||||
| 		m_context << Instruction::POP; | ||||
| 		return; | ||||
| 	} | ||||
| 	// stack: end_pos pos
 | ||||
| 
 | ||||
| 	// jump to and return from the loop to allow for duplicate code removal
 | ||||
| 	eth::AssemblyItem returnTag = m_context.pushNewTag(); | ||||
| 	m_context << eth::Instruction::SWAP2 << eth::Instruction::SWAP1; | ||||
| 	m_context << Instruction::SWAP2 << Instruction::SWAP1; | ||||
| 
 | ||||
| 	// stack: <return tag> end_pos pos
 | ||||
| 	eth::AssemblyItem loopStart = m_context.appendJumpToNew(); | ||||
| 	m_context << loopStart; | ||||
| 	// check for loop condition
 | ||||
| 	m_context << eth::Instruction::DUP1 << eth::Instruction::DUP3 | ||||
| 			   << eth::Instruction::GT << eth::Instruction::ISZERO; | ||||
| 	m_context << Instruction::DUP1 << Instruction::DUP3 | ||||
| 			   << Instruction::GT << Instruction::ISZERO; | ||||
| 	eth::AssemblyItem zeroLoopEnd = m_context.newTag(); | ||||
| 	m_context.appendConditionalJumpTo(zeroLoopEnd); | ||||
| 	// delete
 | ||||
| 	m_context << u256(0); | ||||
| 	StorageItem(m_context, _type).setToZero(SourceLocation(), false); | ||||
| 	m_context << eth::Instruction::POP; | ||||
| 	m_context << Instruction::POP; | ||||
| 	// increment
 | ||||
| 	m_context << u256(1) << eth::Instruction::ADD; | ||||
| 	m_context << u256(1) << Instruction::ADD; | ||||
| 	m_context.appendJumpTo(loopStart); | ||||
| 	// cleanup
 | ||||
| 	m_context << zeroLoopEnd; | ||||
| 	m_context << eth::Instruction::POP << eth::Instruction::SWAP1; | ||||
| 	m_context << Instruction::POP << Instruction::SWAP1; | ||||
| 	// "return"
 | ||||
| 	m_context << eth::Instruction::JUMP; | ||||
| 	m_context << Instruction::JUMP; | ||||
| 
 | ||||
| 	m_context << returnTag; | ||||
| 	solAssert(m_context.stackHeight() == stackHeightStart - 1, ""); | ||||
| @ -779,17 +779,17 @@ void ArrayUtils::convertLengthToSize(ArrayType const& _arrayType, bool _pad) con | ||||
| 		{ | ||||
| 			unsigned baseBytes = _arrayType.baseType()->storageBytes(); | ||||
| 			if (baseBytes == 0) | ||||
| 				m_context << eth::Instruction::POP << u256(1); | ||||
| 				m_context << Instruction::POP << u256(1); | ||||
| 			else if (baseBytes <= 16) | ||||
| 			{ | ||||
| 				unsigned itemsPerSlot = 32 / baseBytes; | ||||
| 				m_context | ||||
| 					<< u256(itemsPerSlot - 1) << eth::Instruction::ADD | ||||
| 					<< u256(itemsPerSlot) << eth::Instruction::SWAP1 << eth::Instruction::DIV; | ||||
| 					<< u256(itemsPerSlot - 1) << Instruction::ADD | ||||
| 					<< u256(itemsPerSlot) << Instruction::SWAP1 << Instruction::DIV; | ||||
| 			} | ||||
| 		} | ||||
| 		else | ||||
| 			m_context << _arrayType.baseType()->storageSize() << eth::Instruction::MUL; | ||||
| 			m_context << _arrayType.baseType()->storageSize() << Instruction::MUL; | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| @ -799,12 +799,12 @@ void ArrayUtils::convertLengthToSize(ArrayType const& _arrayType, bool _pad) con | ||||
| 				m_context << _arrayType.baseType()->memoryHeadSize(); | ||||
| 			else | ||||
| 				m_context << _arrayType.baseType()->calldataEncodedSize(); | ||||
| 			m_context << eth::Instruction::MUL; | ||||
| 			m_context << Instruction::MUL; | ||||
| 		} | ||||
| 		else if (_pad) | ||||
| 			m_context << u256(31) << eth::Instruction::ADD | ||||
| 				<< u256(32) << eth::Instruction::DUP1 | ||||
| 				<< eth::Instruction::SWAP2 << eth::Instruction::DIV << eth::Instruction::MUL; | ||||
| 			m_context << u256(31) << Instruction::ADD | ||||
| 				<< u256(32) << Instruction::DUP1 | ||||
| 				<< Instruction::SWAP2 << Instruction::DIV << Instruction::MUL; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| @ -814,27 +814,27 @@ void ArrayUtils::retrieveLength(ArrayType const& _arrayType, unsigned _stackDept | ||||
| 		m_context << _arrayType.length(); | ||||
| 	else | ||||
| 	{ | ||||
| 		m_context << eth::dupInstruction(1 + _stackDepth); | ||||
| 		m_context << dupInstruction(1 + _stackDepth); | ||||
| 		switch (_arrayType.location()) | ||||
| 		{ | ||||
| 		case DataLocation::CallData: | ||||
| 			// length is stored on the stack
 | ||||
| 			break; | ||||
| 		case DataLocation::Memory: | ||||
| 			m_context << eth::Instruction::MLOAD; | ||||
| 			m_context << Instruction::MLOAD; | ||||
| 			break; | ||||
| 		case DataLocation::Storage: | ||||
| 			m_context << eth::Instruction::SLOAD; | ||||
| 			m_context << Instruction::SLOAD; | ||||
| 			if (_arrayType.isByteArray()) | ||||
| 			{ | ||||
| 				// Retrieve length both for in-place strings and off-place strings:
 | ||||
| 				// Computes (x & (0x100 * (ISZERO (x & 1)) - 1)) / 2
 | ||||
| 				// i.e. for short strings (x & 1 == 0) it does (x & 0xff) / 2 and for long strings it
 | ||||
| 				// computes (x & (-1)) / 2, which is equivalent to just x / 2.
 | ||||
| 				m_context << u256(1) << eth::Instruction::DUP2 << u256(1) << eth::Instruction::AND; | ||||
| 				m_context << eth::Instruction::ISZERO << u256(0x100) << eth::Instruction::MUL; | ||||
| 				m_context << eth::Instruction::SUB << eth::Instruction::AND; | ||||
| 				m_context << u256(2) << eth::Instruction::SWAP1 << eth::Instruction::DIV; | ||||
| 				m_context << u256(1) << Instruction::DUP2 << u256(1) << Instruction::AND; | ||||
| 				m_context << Instruction::ISZERO << u256(0x100) << Instruction::MUL; | ||||
| 				m_context << Instruction::SUB << Instruction::AND; | ||||
| 				m_context << u256(2) << Instruction::SWAP1 << Instruction::DIV; | ||||
| 			} | ||||
| 			break; | ||||
| 		} | ||||
| @ -852,34 +852,34 @@ void ArrayUtils::accessIndex(ArrayType const& _arrayType, bool _doBoundsCheck) c | ||||
| 		ArrayUtils::retrieveLength(_arrayType, 1); | ||||
| 		// Stack: ref [length] index length
 | ||||
| 		// check out-of-bounds access
 | ||||
| 		m_context << eth::Instruction::DUP2 << eth::Instruction::LT << eth::Instruction::ISZERO; | ||||
| 		m_context << Instruction::DUP2 << Instruction::LT << Instruction::ISZERO; | ||||
| 		// out-of-bounds access throws exception
 | ||||
| 		m_context.appendConditionalJumpTo(m_context.errorTag()); | ||||
| 	} | ||||
| 	if (location == DataLocation::CallData && _arrayType.isDynamicallySized()) | ||||
| 		// remove length if present
 | ||||
| 		m_context << eth::Instruction::SWAP1 << eth::Instruction::POP; | ||||
| 		m_context << Instruction::SWAP1 << Instruction::POP; | ||||
| 
 | ||||
| 	// stack: <base_ref> <index>
 | ||||
| 	m_context << eth::Instruction::SWAP1; | ||||
| 	m_context << Instruction::SWAP1; | ||||
| 	// stack: <index> <base_ref>
 | ||||
| 	switch (location) | ||||
| 	{ | ||||
| 	case DataLocation::Memory: | ||||
| 		if (_arrayType.isDynamicallySized()) | ||||
| 			m_context << u256(32) << eth::Instruction::ADD; | ||||
| 			m_context << u256(32) << Instruction::ADD; | ||||
| 		// fall-through
 | ||||
| 	case DataLocation::CallData: | ||||
| 		if (!_arrayType.isByteArray()) | ||||
| 		{ | ||||
| 			m_context << eth::Instruction::SWAP1; | ||||
| 			m_context << Instruction::SWAP1; | ||||
| 			if (location == DataLocation::CallData) | ||||
| 				m_context << _arrayType.baseType()->calldataEncodedSize(); | ||||
| 			else | ||||
| 				m_context << u256(_arrayType.memoryHeadSize()); | ||||
| 			m_context << eth::Instruction::MUL; | ||||
| 			m_context << Instruction::MUL; | ||||
| 		} | ||||
| 		m_context << eth::Instruction::ADD; | ||||
| 		m_context << Instruction::ADD; | ||||
| 		break; | ||||
| 	case DataLocation::Storage: | ||||
| 	{ | ||||
| @ -887,16 +887,16 @@ void ArrayUtils::accessIndex(ArrayType const& _arrayType, bool _doBoundsCheck) c | ||||
| 		if (_arrayType.isByteArray()) | ||||
| 		{ | ||||
| 			// Special case of short byte arrays.
 | ||||
| 			m_context << eth::Instruction::SWAP1; | ||||
| 			m_context << eth::Instruction::DUP2 << eth::Instruction::SLOAD; | ||||
| 			m_context << u256(1) << eth::Instruction::AND << eth::Instruction::ISZERO; | ||||
| 			m_context << Instruction::SWAP1; | ||||
| 			m_context << Instruction::DUP2 << Instruction::SLOAD; | ||||
| 			m_context << u256(1) << Instruction::AND << Instruction::ISZERO; | ||||
| 			// No action needed for short byte arrays.
 | ||||
| 			m_context.appendConditionalJumpTo(endTag); | ||||
| 			m_context << eth::Instruction::SWAP1; | ||||
| 			m_context << Instruction::SWAP1; | ||||
| 		} | ||||
| 		if (_arrayType.isDynamicallySized()) | ||||
| 			CompilerUtils(m_context).computeHashStatic(); | ||||
| 		m_context << eth::Instruction::SWAP1; | ||||
| 		m_context << Instruction::SWAP1; | ||||
| 		if (_arrayType.baseType()->storageBytes() <= 16) | ||||
| 		{ | ||||
| 			// stack: <data_ref> <index>
 | ||||
| @ -905,22 +905,22 @@ void ArrayUtils::accessIndex(ArrayType const& _arrayType, bool _doBoundsCheck) c | ||||
| 			unsigned byteSize = _arrayType.baseType()->storageBytes(); | ||||
| 			solAssert(byteSize != 0, ""); | ||||
| 			unsigned itemsPerSlot = 32 / byteSize; | ||||
| 			m_context << u256(itemsPerSlot) << eth::Instruction::SWAP2; | ||||
| 			m_context << u256(itemsPerSlot) << Instruction::SWAP2; | ||||
| 			// stack: itemsPerSlot index data_ref
 | ||||
| 			m_context | ||||
| 				<< eth::Instruction::DUP3 << eth::Instruction::DUP3 | ||||
| 				<< eth::Instruction::DIV << eth::Instruction::ADD | ||||
| 				<< Instruction::DUP3 << Instruction::DUP3 | ||||
| 				<< Instruction::DIV << Instruction::ADD | ||||
| 			// stack: itemsPerSlot index (data_ref + index / itemsPerSlot)
 | ||||
| 				<< eth::Instruction::SWAP2 << eth::Instruction::SWAP1 | ||||
| 				<< eth::Instruction::MOD; | ||||
| 				<< Instruction::SWAP2 << Instruction::SWAP1 | ||||
| 				<< Instruction::MOD; | ||||
| 			if (byteSize != 1) | ||||
| 				m_context << u256(byteSize) << eth::Instruction::MUL; | ||||
| 				m_context << u256(byteSize) << Instruction::MUL; | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			if (_arrayType.baseType()->storageSize() != 1) | ||||
| 				m_context << _arrayType.baseType()->storageSize() << eth::Instruction::MUL; | ||||
| 			m_context << eth::Instruction::ADD << u256(0); | ||||
| 				m_context << _arrayType.baseType()->storageSize() << Instruction::MUL; | ||||
| 			m_context << Instruction::ADD << u256(0); | ||||
| 		} | ||||
| 		m_context << endTag; | ||||
| 		break; | ||||
| @ -942,27 +942,27 @@ void ArrayUtils::incrementByteOffset(unsigned _byteSize, unsigned _byteOffsetPos | ||||
| 	//     byteOffset = 0;
 | ||||
| 	// }
 | ||||
| 	if (_byteOffsetPosition > 1) | ||||
| 		m_context << eth::swapInstruction(_byteOffsetPosition - 1); | ||||
| 	m_context << u256(_byteSize) << eth::Instruction::ADD; | ||||
| 		m_context << swapInstruction(_byteOffsetPosition - 1); | ||||
| 	m_context << u256(_byteSize) << Instruction::ADD; | ||||
| 	if (_byteOffsetPosition > 1) | ||||
| 		m_context << eth::swapInstruction(_byteOffsetPosition - 1); | ||||
| 		m_context << swapInstruction(_byteOffsetPosition - 1); | ||||
| 	// compute, X := (byteOffset + byteSize - 1) / 32, should be 1 iff byteOffset + bytesize > 32
 | ||||
| 	m_context | ||||
| 		<< u256(32) << eth::dupInstruction(1 + _byteOffsetPosition) << u256(_byteSize - 1) | ||||
| 		<< eth::Instruction::ADD << eth::Instruction::DIV; | ||||
| 		<< u256(32) << dupInstruction(1 + _byteOffsetPosition) << u256(_byteSize - 1) | ||||
| 		<< Instruction::ADD << Instruction::DIV; | ||||
| 	// increment storage offset if X == 1 (just add X to it)
 | ||||
| 	// stack: X
 | ||||
| 	m_context | ||||
| 		<< eth::swapInstruction(_storageOffsetPosition) << eth::dupInstruction(_storageOffsetPosition + 1) | ||||
| 		<< eth::Instruction::ADD << eth::swapInstruction(_storageOffsetPosition); | ||||
| 		<< swapInstruction(_storageOffsetPosition) << dupInstruction(_storageOffsetPosition + 1) | ||||
| 		<< Instruction::ADD << swapInstruction(_storageOffsetPosition); | ||||
| 	// stack: X
 | ||||
| 	// set source_byte_offset to zero if X == 1 (using source_byte_offset *= 1 - X)
 | ||||
| 	m_context << u256(1) << eth::Instruction::SUB; | ||||
| 	m_context << u256(1) << Instruction::SUB; | ||||
| 	// stack: 1 - X
 | ||||
| 	if (_byteOffsetPosition == 1) | ||||
| 		m_context << eth::Instruction::MUL; | ||||
| 		m_context << Instruction::MUL; | ||||
| 	else | ||||
| 		m_context | ||||
| 			<< eth::dupInstruction(_byteOffsetPosition + 1) << eth::Instruction::MUL | ||||
| 			<< eth::swapInstruction(_byteOffsetPosition) << eth::Instruction::POP; | ||||
| 			<< dupInstruction(_byteOffsetPosition + 1) << Instruction::MUL | ||||
| 			<< swapInstruction(_byteOffsetPosition) << Instruction::POP; | ||||
| } | ||||
|  | ||||
| @ -23,7 +23,7 @@ | ||||
| #include <libsolidity/codegen/Compiler.h> | ||||
| #include <algorithm> | ||||
| #include <boost/range/adaptor/reversed.hpp> | ||||
| #include <libevmcore/Instruction.h> | ||||
| #include <libevmasm/Instruction.h> | ||||
| #include <libethcore/ChainOperationParams.h> | ||||
| #include <libevmasm/Assembly.h> | ||||
| #include <libsolidity/inlineasm/AsmCodeGen.h> | ||||
| @ -92,8 +92,8 @@ void Compiler::compileClone( | ||||
| 	m_runtimeSub = size_t(runtimeSub.data()); | ||||
| 
 | ||||
| 	// stack contains sub size
 | ||||
| 	m_context << eth::Instruction::DUP1 << runtimeSub << u256(0) << eth::Instruction::CODECOPY; | ||||
| 	m_context << u256(0) << eth::Instruction::RETURN; | ||||
| 	m_context << Instruction::DUP1 << runtimeSub << u256(0) << Instruction::CODECOPY; | ||||
| 	m_context << u256(0) << Instruction::RETURN; | ||||
| 
 | ||||
| 	appendFunctionsWithoutCode(); | ||||
| 
 | ||||
| @ -164,8 +164,8 @@ void Compiler::packIntoContractCreator(ContractDefinition const& _contract, Comp | ||||
| 	m_runtimeSub = size_t(runtimeSub.data()); | ||||
| 
 | ||||
| 	// stack contains sub size
 | ||||
| 	m_context << eth::Instruction::DUP1 << runtimeSub << u256(0) << eth::Instruction::CODECOPY; | ||||
| 	m_context << u256(0) << eth::Instruction::RETURN; | ||||
| 	m_context << Instruction::DUP1 << runtimeSub << u256(0) << Instruction::CODECOPY; | ||||
| 	m_context << u256(0) << Instruction::RETURN; | ||||
| 
 | ||||
| 	// note that we have to include the functions again because of absolute jump labels
 | ||||
| 	appendFunctionsWithoutCode(); | ||||
| @ -208,15 +208,15 @@ void Compiler::appendConstructor(FunctionDefinition const& _constructor) | ||||
| 			// argument size is dynamic, use CODESIZE to determine it
 | ||||
| 			m_context.appendProgramSize(); // program itself
 | ||||
| 			// CODESIZE is program plus manually added arguments
 | ||||
| 			m_context << eth::Instruction::CODESIZE << eth::Instruction::SUB; | ||||
| 			m_context << Instruction::CODESIZE << Instruction::SUB; | ||||
| 		} | ||||
| 		else | ||||
| 			m_context << u256(argumentSize); | ||||
| 		// stack: <memptr> <argument size>
 | ||||
| 		m_context << eth::Instruction::DUP1; | ||||
| 		m_context << Instruction::DUP1; | ||||
| 		m_context.appendProgramSize(); | ||||
| 		m_context << eth::Instruction::DUP4 << eth::Instruction::CODECOPY; | ||||
| 		m_context << eth::Instruction::DUP2 << eth::Instruction::ADD; | ||||
| 		m_context << Instruction::DUP4 << Instruction::CODECOPY; | ||||
| 		m_context << Instruction::DUP2 << Instruction::ADD; | ||||
| 		CompilerUtils(m_context).storeFreeMemoryPointer(); | ||||
| 		// stack: <memptr>
 | ||||
| 		appendCalldataUnpacker(FunctionType(_constructor).parameterTypes(), true); | ||||
| @ -235,7 +235,7 @@ void Compiler::appendFunctionSelector(ContractDefinition const& _contract) | ||||
| 	// ether with constant gas
 | ||||
| 	if (interfaceFunctions.size() > 5 || fallback) | ||||
| 	{ | ||||
| 		m_context << eth::Instruction::CALLDATASIZE << eth::Instruction::ISZERO; | ||||
| 		m_context << Instruction::CALLDATASIZE << Instruction::ISZERO; | ||||
| 		m_context.appendConditionalJumpTo(notFound); | ||||
| 	} | ||||
| 
 | ||||
| @ -247,7 +247,7 @@ void Compiler::appendFunctionSelector(ContractDefinition const& _contract) | ||||
| 	for (auto const& it: interfaceFunctions) | ||||
| 	{ | ||||
| 		callDataUnpackerEntryPoints.insert(std::make_pair(it.first, m_context.newTag())); | ||||
| 		m_context << eth::dupInstruction(1) << u256(FixedHash<4>::Arith(it.first)) << eth::Instruction::EQ; | ||||
| 		m_context << dupInstruction(1) << u256(FixedHash<4>::Arith(it.first)) << Instruction::EQ; | ||||
| 		m_context.appendConditionalJumpTo(callDataUnpackerEntryPoints.at(it.first)); | ||||
| 	} | ||||
| 	m_context.appendJumpTo(notFound); | ||||
| @ -264,7 +264,7 @@ void Compiler::appendFunctionSelector(ContractDefinition const& _contract) | ||||
| 		// Reject invalid library calls and ether sent to a library.
 | ||||
| 		m_context.appendJumpTo(m_context.errorTag()); | ||||
| 	else | ||||
| 		m_context << eth::Instruction::STOP; // function not found
 | ||||
| 		m_context << Instruction::STOP; // function not found
 | ||||
| 
 | ||||
| 	for (auto const& it: interfaceFunctions) | ||||
| 	{ | ||||
| @ -288,7 +288,7 @@ void Compiler::appendCalldataUnpacker(TypePointers const& _typeParameters, bool | ||||
| 	//@todo this does not yet support nested dynamic arrays
 | ||||
| 
 | ||||
| 	// Retain the offset pointer as base_offset, the point from which the data offsets are computed.
 | ||||
| 	m_context << eth::Instruction::DUP1; | ||||
| 	m_context << Instruction::DUP1; | ||||
| 	for (TypePointer const& parameterType: _typeParameters) | ||||
| 	{ | ||||
| 		// stack: v1 v2 ... v(k-1) base_offset current_offset
 | ||||
| @ -309,15 +309,15 @@ void Compiler::appendCalldataUnpacker(TypePointers const& _typeParameters, bool | ||||
| 				if (arrayType.isDynamicallySized()) | ||||
| 				{ | ||||
| 					// compute data pointer
 | ||||
| 					m_context << eth::Instruction::DUP1 << eth::Instruction::MLOAD; | ||||
| 					m_context << eth::Instruction::DUP3 << eth::Instruction::ADD; | ||||
| 					m_context << eth::Instruction::SWAP2 << eth::Instruction::SWAP1; | ||||
| 					m_context << u256(0x20) << eth::Instruction::ADD; | ||||
| 					m_context << Instruction::DUP1 << Instruction::MLOAD; | ||||
| 					m_context << Instruction::DUP3 << Instruction::ADD; | ||||
| 					m_context << Instruction::SWAP2 << Instruction::SWAP1; | ||||
| 					m_context << u256(0x20) << Instruction::ADD; | ||||
| 				} | ||||
| 				else | ||||
| 				{ | ||||
| 					m_context << eth::Instruction::DUP1; | ||||
| 					m_context << u256(arrayType.calldataEncodedSize(true)) << eth::Instruction::ADD; | ||||
| 					m_context << Instruction::DUP1; | ||||
| 					m_context << u256(arrayType.calldataEncodedSize(true)) << Instruction::ADD; | ||||
| 				} | ||||
| 			} | ||||
| 			else | ||||
| @ -329,19 +329,19 @@ void Compiler::appendCalldataUnpacker(TypePointers const& _typeParameters, bool | ||||
| 					// put on stack: data_pointer length
 | ||||
| 					CompilerUtils(m_context).loadFromMemoryDynamic(IntegerType(256), !_fromMemory); | ||||
| 					// stack: base_offset data_offset next_pointer
 | ||||
| 					m_context << eth::Instruction::SWAP1 << eth::Instruction::DUP3 << eth::Instruction::ADD; | ||||
| 					m_context << Instruction::SWAP1 << Instruction::DUP3 << Instruction::ADD; | ||||
| 					// stack: base_offset next_pointer data_pointer
 | ||||
| 					// retrieve length
 | ||||
| 					CompilerUtils(m_context).loadFromMemoryDynamic(IntegerType(256), !_fromMemory, true); | ||||
| 					// stack: base_offset next_pointer length data_pointer
 | ||||
| 					m_context << eth::Instruction::SWAP2; | ||||
| 					m_context << Instruction::SWAP2; | ||||
| 					// stack: base_offset data_pointer length next_pointer
 | ||||
| 				} | ||||
| 				else | ||||
| 				{ | ||||
| 					// leave the pointer on the stack
 | ||||
| 					m_context << eth::Instruction::DUP1; | ||||
| 					m_context << u256(calldataType->calldataEncodedSize()) << eth::Instruction::ADD; | ||||
| 					m_context << Instruction::DUP1; | ||||
| 					m_context << u256(calldataType->calldataEncodedSize()) << Instruction::ADD; | ||||
| 				} | ||||
| 				if (arrayType.location() == DataLocation::Memory) | ||||
| 				{ | ||||
| @ -355,7 +355,7 @@ void Compiler::appendCalldataUnpacker(TypePointers const& _typeParameters, bool | ||||
| 				} | ||||
| 				// move base_offset up
 | ||||
| 				CompilerUtils(m_context).moveToStackTop(1 + arrayType.sizeOnStack()); | ||||
| 				m_context << eth::Instruction::SWAP1; | ||||
| 				m_context << Instruction::SWAP1; | ||||
| 			} | ||||
| 		} | ||||
| 		else | ||||
| @ -363,18 +363,18 @@ void Compiler::appendCalldataUnpacker(TypePointers const& _typeParameters, bool | ||||
| 			solAssert(!type->isDynamicallySized(), "Unknown dynamically sized type: " + type->toString()); | ||||
| 			CompilerUtils(m_context).loadFromMemoryDynamic(*type, !_fromMemory, true); | ||||
| 			CompilerUtils(m_context).moveToStackTop(1 + type->sizeOnStack()); | ||||
| 			m_context << eth::Instruction::SWAP1; | ||||
| 			m_context << Instruction::SWAP1; | ||||
| 		} | ||||
| 		// stack: v1 v2 ... v(k-1) v(k) base_offset mem_offset
 | ||||
| 	} | ||||
| 	m_context << eth::Instruction::POP << eth::Instruction::POP; | ||||
| 	m_context << Instruction::POP << Instruction::POP; | ||||
| } | ||||
| 
 | ||||
| void Compiler::appendReturnValuePacker(TypePointers const& _typeParameters, bool _isLibrary) | ||||
| { | ||||
| 	CompilerUtils utils(m_context); | ||||
| 	if (_typeParameters.empty()) | ||||
| 		m_context << eth::Instruction::STOP; | ||||
| 		m_context << Instruction::STOP; | ||||
| 	else | ||||
| 	{ | ||||
| 		utils.fetchFreeMemoryPointer(); | ||||
| @ -382,7 +382,7 @@ void Compiler::appendReturnValuePacker(TypePointers const& _typeParameters, bool | ||||
| 		// its data to add the needed parts and we avoid a memory copy.
 | ||||
| 		utils.encodeToMemory(_typeParameters, _typeParameters, true, false, _isLibrary); | ||||
| 		utils.toSizeAfterFreeMemoryPointer(); | ||||
| 		m_context << eth::Instruction::RETURN; | ||||
| 		m_context << Instruction::RETURN; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| @ -476,12 +476,12 @@ bool Compiler::visit(FunctionDefinition const& _function) | ||||
| 	while (stackLayout.back() != int(stackLayout.size() - 1)) | ||||
| 		if (stackLayout.back() < 0) | ||||
| 		{ | ||||
| 			m_context << eth::Instruction::POP; | ||||
| 			m_context << Instruction::POP; | ||||
| 			stackLayout.pop_back(); | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			m_context << eth::swapInstruction(stackLayout.size() - stackLayout.back() - 1); | ||||
| 			m_context << swapInstruction(stackLayout.size() - stackLayout.back() - 1); | ||||
| 			swap(stackLayout[stackLayout.back()], stackLayout.back()); | ||||
| 		} | ||||
| 	//@todo assert that everything is in place now
 | ||||
| @ -532,7 +532,7 @@ bool Compiler::visit(InlineAssembly const& _inlineAssembly) | ||||
| 								errinfo_comment("Stack too deep, try removing local variables.") | ||||
| 							); | ||||
| 						for (unsigned i = 0; i < variable->type()->sizeOnStack(); ++i) | ||||
| 							_assembly.append(eth::dupInstruction(stackDiff)); | ||||
| 							_assembly.append(dupInstruction(stackDiff)); | ||||
| 					} | ||||
| 					else | ||||
| 					{ | ||||
| @ -572,8 +572,8 @@ bool Compiler::visit(InlineAssembly const& _inlineAssembly) | ||||
| 						errinfo_comment("Stack too deep, try removing local variables.") | ||||
| 					); | ||||
| 				for (unsigned i = 0; i < size; ++i) { | ||||
| 					_assembly.append(eth::swapInstruction(stackDiff)); | ||||
| 					_assembly.append(eth::Instruction::POP); | ||||
| 					_assembly.append(swapInstruction(stackDiff)); | ||||
| 					_assembly.append(Instruction::POP); | ||||
| 				} | ||||
| 			} | ||||
| 			return true; | ||||
| @ -588,7 +588,7 @@ bool Compiler::visit(IfStatement const& _ifStatement) | ||||
| 	StackHeightChecker checker(m_context); | ||||
| 	CompilerContext::LocationSetter locationSetter(m_context, _ifStatement); | ||||
| 	compileExpression(_ifStatement.condition()); | ||||
| 	m_context << eth::Instruction::ISZERO; | ||||
| 	m_context << Instruction::ISZERO; | ||||
| 	eth::AssemblyItem falseTag = m_context.appendConditionalJump(); | ||||
| 	eth::AssemblyItem endTag = falseTag; | ||||
| 	_ifStatement.trueStatement().accept(*this); | ||||
| @ -615,7 +615,7 @@ bool Compiler::visit(WhileStatement const& _whileStatement) | ||||
| 
 | ||||
| 	m_context << loopStart; | ||||
| 	compileExpression(_whileStatement.condition()); | ||||
| 	m_context << eth::Instruction::ISZERO; | ||||
| 	m_context << Instruction::ISZERO; | ||||
| 	m_context.appendConditionalJumpTo(loopEnd); | ||||
| 
 | ||||
| 	_whileStatement.body().accept(*this); | ||||
| @ -649,7 +649,7 @@ bool Compiler::visit(ForStatement const& _forStatement) | ||||
| 	if (_forStatement.condition()) | ||||
| 	{ | ||||
| 		compileExpression(*_forStatement.condition()); | ||||
| 		m_context << eth::Instruction::ISZERO; | ||||
| 		m_context << Instruction::ISZERO; | ||||
| 		m_context.appendConditionalJumpTo(loopEnd); | ||||
| 	} | ||||
| 
 | ||||
| @ -710,7 +710,7 @@ bool Compiler::visit(Return const& _return) | ||||
| 			CompilerUtils(m_context).moveToStackVariable(*retVariable); | ||||
| 	} | ||||
| 	for (unsigned i = 0; i < m_stackCleanupForReturn; ++i) | ||||
| 		m_context << eth::Instruction::POP; | ||||
| 		m_context << Instruction::POP; | ||||
| 	m_context.appendJumpTo(m_returnTag); | ||||
| 	m_context.adjustStackOffset(m_stackCleanupForReturn); | ||||
| 	return false; | ||||
| @ -831,7 +831,7 @@ void Compiler::appendModifierOrFunctionCode() | ||||
| 		modifier.body().accept(*this); | ||||
| 
 | ||||
| 		for (unsigned i = 0; i < c_stackSurplus; ++i) | ||||
| 			m_context << eth::Instruction::POP; | ||||
| 			m_context << Instruction::POP; | ||||
| 		m_stackCleanupForReturn -= c_stackSurplus; | ||||
| 	} | ||||
| } | ||||
| @ -855,20 +855,20 @@ eth::Assembly Compiler::cloneRuntime() | ||||
| { | ||||
| 	eth::EVMSchedule schedule; | ||||
| 	eth::Assembly a; | ||||
| 	a << eth::Instruction::CALLDATASIZE; | ||||
| 	a << u256(0) << eth::Instruction::DUP1 << eth::Instruction::CALLDATACOPY; | ||||
| 	a << Instruction::CALLDATASIZE; | ||||
| 	a << u256(0) << Instruction::DUP1 << Instruction::CALLDATACOPY; | ||||
| 	//@todo adjust for larger return values, make this dynamic.
 | ||||
| 	a << u256(0x20) << u256(0) << eth::Instruction::CALLDATASIZE; | ||||
| 	a << u256(0x20) << u256(0) << Instruction::CALLDATASIZE; | ||||
| 	a << u256(0); | ||||
| 	// this is the address which has to be substituted by the linker.
 | ||||
| 	//@todo implement as special "marker" AssemblyItem.
 | ||||
| 	a << u256("0xcafecafecafecafecafecafecafecafecafecafe"); | ||||
| 	a << u256(schedule.callGas + 10) << eth::Instruction::GAS << eth::Instruction::SUB; | ||||
| 	a << eth::Instruction::DELEGATECALL; | ||||
| 	a << u256(schedule.callGas + 10) << Instruction::GAS << Instruction::SUB; | ||||
| 	a << Instruction::DELEGATECALL; | ||||
| 	//Propagate error condition (if DELEGATECALL pushes 0 on stack).
 | ||||
| 	a << eth::Instruction::ISZERO; | ||||
| 	a << Instruction::ISZERO; | ||||
| 	a.appendJumpI(a.errorTag()); | ||||
| 	//@todo adjust for larger return values, make this dynamic.
 | ||||
| 	a << u256(0x20) << u256(0) << eth::Instruction::RETURN; | ||||
| 	a << u256(0x20) << u256(0) << Instruction::RETURN; | ||||
| 	return a; | ||||
| } | ||||
|  | ||||
| @ -166,7 +166,7 @@ pair<u256, unsigned> CompilerContext::storageLocationOfVariable(const Declaratio | ||||
| 
 | ||||
| CompilerContext& CompilerContext::appendJump(eth::AssemblyItem::JumpType _jumpType) | ||||
| { | ||||
| 	eth::AssemblyItem item(eth::Instruction::JUMP); | ||||
| 	eth::AssemblyItem item(Instruction::JUMP); | ||||
| 	item.setJumpType(_jumpType); | ||||
| 	return *this << item; | ||||
| } | ||||
| @ -182,7 +182,7 @@ void CompilerContext::resetVisitedNodes(ASTNode const* _node) | ||||
| void CompilerContext::injectVersionStampIntoSub(size_t _subIndex) | ||||
| { | ||||
| 	eth::Assembly& sub = m_asm.sub(_subIndex); | ||||
| 	sub.injectStart(eth::Instruction::POP); | ||||
| 	sub.injectStart(Instruction::POP); | ||||
| 	sub.injectStart(fromBigEndian<u256>(binaryVersion())); | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -25,7 +25,7 @@ | ||||
| #include <ostream> | ||||
| #include <stack> | ||||
| #include <utility> | ||||
| #include <libevmcore/Instruction.h> | ||||
| #include <libevmasm/Instruction.h> | ||||
| #include <libevmasm/Assembly.h> | ||||
| #include <libsolidity/ast/ASTForward.h> | ||||
| #include <libsolidity/ast/Types.h> | ||||
| @ -126,7 +126,7 @@ public: | ||||
| 
 | ||||
| 	/// Append elements to the current instruction list and adjust @a m_stackOffset.
 | ||||
| 	CompilerContext& operator<<(eth::AssemblyItem const& _item) { m_asm.append(_item); return *this; } | ||||
| 	CompilerContext& operator<<(eth::Instruction _instruction) { m_asm.append(_instruction); return *this; } | ||||
| 	CompilerContext& operator<<(Instruction _instruction) { m_asm.append(_instruction); return *this; } | ||||
| 	CompilerContext& operator<<(u256 const& _value) { m_asm.append(_value); return *this; } | ||||
| 	CompilerContext& operator<<(bytes const& _data) { m_asm.append(_data); return *this; } | ||||
| 
 | ||||
|  | ||||
| @ -22,7 +22,7 @@ | ||||
| 
 | ||||
| #include <libsolidity/codegen/CompilerUtils.h> | ||||
| #include <libsolidity/ast/AST.h> | ||||
| #include <libevmcore/Instruction.h> | ||||
| #include <libevmasm/Instruction.h> | ||||
| #include <libsolidity/codegen/ArrayUtils.h> | ||||
| #include <libsolidity/codegen/LValue.h> | ||||
| 
 | ||||
| @ -45,26 +45,26 @@ void CompilerUtils::initialiseFreeMemoryPointer() | ||||
| 
 | ||||
| void CompilerUtils::fetchFreeMemoryPointer() | ||||
| { | ||||
| 	m_context << u256(freeMemoryPointer) << eth::Instruction::MLOAD; | ||||
| 	m_context << u256(freeMemoryPointer) << Instruction::MLOAD; | ||||
| } | ||||
| 
 | ||||
| void CompilerUtils::storeFreeMemoryPointer() | ||||
| { | ||||
| 	m_context << u256(freeMemoryPointer) << eth::Instruction::MSTORE; | ||||
| 	m_context << u256(freeMemoryPointer) << Instruction::MSTORE; | ||||
| } | ||||
| 
 | ||||
| void CompilerUtils::allocateMemory() | ||||
| { | ||||
| 	fetchFreeMemoryPointer(); | ||||
| 	m_context << eth::Instruction::SWAP1 << eth::Instruction::DUP2 << eth::Instruction::ADD; | ||||
| 	m_context << Instruction::SWAP1 << Instruction::DUP2 << Instruction::ADD; | ||||
| 	storeFreeMemoryPointer(); | ||||
| } | ||||
| 
 | ||||
| void CompilerUtils::toSizeAfterFreeMemoryPointer() | ||||
| { | ||||
| 	fetchFreeMemoryPointer(); | ||||
| 	m_context << eth::Instruction::DUP1 << eth::Instruction::SWAP2 << eth::Instruction::SUB; | ||||
| 	m_context << eth::Instruction::SWAP1; | ||||
| 	m_context << Instruction::DUP1 << Instruction::SWAP2 << Instruction::SUB; | ||||
| 	m_context << Instruction::SWAP1; | ||||
| } | ||||
| 
 | ||||
| unsigned CompilerUtils::loadFromMemory( | ||||
| @ -87,7 +87,7 @@ void CompilerUtils::loadFromMemoryDynamic( | ||||
| ) | ||||
| {		 | ||||
| 	if (_keepUpdatedMemoryOffset) | ||||
| 		m_context << eth::Instruction::DUP1; | ||||
| 		m_context << Instruction::DUP1; | ||||
| 
 | ||||
| 	if (auto arrayType = dynamic_cast<ArrayType const*>(&_type)) | ||||
| 	{ | ||||
| @ -95,7 +95,7 @@ void CompilerUtils::loadFromMemoryDynamic( | ||||
| 		solAssert(!_fromCalldata, ""); | ||||
| 		solAssert(_padToWordBoundaries, ""); | ||||
| 		if (_keepUpdatedMemoryOffset) | ||||
| 			m_context << arrayType->memorySize() << eth::Instruction::ADD; | ||||
| 			m_context << arrayType->memorySize() << Instruction::ADD; | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| @ -104,7 +104,7 @@ void CompilerUtils::loadFromMemoryDynamic( | ||||
| 		{ | ||||
| 			// update memory counter
 | ||||
| 			moveToStackTop(_type.sizeOnStack()); | ||||
| 			m_context << u256(numBytes) << eth::Instruction::ADD; | ||||
| 			m_context << u256(numBytes) << Instruction::ADD; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| @ -113,7 +113,7 @@ void CompilerUtils::storeInMemory(unsigned _offset) | ||||
| { | ||||
| 	unsigned numBytes = prepareMemoryStore(IntegerType(256), true); | ||||
| 	if (numBytes > 0) | ||||
| 		m_context << u256(_offset) << eth::Instruction::MSTORE; | ||||
| 		m_context << u256(_offset) << Instruction::MSTORE; | ||||
| } | ||||
| 
 | ||||
| void CompilerUtils::storeInMemoryDynamic(Type const& _type, bool _padToWordBoundaries) | ||||
| @ -125,13 +125,13 @@ void CompilerUtils::storeInMemoryDynamic(Type const& _type, bool _padToWordBound | ||||
| 	} | ||||
| 	else if (auto str = dynamic_cast<StringLiteralType const*>(&_type)) | ||||
| 	{ | ||||
| 		m_context << eth::Instruction::DUP1; | ||||
| 		m_context << Instruction::DUP1; | ||||
| 		storeStringData(bytesConstRef(str->value())); | ||||
| 		if (_padToWordBoundaries) | ||||
| 			m_context << u256(((str->value().size() + 31) / 32) * 32); | ||||
| 		else | ||||
| 			m_context << u256(str->value().size()); | ||||
| 		m_context << eth::Instruction::ADD; | ||||
| 		m_context << Instruction::ADD; | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| @ -142,8 +142,8 @@ void CompilerUtils::storeInMemoryDynamic(Type const& _type, bool _padToWordBound | ||||
| 				_type.sizeOnStack() == 1, | ||||
| 				"Memory store of types with stack size != 1 not implemented." | ||||
| 			); | ||||
| 			m_context << eth::Instruction::DUP2 << eth::Instruction::MSTORE; | ||||
| 			m_context << u256(numBytes) << eth::Instruction::ADD; | ||||
| 			m_context << Instruction::DUP2 << Instruction::MSTORE; | ||||
| 			m_context << u256(numBytes) << Instruction::ADD; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| @ -168,7 +168,7 @@ void CompilerUtils::encodeToMemory( | ||||
| 	// of the ith dynamic parameter, which is filled once the dynamic parts are processed.
 | ||||
| 
 | ||||
| 	// store memory start pointer
 | ||||
| 	m_context << eth::Instruction::DUP1; | ||||
| 	m_context << Instruction::DUP1; | ||||
| 
 | ||||
| 	unsigned argSize = CompilerUtils::sizeOnStack(_givenTypes); | ||||
| 	unsigned stackPos = 0; // advances through the argument values
 | ||||
| @ -180,7 +180,7 @@ void CompilerUtils::encodeToMemory( | ||||
| 		if (targetType->isDynamicallySized() && !_copyDynamicDataInPlace) | ||||
| 		{ | ||||
| 			// leave end_of_mem as dyn head pointer
 | ||||
| 			m_context << eth::Instruction::DUP1 << u256(32) << eth::Instruction::ADD; | ||||
| 			m_context << Instruction::DUP1 << u256(32) << Instruction::ADD; | ||||
| 			dynPointers++; | ||||
| 		} | ||||
| 		else | ||||
| @ -222,10 +222,10 @@ void CompilerUtils::encodeToMemory( | ||||
| 		if (targetType->isDynamicallySized() && !_copyDynamicDataInPlace) | ||||
| 		{ | ||||
| 			// copy tail pointer (=mem_end - mem_start) to memory
 | ||||
| 			m_context << eth::dupInstruction(2 + dynPointers) << eth::Instruction::DUP2; | ||||
| 			m_context << eth::Instruction::SUB; | ||||
| 			m_context << eth::dupInstruction(2 + dynPointers - thisDynPointer); | ||||
| 			m_context << eth::Instruction::MSTORE; | ||||
| 			m_context << dupInstruction(2 + dynPointers) << Instruction::DUP2; | ||||
| 			m_context << Instruction::SUB; | ||||
| 			m_context << dupInstruction(2 + dynPointers - thisDynPointer); | ||||
| 			m_context << Instruction::MSTORE; | ||||
| 			// stack: ... <end_of_mem>
 | ||||
| 			if (_givenTypes[i]->category() == Type::Category::StringLiteral) | ||||
| 			{ | ||||
| @ -243,13 +243,13 @@ void CompilerUtils::encodeToMemory( | ||||
| 				copyToStackTop(argSize - stackPos + dynPointers + 2, arrayType.sizeOnStack()); | ||||
| 				// stack: ... <end_of_mem> <value...>
 | ||||
| 				// copy length to memory
 | ||||
| 				m_context << eth::dupInstruction(1 + arrayType.sizeOnStack()); | ||||
| 				m_context << dupInstruction(1 + arrayType.sizeOnStack()); | ||||
| 				ArrayUtils(m_context).retrieveLength(arrayType, 1); | ||||
| 				// stack: ... <end_of_mem> <value...> <end_of_mem'> <length>
 | ||||
| 				storeInMemoryDynamic(IntegerType(256), true); | ||||
| 				// stack: ... <end_of_mem> <value...> <end_of_mem''>
 | ||||
| 				// copy the new memory pointer
 | ||||
| 				m_context << eth::swapInstruction(arrayType.sizeOnStack() + 1) << eth::Instruction::POP; | ||||
| 				m_context << swapInstruction(arrayType.sizeOnStack() + 1) << Instruction::POP; | ||||
| 				// stack: ... <end_of_mem''> <value...>
 | ||||
| 				// copy data part
 | ||||
| 				ArrayUtils(m_context).copyArrayToMemory(arrayType, _padToWordBoundaries); | ||||
| @ -262,7 +262,7 @@ void CompilerUtils::encodeToMemory( | ||||
| 	} | ||||
| 
 | ||||
| 	// remove unneeded stack elements (and retain memory pointer)
 | ||||
| 	m_context << eth::swapInstruction(argSize + dynPointers + 1); | ||||
| 	m_context << swapInstruction(argSize + dynPointers + 1); | ||||
| 	popStackSlots(argSize + dynPointers + 1); | ||||
| } | ||||
| 
 | ||||
| @ -272,11 +272,11 @@ void CompilerUtils::zeroInitialiseMemoryArray(ArrayType const& _type) | ||||
| 	m_context << repeat; | ||||
| 	pushZeroValue(*_type.baseType()); | ||||
| 	storeInMemoryDynamic(*_type.baseType()); | ||||
| 	m_context << eth::Instruction::SWAP1 << u256(1) << eth::Instruction::SWAP1; | ||||
| 	m_context << eth::Instruction::SUB << eth::Instruction::SWAP1; | ||||
| 	m_context << eth::Instruction::DUP2; | ||||
| 	m_context << Instruction::SWAP1 << u256(1) << Instruction::SWAP1; | ||||
| 	m_context << Instruction::SUB << Instruction::SWAP1; | ||||
| 	m_context << Instruction::DUP2; | ||||
| 	m_context.appendConditionalJumpTo(repeat); | ||||
| 	m_context << eth::Instruction::SWAP1 << eth::Instruction::POP; | ||||
| 	m_context << Instruction::SWAP1 << Instruction::POP; | ||||
| } | ||||
| 
 | ||||
| void CompilerUtils::memoryCopy() | ||||
| @ -284,16 +284,16 @@ void CompilerUtils::memoryCopy() | ||||
| 	// Stack here: size target source
 | ||||
| 	// stack for call: outsize target size source value contract gas
 | ||||
| 	//@TODO do not use ::CALL if less than 32 bytes?
 | ||||
| 	m_context << eth::Instruction::DUP3 << eth::Instruction::SWAP1; | ||||
| 	m_context << Instruction::DUP3 << Instruction::SWAP1; | ||||
| 	m_context << u256(0) << u256(identityContractAddress); | ||||
| 	// compute gas costs
 | ||||
| 	m_context << u256(32) << eth::Instruction::DUP5 << u256(31) << eth::Instruction::ADD; | ||||
| 	m_context << u256(32) << Instruction::DUP5 << u256(31) << Instruction::ADD; | ||||
| 	static unsigned c_identityGas = 3; | ||||
| 	static unsigned c_identityWordGas = 15; | ||||
| 	m_context << eth::Instruction::DIV << u256(c_identityWordGas) << eth::Instruction::MUL; | ||||
| 	m_context << u256(c_identityGas) << eth::Instruction::ADD; | ||||
| 	m_context << eth::Instruction::CALL; | ||||
| 	m_context << eth::Instruction::POP; // ignore return value
 | ||||
| 	m_context << Instruction::DIV << u256(c_identityWordGas) << Instruction::MUL; | ||||
| 	m_context << u256(c_identityGas) << Instruction::ADD; | ||||
| 	m_context << Instruction::CALL; | ||||
| 	m_context << Instruction::POP; // ignore return value
 | ||||
| } | ||||
| 
 | ||||
| void CompilerUtils::convertType(Type const& _typeOnStack, Type const& _targetType, bool _cleanupNeeded) | ||||
| @ -317,7 +317,7 @@ void CompilerUtils::convertType(Type const& _typeOnStack, Type const& _targetTyp | ||||
| 			// conversion from bytes to integer. no need to clean the high bit
 | ||||
| 			// only to shift right because of opposite alignment
 | ||||
| 			IntegerType const& targetIntegerType = dynamic_cast<IntegerType const&>(_targetType); | ||||
| 			m_context << (u256(1) << (256 - typeOnStack.numBytes() * 8)) << eth::Instruction::SWAP1 << eth::Instruction::DIV; | ||||
| 			m_context << (u256(1) << (256 - typeOnStack.numBytes() * 8)) << Instruction::SWAP1 << Instruction::DIV; | ||||
| 			if (targetIntegerType.numBits() < typeOnStack.numBytes() * 8) | ||||
| 				convertType(IntegerType(typeOnStack.numBytes() * 8), _targetType, _cleanupNeeded); | ||||
| 		} | ||||
| @ -329,12 +329,12 @@ void CompilerUtils::convertType(Type const& _typeOnStack, Type const& _targetTyp | ||||
| 			if (targetType.numBytes() < typeOnStack.numBytes()) | ||||
| 			{ | ||||
| 				if (targetType.numBytes() == 0) | ||||
| 					m_context << eth::Instruction::DUP1 << eth::Instruction::XOR; | ||||
| 					m_context << Instruction::DUP1 << Instruction::XOR; | ||||
| 				else | ||||
| 				{ | ||||
| 					m_context << (u256(1) << (256 - targetType.numBytes() * 8)); | ||||
| 					m_context << eth::Instruction::DUP1 << eth::Instruction::SWAP2; | ||||
| 					m_context << eth::Instruction::DIV << eth::Instruction::MUL; | ||||
| 					m_context << Instruction::DUP1 << Instruction::SWAP2; | ||||
| 					m_context << Instruction::DIV << Instruction::MUL; | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| @ -356,7 +356,7 @@ void CompilerUtils::convertType(Type const& _typeOnStack, Type const& _targetTyp | ||||
| 			if (auto typeOnStack = dynamic_cast<IntegerType const*>(&_typeOnStack)) | ||||
| 				if (targetBytesType.numBytes() * 8 > typeOnStack->numBits()) | ||||
| 					cleanHigherOrderBits(*typeOnStack); | ||||
| 			m_context << (u256(1) << (256 - targetBytesType.numBytes() * 8)) << eth::Instruction::MUL; | ||||
| 			m_context << (u256(1) << (256 - targetBytesType.numBytes() * 8)) << Instruction::MUL; | ||||
| 		} | ||||
| 		else if (targetTypeCategory == Type::Category::Enum) | ||||
| 			// just clean
 | ||||
| @ -406,7 +406,7 @@ void CompilerUtils::convertType(Type const& _typeOnStack, Type const& _targetTyp | ||||
| 			m_context << storageSize; | ||||
| 			allocateMemory(); | ||||
| 			// stack: mempos
 | ||||
| 			m_context << eth::Instruction::DUP1 << u256(data.size()); | ||||
| 			m_context << Instruction::DUP1 << u256(data.size()); | ||||
| 			storeInMemoryDynamic(IntegerType(256)); | ||||
| 			// stack: mempos datapos
 | ||||
| 			storeStringData(data); | ||||
| @ -445,18 +445,18 @@ void CompilerUtils::convertType(Type const& _typeOnStack, Type const& _targetTyp | ||||
| 
 | ||||
| 				// allocate memory
 | ||||
| 				// stack: <source ref> (variably sized) <length>
 | ||||
| 				m_context << eth::Instruction::DUP1; | ||||
| 				m_context << Instruction::DUP1; | ||||
| 				ArrayUtils(m_context).convertLengthToSize(targetType, true); | ||||
| 				// stack: <source ref> (variably sized) <length> <size>
 | ||||
| 				if (targetType.isDynamicallySized()) | ||||
| 					m_context << u256(0x20) << eth::Instruction::ADD; | ||||
| 					m_context << u256(0x20) << Instruction::ADD; | ||||
| 				allocateMemory(); | ||||
| 				// stack: <source ref> (variably sized) <length> <mem start>
 | ||||
| 				m_context << eth::Instruction::DUP1; | ||||
| 				m_context << Instruction::DUP1; | ||||
| 				moveIntoStack(2 + stackSize); | ||||
| 				if (targetType.isDynamicallySized()) | ||||
| 				{ | ||||
| 					m_context << eth::Instruction::DUP2; | ||||
| 					m_context << Instruction::DUP2; | ||||
| 					storeInMemoryDynamic(IntegerType(256)); | ||||
| 				} | ||||
| 				// stack: <mem start> <source ref> (variably sized) <length> <mem data pos>
 | ||||
| @ -468,12 +468,12 @@ void CompilerUtils::convertType(Type const& _typeOnStack, Type const& _targetTyp | ||||
| 				} | ||||
| 				else | ||||
| 				{ | ||||
| 					m_context << u256(0) << eth::Instruction::SWAP1; | ||||
| 					m_context << u256(0) << Instruction::SWAP1; | ||||
| 					// stack: <mem start> <source ref> (variably sized) <length> <counter> <mem data pos>
 | ||||
| 					auto repeat = m_context.newTag(); | ||||
| 					m_context << repeat; | ||||
| 					m_context << eth::Instruction::DUP3 << eth::Instruction::DUP3; | ||||
| 					m_context << eth::Instruction::LT << eth::Instruction::ISZERO; | ||||
| 					m_context << Instruction::DUP3 << Instruction::DUP3; | ||||
| 					m_context << Instruction::LT << Instruction::ISZERO; | ||||
| 					auto loopEnd = m_context.appendConditionalJump(); | ||||
| 					copyToStackTop(3 + stackSize, stackSize); | ||||
| 					copyToStackTop(2 + stackSize, 1); | ||||
| @ -482,11 +482,11 @@ void CompilerUtils::convertType(Type const& _typeOnStack, Type const& _targetTyp | ||||
| 						StorageItem(m_context, *typeOnStack.baseType()).retrieveValue(SourceLocation(), true); | ||||
| 					convertType(*typeOnStack.baseType(), *targetType.baseType(), _cleanupNeeded); | ||||
| 					storeInMemoryDynamic(*targetType.baseType(), true); | ||||
| 					m_context << eth::Instruction::SWAP1 << u256(1) << eth::Instruction::ADD; | ||||
| 					m_context << eth::Instruction::SWAP1; | ||||
| 					m_context << Instruction::SWAP1 << u256(1) << Instruction::ADD; | ||||
| 					m_context << Instruction::SWAP1; | ||||
| 					m_context.appendJumpTo(repeat); | ||||
| 					m_context << loopEnd; | ||||
| 					m_context << eth::Instruction::POP; | ||||
| 					m_context << Instruction::POP; | ||||
| 				} | ||||
| 				// stack: <mem start> <source ref> (variably sized) <length> <mem data pos updated>
 | ||||
| 				popStackSlots(2 + stackSize); | ||||
| @ -540,14 +540,14 @@ void CompilerUtils::convertType(Type const& _typeOnStack, Type const& _targetTyp | ||||
| 				// stack: <source ref>
 | ||||
| 				m_context << typeOnStack.memorySize(); | ||||
| 				allocateMemory(); | ||||
| 				m_context << eth::Instruction::SWAP1 << eth::Instruction::DUP2; | ||||
| 				m_context << Instruction::SWAP1 << Instruction::DUP2; | ||||
| 				// stack: <memory ptr> <source ref> <memory ptr>
 | ||||
| 				for (auto const& member: typeOnStack.members(nullptr)) | ||||
| 				{ | ||||
| 					if (!member.type->canLiveOutsideStorage()) | ||||
| 						continue; | ||||
| 					pair<u256, unsigned> const& offsets = typeOnStack.storageOffsetsOfMember(member.name); | ||||
| 					m_context << offsets.first << eth::Instruction::DUP3 << eth::Instruction::ADD; | ||||
| 					m_context << offsets.first << Instruction::DUP3 << Instruction::ADD; | ||||
| 					m_context << u256(offsets.second); | ||||
| 					StorageItem(m_context, *member.type).retrieveValue(SourceLocation(), true); | ||||
| 					TypePointer targetMemberType = targetType.memberType(member.name); | ||||
| @ -555,7 +555,7 @@ void CompilerUtils::convertType(Type const& _typeOnStack, Type const& _targetTyp | ||||
| 					convertType(*member.type, *targetMemberType, true); | ||||
| 					storeInMemoryDynamic(*targetMemberType, true); | ||||
| 				} | ||||
| 				m_context << eth::Instruction::POP << eth::Instruction::POP; | ||||
| 				m_context << Instruction::POP << Instruction::POP; | ||||
| 			} | ||||
| 			break; | ||||
| 		case DataLocation::CallData: | ||||
| @ -602,13 +602,13 @@ void CompilerUtils::convertType(Type const& _typeOnStack, Type const& _targetTyp | ||||
| 					// Move it back into its place.
 | ||||
| 					for (unsigned j = 0; j < min(sourceSize, targetSize); ++j) | ||||
| 						m_context << | ||||
| 							eth::swapInstruction(depth + targetSize - sourceSize) << | ||||
| 							eth::Instruction::POP; | ||||
| 							swapInstruction(depth + targetSize - sourceSize) << | ||||
| 							Instruction::POP; | ||||
| 					// Value shrank
 | ||||
| 					for (unsigned j = targetSize; j < sourceSize; ++j) | ||||
| 					{ | ||||
| 						moveToStackTop(depth - 1, 1); | ||||
| 						m_context << eth::Instruction::POP; | ||||
| 						m_context << Instruction::POP; | ||||
| 					} | ||||
| 					// Value grew
 | ||||
| 					if (targetSize > sourceSize) | ||||
| @ -639,7 +639,7 @@ void CompilerUtils::pushZeroValue(Type const& _type) | ||||
| 
 | ||||
| 	m_context << u256(max(32u, _type.calldataEncodedSize())); | ||||
| 	allocateMemory(); | ||||
| 	m_context << eth::Instruction::DUP1; | ||||
| 	m_context << Instruction::DUP1; | ||||
| 
 | ||||
| 	if (auto structType = dynamic_cast<StructType const*>(&_type)) | ||||
| 		for (auto const& member: structType->members(nullptr)) | ||||
| @ -657,7 +657,7 @@ void CompilerUtils::pushZeroValue(Type const& _type) | ||||
| 		} | ||||
| 		else if (arrayType->length() > 0) | ||||
| 		{ | ||||
| 			m_context << arrayType->length() << eth::Instruction::SWAP1; | ||||
| 			m_context << arrayType->length() << Instruction::SWAP1; | ||||
| 			// stack: items_to_do memory_pos
 | ||||
| 			zeroInitialiseMemoryArray(*arrayType); | ||||
| 			// stack: updated_memory_pos
 | ||||
| @ -667,7 +667,7 @@ void CompilerUtils::pushZeroValue(Type const& _type) | ||||
| 		solAssert(false, "Requested initialisation for unknown type: " + _type.toString()); | ||||
| 
 | ||||
| 	// remove the updated memory pointer
 | ||||
| 	m_context << eth::Instruction::POP; | ||||
| 	m_context << Instruction::POP; | ||||
| } | ||||
| 
 | ||||
| void CompilerUtils::moveToStackVariable(VariableDeclaration const& _variable) | ||||
| @ -683,14 +683,14 @@ void CompilerUtils::moveToStackVariable(VariableDeclaration const& _variable) | ||||
| 			errinfo_comment("Stack too deep, try removing local variables.") | ||||
| 		); | ||||
| 	for (unsigned i = 0; i < size; ++i) | ||||
| 		m_context << eth::swapInstruction(stackPosition - size + 1) << eth::Instruction::POP; | ||||
| 		m_context << swapInstruction(stackPosition - size + 1) << Instruction::POP; | ||||
| } | ||||
| 
 | ||||
| void CompilerUtils::copyToStackTop(unsigned _stackDepth, unsigned _itemSize) | ||||
| { | ||||
| 	solAssert(_stackDepth <= 16, "Stack too deep, try removing local variables."); | ||||
| 	for (unsigned i = 0; i < _itemSize; ++i) | ||||
| 		m_context << eth::dupInstruction(_stackDepth); | ||||
| 		m_context << dupInstruction(_stackDepth); | ||||
| } | ||||
| 
 | ||||
| void CompilerUtils::moveToStackTop(unsigned _stackDepth, unsigned _itemSize) | ||||
| @ -712,14 +712,14 @@ void CompilerUtils::rotateStackUp(unsigned _items) | ||||
| { | ||||
| 	solAssert(_items - 1 <= 16, "Stack too deep, try removing local variables."); | ||||
| 	for (unsigned i = 1; i < _items; ++i) | ||||
| 		m_context << eth::swapInstruction(_items - i); | ||||
| 		m_context << swapInstruction(_items - i); | ||||
| } | ||||
| 
 | ||||
| void CompilerUtils::rotateStackDown(unsigned _items) | ||||
| { | ||||
| 	solAssert(_items - 1 <= 16, "Stack too deep, try removing local variables."); | ||||
| 	for (unsigned i = 1; i < _items; ++i) | ||||
| 		m_context << eth::swapInstruction(i); | ||||
| 		m_context << swapInstruction(i); | ||||
| } | ||||
| 
 | ||||
| void CompilerUtils::popStackElement(Type const& _type) | ||||
| @ -730,7 +730,7 @@ void CompilerUtils::popStackElement(Type const& _type) | ||||
| void CompilerUtils::popStackSlots(size_t _amount) | ||||
| { | ||||
| 	for (size_t i = 0; i < _amount; ++i) | ||||
| 		m_context << eth::Instruction::POP; | ||||
| 		m_context << Instruction::POP; | ||||
| } | ||||
| 
 | ||||
| unsigned CompilerUtils::sizeOnStack(vector<shared_ptr<Type const>> const& _variableTypes) | ||||
| @ -744,7 +744,7 @@ unsigned CompilerUtils::sizeOnStack(vector<shared_ptr<Type const>> const& _varia | ||||
| void CompilerUtils::computeHashStatic() | ||||
| { | ||||
| 	storeInMemory(0); | ||||
| 	m_context << u256(32) << u256(0) << eth::Instruction::SHA3; | ||||
| 	m_context << u256(32) << u256(0) << Instruction::SHA3; | ||||
| } | ||||
| 
 | ||||
| void CompilerUtils::storeStringData(bytesConstRef _data) | ||||
| @ -758,14 +758,14 @@ void CompilerUtils::storeStringData(bytesConstRef _data) | ||||
| 			m_context << h256::Arith(h256(_data.cropped(i), h256::AlignLeft)); | ||||
| 			storeInMemoryDynamic(IntegerType(256)); | ||||
| 		} | ||||
| 		m_context << eth::Instruction::POP; | ||||
| 		m_context << Instruction::POP; | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		// stack: mempos mempos_data
 | ||||
| 		m_context.appendData(_data.toBytes()); | ||||
| 		m_context << u256(_data.size()) << eth::Instruction::SWAP2; | ||||
| 		m_context << eth::Instruction::CODECOPY; | ||||
| 		m_context << u256(_data.size()) << Instruction::SWAP2; | ||||
| 		m_context << Instruction::CODECOPY; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| @ -774,18 +774,18 @@ unsigned CompilerUtils::loadFromMemoryHelper(Type const& _type, bool _fromCallda | ||||
| 	unsigned numBytes = _type.calldataEncodedSize(_padToWordBoundaries); | ||||
| 	bool leftAligned = _type.category() == Type::Category::FixedBytes; | ||||
| 	if (numBytes == 0) | ||||
| 		m_context << eth::Instruction::POP << u256(0); | ||||
| 		m_context << Instruction::POP << u256(0); | ||||
| 	else | ||||
| 	{ | ||||
| 		solAssert(numBytes <= 32, "Static memory load of more than 32 bytes requested."); | ||||
| 		m_context << (_fromCalldata ? eth::Instruction::CALLDATALOAD : eth::Instruction::MLOAD); | ||||
| 		m_context << (_fromCalldata ? Instruction::CALLDATALOAD : Instruction::MLOAD); | ||||
| 		if (numBytes != 32) | ||||
| 		{ | ||||
| 			// add leading or trailing zeros by dividing/multiplying depending on alignment
 | ||||
| 			u256 shiftFactor = u256(1) << ((32 - numBytes) * 8); | ||||
| 			m_context << shiftFactor << eth::Instruction::SWAP1 << eth::Instruction::DIV; | ||||
| 			m_context << shiftFactor << Instruction::SWAP1 << Instruction::DIV; | ||||
| 			if (leftAligned) | ||||
| 				m_context << shiftFactor << eth::Instruction::MUL; | ||||
| 				m_context << shiftFactor << Instruction::MUL; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| @ -797,9 +797,9 @@ void CompilerUtils::cleanHigherOrderBits(IntegerType const& _typeOnStack) | ||||
| 	if (_typeOnStack.numBits() == 256) | ||||
| 		return; | ||||
| 	else if (_typeOnStack.isSigned()) | ||||
| 		m_context << u256(_typeOnStack.numBits() / 8 - 1) << eth::Instruction::SIGNEXTEND; | ||||
| 		m_context << u256(_typeOnStack.numBits() / 8 - 1) << Instruction::SIGNEXTEND; | ||||
| 	else | ||||
| 		m_context << ((u256(1) << _typeOnStack.numBits()) - 1) << eth::Instruction::AND; | ||||
| 		m_context << ((u256(1) << _typeOnStack.numBits()) - 1) << Instruction::AND; | ||||
| } | ||||
| 
 | ||||
| unsigned CompilerUtils::prepareMemoryStore(Type const& _type, bool _padToWordBoundaries) const | ||||
| @ -807,13 +807,13 @@ unsigned CompilerUtils::prepareMemoryStore(Type const& _type, bool _padToWordBou | ||||
| 	unsigned numBytes = _type.calldataEncodedSize(_padToWordBoundaries); | ||||
| 	bool leftAligned = _type.category() == Type::Category::FixedBytes; | ||||
| 	if (numBytes == 0) | ||||
| 		m_context << eth::Instruction::POP; | ||||
| 		m_context << Instruction::POP; | ||||
| 	else | ||||
| 	{ | ||||
| 		solAssert(numBytes <= 32, "Memory store of more than 32 bytes requested."); | ||||
| 		if (numBytes != 32 && !leftAligned && !_padToWordBoundaries) | ||||
| 			// shift the value accordingly before storing
 | ||||
| 			m_context << (u256(1) << ((32 - numBytes) * 8)) << eth::Instruction::MUL; | ||||
| 			m_context << (u256(1) << ((32 - numBytes) * 8)) << Instruction::MUL; | ||||
| 	} | ||||
| 	return numBytes; | ||||
| } | ||||
|  | ||||
| @ -75,7 +75,7 @@ void ExpressionCompiler::appendConstStateVariableAccessor(VariableDeclaration co | ||||
| 	utils().convertType(*_varDecl.value()->annotation().type, *_varDecl.annotation().type); | ||||
| 
 | ||||
| 	// append return
 | ||||
| 	m_context << eth::dupInstruction(_varDecl.annotation().type->sizeOnStack() + 1); | ||||
| 	m_context << dupInstruction(_varDecl.annotation().type->sizeOnStack() + 1); | ||||
| 	m_context.appendJump(eth::AssemblyItem::JumpType::OutOfFunction); | ||||
| } | ||||
| 
 | ||||
| @ -103,13 +103,13 @@ void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const& | ||||
| 				"Accessors for mapping with dynamically-sized keys not yet implemented." | ||||
| 			); | ||||
| 			// pop offset
 | ||||
| 			m_context << eth::Instruction::POP; | ||||
| 			m_context << Instruction::POP; | ||||
| 			// move storage offset to memory.
 | ||||
| 			utils().storeInMemory(32); | ||||
| 			// move key to memory.
 | ||||
| 			utils().copyToStackTop(paramTypes.size() - i, 1); | ||||
| 			utils().storeInMemory(0); | ||||
| 			m_context << u256(64) << u256(0) << eth::Instruction::SHA3; | ||||
| 			m_context << u256(64) << u256(0) << Instruction::SHA3; | ||||
| 			// push offset
 | ||||
| 			m_context << u256(0); | ||||
| 			returnType = mappingType->valueType(); | ||||
| @ -117,7 +117,7 @@ void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const& | ||||
| 		else if (auto arrayType = dynamic_cast<ArrayType const*>(returnType.get())) | ||||
| 		{ | ||||
| 			// pop offset
 | ||||
| 			m_context << eth::Instruction::POP; | ||||
| 			m_context << Instruction::POP; | ||||
| 			utils().copyToStackTop(paramTypes.size() - i + 1, 1); | ||||
| 			ArrayUtils(m_context).accessIndex(*arrayType); | ||||
| 			returnType = arrayType->baseType(); | ||||
| @ -127,12 +127,12 @@ void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const& | ||||
| 	} | ||||
| 	// remove index arguments.
 | ||||
| 	if (paramTypes.size() == 1) | ||||
| 		m_context << eth::Instruction::SWAP2 << eth::Instruction::POP << eth::Instruction::SWAP1; | ||||
| 		m_context << Instruction::SWAP2 << Instruction::POP << Instruction::SWAP1; | ||||
| 	else if (paramTypes.size() >= 2) | ||||
| 	{ | ||||
| 		m_context << eth::swapInstruction(paramTypes.size()); | ||||
| 		m_context << eth::Instruction::POP; | ||||
| 		m_context << eth::swapInstruction(paramTypes.size()); | ||||
| 		m_context << swapInstruction(paramTypes.size()); | ||||
| 		m_context << Instruction::POP; | ||||
| 		m_context << swapInstruction(paramTypes.size()); | ||||
| 		utils().popStackSlots(paramTypes.size() - 1); | ||||
| 	} | ||||
| 	unsigned retSizeOnStack = 0; | ||||
| @ -141,7 +141,7 @@ void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const& | ||||
| 	if (StructType const* structType = dynamic_cast<StructType const*>(returnType.get())) | ||||
| 	{ | ||||
| 		// remove offset
 | ||||
| 		m_context << eth::Instruction::POP; | ||||
| 		m_context << Instruction::POP; | ||||
| 		auto const& names = accessorType.returnParameterNames(); | ||||
| 		// struct
 | ||||
| 		for (size_t i = 0; i < names.size(); ++i) | ||||
| @ -152,7 +152,7 @@ void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const& | ||||
| 				if (!arrayType->isByteArray()) | ||||
| 					continue; | ||||
| 			pair<u256, unsigned> const& offsets = structType->storageOffsetsOfMember(names[i]); | ||||
| 			m_context << eth::Instruction::DUP1 << u256(offsets.first) << eth::Instruction::ADD << u256(offsets.second); | ||||
| 			m_context << Instruction::DUP1 << u256(offsets.first) << Instruction::ADD << u256(offsets.second); | ||||
| 			TypePointer memberType = structType->memberType(names[i]); | ||||
| 			StorageItem(m_context, *memberType).retrieveValue(SourceLocation(), true); | ||||
| 			utils().convertType(*memberType, *returnTypes[i]); | ||||
| @ -160,7 +160,7 @@ void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const& | ||||
| 			retSizeOnStack += returnTypes[i]->sizeOnStack(); | ||||
| 		} | ||||
| 		// remove slot
 | ||||
| 		m_context << eth::Instruction::POP; | ||||
| 		m_context << Instruction::POP; | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| @ -172,7 +172,7 @@ void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const& | ||||
| 	} | ||||
| 	solAssert(retSizeOnStack == utils().sizeOnStack(returnTypes), ""); | ||||
| 	solAssert(retSizeOnStack <= 15, "Stack is too deep."); | ||||
| 	m_context << eth::dupInstruction(retSizeOnStack + 1); | ||||
| 	m_context << dupInstruction(retSizeOnStack + 1); | ||||
| 	m_context.appendJump(eth::AssemblyItem::JumpType::OutOfFunction); | ||||
| } | ||||
| 
 | ||||
| @ -226,7 +226,7 @@ bool ExpressionCompiler::visit(Assignment const& _assignment) | ||||
| 			solAssert(itemSize + lvalueSize <= 16, "Stack too deep, try removing local variables."); | ||||
| 			// value [lvalue_ref] updated_value
 | ||||
| 			for (unsigned i = 0; i < itemSize; ++i) | ||||
| 				m_context << eth::swapInstruction(itemSize + lvalueSize) << eth::Instruction::POP; | ||||
| 				m_context << swapInstruction(itemSize + lvalueSize) << Instruction::POP; | ||||
| 		} | ||||
| 	} | ||||
| 	m_currentLValue->storeValue(*type, _assignment.location()); | ||||
| @ -243,7 +243,7 @@ bool ExpressionCompiler::visit(TupleExpression const& _tuple) | ||||
| 		solAssert(!arrayType.isDynamicallySized(), "Cannot create dynamically sized inline array."); | ||||
| 		m_context << max(u256(32u), arrayType.memorySize()); | ||||
| 		utils().allocateMemory(); | ||||
| 		m_context << eth::Instruction::DUP1; | ||||
| 		m_context << Instruction::DUP1; | ||||
| 	 | ||||
| 		for (auto const& component: _tuple.components()) | ||||
| 		{ | ||||
| @ -252,7 +252,7 @@ bool ExpressionCompiler::visit(TupleExpression const& _tuple) | ||||
| 			utils().storeInMemoryDynamic(*arrayType.baseType(), true);				 | ||||
| 		} | ||||
| 		 | ||||
| 		m_context << eth::Instruction::POP; | ||||
| 		m_context << Instruction::POP; | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| @ -298,13 +298,13 @@ bool ExpressionCompiler::visit(UnaryOperation const& _unaryOperation) | ||||
| 	switch (_unaryOperation.getOperator()) | ||||
| 	{ | ||||
| 	case Token::Not: // !
 | ||||
| 		m_context << eth::Instruction::ISZERO; | ||||
| 		m_context << Instruction::ISZERO; | ||||
| 		break; | ||||
| 	case Token::BitNot: // ~
 | ||||
| 		m_context << eth::Instruction::NOT; | ||||
| 		m_context << Instruction::NOT; | ||||
| 		break; | ||||
| 	case Token::After: // after
 | ||||
| 		m_context << eth::Instruction::TIMESTAMP << eth::Instruction::ADD; | ||||
| 		m_context << Instruction::TIMESTAMP << Instruction::ADD; | ||||
| 		break; | ||||
| 	case Token::Delete: // delete
 | ||||
| 		solAssert(!!m_currentLValue, "LValue not retrieved."); | ||||
| @ -319,20 +319,20 @@ bool ExpressionCompiler::visit(UnaryOperation const& _unaryOperation) | ||||
| 		{ | ||||
| 			// store value for later
 | ||||
| 			solAssert(_unaryOperation.annotation().type->sizeOnStack() == 1, "Stack size != 1 not implemented."); | ||||
| 			m_context << eth::Instruction::DUP1; | ||||
| 			m_context << Instruction::DUP1; | ||||
| 			if (m_currentLValue->sizeOnStack() > 0) | ||||
| 				for (unsigned i = 1 + m_currentLValue->sizeOnStack(); i > 0; --i) | ||||
| 					m_context << eth::swapInstruction(i); | ||||
| 					m_context << swapInstruction(i); | ||||
| 		} | ||||
| 		m_context << u256(1); | ||||
| 		if (_unaryOperation.getOperator() == Token::Inc) | ||||
| 			m_context << eth::Instruction::ADD; | ||||
| 			m_context << Instruction::ADD; | ||||
| 		else | ||||
| 			m_context << eth::Instruction::SWAP1 << eth::Instruction::SUB; | ||||
| 			m_context << Instruction::SWAP1 << Instruction::SUB; | ||||
| 		// Stack for prefix: [ref...] (*ref)+-1
 | ||||
| 		// Stack for postfix: *ref [ref...] (*ref)+-1
 | ||||
| 		for (unsigned i = m_currentLValue->sizeOnStack(); i > 0; --i) | ||||
| 			m_context << eth::swapInstruction(i); | ||||
| 			m_context << swapInstruction(i); | ||||
| 		m_currentLValue->storeValue( | ||||
| 			*_unaryOperation.annotation().type, _unaryOperation.location(), | ||||
| 			!_unaryOperation.isPrefixOperation()); | ||||
| @ -342,7 +342,7 @@ bool ExpressionCompiler::visit(UnaryOperation const& _unaryOperation) | ||||
| 		// unary add, so basically no-op
 | ||||
| 		break; | ||||
| 	case Token::Sub: // -
 | ||||
| 		m_context << u256(0) << eth::Instruction::SUB; | ||||
| 		m_context << u256(0) << Instruction::SUB; | ||||
| 		break; | ||||
| 	default: | ||||
| 		BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Invalid unary operator: " + | ||||
| @ -452,7 +452,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) | ||||
| 
 | ||||
| 		m_context << max(u256(32u), structType.memorySize()); | ||||
| 		utils().allocateMemory(); | ||||
| 		m_context << eth::Instruction::DUP1; | ||||
| 		m_context << Instruction::DUP1; | ||||
| 
 | ||||
| 		for (unsigned i = 0; i < arguments.size(); ++i) | ||||
| 		{ | ||||
| @ -460,7 +460,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) | ||||
| 			utils().convertType(*arguments[i]->annotation().type, *functionType->parameterTypes()[i]); | ||||
| 			utils().storeInMemoryDynamic(*functionType->parameterTypes()[i]); | ||||
| 		} | ||||
| 		m_context << eth::Instruction::POP; | ||||
| 		m_context << Instruction::POP; | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| @ -518,21 +518,21 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) | ||||
| 			utils().fetchFreeMemoryPointer(); | ||||
| 			// pushes size
 | ||||
| 			eth::AssemblyItem subroutine = m_context.addSubroutine(assembly); | ||||
| 			m_context << eth::Instruction::DUP1 << subroutine; | ||||
| 			m_context << eth::Instruction::DUP4 << eth::Instruction::CODECOPY; | ||||
| 			m_context << Instruction::DUP1 << subroutine; | ||||
| 			m_context << Instruction::DUP4 << Instruction::CODECOPY; | ||||
| 
 | ||||
| 			m_context << eth::Instruction::ADD; | ||||
| 			m_context << Instruction::ADD; | ||||
| 			utils().encodeToMemory(argumentTypes, function.parameterTypes()); | ||||
| 			// now on stack: memory_end_ptr
 | ||||
| 			// need: size, offset, endowment
 | ||||
| 			utils().toSizeAfterFreeMemoryPointer(); | ||||
| 			if (function.valueSet()) | ||||
| 				m_context << eth::dupInstruction(3); | ||||
| 				m_context << dupInstruction(3); | ||||
| 			else | ||||
| 				m_context << u256(0); | ||||
| 			m_context << eth::Instruction::CREATE; | ||||
| 			m_context << Instruction::CREATE; | ||||
| 			if (function.valueSet()) | ||||
| 				m_context << eth::swapInstruction(1) << eth::Instruction::POP; | ||||
| 				m_context << swapInstruction(1) << Instruction::POP; | ||||
| 			break; | ||||
| 		} | ||||
| 		case Location::SetGas: | ||||
| @ -546,9 +546,9 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) | ||||
| 			// Its values of gasSet and valueSet is equal to the original function's though.
 | ||||
| 			unsigned stackDepth = (function.gasSet() ? 1 : 0) + (function.valueSet() ? 1 : 0); | ||||
| 			if (stackDepth > 0) | ||||
| 				m_context << eth::swapInstruction(stackDepth); | ||||
| 				m_context << swapInstruction(stackDepth); | ||||
| 			if (function.gasSet()) | ||||
| 				m_context << eth::Instruction::POP; | ||||
| 				m_context << Instruction::POP; | ||||
| 			break; | ||||
| 		} | ||||
| 		case Location::SetValue: | ||||
| @ -557,7 +557,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) | ||||
| 			// Note that function is not the original function, but the ".value" function.
 | ||||
| 			// Its values of gasSet and valueSet is equal to the original function's though.
 | ||||
| 			if (function.valueSet()) | ||||
| 				m_context << eth::Instruction::POP; | ||||
| 				m_context << Instruction::POP; | ||||
| 			arguments.front()->accept(*this); | ||||
| 			break; | ||||
| 		case Location::Send: | ||||
| @ -586,7 +586,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) | ||||
| 		case Location::Selfdestruct: | ||||
| 			arguments.front()->accept(*this); | ||||
| 			utils().convertType(*arguments.front()->annotation().type, *function.parameterTypes().front(), true); | ||||
| 			m_context << eth::Instruction::SUICIDE; | ||||
| 			m_context << Instruction::SUICIDE; | ||||
| 			break; | ||||
| 		case Location::SHA3: | ||||
| 		{ | ||||
| @ -599,7 +599,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) | ||||
| 			utils().fetchFreeMemoryPointer(); | ||||
| 			utils().encodeToMemory(argumentTypes, TypePointers(), function.padArguments(), true); | ||||
| 			utils().toSizeAfterFreeMemoryPointer(); | ||||
| 			m_context << eth::Instruction::SHA3; | ||||
| 			m_context << Instruction::SHA3; | ||||
| 			break; | ||||
| 		} | ||||
| 		case Location::Log0: | ||||
| @ -622,7 +622,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) | ||||
| 				false, | ||||
| 				true); | ||||
| 			utils().toSizeAfterFreeMemoryPointer(); | ||||
| 			m_context << eth::logInstruction(logNumber); | ||||
| 			m_context << logInstruction(logNumber); | ||||
| 			break; | ||||
| 		} | ||||
| 		case Location::Event: | ||||
| @ -646,7 +646,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) | ||||
| 							true | ||||
| 						); | ||||
| 						utils().toSizeAfterFreeMemoryPointer(); | ||||
| 						m_context << eth::Instruction::SHA3; | ||||
| 						m_context << Instruction::SHA3; | ||||
| 					} | ||||
| 					else | ||||
| 						utils().convertType( | ||||
| @ -676,14 +676,14 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) | ||||
| 			utils().encodeToMemory(nonIndexedArgTypes, nonIndexedParamTypes); | ||||
| 			// need: topic1 ... topicn memsize memstart
 | ||||
| 			utils().toSizeAfterFreeMemoryPointer(); | ||||
| 			m_context << eth::logInstruction(numIndexed); | ||||
| 			m_context << logInstruction(numIndexed); | ||||
| 			break; | ||||
| 		} | ||||
| 		case Location::BlockHash: | ||||
| 		{ | ||||
| 			arguments[0]->accept(*this); | ||||
| 			utils().convertType(*arguments[0]->annotation().type, *function.parameterTypes()[0], true); | ||||
| 			m_context << eth::Instruction::BLOCKHASH; | ||||
| 			m_context << Instruction::BLOCKHASH; | ||||
| 			break; | ||||
| 		} | ||||
| 		case Location::AddMod: | ||||
| @ -695,9 +695,9 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) | ||||
| 				utils().convertType(*arguments[2 - i]->annotation().type, IntegerType(256)); | ||||
| 			} | ||||
| 			if (function.location() == Location::AddMod) | ||||
| 				m_context << eth::Instruction::ADDMOD; | ||||
| 				m_context << Instruction::ADDMOD; | ||||
| 			else | ||||
| 				m_context << eth::Instruction::MULMOD; | ||||
| 				m_context << Instruction::MULMOD; | ||||
| 			break; | ||||
| 		} | ||||
| 		case Location::ECRecover: | ||||
| @ -710,7 +710,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) | ||||
| 															   {Location::RIPEMD160, 3}}; | ||||
| 			m_context << contractAddresses.find(function.location())->second; | ||||
| 			for (unsigned i = function.sizeOnStack(); i > 0; --i) | ||||
| 				m_context << eth::swapInstruction(i); | ||||
| 				m_context << swapInstruction(i); | ||||
| 			appendExternalFunctionCall(function, arguments); | ||||
| 			break; | ||||
| 		} | ||||
| @ -727,13 +727,13 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) | ||||
| 				make_shared<ArrayType>(DataLocation::Storage); | ||||
| 			// get the current length
 | ||||
| 			ArrayUtils(m_context).retrieveLength(*arrayType); | ||||
| 			m_context << eth::Instruction::DUP1; | ||||
| 			m_context << Instruction::DUP1; | ||||
| 			// stack: ArrayReference currentLength currentLength
 | ||||
| 			m_context << u256(1) << eth::Instruction::ADD; | ||||
| 			m_context << u256(1) << Instruction::ADD; | ||||
| 			// stack: ArrayReference currentLength newLength
 | ||||
| 			m_context << eth::Instruction::DUP3 << eth::Instruction::DUP2; | ||||
| 			m_context << Instruction::DUP3 << Instruction::DUP2; | ||||
| 			ArrayUtils(m_context).resizeDynamicArray(*arrayType); | ||||
| 			m_context << eth::Instruction::SWAP2 << eth::Instruction::SWAP1; | ||||
| 			m_context << Instruction::SWAP2 << Instruction::SWAP1; | ||||
| 			// stack: newLength ArrayReference oldLength
 | ||||
| 			ArrayUtils(m_context).accessIndex(*arrayType, false); | ||||
| 
 | ||||
| @ -766,36 +766,36 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) | ||||
| 			// Stack: requested_length
 | ||||
| 			// Allocate at max(MSIZE, freeMemoryPointer)
 | ||||
| 			utils().fetchFreeMemoryPointer(); | ||||
| 			m_context << eth::Instruction::DUP1 << eth::Instruction::MSIZE; | ||||
| 			m_context << eth::Instruction::LT; | ||||
| 			m_context << Instruction::DUP1 << Instruction::MSIZE; | ||||
| 			m_context << Instruction::LT; | ||||
| 			auto initialise = m_context.appendConditionalJump(); | ||||
| 			// Free memory pointer does not point to empty memory, use MSIZE.
 | ||||
| 			m_context << eth::Instruction::POP; | ||||
| 			m_context << eth::Instruction::MSIZE; | ||||
| 			m_context << Instruction::POP; | ||||
| 			m_context << Instruction::MSIZE; | ||||
| 			m_context << initialise; | ||||
| 
 | ||||
| 			// Stack: requested_length memptr
 | ||||
| 			m_context << eth::Instruction::SWAP1; | ||||
| 			m_context << Instruction::SWAP1; | ||||
| 			// Stack: memptr requested_length
 | ||||
| 			// store length
 | ||||
| 			m_context << eth::Instruction::DUP1 << eth::Instruction::DUP3 << eth::Instruction::MSTORE; | ||||
| 			m_context << Instruction::DUP1 << Instruction::DUP3 << Instruction::MSTORE; | ||||
| 			// Stack: memptr requested_length
 | ||||
| 			// update free memory pointer
 | ||||
| 			m_context << eth::Instruction::DUP1 << arrayType.baseType()->memoryHeadSize(); | ||||
| 			m_context << eth::Instruction::MUL << u256(32) << eth::Instruction::ADD; | ||||
| 			m_context << eth::Instruction::DUP3 << eth::Instruction::ADD; | ||||
| 			m_context << Instruction::DUP1 << arrayType.baseType()->memoryHeadSize(); | ||||
| 			m_context << Instruction::MUL << u256(32) << Instruction::ADD; | ||||
| 			m_context << Instruction::DUP3 << Instruction::ADD; | ||||
| 			utils().storeFreeMemoryPointer(); | ||||
| 			// Stack: memptr requested_length
 | ||||
| 
 | ||||
| 			// We only have to initialise if the base type is a not a value type.
 | ||||
| 			if (dynamic_cast<ReferenceType const*>(arrayType.baseType().get())) | ||||
| 			{ | ||||
| 				m_context << eth::Instruction::DUP2 << u256(32) << eth::Instruction::ADD; | ||||
| 				m_context << Instruction::DUP2 << u256(32) << Instruction::ADD; | ||||
| 				utils().zeroInitialiseMemoryArray(arrayType); | ||||
| 				m_context << eth::Instruction::POP; | ||||
| 				m_context << Instruction::POP; | ||||
| 			} | ||||
| 			else | ||||
| 				m_context << eth::Instruction::POP; | ||||
| 				m_context << Instruction::POP; | ||||
| 			break; | ||||
| 		} | ||||
| 		default: | ||||
| @ -876,7 +876,7 @@ void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess) | ||||
| 				IntegerType(0, IntegerType::Modifier::Address), | ||||
| 				true | ||||
| 			); | ||||
| 			m_context << eth::Instruction::BALANCE; | ||||
| 			m_context << Instruction::BALANCE; | ||||
| 		} | ||||
| 		else if ((set<string>{"send", "call", "callcode", "delegatecall"}).count(member)) | ||||
| 			utils().convertType( | ||||
| @ -894,30 +894,30 @@ void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess) | ||||
| 	case Type::Category::Magic: | ||||
| 		// we can ignore the kind of magic and only look at the name of the member
 | ||||
| 		if (member == "coinbase") | ||||
| 			m_context << eth::Instruction::COINBASE; | ||||
| 			m_context << Instruction::COINBASE; | ||||
| 		else if (member == "timestamp") | ||||
| 			m_context << eth::Instruction::TIMESTAMP; | ||||
| 			m_context << Instruction::TIMESTAMP; | ||||
| 		else if (member == "difficulty") | ||||
| 			m_context << eth::Instruction::DIFFICULTY; | ||||
| 			m_context << Instruction::DIFFICULTY; | ||||
| 		else if (member == "number") | ||||
| 			m_context << eth::Instruction::NUMBER; | ||||
| 			m_context << Instruction::NUMBER; | ||||
| 		else if (member == "gaslimit") | ||||
| 			m_context << eth::Instruction::GASLIMIT; | ||||
| 			m_context << Instruction::GASLIMIT; | ||||
| 		else if (member == "sender") | ||||
| 			m_context << eth::Instruction::CALLER; | ||||
| 			m_context << Instruction::CALLER; | ||||
| 		else if (member == "value") | ||||
| 			m_context << eth::Instruction::CALLVALUE; | ||||
| 			m_context << Instruction::CALLVALUE; | ||||
| 		else if (member == "origin") | ||||
| 			m_context << eth::Instruction::ORIGIN; | ||||
| 			m_context << Instruction::ORIGIN; | ||||
| 		else if (member == "gas") | ||||
| 			m_context << eth::Instruction::GAS; | ||||
| 			m_context << Instruction::GAS; | ||||
| 		else if (member == "gasprice") | ||||
| 			m_context << eth::Instruction::GASPRICE; | ||||
| 			m_context << Instruction::GASPRICE; | ||||
| 		else if (member == "data") | ||||
| 			m_context << u256(0) << eth::Instruction::CALLDATASIZE; | ||||
| 			m_context << u256(0) << Instruction::CALLDATASIZE; | ||||
| 		else if (member == "sig") | ||||
| 			m_context << u256(0) << eth::Instruction::CALLDATALOAD | ||||
| 				<< (u256(0xffffffff) << (256 - 32)) << eth::Instruction::AND; | ||||
| 			m_context << u256(0) << Instruction::CALLDATALOAD | ||||
| 				<< (u256(0xffffffff) << (256 - 32)) << Instruction::AND; | ||||
| 		else | ||||
| 			BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unknown magic member.")); | ||||
| 		break; | ||||
| @ -929,13 +929,13 @@ void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess) | ||||
| 		case DataLocation::Storage: | ||||
| 		{ | ||||
| 			pair<u256, unsigned> const& offsets = type.storageOffsetsOfMember(member); | ||||
| 			m_context << offsets.first << eth::Instruction::ADD << u256(offsets.second); | ||||
| 			m_context << offsets.first << Instruction::ADD << u256(offsets.second); | ||||
| 			setLValueToStorageItem(_memberAccess); | ||||
| 			break; | ||||
| 		} | ||||
| 		case DataLocation::Memory: | ||||
| 		{ | ||||
| 			m_context << type.memoryOffsetOfMember(member) << eth::Instruction::ADD; | ||||
| 			m_context << type.memoryOffsetOfMember(member) << Instruction::ADD; | ||||
| 			setLValue<MemoryItem>(_memberAccess, *_memberAccess.annotation().type); | ||||
| 			break; | ||||
| 		} | ||||
| @ -986,13 +986,13 @@ void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess) | ||||
| 				switch (type.location()) | ||||
| 				{ | ||||
| 				case DataLocation::CallData: | ||||
| 					m_context << eth::Instruction::SWAP1 << eth::Instruction::POP; | ||||
| 					m_context << Instruction::SWAP1 << Instruction::POP; | ||||
| 					break; | ||||
| 				case DataLocation::Storage: | ||||
| 					setLValue<StorageArrayLength>(_memberAccess, type); | ||||
| 					break; | ||||
| 				case DataLocation::Memory: | ||||
| 					m_context << eth::Instruction::MLOAD; | ||||
| 					m_context << Instruction::MLOAD; | ||||
| 					break; | ||||
| 				} | ||||
| 		} | ||||
| @ -1046,7 +1046,7 @@ bool ExpressionCompiler::visit(IndexAccess const& _indexAccess) | ||||
| 				false, | ||||
| 				true | ||||
| 			); | ||||
| 			m_context << eth::Instruction::SWAP1; | ||||
| 			m_context << Instruction::SWAP1; | ||||
| 			utils().storeInMemoryDynamic(IntegerType(256)); | ||||
| 			utils().toSizeAfterFreeMemoryPointer(); | ||||
| 		} | ||||
| @ -1054,12 +1054,12 @@ bool ExpressionCompiler::visit(IndexAccess const& _indexAccess) | ||||
| 		{ | ||||
| 			m_context << u256(0); // memory position
 | ||||
| 			appendExpressionCopyToMemory(*keyType, *_indexAccess.indexExpression()); | ||||
| 			m_context << eth::Instruction::SWAP1; | ||||
| 			m_context << Instruction::SWAP1; | ||||
| 			solAssert(CompilerUtils::freeMemoryPointer >= 0x40, ""); | ||||
| 			utils().storeInMemoryDynamic(IntegerType(256)); | ||||
| 			m_context << u256(0); | ||||
| 		} | ||||
| 		m_context << eth::Instruction::SHA3; | ||||
| 		m_context << Instruction::SHA3; | ||||
| 		m_context << u256(0); | ||||
| 		setLValueToStorageItem(_indexAccess); | ||||
| 	} | ||||
| @ -1109,12 +1109,12 @@ bool ExpressionCompiler::visit(IndexAccess const& _indexAccess) | ||||
| 		// stack layout: <value> <index>
 | ||||
| 		// check out-of-bounds access
 | ||||
| 		m_context << u256(fixedBytesType.numBytes()); | ||||
| 		m_context << eth::Instruction::DUP2 << eth::Instruction::LT << eth::Instruction::ISZERO; | ||||
| 		m_context << Instruction::DUP2 << Instruction::LT << Instruction::ISZERO; | ||||
| 		// out-of-bounds access throws exception
 | ||||
| 		m_context.appendConditionalJumpTo(m_context.errorTag()); | ||||
| 
 | ||||
| 		m_context << eth::Instruction::BYTE; | ||||
| 		m_context << (u256(1) << (256 - 8)) << eth::Instruction::MUL; | ||||
| 		m_context << Instruction::BYTE; | ||||
| 		m_context << (u256(1) << (256 - 8)) << Instruction::MUL; | ||||
| 	} | ||||
| 	else if (baseType.category() == Type::Category::TypeType) | ||||
| 	{ | ||||
| @ -1139,11 +1139,11 @@ void ExpressionCompiler::endVisit(Identifier const& _identifier) | ||||
| 		case Type::Category::Contract: | ||||
| 			// "this" or "super"
 | ||||
| 			if (!dynamic_cast<ContractType const&>(*magicVar->type()).isSuper()) | ||||
| 				m_context << eth::Instruction::ADDRESS; | ||||
| 				m_context << Instruction::ADDRESS; | ||||
| 			break; | ||||
| 		case Type::Category::Integer: | ||||
| 			// "now"
 | ||||
| 			m_context << eth::Instruction::TIMESTAMP; | ||||
| 			m_context << Instruction::TIMESTAMP; | ||||
| 			break; | ||||
| 		default: | ||||
| 			break; | ||||
| @ -1208,11 +1208,11 @@ void ExpressionCompiler::appendAndOrOperatorCode(BinaryOperation const& _binaryO | ||||
| 	solAssert(c_op == Token::Or || c_op == Token::And, ""); | ||||
| 
 | ||||
| 	_binaryOperation.leftExpression().accept(*this); | ||||
| 	m_context << eth::Instruction::DUP1; | ||||
| 	m_context << Instruction::DUP1; | ||||
| 	if (c_op == Token::And) | ||||
| 		m_context << eth::Instruction::ISZERO; | ||||
| 		m_context << Instruction::ISZERO; | ||||
| 	eth::AssemblyItem endLabel = m_context.appendConditionalJump(); | ||||
| 	m_context << eth::Instruction::POP; | ||||
| 	m_context << Instruction::POP; | ||||
| 	_binaryOperation.rightExpression().accept(*this); | ||||
| 	m_context << endLabel; | ||||
| } | ||||
| @ -1221,9 +1221,9 @@ void ExpressionCompiler::appendCompareOperatorCode(Token::Value _operator, Type | ||||
| { | ||||
| 	if (_operator == Token::Equal || _operator == Token::NotEqual) | ||||
| 	{ | ||||
| 		m_context << eth::Instruction::EQ; | ||||
| 		m_context << Instruction::EQ; | ||||
| 		if (_operator == Token::NotEqual) | ||||
| 			m_context << eth::Instruction::ISZERO; | ||||
| 			m_context << Instruction::ISZERO; | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| @ -1235,19 +1235,19 @@ void ExpressionCompiler::appendCompareOperatorCode(Token::Value _operator, Type | ||||
| 		{ | ||||
| 		case Token::GreaterThanOrEqual: | ||||
| 			m_context << | ||||
| 				(isSigned ? eth::Instruction::SLT : eth::Instruction::LT) << | ||||
| 				eth::Instruction::ISZERO; | ||||
| 				(isSigned ? Instruction::SLT : Instruction::LT) << | ||||
| 				Instruction::ISZERO; | ||||
| 			break; | ||||
| 		case Token::LessThanOrEqual: | ||||
| 			m_context << | ||||
| 				(isSigned ? eth::Instruction::SGT : eth::Instruction::GT) << | ||||
| 				eth::Instruction::ISZERO; | ||||
| 				(isSigned ? Instruction::SGT : Instruction::GT) << | ||||
| 				Instruction::ISZERO; | ||||
| 			break; | ||||
| 		case Token::GreaterThan: | ||||
| 			m_context << (isSigned ? eth::Instruction::SGT : eth::Instruction::GT); | ||||
| 			m_context << (isSigned ? Instruction::SGT : Instruction::GT); | ||||
| 			break; | ||||
| 		case Token::LessThan: | ||||
| 			m_context << (isSigned ? eth::Instruction::SLT : eth::Instruction::LT); | ||||
| 			m_context << (isSigned ? Instruction::SLT : Instruction::LT); | ||||
| 			break; | ||||
| 		default: | ||||
| 			BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unknown comparison operator.")); | ||||
| @ -1275,22 +1275,22 @@ void ExpressionCompiler::appendArithmeticOperatorCode(Token::Value _operator, Ty | ||||
| 	switch (_operator) | ||||
| 	{ | ||||
| 	case Token::Add: | ||||
| 		m_context << eth::Instruction::ADD; | ||||
| 		m_context << Instruction::ADD; | ||||
| 		break; | ||||
| 	case Token::Sub: | ||||
| 		m_context << eth::Instruction::SUB; | ||||
| 		m_context << Instruction::SUB; | ||||
| 		break; | ||||
| 	case Token::Mul: | ||||
| 		m_context << eth::Instruction::MUL; | ||||
| 		m_context << Instruction::MUL; | ||||
| 		break; | ||||
| 	case Token::Div: | ||||
| 		m_context  << (c_isSigned ? eth::Instruction::SDIV : eth::Instruction::DIV); | ||||
| 		m_context  << (c_isSigned ? Instruction::SDIV : Instruction::DIV); | ||||
| 		break; | ||||
| 	case Token::Mod: | ||||
| 		m_context << (c_isSigned ? eth::Instruction::SMOD : eth::Instruction::MOD); | ||||
| 		m_context << (c_isSigned ? Instruction::SMOD : Instruction::MOD); | ||||
| 		break; | ||||
| 	case Token::Exp: | ||||
| 		m_context << eth::Instruction::EXP; | ||||
| 		m_context << Instruction::EXP; | ||||
| 		break; | ||||
| 	default: | ||||
| 		BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unknown arithmetic operator.")); | ||||
| @ -1302,13 +1302,13 @@ void ExpressionCompiler::appendBitOperatorCode(Token::Value _operator) | ||||
| 	switch (_operator) | ||||
| 	{ | ||||
| 	case Token::BitOr: | ||||
| 		m_context << eth::Instruction::OR; | ||||
| 		m_context << Instruction::OR; | ||||
| 		break; | ||||
| 	case Token::BitAnd: | ||||
| 		m_context << eth::Instruction::AND; | ||||
| 		m_context << Instruction::AND; | ||||
| 		break; | ||||
| 	case Token::BitXor: | ||||
| 		m_context << eth::Instruction::XOR; | ||||
| 		m_context << Instruction::XOR; | ||||
| 		break; | ||||
| 	default: | ||||
| 		BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unknown bit operator.")); | ||||
| @ -1392,7 +1392,7 @@ void ExpressionCompiler::appendExternalFunctionCall( | ||||
| 			true | ||||
| 		); | ||||
| 		for (unsigned i = 0; i < gasValueSize; ++i) | ||||
| 			m_context << eth::swapInstruction(gasValueSize - i); | ||||
| 			m_context << swapInstruction(gasValueSize - i); | ||||
| 		gasStackPos++; | ||||
| 		valueStackPos++; | ||||
| 	} | ||||
| @ -1411,7 +1411,7 @@ void ExpressionCompiler::appendExternalFunctionCall( | ||||
| 	utils().fetchFreeMemoryPointer(); | ||||
| 	if (!_functionType.isBareCall() || manualFunctionId) | ||||
| 	{ | ||||
| 		m_context << eth::dupInstruction(2 + gasValueSize + CompilerUtils::sizeOnStack(argumentTypes)); | ||||
| 		m_context << dupInstruction(2 + gasValueSize + CompilerUtils::sizeOnStack(argumentTypes)); | ||||
| 		utils().storeInMemoryDynamic(IntegerType(8 * CompilerUtils::dataStartOffset), false); | ||||
| 	} | ||||
| 	// If the function takes arbitrary parameters, copy dynamic length data in place.
 | ||||
| @ -1437,21 +1437,21 @@ void ExpressionCompiler::appendExternalFunctionCall( | ||||
| 	// put on stack: <size of output> <memory pos of output> <size of input> <memory pos of input>
 | ||||
| 	m_context << u256(retSize); | ||||
| 	utils().fetchFreeMemoryPointer(); | ||||
| 	m_context << eth::Instruction::DUP1 << eth::Instruction::DUP4 << eth::Instruction::SUB; | ||||
| 	m_context << eth::Instruction::DUP2; | ||||
| 	m_context << Instruction::DUP1 << Instruction::DUP4 << Instruction::SUB; | ||||
| 	m_context << Instruction::DUP2; | ||||
| 
 | ||||
| 	// CALL arguments: outSize, outOff, inSize, inOff (already present up to here)
 | ||||
| 	// [value,] addr, gas (stack top)
 | ||||
| 	if (isDelegateCall) | ||||
| 		solAssert(!_functionType.valueSet(), "Value set for delegatecall"); | ||||
| 	else if (_functionType.valueSet()) | ||||
| 		m_context << eth::dupInstruction(m_context.baseToCurrentStackOffset(valueStackPos)); | ||||
| 		m_context << dupInstruction(m_context.baseToCurrentStackOffset(valueStackPos)); | ||||
| 	else | ||||
| 		m_context << u256(0); | ||||
| 	m_context << eth::dupInstruction(m_context.baseToCurrentStackOffset(contractStackPos)); | ||||
| 	m_context << dupInstruction(m_context.baseToCurrentStackOffset(contractStackPos)); | ||||
| 
 | ||||
| 	if (_functionType.gasSet()) | ||||
| 		m_context << eth::dupInstruction(m_context.baseToCurrentStackOffset(gasStackPos)); | ||||
| 		m_context << dupInstruction(m_context.baseToCurrentStackOffset(gasStackPos)); | ||||
| 	else | ||||
| 	{ | ||||
| 		eth::EVMSchedule schedule; | ||||
| @ -1464,15 +1464,15 @@ void ExpressionCompiler::appendExternalFunctionCall( | ||||
| 			gasNeededByCaller += schedule.callNewAccountGas; // we never know
 | ||||
| 		m_context << | ||||
| 			gasNeededByCaller << | ||||
| 			eth::Instruction::GAS << | ||||
| 			eth::Instruction::SUB; | ||||
| 			Instruction::GAS << | ||||
| 			Instruction::SUB; | ||||
| 	} | ||||
| 	if (isDelegateCall) | ||||
| 		m_context << eth::Instruction::DELEGATECALL; | ||||
| 		m_context << Instruction::DELEGATECALL; | ||||
| 	else if (isCallCode) | ||||
| 		m_context << eth::Instruction::CALLCODE; | ||||
| 		m_context << Instruction::CALLCODE; | ||||
| 	else | ||||
| 		m_context << eth::Instruction::CALL; | ||||
| 		m_context << Instruction::CALL; | ||||
| 
 | ||||
| 	unsigned remainsSize = | ||||
| 		2 + // contract address, input_memory_end
 | ||||
| @ -1481,11 +1481,11 @@ void ExpressionCompiler::appendExternalFunctionCall( | ||||
| 		(!_functionType.isBareCall() || manualFunctionId); | ||||
| 
 | ||||
| 	if (returnSuccessCondition) | ||||
| 		m_context << eth::swapInstruction(remainsSize); | ||||
| 		m_context << swapInstruction(remainsSize); | ||||
| 	else | ||||
| 	{ | ||||
| 		//Propagate error condition (if CALL pushes 0 on stack).
 | ||||
| 		m_context << eth::Instruction::ISZERO; | ||||
| 		m_context << Instruction::ISZERO; | ||||
| 		m_context.appendConditionalJumpTo(m_context.errorTag()); | ||||
| 	} | ||||
| 
 | ||||
| @ -1515,7 +1515,7 @@ void ExpressionCompiler::appendExternalFunctionCall( | ||||
| 		if (memoryNeeded) | ||||
| 			utils().storeFreeMemoryPointer(); | ||||
| 		else | ||||
| 			m_context << eth::Instruction::POP; | ||||
| 			m_context << Instruction::POP; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -21,7 +21,7 @@ | ||||
|  */ | ||||
| 
 | ||||
| #include <libsolidity/codegen/LValue.h> | ||||
| #include <libevmcore/Instruction.h> | ||||
| #include <libevmasm/Instruction.h> | ||||
| #include <libsolidity/ast/Types.h> | ||||
| #include <libsolidity/ast/AST.h> | ||||
| #include <libsolidity/codegen/CompilerUtils.h> | ||||
| @ -49,7 +49,7 @@ void StackVariable::retrieveValue(SourceLocation const& _location, bool) const | ||||
| 		); | ||||
| 	solAssert(stackPos + 1 >= m_size, "Size and stack pos mismatch."); | ||||
| 	for (unsigned i = 0; i < m_size; ++i) | ||||
| 		m_context << eth::dupInstruction(stackPos + 1); | ||||
| 		m_context << dupInstruction(stackPos + 1); | ||||
| } | ||||
| 
 | ||||
| void StackVariable::storeValue(Type const&, SourceLocation const& _location, bool _move) const | ||||
| @ -63,7 +63,7 @@ void StackVariable::storeValue(Type const&, SourceLocation const& _location, boo | ||||
| 		); | ||||
| 	else if (stackDiff > 0) | ||||
| 		for (unsigned i = 0; i < m_size; ++i) | ||||
| 			m_context << eth::swapInstruction(stackDiff) << eth::Instruction::POP; | ||||
| 			m_context << swapInstruction(stackDiff) << Instruction::POP; | ||||
| 	if (!_move) | ||||
| 		retrieveValue(_location); | ||||
| } | ||||
| @ -85,11 +85,11 @@ void MemoryItem::retrieveValue(SourceLocation const&, bool _remove) const | ||||
| 	if (m_dataType->isValueType()) | ||||
| 	{ | ||||
| 		if (!_remove) | ||||
| 			m_context << eth::Instruction::DUP1; | ||||
| 			m_context << Instruction::DUP1; | ||||
| 		CompilerUtils(m_context).loadFromMemoryDynamic(*m_dataType, false, m_padded, false); | ||||
| 	} | ||||
| 	else | ||||
| 		m_context << eth::Instruction::MLOAD; | ||||
| 		m_context << Instruction::MLOAD; | ||||
| } | ||||
| 
 | ||||
| void MemoryItem::storeValue(Type const& _sourceType, SourceLocation const&, bool _move) const | ||||
| @ -109,13 +109,13 @@ void MemoryItem::storeValue(Type const& _sourceType, SourceLocation const&, bool | ||||
| 		{ | ||||
| 			solAssert(m_dataType->calldataEncodedSize(false) == 1, "Invalid non-padded type."); | ||||
| 			if (m_dataType->category() == Type::Category::FixedBytes) | ||||
| 				m_context << u256(0) << eth::Instruction::BYTE; | ||||
| 			m_context << eth::Instruction::SWAP1 << eth::Instruction::MSTORE8; | ||||
| 				m_context << u256(0) << Instruction::BYTE; | ||||
| 			m_context << Instruction::SWAP1 << Instruction::MSTORE8; | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			utils.storeInMemoryDynamic(*m_dataType, m_padded); | ||||
| 			m_context << eth::Instruction::POP; | ||||
| 			m_context << Instruction::POP; | ||||
| 		} | ||||
| 	} | ||||
| 	else | ||||
| @ -124,10 +124,10 @@ void MemoryItem::storeValue(Type const& _sourceType, SourceLocation const&, bool | ||||
| 
 | ||||
| 		solAssert(m_dataType->sizeOnStack() == 1, ""); | ||||
| 		if (!_move) | ||||
| 			m_context << eth::Instruction::DUP2 << eth::Instruction::SWAP1; | ||||
| 			m_context << Instruction::DUP2 << Instruction::SWAP1; | ||||
| 		// stack: [value] value lvalue
 | ||||
| 		// only store the reference
 | ||||
| 		m_context << eth::Instruction::MSTORE; | ||||
| 		m_context << Instruction::MSTORE; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| @ -135,10 +135,10 @@ void MemoryItem::setToZero(SourceLocation const&, bool _removeReference) const | ||||
| { | ||||
| 	CompilerUtils utils(m_context); | ||||
| 	if (!_removeReference) | ||||
| 		m_context << eth::Instruction::DUP1; | ||||
| 		m_context << Instruction::DUP1; | ||||
| 	utils.pushZeroValue(*m_dataType); | ||||
| 	utils.storeInMemoryDynamic(*m_dataType, m_padded); | ||||
| 	m_context << eth::Instruction::POP; | ||||
| 	m_context << Instruction::POP; | ||||
| } | ||||
| 
 | ||||
| StorageItem::StorageItem(CompilerContext& _compilerContext, VariableDeclaration const& _declaration): | ||||
| @ -165,29 +165,29 @@ void StorageItem::retrieveValue(SourceLocation const&, bool _remove) const | ||||
| 	{ | ||||
| 		solAssert(m_dataType->sizeOnStack() == 1, "Invalid storage ref size."); | ||||
| 		if (_remove) | ||||
| 			m_context << eth::Instruction::POP; // remove byte offset
 | ||||
| 			m_context << Instruction::POP; // remove byte offset
 | ||||
| 		else | ||||
| 			m_context << eth::Instruction::DUP2; | ||||
| 			m_context << Instruction::DUP2; | ||||
| 		return; | ||||
| 	} | ||||
| 	if (!_remove) | ||||
| 		CompilerUtils(m_context).copyToStackTop(sizeOnStack(), sizeOnStack()); | ||||
| 	if (m_dataType->storageBytes() == 32) | ||||
| 		m_context << eth::Instruction::POP << eth::Instruction::SLOAD; | ||||
| 		m_context << Instruction::POP << Instruction::SLOAD; | ||||
| 	else | ||||
| 	{ | ||||
| 		m_context | ||||
| 			<< eth::Instruction::SWAP1 << eth::Instruction::SLOAD << eth::Instruction::SWAP1 | ||||
| 			<< u256(0x100) << eth::Instruction::EXP << eth::Instruction::SWAP1 << eth::Instruction::DIV; | ||||
| 			<< Instruction::SWAP1 << Instruction::SLOAD << Instruction::SWAP1 | ||||
| 			<< u256(0x100) << Instruction::EXP << Instruction::SWAP1 << Instruction::DIV; | ||||
| 		if (m_dataType->category() == Type::Category::FixedBytes) | ||||
| 			m_context << (u256(0x1) << (256 - 8 * m_dataType->storageBytes())) << eth::Instruction::MUL; | ||||
| 			m_context << (u256(0x1) << (256 - 8 * m_dataType->storageBytes())) << Instruction::MUL; | ||||
| 		else if ( | ||||
| 			m_dataType->category() == Type::Category::Integer && | ||||
| 			dynamic_cast<IntegerType const&>(*m_dataType).isSigned() | ||||
| 		) | ||||
| 			m_context << u256(m_dataType->storageBytes() - 1) << eth::Instruction::SIGNEXTEND; | ||||
| 			m_context << u256(m_dataType->storageBytes() - 1) << Instruction::SIGNEXTEND; | ||||
| 		else | ||||
| 			m_context << ((u256(0x1) << (8 * m_dataType->storageBytes())) - 1) << eth::Instruction::AND; | ||||
| 			m_context << ((u256(0x1) << (8 * m_dataType->storageBytes())) - 1) << Instruction::AND; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| @ -202,32 +202,32 @@ void StorageItem::storeValue(Type const& _sourceType, SourceLocation const& _loc | ||||
| 		if (m_dataType->storageBytes() == 32) | ||||
| 		{ | ||||
| 			// offset should be zero
 | ||||
| 			m_context << eth::Instruction::POP; | ||||
| 			m_context << Instruction::POP; | ||||
| 			if (!_move) | ||||
| 				m_context << eth::Instruction::DUP2 << eth::Instruction::SWAP1; | ||||
| 			m_context << eth::Instruction::SSTORE; | ||||
| 				m_context << Instruction::DUP2 << Instruction::SWAP1; | ||||
| 			m_context << Instruction::SSTORE; | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			// OR the value into the other values in the storage slot
 | ||||
| 			m_context << u256(0x100) << eth::Instruction::EXP; | ||||
| 			m_context << u256(0x100) << Instruction::EXP; | ||||
| 			// stack: value storage_ref multiplier
 | ||||
| 			// fetch old value
 | ||||
| 			m_context << eth::Instruction::DUP2 << eth::Instruction::SLOAD; | ||||
| 			m_context << Instruction::DUP2 << Instruction::SLOAD; | ||||
| 			// stack: value storege_ref multiplier old_full_value
 | ||||
| 			// clear bytes in old value
 | ||||
| 			m_context | ||||
| 				<< eth::Instruction::DUP2 << ((u256(1) << (8 * m_dataType->storageBytes())) - 1) | ||||
| 				<< eth::Instruction::MUL; | ||||
| 			m_context << eth::Instruction::NOT << eth::Instruction::AND; | ||||
| 				<< Instruction::DUP2 << ((u256(1) << (8 * m_dataType->storageBytes())) - 1) | ||||
| 				<< Instruction::MUL; | ||||
| 			m_context << Instruction::NOT << Instruction::AND; | ||||
| 			// stack: value storage_ref multiplier cleared_value
 | ||||
| 			m_context | ||||
| 				<< eth::Instruction::SWAP1 << eth::Instruction::DUP4; | ||||
| 				<< Instruction::SWAP1 << Instruction::DUP4; | ||||
| 			// stack: value storage_ref cleared_value multiplier value
 | ||||
| 			if (m_dataType->category() == Type::Category::FixedBytes) | ||||
| 				m_context | ||||
| 					<< (u256(0x1) << (256 - 8 * dynamic_cast<FixedBytesType const&>(*m_dataType).numBytes())) | ||||
| 					<< eth::Instruction::SWAP1 << eth::Instruction::DIV; | ||||
| 					<< Instruction::SWAP1 << Instruction::DIV; | ||||
| 			else if ( | ||||
| 				m_dataType->category() == Type::Category::Integer && | ||||
| 				dynamic_cast<IntegerType const&>(*m_dataType).isSigned() | ||||
| @ -235,15 +235,15 @@ void StorageItem::storeValue(Type const& _sourceType, SourceLocation const& _loc | ||||
| 				// remove the higher order bits
 | ||||
| 				m_context | ||||
| 					<< (u256(1) << (8 * (32 - m_dataType->storageBytes()))) | ||||
| 					<< eth::Instruction::SWAP1 | ||||
| 					<< eth::Instruction::DUP2 | ||||
| 					<< eth::Instruction::MUL | ||||
| 					<< eth::Instruction::DIV; | ||||
| 			m_context  << eth::Instruction::MUL << eth::Instruction::OR; | ||||
| 					<< Instruction::SWAP1 | ||||
| 					<< Instruction::DUP2 | ||||
| 					<< Instruction::MUL | ||||
| 					<< Instruction::DIV; | ||||
| 			m_context  << Instruction::MUL << Instruction::OR; | ||||
| 			// stack: value storage_ref updated_value
 | ||||
| 			m_context << eth::Instruction::SWAP1 << eth::Instruction::SSTORE; | ||||
| 			m_context << Instruction::SWAP1 << Instruction::SSTORE; | ||||
| 			if (_move) | ||||
| 				m_context << eth::Instruction::POP; | ||||
| 				m_context << Instruction::POP; | ||||
| 		} | ||||
| 	} | ||||
| 	else | ||||
| @ -253,19 +253,19 @@ void StorageItem::storeValue(Type const& _sourceType, SourceLocation const& _loc | ||||
| 			"Wrong type conversation for assignment."); | ||||
| 		if (m_dataType->category() == Type::Category::Array) | ||||
| 		{ | ||||
| 			m_context << eth::Instruction::POP; // remove byte offset
 | ||||
| 			m_context << Instruction::POP; // remove byte offset
 | ||||
| 			ArrayUtils(m_context).copyArrayToStorage( | ||||
| 				dynamic_cast<ArrayType const&>(*m_dataType), | ||||
| 				dynamic_cast<ArrayType const&>(_sourceType) | ||||
| 			); | ||||
| 			if (_move) | ||||
| 				m_context << eth::Instruction::POP; | ||||
| 				m_context << Instruction::POP; | ||||
| 		} | ||||
| 		else if (m_dataType->category() == Type::Category::Struct) | ||||
| 		{ | ||||
| 			// stack layout: source_ref target_ref target_offset
 | ||||
| 			// note that we have structs, so offset should be zero and are ignored
 | ||||
| 			m_context << eth::Instruction::POP; | ||||
| 			m_context << Instruction::POP; | ||||
| 			auto const& structType = dynamic_cast<StructType const&>(*m_dataType); | ||||
| 			auto const& sourceType = dynamic_cast<StructType const&>(_sourceType); | ||||
| 			solAssert( | ||||
| @ -284,7 +284,7 @@ void StorageItem::storeValue(Type const& _sourceType, SourceLocation const& _loc | ||||
| 				{ | ||||
| 					// stack layout: source_ref target_ref
 | ||||
| 					pair<u256, unsigned> const& offsets = sourceType.storageOffsetsOfMember(member.name); | ||||
| 					m_context << offsets.first << eth::Instruction::DUP3 << eth::Instruction::ADD; | ||||
| 					m_context << offsets.first << Instruction::DUP3 << Instruction::ADD; | ||||
| 					m_context << u256(offsets.second); | ||||
| 					// stack: source_ref target_ref source_member_ref source_member_off
 | ||||
| 					StorageItem(m_context, *sourceMemberType).retrieveValue(_location, true); | ||||
| @ -296,13 +296,13 @@ void StorageItem::storeValue(Type const& _sourceType, SourceLocation const& _loc | ||||
| 					// stack layout: source_ref target_ref
 | ||||
| 					TypePointer sourceMemberType = sourceType.memberType(member.name); | ||||
| 					m_context << sourceType.memoryOffsetOfMember(member.name); | ||||
| 					m_context << eth::Instruction::DUP3 << eth::Instruction::ADD; | ||||
| 					m_context << Instruction::DUP3 << Instruction::ADD; | ||||
| 					MemoryItem(m_context, *sourceMemberType).retrieveValue(_location, true); | ||||
| 					// stack layout: source_ref target_ref source_value...
 | ||||
| 				} | ||||
| 				unsigned stackSize = sourceMemberType->sizeOnStack(); | ||||
| 				pair<u256, unsigned> const& offsets = structType.storageOffsetsOfMember(member.name); | ||||
| 				m_context << eth::dupInstruction(1 + stackSize) << offsets.first << eth::Instruction::ADD; | ||||
| 				m_context << dupInstruction(1 + stackSize) << offsets.first << Instruction::ADD; | ||||
| 				m_context << u256(offsets.second); | ||||
| 				// stack: source_ref target_ref target_off source_value... target_member_ref target_member_byte_off
 | ||||
| 				StorageItem(m_context, *memberType).storeValue(*sourceMemberType, _location, true); | ||||
| @ -312,7 +312,7 @@ void StorageItem::storeValue(Type const& _sourceType, SourceLocation const& _loc | ||||
| 			if (_move) | ||||
| 				utils.popStackSlots(2); | ||||
| 			else | ||||
| 				m_context << eth::Instruction::SWAP1 << eth::Instruction::POP; | ||||
| 				m_context << Instruction::SWAP1 << Instruction::POP; | ||||
| 		} | ||||
| 		else | ||||
| 			BOOST_THROW_EXCEPTION( | ||||
| @ -344,12 +344,12 @@ void StorageItem::setToZero(SourceLocation const&, bool _removeReference) const | ||||
| 				continue; | ||||
| 			pair<u256, unsigned> const& offsets = structType.storageOffsetsOfMember(member.name); | ||||
| 			m_context | ||||
| 				<< offsets.first << eth::Instruction::DUP3 << eth::Instruction::ADD | ||||
| 				<< offsets.first << Instruction::DUP3 << Instruction::ADD | ||||
| 				<< u256(offsets.second); | ||||
| 			StorageItem(m_context, *memberType).setToZero(); | ||||
| 		} | ||||
| 		if (_removeReference) | ||||
| 			m_context << eth::Instruction::POP << eth::Instruction::POP; | ||||
| 			m_context << Instruction::POP << Instruction::POP; | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| @ -360,23 +360,23 @@ void StorageItem::setToZero(SourceLocation const&, bool _removeReference) const | ||||
| 		{ | ||||
| 			// offset should be zero
 | ||||
| 			m_context | ||||
| 				<< eth::Instruction::POP << u256(0) | ||||
| 				<< eth::Instruction::SWAP1 << eth::Instruction::SSTORE; | ||||
| 				<< Instruction::POP << u256(0) | ||||
| 				<< Instruction::SWAP1 << Instruction::SSTORE; | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			m_context << u256(0x100) << eth::Instruction::EXP; | ||||
| 			m_context << u256(0x100) << Instruction::EXP; | ||||
| 			// stack: storage_ref multiplier
 | ||||
| 			// fetch old value
 | ||||
| 			m_context << eth::Instruction::DUP2 << eth::Instruction::SLOAD; | ||||
| 			m_context << Instruction::DUP2 << Instruction::SLOAD; | ||||
| 			// stack: storege_ref multiplier old_full_value
 | ||||
| 			// clear bytes in old value
 | ||||
| 			m_context | ||||
| 				<< eth::Instruction::SWAP1 << ((u256(1) << (8 * m_dataType->storageBytes())) - 1) | ||||
| 				<< eth::Instruction::MUL; | ||||
| 			m_context << eth::Instruction::NOT << eth::Instruction::AND; | ||||
| 				<< Instruction::SWAP1 << ((u256(1) << (8 * m_dataType->storageBytes())) - 1) | ||||
| 				<< Instruction::MUL; | ||||
| 			m_context << Instruction::NOT << Instruction::AND; | ||||
| 			// stack: storage_ref cleared_value
 | ||||
| 			m_context << eth::Instruction::SWAP1 << eth::Instruction::SSTORE; | ||||
| 			m_context << Instruction::SWAP1 << Instruction::SSTORE; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| @ -393,48 +393,48 @@ void StorageByteArrayElement::retrieveValue(SourceLocation const&, bool _remove) | ||||
| { | ||||
| 	// stack: ref byte_number
 | ||||
| 	if (_remove) | ||||
| 		m_context << eth::Instruction::SWAP1 << eth::Instruction::SLOAD | ||||
| 			<< eth::Instruction::SWAP1 << eth::Instruction::BYTE; | ||||
| 		m_context << Instruction::SWAP1 << Instruction::SLOAD | ||||
| 			<< Instruction::SWAP1 << Instruction::BYTE; | ||||
| 	else | ||||
| 		m_context << eth::Instruction::DUP2 << eth::Instruction::SLOAD | ||||
| 			<< eth::Instruction::DUP2 << eth::Instruction::BYTE; | ||||
| 	m_context << (u256(1) << (256 - 8)) << eth::Instruction::MUL; | ||||
| 		m_context << Instruction::DUP2 << Instruction::SLOAD | ||||
| 			<< Instruction::DUP2 << Instruction::BYTE; | ||||
| 	m_context << (u256(1) << (256 - 8)) << Instruction::MUL; | ||||
| } | ||||
| 
 | ||||
| void StorageByteArrayElement::storeValue(Type const&, SourceLocation const&, bool _move) const | ||||
| { | ||||
| 	// stack: value ref byte_number
 | ||||
| 	m_context << u256(31) << eth::Instruction::SUB << u256(0x100) << eth::Instruction::EXP; | ||||
| 	m_context << u256(31) << Instruction::SUB << u256(0x100) << Instruction::EXP; | ||||
| 	// stack: value ref (1<<(8*(31-byte_number)))
 | ||||
| 	m_context << eth::Instruction::DUP2 << eth::Instruction::SLOAD; | ||||
| 	m_context << Instruction::DUP2 << Instruction::SLOAD; | ||||
| 	// stack: value ref (1<<(8*(31-byte_number))) old_full_value
 | ||||
| 	// clear byte in old value
 | ||||
| 	m_context << eth::Instruction::DUP2 << u256(0xff) << eth::Instruction::MUL | ||||
| 		<< eth::Instruction::NOT << eth::Instruction::AND; | ||||
| 	m_context << Instruction::DUP2 << u256(0xff) << Instruction::MUL | ||||
| 		<< Instruction::NOT << Instruction::AND; | ||||
| 	// stack: value ref (1<<(32-byte_number)) old_full_value_with_cleared_byte
 | ||||
| 	m_context << eth::Instruction::SWAP1; | ||||
| 	m_context << (u256(1) << (256 - 8)) << eth::Instruction::DUP5 << eth::Instruction::DIV | ||||
| 		<< eth::Instruction::MUL << eth::Instruction::OR; | ||||
| 	m_context << Instruction::SWAP1; | ||||
| 	m_context << (u256(1) << (256 - 8)) << Instruction::DUP5 << Instruction::DIV | ||||
| 		<< Instruction::MUL << Instruction::OR; | ||||
| 	// stack: value ref new_full_value
 | ||||
| 	m_context << eth::Instruction::SWAP1 << eth::Instruction::SSTORE; | ||||
| 	m_context << Instruction::SWAP1 << Instruction::SSTORE; | ||||
| 	if (_move) | ||||
| 		m_context << eth::Instruction::POP; | ||||
| 		m_context << Instruction::POP; | ||||
| } | ||||
| 
 | ||||
| void StorageByteArrayElement::setToZero(SourceLocation const&, bool _removeReference) const | ||||
| { | ||||
| 	// stack: ref byte_number
 | ||||
| 	if (!_removeReference) | ||||
| 		m_context << eth::Instruction::DUP2 << eth::Instruction::DUP2; | ||||
| 	m_context << u256(31) << eth::Instruction::SUB << u256(0x100) << eth::Instruction::EXP; | ||||
| 		m_context << Instruction::DUP2 << Instruction::DUP2; | ||||
| 	m_context << u256(31) << Instruction::SUB << u256(0x100) << Instruction::EXP; | ||||
| 	// stack: ref (1<<(8*(31-byte_number)))
 | ||||
| 	m_context << eth::Instruction::DUP2 << eth::Instruction::SLOAD; | ||||
| 	m_context << Instruction::DUP2 << Instruction::SLOAD; | ||||
| 	// stack: ref (1<<(8*(31-byte_number))) old_full_value
 | ||||
| 	// clear byte in old value
 | ||||
| 	m_context << eth::Instruction::SWAP1 << u256(0xff) << eth::Instruction::MUL; | ||||
| 	m_context << eth::Instruction::NOT << eth::Instruction::AND; | ||||
| 	m_context << Instruction::SWAP1 << u256(0xff) << Instruction::MUL; | ||||
| 	m_context << Instruction::NOT << Instruction::AND; | ||||
| 	// stack: ref old_full_value_with_cleared_byte
 | ||||
| 	m_context << eth::Instruction::SWAP1 << eth::Instruction::SSTORE; | ||||
| 	m_context << Instruction::SWAP1 << Instruction::SSTORE; | ||||
| } | ||||
| 
 | ||||
| StorageArrayLength::StorageArrayLength(CompilerContext& _compilerContext, const ArrayType& _arrayType): | ||||
| @ -448,22 +448,22 @@ void StorageArrayLength::retrieveValue(SourceLocation const&, bool _remove) cons | ||||
| { | ||||
| 	ArrayUtils(m_context).retrieveLength(m_arrayType); | ||||
| 	if (_remove) | ||||
| 		m_context << eth::Instruction::SWAP1 << eth::Instruction::POP; | ||||
| 		m_context << Instruction::SWAP1 << Instruction::POP; | ||||
| } | ||||
| 
 | ||||
| void StorageArrayLength::storeValue(Type const&, SourceLocation const&, bool _move) const | ||||
| { | ||||
| 	if (_move) | ||||
| 		m_context << eth::Instruction::SWAP1; | ||||
| 		m_context << Instruction::SWAP1; | ||||
| 	else | ||||
| 		m_context << eth::Instruction::DUP2; | ||||
| 		m_context << Instruction::DUP2; | ||||
| 	ArrayUtils(m_context).resizeDynamicArray(m_arrayType); | ||||
| } | ||||
| 
 | ||||
| void StorageArrayLength::setToZero(SourceLocation const&, bool _removeReference) const | ||||
| { | ||||
| 	if (!_removeReference) | ||||
| 		m_context << eth::Instruction::DUP1; | ||||
| 		m_context << Instruction::DUP1; | ||||
| 	ArrayUtils(m_context).clearDynamicArray(m_arrayType); | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -25,6 +25,7 @@ | ||||
| #include <functional> | ||||
| #include <libevmasm/Assembly.h> | ||||
| #include <libevmasm/SourceLocation.h> | ||||
| #include <libevmasm/Instruction.h> | ||||
| #include <libsolidity/inlineasm/AsmParser.h> | ||||
| #include <libsolidity/inlineasm/AsmData.h> | ||||
| 
 | ||||
| @ -116,7 +117,7 @@ public: | ||||
| 			m_identifierAccess = [](assembly::Identifier const&, eth::Assembly&, CodeGenerator::IdentifierContext) { return false; }; | ||||
| 	} | ||||
| 
 | ||||
| 	void operator()(Instruction const& _instruction) | ||||
| 	void operator()(dev::solidity::assembly::Instruction const& _instruction) | ||||
| 	{ | ||||
| 		m_state.assembly.append(_instruction.instruction); | ||||
| 	} | ||||
| @ -145,7 +146,7 @@ public: | ||||
| 					"Variable inaccessible, too deep inside stack (" + boost::lexical_cast<string>(heightDiff) + ")" | ||||
| 				); | ||||
| 			else | ||||
| 				m_state.assembly.append(eth::dupInstruction(heightDiff)); | ||||
| 				m_state.assembly.append(solidity::dupInstruction(heightDiff)); | ||||
| 			return; | ||||
| 		} | ||||
| 		else if (eth::AssemblyItem const* label = m_state.findLabel(_identifier.name)) | ||||
| @ -196,7 +197,7 @@ public: | ||||
| 		//@TODO check height before and after
 | ||||
| 		while (m_state.variables.size() > numVariables) | ||||
| 		{ | ||||
| 			m_state.assembly.append(eth::Instruction::POP); | ||||
| 			m_state.assembly.append(solidity::Instruction::POP); | ||||
| 			m_state.variables.pop_back(); | ||||
| 		} | ||||
| 	} | ||||
| @ -215,8 +216,8 @@ private: | ||||
| 				); | ||||
| 			else | ||||
| 			{ | ||||
| 				m_state.assembly.append(eth::swapInstruction(heightDiff)); | ||||
| 				m_state.assembly.append(eth::Instruction::POP); | ||||
| 				m_state.assembly.append(solidity::swapInstruction(heightDiff)); | ||||
| 				m_state.assembly.append(solidity::Instruction::POP); | ||||
| 			} | ||||
| 			return; | ||||
| 		} | ||||
|  | ||||
| @ -23,7 +23,7 @@ | ||||
| #pragma once | ||||
| 
 | ||||
| #include <boost/variant.hpp> | ||||
| #include <libevmcore/Instruction.h> | ||||
| #include <libevmasm/Instruction.h> | ||||
| 
 | ||||
| namespace dev | ||||
| { | ||||
| @ -35,7 +35,7 @@ namespace assembly | ||||
| /// What follows are the AST nodes for assembly.
 | ||||
| 
 | ||||
| /// Direct EVM instruction (except PUSHi and JUMPDEST)
 | ||||
| struct Instruction { eth::Instruction instruction; }; | ||||
| struct Instruction { solidity::Instruction instruction; }; | ||||
| /// Literal number or string (up to 32 bytes)
 | ||||
| struct Literal { bool isNumber; std::string value; }; | ||||
| /// External / internal identifier or label reference
 | ||||
|  | ||||
| @ -23,7 +23,6 @@ | ||||
| #include <libsolidity/inlineasm/AsmParser.h> | ||||
| #include <ctype.h> | ||||
| #include <algorithm> | ||||
| #include <libevmcore/Instruction.h> | ||||
| #include <libsolidity/parsing/Scanner.h> | ||||
| 
 | ||||
| using namespace std; | ||||
| @ -121,17 +120,17 @@ assembly::Statement Parser::parseExpression() | ||||
| assembly::Statement Parser::parseElementaryOperation(bool _onlySinglePusher) | ||||
| { | ||||
| 	// Allowed instructions, lowercase names.
 | ||||
| 	static map<string, eth::Instruction> s_instructions; | ||||
| 	static map<string, dev::solidity::Instruction> s_instructions; | ||||
| 	if (s_instructions.empty()) | ||||
| 		for (auto const& instruction: eth::c_instructions) | ||||
| 		for (auto const& instruction: solidity::c_instructions) | ||||
| 		{ | ||||
| 			if ( | ||||
| 				instruction.second == eth::Instruction::JUMPDEST || | ||||
| 				(eth::Instruction::PUSH1 <= instruction.second && instruction.second <= eth::Instruction::PUSH32) | ||||
| 				instruction.second == solidity::Instruction::JUMPDEST || | ||||
| 				(solidity::Instruction::PUSH1 <= instruction.second && instruction.second <= solidity::Instruction::PUSH32) | ||||
| 			) | ||||
| 				continue; | ||||
| 			string name = instruction.first; | ||||
| 			if (instruction.second == eth::Instruction::SUICIDE) | ||||
| 			if (instruction.second == solidity::Instruction::SUICIDE) | ||||
| 				name = "selfdestruct"; | ||||
| 			transform(name.begin(), name.end(), name.begin(), [](unsigned char _c) { return tolower(_c); }); | ||||
| 			s_instructions[name] = instruction.second; | ||||
| @ -152,10 +151,10 @@ assembly::Statement Parser::parseElementaryOperation(bool _onlySinglePusher) | ||||
| 		// first search the set of instructions.
 | ||||
| 		if (s_instructions.count(literal)) | ||||
| 		{ | ||||
| 			eth::Instruction const& instr = s_instructions[literal]; | ||||
| 			dev::solidity::Instruction const& instr = s_instructions[literal]; | ||||
| 			if (_onlySinglePusher) | ||||
| 			{ | ||||
| 				eth::InstructionInfo info = eth::instructionInfo(instr); | ||||
| 				InstructionInfo info = dev::solidity::instructionInfo(instr); | ||||
| 				if (info.ret != 1) | ||||
| 					fatalParserError("Instruction " + info.name + " not allowed in this context."); | ||||
| 			} | ||||
| @ -200,11 +199,11 @@ FunctionalInstruction Parser::parseFunctionalInstruction(assembly::Statement con | ||||
| { | ||||
| 	if (_instruction.type() != typeid(Instruction)) | ||||
| 		fatalParserError("Assembly instruction required in front of \"(\")"); | ||||
| 	eth::Instruction instr = boost::get<Instruction>(_instruction).instruction; | ||||
| 	eth::InstructionInfo instrInfo = eth::instructionInfo(instr); | ||||
| 	if (eth::Instruction::DUP1 <= instr && instr <= eth::Instruction::DUP16) | ||||
| 	solidity::Instruction instr = boost::get<solidity::assembly::Instruction>(_instruction).instruction; | ||||
| 	InstructionInfo instrInfo = instructionInfo(instr); | ||||
| 	if (solidity::Instruction::DUP1 <= instr && instr <= solidity::Instruction::DUP16) | ||||
| 		fatalParserError("DUPi instructions not allowed for functional notation"); | ||||
| 	if (eth::Instruction::SWAP1 <= instr && instr <= eth::Instruction::SWAP16) | ||||
| 	if (solidity::Instruction::SWAP1 <= instr && instr <= solidity::Instruction::SWAP16) | ||||
| 		fatalParserError("SWAPi instructions not allowed for functional notation"); | ||||
| 
 | ||||
| 	expectToken(Token::LParen); | ||||
|  | ||||
| @ -137,8 +137,8 @@ GasEstimator::GasConsumption GasEstimator::functionalEstimation( | ||||
| 		using Id = ExpressionClasses::Id; | ||||
| 		using Ids = vector<Id>; | ||||
| 		Id hashValue = classes.find(u256(FixedHash<4>::Arith(FixedHash<4>(dev::sha3(_signature))))); | ||||
| 		Id calldata = classes.find(eth::Instruction::CALLDATALOAD, Ids{classes.find(u256(0))}); | ||||
| 		classes.forceEqual(hashValue, eth::Instruction::DIV, Ids{ | ||||
| 		Id calldata = classes.find(Instruction::CALLDATALOAD, Ids{classes.find(u256(0))}); | ||||
| 		classes.forceEqual(hashValue, Instruction::DIV, Ids{ | ||||
| 			calldata, | ||||
| 			classes.find(u256(1) << (8 * 28)) | ||||
| 		}); | ||||
| @ -165,7 +165,7 @@ GasEstimator::GasConsumption GasEstimator::functionalEstimation( | ||||
| 	AssemblyItem invalidTag(PushTag, u256(-0x10)); | ||||
| 	state->feedItem(invalidTag, true); | ||||
| 	if (parametersSize > 0) | ||||
| 		state->feedItem(eth::swapInstruction(parametersSize)); | ||||
| 		state->feedItem(swapInstruction(parametersSize)); | ||||
| 
 | ||||
| 	return PathGasMeter(_items).estimateMax(_offset, state); | ||||
| } | ||||
|  | ||||
| @ -6,7 +6,7 @@ file(GLOB HEADERS "*.h") | ||||
| include_directories(BEFORE ..) | ||||
| add_executable(${EXECUTABLE} ${SRC_LIST} ${HEADERS}) | ||||
| 
 | ||||
| eth_use(${EXECUTABLE} REQUIRED Solidity::lll Dev::buildinfo) | ||||
| eth_use(${EXECUTABLE} REQUIRED Solidity::lll Dev::buildinfo Solidity::evmasm) | ||||
| 
 | ||||
| install( TARGETS ${EXECUTABLE} DESTINATION bin ) | ||||
| 
 | ||||
|  | ||||
| @ -25,10 +25,11 @@ | ||||
| #include <liblll/Compiler.h> | ||||
| #include <libdevcore/CommonIO.h> | ||||
| #include <libdevcore/CommonData.h> | ||||
| #include <libevmcore/Instruction.h> | ||||
| #include <libevmasm/Instruction.h> | ||||
| #include "ethereum/BuildInfo.h" | ||||
| using namespace std; | ||||
| using namespace dev; | ||||
| using namespace dev::solidity; | ||||
| using namespace dev::eth; | ||||
| 
 | ||||
| void help() | ||||
|  | ||||
| @ -34,7 +34,7 @@ | ||||
| #include <libdevcore/Common.h> | ||||
| #include <libdevcore/CommonData.h> | ||||
| #include <libdevcore/CommonIO.h> | ||||
| #include <libevmcore/Instruction.h> | ||||
| #include <libevmasm/Instruction.h> | ||||
| #include <libsolidity/interface/Version.h> | ||||
| #include <libsolidity/parsing/Scanner.h> | ||||
| #include <libsolidity/parsing/Parser.h> | ||||
| @ -161,11 +161,11 @@ void CommandLineInterface::handleBinary(string const& _contract) | ||||
| void CommandLineInterface::handleOpcode(string const& _contract) | ||||
| { | ||||
| 	if (m_args.count("output-dir")) | ||||
| 		createFile(_contract + ".opcode", eth::disassemble(m_compiler->object(_contract).bytecode)); | ||||
| 		createFile(_contract + ".opcode", solidity::disassemble(m_compiler->object(_contract).bytecode)); | ||||
| 	else | ||||
| 	{ | ||||
| 		cout << "Opcodes: " << endl; | ||||
| 		cout << eth::disassemble(m_compiler->object(_contract).bytecode); | ||||
| 		cout << solidity::disassemble(m_compiler->object(_contract).bytecode); | ||||
| 		cout << endl; | ||||
| 	} | ||||
| } | ||||
| @ -674,7 +674,7 @@ void CommandLineInterface::handleCombinedJSON() | ||||
| 		if (requests.count("clone-bin")) | ||||
| 			contractData["clone-bin"] = m_compiler->cloneObject(contractName).toHex(); | ||||
| 		if (requests.count("opcodes")) | ||||
| 			contractData["opcodes"] = eth::disassemble(m_compiler->object(contractName).bytecode); | ||||
| 			contractData["opcodes"] = solidity::disassemble(m_compiler->object(contractName).bytecode); | ||||
| 		if (requests.count("asm")) | ||||
| 		{ | ||||
| 			ostringstream unused; | ||||
|  | ||||
| @ -27,7 +27,7 @@ | ||||
| #include <libdevcore/Common.h> | ||||
| #include <libdevcore/CommonData.h> | ||||
| #include <libdevcore/CommonIO.h> | ||||
| #include <libevmcore/Instruction.h> | ||||
| #include <libevmasm/Instruction.h> | ||||
| #include <libsolidity/parsing/Scanner.h> | ||||
| #include <libsolidity/parsing/Parser.h> | ||||
| #include <libsolidity/ast/ASTPrinter.h> | ||||
| @ -206,7 +206,7 @@ string compile(StringMap const& _sources, bool _optimize, CStyleReadFileCallback | ||||
| 			contractData["interface"] = compiler.interface(contractName); | ||||
| 			contractData["bytecode"] = compiler.object(contractName).toHex(); | ||||
| 			contractData["runtimeBytecode"] = compiler.runtimeObject(contractName).toHex(); | ||||
| 			contractData["opcodes"] = eth::disassemble(compiler.object(contractName).bytecode); | ||||
| 			contractData["opcodes"] = solidity::disassemble(compiler.object(contractName).bytecode); | ||||
| 			contractData["functionHashes"] = functionHashes(compiler.contractDefinition(contractName)); | ||||
| 			contractData["gasEstimates"] = estimateGas(compiler, contractName); | ||||
| 			ostringstream unused; | ||||
|  | ||||
| @ -174,7 +174,7 @@ BOOST_AUTO_TEST_CASE(literal_true) | ||||
| 							 "}\n"; | ||||
| 	bytes code = compileFirstExpression(sourceCode); | ||||
| 
 | ||||
| 	bytes expectation({byte(eth::Instruction::PUSH1), 0x1}); | ||||
| 	bytes expectation({byte(Instruction::PUSH1), 0x1}); | ||||
| 	BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); | ||||
| } | ||||
| 
 | ||||
| @ -185,7 +185,7 @@ BOOST_AUTO_TEST_CASE(literal_false) | ||||
| 							 "}\n"; | ||||
| 	bytes code = compileFirstExpression(sourceCode); | ||||
| 
 | ||||
| 	bytes expectation({byte(eth::Instruction::PUSH1), 0x0}); | ||||
| 	bytes expectation({byte(Instruction::PUSH1), 0x0}); | ||||
| 	BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); | ||||
| } | ||||
| 
 | ||||
| @ -196,7 +196,7 @@ BOOST_AUTO_TEST_CASE(int_literal) | ||||
| 							 "}\n"; | ||||
| 	bytes code = compileFirstExpression(sourceCode); | ||||
| 
 | ||||
| 	bytes expectation({byte(eth::Instruction::PUSH10), 0x12, 0x34, 0x56, 0x78, 0x90, | ||||
| 	bytes expectation({byte(Instruction::PUSH10), 0x12, 0x34, 0x56, 0x78, 0x90, | ||||
| 													   0x12, 0x34, 0x56, 0x78, 0x90}); | ||||
| 	BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); | ||||
| } | ||||
| @ -212,7 +212,7 @@ BOOST_AUTO_TEST_CASE(int_with_wei_ether_subdenomination) | ||||
| 		})"; | ||||
| 	bytes code = compileFirstExpression(sourceCode); | ||||
| 
 | ||||
| 	bytes expectation({byte(eth::Instruction::PUSH1), 0x1}); | ||||
| 	bytes expectation({byte(Instruction::PUSH1), 0x1}); | ||||
| 	BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); | ||||
| } | ||||
| 
 | ||||
| @ -227,7 +227,7 @@ BOOST_AUTO_TEST_CASE(int_with_szabo_ether_subdenomination) | ||||
| 		})"; | ||||
| 	bytes code = compileFirstExpression(sourceCode); | ||||
| 
 | ||||
| 	bytes expectation({byte(eth::Instruction::PUSH5), 0xe8, 0xd4, 0xa5, 0x10, 0x00}); | ||||
| 	bytes expectation({byte(Instruction::PUSH5), 0xe8, 0xd4, 0xa5, 0x10, 0x00}); | ||||
| 	BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); | ||||
| } | ||||
| 
 | ||||
| @ -242,7 +242,7 @@ BOOST_AUTO_TEST_CASE(int_with_finney_ether_subdenomination) | ||||
| 		})"; | ||||
| 	bytes code = compileFirstExpression(sourceCode); | ||||
| 
 | ||||
| 	bytes expectation({byte(eth::Instruction::PUSH7), 0x3, 0x8d, 0x7e, 0xa4, 0xc6, 0x80, 0x00}); | ||||
| 	bytes expectation({byte(Instruction::PUSH7), 0x3, 0x8d, 0x7e, 0xa4, 0xc6, 0x80, 0x00}); | ||||
| 	BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); | ||||
| } | ||||
| 
 | ||||
| @ -257,7 +257,7 @@ BOOST_AUTO_TEST_CASE(int_with_ether_ether_subdenomination) | ||||
| 		})"; | ||||
| 	bytes code = compileFirstExpression(sourceCode); | ||||
| 
 | ||||
| 	bytes expectation({byte(eth::Instruction::PUSH8), 0xd, 0xe0, 0xb6, 0xb3, 0xa7, 0x64, 0x00, 0x00}); | ||||
| 	bytes expectation({byte(Instruction::PUSH8), 0xd, 0xe0, 0xb6, 0xb3, 0xa7, 0x64, 0x00, 0x00}); | ||||
| 	BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); | ||||
| } | ||||
| 
 | ||||
| @ -268,12 +268,12 @@ BOOST_AUTO_TEST_CASE(comparison) | ||||
| 							 "}\n"; | ||||
| 	bytes code = compileFirstExpression(sourceCode); | ||||
| 
 | ||||
| 	bytes expectation({byte(eth::Instruction::PUSH1), 0x1, | ||||
| 					   byte(eth::Instruction::PUSH2), 0x11, 0xaa, | ||||
| 					   byte(eth::Instruction::PUSH2), 0x10, 0xaa, | ||||
| 					   byte(eth::Instruction::LT), | ||||
| 					   byte(eth::Instruction::EQ), | ||||
| 					   byte(eth::Instruction::ISZERO)}); | ||||
| 	bytes expectation({byte(Instruction::PUSH1), 0x1, | ||||
| 					   byte(Instruction::PUSH2), 0x11, 0xaa, | ||||
| 					   byte(Instruction::PUSH2), 0x10, 0xaa, | ||||
| 					   byte(Instruction::LT), | ||||
| 					   byte(Instruction::EQ), | ||||
| 					   byte(Instruction::ISZERO)}); | ||||
| 	BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); | ||||
| } | ||||
| 
 | ||||
| @ -284,22 +284,22 @@ BOOST_AUTO_TEST_CASE(short_circuiting) | ||||
| 							 "}\n"; | ||||
| 	bytes code = compileFirstExpression(sourceCode); | ||||
| 
 | ||||
| 	bytes expectation({byte(eth::Instruction::PUSH1), 0x12, // 8 + 10
 | ||||
| 					   byte(eth::Instruction::PUSH1), 0x4, | ||||
| 					   byte(eth::Instruction::GT), | ||||
| 					   byte(eth::Instruction::ISZERO), // after this we have 4 <= 8 + 10
 | ||||
| 					   byte(eth::Instruction::DUP1), | ||||
| 					   byte(eth::Instruction::PUSH1), 0x11, | ||||
| 					   byte(eth::Instruction::JUMPI), // short-circuit if it is true
 | ||||
| 					   byte(eth::Instruction::POP), | ||||
| 					   byte(eth::Instruction::PUSH1), 0x2, | ||||
| 					   byte(eth::Instruction::PUSH1), 0x9, | ||||
| 					   byte(eth::Instruction::EQ), | ||||
| 					   byte(eth::Instruction::ISZERO), // after this we have 9 != 2
 | ||||
| 					   byte(eth::Instruction::JUMPDEST), | ||||
| 					   byte(eth::Instruction::PUSH1), 0x1, | ||||
| 					   byte(eth::Instruction::EQ), | ||||
| 					   byte(eth::Instruction::ISZERO)}); | ||||
| 	bytes expectation({byte(Instruction::PUSH1), 0x12, // 8 + 10
 | ||||
| 					   byte(Instruction::PUSH1), 0x4, | ||||
| 					   byte(Instruction::GT), | ||||
| 					   byte(Instruction::ISZERO), // after this we have 4 <= 8 + 10
 | ||||
| 					   byte(Instruction::DUP1), | ||||
| 					   byte(Instruction::PUSH1), 0x11, | ||||
| 					   byte(Instruction::JUMPI), // short-circuit if it is true
 | ||||
| 					   byte(Instruction::POP), | ||||
| 					   byte(Instruction::PUSH1), 0x2, | ||||
| 					   byte(Instruction::PUSH1), 0x9, | ||||
| 					   byte(Instruction::EQ), | ||||
| 					   byte(Instruction::ISZERO), // after this we have 9 != 2
 | ||||
| 					   byte(Instruction::JUMPDEST), | ||||
| 					   byte(Instruction::PUSH1), 0x1, | ||||
| 					   byte(Instruction::EQ), | ||||
| 					   byte(Instruction::ISZERO)}); | ||||
| 	BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); | ||||
| } | ||||
| 
 | ||||
| @ -309,23 +309,23 @@ BOOST_AUTO_TEST_CASE(arithmetics) | ||||
| 							 "  function f(uint y) { var x = ((((((((y ^ 8) & 7) | 6) - 5) + 4) % 3) / 2) * 1); }" | ||||
| 							 "}\n"; | ||||
| 	bytes code = compileFirstExpression(sourceCode, {}, {{"test", "f", "y"}, {"test", "f", "x"}}); | ||||
| 	bytes expectation({byte(eth::Instruction::PUSH1), 0x1, | ||||
| 					   byte(eth::Instruction::PUSH1), 0x2, | ||||
| 					   byte(eth::Instruction::PUSH1), 0x3, | ||||
| 					   byte(eth::Instruction::PUSH1), 0x4, | ||||
| 					   byte(eth::Instruction::PUSH1), 0x5, | ||||
| 					   byte(eth::Instruction::PUSH1), 0x6, | ||||
| 					   byte(eth::Instruction::PUSH1), 0x7, | ||||
| 					   byte(eth::Instruction::PUSH1), 0x8, | ||||
| 					   byte(eth::Instruction::DUP10), | ||||
| 					   byte(eth::Instruction::XOR), | ||||
| 					   byte(eth::Instruction::AND), | ||||
| 					   byte(eth::Instruction::OR), | ||||
| 					   byte(eth::Instruction::SUB), | ||||
| 					   byte(eth::Instruction::ADD), | ||||
| 					   byte(eth::Instruction::MOD), | ||||
| 					   byte(eth::Instruction::DIV), | ||||
| 					   byte(eth::Instruction::MUL)}); | ||||
| 	bytes expectation({byte(Instruction::PUSH1), 0x1, | ||||
| 					   byte(Instruction::PUSH1), 0x2, | ||||
| 					   byte(Instruction::PUSH1), 0x3, | ||||
| 					   byte(Instruction::PUSH1), 0x4, | ||||
| 					   byte(Instruction::PUSH1), 0x5, | ||||
| 					   byte(Instruction::PUSH1), 0x6, | ||||
| 					   byte(Instruction::PUSH1), 0x7, | ||||
| 					   byte(Instruction::PUSH1), 0x8, | ||||
| 					   byte(Instruction::DUP10), | ||||
| 					   byte(Instruction::XOR), | ||||
| 					   byte(Instruction::AND), | ||||
| 					   byte(Instruction::OR), | ||||
| 					   byte(Instruction::SUB), | ||||
| 					   byte(Instruction::ADD), | ||||
| 					   byte(Instruction::MOD), | ||||
| 					   byte(Instruction::DIV), | ||||
| 					   byte(Instruction::MUL)}); | ||||
| 	BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); | ||||
| } | ||||
| 
 | ||||
| @ -336,13 +336,13 @@ BOOST_AUTO_TEST_CASE(unary_operators) | ||||
| 							 "}\n"; | ||||
| 	bytes code = compileFirstExpression(sourceCode, {}, {{"test", "f", "y"}, {"test", "f", "x"}}); | ||||
| 
 | ||||
| 	bytes expectation({byte(eth::Instruction::PUSH1), 0x2, | ||||
| 					   byte(eth::Instruction::DUP3), | ||||
| 					   byte(eth::Instruction::PUSH1), 0x0, | ||||
| 					   byte(eth::Instruction::SUB), | ||||
| 					   byte(eth::Instruction::NOT), | ||||
| 					   byte(eth::Instruction::EQ), | ||||
| 					   byte(eth::Instruction::ISZERO)}); | ||||
| 	bytes expectation({byte(Instruction::PUSH1), 0x2, | ||||
| 					   byte(Instruction::DUP3), | ||||
| 					   byte(Instruction::PUSH1), 0x0, | ||||
| 					   byte(Instruction::SUB), | ||||
| 					   byte(Instruction::NOT), | ||||
| 					   byte(Instruction::EQ), | ||||
| 					   byte(Instruction::ISZERO)}); | ||||
| 	BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); | ||||
| } | ||||
| 
 | ||||
| @ -354,44 +354,44 @@ BOOST_AUTO_TEST_CASE(unary_inc_dec) | ||||
| 	bytes code = compileFirstExpression(sourceCode, {}, {{"test", "f", "a"}, {"test", "f", "x"}}); | ||||
| 
 | ||||
| 	// Stack: a, x
 | ||||
| 	bytes expectation({byte(eth::Instruction::DUP2), | ||||
| 					   byte(eth::Instruction::DUP1), | ||||
| 					   byte(eth::Instruction::PUSH1), 0x1, | ||||
| 					   byte(eth::Instruction::ADD), | ||||
| 	bytes expectation({byte(Instruction::DUP2), | ||||
| 					   byte(Instruction::DUP1), | ||||
| 					   byte(Instruction::PUSH1), 0x1, | ||||
| 					   byte(Instruction::ADD), | ||||
| 					   // Stack here: a x a (a+1)
 | ||||
| 					   byte(eth::Instruction::SWAP3), | ||||
| 					   byte(eth::Instruction::POP), // first ++
 | ||||
| 					   byte(Instruction::SWAP3), | ||||
| 					   byte(Instruction::POP), // first ++
 | ||||
| 					   // Stack here: (a+1) x a
 | ||||
| 					   byte(eth::Instruction::DUP3), | ||||
| 					   byte(eth::Instruction::PUSH1), 0x1, | ||||
| 					   byte(eth::Instruction::ADD), | ||||
| 					   byte(Instruction::DUP3), | ||||
| 					   byte(Instruction::PUSH1), 0x1, | ||||
| 					   byte(Instruction::ADD), | ||||
| 					   // Stack here: (a+1) x a (a+2)
 | ||||
| 					   byte(eth::Instruction::SWAP3), | ||||
| 					   byte(eth::Instruction::POP), | ||||
| 					   byte(Instruction::SWAP3), | ||||
| 					   byte(Instruction::POP), | ||||
| 					   // Stack here: (a+2) x a
 | ||||
| 					   byte(eth::Instruction::DUP3), // second ++
 | ||||
| 					   byte(eth::Instruction::XOR), | ||||
| 					   byte(Instruction::DUP3), // second ++
 | ||||
| 					   byte(Instruction::XOR), | ||||
| 					   // Stack here: (a+2) x a^(a+2)
 | ||||
| 					   byte(eth::Instruction::DUP3), | ||||
| 					   byte(eth::Instruction::DUP1), | ||||
| 					   byte(eth::Instruction::PUSH1), 0x1, | ||||
| 					   byte(eth::Instruction::SWAP1), | ||||
| 					   byte(eth::Instruction::SUB), | ||||
| 					   byte(Instruction::DUP3), | ||||
| 					   byte(Instruction::DUP1), | ||||
| 					   byte(Instruction::PUSH1), 0x1, | ||||
| 					   byte(Instruction::SWAP1), | ||||
| 					   byte(Instruction::SUB), | ||||
| 					   // Stack here: (a+2) x a^(a+2) (a+2) (a+1)
 | ||||
| 					   byte(eth::Instruction::SWAP4), | ||||
| 					   byte(eth::Instruction::POP), // first --
 | ||||
| 					   byte(eth::Instruction::XOR), | ||||
| 					   byte(Instruction::SWAP4), | ||||
| 					   byte(Instruction::POP), // first --
 | ||||
| 					   byte(Instruction::XOR), | ||||
| 					   // Stack here: (a+1) x a^(a+2)^(a+2)
 | ||||
| 					   byte(eth::Instruction::DUP3), | ||||
| 					   byte(eth::Instruction::PUSH1), 0x1, | ||||
| 					   byte(eth::Instruction::SWAP1), | ||||
| 					   byte(eth::Instruction::SUB), | ||||
| 					   byte(Instruction::DUP3), | ||||
| 					   byte(Instruction::PUSH1), 0x1, | ||||
| 					   byte(Instruction::SWAP1), | ||||
| 					   byte(Instruction::SUB), | ||||
| 					   // Stack here: (a+1) x a^(a+2)^(a+2) a
 | ||||
| 					   byte(eth::Instruction::SWAP3), | ||||
| 					   byte(eth::Instruction::POP), // second ++
 | ||||
| 					   byte(Instruction::SWAP3), | ||||
| 					   byte(Instruction::POP), // second ++
 | ||||
| 					   // Stack here: a x a^(a+2)^(a+2)
 | ||||
| 					   byte(eth::Instruction::DUP3), // will change
 | ||||
| 					   byte(eth::Instruction::XOR)}); | ||||
| 					   byte(Instruction::DUP3), // will change
 | ||||
| 					   byte(Instruction::XOR)}); | ||||
| 					   // Stack here: a x a^(a+2)^(a+2)^a
 | ||||
| 	BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); | ||||
| } | ||||
| @ -404,16 +404,16 @@ BOOST_AUTO_TEST_CASE(assignment) | ||||
| 	bytes code = compileFirstExpression(sourceCode, {}, {{"test", "f", "a"}, {"test", "f", "b"}}); | ||||
| 
 | ||||
| 	// Stack: a, b
 | ||||
| 	bytes expectation({byte(eth::Instruction::PUSH1), 0x2, | ||||
| 					   byte(eth::Instruction::DUP2), | ||||
| 					   byte(eth::Instruction::DUP4), | ||||
| 					   byte(eth::Instruction::ADD), | ||||
| 	bytes expectation({byte(Instruction::PUSH1), 0x2, | ||||
| 					   byte(Instruction::DUP2), | ||||
| 					   byte(Instruction::DUP4), | ||||
| 					   byte(Instruction::ADD), | ||||
| 					   // Stack here: a b 2 a+b
 | ||||
| 					   byte(eth::Instruction::SWAP3), | ||||
| 					   byte(eth::Instruction::POP), | ||||
| 					   byte(eth::Instruction::DUP3), | ||||
| 					   byte(Instruction::SWAP3), | ||||
| 					   byte(Instruction::POP), | ||||
| 					   byte(Instruction::DUP3), | ||||
| 					   // Stack here: a+b b 2 a+b
 | ||||
| 					   byte(eth::Instruction::MUL)}); | ||||
| 					   byte(Instruction::MUL)}); | ||||
| 	BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); | ||||
| } | ||||
| 
 | ||||
| @ -427,26 +427,26 @@ BOOST_AUTO_TEST_CASE(function_call) | ||||
| 										{{"test", "f", "a"}, {"test", "f", "b"}}); | ||||
| 
 | ||||
| 	// Stack: a, b
 | ||||
| 	bytes expectation({byte(eth::Instruction::PUSH1), 0x02, | ||||
| 					   byte(eth::Instruction::PUSH1), 0x0c, | ||||
| 					   byte(eth::Instruction::PUSH1), 0x01, | ||||
| 					   byte(eth::Instruction::DUP5), | ||||
| 					   byte(eth::Instruction::ADD), | ||||
| 	bytes expectation({byte(Instruction::PUSH1), 0x02, | ||||
| 					   byte(Instruction::PUSH1), 0x0c, | ||||
| 					   byte(Instruction::PUSH1), 0x01, | ||||
| 					   byte(Instruction::DUP5), | ||||
| 					   byte(Instruction::ADD), | ||||
| 					   // Stack here: a b 2 <ret label> (a+1)
 | ||||
| 					   byte(eth::Instruction::DUP4), | ||||
| 					   byte(eth::Instruction::PUSH1), 0x13, | ||||
| 					   byte(eth::Instruction::JUMP), | ||||
| 					   byte(eth::Instruction::JUMPDEST), | ||||
| 					   byte(Instruction::DUP4), | ||||
| 					   byte(Instruction::PUSH1), 0x13, | ||||
| 					   byte(Instruction::JUMP), | ||||
| 					   byte(Instruction::JUMPDEST), | ||||
| 					   // Stack here: a b 2 g(a+1, b)
 | ||||
| 					   byte(eth::Instruction::MUL), | ||||
| 					   byte(Instruction::MUL), | ||||
| 					   // Stack here: a b g(a+1, b)*2
 | ||||
| 					   byte(eth::Instruction::DUP3), | ||||
| 					   byte(eth::Instruction::ADD), | ||||
| 					   byte(Instruction::DUP3), | ||||
| 					   byte(Instruction::ADD), | ||||
| 					   // Stack here: a b a+g(a+1, b)*2
 | ||||
| 					   byte(eth::Instruction::SWAP2), | ||||
| 					   byte(eth::Instruction::POP), | ||||
| 					   byte(eth::Instruction::DUP2), | ||||
| 					   byte(eth::Instruction::JUMPDEST)}); | ||||
| 					   byte(Instruction::SWAP2), | ||||
| 					   byte(Instruction::POP), | ||||
| 					   byte(Instruction::DUP2), | ||||
| 					   byte(Instruction::JUMPDEST)}); | ||||
| 	BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); | ||||
| } | ||||
| 
 | ||||
| @ -457,7 +457,7 @@ BOOST_AUTO_TEST_CASE(negative_literals_8bits) | ||||
| 							 "}\n"; | ||||
| 	bytes code = compileFirstExpression(sourceCode); | ||||
| 
 | ||||
| 	bytes expectation(bytes({byte(eth::Instruction::PUSH32)}) + bytes(31, 0xff) + bytes(1, 0x80)); | ||||
| 	bytes expectation(bytes({byte(Instruction::PUSH32)}) + bytes(31, 0xff) + bytes(1, 0x80)); | ||||
| 	BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); | ||||
| } | ||||
| 
 | ||||
| @ -468,7 +468,7 @@ BOOST_AUTO_TEST_CASE(negative_literals_16bits) | ||||
| 							 "}\n"; | ||||
| 	bytes code = compileFirstExpression(sourceCode); | ||||
| 
 | ||||
| 	bytes expectation(bytes({byte(eth::Instruction::PUSH32)}) + bytes(30, 0xff) + bytes{0xf5, 0x43}); | ||||
| 	bytes expectation(bytes({byte(Instruction::PUSH32)}) + bytes(30, 0xff) + bytes{0xf5, 0x43}); | ||||
| 	BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); | ||||
| } | ||||
| 
 | ||||
| @ -481,7 +481,7 @@ BOOST_AUTO_TEST_CASE(intermediately_overflowing_literals) | ||||
| 							 "}\n"; | ||||
| 	bytes code = compileFirstExpression(sourceCode); | ||||
| 
 | ||||
| 	bytes expectation(bytes({byte(eth::Instruction::PUSH1), 0xbf})); | ||||
| 	bytes expectation(bytes({byte(Instruction::PUSH1), 0xbf})); | ||||
| 	BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); | ||||
| } | ||||
| 
 | ||||
| @ -495,8 +495,8 @@ BOOST_AUTO_TEST_CASE(blockhash) | ||||
| 	bytes code = compileFirstExpression(sourceCode, {}, {}, | ||||
| 										{make_shared<MagicVariableDeclaration>("block", make_shared<MagicType>(MagicType::Kind::Block))}); | ||||
| 
 | ||||
| 	bytes expectation({byte(eth::Instruction::PUSH1), 0x03, | ||||
| 					   byte(eth::Instruction::BLOCKHASH)}); | ||||
| 	bytes expectation({byte(Instruction::PUSH1), 0x03, | ||||
| 					   byte(Instruction::BLOCKHASH)}); | ||||
| 	BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -58,11 +58,11 @@ public: | ||||
| 		m_optimize = true; | ||||
| 		bytes optimizedBytecode = compileAndRun(_sourceCode, _value, _contractName); | ||||
| 		size_t nonOptimizedSize = 0; | ||||
| 		eth::eachInstruction(nonOptimizedBytecode, [&](Instruction, u256 const&) { | ||||
| 		solidity::eachInstruction(nonOptimizedBytecode, [&](Instruction, u256 const&) { | ||||
| 			nonOptimizedSize++; | ||||
| 		}); | ||||
| 		size_t optimizedSize = 0; | ||||
| 		eth::eachInstruction(optimizedBytecode, [&](Instruction, u256 const&) { | ||||
| 		solidity::eachInstruction(optimizedBytecode, [&](Instruction, u256 const&) { | ||||
| 			optimizedSize++; | ||||
| 		}); | ||||
| 		BOOST_CHECK_MESSAGE( | ||||
| @ -308,8 +308,8 @@ BOOST_AUTO_TEST_CASE(retain_information_in_branches) | ||||
| 	m_optimize = true; | ||||
| 	bytes optimizedBytecode = compileAndRun(sourceCode, 0, "c"); | ||||
| 	size_t numSHA3s = 0; | ||||
| 	eth::eachInstruction(optimizedBytecode, [&](Instruction _instr, u256 const&) { | ||||
| 		if (_instr == eth::Instruction::SHA3) | ||||
| 	eachInstruction(optimizedBytecode, [&](Instruction _instr, u256 const&) { | ||||
| 		if (_instr == Instruction::SHA3) | ||||
| 			numSHA3s++; | ||||
| 	}); | ||||
| 	BOOST_CHECK_EQUAL(1, numSHA3s); | ||||
| @ -351,8 +351,8 @@ BOOST_AUTO_TEST_CASE(store_tags_as_unions) | ||||
| 	m_optimize = true; | ||||
| 	bytes optimizedBytecode = compileAndRun(sourceCode, 0, "test"); | ||||
| 	size_t numSHA3s = 0; | ||||
| 	eth::eachInstruction(optimizedBytecode, [&](Instruction _instr, u256 const&) { | ||||
| 		if (_instr == eth::Instruction::SHA3) | ||||
| 	eachInstruction(optimizedBytecode, [&](Instruction _instr, u256 const&) { | ||||
| 		if (_instr == Instruction::SHA3) | ||||
| 			numSHA3s++; | ||||
| 	}); | ||||
| // TEST DISABLED UNTIL 93693404 IS IMPLEMENTED
 | ||||
| @ -1071,16 +1071,16 @@ BOOST_AUTO_TEST_CASE(block_deduplicator) | ||||
| 		AssemblyItem(PushTag, 1), | ||||
| 		AssemblyItem(PushTag, 3), | ||||
| 		u256(6), | ||||
| 		eth::Instruction::SWAP3, | ||||
| 		eth::Instruction::JUMP, | ||||
| 		Instruction::SWAP3, | ||||
| 		Instruction::JUMP, | ||||
| 		AssemblyItem(Tag, 1), | ||||
| 		u256(6), | ||||
| 		eth::Instruction::SWAP3, | ||||
| 		eth::Instruction::JUMP, | ||||
| 		Instruction::SWAP3, | ||||
| 		Instruction::JUMP, | ||||
| 		AssemblyItem(Tag, 2), | ||||
| 		u256(6), | ||||
| 		eth::Instruction::SWAP3, | ||||
| 		eth::Instruction::JUMP, | ||||
| 		Instruction::SWAP3, | ||||
| 		Instruction::JUMP, | ||||
| 		AssemblyItem(Tag, 3) | ||||
| 	}; | ||||
| 	BlockDeduplicator dedup(input); | ||||
| @ -1097,23 +1097,23 @@ BOOST_AUTO_TEST_CASE(block_deduplicator_loops) | ||||
| { | ||||
| 	AssemblyItems input{ | ||||
| 		u256(0), | ||||
| 		eth::Instruction::SLOAD, | ||||
| 		Instruction::SLOAD, | ||||
| 		AssemblyItem(PushTag, 1), | ||||
| 		AssemblyItem(PushTag, 2), | ||||
| 		eth::Instruction::JUMPI, | ||||
| 		eth::Instruction::JUMP, | ||||
| 		Instruction::JUMPI, | ||||
| 		Instruction::JUMP, | ||||
| 		AssemblyItem(Tag, 1), | ||||
| 		u256(5), | ||||
| 		u256(6), | ||||
| 		eth::Instruction::SSTORE, | ||||
| 		Instruction::SSTORE, | ||||
| 		AssemblyItem(PushTag, 1), | ||||
| 		eth::Instruction::JUMP, | ||||
| 		Instruction::JUMP, | ||||
| 		AssemblyItem(Tag, 2), | ||||
| 		u256(5), | ||||
| 		u256(6), | ||||
| 		eth::Instruction::SSTORE, | ||||
| 		Instruction::SSTORE, | ||||
| 		AssemblyItem(PushTag, 2), | ||||
| 		eth::Instruction::JUMP, | ||||
| 		Instruction::JUMP, | ||||
| 	}; | ||||
| 	BlockDeduplicator dedup(input); | ||||
| 	dedup.deduplicate(); | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user