2 * Copyright (c) 2017, Facebook, Inc.
5 * This source code is licensed under the BSD-style license found in the
6 * LICENSE file in the "hack" directory of this source tree. An additional grant
7 * of patent rights can be found in the PATENTS file in the same directory.
10 open Instruction_sequence
15 type wrapper_type
= InoutWrapper
| RefWrapper
17 let extract_inout_or_ref_param_locations ~is_closure_or_func params
=
18 let inout_param_locations = List.filter_mapi params
19 ~f
:(fun i p
-> if p
.Ast.param_callconv
<> Some
Ast.Pinout
20 then None
else Some i
) in
21 if List.length
inout_param_locations <> 0 then
22 Some InoutWrapper
, inout_param_locations
24 let module O
= Hhbc_options
in
26 O.create_inout_wrapper_functions
!O.compiler_options
27 && (Emit_env.is_hh_syntax_enabled
())
28 && (O.reffiness_invariance
!O.compiler_options
|| is_closure_or_func
) in
31 then List.filter_mapi params ~f
:(fun i p
-> Option.some_if p
.Ast.param_is_reference i
)
33 if List.is_empty
l then None
, []
34 else Some RefWrapper
, l
36 let inout_suffix param_location
=
37 let param_location = List.map ~f
:string_of_int
param_location in
39 ^
(String.concat
";" param_location)
42 let emit_set_instrs ?
(is_last
=false) opt_base
(index
, set_instrs
) =
43 let index = if is_last
then 0 else index in
50 instr_basel base
H.MemberOpMode.Warn
;
51 instr_querym
0 H.QueryOp.CGet
(H.MemberKey.EI
(Int64.of_int
index))
56 let emit_list_set_for_inout_call local inout_params
= Local.scope
@@ fun () ->
57 if List.length inout_params
= 0 then empty
else
58 let inout_params = List.mapi ~f
:(fun i p
-> (i
+ 2, p
)) inout_params in
59 (* We know that this is safe since there must be at least 1 inout param *)
60 let all_but_last, last
=
61 List.split_n
inout_params (List.length
inout_params - 1) in
62 let last = List.hd_exn
last in
64 Hhbc_options.use_msrv_for_inout
!Hhbc_options.compiler_options
in
69 emit_set_instrs (Some local
) (1, instr_setl local
);
70 gather
@@ List.map
all_but_last ~f
:(emit_set_instrs (Some local
));
71 emit_set_instrs ~is_last
:true (Some local
) last
74 let unset_instr = instr_unsetl local
in
75 let f_label = Label.next_fault
() in
76 let fault_body = gather
[ unset_instr; instr_unwind
] in
78 instr_try_fault
f_label try_body fault_body;
85 gather
@@ List.map
all_but_last ~f
:(emit_set_instrs None
);
86 emit_set_instrs ~is_last
:true None
last;