|
| 1 | +diff --git a/bytecomp/bytegen.ml b/bytecomp/bytegen.ml |
| 2 | +index 27e170ffce..12690f7061 100644 |
| 3 | +--- a/bytecomp/bytegen.ml |
| 4 | ++++ b/bytecomp/bytegen.ml |
| 5 | +@@ -34,20 +34,53 @@ let new_label () = |
| 6 | + (**** Operations on compilation environments. ****) |
| 7 | + |
| 8 | + let empty_env = |
| 9 | +- { ce_stack = Ident.empty; ce_heap = Ident.empty; ce_rec = Ident.empty } |
| 10 | ++ { ce_stack = Ident.empty; ce_closure = Not_in_closure } |
| 11 | + |
| 12 | + (* Add a stack-allocated variable *) |
| 13 | + |
| 14 | + let add_var id pos env = |
| 15 | + { ce_stack = Ident.add id pos env.ce_stack; |
| 16 | +- ce_heap = env.ce_heap; |
| 17 | +- ce_rec = env.ce_rec } |
| 18 | ++ ce_closure = env.ce_closure } |
| 19 | + |
| 20 | + let rec add_vars idlist pos env = |
| 21 | + match idlist with |
| 22 | + [] -> env |
| 23 | + | id :: rem -> add_vars rem (pos + 1) (add_var id pos env) |
| 24 | + |
| 25 | ++(* Compute the closure environment *) |
| 26 | ++ |
| 27 | ++let rec add_positions entries pos_to_entry ~pos ~delta = function |
| 28 | ++ | [] -> entries, pos |
| 29 | ++ | id :: rem -> |
| 30 | ++ let entries = |
| 31 | ++ Ident.add id (pos_to_entry pos) entries |
| 32 | ++ in |
| 33 | ++ add_positions entries pos_to_entry ~pos:(pos + delta) ~delta rem |
| 34 | ++ |
| 35 | ++type function_definition = |
| 36 | ++ | Single_non_recursive |
| 37 | ++ | Multiple_recursive of Ident.t list |
| 38 | ++ |
| 39 | ++let closure_entries fun_defs fvs = |
| 40 | ++ let funct_entries, pos_end_functs = |
| 41 | ++ match fun_defs with |
| 42 | ++ | Single_non_recursive -> |
| 43 | ++ (* No need to store the function in the environment, but we still need to |
| 44 | ++ reserve a slot in the closure block *) |
| 45 | ++ Ident.empty, 3 |
| 46 | ++ | Multiple_recursive functs -> |
| 47 | ++ add_positions Ident.empty (fun pos -> Function pos) ~pos:0 ~delta:3 functs |
| 48 | ++ in |
| 49 | ++ (* Note: [pos_end_functs] is the position where we would store the next |
| 50 | ++ function if there was one, and points after an eventual infix tag. |
| 51 | ++ Since that was the last function, we don't need the last infix tag |
| 52 | ++ and start storing free variables at [pos_end_functs - 1]. *) |
| 53 | ++ let all_entries, _end_pos = |
| 54 | ++ add_positions funct_entries (fun pos -> Free_variable pos) |
| 55 | ++ ~pos:(pos_end_functs - 1) ~delta:1 fvs |
| 56 | ++ in |
| 57 | ++ all_entries |
| 58 | ++ |
| 59 | + (**** Examination of the continuation ****) |
| 60 | + |
| 61 | + (* Return a label to the beginning of the given continuation. |
| 62 | +@@ -354,9 +387,8 @@ type function_to_compile = |
| 63 | + { params: Ident.t list; (* function parameters *) |
| 64 | + body: lambda; (* the function body *) |
| 65 | + label: label; (* the label of the function entry *) |
| 66 | +- free_vars: Ident.t list; (* free variables of the function *) |
| 67 | +- num_defs: int; (* number of mutually recursive definitions *) |
| 68 | +- rec_vars: Ident.t list; (* mutually recursive fn names *) |
| 69 | ++ entries: closure_entry Ident.tbl; (* the offsets for the free variables |
| 70 | ++ and mutually recursive functions *) |
| 71 | + rec_pos: int } (* rank in recursive definition *) |
| 72 | + |
| 73 | + let functions_to_compile = (Stack.create () : function_to_compile Stack.t) |
| 74 | +@@ -545,15 +577,18 @@ let rec comp_expr env exp sz cont = |
| 75 | + let pos = Ident.find_same id env.ce_stack in |
| 76 | + Kacc(sz - pos) :: cont |
| 77 | + with Not_found -> |
| 78 | +- try |
| 79 | +- let pos = Ident.find_same id env.ce_heap in |
| 80 | +- Kenvacc(pos) :: cont |
| 81 | +- with Not_found -> |
| 82 | +- try |
| 83 | +- let ofs = Ident.find_same id env.ce_rec in |
| 84 | +- Koffsetclosure(ofs) :: cont |
| 85 | +- with Not_found -> |
| 86 | ++ let not_found () = |
| 87 | + fatal_error ("Bytegen.comp_expr: var " ^ Ident.unique_name id) |
| 88 | ++ in |
| 89 | ++ match env.ce_closure with |
| 90 | ++ | Not_in_closure -> not_found () |
| 91 | ++ | In_closure { entries; env_pos } -> |
| 92 | ++ match Ident.find_same id entries with |
| 93 | ++ | Free_variable pos -> |
| 94 | ++ Kenvacc(pos - env_pos) :: cont |
| 95 | ++ | Function pos -> |
| 96 | ++ Koffsetclosure(pos - env_pos) :: cont |
| 97 | ++ | exception Not_found -> not_found () |
| 98 | + end |
| 99 | + | Lconst cst -> |
| 100 | + Kconst cst :: cont |
| 101 | +@@ -601,9 +636,10 @@ let rec comp_expr env exp sz cont = |
| 102 | + let cont = add_pseudo_event loc !compunit_name cont in |
| 103 | + let lbl = new_label() in |
| 104 | + let fv = Ident.Set.elements(free_variables exp) in |
| 105 | ++ let entries = closure_entries Single_non_recursive fv in |
| 106 | + let to_compile = |
| 107 | + { params = List.map fst params; body = body; label = lbl; |
| 108 | +- free_vars = fv; num_defs = 1; rec_vars = []; rec_pos = 0 } in |
| 109 | ++ entries = entries; rec_pos = 0 } in |
| 110 | + Stack.push to_compile functions_to_compile; |
| 111 | + comp_args env (List.map (fun n -> Lvar n) fv) sz |
| 112 | + (Kclosure(lbl, List.length fv) :: cont) |
| 113 | +@@ -620,14 +656,16 @@ let rec comp_expr env exp sz cont = |
| 114 | + let fv = |
| 115 | + Ident.Set.elements (free_variables (Lletrec(decl, lambda_unit))) in |
| 116 | + let rec_idents = List.map (fun (id, _lam) -> id) decl in |
| 117 | ++ let entries = |
| 118 | ++ closure_entries (Multiple_recursive rec_idents) fv |
| 119 | ++ in |
| 120 | + let rec comp_fun pos = function |
| 121 | + [] -> [] |
| 122 | + | (_id, Lfunction{params; body}) :: rem -> |
| 123 | + let lbl = new_label() in |
| 124 | + let to_compile = |
| 125 | + { params = List.map fst params; body = body; label = lbl; |
| 126 | +- free_vars = fv; num_defs = ndecl; rec_vars = rec_idents; |
| 127 | +- rec_pos = pos} in |
| 128 | ++ entries = entries; rec_pos = pos} in |
| 129 | + Stack.push to_compile functions_to_compile; |
| 130 | + lbl :: comp_fun (pos + 1) rem |
| 131 | + | _ -> assert false in |
| 132 | +@@ -1060,13 +1098,15 @@ let comp_block env exp sz cont = |
| 133 | + |
| 134 | + let comp_function tc cont = |
| 135 | + let arity = List.length tc.params in |
| 136 | +- let rec positions pos delta = function |
| 137 | +- [] -> Ident.empty |
| 138 | +- | id :: rem -> Ident.add id pos (positions (pos + delta) delta rem) in |
| 139 | ++ let ce_stack, _last_pos = |
| 140 | ++ add_positions Ident.empty Fun.id ~pos:arity ~delta:(-1) tc.params |
| 141 | ++ in |
| 142 | + let env = |
| 143 | +- { ce_stack = positions arity (-1) tc.params; |
| 144 | +- ce_heap = positions (3 * (tc.num_defs - tc.rec_pos) - 1) 1 tc.free_vars; |
| 145 | +- ce_rec = positions (-3 * tc.rec_pos) 3 tc.rec_vars } in |
| 146 | ++ { ce_stack; |
| 147 | ++ ce_closure = |
| 148 | ++ In_closure { entries = tc.entries; env_pos = 3 * tc.rec_pos } |
| 149 | ++ } |
| 150 | ++ in |
| 151 | + let cont = |
| 152 | + comp_block env tc.body arity (Kreturn arity :: cont) in |
| 153 | + if arity > 1 then |
| 154 | +diff --git a/bytecomp/instruct.ml b/bytecomp/instruct.ml |
| 155 | +index c684bedf99..c1ecf1f51a 100644 |
| 156 | +--- a/bytecomp/instruct.ml |
| 157 | ++++ b/bytecomp/instruct.ml |
| 158 | +@@ -15,10 +15,20 @@ |
| 159 | + |
| 160 | + open Lambda |
| 161 | + |
| 162 | ++type closure_entry = |
| 163 | ++ | Free_variable of int |
| 164 | ++ | Function of int |
| 165 | ++ |
| 166 | ++type closure_env = |
| 167 | ++ | Not_in_closure |
| 168 | ++ | In_closure of { |
| 169 | ++ entries: closure_entry Ident.tbl; |
| 170 | ++ env_pos: int; |
| 171 | ++ } |
| 172 | ++ |
| 173 | + type compilation_env = |
| 174 | + { ce_stack: int Ident.tbl; |
| 175 | +- ce_heap: int Ident.tbl; |
| 176 | +- ce_rec: int Ident.tbl } |
| 177 | ++ ce_closure: closure_env } |
| 178 | + |
| 179 | + type debug_event = |
| 180 | + { mutable ev_pos: int; (* Position in bytecode *) |
| 181 | +diff --git a/bytecomp/instruct.mli b/bytecomp/instruct.mli |
| 182 | +index e1cae776b0..a95990f153 100644 |
| 183 | +--- a/bytecomp/instruct.mli |
| 184 | ++++ b/bytecomp/instruct.mli |
| 185 | +@@ -19,21 +19,35 @@ open Lambda |
| 186 | + |
| 187 | + (* Structure of compilation environments *) |
| 188 | + |
| 189 | ++type closure_entry = |
| 190 | ++ | Free_variable of int |
| 191 | ++ | Function of int |
| 192 | ++ |
| 193 | ++type closure_env = |
| 194 | ++ | Not_in_closure |
| 195 | ++ | In_closure of { |
| 196 | ++ entries: closure_entry Ident.tbl; (* Offsets of the free variables and |
| 197 | ++ recursive functions from the start of |
| 198 | ++ the block *) |
| 199 | ++ env_pos: int; (* Offset of the current function from |
| 200 | ++ the start of the block *) |
| 201 | ++ } |
| 202 | ++ |
| 203 | + type compilation_env = |
| 204 | +- { ce_stack: int Ident.tbl; (* Positions of variables in the stack *) |
| 205 | +- ce_heap: int Ident.tbl; (* Structure of the heap-allocated env *) |
| 206 | +- ce_rec: int Ident.tbl } (* Functions bound by the same let rec *) |
| 207 | ++ { ce_stack: int Ident.tbl; (* Positions of variables in the stack *) |
| 208 | ++ ce_closure: closure_env } (* Structure of the heap-allocated env *) |
| 209 | + |
| 210 | + (* The ce_stack component gives locations of variables residing |
| 211 | + in the stack. The locations are offsets w.r.t. the origin of the |
| 212 | + stack frame. |
| 213 | +- The ce_heap component gives the positions of variables residing in the |
| 214 | +- heap-allocated environment. |
| 215 | +- The ce_rec component associates offsets to identifiers for functions |
| 216 | +- bound by the same let rec as the current function. The offsets |
| 217 | +- are used by the OFFSETCLOSURE instruction to recover the closure |
| 218 | +- pointer of the desired function from the env register (which |
| 219 | +- points to the closure for the current function). *) |
| 220 | ++ The ce_closure component gives the positions of variables residing in the |
| 221 | ++ heap-allocated environment. The env_pos component gives the position of |
| 222 | ++ the current function from the start of the closure block, and the entries |
| 223 | ++ component gives the positions of free variables and functions bound by the |
| 224 | ++ same let rec as the current function, from the start of the closure block. |
| 225 | ++ These are used by the ENVACC and OFFSETCLOSURE instructions to recover the |
| 226 | ++ relevant value from the env register (which points to the current function). |
| 227 | ++*) |
| 228 | + |
| 229 | + (* Debugging events *) |
| 230 | + |
| 231 | +diff --git a/debugger/eval.ml b/debugger/eval.ml |
| 232 | +index a47f381de5..9d9a8c090b 100644 |
| 233 | +--- a/debugger/eval.ml |
| 234 | ++++ b/debugger/eval.ml |
| 235 | +@@ -47,20 +47,28 @@ let rec address path event = function |
| 236 | + Debugcom.Remote_value.global (Symtable.get_global_position id) |
| 237 | + with Symtable.Error _ -> raise(Error(Unbound_identifier id)) |
| 238 | + else |
| 239 | ++ let not_found () = |
| 240 | ++ raise(Error(Unbound_identifier id)) |
| 241 | ++ in |
| 242 | + begin match event with |
| 243 | + Some {ev_ev = ev} -> |
| 244 | + begin try |
| 245 | + let pos = Ident.find_same id ev.ev_compenv.ce_stack in |
| 246 | + Debugcom.Remote_value.local (ev.ev_stacksize - pos) |
| 247 | + with Not_found -> |
| 248 | +- try |
| 249 | +- let pos = Ident.find_same id ev.ev_compenv.ce_heap in |
| 250 | +- Debugcom.Remote_value.from_environment pos |
| 251 | +- with Not_found -> |
| 252 | +- raise(Error(Unbound_identifier id)) |
| 253 | ++ match ev.ev_compenv.ce_closure with |
| 254 | ++ | Not_in_closure -> not_found () |
| 255 | ++ | In_closure { entries; env_pos } -> |
| 256 | ++ match Ident.find_same id entries with |
| 257 | ++ | Free_variable pos -> |
| 258 | ++ Debugcom.Remote_value.from_environment (pos - env_pos) |
| 259 | ++ | Function _pos -> |
| 260 | ++ (* Recursive functions seem to be unhandled *) |
| 261 | ++ not_found () |
| 262 | ++ | exception Not_found -> not_found () |
| 263 | + end |
| 264 | + | None -> |
| 265 | +- raise(Error(Unbound_identifier id)) |
| 266 | ++ not_found () |
| 267 | + end |
| 268 | + | Env.Adot(root, pos) -> |
| 269 | + let v = address path event root in |
| 270 | +diff --git a/middle_end/closure/closure.ml b/middle_end/closure/closure.ml |
| 271 | +index ac18435189..0fb50cb880 100644 |
| 272 | +--- a/middle_end/closure/closure.ml |
| 273 | ++++ b/middle_end/closure/closure.ml |
| 274 | +@@ -50,13 +50,6 @@ let rec split_list n l = |
| 275 | + | a::l -> let (l1, l2) = split_list (n-1) l in (a::l1, l2) |
| 276 | + end |
| 277 | + |
| 278 | +-let rec build_closure_env env_param pos = function |
| 279 | +- [] -> V.Map.empty |
| 280 | +- | id :: rem -> |
| 281 | +- V.Map.add id |
| 282 | +- (Uprim(P.Pfield pos, [Uvar env_param], Debuginfo.none)) |
| 283 | +- (build_closure_env env_param (pos+1) rem) |
| 284 | +- |
| 285 | + (* Auxiliary for accessing globals. We change the name of the global |
| 286 | + to the name of the corresponding asm symbol. This is done here |
| 287 | + and no longer in Cmmgen so that approximations stored in .cmx files |
| 288 | +@@ -701,9 +694,21 @@ let rec substitute loc ((backend, fpc) as st) sb rn ulam = |
| 289 | + | Uunreachable -> |
| 290 | + Uunreachable |
| 291 | + |
| 292 | ++type closure_entry = |
| 293 | ++ | Free_variable of int |
| 294 | ++ | Function of int |
| 295 | ++ |
| 296 | ++type closure_env = |
| 297 | ++ | Not_in_closure |
| 298 | ++ | In_closure of { |
| 299 | ++ entries: closure_entry V.Map.t; |
| 300 | ++ env_param: V.t; |
| 301 | ++ env_pos: int; |
| 302 | ++ } |
| 303 | ++ |
| 304 | + type env = { |
| 305 | + backend : (module Backend_intf.S); |
| 306 | +- cenv : ulambda V.Map.t; |
| 307 | ++ cenv : closure_env; |
| 308 | + fenv : value_approximation V.Map.t; |
| 309 | + mutable_vars : V.Set.t; |
| 310 | + } |
| 311 | +@@ -882,8 +887,20 @@ let close_approx_var { fenv; cenv } id = |
| 312 | + match approx with |
| 313 | + Value_const c -> make_const c |
| 314 | + | approx -> |
| 315 | +- let subst = try V.Map.find id cenv with Not_found -> Uvar id in |
| 316 | +- (subst, approx) |
| 317 | ++ match cenv with |
| 318 | ++ | Not_in_closure -> Uvar id, approx |
| 319 | ++ | In_closure { entries; env_param; env_pos } -> |
| 320 | ++ let subst = |
| 321 | ++ match V.Map.find id entries with |
| 322 | ++ | Free_variable fv_pos -> |
| 323 | ++ Uprim(P.Pfield (fv_pos - env_pos), |
| 324 | ++ [Uvar env_param], |
| 325 | ++ Debuginfo.none) |
| 326 | ++ | Function fun_pos -> |
| 327 | ++ Uoffset(Uvar env_param, fun_pos - env_pos) |
| 328 | ++ | exception Not_found -> Uvar id |
| 329 | ++ in |
| 330 | ++ (subst, approx) |
| 331 | + |
| 332 | + let close_var env id = |
| 333 | + let (ulam, _app) = close_approx_var env id in ulam |
| 334 | +@@ -1296,16 +1313,29 @@ and close_functions { backend; fenv; cenv; mutable_vars } fun_defs = |
| 335 | + (* This reference will be set to false if the hypothesis that a function |
| 336 | + does not use its environment parameter is invalidated. *) |
| 337 | + let useless_env = ref initially_closed in |
| 338 | ++ let cenv_entries = |
| 339 | ++ let rec free_variables_entries fv_pos = function |
| 340 | ++ [] -> V.Map.empty |
| 341 | ++ | id :: rem -> |
| 342 | ++ V.Map.add id (Free_variable fv_pos) |
| 343 | ++ (free_variables_entries (fv_pos+1) rem) |
| 344 | ++ in |
| 345 | ++ let entries_fv = free_variables_entries fv_pos fv in |
| 346 | ++ List.fold_right2 |
| 347 | ++ (fun (id, _params, _return, _body, _fundesc, _dbg) pos env -> |
| 348 | ++ V.Map.add id (Function pos) env) |
| 349 | ++ uncurried_defs clos_offsets entries_fv |
| 350 | ++ in |
| 351 | + (* Translate each function definition *) |
| 352 | + let clos_fundef (id, params, return, body, fundesc, dbg) env_pos = |
| 353 | + let env_param = V.create_local "env" in |
| 354 | +- let cenv_fv = |
| 355 | +- build_closure_env env_param (fv_pos - env_pos) fv in |
| 356 | + let cenv_body = |
| 357 | +- List.fold_right2 |
| 358 | +- (fun (id, _params, _return, _body, _fundesc, _dbg) pos env -> |
| 359 | +- V.Map.add id (Uoffset(Uvar env_param, pos - env_pos)) env) |
| 360 | +- uncurried_defs clos_offsets cenv_fv in |
| 361 | ++ In_closure { |
| 362 | ++ entries = cenv_entries; |
| 363 | ++ env_param; |
| 364 | ++ env_pos; |
| 365 | ++ } |
| 366 | ++ in |
| 367 | + let (ubody, approx) = |
| 368 | + close { backend; fenv = fenv_rec; cenv = cenv_body; mutable_vars } body |
| 369 | + in |
| 370 | +@@ -1514,7 +1544,7 @@ let intro ~backend ~size lam = |
| 371 | + Compilenv.set_global_approx(Value_tuple !global_approx); |
| 372 | + let (ulam, _approx) = |
| 373 | + close { backend; fenv = V.Map.empty; |
| 374 | +- cenv = V.Map.empty; mutable_vars = V.Set.empty } lam |
| 375 | ++ cenv = Not_in_closure; mutable_vars = V.Set.empty } lam |
| 376 | + in |
| 377 | + let opaque = |
| 378 | + !Clflags.opaque |
0 commit comments