summaryrefslogtreecommitdiffstats
path: root/bytecomp/translclass.ml
diff options
context:
space:
mode:
Diffstat (limited to 'bytecomp/translclass.ml')
-rw-r--r--bytecomp/translclass.ml610
1 files changed, 499 insertions, 111 deletions
diff --git a/bytecomp/translclass.ml b/bytecomp/translclass.ml
index e379a87af..dd1f57256 100644
--- a/bytecomp/translclass.ml
+++ b/bytecomp/translclass.ml
@@ -27,6 +27,7 @@ type error = Illegal_class_expr
exception Error of Location.t * error
let lfunction params body =
+ if params = [] then body else
match body with
Lfunction (Curried, params', body') ->
Lfunction (Curried, params @ params', body')
@@ -43,13 +44,14 @@ let lapply func args =
let lsequence l1 l2 =
if l2 = lambda_unit then l1 else Lsequence(l1, l2)
-let transl_label l = Lconst (Const_base (Const_string l))
+let lfield v i = Lprim(Pfield i, [Lvar v])
+
+let transl_label l = share (Const_base (Const_string l))
let rec transl_meth_list lst =
- Lconst
- (List.fold_right
- (fun lab rem -> Const_block (0, [Const_base (Const_string lab); rem]))
- lst (Const_pointer 0))
+ if lst = [] then Lconst (Const_pointer 0) else
+ share (Const_block
+ (0, List.map (fun lab -> Const_base (Const_string lab)) lst))
let set_inst_var obj id expr =
let kind = if Typeopt.maybe_pointer expr then Paddrarray else Pintarray in
@@ -65,15 +67,26 @@ let copy_inst_var obj id expr templ offset =
[Lvar id';
Lvar offset])])]))
-let transl_val tbl create name id rem =
- Llet(StrictOpt, id, Lapply (oo_prim (if create then "new_variable"
- else "get_variable"),
- [Lvar tbl; transl_label name]),
- rem)
+let transl_val tbl create name =
+ Lapply (oo_prim (if create then "new_variable" else "get_variable"),
+ [Lvar tbl; transl_label name])
-let transl_vals tbl create vals rem =
+let transl_vals tbl create sure vals rem =
+ if create && sure && List.length vals > 1 then
+ let (_,id0) = List.hd vals in
+ let call =
+ Lapply(oo_prim "new_variables",
+ [Lvar tbl; transl_meth_list (List.map fst vals)]) in
+ let i = ref (List.length vals) in
+ Llet(Strict, id0, call,
+ List.fold_right
+ (fun (name,id) rem ->
+ decr i; Llet(Alias, id, Lprim(Poffsetint !i, [Lvar id0]), rem))
+ (List.tl vals) rem)
+ else
List.fold_right
- (fun (name, id) rem -> transl_val tbl create name id rem)
+ (fun (name, id) rem ->
+ Llet(StrictOpt, id, transl_val tbl create name, rem))
vals rem
let transl_super tbl meths inh_methods rem =
@@ -93,22 +106,27 @@ let create_object cl obj init =
let (inh_init, obj_init) = init obj' in
if obj_init = lambda_unit then
(inh_init,
- Lapply (oo_prim "create_object_and_run_initializers",
- [Lvar obj; Lvar cl]))
+ Lapply (oo_prim "create_object_and_run_initializers", [obj; Lvar cl]))
else begin
(inh_init,
Llet(Strict, obj',
- Lapply (oo_prim "create_object_opt", [Lvar obj; Lvar cl]),
+ Lapply (oo_prim "create_object_opt", [obj; Lvar cl]),
Lsequence(obj_init,
- Lapply (oo_prim "run_initializers_opt",
- [Lvar obj; Lvar obj'; Lvar cl]))))
+ Lapply (oo_prim "run_initializers_opt",
+ [obj; Lvar obj'; Lvar cl]))))
end
-let rec build_object_init cl_table obj params inh_init cl =
+let rec build_object_init cl_table obj params inh_init obj_init cl =
match cl.cl_desc with
Tclass_ident path ->
let obj_init = Ident.create "obj_init" in
- (obj_init::inh_init, Lapply(Lvar obj_init, [Lvar obj]))
+ let envs, inh_init = inh_init in
+ let env =
+ match envs with None -> []
+ | Some envs -> [Lprim(Pfield (List.length inh_init + 1), [Lvar envs])]
+ in
+ ((envs, (obj_init, path)::inh_init),
+ Lapply(Lvar obj_init, env @ [obj]))
| Tclass_structure str ->
create_object cl_table obj (fun obj ->
let (inh_init, obj_init) =
@@ -117,7 +135,8 @@ let rec build_object_init cl_table obj params inh_init cl =
match field with
Cf_inher (cl, _, _) ->
let (inh_init, obj_init') =
- build_object_init cl_table obj [] inh_init cl
+ build_object_init cl_table (Lvar obj) [] inh_init
+ (fun _ -> lambda_unit) cl
in
(inh_init, lsequence obj_init' obj_init)
| Cf_val (_, id, exp) ->
@@ -133,7 +152,7 @@ let rec build_object_init cl_table obj params inh_init cl =
rem)
vals obj_init)))
str.cl_field
- (inh_init, lambda_unit)
+ (inh_init, obj_init obj)
in
(inh_init,
List.fold_right
@@ -142,7 +161,7 @@ let rec build_object_init cl_table obj params inh_init cl =
params obj_init))
| Tclass_fun (pat, vals, cl, partial) ->
let (inh_init, obj_init) =
- build_object_init cl_table obj (vals @ params) inh_init cl
+ build_object_init cl_table obj (vals @ params) inh_init obj_init cl
in
(inh_init,
let build params rem =
@@ -157,29 +176,32 @@ let rec build_object_init cl_table obj params inh_init cl =
end)
| Tclass_apply (cl, oexprs) ->
let (inh_init, obj_init) =
- build_object_init cl_table obj params inh_init cl
+ build_object_init cl_table obj params inh_init obj_init cl
in
(inh_init, transl_apply obj_init oexprs)
| Tclass_let (rec_flag, defs, vals, cl) ->
let (inh_init, obj_init) =
- build_object_init cl_table obj (vals @ params) inh_init cl
+ build_object_init cl_table obj (vals @ params) inh_init obj_init cl
in
(inh_init, Translcore.transl_let rec_flag defs obj_init)
| Tclass_constraint (cl, vals, pub_meths, concr_meths) ->
- build_object_init cl_table obj params inh_init cl
+ build_object_init cl_table obj params inh_init obj_init cl
-let rec build_object_init_0 cl_table params cl =
+let rec build_object_init_0 cl_table params cl copy_env subst_env top ids =
match cl.cl_desc with
Tclass_let (rec_flag, defs, vals, cl) ->
- let (inh_init, obj_init) =
- build_object_init_0 cl_table (vals @ params) cl
- in
- (inh_init, Translcore.transl_let rec_flag defs obj_init)
+ build_object_init_0 cl_table (vals@params) cl copy_env subst_env top ids
| _ ->
- let obj = Ident.create "self" in
- let (inh_init, obj_init) = build_object_init cl_table obj params [] cl in
- let obj_init = lfunction [obj] obj_init in
- (inh_init, obj_init)
+ let self = Ident.create "self" in
+ let env = Ident.create "env" in
+ let obj = if ids = [] then lambda_unit else Lvar self in
+ let envs = if top then None else Some env in
+ let ((_,inh_init), obj_init) =
+ build_object_init cl_table obj params (envs,[]) (copy_env env) cl in
+ let obj_init =
+ if ids = [] then obj_init else lfunction [self] obj_init in
+ (inh_init, lfunction [env] (subst_env env obj_init))
+
let bind_method tbl public_methods lab id cl_init =
if List.mem lab public_methods then
@@ -192,138 +214,504 @@ let bind_method tbl public_methods lab id cl_init =
let bind_methods tbl public_methods meths cl_init =
Meths.fold (bind_method tbl public_methods) meths cl_init
-let rec build_class_init cla pub_meths cstr inh_init cl_init cl =
+let output_methods tbl vals methods lam =
+ let lam =
+ match methods with
+ [] -> lam
+ | [lab; code] ->
+ lsequence (Lapply(oo_prim "set_method", [Lvar tbl; lab; code])) lam
+ | _ ->
+ lsequence (Lapply(oo_prim "set_methods",
+ [Lvar tbl; Lprim(Pmakeblock(0,Immutable), methods)]))
+ lam
+ in
+ transl_vals tbl true true vals lam
+
+let rec ignore_cstrs cl =
+ match cl.cl_desc with
+ Tclass_constraint (cl, _, _, _) -> ignore_cstrs cl
+ | Tclass_apply (cl, _) -> ignore_cstrs cl
+ | _ -> cl
+
+let rec build_class_init cla pub_meths cstr inh_init cl_init msubst top cl =
match cl.cl_desc with
Tclass_ident path ->
begin match inh_init with
- obj_init::inh_init ->
+ (obj_init, path')::inh_init ->
+ let lpath = transl_path path in
(inh_init,
Llet (Strict, obj_init,
- Lapply(Lprim(Pfield 1, [transl_path path]), [Lvar cla]),
+ Lapply(Lprim(Pfield 1, [lpath]), Lvar cla ::
+ if top then [Lprim(Pfield 3, [lpath])] else []),
cl_init))
| _ ->
assert false
end
| Tclass_structure str ->
- let (inh_init, cl_init) =
+ let (inh_init, cl_init, methods, values) =
List.fold_right
- (fun field (inh_init, cl_init) ->
+ (fun field (inh_init, cl_init, methods, values) ->
match field with
Cf_inher (cl, vals, meths) ->
- build_class_init cla pub_meths false inh_init
- (transl_vals cla false vals
- (transl_super cla str.cl_meths meths cl_init))
- cl
+ let cl_init = output_methods cla values methods cl_init in
+ let inh_init, cl_init =
+ build_class_init cla pub_meths false inh_init
+ (transl_vals cla false false vals
+ (transl_super cla str.cl_meths meths cl_init))
+ msubst top cl in
+ (inh_init, cl_init, [], [])
| Cf_val (name, id, exp) ->
- (inh_init, transl_val cla true name id cl_init)
+ (inh_init, cl_init, methods, (name, id)::values)
| Cf_meth (name, exp) ->
+ let met_code = msubst true (transl_exp exp) in
let met_code =
- if !Clflags.native_code then begin
+ if !Clflags.native_code && List.length met_code = 1 then
(* Force correct naming of method for profiles *)
let met = Ident.create ("method_" ^ name) in
- Llet(Strict, met, transl_exp exp, Lvar met)
- end else
- transl_exp exp in
- (inh_init,
- Lsequence(Lapply (oo_prim "set_method",
- [Lvar cla;
- Lvar (Meths.find name str.cl_meths);
- met_code]),
+ [Llet(Strict, met, List.hd met_code, Lvar met)]
+ else met_code
+ in
+ (inh_init, cl_init,
+ Lvar (Meths.find name str.cl_meths) :: met_code @ methods,
+ values)
+ (*
+ Lsequence(Lapply (oo_prim ("set_method" ^ builtin),
+ Lvar cla ::
+ Lvar (Meths.find name str.cl_meths) ::
+ met_code),
cl_init))
+ *)
| Cf_let (rec_flag, defs, vals) ->
let vals =
List.map (function (id, _) -> (Ident.name id, id)) vals
in
- (inh_init, transl_vals cla true vals cl_init)
+ (inh_init, cl_init, methods, vals @ values)
| Cf_init exp ->
(inh_init,
Lsequence(Lapply (oo_prim "add_initializer",
- [Lvar cla; transl_exp exp]),
- cl_init)))
+ Lvar cla :: msubst false (transl_exp exp)),
+ cl_init),
+ methods, values))
str.cl_field
- (inh_init, cl_init)
+ (inh_init, cl_init, [], [])
in
+ let cl_init = output_methods cla values methods cl_init in
(inh_init, bind_methods cla pub_meths str.cl_meths cl_init)
| Tclass_fun (pat, vals, cl, _) ->
let (inh_init, cl_init) =
- build_class_init cla pub_meths cstr inh_init cl_init cl
+ build_class_init cla pub_meths cstr inh_init cl_init msubst top cl
in
let vals = List.map (function (id, _) -> (Ident.name id, id)) vals in
- (inh_init, transl_vals cla true vals cl_init)
+ (inh_init, transl_vals cla true false vals cl_init)
| Tclass_apply (cl, exprs) ->
- build_class_init cla pub_meths cstr inh_init cl_init cl
+ build_class_init cla pub_meths cstr inh_init cl_init msubst top cl
| Tclass_let (rec_flag, defs, vals, cl) ->
let (inh_init, cl_init) =
- build_class_init cla pub_meths cstr inh_init cl_init cl
+ build_class_init cla pub_meths cstr inh_init cl_init msubst top cl
in
let vals = List.map (function (id, _) -> (Ident.name id, id)) vals in
- (inh_init, transl_vals cla true vals cl_init)
+ (inh_init, transl_vals cla true false vals cl_init)
| Tclass_constraint (cl, vals, meths, concr_meths) ->
- let core cl_init =
- build_class_init cla pub_meths true inh_init cl_init cl
- in
- if cstr then
- core cl_init
- else
- let virt_meths =
- List.fold_right
- (fun lab rem ->
- if Concr.mem lab concr_meths then rem else lab::rem)
- meths
- []
- in
- let (inh_init, cl_init) =
- core (Lsequence (Lapply (oo_prim "widen", [Lvar cla]),
- cl_init))
- in
- (inh_init,
- Lsequence(Lapply (oo_prim "narrow",
- [Lvar cla;
- transl_meth_list vals;
- transl_meth_list virt_meths;
- transl_meth_list (Concr.elements concr_meths)]),
- cl_init))
+ let virt_meths =
+ List.filter (fun lab -> not (Concr.mem lab concr_meths)) meths in
+ let narrow_args =
+ [Lvar cla;
+ transl_meth_list vals;
+ transl_meth_list virt_meths;
+ transl_meth_list (Concr.elements concr_meths)] in
+ let cl = ignore_cstrs cl in
+ begin match cl.cl_desc, inh_init with
+ Tclass_ident path, (obj_init, path')::inh_init ->
+ assert (Path.same path path');
+ let lpath = transl_path path in
+ (inh_init,
+ Llet (Strict, obj_init,
+ Lapply(oo_prim "inherits", narrow_args @
+ [lpath; Lconst(Const_pointer(if top then 1 else 0))]),
+ cl_init))
+ | _ ->
+ let core cl_init =
+ build_class_init cla pub_meths true inh_init cl_init msubst top cl
+ in
+ if cstr then core cl_init else
+ let (inh_init, cl_init) =
+ core (Lsequence (Lapply (oo_prim "widen", [Lvar cla]), cl_init))
+ in
+ (inh_init,
+ Lsequence(Lapply (oo_prim "narrow", narrow_args), cl_init))
+ end
+let rec build_class_lets cl =
+ match cl.cl_desc with
+ Tclass_let (rec_flag, defs, vals, cl) ->
+ let env, wrap = build_class_lets cl in
+ (env, fun x -> Translcore.transl_let rec_flag defs (wrap x))
+ | _ ->
+ (cl.cl_env, fun x -> x)
(*
XXX Il devrait etre peu couteux d'ecrire des classes :
class c x y = d e f
*)
+let rec transl_class_rebind obj_init cl =
+ match cl.cl_desc with
+ Tclass_ident path ->
+ (path, obj_init)
+ | Tclass_fun (pat, _, cl, partial) ->
+ let path, obj_init = transl_class_rebind obj_init cl in
+ let build params rem =
+ let param = name_pattern "param" [pat, ()] in
+ Lfunction (Curried, param::params,
+ Matching.for_function
+ pat.pat_loc None (Lvar param) [pat, rem] partial)
+ in
+ (path,
+ match obj_init with
+ Lfunction (Curried, params, rem) -> build params rem
+ | rem -> build [] rem)
+ | Tclass_apply (cl, oexprs) ->
+ let path, obj_init = transl_class_rebind obj_init cl in
+ (path, transl_apply obj_init oexprs)
+ | Tclass_let (rec_flag, defs, vals, cl) ->
+ let path, obj_init = transl_class_rebind obj_init cl in
+ (path, Translcore.transl_let rec_flag defs obj_init)
+ | Tclass_structure {cl_field = [Cf_inher(cl, _, _)]} ->
+ let path, obj_init = transl_class_rebind obj_init cl in
+ (path, obj_init)
+ | Tclass_structure _ -> raise Exit
+ | Tclass_constraint (cl', _, _, _) ->
+ let path, obj_init = transl_class_rebind obj_init cl' in
+ let rec check_constraint = function
+ Tcty_constr(path', _, _) when Path.same path path' -> ()
+ | Tcty_fun (_, _, cty) -> check_constraint cty
+ | _ -> raise Exit
+ in
+ check_constraint cl.cl_type;
+ (path, obj_init)
+
+let rec transl_class_rebind_0 self obj_init cl =
+ match cl.cl_desc with
+ Tclass_let (rec_flag, defs, vals, cl) ->
+ let path, obj_init = transl_class_rebind_0 self obj_init cl in
+ (path, Translcore.transl_let rec_flag defs obj_init)
+ | _ ->
+ let path, obj_init = transl_class_rebind obj_init cl in
+ (path, lfunction [self] obj_init)
+
+let transl_class_rebind ids cl =
+ try
+ let obj_init = Ident.create "obj_init"
+ and self = Ident.create "self" in
+ let obj_init0 = lapply (Lvar obj_init) [Lvar self] in
+ let path, obj_init' = transl_class_rebind_0 self obj_init0 cl in
+ if not (Translcore.check_recursive_lambda ids obj_init') then
+ raise(Error(cl.cl_loc, Illegal_class_expr));
+ let id = (obj_init' = lfunction [self] obj_init0) in
+ if id then transl_path path else
+
+ let cla = Ident.create "class"
+ and new_init = Ident.create "new_init"
+ and arg = Ident.create "arg"
+ and env_init = Ident.create "env_init"
+ and table = Ident.create "table"
+ and envs = Ident.create "envs" in
+ Llet(
+ Strict, new_init, lfunction [obj_init] obj_init',
+ Llet(
+ Alias, cla, transl_path path,
+ Lprim(Pmakeblock(0, Immutable),
+ [Lapply(Lvar new_init, [lfield cla 0]);
+ lfunction [table]
+ (Llet(Strict, env_init,
+ Lapply(lfield cla 1, [Lvar table]),
+ lfunction [envs]
+ (Lapply(Lvar new_init,
+ [Lapply(Lvar env_init, [Lvar envs])]))));
+ lfield cla 2;
+ lfield cla 3])))
+ with Exit ->
+ lambda_unit
+
+(* Rewrite a closure using builtins. Improves native code size. *)
+
+let rec module_path = function
+ Lvar id ->
+ let s = Ident.name id in s <> "" && s.[0] >= 'A' && s.[0] <= 'Z'
+ | Lprim(Pfield _, [p]) -> module_path p
+ | Lprim(Pgetglobal _, []) -> true
+ | _ -> false
+
+let const_path local = function
+ Lvar id -> not (List.mem id local)
+ | Lconst _ -> true
+ | Lfunction (Curried, _, body) ->
+ let fv = free_variables body in
+ List.for_all (fun x -> not (IdentSet.mem x fv)) local
+ | p -> module_path p
+
+let rec builtin_meths self env env2 body =
+ let const_path = const_path (env::self) in
+ let conv = function
+ (* Lvar s when List.mem s self -> "_self", [] *)
+ | p when const_path p -> "const", [p]
+ | Lprim(Parrayrefu _, [Lvar s; Lvar n]) when List.mem s self ->
+ "var", [Lvar n]
+ | Lprim(Pfield n, [Lvar e]) when Ident.same e env ->
+ "env", [Lvar env2; Lconst(Const_pointer n)]
+ | Lsend(Lvar n, Lvar s, []) when List.mem s self ->
+ "meth", [Lvar n]
+ | _ -> raise Not_found
+ in
+ match body with
+ | Llet(Alias, s', Lvar s, body) when List.mem s self ->
+ builtin_meths self env env2 body
+ | Lapply(f, [arg]) when const_path f ->
+ let s, args = conv arg in ("app_"^s, f :: args)
+ | Lapply(f, [arg; p]) when const_path f && const_path p ->
+ let s, args = conv arg in
+ ("app_"^s^"_const", f :: args @ [p])
+ | Lapply(f, [p; arg]) when const_path f && const_path p ->
+ let s, args = conv arg in
+ ("app_const_"^s, f :: p :: args)
+ | Lsend(Lvar n, Lvar s, [arg]) when List.mem s self ->
+ let s, args = conv arg in
+ ("meth_app_"^s, Lvar n :: args)
+ | Lfunction (Curried, [x], body) ->
+ let rec enter self = function
+ | Lprim(Parraysetu _, [Lvar s; Lvar n; Lvar x'])
+ when Ident.same x x' && List.mem s self ->
+ ("set_var", [Lvar n])
+ | Llet(Alias, s', Lvar s, body) when List.mem s self ->
+ enter (s'::self) body
+ | _ -> raise Not_found
+ in enter self body
+ | Lfunction _ -> raise Not_found
+ | _ ->
+ let s, args = conv body in ("get_"^s, args)
+
+module M = struct
+ open CamlinternalOO
+ let builtin_meths arr self env env2 body =
+ let builtin, args = builtin_meths self env env2 body in
+ if not arr then [Lapply(oo_prim builtin, args)] else
+ let tag = match builtin with
+ "get_const" -> GetConst
+ | "get_var" -> GetVar
+ | "get_env" -> GetEnv
+ | "get_meth" -> GetMeth
+ | "set_var" -> SetVar
+ | "app_const" -> AppConst
+ | "app_var" -> AppVar
+ | "app_env" -> AppEnv
+ | "app_meth" -> AppMeth
+ | "app_const_const" -> AppConstConst
+ | "app_const_var" -> AppConstVar
+ | "app_const_env" -> AppConstEnv
+ | "app_const_meth" -> AppConstMeth
+ | "app_var_const" -> AppVarConst
+ | "app_env_const" -> AppEnvConst
+ | "app_meth_const" -> AppMethConst
+ | "meth_app_const" -> MethAppConst
+ | "meth_app_var" -> MethAppVar
+ | "meth_app_env" -> MethAppEnv
+ | "meth_app_meth" -> MethAppMeth
+ | _ -> assert false
+ in Lconst(Const_pointer(Obj.magic tag)) :: args
+end
+open M
+
+
(*
- XXX
- Exploiter le fait que les methodes sont definies dans l'ordre pour
- l'initialisation des classes (et les variables liees par un
- let ???) ?
+ Traduction d'une classe.
+ Plusieurs cas:
+ * reapplication d'une classe connue -> transl_class_rebind
+ * classe sans dependances locales -> traduction directe
+ * avec dependances locale -> creation d'un arbre de stubs,
+ avec un noeud pour chaque classe locale heritee
+ Une classe est un 4-uplet:
+ (obj_init, class_init, env_init, env)
+ obj_init: fonction de creation d'objet (unit -> obj)
+ class_init: fonction d'heritage (table -> env_init)
+ (une seule par code source)
+ env_init: parametrage par l'environnement local (env -> params -> obj_init)
+ (une par combinaison d'env_init herites)
+ env: environnement local
+ Si ids=0 (objet immediat), alors on ne conserve que env_init.
*)
+
let transl_class ids cl_id arity pub_meths cl =
+ (* First check if it is not only a rebind *)
+ let rebind = transl_class_rebind ids cl in
+ if rebind <> lambda_unit then rebind else
+
+ (* Prepare for heavy environment handling *)
+ let tables = Ident.create (Ident.name cl_id ^ "_tables") in
+ let (top_env, req) = oo_add_class tables in
+ let top = not req in
+ let cl_env, llets = build_class_lets cl in
+ let new_ids = if top then [] else Env.diff top_env cl_env in
+ let env2 = Ident.create "env" in
+ let subst env lam i0 new_ids' =
+ let fv = free_variables lam in
+ let fv = List.fold_right IdentSet.remove !new_ids' fv in
+ let fv =
+ IdentSet.filter (fun id -> List.mem id new_ids) fv in
+ new_ids' := !new_ids' @ IdentSet.elements fv;
+ let i = ref (i0-1) in
+ List.fold_left
+ (fun subst id ->
+ incr i; Ident.add id (lfield env !i) subst)
+ Ident.empty !new_ids'
+ in
+ let new_ids_meths = ref [] in
+ let msubst arr = function
+ Lfunction (Curried, self :: args, body) ->
+ let env = Ident.create "env" in
+ let body' =
+ if new_ids = [] then body else
+ subst_lambda (subst env body 0 new_ids_meths) body in
+ begin try
+ (* Doesn't seem to improve size for bytecode *)
+ (* if not !Clflags.native_code then raise Not_found; *)
+ builtin_meths arr [self] env env2 (lfunction args body')
+ with Not_found ->
+ [lfunction (self :: args)
+ (if not (IdentSet.mem env (free_variables body')) then body' else
+ Llet(Alias, env,
+ Lprim(Parrayrefu Paddrarray,
+ [Lvar self; Lvar env2]), body'))]
+ end
+ | _ -> assert false
+ in
+ let new_ids_init = ref [] in
+ let env1 = Ident.create "env" in
+ let copy_env envs self =
+ if top then lambda_unit else
+ Lifused(env2, Lprim(Parraysetu Paddrarray,
+ [Lvar self; Lvar env2; lfield env1 0]))
+ and subst_env envs lam =
+ if top then lam else
+ Llet(Alias, env1, lfield envs 0,
+ subst_lambda (subst env1 lam 1 new_ids_init) lam)
+ in
+
+ (* Now we start compiling the class *)
let cla = Ident.create "class" in
- let (inh_init, obj_init) = build_object_init_0 cla [] cl in
+ let (inh_init, obj_init) =
+ build_object_init_0 cla [] cl copy_env subst_env top ids in
if not (Translcore.check_recursive_lambda ids obj_init) then
raise(Error(cl.cl_loc, Illegal_class_expr));
- let (inh_init, cl_init) =
- build_class_init cla pub_meths true (List.rev inh_init) obj_init cl
+ let (inh_init', cl_init) =
+ build_class_init cla pub_meths true (List.rev inh_init)
+ obj_init msubst top cl
+ in
+ assert (inh_init' = []);
+ let table = Ident.create "table"
+ and class_init = Ident.create "class_init"
+ and env_init = Ident.create "env_init"
+ and obj_init = Ident.create "obj_init" in
+ let ltable table lam =
+ Llet(Strict, table,
+ Lapply (oo_prim "create_table", [transl_meth_list pub_meths]), lam)
+ and ldirect obj_init =
+ Llet(Strict, obj_init, cl_init,
+ Lsequence(Lapply (oo_prim "init_class", [Lvar cla]),
+ Lapply(Lvar obj_init, [lambda_unit])))
in
- assert (inh_init = []);
- let table = Ident.create "table" in
- let class_init = Ident.create "class_init" in
- let obj_init = Ident.create "obj_init" in
- Llet(Strict, table,
- Lapply (oo_prim "create_table", [transl_meth_list pub_meths]),
- Llet(Strict, class_init,
- Lfunction(Curried, [cla], cl_init),
- Llet(Strict, obj_init, Lapply(Lvar class_init, [Lvar table]),
- Lsequence(Lapply (oo_prim "init_class", [Lvar table]),
- Lprim(Pmakeblock(0, Immutable),
- [Lvar obj_init;
- Lvar class_init;
- Lvar table])))))
-
-let class_stub =
- Lprim(Pmakeblock(0, Mutable), [lambda_unit; lambda_unit; lambda_unit])
+ (* Simplest case: an object defined at toplevel (ids=[]) *)
+ if top && ids = [] then llets (ltable cla (ldirect obj_init)) else
+
+ let lclass lam =
+ Llet(Strict, class_init, Lfunction(Curried, [cla], cl_init), lam)
+ and lbody =
+ Lapply (oo_prim "make_class",
+ [transl_meth_list pub_meths; Lvar class_init])
+ in
+ (* Still easy: a class defined at toplevel *)
+ if top then llets (lclass lbody) else
+
+ (* Now for the hard stuff: prepare for table cacheing *)
+ let env_index = Ident.create "env_index"
+ and envs = Ident.create "envs" in
+ let lenvs =
+ if !new_ids_meths = [] && !new_ids_init = [] && inh_init = []
+ then lambda_unit
+ else Lvar envs in
+ let lenv =
+ if !new_ids_meths = [] && !new_ids_init = [] then lambda_unit else
+ Lprim(Pmakeblock(0, Immutable),
+ (if !new_ids_meths = [] then lambda_unit else
+ Lprim(Pmakeblock(0, Immutable),
+ List.map (fun id -> Lvar id) !new_ids_meths)) ::
+ List.map (fun id -> Lvar id) !new_ids_init)
+ and linh_envs =
+ List.map (fun (_, p) -> Lprim(Pfield 3, [transl_path p]))
+ (List.rev inh_init)
+ in
+ let make_envs lam =
+ Llet(StrictOpt, envs,
+ Lprim(Pmakeblock(0, Immutable), lenv :: linh_envs),
+ lam)
+ and def_ids cla lam =
+ Llet(StrictOpt, env2,
+ Lapply (oo_prim "new_variable", [Lvar cla; transl_label ""]),
+ lam)
+ in
+ let obj_init2 = Ident.create "obj_init"
+ and cached = Ident.create "cached" in
+ let inh_paths =
+ List.filter
+ (fun (_,path) -> List.mem (Path.head path) new_ids) inh_init in
+ let inh_keys =
+ List.map (fun (_,p) -> Lprim(Pfield 2, [transl_path p])) inh_paths in
+ let lclass lam =
+ Llet(Strict, class_init,
+ Lfunction(Curried, [cla], def_ids cla cl_init), lam)
+ and lcache lam =
+ if inh_keys = [] then Llet(Alias, cached, Lvar tables, lam) else
+ Llet(Strict, cached,
+ Lapply(oo_prim "lookup_tables",
+ [Lvar tables; Lprim(Pmakeblock(0, Immutable), inh_keys)]),
+ lam)
+ and lset cached i lam =
+ Lprim(Psetfield(i, true), [Lvar cached; lam])
+ in
+ let ldirect () =
+ ltable cla
+ (Llet(Strict, env_init, def_ids cla cl_init,
+ Lsequence(Lapply (oo_prim "init_class", [Lvar cla]),
+ lset cached 0 (Lvar env_init))))
+ in
+ llets (
+ lcache (
+ Lsequence(
+ Lifthenelse(lfield cached 0, lambda_unit,
+ if ids = [] then ldirect () else
+ lclass (
+ Lapply (oo_prim "make_class_store",
+ [transl_meth_list pub_meths;
+ Lvar class_init; Lvar cached]))),
+ make_envs (
+ if ids = [] then Lapply(lfield cached 0, [lenvs]) else
+ Lprim(Pmakeblock(0, Immutable),
+ [Lapply(lfield cached 0, [lenvs]);
+ lfield cached 1;
+ lfield cached 0;
+ lenvs])))))
+
+(* Dummy for recursive modules *)
let dummy_class undef_fn =
- Lprim(Pmakeblock(0, Mutable), [undef_fn; undef_fn; oo_prim "dummy_table"])
+ Lprim(Pmakeblock(0, Mutable), [undef_fn; undef_fn; undef_fn; lambda_unit])
+
+(* Wrapper for class compilation *)
+
+let transl_class ids cl_id arity pub_meths cl =
+ oo_wrap cl.cl_env false (transl_class ids cl_id arity pub_meths) cl
+
+let () =
+ transl_object := (fun id meths cl -> transl_class [] id 0 meths cl)
(* Error report *)