Merging long emulation branch into trunk. Longs are now emulated in web mode as a pair of doubles, representing the upper and lower 32
bits.
TODO(spoon): warn on long values passing between Java and JavaScript
Patch by: spoon (LongLib/LongLibTest), me (most everything else)
Review by: fabbott (LongLib/JRE changes), bobv & spoon (TBR, everything else)
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@2145 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/dev/core/build.xml b/dev/core/build.xml
index 6c61218..a89c2eb 100755
--- a/dev/core/build.xml
+++ b/dev/core/build.xml
@@ -94,6 +94,7 @@
<antcall target="-filter.src" />
<mkdir dir="${javac.out}" />
+ <gwt.javac srcdir="super" excludes="com/google/gwt/dev/jjs/intrinsic/"/>
<gwt.javac srcdir="${src.filtered}" />
<gwt.javac srcdir="src" excludes="${filter.pattern}">
<classpath>
diff --git a/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java b/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java
index b36f237..dfd635a 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java
@@ -48,8 +48,10 @@
import com.google.gwt.dev.jjs.impl.GenerateJavaScriptAST;
import com.google.gwt.dev.jjs.impl.JavaScriptObjectNormalizer;
import com.google.gwt.dev.jjs.impl.JsoDevirtualizer;
+import com.google.gwt.dev.jjs.impl.LongCastNormalizer;
+import com.google.gwt.dev.jjs.impl.LongEmulationNormalizer;
import com.google.gwt.dev.jjs.impl.MakeCallsStatic;
-import com.google.gwt.dev.jjs.impl.MethodAndClassFinalizer;
+import com.google.gwt.dev.jjs.impl.Finalizer;
import com.google.gwt.dev.jjs.impl.MethodCallTightener;
import com.google.gwt.dev.jjs.impl.MethodInliner;
import com.google.gwt.dev.jjs.impl.Pruner;
@@ -287,9 +289,7 @@
String[] all = rpo.getAllPossibleRebindAnswers(logger, element);
Util.addAll(allEntryPoints, all);
}
- allEntryPoints.add("com.google.gwt.lang.Array");
- allEntryPoints.add("com.google.gwt.lang.Cast");
- allEntryPoints.add("com.google.gwt.lang.Exceptions");
+ allEntryPoints.addAll(JProgram.CODEGEN_TYPES_SET);
allEntryPoints.add("com.google.gwt.lang.Stats");
allEntryPoints.add("java.lang.Object");
allEntryPoints.add("java.lang.String");
@@ -399,7 +399,7 @@
// Remove unreferenced types, fields, methods, [params, locals]
didChange = Pruner.exec(jprogram, true) || didChange;
// finalize locals, params, fields, methods, classes
- didChange = MethodAndClassFinalizer.exec(jprogram) || didChange;
+ didChange = Finalizer.exec(jprogram) || didChange;
// rewrite non-polymorphic calls as static calls; update all call sites
didChange = MakeCallsStatic.exec(jprogram) || didChange;
@@ -428,9 +428,11 @@
// (5) "Normalize" the high-level Java tree into a lower-level tree more
// suited for JavaScript code generation. Don't go reordering these
// willy-nilly because there are some subtle interdependencies.
+ LongCastNormalizer.exec(jprogram);
JsoDevirtualizer.exec(jprogram);
CatchBlockNormalizer.exec(jprogram);
CompoundAssignmentNormalizer.exec(jprogram);
+ LongEmulationNormalizer.exec(jprogram);
CastNormalizer.exec(jprogram);
ArrayNormalizer.exec(jprogram);
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/CanBeSetFinal.java b/dev/core/src/com/google/gwt/dev/jjs/ast/CanBeSetFinal.java
index 0c4e2b4..39c9709 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/CanBeSetFinal.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/CanBeSetFinal.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2007 Google Inc.
+ * Copyright 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
@@ -19,6 +19,6 @@
* Characteristic interface to be overlaid on AST constructs that can retain a
* boolean 'final' flag.
*/
-public interface CanBeSetFinal {
- void setFinal(boolean b);
+public interface CanBeSetFinal extends CanBeFinal {
+ void setFinal();
}
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/HasInitializer.java b/dev/core/src/com/google/gwt/dev/jjs/ast/CanHaveInitializer.java
similarity index 84%
rename from dev/core/src/com/google/gwt/dev/jjs/ast/HasInitializer.java
rename to dev/core/src/com/google/gwt/dev/jjs/ast/CanHaveInitializer.java
index 20a97f7..a6cdbfc 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/HasInitializer.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/CanHaveInitializer.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2007 Google Inc.
+ * Copyright 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
@@ -16,9 +16,11 @@
package com.google.gwt.dev.jjs.ast;
/**
- * Interface implemented by Java entities that can have an initialization
+ * Interface implemented by Java entities that can have an initialization
* expression.
*/
-public interface HasInitializer {
+public interface CanHaveInitializer {
+ JLiteral getConstInitializer();
+ boolean hasInitializer();
void setInitializer(JExpression expression);
}
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JArrayRef.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JArrayRef.java
index d745816..c6d368a 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JArrayRef.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JArrayRef.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2007 Google Inc.
+ * Copyright 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
@@ -56,7 +56,9 @@
}
public boolean hasSideEffects() {
- return instance.hasSideEffects() || indexExpr.hasSideEffects();
+ // TODO: make the last test better when we have null tracking.
+ return instance.hasSideEffects() || indexExpr.hasSideEffects()
+ || instance.getType() == program.getTypeNull();
}
public void traverse(JVisitor visitor, Context ctx) {
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JArrayType.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JArrayType.java
index 82261db..a220699 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JArrayType.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JArrayType.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2007 Google Inc.
+ * Copyright 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
@@ -81,7 +81,7 @@
}
public boolean isFinal() {
- return false;
+ return leafType.isFinal();
}
public void traverse(JVisitor visitor, Context ctx) {
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JBinaryOperation.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JBinaryOperation.java
index b8ac8a9..1694a80 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JBinaryOperation.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JBinaryOperation.java
@@ -49,11 +49,8 @@
}
public JType getType() {
- if (op == JBinaryOperator.ASG) {
- // Use rhs because (generality lhs >= generality rhs)
- return getRhs().getType();
- } else if (isAssignment()) {
- // Use lhs because this is really a write-then-read
+ if (isAssignment()) {
+ // Use the type of the lhs
return getLhs().getType();
} else {
// Most binary operators never change type
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JBinaryOperator.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JBinaryOperator.java
index 72785fd..1922711 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JBinaryOperator.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JBinaryOperator.java
@@ -20,58 +20,35 @@
* 750, Table 2. I just numbered the table top to bottom as 0 through 14. Lower
* number means higher precedence.
*/
-public class JBinaryOperator {
+public enum JBinaryOperator {
- public static final JBinaryOperator MUL = new JBinaryOperator("*", 3);
- public static final JBinaryOperator DIV = new JBinaryOperator("/", 3);
- public static final JBinaryOperator MOD = new JBinaryOperator("%", 3);
- public static final JBinaryOperator ADD = new JBinaryOperator("+", 4);
- public static final JBinaryOperator SUB = new JBinaryOperator("-", 4);
+ // Don't renumber precs without checking implementation of isShiftOperator()
- public static final JBinaryOperator SHL = new JBinaryOperator("<<", 5);
- public static final JBinaryOperator SHR = new JBinaryOperator(">>", 5);
- public static final JBinaryOperator SHRU = new JBinaryOperator(">>>", 5);
-
- public static final JBinaryOperator LT = new JBinaryOperator("<", 6);
- public static final JBinaryOperator LTE = new JBinaryOperator("<=", 6);
- public static final JBinaryOperator GT = new JBinaryOperator(">", 6);
- public static final JBinaryOperator GTE = new JBinaryOperator(">=", 6);
-
- public static final JBinaryOperator EQ = new JBinaryOperator("==", 7);
- public static final JBinaryOperator NEQ = new JBinaryOperator("!=", 7);
-
- public static final JBinaryOperator BIT_AND = new JBinaryOperator("&", 8);
-
- public static final JBinaryOperator BIT_XOR = new JBinaryOperator("^", 9);
-
- public static final JBinaryOperator BIT_OR = new JBinaryOperator("|", 10);
-
- public static final JBinaryOperator AND = new JBinaryOperator("&&", 11);
-
- public static final JBinaryOperator OR = new JBinaryOperator("||", 12);
-
- // Don't renumber ASG precs without checking implementation of isAssignment()
- public static final JBinaryOperator ASG = new JBinaryOperator("=", 14);
- public static final JBinaryOperator ASG_ADD = new JBinaryOperator("+=", 14);
- public static final JBinaryOperator ASG_SUB = new JBinaryOperator("-=", 14);
- public static final JBinaryOperator ASG_MUL = new JBinaryOperator("*=", 14);
- public static final JBinaryOperator ASG_DIV = new JBinaryOperator("/=", 14);
- public static final JBinaryOperator ASG_MOD = new JBinaryOperator("%=", 14);
- public static final JBinaryOperator ASG_SHL = new JBinaryOperator("<<=", 14);
- public static final JBinaryOperator ASG_SHR = new JBinaryOperator(">>=", 14);
- public static final JBinaryOperator ASG_SHRU = new JBinaryOperator(">>>=", 14);
- public static final JBinaryOperator ASG_BIT_AND = new JBinaryOperator("&=",
- 14);
- public static final JBinaryOperator ASG_BIT_OR = new JBinaryOperator("|=", 14);
- public static final JBinaryOperator ASG_BIT_XOR = new JBinaryOperator("^=",
- 14);
+ MUL("*", 3), DIV("/", 3), MOD("%", 3), ADD("+", 4), SUB("-", 4), SHL("<<", 5), SHR(
+ ">>", 5), SHRU(">>>", 5), LT("<", 6), LTE("<=", 6), GT(">", 6), GTE(">=",
+ 6), EQ("==", 7), NEQ("!=", 7), BIT_AND("&", 8), BIT_XOR("^", 9), BIT_OR(
+ "|", 10), AND("&&", 11), OR("||", 12), ASG("=", 14), ASG_ADD("+=", 14,
+ ADD), ASG_SUB("-=", 14, SUB), ASG_MUL("*=", 14, MUL), ASG_DIV("/=", 14,
+ DIV), ASG_MOD("%=", 14, MOD), ASG_SHL("<<=", 14, SHL), ASG_SHR(">>=", 14,
+ SHR), ASG_SHRU(">>>=", 14, SHRU), ASG_BIT_AND("&=", 14, BIT_AND), ASG_BIT_OR(
+ "|=", 14, BIT_OR), ASG_BIT_XOR("^=", 14, BIT_XOR);
private final char[] symbol;
+ private final JBinaryOperator nonAsg;
private final int precedence;
private JBinaryOperator(String symbol, int precedence) {
+ this(symbol, precedence, null);
+ }
+
+ private JBinaryOperator(String symbol, int precedence, JBinaryOperator nonAsg) {
this.symbol = symbol.toCharArray();
this.precedence = precedence;
+ this.nonAsg = nonAsg;
+ }
+
+ public JBinaryOperator getNonAssignmentOf() {
+ return nonAsg;
}
public int getPrecedence() {
@@ -83,11 +60,12 @@
}
public boolean isAssignment() {
- /*
- * Beware, flaky! Maybe I should have added Yet Another Field to
- * BinaryOperator?
- */
- return (precedence == ASG.getPrecedence());
+ return (this == ASG) || (getNonAssignmentOf() != null);
+ }
+
+ public boolean isShiftOperator() {
+ // Fragile implementation.
+ return precedence == 5 || (nonAsg != null && nonAsg.precedence == 5);
}
public String toString() {
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JClassType.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JClassType.java
index 0272c16..ebad0df 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JClassType.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JClassType.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2007 Google Inc.
+ * Copyright 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
@@ -52,8 +52,8 @@
return isFinal;
}
- public void setFinal(boolean b) {
- isFinal = b;
+ public void setFinal() {
+ isFinal = true;
}
public void traverse(JVisitor visitor, Context ctx) {
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JLocalDeclarationStatement.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JDeclarationStatement.java
similarity index 68%
rename from dev/core/src/com/google/gwt/dev/jjs/ast/JLocalDeclarationStatement.java
rename to dev/core/src/com/google/gwt/dev/jjs/ast/JDeclarationStatement.java
index 7b5085c..c85bd77 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JLocalDeclarationStatement.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JDeclarationStatement.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2007 Google Inc.
+ * Copyright 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
@@ -20,29 +20,31 @@
/**
* Java initialized local variable statement.
*/
-public class JLocalDeclarationStatement extends JStatement {
+public class JDeclarationStatement extends JStatement {
public JExpression initializer;
- private JLocalRef localRef;
+ private JVariableRef variableRef;
- public JLocalDeclarationStatement(JProgram program, SourceInfo info,
- JLocalRef localRef, JExpression intializer) {
+ public JDeclarationStatement(JProgram program, SourceInfo info,
+ JVariableRef variableRef, JExpression intializer) {
super(program, info);
- this.localRef = localRef;
+ this.variableRef = variableRef;
this.initializer = intializer;
+ CanHaveInitializer variable = variableRef.getTarget();
+ variable.setInitializer(intializer);
}
public JExpression getInitializer() {
return initializer;
}
- public JLocalRef getLocalRef() {
- return localRef;
+ public JVariableRef getVariableRef() {
+ return variableRef;
}
public void traverse(JVisitor visitor, Context ctx) {
if (visitor.visit(this, ctx)) {
- localRef = (JLocalRef) visitor.accept(localRef);
+ variableRef = (JVariableRef) visitor.accept(variableRef);
if (initializer != null) {
initializer = visitor.accept(initializer);
}
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JEnumField.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JEnumField.java
index c8942d1..42e94bc 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JEnumField.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JEnumField.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2007 Google Inc.
+ * Copyright 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
@@ -26,7 +26,7 @@
public JEnumField(JProgram program, SourceInfo info, String name,
int ordinal, JEnumType enclosingType, JClassType type) {
- super(program, info, name, enclosingType, type, true, true, true);
+ super(program, info, name, enclosingType, type, true, true, false);
this.ordinal = ordinal;
}
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JField.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JField.java
index 534e772..5a319f4 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JField.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JField.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2007 Google Inc.
+ * Copyright 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
@@ -18,35 +18,51 @@
import com.google.gwt.dev.jjs.SourceInfo;
/**
- * Java field definition.
+ * Java field definition.
*/
-public class JField extends JVariable implements CanBeStatic, HasEnclosingType {
+public class JField extends JVariable implements CanBeStatic, HasEnclosingType,
+ CanHaveInitializer {
- private JReferenceType enclosingType;
- public JLiteral constInitializer;
+ private final JReferenceType enclosingType;
+ private final boolean isCompileTimeConstant;
private final boolean isStatic;
- private final boolean hasInitializer;
+ private boolean isVolatile;
JField(JProgram program, SourceInfo info, String name,
- JReferenceType enclosingType, JType type, boolean isStatic, boolean isFinal, boolean hasInitializer) {
+ JReferenceType enclosingType, JType type, boolean isStatic,
+ boolean isFinal, boolean isCompileTimeConstant) {
super(program, info, name, type, isFinal);
this.enclosingType = enclosingType;
this.isStatic = isStatic;
- this.hasInitializer = hasInitializer;
+ this.isCompileTimeConstant = isCompileTimeConstant;
+ assert (isFinal || !isCompileTimeConstant);
}
public JReferenceType getEnclosingType() {
return enclosingType;
}
- public boolean hasInitializer() {
- return hasInitializer;
+ public boolean isCompileTimeConstant() {
+ return isCompileTimeConstant;
+ }
+
+ @Override
+ public boolean isFinal() {
+ return !isVolatile && super.isFinal();
}
public boolean isStatic() {
return isStatic;
}
+ public void setInitializer(JExpression initializer) {
+ this.initializer = initializer;
+ }
+
+ public void setVolatile() {
+ isVolatile = true;
+ }
+
public void traverse(JVisitor visitor, Context ctx) {
if (visitor.visit(this, ctx)) {
}
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JFieldRef.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JFieldRef.java
index c78e8c7..5abe912 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JFieldRef.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JFieldRef.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2007 Google Inc.
+ * Copyright 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
@@ -61,7 +61,7 @@
public boolean hasSideEffects() {
// A cross-class reference to a static, non constant field forces clinit
if (field.isStatic()
- && (!field.isFinal() || field.constInitializer == null)) {
+ && (!field.isFinal() || !field.isCompileTimeConstant())) {
if (program.typeOracle.checkClinit(enclosingType,
field.getEnclosingType())) {
// Therefore, we have side effects
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JLocal.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JLocal.java
index 924bba5..66a6e2d 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JLocal.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JLocal.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2007 Google Inc.
+ * Copyright 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
@@ -20,7 +20,8 @@
/**
* Java local variable definition.
*/
-public class JLocal extends JVariable implements HasEnclosingMethod {
+public class JLocal extends JVariable implements HasEnclosingMethod,
+ CanHaveInitializer {
private final JMethodBody enclosingMethodBody;
@@ -34,6 +35,10 @@
return enclosingMethodBody.method;
}
+ public void setInitializer(JExpression initializer) {
+ this.initializer = initializer;
+ }
+
public void traverse(JVisitor visitor, Context ctx) {
if (visitor.visit(this, ctx)) {
}
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JMethod.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JMethod.java
index 75ba9e9..e2976b3 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JMethod.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JMethod.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2007 Google Inc.
+ * Copyright 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
@@ -25,8 +25,8 @@
* A Java method implementation.
*/
public final class JMethod extends JNode implements HasEnclosingType, HasName,
- HasType, HasSettableType, CanBeAbstract, CanBeFinal, CanBeSetFinal,
- CanBeNative, CanBeStatic {
+ HasSettableType, CanBeAbstract, CanBeSetFinal, CanBeNative,
+ CanBeStatic {
/**
* References to any methods which this method overrides. This should be an
@@ -35,10 +35,8 @@
*/
public final List<JMethod> overrides = new ArrayList<JMethod>();
- public final ArrayList<JParameter> params =
- new ArrayList<JParameter>();
- public final ArrayList<JClassType> thrownExceptions =
- new ArrayList<JClassType>();
+ public final ArrayList<JParameter> params = new ArrayList<JParameter>();
+ public final ArrayList<JClassType> thrownExceptions = new ArrayList<JClassType>();
private JAbstractMethodBody body = null;
private final JReferenceType enclosingType;
private final boolean isAbstract;
@@ -131,8 +129,8 @@
body.setMethod(this);
}
- public void setFinal(boolean b) {
- isFinal = b;
+ public void setFinal() {
+ isFinal = true;
}
public void setType(JType newType) {
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JModVisitor.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JModVisitor.java
index 0f6ae4e..0468afb 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JModVisitor.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JModVisitor.java
@@ -23,6 +23,7 @@
/**
* A visitor for iterating through and modifying an AST.
*/
+@SuppressWarnings("unchecked")
public class JModVisitor extends JVisitor {
private interface ContextFactory {
@@ -92,13 +93,6 @@
didChange = replaced = true;
}
- protected void doReplace(Class targetClass, JNode x) {
- checkState();
- checkReplacement((JNode) list.get(index), x);
- list.set(index, x);
- didChange = replaced = true;
- }
-
protected void traverse(List list) {
this.list = list;
for (index = 0; index < list.size(); ++index) {
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JParameter.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JParameter.java
index f8a644b..f49d3bc 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JParameter.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JParameter.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2007 Google Inc.
+ * Copyright 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
@@ -44,6 +44,11 @@
return isThis;
}
+ public void setInitializer(JExpression expression) {
+ throw new UnsupportedOperationException(
+ "A JParameter cannot have an initializer");
+ }
+
public void traverse(JVisitor visitor, Context ctx) {
if (visitor.visit(this, ctx)) {
}
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JPrimitiveType.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JPrimitiveType.java
index d6e9aef..9f05640 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JPrimitiveType.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JPrimitiveType.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2007 Google Inc.
+ * Copyright 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
@@ -50,6 +50,10 @@
return wrapperTypeName;
}
+ public boolean isFinal() {
+ return true;
+ }
+
public void traverse(JVisitor visitor, Context ctx) {
if (visitor.visit(this, ctx)) {
}
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JProgram.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JProgram.java
index 63d520b..9bc354a 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JProgram.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JProgram.java
@@ -33,6 +33,7 @@
import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.Iterator;
+import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -43,18 +44,18 @@
*/
public class JProgram extends JNode {
- private static final Set<String> CODEGEN_TYPES_SET = new HashSet<String>(
+ public static final Set<String> CODEGEN_TYPES_SET = new LinkedHashSet<String>(
Arrays.asList(new String[] {
"com.google.gwt.lang.Array", "com.google.gwt.lang.Cast",
- "com.google.gwt.lang.Exceptions", "com.google.gwt.lang.Stats"}));
+ "com.google.gwt.lang.Exceptions", "com.google.gwt.lang.LongLib",
+ "com.google.gwt.lang.Stats",}));
private static final Set<String> INDEX_TYPES_SET = new HashSet<String>(
Arrays.asList(new String[] {
"java.lang.Object", "java.lang.String", "java.lang.Class",
"java.lang.CharSequence", "java.lang.Comparable", "java.lang.Enum",
"java.lang.Iterable", "java.util.Iterator",
- "com.google.gwt.core.client.JavaScriptObject",
- "com.google.gwt.lang.Array"}));
+ "com.google.gwt.core.client.JavaScriptObject"}));
private static final int IS_ARRAY = 2;
@@ -305,22 +306,14 @@
public JField createField(SourceInfo info, char[] name,
JReferenceType enclosingType, JType type, boolean isStatic,
- boolean isFinal, boolean hasInitializer) {
+ boolean isFinal, boolean isCompileTimeConstant) {
assert (name != null);
assert (enclosingType != null);
assert (type != null);
- /*
- * MAGIC: filled in during code gen, don't bother synthesizing dummy
- * initializations.
- */
- if (enclosingType == typeJavaLangObject) {
- hasInitializer = true;
- }
-
String sname = String.valueOf(name);
JField x = new JField(this, info, sname, enclosingType, type, isStatic,
- isFinal, hasInitializer);
+ isFinal, isCompileTimeConstant);
if (indexedTypes.containsValue(enclosingType)) {
indexedFields.put(enclosingType.getShortName() + '.' + sname, x);
@@ -540,7 +533,7 @@
public JField getNullField() {
if (nullField == null) {
nullField = new JField(this, null, "nullField", null, typeNull, false,
- true, true);
+ true, false);
}
return nullField;
}
@@ -678,7 +671,12 @@
public boolean isClinit(JMethod method) {
JReferenceType enclosingType = method.getEnclosingType();
- return (enclosingType != null) && (method == enclosingType.methods.get(0));
+ if ((enclosingType != null) && (method == enclosingType.methods.get(0))) {
+ assert (method.getName().equals("$clinit"));
+ return true;
+ } else {
+ return false;
+ }
}
public boolean isJavaScriptObject(JType type) {
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JReferenceType.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JReferenceType.java
index b8e2ae0..76e244a 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JReferenceType.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JReferenceType.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2007 Google Inc.
+ * Copyright 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
@@ -23,8 +23,7 @@
/**
* Base class for any reference type.
*/
-public abstract class JReferenceType extends JType implements CanBeAbstract,
- CanBeFinal {
+public abstract class JReferenceType extends JType implements CanBeAbstract {
public List<JField> fields = new ArrayList<JField>();
public List<JMethod> methods = new ArrayList<JMethod>();
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JType.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JType.java
index e6232d7..2223750 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JType.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JType.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2007 Google Inc.
+ * Copyright 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
@@ -20,7 +20,7 @@
/**
* Base class for any types entity.
*/
-public abstract class JType extends JNode implements HasName {
+public abstract class JType extends JNode implements HasName, CanBeFinal {
protected final String name;
private final JLiteral defaultValue;
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JUnaryOperator.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JUnaryOperator.java
index d66851d..49b865a 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JUnaryOperator.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JUnaryOperator.java
@@ -18,13 +18,9 @@
/**
* An enumeration of the available unary operators.
*/
-public class JUnaryOperator {
+public enum JUnaryOperator {
- public static final JUnaryOperator INC = new JUnaryOperator("++");
- public static final JUnaryOperator DEC = new JUnaryOperator("--");
- public static final JUnaryOperator NEG = new JUnaryOperator("-");
- public static final JUnaryOperator NOT = new JUnaryOperator("!");
- public static final JUnaryOperator BIT_NOT = new JUnaryOperator("~");
+ INC("++"), DEC("--"), NEG("-"), NOT("!"), BIT_NOT("~");
private final char[] symbol;
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JVariable.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JVariable.java
index 9f784f9..32416b8 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JVariable.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JVariable.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2007 Google Inc.
+ * Copyright 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
@@ -20,9 +20,10 @@
/**
* Base class for any storage location.
*/
-public abstract class JVariable extends JNode implements CanBeFinal, HasName,
- HasType, HasSettableType {
+public abstract class JVariable extends JNode implements CanBeSetFinal,
+ CanHaveInitializer, HasName, HasSettableType {
+ protected JExpression initializer = null;
private boolean isFinal;
private final String name;
private JType type;
@@ -35,6 +36,13 @@
this.isFinal = isFinal;
}
+ public JLiteral getConstInitializer() {
+ if (isFinal() && initializer instanceof JLiteral) {
+ return (JLiteral) initializer;
+ }
+ return null;
+ }
+
public String getName() {
return name;
}
@@ -43,10 +51,18 @@
return type;
}
+ public boolean hasInitializer() {
+ return initializer != null;
+ }
+
public boolean isFinal() {
return isFinal;
}
+ public void setFinal() {
+ isFinal = true;
+ }
+
public void setType(JType newType) {
type = newType;
}
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JVisitor.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JVisitor.java
index 33d3d2d..7e61a47 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JVisitor.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JVisitor.java
@@ -25,12 +25,12 @@
import com.google.gwt.dev.jjs.ast.js.JsonObject;
import com.google.gwt.dev.jjs.ast.js.JsonObject.JsonPropInit;
-import java.util.Iterator;
import java.util.List;
/**
* A visitor for iterating through an AST.
*/
+@SuppressWarnings({"unused", "unchecked"})
public class JVisitor {
protected static final Context UNMODIFIABLE_CONTEXT = new Context() {
@@ -133,6 +133,9 @@
public void endVisit(JContinueStatement x, Context ctx) {
}
+ public void endVisit(JDeclarationStatement x, Context ctx) {
+ }
+
public void endVisit(JDoStatement x, Context ctx) {
}
@@ -175,9 +178,6 @@
public void endVisit(JLocal x, Context ctx) {
}
- public void endVisit(JLocalDeclarationStatement x, Context ctx) {
- }
-
public void endVisit(JLocalRef x, Context ctx) {
}
@@ -329,6 +329,10 @@
return true;
}
+ public boolean visit(JDeclarationStatement x, Context ctx) {
+ return true;
+ }
+
public boolean visit(JDoStatement x, Context ctx) {
return true;
}
@@ -385,10 +389,6 @@
return true;
}
- public boolean visit(JLocalDeclarationStatement x, Context ctx) {
- return true;
- }
-
public boolean visit(JLocalRef x, Context ctx) {
return true;
}
@@ -511,14 +511,14 @@
}
protected void doAccept(List list) {
- for (Iterator it = list.iterator(); it.hasNext();) {
- doTraverse((JNode) it.next(), UNMODIFIABLE_CONTEXT);
+ for (Object node : list) {
+ doTraverse((JNode) node, UNMODIFIABLE_CONTEXT);
}
}
protected void doAcceptWithInsertRemove(List list) {
- for (Iterator it = list.iterator(); it.hasNext();) {
- doTraverse((JNode) it.next(), UNMODIFIABLE_CONTEXT);
+ for (Object node : list) {
+ doTraverse((JNode) node, UNMODIFIABLE_CONTEXT);
}
}
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/BuildTypeMap.java b/dev/core/src/com/google/gwt/dev/jjs/impl/BuildTypeMap.java
index f6b8906..66a7df0 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/BuildTypeMap.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/BuildTypeMap.java
@@ -29,6 +29,7 @@
import com.google.gwt.dev.jjs.ast.JNewInstance;
import com.google.gwt.dev.jjs.ast.JParameter;
import com.google.gwt.dev.jjs.ast.JParameterRef;
+import com.google.gwt.dev.jjs.ast.JPrimitiveType;
import com.google.gwt.dev.jjs.ast.JProgram;
import com.google.gwt.dev.jjs.ast.JReferenceType;
import com.google.gwt.dev.jjs.ast.JReturnStatement;
@@ -60,6 +61,7 @@
import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration;
import org.eclipse.jdt.internal.compiler.ast.Statement;
import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
+import org.eclipse.jdt.internal.compiler.impl.Constant;
import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
import org.eclipse.jdt.internal.compiler.lookup.ClassScope;
import org.eclipse.jdt.internal.compiler.lookup.CompilationUnitScope;
@@ -273,7 +275,7 @@
&& ((AllocationExpression) initialization).enumConstant != null) {
createEnumField(info, b, enclosingType);
} else {
- createField(info, b, enclosingType, initialization != null);
+ createField(info, b, enclosingType);
}
return true;
} catch (Throwable e) {
@@ -342,10 +344,19 @@
}
private JField createField(SourceInfo info, FieldBinding binding,
- JReferenceType enclosingType, boolean hasInitializer) {
+ JReferenceType enclosingType) {
JType type = (JType) typeMap.get(binding.type);
+
+ boolean isCompileTimeConstant = binding.isStatic() && (binding.isFinal())
+ && (binding.constant() != Constant.NotAConstant)
+ && (binding.type.isBaseType());
+ assert (type instanceof JPrimitiveType || !isCompileTimeConstant);
+
JField field = program.createField(info, binding.name, enclosingType,
- type, binding.isStatic(), binding.isFinal(), hasInitializer);
+ type, binding.isStatic(), binding.isFinal(), isCompileTimeConstant);
+ if (binding.isVolatile()) {
+ field.setVolatile();
+ }
typeMap.put(binding, field);
return field;
}
@@ -354,7 +365,7 @@
JReferenceType enclosingType) {
JType type = (JType) typeMap.get(binding.type);
JField field = program.createField(null, binding.name, enclosingType,
- type, false, true, true);
+ type, false, true, false);
if (binding.matchingField != null) {
typeMap.put(binding.matchingField, field);
}
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/CastNormalizer.java b/dev/core/src/com/google/gwt/dev/jjs/impl/CastNormalizer.java
index c340f98..02eb46b 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/CastNormalizer.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/CastNormalizer.java
@@ -48,8 +48,8 @@
/**
* Replace cast and instanceof operations with calls to the Cast class. Depends
- * on {@link CatchBlockNormalizer}, {@link CompoundAssignmentNormalizer}, and
- * {@link JsoDevirtualizer} having already run.
+ * on {@link CatchBlockNormalizer}, {@link CompoundAssignmentNormalizer},
+ * {@link JsoDevirtualizer}, and {@link LongCastNormalizer} having already run.
*
* <p>
* Object and String always get a typeId of 1 and 2, respectively. 0 is reserved
@@ -316,13 +316,12 @@
}
/**
- * Explicitly convert any char-typed expressions within a concat operation
- * into strings.
+ * Explicitly convert any char or long type expressions within a concat
+ * operation into strings because normal JavaScript conversion does not work
+ * correctly.
*/
private class ConcatVisitor extends JModVisitor {
- private JMethod stringValueOfChar = null;
-
@Override
public void endVisit(JBinaryOperation x, Context ctx) {
if (x.getType() != program.getTypeJavaLangString()) {
@@ -330,8 +329,8 @@
}
if (x.getOp() == JBinaryOperator.ADD) {
- JExpression newLhs = convertCharString(x.getLhs());
- JExpression newRhs = convertCharString(x.getRhs());
+ JExpression newLhs = convertString(x.getLhs());
+ JExpression newRhs = convertString(x.getRhs());
if (newLhs != x.getLhs() || newRhs != x.getRhs()) {
JBinaryOperation newExpr = new JBinaryOperation(program,
x.getSourceInfo(), program.getTypeJavaLangString(),
@@ -339,7 +338,7 @@
ctx.replaceMe(newExpr);
}
} else if (x.getOp() == JBinaryOperator.ASG_ADD) {
- JExpression newRhs = convertCharString(x.getRhs());
+ JExpression newRhs = convertString(x.getRhs());
if (newRhs != x.getRhs()) {
JBinaryOperation newExpr = new JBinaryOperation(program,
x.getSourceInfo(), program.getTypeJavaLangString(),
@@ -349,16 +348,18 @@
}
}
- private JExpression convertCharString(JExpression expr) {
+ private JExpression convertString(JExpression expr) {
JPrimitiveType charType = program.getTypePrimitiveChar();
if (expr.getType() == charType) {
- // Replace the character with a call to Cast.charToString()
- if (stringValueOfChar == null) {
- stringValueOfChar = program.getIndexedMethod("Cast.charToString");
- assert (stringValueOfChar != null);
- }
+ // Replace with Cast.charToString(c)
JMethodCall call = new JMethodCall(program, expr.getSourceInfo(), null,
- stringValueOfChar);
+ program.getIndexedMethod("Cast.charToString"));
+ call.getArgs().add(expr);
+ return call;
+ } else if (expr.getType() == program.getTypePrimitiveLong()) {
+ // Replace with LongLib.toString(l)
+ JMethodCall call = new JMethodCall(program, expr.getSourceInfo(), null,
+ program.getIndexedMethod("LongLib.toString"));
call.getArgs().add(expr);
return call;
}
@@ -396,6 +397,7 @@
public void endVisit(JCastOperation x, Context ctx) {
JExpression replaceExpr;
JType toType = x.getCastType();
+ JExpression expr = x.getExpr();
if (toType instanceof JNullType) {
/*
* Magic: a null type cast means the user tried a cast that couldn't
@@ -410,12 +412,12 @@
*/
JMethodCall call = new JMethodCall(program, x.getSourceInfo(), null,
method, program.getTypeNull());
- call.getArgs().add(x.getExpr());
+ call.getArgs().add(expr);
replaceExpr = call;
} else if (toType instanceof JReferenceType) {
- JExpression curExpr = x.getExpr();
+ JExpression curExpr = expr;
JReferenceType refType = (JReferenceType) toType;
- JReferenceType argType = (JReferenceType) x.getExpr().getType();
+ JReferenceType argType = (JReferenceType) expr.getType();
if (program.typeOracle.canTriviallyCast(argType, refType)) {
// just remove the cast
replaceExpr = curExpr;
@@ -439,7 +441,6 @@
* call a narrowing conversion function. EXCEPTION: we currently have no
* way to narrow double to float, so don't bother.
*/
- boolean narrow = false, round = false;
JPrimitiveType tByte = program.getTypePrimitiveByte();
JPrimitiveType tChar = program.getTypePrimitiveChar();
JPrimitiveType tShort = program.getTypePrimitiveShort();
@@ -447,47 +448,70 @@
JPrimitiveType tLong = program.getTypePrimitiveLong();
JPrimitiveType tFloat = program.getTypePrimitiveFloat();
JPrimitiveType tDouble = program.getTypePrimitiveDouble();
- JType fromType = x.getExpr().getType();
- if (tByte == fromType) {
- if (tChar == toType) {
- narrow = true;
- }
- } else if (tShort == fromType) {
- if (tByte == toType || tChar == toType) {
- narrow = true;
- }
- } else if (tChar == fromType) {
- if (tByte == toType || tShort == toType) {
- narrow = true;
- }
- } else if (tInt == fromType) {
+ JType fromType = expr.getType();
+
+ String methodName = null;
+
+ if (tLong == fromType && tLong != toType) {
if (tByte == toType || tShort == toType || tChar == toType) {
- narrow = true;
- }
- } else if (tLong == fromType) {
- if (tByte == toType || tShort == toType || tChar == toType
- || tInt == toType) {
- narrow = true;
- }
- } else if (tFloat == fromType || tDouble == fromType) {
- if (tByte == toType || tShort == toType || tChar == toType
- || tInt == toType || tLong == toType) {
- round = true;
+ /*
+ * We need a double call here, one to convert long->int, and another
+ * one to narrow. Construct the inner call here and fall through to
+ * do the narrowing conversion.
+ */
+ JMethod castMethod = program.getIndexedMethod("LongLib.toInt");
+ JMethodCall call = new JMethodCall(program, x.getSourceInfo(),
+ null, castMethod);
+ call.getArgs().add(expr);
+ expr = call;
+ fromType = tInt;
+ } else if (tInt == toType) {
+ methodName = "LongLib.toInt";
+ } else if (tFloat == toType || tDouble == toType) {
+ methodName = "LongLib.toDouble";
}
}
- if (narrow || round) {
- // Replace the expression with a call to the narrow or round method
- String methodName = "Cast." + (narrow ? "narrow_" : "round_")
- + toType.getName();
+ if (toType == tLong && fromType != tLong) {
+ // Longs get special treatment.
+ if (tByte == fromType || tShort == fromType || tChar == fromType
+ || tInt == fromType) {
+ methodName = "LongLib.fromInt";
+ } else if (tFloat == fromType || tDouble == fromType) {
+ methodName = "LongLib.fromDouble";
+ }
+ } else if (tByte == fromType) {
+ if (tChar == toType) {
+ methodName = "Cast.narrow_" + toType.getName();
+ }
+ } else if (tShort == fromType) {
+ if (tByte == toType || tChar == toType) {
+ methodName = "Cast.narrow_" + toType.getName();
+ }
+ } else if (tChar == fromType) {
+ if (tByte == toType || tShort == toType) {
+ methodName = "Cast.narrow_" + toType.getName();
+ }
+ } else if (tInt == fromType) {
+ if (tByte == toType || tShort == toType || tChar == toType) {
+ methodName = "Cast.narrow_" + toType.getName();
+ }
+ } else if (tFloat == fromType || tDouble == fromType) {
+ if (tByte == toType || tShort == toType || tChar == toType
+ || tInt == toType) {
+ methodName = "Cast.round_" + toType.getName();
+ }
+ }
+
+ if (methodName != null) {
JMethod castMethod = program.getIndexedMethod(methodName);
JMethodCall call = new JMethodCall(program, x.getSourceInfo(), null,
- castMethod);
- call.getArgs().add(x.getExpr());
+ castMethod, toType);
+ call.getArgs().add(expr);
replaceExpr = call;
} else {
// Just remove the cast
- replaceExpr = x.getExpr();
+ replaceExpr = expr;
}
}
ctx.replaceMe(replaceExpr);
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/CompoundAssignmentNormalizer.java b/dev/core/src/com/google/gwt/dev/jjs/impl/CompoundAssignmentNormalizer.java
index f738203..1ef357d 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/CompoundAssignmentNormalizer.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/CompoundAssignmentNormalizer.java
@@ -15,6 +15,7 @@
*/
package com.google.gwt.dev.jjs.impl;
+import com.google.gwt.dev.jjs.InternalCompilerException;
import com.google.gwt.dev.jjs.ast.Context;
import com.google.gwt.dev.jjs.ast.JArrayRef;
import com.google.gwt.dev.jjs.ast.JBinaryOperation;
@@ -26,8 +27,12 @@
import com.google.gwt.dev.jjs.ast.JMethodBody;
import com.google.gwt.dev.jjs.ast.JModVisitor;
import com.google.gwt.dev.jjs.ast.JParameterRef;
+import com.google.gwt.dev.jjs.ast.JPostfixOperation;
+import com.google.gwt.dev.jjs.ast.JPrefixOperation;
import com.google.gwt.dev.jjs.ast.JProgram;
import com.google.gwt.dev.jjs.ast.JThisRef;
+import com.google.gwt.dev.jjs.ast.JType;
+import com.google.gwt.dev.jjs.ast.JUnaryOperator;
import com.google.gwt.dev.jjs.ast.js.JMultiExpression;
import java.util.ArrayList;
@@ -45,62 +50,146 @@
*/
private class BreakupAssignOpsVisitor extends JModVisitor {
- // @Override
+ @Override
public void endVisit(JBinaryOperation x, Context ctx) {
- /*
- * Convert to a normal divide operation so we can cast the result. Since
- * the left hand size must be computed twice, we have to replace any
- * left-hand side expressions that could have side effects with
- * temporaries, so that they are only run once.
- */
- if (x.getOp() == JBinaryOperator.ASG_DIV
+ JBinaryOperator op = x.getOp();
+ if (op.getNonAssignmentOf() == null) {
+ return;
+ }
+
+ boolean doIt = false;
+ if (x.getType() == program.getTypePrimitiveLong()) {
+ doIt = true;
+ }
+ if (op == JBinaryOperator.ASG_DIV
&& x.getType() != program.getTypePrimitiveFloat()
&& x.getType() != program.getTypePrimitiveDouble()) {
+ doIt = true;
+ }
- /*
- * Convert to a normal divide operation so we can cast the result. Since
- * the left hand size must be computed twice, we have to replace any
- * left-hand side expressions that could have side effects with
- * temporaries, so that they are only run once.
- */
- final int pushUsedLocals = localIndex;
- JMultiExpression multi = new JMultiExpression(program,
- x.getSourceInfo());
- ReplaceSideEffectsInLvalue replacer = new ReplaceSideEffectsInLvalue(
- multi);
- JExpression newLhs = replacer.accept(x.getLhs());
- localIndex = pushUsedLocals;
+ if (!doIt) {
+ return;
+ }
- JBinaryOperation operation = new JBinaryOperation(program,
- x.getSourceInfo(), newLhs.getType(), JBinaryOperator.DIV, newLhs,
- x.getRhs());
- JBinaryOperation asg = new JBinaryOperation(program, x.getSourceInfo(),
- newLhs.getType(), JBinaryOperator.ASG, newLhs, operation);
+ /*
+ * Convert to an assignment and binary operation. Since the left hand size
+ * must be computed twice, we have to replace any left-hand side
+ * expressions that could have side effects with temporaries, so that they
+ * are only run once.
+ */
+ final int pushLocalIndex = localIndex;
+ ReplaceSideEffectsInLvalue replacer = new ReplaceSideEffectsInLvalue(
+ new JMultiExpression(program, x.getSourceInfo()));
+ JExpression newLhs = replacer.accept(x.getLhs());
+ localIndex = pushLocalIndex;
- JMultiExpression multiExpr = replacer.getMultiExpr();
- if (multiExpr.exprs.isEmpty()) {
- // just use the split assignment expression
- ctx.replaceMe(asg);
- } else {
- // add the assignment as the last item in the multi
- multi.exprs.add(asg);
- ctx.replaceMe(multi);
- }
+ JBinaryOperation operation = new JBinaryOperation(program,
+ x.getSourceInfo(), newLhs.getType(), op.getNonAssignmentOf(), newLhs,
+ x.getRhs());
+ JBinaryOperation asg = new JBinaryOperation(program, x.getSourceInfo(),
+ newLhs.getType(), JBinaryOperator.ASG, newLhs, operation);
+
+ JMultiExpression multiExpr = replacer.getMultiExpr();
+ if (multiExpr.exprs.isEmpty()) {
+ // just use the split assignment expression
+ ctx.replaceMe(asg);
+ } else {
+ // add the assignment as the last item in the multi
+ multiExpr.exprs.add(asg);
+ ctx.replaceMe(multiExpr);
}
}
- // @Override
+ @Override
public void endVisit(JMethodBody x, Context ctx) {
clearLocals();
currentMethodBody = null;
}
- // @Override
+ @Override
+ public void endVisit(JPostfixOperation x, Context ctx) {
+ JUnaryOperator op = x.getOp();
+ if (!op.isModifying()) {
+ return;
+ }
+ if (x.getType() != program.getTypePrimitiveLong()) {
+ return;
+ }
+
+ // Convert into a comma operation, such as:
+ // (t = x, x += 1, t)
+
+ // First, replace the arg with a non-side-effect causing one.
+ final int pushLocalIndex = localIndex;
+ JMultiExpression multi = new JMultiExpression(program, x.getSourceInfo());
+ ReplaceSideEffectsInLvalue replacer = new ReplaceSideEffectsInLvalue(
+ multi);
+ JExpression newArg = replacer.accept(x.getArg());
+
+ // Now generate the appropriate expressions.
+ JLocal tempLocal = getTempLocal(newArg.getType());
+
+ // t = x
+ JLocalRef tempRef = new JLocalRef(program, x.getSourceInfo(), tempLocal);
+ JBinaryOperation asg = new JBinaryOperation(program, x.getSourceInfo(),
+ x.getType(), JBinaryOperator.ASG, tempRef, newArg);
+ multi.exprs.add(asg);
+
+ // x += 1
+ asg = createAsgOpFromUnary(newArg, op);
+ // Break the resulting asg op before adding to multi.
+ multi.exprs.add(accept(asg));
+
+ // t
+ tempRef = new JLocalRef(program, x.getSourceInfo(), tempLocal);
+ multi.exprs.add(tempRef);
+
+ ctx.replaceMe(multi);
+ localIndex = pushLocalIndex;
+ }
+
+ @Override
+ public void endVisit(JPrefixOperation x, Context ctx) {
+ JUnaryOperator op = x.getOp();
+ if (!op.isModifying()) {
+ return;
+ }
+ if (x.getType() != program.getTypePrimitiveLong()) {
+ return;
+ }
+
+ // Convert into the equivalent binary assignment operation, such as:
+ // x += 1
+ JBinaryOperation asg = createAsgOpFromUnary(x.getArg(), op);
+
+ // Visit the result to break it up even more.
+ ctx.replaceMe(accept(asg));
+ }
+
+ @Override
public boolean visit(JMethodBody x, Context ctx) {
currentMethodBody = x;
clearLocals();
return true;
}
+
+ private JBinaryOperation createAsgOpFromUnary(JExpression arg,
+ JUnaryOperator op) {
+ JBinaryOperator newOp;
+ if (op == JUnaryOperator.INC) {
+ newOp = JBinaryOperator.ASG_ADD;
+ } else if (op == JUnaryOperator.DEC) {
+ newOp = JBinaryOperator.ASG_SUB;
+ } else {
+ throw new InternalCompilerException(
+ "Unexpected modifying unary operator: "
+ + String.valueOf(op.getSymbol()));
+ }
+
+ JBinaryOperation asg = new JBinaryOperation(program, arg.getSourceInfo(),
+ arg.getType(), newOp, arg, program.getLiteralLong(1));
+ return asg;
+ }
}
/**
* Replaces side effects in lvalue.
@@ -117,7 +206,7 @@
return multi;
}
- // @Override
+ @Override
public boolean visit(JArrayRef x, Context ctx) {
JExpression newInstance = possiblyReplace(x.getInstance());
JExpression newIndexExpr = possiblyReplace(x.getIndexExpr());
@@ -129,7 +218,7 @@
return false;
}
- // @Override
+ @Override
public boolean visit(JFieldRef x, Context ctx) {
if (x.getInstance() != null) {
JExpression newInstance = possiblyReplace(x.getInstance());
@@ -142,17 +231,17 @@
return false;
}
- // @Override
+ @Override
public boolean visit(JLocalRef x, Context ctx) {
return false;
}
- // @Override
+ @Override
public boolean visit(JParameterRef x, Context ctx) {
return false;
}
- // @Override
+ @Override
public boolean visit(JThisRef x, Context ctx) {
return false;
}
@@ -163,7 +252,7 @@
}
// Create a temp local
- JLocal tempLocal = getTempLocal();
+ JLocal tempLocal = getTempLocal(x.getType());
// Create an assignment for this temp and add it to multi.
JLocalRef tempRef = new JLocalRef(program, x.getSourceInfo(), tempLocal);
@@ -198,13 +287,12 @@
breaker.accept(program);
}
- private JLocal getTempLocal() {
+ private JLocal getTempLocal(JType type) {
if (localIndex < tempLocals.size()) {
return tempLocals.get(localIndex++);
}
JLocal newTemp = program.createLocal(null,
- ("$t" + localIndex++).toCharArray(), program.getTypeVoid(), false,
- currentMethodBody);
+ ("$t" + localIndex++).toCharArray(), type, false, currentMethodBody);
tempLocals.add(newTemp);
return newTemp;
}
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/DeadCodeElimination.java b/dev/core/src/com/google/gwt/dev/jjs/impl/DeadCodeElimination.java
index dcd896a..c14e418 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/DeadCodeElimination.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/DeadCodeElimination.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2007 Google Inc.
+ * Copyright 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
@@ -23,23 +23,28 @@
import com.google.gwt.dev.jjs.ast.JBreakStatement;
import com.google.gwt.dev.jjs.ast.JCaseStatement;
import com.google.gwt.dev.jjs.ast.JCharLiteral;
+import com.google.gwt.dev.jjs.ast.JClassType;
import com.google.gwt.dev.jjs.ast.JConditional;
import com.google.gwt.dev.jjs.ast.JContinueStatement;
+import com.google.gwt.dev.jjs.ast.JDeclarationStatement;
import com.google.gwt.dev.jjs.ast.JDoStatement;
import com.google.gwt.dev.jjs.ast.JDoubleLiteral;
import com.google.gwt.dev.jjs.ast.JExpression;
import com.google.gwt.dev.jjs.ast.JExpressionStatement;
+import com.google.gwt.dev.jjs.ast.JField;
import com.google.gwt.dev.jjs.ast.JFieldRef;
import com.google.gwt.dev.jjs.ast.JForStatement;
import com.google.gwt.dev.jjs.ast.JIfStatement;
import com.google.gwt.dev.jjs.ast.JIntLiteral;
-import com.google.gwt.dev.jjs.ast.JLocalDeclarationStatement;
+import com.google.gwt.dev.jjs.ast.JLiteral;
import com.google.gwt.dev.jjs.ast.JLocalRef;
import com.google.gwt.dev.jjs.ast.JLongLiteral;
import com.google.gwt.dev.jjs.ast.JMethod;
import com.google.gwt.dev.jjs.ast.JMethodCall;
import com.google.gwt.dev.jjs.ast.JModVisitor;
import com.google.gwt.dev.jjs.ast.JNode;
+import com.google.gwt.dev.jjs.ast.JParameterRef;
+import com.google.gwt.dev.jjs.ast.JPostfixOperation;
import com.google.gwt.dev.jjs.ast.JPrefixOperation;
import com.google.gwt.dev.jjs.ast.JProgram;
import com.google.gwt.dev.jjs.ast.JReferenceType;
@@ -50,6 +55,7 @@
import com.google.gwt.dev.jjs.ast.JType;
import com.google.gwt.dev.jjs.ast.JUnaryOperator;
import com.google.gwt.dev.jjs.ast.JValueLiteral;
+import com.google.gwt.dev.jjs.ast.JVariableRef;
import com.google.gwt.dev.jjs.ast.JVisitor;
import com.google.gwt.dev.jjs.ast.JWhileStatement;
import com.google.gwt.dev.jjs.ast.js.JMultiExpression;
@@ -73,10 +79,17 @@
*/
public class DeadCodeVisitor extends JModVisitor {
+ private JClassType currentClass;
+
/**
- * An expression whose result does not matter.
+ * Expressions whose result does not matter.
*/
- private JExpression ignoringExpressionOutput;
+ private Set<JExpression> ignoringExpressionOutput = new HashSet<JExpression>();
+
+ /**
+ * Expressions being used as lvalues.
+ */
+ private Set<JExpression> lvalues = new HashSet<JExpression>();
private Set<JBlock> switchBlocks = new HashSet<JBlock>();
@@ -88,72 +101,37 @@
JBinaryOperator op = x.getOp();
JExpression lhs = x.getLhs();
JExpression rhs = x.getRhs();
- if (op == JBinaryOperator.AND) {
- // simplify short circuit AND expressions
- if (lhs instanceof JBooleanLiteral) {
- // eg: if (false && isWhatever()) -> if (false)
- // eg: if (true && isWhatever()) -> if (isWhatever())
- JBooleanLiteral booleanLiteral = (JBooleanLiteral) lhs;
- if (booleanLiteral.getValue()) {
- ctx.replaceMe(rhs);
- } else {
- ctx.replaceMe(lhs);
+ switch (op) {
+ case AND:
+ shortCircuitAnd(lhs, rhs, ctx);
+ break;
+ case OR:
+ shortCircuitOr(lhs, rhs, ctx);
+ break;
+ case EQ:
+ // simplify: null == null -> true
+ if (lhs.getType() == program.getTypeNull()
+ && rhs.getType() == program.getTypeNull() && !x.hasSideEffects()) {
+ ctx.replaceMe(program.getLiteralBoolean(true));
}
-
- } else if (rhs instanceof JBooleanLiteral) {
- // eg: if (isWhatever() && true) -> if (isWhatever())
- // eg: if (isWhatever() && false) -> if (false), unless side effects
- JBooleanLiteral booleanLiteral = (JBooleanLiteral) rhs;
- if (booleanLiteral.getValue()) {
- ctx.replaceMe(lhs);
- } else if (!lhs.hasSideEffects()) {
- ctx.replaceMe(rhs);
+ break;
+ case NEQ:
+ // simplify: null != null -> false
+ if (lhs.getType() == program.getTypeNull()
+ && rhs.getType() == program.getTypeNull() && !x.hasSideEffects()) {
+ ctx.replaceMe(program.getLiteralBoolean(false));
}
- }
-
- } else if (op == JBinaryOperator.OR) {
- // simplify short circuit OR expressions
- if (lhs instanceof JBooleanLiteral) {
- // eg: if (true || isWhatever()) -> if (true)
- // eg: if (false || isWhatever()) -> if (isWhatever())
- JBooleanLiteral booleanLiteral = (JBooleanLiteral) lhs;
- if (booleanLiteral.getValue()) {
- ctx.replaceMe(lhs);
- } else {
- ctx.replaceMe(rhs);
+ break;
+ case ADD:
+ if (x.getType() == program.getTypeJavaLangString()) {
+ evalConcat(ctx, lhs, rhs);
}
-
- } else if (rhs instanceof JBooleanLiteral) {
- // eg: if (isWhatever() || false) -> if (isWhatever())
- // eg: if (isWhatever() && true) -> if (true), unless side effects
- JBooleanLiteral booleanLiteral = (JBooleanLiteral) rhs;
- if (!booleanLiteral.getValue()) {
- ctx.replaceMe(lhs);
- } else if (!lhs.hasSideEffects()) {
- ctx.replaceMe(rhs);
+ break;
+ default:
+ if (op.isAssignment()) {
+ lvalues.remove(lhs);
}
- }
- } else if (op == JBinaryOperator.EQ) {
- // simplify: null == null -> true
- if (lhs.getType() == program.getTypeNull()
- && rhs.getType() == program.getTypeNull()) {
- ctx.replaceMe(program.getLiteralBoolean(true));
- }
- } else if (op == JBinaryOperator.NEQ) {
- // simplify: null != null -> false
- if (lhs.getType() == program.getTypeNull()
- && rhs.getType() == program.getTypeNull()) {
- ctx.replaceMe(program.getLiteralBoolean(false));
- }
- } else if (op == JBinaryOperator.ADD
- && x.getType() == program.getTypeJavaLangString()) {
- // try to statically evaluate concatentation
- if (lhs instanceof JValueLiteral && rhs instanceof JValueLiteral) {
- Object lhsObj = ((JValueLiteral) lhs).getValueObj();
- Object rhsObj = ((JValueLiteral) rhs).getValueObj();
- ctx.replaceMe(program.getLiteralString(String.valueOf(lhsObj)
- + String.valueOf(rhsObj)));
- }
+ break;
}
}
@@ -205,6 +183,11 @@
}
@Override
+ public void endVisit(JClassType x, Context ctx) {
+ currentClass = null;
+ }
+
+ @Override
public void endVisit(JConditional x, Context ctx) {
JExpression condExpr = x.getIfTest();
JExpression thenExpr = x.getThenExpr();
@@ -252,6 +235,11 @@
}
}
+ @Override
+ public void endVisit(JDeclarationStatement x, Context ctx) {
+ lvalues.remove(x.getVariableRef());
+ }
+
/**
* Convert do { } while (false); into a block.
*/
@@ -275,11 +263,44 @@
@Override
public void endVisit(JExpressionStatement x, Context ctx) {
+ ignoringExpressionOutput.remove(x.getExpr());
if (!x.getExpr().hasSideEffects()) {
removeMe(x, ctx);
}
}
+ @Override
+ public void endVisit(JFieldRef x, Context ctx) {
+ JLiteral literal = tryGetConstant(x);
+ if (literal == null && !ignoringExpressionOutput.contains(x)) {
+ return;
+ }
+ /*
+ * At this point, either we have a constant replacement, or our value is
+ * irrelevant. We can inline the constant, if any, but we might also need
+ * to evaluate an instance and run a clinit.
+ */
+ // We can inline the constant, but we might also need to evaluate an
+ // instance and run a clinit.
+ JMultiExpression multi = new JMultiExpression(program, x.getSourceInfo());
+
+ JExpression instance = x.getInstance();
+ if (instance != null) {
+ multi.exprs.add(instance);
+ }
+
+ JMethodCall clinit = maybeCreateClinitCall(x);
+ if (clinit != null) {
+ multi.exprs.add(clinit);
+ }
+
+ if (literal != null) {
+ multi.exprs.add(literal);
+ }
+
+ ctx.replaceMe(accept(multi));
+ }
+
/**
* Prune for (X; false; Y) statements, but make sure X is run.
*/
@@ -324,6 +345,15 @@
}
}
+ @Override
+ public void endVisit(JLocalRef x, Context ctx) {
+ JLiteral literal = tryGetConstant(x);
+ if (literal != null) {
+ assert (!x.hasSideEffects());
+ ctx.replaceMe(literal);
+ }
+ }
+
/**
* Resolve method calls that can be computed statically.
*/
@@ -346,6 +376,12 @@
*/
@Override
public void endVisit(JMultiExpression x, Context ctx) {
+ List<JExpression> exprs = x.exprs;
+ if (exprs.size() > 1) {
+ List<JExpression> nonFinalChildren = exprs.subList(0, exprs.size() - 1);
+ ignoringExpressionOutput.removeAll(nonFinalChildren);
+ }
+
/*
* If we're ignoring the output of this expression, we don't need to
* maintain the final multi value.
@@ -365,22 +401,6 @@
i--;
continue;
}
-
- if (expr instanceof JFieldRef) {
- JFieldRef fieldRef = (JFieldRef) expr;
- JExpression instance = fieldRef.getInstance();
- if (instance == null || !instance.hasSideEffects()) {
- // If the instance doesn't have side-effects, but the field ref
- // does, it's because a clinit() needs to happen.
- JMethod clinit = fieldRef.getField().getEnclosingType().methods.get(0);
- assert (clinit.getName().equals("$clinit"));
-
- // Replace the field ref with a direct call to the clinit.
- JMethodCall methodCall = new JMethodCall(program,
- expr.getSourceInfo(), instance, clinit);
- x.exprs.set(i, methodCall);
- }
- }
}
if (x.exprs.size() == 1) {
@@ -388,11 +408,38 @@
}
}
+ @Override
+ public void endVisit(JParameterRef x, Context ctx) {
+ JLiteral literal = tryGetConstant(x);
+ if (literal != null) {
+ assert (!x.hasSideEffects());
+ ctx.replaceMe(literal);
+ }
+ }
+
+ /**
+ * Replace post-inc/dec with pre-inc/dec if the result doesn't matter.
+ */
+ @Override
+ public void endVisit(JPostfixOperation x, Context ctx) {
+ if (x.getOp().isModifying()) {
+ lvalues.remove(x.getArg());
+ }
+ if (x == ignoringExpressionOutput) {
+ JPrefixOperation newOp = new JPrefixOperation(program,
+ x.getSourceInfo(), x.getOp(), x.getArg());
+ ctx.replaceMe(newOp);
+ }
+ }
+
/**
* Simplify the ! operator if possible.
*/
@Override
public void endVisit(JPrefixOperation x, Context ctx) {
+ if (x.getOp().isModifying()) {
+ lvalues.remove(x.getArg());
+ }
if (x.getOp() == JUnaryOperator.NOT) {
JExpression arg = x.getArg();
if (arg instanceof JBooleanLiteral) {
@@ -516,8 +563,54 @@
}
@Override
+ public boolean visit(JBinaryOperation x, Context ctx) {
+ if (x.getOp().isAssignment()) {
+ lvalues.add(x.getLhs());
+ }
+ return true;
+ }
+
+ @Override
+ public boolean visit(JClassType x, Context ctx) {
+ currentClass = x;
+ return true;
+ }
+
+ @Override
+ public boolean visit(JDeclarationStatement x, Context ctx) {
+ lvalues.add(x.getVariableRef());
+ return true;
+ }
+
+ @Override
public boolean visit(JExpressionStatement x, Context ctx) {
- ignoringExpressionOutput = x.getExpr();
+ ignoringExpressionOutput.add(x.getExpr());
+ return true;
+ }
+
+ @Override
+ public boolean visit(JMultiExpression x, Context ctx) {
+ List<JExpression> exprs = x.exprs;
+ if (exprs.size() > 1) {
+ List<JExpression> nonFinalChildren = exprs.subList(0, exprs.size() - 1);
+ ignoringExpressionOutput.addAll(nonFinalChildren);
+ }
+ return true;
+ }
+
+ @Override
+ public boolean visit(JPostfixOperation x, Context ctx) {
+ if (x.getOp().isModifying()) {
+ lvalues.add(x.getArg());
+ }
+ return true;
+ }
+
+ @Override
+ public boolean visit(JPrefixOperation x, Context ctx) {
+ if (x.getOp().isModifying()) {
+ lvalues.add(x.getArg());
+ }
return true;
}
@@ -533,13 +626,25 @@
*/
private boolean canPromoteBlock(JBlock block) {
for (JStatement nestedStmt : block.statements) {
- if (nestedStmt instanceof JLocalDeclarationStatement) {
- return false;
+ if (nestedStmt instanceof JDeclarationStatement) {
+ JDeclarationStatement decl = (JDeclarationStatement) nestedStmt;
+ if (decl.getVariableRef() instanceof JLocalRef) {
+ return false;
+ }
}
}
return true;
}
+ private void evalConcat(Context ctx, JExpression lhs, JExpression rhs) {
+ if (lhs instanceof JValueLiteral && rhs instanceof JValueLiteral) {
+ Object lhsObj = ((JValueLiteral) lhs).getValueObj();
+ Object rhsObj = ((JValueLiteral) rhs).getValueObj();
+ ctx.replaceMe(program.getLiteralString(String.valueOf(lhsObj)
+ + String.valueOf(rhsObj)));
+ }
+ }
+
private boolean hasNoDefaultCase(JSwitchStatement x) {
JBlock body = x.getBody();
boolean inDefault = false;
@@ -589,8 +694,24 @@
return typeClassMap.get(type);
}
+ private JMethodCall maybeCreateClinitCall(JFieldRef x) {
+ JMethodCall call;
+ JField field = x.getField();
+ if (field.isStatic()
+ && !field.isCompileTimeConstant()
+ && program.typeOracle.checkClinit(currentClass,
+ field.getEnclosingType())) {
+ JMethod clinit = field.getEnclosingType().methods.get(0);
+ assert (program.isClinit(clinit));
+ call = new JMethodCall(program, x.getSourceInfo(), null, clinit);
+ } else {
+ call = null;
+ }
+ return call;
+ }
+
private int numRemovableExpressions(JMultiExpression x) {
- if (x == ignoringExpressionOutput) {
+ if (ignoringExpressionOutput.contains(x)) {
// All expressions can be removed.
return x.exprs.size();
} else {
@@ -663,6 +784,73 @@
}
/**
+ * Simplify short circuit AND expressions.
+ *
+ * <pre>
+ * if (true || isWhatever()) -> if (true)
+ * if (false || isWhatever()) -> if (isWhatever())
+ *
+ * if (isWhatever() && true) -> if (isWhatever())
+ * if (isWhatever() && false) -> if (false), unless side effects
+ * </pre>
+ */
+ private void shortCircuitAnd(JExpression lhs, JExpression rhs, Context ctx) {
+ if (lhs instanceof JBooleanLiteral) {
+ JBooleanLiteral booleanLiteral = (JBooleanLiteral) lhs;
+ if (booleanLiteral.getValue()) {
+ ctx.replaceMe(rhs);
+ } else {
+ ctx.replaceMe(lhs);
+ }
+
+ } else if (rhs instanceof JBooleanLiteral) {
+ JBooleanLiteral booleanLiteral = (JBooleanLiteral) rhs;
+ if (booleanLiteral.getValue()) {
+ ctx.replaceMe(lhs);
+ } else if (!lhs.hasSideEffects()) {
+ ctx.replaceMe(rhs);
+ }
+ }
+ }
+
+ /**
+ * Simplify short circuit OR expressions.
+ *
+ * <pre>
+ * if (true || isWhatever()) -> if (true)
+ * if (false || isWhatever()) -> if (isWhatever())
+ *
+ * if (isWhatever() || false) -> if (isWhatever())
+ * if (isWhatever() && true) -> if (true), unless side effects
+ * </pre>
+ */
+ private void shortCircuitOr(JExpression lhs, JExpression rhs, Context ctx) {
+ if (lhs instanceof JBooleanLiteral) {
+ JBooleanLiteral booleanLiteral = (JBooleanLiteral) lhs;
+ if (booleanLiteral.getValue()) {
+ ctx.replaceMe(lhs);
+ } else {
+ ctx.replaceMe(rhs);
+ }
+
+ } else if (rhs instanceof JBooleanLiteral) {
+ JBooleanLiteral booleanLiteral = (JBooleanLiteral) rhs;
+ if (!booleanLiteral.getValue()) {
+ ctx.replaceMe(lhs);
+ } else if (!lhs.hasSideEffects()) {
+ ctx.replaceMe(rhs);
+ }
+ }
+ }
+
+ private JLiteral tryGetConstant(JVariableRef x) {
+ if (!lvalues.contains(x)) {
+ return x.getTarget().getConstInitializer();
+ }
+ return null;
+ }
+
+ /**
* Replace String methods having literal args with the static result.
*/
private void tryOptimizeStringCall(JMethodCall x, Context ctx,
@@ -671,12 +859,12 @@
if (method.getType() == program.getTypeVoid()) {
return;
}
-
+
if (method.getOriginalParamTypes().size() != method.params.size()) {
// One or more parameters were pruned, abort.
return;
}
-
+
if (method.getName().endsWith("hashCode")) {
// This cannot be computed at compile time because our implementation
// differs from the JRE.
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/Finalizer.java b/dev/core/src/com/google/gwt/dev/jjs/impl/Finalizer.java
new file mode 100644
index 0000000..322f3b5
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/Finalizer.java
@@ -0,0 +1,195 @@
+/*
+ * Copyright 2007 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.dev.jjs.impl;
+
+import com.google.gwt.dev.jjs.ast.CanBeSetFinal;
+import com.google.gwt.dev.jjs.ast.Context;
+import com.google.gwt.dev.jjs.ast.JBinaryOperation;
+import com.google.gwt.dev.jjs.ast.JClassType;
+import com.google.gwt.dev.jjs.ast.JDeclarationStatement;
+import com.google.gwt.dev.jjs.ast.JExpression;
+import com.google.gwt.dev.jjs.ast.JField;
+import com.google.gwt.dev.jjs.ast.JLocal;
+import com.google.gwt.dev.jjs.ast.JMethod;
+import com.google.gwt.dev.jjs.ast.JMethodBody;
+import com.google.gwt.dev.jjs.ast.JParameter;
+import com.google.gwt.dev.jjs.ast.JPostfixOperation;
+import com.google.gwt.dev.jjs.ast.JPrefixOperation;
+import com.google.gwt.dev.jjs.ast.JProgram;
+import com.google.gwt.dev.jjs.ast.JVariable;
+import com.google.gwt.dev.jjs.ast.JVariableRef;
+import com.google.gwt.dev.jjs.ast.JVisitor;
+import com.google.gwt.dev.jjs.ast.js.JsniFieldRef;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Finds all items are effectively final. That is, methods that are never
+ * overridden, classes that are never subclassed, and variables that are never
+ * reassigned. Mark all such methods and classes as final, since it helps us
+ * optimize.
+ */
+public class Finalizer {
+
+ /**
+ * Any items that weren't marked during MarkVisitor can be set final.
+ *
+ * Open question: What does it mean if an interface/abstract method becomes
+ * final? Is this possible after Pruning? I guess it means that someone tried
+ * to make a call to method that wasn't actually implemented anywhere in the
+ * program. But if it wasn't implemented, then the enclosing class should have
+ * come up as not instantiated and been culled. So I think it's not possible.
+ */
+ private class FinalizeVisitor extends JVisitor {
+
+ private boolean didChange = false;
+
+ @Override
+ public boolean didChange() {
+ return didChange;
+ }
+
+ @Override
+ public void endVisit(JClassType x, Context ctx) {
+ if (!x.isFinal() && !isSubclassed.contains(x)) {
+ setFinal(x);
+ }
+ }
+
+ @Override
+ public void endVisit(JField x, Context ctx) {
+ maybeFinalize(x);
+ }
+
+ @Override
+ public void endVisit(JLocal x, Context ctx) {
+ maybeFinalize(x);
+ }
+
+ @Override
+ public void endVisit(JMethod x, Context ctx) {
+ if (!x.isFinal() && !isOverriden.contains(x)) {
+ setFinal(x);
+ }
+ }
+
+ @Override
+ public void endVisit(JParameter x, Context ctx) {
+ maybeFinalize(x);
+ }
+
+ @Override
+ public boolean visit(JMethodBody x, Context ctx) {
+ accept(x.locals);
+ return false;
+ }
+
+ private void maybeFinalize(JVariable x) {
+ if (!x.isFinal() && !isReassigned.contains(x)) {
+ setFinal(x);
+ }
+ }
+
+ private void setFinal(CanBeSetFinal x) {
+ x.setFinal();
+ if (x.isFinal()) {
+ didChange = true;
+ }
+ }
+ }
+ /**
+ * Find all items that ARE overriden/subclassed/reassigned.
+ */
+ private class MarkVisitor extends JVisitor {
+
+ @Override
+ public void endVisit(JBinaryOperation x, Context ctx) {
+ if (x.getOp().isAssignment()) {
+ recordAssignment(x.getLhs());
+ }
+ }
+
+ @Override
+ public void endVisit(JClassType x, Context ctx) {
+ if (x.extnds != null) {
+ isSubclassed.add(x.extnds);
+ }
+ }
+
+ @Override
+ public void endVisit(JDeclarationStatement x, Context ctx) {
+ // This is not a reassignment, the target may still be final.
+ }
+
+ @Override
+ public void endVisit(JMethod x, Context ctx) {
+ for (int i = 0; i < x.overrides.size(); ++i) {
+ JMethod it = x.overrides.get(i);
+ isOverriden.add(it);
+ }
+ }
+
+ @Override
+ public void endVisit(JPostfixOperation x, Context ctx) {
+ if (x.getOp().isModifying()) {
+ recordAssignment(x.getArg());
+ }
+ }
+
+ @Override
+ public void endVisit(JPrefixOperation x, Context ctx) {
+ if (x.getOp().isModifying()) {
+ recordAssignment(x.getArg());
+ }
+ }
+
+ @Override
+ public void endVisit(JsniFieldRef x, Context ctx) {
+ recordAssignment(x);
+ }
+
+ private void recordAssignment(JExpression lhs) {
+ if (lhs instanceof JVariableRef) {
+ JVariableRef variableRef = (JVariableRef) lhs;
+ isReassigned.add(variableRef.getTarget());
+ }
+ }
+ }
+
+ public static boolean exec(JProgram program) {
+ return new Finalizer().execImpl(program);
+ }
+
+ private final Set<JMethod> isOverriden = new HashSet<JMethod>();
+
+ private final Set<JVariable> isReassigned = new HashSet<JVariable>();
+
+ private final Set<JClassType> isSubclassed = new HashSet<JClassType>();
+
+ private Finalizer() {
+ }
+
+ private boolean execImpl(JProgram program) {
+ MarkVisitor marker = new MarkVisitor();
+ marker.accept(program);
+
+ FinalizeVisitor finalizer = new FinalizeVisitor();
+ finalizer.accept(program);
+ return finalizer.didChange();
+ }
+
+}
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaAST.java b/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaAST.java
index 4687d70..fd392c4 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaAST.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaAST.java
@@ -52,7 +52,7 @@
import com.google.gwt.dev.jjs.ast.JLabeledStatement;
import com.google.gwt.dev.jjs.ast.JLiteral;
import com.google.gwt.dev.jjs.ast.JLocal;
-import com.google.gwt.dev.jjs.ast.JLocalDeclarationStatement;
+import com.google.gwt.dev.jjs.ast.JDeclarationStatement;
import com.google.gwt.dev.jjs.ast.JLocalRef;
import com.google.gwt.dev.jjs.ast.JLongLiteral;
import com.google.gwt.dev.jjs.ast.JMethod;
@@ -322,8 +322,8 @@
* We must replace any compile-time constants with the constant value of
* the field.
*/
- JLiteral initializer = field.constInitializer;
- if (field.isStatic() && field.isFinal() && initializer != null) {
+ if (field.isCompileTimeConstant()) {
+ JLiteral initializer = field.getConstInitializer();
JType type = initializer.getType();
if (type instanceof JPrimitiveType
|| type == program.getTypeJavaLangString()) {
@@ -1081,10 +1081,6 @@
return processBinaryOperation(info, op, type, x.left, x.right);
}
- JExpression processExpression(CombinedBinaryExpression x) {
- return processExpression((BinaryExpression) x);
- }
-
JExpression processExpression(CastExpression x) {
SourceInfo info = makeSourceInfo(x);
JType type = (JType) typeMap.get(x.resolvedType);
@@ -1098,6 +1094,10 @@
return program.getLiteralClass(type);
}
+ JExpression processExpression(CombinedBinaryExpression x) {
+ return processExpression((BinaryExpression) x);
+ }
+
JExpression processExpression(CompoundAssignment x) {
JBinaryOperator op;
@@ -1542,15 +1542,13 @@
assert (initializer instanceof JMethodCall);
}
- if (initializer instanceof JLiteral) {
- field.constInitializer = (JLiteral) initializer;
- } else if (initializer != null) {
+ if (initializer != null) {
SourceInfo info = makeSourceInfo(declaration);
- JStatement assignStmt = program.createAssignmentStmt(info,
+ JStatement decl = new JDeclarationStatement(program, info,
createVariableRef(info, field), initializer);
// will either be init or clinit
- currentMethodBody.getStatements().add(assignStmt);
+ currentMethodBody.getStatements().add(decl);
}
} catch (Throwable e) {
throw translateException(field, e);
@@ -1693,7 +1691,7 @@
JLocal elementVar = (JLocal) typeMap.get(x.elementVariable.binding);
String elementVarName = elementVar.getName();
- JLocalDeclarationStatement elementDecl = (JLocalDeclarationStatement) processStatement(x.elementVariable);
+ JDeclarationStatement elementDecl = (JDeclarationStatement) processStatement(x.elementVariable);
assert (elementDecl.initializer == null);
JForStatement result;
@@ -1716,14 +1714,14 @@
List<JStatement> initializers = new ArrayList<JStatement>(3);
// T[] i$array = arr
- initializers.add(createLocalDeclaration(info, arrayVar,
+ initializers.add(createDeclaration(info, arrayVar,
dispProcessExpression(x.collection)));
// int i$index = 0
- initializers.add(createLocalDeclaration(info, indexVar,
+ initializers.add(createDeclaration(info, indexVar,
program.getLiteralInt(0)));
// int i$max = i$array.length
- initializers.add(createLocalDeclaration(info, maxVar, new JFieldRef(
- program, info, createVariableRef(info, arrayVar),
+ initializers.add(createDeclaration(info, maxVar, new JFieldRef(program,
+ info, createVariableRef(info, arrayVar),
program.getIndexedField("Array.length"), currentClass)));
// i$index < i$max
@@ -1759,9 +1757,9 @@
List<JStatement> initializers = new ArrayList<JStatement>(1);
// Iterator<T> i$iterator = collection.iterator()
- initializers.add(createLocalDeclaration(info, iteratorVar,
- new JMethodCall(program, info, dispProcessExpression(x.collection),
- program.getIndexedMethod("Iterable.iterator"))));
+ initializers.add(createDeclaration(info, iteratorVar, new JMethodCall(
+ program, info, dispProcessExpression(x.collection),
+ program.getIndexedMethod("Iterable.iterator"))));
// i$iterator.hasNext()
JExpression condition = new JMethodCall(program, info,
@@ -1837,8 +1835,7 @@
JLocal local = (JLocal) typeMap.get(x.binding);
JLocalRef localRef = new JLocalRef(program, info, local);
JExpression initializer = dispProcessExpression(x.initialization);
- return new JLocalDeclarationStatement(program, info, localRef,
- initializer);
+ return new JDeclarationStatement(program, info, localRef, initializer);
}
JStatement processStatement(ReturnStatement x) {
@@ -2154,6 +2151,12 @@
return box(toBox, wrapperType);
}
+ private JDeclarationStatement createDeclaration(SourceInfo info,
+ JLocal local, JExpression value) {
+ return new JDeclarationStatement(program, info, new JLocalRef(program,
+ info, local), value);
+ }
+
private JField createEnumValueMap(JEnumType type) {
JsonObject map = new JsonObject(program);
for (JEnumField field : type.enumList) {
@@ -2163,7 +2166,7 @@
map.propInits.add(new JsonObject.JsonPropInit(program, key, value));
}
JField mapField = program.createField(null, "enum$map".toCharArray(),
- type, map.getType(), true, true, true);
+ type, map.getType(), true, true, false);
// Initialize in clinit.
JMethodBody clinitBody = (JMethodBody) type.methods.get(0).getBody();
@@ -2173,12 +2176,6 @@
return mapField;
}
- private JLocalDeclarationStatement createLocalDeclaration(SourceInfo info,
- JLocal arrayVar, JExpression value) {
- return new JLocalDeclarationStatement(program, info, new JLocalRef(
- program, info, arrayVar), value);
- }
-
/**
* Helper to create a qualified "this" ref (really a synthetic this field
* access) of the appropriate type. Always use this method instead of
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptAST.java b/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptAST.java
index e7baca2..05cdad3 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptAST.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptAST.java
@@ -46,8 +46,9 @@
import com.google.gwt.dev.jjs.ast.JLabel;
import com.google.gwt.dev.jjs.ast.JLabeledStatement;
import com.google.gwt.dev.jjs.ast.JLocal;
-import com.google.gwt.dev.jjs.ast.JLocalDeclarationStatement;
+import com.google.gwt.dev.jjs.ast.JDeclarationStatement;
import com.google.gwt.dev.jjs.ast.JLocalRef;
+import com.google.gwt.dev.jjs.ast.JLongLiteral;
import com.google.gwt.dev.jjs.ast.JMethod;
import com.google.gwt.dev.jjs.ast.JMethodBody;
import com.google.gwt.dev.jjs.ast.JMethodCall;
@@ -68,6 +69,7 @@
import com.google.gwt.dev.jjs.ast.JType;
import com.google.gwt.dev.jjs.ast.JTypeOracle;
import com.google.gwt.dev.jjs.ast.JUnaryOperator;
+import com.google.gwt.dev.jjs.ast.JVariable;
import com.google.gwt.dev.jjs.ast.JVisitor;
import com.google.gwt.dev.jjs.ast.JWhileStatement;
import com.google.gwt.dev.jjs.ast.js.JClassSeed;
@@ -135,6 +137,7 @@
import java.util.Set;
import java.util.Stack;
import java.util.TreeMap;
+import java.util.Map.Entry;
/**
* Creates a JavaScript AST from a <code>JProgram</code> node.
@@ -361,14 +364,14 @@
private final Set<JClassType> alreadyRan = new HashSet<JClassType>();
+ private Map<JClassType, JsFunction> clinitMap = new HashMap<JClassType, JsFunction>();
+
private JMethod currentMethod = null;
private final JsName globalTemp = topScope.declareName("_");
private final JsName prototype = objectScope.declareName("prototype");
- private Map<JClassType, JsFunction> clinitMap = new HashMap<JClassType, JsFunction>();
-
{
globalTemp.setObfuscatable(false);
prototype.setObfuscatable(false);
@@ -477,6 +480,7 @@
push(names.get(x.getRefType()).makeRef());
}
+ @SuppressWarnings("unchecked")
@Override
public void endVisit(JClassType x, Context ctx) {
if (alreadyRan.contains(x)) {
@@ -547,6 +551,34 @@
}
@Override
+ public void endVisit(JDeclarationStatement x, Context ctx) {
+ if (x.getInitializer() == null) {
+ pop(); // variableRef
+ /*
+ * Declaration statements can only appear in blocks, so it's okay to
+ * push null instead of an empty statement
+ */
+ push(null);
+ return;
+ }
+
+ JsExpression initializer = (JsExpression) pop(); // initializer
+ JsNameRef localRef = (JsNameRef) pop(); // localRef
+
+ JVariable target = x.getVariableRef().getTarget();
+ if (target instanceof JField && target.getConstInitializer() != null) {
+ // Will initialize at top scope; no need to double-initialize.
+ push(null);
+ return;
+ }
+
+ JsBinaryOperation binOp = new JsBinaryOperation(JsBinaryOperator.ASG,
+ localRef, initializer);
+
+ push(binOp.makeStmt());
+ }
+
+ @Override
public void endVisit(JDoStatement x, Context ctx) {
JsDoWhile stmt = new JsDoWhile();
if (x.getBody() != null) {
@@ -567,13 +599,14 @@
@Override
public void endVisit(JField x, Context ctx) {
// if we need an initial value, create an assignment
- if (x.constInitializer != null) {
+ if (x.getConstInitializer() != null) {
// setup the constant value
- accept(x.constInitializer);
+ accept(x.getConstInitializer());
} else if (x == program.getIndexedField("Cast.typeIdArray")) {
// magic: setup the type id table
push(generateTypeTable());
- } else if (!x.hasInitializer()) {
+ } else if (!x.hasInitializer()
+ && x.getEnclosingType() != program.getTypeJavaLangObject()) {
// setup a default value
accept(x.getType().getDefaultValue());
} else {
@@ -739,30 +772,27 @@
}
@Override
- public void endVisit(JLocalDeclarationStatement x, Context ctx) {
-
- if (x.getInitializer() == null) {
- pop(); // localRef
- /*
- * local decls can only appear in blocks, so it's okay to push null
- * instead of an empty statement
- */
- push(null);
- return;
- }
-
- JsExpression initializer = (JsExpression) pop(); // initializer
- JsNameRef localRef = (JsNameRef) pop(); // localRef
-
- JsBinaryOperation binOp = new JsBinaryOperation(JsBinaryOperator.ASG,
- localRef, initializer);
-
- push(binOp.makeStmt());
+ public void endVisit(JLocalRef x, Context ctx) {
+ push(names.get(x.getTarget()).makeRef());
}
@Override
- public void endVisit(JLocalRef x, Context ctx) {
- push(names.get(x.getTarget()).makeRef());
+ public void endVisit(JLongLiteral x, Context ctx) {
+ super.endVisit(x, ctx);
+ JsExpression longLiteralAllocation = pop();
+
+ // My seed function name
+ String nameString = Long.toString(x.getValue(), 16);
+ if (nameString.charAt(0) == '-') {
+ nameString = "N" + nameString.substring(1);
+ } else {
+ nameString = "P" + nameString;
+ }
+ nameString += "_longLit";
+ JsName longLit = topScope.declareName(nameString);
+ longLits.put(x.getValue(), longLit);
+ longObjects.put(longLit, longLiteralAllocation);
+ push(longLit.makeRef());
}
@Override
@@ -946,6 +976,12 @@
JsVars vars = new JsVars();
vars.add(new JsVar(globalTemp));
globalStmts.add(0, vars);
+
+ /*
+ * Long lits must got at the top, they can serve as constant field
+ * initializers.
+ */
+ generateLongLiterals(vars);
// Generate class objects.
vars = new JsVars();
@@ -1141,7 +1177,7 @@
assert (curStatements != null);
JsStatement newStmt = (JsStatement) pop(); // stmt
if (newStmt != null) {
- // Empty JLocalDeclarationStatement produces a null
+ // Empty JDeclarationStatement produces a null
curStatements.add(newStmt);
}
}
@@ -1168,8 +1204,7 @@
private void generateClassLiterals(JsVars vars) {
Set<JType> alreadyGenerated = new HashSet<JType>();
- for (Object element : classLits.keySet()) {
- JType type = (JType) element;
+ for (JType type : classLits.keySet()) {
generateClassLiteralsRecursive(alreadyGenerated, type, vars);
}
}
@@ -1212,7 +1247,7 @@
// special: setup a "toString" alias for java.lang.Object.toString()
generateToStringAlias(x, globalStmts);
// special: setup the identifying typeMarker field
- generateTypeMarker(x, globalStmts);
+ generateTypeMarker(globalStmts);
}
generateTypeId(x, globalStmts);
@@ -1285,6 +1320,16 @@
errCall.getArguments().add(modName.makeRef());
}
+ private void generateLongLiterals(JsVars vars) {
+ for (Entry<Long, JsName> entry : longLits.entrySet()) {
+ JsName jsName = entry.getValue();
+ JsExpression longObjectAlloc = longObjects.get(jsName);
+ JsVar var = new JsVar(jsName);
+ var.setInitExpr(longObjectAlloc);
+ vars.add(var);
+ }
+ }
+
private void generateNullFunc(List<JsStatement> globalStatements) {
// handle null method
JsFunction nullFunc = new JsFunction(topScope, nullMethodName);
@@ -1378,7 +1423,7 @@
}
}
- private void generateTypeMarker(JClassType x, List<JsStatement> globalStmts) {
+ private void generateTypeMarker(List<JsStatement> globalStmts) {
JField typeMarkerField = program.getIndexedField("Object.typeMarker");
JsName typeMarkerName = names.get(typeMarkerField);
if (typeMarkerName == null) {
@@ -1605,7 +1650,6 @@
* clinit).
*/
private Set<JMethod> crossClassTargets = new HashSet<JMethod>();
-
/**
* Contains JsNames for all interface methods. A special scope is needed so
* that independent classes will obfuscate their interface implementation
@@ -1614,6 +1658,13 @@
private final JsScope interfaceScope;
private final JsProgram jsProgram;
+
+ /**
+ * Sorted to avoid nondeterministic iteration.
+ */
+ private final Map<Long, JsName> longLits = new TreeMap<Long, JsName>();
+
+ private final Map<JsName, JsExpression> longObjects = new IdentityHashMap<JsName, JsExpression>();
private final Map<JAbstractMethodBody, JsFunction> methodBodyMap = new IdentityHashMap<JAbstractMethodBody, JsFunction>();
private final Map<HasName, JsName> names = new IdentityHashMap<HasName, JsName>();
private JsName nullMethodName;
@@ -1623,7 +1674,9 @@
* and toString. All other class scopes have this scope as an ultimate parent.
*/
private final JsScope objectScope;
+ private final JsOutputOption output;
private final Map<JMethod, JsName> polymorphicNames = new IdentityHashMap<JMethod, JsName>();
+
private final JProgram program;
/**
@@ -1646,9 +1699,7 @@
* Contains JsNames for all globals, such as static fields and methods.
*/
private final JsScope topScope;
-
private final JTypeOracle typeOracle;
- private final JsOutputOption output;
private GenerateJavaScriptAST(JProgram program, JsProgram jsProgram,
JsOutputOption output) {
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptLiterals.java b/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptLiterals.java
index a8cda95..07137c0 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptLiterals.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptLiterals.java
@@ -25,8 +25,10 @@
import com.google.gwt.dev.jjs.ast.JNullLiteral;
import com.google.gwt.dev.jjs.ast.JStringLiteral;
import com.google.gwt.dev.jjs.ast.JVisitor;
+import com.google.gwt.dev.js.ast.JsArrayLiteral;
import com.google.gwt.dev.js.ast.JsProgram;
import com.google.gwt.dev.js.ast.JsVisitable;
+import com.google.gwt.lang.LongLib;
import java.math.BigInteger;
import java.util.ArrayList;
@@ -39,6 +41,10 @@
*/
public class GenerateJavaScriptLiterals extends JVisitor {
+ static {
+ LongLib.RUN_IN_JVM = true;
+ }
+
private final JsProgram program;
private final Stack<JsVisitable<?>> nodeStack = new Stack<JsVisitable<?>>();
@@ -72,8 +78,14 @@
}
@Override
- public final void endVisit(JLongLiteral x, Context ctx) {
- push(program.getIntegralLiteral(BigInteger.valueOf(x.getValue())));
+ public void endVisit(JLongLiteral x, Context ctx) {
+ JsArrayLiteral arrayLit = new JsArrayLiteral();
+ double[] doubleArray = LongLib.typeChange(x.getValue());
+ arrayLit.getExpressions().add(
+ program.getDecimalLiteral(String.valueOf(doubleArray[0])));
+ arrayLit.getExpressions().add(
+ program.getDecimalLiteral(String.valueOf(doubleArray[1])));
+ push(arrayLit);
}
@Override
@@ -86,14 +98,17 @@
push(program.getStringLiteral(x.getValue()));
}
+ @SuppressWarnings("unchecked")
public final <T extends JsVisitable> T peek() {
return (T) nodeStack.peek();
}
+ @SuppressWarnings("unchecked")
protected final <T extends JsVisitable> T pop() {
return (T) nodeStack.pop();
}
+ @SuppressWarnings("unchecked")
protected final <T extends JsVisitable> List<T> popList(int count) {
List<T> list = new ArrayList<T>();
while (count > 0) {
@@ -107,6 +122,7 @@
return list;
}
+ @SuppressWarnings("unchecked")
protected final <T extends JsVisitable> void popList(List<T> collection,
int count) {
List<T> list = new ArrayList<T>();
@@ -121,6 +137,7 @@
collection.addAll(list);
}
+ @SuppressWarnings("unchecked")
protected final <T extends JsVisitable> void push(T node) {
nodeStack.push(node);
}
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/LongCastNormalizer.java b/dev/core/src/com/google/gwt/dev/jjs/impl/LongCastNormalizer.java
new file mode 100644
index 0000000..b82b4bb
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/LongCastNormalizer.java
@@ -0,0 +1,217 @@
+/*
+ * Copyright 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.dev.jjs.impl;
+
+import com.google.gwt.dev.jjs.ast.Context;
+import com.google.gwt.dev.jjs.ast.JBinaryOperation;
+import com.google.gwt.dev.jjs.ast.JCastOperation;
+import com.google.gwt.dev.jjs.ast.JConditional;
+import com.google.gwt.dev.jjs.ast.JExpression;
+import com.google.gwt.dev.jjs.ast.JDeclarationStatement;
+import com.google.gwt.dev.jjs.ast.JMethod;
+import com.google.gwt.dev.jjs.ast.JMethodCall;
+import com.google.gwt.dev.jjs.ast.JModVisitor;
+import com.google.gwt.dev.jjs.ast.JNewArray;
+import com.google.gwt.dev.jjs.ast.JParameter;
+import com.google.gwt.dev.jjs.ast.JPrimitiveType;
+import com.google.gwt.dev.jjs.ast.JProgram;
+import com.google.gwt.dev.jjs.ast.JReturnStatement;
+import com.google.gwt.dev.jjs.ast.JType;
+
+import java.util.List;
+
+/**
+ * Synthesize explicit casts to and from the primitive long type where such a
+ * cast would have been implicit. The explicit casts serve as markers for
+ * {@link CastNormalizer}.
+ */
+public class LongCastNormalizer {
+
+ /**
+ * Synthesize casts to longs and from long to trigger conversions.
+ */
+ private class ImplicitCastVisitor extends JModVisitor {
+
+ private JMethod currentMethod;
+ private final JPrimitiveType longType;
+
+ public ImplicitCastVisitor(JPrimitiveType longType) {
+ this.longType = longType;
+ }
+
+ @Override
+ public void endVisit(JBinaryOperation x, Context ctx) {
+ JType lhsType = x.getLhs().getType();
+ JType rhsType = x.getRhs().getType();
+ JType resultType = x.getType();
+
+ if (resultType == program.getTypeJavaLangString()) {
+ // Don't mess with concat.
+ return;
+ }
+
+ // Special case: shift operators always coerce a long RHS to int.
+ if (x.getOp().isShiftOperator()) {
+ if (rhsType == longType) {
+ rhsType = program.getTypePrimitiveInt();
+ }
+ } else if (lhsType == longType || rhsType == longType) {
+ // We must coerce lhs and rhs to the same type, either long or a float.
+
+ // Assume a long type.
+ JType coerceTo = longType;
+
+ // But double / float takes precedence over long.
+ JPrimitiveType floatType = program.getTypePrimitiveFloat();
+ JPrimitiveType doubleType = program.getTypePrimitiveDouble();
+ // See if the lhs can coerce the rhs
+ if ((lhsType == floatType || lhsType == doubleType)) {
+ coerceTo = lhsType;
+ }
+ if (x.getOp().isAssignment()) {
+ // In an assignment, the lhs must coerce the rhs
+ coerceTo = lhsType;
+ } else if ((rhsType == floatType || rhsType == doubleType)) {
+ coerceTo = rhsType;
+ }
+ lhsType = rhsType = coerceTo;
+ }
+
+ JExpression newLhs = checkAndReplace(x.getLhs(), lhsType);
+ JExpression newRhs = checkAndReplace(x.getRhs(), rhsType);
+ if (newLhs != x.getLhs() || newRhs != x.getRhs()) {
+ JBinaryOperation binOp = new JBinaryOperation(program,
+ x.getSourceInfo(), resultType, x.getOp(), newLhs, newRhs);
+ ctx.replaceMe(binOp);
+ }
+ }
+
+ @Override
+ public void endVisit(JConditional x, Context ctx) {
+ JExpression newThen = checkAndReplace(x.getThenExpr(), x.getType());
+ JExpression newElse = checkAndReplace(x.getElseExpr(), x.getType());
+ if (newThen != x.getThenExpr() || newElse != x.getElseExpr()) {
+ JConditional newCond = new JConditional(program, x.getSourceInfo(),
+ x.getType(), x.getIfTest(), newThen, newElse);
+ ctx.replaceMe(newCond);
+ }
+ }
+
+ @Override
+ public void endVisit(JDeclarationStatement x, Context ctx) {
+ JExpression init = x.getInitializer();
+ if (init != null) {
+ init = checkAndReplace(init, x.getVariableRef().getType());
+ if (init != x.getInitializer()) {
+ JDeclarationStatement newStmt = new JDeclarationStatement(program,
+ x.getSourceInfo(), x.getVariableRef(), init);
+ ctx.replaceMe(newStmt);
+ }
+ }
+ }
+
+ @Override
+ public void endVisit(JMethod x, Context ctx) {
+ currentMethod = null;
+ }
+
+ @Override
+ public void endVisit(JMethodCall x, Context ctx) {
+ List<JParameter> params = x.getTarget().params;
+ List<JExpression> args = x.getArgs();
+ for (int i = 0; i < params.size(); ++i) {
+ JParameter param = params.get(i);
+ JExpression arg = args.get(i);
+ JExpression newArg = checkAndReplace(arg, param.getType());
+ if (arg != newArg) {
+ args.set(i, newArg);
+ this.didChange = true;
+ }
+ }
+ }
+
+ @Override
+ public void endVisit(JNewArray x, Context ctx) {
+ JType elementType = x.getArrayType().getElementType();
+ List<JExpression> initializers = x.initializers;
+ if (initializers != null) {
+ for (int i = 0; i < initializers.size(); ++i) {
+ JExpression initializer = initializers.get(i);
+ JExpression newInitializer = checkAndReplace(initializer, elementType);
+ if (initializer != newInitializer) {
+ initializers.set(i, newInitializer);
+ this.didChange = true;
+ }
+ }
+ }
+ }
+
+ @Override
+ public void endVisit(JReturnStatement x, Context ctx) {
+ JExpression expr = x.getExpr();
+ if (expr != null) {
+ JExpression newExpr = checkAndReplace(expr, currentMethod.getType());
+ if (expr != newExpr) {
+ JReturnStatement newStmt = new JReturnStatement(program,
+ x.getSourceInfo(), newExpr);
+ ctx.replaceMe(newStmt);
+ }
+ }
+ }
+
+ @Override
+ public boolean visit(JMethod x, Context ctx) {
+ currentMethod = x;
+ return true;
+ }
+
+ /**
+ * Returns an explicit cast if the target type is long and the input
+ * expression is not a long, or if the target type is floating point and the
+ * expression is a long.
+ */
+ private JExpression checkAndReplace(JExpression arg, JType targetType) {
+ JType argType = arg.getType();
+ if (targetType == argType) {
+ return arg;
+ }
+ if (targetType != longType && argType != longType) {
+ return arg;
+ }
+ // Synthesize a cast to long to force explicit conversion.
+ JCastOperation cast = new JCastOperation(program, arg.getSourceInfo(),
+ targetType, arg);
+ return cast;
+ }
+ }
+
+ public static void exec(JProgram program) {
+ new LongCastNormalizer(program).execImpl();
+ }
+
+ private final JProgram program;
+
+ private LongCastNormalizer(JProgram program) {
+ this.program = program;
+ }
+
+ private void execImpl() {
+ ImplicitCastVisitor visitor = new ImplicitCastVisitor(
+ program.getTypePrimitiveLong());
+ visitor.accept(program);
+ }
+
+}
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/LongEmulationNormalizer.java b/dev/core/src/com/google/gwt/dev/jjs/impl/LongEmulationNormalizer.java
new file mode 100644
index 0000000..bdc3eb8
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/LongEmulationNormalizer.java
@@ -0,0 +1,210 @@
+/*
+ * Copyright 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.dev.jjs.impl;
+
+import com.google.gwt.dev.jjs.InternalCompilerException;
+import com.google.gwt.dev.jjs.ast.Context;
+import com.google.gwt.dev.jjs.ast.JBinaryOperation;
+import com.google.gwt.dev.jjs.ast.JBinaryOperator;
+import com.google.gwt.dev.jjs.ast.JMethod;
+import com.google.gwt.dev.jjs.ast.JMethodCall;
+import com.google.gwt.dev.jjs.ast.JModVisitor;
+import com.google.gwt.dev.jjs.ast.JPostfixOperation;
+import com.google.gwt.dev.jjs.ast.JPrefixOperation;
+import com.google.gwt.dev.jjs.ast.JPrimitiveType;
+import com.google.gwt.dev.jjs.ast.JProgram;
+import com.google.gwt.dev.jjs.ast.JType;
+import com.google.gwt.dev.jjs.ast.JUnaryOperator;
+
+/**
+ * Replaces long operations with calls to the emulation library. Depends on
+ * {@link LongCastNormalizer} and {@link CompoundAssignmentNormalizer} having
+ * been run.
+ */
+public class LongEmulationNormalizer {
+
+ /**
+ * Replace all long math with calls into the long emulation library.
+ */
+ private class LongOpVisitor extends JModVisitor {
+
+ private final JPrimitiveType longType;
+
+ public LongOpVisitor(JPrimitiveType longType) {
+ this.longType = longType;
+ }
+
+ @Override
+ public void endVisit(JBinaryOperation x, Context ctx) {
+ JType lhsType = x.getLhs().getType();
+ JType rhsType = x.getRhs().getType();
+ if (lhsType != longType) {
+ return;
+ }
+
+ String methodName = getEmulationMethod(x.getOp());
+ if (methodName == null) {
+ return;
+ }
+
+ // Check operand types.
+ switch (x.getOp()) {
+ case SHL:
+ case SHR:
+ case SHRU:
+ if (rhsType != program.getTypePrimitiveInt()) {
+ throw new InternalCompilerException(
+ "Expected right operand to be of type int");
+ }
+ break;
+ default:
+ if (rhsType != longType) {
+ throw new InternalCompilerException(
+ "Expected right operand to be of type long");
+ }
+ }
+
+ JMethod method = program.getIndexedMethod("LongLib." + methodName);
+ JMethodCall call = new JMethodCall(program, x.getSourceInfo(), null,
+ method, x.getType());
+ call.getArgs().add(x.getLhs());
+ call.getArgs().add(x.getRhs());
+ ctx.replaceMe(call);
+ }
+
+ @Override
+ public void endVisit(JPostfixOperation x, Context ctx) {
+ JType argType = x.getArg().getType();
+ if (argType == longType) {
+ throw new InternalCompilerException(
+ "Postfix operations on longs should not reach here");
+ }
+ }
+
+ @Override
+ public void endVisit(JPrefixOperation x, Context ctx) {
+ JType argType = x.getArg().getType();
+ if (argType != longType) {
+ return;
+ }
+
+ String methodName = getEmulationMethod(x.getOp());
+ JMethod method = program.getIndexedMethod("LongLib." + methodName);
+ JMethodCall call = new JMethodCall(program, x.getSourceInfo(), null,
+ method, x.getType());
+ call.getArgs().add(x.getArg());
+ ctx.replaceMe(call);
+ }
+
+ private String getEmulationMethod(JBinaryOperator op) {
+ switch (op) {
+ case MUL:
+ return "mul";
+ case DIV:
+ return "div";
+ case MOD:
+ return "mod";
+ case ADD:
+ return "add";
+ case SUB:
+ return "sub";
+ case SHL:
+ return "shl";
+ case SHR:
+ return "shr";
+ case SHRU:
+ return "shru";
+ case LT:
+ return "lt";
+ case LTE:
+ return "lte";
+ case GT:
+ return "gt";
+ case GTE:
+ return "gte";
+ case EQ:
+ return "eq";
+ case NEQ:
+ return "neq";
+ case BIT_AND:
+ return "and";
+ case BIT_XOR:
+ return "xor";
+ case BIT_OR:
+ return "or";
+
+ case AND:
+ case OR:
+ throw new InternalCompilerException(
+ "AND and OR sould not have long operands");
+
+ case ASG:
+ // Nothing to do.
+ return null;
+
+ case ASG_ADD:
+ case ASG_SUB:
+ case ASG_MUL:
+ case ASG_DIV:
+ case ASG_MOD:
+ case ASG_SHL:
+ case ASG_SHR:
+ case ASG_SHRU:
+ case ASG_BIT_AND:
+ case ASG_BIT_OR:
+ case ASG_BIT_XOR:
+ throw new InternalCompilerException(
+ "Modifying long ops should not reach here");
+ default:
+ throw new InternalCompilerException("Should not reach here");
+ }
+ }
+
+ private String getEmulationMethod(JUnaryOperator op) {
+ switch (op) {
+ case INC:
+ case DEC:
+ throw new InternalCompilerException(
+ "Modifying long ops should not reach here");
+ case NEG:
+ return "neg";
+ case NOT:
+ throw new InternalCompilerException(
+ "NOT sould not have a long operand");
+ case BIT_NOT:
+ return "not";
+ default:
+ throw new InternalCompilerException("Should not reach here");
+ }
+ }
+ }
+
+ public static void exec(JProgram program) {
+ new LongEmulationNormalizer(program).execImpl();
+ }
+
+ private final JProgram program;
+
+ private LongEmulationNormalizer(JProgram program) {
+ this.program = program;
+ }
+
+ private void execImpl() {
+ LongOpVisitor visitor = new LongOpVisitor(program.getTypePrimitiveLong());
+ visitor.accept(program);
+ }
+
+}
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/MethodAndClassFinalizer.java b/dev/core/src/com/google/gwt/dev/jjs/impl/MethodAndClassFinalizer.java
deleted file mode 100644
index 5367faa..0000000
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/MethodAndClassFinalizer.java
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * Copyright 2007 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package com.google.gwt.dev.jjs.impl;
-
-import com.google.gwt.dev.jjs.ast.Context;
-import com.google.gwt.dev.jjs.ast.JClassType;
-import com.google.gwt.dev.jjs.ast.JInterfaceType;
-import com.google.gwt.dev.jjs.ast.JMethod;
-import com.google.gwt.dev.jjs.ast.JProgram;
-import com.google.gwt.dev.jjs.ast.JReferenceType;
-import com.google.gwt.dev.jjs.ast.JVisitor;
-
-import java.util.HashSet;
-import java.util.Set;
-
-/**
- * Finds all methods and classes are effectively final. That is, methods that
- * are never overridden and classes that are never subclassed. Mark all such
- * methods and classes as final, since it helps us optimize.
- */
-public class MethodAndClassFinalizer {
-
- /**
- * Any method and classes that weren't marked during MarkVisitor can be set
- * final.
- *
- * Open question: What does it mean if an interface/abstract method becomes
- * final? Is this possible after Pruning? I guess it means that someone tried
- * to make a call to method that wasn't actually implemented anywhere in the
- * program. But if it wasn't implemented, then the enclosing class should have
- * come up as not instantiated and been culled. So I think it's not possible.
- */
- private class FinalizeVisitor extends JVisitor {
-
- private boolean didChange = false;
-
- @Override
- public boolean didChange() {
- return didChange;
- }
-
- // @Override
- @Override
- public boolean visit(JClassType x, Context ctx) {
- if (!x.isFinal() && !isSubclassed.contains(x)) {
- x.setFinal(true);
- didChange = true;
- }
- for (int i = 0; i < x.methods.size(); ++i) {
- JMethod method = x.methods.get(i);
- accept(method);
- }
- return false;
- }
-
- // @Override
- @Override
- public boolean visit(JInterfaceType x, Context ctx) {
- for (int i = 0; i < x.methods.size(); ++i) {
- JMethod method = x.methods.get(i);
- accept(method);
- }
- return false;
- }
-
- // @Override
- @Override
- public boolean visit(JMethod x, Context ctx) {
- if (!x.isFinal() && !isOverriden.contains(x)) {
- x.setFinal(true);
- didChange = true;
- }
- return false;
- }
- }
- /**
- * Find all methods and classes that ARE overriden/subclassed.
- */
- private class MarkVisitor extends JVisitor {
-
- // @Override
- @Override
- public boolean visit(JClassType x, Context ctx) {
- if (x.extnds != null) {
- isSubclassed.add(x.extnds);
- }
-
- for (int i = 0; i < x.methods.size(); ++i) {
- JMethod method = x.methods.get(i);
- accept(method);
- }
- return false;
- }
-
- // @Override
- @Override
- public boolean visit(JInterfaceType x, Context ctx) {
- for (int i = 0; i < x.methods.size(); ++i) {
- JMethod method = x.methods.get(i);
- accept(method);
- }
- return false;
- }
-
- // @Override
- @Override
- public boolean visit(JMethod x, Context ctx) {
- for (int i = 0; i < x.overrides.size(); ++i) {
- JMethod it = x.overrides.get(i);
- isOverriden.add(it);
- }
- return false;
- }
-
- // @Override
- @Override
- public boolean visit(JProgram x, Context ctx) {
- for (int i = 0; i < x.getDeclaredTypes().size(); ++i) {
- JReferenceType type = x.getDeclaredTypes().get(i);
- accept(type);
- }
- return false;
- }
- }
-
- public static boolean exec(JProgram program) {
- return new MethodAndClassFinalizer().execImpl(program);
- }
-
- private final Set<JMethod> isOverriden = new HashSet<JMethod>();
-
- private final Set<JClassType> isSubclassed = new HashSet<JClassType>();
-
- private MethodAndClassFinalizer() {
- }
-
- private boolean execImpl(JProgram program) {
- MarkVisitor marker = new MarkVisitor();
- marker.accept(program);
-
- FinalizeVisitor finalizer = new FinalizeVisitor();
- finalizer.accept(program);
- return finalizer.didChange();
- }
-
-}
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/MethodInliner.java b/dev/core/src/com/google/gwt/dev/jjs/impl/MethodInliner.java
index b09f80c..eaab6ad 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/MethodInliner.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/MethodInliner.java
@@ -17,6 +17,7 @@
import com.google.gwt.dev.jjs.InternalCompilerException;
import com.google.gwt.dev.jjs.ast.Context;
+import com.google.gwt.dev.jjs.ast.JCastOperation;
import com.google.gwt.dev.jjs.ast.JExpression;
import com.google.gwt.dev.jjs.ast.JExpressionStatement;
import com.google.gwt.dev.jjs.ast.JLocalRef;
@@ -452,6 +453,15 @@
CloneExpressionVisitor cloner = new CloneExpressionVisitor(program);
JExpression arg = methodCall.getArgs().get(paramIndex);
JExpression clone = cloner.cloneExpression(arg);
+
+ /*
+ * Insert an implicit cast if the types differ; it might get optimized out
+ * later, but in some cases it will force correct math evaluation.
+ */
+ if (clone.getType() != x.getType()) {
+ clone = new JCastOperation(program, clone.getSourceInfo(), x.getType(),
+ clone);
+ }
ctx.replaceMe(clone);
}
}
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/Pruner.java b/dev/core/src/com/google/gwt/dev/jjs/impl/Pruner.java
index 186890f..7185243 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/Pruner.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/Pruner.java
@@ -22,15 +22,14 @@
import com.google.gwt.dev.jjs.ast.JArrayType;
import com.google.gwt.dev.jjs.ast.JBinaryOperation;
import com.google.gwt.dev.jjs.ast.JBinaryOperator;
-import com.google.gwt.dev.jjs.ast.JBlock;
import com.google.gwt.dev.jjs.ast.JCastOperation;
import com.google.gwt.dev.jjs.ast.JClassType;
+import com.google.gwt.dev.jjs.ast.JDeclarationStatement;
import com.google.gwt.dev.jjs.ast.JExpression;
import com.google.gwt.dev.jjs.ast.JField;
import com.google.gwt.dev.jjs.ast.JFieldRef;
import com.google.gwt.dev.jjs.ast.JInterfaceType;
import com.google.gwt.dev.jjs.ast.JLocal;
-import com.google.gwt.dev.jjs.ast.JLocalDeclarationStatement;
import com.google.gwt.dev.jjs.ast.JLocalRef;
import com.google.gwt.dev.jjs.ast.JMethod;
import com.google.gwt.dev.jjs.ast.JMethodBody;
@@ -114,22 +113,30 @@
}
}
- public void endVisit(JLocalDeclarationStatement x, Context ctx) {
+ public void endVisit(JDeclarationStatement x, Context ctx) {
// The variable may have been pruned.
- if (!referencedNonTypes.contains(x.getLocalRef().getTarget())) {
- // If there is an initializer, just replace with that.
- if (x.getInitializer() != null) {
- ctx.replaceMe(x.getInitializer().makeStatement());
- } else {
- // No initializer, prune this entirely.
- if (ctx.canRemove()) {
- // Just remove it if we can.
- ctx.removeMe();
- } else {
- // Replace with empty block.
- ctx.replaceMe(new JBlock(program, x.getSourceInfo()));
+ if (!referencedNonTypes.contains(x.getVariableRef().getTarget())) {
+ // Replace with a multi, which may wind up empty.
+ JMultiExpression multi = new JMultiExpression(program,
+ x.getSourceInfo());
+
+ // If the lhs is a field ref, evaluate it first.
+ JVariableRef variableRef = x.getVariableRef();
+ if (variableRef instanceof JFieldRef) {
+ JFieldRef fieldRef = (JFieldRef) variableRef;
+ JExpression instance = fieldRef.getInstance();
+ if (instance != null) {
+ multi.exprs.add(instance);
}
}
+
+ // If there is an initializer, evaluate it second.
+ JExpression initializer = x.getInitializer();
+ if (initializer != null) {
+ multi.exprs.add(initializer);
+ }
+
+ ctx.replaceMe(multi.makeStatement());
}
}
@@ -574,7 +581,7 @@
return false;
}
- public boolean visit(JLocalDeclarationStatement x, Context ctx) {
+ public boolean visit(JDeclarationStatement x, Context ctx) {
/*
* A declaration by itself doesn't rescue a local (even if it has an
* initializer). Writes don't count, only reads.
@@ -582,6 +589,16 @@
if (x.getInitializer() != null) {
accept(x.getInitializer());
}
+
+ // If the lhs is a field ref, we have to visit its qualifier.
+ JVariableRef variableRef = x.getVariableRef();
+ if (variableRef instanceof JFieldRef) {
+ JFieldRef fieldRef = (JFieldRef) variableRef;
+ JExpression instance = fieldRef.getInstance();
+ if (instance != null) {
+ accept(instance);
+ }
+ }
return false;
}
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/SourceGenerationVisitor.java b/dev/core/src/com/google/gwt/dev/jjs/impl/SourceGenerationVisitor.java
index d701d01..c457fe9 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/SourceGenerationVisitor.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/SourceGenerationVisitor.java
@@ -89,9 +89,9 @@
public boolean visit(JField x, Context ctx) {
super.visit(x, ctx);
- if (x.constInitializer != null) {
+ if (x.getConstInitializer() != null) {
print(" = ");
- accept(x.constInitializer);
+ accept(x.getConstInitializer());
}
semi();
return false;
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/ToStringGenerationVisitor.java b/dev/core/src/com/google/gwt/dev/jjs/impl/ToStringGenerationVisitor.java
index b740e13..f5d44be 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/ToStringGenerationVisitor.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/ToStringGenerationVisitor.java
@@ -52,7 +52,7 @@
import com.google.gwt.dev.jjs.ast.JLabel;
import com.google.gwt.dev.jjs.ast.JLabeledStatement;
import com.google.gwt.dev.jjs.ast.JLocal;
-import com.google.gwt.dev.jjs.ast.JLocalDeclarationStatement;
+import com.google.gwt.dev.jjs.ast.JDeclarationStatement;
import com.google.gwt.dev.jjs.ast.JLocalRef;
import com.google.gwt.dev.jjs.ast.JLongLiteral;
import com.google.gwt.dev.jjs.ast.JMethod;
@@ -383,7 +383,7 @@
public boolean visit(JField x, Context ctx) {
// Due to our wacky construction model, only constant fields may be final
// when generating source
- if (x.constInitializer != null) {
+ if (x.getConstInitializer() != null) {
printFinalFlag(x);
} else {
printMemberFinalFlag(x);
@@ -552,11 +552,11 @@
}
@Override
- public boolean visit(JLocalDeclarationStatement x, Context ctx) {
+ public boolean visit(JDeclarationStatement x, Context ctx) {
if (!suppressType) {
- accept(x.getLocalRef().getTarget());
+ accept(x.getVariableRef().getTarget());
} else {
- accept(x.getLocalRef());
+ accept(x.getVariableRef());
}
JExpression initializer = x.getInitializer();
if (initializer != null) {
@@ -607,8 +607,12 @@
@Override
public boolean visit(JMethodBody x, Context ctx) {
- visitCollectionWithCommas(x.locals.iterator());
- return false;
+ if (shouldPrintMethodBody()) {
+ return true;
+ } else {
+ visitCollectionWithCommas(x.locals.iterator());
+ return false;
+ }
}
@Override
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/TypeTightener.java b/dev/core/src/com/google/gwt/dev/jjs/impl/TypeTightener.java
index 09b712d..51c7dd6 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/TypeTightener.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/TypeTightener.java
@@ -28,7 +28,7 @@
import com.google.gwt.dev.jjs.ast.JInstanceOf;
import com.google.gwt.dev.jjs.ast.JInterfaceType;
import com.google.gwt.dev.jjs.ast.JLocal;
-import com.google.gwt.dev.jjs.ast.JLocalDeclarationStatement;
+import com.google.gwt.dev.jjs.ast.JDeclarationStatement;
import com.google.gwt.dev.jjs.ast.JLocalRef;
import com.google.gwt.dev.jjs.ast.JMethod;
import com.google.gwt.dev.jjs.ast.JMethodCall;
@@ -208,19 +208,20 @@
}
@Override
- public void endVisit(JField x, Context ctx) {
- if (x.constInitializer != null) {
- addAssignment(x, x.constInitializer);
+ public void endVisit(JDeclarationStatement x, Context ctx) {
+ JExpression initializer = x.getInitializer();
+ if (initializer != null) {
+ addAssignment(x.getVariableRef().getTarget(), initializer);
}
- currentMethod = null;
}
@Override
- public void endVisit(JLocalDeclarationStatement x, Context ctx) {
- JExpression initializer = x.getInitializer();
- if (initializer != null) {
- addAssignment(x.getLocalRef().getTarget(), initializer);
+ public void endVisit(JField x, Context ctx) {
+ if (x.getConstInitializer() != null) {
+ // TODO: do I still need this?
+ addAssignment(x, x.getConstInitializer());
}
+ currentMethod = null;
}
@Override
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/HasInitializer.java b/dev/core/src/com/google/gwt/dev/shell/JavaLong.java
similarity index 60%
copy from dev/core/src/com/google/gwt/dev/jjs/ast/HasInitializer.java
copy to dev/core/src/com/google/gwt/dev/shell/JavaLong.java
index 20a97f7..3217f4f 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/HasInitializer.java
+++ b/dev/core/src/com/google/gwt/dev/shell/JavaLong.java
@@ -1,24 +1,38 @@
-/*
- * Copyright 2007 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package com.google.gwt.dev.jjs.ast;
-
-/**
- * Interface implemented by Java entities that can have an initialization
- * expression.
- */
-public interface HasInitializer {
- void setInitializer(JExpression expression);
-}
+/*
+ * Copyright 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.dev.shell;
+
+/**
+ * Hosted mode wrapper for a Java long value.
+ */
+public class JavaLong {
+
+ private final long longVal;
+
+ public JavaLong(long longVal) {
+ this.longVal = longVal;
+ }
+
+ public long longValue() {
+ return longVal;
+ }
+
+ @Override
+ public String toString() {
+ return "Java long value: " + longVal;
+ }
+
+}
diff --git a/dev/core/src/com/google/gwt/dev/shell/JsValueGlue.java b/dev/core/src/com/google/gwt/dev/shell/JsValueGlue.java
index 4d6f1e7..611f95d 100644
--- a/dev/core/src/com/google/gwt/dev/shell/JsValueGlue.java
+++ b/dev/core/src/com/google/gwt/dev/shell/JsValueGlue.java
@@ -106,23 +106,12 @@
return (T) Integer.valueOf(getIntRange(value, Integer.MIN_VALUE,
Integer.MAX_VALUE, "int", msgPrefix));
} else if (type == Long.TYPE) {
- if (!value.isNumber()) {
+ if (!value.isWrappedJavaObject()) {
throw new HostedModeException(msgPrefix + ": JS value of type "
- + value.getTypeString() + ", expected long");
+ + value.getTypeString() + ", expected Java long");
}
- double doubleVal = value.getNumber();
- if (doubleVal < Long.MIN_VALUE || doubleVal > Long.MAX_VALUE) {
- throw new HostedModeException(msgPrefix + ": JS double value "
- + doubleVal + " out of range for a long");
- }
- // TODO(jat): can this actually detect loss of precision?
- long longVal = (long) doubleVal;
- if (doubleVal != longVal) {
- // TODO(jat): should this be an error or exception?
- ModuleSpace.getLogger().log(TreeLogger.WARN,
- msgPrefix + ": Loss of precision converting double to long", null);
- }
- return (T) Long.valueOf(longVal);
+ JavaLong javaLong = (JavaLong) value.getWrappedJavaObject();
+ return (T) Long.valueOf(javaLong.longValue());
} else if (type == Short.TYPE) {
return (T) Short.valueOf((short) getIntRange(value, Short.MIN_VALUE,
Short.MAX_VALUE, "short", msgPrefix));
@@ -172,13 +161,7 @@
value.setInt(((Integer) obj).intValue());
} else if (type == Long.TYPE) {
long longVal = ((Long) obj).longValue();
- double doubleVal = longVal;
- if ((long) doubleVal != longVal) {
- // TODO(jat): should this be an error or exception?
- ModuleSpace.getLogger().log(TreeLogger.WARN,
- "Loss of precision converting long to double", null);
- }
- value.setDouble(doubleVal);
+ value.setWrappedJavaObject(cl, new JavaLong(longVal));
} else if (type == Short.TYPE) {
value.setInt(((Short) obj).shortValue());
} else if (type == Void.TYPE) {
diff --git a/dev/core/super/com/google/gwt/dev/jjs/intrinsic/Intrinsic.gwt.xml b/dev/core/super/com/google/gwt/dev/jjs/intrinsic/Intrinsic.gwt.xml
index c76608c..dc7c8fe 100644
--- a/dev/core/super/com/google/gwt/dev/jjs/intrinsic/Intrinsic.gwt.xml
+++ b/dev/core/super/com/google/gwt/dev/jjs/intrinsic/Intrinsic.gwt.xml
@@ -18,5 +18,6 @@
<!-- Types from this module are not visible to nor imported into user code. -->
<!-- -->
<module>
+ <inherits name="com.google.gwt.lang.LongLib"/>
<super-source/>
</module>
diff --git a/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/Array.java b/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/Array.java
index 7c6e2b5..eb2874a 100644
--- a/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/Array.java
+++ b/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/Array.java
@@ -218,7 +218,7 @@
* Explicitly initialize all fields to JS false values; see comment in
* wrapArray(Array, Array).
*/
- public int length = 0;
+ public volatile int length = 0;
protected Class arrayClass = null;
protected int queryId = 0;
diff --git a/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/Cast.java b/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/Cast.java
index e0177fc..bda5433 100644
--- a/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/Cast.java
+++ b/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/Cast.java
@@ -81,28 +81,28 @@
/**
* See JLS 5.1.3.
*/
- static native byte narrow_byte(Object x) /*-{
+ static native byte narrow_byte(double x) /*-{
return x << 24 >> 24;
}-*/;
/**
* See JLS 5.1.3.
*/
- static native char narrow_char(Object x) /*-{
+ static native char narrow_char(double x) /*-{
return x & 0xFFFF;
}-*/;
/**
* See JLS 5.1.3.
*/
- static native int narrow_int(Object x) /*-{
+ static native int narrow_int(double x) /*-{
return ~~x;
}-*/;
/**
* See JLS 5.1.3.
*/
- static native short narrow_short(Object x) /*-{
+ static native short narrow_short(double x) /*-{
return x << 16 >> 16;
}-*/;
@@ -110,7 +110,7 @@
* See JLS 5.1.3 for why we do a two-step cast. First we round to int, then
* narrow to byte.
*/
- static byte round_byte(Object x) {
+ static byte round_byte(double x) {
return narrow_byte(round_int(x));
}
@@ -118,32 +118,23 @@
* See JLS 5.1.3 for why we do a two-step cast. First we round to int, then
* narrow to char.
*/
- static char round_char(Object x) {
+ static char round_char(double x) {
return narrow_char(round_int(x));
}
/**
* See JLS 5.1.3.
*/
- static native int round_int(Object x) /*-{
+ static native int round_int(double x) /*-{
// TODO: reference java.lang.Integer::MAX_VALUE when we get clinits fixed
return ~~Math.max(Math.min(x, 2147483647), -2147483648);
}-*/;
/**
- * See JLS 5.1.3.
- */
- static native long round_long(Object x) /*-{
- // TODO: reference java.lang.Long::MAX_VALUE when we get clinits fixed
- x = Math.max(Math.min(x, 9223372036854775807), -9223372036854775808);
- return (x >= 0) ? Math.floor(x) : Math.ceil(x);
- }-*/;
-
- /**
* See JLS 5.1.3 for why we do a two-step cast. First we rount to int, then
* narrow to short.
*/
- static short round_short(Object x) {
+ static short round_short(double x) {
return narrow_short(round_int(x));
}
diff --git a/dev/core/super/com/google/gwt/lang/LongLib.gwt.xml b/dev/core/super/com/google/gwt/lang/LongLib.gwt.xml
new file mode 100644
index 0000000..1988a50
--- /dev/null
+++ b/dev/core/super/com/google/gwt/lang/LongLib.gwt.xml
@@ -0,0 +1,22 @@
+<!-- -->
+<!-- Copyright 2008 Google Inc. -->
+<!-- Licensed under the Apache License, Version 2.0 (the "License"); you -->
+<!-- may not use this file except in compliance with the License. You may -->
+<!-- may obtain a copy of the License at -->
+<!-- -->
+<!-- http://www.apache.org/licenses/LICENSE-2.0 -->
+<!-- -->
+<!-- Unless required by applicable law or agreed to in writing, software -->
+<!-- distributed under the License is distributed on an "AS IS" BASIS, -->
+<!-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -->
+<!-- implied. License for the specific language governing permissions and -->
+<!-- limitations under the License. -->
+
+<!-- Internal long emulation library. -->
+<!-- Do not inherit this module directly; inherit com.google.gwt.core.Core. -->
+<!-- -->
+<!-- Types from this module are not visible to nor imported into user code. -->
+<!-- -->
+<module>
+ <source path=""/>
+</module>
diff --git a/dev/core/super/com/google/gwt/lang/LongLib.java b/dev/core/super/com/google/gwt/lang/LongLib.java
new file mode 100644
index 0000000..be4bab3
--- /dev/null
+++ b/dev/core/super/com/google/gwt/lang/LongLib.java
@@ -0,0 +1,692 @@
+/*
+ * Copyright 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.lang;
+
+import static com.google.gwt.lang.LongLib.Const.LN_2;
+import static com.google.gwt.lang.LongLib.Const.MAX_VALUE;
+import static com.google.gwt.lang.LongLib.Const.MIN_VALUE;
+import static com.google.gwt.lang.LongLib.Const.NEG_ONE;
+import static com.google.gwt.lang.LongLib.Const.ONE;
+import static com.google.gwt.lang.LongLib.Const.TWO;
+import static com.google.gwt.lang.LongLib.Const.TWO_PWR_24;
+import static com.google.gwt.lang.LongLib.Const.ZERO;
+
+/**
+ * Implements a Java <code>long</code> in a way that can be translated to
+ * JavaScript.
+ */
+public class LongLib {
+ /*
+ * Implementation: An array of two doubles, low and high, such that high+low
+ * is mathematically equivalent to the original integer. Since a JavaScript
+ * Number does not hold enough bits to precisely calculate high+low, all
+ * operations must be implemented carefully. "low" is always between 0 and
+ * 2^32-1 inclusive. "high" is always between -2^63 and 2^63-2^32 inclusive
+ * and is a multiple of 2^32. The sign of the number is determined entirely by
+ * "high". Since low is always positive, small negative numbers are encoded
+ * with high=-2^32. For example, -1 is encoded as { high=-2^32, low=2^32-1 }.
+ *
+ * Note that this class must be careful using type "long". Being the
+ * implementation of the long type for web mode, any place it uses a long is
+ * not usable in web mode. There are currently two such methods:
+ * {@link #toLong(double[])} and {@link #make(long)}.
+ */
+
+ /**
+ * Number of bits we expect to be accurate for a double representing a large
+ * integer.
+ */
+ private static final int PRECISION_BITS = 48;
+
+ /**
+ * Use nested class to avoid clinit on outer.
+ */
+ static class CachedInts {
+ // Between -128 and 127.
+ static double[][] boxedValues = new double[256][];
+ }
+
+ static class Const {
+ static final double LN_2 = Math.log(2);
+ static final double[] MAX_VALUE = typeChange(Long.MAX_VALUE);
+ static final double[] MIN_VALUE = typeChange(Long.MIN_VALUE);
+ static final double[] NEG_ONE = fromInt(-1);
+ static final double[] ONE = fromInt(1);
+ static final double[] TWO = fromInt(2);
+
+ /**
+ * Half of the number of bits we expect to be precise.
+ *
+ * @see LongLib#PRECISION_BITS
+ */
+ static final double[] TWO_PWR_24 = typeChange(0x1000000L);
+
+ static final double[] ZERO = fromInt(0);
+ }
+
+ /**
+ * Set this to false before calling any methods when using this class outside
+ * of GWT!
+ */
+ public static volatile boolean RUN_IN_JVM = false;
+
+ /**
+ * Index of the high bits in a 2-double array.
+ */
+ private static final int HIGH = 1;
+ private static final double HIGH_MAX = 9223372032559808512d;
+ private static final double HIGH_MIN = -9223372036854775808d;
+
+ /**
+ * Index of the low bits in a 2-double array.
+ */
+ private static final int LOW = 0;
+ private static final double LOW_MAX = 4294967295d;
+ private static final double LOW_MIN = 0;
+
+ private static final double TWO_PWR_15_DBL = 0x8000;
+ private static final double TWO_PWR_16_DBL = 0x10000;
+ private static final double TWO_PWR_31_DBL = TWO_PWR_16_DBL * TWO_PWR_15_DBL;
+ private static final double TWO_PWR_32_DBL = TWO_PWR_16_DBL * TWO_PWR_16_DBL;
+ private static final double TWO_PWR_48_DBL = TWO_PWR_32_DBL * TWO_PWR_16_DBL;
+ private static final double TWO_PWR_63_DBL = TWO_PWR_32_DBL * TWO_PWR_31_DBL;
+ private static final double TWO_PWR_64_DBL = TWO_PWR_32_DBL * TWO_PWR_32_DBL;
+
+ public static double[] add(double[] a, double[] b) {
+ double newHigh = a[HIGH] + b[HIGH];
+ double newLow = a[LOW] + b[LOW];
+ return create(newLow, newHigh);
+ }
+
+ public static double[] and(double[] a, double[] b) {
+ return makeFromBits(highBits(a) & highBits(b), lowBits(a) & lowBits(b));
+ }
+
+ public static double[] div(double[] a, double[] b) {
+ if (isZero(b)) {
+ throw new ArithmeticException("/ by zero");
+ }
+ if (isZero(a)) {
+ return ZERO;
+ }
+
+ if (eq(a, MIN_VALUE)) {
+ // handle a==MIN_VALUE carefully because of overflow issues
+ if (eq(b, ONE) || eq(b, NEG_ONE)) {
+ // this strange exception is described in JLS3 17.17.2
+ return MIN_VALUE;
+ }
+ // at this point, abs(b) >= 2, so |a/b| < -MIN_VALUE
+ double[] halfa = shr(a, 1);
+ double[] approx = shl(div(halfa, b), 1);
+ double[] rem = sub(a, mul(b, approx));
+ assert gt(rem, MIN_VALUE);
+ return add(approx, div(rem, b));
+ }
+
+ if (eq(b, MIN_VALUE)) {
+ assert !eq(a, MIN_VALUE);
+ return ZERO;
+ }
+
+ // To keep the implementation compact, make a and be
+ // both be positive and swap the sign of the result
+ // if necessary.
+ if (isNegative(a)) {
+ if (isNegative(b)) {
+ return div(neg(a), neg(b));
+ } else {
+ return neg(div(neg(a), b));
+ }
+ }
+ assert (!isNegative(a));
+ if (isNegative(b)) {
+ return neg(div(a, neg(b)));
+ }
+ assert (!isNegative(b));
+
+ // Use float division to approximate the answer.
+ // Repeat until the remainder is less than b.
+ double[] result = ZERO;
+ double[] rem = a;
+ while (gte(rem, b)) {
+ // approximate using float division
+ double[] deltaResult = fromDouble(Math.floor(toDoubleRoundDown(rem)
+ / toDoubleRoundUp(b)));
+ if (isZero(deltaResult)) {
+ deltaResult = Const.ONE;
+ }
+ double[] deltaRem = mul(deltaResult, b);
+
+ assert gte(deltaResult, ONE);
+ assert lte(deltaRem, rem);
+ result = add(result, deltaResult);
+ rem = sub(rem, deltaRem);
+ }
+
+ return result;
+ }
+
+ public static boolean eq(double[] a, double[] b) {
+ return ((a[LOW] == b[LOW]) && (a[HIGH] == b[HIGH]));
+ }
+
+ public static double[] fromDouble(double value) {
+ if (Double.isNaN(value)) {
+ return ZERO;
+ }
+ if (value < -TWO_PWR_63_DBL) {
+ return MIN_VALUE;
+ }
+ if (value >= TWO_PWR_63_DBL) {
+ return MAX_VALUE;
+ }
+ if (value > 0) {
+ return create(Math.floor(value), 0.0);
+ } else {
+ return create(Math.ceil(value), 0.0);
+ }
+ }
+
+ public static double[] fromInt(int value) {
+ if (value > -129 && value < 128) {
+ int rebase = value + 128;
+ double[] result = CachedInts.boxedValues[rebase];
+ if (result == null) {
+ result = CachedInts.boxedValues[rebase] = internalFromInt(value);
+ }
+ return result;
+ }
+ return internalFromInt(value);
+ }
+
+ public static boolean gt(double[] a, double[] b) {
+ return compare(a, b) > 0;
+ }
+
+ public static boolean gte(double[] a, double[] b) {
+ return compare(a, b) >= 0;
+ }
+
+ public static boolean lt(double[] a, double[] b) {
+ return compare(a, b) < 0;
+ }
+
+ public static boolean lte(double[] a, double[] b) {
+ return compare(a, b) <= 0;
+ }
+
+ public static double[] mod(double[] a, double[] b) {
+ return sub(a, mul(div(a, b), b));
+ }
+
+ public static double[] mul(double[] a, double[] b) {
+ if (isZero(a)) {
+ return ZERO;
+ }
+ if (isZero(b)) {
+ return ZERO;
+ }
+
+ // handle MIN_VALUE carefully, because neg(MIN_VALUE)==MIN_VALUE
+ if (eq(a, MIN_VALUE)) {
+ return multByMinValue(b);
+ }
+ if (eq(b, MIN_VALUE)) {
+ return multByMinValue(a);
+ }
+
+ // If either argument is negative, change it to positive, multiply,
+ // and then negate the result.
+ if (isNegative(a)) {
+ if (isNegative(b)) {
+ return mul(neg(a), neg(b));
+ } else {
+ return neg(mul(neg(a), b));
+ }
+ }
+ assert (!isNegative(a));
+ if (isNegative(b)) {
+ return neg(mul(a, neg(b)));
+ }
+ assert (!isNegative(b));
+
+ // If both numbers are small, use float multiplication
+ if (lt(a, TWO_PWR_24) && lt(b, TWO_PWR_24)) {
+ return create(toDouble(a) * toDouble(b), 0.0);
+ }
+
+ // Divide each number into 4 chunks of 16 bits, and then add
+ // up 4x4 multiplies. Skip the six multiplies where the result
+ // mod 2^64 would be 0.
+ double a3 = a[HIGH] % TWO_PWR_48_DBL;
+ double a4 = a[HIGH] - a3;
+ double a1 = a[LOW] % TWO_PWR_16_DBL;
+ double a2 = a[LOW] - a1;
+
+ double b3 = b[HIGH] % TWO_PWR_48_DBL;
+ double b4 = b[HIGH] - b3;
+ double b1 = b[LOW] % TWO_PWR_16_DBL;
+ double b2 = b[LOW] - b1;
+
+ double[] res = ZERO;
+
+ res = addTimes(res, a4, b1);
+ res = addTimes(res, a3, b2);
+ res = addTimes(res, a3, b1);
+ res = addTimes(res, a2, b3);
+ res = addTimes(res, a2, b2);
+ res = addTimes(res, a2, b1);
+ res = addTimes(res, a1, b4);
+ res = addTimes(res, a1, b3);
+ res = addTimes(res, a1, b2);
+ res = addTimes(res, a1, b1);
+
+ return res;
+ }
+
+ public static double[] neg(double[] a) {
+ if (eq(a, MIN_VALUE)) {
+ return MIN_VALUE;
+ }
+ double newHigh = -a[HIGH];
+ double newLow = -a[LOW];
+ if (newLow > LOW_MAX) {
+ newLow -= TWO_PWR_32_DBL;
+ newHigh += TWO_PWR_32_DBL;
+ }
+ if (newLow < LOW_MIN) {
+ newLow += TWO_PWR_32_DBL;
+ newHigh -= TWO_PWR_32_DBL;
+ }
+ return createNormalized(newLow, newHigh);
+ }
+
+ public static boolean neq(double[] a, double[] b) {
+ return ((a[LOW] != b[LOW]) || (a[HIGH] != b[HIGH]));
+ }
+
+ public static double[] not(double[] a) {
+ return makeFromBits(~highBits(a), ~lowBits(a));
+ }
+
+ public static double[] or(double[] a, double[] b) {
+ return makeFromBits(highBits(a) | highBits(b), lowBits(a) | lowBits(b));
+ }
+
+ public static double[] shl(double[] a, int n) {
+ n &= 63;
+
+ if (eq(a, MIN_VALUE)) {
+ if (n == 0) {
+ return a;
+ } else {
+ return ZERO;
+ }
+ }
+
+ if (isNegative(a)) {
+ return neg(shl(neg(a), n));
+ }
+
+ final double twoToN = pwrAsDouble(n);
+
+ double newHigh = a[HIGH] * twoToN % TWO_PWR_64_DBL;
+ double newLow = a[LOW] * twoToN;
+ double diff = newLow - (newLow % TWO_PWR_32_DBL);
+ newHigh += diff;
+ newLow -= diff;
+ if (newHigh >= TWO_PWR_63_DBL) {
+ newHigh -= TWO_PWR_64_DBL;
+ }
+
+ return createNormalized(newLow, newHigh);
+ }
+
+ public static double[] shr(double[] a, int n) {
+ n &= 63;
+ double shiftFact = pwrAsDouble(n);
+ double newHigh = a[HIGH] / shiftFact;
+ double newLow = Math.floor(a[LOW] / shiftFact);
+ return create(newLow, newHigh);
+ }
+
+ /**
+ * Logical right shift. It does not preserve the sign of the input.
+ */
+ public static double[] shru(double[] a, int n) {
+ n &= 63;
+ double[] sr = shr(a, n);
+ if (isNegative(a)) {
+ // the following changes the high bits to 0, using
+ // a formula from JLS3 section 15.19
+ sr = add(sr, shl(TWO, 63 - n));
+ }
+
+ return sr;
+ }
+
+ public static double[] sub(double[] a, double[] b) {
+ double newHigh = a[HIGH] - b[HIGH];
+ double newLow = a[LOW] - b[LOW];
+ return create(newLow, newHigh);
+ }
+
+ /**
+ * Cast from long to double or float.
+ */
+ public static double toDouble(double[] a) {
+ return a[HIGH] + a[LOW];
+ }
+
+ /**
+ * Cast from long to int.
+ */
+ public static int toInt(double[] a) {
+ return lowBits(a);
+ }
+
+ /**
+ * Implicit conversion from long to String.
+ */
+ public static String toString(double[] a) {
+ if (isZero(a)) {
+ return "0";
+ }
+
+ if (eq(a, MIN_VALUE)) {
+ // Special-case MIN_VALUE because neg(MIN_VALUE)==MIN_VALUE
+ return "-9223372036854775808";
+ }
+
+ if (isNegative(a)) {
+ return "-" + toString(neg(a));
+ }
+
+ double[] rem = a;
+ String res = "";
+
+ while (!isZero(rem)) {
+ // Do several digits each time through the loop, so as to
+ // minimize the calls to the very expensive emulated div.
+ final int divByZeroes = 9;
+ final int divBy = 1000000000;
+
+ String digits = "" + toInt(mod(rem, fromInt(divBy)));
+ rem = div(rem, fromInt(divBy));
+
+ if (!isZero(rem)) {
+ int zeroesNeeded = divByZeroes - digits.length();
+ for (; zeroesNeeded > 0; zeroesNeeded--) {
+ digits = "0" + digits;
+ }
+ }
+
+ res = digits + res;
+ }
+
+ return res;
+ }
+
+ public static double[] typeChange(long value) {
+ if (RUN_IN_JVM) {
+ return makeFromBits((int) (value >> 32), (int) value);
+ } else {
+ return typeChange0(value);
+ }
+ }
+
+ public static double[] xor(double[] a, double[] b) {
+ return makeFromBits(highBits(a) ^ highBits(b), lowBits(a) ^ lowBits(b));
+ }
+
+ /**
+ * Because this is a code gen type, this function will keep the double[] type
+ * from being pruned during optimizations. If double[] gets pruned, bad stuff
+ * happens.
+ */
+ static double[] saveDoubleArrayFromPruning() {
+ return new double[2];
+ }
+
+ static long toLong(double[] a) {
+ return (long) a[HIGH] + (long) a[LOW];
+ }
+
+ private static double[] addTimes(double[] accum, double a, double b) {
+ if (a == 0.0) {
+ return accum;
+ }
+ if (b == 0.0) {
+ return accum;
+ }
+ return add(accum, create(a * b, 0.0));
+ }
+
+ /**
+ * Compare the receiver to the argument.
+ *
+ * @return 0 if they are the same, 1 if the receiver is greater, -1 if the
+ * argument is greater.
+ */
+ private static int compare(double[] a, double[] b) {
+ if (eq(a, b)) {
+ return 0;
+ }
+
+ boolean nega = isNegative(a);
+ boolean negb = isNegative(b);
+ if (nega && !negb) {
+ return -1;
+ }
+ if (!nega && negb) {
+ return 1;
+ }
+
+ // at this point, the signs are the same, so subtraction will not overflow
+ assert (nega == negb);
+ if (isNegative(sub(a, b))) {
+ return -1;
+ } else {
+ return 1;
+ }
+ }
+
+ /*
+ * Make a new instance equal to valueLow+valueHigh. The arguments do not need
+ * to be normalized, though by convention valueHigh and valueLow will hold the
+ * high and low bits, respectively.
+ */
+ private static double[] create(double valueLow, double valueHigh) {
+ assert (!Double.isNaN(valueHigh));
+ assert (!Double.isNaN(valueLow));
+ assert (!Double.isInfinite(valueHigh));
+ assert (!Double.isInfinite(valueLow));
+ assert (Math.floor(valueHigh) == valueHigh);
+ assert (Math.floor(valueLow) == valueLow);
+
+ // remove overly high bits
+ valueHigh %= TWO_PWR_64_DBL;
+ valueLow %= TWO_PWR_64_DBL;
+
+ // segregate high and low bits between high and low
+ {
+ double diffHigh = valueHigh % TWO_PWR_32_DBL;
+ double diffLow = Math.floor(valueLow / TWO_PWR_32_DBL) * TWO_PWR_32_DBL;
+
+ valueHigh = (valueHigh - diffHigh) + diffLow;
+ valueLow = (valueLow - diffLow) + diffHigh;
+ }
+
+ // Most or all of the while's in this implementation could probably be if's,
+ // but they are left as while's for now pending a careful review.
+
+ // make valueLow be positive
+ while (valueLow < LOW_MIN) {
+ valueLow += TWO_PWR_32_DBL;
+ valueHigh -= TWO_PWR_32_DBL;
+ }
+
+ // make valueLow not too large
+ while (valueLow > LOW_MAX) {
+ valueLow -= TWO_PWR_32_DBL;
+ valueHigh += TWO_PWR_32_DBL;
+ }
+
+ // make valueHigh within range
+ valueHigh = valueHigh % TWO_PWR_64_DBL;
+ while (valueHigh > HIGH_MAX) {
+ valueHigh -= TWO_PWR_64_DBL;
+ }
+ while (valueHigh < HIGH_MIN) {
+ valueHigh += TWO_PWR_64_DBL;
+ }
+
+ return createNormalized(valueLow, valueHigh);
+ }
+
+ /**
+ * Create an instance. The high and low parts must be normalized. Normal
+ * callers should use the factory method {@link #make(double, double) make}.
+ */
+ private static double[] createNormalized(double valueLow, double valueHigh) {
+ assert (valueHigh <= HIGH_MAX);
+ assert (valueHigh >= HIGH_MIN);
+ assert (valueLow >= 0);
+ assert (valueLow <= LOW_MAX);
+ assert (valueHigh % TWO_PWR_32_DBL == 0);
+ assert (Math.floor(valueLow) == valueLow); // no fractional bits allowed
+
+ if (RUN_IN_JVM) {
+ return new double[] {valueLow, valueHigh};
+ } else {
+ return newLong0(valueLow, valueHigh);
+ }
+ }
+
+ private static int highBits(double[] a) {
+ return (int) (a[HIGH] / TWO_PWR_32_DBL);
+ }
+
+ private static double[] internalFromInt(int value) {
+ if (value >= 0) {
+ return createNormalized(value, 0.0);
+ } else {
+ return createNormalized(value + TWO_PWR_32_DBL, -TWO_PWR_32_DBL);
+ }
+ }
+
+ private static boolean isNegative(double[] a) {
+ return a[HIGH] < 0;
+ }
+
+ private static boolean isOdd(double[] a) {
+ return (lowBits(a) & 1) == 1;
+ }
+
+ private static boolean isZero(double[] a) {
+ return a[LOW] == 0.0 && a[HIGH] == 0.0;
+ }
+
+ private static int lowBits(double[] a) {
+ if (a[LOW] >= TWO_PWR_31_DBL) {
+ return (int) (a[LOW] - TWO_PWR_32_DBL);
+ } else {
+ return (int) a[LOW];
+ }
+ }
+
+ /**
+ * Make an instance equivalent to stringing highBits next to lowBits, where
+ * highBits and lowBits are assumed to be in 32-bit twos-complement notation.
+ * As a result, for any double[] l, the following identity holds:
+ *
+ * <blockquote> <code>l == makeFromBits(l.highBits(), l.lowBits())</code>
+ * </blockquote>
+ */
+ private static double[] makeFromBits(int highBits, int lowBits) {
+ double high = highBits * TWO_PWR_32_DBL;
+ double low = lowBits;
+ if (lowBits < 0) {
+ low += TWO_PWR_32_DBL;
+ }
+ return createNormalized(low, high);
+ }
+
+ private static double[] multByMinValue(double[] a) {
+ if (isOdd(a)) {
+ return MIN_VALUE;
+ } else {
+ return ZERO;
+ }
+ }
+
+ /**
+ * Faster web mode implementation doesn't need full type semantics.
+ */
+ private static native double[] newLong0(double valueLow, double valueHigh) /*-{
+ return [valueLow, valueHigh];
+ }-*/;
+
+ /**
+ * Return a power of two as a double.
+ *
+ * @return 2 raised to the <code>n</code>
+ */
+ private static double pwrAsDouble(int n) {
+ if (n <= 30) {
+ return (1 << n);
+ } else {
+ return pwrAsDouble(30) * pwrAsDouble(n - 30);
+ }
+ }
+
+ private static double toDoubleRoundDown(double[] a) {
+ int magnitute = (int) (Math.log(a[HIGH]) / LN_2);
+ if (magnitute <= PRECISION_BITS) {
+ return toDouble(a);
+ } else {
+ int diff = magnitute - PRECISION_BITS;
+ int toSubtract = (1 << diff) - 1;
+ return a[HIGH] + (a[LOW] - toSubtract);
+ }
+ }
+
+ private static double toDoubleRoundUp(double[] a) {
+ int magnitute = (int) (Math.log(a[HIGH]) / LN_2);
+ if (magnitute <= PRECISION_BITS) {
+ return toDouble(a);
+ } else {
+ int diff = magnitute - PRECISION_BITS;
+ int toAdd = (1 << diff) - 1;
+ return a[HIGH] + (a[LOW] + toAdd);
+ }
+ }
+
+ /**
+ * Web mode implementation; the long is already the right object.
+ */
+ private static native double[] typeChange0(long value) /*-{
+ return value;
+ }-*/;
+
+ /**
+ * Not instantiable.
+ */
+ private LongLib() {
+ }
+
+}
diff --git a/dev/core/test/com/google/gwt/lang/LongLibJreTest.java b/dev/core/test/com/google/gwt/lang/LongLibJreTest.java
new file mode 100644
index 0000000..9cc6a8f
--- /dev/null
+++ b/dev/core/test/com/google/gwt/lang/LongLibJreTest.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.lang;
+
+import junit.framework.TestCase;
+
+/**
+ * Test the LongLib class as a GWTTestCase.
+ */
+public class LongLibJreTest extends TestCase {
+
+ static {
+ LongLib.RUN_IN_JVM = true;
+ }
+
+ private LongLibTestBase impl = new LongLibTestBase();
+
+ public void testAdditive() {
+ impl.testAdditive();
+ }
+
+ public void testBitOps() {
+ impl.testBitOps();
+ }
+
+ public void testComparisons() {
+ impl.testComparisons();
+ }
+
+ public void testConversions() {
+ impl.testConversions();
+ }
+
+ public void testDiv() {
+ impl.testDiv();
+ }
+
+ public void testFactorial() {
+ impl.testFactorial();
+ }
+
+ public void testFromDouble() {
+ impl.testFromDouble();
+ }
+
+ public void testMinMax() {
+ impl.testMinMax();
+ }
+
+ public void testMultiplicative() {
+ impl.testMultiplicative();
+ }
+
+ public void testNegate() {
+ impl.testNegate();
+ }
+
+ public void testShift() {
+ impl.testShift();
+ }
+
+ public void testToHexString() {
+ impl.testToHexString();
+ }
+
+ public void testToString() {
+ impl.testToString();
+ }
+}
diff --git a/dev/core/test/com/google/gwt/lang/LongLibTestBase.java b/dev/core/test/com/google/gwt/lang/LongLibTestBase.java
new file mode 100644
index 0000000..618df5a
--- /dev/null
+++ b/dev/core/test/com/google/gwt/lang/LongLibTestBase.java
@@ -0,0 +1,353 @@
+/*
+ * Copyright 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.lang;
+
+import com.google.gwt.lang.LongLib.Const;
+
+import junit.framework.TestCase;
+
+/**
+ * Test the LongLib class. The magic expected values were computed by using a
+ * Java println on normal Java longs.
+ */
+public class LongLibTestBase extends TestCase {
+
+ static void assertEquals(double[] expected, double[] actual) {
+ assertTrue("expected=" + LongLib.toString(expected) + " actual="
+ + LongLib.toString(actual), LongLib.eq(expected, actual));
+ }
+
+ public void testAdditive() {
+ {
+ final double[] n1 = LongLib.fromInt(1234);
+ final double[] n2 = LongLib.fromInt(9876);
+ assertEquals(LongLib.fromInt(11110), LongLib.add(n1, n2));
+ assertEquals(LongLib.fromInt(-8642), LongLib.sub(n1, n2));
+ }
+
+ {
+ final double[] n1 = LongLib.fromInt(-1234);
+ final double[] n2 = LongLib.fromInt(9876);
+ assertEquals(LongLib.fromInt(8642), LongLib.add(n1, n2));
+ assertEquals(LongLib.fromInt(-11110), LongLib.sub(n1, n2));
+ }
+
+ {
+ final double[] n1 = LongLib.fromInt(-1234);
+ final double[] n2 = LongLib.fromInt(-9876);
+ assertEquals(LongLib.fromInt(-11110), LongLib.add(n1, n2));
+ assertEquals(LongLib.fromInt(8642), LongLib.sub(n1, n2));
+ }
+
+ {
+ final double[] n1 = longFromBits(0x12345678, 0xabcdabcd);
+ final double[] n2 = longFromBits(0x77773333, 0x22224444);
+ assertEquals(longFromBits(0x89ab89ab, 0xcdeff011), LongLib.add(n1, n2));
+ assertEquals(longFromBits(0x9abd2345, 0x89ab6789), LongLib.sub(n1, n2));
+ }
+ }
+
+ public void testBitOps() {
+ {
+ final double[] n1 = LongLib.fromInt(1234);
+ final double[] n2 = LongLib.fromInt(9876);
+
+ assertEquals(LongLib.fromInt(1168), LongLib.and(n1, n2));
+ assertEquals(LongLib.fromInt(9942), LongLib.or(n1, n2));
+ assertEquals(LongLib.fromInt(8774), LongLib.xor(n1, n2));
+ assertEquals(LongLib.fromInt(-1235), LongLib.not(n1));
+ assertEquals(LongLib.fromInt(-9877), LongLib.not(n2));
+ }
+
+ {
+ final double[] n1 = LongLib.fromInt(-1234);
+ final double[] n2 = LongLib.fromInt(9876);
+ assertEquals(LongLib.fromInt(8708), LongLib.and(n1, n2));
+ assertEquals(LongLib.fromInt(-66), LongLib.or(n1, n2));
+ assertEquals(LongLib.fromInt(-8774), LongLib.xor(n1, n2));
+ assertEquals(LongLib.fromInt(1233), LongLib.not(n1));
+ assertEquals(LongLib.fromInt(-9877), LongLib.not(n2));
+ }
+
+ {
+ final double[] n1 = LongLib.shl(LongLib.fromInt(0x1234), 32);
+ final double[] n2 = LongLib.shl(LongLib.fromInt(0x9876), 32);
+ assertEquals(LongLib.shl(LongLib.fromInt(0x1034), 32),
+ LongLib.and(n1, n2));
+ assertEquals(LongLib.shl(LongLib.fromInt(0x9a76), 32), LongLib.or(n1, n2));
+ assertEquals(LongLib.shl(LongLib.fromInt(0x8a42), 32),
+ LongLib.xor(n1, n2));
+ assertEquals(longFromBits(0xffffedcb, 0xffffffff), LongLib.not(n1));
+ assertEquals(longFromBits(0xffff6789, 0xffffffff), LongLib.not(n2));
+ }
+ }
+
+ public void testComparisons() {
+ assertTrue(LongLib.lt(LongLib.fromInt(10), LongLib.fromInt(11)));
+ assertTrue(LongLib.lte(LongLib.fromInt(10), LongLib.fromInt(11)));
+ assertTrue(!LongLib.eq(LongLib.fromInt(10), LongLib.fromInt(11)));
+ assertTrue(!LongLib.gte(LongLib.fromInt(10), LongLib.fromInt(11)));
+ assertTrue(!LongLib.gt(LongLib.fromInt(10), LongLib.fromInt(11)));
+
+ assertTrue(!LongLib.lt(LongLib.fromInt(10), LongLib.fromInt(10)));
+ assertTrue(LongLib.lte(LongLib.fromInt(10), LongLib.fromInt(10)));
+ assertTrue(LongLib.eq(LongLib.fromInt(10), LongLib.fromInt(10)));
+ assertTrue(LongLib.gte(LongLib.fromInt(10), LongLib.fromInt(10)));
+ assertTrue(!LongLib.gt(LongLib.fromInt(10), LongLib.fromInt(10)));
+
+ assertTrue(!LongLib.lt(LongLib.fromInt(12), LongLib.fromInt(11)));
+ assertTrue(!LongLib.lte(LongLib.fromInt(12), LongLib.fromInt(11)));
+ assertTrue(!LongLib.eq(LongLib.fromInt(12), LongLib.fromInt(11)));
+ assertTrue(LongLib.gte(LongLib.fromInt(12), LongLib.fromInt(11)));
+ assertTrue(LongLib.gt(LongLib.fromInt(12), LongLib.fromInt(11)));
+
+ // the following three comparisons cannot be implemented by
+ // subtracting the arguments, because the subtraction causes an overflow
+ final double[] largeNeg = longFromBits(0x82341234, 0x0);
+ final double[] largePos = longFromBits(0x12341234, 0x0);
+ assertTrue(LongLib.lt(largeNeg, largePos));
+
+ assertTrue(LongLib.lt(Const.MIN_VALUE, LongLib.fromInt(0)));
+ assertTrue(LongLib.gt(LongLib.fromInt(0), Const.MIN_VALUE));
+
+ final double[] largePosPlusOne = LongLib.add(largePos, LongLib.fromInt(1));
+
+ assertTrue(LongLib.lt(largePos, largePosPlusOne));
+ assertTrue(LongLib.lte(largePos, largePosPlusOne));
+ assertTrue(!LongLib.eq(largePos, largePosPlusOne));
+ assertTrue(!LongLib.gte(largePos, largePosPlusOne));
+ assertTrue(!LongLib.gt(largePos, largePosPlusOne));
+
+ assertTrue(!LongLib.lt(largePos, largePos));
+ assertTrue(LongLib.lte(largePos, largePos));
+ assertTrue(LongLib.eq(largePos, largePos));
+ assertTrue(LongLib.gte(largePos, largePos));
+ assertTrue(!LongLib.gt(largePos, largePos));
+
+ assertTrue(!LongLib.lt(largePosPlusOne, largePos));
+ assertTrue(!LongLib.lte(largePosPlusOne, largePos));
+ assertTrue(!LongLib.eq(largePosPlusOne, largePos));
+ assertTrue(LongLib.gte(largePosPlusOne, largePos));
+ assertTrue(LongLib.gt(largePosPlusOne, largePos));
+ }
+
+ public void testConversions() {
+ assertEquals(10, LongLib.toInt(longFromBits(0, 10)));
+ assertEquals(-10, LongLib.toInt(longFromBits(0, -10)));
+ assertEquals(-10, LongLib.toInt(longFromBits(100, -10)));
+ assertEquals(-10, LongLib.toInt(longFromBits(-100000, -10)));
+ }
+
+ public void testDiv() {
+ double[] deadBeef = LongLib.typeChange(0xdeadbeefdeadbeefL);
+ double[] ten = LongLib.fromInt(10);
+ assertEquals(LongLib.typeChange(-240105308887621659L), LongLib.div(
+ deadBeef, ten));
+ assertEquals(Const.ZERO, LongLib.div(Const.ONE, Const.TWO));
+ assertEquals(LongLib.typeChange(4611686018427387903L), LongLib.div(
+ Const.MAX_VALUE, Const.TWO));
+ }
+
+ public void testFactorial() {
+ double[] fact18 = fact(LongLib.fromInt(18));
+ double[] fact17 = fact(LongLib.fromInt(17));
+ assertEquals(LongLib.fromInt(18), LongLib.div(fact18, fact17));
+ }
+
+ public void testFromDouble() {
+ // these tests are based on JLS3, section 5.1.3
+
+ assertEquals(LongLib.fromInt(10), LongLib.fromDouble(10.5));
+ assertEquals(LongLib.fromInt(-10), LongLib.fromDouble(-10.5));
+ assertEquals(LongLib.shl(LongLib.fromInt(1), 55),
+ LongLib.fromDouble(Math.pow(2.0, 55) + 0.5));
+ assertEquals(LongLib.neg(LongLib.shl(LongLib.fromInt(1), 55)),
+ LongLib.fromDouble(-Math.pow(2.0, 55) - 0.5));
+
+ assertEquals(LongLib.fromInt(0), LongLib.fromDouble(Double.NaN));
+
+ assertEquals(Const.MAX_VALUE, LongLib.fromDouble(Math.pow(2.0, 100)));
+ assertEquals(Const.MAX_VALUE, LongLib.fromDouble(Double.POSITIVE_INFINITY));
+ assertEquals(Const.MIN_VALUE, LongLib.fromDouble(-Math.pow(2.0, 100)));
+ assertEquals(Const.MIN_VALUE, LongLib.fromDouble(Double.NEGATIVE_INFINITY));
+ }
+
+ public void testMinMax() {
+ assertEquals(Const.MIN_VALUE, LongLib.shl(LongLib.fromInt(1), 63));
+ assertEquals(Const.MAX_VALUE, LongLib.neg(LongLib.add(Const.MIN_VALUE,
+ LongLib.fromInt(1))));
+ }
+
+ public void testMultiplicative() {
+ assertEquals(LongLib.fromInt(3333), LongLib.mul(LongLib.fromInt(1111),
+ LongLib.fromInt(3)));
+ assertEquals(LongLib.fromInt(-3333), LongLib.mul(LongLib.fromInt(1111),
+ LongLib.fromInt(-3)));
+ assertEquals(LongLib.fromInt(-3333), LongLib.mul(LongLib.fromInt(-1111),
+ LongLib.fromInt(3)));
+ assertEquals(LongLib.fromInt(3333), LongLib.mul(LongLib.fromInt(-1111),
+ LongLib.fromInt(-3)));
+ assertEquals(LongLib.fromInt(0), LongLib.mul(LongLib.fromInt(100),
+ LongLib.fromInt(0)));
+
+ assertEquals(longFromBits(0x7ff63f7c, 0x1df4d840), LongLib.mul(
+ longFromBits(0x12345678, 0x12345678), longFromBits(0x1234, 0x12345678)));
+ assertEquals(longFromBits(0x7ff63f7c, 0x1df4d840), LongLib.mul(
+ longFromBits(0xf2345678, 0x12345678), longFromBits(0x1234, 0x12345678)));
+ assertEquals(longFromBits(0x297e3f7c, 0x1df4d840), LongLib.mul(
+ longFromBits(0xf2345678, 0x12345678), longFromBits(0xffff1234,
+ 0x12345678)));
+
+ assertEquals(LongLib.fromInt(0), LongLib.mul(Const.MIN_VALUE,
+ LongLib.fromInt(2)));
+ assertEquals(Const.MIN_VALUE, LongLib.mul(Const.MIN_VALUE,
+ LongLib.fromInt(1)));
+ assertEquals(Const.MIN_VALUE, LongLib.mul(Const.MIN_VALUE,
+ LongLib.fromInt(-1)));
+
+ assertEquals(LongLib.fromInt(1), LongLib.div(LongLib.fromInt(5),
+ LongLib.fromInt(5)));
+ assertEquals(LongLib.fromInt(333), LongLib.div(LongLib.fromInt(1000),
+ LongLib.fromInt(3)));
+ assertEquals(LongLib.fromInt(-333), LongLib.div(LongLib.fromInt(1000),
+ LongLib.fromInt(-3)));
+ assertEquals(LongLib.fromInt(-333), LongLib.div(LongLib.fromInt(-1000),
+ LongLib.fromInt(3)));
+ assertEquals(LongLib.fromInt(333), LongLib.div(LongLib.fromInt(-1000),
+ LongLib.fromInt(-3)));
+ assertEquals(LongLib.fromInt(0), LongLib.div(LongLib.fromInt(3),
+ LongLib.fromInt(1000)));
+ assertEquals(longFromBits(0x1003d0, 0xe84f5ae8), LongLib.div(longFromBits(
+ 0x12345678, 0x12345678), longFromBits(0x0, 0x123)));
+ assertEquals(longFromBits(0x0, 0x10003), LongLib.div(longFromBits(
+ 0x12345678, 0x12345678), longFromBits(0x1234, 0x12345678)));
+ assertEquals(longFromBits(0xffffffff, 0xffff3dfe), LongLib.div(
+ longFromBits(0xf2345678, 0x12345678), longFromBits(0x1234, 0x12345678)));
+ assertEquals(longFromBits(0x0, 0xeda), LongLib.div(longFromBits(0xf2345678,
+ 0x12345678), longFromBits(0xffff1234, 0x12345678)));
+
+ try {
+ LongLib.div(LongLib.fromInt(1), LongLib.fromInt(0));
+ fail("Expected an ArithmeticException");
+ } catch (ArithmeticException e) {
+ }
+
+ assertEquals(longFromBits(0xc0000000, 0x00000000), LongLib.div(
+ Const.MIN_VALUE, LongLib.fromInt(2)));
+ assertEquals(Const.MIN_VALUE, LongLib.div(Const.MIN_VALUE,
+ LongLib.fromInt(1)));
+ assertEquals(Const.MIN_VALUE, LongLib.div(Const.MIN_VALUE,
+ LongLib.fromInt(-1))); // JLS3 section 15.17.2
+ }
+
+ public void testNegate() {
+ assertEquals(LongLib.fromInt(-1), LongLib.neg(LongLib.fromInt(1)));
+ assertEquals(LongLib.fromInt(1), LongLib.neg(LongLib.fromInt(-1)));
+
+ // JLS3 15.15.4
+ assertEquals(Const.MIN_VALUE, LongLib.neg(Const.MIN_VALUE));
+ }
+
+ public void testShift() {
+ assertEquals(longFromBits(0xd048d115, 0x9d159c00), LongLib.shl(
+ longFromBits(0x12341234, 0x45674567), 10));
+ assertEquals(longFromBits(0x48d04, 0x8d1159d1), LongLib.shr(longFromBits(
+ 0x12341234, 0x45674567), 10));
+ assertEquals(longFromBits(0x48d04, 0x8d1159d1), LongLib.shru(longFromBits(
+ 0x12341234, 0x45674567), 10));
+ assertEquals(longFromBits(0xd048d115, 0x9d159c00), LongLib.shl(
+ longFromBits(0x92341234, 0x45674567), 10));
+ assertEquals(longFromBits(0xffe48d04, 0x8d1159d1), LongLib.shr(
+ longFromBits(0x92341234, 0x45674567), 10));
+ assertEquals(longFromBits(0x248d04, 0x8d1159d1), LongLib.shru(longFromBits(
+ 0x92341234, 0x45674567), 10));
+
+ assertEquals(LongLib.fromInt(-1), LongLib.shr(LongLib.fromInt(-1), 10));
+
+ assertEquals(LongLib.fromInt(-1 << 5), LongLib.shl(LongLib.fromInt(-1), 5));
+ assertEquals(LongLib.fromInt(-1), LongLib.shl(LongLib.fromInt(-1), 0));
+ assertEquals(LongLib.neg(LongLib.typeChange(0x4000000000000000L)),
+ LongLib.shr(LongLib.shl(LongLib.fromInt(1), 63), 1));
+ assertEquals(LongLib.fromInt(0), LongLib.shl(LongLib.shl(
+ LongLib.fromInt(-1), 32), 32));
+ assertEquals(Const.MIN_VALUE, LongLib.shl(Const.MIN_VALUE, 0));
+ assertEquals(LongLib.fromInt(0), LongLib.shl(Const.MIN_VALUE, 1));
+ assertEquals(longFromBits(0xfffffffc, 0x00000000), LongLib.shr(
+ LongLib.neg(longFromBits(8, 0)), 1));
+ assertEquals(longFromBits(0x7ffffffc, 0x0), LongLib.shru(
+ LongLib.neg(longFromBits(8, 0)), 1));
+ }
+
+ // Issue 1198, and also a good exercise of several methods.
+ public void testToHexString() {
+ double[] deadbeaf12341234 = longFromBits(0xdeadbeaf, 0x12341234);
+
+ assertEquals("deadbeaf12341234", toHexString(deadbeaf12341234));
+ }
+
+ public void testToString() {
+ assertEquals("0", LongLib.toString(LongLib.fromInt(0)));
+ assertEquals("1", LongLib.toString(LongLib.fromInt(1)));
+ assertEquals("-1", LongLib.toString(LongLib.fromInt(-1)));
+ assertEquals("-10", LongLib.toString(LongLib.fromInt(-10)));
+ assertEquals("-9223372036854775808", LongLib.toString(Const.MIN_VALUE));
+
+ int top = 922337201;
+ int bottom = 967490662;
+ double[] fullnum = LongLib.add(LongLib.mul(LongLib.fromInt(1000000000),
+ LongLib.fromInt(top)), LongLib.fromInt(bottom));
+
+ assertEquals("922337201967490662", LongLib.toString(fullnum));
+ assertEquals("-922337201967490662", LongLib.toString(LongLib.neg(fullnum)));
+ }
+
+ private double[] fact(double[] n) {
+ if (LongLib.eq(n, LongLib.fromInt(0))) {
+ return LongLib.fromInt(1);
+ } else {
+ return LongLib.mul(n, fact(LongLib.sub(n, LongLib.fromInt(1))));
+ }
+ }
+
+ private double[] longFromBits(int top, int bottom) {
+ double[] topHalf = LongLib.shl(LongLib.fromInt(top), 32);
+ double[] bottomHalf = LongLib.fromInt(bottom);
+ if (LongLib.lt(bottomHalf, Const.ZERO)) {
+ bottomHalf = LongLib.add(bottomHalf, LongLib.shl(LongLib.fromInt(1), 32));
+ }
+ double[] total = LongLib.add(topHalf, bottomHalf);
+ return total;
+ }
+
+ private String toHexString(double[] x) {
+ // copied from the GWT Long class and modified for double[]
+ double[] zero = LongLib.fromInt(0);
+
+ if (LongLib.eq(x, zero)) {
+ return "0";
+ }
+ String[] hexDigits = new String[] {
+ "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d",
+ "e", "f"};
+ String hexStr = "";
+ while (!LongLib.eq(x, zero)) {
+ int nibble = LongLib.toInt(x) & 0xF;
+ hexStr = hexDigits[nibble] + hexStr;
+ x = LongLib.shru(x, 4);
+ }
+ return hexStr;
+ }
+}
diff --git a/eclipse/dev/linux/.classpath b/eclipse/dev/linux/.classpath
index bd7b01b..474df8f 100644
--- a/eclipse/dev/linux/.classpath
+++ b/eclipse/dev/linux/.classpath
@@ -3,6 +3,7 @@
<classpathentry kind="src" path="core/src"/>
<classpathentry kind="src" path="core/test"/>
<classpathentry kind="src" path="linux/src"/>
+ <classpathentry excluding="com/google/gwt/dev/jjs/intrinsic/" kind="src" path="core/super"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="var" path="GWT_TOOLS/lib/eclipse/org.eclipse.swt.gtk-linux-3.2.1.jar" sourcepath="/GWT_TOOLS/lib/eclipse/org.eclipse.swt.gtk-linux-3.2.1.src.zip"/>
<classpathentry kind="var" path="GWT_TOOLS/lib/apache/ant-1.6.5.jar" sourcepath="/GWT_TOOLS/lib/apache/ant-1.6.5-src.zip"/>
diff --git a/eclipse/dev/mac/.classpath b/eclipse/dev/mac/.classpath
index b5c179a..0f3a28d 100644
--- a/eclipse/dev/mac/.classpath
+++ b/eclipse/dev/mac/.classpath
@@ -3,6 +3,7 @@
<classpathentry kind="src" path="core/src"/>
<classpathentry kind="src" path="core/test"/>
<classpathentry kind="src" path="mac/src"/>
+ <classpathentry excluding="com/google/gwt/dev/jjs/intrinsic/" kind="src" path="core/super"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="var" path="GWT_TOOLS/lib/eclipse/org.eclipse.swt.carbon-macosx-3.2.1.jar" sourcepath="/GWT_TOOLS/lib/eclipse/org.eclipse.swt.carbon-macosx-3.2.1.src.zip"/>
<classpathentry kind="var" path="GWT_TOOLS/lib/apache/ant-1.6.5.jar" sourcepath="/GWT_TOOLS/lib/apache/ant-1.6.5-src.zip"/>
diff --git a/eclipse/dev/windows/.classpath b/eclipse/dev/windows/.classpath
index cf646da..f35f9ec 100644
--- a/eclipse/dev/windows/.classpath
+++ b/eclipse/dev/windows/.classpath
@@ -3,6 +3,7 @@
<classpathentry kind="src" path="core/src"/>
<classpathentry kind="src" path="core/test"/>
<classpathentry kind="src" path="windows/src"/>
+ <classpathentry excluding="com/google/gwt/dev/jjs/intrinsic/" kind="src" path="core/super"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="var" path="GWT_TOOLS/lib/eclipse/org.eclipse.swt.win32-win32-3.2.1.jar" sourcepath="/GWT_TOOLS/lib/eclipse/org.eclipse.swt.win32-win32-3.2.1.src.zip"/>
<classpathentry kind="var" path="GWT_TOOLS/lib/apache/ant-1.6.5.jar" sourcepath="/GWT_TOOLS/lib/apache/ant-1.6.5-src.zip"/>
diff --git a/user/build.xml b/user/build.xml
index fab6c83..fb08c64 100755
--- a/user/build.xml
+++ b/user/build.xml
@@ -38,7 +38,7 @@
<target name="compile.tests" description="Compiles the test code for this project">
<mkdir dir="${javac.junit.out}" />
- <gwt.javac srcdir="test" destdir="${javac.junit.out}">
+ <gwt.javac srcdir="test" excludes="com/google/gwt/langtest/**" destdir="${javac.junit.out}">
<classpath>
<pathelement location="${javac.out}" />
<pathelement location="${gwt.tools.lib}/junit/junit-3.8.1.jar" />
diff --git a/user/src/com/google/gwt/user/client/Cookies.java b/user/src/com/google/gwt/user/client/Cookies.java
index 829b1f0..15554ce 100644
--- a/user/src/com/google/gwt/user/client/Cookies.java
+++ b/user/src/com/google/gwt/user/client/Cookies.java
@@ -147,7 +147,7 @@
}-*/;
private static native void setCookieImpl(String name, String value,
- long expires, String domain, String path, boolean secure) /*-{
+ double expires, String domain, String path, boolean secure) /*-{
var c = encodeURIComponent(name) + '=' + encodeURIComponent(value);
if ( expires )
c += ';expires=' + (new Date(expires)).toGMTString();
diff --git a/user/src/com/google/gwt/user/client/rpc/impl/AbstractSerializationStreamWriter.java b/user/src/com/google/gwt/user/client/rpc/impl/AbstractSerializationStreamWriter.java
index e8b86bc..a89fa39 100644
--- a/user/src/com/google/gwt/user/client/rpc/impl/AbstractSerializationStreamWriter.java
+++ b/user/src/com/google/gwt/user/client/rpc/impl/AbstractSerializationStreamWriter.java
@@ -54,9 +54,10 @@
append(String.valueOf(fieldValue));
}
- public void writeLong(long fieldValue) {
- append(String.valueOf(fieldValue));
- }
+ /**
+ * Asymmetric implementation; see subclasses.
+ */
+ public abstract void writeLong(long value) throws SerializationException;
public void writeObject(Object instance) throws SerializationException {
if (instance == null) {
diff --git a/user/src/com/google/gwt/user/client/rpc/impl/ClientSerializationStreamReader.java b/user/src/com/google/gwt/user/client/rpc/impl/ClientSerializationStreamReader.java
index 7ff2cad..e2c20d1 100644
--- a/user/src/com/google/gwt/user/client/rpc/impl/ClientSerializationStreamReader.java
+++ b/user/src/com/google/gwt/user/client/rpc/impl/ClientSerializationStreamReader.java
@@ -76,9 +76,13 @@
return this.@com.google.gwt.user.client.rpc.impl.ClientSerializationStreamReader::results[--this.@com.google.gwt.user.client.rpc.impl.ClientSerializationStreamReader::index];
}-*/;
- public native long readLong() /*-{
- return this.@com.google.gwt.user.client.rpc.impl.ClientSerializationStreamReader::results[--this.@com.google.gwt.user.client.rpc.impl.ClientSerializationStreamReader::index];
- }-*/;
+ public long readLong() {
+ /*
+ * Sent as a string; if we tried to marshal as a number the JSON eval would
+ * lose precision. We use hex due to specially optimized code paths in Long.
+ */
+ return Long.parseLong(readString(), 16);
+ }
public native short readShort() /*-{
return this.@com.google.gwt.user.client.rpc.impl.ClientSerializationStreamReader::results[--this.@com.google.gwt.user.client.rpc.impl.ClientSerializationStreamReader::index];
diff --git a/user/src/com/google/gwt/user/client/rpc/impl/ClientSerializationStreamWriter.java b/user/src/com/google/gwt/user/client/rpc/impl/ClientSerializationStreamWriter.java
index 5915306..d466958 100644
--- a/user/src/com/google/gwt/user/client/rpc/impl/ClientSerializationStreamWriter.java
+++ b/user/src/com/google/gwt/user/client/rpc/impl/ClientSerializationStreamWriter.java
@@ -115,6 +115,10 @@
return buffer.toString();
}
+ public void writeLong(long fieldValue) {
+ append(Long.toString(fieldValue, 16));
+ }
+
@Override
protected int addString(String string) {
if (string == null) {
diff --git a/user/src/com/google/gwt/user/server/rpc/impl/ServerSerializationStreamReader.java b/user/src/com/google/gwt/user/server/rpc/impl/ServerSerializationStreamReader.java
index 8fecf23..fea0b56 100644
--- a/user/src/com/google/gwt/user/server/rpc/impl/ServerSerializationStreamReader.java
+++ b/user/src/com/google/gwt/user/server/rpc/impl/ServerSerializationStreamReader.java
@@ -337,7 +337,7 @@
}
public long readLong() {
- return Long.parseLong(extract());
+ return Long.parseLong(extract(), 16);
}
public short readShort() {
diff --git a/user/src/com/google/gwt/user/server/rpc/impl/ServerSerializationStreamWriter.java b/user/src/com/google/gwt/user/server/rpc/impl/ServerSerializationStreamWriter.java
index 2549eb2..9dc1e9d 100644
--- a/user/src/com/google/gwt/user/server/rpc/impl/ServerSerializationStreamWriter.java
+++ b/user/src/com/google/gwt/user/server/rpc/impl/ServerSerializationStreamWriter.java
@@ -496,6 +496,14 @@
return buffer.toString();
}
+ public void writeLong(long fieldValue) {
+ /*
+ * Marshal down to client as a string; if we tried to marshal as a number
+ * the JSON eval would lose precision.
+ */
+ writeString(Long.toString(fieldValue, 16));
+ }
+
@Override
protected int addString(String string) {
if (string == null) {
diff --git a/user/super/com/google/gwt/emul/java/lang/ArithmeticException.java b/user/super/com/google/gwt/emul/java/lang/ArithmeticException.java
new file mode 100644
index 0000000..0f1a68a
--- /dev/null
+++ b/user/super/com/google/gwt/emul/java/lang/ArithmeticException.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package java.lang;
+
+/**
+ * NOTE: in GWT this is only thrown for division by zero on longs.
+ *
+ * See <a
+ * href="http://java.sun.com/j2se/1.5.0/docs/api/java/lang/ArrayIndexOutOfBoundsException.html">the
+ * official Java API doc</a> for details.
+ */
+public class ArithmeticException extends RuntimeException {
+ public ArithmeticException(String explanation) {
+ super(explanation);
+ }
+ public ArithmeticException() {
+ super();
+ }
+}
diff --git a/user/super/com/google/gwt/emul/java/lang/Byte.java b/user/super/com/google/gwt/emul/java/lang/Byte.java
index eacee7e..4033f80 100644
--- a/user/super/com/google/gwt/emul/java/lang/Byte.java
+++ b/user/super/com/google/gwt/emul/java/lang/Byte.java
@@ -24,11 +24,16 @@
public static final byte MAX_VALUE = (byte) 0x7F;
public static final int SIZE = 8;
- // Box all values according to JLS
- private static Byte[] boxedValues = new Byte[256];
+ /**
+ * Use nested class to avoid clinit on outer.
+ */
+ private static class BoxedValues {
+ // Box all values according to JLS
+ private static Byte[] boxedValues = new Byte[256];
+ }
public static Byte decode(String s) throws NumberFormatException {
- return new Byte((byte) __decodeAndValidateLong(s, MIN_VALUE, MAX_VALUE));
+ return new Byte((byte) __decodeAndValidateInt(s, MIN_VALUE, MAX_VALUE));
}
/**
@@ -47,7 +52,7 @@
public static byte parseByte(String s, int radix)
throws NumberFormatException {
- return (byte) __parseAndValidateLong(s, radix, MIN_VALUE, MAX_VALUE);
+ return (byte) __parseAndValidateInt(s, radix, MIN_VALUE, MAX_VALUE);
}
public static String toString(byte b) {
@@ -56,10 +61,11 @@
public static Byte valueOf(byte b) {
int rebase = b + 128;
- if (boxedValues[rebase] == null) {
- boxedValues[rebase] = new Byte(b);
+ Byte result = BoxedValues.boxedValues[rebase];
+ if (result == null) {
+ result = BoxedValues.boxedValues[rebase] = new Byte(b);
}
- return boxedValues[rebase];
+ return result;
}
public static Byte valueOf(String s) throws NumberFormatException {
diff --git a/user/super/com/google/gwt/emul/java/lang/Character.java b/user/super/com/google/gwt/emul/java/lang/Character.java
index 9dd6ad3..fbe8f5c 100644
--- a/user/super/com/google/gwt/emul/java/lang/Character.java
+++ b/user/super/com/google/gwt/emul/java/lang/Character.java
@@ -28,8 +28,13 @@
public static final char MIN_VALUE = '\u0000';
public static final char MAX_VALUE = '\uFFFF';
- // Box values according to JLS - from \u0000 to \u007f
- private static Character[] boxedValues = new Character[128];
+ /**
+ * Use nested class to avoid clinit on outer.
+ */
+ private static class BoxedValues {
+ // Box values according to JLS - from \u0000 to \u007f
+ private static Character[] boxedValues = new Character[128];
+ }
public static int digit(char c, int radix) {
if (radix < MIN_RADIX || radix > MAX_RADIX) {
@@ -129,10 +134,11 @@
public static Character valueOf(char c) {
if (c < 128) {
- if (boxedValues[c] == null) {
- boxedValues[c] = new Character(c);
+ Character result = BoxedValues.boxedValues[c];
+ if (result == null) {
+ result = BoxedValues.boxedValues[c] = new Character(c);
}
- return boxedValues[c];
+ return result;
}
return new Character(c);
}
diff --git a/user/super/com/google/gwt/emul/java/lang/Integer.java b/user/super/com/google/gwt/emul/java/lang/Integer.java
index c5b0c15..ac945f5 100644
--- a/user/super/com/google/gwt/emul/java/lang/Integer.java
+++ b/user/super/com/google/gwt/emul/java/lang/Integer.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2007 Google Inc.
+ * Copyright 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
@@ -20,12 +20,30 @@
*/
public final class Integer extends Number implements Comparable<Integer> {
- public static final int MIN_VALUE = 0x80000000;
public static final int MAX_VALUE = 0x7fffffff;
+ public static final int MIN_VALUE = 0x80000000;
public static final int SIZE = 32;
- // Box values according to JLS - between -128 and 127
- private static Integer[] boxedValues = new Integer[256];
+ /**
+ * Use nested class to avoid clinit on outer.
+ */
+ private static class BoxedValues {
+ // Box values according to JLS - between -128 and 127
+ private static Integer[] boxedValues = new Integer[256];
+ }
+
+ /**
+ * Use nested class to avoid clinit on outer.
+ */
+ private static class ReverseNibbles {
+ /**
+ * A fast-lookup of the reversed bits of all the nibbles 0-15. Used to
+ * implement {@link #reverse(int)}.
+ */
+ private static int[] reverseNibbles = {
+ 0x0, 0x8, 0x4, 0xc, 0x2, 0xa, 0x6, 0xe, 0x1, 0x9, 0x5, 0xd, 0x3, 0xb,
+ 0x7, 0xf};
+ }
public static int bitCount(int x) {
// Courtesy the University of Kentucky
@@ -39,7 +57,7 @@
}
public static Integer decode(String s) throws NumberFormatException {
- return new Integer((int) __decodeAndValidateLong(s, MIN_VALUE, MAX_VALUE));
+ return new Integer((int) __decodeAndValidateInt(s, MIN_VALUE, MAX_VALUE));
}
/**
@@ -58,25 +76,15 @@
return 0;
} else {
int rtn;
- for (rtn = 0x40000000; (rtn & i) == 0; rtn = rtn >> 1) {
- // loop down until smaller
+ for (rtn = 0x40000000; (rtn & i) == 0; rtn >>= 1) {
+ // loop down until matched
}
return rtn;
}
}
public static int lowestOneBit(int i) {
- if (i == 0) {
- return 0;
- } else if (i == Integer.MIN_VALUE) {
- return 0x80000000;
- } else {
- int r = 1;
- while ((r & i) == 0) {
- r = r * 2;
- }
- return r;
- }
+ return i & -i;
}
public static int numberOfLeadingZeros(int i) {
@@ -91,10 +99,10 @@
public static int numberOfTrailingZeros(int i) {
if (i == 0) {
- return 32;
+ return SIZE;
} else {
int rtn = 0;
- for (int r = 1; (r & i) == 0; r = r * 2) {
+ for (int r = 1; (r & i) == 0; r <<= 1) {
rtn++;
}
return rtn;
@@ -106,25 +114,15 @@
}
public static int parseInt(String s, int radix) throws NumberFormatException {
- return (int) __parseAndValidateLong(s, radix, MIN_VALUE, MAX_VALUE);
+ return __parseAndValidateInt(s, radix, MIN_VALUE, MAX_VALUE);
}
public static int reverse(int i) {
- int ui = i & 0x7fffffff; // avoid sign extension
- int acc = 0;
- int front = 0x80000000;
- int back = 1;
- int swing = 31;
- while (swing > 0) {
- acc = acc | ((ui & front) >> swing) | ((ui & back) << swing);
- swing -= 2;
- front = front >> 1;
- back = back << 1;
- }
- if (i < 0) {
- acc = acc | 0x1; // restore the real value of 0x80000000
- }
- return acc;
+ int[] nibbles = ReverseNibbles.reverseNibbles;
+ return (nibbles[i >>> 28]) | (nibbles[(i >> 24) & 0xf] << 4)
+ | (nibbles[(i >> 20) & 0xf] << 8) | (nibbles[(i >> 16) & 0xf] << 12)
+ | (nibbles[(i >> 12) & 0xf] << 16) | (nibbles[(i >> 8) & 0xf] << 20)
+ | (nibbles[(i >> 4) & 0xf] << 24) | (nibbles[i & 0xf] << 28);
}
public static int reverseBytes(int i) {
@@ -140,15 +138,15 @@
}
public static int rotateRight(int i, int distance) {
- int ui = i & 0x7fffffff; // avoid sign extension
- int carry = (i < 0) ? 0x40000000 : 0; // 0x80000000 rightshifted 1
+ int ui = i & MAX_VALUE; // avoid sign extension
+ int carry = (i < 0) ? 0x40000000 : 0; // MIN_VALUE rightshifted 1
while (distance-- > 0) {
int nextcarry = ui & 1;
ui = carry | (ui >> 1);
carry = (nextcarry == 0) ? 0 : 0x40000000;
}
if (carry != 0) {
- ui = ui | 0x80000000;
+ ui = ui | MIN_VALUE;
}
return ui;
}
@@ -163,25 +161,51 @@
}
}
- public static String toBinaryString(int x) {
- return Long.toBinaryString(x);
+ public static String toBinaryString(int value) {
+ return toPowerOfTwoString(value, 1);
}
- public static String toHexString(int x) {
- return Long.toHexString(x);
+ public static String toHexString(int value) {
+ return toPowerOfTwoString(value, 4);
}
- public static String toString(int b) {
- return String.valueOf(b);
+ public static String toString(int value) {
+ return String.valueOf(value);
+ }
+
+ public static String toString(int value, int radix) {
+ if (radix == 10 || radix < Character.MIN_RADIX || radix > Character.MAX_RADIX) {
+ return String.valueOf(value);
+ }
+
+ final int bufSize = 33;
+ char[] buf = new char[bufSize];
+ int pos = bufSize - 1;
+ if (value >= 0) {
+ while (value >= radix) {
+ buf[pos--] = __Digits.digits[value % radix];
+ value /= radix;
+ }
+ buf[pos] = __Digits.digits[value];
+ } else {
+ while (value <= -radix) {
+ buf[pos--] = __Digits.digits[-(value % radix)];
+ value /= radix;
+ }
+ buf[pos--] = __Digits.digits[-value];
+ buf[pos] = '-';
+ }
+ return String.__valueOf(buf, pos, bufSize);
}
public static Integer valueOf(int i) {
if (i > -129 && i < 128) {
int rebase = i + 128;
- if (boxedValues[rebase] == null) {
- boxedValues[rebase] = new Integer(i);
+ Integer result = BoxedValues.boxedValues[rebase];
+ if (result == null) {
+ result = BoxedValues.boxedValues[rebase] = new Integer(i);
}
- return boxedValues[rebase];
+ return result;
}
return new Integer(i);
}
@@ -195,6 +219,26 @@
return new Integer(Integer.parseInt(s, radix));
}
+ private static String toPowerOfTwoString(int value, int shift) {
+ final int bufSize = 32 / shift;
+ int bitMask = (1 << shift) - 1;
+ char[] buf = new char[bufSize];
+ int pos = bufSize - 1;
+ if (value >= 0) {
+ while (value > bitMask) {
+ buf[pos--] = __Digits.digits[value & bitMask];
+ value >>= shift;
+ }
+ } else {
+ while (pos > 0) {
+ buf[pos--] = __Digits.digits[value & bitMask];
+ value >>= shift;
+ }
+ }
+ buf[pos] = __Digits.digits[value & bitMask];
+ return String.__valueOf(buf, pos, bufSize);
+ }
+
private final transient int value;
public Integer(int value) {
diff --git a/user/super/com/google/gwt/emul/java/lang/Long.java b/user/super/com/google/gwt/emul/java/lang/Long.java
index 9aab04c..97c1f88 100644
--- a/user/super/com/google/gwt/emul/java/lang/Long.java
+++ b/user/super/com/google/gwt/emul/java/lang/Long.java
@@ -19,25 +19,46 @@
* Wraps a primitive <code>long</code> as an object.
*/
public final class Long extends Number implements Comparable<Long> {
- public static final long MIN_VALUE = 0x8000000000000000L;
- public static final long MAX_VALUE = 0x7fffffffffffffffL;
- public static final int SIZE = 64;
+ /**
+ * Use nested class to avoid clinit on outer.
+ */
+ static class BoxedValues {
+ // Box values according to JLS - between -128 and 127
+ static Long[] boxedValues = new Long[256];
+ }
- // Box values according to JLS - between -128 and 127
- private static Long[] boxedValues = new Long[256];
+ static class HexLookup {
+ /**
+ * Super fast char->digit conversion.
+ */
+ static int[] hexLookup = new int[0];
- public static int bitCount(long i) {
- int cnt = 0;
- for (long q = MIN_VALUE; q > 0; q = q >> 1) {
- if ((q & i) != 0) {
- cnt++;
+ static {
+ for (char c = '0'; c <= '9'; ++c) {
+ hexLookup[c] = c - '0';
+ }
+ for (char c = 'A'; c <= 'F'; ++c) {
+ hexLookup[c] = c - 'A' + 10;
+ }
+ for (char c = 'a'; c <= 'f'; ++c) {
+ hexLookup[c] = c - 'a' + 10;
}
}
- return cnt;
+ }
+
+ public static final long MAX_VALUE = 0x7fffffffffffffffL;
+ public static final long MIN_VALUE = 0x8000000000000000L;
+ public static final int SIZE = 64;
+
+ public static int bitCount(long i) {
+ int high = (int) (i >> 32);
+ int low = (int) i;
+ return Integer.bitCount(high) + Integer.bitCount(low);
}
public static Long decode(String s) throws NumberFormatException {
- return new Long(__decodeAndValidateLong(s, MIN_VALUE, MAX_VALUE));
+ __Decode decode = __decodeNumberString(s);
+ return new Long(parseLong(decode.payload, decode.radix));
}
/**
@@ -48,50 +69,33 @@
}
public static long highestOneBit(long i) {
- if (i < 0) {
- return MIN_VALUE;
+ int high = (int) (i >> 32);
+ if (high != 0) {
+ return ((long) Integer.highestOneBit(high)) << 32;
} else {
- long rtn;
- for (rtn = 0x4000000000000000L; (rtn >> 1) > i; rtn = rtn >> 1) {
- // loop down until smaller
- }
- return rtn;
+ return Integer.highestOneBit((int) i);
}
}
public static long lowestOneBit(long i) {
- if (i == 0) {
- return SIZE;
- } else {
- long r = 1;
- while ((r & i) != 0) {
- r = r << 1;
- }
- return r;
- }
+ return i & -i;
}
public static int numberOfLeadingZeros(long i) {
- if (i < 0) {
- return 0;
- } else if (i == 0) {
- return SIZE;
+ int high = (int) (i >> 32);
+ if (high != 0) {
+ return Integer.numberOfLeadingZeros(high);
} else {
- return SIZE - 1 - (int) Math.floor(Math.log(i) / Math.log(2.0d));
+ return Integer.numberOfLeadingZeros((int) i) + 32;
}
}
public static int numberOfTrailingZeros(long i) {
- if (i < 0) {
- return 0;
- } else if (i == 0) {
- return SIZE;
+ int low = (int) i;
+ if (low != 0) {
+ return Integer.numberOfTrailingZeros(low);
} else {
- int rtn = 0;
- for (int r = 1; (r & i) != 0; r = r * 2) {
- rtn++;
- }
- return rtn;
+ return Integer.numberOfTrailingZeros((int) (i >> 32)) + 32;
}
}
@@ -99,30 +103,66 @@
return parseLong(s, 10);
}
- public static long parseLong(String s, int radix)
+ public static long parseLong(String orig, int intRadix)
throws NumberFormatException {
- return __parseAndValidateLong(s, radix, MIN_VALUE, MAX_VALUE);
+ if (orig == null) {
+ throw new NumberFormatException("null");
+ }
+ if (intRadix < Character.MIN_RADIX || intRadix > Character.MAX_RADIX) {
+ throw new NumberFormatException("radix " + intRadix + " out of range");
+ }
+
+ boolean neg = false;
+ String s;
+ if (orig.charAt(0) == '-') {
+ neg = true;
+ s = orig.substring(1);
+ } else {
+ s = orig;
+ }
+
+ long result = 0;
+ if (intRadix == 16) {
+ result = parseHex(s);
+ } else {
+ // Cache a converted version for performance (pure long ops are faster).
+ long radix = intRadix;
+ for (int i = 0, len = s.length(); i < len; ++i) {
+ if (result < 0) {
+ throw NumberFormatException.forInputString(s);
+ }
+ result *= radix;
+ char c = s.charAt(i);
+ int value = Character.digit(c, intRadix);
+ if (value < 0) {
+ throw NumberFormatException.forInputString(s);
+ }
+ result += value;
+ }
+ }
+
+ if (result < 0 && result != MIN_VALUE) {
+ throw NumberFormatException.forInputString(s);
+ }
+ if (neg) {
+ return -result;
+ } else {
+ return result;
+ }
}
public static long reverse(long i) {
- long acc = 0;
- long front = MIN_VALUE;
- int back = 1;
- int swing = SIZE - 1;
- while (swing > 15) {
- acc = acc | ((i & front) >> swing) | ((i & back) << swing);
- swing--;
- front = front >> 1;
- back = back << 1;
- }
- return acc;
+ int high = (int) (i >>> 32);
+ int low = (int) i;
+ return ((long) Integer.reverse(low) << 32)
+ | (Integer.reverse(high) & 0xffffffffL);
}
public static long reverseBytes(long i) {
- return ((i & 0xffL) << 56) | ((i & 0xff00L) << 40)
- | ((i & 0xff0000L) << 24) | ((i & 0xff000000L) << 8)
- | ((i & 0xff00000000L) >> 8) | ((i & 0xff0000000000L) >> 24)
- | ((i & 0xff000000000000L) >> 40) | ((i & 0xff00000000000000L) >> 56);
+ int high = (int) (i >>> 32);
+ int low = (int) i;
+ return ((long) Integer.reverseBytes(low) << 32)
+ | (Integer.reverseBytes(high) & 0xffffffffL);
}
public static long rotateLeft(long i, int distance) {
@@ -133,10 +173,17 @@
}
public static long rotateRight(long i, int distance) {
+ long ui = i & MAX_VALUE; // avoid sign extension
+ long carry = (i < 0) ? 0x4000000000000000L : 0; // MIN_VALUE rightshifted 1
while (distance-- > 0) {
- i = ((i & 1) == 0 ? 0 : 0x80000000) | i >> 1;
+ long nextcarry = ui & 1;
+ ui = carry | (ui >> 1);
+ carry = (nextcarry == 0) ? 0 : 0x4000000000000000L;
}
- return i;
+ if (carry != 0) {
+ ui = ui | MIN_VALUE;
+ }
+ return ui;
}
public static int signum(long i) {
@@ -149,43 +196,54 @@
}
}
- public static String toBinaryString(long x) {
- if (x == 0) {
- return "0";
- }
- String binStr = "";
- while (x != 0) {
- int bit = (int) x & 0x1;
- binStr = __hexDigits[bit] + binStr;
- x = x >>> 1;
- }
- return binStr;
+ public static String toBinaryString(long value) {
+ return toPowerOfTwoString(value, 1);
}
- public static String toHexString(long x) {
- if (x == 0) {
- return "0";
- }
- String hexStr = "";
- while (x != 0) {
- int nibble = (int) x & 0xF;
- hexStr = __hexDigits[nibble] + hexStr;
- x = x >>> 4;
- }
- return hexStr;
+ public static String toHexString(long value) {
+ return toPowerOfTwoString(value, 4);
}
- public static String toString(long b) {
- return String.valueOf(b);
+ public static String toString(long value) {
+ return String.valueOf(value);
+ }
+
+ public static String toString(long value, int intRadix) {
+ if (intRadix == 10 || intRadix < Character.MIN_RADIX
+ || intRadix > Character.MAX_RADIX) {
+ return String.valueOf(value);
+ }
+
+ final int bufSize = 65;
+ char[] buf = new char[bufSize];
+ int pos = bufSize - 1;
+ // Cache a converted version for performance (pure long ops are faster).
+ long radix = intRadix;
+ if (value >= 0) {
+ while (value >= radix) {
+ buf[pos--] = __Digits.digits[(int) (value % radix)];
+ value /= radix;
+ }
+ buf[pos] = __Digits.digits[(int) value];
+ } else {
+ while (value <= -radix) {
+ buf[pos--] = __Digits.digits[(int) -(value % radix)];
+ value /= radix;
+ }
+ buf[pos--] = __Digits.digits[(int) -value];
+ buf[pos] = '-';
+ }
+ return String.__valueOf(buf, pos, bufSize);
}
public static Long valueOf(long i) {
if (i > -129 && i < 128) {
int rebase = (int) i + 128;
- if (boxedValues[rebase] == null) {
- boxedValues[rebase] = new Long(i);
+ Long result = BoxedValues.boxedValues[rebase];
+ if (result == null) {
+ result = BoxedValues.boxedValues[rebase] = new Long(i);
}
- return boxedValues[rebase];
+ return result;
}
return new Long(i);
}
@@ -198,6 +256,49 @@
return new Long(Long.parseLong(s, radix));
}
+ private static native int hexDigit(char c, String s) /*-{
+ var val = @java.lang.Long.HexLookup::hexLookup[c];
+ if (val == null) {
+ throw @java.lang.NumberFormatException::forInputString(Ljava/lang/String;)(s);
+ }
+ return val;
+ }-*/;
+
+ private static long parseHex(String s) {
+ // TODO: make faster using int math!
+ int len = s.length();
+ if (len > 16) {
+ throw NumberFormatException.forInputString(s);
+ }
+ long result = 0;
+ for (int i = 0; i < len; ++i) {
+ result <<= 4;
+ result += hexDigit(s.charAt(i), s);
+ }
+ return result;
+ }
+
+ private static String toPowerOfTwoString(long value, int shift) {
+ // TODO: make faster using int math!
+ final int bufSize = 64 / shift;
+ long bitMask = (1 << shift) - 1;
+ char[] buf = new char[bufSize];
+ int pos = bufSize - 1;
+ if (value >= 0) {
+ while (value > bitMask) {
+ buf[pos--] = __Digits.digits[(int) (value & bitMask)];
+ value >>= shift;
+ }
+ } else {
+ while (pos > 0) {
+ buf[pos--] = __Digits.digits[(int) (value & bitMask)];
+ value >>= shift;
+ }
+ }
+ buf[pos] = __Digits.digits[(int) (value & bitMask)];
+ return String.__valueOf(buf, pos, bufSize);
+ }
+
private final transient long value;
public Long(long value) {
diff --git a/user/super/com/google/gwt/emul/java/lang/Math.java b/user/super/com/google/gwt/emul/java/lang/Math.java
index 5ff0aed..debd2df 100644
--- a/user/super/com/google/gwt/emul/java/lang/Math.java
+++ b/user/super/com/google/gwt/emul/java/lang/Math.java
@@ -201,9 +201,9 @@
}
};
- public static native long round(double x) /*-{
- return Math.round(x);
- }-*/;
+ public static long round(double x) {
+ return (long) round0(x);
+ }
public static native int round(float x) /*-{
return Math.round(x);
@@ -277,6 +277,10 @@
return x * PI_OVER_180;
}
+ private static native double round0(double x) /*-{
+ return Math.round(x);
+ }-*/;
+
/* NYI: Java 1.5 includes this, but JS doesn't give us the ingredients.
public static double ulp (double x) {
};
diff --git a/user/super/com/google/gwt/emul/java/lang/Number.java b/user/super/com/google/gwt/emul/java/lang/Number.java
index 2360eff..f3d2e3a 100644
--- a/user/super/com/google/gwt/emul/java/lang/Number.java
+++ b/user/super/com/google/gwt/emul/java/lang/Number.java
@@ -1,12 +1,12 @@
/*
* Copyright 2007 Google Inc.
- *
+ *
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
@@ -25,37 +25,48 @@
public abstract class Number implements Serializable {
/**
- * Stores a regular expression object to verify format of float values.
+ * Stores a regular expression object to verify format of float values.
*/
protected static JavaScriptObject floatRegex;
// CHECKSTYLE_OFF: A special need to use unusual identifiers to avoid
// introducing name collisions.
- /**
- * @skip
- */
- protected static String[] __hexDigits = new String[] {
- "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d",
- "e", "f"};
+ static class __Decode {
+ public final String payload;
+ public final int radix;
- static {
- initNative();
+ public __Decode(int radix, String payload) {
+ this.radix = radix;
+ this.payload = payload;
+ }
}
- private static native void initNative() /*-{
- @java.lang.Number::floatRegex = /^[+-]?\d*\.?\d*(e[+-]?\d+)?$/i;
- }-*/;
+ /**
+ * Use nested class to avoid clinit on outer.
+ */
+ static class __Digits {
+ final static char[] digits = {
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd',
+ 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r',
+ 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'};
+ }
/**
* @skip
- *
+ *
* This function will determine the radix that the string is expressed in
* based on the parsing rules defined in the Javadocs for Integer.decode() and
- * invoke __parseAndValidateLong.
+ * invoke __parseAndValidateInt.
*/
- protected static long __decodeAndValidateLong(String s, long lowerBound,
- long upperBound) throws NumberFormatException {
+ protected static long __decodeAndValidateInt(String s, int lowerBound,
+ int upperBound) throws NumberFormatException {
+ __Decode decode = __decodeNumberString(s);
+ return __parseAndValidateInt(decode.payload, decode.radix, lowerBound,
+ upperBound);
+ }
+
+ protected static __Decode __decodeNumberString(String s) {
final boolean negative;
if (s.startsWith("-")) {
negative = true;
@@ -76,50 +87,16 @@
} else {
radix = 10;
}
-
+
if (negative) {
s = "-" + s;
}
-
- return __parseAndValidateLong(s, radix, lowerBound, upperBound);
+ return new __Decode(radix, s);
}
/**
* @skip
- *
- * This function contains common logic for parsing a String in a given
- * radix and validating the result.
- */
- protected static long __parseAndValidateLong(String s, int radix,
- long lowerBound, long upperBound) throws NumberFormatException {
-
- if (s == null) {
- throw new NumberFormatException("Unable to parse null");
- }
- int length = s.length();
- int startIndex = (length > 0) && (s.charAt(0) == '-') ? 1 : 0;
-
- for (int i = startIndex; i < length; i++) {
- if (Character.digit(s.charAt(i), radix) == -1) {
- throw new NumberFormatException("Could not parse " + s +
- " in radix " + radix);
- }
- }
-
- long toReturn = __parseInt(s, radix);
- if (__isLongNaN(toReturn)) {
- throw new NumberFormatException("Unable to parse " + s);
- } else if (toReturn < lowerBound || toReturn > upperBound) {
- throw new NumberFormatException(
- "The string " + s + " exceeds the range for the requested data type");
- }
-
- return toReturn;
- }
-
- /**
- * @skip
- *
+ *
* This function contains common logic for parsing a String as a floating-
* point number and validating the range.
*/
@@ -128,63 +105,84 @@
double toReturn = __parseDouble(s);
- if (__isDoubleNaN(toReturn)) {
- throw new NumberFormatException("Unable to parse " + s);
+ if (__isNaN(toReturn)) {
+ throw NumberFormatException.forInputString(s);
}
-
+
+ return toReturn;
+ }
+
+ /**
+ * @skip
+ *
+ * This function contains common logic for parsing a String in a given radix
+ * and validating the result.
+ */
+ protected static int __parseAndValidateInt(String s, int radix,
+ int lowerBound, int upperBound) throws NumberFormatException {
+
+ if (s == null) {
+ throw new NumberFormatException("null");
+ }
+ if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX) {
+ throw new NumberFormatException("radix " + radix + " out of range");
+ }
+
+ int length = s.length();
+ int startIndex = (length > 0) && (s.charAt(0) == '-') ? 1 : 0;
+
+ for (int i = startIndex; i < length; i++) {
+ if (Character.digit(s.charAt(i), radix) == -1) {
+ throw NumberFormatException.forInputString(s);
+ }
+ }
+
+ int toReturn = __parseInt(s, radix);
+ if (__isNaN(toReturn)) {
+ throw NumberFormatException.forInputString(s);
+ } else if (toReturn < lowerBound || toReturn > upperBound) {
+ throw NumberFormatException.forInputString(s);
+ }
+
return toReturn;
}
/**
* @skip
*/
- private static native boolean __isDoubleNaN(double x) /*-{
+ private static native boolean __isNaN(double x) /*-{
return isNaN(x);
}-*/;
/**
* @skip
- */
- private static native boolean __isLongNaN(long x) /*-{
- return isNaN(x);
- }-*/;
-
- /**
- * @skip
- *
- * Invokes the global JS function <code>parseInt()</code>.
- */
- private static native long __parseInt(String s, int radix) /*-{
- return parseInt(s, radix);
- }-*/;
-
- /**
- * @skip
- *
+ *
* @return The floating-point representation of <code>str</code> or
- * <code>Number.NaN</code> if the string does not match
- * {@link floatRegex}.
+ * <code>Number.NaN</code> if the string does not match
+ * {@link floatRegex}.
*/
private static native double __parseDouble(String str) /*-{
- if (@java.lang.Number::floatRegex.test(str)) {
+ var floatRegex = @java.lang.Number::floatRegex;
+ if (!floatRegex) {
+ floatRegex = @java.lang.Number::floatRegex = /^[+-]?\d*\.?\d*(e[+-]?\d+)?$/i;
+ }
+ if (floatRegex.test(str)) {
return parseFloat(str);
} else {
return Number.NaN;
}
}-*/;
- // CHECKSTYLE_ON
-
/**
- * Used by JSNI methods to report badly formatted strings.
- * @param s the unparseable string
- * @throws NumberFormatException every time
+ * @skip
+ *
+ * Invokes the global JS function <code>parseInt()</code>.
*/
- @SuppressWarnings("unused") // called by JSNI
- private static void throwNumberFormatException(String s)
- throws NumberFormatException {
- throw new NumberFormatException("Could not parse " + s);
- }
+ private static native int __parseInt(String s, int radix) /*-{
+ return parseInt(s, radix);
+ }-*/;
+
+ // CHECKSTYLE_ON
public abstract byte byteValue();
diff --git a/user/super/com/google/gwt/emul/java/lang/NumberFormatException.java b/user/super/com/google/gwt/emul/java/lang/NumberFormatException.java
index 7754e0b..c98608c 100644
--- a/user/super/com/google/gwt/emul/java/lang/NumberFormatException.java
+++ b/user/super/com/google/gwt/emul/java/lang/NumberFormatException.java
@@ -22,11 +22,14 @@
*/
public class NumberFormatException extends IllegalArgumentException {
+ static NumberFormatException forInputString(String s) {
+ return new NumberFormatException("For input string: \"" + s + "\"");
+ }
+
public NumberFormatException() {
}
public NumberFormatException(String message) {
super(message);
}
-
}
diff --git a/user/super/com/google/gwt/emul/java/lang/Short.java b/user/super/com/google/gwt/emul/java/lang/Short.java
index a570d95..a27fa68 100644
--- a/user/super/com/google/gwt/emul/java/lang/Short.java
+++ b/user/super/com/google/gwt/emul/java/lang/Short.java
@@ -24,11 +24,16 @@
public static final short MAX_VALUE = (short) 0x7fff;
public static final int SIZE = 16;
- // Box values according to JLS - between -128 and 127
- private static Short[] boxedValues = new Short[256];
+ /**
+ * Use nested class to avoid clinit on outer.
+ */
+ private static class BoxedValues {
+ // Box values according to JLS - between -128 and 127
+ private static Short[] boxedValues = new Short[256];
+ }
public static Short decode(String s) throws NumberFormatException {
- return new Short((short) __decodeAndValidateLong(s, MIN_VALUE, MAX_VALUE));
+ return new Short((short) __decodeAndValidateInt(s, MIN_VALUE, MAX_VALUE));
}
/**
@@ -44,7 +49,7 @@
public static short parseShort(String s, int radix)
throws NumberFormatException {
- return (short) __parseAndValidateLong(s, radix, MIN_VALUE, MAX_VALUE);
+ return (short) __parseAndValidateInt(s, radix, MIN_VALUE, MAX_VALUE);
}
public static short reverseBytes(short s) {
@@ -58,10 +63,11 @@
public static Short valueOf(short s) {
if (s > -129 && s < 128) {
int rebase = s + 128;
- if (boxedValues[rebase] == null) {
- boxedValues[rebase] = new Short(s);
+ Short result = BoxedValues.boxedValues[rebase];
+ if (result == null) {
+ result = BoxedValues.boxedValues[rebase] = new Short(s);
}
- return boxedValues[rebase];
+ return result;
}
return new Short(s);
}
diff --git a/user/super/com/google/gwt/emul/java/lang/System.java b/user/super/com/google/gwt/emul/java/lang/System.java
index 1811bee..9a2c21c 100644
--- a/user/super/com/google/gwt/emul/java/lang/System.java
+++ b/user/super/com/google/gwt/emul/java/lang/System.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2007 Google Inc.
+ * Copyright 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
@@ -84,18 +84,18 @@
nativeArraycopy(src, srcOfs, dest, destOfs, len);
}
}
-
- public static native long currentTimeMillis() /*-{
- return (new Date()).getTime();
- }-*/;
+
+ public static long currentTimeMillis() {
+ return (long) currentTimeMillis0();
+ };
/**
* Has no effect; just here for source compatibility.
*
* @skip
*/
- public static native void gc() /*-{
- }-*/;
+ public static void gc() {
+ };
public static native int identityHashCode(Object o) /*-{
return (o == null) ? 0 : @com.google.gwt.core.client.Impl::getHashCode(Ljava/lang/Object;)(o);
@@ -109,6 +109,10 @@
@java.lang.System::out = out;
}-*/;
+ private static native double currentTimeMillis0() /*-{
+ return (new Date()).getTime();
+ }-*/;
+
/**
* Returns the length of an array via Javascript.
*/
diff --git a/user/super/com/google/gwt/emul/java/util/Date.java b/user/super/com/google/gwt/emul/java/util/Date.java
index bc730e3..1b55c4a 100644
--- a/user/super/com/google/gwt/emul/java/util/Date.java
+++ b/user/super/com/google/gwt/emul/java/util/Date.java
@@ -36,15 +36,8 @@
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
};
- // CHECKSTYLE_OFF: The underscore prefix is an old convention that could be
- // easily replaced.
- public static native long __parse(String s) /*-{
- var d = Date.parse(s);
- return isNaN(d) ? -1 : d;
- }-*/;
-
public static long parse(String s) {
- long d = __parse(s);
+ long d = (long) parse0(s);
if (d != -1) {
return d;
} else {
@@ -53,10 +46,11 @@
}
// CHECKSTYLE_OFF: Matching the spec.
- public static native long UTC(int year, int month, int date, int hrs,
- int min, int sec) /*-{
- return Date.UTC(year + 1900, month, date, hrs, min, sec);
- }-*/;
+ public static long UTC(int year, int month, int date, int hrs,
+ int min, int sec) {
+ return (long) utc0(year, month, date, hrs, min, sec);
+ }
+ // CHECKSTYLE_ON
/**
* Return the names for the days of the week as specified by the Date
@@ -89,6 +83,16 @@
}
}
+ private static native double parse0(String s) /*-{
+ var d = Date.parse(s);
+ return isNaN(d) ? -1 : d;
+ }-*/;
+
+ private static native double utc0(int year, int month, int date, int hrs,
+ int min, int sec) /*-{
+ return Date.UTC(year + 1900, month, date, hrs, min, sec);
+ }-*/;
+
public Date() {
init();
}
@@ -166,9 +170,9 @@
return this.jsdate.getSeconds();
}-*/;
- public native long getTime() /*-{
- return this.jsdate.getTime();
- }-*/;
+ public long getTime() {
+ return (long) getTime0();
+ }
public native int getTimezoneOffset() /*-{
return this.jsdate.getTimezoneOffset();
@@ -199,17 +203,13 @@
this.jsdate.setMonth(month);
}-*/;
- // CHECKSTYLE_ON
-
public native void setSeconds(int seconds) /*-{
this.jsdate.setSeconds(seconds);
- }-*/;;
-
- public native void setTime(long time) /*-{
- this.jsdate.setTime(time);
}-*/;
- // CHECKSTYLE_ON
+ public void setTime(long time) {
+ setTime0(time);
+ }
public native void setYear(int year) /*-{
this.jsdate.setFullYear(year + 1900);
@@ -259,10 +259,18 @@
+ " " + d.getFullYear();
}-*/;
+ private native double getTime0() /*-{
+ return this.jsdate.getTime();
+ }-*/;
+
private native void init() /*-{
this.jsdate = new Date();
}-*/;
+ private native void init(double date) /*-{
+ this.jsdate = new Date(date);
+ }-*/;
+
private native void init(int year, int month, int date, int hrs, int min,
int sec) /*-{
this.jsdate = new Date();
@@ -270,7 +278,7 @@
this.jsdate.setHours(hrs, min, sec, 0);
}-*/;
- private native void init(long date) /*-{
- this.jsdate = new Date(date);
+ private native void setTime0(double time) /*-{
+ this.jsdate.setTime(time);
}-*/;
}
diff --git a/user/test/com/google/gwt/dev/jjs/test/HostedTest.java b/user/test/com/google/gwt/dev/jjs/test/HostedTest.java
index 9df5500..6359842 100644
--- a/user/test/com/google/gwt/dev/jjs/test/HostedTest.java
+++ b/user/test/com/google/gwt/dev/jjs/test/HostedTest.java
@@ -148,6 +148,10 @@
return val;
}-*/;
+ private static native long passThroughLong(long val) /*-{
+ return val;
+ }-*/;
+
private static native String sFooCall(String s) /*-{
var func = @com.google.gwt.dev.jjs.test.HostedTest::sFoo(Ljava/lang/String;);
return func.call(null, s);
@@ -393,8 +397,7 @@
public void testLongMarshalling() {
// a big number that cannot accurately be represented as a double
long l = 1234567890123456789L;
- double d = l;
- assertTrue(isEq(l, d));
+ assertEquals(l, passThroughLong(l));
}
/*
@@ -511,10 +514,6 @@
return this.@com.google.gwt.dev.jjs.test.HostedTest::foo(Ljava/lang/String;);
}-*/;
- private native boolean isEq(long l, double d) /*-{
- return l == d;
- }-*/;
-
private native void jsniA()/*-{}-*/;
private native void jsniB()/*-{
diff --git a/user/test/com/google/gwt/dev/jjs/test/NativeLongTest.java b/user/test/com/google/gwt/dev/jjs/test/NativeLongTest.java
index 3c3b692..3d2aabd 100644
--- a/user/test/com/google/gwt/dev/jjs/test/NativeLongTest.java
+++ b/user/test/com/google/gwt/dev/jjs/test/NativeLongTest.java
@@ -18,38 +18,166 @@
import com.google.gwt.junit.client.GWTTestCase;
/**
- * TODO: document me.
+ * Test direct uses of longs. Mostly this tests that LongLib is in fact being
+ * invoked in various cases. The behavior of LongLib itself is tested in
+ * LongLibTest.
*/
public class NativeLongTest extends GWTTestCase {
+ /*
+ * These silly looking constants are made into public fields so that the
+ * compiler will not constant fold them. The problem is that if you write
+ * assertEquals(2L, 4L/2L), the compiler will emit assertEquals(2L, 2L).
+ */
+ private static long LONG_1234 = 0x1234123412341234L;
+ private static long LONG_1234_DECIMAL = 1234123412341234L;
+ private static long LONG_1234000012340000 = 0x1234000012340000L;
+ private static long LONG_5DEECE66D = 0x5DEECE66DL;
+ private static long LONG_B = 0xBL;
+ private static long LONG_DEADBEEF = 0xdeadbeefdeadbeefL;
+ private static long LONG_DEADBEEF12341234 = 0xdeadbeef12341234L;
+ private static long LONG_FFFFFFFF = 0xFFFFFFFFL;
+ private static long LONG_ONE = 1L;
+ private static long LONG_THREE = 3L;
+ private static long LONG_TWO = 2L;
+ private static long LONG_TWO_PWR_32 = 0x100000000L;
+ private static long LONG_ZERO = 0L;
+ @Override
public String getModuleName() {
return "com.google.gwt.dev.jjs.CompilerSuite";
}
+ @Override
+ public void setUp() {
+ pretendToChangeTheConstants();
+ }
+
+ public void testArithmetic() {
+ assertEquals(-1089359682551557853L, LONG_1234 + LONG_DEADBEEF);
+ assertEquals(5024439901525534073L, 2 * LONG_1234 - LONG_DEADBEEF);
+ assertEquals(2476047018506819212L, LONG_1234 * LONG_DEADBEEF);
+ assertEquals(-240105308887621659L, LONG_DEADBEEF / 10);
+ assertEquals(-1089359682551557853L, LONG_DEADBEEF % LONG_1234);
+ }
+
+ public void testCasts() {
+ assertEquals(0x12341234, (int) LONG_1234);
+ assertEquals(0x1234, (short) LONG_1234);
+ }
+
public void testConstants() {
- assertEquals(0x5DEECE66DL, 0x5DEECE66DL);
- assertTrue(0x5DEECE66DL > 0L);
- assertTrue(0L < 0x5DEECE66DL);
- assertEquals(0xBL, 0xBL);
- assertTrue(0xBL > 0L);
- assertTrue(0L < 0xBL);
+ assertEquals(LONG_5DEECE66D, LONG_5DEECE66D);
+ assertTrue(LONG_5DEECE66D > 0L);
+ assertTrue(0L < LONG_5DEECE66D);
+ assertEquals(LONG_B, LONG_B);
+ assertTrue(LONG_B > 0L);
+ assertTrue(0L < LONG_B);
+ }
+
+ public void testFor64Bits() {
+ long x = LONG_1234;
+ pretendToChangeTheConstants();
+ long y = LONG_1234 + LONG_ONE;
+ long z = y - x;
+ // with longs implemented as doubles, z will be 0 instead of 1
+ assertEquals(1L, z);
+ }
+
+ public void testImplicitCastFromLong() {
+ double d = LONG_ONE;
+ d += LONG_TWO;
+ assertEquals(0.0, 3L, d);
+ assertTrue(3L == d);
+
+ float f = LONG_ONE;
+ f += LONG_TWO;
+ assertEquals(0.0, 3L, f);
+ assertTrue(3L == f);
+ }
+
+ public void testImplicitCastToLong() {
+ long l = 10;
+ l += 5;
+ assertEquals(15, l);
+ assertTrue(15 == l);
+ }
+
+ public void testModifyingOps() {
+ long l = 20;
+ l += 10;
+ assertEquals(31, ++l);
+ assertEquals(31, l++);
+ assertEquals(32, l);
}
public void testLogicalAnd() {
- assertEquals(1L & 0L, 0L);
- assertEquals(1L & 3L, 1L);
+ assertEquals(LONG_1234, LONG_1234 & -LONG_ONE);
+ assertEquals(0x12341234L, LONG_1234 & LONG_FFFFFFFF);
+ assertEquals(0L, LONG_ONE & LONG_ZERO);
+ assertEquals(1L, LONG_ONE & LONG_THREE);
+ }
+
+ public void testLogicalOr() {
+ assertEquals(-1L, LONG_1234 | -LONG_ONE);
+ assertEquals(0x12341234FFFFFFFFL, LONG_1234 | LONG_FFFFFFFF);
+ assertEquals(1L, LONG_ONE | LONG_ZERO);
+ assertEquals(3L, LONG_ONE | LONG_THREE);
+ }
+
+ public void testLogicalXor() {
+ assertTrue((255L ^ LONG_5DEECE66D) != 0);
+
+ assertEquals(0L, LONG_1234 ^ LONG_1234);
+ assertEquals(0x0000123400001234L, LONG_1234 ^ LONG_1234000012340000);
+ assertEquals(1L, LONG_ONE ^ LONG_ZERO);
+ assertEquals(2L, LONG_ONE ^ LONG_THREE);
}
public void testShift() {
- assertEquals(0x5DEECE66DL, 0x5DEECE66DL & ((1L << 48) - 1));
+ assertEquals(LONG_5DEECE66D, LONG_5DEECE66D & ((LONG_ONE << 48) - 1));
+ assertEquals(LONG_ONE << 12, (LONG_ONE << 60) >>> (48));
+
+ assertTrue((LONG_ONE << 35) > (LONG_ONE << 30));
+
+ assertEquals(1L, LONG_TWO_PWR_32 >> 32);
+ assertEquals(1L, LONG_TWO_PWR_32 >>> 32);
}
- public void testTripleShift() {
- assertEquals(1 << 12, (1 << 60) >>> (48));
+ // Issue 1198
+ public void testToHexString() {
+ assertEquals("deadbeef12341234", Long.toHexString(LONG_DEADBEEF12341234));
}
- public void testXor() {
- assertTrue((255L ^ 0x5DEECE66DL) != 0);
+ public void testToString() {
+ assertEquals("1234123412341234", "" + LONG_1234_DECIMAL);
}
+ /**
+ * This method tries to trick the compiler into thinking the global constants
+ * are not fixed.
+ */
+ private void pretendToChangeTheConstants() {
+ int i = 10;
+ while (i > 1) {
+ i /= 2;
+ }
+ if (i == 1) {
+ return;
+ }
+
+ // not reached
+ ++LONG_1234;
+ ++LONG_1234_DECIMAL;
+ ++LONG_1234000012340000;
+ ++LONG_5DEECE66D;
+ ++LONG_B;
+ ++LONG_DEADBEEF;
+ ++LONG_DEADBEEF12341234;
+ ++LONG_FFFFFFFF;
+ ++LONG_ONE;
+ ++LONG_THREE;
+ ++LONG_TWO;
+ ++LONG_TWO_PWR_32;
+ ++LONG_ZERO;
+ }
}
diff --git a/user/test/com/google/gwt/emultest/EmulSuite.java b/user/test/com/google/gwt/emultest/EmulSuite.java
index 6f11f17..7186c61 100644
--- a/user/test/com/google/gwt/emultest/EmulSuite.java
+++ b/user/test/com/google/gwt/emultest/EmulSuite.java
@@ -21,6 +21,7 @@
import com.google.gwt.emultest.java.lang.DoubleTest;
import com.google.gwt.emultest.java.lang.FloatTest;
import com.google.gwt.emultest.java.lang.IntegerTest;
+import com.google.gwt.emultest.java.lang.LongTest;
import com.google.gwt.emultest.java.lang.ObjectTest;
import com.google.gwt.emultest.java.lang.ShortTest;
import com.google.gwt.emultest.java.lang.StringBufferTest;
@@ -56,6 +57,7 @@
suite.addTestSuite(CharacterTest.class);
suite.addTestSuite(DoubleTest.class);
suite.addTestSuite(FloatTest.class);
+ suite.addTestSuite(LongTest.class);
suite.addTestSuite(IntegerTest.class);
suite.addTestSuite(ObjectTest.class);
suite.addTestSuite(ShortTest.class);
diff --git a/user/test/com/google/gwt/emultest/java/lang/IntegerTest.java b/user/test/com/google/gwt/emultest/java/lang/IntegerTest.java
index e33cf6e..3f34e83 100644
--- a/user/test/com/google/gwt/emultest/java/lang/IntegerTest.java
+++ b/user/test/com/google/gwt/emultest/java/lang/IntegerTest.java
@@ -142,7 +142,7 @@
assertEquals(Integer.MIN_VALUE, Integer.highestOneBit(-1));
assertEquals(Integer.MIN_VALUE, Integer.highestOneBit(-256));
assertEquals(1, Integer.highestOneBit(1));
- assertEquals(0x80, Integer.highestOneBit(0x80));
+ assertEquals(0x80, Integer.highestOneBit(0x88));
assertEquals(0x40000000, Integer.highestOneBit(Integer.MAX_VALUE));
}
@@ -151,7 +151,7 @@
assertEquals(1, Integer.lowestOneBit(-1));
assertEquals(0x100, Integer.lowestOneBit(-256));
assertEquals(1, Integer.lowestOneBit(1));
- assertEquals(0x80, Integer.lowestOneBit(0x80));
+ assertEquals(0x80, Integer.lowestOneBit(0x880));
assertEquals(0x80000000, Integer.lowestOneBit(Integer.MIN_VALUE));
}
@@ -181,6 +181,11 @@
assertEquals(Integer.MIN_VALUE, Integer.reverse(1));
assertEquals(1, Integer.reverse(Integer.MIN_VALUE));
assertEquals(0xaaaaaaaa, Integer.reverse(0x55555555));
+ assertEquals(0xaaaa0000, Integer.reverse(0x00005555));
+ assertEquals(0xaa00aa00, Integer.reverse(0x00550055));
+ assertEquals(0x55555555, Integer.reverse(0xaaaaaaaa));
+ assertEquals(0x00005555, Integer.reverse(0xaaaa0000));
+ assertEquals(0x00550055, Integer.reverse(0xaa00aa00));
}
public void testReverseBytes() {
@@ -222,7 +227,8 @@
}
public void testToHexString() {
- // TODO: not implemented in our JRE
+ assertEquals("12345", Integer.toHexString(0x12345));
+ assertEquals("fff12345", Integer.toHexString(0xFFF12345));
}
public void testToString() {
diff --git a/user/test/com/google/gwt/emultest/java/lang/LongTest.java b/user/test/com/google/gwt/emultest/java/lang/LongTest.java
new file mode 100644
index 0000000..12b5f70
--- /dev/null
+++ b/user/test/com/google/gwt/emultest/java/lang/LongTest.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2007 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.emultest.java.lang;
+
+import com.google.gwt.junit.client.GWTTestCase;
+
+/**
+ * TODO: document me.
+ */
+public class LongTest extends GWTTestCase {
+
+ public String getModuleName() {
+ return "com.google.gwt.emultest.EmulSuite";
+ }
+
+ public void testBinaryString() {
+ assertEquals("10001111101101101111011110001100100000000",
+ Long.toBinaryString(1234500000000L));
+ assertEquals("0", Long.toBinaryString(0L));
+ assertEquals(
+ "1111111111111111111111101110000010010010000100001110011100000000",
+ Long.toBinaryString(-1234500000000L));
+ }
+
+ public void testBitCount() {
+ assertEquals(0, Long.bitCount(0));
+ assertEquals(1, Long.bitCount(1));
+ assertEquals(64, Long.bitCount(-1));
+ assertEquals(63, Long.bitCount(Long.MAX_VALUE));
+ assertEquals(1, Long.bitCount(Long.MIN_VALUE));
+ }
+
+ public void testConstants() {
+ assertEquals(64, Long.SIZE);
+ assertEquals(0x7fffffffffffffffL, Long.MAX_VALUE);
+ assertEquals(0x8000000000000000L, Long.MIN_VALUE);
+ }
+
+ public void testHighestOneBit() {
+ assertEquals(0, Long.highestOneBit(0));
+ assertEquals(Long.MIN_VALUE, Long.highestOneBit(-1));
+ assertEquals(Long.MIN_VALUE, Long.highestOneBit(-256));
+ assertEquals(1, Long.highestOneBit(1));
+ assertEquals(0x80, Long.highestOneBit(0x88));
+ assertEquals(0x4000000000000000L, Long.highestOneBit(Long.MAX_VALUE));
+ }
+
+ public void testLowestOneBit() {
+ assertEquals(0, Long.lowestOneBit(0));
+ assertEquals(1, Long.lowestOneBit(-1));
+ assertEquals(0x100, Long.lowestOneBit(-256));
+ assertEquals(1, Long.lowestOneBit(1));
+ assertEquals(0x80, Long.lowestOneBit(0x780));
+ assertEquals(Long.MIN_VALUE, Long.lowestOneBit(Long.MIN_VALUE));
+ }
+
+ public void testNumberOfLeadingZeros() {
+ assertEquals(64, Long.numberOfLeadingZeros(0));
+ assertEquals(63, Long.numberOfLeadingZeros(1));
+ assertEquals(0, Long.numberOfLeadingZeros(-1));
+ assertEquals(32, Long.numberOfLeadingZeros(0x80000000L));
+ assertEquals(1, Long.numberOfLeadingZeros(Long.MAX_VALUE));
+ assertEquals(0, Long.numberOfLeadingZeros(Long.MIN_VALUE));
+ assertEquals(0, Long.numberOfLeadingZeros(-0x80000000L));
+ }
+
+ public void testNumberOfTrailingZeros() {
+ assertEquals(64, Long.numberOfTrailingZeros(0));
+ assertEquals(0, Long.numberOfTrailingZeros(1));
+ assertEquals(0, Long.numberOfTrailingZeros(-1));
+ assertEquals(31, Long.numberOfTrailingZeros(0x80000000L));
+ assertEquals(0, Long.numberOfTrailingZeros(Long.MAX_VALUE));
+ assertEquals(63, Long.numberOfTrailingZeros(Long.MIN_VALUE));
+ assertEquals(20, Long.numberOfTrailingZeros(-0x7ff00000L));
+ }
+
+ public void testReverse() {
+ assertEquals(0L, Long.reverse(0L));
+ assertEquals(-1L, Long.reverse(-1L));
+ assertEquals(Long.MIN_VALUE, Long.reverse(1L));
+ assertEquals(1L, Long.reverse(Long.MIN_VALUE));
+ assertEquals(0xaaaaaaaaaaaaaaaaL, Long.reverse(0x5555555555555555L));
+ assertEquals(0xaaaaaaaa00000000L, Long.reverse(0x55555555L));
+ assertEquals(0xaa00aa00aa00aa00L, Long.reverse(0x0055005500550055L));
+ assertEquals(0x5555555555555555L, Long.reverse(0xaaaaaaaaaaaaaaaaL));
+ assertEquals(0x55555555L, Long.reverse(0xaaaaaaaa00000000L));
+ assertEquals(0x0055005500550055L, Long.reverse(0xaa00aa00aa00aa00L));
+ }
+
+ public void testReverseBytes() {
+ }
+
+ public void testRotateLeft() {
+ assertEquals(0, Long.rotateLeft(0, 4));
+ assertEquals(0x2, Long.rotateLeft(1, 1));
+ assertEquals(0x10, Long.rotateLeft(1, 4));
+ assertEquals(-1, Long.rotateLeft(-1, 4));
+ assertEquals(Long.MIN_VALUE, Long.rotateLeft(0x4000000000000000L, 1));
+ assertEquals(1, Long.rotateLeft(Long.MIN_VALUE, 1));
+ }
+
+ public void testRotateRight() {
+ assertEquals(0, Long.rotateRight(0, 4));
+ assertEquals(Long.MIN_VALUE, Long.rotateRight(1, 1));
+ assertEquals(0x1000000000000000L, Long.rotateRight(1, 4));
+ assertEquals(-1, Long.rotateRight(-1, 4));
+ }
+
+ public void testSignum() {
+ assertEquals(0, Long.signum(0));
+ assertEquals(1, Long.signum(1));
+ assertEquals(-1, Long.signum(-1));
+ assertEquals(1, Long.signum(Long.MAX_VALUE));
+ assertEquals(-1, Long.signum(Long.MIN_VALUE));
+ }
+
+ public void testStaticValueOf() {
+ assertEquals(Long.MIN_VALUE, Long.valueOf(Long.MIN_VALUE).longValue());
+ assertEquals(Long.MAX_VALUE, Long.valueOf(Long.MAX_VALUE).longValue());
+ }
+
+ public void testToHexString() {
+ assertEquals("1234500000000", Long.toHexString(0x1234500000000L));
+ assertEquals("fff1234500000000", Long.toHexString(0xFFF1234500000000L));
+ }
+}
diff --git a/user/test/com/google/gwt/emultest/java/util/DateTest.java b/user/test/com/google/gwt/emultest/java/util/DateTest.java
index d4753de..3dc1240 100644
--- a/user/test/com/google/gwt/emultest/java/util/DateTest.java
+++ b/user/test/com/google/gwt/emultest/java/util/DateTest.java
@@ -1,12 +1,12 @@
/*
- * Copyright 2007 Google Inc.
- *
+ * Copyright 2008 Google Inc.
+ *
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
@@ -20,23 +20,25 @@
import java.util.Date;
/**
- * Tests for GWT's emulation of the JRE Date class.
+ * Tests for GWT's emulation of the JRE Date class.
*/
+@SuppressWarnings("deprecation")
public class DateTest extends GWTTestCase {
public static final String CURRENT = "CURRENT";
- public static final String TO_STRING_PATTERN =
- "\\w{3} \\w{3} \\d{2} \\d{2}:\\d{2}:\\d{2}( .+)? \\d{4}";
+ public static final String TO_STRING_PATTERN = "\\w{3} \\w{3} \\d{2} \\d{2}:\\d{2}:\\d{2}( .+)? \\d{4}";
public static final long DAY_MILLISECONDS_SHIFT = 27;
public static final String FUTURE = "FUTURE";
public static final String PAST = "PAST";
public static final long SECOND_MILLISECONDS_SHIFT = 10;
- /** Sets module name so that javascript compiler can operate */
+ /**
+ * Sets module name so that javascript compiler can operate.
+ */
public String getModuleName() {
return "com.google.gwt.emultest.EmulSuite";
}
- /** Testing for public boolean java.util.Date.after(java.util.Date)* */
+ /** Testing for public boolean java.util.Date.after(java.util.Date). */
public void testAfter() {
// /////////////////////////////
@@ -63,7 +65,7 @@
assertTrue(a2);
}
- /** Testing for public boolean java.util.Date.before(java.util.Date)* */
+ /** Testing for public boolean java.util.Date.before(java.util.Date). */
public void testBefore() {
// /////////////////////////////
@@ -90,7 +92,7 @@
assertFalse(a2);
}
- /** Testing for public java.lang.Object java.util.Date.clone()* */
+ /** Testing for public java.lang.Object java.util.Date.clone(). */
public void testClone() {
// /////////////////////////////
@@ -117,7 +119,7 @@
assertEquals(a2, accum2);
}
- /** Testing for public int java.util.Date.compareTo(java.util.Date)* */
+ /** Testing for public int java.util.Date.compareTo(java.util.Date). */
public void testCompareTo() {
// /////////////////////////////
@@ -143,7 +145,7 @@
assertEquals(a2, -1);
}
- /** Testing for public int java.util.Date.getDate()* */
+ /** Testing for public int java.util.Date.getDate(). */
public void testGetDate() {
// /////////////////////////////
@@ -160,7 +162,7 @@
assertEquals(29, a2);
}
- /** Testing for public int java.util.Date.getDay()* */
+ /** Testing for public int java.util.Date.getDay(). */
public void testGetDay() {
// /////////////////////////////
@@ -182,15 +184,13 @@
int a2 = accum2.getDay();
}
- /**
- * Testing for public int java.util.Date.getHours()
- */
+ /** Testing for public int java.util.Date.getHours(). */
public void testGetHours() {
// Cannot be done because each time zone will give a different
// answer
}
- /** Testing for public int java.util.Date.getMinutes()* */
+ /** Testing for public int java.util.Date.getMinutes(). */
public void testGetMinutes() {
// /////////////////////////////
@@ -207,7 +207,7 @@
assertEquals(a2, 4);
}
- /** Testing for public int java.util.Date.getMonth()* */
+ /** Testing for public int java.util.Date.getMonth(). */
public void testGetMonth() {
// /////////////////////////////
@@ -225,7 +225,7 @@
assertEquals(11, a2);
}
- /** Testing for public int java.util.Date.getSeconds()* */
+ /** Testing for public int java.util.Date.getSeconds(). */
public void testGetSeconds() {
// /////////////////////////////
@@ -243,7 +243,7 @@
assertEquals(5, a2);
}
- /** Testing for public long java.util.Date.getTime()* */
+ /** Testing for public long java.util.Date.getTime(). */
public void testGetTime() {
// /////////////////////////////
@@ -261,7 +261,7 @@
assertEquals(1293678245000L, a2);
}
- /** Testing for public int java.util.Date.getTimezoneOffset()* */
+ /** Testing for public int java.util.Date.getTimezoneOffset(). */
public void testGetTimezoneOffset() {
// /////////////////////////////
@@ -283,7 +283,7 @@
int a2 = accum2.getTimezoneOffset();
}
- /** Testing for public int java.util.Date.getYear()* */
+ /** Testing for public int java.util.Date.getYear(). */
public void testGetYear() {
// /////////////////////////////
@@ -301,7 +301,7 @@
assertEquals(110, a2);
}
- /** Testing for public static long java.util.Date.parse(java.lang.String)* */
+ /** Testing for public static long java.util.Date.parse(java.lang.String). */
public void testParse() {
// /////////////////////////////
@@ -328,7 +328,7 @@
assertEquals(1293678245000L, a2);
}
- /** Testing for public void java.util.Date.setDate(int)* */
+ /** Testing for public void java.util.Date.setDate(int). */
public void testSetDate() {
// We only go through dates from 0-28 here. There are some months that do
// not
@@ -357,7 +357,7 @@
assertEquals(dateWithThirtyDays.getDate(), newDayNum - numDaysInOldMonth);
}
- /** Testing for public void java.util.Date.setHours(int)* */
+ /** Testing for public void java.util.Date.setHours(int). */
public void testSetHours() {
for (int i = 0; i < 24; i++) {
Date accum0 = create();
@@ -366,7 +366,7 @@
}
}
- /** Testing for public void java.util.Date.setMinutes(int)* */
+ /** Testing for public void java.util.Date.setMinutes(int). */
public void testSetMinutes() {
for (int i = 0; i < 24; i++) {
Date accum0 = create();
@@ -375,7 +375,7 @@
}
}
- /** Testing for public void java.util.Date.setMonth(int)* */
+ /** Testing for public void java.util.Date.setMonth(int). */
public void testSetMonth() {
for (int i = 0; i < 12; i++) {
// We want to use a fixed date here. If we use the current date, the
@@ -393,7 +393,7 @@
* We want to test to see that if we are currently in a month with 31 days and
* we set the month to one which has less than 31 days, that the month
* returned by the date class will be one higher than the month that we
- * originally set (according to the spec of java.util.date)
+ * originally set (according to the spec of java.util.date).
*/
public void testSetInvalidMonthForDate() {
int dayNum = 31;
@@ -405,7 +405,7 @@
assertEquals(dateWithThirtyOneDays.getDate(), dayNum - numDaysInNewMonth);
}
- /** Testing for public void java.util.Date.setSeconds(int)* */
+ /** Testing for public void java.util.Date.setSeconds(int). */
public void testSetSeconds() {
for (int i = 0; i < 24; i++) {
Date accum0 = create();
@@ -414,7 +414,7 @@
}
}
- /** Testing for public void java.util.Date.setTime(long)* */
+ /** Testing for public void java.util.Date.setTime(long). */
public void testSetTime() {
long[] values = new long[] {-100000000000L, -100L, 0, 100L, 1000000000L};
for (int i = 0; i < values.length; i++) {
@@ -424,7 +424,7 @@
}
}
- /** Testing for public void java.util.Date.setYear(int)* */
+ /** Testing for public void java.util.Date.setYear(int). */
public void testSetYear() {
for (int i = 1880; i < 2050; i++) {
// We want to use a fixed date here. If we use the current date, the
@@ -455,7 +455,7 @@
/**
* We want to test to see that if the date is Feb 29th (in a leap year) and we
- * set the year to another leap year, that the month and day will be retained
+ * set the year to another leap year, that the month and day will be retained.
*/
public void testSetValidLeapYearForDate() {
int dayNum = 29;
@@ -469,7 +469,7 @@
assertEquals(leapYearDate.getDate(), dayNum);
}
- /** Testing for public java.lang.String java.util.Date.toGMTString()* */
+ /** Testing for public java.lang.String java.util.Date.toGMTString(). */
public void testToGMTString() {
// /////////////////////////////
@@ -487,7 +487,7 @@
assertEquals("30 Dec 2010 03:04:05 GMT", a2);
}
- /** Testing for public java.lang.String java.util.Date.toLocaleString()* */
+ /** Testing for public java.lang.String java.util.Date.toLocaleString(). */
public void testToLocaleString() {
// /////////////////////////////
@@ -504,7 +504,7 @@
assertTrue(a2.indexOf("2010") != -1);
}
- /** Date docs specify an exact format for toString() */
+ /** Date docs specify an exact format for toString(). */
public void testToString() {
// /////////////////////////////
// Past
@@ -513,8 +513,8 @@
String s = d.toString();
assertTrue("Bad format " + s, s.matches(TO_STRING_PATTERN));
- assertEquals("Parsing returned unequal dates from " + s,
- d, new Date(Date.parse(s)));
+ assertEquals("Parsing returned unequal dates from " + s, d, new Date(
+ Date.parse(s)));
// /////////////////////////////
// Future
@@ -523,11 +523,11 @@
s = d.toString();
assertTrue("Bad format " + s, s.matches(TO_STRING_PATTERN));
- assertEquals("Parsing returned unequal dates from " + s,
- d, new Date(Date.parse(s)));
+ assertEquals("Parsing returned unequal dates from " + s, d, new Date(
+ Date.parse(s)));
}
- /** Testing for public static long java.util.Date.UTC(int,int,int,int,int,int)* */
+ /** Testing for public static long java.util.Date.UTC(int,int,int,int,int,int). */
public void testUTC() {
// /////////////////////////////
diff --git a/user/test/com/google/gwt/i18n/client/NumberFormat_fr_Test.java b/user/test/com/google/gwt/i18n/client/NumberFormat_fr_Test.java
index 33ca691..fcc5abc 100644
--- a/user/test/com/google/gwt/i18n/client/NumberFormat_fr_Test.java
+++ b/user/test/com/google/gwt/i18n/client/NumberFormat_fr_Test.java
@@ -34,9 +34,8 @@
* Add as many tests as you like.
*/
public void testBasicFormat() {
- String str = NumberFormat.getFormat("0.0000").format(
- 123.45789179565757f);
- assertTrue(str.equals("123,4579"));
+ String str = NumberFormat.getFormat("0.0000").format(123.45789179565757f);
+ assertEquals("123,4579", str);
}
public void testCurrency() {
@@ -44,214 +43,212 @@
str = NumberFormat.getFormat("\u00a4#,##0.00;-\u00a4#,##0.00").format(
1234.56);
- assertTrue(str.equals("\u20AC1\u00A0234,56"));
+ assertEquals("\u20AC1\u00A0234,56", str);
str = NumberFormat.getFormat("\u00a4#,##0.00;-\u00a4#,##0.00").format(
-1234.56);
- assertTrue(str.equals("-\u20AC1\u00A0234,56"));
+ assertEquals("-\u20AC1\u00A0234,56", str);
- str = NumberFormat.getFormat(
- "\u00a4\u00a4 #,##0.00;-\u00a4\u00a4 #,##0.00").format(1234.56);
- assertTrue(str.equals("EUR 1\u00A0234,56"));
- str = NumberFormat.getFormat(
- "\u00a4\u00a4 #,##0.00;\u00a4\u00a4 -#,##0.00").format(-1234.56);
- assertTrue(str.equals("EUR -1\u00A0234,56"));
+ str = NumberFormat.getFormat("\u00a4\u00a4 #,##0.00;-\u00a4\u00a4 #,##0.00").format(
+ 1234.56);
+ assertEquals("EUR 1\u00A0234,56", str);
+ str = NumberFormat.getFormat("\u00a4\u00a4 #,##0.00;\u00a4\u00a4 -#,##0.00").format(
+ -1234.56);
+ assertEquals("EUR -1\u00A0234,56", str);
NumberFormat formatter = NumberFormat.getFormat(
"\u00a4#,##0.00;-\u00a4#,##0.00", "BRL");
str = formatter.format(1234.56);
- assertTrue(str.equals("R$1\u00A0234,56"));
+ assertEquals("R$1\u00A0234,56", str);
str = formatter.format(-1234.56);
- assertTrue(str.equals("-R$1\u00A0234,56"));
+ assertEquals("-R$1\u00A0234,56", str);
formatter = NumberFormat.getFormat(
"\u00a4\u00a4 #,##0.00;(\u00a4\u00a4 #,##0.00)", "BRL");
str = formatter.format(1234.56);
- assertTrue(str.equals("BRL 1\u00A0234,56"));
+ assertEquals("BRL 1\u00A0234,56", str);
str = formatter.format(-1234.56);
- assertTrue(str.equals("(BRL 1\u00A0234,56)"));
+ assertEquals("(BRL 1\u00A0234,56)", str);
}
public void testExponential() {
String str;
str = NumberFormat.getFormat("0.####E0").format(0.01234);
- assertTrue(str.equals("1,234E-2"));
+ assertEquals("1,234E-2", str);
str = NumberFormat.getFormat("00.000E00").format(0.01234);
- assertTrue(str.equals("12,340E-03"));
+ assertEquals("12,340E-03", str);
str = NumberFormat.getFormat("##0.######E000").format(0.01234);
- assertTrue(str.equals("12,34E-003"));
+ assertEquals("12,34E-003", str);
str = NumberFormat.getFormat("0.###E0;[0.###E0]").format(0.01234);
- assertTrue(str.equals("1,234E-2"));
+ assertEquals("1,234E-2", str);
str = NumberFormat.getFormat("0.####E0").format(123456789);
- assertTrue(str.equals("1,2346E8"));
+ assertEquals("1,2346E8", str);
str = NumberFormat.getFormat("00.000E00").format(123456789);
- assertTrue(str.equals("12,346E07"));
+ assertEquals("12,346E07", str);
str = NumberFormat.getFormat("##0.######E000").format(123456789);
- assertTrue(str.equals("123,456789E006"));
+ assertEquals("123,456789E006", str);
str = NumberFormat.getFormat("0.###E0;[0.###E0]").format(123456789);
- assertTrue(str.equals("1,235E8"));
+ assertEquals("1,235E8", str);
str = NumberFormat.getFormat("0.####E0").format(1.23e300);
- assertTrue(str.equals("1,23E300"));
+ assertEquals("1,23E300", str);
str = NumberFormat.getFormat("00.000E00").format(1.23e300);
- assertTrue(str.equals("12,300E299"));
+ assertEquals("12,300E299", str);
str = NumberFormat.getFormat("##0.######E000").format(1.23e300);
- assertTrue(str.equals("1,23E300"));
+ assertEquals("1,23E300", str);
str = NumberFormat.getFormat("0.###E0;[0.###E0]").format(1.23e300);
- assertTrue(str.equals("1,23E300"));
+ assertEquals("1,23E300", str);
str = NumberFormat.getFormat("0.####E0").format(-3.141592653e-271);
- assertTrue(str.equals("-3,1416E-271"));
+ assertEquals("-3,1416E-271", str);
str = NumberFormat.getFormat("00.000E00").format(-3.141592653e-271);
- assertTrue(str.equals("-31,416E-272"));
- str = NumberFormat.getFormat("##0.######E000").format(
- -3.141592653e-271);
- assertTrue(str.equals("-314,159265E-273"));
- str = NumberFormat.getFormat("0.###E0;[0.###E0]").format(
- -3.141592653e-271);
- assertTrue(str.equals("[3,142E-271]"));
+ assertEquals("-31,416E-272", str);
+ str = NumberFormat.getFormat("##0.######E000").format(-3.141592653e-271);
+ assertEquals("-314,159265E-273", str);
+ str = NumberFormat.getFormat("0.###E0;[0.###E0]").format(-3.141592653e-271);
+ assertEquals("[3,142E-271]", str);
str = NumberFormat.getFormat("0.####E0").format(0);
- assertTrue(str.equals("0E0"));
+ assertEquals("0E0", str);
str = NumberFormat.getFormat("00.000E00").format(0);
- assertTrue(str.equals("00,000E00"));
+ assertEquals("00,000E00", str);
str = NumberFormat.getFormat("##0.######E000").format(0);
- assertTrue(str.equals("0E000"));
+ assertEquals("0E000", str);
str = NumberFormat.getFormat("0.###E0;[0.###E0]").format(0);
- assertTrue(str.equals("0E0"));
+ assertEquals("0E0", str);
str = NumberFormat.getFormat("0.####E0").format(-1);
- assertTrue(str.equals("-1E0"));
+ assertEquals("-1E0", str);
str = NumberFormat.getFormat("00.000E00").format(-1);
- assertTrue(str.equals("-10,000E-01"));
+ assertEquals("-10,000E-01", str);
str = NumberFormat.getFormat("##0.######E000").format(-1);
- assertTrue(str.equals("-1E000"));
+ assertEquals("-1E000", str);
str = NumberFormat.getFormat("0.###E0;[0.###E0]").format(-1);
- assertTrue(str.equals("[1E0]"));
+ assertEquals("[1E0]", str);
str = NumberFormat.getFormat("0.####E0").format(1);
- assertTrue(str.equals("1E0"));
+ assertEquals("1E0", str);
str = NumberFormat.getFormat("00.000E00").format(1);
- assertTrue(str.equals("10,000E-01"));
+ assertEquals("10,000E-01", str);
str = NumberFormat.getFormat("##0.######E000").format(1);
- assertTrue(str.equals("1E000"));
+ assertEquals("1E000", str);
str = NumberFormat.getFormat("0.###E0;[0.###E0]").format(1);
- assertTrue(str.equals("1E0"));
+ assertEquals("1E0", str);
str = NumberFormat.getFormat("#E0").format(12345.0);
- assertTrue(str.equals("1E4"));
+ assertEquals("1E4", str);
str = NumberFormat.getFormat("0E0").format(12345.0);
- assertTrue(str.equals("1E4"));
+ assertEquals("1E4", str);
str = NumberFormat.getFormat("##0.###E0").format(12345.0);
- assertTrue(str.equals("12,345E3"));
+ assertEquals("12,345E3", str);
str = NumberFormat.getFormat("##0.###E0").format(12345.00001);
- assertTrue(str.equals("12,345E3"));
+ assertEquals("12,345E3", str);
str = NumberFormat.getFormat("##0.###E0").format(12345);
- assertTrue(str.equals("12,345E3"));
+ assertEquals("12,345E3", str);
str = NumberFormat.getFormat("##0.####E0").format(789.12345e-9);
- assertTrue(str.equals("789,1235E-9"));
+ assertEquals("789,1235E-9", str);
str = NumberFormat.getFormat("##0.####E0").format(780.e-9);
- assertTrue(str.equals("780E-9"));
+ assertEquals("780E-9", str);
str = NumberFormat.getFormat(".###E0").format(45678.0);
- assertTrue(str.equals(",457E5"));
+ assertEquals(",457E5", str);
str = NumberFormat.getFormat(".###E0").format(0);
- assertTrue(str.equals(",0E0"));
+ assertEquals(",0E0", str);
str = NumberFormat.getFormat("#E0").format(45678000);
- assertTrue(str.equals("5E7"));
+ assertEquals("5E7", str);
str = NumberFormat.getFormat("##E0").format(45678000);
- assertTrue(str.equals("46E6"));
+ assertEquals("46E6", str);
str = NumberFormat.getFormat("####E0").format(45678000);
- assertTrue(str.equals("4568E4"));
+ assertEquals("4568E4", str);
str = NumberFormat.getFormat("0E0").format(45678000);
- assertTrue(str.equals("5E7"));
+ assertEquals("5E7", str);
str = NumberFormat.getFormat("00E0").format(45678000);
- assertTrue(str.equals("46E6"));
+ assertEquals("46E6", str);
str = NumberFormat.getFormat("000E0").format(45678000);
- assertTrue(str.equals("457E5"));
+ assertEquals("457E5", str);
str = NumberFormat.getFormat("###E0").format(0.0000123);
- assertTrue(str.equals("12E-6"));
+ assertEquals("12E-6", str);
str = NumberFormat.getFormat("###E0").format(0.000123);
- assertTrue(str.equals("123E-6"));
+ assertEquals("123E-6", str);
str = NumberFormat.getFormat("###E0").format(0.00123);
- assertTrue(str.equals("1E-3"));
+ assertEquals("1E-3", str);
str = NumberFormat.getFormat("###E0").format(0.0123);
- assertTrue(str.equals("12E-3"));
+ assertEquals("12E-3", str);
str = NumberFormat.getFormat("###E0").format(0.123);
- assertTrue(str.equals("123E-3"));
+ assertEquals("123E-3", str);
str = NumberFormat.getFormat("###E0").format(1.23);
- assertTrue(str.equals("1E0"));
+ assertEquals("1E0", str);
str = NumberFormat.getFormat("###E0").format(12.3);
- assertTrue(str.equals("12E0"));
+ assertEquals("12E0", str);
str = NumberFormat.getFormat("###E0").format(123.0);
- assertTrue(str.equals("123E0"));
+ assertEquals("123E0", str);
str = NumberFormat.getFormat("###E0").format(1230.0);
- assertTrue(str.equals("1E3"));
+ assertEquals("1E3", str);
}
public void testGrouping() {
String str;
str = NumberFormat.getFormat("#,###").format(1234567890);
- assertTrue(str.equals("1\u00a0234\u00a0567\u00a0890"));
+ assertEquals("1\u00a0234\u00a0567\u00a0890", str);
str = NumberFormat.getFormat("#,####").format(1234567890);
- assertTrue(str.equals("12\u00a03456\u00a07890"));
+ assertEquals("12\u00a03456\u00a07890", str);
str = NumberFormat.getFormat("#").format(1234567890);
- assertTrue(str.equals("1234567890"));
+ assertEquals("1234567890", str);
}
public void testPerMill() {
String str;
str = NumberFormat.getFormat("###.###\u2030").format(0.4857);
- assertTrue(str.equals("485,7\u2030"));
+ assertEquals("485,7\u2030", str);
}
public void testQuotes() {
String str;
str = NumberFormat.getFormat("a'fo''o'b#").format(123);
- assertTrue(str.equals("afo'ob123"));
+ assertEquals("afo'ob123", str);
str = NumberFormat.getFormat("a''b#").format(123);
- assertTrue(str.equals("a'b123"));
+ assertEquals("a'b123", str);
}
public void testStandardFormat() {
String str;
str = NumberFormat.getCurrencyFormat().format(1234.579);
- assertTrue(str.equals("1\u00A0234,58 \u20AC"));
+ assertEquals("1\u00A0234,58 \u20AC", str);
str = NumberFormat.getDecimalFormat().format(1234.579);
- assertTrue(str.equals("1\u00A0234,579"));
+ assertEquals("1\u00A0234,579", str);
str = NumberFormat.getPercentFormat().format(1234.579);
- assertTrue(str.equals("123\u00A0458\u00A0%"));
+ assertEquals("123\u00A0458\u00A0%", str);
str = NumberFormat.getScientificFormat().format(1234.579);
- assertTrue(str.equals("1,235E3"));
+ assertEquals("1,235E3", str);
}
public void testZeros() {
String str;
str = NumberFormat.getFormat("#.#").format(0);
- assertTrue(str.equals("0"));
+ assertEquals("0", str);
str = NumberFormat.getFormat("#.").format(0);
- assertTrue(str.equals("0,"));
+ assertEquals("0,", str);
str = NumberFormat.getFormat(".#").format(0);
- assertTrue(str.equals(",0"));
+ assertEquals(",0", str);
str = NumberFormat.getFormat("#").format(0);
- assertTrue(str.equals("0"));
+ assertEquals("0", str);
str = NumberFormat.getFormat("#0.#").format(0);
- assertTrue(str.equals("0"));
+ assertEquals("0", str);
str = NumberFormat.getFormat("#0.").format(0);
- assertTrue(str.equals("0,"));
+ assertEquals("0,", str);
str = NumberFormat.getFormat("#.0").format(0);
- assertTrue(str.equals(",0"));
+ assertEquals(",0", str);
str = NumberFormat.getFormat("#").format(0);
- assertTrue(str.equals("0"));
+ assertEquals("0", str);
}
}
diff --git a/user/test/com/google/gwt/i18n/client/NumberParse_fr_Test.java b/user/test/com/google/gwt/i18n/client/NumberParse_fr_Test.java
index 0abd555..e9855ed 100644
--- a/user/test/com/google/gwt/i18n/client/NumberParse_fr_Test.java
+++ b/user/test/com/google/gwt/i18n/client/NumberParse_fr_Test.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2006 Google Inc.
+ * Copyright 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
@@ -40,13 +40,13 @@
Number value;
value = numberParse("0.0000", "123,4579");
- assertTrue(value.doubleValue() == 123.4579);
+ assertEquals(123.4579, value.doubleValue(), 0.0);
value = numberParse("0.0000", "+123,4579");
- assertTrue(value.doubleValue() == 123.4579);
+ assertEquals(123.4579, value.doubleValue(), 0.0);
value = numberParse("0.0000", "-123,4579");
- assertTrue(value.doubleValue() == -123.4579);
+ assertEquals(-123.4579, value.doubleValue(), 0.0);
}
public void testExponentParse() {
@@ -54,19 +54,19 @@
Number value;
value = numberParse("#E0", "1,234E3");
- assertTrue(value.doubleValue() == 1.234E+3);
+ assertEquals(1.234E+3, value.doubleValue(), 0.0);
value = numberParse("0.###E0", "1,234E3");
- assertTrue(value.doubleValue() == 1.234E+3);
+ assertEquals(1.234E+3, value.doubleValue(), 0.0);
value = numberParse("#E0", "1,2345E4");
- assertTrue(value.doubleValue() == 12345.0);
+ assertEquals(12345.0, value.doubleValue(), 0.0);
value = numberParse("0E0", "1,2345E4");
- assertTrue(value.doubleValue() == 12345.0);
+ assertEquals(12345.0, value.doubleValue(), 0.0);
value = numberParse("0E0", "1,2345E+4");
- assertTrue(value.doubleValue() == 12345.0);
+ assertEquals(12345.0, value.doubleValue(), 0.0);
}
public void testGroupingParse() {
@@ -74,12 +74,12 @@
Number value;
value = numberParse("#,###", "1\u00a0234\u00a0567\u00a0890");
- assertTrue(value.doubleValue() == 1234567890);
+ assertEquals(1234567890, value.doubleValue(), 0.0);
value = numberParse("#,####", "12\u00a03456\u00a07890");
- assertTrue(value.doubleValue() == 1234567890);
+ assertEquals(1234567890, value.doubleValue(), 0.0);
value = numberParse("#", "1234567890");
- assertTrue(value.doubleValue() == 1234567890);
+ assertEquals(1234567890, value.doubleValue(), 0.0);
}
public void testInfinityParse() {
@@ -87,10 +87,10 @@
Number value;
value = numberParse("0.0;(0.0)", "\u221E");
- assertTrue(value.doubleValue() == Double.POSITIVE_INFINITY);
+ assertEquals(Double.POSITIVE_INFINITY, value.doubleValue(), 0.0);
value = numberParse("0.0;(0.0)", "(\u221E)");
- assertTrue(value.doubleValue() == Double.NEGATIVE_INFINITY);
+ assertEquals(Double.NEGATIVE_INFINITY, value.doubleValue(), 0.0);
}
public void testPrecentParse() {
@@ -98,16 +98,16 @@
Number value;
value = numberParse("0.0;(0.0)", "123,4579%");
- assertTrue(value.doubleValue() == (123.4579 / 100));
+ assertEquals((123.4579 / 100), value.doubleValue(), 0.0);
value = numberParse("0.0;(0.0)", "(%123,4579)");
- assertTrue(value.doubleValue() == (-123.4579 / 100));
+ assertEquals((-123.4579 / 100), value.doubleValue(), 0.0);
value = numberParse("0.0;(0.0)", "123,4579\u2030");
- assertTrue(value.doubleValue() == (123.4579 / 1000));
+ assertEquals((123.4579 / 1000), value.doubleValue(), 0.0);
value = numberParse("0.0;(0.0)", "(\u2030123,4579)");
- assertTrue(value.doubleValue() == (-123.4579 / 1000));
+ assertEquals((-123.4579 / 1000), value.doubleValue(), 0.0);
}
public void testPrefixParse() {
@@ -115,10 +115,10 @@
Number value;
value = numberParse("0.0;(0.0)", "123,4579");
- assertTrue(value.doubleValue() == 123.4579);
+ assertEquals(123.4579, value.doubleValue(), 0.0);
value = numberParse("0.0;(0.0)", "(123,4579)");
- assertTrue(value.doubleValue() == -123.4579);
+ assertEquals(-123.4579, value.doubleValue(), 0.0);
}
}
diff --git a/user/test/com/google/gwt/langtest/LongLibGwtTest.gwt.xml b/user/test/com/google/gwt/langtest/LongLibGwtTest.gwt.xml
new file mode 100644
index 0000000..fab5801
--- /dev/null
+++ b/user/test/com/google/gwt/langtest/LongLibGwtTest.gwt.xml
@@ -0,0 +1,16 @@
+<!-- -->
+<!-- Copyright 2008 Google Inc. -->
+<!-- Licensed under the Apache License, Version 2.0 (the "License"); you -->
+<!-- may not use this file except in compliance with the License. You may -->
+<!-- may obtain a copy of the License at -->
+<!-- -->
+<!-- http://www.apache.org/licenses/LICENSE-2.0 -->
+<!-- -->
+<!-- Unless required by applicable law or agreed to in writing, software -->
+<!-- distributed under the License is distributed on an "AS IS" BASIS, -->
+<!-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -->
+<!-- implied. License for the specific language governing permissions and -->
+<!-- limitations under the License. -->
+<module>
+ <source path=""/>
+</module>
diff --git a/user/test/com/google/gwt/langtest/LongLibGwtTest.java b/user/test/com/google/gwt/langtest/LongLibGwtTest.java
new file mode 100644
index 0000000..66225de
--- /dev/null
+++ b/user/test/com/google/gwt/langtest/LongLibGwtTest.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.langtest;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.junit.client.GWTTestCase;
+import com.google.gwt.lang.LongLib;
+import com.google.gwt.lang.LongLibTestBase;
+
+/**
+ * Test the LongLib class as a GWTTestCase.
+ */
+public class LongLibGwtTest extends GWTTestCase {
+
+ static {
+ if (!GWT.isScript()) {
+ LongLib.RUN_IN_JVM = true;
+ }
+ }
+
+ private LongLibTestBase impl = new LongLibTestBase();
+
+ @Override
+ public String getModuleName() {
+ return "com.google.gwt.langtest.LongLibGwtTest";
+ }
+
+ public void testAdditive() {
+ impl.testAdditive();
+ }
+
+ public void testBitOps() {
+ impl.testBitOps();
+ }
+
+ public void testComparisons() {
+ impl.testComparisons();
+ }
+
+ public void testConversions() {
+ impl.testConversions();
+ }
+
+ public void testDiv() {
+ impl.testDiv();
+ }
+
+ public void testFactorial() {
+ impl.testFactorial();
+ }
+
+ public void testFromDouble() {
+ impl.testFromDouble();
+ }
+
+ public void testMinMax() {
+ impl.testMinMax();
+ }
+
+ public void testMultiplicative() {
+ impl.testMultiplicative();
+ }
+
+ public void testNegate() {
+ impl.testNegate();
+ }
+
+ public void testShift() {
+ impl.testShift();
+ }
+
+ public void testToHexString() {
+ impl.testToHexString();
+ }
+
+ public void testToString() {
+ impl.testToString();
+ }
+}
diff --git a/user/test/com/google/gwt/user/client/rpc/ValueTypesTest.java b/user/test/com/google/gwt/user/client/rpc/ValueTypesTest.java
index 2d3d190..7f82ce2 100644
--- a/user/test/com/google/gwt/user/client/rpc/ValueTypesTest.java
+++ b/user/test/com/google/gwt/user/client/rpc/ValueTypesTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2007 Google Inc.
+ * Copyright 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
@@ -24,6 +24,8 @@
public class ValueTypesTest extends GWTTestCase {
private static final int TEST_DELAY = 5000;
+ private ValueTypesTestServiceAsync primitiveTypeTestService;
+
public String getModuleName() {
return "com.google.gwt.user.RPCSuite";
}
@@ -217,8 +219,7 @@
}
/**
- * Validate that NaNs (not-a-number, such as 0/0) propagate
- * properly via RPC.
+ * Validate that NaNs (not-a-number, such as 0/0) propagate properly via RPC.
*/
public void testDouble_NaN() {
delayTestFinish(TEST_DELAY);
@@ -331,8 +332,7 @@
}
/**
- * Validate that NaNs (not-a-number, such as 0/0) propagate
- * properly via RPC.
+ * Validate that NaNs (not-a-number, such as 0/0) propagate properly via RPC.
*/
public void testFloat_NaN() {
delayTestFinish(TEST_DELAY);
@@ -444,7 +444,7 @@
});
}
- public void disabledTestLong() {
+ public void testLong() {
delayTestFinish(TEST_DELAY);
ValueTypesTestServiceAsync service = getServiceAsync();
service.echo(Long.MAX_VALUE / 2, new AsyncCallback() {
@@ -456,16 +456,13 @@
public void onSuccess(Object result) {
assertNotNull(result);
long expected = Long.MAX_VALUE / 2;
- // TODO: resolve off-by-one problem (probably just a side effect of
- // loss of precision).
- // ++expected;
assertEquals(expected, ((Long) result).longValue());
finishTest();
}
});
}
- public void disabledTestLong_MAX_VALUE() {
+ public void testLong_MAX_VALUE() {
delayTestFinish(TEST_DELAY);
ValueTypesTestServiceAsync service = getServiceAsync();
service.echo_MAX_VALUE(Long.MAX_VALUE, new AsyncCallback() {
@@ -482,7 +479,7 @@
});
}
- public void disabledTestLong_MIN_VALUE() {
+ public void testLong_MIN_VALUE() {
delayTestFinish(TEST_DELAY);
ValueTypesTestServiceAsync service = getServiceAsync();
service.echo_MIN_VALUE(Long.MIN_VALUE, new AsyncCallback() {
@@ -558,6 +555,4 @@
}
return primitiveTypeTestService;
}
-
- private ValueTypesTestServiceAsync primitiveTypeTestService;
}