diff --git a/js/src/builtin/Array.cpp b/js/src/builtin/Array.cpp index f8d7aee344fc..25218f0a5a0d 100644 --- a/js/src/builtin/Array.cpp +++ b/js/src/builtin/Array.cpp @@ -154,7 +154,7 @@ bool js::GetLengthProperty(JSContext* cx, HandleObject obj, uint32_t* lengthp) { } // ES2017 7.1.15 ToLength. -static bool ToLength(JSContext* cx, HandleValue v, uint64_t* out) { +bool js::ToLength(JSContext* cx, HandleValue v, uint64_t* out) { if (v.isInt32()) { int32_t i = v.toInt32(); *out = i < 0 ? 0 : i; diff --git a/js/src/builtin/Array.h b/js/src/builtin/Array.h index de2b924a2cef..522f0745d8c1 100644 --- a/js/src/builtin/Array.h +++ b/js/src/builtin/Array.h @@ -118,6 +118,8 @@ extern ArrayObject* NewArrayWithGroup(JSContext* cx, uint32_t length, HandleObjectGroup group, bool convertDoubleElements); +extern bool ToLength(JSContext* cx, HandleValue v, uint64_t* out); + extern bool GetLengthProperty(JSContext* cx, HandleObject obj, uint32_t* lengthp); diff --git a/js/src/builtin/Utilities.js b/js/src/builtin/Utilities.js index 149ebb578cfe..787b10ce790f 100644 --- a/js/src/builtin/Utilities.js +++ b/js/src/builtin/Utilities.js @@ -75,20 +75,6 @@ function RequireObjectCoercible(v) { ThrowTypeError(JSMSG_CANT_CONVERT_TO, ToString(v), "object"); } -/* Spec: ECMAScript Draft, 6 edition May 22, 2014, 7.1.15 */ -function ToLength(v) { - // Step 1. - v = ToInteger(v); - - // Step 2. - // Use max(v, 0) here, because it's easier to optimize in Ion. - v = std_Math_max(v, 0); - - // Step 3. - // Math.pow(2, 53) - 1 = 0x1fffffffffffff - return std_Math_min(v, 0x1fffffffffffff); -} - // ES2017 draft rev aebf014403a3e641fb1622aec47c40f051943527 // 7.2.10 SameValueZero ( x, y ) function SameValueZero(x, y) { diff --git a/js/src/vm/SelfHosting.cpp b/js/src/vm/SelfHosting.cpp index 7266f170ba96..bddf5826d29b 100644 --- a/js/src/vm/SelfHosting.cpp +++ b/js/src/vm/SelfHosting.cpp @@ -159,6 +159,26 @@ static bool intrinsic_IsCrossRealmArrayConstructor(JSContext* cx, unsigned argc, return true; } +static bool intrinsic_ToLength(JSContext* cx, unsigned argc, Value* vp) { + CallArgs args = CallArgsFromVp(argc, vp); + MOZ_ASSERT(args.length() == 1); + + // Inline fast path for the common case. + if (args[0].isInt32()) { + int32_t i = args[0].toInt32(); + args.rval().setInt32(i < 0 ? 0 : i); + return true; + } + + uint64_t length = 0; + if (!ToLength(cx, args[0], &length)) { + return false; + } + + args.rval().setNumber(double(length)); + return true; +} + static bool intrinsic_ToInteger(JSContext* cx, unsigned argc, Value* vp) { CallArgs args = CallArgsFromVp(argc, vp); double result; @@ -2140,6 +2160,7 @@ static const JSFunctionSpec intrinsic_functions[] = { intrinsic_IsCrossRealmArrayConstructor, 1, 0, IntrinsicIsCrossRealmArrayConstructor), JS_INLINABLE_FN("ToInteger", intrinsic_ToInteger, 1, 0, IntrinsicToInteger), + JS_FN("ToLength", intrinsic_ToLength, 1, 0), JS_INLINABLE_FN("ToString", intrinsic_ToString, 1, 0, IntrinsicToString), JS_FN("ToSource", intrinsic_ToSource, 1, 0), JS_FN("ToPropertyKey", intrinsic_ToPropertyKey, 1, 0),