From aa45f6586ebf60643682c41aaf2b66c623bece43 Mon Sep 17 00:00:00 2001 From: Mihai Bazon Date: Mon, 16 Mar 2015 13:16:30 +0200 Subject: [PATCH] rename --prop-cache to --name-cache ... and support storing there variable names as well, to help with multiple invocations when mangling toplevel. --- bin/uglifyjs | 70 ++++++++++++++++++++++++++++++++++------------------ lib/scope.js | 29 ++++++++++++++++++++-- 2 files changed, 73 insertions(+), 26 deletions(-) diff --git a/bin/uglifyjs b/bin/uglifyjs index 5467869b..f2f8f0d9 100755 --- a/bin/uglifyjs +++ b/bin/uglifyjs @@ -69,7 +69,7 @@ You need to pass an argument to this option to specify the name that your module .describe("quotes", "Quote style (0 - auto, 1 - single, 2 - double, 3 - original)") .describe("reserved-file", "File containing reserved names") .describe("mangle-props", "Mangle property names") - .describe("prop-cache", "File to hold mangled properties mapping") + .describe("name-cache", "File to hold mangled names mappings") .alias("p", "prefix") .alias("o", "output") @@ -95,7 +95,7 @@ You need to pass an argument to this option to specify the name that your module .string("wrap") .string("p") .string("reserved-file") - .string("prop-cache") + .string("name-cache") .boolean("expr") .boolean("source-map-include-sources") @@ -170,6 +170,41 @@ if (ARGS.reserved_file) (function(){ } })(); +function readNameCache(key) { + var cache = null; + if (ARGS.name_cache) { + try { + var cache = fs.readFileSync(ARGS.name_cache, "utf8"); + cache = JSON.parse(cache)[key]; + if (!cache) throw "init"; + cache.props = UglifyJS.Dictionary.fromObject(cache.props); + } catch(ex) { + cache = { + cname: -1, + props: new UglifyJS.Dictionary() + }; + } + } + return cache; +} + +function writeNameCache(key, cache) { + if (ARGS.name_cache) { + var data; + try { + data = fs.readFileSync(ARGS.name_cache, "utf8"); + data = JSON.parse(data); + } catch(ex) { + data = {}; + } + data[key] = { + cname: cache.cname, + props: cache.props.toObject() + }; + fs.writeFileSync(ARGS.name_cache, JSON.stringify(data, null, 2), "utf8"); + } +} + if (ARGS.quotes === true) { ARGS.quotes = 3; } @@ -353,36 +388,20 @@ async.eachLimit(files, 1, function (file, cb) { if (ARGS.mangle_props) (function(){ var reserved = RESERVED ? RESERVED.props : null; - var cache = null; - if (ARGS.prop_cache) { - try { - cache = fs.readFileSync(ARGS.prop_cache, "utf8"); - cache = JSON.parse(cache); - cache.props = UglifyJS.Dictionary.fromObject(cache.props); - } catch(ex) { - cache = { - cname: -1, - props: new UglifyJS.Dictionary() - }; - } - } + var cache = readNameCache("props"); TOPLEVEL = UglifyJS.mangle_properties(TOPLEVEL, { reserved: reserved, cache: cache }); - if (ARGS.prop_cache) { - fs.writeFileSync(ARGS.prop_cache, JSON.stringify({ - cname: cache.cname, - props: cache.props.toObject() - }, null, 2), "utf8"); - } + writeNameCache("props", cache); })(); var SCOPE_IS_NEEDED = COMPRESS || MANGLE || ARGS.lint; + var TL_CACHE = readNameCache("vars"); if (SCOPE_IS_NEEDED) { time_it("scope", function(){ - TOPLEVEL.figure_out_scope({ screw_ie8: ARGS.screw_ie8 }); + TOPLEVEL.figure_out_scope({ screw_ie8: ARGS.screw_ie8, cache: TL_CACHE }); if (ARGS.lint) { TOPLEVEL.scope_warnings(); } @@ -397,17 +416,20 @@ async.eachLimit(files, 1, function (file, cb) { if (SCOPE_IS_NEEDED) { time_it("scope", function(){ - TOPLEVEL.figure_out_scope({ screw_ie8: ARGS.screw_ie8 }); - if (MANGLE) { + TOPLEVEL.figure_out_scope({ screw_ie8: ARGS.screw_ie8, cache: TL_CACHE }); + if (MANGLE && !TL_CACHE) { TOPLEVEL.compute_char_frequency(MANGLE); } }); } if (MANGLE) time_it("mangle", function(){ + MANGLE.cache = TL_CACHE; TOPLEVEL.mangle_names(MANGLE); }); + writeNameCache("vars", TL_CACHE); + if (ARGS.source_map_include_sources) { for (var file in SOURCES_CONTENT) { if (SOURCES_CONTENT.hasOwnProperty(file)) { diff --git a/lib/scope.js b/lib/scope.js index 73442a30..6c19c19a 100644 --- a/lib/scope.js +++ b/lib/scope.js @@ -67,18 +67,26 @@ SymbolDef.prototype = { || this.orig[0] instanceof AST_SymbolDefun)); }, mangle: function(options) { - if (!this.mangled_name && !this.unmangleable(options)) { + var cache = options.cache && options.cache.props; + if (this.global && cache && cache.has(this.name)) { + this.mangled_name = cache.get(this.name); + } + else if (!this.mangled_name && !this.unmangleable(options)) { var s = this.scope; if (!options.screw_ie8 && this.orig[0] instanceof AST_SymbolLambda) s = s.parent_scope; this.mangled_name = s.next_mangled(options, this); + if (this.global && cache) { + cache.set(this.name, this.mangled_name); + } } } }; AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){ options = defaults(options, { - screw_ie8: false + screw_ie8: false, + cache: null }); // pass 1: setup scope chaining and handle definitions @@ -183,6 +191,10 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){ } }); self.walk(tw); + + if (options.cache) { + this.cname = options.cache.cname; + } }); AST_Scope.DEFMETHOD("init_scope_vars", function(nesting){ @@ -344,6 +356,15 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options){ // the AST_SymbolDeclaration that it points to). var lname = -1; var to_mangle = []; + + if (options.cache) { + this.globals.each(function(symbol){ + if (options.except.indexOf(symbol.name) < 0) { + to_mangle.push(symbol); + } + }); + } + var tw = new TreeWalker(function(node, descend){ if (node instanceof AST_LabeledStatement) { // lname is incremented when we get to the AST_Label @@ -378,6 +399,10 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options){ }); this.walk(tw); to_mangle.forEach(function(def){ def.mangle(options) }); + + if (options.cache) { + options.cache.cname = this.cname; + } }); AST_Toplevel.DEFMETHOD("compute_char_frequency", function(options){ -- 2.34.1