tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

BigInt.cpp (7519B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
      2 * vim: set ts=8 sts=2 et sw=2 tw=80:
      3 * This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "builtin/BigInt.h"
      8 
      9 #if JS_HAS_INTL_API
     10 #  include "builtin/intl/GlobalIntlData.h"
     11 #  include "builtin/intl/NumberFormat.h"
     12 #endif
     13 #include "jit/InlinableNatives.h"
     14 #include "js/friend/ErrorMessages.h"  // js::GetErrorMessage, JSMSG_*
     15 #include "js/PropertySpec.h"
     16 #include "vm/BigIntType.h"
     17 
     18 #include "vm/GeckoProfiler-inl.h"
     19 #include "vm/JSObject-inl.h"
     20 
     21 using namespace js;
     22 
     23 static MOZ_ALWAYS_INLINE bool IsBigInt(HandleValue v) {
     24  return v.isBigInt() || (v.isObject() && v.toObject().is<BigIntObject>());
     25 }
     26 
     27 // BigInt proposal section 5.1.3
     28 static bool BigIntConstructor(JSContext* cx, unsigned argc, Value* vp) {
     29  AutoJSConstructorProfilerEntry pseudoFrame(cx, "BigInt");
     30  CallArgs args = CallArgsFromVp(argc, vp);
     31 
     32  // Step 1.
     33  if (args.isConstructing()) {
     34    JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
     35                              JSMSG_NOT_CONSTRUCTOR, "BigInt");
     36    return false;
     37  }
     38 
     39  // Step 2.
     40  RootedValue v(cx, args.get(0));
     41  if (!ToPrimitive(cx, JSTYPE_NUMBER, &v)) {
     42    return false;
     43  }
     44 
     45  // Steps 3-4.
     46  BigInt* bi;
     47  if (!v.isNumber()) {
     48    bi = ToBigInt(cx, v);
     49  } else if (v.isInt32()) {
     50    bi = BigInt::createFromInt64(cx, int64_t(v.toInt32()));
     51  } else {
     52    bi = NumberToBigInt(cx, v.toDouble());
     53  }
     54  if (!bi) {
     55    return false;
     56  }
     57 
     58  args.rval().setBigInt(bi);
     59  return true;
     60 }
     61 
     62 JSObject* BigIntObject::create(JSContext* cx, HandleBigInt bigInt) {
     63  BigIntObject* bn = NewBuiltinClassInstance<BigIntObject>(cx);
     64  if (!bn) {
     65    return nullptr;
     66  }
     67  bn->initFixedSlot(PRIMITIVE_VALUE_SLOT, BigIntValue(bigInt));
     68  return bn;
     69 }
     70 
     71 BigInt* BigIntObject::unbox() const {
     72  return getFixedSlot(PRIMITIVE_VALUE_SLOT).toBigInt();
     73 }
     74 
     75 static BigInt* ThisBigIntValue(const CallArgs& args) {
     76  HandleValue thisv = args.thisv();
     77  MOZ_ASSERT(IsBigInt(thisv));
     78 
     79  return thisv.isBigInt() ? thisv.toBigInt()
     80                          : thisv.toObject().as<BigIntObject>().unbox();
     81 }
     82 
     83 /**
     84 * BigInt.prototype.valueOf ( )
     85 *
     86 * ES2025 draft rev e42d11da7753bd933b1e7a5f3cb657ab0a8f6251
     87 */
     88 bool BigIntObject::valueOf_impl(JSContext* cx, const CallArgs& args) {
     89  // Step 1.
     90  args.rval().setBigInt(ThisBigIntValue(args));
     91  return true;
     92 }
     93 
     94 /**
     95 * BigInt.prototype.valueOf ( )
     96 *
     97 * ES2025 draft rev e42d11da7753bd933b1e7a5f3cb657ab0a8f6251
     98 */
     99 bool BigIntObject::valueOf(JSContext* cx, unsigned argc, Value* vp) {
    100  CallArgs args = CallArgsFromVp(argc, vp);
    101  return CallNonGenericMethod<IsBigInt, valueOf_impl>(cx, args);
    102 }
    103 
    104 /**
    105 * BigInt.prototype.toString ( [ radix ] )
    106 *
    107 * ES2025 draft rev e42d11da7753bd933b1e7a5f3cb657ab0a8f6251
    108 */
    109 bool BigIntObject::toString_impl(JSContext* cx, const CallArgs& args) {
    110  // Step 1.
    111  RootedBigInt bi(cx, ThisBigIntValue(args));
    112 
    113  // Step 2.
    114  uint8_t radix = 10;
    115 
    116  // Steps 3-4.
    117  if (args.hasDefined(0)) {
    118    double d;
    119    if (!ToInteger(cx, args[0], &d)) {
    120      return false;
    121    }
    122    if (d < 2 || d > 36) {
    123      JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BAD_RADIX);
    124      return false;
    125    }
    126    radix = d;
    127  }
    128 
    129  // Step 5.
    130  JSLinearString* str = BigInt::toString<CanGC>(cx, bi, radix);
    131  if (!str) {
    132    return false;
    133  }
    134  args.rval().setString(str);
    135  return true;
    136 }
    137 
    138 bool BigIntObject::toString(JSContext* cx, unsigned argc, Value* vp) {
    139  AutoJSMethodProfilerEntry pseudoFrame(cx, "BigInt.prototype", "toString");
    140  CallArgs args = CallArgsFromVp(argc, vp);
    141  return CallNonGenericMethod<IsBigInt, toString_impl>(cx, args);
    142 }
    143 
    144 /**
    145 * BigInt.prototype.toLocaleString ( [ reserved1 [ , reserved2 ] ] )
    146 *
    147 * ES2025 draft rev e42d11da7753bd933b1e7a5f3cb657ab0a8f6251
    148 *
    149 * BigInt.prototype.toLocaleString ( [ locales [ , options ] ] )
    150 *
    151 * ES2025 Intl draft rev 6827e6e40b45fb313472595be31352451a2d85fa
    152 */
    153 bool BigIntObject::toLocaleString_impl(JSContext* cx, const CallArgs& args) {
    154  // Step 1.
    155  RootedBigInt bi(cx, ThisBigIntValue(args));
    156 
    157 #if JS_HAS_INTL_API
    158  HandleValue locales = args.get(0);
    159  HandleValue options = args.get(1);
    160 
    161  // Step 2.
    162  Rooted<NumberFormatObject*> numberFormat(
    163      cx, intl::GetOrCreateNumberFormat(cx, locales, options));
    164  if (!numberFormat) {
    165    return false;
    166  }
    167 
    168  // Step 3.
    169  JSString* str = intl::FormatBigInt(cx, numberFormat, bi);
    170  if (!str) {
    171    return false;
    172  }
    173  args.rval().setString(str);
    174  return true;
    175 #else
    176  // This method is implementation-defined, and it is permissible, but not
    177  // encouraged, for it to return the same thing as toString.
    178  JSString* str = BigInt::toString<CanGC>(cx, bi, 10);
    179  if (!str) {
    180    return false;
    181  }
    182  args.rval().setString(str);
    183  return true;
    184 #endif
    185 }
    186 
    187 bool BigIntObject::toLocaleString(JSContext* cx, unsigned argc, Value* vp) {
    188  AutoJSMethodProfilerEntry pseudoFrame(cx, "BigInt.prototype",
    189                                        "toLocaleString");
    190  CallArgs args = CallArgsFromVp(argc, vp);
    191  return CallNonGenericMethod<IsBigInt, toLocaleString_impl>(cx, args);
    192 }
    193 
    194 // BigInt proposal section 5.2.1. BigInt.asUintN ( bits, bigint )
    195 bool BigIntObject::asUintN(JSContext* cx, unsigned argc, Value* vp) {
    196  CallArgs args = CallArgsFromVp(argc, vp);
    197 
    198  // Step 1.
    199  uint64_t bits;
    200  if (!ToIndex(cx, args.get(0), &bits)) {
    201    return false;
    202  }
    203 
    204  // Step 2.
    205  RootedBigInt bi(cx, ToBigInt(cx, args.get(1)));
    206  if (!bi) {
    207    return false;
    208  }
    209 
    210  // Step 3.
    211  BigInt* res = BigInt::asUintN(cx, bi, bits);
    212  if (!res) {
    213    return false;
    214  }
    215 
    216  args.rval().setBigInt(res);
    217  return true;
    218 }
    219 
    220 // BigInt proposal section 5.2.2. BigInt.asIntN ( bits, bigint )
    221 bool BigIntObject::asIntN(JSContext* cx, unsigned argc, Value* vp) {
    222  CallArgs args = CallArgsFromVp(argc, vp);
    223 
    224  // Step 1.
    225  uint64_t bits;
    226  if (!ToIndex(cx, args.get(0), &bits)) {
    227    return false;
    228  }
    229 
    230  // Step 2.
    231  RootedBigInt bi(cx, ToBigInt(cx, args.get(1)));
    232  if (!bi) {
    233    return false;
    234  }
    235 
    236  // Step 3.
    237  BigInt* res = BigInt::asIntN(cx, bi, bits);
    238  if (!res) {
    239    return false;
    240  }
    241 
    242  args.rval().setBigInt(res);
    243  return true;
    244 }
    245 
    246 const ClassSpec BigIntObject::classSpec_ = {
    247    GenericCreateConstructor<BigIntConstructor, 1, gc::AllocKind::FUNCTION,
    248                             &jit::JitInfo_BigInt>,
    249    GenericCreatePrototype<BigIntObject>,
    250    BigIntObject::staticMethods,
    251    nullptr,
    252    BigIntObject::methods,
    253    BigIntObject::properties,
    254 };
    255 
    256 const JSClass BigIntObject::class_ = {
    257    "BigInt",
    258    JSCLASS_HAS_CACHED_PROTO(JSProto_BigInt) |
    259        JSCLASS_HAS_RESERVED_SLOTS(RESERVED_SLOTS),
    260    JS_NULL_CLASS_OPS,
    261    &BigIntObject::classSpec_,
    262 };
    263 
    264 const JSClass BigIntObject::protoClass_ = {
    265    "BigInt.prototype",
    266    JSCLASS_HAS_CACHED_PROTO(JSProto_BigInt),
    267    JS_NULL_CLASS_OPS,
    268    &BigIntObject::classSpec_,
    269 };
    270 
    271 const JSPropertySpec BigIntObject::properties[] = {
    272    // BigInt proposal section 5.3.5
    273    JS_STRING_SYM_PS(toStringTag, "BigInt", JSPROP_READONLY),
    274    JS_PS_END,
    275 };
    276 
    277 const JSFunctionSpec BigIntObject::methods[] = {
    278    JS_FN("valueOf", valueOf, 0, 0),
    279    JS_FN("toString", toString, 0, 0),
    280    JS_FN("toLocaleString", toLocaleString, 0, 0),
    281    JS_FS_END,
    282 };
    283 
    284 const JSFunctionSpec BigIntObject::staticMethods[] = {
    285    JS_INLINABLE_FN("asUintN", asUintN, 2, 0, BigIntAsUintN),
    286    JS_INLINABLE_FN("asIntN", asIntN, 2, 0, BigIntAsIntN),
    287    JS_FS_END,
    288 };