# HG changeset patch # User Lubomir Nerad # Date 1360940772 -3600 # Node ID b2731af0357df566151cf422444d6c3bb9d335e8 # Parent 419d8802bcbadadaae68e124887178c4d4aa49ce Fixed int & long division by zero (Bug 4668) and int negative division diff -r 419d8802bcba -r b2731af0357d emul/mini/src/main/resources/org/apidesign/vm4brwsr/emul/lang/java_lang_Number.js --- a/emul/mini/src/main/resources/org/apidesign/vm4brwsr/emul/lang/java_lang_Number.js Fri Feb 15 11:40:01 2013 +0100 +++ b/emul/mini/src/main/resources/org/apidesign/vm4brwsr/emul/lang/java_lang_Number.js Fri Feb 15 16:06:12 2013 +0100 @@ -212,6 +212,14 @@ }; (function(numberPrototype) { + function __handleDivByZero() { + var exception = new vm.java_lang_ArithmeticException; + vm.java_lang_ArithmeticException(false).constructor + .cons__VLjava_lang_String_2.call(exception, "/ by zero"); + + throw exception; + } + function __Int64(hi32, lo32) { this.hi32 = hi32 | 0; this.lo32 = lo32 | 0; @@ -438,11 +446,27 @@ r.setDigit(j + n, nrm, uj); } } - + + numberPrototype.div32 = function(x) { + if (x === 0) { + __handleDivByZero(); + } + + return (this / x) | 0; + } + + numberPrototype.mod32 = function(x) { + if (x === 0) { + __handleDivByZero(); + } + + return (this % x); + } + numberPrototype.div64 = function(x) { var negateResult = false; var u, v; - + if ((this.high32() & 0x80000000) != 0) { u = this.neg64(); negateResult = !negateResult; @@ -458,7 +482,7 @@ } if ((v === 0) && (v.high32() === 0)) { - // TODO: throw + __handleDivByZero(); } if (u.high32() === 0) { @@ -499,7 +523,7 @@ } if ((v === 0) && (v.high32() === 0)) { - // TODO: throw + __handleDivByZero(); } if (u.high32() === 0) { diff -r 419d8802bcba -r b2731af0357d vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java --- a/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java Fri Feb 15 11:40:01 2013 +0100 +++ b/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java Fri Feb 15 16:06:12 2013 +0100 @@ -553,7 +553,7 @@ emit(out, "@1 *= @2;", smapper.getD(1), smapper.popD()); break; case opc_idiv: - emit(out, "@1 = Math.floor(@1 / @2);", + emit(out, "@1 = @1.div32(@2);", smapper.getI(1), smapper.popI()); break; case opc_ldiv: @@ -567,7 +567,8 @@ emit(out, "@1 /= @2;", smapper.getD(1), smapper.popD()); break; case opc_irem: - emit(out, "@1 %= @2;", smapper.getI(1), smapper.popI()); + emit(out, "@1 = @1.mod32(@2);", + smapper.getI(1), smapper.popI()); break; case opc_lrem: emit(out, "@1 = @1.mod64(@2);", diff -r 419d8802bcba -r b2731af0357d vmtest/src/test/java/org/apidesign/bck2brwsr/tck/IntegerArithmeticTest.java --- a/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/IntegerArithmeticTest.java Fri Feb 15 11:40:01 2013 +0100 +++ b/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/IntegerArithmeticTest.java Fri Feb 15 16:06:12 2013 +0100 @@ -94,7 +94,33 @@ @Compare public int divisionReminder() { return mod(1, 2); } - + + @Compare public int negativeDivision() { + return div(-7, 3); + } + + @Compare public int negativeDivisionReminder() { + return mod(-7, 3); + } + + @Compare public boolean divByZeroThrowsArithmeticException() { + try { + div(1, 0); + return false; + } catch (final ArithmeticException e) { + return true; + } + } + + @Compare public boolean modByZeroThrowsArithmeticException() { + try { + mod(1, 0); + return false; + } catch (final ArithmeticException e) { + return true; + } + } + @Compare public int negate() { return neg(123456); } diff -r 419d8802bcba -r b2731af0357d vmtest/src/test/java/org/apidesign/bck2brwsr/tck/LongArithmeticTest.java --- a/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/LongArithmeticTest.java Fri Feb 15 11:40:01 2013 +0100 +++ b/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/LongArithmeticTest.java Fri Feb 15 16:06:12 2013 +0100 @@ -250,7 +250,25 @@ @Compare public long moduloWithCorrection() { return mod(0x7fff800000000000l, 0x800000000001l); } - + + @Compare public boolean divByZeroThrowsArithmeticException() { + try { + div(1, 0); + return false; + } catch (final ArithmeticException e) { + return true; + } + } + + @Compare public boolean modByZeroThrowsArithmeticException() { + try { + mod(1, 0); + return false; + } catch (final ArithmeticException e) { + return true; + } + } + @Compare public long shiftL1() { return shl(0x00fa37d7763e0ca1l, 5); }