1287
1297
let divide_var ctx pm =
1288
1298
divide_line ctx_lshift make_var_matching get_args_var omega ctx pm
1300
(* Matching and forcing a lazy value *)
1302
let get_arg_lazy p rem = match p with
1303
| {pat_desc = Tpat_any} -> omega :: rem
1304
| {pat_desc = Tpat_lazy arg} -> arg :: rem
1307
let matcher_lazy p rem = match p.pat_desc with
1308
| Tpat_or (_,_,_) -> raise OrPat
1309
| Tpat_var _ -> get_arg_lazy omega rem
1310
| _ -> get_arg_lazy p rem
1312
(* Inlining the tag tests before calling the primitive that works on
1313
lazy blocks. This is alse used in translcore.ml.
1314
No call other than Obj.tag when the value has been forced before.
1318
{prim_name = "caml_obj_tag";
1319
prim_arity = 1; prim_alloc = false;
1320
prim_native_name = "";
1321
prim_native_float = false}
1323
let get_mod_field modname field =
1326
let mod_ident = Ident.create_persistent modname in
1327
let env = Env.open_pers_signature modname Env.initial in
1329
match Env.lookup_value (Longident.Lident field) env with
1330
| (Path.Pdot(_,_,i), _) -> i
1331
| _ -> fatal_error ("Primitive "^modname^"."^field^" not found.")
1332
with Not_found -> fatal_error ("Primitive "^modname^"."^field^" not found.")
1334
Lprim(Pfield p, [Lprim(Pgetglobal mod_ident, [])])
1335
with Not_found -> fatal_error ("Module "^modname^" unavailable.")
1338
let code_force_lazy_block =
1339
get_mod_field "CamlinternalLazy" "force_lazy_block"
1342
(* inline_lazy_force inlines the beginning of the code of Lazy.force. When
1343
the value argument is tagged as:
1344
- forward, take field 0
1345
- lazy, call the primitive that forces (without testing again the tag)
1346
- anything else, return it
1348
Using Lswitch below relies on the fact that the GC does not shortcut
1349
Forward(val_out_of_heap).
1352
let inline_lazy_force_cond arg loc =
1353
let idarg = Ident.create "lzarg" in
1354
let varg = Lvar idarg in
1355
let tag = Ident.create "tag" in
1356
let force_fun = Lazy.force code_force_lazy_block in
1357
Llet(Strict, idarg, arg,
1358
Llet(Alias, tag, Lprim(Pccall prim_obj_tag, [varg]),
1360
(* if (tag == Obj.forward_tag) then varg.(0) else ... *)
1362
[Lvar tag; Lconst(Const_base(Const_int Obj.forward_tag))]),
1363
Lprim(Pfield 0, [varg]),
1365
(* ... if (tag == Obj.lazy_tag) then Lazy.force varg else ... *)
1367
[Lvar tag; Lconst(Const_base(Const_int Obj.lazy_tag))]),
1368
Lapply(force_fun, [varg], loc),
1372
let inline_lazy_force_switch arg loc =
1373
let idarg = Ident.create "lzarg" in
1374
let varg = Lvar idarg in
1375
let force_fun = Lazy.force code_force_lazy_block in
1376
Llet(Strict, idarg, arg,
1378
Lprim(Pisint, [varg]), varg,
1381
{ sw_numconsts = 0; sw_consts = [];
1382
sw_numblocks = (max Obj.lazy_tag Obj.forward_tag) + 1;
1384
[ (Obj.forward_tag, Lprim(Pfield 0, [varg]));
1386
Lapply(force_fun, [varg], loc)) ];
1387
sw_failaction = Some varg } ))))
1389
let inline_lazy_force =
1390
if !Clflags.native_code then
1391
(* Lswitch generates compact and efficient native code *)
1392
inline_lazy_force_switch
1394
(* generating bytecode: Lswitch would generate too many rather big
1395
tables (~ 250 elts); conditionals are better *)
1396
inline_lazy_force_cond
1398
let make_lazy_matching def = function
1399
[] -> fatal_error "Matching.make_lazy_matching"
1400
| (arg,mut) :: argl ->
1403
(inline_lazy_force arg Location.none, Strict) :: argl;
1404
default = make_default matcher_lazy def }
1406
let divide_lazy p ctx pm =
1290
1413
(* Matching against a tuple pattern *)