22
22
* along with this program; if not, write to the Free Software
23
23
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *)
24
24
25
-
26
-
27
-
28
-
29
-
30
25
(* When we inline a function call, if we don't do a beta-reduction immediately, there is
31
26
a chance that it is ignored, (we can not assume that each pass is robust enough)
32
27
@@ -41,11 +36,9 @@ module S = Js_stmt_make
41
36
(* module E = Js_exp_make *)
42
37
43
38
let super = Js_record_map. super
44
- let substitue_variables (map : Ident.t Map_ident.t ) = {
45
- super with ident = fun _ id ->
46
- Map_ident. find_default map id id
47
39
48
- }
40
+ let substitue_variables (map : Ident.t Map_ident.t ) =
41
+ { super with ident = (fun _ id -> Map_ident. find_default map id id) }
49
42
50
43
(* 1. recursive value ? let rec x = 1 :: x
51
44
non-terminating
@@ -64,32 +57,26 @@ let substitue_variables (map : Ident.t Map_ident.t) = {
64
57
if it is substitued, the assignment will align the value which is incorrect
65
58
*)
66
59
67
- let inline_call
68
- (immutable_list : bool list )
69
- params (args : J.expression list ) processed_blocks =
70
- let map, block =
71
- if immutable_list = [] then
72
- Ext_list. fold_right2
73
- params args (Map_ident. empty, processed_blocks)
74
- (fun param arg (map ,acc ) ->
75
- match arg.expression_desc with
76
- | Var (Id id ) ->
77
- Map_ident. add map param id, acc
78
- | _ ->
79
- map, S. define_variable ~kind: Variable param arg :: acc)
80
- else
81
- Ext_list. fold_right3
82
- params args immutable_list (Map_ident. empty, processed_blocks)
83
- (fun param arg mask (map ,acc ) ->
84
- match mask, arg.expression_desc with
85
- | true , Var (Id id ) ->
86
- Map_ident. add map param id, acc
87
- | _ ->
88
- map, S. define_variable ~kind: Variable param arg :: acc) in
89
- if Map_ident. is_empty map then block
90
- else
91
- let obj = substitue_variables map in
92
- obj.block obj block
60
+ let inline_call (immutable_list : bool list ) params (args : J.expression list )
61
+ processed_blocks =
62
+ let map, block =
63
+ if immutable_list = [] then
64
+ Ext_list. fold_right2 params args (Map_ident. empty, processed_blocks)
65
+ (fun param arg (map , acc ) ->
66
+ match arg.expression_desc with
67
+ | Var (Id id ) -> (Map_ident. add map param id, acc)
68
+ | _ -> (map, S. define_variable ~kind: Variable param arg :: acc))
69
+ else
70
+ Ext_list. fold_right3 params args immutable_list
71
+ (Map_ident. empty, processed_blocks) (fun param arg mask (map , acc ) ->
72
+ match (mask, arg.expression_desc) with
73
+ | true , Var (Id id ) -> (Map_ident. add map param id, acc)
74
+ | _ -> (map, S. define_variable ~kind: Variable param arg :: acc))
75
+ in
76
+ if Map_ident. is_empty map then block
77
+ else
78
+ let obj = substitue_variables map in
79
+ obj.block obj block
93
80
94
81
(* * There is a side effect when traversing dead code, since
95
82
we assume that substitue a node would mark a node as dead node,
@@ -117,108 +104,118 @@ let inline_call
117
104
while it is still called
118
105
*)
119
106
let super = Js_record_map. super
120
- let subst (export_set : Set_ident.t ) stats = {super with
121
-
122
- statement = (fun self st ->
123
- match st.statement_desc with
124
- | Variable
125
- {value = _ ;
126
- ident_info = {used_stats = Dead_pure }
127
- }
128
-
129
- ->
130
- S. block []
131
- | Variable { ident_info = {used_stats = Dead_non_pure } ;
132
- value = Some v ; _ }
133
- -> S. exp v
134
- | _ -> super.statement self st );
135
- variable_declaration = (fun self
136
- ({ident; value = _ ; property = _ ; ident_info = _ } as v ) ->
137
- (* TODO: replacement is a bit shaky, the problem is the lambda we stored is
138
- not consistent after we did some subsititution, and the dead code removal
139
- does rely on this (otherwise, when you do beta-reduction you have to regenerate names)
140
- *)
141
- let v = super . variable_declaration self v in
142
- Hash_ident. add stats ident v; (* see #278 before changes *)
143
- v);
144
- block = (fun self bs ->
145
- match bs with
146
- | ({statement_desc =
147
- Variable ({value =
148
- Some ({expression_desc = Fun _; _ } as v )
149
- } as vd) ; comment = _} as st) :: rest ->
150
- let is_export = Set_ident. mem export_set vd.ident in
151
- if is_export then
152
- self.statement self st :: self.block self rest
153
- else
154
- begin
155
- match Hash_ident. find_opt stats vd.ident with
156
- (* TODO: could be improved as [mem] * )
157
- | None ->
158
- if Js_analyzer. no_side_effect_expression v
159
- then S. exp v :: self.block self rest
160
- else self.block self rest
161
-
162
- | Some _ -> self.statement self st :: self.block self rest
163
- end
164
107
165
- | [{statement_desc =
166
- Return
167
- {expression_desc =
168
- Call ({expression_desc = Var (Id id)},args,_info)} } as st ]
169
- ->
170
- begin match Hash_ident. find_opt stats id with
171
-
172
- | Some ({ value =
173
- Some {expression_desc = Fun (false , params, block, env) ; comment = _};
174
- (* TODO: don't inline method tail call yet,
175
- [this] semantics are weird
176
- *)
177
- property = (Alias | StrictOpt | Strict );
178
- ident_info = {used_stats = Once_pure };
179
- ident = _
180
- } as v)
181
- when Ext_list. same_length params args
182
- ->
183
- Js_op_util. update_used_stats v.ident_info Dead_pure ;
184
- let no_tailcall = Js_fun_env. no_tailcall env in
185
- let processed_blocks = ( self.block self block) (* see #278 before changes*) in
186
- inline_call no_tailcall params args processed_blocks
187
- (* Ext_list.fold_right2
188
- params args processed_blocks
189
- (fun param arg acc ->
190
- S.define_variable ~kind:Variable param arg :: acc) *)
191
- (* Mark a function as dead means it will never be scanned,
192
- here we inline the function
193
- *)
194
-
195
- | (None | Some _ ) ->
196
- [self.statement self st ]
197
- end
198
-
199
- | [{statement_desc =
200
- Return {expression_desc =
201
- Call ({expression_desc = Fun (false , params, block, env)},args,_info)}} ]
202
-
203
- when Ext_list. same_length params args
204
- ->
205
- let no_tailcall = Js_fun_env. no_tailcall env in
206
- let processed_blocks = ( self.block self block) (* see #278 before changes*) in
207
- inline_call no_tailcall params args processed_blocks
208
- | x :: xs
209
- ->
210
- self.statement self x :: self.block self xs
211
- | []
212
- ->
213
- []
214
- )
215
- }
216
-
217
-
218
- let tailcall_inline (program : J.program ) =
108
+ let subst (export_set : Set_ident.t ) stats =
109
+ {
110
+ super with
111
+ statement =
112
+ (fun self st ->
113
+ match st.statement_desc with
114
+ | Variable { value = _ ; ident_info = { used_stats = Dead_pure } } ->
115
+ S. block []
116
+ | Variable
117
+ { ident_info = { used_stats = Dead_non_pure }; value = Some v; _ }
118
+ ->
119
+ S. exp v
120
+ | _ -> super.statement self st);
121
+ variable_declaration =
122
+ (fun self ({ ident; value = _ ; property = _ ; ident_info = _ } as v ) ->
123
+ (* TODO: replacement is a bit shaky, the problem is the lambda we stored is
124
+ not consistent after we did some subsititution, and the dead code removal
125
+ does rely on this (otherwise, when you do beta-reduction you have to regenerate names)
126
+ *)
127
+ let v = super.variable_declaration self v in
128
+ Hash_ident. add stats ident v;
129
+ (* see #278 before changes *)
130
+ v);
131
+ block =
132
+ (fun self bs ->
133
+ match bs with
134
+ | ({
135
+ statement_desc =
136
+ Variable
137
+ ({ value = Some ({ expression_desc = Fun _; _ } as v) } as vd);
138
+ comment = _;
139
+ } as st)
140
+ :: rest -> (
141
+ let is_export = Set_ident. mem export_set vd.ident in
142
+ if is_export then self.statement self st :: self.block self rest
143
+ else
144
+ match Hash_ident. find_opt stats vd.ident with
145
+ (* TODO: could be improved as [mem] * )
146
+ | None ->
147
+ if Js_analyzer. no_side_effect_expression v then
148
+ S. exp v :: self.block self rest
149
+ else self.block self rest
150
+ | Some _ -> self.statement self st :: self.block self rest)
151
+ | [
152
+ ({
153
+ statement_desc =
154
+ Return
155
+ {
156
+ expression_desc =
157
+ Call ({ expression_desc = Var (Id id) }, args, _info);
158
+ };
159
+ } as st);
160
+ ] -> (
161
+ match Hash_ident. find_opt stats id with
162
+ | Some
163
+ ({
164
+ value =
165
+ Some
166
+ {
167
+ expression_desc = Fun (false , params, block, env);
168
+ comment = _;
169
+ };
170
+ (* TODO: don't inline method tail call yet,
171
+ [this] semantics are weird
172
+ *)
173
+ property = Alias | StrictOpt | Strict ;
174
+ ident_info = { used_stats = Once_pure };
175
+ ident = _;
176
+ } as v)
177
+ when Ext_list. same_length params args ->
178
+ Js_op_util. update_used_stats v.ident_info Dead_pure ;
179
+ let no_tailcall = Js_fun_env. no_tailcall env in
180
+ let processed_blocks =
181
+ self.block self block
182
+ (* see #278 before changes*)
183
+ in
184
+ inline_call no_tailcall params args processed_blocks
185
+ (* Ext_list.fold_right2
186
+ params args processed_blocks
187
+ (fun param arg acc ->
188
+ S.define_variable ~kind:Variable param arg :: acc) *)
189
+ (* Mark a function as dead means it will never be scanned,
190
+ here we inline the function
191
+ *)
192
+ | None | Some _ -> [ self.statement self st ])
193
+ | [
194
+ {
195
+ statement_desc =
196
+ Return
197
+ {
198
+ expression_desc =
199
+ Call
200
+ ( { expression_desc = Fun (false , params, block, env) },
201
+ args,
202
+ _info );
203
+ };
204
+ };
205
+ ]
206
+ when Ext_list. same_length params args ->
207
+ let no_tailcall = Js_fun_env. no_tailcall env in
208
+ let processed_blocks =
209
+ self.block self block
210
+ (* see #278 before changes*)
211
+ in
212
+ inline_call no_tailcall params args processed_blocks
213
+ | x :: xs -> self.statement self x :: self.block self xs
214
+ | [] -> [] );
215
+ }
216
+
217
+ let tailcall_inline (program : J.program ) =
219
218
let stats = Js_pass_get_used. get_stats program in
220
219
let export_set = program.export_set in
221
- let obj = ( subst export_set stats ) in
220
+ let obj = subst export_set stats in
222
221
obj.program obj program
223
-
224
-
0 commit comments