diff options
author | Brian Smith <brian@dbsoft.org> | 2023-07-13 01:59:24 -0500 |
---|---|---|
committer | Brian Smith <brian@dbsoft.org> | 2023-07-13 01:59:24 -0500 |
commit | eb7a856c766a508cde0a9ad90a233b272c7a9e54 (patch) | |
tree | ecd43618fb67009fd1b5cc1247262fa410b8f5d0 /js | |
parent | 377625e5391178db4fba7e24288a813c5abd43e9 (diff) | |
download | uxp-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')
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"; |