#include "builtin/BigInt.h"
#include "jsapi.h"
#include "builtin/TypedObject.h"
#include "gc/Tracer.h"
#include "js/PropertySpec.h"
#include "js/TracingAPI.h"
#include "vm/ArrayBufferObject.h"
#include "vm/BigIntType.h"
#include "vm/SelfHosting.h"
#include "vm/TaggedProto.h"
#include "vm/JSObject-inl.h"
using namespace js;
static MOZ_ALWAYS_INLINE bool IsBigInt(HandleValue v) {
return v.isBigInt() || (v.isObject() && v.toObject().is<BigIntObject>());
}
static bool BigIntConstructor(JSContext* cx, unsigned argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
if (args.isConstructing()) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
JSMSG_NOT_CONSTRUCTOR, "BigInt");
return false;
}
RootedValue v(cx, args.get(0));
if (!ToPrimitive(cx, JSTYPE_NUMBER, &v)) {
return false;
}
BigInt* bi =
v.isNumber() ? NumberToBigInt(cx, v.toNumber()) : ToBigInt(cx, v);
if (!bi) {
return false;
}
args.rval().setBigInt(bi);
return true;
}
JSObject* BigIntObject::create(JSContext* cx, HandleBigInt bigInt) {
RootedObject obj(cx, NewBuiltinClassInstance(cx, &class_));
if (!obj) {
return nullptr;
}
BigIntObject& bn = obj->as<BigIntObject>();
bn.setFixedSlot(PRIMITIVE_VALUE_SLOT, BigIntValue(bigInt));
return &bn;
}
BigInt* BigIntObject::unbox() const {
return getFixedSlot(PRIMITIVE_VALUE_SLOT).toBigInt();
}
bool BigIntObject::valueOf_impl(JSContext* cx, const CallArgs& args) {
HandleValue thisv = args.thisv();
MOZ_ASSERT(IsBigInt(thisv));
RootedBigInt bi(cx, thisv.isBigInt()
? thisv.toBigInt()
: thisv.toObject().as<BigIntObject>().unbox());
args.rval().setBigInt(bi);
return true;
}
bool BigIntObject::valueOf(JSContext* cx, unsigned argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
return CallNonGenericMethod<IsBigInt, valueOf_impl>(cx, args);
}
bool BigIntObject::toString_impl(JSContext* cx, const CallArgs& args) {
HandleValue thisv = args.thisv();
MOZ_ASSERT(IsBigInt(thisv));
RootedBigInt bi(cx, thisv.isBigInt()
? thisv.toBigInt()
: thisv.toObject().as<BigIntObject>().unbox());
uint8_t radix = 10;
if (args.hasDefined(0)) {
double d;
if (!ToInteger(cx, args[0], &d)) {
return false;
}
if (d < 2 || d > 36) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BAD_RADIX);
return false;
}
radix = d;
}
JSLinearString* str = BigInt::toString<CanGC>(cx, bi, radix);
if (!str) {
return false;
}
args.rval().setString(str);
return true;
}
bool BigIntObject::toString(JSContext* cx, unsigned argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
return CallNonGenericMethod<IsBigInt, toString_impl>(cx, args);
}
bool BigIntObject::toLocaleString_impl(JSContext* cx, const CallArgs& args) {
HandleValue thisv = args.thisv();
MOZ_ASSERT(IsBigInt(thisv));
RootedBigInt bi(cx, thisv.isBigInt()
? thisv.toBigInt()
: thisv.toObject().as<BigIntObject>().unbox());
RootedString str(cx, BigInt::toString<CanGC>(cx, bi, 10));
if (!str) {
return false;
}
args.rval().setString(str);
return true;
}
bool BigIntObject::toLocaleString(JSContext* cx, unsigned argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
return CallNonGenericMethod<IsBigInt, toLocaleString_impl>(cx, args);
}
bool BigIntObject::asUintN(JSContext* cx, unsigned argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
uint64_t bits;
if (!ToIndex(cx, args.get(0), &bits)) {
return false;
}
RootedBigInt bi(cx, ToBigInt(cx, args.get(1)));
if (!bi) {
return false;
}
BigInt* res = BigInt::asUintN(cx, bi, bits);
if (!res) {
return false;
}
args.rval().setBigInt(res);
return true;
}
bool BigIntObject::asIntN(JSContext* cx, unsigned argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
uint64_t bits;
if (!ToIndex(cx, args.get(0), &bits)) {
return false;
}
RootedBigInt bi(cx, ToBigInt(cx, args.get(1)));
if (!bi) {
return false;
}
BigInt* res = BigInt::asIntN(cx, bi, bits);
if (!res) {
return false;
}
args.rval().setBigInt(res);
return true;
}
const ClassSpec BigIntObject::classSpec_ = {
GenericCreateConstructor<BigIntConstructor, 1, gc::AllocKind::FUNCTION>,
GenericCreatePrototype<BigIntObject>,
BigIntObject::staticMethods,
nullptr,
BigIntObject::methods,
BigIntObject::properties};
const Class BigIntObject::class_ = {
"Object",
JSCLASS_HAS_CACHED_PROTO(JSProto_BigInt) |
JSCLASS_HAS_RESERVED_SLOTS(RESERVED_SLOTS),
JS_NULL_CLASS_OPS, &BigIntObject::classSpec_};
const Class BigIntObject::protoClass_ = {
js_Object_str, JSCLASS_HAS_CACHED_PROTO(JSProto_BigInt), JS_NULL_CLASS_OPS,
&BigIntObject::classSpec_};
const JSPropertySpec BigIntObject::properties[] = {
JS_STRING_SYM_PS(toStringTag, "BigInt", JSPROP_READONLY), JS_PS_END};
const JSFunctionSpec BigIntObject::methods[] = {
JS_FN("valueOf", valueOf, 0, 0), JS_FN("toString", toString, 0, 0),
JS_FN("toLocaleString", toLocaleString, 0, 0), JS_FS_END};
const JSFunctionSpec BigIntObject::staticMethods[] = {
JS_FN("asUintN", asUintN, 2, 0), JS_FN("asIntN", asIntN, 2, 0), JS_FS_END};