Source code

Revision control

Other Tools

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
#include "jsapi.h"
10
11
#include "builtin/TypedObject.h"
12
#include "gc/Tracer.h"
13
#include "js/PropertySpec.h"
14
#include "js/TracingAPI.h"
15
#include "vm/ArrayBufferObject.h"
16
#include "vm/BigIntType.h"
17
#include "vm/SelfHosting.h"
18
#include "vm/TaggedProto.h"
19
20
#include "vm/JSObject-inl.h"
21
22
using namespace js;
23
24
static MOZ_ALWAYS_INLINE bool IsBigInt(HandleValue v) {
25
return v.isBigInt() || (v.isObject() && v.toObject().is<BigIntObject>());
26
}
27
28
// BigInt proposal section 5.1.3
29
static bool BigIntConstructor(JSContext* cx, unsigned argc, Value* vp) {
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
v.isNumber() ? NumberToBigInt(cx, v.toNumber()) : ToBigInt(cx, v);
48
if (!bi) {
49
return false;
50
}
51
52
args.rval().setBigInt(bi);
53
return true;
54
}
55
56
JSObject* BigIntObject::create(JSContext* cx, HandleBigInt bigInt) {
57
RootedObject obj(cx, NewBuiltinClassInstance(cx, &class_));
58
if (!obj) {
59
return nullptr;
60
}
61
BigIntObject& bn = obj->as<BigIntObject>();
62
bn.setFixedSlot(PRIMITIVE_VALUE_SLOT, BigIntValue(bigInt));
63
return &bn;
64
}
65
66
BigInt* BigIntObject::unbox() const {
67
return getFixedSlot(PRIMITIVE_VALUE_SLOT).toBigInt();
68
}
69
70
// BigInt proposal section 5.3.4
71
bool BigIntObject::valueOf_impl(JSContext* cx, const CallArgs& args) {
72
// Step 1.
73
HandleValue thisv = args.thisv();
74
MOZ_ASSERT(IsBigInt(thisv));
75
RootedBigInt bi(cx, thisv.isBigInt()
76
? thisv.toBigInt()
77
: thisv.toObject().as<BigIntObject>().unbox());
78
79
args.rval().setBigInt(bi);
80
return true;
81
}
82
83
bool BigIntObject::valueOf(JSContext* cx, unsigned argc, Value* vp) {
84
CallArgs args = CallArgsFromVp(argc, vp);
85
return CallNonGenericMethod<IsBigInt, valueOf_impl>(cx, args);
86
}
87
88
// BigInt proposal section 5.3.3
89
bool BigIntObject::toString_impl(JSContext* cx, const CallArgs& args) {
90
// Step 1.
91
HandleValue thisv = args.thisv();
92
MOZ_ASSERT(IsBigInt(thisv));
93
RootedBigInt bi(cx, thisv.isBigInt()
94
? thisv.toBigInt()
95
: thisv.toObject().as<BigIntObject>().unbox());
96
97
// Steps 2-3.
98
uint8_t radix = 10;
99
100
// Steps 4-5.
101
if (args.hasDefined(0)) {
102
double d;
103
if (!ToInteger(cx, args[0], &d)) {
104
return false;
105
}
106
if (d < 2 || d > 36) {
107
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BAD_RADIX);
108
return false;
109
}
110
radix = d;
111
}
112
113
// Steps 6-7.
114
JSLinearString* str = BigInt::toString<CanGC>(cx, bi, radix);
115
if (!str) {
116
return false;
117
}
118
args.rval().setString(str);
119
return true;
120
}
121
122
bool BigIntObject::toString(JSContext* cx, unsigned argc, Value* vp) {
123
CallArgs args = CallArgsFromVp(argc, vp);
124
return CallNonGenericMethod<IsBigInt, toString_impl>(cx, args);
125
}
126
127
#ifndef ENABLE_INTL_API
128
// BigInt proposal section 5.3.2. "This function is
129
// implementation-dependent, and it is permissible, but not encouraged,
130
// for it to return the same thing as toString."
131
bool BigIntObject::toLocaleString_impl(JSContext* cx, const CallArgs& args) {
132
HandleValue thisv = args.thisv();
133
MOZ_ASSERT(IsBigInt(thisv));
134
RootedBigInt bi(cx, thisv.isBigInt()
135
? thisv.toBigInt()
136
: thisv.toObject().as<BigIntObject>().unbox());
137
138
RootedString str(cx, BigInt::toString<CanGC>(cx, bi, 10));
139
if (!str) {
140
return false;
141
}
142
args.rval().setString(str);
143
return true;
144
}
145
146
bool BigIntObject::toLocaleString(JSContext* cx, unsigned argc, Value* vp) {
147
CallArgs args = CallArgsFromVp(argc, vp);
148
return CallNonGenericMethod<IsBigInt, toLocaleString_impl>(cx, args);
149
}
150
#endif /* !ENABLE_INTL_API */
151
152
// BigInt proposal section 5.2.1. BigInt.asUintN ( bits, bigint )
153
bool BigIntObject::asUintN(JSContext* cx, unsigned argc, Value* vp) {
154
CallArgs args = CallArgsFromVp(argc, vp);
155
156
// Step 1.
157
uint64_t bits;
158
if (!ToIndex(cx, args.get(0), &bits)) {
159
return false;
160
}
161
162
// Step 2.
163
RootedBigInt bi(cx, ToBigInt(cx, args.get(1)));
164
if (!bi) {
165
return false;
166
}
167
168
// Step 3.
169
BigInt* res = BigInt::asUintN(cx, bi, bits);
170
if (!res) {
171
return false;
172
}
173
174
args.rval().setBigInt(res);
175
return true;
176
}
177
178
// BigInt proposal section 5.2.2. BigInt.asIntN ( bits, bigint )
179
bool BigIntObject::asIntN(JSContext* cx, unsigned argc, Value* vp) {
180
CallArgs args = CallArgsFromVp(argc, vp);
181
182
// Step 1.
183
uint64_t bits;
184
if (!ToIndex(cx, args.get(0), &bits)) {
185
return false;
186
}
187
188
// Step 2.
189
RootedBigInt bi(cx, ToBigInt(cx, args.get(1)));
190
if (!bi) {
191
return false;
192
}
193
194
// Step 3.
195
BigInt* res = BigInt::asIntN(cx, bi, bits);
196
if (!res) {
197
return false;
198
}
199
200
args.rval().setBigInt(res);
201
return true;
202
}
203
204
const ClassSpec BigIntObject::classSpec_ = {
205
GenericCreateConstructor<BigIntConstructor, 1, gc::AllocKind::FUNCTION>,
206
GenericCreatePrototype<BigIntObject>,
207
BigIntObject::staticMethods,
208
nullptr,
209
BigIntObject::methods,
210
BigIntObject::properties};
211
212
// The class is named "Object" as a workaround for bug 1277801.
213
const JSClass BigIntObject::class_ = {
214
"Object",
215
JSCLASS_HAS_CACHED_PROTO(JSProto_BigInt) |
216
JSCLASS_HAS_RESERVED_SLOTS(RESERVED_SLOTS),
217
JS_NULL_CLASS_OPS, &BigIntObject::classSpec_};
218
219
const JSClass BigIntObject::protoClass_ = {
220
js_Object_str, JSCLASS_HAS_CACHED_PROTO(JSProto_BigInt), JS_NULL_CLASS_OPS,
221
&BigIntObject::classSpec_};
222
223
const JSPropertySpec BigIntObject::properties[] = {
224
// BigInt proposal section 5.3.5
225
JS_STRING_SYM_PS(toStringTag, "BigInt", JSPROP_READONLY), JS_PS_END};
226
227
const JSFunctionSpec BigIntObject::methods[] = {
228
JS_FN("valueOf", valueOf, 0, 0), JS_FN("toString", toString, 0, 0),
229
#ifdef ENABLE_INTL_API
230
JS_SELF_HOSTED_FN("toLocaleString", "BigInt_toLocaleString", 0, 0),
231
#else
232
JS_FN("toLocaleString", toLocaleString, 0, 0),
233
#endif
234
JS_FS_END};
235
236
const JSFunctionSpec BigIntObject::staticMethods[] = {
237
JS_FN("asUintN", asUintN, 2, 0), JS_FN("asIntN", asIntN, 2, 0), JS_FS_END};