Index: src/runtime.cc |
=================================================================== |
--- src/runtime.cc (revision 8431) |
+++ src/runtime.cc (working copy) |
@@ -45,6 +45,7 @@ |
#include "json-parser.h" |
#include "liveedit.h" |
#include "liveobjectlist-inl.h" |
+#include "misc-intrinsics.h" |
#include "parser.h" |
#include "platform.h" |
#include "runtime-profiler.h" |
@@ -6645,50 +6646,69 @@ |
// If the integers are equal so are the string representations. |
if (x_value == y_value) return Smi::FromInt(EQUAL); |
- // If one of the integers are zero the normal integer order is the |
+ // If one of the integers is zero the normal integer order is the |
// same as the lexicographic order of the string representations. |
- if (x_value == 0 || y_value == 0) return Smi::FromInt(x_value - y_value); |
+ if (x_value == 0 || y_value == 0) |
+ return Smi::FromInt(x_value < y_value ? LESS : GREATER); |
// If only one of the integers is negative the negative number is |
// smallest because the char code of '-' is less than the char code |
// of any digit. Otherwise, we make both values positive. |
+ |
+ // Use unsigned values otherwise the logic is incorrect for -MIN_INT on |
+ // architectures using 32-bit Smis. |
+ uint32_t x_scaled = x_value; |
+ uint32_t y_scaled = y_value; |
if (x_value < 0 || y_value < 0) { |
if (y_value >= 0) return Smi::FromInt(LESS); |
if (x_value >= 0) return Smi::FromInt(GREATER); |
- x_value = -x_value; |
- y_value = -y_value; |
+ x_scaled = -x_value; |
+ y_scaled = -y_value; |
} |
- // Arrays for the individual characters of the two Smis. Smis are |
- // 31 bit integers and 10 decimal digits are therefore enough. |
- // TODO(isolates): maybe we should simply allocate 20 bytes on the stack. |
- int* x_elms = isolate->runtime_state()->smi_lexicographic_compare_x_elms(); |
- int* y_elms = isolate->runtime_state()->smi_lexicographic_compare_y_elms(); |
+ static const uint32_t kPowersOf10[] = { |
+ 1, 10, 100, 1000, 10*1000, 100*1000, |
+ 1000*1000, 10*1000*1000, 100*1000*1000, |
+ 1000*1000*1000 |
+ }; |
+ // If the integers have the same number of decimal digits they can be |
+ // compared directly as the numeric order is the same as the |
+ // lexicographic order. If one integer has fewer digits, it is scaled |
+ // by some power of 10 to have the same number of digits as the longer |
+ // integer. If the scaled integers are equal it means the shorter |
+ // integer comes first in the lexicographic order. |
- // Convert the integers to arrays of their decimal digits. |
- int x_index = 0; |
- int y_index = 0; |
- while (x_value > 0) { |
- x_elms[x_index++] = x_value % 10; |
- x_value /= 10; |
- } |
- while (y_value > 0) { |
- y_elms[y_index++] = y_value % 10; |
- y_value /= 10; |
- } |
+ // From http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10 |
+ int x_log2 = IntegerLog2(x_scaled); |
+ int x_log10 = ((x_log2 + 1) * 1233) >> 12; |
+ x_log10 -= x_scaled < kPowersOf10[x_log10]; |
- // Loop through the arrays of decimal digits finding the first place |
- // where they differ. |
- while (--x_index >= 0 && --y_index >= 0) { |
- int diff = x_elms[x_index] - y_elms[y_index]; |
- if (diff != 0) return Smi::FromInt(diff); |
+ int y_log2 = IntegerLog2(y_scaled); |
+ int y_log10 = ((y_log2 + 1) * 1233) >> 12; |
+ y_log10 -= y_scaled < kPowersOf10[y_log10]; |
+ |
+ int tie = EQUAL; |
+ |
+ if (x_log10 < y_log10) { |
+ // X has fewer digits. We would like to simply scale up X but that |
+ // might overflow, e.g when comparing 9 with 1_000_000_000, 9 would |
+ // be scaled up to 9_000_000_000. So we scale up by the next |
+ // smallest power and scale down Y to drop one digit. It is OK to |
+ // drop one digit from the longer integer since the final digit is |
+ // past the length of the shorter integer. |
+ x_scaled *= kPowersOf10[y_log10 - x_log10 - 1]; |
+ y_scaled /= 10; |
+ tie = LESS; |
+ } else if (y_log10 < x_log10) { |
+ y_scaled *= kPowersOf10[x_log10 - y_log10 - 1]; |
+ x_scaled /= 10; |
+ tie = GREATER; |
} |
- // If one array is a suffix of the other array, the longest array is |
- // the representation of the largest of the Smis in the |
- // lexicographic ordering. |
- return Smi::FromInt(x_index - y_index); |
+ if (x_scaled < y_scaled) return Smi::FromInt(LESS); |
+ if (x_scaled > y_scaled) return Smi::FromInt(GREATER); |
+ return Smi::FromInt(tie); |
} |