Perform sanity checks both in serialize and deserialize
This commit is contained in:
parent
eeaf646a86
commit
33a1d5f4fb
@ -100,6 +100,7 @@ serialize(#fcode{} = F) ->
|
|||||||
serialize(F, []).
|
serialize(F, []).
|
||||||
|
|
||||||
serialize(#fcode{} = F, Options) ->
|
serialize(#fcode{} = F, Options) ->
|
||||||
|
sanity_check(F),
|
||||||
serialize(F, serialize_functions(F), Options).
|
serialize(F, serialize_functions(F), Options).
|
||||||
|
|
||||||
serialize(#fcode{} = F, Functions, Options) ->
|
serialize(#fcode{} = F, Functions, Options) ->
|
||||||
@ -127,10 +128,8 @@ to_hexstring(ByteList) ->
|
|||||||
serialize_functions(#fcode{ functions = Functions }) ->
|
serialize_functions(#fcode{ functions = Functions }) ->
|
||||||
%% Sort the functions on name to get a canonical serialisation.
|
%% Sort the functions on name to get a canonical serialisation.
|
||||||
iolist_to_binary(
|
iolist_to_binary(
|
||||||
lists:foldr(fun({Id, {Sig, C}}, Acc) when byte_size(Id) == 4 ->
|
lists:foldr(fun({Id, {Sig, C}}, Acc) ->
|
||||||
[[?FUNCTION, Id, serialize_signature(Sig), serialize_bbs(C)] | Acc];
|
[[?FUNCTION, Id, serialize_signature(Sig), serialize_bbs(C)] | Acc]
|
||||||
({Id, _}, _) ->
|
|
||||||
error({illegal_function_id, Id})
|
|
||||||
end, [], lists:sort(maps:to_list(Functions)))).
|
end, [], lists:sort(maps:to_list(Functions)))).
|
||||||
|
|
||||||
serialize_signature({Args, RetType}) ->
|
serialize_signature({Args, RetType}) ->
|
||||||
@ -148,46 +147,70 @@ serialize_bbs(#{} = BBs) ->
|
|||||||
|
|
||||||
serialize_bbs(BBs, N, Acc) ->
|
serialize_bbs(BBs, N, Acc) ->
|
||||||
case maps:get(N, BBs, none) of
|
case maps:get(N, BBs, none) of
|
||||||
none ->
|
none -> lists:reverse(Acc);
|
||||||
%% Assert that the BBs were contiguous
|
BB -> serialize_bbs(BBs, N + 1, [serialize_bb(BB, [])|Acc])
|
||||||
Size = maps:size(BBs),
|
|
||||||
case Size =:= N of
|
|
||||||
true ->
|
|
||||||
lists:reverse(Acc);
|
|
||||||
false ->
|
|
||||||
error({not_contiguous_labels, lists:sort(maps:keys(BBs))})
|
|
||||||
end;
|
|
||||||
[] ->
|
|
||||||
error({empty_code_block, N});
|
|
||||||
BB ->
|
|
||||||
serialize_bbs(BBs, N + 1, [serialize_bb(BB, [])|Acc])
|
|
||||||
end.
|
end.
|
||||||
|
|
||||||
serialize_bb([Op], Acc) ->
|
serialize_bb([Op], Acc) ->
|
||||||
lists:reverse([serialize_op(true, Op)|Acc]);
|
lists:reverse([serialize_op(Op)|Acc]);
|
||||||
serialize_bb([Op|Rest], Acc) ->
|
serialize_bb([Op|Rest], Acc) ->
|
||||||
serialize_bb(Rest, [serialize_op(false, Op)|Acc]).
|
serialize_bb(Rest, [serialize_op(Op)|Acc]).
|
||||||
%% serialize_bb([], Acc) ->
|
|
||||||
%% lists:reverse(Acc).
|
|
||||||
|
|
||||||
serialize_op(Kind, Op) ->
|
serialize_op(Op) ->
|
||||||
[Mnemonic|Args] =
|
[Mnemonic|Args] =
|
||||||
case is_tuple(Op) of
|
case is_tuple(Op) of
|
||||||
true -> tuple_to_list(Op);
|
true -> tuple_to_list(Op);
|
||||||
false -> [Op]
|
false -> [Op]
|
||||||
end,
|
end,
|
||||||
safe_serialize(Kind, aeb_fate_opcodes:m_to_op(Mnemonic), Args).
|
[aeb_fate_opcodes:m_to_op(Mnemonic) | serialize_code(Args)].
|
||||||
|
|
||||||
safe_serialize(Last, Op, Args) ->
|
sanity_check(#fcode{ functions = Funs }) ->
|
||||||
|
_ = [ case Def of
|
||||||
|
{_, BBs} when byte_size(Id) == 4 -> sanity_check_bbs(BBs);
|
||||||
|
_ -> error({illegal_function_id, Id})
|
||||||
|
end || {Id, Def} <- maps:to_list(Funs) ],
|
||||||
|
ok.
|
||||||
|
|
||||||
|
sanity_check_bbs(#{} = BBs) ->
|
||||||
|
sanity_check_bbs(BBs, 0).
|
||||||
|
|
||||||
|
sanity_check_bbs(BBs, N) ->
|
||||||
|
case maps:get(N, BBs, none) of
|
||||||
|
none ->
|
||||||
|
%% Assert that the BBs were contiguous
|
||||||
|
case maps:size(BBs) =:= N of
|
||||||
|
true -> ok;
|
||||||
|
false -> error({not_contiguous_labels, lists:sort(maps:keys(BBs))})
|
||||||
|
end;
|
||||||
|
[] ->
|
||||||
|
error({empty_code_block, N});
|
||||||
|
BB ->
|
||||||
|
sanity_check_bb(BB),
|
||||||
|
sanity_check_bbs(BBs, N + 1)
|
||||||
|
end.
|
||||||
|
|
||||||
|
sanity_check_bb([Op]) ->
|
||||||
|
sanity_check_op(true, Op);
|
||||||
|
sanity_check_bb([Op|Rest]) ->
|
||||||
|
sanity_check_op(false, Op),
|
||||||
|
sanity_check_bb(Rest).
|
||||||
|
|
||||||
|
sanity_check_op(IsLast, Op) ->
|
||||||
|
[Mnemonic|Args] =
|
||||||
|
case is_tuple(Op) of
|
||||||
|
true -> tuple_to_list(Op);
|
||||||
|
false -> [Op]
|
||||||
|
end,
|
||||||
|
safe_sanity_check(IsLast, aeb_fate_opcodes:m_to_op(Mnemonic), Args).
|
||||||
|
|
||||||
|
safe_sanity_check(IsLast, Op, Args) ->
|
||||||
case length(Args) == aeb_fate_opcodes:args(Op) of
|
case length(Args) == aeb_fate_opcodes:args(Op) of
|
||||||
true ->
|
true ->
|
||||||
case Last == aeb_fate_opcodes:end_bb(Op) of
|
case IsLast == aeb_fate_opcodes:end_bb(Op) of
|
||||||
true -> [Op|serialize_code(Args)];
|
true -> ok;
|
||||||
false ->
|
false -> error({wrong_opcode_in_bb, Op})
|
||||||
error({wrong_opcode_in_bb, Op})
|
|
||||||
end;
|
end;
|
||||||
false ->
|
false -> error({wrong_nr_args_opcode, Op})
|
||||||
error({wrong_nr_args_opcode, Op})
|
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
|
||||||
@ -266,10 +289,13 @@ deserialize(Bytes) ->
|
|||||||
, functions => #{}
|
, functions => #{}
|
||||||
, code => #{}
|
, code => #{}
|
||||||
},
|
},
|
||||||
#fcode{ functions = deserialize_functions(ByteCode, Env)
|
Fcode =
|
||||||
, annotations = deserialize_annotations(Annotations)
|
#fcode{ functions = deserialize_functions(ByteCode, Env)
|
||||||
, symbols = deserialize_symbols(SymbolTable)
|
, annotations = deserialize_annotations(Annotations)
|
||||||
}.
|
, symbols = deserialize_symbols(SymbolTable)
|
||||||
|
},
|
||||||
|
sanity_check(Fcode),
|
||||||
|
Fcode.
|
||||||
|
|
||||||
|
|
||||||
deserialize_functions(<<?FUNCTION:8, A, B, C, D, Rest/binary>>,
|
deserialize_functions(<<?FUNCTION:8, A, B, C, D, Rest/binary>>,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user