1(**************************************************************************) 2(* *) 3(* OCaml *) 4(* *) 5(* Xavier Leroy, projet Cristal, INRIA Rocquencourt *) 6(* *) 7(* Copyright 1996 Institut National de Recherche en Informatique et *) 8(* en Automatique. *) 9(* *) 10(* All rights reserved. This file is distributed under the terms of *) 11(* the GNU Lesser General Public License version 2.1, with the *) 12(* special exception on linking described in the file LICENSE. *) 13(* *) 14(**************************************************************************) 15 16(* bytegen.ml : translation of lambda terms to lists of instructions. *) 17 18open Misc 19open Asttypes 20open Primitive 21open Types 22open Lambda 23open Switch 24open Instruct 25 26(**** Label generation ****) 27 28let label_counter = ref 0 29 30let new_label () = 31 incr label_counter; !label_counter 32 33(**** Operations on compilation environments. ****) 34 35let empty_env = 36 { ce_stack = Ident.empty; ce_heap = Ident.empty; ce_rec = Ident.empty } 37 38(* Add a stack-allocated variable *) 39 40let add_var id pos env = 41 { ce_stack = Ident.add id pos env.ce_stack; 42 ce_heap = env.ce_heap; 43 ce_rec = env.ce_rec } 44 45let rec add_vars idlist pos env = 46 match idlist with 47 [] -> env 48 | id :: rem -> add_vars rem (pos + 1) (add_var id pos env) 49 50(**** Examination of the continuation ****) 51 52(* Return a label to the beginning of the given continuation. 53 If the sequence starts with a branch, use the target of that branch 54 as the label, thus avoiding a jump to a jump. *) 55 56let label_code = function 57 Kbranch lbl :: _ as cont -> (lbl, cont) 58 | Klabel lbl :: _ as cont -> (lbl, cont) 59 | cont -> let lbl = new_label() in (lbl, Klabel lbl :: cont) 60 61(* Return a branch to the continuation. That is, an instruction that, 62 when executed, branches to the continuation or performs what the 63 continuation performs. We avoid generating branches to branches and 64 branches to returns. *) 65 66let rec make_branch_2 lbl n cont = 67 function 68 Kreturn m :: _ -> (Kreturn (n + m), cont) 69 | Klabel _ :: c -> make_branch_2 lbl n cont c 70 | Kpop m :: c -> make_branch_2 lbl (n + m) cont c 71 | _ -> 72 match lbl with 73 Some lbl -> (Kbranch lbl, cont) 74 | None -> let lbl = new_label() in (Kbranch lbl, Klabel lbl :: cont) 75 76let make_branch cont = 77 match cont with 78 (Kbranch _ as branch) :: _ -> (branch, cont) 79 | (Kreturn _ as return) :: _ -> (return, cont) 80 | Kraise k :: _ -> (Kraise k, cont) 81 | Klabel lbl :: _ -> make_branch_2 (Some lbl) 0 cont cont 82 | _ -> make_branch_2 (None) 0 cont cont 83 84(* Avoid a branch to a label that follows immediately *) 85 86let branch_to label cont = match cont with 87| Klabel label0::_ when label = label0 -> cont 88| _ -> Kbranch label::cont 89 90(* Discard all instructions up to the next label. 91 This function is to be applied to the continuation before adding a 92 non-terminating instruction (branch, raise, return) in front of it. *) 93 94let rec discard_dead_code = function 95 [] -> [] 96 | (Klabel _ | Krestart | Ksetglobal _) :: _ as cont -> cont 97 | _ :: cont -> discard_dead_code cont 98 99(* Check if we're in tailcall position *) 100 101let rec is_tailcall = function 102 Kreturn _ :: _ -> true 103 | Klabel _ :: c -> is_tailcall c 104 | Kpop _ :: c -> is_tailcall c 105 | _ -> false 106 107(* Add a Kpop N instruction in front of a continuation *) 108 109let rec add_pop n cont = 110 if n = 0 then cont else 111 match cont with 112 Kpop m :: cont -> add_pop (n + m) cont 113 | Kreturn m :: cont -> Kreturn(n + m) :: cont 114 | Kraise _ :: _ -> cont 115 | _ -> Kpop n :: cont 116 117(* Add the constant "unit" in front of a continuation *) 118 119let add_const_unit = function 120 (Kacc _ | Kconst _ | Kgetglobal _ | Kpush_retaddr _) :: _ as cont -> cont 121 | cont -> Kconst const_unit :: cont 122 123let rec push_dummies n k = match n with 124| 0 -> k 125| _ -> Kconst const_unit::Kpush::push_dummies (n-1) k 126 127 128(**** Auxiliary for compiling "let rec" ****) 129 130type rhs_kind = 131 | RHS_block of int 132 | RHS_floatblock of int 133 | RHS_nonrec 134 | RHS_function of int * int 135;; 136 137let rec check_recordwith_updates id e = 138 match e with 139 | Lsequence (Lprim ((Psetfield _ | Psetfloatfield _), [Lvar id2; _], _), cont) 140 -> id2 = id && check_recordwith_updates id cont 141 | Lvar id2 -> id2 = id 142 | _ -> false 143;; 144 145let rec size_of_lambda = function 146 | Lfunction{params} as funct -> 147 RHS_function (1 + IdentSet.cardinal(free_variables funct), 148 List.length params) 149 | Llet (Strict, _k, id, Lprim (Pduprecord (kind, size), _, _), body) 150 when check_recordwith_updates id body -> 151 begin match kind with 152 | Record_regular | Record_inlined _ -> RHS_block size 153 | Record_unboxed _ -> assert false 154 | Record_float -> RHS_floatblock size 155 | Record_extension -> RHS_block (size + 1) 156 end 157 | Llet(_str, _k, _id, _arg, body) -> size_of_lambda body 158 | Lletrec(_bindings, body) -> size_of_lambda body 159 | Lprim(Pmakeblock _, args, _) -> RHS_block (List.length args) 160 | Lprim (Pmakearray ((Paddrarray|Pintarray), _), args, _) -> 161 RHS_block (List.length args) 162 | Lprim (Pmakearray (Pfloatarray, _), args, _) -> 163 RHS_floatblock (List.length args) 164 | Lprim (Pmakearray (Pgenarray, _), _, _) -> assert false 165 | Lprim (Pduprecord ((Record_regular | Record_inlined _), size), _, _) -> 166 RHS_block size 167 | Lprim (Pduprecord (Record_unboxed _, _), _, _) -> 168 assert false 169 | Lprim (Pduprecord (Record_extension, size), _, _) -> 170 RHS_block (size + 1) 171 | Lprim (Pduprecord (Record_float, size), _, _) -> RHS_floatblock size 172 | Levent (lam, _) -> size_of_lambda lam 173 | Lsequence (_lam, lam') -> size_of_lambda lam' 174 | _ -> RHS_nonrec 175 176(**** Merging consecutive events ****) 177 178let copy_event ev kind info repr = 179 { ev_pos = 0; (* patched in emitcode *) 180 ev_module = ev.ev_module; 181 ev_loc = ev.ev_loc; 182 ev_kind = kind; 183 ev_info = info; 184 ev_typenv = ev.ev_typenv; 185 ev_typsubst = ev.ev_typsubst; 186 ev_compenv = ev.ev_compenv; 187 ev_stacksize = ev.ev_stacksize; 188 ev_repr = repr } 189 190let merge_infos ev ev' = 191 match ev.ev_info, ev'.ev_info with 192 Event_other, info -> info 193 | info, Event_other -> info 194 | _ -> fatal_error "Bytegen.merge_infos" 195 196let merge_repr ev ev' = 197 match ev.ev_repr, ev'.ev_repr with 198 Event_none, x -> x 199 | x, Event_none -> x 200 | Event_parent r, Event_child r' when r == r' && !r = 1 -> Event_none 201 | Event_child r, Event_parent r' when r == r' -> Event_parent r 202 | _, _ -> fatal_error "Bytegen.merge_repr" 203 204let merge_events ev ev' = 205 let (maj, min) = 206 match ev.ev_kind, ev'.ev_kind with 207 (* Discard pseudo-events *) 208 Event_pseudo, _ -> ev', ev 209 | _, Event_pseudo -> ev, ev' 210 (* Keep following event, supposedly more informative *) 211 | Event_before, (Event_after _ | Event_before) -> ev', ev 212 (* Discard following events, supposedly less informative *) 213 | Event_after _, (Event_after _ | Event_before) -> ev, ev' 214 in 215 copy_event maj maj.ev_kind (merge_infos maj min) (merge_repr maj min) 216 217let weaken_event ev cont = 218 match ev.ev_kind with 219 Event_after _ -> 220 begin match cont with 221 Kpush :: Kevent ({ev_repr = Event_none} as ev') :: c -> 222 begin match ev.ev_info with 223 Event_return _ -> 224 (* Weaken event *) 225 let repr = ref 1 in 226 let ev = 227 copy_event ev Event_pseudo ev.ev_info (Event_parent repr) 228 and ev' = 229 copy_event ev' ev'.ev_kind ev'.ev_info (Event_child repr) 230 in 231 Kevent ev :: Kpush :: Kevent ev' :: c 232 | _ -> 233 (* Only keep following event, equivalent *) 234 cont 235 end 236 | _ -> 237 Kevent ev :: cont 238 end 239 | _ -> 240 Kevent ev :: cont 241 242let add_event ev = 243 function 244 Kevent ev' :: cont -> weaken_event (merge_events ev ev') cont 245 | cont -> weaken_event ev cont 246 247(**** Compilation of a lambda expression ****) 248 249let try_blocks = ref [] (* list of stack size for each nested try block *) 250 251(* association staticraise numbers -> (lbl,size of stack, try_blocks *) 252 253let sz_static_raises = ref [] 254 255let push_static_raise i lbl_handler sz = 256 sz_static_raises := (i, (lbl_handler, sz, !try_blocks)) :: !sz_static_raises 257 258let find_raise_label i = 259 try 260 List.assoc i !sz_static_raises 261 with 262 | Not_found -> 263 Misc.fatal_error 264 ("exit("^string_of_int i^") outside appropriated catch") 265 266(* Will the translation of l lead to a jump to label ? *) 267let code_as_jump l sz = match l with 268| Lstaticraise (i,[]) -> 269 let label,size,tb = find_raise_label i in 270 if sz = size && tb == !try_blocks then 271 Some label 272 else 273 None 274| _ -> None 275 276(* Function bodies that remain to be compiled *) 277 278type function_to_compile = 279 { params: Ident.t list; (* function parameters *) 280 body: lambda; (* the function body *) 281 label: label; (* the label of the function entry *) 282 free_vars: Ident.t list; (* free variables of the function *) 283 num_defs: int; (* number of mutually recursive definitions *) 284 rec_vars: Ident.t list; (* mutually recursive fn names *) 285 rec_pos: int } (* rank in recursive definition *) 286 287let functions_to_compile = (Stack.create () : function_to_compile Stack.t) 288 289(* Name of current compilation unit (for debugging events) *) 290 291let compunit_name = ref "" 292 293(* Maximal stack size reached during the current function body *) 294 295let max_stack_used = ref 0 296 297 298(* Sequence of string tests *) 299 300 301(* Translate a primitive to a bytecode instruction (possibly a call to a C 302 function) *) 303 304let comp_bint_primitive bi suff args = 305 let pref = 306 match bi with Pnativeint -> "caml_nativeint_" 307 | Pint32 -> "caml_int32_" 308 | Pint64 -> "caml_int64_" in 309 Kccall(pref ^ suff, List.length args) 310 311let comp_primitive p args = 312 match p with 313 Pgetglobal id -> Kgetglobal id 314 | Psetglobal id -> Ksetglobal id 315 | Pintcomp cmp -> Kintcomp cmp 316 | Pmakeblock(tag, _mut, _) -> Kmakeblock(List.length args, tag) 317 | Pfield n -> Kgetfield n 318 | Pfield_computed -> Kgetvectitem 319 | Psetfield(n, _ptr, _init) -> Ksetfield n 320 | Psetfield_computed(_ptr, _init) -> Ksetvectitem 321 | Pfloatfield n -> Kgetfloatfield n 322 | Psetfloatfield (n, _init) -> Ksetfloatfield n 323 | Pduprecord _ -> Kccall("caml_obj_dup", 1) 324 | Pccall p -> Kccall(p.prim_name, p.prim_arity) 325 | Pnegint -> Knegint 326 | Paddint -> Kaddint 327 | Psubint -> Ksubint 328 | Pmulint -> Kmulint 329 | Pdivint _ -> Kdivint 330 | Pmodint _ -> Kmodint 331 | Pandint -> Kandint 332 | Porint -> Korint 333 | Pxorint -> Kxorint 334 | Plslint -> Klslint 335 | Plsrint -> Klsrint 336 | Pasrint -> Kasrint 337 | Poffsetint n -> Koffsetint n 338 | Poffsetref n -> Koffsetref n 339 | Pintoffloat -> Kccall("caml_int_of_float", 1) 340 | Pfloatofint -> Kccall("caml_float_of_int", 1) 341 | Pnegfloat -> Kccall("caml_neg_float", 1) 342 | Pabsfloat -> Kccall("caml_abs_float", 1) 343 | Paddfloat -> Kccall("caml_add_float", 2) 344 | Psubfloat -> Kccall("caml_sub_float", 2) 345 | Pmulfloat -> Kccall("caml_mul_float", 2) 346 | Pdivfloat -> Kccall("caml_div_float", 2) 347 | Pfloatcomp Ceq -> Kccall("caml_eq_float", 2) 348 | Pfloatcomp Cneq -> Kccall("caml_neq_float", 2) 349 | Pfloatcomp Clt -> Kccall("caml_lt_float", 2) 350 | Pfloatcomp Cgt -> Kccall("caml_gt_float", 2) 351 | Pfloatcomp Cle -> Kccall("caml_le_float", 2) 352 | Pfloatcomp Cge -> Kccall("caml_ge_float", 2) 353 | Pstringlength -> Kccall("caml_ml_string_length", 1) 354 | Pbyteslength -> Kccall("caml_ml_bytes_length", 1) 355 | Pstringrefs -> Kccall("caml_string_get", 2) 356 | Pbytesrefs -> Kccall("caml_bytes_get", 2) 357 | Pbytessets -> Kccall("caml_bytes_set", 3) 358 | Pstringrefu | Pbytesrefu -> Kgetstringchar 359 | Pbytessetu -> Ksetstringchar 360 | Pstring_load_16(_) -> Kccall("caml_string_get16", 2) 361 | Pstring_load_32(_) -> Kccall("caml_string_get32", 2) 362 | Pstring_load_64(_) -> Kccall("caml_string_get64", 2) 363 | Pstring_set_16(_) -> Kccall("caml_string_set16", 3) 364 | Pstring_set_32(_) -> Kccall("caml_string_set32", 3) 365 | Pstring_set_64(_) -> Kccall("caml_string_set64", 3) 366 | Parraylength _ -> Kvectlength 367 | Parrayrefs Pgenarray -> Kccall("caml_array_get", 2) 368 | Parrayrefs Pfloatarray -> Kccall("caml_array_get_float", 2) 369 | Parrayrefs _ -> Kccall("caml_array_get_addr", 2) 370 | Parraysets Pgenarray -> Kccall("caml_array_set", 3) 371 | Parraysets Pfloatarray -> Kccall("caml_array_set_float", 3) 372 | Parraysets _ -> Kccall("caml_array_set_addr", 3) 373 | Parrayrefu Pgenarray -> Kccall("caml_array_unsafe_get", 2) 374 | Parrayrefu Pfloatarray -> Kccall("caml_array_unsafe_get_float", 2) 375 | Parrayrefu _ -> Kgetvectitem 376 | Parraysetu Pgenarray -> Kccall("caml_array_unsafe_set", 3) 377 | Parraysetu Pfloatarray -> Kccall("caml_array_unsafe_set_float", 3) 378 | Parraysetu _ -> Ksetvectitem 379 | Pctconst c -> 380 let const_name = match c with 381 | Big_endian -> "big_endian" 382 | Word_size -> "word_size" 383 | Int_size -> "int_size" 384 | Max_wosize -> "max_wosize" 385 | Ostype_unix -> "ostype_unix" 386 | Ostype_win32 -> "ostype_win32" 387 | Ostype_cygwin -> "ostype_cygwin" 388 | Backend_type -> "backend_type" in 389 Kccall(Printf.sprintf "caml_sys_const_%s" const_name, 1) 390 | Pisint -> Kisint 391 | Pisout -> Kisout 392 | Pbittest -> Kccall("caml_bitvect_test", 2) 393 | Pbintofint bi -> comp_bint_primitive bi "of_int" args 394 | Pintofbint bi -> comp_bint_primitive bi "to_int" args 395 | Pcvtbint(Pint32, Pnativeint) -> Kccall("caml_nativeint_of_int32", 1) 396 | Pcvtbint(Pnativeint, Pint32) -> Kccall("caml_nativeint_to_int32", 1) 397 | Pcvtbint(Pint32, Pint64) -> Kccall("caml_int64_of_int32", 1) 398 | Pcvtbint(Pint64, Pint32) -> Kccall("caml_int64_to_int32", 1) 399 | Pcvtbint(Pnativeint, Pint64) -> Kccall("caml_int64_of_nativeint", 1) 400 | Pcvtbint(Pint64, Pnativeint) -> Kccall("caml_int64_to_nativeint", 1) 401 | Pnegbint bi -> comp_bint_primitive bi "neg" args 402 | Paddbint bi -> comp_bint_primitive bi "add" args 403 | Psubbint bi -> comp_bint_primitive bi "sub" args 404 | Pmulbint bi -> comp_bint_primitive bi "mul" args 405 | Pdivbint { size = bi } -> comp_bint_primitive bi "div" args 406 | Pmodbint { size = bi } -> comp_bint_primitive bi "mod" args 407 | Pandbint bi -> comp_bint_primitive bi "and" args 408 | Porbint bi -> comp_bint_primitive bi "or" args 409 | Pxorbint bi -> comp_bint_primitive bi "xor" args 410 | Plslbint bi -> comp_bint_primitive bi "shift_left" args 411 | Plsrbint bi -> comp_bint_primitive bi "shift_right_unsigned" args 412 | Pasrbint bi -> comp_bint_primitive bi "shift_right" args 413 | Pbintcomp(_, Ceq) -> Kccall("caml_equal", 2) 414 | Pbintcomp(_, Cneq) -> Kccall("caml_notequal", 2) 415 | Pbintcomp(_, Clt) -> Kccall("caml_lessthan", 2) 416 | Pbintcomp(_, Cgt) -> Kccall("caml_greaterthan", 2) 417 | Pbintcomp(_, Cle) -> Kccall("caml_lessequal", 2) 418 | Pbintcomp(_, Cge) -> Kccall("caml_greaterequal", 2) 419 | Pbigarrayref(_, n, _, _) -> Kccall("caml_ba_get_" ^ string_of_int n, n + 1) 420 | Pbigarrayset(_, n, _, _) -> Kccall("caml_ba_set_" ^ string_of_int n, n + 2) 421 | Pbigarraydim(n) -> Kccall("caml_ba_dim_" ^ string_of_int n, 1) 422 | Pbigstring_load_16(_) -> Kccall("caml_ba_uint8_get16", 2) 423 | Pbigstring_load_32(_) -> Kccall("caml_ba_uint8_get32", 2) 424 | Pbigstring_load_64(_) -> Kccall("caml_ba_uint8_get64", 2) 425 | Pbigstring_set_16(_) -> Kccall("caml_ba_uint8_set16", 3) 426 | Pbigstring_set_32(_) -> Kccall("caml_ba_uint8_set32", 3) 427 | Pbigstring_set_64(_) -> Kccall("caml_ba_uint8_set64", 3) 428 | Pbswap16 -> Kccall("caml_bswap16", 1) 429 | Pbbswap(bi) -> comp_bint_primitive bi "bswap" args 430 | Pint_as_pointer -> Kccall("caml_int_as_pointer", 1) 431 | _ -> fatal_error "Bytegen.comp_primitive" 432 433let is_immed n = immed_min <= n && n <= immed_max 434 435module Storer = 436 Switch.Store 437 (struct type t = lambda type key = lambda 438 let make_key = Lambda.make_key end) 439 440(* Compile an expression. 441 The value of the expression is left in the accumulator. 442 env = compilation environment 443 exp = the lambda expression to compile 444 sz = current size of the stack frame 445 cont = list of instructions to execute afterwards 446 Result = list of instructions that evaluate exp, then perform cont. *) 447 448let rec comp_expr env exp sz cont = 449 if sz > !max_stack_used then max_stack_used := sz; 450 match exp with 451 Lvar id -> 452 begin try 453 let pos = Ident.find_same id env.ce_stack in 454 Kacc(sz - pos) :: cont 455 with Not_found -> 456 try 457 let pos = Ident.find_same id env.ce_heap in 458 Kenvacc(pos) :: cont 459 with Not_found -> 460 try 461 let ofs = Ident.find_same id env.ce_rec in 462 Koffsetclosure(ofs) :: cont 463 with Not_found -> 464 fatal_error ("Bytegen.comp_expr: var " ^ Ident.unique_name id) 465 end 466 | Lconst cst -> 467 Kconst cst :: cont 468 | Lapply{ap_func = func; ap_args = args} -> 469 let nargs = List.length args in 470 if is_tailcall cont then begin 471 comp_args env args sz 472 (Kpush :: comp_expr env func (sz + nargs) 473 (Kappterm(nargs, sz + nargs) :: discard_dead_code cont)) 474 end else begin 475 if nargs < 4 then 476 comp_args env args sz 477 (Kpush :: comp_expr env func (sz + nargs) (Kapply nargs :: cont)) 478 else begin 479 let (lbl, cont1) = label_code cont in 480 Kpush_retaddr lbl :: 481 comp_args env args (sz + 3) 482 (Kpush :: comp_expr env func (sz + 3 + nargs) 483 (Kapply nargs :: cont1)) 484 end 485 end 486 | Lsend(kind, met, obj, args, _) -> 487 let args = if kind = Cached then List.tl args else args in 488 let nargs = List.length args + 1 in 489 let getmethod, args' = 490 if kind = Self then (Kgetmethod, met::obj::args) else 491 match met with 492 Lconst(Const_base(Const_int n)) -> (Kgetpubmet n, obj::args) 493 | _ -> (Kgetdynmet, met::obj::args) 494 in 495 if is_tailcall cont then 496 comp_args env args' sz 497 (getmethod :: Kappterm(nargs, sz + nargs) :: discard_dead_code cont) 498 else 499 if nargs < 4 then 500 comp_args env args' sz 501 (getmethod :: Kapply nargs :: cont) 502 else begin 503 let (lbl, cont1) = label_code cont in 504 Kpush_retaddr lbl :: 505 comp_args env args' (sz + 3) 506 (getmethod :: Kapply nargs :: cont1) 507 end 508 | Lfunction{params; body} -> (* assume kind = Curried *) 509 let lbl = new_label() in 510 let fv = IdentSet.elements(free_variables exp) in 511 let to_compile = 512 { params = params; body = body; label = lbl; 513 free_vars = fv; num_defs = 1; rec_vars = []; rec_pos = 0 } in 514 Stack.push to_compile functions_to_compile; 515 comp_args env (List.map (fun n -> Lvar n) fv) sz 516 (Kclosure(lbl, List.length fv) :: cont) 517 | Llet(_str, _k, id, arg, body) -> 518 comp_expr env arg sz 519 (Kpush :: comp_expr (add_var id (sz+1) env) body (sz+1) 520 (add_pop 1 cont)) 521 | Lletrec(decl, body) -> 522 let ndecl = List.length decl in 523 if List.for_all (function (_, Lfunction _) -> true | _ -> false) 524 decl then begin 525 (* let rec of functions *) 526 let fv = 527 IdentSet.elements (free_variables (Lletrec(decl, lambda_unit))) in 528 let rec_idents = List.map (fun (id, _lam) -> id) decl in 529 let rec comp_fun pos = function 530 [] -> [] 531 | (_id, Lfunction{params; body}) :: rem -> 532 let lbl = new_label() in 533 let to_compile = 534 { params = params; body = body; label = lbl; free_vars = fv; 535 num_defs = ndecl; rec_vars = rec_idents; rec_pos = pos} in 536 Stack.push to_compile functions_to_compile; 537 lbl :: comp_fun (pos + 1) rem 538 | _ -> assert false in 539 let lbls = comp_fun 0 decl in 540 comp_args env (List.map (fun n -> Lvar n) fv) sz 541 (Kclosurerec(lbls, List.length fv) :: 542 (comp_expr (add_vars rec_idents (sz+1) env) body (sz + ndecl) 543 (add_pop ndecl cont))) 544 end else begin 545 let decl_size = 546 List.map (fun (id, exp) -> (id, exp, size_of_lambda exp)) decl in 547 let rec comp_init new_env sz = function 548 | [] -> comp_nonrec new_env sz ndecl decl_size 549 | (id, _exp, RHS_floatblock blocksize) :: rem -> 550 Kconst(Const_base(Const_int blocksize)) :: 551 Kccall("caml_alloc_dummy_float", 1) :: Kpush :: 552 comp_init (add_var id (sz+1) new_env) (sz+1) rem 553 | (id, _exp, RHS_block blocksize) :: rem -> 554 Kconst(Const_base(Const_int blocksize)) :: 555 Kccall("caml_alloc_dummy", 1) :: Kpush :: 556 comp_init (add_var id (sz+1) new_env) (sz+1) rem 557 | (id, _exp, RHS_function (blocksize,arity)) :: rem -> 558 Kconst(Const_base(Const_int arity)) :: 559 Kpush :: 560 Kconst(Const_base(Const_int blocksize)) :: 561 Kccall("caml_alloc_dummy_function", 2) :: Kpush :: 562 comp_init (add_var id (sz+1) new_env) (sz+1) rem 563 | (id, _exp, RHS_nonrec) :: rem -> 564 Kconst(Const_base(Const_int 0)) :: Kpush :: 565 comp_init (add_var id (sz+1) new_env) (sz+1) rem 566 and comp_nonrec new_env sz i = function 567 | [] -> comp_rec new_env sz ndecl decl_size 568 | (_id, _exp, (RHS_block _ | RHS_floatblock _ | RHS_function _)) 569 :: rem -> 570 comp_nonrec new_env sz (i-1) rem 571 | (_id, exp, RHS_nonrec) :: rem -> 572 comp_expr new_env exp sz 573 (Kassign (i-1) :: comp_nonrec new_env sz (i-1) rem) 574 and comp_rec new_env sz i = function 575 | [] -> comp_expr new_env body sz (add_pop ndecl cont) 576 | (_id, exp, (RHS_block _ | RHS_floatblock _ | RHS_function _)) 577 :: rem -> 578 comp_expr new_env exp sz 579 (Kpush :: Kacc i :: Kccall("caml_update_dummy", 2) :: 580 comp_rec new_env sz (i-1) rem) 581 | (_id, _exp, RHS_nonrec) :: rem -> 582 comp_rec new_env sz (i-1) rem 583 in 584 comp_init env sz decl_size 585 end 586 | Lprim((Pidentity | Popaque | Pbytes_to_string | Pbytes_of_string), [arg], _) 587 -> 588 comp_expr env arg sz cont 589 | Lprim(Pignore, [arg], _) -> 590 comp_expr env arg sz (add_const_unit cont) 591 | Lprim(Pdirapply, [func;arg], loc) 592 | Lprim(Prevapply, [arg;func], loc) -> 593 let exp = Lapply{ap_should_be_tailcall=false; 594 ap_loc=loc; 595 ap_func=func; 596 ap_args=[arg]; 597 ap_inlined=Default_inline; 598 ap_specialised=Default_specialise} in 599 comp_expr env exp sz cont 600 | Lprim(Pnot, [arg], _) -> 601 let newcont = 602 match cont with 603 Kbranchif lbl :: cont1 -> Kbranchifnot lbl :: cont1 604 | Kbranchifnot lbl :: cont1 -> Kbranchif lbl :: cont1 605 | _ -> Kboolnot :: cont in 606 comp_expr env arg sz newcont 607 | Lprim(Psequand, [exp1; exp2], _) -> 608 begin match cont with 609 Kbranchifnot lbl :: _ -> 610 comp_expr env exp1 sz (Kbranchifnot lbl :: 611 comp_expr env exp2 sz cont) 612 | Kbranchif lbl :: cont1 -> 613 let (lbl2, cont2) = label_code cont1 in 614 comp_expr env exp1 sz (Kbranchifnot lbl2 :: 615 comp_expr env exp2 sz (Kbranchif lbl :: cont2)) 616 | _ -> 617 let (lbl, cont1) = label_code cont in 618 comp_expr env exp1 sz (Kstrictbranchifnot lbl :: 619 comp_expr env exp2 sz cont1) 620 end 621 | Lprim(Psequor, [exp1; exp2], _) -> 622 begin match cont with 623 Kbranchif lbl :: _ -> 624 comp_expr env exp1 sz (Kbranchif lbl :: 625 comp_expr env exp2 sz cont) 626 | Kbranchifnot lbl :: cont1 -> 627 let (lbl2, cont2) = label_code cont1 in 628 comp_expr env exp1 sz (Kbranchif lbl2 :: 629 comp_expr env exp2 sz (Kbranchifnot lbl :: cont2)) 630 | _ -> 631 let (lbl, cont1) = label_code cont in 632 comp_expr env exp1 sz (Kstrictbranchif lbl :: 633 comp_expr env exp2 sz cont1) 634 end 635 | Lprim(Praise k, [arg], _) -> 636 comp_expr env arg sz (Kraise k :: discard_dead_code cont) 637 | Lprim(Paddint, [arg; Lconst(Const_base(Const_int n))], _) 638 when is_immed n -> 639 comp_expr env arg sz (Koffsetint n :: cont) 640 | Lprim(Psubint, [arg; Lconst(Const_base(Const_int n))], _) 641 when is_immed (-n) -> 642 comp_expr env arg sz (Koffsetint (-n) :: cont) 643 | Lprim (Poffsetint n, [arg], _) 644 when not (is_immed n) -> 645 comp_expr env arg sz 646 (Kpush:: 647 Kconst (Const_base (Const_int n)):: 648 Kaddint::cont) 649 | Lprim(Pmakearray (kind, _), args, _) -> 650 begin match kind with 651 Pintarray | Paddrarray -> 652 comp_args env args sz (Kmakeblock(List.length args, 0) :: cont) 653 | Pfloatarray -> 654 comp_args env args sz (Kmakefloatblock(List.length args) :: cont) 655 | Pgenarray -> 656 if args = [] 657 then Kmakeblock(0, 0) :: cont 658 else comp_args env args sz 659 (Kmakeblock(List.length args, 0) :: 660 Kccall("caml_make_array", 1) :: cont) 661 end 662 | Lprim (Pduparray (kind, mutability), 663 [Lprim (Pmakearray (kind',_),args,_)], loc) -> 664 assert (kind = kind'); 665 comp_expr env (Lprim (Pmakearray (kind, mutability), args, loc)) sz cont 666 | Lprim (Pduparray _, [arg], loc) -> 667 let prim_obj_dup = 668 Primitive.simple ~name:"caml_obj_dup" ~arity:1 ~alloc:true 669 in 670 comp_expr env (Lprim (Pccall prim_obj_dup, [arg], loc)) sz cont 671 | Lprim (Pduparray _, _, _) -> 672 Misc.fatal_error "Bytegen.comp_expr: Pduparray takes exactly one arg" 673(* Integer first for enabling futher optimization (cf. emitcode.ml) *) 674 | Lprim (Pintcomp c, [arg ; (Lconst _ as k)], _) -> 675 let p = Pintcomp (commute_comparison c) 676 and args = [k ; arg] in 677 comp_args env args sz (comp_primitive p args :: cont) 678 | Lprim(p, args, _) -> 679 comp_args env args sz (comp_primitive p args :: cont) 680 | Lstaticcatch (body, (i, vars) , handler) -> 681 let nvars = List.length vars in 682 let branch1, cont1 = make_branch cont in 683 let r = 684 if nvars <> 1 then begin (* general case *) 685 let lbl_handler, cont2 = 686 label_code 687 (comp_expr 688 (add_vars vars (sz+1) env) 689 handler (sz+nvars) (add_pop nvars cont1)) in 690 push_static_raise i lbl_handler (sz+nvars); 691 push_dummies nvars 692 (comp_expr env body (sz+nvars) 693 (add_pop nvars (branch1 :: cont2))) 694 end else begin (* small optimization for nvars = 1 *) 695 let var = match vars with [var] -> var | _ -> assert false in 696 let lbl_handler, cont2 = 697 label_code 698 (Kpush::comp_expr 699 (add_var var (sz+1) env) 700 handler (sz+1) (add_pop 1 cont1)) in 701 push_static_raise i lbl_handler sz; 702 comp_expr env body sz (branch1 :: cont2) 703 end in 704 sz_static_raises := List.tl !sz_static_raises ; 705 r 706 | Lstaticraise (i, args) -> 707 let cont = discard_dead_code cont in 708 let label,size,tb = find_raise_label i in 709 let cont = branch_to label cont in 710 let rec loop sz tbb = 711 if tb == tbb then add_pop (sz-size) cont 712 else match tbb with 713 | [] -> assert false 714 | try_sz :: tbb -> add_pop (sz-try_sz-4) (Kpoptrap :: loop try_sz tbb) 715 in 716 let cont = loop sz !try_blocks in 717 begin match args with 718 | [arg] -> (* optim, argument passed in accumulator *) 719 comp_expr env arg sz cont 720 | _ -> comp_exit_args env args sz size cont 721 end 722 | Ltrywith(body, id, handler) -> 723 let (branch1, cont1) = make_branch cont in 724 let lbl_handler = new_label() in 725 let body_cont = 726 Kpoptrap :: branch1 :: 727 Klabel lbl_handler :: Kpush :: 728 comp_expr (add_var id (sz+1) env) handler (sz+1) (add_pop 1 cont1) 729 in 730 try_blocks := sz :: !try_blocks; 731 let l = comp_expr env body (sz+4) body_cont in 732 try_blocks := List.tl !try_blocks; 733 Kpushtrap lbl_handler :: l 734 | Lifthenelse(cond, ifso, ifnot) -> 735 comp_binary_test env cond ifso ifnot sz cont 736 | Lsequence(exp1, exp2) -> 737 comp_expr env exp1 sz (comp_expr env exp2 sz cont) 738 | Lwhile(cond, body) -> 739 let lbl_loop = new_label() in 740 let lbl_test = new_label() in 741 Kbranch lbl_test :: Klabel lbl_loop :: Kcheck_signals :: 742 comp_expr env body sz 743 (Klabel lbl_test :: 744 comp_expr env cond sz (Kbranchif lbl_loop :: add_const_unit cont)) 745 | Lfor(param, start, stop, dir, body) -> 746 let lbl_loop = new_label() in 747 let lbl_exit = new_label() in 748 let offset = match dir with Upto -> 1 | Downto -> -1 in 749 let comp = match dir with Upto -> Cgt | Downto -> Clt in 750 comp_expr env start sz 751 (Kpush :: comp_expr env stop (sz+1) 752 (Kpush :: Kpush :: Kacc 2 :: Kintcomp comp :: Kbranchif lbl_exit :: 753 Klabel lbl_loop :: Kcheck_signals :: 754 comp_expr (add_var param (sz+1) env) body (sz+2) 755 (Kacc 1 :: Kpush :: Koffsetint offset :: Kassign 2 :: 756 Kacc 1 :: Kintcomp Cneq :: Kbranchif lbl_loop :: 757 Klabel lbl_exit :: add_const_unit (add_pop 2 cont)))) 758 | Lswitch(arg, sw) -> 759 let (branch, cont1) = make_branch cont in 760 let c = ref (discard_dead_code cont1) in 761 762(* Build indirection vectors *) 763 let store = Storer.mk_store () in 764 let act_consts = Array.make sw.sw_numconsts 0 765 and act_blocks = Array.make sw.sw_numblocks 0 in 766 begin match sw.sw_failaction with (* default is index 0 *) 767 | Some fail -> ignore (store.act_store fail) 768 | None -> () 769 end ; 770 List.iter 771 (fun (n, act) -> act_consts.(n) <- store.act_store act) sw.sw_consts; 772 List.iter 773 (fun (n, act) -> act_blocks.(n) <- store.act_store act) sw.sw_blocks; 774(* Compile and label actions *) 775 let acts = store.act_get () in 776(* 777 let a = store.act_get_shared () in 778 Array.iter 779 (function 780 | Switch.Shared (Lstaticraise _) -> () 781 | Switch.Shared act -> 782 Printlambda.lambda Format.str_formatter act ; 783 Printf.eprintf "SHARE BYTE:\n%s\n" (Format.flush_str_formatter ()) 784 | _ -> ()) 785 a ; 786*) 787 let lbls = Array.make (Array.length acts) 0 in 788 for i = Array.length acts-1 downto 0 do 789 let lbl,c1 = label_code (comp_expr env acts.(i) sz (branch :: !c)) in 790 lbls.(i) <- lbl ; 791 c := discard_dead_code c1 792 done ; 793 794(* Build label vectors *) 795 let lbl_blocks = Array.make sw.sw_numblocks 0 in 796 for i = sw.sw_numblocks - 1 downto 0 do 797 lbl_blocks.(i) <- lbls.(act_blocks.(i)) 798 done; 799 let lbl_consts = Array.make sw.sw_numconsts 0 in 800 for i = sw.sw_numconsts - 1 downto 0 do 801 lbl_consts.(i) <- lbls.(act_consts.(i)) 802 done; 803 comp_expr env arg sz (Kswitch(lbl_consts, lbl_blocks) :: !c) 804 | Lstringswitch (arg,sw,d,loc) -> 805 comp_expr env (Matching.expand_stringswitch loc arg sw d) sz cont 806 | Lassign(id, expr) -> 807 begin try 808 let pos = Ident.find_same id env.ce_stack in 809 comp_expr env expr sz (Kassign(sz - pos) :: cont) 810 with Not_found -> 811 fatal_error "Bytegen.comp_expr: assign" 812 end 813 | Levent(lam, lev) -> 814 let event kind info = 815 { ev_pos = 0; (* patched in emitcode *) 816 ev_module = !compunit_name; 817 ev_loc = lev.lev_loc; 818 ev_kind = kind; 819 ev_info = info; 820 ev_typenv = lev.lev_env; 821 ev_typsubst = Subst.identity; 822 ev_compenv = env; 823 ev_stacksize = sz; 824 ev_repr = 825 begin match lev.lev_repr with 826 None -> 827 Event_none 828 | Some ({contents = 1} as repr) when lev.lev_kind = Lev_function -> 829 Event_child repr 830 | Some ({contents = 1} as repr) -> 831 Event_parent repr 832 | Some repr when lev.lev_kind = Lev_function -> 833 Event_parent repr 834 | Some repr -> 835 Event_child repr 836 end } 837 in 838 begin match lev.lev_kind with 839 Lev_before -> 840 let c = comp_expr env lam sz cont in 841 let ev = event Event_before Event_other in 842 add_event ev c 843 | Lev_function -> 844 let c = comp_expr env lam sz cont in 845 let ev = event Event_pseudo Event_function in 846 add_event ev c 847 | Lev_pseudo -> 848 let c = comp_expr env lam sz cont in 849 let ev = event Event_pseudo Event_other in 850 add_event ev c 851 | Lev_after _ when is_tailcall cont -> (* don't destroy tail call opt *) 852 comp_expr env lam sz cont 853 | Lev_after ty -> 854 let info = 855 match lam with 856 Lapply{ap_args = args} -> Event_return (List.length args) 857 | Lsend(_, _, _, args, _) -> Event_return (List.length args + 1) 858 | _ -> Event_other 859 in 860 let ev = event (Event_after ty) info in 861 let cont1 = add_event ev cont in 862 comp_expr env lam sz cont1 863 end 864 | Lifused (_, exp) -> 865 comp_expr env exp sz cont 866 867(* Compile a list of arguments [e1; ...; eN] to a primitive operation. 868 The values of eN ... e2 are pushed on the stack, e2 at top of stack, 869 then e3, then ... The value of e1 is left in the accumulator. *) 870 871and comp_args env argl sz cont = 872 comp_expr_list env (List.rev argl) sz cont 873 874and comp_expr_list env exprl sz cont = match exprl with 875 [] -> cont 876 | [exp] -> comp_expr env exp sz cont 877 | exp :: rem -> 878 comp_expr env exp sz (Kpush :: comp_expr_list env rem (sz+1) cont) 879 880and comp_exit_args env argl sz pos cont = 881 comp_expr_list_assign env (List.rev argl) sz pos cont 882 883and comp_expr_list_assign env exprl sz pos cont = match exprl with 884 | [] -> cont 885 | exp :: rem -> 886 comp_expr env exp sz 887 (Kassign (sz-pos)::comp_expr_list_assign env rem sz (pos-1) cont) 888 889(* Compile an if-then-else test. *) 890 891and comp_binary_test env cond ifso ifnot sz cont = 892 let cont_cond = 893 if ifnot = Lconst const_unit then begin 894 let (lbl_end, cont1) = label_code cont in 895 Kstrictbranchifnot lbl_end :: comp_expr env ifso sz cont1 896 end else 897 match code_as_jump ifso sz with 898 | Some label -> 899 let cont = comp_expr env ifnot sz cont in 900 Kbranchif label :: cont 901 | _ -> 902 match code_as_jump ifnot sz with 903 | Some label -> 904 let cont = comp_expr env ifso sz cont in 905 Kbranchifnot label :: cont 906 | _ -> 907 let (branch_end, cont1) = make_branch cont in 908 let (lbl_not, cont2) = label_code(comp_expr env ifnot sz cont1) in 909 Kbranchifnot lbl_not :: 910 comp_expr env ifso sz (branch_end :: cont2) in 911 912 comp_expr env cond sz cont_cond 913 914(**** Compilation of a code block (with tracking of stack usage) ****) 915 916let comp_block env exp sz cont = 917 max_stack_used := 0; 918 let code = comp_expr env exp sz cont in 919 let used_safe = !max_stack_used + Config.stack_safety_margin in 920 if used_safe > Config.stack_threshold then 921 Kconst(Const_base(Const_int used_safe)) :: 922 Kccall("caml_ensure_stack_capacity", 1) :: 923 code 924 else 925 code 926 927(**** Compilation of functions ****) 928 929let comp_function tc cont = 930 let arity = List.length tc.params in 931 let rec positions pos delta = function 932 [] -> Ident.empty 933 | id :: rem -> Ident.add id pos (positions (pos + delta) delta rem) in 934 let env = 935 { ce_stack = positions arity (-1) tc.params; 936 ce_heap = positions (2 * (tc.num_defs - tc.rec_pos) - 1) 1 tc.free_vars; 937 ce_rec = positions (-2 * tc.rec_pos) 2 tc.rec_vars } in 938 let cont = 939 comp_block env tc.body arity (Kreturn arity :: cont) in 940 if arity > 1 then 941 Krestart :: Klabel tc.label :: Kgrab(arity - 1) :: cont 942 else 943 Klabel tc.label :: cont 944 945let comp_remainder cont = 946 let c = ref cont in 947 begin try 948 while true do 949 c := comp_function (Stack.pop functions_to_compile) !c 950 done 951 with Stack.Empty -> 952 () 953 end; 954 !c 955 956(**** Compilation of a lambda phrase ****) 957 958let compile_implementation modulename expr = 959 Stack.clear functions_to_compile; 960 label_counter := 0; 961 sz_static_raises := [] ; 962 compunit_name := modulename; 963 let init_code = comp_block empty_env expr 0 [] in 964 if Stack.length functions_to_compile > 0 then begin 965 let lbl_init = new_label() in 966 Kbranch lbl_init :: comp_remainder (Klabel lbl_init :: init_code) 967 end else 968 init_code 969 970let compile_phrase expr = 971 Stack.clear functions_to_compile; 972 label_counter := 0; 973 sz_static_raises := [] ; 974 let init_code = comp_block empty_env expr 1 [Kreturn 1] in 975 let fun_code = comp_remainder [] in 976 (init_code, fun_code) 977 978let reset () = 979 label_counter := 0; 980 sz_static_raises := []; 981 compunit_name := ""; 982 Stack.clear functions_to_compile; 983 max_stack_used := 0 984