compress.js 116 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769
  1. /***********************************************************************
  2. A JavaScript tokenizer / parser / beautifier / compressor.
  3. https://github.com/mishoo/UglifyJS
  4. -------------------------------- (C) ---------------------------------
  5. Author: Mihai Bazon
  6. <mihai.bazon@gmail.com>
  7. http://mihai.bazon.net/blog
  8. Distributed under the BSD license:
  9. Copyright 2012 (c) Mihai Bazon <mihai.bazon@gmail.com>
  10. Redistribution and use in source and binary forms, with or without
  11. modification, are permitted provided that the following conditions
  12. are met:
  13. * Redistributions of source code must retain the above
  14. copyright notice, this list of conditions and the following
  15. disclaimer.
  16. * Redistributions in binary form must reproduce the above
  17. copyright notice, this list of conditions and the following
  18. disclaimer in the documentation and/or other materials
  19. provided with the distribution.
  20. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
  21. EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  22. IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  23. PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
  24. LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
  25. OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  26. PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  27. PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  28. THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
  29. TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
  30. THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31. SUCH DAMAGE.
  32. ***********************************************************************/
  33. "use strict";
  34. function Compressor(options, false_by_default) {
  35. if (!(this instanceof Compressor))
  36. return new Compressor(options, false_by_default);
  37. TreeTransformer.call(this, this.before, this.after);
  38. this.options = defaults(options, {
  39. annotations : !false_by_default,
  40. arguments : !false_by_default,
  41. arrows : !false_by_default,
  42. assignments : !false_by_default,
  43. awaits : !false_by_default,
  44. booleans : !false_by_default,
  45. collapse_vars : !false_by_default,
  46. comparisons : !false_by_default,
  47. conditionals : !false_by_default,
  48. dead_code : !false_by_default,
  49. default_values : !false_by_default,
  50. directives : !false_by_default,
  51. drop_console : false,
  52. drop_debugger : !false_by_default,
  53. evaluate : !false_by_default,
  54. expression : false,
  55. functions : !false_by_default,
  56. global_defs : false,
  57. hoist_exports : !false_by_default,
  58. hoist_funs : false,
  59. hoist_props : !false_by_default,
  60. hoist_vars : false,
  61. ie : false,
  62. if_return : !false_by_default,
  63. imports : !false_by_default,
  64. inline : !false_by_default,
  65. join_vars : !false_by_default,
  66. keep_fargs : false_by_default,
  67. keep_fnames : false,
  68. keep_infinity : false,
  69. loops : !false_by_default,
  70. merge_vars : !false_by_default,
  71. module : false,
  72. negate_iife : !false_by_default,
  73. objects : !false_by_default,
  74. optional_chains : !false_by_default,
  75. passes : 1,
  76. properties : !false_by_default,
  77. pure_funcs : null,
  78. pure_getters : !false_by_default && "strict",
  79. reduce_funcs : !false_by_default,
  80. reduce_vars : !false_by_default,
  81. rests : !false_by_default,
  82. sequences : !false_by_default,
  83. side_effects : !false_by_default,
  84. spreads : !false_by_default,
  85. strings : !false_by_default,
  86. switches : !false_by_default,
  87. templates : !false_by_default,
  88. top_retain : null,
  89. toplevel : !!(options && !options["expression"] && options["top_retain"]),
  90. typeofs : !false_by_default,
  91. unsafe : false,
  92. unsafe_comps : false,
  93. unsafe_Function : false,
  94. unsafe_math : false,
  95. unsafe_proto : false,
  96. unsafe_regexp : false,
  97. unsafe_undefined: false,
  98. unused : !false_by_default,
  99. varify : !false_by_default,
  100. webkit : false,
  101. yields : !false_by_default,
  102. }, true);
  103. var evaluate = this.options["evaluate"];
  104. this.eval_threshold = /eager/.test(evaluate) ? 1 / 0 : +evaluate;
  105. var global_defs = this.options["global_defs"];
  106. if (typeof global_defs == "object") for (var key in global_defs) {
  107. if (/^@/.test(key) && HOP(global_defs, key)) {
  108. global_defs[key.slice(1)] = parse(global_defs[key], { expression: true });
  109. }
  110. }
  111. if (this.options["inline"] === true) this.options["inline"] = 4;
  112. this.drop_fargs = this.options["keep_fargs"] ? return_false : function(lambda, parent) {
  113. if (lambda.length_read) return false;
  114. var name = lambda.name;
  115. if (!name) return parent && parent.TYPE == "Call" && parent.expression === lambda;
  116. if (name.fixed_value() !== lambda) return false;
  117. var def = name.definition();
  118. if (def.direct_access) return false;
  119. var escaped = def.escaped;
  120. return escaped && escaped.depth != 1;
  121. };
  122. if (this.options["module"]) this.directives["use strict"] = true;
  123. var pure_funcs = this.options["pure_funcs"];
  124. if (typeof pure_funcs == "function") {
  125. this.pure_funcs = pure_funcs;
  126. } else if (typeof pure_funcs == "string") {
  127. this.pure_funcs = function(node) {
  128. var expr;
  129. if (node instanceof AST_Call) {
  130. expr = node.expression;
  131. } else if (node instanceof AST_Template) {
  132. expr = node.tag;
  133. }
  134. return !(expr && pure_funcs === expr.print_to_string());
  135. };
  136. } else if (Array.isArray(pure_funcs)) {
  137. this.pure_funcs = function(node) {
  138. var expr;
  139. if (node instanceof AST_Call) {
  140. expr = node.expression;
  141. } else if (node instanceof AST_Template) {
  142. expr = node.tag;
  143. }
  144. return !(expr && member(expr.print_to_string(), pure_funcs));
  145. };
  146. } else {
  147. this.pure_funcs = return_true;
  148. }
  149. var sequences = this.options["sequences"];
  150. this.sequences_limit = sequences == 1 ? 800 : sequences | 0;
  151. var top_retain = this.options["top_retain"];
  152. if (top_retain instanceof RegExp) {
  153. this.top_retain = function(def) {
  154. return top_retain.test(def.name);
  155. };
  156. } else if (typeof top_retain == "function") {
  157. this.top_retain = top_retain;
  158. } else if (top_retain) {
  159. if (typeof top_retain == "string") {
  160. top_retain = top_retain.split(/,/);
  161. }
  162. this.top_retain = function(def) {
  163. return member(def.name, top_retain);
  164. };
  165. }
  166. var toplevel = this.options["toplevel"];
  167. this.toplevel = typeof toplevel == "string" ? {
  168. funcs: /funcs/.test(toplevel),
  169. vars: /vars/.test(toplevel)
  170. } : {
  171. funcs: toplevel,
  172. vars: toplevel
  173. };
  174. }
  175. Compressor.prototype = new TreeTransformer(function(node, descend) {
  176. if (node._squeezed) return node;
  177. var is_scope = node instanceof AST_Scope;
  178. if (is_scope) {
  179. if (this.option("arrows") && is_arrow(node) && node.value) {
  180. node.body = [ node.first_statement() ];
  181. node.value = null;
  182. }
  183. node.hoist_properties(this);
  184. node.hoist_declarations(this);
  185. node.process_returns(this);
  186. }
  187. // Before https://github.com/mishoo/UglifyJS/pull/1602 AST_Node.optimize()
  188. // would call AST_Node.transform() if a different instance of AST_Node is
  189. // produced after OPT().
  190. // This corrupts TreeWalker.stack, which cause AST look-ups to malfunction.
  191. // Migrate and defer all children's AST_Node.transform() to below, which
  192. // will now happen after this parent AST_Node has been properly substituted
  193. // thus gives a consistent AST snapshot.
  194. descend(node, this);
  195. // Existing code relies on how AST_Node.optimize() worked, and omitting the
  196. // following replacement call would result in degraded efficiency of both
  197. // output and performance.
  198. descend(node, this);
  199. var opt = node.optimize(this);
  200. if (is_scope) {
  201. if (opt === node && !this.has_directive("use asm") && !opt.pinned()) {
  202. opt.drop_unused(this);
  203. if (opt.merge_variables(this)) opt.drop_unused(this);
  204. descend(opt, this);
  205. }
  206. if (this.option("arrows") && is_arrow(opt) && opt.body.length == 1) {
  207. var stat = opt.body[0];
  208. if (stat instanceof AST_Return) {
  209. opt.body.length = 0;
  210. opt.value = stat.value;
  211. }
  212. }
  213. }
  214. if (opt === node) opt._squeezed = true;
  215. return opt;
  216. });
  217. Compressor.prototype.option = function(key) {
  218. return this.options[key];
  219. };
  220. Compressor.prototype.exposed = function(def) {
  221. if (def.exported) return true;
  222. if (def.undeclared) return true;
  223. if (!(def.global || def.scope.resolve() instanceof AST_Toplevel)) return false;
  224. var toplevel = this.toplevel;
  225. return !all(def.orig, function(sym) {
  226. return toplevel[sym instanceof AST_SymbolDefun ? "funcs" : "vars"];
  227. });
  228. };
  229. Compressor.prototype.compress = function(node) {
  230. node = node.resolve_defines(this);
  231. node.hoist_exports(this);
  232. if (this.option("expression")) node.process_expression(true);
  233. var merge_vars = this.options.merge_vars;
  234. var passes = +this.options.passes || 1;
  235. var min_count = 1 / 0;
  236. var stopping = false;
  237. var mangle = { ie: this.option("ie") };
  238. for (var pass = 0; pass < passes; pass++) {
  239. node.figure_out_scope(mangle);
  240. if (pass > 0 || this.option("reduce_vars"))
  241. node.reset_opt_flags(this);
  242. this.options.merge_vars = merge_vars && (stopping || pass == passes - 1);
  243. node = node.transform(this);
  244. if (passes > 1) {
  245. var count = 0;
  246. node.walk(new TreeWalker(function() {
  247. count++;
  248. }));
  249. AST_Node.info("pass {pass}: last_count: {min_count}, count: {count}", {
  250. pass: pass,
  251. min_count: min_count,
  252. count: count,
  253. });
  254. if (count < min_count) {
  255. min_count = count;
  256. stopping = false;
  257. } else if (stopping) {
  258. break;
  259. } else {
  260. stopping = true;
  261. }
  262. }
  263. }
  264. if (this.option("expression")) node.process_expression(false);
  265. return node;
  266. };
  267. (function(OPT) {
  268. OPT(AST_Node, function(self) {
  269. return self;
  270. });
  271. AST_Toplevel.DEFMETHOD("hoist_exports", function(compressor) {
  272. if (!compressor.option("hoist_exports")) return;
  273. var body = this.body, props = [];
  274. for (var i = 0; i < body.length; i++) {
  275. var stat = body[i];
  276. if (stat instanceof AST_ExportDeclaration) {
  277. body[i] = stat = stat.body;
  278. if (stat instanceof AST_Definitions) {
  279. stat.definitions.forEach(function(defn) {
  280. defn.name.match_symbol(export_symbol, true);
  281. });
  282. } else {
  283. export_symbol(stat.name);
  284. }
  285. } else if (stat instanceof AST_ExportReferences) {
  286. body.splice(i--, 1);
  287. [].push.apply(props, stat.properties);
  288. }
  289. }
  290. if (props.length) body.push(make_node(AST_ExportReferences, this, { properties: props }));
  291. function export_symbol(sym) {
  292. if (!(sym instanceof AST_SymbolDeclaration)) return;
  293. var node = make_node(AST_SymbolExport, sym);
  294. node.alias = make_node(AST_String, node, { value: node.name });
  295. props.push(node);
  296. }
  297. });
  298. AST_Scope.DEFMETHOD("process_expression", function(insert, transform) {
  299. var self = this;
  300. var tt = new TreeTransformer(function(node) {
  301. if (insert) {
  302. if (node instanceof AST_Directive) node = make_node(AST_SimpleStatement, node, {
  303. body: make_node(AST_String, node),
  304. });
  305. if (node instanceof AST_SimpleStatement) {
  306. return transform ? transform(node) : make_node(AST_Return, node, { value: node.body });
  307. }
  308. } else if (node instanceof AST_Return) {
  309. if (transform) return transform(node);
  310. var value = node.value;
  311. if (value instanceof AST_String) return make_node(AST_Directive, value);
  312. return make_node(AST_SimpleStatement, node, {
  313. body: value || make_node(AST_UnaryPrefix, node, {
  314. operator: "void",
  315. expression: make_node(AST_Number, node, { value: 0 }),
  316. }),
  317. });
  318. }
  319. if (node instanceof AST_Block) {
  320. if (node instanceof AST_Lambda) {
  321. if (node !== self) return node;
  322. } else if (insert === "awaits" && node instanceof AST_Try) {
  323. if (node.bfinally) return node;
  324. }
  325. for (var index = node.body.length; --index >= 0;) {
  326. var stat = node.body[index];
  327. if (!is_declaration(stat, true)) {
  328. node.body[index] = stat.transform(tt);
  329. break;
  330. }
  331. }
  332. } else if (node instanceof AST_If) {
  333. node.body = node.body.transform(tt);
  334. if (node.alternative) node.alternative = node.alternative.transform(tt);
  335. } else if (node instanceof AST_With) {
  336. node.body = node.body.transform(tt);
  337. }
  338. return node;
  339. });
  340. self.transform(tt);
  341. });
  342. AST_Toplevel.DEFMETHOD("unwrap_expression", function() {
  343. var self = this;
  344. switch (self.body.length) {
  345. case 0:
  346. return make_node(AST_UnaryPrefix, self, {
  347. operator: "void",
  348. expression: make_node(AST_Number, self, { value: 0 }),
  349. });
  350. case 1:
  351. var stat = self.body[0];
  352. if (stat instanceof AST_Directive) return make_node(AST_String, stat);
  353. if (stat instanceof AST_SimpleStatement) return stat.body;
  354. default:
  355. return make_node(AST_Call, self, {
  356. expression: make_node(AST_Function, self, {
  357. argnames: [],
  358. body: self.body,
  359. }).init_vars(self, self),
  360. args: [],
  361. });
  362. }
  363. });
  364. AST_Node.DEFMETHOD("wrap_expression", function() {
  365. var self = this;
  366. if (!is_statement(self)) self = make_node(AST_SimpleStatement, self, { body: self });
  367. if (!(self instanceof AST_Toplevel)) self = make_node(AST_Toplevel, self, { body: [ self ] });
  368. return self;
  369. });
  370. function read_property(obj, node) {
  371. var key = node.get_property();
  372. if (key instanceof AST_Node) return;
  373. var value;
  374. if (obj instanceof AST_Array) {
  375. var elements = obj.elements;
  376. if (key == "length") return make_node_from_constant(elements.length, obj);
  377. if (typeof key == "number" && key in elements) value = elements[key];
  378. } else if (obj instanceof AST_Lambda) {
  379. if (key == "length") {
  380. obj.length_read = true;
  381. return make_node_from_constant(obj.argnames.length, obj);
  382. }
  383. } else if (obj instanceof AST_Object) {
  384. key = "" + key;
  385. var props = obj.properties;
  386. for (var i = props.length; --i >= 0;) {
  387. var prop = props[i];
  388. if (!can_hoist_property(prop)) return;
  389. if (!value && props[i].key === key) value = props[i].value;
  390. }
  391. }
  392. return value instanceof AST_SymbolRef && value.fixed_value() || value;
  393. }
  394. function is_read_only_fn(value, name) {
  395. if (value instanceof AST_Boolean) return native_fns.Boolean[name];
  396. if (value instanceof AST_Number) return native_fns.Number[name];
  397. if (value instanceof AST_String) return native_fns.String[name];
  398. if (name == "valueOf") return false;
  399. if (value instanceof AST_Array) return native_fns.Array[name];
  400. if (value instanceof AST_Lambda) return native_fns.Function[name];
  401. if (value instanceof AST_Object) return native_fns.Object[name];
  402. if (value instanceof AST_RegExp) return native_fns.RegExp[name] && !value.value.global;
  403. }
  404. function is_modified(compressor, tw, node, value, level, immutable, recursive) {
  405. var parent = tw.parent(level);
  406. if (compressor.option("unsafe") && parent instanceof AST_Dot && is_read_only_fn(value, parent.property)) {
  407. return;
  408. }
  409. var lhs = is_lhs(node, parent);
  410. if (lhs) return lhs;
  411. if (level == 0 && value && value.is_constant()) return;
  412. if (parent instanceof AST_Array) return is_modified(compressor, tw, parent, parent, level + 1);
  413. if (parent instanceof AST_Assign) switch (parent.operator) {
  414. case "=":
  415. return is_modified(compressor, tw, parent, value, level + 1, immutable, recursive);
  416. case "&&=":
  417. case "||=":
  418. case "??=":
  419. return is_modified(compressor, tw, parent, parent, level + 1);
  420. default:
  421. return;
  422. }
  423. if (parent instanceof AST_Binary) {
  424. if (!lazy_op[parent.operator]) return;
  425. return is_modified(compressor, tw, parent, parent, level + 1);
  426. }
  427. if (parent instanceof AST_Call) {
  428. return !immutable
  429. && parent.expression === node
  430. && !parent.is_expr_pure(compressor)
  431. && (!(value instanceof AST_LambdaExpression) || !(parent instanceof AST_New) && value.contains_this());
  432. }
  433. if (parent instanceof AST_Conditional) {
  434. if (parent.condition === node) return;
  435. return is_modified(compressor, tw, parent, parent, level + 1);
  436. }
  437. if (parent instanceof AST_ForEnumeration) return parent.init === node;
  438. if (parent instanceof AST_ObjectKeyVal) {
  439. if (parent.value !== node) return;
  440. var obj = tw.parent(level + 1);
  441. return is_modified(compressor, tw, obj, obj, level + 2);
  442. }
  443. if (parent instanceof AST_PropAccess) {
  444. if (parent.expression !== node) return;
  445. var prop = read_property(value, parent);
  446. return (!immutable || recursive) && is_modified(compressor, tw, parent, prop, level + 1);
  447. }
  448. if (parent instanceof AST_Sequence) {
  449. if (parent.tail_node() !== node) return;
  450. return is_modified(compressor, tw, parent, value, level + 1, immutable, recursive);
  451. }
  452. }
  453. function is_lambda(node) {
  454. return node instanceof AST_Class || node instanceof AST_Lambda;
  455. }
  456. function safe_for_extends(node) {
  457. return node instanceof AST_Class || node instanceof AST_Defun || node instanceof AST_Function;
  458. }
  459. function is_arguments(def) {
  460. return def.name == "arguments" && def.scope.uses_arguments;
  461. }
  462. function cross_scope(def, sym) {
  463. do {
  464. if (def === sym) return false;
  465. if (sym instanceof AST_Scope) return true;
  466. } while (sym = sym.parent_scope);
  467. }
  468. function can_drop_symbol(ref, compressor, keep_lambda) {
  469. var def = ref.redef || ref.definition();
  470. if (ref.in_arg && is_funarg(def)) return false;
  471. return all(def.orig, function(sym) {
  472. if (sym instanceof AST_SymbolConst || sym instanceof AST_SymbolLet) {
  473. if (sym instanceof AST_SymbolImport) return true;
  474. return compressor && safe_from_tdz(compressor, sym);
  475. }
  476. return !(keep_lambda && sym instanceof AST_SymbolLambda);
  477. });
  478. }
  479. function has_escaped(d, scope, node, parent) {
  480. if (parent instanceof AST_Assign) return parent.operator == "=" && parent.right === node;
  481. if (parent instanceof AST_Call) return parent.expression !== node || parent instanceof AST_New;
  482. if (parent instanceof AST_ClassField) return parent.value === node && !parent.static;
  483. if (parent instanceof AST_Exit) return parent.value === node && scope.resolve() !== d.scope.resolve();
  484. if (parent instanceof AST_VarDef) return parent.value === node;
  485. }
  486. function make_ref(ref, fixed) {
  487. var node = make_node(AST_SymbolRef, ref);
  488. node.fixed = fixed || make_node(AST_Undefined, ref);
  489. return node;
  490. }
  491. function replace_ref(resolve, fixed) {
  492. return function(node) {
  493. var ref = resolve(node);
  494. var node = make_ref(ref, fixed);
  495. var def = ref.definition();
  496. def.references.push(node);
  497. def.replaced++;
  498. return node;
  499. };
  500. }
  501. var RE_POSITIVE_INTEGER = /^(0|[1-9][0-9]*)$/;
  502. (function(def) {
  503. def(AST_Node, noop);
  504. function reset_def(tw, compressor, def) {
  505. def.assignments = 0;
  506. def.bool_return = 0;
  507. def.cross_loop = false;
  508. def.direct_access = false;
  509. def.drop_return = 0;
  510. def.escaped = [];
  511. def.first_decl = null;
  512. def.fixed = !def.const_redefs
  513. && !def.scope.pinned()
  514. && !compressor.exposed(def)
  515. && !(def.init instanceof AST_LambdaExpression && def.init !== def.scope)
  516. && def.init;
  517. def.reassigned = 0;
  518. def.recursive_refs = 0;
  519. def.references = [];
  520. def.single_use = undefined;
  521. }
  522. function reset_block_variables(tw, compressor, scope) {
  523. scope.variables.each(function(def) {
  524. reset_def(tw, compressor, def);
  525. });
  526. }
  527. function reset_variables(tw, compressor, scope) {
  528. scope.fn_defs = [];
  529. scope.variables.each(function(def) {
  530. reset_def(tw, compressor, def);
  531. var init = def.init;
  532. if (init instanceof AST_LambdaDefinition) {
  533. scope.fn_defs.push(init);
  534. init.safe_ids = null;
  535. }
  536. if (def.fixed === null) {
  537. def.safe_ids = tw.safe_ids;
  538. mark(tw, def);
  539. } else if (def.fixed) {
  540. tw.loop_ids[def.id] = tw.in_loop;
  541. mark(tw, def);
  542. }
  543. });
  544. scope.may_call_this = function() {
  545. scope.may_call_this = scope.contains_this() ? return_true : return_false;
  546. };
  547. if (scope.uses_arguments) scope.each_argname(function(node) {
  548. node.definition().last_ref = false;
  549. });
  550. if (compressor.option("ie")) scope.variables.each(function(def) {
  551. var d = def.orig[0].definition();
  552. if (d !== def) d.fixed = false;
  553. });
  554. }
  555. function safe_to_visit(tw, fn) {
  556. var marker = fn.safe_ids;
  557. return marker === undefined || marker === tw.safe_ids;
  558. }
  559. function walk_fn_def(tw, fn) {
  560. var was_scanning = tw.fn_scanning;
  561. tw.fn_scanning = fn;
  562. fn.walk(tw);
  563. tw.fn_scanning = was_scanning;
  564. }
  565. function revisit_fn_def(tw, fn) {
  566. fn.enclosed.forEach(function(d) {
  567. if (fn.variables.get(d.name) === d) return;
  568. if (safe_to_read(tw, d)) return;
  569. d.single_use = false;
  570. var fixed = d.fixed;
  571. if (typeof fixed == "function") fixed = fixed();
  572. if (fixed instanceof AST_Lambda) {
  573. var safe_ids = fixed.safe_ids;
  574. switch (safe_ids) {
  575. case null:
  576. case false:
  577. return;
  578. default:
  579. if (safe_ids && safe_ids.seq !== tw.safe_ids.seq) return;
  580. }
  581. }
  582. d.fixed = false;
  583. });
  584. }
  585. function mark_fn_def(tw, def, fn) {
  586. var marker = fn.safe_ids;
  587. if (marker === undefined) return;
  588. if (marker === false) return;
  589. if (fn.parent_scope.resolve().may_call_this === return_true) {
  590. if (member(fn, tw.fn_visited)) revisit_fn_def(tw, fn);
  591. } else if (marker) {
  592. var visited = member(fn, tw.fn_visited);
  593. if (marker === tw.safe_ids) {
  594. if (!visited) walk_fn_def(tw, fn);
  595. } else if (visited) {
  596. revisit_fn_def(tw, fn);
  597. } else {
  598. fn.safe_ids = false;
  599. }
  600. } else if (tw.fn_scanning && tw.fn_scanning !== def.scope.resolve()) {
  601. fn.safe_ids = false;
  602. } else {
  603. fn.safe_ids = tw.safe_ids;
  604. walk_fn_def(tw, fn);
  605. }
  606. }
  607. function pop_scope(tw, scope) {
  608. pop(tw);
  609. var fn_defs = scope.fn_defs;
  610. fn_defs.forEach(function(fn) {
  611. fn.safe_ids = tw.safe_ids;
  612. walk_fn_def(tw, fn);
  613. });
  614. fn_defs.forEach(function(fn) {
  615. fn.safe_ids = undefined;
  616. });
  617. scope.fn_defs = undefined;
  618. scope.may_call_this = undefined;
  619. }
  620. function push(tw, sequential, conditional) {
  621. var defined_ids = Object.create(tw.defined_ids);
  622. if (!sequential || conditional) defined_ids.seq = Object.create(null);
  623. tw.defined_ids = defined_ids;
  624. var safe_ids = Object.create(tw.safe_ids);
  625. if (!sequential) safe_ids.seq = {};
  626. if (conditional) safe_ids.cond = true;
  627. tw.safe_ids = safe_ids;
  628. }
  629. function pop(tw) {
  630. tw.defined_ids = Object.getPrototypeOf(tw.defined_ids);
  631. tw.safe_ids = Object.getPrototypeOf(tw.safe_ids);
  632. }
  633. function access(tw, def) {
  634. var seq = tw.defined_ids.seq;
  635. tw.defined_ids[def.id] = seq;
  636. seq[def.id] = true;
  637. }
  638. function assign(tw, def) {
  639. var seq = tw.defined_ids.seq;
  640. tw.assigned_ids[def.id] = seq;
  641. seq[def.id] = false;
  642. }
  643. function safe_to_access(tw, def) {
  644. var seq = tw.defined_ids.seq;
  645. var defined = tw.defined_ids[def.id];
  646. if (defined !== seq) return false;
  647. if (!defined[def.id]) return false;
  648. var assigned = tw.assigned_ids[def.id];
  649. return !assigned || assigned === seq;
  650. }
  651. function mark(tw, def) {
  652. tw.safe_ids[def.id] = {};
  653. }
  654. function push_ref(def, ref) {
  655. def.references.push(ref);
  656. if (def.last_ref !== false) def.last_ref = ref;
  657. }
  658. function safe_to_read(tw, def) {
  659. if (def.single_use == "m") return false;
  660. var safe = tw.safe_ids[def.id];
  661. if (safe) {
  662. var in_order = HOP(tw.safe_ids, def.id);
  663. if (!in_order) {
  664. var seq = tw.safe_ids.seq;
  665. if (!safe.read) {
  666. safe.read = seq;
  667. } else if (safe.read !== seq) {
  668. safe.read = true;
  669. }
  670. }
  671. if (def.fixed == null) {
  672. if (is_arguments(def)) return false;
  673. if (def.global && def.name == "arguments") return false;
  674. tw.loop_ids[def.id] = null;
  675. def.fixed = make_node(AST_Undefined, def.orig[0]);
  676. if (in_order) def.safe_ids = undefined;
  677. return true;
  678. }
  679. return !safe.assign || safe.assign === tw.safe_ids;
  680. }
  681. return def.fixed instanceof AST_LambdaDefinition;
  682. }
  683. function safe_to_assign(tw, def, declare) {
  684. if (!declare) {
  685. if (is_funarg(def) && def.scope.uses_arguments && !tw.has_directive("use strict")) return false;
  686. if (!all(def.orig, function(sym) {
  687. return !(sym instanceof AST_SymbolConst);
  688. })) return false;
  689. }
  690. if (def.fixed === undefined) return declare || all(def.orig, function(sym) {
  691. return !(sym instanceof AST_SymbolLet);
  692. });
  693. if (def.fixed === false || def.fixed === 0) return false;
  694. var safe = tw.safe_ids[def.id];
  695. if (def.safe_ids) {
  696. def.safe_ids[def.id] = false;
  697. def.safe_ids = undefined;
  698. return def.fixed === null || HOP(tw.safe_ids, def.id) && !safe.read;
  699. }
  700. if (!HOP(tw.safe_ids, def.id)) {
  701. if (!safe) return false;
  702. if (safe.read || tw.in_loop) {
  703. var scope = tw.find_parent(AST_BlockScope);
  704. if (scope instanceof AST_Class) return false;
  705. if (def.scope.resolve() !== scope.resolve()) return false;
  706. }
  707. safe.assign = safe.assign && safe.assign !== tw.safe_ids ? true : tw.safe_ids;
  708. }
  709. if (def.fixed != null && safe.read) {
  710. if (safe.read !== tw.safe_ids.seq) return false;
  711. if (tw.loop_ids[def.id] !== tw.in_loop) return false;
  712. }
  713. return safe_to_read(tw, def) && all(def.orig, function(sym) {
  714. return !(sym instanceof AST_SymbolLambda);
  715. });
  716. }
  717. function ref_once(compressor, def) {
  718. return compressor.option("unused")
  719. && !def.scope.pinned()
  720. && def.single_use !== false
  721. && def.references.length - def.recursive_refs == 1
  722. && !(is_funarg(def) && def.scope.uses_arguments);
  723. }
  724. function is_immutable(value) {
  725. if (!value) return false;
  726. if (value instanceof AST_Assign) {
  727. var op = value.operator;
  728. return op == "=" ? is_immutable(value.right) : !lazy_op[op.slice(0, -1)];
  729. }
  730. if (value instanceof AST_Sequence) return is_immutable(value.tail_node());
  731. return value.is_constant() || is_lambda(value) || value instanceof AST_ObjectIdentity;
  732. }
  733. function value_in_use(node, parent) {
  734. if (parent instanceof AST_Array) return true;
  735. if (parent instanceof AST_Binary) return lazy_op[parent.operator];
  736. if (parent instanceof AST_Conditional) return parent.condition !== node;
  737. if (parent instanceof AST_Sequence) return parent.tail_node() === node;
  738. if (parent instanceof AST_Spread) return true;
  739. }
  740. function mark_escaped(tw, d, scope, node, value, level, depth) {
  741. var parent = tw.parent(level);
  742. if (value && value.is_constant()) return;
  743. if (has_escaped(d, scope, node, parent)) {
  744. d.escaped.push(parent);
  745. if (depth > 1 && !(value && value.is_constant_expression(scope))) depth = 1;
  746. if (!d.escaped.depth || d.escaped.depth > depth) d.escaped.depth = depth;
  747. if (d.scope.resolve() !== scope.resolve()) d.escaped.cross_scope = true;
  748. if (d.fixed) d.fixed.escaped = d.escaped;
  749. return;
  750. } else if (value_in_use(node, parent)) {
  751. mark_escaped(tw, d, scope, parent, parent, level + 1, depth);
  752. } else if (parent instanceof AST_ObjectKeyVal && parent.value === node) {
  753. var obj = tw.parent(level + 1);
  754. mark_escaped(tw, d, scope, obj, obj, level + 2, depth);
  755. } else if (parent instanceof AST_PropAccess && parent.expression === node) {
  756. value = read_property(value, parent);
  757. mark_escaped(tw, d, scope, parent, value, level + 1, depth + 1);
  758. if (value) return;
  759. }
  760. if (level > 0) return;
  761. if (parent instanceof AST_Call && parent.expression === node) return;
  762. if (parent instanceof AST_Sequence && parent.tail_node() !== node) return;
  763. if (parent instanceof AST_SimpleStatement) return;
  764. if (parent instanceof AST_Unary && !unary_side_effects[parent.operator]) return;
  765. d.direct_access = true;
  766. if (d.fixed) d.fixed.direct_access = true;
  767. }
  768. function mark_assignment_to_arguments(node) {
  769. if (!(node instanceof AST_Sub)) return;
  770. var expr = node.expression;
  771. if (!(expr instanceof AST_SymbolRef)) return;
  772. var def = expr.definition();
  773. if (!is_arguments(def)) return;
  774. var key = node.property;
  775. if (key.is_constant()) key = key.value;
  776. if (!(key instanceof AST_Node) && !RE_POSITIVE_INTEGER.test(key)) return;
  777. def.reassigned++;
  778. (key instanceof AST_Node ? def.scope.argnames : [ def.scope.argnames[key] ]).forEach(function(argname) {
  779. if (argname instanceof AST_SymbolFunarg) argname.definition().fixed = false;
  780. });
  781. }
  782. function make_fixed(save, fn) {
  783. var prev_save, prev_value;
  784. return function() {
  785. var current = save();
  786. if (prev_save !== current) {
  787. prev_save = current;
  788. prev_value = fn(current);
  789. }
  790. return prev_value;
  791. };
  792. }
  793. function make_fixed_default(compressor, node, save) {
  794. var prev_save, prev_seq;
  795. return function() {
  796. if (prev_seq === node) return node;
  797. var current = save();
  798. var ev = fuzzy_eval(compressor, current, true);
  799. if (ev instanceof AST_Node) {
  800. prev_seq = node;
  801. } else if (prev_save !== current) {
  802. prev_save = current;
  803. prev_seq = ev === undefined ? make_sequence(node, [ current, node.value ]) : current;
  804. }
  805. return prev_seq;
  806. };
  807. }
  808. function scan_declaration(tw, compressor, lhs, fixed, visit) {
  809. var scanner = new TreeWalker(function(node) {
  810. if (node instanceof AST_DefaultValue) {
  811. reset_flags(node);
  812. push(tw, true, true);
  813. node.value.walk(tw);
  814. pop(tw);
  815. var save = fixed;
  816. if (save) fixed = make_fixed_default(compressor, node, save);
  817. node.name.walk(scanner);
  818. fixed = save;
  819. return true;
  820. }
  821. if (node instanceof AST_DestructuredArray) {
  822. reset_flags(node);
  823. var save = fixed;
  824. node.elements.forEach(function(node, index) {
  825. if (node instanceof AST_Hole) return reset_flags(node);
  826. if (save) fixed = make_fixed(save, function(value) {
  827. return make_node(AST_Sub, node, {
  828. expression: value,
  829. property: make_node(AST_Number, node, { value: index }),
  830. });
  831. });
  832. node.walk(scanner);
  833. });
  834. if (node.rest) {
  835. var fixed_node;
  836. if (save) fixed = compressor.option("rests") && make_fixed(save, function(value) {
  837. if (!(value instanceof AST_Array)) return node;
  838. for (var i = 0, len = node.elements.length; i < len; i++) {
  839. if (value.elements[i] instanceof AST_Spread) return node;
  840. }
  841. if (!fixed_node) fixed_node = make_node(AST_Array, node, {});
  842. fixed_node.elements = value.elements.slice(len);
  843. return fixed_node;
  844. });
  845. node.rest.walk(scanner);
  846. }
  847. fixed = save;
  848. return true;
  849. }
  850. if (node instanceof AST_DestructuredObject) {
  851. reset_flags(node);
  852. var save = fixed;
  853. node.properties.forEach(function(node) {
  854. reset_flags(node);
  855. if (node.key instanceof AST_Node) {
  856. push(tw);
  857. node.key.walk(tw);
  858. pop(tw);
  859. }
  860. if (save) fixed = make_fixed(save, function(value) {
  861. var key = node.key;
  862. var type = AST_Sub;
  863. if (typeof key == "string") {
  864. if (is_identifier_string(key)) {
  865. type = AST_Dot;
  866. } else {
  867. key = make_node_from_constant(key, node);
  868. }
  869. }
  870. return make_node(type, node, {
  871. expression: value,
  872. property: key,
  873. });
  874. });
  875. node.value.walk(scanner);
  876. });
  877. if (node.rest) {
  878. fixed = false;
  879. node.rest.walk(scanner);
  880. }
  881. fixed = save;
  882. return true;
  883. }
  884. visit(node, fixed, function() {
  885. var save_len = tw.stack.length;
  886. for (var i = 0, len = scanner.stack.length - 1; i < len; i++) {
  887. tw.stack.push(scanner.stack[i]);
  888. }
  889. node.walk(tw);
  890. tw.stack.length = save_len;
  891. });
  892. return true;
  893. });
  894. lhs.walk(scanner);
  895. }
  896. function reduce_iife(tw, descend, compressor) {
  897. var fn = this;
  898. fn.inlined = false;
  899. var iife = tw.parent();
  900. var sequential = !is_async(fn) && !is_generator(fn);
  901. var hit = !sequential;
  902. var aborts = false;
  903. fn.walk(new TreeWalker(function(node) {
  904. if (hit) return aborts = true;
  905. if (node instanceof AST_Return) return hit = true;
  906. if (node instanceof AST_Scope && node !== fn) return true;
  907. }));
  908. if (aborts) push(tw, sequential);
  909. reset_variables(tw, compressor, fn);
  910. // Virtually turn IIFE parameters into variable definitions:
  911. // (function(a,b) {...})(c,d) ---> (function() {var a=c,b=d; ...})()
  912. // So existing transformation rules can work on them.
  913. var safe = !fn.uses_arguments || tw.has_directive("use strict");
  914. fn.argnames.forEach(function(argname, i) {
  915. var value = iife.args[i];
  916. scan_declaration(tw, compressor, argname, function() {
  917. var j = fn.argnames.indexOf(argname);
  918. var arg = j < 0 ? value : iife.args[j];
  919. if (arg instanceof AST_Sequence && arg.expressions.length < 2) arg = arg.expressions[0];
  920. return arg || make_node(AST_Undefined, iife);
  921. }, visit);
  922. });
  923. var rest = fn.rest, fixed_node;
  924. if (rest) scan_declaration(tw, compressor, rest, compressor.option("rests") && function() {
  925. if (fn.rest !== rest) return rest;
  926. if (!fixed_node) fixed_node = make_node(AST_Array, fn, {});
  927. fixed_node.elements = iife.args.slice(fn.argnames.length);
  928. return fixed_node;
  929. }, visit);
  930. walk_lambda(fn, tw);
  931. var defined_ids = tw.defined_ids;
  932. var safe_ids = tw.safe_ids;
  933. pop_scope(tw, fn);
  934. if (!aborts) {
  935. tw.defined_ids = defined_ids;
  936. tw.safe_ids = safe_ids;
  937. }
  938. return true;
  939. function visit(node, fixed) {
  940. var d = node.definition();
  941. if (!d.first_decl && d.references.length == 0) d.first_decl = node;
  942. if (fixed && safe && d.fixed === undefined) {
  943. mark(tw, d);
  944. tw.loop_ids[d.id] = tw.in_loop;
  945. d.fixed = fixed;
  946. d.fixed.assigns = [ node ];
  947. } else {
  948. d.fixed = false;
  949. }
  950. }
  951. }
  952. def(AST_Assign, function(tw, descend, compressor) {
  953. var node = this;
  954. var left = node.left;
  955. var right = node.right;
  956. var ld = left instanceof AST_SymbolRef && left.definition();
  957. var scan = ld || left instanceof AST_Destructured;
  958. switch (node.operator) {
  959. case "=":
  960. if (left.equals(right) && !left.has_side_effects(compressor)) {
  961. right.walk(tw);
  962. walk_prop(left);
  963. return true;
  964. }
  965. if (ld && right instanceof AST_LambdaExpression) {
  966. walk_assign();
  967. right.parent_scope.resolve().fn_defs.push(right);
  968. right.safe_ids = null;
  969. if (!ld.fixed || !node.write_only || tw.safe_ids.cond) mark_fn_def(tw, ld, right);
  970. return true;
  971. }
  972. if (scan) {
  973. right.walk(tw);
  974. walk_assign();
  975. return true;
  976. }
  977. mark_assignment_to_arguments(left);
  978. return;
  979. case "&&=":
  980. case "||=":
  981. case "??=":
  982. var lazy = true;
  983. default:
  984. if (!scan) {
  985. mark_assignment_to_arguments(left);
  986. return walk_lazy();
  987. }
  988. assign(tw, ld);
  989. ld.assignments++;
  990. var fixed = ld.fixed;
  991. if (is_modified(compressor, tw, node, node, 0)) {
  992. ld.fixed = false;
  993. return walk_lazy();
  994. }
  995. var safe = safe_to_read(tw, ld);
  996. if (lazy) push(tw, true, true);
  997. right.walk(tw);
  998. if (lazy) pop(tw);
  999. if (safe && !left.in_arg && safe_to_assign(tw, ld)) {
  1000. push_ref(ld, left);
  1001. mark(tw, ld);
  1002. if (ld.single_use) ld.single_use = false;
  1003. left.fixed = ld.fixed = function() {
  1004. return make_node(AST_Binary, node, {
  1005. operator: node.operator.slice(0, -1),
  1006. left: make_ref(left, fixed),
  1007. right: node.right,
  1008. });
  1009. };
  1010. left.fixed.assigns = !fixed || !fixed.assigns ? [ ld.orig[0] ] : fixed.assigns.slice();
  1011. left.fixed.assigns.push(node);
  1012. left.fixed.to_binary = replace_ref(function(node) {
  1013. return node.left;
  1014. }, fixed);
  1015. } else {
  1016. left.walk(tw);
  1017. ld.fixed = false;
  1018. }
  1019. return true;
  1020. }
  1021. function walk_prop(lhs) {
  1022. reset_flags(lhs);
  1023. if (lhs instanceof AST_Dot) {
  1024. walk_prop(lhs.expression);
  1025. } else if (lhs instanceof AST_Sub) {
  1026. walk_prop(lhs.expression);
  1027. lhs.property.walk(tw);
  1028. } else if (lhs instanceof AST_SymbolRef) {
  1029. var d = lhs.definition();
  1030. push_ref(d, lhs);
  1031. if (d.fixed) {
  1032. lhs.fixed = d.fixed;
  1033. if (lhs.fixed.assigns) {
  1034. lhs.fixed.assigns.push(node);
  1035. } else {
  1036. lhs.fixed.assigns = [ node ];
  1037. }
  1038. }
  1039. } else {
  1040. lhs.walk(tw);
  1041. }
  1042. }
  1043. function walk_assign() {
  1044. var recursive = ld && recursive_ref(tw, ld);
  1045. var modified = is_modified(compressor, tw, node, right, 0, is_immutable(right), recursive);
  1046. scan_declaration(tw, compressor, left, function() {
  1047. return node.right;
  1048. }, function(sym, fixed, walk) {
  1049. if (!(sym instanceof AST_SymbolRef)) {
  1050. mark_assignment_to_arguments(sym);
  1051. walk();
  1052. return;
  1053. }
  1054. var d = sym.definition();
  1055. assign(tw, d);
  1056. d.assignments++;
  1057. if (!fixed || sym.in_arg || !safe_to_assign(tw, d)) {
  1058. walk();
  1059. d.fixed = false;
  1060. } else {
  1061. push_ref(d, sym);
  1062. mark(tw, d);
  1063. if (left instanceof AST_Destructured
  1064. || d.orig.length == 1 && d.orig[0] instanceof AST_SymbolDefun) {
  1065. d.single_use = false;
  1066. }
  1067. tw.loop_ids[d.id] = tw.in_loop;
  1068. d.fixed = modified ? 0 : fixed;
  1069. sym.fixed = fixed;
  1070. sym.fixed.assigns = [ node ];
  1071. mark_escaped(tw, d, sym.scope, node, right, 0, 1);
  1072. }
  1073. });
  1074. }
  1075. function walk_lazy() {
  1076. if (!lazy) return;
  1077. left.walk(tw);
  1078. push(tw, true, true);
  1079. right.walk(tw);
  1080. pop(tw);
  1081. return true;
  1082. }
  1083. });
  1084. def(AST_Binary, function(tw) {
  1085. if (!lazy_op[this.operator]) return;
  1086. this.left.walk(tw);
  1087. push(tw, true, true);
  1088. this.right.walk(tw);
  1089. pop(tw);
  1090. return true;
  1091. });
  1092. def(AST_BlockScope, function(tw, descend, compressor) {
  1093. reset_block_variables(tw, compressor, this);
  1094. });
  1095. def(AST_Call, function(tw) {
  1096. var node = this;
  1097. var exp = node.expression;
  1098. if (exp instanceof AST_LambdaExpression) {
  1099. var iife = is_iife_single(node);
  1100. node.args.forEach(function(arg) {
  1101. arg.walk(tw);
  1102. if (arg instanceof AST_Spread) iife = false;
  1103. });
  1104. if (iife) exp.reduce_vars = reduce_iife;
  1105. exp.walk(tw);
  1106. if (iife) delete exp.reduce_vars;
  1107. return true;
  1108. }
  1109. if (node.TYPE == "Call") switch (tw.in_boolean_context()) {
  1110. case "d":
  1111. var drop = true;
  1112. case true:
  1113. mark_refs(exp, drop);
  1114. }
  1115. exp.walk(tw);
  1116. var optional = node.optional;
  1117. if (optional) push(tw, true, true);
  1118. node.args.forEach(function(arg) {
  1119. arg.walk(tw);
  1120. });
  1121. if (optional) pop(tw);
  1122. var fixed = exp instanceof AST_SymbolRef && exp.fixed_value();
  1123. if (fixed instanceof AST_Lambda) {
  1124. mark_fn_def(tw, exp.definition(), fixed);
  1125. } else {
  1126. tw.defined_ids.seq = {};
  1127. tw.find_parent(AST_Scope).may_call_this();
  1128. }
  1129. return true;
  1130. function mark_refs(node, drop) {
  1131. if (node instanceof AST_Assign) {
  1132. if (node.operator != "=") return;
  1133. mark_refs(node.left, drop);
  1134. mark_refs(node.right, drop);
  1135. } else if (node instanceof AST_Binary) {
  1136. if (!lazy_op[node.operator]) return;
  1137. mark_refs(node.left, drop);
  1138. mark_refs(node.right, drop);
  1139. } else if (node instanceof AST_Conditional) {
  1140. mark_refs(node.consequent, drop);
  1141. mark_refs(node.alternative, drop);
  1142. } else if (node instanceof AST_SymbolRef) {
  1143. var def = node.definition();
  1144. def.bool_return++;
  1145. if (drop) def.drop_return++;
  1146. }
  1147. }
  1148. });
  1149. def(AST_Class, function(tw, descend, compressor) {
  1150. var node = this;
  1151. reset_block_variables(tw, compressor, node);
  1152. if (node.extends) node.extends.walk(tw);
  1153. var props = node.properties.filter(function(prop) {
  1154. reset_flags(prop);
  1155. if (prop.key instanceof AST_Node) {
  1156. tw.push(prop);
  1157. prop.key.walk(tw);
  1158. tw.pop();
  1159. }
  1160. return prop.value;
  1161. });
  1162. if (node.name) {
  1163. var d = node.name.definition();
  1164. var parent = tw.parent();
  1165. if (parent instanceof AST_ExportDeclaration || parent instanceof AST_ExportDefault) d.single_use = false;
  1166. if (safe_to_assign(tw, d, true)) {
  1167. mark(tw, d);
  1168. tw.loop_ids[d.id] = tw.in_loop;
  1169. d.fixed = function() {
  1170. return node;
  1171. };
  1172. d.fixed.assigns = [ node ];
  1173. if (!is_safe_lexical(d)) d.single_use = false;
  1174. } else {
  1175. d.fixed = false;
  1176. }
  1177. }
  1178. props.forEach(function(prop) {
  1179. tw.push(prop);
  1180. if (!prop.static || is_static_field_or_init(prop) && prop.value.contains_this()) {
  1181. push(tw);
  1182. prop.value.walk(tw);
  1183. pop(tw);
  1184. } else {
  1185. prop.value.walk(tw);
  1186. }
  1187. tw.pop();
  1188. });
  1189. return true;
  1190. });
  1191. def(AST_ClassInitBlock, function(tw, descend, compressor) {
  1192. var node = this;
  1193. push(tw, true);
  1194. reset_variables(tw, compressor, node);
  1195. descend();
  1196. pop_scope(tw, node);
  1197. return true;
  1198. });
  1199. def(AST_Conditional, function(tw) {
  1200. this.condition.walk(tw);
  1201. push(tw, true, true);
  1202. this.consequent.walk(tw);
  1203. pop(tw);
  1204. push(tw, true, true);
  1205. this.alternative.walk(tw);
  1206. pop(tw);
  1207. return true;
  1208. });
  1209. def(AST_DefaultValue, function(tw) {
  1210. push(tw, true, true);
  1211. this.value.walk(tw);
  1212. pop(tw);
  1213. this.name.walk(tw);
  1214. return true;
  1215. });
  1216. def(AST_Do, function(tw) {
  1217. var save_loop = tw.in_loop;
  1218. tw.in_loop = this;
  1219. push(tw);
  1220. this.body.walk(tw);
  1221. if (has_loop_control(this, tw.parent())) {
  1222. pop(tw);
  1223. push(tw);
  1224. }
  1225. this.condition.walk(tw);
  1226. pop(tw);
  1227. tw.in_loop = save_loop;
  1228. return true;
  1229. });
  1230. def(AST_Dot, function(tw, descend) {
  1231. descend();
  1232. var node = this;
  1233. var expr = node.expression;
  1234. if (!node.optional) {
  1235. while (expr instanceof AST_Assign && expr.operator == "=") {
  1236. var lhs = expr.left;
  1237. if (lhs instanceof AST_SymbolRef) access(tw, lhs.definition());
  1238. expr = expr.right;
  1239. }
  1240. if (expr instanceof AST_SymbolRef) access(tw, expr.definition());
  1241. }
  1242. return true;
  1243. });
  1244. def(AST_For, function(tw, descend, compressor) {
  1245. var node = this;
  1246. reset_block_variables(tw, compressor, node);
  1247. if (node.init) node.init.walk(tw);
  1248. var save_loop = tw.in_loop;
  1249. tw.in_loop = node;
  1250. push(tw);
  1251. if (node.condition) node.condition.walk(tw);
  1252. node.body.walk(tw);
  1253. if (node.step) {
  1254. if (has_loop_control(node, tw.parent())) {
  1255. pop(tw);
  1256. push(tw);
  1257. }
  1258. node.step.walk(tw);
  1259. }
  1260. pop(tw);
  1261. tw.in_loop = save_loop;
  1262. return true;
  1263. });
  1264. def(AST_ForEnumeration, function(tw, descend, compressor) {
  1265. var node = this;
  1266. reset_block_variables(tw, compressor, node);
  1267. node.object.walk(tw);
  1268. var save_loop = tw.in_loop;
  1269. tw.in_loop = node;
  1270. push(tw);
  1271. var init = node.init;
  1272. if (init instanceof AST_Definitions) {
  1273. init.definitions[0].name.mark_symbol(function(node) {
  1274. if (node instanceof AST_SymbolDeclaration) {
  1275. var def = node.definition();
  1276. def.assignments++;
  1277. def.fixed = false;
  1278. }
  1279. }, tw);
  1280. } else if (init instanceof AST_Destructured || init instanceof AST_SymbolRef) {
  1281. init.mark_symbol(function(node) {
  1282. if (node instanceof AST_SymbolRef) {
  1283. var def = node.definition();
  1284. push_ref(def, node);
  1285. def.assignments++;
  1286. if (!node.is_immutable()) def.fixed = false;
  1287. }
  1288. }, tw);
  1289. } else {
  1290. init.walk(tw);
  1291. }
  1292. node.body.walk(tw);
  1293. pop(tw);
  1294. tw.in_loop = save_loop;
  1295. return true;
  1296. });
  1297. def(AST_If, function(tw) {
  1298. this.condition.walk(tw);
  1299. push(tw, true, true);
  1300. this.body.walk(tw);
  1301. pop(tw);
  1302. if (this.alternative) {
  1303. push(tw, true, true);
  1304. this.alternative.walk(tw);
  1305. pop(tw);
  1306. }
  1307. return true;
  1308. });
  1309. def(AST_LabeledStatement, function(tw) {
  1310. push(tw, true);
  1311. this.body.walk(tw);
  1312. pop(tw);
  1313. return true;
  1314. });
  1315. def(AST_Lambda, function(tw, descend, compressor) {
  1316. var fn = this;
  1317. if (!safe_to_visit(tw, fn)) return true;
  1318. if (!push_uniq(tw.fn_visited, fn)) return true;
  1319. fn.inlined = false;
  1320. push(tw);
  1321. reset_variables(tw, compressor, fn);
  1322. descend();
  1323. pop_scope(tw, fn);
  1324. if (fn.name) mark_escaped(tw, fn.name.definition(), fn, fn.name, fn, 0, 1);
  1325. return true;
  1326. });
  1327. def(AST_LambdaDefinition, function(tw, descend, compressor) {
  1328. var fn = this;
  1329. var def = fn.name.definition();
  1330. if (!safe_to_trim(fn)) def.fixed = false;
  1331. var parent = tw.parent();
  1332. if (parent instanceof AST_ExportDeclaration || parent instanceof AST_ExportDefault) def.single_use = false;
  1333. if (!safe_to_visit(tw, fn)) return true;
  1334. if (!push_uniq(tw.fn_visited, fn)) return true;
  1335. fn.inlined = false;
  1336. push(tw);
  1337. reset_variables(tw, compressor, fn);
  1338. descend();
  1339. pop_scope(tw, fn);
  1340. return true;
  1341. });
  1342. def(AST_Sub, function(tw, descend) {
  1343. var node = this;
  1344. var expr = node.expression;
  1345. if (node.optional) {
  1346. expr.walk(tw);
  1347. push(tw, true, true);
  1348. node.property.walk(tw);
  1349. pop(tw);
  1350. } else {
  1351. descend();
  1352. while (expr instanceof AST_Assign && expr.operator == "=") {
  1353. var lhs = expr.left;
  1354. if (lhs instanceof AST_SymbolRef) access(tw, lhs.definition());
  1355. expr = expr.right;
  1356. }
  1357. if (expr instanceof AST_SymbolRef) access(tw, expr.definition());
  1358. }
  1359. return true;
  1360. });
  1361. def(AST_Switch, function(tw, descend, compressor) {
  1362. var node = this;
  1363. reset_block_variables(tw, compressor, node);
  1364. node.expression.walk(tw);
  1365. var first = true;
  1366. node.body.forEach(function(branch) {
  1367. if (branch instanceof AST_Default) return;
  1368. branch.expression.walk(tw);
  1369. if (first) {
  1370. first = false;
  1371. push(tw, true, true);
  1372. }
  1373. });
  1374. if (!first) pop(tw);
  1375. walk_body(node, tw);
  1376. return true;
  1377. });
  1378. def(AST_SwitchBranch, function(tw) {
  1379. push(tw, true, true);
  1380. walk_body(this, tw);
  1381. pop(tw);
  1382. return true;
  1383. });
  1384. def(AST_SymbolCatch, function() {
  1385. var d = this.definition();
  1386. if (!d.first_decl && d.references.length == 0) d.first_decl = this;
  1387. d.fixed = false;
  1388. });
  1389. def(AST_SymbolDeclaration, function() {
  1390. var d = this.definition();
  1391. if (!d.first_decl && d.references.length == 0) d.first_decl = this;
  1392. });
  1393. def(AST_SymbolDefun, function() {
  1394. var d = this.definition();
  1395. if (!d.first_decl && d.references.length == 0) d.first_decl = this;
  1396. if (d.orig.length > 1 && d.scope.resolve() !== this.scope) d.fixed = false;
  1397. });
  1398. def(AST_SymbolImport, function() {
  1399. var d = this.definition();
  1400. d.first_decl = this;
  1401. d.fixed = false;
  1402. });
  1403. def(AST_SymbolRef, function(tw, descend, compressor) {
  1404. var ref = this;
  1405. var d = ref.definition();
  1406. var fixed = d.fixed || d.last_ref && d.last_ref.fixed;
  1407. push_ref(d, ref);
  1408. if (safe_to_access(tw, d)) ref.defined = true;
  1409. if (d.references.length == 1 && !d.fixed && d.orig[0] instanceof AST_SymbolDefun) {
  1410. tw.loop_ids[d.id] = tw.in_loop;
  1411. }
  1412. var recursive = recursive_ref(tw, d);
  1413. if (recursive) recursive.enclosed.forEach(function(def) {
  1414. if (d === def) return;
  1415. if (def.scope.resolve() === recursive) return;
  1416. var assigns = def.fixed && def.fixed.assigns;
  1417. if (!assigns) return;
  1418. if (assigns[assigns.length - 1] instanceof AST_VarDef) return;
  1419. var safe = tw.safe_ids[def.id];
  1420. if (!safe) return;
  1421. safe.assign = true;
  1422. });
  1423. if (d.single_use == "m" && d.fixed) {
  1424. d.fixed = 0;
  1425. d.single_use = false;
  1426. }
  1427. switch (d.fixed) {
  1428. case 0:
  1429. if (!safe_to_read(tw, d)) d.fixed = false;
  1430. case false:
  1431. var redef = d.redefined();
  1432. if (redef && cross_scope(d.scope, ref.scope)) redef.single_use = false;
  1433. break;
  1434. case undefined:
  1435. d.fixed = false;
  1436. break;
  1437. default:
  1438. if (!safe_to_read(tw, d)) {
  1439. d.fixed = false;
  1440. break;
  1441. }
  1442. if (ref.in_arg && d.orig[0] instanceof AST_SymbolLambda) ref.fixed = d.scope;
  1443. var value = ref.fixed_value();
  1444. if (recursive) {
  1445. d.recursive_refs++;
  1446. } else if (value && ref_once(compressor, d)) {
  1447. d.in_loop = tw.loop_ids[d.id] !== tw.in_loop;
  1448. d.single_use = is_lambda(value)
  1449. && !value.pinned()
  1450. && (!d.in_loop || tw.parent() instanceof AST_Call)
  1451. || !d.in_loop
  1452. && d.scope === ref.scope.resolve()
  1453. && value.is_constant_expression();
  1454. } else {
  1455. d.single_use = false;
  1456. }
  1457. if (is_modified(compressor, tw, ref, value, 0, is_immutable(value), recursive)) {
  1458. if (d.single_use) {
  1459. d.single_use = "m";
  1460. } else {
  1461. d.fixed = 0;
  1462. }
  1463. }
  1464. if (d.fixed && tw.loop_ids[d.id] !== tw.in_loop) d.cross_loop = true;
  1465. mark_escaped(tw, d, ref.scope, ref, value, 0, 1);
  1466. break;
  1467. }
  1468. if (!ref.fixed) ref.fixed = d.fixed === 0 ? fixed : d.fixed;
  1469. if (!value && fixed) value = fixed instanceof AST_Node ? fixed : fixed();
  1470. if (!(value instanceof AST_Lambda)) return;
  1471. if (d.fixed) {
  1472. var parent = tw.parent();
  1473. if (parent instanceof AST_Call && parent.expression === ref) return;
  1474. }
  1475. mark_fn_def(tw, d, value);
  1476. });
  1477. def(AST_Template, function(tw) {
  1478. var node = this;
  1479. var tag = node.tag;
  1480. if (!tag) return;
  1481. if (tag instanceof AST_LambdaExpression) {
  1482. node.expressions.forEach(function(exp) {
  1483. exp.walk(tw);
  1484. });
  1485. tag.walk(tw);
  1486. return true;
  1487. }
  1488. tag.walk(tw);
  1489. node.expressions.forEach(function(exp) {
  1490. exp.walk(tw);
  1491. });
  1492. var fixed = tag instanceof AST_SymbolRef && tag.fixed_value();
  1493. if (fixed instanceof AST_Lambda) {
  1494. mark_fn_def(tw, tag.definition(), fixed);
  1495. } else {
  1496. tw.find_parent(AST_Scope).may_call_this();
  1497. }
  1498. return true;
  1499. });
  1500. def(AST_Toplevel, function(tw, descend, compressor) {
  1501. var node = this;
  1502. node.globals.each(function(def) {
  1503. reset_def(tw, compressor, def);
  1504. });
  1505. push(tw, true);
  1506. reset_variables(tw, compressor, node);
  1507. descend();
  1508. pop_scope(tw, node);
  1509. return true;
  1510. });
  1511. def(AST_Try, function(tw, descend, compressor) {
  1512. var node = this;
  1513. reset_block_variables(tw, compressor, node);
  1514. push(tw, true);
  1515. walk_body(node, tw);
  1516. pop(tw);
  1517. if (node.bcatch) {
  1518. push(tw, true, true);
  1519. node.bcatch.walk(tw);
  1520. pop(tw);
  1521. }
  1522. if (node.bfinally) node.bfinally.walk(tw);
  1523. return true;
  1524. });
  1525. def(AST_Unary, function(tw) {
  1526. var node = this;
  1527. if (!UNARY_POSTFIX[node.operator]) return;
  1528. var exp = node.expression;
  1529. if (!(exp instanceof AST_SymbolRef)) {
  1530. mark_assignment_to_arguments(exp);
  1531. return;
  1532. }
  1533. var d = exp.definition();
  1534. d.assignments++;
  1535. var fixed = d.fixed;
  1536. if (safe_to_read(tw, d) && !exp.in_arg && safe_to_assign(tw, d)) {
  1537. push_ref(d, exp);
  1538. mark(tw, d);
  1539. if (d.single_use) d.single_use = false;
  1540. d.fixed = function() {
  1541. return make_node(AST_Binary, node, {
  1542. operator: node.operator.slice(0, -1),
  1543. left: make_node(AST_UnaryPrefix, node, {
  1544. operator: "+",
  1545. expression: make_ref(exp, fixed),
  1546. }),
  1547. right: make_node(AST_Number, node, { value: 1 }),
  1548. });
  1549. };
  1550. d.fixed.assigns = fixed && fixed.assigns ? fixed.assigns.slice() : [];
  1551. d.fixed.assigns.push(node);
  1552. if (node instanceof AST_UnaryPrefix) {
  1553. exp.fixed = d.fixed;
  1554. } else {
  1555. exp.fixed = function() {
  1556. return make_node(AST_UnaryPrefix, node, {
  1557. operator: "+",
  1558. expression: make_ref(exp, fixed),
  1559. });
  1560. };
  1561. exp.fixed.assigns = fixed && fixed.assigns;
  1562. exp.fixed.to_prefix = replace_ref(function(node) {
  1563. return node.expression;
  1564. }, d.fixed);
  1565. }
  1566. } else {
  1567. exp.walk(tw);
  1568. d.fixed = false;
  1569. }
  1570. return true;
  1571. });
  1572. def(AST_VarDef, function(tw, descend, compressor) {
  1573. var node = this;
  1574. var value = node.value;
  1575. if (value instanceof AST_LambdaExpression && node.name instanceof AST_SymbolDeclaration) {
  1576. walk_defn();
  1577. value.parent_scope.resolve().fn_defs.push(value);
  1578. value.safe_ids = null;
  1579. var ld = node.name.definition();
  1580. if (!ld.fixed) mark_fn_def(tw, ld, value);
  1581. } else if (value) {
  1582. value.walk(tw);
  1583. walk_defn();
  1584. } else if (tw.parent() instanceof AST_Let) {
  1585. walk_defn();
  1586. } else {
  1587. node.name.walk(tw);
  1588. }
  1589. return true;
  1590. function walk_defn() {
  1591. scan_declaration(tw, compressor, node.name, function() {
  1592. return node.value || make_node(AST_Undefined, node);
  1593. }, function(name, fixed) {
  1594. var d = name.definition();
  1595. assign(tw, d);
  1596. if (!d.first_decl && d.references.length == 0) d.first_decl = name;
  1597. if (fixed && safe_to_assign(tw, d, true)) {
  1598. mark(tw, d);
  1599. tw.loop_ids[d.id] = tw.in_loop;
  1600. d.fixed = fixed;
  1601. d.fixed.assigns = [ node ];
  1602. if (name instanceof AST_SymbolConst && d.redefined()
  1603. || !(can_drop_symbol(name) || is_safe_lexical(d))) {
  1604. d.single_use = false;
  1605. }
  1606. } else {
  1607. d.fixed = false;
  1608. }
  1609. });
  1610. }
  1611. });
  1612. def(AST_While, function(tw, descend) {
  1613. var save_loop = tw.in_loop;
  1614. tw.in_loop = this;
  1615. push(tw);
  1616. descend();
  1617. pop(tw);
  1618. tw.in_loop = save_loop;
  1619. return true;
  1620. });
  1621. })(function(node, func) {
  1622. node.DEFMETHOD("reduce_vars", func);
  1623. });
  1624. function reset_flags(node) {
  1625. node._squeezed = false;
  1626. node._optimized = false;
  1627. node.single_use = false;
  1628. if (node instanceof AST_BlockScope) node._var_names = undefined;
  1629. if (node instanceof AST_SymbolRef) node.fixed = undefined;
  1630. }
  1631. AST_Toplevel.DEFMETHOD("reset_opt_flags", function(compressor) {
  1632. var tw = new TreeWalker(compressor.option("reduce_vars") ? function(node, descend) {
  1633. reset_flags(node);
  1634. return node.reduce_vars(tw, descend, compressor);
  1635. } : reset_flags);
  1636. // Side-effect tracking on sequential property access
  1637. tw.assigned_ids = Object.create(null);
  1638. tw.defined_ids = Object.create(null);
  1639. tw.defined_ids.seq = {};
  1640. // Flow control for visiting lambda definitions
  1641. tw.fn_scanning = null;
  1642. tw.fn_visited = [];
  1643. // Record the loop body in which `AST_SymbolDeclaration` is first encountered
  1644. tw.in_loop = null;
  1645. tw.loop_ids = Object.create(null);
  1646. // Stack of look-up tables to keep track of whether a `SymbolDef` has been
  1647. // properly assigned before use:
  1648. // - `push()` & `pop()` when visiting conditional branches
  1649. // - backup & restore via `save_ids` when visiting out-of-order sections
  1650. tw.safe_ids = Object.create(null);
  1651. tw.safe_ids.seq = {};
  1652. this.walk(tw);
  1653. });
  1654. AST_Symbol.DEFMETHOD("fixed_value", function(ref_only) {
  1655. var def = this.definition();
  1656. var fixed = def.fixed;
  1657. if (fixed) {
  1658. if (this.fixed) fixed = this.fixed;
  1659. return (fixed instanceof AST_Node ? fixed : fixed()).tail_node();
  1660. }
  1661. fixed = fixed === 0 && this.fixed;
  1662. if (!fixed) return fixed;
  1663. var value = (fixed instanceof AST_Node ? fixed : fixed()).tail_node();
  1664. if (ref_only && def.escaped.depth != 1 && is_object(value, true)) return value;
  1665. if (value.is_constant()) return value;
  1666. });
  1667. AST_SymbolRef.DEFMETHOD("is_immutable", function() {
  1668. var def = this.redef || this.definition();
  1669. if (!(def.orig[0] instanceof AST_SymbolLambda)) return false;
  1670. if (def.orig.length == 1) return true;
  1671. if (!this.in_arg) return false;
  1672. return !(def.orig[1] instanceof AST_SymbolFunarg);
  1673. });
  1674. AST_Node.DEFMETHOD("convert_symbol", noop);
  1675. function convert_destructured(type, process) {
  1676. return this.transform(new TreeTransformer(function(node, descend) {
  1677. if (node instanceof AST_DefaultValue) {
  1678. node = node.clone();
  1679. node.name = node.name.transform(this);
  1680. return node;
  1681. }
  1682. if (node instanceof AST_Destructured) {
  1683. node = node.clone();
  1684. descend(node, this);
  1685. return node;
  1686. }
  1687. if (node instanceof AST_DestructuredKeyVal) {
  1688. node = node.clone();
  1689. node.value = node.value.transform(this);
  1690. return node;
  1691. }
  1692. return node.convert_symbol(type, process);
  1693. }));
  1694. }
  1695. AST_DefaultValue.DEFMETHOD("convert_symbol", convert_destructured);
  1696. AST_Destructured.DEFMETHOD("convert_symbol", convert_destructured);
  1697. function convert_symbol(type, process) {
  1698. var node = make_node(type, this);
  1699. return process(node, this) || node;
  1700. }
  1701. AST_SymbolDeclaration.DEFMETHOD("convert_symbol", convert_symbol);
  1702. AST_SymbolRef.DEFMETHOD("convert_symbol", convert_symbol);
  1703. function process_to_assign(ref) {
  1704. var def = ref.definition();
  1705. def.assignments++;
  1706. def.references.push(ref);
  1707. }
  1708. function mark_destructured(process, tw) {
  1709. var marker = new TreeWalker(function(node) {
  1710. if (node instanceof AST_DefaultValue) {
  1711. node.value.walk(tw);
  1712. node.name.walk(marker);
  1713. return true;
  1714. }
  1715. if (node instanceof AST_DestructuredKeyVal) {
  1716. if (node.key instanceof AST_Node) node.key.walk(tw);
  1717. node.value.walk(marker);
  1718. return true;
  1719. }
  1720. return process(node);
  1721. });
  1722. this.walk(marker);
  1723. }
  1724. AST_DefaultValue.DEFMETHOD("mark_symbol", mark_destructured);
  1725. AST_Destructured.DEFMETHOD("mark_symbol", mark_destructured);
  1726. function mark_symbol(process) {
  1727. return process(this);
  1728. }
  1729. AST_SymbolDeclaration.DEFMETHOD("mark_symbol", mark_symbol);
  1730. AST_SymbolRef.DEFMETHOD("mark_symbol", mark_symbol);
  1731. AST_Node.DEFMETHOD("match_symbol", function(predicate) {
  1732. return predicate(this);
  1733. });
  1734. function match_destructured(predicate, ignore_side_effects) {
  1735. var found = false;
  1736. var tw = new TreeWalker(function(node) {
  1737. if (found) return true;
  1738. if (node instanceof AST_DefaultValue) {
  1739. if (!ignore_side_effects) return found = true;
  1740. node.name.walk(tw);
  1741. return true;
  1742. }
  1743. if (node instanceof AST_DestructuredKeyVal) {
  1744. if (!ignore_side_effects && node.key instanceof AST_Node) return found = true;
  1745. node.value.walk(tw);
  1746. return true;
  1747. }
  1748. if (predicate(node)) return found = true;
  1749. });
  1750. this.walk(tw);
  1751. return found;
  1752. }
  1753. AST_DefaultValue.DEFMETHOD("match_symbol", match_destructured);
  1754. AST_Destructured.DEFMETHOD("match_symbol", match_destructured);
  1755. function in_async_generator(scope) {
  1756. return scope instanceof AST_AsyncGeneratorDefun || scope instanceof AST_AsyncGeneratorFunction;
  1757. }
  1758. function find_scope(compressor) {
  1759. var level = 0, node = compressor.self();
  1760. do {
  1761. if (node.variables) return node;
  1762. } while (node = compressor.parent(level++));
  1763. }
  1764. function find_try(compressor, level, node, scope, may_throw, sync) {
  1765. for (var parent; parent = compressor.parent(level++); node = parent) {
  1766. if (parent === scope) return false;
  1767. if (sync && parent instanceof AST_Lambda) {
  1768. if (parent.name || is_async(parent) || is_generator(parent)) return true;
  1769. } else if (parent instanceof AST_Try) {
  1770. if (parent.bfinally && parent.bfinally !== node) return true;
  1771. if (may_throw && parent.bcatch && parent.bcatch !== node) return true;
  1772. }
  1773. }
  1774. return false;
  1775. }
  1776. var identifier_atom = makePredicate("Infinity NaN undefined");
  1777. function is_lhs_read_only(lhs, compressor) {
  1778. if (lhs instanceof AST_Assign) {
  1779. if (lhs.operator != "=") return true;
  1780. if (lhs.right.tail_node().is_constant()) return true;
  1781. return is_lhs_read_only(lhs.left, compressor);
  1782. }
  1783. if (lhs instanceof AST_Atom) return true;
  1784. if (lhs instanceof AST_ObjectIdentity) return true;
  1785. if (lhs instanceof AST_PropAccess) {
  1786. if (lhs.property === "__proto__") return true;
  1787. lhs = lhs.expression;
  1788. if (lhs instanceof AST_SymbolRef) {
  1789. if (lhs.is_immutable()) return false;
  1790. lhs = lhs.fixed_value();
  1791. }
  1792. if (!lhs) return true;
  1793. if (lhs.tail_node().is_constant()) return true;
  1794. return is_lhs_read_only(lhs, compressor);
  1795. }
  1796. if (lhs instanceof AST_SymbolRef) {
  1797. if (lhs.is_immutable()) return true;
  1798. var def = lhs.definition();
  1799. return compressor.exposed(def) && identifier_atom[def.name];
  1800. }
  1801. return false;
  1802. }
  1803. function make_node(ctor, orig, props) {
  1804. if (props) {
  1805. props.start = orig.start;
  1806. props.end = orig.end;
  1807. } else {
  1808. props = orig;
  1809. }
  1810. return new ctor(props);
  1811. }
  1812. function make_sequence(orig, expressions) {
  1813. if (expressions.length == 1) return expressions[0];
  1814. return make_node(AST_Sequence, orig, { expressions: expressions.reduce(merge_sequence, []) });
  1815. }
  1816. function make_node_from_constant(val, orig) {
  1817. switch (typeof val) {
  1818. case "string":
  1819. return make_node(AST_String, orig, { value: val });
  1820. case "number":
  1821. if (isNaN(val)) return make_node(AST_NaN, orig);
  1822. if (isFinite(val)) {
  1823. return 1 / val < 0 ? make_node(AST_UnaryPrefix, orig, {
  1824. operator: "-",
  1825. expression: make_node(AST_Number, orig, { value: -val }),
  1826. }) : make_node(AST_Number, orig, { value: val });
  1827. }
  1828. return val < 0 ? make_node(AST_UnaryPrefix, orig, {
  1829. operator: "-",
  1830. expression: make_node(AST_Infinity, orig),
  1831. }) : make_node(AST_Infinity, orig);
  1832. case "boolean":
  1833. return make_node(val ? AST_True : AST_False, orig);
  1834. case "undefined":
  1835. return make_node(AST_Undefined, orig);
  1836. default:
  1837. if (val === null) {
  1838. return make_node(AST_Null, orig);
  1839. }
  1840. if (val instanceof RegExp) {
  1841. return make_node(AST_RegExp, orig, { value: val });
  1842. }
  1843. throw new Error(string_template("Can't handle constant of type: {type}", { type: typeof val }));
  1844. }
  1845. }
  1846. function needs_unbinding(val) {
  1847. return val instanceof AST_PropAccess
  1848. || is_undeclared_ref(val) && val.name == "eval";
  1849. }
  1850. // we shouldn't compress (1,func)(something) to
  1851. // func(something) because that changes the meaning of
  1852. // the func (becomes lexical instead of global).
  1853. function maintain_this_binding(parent, orig, val) {
  1854. var wrap = false;
  1855. if (parent.TYPE == "Call") {
  1856. wrap = parent.expression === orig && needs_unbinding(val);
  1857. } else if (parent instanceof AST_Template) {
  1858. wrap = parent.tag === orig && needs_unbinding(val);
  1859. } else if (parent instanceof AST_UnaryPrefix) {
  1860. wrap = parent.operator == "delete"
  1861. || parent.operator == "typeof" && is_undeclared_ref(val);
  1862. }
  1863. return wrap ? make_sequence(orig, [ make_node(AST_Number, orig, { value: 0 }), val ]) : val;
  1864. }
  1865. function merge_expression(base, target) {
  1866. var fixed_by_id = new Dictionary();
  1867. base.walk(new TreeWalker(function(node) {
  1868. if (!(node instanceof AST_SymbolRef)) return;
  1869. var def = node.definition();
  1870. var fixed = node.fixed;
  1871. if (!fixed || !fixed_by_id.has(def.id)) {
  1872. fixed_by_id.set(def.id, fixed);
  1873. } else if (fixed_by_id.get(def.id) !== fixed) {
  1874. fixed_by_id.set(def.id, false);
  1875. }
  1876. }));
  1877. if (fixed_by_id.size() > 0) target.walk(new TreeWalker(function(node) {
  1878. if (!(node instanceof AST_SymbolRef)) return;
  1879. var def = node.definition();
  1880. var fixed = node.fixed;
  1881. if (!fixed || !fixed_by_id.has(def.id)) return;
  1882. if (fixed_by_id.get(def.id) !== fixed) node.fixed = false;
  1883. }));
  1884. return target;
  1885. }
  1886. function merge_sequence(array, node) {
  1887. if (node instanceof AST_Sequence) {
  1888. [].push.apply(array, node.expressions);
  1889. } else {
  1890. array.push(node);
  1891. }
  1892. return array;
  1893. }
  1894. function is_lexical_definition(stat) {
  1895. return stat instanceof AST_Const || stat instanceof AST_DefClass || stat instanceof AST_Let;
  1896. }
  1897. function safe_to_trim(stat) {
  1898. if (stat instanceof AST_LambdaDefinition) {
  1899. var def = stat.name.definition();
  1900. var scope = stat.name.scope;
  1901. if (def.orig.length > 1 && def.scope.resolve() !== scope) return false;
  1902. return def.scope === scope || all(def.references, function(ref) {
  1903. var s = ref.scope;
  1904. do {
  1905. if (s === scope) return true;
  1906. } while (s = s.parent_scope);
  1907. });
  1908. }
  1909. return !is_lexical_definition(stat);
  1910. }
  1911. function as_statement_array(thing) {
  1912. if (thing === null) return [];
  1913. if (thing instanceof AST_BlockStatement) return all(thing.body, safe_to_trim) ? thing.body : [ thing ];
  1914. if (thing instanceof AST_EmptyStatement) return [];
  1915. if (is_statement(thing)) return [ thing ];
  1916. throw new Error("Can't convert thing to statement array");
  1917. }
  1918. function is_empty(thing) {
  1919. if (thing === null) return true;
  1920. if (thing instanceof AST_EmptyStatement) return true;
  1921. if (thing instanceof AST_BlockStatement) return thing.body.length == 0;
  1922. return false;
  1923. }
  1924. function has_declarations_only(block) {
  1925. return all(block.body, function(stat) {
  1926. return is_empty(stat)
  1927. || stat instanceof AST_Defun
  1928. || stat instanceof AST_Var && declarations_only(stat);
  1929. });
  1930. }
  1931. function loop_body(x) {
  1932. if (x instanceof AST_IterationStatement) {
  1933. return x.body instanceof AST_BlockStatement ? x.body : x;
  1934. }
  1935. return x;
  1936. }
  1937. function is_iife_call(node) {
  1938. if (node.TYPE != "Call") return false;
  1939. do {
  1940. node = node.expression;
  1941. } while (node instanceof AST_PropAccess);
  1942. return node instanceof AST_LambdaExpression ? !is_arrow(node) : is_iife_call(node);
  1943. }
  1944. function is_iife_single(call) {
  1945. var exp = call.expression;
  1946. if (exp.name) return false;
  1947. if (!(call instanceof AST_New)) return true;
  1948. var found = false;
  1949. exp.walk(new TreeWalker(function(node) {
  1950. if (found) return true;
  1951. if (node instanceof AST_NewTarget) return found = true;
  1952. if (node instanceof AST_Scope && node !== exp) return true;
  1953. }));
  1954. return !found;
  1955. }
  1956. function is_undeclared_ref(node) {
  1957. return node instanceof AST_SymbolRef && node.definition().undeclared;
  1958. }
  1959. var global_names = makePredicate("Array Boolean clearInterval clearTimeout console Date decodeURI decodeURIComponent encodeURI encodeURIComponent Error escape eval EvalError Function isFinite isNaN JSON Map Math Number parseFloat parseInt RangeError ReferenceError RegExp Object Set setInterval setTimeout String SyntaxError TypeError unescape URIError WeakMap WeakSet");
  1960. AST_SymbolRef.DEFMETHOD("is_declared", function(compressor) {
  1961. return this.defined
  1962. || !this.definition().undeclared
  1963. || compressor.option("unsafe") && global_names[this.name];
  1964. });
  1965. function is_static_field_or_init(prop) {
  1966. return prop.static && prop.value && (prop instanceof AST_ClassField || prop instanceof AST_ClassInit);
  1967. }
  1968. function declarations_only(node) {
  1969. return all(node.definitions, function(var_def) {
  1970. return !var_def.value;
  1971. });
  1972. }
  1973. function is_declaration(stat, lexical) {
  1974. if (stat instanceof AST_DefClass) return lexical && !stat.extends && all(stat.properties, function(prop) {
  1975. if (prop.key instanceof AST_Node) return false;
  1976. return !is_static_field_or_init(prop);
  1977. });
  1978. if (stat instanceof AST_Definitions) return (lexical || stat instanceof AST_Var) && declarations_only(stat);
  1979. if (stat instanceof AST_ExportDeclaration) return is_declaration(stat.body, lexical);
  1980. if (stat instanceof AST_ExportDefault) return is_declaration(stat.body, lexical);
  1981. return stat instanceof AST_LambdaDefinition;
  1982. }
  1983. function is_last_statement(body, stat) {
  1984. var index = body.lastIndexOf(stat);
  1985. if (index < 0) return false;
  1986. while (++index < body.length) {
  1987. if (!is_declaration(body[index], true)) return false;
  1988. }
  1989. return true;
  1990. }
  1991. // Certain combination of unused name + side effect leads to invalid AST:
  1992. // https://github.com/mishoo/UglifyJS/issues/44
  1993. // https://github.com/mishoo/UglifyJS/issues/1838
  1994. // https://github.com/mishoo/UglifyJS/issues/3371
  1995. // We fix it at this stage by moving the `var` outside the `for`.
  1996. function patch_for_init(node, in_list) {
  1997. var block;
  1998. if (node.init instanceof AST_BlockStatement) {
  1999. block = node.init;
  2000. node.init = block.body.pop();
  2001. block.body.push(node);
  2002. }
  2003. if (node.init instanceof AST_Defun) {
  2004. if (!block) block = make_node(AST_BlockStatement, node, { body: [ node ] });
  2005. block.body.splice(-1, 0, node.init);
  2006. node.init = null;
  2007. } else if (node.init instanceof AST_SimpleStatement) {
  2008. node.init = node.init.body;
  2009. } else if (is_empty(node.init)) {
  2010. node.init = null;
  2011. }
  2012. if (!block) return;
  2013. return in_list ? List.splice(block.body) : block;
  2014. }
  2015. function tighten_body(statements, compressor) {
  2016. var in_lambda = last_of(compressor, function(node) {
  2017. return node instanceof AST_Lambda;
  2018. });
  2019. var block_scope, iife_in_try, in_iife_single, in_loop, in_try, scope;
  2020. find_loop_scope_try();
  2021. var changed, last_changed, max_iter = 10;
  2022. do {
  2023. last_changed = changed;
  2024. changed = 0;
  2025. if (eliminate_spurious_blocks(statements)) changed = 1;
  2026. if (!changed && last_changed == 1) break;
  2027. if (compressor.option("dead_code")) {
  2028. if (eliminate_dead_code(statements, compressor)) changed = 2;
  2029. if (!changed && last_changed == 2) break;
  2030. }
  2031. if (compressor.option("if_return")) {
  2032. if (handle_if_return(statements, compressor)) changed = 3;
  2033. if (!changed && last_changed == 3) break;
  2034. }
  2035. if (compressor.option("awaits") && compressor.option("side_effects")) {
  2036. if (trim_awaits(statements, compressor)) changed = 4;
  2037. if (!changed && last_changed == 4) break;
  2038. }
  2039. if (compressor.option("inline") >= 4) {
  2040. if (inline_iife(statements, compressor)) changed = 5;
  2041. if (!changed && last_changed == 5) break;
  2042. }
  2043. if (compressor.sequences_limit > 0) {
  2044. if (sequencesize(statements, compressor)) changed = 6;
  2045. if (!changed && last_changed == 6) break;
  2046. if (sequencesize_2(statements, compressor)) changed = 7;
  2047. if (!changed && last_changed == 7) break;
  2048. }
  2049. if (compressor.option("join_vars")) {
  2050. if (join_consecutive_vars(statements)) changed = 8;
  2051. if (!changed && last_changed == 8) break;
  2052. }
  2053. if (compressor.option("collapse_vars")) {
  2054. if (collapse(statements, compressor)) changed = 9;
  2055. }
  2056. } while (changed && max_iter-- > 0);
  2057. return statements;
  2058. function last_of(compressor, predicate) {
  2059. var block = compressor.self(), level = 0, stat;
  2060. do {
  2061. if (block instanceof AST_Catch) {
  2062. block = compressor.parent(level++);
  2063. } else if (block instanceof AST_LabeledStatement) {
  2064. block = block.body;
  2065. } else if (block instanceof AST_SwitchBranch) {
  2066. var branches = compressor.parent(level);
  2067. if (branches.body[branches.body.length - 1] === block || has_break(block.body)) {
  2068. level++;
  2069. block = branches;
  2070. }
  2071. }
  2072. do {
  2073. stat = block;
  2074. if (predicate(stat)) return stat;
  2075. block = compressor.parent(level++);
  2076. } while (block instanceof AST_If);
  2077. } while (stat
  2078. && (block instanceof AST_BlockStatement
  2079. || block instanceof AST_Catch
  2080. || block instanceof AST_Scope
  2081. || block instanceof AST_SwitchBranch
  2082. || block instanceof AST_Try)
  2083. && is_last_statement(block.body, stat));
  2084. function has_break(stats) {
  2085. for (var i = stats.length; --i >= 0;) {
  2086. if (stats[i] instanceof AST_Break) return true;
  2087. }
  2088. return false;
  2089. }
  2090. }
  2091. function find_loop_scope_try() {
  2092. var node = compressor.self(), level = 0;
  2093. do {
  2094. if (!block_scope && node.variables) block_scope = node;
  2095. if (node instanceof AST_Catch) {
  2096. if (compressor.parent(level).bfinally) {
  2097. if (!in_try) in_try = {};
  2098. in_try.bfinally = true;
  2099. }
  2100. level++;
  2101. } else if (node instanceof AST_Finally) {
  2102. level++;
  2103. } else if (node instanceof AST_IterationStatement) {
  2104. in_loop = true;
  2105. } else if (node instanceof AST_Scope) {
  2106. scope = node;
  2107. break;
  2108. } else if (node instanceof AST_Try) {
  2109. if (!in_try) in_try = {};
  2110. if (node.bcatch) in_try.bcatch = true;
  2111. if (node.bfinally) in_try.bfinally = true;
  2112. }
  2113. } while (node = compressor.parent(level++));
  2114. }
  2115. // Search from right to left for assignment-like expressions:
  2116. // - `var a = x;`
  2117. // - `a = x;`
  2118. // - `++a`
  2119. // For each candidate, scan from left to right for first usage, then try
  2120. // to fold assignment into the site for compression.
  2121. // Will not attempt to collapse assignments into or past code blocks
  2122. // which are not sequentially executed, e.g. loops and conditionals.
  2123. function collapse(statements, compressor) {
  2124. if (scope.pinned()) return;
  2125. var args;
  2126. var assignments = new Dictionary();
  2127. var candidates = [];
  2128. var changed = false;
  2129. var declare_only = new Dictionary();
  2130. var force_single;
  2131. var stat_index = statements.length;
  2132. var scanner = new TreeTransformer(function(node, descend) {
  2133. if (abort) return node;
  2134. // Skip nodes before `candidate` as quickly as possible
  2135. if (!hit) {
  2136. if (node !== hit_stack[hit_index]) return node;
  2137. hit_index++;
  2138. if (hit_index < hit_stack.length) return handle_custom_scan_order(node, scanner);
  2139. hit = true;
  2140. stop_after = (value_def ? find_stop_value : find_stop)(node, 0);
  2141. if (stop_after === node) abort = true;
  2142. return node;
  2143. }
  2144. var parent = scanner.parent();
  2145. // Stop only if candidate is found within conditional branches
  2146. if (!stop_if_hit && in_conditional(node, parent)) {
  2147. stop_if_hit = parent;
  2148. }
  2149. // Cascade compound assignments
  2150. if (compound && scan_lhs && can_replace && !stop_if_hit
  2151. && node instanceof AST_Assign && node.operator != "=" && node.left.equals(lhs)) {
  2152. replaced++;
  2153. changed = true;
  2154. AST_Node.info("Cascading {this} [{start}]", node);
  2155. can_replace = false;
  2156. lvalues = get_lvalues(lhs);
  2157. node.right.transform(scanner);
  2158. clear_write_only(candidate);
  2159. var folded;
  2160. if (abort) {
  2161. folded = candidate;
  2162. } else {
  2163. abort = true;
  2164. folded = make_node(AST_Binary, candidate, {
  2165. operator: compound,
  2166. left: lhs.fixed && lhs.definition().fixed ? lhs.fixed.to_binary(candidate) : lhs,
  2167. right: rvalue,
  2168. });
  2169. }
  2170. return make_node(AST_Assign, node, {
  2171. operator: "=",
  2172. left: node.left,
  2173. right: make_node(AST_Binary, node, {
  2174. operator: node.operator.slice(0, -1),
  2175. left: folded,
  2176. right: node.right,
  2177. }),
  2178. });
  2179. }
  2180. // Stop immediately if these node types are encountered
  2181. if (should_stop(node, parent)) {
  2182. abort = true;
  2183. return node;
  2184. }
  2185. // Skip transient nodes caused by single-use variable replacement
  2186. if (node.single_use) return node;
  2187. // Replace variable with assignment when found
  2188. var hit_rhs;
  2189. if (!(node instanceof AST_SymbolDeclaration)
  2190. && (scan_lhs && lhs.equals(node)
  2191. || scan_rhs && (hit_rhs = scan_rhs(node, this)))) {
  2192. if (!can_replace || stop_if_hit && (hit_rhs || !lhs_local || !replace_all)) {
  2193. if (!hit_rhs && !value_def) abort = true;
  2194. return node;
  2195. }
  2196. if (is_lhs(node, parent)) {
  2197. if (value_def && !hit_rhs) assign_used = true;
  2198. return node;
  2199. }
  2200. if (!hit_rhs && verify_ref && node.fixed !== lhs.fixed) {
  2201. abort = true;
  2202. return node;
  2203. }
  2204. if (value_def) {
  2205. if (stop_if_hit && assign_pos == 0) assign_pos = remaining - replaced;
  2206. if (!hit_rhs) replaced++;
  2207. return node;
  2208. }
  2209. replaced++;
  2210. changed = abort = true;
  2211. AST_Node.info("Collapsing {this} [{start}]", node);
  2212. if (candidate.TYPE == "Binary") {
  2213. update_symbols(candidate, node);
  2214. return make_node(AST_Assign, candidate, {
  2215. operator: "=",
  2216. left: candidate.right.left,
  2217. right: candidate.operator == "&&" ? make_node(AST_Conditional, candidate, {
  2218. condition: candidate.left,
  2219. consequent: candidate.right.right,
  2220. alternative: node,
  2221. }) : make_node(AST_Conditional, candidate, {
  2222. condition: candidate.left,
  2223. consequent: node,
  2224. alternative: candidate.right.right,
  2225. }),
  2226. });
  2227. }
  2228. if (candidate instanceof AST_UnaryPostfix) return make_node(AST_UnaryPrefix, candidate, {
  2229. operator: candidate.operator,
  2230. expression: lhs.fixed && lhs.definition().fixed ? lhs.fixed.to_prefix(candidate) : lhs,
  2231. });
  2232. if (candidate instanceof AST_UnaryPrefix) {
  2233. clear_write_only(candidate);
  2234. return candidate;
  2235. }
  2236. update_symbols(rvalue, node);
  2237. if (candidate instanceof AST_VarDef) {
  2238. var def = candidate.name.definition();
  2239. if (def.references.length - def.replaced == 1 && !compressor.exposed(def)) {
  2240. def.replaced++;
  2241. return maintain_this_binding(parent, node, rvalue);
  2242. }
  2243. return make_node(AST_Assign, candidate, {
  2244. operator: "=",
  2245. left: node,
  2246. right: rvalue,
  2247. });
  2248. }
  2249. clear_write_only(rvalue);
  2250. var assign = candidate.clone();
  2251. assign.right = rvalue;
  2252. return assign;
  2253. }
  2254. // Stop signals related to AST_SymbolRef
  2255. if (should_stop_ref(node, parent)) {
  2256. abort = true;
  2257. return node;
  2258. }
  2259. // These node types have child nodes that execute sequentially,
  2260. // but are otherwise not safe to scan into or beyond them.
  2261. if (is_last_node(node, parent) || may_throw(node)) {
  2262. stop_after = node;
  2263. if (node instanceof AST_Scope) abort = true;
  2264. }
  2265. // Scan but don't replace inside getter/setter
  2266. if (node instanceof AST_Accessor) {
  2267. var replace = can_replace;
  2268. can_replace = false;
  2269. descend(node, scanner);
  2270. can_replace = replace;
  2271. return signal_abort(node);
  2272. }
  2273. // Scan but don't replace inside destructuring expression
  2274. if (node instanceof AST_Destructured) {
  2275. var replace = can_replace;
  2276. can_replace = false;
  2277. descend(node, scanner);
  2278. can_replace = replace;
  2279. return signal_abort(node);
  2280. }
  2281. // Scan but don't replace inside default value
  2282. if (node instanceof AST_DefaultValue) {
  2283. node.name = node.name.transform(scanner);
  2284. var replace = can_replace;
  2285. can_replace = false;
  2286. node.value = node.value.transform(scanner);
  2287. can_replace = replace;
  2288. return signal_abort(node);
  2289. }
  2290. // Scan but don't replace inside block scope with colliding variable
  2291. if (node instanceof AST_BlockScope
  2292. && !(node instanceof AST_Scope)
  2293. && !(node.variables && node.variables.all(function(def) {
  2294. return !enclosed.has(def.name) && !lvalues.has(def.name);
  2295. }))) {
  2296. var replace = can_replace;
  2297. can_replace = false;
  2298. if (!handle_custom_scan_order(node, scanner)) descend(node, scanner);
  2299. can_replace = replace;
  2300. return signal_abort(node);
  2301. }
  2302. if (handle_custom_scan_order(node, scanner)) return signal_abort(node);
  2303. }, signal_abort);
  2304. var multi_replacer = new TreeTransformer(function(node) {
  2305. if (abort) return node;
  2306. // Skip nodes before `candidate` as quickly as possible
  2307. if (!hit) {
  2308. if (node !== hit_stack[hit_index]) return node;
  2309. hit_index++;
  2310. switch (hit_stack.length - hit_index) {
  2311. case 0:
  2312. hit = true;
  2313. if (assign_used) return node;
  2314. if (node !== candidate) return node;
  2315. if (node instanceof AST_VarDef) return node;
  2316. def.replaced++;
  2317. var parent = multi_replacer.parent();
  2318. if (parent instanceof AST_Sequence && parent.tail_node() !== node) {
  2319. value_def.replaced++;
  2320. if (rvalue === rhs_value) return List.skip;
  2321. return make_sequence(rhs_value, rhs_value.expressions.slice(0, -1));
  2322. }
  2323. return rvalue;
  2324. case 1:
  2325. if (!assign_used && node.body === candidate) {
  2326. hit = true;
  2327. def.replaced++;
  2328. value_def.replaced++;
  2329. return null;
  2330. }
  2331. default:
  2332. return handle_custom_scan_order(node, multi_replacer);
  2333. }
  2334. }
  2335. // Replace variable when found
  2336. if (node instanceof AST_SymbolRef && node.definition() === def) {
  2337. if (is_lhs(node, multi_replacer.parent())) return node;
  2338. if (!--replaced) abort = true;
  2339. AST_Node.info("Replacing {this} [{start}]", node);
  2340. var ref = rvalue.clone();
  2341. ref.scope = node.scope;
  2342. ref.reference();
  2343. if (replaced == assign_pos) {
  2344. abort = true;
  2345. return make_node(AST_Assign, candidate, {
  2346. operator: "=",
  2347. left: node,
  2348. right: ref,
  2349. });
  2350. }
  2351. def.replaced++;
  2352. return ref;
  2353. }
  2354. // Skip (non-executed) functions and (leading) default case in switch statements
  2355. if (node instanceof AST_Default || node instanceof AST_Scope) return node;
  2356. }, function(node) {
  2357. return patch_sequence(node, multi_replacer);
  2358. });
  2359. while (--stat_index >= 0) {
  2360. // Treat parameters as collapsible in IIFE, i.e.
  2361. // function(a, b){ ... }(x());
  2362. // would be translated into equivalent assignments:
  2363. // var a = x(), b = undefined;
  2364. if (stat_index == 0 && compressor.option("unused")) extract_args();
  2365. // Find collapsible assignments
  2366. var hit_stack = [];
  2367. extract_candidates(statements[stat_index]);
  2368. while (candidates.length > 0) {
  2369. hit_stack = candidates.pop();
  2370. var hit_index = 0;
  2371. var candidate = hit_stack[hit_stack.length - 1];
  2372. var assign_pos = -1;
  2373. var assign_used = false;
  2374. var verify_ref = false;
  2375. var remaining;
  2376. var value_def = null;
  2377. var stop_after = null;
  2378. var stop_if_hit = null;
  2379. var lhs = get_lhs(candidate);
  2380. var side_effects = lhs && lhs.has_side_effects(compressor);
  2381. var scan_lhs = lhs && (!side_effects || lhs instanceof AST_SymbolRef)
  2382. && !is_lhs_read_only(lhs, compressor);
  2383. var scan_rhs = foldable(candidate);
  2384. if (!scan_lhs && !scan_rhs) continue;
  2385. var compound = candidate instanceof AST_Assign && candidate.operator.slice(0, -1);
  2386. var funarg = candidate.name instanceof AST_SymbolFunarg;
  2387. var may_throw = return_false;
  2388. if (candidate.may_throw(compressor)) {
  2389. if (funarg && is_async(scope)) continue;
  2390. may_throw = in_try ? function(node) {
  2391. return node.has_side_effects(compressor);
  2392. } : side_effects_external;
  2393. }
  2394. var read_toplevel = false;
  2395. var modify_toplevel = false;
  2396. var defun_scopes = get_defun_scopes(lhs);
  2397. // Locate symbols which may execute code outside of scanning range
  2398. var enclosed = new Dictionary();
  2399. var well_defined = true;
  2400. var lvalues = get_lvalues(candidate);
  2401. var lhs_local = is_lhs_local(lhs);
  2402. var rhs_value = get_rvalue(candidate);
  2403. var rvalue = rhs_value;
  2404. if (!side_effects) {
  2405. if (!compound && rvalue instanceof AST_Sequence) rvalue = rvalue.tail_node();
  2406. side_effects = value_has_side_effects();
  2407. }
  2408. var check_destructured = in_try || !lhs_local ? function(node) {
  2409. return node instanceof AST_Destructured;
  2410. } : return_false;
  2411. var replace_all = replace_all_symbols(candidate);
  2412. var hit = funarg;
  2413. var abort = false;
  2414. var replaced = 0;
  2415. var can_replace = !args || !hit;
  2416. if (!can_replace) {
  2417. for (var j = candidate.arg_index + 1; !abort && j < args.length; j++) {
  2418. if (args[j]) args[j].transform(scanner);
  2419. }
  2420. can_replace = true;
  2421. }
  2422. for (var i = stat_index; !abort && i < statements.length; i++) {
  2423. statements[i].transform(scanner);
  2424. }
  2425. if (value_def) {
  2426. if (!replaced || remaining > replaced + assign_used) {
  2427. candidates.push(hit_stack);
  2428. force_single = true;
  2429. continue;
  2430. }
  2431. if (replaced == assign_pos) assign_used = true;
  2432. var def = lhs.definition();
  2433. abort = false;
  2434. hit_index = 0;
  2435. hit = funarg;
  2436. for (var i = stat_index; !abort && i < statements.length; i++) {
  2437. if (!statements[i].transform(multi_replacer)) statements.splice(i--, 1);
  2438. }
  2439. replaced = candidate instanceof AST_VarDef
  2440. && candidate === hit_stack[hit_stack.length - 1]
  2441. && def.references.length == def.replaced
  2442. && !compressor.exposed(def);
  2443. value_def.last_ref = false;
  2444. value_def.single_use = false;
  2445. changed = true;
  2446. }
  2447. if (replaced) remove_candidate(candidate);
  2448. }
  2449. }
  2450. return changed;
  2451. function signal_abort(node) {
  2452. if (abort) return node;
  2453. if (stop_after === node) abort = true;
  2454. if (stop_if_hit === node) stop_if_hit = null;
  2455. return node;
  2456. }
  2457. function handle_custom_scan_order(node, tt) {
  2458. if (!(node instanceof AST_BlockScope)) return;
  2459. // Skip (non-executed) functions
  2460. if (node instanceof AST_Scope) return node;
  2461. // Scan computed keys, static fields & initializers in class
  2462. if (node instanceof AST_Class) {
  2463. var replace = can_replace;
  2464. can_replace = false;
  2465. if (node.name) node.name.transform(tt);
  2466. if (!abort && node.extends) node.extends.transform(tt);
  2467. var fields = [], stats = [];
  2468. for (var i = 0; !abort && i < node.properties.length; i++) {
  2469. var prop = node.properties[i];
  2470. if (prop.key instanceof AST_Node) prop.key = prop.key.transform(tt);
  2471. if (!prop.static) continue;
  2472. if (prop instanceof AST_ClassField) {
  2473. if (prop.value) fields.push(prop);
  2474. } else if (prop instanceof AST_ClassInit) {
  2475. [].push.apply(stats, prop.value.body);
  2476. }
  2477. }
  2478. for (var i = 0; !abort && i < stats.length; i++) {
  2479. stats[i].transform(tt);
  2480. }
  2481. for (var i = 0; !abort && i < fields.length; i++) {
  2482. fields[i].value.transform(tt);
  2483. }
  2484. can_replace = replace;
  2485. return node;
  2486. }
  2487. // Scan object only in a for-in/of statement
  2488. if (node instanceof AST_ForEnumeration) {
  2489. node.object = node.object.transform(tt);
  2490. abort = true;
  2491. return node;
  2492. }
  2493. // Scan first case expression only in a switch statement
  2494. if (node instanceof AST_Switch) {
  2495. node.expression = node.expression.transform(tt);
  2496. for (var i = 0; !abort && i < node.body.length; i++) {
  2497. var branch = node.body[i];
  2498. if (branch instanceof AST_Case) {
  2499. if (!hit) {
  2500. if (branch !== hit_stack[hit_index]) continue;
  2501. hit_index++;
  2502. }
  2503. branch.expression = branch.expression.transform(tt);
  2504. if (!replace_all || verify_ref) break;
  2505. scan_rhs = false;
  2506. }
  2507. }
  2508. abort = true;
  2509. return node;
  2510. }
  2511. }
  2512. function is_direct_assignment(node, parent) {
  2513. if (parent instanceof AST_Assign) return parent.operator == "=" && parent.left === node;
  2514. if (parent instanceof AST_DefaultValue) return parent.name === node;
  2515. if (parent instanceof AST_DestructuredArray) return true;
  2516. if (parent instanceof AST_DestructuredKeyVal) return parent.value === node;
  2517. }
  2518. function should_stop(node, parent) {
  2519. if (node === rvalue) return true;
  2520. if (parent instanceof AST_For) {
  2521. if (node !== parent.init) return true;
  2522. }
  2523. if (node instanceof AST_Assign) return node.operator != "=" && lhs.equals(node.left);
  2524. if (node instanceof AST_BlockStatement) {
  2525. return defun_scopes && !all(defun_scopes, function(scope) {
  2526. return node !== scope;
  2527. });
  2528. }
  2529. if (node instanceof AST_Call) {
  2530. if (!(lhs instanceof AST_PropAccess)) return false;
  2531. if (!lhs.equals(node.expression)) return false;
  2532. return !(rvalue instanceof AST_LambdaExpression && !rvalue.contains_this());
  2533. }
  2534. if (node instanceof AST_Class) return !compressor.has_directive("use strict");
  2535. if (node instanceof AST_Debugger) return true;
  2536. if (node instanceof AST_Defun) return funarg && lhs.name === node.name.name;
  2537. if (node instanceof AST_DestructuredKeyVal) return node.key instanceof AST_Node;
  2538. if (node instanceof AST_DWLoop) return true;
  2539. if (node instanceof AST_LoopControl) return true;
  2540. if (node instanceof AST_Try) return true;
  2541. if (node instanceof AST_With) return true;
  2542. return false;
  2543. }
  2544. function should_stop_ref(node, parent) {
  2545. if (!(node instanceof AST_SymbolRef)) return false;
  2546. if (node.is_declared(compressor)) {
  2547. if (node.fixed_value()) return false;
  2548. if (can_drop_symbol(node)) {
  2549. return !(parent instanceof AST_PropAccess && parent.expression === node)
  2550. && is_arguments(node.definition());
  2551. }
  2552. } else if (is_direct_assignment(node, parent)) {
  2553. return false;
  2554. }
  2555. if (!replace_all) return true;
  2556. scan_rhs = false;
  2557. return false;
  2558. }
  2559. function in_conditional(node, parent) {
  2560. if (parent instanceof AST_Assign) return parent.left !== node && lazy_op[parent.operator.slice(0, -1)];
  2561. if (parent instanceof AST_Binary) return parent.left !== node && lazy_op[parent.operator];
  2562. if (parent instanceof AST_Call) return parent.optional && parent.expression !== node;
  2563. if (parent instanceof AST_Case) return parent.expression !== node;
  2564. if (parent instanceof AST_Conditional) return parent.condition !== node;
  2565. if (parent instanceof AST_If) return parent.condition !== node;
  2566. if (parent instanceof AST_Sub) return parent.optional && parent.expression !== node;
  2567. }
  2568. function is_last_node(node, parent) {
  2569. if (node instanceof AST_Await) return true;
  2570. if (node.TYPE == "Binary") return !can_drop_op(node, compressor);
  2571. if (node instanceof AST_Call) {
  2572. var def, fn = node.expression;
  2573. if (fn instanceof AST_SymbolRef) {
  2574. def = fn.definition();
  2575. fn = fn.fixed_value();
  2576. }
  2577. if (!(fn instanceof AST_Lambda)) return !node.is_expr_pure(compressor);
  2578. if (def && recursive_ref(compressor, def, fn)) return true;
  2579. if (fn.collapse_scanning) return false;
  2580. fn.collapse_scanning = true;
  2581. var replace = can_replace;
  2582. can_replace = false;
  2583. var after = stop_after;
  2584. var if_hit = stop_if_hit;
  2585. for (var i = 0; !abort && i < fn.argnames.length; i++) {
  2586. if (arg_may_throw(reject, fn.argnames[i], node.args[i])) abort = true;
  2587. }
  2588. if (!abort) {
  2589. if (fn.rest && arg_may_throw(reject, fn.rest, make_node(AST_Array, node, {
  2590. elements: node.args.slice(i),
  2591. }))) {
  2592. abort = true;
  2593. } else if (is_arrow(fn) && fn.value) {
  2594. fn.value.transform(scanner);
  2595. } else for (var i = 0; !abort && i < fn.body.length; i++) {
  2596. var stat = fn.body[i];
  2597. if (stat instanceof AST_Return) {
  2598. if (stat.value) stat.value.transform(scanner);
  2599. break;
  2600. }
  2601. stat.transform(scanner);
  2602. }
  2603. }
  2604. stop_if_hit = if_hit;
  2605. stop_after = after;
  2606. can_replace = replace;
  2607. fn.collapse_scanning = false;
  2608. if (!abort) return false;
  2609. abort = false;
  2610. return true;
  2611. }
  2612. if (node instanceof AST_Class) {
  2613. if (!in_try) return false;
  2614. var base = node.extends;
  2615. if (!base) return false;
  2616. if (base instanceof AST_SymbolRef) base = base.fixed_value();
  2617. return !safe_for_extends(base);
  2618. }
  2619. if (node instanceof AST_Exit) {
  2620. if (in_try) {
  2621. if (in_try.bfinally) return true;
  2622. if (in_try.bcatch && node instanceof AST_Throw) return true;
  2623. }
  2624. return side_effects || lhs instanceof AST_PropAccess || may_modify(lhs);
  2625. }
  2626. if (node instanceof AST_Function) {
  2627. return compressor.option("ie") && node.name && lvalues.has(node.name.name);
  2628. }
  2629. if (node instanceof AST_ObjectIdentity) return symbol_in_lvalues(node);
  2630. if (node instanceof AST_PropAccess) {
  2631. var exp = node.expression;
  2632. if (compressor.option("unsafe")) {
  2633. if (is_undeclared_ref(exp) && global_names[exp.name]) return false;
  2634. if (is_static_fn(exp)) return false;
  2635. }
  2636. if (exp instanceof AST_SymbolRef && is_arguments(exp.definition())) return true;
  2637. if (side_effects) return true;
  2638. if (!well_defined) return true;
  2639. if (value_def) return false;
  2640. if (!in_try && lhs_local) return false;
  2641. if (node.optional) return false;
  2642. return exp.may_throw_on_access(compressor);
  2643. }
  2644. if (node instanceof AST_Spread) return true;
  2645. if (node instanceof AST_SymbolRef) {
  2646. var assign_direct = symbol_in_lvalues(node);
  2647. if (is_undeclared_ref(node) && node.is_declared(compressor)) return false;
  2648. if (assign_direct) return !is_direct_assignment(node, parent);
  2649. if (side_effects && may_modify(node)) return true;
  2650. var def = node.definition();
  2651. return (in_try || def.scope.resolve() !== scope) && !can_drop_symbol(node);
  2652. }
  2653. if (node instanceof AST_Template) return !node.is_expr_pure(compressor);
  2654. if (node instanceof AST_VarDef) {
  2655. if (check_destructured(node.name)) return true;
  2656. return (node.value || parent instanceof AST_Let) && node.name.match_symbol(function(node) {
  2657. return node instanceof AST_SymbolDeclaration
  2658. && (lvalues.has(node.name) || side_effects && may_modify(node));
  2659. }, true);
  2660. }
  2661. if (node instanceof AST_Y