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/. */
7 #include "builtin/BigInt.h"
9 #include "jit/InlinableNatives.h"
10 #include "js/friend/ErrorMessages.h" // js::GetErrorMessage, JSMSG_*
11 #include "js/PropertySpec.h"
12 #include "vm/BigIntType.h"
14 #include "vm/GeckoProfiler-inl.h"
15 #include "vm/JSObject-inl.h"
19 static MOZ_ALWAYS_INLINE
bool IsBigInt(HandleValue v
) {
20 return v
.isBigInt() || (v
.isObject() && v
.toObject().is
<BigIntObject
>());
23 // BigInt proposal section 5.1.3
24 static bool BigIntConstructor(JSContext
* cx
, unsigned argc
, Value
* vp
) {
25 AutoJSConstructorProfilerEntry
pseudoFrame(cx
, "BigInt");
26 CallArgs args
= CallArgsFromVp(argc
, vp
);
29 if (args
.isConstructing()) {
30 JS_ReportErrorNumberASCII(cx
, GetErrorMessage
, nullptr,
31 JSMSG_NOT_CONSTRUCTOR
, "BigInt");
36 RootedValue
v(cx
, args
.get(0));
37 if (!ToPrimitive(cx
, JSTYPE_NUMBER
, &v
)) {
43 v
.isNumber() ? NumberToBigInt(cx
, v
.toNumber()) : ToBigInt(cx
, v
);
48 args
.rval().setBigInt(bi
);
52 JSObject
* BigIntObject::create(JSContext
* cx
, HandleBigInt bigInt
) {
53 BigIntObject
* bn
= NewBuiltinClassInstance
<BigIntObject
>(cx
);
57 bn
->setFixedSlot(PRIMITIVE_VALUE_SLOT
, BigIntValue(bigInt
));
61 BigInt
* BigIntObject::unbox() const {
62 return getFixedSlot(PRIMITIVE_VALUE_SLOT
).toBigInt();
65 // BigInt proposal section 5.3.4
66 bool BigIntObject::valueOf_impl(JSContext
* cx
, const CallArgs
& args
) {
68 HandleValue thisv
= args
.thisv();
69 MOZ_ASSERT(IsBigInt(thisv
));
70 BigInt
* bi
= thisv
.isBigInt() ? thisv
.toBigInt()
71 : thisv
.toObject().as
<BigIntObject
>().unbox();
73 args
.rval().setBigInt(bi
);
77 bool BigIntObject::valueOf(JSContext
* cx
, unsigned argc
, Value
* vp
) {
78 CallArgs args
= CallArgsFromVp(argc
, vp
);
79 return CallNonGenericMethod
<IsBigInt
, valueOf_impl
>(cx
, args
);
82 // BigInt proposal section 5.3.3
83 bool BigIntObject::toString_impl(JSContext
* cx
, const CallArgs
& args
) {
85 HandleValue thisv
= args
.thisv();
86 MOZ_ASSERT(IsBigInt(thisv
));
87 RootedBigInt
bi(cx
, thisv
.isBigInt()
89 : thisv
.toObject().as
<BigIntObject
>().unbox());
95 if (args
.hasDefined(0)) {
97 if (!ToInteger(cx
, args
[0], &d
)) {
100 if (d
< 2 || d
> 36) {
101 JS_ReportErrorNumberASCII(cx
, GetErrorMessage
, nullptr, JSMSG_BAD_RADIX
);
108 JSLinearString
* str
= BigInt::toString
<CanGC
>(cx
, bi
, radix
);
112 args
.rval().setString(str
);
116 bool BigIntObject::toString(JSContext
* cx
, unsigned argc
, Value
* vp
) {
117 AutoJSMethodProfilerEntry
pseudoFrame(cx
, "BigInt.prototype", "toString");
118 CallArgs args
= CallArgsFromVp(argc
, vp
);
119 return CallNonGenericMethod
<IsBigInt
, toString_impl
>(cx
, args
);
122 #ifndef JS_HAS_INTL_API
123 // BigInt proposal section 5.3.2. "This function is
124 // implementation-dependent, and it is permissible, but not encouraged,
125 // for it to return the same thing as toString."
126 bool BigIntObject::toLocaleString_impl(JSContext
* cx
, const CallArgs
& args
) {
127 HandleValue thisv
= args
.thisv();
128 MOZ_ASSERT(IsBigInt(thisv
));
129 RootedBigInt
bi(cx
, thisv
.isBigInt()
131 : thisv
.toObject().as
<BigIntObject
>().unbox());
133 JSString
* str
= BigInt::toString
<CanGC
>(cx
, bi
, 10);
137 args
.rval().setString(str
);
141 bool BigIntObject::toLocaleString(JSContext
* cx
, unsigned argc
, Value
* vp
) {
142 AutoJSMethodProfilerEntry
pseudoFrame(cx
, "BigInt.prototype",
144 CallArgs args
= CallArgsFromVp(argc
, vp
);
145 return CallNonGenericMethod
<IsBigInt
, toLocaleString_impl
>(cx
, args
);
147 #endif /* !JS_HAS_INTL_API */
149 // BigInt proposal section 5.2.1. BigInt.asUintN ( bits, bigint )
150 bool BigIntObject::asUintN(JSContext
* cx
, unsigned argc
, Value
* vp
) {
151 CallArgs args
= CallArgsFromVp(argc
, vp
);
155 if (!ToIndex(cx
, args
.get(0), &bits
)) {
160 RootedBigInt
bi(cx
, ToBigInt(cx
, args
.get(1)));
166 BigInt
* res
= BigInt::asUintN(cx
, bi
, bits
);
171 args
.rval().setBigInt(res
);
175 // BigInt proposal section 5.2.2. BigInt.asIntN ( bits, bigint )
176 bool BigIntObject::asIntN(JSContext
* cx
, unsigned argc
, Value
* vp
) {
177 CallArgs args
= CallArgsFromVp(argc
, vp
);
181 if (!ToIndex(cx
, args
.get(0), &bits
)) {
186 RootedBigInt
bi(cx
, ToBigInt(cx
, args
.get(1)));
192 BigInt
* res
= BigInt::asIntN(cx
, bi
, bits
);
197 args
.rval().setBigInt(res
);
201 const ClassSpec
BigIntObject::classSpec_
= {
202 GenericCreateConstructor
<BigIntConstructor
, 1, gc::AllocKind::FUNCTION
>,
203 GenericCreatePrototype
<BigIntObject
>,
204 BigIntObject::staticMethods
,
206 BigIntObject::methods
,
207 BigIntObject::properties
};
209 const JSClass
BigIntObject::class_
= {
211 JSCLASS_HAS_CACHED_PROTO(JSProto_BigInt
) |
212 JSCLASS_HAS_RESERVED_SLOTS(RESERVED_SLOTS
),
213 JS_NULL_CLASS_OPS
, &BigIntObject::classSpec_
};
215 const JSClass
BigIntObject::protoClass_
= {
216 "BigInt.prototype", JSCLASS_HAS_CACHED_PROTO(JSProto_BigInt
),
217 JS_NULL_CLASS_OPS
, &BigIntObject::classSpec_
};
219 const JSPropertySpec
BigIntObject::properties
[] = {
220 // BigInt proposal section 5.3.5
221 JS_STRING_SYM_PS(toStringTag
, "BigInt", JSPROP_READONLY
), JS_PS_END
};
223 const JSFunctionSpec
BigIntObject::methods
[] = {
224 JS_FN("valueOf", valueOf
, 0, 0), JS_FN("toString", toString
, 0, 0),
225 #ifdef JS_HAS_INTL_API
226 JS_SELF_HOSTED_FN("toLocaleString", "BigInt_toLocaleString", 0, 0),
228 JS_FN("toLocaleString", toLocaleString
, 0, 0),
232 const JSFunctionSpec
BigIntObject::staticMethods
[] = {
233 JS_INLINABLE_FN("asUintN", asUintN
, 2, 0, BigIntAsUintN
),
234 JS_INLINABLE_FN("asIntN", asIntN
, 2, 0, BigIntAsIntN
), JS_FS_END
};