aboutsummaryrefslogtreecommitdiffstats
path: root/Assembly.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Assembly.cpp')
-rw-r--r--Assembly.cpp175
1 files changed, 169 insertions, 6 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;
}