Add codegen for inout arguments
[hiphop-php.git] / hphp / hack / src / hhbc / emit_function.ml
blob2128cd39752950983f9b38098b8554594814348e
1 (**
2 * Copyright (c) 2017, Facebook, Inc.
3 * All rights reserved.
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.
9 *)
11 open Instruction_sequence
12 module A = Ast
13 open Hh_core
15 let find_first_redeclaration pick_name_span l =
16 let rec aux seen l =
17 match l with
18 | [] -> None
19 | x :: xs ->
20 match pick_name_span x with
21 | Some (name, span) ->
22 begin match SMap.get name seen with
23 | None -> aux (SMap.add name span seen) xs
24 | Some original -> Some (name, original, span)
25 end
26 | None -> aux seen xs in
27 aux SMap.empty l
29 (* Given a function definition, emit code, and in the case of <<__Memoize>>,
30 * a wrapper function
32 let emit_function : A.fun_ * bool -> Hhas_function.t list =
33 fun (ast_fun, is_top) ->
34 let namespace = ast_fun.A.f_namespace in
35 let original_id, _ =
36 Hhbc_id.Function.elaborate_id namespace ast_fun.A.f_name in
37 let function_is_async =
38 ast_fun.Ast.f_fun_kind = Ast_defs.FAsync
39 || ast_fun.Ast.f_fun_kind = Ast_defs.FAsyncGenerator in
40 let function_attributes =
41 Emit_attribute.from_asts namespace ast_fun.Ast.f_user_attributes in
42 let is_memoize = Hhas_attribute.is_memoized function_attributes in
43 let deprecation_info = Hhas_attribute.deprecation_info function_attributes in
44 let inout_param_locations = List.filter_mapi ast_fun.Ast.f_params
45 ~f:(fun i p -> if p.Ast.param_callconv <> Some Ast.Pinout
46 then None else Some (string_of_int i)) in
47 let has_inout_args = List.length inout_param_locations <> 0 in
48 let renamed_id =
49 if is_memoize
50 then Hhbc_id.Function.add_suffix
51 original_id Emit_memoize_helpers.memoize_suffix
52 else if has_inout_args
53 then Hhbc_id.Function.add_suffix
54 original_id (Emit_inout_helpers.inout_suffix inout_param_locations)
55 else original_id in
56 let scope = [Ast_scope.ScopeItem.Function ast_fun] in
57 let function_body, function_is_generator, function_is_pair_generator =
58 Emit_body.emit_body
59 ~pos: ast_fun.A.f_span
60 ~scope
61 ~is_closure_body:false
62 ~is_memoize
63 ~is_async:function_is_async
64 ~deprecation_info:(if is_memoize then None else deprecation_info)
65 ~skipawaitable:(ast_fun.Ast.f_fun_kind = Ast_defs.FAsync)
66 ~is_return_by_ref:ast_fun.Ast.f_ret_by_ref
67 ~default_dropthrough:None
68 ~return_value:instr_null
69 ~namespace
70 ~doc_comment:ast_fun.Ast.f_doc_comment
71 ast_fun.Ast.f_params
72 ast_fun.Ast.f_ret
73 [Ast.Stmt (Ast.Block ast_fun.Ast.f_body)] in
74 let normal_function =
75 Hhas_function.make
76 function_attributes
77 renamed_id
78 function_body
79 (Hhas_pos.pos_to_span ast_fun.Ast.f_span)
80 function_is_async
81 function_is_generator
82 function_is_pair_generator
83 is_top
84 false (*no_injection*)
85 false (*inout_wrapper*)
87 if is_memoize
88 then [normal_function;
89 Emit_memoize_function.emit_wrapper_function
90 ~original_id
91 ~renamed_id
92 ~is_method:false
93 ~deprecation_info
94 ast_fun]
95 else if has_inout_args
96 then [Emit_inout_function.emit_wrapper_function
97 ~original_id
98 ~renamed_id
99 ~verify_ret:(ast_fun.Ast.f_ret <> None)
100 ast_fun;
101 normal_function]
102 else [normal_function]
104 let emit_functions_from_program ast =
105 List.concat_map (List.sort (fun (t1, _) (t2, _) -> compare t1 t2) ast)
106 (fun (is_top, d) ->
107 match d with Ast.Fun fd -> emit_function (fd, is_top) | _ -> [])