diff options
author | Jacques Garrigue <garrigue at math.nagoya-u.ac.jp> | 2003-12-01 00:56:52 +0000 |
---|---|---|
committer | Jacques Garrigue <garrigue at math.nagoya-u.ac.jp> | 2003-12-01 00:56:52 +0000 |
commit | 073f94ec3520efd524d23373a3b2441f66f86b1c (patch) | |
tree | b8a90615418bb5af049d1a88ce6dbd4d91c402e5 | |
parent | bbc1c339f4b0de238e8024fb632ecb30bcc686de (diff) | |
download | ocaml-073f94ec3520efd524d23373a3b2441f66f86b1c.tar.gz |
replace method labels by hashes
git-svn-id: http://caml.inria.fr/svn/ocaml/branches/newoolab@5990 f963ae5c-01c2-4b8c-9fe0-0dff7051ff02
-rw-r--r-- | bytecomp/matching.mli | 4 | ||||
-rw-r--r-- | bytecomp/translclass.ml | 26 | ||||
-rw-r--r-- | bytecomp/translcore.ml | 15 | ||||
-rw-r--r-- | bytecomp/translobj.ml | 4 | ||||
-rw-r--r-- | bytecomp/translobj.mli | 2 | ||||
-rw-r--r-- | byterun/interp.c | 20 | ||||
-rw-r--r-- | stdlib/camlinternalOO.ml | 275 | ||||
-rw-r--r-- | stdlib/camlinternalOO.mli | 25 | ||||
-rw-r--r-- | stdlib/oo.ml | 2 |
9 files changed, 111 insertions, 262 deletions
diff --git a/bytecomp/matching.mli b/bytecomp/matching.mli index 763f8fe03a..acbcd6ff8e 100644 --- a/bytecomp/matching.mli +++ b/bytecomp/matching.mli @@ -35,3 +35,7 @@ val for_tupled_function: exception Cannot_flatten val flatten_pattern: int -> pattern -> pattern list + +val make_test_sequence: + lambda option -> primitive -> primitive -> lambda -> + (Asttypes.constant * lambda) list -> lambda diff --git a/bytecomp/translclass.ml b/bytecomp/translclass.ml index 81b1fb52ee..68616a4173 100644 --- a/bytecomp/translclass.ml +++ b/bytecomp/translclass.ml @@ -204,12 +204,9 @@ let rec build_object_init_0 cl_table params cl copy_env subst_env top ids = let bind_method tbl public_methods lab id cl_init = - if List.mem lab public_methods then - Llet(Alias, id, Lvar (meth lab), cl_init) - else - Llet(StrictOpt, id, Lapply (oo_prim "get_method_label", - [Lvar tbl; transl_label lab]), - cl_init) + Llet(StrictOpt, id, Lapply (oo_prim "get_method_label", + [Lvar tbl; transl_label lab]), + cl_init) let bind_methods tbl public_methods meths cl_init = Meths.fold (bind_method tbl public_methods) meths cl_init @@ -572,6 +569,7 @@ let transl_class ids cl_id arity pub_meths cl = if new_ids = [] then body else subst_lambda (subst env body 0 new_ids_meths) body in begin try + raise Not_found; (* 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') @@ -611,9 +609,19 @@ let transl_class ids cl_id arity pub_meths cl = and class_init = Ident.create "class_init" and env_init = Ident.create "env_init" and obj_init = Ident.create "obj_init" in + let public_map pub_meths = + let meth = Ident.create "meth" in + let i = ref 0 in + let index m = incr i; + (Const_int (Btype.hash_variant m), Lconst(Const_pointer !i)) in + Lfunction(Curried, [meth], + Matching.make_test_sequence None (Pintcomp Cneq) (Pintcomp Clt) + (Lvar meth) (List.map index pub_meths)) + in let ltable table lam = Llet(Strict, table, - Lapply (oo_prim "create_table", [transl_meth_list pub_meths]), lam) + Lapply (oo_prim "create_table", + [public_map pub_meths; transl_meth_list pub_meths]), lam) and ldirect obj_init = Llet(Strict, obj_init, cl_init, Lsequence(Lapply (oo_prim "init_class", [Lvar cla]), @@ -630,7 +638,7 @@ let transl_class ids cl_id arity pub_meths cl = lam class_init) and lbody class_init = Lapply (oo_prim "make_class", - [transl_meth_list pub_meths; Lvar class_init]) + [public_map pub_meths;transl_meth_list pub_meths; Lvar class_init]) and lbody_virt lenvs = Lprim(Pmakeblock(0, Immutable), [lambda_unit; Lfunction(Curried,[cla], cl_init); lambda_unit; lenvs]) @@ -701,7 +709,7 @@ let transl_class ids cl_id arity pub_meths cl = if not concrete then lclass_virt () else lclass ( Lapply (oo_prim "make_class_store", - [transl_meth_list pub_meths; + [public_map pub_meths; transl_meth_list pub_meths; Lvar class_init; Lvar cached]))), make_envs ( if ids = [] then Lapply(lfield cached 0, [lenvs]) else diff --git a/bytecomp/translcore.ml b/bytecomp/translcore.ml index 49f4bd8ae7..17007f091a 100644 --- a/bytecomp/translcore.ml +++ b/bytecomp/translcore.ml @@ -655,12 +655,19 @@ and transl_exp0 e = (Lifthenelse(transl_exp cond, event_before body (transl_exp body), staticfail)) | Texp_send(expr, met) -> - let met_id = + let self = Ident.create "obj" in + let met_index = match met with - Tmeth_name nm -> Translobj.meth nm - | Tmeth_val id -> id + Tmeth_name nm -> + Lapply(Lprim(Pfield 0,[Lprim(Pfield 0,[Lvar self])]), + [Translobj.meth nm]) + | Tmeth_val id -> Lvar id in - event_after e (Lsend(Lvar met_id, transl_exp expr, [])) + event_after e + (Llet(Strict, self, transl_exp expr, + Lapply(Lprim(Parrayrefu Paddrarray, + [Lprim(Pfield 0,[Lvar self]); met_index]), + [Lvar self]))) | Texp_new (cl, _) -> Lapply(Lprim(Pfield 0, [transl_path cl]), [lambda_unit]) | Texp_instvar(path_self, path) -> diff --git a/bytecomp/translobj.ml b/bytecomp/translobj.ml index ea449202eb..d46c960d0a 100644 --- a/bytecomp/translobj.ml +++ b/bytecomp/translobj.ml @@ -46,6 +46,9 @@ let share c = let used_methods = ref ([] : (string * Ident.t) list);; +let meth s = Lconst(Const_pointer(Btype.hash_variant s)) + +(* let meth lab = try List.assoc lab !used_methods @@ -53,6 +56,7 @@ let meth lab = let id = Ident.create lab in used_methods := (lab, id)::!used_methods; id +*) let reset_labels () = Hashtbl.clear consts; diff --git a/bytecomp/translobj.mli b/bytecomp/translobj.mli index f0a92b3324..fe0ce1ab5e 100644 --- a/bytecomp/translobj.mli +++ b/bytecomp/translobj.mli @@ -17,7 +17,7 @@ open Lambda val oo_prim: string -> lambda val share: structured_constant -> lambda -val meth: string -> Ident.t +val meth: string -> lambda val reset_labels: unit -> unit val transl_label_init: lambda -> lambda diff --git a/byterun/interp.c b/byterun/interp.c index 557ed6f091..3eb9917da2 100644 --- a/byterun/interp.c +++ b/byterun/interp.c @@ -1009,14 +1009,34 @@ value interprete(code_t prog, asize_t prog_size) /* Object-oriented operations */ +/* #define Lookup(obj, lab) \ Field (Field (Field (obj, 0), ((lab) >> 16) / sizeof (value)), \ ((lab) / sizeof (value)) & 0xFF) +*/ +#define Lookup(obj, lab) Field (Field (obj, 0), Int_val(lab)) Instruct(GETMETHOD): accu = Lookup(sp[0], accu); Next; + Instruct(GETMETIND): { + /* accu == object, *pc == label */ + value tags = Field (Field(accu,0), 0); + value tag = *pc; + pc++; + int li = 0, hi = Wosize_val(tags)-1, mi; + value low = Field(tags,li), high = Field(tags,hi), mid; + while (li < hi) { + mi = (li+hi+1) >> 1; + mid = Field(tags,mi); + if (tag < mid) hi = mi-1; + else li = mi; + } + accu = Field (Field(obj,0), li+1); + Next; + } + /* Debugging and machine control */ Instruct(STOP): diff --git a/stdlib/camlinternalOO.ml b/stdlib/camlinternalOO.ml index 29e81dc8c0..566d620827 100644 --- a/stdlib/camlinternalOO.ml +++ b/stdlib/camlinternalOO.ml @@ -58,181 +58,30 @@ let first_bucket = 0 let bucket_size = 32 (* Must be 256 or less *) let initial_object_size = 2 -(**** Index ****) - -type label = int - -let label_count = ref 0 - -let next label = - incr label_count; - let label = label + step in - if label mod (step * bucket_size) = 0 then - label + step * (65536 - bucket_size) - else - label - -let decode label = - (label / 65536 / step, (label mod (step * bucket_size)) / step) - (**** Items ****) type item let dummy_item = (magic () : item) -(**** Buckets ****) - -type bucket = item array - -let version = ref 0 - -let set_bucket_version (bucket : bucket) = - bucket.(bucket_size) <- (magic !version : item) - -let bucket_version bucket = - (magic bucket.(bucket_size) : int) - -let bucket_list = ref [] - -let empty_bucket = [| |] - -let new_bucket () = - let bucket = Array.create (bucket_size + 1) dummy_item in - set_bucket_version bucket; - bucket_list := bucket :: !bucket_list; - bucket - -let copy_bucket bucket = - let bucket = Array.copy bucket in - set_bucket_version bucket; - bucket.(bucket_size) <- (magic !version : item); - bucket_list := bucket :: !bucket_list; - bucket - -(**** Make a clean bucket ****) - -let new_filled_bucket pos methods = - let bucket = new_bucket () in - List.iter - (fun (lab, met) -> - let (buck, elem) = decode lab in - if buck = pos then - bucket.(elem) <- (magic met : item)) - (List.rev methods); - bucket - -(**** Bucket merging ****) - -let small_buckets = ref (Array.create 10 [| |]) -let small_bucket_count = ref 0 - -let insert_bucket bucket = - let length = Array.length !small_buckets in - if !small_bucket_count >= length then begin - let new_array = Array.create (2 * length) [| |] in - Array.blit !small_buckets 0 new_array 0 length; - small_buckets := new_array - end; - !small_buckets.(!small_bucket_count) <- bucket; - incr small_bucket_count - -let remove_bucket n = - !small_buckets.(n) <- !small_buckets.(!small_bucket_count - 1); - decr small_bucket_count - -let bucket_used b = - let n = ref 0 in - for i = 0 to bucket_size - 1 do - if b.(i) != dummy_item then incr n - done; - !n - -let small_bucket b = bucket_used b <= params.bucket_small_size - -exception Failed - -let rec except e = - function - [] -> [] - | e'::l -> if e == e' then l else e'::(except e l) - -let merge_buckets b1 b2 = - for i = 0 to bucket_size - 1 do - if - (b2.(i) != dummy_item) && (b1.(i) != dummy_item) && (b2.(i) != b1.(i)) - then - raise Failed - done; - for i = 0 to bucket_size - 1 do - if b2.(i) != dummy_item then - b1.(i) <- b2.(i) - done; - bucket_list := except b2 !bucket_list; - b1 - -let prng = Random.State.make [| 0 |];; - -let rec choose bucket i = - if (i > 0) && (!small_bucket_count > 0) then begin - let n = Random.State.int prng !small_bucket_count in - if not (small_bucket !small_buckets.(n)) then begin - remove_bucket n; choose bucket i - end else - try - merge_buckets !small_buckets.(n) bucket - with Failed -> - choose bucket (i - 1) - end else begin - insert_bucket bucket; - bucket - end - -let compact b = - if - (b != empty_bucket) && (bucket_version b = !version) && (small_bucket b) - then - choose b params.retry_count - else - b +(**** Types ****) -let compact_buckets buckets = - for i = first_bucket to Array.length buckets - 1 do - buckets.(i) <- compact buckets.(i) - done +type label = int +type closure = item +type obj = t array +external ret : (obj -> 'a) -> closure = "%identity" (**** Labels ****) -let first_label = first_bucket * 65536 * step - -let last_label = ref first_label -let methods = Hashtbl.create 101 - -let new_label () = - let label = !last_label in - last_label := next !last_label; - label - -let new_method met = - try - Hashtbl.find methods met - with Not_found -> - let label = new_label () in - Hashtbl.add methods met label; - label - -let public_method_label met = - try - Hashtbl.find methods met - with Not_found -> - invalid_arg "Oo.public_method_label" - -let new_anonymous_method = - new_label - -(**** Types ****) - -type obj = t array +let public_method_label s = + let accu = ref 0 in + for i = 0 to String.length s - 1 do + accu := 223 * !accu + Char.code s.[i] + done; + (* reduce to 31 bits *) + accu := !accu land (1 lsl 31 - 1); + (* make it signed for 64 bits architectures *) + if !accu > 0x3FFFFFFF then !accu - (1 lsl 31) else !accu (**** Sparse array ****) @@ -247,7 +96,7 @@ type labs = bool Labs.t (* The compiler assumes that the first field of this structure is [size]. *) type table = { mutable size: int; - mutable buckets: bucket array; + mutable methods: closure array; mutable methods_by_name: meths; mutable methods_by_label: labs; mutable previous_states: @@ -258,20 +107,20 @@ type table = mutable initializers: (obj -> unit) list } let dummy_table = - { buckets = [| |]; + { methods = [| |]; methods_by_name = Meths.empty; methods_by_label = Labs.empty; previous_states = []; hidden_meths = []; vars = Vars.empty; initializers = []; - size = initial_object_size } + size = 0 } let table_count = ref 0 -let new_table () = +let new_table public = incr table_count; - { buckets = [| |]; + { methods = [| public |]; methods_by_name = Meths.empty; methods_by_label = Labs.empty; previous_states = []; @@ -281,22 +130,16 @@ let new_table () = size = initial_object_size } let resize array new_size = - let old_size = Array.length array.buckets in + let old_size = Array.length array.methods in if new_size > old_size then begin - let new_buck = Array.create new_size empty_bucket in - Array.blit array.buckets 0 new_buck 0 old_size; - array.buckets <- new_buck + let new_buck = Array.create new_size dummy_item in + Array.blit array.methods 0 new_buck 0 old_size; + array.methods <- new_buck end let put array label element = - let (buck, elem) = decode label in - resize array (buck + 1); - let bucket = ref (array.buckets.(buck)) in - if !bucket == empty_bucket then begin - bucket := new_bucket (); - array.buckets.(buck) <- !bucket - end; - !bucket.(elem) <- element + resize array (label + 1); + array.methods.(label) <- element (**** Classes ****) @@ -306,11 +149,16 @@ let inst_var_count = ref 0 type t type meth = item +let new_method table = + let index = Array.length table.methods in + resize table (index + 1); + index + let get_method_label table name = try Meths.find name table.methods_by_name with Not_found -> - let label = new_anonymous_method () in + let label = new_method table in table.methods_by_name <- Meths.add name label table.methods_by_name; table.methods_by_label <- Labs.add label true table.methods_by_label; label @@ -323,9 +171,8 @@ let set_method table label element = table.hidden_meths <- (label, element) :: table.hidden_meths let get_method table label = - try List.assoc label table.hidden_meths with Not_found -> - let (buck, elem) = decode label in - table.buckets.(buck).(elem) + try List.assoc label table.hidden_meths + with Not_found -> table.methods.(label) let to_list arr = if arr == magic 0 then [] else Array.to_list arr @@ -406,12 +253,12 @@ let get_variable table name = let add_initializer table f = table.initializers <- f::table.initializers -let create_table public_methods = - let table = new_table () in +let create_table public_map public_methods = + let table = new_table public_map in if public_methods != magic 0 then Array.iter (function met -> - let lab = new_method met in + let lab = new_method table in table.methods_by_name <- Meths.add met lab table.methods_by_name; table.methods_by_label <- Labs.add lab true table.methods_by_label) public_methods; @@ -419,8 +266,6 @@ let create_table public_methods = let init_class table = inst_var_count := !inst_var_count + table.size - 1; - if params.compact_table then - compact_buckets table.buckets; table.initializers <- List.rev table.initializers let inherits cla vals virt_meths concr_meths (_, super, _, env) top = @@ -430,16 +275,16 @@ let inherits cla vals virt_meths concr_meths (_, super, _, env) top = widen cla; init -let make_class pub_meths class_init = - let table = create_table pub_meths in +let make_class pub_map pub_meths class_init = + let table = create_table pub_map pub_meths in let env_init = class_init table in init_class table; (env_init (Obj.repr 0), class_init, env_init, Obj.repr 0) type init_table = { mutable env_init: t; mutable class_init: table -> t } -let make_class_store pub_meths class_init init_table = - let table = create_table pub_meths in +let make_class_store pub_map pub_meths class_init init_table = + let table = create_table pub_map pub_meths in let env_init = class_init table in init_class table; init_table.class_init <- class_init; @@ -451,7 +296,7 @@ let create_object table = (* XXX Appel de [obj_block] *) let obj = Obj.new_block Obj.object_tag table.size in (* XXX Appel de [modify] *) - Obj.set_field obj 0 (Obj.repr table.buckets); + Obj.set_field obj 0 (Obj.repr table.methods); set_id obj last_id; (Obj.obj obj) @@ -460,7 +305,7 @@ let create_object_opt obj_0 table = (* XXX Appel de [obj_block] *) let obj = Obj.new_block Obj.object_tag table.size in (* XXX Appel de [modify] *) - Obj.set_field obj 0 (Obj.repr table.buckets); + Obj.set_field obj 0 (Obj.repr table.methods); set_id obj last_id; (Obj.obj obj) end @@ -533,9 +378,6 @@ let lookup_tables root keys = (**** builtin methods ****) -type closure = item -external ret : (obj -> 'a) -> closure = "%identity" - let get_const x = ret (fun obj -> x) let get_var n = ret (fun obj -> Array.unsafe_get obj n) let get_env e n = ret (fun obj -> Obj.field (Array.unsafe_get obj e) n) @@ -635,35 +477,8 @@ let set_methods table methods = (**** Statistics ****) type stats = - { classes: int; labels: int; methods: int; inst_vars: int; buckets: int; - distrib : int array; small_bucket_count: int; small_bucket_max: int } - -let distrib () = - let d = Array.create 32 0 in - List.iter - (function b -> - let n = bucket_used b in - d.(n - 1) <- d.(n - 1) + 1) - !bucket_list; - d + { classes: int; methods: int; inst_vars: int; } let stats () = - { classes = !table_count; labels = !label_count; - methods = !method_count; inst_vars = !inst_var_count; - buckets = List.length !bucket_list; distrib = distrib (); - small_bucket_count = !small_bucket_count; - small_bucket_max = Array.length !small_buckets } - -let sort_buck lst = - List.map snd - (Sort.list (fun (n, _) (n', _) -> n <= n') - (List.map (function b -> (bucket_used b, b)) lst)) - -let show_buckets () = - List.iter - (function b -> - for i = 0 to bucket_size - 1 do - print_char (if b.(i) == dummy_item then '.' else '*') - done; - print_newline ()) - (sort_buck !bucket_list) + { classes = !table_count; + methods = !method_count; inst_vars = !inst_var_count; } diff --git a/stdlib/camlinternalOO.mli b/stdlib/camlinternalOO.mli index 0195d465f5..7fa609918a 100644 --- a/stdlib/camlinternalOO.mli +++ b/stdlib/camlinternalOO.mli @@ -17,18 +17,16 @@ All functions in this module are for system use only, not for the casual user. *) -(** {6 Methods} *) - -type label -val new_method : string -> label -val public_method_label : string -> label - (** {6 Classes} *) +type label type table type meth type t type obj +type closure +val public_method_label : string -> label +val new_method : table -> label val new_variable : table -> string -> int val new_variables : table -> string array -> int val get_variable : table -> string -> int @@ -40,17 +38,17 @@ val narrow : table -> string array -> string array -> string array -> unit val widen : table -> unit val add_initializer : table -> (obj -> unit) -> unit val dummy_table : table -val create_table : string array -> table +val create_table : closure -> string array -> table val init_class : table -> unit val inherits : table -> string array -> string array -> string array -> (t * (table -> obj -> Obj.t) * t * obj) -> bool -> Obj.t val make_class : - string array -> (table -> Obj.t -> t) -> + closure -> string array -> (table -> Obj.t -> t) -> (t * (table -> Obj.t -> t) * (Obj.t -> t) * Obj.t) type init_table val make_class_store : - string array -> (table -> t) -> init_table -> unit + closure -> string array -> (table -> t) -> init_table -> unit (** {6 Objects} *) @@ -70,7 +68,6 @@ val lookup_tables : tables -> table array -> tables (** {6 Builtins to reduce code size} *) open Obj -type closure val get_const : t -> closure val get_var : int -> closure val get_env : int -> int -> closure @@ -130,12 +127,6 @@ val params : params type stats = { classes : int; - labels : int; methods : int; - inst_vars : int; - buckets : int; - distrib : int array; - small_bucket_count : int; - small_bucket_max : int } + inst_vars : int } val stats : unit -> stats -val show_buckets : unit -> unit diff --git a/stdlib/oo.ml b/stdlib/oo.ml index e8795d8573..c9ec64ae44 100644 --- a/stdlib/oo.ml +++ b/stdlib/oo.ml @@ -15,5 +15,5 @@ let copy = CamlinternalOO.copy external id : < .. > -> int = "%field1" -let new_method = CamlinternalOO.new_method +let new_method = CamlinternalOO.public_method_label let public_method_label = CamlinternalOO.public_method_label |