Skip to content

Commit eb7f316

Browse files
committed
Minify boolean and numeric literals in obfuscated mode
1 parent 4b6a646 commit eb7f316

File tree

9 files changed

+178
-37
lines changed

9 files changed

+178
-37
lines changed

dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@
151151
import com.google.gwt.dev.js.JsStackEmulator;
152152
import com.google.gwt.dev.js.JsStaticEval;
153153
import com.google.gwt.dev.js.JsSymbolResolver;
154+
import com.google.gwt.dev.js.JsToStringGenerationVisitor;
154155
import com.google.gwt.dev.js.JsUnusedFunctionRemover;
155156
import com.google.gwt.dev.js.JsVerboseNamer;
156157
import com.google.gwt.dev.js.SizeBreakdown;
@@ -772,7 +773,9 @@ private void generateJavaScriptCode(JavaToJavaScriptMap jjsMap, String[] jsFragm
772773
DefaultTextOutput out = new DefaultTextOutput(!options.isIncrementalCompileEnabled() &&
773774
options.getOutput().shouldMinimize());
774775
JsReportGenerationVisitor v = new JsReportGenerationVisitor(out, jjsMap,
775-
options.isJsonSoycEnabled());
776+
options.isJsonSoycEnabled(),
777+
new JsToStringGenerationVisitor.PrintOptions(false,
778+
options.getOutput() == JsOutputOption.DETAILED));
776779
v.accept(jsProgram.getFragmentBlock(i));
777780

778781
StatementRanges statementRanges = v.getStatementRanges();

dev/core/src/com/google/gwt/dev/js/JsReportGenerationVisitor.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,8 @@ public class JsReportGenerationVisitor extends
5656
private List<JsNode> parentStack = Lists.newArrayList();
5757

5858
public JsReportGenerationVisitor(TextOutput out, JavaToJavaScriptMap map,
59-
boolean needSourcemapNames) {
60-
super(out, map);
59+
boolean needSourcemapNames, PrintOptions options) {
60+
super(out, map, options);
6161
this.out = out;
6262
this.needSourcemapNames = needSourcemapNames;
6363
}

dev/core/src/com/google/gwt/dev/js/JsSourceGenerationVisitor.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,10 @@ public JsSourceGenerationVisitor(TextOutput out) {
3636
/**
3737
* Generate the output source code using short or long identifiers.
3838
*
39-
* @param useLongIdents if true, emit all identifiers in long form
39+
* @param options minification options
4040
*/
41-
public JsSourceGenerationVisitor(TextOutput out, boolean useLongIdents) {
42-
super(out, useLongIdents);
41+
public JsSourceGenerationVisitor(TextOutput out, PrintOptions options) {
42+
super(out, options);
4343
}
4444

4545
@Override

dev/core/src/com/google/gwt/dev/js/JsSourceGenerationVisitorWithSizeBreakdown.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,8 @@ public class JsSourceGenerationVisitorWithSizeBreakdown extends JsSourceGenerati
4040
private final Map<JsName, Integer> sizeMap = new HashMap<JsName, Integer>();
4141

4242
public JsSourceGenerationVisitorWithSizeBreakdown(TextOutput out,
43-
JavaToJavaScriptMap javaToJavaScriptMap) {
44-
super(out);
43+
JavaToJavaScriptMap javaToJavaScriptMap, PrintOptions options) {
44+
super(out, options);
4545
this.out = out;
4646
this.map = javaToJavaScriptMap;
4747
}

dev/core/src/com/google/gwt/dev/js/JsToStringGenerationVisitor.java

Lines changed: 79 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -115,9 +115,10 @@ public class JsToStringGenerationVisitor extends JsVisitor {
115115
* How many lines of code to print inside of a JsBlock when printing terse.
116116
*/
117117
private static final int JSBLOCK_LINES_TO_PRINT = 3;
118+
private static final long MAX_DECIMAL_VALUE = 999_999_999_999L;
118119

119120
protected boolean needSemi = true;
120-
private List<NamedRange> classRanges = new ArrayList<NamedRange>();
121+
private final List<NamedRange> classRanges = new ArrayList<>();
121122
private NamedRange currentClassRange;
122123
private NamedRange programClassRange;
123124

@@ -127,27 +128,39 @@ public class JsToStringGenerationVisitor extends JsVisitor {
127128
* because the statements designated by statementEnds and statementStarts are
128129
* those that appear directly within these global blocks.
129130
*/
130-
private Set<JsBlock> globalBlocks = new HashSet<JsBlock>();
131+
private final Set<JsBlock> globalBlocks = new HashSet<>();
131132
private final TextOutput p;
132-
private ArrayList<Integer> statementEnds = new ArrayList<Integer>();
133-
private ArrayList<Integer> statementStarts = new ArrayList<Integer>();
133+
private final ArrayList<Integer> statementEnds = new ArrayList<>();
134+
private final ArrayList<Integer> statementStarts = new ArrayList<>();
134135
private final boolean useLongIdents;
136+
private final boolean minifyLiterals;
137+
138+
public static class PrintOptions {
139+
public final boolean useLongIdents;
140+
public final boolean minifyLiterals;
141+
142+
public PrintOptions(boolean useLongIdents, boolean minifyLiterals) {
143+
this.useLongIdents = useLongIdents;
144+
this.minifyLiterals = minifyLiterals;
145+
}
146+
}
135147

136148
/**
137149
* Generate the output string using short identifiers.
138150
*/
139151
public JsToStringGenerationVisitor(TextOutput out) {
140-
this(out, false);
152+
this(out, new PrintOptions(false, false));
141153
}
142154

143155
/**
144156
* Generate the output string using short or long identifiers.
145157
*
146-
* @param useLongIdents if true, emit all identifiers in long form
158+
* @param options settings for minification
147159
*/
148-
JsToStringGenerationVisitor(TextOutput out, boolean useLongIdents) {
160+
JsToStringGenerationVisitor(TextOutput out, PrintOptions options) {
149161
this.p = out;
150-
this.useLongIdents = useLongIdents;
162+
this.useLongIdents = options.useLongIdents;
163+
this.minifyLiterals = options.minifyLiterals;
151164
}
152165

153166
public List<NamedRange> getClassRanges() {
@@ -183,8 +196,7 @@ public boolean visit(JsArrayAccess x, JsContext ctx) {
183196
public boolean visit(JsArrayLiteral x, JsContext ctx) {
184197
_lsquare();
185198
boolean sep = false;
186-
for (Object element : x.getExpressions()) {
187-
JsExpression arg = (JsExpression) element;
199+
for (JsExpression arg : x.getExpressions()) {
188200
sep = _sepCommaOptSpace(sep);
189201
_parenPushIfCommaExpr(arg);
190202
accept(arg);
@@ -227,6 +239,10 @@ public boolean visit(JsBlock x, JsContext ctx) {
227239

228240
@Override
229241
public boolean visit(JsBooleanLiteral x, JsContext ctx) {
242+
if (minifyLiterals) {
243+
p.print(x.getValue() ? "!0" : "!1");
244+
return false;
245+
}
230246
if (x.getValue()) {
231247
_true();
232248
} else {
@@ -257,8 +273,7 @@ public boolean visit(JsCase x, JsContext ctx) {
257273
_newlineOpt();
258274

259275
indent();
260-
for (Object element : x.getStmts()) {
261-
JsStatement stmt = (JsStatement) element;
276+
for (JsStatement stmt : x.getStmts()) {
262277
needSemi = true;
263278
accept(stmt);
264279
if (needSemi) {
@@ -387,8 +402,7 @@ public boolean visit(JsDefault x, JsContext ctx) {
387402
_colon();
388403

389404
indent();
390-
for (Object element : x.getStmts()) {
391-
JsStatement stmt = (JsStatement) element;
405+
for (JsStatement stmt : x.getStmts()) {
392406
needSemi = true;
393407
accept(stmt);
394408
if (needSemi) {
@@ -532,8 +546,7 @@ public boolean visit(JsFunction x, JsContext ctx) {
532546

533547
_lparen();
534548
boolean sep = false;
535-
for (Object element : x.getParameters()) {
536-
JsParameter param = (JsParameter) element;
549+
for (JsParameter param : x.getParameters()) {
537550
sep = _sepCommaOptSpace(sep);
538551
accept(param);
539552
}
@@ -588,8 +601,7 @@ public boolean visit(JsInvocation x, JsContext ctx) {
588601

589602
_lparen();
590603
boolean sep = false;
591-
for (Object element : x.getArguments()) {
592-
JsExpression arg = (JsExpression) element;
604+
for (JsExpression arg : x.getArguments()) {
593605
sep = _sepCommaOptSpace(sep);
594606
_parenPushIfCommaExpr(arg);
595607
accept(arg);
@@ -626,7 +638,7 @@ public boolean visit(JsNameRef x, JsContext ctx) {
626638
_parenPush(x, q, false);
627639
accept(q);
628640
if (q instanceof JsNumberLiteral) {
629-
/**
641+
/*
630642
* Fix for Issue #3796. "42.foo" is not allowed, but "42 .foo" is.
631643
*/
632644
_space();
@@ -690,13 +702,40 @@ public boolean visit(JsNumberLiteral x, JsContext ctx) {
690702

691703
long lvalue = (long) dvalue;
692704
if (lvalue == dvalue) {
693-
p.print(Long.toString(lvalue));
705+
String longVal = Long.toString(lvalue);
706+
if (minifyLiterals && lvalue != 0) {
707+
int trailingZeros = numberOfTrailingDecZeros(longVal);
708+
if (trailingZeros > 2) {
709+
// print 1000 as 1e3, keep 100 as is
710+
longVal = longVal.substring(0, longVal.length() - trailingZeros) + "e" + trailingZeros;
711+
} else if (Math.abs(lvalue) > MAX_DECIMAL_VALUE) {
712+
// from 1e12 we may save 1 or 2 bytes by using the hex code
713+
longVal = (lvalue < 0 ? "-0x" : "0x") + Long.toString(Math.abs(lvalue), 16);
714+
}
715+
}
716+
p.print(longVal);
694717
} else {
695-
p.print(Double.toString(dvalue));
718+
String doubleVal = Double.toString(dvalue);
719+
if (minifyLiterals) {
720+
if (doubleVal.startsWith("0.")) {
721+
doubleVal = doubleVal.substring(1);
722+
} else if (doubleVal.startsWith("-0.")) {
723+
doubleVal = "-" + doubleVal.substring(2);
724+
}
725+
}
726+
p.print(doubleVal);
696727
}
697728
return false;
698729
}
699730

731+
private int numberOfTrailingDecZeros(String longVal) {
732+
int idx = longVal.length() - 1;
733+
while (longVal.charAt(idx) == '0') {
734+
idx--;
735+
}
736+
return longVal.length() - idx - 1;
737+
}
738+
700739
@Override
701740
public boolean visit(JsNumericEntry x, JsContext ctx) {
702741
p.print(Integer.toString(x.getValue()));
@@ -790,7 +829,11 @@ public boolean visit(JsReturn x, JsContext ctx) {
790829
_return();
791830
JsExpression expr = x.getExpr();
792831
if (expr != null) {
793-
_space();
832+
if (spaceReturn(expr)) {
833+
_space();
834+
} else {
835+
_spaceOpt();
836+
}
794837
accept(expr);
795838
}
796839
return false;
@@ -1275,6 +1318,20 @@ private boolean _spaceCalc(JsOperator op, JsExpression arg) {
12751318
return false;
12761319
}
12771320

1321+
private boolean spaceReturn(JsExpression arg) {
1322+
if (arg instanceof JsBooleanLiteral) {
1323+
return !minifyLiterals;
1324+
}
1325+
if (arg instanceof JsPrefixOperation) {
1326+
return ((JsPrefixOperation) arg).getOperator().isKeyword();
1327+
}
1328+
if (arg instanceof JsNumberLiteral) {
1329+
double value = ((JsNumberLiteral) arg).getValue();
1330+
return Double.isNaN(value) || value > 0 || 1 / value > 0;
1331+
}
1332+
return true;
1333+
}
1334+
12781335
private void _spaceOpt() {
12791336
p.printOpt(' ');
12801337
}

dev/core/src/com/google/gwt/dev/js/ast/JsNode.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,8 @@ public final String toSource() {
5959
*/
6060
public final String toSource(boolean useLongIdents) {
6161
DefaultTextOutput out = new DefaultTextOutput(false);
62-
JsSourceGenerationVisitor v = new JsSourceGenerationVisitor(out, useLongIdents);
62+
JsSourceGenerationVisitor v = new JsSourceGenerationVisitor(out,
63+
new JsToStringGenerationVisitor.PrintOptions(useLongIdents, false));
6364
v.accept(this);
6465
return out.toString();
6566
}

dev/core/src/com/google/gwt/dev/util/AbstractTextOutput.java

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -73,11 +73,7 @@ public void indentOut() {
7373

7474
@Override
7575
public void newline() {
76-
if (compact) {
77-
out.print('\n');
78-
} else {
79-
out.print('\n');
80-
}
76+
out.print('\n');
8177
position++;
8278
line++;
8379
column = 0;

dev/core/test/com/google/gwt/dev/js/JsReportGenerationVisitorTest.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,8 @@ private void checkMappings(String ...expectedLines)
253253
throws IOException, JsParserException {
254254
DefaultTextOutput text = new DefaultTextOutput(compact);
255255
JsReportGenerationVisitor generator = new JsReportGenerationVisitor(text,
256-
JavaToJavaScriptMap.EMPTY, false) {
256+
JavaToJavaScriptMap.EMPTY, false,
257+
new JsToStringGenerationVisitor.PrintOptions(false, false)) {
257258
@Override
258259
boolean surroundsInJavaSource(SourceInfo parent, SourceInfo child) {
259260
// The Rhino-based JavaScript parser doesn't provide character ranges

0 commit comments

Comments
 (0)