diff options
author | Gav Wood <i@gavwood.com> | 2014-05-27 01:41:46 +0800 |
---|---|---|
committer | Gav Wood <i@gavwood.com> | 2014-05-27 01:41:46 +0800 |
commit | 51e6c251641eef12ba93b725974faa35b514d636 (patch) | |
tree | 9113f63687347c7d5a61c5bb2db61ffe4d800da4 | |
parent | 8e3e592ec6a3b39835e540766774025e3f34c590 (diff) | |
download | dexon-solidity-51e6c251641eef12ba93b725974faa35b514d636.tar.gz dexon-solidity-51e6c251641eef12ba93b725974faa35b514d636.tar.zst dexon-solidity-51e6c251641eef12ba93b725974faa35b514d636.zip |
New Assembler.
-rw-r--r-- | Assembly.cpp | 175 | ||||
-rw-r--r-- | Assembly.h | 54 | ||||
-rw-r--r-- | CodeFragment.cpp | 338 | ||||
-rw-r--r-- | CodeFragment.h | 51 | ||||
-rw-r--r-- | CodeLocation.cpp | 59 | ||||
-rw-r--r-- | CodeLocation.h | 54 | ||||
-rw-r--r-- | Compiler.cpp | 27 | ||||
-rw-r--r-- | Compiler.h | 3 |
8 files changed, 357 insertions, 404 deletions
diff --git a/Assembly.cpp b/Assembly.cpp index a8491376..1f53cfb5 100644 --- a/Assembly.cpp +++ b/Assembly.cpp @@ -26,38 +26,201 @@ using namespace std; using namespace eth; +int AssemblyItem::deposit() const +{ + switch (m_type) + { + case Operation: + return c_instructionInfo.at((Instruction)(byte)m_data).ret - c_instructionInfo.at((Instruction)(byte)m_data).args; + case Push: case PushString: case PushTag: case PushData: + return 1; + case Tag: + return 0; + } + assert(false); +} + +unsigned Assembly::bytesRequired() const +{ + for (unsigned br = 1;; ++br) + { + unsigned ret = 1; + for (auto const& i: m_data) + ret += i.second.size(); + + for (AssemblyItem const& i: m_items) + switch (i.m_type) + { + case Operation: + ret++; + break; + case PushString: + ret += 33; + break; + case Push: + ret += 1 + max<unsigned>(1, eth::bytesRequired(i.m_data)); + break; + case PushTag: + case PushData: + ret += 1 + br; + case Tag:; + } + if (eth::bytesRequired(ret) <= br) + return ret; + } +} + void Assembly::append(Assembly const& _a) { for (AssemblyItem i: _a.m_items) { if (i.type() == Tag || i.type() == PushTag) i.m_data += m_usedTags; - m_items.push_back(i); + append(i); } + m_usedTags += _a.m_usedTags; for (auto const& i: _a.m_data) m_data.insert(i); + for (auto const& i: _a.m_strings) + m_strings.insert(i); + + assert(!_a.m_baseDeposit); + assert(!_a.m_totalDeposit); +} + +void Assembly::append(Assembly const& _a, int _deposit) +{ + if (_deposit > _a.m_deposit) + throw InvalidDeposit(); + else + { + append(_a); + while (_deposit++ < _a.m_deposit) + append(Instruction::POP); + } } ostream& Assembly::streamOut(ostream& _out) const { + _out << ".code:" << endl; for (AssemblyItem const& i: m_items) switch (i.m_type) { case Operation: - _out << c_instructionInfo.at((Instruction)(byte)i.m_data).name << endl; + _out << " " << c_instructionInfo.at((Instruction)(byte)i.m_data).name << endl; break; case Push: - _out << i.m_data << endl; + _out << " PUSH " << i.m_data << endl; + break; + case PushString: + _out << " PUSH \"" << m_strings.at((h256)i.m_data) << "\"" << endl; + break; + case PushTag: + _out << " PUSH [tag" << i.m_data << "]" << endl; + break; + case Tag: + _out << "tag" << i.m_data << ": " << endl; + break; + case PushData: + _out << " PUSH [" << h256(i.m_data).abridged() << "]" << endl; break; -/* case PushString: - _out << i.m_data << endl; - break;*/ } + + if (m_data.size()) + { + _out << ".data:" << endl; + for (auto const& i: m_data) + _out << " " << i.first.abridged() << ": " << toHex(i.second) << endl; + } return _out; } +AssemblyItem const& Assembly::append(AssemblyItem const& _i) +{ + m_deposit += _i.deposit(); + m_items.push_back(_i); + return back(); +} + bytes Assembly::assemble() const { bytes ret; + + unsigned totalBytes = bytesRequired(); + ret.reserve(totalBytes); + vector<unsigned> tagPos(m_usedTags); + map<unsigned, unsigned> tagRef; + multimap<h256, unsigned> dataRef; + unsigned bytesPerTag = eth::bytesRequired(totalBytes); + byte tagPush = (byte)Instruction::PUSH1 - 1 + bytesPerTag; + + for (AssemblyItem const& i: m_items) + switch (i.m_type) + { + case Operation: + ret.push_back((byte)i.m_data); + break; + case PushString: + { + ret.push_back((byte)Instruction::PUSH32); + unsigned ii = 0; + for (auto j: m_strings.at((h256)i.m_data)) + if (++ii > 32) + break; + else + ret.push_back((byte)j); + while (ii++ < 32) + ret.push_back(0); + break; + } + case Push: + { + byte b = max<unsigned>(1, eth::bytesRequired(i.m_data)); + ret.push_back((byte)Instruction::PUSH1 - 1 + b); + ret.resize(ret.size() + b); + bytesRef byr(&ret.back() + 1 - b, b); + toBigEndian(i.m_data, byr); + break; + } + case PushTag: + { + ret.push_back(tagPush); + tagRef[ret.size()] = (unsigned)i.m_data; + ret.resize(ret.size() + bytesPerTag); + break; + } + case PushData: + { + ret.push_back(tagPush); + dataRef.insert(make_pair((h256)i.m_data, ret.size())); + ret.resize(ret.size() + bytesPerTag); + break; + } + case Tag: + tagPos[(unsigned)i.m_data] = ret.size(); + break; + } + + for (auto const& i: tagRef) + { + bytesRef r(ret.data() + i.first, bytesPerTag); + toBigEndian(tagPos[i.second], r); + } + + if (m_data.size()) + { + ret.push_back(0); + for (auto const& i: m_data) + { + auto its = dataRef.equal_range(i.first); + for (auto it = its.first; it != its.second; ++it) + { + bytesRef r(ret.data() + it->second, bytesPerTag); + toBigEndian(ret.size(), r); + } + for (auto b: i.second) + ret.push_back(b); + } + } return ret; } @@ -22,6 +22,7 @@ #pragma once #include <iostream> +#include <sstream> #include <libethsupport/Common.h> #include <libethcore/Instruction.h> #include "Exceptions.h" @@ -39,14 +40,16 @@ class AssemblyItem public: AssemblyItem(u256 _push): m_type(Push), m_data(_push) {} - AssemblyItem(AssemblyItemType _type, AssemblyItem const& _tag): m_type(_type), m_data(_tag.m_data) { assert(_type == PushTag); assert(_tag.m_type == Tag); } AssemblyItem(Instruction _i): m_type(Operation), m_data((byte)_i) {} AssemblyItem(AssemblyItemType _type, u256 _data): m_type(_type), m_data(_data) {} + AssemblyItem tag() const { assert(m_type == PushTag || m_type == Tag); return AssemblyItem(Tag, m_data); } + AssemblyItem pushTag() const { assert(m_type == PushTag || m_type == Tag); return AssemblyItem(PushTag, m_data); } + AssemblyItemType type() const { return m_type; } u256 data() const { return m_data; } - std::ostream& streamOut(std::ostream& _out) const; + int deposit() const; private: AssemblyItemType m_type; @@ -57,19 +60,58 @@ class Assembly { public: AssemblyItem newTag() { return AssemblyItem(Tag, m_usedTags++); } + AssemblyItem newPushTag() { return AssemblyItem(PushTag, m_usedTags++); } AssemblyItem newData(bytes const& _data) { auto h = sha3(_data); m_data[h] = _data; return AssemblyItem(PushData, h); } - AssemblyItem newPushString(std::string const& _data) { auto b = asBytes(_data); auto h = sha3(b); m_data[h] = b; return AssemblyItem(PushString, h); } + AssemblyItem newPushString(std::string const& _data) { auto h = sha3(_data); m_strings[h] = _data; return AssemblyItem(PushString, h); } + + AssemblyItem append() { return append(newTag()); } + void append(Assembly const& _a); + void append(Assembly const& _a, int _deposit); + AssemblyItem const& append(AssemblyItem const& _i); + AssemblyItem const& append(std::string const& _data) { return append(newPushString(_data)); } + AssemblyItem const& append(bytes const& _data) { return append(newData(_data)); } + + 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; } + + template <class T> Assembly& operator<<(T const& _d) { append(_d); return *this; } + + AssemblyItem const& back() { return m_items.back(); } + std::string backString() const { return m_items.back().m_type == PushString ? m_strings.at((h256)m_items.back().m_data) : std::string(); } - void append(AssemblyItem const& _i) { m_items.push_back(_i); } + void onePath() { assert(!m_totalDeposit && !m_baseDeposit); m_baseDeposit = m_deposit; m_totalDeposit = INT_MAX; } + void otherPath() { donePath(); m_totalDeposit = m_deposit; m_deposit = m_baseDeposit; } + void donePaths() { donePath(); m_totalDeposit = m_baseDeposit = 0; } + 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); } + + std::string out() const { std::stringstream ret; streamOut(ret); return ret.str(); } + int deposit() const { return m_deposit; } bytes assemble() const; - void append(Assembly const& _a); std::ostream& streamOut(std::ostream& _out) const; private: - u256 m_usedTags = 0; + void donePath() { if (m_totalDeposit != INT_MAX && m_totalDeposit != m_deposit) throw InvalidDeposit(); } + unsigned bytesRequired() const; + + unsigned m_usedTags = 0; std::vector<AssemblyItem> m_items; std::map<h256, bytes> m_data; + std::map<h256, std::string> m_strings; + + int m_deposit = 0; + int m_baseDeposit = 0; + int m_totalDeposit = 0; }; +inline std::ostream& operator<<(std::ostream& _out, Assembly const& _a) +{ + _a.streamOut(_out); + return _out; +} + } diff --git a/CodeFragment.cpp b/CodeFragment.cpp index c4b7ae0b..59ff729e 100644 --- a/CodeFragment.cpp +++ b/CodeFragment.cpp @@ -34,100 +34,6 @@ namespace qi = boost::spirit::qi; namespace px = boost::phoenix; namespace sp = boost::spirit; -void CodeFragment::appendFragment(CodeFragment const& _f) -{ - m_locs.reserve(m_locs.size() + _f.m_locs.size()); - m_code.reserve(m_code.size() + _f.m_code.size()); - - unsigned os = m_code.size(); - - for (auto i: _f.m_code) - m_code.push_back(i); - - for (auto i: _f.m_locs) - { - CodeLocation(this, i + os).increase(os); - m_locs.push_back(i + os); - } - - for (auto i: _f.m_data) - m_data.insert(make_pair(i.first, i.second + os)); - - m_deposit += _f.m_deposit; -} - -CodeFragment CodeFragment::compile(string const& _src, CompilerState& _s) -{ - CodeFragment ret; - sp::utree o; - parseTreeLLL(_src, o); - if (!o.empty()) - ret = CodeFragment(o, _s); - _s.treesToKill.push_back(o); - return ret; -} - -void CodeFragment::consolidateData() -{ - m_code.push_back(0); - bytes ld; - for (auto const& i: m_data) - { - if (ld != i.first) - { - ld = i.first; - for (auto j: ld) - m_code.push_back(j); - } - CodeLocation(this, i.second).set(m_code.size() - ld.size()); - } - m_data.clear(); -} - -void CodeFragment::appendFragment(CodeFragment const& _f, unsigned _deposit) -{ - if ((int)_deposit > _f.m_deposit) - error<InvalidDeposit>(); - else - { - appendFragment(_f); - while (_deposit++ < (unsigned)_f.m_deposit) - appendInstruction(Instruction::POP); - } -} - -CodeLocation CodeFragment::appendPushLocation(unsigned _locationValue) -{ - m_code.push_back((byte)Instruction::PUSH4); - CodeLocation ret(this, m_code.size()); - m_locs.push_back(m_code.size()); - m_code.resize(m_code.size() + 4); - bytesRef r(&m_code[m_code.size() - 4], 4); - toBigEndian(_locationValue, r); - m_deposit++; - return ret; -} - -unsigned CodeFragment::appendPush(u256 _literalValue) -{ - unsigned br = max<unsigned>(1, bytesRequired(_literalValue)); - m_code.push_back((byte)Instruction::PUSH1 + br - 1); - m_code.resize(m_code.size() + br); - for (unsigned i = 0; i < br; ++i) - { - m_code[m_code.size() - 1 - i] = (byte)(_literalValue & 0xff); - _literalValue >>= 8; - } - m_deposit++; - return br + 1; -} - -void CodeFragment::appendInstruction(Instruction _i) -{ - m_code.push_back((byte)_i); - m_deposit += c_instructionInfo.at(_i).ret - c_instructionInfo.at(_i).args; -} - CodeFragment::CodeFragment(sp::utree const& _t, CompilerState& _s, bool _allowASM) { /* cdebug << "CodeFragment. Locals:"; @@ -151,12 +57,7 @@ CodeFragment::CodeFragment(sp::utree const& _t, CompilerState& _s, bool _allowAS { auto sr = _t.get<sp::basic_string<boost::iterator_range<char const*>, sp::utree_type::string_type>>(); string s(sr.begin(), sr.end()); - if (s.size() > 32) - error<StringTooLong>(); - h256 valHash; - memcpy(valHash.data(), s.data(), s.size()); - memset(valHash.data() + s.size(), 0, 32 - s.size()); - appendPush(valHash); + m_asm.append(s); break; } case sp::utree_type::symbol_type: @@ -164,21 +65,14 @@ CodeFragment::CodeFragment(sp::utree const& _t, CompilerState& _s, bool _allowAS auto sr = _t.get<sp::basic_string<boost::iterator_range<char const*>, sp::utree_type::symbol_type>>(); string s(sr.begin(), sr.end()); string us = boost::algorithm::to_upper_copy(s); - if (_allowASM) - { - if (c_instructions.count(us)) - { - auto it = c_instructions.find(us); - m_deposit = c_instructionInfo.at(it->second).ret - c_instructionInfo.at(it->second).args; - m_code.push_back((byte)it->second); - } - } + if (_allowASM && c_instructions.count(us)) + m_asm.append(c_instructions.at(us)); if (_s.defs.count(s)) - appendFragment(_s.defs.at(s)); + m_asm.append(_s.defs.at(s).m_asm); else if (_s.args.count(s)) - appendFragment(_s.args.at(s)); + m_asm.append(_s.args.at(s).m_asm); else if (_s.outers.count(s)) - appendFragment(_s.outers.at(s)); + m_asm.append(_s.outers.at(s).m_asm); else if (us.find_first_of("1234567890") != 0 && us.find_first_not_of("QWERTYUIOPASDFGHJKLZXCVBNM1234567890_") == string::npos) { auto it = _s.vars.find(s); @@ -187,7 +81,7 @@ CodeFragment::CodeFragment(sp::utree const& _t, CompilerState& _s, bool _allowAS bool ok; tie(it, ok) = _s.vars.insert(make_pair(s, _s.vars.size() * 32)); } - appendPush(it->second); + m_asm.append((u256)it->second); } else error<BareSymbol>(); @@ -199,44 +93,13 @@ CodeFragment::CodeFragment(sp::utree const& _t, CompilerState& _s, bool _allowAS bigint i = *_t.get<bigint*>(); if (i < 0 || i > bigint(u256(0) - 1)) error<IntegerOutOfRange>(); - appendPush((u256)i); + m_asm.append((u256)i); break; } default: break; } } -void CodeFragment::appendPushDataLocation(bytes const& _data) -{ - m_code.push_back((byte)Instruction::PUSH4); - m_data.insert(make_pair(_data, m_code.size())); - m_code.resize(m_code.size() + 4); - memset(&m_code.back() - 3, 0, 4); - m_deposit++; -} - -std::string CodeFragment::asPushedString() const -{ - string ret; - if (m_code.size()) - { - unsigned bc = m_code[0] - (byte)Instruction::PUSH1 + 1; - if (m_code[0] >= (byte)Instruction::PUSH1 && m_code[0] <= (byte)Instruction::PUSH32) - { - for (unsigned s = 0; s < bc && m_code[1 + s]; ++s) - ret.push_back(m_code[1 + s]); - return ret; - } - } - error<ExpectedLiteral>(); - return ret; -} - -void CodeFragment::optimise() -{ -// map<string, function<bytes(vector<u256> const&)>> pattern = { { "PUSH,PUSH,ADD", [](vector<u256> const& v) { return CodeFragment(appendPush(v[0] + v[1])); } } }; -} - void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s) { if (_t.empty()) @@ -281,7 +144,7 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s) int c = 0; for (auto const& i: _t) if (c++) - appendFragment(CodeFragment(i, _s, true)); + m_asm.append(CodeFragment(i, _s, true).m_asm); } else if (us == "INCLUDE") { @@ -299,9 +162,9 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s) else if (i.which() == sp::utree_type::symbol_type) { auto sr = i.get<sp::basic_string<boost::iterator_range<char const*>, sp::utree_type::symbol_type>>(); - n = _s.getDef(string(sr.begin(), sr.end())).asPushedString(); + n = _s.getDef(string(sr.begin(), sr.end())).m_asm.backString(); } - appendFragment(CodeFragment::compile(asString(contents(n)), _s)); + m_asm.append(CodeFragment::compile(asString(contents(n)), _s).m_asm); } else if (us == "DEF") { @@ -323,7 +186,7 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s) else if (i.which() == sp::utree_type::symbol_type) { auto sr = i.get<sp::basic_string<boost::iterator_range<char const*>, sp::utree_type::symbol_type>>(); - n = _s.getDef(string(sr.begin(), sr.end())).asPushedString(); + n = _s.getDef(string(sr.begin(), sr.end())).m_asm.backString(); } } else if (ii == 2) @@ -362,7 +225,7 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s) if (ii == 1) { pos = CodeFragment(i, _s); - if (pos.m_deposit != 1) + if (pos.m_asm.deposit() != 1) error<InvalidDeposit>(); } else if (ii == 2 && !i.tag() && i.which() == sp::utree_type::string_type) @@ -396,11 +259,11 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s) error<InvalidLiteral>(); ++ii; } - appendPush(data.size()); - appendInstruction(Instruction::DUP); - appendPushDataLocation(data); - appendFragment(pos, 1); - appendInstruction(Instruction::CODECOPY); + m_asm.append((u256)data.size()); + m_asm.append(Instruction::DUP); + m_asm.append(data); + m_asm.append(pos.m_asm, 1); + m_asm.append(Instruction::CODECOPY); } else nonStandard = false; @@ -427,7 +290,7 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s) auto requireSize = [&](unsigned s) { if (code.size() != s) error<IncorrectParameterCount>(); }; auto requireMinSize = [&](unsigned s) { if (code.size() < s) error<IncorrectParameterCount>(); }; auto requireMaxSize = [&](unsigned s) { if (code.size() > s) error<IncorrectParameterCount>(); }; - auto requireDeposit = [&](unsigned i, int s) { if (code[i].m_deposit != s) error<InvalidDeposit>(); }; + auto requireDeposit = [&](unsigned i, int s) { if (code[i].m_asm.deposit() != s) error<InvalidDeposit>(); }; if (_s.macros.count(s) && _s.macros.at(s).args.size() == code.size()) { @@ -443,7 +306,7 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s) requireDeposit(i, 1); cs.args[m.args[i]] = code[i]; } - appendFragment(CodeFragment(m.code, cs)); + m_asm.append(CodeFragment(m.code, cs).m_asm); for (auto const& i: cs.defs) _s.defs[i.first] = i.second; for (auto const& i: cs.macros) @@ -459,8 +322,8 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s) requireMinSize(-ea); for (unsigned i = code.size(); i; --i) - appendFragment(code[i - 1], 1); - appendInstruction(it->second); + m_asm.append(code[i - 1].m_asm, 1); + m_asm.append(it->second); } else if (c_arith.count(us)) { @@ -469,10 +332,10 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s) for (unsigned i = code.size(); i; --i) { requireDeposit(i - 1, 1); - appendFragment(code[i - 1], 1); + m_asm.append(code[i - 1].m_asm, 1); } for (unsigned i = 1; i < code.size(); ++i) - appendInstruction(it->second); + m_asm.append(it->second); } else if (c_binary.count(us)) { @@ -480,74 +343,75 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s) requireSize(2); requireDeposit(0, 1); requireDeposit(1, 1); - appendFragment(code[1], 1); - appendFragment(code[0], 1); - appendInstruction(it->second.first); + m_asm.append(code[1].m_asm, 1); + m_asm.append(code[0].m_asm, 1); + m_asm.append(it->second.first); if (it->second.second) - appendInstruction(Instruction::NOT); + m_asm.append(Instruction::NOT); } else if (c_unary.count(us)) { auto it = c_unary.find(us); requireSize(1); requireDeposit(0, 1); - appendFragment(code[0], 1); - appendInstruction(it->second); + m_asm.append(code[0].m_asm, 1); + m_asm.append(it->second); } else if (us == "IF") { requireSize(3); requireDeposit(0, 1); - appendFragment(code[0]); - auto pos = appendJumpI(); - onePath(); - appendFragment(code[2]); - auto end = appendJump(); - otherPath(); - pos.anchor(); - appendFragment(code[1]); - donePaths(); - end.anchor(); + + m_asm.append(code[0].m_asm); + auto pos = m_asm.appendJumpI(); + m_asm.onePath(); + m_asm << code[2].m_asm; + auto end = m_asm.appendJump(); + m_asm.otherPath(); + m_asm << pos.tag() << code[1].m_asm << end.tag(); + m_asm.donePaths(); } else if (us == "WHEN" || us == "UNLESS") { requireSize(2); requireDeposit(0, 1); - appendFragment(code[0]); + + m_asm.append(code[0].m_asm); if (us == "WHEN") - appendInstruction(Instruction::NOT); - auto end = appendJumpI(); - onePath(); - otherPath(); - appendFragment(code[1], 0); - donePaths(); - end.anchor(); + m_asm.append(Instruction::NOT); + auto end = m_asm.appendJumpI(); + m_asm.onePath(); + m_asm.otherPath(); + m_asm << code[1].m_asm << end.tag(); + m_asm.donePaths(); } else if (us == "WHILE") { requireSize(2); requireDeposit(0, 1); - auto begin = CodeLocation(this); - appendFragment(code[0], 1); - appendInstruction(Instruction::NOT); - auto end = appendJumpI(); - appendFragment(code[1], 0); - appendJump(begin); - end.anchor(); + + auto begin = m_asm.append(); + m_asm.append(code[0].m_asm); + m_asm.append(Instruction::NOT); + auto end = m_asm.appendJumpI(); + m_asm.append(code[1].m_asm, 0); + m_asm.appendJump(begin); + m_asm << end.tag(); } else if (us == "FOR") { requireSize(4); requireDeposit(1, 1); - appendFragment(code[0], 0); - auto begin = CodeLocation(this); - appendFragment(code[1], 1); - appendInstruction(Instruction::NOT); - auto end = appendJumpI(); - appendFragment(code[3], 0); - appendFragment(code[2], 0); - appendJump(begin); - end.anchor(); + + m_asm.append(code[0].m_asm, 0); + auto begin = m_asm.append(); + m_asm.append(code[1].m_asm); + m_asm.append(Instruction::NOT); + auto end = m_asm.appendJumpI(); + m_asm.append(code[3].m_asm, 0); + m_asm.append(code[2].m_asm, 0); + m_asm.appendJump(begin); + m_asm << end.tag(); } else if (us == "LLL") { @@ -555,22 +419,22 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s) requireMaxSize(3); requireDeposit(1, 1); - CodeLocation codeloc(this, m_code.size() + 6); bytes const& subcode = code[0].code(); - appendPush(subcode.size()); - appendInstruction(Instruction::DUP); + + m_asm.append((u256)subcode.size()); + m_asm.append(Instruction::DUP); if (code.size() == 3) { requireDeposit(2, 1); - appendFragment(code[2], 1); - appendInstruction(Instruction::LT); - appendInstruction(Instruction::NOT); - appendInstruction(Instruction::MUL); - appendInstruction(Instruction::DUP); + m_asm.append(code[2].m_asm, 1); + m_asm.append(Instruction::LT); + m_asm.append(Instruction::NOT); + m_asm.append(Instruction::MUL); + m_asm.append(Instruction::DUP); } - appendPushDataLocation(subcode); - appendFragment(code[1], 1); - appendInstruction(Instruction::CODECOPY); + m_asm.append(subcode); + m_asm.append(code[1].m_asm, 1); + m_asm.append(Instruction::CODECOPY); } else if (us == "&&" || us == "||") { @@ -578,53 +442,52 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s) for (unsigned i = 0; i < code.size(); ++i) requireDeposit(i, 1); - vector<CodeLocation> ends; + auto end = m_asm.newTag(); if (code.size() > 1) { - appendPush(us == "||" ? 1 : 0); + m_asm.append((u256)(us == "||" ? 1 : 0)); for (unsigned i = 1; i < code.size(); ++i) { // Check if true - predicate - appendFragment(code[i - 1], 1); + m_asm.append(code[i - 1].m_asm, 1); if (us == "&&") - appendInstruction(Instruction::NOT); - ends.push_back(appendJumpI()); + m_asm.append(Instruction::NOT); + m_asm.appendJumpI(end); } - appendInstruction(Instruction::POP); + m_asm.append(Instruction::POP); } // Check if true - predicate - appendFragment(code.back(), 1); + m_asm.append(code.back().m_asm, 1); // At end now. - for (auto& i: ends) - i.anchor(); + m_asm.append(end); } else if (us == "~") { requireSize(1); requireDeposit(0, 1); - appendFragment(code[0], 1); - appendPush(1); - appendPush(0); - appendInstruction(Instruction::SUB); - appendInstruction(Instruction::SUB); + + m_asm.append(code[0].m_asm, 1); + m_asm.append((u256)1); + m_asm.append((u256)0); + m_asm.append(Instruction::SUB); + m_asm.append(Instruction::SUB); } else if (us == "SEQ") { unsigned ii = 0; for (auto const& i: code) if (++ii < code.size()) - appendFragment(i, 0); + m_asm.append(i.m_asm, 0); else - appendFragment(i); + m_asm.append(i.m_asm); } else if (us == "RAW") { for (auto const& i: code) - appendFragment(i); - while (m_deposit > 1) - appendInstruction(Instruction::POP); + m_asm.append(i.m_asm); + m_asm.popTo(1); } else if (us.find_first_of("1234567890") != 0 && us.find_first_not_of("QWERTYUIOPASDFGHJKLZXCVBNM1234567890_") == string::npos) { @@ -634,9 +497,20 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s) bool ok; tie(it, ok) = _s.vars.insert(make_pair(s, _s.vars.size() * 32)); } - appendPush(it->second); + m_asm.append((u256)it->second); } else error<InvalidOperation>(); } } + +CodeFragment CodeFragment::compile(string const& _src, CompilerState& _s) +{ + CodeFragment ret; + sp::utree o; + parseTreeLLL(_src, o); + if (!o.empty()) + ret = CodeFragment(o, _s); + _s.treesToKill.push_back(o); + return ret; +} diff --git a/CodeFragment.h b/CodeFragment.h index 9f312cda..64760484 100644 --- a/CodeFragment.h +++ b/CodeFragment.h @@ -23,7 +23,7 @@ #include <libethsupport/Common.h> #include <libethcore/Instruction.h> -#include "CodeLocation.h" +#include "Assembly.h" #include "Exceptions.h" namespace boost { namespace spirit { class utree; } } @@ -36,60 +36,23 @@ class CompilerState; class CodeFragment { - friend class CodeLocation; - public: + CodeFragment() {} CodeFragment(sp::utree const& _t, CompilerState& _s, bool _allowASM = false); - CodeFragment(bytes const& _c = bytes()): m_code(_c) {} static CodeFragment compile(std::string const& _src, CompilerState& _s); - /// Consolidates data and returns code. - bytes const& code() { optimise(); consolidateData(); return m_code; } - - unsigned appendPush(u256 _l); - void appendFragment(CodeFragment const& _f); - void appendFragment(CodeFragment const& _f, unsigned _i); - void appendInstruction(Instruction _i); - - CodeLocation appendPushLocation(unsigned _l = 0); - void appendPushLocation(CodeLocation _l) { assert(_l.m_f == this); appendPushLocation(_l.m_pos); } - void appendPushDataLocation(bytes const& _data); - - CodeLocation appendJump() { auto ret = appendPushLocation(0); appendInstruction(Instruction::JUMP); return ret; } - CodeLocation appendJumpI() { auto ret = appendPushLocation(0); appendInstruction(Instruction::JUMPI); return ret; } - CodeLocation appendJump(CodeLocation _l) { auto ret = appendPushLocation(_l.m_pos); appendInstruction(Instruction::JUMP); return ret; } - CodeLocation appendJumpI(CodeLocation _l) { auto ret = appendPushLocation(_l.m_pos); appendInstruction(Instruction::JUMPI); return ret; } - - void appendFile(std::string const& _fn); + /// Consolidates data and compiles code. + bytes code() const { return m_asm.assemble(); } - std::string asPushedString() const; - - void onePath() { assert(!m_totalDeposit && !m_baseDeposit); m_baseDeposit = m_deposit; m_totalDeposit = INT_MAX; } - void otherPath() { donePath(); m_totalDeposit = m_deposit; m_deposit = m_baseDeposit; } - void donePaths() { donePath(); m_totalDeposit = m_baseDeposit = 0; } - void ignored() { m_baseDeposit = m_deposit; } - void endIgnored() { m_deposit = m_baseDeposit; m_baseDeposit = 0; } - - bool operator==(CodeFragment const& _f) const { return _f.m_code == m_code && _f.m_data == m_data; } - bool operator!=(CodeFragment const& _f) const { return !operator==(_f); } - unsigned size() const { return m_code.size(); } - - void consolidateData(); - void optimise(); + /// Consolidates data and compiles code. + std::string assembly() const { return m_asm.out(); } private: template <class T> void error() const { throw T(); } void constructOperation(sp::utree const& _t, CompilerState& _s); - void donePath() { if (m_totalDeposit != INT_MAX && m_totalDeposit != m_deposit) error<InvalidDeposit>(); } - - int m_deposit = 0; - int m_baseDeposit = 0; - int m_totalDeposit = 0; - bytes m_code; - std::vector<unsigned> m_locs; - std::multimap<bytes, unsigned> m_data; + Assembly m_asm; }; static const CodeFragment NullCodeFragment; diff --git a/CodeLocation.cpp b/CodeLocation.cpp deleted file mode 100644 index 2c9ca264..00000000 --- a/CodeLocation.cpp +++ /dev/null @@ -1,59 +0,0 @@ -/* - This file is part of cpp-ethereum. - - cpp-ethereum is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - cpp-ethereum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. -*/ -/** @file CodeLocation.cpp - * @author Gav Wood <i@gavwood.com> - * @date 2014 - */ - -#include "CodeLocation.h" -#include "CodeFragment.h" -using namespace std; -using namespace eth; - -CodeLocation::CodeLocation(CodeFragment* _f) -{ - m_f = _f; - m_pos = _f->m_code.size(); -} - -unsigned CodeLocation::get() const -{ - assert(m_f->m_code[m_pos - 1] == (byte)Instruction::PUSH4); - bytesConstRef r(&m_f->m_code[m_pos], 4); - return fromBigEndian<uint32_t>(r); -} - -void CodeLocation::set(unsigned _val) -{ - assert(m_f->m_code[m_pos - 1] == (byte)Instruction::PUSH4); - assert(!get()); - bytesRef r(&m_f->m_code[m_pos], 4); - toBigEndian(_val, r); -} - -void CodeLocation::anchor() -{ - set(m_f->m_code.size()); -} - -void CodeLocation::increase(unsigned _val) -{ - assert(m_f->m_code[m_pos - 1] == (byte)Instruction::PUSH4); - bytesRef r(&m_f->m_code[m_pos], 4); - toBigEndian(get() + _val, r); -} - diff --git a/CodeLocation.h b/CodeLocation.h deleted file mode 100644 index c8cf5ee8..00000000 --- a/CodeLocation.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - This file is part of cpp-ethereum. - - cpp-ethereum is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - cpp-ethereum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. -*/ -/** @file CodeLocation.h - * @author Gav Wood <i@gavwood.com> - * @date 2014 - */ - -#pragma once - -#include <libethsupport/Common.h> -#include <libethcore/Instruction.h> -#include "Exceptions.h" - -namespace eth -{ - -class CodeFragment; - -class CodeLocation -{ - friend class CodeFragment; - -public: - CodeLocation(CodeFragment* _f); - CodeLocation(CodeFragment* _f, unsigned _p): m_f(_f), m_pos(_p) {} - - unsigned get() const; - void increase(unsigned _val); - void set(unsigned _val); - void set(CodeLocation _loc) { assert(_loc.m_f == m_f); set(_loc.m_pos); } - void anchor(); - - CodeLocation operator+(unsigned _i) const { return CodeLocation(m_f, m_pos + _i); } - -private: - CodeFragment* m_f; - unsigned m_pos; -}; - -} diff --git a/Compiler.cpp b/Compiler.cpp index afe84eb4..777bb72d 100644 --- a/Compiler.cpp +++ b/Compiler.cpp @@ -27,12 +27,12 @@ using namespace std; using namespace eth; -bytes eth::compileLLL(string const& _s, vector<string>* _errors) +bytes eth::compileLLL(string const& _src, vector<string>* _errors) { try { CompilerState cs; - bytes ret = CodeFragment::compile(_s, cs).code(); + bytes ret = CodeFragment::compile(_src, cs).code(); for (auto i: cs.treesToKill) killBigints(i); return ret; @@ -50,6 +50,29 @@ bytes eth::compileLLL(string const& _s, vector<string>* _errors) return bytes(); } +std::string eth::compileLLLToAsm(std::string const& _src, std::vector<std::string>* _errors) +{ + try + { + CompilerState cs; + string ret = CodeFragment::compile(_src, cs).assembly(); + for (auto i: cs.treesToKill) + killBigints(i); + return ret; + } + catch (Exception const& _e) + { + if (_errors) + _errors->push_back(_e.description()); + } + catch (std::exception) + { + if (_errors) + _errors->push_back("Parse error."); + } + return string(); +} + string eth::parseLLL(string const& _src) { sp::utree o; @@ -29,7 +29,8 @@ namespace eth { std::string parseLLL(std::string const& _src); -bytes compileLLL(std::string const& _s, std::vector<std::string>* _errors = nullptr); +std::string compileLLLToAsm(std::string const& _src, std::vector<std::string>* _errors = nullptr); +bytes compileLLL(std::string const& _src, std::vector<std::string>* _errors = nullptr); } |