aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorchriseth <c@ethdev.com>2016-11-15 21:01:11 +0800
committerchriseth <c@ethdev.com>2017-01-03 21:13:49 +0800
commita285ca44f228236ab92eb8dc9d878053829276b4 (patch)
tree68040d0309c0d4de80514a7f58f27dbe7a72a71b
parent0bd8c204f04f679b4371199d876bc6160d913782 (diff)
downloaddexon-solidity-a285ca44f228236ab92eb8dc9d878053829276b4.tar.gz
dexon-solidity-a285ca44f228236ab92eb8dc9d878053829276b4.tar.zst
dexon-solidity-a285ca44f228236ab92eb8dc9d878053829276b4.zip
Assembly output for Assembly object.
-rw-r--r--libevmasm/Assembly.cpp69
-rw-r--r--libevmasm/AssemblyItem.cpp82
-rw-r--r--libevmasm/AssemblyItem.h5
3 files changed, 105 insertions, 51 deletions
diff --git a/libevmasm/Assembly.cpp b/libevmasm/Assembly.cpp
index a9ca24dc..f50a38a6 100644
--- a/libevmasm/Assembly.cpp
+++ b/libevmasm/Assembly.cpp
@@ -117,69 +117,36 @@ string Assembly::locationFromSources(StringMap const& _sourceCodes, SourceLocati
ostream& Assembly::streamAsm(ostream& _out, string const& _prefix, StringMap const& _sourceCodes) const
{
- _out << _prefix << ".code:" << endl;
- for (AssemblyItem const& i: m_items)
+ for (size_t i = 0; i < m_items.size(); ++i)
{
- _out << _prefix;
- switch (i.type())
+ AssemblyItem const& item = m_items[i];
+ if (!item.location().isEmpty() && (i == 0 || m_items[i - 1].location() != item.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
- {
- 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 << "]";
- }
- 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());
+ _out << _prefix << " /*";
+ if (item.location().sourceName)
+ _out << " \"" + *item.location().sourceName + "\"";
+ if (!item.location().isEmpty())
+ _out << ":" << to_string(item.location().start) + ":" + to_string(item.location().end);
+ _out << " */" << endl;
}
- _out << "\t\t" << locationFromSources(_sourceCodes, i.location()) << endl;
+ _out << _prefix << (item.type() == Tag ? "" : " ") << item.toAssemblyText() << endl;
}
if (!m_data.empty() || !m_subs.empty())
{
- _out << _prefix << ".data:" << endl;
+ _out << _prefix << "stop" << endl;
+ Json::Value data;
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;
+ assertThrow(u256(i.first) < m_subs.size(), AssemblyException, "Data not yet implemented.");
+
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;
}
}
+
return _out;
}
diff --git a/libevmasm/AssemblyItem.cpp b/libevmasm/AssemblyItem.cpp
index 54e38de8..8b3f920a 100644
--- a/libevmasm/AssemblyItem.cpp
+++ b/libevmasm/AssemblyItem.cpp
@@ -20,6 +20,7 @@
*/
#include "AssemblyItem.h"
+#include <libevmasm/SemanticInformation.h>
#include <fstream>
using namespace std;
@@ -97,6 +98,28 @@ int AssemblyItem::deposit() const
return 0;
}
+bool AssemblyItem::canBeFunctional() const
+{
+ switch (m_type)
+ {
+ case Operation:
+ return !SemanticInformation::isDupInstruction(*this) && !SemanticInformation::isSwapInstruction(*this);
+ case Push:
+ case PushString:
+ case PushTag:
+ case PushData:
+ case PushSub:
+ case PushSubSize:
+ case PushProgramSize:
+ case PushLibraryAddress:
+ return true;
+ case Tag:
+ return false;
+ default:;
+ }
+ return 0;
+}
+
string AssemblyItem::getJumpTypeAsString() const
{
switch (m_jumpType)
@@ -111,6 +134,65 @@ string AssemblyItem::getJumpTypeAsString() const
}
}
+string AssemblyItem::toAssemblyText() const
+{
+ string text;
+ switch (type())
+ {
+ case Operation:
+ {
+ assertThrow(isValidInstruction(instruction()), AssemblyException, "Invalid instruction.");
+ string name = instructionInfo(instruction()).name;
+ transform(name.begin(), name.end(), name.begin(), [](unsigned char _c) { return tolower(_c); });
+ text = name;
+ break;
+ }
+ case Push:
+ text = toHex(toCompactBigEndian(data(), 1), 1, HexPrefix::Add);
+ break;
+ case PushString:
+ assertThrow(false, AssemblyException, "Push string assembly output not implemented.");
+ break;
+ case PushTag:
+ assertThrow(data() < 0x10000, AssemblyException, "Sub-assembly tags not yet implemented.");
+ text = string("tag_") + to_string(size_t(data()));
+ break;
+ case Tag:
+ assertThrow(data() < 0x10000, AssemblyException, "Sub-assembly tags not yet implemented.");
+ text = string("tag_") + to_string(size_t(data())) + ":";
+ break;
+ case PushData:
+ assertThrow(false, AssemblyException, "Push data not implemented.");
+ break;
+ case PushSub:
+ text = string("dataOffset(sub_") + to_string(size_t(data())) + ")";
+ break;
+ case PushSubSize:
+ text = string("dataSize(sub_") + to_string(size_t(data())) + ")";
+ break;
+ case PushProgramSize:
+ text = string("programSize");
+ break;
+ case PushLibraryAddress:
+ text = string("linkerSymbol(\"") + toHex(data()) + string("\")");
+ break;
+ case UndefinedItem:
+ assertThrow(false, AssemblyException, "Invalid assembly item.");
+ break;
+ default:
+ BOOST_THROW_EXCEPTION(InvalidOpcode());
+ }
+ if (m_jumpType == JumpType::IntoFunction || m_jumpType == JumpType::OutOfFunction)
+ {
+ text += "\t//";
+ if (m_jumpType == JumpType::IntoFunction)
+ text += " in";
+ else
+ text += " out";
+ }
+ return text;
+}
+
ostream& dev::eth::operator<<(ostream& _out, AssemblyItem const& _item)
{
switch (_item.type())
diff --git a/libevmasm/AssemblyItem.h b/libevmasm/AssemblyItem.h
index b5bd3ed8..cddfb17c 100644
--- a/libevmasm/AssemblyItem.h
+++ b/libevmasm/AssemblyItem.h
@@ -97,6 +97,9 @@ public:
unsigned bytesRequired(unsigned _addressLength) const;
int deposit() const;
+ /// @returns true if the assembly item can be used in a functional context.
+ bool canBeFunctional() const;
+
bool match(AssemblyItem const& _i) const { return _i.m_type == UndefinedItem || (m_type == _i.m_type && (m_type != Operation || m_data == _i.m_data)); }
void setLocation(SourceLocation const& _location) { m_location = _location; }
SourceLocation const& location() const { return m_location; }
@@ -108,6 +111,8 @@ public:
void setPushedValue(u256 const& _value) const { m_pushedValue = std::make_shared<u256>(_value); }
u256 const* pushedValue() const { return m_pushedValue.get(); }
+ std::string toAssemblyText() const;
+
private:
AssemblyItemType m_type;
u256 m_data;