diff options
Diffstat (limited to 'libevmasm/Assembly.cpp')
-rw-r--r-- | libevmasm/Assembly.cpp | 170 |
1 files changed, 101 insertions, 69 deletions
diff --git a/libevmasm/Assembly.cpp b/libevmasm/Assembly.cpp index a9ca24dc..597fdae1 100644 --- a/libevmasm/Assembly.cpp +++ b/libevmasm/Assembly.cpp @@ -55,28 +55,15 @@ void Assembly::append(Assembly const& _a) m_subs += _a.m_subs; for (auto const& lib: _a.m_libraries) m_libraries.insert(lib); - - assert(!_a.m_baseDeposit); - assert(!_a.m_totalDeposit); } void Assembly::append(Assembly const& _a, int _deposit) { - if (_deposit > _a.m_deposit) - BOOST_THROW_EXCEPTION(InvalidDeposit()); - else - { - append(_a); - while (_deposit++ < _a.m_deposit) - append(Instruction::POP); - } -} + assertThrow(_deposit <= _a.m_deposit, InvalidDeposit, ""); -string Assembly::out() const -{ - stringstream ret; - stream(ret); - return ret.str(); + append(_a); + while (_deposit++ < _a.m_deposit) + append(Instruction::POP); } unsigned Assembly::bytesRequired(unsigned subTagSize) const @@ -94,7 +81,10 @@ unsigned Assembly::bytesRequired(unsigned subTagSize) const } } -string Assembly::locationFromSources(StringMap const& _sourceCodes, SourceLocation const& _location) const +namespace +{ + +string locationFromSources(StringMap const& _sourceCodes, SourceLocation const& _location) { if (_location.isEmpty() || _sourceCodes.empty() || _location.start >= _location.end || _location.start < 0) return ""; @@ -115,71 +105,107 @@ string Assembly::locationFromSources(StringMap const& _sourceCodes, SourceLocati return cut; } -ostream& Assembly::streamAsm(ostream& _out, string const& _prefix, StringMap const& _sourceCodes) const +class Functionalizer { - _out << _prefix << ".code:" << endl; - for (AssemblyItem const& i: m_items) +public: + Functionalizer (ostream& _out, string const& _prefix, StringMap const& _sourceCodes): + m_out(_out), m_prefix(_prefix), m_sourceCodes(_sourceCodes) + {} + + void feed(AssemblyItem const& _item) { - _out << _prefix; - switch (i.type()) + if (!_item.location().isEmpty() && _item.location() != m_location) { - case Operation: - _out << " " << instructionInfo(i.instruction()).name << "\t" << i.getJumpTypeAsString(); - break; - case Push: - _out << " PUSH" << dec << max<unsigned>(1, dev::bytesRequired(i.data())) << " 0x" << hex << i.data(); - break; - case PushString: - _out << " PUSH \"" << m_strings.at((h256)i.data()) << "\""; - break; - case PushTag: - if (i.data() == 0) - _out << " PUSH [ErrorTag]"; - else + flush(); + m_location = _item.location(); + printLocation(); + } + if (!( + _item.canBeFunctional() && + _item.returnValues() <= 1 && + _item.arguments() <= int(m_pending.size()) + )) + { + flush(); + m_out << m_prefix << (_item.type() == Tag ? "" : " ") << _item.toAssemblyText() << endl; + return; + } + string expression = _item.toAssemblyText(); + if (_item.arguments() > 0) + { + expression += "("; + for (int i = 0; i < _item.arguments(); ++i) { - size_t subId = i.splitForeignPushTag().first; - if (subId == size_t(-1)) - _out << " PUSH [tag" << dec << i.splitForeignPushTag().second << "]"; - else - _out << " PUSH [tag" << dec << subId << ":" << i.splitForeignPushTag().second << "]"; + expression += m_pending.back(); + m_pending.pop_back(); + if (i + 1 < _item.arguments()) + expression += ", "; } - break; - case PushSub: - _out << " PUSH [$" << size_t(i.data()) << "]"; - break; - case PushSubSize: - _out << " PUSH #[$" << size_t(i.data()) << "]"; - break; - case PushProgramSize: - _out << " PUSHSIZE"; - break; - case PushLibraryAddress: - _out << " PUSHLIB \"" << m_libraries.at(h256(i.data())) << "\""; - break; - case Tag: - _out << "tag" << dec << i.data() << ": " << endl << _prefix << " JUMPDEST"; - break; - case PushData: - _out << " PUSH [" << hex << (unsigned)i.data() << "]"; - break; - default: - BOOST_THROW_EXCEPTION(InvalidOpcode()); + expression += ")"; } - _out << "\t\t" << locationFromSources(_sourceCodes, i.location()) << endl; + + m_pending.push_back(expression); + if (_item.returnValues() != 1) + flush(); + } + + void flush() + { + for (string const& expression: m_pending) + m_out << m_prefix << " " << expression << endl; + m_pending.clear(); } + void printLocation() + { + if (!m_location.sourceName && m_location.isEmpty()) + return; + m_out << m_prefix << " /*"; + if (m_location.sourceName) + m_out << " \"" + *m_location.sourceName + "\""; + if (!m_location.isEmpty()) + m_out << ":" << to_string(m_location.start) + ":" + to_string(m_location.end); + m_out << " " << locationFromSources(m_sourceCodes, m_location); + m_out << " */" << endl; + } + +private: + strings m_pending; + SourceLocation m_location; + + ostream& m_out; + string const& m_prefix; + StringMap const& m_sourceCodes; +}; + +} + +ostream& Assembly::streamAsm(ostream& _out, string const& _prefix, StringMap const& _sourceCodes) const +{ + Functionalizer f(_out, _prefix, _sourceCodes); + + for (auto const& i: m_items) + f.feed(i); + f.flush(); + if (!m_data.empty() || !m_subs.empty()) { - _out << _prefix << ".data:" << endl; + _out << _prefix << "stop" << endl; for (auto const& i: m_data) if (u256(i.first) >= m_subs.size()) - _out << _prefix << " " << hex << (unsigned)(u256)i.first << ": " << dev::toHex(i.second) << endl; + _out << _prefix << "data_" << toHex(u256(i.first)) << " " << toHex(i.second) << endl; + for (size_t i = 0; i < m_subs.size(); ++i) { - _out << _prefix << " " << hex << i << ": " << endl; - m_subs[i]->stream(_out, _prefix + " ", _sourceCodes); + _out << endl << _prefix << "sub_" << i << ": assembly {\n"; + m_subs[i]->streamAsm(_out, _prefix + " ", _sourceCodes); + _out << _prefix << "}" << endl; } } + + if (m_auxiliaryData.size() > 0) + _out << endl << _prefix << "auxdata: 0x" << toHex(m_auxiliaryData) << endl; + return _out; } @@ -279,8 +305,13 @@ Json::Value Assembly::streamAsmJson(ostream& _out, StringMap const& _sourceCodes data[hexStr.str()] = m_subs[i]->stream(_out, "", _sourceCodes, true); } root[".data"] = data; - _out << root; } + + if (m_auxiliaryData.size() > 0) + root[".auxdata"] = toHex(m_auxiliaryData); + + _out << root; + return root; } @@ -297,6 +328,7 @@ Json::Value Assembly::stream(ostream& _out, string const& _prefix, StringMap con AssemblyItem const& Assembly::append(AssemblyItem const& _i) { + assertThrow(m_deposit >= 0, AssemblyException, ""); m_deposit += _i.deposit(); m_items.push_back(_i); if (m_items.back().location().isEmpty() && !m_currentSourceLocation.isEmpty()) @@ -449,7 +481,7 @@ LinkerObject const& Assembly::assemble() const switch (i.type()) { case Operation: - ret.bytecode.push_back((byte)i.data()); + ret.bytecode.push_back((byte)i.instruction()); break; case PushString: { |