Merge branch 'master' into harmony-v3.0.5

This commit is contained in:
alexlamsl
2017-05-15 18:58:54 +08:00
15 changed files with 479 additions and 265 deletions

View File

@@ -278,3 +278,19 @@ try_catch_finally: {
"1",
]
}
accessor: {
options = {
side_effects: true,
}
input: {
({
get a() {},
set a(v){
this.b = 2;
},
b: 1
});
}
expect: {}
}

View File

@@ -119,3 +119,62 @@ chained: {
a.b.c;
}
}
impure_getter_1: {
options = {
pure_getters: "strict",
side_effects: true,
}
input: {
({
get a() {
console.log(1);
},
b: 1
}).a;
({
get a() {
console.log(1);
},
b: 1
}).b;
}
expect: {
({
get a() {
console.log(1);
},
b: 1
}).a;
({
get a() {
console.log(1);
},
b: 1
}).b;
}
expect_stdout: "1"
}
impure_getter_2: {
options = {
pure_getters: true,
side_effects: true,
}
input: {
// will produce incorrect output because getter is not pure
({
get a() {
console.log(1);
},
b: 1
}).a;
({
get a() {
console.log(1);
},
b: 1
}).b;
}
expect: {}
}

View File

@@ -41,20 +41,20 @@ reduce_vars: {
var A = 1;
(function() {
console.log(-3);
console.log(-4);
console.log(A - 5);
})();
(function f1() {
var a = 2;
console.log(-3);
console.log(a - 5);
eval("console.log(a);");
})();
(function f2(eval) {
var a = 2;
console.log(-3);
console.log(a - 5);
eval("console.log(a);");
})(eval);
"yes";
console.log(2);
console.log(A + 1);
}
expect_stdout: true
}
@@ -1749,7 +1749,10 @@ redefine_arguments_3: {
console.log(function() {
var arguments;
return typeof arguments;
}(), "number", "undefined");
}(), "number", function(x) {
var arguments = x;
return typeof arguments;
}());
}
expect_stdout: "object number undefined"
}
@@ -2461,3 +2464,76 @@ issue_1865: {
}
expect_stdout: true
}
issue_1922_1: {
options = {
evaluate: true,
reduce_vars: true,
unused: true,
}
input: {
console.log(function(a) {
arguments[0] = 2;
return a;
}(1));
}
expect: {
console.log(function(a) {
arguments[0] = 2;
return a;
}(1));
}
expect_stdout: "2"
}
issue_1922_2: {
options = {
evaluate: true,
reduce_vars: true,
unused: true,
}
input: {
console.log(function() {
var a;
eval("a = 1");
return a;
}(1));
}
expect: {
console.log(function() {
var a;
eval("a = 1");
return a;
}(1));
}
expect_stdout: "1"
}
accessor: {
options = {
evaluate: true,
reduce_vars: true,
toplevel: true,
}
input: {
var a = 1;
console.log({
get a() {
a = 2;
return a;
},
b: 1
}.b, a);
}
expect: {
var a = 1;
console.log({
get a() {
a = 2;
return a;
},
b: 1
}.b, a);
}
expect_stdout: "1 1"
}

View File

@@ -361,18 +361,28 @@ describe("Directives", function() {
var tests = [
[
'"use strict";"use strict";"use strict";"use foo";"use strict";;"use sloppy";doSomething("foo");',
'"use strict";"use foo";doSomething("foo");'
'"use strict";"use foo";doSomething("foo");',
'function f(){ "use strict" }',
'function f(){ "use asm" }',
'function f(){ "use nondirective" }',
'function f(){ ;"use strict" }',
'function f(){ "use \n"; }',
],
[
// Nothing gets optimised in the compressor because "use asm" is the first statement
'"use asm";"use\\x20strict";1+1;',
'"use asm";;"use strict";1+1;' // Yet, the parser noticed that "use strict" wasn't a directive
'"use asm";;"use strict";1+1;', // Yet, the parser noticed that "use strict" wasn't a directive
'function f(){"use strict"}',
'function f(){"use asm"}',
'function f(){"use nondirective"}',
'function f(){}',
'function f(){}',
]
];
for (var i = 0; i < tests.length; i++) {
assert.strictEqual(
uglify.minify(tests[i][0], {compress: {collapse_vars: true, side_effects: true}}).code,
uglify.minify(tests[i][0]).code,
tests[i][1],
tests[i][0]
);

View File

@@ -1,103 +1,73 @@
// Testing UglifyJS <-> SpiderMonkey AST conversion
// through generative testing.
"use strict";
var UglifyJS = require("./node"),
escodegen = require("escodegen"),
esfuzz = require("esfuzz"),
estraverse = require("estraverse"),
prefix = "\r ";
var acorn = require("acorn");
var ufuzz = require("./ufuzz");
var UglifyJS = require("..");
// Normalizes input AST for UglifyJS in order to get correct comparison.
function normalizeInput(ast) {
return estraverse.replace(ast, {
enter: function(node, parent) {
switch (node.type) {
// Internally mark all the properties with semi-standard type "Property".
case "ObjectExpression":
node.properties.forEach(function (property) {
property.type = "Property";
});
break;
// Since UglifyJS doesn"t recognize different types of property keys,
// decision on SpiderMonkey node type is based on check whether key
// can be valid identifier or not - so we do in input AST.
case "Property":
var key = node.key;
if (key.type === "Literal" && typeof key.value === "string" && UglifyJS.is_identifier(key.value)) {
node.key = {
type: "Identifier",
name: key.value
};
} else if (key.type === "Identifier" && !UglifyJS.is_identifier(key.name)) {
node.key = {
type: "Literal",
value: key.name
};
}
break;
// UglifyJS internally flattens all the expression sequences - either
// to one element (if sequence contains only one element) or flat list.
case "SequenceExpression":
node.expressions = node.expressions.reduce(function flatten(list, expr) {
return list.concat(expr.type === "SequenceExpression" ? expr.expressions.reduce(flatten, []) : [expr]);
}, []);
if (node.expressions.length === 1) {
return node.expressions[0];
}
break;
}
function try_beautify(code) {
var beautified = UglifyJS.minify(code, {
compress: false,
mangle: false,
output: {
beautify: true,
bracketize: true
}
});
if (beautified.error) {
console.log("// !!! beautify failed !!!");
console.log(beautified.error.stack);
console.log(code);
} else {
console.log("// (beautified)");
console.log(beautified.code);
}
}
module.exports = function(options) {
console.log("--- UglifyJS <-> Mozilla AST conversion");
for (var counter = 0; counter < options.iterations; counter++) {
process.stdout.write(prefix + counter + "/" + options.iterations);
var ast1 = normalizeInput(esfuzz.generate({
maxDepth: options.maxDepth
}));
var ast2 =
UglifyJS
.AST_Node
.from_mozilla_ast(ast1)
.to_mozilla_ast();
var astPair = [
{name: 'expected', value: ast1},
{name: 'actual', value: ast2}
];
var jsPair = astPair.map(function(item) {
return {
name: item.name,
value: escodegen.generate(item.value)
}
});
if (jsPair[0].value !== jsPair[1].value) {
var fs = require("fs");
var acorn = require("acorn");
fs.existsSync("tmp") || fs.mkdirSync("tmp");
jsPair.forEach(function (item) {
var fileName = "tmp/dump_" + item.name;
var ast = acorn.parse(item.value);
fs.writeFileSync(fileName + ".js", item.value);
fs.writeFileSync(fileName + ".json", JSON.stringify(ast, null, 2));
});
process.stdout.write("\n");
throw new Error("Got different outputs, check out tmp/dump_*.{js,json} for codes and ASTs.");
function test(original, estree, description) {
var transformed = UglifyJS.minify(UglifyJS.AST_Node.from_mozilla_ast(estree), {
compress: false,
mangle: false
});
if (transformed.error || original !== transformed.code) {
console.log("//=============================================================");
console.log("// !!!!!! Failed... round", round);
console.log("// original code");
try_beautify(original);
console.log();
console.log();
console.log("//-------------------------------------------------------------");
console.log("//", description);
if (transformed.error) {
console.log(transformed.error.stack);
} else {
try_beautify(transformed.code);
}
console.log("!!!!!! Failed... round", round);
process.exit(1);
}
}
process.stdout.write(prefix + "Probability of error is less than " + (100 / options.iterations) + "%, stopping.\n");
};
var num_iterations = ufuzz.num_iterations;
for (var round = 1; round <= num_iterations; round++) {
process.stdout.write(round + " of " + num_iterations + "\r");
var code = ufuzz.createTopLevelCode();
var uglified = UglifyJS.minify(code, {
compress: false,
mangle: false,
output: {
ast: true
}
});
test(uglified.code, uglified.ast.to_mozilla_ast(), "AST_Node.to_mozilla_ast()");
try {
test(uglified.code, acorn.parse(code), "acorn.parse()");
} catch (e) {
console.log("//=============================================================");
console.log("// acorn parser failed... round", round);
console.log(e);
console.log("// original code");
console.log(code);
}
}
console.log();

View File

@@ -23,12 +23,6 @@ mocha_tests();
var run_sourcemaps_tests = require('./sourcemaps');
run_sourcemaps_tests();
var run_ast_conversion_tests = require("./mozilla-ast");
run_ast_conversion_tests({
iterations: 1000
});
/* -----[ utils ]----- */
function tmpl() {

View File

@@ -1,14 +1,16 @@
var vm = require("vm");
function safe_log(arg) {
function safe_log(arg, level) {
if (arg) switch (typeof arg) {
case "function":
return arg.toString();
case "object":
if (/Error$/.test(arg.name)) return arg.toString();
arg.constructor.toString();
for (var key in arg) {
arg[key] = safe_log(arg[key]);
if (level--) for (var key in arg) {
if (!Object.getOwnPropertyDescriptor(arg, key).get) {
arg[key] = safe_log(arg[key], level);
}
}
}
return arg;
@@ -48,7 +50,9 @@ exports.run_code = function(code) {
].join("\n"), {
console: {
log: function() {
return console.log.apply(console, [].map.call(arguments, safe_log));
return console.log.apply(console, [].map.call(arguments, function(arg) {
return safe_log(arg, 3);
}));
}
}
}, { timeout: 5000 });

View File

@@ -48,8 +48,9 @@ var STMT_COUNT_FROM_GLOBAL = true; // count statement depth from nearest functio
var num_iterations = +process.argv[2] || 1/0;
var verbose = false; // log every generated test
var verbose_interval = false; // log every 100 generated tests
var verbose_error = false;
var use_strict = false;
var catch_redef = require.main === module;
var generate_directive = require.main === module;
for (var i = 2; i < process.argv.length; ++i) {
switch (process.argv[i]) {
case '-v':
@@ -58,9 +59,6 @@ for (var i = 2; i < process.argv.length; ++i) {
case '-V':
verbose_interval = true;
break;
case '-E':
verbose_error = true;
break;
case '-t':
MAX_GENERATED_TOPLEVELS_PER_RUN = +process.argv[++i];
if (!MAX_GENERATED_TOPLEVELS_PER_RUN) throw new Error('Must generate at least one toplevel per run');
@@ -79,6 +77,12 @@ for (var i = 2; i < process.argv.length; ++i) {
STMT_SECOND_LEVEL_OVERRIDE = STMT_ARG_TO_ID[name];
if (!(STMT_SECOND_LEVEL_OVERRIDE >= 0)) throw new Error('Unknown statement name; use -? to get a list');
break;
case '--no-catch-redef':
catch_redef = false;
break;
case '--no-directive':
generate_directive = false;
break;
case '--use-strict':
use_strict = true;
break;
@@ -103,11 +107,12 @@ for (var i = 2; i < process.argv.length; ++i) {
console.log('<number>: generate this many cases (if used must be first arg)');
console.log('-v: print every generated test case');
console.log('-V: print every 100th generated test case');
console.log('-E: print generated test case with runtime error');
console.log('-t <int>: generate this many toplevels per run (more take longer)');
console.log('-r <int>: maximum recursion depth for generator (higher takes longer)');
console.log('-s1 <statement name>: force the first level statement to be this one (see list below)');
console.log('-s2 <statement name>: force the second level statement to be this one (see list below)');
console.log('--no-catch-redef: do not redefine catch variables');
console.log('--no-directive: do not generate directives');
console.log('--use-strict: generate "use strict"');
console.log('--stmt-depth-from-func: reset statement depth counter at each function, counts from global otherwise');
console.log('--only-stmt <statement names>: a comma delimited white list of statements that may be generated');
@@ -192,12 +197,33 @@ var ASSIGNMENTS = [
'=',
'=',
'=',
'=',
'=',
'=',
'=',
'=',
'=',
'=',
'=',
'=',
'=',
'=',
'=',
'=',
'=',
'==',
'!=',
'===',
'!==',
'+=',
'+=',
'+=',
'+=',
'+=',
'+=',
'+=',
'+=',
'+=',
'+=',
'-=',
'*=',
'/=',
@@ -207,7 +233,8 @@ var ASSIGNMENTS = [
'<<=',
'>>=',
'>>>=',
'%=' ];
'%=',
];
var UNARY_SAFE = [
'+',
@@ -276,6 +303,7 @@ var TYPEOF_OUTCOMES = [
'symbol',
'crap' ];
var unique_vars = [];
var loops = 0;
var funcs = 0;
var labels = 10000;
@@ -290,6 +318,10 @@ function strictMode() {
}
function createTopLevelCode() {
VAR_NAMES.length = INITIAL_NAMES_LEN; // prune any previous names still in the list
unique_vars.length = 0;
loops = 0;
funcs = 0;
return [
strictMode(),
'var a = 100, b = 10, c = 0;',
@@ -325,33 +357,36 @@ function createArgs() {
return args.join(', ');
}
function filterDirective(s) {
if (!generate_directive && !s[1] && /\("/.test(s[2])) s[2] = ';' + s[2];
return s;
}
function createFunction(recurmax, inGlobal, noDecl, canThrow, stmtDepth) {
if (--recurmax < 0) { return ';'; }
if (!STMT_COUNT_FROM_GLOBAL) stmtDepth = 0;
var func = funcs++;
var namesLenBefore = VAR_NAMES.length;
var name = (inGlobal || rng(5) > 0) ? 'f' + func : createVarName(MANDATORY, noDecl);
if (name === 'a' || name === 'b' || name === 'c') name = 'f' + func; // quick hack to prevent assignment to func names of being called
var s = '';
var name;
if (inGlobal || rng(5) > 0) name = 'f' + func;
else {
unique_vars.push('a', 'b', 'c');
name = createVarName(MANDATORY, noDecl);
unique_vars.length -= 3;
}
var s = [
'function ' + name + '(' + createParams() + '){',
strictMode()
];
if (rng(5) === 0) {
// functions with functions. lower the recursion to prevent a mess.
s = [
'function ' + name + '(' + createParams() + '){',
strictMode(),
createFunctions(rng(5) + 1, Math.ceil(recurmax * 0.7), NOT_GLOBAL, ANY_TYPE, canThrow, stmtDepth),
'}',
''
].join('\n');
s.push(createFunctions(rng(5) + 1, Math.ceil(recurmax * 0.7), NOT_GLOBAL, ANY_TYPE, canThrow, stmtDepth));
} else {
// functions with statements
s = [
'function ' + name + '(' + createParams() + '){',
strictMode(),
createStatements(3, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth),
'}',
''
].join('\n');
s.push(createStatements(3, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth));
}
s.push('}', '');
s = filterDirective(s).join('\n');
VAR_NAMES.length = namesLenBefore;
@@ -359,7 +394,6 @@ function createFunction(recurmax, inGlobal, noDecl, canThrow, stmtDepth) {
// avoid "function statements" (decl inside statements)
else if (inGlobal || rng(10) > 0) s += 'var ' + createVarName(MANDATORY) + ' = ' + name + '(' + createArgs() + ');';
return s;
}
@@ -406,7 +440,7 @@ function getLabel(label) {
return label && " L" + label;
}
function createStatement(recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth) {
function createStatement(recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth, target) {
++stmtDepth;
var loop = ++loops;
if (--recurmax < 0) {
@@ -414,10 +448,11 @@ function createStatement(recurmax, canThrow, canBreak, canContinue, cannotReturn
}
// allow to forcefully generate certain structures at first or second recursion level
var target = 0;
if (stmtDepth === 1 && STMT_FIRST_LEVEL_OVERRIDE >= 0) target = STMT_FIRST_LEVEL_OVERRIDE;
else if (stmtDepth === 2 && STMT_SECOND_LEVEL_OVERRIDE >= 0) target = STMT_SECOND_LEVEL_OVERRIDE;
else target = STMTS_TO_USE[rng(STMTS_TO_USE.length)];
if (target === undefined) {
if (stmtDepth === 1 && STMT_FIRST_LEVEL_OVERRIDE >= 0) target = STMT_FIRST_LEVEL_OVERRIDE;
else if (stmtDepth === 2 && STMT_SECOND_LEVEL_OVERRIDE >= 0) target = STMT_SECOND_LEVEL_OVERRIDE;
else target = STMTS_TO_USE[rng(STMTS_TO_USE.length)];
}
switch (target) {
case STMT_BLOCK:
@@ -460,20 +495,22 @@ function createStatement(recurmax, canThrow, canBreak, canContinue, cannotReturn
case STMT_VAR:
switch (rng(3)) {
case 0:
unique_vars.push('c');
var name = createVarName(MANDATORY);
if (name === 'c') name = 'a';
unique_vars.pop();
return 'var ' + name + ';';
case 1:
// initializer can only have one expression
unique_vars.push('c');
var name = createVarName(MANDATORY);
if (name === 'c') name = 'b';
unique_vars.pop();
return 'var ' + name + ' = ' + createExpression(recurmax, NO_COMMA, stmtDepth, canThrow) + ';';
default:
// initializer can only have one expression
unique_vars.push('c');
var n1 = createVarName(MANDATORY);
if (n1 === 'c') n1 = 'b';
var n2 = createVarName(MANDATORY);
if (n2 === 'c') n2 = 'b';
unique_vars.pop();
return 'var ' + n1 + ' = ' + createExpression(recurmax, NO_COMMA, stmtDepth, canThrow) + ', ' + n2 + ' = ' + createExpression(recurmax, NO_COMMA, stmtDepth, canThrow) + ';';
}
case STMT_RETURN_ETC:
@@ -514,8 +551,11 @@ function createStatement(recurmax, canThrow, canBreak, canContinue, cannotReturn
var nameLenBefore = VAR_NAMES.length;
var catchName = createVarName(MANDATORY);
var freshCatchName = VAR_NAMES.length !== nameLenBefore;
if (!catch_redef) unique_vars.push(catchName);
s += ' catch (' + catchName + ') { ' + createStatements(3, recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth) + ' }';
if (freshCatchName) VAR_NAMES.splice(nameLenBefore, 1); // remove catch name
// remove catch name
if (!catch_redef) unique_vars.pop();
if (freshCatchName) VAR_NAMES.splice(nameLenBefore, 1);
}
if (n !== 0) s += ' finally { ' + createStatements(3, recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth) + ' }';
return s;
@@ -593,8 +633,9 @@ function _createExpression(recurmax, noComma, stmtDepth, canThrow) {
case p++:
case p++:
var nameLenBefore = VAR_NAMES.length;
unique_vars.push('c');
var name = createVarName(MAYBE); // note: this name is only accessible from _within_ the function. and immutable at that.
if (name == 'c') name = 'a';
unique_vars.pop();
var s = [];
switch (rng(5)) {
case 0:
@@ -636,7 +677,7 @@ function _createExpression(recurmax, noComma, stmtDepth, canThrow) {
strictMode()
);
if (instantiate) for (var i = rng(4); --i >= 0;) {
if (rng(2)) s.push('this.' + getDotKey() + createAssignment() + _createBinaryExpr(recurmax, noComma, stmtDepth, canThrow) + ';');
if (rng(2)) s.push('this.' + getDotKey(true) + createAssignment() + _createBinaryExpr(recurmax, noComma, stmtDepth, canThrow) + ';');
else s.push('this[' + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + ']' + createAssignment() + _createBinaryExpr(recurmax, noComma, stmtDepth, canThrow) + ';');
}
s.push(
@@ -646,7 +687,7 @@ function _createExpression(recurmax, noComma, stmtDepth, canThrow) {
break;
}
VAR_NAMES.length = nameLenBefore;
return s.join('\n');
return filterDirective(s).join('\n');
case p++:
case p++:
return createTypeofExpr(recurmax, stmtDepth, canThrow);
@@ -689,19 +730,19 @@ function _createExpression(recurmax, noComma, stmtDepth, canThrow) {
") || " + rng(10) + ").toString()[" +
createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + "] ";
case p++:
return createArrayLiteral(recurmax, COMMA_OK, stmtDepth, canThrow);
return createArrayLiteral(recurmax, stmtDepth, canThrow);
case p++:
return createObjectLiteral(recurmax, COMMA_OK, stmtDepth, canThrow);
return createObjectLiteral(recurmax, stmtDepth, canThrow);
case p++:
return createArrayLiteral(recurmax, COMMA_OK, stmtDepth, canThrow) + '[' +
return createArrayLiteral(recurmax, stmtDepth, canThrow) + '[' +
createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + ']';
case p++:
return createObjectLiteral(recurmax, COMMA_OK, stmtDepth, canThrow) + '[' +
return createObjectLiteral(recurmax, stmtDepth, canThrow) + '[' +
createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + ']';
case p++:
return createArrayLiteral(recurmax, COMMA_OK, stmtDepth, canThrow) + '.' + getDotKey();
return createArrayLiteral(recurmax, stmtDepth, canThrow) + '.' + getDotKey();
case p++:
return createObjectLiteral(recurmax, COMMA_OK, stmtDepth, canThrow) + '.' + getDotKey();
return createObjectLiteral(recurmax, stmtDepth, canThrow) + '.' + getDotKey();
case p++:
var name = getVarName();
return name + ' && ' + name + '[' + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + ']';
@@ -713,7 +754,7 @@ function _createExpression(recurmax, noComma, stmtDepth, canThrow) {
return _createExpression(recurmax, noComma, stmtDepth, canThrow);
}
function createArrayLiteral(recurmax, noComma, stmtDepth, canThrow) {
function createArrayLiteral(recurmax, stmtDepth, canThrow) {
recurmax--;
var arr = "[";
for (var i = rng(6); --i >= 0;) {
@@ -746,18 +787,56 @@ var KEYS = [
"3",
].concat(SAFE_KEYS);
function getDotKey() {
return SAFE_KEYS[rng(SAFE_KEYS.length)];
function getDotKey(assign) {
var key;
do {
key = SAFE_KEYS[rng(SAFE_KEYS.length)];
} while (assign && key == "length");
return key;
}
function createObjectLiteral(recurmax, noComma, stmtDepth, canThrow) {
recurmax--;
var obj = "({";
for (var i = rng(6); --i >= 0;) {
var key = KEYS[rng(KEYS.length)];
obj += key + ":(" + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + "), ";
function createAccessor(recurmax, stmtDepth, canThrow) {
var namesLenBefore = VAR_NAMES.length;
var s;
var prop1 = getDotKey();
if (rng(2) == 0) {
s = [
'get ' + prop1 + '(){',
strictMode(),
createStatements(2, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth),
createStatement(recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth, STMT_RETURN_ETC),
'},'
];
} else {
var prop2;
do {
prop2 = getDotKey();
} while (prop1 == prop2);
s = [
'set ' + prop1 + '(' + createVarName(MANDATORY) + '){',
strictMode(),
createStatements(2, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth),
'this.' + prop2 + createAssignment() + _createBinaryExpr(recurmax, COMMA_OK, stmtDepth, canThrow) + ';',
'},'
];
}
return obj + "})";
VAR_NAMES.length = namesLenBefore;
return filterDirective(s).join('\n');
}
function createObjectLiteral(recurmax, stmtDepth, canThrow) {
recurmax--;
var obj = ['({'];
for (var i = rng(6); --i >= 0;) {
if (rng(20) == 0) {
obj.push(createAccessor(recurmax, stmtDepth, canThrow));
} else {
var key = KEYS[rng(KEYS.length)];
obj.push(key + ':(' + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + '),');
}
}
obj.push('})');
return obj.join('\n');
}
function createNestedBinaryExpr(recurmax, noComma, stmtDepth, canThrow) {
@@ -787,7 +866,7 @@ function _createSimpleBinaryExpr(recurmax, noComma, stmtDepth, canThrow) {
return canThrow && rng(10) == 0 ? expr : '(' + assignee + ' && ' + expr + ')';
case 4:
assignee = getVarName();
expr = '(' + assignee + '.' + getDotKey() + createAssignment()
expr = '(' + assignee + '.' + getDotKey(true) + createAssignment()
+ _createBinaryExpr(recurmax, noComma, stmtDepth, canThrow) + ')';
return canThrow && rng(10) == 0 ? expr : '(' + assignee + ' && ' + expr + ')';
default:
@@ -844,17 +923,24 @@ function getVarName() {
function createVarName(maybe, dontStore) {
if (!maybe || rng(2)) {
var name = VAR_NAMES[rng(VAR_NAMES.length)];
var suffix = rng(3);
if (suffix) {
name += '_' + suffix;
if (!dontStore) VAR_NAMES.push(name);
}
var name;
do {
name = VAR_NAMES[rng(VAR_NAMES.length)];
if (suffix) name += '_' + suffix;
} while (unique_vars.indexOf(name) >= 0);
if (suffix && !dontStore) VAR_NAMES.push(name);
return name;
}
return '';
}
if (require.main !== module) {
exports.createTopLevelCode = createTopLevelCode;
exports.num_iterations = num_iterations;
return;
}
function try_beautify(code, result) {
var beautified = UglifyJS.minify(code, {
compress: false,
@@ -973,10 +1059,6 @@ var uglify_code, uglify_result, ok;
for (var round = 1; round <= num_iterations; round++) {
process.stdout.write(round + " of " + num_iterations + "\r");
VAR_NAMES.length = INITIAL_NAMES_LEN; // prune any previous names still in the list
loops = 0;
funcs = 0;
original_code = createTopLevelCode();
original_result = sandbox.run_code(original_code);
(typeof original_result != "string" ? fallback_options : minify_options).forEach(function(options) {
@@ -992,7 +1074,7 @@ for (var round = 1; round <= num_iterations; round++) {
}
}
if (verbose || (verbose_interval && !(round % INTERVAL_COUNT)) || !ok) log(options);
else if (verbose_error && typeof original_result != "string") {
else if (typeof original_result != "string") {
console.log("//=============================================================");
console.log("// original code");
try_beautify(original_code, original_result);