From 5fd12451f90eb6ae8f009da41197ad5da9e0fee8 Mon Sep 17 00:00:00 2001 From: Ville Lautanala Date: Sat, 23 May 2015 01:46:08 +0300 Subject: [PATCH 01/15] Control keeping function arguments with a single option --- lib/compress.js | 4 ++-- test/compress/drop-unused.js | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/compress.js b/lib/compress.js index 51dd66f8..8360473f 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -61,7 +61,7 @@ function Compressor(options, false_by_default) { loops : !false_by_default, unused : !false_by_default, hoist_funs : !false_by_default, - keep_fargs : false, + keep_fargs : true, keep_fnames : false, hoist_vars : false, if_return : !false_by_default, @@ -1087,7 +1087,7 @@ merge(Compressor.prototype, { var tt = new TreeTransformer( function before(node, descend, in_list) { if (node instanceof AST_Lambda && !(node instanceof AST_Accessor)) { - if (compressor.option("unsafe") && !compressor.option("keep_fargs")) { + if (!compressor.option("keep_fargs")) { for (var a = node.argnames, i = a.length; --i >= 0;) { var sym = a[i]; if (sym.unreferenced()) { diff --git a/test/compress/drop-unused.js b/test/compress/drop-unused.js index c1cf5c3c..035a428e 100644 --- a/test/compress/drop-unused.js +++ b/test/compress/drop-unused.js @@ -1,5 +1,5 @@ unused_funarg_1: { - options = { unused: true, unsafe: true }; + options = { unused: true, keep_fargs: false }; input: { function f(a, b, c, d, e) { return a + b; @@ -13,7 +13,7 @@ unused_funarg_1: { } unused_funarg_2: { - options = { unused: true, unsafe: true }; + options = { unused: true, keep_fargs: false }; input: { function f(a, b, c, d, e) { return a + c; @@ -173,7 +173,7 @@ keep_fnames: { } expect: { function foo() { - return function bar() {}; + return function bar(baz) {}; } } } From 20542a37a88393393279ae031f8925efed1f4573 Mon Sep 17 00:00:00 2001 From: Kyle Mitchell Date: Mon, 4 May 2015 23:33:09 +0000 Subject: [PATCH 02/15] use a valid SPDX license identifier --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 0bf1de09..c50a64f6 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "description": "JavaScript parser, mangler/compressor and beautifier toolkit", "homepage": "http://lisperator.net/uglifyjs", "author": "Mihai Bazon (http://lisperator.net/)", - "license": "BSD", + "license": "BSD-2-Clause", "version": "2.4.24", "engines": { "node": ">=0.8.0" From 33528002b496728457cccd9ddf54d2e50bc7e3f2 Mon Sep 17 00:00:00 2001 From: Mihai Bazon Date: Thu, 24 Sep 2015 17:55:37 +0300 Subject: [PATCH 03/15] Fix wrap_commonjs to include code first (code could have directives, i.e. "use strict") --- lib/ast.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/lib/ast.js b/lib/ast.js index 2e539cff..c3176702 100644 --- a/lib/ast.js +++ b/lib/ast.js @@ -329,12 +329,11 @@ var AST_Toplevel = DEFNODE("Toplevel", "globals", { } })); } - var wrapped_tl = "(function(exports, global){ global['" + name + "'] = exports; '$ORIG'; '$EXPORTS'; }({}, (function(){return this}())))"; + var wrapped_tl = "(function(exports, global){ '$ORIG'; '$EXPORTS'; global['" + name + "'] = exports; }({}, (function(){return this}())))"; wrapped_tl = parse(wrapped_tl); wrapped_tl = wrapped_tl.transform(new TreeTransformer(function before(node){ - if (node instanceof AST_SimpleStatement) { - node = node.body; - if (node instanceof AST_String) switch (node.getValue()) { + if (node instanceof AST_Directive) { + switch (node.value) { case "$ORIG": return MAP.splice(self.body); case "$EXPORTS": From 99233c44cc125fa1a96a47b863dbfb3ec0c3fadc Mon Sep 17 00:00:00 2001 From: Mihai Bazon Date: Thu, 24 Sep 2015 17:57:47 +0300 Subject: [PATCH 04/15] No longer use `vm` to load code. Improves performance 2x on node > 0.10. Ref #636 --- bin/uglifyjs | 1 - lib/ast.js | 1 + tools/exports.js | 16 ++++++++++++++++ tools/node.js | 40 ++++++++++------------------------------ 4 files changed, 27 insertions(+), 31 deletions(-) create mode 100644 tools/exports.js diff --git a/bin/uglifyjs b/bin/uglifyjs index 4768f766..fbb053d8 100755 --- a/bin/uglifyjs +++ b/bin/uglifyjs @@ -254,7 +254,6 @@ if (ARGS.self) { } files = UglifyJS.FILES; if (!ARGS.wrap) ARGS.wrap = "UglifyJS"; - ARGS.export_all = true; } var ORIG_MAP = ARGS.in_source_map; diff --git a/lib/ast.js b/lib/ast.js index c3176702..c5ec8163 100644 --- a/lib/ast.js +++ b/lib/ast.js @@ -81,6 +81,7 @@ function DEFNODE(type, props, methods, base) { ctor.DEFMETHOD = function(name, method) { this.prototype[name] = method; }; + exports["AST_" + type] = ctor; return ctor; }; diff --git a/tools/exports.js b/tools/exports.js new file mode 100644 index 00000000..a27cef90 --- /dev/null +++ b/tools/exports.js @@ -0,0 +1,16 @@ +exports["Compressor"] = Compressor; +exports["DefaultsError"] = DefaultsError; +exports["Dictionary"] = Dictionary; +exports["JS_Parse_Error"] = JS_Parse_Error; +exports["MAP"] = MAP; +exports["OutputStream"] = OutputStream; +exports["SourceMap"] = SourceMap; +exports["TreeTransformer"] = TreeTransformer; +exports["TreeWalker"] = TreeWalker; +exports["base54"] = base54; +exports["defaults"] = defaults; +exports["mangle_properties"] = mangle_properties; +exports["merge"] = merge; +exports["parse"] = parse; +exports["push_uniq"] = push_uniq; +exports["string_template"] = string_template; diff --git a/tools/node.js b/tools/node.js index eba2bc1d..f6048661 100644 --- a/tools/node.js +++ b/tools/node.js @@ -1,26 +1,5 @@ var path = require("path"); var fs = require("fs"); -var vm = require("vm"); - -var UglifyJS = vm.createContext({ - console : console, - process : process, - Buffer : Buffer, - MOZ_SourceMap : require("source-map") -}); - -function load_global(file) { - file = path.resolve(path.dirname(module.filename), file); - try { - var code = fs.readFileSync(file, "utf8"); - return vm.runInContext(code, UglifyJS, file); - } catch(ex) { - // XXX: in case of a syntax error, the message is kinda - // useless. (no location information). - console.log("ERROR in file: " + file + " / " + ex); - process.exit(1); - } -}; var FILES = exports.FILES = [ "../lib/utils.js", @@ -32,24 +11,25 @@ var FILES = exports.FILES = [ "../lib/compress.js", "../lib/sourcemap.js", "../lib/mozilla-ast.js", - "../lib/propmangle.js" + "../lib/propmangle.js", + "./exports.js", ].map(function(file){ return fs.realpathSync(path.join(path.dirname(__filename), file)); }); -FILES.forEach(load_global); +var UglifyJS = exports; + +new Function("MOZ_SourceMap", "exports", FILES.map(function(file){ + return fs.readFileSync(file, "utf8"); +}).join("\n\n"))( + require("source-map"), + UglifyJS +); UglifyJS.AST_Node.warn_function = function(txt) { console.error("WARN: %s", txt); }; -// XXX: perhaps we shouldn't export everything but heck, I'm lazy. -for (var i in UglifyJS) { - if (UglifyJS.hasOwnProperty(i)) { - exports[i] = UglifyJS[i]; - } -} - exports.minify = function(files, options) { options = UglifyJS.defaults(options, { spidermonkey : false, From 6637c267a53ae7e21807da1da862fbae0bb880fd Mon Sep 17 00:00:00 2001 From: Mihai Bazon Date: Thu, 24 Sep 2015 18:12:06 +0300 Subject: [PATCH 05/15] Fix mozilla-ast after module loading changes Need to explicitly qualify stuff now, since it's not evaluated in some global scope. Ref #636 --- lib/mozilla-ast.js | 6 +++--- test/mozilla-ast.js | 2 +- tools/exports.js | 1 + 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/mozilla-ast.js b/lib/mozilla-ast.js index 1deb18e2..ac53ca27 100644 --- a/lib/mozilla-ast.js +++ b/lib/mozilla-ast.js @@ -399,7 +399,7 @@ function map(moztype, mytype, propmap) { var moz_to_me = "function From_Moz_" + moztype + "(M){\n"; - moz_to_me += "return new " + mytype.name + "({\n" + + moz_to_me += "return new U2." + mytype.name + "({\n" + "start: my_start_token(M),\n" + "end: my_end_token(M)"; @@ -442,8 +442,8 @@ //me_to_moz = parse(me_to_moz).print_to_string({ beautify: true }); //console.log(moz_to_me); - moz_to_me = new Function("my_start_token", "my_end_token", "from_moz", "return(" + moz_to_me + ")")( - my_start_token, my_end_token, from_moz + moz_to_me = new Function("U2", "my_start_token", "my_end_token", "from_moz", "return(" + moz_to_me + ")")( + exports, my_start_token, my_end_token, from_moz ); me_to_moz = new Function("to_moz", "to_moz_block", "return(" + me_to_moz + ")")( to_moz, to_moz_block diff --git a/test/mozilla-ast.js b/test/mozilla-ast.js index 02628676..b5c6c6ed 100644 --- a/test/mozilla-ast.js +++ b/test/mozilla-ast.js @@ -100,4 +100,4 @@ module.exports = function(options) { } process.stdout.write(prefix + "Probability of error is less than " + (100 / options.iterations) + "%, stopping.\n"); -}; \ No newline at end of file +}; diff --git a/tools/exports.js b/tools/exports.js index a27cef90..5007e03b 100644 --- a/tools/exports.js +++ b/tools/exports.js @@ -14,3 +14,4 @@ exports["merge"] = merge; exports["parse"] = parse; exports["push_uniq"] = push_uniq; exports["string_template"] = string_template; +exports["is_identifier"] = is_identifier; From 233fb62bd818272ad07ca30636d8d9f1f9fcc85e Mon Sep 17 00:00:00 2001 From: Mihai Bazon Date: Thu, 24 Sep 2015 18:26:23 +0300 Subject: [PATCH 06/15] Disable node 0.8 in Travis --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index c33b24d1..511e4476 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,7 +4,6 @@ node_js: - "iojs" - "0.12" - "0.10" - - "0.8" matrix: fast_finish: true sudo: false From 7ee1ec91a206e9b88bdbd4e47c9d206f91d90e11 Mon Sep 17 00:00:00 2001 From: Anthony Van de Gejuchte Date: Thu, 24 Sep 2015 17:41:52 +0200 Subject: [PATCH 07/15] Add node 4.x in Travis --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 511e4476..0324385f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,6 +4,7 @@ node_js: - "iojs" - "0.12" - "0.10" + - "4" matrix: fast_finish: true sudo: false From c69294c44929d728807bdeabac8a024f108f198b Mon Sep 17 00:00:00 2001 From: Anthony Van de Gejuchte Date: Fri, 20 Feb 2015 16:08:01 +0100 Subject: [PATCH 08/15] Implement shebang support --- lib/output.js | 111 +++++++++++++++++++++++++++----------------------- lib/parse.js | 12 +++++- 2 files changed, 69 insertions(+), 54 deletions(-) diff --git a/lib/output.js b/lib/output.js index 396c6a29..3b4c1469 100644 --- a/lib/output.js +++ b/lib/output.js @@ -60,6 +60,7 @@ function OutputStream(options) { bracketize : false, semicolons : true, comments : false, + shebang : true, preserve_line : false, screw_ie8 : false, preamble : null, @@ -403,63 +404,69 @@ function OutputStream(options) { AST_Node.DEFMETHOD("add_comments", function(output){ var c = output.option("comments"), self = this; - if (c) { - var start = self.start; - if (start && !start._comments_dumped) { - start._comments_dumped = true; - var comments = start.comments_before || []; + var start = self.start; + if (start && !start._comments_dumped) { + start._comments_dumped = true; + var comments = start.comments_before || []; - // XXX: ugly fix for https://github.com/mishoo/UglifyJS2/issues/112 - // and https://github.com/mishoo/UglifyJS2/issues/372 - if (self instanceof AST_Exit && self.value) { - self.value.walk(new TreeWalker(function(node){ - if (node.start && node.start.comments_before) { - comments = comments.concat(node.start.comments_before); - node.start.comments_before = []; - } - if (node instanceof AST_Function || - node instanceof AST_Array || - node instanceof AST_Object) - { - return true; // don't go inside. - } - })); - } - - if (c.test) { - comments = comments.filter(function(comment){ - return c.test(comment.value); - }); - } else if (typeof c == "function") { - comments = comments.filter(function(comment){ - return c(self, comment); - }); - } - - // Keep single line comments after nlb, after nlb - if (!output.option("beautify") && comments.length > 0 && - /comment[134]/.test(comments[0].type) && - output.col() !== 0 && comments[0].nlb) - { - output.print("\n"); - } - - comments.forEach(function(c){ - if (/comment[134]/.test(c.type)) { - output.print("//" + c.value + "\n"); - output.indent(); + // XXX: ugly fix for https://github.com/mishoo/UglifyJS2/issues/112 + // and https://github.com/mishoo/UglifyJS2/issues/372 + if (self instanceof AST_Exit && self.value) { + self.value.walk(new TreeWalker(function(node){ + if (node.start && node.start.comments_before) { + comments = comments.concat(node.start.comments_before); + node.start.comments_before = []; } - else if (c.type == "comment2") { - output.print("/*" + c.value + "*/"); - if (start.nlb) { - output.print("\n"); - output.indent(); - } else { - output.space(); - } + if (node instanceof AST_Function || + node instanceof AST_Array || + node instanceof AST_Object) + { + return true; // don't go inside. } + })); + } + + if (!c) { + comments = comments.filter(function(comment) { + return comment.type == "comment5"; + }); + } else if (c.test) { + comments = comments.filter(function(comment){ + return c.test(comment.value) || comment.type == "comment5"; + }); + } else if (typeof c == "function") { + comments = comments.filter(function(comment){ + return c(self, comment) || comment.type == "comment5"; }); } + + // Keep single line comments after nlb, after nlb + if (!output.option("beautify") && comments.length > 0 && + /comment[134]/.test(comments[0].type) && + output.col() !== 0 && comments[0].nlb) + { + output.print("\n"); + } + + comments.forEach(function(c){ + if (/comment[134]/.test(c.type)) { + output.print("//" + c.value + "\n"); + output.indent(); + } + else if (c.type == "comment2") { + output.print("/*" + c.value + "*/"); + if (start.nlb) { + output.print("\n"); + output.indent(); + } else { + output.space(); + } + } + else if (output.pos() === 0 && c.type == "comment5" && output.option("shebang")) { + output.print("#!" + c.value + "\n"); + output.indent(); + } + }); } }); diff --git a/lib/parse.js b/lib/parse.js index 496a673f..cbfb5757 100644 --- a/lib/parse.js +++ b/lib/parse.js @@ -210,7 +210,7 @@ function is_token(token, type, val) { var EX_EOF = {}; -function tokenizer($TEXT, filename, html5_comments) { +function tokenizer($TEXT, filename, html5_comments, shebang) { var S = { text : $TEXT, @@ -568,6 +568,13 @@ function tokenizer($TEXT, filename, html5_comments) { if (PUNC_CHARS(ch)) return token("punc", next()); if (OPERATOR_CHARS(ch)) return read_operator(); if (code == 92 || is_identifier_start(code)) return read_word(); + + if (shebang) { + if (S.pos == 0 && looking_at("#!")) { + forward(2); + return skip_line_comment("comment5"); + } + } parse_error("Unexpected character '" + ch + "'"); }; @@ -637,12 +644,13 @@ function parse($TEXT, options) { expression : false, html5_comments : true, bare_returns : false, + shebang : true, }); var S = { input : (typeof $TEXT == "string" ? tokenizer($TEXT, options.filename, - options.html5_comments) + options.html5_comments, options.shebang) : $TEXT), token : null, prev : null, From 593677d2ff04f61a2230c18722ec89b820ee0307 Mon Sep 17 00:00:00 2001 From: kzc Date: Mon, 5 Oct 2015 19:51:09 -0400 Subject: [PATCH 09/15] Add proper support for "use asm"; blocks. Disable -c optimization within "use asm"; sections and preserve floating point literals in their original form. Non-asm.js sections are optimized as before. Asm.js sections can still be mangled and minified of whitespace. No special command line flags are required. --- bin/uglifyjs | 2 +- lib/compress.js | 26 ++++++++++++++------------ lib/output.js | 6 +++++- lib/parse.js | 3 +++ lib/scope.js | 4 ++++ 5 files changed, 27 insertions(+), 14 deletions(-) diff --git a/bin/uglifyjs b/bin/uglifyjs index fbb053d8..00342b8f 100755 --- a/bin/uglifyjs +++ b/bin/uglifyjs @@ -401,7 +401,7 @@ async.eachLimit(files, 1, function (file, cb) { writeNameCache("props", cache); })(); - var SCOPE_IS_NEEDED = COMPRESS || MANGLE || ARGS.lint; + var SCOPE_IS_NEEDED = COMPRESS || MANGLE || BEAUTIFY || ARGS.lint; var TL_CACHE = readNameCache("vars"); if (SCOPE_IS_NEEDED) { diff --git a/lib/compress.js b/lib/compress.js index 8360473f..216aade9 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -111,6 +111,7 @@ merge(Compressor.prototype, { node.DEFMETHOD("optimize", function(compressor){ var self = this; if (self._optimized) return self; + if (compressor.has_directive("use asm")) return self; var opt = optimizer(self, compressor); opt._optimized = true; if (opt === self) return opt; @@ -1026,6 +1027,7 @@ merge(Compressor.prototype, { AST_Scope.DEFMETHOD("drop_unused", function(compressor){ var self = this; + if (compressor.has_directive("use asm")) return self; if (compressor.option("unused") && !(self instanceof AST_Toplevel) && !self.uses_eval @@ -1205,9 +1207,10 @@ merge(Compressor.prototype, { }); AST_Scope.DEFMETHOD("hoist_declarations", function(compressor){ + var self = this; + if (compressor.has_directive("use asm")) return self; var hoist_funs = compressor.option("hoist_funs"); var hoist_vars = compressor.option("hoist_vars"); - var self = this; if (hoist_funs || hoist_vars) { var dirs = []; var hoisted = []; @@ -2028,15 +2031,14 @@ merge(Compressor.prototype, { var commutativeOperators = makePredicate("== === != !== * & | ^"); OPT(AST_Binary, function(self, compressor){ - var reverse = compressor.has_directive("use asm") ? noop - : function(op, force) { - if (force || !(self.left.has_side_effects(compressor) || self.right.has_side_effects(compressor))) { - if (op) self.operator = op; - var tmp = self.left; - self.left = self.right; - self.right = tmp; - } - }; + function reverse(op, force) { + if (force || !(self.left.has_side_effects(compressor) || self.right.has_side_effects(compressor))) { + if (op) self.operator = op; + var tmp = self.left; + self.left = self.right; + self.right = tmp; + } + } if (commutativeOperators(self.operator)) { if (self.right instanceof AST_Constant && !(self.left instanceof AST_Constant)) { @@ -2104,10 +2106,10 @@ merge(Compressor.prototype, { if (compressor.option("conditionals")) { if (self.operator == "&&") { var ll = self.left.evaluate(compressor); - var rr = self.right.evaluate(compressor); if (ll.length > 1) { if (ll[1]) { compressor.warn("Condition left of && always true [{file}:{line},{col}]", self.start); + var rr = self.right.evaluate(compressor); return rr[0]; } else { compressor.warn("Condition left of && always false [{file}:{line},{col}]", self.start); @@ -2117,13 +2119,13 @@ merge(Compressor.prototype, { } else if (self.operator == "||") { var ll = self.left.evaluate(compressor); - var rr = self.right.evaluate(compressor); if (ll.length > 1) { if (ll[1]) { compressor.warn("Condition left of || always true [{file}:{line},{col}]", self.start); return ll[0]; } else { compressor.warn("Condition left of || always false [{file}:{line},{col}]", self.start); + var rr = self.right.evaluate(compressor); return rr[0]; } } diff --git a/lib/output.js b/lib/output.js index 3b4c1469..06c1e429 100644 --- a/lib/output.js +++ b/lib/output.js @@ -1158,7 +1158,11 @@ function OutputStream(options) { output.print_string(self.getValue(), self.quote); }); DEFPRINT(AST_Number, function(self, output){ - output.print(make_num(self.getValue())); + if (self.value_string !== undefined && self.scope && self.scope.has_directive('use asm')) { + output.print(self.value_string); + } else { + output.print(make_num(self.getValue())); + } }); function regexp_safe_literal(code) { diff --git a/lib/parse.js b/lib/parse.js index cbfb5757..830b5227 100644 --- a/lib/parse.js +++ b/lib/parse.js @@ -1149,6 +1149,9 @@ function parse($TEXT, options) { break; case "num": ret = new AST_Number({ start: tok, end: tok, value: tok.value }); + var value_string = $TEXT.substring(tok.pos, tok.endpos); + if (value_string.indexOf('.') >= 0) + ret.value_string = value_string; break; case "string": ret = new AST_String({ diff --git a/lib/scope.js b/lib/scope.js index 6c19c19a..06bd65ae 100644 --- a/lib/scope.js +++ b/lib/scope.js @@ -119,6 +119,10 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){ push_uniq(scope.directives, node.value); return true; } + if (node instanceof AST_Number) { + node.scope = scope; + return true; + } if (node instanceof AST_With) { for (var s = scope; s; s = s.parent_scope) s.uses_with = true; From 0d952ae43de50d85a2315b2a94594eaf5f498009 Mon Sep 17 00:00:00 2001 From: kzc Date: Tue, 6 Oct 2015 17:05:36 -0400 Subject: [PATCH 10/15] add asm.js test --- test/compress/asm.js | 106 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 test/compress/asm.js diff --git a/test/compress/asm.js b/test/compress/asm.js new file mode 100644 index 00000000..c3018485 --- /dev/null +++ b/test/compress/asm.js @@ -0,0 +1,106 @@ +asm_mixed: { + options = { + sequences : true, + properties : true, + dead_code : true, + drop_debugger : true, + conditionals : true, + comparisons : true, + evaluate : true, + booleans : true, + loops : true, + unused : true, + hoist_funs : true, + keep_fargs : true, + keep_fnames : false, + hoist_vars : true, + if_return : true, + join_vars : true, + cascade : true, + side_effects : true, + negate_iife : true + }; + input: { + // adapted from http://asmjs.org/spec/latest/ + function asm_GeometricMean(stdlib, foreign, buffer) { + "use asm"; + var exp = stdlib.Math.exp; + var log = stdlib.Math.log; + var values = new stdlib.Float64Array(buffer); + function logSum(start, end) { + start = start|0; + end = end|0; + var sum = 0.0, p = 0, q = 0; + // asm.js forces byte addressing of the heap by requiring shifting by 3 + for (p = start << 3, q = end << 3; (p|0) < (q|0); p = (p + 8)|0) { + sum = sum + +log(values[p>>3]); + } + return +sum; + } + function geometricMean(start, end) { + start = start|0; + end = end|0; + return +exp(+logSum(start, end) / +((end - start)|0)); + } + return { geometricMean: geometricMean }; + } + function no_asm_GeometricMean(stdlib, foreign, buffer) { + var exp = stdlib.Math.exp; + var log = stdlib.Math.log; + var values = new stdlib.Float64Array(buffer); + function logSum(start, end) { + start = start|0; + end = end|0; + var sum = 0.0, p = 0, q = 0; + // asm.js forces byte addressing of the heap by requiring shifting by 3 + for (p = start << 3, q = end << 3; (p|0) < (q|0); p = (p + 8)|0) { + sum = sum + +log(values[p>>3]); + } + return +sum; + } + function geometricMean(start, end) { + start = start|0; + end = end|0; + return +exp(+logSum(start, end) / +((end - start)|0)); + } + return { geometricMean: geometricMean }; + } + } + expect: { + function asm_GeometricMean(stdlib, foreign, buffer) { + "use asm"; + var exp = stdlib.Math.exp; + var log = stdlib.Math.log; + var values = new stdlib.Float64Array(buffer); + function logSum(start, end) { + start = start | 0; + end = end | 0; + var sum = 0.0, p = 0, q = 0; + for (p = start << 3, q = end << 3; (p | 0) < (q | 0); p = p + 8 | 0) { + sum = sum + +log(values[p >> 3]); + } + return +sum; + } + function geometricMean(start, end) { + start = start | 0; + end = end | 0; + return +exp(+logSum(start, end) / +(end - start | 0)); + } + return { geometricMean: geometricMean }; + } + function no_asm_GeometricMean(stdlib, foreign, buffer) { + function logSum(start, end) { + start = 0 | start, end = 0 | end; + var sum = 0, p = 0, q = 0; + for (p = start << 3, q = end << 3; (0 | q) > (0 | p); p = p + 8 | 0) sum += +log(values[p >> 3]); + return +sum; + } + function geometricMean(start, end) { + return start = 0 | start, end = 0 | end, +exp(+logSum(start, end) / +(end - start | 0)); + } + var exp = stdlib.Math.exp, log = stdlib.Math.log, values = new stdlib.Float64Array(buffer); + return { geometricMean: geometricMean }; + } + } +} + From 99945fcd040b3f28360d69f5b8ab7b679e7b3375 Mon Sep 17 00:00:00 2001 From: SpainTrain Date: Thu, 24 Sep 2015 16:24:50 -0400 Subject: [PATCH 11/15] Pin dependencies with npm shrinkwrap * Use `npm run shrinkwrap` to create a shrinkwrap file with all dependencies pinned * Update dependency `source-map` to latest (Closes #738) --- npm-shrinkwrap.json | 128 ++++++++++++++++++++++++++++++++++++++++++++ package.json | 3 +- 2 files changed, 130 insertions(+), 1 deletion(-) create mode 100644 npm-shrinkwrap.json diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json new file mode 100644 index 00000000..760575c0 --- /dev/null +++ b/npm-shrinkwrap.json @@ -0,0 +1,128 @@ +{ + "name": "uglify-js", + "version": "2.4.24", + "dependencies": { + "abbrev": { + "version": "1.0.7", + "from": "abbrev@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.7.tgz" + }, + "amdefine": { + "version": "1.0.0", + "from": "amdefine@>=0.0.4", + "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.0.tgz" + }, + "async": { + "version": "0.2.10", + "from": "async@>=0.2.6 <0.3.0", + "resolved": "https://registry.npmjs.org/async/-/async-0.2.10.tgz" + }, + "camelcase": { + "version": "1.2.1", + "from": "camelcase@>=1.0.2 <2.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz" + }, + "decamelize": { + "version": "1.0.0", + "from": "decamelize@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.0.0.tgz" + }, + "deep-is": { + "version": "0.1.3", + "from": "deep-is@>=0.1.2 <0.2.0", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz" + }, + "esprima": { + "version": "1.1.1", + "from": "esprima@>=1.1.1 <1.2.0", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.1.1.tgz" + }, + "estraverse": { + "version": "1.5.1", + "from": "estraverse@>=1.5.1 <1.6.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-1.5.1.tgz" + }, + "esutils": { + "version": "1.0.0", + "from": "esutils@>=1.0.0 <1.1.0", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-1.0.0.tgz" + }, + "fast-levenshtein": { + "version": "1.0.7", + "from": "fast-levenshtein@>=1.0.0 <1.1.0", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-1.0.7.tgz" + }, + "levn": { + "version": "0.2.5", + "from": "levn@>=0.2.5 <0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.2.5.tgz" + }, + "nopt": { + "version": "2.1.2", + "from": "nopt@>=2.1.2 <2.2.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-2.1.2.tgz" + }, + "optionator": { + "version": "0.5.0", + "from": "optionator@>=0.5.0 <0.6.0", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.5.0.tgz" + }, + "prelude-ls": { + "version": "1.1.2", + "from": "prelude-ls@>=1.1.1 <1.2.0", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz" + }, + "reflect": { + "version": "0.1.3", + "from": "git://github.com/zaach/reflect.js.git", + "resolved": "git://github.com/zaach/reflect.js.git#286bcd79661c96ecc404357d3c0e35fdb54a6967" + }, + "source-map": { + "version": "0.5.1", + "from": "source-map@>=0.5.1 <0.6.0", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.1.tgz" + }, + "type-check": { + "version": "0.3.1", + "from": "type-check@>=0.3.1 <0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.1.tgz" + }, + "uglify-js": { + "version": "2.4.24", + "from": "git://github.com/mishoo/UglifyJS2.git", + "resolved": "git://github.com/mishoo/UglifyJS2.git#2a06c7758e24a64740473c8031eafbb7fefa213f", + "dependencies": { + "source-map": { + "version": "0.1.34", + "from": "source-map@0.1.34", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.34.tgz" + } + } + }, + "uglify-to-browserify": { + "version": "1.0.2", + "from": "uglify-to-browserify@>=1.0.0 <1.1.0", + "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz" + }, + "window-size": { + "version": "0.1.0", + "from": "window-size@0.1.0", + "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz" + }, + "wordwrap": { + "version": "0.0.2", + "from": "wordwrap@0.0.2", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz" + }, + "yargs": { + "version": "3.5.4", + "from": "yargs@>=3.5.4 <3.6.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.5.4.tgz" + }, + "zeparser": { + "version": "0.0.7", + "from": "git://github.com/qfox/ZeParser.git", + "resolved": "git://github.com/qfox/ZeParser.git#c99240c5ba7054c467733800ff38265958a2dda9" + } + } +} diff --git a/package.json b/package.json index c50a64f6..51b309b9 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,7 @@ ], "dependencies": { "async": "~0.2.6", - "source-map": "0.1.34", + "source-map": "~0.5.1", "uglify-to-browserify": "~1.0.0", "yargs": "~3.5.4" }, @@ -46,6 +46,7 @@ ] }, "scripts": { + "shrinkwrap": "rm ./npm-shrinkwrap.json; rm -rf ./node_modules; npm i && npm shrinkwrap && npm outdated", "test": "node test/run-tests.js" } } From 4d2f7d83af839d78a381fc4faa79dbea3b2c8070 Mon Sep 17 00:00:00 2001 From: kzc Date: Wed, 7 Oct 2015 13:10:53 -0400 Subject: [PATCH 12/15] Fix handling of "use asm" when no command line flags are passed to uglifyjs. SCOPE_IS_NEEDED is unconditionally true now. Refactored floating point literal parsing to be more in keeping with the AST class design. --- bin/uglifyjs | 2 +- lib/ast.js | 5 +++-- lib/output.js | 6 ++++-- lib/parse.js | 11 ++++++----- 4 files changed, 14 insertions(+), 10 deletions(-) diff --git a/bin/uglifyjs b/bin/uglifyjs index 00342b8f..eb970c60 100755 --- a/bin/uglifyjs +++ b/bin/uglifyjs @@ -401,7 +401,7 @@ async.eachLimit(files, 1, function (file, cb) { writeNameCache("props", cache); })(); - var SCOPE_IS_NEEDED = COMPRESS || MANGLE || BEAUTIFY || ARGS.lint; + var SCOPE_IS_NEEDED = true; var TL_CACHE = readNameCache("vars"); if (SCOPE_IS_NEEDED) { diff --git a/lib/ast.js b/lib/ast.js index c5ec8163..e7952847 100644 --- a/lib/ast.js +++ b/lib/ast.js @@ -864,10 +864,11 @@ var AST_String = DEFNODE("String", "value quote", { } }, AST_Constant); -var AST_Number = DEFNODE("Number", "value", { +var AST_Number = DEFNODE("Number", "value literal", { $documentation: "A number literal", $propdoc: { - value: "[number] the numeric value" + value: "[number] the numeric value", + literal: "[string] numeric value as string (optional)" } }, AST_Constant); diff --git a/lib/output.js b/lib/output.js index 06c1e429..c15f3b20 100644 --- a/lib/output.js +++ b/lib/output.js @@ -1158,8 +1158,10 @@ function OutputStream(options) { output.print_string(self.getValue(), self.quote); }); DEFPRINT(AST_Number, function(self, output){ - if (self.value_string !== undefined && self.scope && self.scope.has_directive('use asm')) { - output.print(self.value_string); + if (self.literal !== undefined + && +self.literal === self.value /* paranoid check */ + && self.scope && self.scope.has_directive('use asm')) { + output.print(self.literal); } else { output.print(make_num(self.getValue())); } diff --git a/lib/parse.js b/lib/parse.js index 830b5227..1ab03589 100644 --- a/lib/parse.js +++ b/lib/parse.js @@ -335,7 +335,11 @@ function tokenizer($TEXT, filename, html5_comments, shebang) { if (prefix) num = prefix + num; var valid = parse_js_number(num); if (!isNaN(valid)) { - return token("num", valid); + var tok = token("num", valid); + if (num.indexOf('.') >= 0) { + tok.literal = num; + } + return tok; } else { parse_error("Invalid syntax: " + num); } @@ -1148,10 +1152,7 @@ function parse($TEXT, options) { ret = _make_symbol(AST_SymbolRef); break; case "num": - ret = new AST_Number({ start: tok, end: tok, value: tok.value }); - var value_string = $TEXT.substring(tok.pos, tok.endpos); - if (value_string.indexOf('.') >= 0) - ret.value_string = value_string; + ret = new AST_Number({ start: tok, end: tok, value: tok.value, literal: tok.literal }); break; case "string": ret = new AST_String({ From 6500f8c52cc75c45a4fac16324d4e531e372874d Mon Sep 17 00:00:00 2001 From: kzc Date: Wed, 7 Oct 2015 15:33:24 -0400 Subject: [PATCH 13/15] get rid of SCOPE_IS_NEEDED as it was always true --- bin/uglifyjs | 29 ++++++++++++----------------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/bin/uglifyjs b/bin/uglifyjs index eb970c60..f82d43cb 100755 --- a/bin/uglifyjs +++ b/bin/uglifyjs @@ -401,17 +401,14 @@ async.eachLimit(files, 1, function (file, cb) { writeNameCache("props", cache); })(); - var SCOPE_IS_NEEDED = true; var TL_CACHE = readNameCache("vars"); - if (SCOPE_IS_NEEDED) { - time_it("scope", function(){ - TOPLEVEL.figure_out_scope({ screw_ie8: ARGS.screw_ie8, cache: TL_CACHE }); - if (ARGS.lint) { - TOPLEVEL.scope_warnings(); - } - }); - } + time_it("scope", function(){ + TOPLEVEL.figure_out_scope({ screw_ie8: ARGS.screw_ie8, cache: TL_CACHE }); + if (ARGS.lint) { + TOPLEVEL.scope_warnings(); + } + }); if (COMPRESS) { time_it("squeeze", function(){ @@ -419,14 +416,12 @@ async.eachLimit(files, 1, function (file, cb) { }); } - if (SCOPE_IS_NEEDED) { - time_it("scope", function(){ - TOPLEVEL.figure_out_scope({ screw_ie8: ARGS.screw_ie8, cache: TL_CACHE }); - if (MANGLE && !TL_CACHE) { - TOPLEVEL.compute_char_frequency(MANGLE); - } - }); - } + time_it("scope", function(){ + 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; From e870c7db45aca4cb1585d5b10e631ab293e8dc3a Mon Sep 17 00:00:00 2001 From: kzc Date: Wed, 7 Oct 2015 16:31:57 -0400 Subject: [PATCH 14/15] have minify() call figure_out_scope() if needed to produce well formed "use asm" code --- tools/node.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/tools/node.js b/tools/node.js index f6048661..7e61d2a1 100644 --- a/tools/node.js +++ b/tools/node.js @@ -45,6 +45,7 @@ exports.minify = function(files, options) { UglifyJS.base54.reset(); // 1. parse + var haveScope = false; var toplevel = null, sourcesContent = {}; @@ -73,6 +74,7 @@ exports.minify = function(files, options) { var compress = { warnings: options.warnings }; UglifyJS.merge(compress, options.compress); toplevel.figure_out_scope(); + haveScope = true; var sq = UglifyJS.Compressor(compress); toplevel = toplevel.transform(sq); } @@ -80,11 +82,17 @@ exports.minify = function(files, options) { // 3. mangle if (options.mangle) { toplevel.figure_out_scope(options.mangle); + haveScope = true; toplevel.compute_char_frequency(options.mangle); toplevel.mangle_names(options.mangle); } - // 4. output + // 4. scope (if needed) + if (!haveScope) { + toplevel.figure_out_scope(); + } + + // 5. output var inMap = options.inSourceMap; var output = {}; if (typeof options.inSourceMap == "string") { From a8e67d157e9caa59bbaf47cd6208eaa583853abb Mon Sep 17 00:00:00 2001 From: Mihai Bazon Date: Sun, 11 Oct 2015 18:24:38 +0300 Subject: [PATCH 15/15] v2.5.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 51b309b9..c172be39 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "homepage": "http://lisperator.net/uglifyjs", "author": "Mihai Bazon (http://lisperator.net/)", "license": "BSD-2-Clause", - "version": "2.4.24", + "version": "2.5.0", "engines": { "node": ">=0.8.0" },