From de41c625dd26de34b45f0726f5bc3a4e3702f5d1 Mon Sep 17 00:00:00 2001 From: Robin Templeton Date: Thu, 24 May 2018 11:26:09 -0700 Subject: [PATCH] Bug 1366287 - Part 1.0: Define a new BigInt primitive type, with a GDB prettyprinter, Rust binding support, and a new out-of-line TraceKind. (Disabled by default, implemented only incompletely, currently passing --enable-bigint will disable JITs, will be flipped on Eventually once every sub-aspect is in place, Don't Have A Cow, Man.) r=jwalden, r=Ms2ger, r=sfink --HG-- extra : rebase_source : aa13bd94bc6157ff8134894e3ba2e7a2b53e28d9 --- js/moz.configure | 20 ++++- js/public/Conversions.h | 2 +- js/public/GCPolicyAPI.h | 4 + js/public/MemoryMetrics.h | 6 ++ js/public/TraceKind.h | 6 +- js/public/TracingAPI.h | 6 ++ js/public/TypeDecls.h | 21 +++++ js/public/UbiNode.h | 18 ++++ js/public/Value.h | 78 ++++++++++++++++- js/rust/Cargo.toml | 1 + js/rust/build.rs | 8 ++ js/rust/src/jsval.rs | 41 +++++++++ js/rust/src/rust.rs | 6 ++ js/src/Cargo.toml | 1 + js/src/NamespaceImports.h | 18 ++++ js/src/build.rs | 14 ++-- js/src/builtin/Array.cpp | 6 ++ js/src/builtin/Boolean.cpp | 7 ++ js/src/builtin/JSON.cpp | 7 ++ js/src/builtin/MapObject.cpp | 21 ++++- js/src/devtools/automation/variants/bigint | 7 ++ .../devtools/automation/variants/bigintdebug | 7 ++ js/src/gc/AllocKind.h | 1 + js/src/gc/AtomMarking.cpp | 10 ++- js/src/gc/DeletePolicy.h | 6 ++ js/src/gc/GC.cpp | 15 +++- js/src/gc/Marking-inl.h | 4 + js/src/gc/Marking.cpp | 25 +++++- js/src/gc/Marking.h | 9 +- js/src/gc/Tracer.cpp | 9 ++ js/src/gdb/lib-for-tests/prologue.py | 7 ++ js/src/gdb/mozilla/jsval.py | 11 +++ js/src/gdb/tests/test-jsval.cpp | 10 +++ js/src/gdb/tests/test-jsval.py | 2 + js/src/js.msg | 9 ++ js/src/jsnum.cpp | 18 +++- js/src/jspubtd.h | 3 + js/src/moz.build | 5 ++ js/src/util/StringBuffer.cpp | 8 ++ js/src/vm/BigIntType.cpp | 83 +++++++++++++++++++ js/src/vm/BigIntType.h | 60 ++++++++++++++ js/src/vm/CommonPropertyNames.h | 3 +- js/src/vm/Interpreter.cpp | 12 ++- js/src/vm/JSAtom.cpp | 8 ++ js/src/vm/JSCompartment-inl.h | 10 +++ js/src/vm/JSCompartment.cpp | 17 ++++ js/src/vm/JSCompartment.h | 3 + js/src/vm/JSObject.cpp | 11 +++ js/src/vm/MemoryMetrics.cpp | 12 +++ js/src/vm/StringType.cpp | 10 ++- js/src/vm/TypeInference-inl.h | 8 ++ js/src/vm/TypeInference.cpp | 8 ++ js/src/vm/TypeInference.h | 25 +++++- js/src/vm/UbiNode.cpp | 20 ++++- 54 files changed, 718 insertions(+), 29 deletions(-) create mode 100644 js/src/devtools/automation/variants/bigint create mode 100644 js/src/devtools/automation/variants/bigintdebug create mode 100644 js/src/vm/BigIntType.cpp create mode 100644 js/src/vm/BigIntType.h diff --git a/js/moz.configure b/js/moz.configure index 5aee8ed781b8..3b07120e6d74 100644 --- a/js/moz.configure +++ b/js/moz.configure @@ -102,13 +102,29 @@ def disable_export_js(value): die('Setting %s is deprecated, use %s instead.', value.format('DISABLE_EXPORT_JS'), suggestion) +# Experimental BigInt support +# ======================================================= +js_option('--enable-bigint', + default=False, + help='Enable BigInt') + +@depends('--enable-bigint') +def enable_bigint(value): + if value: + return True + +set_config('ENABLE_BIGINT', enable_bigint) +set_define('ENABLE_BIGINT', enable_bigint) # JIT support # ======================================================= -@depends(target) -def ion_default(target): +@depends(target, '--enable-bigint') +def ion_default(target, enable_bigint): + if enable_bigint: + return False if target.cpu in ('x86', 'x86_64', 'arm', 'aarch64', 'mips32', 'mips64'): return True + return False js_option('--enable-ion', default=ion_default, diff --git a/js/public/Conversions.h b/js/public/Conversions.h index 4aeeb697ad67..02ec5158efb9 100644 --- a/js/public/Conversions.h +++ b/js/public/Conversions.h @@ -122,7 +122,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 5187949f2e33..8b8297b0d1c0 100644 --- a/js/public/GCPolicyAPI.h +++ b/js/public/GCPolicyAPI.h @@ -50,6 +50,7 @@ // Expand the given macro D for each public GC pointer. #define FOR_EACH_PUBLIC_GC_POINTER_TYPE(D) \ D(JS::Symbol*) \ + IF_BIGINT(D(JS::BigInt*),) \ D(JSAtom*) \ D(JSFunction*) \ D(JSObject*) \ @@ -127,6 +128,9 @@ struct GCPointerPolicy } }; template <> struct GCPolicy : public GCPointerPolicy {}; +#ifdef ENABLE_BIGINT +template <> struct GCPolicy : public GCPointerPolicy {}; +#endif template <> struct GCPolicy : public GCPointerPolicy {}; template <> struct GCPolicy : public GCPointerPolicy {}; template <> struct GCPolicy : public GCPointerPolicy {}; diff --git a/js/public/MemoryMetrics.h b/js/public/MemoryMetrics.h index 0cb5535da7fd..e4cdb71c8bcc 100644 --- a/js/public/MemoryMetrics.h +++ b/js/public/MemoryMetrics.h @@ -629,6 +629,7 @@ struct UnusedGCThingSizes macro(Other, GCHeapUnused, objectGroup) \ macro(Other, GCHeapUnused, string) \ macro(Other, GCHeapUnused, symbol) \ + IF_BIGINT(macro(Other, GCHeapUnused, bigInt),) \ macro(Other, GCHeapUnused, jitcode) \ macro(Other, GCHeapUnused, scope) \ macro(Other, GCHeapUnused, regExpShared) @@ -648,6 +649,9 @@ struct UnusedGCThingSizes case JS::TraceKind::Object: object += n; break; case JS::TraceKind::String: string += n; break; case JS::TraceKind::Symbol: symbol += n; break; +#ifdef ENABLE_BIGINT + case JS::TraceKind::BigInt: bigInt += n; break; +#endif case JS::TraceKind::Script: script += n; break; case JS::TraceKind::Shape: shape += n; break; case JS::TraceKind::BaseShape: baseShape += n; break; @@ -689,6 +693,8 @@ struct ZoneStats { #define FOR_EACH_SIZE(macro) \ macro(Other, GCHeapUsed, symbolsGCHeap) \ + IF_BIGINT(macro(Other, GCHeapUsed, bigIntsGCHeap),) \ + IF_BIGINT(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 145d2dac8199..719ed7945013 100644 --- a/js/public/TraceKind.h +++ b/js/public/TraceKind.h @@ -61,7 +61,10 @@ enum class TraceKind JitCode = 0x1F, LazyScript = 0x2F, Scope = 0x3F, - RegExpShared = 0x4F + RegExpShared = 0x4F, +#ifdef ENABLE_BIGINT + BigInt = 0x5F +#endif }; const static uintptr_t OutOfLineTraceKindMask = 0x07; @@ -97,6 +100,7 @@ struct MapTypeToTraceKind { D(Shape, js::Shape, true) \ D(String, JSString, false) \ D(Symbol, JS::Symbol, false) \ + IF_BIGINT(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 1dff19abba96..0f07681f4dda 100644 --- a/js/public/TracingAPI.h +++ b/js/public/TracingAPI.h @@ -151,6 +151,9 @@ 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)); } +#ifdef ENABLE_BIGINT + virtual void onBigIntEdge(JS::BigInt** bip) { onChild(JS::GCCellPtr(*bip)); } +#endif virtual void onScriptEdge(JSScript** scriptp) { onChild(JS::GCCellPtr(*scriptp)); } virtual void onShapeEdge(js::Shape** shapep) { onChild(JS::GCCellPtr(*shapep, JS::TraceKind::Shape)); @@ -243,6 +246,9 @@ 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); } +#ifdef ENABLE_BIGINT + void dispatchToOnEdge(JS::BigInt** bip) { onBigIntEdge(bip); } +#endif 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 8b1536eae47d..1b9fbfe318ce 100644 --- a/js/public/TypeDecls.h +++ b/js/public/TypeDecls.h @@ -41,6 +41,9 @@ namespace JS { typedef unsigned char Latin1Char; class Symbol; +#ifdef ENABLE_BIGINT +class BigInt; +#endif union Value; class Realm; struct Runtime; @@ -57,6 +60,9 @@ typedef Handle HandleObject; typedef Handle HandleScript; typedef Handle HandleString; typedef Handle HandleSymbol; +#ifdef ENABLE_BIGINT +typedef Handle HandleBigInt; +#endif typedef Handle HandleValue; typedef MutableHandle MutableHandleFunction; @@ -65,6 +71,9 @@ typedef MutableHandle MutableHandleObject; typedef MutableHandle MutableHandleScript; typedef MutableHandle MutableHandleString; typedef MutableHandle MutableHandleSymbol; +#ifdef ENABLE_BIGINT +typedef MutableHandle MutableHandleBigInt; +#endif typedef MutableHandle MutableHandleValue; typedef Rooted RootedObject; @@ -72,6 +81,9 @@ typedef Rooted RootedFunction; typedef Rooted RootedScript; typedef Rooted RootedString; typedef Rooted RootedSymbol; +#ifdef ENABLE_BIGINT +typedef Rooted RootedBigInt; +#endif typedef Rooted RootedId; typedef Rooted RootedValue; @@ -81,8 +93,17 @@ typedef PersistentRooted PersistentRootedObject; typedef PersistentRooted PersistentRootedScript; typedef PersistentRooted PersistentRootedString; typedef PersistentRooted PersistentRootedSymbol; +#ifdef ENABLE_BIGINT +typedef PersistentRooted PersistentRootedBigInt; +#endif typedef PersistentRooted PersistentRootedValue; } // namespace JS +#ifdef ENABLE_BIGINT +#define IF_BIGINT(x, y) x +#else +#define IF_BIGINT(x, y) y +#endif + #endif /* js_TypeDecls_h */ diff --git a/js/public/UbiNode.h b/js/public/UbiNode.h index 1fb5db17f310..5ec507285e44 100644 --- a/js/public/UbiNode.h +++ b/js/public/UbiNode.h @@ -1056,6 +1056,24 @@ class JS_PUBLIC_API(Concrete) : TracerConcrete { static const char16_t concreteTypeName[]; }; +#ifdef ENABLE_BIGINT +template<> +class JS_PUBLIC_API(Concrete) : TracerConcrete { + 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[]; +}; +#endif + template<> class JS_PUBLIC_API(Concrete) : TracerConcreteWithCompartment { protected: diff --git a/js/public/Value.h b/js/public/Value.h index 30e3dc25ee4f..4033960f980f 100644 --- a/js/public/Value.h +++ b/js/public/Value.h @@ -59,6 +59,9 @@ enum JSValueType : uint8_t JSVAL_TYPE_STRING = 0x06, JSVAL_TYPE_SYMBOL = 0x07, JSVAL_TYPE_PRIVATE_GCTHING = 0x08, +#ifdef ENABLE_BIGINT + JSVAL_TYPE_BIGINT = 0x09, +#endif JSVAL_TYPE_OBJECT = 0x0c, /* These never appear in a jsval; they are only provided as an out-of-band value. */ @@ -82,6 +85,9 @@ JS_ENUM_HEADER(JSValueTag, uint32_t) JSVAL_TAG_STRING = JSVAL_TAG_CLEAR | JSVAL_TYPE_STRING, JSVAL_TAG_SYMBOL = JSVAL_TAG_CLEAR | JSVAL_TYPE_SYMBOL, JSVAL_TAG_PRIVATE_GCTHING = JSVAL_TAG_CLEAR | JSVAL_TYPE_PRIVATE_GCTHING, +#ifdef ENABLE_BIGINT + JSVAL_TAG_BIGINT = JSVAL_TAG_CLEAR | JSVAL_TYPE_BIGINT, +#endif JSVAL_TAG_OBJECT = JSVAL_TAG_CLEAR | JSVAL_TYPE_OBJECT } JS_ENUM_FOOTER(JSValueTag); @@ -101,6 +107,9 @@ JS_ENUM_HEADER(JSValueTag, uint32_t) JSVAL_TAG_STRING = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_STRING, JSVAL_TAG_SYMBOL = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_SYMBOL, JSVAL_TAG_PRIVATE_GCTHING = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_PRIVATE_GCTHING, +#ifdef ENABLE_BIGINT + JSVAL_TAG_BIGINT = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_BIGINT, +#endif JSVAL_TAG_OBJECT = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_OBJECT } JS_ENUM_FOOTER(JSValueTag); @@ -118,6 +127,9 @@ enum JSValueShiftedTag : uint64_t JSVAL_SHIFTED_TAG_STRING = (((uint64_t)JSVAL_TAG_STRING) << JSVAL_TAG_SHIFT), JSVAL_SHIFTED_TAG_SYMBOL = (((uint64_t)JSVAL_TAG_SYMBOL) << JSVAL_TAG_SHIFT), JSVAL_SHIFTED_TAG_PRIVATE_GCTHING = (((uint64_t)JSVAL_TAG_PRIVATE_GCTHING) << JSVAL_TAG_SHIFT), +#ifdef ENABLE_BIGINT + JSVAL_SHIFTED_TAG_BIGINT = (((uint64_t)JSVAL_TAG_BIGINT) << JSVAL_TAG_SHIFT), +#endif JSVAL_SHIFTED_TAG_OBJECT = (((uint64_t)JSVAL_TAG_OBJECT) << JSVAL_TAG_SHIFT) }; @@ -261,7 +273,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. * @@ -343,6 +355,9 @@ union MOZ_NON_PARAM alignas(8) Value uint32_t boo_; // Don't use |bool| -- it must be four bytes. JSString* str_; JS::Symbol* sym_; +#ifdef ENABLE_BIGINT + JS::BigInt* bi_; +#endif JSObject* obj_; js::gc::Cell* cell_; void* ptr_; @@ -454,6 +469,13 @@ union MOZ_NON_PARAM alignas(8) Value asBits_ = bitsFromTagAndPayload(JSVAL_TAG_SYMBOL, PayloadType(sym)); } +#ifdef ENABLE_BIGINT + void setBigInt(JS::BigInt* bi) { + MOZ_ASSERT(js::gc::IsCellPointerValid(bi)); + asBits_ = bitsFromTagAndPayload(JSVAL_TAG_BIGINT, PayloadType(bi)); + } +#endif + void setObject(JSObject& obj) { MOZ_ASSERT(js::gc::IsCellPointerValid(&obj)); @@ -620,6 +642,12 @@ union MOZ_NON_PARAM alignas(8) Value return toTag() == JSVAL_TAG_SYMBOL; } +#ifdef ENABLE_BIGINT + bool isBigInt() const { + return toTag() == JSVAL_TAG_BIGINT; + } +#endif + bool isObject() const { #if defined(JS_NUNBOX32) return toTag() == JSVAL_TAG_OBJECT; @@ -681,6 +709,10 @@ union MOZ_NON_PARAM alignas(8) Value "Value type tags must correspond with JS::TraceKinds."); if (MOZ_UNLIKELY(isPrivateGCThing())) return JS::GCThingTraceKind(toGCThing()); +#ifdef ENABLE_BIGINT + if (MOZ_UNLIKELY(isBigInt())) + return JS::TraceKind::BigInt; +#endif return JS::TraceKind(toTag() & 0x03); } @@ -745,6 +777,17 @@ union MOZ_NON_PARAM alignas(8) Value #endif } +#ifdef ENABLE_BIGINT + JS::BigInt* toBigInt() const { + MOZ_ASSERT(isBigInt()); +#if defined(JS_NUNBOX32) + return s_.payload_.bi_; +#elif defined(JS_PUNBOX64) + return reinterpret_cast(asBits_ ^ JSVAL_SHIFTED_TAG_BIGINT); +#endif + } +#endif + JSObject& toObject() const { MOZ_ASSERT(isObject()); #if defined(JS_NUNBOX32) @@ -862,6 +905,10 @@ union 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."); +#ifdef ENABLE_BIGINT + MOZ_ASSERT(JS::GCThingTraceKind(cell) != JS::TraceKind::BigInt, + "Private GC thing Values must not be BigInts. Make a BigIntValue instead."); +#endif MOZ_ASSERT(JS::GCThingTraceKind(cell) != JS::TraceKind::Object, "Private GC thing Values must not be objects. Make an ObjectValue instead."); @@ -987,6 +1034,16 @@ SymbolValue(JS::Symbol* sym) return v; } +#ifdef ENABLE_BIGINT +static inline Value +BigIntValue(JS::BigInt* bi) +{ + Value v; + v.setBigInt(bi); + return v; +} +#endif + static inline Value BooleanValue(bool boo) { @@ -1242,6 +1299,9 @@ class WrappedPtrOperations bool isDouble() const { return value().isDouble(); } bool isString() const { return value().isString(); } bool isSymbol() const { return value().isSymbol(); } +#ifdef ENABLE_BIGINT + bool isBigInt() const { return value().isBigInt(); } +#endif bool isObject() const { return value().isObject(); } bool isMagic() const { return value().isMagic(); } bool isMagic(JSWhyMagic why) const { return value().isMagic(why); } @@ -1257,6 +1317,9 @@ class WrappedPtrOperations double toDouble() const { return value().toDouble(); } JSString* toString() const { return value().toString(); } JS::Symbol* toSymbol() const { return value().toSymbol(); } +#ifdef ENABLE_BIGINT + JS::BigInt* toBigInt() const { return value().toBigInt(); } +#endif JSObject& toObject() const { return value().toObject(); } JSObject* toObjectOrNull() const { return value().toObjectOrNull(); } gc::Cell* toGCThing() const { return value().toGCThing(); } @@ -1294,6 +1357,9 @@ class MutableWrappedPtrOperations : public WrappedPtrOperati bool setNumber(double d) { return value().setNumber(d); } void setString(JSString* str) { this->value().setString(str); } void setSymbol(JS::Symbol* sym) { this->value().setSymbol(sym); } +#ifdef ENABLE_BIGINT + void setBigInt(JS::BigInt* bi) { this->value().setBigInt(bi); } +#endif void setObject(JSObject& obj) { this->value().setObject(obj); } void setObjectOrNull(JSObject* arg) { this->value().setObjectOrNull(arg); } void setPrivate(void* ptr) { this->value().setPrivate(ptr); } @@ -1322,6 +1388,9 @@ class HeapBase : public WrappedPtrOperations(args)...); } +#ifdef ENABLE_BIGINT + if (val.isBigInt()) { + JS::BigInt* bi = val.toBigInt(); + MOZ_ASSERT(gc::IsCellPointerValid(bi)); + return f(bi, mozilla::Forward(args)...); + } +#endif if (MOZ_UNLIKELY(val.isPrivateGCThing())) { MOZ_ASSERT(gc::IsCellPointerValid(val.toGCThing())); return DispatchTyped(f, val.toGCCellPtr(), mozilla::Forward(args)...); diff --git a/js/rust/Cargo.toml b/js/rust/Cargo.toml index 624dfc6cd040..d821f24f7ce7 100644 --- a/js/rust/Cargo.toml +++ b/js/rust/Cargo.toml @@ -39,6 +39,7 @@ doctest = false debugmozjs = ['mozjs_sys/debugmozjs'] promises = ['mozjs_sys/promises'] nonzero = [] +bigint = ['mozjs_sys/bigint'] [dependencies.mozjs_sys] path = "../src" diff --git a/js/rust/build.rs b/js/rust/build.rs index eff9a04ea511..1f8eae7d6910 100644 --- a/js/rust/build.rs +++ b/js/rust/build.rs @@ -73,6 +73,10 @@ fn build_jsapi_bindings() { .clang_arg("-DJS_DEBUG"); } + if cfg!(feature = "bigint") { + builder = builder.clang_arg("-DENABLE_BIGINT"); + } + let include_dir = get_mozjs_include_dir(); let include_dir = include_dir.to_str() .expect("Path to mozjs include dir should be utf-8"); @@ -99,6 +103,10 @@ fn build_jsapi_bindings() { builder = builder.whitelist_function(func); } + if cfg!(feature = "bigint") { + builder = builder.whitelist_type("JS::BigInt"); + } + for ty in OPAQUE_TYPES { builder = builder.opaque_type(ty); } diff --git a/js/rust/src/jsval.rs b/js/rust/src/jsval.rs index 6df051e0754a..ac9e42647494 100644 --- a/js/rust/src/jsval.rs +++ b/js/rust/src/jsval.rs @@ -25,6 +25,8 @@ enum ValueTag { UNDEFINED = JSVAL_TAG_MAX_DOUBLE | (JSValueType::JSVAL_TYPE_UNDEFINED as u32), STRING = JSVAL_TAG_MAX_DOUBLE | (JSValueType::JSVAL_TYPE_STRING as u32), SYMBOL = JSVAL_TAG_MAX_DOUBLE | (JSValueType::JSVAL_TYPE_SYMBOL as u32), + #[cfg(feature = "bigint")] + BIGINT = JSVAL_TAG_MAX_DOUBLE | (JSValueType::JSVAL_TYPE_BIGINT as u32), BOOLEAN = JSVAL_TAG_MAX_DOUBLE | (JSValueType::JSVAL_TYPE_BOOLEAN as u32), MAGIC = JSVAL_TAG_MAX_DOUBLE | (JSValueType::JSVAL_TYPE_MAGIC as u32), NULL = JSVAL_TAG_MAX_DOUBLE | (JSValueType::JSVAL_TYPE_NULL as u32), @@ -41,6 +43,8 @@ enum ValueTag { UNDEFINED = JSVAL_TAG_CLEAR as u32 | (JSValueType::JSVAL_TYPE_UNDEFINED as u32), STRING = JSVAL_TAG_CLEAR as u32 | (JSValueType::JSVAL_TYPE_STRING as u32), SYMBOL = JSVAL_TAG_CLEAR as u32 | (JSValueType::JSVAL_TYPE_SYMBOL as u32), + #[cfg(feature = "bigint")] + BIGINT = JSVAL_TAG_CLEAR as u32 | (JSValueType::JSVAL_TYPE_BIGINT as u32), BOOLEAN = JSVAL_TAG_CLEAR as u32 | (JSValueType::JSVAL_TYPE_BOOLEAN as u32), MAGIC = JSVAL_TAG_CLEAR as u32 | (JSValueType::JSVAL_TYPE_MAGIC as u32), NULL = JSVAL_TAG_CLEAR as u32 | (JSValueType::JSVAL_TYPE_NULL as u32), @@ -57,6 +61,8 @@ enum ValueShiftedTag { UNDEFINED = ((ValueTag::UNDEFINED as u64) << JSVAL_TAG_SHIFT), STRING = ((ValueTag::STRING as u64) << JSVAL_TAG_SHIFT), SYMBOL = ((ValueTag::SYMBOL as u64) << JSVAL_TAG_SHIFT), + #[cfg(feature = "bigint")] + BIGINT = ((ValueTag::BIGINT as u64) << JSVAL_TAG_SHIFT), BOOLEAN = ((ValueTag::BOOLEAN as u64) << JSVAL_TAG_SHIFT), MAGIC = ((ValueTag::MAGIC as u64) << JSVAL_TAG_SHIFT), NULL = ((ValueTag::NULL as u64) << JSVAL_TAG_SHIFT), @@ -187,6 +193,23 @@ pub fn PrivateValue(o: *const c_void) -> JS::Value { BuildJSVal(ValueTag::PRIVATE, ptrBits) } +#[inline(always)] +#[cfg(feature = "bigint")] +#[cfg(target_pointer_width = "64")] +pub fn BigIntValue(b: &JS::BigInt) -> JS::Value { + let bits = b as *const JS::BigInt as usize as u64; + assert!((bits >> JSVAL_TAG_SHIFT) == 0); + BuildJSVal(ValueTag::BIGINT, bits) +} + +#[inline(always)] +#[cfg(target_pointer_width = "32")] +#[inline(always)] +pub fn BigIntValue(s: &JS::BigInt) -> JS::Value { + let bits = s as *const JS::BigInt as usize as u64; + BuildJSVal(ValueTag::BIGINT, bits) +} + impl JS::Value { #[inline(always)] unsafe fn asBits(&self) -> u64 { @@ -363,6 +386,24 @@ impl JS::Value { } } + #[inline(always)] + #[cfg(feature = "bigint")] + #[cfg(target_pointer_width = "64")] + pub fn is_bigint(&self) -> bool { + unsafe { + (self.asBits() >> JSVAL_TAG_SHIFT) == ValueTag::BIGINT as u64 + } + } + + #[inline(always)] + #[cfg(feature = "bigint")] + #[cfg(target_pointer_width = "32")] + pub fn is_bigint(&self) -> bool { + unsafe { + (self.asBits() >> 32) == ValueTag::BIGINT as u64 + } + } + #[inline(always)] #[cfg(target_pointer_width = "64")] pub fn to_boolean(&self) -> bool { diff --git a/js/rust/src/rust.rs b/js/rust/src/rust.rs index 438757cafe87..ad8bb0a2e80d 100644 --- a/js/rust/src/rust.rs +++ b/js/rust/src/rust.rs @@ -306,6 +306,12 @@ impl RootKind for *mut JS::Symbol { fn rootKind() -> JS::RootKind { JS::RootKind::Symbol } } +#[cfg(feature = "bigint")] +impl RootKind for *mut JS::BigInt { + #[inline(always)] + fn rootKind() -> JS::RootKind { JS::RootKind::BigInt } +} + impl RootKind for *mut JSScript { #[inline(always)] fn rootKind() -> JS::RootKind { JS::RootKind::Script } diff --git a/js/src/Cargo.toml b/js/src/Cargo.toml index 4829b49b101e..060ea42f4b5d 100644 --- a/js/src/Cargo.toml +++ b/js/src/Cargo.toml @@ -8,6 +8,7 @@ build = "build.rs" [features] debugmozjs = [] promises = [] +bigint = [] [lib] name = "mozjs_sys" diff --git a/js/src/NamespaceImports.h b/js/src/NamespaceImports.h index ec85f2d87024..e8dfa3557b4c 100644 --- a/js/src/NamespaceImports.h +++ b/js/src/NamespaceImports.h @@ -47,6 +47,9 @@ class PropertyResult; enum class SymbolCode: uint32_t; +#ifdef ENABLE_BIGINT +class BigInt; +#endif } // namespace JS // Do the importing. @@ -112,6 +115,9 @@ using JS::RootedObject; using JS::RootedScript; using JS::RootedString; using JS::RootedSymbol; +#ifdef ENABLE_BIGINT +using JS::RootedBigInt; +#endif using JS::RootedValue; using JS::PersistentRooted; @@ -121,6 +127,9 @@ using JS::PersistentRootedObject; using JS::PersistentRootedScript; using JS::PersistentRootedString; using JS::PersistentRootedSymbol; +#ifdef ENABLE_BIGINT +using JS::PersistentRootedBigInt; +#endif using JS::PersistentRootedValue; using JS::Handle; @@ -130,6 +139,9 @@ using JS::HandleObject; using JS::HandleScript; using JS::HandleString; using JS::HandleSymbol; +#ifdef ENABLE_BIGINT +using JS::HandleBigInt; +#endif using JS::HandleValue; using JS::MutableHandle; @@ -139,6 +151,9 @@ using JS::MutableHandleObject; using JS::MutableHandleScript; using JS::MutableHandleString; using JS::MutableHandleSymbol; +#ifdef ENABLE_BIGINT +using JS::MutableHandleBigInt; +#endif using JS::MutableHandleValue; using JS::NullHandleValue; @@ -157,6 +172,9 @@ using JS::Zone; using JS::Symbol; using JS::SymbolCode; +#ifdef ENABLE_BIGINT +using JS::BigInt; +#endif } /* namespace js */ #endif /* NamespaceImports_h */ diff --git a/js/src/build.rs b/js/src/build.rs index 5230e5ed803c..e42c1020d0b8 100644 --- a/js/src/build.rs +++ b/js/src/build.rs @@ -16,11 +16,9 @@ fn main() { env::set_var("MAKEFLAGS", format!("-j{}", num_cpus::get())); env::set_current_dir(&js_src).unwrap(); - let variant = if cfg!(feature = "debugmozjs") { - "plaindebug" - } else { - "plain" - }; + let variant = format!("{}{}", + if cfg!(feature = "bigint") { "bigint" } else { "plain" }, + if cfg!(feature = "debugmozjs") { "debug" } else { "" }); let python = env::var("PYTHON").unwrap_or("python2.7".into()); let mut cmd = Command::new(&python); @@ -36,7 +34,7 @@ fn main() { // already exists but wasn't created by autospider. "--dep", "--objdir", &out_dir, - variant]) + &variant]) .env("SOURCE", &js_src) .env("PWD", &js_src) .stdout(Stdio::inherit()) @@ -54,6 +52,10 @@ fn main() { println!("cargo:rustc-link-search=native={}/dist/bin", out_dir); println!("cargo:rustc-link-lib=nspr4"); + if cfg!(feature = "bigint") { + println!("cargo:rustc-link-lib=gmp"); + } + if target.contains("windows") { println!("cargo:rustc-link-lib=winmm"); if target.contains("gnu") { diff --git a/js/src/builtin/Array.cpp b/js/src/builtin/Array.cpp index 98fb372e834b..8955563cd1e4 100644 --- a/js/src/builtin/Array.cpp +++ b/js/src/builtin/Array.cpp @@ -1272,6 +1272,12 @@ ArrayJoinDenseKernel(JSContext* cx, SeparatorOp sepOp, HandleNativeObject obj, u * with those as well. */ break; + } else if (IF_BIGINT(elem.isBigInt(), false)) { + // 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/builtin/Boolean.cpp b/js/src/builtin/Boolean.cpp index 439c7f21a34d..df6138b25d6c 100644 --- a/js/src/builtin/Boolean.cpp +++ b/js/src/builtin/Boolean.cpp @@ -15,6 +15,9 @@ #include "jit/InlinableNatives.h" #include "util/StringBuffer.h" +#ifdef ENABLE_BIGINT +#include "vm/BigIntType.h" +#endif #include "vm/GlobalObject.h" #include "vm/JSAtom.h" #include "vm/JSContext.h" @@ -164,6 +167,10 @@ js::ToBooleanSlow(HandleValue v) { if (v.isString()) return v.toString()->length() != 0; +#ifdef ENABLE_BIGINT + if (v.isBigInt()) + return v.toBigInt()->toBoolean(); +#endif MOZ_ASSERT(v.isObject()); return !EmulatesUndefined(&v.toObject()); diff --git a/js/src/builtin/JSON.cpp b/js/src/builtin/JSON.cpp index 67e2a73a31c8..d5731280ec08 100644 --- a/js/src/builtin/JSON.cpp +++ b/js/src/builtin/JSON.cpp @@ -587,6 +587,13 @@ Str(JSContext* cx, const Value& v, StringifyContext* scx) return NumberValueToStringBuffer(cx, v, scx->sb); } +#ifdef ENABLE_BIGINT + if (v.isBigInt()) { + JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BIGINT_NOT_SERIALIZABLE); + return false; + } +#endif + /* Step 10. */ MOZ_ASSERT(v.isObject()); RootedObject obj(cx, &v.toObject()); diff --git a/js/src/builtin/MapObject.cpp b/js/src/builtin/MapObject.cpp index 1a9157f21ff0..9879d83f61d6 100644 --- a/js/src/builtin/MapObject.cpp +++ b/js/src/builtin/MapObject.cpp @@ -57,7 +57,8 @@ 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() || + IF_BIGINT(value.isBigInt(), false)); return true; } @@ -77,6 +78,10 @@ HashValue(const Value& v, const mozilla::HashCodeScrambler& hcs) return v.toString()->asAtom().hash(); if (v.isSymbol()) return v.toSymbol()->hash(); +#ifdef ENABLE_BIGINT + if (v.isBigInt()) + return v.toBigInt()->hash(); +#endif if (v.isObject()) return hcs.scramble(v.asRawBits()); @@ -96,12 +101,24 @@ HashableValue::operator==(const HashableValue& other) const // Two HashableValues are equal if they have equal bits. bool b = (value.asRawBits() == other.value.asRawBits()); +#ifdef ENABLE_BIGINT + // 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())) { + JSContext* cx = TlsContext.get(); + RootedValue valueRoot(cx, value); + RootedValue otherRoot(cx, other.value); + SameValue(cx, valueRoot, otherRoot, &b); + } +#endif + #ifdef DEBUG bool same; JSContext* cx = TlsContext.get(); RootedValue valueRoot(cx, value); RootedValue otherRoot(cx, other.value); - MOZ_ASSERT(SameValue(nullptr, valueRoot, otherRoot, &same)); + MOZ_ASSERT(SameValue(cx, valueRoot, otherRoot, &same)); MOZ_ASSERT(same == b); #endif return b; diff --git a/js/src/devtools/automation/variants/bigint b/js/src/devtools/automation/variants/bigint new file mode 100644 index 000000000000..46cfd9d4c1c5 --- /dev/null +++ b/js/src/devtools/automation/variants/bigint @@ -0,0 +1,7 @@ +{ + "configure-args": "--enable-bigint", + "optimize": true, + "env": { + "JSTESTS_EXTRA_ARGS": "--jitflags=all" + } +} diff --git a/js/src/devtools/automation/variants/bigintdebug b/js/src/devtools/automation/variants/bigintdebug new file mode 100644 index 000000000000..c5f622fe84c3 --- /dev/null +++ b/js/src/devtools/automation/variants/bigintdebug @@ -0,0 +1,7 @@ +{ + "configure-args": "--enable-bigint", + "debug": true, + "env": { + "JSTESTS_EXTRA_ARGS": "--jitflags=debug" + } +} diff --git a/js/src/gc/AllocKind.h b/js/src/gc/AllocKind.h index c4f52bc5bf41..5ca648f5bec2 100644 --- a/js/src/gc/AllocKind.h +++ b/js/src/gc/AllocKind.h @@ -64,6 +64,7 @@ namespace gc { D(FAT_INLINE_ATOM, String, js::FatInlineAtom, js::FatInlineAtom, true, false) \ D(ATOM, String, js::NormalAtom, js::NormalAtom, true, false) \ D(SYMBOL, Symbol, JS::Symbol, JS::Symbol, true, false) \ + IF_BIGINT(D(BIGINT, BigInt, JS::BigInt, JS::BigInt, true, false),) \ D(JITCODE, JitCode, js::jit::JitCode, js::jit::JitCode, false, false) \ D(SCOPE, Scope, js::Scope, js::Scope, true, false) \ D(REGEXP_SHARED, RegExpShared, js::RegExpShared, js::RegExpShared, true, false) diff --git a/js/src/gc/AtomMarking.cpp b/js/src/gc/AtomMarking.cpp index 5da857794bed..7369de1720a6 100644 --- a/js/src/gc/AtomMarking.cpp +++ b/js/src/gc/AtomMarking.cpp @@ -190,7 +190,10 @@ AtomMarkingRuntime::markAtomValue(JSContext* cx, const Value& value) markAtom(cx, value.toSymbol()); return; } - MOZ_ASSERT_IF(value.isGCThing(), value.isObject() || value.isPrivateGCThing()); + MOZ_ASSERT_IF(value.isGCThing(), + value.isObject() || + value.isPrivateGCThing() || + IF_BIGINT(value.isBigInt(), false)); } void @@ -272,7 +275,10 @@ AtomMarkingRuntime::valueIsMarked(Zone* zone, const Value& value) if (value.isSymbol()) return atomIsMarked(zone, value.toSymbol()); - MOZ_ASSERT_IF(value.isGCThing(), value.isObject() || value.isPrivateGCThing()); + MOZ_ASSERT_IF(value.isGCThing(), + value.isObject() || + value.isPrivateGCThing() || + IF_BIGINT(value.isBigInt(), false)); return true; } diff --git a/js/src/gc/DeletePolicy.h b/js/src/gc/DeletePolicy.h index bfa21158dbba..edccfcfabc24 100644 --- a/js/src/gc/DeletePolicy.h +++ b/js/src/gc/DeletePolicy.h @@ -8,6 +8,9 @@ #define gc_DeletePolicy_h #include "js/TracingAPI.h" +#ifdef ENABLE_BIGINT +#include "vm/BigIntType.h" +#endif namespace js { namespace gc { @@ -26,6 +29,9 @@ struct ClearEdgesTracer : public JS::CallbackTracer void onObjectEdge(JSObject** objp) override; void onStringEdge(JSString** strp) override; void onSymbolEdge(JS::Symbol** symp) override; +#ifdef ENABLE_BIGINT + void onBigIntEdge(JS::BigInt** bip) override; +#endif void onScriptEdge(JSScript** scriptp) override; void onShapeEdge(js::Shape** shapep) override; void onObjectGroupEdge(js::ObjectGroup** groupp) override; diff --git a/js/src/gc/GC.cpp b/js/src/gc/GC.cpp index b4343a9362e5..9bc0fda04d35 100644 --- a/js/src/gc/GC.cpp +++ b/js/src/gc/GC.cpp @@ -224,6 +224,9 @@ #include "js/SliceBudget.h" #include "proxy/DeadObjectProxy.h" #include "util/Windows.h" +#ifdef ENABLE_BIGINT +#include "vm/BigIntType.h" +#endif #include "vm/Debugger.h" #include "vm/GeckoProfiler.h" #include "vm/JSAtom.h" @@ -495,7 +498,10 @@ static const FinalizePhase BackgroundFinalizePhases[] = { AllocKind::EXTERNAL_STRING, AllocKind::FAT_INLINE_ATOM, AllocKind::ATOM, - AllocKind::SYMBOL + AllocKind::SYMBOL, +#ifdef ENABLE_BIGINT + AllocKind::BIGINT +#endif } }, { @@ -8436,6 +8442,10 @@ JS::GCCellPtr::GCCellPtr(const Value& v) ptr = checkedCast(&v.toObject(), JS::TraceKind::Object); else if (v.isSymbol()) ptr = checkedCast(v.toSymbol(), JS::TraceKind::Symbol); +#ifdef ENABLE_BIGINT + else if (v.isBigInt()) + ptr = checkedCast(v.toBigInt(), JS::TraceKind::BigInt); +#endif else if (v.isPrivateGCThing()) ptr = checkedCast(v.toGCThing(), v.toGCThing()->getTraceKind()); else @@ -9138,6 +9148,9 @@ js::gc::ClearEdgesTracer::clearEdge(S** thingp) void js::gc::ClearEdgesTracer::onObjectEdge(JSObject** objp) { clearEdge(objp); } void js::gc::ClearEdgesTracer::onStringEdge(JSString** strp) { clearEdge(strp); } void js::gc::ClearEdgesTracer::onSymbolEdge(JS::Symbol** symp) { clearEdge(symp); } +#ifdef ENABLE_BIGINT +void js::gc::ClearEdgesTracer::onBigIntEdge(JS::BigInt** bip) { clearEdge(bip); } +#endif void js::gc::ClearEdgesTracer::onScriptEdge(JSScript** scriptp) { clearEdge(scriptp); } void js::gc::ClearEdgesTracer::onShapeEdge(js::Shape** shapep) { clearEdge(shapep); } void js::gc::ClearEdgesTracer::onObjectGroupEdge(js::ObjectGroup** groupp) { clearEdge(groupp); } diff --git a/js/src/gc/Marking-inl.h b/js/src/gc/Marking-inl.h index 4ed3acaf3c0c..548478f51292 100644 --- a/js/src/gc/Marking-inl.h +++ b/js/src/gc/Marking-inl.h @@ -11,6 +11,10 @@ #include "gc/RelocationOverlay.h" +#ifdef ENABLE_BIGINT +#include "vm/BigIntType.h" +#endif + namespace js { namespace gc { diff --git a/js/src/gc/Marking.cpp b/js/src/gc/Marking.cpp index dddb2b711484..520dbc2b2a81 100644 --- a/js/src/gc/Marking.cpp +++ b/js/src/gc/Marking.cpp @@ -21,6 +21,9 @@ #include "js/SliceBudget.h" #include "vm/ArgumentsObject.h" #include "vm/ArrayObject.h" +#ifdef ENABLE_BIGINT +#include "vm/BigIntType.h" +#endif #include "vm/Debugger.h" #include "vm/EnvironmentObject.h" #include "vm/RegExpObject.h" @@ -894,6 +897,9 @@ js::GCMarker::markAndTraceChildren(T* thing) namespace js { template <> void GCMarker::traverse(BaseShape* thing) { markAndTraceChildren(thing); } template <> void GCMarker::traverse(JS::Symbol* thing) { markAndTraceChildren(thing); } +#ifdef ENABLE_BIGINT +template <> void GCMarker::traverse(JS::BigInt* thing) { markAndTraceChildren(thing); } +#endif template <> void GCMarker::traverse(RegExpShared* thing) { markAndTraceChildren(thing); } } // namespace js @@ -1550,6 +1556,14 @@ js::GCMarker::lazilyMarkChildren(ObjectGroup* group) traverseEdge(group, static_cast(fun)); } +#ifdef ENABLE_BIGINT +void +JS::BigInt::traceChildren(JSTracer* trc) +{ + return; +} +#endif + struct TraverseObjectFunctor { template @@ -1694,7 +1708,8 @@ ObjectDenseElementsMayBeMarkable(NativeObject* nobj) return true; static const uint32_t flagMask = - TYPE_FLAG_STRING | TYPE_FLAG_SYMBOL | TYPE_FLAG_LAZYARGS | TYPE_FLAG_ANYOBJECT; + TYPE_FLAG_STRING | TYPE_FLAG_SYMBOL | TYPE_FLAG_LAZYARGS | TYPE_FLAG_ANYOBJECT | + IF_BIGINT(TYPE_FLAG_BIGINT, 0); bool mayBeMarkable = typeSet->hasAnyFlag(flagMask) || typeSet->getObjectCount() != 0; #ifdef DEBUG @@ -1808,7 +1823,13 @@ GCMarker::processMarkStackTop(SliceBudget& budget) } } else if (v.isSymbol()) { traverseEdge(obj, v.toSymbol()); - } else if (v.isPrivateGCThing()) { + } +#ifdef ENABLE_BIGINT + else if (v.isBigInt()) { + traverseEdge(obj, v.toBigInt()); + } +#endif + else if (v.isPrivateGCThing()) { // v.toGCCellPtr cannot be inlined, so construct one manually. Cell* cell = v.toGCThing(); traverseEdge(obj, JS::GCCellPtr(cell, cell->getTraceKind())); diff --git a/js/src/gc/Marking.h b/js/src/gc/Marking.h index dc648c24ac29..0d11a07db9df 100644 --- a/js/src/gc/Marking.h +++ b/js/src/gc/Marking.h @@ -109,6 +109,9 @@ struct RewrapTaggedPointer{}; DECLARE_REWRAP(JS::Value, JSObject, JS::ObjectOrNullValue, ); DECLARE_REWRAP(JS::Value, JSString, JS::StringValue, ); DECLARE_REWRAP(JS::Value, JS::Symbol, JS::SymbolValue, ); +#ifdef ENABLE_BIGINT +DECLARE_REWRAP(JS::Value, JS::BigInt, JS::BigIntValue, ); +#endif 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, ); @@ -119,7 +122,11 @@ struct IsPrivateGCThingInValue : public mozilla::EnableIf::value && !mozilla::IsBaseOf::value && !mozilla::IsBaseOf::value && - !mozilla::IsBaseOf::value, T> + !mozilla::IsBaseOf::value +#ifdef ENABLE_BIGINT + && !mozilla::IsBaseOf::value +#endif + , T> { static_assert(!mozilla::IsSame::value && !mozilla::IsSame::value, "T must not be Cell or TenuredCell"); diff --git a/js/src/gc/Tracer.cpp b/js/src/gc/Tracer.cpp index be72b1692b6d..b339237007e7 100644 --- a/js/src/gc/Tracer.cpp +++ b/js/src/gc/Tracer.cpp @@ -16,6 +16,9 @@ #include "gc/PublicIterators.h" #include "gc/Zone.h" #include "util/Text.h" +#ifdef ENABLE_BIGINT +#include "vm/BigIntType.h" +#endif #include "vm/JSFunction.h" #include "vm/JSScript.h" #include "vm/Shape.h" @@ -396,6 +399,12 @@ JS_GetTraceThingInfo(char* buf, size_t bufsize, JSTracer* trc, void* thing, name = "symbol"; break; +#ifdef ENABLE_BIGINT + case JS::TraceKind::BigInt: + name = "BigInt"; + break; +#endif + default: name = "INVALID"; break; diff --git a/js/src/gdb/lib-for-tests/prologue.py b/js/src/gdb/lib-for-tests/prologue.py index d5fe91b2ad12..7a7b28991bfd 100644 --- a/js/src/gdb/lib-for-tests/prologue.py +++ b/js/src/gdb/lib-for-tests/prologue.py @@ -69,6 +69,13 @@ def assert_subprinter_registered(printer, subprinter): "'info pretty-printer' says:\n" "%s" % (printer, subprinter, output)) +enable_bigint = False +try: + if gdb.lookup_type('JS::BigInt'): + enable_bigint = True +except: + pass + # Request full stack traces for Python errors. gdb.execute('set python print-stack full') diff --git a/js/src/gdb/mozilla/jsval.py b/js/src/gdb/mozilla/jsval.py index 953cbf33fc13..265e7ea2395a 100644 --- a/js/src/gdb/mozilla/jsval.py +++ b/js/src/gdb/mozilla/jsval.py @@ -146,6 +146,15 @@ class JSValueTypeCache(object): self.NULL = get('JSVAL_TYPE_NULL') self.OBJECT = get('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')) @@ -198,6 +207,8 @@ class JSValue(object): value = self.box.as_address().cast(self.cache.JSObject_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()' else: value = 'unrecognized!' return '$JS::Value(%s)' % (value,) diff --git a/js/src/gdb/tests/test-jsval.cpp b/js/src/gdb/tests/test-jsval.cpp index d2506668d5c1..7d4da4c02a73 100644 --- a/js/src/gdb/tests/test-jsval.cpp +++ b/js/src/gdb/tests/test-jsval.cpp @@ -1,6 +1,10 @@ #include "gdb-tests.h" #include "jsapi.h" +#ifdef ENABLE_BIGINT +#include "vm/BigIntType.h" +#endif + FRAGMENT(jsval, simple) { using namespace JS; @@ -18,6 +22,9 @@ FRAGMENT(jsval, simple) { RootedString hello(cx, JS_NewStringCopyZ(cx, "Hello!")); RootedValue friendly_string(cx, StringValue(hello)); RootedValue symbol(cx, SymbolValue(GetSymbolFor(cx, hello))); +#ifdef ENABLE_BIGINT + RootedValue bi(cx, BigIntValue(BigInt::create(cx))); +#endif RootedValue global(cx); global.setObject(*CurrentGlobalOrNull(cx)); @@ -38,5 +45,8 @@ FRAGMENT(jsval, simple) { use(empty_string); use(friendly_string); use(symbol); +#ifdef ENABLE_BIGINT + use(bi); +#endif use(global); } diff --git a/js/src/gdb/tests/test-jsval.py b/js/src/gdb/tests/test-jsval.py index 68a949e0b9a1..5196bdf4cb2c 100644 --- a/js/src/gdb/tests/test-jsval.py +++ b/js/src/gdb/tests/test-jsval.py @@ -15,5 +15,7 @@ assert_pretty('elements_hole', '$JS::MagicValue(JS_ELEMENTS_HOLE)') assert_pretty('empty_string', '$JS::Value("")') assert_pretty('friendly_string', '$JS::Value("Hello!")') assert_pretty('symbol', '$JS::Value(Symbol.for("Hello!"))') +if enable_bigint: + assert_pretty('bi', '$JS::BigIntValue()') assert_pretty('global', '$JS::Value((JSObject *) [object global] delegate)') assert_pretty('onehundredthirtysevenonehundredtwentyeighths', '$JS::DoubleValue(1.0703125)') diff --git a/js/src/js.msg b/js/src/js.msg index 0f6cadd5dfd3..5cf79dc3968c 100644 --- a/js/src/js.msg +++ b/js/src/js.msg @@ -647,3 +647,12 @@ MSG_DEF(JSMSG_BAD_RESPONSE_MIME_TYPE, 0, JSEXN_TYPEERR, "Res MSG_DEF(JSMSG_BAD_RESPONSE_CORS_SAME_ORIGIN, 0, JSEXN_TYPEERR, "Response.type must be 'basic', 'cors' or 'default'") MSG_DEF(JSMSG_BAD_RESPONSE_STATUS, 0, JSEXN_TYPEERR, "Response does not have ok status") MSG_DEF(JSMSG_RESPONSE_ALREADY_CONSUMED, 0, JSEXN_TYPEERR, "Response already consumed") + +// 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/jsnum.cpp b/js/src/jsnum.cpp index 0c4b6090f4dd..482d3cd3190d 100644 --- a/js/src/jsnum.cpp +++ b/js/src/jsnum.cpp @@ -1591,9 +1591,21 @@ js::ToNumberSlow(JSContext* 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() || IF_BIGINT(v.isBigInt(), false)); + if (!cx->helperThread()) { + unsigned errnum = JSMSG_SYMBOL_TO_NUMBER; +#ifdef ENABLE_BIGINT + if (v.isBigInt()) + errnum = JSMSG_BIGINT_TO_NUMBER; +#endif + JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, errnum); + } + return false; } /* diff --git a/js/src/jspubtd.h b/js/src/jspubtd.h index 45a0c45f6304..d373e326cda0 100644 --- a/js/src/jspubtd.h +++ b/js/src/jspubtd.h @@ -49,6 +49,9 @@ enum JSType { JSTYPE_BOOLEAN, /* boolean */ JSTYPE_NULL, /* null */ JSTYPE_SYMBOL, /* symbol */ +#ifdef ENABLE_BIGINT + JSTYPE_BIGINT, /* BigInt */ +#endif JSTYPE_LIMIT }; diff --git a/js/src/moz.build b/js/src/moz.build index 74d73f1f8ddb..0dd2034b59e2 100755 --- a/js/src/moz.build +++ b/js/src/moz.build @@ -458,6 +458,11 @@ SOURCES += [ 'vm/ProfilingStack.cpp', ] +if CONFIG['ENABLE_BIGINT']: + SOURCES += [ + 'vm/BigIntType.cpp', + ] + if CONFIG['JS_POSIX_NSPR']: UNIFIED_SOURCES += [ 'vm/PosixNSPR.cpp', diff --git a/js/src/util/StringBuffer.cpp b/js/src/util/StringBuffer.cpp index 56b757b07d91..86fee26981e1 100644 --- a/js/src/util/StringBuffer.cpp +++ b/js/src/util/StringBuffer.cpp @@ -164,6 +164,14 @@ js::ValueToStringBufferSlow(JSContext* cx, const Value& arg, StringBuffer& sb) JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_SYMBOL_TO_STRING); return false; } +#ifdef ENABLE_BIGINT + if (v.isBigInt()) { + JSString* str = BigInt::toString(cx, v.toBigInt()); + if (!str) + return false; + return sb.append(str); + } +#endif MOZ_ASSERT(v.isUndefined()); return sb.append(cx->names().undefined); } diff --git a/js/src/vm/BigIntType.cpp b/js/src/vm/BigIntType.cpp new file mode 100644 index 000000000000..a060b00a68f4 --- /dev/null +++ b/js/src/vm/BigIntType.cpp @@ -0,0 +1,83 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sts=4 et sw=4 tw=99: + * 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 "gc/Allocator.h" +#include "gc/Tracer.h" +#include "vm/JSContext.h" +#include "vm/SelfHosting.h" + +using namespace js; + +BigInt* +BigInt::create(JSContext* cx) +{ + BigInt* x = Allocate(cx); + if (!x) + return nullptr; + return x; +} + +BigInt* +BigInt::copy(JSContext* cx, HandleBigInt x) +{ + BigInt* bi = create(cx); + if (!bi) + return nullptr; + return bi; +} + +JSLinearString* +BigInt::toString(JSContext* cx, BigInt* x) +{ + return nullptr; +} + +void +BigInt::finalize(js::FreeOp* fop) +{ + return; +} + +JSAtom* +js::BigIntToAtom(JSContext* 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::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 000000000000..79da8e8c77ed --- /dev/null +++ b/js/src/vm/BigIntType.h @@ -0,0 +1,60 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sts=4 et sw=4 tw=99: + * 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/GC.h" +#include "gc/Heap.h" +#include "js/AllocPolicy.h" +#include "js/GCHashTable.h" +#include "js/RootingAPI.h" +#include "js/TypeDecls.h" +#include "vm/StringType.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_[js::gc::MinCellSize]; + + public: + // Allocate and initialize a BigInt value + static BigInt* create(JSContext* 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(JSContext* cx, BigInt* x); + bool toBoolean(); + + static BigInt* copy(JSContext* cx, Handle x); +}; + +static_assert(sizeof(BigInt) >= js::gc::MinCellSize, + "sizeof(BigInt) must be greater than the minimum allocation size"); + +} // namespace JS + +namespace js { + +extern JSAtom* +BigIntToAtom(JSContext* cx, JS::BigInt* bi); + +} // namespace js + +#endif diff --git a/js/src/vm/CommonPropertyNames.h b/js/src/vm/CommonPropertyNames.h index 262fd1055aca..35cfc2157269 100644 --- a/js/src/vm/CommonPropertyNames.h +++ b/js/src/vm/CommonPropertyNames.h @@ -464,6 +464,7 @@ macro(boolean, boolean, "boolean") \ macro(null, null, "null") \ macro(symbol, symbol, "symbol") \ - macro(defineDataPropertyIntrinsic, defineDataPropertyIntrinsic, "_DefineDataProperty") \ + macro(bigint, bigint, "bigint") \ + macro(defineDataPropertyIntrinsic, defineDataPropertyIntrinsic, "_DefineDataProperty") #endif /* vm_CommonPropertyNames_h */ diff --git a/js/src/vm/Interpreter.cpp b/js/src/vm/Interpreter.cpp index eb457c333cef..22dd9cd5393c 100644 --- a/js/src/vm/Interpreter.cpp +++ b/js/src/vm/Interpreter.cpp @@ -32,6 +32,9 @@ #include "util/StringBuffer.h" #include "vm/AsyncFunction.h" #include "vm/AsyncIteration.h" +#ifdef ENABLE_BIGINT +#include "vm/BigIntType.h" +#endif #include "vm/BytecodeUtil.h" #include "vm/Debugger.h" #include "vm/GeneratorObject.h" @@ -969,6 +972,10 @@ js::TypeOfValue(const Value& v) return TypeOfObject(&v.toObject()); if (v.isBoolean()) return JSTYPE_BOOLEAN; +#ifdef ENABLE_BIGINT + if (v.isBigInt()) + return JSTYPE_BIGINT; +#endif MOZ_ASSERT(v.isSymbol()); return JSTYPE_SYMBOL; } @@ -4383,7 +4390,10 @@ 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() && + IF_BIGINT(!v.isBigInt(), true)) + { NativeObject* proto; if (v.isNumber()) { proto = GlobalObject::getOrCreateNumberPrototype(cx, cx->global()); diff --git a/js/src/vm/JSAtom.cpp b/js/src/vm/JSAtom.cpp index bd763192bf71..ad25e95f1c0a 100644 --- a/js/src/vm/JSAtom.cpp +++ b/js/src/vm/JSAtom.cpp @@ -636,6 +636,14 @@ ToAtomSlow(JSContext* cx, typename MaybeRooted::HandleType arg) } return nullptr; } +#ifdef ENABLE_BIGINT + if (v.isBigInt()) { + JSAtom* atom = BigIntToAtom(cx, v.toBigInt()); + if (!allowGC && !atom) + cx->recoverFromOutOfMemory(); + return atom; + } +#endif MOZ_ASSERT(v.isUndefined()); return cx->names().undefined; } diff --git a/js/src/vm/JSCompartment-inl.h b/js/src/vm/JSCompartment-inl.h index 833ee809b5cf..5f4c9fb928e2 100644 --- a/js/src/vm/JSCompartment-inl.h +++ b/js/src/vm/JSCompartment-inl.h @@ -121,6 +121,16 @@ JSCompartment::wrap(JSContext* cx, JS::MutableHandleValue vp) return true; } +#ifdef ENABLE_BIGINT + if (vp.isBigInt()) { + JS::RootedBigInt bi(cx, vp.toBigInt()); + if (!wrap(cx, &bi)) + return false; + vp.setBigInt(bi); + return true; + } +#endif + MOZ_ASSERT(vp.isObject()); /* diff --git a/js/src/vm/JSCompartment.cpp b/js/src/vm/JSCompartment.cpp index 0391d5a06b0b..6a8dba128343 100644 --- a/js/src/vm/JSCompartment.cpp +++ b/js/src/vm/JSCompartment.cpp @@ -345,6 +345,23 @@ JSCompartment::wrap(JSContext* cx, MutableHandleString strp) return true; } +#ifdef ENABLE_BIGINT +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; +} +#endif + bool JSCompartment::getNonWrapperObjectForCurrentCompartment(JSContext* cx, MutableHandleObject obj) { diff --git a/js/src/vm/JSCompartment.h b/js/src/vm/JSCompartment.h index a967543f0f65..3dd4508dc06a 100644 --- a/js/src/vm/JSCompartment.h +++ b/js/src/vm/JSCompartment.h @@ -636,6 +636,9 @@ struct JSCompartment MOZ_MUST_USE inline bool wrap(JSContext* cx, JS::MutableHandleValue vp); MOZ_MUST_USE bool wrap(JSContext* cx, js::MutableHandleString strp); +#ifdef ENABLE_BIGINT + MOZ_MUST_USE bool wrap(JSContext* cx, js::MutableHandle bi); +#endif MOZ_MUST_USE bool wrap(JSContext* cx, JS::MutableHandleObject obj); MOZ_MUST_USE bool wrap(JSContext* cx, JS::MutableHandle desc); MOZ_MUST_USE bool wrap(JSContext* cx, JS::MutableHandle> vec); diff --git a/js/src/vm/JSObject.cpp b/js/src/vm/JSObject.cpp index 6adaa38b1c8e..f69699784712 100644 --- a/js/src/vm/JSObject.cpp +++ b/js/src/vm/JSObject.cpp @@ -3251,9 +3251,20 @@ js::PrimitiveToObject(JSContext* cx, const Value& v) return NumberObject::create(cx, v.toNumber()); if (v.isBoolean()) return BooleanObject::create(cx, v.toBoolean()); +#ifdef ENABLE_BIGINT + 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; +#else MOZ_ASSERT(v.isSymbol()); RootedSymbol symbol(cx, v.toSymbol()); return SymbolObject::create(cx, symbol); +#endif } /* diff --git a/js/src/vm/MemoryMetrics.cpp b/js/src/vm/MemoryMetrics.cpp index f4e8be45003f..b6bc660ea203 100644 --- a/js/src/vm/MemoryMetrics.cpp +++ b/js/src/vm/MemoryMetrics.cpp @@ -13,6 +13,9 @@ #include "jit/BaselineJIT.h" #include "jit/Ion.h" #include "vm/ArrayObject.h" +#ifdef ENABLE_BIGINT +#include "vm/BigIntType.h" +#endif #include "vm/HelperThreads.h" #include "vm/JSCompartment.h" #include "vm/JSObject.h" @@ -556,6 +559,15 @@ StatsCellCallback(JSRuntime* rt, void* data, void* thing, JS::TraceKind traceKin zStats->symbolsGCHeap += thingSize; break; +#ifdef ENABLE_BIGINT + case JS::TraceKind::BigInt: { + JS::BigInt* bi = static_cast(thing); + zStats->bigIntsGCHeap += thingSize; + zStats->bigIntsMallocHeap += bi->sizeOfExcludingThis(rtStats->mallocSizeOf_); + break; + } +#endif + case JS::TraceKind::BaseShape: { JS::ShapeInfo info; // This zeroes all the sizes. info.shapesGCHeapBase += thingSize; diff --git a/js/src/vm/StringType.cpp b/js/src/vm/StringType.cpp index 50d2770fe97e..6dc909d85c8f 100644 --- a/js/src/vm/StringType.cpp +++ b/js/src/vm/StringType.cpp @@ -2071,7 +2071,15 @@ js::ToStringSlow(JSContext* cx, typename MaybeRooted::HandleType JSMSG_SYMBOL_TO_STRING); } return nullptr; - } else { + } +#ifdef ENABLE_BIGINT + else if (v.isBigInt()) { + if (!allowGC) + return nullptr; + str = BigInt::toString(cx, v.toBigInt()); + } +#endif + else { MOZ_ASSERT(v.isUndefined()); str = cx->names().undefined; } diff --git a/js/src/vm/TypeInference-inl.h b/js/src/vm/TypeInference-inl.h index 242daa1785ed..8221720c7da4 100644 --- a/js/src/vm/TypeInference-inl.h +++ b/js/src/vm/TypeInference-inl.h @@ -190,6 +190,10 @@ PrimitiveTypeFlag(JSValueType type) return TYPE_FLAG_STRING; case JSVAL_TYPE_SYMBOL: return TYPE_FLAG_SYMBOL; +#ifdef ENABLE_BIGINT + case JSVAL_TYPE_BIGINT: + return TYPE_FLAG_BIGINT; +#endif case JSVAL_TYPE_MAGIC: return TYPE_FLAG_LAZYARGS; default: @@ -215,6 +219,10 @@ TypeFlagPrimitive(TypeFlags flags) return JSVAL_TYPE_STRING; case TYPE_FLAG_SYMBOL: return JSVAL_TYPE_SYMBOL; +#ifdef ENABLE_BIGINT + case TYPE_FLAG_BIGINT: + return JSVAL_TYPE_BIGINT; +#endif case TYPE_FLAG_LAZYARGS: return JSVAL_TYPE_MAGIC; default: diff --git a/js/src/vm/TypeInference.cpp b/js/src/vm/TypeInference.cpp index 0a898f55a6cf..5f1c52a67a50 100644 --- a/js/src/vm/TypeInference.cpp +++ b/js/src/vm/TypeInference.cpp @@ -113,6 +113,10 @@ TypeSet::NonObjectTypeString(TypeSet::Type type) return "string"; case JSVAL_TYPE_SYMBOL: return "symbol"; +#ifdef ENABLE_BIGINT + case JSVAL_TYPE_BIGINT: + return "BigInt"; +#endif case JSVAL_TYPE_MAGIC: return "lazyargs"; default: @@ -785,6 +789,10 @@ TypeSet::print(FILE* fp) fprintf(fp, " string"); if (flags & TYPE_FLAG_SYMBOL) fprintf(fp, " symbol"); +#ifdef ENABLE_BIGINT + if (flags & TYPE_FLAG_BIGINT) + fprintf(fp, " BigInt"); +#endif if (flags & TYPE_FLAG_LAZYARGS) fprintf(fp, " lazyargs"); diff --git a/js/src/vm/TypeInference.h b/js/src/vm/TypeInference.h index 81fbd32bc635..2b22b36d78d6 100644 --- a/js/src/vm/TypeInference.h +++ b/js/src/vm/TypeInference.h @@ -60,17 +60,29 @@ enum : uint32_t { TYPE_FLAG_DOUBLE = 0x10, TYPE_FLAG_STRING = 0x20, TYPE_FLAG_SYMBOL = 0x40, - TYPE_FLAG_LAZYARGS = 0x80, +#ifdef ENABLE_BIGINT + TYPE_FLAG_BIGINT = 0x80, + TYPE_FLAG_LAZYARGS = 0x100, + TYPE_FLAG_ANYOBJECT = 0x200, +#else + TYPE_FLAG_LAZYARGS = 0x80, TYPE_FLAG_ANYOBJECT = 0x100, +#endif /* 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 | + IF_BIGINT(TYPE_FLAG_BIGINT, 0), /* Mask/shift for the number of objects in objectSet */ +#ifdef ENABLE_BIGINT + TYPE_FLAG_OBJECT_COUNT_MASK = 0x3c00, + TYPE_FLAG_OBJECT_COUNT_SHIFT = 10, +#else TYPE_FLAG_OBJECT_COUNT_MASK = 0x3e00, TYPE_FLAG_OBJECT_COUNT_SHIFT = 9, +#endif TYPE_FLAG_OBJECT_COUNT_LIMIT = 7, TYPE_FLAG_DOMOBJECT_COUNT_LIMIT = TYPE_FLAG_OBJECT_COUNT_MASK >> TYPE_FLAG_OBJECT_COUNT_SHIFT, @@ -79,7 +91,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. */ @@ -110,6 +122,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 +382,9 @@ 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); } +#ifdef ENABLE_BIGINT + static inline Type BigIntType() { return Type(JSVAL_TYPE_BIGINT); } +#endif 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 139586d15c4f..25280d1ced81 100644 --- a/js/src/vm/UbiNode.cpp +++ b/js/src/vm/UbiNode.cpp @@ -22,6 +22,9 @@ #include "js/Utility.h" #include "js/Vector.h" #include "util/Text.h" +#ifdef ENABLE_BIGINT +#include "vm/BigIntType.h" +#endif #include "vm/Debugger.h" #include "vm/EnvironmentObject.h" #include "vm/GlobalObject.h" @@ -203,7 +206,13 @@ Node::exposeToJS() const v.setString(as()); } else if (is()) { v.setSymbol(as()); - } else { + } +#ifdef ENABLE_BIGINT + else if (is()) { + v.setBigInt(as()); + } +#endif + else { v.setUndefined(); } @@ -315,6 +324,9 @@ template JS::Zone* TracerConcrete::zone() const; template JS::Zone* TracerConcrete::zone() const; template JS::Zone* TracerConcrete::zone() const; template JS::Zone* TracerConcrete::zone() const; +#ifdef ENABLE_BIGINT +template JS::Zone* TracerConcrete::zone() const; +#endif template JS::Zone* TracerConcrete::zone() const; template @@ -338,6 +350,9 @@ template UniquePtr TracerConcrete::edges(JSContext* template UniquePtr TracerConcrete::edges(JSContext* cx, bool wantNames) const; template UniquePtr TracerConcrete::edges(JSContext* cx, bool wantNames) const; template UniquePtr TracerConcrete::edges(JSContext* cx, bool wantNames) const; +#ifdef ENABLE_BIGINT +template UniquePtr TracerConcrete::edges(JSContext* cx, bool wantNames) const; +#endif template UniquePtr TracerConcrete::edges(JSContext* cx, bool wantNames) const; template @@ -393,6 +408,9 @@ Concrete::jsObjectConstructorName(JSContext* cx, UniqueTwoByteChars& o } const char16_t Concrete::concreteTypeName[] = u"JS::Symbol"; +#ifdef ENABLE_BIGINT +const char16_t Concrete::concreteTypeName[] = u"JS::BigInt"; +#endif const char16_t Concrete::concreteTypeName[] = u"JSScript"; const char16_t Concrete::concreteTypeName[] = u"js::LazyScript"; const char16_t Concrete::concreteTypeName[] = u"js::jit::JitCode";