Refactoring builtins and improve base58 encoding

This commit is contained in:
Hans Svensson 2019-01-11 11:09:00 +01:00
parent dbf2aa45c3
commit 9187659a1e

View File

@ -13,6 +13,38 @@
, check_event_type/1 , check_event_type/1
, used_builtins/1 ]). , used_builtins/1 ]).
-export([ builtin_event/1
, builtin_abort/0
, builtin_map_lookup/1
, builtin_map_put/0
, builtin_map_delete/0
, builtin_map_size/0
, builtin_map_get/1
, builtin_map_lookup_default/1
, builtin_map_member/0
, builtin_map_upd/1
, builtin_map_upd_default/1
, builtin_map_from_list/0
, builtin_list_concat/0
, builtin_string_length/0
, builtin_string_concat/0
, builtin_string_concat_inner1/0
, builtin_string_concat_inner2/0
, builtin_str_equal_p/0
, builtin_str_equal/0
, builtin_int_to_str/0
, builtin_int_to_str_/0
, builtin_int_digits/1
, builtin_base58_tab/0
, builtin_base58_int/0
, builtin_string_reverse/0
, builtin_string_reverse_/0
, builtin_base58_int_pad/0
, builtin_base58_int_encode/0
, builtin_base58_int_encode_/0
, builtin_addr_to_str/0]).
-import(aeso_ast_to_icode, [prim_call/5]). -import(aeso_ast_to_icode, [prim_call/5]).
-include_lib("aebytecode/include/aeb_opcodes.hrl"). -include_lib("aebytecode/include/aeb_opcodes.hrl").
@ -39,10 +71,10 @@ builtin_deps1({map_upd_default, Type}) -> [{map_lookup_default, Type}, map_pu
builtin_deps1(map_from_list) -> [map_put]; builtin_deps1(map_from_list) -> [map_put];
builtin_deps1(str_equal) -> [str_equal_p]; builtin_deps1(str_equal) -> [str_equal_p];
builtin_deps1(string_concat) -> [string_concat_inner1, string_concat_inner2]; builtin_deps1(string_concat) -> [string_concat_inner1, string_concat_inner2];
builtin_deps1(int_to_str) -> [int_to_str_, int_digits]; builtin_deps1(int_to_str) -> [int_to_str_, {int_digits, 10}];
builtin_deps1(addr_to_str) -> [base58_int, string_concat]; builtin_deps1(addr_to_str) -> [base58_int, string_concat];
builtin_deps1(base58_int) -> [base58_int_encode, base58_int_pad, string_reverse, string_concat]; builtin_deps1(base58_int) -> [base58_int_encode, base58_int_pad, string_reverse, string_concat];
builtin_deps1(base58_int_encode) -> [base58_int_encode_, base58_tab]; builtin_deps1(base58_int_encode) -> [base58_int_encode_, base58_tab, {int_digits, 58}];
builtin_deps1(string_reverse) -> [string_reverse_]; builtin_deps1(string_reverse) -> [string_reverse_];
builtin_deps1(_) -> []. builtin_deps1(_) -> [].
@ -108,8 +140,6 @@ check_event_type(Evts, Icode) ->
|| {constr_t, _, {con, _, Name}, Types} <- Evts, T <- Types ]. || {constr_t, _, {con, _, Name}, Types} <- Evts, T <- Types ].
check_event_type(EvtName, Type, Icode) -> check_event_type(EvtName, Type, Icode) ->
io:format("~p: ~p??\n", [EvtName, Type]),
io:format("=> ~p\n", [aeso_ast_to_icode:ast_typerep(Type, Icode)]),
VMType = VMType =
try try
aeso_ast_to_icode:ast_typerep(Type, Icode) aeso_ast_to_icode:ast_typerep(Type, Icode)
@ -123,11 +153,49 @@ check_event_type(EvtName, Type, Icode) ->
false -> error({EvtName, payload_should_be_string, is, VMType}) false -> error({EvtName, payload_should_be_string, is, VMType})
end. end.
bfun(B, F, Args) ->
{IArgs, IExpr, IRet} = erlang:apply(?MODULE, F, Args),
{{builtin, B}, [private], IArgs, IExpr, IRet}.
builtin_function(BF) ->
case BF of
{event, EventT} -> bfun(BF, builtin_event, [EventT]);
abort -> bfun(BF, builtin_abort, []);
{map_lookup, Type} -> bfun(BF, builtin_map_lookup, [Type]);
map_put -> bfun(BF, builtin_map_put, []);
map_delete -> bfun(BF, builtin_map_delete, []);
map_size -> bfun(BF, builtin_map_size, []);
{map_get, Type} -> bfun(BF, builtin_map_get, [Type]);
{map_lookup_default, Type} -> bfun(BF, builtin_map_lookup_default, [Type]);
map_member -> bfun(BF, builtin_map_member, []);
{map_upd, Type} -> bfun(BF, builtin_map_upd, [Type]);
{map_upd_default, Type} -> bfun(BF, builtin_map_upd_default, [Type]);
map_from_list -> bfun(BF, builtin_map_from_list, []);
list_concat -> bfun(BF, builtin_list_concat, []);
string_length -> bfun(BF, builtin_string_length, []);
string_concat -> bfun(BF, builtin_string_concat, []);
string_concat_inner1 -> bfun(BF, builtin_string_concat_inner1, []);
string_concat_inner2 -> bfun(BF, builtin_string_concat_inner2, []);
str_equal_p -> bfun(BF, builtin_str_equal_p, []);
str_equal -> bfun(BF, builtin_str_equal, []);
int_to_str -> bfun(BF, builtin_int_to_str, []);
int_to_str_ -> bfun(BF, builtin_int_to_str_, []);
{int_digits, X} -> bfun(BF, builtin_int_digits, [X]);
base58_tab -> bfun(BF, builtin_base58_tab, []);
base58_int -> bfun(BF, builtin_base58_int, []);
string_reverse -> bfun(BF, builtin_string_reverse, []);
string_reverse_ -> bfun(BF, builtin_string_reverse_, []);
base58_int_pad -> bfun(BF, builtin_base58_int_pad, []);
base58_int_encode -> bfun(BF, builtin_base58_int_encode, []);
base58_int_encode_ -> bfun(BF, builtin_base58_int_encode_, []);
addr_to_str -> bfun(BF, builtin_addr_to_str, [])
end.
%% Event primitive (dependent on Event type) %% Event primitive (dependent on Event type)
%% %%
%% We need to switch on the event and prepare the correct #event for icode_to_asm %% We need to switch on the event and prepare the correct #event for icode_to_asm
%% NOTE: we assume all errors are already checked! %% NOTE: we assume all errors are already checked!
builtin_function(Builtin = {event, EventT}) -> builtin_event(EventT) ->
A = fun(X) -> aeb_opcodes:mnemonic(X) end, A = fun(X) -> aeb_opcodes:mnemonic(X) end,
VIx = fun(Ix) -> v(lists:concat(["v", Ix])) end, VIx = fun(Ix) -> v(lists:concat(["v", Ix])) end,
ArgPats = fun(Ts) -> [ VIx(Ix) || Ix <- lists:seq(0, length(Ts) - 1) ] end, ArgPats = fun(Ts) -> [ VIx(Ix) || Ix <- lists:seq(0, length(Ts) - 1) ] end,
@ -149,149 +217,132 @@ builtin_function(Builtin = {event, EventT}) ->
{variant_t, Cons} = EventT, {variant_t, Cons} = EventT,
Tags = lists:seq(0, length(Cons) - 1), Tags = lists:seq(0, length(Cons) - 1),
{{builtin, Builtin}, [private], {[{"e", event}],
[{"e", event}],
{switch, v(e), {switch, v(e),
[{Pat(Tag, Types), Clause(Tag, Con, Types)} [{Pat(Tag, Types), Clause(Tag, Con, Types)}
|| {Tag, {constr_t, _, Con, Types}} <- lists:zip(Tags, Cons) ]}, || {Tag, {constr_t, _, Con, Types}} <- lists:zip(Tags, Cons) ]},
{tuple, []}}; {tuple, []}}.
%% Abort primitive. %% Abort primitive.
builtin_function(abort) -> builtin_abort() ->
A = fun(X) -> aeb_opcodes:mnemonic(X) end, A = fun(X) -> aeb_opcodes:mnemonic(X) end,
{{builtin, abort}, [private], {[{"s", string}],
[{"s", string}],
{inline_asm, [A(?PUSH1),0, %% Push a dummy 0 for the first arg {inline_asm, [A(?PUSH1),0, %% Push a dummy 0 for the first arg
A(?REVERT)]}, %% Stack: 0,Ptr A(?REVERT)]}, %% Stack: 0,Ptr
{tuple,[]}}; {tuple,[]}}.
%% Map primitives %% Map primitives
builtin_function(Builtin = {map_lookup, Type}) -> builtin_map_lookup(Type) ->
Ret = aeso_icode:option_typerep(Type), Ret = aeso_icode:option_typerep(Type),
{{builtin, Builtin}, [private], {[{"m", word}, {"k", word}],
[{"m", word}, {"k", word}],
prim_call(?PRIM_CALL_MAP_GET, #integer{value = 0}, prim_call(?PRIM_CALL_MAP_GET, #integer{value = 0},
[#var_ref{name = "m"}, #var_ref{name = "k"}], [#var_ref{name = "m"}, #var_ref{name = "k"}],
[word, word], Ret), [word, word], Ret),
Ret}; Ret}.
builtin_function(Builtin = map_put) -> builtin_map_put() ->
%% We don't need the types for put. %% We don't need the types for put.
{{builtin, Builtin}, [private], {[{"m", word}, {"k", word}, {"v", word}],
[{"m", word}, {"k", word}, {"v", word}],
prim_call(?PRIM_CALL_MAP_PUT, #integer{value = 0}, prim_call(?PRIM_CALL_MAP_PUT, #integer{value = 0},
[v(m), v(k), v(v)], [v(m), v(k), v(v)], [word, word, word], word),
[word, word, word], word), word}.
word};
builtin_function(Builtin = map_delete) -> builtin_map_delete() ->
{{builtin, Builtin}, [private], {[{"m", word}, {"k", word}],
[{"m", word}, {"k", word}],
prim_call(?PRIM_CALL_MAP_DELETE, #integer{value = 0}, prim_call(?PRIM_CALL_MAP_DELETE, #integer{value = 0},
[v(m), v(k)], [v(m), v(k)], [word, word], word),
[word, word], word), word}.
word};
builtin_function(Builtin = map_size) -> builtin_map_size() ->
Name = {builtin, Builtin}, {[{"m", word}],
{Name, [private], [{"m", word}],
prim_call(?PRIM_CALL_MAP_SIZE, #integer{value = 0}, prim_call(?PRIM_CALL_MAP_SIZE, #integer{value = 0},
[v(m)], [word], word), [v(m)], [word], word),
word}; word}.
%% Map builtins %% Map builtins
builtin_function(Builtin = {map_get, Type}) -> builtin_map_get(Type) ->
%% function map_get(m, k) = %% function map_get(m, k) =
%% switch(map_lookup(m, k)) %% switch(map_lookup(m, k))
%% Some(v) => v %% Some(v) => v
{{builtin, Builtin}, [private], {[{"m", word}, {"k", word}],
[{"m", word}, {"k", word}], {switch, ?call({map_lookup, Type}, [v(m), v(k)]), [{option_some(v(v)), v(v)}]},
{switch, ?call({map_lookup, Type}, [v(m), v(k)]), Type}.
[{option_some(v(v)), v(v)}]},
Type};
builtin_function(Builtin = {map_lookup_default, Type}) -> builtin_map_lookup_default(Type) ->
%% function map_lookup_default(m, k, default) = %% function map_lookup_default(m, k, default) =
%% switch(map_lookup(m, k)) %% switch(map_lookup(m, k))
%% None => default %% None => default
%% Some(v) => v %% Some(v) => v
{{builtin, Builtin}, [private], {[{"m", word}, {"k", word}, {"default", Type}],
[{"m", word}, {"k", word}, {"default", Type}],
{switch, ?call({map_lookup, Type}, [v(m), v(k)]), {switch, ?call({map_lookup, Type}, [v(m), v(k)]),
[{option_none(), v(default)}, [{option_none(), v(default)},
{option_some(v(v)), v(v)}]}, {option_some(v(v)), v(v)}]},
Type}; Type}.
builtin_function(Builtin = map_member) -> builtin_map_member() ->
%% function map_member(m, k) : bool = %% function map_member(m, k) : bool =
%% switch(Map.lookup(m, k)) %% switch(Map.lookup(m, k))
%% None => false %% None => false
%% _ => true %% _ => true
{{builtin, Builtin}, [private], {[{"m", word}, {"k", word}],
[{"m", word}, {"k", word}],
{switch, ?call({map_lookup, word}, [v(m), v(k)]), {switch, ?call({map_lookup, word}, [v(m), v(k)]),
[{option_none(), {integer, 0}}, [{option_none(), {integer, 0}},
{{var_ref, "_"}, {integer, 1}}]}, {{var_ref, "_"}, {integer, 1}}]},
word}; word}.
builtin_function(Builtin = {map_upd, Type}) -> builtin_map_upd(Type) ->
%% function map_upd(map, key, fun) = %% function map_upd(map, key, fun) =
%% map_put(map, key, fun(map_get(map, key))) %% map_put(map, key, fun(map_get(map, key)))
{{builtin, Builtin}, [private], {[{"map", word}, {"key", word}, {"valfun", word}],
[{"map", word}, {"key", word}, {"valfun", word}],
?call(map_put, ?call(map_put,
[v(map), v(key), [v(map), v(key),
#funcall{ function = v(valfun), #funcall{ function = v(valfun),
args = [?call({map_get, Type}, [v(map), v(key)])] }]), args = [?call({map_get, Type}, [v(map), v(key)])] }]),
word}; word}.
builtin_function(Builtin = {map_upd_default, Type}) -> builtin_map_upd_default(Type) ->
%% function map_upd(map, key, val, fun) = %% function map_upd(map, key, val, fun) =
%% map_put(map, key, fun(map_lookup_default(map, key, val))) %% map_put(map, key, fun(map_lookup_default(map, key, val)))
{{builtin, Builtin}, [private], {[{"map", word}, {"key", word}, {"val", word}, {"valfun", word}],
[{"map", word}, {"key", word}, {"val", word}, {"valfun", word}],
?call(map_put, ?call(map_put,
[v(map), v(key), [v(map), v(key),
#funcall{ function = v(valfun), #funcall{ function = v(valfun),
args = [?call({map_lookup_default, Type}, [v(map), v(key), v(val)])] }]), args = [?call({map_lookup_default, Type}, [v(map), v(key), v(val)])] }]),
word}; word}.
builtin_function(Builtin = map_from_list) -> builtin_map_from_list() ->
%% function map_from_list(xs, acc) = %% function map_from_list(xs, acc) =
%% switch(xs) %% switch(xs)
%% [] => acc %% [] => acc
%% (k, v) :: xs => map_from_list(xs, acc { [k] = v }) %% (k, v) :: xs => map_from_list(xs, acc { [k] = v })
{{builtin, Builtin}, [private], {[{"xs", {list, {tuple, [word, word]}}}, {"acc", word}],
[{"xs", {list, {tuple, [word, word]}}}, {"acc", word}],
{switch, v(xs), {switch, v(xs),
[{{list, []}, v(acc)}, [{{list, []}, v(acc)},
{{binop, '::', {tuple, [v(k), v(v)]}, v(ys)}, {{binop, '::', {tuple, [v(k), v(v)]}, v(ys)},
?call(map_from_list, ?call(map_from_list,
[v(ys), ?call(map_put, [v(acc), v(k), v(v)])])}]}, [v(ys), ?call(map_put, [v(acc), v(k), v(v)])])}]},
word}; word}.
%% list_concat %% list_concat
%% %%
%% Concatenates two lists. %% Concatenates two lists.
builtin_function(list_concat) -> builtin_list_concat() ->
{{builtin, list_concat}, [private], {[{"l1", {list, word}}, {"l2", {list, word}}],
[{"l1", {list, word}}, {"l2", {list, word}}],
{switch, v(l1), {switch, v(l1),
[{{list, []}, v(l2)}, [{{list, []}, v(l2)},
{{binop, '::', v(hd), v(tl)}, {{binop, '::', v(hd), v(tl)},
{binop, '::', v(hd), ?call(list_concat, [v(tl), v(l2)])}} {binop, '::', v(hd), ?call(list_concat, [v(tl), v(l2)])}}
] ]
}, },
word}; word}.
builtin_function(string_length) -> builtin_string_length() ->
%% function length(str) = %% function length(str) =
%% switch(str) %% switch(str)
%% {n} -> n // (ab)use the representation %% {n} -> n // (ab)use the representation
{{builtin, string_length}, [private], {[{"s", string}],
[{"s", string}],
?DEREF(n, s, ?V(n)), ?DEREF(n, s, ?V(n)),
word}; word}.
%% str_concat - concatenate two strings %% str_concat - concatenate two strings
%% %%
@ -299,9 +350,8 @@ builtin_function(string_length) ->
%% top of the Heap and the address to it is returned. The tricky bit is when %% top of the Heap and the address to it is returned. The tricky bit is when
%% the words from the second string has to be shifted to fit next to the first %% the words from the second string has to be shifted to fit next to the first
%% string. %% string.
builtin_function(string_concat) -> builtin_string_concat() ->
{{builtin, string_concat}, [private], {[{"s1", string}, {"s2", string}],
[{"s1", string}, {"s2", string}],
?DEREF(n1, s1, ?DEREF(n1, s1,
?DEREF(n2, s2, ?DEREF(n2, s2,
{ifte, ?EQ(n2, 0), {ifte, ?EQ(n2, 0),
@ -313,13 +363,12 @@ builtin_function(string_concat) ->
?V(ret) %% Put the actual return value ?V(ret) %% Put the actual return value
]})} ]})}
)), )),
word}; word}.
builtin_function(string_concat_inner1) -> builtin_string_concat_inner1() ->
%% Copy all whole words from the first string, and set up for word fusion %% Copy all whole words from the first string, and set up for word fusion
%% Special case when the length of the first string is divisible by 32. %% Special case when the length of the first string is divisible by 32.
{{builtin, string_concat_inner1}, [private], {[{"n1", word}, {"p1", pointer}, {"n2", word}, {"p2", pointer}],
[{"n1", word}, {"p1", pointer}, {"n2", word}, {"p2", pointer}],
?DEREF(w1, p1, ?DEREF(w1, p1,
{ifte, ?GT(n1, 32), {ifte, ?GT(n1, 32),
{seq, [?V(w1), {inline_asm, [?A(?MSIZE), ?A(?MSTORE)]}, {seq, [?V(w1), {inline_asm, [?A(?MSIZE), ?A(?MSTORE)]},
@ -328,13 +377,12 @@ builtin_function(string_concat_inner1) ->
?call(string_concat_inner2, [?I(32), ?I(0), ?V(n2), ?V(p2)]), ?call(string_concat_inner2, [?I(32), ?I(0), ?V(n2), ?V(p2)]),
?call(string_concat_inner2, [?SUB(32, n1), ?V(w1), ?V(n2), ?V(p2)])} ?call(string_concat_inner2, [?SUB(32, n1), ?V(w1), ?V(n2), ?V(p2)])}
}), }),
word}; word}.
builtin_function(string_concat_inner2) -> builtin_string_concat_inner2() ->
%% Current "work in progess" word 'x', has 'o' bytes that are "free" - fill them from %% Current "work in progess" word 'x', has 'o' bytes that are "free" - fill them from
%% words of the second string. %% words of the second string.
{{builtin, string_concat_inner2}, [private], {[{"o", word}, {"x", word}, {"n2", word}, {"p2", pointer}],
[{"o", word}, {"x", word}, {"n2", word}, {"p2", pointer}],
{ifte, ?LT(n2, 1), {ifte, ?LT(n2, 1),
{seq, [?V(x), {inline_asm, [?A(?MSIZE), ?A(?MSTORE), ?A(?MSIZE)]}]}, %% Use MSIZE as dummy return value {seq, [?V(x), {inline_asm, [?A(?MSIZE), ?A(?MSTORE), ?A(?MSIZE)]}]}, %% Use MSIZE as dummy return value
?DEREF(w2, p2, ?DEREF(w2, p2,
@ -348,61 +396,57 @@ builtin_function(string_concat_inner2) ->
{inline_asm, [?A(?MSIZE), ?A(?MSTORE), ?A(?MSIZE)]}]} %% Use MSIZE as dummy return value {inline_asm, [?A(?MSIZE), ?A(?MSTORE), ?A(?MSIZE)]}]} %% Use MSIZE as dummy return value
}) })
}, },
word}; word}.
builtin_function(str_equal_p) -> builtin_str_equal_p() ->
%% function str_equal_p(n, p1, p2) = %% function str_equal_p(n, p1, p2) =
%% if(n =< 0) true %% if(n =< 0) true
%% else %% else
%% let w1 = *p1 %% let w1 = *p1
%% let w2 = *p2 %% let w2 = *p2
%% w1 == w2 && str_equal_p(n - 32, p1 + 32, p2 + 32) %% w1 == w2 && str_equal_p(n - 32, p1 + 32, p2 + 32)
{{builtin, str_equal_p}, [private], {[{"n", word}, {"p1", pointer}, {"p2", pointer}],
[{"n", word}, {"p1", pointer}, {"p2", pointer}],
{ifte, ?LT(n, 1), {ifte, ?LT(n, 1),
?I(1), ?I(1),
?DEREF(w1, p1, ?DEREF(w1, p1,
?DEREF(w2, p2, ?DEREF(w2, p2,
?AND(?EQ(w1, w2), ?AND(?EQ(w1, w2),
?call(str_equal_p, [?SUB(n, 32), ?NXT(p1), ?NXT(p2)]))))}, ?call(str_equal_p, [?SUB(n, 32), ?NXT(p1), ?NXT(p2)]))))},
word}; word}.
builtin_function(str_equal) -> builtin_str_equal() ->
%% function str_equal(s1, s2) = %% function str_equal(s1, s2) =
%% let n1 = length(s1) %% let n1 = length(s1)
%% let n2 = length(s2) %% let n2 = length(s2)
%% n1 == n2 && str_equal_p(n1, s1 + 32, s2 + 32) %% n1 == n2 && str_equal_p(n1, s1 + 32, s2 + 32)
{{builtin, str_equal}, [private], {[{"s1", string}, {"s2", string}],
[{"s1", string}, {"s2", string}],
?DEREF(n1, s1, ?DEREF(n1, s1,
?DEREF(n2, s2, ?DEREF(n2, s2,
?AND(?EQ(n1, n2), ?call(str_equal_p, [?V(n1), ?NXT(s1), ?NXT(s2)])) ?AND(?EQ(n1, n2), ?call(str_equal_p, [?V(n1), ?NXT(s1), ?NXT(s2)]))
)), )),
word}; word}.
builtin_function(int_to_str) -> builtin_int_to_str() ->
{{builtin, int_to_str}, [private], {[{"i0", word}],
[{"i0", word}],
{switch, {ifte, ?LT(i0, 0), {switch, {ifte, ?LT(i0, 0),
{tuple, [?I(2), ?NEG(i0), ?BSL(45, 31)]}, {tuple, [?I(2), ?NEG(i0), ?BSL(45, 31)]},
{tuple, [?I(1), ?V(i0), ?I(0)]}}, {tuple, [?I(1), ?V(i0), ?I(0)]}},
[{{tuple, [v(off), v(i), v(x)]}, [{{tuple, [v(off), v(i), v(x)]},
?LET(ret, {inline_asm, [?A(?MSIZE)]}, ?LET(ret, {inline_asm, [?A(?MSIZE)]},
?LET(n, ?call(int_digits, [?DIV(i, 10), ?I(0)]), ?LET(n, ?call({int_digits, 10}, [?V(i), ?I(0)]),
?LET(fac, ?EXP(10, n), ?LET(fac, ?EXP(10, n),
{seq, [?ADD(n, off), {inline_asm, [?A(?MSIZE), ?A(?MSTORE)]}, %% Store str len {seq, [?ADD(n, off), {inline_asm, [?A(?MSIZE), ?A(?MSTORE)]}, %% Store str len
?call(int_to_str_, ?call(int_to_str_,
[?MOD(i, fac), ?ADD(x, ?BSL(?ADD(48, ?DIV(i, fac)), ?SUB(32, off))), ?DIV(fac, 10), ?V(off)]), [?MOD(i, fac), ?ADD(x, ?BSL(?ADD(48, ?DIV(i, fac)), ?SUB(32, off))), ?DIV(fac, 10), ?V(off)]),
{inline_asm, [?A(?POP)]}, ?V(ret)]} {inline_asm, [?A(?POP)]}, ?V(ret)]}
)))}]}, )))}]},
word}; word}.
builtin_function(int_to_str_) -> builtin_int_to_str_() ->
{{builtin, int_to_str_}, [private], {[{"x", word}, {"y", word}, {"fac", word}, {"n", word}],
[{"x", word}, {"y", word}, {"fac", word}, {"n", word}],
{ifte, ?EQ(fac, 0), {ifte, ?EQ(fac, 0),
{seq, [?V(y), {inline_asm, [?A(?MSIZE), ?A(?MSTORE)]}, ?V(n)]}, {seq, [?V(y), {inline_asm, [?A(?MSIZE), ?A(?MSTORE)]}, ?V(n)]},
{ifte, ?EQ(?MOD(n, 32), 0), {ifte, ?EQ(n, 32),
%% We've filled a word, write it and start on new word %% We've filled a word, write it and start on new word
{seq, [?V(y), {inline_asm, [?A(?MSIZE), ?A(?MSTORE)]}, {seq, [?V(y), {inline_asm, [?A(?MSIZE), ?A(?MSTORE)]},
?call(int_to_str_, ?call(int_to_str_,
@ -412,47 +456,69 @@ builtin_function(int_to_str_) ->
[?MOD(x, fac), ?ADD(y, ?BSL(?ADD(48, ?DIV(x, fac)), ?SUB(31, n))), [?MOD(x, fac), ?ADD(y, ?BSL(?ADD(48, ?DIV(x, fac)), ?SUB(31, n))),
?DIV(fac, 10), ?ADD(n, 1)])} ?DIV(fac, 10), ?ADD(n, 1)])}
}, },
word}; word}.
builtin_function(int_digits) -> builtin_base58_tab() ->
{{builtin, int_digits}, [private], <<Fst32:256>> = <<"123456789ABCDEFGHJKLMNPQRSTUVWXY">>,
[{"x", word}, {"n", word}], <<Lst26:256>> = <<"Zabcdefghijkmnopqrstuvwxyz", 0:48>>,
{ifte, ?EQ(x, 0), ?V(n), ?call(int_digits, [?DIV(x, 10), ?ADD(n, 1)])}, {[{"ix", word}],
word};
builtin_function(base58_tab) ->
Fst32 = 22252025330403739761829862310514590177935513752035045390683118730099851483225,
Lst26 = 40880219588527126470443504235291962205031881694701834176631306799289575931904,
{{builtin, base58_tab}, [private],
[{"ix", word}],
{ifte, ?LT(ix, 32), {ifte, ?LT(ix, 32),
?BYTE(ix, Fst32), ?BYTE(ix, Fst32),
?BYTE(?SUB(ix, 32), Lst26) ?BYTE(?SUB(ix, 32), Lst26)
}, word}; },
word}.
builtin_function(base58_int) -> builtin_base58_int() ->
{{builtin, base58_int}, [private], {[{"w", word}],
[{"w", word}], ?LET(ret, {inline_asm, [?A(?MSIZE)]},
?LET(str0, ?call(base58_int_encode, [?V(w)]), {seq, [?call(base58_int_pad, [?V(w), ?I(0), ?I(0)]), {inline_asm, [?A(?POP)]}, ?V(ret)]}),
?LET(str1, ?call(base58_int_pad, [?V(w), ?I(0), ?I(0)]), word}.
?LET(str2, ?call(string_concat, [?V(str0), ?V(str1)]),
?call(string_reverse, [?V(str2)])
))),
word};
builtin_function(string_reverse) -> builtin_base58_int_pad() ->
{{builtin, string_reverse}, [private], {[{"src", word}, {"ix", word}, {"dst", word}],
[{"s", string}], {ifte, ?GT(?ADD(?DIV(ix, 31), ?BYTE(ix, src)), 0),
?call(base58_int_encode, [?V(src), ?V(ix), ?V(dst)]),
?call(base58_int_pad, [?V(src), ?ADD(ix, 1), ?ADD(dst, ?BSL($1, ?SUB(31, ix)))])},
word}.
builtin_base58_int_encode() ->
{[{"src", word}, {"ix", word}, {"dst", word}],
?LET(n, ?call({int_digits, 58}, [?V(src), ?I(0)]),
{seq, [?ADD(n, ?ADD(ix, 1)), {inline_asm, [?A(?MSIZE), ?A(?MSTORE)]},
?call(base58_int_encode_, [?V(src), ?V(dst), ?EXP(58, n), ?V(ix)])]}),
word}.
builtin_base58_int_encode_() ->
{[{"src", word}, {"dst", word}, {"fac", word}, {"ix", word}],
{ifte, ?EQ(fac, 0),
{seq, [?V(dst), {inline_asm, [?A(?MSIZE), ?A(?MSTORE), ?A(?MSIZE)]}]},
{ifte, ?EQ(ix, 32),
%% We've filled a word, write it and start on new word
{seq, [?V(dst), {inline_asm, [?A(?MSIZE), ?A(?MSTORE)]},
?call(base58_int_encode_, [?V(src), ?I(0), ?V(fac), ?I(0)])]},
?call(base58_int_encode_,
[?MOD(src, fac), ?ADD(dst, ?BSL(?call(base58_tab, [?DIV(src, fac)]), ?SUB(31, ix))),
?DIV(fac, 58), ?ADD(ix, 1)])}
},
word}.
builtin_int_digits(X) ->
{[{"x0", word}, {"dgts", word}],
?LET(x1, ?DIV(x0, X),
{ifte, ?EQ(x1, 0), ?V(dgts), ?call({int_digits, X}, [?V(x1), ?ADD(dgts, 1)])}),
word}.
builtin_string_reverse() ->
{[{"s", string}],
?DEREF(n, s, ?DEREF(n, s,
?LET(ret, {inline_asm, [?A(?MSIZE)]}, ?LET(ret, {inline_asm, [?A(?MSIZE)]},
{seq, [?V(n), {inline_asm, [?A(?MSIZE), ?A(?MSTORE)]}, {seq, [?V(n), {inline_asm, [?A(?MSIZE), ?A(?MSTORE)]},
?call(string_reverse_, [?NXT(s), ?I(0), ?I(31), ?SUB(?V(n), 1)]), ?call(string_reverse_, [?NXT(s), ?I(0), ?I(31), ?SUB(?V(n), 1)]),
{inline_asm, [?A(?POP)]}, ?V(ret)]})), {inline_asm, [?A(?POP)]}, ?V(ret)]})),
word}; word}.
builtin_function(string_reverse_) -> builtin_string_reverse_() ->
{{builtin, string_reverse_}, [private], {[{"p", pointer}, {"x", word}, {"i1", word}, {"i2", word}],
[{"p", pointer}, {"x", word}, {"i1", word}, {"i2", word}],
{ifte, ?LT(i2, 0), {ifte, ?LT(i2, 0),
{seq, [?V(x), {inline_asm, [?A(?MSIZE), ?A(?MSTORE), ?A(?MSIZE)]}]}, {seq, [?V(x), {inline_asm, [?A(?MSIZE), ?A(?MSTORE), ?A(?MSIZE)]}]},
?LET(p1, ?ADD(p, ?MUL(?DIV(i2, 32), 32)), ?LET(p1, ?ADD(p, ?MUL(?DIV(i2, 32), 32)),
@ -464,47 +530,8 @@ builtin_function(string_reverse_) ->
[?V(p), ?BSL(b, 31), ?I(30), ?SUB(i2, 1)])]}, [?V(p), ?BSL(b, 31), ?I(30), ?SUB(i2, 1)])]},
?call(string_reverse_, ?call(string_reverse_,
[?V(p), ?ADD(x, ?BSL(b, i1)), ?SUB(i1, 1), ?SUB(i2, 1)])})))}, [?V(p), ?ADD(x, ?BSL(b, i1)), ?SUB(i1, 1), ?SUB(i2, 1)])})))},
word};
builtin_function(base58_int_pad) ->
{{builtin, base58_int_pad}, [private],
[{"w", word}, {"i", word}, {"x", word}],
{ifte, ?GT(?BYTE(i, w), 0),
{seq, [?V(i), {inline_asm, [?A(?MSIZE), ?A(?MSTORE)]},
?V(x), {inline_asm, [?A(?MSIZE), ?A(?MSTORE)]},
{inline_asm, [?A(?PUSH1), 64, ?A(?MSIZE), ?A(?SUB)]}]},
?call(base58_int_pad, [?V(w), ?ADD(i, 1),
?ADD(x, ?BSL(49, ?SUB(31, i)))])},
word};
builtin_function(base58_int_encode) ->
{{builtin, base58_int_encode}, [private],
[{"w", word}],
?LET(ret, {inline_asm, [?A(?MSIZE), ?A(?PUSH1), 0, ?A(?MSIZE), ?A(?MSTORE)]}, %% write placeholder
?LET(n, ?call(base58_int_encode_, [?V(w), ?I(0), ?I(0), ?I(31)]),
{seq, [?V(ret), {inline_asm, [?A(?DUP2), ?A(?SWAP1), ?A(?MSTORE)]},
?V(ret)]})),
word};
builtin_function(base58_int_encode_) ->
{{builtin, base58_int_encode_}, [private],
[{"w", word}, {"x", word}, {"n", word}, {"i", word}],
{ifte, ?EQ(w, 0),
{seq, [?V(x), {inline_asm, [?A(?MSIZE), ?A(?MSTORE)]}, ?V(n)]},
{ifte, ?LT(i, 0),
{seq, [?V(x), {inline_asm, [?A(?MSIZE), ?A(?MSTORE)]},
?call(base58_int_encode_,
[?DIV(w, 58), ?BSL(?call(base58_tab, [?MOD(w, 58)]), 31),
?ADD(n, 1), ?I(30)])]},
?call(base58_int_encode_,
[?DIV(w, 58), ?ADD(x, ?BSL(?call(base58_tab, [?MOD(w, 58)]), i)),
?ADD(n, 1), ?SUB(i, 1)])}},
word};
builtin_function(addr_to_str) ->
{{builtin, addr_to_str}, [private],
[{"a", word}],
?call(base58_int, [?V(a)]),
word}. word}.
builtin_addr_to_str() ->
{[{"a", word}], ?call(base58_int, [?V(a)]), word}.