Changeset 260863 in webkit
- Timestamp:
- Apr 28, 2020 8:54:56 PM (4 years ago)
- Location:
- trunk
- Files:
-
- 1 added
- 10 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/JSTests/ChangeLog
r260834 r260863 1 2020-04-28 Yusuke Suzuki <ysuzuki@apple.com> 2 3 [JSC] BigInt constructor should accept larger integers than safe-integers 4 https://bugs.webkit.org/show_bug.cgi?id=210755 5 6 Reviewed by Darin Adler. 7 8 * stress/big-int-constructor.js: 9 * stress/large-number-to-bigint.js: Added. 10 (shouldBe): 11 (shouldThrow): 12 * test262/config.yaml: 13 1 14 2020-04-28 Yusuke Suzuki <ysuzuki@apple.com> 2 15 -
trunk/JSTests/stress/big-int-constructor.js
r227004 r260863 248 248 assertThrowRangeError(0.5); 249 249 assertThrowRangeError(-.5); 250 assertThrowRangeError(9007199254740992);251 250 assertThrowRangeError(Infinity); 252 251 assertThrowRangeError(-Infinity); -
trunk/JSTests/test262/config.yaml
r260591 r260863 159 159 - test/intl402/RelativeTimeFormat/prototype/format/en-us-numeric-auto.js 160 160 - test/intl402/RelativeTimeFormat/prototype/formatToParts/en-us-numeric-auto.js 161 162 # Spec is changed. https://github.com/tc39/proposal-bigint/pull/138163 - test/built-ins/BigInt/constructor-integer.js -
trunk/Source/JavaScriptCore/ChangeLog
r260848 r260863 1 2020-04-28 Yusuke Suzuki <ysuzuki@apple.com> 2 3 [JSC] BigInt constructor should accept larger integers than safe-integers 4 https://bugs.webkit.org/show_bug.cgi?id=210755 5 6 Reviewed by Darin Adler. 7 8 While our implementation of BigInt constructor only accepts safe integers, it should accept all integers. 9 This patch implements it by creating JSBigInt::createFrom(double). We port double bit processing part from 10 V8 as the same to the other part of JSBigInt. 11 12 * runtime/BigIntConstructor.cpp: 13 (JSC::callBigIntConstructor): 14 * runtime/JSBigInt.cpp: 15 (JSC::JSBigInt::createFrom): 16 * runtime/JSBigInt.h: 17 * runtime/MathCommon.h: 18 (JSC::isInteger): 19 (JSC::isSafeInteger): 20 * runtime/NumberConstructor.cpp: 21 (JSC::numberConstructorFuncIsSafeInteger): 22 * runtime/NumberConstructor.h: 23 1 24 2020-04-28 Ross Kirsling <ross.kirsling@sony.com> 2 25 -
trunk/Source/JavaScriptCore/runtime/BigIntConstructor.cpp
r260683 r260863 123 123 124 124 if (primitive.isDouble()) { 125 // FIXME: Accept larger integers than safe-integers.126 // https://bugs.webkit.org/show_bug.cgi?id=210755127 125 double number = primitive.asDouble(); 128 if (trunc(number) != number || std::abs(number) > maxSafeInteger()) 129 return throwVMError(globalObject, scope, createRangeError(globalObject, "Not a safe integer"_s)); 130 131 return JSValue::encode(JSBigInt::makeHeapBigIntOrBigInt32(vm, static_cast<int64_t>(primitive.asDouble()))); 126 if (!isInteger(number)) 127 return throwVMError(globalObject, scope, createRangeError(globalObject, "Not an integer"_s)); 128 return JSValue::encode(JSBigInt::makeHeapBigIntOrBigInt32(vm, primitive.asDouble())); 132 129 } 133 130 -
trunk/Source/JavaScriptCore/runtime/JSBigInt.cpp
r260834 r260863 186 186 } 187 187 188 JSBigInt* JSBigInt::createFrom(VM& vm, double value) 189 { 190 ASSERT(isInteger(value)); 191 if (!value) 192 return createZero(vm); 193 194 bool sign = value < 0; // -0 was already handled above. 195 uint64_t doubleBits = bitwise_cast<uint64_t>(value); 196 int32_t rawExponent = static_cast<int32_t>(doubleBits >> doublePhysicalMantissaSize) & 0x7ff; 197 ASSERT(rawExponent != 0x7ff); // Since value is integer, exponent should not be 0x7ff (full bits, used for infinity etc.). 198 ASSERT(rawExponent >= 0x3ff); // Since value is integer, exponent should be >= 0 + bias (0x3ff). 199 int32_t exponent = rawExponent - 0x3ff; 200 int32_t digits = exponent / digitBits + 1; 201 JSBigInt* result = createWithLengthUnchecked(vm, digits); 202 ASSERT(result); 203 result->initialize(InitializationType::WithZero); 204 result->setSign(sign); 205 206 // We construct a BigInt from the double value by shifting its mantissa 207 // according to its exponent and mapping the bit pattern onto digits. 208 // 209 // <----------- bitlength = exponent + 1 -----------> 210 // <----- 52 ------> <------ trailing zeroes ------> 211 // mantissa: 1yyyyyyyyyyyyyyyyy 0000000000000000000000000000000 212 // digits: 0001xxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx 213 // <--> <------> 214 // msdTopBit digitBits 215 // 216 217 uint64_t mantissa = (doubleBits & doublePhysicalMantissaMask) | doubleMantissaHiddenBit; 218 219 int32_t mantissaTopBit = doubleMantissaSize - 1; // 0-indexed. 220 // 0-indexed position of most significant bit in the most significant digit. 221 int32_t msdTopBit = exponent % digitBits; 222 // Number of unused bits in mantissa. We'll keep them shifted to the 223 // left (i.e. most significant part) of the underlying uint64_t. 224 int32_t remainingMantissaBits = 0; 225 // Next digit under construction. 226 Digit digit = 0; 227 228 // First, build the MSD by shifting the mantissa appropriately. 229 if (msdTopBit < mantissaTopBit) { 230 remainingMantissaBits = mantissaTopBit - msdTopBit; 231 digit = mantissa >> remainingMantissaBits; 232 mantissa = mantissa << (64 - remainingMantissaBits); 233 } else { 234 ASSERT(msdTopBit >= mantissaTopBit); 235 digit = mantissa << (msdTopBit - mantissaTopBit); 236 mantissa = 0; 237 } 238 result->setDigit(digits - 1, digit); 239 // Then fill in the rest of the digits. 240 for (int32_t digitIndex = digits - 2; digitIndex >= 0; digitIndex--) { 241 if (remainingMantissaBits > 0) { 242 remainingMantissaBits -= digitBits; 243 if constexpr (sizeof(Digit) == 4) { 244 digit = mantissa >> 32; 245 mantissa = mantissa << 32; 246 } else { 247 ASSERT(sizeof(Digit) == 8); 248 digit = mantissa; 249 mantissa = 0; 250 } 251 } else 252 digit = 0; 253 result->setDigit(digitIndex, digit); 254 } 255 return result->rightTrim(vm); 256 } 257 188 258 JSValue JSBigInt::toPrimitive(JSGlobalObject*, PreferredPrimitiveType) const 189 259 { -
trunk/Source/JavaScriptCore/runtime/JSBigInt.h
r260834 r260863 32 32 #include "JSGlobalObject.h" 33 33 #include "JSObject.h" 34 #include "MathCommon.h" 34 35 #include <wtf/CagedUniquePtr.h> 35 36 #include <wtf/text/StringBuilder.h> … … 73 74 static JSBigInt* createFrom(VM&, int64_t value); 74 75 static JSBigInt* createFrom(VM&, bool value); 76 static JSBigInt* createFrom(VM&, double value); 75 77 76 78 static size_t offsetOfLength() … … 94 96 return jsBigInt32(static_cast<int32_t>(value)); 95 97 #endif 96 97 auto ptr = JSBigInt::createFrom(vm, value); 98 return JSValue(static_cast<JSCell*>(ptr)); 98 return JSBigInt::createFrom(vm, value); 99 } 100 101 static JSValue makeHeapBigIntOrBigInt32(VM& vm, double value) 102 { 103 ASSERT(isInteger(value)); 104 if (std::abs(value) <= maxSafeInteger()) 105 return makeHeapBigIntOrBigInt32(vm, static_cast<int64_t>(value)); 106 return JSBigInt::createFrom(vm, value); 99 107 } 100 108 … … 418 426 static constexpr int maxInt = 0x7FFFFFFF; 419 427 420 static constexpr unsigned doublePhysicalMantissaSize = 52; 428 static constexpr unsigned doubleMantissaSize = 53; 429 static constexpr unsigned doublePhysicalMantissaSize = 52; // Excluding hidden-bit. 430 static constexpr uint64_t doublePhysicalMantissaMask = (1ULL << doublePhysicalMantissaSize) - 1; 431 static constexpr uint64_t doubleMantissaHiddenBit = 1ULL << doublePhysicalMantissaSize; 421 432 422 433 // The maximum length that the current implementation supports would be -
trunk/Source/JavaScriptCore/runtime/MathCommon.h
r259320 r260863 49 49 } 50 50 51 inline bool isInteger(double value) 52 { 53 return std::isfinite(value) && std::trunc(value) == value; 54 } 55 56 inline bool isInteger(float value) 57 { 58 return std::isfinite(value) && std::trunc(value) == value; 59 } 60 61 inline bool isSafeInteger(double value) 62 { 63 return std::trunc(value) == value && std::abs(value) <= maxSafeInteger(); 64 } 65 51 66 // This in the ToInt32 operation is defined in section 9.5 of the ECMA-262 spec. 52 67 // Note that this operation is identical to ToUInt32 other than to interpretation -
trunk/Source/JavaScriptCore/runtime/NumberConstructor.cpp
r260834 r260863 141 141 { 142 142 JSValue argument = callFrame->argument(0); 143 bool isInteger;144 143 if (argument.isInt32()) 145 isInteger = true; 146 else if (!argument.isDouble()) 147 isInteger = false; 148 else { 149 double number = argument.asDouble(); 150 isInteger = trunc(number) == number && std::abs(number) <= maxSafeInteger(); 151 } 152 return JSValue::encode(jsBoolean(isInteger)); 144 return JSValue::encode(jsBoolean(true)); 145 if (!argument.isDouble()) 146 return JSValue::encode(jsBoolean(false)); 147 return JSValue::encode(jsBoolean(isSafeInteger(argument.asDouble()))); 153 148 } 154 149 -
trunk/Source/JavaScriptCore/runtime/NumberConstructor.h
r260415 r260863 22 22 23 23 #include "InternalFunction.h" 24 #include "MathCommon.h" 24 25 25 26 namespace JSC { … … 49 50 static bool isIntegerImpl(JSValue value) 50 51 { 51 if (value.isInt32()) 52 return true; 53 if (!value.isDouble()) 54 return false; 55 56 double number = value.asDouble(); 57 return std::isfinite(number) && trunc(number) == number; 52 return value.isInt32() || (value.isDouble() && isInteger(value.asDouble())); 58 53 } 59 54
Note: See TracChangeset
for help on using the changeset viewer.