Skip to content

Commit bbf93c9

Browse files
committed
finish the removal of all object usage
1 parent 6b3bdc0 commit bbf93c9

File tree

11 files changed

+1003
-1138
lines changed

11 files changed

+1003
-1138
lines changed

jscomp/core/j.ml

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -355,7 +355,7 @@ and deps_program =
355355
int_clause;
356356
string_clause ;
357357
for_direction;
358-
exception_ident;
358+
(* exception_ident; *)
359359
for_direction;
360360
expression_desc;
361361
statement_desc;
@@ -364,7 +364,12 @@ and deps_program =
364364
finish_ident_expression;
365365
property_map;
366366
length_object;
367-
for_ident;
367+
(* for_ident; *)
368368
required_modules;
369369
case_clause
370-
|] }]
370+
|] }]
371+
(*
372+
FIXME: customize for each code generator
373+
for each code generator, we can provide a white-list
374+
so that we can achieve the optimal
375+
*)

jscomp/core/js_pass_scope.ml

Lines changed: 146 additions & 157 deletions
Original file line numberDiff line numberDiff line change
@@ -99,118 +99,100 @@
9999
done
100100
]}
101101
*)
102-
103-
let scope_pass =
104-
object(self)
105-
inherit Js_fold.fold as super
106-
107-
val defined_idents = Set_ident.empty
108-
109-
(** [used_idents]
110-
does not contain locally defined idents *)
111-
val used_idents = Set_ident.empty
112-
(** we need collect mutable values and loop defined varaibles *)
113-
val loop_mutable_values = Set_ident.empty
114-
115-
val mutable_values = Set_ident.empty
116-
117-
val closured_idents = Set_ident.empty
118-
119-
(** check if in loop or not *)
120-
val in_loop = false
121-
122-
(* method get_in_loop = in_loop *)
123-
124-
method get_defined_idents = defined_idents
125-
126-
method get_used_idents = used_idents
127-
128-
method get_loop_mutable_values = loop_mutable_values
129-
130-
(* method get_mutable_values = mutable_values *)
131-
132-
method get_closured_idents = closured_idents
133-
134-
method with_in_loop b =
135-
if b = in_loop then self
136-
else {< in_loop = b >}
137-
(* Since it's loop mutable variable, for sure
138-
it is mutable variable
139-
*)
140-
method with_loop_mutable_values b =
141-
{< loop_mutable_values = b >}
142-
143-
method add_loop_mutable_variable id =
144-
{< loop_mutable_values = Set_ident.add loop_mutable_values id;
145-
mutable_values = Set_ident.add mutable_values id
146-
>}
147-
148-
method add_mutable_variable id =
149-
{< mutable_values = Set_ident.add mutable_values id >}
150-
151-
method add_defined_ident ident =
152-
{< defined_idents = Set_ident.add defined_idents ident >}
153-
method add_used_ident ident =
154-
{< used_idents = Set_ident.add used_idents ident >}
155-
method! expression x =
156-
match x.expression_desc with
157-
| Fun (_method_, params, block , env) ->
158-
(* Function is the only place to introduce a new scope in
159-
ES5
160-
TODO: check
161-
{[ try .. catch(exn) {.. }]}
162-
what's the scope of exn
163-
*)
164-
(* Note that [used_idents] is not complete
165-
it ignores some locally defined idents *)
166-
let param_set = Set_ident.of_list params in
167-
let obj = {<defined_idents = Set_ident.empty;
168-
(** pass [empty]
169-
so that we can check which parameter was actually used *)
170-
used_idents = Set_ident.empty ;
171-
in_loop = false;
172-
loop_mutable_values = Set_ident.empty;
173-
mutable_values = Set_ident.of_list (Js_fun_env.get_mutable_params params env) ;
174-
closured_idents = Set_ident.empty; (* think about nested function*)
175-
>} # block block in
176-
let defined_idents', used_idents' =
177-
obj#get_defined_idents, obj#get_used_idents in
178-
(* mark which param is used *)
179-
params |> List.iteri
180-
(fun i v ->
181-
if not (Set_ident.mem used_idents' v) then
182-
Js_fun_env.mark_unused env i) ;
183-
let closured_idents' = (* pass param_set down *)
184-
Set_ident.(diff used_idents' (union defined_idents' param_set )) in
185-
186-
(* Noe that we don't know which variables are exactly mutable yet ..
187-
due to the recursive thing
188-
*)
189-
Js_fun_env.set_unbounded env closured_idents' ;
190-
let lexical_scopes = Set_ident.(inter closured_idents' self#get_loop_mutable_values) in
191-
Js_fun_env.set_lexical_scope env lexical_scopes;
192-
(* tailcall , note that these varibles are used in another pass *)
193-
{< used_idents =
194-
Set_ident.union used_idents closured_idents' ;
195-
(* There is a bug in ocaml -dsource*)
196-
closured_idents = Set_ident.union closured_idents closured_idents'
197-
>}
198-
| _ ->
199-
let obj = super#expression x in
200-
match Js_block_runtime.check_additional_id x with
201-
| None -> obj
202-
| Some id ->
203-
obj#add_used_ident id
204-
(* TODO: most variables are immutable *)
205-
206-
method! variable_declaration x =
102+
type state = {
103+
defined_idents : Set_ident.t;
104+
used_idents : Set_ident.t;
105+
loop_mutable_values : Set_ident.t;
106+
mutable_values : Set_ident.t;
107+
closured_idents : Set_ident.t;
108+
in_loop : bool;
109+
}
110+
111+
let init_state = {
112+
defined_idents = Set_ident.empty;
113+
used_idents = Set_ident.empty;
114+
loop_mutable_values = Set_ident.empty;
115+
mutable_values = Set_ident.empty;
116+
closured_idents = Set_ident.empty;
117+
in_loop = false;
118+
}
119+
let with_in_loop (st:state) b =
120+
if b = st.in_loop then st
121+
else {st with in_loop = b}
122+
let add_loop_mutable_variable (st : state) id =
123+
{ st with
124+
loop_mutable_values = Set_ident.add st.loop_mutable_values id;
125+
mutable_values = Set_ident.add st.mutable_values id
126+
}
127+
let add_mutable_variable (st: state) id =
128+
{
129+
st with
130+
mutable_values = Set_ident.add st.mutable_values id
131+
}
132+
let add_defined_ident (st : state) id = {
133+
st with
134+
defined_idents = Set_ident.add st.defined_idents id
135+
}
136+
let add_used_ident (st : state) id = {
137+
st with used_idents = Set_ident.add st.used_idents id
138+
}
139+
140+
141+
let super = Js_record_fold.super
142+
let record_scope_pass = {
143+
super with
144+
expression = begin fun self state x ->
145+
match x.expression_desc with
146+
| Fun (_method_, params, block , env) ->
147+
(* Function is the only place to introduce a new scope in
148+
ES5
149+
TODO: check
150+
{[ try .. catch(exn) {.. }]}
151+
what's the scope of exn
152+
*)
153+
(* Note that [used_idents] is not complete
154+
it ignores some locally defined idents *)
155+
let param_set = Set_ident.of_list params in
156+
let {defined_idents = defined_idents' ; used_idents = used_idents' } = self.block self {
157+
init_state with
158+
mutable_values = Set_ident.of_list (Js_fun_env.get_mutable_params params env) ;
159+
} block in
160+
(* let defined_idents', used_idents' =
161+
obj#get_defined_idents, obj#get_used_idents in *)
162+
(* mark which param is used *)
163+
params |> List.iteri
164+
(fun i v ->
165+
if not (Set_ident.mem used_idents' v) then
166+
Js_fun_env.mark_unused env i) ;
167+
let closured_idents' = (* pass param_set down *)
168+
Set_ident.(diff used_idents' (union defined_idents' param_set )) in
169+
170+
(* Noe that we don't know which variables are exactly mutable yet ..
171+
due to the recursive thing
172+
*)
173+
Js_fun_env.set_unbounded env closured_idents' ;
174+
let lexical_scopes = Set_ident.(inter closured_idents' state.loop_mutable_values) in
175+
Js_fun_env.set_lexical_scope env lexical_scopes;
176+
(* tailcall , note that these varibles are used in another pass *)
177+
{state with used_idents =
178+
Set_ident.union state.used_idents closured_idents' ;
179+
(* There is a bug in ocaml -dsource*)
180+
closured_idents = Set_ident.union state.closured_idents closured_idents'
181+
}
182+
| _ ->
183+
let obj = super.expression self state x in
184+
match Js_block_runtime.check_additional_id x with
185+
| None -> obj
186+
| Some id -> add_used_ident obj id
187+
end;
188+
variable_declaration = begin fun self state x ->
207189
match x with
208190
| { ident ; value; property } ->
209191
let obj =
210-
(match in_loop, property with
192+
add_defined_ident (match state.in_loop, property with
211193
| true, Variable
212194
->
213-
self#add_loop_mutable_variable ident
195+
add_loop_mutable_variable state ident
214196
| true, (Strict | StrictOpt | Alias)
215197
(* Not real true immutable in javascript
216198
since it's in the loop
@@ -219,7 +201,7 @@ let scope_pass =
219201
*)
220202
->
221203
begin match value with
222-
| None -> self#add_loop_mutable_variable ident
204+
| None -> add_loop_mutable_variable state ident
223205
(* TODO: Check why assertion failure *)
224206
(* self#add_loop_mutable_variable ident *) (* assert false *)
225207
| Some x
@@ -234,7 +216,7 @@ let scope_pass =
234216
*)
235217
match x.expression_desc with
236218
| Fun _ | Number _ | Str _
237-
-> self
219+
-> state
238220
| _ ->
239221
(* if Set_ident.(is_empty @@ *)
240222
(* inter self#get_mutable_values *)
@@ -245,80 +227,87 @@ let scope_pass =
245227
(* (\* FIXME: still need to check expression is pure or not*\) *)
246228
(* self *)
247229
(* else *)
248-
self#add_loop_mutable_variable ident
230+
add_loop_mutable_variable state ident
249231
end
250232
| false, Variable
251233
->
252-
self#add_mutable_variable ident
234+
add_mutable_variable state ident
253235
| false, (Strict | StrictOpt | Alias)
254-
-> self
255-
)#add_defined_ident ident
236+
-> state
237+
) ident
256238
in
257239
begin match value with
258240
| None -> obj
259-
| Some x -> obj # expression x
241+
| Some x -> self.expression self obj x
260242
end
261-
262-
263-
method! statement x =
243+
end;
244+
statement = begin fun self state x ->
264245
match x.statement_desc with
265-
| ForRange (_,_, loop_id, _,_,a_env) as y -> (* TODO: simplify definition of For *)
266-
let obj =
267-
{< in_loop = true ;
268-
loop_mutable_values = Set_ident.singleton loop_id ;
269-
used_idents = Set_ident.empty; (* TODO: if unused, can we generate better code? *)
270-
defined_idents = Set_ident.singleton loop_id ;
271-
closured_idents = Set_ident.empty (* Think about nested for blocks *)
272-
(* Invariant: Finish id is never used *)
273-
>}
274-
# statement_desc y in
246+
| ForRange (_,_, loop_id, _,_,a_env) -> (* TODO: simplify definition of For *)
247+
let {defined_idents = defined_idents'; used_idents = used_idents'; closured_idents = closured_idents'} =
275248

276-
let defined_idents', used_idents', closured_idents' =
277-
obj#get_defined_idents, obj#get_used_idents, obj#get_closured_idents in
249+
super.statement self { in_loop = true ;
250+
loop_mutable_values = Set_ident.singleton loop_id ;
251+
used_idents = Set_ident.empty; (* TODO: if unused, can we generate better code? *)
252+
defined_idents = Set_ident.singleton loop_id ;
253+
closured_idents = Set_ident.empty ;(* Think about nested for blocks *)
254+
(* Invariant: Finish id is never used *)
255+
mutable_values = state.mutable_values
256+
} x in (* CHECK*)
278257

258+
(* let defined_idents', used_idents', closured_idents' =
259+
obj#get_defined_idents, obj#get_used_idents, obj#get_closured_idents in *)
279260

280-
let lexical_scope = Set_ident.(inter (diff closured_idents' defined_idents') self#get_loop_mutable_values) in
261+
262+
let lexical_scope = Set_ident.(inter (diff closured_idents' defined_idents') state.loop_mutable_values) in
281263
let () = Js_closure.set_lexical_scope a_env lexical_scope in
282264
(* set scope *)
283-
{< used_idents = Set_ident.union used_idents used_idents';
265+
{ state with
266+
used_idents = Set_ident.union state.used_idents used_idents';
284267
(* walk around ocaml -dsource bug
285268
{[
286269
Set_ident.(union used_idents used_idents)
287270
]}
288271
*)
289-
defined_idents = Set_ident.union defined_idents defined_idents';
272+
defined_idents = Set_ident.union state.defined_idents defined_idents';
290273
(* TODO: if we our generated code also follow lexical scope,
291274
this is not necessary ;
292275
[varaibles] are mutable or not is known at definition
293276
*)
294-
closured_idents = Set_ident.union closured_idents lexical_scope
295-
>}
277+
closured_idents = Set_ident.union state.closured_idents lexical_scope
278+
}
296279

297280
| While (_label,pred,body, _env) ->
298-
(((self#expression pred)#with_in_loop true) # block body )
299-
#with_in_loop (in_loop)
281+
with_in_loop (self.block self (with_in_loop (self.expression self state pred) true) body )
282+
(state.in_loop)
300283
| _ ->
301-
super#statement x
302-
303-
method! exception_ident x =
304-
(* we can not simply skip it, since it can be used
305-
TODO: check loop exception
306-
(loop {
307-
excption(i){
308-
() => {i}
309-
}
310-
})
311-
*)
312-
{< used_idents = Set_ident.add used_idents x ;
313-
defined_idents = Set_ident.add defined_idents x
314-
>}
315-
method! for_ident x = {< loop_mutable_values = Set_ident.add loop_mutable_values x >}
284+
super.statement self state x
285+
end;
286+
287+
288+
exception_ident = begin fun _ state x ->
289+
(* we can not simply skip it, since it can be used
290+
TODO: check loop exception
291+
(loop {
292+
excption(i){
293+
() => {i}
294+
}
295+
})
296+
*)
297+
{state with used_idents = Set_ident.add state.used_idents x ;
298+
defined_idents = Set_ident.add state.defined_idents x
299+
}
300+
end;
301+
for_ident = begin fun _ state x -> {state with loop_mutable_values = Set_ident.add state.loop_mutable_values x } end;
302+
303+
ident = begin fun _ state x ->
304+
if Set_ident.mem state.defined_idents x then
305+
state
306+
else {state with used_idents = Set_ident.add state.used_idents x }
307+
end
308+
}
316309

317-
method! ident x =
318-
if Set_ident.mem defined_idents x then
319-
self
320-
else {< used_idents = Set_ident.add used_idents x >}
321-
end
322310

323311
let program js =
324-
(scope_pass # program js ) # get_loop_mutable_values
312+
(record_scope_pass.program record_scope_pass init_state js).loop_mutable_values
313+
(* (scope_pass # program js ) # get_loop_mutable_values *)

0 commit comments

Comments
 (0)