Skip to content

Commit

Permalink
experiment with equality operand orderings (#2364)
Browse files Browse the repository at this point in the history
  • Loading branch information
evanw committed Jul 6, 2022
1 parent ffbc5c2 commit 580ad40
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 18 deletions.
20 changes: 20 additions & 0 deletions internal/js_parser/js_parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -12196,6 +12196,26 @@ func (p *parser) visitExprInOut(expr js_ast.Expr, in exprIn) (js_ast.Expr, exprO
}
p.fnOnlyDataVisit.silenceWarningAboutThisBeingUndefined = oldSilenceWarningAboutThisBeingUndefined

// Always put constants consistently on the same side for equality
// comparisons to help improve compression. In theory, dictionary-based
// compression methods may already have a dictionary entry for code that
// is similar to previous code. Note that we can only reorder expressions
// that do not have any side effects.
//
// Constants are currently ordered on the right instead of the left because
// it results in slightly smalller gzip size on our primary benchmark
// (although slightly larger uncompressed size). The size difference is
// less than 0.1% so it really isn't that important an optimization.
if p.options.minifySyntax {
switch e.Op {
case js_ast.BinOpLooseEq, js_ast.BinOpLooseNe, js_ast.BinOpStrictEq, js_ast.BinOpStrictNe:
// "1 === x" => "x === 1"
if isPrimitiveLiteral(e.Left.Data) && !isPrimitiveLiteral(e.Right.Data) {
e.Left, e.Right = e.Right, e.Left
}
}
}

// Post-process the binary expression
switch e.Op {
case js_ast.BinOpComma:
Expand Down
36 changes: 18 additions & 18 deletions internal/js_parser/js_parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3172,20 +3172,20 @@ func TestMangleIf(t *testing.T) {

expectPrintedMangle(t, "let b; a = null == b ? c : b", "let b;\na = b ?? c;\n")
expectPrintedMangle(t, "let b; a = null != b ? b : c", "let b;\na = b ?? c;\n")
expectPrintedMangle(t, "let b; a = null == b ? b : c", "let b;\na = null == b ? b : c;\n")
expectPrintedMangle(t, "let b; a = null != b ? c : b", "let b;\na = null != b ? c : b;\n")
expectPrintedMangle(t, "let b; a = null == b ? b : c", "let b;\na = b == null ? b : c;\n")
expectPrintedMangle(t, "let b; a = null != b ? c : b", "let b;\na = b != null ? c : b;\n")

// Don't do this if the condition has side effects
expectPrintedMangle(t, "let b; a = b.x == null ? c : b.x", "let b;\na = b.x == null ? c : b.x;\n")
expectPrintedMangle(t, "let b; a = b.x != null ? b.x : c", "let b;\na = b.x != null ? b.x : c;\n")
expectPrintedMangle(t, "let b; a = null == b.x ? c : b.x", "let b;\na = null == b.x ? c : b.x;\n")
expectPrintedMangle(t, "let b; a = null != b.x ? b.x : c", "let b;\na = null != b.x ? b.x : c;\n")
expectPrintedMangle(t, "let b; a = null == b.x ? c : b.x", "let b;\na = b.x == null ? c : b.x;\n")
expectPrintedMangle(t, "let b; a = null != b.x ? b.x : c", "let b;\na = b.x != null ? b.x : c;\n")

// Don't do this for strict equality comparisons
expectPrintedMangle(t, "let b; a = b === null ? c : b", "let b;\na = b === null ? c : b;\n")
expectPrintedMangle(t, "let b; a = b !== null ? b : c", "let b;\na = b !== null ? b : c;\n")
expectPrintedMangle(t, "let b; a = null === b ? c : b", "let b;\na = null === b ? c : b;\n")
expectPrintedMangle(t, "let b; a = null !== b ? b : c", "let b;\na = null !== b ? b : c;\n")
expectPrintedMangle(t, "let b; a = null === b ? c : b", "let b;\na = b === null ? c : b;\n")
expectPrintedMangle(t, "let b; a = null !== b ? b : c", "let b;\na = b !== null ? b : c;\n")

expectPrintedMangle(t, "let b; a = null === b || b === undefined ? c : b", "let b;\na = b ?? c;\n")
expectPrintedMangle(t, "let b; a = b !== undefined && b !== null ? b : c", "let b;\na = b ?? c;\n")
Expand Down Expand Up @@ -3317,8 +3317,8 @@ func TestMangleOptionalChain(t *testing.T) {

expectPrintedMangle(t, "a == null && a.b()", "a == null && a.b();\n")
expectPrintedMangle(t, "a != null || a.b()", "a != null || a.b();\n")
expectPrintedMangle(t, "null == a && a.b()", "null == a && a.b();\n")
expectPrintedMangle(t, "null != a || a.b()", "null != a || a.b();\n")
expectPrintedMangle(t, "null == a && a.b()", "a == null && a.b();\n")
expectPrintedMangle(t, "null != a || a.b()", "a != null || a.b();\n")

expectPrintedMangle(t, "x = a != null && a.b()", "x = a != null && a.b();\n")
expectPrintedMangle(t, "x = a == null || a.b()", "x = a == null || a.b();\n")
Expand Down Expand Up @@ -3746,13 +3746,13 @@ func TestMangleTypeofIdentifier(t *testing.T) {
func TestMangleTypeofEqualsUndefined(t *testing.T) {
expectPrintedMangle(t, "return typeof x !== 'undefined'", "return typeof x < \"u\";\n")
expectPrintedMangle(t, "return typeof x != 'undefined'", "return typeof x < \"u\";\n")
expectPrintedMangle(t, "return 'undefined' !== typeof x", "return \"u\" > typeof x;\n")
expectPrintedMangle(t, "return 'undefined' != typeof x", "return \"u\" > typeof x;\n")
expectPrintedMangle(t, "return 'undefined' !== typeof x", "return typeof x < \"u\";\n")
expectPrintedMangle(t, "return 'undefined' != typeof x", "return typeof x < \"u\";\n")

expectPrintedMangle(t, "return typeof x === 'undefined'", "return typeof x > \"u\";\n")
expectPrintedMangle(t, "return typeof x == 'undefined'", "return typeof x > \"u\";\n")
expectPrintedMangle(t, "return 'undefined' === typeof x", "return \"u\" < typeof x;\n")
expectPrintedMangle(t, "return 'undefined' == typeof x", "return \"u\" < typeof x;\n")
expectPrintedMangle(t, "return 'undefined' === typeof x", "return typeof x > \"u\";\n")
expectPrintedMangle(t, "return 'undefined' == typeof x", "return typeof x > \"u\";\n")
}

func TestMangleEquals(t *testing.T) {
Expand All @@ -3763,8 +3763,8 @@ func TestMangleEquals(t *testing.T) {

expectPrintedMangle(t, "return typeof x === 'string'", "return typeof x == \"string\";\n")
expectPrintedMangle(t, "return typeof x !== 'string'", "return typeof x != \"string\";\n")
expectPrintedMangle(t, "return 'string' === typeof x", "return \"string\" == typeof x;\n")
expectPrintedMangle(t, "return 'string' !== typeof x", "return \"string\" != typeof x;\n")
expectPrintedMangle(t, "return 'string' === typeof x", "return typeof x == \"string\";\n")
expectPrintedMangle(t, "return 'string' !== typeof x", "return typeof x != \"string\";\n")

expectPrintedMangle(t, "return a === 0", "return a === 0;\n")
expectPrintedMangle(t, "return a !== 0", "return a !== 0;\n")
Expand Down Expand Up @@ -3890,13 +3890,13 @@ func TestMangleNestedLogical(t *testing.T) {
func TestMangleEqualsUndefined(t *testing.T) {
expectPrintedMangle(t, "return a === void 0", "return a === void 0;\n")
expectPrintedMangle(t, "return a !== void 0", "return a !== void 0;\n")
expectPrintedMangle(t, "return void 0 === a", "return void 0 === a;\n")
expectPrintedMangle(t, "return void 0 !== a", "return void 0 !== a;\n")
expectPrintedMangle(t, "return void 0 === a", "return a === void 0;\n")
expectPrintedMangle(t, "return void 0 !== a", "return a !== void 0;\n")

expectPrintedMangle(t, "return a == void 0", "return a == null;\n")
expectPrintedMangle(t, "return a != void 0", "return a != null;\n")
expectPrintedMangle(t, "return void 0 == a", "return null == a;\n")
expectPrintedMangle(t, "return void 0 != a", "return null != a;\n")
expectPrintedMangle(t, "return void 0 == a", "return a == null;\n")
expectPrintedMangle(t, "return void 0 != a", "return a != null;\n")

expectPrintedMangle(t, "return a === null || a === undefined", "return a == null;\n")
expectPrintedMangle(t, "return a === null || a !== undefined", "return a === null || a !== void 0;\n")
Expand Down

0 comments on commit 580ad40

Please sign in to comment.