Add support for FCallM/RetM ABI to HackC and semdiff
[hiphop-php.git] / hphp / hack / src / hhbc / hhbc_options.ml
bloba7bc86f5d06c70afcdf17d8162d74f7d7d35364f
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 Hh_core
13 module J = Hh_json
15 (* Compiler configuration options, as set by -v key=value on the command line *)
16 type t = {
17 option_ints_overflow_to_ints : bool option;
18 option_enable_hiphop_syntax : bool;
19 option_php7_scalar_types : bool;
20 option_enable_xhp : bool;
21 option_constant_folding : bool;
22 option_optimize_null_check : bool;
23 option_optimize_cuf : bool;
24 option_max_array_elem_size_on_the_stack : int;
25 option_aliased_namespaces : (string * string) list option;
26 option_source_mapping : bool;
27 option_relabel : bool;
28 option_php7_uvs : bool;
29 option_php7_ltr_assign : bool;
30 option_create_inout_wrapper_functions : bool;
31 option_reffiness_invariance : bool;
32 option_hack_arr_compat_notices : bool;
33 option_dynamic_invoke_functions : SSet.t;
34 option_repo_authoritative : bool;
35 option_jit_enable_rename_function : bool;
36 option_can_inline_gen_functions : bool;
37 option_use_msrv_for_inout : bool;
40 let default = {
41 option_ints_overflow_to_ints = None;
42 option_enable_hiphop_syntax = false;
43 option_php7_scalar_types = false;
44 option_enable_xhp = false;
45 option_constant_folding = false;
46 option_optimize_null_check = false;
47 option_optimize_cuf = true;
48 option_max_array_elem_size_on_the_stack = 64;
49 option_aliased_namespaces = None;
50 option_source_mapping = false;
51 option_php7_uvs = false;
52 option_php7_ltr_assign = false;
53 (* If true, then renumber labels after generating code for a method
54 * body. Semantic diff doesn't care about labels, but for visual diff against
55 * HHVM it's helpful to renumber in order that the labels match more closely *)
56 option_relabel = true;
57 option_create_inout_wrapper_functions = true;
58 option_reffiness_invariance = false;
59 option_hack_arr_compat_notices = false;
60 option_dynamic_invoke_functions = SSet.empty;
61 option_repo_authoritative = false;
62 option_jit_enable_rename_function = false;
63 option_can_inline_gen_functions = true;
64 option_use_msrv_for_inout = false;
67 let enable_hiphop_syntax o = o.option_enable_hiphop_syntax
68 let php7_scalar_types o = o.option_php7_scalar_types
69 let enable_xhp o = o.option_enable_xhp
70 let constant_folding o = o.option_constant_folding
71 let optimize_null_check o = o.option_optimize_null_check
72 let optimize_cuf o = o.option_optimize_cuf
73 let max_array_elem_size_on_the_stack o =
74 o.option_max_array_elem_size_on_the_stack
75 let aliased_namespaces o = o.option_aliased_namespaces
76 let source_mapping o = o.option_source_mapping
77 let relabel o = o.option_relabel
78 let enable_uniform_variable_syntax o = o.option_php7_uvs
79 let php7_ltr_assign o = o.option_php7_ltr_assign
80 let create_inout_wrapper_functions o = o.option_create_inout_wrapper_functions
81 let reffiness_invariance o = o.option_reffiness_invariance
82 let hack_arr_compat_notices o = o.option_hack_arr_compat_notices
83 let dynamic_invoke_functions o = o.option_dynamic_invoke_functions
84 let repo_authoritative o = o.option_repo_authoritative
85 let jit_enable_rename_function o = o.option_jit_enable_rename_function
86 let can_inline_gen_functions o = o.option_can_inline_gen_functions
87 let use_msrv_for_inout o = o.option_use_msrv_for_inout
89 let to_string o =
90 let dynamic_invokes =
91 String.concat ", " (SSet.elements (dynamic_invoke_functions o)) in
92 String.concat "\n"
93 [ Printf.sprintf "enable_hiphop_syntax: %B" @@ enable_hiphop_syntax o
94 ; Printf.sprintf "php7_scalar_types: %B" @@ php7_scalar_types o
95 ; Printf.sprintf "enable_xhp: %B" @@ enable_xhp o
96 ; Printf.sprintf "constant_folding: %B" @@ constant_folding o
97 ; Printf.sprintf "optimize_null_check: %B" @@ optimize_null_check o
98 ; Printf.sprintf "optimize_cuf: %B" @@ optimize_cuf o
99 ; Printf.sprintf "max_array_elem_size_on_the_stack: %d"
100 @@ max_array_elem_size_on_the_stack o
101 ; Printf.sprintf "source_mapping: %B" @@ source_mapping o
102 ; Printf.sprintf "relabel: %B" @@ relabel o
103 ; Printf.sprintf "enable_uniform_variable_syntax: %B"
104 @@ enable_uniform_variable_syntax o
105 ; Printf.sprintf "php7_ltr_assign: %B" @@ php7_ltr_assign o
106 ; Printf.sprintf "create_inout_wrapper_functions: %B"
107 @@ create_inout_wrapper_functions o
108 ; Printf.sprintf "reffiness_invariance: %B" @@ reffiness_invariance o
109 ; Printf.sprintf "hack_arr_compat_notices: %B" @@ hack_arr_compat_notices o
110 ; Printf.sprintf "dynamic_invoke_functions: [%s]" dynamic_invokes
111 ; Printf.sprintf "repo_authoritative: %B" @@ repo_authoritative o
112 ; Printf.sprintf "jit_enable_rename_function: %B"
113 @@ jit_enable_rename_function o
114 ; Printf.sprintf "can_inline_gen_functions: %B" @@ can_inline_gen_functions o
115 ; Printf.sprintf "use_msrv_for_inout: %B" @@ use_msrv_for_inout o
118 (* The Hack.Lang.IntsOverflowToInts setting overrides the
119 * Eval.EnableHipHopSyntax setting *)
120 let ints_overflow_to_ints options =
121 match options.option_ints_overflow_to_ints with
122 | Some v -> v
123 | None -> options.option_enable_hiphop_syntax
125 let as_bool s =
126 match String.lowercase_ascii s with
127 | "0" | "false" -> false
128 | "1" | "true" -> true
129 | _ -> raise (Arg.Bad (s ^ " can't be cast to bool"))
131 let set_option options name value =
132 match String.lowercase_ascii name with
133 | "eval.enablehiphopsyntax" ->
134 { options with option_enable_hiphop_syntax = as_bool value }
135 | "hack.lang.intsoverflowtoints" ->
136 { options with option_ints_overflow_to_ints = Some (as_bool value) }
137 | "hack.compiler.constantfolding" ->
138 { options with option_constant_folding = as_bool value }
139 | "hack.compiler.optimizenullcheck" ->
140 { options with option_optimize_null_check = as_bool value }
141 | "hack.compiler.optimizecuf" ->
142 { options with option_optimize_cuf = as_bool value }
143 | "hack.compiler.sourcemapping" ->
144 { options with option_source_mapping = as_bool value }
145 | "hhvm.php7.scalar_types" ->
146 { options with option_php7_scalar_types = as_bool value }
147 | "hhvm.php7.ltr_assign" ->
148 { options with option_php7_ltr_assign = as_bool value }
149 | "hhvm.enable_xhp" ->
150 { options with option_enable_xhp = as_bool value }
151 | "hhvm.php7.uvs" ->
152 { options with option_php7_uvs = as_bool value }
153 | "hack.compiler.relabel" ->
154 { options with option_relabel = as_bool value }
155 | "eval.createinoutwrapperfunctions" ->
156 { options with option_create_inout_wrapper_functions = as_bool value }
157 | "eval.reffinessinvariance" ->
158 { options with option_reffiness_invariance = as_bool value }
159 | "eval.hackarrcompatnotices" ->
160 { options with option_hack_arr_compat_notices = as_bool value }
161 | "hhvm.repo_authoritative" ->
162 { options with option_repo_authoritative = as_bool value }
163 | "eval.jitenablerenamefunction" ->
164 { options with option_jit_enable_rename_function = as_bool value }
165 | "eval.disablehphpcopts" ->
166 let v = not (as_bool value) in
167 { options with option_optimize_cuf = v;
168 option_constant_folding = v;
169 option_can_inline_gen_functions = v}
170 | "hhvm.use_msrv_for_in_out" ->
171 { options with option_use_msrv_for_inout = as_bool value }
172 | _ -> options
174 let get_value_from_config_ config key =
175 let f k1 (k2, _) = k1 = k2 in
176 match List.find config ~f:(f key) with
177 | None -> None
178 | Some (_, json) ->
179 begin match List.find (J.get_object_exn json) ~f:(f "global_value") with
180 | None -> None
181 | Some (_, json) -> Some json
184 let get_value_from_config_int config key =
185 let json_opt = get_value_from_config_ config key in
186 Option.map json_opt ~f:(fun json ->
187 match J.get_string_exn json with
188 | "" -> 0
189 | x -> int_of_string x)
191 let get_value_from_config_kv_list config key =
192 let json_opt = get_value_from_config_ config key in
193 Option.map json_opt ~f:(fun json ->
194 match json with
195 | J.JSON_Array [] -> []
196 | json ->
197 let keys_with_json = J.get_object_exn json in
198 List.map ~f:(fun (k, v) -> k, J.get_string_exn v) keys_with_json)
200 let get_value_from_config_string_array config key =
201 let json_opt = get_value_from_config_ config key in
202 match json_opt with
203 | None -> Some []
204 | Some (J.JSON_Array fs) -> Some (List.map fs J.get_string_exn)
205 | _ -> raise (Arg.Bad ("Expected list of strings at " ^ key))
207 let set_value name get set config opts =
209 let value = get config name in
210 Option.value_map value ~default:opts ~f:(set opts)
211 with
212 | Arg.Bad why -> raise (Arg.Bad ("Option " ^ name ^ ": " ^ why))
213 | Assert_failure _ -> raise (Arg.Bad ("Option " ^ name ^ ": error parsing JSON"))
215 let value_setters = [
216 (set_value "hhvm.aliased_namespaces" get_value_from_config_kv_list @@
217 fun opts v -> { opts with option_aliased_namespaces = Some v });
218 (set_value "hhvm.force_hh" get_value_from_config_int @@
219 fun opts v -> { opts with option_enable_hiphop_syntax = (v = 1) });
220 (set_value "hhvm.enable_xhp" get_value_from_config_int @@
221 fun opts v -> { opts with option_enable_xhp = (v = 1) });
222 (set_value "hhvm.php7.scalar_types" get_value_from_config_int @@
223 fun opts v -> { opts with option_php7_scalar_types = (v = 1) });
224 (set_value "hhvm.hack.lang.ints_overflow_to_ints" get_value_from_config_int @@
225 fun opts v -> { opts with option_ints_overflow_to_ints = Some (v = 1) });
226 (set_value "hack.compiler.constant_folding" get_value_from_config_int @@
227 fun opts v -> { opts with option_constant_folding = (v = 1) });
228 (set_value "hack.compiler.optimize_null_checks" get_value_from_config_int @@
229 fun opts v -> { opts with option_optimize_null_check = (v = 1) });
230 (set_value "hhvm.disable_hphpc_opts" get_value_from_config_int @@
231 fun opts v -> { opts with option_optimize_cuf = (v = 0);
232 option_constant_folding = (v = 0);
233 option_can_inline_gen_functions = (v = 0) });
234 (set_value "hack.compiler.optimize_cuf" get_value_from_config_int @@
235 fun opts v -> { opts with option_optimize_cuf = (v = 1) });
236 (set_value "hhvm.php7.uvs" get_value_from_config_int @@
237 fun opts v -> { opts with option_php7_uvs = (v = 1) });
238 (set_value "hhvm.php7.ltr_assign" get_value_from_config_int @@
239 fun opts v -> { opts with option_php7_ltr_assign = (v = 1) });
240 (set_value "hhvm.create_in_out_wrapper_functions" get_value_from_config_int @@
241 fun opts v -> { opts with option_create_inout_wrapper_functions = (v = 1)});
242 (set_value "hhvm.reffiness_invariance" get_value_from_config_int @@
243 fun opts v -> { opts with option_reffiness_invariance = (v = 1) });
244 (set_value "hhvm.hack_arr_compat_notices" get_value_from_config_int @@
245 fun opts v -> { opts with option_hack_arr_compat_notices = (v = 1) });
246 (set_value "hhvm.dynamic_invoke_functions" get_value_from_config_string_array @@
247 fun opts v -> {opts with option_dynamic_invoke_functions =
248 SSet.of_list (List.map v String.lowercase_ascii)});
249 (set_value "hhvm.repo.authoritative" get_value_from_config_int @@
250 fun opts v -> { opts with option_repo_authoritative = (v = 1) });
251 (set_value "hhvm.jit_enable_rename_function" get_value_from_config_int @@
252 fun opts v -> { opts with option_jit_enable_rename_function = (v = 1) });
253 (set_value "hhvm.use_msrv_for_in_out" get_value_from_config_int @@
254 fun opts v -> { opts with option_use_msrv_for_inout = (v = 1) });
257 let extract_config_options_from_json ~init config_json =
258 match config_json with None -> init | Some config_json ->
259 let config = J.get_object_exn config_json in
260 List.fold_left value_setters ~init ~f:(fun opts setter -> setter config opts)
262 (* Construct an instance of Hhbc_options.t from the options passed in as well as
263 * as specified in `-v str` on the command line.
265 let get_options_from_config config_json config_list =
266 let init = extract_config_options_from_json ~init:default config_json in
267 List.fold_left config_list ~init ~f:begin
268 fun options str ->
269 match Str.split_delim (Str.regexp "=") str with
270 | [name; value] -> set_option options name value
271 | _ -> options
274 let compiler_options = ref default
275 let set_compiler_options o = compiler_options := o