# HG changeset patch # User Jaroslav Tulach # Date 1362041414 -3600 # Node ID da63749558e216ed68ca488900958ee858847bdb # Parent bb75065133539582e364805e3a619831a0fe1bb8# Parent 8264f07b1f460d1d52e2ce9cda6e680a017de442 Merge of new advances in arithmetic including JavaScript Number having all methods of java.lang.Number and good valueOf implementation diff -r bb7506513353 -r da63749558e2 rt/emul/mini/src/main/java/java/io/DataInputStream.java --- a/rt/emul/mini/src/main/java/java/io/DataInputStream.java Thu Feb 28 07:48:54 2013 +0100 +++ b/rt/emul/mini/src/main/java/java/io/DataInputStream.java Thu Feb 28 09:50:14 2013 +0100 @@ -468,42 +468,8 @@ * @see java.lang.Double#longBitsToDouble(long) */ public final double readDouble() throws IOException { - int hi = readInt(); - int low = readInt(); - return toDouble(hi, low); - } - - @JavaScriptBody(args={ "hi", "low" }, - body= - "if (low == 0) {\n" - + " if (hi === 0x7ff00000) return Number.POSITIVE_INFINITY;\n" - + " if (hi === 0xfff00000) return Number.NEGATIVE_INFINITY;\n" - + "}\n" - + "if (hi >= 0x7ff00000 && hi <= 0x7fffffff) return Number.NaN;\n" - + "if (hi >= 0xfff00000 && hi <= 0xffffffff) return Number.NaN;\n" - + "var s = (hi & 0x80000000) === 0 ? 1 : -1;\n" - + "var e = (hi >> 20) & 0x7ff;\n" - + "var to32 = low >> 0;\n" - + "if (e === 0) {\n" - + " if (to32 & 0x80000000) {\n" - + " hi = hi << 1 + 1; low = low << 1;\n" - + " } else {\n" - + " hi = hi << 1; low = low << 1;\n" - + " }\n" - + "} else {\n" - + " hi = (hi & 0xfffff) | 0x100000;\n" - + "}\n" - + "to32 = low >> 0;\n" - + "var m = Math.pow(2.0, 32) * hi + to32;\n" - + "var r = s * m * Math.pow(2.0, e - 1075);\n" - + "//throw 'exp: ' + e + ' sign: ' + s + ' hi:' + hi + ' low: ' + low + ' m: ' + m + ' r: ' + r;\n" - + "return r;\n" - ) - private static double toDouble(int hi, int low) { - long both = hi; - both = (both << 32) & low; - return Double.doubleToLongBits(both); - } + return Double.longBitsToDouble(readLong()); + } private char lineBuffer[]; diff -r bb7506513353 -r da63749558e2 rt/emul/mini/src/main/java/java/lang/Double.java --- a/rt/emul/mini/src/main/java/java/lang/Double.java Thu Feb 28 07:48:54 2013 +0100 +++ b/rt/emul/mini/src/main/java/java/lang/Double.java Thu Feb 28 09:50:14 2013 +0100 @@ -920,6 +920,26 @@ * @return the {@code double} floating-point value with the same * bit pattern. */ + @JavaScriptBody(args={ "bits" }, + body= + "var hi = bits.high32();\n" + + "var s = (hi & 0x80000000) === 0 ? 1 : -1;\n" + + "var e = (hi >> 20) & 0x7ff;\n" + + "if (e === 0x7ff) {\n" + + " if ((bits == 0) && ((hi & 0xfffff) === 0)) {\n" + + " return (s > 0) ? Number.POSITIVE_INFINITY" + + " : Number.NEGATIVE_INFINITY;\n" + + " }\n" + + " return Number.NaN;\n" + + "}\n" + + "var m = (hi & 0xfffff).next32(bits);\n" + + "if (e === 0) {\n" + + " m = m.shl64(1);\n" + + "} else {\n" + + " m.hi = m.high32() | 0x100000;\n" + + "}\n" + + "return s * m.toFP() * Math.pow(2.0, e - 1075);\n" + ) public static native double longBitsToDouble(long bits); /** diff -r bb7506513353 -r da63749558e2 rt/emul/mini/src/main/java/java/lang/Float.java --- a/rt/emul/mini/src/main/java/java/lang/Float.java Thu Feb 28 07:48:54 2013 +0100 +++ b/rt/emul/mini/src/main/java/java/lang/Float.java Thu Feb 28 09:50:14 2013 +0100 @@ -822,13 +822,13 @@ "var s = ((bits >> 31) == 0) ? 1 : -1;\n" + "var e = ((bits >> 23) & 0xff);\n" + "if (e === 0xff) {\n" - + " if ((bits & 0x7fffff) === 0) {\n" - + " return (s > 0) ? Number.POSITIVE_INFINITY" - + " : Number.NEGATIVE_INFINITY;\n" - + " }\n" - + " return Number.NaN;\n" + + " if ((bits & 0x7fffff) === 0) {\n" + + " return (s > 0) ? Number.POSITIVE_INFINITY" + + " : Number.NEGATIVE_INFINITY;\n" + + " }\n" + + " return Number.NaN;\n" + "}\n" - + "var m = (e == 0) ?\n" + + "var m = (e === 0) ?\n" + " (bits & 0x7fffff) << 1 :\n" + " (bits & 0x7fffff) | 0x800000;\n" + "return s * m * Math.pow(2.0, e - 150);\n" diff -r bb7506513353 -r da63749558e2 rt/emul/mini/src/main/java/java/lang/Number.java --- a/rt/emul/mini/src/main/java/java/lang/Number.java Thu Feb 28 07:48:54 2013 +0100 +++ b/rt/emul/mini/src/main/java/java/lang/Number.java Thu Feb 28 09:50:14 2013 +0100 @@ -26,6 +26,9 @@ package java.lang; import org.apidesign.bck2brwsr.core.ExtraJavaScript; +import org.apidesign.bck2brwsr.core.JavaScriptBody; +import org.apidesign.bck2brwsr.core.JavaScriptOnly; +import org.apidesign.bck2brwsr.core.JavaScriptPrototype; /** * The abstract class Number is the superclass of classes @@ -52,6 +55,7 @@ resource="/org/apidesign/vm4brwsr/emul/lang/java_lang_Number.js", processByteCode=true ) +@JavaScriptPrototype(container = "Number.prototype", prototype = "new Number") public abstract class Number implements java.io.Serializable { /** * Returns the value of the specified number as an int. @@ -60,6 +64,7 @@ * @return the numeric value represented by this object after conversion * to type int. */ + @JavaScriptBody(args = {}, body = "return this | 0;") public abstract int intValue(); /** @@ -69,6 +74,7 @@ * @return the numeric value represented by this object after conversion * to type long. */ + @JavaScriptBody(args = {}, body = "return this.toLong();") public abstract long longValue(); /** @@ -78,6 +84,7 @@ * @return the numeric value represented by this object after conversion * to type float. */ + @JavaScriptBody(args = {}, body = "return this;") public abstract float floatValue(); /** @@ -87,6 +94,7 @@ * @return the numeric value represented by this object after conversion * to type double. */ + @JavaScriptBody(args = {}, body = "return this;") public abstract double doubleValue(); /** @@ -115,4 +123,15 @@ /** use serialVersionUID from JDK 1.0.2 for interoperability */ private static final long serialVersionUID = -8742448824652078965L; + + static { + // as last step of initialization, initialize valueOf method + initValueOf(); + } + @JavaScriptBody(args = { }, body = + "var p = vm.java_lang_Number(false);\n" + + "p.valueOf = function() { return this.doubleValue__D(); };\n" + + "p.toString = function() { return this.toString__Ljava_lang_String_2(); };" + ) + private native static void initValueOf(); } diff -r bb7506513353 -r da63749558e2 rt/emul/mini/src/main/resources/org/apidesign/vm4brwsr/emul/lang/java_lang_Number.js --- a/rt/emul/mini/src/main/resources/org/apidesign/vm4brwsr/emul/lang/java_lang_Number.js Thu Feb 28 07:48:54 2013 +0100 +++ b/rt/emul/mini/src/main/resources/org/apidesign/vm4brwsr/emul/lang/java_lang_Number.js Thu Feb 28 09:50:14 2013 +0100 @@ -28,8 +28,17 @@ return this.hi ? this.hi * (__m32+1) + this : this; }; Number.prototype.toLong = function() { - var hi = (this > __m32) ? (Math.floor(this / (__m32+1))) | 0 : 0; - return hi.next32(Math.floor(this % (__m32+1))); + var hi = (this / (__m32+1)) | 0; + var low = (this % (__m32+1)) | 0; + if (low < 0) { + low += __m32+1; + } + + if (this < 0) { + hi -= 1; + } + + return hi.next32(low); }; Number.prototype.toExactString = function() { @@ -481,7 +490,7 @@ v = x; } - if ((v === 0) && (v.high32() === 0)) { + if ((v == 0) && (v.high32() === 0)) { __handleDivByZero(); } @@ -522,7 +531,7 @@ v = x; } - if ((v === 0) && (v.high32() === 0)) { + if ((v == 0) && (v.high32() === 0)) { __handleDivByZero(); } diff -r bb7506513353 -r da63749558e2 rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java --- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java Thu Feb 28 07:48:54 2013 +0100 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java Thu Feb 28 09:50:14 2013 +0100 @@ -695,19 +695,19 @@ emit(out, "var @2 = @1;", smapper.popD(), smapper.pushF()); break; case opc_f2i: - emit(out, "var @2 = Math.floor(@1).toInt32();", + emit(out, "var @2 = @1.toInt32();", smapper.popF(), smapper.pushI()); break; case opc_f2l: - emit(out, "var @2 = Math.floor(@1).toLong();", + emit(out, "var @2 = @1.toLong();", smapper.popF(), smapper.pushL()); break; case opc_d2i: - emit(out, "var @2 = Math.floor(@1).toInt32();", + emit(out, "var @2 = @1.toInt32();", smapper.popD(), smapper.pushI()); break; case opc_d2l: - emit(out, "var @2 = Math.floor(@1).toLong();", + emit(out, "var @2 = @1.toLong();", smapper.popD(), smapper.pushL()); break; case opc_i2b: diff -r bb7506513353 -r da63749558e2 rt/vm/src/test/java/org/apidesign/vm4brwsr/NumberTest.java --- a/rt/vm/src/test/java/org/apidesign/vm4brwsr/NumberTest.java Thu Feb 28 07:48:54 2013 +0100 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/NumberTest.java Thu Feb 28 09:50:14 2013 +0100 @@ -143,6 +143,49 @@ ); } + @Test public void everyNumberHasJavaLangNumberMethods() throws Exception { + assertExec("Can we call doubleValue?", + Numbers.class, "seven__DI", + Double.valueOf(7.0), 0 + ); + } + @Test public void everyNumberHasJavaLangNumberMethodsInt() throws Exception { + assertExec("Can we call doubleValue?", + Numbers.class, "seven__DI", + Double.valueOf(7.0), 1 + ); + } + @Test public void everyNumberHasJavaLangNumberMethodsLong() throws Exception { + assertExec("Can we call doubleValue?", + Numbers.class, "seven__DI", + Double.valueOf(7.0), 2 + ); + } + @Test public void everyNumberHasJavaLangNumberMethodsShort() throws Exception { + assertExec("Can we call doubleValue?", + Numbers.class, "seven__DI", + Double.valueOf(7.0), 3 + ); + } + @Test public void everyNumberHasJavaLangNumberMethodsByte() throws Exception { + assertExec("Can we call doubleValue?", + Numbers.class, "seven__DI", + Double.valueOf(7.0), 4 + ); + } + @Test public void valueOfNumber() throws Exception { + assertExec("Can we call JavaScripts valueOf?", + Numbers.class, "seven__DI", + Double.valueOf(7.0), 8 + ); + } + @Test public void valueOfLongNumber() throws Exception { + assertExec("Can we call JavaScripts valueOf?", + Numbers.class, "seven__DI", + Double.valueOf(Long.MAX_VALUE / 5), 9 + ); + } + private static TestVM code; @BeforeClass diff -r bb7506513353 -r da63749558e2 rt/vm/src/test/java/org/apidesign/vm4brwsr/Numbers.java --- a/rt/vm/src/test/java/org/apidesign/vm4brwsr/Numbers.java Thu Feb 28 07:48:54 2013 +0100 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/Numbers.java Thu Feb 28 09:50:14 2013 +0100 @@ -20,6 +20,7 @@ import java.io.ByteArrayInputStream; import java.io.DataInputStream; import java.io.IOException; +import org.apidesign.bck2brwsr.core.JavaScriptBody; /** * @@ -67,4 +68,23 @@ static String floatToString() { return new Float(7.0).toString().toString(); } + + static double seven(int todo) { + switch (todo) { + case 0: return sevenNew().doubleValue(); + case 1: return sevenNew().intValue(); + case 2: return sevenNew().longValue(); + case 3: return sevenNew().shortValue(); + case 4: return sevenNew().byteValue(); + case 8: return valueOf(Double.valueOf(7.0)); + case 9: return valueOf(Long.valueOf(Long.MAX_VALUE / 5)); + default: throw new IllegalStateException(); + } + } + + @JavaScriptBody(args = {}, body = "return 7;") + private static native Number sevenNew(); + + @JavaScriptBody(args = { "o" }, body = "return o.valueOf();") + private static native double valueOf(Object o); } diff -r bb7506513353 -r da63749558e2 rt/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/IntegerArithmeticTest.java --- a/rt/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/IntegerArithmeticTest.java Thu Feb 28 07:48:54 2013 +0100 +++ b/rt/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/IntegerArithmeticTest.java Thu Feb 28 09:50:14 2013 +0100 @@ -50,6 +50,14 @@ private static int neg(int x) { return (-x); } + + private static float fadd(float x, float y) { + return x + y; + } + + private static double dadd(double x, double y) { + return x + y; + } @Compare public int addOverflow() { return add(Integer.MAX_VALUE, 1); @@ -90,7 +98,7 @@ @Compare public int division() { return div(1, 2); } - + @Compare public int divisionReminder() { return mod(1, 2); } @@ -103,6 +111,14 @@ return mod(-7, 3); } + @Compare public int conversionFromFloat() { + return (int) fadd(-2, -0.6f); + } + + @Compare public int conversionFromDouble() { + return (int) dadd(-2, -0.6); + } + @Compare public boolean divByZeroThrowsArithmeticException() { try { div(1, 0); diff -r bb7506513353 -r da63749558e2 rt/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/LongArithmeticTest.java --- a/rt/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/LongArithmeticTest.java Thu Feb 28 07:48:54 2013 +0100 +++ b/rt/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/LongArithmeticTest.java Thu Feb 28 09:50:14 2013 +0100 @@ -26,55 +26,63 @@ * @author Jaroslav Tulach */ public class LongArithmeticTest { - + private static long add(long x, long y) { return (x + y); } - + private static long sub(long x, long y) { return (x - y); } - + private static long mul(long x, long y) { return (x * y); } - + private static long div(long x, long y) { return (x / y); } - + private static long mod(long x, long y) { return (x % y); } - + private static long neg(long x) { return (-x); } - + private static long shl(long x, int b) { return (x << b); } - + private static long shr(long x, int b) { return (x >> b); } - + private static long ushr(long x, int b) { return (x >>> b); } - + private static long and(long x, long y) { return (x & y); } - + private static long or(long x, long y) { return (x | y); } - + private static long xor(long x, long y) { return (x ^ y); } - + + private static float fadd(float x, float y) { + return x + y; + } + + private static double dadd(double x, double y) { + return x + y; + } + public static int compare(long x, long y, int zero) { final int xyResult = compareL(x, y, zero); final int yxResult = compareL(y, x, zero); @@ -106,15 +114,15 @@ return (trueCount == 1) ? result : -2; } - + @Compare public long conversion() { return Long.MAX_VALUE; } - + @Compare public long negate1() { return neg(0x00fa37d7763e0ca1l); } - + @Compare public long negate2() { return neg(0x80fa37d7763e0ca1l); } @@ -134,11 +142,11 @@ @Compare public long addMaxLongAndMaxLong() { return add(Long.MAX_VALUE, Long.MAX_VALUE); } - + @Compare public long subMinLongAndMinLong() { return sub(Long.MIN_VALUE, Long.MIN_VALUE); } - + @Compare public long subMinLongAndMaxLong() { return sub(Long.MIN_VALUE, Long.MAX_VALUE); } @@ -146,23 +154,23 @@ @Compare public long multiplyMaxLong() { return mul(Long.MAX_VALUE, 2l); } - + @Compare public long multiplyMaxLongAndMaxLong() { return mul(Long.MAX_VALUE, Long.MAX_VALUE); } - + @Compare public long multiplyMinLong() { return mul(Long.MIN_VALUE, 2l); } - + @Compare public long multiplyMinLongAndMinLong() { return mul(Long.MIN_VALUE, Long.MIN_VALUE); } - + @Compare public long multiplyPrecision() { return mul(0x00fa37d7763e0ca1l, 0xa7b3432fff00123el); } - + @Compare public long divideSmallPositiveNumbers() { return div(0xabcdef, 0x123); } @@ -251,6 +259,22 @@ return mod(0x7fff800000000000l, 0x800000000001l); } + @Compare public long conversionFromFloatPositive() { + return (long) fadd(2, 0.6f); + } + + @Compare public long conversionFromFloatNegative() { + return (long) fadd(-2, -0.6f); + } + + @Compare public long conversionFromDoublePositive() { + return (long) dadd(0x20ffff0000L, 0.6); + } + + @Compare public long conversionFromDoubleNegative() { + return (long) dadd(-0x20ffff0000L, -0.6); + } + @Compare public boolean divByZeroThrowsArithmeticException() { try { div(1, 0); @@ -272,63 +296,63 @@ @Compare public long shiftL1() { return shl(0x00fa37d7763e0ca1l, 5); } - + @Compare public long shiftL2() { return shl(0x00fa37d7763e0ca1l, 32); } - + @Compare public long shiftL3() { return shl(0x00fa37d7763e0ca1l, 45); } - + @Compare public long shiftR1() { return shr(0x00fa37d7763e0ca1l, 5); } - + @Compare public long shiftR2() { return shr(0x00fa37d7763e0ca1l, 32); } - + @Compare public long shiftR3() { return shr(0x00fa37d7763e0ca1l, 45); } - + @Compare public long uShiftR1() { return ushr(0x00fa37d7763e0ca1l, 5); } - + @Compare public long uShiftR2() { return ushr(0x00fa37d7763e0ca1l, 45); } - + @Compare public long uShiftR3() { return ushr(0xf0fa37d7763e0ca1l, 5); } - + @Compare public long uShiftR4() { return ushr(0xf0fa37d7763e0ca1l, 45); } - + @Compare public long and1() { return and(0x00fa37d7763e0ca1l, 0xa7b3432fff00123el); } - + @Compare public long or1() { return or(0x00fa37d7763e0ca1l, 0xa7b3432fff00123el); } - + @Compare public long xor1() { return xor(0x00fa37d7763e0ca1l, 0xa7b3432fff00123el); } - + @Compare public long xor2() { return xor(0x00fa37d7763e0ca1l, 0x00000000ff00123el); } - + @Compare public long xor3() { return xor(0x00000000763e0ca1l, 0x00000000ff00123el); } - + @Compare public int compareSameNumbers() { return compare(0x0000000000000000l, 0x0000000000000000l, 0); }