Skip to content

Commit c8f24bd

Browse files
committed
Compute TruffleString.fromLong hash code without materializing the string.
1 parent 4dc61ab commit c8f24bd

File tree

2 files changed

+65
-2
lines changed

2 files changed

+65
-2
lines changed

truffle/src/com.oracle.truffle.api.strings/src/com/oracle/truffle/api/strings/NumberConversion.java

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -476,4 +476,65 @@ private static void writeDigitPairToByteArray(byte[] buf, int stride, int bufPos
476476
writeToByteArray(buf, stride, bufPos, digitPairHi(digitPair));
477477
writeToByteArray(buf, stride, bufPos + 1, digitPairLo(digitPair));
478478
}
479+
480+
/**
481+
* Computes Long.toString(value).hashCode() from the long value.
482+
*
483+
* @implNote This method converts positive inputs into negative values, to cover the
484+
* Long.MIN_VALUE case.
485+
* @see #writeLongToBytesIntl
486+
*/
487+
static int computeLongStringHashCode(long value) {
488+
long i = value;
489+
boolean negative = (i < 0);
490+
if (!negative) {
491+
i = -i;
492+
}
493+
494+
int hash = 0;
495+
int coef = 1;
496+
// Get 2 digits/iteration using longs until quotient fits into an int
497+
while (i < Integer.MIN_VALUE) {
498+
long q = i / 100;
499+
int r = (int) ((q * 100) - i);
500+
i = q;
501+
var digitPair = digitPair(r);
502+
hash += coef * digitPairLo(digitPair);
503+
coef *= 31;
504+
hash += coef * digitPairHi(digitPair);
505+
coef *= 31;
506+
}
507+
508+
// Get 2 digits/iteration using ints
509+
int i2 = (int) i;
510+
while (i2 <= -100) {
511+
int q = i2 / 100;
512+
int r = (q * 100) - i2;
513+
i2 = q;
514+
var digitPair = digitPair(r);
515+
hash += coef * digitPairLo(digitPair);
516+
coef *= 31;
517+
hash += coef * digitPairHi(digitPair);
518+
coef *= 31;
519+
}
520+
521+
// We know there are at most two digits and at least one digit left at this point.
522+
if (i2 < -9) {
523+
int r = -i2;
524+
var digitPair = digitPair(r);
525+
hash += coef * digitPairLo(digitPair);
526+
coef *= 31;
527+
hash += coef * digitPairHi(digitPair);
528+
coef *= 31;
529+
} else {
530+
hash += coef * ('0' - i2);
531+
coef *= 31;
532+
}
533+
534+
if (negative) {
535+
hash += coef * '-';
536+
}
537+
assert hash == Long.toString(value).hashCode() : value;
538+
return hash;
539+
}
479540
}

truffle/src/com.oracle.truffle.api.strings/src/com/oracle/truffle/api/strings/TruffleString.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,8 @@ static TruffleString createConstant(byte[] bytes, int length, int stride, Encodi
209209

210210
static TruffleString createLazyLong(long value, Encoding encoding) {
211211
int length = NumberConversion.stringLengthLong(value);
212-
return TruffleString.create(new LazyLong(value), 0, length, 0, encoding, length, TSCodeRange.get7Bit(), 0, true);
212+
int hash = HashCodeNode.maskZero(NumberConversion.computeLongStringHashCode(value));
213+
return TruffleString.create(new LazyLong(value), 0, length, 0, encoding, length, TSCodeRange.get7Bit(), hash, true);
213214
}
214215

215216
static TruffleString createLazyConcat(TruffleString a, TruffleString b, Encoding encoding, int length, int stride, int codeRange) {
@@ -1870,7 +1871,8 @@ static TruffleString doLazy(long value, Encoding enc, @SuppressWarnings("unused"
18701871
static TruffleString doEager(long value, Encoding enc, @SuppressWarnings("unused") boolean lazy) {
18711872
CompilerAsserts.partialEvaluationConstant(lazy);
18721873
int length = NumberConversion.stringLengthLong(value);
1873-
return TruffleString.createFromByteArray(NumberConversion.longToString(value, length), length, 0, enc, length, TSCodeRange.get7Bit());
1874+
int hash = HashCodeNode.maskZero(NumberConversion.computeLongStringHashCode(value));
1875+
return TruffleString.createFromByteArray(NumberConversion.longToString(value, length), 0, length, 0, enc, length, TSCodeRange.get7Bit(), hash, true);
18741876
}
18751877

18761878
@Specialization(guards = "!is7BitCompatible(enc)")

0 commit comments

Comments
 (0)