From 646dfeef84de0e45c868af1e258160b7c3ca6f6f Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 25 May 2014 13:37:40 +0200 Subject: [PATCH] Data segment for memory literals. --- libethereum/Instruction.cpp | 153 +++++++++++++++++++++++------------- libethereum/Instruction.h | 11 ++- 2 files changed, 106 insertions(+), 58 deletions(-) diff --git a/libethereum/Instruction.cpp b/libethereum/Instruction.cpp index f0f058181..826d4072f 100644 --- a/libethereum/Instruction.cpp +++ b/libethereum/Instruction.cpp @@ -271,6 +271,7 @@ struct Macro struct CompilerState { std::map vars; + std::map defs; std::map macros; }; @@ -317,6 +318,7 @@ void CodeFragment::appendFragment(CodeFragment const& _f) 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); @@ -325,9 +327,30 @@ void CodeFragment::appendFragment(CodeFragment const& _f) 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; } +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) @@ -429,8 +452,10 @@ CodeFragment::CodeFragment(sp::utree const& _t, CompilerState& _s, bool _allowAS m_deposit = c_instructionInfo.at(it->second).ret - c_instructionInfo.at(it->second).args; m_code.push_back((byte)it->second); } + else if (_s.defs.count(s)) + appendFragment(_s.defs.at(s)); else - error(); + error(); } else if (_s.defs.count(s)) appendFragment(_s.defs.at(s)); @@ -451,7 +476,14 @@ CodeFragment::CodeFragment(sp::utree const& _t, CompilerState& _s, bool _allowAS } } -// (define plus1 (a) (+ a 1)) +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++; +} void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s) { @@ -490,68 +522,82 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s) default:; } + // Operations who args are not standard stack-pushers. + bool nonStandard = true; if (us == "ASM") { int c = 0; for (auto const& i: _t) if (c++) appendFragment(CodeFragment(i, _s, true)); - return; } - - if (us == "MACRO") + else if (us == "DEF") { string n; unsigned ii = 0; - if (_t.size() != 4) + if (_t.size() != 3 && _t.size() != 4) error(); for (auto const& i: _t) { if (ii == 1) { - if (i.tag() != 0 || i.which() != sp::utree_type::symbol_type) + if (i.tag() || i.which() != sp::utree_type::symbol_type) error(); auto sr = i.get, sp::utree_type::symbol_type>>(); n = string(sr.begin(), sr.end()); } else if (ii == 2) - { - for (auto const& j: i) - { - if (j.tag() != 0 || j.which() != sp::utree_type::symbol_type) - error(); - auto sr = j.get, sp::utree_type::symbol_type>>(); - _s.macros[n].args.push_back(string(sr.begin(), sr.end())); - } - } + if (_t.size() == 3) + _s.defs[n] = CodeFragment(i, _s); + else + for (auto const& j: i) + { + if (j.tag() || j.which() != sp::utree_type::symbol_type) + error(); + auto sr = j.get, sp::utree_type::symbol_type>>(); + _s.macros[n].args.push_back(string(sr.begin(), sr.end())); + } else if (ii == 3) _s.macros[n].code = i; ++ii; } - return; } - - if (us == "DEF") + else if (us == "LIT") { - string n; - unsigned ii = 0; - if (_t.size() != 3) + if (_t.size() < 3) error(); + unsigned ii = 0; + CodeFragment pos; for (auto const& i: _t) { if (ii == 1) { - if (i.tag() != 0 || i.which() != sp::utree_type::symbol_type) - error(); - auto sr = i.get, sp::utree_type::symbol_type>>(); - n = string(sr.begin(), sr.end()); + pos = CodeFragment(i, _s); + if (pos.m_deposit != 1) + error(); } - else if (ii == 2) - _s.defs[n] = CodeFragment(i, _s); + else if (ii == 2 && !i.tag() && i.which() == sp::utree_type::string_type) + { + auto sr = i.get, sp::utree_type::string_type>>(); + appendPush(sr.end() - sr.begin()); + appendInstruction(Instruction::DUP); + appendPushDataLocation(bytes((byte const*)sr.begin(), (byte const*)sr.end())); + appendFragment(pos, 1); + appendInstruction(Instruction::CODECOPY); + } + else if (ii >= 2 && !i.tag() && i.which() == sp::utree_type::any_type) + { + } + else if (ii) + error(); ++ii; } - return; } + else + nonStandard = false; + + if (nonStandard) + return; std::map const c_arith = { { "+", Instruction::ADD }, { "-", Instruction::SUB }, { "*", Instruction::MUL }, { "/", Instruction::DIV }, { "%", Instruction::MOD }, { "&", Instruction::AND }, { "|", Instruction::OR }, { "^", Instruction::XOR } }; std::map> const c_binary = { { "<", { Instruction::LT, false } }, { "<=", { Instruction::GT, true } }, { ">", { Instruction::GT, false } }, { ">=", { Instruction::LT, true } }, { "S<", { Instruction::SLT, false } }, { "S<=", { Instruction::SGT, true } }, { "S>", { Instruction::SGT, false } }, { "S>=", { Instruction::SLT, true } }, { "=", { Instruction::EQ, false } }, { "!=", { Instruction::EQ, true } } }; @@ -563,7 +609,12 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s) int c = _t.tag() ? 1 : 0; for (auto const& i: _t) if (c++) - code.push_back(CodeFragment(i, (us == "LLL" && c == 1) ? ns : _s)); + { + if (us == "LLL" && c == 1) + code.push_back(CodeFragment(i, ns)); + else + code.push_back(CodeFragment(i, _s)); + } auto requireSize = [&](unsigned s) { if (code.size() != s) error(); }; auto requireMinSize = [&](unsigned s) { if (code.size() < s) error(); }; auto requireMaxSize = [&](unsigned s) { if (code.size() > s) error(); }; @@ -669,20 +720,6 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s) appendJump(begin); end.anchor(); } - /*else if (s == "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(); - }*/ else if (us == "LLL") { requireMinSize(2); @@ -690,11 +727,8 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s) requireDeposit(1, 1); CodeLocation codeloc(this, m_code.size() + 6); - appendJump(codeloc + code[0].size()); - ignored(); - appendFragment(code[0]); - endIgnored(); - appendPush(code[0].size()); + bytes const& subcode = code[0].code(); + appendPush(subcode.size()); appendInstruction(Instruction::DUP); if (code.size() == 3) { @@ -705,7 +739,7 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s) appendInstruction(Instruction::MUL); appendInstruction(Instruction::DUP); } - appendPushLocation(codeloc); + appendPushDataLocation(subcode); appendFragment(code[1], 1); appendInstruction(Instruction::CODECOPY); } @@ -768,7 +802,7 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s) } appendFragment(CodeFragment(m.code, cs)); } - else + else if (us.find_first_of("1234567890") != 0 && us.find_first_not_of("QWERTYUIOPASDFGHJKLZXCVBNM1234567890") == string::npos) { auto it = _s.vars.find(s); if (it == _s.vars.end()) @@ -778,18 +812,27 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s) } appendPush(it->second); } -// else -// error(); + else + error(); } } bytes eth::compileLLL(string const& _s, vector* _errors) { + bytes ret; sp::utree o; - parseLLL(_s, o); + try + { + parseLLL(_s, o); + } + catch (...) + { + if (_errors) + _errors->push_back("Syntax error."); + return ret; + } debugOutAST(cerr, o); cerr << endl; - bytes ret; if (!o.empty()) try { diff --git a/libethereum/Instruction.h b/libethereum/Instruction.h index 45b742552..284688484 100644 --- a/libethereum/Instruction.h +++ b/libethereum/Instruction.h @@ -152,16 +152,15 @@ std::string disassemble(bytes const& _mem); /// Compile a Low-level Lisp-like Language program into EVM-code. class CompilerException: public Exception {}; class InvalidOperation: public CompilerException {}; -class SymbolNotFirst: public CompilerException {}; class IntegerOutOfRange: public CompilerException {}; class StringTooLong: public CompilerException {}; class EmptyList: public CompilerException {}; class DataNotExecutable: public CompilerException {}; class IncorrectParameterCount: public CompilerException {}; class InvalidDeposit: public CompilerException {}; -class InvalidOpCode: public CompilerException {}; class InvalidName: public CompilerException {}; class InvalidMacroArgs: public CompilerException {}; +class InvalidLiteral: public CompilerException {}; class BareSymbol: public CompilerException {}; bytes compileLLL(std::string const& _s, std::vector* _errors = nullptr); @@ -199,15 +198,18 @@ public: CodeFragment(sp::utree const& _t, CompilerState& _s, bool _allowASM = false); CodeFragment(bytes const& _c = bytes()): m_code(_c) {} - bytes const& code() const { return m_code; } + /// Consolidates data and returns code. + bytes const& code() { consolidateData(); return m_code; } unsigned appendPush(u256 _l); void appendFragment(CodeFragment const& _f); void appendFragment(CodeFragment const& _f, unsigned _i); void appendInstruction(Instruction _i); + void appendString(std::string const& _s) { for (auto i: _s) m_code.push_back((char)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; } @@ -222,6 +224,8 @@ public: unsigned size() const { return m_code.size(); } + void consolidateData(); + private: template void error() { throw T(); } void constructOperation(sp::utree const& _t, CompilerState& _s); @@ -233,6 +237,7 @@ private: int m_totalDeposit = 0; bytes m_code; std::vector m_locs; + std::multimap m_data; }; }