forked from ethereum/solidity
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Initial EVM1.5 assembly implementation.
- Loading branch information
Showing
20 changed files
with
857 additions
and
139 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,174 @@ | ||
/* | ||
This file is part of solidity. | ||
solidity 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. | ||
solidity 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 solidity. If not, see <http://www.gnu.org/licenses/>. | ||
*/ | ||
/** | ||
* Assembly interface for EVM and EVM1.5. | ||
*/ | ||
|
||
#include <libjulia/backends/evm/EVMAssembly.h> | ||
|
||
#include <libevmasm/Instruction.h> | ||
|
||
#include <libsolidity/interface/Utils.h> | ||
|
||
using namespace std; | ||
using namespace dev; | ||
using namespace julia; | ||
|
||
namespace | ||
{ | ||
size_t constexpr labelReferenceSize = 4; | ||
} | ||
|
||
|
||
void EVMAssembly::setSourceLocation(SourceLocation const&) | ||
{ | ||
// Ignored for now; | ||
} | ||
|
||
void EVMAssembly::appendInstruction(solidity::Instruction _instr) | ||
{ | ||
m_bytecode.push_back(byte(_instr)); | ||
m_stackHeight += solidity::instructionInfo(_instr).ret - solidity::instructionInfo(_instr).args; | ||
} | ||
|
||
void EVMAssembly::appendConstant(u256 const& _constant) | ||
{ | ||
bytes data = toCompactBigEndian(_constant, 1); | ||
appendInstruction(solidity::pushInstruction(data.size())); | ||
m_bytecode += data; | ||
} | ||
|
||
void EVMAssembly::appendLabel(LabelID _labelId) | ||
{ | ||
setLabelToCurrentPosition(_labelId); | ||
appendInstruction(solidity::Instruction::JUMPDEST); | ||
} | ||
|
||
void EVMAssembly::appendLabelReference(LabelID _labelId) | ||
{ | ||
solAssert(!m_evm15, "Cannot use plain label references in EMV1.5 mode."); | ||
// @TODO we now always use labelReferenceSize for all labels, it could be shortened | ||
// for some of them. | ||
appendInstruction(solidity::pushInstruction(labelReferenceSize)); | ||
m_labelReferences[m_bytecode.size()] = _labelId; | ||
m_bytecode += bytes(labelReferenceSize); | ||
} | ||
|
||
EVMAssembly::LabelID EVMAssembly::newLabelId() | ||
{ | ||
m_labelPositions[m_nextLabelID] = size_t(-1); | ||
return m_nextLabelID++; | ||
} | ||
|
||
void EVMAssembly::appendLinkerSymbol(string const&) | ||
{ | ||
solAssert(false, "Linker symbols not yet implemented."); | ||
} | ||
|
||
void EVMAssembly::appendJump(int _stackDiffAfter) | ||
{ | ||
solAssert(!m_evm15, "Plain JUMP used for EVM 1.5"); | ||
appendInstruction(solidity::Instruction::JUMP); | ||
m_stackHeight += _stackDiffAfter; | ||
} | ||
|
||
void EVMAssembly::appendJumpTo(AbstractAssembly::LabelID _labelId, int _stackDiffAfter) | ||
{ | ||
if (m_evm15) | ||
{ | ||
m_bytecode.push_back(byte(solidity::Instruction::JUMPTO)); | ||
appendLabelReferenceInternal(_labelId); | ||
m_stackHeight += _stackDiffAfter; | ||
} | ||
else | ||
{ | ||
appendLabelReference(_labelId); | ||
appendJump(_stackDiffAfter); | ||
} | ||
} | ||
|
||
void EVMAssembly::appendJumpToIf(AbstractAssembly::LabelID _labelId) | ||
{ | ||
if (m_evm15) | ||
{ | ||
m_bytecode.push_back(byte(solidity::Instruction::JUMPIF)); | ||
appendLabelReferenceInternal(_labelId); | ||
m_stackHeight--; | ||
} | ||
else | ||
{ | ||
appendLabelReference(_labelId); | ||
appendInstruction(solidity::Instruction::JUMPI); | ||
} | ||
} | ||
|
||
void EVMAssembly::appendBeginsub(AbstractAssembly::LabelID _labelId, int _arguments) | ||
{ | ||
solAssert(m_evm15, "BEGINSUB used for EVM 1.0"); | ||
solAssert(_arguments >= 0, ""); | ||
setLabelToCurrentPosition(_labelId); | ||
m_bytecode.push_back(byte(solidity::Instruction::BEGINSUB)); | ||
m_stackHeight += _arguments; | ||
} | ||
|
||
void EVMAssembly::appendJumpsub(AbstractAssembly::LabelID _labelId, int _arguments, int _returns) | ||
{ | ||
solAssert(m_evm15, "JUMPSUB used for EVM 1.0"); | ||
solAssert(_arguments >= 0 && _returns >= 0, ""); | ||
m_bytecode.push_back(byte(solidity::Instruction::JUMPSUB)); | ||
appendLabelReferenceInternal(_labelId); | ||
m_stackHeight += _returns - _arguments; | ||
} | ||
|
||
void EVMAssembly::appendReturnsub(int _returns) | ||
{ | ||
solAssert(m_evm15, "RETURNSUB used for EVM 1.0"); | ||
solAssert(_returns >= 0, ""); | ||
m_bytecode.push_back(byte(solidity::Instruction::RETURNSUB)); | ||
m_stackHeight -= _returns; | ||
} | ||
|
||
eth::LinkerObject EVMAssembly::finalize() | ||
{ | ||
for (auto const& ref: m_labelReferences) | ||
{ | ||
size_t referencePos = ref.first; | ||
solAssert(m_labelPositions.count(ref.second), ""); | ||
size_t labelPos = m_labelPositions.at(ref.second); | ||
solAssert(labelPos != size_t(-1), "Undefined but allocated label used."); | ||
solAssert(m_bytecode.size() >= 4 && referencePos <= m_bytecode.size() - 4, ""); | ||
solAssert(labelPos < (uint64_t(1) << (8 * labelReferenceSize)), ""); | ||
for (size_t i = 0; i < labelReferenceSize; i++) | ||
m_bytecode[referencePos + i] = byte((labelPos >> (8 * (labelReferenceSize - i - 1))) & 0xff); | ||
} | ||
eth::LinkerObject obj; | ||
obj.bytecode = m_bytecode; | ||
return obj; | ||
} | ||
|
||
void EVMAssembly::setLabelToCurrentPosition(AbstractAssembly::LabelID _labelId) | ||
{ | ||
solAssert(m_labelPositions.count(_labelId), "Label not found."); | ||
solAssert(m_labelPositions[_labelId] == size_t(-1), "Label already set."); | ||
m_labelPositions[_labelId] = m_bytecode.size(); | ||
} | ||
|
||
void EVMAssembly::appendLabelReferenceInternal(AbstractAssembly::LabelID _labelId) | ||
{ | ||
m_labelReferences[m_bytecode.size()] = _labelId; | ||
m_bytecode += bytes(labelReferenceSize); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
/* | ||
This file is part of solidity. | ||
solidity 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. | ||
solidity 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 solidity. If not, see <http://www.gnu.org/licenses/>. | ||
*/ | ||
/** | ||
* Assembly interface for EVM and EVM1.5. | ||
*/ | ||
|
||
#pragma once | ||
|
||
#include <libjulia/backends/evm/AbstractAssembly.h> | ||
|
||
#include <libevmasm/LinkerObject.h> | ||
|
||
#include <map> | ||
|
||
namespace dev | ||
{ | ||
namespace julia | ||
{ | ||
|
||
class EVMAssembly: public AbstractAssembly | ||
{ | ||
public: | ||
explicit EVMAssembly(bool _evm15 = false): m_evm15(_evm15) { } | ||
virtual ~EVMAssembly() {} | ||
|
||
/// Set a new source location valid starting from the next instruction. | ||
virtual void setSourceLocation(SourceLocation const& _location) override; | ||
/// Retrieve the current height of the stack. This does not have to be zero | ||
/// at the beginning. | ||
virtual int stackHeight() const override { return m_stackHeight; } | ||
/// Append an EVM instruction. | ||
virtual void appendInstruction(solidity::Instruction _instruction) override; | ||
/// Append a constant. | ||
virtual void appendConstant(u256 const& _constant) override; | ||
/// Append a label. | ||
virtual void appendLabel(LabelID _labelId) override; | ||
/// Append a label reference. | ||
virtual void appendLabelReference(LabelID _labelId) override; | ||
/// Generate a new unique label. | ||
virtual LabelID newLabelId() override; | ||
/// Append a reference to a to-be-linked symobl. | ||
/// Currently, we assume that the value is always a 20 byte number. | ||
virtual void appendLinkerSymbol(std::string const& _name) override; | ||
|
||
/// Append a jump instruction. | ||
/// @param _stackDiffAfter the stack adjustment after this instruction. | ||
virtual void appendJump(int _stackDiffAfter) override; | ||
/// Append a jump-to-immediate operation. | ||
virtual void appendJumpTo(LabelID _label, int _stackDiffAfter) override; | ||
/// Append a jump-to-if-immediate operation. | ||
virtual void appendJumpToIf(LabelID _label) override; | ||
/// Start a subroutine. | ||
virtual void appendBeginsub(LabelID _label, int _arguments) override; | ||
/// Call a subroutine. | ||
virtual void appendJumpsub(LabelID _label, int _arguments, int _returns) override; | ||
/// Return from a subroutine. | ||
virtual void appendReturnsub(int _returns) override; | ||
|
||
|
||
/// Resolves references inside the bytecode and returns the linker object. | ||
eth::LinkerObject finalize(); | ||
|
||
private: | ||
void setLabelToCurrentPosition(AbstractAssembly::LabelID _labelId); | ||
void appendLabelReferenceInternal(AbstractAssembly::LabelID _labelId); | ||
|
||
bool m_evm15 = false; ///< if true, switch to evm1.5 mode | ||
LabelID m_nextLabelID = 0; | ||
int m_stackHeight = 0; | ||
bytes m_bytecode; | ||
std::map<LabelID, size_t> m_labelPositions; | ||
std::map<size_t, LabelID> m_labelReferences; | ||
}; | ||
|
||
} | ||
} |
Oops, something went wrong.