Pt 166148534 refactor fate code (#40)
* Change names of generated aeb_fate_code -> aeb_fate_ops * Break out fate code to separate adt module * Fix documentation of the SPEND op * More compact implementation of serialization/deserialization * Changed argument specification order
This commit is contained in:
parent
2f4e1888c2
commit
11a8997ac7
2
.gitignore
vendored
2
.gitignore
vendored
@ -14,8 +14,8 @@ aeb_fate_asm_scan.xrl
|
|||||||
_build/
|
_build/
|
||||||
aefateasm
|
aefateasm
|
||||||
include/aeb_fate_opcodes.hrl
|
include/aeb_fate_opcodes.hrl
|
||||||
src/aeb_fate_code.erl
|
|
||||||
src/aeb_fate_opcodes.erl
|
src/aeb_fate_opcodes.erl
|
||||||
|
src/aeb_fate_ops.erl
|
||||||
src/aeb_fate_pp.erl
|
src/aeb_fate_pp.erl
|
||||||
*.erl~
|
*.erl~
|
||||||
*.hrl~
|
*.hrl~
|
||||||
|
2
Makefile
2
Makefile
@ -1,4 +1,4 @@
|
|||||||
GENERATED_SRC = src/aeb_fate_opcodes.erl src/aeb_fate_code.erl include/aeb_fate_opcodes.hrl src/aeb_fate_asm_scan.xrl src/aeb_fate_pp.erl
|
GENERATED_SRC = src/aeb_fate_opcodes.erl src/aeb_fate_ops.erl include/aeb_fate_opcodes.hrl src/aeb_fate_asm_scan.xrl src/aeb_fate_pp.erl
|
||||||
GENERATOR_DEPS = ebin/aeb_fate_generate_ops.beam src/aeb_fate_asm_scan.template
|
GENERATOR_DEPS = ebin/aeb_fate_generate_ops.beam src/aeb_fate_asm_scan.template
|
||||||
REBAR ?= rebar3
|
REBAR ?= rebar3
|
||||||
|
|
||||||
|
@ -89,13 +89,11 @@
|
|||||||
|
|
||||||
-export([ assemble_file/3
|
-export([ assemble_file/3
|
||||||
, asm_to_bytecode/2
|
, asm_to_bytecode/2
|
||||||
, bytecode_to_fate_code/2
|
|
||||||
, function_call/1
|
, function_call/1
|
||||||
, pp/1
|
, pp/1
|
||||||
, read_file/1
|
, read_file/1
|
||||||
, strip/1
|
, strip/1
|
||||||
, to_asm/1
|
, to_asm/1
|
||||||
, to_hexstring/1
|
|
||||||
]).
|
]).
|
||||||
|
|
||||||
-include_lib("aebytecode/include/aeb_fate_opcodes.hrl").
|
-include_lib("aebytecode/include/aeb_fate_opcodes.hrl").
|
||||||
@ -132,9 +130,10 @@ pp(FateCode) ->
|
|||||||
io_lib:format("~ts~n",[Listing]).
|
io_lib:format("~ts~n",[Listing]).
|
||||||
|
|
||||||
|
|
||||||
to_asm(#{ functions := Functions
|
to_asm(FateCode) ->
|
||||||
, symbols := Symbols
|
Functions = aeb_fate_code:functions(FateCode),
|
||||||
, annotations := Annotations} = _FateCode) ->
|
Symbols = aeb_fate_code:symbols(FateCode),
|
||||||
|
Annotations = aeb_fate_code:annotations(FateCode),
|
||||||
insert_comments(get_comments(Annotations), 1,
|
insert_comments(get_comments(Annotations), 1,
|
||||||
lists:flatten(
|
lists:flatten(
|
||||||
io_lib:format("~s",
|
io_lib:format("~s",
|
||||||
@ -150,12 +149,6 @@ insert_comments([],_,[]) -> [];
|
|||||||
insert_comments([{L,C}|Rest], _, []) ->
|
insert_comments([{L,C}|Rest], _, []) ->
|
||||||
";; " ++ C ++ "\n" ++ insert_comments(Rest, L + 1, []).
|
";; " ++ C ++ "\n" ++ insert_comments(Rest, L + 1, []).
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
format_functions(Functions, Symbols) ->
|
format_functions(Functions, Symbols) ->
|
||||||
[format(lookup(Name, Symbols),
|
[format(lookup(Name, Symbols),
|
||||||
Sig,
|
Sig,
|
||||||
@ -218,521 +211,22 @@ asm_to_bytecode(AssemblerCode, Options) ->
|
|||||||
none ->
|
none ->
|
||||||
ok
|
ok
|
||||||
end,
|
end,
|
||||||
|
Env = #{ fate_code => aeb_fate_code:new()
|
||||||
|
, functions => #{}
|
||||||
|
},
|
||||||
|
|
||||||
Env = to_bytecode(Tokens, none, #{ functions => #{}
|
Env1 = to_bytecode(Tokens, none, Env, [], Options),
|
||||||
, symbols => #{}
|
FateCode = maps:get(fate_code, Env1),
|
||||||
, annotations => #{}
|
FunctionsMap = maps:get(functions, Env1),
|
||||||
}, [], Options),
|
Functions = [X || {_, X} <- lists:sort(maps:to_list(FunctionsMap))],
|
||||||
|
FunctionsBin = iolist_to_binary(Functions),
|
||||||
ByteList = serialize(Env),
|
ByteCode = aeb_fate_code:serialize(FateCode, FunctionsBin, Options),
|
||||||
Signatures = serialize_sigs(Env),
|
|
||||||
SymbolTable = serialize_symbol_table(Env),
|
|
||||||
Annotatations = serialize_annotations(Env),
|
|
||||||
ByteCode = << (aeser_rlp:encode(list_to_binary(ByteList)))/binary,
|
|
||||||
(aeser_rlp:encode(list_to_binary(Signatures)))/binary,
|
|
||||||
(aeser_rlp:encode(SymbolTable))/binary,
|
|
||||||
(aeser_rlp:encode(Annotatations))/binary
|
|
||||||
>>,
|
|
||||||
|
|
||||||
case proplists:lookup(pp_hex_string, Options) of
|
|
||||||
{pp_hex_string, true} ->
|
|
||||||
io:format("Code: ~s~n",[to_hexstring(ByteList)]);
|
|
||||||
none ->
|
|
||||||
ok
|
|
||||||
end,
|
|
||||||
|
|
||||||
{Env, ByteCode}.
|
{Env, ByteCode}.
|
||||||
|
|
||||||
strip(ByteCode) ->
|
strip(ByteCode) ->
|
||||||
{Code, _Rest} = aeser_rlp:decode_one(ByteCode),
|
{Code, _Rest} = aeser_rlp:decode_one(ByteCode),
|
||||||
Code.
|
Code.
|
||||||
|
|
||||||
bytecode_to_fate_code(Bytes, _Options) ->
|
|
||||||
{ByteCode, Rest1} = aeser_rlp:decode_one(Bytes),
|
|
||||||
{Signatures, Rest2} = aeser_rlp:decode_one(Rest1),
|
|
||||||
{SymbolTable, Rest3} = aeser_rlp:decode_one(Rest2),
|
|
||||||
{Annotations, <<>>} = aeser_rlp:decode_one(Rest3),
|
|
||||||
|
|
||||||
Env1 = deserialize(ByteCode, #{ function => none
|
|
||||||
, bb => 0
|
|
||||||
, current_bb_code => []
|
|
||||||
, functions => #{}
|
|
||||||
, code => #{}
|
|
||||||
}),
|
|
||||||
Env2 = deserialize_signatures(Signatures, Env1),
|
|
||||||
Env3 = deserialize_symbols(SymbolTable, Env2),
|
|
||||||
Env4 = deserialize_annotations(Annotations, Env3),
|
|
||||||
Env4.
|
|
||||||
|
|
||||||
|
|
||||||
deserialize(<<?FUNCTION:8, A, B, C, D, Rest/binary>>,
|
|
||||||
#{ function := none
|
|
||||||
, bb := 0
|
|
||||||
, current_bb_code := []
|
|
||||||
} = Env) ->
|
|
||||||
{Sig, Rest2} = deserialize_signature(Rest),
|
|
||||||
Env2 = Env#{function => {<<A,B,C,D>>, Sig}},
|
|
||||||
deserialize(Rest2, Env2);
|
|
||||||
deserialize(<<?FUNCTION:8, A, B, C, D, Rest/binary>>,
|
|
||||||
#{ function := {F, Sig}
|
|
||||||
, bb := BB
|
|
||||||
, current_bb_code := Code
|
|
||||||
, code := Program
|
|
||||||
, functions := Funs} = Env) ->
|
|
||||||
{NewSig, Rest2} = deserialize_signature(Rest),
|
|
||||||
case Code of
|
|
||||||
[] ->
|
|
||||||
Env2 = Env#{ bb => 0
|
|
||||||
, current_bb_code => []
|
|
||||||
, function => {<<A,B,C,D>>, NewSig}
|
|
||||||
, code => #{}
|
|
||||||
, functions => Funs#{F => {Sig, Program}}},
|
|
||||||
deserialize(Rest2, Env2);
|
|
||||||
_ ->
|
|
||||||
Env2 = Env#{ bb => 0
|
|
||||||
, current_bb_code => []
|
|
||||||
, function => {<<A,B,C,D>>, NewSig}
|
|
||||||
, code => #{}
|
|
||||||
, functions =>
|
|
||||||
Funs#{F => {Sig,
|
|
||||||
Program#{ BB => lists:reverse(Code)}}}},
|
|
||||||
deserialize(Rest2, Env2)
|
|
||||||
end;
|
|
||||||
deserialize(<<Op:8, Rest/binary>>,
|
|
||||||
#{ bb := BB
|
|
||||||
, current_bb_code := Code
|
|
||||||
, code := Program} = Env) ->
|
|
||||||
{Rest2, OpCode} = deserialize_op(Op, Rest, Code),
|
|
||||||
case aeb_fate_opcodes:end_bb(Op) of
|
|
||||||
true ->
|
|
||||||
deserialize(Rest2, Env#{ bb => BB+1
|
|
||||||
, current_bb_code => []
|
|
||||||
, code => Program#{BB =>
|
|
||||||
lists:reverse(OpCode)}});
|
|
||||||
false ->
|
|
||||||
deserialize(Rest2, Env#{ current_bb_code => OpCode})
|
|
||||||
end;
|
|
||||||
deserialize(<<>>, #{ function := {F, Sig}
|
|
||||||
, bb := BB
|
|
||||||
, current_bb_code := Code
|
|
||||||
, code := Program
|
|
||||||
, functions := Funs} = Env) ->
|
|
||||||
FunctionCode =
|
|
||||||
case Code of
|
|
||||||
[] -> Program;
|
|
||||||
_ -> Program#{ BB => lists:reverse(Code)}
|
|
||||||
end,
|
|
||||||
Env#{ bb => 0
|
|
||||||
, current_bb_code => []
|
|
||||||
, function => none
|
|
||||||
, code => #{}
|
|
||||||
, functions => Funs#{F => {Sig, FunctionCode}}}.
|
|
||||||
|
|
||||||
deserialize_op(?SWITCH_VN, Rest, Code) ->
|
|
||||||
<<ArgType:8, Rest2/binary>> = Rest,
|
|
||||||
{Arg0, Rest3} = aeb_fate_encoding:deserialize_one(Rest2),
|
|
||||||
case aeb_fate_encoding:deserialize_one(Rest3) of
|
|
||||||
{L, Rest4} when is_list(L) ->
|
|
||||||
Modifier0 = bits_to_modifier(ArgType band 2#11),
|
|
||||||
immediate = bits_to_modifier((ArgType bsr 2) band 2#11),
|
|
||||||
{Rest4, [{aeb_fate_opcodes:mnemonic(?SWITCH_VN)
|
|
||||||
, {Modifier0, Arg0}
|
|
||||||
, {immediate, L}
|
|
||||||
}
|
|
||||||
| Code]};
|
|
||||||
_ -> exit(bad_argument_to_switch_vn)
|
|
||||||
end;
|
|
||||||
deserialize_op(Op, Rest, Code) ->
|
|
||||||
OpName = aeb_fate_opcodes:mnemonic(Op),
|
|
||||||
case aeb_fate_opcodes:args(Op) of
|
|
||||||
0 -> {Rest, [OpName | Code]};
|
|
||||||
1 ->
|
|
||||||
<<ArgType:8, Rest2/binary>> = Rest,
|
|
||||||
{Arg, Rest3} = aeb_fate_encoding:deserialize_one(Rest2),
|
|
||||||
Modifier = bits_to_modifier(ArgType),
|
|
||||||
{Rest3, [{OpName, {Modifier, Arg}} | Code]};
|
|
||||||
2 ->
|
|
||||||
<<ArgType:8, Rest2/binary>> = Rest,
|
|
||||||
{Arg0, Rest3} = aeb_fate_encoding:deserialize_one(Rest2),
|
|
||||||
{Arg1, Rest4} = aeb_fate_encoding:deserialize_one(Rest3),
|
|
||||||
Modifier0 = bits_to_modifier(ArgType band 2#11),
|
|
||||||
Modifier1 = bits_to_modifier((ArgType bsr 2) band 2#11),
|
|
||||||
{Rest4, [{OpName, {Modifier0, Arg0},
|
|
||||||
{Modifier1, Arg1}} | Code]};
|
|
||||||
3 ->
|
|
||||||
<<ArgType:8, Rest2/binary>> = Rest,
|
|
||||||
{Arg0, Rest3} = aeb_fate_encoding:deserialize_one(Rest2),
|
|
||||||
{Arg1, Rest4} = aeb_fate_encoding:deserialize_one(Rest3),
|
|
||||||
{Arg2, Rest5} = aeb_fate_encoding:deserialize_one(Rest4),
|
|
||||||
Modifier0 = bits_to_modifier(ArgType band 2#11),
|
|
||||||
Modifier1 = bits_to_modifier((ArgType bsr 2) band 2#11),
|
|
||||||
Modifier2 = bits_to_modifier((ArgType bsr 4) band 2#11),
|
|
||||||
{Rest5, [{ OpName
|
|
||||||
, {Modifier0, Arg0}
|
|
||||||
, {Modifier1, Arg1}
|
|
||||||
, {Modifier2, Arg2}}
|
|
||||||
| Code]};
|
|
||||||
4 ->
|
|
||||||
<<ArgType:8, Rest2/binary>> = Rest,
|
|
||||||
{Arg0, Rest3} = aeb_fate_encoding:deserialize_one(Rest2),
|
|
||||||
{Arg1, Rest4} = aeb_fate_encoding:deserialize_one(Rest3),
|
|
||||||
{Arg2, Rest5} = aeb_fate_encoding:deserialize_one(Rest4),
|
|
||||||
{Arg3, Rest6} = aeb_fate_encoding:deserialize_one(Rest5),
|
|
||||||
Modifier0 = bits_to_modifier(ArgType band 2#11),
|
|
||||||
Modifier1 = bits_to_modifier((ArgType bsr 2) band 2#11),
|
|
||||||
Modifier2 = bits_to_modifier((ArgType bsr 4) band 2#11),
|
|
||||||
Modifier3 = bits_to_modifier((ArgType bsr 6) band 2#11),
|
|
||||||
{Rest6, [{ OpName
|
|
||||||
, {Modifier0, Arg0}
|
|
||||||
, {Modifier1, Arg1}
|
|
||||||
, {Modifier2, Arg2}
|
|
||||||
, {Modifier3, Arg3}}
|
|
||||||
| Code]};
|
|
||||||
5 ->
|
|
||||||
<<ArgType:8, ArgType2:8, Rest2/binary>> = Rest,
|
|
||||||
{Arg0, Rest3} = aeb_fate_encoding:deserialize_one(Rest2),
|
|
||||||
{Arg1, Rest4} = aeb_fate_encoding:deserialize_one(Rest3),
|
|
||||||
{Arg2, Rest5} = aeb_fate_encoding:deserialize_one(Rest4),
|
|
||||||
{Arg3, Rest6} = aeb_fate_encoding:deserialize_one(Rest5),
|
|
||||||
{Arg4, Rest7} = aeb_fate_encoding:deserialize_one(Rest6),
|
|
||||||
Modifier0 = bits_to_modifier(ArgType band 2#11),
|
|
||||||
Modifier1 = bits_to_modifier((ArgType bsr 2) band 2#11),
|
|
||||||
Modifier2 = bits_to_modifier((ArgType bsr 4) band 2#11),
|
|
||||||
Modifier3 = bits_to_modifier((ArgType bsr 6) band 2#11),
|
|
||||||
Modifier4 = bits_to_modifier(ArgType2 band 2#11),
|
|
||||||
{Rest7, [{ OpName
|
|
||||||
, {Modifier0, Arg0}
|
|
||||||
, {Modifier1, Arg1}
|
|
||||||
, {Modifier2, Arg2}
|
|
||||||
, {Modifier3, Arg3}
|
|
||||||
, {Modifier4, Arg4}
|
|
||||||
}
|
|
||||||
| Code]};
|
|
||||||
6 ->
|
|
||||||
<<ArgType:8, ArgType2:8, Rest2/binary>> = Rest,
|
|
||||||
{Arg0, Rest3} = aeb_fate_encoding:deserialize_one(Rest2),
|
|
||||||
{Arg1, Rest4} = aeb_fate_encoding:deserialize_one(Rest3),
|
|
||||||
{Arg2, Rest5} = aeb_fate_encoding:deserialize_one(Rest4),
|
|
||||||
{Arg3, Rest6} = aeb_fate_encoding:deserialize_one(Rest5),
|
|
||||||
{Arg4, Rest7} = aeb_fate_encoding:deserialize_one(Rest6),
|
|
||||||
{Arg5, Rest8} = aeb_fate_encoding:deserialize_one(Rest7),
|
|
||||||
Modifier0 = bits_to_modifier(ArgType band 2#11),
|
|
||||||
Modifier1 = bits_to_modifier((ArgType bsr 2) band 2#11),
|
|
||||||
Modifier2 = bits_to_modifier((ArgType bsr 4) band 2#11),
|
|
||||||
Modifier3 = bits_to_modifier((ArgType bsr 6) band 2#11),
|
|
||||||
Modifier4 = bits_to_modifier(ArgType2 band 2#11),
|
|
||||||
Modifier5 = bits_to_modifier((ArgType2 bsr 2) band 2#11),
|
|
||||||
{Rest8, [{ OpName
|
|
||||||
, {Modifier0, Arg0}
|
|
||||||
, {Modifier1, Arg1}
|
|
||||||
, {Modifier2, Arg2}
|
|
||||||
, {Modifier3, Arg3}
|
|
||||||
, {Modifier4, Arg4}
|
|
||||||
, {Modifier5, Arg5}
|
|
||||||
}
|
|
||||||
| Code]};
|
|
||||||
7 ->
|
|
||||||
<<ArgType:8, ArgType2:8, Rest2/binary>> = Rest,
|
|
||||||
{Arg0, Rest3} = aeb_fate_encoding:deserialize_one(Rest2),
|
|
||||||
{Arg1, Rest4} = aeb_fate_encoding:deserialize_one(Rest3),
|
|
||||||
{Arg2, Rest5} = aeb_fate_encoding:deserialize_one(Rest4),
|
|
||||||
{Arg3, Rest6} = aeb_fate_encoding:deserialize_one(Rest5),
|
|
||||||
{Arg4, Rest7} = aeb_fate_encoding:deserialize_one(Rest6),
|
|
||||||
{Arg5, Rest8} = aeb_fate_encoding:deserialize_one(Rest7),
|
|
||||||
{Arg6, Rest9} = aeb_fate_encoding:deserialize_one(Rest8),
|
|
||||||
Modifier0 = bits_to_modifier(ArgType band 2#11),
|
|
||||||
Modifier1 = bits_to_modifier((ArgType bsr 2) band 2#11),
|
|
||||||
Modifier2 = bits_to_modifier((ArgType bsr 4) band 2#11),
|
|
||||||
Modifier3 = bits_to_modifier((ArgType bsr 6) band 2#11),
|
|
||||||
Modifier4 = bits_to_modifier(ArgType2 band 2#11),
|
|
||||||
Modifier5 = bits_to_modifier((ArgType2 bsr 2) band 2#11),
|
|
||||||
Modifier6 = bits_to_modifier((ArgType2 bsr 4) band 2#11),
|
|
||||||
{Rest9, [{ OpName
|
|
||||||
, {Modifier0, Arg0}
|
|
||||||
, {Modifier1, Arg1}
|
|
||||||
, {Modifier2, Arg2}
|
|
||||||
, {Modifier3, Arg3}
|
|
||||||
, {Modifier4, Arg4}
|
|
||||||
, {Modifier5, Arg5}
|
|
||||||
, {Modifier6, Arg6}
|
|
||||||
}
|
|
||||||
| Code]};
|
|
||||||
8 ->
|
|
||||||
<<ArgType:8, ArgType2:8, Rest2/binary>> = Rest,
|
|
||||||
{Arg0, Rest3} = aeb_fate_encoding:deserialize_one(Rest2),
|
|
||||||
{Arg1, Rest4} = aeb_fate_encoding:deserialize_one(Rest3),
|
|
||||||
{Arg2, Rest5} = aeb_fate_encoding:deserialize_one(Rest4),
|
|
||||||
{Arg3, Rest6} = aeb_fate_encoding:deserialize_one(Rest5),
|
|
||||||
{Arg4, Rest7} = aeb_fate_encoding:deserialize_one(Rest6),
|
|
||||||
{Arg5, Rest8} = aeb_fate_encoding:deserialize_one(Rest7),
|
|
||||||
{Arg6, Rest9} = aeb_fate_encoding:deserialize_one(Rest8),
|
|
||||||
{Arg7, Rest10} = aeb_fate_encoding:deserialize_one(Rest9),
|
|
||||||
Modifier0 = bits_to_modifier(ArgType band 2#11),
|
|
||||||
Modifier1 = bits_to_modifier((ArgType bsr 2) band 2#11),
|
|
||||||
Modifier2 = bits_to_modifier((ArgType bsr 4) band 2#11),
|
|
||||||
Modifier3 = bits_to_modifier((ArgType bsr 6) band 2#11),
|
|
||||||
Modifier4 = bits_to_modifier(ArgType2 band 2#11),
|
|
||||||
Modifier5 = bits_to_modifier((ArgType2 bsr 2) band 2#11),
|
|
||||||
Modifier6 = bits_to_modifier((ArgType2 bsr 4) band 2#11),
|
|
||||||
Modifier7 = bits_to_modifier((ArgType2 bsr 6) band 2#11),
|
|
||||||
{Rest10, [{ OpName
|
|
||||||
, {Modifier0, Arg0}
|
|
||||||
, {Modifier1, Arg1}
|
|
||||||
, {Modifier2, Arg2}
|
|
||||||
, {Modifier3, Arg3}
|
|
||||||
, {Modifier4, Arg4}
|
|
||||||
, {Modifier5, Arg5}
|
|
||||||
, {Modifier6, Arg6}
|
|
||||||
, {Modifier7, Arg7}
|
|
||||||
}
|
|
||||||
| Code]}
|
|
||||||
end.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
deserialize_signatures(_Signatures, Env) -> Env.
|
|
||||||
|
|
||||||
deserialize_symbols(Table, Env) ->
|
|
||||||
?FATE_MAP_VALUE(SymbolTable) = aeb_fate_encoding:deserialize(Table),
|
|
||||||
Env#{symbols => SymbolTable}.
|
|
||||||
|
|
||||||
deserialize_annotations(AnnotationsBin, Env) ->
|
|
||||||
?FATE_MAP_VALUE(Annotations) = aeb_fate_encoding:deserialize(AnnotationsBin),
|
|
||||||
Env#{annotations => Annotations}.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
serialize_sigs(_Env) -> [].
|
|
||||||
|
|
||||||
serialize_symbol_table(#{ symbols := Symbols }) ->
|
|
||||||
aeb_fate_encoding:serialize(aeb_fate_data:make_map(Symbols)).
|
|
||||||
|
|
||||||
serialize_annotations(#{ annotations := Annotations}) ->
|
|
||||||
aeb_fate_encoding:serialize(aeb_fate_data:make_map(Annotations)).
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
serialize(#{functions := Functions} =_Env) ->
|
|
||||||
%% Sort the functions oon name to get a canonical serialisation.
|
|
||||||
Code = [[?FUNCTION, Name, serialize_signature(Sig), C] ||
|
|
||||||
{Name, {Sig, C}} <- lists:sort(maps:to_list(Functions))],
|
|
||||||
serialize_code(lists:flatten(Code)).
|
|
||||||
|
|
||||||
|
|
||||||
%% Argument encoding
|
|
||||||
%% Agument Specification Byte
|
|
||||||
%% bitpos: 6 4 2 0
|
|
||||||
%% xx xx xx xx
|
|
||||||
%% Arg3 Arg2 Arg1 Arg0
|
|
||||||
%% For 5-8 args another Argument Spec Byte is used
|
|
||||||
%% Bit pattern
|
|
||||||
%% 00 : stack/unused (depending on instruction)
|
|
||||||
%% 01 : argN
|
|
||||||
%% 10 : varN
|
|
||||||
%% 11 : immediate
|
|
||||||
serialize_code([ {Arg0Type, Arg0}
|
|
||||||
, {Arg1Type, Arg1}
|
|
||||||
, {Arg2Type, Arg2}
|
|
||||||
, {Arg3Type, Arg3}
|
|
||||||
, {Arg4Type, Arg4}
|
|
||||||
, {Arg5Type, Arg5}
|
|
||||||
, {Arg6Type, Arg6}
|
|
||||||
, {Arg7Type, Arg7}
|
|
||||||
| Rest]) ->
|
|
||||||
ArgSpec1 =
|
|
||||||
modifier_bits(Arg0Type) bor
|
|
||||||
(modifier_bits(Arg1Type) bsl 2) bor
|
|
||||||
(modifier_bits(Arg2Type) bsl 4) bor
|
|
||||||
(modifier_bits(Arg3Type) bsl 6),
|
|
||||||
ArgSpec2 =
|
|
||||||
modifier_bits(Arg4Type) bor
|
|
||||||
(modifier_bits(Arg5Type) bsl 2) bor
|
|
||||||
(modifier_bits(Arg6Type) bsl 4) bor
|
|
||||||
(modifier_bits(Arg7Type) bsl 6),
|
|
||||||
[ ArgSpec1
|
|
||||||
, ArgSpec2
|
|
||||||
, serialize_data(Arg0Type, Arg0)
|
|
||||||
, serialize_data(Arg1Type, Arg1)
|
|
||||||
, serialize_data(Arg2Type, Arg2)
|
|
||||||
, serialize_data(Arg3Type, Arg3)
|
|
||||||
, serialize_data(Arg4Type, Arg4)
|
|
||||||
, serialize_data(Arg5Type, Arg5)
|
|
||||||
, serialize_data(Arg6Type, Arg6)
|
|
||||||
, serialize_data(Arg7Type, Arg7)
|
|
||||||
| serialize_code(Rest)];
|
|
||||||
serialize_code([ {Arg0Type, Arg0}
|
|
||||||
, {Arg1Type, Arg1}
|
|
||||||
, {Arg2Type, Arg2}
|
|
||||||
, {Arg3Type, Arg3}
|
|
||||||
, {Arg4Type, Arg4}
|
|
||||||
, {Arg5Type, Arg5}
|
|
||||||
, {Arg6Type, Arg6}
|
|
||||||
| Rest]) ->
|
|
||||||
ArgSpec1 =
|
|
||||||
modifier_bits(Arg0Type) bor
|
|
||||||
(modifier_bits(Arg1Type) bsl 2) bor
|
|
||||||
(modifier_bits(Arg2Type) bsl 4) bor
|
|
||||||
(modifier_bits(Arg3Type) bsl 6),
|
|
||||||
ArgSpec2 =
|
|
||||||
modifier_bits(Arg4Type) bor
|
|
||||||
(modifier_bits(Arg5Type) bsl 2) bor
|
|
||||||
(modifier_bits(Arg6Type) bsl 4),
|
|
||||||
[ ArgSpec1
|
|
||||||
, ArgSpec2
|
|
||||||
, serialize_data(Arg0Type, Arg0)
|
|
||||||
, serialize_data(Arg1Type, Arg1)
|
|
||||||
, serialize_data(Arg2Type, Arg2)
|
|
||||||
, serialize_data(Arg3Type, Arg3)
|
|
||||||
, serialize_data(Arg4Type, Arg4)
|
|
||||||
, serialize_data(Arg5Type, Arg5)
|
|
||||||
, serialize_data(Arg6Type, Arg6)
|
|
||||||
| serialize_code(Rest)];
|
|
||||||
serialize_code([ {Arg0Type, Arg0}
|
|
||||||
, {Arg1Type, Arg1}
|
|
||||||
, {Arg2Type, Arg2}
|
|
||||||
, {Arg3Type, Arg3}
|
|
||||||
, {Arg4Type, Arg4}
|
|
||||||
, {Arg5Type, Arg5}
|
|
||||||
| Rest]) ->
|
|
||||||
ArgSpec1 =
|
|
||||||
modifier_bits(Arg0Type) bor
|
|
||||||
(modifier_bits(Arg1Type) bsl 2) bor
|
|
||||||
(modifier_bits(Arg2Type) bsl 4) bor
|
|
||||||
(modifier_bits(Arg3Type) bsl 6),
|
|
||||||
ArgSpec2 =
|
|
||||||
modifier_bits(Arg4Type) bor
|
|
||||||
(modifier_bits(Arg5Type) bsl 2),
|
|
||||||
[ ArgSpec1
|
|
||||||
, ArgSpec2
|
|
||||||
, serialize_data(Arg0Type, Arg0)
|
|
||||||
, serialize_data(Arg1Type, Arg1)
|
|
||||||
, serialize_data(Arg2Type, Arg2)
|
|
||||||
, serialize_data(Arg3Type, Arg3)
|
|
||||||
, serialize_data(Arg4Type, Arg4)
|
|
||||||
, serialize_data(Arg5Type, Arg5)
|
|
||||||
| serialize_code(Rest)];
|
|
||||||
serialize_code([ {Arg0Type, Arg0}
|
|
||||||
, {Arg1Type, Arg1}
|
|
||||||
, {Arg2Type, Arg2}
|
|
||||||
, {Arg3Type, Arg3}
|
|
||||||
, {Arg4Type, Arg4}
|
|
||||||
| Rest]) ->
|
|
||||||
ArgSpec1 =
|
|
||||||
modifier_bits(Arg0Type) bor
|
|
||||||
(modifier_bits(Arg1Type) bsl 2) bor
|
|
||||||
(modifier_bits(Arg2Type) bsl 4) bor
|
|
||||||
(modifier_bits(Arg3Type) bsl 6),
|
|
||||||
ArgSpec2 =
|
|
||||||
modifier_bits(Arg4Type),
|
|
||||||
[ ArgSpec1
|
|
||||||
, ArgSpec2
|
|
||||||
, serialize_data(Arg0Type, Arg0)
|
|
||||||
, serialize_data(Arg1Type, Arg1)
|
|
||||||
, serialize_data(Arg2Type, Arg2)
|
|
||||||
, serialize_data(Arg3Type, Arg3)
|
|
||||||
, serialize_data(Arg4Type, Arg4)
|
|
||||||
| serialize_code(Rest)];
|
|
||||||
|
|
||||||
serialize_code([ {Arg0Type, Arg0}
|
|
||||||
, {Arg1Type, Arg1}
|
|
||||||
, {Arg2Type, Arg2}
|
|
||||||
, {Arg3Type, Arg3}| Rest]) ->
|
|
||||||
ArgSpec =
|
|
||||||
modifier_bits(Arg0Type) bor
|
|
||||||
(modifier_bits(Arg1Type) bsl 2) bor
|
|
||||||
(modifier_bits(Arg2Type) bsl 4) bor
|
|
||||||
(modifier_bits(Arg3Type) bsl 6),
|
|
||||||
[ ArgSpec
|
|
||||||
, serialize_data(Arg0Type, Arg0)
|
|
||||||
, serialize_data(Arg1Type, Arg1)
|
|
||||||
, serialize_data(Arg2Type, Arg2)
|
|
||||||
, serialize_data(Arg3Type, Arg3)
|
|
||||||
| serialize_code(Rest)];
|
|
||||||
serialize_code([ {Arg0Type, Arg0}
|
|
||||||
, {Arg1Type, Arg1}
|
|
||||||
, {Arg2Type, Arg2}
|
|
||||||
| Rest]) ->
|
|
||||||
ArgSpec =
|
|
||||||
modifier_bits(Arg0Type) bor
|
|
||||||
(modifier_bits(Arg1Type) bsl 2) bor
|
|
||||||
(modifier_bits(Arg2Type) bsl 4),
|
|
||||||
[ArgSpec
|
|
||||||
, serialize_data(Arg0Type, Arg0)
|
|
||||||
, serialize_data(Arg1Type, Arg1)
|
|
||||||
, serialize_data(Arg2Type, Arg2)
|
|
||||||
| serialize_code(Rest)];
|
|
||||||
serialize_code([ {Arg0Type, Arg0}
|
|
||||||
, {Arg1Type, Arg1}
|
|
||||||
| Rest]) ->
|
|
||||||
ArgSpec =
|
|
||||||
modifier_bits(Arg0Type) bor
|
|
||||||
(modifier_bits(Arg1Type) bsl 2),
|
|
||||||
[ArgSpec
|
|
||||||
, serialize_data(Arg0Type, Arg0)
|
|
||||||
, serialize_data(Arg1Type, Arg1)
|
|
||||||
| serialize_code(Rest)];
|
|
||||||
serialize_code([ {Arg0Type, Arg0} | Rest]) ->
|
|
||||||
ArgSpec =
|
|
||||||
modifier_bits(Arg0Type),
|
|
||||||
[ArgSpec
|
|
||||||
, serialize_data(Arg0Type, Arg0)
|
|
||||||
| serialize_code(Rest)];
|
|
||||||
serialize_code([ ?SWITCH_VN
|
|
||||||
, {Arg0Type, Arg0}
|
|
||||||
, {immediate, L}
|
|
||||||
| Rest]) ->
|
|
||||||
ArgSpec =
|
|
||||||
modifier_bits(Arg0Type) bor
|
|
||||||
(modifier_bits(immediate) bsl 2),
|
|
||||||
[?SWITCH_VN
|
|
||||||
, ArgSpec
|
|
||||||
, serialize_data(Arg0Type, Arg0)
|
|
||||||
, serialize_data(immediate, L)] ++ serialize_code(Rest);
|
|
||||||
serialize_code([B|Rest]) ->
|
|
||||||
[B | serialize_code(Rest)];
|
|
||||||
serialize_code([]) -> [].
|
|
||||||
|
|
||||||
|
|
||||||
%% 00 : stack/unused (depending on instruction)
|
|
||||||
%% 01 : argN
|
|
||||||
%% 10 : varN
|
|
||||||
%% 11 : immediate
|
|
||||||
modifier_bits(immediate) -> 2#11;
|
|
||||||
modifier_bits(var) -> 2#10;
|
|
||||||
modifier_bits(arg) -> 2#01;
|
|
||||||
modifier_bits(stack) -> 2#00.
|
|
||||||
|
|
||||||
bits_to_modifier(2#11) -> immediate;
|
|
||||||
bits_to_modifier(2#10) -> var;
|
|
||||||
bits_to_modifier(2#01) -> arg;
|
|
||||||
bits_to_modifier(2#00) -> stack.
|
|
||||||
|
|
||||||
serialize_data(_, Data) ->
|
|
||||||
aeb_fate_encoding:serialize(Data).
|
|
||||||
|
|
||||||
serialize_signature({Args, RetType}) ->
|
|
||||||
[aeb_fate_encoding:serialize_type({tuple, Args}) |
|
|
||||||
aeb_fate_encoding:serialize_type(RetType)].
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
deserialize_signature(Binary) ->
|
|
||||||
{{tuple, Args}, Rest} = aeb_fate_encoding:deserialize_type(Binary),
|
|
||||||
{RetType, Rest2} = aeb_fate_encoding:deserialize_type(Rest),
|
|
||||||
{{Args, RetType}, Rest2}.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
to_hexstring(ByteList) ->
|
|
||||||
"0x" ++ lists:flatten(
|
|
||||||
[io_lib:format("~2.16.0b", [X])
|
|
||||||
|| X <- ByteList]).
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
%% -------------------------------------------------------------------
|
%% -------------------------------------------------------------------
|
||||||
%% Parser
|
%% Parser
|
||||||
%% Asm tokens -> Fate code env
|
%% Asm tokens -> Fate code env
|
||||||
@ -795,8 +289,8 @@ to_bytecode([{signature,_line, {signature, Value}}|Rest],
|
|||||||
[{immediate, aeb_fate_data:make_signature(Value)}|Code],
|
[{immediate, aeb_fate_data:make_signature(Value)}|Code],
|
||||||
Opts);
|
Opts);
|
||||||
to_bytecode([{id,_line, ID}|Rest], Address, Env, Code, Opts) ->
|
to_bytecode([{id,_line, ID}|Rest], Address, Env, Code, Opts) ->
|
||||||
{Hash, Env2} = insert_symbol(ID, Env),
|
{Env2, Id} = insert_symbol(list_to_binary(ID), Env),
|
||||||
to_bytecode(Rest, Address, Env2, [{immediate, Hash}|Code], Opts);
|
to_bytecode(Rest, Address, Env2, [{immediate, Id}|Code], Opts);
|
||||||
to_bytecode([{'{',_line}|Rest], Address, Env, Code, Opts) ->
|
to_bytecode([{'{',_line}|Rest], Address, Env, Code, Opts) ->
|
||||||
{Map, Rest2} = parse_map(Rest),
|
{Map, Rest2} = parse_map(Rest),
|
||||||
to_bytecode(Rest2, Address, Env, [{immediate, Map}|Code], Opts);
|
to_bytecode(Rest2, Address, Env, [{immediate, Map}|Code], Opts);
|
||||||
@ -819,17 +313,8 @@ to_bytecode([{comment, Line, Comment}|Rest], Address, Env, Code, Opts) ->
|
|||||||
Env2 = insert_annotation(comment, Line, Comment, Env),
|
Env2 = insert_annotation(comment, Line, Comment, Env),
|
||||||
to_bytecode(Rest, Address, Env2, Code, Opts);
|
to_bytecode(Rest, Address, Env2, Code, Opts);
|
||||||
|
|
||||||
to_bytecode([], Address, Env, Code, Opts) ->
|
to_bytecode([], Address, Env, Code,_Opts) ->
|
||||||
Env2 = insert_fun(Address, Code, Env),
|
insert_fun(Address, Code, Env).
|
||||||
#{functions := Funs} = Env2,
|
|
||||||
case proplists:lookup(pp_opcodes, Opts) of
|
|
||||||
{pp_opcodes, true} ->
|
|
||||||
Ops = [C || {_Name, {_Sig, C}} <- maps:to_list(Funs)],
|
|
||||||
io:format("opcodes ~p~n", [Ops]);
|
|
||||||
none ->
|
|
||||||
ok
|
|
||||||
end,
|
|
||||||
Env2.
|
|
||||||
|
|
||||||
parse_map([{'}',_line}|Rest]) ->
|
parse_map([{'}',_line}|Rest]) ->
|
||||||
{#{}, Rest};
|
{#{}, Rest};
|
||||||
@ -990,11 +475,24 @@ to_list_of_types(Tokens) ->
|
|||||||
%% State handling
|
%% State handling
|
||||||
|
|
||||||
insert_fun(none, [], Env) -> Env;
|
insert_fun(none, [], Env) -> Env;
|
||||||
insert_fun({Name, Type, RetType}, Code, #{functions := Functions} = Env) ->
|
insert_fun({NameString, ArgType, RetType}, Code, #{ fate_code := FateCode
|
||||||
{Hash, Env2} = insert_symbol(Name, Env),
|
, functions := Funs} = Env) ->
|
||||||
Env2#{
|
Name = list_to_binary(NameString),
|
||||||
functions => Functions#{Hash => {{Type, RetType}, lists:reverse(Code)}}
|
{FateCode1, Id} = aeb_fate_code:insert_symbol(Name, FateCode),
|
||||||
}.
|
BodyByteCode = aeb_fate_code:serialize_code(lists:reverse(Code)),
|
||||||
|
SigByteCode = aeb_fate_code:serialize_signature({ArgType, RetType}),
|
||||||
|
FunByteCode = [?FUNCTION, Id, SigByteCode, BodyByteCode],
|
||||||
|
Env#{ functions => Funs#{ Id => FunByteCode }
|
||||||
|
, fate_code => FateCode1}.
|
||||||
|
|
||||||
|
insert_symbol(Name, #{ fate_code := FateCode } = Env) ->
|
||||||
|
{FateCode1, Id} = aeb_fate_code:insert_symbol(Name, FateCode),
|
||||||
|
{ Env#{ fate_code => FateCode1 }
|
||||||
|
, Id}.
|
||||||
|
|
||||||
|
insert_annotation(comment, Line, Comment, #{ fate_code := FateCode } = Env) ->
|
||||||
|
FateCode1 = aeb_fate_code:insert_annotation(comment, Line, Comment, FateCode),
|
||||||
|
Env#{ fate_code => FateCode1}.
|
||||||
|
|
||||||
mk_hash(Id) ->
|
mk_hash(Id) ->
|
||||||
%% Use first 4 bytes of blake hash
|
%% Use first 4 bytes of blake hash
|
||||||
@ -1003,33 +501,11 @@ mk_hash(Id) ->
|
|||||||
|
|
||||||
%% Handle annotations
|
%% Handle annotations
|
||||||
|
|
||||||
insert_annotation(comment, Line, Comment, #{annotations := A} = Env) ->
|
|
||||||
Key = aeb_fate_data:make_tuple({aeb_fate_data:make_string("comment"), Line}),
|
|
||||||
Value = aeb_fate_data:make_string(Comment),
|
|
||||||
Env#{annotations => A#{ Key => Value}}.
|
|
||||||
|
|
||||||
get_comments(Annotations) ->
|
get_comments(Annotations) ->
|
||||||
[ {Line, Comment} ||
|
[ {Line, Comment} ||
|
||||||
{?FATE_TUPLE({?FATE_STRING_VALUE("comment"), Line}),
|
{?FATE_TUPLE({?FATE_STRING_VALUE("comment"), Line}),
|
||||||
?FATE_STRING_VALUE(Comment)} <- maps:to_list(Annotations)].
|
?FATE_STRING_VALUE(Comment)} <- maps:to_list(Annotations)].
|
||||||
|
|
||||||
%% Symbols handling
|
|
||||||
|
|
||||||
insert_symbol(Id, Env) ->
|
|
||||||
Hash = mk_hash(Id),
|
|
||||||
insert_symbol(Id, Hash, Env).
|
|
||||||
|
|
||||||
insert_symbol(Id, Hash, #{symbols := Symbols} = Env) ->
|
|
||||||
case maps:find(Hash, Symbols) of
|
|
||||||
{ok, Id} -> {Hash, Env};
|
|
||||||
{ok, Id2} ->
|
|
||||||
%% Very unlikely...
|
|
||||||
exit({two_symbols_with_same_hash, Id, Id2});
|
|
||||||
error ->
|
|
||||||
{Hash, Env#{symbols => Symbols#{ Id => Hash
|
|
||||||
, Hash => Id}}}
|
|
||||||
end.
|
|
||||||
|
|
||||||
%% Symbol table handling
|
%% Symbol table handling
|
||||||
|
|
||||||
lookup(Name, Symbols) ->
|
lookup(Name, Symbols) ->
|
||||||
|
329
src/aeb_fate_code.erl
Normal file
329
src/aeb_fate_code.erl
Normal file
@ -0,0 +1,329 @@
|
|||||||
|
%%%-------------------------------------------------------------------
|
||||||
|
%%% @copyright (C) 2019, Aeternity Anstalt
|
||||||
|
%%% @doc
|
||||||
|
%%% ADT for fate byte code/fate code
|
||||||
|
%%% @end
|
||||||
|
%%%
|
||||||
|
%%%-------------------------------------------------------------------
|
||||||
|
-module(aeb_fate_code).
|
||||||
|
|
||||||
|
-export([ annotations/1
|
||||||
|
, deserialize/1
|
||||||
|
, functions/1
|
||||||
|
, insert_annotation/4
|
||||||
|
, insert_fun/4
|
||||||
|
, insert_symbol/2
|
||||||
|
, new/0
|
||||||
|
, serialize/1
|
||||||
|
, serialize/2
|
||||||
|
, serialize/3
|
||||||
|
, serialize_code/1
|
||||||
|
, serialize_signature/1
|
||||||
|
, symbol_identifier/1
|
||||||
|
, symbols/1
|
||||||
|
]).
|
||||||
|
|
||||||
|
-include("../include/aeb_fate_opcodes.hrl").
|
||||||
|
-include("../include/aeb_fate_data.hrl").
|
||||||
|
|
||||||
|
|
||||||
|
-record(fcode, { functions = #{} :: map()
|
||||||
|
, symbols = #{} :: map()
|
||||||
|
, annotations = #{} :: map()
|
||||||
|
}).
|
||||||
|
|
||||||
|
-define(HASH_BYTES, 32).
|
||||||
|
|
||||||
|
%%%===================================================================
|
||||||
|
%%% API
|
||||||
|
%%%===================================================================
|
||||||
|
|
||||||
|
new() ->
|
||||||
|
#fcode{}.
|
||||||
|
|
||||||
|
annotations(#fcode{ annotations = As }) ->
|
||||||
|
As.
|
||||||
|
|
||||||
|
functions(#fcode{ functions = Fs }) ->
|
||||||
|
Fs.
|
||||||
|
|
||||||
|
symbols(#fcode{ symbols = Ss}) ->
|
||||||
|
Ss.
|
||||||
|
|
||||||
|
symbol_identifier(Bin) ->
|
||||||
|
%% First 4 bytes of blake hash
|
||||||
|
{ok, <<X:4/binary,_/binary>> } = eblake2:blake2b(?HASH_BYTES, Bin),
|
||||||
|
X.
|
||||||
|
|
||||||
|
insert_fun(Name, {ArgType, RetType}, #{} = BBs, #fcode{ functions = Funs } = F) ->
|
||||||
|
{F1, ID} = insert_symbol(Name, F),
|
||||||
|
F1#fcode{ functions = Funs#{ ID => {{ArgType, RetType}, BBs}} }.
|
||||||
|
|
||||||
|
insert_symbol(Name, #fcode{ symbols = Syms } = F) ->
|
||||||
|
ID = symbol_identifier(Name),
|
||||||
|
case maps:find(ID, Syms) of
|
||||||
|
{ok, Name} ->
|
||||||
|
{F, ID};
|
||||||
|
{ok, X} ->
|
||||||
|
error({two_symbols_with_same_hash, Name, X});
|
||||||
|
error ->
|
||||||
|
{F#fcode{symbols = Syms#{ ID => Name}}, ID}
|
||||||
|
end.
|
||||||
|
|
||||||
|
insert_annotation(comment =_Type, Line, Comment, #fcode{ annotations = Anns} = F) ->
|
||||||
|
Key = aeb_fate_data:make_tuple({aeb_fate_data:make_string("comment"), Line}),
|
||||||
|
Value = aeb_fate_data:make_string(Comment),
|
||||||
|
F#fcode{ annotations = Anns#{ Key => Value}}.
|
||||||
|
|
||||||
|
%%%===================================================================
|
||||||
|
%%% Serialization
|
||||||
|
%%%===================================================================
|
||||||
|
|
||||||
|
serialize(#fcode{} = F) ->
|
||||||
|
serialize(F, []).
|
||||||
|
|
||||||
|
serialize(#fcode{} = F, Options) ->
|
||||||
|
serialize(F, iolist_to_binary(serialize_functions(F)), Options).
|
||||||
|
|
||||||
|
serialize(#fcode{} = F, Functions, Options) ->
|
||||||
|
SymbolTable = serialize_symbol_table(F),
|
||||||
|
Annotatations = serialize_annotations(F),
|
||||||
|
ByteCode = << (aeser_rlp:encode(Functions))/binary,
|
||||||
|
(aeser_rlp:encode(SymbolTable))/binary,
|
||||||
|
(aeser_rlp:encode(Annotatations))/binary
|
||||||
|
>>,
|
||||||
|
|
||||||
|
case proplists:lookup(pp_hex_string, Options) of
|
||||||
|
{pp_hex_string, true} ->
|
||||||
|
io:format("Code: ~s~n",[to_hexstring(Functions)]);
|
||||||
|
none ->
|
||||||
|
ok
|
||||||
|
end,
|
||||||
|
ByteCode.
|
||||||
|
|
||||||
|
to_hexstring(ByteList) ->
|
||||||
|
"0x" ++ lists:flatten(
|
||||||
|
[io_lib:format("~2.16.0b", [X])
|
||||||
|
|| X <- ByteList]).
|
||||||
|
|
||||||
|
|
||||||
|
serialize_functions(#fcode{ functions = Functions }) ->
|
||||||
|
%% Sort the functions on name to get a canonical serialisation.
|
||||||
|
Code = [[?FUNCTION, Name, serialize_signature(Sig), serialize_bbs(C)] ||
|
||||||
|
{Name, {Sig, C}} <- lists:sort(maps:to_list(Functions))],
|
||||||
|
lists:flatten(Code).
|
||||||
|
|
||||||
|
serialize_signature({Args, RetType}) ->
|
||||||
|
[aeb_fate_encoding:serialize_type({tuple, Args}) |
|
||||||
|
aeb_fate_encoding:serialize_type(RetType)].
|
||||||
|
|
||||||
|
serialize_symbol_table(#fcode{ symbols = Symbols }) ->
|
||||||
|
aeb_fate_encoding:serialize(aeb_fate_data:make_map(Symbols)).
|
||||||
|
|
||||||
|
serialize_annotations(#fcode{ annotations = Annotations}) ->
|
||||||
|
aeb_fate_encoding:serialize(aeb_fate_data:make_map(Annotations)).
|
||||||
|
|
||||||
|
serialize_bbs(#{} = BBs) ->
|
||||||
|
serialize_bbs(BBs, 0, []).
|
||||||
|
|
||||||
|
serialize_bbs(BBs, N, Acc) ->
|
||||||
|
case maps:get(N, BBs, none) of
|
||||||
|
none ->
|
||||||
|
%% Assert that the BBs were contiguous
|
||||||
|
Size = maps:size(BBs),
|
||||||
|
case Size =:= N of
|
||||||
|
true ->
|
||||||
|
lists:reverse(Acc);
|
||||||
|
false ->
|
||||||
|
error({not_contiguous_labels, lists:sort(maps:keys(BBs))})
|
||||||
|
end;
|
||||||
|
BB ->
|
||||||
|
serialize_bbs(BBs, N + 1, [serialize_bb(BB, [])|Acc])
|
||||||
|
end.
|
||||||
|
|
||||||
|
serialize_bb([Op|Rest], Acc) ->
|
||||||
|
serialize_bb(Rest, [serialize_op(Op)|Acc]);
|
||||||
|
serialize_bb([], Acc) ->
|
||||||
|
lists:reverse(Acc).
|
||||||
|
|
||||||
|
serialize_op(Op) when is_tuple(Op) ->
|
||||||
|
[Opcode|Args] = tuple_to_list(Op),
|
||||||
|
[aeb_fate_opcodes:m_to_op(Opcode)|serialize_code(Args)];
|
||||||
|
serialize_op(Opcode) ->
|
||||||
|
[aeb_fate_opcodes:m_to_op(Opcode)].
|
||||||
|
|
||||||
|
%% Argument encoding
|
||||||
|
%% Argument Specification Byte
|
||||||
|
%% bitpos: 6 4 2 0
|
||||||
|
%% xx xx xx xx
|
||||||
|
%% Arg3 Arg2 Arg1 Arg0
|
||||||
|
%% For 5-8 args another Argument Spec Byte is used
|
||||||
|
%% bitpos: 6 4 2 0 | 6 4 2 0
|
||||||
|
%% xx xx xx xx | xx xx xx xx
|
||||||
|
%% Arg7 Arg6 Arg5 Arg4 | Arg3 Arg2 Arg1 Arg0
|
||||||
|
%% Bit pattern
|
||||||
|
%% 00 : stack/unused (depending on instruction)
|
||||||
|
%% 01 : argN
|
||||||
|
%% 10 : varN
|
||||||
|
%% 11 : immediate
|
||||||
|
|
||||||
|
serialize_code([{_,_}|_] = List ) ->
|
||||||
|
%% Take out the full argument list.
|
||||||
|
{Args, Rest} = lists:splitwith(fun({_, _}) -> true; (_) -> false end, List),
|
||||||
|
%% Create the appropriate number of modifier bytes.
|
||||||
|
Mods = << <<(modifier_bits(Type)):2>> || {Type, _} <- pad_args(lists:reverse(Args)) >>,
|
||||||
|
case Mods of
|
||||||
|
<<M1:8, M2:8>> ->
|
||||||
|
[M1, M2 | [serialize_data(Type, Arg) || {Type, Arg} <- Args]] ++
|
||||||
|
serialize_code(Rest);
|
||||||
|
<<M1:8>> ->
|
||||||
|
[M1 | [serialize_data(Type, Arg) || {Type, Arg} <- Args]] ++
|
||||||
|
serialize_code(Rest)
|
||||||
|
end;
|
||||||
|
serialize_code([Op|Rest]) ->
|
||||||
|
[Op|serialize_code(Rest)];
|
||||||
|
serialize_code([]) ->
|
||||||
|
[].
|
||||||
|
|
||||||
|
pad_args(List) ->
|
||||||
|
case length(List) of
|
||||||
|
0 -> List;
|
||||||
|
N when N =< 4 ->
|
||||||
|
lists:duplicate(4 - N, {stack, 0}) ++ List;
|
||||||
|
N when N =< 8 ->
|
||||||
|
lists:duplicate(8 - N, {stack, 0}) ++ List
|
||||||
|
end.
|
||||||
|
|
||||||
|
serialize_data(_, Data) ->
|
||||||
|
aeb_fate_encoding:serialize(Data).
|
||||||
|
|
||||||
|
%% 00 : stack/unused (depending on instruction)
|
||||||
|
%% 01 : argN
|
||||||
|
%% 10 : varN
|
||||||
|
%% 11 : immediate
|
||||||
|
modifier_bits(immediate) -> 2#11;
|
||||||
|
modifier_bits(var) -> 2#10;
|
||||||
|
modifier_bits(arg) -> 2#01;
|
||||||
|
modifier_bits(stack) -> 2#00.
|
||||||
|
|
||||||
|
bits_to_modifier(2#11) -> immediate;
|
||||||
|
bits_to_modifier(2#10) -> var;
|
||||||
|
bits_to_modifier(2#01) -> arg;
|
||||||
|
bits_to_modifier(2#00) -> stack.
|
||||||
|
|
||||||
|
%%%===================================================================
|
||||||
|
%%% Deserialization
|
||||||
|
%%%===================================================================
|
||||||
|
|
||||||
|
deserialize(Bytes) ->
|
||||||
|
{ByteCode, Rest1} = aeser_rlp:decode_one(Bytes),
|
||||||
|
{SymbolTable, Rest2} = aeser_rlp:decode_one(Rest1),
|
||||||
|
{Annotations, <<>>} = aeser_rlp:decode_one(Rest2),
|
||||||
|
|
||||||
|
Env = #{ function => none
|
||||||
|
, bb => 0
|
||||||
|
, current_bb_code => []
|
||||||
|
, functions => #{}
|
||||||
|
, code => #{}
|
||||||
|
},
|
||||||
|
#fcode{ functions = deserialize_functions(ByteCode, Env)
|
||||||
|
, annotations = deserialize_annotations(Annotations)
|
||||||
|
, symbols = deserialize_symbols(SymbolTable)
|
||||||
|
}.
|
||||||
|
|
||||||
|
|
||||||
|
deserialize_functions(<<?FUNCTION:8, A, B, C, D, Rest/binary>>,
|
||||||
|
#{ function := none
|
||||||
|
, bb := 0
|
||||||
|
, current_bb_code := []
|
||||||
|
} = Env) ->
|
||||||
|
{Sig, Rest2} = deserialize_signature(Rest),
|
||||||
|
Env2 = Env#{function => {<<A,B,C,D>>, Sig}},
|
||||||
|
deserialize_functions(Rest2, Env2);
|
||||||
|
deserialize_functions(<<?FUNCTION:8, A, B, C, D, Rest/binary>>,
|
||||||
|
#{ function := {F, Sig}
|
||||||
|
, bb := BB
|
||||||
|
, current_bb_code := Code
|
||||||
|
, code := Program
|
||||||
|
, functions := Funs} = Env) ->
|
||||||
|
{NewSig, Rest2} = deserialize_signature(Rest),
|
||||||
|
case Code of
|
||||||
|
[] ->
|
||||||
|
Env2 = Env#{ bb => 0
|
||||||
|
, current_bb_code => []
|
||||||
|
, function => {<<A,B,C,D>>, NewSig}
|
||||||
|
, code => #{}
|
||||||
|
, functions => Funs#{F => {Sig, Program}}},
|
||||||
|
deserialize_functions(Rest2, Env2);
|
||||||
|
_ ->
|
||||||
|
Env2 = Env#{ bb => 0
|
||||||
|
, current_bb_code => []
|
||||||
|
, function => {<<A,B,C,D>>, NewSig}
|
||||||
|
, code => #{}
|
||||||
|
, functions =>
|
||||||
|
Funs#{F => {Sig,
|
||||||
|
Program#{ BB => lists:reverse(Code)}}}},
|
||||||
|
deserialize_functions(Rest2, Env2)
|
||||||
|
end;
|
||||||
|
deserialize_functions(<<Op:8, Rest/binary>>,
|
||||||
|
#{ bb := BB
|
||||||
|
, current_bb_code := Code
|
||||||
|
, code := Program} = Env) ->
|
||||||
|
{Rest2, OpCode} = deserialize_op(Op, Rest, Code),
|
||||||
|
case aeb_fate_opcodes:end_bb(Op) of
|
||||||
|
true ->
|
||||||
|
deserialize_functions(Rest2, Env#{ bb => BB+1
|
||||||
|
, current_bb_code => []
|
||||||
|
, code => Program#{BB =>
|
||||||
|
lists:reverse(OpCode)}});
|
||||||
|
false ->
|
||||||
|
deserialize_functions(Rest2, Env#{ current_bb_code => OpCode})
|
||||||
|
end;
|
||||||
|
deserialize_functions(<<>>, #{ function := {F, Sig}
|
||||||
|
, bb := BB
|
||||||
|
, current_bb_code := Code
|
||||||
|
, code := Program
|
||||||
|
, functions := Funs}) ->
|
||||||
|
FunctionCode =
|
||||||
|
case Code of
|
||||||
|
[] -> Program;
|
||||||
|
_ -> Program#{ BB => lists:reverse(Code)}
|
||||||
|
end,
|
||||||
|
Funs#{F => {Sig, FunctionCode}}.
|
||||||
|
|
||||||
|
deserialize_op(Op, Rest, Code) ->
|
||||||
|
OpName = aeb_fate_opcodes:mnemonic(Op),
|
||||||
|
case aeb_fate_opcodes:args(Op) of
|
||||||
|
0 ->
|
||||||
|
{Rest, [OpName | Code]};
|
||||||
|
N ->
|
||||||
|
{Args, Rest1} = deserialize_n_args(N, Rest),
|
||||||
|
{Rest1, [list_to_tuple([OpName|Args])|Code]}
|
||||||
|
end.
|
||||||
|
|
||||||
|
deserialize_n_args(N, <<M3:2, M2:2, M1:2, M0:2, Rest/binary>>) when N =< 4 ->
|
||||||
|
ArgMods = lists:sublist([M0, M1, M2, M3], N),
|
||||||
|
lists:mapfoldl(fun(M, Acc) ->
|
||||||
|
{Arg, Acc2} = aeb_fate_encoding:deserialize_one(Acc),
|
||||||
|
{{bits_to_modifier(M), Arg}, Acc2}
|
||||||
|
end, Rest, ArgMods);
|
||||||
|
deserialize_n_args(N, <<M7:2, M6:2, M5:2, M4:2, M3:2, M2:2, M1:2, M0:2,
|
||||||
|
Rest/binary>>) when N =< 8 ->
|
||||||
|
ArgMods = lists:sublist([M0, M1, M2, M3, M4, M5, M6, M7], N),
|
||||||
|
lists:mapfoldl(fun(M, Acc) ->
|
||||||
|
{Arg, Acc2} = aeb_fate_encoding:deserialize_one(Acc),
|
||||||
|
{{bits_to_modifier(M), Arg}, Acc2}
|
||||||
|
end, Rest, ArgMods).
|
||||||
|
|
||||||
|
deserialize_signature(Binary) ->
|
||||||
|
{{tuple, Args}, Rest} = aeb_fate_encoding:deserialize_type(Binary),
|
||||||
|
{RetType, Rest2} = aeb_fate_encoding:deserialize_type(Rest),
|
||||||
|
{{Args, RetType}, Rest2}.
|
||||||
|
|
||||||
|
deserialize_symbols(Table) ->
|
||||||
|
?FATE_MAP_VALUE(SymbolTable) = aeb_fate_encoding:deserialize(Table),
|
||||||
|
SymbolTable.
|
||||||
|
|
||||||
|
deserialize_annotations(AnnotationsBin) ->
|
||||||
|
?FATE_MAP_VALUE(Annotations) = aeb_fate_encoding:deserialize(AnnotationsBin),
|
||||||
|
Annotations.
|
@ -21,7 +21,7 @@ generate(Src, Include) ->
|
|||||||
HrlFile = Include ++ "aeb_fate_opcodes.hrl",
|
HrlFile = Include ++ "aeb_fate_opcodes.hrl",
|
||||||
generate_header_file(HrlFile, Ops),
|
generate_header_file(HrlFile, Ops),
|
||||||
generate_opcodes_ops(aeb_fate_opcodes, HrlFile, Src, Ops),
|
generate_opcodes_ops(aeb_fate_opcodes, HrlFile, Src, Ops),
|
||||||
generate_code_ops(aeb_fate_code, Src, Ops),
|
generate_code_ops(aeb_fate_ops, Src, Ops),
|
||||||
generate_scanner("aeb_fate_asm_scan.template", "aeb_fate_asm_scan.xrl", Src, Ops),
|
generate_scanner("aeb_fate_asm_scan.template", "aeb_fate_asm_scan.xrl", Src, Ops),
|
||||||
gen_asm_pp(aeb_fate_pp, Src, Ops).
|
gen_asm_pp(aeb_fate_pp, Src, Ops).
|
||||||
|
|
||||||
@ -120,7 +120,7 @@ ops_defs() ->
|
|||||||
, { 'LOG4', 16#6a, 6, false, 3, [a,a,a,a,a,a], log, "Create a log message with four topics in the call object."}
|
, { 'LOG4', 16#6a, 6, false, 3, [a,a,a,a,a,a], log, "Create a log message with four topics in the call object."}
|
||||||
, { 'DEACTIVATE', 16#6b, 0, false, 3, atomic, deactivate, "Mark the current contract for deactication."}
|
, { 'DEACTIVATE', 16#6b, 0, false, 3, atomic, deactivate, "Mark the current contract for deactication."}
|
||||||
%% Transaction ops
|
%% Transaction ops
|
||||||
, { 'SPEND', 16#6c, 2, false,3, [a,a], spend, "Transfer Arg0 tokens to account Arg1. (If the contract account has at least that many tokens."}
|
, { 'SPEND', 16#6c, 2, false,3, [a,a], spend, "Transfer Arg1 tokens to account Arg0. (If the contract account has at least that many tokens."}
|
||||||
, { 'ORACLE_REGISTER', 16#6d, 6, false,3, [a,a,a,a,a,a], oracle_register, "Mark the current contract for deactication."}
|
, { 'ORACLE_REGISTER', 16#6d, 6, false,3, [a,a,a,a,a,a], oracle_register, "Mark the current contract for deactication."}
|
||||||
%% TODO:
|
%% TODO:
|
||||||
, { 'ORACLE_QUERY', 16#6e, 0, false,3, atomic, oracle_query, ""}
|
, { 'ORACLE_QUERY', 16#6e, 0, false,3, atomic, oracle_query, ""}
|
||||||
|
@ -25,12 +25,7 @@ read_file(File) ->
|
|||||||
Asm.
|
Asm.
|
||||||
|
|
||||||
assemble(Asm) ->
|
assemble(Asm) ->
|
||||||
{Env, BC} = aeb_fate_asm:asm_to_bytecode(Asm, []),
|
aeb_fate_asm:asm_to_bytecode(Asm, []).
|
||||||
{Env, BC}.
|
|
||||||
|
|
||||||
disassemble(BC) ->
|
|
||||||
aeb_fate_asm:bytecode_to_fate_code(BC, []).
|
|
||||||
|
|
||||||
|
|
||||||
asm_disasm_idenity_test() ->
|
asm_disasm_idenity_test() ->
|
||||||
check_roundtrip(identity).
|
check_roundtrip(identity).
|
||||||
@ -58,12 +53,12 @@ sources() ->
|
|||||||
check_roundtrip(File) ->
|
check_roundtrip(File) ->
|
||||||
AssemblerCode = read_file(File),
|
AssemblerCode = read_file(File),
|
||||||
{_Env, ByteCode} = assemble(AssemblerCode),
|
{_Env, ByteCode} = assemble(AssemblerCode),
|
||||||
FateCode = disassemble(ByteCode),
|
FateCode = aeb_fate_code:deserialize(ByteCode),
|
||||||
DissasmCode = aeb_fate_asm:to_asm(FateCode),
|
DissasmCode = aeb_fate_asm:to_asm(FateCode),
|
||||||
io:format("~s~n", [AssemblerCode]),
|
|
||||||
io:format("~s~n", [DissasmCode]),
|
|
||||||
{_Env2, ByteCode2} = assemble(DissasmCode),
|
{_Env2, ByteCode2} = assemble(DissasmCode),
|
||||||
|
ByteCode3 = aeb_fate_code:serialize(FateCode),
|
||||||
Code1 = aeb_fate_asm:strip(ByteCode),
|
Code1 = aeb_fate_asm:strip(ByteCode),
|
||||||
Code2 = aeb_fate_asm:strip(ByteCode2),
|
Code2 = aeb_fate_asm:strip(ByteCode2),
|
||||||
io:format("~s~n", [aeb_fate_asm:to_asm(disassemble(ByteCode2))]),
|
Code3 = aeb_fate_asm:strip(ByteCode3),
|
||||||
?assertEqual(Code1, Code2).
|
?assertEqual(Code1, Code2),
|
||||||
|
?assertEqual(Code1, Code3).
|
||||||
|
Loading…
x
Reference in New Issue
Block a user