Skip to content

Commit

Permalink
Merge pull request #1938 from alexlamsl/v2.8.25
Browse files Browse the repository at this point in the history
  • Loading branch information
alexlamsl committed May 15, 2017
2 parents 87f8a48 + 24967b8 commit 3ee1464
Show file tree
Hide file tree
Showing 24 changed files with 579 additions and 294 deletions.
11 changes: 6 additions & 5 deletions README.md
Expand Up @@ -436,16 +436,17 @@ to set `true`; it's effectively a shortcut for `foo=true`).
compressor from discarding function names. Useful for code relying on
`Function.prototype.name`. See also: the `keep_fnames` [mangle option](#mangle).

- `passes` -- default `1`. Number of times to run compress. Use an
integer argument larger than 1 to further reduce code size in some cases.
Note: raising the number of passes will increase uglify compress time.
- `passes` -- default `1`. Number of times to run compress with a maximum of 3.
In some cases more than one pass leads to further compressed code. Keep in
mind more passes will take more time.

- `keep_infinity` -- default `false`. Pass `true` to prevent `Infinity` from
being compressed into `1/0`, which may cause performance issues on Chrome.

- `side_effects` -- default `false`. Pass `true` to potentially drop functions
marked as "pure". (A function is marked as "pure" via the comment annotation
`/* @__PURE__ */` or `/* #__PURE__ */`)
marked as "pure". A function call is marked as "pure" if a comment annotation
`/*@__PURE__*/` or `/*#__PURE__*/` immediately precedes the call. For example:
`/*@__PURE__*/foo()`;


### The `unsafe` option
Expand Down
16 changes: 8 additions & 8 deletions bin/uglifyjs
Expand Up @@ -367,19 +367,19 @@ var index = 0;
if (ex instanceof UglifyJS.JS_Parse_Error) {
print_error("Parse error at " + file + ":" + ex.line + "," + ex.col);
var col = ex.col;
var line = code.split(/\r?\n/)[ex.line - (col ? 1 : 2)];
var lines = code.split(/\r?\n/);
var line = lines[ex.line - 1];
if (!line && !col) {
line = lines[ex.line - 2];
col = line.length;
}
if (line) {
if (col > 40) {
line = line.slice(col - 40);
col = 40;
}
if (col) {
print_error(line.slice(0, 80));
print_error(line.slice(0, col).replace(/\S/g, " ") + "^");
} else {
print_error(line.slice(-40));
print_error(line.slice(-40).replace(/\S/g, " ") + "^");
}
print_error(line.slice(0, 80));
print_error(line.slice(0, col).replace(/\S/g, " ") + "^");
}
print_error(ex.stack);
process.exit(1);
Expand Down
4 changes: 2 additions & 2 deletions lib/ast.js
Expand Up @@ -798,8 +798,8 @@ var AST_Object = DEFNODE("Object", "properties", {
var AST_ObjectProperty = DEFNODE("ObjectProperty", "key value", {
$documentation: "Base class for literal object properties",
$propdoc: {
key: "[string] the property name converted to a string for ObjectKeyVal. For setters and getters this is an arbitrary AST_Node.",
value: "[AST_Node] property value. For setters and getters this is an AST_Function."
key: "[string] the property name converted to a string for ObjectKeyVal. For setters and getters this is an AST_SymbolAccessor.",
value: "[AST_Node] property value. For setters and getters this is an AST_Accessor."
},
_walk: function(visitor) {
return visitor._visit(this, function(){
Expand Down
110 changes: 73 additions & 37 deletions lib/compress.js
Expand Up @@ -316,25 +316,55 @@ merge(Compressor.prototype, {
safe_ids = save_ids;
return true;
}
var iife;
if (node instanceof AST_Function
&& !node.name
&& (iife = tw.parent()) instanceof AST_Call
&& iife.expression === node) {
// Virtually turn IIFE parameters into variable definitions:
// (function(a,b) {...})(c,d) => (function() {var a=c,b=d; ...})()
// So existing transformation rules can work on them.
node.argnames.forEach(function(arg, i) {
var d = arg.definition();
if (!node.uses_arguments && d.fixed === undefined) {
d.fixed = function() {
return iife.args[i] || make_node(AST_Undefined, iife);
};
mark(d, true);
} else {
d.fixed = false;
}
});
if (node instanceof AST_Function) {
push();
var iife;
if (!node.name
&& (iife = tw.parent()) instanceof AST_Call
&& iife.expression === node) {
// Virtually turn IIFE parameters into variable definitions:
// (function(a,b) {...})(c,d) => (function() {var a=c,b=d; ...})()
// So existing transformation rules can work on them.
node.argnames.forEach(function(arg, i) {
var d = arg.definition();
if (!node.uses_arguments && d.fixed === undefined) {
d.fixed = function() {
return iife.args[i] || make_node(AST_Undefined, iife);
};
mark(d, true);
} else {
d.fixed = false;
}
});
}
descend();
pop();
return true;
}
if (node instanceof AST_Accessor) {
var save_ids = safe_ids;
safe_ids = Object.create(null);
descend();
safe_ids = save_ids;
return true;
}
if (node instanceof AST_Binary
&& (node.operator == "&&" || node.operator == "||")) {
node.left.walk(tw);
push();
node.right.walk(tw);
pop();
return true;
}
if (node instanceof AST_Conditional) {
node.condition.walk(tw);
push();
node.consequent.walk(tw);
pop();
push();
node.alternative.walk(tw);
pop();
return true;
}
if (node instanceof AST_If || node instanceof AST_DWLoop) {
node.condition.walk(tw);
Expand Down Expand Up @@ -1195,12 +1225,12 @@ merge(Compressor.prototype, {
&& !node.expression.has_side_effects(compressor);
}

// may_eq_null()
// returns true if this node may evaluate to null or undefined
// may_throw_on_access()
// returns true if this node may be null, undefined or contain `AST_Accessor`
(function(def) {
AST_Node.DEFMETHOD("may_eq_null", function(compressor) {
AST_Node.DEFMETHOD("may_throw_on_access", function(compressor) {
var pure_getters = compressor.option("pure_getters");
return !pure_getters || this._eq_null(pure_getters);
return !pure_getters || this._throw_on_access(pure_getters);
});

function is_strict(pure_getters) {
Expand All @@ -1212,7 +1242,12 @@ merge(Compressor.prototype, {
def(AST_Undefined, return_true);
def(AST_Constant, return_false);
def(AST_Array, return_false);
def(AST_Object, return_false);
def(AST_Object, function(pure_getters) {
if (!is_strict(pure_getters)) return false;
for (var i = this.properties.length; --i >=0;)
if (this.properties[i].value instanceof AST_Accessor) return true;
return false;
});
def(AST_Function, return_false);
def(AST_UnaryPostfix, return_false);
def(AST_UnaryPrefix, function() {
Expand All @@ -1221,33 +1256,33 @@ merge(Compressor.prototype, {
def(AST_Binary, function(pure_getters) {
switch (this.operator) {
case "&&":
return this.left._eq_null(pure_getters);
return this.left._throw_on_access(pure_getters);
case "||":
return this.left._eq_null(pure_getters)
&& this.right._eq_null(pure_getters);
return this.left._throw_on_access(pure_getters)
&& this.right._throw_on_access(pure_getters);
default:
return false;
}
})
def(AST_Assign, function(pure_getters) {
return this.operator == "="
&& this.right._eq_null(pure_getters);
&& this.right._throw_on_access(pure_getters);
})
def(AST_Conditional, function(pure_getters) {
return this.consequent._eq_null(pure_getters)
|| this.alternative._eq_null(pure_getters);
return this.consequent._throw_on_access(pure_getters)
|| this.alternative._throw_on_access(pure_getters);
})
def(AST_Seq, function(pure_getters) {
return this.cdr._eq_null(pure_getters);
return this.cdr._throw_on_access(pure_getters);
});
def(AST_SymbolRef, function(pure_getters) {
if (this.is_undefined) return true;
if (!is_strict(pure_getters)) return false;
var fixed = this.fixed_value();
return !fixed || fixed._eq_null(pure_getters);
return !fixed || fixed._throw_on_access(pure_getters);
});
})(function(node, func) {
node.DEFMETHOD("_eq_null", func);
node.DEFMETHOD("_throw_on_access", func);
});

/* -----[ boolean/negation helpers ]----- */
Expand Down Expand Up @@ -1787,11 +1822,11 @@ merge(Compressor.prototype, {
return any(this.elements, compressor);
});
def(AST_Dot, function(compressor){
return this.expression.may_eq_null(compressor)
return this.expression.may_throw_on_access(compressor)
|| this.expression.has_side_effects(compressor);
});
def(AST_Sub, function(compressor){
return this.expression.may_eq_null(compressor)
return this.expression.may_throw_on_access(compressor)
|| this.expression.has_side_effects(compressor)
|| this.property.has_side_effects(compressor);
});
Expand Down Expand Up @@ -2295,6 +2330,7 @@ merge(Compressor.prototype, {
var args = trim(this.args, compressor, first_in_statement);
return args && AST_Seq.from_array(args);
});
def(AST_Accessor, return_null);
def(AST_Function, return_null);
def(AST_Binary, function(compressor, first_in_statement){
var right = this.right.drop_side_effect_free(compressor);
Expand Down Expand Up @@ -2365,11 +2401,11 @@ merge(Compressor.prototype, {
return values && AST_Seq.from_array(values);
});
def(AST_Dot, function(compressor, first_in_statement){
if (this.expression.may_eq_null(compressor)) return this;
if (this.expression.may_throw_on_access(compressor)) return this;
return this.expression.drop_side_effect_free(compressor, first_in_statement);
});
def(AST_Sub, function(compressor, first_in_statement){
if (this.expression.may_eq_null(compressor)) return this;
if (this.expression.may_throw_on_access(compressor)) return this;
var expression = this.expression.drop_side_effect_free(compressor, first_in_statement);
if (!expression) return this.property.drop_side_effect_free(compressor, first_in_statement);
var property = this.property.drop_side_effect_free(compressor);
Expand Down
52 changes: 27 additions & 25 deletions lib/mozilla-ast.js
Expand Up @@ -111,23 +111,19 @@
},
Property: function(M) {
var key = M.key;
var name = key.type == "Identifier" ? key.name : key.value;
var args = {
start : my_start_token(key),
end : my_end_token(M.value),
key : name,
key : key.type == "Identifier" ? key.name : key.value,
value : from_moz(M.value)
};
switch (M.kind) {
case "init":
return new AST_ObjectKeyVal(args);
case "set":
args.value.name = from_moz(key);
return new AST_ObjectSetter(args);
case "get":
args.value.name = from_moz(key);
return new AST_ObjectGetter(args);
}
if (M.kind == "init") return new AST_ObjectKeyVal(args);
args.key = new AST_SymbolAccessor({
name: args.key
});
args.value = new AST_Accessor(args.value);
if (M.kind == "get") return new AST_ObjectGetter(args);
if (M.kind == "set") return new AST_ObjectSetter(args);
},
ArrayExpression: function(M) {
return new AST_Array({
Expand Down Expand Up @@ -256,18 +252,15 @@
map("CallExpression", AST_Call, "callee>expression, arguments@args");

def_to_moz(AST_Toplevel, function To_Moz_Program(M) {
return {
type: "Program",
body: M.body.map(to_moz)
};
return to_moz_scope("Program", M);
});

def_to_moz(AST_Defun, function To_Moz_FunctionDeclaration(M) {
return {
type: "FunctionDeclaration",
id: to_moz(M.name),
params: M.argnames.map(to_moz),
body: to_moz_block(M)
body: to_moz_scope("BlockStatement", M)
}
});

Expand All @@ -276,7 +269,7 @@
type: "FunctionExpression",
id: to_moz(M.name),
params: M.argnames.map(to_moz),
body: to_moz_block(M)
body: to_moz_scope("BlockStatement", M)
}
});

Expand Down Expand Up @@ -382,11 +375,10 @@
});

def_to_moz(AST_ObjectProperty, function To_Moz_Property(M) {
var key = (
is_identifier(M.key)
? {type: "Identifier", name: M.key}
: {type: "Literal", value: M.key}
);
var key = {
type: "Literal",
value: M.key instanceof AST_SymbolAccessor ? M.key.name : M.key
};
var kind;
if (M instanceof AST_ObjectKeyVal) {
kind = "init";
Expand Down Expand Up @@ -547,8 +539,8 @@
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
me_to_moz = new Function("to_moz", "to_moz_block", "to_moz_scope", "return(" + me_to_moz + ")")(
to_moz, to_moz_block, to_moz_scope
);
MOZ_TO_ME[moztype] = moz_to_me;
def_to_moz(mytype, me_to_moz);
Expand Down Expand Up @@ -606,4 +598,14 @@
};
};

function to_moz_scope(type, node) {
var body = node.body.map(to_moz);
if (node.body[0] instanceof AST_SimpleStatement && node.body[0].body instanceof AST_String) {
body.unshift(to_moz(new AST_EmptyStatement(node.body[0])));
}
return {
type: type,
body: body
};
};
})();

0 comments on commit 3ee1464

Please sign in to comment.