summaryrefslogtreecommitdiff
path: root/js
diff options
context:
space:
mode:
authorBrian Smith <brian@dbsoft.org>2023-07-13 01:59:24 -0500
committerBrian Smith <brian@dbsoft.org>2023-07-13 01:59:24 -0500
commiteb7a856c766a508cde0a9ad90a233b272c7a9e54 (patch)
treeecd43618fb67009fd1b5cc1247262fa410b8f5d0 /js
parent377625e5391178db4fba7e24288a813c5abd43e9 (diff)
downloaduxp-eb7a856c766a508cde0a9ad90a233b272c7a9e54.tar.gz
Issue #1240 - Part 1 - Define a new BigInt primitive type.
Based on https://bugzilla.mozilla.org/show_bug.cgi?id=1366287 Part 1.0. However leaving out the --enable-bigint changes.
Diffstat (limited to 'js')
-rw-r--r--js/public/Conversions.h2
-rw-r--r--js/public/GCPolicyAPI.h2
-rw-r--r--js/public/MemoryMetrics.h4
-rw-r--r--js/public/TraceKind.h4
-rw-r--r--js/public/TracingAPI.h2
-rw-r--r--js/public/TypeDecls.h5
-rw-r--r--js/public/UbiNode.h16
-rw-r--r--js/public/Value.h41
-rw-r--r--js/src/NamespaceImports.h6
-rw-r--r--js/src/builtin/MapObject.cpp14
-rw-r--r--js/src/gc/GCInternals.h2
-rw-r--r--js/src/gc/Heap.h2
-rw-r--r--js/src/gc/Marking.cpp10
-rw-r--r--js/src/gc/Marking.h4
-rw-r--r--js/src/gc/Tracer.cpp5
-rw-r--r--js/src/gdb/mozilla/jsval.py11
-rw-r--r--js/src/gdb/tests/test-jsval.cpp4
-rw-r--r--js/src/gdb/tests/test-jsval.py2
-rw-r--r--js/src/js.msg9
-rw-r--r--js/src/jsarray.cpp6
-rw-r--r--js/src/jsatom.cpp8
-rw-r--r--js/src/jsbool.cpp3
-rw-r--r--js/src/jscompartment.cpp15
-rw-r--r--js/src/jscompartment.h1
-rw-r--r--js/src/jscompartmentinlines.h8
-rw-r--r--js/src/jsgc.cpp7
-rw-r--r--js/src/jsgc.h3
-rw-r--r--js/src/jsnum.cpp16
-rw-r--r--js/src/jsobj.cpp11
-rw-r--r--js/src/json.cpp5
-rw-r--r--js/src/jspubtd.h1
-rw-r--r--js/src/jsstr.cpp4
-rw-r--r--js/src/moz.build1
-rw-r--r--js/src/vm/BigIntType.cpp82
-rw-r--r--js/src/vm/BigIntType.h58
-rw-r--r--js/src/vm/CommonPropertyNames.h1
-rw-r--r--js/src/vm/Interpreter.cpp6
-rw-r--r--js/src/vm/MemoryMetrics.cpp8
-rw-r--r--js/src/vm/StringBuffer.cpp6
-rw-r--r--js/src/vm/TypeInference-inl.h4
-rw-r--r--js/src/vm/TypeInference.cpp4
-rw-r--r--js/src/vm/TypeInference.h18
-rw-r--r--js/src/vm/UbiNode.cpp10
43 files changed, 411 insertions, 20 deletions
diff --git a/js/public/Conversions.h b/js/public/Conversions.h
index 4978583eca..1850a42f0e 100644
--- a/js/public/Conversions.h
+++ b/js/public/Conversions.h
@@ -120,7 +120,7 @@ ToBoolean(HandleValue v)
if (v.isSymbol())
return true;
- /* The slow path handles strings and objects. */
+ /* The slow path handles strings, BigInts and objects. */
return js::ToBooleanSlow(v);
}
diff --git a/js/public/GCPolicyAPI.h b/js/public/GCPolicyAPI.h
index 151ed4e048..cffaee7140 100644
--- a/js/public/GCPolicyAPI.h
+++ b/js/public/GCPolicyAPI.h
@@ -47,6 +47,7 @@
// Expand the given macro D for each public GC pointer.
#define FOR_EACH_PUBLIC_GC_POINTER_TYPE(D) \
D(JS::Symbol*) \
+ D(JS::BigInt*) \
D(JSAtom*) \
D(JSFunction*) \
D(JSObject*) \
@@ -125,6 +126,7 @@ struct GCPointerPolicy
}
};
template <> struct GCPolicy<JS::Symbol*> : public GCPointerPolicy<JS::Symbol*> {};
+template <> struct GCPolicy<JS::BigInt*> : public GCPointerPolicy<JS::BigInt*> {};
template <> struct GCPolicy<JSAtom*> : public GCPointerPolicy<JSAtom*> {};
template <> struct GCPolicy<JSFunction*> : public GCPointerPolicy<JSFunction*> {};
template <> struct GCPolicy<JSObject*> : public GCPointerPolicy<JSObject*> {};
diff --git a/js/public/MemoryMetrics.h b/js/public/MemoryMetrics.h
index 72764aec0e..d9660a7cf8 100644
--- a/js/public/MemoryMetrics.h
+++ b/js/public/MemoryMetrics.h
@@ -580,6 +580,7 @@ struct UnusedGCThingSizes
macro(Other, GCHeapUnused, objectGroup) \
macro(Other, GCHeapUnused, string) \
macro(Other, GCHeapUnused, symbol) \
+ macro(Other, GCHeapUnused, bigInt) \
macro(Other, GCHeapUnused, jitcode) \
macro(Other, GCHeapUnused, scope) \
macro(Other, GCHeapUnused, regExpShared)
@@ -599,6 +600,7 @@ struct UnusedGCThingSizes
case JS::TraceKind::Object: object += n; break;
case JS::TraceKind::String: string += n; break;
case JS::TraceKind::Symbol: symbol += n; break;
+ case JS::TraceKind::BigInt: bigInt += n; break;
case JS::TraceKind::Script: script += n; break;
case JS::TraceKind::Shape: shape += n; break;
case JS::TraceKind::BaseShape: baseShape += n; break;
@@ -640,6 +642,8 @@ struct ZoneStats
{
#define FOR_EACH_SIZE(macro) \
macro(Other, GCHeapUsed, symbolsGCHeap) \
+ macro(Other, GCHeapUsed, bigIntsGCHeap) \
+ macro(Other, MallocHeap, bigIntsMallocHeap) \
macro(Other, GCHeapAdmin, gcHeapArenaAdmin) \
macro(Other, GCHeapUsed, lazyScriptsGCHeap) \
macro(Other, MallocHeap, lazyScriptsMallocHeap) \
diff --git a/js/public/TraceKind.h b/js/public/TraceKind.h
index 13228a9612..78cf20f3a1 100644
--- a/js/public/TraceKind.h
+++ b/js/public/TraceKind.h
@@ -60,7 +60,8 @@ enum class TraceKind
JitCode = 0x1F,
LazyScript = 0x2F,
Scope = 0x3F,
- RegExpShared = 0x4F
+ RegExpShared = 0x4F,
+ BigInt = 0x5F
};
const static uintptr_t OutOfLineTraceKindMask = 0x07;
static_assert(uintptr_t(JS::TraceKind::BaseShape) & OutOfLineTraceKindMask, "mask bits are set");
@@ -91,6 +92,7 @@ struct MapTypeToTraceKind {
D(Shape, js::Shape, true) \
D(String, JSString, false) \
D(Symbol, JS::Symbol, false) \
+ D(BigInt, JS::BigInt, false) \
D(RegExpShared, js::RegExpShared, true)
// Map from all public types to their trace kind.
diff --git a/js/public/TracingAPI.h b/js/public/TracingAPI.h
index 01d28d93c3..cc03a54609 100644
--- a/js/public/TracingAPI.h
+++ b/js/public/TracingAPI.h
@@ -141,6 +141,7 @@ class JS_PUBLIC_API(CallbackTracer) : public JSTracer
virtual void onObjectEdge(JSObject** objp) { onChild(JS::GCCellPtr(*objp)); }
virtual void onStringEdge(JSString** strp) { onChild(JS::GCCellPtr(*strp)); }
virtual void onSymbolEdge(JS::Symbol** symp) { onChild(JS::GCCellPtr(*symp)); }
+ virtual void onBigIntEdge(JS::BigInt** bip) { onChild(JS::GCCellPtr(*bip)); }
virtual void onScriptEdge(JSScript** scriptp) { onChild(JS::GCCellPtr(*scriptp)); }
virtual void onShapeEdge(js::Shape** shapep) {
onChild(JS::GCCellPtr(*shapep, JS::TraceKind::Shape));
@@ -226,6 +227,7 @@ class JS_PUBLIC_API(CallbackTracer) : public JSTracer
void dispatchToOnEdge(JSObject** objp) { onObjectEdge(objp); }
void dispatchToOnEdge(JSString** strp) { onStringEdge(strp); }
void dispatchToOnEdge(JS::Symbol** symp) { onSymbolEdge(symp); }
+ void dispatchToOnEdge(JS::BigInt** bip) { onBigIntEdge(bip); }
void dispatchToOnEdge(JSScript** scriptp) { onScriptEdge(scriptp); }
void dispatchToOnEdge(js::Shape** shapep) { onShapeEdge(shapep); }
void dispatchToOnEdge(js::ObjectGroup** groupp) { onObjectGroupEdge(groupp); }
diff --git a/js/public/TypeDecls.h b/js/public/TypeDecls.h
index 2b36ed95b9..27f652f04f 100644
--- a/js/public/TypeDecls.h
+++ b/js/public/TypeDecls.h
@@ -39,6 +39,7 @@ namespace JS {
typedef unsigned char Latin1Char;
class Symbol;
+class BigInt;
class Value;
template <typename T> class Handle;
template <typename T> class MutableHandle;
@@ -53,6 +54,7 @@ typedef Handle<JSObject*> HandleObject;
typedef Handle<JSScript*> HandleScript;
typedef Handle<JSString*> HandleString;
typedef Handle<JS::Symbol*> HandleSymbol;
+typedef Handle<JS::BigInt*> HandleBigInt;
typedef Handle<Value> HandleValue;
typedef Handle<StackGCVector<Value>> HandleValueVector;
@@ -62,6 +64,7 @@ typedef MutableHandle<JSObject*> MutableHandleObject;
typedef MutableHandle<JSScript*> MutableHandleScript;
typedef MutableHandle<JSString*> MutableHandleString;
typedef MutableHandle<JS::Symbol*> MutableHandleSymbol;
+typedef MutableHandle<JS::BigInt*> MutableHandleBigInt;
typedef MutableHandle<Value> MutableHandleValue;
typedef MutableHandle<StackGCVector<Value>> MutableHandleValueVector;
@@ -70,6 +73,7 @@ typedef Rooted<JSFunction*> RootedFunction;
typedef Rooted<JSScript*> RootedScript;
typedef Rooted<JSString*> RootedString;
typedef Rooted<JS::Symbol*> RootedSymbol;
+typedef Rooted<JS::BigInt*> RootedBigInt;
typedef Rooted<jsid> RootedId;
typedef Rooted<JS::Value> RootedValue;
@@ -81,6 +85,7 @@ typedef PersistentRooted<JSObject*> PersistentRootedObject;
typedef PersistentRooted<JSScript*> PersistentRootedScript;
typedef PersistentRooted<JSString*> PersistentRootedString;
typedef PersistentRooted<JS::Symbol*> PersistentRootedSymbol;
+typedef PersistentRooted<JS::BigInt*> PersistentRootedBigInt;
typedef PersistentRooted<Value> PersistentRootedValue;
diff --git a/js/public/UbiNode.h b/js/public/UbiNode.h
index a4ed0dff49..3df3a4840b 100644
--- a/js/public/UbiNode.h
+++ b/js/public/UbiNode.h
@@ -1057,6 +1057,22 @@ class JS_PUBLIC_API(Concrete<JS::Symbol>) : TracerConcrete<JS::Symbol> {
};
template<>
+class JS_PUBLIC_API(Concrete<JS::BigInt>) : TracerConcrete<JS::BigInt> {
+ protected:
+ explicit Concrete(JS::BigInt* ptr) : TracerConcrete(ptr) {}
+
+ public:
+ static void construct(void* storage, JS::BigInt* ptr) {
+ new (storage) Concrete(ptr);
+ }
+
+ Size size(mozilla::MallocSizeOf mallocSizeOf) const override;
+
+ const char16_t* typeName() const override { return concreteTypeName; }
+ static const char16_t concreteTypeName[];
+};
+
+template<>
class JS_PUBLIC_API(Concrete<JSScript>) : TracerConcreteWithCompartment<JSScript> {
protected:
explicit Concrete(JSScript *ptr) : TracerConcreteWithCompartment<JSScript>(ptr) { }
diff --git a/js/public/Value.h b/js/public/Value.h
index c645f07733..dff673cec8 100644
--- a/js/public/Value.h
+++ b/js/public/Value.h
@@ -56,6 +56,7 @@ JS_ENUM_HEADER(JSValueType, uint8_t)
JSVAL_TYPE_STRING = 0x06,
JSVAL_TYPE_SYMBOL = 0x07,
JSVAL_TYPE_PRIVATE_GCTHING = 0x08,
+ JSVAL_TYPE_BIGINT = 0x09,
JSVAL_TYPE_OBJECT = 0x0c,
/* These never appear in a jsval; they are only provided as an out-of-band value. */
@@ -80,6 +81,7 @@ JS_ENUM_HEADER(JSValueTag, uint32_t)
JSVAL_TAG_BOOLEAN = JSVAL_TAG_CLEAR | JSVAL_TYPE_BOOLEAN,
JSVAL_TAG_MAGIC = JSVAL_TAG_CLEAR | JSVAL_TYPE_MAGIC,
JSVAL_TAG_OBJECT = JSVAL_TAG_CLEAR | JSVAL_TYPE_OBJECT,
+ JSVAL_TAG_BIGINT = JSVAL_TAG_CLEAR | JSVAL_TYPE_BIGINT,
JSVAL_TAG_PRIVATE_GCTHING = JSVAL_TAG_CLEAR | JSVAL_TYPE_PRIVATE_GCTHING
} JS_ENUM_FOOTER(JSValueTag);
@@ -100,6 +102,7 @@ JS_ENUM_HEADER(JSValueTag, uint32_t)
JSVAL_TAG_BOOLEAN = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_BOOLEAN,
JSVAL_TAG_MAGIC = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_MAGIC,
JSVAL_TAG_OBJECT = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_OBJECT,
+ JSVAL_TAG_BIGINT = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_BIGINT,
JSVAL_TAG_PRIVATE_GCTHING = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_PRIVATE_GCTHING
} JS_ENUM_FOOTER(JSValueTag);
@@ -117,6 +120,7 @@ JS_ENUM_HEADER(JSValueShiftedTag, uint64_t)
JSVAL_SHIFTED_TAG_BOOLEAN = (((uint64_t)JSVAL_TAG_BOOLEAN) << JSVAL_TAG_SHIFT),
JSVAL_SHIFTED_TAG_MAGIC = (((uint64_t)JSVAL_TAG_MAGIC) << JSVAL_TAG_SHIFT),
JSVAL_SHIFTED_TAG_OBJECT = (((uint64_t)JSVAL_TAG_OBJECT) << JSVAL_TAG_SHIFT),
+ JSVAL_SHIFTED_TAG_BIGINT = (((uint64_t)JSVAL_TAG_BIGINT) << JSVAL_TAG_SHIFT),
JSVAL_SHIFTED_TAG_PRIVATE_GCTHING = (((uint64_t)JSVAL_TAG_PRIVATE_GCTHING) << JSVAL_TAG_SHIFT)
} JS_ENUM_FOOTER(JSValueShiftedTag);
@@ -275,7 +279,7 @@ CanonicalizeNaN(double d)
*
* - JS::Value has setX() and isX() members for X in
*
- * { Int32, Double, String, Symbol, Boolean, Undefined, Null, Object, Magic }
+ * { Int32, Double, String, Symbol, BigInt, Boolean, Undefined, Null, Object, Magic }
*
* JS::Value also contains toX() for each of the non-singleton types.
*
@@ -370,6 +374,11 @@ class MOZ_NON_PARAM alignas(8) Value
data.asBits = bitsFromTagAndPayload(JSVAL_TAG_SYMBOL, PayloadType(sym));
}
+ void setBigInt(JS::BigInt* bi) {
+ MOZ_ASSERT(uintptr_t(bi) > 0x1000);
+ data.asBits = bitsFromTagAndPayload(JSVAL_TAG_BIGINT, PayloadType(bi));
+ }
+
void setObject(JSObject& obj) {
MOZ_ASSERT(uintptr_t(&obj) > 0x1000 || uintptr_t(&obj) == 0x48);
#if defined(JS_PUNBOX64)
@@ -519,6 +528,10 @@ class MOZ_NON_PARAM alignas(8) Value
return toTag() == JSVAL_TAG_SYMBOL;
}
+ bool isBigInt() const {
+ return toTag() == JSVAL_TAG_BIGINT;
+ }
+
bool isObject() const {
#if defined(JS_NUNBOX32)
return toTag() == JSVAL_TAG_OBJECT;
@@ -583,6 +596,8 @@ class MOZ_NON_PARAM alignas(8) Value
"Value type tags must correspond with JS::TraceKinds.");
if (MOZ_UNLIKELY(isPrivateGCThing()))
return JS::GCThingTraceKind(toGCThing());
+ if (MOZ_UNLIKELY(isBigInt()))
+ return JS::TraceKind::BigInt;
return JS::TraceKind(toTag() & 0x03);
}
@@ -647,6 +662,15 @@ class MOZ_NON_PARAM alignas(8) Value
#endif
}
+ JS::BigInt* toBigInt() const {
+ MOZ_ASSERT(isBigInt());
+#if defined(JS_NUNBOX32)
+ return data.s.payload.bi;
+#elif defined(JS_PUNBOX64)
+ return reinterpret_cast<JS::BigInt*>(data.asBits & JSVAL_SHIFTED_TAG_BIGINT);
+#endif
+ }
+
JSObject& toObject() const {
MOZ_ASSERT(isObject());
#if defined(JS_NUNBOX32)
@@ -759,6 +783,8 @@ class MOZ_NON_PARAM alignas(8) Value
"Private GC thing Values must not be strings. Make a StringValue instead.");
MOZ_ASSERT(JS::GCThingTraceKind(cell) != JS::TraceKind::Symbol,
"Private GC thing Values must not be symbols. Make a SymbolValue instead.");
+ MOZ_ASSERT(JS::GCThingTraceKind(cell) != JS::TraceKind::BigInt,
+ "Private GC thing Values must not be BigInts. Make a BigIntValue instead.");
MOZ_ASSERT(JS::GCThingTraceKind(cell) != JS::TraceKind::Object,
"Private GC thing Values must not be objects. Make an ObjectValue instead.");
@@ -811,6 +837,7 @@ class MOZ_NON_PARAM alignas(8) Value
uint32_t boo; // Don't use |bool| -- it must be four bytes.
JSString* str;
JS::Symbol* sym;
+ JS::BigInt* bi;
JSObject* obj;
js::gc::Cell* cell;
void* ptr;
@@ -866,6 +893,7 @@ class MOZ_NON_PARAM alignas(8) Value
uint32_t boo; // Don't use |bool| -- it must be four bytes.
JSString* str;
JS::Symbol* sym;
+ JS::BigInt* bi;
JSObject* obj;
js::gc::Cell* cell;
void* ptr;
@@ -1098,6 +1126,14 @@ SymbolValue(JS::Symbol* sym)
}
static inline Value
+BigIntValue(JS::BigInt* bi)
+{
+ Value v;
+ v.setBigInt(bi);
+ return v;
+}
+
+static inline Value
BooleanValue(bool boo)
{
Value v;
@@ -1365,6 +1401,7 @@ class WrappedPtrOperations<JS::Value, Wrapper>
bool isDouble() const { return value().isDouble(); }
bool isString() const { return value().isString(); }
bool isSymbol() const { return value().isSymbol(); }
+ bool isBigInt() const { return value().isBigInt(); }
bool isObject() const { return value().isObject(); }
bool isMagic() const { return value().isMagic(); }
bool isMagic(JSWhyMagic why) const { return value().isMagic(why); }
@@ -1380,6 +1417,7 @@ class WrappedPtrOperations<JS::Value, Wrapper>
double toDouble() const { return value().toDouble(); }
JSString* toString() const { return value().toString(); }
JS::Symbol* toSymbol() const { return value().toSymbol(); }
+ JS::BigInt* toBigInt() const { return value().toBigInt(); }
JSObject& toObject() const { return value().toObject(); }
JSObject* toObjectOrNull() const { return value().toObjectOrNull(); }
gc::Cell* toGCThing() const { return value().toGCThing(); }
@@ -1421,6 +1459,7 @@ class MutableWrappedPtrOperations<JS::Value, Wrapper> : public WrappedPtrOperati
void setNumber(double d) { set(JS::NumberValue(d)); }
void setString(JSString* str) { set(JS::StringValue(str)); }
void setSymbol(JS::Symbol* sym) { set(JS::SymbolValue(sym)); }
+ void setBigInt(JS::BigInt* bi) { set(JS::BigIntValue(bi)); }
void setObject(JSObject& obj) { set(JS::ObjectValue(obj)); }
void setObjectOrNull(JSObject* arg) { set(JS::ObjectOrNullValue(arg)); }
void setPrivate(void* ptr) { set(JS::PrivateValue(ptr)); }
diff --git a/js/src/NamespaceImports.h b/js/src/NamespaceImports.h
index a1d8bca1c3..dd940dc808 100644
--- a/js/src/NamespaceImports.h
+++ b/js/src/NamespaceImports.h
@@ -50,6 +50,7 @@ class PropertyResult;
class Symbol;
enum class SymbolCode: uint32_t;
+class BigInt;
} // namespace JS
// Do the importing.
@@ -122,6 +123,7 @@ using JS::RootedObject;
using JS::RootedScript;
using JS::RootedString;
using JS::RootedSymbol;
+using JS::RootedBigInt;
using JS::RootedValue;
using JS::PersistentRooted;
@@ -131,6 +133,7 @@ using JS::PersistentRootedObject;
using JS::PersistentRootedScript;
using JS::PersistentRootedString;
using JS::PersistentRootedSymbol;
+using JS::PersistentRootedBigInt;
using JS::PersistentRootedValue;
using JS::Handle;
@@ -140,6 +143,7 @@ using JS::HandleObject;
using JS::HandleScript;
using JS::HandleString;
using JS::HandleSymbol;
+using JS::HandleBigInt;
using JS::HandleValue;
using JS::MutableHandle;
@@ -149,6 +153,7 @@ using JS::MutableHandleObject;
using JS::MutableHandleScript;
using JS::MutableHandleString;
using JS::MutableHandleSymbol;
+using JS::MutableHandleBigInt;
using JS::MutableHandleValue;
using JS::NullHandleValue;
@@ -166,6 +171,7 @@ using JS::Zone;
using JS::Symbol;
using JS::SymbolCode;
+using JS::BigInt;
} /* namespace js */
#endif /* NamespaceImports_h */
diff --git a/js/src/builtin/MapObject.cpp b/js/src/builtin/MapObject.cpp
index 893e0448a4..8bd87d8f16 100644
--- a/js/src/builtin/MapObject.cpp
+++ b/js/src/builtin/MapObject.cpp
@@ -61,7 +61,7 @@ HashableValue::setValue(JSContext* cx, HandleValue v)
}
MOZ_ASSERT(value.isUndefined() || value.isNull() || value.isBoolean() || value.isNumber() ||
- value.isString() || value.isSymbol() || value.isObject());
+ value.isString() || value.isSymbol() || value.isObject() || value.isBigInt());
return true;
}
@@ -81,6 +81,8 @@ HashValue(const Value& v, const mozilla::HashCodeScrambler& hcs)
return v.toString()->asAtom().hash();
if (v.isSymbol())
return v.toSymbol()->hash();
+ if (v.isBigInt())
+ return v.toBigInt()->hash();
if (v.isObject())
return hcs.scramble(v.asRawBits());
@@ -100,6 +102,16 @@ HashableValue::operator==(const HashableValue& other) const
// Two HashableValues are equal if they have equal bits.
bool b = (value.asRawBits() == other.value.asRawBits());
+ // BigInt values are considered equal if they represent the same
+ // integer. This test should use a comparison function that doesn't
+ // require a JSContext once one is defined in the BigInt class.
+ if (!b && (value.isBigInt() && other.value.isBigInt())) {
+ JS::RootingContext* rcx = GetJSContextFromMainThread();
+ RootedValue valueRoot(rcx, value);
+ RootedValue otherRoot(rcx, other.value);
+ SameValue(nullptr, valueRoot, otherRoot, &b);
+ }
+
#ifdef DEBUG
bool same;
JS::RootingContext* rcx = GetJSContextFromMainThread();
diff --git a/js/src/gc/GCInternals.h b/js/src/gc/GCInternals.h
index 5c51540351..c0e980a7c1 100644
--- a/js/src/gc/GCInternals.h
+++ b/js/src/gc/GCInternals.h
@@ -14,6 +14,7 @@
#include "gc/Zone.h"
#include "vm/HelperThreads.h"
#include "vm/Runtime.h"
+#include "vm/BigIntType.h"
namespace js {
namespace gc {
@@ -71,6 +72,7 @@ struct MovingTracer : JS::CallbackTracer
void onObjectEdge(JSObject** objp) override;
void onShapeEdge(Shape** shapep) override;
void onStringEdge(JSString** stringp) override;
+ void onBigIntEdge(JS::BigInt** bip) override;
void onScriptEdge(JSScript** scriptp) override;
void onLazyScriptEdge(LazyScript** lazyp) override;
void onBaseShapeEdge(BaseShape** basep) override;
diff --git a/js/src/gc/Heap.h b/js/src/gc/Heap.h
index 371e4119f9..3e14ed906f 100644
--- a/js/src/gc/Heap.h
+++ b/js/src/gc/Heap.h
@@ -111,6 +111,7 @@ enum class AllocKind : uint8_t {
FAT_INLINE_ATOM,
ATOM,
SYMBOL,
+ BIGINT,
JITCODE,
SCOPE,
REGEXP_SHARED,
@@ -151,6 +152,7 @@ enum class AllocKind : uint8_t {
D(FAT_INLINE_ATOM, String, js::FatInlineAtom, js::FatInlineAtom) \
D(ATOM, String, js::NormalAtom, js::NormalAtom) \
D(SYMBOL, Symbol, JS::Symbol, JS::Symbol) \
+ D(BIGINT, BigInt, JS::BigInt, JS::BigInt) \
D(JITCODE, JitCode, js::jit::JitCode, js::jit::JitCode) \
D(SCOPE, Scope, js::Scope, js::Scope) \
D(REGEXP_SHARED, RegExpShared, js::RegExpShared, js::RegExpShared)
diff --git a/js/src/gc/Marking.cpp b/js/src/gc/Marking.cpp
index 42c872a1da..13ec5b0c05 100644
--- a/js/src/gc/Marking.cpp
+++ b/js/src/gc/Marking.cpp
@@ -21,6 +21,7 @@
#include "js/SliceBudget.h"
#include "vm/ArgumentsObject.h"
#include "vm/ArrayObject.h"
+#include "vm/BigIntType.h"
#include "vm/Debugger.h"
#include "vm/EnvironmentObject.h"
#include "vm/Scope.h"
@@ -875,6 +876,7 @@ js::GCMarker::markAndTraceChildren(T* thing)
namespace js {
template <> void GCMarker::traverse(BaseShape* thing) { markAndTraceChildren(thing); }
template <> void GCMarker::traverse(JS::Symbol* thing) { markAndTraceChildren(thing); }
+template <> void GCMarker::traverse(JS::BigInt* thing) { markAndTraceChildren(thing); }
template <> void GCMarker::traverse(RegExpShared* thing) { markAndTraceChildren(thing); }
} // namespace js
@@ -1458,6 +1460,12 @@ js::GCMarker::lazilyMarkChildren(ObjectGroup* group)
traverseEdge(group, static_cast<JSObject*>(fun));
}
+void
+JS::BigInt::traceChildren(JSTracer* trc)
+{
+ return;
+}
+
struct TraverseObjectFunctor
{
template <typename T>
@@ -1704,6 +1712,8 @@ GCMarker::processMarkStackTop(SliceBudget& budget)
}
} else if (v.isSymbol()) {
traverseEdge(obj, v.toSymbol());
+ } else if (v.isBigInt()) {
+ traverseEdge(obj, v.toBigInt());
} else if (v.isPrivateGCThing()) {
traverseEdge(obj, v.toGCCellPtr());
}
diff --git a/js/src/gc/Marking.h b/js/src/gc/Marking.h
index 40b331b311..414079f799 100644
--- a/js/src/gc/Marking.h
+++ b/js/src/gc/Marking.h
@@ -425,6 +425,7 @@ struct RewrapTaggedPointer{};
DECLARE_REWRAP(JS::Value, JSObject, JS::ObjectOrNullValue, );
DECLARE_REWRAP(JS::Value, JSString, JS::StringValue, );
DECLARE_REWRAP(JS::Value, JS::Symbol, JS::SymbolValue, );
+DECLARE_REWRAP(JS::Value, JS::BigInt, JS::BigIntValue, );
DECLARE_REWRAP(jsid, JSString, NON_INTEGER_ATOM_TO_JSID, (JSAtom*));
DECLARE_REWRAP(jsid, JS::Symbol, SYMBOL_TO_JSID, );
DECLARE_REWRAP(js::TaggedProto, JSObject, js::TaggedProto, );
@@ -435,7 +436,8 @@ struct IsPrivateGCThingInValue
: public mozilla::EnableIf<mozilla::IsBaseOf<Cell, T>::value &&
!mozilla::IsBaseOf<JSObject, T>::value &&
!mozilla::IsBaseOf<JSString, T>::value &&
- !mozilla::IsBaseOf<JS::Symbol, T>::value, T>
+ !mozilla::IsBaseOf<JS::Symbol, T>::value &&
+ !mozilla::IsBaseOf<JS::BigInt, T>::value, T>
{
static_assert(!mozilla::IsSame<Cell, T>::value && !mozilla::IsSame<TenuredCell, T>::value,
"T must not be Cell or TenuredCell");
diff --git a/js/src/gc/Tracer.cpp b/js/src/gc/Tracer.cpp
index 26a9e5ff78..ea7f613e38 100644
--- a/js/src/gc/Tracer.cpp
+++ b/js/src/gc/Tracer.cpp
@@ -20,6 +20,7 @@
#include "gc/Marking.h"
#include "gc/Zone.h"
+#include "vm/BigIntType.h"
#include "vm/Shape.h"
#include "vm/Symbol.h"
@@ -319,6 +320,10 @@ JS_GetTraceThingInfo(char* buf, size_t bufsize, JSTracer* trc, void* thing,
name = "symbol";
break;
+ case JS::TraceKind::BigInt:
+ name = "BigInt";
+ break;
+
case JS::TraceKind::BaseShape:
name = "base_shape";
break;
diff --git a/js/src/gdb/mozilla/jsval.py b/js/src/gdb/mozilla/jsval.py
index f5ae78b1c2..d6f5e01fdf 100644
--- a/js/src/gdb/mozilla/jsval.py
+++ b/js/src/gdb/mozilla/jsval.py
@@ -165,6 +165,15 @@ class jsvalTypeCache(object):
self.NULL = d['JSVAL_TYPE_NULL']
self.OBJECT = d['JSVAL_TYPE_OBJECT']
+ self.enable_bigint = False
+ try:
+ # Looking up the tag will throw an exception if BigInt is not
+ # enabled.
+ self.BIGINT = get('JSVAL_TYPE_BIGINT')
+ self.enable_bigint = True
+ except:
+ pass
+
# Let self.magic_names be an array whose i'th element is the name of
# the i'th magic value.
d = gdb.types.make_enum_dict(gdb.lookup_type('JSWhyMagic'))
@@ -206,6 +215,8 @@ class jsval_layout(object):
value = self.box.as_address().cast(self.cache.JSString_ptr_t)
elif tag == self.jtc.SYMBOL:
value = self.box.as_address().cast(self.cache.JSSymbol_ptr_t)
+ elif self.jtc.enable_bigint and tag == self.jtc.BIGINT:
+ return '$JS::BigIntValue()'
elif tag == self.jtc.NULL:
return 'JSVAL_NULL'
elif tag == self.jtc.OBJECT:
diff --git a/js/src/gdb/tests/test-jsval.cpp b/js/src/gdb/tests/test-jsval.cpp
index f3c3247e2c..3bd197aa77 100644
--- a/js/src/gdb/tests/test-jsval.cpp
+++ b/js/src/gdb/tests/test-jsval.cpp
@@ -1,6 +1,8 @@
#include "gdb-tests.h"
#include "jsapi.h"
+#include "vm/BigIntType.h"
+
FRAGMENT(jsval, simple) {
using namespace JS;
@@ -17,6 +19,7 @@ FRAGMENT(jsval, simple) {
RootedString hello(cx, JS_NewStringCopyZ(cx, "Hello!"));
RootedValue friendly_string(cx, StringValue(hello));
RootedValue symbol(cx, SymbolValue(GetSymbolFor(cx, hello)));
+ RootedValue bi(cx, BigIntValue(BigInt::create(cx)));
RootedValue global(cx);
global.setObject(*CurrentGlobalOrNull(cx));
@@ -36,5 +39,6 @@ FRAGMENT(jsval, simple) {
(void) empty_string;
(void) friendly_string;
(void) symbol;
+ (void) bi;
(void) global;
}
diff --git a/js/src/gdb/tests/test-jsval.py b/js/src/gdb/tests/test-jsval.py
index f39a6591fd..38edb28197 100644
--- a/js/src/gdb/tests/test-jsval.py
+++ b/js/src/gdb/tests/test-jsval.py
@@ -14,5 +14,7 @@ assert_pretty('elements_hole', '$jsmagic(JS_ELEMENTS_HOLE)')
assert_pretty('empty_string', '$jsval("")')
assert_pretty('friendly_string', '$jsval("Hello!")')
assert_pretty('symbol', '$jsval(Symbol.for("Hello!"))')
+if enable_bigint:
+ assert_pretty('bi', '$JS::BigIntValue()')
assert_pretty('global', '$jsval((JSObject *) [object global] delegate)')
assert_pretty('onehundredthirtysevenonehundredtwentyeighths', '$jsval(1.0703125)')
diff --git a/js/src/js.msg b/js/src/js.msg
index 242d81a5c8..7e6ddd81bc 100644
--- a/js/src/js.msg
+++ b/js/src/js.msg
@@ -619,3 +619,12 @@ MSG_DEF(JSMSG_FOR_AWAIT_NOT_OF, 0, JSEXN_TYPEERR, "'for await' loop shoul
MSG_DEF(JSMSG_NOT_AN_ASYNC_GENERATOR, 0, JSEXN_TYPEERR, "Not an async generator")
MSG_DEF(JSMSG_NOT_AN_ASYNC_ITERATOR, 0, JSEXN_TYPEERR, "Not an async from sync iterator")
MSG_DEF(JSMSG_GET_ASYNC_ITER_RETURNED_PRIMITIVE, 0, JSEXN_TYPEERR, "[Symbol.asyncIterator]() returned a non-object value")
+
+// BigInt
+MSG_DEF(JSMSG_BIGINT_TO_NUMBER, 0, JSEXN_TYPEERR, "can't convert BigInt to number")
+MSG_DEF(JSMSG_NUMBER_TO_BIGINT, 0, JSEXN_RANGEERR, "can't convert non-finite number to BigInt")
+MSG_DEF(JSMSG_BIGINT_DIVISION_BY_ZERO, 0, JSEXN_RANGEERR, "BigInt division by zero")
+MSG_DEF(JSMSG_BIGINT_NEGATIVE_EXPONENT, 0, JSEXN_RANGEERR, "BigInt negative exponent")
+MSG_DEF(JSMSG_BIGINT_INVALID_SYNTAX, 0, JSEXN_SYNTAXERR, "invalid BigInt syntax")
+MSG_DEF(JSMSG_NOT_BIGINT, 0, JSEXN_TYPEERR, "not a BigInt")
+MSG_DEF(JSMSG_BIGINT_NOT_SERIALIZABLE, 0, JSEXN_TYPEERR, "BigInt value can't be serialized in JSON")
diff --git a/js/src/jsarray.cpp b/js/src/jsarray.cpp
index b166a786ca..cc0fcbebd9 100644
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -1099,6 +1099,12 @@ ArrayJoinDenseKernel(JSContext* cx, SeparatorOp sepOp, HandleObject obj, uint32_
* with those as well.
*/
break;
+ } else if (elem.isBigInt()) {
+ // ToString(bigint) doesn't access bigint.toString or
+ // anything like that, so it can't mutate the array we're
+ // walking through, so it *could* be handled here. We don't
+ // do so yet for reasons of initial-implementation economy.
+ break;
} else {
MOZ_ASSERT(elem.isMagic(JS_ELEMENTS_HOLE) || elem.isNullOrUndefined());
}
diff --git a/js/src/jsatom.cpp b/js/src/jsatom.cpp
index 02308314c9..89e9f71aae 100644
--- a/js/src/jsatom.cpp
+++ b/js/src/jsatom.cpp
@@ -28,6 +28,8 @@
#include "vm/String-inl.h"
+#include "vm/BigIntType.h"
+
using namespace js;
using namespace js::gc;
@@ -484,6 +486,12 @@ ToAtomSlow(ExclusiveContext* cx, typename MaybeRooted<Value, allowGC>::HandleTyp
}
return nullptr;
}
+ if (v.isBigInt()) {
+ JSAtom* atom = BigIntToAtom(cx, v.toBigInt());
+ if (!allowGC && !atom)
+ cx->recoverFromOutOfMemory();
+ return atom;
+ }
MOZ_ASSERT(v.isUndefined());
return cx->names().undefined;
}
diff --git a/js/src/jsbool.cpp b/js/src/jsbool.cpp
index 324868216b..ee24f76987 100644
--- a/js/src/jsbool.cpp
+++ b/js/src/jsbool.cpp
@@ -18,6 +18,7 @@
#include "vm/GlobalObject.h"
#include "vm/ProxyObject.h"
#include "vm/StringBuffer.h"
+#include "vm/BigIntType.h"
#include "vm/BooleanObject-inl.h"
@@ -170,6 +171,8 @@ js::ToBooleanSlow(HandleValue v)
{
if (v.isString())
return v.toString()->length() != 0;
+ if (v.isBigInt())
+ return v.toBigInt()->toBoolean();
MOZ_ASSERT(v.isObject());
return !EmulatesUndefined(&v.toObject());
diff --git a/js/src/jscompartment.cpp b/js/src/jscompartment.cpp
index c93dee510b..926c7e3c86 100644
--- a/js/src/jscompartment.cpp
+++ b/js/src/jscompartment.cpp
@@ -340,6 +340,21 @@ JSCompartment::wrap(JSContext* cx, MutableHandleString strp)
}
bool
+JSCompartment::wrap(JSContext* cx, MutableHandleBigInt bi)
+{
+ MOZ_ASSERT(cx->compartment() == this);
+
+ if (bi->zone() == cx->zone())
+ return true;
+
+ BigInt* copy = BigInt::copy(cx, bi);
+ if (!copy)
+ return false;
+ bi.set(copy);
+ return true;
+}
+
+bool
JSCompartment::getNonWrapperObjectForCurrentCompartment(JSContext* cx, MutableHandleObject obj)
{
// Ensure that we have entered a compartment.
diff --git a/js/src/jscompartment.h b/js/src/jscompartment.h
index dbada58439..a02b39301d 100644
--- a/js/src/jscompartment.h
+++ b/js/src/jscompartment.h
@@ -583,6 +583,7 @@ struct JSCompartment
MOZ_MUST_USE inline bool wrap(JSContext* cx, JS::MutableHandleValue vp);
MOZ_MUST_USE bool wrap(JSContext* cx, js::MutableHandleString strp);
+ MOZ_MUST_USE bool wrap(JSContext* cx, js::MutableHandle<JS::BigInt*> bi);
MOZ_MUST_USE bool wrap(JSContext* cx, JS::MutableHandleObject obj);
MOZ_MUST_USE bool wrap(JSContext* cx, JS::MutableHandle<js::PropertyDescriptor> desc);
MOZ_MUST_USE bool wrap(JSContext* cx, JS::MutableHandle<JS::GCVector<JS::Value>> vec);
diff --git a/js/src/jscompartmentinlines.h b/js/src/jscompartmentinlines.h
index c17ba99de2..c092889e28 100644
--- a/js/src/jscompartmentinlines.h
+++ b/js/src/jscompartmentinlines.h
@@ -79,6 +79,14 @@ JSCompartment::wrap(JSContext* cx, JS::MutableHandleValue vp)
return true;
}
+ if (vp.isBigInt()) {
+ JS::RootedBigInt bi(cx, vp.toBigInt());
+ if (!wrap(cx, &bi))
+ return false;
+ vp.setBigInt(bi);
+ return true;
+ }
+
MOZ_ASSERT(vp.isObject());
/*
diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp
index e172ea36c2..5c2835cca9 100644
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -222,6 +222,7 @@
#include "jit/JitcodeMap.h"
#include "js/SliceBudget.h"
#include "proxy/DeadObjectProxy.h"
+#include "vm/BigIntType.h"
#include "vm/Debugger.h"
#include "vm/ProxyObject.h"
#include "vm/Shape.h"
@@ -371,7 +372,8 @@ static const FinalizePhase BackgroundFinalizePhases[] = {
AllocKind::STRING,
AllocKind::FAT_INLINE_ATOM,
AllocKind::ATOM,
- AllocKind::SYMBOL
+ AllocKind::SYMBOL,
+ AllocKind::BIGINT
}
},
{
@@ -1986,6 +1988,7 @@ MovingTracer::updateEdge(T** thingp)
void MovingTracer::onObjectEdge(JSObject** objp) { updateEdge(objp); }
void MovingTracer::onShapeEdge(Shape** shapep) { updateEdge(shapep); }
void MovingTracer::onStringEdge(JSString** stringp) { updateEdge(stringp); }
+void MovingTracer::onBigIntEdge(JS::BigInt** bip) { updateEdge(bip); }
void MovingTracer::onScriptEdge(JSScript** scriptp) { updateEdge(scriptp); }
void MovingTracer::onLazyScriptEdge(LazyScript** lazyp) { updateEdge(lazyp); }
void MovingTracer::onBaseShapeEdge(BaseShape** basep) { updateEdge(basep); }
@@ -6557,6 +6560,8 @@ JS::GCCellPtr::GCCellPtr(const Value& v)
ptr = checkedCast(&v.toObject(), JS::TraceKind::Object);
else if (v.isSymbol())
ptr = checkedCast(v.toSymbol(), JS::TraceKind::Symbol);
+ else if (v.isBigInt())
+ ptr = checkedCast(v.toBigInt(), JS::TraceKind::BigInt);
else if (v.isPrivateGCThing())
ptr = checkedCast(v.toGCThing(), v.toGCThing()->getTraceKind());
else
diff --git a/js/src/jsgc.h b/js/src/jsgc.h
index ffd6102747..521dea05c6 100644
--- a/js/src/jsgc.h
+++ b/js/src/jsgc.h
@@ -20,6 +20,7 @@
#include "threading/ConditionVariable.h"
#include "threading/Thread.h"
#include "vm/NativeObject.h"
+#include "vm/BigIntType.h"
namespace js {
@@ -119,6 +120,7 @@ IsNurseryAllocable(AllocKind kind)
false, /* AllocKind::FAT_INLINE_ATOM */
false, /* AllocKind::ATOM */
false, /* AllocKind::SYMBOL */
+ false, /* AllocKind::BIGINT */
false, /* AllocKind::JITCODE */
false, /* AllocKind::SCOPE */
false, /* AllocKind::REGEXP_SHARED */
@@ -158,6 +160,7 @@ IsBackgroundFinalized(AllocKind kind)
true, /* AllocKind::FAT_INLINE_ATOM */
true, /* AllocKind::ATOM */
true, /* AllocKind::SYMBOL */
+ true, /* AllocKind::BIGINT */
false, /* AllocKind::JITCODE */
true, /* AllocKind::SCOPE */
true, /* AllocKind::REGEXP_SHARED */
diff --git a/js/src/jsnum.cpp b/js/src/jsnum.cpp
index 549596e579..f103f4dc79 100644
--- a/js/src/jsnum.cpp
+++ b/js/src/jsnum.cpp
@@ -1452,9 +1452,19 @@ js::ToNumberSlow(ExclusiveContext* cx, HandleValue v_, double* out)
return false;
}
- MOZ_ASSERT(v.isUndefined());
- *out = GenericNaN();
- return true;
+ if (v.isUndefined()) {
+ *out = GenericNaN();
+ return true;
+ }
+
+ MOZ_ASSERT(v.isSymbol() || v.isBigInt());
+ if (cx->isJSContext()) {
+ unsigned errnum = JSMSG_SYMBOL_TO_NUMBER;
+ if (v.isBigInt())
+ errnum = JSMSG_BIGINT_TO_NUMBER;
+ JS_ReportErrorNumberASCII(cx->asJSContext(), GetErrorMessage, nullptr, errnum);
+ }
+ return false;
}
JS_PUBLIC_API(bool)
diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp
index b0cf6bc69b..75d45e76d5 100644
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -3104,9 +3104,14 @@ js::PrimitiveToObject(JSContext* cx, const Value& v)
return NumberObject::create(cx, v.toNumber());
if (v.isBoolean())
return BooleanObject::create(cx, v.toBoolean());
- MOZ_ASSERT(v.isSymbol());
- RootedSymbol symbol(cx, v.toSymbol());
- return SymbolObject::create(cx, symbol);
+ if (v.isSymbol()) {
+ RootedSymbol symbol(cx, v.toSymbol());
+ return SymbolObject::create(cx, symbol);
+ }
+ MOZ_ASSERT(v.isBigInt());
+ RootedBigInt bigInt(cx, v.toBigInt());
+ // Return nullptr because BigIntObject has not been defined yet.
+ return nullptr;
}
/*
diff --git a/js/src/json.cpp b/js/src/json.cpp
index f3cf22dac9..084deb2b94 100644
--- a/js/src/json.cpp
+++ b/js/src/json.cpp
@@ -626,6 +626,11 @@ Str(JSContext* cx, const Value& v, StringifyContext* scx)
return NumberValueToStringBuffer(cx, v, scx->sb);
}
+ if (v.isBigInt()) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BIGINT_NOT_SERIALIZABLE);
+ return false;
+ }
+
/* Step 10. */
MOZ_ASSERT(v.isObject());
RootedObject obj(cx, &v.toObject());
diff --git a/js/src/jspubtd.h b/js/src/jspubtd.h
index 01d3143023..4bc8b0649a 100644
--- a/js/src/jspubtd.h
+++ b/js/src/jspubtd.h
@@ -80,6 +80,7 @@ enum JSType {
JSTYPE_BOOLEAN, /* boolean */
JSTYPE_NULL, /* null */
JSTYPE_SYMBOL, /* symbol */
+ JSTYPE_BIGINT, /* BigInt */
JSTYPE_LIMIT
};
diff --git a/js/src/jsstr.cpp b/js/src/jsstr.cpp
index fdee274c32..bd1ca38972 100644
--- a/js/src/jsstr.cpp
+++ b/js/src/jsstr.cpp
@@ -3734,6 +3734,10 @@ js::ToStringSlow(ExclusiveContext* cx, typename MaybeRooted<Value, allowGC>::Han
JSMSG_SYMBOL_TO_STRING);
}
return nullptr;
+ } else if (v.isBigInt()) {
+ if (!allowGC)
+ return nullptr;
+ str = BigInt::toString(cx, v.toBigInt());
} else {
MOZ_ASSERT(v.isUndefined());
str = cx->names().undefined;
diff --git a/js/src/moz.build b/js/src/moz.build
index cecb7ae32d..321fdb88a9 100644
--- a/js/src/moz.build
+++ b/js/src/moz.build
@@ -392,6 +392,7 @@ SOURCES += [
'jsdtoa.cpp',
'jsmath.cpp',
'jsutil.cpp',
+ 'vm/BigIntType.cpp',
'vm/Initialization.cpp',
]
diff --git a/js/src/vm/BigIntType.cpp b/js/src/vm/BigIntType.cpp
new file mode 100644
index 0000000000..394f8f8784
--- /dev/null
+++ b/js/src/vm/BigIntType.cpp
@@ -0,0 +1,82 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "vm/BigIntType.h"
+
+#include "mozilla/FloatingPoint.h"
+#include "mozilla/HashFunctions.h"
+
+#include "jsapi.h"
+#include "jscntxt.h"
+
+#include "gc/Allocator.h"
+#include "gc/Tracer.h"
+#include "vm/SelfHosting.h"
+
+using namespace js;
+
+BigInt*
+BigInt::create(js::ExclusiveContext* cx)
+{
+ BigInt* x = Allocate<BigInt>(cx);
+ if (!x)
+ return nullptr;
+ return x;
+}
+
+BigInt*
+BigInt::copy(js::ExclusiveContext* cx, HandleBigInt x)
+{
+ BigInt* bi = create(cx);
+ if (!bi)
+ return nullptr;
+ return bi;
+}
+
+JSLinearString*
+BigInt::toString(ExclusiveContext* cx, BigInt* x)
+{
+ return nullptr;
+}
+
+void
+BigInt::finalize(js::FreeOp* fop)
+{
+ return;
+}
+
+JSAtom*
+js::BigIntToAtom(ExclusiveContext* cx, BigInt* bi)
+{
+ JSString* str = BigInt::toString(cx, bi);
+ if (!str)
+ return nullptr;
+ return AtomizeString(cx, str);
+}
+
+bool
+BigInt::toBoolean()
+{
+ return false;
+}
+
+js::HashNumber
+BigInt::hash()
+{
+ return 0;
+}
+
+size_t
+BigInt::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const
+{
+ return 0;
+}
+
+JS::ubi::Node::Size
+JS::ubi::Concrete<BigInt>::size(mozilla::MallocSizeOf mallocSizeOf) const
+{
+ MOZ_ASSERT(get().isTenured());
+ return js::gc::Arena::thingSize(get().asTenured().getAllocKind());
+}
diff --git a/js/src/vm/BigIntType.h b/js/src/vm/BigIntType.h
new file mode 100644
index 0000000000..3c5768e818
--- /dev/null
+++ b/js/src/vm/BigIntType.h
@@ -0,0 +1,58 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef vm_BigIntType_h
+#define vm_BigIntType_h
+
+#include "gc/Barrier.h"
+#include "gc/Marking.h"
+#include "gc/Heap.h"
+#include "js/GCHashTable.h"
+#include "js/RootingAPI.h"
+#include "js/TypeDecls.h"
+#include "vm/String.h"
+
+namespace JS {
+
+class BigInt final : public js::gc::TenuredCell
+{
+ private:
+ // The minimum allocation size is currently 16 bytes (see
+ // SortedArenaList in gc/ArenaList.h).
+ uint8_t unused_[16 + (16 % js::gc::CellSize)];
+
+ public:
+ // Allocate and initialize a BigInt value
+ static BigInt* create(js::ExclusiveContext* cx);
+
+ static const JS::TraceKind TraceKind = JS::TraceKind::BigInt;
+
+ void traceChildren(JSTracer* trc);
+
+ void finalize(js::FreeOp* fop);
+
+ js::HashNumber hash();
+
+ size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
+
+ static JSLinearString* toString(js::ExclusiveContext* cx, BigInt* x);
+ bool toBoolean();
+
+ static BigInt* copy(js::ExclusiveContext* cx, Handle<BigInt*> x);
+};
+
+static_assert(sizeof(BigInt) >= js::gc::CellSize,
+ "sizeof(BigInt) must be greater than the minimum allocation size");
+
+} // namespace JS
+
+namespace js {
+
+extern JSAtom*
+BigIntToAtom(ExclusiveContext* cx, JS::BigInt* bi);
+
+} // namespace js
+
+#endif
diff --git a/js/src/vm/CommonPropertyNames.h b/js/src/vm/CommonPropertyNames.h
index d5e7a2d058..84582b0ac5 100644
--- a/js/src/vm/CommonPropertyNames.h
+++ b/js/src/vm/CommonPropertyNames.h
@@ -424,5 +424,6 @@
macro(boolean, boolean, "boolean") \
macro(null, null, "null") \
macro(symbol, symbol, "symbol") \
+ macro(bigint, bigint, "bigint") \
#endif /* vm_CommonPropertyNames_h */
diff --git a/js/src/vm/Interpreter.cpp b/js/src/vm/Interpreter.cpp
index d7c1b8e84a..041a1d4b8c 100644
--- a/js/src/vm/Interpreter.cpp
+++ b/js/src/vm/Interpreter.cpp
@@ -40,6 +40,7 @@
#include "jit/IonAnalysis.h"
#include "vm/AsyncFunction.h"
#include "vm/AsyncIteration.h"
+#include "vm/BigIntType.h"
#include "vm/Debugger.h"
#include "vm/EqualityOperations.h" // js::StrictlyEqual
#include "vm/GeneratorObject.h"
@@ -812,6 +813,8 @@ js::TypeOfValue(const Value& v)
return TypeOfObject(&v.toObject());
if (v.isBoolean())
return JSTYPE_BOOLEAN;
+ if (v.isBigInt())
+ return JSTYPE_BIGINT;
MOZ_ASSERT(v.isSymbol());
return JSTYPE_SYMBOL;
}
@@ -4222,7 +4225,8 @@ js::GetProperty(JSContext* cx, HandleValue v, HandlePropertyName name, MutableHa
// Optimize common cases like (2).toString() or "foo".valueOf() to not
// create a wrapper object.
- if (v.isPrimitive() && !v.isNullOrUndefined()) {
+ if (v.isPrimitive() && !v.isNullOrUndefined() && !v.isBigInt())
+ {
NativeObject* proto;
if (v.isNumber()) {
proto = GlobalObject::getOrCreateNumberPrototype(cx, cx->global());
diff --git a/js/src/vm/MemoryMetrics.cpp b/js/src/vm/MemoryMetrics.cpp
index 9b6d3dda72..2a28cf23c0 100644
--- a/js/src/vm/MemoryMetrics.cpp
+++ b/js/src/vm/MemoryMetrics.cpp
@@ -17,6 +17,7 @@
#include "jit/BaselineJIT.h"
#include "jit/Ion.h"
#include "vm/ArrayObject.h"
+#include "vm/BigIntType.h"
#include "vm/Runtime.h"
#include "vm/Shape.h"
#include "vm/String.h"
@@ -546,6 +547,13 @@ StatsCellCallback(JSRuntime* rt, void* data, void* thing, JS::TraceKind traceKin
zStats->symbolsGCHeap += thingSize;
break;
+ case JS::TraceKind::BigInt: {
+ JS::BigInt* bi = static_cast<BigInt*>(thing);
+ zStats->bigIntsGCHeap += thingSize;
+ zStats->bigIntsMallocHeap += bi->sizeOfExcludingThis(rtStats->mallocSizeOf_);
+ break;
+ }
+
case JS::TraceKind::BaseShape: {
JS::ShapeInfo info; // This zeroes all the sizes.
info.shapesGCHeapBase += thingSize;
diff --git a/js/src/vm/StringBuffer.cpp b/js/src/vm/StringBuffer.cpp
index e4f0e4f4d6..38f1e74e71 100644
--- a/js/src/vm/StringBuffer.cpp
+++ b/js/src/vm/StringBuffer.cpp
@@ -170,6 +170,12 @@ js::ValueToStringBufferSlow(JSContext* cx, const Value& arg, StringBuffer& sb)
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_SYMBOL_TO_STRING);
return false;
}
+ if (v.isBigInt()) {
+ JSString* str = BigInt::toString(cx, v.toBigInt());
+ if (!str)
+ return false;
+ return sb.append(str);
+ }
MOZ_ASSERT(v.isUndefined());
return sb.append(cx->names().undefined);
}
diff --git a/js/src/vm/TypeInference-inl.h b/js/src/vm/TypeInference-inl.h
index 5e1bac6bc9..8c9b179223 100644
--- a/js/src/vm/TypeInference-inl.h
+++ b/js/src/vm/TypeInference-inl.h
@@ -213,6 +213,8 @@ PrimitiveTypeFlag(JSValueType type)
return TYPE_FLAG_STRING;
case JSVAL_TYPE_SYMBOL:
return TYPE_FLAG_SYMBOL;
+ case JSVAL_TYPE_BIGINT:
+ return TYPE_FLAG_BIGINT;
case JSVAL_TYPE_MAGIC:
return TYPE_FLAG_LAZYARGS;
default:
@@ -238,6 +240,8 @@ TypeFlagPrimitive(TypeFlags flags)
return JSVAL_TYPE_STRING;
case TYPE_FLAG_SYMBOL:
return JSVAL_TYPE_SYMBOL;
+ case TYPE_FLAG_BIGINT:
+ return JSVAL_TYPE_BIGINT;
case TYPE_FLAG_LAZYARGS:
return JSVAL_TYPE_MAGIC;
default:
diff --git a/js/src/vm/TypeInference.cpp b/js/src/vm/TypeInference.cpp
index ca34b184e8..83da598815 100644
--- a/js/src/vm/TypeInference.cpp
+++ b/js/src/vm/TypeInference.cpp
@@ -111,6 +111,8 @@ TypeSet::NonObjectTypeString(TypeSet::Type type)
return "string";
case JSVAL_TYPE_SYMBOL:
return "symbol";
+ case JSVAL_TYPE_BIGINT:
+ return "BigInt";
case JSVAL_TYPE_MAGIC:
return "lazyargs";
default:
@@ -755,6 +757,8 @@ TypeSet::print(FILE* fp)
fprintf(fp, " string");
if (flags & TYPE_FLAG_SYMBOL)
fprintf(fp, " symbol");
+ if (flags & TYPE_FLAG_BIGINT)
+ fprintf(fp, " BigInt");
if (flags & TYPE_FLAG_LAZYARGS)
fprintf(fp, " lazyargs");
diff --git a/js/src/vm/TypeInference.h b/js/src/vm/TypeInference.h
index 764f99ca07..58c606912c 100644
--- a/js/src/vm/TypeInference.h
+++ b/js/src/vm/TypeInference.h
@@ -59,17 +59,18 @@ enum : uint32_t {
TYPE_FLAG_DOUBLE = 0x10,
TYPE_FLAG_STRING = 0x20,
TYPE_FLAG_SYMBOL = 0x40,
- TYPE_FLAG_LAZYARGS = 0x80,
- TYPE_FLAG_ANYOBJECT = 0x100,
+ TYPE_FLAG_BIGINT = 0x80,
+ TYPE_FLAG_LAZYARGS = 0x100,
+ TYPE_FLAG_ANYOBJECT = 0x200,
/* Mask containing all primitives */
TYPE_FLAG_PRIMITIVE = TYPE_FLAG_UNDEFINED | TYPE_FLAG_NULL | TYPE_FLAG_BOOLEAN |
TYPE_FLAG_INT32 | TYPE_FLAG_DOUBLE | TYPE_FLAG_STRING |
- TYPE_FLAG_SYMBOL,
+ TYPE_FLAG_SYMBOL |TYPE_FLAG_BIGINT,
/* Mask/shift for the number of objects in objectSet */
- TYPE_FLAG_OBJECT_COUNT_MASK = 0x3e00,
- TYPE_FLAG_OBJECT_COUNT_SHIFT = 9,
+ TYPE_FLAG_OBJECT_COUNT_MASK = 0x3c00,
+ TYPE_FLAG_OBJECT_COUNT_SHIFT = 10,
TYPE_FLAG_OBJECT_COUNT_LIMIT = 7,
TYPE_FLAG_DOMOBJECT_COUNT_LIMIT =
TYPE_FLAG_OBJECT_COUNT_MASK >> TYPE_FLAG_OBJECT_COUNT_SHIFT,
@@ -78,7 +79,7 @@ enum : uint32_t {
TYPE_FLAG_UNKNOWN = 0x00004000,
/* Mask of normal type flags on a type set. */
- TYPE_FLAG_BASE_MASK = 0x000041ff,
+ TYPE_FLAG_BASE_MASK = TYPE_FLAG_PRIMITIVE | TYPE_FLAG_LAZYARGS | TYPE_FLAG_ANYOBJECT | TYPE_FLAG_UNKNOWN,
/* Additional flags for HeapTypeSet sets. */
@@ -109,6 +110,10 @@ enum : uint32_t {
};
typedef uint32_t TypeFlags;
+static_assert(TYPE_FLAG_PRIMITIVE < TYPE_FLAG_ANYOBJECT &&
+ TYPE_FLAG_LAZYARGS < TYPE_FLAG_ANYOBJECT,
+ "TYPE_FLAG_ANYOBJECT should be greater than primitive type flags");
+
/* Flags and other state stored in ObjectGroup::Flags */
enum : uint32_t {
/* Whether this group is associated with some allocation site. */
@@ -366,6 +371,7 @@ class TypeSet
static inline Type DoubleType() { return Type(JSVAL_TYPE_DOUBLE); }
static inline Type StringType() { return Type(JSVAL_TYPE_STRING); }
static inline Type SymbolType() { return Type(JSVAL_TYPE_SYMBOL); }
+ static inline Type BigIntType() { return Type(JSVAL_TYPE_BIGINT); }
static inline Type MagicArgType() { return Type(JSVAL_TYPE_MAGIC); }
static inline Type AnyObjectType() { return Type(JSVAL_TYPE_OBJECT); }
static inline Type UnknownType() { return Type(JSVAL_TYPE_UNKNOWN); }
diff --git a/js/src/vm/UbiNode.cpp b/js/src/vm/UbiNode.cpp
index ab966cbb4d..3a3b1ee2bf 100644
--- a/js/src/vm/UbiNode.cpp
+++ b/js/src/vm/UbiNode.cpp
@@ -23,6 +23,7 @@
#include "js/TypeDecls.h"
#include "js/Utility.h"
#include "js/Vector.h"
+#include "vm/BigIntType.h"
#include "vm/Debugger.h"
#include "vm/EnvironmentObject.h"
#include "vm/GlobalObject.h"
@@ -202,7 +203,11 @@ Node::exposeToJS() const
v.setString(as<JSString>());
} else if (is<JS::Symbol>()) {
v.setSymbol(as<JS::Symbol>());
- } else {
+ }
+ else if (is<BigInt>()) {
+ v.setBigInt(as<BigInt>());
+ }
+ else {
v.setUndefined();
}
@@ -314,6 +319,7 @@ template JS::Zone* TracerConcrete<js::ObjectGroup>::zone() const;
template JS::Zone* TracerConcrete<js::RegExpShared>::zone() const;
template JS::Zone* TracerConcrete<js::Scope>::zone() const;
template JS::Zone* TracerConcrete<JS::Symbol>::zone() const;
+template JS::Zone* TracerConcrete<BigInt>::zone() const;
template JS::Zone* TracerConcrete<JSString>::zone() const;
template<typename Referent>
@@ -337,6 +343,7 @@ template UniquePtr<EdgeRange> TracerConcrete<js::ObjectGroup>::edges(JSContext*
template UniquePtr<EdgeRange> TracerConcrete<js::RegExpShared>::edges(JSContext* cx, bool wantNames) const;
template UniquePtr<EdgeRange> TracerConcrete<js::Scope>::edges(JSContext* cx, bool wantNames) const;
template UniquePtr<EdgeRange> TracerConcrete<JS::Symbol>::edges(JSContext* cx, bool wantNames) const;
+template UniquePtr<EdgeRange> TracerConcrete<BigInt>::edges(JSContext* cx, bool wantNames) const;
template UniquePtr<EdgeRange> TracerConcrete<JSString>::edges(JSContext* cx, bool wantNames) const;
template<typename Referent>
@@ -392,6 +399,7 @@ Concrete<JSObject>::jsObjectConstructorName(JSContext* cx, UniqueTwoByteChars& o
}
const char16_t Concrete<JS::Symbol>::concreteTypeName[] = u"JS::Symbol";
+const char16_t Concrete<BigInt>::concreteTypeName[] = u"JS::BigInt";
const char16_t Concrete<JSScript>::concreteTypeName[] = u"JSScript";
const char16_t Concrete<js::LazyScript>::concreteTypeName[] = u"js::LazyScript";
const char16_t Concrete<js::jit::JitCode>::concreteTypeName[] = u"js::jit::JitCode";