diff options
author | Gav Wood <i@gavwood.com> | 2014-07-27 19:09:36 +0800 |
---|---|---|
committer | Gav Wood <i@gavwood.com> | 2014-07-27 19:09:36 +0800 |
commit | ed0209fefc50ab59b43b7f781410699c49445aab (patch) | |
tree | f82f1e4fee307efb67a16d9fb82e37c78e16b5b1 | |
parent | 510abc0997c248a1a767ceade6749f426ae3a968 (diff) | |
download | dexon-solidity-ed0209fefc50ab59b43b7f781410699c49445aab.tar dexon-solidity-ed0209fefc50ab59b43b7f781410699c49445aab.tar.gz dexon-solidity-ed0209fefc50ab59b43b7f781410699c49445aab.tar.bz2 dexon-solidity-ed0209fefc50ab59b43b7f781410699c49445aab.tar.lz dexon-solidity-ed0209fefc50ab59b43b7f781410699c49445aab.tar.xz dexon-solidity-ed0209fefc50ab59b43b7f781410699c49445aab.tar.zst dexon-solidity-ed0209fefc50ab59b43b7f781410699c49445aab.zip |
Updates to assembler - see the sub-codes.
-rw-r--r-- | Assembly.cpp | 74 | ||||
-rw-r--r-- | Assembly.h | 12 | ||||
-rw-r--r-- | CodeFragment.cpp | 13 | ||||
-rw-r--r-- | CodeFragment.h | 8 | ||||
-rw-r--r-- | Compiler.cpp | 9 |
5 files changed, 73 insertions, 43 deletions
diff --git a/Assembly.cpp b/Assembly.cpp index 3abdf66f..78552f3c 100644 --- a/Assembly.cpp +++ b/Assembly.cpp @@ -32,7 +32,7 @@ int AssemblyItem::deposit() const { 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: + case Push: case PushString: case PushTag: case PushData: case PushSub: case PushSubSize: return 1; case Tag: return 0; @@ -61,8 +61,12 @@ unsigned Assembly::bytesRequired() const case Push: ret += 1 + max<unsigned>(1, eth::bytesRequired(i.m_data)); break; + case PushSubSize: + ret += 4; // worst case: a 16MB program + break; case PushTag: case PushData: + case PushSub: ret += 1 + br; case Tag:; default:; @@ -87,6 +91,8 @@ void Assembly::append(Assembly const& _a) m_data.insert(i); for (auto const& i: _a.m_strings) m_strings.insert(i); + for (auto const& i: _a.m_subs) + m_subs.insert(i); assert(!_a.m_baseDeposit); assert(!_a.m_totalDeposit); @@ -127,6 +133,12 @@ ostream& eth::operator<<(ostream& _out, AssemblyItemsConstRef _i) case PushData: _out << " PUSH*[" << hex << (unsigned)i.data() << "]"; break; + case PushSub: + _out << " PUSHs[" << hex << h256(i.data()).abridged() << "]"; + break; + case PushSubSize: + _out << " PUSHss[" << hex << h256(i.data()).abridged() << "]"; + break; case UndefinedItem: _out << " ???"; default:; @@ -134,38 +146,50 @@ ostream& eth::operator<<(ostream& _out, AssemblyItemsConstRef _i) return _out; } -ostream& Assembly::streamOut(ostream& _out) const +ostream& Assembly::streamOut(ostream& _out, string const& _prefix) const { - _out << ".code:" << endl; + _out << _prefix << ".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 << _prefix << " " << c_instructionInfo.at((Instruction)(byte)i.m_data).name << endl; break; case Push: - _out << " PUSH " << i.m_data << endl; + _out << _prefix << " PUSH " << i.m_data << endl; break; case PushString: - _out << " PUSH \"" << m_strings.at((h256)i.m_data) << "\"" << endl; + _out << _prefix << " PUSH \"" << m_strings.at((h256)i.m_data) << "\"" << endl; break; case PushTag: - _out << " PUSH [tag" << i.m_data << "]" << endl; + _out << _prefix << " PUSH [tag" << i.m_data << "]" << endl; + break; + case PushSub: + _out << _prefix << " PUSH [$" << h256(i.m_data).abridged() << "]" << endl; + break; + case PushSubSize: + _out << _prefix << " PUSH #[$" << h256(i.m_data).abridged() << "]" << endl; break; case Tag: - _out << "tag" << i.m_data << ": " << endl; + _out << _prefix << "tag" << i.m_data << ": " << endl; break; case PushData: - _out << " PUSH [" << hex << (unsigned)i.m_data << "]" << endl; + _out << _prefix << " PUSH [" << hex << (unsigned)i.m_data << "]" << endl; break; default:; } - if (m_data.size()) + if (m_data.size() || m_subs.size()) { - _out << ".data:" << endl; + _out << _prefix << ".data:" << endl; for (auto const& i: m_data) - _out << " " << hex << (unsigned)(u256)i.first << ": " << toHex(i.second) << endl; + if (!m_subs.count(i.first)) + _out << _prefix << " " << hex << (unsigned)(u256)i.first << ": " << toHex(i.second) << endl; + for (auto const& i: m_subs) + { + _out << _prefix << " " << hex << (unsigned)(u256)i.first << ": " << endl; + i.second.streamOut(_out, _prefix + " "); + } } return _out; } @@ -195,8 +219,10 @@ inline bool matches(AssemblyItemsConstRef _a, AssemblyItemsConstRef _b) struct OptimiserChannel: public LogChannel { static const char* name() { return "OPT"; } static const int verbosity = 12; }; #define copt eth::LogOutputStream<OptimiserChannel, true>() -void Assembly::optimise() +Assembly& Assembly::optimise(bool _enable) { + if (!_enable) + return *this; map<Instruction, function<u256(u256, u256)>> c_simple = { { Instruction::SUB, [](u256 a, u256 b)->u256{return a - b;} }, @@ -221,6 +247,8 @@ void Assembly::optimise() { { Push, Instruction::POP }, [](AssemblyItemsConstRef) -> AssemblyItems { return {}; } }, { { PushTag, Instruction::POP }, [](AssemblyItemsConstRef) -> AssemblyItems { return {}; } }, { { PushString, Instruction::POP }, [](AssemblyItemsConstRef) -> AssemblyItems { return {}; } }, + { { PushSub, Instruction::POP }, [](AssemblyItemsConstRef) -> AssemblyItems { return {}; } }, + { { PushSubSize, Instruction::POP }, [](AssemblyItemsConstRef) -> AssemblyItems { return {}; } }, { { Push, PushTag, Instruction::JUMPI }, [](AssemblyItemsConstRef m) -> AssemblyItems { if (m[0].data()) return { m[1], Instruction::JUMP }; else return {}; } }, { { Instruction::NOT, Instruction::NOT }, [](AssemblyItemsConstRef) -> AssemblyItems { return {}; } }, }; @@ -309,6 +337,11 @@ void Assembly::optimise() } copt << total << " optimisations done."; + + for (auto& i: m_subs) + i.second.optimise(true); + + return *this; } bytes Assembly::assemble() const @@ -323,6 +356,9 @@ bytes Assembly::assemble() const unsigned bytesPerTag = eth::bytesRequired(totalBytes); byte tagPush = (byte)Instruction::PUSH1 - 1 + bytesPerTag; + for (auto const& i: m_subs) + m_data[i.first] = i.second.assemble(); + for (AssemblyItem const& i: m_items) switch (i.m_type) { @@ -358,13 +394,23 @@ bytes Assembly::assemble() const ret.resize(ret.size() + bytesPerTag); break; } - case PushData: + case PushData: case PushSub: { ret.push_back(tagPush); dataRef.insert(make_pair((h256)i.m_data, ret.size())); ret.resize(ret.size() + bytesPerTag); break; } + case PushSubSize: + { + auto s = m_data[i.m_data].size(); + byte b = max<unsigned>(1, eth::bytesRequired(s)); + ret.push_back((byte)Instruction::PUSH1 - 1 + b); + ret.resize(ret.size() + b); + bytesRef byr(&ret.back() + 1 - b, b); + toBigEndian(s, byr); + break; + } case Tag: tagPos[(unsigned)i.m_data] = ret.size(); break; @@ -30,7 +30,7 @@ namespace eth { -enum AssemblyItemType { UndefinedItem, Operation, Push, PushString, PushTag, Tag, PushData }; +enum AssemblyItemType { UndefinedItem, Operation, Push, PushString, PushTag, PushSub, PushSubSize, Tag, PushData }; class Assembly; @@ -70,7 +70,9 @@ public: AssemblyItem newTag() { return AssemblyItem(Tag, m_usedTags++); } AssemblyItem newPushTag() { return AssemblyItem(PushTag, m_usedTags++); } AssemblyItem newData(bytes const& _data) { h256 h = (u256)std::hash<std::string>()(asString(_data)); m_data[h] = _data; return AssemblyItem(PushData, h); } + AssemblyItem newSub(Assembly const& _sub) { h256 h = h256::random(s_fixedHashEngine); m_subs[h] = _sub; return AssemblyItem(PushSub, h); } AssemblyItem newPushString(std::string const& _data) { h256 h = (u256)std::hash<std::string>()(_data); m_strings[h] = _data; return AssemblyItem(PushString, h); } + AssemblyItem newPushSubSize(h256 const& _subId) { return AssemblyItem(PushSubSize, _subId); } AssemblyItem append() { return append(newTag()); } void append(Assembly const& _a); @@ -78,6 +80,7 @@ public: 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 appendSubSize(Assembly const& _asm) { auto ret = newSub(_asm); append(newPushSubSize(ret.data())); return ret; } AssemblyItem appendJump() { auto ret = append(newPushTag()); append(Instruction::JUMP); return ret; } AssemblyItem appendJumpI() { auto ret = append(newPushTag()); append(Instruction::JUMPI); return ret; } @@ -102,8 +105,8 @@ public: std::string out() const { std::stringstream ret; streamOut(ret); return ret.str(); } int deposit() const { return m_deposit; } bytes assemble() const; - void optimise(); - std::ostream& streamOut(std::ostream& _out) const; + Assembly& optimise(bool _enable); + std::ostream& streamOut(std::ostream& _out, std::string const& _prefix = "") const; private: void donePath() { if (m_totalDeposit != INT_MAX && m_totalDeposit != m_deposit) throw InvalidDeposit(); } @@ -111,7 +114,8 @@ private: unsigned m_usedTags = 0; AssemblyItems m_items; - std::map<h256, bytes> m_data; + mutable std::map<h256, bytes> m_data; + std::map<h256, Assembly> m_subs; std::map<h256, std::string> m_strings; int m_deposit = 0; diff --git a/CodeFragment.cpp b/CodeFragment.cpp index d19d7509..bc7fa615 100644 --- a/CodeFragment.cpp +++ b/CodeFragment.cpp @@ -44,12 +44,6 @@ void CodeFragment::finalise(CompilerState const& _cs) } } -bytes CodeFragment::code(CompilerState const& _cs) -{ - finalise(_cs); - return m_asm.assemble(); -} - CodeFragment::CodeFragment(sp::utree const& _t, CompilerState& _s, bool _allowASM) { /* cdebug << "CodeFragment. Locals:"; @@ -499,10 +493,7 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s) requireMaxSize(3); requireDeposit(1, 1); - code[0].optimise(); - bytes subcode = code[0].code(ns); - - m_asm.append((u256)subcode.size()); + auto subPush = m_asm.appendSubSize(code[0].assembly(ns)); m_asm.append(Instruction::DUP); if (code.size() == 3) { @@ -513,7 +504,7 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s) m_asm.append(Instruction::MUL); m_asm.append(Instruction::DUP); } - m_asm.append(subcode); + m_asm.append(subPush); m_asm.append(code[1].m_asm, 1); m_asm.append(Instruction::CODECOPY); } diff --git a/CodeFragment.h b/CodeFragment.h index 58e40912..98a6f15c 100644 --- a/CodeFragment.h +++ b/CodeFragment.h @@ -43,13 +43,7 @@ public: static CodeFragment compile(std::string const& _src, CompilerState& _s); /// Consolidates data and compiles code. - bytes code(CompilerState const& _cs); - - /// Consolidates data and compiles code. - std::string assembly(CompilerState const& _cs) { finalise(_cs); return m_asm.out(); } - - /// Optimise the code. Best do this just before calling code() or assembly(). - void optimise() { m_asm.optimise(); } + Assembly& assembly(CompilerState const& _cs) { finalise(_cs); return m_asm; } private: void finalise(CompilerState const& _cs); diff --git a/Compiler.cpp b/Compiler.cpp index 1621acf9..ebe2638b 100644 --- a/Compiler.cpp +++ b/Compiler.cpp @@ -34,9 +34,7 @@ bytes eth::compileLLL(string const& _src, bool _opt, vector<string>* _errors) CompilerState cs; cs.populateStandard(); auto f = CodeFragment::compile(_src, cs); - if (_opt) - f.optimise(); - bytes ret = f.code(cs); + bytes ret = f.assembly(cs).optimise(_opt).assemble(); for (auto i: cs.treesToKill) killBigints(i); return ret; @@ -60,10 +58,7 @@ std::string eth::compileLLLToAsm(std::string const& _src, bool _opt, std::vector { CompilerState cs; cs.populateStandard(); - auto f = CodeFragment::compile(_src, cs); - if (_opt) - f.optimise(); - string ret = f.assembly(cs); + string ret = CodeFragment::compile(_src, cs).assembly(cs).optimise(_opt).out(); for (auto i: cs.treesToKill) killBigints(i); return ret; |