Ignore:
Timestamp:
Sep 19, 2010, 6:23:33 PM (15 years ago)
Author:
[email protected]
Message:

Bug 46065 - Unify implementation of ToInt32 and ToUInt32, don't use fmod.

Reviewed by Oliver Hunt.

These methods implement the same conversion (see discussion in the notes
of sections of 9.5 and 9.6 of the spec), only differing in how the result
is interpretted.

JavaScriptCore:

Date prototype is incorrectly using toInt32, and this is causing us to
provide an output value indicating whether the input to ToInt32 was finite
(the corresponding methods on Date are actually spec'ed to use ToInteger,
not ToInt32). This patch partially fixes this in order to remove this
bogus output value, hoewever more work will be require to bring Date
fully up to spec compliance (the constructor is still performing ToInt32
conversions).

(JSC::fillStructuresUsingTimeArgs):
(JSC::fillStructuresUsingDateArgs):
(JSC::dateProtoFuncSetYear):

  • runtime/JSValue.cpp:

(JSC::toInt32):

  • runtime/JSValue.h:

(JSC::toUInt32):
(JSC::JSValue::toInt32):
(JSC::JSValue::toUInt32):

WebCore:

Removing JSValue::toInt32 (since this has weird, non-spec function).
A couple of places in the binding are using this method, so adding
finiteInt32Value to the bindings to maintain current behaviour.

Test: fast/js/toInt32UInt32.html

  • bindings/js/JSDOMBinding.h:

(WebCore::finiteInt32Value):

  • bindings/js/JSHTMLOptionsCollectionCustom.cpp:

(WebCore::JSHTMLOptionsCollection::add):

  • bindings/js/JSSQLResultSetRowListCustom.cpp:

(WebCore::JSSQLResultSetRowList::item):

  • bindings/js/JSSVGPODListCustom.h:

(WebCore::JSSVGPODListCustom::getItem):
(WebCore::JSSVGPODListCustom::insertItemBefore):
(WebCore::JSSVGPODListCustom::replaceItem):
(WebCore::JSSVGPODListCustom::removeItem):

  • bindings/js/JSSVGPathSegListCustom.cpp:

(WebCore::JSSVGPathSegList::getItem):
(WebCore::JSSVGPathSegList::insertItemBefore):
(WebCore::JSSVGPathSegList::replaceItem):
(WebCore::JSSVGPathSegList::removeItem):

LayoutTests:

Add test cases for ToInt32 / ToUInt32 functionality.

  • fast/js/script-tests/toInt32UInt32.js: Added.
  • fast/js/toInt32UInt32-expected.txt: Added.
  • fast/js/toInt32UInt32.html: Added.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/JavaScriptCore/runtime/JSValue.cpp

    r65698 r67825  
    136136#endif
    137137
    138 int32_t toInt32SlowCase(double d, bool& ok)
     138// This in the ToInt32 operation is defined in section 9.5 of the ECMA-262 spec.
     139// Note that this operation is identical to ToUInt32 other than to interpretation
     140// of the resulting bit-pattern (as such this metod is also called to implement
     141// ToUInt32).
     142//
     143// The operation can be descibed as round towards zero, then select the 32 least
     144// bits of the resulting value in 2s-complement representation.
     145int32_t toInt32(double number)
    139146{
    140     if (isnan(d) || isinf(d)) {
    141         ok = false;
     147    int64_t bits = WTF::bitwise_cast<int64_t>(number);
     148    int32_t exp = (static_cast<int32_t>(bits >> 52) & 0x7ff) - 0x3ff;
     149
     150    // If exponent < 0 there will be no bits to the left of the decimal point
     151    // after rounding; if the exponent is > 83 then no bits of precision can be
     152    // left in the low 32-bit range of the result (IEEE-754 doubles have 52 bits
     153    // of fractional precision).
     154    // Note this case handles 0, -0, and all infinte, NaN, & denormal value.
     155    if (exp < 0 || exp > 83)
    142156        return 0;
     157
     158    // Select the appropriate 32-bits from the floating point mantissa.  If the
     159    // exponent is 52 then the bits we need to select are already aligned to the
     160    // lowest bits of the 64-bit integer representation of tghe number, no need
     161    // to shift.  If the exponent is greater than 52 we need to shift the value
     162    // left by (exp - 52), if the value is less than 52 we need to shift right
     163    // accordingly.
     164    int32_t result = (exp > 52)
     165        ? static_cast<int32_t>(bits << (exp - 52))
     166        : static_cast<int32_t>(bits >> (52 - exp));
     167
     168    // IEEE-754 double precision values are stored omitting an implicit 1 before
     169    // the decimal point; we need to reinsert this now.  We may also the shifted
     170    // invalid bits into the result that are not a part of the mantissa (the sign
     171    // and exponent bits from the floatingpoint representation); mask these out.
     172    if (exp < 32) {
     173        int32_t missingOne = 1 << exp;
     174        result &= missingOne - 1;
     175        result += missingOne;
    143176    }
    144177
    145     ok = true;
    146 
    147     double d32 = fmod(trunc(d), D32);
    148     if (d32 >= D32 / 2)
    149         d32 -= D32;
    150     else if (d32 < -D32 / 2)
    151         d32 += D32;
    152     return static_cast<int32_t>(d32);
    153 }
    154 
    155 uint32_t toUInt32SlowCase(double d, bool& ok)
    156 {
    157     if (isnan(d) || isinf(d)) {
    158         ok = false;
    159         return 0;
    160     }
    161 
    162     ok = true;
    163 
    164     double d32 = fmod(trunc(d), D32);
    165     if (d32 < 0)
    166         d32 += D32;
    167     return static_cast<uint32_t>(d32);
     178    // If the input value was negative (we could test either 'number' or 'bits',
     179    // but testing 'bits' is likely faster) invert the result appropriately.
     180    return bits < 0 ? -result : result;
    168181}
    169182
Note: See TracChangeset for help on using the changeset viewer.