@@ -179,38 +179,105 @@ merge(Compressor.prototype, {
179
179
180
180
AST_Node . DEFMETHOD ( "reset_opt_flags" , function ( compressor , rescan ) {
181
181
var reduce_vars = rescan && compressor . option ( "reduce_vars" ) ;
182
- var unsafe = compressor . option ( "unsafe" ) ;
182
+ var safe_ids = [ ] ;
183
+ push ( ) ;
183
184
var tw = new TreeWalker ( function ( node ) {
185
+ if ( ! ( node instanceof AST_Directive || node instanceof AST_Constant ) ) {
186
+ node . _squeezed = false ;
187
+ node . _optimized = false ;
188
+ }
184
189
if ( reduce_vars ) {
185
190
if ( node instanceof AST_Toplevel ) node . globals . each ( reset_def ) ;
186
191
if ( node instanceof AST_Scope ) node . variables . each ( reset_def ) ;
187
192
if ( node instanceof AST_SymbolRef ) {
188
193
var d = node . definition ( ) ;
189
194
d . references . push ( node ) ;
190
- if ( d . fixed && ( d . orig . length > 1 || isModified ( node , 0 ) ) ) {
195
+ if ( ! d . fixed || isModified ( node , 0 ) || ! is_safe ( d ) ) {
196
+ d . fixed = false ;
197
+ }
198
+ }
199
+ if ( node instanceof AST_VarDef ) {
200
+ var d = node . name . definition ( ) ;
201
+ if ( d . fixed === undefined ) {
202
+ d . fixed = node . value || make_node ( AST_Undefined , node ) ;
203
+ mark_as_safe ( d ) ;
204
+ } else {
191
205
d . fixed = false ;
192
206
}
193
207
}
194
- if ( node instanceof AST_Call && node . expression instanceof AST_Function ) {
195
- node . expression . argnames . forEach ( function ( arg , i ) {
196
- arg . definition ( ) . init = node . args [ i ] || make_node ( AST_Undefined , node ) ;
208
+ var iife ;
209
+ if ( node instanceof AST_Function
210
+ && ( iife = tw . parent ( ) ) instanceof AST_Call
211
+ && iife . expression === node ) {
212
+ node . argnames . forEach ( function ( arg , i ) {
213
+ var d = arg . definition ( ) ;
214
+ d . fixed = iife . args [ i ] || make_node ( AST_Undefined , iife ) ;
215
+ mark_as_safe ( d ) ;
197
216
} ) ;
198
217
}
199
- }
200
- if ( ! ( node instanceof AST_Directive || node instanceof AST_Constant ) ) {
201
- node . _squeezed = false ;
202
- node . _optimized = false ;
218
+ if ( node instanceof AST_If || node instanceof AST_DWLoop ) {
219
+ node . condition . walk ( tw ) ;
220
+ push ( ) ;
221
+ node . body . walk ( tw ) ;
222
+ pop ( ) ;
223
+ if ( node . alternative ) {
224
+ push ( ) ;
225
+ node . alternative . walk ( tw ) ;
226
+ pop ( ) ;
227
+ }
228
+ return true ;
229
+ }
230
+ if ( node instanceof AST_LabeledStatement ) {
231
+ push ( ) ;
232
+ node . body . walk ( tw ) ;
233
+ pop ( ) ;
234
+ return true ;
235
+ }
236
+ if ( node instanceof AST_For ) {
237
+ if ( node . init ) node . init . walk ( tw ) ;
238
+ push ( ) ;
239
+ if ( node . condition ) node . condition . walk ( tw ) ;
240
+ node . body . walk ( tw ) ;
241
+ if ( node . step ) node . step . walk ( tw ) ;
242
+ pop ( ) ;
243
+ return true ;
244
+ }
245
+ if ( node instanceof AST_ForIn ) {
246
+ if ( node . init instanceof AST_SymbolRef ) {
247
+ node . init . definition ( ) . fixed = false ;
248
+ }
249
+ node . object . walk ( tw ) ;
250
+ push ( ) ;
251
+ node . body . walk ( tw ) ;
252
+ pop ( ) ;
253
+ return true ;
254
+ }
203
255
}
204
256
} ) ;
205
257
this . walk ( tw ) ;
206
258
259
+ function mark_as_safe ( def ) {
260
+ safe_ids [ safe_ids . length - 1 ] [ def . id ] = true ;
261
+ }
262
+
263
+ function is_safe ( def ) {
264
+ for ( var i = safe_ids . length , id = def . id ; -- i >= 0 ; ) {
265
+ if ( safe_ids [ i ] [ id ] ) return true ;
266
+ }
267
+ }
268
+
269
+ function push ( ) {
270
+ safe_ids . push ( Object . create ( null ) ) ;
271
+ }
272
+
273
+ function pop ( ) {
274
+ safe_ids . pop ( ) ;
275
+ }
276
+
207
277
function reset_def ( def ) {
208
- def . fixed = true ;
278
+ def . fixed = undefined ;
209
279
def . references = [ ] ;
210
280
def . should_replace = undefined ;
211
- if ( unsafe && def . init ) {
212
- def . init . _evaluated = undefined ;
213
- }
214
281
}
215
282
216
283
function isModified ( node , level ) {
@@ -1263,14 +1330,14 @@ merge(Compressor.prototype, {
1263
1330
this . _evaluating = true ;
1264
1331
try {
1265
1332
var d = this . definition ( ) ;
1266
- if ( compressor . option ( "reduce_vars" ) && d . fixed && d . init ) {
1333
+ if ( compressor . option ( "reduce_vars" ) && d . fixed ) {
1267
1334
if ( compressor . option ( "unsafe" ) ) {
1268
- if ( d . init . _evaluated === undefined ) {
1269
- d . init . _evaluated = ev ( d . init , compressor ) ;
1335
+ if ( ! HOP ( d . fixed , "_evaluated" ) ) {
1336
+ d . fixed . _evaluated = ev ( d . fixed , compressor ) ;
1270
1337
}
1271
- return d . init . _evaluated ;
1338
+ return d . fixed . _evaluated ;
1272
1339
}
1273
- return ev ( d . init , compressor ) ;
1340
+ return ev ( d . fixed , compressor ) ;
1274
1341
}
1275
1342
} finally {
1276
1343
this . _evaluating = false ;
@@ -3046,9 +3113,9 @@ merge(Compressor.prototype, {
3046
3113
}
3047
3114
if ( compressor . option ( "evaluate" ) && compressor . option ( "reduce_vars" ) ) {
3048
3115
var d = self . definition ( ) ;
3049
- if ( d . fixed && d . init ) {
3116
+ if ( d . fixed ) {
3050
3117
if ( d . should_replace === undefined ) {
3051
- var init = d . init . evaluate ( compressor ) ;
3118
+ var init = d . fixed . evaluate ( compressor ) ;
3052
3119
if ( init . length > 1 ) {
3053
3120
var value = init [ 0 ] . print_to_string ( ) . length ;
3054
3121
var name = d . name . length ;
0 commit comments