diff --git a/classlib/src/main/java/org/teavm/classlib/java/lang/TLong.java b/classlib/src/main/java/org/teavm/classlib/java/lang/TLong.java index a48dc605c..c40ab282a 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/lang/TLong.java +++ b/classlib/src/main/java/org/teavm/classlib/java/lang/TLong.java @@ -198,7 +198,7 @@ public class TLong extends TNumber implements TComparable { } private static int hashCode(long value) { - return (int) (value ^ (value >>> 32)); + return (int) value ^ (int) (value >>> 32); } @Override diff --git a/core/src/main/java/org/teavm/backend/javascript/rendering/StatementRenderer.java b/core/src/main/java/org/teavm/backend/javascript/rendering/StatementRenderer.java index c8902b989..310c41588 100644 --- a/core/src/main/java/org/teavm/backend/javascript/rendering/StatementRenderer.java +++ b/core/src/main/java/org/teavm/backend/javascript/rendering/StatementRenderer.java @@ -881,8 +881,14 @@ public class StatementRenderer implements ExprVisitor, StatementVisitor { switch (expr.getTarget()) { case INT: precedence = Precedence.MEMBER_ACCESS; - expr.getValue().acceptVisitor(this); - writer.append(".lo"); + Expr longShifted = extractLongRightShiftedBy32(expr.getValue()); + if (longShifted != null) { + longShifted.acceptVisitor(this); + writer.append(".hi"); + } else { + expr.getValue().acceptVisitor(this); + writer.append(".lo"); + } break; case FLOAT: case DOUBLE: @@ -927,6 +933,31 @@ public class StatementRenderer implements ExprVisitor, StatementVisitor { } } + private Expr extractLongRightShiftedBy32(Expr expr) { + if (!(expr instanceof BinaryExpr)) { + return null; + } + + BinaryExpr binary = (BinaryExpr) expr; + if (binary.getOperation() != BinaryOperation.RIGHT_SHIFT + && binary.getOperation() != BinaryOperation.UNSIGNED_RIGHT_SHIFT) { + return null; + } + if (binary.getType() != OperationType.LONG) { + return null; + } + if (!(binary.getSecondOperand() instanceof ConstantExpr)) { + return null; + } + + Object rightConstant = ((ConstantExpr) binary.getSecondOperand()).getValue(); + if (rightConstant.equals(32) || rightConstant.equals(32L)) { + return binary.getFirstOperand(); + } + + return null; + } + @Override public void visit(ConditionalExpr expr) { try { diff --git a/tests/src/test/java/org/teavm/classlib/java/lang/LongTest.java b/tests/src/test/java/org/teavm/classlib/java/lang/LongTest.java index 1eee9d544..3cf4573bb 100644 --- a/tests/src/test/java/org/teavm/classlib/java/lang/LongTest.java +++ b/tests/src/test/java/org/teavm/classlib/java/lang/LongTest.java @@ -15,9 +15,11 @@ */ package org.teavm.classlib.java.lang; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import org.junit.Test; import org.junit.runner.RunWith; +import org.teavm.junit.SkipJVM; import org.teavm.junit.TeaVMTestRunner; @RunWith(TeaVMTestRunner.class) @@ -30,4 +32,10 @@ public class LongTest { assertTrue(Long.compare(Long.MAX_VALUE, Long.MIN_VALUE) > 0); assertTrue(Long.compare(Long.MIN_VALUE, Long.MAX_VALUE) < 0); } + + @Test + @SkipJVM + public void calculatesHashCode() { + assertEquals(23 ^ 42, Long.hashCode((23L << 32) | 42)); + } }