aboutsummaryrefslogtreecommitdiffstats
path: root/liblll
diff options
context:
space:
mode:
Diffstat (limited to 'liblll')
-rw-r--r--liblll/All.h6
-rw-r--r--liblll/CodeFragment.cpp62
-rw-r--r--liblll/Compiler.cpp5
-rw-r--r--liblll/CompilerState.cpp16
-rw-r--r--liblll/Parser.cpp2
5 files changed, 57 insertions, 34 deletions
diff --git a/liblll/All.h b/liblll/All.h
deleted file mode 100644
index 7c4192f6..00000000
--- a/liblll/All.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#pragma once
-
-#include "CodeFragment.h"
-#include "Compiler.h"
-#include "CompilerState.h"
-#include "Parser.h"
diff --git a/liblll/CodeFragment.cpp b/liblll/CodeFragment.cpp
index 2b8822a6..56c1e26a 100644
--- a/liblll/CodeFragment.cpp
+++ b/liblll/CodeFragment.cpp
@@ -171,11 +171,23 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s)
return string();
};
- auto varAddress = [&](string const& n)
+ auto varAddress = [&](string const& n, bool createMissing = false)
{
+ if (n.empty())
+ error<InvalidName>("Empty variable name not allowed");
auto it = _s.vars.find(n);
if (it == _s.vars.end())
- error<InvalidName>(std::string("Symbol not found: ") + s);
+ {
+ if (createMissing)
+ {
+ // Create new variable
+ bool ok;
+ tie(it, ok) = _s.vars.insert(make_pair(n, make_pair(_s.stackSize, 32)));
+ _s.stackSize += 32;
+ }
+ else
+ error<InvalidName>(std::string("Symbol not found: ") + n);
+ }
return it->second.first;
};
@@ -192,7 +204,13 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s)
{
if (_t.size() != 2)
error<IncorrectParameterCount>();
- m_asm.append(CodeFragment::compile(contentsString(firstAsString()), _s).m_asm);
+ string fileName = firstAsString();
+ if (fileName.empty())
+ error<InvalidName>("Empty file name provided");
+ string contents = contentsString(fileName);
+ if (contents.empty())
+ error<InvalidName>(std::string("File not found (or empty): ") + fileName);
+ m_asm.append(CodeFragment::compile(contents, _s).m_asm);
}
else if (us == "SET")
{
@@ -202,7 +220,7 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s)
for (auto const& i: _t)
if (c++ == 2)
m_asm.append(CodeFragment(i, _s, false).m_asm);
- m_asm.append((u256)varAddress(firstAsString()));
+ m_asm.append((u256)varAddress(firstAsString(), true));
m_asm.append(Instruction::MSTORE);
}
else if (us == "GET")
@@ -240,7 +258,11 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s)
}
else if (ii == 2)
if (_t.size() == 3)
- _s.defs[n] = CodeFragment(i, _s);
+ {
+ /// NOTE: some compilers could do the assignment first if this is done in a single line
+ CodeFragment code = CodeFragment(i, _s);
+ _s.defs[n] = code;
+ }
else
for (auto const& j: i)
{
@@ -439,15 +461,21 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s)
int minDep = min(code[1].m_asm.deposit(), code[2].m_asm.deposit());
m_asm.append(code[0].m_asm);
- auto pos = m_asm.appendJumpI();
- m_asm.onePath();
+ auto mainBranch = m_asm.appendJumpI();
+
+ /// The else branch.
+ int startDeposit = m_asm.deposit();
m_asm.append(code[2].m_asm, minDep);
auto end = m_asm.appendJump();
- m_asm.otherPath();
- m_asm << pos.tag();
+ int deposit = m_asm.deposit();
+ m_asm.setDeposit(startDeposit);
+
+ /// The main branch.
+ m_asm << mainBranch.tag();
m_asm.append(code[1].m_asm, minDep);
m_asm << end.tag();
- m_asm.donePaths();
+ if (m_asm.deposit() != deposit)
+ error<InvalidDeposit>();
}
else if (us == "WHEN" || us == "UNLESS")
{
@@ -458,11 +486,8 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s)
if (us == "WHEN")
m_asm.append(Instruction::ISZERO);
auto end = m_asm.appendJumpI();
- m_asm.onePath();
- m_asm.otherPath();
m_asm.append(code[1].m_asm, 0);
m_asm << end.tag();
- m_asm.donePaths();
}
else if (us == "WHILE" || us == "UNTIL")
{
@@ -515,8 +540,7 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s)
requireMaxSize(3);
requireDeposit(1, 1);
- auto subPush = m_asm.newSub(make_shared<Assembly>(code[0].assembly(ns)));
- m_asm.append(m_asm.newPushSubSize(subPush.data()));
+ auto subPush = m_asm.appendSubroutine(make_shared<Assembly>(code[0].assembly(ns)));
m_asm.append(Instruction::DUP1);
if (code.size() == 3)
{
@@ -571,11 +595,9 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s)
{
for (auto const& i: code)
m_asm.append(i.m_asm);
- m_asm.popTo(1);
- }
- else if (us == "PANIC")
- {
- m_asm.appendJump(m_asm.errorTag());
+ // Leave only the last item on stack.
+ while (m_asm.deposit() > 1)
+ m_asm.append(Instruction::POP);
}
else if (us == "BYTECODESIZE")
{
diff --git a/liblll/Compiler.cpp b/liblll/Compiler.cpp
index ea8b27af..05376cd5 100644
--- a/liblll/Compiler.cpp
+++ b/liblll/Compiler.cpp
@@ -69,10 +69,11 @@ std::string dev::eth::compileLLLToAsm(std::string const& _src, bool _opt, std::v
{
CompilerState cs;
cs.populateStandard();
- string ret = CodeFragment::compile(_src, cs).assembly(cs).optimise(_opt).out();
+ stringstream ret;
+ CodeFragment::compile(_src, cs).assembly(cs).optimise(_opt).stream(ret);
for (auto i: cs.treesToKill)
killBigints(i);
- return ret;
+ return ret.str();
}
catch (Exception const& _e)
{
diff --git a/liblll/CompilerState.cpp b/liblll/CompilerState.cpp
index 88e43e18..5d38bb8c 100644
--- a/liblll/CompilerState.cpp
+++ b/liblll/CompilerState.cpp
@@ -45,26 +45,29 @@ CodeFragment const& CompilerState::getDef(std::string const& _s)
void CompilerState::populateStandard()
{
static const string s = "{"
+ "(def 'panic () (asm INVALID))"
"(def 'allgas (- (gas) 21))"
"(def 'send (to value) (call allgas to value 0 0 0 0))"
"(def 'send (gaslimit to value) (call gaslimit to value 0 0 0 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 })"
+ // NOTE: in this macro, memory location 0 is set in order to force msize to be at least 32 bytes.
+ "(def 'msg (gaslimit to value data datasize outsize) { [0]:0 [0]:(msize) (call gaslimit to value data datasize @0 outsize) @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 allgas to value 0 32) })"
"(def 'msg (to data) { [0]:data (msg allgas to 0 0 32) })"
- "(def 'create (value code) { [0]:(msize) (create value @0 (lll code @0)) })"
- "(def 'create (code) { [0]:(msize) (create 0 @0 (lll code @0)) })"
+ // NOTE: in the create macros, memory location 0 is set in order to force msize to be at least 32 bytes.
+ "(def 'create (value code) { [0]:0 [0]:(msize) (create value @0 (lll code @0)) })"
+ "(def 'create (code) { [0]:0 [0]:(msize) (create 0 @0 (lll code @0)) })"
+ "(def 'sha3 (loc len) (keccak256 loc len))"
"(def 'sha3 (val) { [0]:val (sha3 0 32) })"
"(def 'sha3pair (a b) { [0]:a [32]:b (sha3 0 64) })"
"(def 'sha3trip (a b c) { [0]:a [32]:b [64]:c (sha3 0 96) })"
- "(def 'keccak256 (loc len) (sha3 loc len))"
"(def 'return (val) { [0]:val (return 0 32) })"
"(def 'returnlll (code) (return 0 (lll code 0)) )"
"(def 'makeperm (name pos) { (def name (sload pos)) (def name (v) (sstore pos v)) } )"
"(def 'permcount 0)"
"(def 'perm (name) { (makeperm name permcount) (def 'permcount (+ permcount 1)) } )"
- "(def 'ecrecover (r s v hash) { [0] r [32] s [64] v [96] hash (msg allgas 1 0 0 128) })"
+ "(def 'ecrecover (hash v r s) { [0] hash [32] v [64] r [96] s (msg allgas 1 0 0 128) })"
"(def 'sha256 (data datasize) (msg allgas 2 0 data datasize))"
"(def 'ripemd160 (data datasize) (msg allgas 3 0 data datasize))"
"(def 'sha256 (val) { [0]:val (sha256 0 32) })"
@@ -73,6 +76,9 @@ void CompilerState::populateStandard()
"(def 'szabo 1000000000000)"
"(def 'finney 1000000000000000)"
"(def 'ether 1000000000000000000)"
+ // these could be replaced by native instructions once supported by EVM
+ "(def 'shl (val shift) (mul val (exp 2 shift)))"
+ "(def 'shr (val shift) (div val (exp 2 shift)))"
"}";
CodeFragment::compile(s, *this);
}
diff --git a/liblll/Parser.cpp b/liblll/Parser.cpp
index 44d2a2ae..a3962df4 100644
--- a/liblll/Parser.cpp
+++ b/liblll/Parser.cpp
@@ -109,7 +109,7 @@ void dev::eth::parseTreeLLL(string const& _s, sp::utree& o_out)
qi::rule<it, space_type, sp::utree::list_type()> mstore = '[' > element > ']' > -qi::lit(":") > element;
qi::rule<it, space_type, sp::utree::list_type()> sstore = qi::lit("[[") > element > qi::lit("]]") > -qi::lit(":") > element;
qi::rule<it, space_type, sp::utree::list_type()> calldataload = qi::lit("$") > element;
- qi::rule<it, space_type, sp::utree::list_type()> list = '(' > +element > ')';
+ qi::rule<it, space_type, sp::utree::list_type()> list = '(' > *element > ')';
qi::rule<it, space_type, sp::utree()> extra = sload[tagNode<2>()] | mload[tagNode<1>()] | sstore[tagNode<4>()] | mstore[tagNode<3>()] | seq[tagNode<5>()] | calldataload[tagNode<6>()];
element = atom | list | extra;