aboutsummaryrefslogtreecommitdiff
path: root/kernel/cbytegen.ml
diff options
context:
space:
mode:
authorGaëtan Gilbert2020-08-18 13:07:54 +0200
committerGaëtan Gilbert2020-08-18 13:07:54 +0200
commit4ee0cedff7726a56ebd53125995a7ae131660b4a (patch)
treef5049f849a27b518f5c27298058df620a0ca38b3 /kernel/cbytegen.ml
parentaa926429727f1f6b5ef07c8912f2618d53f6d155 (diff)
Rename VM-related kernel/cfoo files to kernel/vmfoo
Diffstat (limited to 'kernel/cbytegen.ml')
-rw-r--r--kernel/cbytegen.ml934
1 files changed, 0 insertions, 934 deletions
diff --git a/kernel/cbytegen.ml b/kernel/cbytegen.ml
deleted file mode 100644
index bacc308e1f..0000000000
--- a/kernel/cbytegen.ml
+++ /dev/null
@@ -1,934 +0,0 @@
-(************************************************************************)
-(* * The Coq Proof Assistant / The Coq Development Team *)
-(* v * Copyright INRIA, CNRS and contributors *)
-(* <O___,, * (see version control and CREDITS file for authors & dates) *)
-(* \VV/ **************************************************************)
-(* // * This file is distributed under the terms of the *)
-(* * GNU Lesser General Public License Version 2.1 *)
-(* * (see LICENSE file for the text of the license) *)
-(************************************************************************)
-
-(* Author: Benjamin Grégoire as part of the bytecode-based virtual reduction
- machine, Oct 2004 *)
-(* Extension: Arnaud Spiwack (support for native arithmetic), May 2005 *)
-
-open Util
-open Names
-open Vmvalues
-open Cbytecodes
-open Cemitcodes
-open Clambda
-open Constr
-open Declarations
-open Environ
-
-
-(* Compilation of variables + computing free variables *)
-
-(* The virtual machine doesn't distinguish closures and their environment *)
-
-(* Representation of function environments : *)
-(* [clos_t | code | fv1 | fv2 | ... | fvn ] *)
-(* ^ *)
-(* The offset for accessing free variables is 1 (we must skip the code *)
-(* pointer). *)
-(* While compiling, free variables are stored in [in_env] in order *)
-(* opposite to machine representation, so we can add new free variables *)
-(* easily (i.e. without changing the position of previous variables) *)
-(* Function arguments are on the stack in the same order as the *)
-(* application : f arg1 ... argn *)
-(* - the stack is then : *)
-(* arg1 : ... argn : extra args : return addr : ... *)
-(* In the function body [arg1] is represented by de Bruijn [n], and *)
-(* [argn] by de Bruijn [1] *)
-
-(* Representation of environments of mutual fixpoints : *)
-(* [t1|C1| ... |tc|Cc| ... |t(nbr)|C(nbr)| fv1 | fv2 | .... | fvn | type] *)
-(* ^<----------offset---------> *)
-(* type = [Ct1 | .... | Ctn] *)
-(* Ci is the code pointer of the i-th body *)
-(* At runtime, a fixpoint environment (which is the same as the fixpoint *)
-(* itself) is a pointer to the field holding its code pointer. *)
-(* In each fixpoint body, de Bruijn [nbr] represents the first fixpoint *)
-(* and de Bruijn [1] the last one. *)
-(* Access to these variables is performed by the [Koffsetclosure n] *)
-(* instruction that shifts the environment pointer of [n] fields. *)
-
-(* This allows representing mutual fixpoints in just one block. *)
-(* [Ct1 | ... | Ctn] is an array holding code pointers of the fixpoint *)
-(* types. They are used in conversion tests (which requires that *)
-(* fixpoint types must be convertible). Their environment is the one of *)
-(* the last fixpoint : *)
-(* [t1|C1| ... |tc|Cc| ... |t(nbr)|C(nbr)| fv1 | fv2 | .... | fvn | type] *)
-(* ^ *)
-
-(* Representation of mutual cofix : *)
-(* a1 = [A_t | accumulate | [Cfx_t | fcofix1 ] ] *)
-(* ... *)
-(* anbr = [A_t | accumulate | [Cfx_t | fcofixnbr ] ] *)
-(* *)
-(* fcofix1 = [clos_t | code1 | a1 |...| anbr | fv1 |...| fvn | type] *)
-(* ^ *)
-(* ... *)
-(* fcofixnbr = [clos_t | codenbr | a1 |...| anbr | fv1 |...| fvn | type] *)
-(* ^ *)
-(* The [ai] blocks are functions that accumulate their arguments: *)
-(* ai arg1 argp ---> *)
-(* ai' = [A_t | accumulate | [Cfx_t | fcofixi] | arg1 | ... | argp ] *)
-(* If such a block is matched against, we have to force evaluation, *)
-(* function [fcofixi] is then applied to [ai'] [arg1] ... [argp] *)
-(* (note that [ai'] is a pointer to the closure, passed as argument) *)
-(* Once evaluation is completed [ai'] is updated with the result: *)
-(* ai' <-- *)
-(* [A_t | accumulate | [Cfxe_t |fcofixi|result] | arg1 | ... | argp ] *)
-(* This representation is nice because the application of the cofix is *)
-(* evaluated only once (it simulates a lazy evaluation) *)
-(* Moreover, when cofix don't have arguments, it is possible to create *)
-(* a cycle, e.g.: *)
-(* cofix one := cons 1 one *)
-(* a1 = [A_t | accumulate | [Cfx_t|fcofix1] ] *)
-(* fcofix1 = [clos_t | code | a1] *)
-(* The result of evaluating [a1] is [cons_t | 1 | a1]. *)
-(* When [a1] is updated : *)
-(* a1 = [A_t | accumulate | [Cfxe_t | fcofix1 | [cons_t | 1 | a1]] ] *)
-(* The cycle is created ... *)
-(* *)
-(* In Cfxe_t accumulators, we need to store [fcofixi] for testing *)
-(* conversion of cofixpoints (which is intentional). *)
-
-module Fv_elem =
-struct
-type t = fv_elem
-
-let compare e1 e2 = match e1, e2 with
-| FVnamed id1, FVnamed id2 -> Id.compare id1 id2
-| FVnamed _, (FVrel _ | FVuniv_var _ | FVevar _) -> -1
-| FVrel _, FVnamed _ -> 1
-| FVrel r1, FVrel r2 -> Int.compare r1 r2
-| FVrel _, (FVuniv_var _ | FVevar _) -> -1
-| FVuniv_var i1, FVuniv_var i2 -> Int.compare i1 i2
-| FVuniv_var _, (FVnamed _ | FVrel _) -> 1
-| FVuniv_var _, FVevar _ -> -1
-| FVevar _, (FVnamed _ | FVrel _ | FVuniv_var _) -> 1
-| FVevar e1, FVevar e2 -> Evar.compare e1 e2
-
-end
-
-module FvMap = Map.Make(Fv_elem)
-
-(*spiwack: both type have been moved from Cbytegen because I needed then
- for the retroknowledge *)
-type vm_env = {
- size : int; (* longueur de la liste [n] *)
- fv_rev : fv_elem list; (* [fvn; ... ;fv1] *)
- fv_fwd : int FvMap.t; (* reverse mapping *)
- }
-
-
-type comp_env = {
- arity : int; (* arity of the current function, 0 if none *)
- nb_uni_stack : int ; (* number of universes on the stack, *)
- (* universes are always at the bottom. *)
- nb_stack : int; (* number of variables on the stack *)
- in_stack : int Range.t; (* position in the stack *)
- nb_rec : int; (* number of mutually recursive functions *)
- pos_rec : instruction list; (* instruction d'acces pour les variables *)
- (* de point fix ou de cofix *)
- offset : int;
- in_env : vm_env ref (* The free variables of the expression *)
- }
-
-module Config = struct
- let stack_threshold = 256 (* see byterun/coq_memory.h *)
- let stack_safety_margin = 15
-end
-
-type argument = ArgLambda of lambda | ArgUniv of Univ.Level.t
-
-let empty_fv = { size= 0; fv_rev = []; fv_fwd = FvMap.empty }
-let push_fv d e = {
- size = e.size + 1;
- fv_rev = d :: e.fv_rev;
- fv_fwd = FvMap.add d e.size e.fv_fwd;
-}
-
-let fv r = !(r.in_env)
-
-let empty_comp_env ()=
- { arity = 0;
- nb_uni_stack = 0;
- nb_stack = 0;
- in_stack = Range.empty;
- nb_rec = 0;
- pos_rec = [];
- offset = 0;
- in_env = ref empty_fv
- }
-
-(* Maximal stack size reached during the current function body. Used to
- reallocate the stack if we lack space. *)
-let max_stack_size = ref 0
-
-let set_max_stack_size stack_size =
- if stack_size > !max_stack_size then
- max_stack_size := stack_size
-
-let ensure_stack_capacity f x =
- let old = !max_stack_size in
- max_stack_size := 0;
- let code = f x in
- let used_safe =
- !max_stack_size + Config.stack_safety_margin
- in
- max_stack_size := old;
- if used_safe > Config.stack_threshold then
- Kensurestackcapacity used_safe :: code
- else code
-
-(*i Creation functions for comp_env *)
-
-let rec add_param n sz l =
- if Int.equal n 0 then l else add_param (n - 1) sz (Range.cons (n+sz) l)
-
-let comp_env_fun ?(univs=0) arity =
- { arity;
- nb_uni_stack = univs ;
- nb_stack = arity;
- in_stack = add_param arity 0 Range.empty;
- nb_rec = 0;
- pos_rec = [];
- offset = 1;
- in_env = ref empty_fv
- }
-
-
-let comp_env_fix_type rfv =
- { arity = 0;
- nb_uni_stack = 0;
- nb_stack = 0;
- in_stack = Range.empty;
- nb_rec = 0;
- pos_rec = [];
- offset = 1;
- in_env = rfv
- }
-
-let comp_env_fix ndef curr_pos arity rfv =
- let prec = ref [] in
- for i = ndef downto 1 do
- prec := Koffsetclosure (2 * (ndef - curr_pos - i)) :: !prec
- done;
- { arity;
- nb_uni_stack = 0;
- nb_stack = arity;
- in_stack = add_param arity 0 Range.empty;
- nb_rec = ndef;
- pos_rec = !prec;
- offset = 2 * (ndef - curr_pos - 1)+1;
- in_env = rfv
- }
-
-let comp_env_cofix_type ndef rfv =
- { arity = 0;
- nb_uni_stack = 0;
- nb_stack = 0;
- in_stack = Range.empty;
- nb_rec = 0;
- pos_rec = [];
- offset = 1+ndef;
- in_env = rfv
- }
-
-let comp_env_cofix ndef arity rfv =
- let prec = ref [] in
- for i = 1 to ndef do
- prec := Kenvacc i :: !prec
- done;
- { arity;
- nb_uni_stack = 0;
- nb_stack = arity;
- in_stack = add_param arity 0 Range.empty;
- nb_rec = ndef;
- pos_rec = !prec;
- offset = ndef+1;
- in_env = rfv
- }
-
-(* [push_param ] add function parameters on the stack *)
-let push_param n sz r =
- { r with
- nb_stack = r.nb_stack + n;
- in_stack = add_param n sz r.in_stack }
-
-(* [push_local sz r] add a new variable on the stack at position [sz] *)
-let push_local sz r =
- { r with
- nb_stack = r.nb_stack + 1;
- in_stack = Range.cons (sz + 1) r.in_stack }
-
-(*i Compilation of variables *)
-let find_at fv env = FvMap.find fv env.fv_fwd
-
-let pos_named id r =
- let env = !(r.in_env) in
- let cid = FVnamed id in
- try Kenvacc(r.offset + find_at cid env)
- with Not_found ->
- let pos = env.size in
- r.in_env := push_fv cid env;
- Kenvacc (r.offset + pos)
-
-let pos_rel i r sz =
- if i <= r.nb_stack then
- Kacc(sz - (Range.get r.in_stack (i-1)))
- else
- let i = i - r.nb_stack in
- if i <= r.nb_rec then
- try List.nth r.pos_rec (i-1)
- with (Failure _|Invalid_argument _) -> assert false
- else
- let i = i - r.nb_rec in
- let db = FVrel(i) in
- let env = !(r.in_env) in
- try Kenvacc(r.offset + find_at db env)
- with Not_found ->
- let pos = env.size in
- r.in_env := push_fv db env;
- Kenvacc(r.offset + pos)
-
-let pos_universe_var i r sz =
- (* Compilation of a universe variable can happen either at toplevel (the
- current closure correspond to a constant and has local universes) or in a
- local closure (which has no local universes). *)
- if r.nb_uni_stack != 0 then
- (* Universe variables are represented by De Bruijn levels (not indices),
- starting at 0. The shape of the stack will be [v1|..|vn|u1..up|arg1..argq]
- with size = n + p + q, and q = r.arity. So Kacc (sz - r.arity - 1) will access
- the last universe. *)
- Kacc (sz - r.arity - (r.nb_uni_stack - i))
- else
- let env = !(r.in_env) in
- let db = FVuniv_var i in
- try Kenvacc (r.offset + find_at db env)
- with Not_found ->
- let pos = env.size in
- r.in_env := push_fv db env;
- Kenvacc(r.offset + pos)
-
-let pos_evar evk r =
- let env = !(r.in_env) in
- let cid = FVevar evk in
- try Kenvacc(r.offset + find_at cid env)
- with Not_found ->
- let pos = env.size in
- r.in_env := push_fv cid env;
- Kenvacc (r.offset + pos)
-
-(*i Examination of the continuation *)
-
-(* Discard all instructions up to the next label. *)
-(* This function is to be applied to the continuation before adding a *)
-(* non-terminating instruction (branch, raise, return, appterm) *)
-(* in front of it. *)
-
-let discard_dead_code cont = cont
-(*function
- [] -> []
- | (Klabel _ | Krestart ) :: _ as cont -> cont
- | _ :: cont -> discard_dead_code cont
-*)
-
-(* Return a label to the beginning of the given continuation. *)
-(* If the sequence starts with a branch, use the target of that branch *)
-(* as the label, thus avoiding a jump to a jump. *)
-
-let label_code = function
- | Klabel lbl :: _ as cont -> (lbl, cont)
- | Kbranch lbl :: _ as cont -> (lbl, cont)
- | cont -> let lbl = Label.create() in (lbl, Klabel lbl :: cont)
-
-(* Return a branch to the continuation. That is, an instruction that,
- when executed, branches to the continuation or performs what the
- continuation performs. We avoid generating branches to returns. *)
-(* spiwack: make_branch was only used once. Changed it back to the ZAM
- one to match the appropriate semantics (old one avoided the
- introduction of an unconditional branch operation, which seemed
- appropriate for the 31-bit integers' code). As a memory, I leave
- the former version in this comment.
-let make_branch cont =
- match cont with
- | (Kreturn _ as return) :: cont' -> return, cont'
- | Klabel lbl as b :: _ -> b, cont
- | _ -> let b = Klabel(Label.create()) in b,b::cont
-*)
-
-let rec make_branch_2 lbl n cont =
- function
- Kreturn m :: _ -> (Kreturn (n + m), cont)
- | Klabel _ :: c -> make_branch_2 lbl n cont c
- | Kpop m :: c -> make_branch_2 lbl (n + m) cont c
- | _ ->
- match lbl with
- Some lbl -> (Kbranch lbl, cont)
- | None -> let lbl = Label.create() in (Kbranch lbl, Klabel lbl :: cont)
-
-let make_branch cont =
- match cont with
- (Kbranch _ as branch) :: _ -> (branch, cont)
- | (Kreturn _ as return) :: _ -> (return, cont)
- | Klabel lbl :: _ -> make_branch_2 (Some lbl) 0 cont cont
- | _ -> make_branch_2 (None) 0 cont cont
-
-(* Check if we're in tailcall position *)
-
-let rec is_tailcall = function
- | Kreturn k :: _ -> Some k
- | Klabel _ :: c -> is_tailcall c
- | _ -> None
-
-(* Extension of the continuation *)
-
-(* Add a Kpop n instruction in front of a continuation *)
-let rec add_pop n = function
- | Kpop m :: cont -> add_pop (n+m) cont
- | Kreturn m:: cont -> Kreturn (n+m) ::cont
- | cont -> if Int.equal n 0 then cont else Kpop n :: cont
-
-let add_grab arity lbl cont =
- if Int.equal arity 1 then Klabel lbl :: cont
- else Krestart :: Klabel lbl :: Kgrab (arity - 1) :: cont
-
-let add_grabrec rec_arg arity lbl cont =
- if Int.equal arity 1 && rec_arg < arity then
- Klabel lbl :: Kgrabrec 0 :: Krestart :: cont
- else
- Krestart :: Klabel lbl :: Kgrabrec rec_arg ::
- Krestart :: Kgrab (arity - 1) :: cont
-
-(* continuation of a cofix *)
-
-let cont_cofix arity =
- (* accu = res *)
- (* stk = ai::args::ra::... *)
- (* ai = [At|accumulate|[Cfx_t|fcofix]|args] *)
- [ Kpush;
- Kpush; (* stk = res::res::ai::args::ra::... *)
- Kacc 2;
- Kfield 1;
- Kfield 0;
- Kmakeblock(2, cofix_evaluated_tag);
- Kpush; (* stk = [Cfxe_t|fcofix|res]::res::ai::args::ra::...*)
- Kacc 2;
- Ksetfield 1; (* ai = [At|accumulate|[Cfxe_t|fcofix|res]|args] *)
- (* stk = res::ai::args::ra::... *)
- Kacc 0; (* accu = res *)
- Kreturn (arity+2) ]
-
-
-(* Code of closures *)
-let fun_code = ref []
-
-let init_fun_code () = fun_code := []
-
-(* Compilation of constructors and inductive types *)
-
-
-(*
-If [tag] hits the OCaml limitation for non constant constructors, we switch to
-another representation for the remaining constructors:
-[last_variant_tag|tag - Obj.last_non_constant_constructor_tag|args]
-
-We subtract Obj.last_non_constant_constructor_tag for efficiency of match interpretation.
- *)
-
-let nest_block tag arity cont =
- Kconst (Const_b0 (tag - Obj.last_non_constant_constructor_tag)) ::
- Kmakeblock(arity+1, Obj.last_non_constant_constructor_tag) :: cont
-
-let code_makeblock ~stack_size ~arity ~tag cont =
- if tag < Obj.last_non_constant_constructor_tag then
- Kmakeblock(arity, tag) :: cont
- else begin
- set_max_stack_size (stack_size + 1);
- Kpush :: nest_block tag arity cont
- end
-
-let compile_structured_constant _cenv sc sz cont =
- set_max_stack_size sz;
- Kconst sc :: cont
-
-(* compiling application *)
-let comp_args comp_expr cenv args sz cont =
- let nargs_m_1 = Array.length args - 1 in
- let c = ref (comp_expr cenv args.(0) (sz + nargs_m_1) cont) in
- for i = 1 to nargs_m_1 do
- c := comp_expr cenv args.(i) (sz + nargs_m_1 - i) (Kpush :: !c)
- done;
- !c
-
-let comp_app comp_fun comp_arg cenv f args sz cont =
- let nargs = Array.length args in
- if Int.equal nargs 0 then comp_fun cenv f sz cont
- else
- match is_tailcall cont with
- | Some k ->
- comp_args comp_arg cenv args sz
- (Kpush ::
- comp_fun cenv f (sz + nargs)
- (Kappterm(nargs, k + nargs) :: (discard_dead_code cont)))
- | None ->
- if nargs <= 4 then
- comp_args comp_arg cenv args sz
- (Kpush :: (comp_fun cenv f (sz+nargs) (Kapply nargs :: cont)))
- else
- let lbl,cont1 = label_code cont in
- Kpush_retaddr lbl ::
- (comp_args comp_arg cenv args (sz + 3)
- (Kpush :: (comp_fun cenv f (sz+3+nargs) (Kapply nargs :: cont1))))
-
-(* Compiling free variables *)
-
-let compile_fv_elem cenv fv sz cont =
- match fv with
- | FVrel i -> pos_rel i cenv sz :: cont
- | FVnamed id -> pos_named id cenv :: cont
- | FVuniv_var i -> pos_universe_var i cenv sz :: cont
- | FVevar evk -> pos_evar evk cenv :: cont
-
-let rec compile_fv cenv l sz cont =
- match l with
- | [] -> cont
- | [fvn] -> set_max_stack_size (sz + 1); compile_fv_elem cenv fvn sz cont
- | fvn :: tl ->
- compile_fv_elem cenv fvn sz
- (Kpush :: compile_fv cenv tl (sz + 1) cont)
-
-
-(* Compiling constants *)
-
-let rec get_alias env kn =
- let cb = lookup_constant kn env in
- let tps = cb.const_body_code in
- match tps with
- | None -> kn
- | Some tps ->
- (match Cemitcodes.force tps with
- | BCalias kn' -> get_alias env kn'
- | _ -> kn)
-
-(* Some primitives are not implemented natively by the VM, but calling OCaml
- code instead *)
-let is_caml_prim = let open CPrimitives in function
- | Arraymake
- | Arrayget
- | Arraydefault
- | Arrayset
- | Arraycopy
- | Arrayreroot
- | Arraylength -> true
- | _ -> false
-
-(* sz is the size of the local stack *)
-let rec compile_lam env cenv lam sz cont =
- set_max_stack_size sz;
- match lam with
- | Lrel(_, i) -> pos_rel i cenv sz :: cont
-
- | Lint i -> compile_structured_constant cenv (Const_b0 i) sz cont
-
- | Lval v -> compile_structured_constant cenv (Const_val v) sz cont
-
- | Luint i -> compile_structured_constant cenv (Const_uint i) sz cont
-
- | Lfloat f -> compile_structured_constant cenv (Const_float f) sz cont
-
- | Lproj (p,arg) ->
- compile_lam env cenv arg sz (Kproj p :: cont)
-
- | Lvar id -> pos_named id cenv :: cont
-
- | Levar (evk, args) ->
- if Array.is_empty args then
- compile_fv_elem cenv (FVevar evk) sz cont
- else
- (** Arguments are reversed in evar instances *)
- let args = Array.copy args in
- let () = Array.rev args in
- comp_app compile_fv_elem (compile_lam env) cenv (FVevar evk) args sz cont
-
- | Lconst (kn,u) -> compile_constant env cenv kn u [||] sz cont
-
- | Lind (ind,u) ->
- if Univ.Instance.is_empty u then
- compile_structured_constant cenv (Const_ind ind) sz cont
- else comp_app compile_structured_constant compile_universe cenv
- (Const_ind ind) (Univ.Instance.to_array u) sz cont
-
- | Lsort (Sorts.SProp | Sorts.Prop | Sorts.Set as s) ->
- compile_structured_constant cenv (Const_sort s) sz cont
- | Lsort (Sorts.Type u) ->
- (* We represent universes as a global constant with local universes
- "compacted", i.e. as [u arg0 ... argn] where we will substitute (after
- evaluation) [Var 0,...,Var n] with values of [arg0,...,argn] *)
- let u,s = Univ.compact_univ u in
- let compile_get_univ cenv idx sz cont =
- set_max_stack_size sz;
- compile_fv_elem cenv (FVuniv_var idx) sz cont
- in
- if List.is_empty s then
- compile_structured_constant cenv (Const_sort (Sorts.sort_of_univ u)) sz cont
- else
- comp_app compile_structured_constant compile_get_univ cenv
- (Const_sort (Sorts.sort_of_univ u)) (Array.of_list s) sz cont
-
- | Llet (_id,def,body) ->
- compile_lam env cenv def sz
- (Kpush ::
- compile_lam env (push_local sz cenv) body (sz+1) (add_pop 1 cont))
-
- | Lprod (dom,codom) ->
- let cont1 =
- Kpush :: compile_lam env cenv dom (sz+1) (Kmakeprod :: cont) in
- compile_lam env cenv codom sz cont1
-
- | Llam (ids,body) ->
- let arity = Array.length ids in
- let r_fun = comp_env_fun arity in
- let lbl_fun = Label.create() in
- let cont_fun =
- ensure_stack_capacity (compile_lam env r_fun body arity) [Kreturn arity]
- in
- fun_code := [Ksequence(add_grab arity lbl_fun cont_fun,!fun_code)];
- let fv = fv r_fun in
- compile_fv cenv fv.fv_rev sz (Kclosure(lbl_fun,fv.size) :: cont)
-
- | Lapp (f, args) ->
- begin match f with
- | Lconst (kn,u) -> compile_constant env cenv kn u args sz cont
- | _ -> comp_app (compile_lam env) (compile_lam env) cenv f args sz cont
- end
-
- | Lfix ((rec_args, init), (_decl, types, bodies)) ->
- let ndef = Array.length types in
- let rfv = ref empty_fv in
- let lbl_types = Array.make ndef Label.no in
- let lbl_bodies = Array.make ndef Label.no in
- (* Compiling types *)
- let env_type = comp_env_fix_type rfv in
- for i = 0 to ndef - 1 do
- let fcode =
- ensure_stack_capacity (compile_lam env env_type types.(i) 0) [Kstop]
- in
- let lbl,fcode = label_code fcode in
- lbl_types.(i) <- lbl;
- fun_code := [Ksequence(fcode,!fun_code)]
- done;
- (* Compiling bodies *)
- for i = 0 to ndef - 1 do
- let params,body = decompose_Llam bodies.(i) in
- let arity = Array.length params in
- let env_body = comp_env_fix ndef i arity rfv in
- let cont1 =
- ensure_stack_capacity (compile_lam env env_body body arity) [Kreturn arity]
- in
- let lbl = Label.create () in
- lbl_bodies.(i) <- lbl;
- let fcode = add_grabrec rec_args.(i) arity lbl cont1 in
- fun_code := [Ksequence(fcode,!fun_code)]
- done;
- let fv = !rfv in
- compile_fv cenv fv.fv_rev sz
- (Kclosurerec(fv.size,init,lbl_types,lbl_bodies) :: cont)
-
-
- | Lcofix(init, (_decl,types,bodies)) ->
- let ndef = Array.length types in
- let lbl_types = Array.make ndef Label.no in
- let lbl_bodies = Array.make ndef Label.no in
- (* Compiling types *)
- let rfv = ref empty_fv in
- let env_type = comp_env_cofix_type ndef rfv in
- for i = 0 to ndef - 1 do
- let fcode =
- ensure_stack_capacity (compile_lam env env_type types.(i) 0) [Kstop]
- in
- let lbl,fcode = label_code fcode in
- lbl_types.(i) <- lbl;
- fun_code := [Ksequence(fcode,!fun_code)]
- done;
- (* Compiling bodies *)
- for i = 0 to ndef - 1 do
- let params,body = decompose_Llam bodies.(i) in
- let arity = Array.length params in
- let env_body = comp_env_cofix ndef arity rfv in
- let lbl = Label.create () in
- let comp arity =
- (* 4 stack slots are needed to update the cofix when forced *)
- set_max_stack_size (arity + 4);
- compile_lam env env_body body (arity+1) (cont_cofix arity)
- in
- let cont = ensure_stack_capacity comp arity in
- lbl_bodies.(i) <- lbl;
- fun_code := [Ksequence(add_grab (arity+1) lbl cont,!fun_code)];
- done;
- let fv = !rfv in
- set_max_stack_size (sz + fv.size + ndef + 2);
- compile_fv cenv fv.fv_rev sz
- (Kclosurecofix(fv.size, init, lbl_types, lbl_bodies) :: cont)
-
- | Lif(t, bt, bf) ->
- let branch, cont = make_branch cont in
- let lbl_true = Label.create() in
- let lbl_false = Label.create() in
- compile_lam env cenv t sz
- (Kswitch([|lbl_true;lbl_false|],[||]) ::
- Klabel lbl_false ::
- compile_lam env cenv bf sz
- (branch ::
- Klabel lbl_true ::
- compile_lam env cenv bt sz cont))
-
- | Lcase(ci,rtbl,t,a,branches) ->
- let ind = ci.ci_ind in
- let mib = lookup_mind (fst ind) env in
- let oib = mib.mind_packets.(snd ind) in
- let lbl_consts = Array.make oib.mind_nb_constant Label.no in
- let nallblock = oib.mind_nb_args + 1 in (* +1 : accumulate *)
- let nconst = Array.length branches.constant_branches in
- let nblock = min nallblock (Obj.last_non_constant_constructor_tag + 1) in
- let lbl_blocks = Array.make nblock Label.no in
- let neblock = max 0 (nallblock - Obj.last_non_constant_constructor_tag) in
- let lbl_eblocks = Array.make neblock Label.no in
- let branch1, cont = make_branch cont in
- (* Compilation of the return type *)
- let fcode =
- ensure_stack_capacity (compile_lam env cenv t sz) [Kpop sz; Kstop]
- in
- let lbl_typ,fcode = label_code fcode in
- fun_code := [Ksequence(fcode,!fun_code)];
- (* Compilation of the branches *)
- let lbl_sw = Label.create () in
- let sz_b,branch,is_tailcall =
- match branch1 with
- | Kreturn k ->
- assert (Int.equal k sz) ;
- sz, branch1, true
- | Kbranch _ -> sz+3, Kjump, false
- | _ -> assert false
- in
-
- let c = ref cont in
- (* Perform the extra match if needed (too many block constructors) *)
- if neblock <> 0 then begin
- let lbl_b, code_b =
- label_code (
- Kpush :: Kfield 0 :: Kswitch(lbl_eblocks, [||]) :: !c) in
- lbl_blocks.(Obj.last_non_constant_constructor_tag) <- lbl_b;
- c := code_b
- end;
-
- (* Compilation of constant branches *)
- for i = nconst - 1 downto 0 do
- let aux =
- compile_lam env cenv branches.constant_branches.(i) sz_b (branch::!c)
- in
- let lbl_b,code_b = label_code aux in
- lbl_consts.(i) <- lbl_b;
- c := code_b
- done;
- (* -1 for accu branch *)
- for i = nallblock - 2 downto 0 do
- let tag = i + 1 in
- let (ids, body) = branches.nonconstant_branches.(i) in
- let arity = Array.length ids in
- let code_b =
- compile_lam env (push_param arity sz_b cenv)
- body (sz_b+arity) (add_pop arity (branch::!c)) in
- let code_b =
- if tag < Obj.last_non_constant_constructor_tag then begin
- set_max_stack_size (sz_b + arity);
- Kpushfields arity :: code_b
- end
- else begin
- set_max_stack_size (sz_b + arity + 1);
- Kacc 0::Kpop 1::Kpushfields(arity+1)::Kpop 1::code_b
- end
- in
- let lbl_b, code_b = label_code code_b in
- if tag < Obj.last_non_constant_constructor_tag then lbl_blocks.(tag) <- lbl_b
- else lbl_eblocks.(tag - Obj.last_non_constant_constructor_tag) <- lbl_b;
- c := code_b
- done;
-
- let annot =
- {rtbl = rtbl; tailcall = is_tailcall;
- max_stack_size = !max_stack_size - sz}
- in
-
- (* Compiling branch for accumulators *)
- let lbl_accu, code_accu =
- set_max_stack_size (sz+3);
- label_code(Kmakeswitchblock(lbl_typ,lbl_sw,annot,sz) :: branch :: !c)
- in
- lbl_blocks.(0) <- lbl_accu;
-
- c := Klabel lbl_sw :: Kswitch(lbl_consts,lbl_blocks) :: code_accu;
- let code_sw =
- match branch1 with
- (* spiwack : branch1 can't be a lbl anymore it's a Branch instead
- | Klabel lbl -> Kpush_retaddr lbl :: !c *)
- | Kbranch lbl -> Kpush_retaddr lbl :: !c
- | _ -> !c
- in
- compile_lam env cenv a sz code_sw
-
- | Lmakeblock (tag,args) ->
- let arity = Array.length args in
- let cont = code_makeblock ~stack_size:(sz+arity-1) ~arity ~tag cont in
- comp_args (compile_lam env) cenv args sz cont
-
- | Lprim (Some (kn,u), op, args) when is_caml_prim op ->
- let arity = CPrimitives.arity op in
- let nparams = CPrimitives.nparams op in
- let nargs = arity - nparams in
- assert (arity = Array.length args && arity <= 4);
- let (jump, cont) = make_branch cont in
- let lbl_default = Label.create () in
- let default =
- let cont = [Kgetglobal kn; Kapply (arity + Univ.Instance.length u); jump] in
- let cont =
- if Univ.Instance.is_empty u then cont
- else comp_args compile_universe cenv (Univ.Instance.to_array u) (sz + arity) (Kpush::cont)
- in
- Klabel lbl_default ::
- Kpush ::
- if Int.equal nparams 0 then cont
- else comp_args (compile_lam env) cenv (Array.sub args 0 nparams) (sz + nargs) (Kpush::cont)
- in
- fun_code := [Ksequence(default, !fun_code)];
- comp_args (compile_lam env) cenv (Array.sub args nparams nargs) sz (Kcamlprim (op, lbl_default) :: cont)
-
- | Lprim (kn, op, args) ->
- comp_args (compile_lam env) cenv args sz (Kprim(op, kn)::cont)
-
-and compile_get_global cenv (kn,u) sz cont =
- set_max_stack_size sz;
- if Univ.Instance.is_empty u then
- Kgetglobal kn :: cont
- else
- comp_app (fun _ _ _ cont -> Kgetglobal kn :: cont)
- compile_universe cenv () (Univ.Instance.to_array u) sz cont
-
-and compile_universe cenv uni sz cont =
- set_max_stack_size sz;
- match Univ.Level.var_index uni with
- | None -> compile_structured_constant cenv (Const_univ_level uni) sz cont
- | Some idx -> pos_universe_var idx cenv sz :: cont
-
-and compile_constant env cenv kn u args sz cont =
- set_max_stack_size sz;
- if Univ.Instance.is_empty u then
- (* normal compilation *)
- comp_app (fun _ _ sz cont ->
- compile_get_global cenv (kn,u) sz cont)
- (compile_lam env) cenv () args sz cont
- else
- let compile_arg cenv constr_or_uni sz cont =
- match constr_or_uni with
- | ArgLambda t -> compile_lam env cenv t sz cont
- | ArgUniv uni -> compile_universe cenv uni sz cont
- in
- let u = Univ.Instance.to_array u in
- let lu = Array.length u in
- let all =
- Array.init (lu + Array.length args)
- (fun i -> if i < lu then ArgUniv u.(i) else ArgLambda args.(i-lu))
- in
- comp_app (fun _ _ _ cont -> Kgetglobal kn :: cont)
- compile_arg cenv () all sz cont
-
-let is_univ_copy max u =
- let u = Univ.Instance.to_array u in
- if Array.length u = max then
- Array.fold_left_i (fun i acc u ->
- if acc then
- match Univ.Level.var_index u with
- | None -> false
- | Some l -> l = i
- else false) true u
- else
- false
-
-let dump_bytecode = ref false
-
-let dump_bytecodes init code fvs =
- let open Pp in
- (str "code =" ++ fnl () ++
- pp_bytecodes init ++ fnl () ++
- pp_bytecodes code ++ fnl () ++
- str "fv = " ++
- prlist_with_sep (fun () -> str "; ") pp_fv_elem fvs ++
- fnl ())
-
-let compile ~fail_on_error ?universes:(universes=0) env c =
- init_fun_code ();
- Label.reset_label_counter ();
- let cont = [Kstop] in
- try
- let cenv, init_code =
- if Int.equal universes 0 then
- let lam = lambda_of_constr ~optimize:true env c in
- let cenv = empty_comp_env () in
- cenv, ensure_stack_capacity (compile_lam env cenv lam 0) cont
- else
- (* We are going to generate a lambda, but merge the universe closure
- * with the function closure if it exists.
- *)
- let lam = lambda_of_constr ~optimize:true env c in
- let params, body = decompose_Llam lam in
- let arity = Array.length params in
- let cenv = empty_comp_env () in
- let full_arity = arity + universes in
- let r_fun = comp_env_fun ~univs:universes arity in
- let lbl_fun = Label.create () in
- let cont_fun =
- ensure_stack_capacity (compile_lam env r_fun body full_arity)
- [Kreturn full_arity]
- in
- fun_code := [Ksequence(add_grab full_arity lbl_fun cont_fun,!fun_code)];
- let fv = fv r_fun in
- let init_code =
- ensure_stack_capacity (compile_fv cenv fv.fv_rev 0)
- (Kclosure(lbl_fun,fv.size) :: cont)
- in
- cenv, init_code
- in
- let fv = List.rev (!(cenv.in_env).fv_rev) in
- (if !dump_bytecode then
- Feedback.msg_debug (dump_bytecodes init_code !fun_code fv)) ;
- Some (init_code,!fun_code, Array.of_list fv)
- with TooLargeInductive msg as exn ->
- let _, info = Exninfo.capture exn in
- let fn = if fail_on_error then
- CErrors.user_err ?loc:None ~info ~hdr:"compile"
- else
- (fun x -> Feedback.msg_warning x) in
- fn msg; None
-
-let compile_constant_body ~fail_on_error env univs = function
- | Undef _ | OpaqueDef _ | Primitive _ -> Some BCconstant
- | Def sb ->
- let body = Mod_subst.force_constr sb in
- let instance_size = Univ.AUContext.size (Declareops.universes_context univs) in
- match kind body with
- | Const (kn',u) when is_univ_copy instance_size u ->
- (* we use the canonical name of the constant*)
- let con= Constant.make1 (Constant.canonical kn') in
- Some (BCalias (get_alias env con))
- | _ ->
- let res = compile ~fail_on_error ~universes:instance_size env body in
- Option.map (fun x -> BCdefined (to_memory x)) res
-
-(* Shortcut of the previous function used during module strengthening *)
-
-let compile_alias kn = BCalias (Constant.make1 (Constant.canonical kn))