diff options
-rw-r--r-- | Assembly.cpp | 5 | ||||
-rw-r--r-- | Assembly.h | 2 | ||||
-rw-r--r-- | CodeFragment.cpp | 39 | ||||
-rw-r--r-- | CodeFragment.h | 7 | ||||
-rw-r--r-- | Compiler.cpp | 4 | ||||
-rw-r--r-- | CompilerState.cpp | 3 | ||||
-rw-r--r-- | CompilerState.h | 1 |
7 files changed, 53 insertions, 8 deletions
diff --git a/Assembly.cpp b/Assembly.cpp index 0fa12537..7016b286 100644 --- a/Assembly.cpp +++ b/Assembly.cpp @@ -176,6 +176,11 @@ AssemblyItem const& Assembly::append(AssemblyItem const& _i) return back(); } +void Assembly::injectStart(AssemblyItem const& _i) +{ + m_items.insert(m_items.begin(), _i); +} + inline bool matches(AssemblyItemsConstRef _a, AssemblyItemsConstRef _b) { if (_a.size() != _b.size()) @@ -98,6 +98,8 @@ public: void popTo(int _deposit) { while (m_deposit > _deposit) append(Instruction::POP); } + void injectStart(AssemblyItem const& _i); + std::string out() const { std::stringstream ret; streamOut(ret); return ret.str(); } int deposit() const { return m_deposit; } bytes assemble() const; diff --git a/CodeFragment.cpp b/CodeFragment.cpp index f0aeb860..70973aab 100644 --- a/CodeFragment.cpp +++ b/CodeFragment.cpp @@ -19,7 +19,6 @@ * @date 2014 */ -#include "Parser.h" #include "CodeFragment.h" #include <boost/algorithm/string.hpp> @@ -27,12 +26,30 @@ #include <libethential/Log.h> #include <libevmface/Instruction.h> #include "CompilerState.h" +#include "Parser.h" using namespace std; using namespace eth; namespace qi = boost::spirit::qi; namespace px = boost::phoenix; namespace sp = boost::spirit; +void CodeFragment::finalise(CompilerState const& _cs) +{ + if (_cs.usedAlloc && _cs.vars.size() && !m_finalised) + { + m_finalised = true; + m_asm.injectStart(Instruction::MSTORE8); + m_asm.injectStart((u256)((_cs.vars.size() + 2) * 32) - 1); + m_asm.injectStart((u256)1); + } +} + +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:"; @@ -317,6 +334,7 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s) vector<CodeFragment> code; CompilerState ns = _s; ns.vars.clear(); + ns.usedAlloc = false; int c = _t.tag() ? 1 : 0; for (auto const& i: _t) if (c++) @@ -456,13 +474,30 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s) m_asm.appendJump(begin); m_asm << end.tag(); } + else if (us == "ALLOC") + { + requireSize(1); + requireDeposit(0, 1); + + m_asm.append(Instruction::MEMSIZE); + m_asm.append(u256(0)); + m_asm.append(u256(1)); + m_asm.append(code[0].m_asm, 1); + m_asm.append(Instruction::MEMSIZE); + m_asm.append(Instruction::ADD); + m_asm.append(Instruction::SUB); + m_asm.append(Instruction::MSTORE8); + + _s.usedAlloc = true; + } else if (us == "LLL") { requireMinSize(2); requireMaxSize(3); requireDeposit(1, 1); - bytes const& subcode = code[0].code(); + code[0].optimise(); + bytes subcode = code[0].code(ns); m_asm.append((u256)subcode.size()); m_asm.append(Instruction::DUP); diff --git a/CodeFragment.h b/CodeFragment.h index b9d44c03..58e40912 100644 --- a/CodeFragment.h +++ b/CodeFragment.h @@ -43,18 +43,21 @@ public: static CodeFragment compile(std::string const& _src, CompilerState& _s); /// Consolidates data and compiles code. - bytes code() const { return m_asm.assemble(); } + bytes code(CompilerState const& _cs); /// Consolidates data and compiles code. - std::string assembly() const { return m_asm.out(); } + 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(); } private: + void finalise(CompilerState const& _cs); + template <class T> void error() const { throw T(); } void constructOperation(sp::utree const& _t, CompilerState& _s); + bool m_finalised = false; Assembly m_asm; }; diff --git a/Compiler.cpp b/Compiler.cpp index 8400ad95..0faf478d 100644 --- a/Compiler.cpp +++ b/Compiler.cpp @@ -36,7 +36,7 @@ bytes eth::compileLLL(string const& _src, bool _opt, vector<string>* _errors) auto f = CodeFragment::compile(_src, cs); if (_opt) f.optimise(); - bytes ret = f.code(); + bytes ret = f.code(cs); for (auto i: cs.treesToKill) killBigints(i); return ret; @@ -63,7 +63,7 @@ std::string eth::compileLLLToAsm(std::string const& _src, bool _opt, std::vector auto f = CodeFragment::compile(_src, cs); if (_opt) f.optimise(); - string ret = f.assembly(); + string ret = f.assembly(cs); for (auto i: cs.treesToKill) killBigints(i); return ret; diff --git a/CompilerState.cpp b/CompilerState.cpp index 7e990413..7a668190 100644 --- a/CompilerState.cpp +++ b/CompilerState.cpp @@ -52,8 +52,7 @@ void CompilerState::populateStandard() "(def 'regname (name) { [0]:name (call (- (gas) 21) namereg 0 0 32 0 0) })" "(def 'send (to value) (call (- (gas) 21) to value 0 0 0 0))" "(def 'send (gaslimit to value) (call gaslimit to value 0 0 0 0))" - "(def 'alloc (len) (asm msize 0 1 len msize add sub mstore8))" - "(def 'msg (gaslimit to value data datasize outsize) { [32]:outsize [0]:(alloc @32) (call gaslimit to value data datasize @0 @32) @0 })" + "(def 'msg (gaslimit to value data datasize outsize) { (set x outsize) (set y (alloc @32)) (call gaslimit to value data datasize @0 @32) @0 })" "(def 'msg (gaslimit to value data datasize) { (call gaslimit to value data datasize 0 32) @0 })" "(def 'msg (gaslimit to value data) { [0]:data (msg gaslimit to value 0 32) })" "(def 'msg (to value data) { [0]:data (msg 0 to value 0 32) })" diff --git a/CompilerState.h b/CompilerState.h index f8f7ce81..5dcde614 100644 --- a/CompilerState.h +++ b/CompilerState.h @@ -48,6 +48,7 @@ struct CompilerState std::map<std::string, CodeFragment> outers; std::map<std::pair<std::string, unsigned>, Macro> macros; std::vector<boost::spirit::utree> treesToKill; + bool usedAlloc = false; }; } |