Skip to content

Commit 18b65cc

Browse files
Hongbo Zhangbobzhang
authored andcommitted
small enhancement to cross inlining: TODO: 1. add comments if we can, for example, cross module constants, 2. specialize some functions as early as we can
TODO: improve lambda exports
1 parent d9dc1c0 commit 18b65cc

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

53 files changed

+366
-154
lines changed

jscomp/lam_analysis.ml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -452,6 +452,8 @@ let is_closed_by set lam =
452452
Ident_map.is_empty (free_variables set (Ident_map.empty ) lam )
453453

454454

455+
(** A bit consverative , it should be empty *)
455456
let is_closed lam =
456-
Ident_map.is_empty (free_variables Ident_set.empty Ident_map.empty lam)
457+
Ident_map.for_all (fun k _ -> Ident.global k)
458+
(free_variables Ident_set.empty Ident_map.empty lam)
457459

jscomp/lam_analysis.mli

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ val is_closed : Lambda.lambda -> bool
4141

4242

4343

44+
4445
type stats =
4546
{
4647
mutable top : bool ;
@@ -57,6 +58,7 @@ type stats =
5758
}
5859

5960
val param_map_of_list : Ident.t list -> stats Ident_map.t
61+
6062
val free_variables : Ident_set.t -> stats Ident_map.t -> Lambda.lambda -> stats Ident_map.t
6163

6264
val small_inline_size : int

jscomp/lam_compile.ml

Lines changed: 138 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,140 @@ type default_case =
5151
| Complete
5252
| NonComplete
5353

54+
5455
let rec
55-
compile_let flag (cxt : Lam_compile_defs.cxt) id (arg : Lambda.lambda) : Js_output.t =
56+
get_exp_with_index (cxt : Lam_compile_defs.cxt) lam
57+
((id : Ident.t), (pos : int),env) : Js_output.t =
58+
let f = Js_output.handle_name_tail cxt.st cxt.should_return lam in
59+
Lam_compile_env.find_and_add_if_not_exist (id,pos) env
60+
~not_found:(fun id ->
61+
f (E.str ~pure:false (Printf.sprintf "Err %s %d %d" id.name id.flags pos))
62+
(* E.index m (pos + 1) *) (** shift by one *)
63+
(** This can not happen since this id should be already consulted by type checker *)
64+
)
65+
~found:(fun {id; name; closed_lambda } ->
66+
match id, name, closed_lambda with
67+
| {name = "Sys"; _}, "os_type" , _
68+
(** We drop the ability of cross-compiling
69+
the compiler has to be the same running
70+
*)
71+
-> f (E.str Sys.os_type)
72+
| _, _, Some lam when Lam_util.not_function lam
73+
(* since it's only for alias, there is no arguments,
74+
we should not inline function definition here, even though
75+
it is very small
76+
TODO: add comment here, we should try to add comment for
77+
cross module inlining
78+
*)
79+
->
80+
compile_lambda cxt lam
81+
| _ ->
82+
f (E.ml_var_dot id name)
83+
)
84+
(* TODO: how nested module call would behave,
85+
In the future, we should keep in track of if
86+
it is fully applied from [Lapply]
87+
Seems that the module dependency is tricky..
88+
should we depend on [Pervasives] or not?
89+
90+
we can not do this correctly for the return value,
91+
however we can inline the definition in Pervasives
92+
TODO:
93+
[Pervasives.print_endline]
94+
[Pervasives.prerr_endline]
95+
@param id external module id
96+
@param number the index of the external function
97+
@param env typing environment
98+
@param args arguments
99+
*)
100+
101+
and get_exp_with_args (cxt : Lam_compile_defs.cxt) lam args_lambda
102+
(id : Ident.t) (pos : int) env : Js_output.t =
103+
let args_code, args =
104+
List.fold_right
105+
(fun (x : Lambda.lambda) (args_code, args) ->
106+
match x with
107+
| Lprim (Pgetglobal i, [] ) ->
108+
(* when module is passed as an argument - unpack to an array
109+
for the function, generative module or functor can be a function,
110+
however it can not be global -- global can only module
111+
*)
112+
113+
args_code, (Lam_compile_global.get_exp (i, env, true) :: args)
114+
| _ ->
115+
begin match compile_lambda {cxt with st = NeedValue; should_return = False} x with
116+
| {block = a; value = Some b} ->
117+
(a @ args_code), (b :: args )
118+
| _ -> assert false
119+
end
120+
) args_lambda ([], []) in
121+
122+
Lam_compile_env.find_and_add_if_not_exist (id,pos) env ~not_found:(fun id ->
123+
(** This can not happen since this id should be already consulted by type checker
124+
Worst case
125+
{[
126+
E.index m (pos + 1)
127+
]}
128+
shift by one (due to module encoding)
129+
*)
130+
Js_output.handle_block_return cxt.st cxt.should_return lam args_code @@
131+
E.str ~pure:false (Printf.sprintf "Err %s %d %d"
132+
id.name
133+
id.flags
134+
pos
135+
))
136+
137+
~found:(fun {id; name;arity; closed_lambda ; _} ->
138+
match closed_lambda with
139+
| Some (Lfunction (_, params, body))
140+
when Ext_list.same_length params args_lambda ->
141+
compile_lambda cxt
142+
(Lam_beta_reduce.propogate_beta_reduce cxt.meta params body args_lambda)
143+
| _ ->
144+
Js_output.handle_block_return cxt.st cxt.should_return lam args_code @@
145+
(match id, name, args with
146+
| {name = "Pervasives"; _}, "^", [ e0 ; e1] ->
147+
E.string_append e0 e1
148+
| {name = "Pervasives"; _}, "string_of_int", [e]
149+
-> E.int_to_string e
150+
| {name = "Pervasives"; _}, "print_endline", ([ _ ] as args) ->
151+
E.seq (E.dump Log args) (E.unit ())
152+
| {name = "Pervasives"; _}, "prerr_endline", ([ _ ] as args) ->
153+
E.seq (E.dump Error args) (E.unit ())
154+
| _ ->
155+
156+
157+
let rec aux (acc : J.expression)
158+
(arity : Lam_stats.function_arities) args (len : int) =
159+
match arity, len with
160+
| _, 0 ->
161+
acc (** All arguments consumed so far *)
162+
| Determin (a, (x,_) :: rest, b), len ->
163+
let x =
164+
if x = 0
165+
then 1
166+
else x in (* Relax when x = 0 *)
167+
if len >= x
168+
then
169+
let first_part, continue = (Ext_list.take x args) in
170+
aux
171+
(E.call ~info:{arity=Full} acc first_part)
172+
(Determin (a, rest, b))
173+
continue (len - x)
174+
else acc
175+
(* alpha conversion now? --
176+
Since we did an alpha conversion before so it is not here
177+
*)
178+
| Determin (a, [], b ), _ ->
179+
(* can not happen, unless it's an exception ? *)
180+
E.call acc args
181+
| NA, _ ->
182+
E.call acc args
183+
in
184+
aux (E.ml_var_dot id name) arity args (List.length args ))
185+
)
186+
187+
and compile_let flag (cxt : Lam_compile_defs.cxt) id (arg : Lambda.lambda) : Js_output.t =
56188

57189

58190
match flag, arg with
@@ -285,28 +417,8 @@ and
285417
(Lapply (an, (args' @ args), (Lam_util.mk_apply_info NA)))
286418
(* External function calll *)
287419
| Lapply(Lprim(Pfield n, [ Lprim(Pgetglobal id,[])]), args_lambda,_info) ->
288-
let [@warning "-8" (* non-exhaustive pattern*)] (args_code,args) =
289-
args_lambda
290-
|> List.map
291-
(
292-
fun (x : Lambda.lambda) ->
293-
match x with
294-
| Lprim (Pgetglobal i, []) ->
295-
(* when module is passed as an argument - unpack to an array
296-
for the function, generative module or functor can be a function,
297-
however it can not be global -- global can only module
298-
*)
299-
[], Lam_compile_global.get_exp (QueryGlobal (i, env,true))
300-
| _ ->
301-
begin
302-
match compile_lambda
303-
{cxt with st = NeedValue ; should_return = False} x with
304-
| {block = a; value = Some b} -> a,b
305-
| _ -> assert false
306-
end)
307-
|> List.split in
308-
Js_output.handle_block_return st should_return lam (List.concat args_code )
309-
(Lam_compile_global.get_exp_with_args id n env args)
420+
421+
get_exp_with_args cxt lam args_lambda(* args_code *) id n env (* args *)
310422

311423

312424
| Lapply(fn,args_lambda, info) ->
@@ -326,7 +438,7 @@ and
326438
for the function, generative module or functor can be a function,
327439
however it can not be global -- global can only module
328440
*)
329-
[], Lam_compile_global.get_exp (QueryGlobal (ident, env,true))
441+
[], Lam_compile_global.get_exp (ident, env,true)
330442
| _ ->
331443
begin
332444
match compile_lambda
@@ -444,8 +556,7 @@ and
444556
Js_output.handle_name_tail st should_return lam (Lam_compile_const.translate c)
445557

446558
| Lprim(Pfield n, [ Lprim(Pgetglobal id,[])]) -> (* should be before Pgetglobal *)
447-
Js_output.handle_name_tail st should_return lam
448-
(Lam_compile_global.get_exp (GetGlobal (id,n, env)))
559+
get_exp_with_index cxt lam (id,n, env)
449560

450561
| Lprim(Praise _raise_kind, [ e ]) ->
451562
begin
@@ -1089,7 +1200,7 @@ and
10891200
|> List.map (fun (x : Lambda.lambda) ->
10901201
match x with
10911202
| Lprim (Pgetglobal i, []) ->
1092-
[], Lam_compile_global.get_exp (QueryGlobal (i, env, true))
1203+
[], Lam_compile_global.get_exp (i, env, true)
10931204
| _ ->
10941205
begin
10951206
match compile_lambda {cxt with st = NeedValue; should_return = False}

jscomp/lam_compile_env.ml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,9 @@ type module_info = {
4646
type primitive_description = Types.type_expr option Primitive.description
4747

4848
type key =
49-
| GetGlobal of Ident.t * int * Env.t
50-
| QueryGlobal of Ident.t * Env.t * bool (** we need register which global variable is an dependency *)
51-
| CamlRuntimePrimitive of primitive_description * J.expression list
49+
50+
Ident.t * Env.t * bool (** we need register which global variable is an dependency *)
51+
5252

5353
type ident_info = {
5454
id : Ident.t;

jscomp/lam_compile_env.mli

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,15 +25,14 @@
2525
type primitive_description = Types.type_expr option Primitive.description
2626

2727
type key =
28-
| GetGlobal of Ident.t * int * Env.t
29-
| QueryGlobal of Ident.t * Env.t * bool
28+
Ident.t * Env.t * bool
3029
(** the boolean is expand or not
3130
when it's passed as module, it should be expanded,
3231
otherwise for alias, [include Array], it's okay to return an identifier
3332
TODO: be more clear about its concept
3433
*)
3534
(** we need register which global variable is an dependency *)
36-
| CamlRuntimePrimitive of primitive_description * J.expression list
35+
3736

3837
type ident_info = {
3938
id : Ident.t;

jscomp/lam_compile_external_call.ml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -288,7 +288,7 @@ let translate
288288
in
289289
E.obj kvs
290290
| None -> assert false
291-
(* Lam_compile_global.get_exp (CamlRuntimePrimitive (prim, args)) *)
291+
292292
end
293293
| Js_call{ external_module_name = module_name;
294294
txt = { name = fn; splice = js_splice ;
@@ -375,8 +375,8 @@ let translate
375375
| _ -> assert false
376376
end
377377

378-
| Normal ->
379-
Lam_compile_global.get_exp (CamlRuntimePrimitive (prim, args))
378+
| Normal -> Lam_dispatch_primitive.query prim args
379+
380380

381381
end
382382

jscomp/lam_compile_global.ml

Lines changed: 3 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -41,28 +41,11 @@ let query_lambda id env =
4141
Lambda.Lprim(Pfield i, [Lprim(Pgetglobal id,[])])))
4242
sigs))
4343

44+
4445
(* Given an module name and position, find its corresponding name *)
4546
let get_exp (key : Lam_compile_env.key) : J.expression =
4647
match key with
47-
| GetGlobal ((id : Ident.t), (pos : int),env) ->
48-
Lam_compile_env.find_and_add_if_not_exist (id,pos) env
49-
~not_found:(fun id ->
50-
E.str ~pure:false (Printf.sprintf "Err %s %d %d" id.name id.flags pos)
51-
(* E.index m (pos + 1) *) (** shift by one *)
52-
(** This can not happen since this id should be already consulted by type checker *)
53-
)
54-
~found:(fun {id; name;_} ->
55-
match id, name with
56-
| {name = "Sys"; _}, "os_type"
57-
(** We drop the ability of cross-compiling
58-
the compiler has to be the same running
59-
*)
60-
-> E.str Sys.os_type
61-
| _ ->
62-
E.ml_var_dot id name
63-
)
64-
65-
| QueryGlobal (id, env, expand) ->
48+
(id, env, expand) ->
6649
if Ident.is_predef_exn id
6750
then
6851
begin
@@ -83,9 +66,7 @@ let get_exp (key : Lam_compile_env.key) : J.expression =
8366
else
8467
E.ml_var id)
8568

86-
| CamlRuntimePrimitive (prim, args) ->
87-
Lam_dispatch_primitive.query prim args
88-
69+
8970

9071
(* TODO: how nested module call would behave,
9172
In the future, we should keep in track of if

jscomp/lam_compile_global.mli

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,6 @@
2424

2525
val get_exp : Lam_compile_env.key -> J.expression
2626

27-
(*
28-
@param id external module id
29-
@param number the index of the external function
30-
@param env typing environment
31-
@param args arguments
32-
*)
33-
val get_exp_with_args : Ident.t -> int -> Env.t -> J.expression list -> J.expression
27+
3428

3529
val query_lambda : Ident.t -> Env.t -> Lambda.lambda

jscomp/lam_compile_group.ml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -357,7 +357,7 @@ let lambda_as_module
357357
(lam : Lambda.lambda) =
358358
begin
359359
Lam_current_unit.set_file filename ;
360-
Lam_current_unit.iset_debug_file "format_regression.ml";
360+
Lam_current_unit.set_debug_file "pervasives.ml";
361361
Ext_pervasives.with_file_as_chan
362362
(Ext_filename.chop_extension ~loc:__LOC__ filename ^ ".js")
363363
(fun chan -> Js_dump.dump_deps_program (compile ~filename false env sigs lam) chan)

jscomp/lam_compile_primitive.ml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -298,7 +298,7 @@ let translate
298298
1. include Array --> let include = Array
299299
2. get exception
300300
*)
301-
Lam_compile_global.get_exp (QueryGlobal (i,env,false))
301+
Lam_compile_global.get_exp (i,env,false)
302302

303303
(** only when Lapply -> expand = true*)
304304
| Praise _raise_kind -> assert false (* handled before here *)

jscomp/lam_inline_util.ml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@
2424
let maybe_functor (name : string) =
2525
name.[0] >= 'A' && name.[0] <= 'Z'
2626

27+
28+
let should_be_functor (name : string) lam =
29+
maybe_functor name && (function | Lambda.Lfunction _ -> true | _ -> false) lam
30+
2731
(* TODO: add a context, like
2832
[args]
2933
[Lfunction(params,body)]

jscomp/lam_inline_util.mli

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,5 @@
2323
(** Utilities for lambda inlining *)
2424

2525
val maybe_functor : string -> bool
26+
27+
val should_be_functor : string -> Lambda.lambda -> bool

0 commit comments

Comments
 (0)