Comparing version 5.16.2 to 5.16.3
# Changelog | ||
## v5.16.3 | ||
- Ensure function definitions, don't assume the values of variables defined after them. | ||
## v5.16.2 | ||
@@ -4,0 +8,0 @@ |
@@ -95,3 +95,2 @@ /*********************************************************************** | ||
import "./reduce-vars.js"; | ||
import { is_lhs } from "./inference.js"; | ||
import { | ||
@@ -118,2 +117,9 @@ SQUEEZED, | ||
/** | ||
* Module that contains the inlining logic. | ||
* | ||
* @module | ||
* | ||
* The stars of the show are `inline_into_symbolref` and `inline_into_call`. | ||
*/ | ||
@@ -149,132 +155,131 @@ function within_array_or_object_literal(compressor) { | ||
const parent = compressor.parent(); | ||
if (compressor.option("reduce_vars") && is_lhs(self, parent) !== self) { | ||
const def = self.definition(); | ||
const nearest_scope = compressor.find_scope(); | ||
if (compressor.top_retain && def.global && compressor.top_retain(def)) { | ||
def.fixed = false; | ||
def.single_use = false; | ||
return self; | ||
const def = self.definition(); | ||
const nearest_scope = compressor.find_scope(); | ||
if (compressor.top_retain && def.global && compressor.top_retain(def)) { | ||
def.fixed = false; | ||
def.single_use = false; | ||
return self; | ||
} | ||
let fixed = self.fixed_value(); | ||
let single_use = def.single_use | ||
&& !(parent instanceof AST_Call | ||
&& (parent.is_callee_pure(compressor)) | ||
|| has_annotation(parent, _NOINLINE)) | ||
&& !(parent instanceof AST_Export | ||
&& fixed instanceof AST_Lambda | ||
&& fixed.name); | ||
if (single_use && fixed instanceof AST_Node) { | ||
single_use = | ||
!fixed.has_side_effects(compressor) | ||
&& !fixed.may_throw(compressor); | ||
} | ||
if (single_use && (fixed instanceof AST_Lambda || fixed instanceof AST_Class)) { | ||
if (retain_top_func(fixed, compressor)) { | ||
single_use = false; | ||
} else if (def.scope !== self.scope | ||
&& (def.escaped == 1 | ||
|| has_flag(fixed, INLINED) | ||
|| within_array_or_object_literal(compressor) | ||
|| !compressor.option("reduce_funcs"))) { | ||
single_use = false; | ||
} else if (is_recursive_ref(compressor, def)) { | ||
single_use = false; | ||
} else if (def.scope !== self.scope || def.orig[0] instanceof AST_SymbolFunarg) { | ||
single_use = fixed.is_constant_expression(self.scope); | ||
if (single_use == "f") { | ||
var scope = self.scope; | ||
do { | ||
if (scope instanceof AST_Defun || is_func_expr(scope)) { | ||
set_flag(scope, INLINED); | ||
} | ||
} while (scope = scope.parent_scope); | ||
} | ||
} | ||
} | ||
let fixed = self.fixed_value(); | ||
let single_use = def.single_use | ||
&& !(parent instanceof AST_Call | ||
&& (parent.is_callee_pure(compressor)) | ||
|| has_annotation(parent, _NOINLINE)) | ||
&& !(parent instanceof AST_Export | ||
&& fixed instanceof AST_Lambda | ||
&& fixed.name); | ||
if (single_use && (fixed instanceof AST_Lambda || fixed instanceof AST_Class)) { | ||
single_use = | ||
def.scope === self.scope | ||
&& !scope_encloses_variables_in_this_scope(nearest_scope, fixed) | ||
|| parent instanceof AST_Call | ||
&& parent.expression === self | ||
&& !scope_encloses_variables_in_this_scope(nearest_scope, fixed) | ||
&& !(fixed.name && fixed.name.definition().recursive_refs > 0); | ||
} | ||
if (single_use && fixed instanceof AST_Node) { | ||
single_use = | ||
!fixed.has_side_effects(compressor) | ||
&& !fixed.may_throw(compressor); | ||
if (single_use && fixed) { | ||
if (fixed instanceof AST_DefClass) { | ||
set_flag(fixed, SQUEEZED); | ||
fixed = make_node(AST_ClassExpression, fixed, fixed); | ||
} | ||
if (single_use && (fixed instanceof AST_Lambda || fixed instanceof AST_Class)) { | ||
if (retain_top_func(fixed, compressor)) { | ||
single_use = false; | ||
} else if (def.scope !== self.scope | ||
&& (def.escaped == 1 | ||
|| has_flag(fixed, INLINED) | ||
|| within_array_or_object_literal(compressor) | ||
|| !compressor.option("reduce_funcs"))) { | ||
single_use = false; | ||
} else if (is_recursive_ref(compressor, def)) { | ||
single_use = false; | ||
} else if (def.scope !== self.scope || def.orig[0] instanceof AST_SymbolFunarg) { | ||
single_use = fixed.is_constant_expression(self.scope); | ||
if (single_use == "f") { | ||
var scope = self.scope; | ||
do { | ||
if (scope instanceof AST_Defun || is_func_expr(scope)) { | ||
set_flag(scope, INLINED); | ||
} | ||
} while (scope = scope.parent_scope); | ||
if (fixed instanceof AST_Defun) { | ||
set_flag(fixed, SQUEEZED); | ||
fixed = make_node(AST_Function, fixed, fixed); | ||
} | ||
if (def.recursive_refs > 0 && fixed.name instanceof AST_SymbolDefun) { | ||
const defun_def = fixed.name.definition(); | ||
let lambda_def = fixed.variables.get(fixed.name.name); | ||
let name = lambda_def && lambda_def.orig[0]; | ||
if (!(name instanceof AST_SymbolLambda)) { | ||
name = make_node(AST_SymbolLambda, fixed.name, fixed.name); | ||
name.scope = fixed; | ||
fixed.name = name; | ||
lambda_def = fixed.def_function(name); | ||
} | ||
walk(fixed, node => { | ||
if (node instanceof AST_SymbolRef && node.definition() === defun_def) { | ||
node.thedef = lambda_def; | ||
lambda_def.references.push(node); | ||
} | ||
} | ||
}); | ||
} | ||
if ( | ||
(fixed instanceof AST_Lambda || fixed instanceof AST_Class) | ||
&& fixed.parent_scope !== nearest_scope | ||
) { | ||
fixed = fixed.clone(true, compressor.get_toplevel()); | ||
if (single_use && (fixed instanceof AST_Lambda || fixed instanceof AST_Class)) { | ||
single_use = | ||
def.scope === self.scope | ||
&& !scope_encloses_variables_in_this_scope(nearest_scope, fixed) | ||
|| parent instanceof AST_Call | ||
&& parent.expression === self | ||
&& !scope_encloses_variables_in_this_scope(nearest_scope, fixed) | ||
&& !(fixed.name && fixed.name.definition().recursive_refs > 0); | ||
nearest_scope.add_child_scope(fixed); | ||
} | ||
return fixed.optimize(compressor); | ||
} | ||
if (single_use && fixed) { | ||
if (fixed instanceof AST_DefClass) { | ||
set_flag(fixed, SQUEEZED); | ||
fixed = make_node(AST_ClassExpression, fixed, fixed); | ||
// multiple uses | ||
if (fixed) { | ||
let replace; | ||
if (fixed instanceof AST_This) { | ||
if (!(def.orig[0] instanceof AST_SymbolFunarg) | ||
&& def.references.every((ref) => | ||
def.scope === ref.scope | ||
)) { | ||
replace = fixed; | ||
} | ||
if (fixed instanceof AST_Defun) { | ||
set_flag(fixed, SQUEEZED); | ||
fixed = make_node(AST_Function, fixed, fixed); | ||
} | ||
if (def.recursive_refs > 0 && fixed.name instanceof AST_SymbolDefun) { | ||
const defun_def = fixed.name.definition(); | ||
let lambda_def = fixed.variables.get(fixed.name.name); | ||
let name = lambda_def && lambda_def.orig[0]; | ||
if (!(name instanceof AST_SymbolLambda)) { | ||
name = make_node(AST_SymbolLambda, fixed.name, fixed.name); | ||
name.scope = fixed; | ||
fixed.name = name; | ||
lambda_def = fixed.def_function(name); | ||
} | ||
walk(fixed, node => { | ||
if (node instanceof AST_SymbolRef && node.definition() === defun_def) { | ||
node.thedef = lambda_def; | ||
lambda_def.references.push(node); | ||
} | ||
}); | ||
} | ||
} else { | ||
var ev = fixed.evaluate(compressor); | ||
if ( | ||
(fixed instanceof AST_Lambda || fixed instanceof AST_Class) | ||
&& fixed.parent_scope !== nearest_scope | ||
ev !== fixed | ||
&& (compressor.option("unsafe_regexp") || !(ev instanceof RegExp)) | ||
) { | ||
fixed = fixed.clone(true, compressor.get_toplevel()); | ||
nearest_scope.add_child_scope(fixed); | ||
replace = make_node_from_constant(ev, fixed); | ||
} | ||
return fixed.optimize(compressor); | ||
} | ||
// multiple uses | ||
if (fixed) { | ||
let replace; | ||
if (replace) { | ||
const name_length = self.size(compressor); | ||
const replace_size = replace.size(compressor); | ||
if (fixed instanceof AST_This) { | ||
if (!(def.orig[0] instanceof AST_SymbolFunarg) | ||
&& def.references.every((ref) => | ||
def.scope === ref.scope | ||
)) { | ||
replace = fixed; | ||
} | ||
} else { | ||
var ev = fixed.evaluate(compressor); | ||
if ( | ||
ev !== fixed | ||
&& (compressor.option("unsafe_regexp") || !(ev instanceof RegExp)) | ||
) { | ||
replace = make_node_from_constant(ev, fixed); | ||
} | ||
let overhead = 0; | ||
if (compressor.option("unused") && !compressor.exposed(def)) { | ||
overhead = | ||
(name_length + 2 + replace_size) / | ||
(def.references.length - def.assignments); | ||
} | ||
if (replace) { | ||
const name_length = self.size(compressor); | ||
const replace_size = replace.size(compressor); | ||
let overhead = 0; | ||
if (compressor.option("unused") && !compressor.exposed(def)) { | ||
overhead = | ||
(name_length + 2 + replace_size) / | ||
(def.references.length - def.assignments); | ||
} | ||
if (replace_size <= name_length + overhead) { | ||
return replace; | ||
} | ||
if (replace_size <= name_length + overhead) { | ||
return replace; | ||
} | ||
@@ -281,0 +286,0 @@ } |
@@ -106,5 +106,6 @@ /*********************************************************************** | ||
// Define the method AST_Node#reduce_vars, which goes through the AST in | ||
// execution order to perform basic flow analysis | ||
/** | ||
* Define the method AST_Node#reduce_vars, which goes through the AST in | ||
* execution order to perform basic flow analysis | ||
*/ | ||
function def_reduce_vars(node, func) { | ||
@@ -116,2 +117,3 @@ node.DEFMETHOD("reduce_vars", func); | ||
/** Clear definition properties */ | ||
function reset_def(compressor, def) { | ||
@@ -125,3 +127,6 @@ def.assignments = 0; | ||
def.single_use = undefined; | ||
if (def.scope.pinned()) { | ||
if ( | ||
def.scope.pinned() | ||
|| (def.orig[0] instanceof AST_SymbolFunarg && def.scope.uses_arguments) | ||
) { | ||
def.fixed = false; | ||
@@ -448,11 +453,19 @@ } else if (def.orig[0] instanceof AST_SymbolConst || !compressor.exposed(def)) { | ||
clear_flag(this, INLINED); | ||
push(tw); | ||
// Sometimes we detach the lambda for safety, and instead of push() | ||
// we go to an entirely fresh lineage of safe_ids. | ||
let previous_safe_ids; | ||
if (this instanceof AST_Defun || this.uses_arguments || this.pinned()) { | ||
previous_safe_ids = tw.safe_ids; | ||
tw.safe_ids = Object.create(null); | ||
} else { | ||
push(tw); | ||
} | ||
reset_variables(tw, compressor, this); | ||
if (this.uses_arguments) { | ||
descend(); | ||
pop(tw); | ||
return; | ||
} | ||
var iife; | ||
if (!this.name | ||
&& !this.uses_arguments | ||
&& !this.pinned() | ||
&& (iife = tw.parent()) instanceof AST_Call | ||
@@ -483,3 +496,9 @@ && iife.expression === this | ||
descend(); | ||
pop(tw); | ||
if (previous_safe_ids) { | ||
tw.safe_ids = previous_safe_ids; | ||
} else { | ||
pop(tw); | ||
} | ||
return true; | ||
@@ -486,0 +505,0 @@ } |
@@ -7,3 +7,3 @@ { | ||
"license": "BSD-2-Clause", | ||
"version": "5.16.2", | ||
"version": "5.16.3", | ||
"engines": { | ||
@@ -10,0 +10,0 @@ "node": ">=10" |
Sorry, the diff of this file is too big to display
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
2066039
58873
1