ling_disasm.erl 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492
  1. %% Copyright (c) 2013-2014 Cloudozer LLP. All rights reserved.
  2. %%
  3. %% Redistribution and use in source and binary forms, with or without
  4. %% modification, are permitted provided that the following conditions are met:
  5. %%
  6. %% * Redistributions of source code must retain the above copyright notice, this
  7. %% list of conditions and the following disclaimer.
  8. %%
  9. %% * Redistributions in binary form must reproduce the above copyright notice,
  10. %% this list of conditions and the following disclaimer in the documentation
  11. %% and/or other materials provided with the distribution.
  12. %%
  13. %% * Redistributions in any form must be accompanied by information on how to
  14. %% obtain complete source code for the LING software and any accompanying
  15. %% software that uses the LING software. The source code must either be included
  16. %% in the distribution or be available for no more than the cost of distribution
  17. %% plus a nominal fee, and must be freely redistributable under reasonable
  18. %% conditions. For an executable file, complete source code means the source
  19. %% code for all modules it contains. It does not include source code for modules
  20. %% or files that typically accompany the major components of the operating
  21. %% system on which the executable file runs.
  22. %%
  23. %% THIS SOFTWARE IS PROVIDED BY CLOUDOZER LLP ``AS IS'' AND ANY EXPRESS OR
  24. %% IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  25. %% MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE
  26. %% DISCLAIMED. IN NO EVENT SHALL CLOUDOZER LLP BE LIABLE FOR ANY DIRECT,
  27. %% INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  28. %% (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  29. %% LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  30. %% ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  31. %% (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  32. %% SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  33. -module(ling_disasm).
  34. -export([beam/1]).
  35. -include("ling_code.hrl").
  36. -define(tag_u, 0).
  37. -define(tag_i, 1).
  38. -define(tag_a, 2).
  39. -define(tag_x, 3).
  40. -define(tag_y, 4).
  41. -define(tag_f, 5).
  42. -define(tag_h, 6).
  43. -define(tag_z, 7).
  44. -define(CODE_CHUNK, "Code").
  45. -define(STR_CHUNK, "StrT").
  46. -define(LIT_CHUNK, "LitT").
  47. -define(FUN_CHUNK, "FunT").
  48. -define(ATTR_CHUNK, "Attr").
  49. -define(CINF_CHUNK, "CInf").
  50. -define(LINE_CHUNK, "Line").
  51. -define(ABST_CHUNK, "Abst").
  52. -record(da, {atoms,literals,lambdas,imports,exports}).
  53. beam(Beam) -> %% {ok,#m{}}
  54. ChunkNames = [?CODE_CHUNK,
  55. atoms,indexed_imports,labeled_exports,?STR_CHUNK,abstract_code],
  56. {ok,{Module,[{?CODE_CHUNK,HdrCodeBin},
  57. {atoms,Atoms},
  58. {indexed_imports,Imports},
  59. {labeled_exports,Exports},
  60. {?STR_CHUNK,StrTabBin},
  61. {abstract_code,_AbstCode}]}} =
  62. beam_lib:chunks(Beam, ChunkNames),
  63. %% AbstCode = no_abstract_code | {raw_abstract_v1,Forms}
  64. %%TODO: make this an option
  65. AbstCode = no_abstract_code,
  66. Literals = case optional_chunk(Beam, ?LIT_CHUNK) of
  67. missing ->
  68. [];
  69. LitBin ->
  70. decode_literals(LitBin)
  71. end,
  72. Lambdas = case optional_chunk(Beam, ?FUN_CHUNK) of
  73. missing ->
  74. [];
  75. FunBin ->
  76. decode_lambdas(FunBin, Atoms)
  77. end,
  78. %%mad:info("Lambdas=~p~n", [Lambdas]),
  79. Attrs = case optional_chunk(Beam, ?ATTR_CHUNK) of
  80. missing ->
  81. undefined;
  82. AttrBin ->
  83. binary_to_term(AttrBin)
  84. end,
  85. CInfs = case optional_chunk(Beam, ?CINF_CHUNK) of
  86. missing ->
  87. undefined;
  88. CInfBin ->
  89. binary_to_term(CInfBin)
  90. end,
  91. <<16:32, %% header size
  92. 0:32, %% BEAM format number
  93. _MaxOpCode:32,
  94. _NumLabels:32,
  95. _NumFunctions:32,CodeBin/binary>> = HdrCodeBin,
  96. St = #da{atoms=Atoms,
  97. literals=Literals,
  98. lambdas=Lambdas,
  99. imports=Imports,
  100. exports=Exports},
  101. Code = disasm_code(CodeBin, St),
  102. LineInfo = case optional_chunk(Beam, ?LINE_CHUNK) of
  103. missing ->
  104. undefined;
  105. LineBin ->
  106. decode_line_info(LineBin)
  107. end,
  108. lists:foreach(fun(Op) ->
  109. %%mad:info("~p~n", [Op]),
  110. validate(Op)
  111. end, Code),
  112. {ok,#m{mod_name=Module,
  113. code =Code,
  114. exports =Exports,
  115. lambdas =Lambdas,
  116. strings =StrTabBin,
  117. attrs =Attrs,
  118. compile_info =CInfs,
  119. line_info =LineInfo,
  120. abst_code =AbstCode}}.
  121. optional_chunk(Beam, ChunkName) ->
  122. case beam_lib:chunks(Beam, [ChunkName]) of
  123. {error,beam_lib,{missing_chunk,_,_}} ->
  124. missing;
  125. {ok,{_,[{_,Chunk}]}} ->
  126. Chunk
  127. end.
  128. decode_literals(<<_:32,Compressed/binary>>) ->
  129. <<_:32,Tab/binary>> = case catch zlib:uncompress(Compressed) of
  130. {'EXIT',_} -> %% BEAM uses noop zlib
  131. Compressed;
  132. X ->
  133. X
  134. end,
  135. decode_literals_1(Tab, 0).
  136. decode_literals_1(<<Sz:32,Ext:Sz/binary,Rest/binary>>, Index) ->
  137. [{Index,binary_to_term(Ext)}|decode_literals_1(Rest, Index+1)];
  138. decode_literals_1(<<>>, _) -> [].
  139. decode_lambdas(<<_:32,Tab/binary>>, Atoms) ->
  140. decode_lambdas_1(Tab, Atoms, 0). %% NB: sorting order is not by Index
  141. decode_lambdas_1(<<F:32,A:32,Lab:32,Index:32,NFree:32,OldUniq:32,More/binary>>,
  142. Atoms, OldIndex) ->
  143. Info = {lookup(F, Atoms),A,Lab,Index,NFree,OldUniq},
  144. [Info|decode_lambdas_1(More, Atoms, OldIndex+1)];
  145. decode_lambdas_1(<<>>, _, _) -> [].
  146. disasm_code(Code, St) ->
  147. disasm_code(Code, St, []).
  148. disasm_code(<<>>, _St, Acc) ->
  149. lists:reverse(Acc);
  150. disasm_code(<<OpCode,Code/binary>>, St, Acc) ->
  151. {OpName,Arity} = beam_opcodes:opname(OpCode),
  152. {Args,More} = decode_args(Code, Arity, [], St),
  153. disasm_code(More, St, [decorate(OpName, Args, St)|Acc]).
  154. decode_line_info(<<0:32, %% Version
  155. Flags:32,
  156. NI:32,
  157. NT:32,
  158. NF:32,LBin/binary>>) ->
  159. decode_line_info(LBin, {Flags,NI,NT,NF}, 1, nofile, []).
  160. decode_line_info(LBin, {_,_,NT,_}=D, T, CF, Acc) when T =< NT ->
  161. case decode_arg(LBin, nostate) of
  162. {{a,FileIndex},More} ->
  163. decode_line_info(More, D, T, FileIndex, Acc);
  164. {{i,Line},More} ->
  165. decode_line_info(More, D, T+1, CF, [{CF,Line}|Acc])
  166. end;
  167. decode_line_info(LBin, D, _, _, Acc) ->
  168. Items = lists:reverse(Acc),
  169. decode_line_info2(LBin, D, Items, 1, []).
  170. decode_line_info2(<<Sz:16,Name:Sz/binary,LBin/binary>>,
  171. {_,_,_,NF}=D, Items, F, Acc) when F =< NF ->
  172. NameStr = binary_to_list(Name),
  173. decode_line_info2(LBin, D, Items, F+1, [NameStr|Acc]);
  174. decode_line_info2(_, {Flags,NI,_,_}, Items, _, Acc) ->
  175. Files = lists:reverse(Acc),
  176. {Flags,NI,Items,Files}.
  177. decode_args(Code, 0, Acc, _St) ->
  178. {lists:reverse(Acc),Code};
  179. decode_args(Code, N, Acc, St) ->
  180. {Arg,MoreCode} = decode_arg(Code, St),
  181. decode_args(MoreCode, N-1, [Arg|Acc], St).
  182. decode_arg(<<0:4,0:1,?tag_z:3,Float:64/float,Code/binary>>, _St) ->
  183. {{float,Float},Code};
  184. decode_arg(<<1:4,0:1,?tag_z:3,Code/binary>>, St) ->
  185. {Len,MoreCode} = decode_arg(Code, St),
  186. {List,EvenMore} = decode_list(MoreCode, Len, St),
  187. {{list,List},EvenMore};
  188. decode_arg(<<2:4,0:1,?tag_z:3,Code/binary>>, St) ->
  189. {R,MoreCode} = decode_arg(Code, St),
  190. {{fr,R},MoreCode};
  191. decode_arg(<<3:4,0:1,?tag_z:3,LenCode/binary>>, St) ->
  192. {Len = 2,Code} = decode_arg(LenCode, St),
  193. case decode_list(Code, 2*Len, St) of
  194. {[0,Words,1,Floats],MoreCode} ->
  195. {{alloc,[{words,Words},{floats,Floats}]},MoreCode};
  196. {[1,Floats,0,Words],MoreCode} ->
  197. {{alloc,[{words,Words},{floats,Floats}]},MoreCode}
  198. end;
  199. decode_arg(<<4:4,0:1,?tag_z:3,Code/binary>>, St) ->
  200. {Index,MoreCode} = decode_arg(Code, St),
  201. {{literal,lookup(Index, St#da.literals)},MoreCode};
  202. decode_arg(<<V:4,0:1,Tag:3,Code/binary>>, St) ->
  203. {decode_tag(Tag, V, St),Code};
  204. decode_arg(<<V1:3,1:2,Tag:3,V2,Code/binary>>, St) ->
  205. {decode_tag(Tag, (V1 bsl 8) bor V2, St),Code};
  206. decode_arg(<<31:5,Tag:3,Code/binary>>, St) ->
  207. {S,BytesCode} = decode_arg(Code, St),
  208. Size = S+9,
  209. <<Bytes:Size/binary,MoreCode/binary>> = BytesCode,
  210. {decode_tag(Tag, bytes_to_value(Bytes), St),MoreCode};
  211. decode_arg(<<S:3,3:2,Tag:3,Code/binary>>, St) ->
  212. Size = S+2,
  213. <<Bytes:Size/binary,MoreCode/binary>> = Code,
  214. {decode_tag(Tag, bytes_to_value(Bytes), St),MoreCode}.
  215. decode_tag(?tag_x, X, _St) -> {x,X};
  216. decode_tag(?tag_y, Y, _St) -> {y,Y};
  217. decode_tag(?tag_a, Index, nostate) -> {a,Index};
  218. decode_tag(?tag_a, 0, _St) -> nil;
  219. decode_tag(?tag_a, Index, St) -> {a,lookup(Index, St#da.atoms)};
  220. decode_tag(?tag_i, I, _St) -> {i,I};
  221. decode_tag(?tag_f, L, _St) -> {f,L};
  222. decode_tag(?tag_u, N, _St) -> N.
  223. bytes_to_value(<<Digit,_/binary>> = Bytes) when Digit > 127 ->
  224. negative_bytes_to_value(Bytes, 0, 1);
  225. bytes_to_value(Bytes) ->
  226. bytes_to_value(Bytes, 0).
  227. bytes_to_value(<<>>, Acc) ->
  228. Acc;
  229. bytes_to_value(<<N,Bytes/binary>>, Acc) ->
  230. bytes_to_value(Bytes, (Acc bsl 8) bor N).
  231. negative_bytes_to_value(<<>>, Acc, Z) ->
  232. Acc - Z;
  233. negative_bytes_to_value(<<N,Bytes/binary>>, Acc, Z) ->
  234. negative_bytes_to_value(Bytes, (Acc bsl 8) bor N, (Z bsl 8)).
  235. decode_list(Code, N, St) ->
  236. decode_list(Code, N, St, []).
  237. decode_list(Code, 0, _St, Acc) ->
  238. {lists:reverse(Acc),Code};
  239. decode_list(Code, N, St, Acc) ->
  240. {Arg,MoreCode} = decode_arg(Code, St),
  241. decode_list(MoreCode, N-1, St, [Arg|Acc]).
  242. lookup(Key, List) ->
  243. {_, Val} = lists:keyfind(Key, 1, List),
  244. Val.
  245. lookup_import(E, St) ->
  246. {_,M,F,A} = lists:keyfind(E+1, 1, St#da.imports),
  247. [{a,M},{a,F},A].
  248. decorate(call_ext=Op, [_A,E], St) ->
  249. {Op,lookup_import(E, St)};
  250. decorate(call_ext_last=Op, [_A,E,D], St) ->
  251. {Op,lookup_import(E, St) ++ [D]};
  252. decorate(call_ext_only=Op, [_A,E], St) ->
  253. {Op,lookup_import(E, St)};
  254. decorate(bif0=Op, [E,D], St) ->
  255. [M,F,A] = lookup_import(E, St),
  256. {Op,[M,F,A,D]};
  257. decorate(bif1=Op, [Fail,E,S,D], St) ->
  258. [M,F,A] = lookup_import(E, St),
  259. {Op,[Fail,M,F,A,S,D]};
  260. decorate(bif2=Op, [Fail,E,S1,S2,D], St) ->
  261. [M,F,A] = lookup_import(E, St),
  262. {Op,[Fail,M,F,A,S1,S2,D]};
  263. decorate(gc_bif1=Op, [Fail,Live,E,S,D], St) ->
  264. [M,F,A] = lookup_import(E, St),
  265. {Op,[Fail,Live,M,F,A,S,D]};
  266. decorate(gc_bif2=Op, [Fail,Live,E,S1,S2,D], St) ->
  267. [M,F,A] = lookup_import(E, St),
  268. {Op,[Fail,Live,M,F,A,S1,S2,D]};
  269. decorate(gc_bif3=Op, [Fail,Live,E,S1,S2,S3,D], St) ->
  270. [M,F,A] = lookup_import(E, St),
  271. {Op,[Fail,Live,M,F,A,S1,S2,S3,D]};
  272. %decorate(make_fun2=Op, [OldIndex], St) ->
  273. % {_,_,_,_,NumFree,_} = lookup(OldIndex, St#da.lambdas),
  274. % {Op,[OldIndex,NumFree]};
  275. decorate(is_function2=Op,[{f,_}=F,{x,_}=X,{i,N}], _St) ->
  276. {Op,[F,X,N]};
  277. decorate(is_function2=Op,[{f,_}=F,{y,_}=Y,{i,N}], _St) ->
  278. {Op,[F,Y,N]};
  279. decorate(OpName, [], _St) ->
  280. OpName;
  281. decorate(OpName, Args, _St) ->
  282. {OpName,Args}.
  283. -define(U(X), (is_integer(X) andalso X >= 0)).
  284. validate({allocate,[U1,U2]}) when ?U(U1), ?U(U2) -> ok;
  285. validate({allocate_heap,[U1,{alloc,_},U2]}) when ?U(U1), ?U(U2) -> ok;
  286. validate({allocate_heap,[U1,U2,U3]}) when ?U(U1), ?U(U2), ?U(U3) -> ok;
  287. validate({allocate_heap_zero,[U1,{alloc,_},U2]}) when ?U(U1), ?U(U2) -> ok;
  288. validate({allocate_heap_zero,[U1,U2,U3]}) when ?U(U1), ?U(U2), ?U(U3) -> ok;
  289. validate({allocate_zero,[U1,U2]}) when ?U(U1), ?U(U2) -> ok;
  290. validate({apply,[U]}) when ?U(U) -> ok;
  291. validate({apply_last,[U1,U2]}) when ?U(U1), ?U(U2) -> ok;
  292. validate({badmatch,[S]}) -> src(S);
  293. validate({bif0,[{a,_},{a,_},U,D]}) when ?U(U) -> dst(D);
  294. validate({bif1,[{f,_},{a,_},{a,_},U,S,D]}) when ?U(U) -> src(S), dst(D);
  295. validate({bif2,[{f,_},{a,_},{a,_},U,S1,S2,D]}) when ?U(U) -> src(S1), src(S2), dst(D);
  296. validate({bs_add,[{f,_},S1,S2,U,{x,_}]}) when ?U(U) -> src(S1), src(S2);
  297. validate({bs_append,[{f,_},S,U1,U2,U3,_D,U4,{x,_}]}) when ?U(U1), ?U(U2), ?U(U3), ?U(U4) -> src(S); %%, dst(D);
  298. validate({bs_context_to_binary,[D]}) -> dst(D);
  299. validate({bs_get_binary2,[{f,_},{x,_},U1,S,U2,U3,{x,_}]}) when ?U(U1), ?U(U2), ?U(U3) -> src(S);
  300. validate({bs_get_float2,[{f,_},{x,_},U1,S,U2,U3,{x,_}]}) when ?U(U1), ?U(U2), ?U(U3) -> src(S);
  301. validate({bs_get_integer2,[{f,_},{x,_},U1,S,U2,U3,{x,_}]}) when ?U(U1), ?U(U2), ?U(U3) -> src(S);
  302. validate({bs_get_utf16,[{f,_},{x,_},U1,U2,{x,_}]}) when ?U(U1), ?U(U2) -> ok;
  303. validate({bs_get_utf32,[{f,_},{x,_},U1,U2,{x,_}]}) when ?U(U1), ?U(U2) -> ok;
  304. validate({bs_get_utf8,[{f,_},{x,_},U1,U2,{x,_}]}) when ?U(U1), ?U(U2) -> ok;
  305. validate({bs_init2,[{f,_},U1,U2,U3,U4,{x,_}]}) when ?U(U1), ?U(U2), ?U(U3), ?U(U4) -> ok;
  306. validate({bs_init2,[{f,_},{x,_},U1,U2,U3,{x,_}]}) when ?U(U1), ?U(U2), ?U(U3) -> ok;
  307. validate({bs_init_bits,[{f,_},U1,U2,U3,U4,{x,_}]}) when ?U(U1), ?U(U2), ?U(U3), ?U(U4) -> ok;
  308. validate({bs_init_bits,[{f,_},{x,_},U1,U2,U3,{x,_}]}) when ?U(U1), ?U(U2), ?U(U3) -> ok;
  309. validate(bs_init_writable) -> ok;
  310. validate({bs_match_string,[{f,_},{x,_},U1,U2]}) when ?U(U1), ?U(U2) -> ok;
  311. validate({bs_private_append,[{f,_},S,U1,D,U2,{x,_}]}) when ?U(U1), ?U(U2) -> src(S), dst(D);
  312. validate({bs_put_binary,[{f,_},S1,U1,U2,S2]}) when ?U(U1), ?U(U2) -> src(S1), src(S2);
  313. validate({bs_put_float,[{f,_},S1,U1,U2,S2]}) when ?U(U1), ?U(U2) -> src(S1), src(S2);
  314. validate({bs_put_integer,[{f,_},S1,U1,U2,S2]}) when ?U(U1), ?U(U2) -> src(S1), src(S2);
  315. validate({bs_put_string,[U1,U2]}) when ?U(U1), ?U(U2) -> ok;
  316. validate({bs_put_utf16,[{f,_},U,D]}) when ?U(U) -> dst(D);
  317. validate({bs_put_utf32,[{f,_},U,D]}) when ?U(U) -> dst(D);
  318. validate({bs_put_utf8,[{f,_},U,D]}) when ?U(U) -> dst(D);
  319. validate({bs_restore2,[{x,_},{a,_}]}) -> ok;
  320. validate({bs_restore2,[{x,_},U]}) when ?U(U) -> ok;
  321. validate({bs_save2,[{x,_},{a,_}]}) -> ok;
  322. validate({bs_save2,[{x,_},U]}) when ?U(U) -> ok;
  323. validate({bs_skip_bits2,[{f,_},{x,_},S,U1,U2]}) when ?U(U1), ?U(U2) -> src(S);
  324. validate({bs_skip_utf16,[{f,_},{x,_},U1,U2]}) when ?U(U1), ?U(U2) -> ok;
  325. validate({bs_skip_utf32,[{f,_},{x,_},U1,U2]}) when ?U(U1), ?U(U2) -> ok;
  326. validate({bs_skip_utf8,[{f,_},{x,_},U1,U2]}) when ?U(U1), ?U(U2) -> ok;
  327. validate({bs_start_match2,[{f,_},D,U1,U2,{x,_}]}) when ?U(U1), ?U(U2) -> dst(D);
  328. validate({bs_test_tail2,[{f,_},{x,_},U]}) when ?U(U) -> ok;
  329. validate({bs_test_unit,[{f,_},{x,_},U]}) when ?U(U) -> ok;
  330. validate({bs_utf16_size,[{f,_},S,{x,_}]}) -> src(S);
  331. validate({bs_utf8_size,[{f,_},S,{x,_}]}) -> src(S);
  332. validate({call,[U,{f,_}]}) when ?U(U) -> ok;
  333. validate({call_ext,[{a,_},{a,_},U]}) when ?U(U) -> ok;
  334. validate({call_ext_last,[{a,_},{a,_},U1,U2]}) when ?U(U1), ?U(U2) -> ok;
  335. validate({call_ext_only,[{a,_},{a,_},U]}) when ?U(U) -> ok;
  336. validate({call_fun,[U]}) when ?U(U) -> ok;
  337. validate({call_last,[U1,{f,_},U2]}) when ?U(U1), ?U(U2) -> ok;
  338. validate({call_only,[U,{f,_}]}) when ?U(U) -> ok;
  339. validate({case_end,[D]}) -> dst(D);
  340. validate({'catch',[{y,_},{f,_}]}) -> ok;
  341. validate({catch_end,[{y,_}]}) -> ok;
  342. validate({deallocate,[U]}) when ?U(U) -> ok;
  343. validate({fadd,[{f,_},{fr,_},{fr,_},{fr,_}]}) -> ok;
  344. validate({fcheckerror,[{f,_}]}) -> ok;
  345. validate(fclearerror) -> ok;
  346. validate({fconv,[S,{fr,_}]}) -> src(S);
  347. validate({fdiv,[{f,_},{fr,_},{fr,_},{fr,_}]}) -> ok;
  348. validate({fmove,[S,{fr,_}]}) -> src(S);
  349. validate({fmove,[{fr,_},{fr,_}]}) -> ok;
  350. validate({fmove,[{fr,_},D]}) -> dst(D);
  351. validate({fmul,[{f,_},{fr,_},{fr,_},{fr,_}]}) -> ok;
  352. validate({fnegate,[{f,_},{fr,_},{fr,_}]}) -> ok;
  353. validate({fsub,[{f,_},{fr,_},{fr,_},{fr,_}]}) -> ok;
  354. validate({func_info,[{a,_},{a,_},U]}) when ?U(U) -> ok;
  355. validate({gc_bif1,[{f,_},U1,{a,_},{a,_},U2,S,D]}) when ?U(U1), ?U(U2) -> src(S), dst(D);
  356. validate({gc_bif2,[{f,_},U1,{a,_},{a,_},U2,S1,S2,D]}) when ?U(U1), ?U(U2) -> src(S1), src(S2), dst(D);
  357. validate({gc_bif3,[{f,_},U1,{a,_},{a,_},U2,S1,S2,S3,D]}) when ?U(U1), ?U(U2) -> src(S1), src(S2), src(S3), dst(D);
  358. validate({get_list,[D1,D2,D3]}) -> dst(D1), dst(D2), dst(D3);
  359. validate({get_tuple_element,[D1,U,D2]}) when ?U(U) -> dst(D1), dst(D2);
  360. validate(if_end) -> ok;
  361. validate({init,[{y,_}]}) -> ok;
  362. validate(int_code_end) -> ok;
  363. validate({is_atom,[{f,_},D]}) -> dst(D);
  364. validate({is_binary,[{f,_},D]}) -> dst(D);
  365. validate({is_bitstr,[{f,_},D]}) -> dst(D);
  366. validate({is_boolean,[{f,_},D]}) -> dst(D);
  367. validate({is_eq,[{f,_},S1,S2]}) -> src(S1), src(S2);
  368. validate({is_eq_exact,[{f,_},S1,S2]}) -> src(S1), src(S2);
  369. validate({is_float,[{f,_},D]}) -> dst(D);
  370. validate({is_function,[{f,_},D]}) -> dst(D);
  371. validate({is_function2,[{f,_},D,U]}) when ?U(U) -> dst(D);
  372. validate({is_function2,[{f,_},D1,D2]}) -> dst(D1), dst(D2);
  373. validate({is_ge,[{f,_},S1,S2]}) -> src(S1), src(S2);
  374. validate({is_integer,[{f,_},D]}) -> dst(D);
  375. validate({is_list,[{f,_},D]}) -> dst(D);
  376. validate({is_lt,[{f,_},S1,S2]}) -> src(S1), src(S2);
  377. validate({is_ne,[{f,_},S1,S2]}) -> src(S1), src(S2);
  378. validate({is_ne_exact,[{f,_},S1,S2]}) -> src(S1), src(S2);
  379. validate({is_nil,[{f,_},D]}) -> dst(D);
  380. validate({is_nonempty_list,[{f,_},D]}) -> dst(D);
  381. validate({is_number,[{f,_},D]}) -> dst(D);
  382. validate({is_pid,[{f,_},D]}) -> dst(D);
  383. validate({is_port,[{f,_},D]}) -> dst(D);
  384. validate({is_reference,[{f,_},D]}) -> dst(D);
  385. validate({is_tuple,[{f,_},D]}) -> dst(D);
  386. validate({jump,[{f,_}]}) -> ok;
  387. validate({label,[U]}) when ?U(U) -> ok;
  388. validate({loop_rec,[{f,_},{x,_}]}) -> ok;
  389. validate({loop_rec_end,[{f,_}]}) -> ok;
  390. validate({make_fun2,[U]}) when ?U(U) -> ok;
  391. validate({move,[S,D]}) -> src(S), dst(D);
  392. validate(on_load) -> ok;
  393. validate({put,[S]}) -> src(S);
  394. validate({put_list,[S1,S2,D]}) -> src(S1), src(S2), dst(D);
  395. validate({put_tuple,[U,D]}) when ?U(U) -> dst(D);
  396. validate({raise,[D1,D2]}) -> dst(D1), dst(D2);
  397. validate({recv_mark,[{f,_}]}) -> ok;
  398. validate({recv_set,[{f,_}]}) -> ok;
  399. validate(remove_message) -> ok;
  400. validate(return) -> ok;
  401. validate({select_tuple_arity,[D,{f,_},{list,_}]}) -> dst(D);
  402. validate({select_val,[D,{f,_},{list,_}]}) -> dst(D);
  403. validate(send) -> ok;
  404. validate({set_tuple_element,[S,{x,_},U]}) when ?U(U) -> src(S);
  405. validate({test_arity,[{f,_},D,U]}) when ?U(U) -> dst(D);
  406. validate({test_heap,[{alloc,_},U]}) when ?U(U) -> ok;
  407. validate({test_heap,[U1,U2]}) when ?U(U1), ?U(U2) -> ok;
  408. validate(timeout) -> ok;
  409. validate({trim,[U1,U2]}) when ?U(U1), ?U(U2) -> ok;
  410. validate({'try',[{y,_},{f,_}]}) -> ok;
  411. validate({try_case,[{y,_}]}) -> ok;
  412. validate({try_case_end,[{x,_}]}) -> ok;
  413. validate({try_end,[{y,_}]}) -> ok;
  414. validate({wait,[{f,_}]}) -> ok;
  415. validate({wait_timeout,[{f,_},S]}) -> src(S);
  416. validate({is_map,[{f,_},S]}) -> src(S);
  417. validate({put_map_assoc,[{f,_},S,D,_Live,{list,_}]}) -> src(S), dst(D);
  418. validate({put_map_exact,[{f,_},S,D,_Live,{list,_}]}) -> src(S), dst(D);
  419. validate({get_map_elements,[{f,_},S,{list,_}]}) -> src(S);
  420. validate({has_map_fields,[{f,_},S,{list,_}]}) -> src(S);
  421. validate({line,_}) -> ok;
  422. validate(X) -> erlang:error(X).
  423. %% a/float/i/literal/nil/x/y
  424. src({a,_}) -> ok;
  425. src({float,_}) -> ok;
  426. src({i,_}) -> ok;
  427. src({literal,_}) -> ok;
  428. src(nil) -> ok;
  429. src({x,_}) -> ok;
  430. src({y,_}) -> ok;
  431. src(X) -> erlang:error(X).
  432. dst({x,_}) -> ok;
  433. dst({y,_}) -> ok;
  434. dst(X) -> erlang:error(X).
  435. %%EOF