Bug 1366287 - Part 1.0: Define a new BigInt primitive type. (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
☠☠ backed out by f0cb25b7bdee ☠ ☠
authorRobin Templeton <robin@igalia.com>
Fri, 11 May 2018 19:09:28 -0700
changeset 794512 b424782cd5d1646cc50d4aae08049163d3c4c898
parent 794511 e4fd5393d398797c9c83b26bc583bedfe7412aa0
child 794513 76fdbe405fbd1237567bb70e218ef144a7190221
push id109697
push userbmo:sledru@mozilla.com
push dateSat, 12 May 2018 10:04:34 +0000
reviewersjwalden
bugs1366287
milestone62.0a1
Bug 1366287 - Part 1.0: Define a new BigInt primitive type. (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
js/moz.configure
js/public/Conversions.h
js/public/GCPolicyAPI.h
js/public/MemoryMetrics.h
js/public/TraceKind.h
js/public/TracingAPI.h
js/public/TypeDecls.h
js/public/UbiNode.h
js/public/Value.h
js/src/NamespaceImports.h
js/src/builtin/Array.cpp
js/src/builtin/Boolean.cpp
js/src/builtin/JSON.cpp
js/src/builtin/MapObject.cpp
js/src/gc/AllocKind.h
js/src/gc/AtomMarking.cpp
js/src/gc/DeletePolicy.h
js/src/gc/GC.cpp
js/src/gc/Marking-inl.h
js/src/gc/Marking.cpp
js/src/gc/Marking.h
js/src/gc/Tracer.cpp
js/src/js.msg
js/src/jsnum.cpp
js/src/jspubtd.h
js/src/moz.build
js/src/util/StringBuffer.cpp
js/src/vm/BigIntType.cpp
js/src/vm/BigIntType.h
js/src/vm/CommonPropertyNames.h
js/src/vm/Interpreter.cpp
js/src/vm/JSAtom.cpp
js/src/vm/JSCompartment-inl.h
js/src/vm/JSCompartment.cpp
js/src/vm/JSCompartment.h
js/src/vm/JSObject.cpp
js/src/vm/MemoryMetrics.cpp
js/src/vm/StringType.cpp
js/src/vm/TypeInference-inl.h
js/src/vm/TypeInference.cpp
js/src/vm/TypeInference.h
js/src/vm/UbiNode.cpp
--- a/js/moz.configure
+++ b/js/moz.configure
@@ -97,23 +97,39 @@ def disable_export_js(value):
     if value and not len(value):
         suggestion = '--disable-export-js'
     else:
         suggestion = '--enable-export-js'
 
     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,
           help='Enable use of the IonMonkey JIT')
 
 set_config('ENABLE_ION', depends_if('--enable-ion')(lambda x: True))
 
 # JIT code simulator for cross compiles
--- a/js/public/Conversions.h
+++ b/js/public/Conversions.h
@@ -117,17 +117,17 @@ ToBoolean(HandleValue v)
         return false;
     if (v.isDouble()) {
         double d = v.toDouble();
         return !mozilla::IsNaN(d) && d != 0;
     }
     if (v.isSymbol())
         return true;
 
-    /* The slow path handles strings and objects. */
+    /* The slow path handles strings, BigInts and objects. */
     return js::ToBooleanSlow(v);
 }
 
 /* ES6 draft 20141224, 7.1.3. */
 MOZ_ALWAYS_INLINE bool
 ToNumber(JSContext* cx, HandleValue v, double* out)
 {
     detail::AssertArgumentsAreSane(cx, v);
--- a/js/public/GCPolicyAPI.h
+++ b/js/public/GCPolicyAPI.h
@@ -45,16 +45,17 @@
 
 #include "js/TraceKind.h"
 #include "js/TracingAPI.h"
 #include "js/TypeDecls.h"
 
 // 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*) \
     D(JSScript*) \
     D(JSString*)
 
 // Expand the given macro D for each public tagged GC pointer type.
 #define FOR_EACH_PUBLIC_TAGGED_GC_POINTER_TYPE(D) \
@@ -122,16 +123,19 @@ struct GCPointerPolicy
             return js::gc::IsAboutToBeFinalizedUnbarriered(vp);
         return false;
     }
     static bool isValid(T v) {
         return js::gc::IsCellPointerValidOrNull(v);
     }
 };
 template <> struct GCPolicy<JS::Symbol*> : public GCPointerPolicy<JS::Symbol*> {};
+#ifdef ENABLE_BIGINT
+template <> struct GCPolicy<JS::BigInt*> : public GCPointerPolicy<JS::BigInt*> {};
+#endif
 template <> struct GCPolicy<JSAtom*> : public GCPointerPolicy<JSAtom*> {};
 template <> struct GCPolicy<JSFunction*> : public GCPointerPolicy<JSFunction*> {};
 template <> struct GCPolicy<JSObject*> : public GCPointerPolicy<JSObject*> {};
 template <> struct GCPolicy<JSScript*> : public GCPointerPolicy<JSScript*> {};
 template <> struct GCPolicy<JSString*> : public GCPointerPolicy<JSString*> {};
 
 template <typename T>
 struct NonGCPointerPolicy
--- a/js/public/MemoryMetrics.h
+++ b/js/public/MemoryMetrics.h
@@ -625,16 +625,17 @@ struct UnusedGCThingSizes
     macro(Other, GCHeapUnused, object) \
     macro(Other, GCHeapUnused, script) \
     macro(Other, GCHeapUnused, lazyScript) \
     macro(Other, GCHeapUnused, shape) \
     macro(Other, GCHeapUnused, baseShape) \
     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)
 
     UnusedGCThingSizes()
       : FOR_EACH_SIZE(ZERO_SIZE)
         dummy()
     {}
@@ -644,16 +645,19 @@ struct UnusedGCThingSizes
         dummy()
     {}
 
     void addToKind(JS::TraceKind kind, intptr_t n) {
         switch (kind) {
           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;
           case JS::TraceKind::JitCode:      jitcode += n;      break;
           case JS::TraceKind::LazyScript:   lazyScript += n;   break;
           case JS::TraceKind::ObjectGroup:  objectGroup += n;  break;
           case JS::TraceKind::Scope:        scope += n;        break;
           case JS::TraceKind::RegExpShared: regExpShared += n; break;
@@ -685,16 +689,18 @@ struct UnusedGCThingSizes
 
 #undef FOR_EACH_SIZE
 };
 
 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) \
     macro(Other,   GCHeapUsed,  jitCodesGCHeap) \
     macro(Other,   GCHeapUsed,  objectGroupsGCHeap) \
     macro(Other,   MallocHeap,  objectGroupsMallocHeap) \
     macro(Other,   GCHeapUsed,  scopesGCHeap) \
     macro(Other,   MallocHeap,  scopesMallocHeap) \
--- a/js/public/TraceKind.h
+++ b/js/public/TraceKind.h
@@ -36,30 +36,33 @@ namespace JS {
 //
 // See Value::gcKind() and JSTraceCallback in Tracer.h for more details.
 enum class TraceKind
 {
     // These trace kinds have a publicly exposed, although opaque, C++ type.
     // Note: The order here is determined by our Value packing. Other users
     //       should sort alphabetically, for consistency.
     Object = 0x00,
+#ifdef ENABLE_BIGINT
+    BigInt = 0x01,
+#endif
     String = 0x02,
     Symbol = 0x03,
 
-    // 0x1 is not used for any GCThing Value tag, so we use it for Script.
-    Script = 0x01,
+    // 0x4 is not used for any GCThing Value tag, so we use it for Script.
+    Script = 0x04,
 
     // Shape details are exposed through JS_TraceShapeCycleCollectorChildren.
-    Shape = 0x04,
+    Shape = 0x05,
 
     // ObjectGroup details are exposed through JS_TraceObjectGroupCycleCollectorChildren.
-    ObjectGroup = 0x05,
+    ObjectGroup = 0x06,
 
     // The kind associated with a nullptr.
-    Null = 0x06,
+    Null = 0x07,
 
     // The following kinds do not have an exposed C++ idiom.
     BaseShape = 0x0F,
     JitCode = 0x1F,
     LazyScript = 0x2F,
     Scope = 0x3F,
     RegExpShared = 0x4F
 };
@@ -92,16 +95,17 @@ struct MapTypeToTraceKind {
     D(LazyScript,    js::LazyScript,    true) \
     D(Scope,         js::Scope,         true) \
     D(Object,        JSObject,          true) \
     D(ObjectGroup,   js::ObjectGroup,   true) \
     D(Script,        JSScript,          true) \
     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.
 #define JS_EXPAND_DEF(name, type, _) \
     template <> struct MapTypeToTraceKind<type> { \
         static const JS::TraceKind kind = JS::TraceKind::name; \
     };
 JS_FOR_EACH_TRACEKIND(JS_EXPAND_DEF);
--- a/js/public/TracingAPI.h
+++ b/js/public/TracingAPI.h
@@ -143,16 +143,19 @@ class JS_PUBLIC_API(CallbackTracer) : pu
     // Override these methods to receive notification when an edge is visited
     // with the type contained in the callback. The default implementation
     // dispatches to the fully-generic onChild implementation, so for cases that
     // do not care about boxing overhead and do not need the actual edges,
     // just override the generic onChild.
     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));
     }
     virtual void onObjectGroupEdge(js::ObjectGroup** groupp) {
         onChild(JS::GCCellPtr(*groupp, JS::TraceKind::ObjectGroup));
     }
     virtual void onBaseShapeEdge(js::BaseShape** basep) {
@@ -235,16 +238,19 @@ class JS_PUBLIC_API(CallbackTracer) : pu
     // In C++, overriding a method hides all methods in the base class with
     // that name, not just methods with that signature. Thus, the typed edge
     // methods have to have distinct names to allow us to override them
     // individually, which is freqently useful if, for example, we only want to
     // process only one type of edge.
     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); }
     void dispatchToOnEdge(js::BaseShape** basep) { onBaseShapeEdge(basep); }
     void dispatchToOnEdge(js::jit::JitCode** codep) { onJitCodeEdge(codep); }
     void dispatchToOnEdge(js::LazyScript** lazyp) { onLazyScriptEdge(lazyp); }
     void dispatchToOnEdge(js::Scope** scopep) { onScopeEdge(scopep); }
     void dispatchToOnEdge(js::RegExpShared** sharedp) { onRegExpSharedEdge(sharedp); }
--- a/js/public/TypeDecls.h
+++ b/js/public/TypeDecls.h
@@ -36,53 +36,74 @@ struct JSFreeOp;
 
 struct jsid;
 
 namespace JS {
 
 typedef unsigned char Latin1Char;
 
 class Symbol;
+#ifdef ENABLE_BIGINT
+class BigInt;
+#endif
 union Value;
 class Realm;
 struct Runtime;
 struct Zone;
 
 template <typename T> class Handle;
 template <typename T> class MutableHandle;
 template <typename T> class Rooted;
 template <typename T> class PersistentRooted;
 
 typedef Handle<JSFunction*> HandleFunction;
 typedef Handle<jsid>        HandleId;
 typedef Handle<JSObject*>   HandleObject;
 typedef Handle<JSScript*>   HandleScript;
 typedef Handle<JSString*>   HandleString;
 typedef Handle<JS::Symbol*> HandleSymbol;
+#ifdef ENABLE_BIGINT
+typedef Handle<JS::BigInt*> HandleBigInt;
+#endif
 typedef Handle<Value>       HandleValue;
 
 typedef MutableHandle<JSFunction*> MutableHandleFunction;
 typedef MutableHandle<jsid>        MutableHandleId;
 typedef MutableHandle<JSObject*>   MutableHandleObject;
 typedef MutableHandle<JSScript*>   MutableHandleScript;
 typedef MutableHandle<JSString*>   MutableHandleString;
 typedef MutableHandle<JS::Symbol*> MutableHandleSymbol;
+#ifdef ENABLE_BIGINT
+typedef MutableHandle<JS::BigInt*> MutableHandleBigInt;
+#endif
 typedef MutableHandle<Value>       MutableHandleValue;
 
 typedef Rooted<JSObject*>       RootedObject;
 typedef Rooted<JSFunction*>     RootedFunction;
 typedef Rooted<JSScript*>       RootedScript;
 typedef Rooted<JSString*>       RootedString;
 typedef Rooted<JS::Symbol*>     RootedSymbol;
+#ifdef ENABLE_BIGINT
+typedef Rooted<JS::BigInt*>     RootedBigInt;
+#endif
 typedef Rooted<jsid>            RootedId;
 typedef Rooted<JS::Value>       RootedValue;
 
 typedef PersistentRooted<JSFunction*> PersistentRootedFunction;
 typedef PersistentRooted<jsid>        PersistentRootedId;
 typedef PersistentRooted<JSObject*>   PersistentRootedObject;
 typedef PersistentRooted<JSScript*>   PersistentRootedScript;
 typedef PersistentRooted<JSString*>   PersistentRootedString;
 typedef PersistentRooted<JS::Symbol*> PersistentRootedSymbol;
+#ifdef ENABLE_BIGINT
+typedef PersistentRooted<JS::BigInt*> PersistentRootedBigInt;
+#endif
 typedef PersistentRooted<Value>       PersistentRootedValue;
 
 } // namespace JS
 
+#ifdef ENABLE_BIGINT
+#define IF_BIGINT(x, y) x
+#else
+#define IF_BIGINT(x, y) y
+#endif
+
 #endif /* js_TypeDecls_h */
--- a/js/public/UbiNode.h
+++ b/js/public/UbiNode.h
@@ -1051,16 +1051,34 @@ class JS_PUBLIC_API(Concrete<JS::Symbol>
     }
 
     Size size(mozilla::MallocSizeOf mallocSizeOf) const override;
 
     const char16_t* typeName() const override { return concreteTypeName; }
     static const char16_t concreteTypeName[];
 };
 
+#ifdef ENABLE_BIGINT
+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[];
+};
+#endif
+
 template<>
 class JS_PUBLIC_API(Concrete<JSScript>) : TracerConcreteWithCompartment<JSScript> {
   protected:
     explicit Concrete(JSScript *ptr) : TracerConcreteWithCompartment<JSScript>(ptr) { }
 
   public:
     static void construct(void *storage, JSScript *ptr) { new (storage) Concrete(ptr); }
 
--- a/js/public/Value.h
+++ b/js/public/Value.h
@@ -54,16 +54,19 @@ enum JSValueType : uint8_t
     JSVAL_TYPE_INT32               = 0x01,
     JSVAL_TYPE_BOOLEAN             = 0x02,
     JSVAL_TYPE_UNDEFINED           = 0x03,
     JSVAL_TYPE_NULL                = 0x04,
     JSVAL_TYPE_MAGIC               = 0x05,
     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. */
     JSVAL_TYPE_UNKNOWN             = 0x20,
     JSVAL_TYPE_MISSING             = 0x21
 };
 
 static_assert(sizeof(JSValueType) == 1,
@@ -77,16 +80,19 @@ JS_ENUM_HEADER(JSValueTag, uint32_t)
     JSVAL_TAG_INT32                = JSVAL_TAG_CLEAR | JSVAL_TYPE_INT32,
     JSVAL_TAG_UNDEFINED            = JSVAL_TAG_CLEAR | JSVAL_TYPE_UNDEFINED,
     JSVAL_TAG_NULL                 = JSVAL_TAG_CLEAR | JSVAL_TYPE_NULL,
     JSVAL_TAG_BOOLEAN              = JSVAL_TAG_CLEAR | JSVAL_TYPE_BOOLEAN,
     JSVAL_TAG_MAGIC                = JSVAL_TAG_CLEAR | JSVAL_TYPE_MAGIC,
     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);
 
 static_assert(sizeof(JSValueTag) == sizeof(uint32_t),
               "compiler typed enum support is apparently buggy");
 
 #elif defined(JS_PUNBOX64)
 
@@ -96,16 +102,19 @@ JS_ENUM_HEADER(JSValueTag, uint32_t)
     JSVAL_TAG_INT32                = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_INT32,
     JSVAL_TAG_UNDEFINED            = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_UNDEFINED,
     JSVAL_TAG_NULL                 = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_NULL,
     JSVAL_TAG_BOOLEAN              = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_BOOLEAN,
     JSVAL_TAG_MAGIC                = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_MAGIC,
     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);
 
 static_assert(sizeof(JSValueTag) == sizeof(uint32_t),
               "compiler typed enum support is apparently buggy");
 
 enum JSValueShiftedTag : uint64_t
 {
@@ -113,16 +122,19 @@ enum JSValueShiftedTag : uint64_t
     JSVAL_SHIFTED_TAG_INT32           = (((uint64_t)JSVAL_TAG_INT32)           << JSVAL_TAG_SHIFT),
     JSVAL_SHIFTED_TAG_UNDEFINED       = (((uint64_t)JSVAL_TAG_UNDEFINED)       << JSVAL_TAG_SHIFT),
     JSVAL_SHIFTED_TAG_NULL            = (((uint64_t)JSVAL_TAG_NULL)            << JSVAL_TAG_SHIFT),
     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_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)
 };
 
 static_assert(sizeof(JSValueShiftedTag) == sizeof(uint64_t),
               "compiler typed enum support is apparently buggy");
 
 #endif
 
@@ -256,17 +268,17 @@ CanonicalizeNaN(double d)
 }
 
 /**
  * JS::Value is the interface for a single JavaScript Engine value.  A few
  * general notes on JS::Value:
  *
  * - 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.
  *
  * - Magic is a singleton type whose payload contains either a JSWhyMagic "reason" for
  *   the magic value or a uint32_t value. By providing JSWhyMagic values when
  *   creating and checking for magic values, it is possible to assert, at
  *   runtime, that only magic values with the expected reason flow through a
  *   particular value. For example, if cx->exception has a magic value, the
@@ -338,16 +350,19 @@ union MOZ_NON_PARAM alignas(8) Value
         JSValueTag tag_;
 #  endif // MOZ_BIG_ENDIAN
         union {
             int32_t i32_;
             uint32_t u32_;
             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_;
             JSWhyMagic why_;
         } payload_;
 #  if MOZ_LITTLE_ENDIAN
         JSValueTag tag_;
 #  endif // MOZ_LITTLE_ENDIAN
@@ -449,16 +464,23 @@ union MOZ_NON_PARAM alignas(8) Value
         asBits_ = bitsFromTagAndPayload(JSVAL_TAG_STRING, PayloadType(str));
     }
 
     void setSymbol(JS::Symbol* sym) {
         MOZ_ASSERT(js::gc::IsCellPointerValid(sym));
         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));
 
         // This should not be possible and is undefined behavior, but some
         // ObjectValue(nullptr) are sneaking in. Try to catch them here, if
         // indeed they are going through this code. I tested gcc, and it at
         // least will *not* elide the null check even though it would be
         // permitted according to the spec. The temporary is necessary to
@@ -615,16 +637,22 @@ union MOZ_NON_PARAM alignas(8) Value
     bool isString() const {
         return toTag() == JSVAL_TAG_STRING;
     }
 
     bool isSymbol() const {
         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;
 #elif defined(JS_PUNBOX64)
         MOZ_ASSERT((asBits_ >> JSVAL_TAG_SHIFT) <= JSVAL_TAG_OBJECT);
         return asBits_ >= JSVAL_SHIFTED_TAG_OBJECT;
 #endif
     }
@@ -672,16 +700,20 @@ union MOZ_NON_PARAM alignas(8) Value
     }
 
     JS::TraceKind traceKind() const {
         MOZ_ASSERT(isGCThing());
         static_assert((JSVAL_TAG_STRING & 0x03) == size_t(JS::TraceKind::String),
                       "Value type tags must correspond with JS::TraceKinds.");
         static_assert((JSVAL_TAG_SYMBOL & 0x03) == size_t(JS::TraceKind::Symbol),
                       "Value type tags must correspond with JS::TraceKinds.");
+#ifdef ENABLE_BIGINT
+        static_assert((JSVAL_TAG_BIGINT & 0x03) == size_t(JS::TraceKind::BigInt),
+                      "Value type tags must correspond with JS::TraceKinds.");
+#endif
         static_assert((JSVAL_TAG_OBJECT & 0x03) == size_t(JS::TraceKind::Object),
                       "Value type tags must correspond with JS::TraceKinds.");
         if (MOZ_UNLIKELY(isPrivateGCThing()))
             return JS::GCThingTraceKind(toGCThing());
         return JS::TraceKind(toTag() & 0x03);
     }
 
     JSWhyMagic whyMagic() const {
@@ -740,16 +772,27 @@ union MOZ_NON_PARAM alignas(8) Value
         MOZ_ASSERT(isSymbol());
 #if defined(JS_NUNBOX32)
         return s_.payload_.sym_;
 #elif defined(JS_PUNBOX64)
         return reinterpret_cast<JS::Symbol*>(asBits_ ^ JSVAL_SHIFTED_TAG_SYMBOL);
 #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<JS::BigInt*>(asBits_ ^ JSVAL_SHIFTED_TAG_BIGINT);
+#endif
+    }
+#endif
+
     JSObject& toObject() const {
         MOZ_ASSERT(isObject());
 #if defined(JS_NUNBOX32)
         return *s_.payload_.obj_;
 #elif defined(JS_PUNBOX64)
         uint64_t ptrBits = asBits_ ^ JSVAL_SHIFTED_TAG_OBJECT;
         MOZ_ASSERT(ptrBits);
         MOZ_ASSERT((ptrBits & 0x7) == 0);
@@ -857,16 +900,20 @@ union MOZ_NON_PARAM alignas(8) Value
      * cells.
      */
 
     void setPrivateGCThing(js::gc::Cell* cell) {
         MOZ_ASSERT(JS::GCThingTraceKind(cell) != JS::TraceKind::String,
                    "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.");
 
         MOZ_ASSERT(js::gc::IsCellPointerValid(cell));
 #if defined(JS_PUNBOX64)
         // VisualStudio cannot contain parenthesized C++ style cast and shift
         // inside decltype in template parameter:
         //   AssertionConditionType<decltype((uintptr_t(x) >> 1))>
@@ -982,16 +1029,26 @@ StringValue(JSString* str)
 static inline Value
 SymbolValue(JS::Symbol* sym)
 {
     Value v;
     v.setSymbol(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)
 {
     Value v;
     v.setBoolean(boo);
     return v;
 }
 
@@ -1237,31 +1294,37 @@ class WrappedPtrOperations<JS::Value, Wr
     bool isTrue() const { return value().isTrue(); }
     bool isFalse() const { return value().isFalse(); }
     bool isNumber() const { return value().isNumber(); }
     bool isInt32() const { return value().isInt32(); }
     bool isInt32(int32_t i32) const { return value().isInt32(i32); }
     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); }
     bool isGCThing() const { return value().isGCThing(); }
     bool isPrimitive() const { return value().isPrimitive(); }
 
     bool isNullOrUndefined() const { return value().isNullOrUndefined(); }
     bool isObjectOrNull() const { return value().isObjectOrNull(); }
 
     bool toBoolean() const { return value().toBoolean(); }
     double toNumber() const { return value().toNumber(); }
     int32_t toInt32() const { return value().toInt32(); }
     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(); }
     JS::TraceKind traceKind() const { return value().traceKind(); }
     void* toPrivate() const { return value().toPrivate(); }
     uint32_t toPrivateUint32() const { return value().toPrivateUint32(); }
 
     uint64_t asRawBits() const { return value().asRawBits(); }
@@ -1289,16 +1352,19 @@ class MutableWrappedPtrOperations<JS::Va
     void setDouble(double d) { value().setDouble(d); }
     void setNaN() { setDouble(JS::GenericNaN()); }
     void setBoolean(bool b) { value().setBoolean(b); }
     void setMagic(JSWhyMagic why) { value().setMagic(why); }
     bool setNumber(uint32_t ui) { return value().setNumber(ui); }
     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); }
     void setPrivateUint32(uint32_t ui) { this->value().setPrivateUint32(ui); }
     void setPrivateGCThing(js::gc::Cell* cell) { this->value().setPrivateGCThing(cell); }
 };
 
 /*
@@ -1317,16 +1383,19 @@ class HeapBase<JS::Value, Wrapper> : pub
     void setUndefined() { setBarriered(JS::UndefinedValue()); }
     void setInt32(int32_t i) { setBarriered(JS::Int32Value(i)); }
     void setDouble(double d) { setBarriered(JS::DoubleValue(d)); }
     void setNaN() { setDouble(JS::GenericNaN()); }
     void setBoolean(bool b) { setBarriered(JS::BooleanValue(b)); }
     void setMagic(JSWhyMagic why) { setBarriered(JS::MagicValue(why)); }
     void setString(JSString* str) { setBarriered(JS::StringValue(str)); }
     void setSymbol(JS::Symbol* sym) { setBarriered(JS::SymbolValue(sym)); }
+#ifdef ENABLE_BIGINT
+    void setBigInt(JS::BigInt* bi) { setBarriered(JS::BigIntValue(bi)); }
+#endif
     void setObject(JSObject& obj) { setBarriered(JS::ObjectValue(obj)); }
     void setPrivateGCThing(js::gc::Cell* cell) { setBarriered(JS::PrivateGCThingValue(cell)); }
 
     bool setNumber(uint32_t ui) {
         if (ui > JSVAL_INT_MAX) {
             setDouble((double)ui);
             return false;
         } else {
@@ -1373,16 +1442,23 @@ DispatchTyped(F f, const JS::Value& val,
         MOZ_ASSERT(gc::IsCellPointerValid(obj));
         return f(obj, mozilla::Forward<Args>(args)...);
     }
     if (val.isSymbol()) {
         JS::Symbol* sym = val.toSymbol();
         MOZ_ASSERT(gc::IsCellPointerValid(sym));
         return f(sym, mozilla::Forward<Args>(args)...);
     }
+#ifdef ENABLE_BIGINT
+    if (val.isBigInt()) {
+        JS::BigInt* bi = val.toBigInt();
+        MOZ_ASSERT(gc::IsCellPointerValid(bi));
+        return f(bi, mozilla::Forward<Args>(args)...);
+    }
+#endif
     if (MOZ_UNLIKELY(val.isPrivateGCThing())) {
         MOZ_ASSERT(gc::IsCellPointerValid(val.toGCThing()));
         return DispatchTyped(f, val.toGCCellPtr(), mozilla::Forward<Args>(args)...);
     }
     MOZ_ASSERT(!val.isGCThing());
     return F::defaultValue(val);
 }
 
--- a/js/src/NamespaceImports.h
+++ b/js/src/NamespaceImports.h
@@ -45,16 +45,19 @@ class MOZ_STACK_CLASS SourceBufferHolder
 
 class HandleValueArray;
 
 class ObjectOpResult;
 class PropertyResult;
 
 enum class SymbolCode: uint32_t;
 
+#ifdef ENABLE_BIGINT
+class BigInt;
+#endif
 } // namespace JS
 
 // Do the importing.
 namespace js {
 
 using JS::Value;
 using JS::BooleanValue;
 using JS::DoubleValue;
@@ -113,43 +116,55 @@ using JS::TransitiveCompileOptions;
 
 using JS::Rooted;
 using JS::RootedFunction;
 using JS::RootedId;
 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;
 using JS::PersistentRootedFunction;
 using JS::PersistentRootedId;
 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;
 using JS::HandleFunction;
 using JS::HandleId;
 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;
 using JS::MutableHandleFunction;
 using JS::MutableHandleId;
 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;
 using JS::UndefinedHandleValue;
 using JS::TrueHandleValue;
 using JS::FalseHandleValue;
 
 using JS::HandleValueArray;
@@ -157,11 +172,14 @@ using JS::HandleValueArray;
 using JS::ObjectOpResult;
 using JS::PropertyResult;
 
 using JS::Zone;
 
 using JS::Symbol;
 using JS::SymbolCode;
 
+#ifdef ENABLE_BIGINT
+using JS::BigInt;
+#endif
 } /* namespace js */
 
 #endif /* NamespaceImports_h */
--- a/js/src/builtin/Array.cpp
+++ b/js/src/builtin/Array.cpp
@@ -1265,16 +1265,22 @@ ArrayJoinDenseKernel(JSContext* cx, Sepa
              * Object stringifying could modify the initialized length or make
              * the array sparse. Delegate it to a separate loop to keep this
              * one tight.
              *
              * Symbol stringifying is a TypeError, so into the slow path
              * 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());
         }
 
         // Steps 7.a, 7.e.
         if (++(*numProcessed) != length && !sepOp(cx, sb))
             return false;
     }
--- a/js/src/builtin/Boolean.cpp
+++ b/js/src/builtin/Boolean.cpp
@@ -10,16 +10,19 @@
 
 #include "builtin/Boolean-inl.h"
 
 #include "jsapi.h"
 #include "jstypes.h"
 
 #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"
 #include "vm/JSObject.h"
 #include "vm/ProxyObject.h"
 
 #include "vm/BooleanObject-inl.h"
 
@@ -159,12 +162,16 @@ js::BooleanToString(JSContext* cx, bool 
     return b ? cx->names().true_ : cx->names().false_;
 }
 
 JS_PUBLIC_API(bool)
 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());
 }
--- a/js/src/builtin/JSON.cpp
+++ b/js/src/builtin/JSON.cpp
@@ -582,16 +582,23 @@ Str(JSContext* cx, const Value& v, Strin
                            "reachable non-finite numbers");
                 return scx->sb.append("null");
             }
         }
 
         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());
 
     MOZ_ASSERT(!scx->maybeSafely || obj->is<PlainObject>() || obj->is<ArrayObject>(),
                "input to JS::ToJSONMaybeSafely must not include reachable "
                "objects that are neither arrays nor plain objects");
 
--- a/js/src/builtin/MapObject.cpp
+++ b/js/src/builtin/MapObject.cpp
@@ -52,17 +52,18 @@ HashableValue::setValue(JSContext* cx, H
         } else {
             value = v;
         }
     } else {
         value = 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;
 }
 
 static HashNumber
 HashValue(const Value& v, const mozilla::HashCodeScrambler& hcs)
 {
     // HashableValue::setValue normalizes values so that the SameValue relation
     // on HashableValues is the same as the == relationship on
@@ -72,16 +73,20 @@ HashValue(const Value& v, const mozilla:
     // from the string contents rather than any pointer; to avoid revealing
     // addresses, pointer-based hash codes are computed using the
     // HashCodeScrambler.
 
     if (v.isString())
         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());
 
     MOZ_ASSERT(!v.isGCThing(), "do not reveal pointers via hash codes");
     return mozilla::HashGeneric(v.asRawBits());
 }
 
 HashNumber
@@ -91,22 +96,34 @@ HashableValue::hash(const mozilla::HashC
 }
 
 bool
 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;
 }
 
 HashableValue
 HashableValue::trace(JSTracer* trc) const
 {
--- a/js/src/gc/AllocKind.h
+++ b/js/src/gc/AllocKind.h
@@ -59,16 +59,17 @@ namespace gc {
     D(SHAPE,               Shape,        js::Shape,         js::Shape,         true,   false) \
     D(ACCESSOR_SHAPE,      Shape,        js::AccessorShape, js::AccessorShape, true,   false) \
     D(BASE_SHAPE,          BaseShape,    js::BaseShape,     js::BaseShape,     true,   false) \
     D(OBJECT_GROUP,        ObjectGroup,  js::ObjectGroup,   js::ObjectGroup,   true,   false) \
     D(EXTERNAL_STRING,     String,       JSExternalString,  JSExternalString,  true,   false) \
     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)
 
 #define FOR_EACH_NURSERY_STRING_ALLOCKIND(D) \
     D(FAT_INLINE_STRING,   String,        JSFatInlineString, JSFatInlineString, true,   true) \
     D(STRING,              String,        JSString,          JSString,          true,   true)
 
--- a/js/src/gc/AtomMarking.cpp
+++ b/js/src/gc/AtomMarking.cpp
@@ -185,17 +185,20 @@ AtomMarkingRuntime::markAtomValue(JSCont
         if (value.toString()->isAtom())
             markAtom(cx, &value.toString()->asAtom());
         return;
     }
     if (value.isSymbol()) {
         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
 AtomMarkingRuntime::adoptMarkedAtoms(Zone* target, Zone* source)
 {
     MOZ_ASSERT(CurrentThreadCanAccessZone(source));
     MOZ_ASSERT(CurrentThreadCanAccessZone(target));
     target->markedAtoms().bitwiseOrWith(source->markedAtoms());
@@ -267,17 +270,20 @@ AtomMarkingRuntime::valueIsMarked(Zone* 
         if (value.toString()->isAtom())
             return atomIsMarked(zone, &value.toString()->asAtom());
         return true;
     }
 
     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;
 }
 
 #endif // DEBUG
 
 } // namespace gc
 
 #ifdef DEBUG
--- a/js/src/gc/DeletePolicy.h
+++ b/js/src/gc/DeletePolicy.h
@@ -3,16 +3,19 @@
  * 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 gc_DeletePolicy_h
 #define gc_DeletePolicy_h
 
 #include "js/TracingAPI.h"
+#ifdef ENABLE_BIGINT
+#include "vm/BigIntType.h"
+#endif
 
 namespace js {
 namespace gc {
 
 struct ClearEdgesTracer : public JS::CallbackTracer
 {
     ClearEdgesTracer();
 
@@ -21,16 +24,19 @@ struct ClearEdgesTracer : public JS::Cal
 #endif
 
     template <typename T>
     inline void clearEdge(T** thingp);
 
     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;
     void onBaseShapeEdge(js::BaseShape** basep) override;
     void onJitCodeEdge(js::jit::JitCode** codep) override;
     void onLazyScriptEdge(js::LazyScript** lazyp) override;
     void onScopeEdge(js::Scope** scopep) override;
     void onRegExpSharedEdge(js::RegExpShared** sharedp) override;
--- a/js/src/gc/GC.cpp
+++ b/js/src/gc/GC.cpp
@@ -219,16 +219,19 @@
 #include "gc/Policy.h"
 #include "gc/WeakMap.h"
 #include "jit/BaselineJIT.h"
 #include "jit/IonCode.h"
 #include "jit/JitcodeMap.h"
 #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"
 #include "vm/JSCompartment.h"
 #include "vm/JSContext.h"
 #include "vm/JSObject.h"
 #include "vm/JSScript.h"
 #include "vm/Printer.h"
@@ -490,17 +493,20 @@ static const FinalizePhase BackgroundFin
     },
     {
         gcstats::PhaseKind::SWEEP_STRING, {
             AllocKind::FAT_INLINE_STRING,
             AllocKind::STRING,
             AllocKind::EXTERNAL_STRING,
             AllocKind::FAT_INLINE_ATOM,
             AllocKind::ATOM,
-            AllocKind::SYMBOL
+            AllocKind::SYMBOL,
+#ifdef ENABLE_BIGINT
+            AllocKind::BIGINT
+#endif
         }
     },
     {
         gcstats::PhaseKind::SWEEP_SHAPE, {
             AllocKind::SHAPE,
             AllocKind::ACCESSOR_SHAPE,
             AllocKind::BASE_SHAPE,
             AllocKind::OBJECT_GROUP
@@ -8425,16 +8431,20 @@ JS::GCCellPtr::GCCellPtr(const Value& v)
   : ptr(0)
 {
     if (v.isString())
         ptr = checkedCast(v.toString(), JS::TraceKind::String);
     else if (v.isObject())
         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
         ptr = checkedCast(nullptr, JS::TraceKind::Null);
 }
 
 JS::TraceKind
 JS::GCCellPtr::outOfLineKind() const
@@ -9134,16 +9144,19 @@ js::gc::ClearEdgesTracer::clearEdge(S** 
     InternalBarrierMethods<S*>::preBarrier(*thingp);
     InternalBarrierMethods<S*>::postBarrier(thingp, *thingp, nullptr);
     *thingp = nullptr;
 }
 
 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); }
 void js::gc::ClearEdgesTracer::onBaseShapeEdge(js::BaseShape** basep) { clearEdge(basep); }
 void js::gc::ClearEdgesTracer::onJitCodeEdge(js::jit::JitCode** codep) { clearEdge(codep); }
 void js::gc::ClearEdgesTracer::onLazyScriptEdge(js::LazyScript** lazyp) { clearEdge(lazyp); }
 void js::gc::ClearEdgesTracer::onScopeEdge(js::Scope** scopep) { clearEdge(scopep); }
 void js::gc::ClearEdgesTracer::onRegExpSharedEdge(js::RegExpShared** sharedp) { clearEdge(sharedp); }
--- a/js/src/gc/Marking-inl.h
+++ b/js/src/gc/Marking-inl.h
@@ -6,16 +6,20 @@
 
 #ifndef gc_Marking_inl_h
 #define gc_Marking_inl_h
 
 #include "gc/Marking.h"
 
 #include "gc/RelocationOverlay.h"
 
+#ifdef ENABLE_BIGINT
+#include "vm/BigIntType.h"
+#endif
+
 namespace js {
 namespace gc {
 
 template <typename T>
 struct MightBeForwarded
 {
     static_assert(mozilla::IsBaseOf<Cell, T>::value,
                   "T must derive from Cell");
--- a/js/src/gc/Marking.cpp
+++ b/js/src/gc/Marking.cpp
@@ -16,16 +16,19 @@
 
 #include "builtin/ModuleObject.h"
 #include "gc/GCInternals.h"
 #include "gc/Policy.h"
 #include "jit/IonCode.h"
 #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"
 #include "vm/RegExpShared.h"
 #include "vm/Scope.h"
 #include "vm/Shape.h"
 #include "vm/SymbolType.h"
 #include "vm/TypedArrayObject.h"
@@ -889,16 +892,19 @@ js::GCMarker::markAndTraceChildren(T* th
     if (ThingIsPermanentAtomOrWellKnownSymbol(thing))
         return;
     if (mark(thing))
         thing->traceChildren(this);
 }
 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
 
 // Strings, LazyScripts, Shapes, and Scopes are extremely common, but have
 // simple patterns of recursion. We traverse trees of these edges immediately,
 // with aggressive, manual inlining, implemented by eagerlyTraceChildren.
 template <typename T>
 void
@@ -1542,16 +1548,24 @@ js::GCMarker::lazilyMarkChildren(ObjectG
 
     if (TypeDescr* descr = group->maybeTypeDescr())
         traverseEdge(group, static_cast<JSObject*>(descr));
 
     if (JSFunction* fun = group->maybeInterpretedFunction())
         traverseEdge(group, static_cast<JSObject*>(fun));
 }
 
+#ifdef ENABLE_BIGINT
+void
+JS::BigInt::traceChildren(JSTracer* trc)
+{
+    return;
+}
+#endif
+
 struct TraverseObjectFunctor
 {
     template <typename T>
     void operator()(T* thing, GCMarker* gcmarker, JSObject* src) {
         gcmarker->traverseEdge(src, *thing);
     }
 };
 
@@ -1686,17 +1700,18 @@ ObjectDenseElementsMayBeMarkable(NativeO
         return true;
 
     // This typeset doesn't escape this function so avoid sweeping here.
     HeapTypeSet* typeSet = group->maybeGetPropertyDontCheckGeneration(JSID_VOID);
     if (!typeSet)
         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
     if (!mayBeMarkable) {
         const Value* elements = nobj->getDenseElementsAllowCopyOnWrite();
         for (unsigned i = 0; i < nobj->getDenseInitializedLength(); i++)
             MOZ_ASSERT(!elements[i].isGCThing());
     }
@@ -1800,17 +1815,23 @@ GCMarker::processMarkStackTop(SliceBudge
             if (mark(obj2)) {
                 // Save the rest of this value array for later and start scanning obj2's children.
                 pushValueArray(obj, vp, end);
                 obj = obj2;
                 goto scan_obj;
             }
         } 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()));
         }
     }
     return;
 
   scan_obj:
--- a/js/src/gc/Marking.h
+++ b/js/src/gc/Marking.h
@@ -104,27 +104,34 @@ template <typename S, typename T>
 struct RewrapTaggedPointer{};
 #define DECLARE_REWRAP(S, T, method, prefix) \
     template <> struct RewrapTaggedPointer<S, T> { \
         static S wrap(T* thing) { return method ( prefix thing ); } \
     }
 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, );
 #undef DECLARE_REWRAP
 
 template <typename T>
 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
+#ifdef ENABLE_BIGINT
+                             && !mozilla::IsBaseOf<JS::BigInt, T>::value
+#endif
+                             , T>
 {
     static_assert(!mozilla::IsSame<Cell, T>::value && !mozilla::IsSame<TenuredCell, T>::value,
                   "T must not be Cell or TenuredCell");
 };
 
 template <typename T>
 struct RewrapTaggedPointer<Value, T>
 {
--- a/js/src/gc/Tracer.cpp
+++ b/js/src/gc/Tracer.cpp
@@ -11,16 +11,19 @@
 #include "jsutil.h"
 #include "NamespaceImports.h"
 
 #include "gc/GCInternals.h"
 #include "gc/Marking.h"
 #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"
 #include "vm/SymbolType.h"
 
 #include "gc/GC-inl.h"
 #include "vm/JSCompartment-inl.h"
 #include "vm/ObjectGroup-inl.h"
@@ -391,16 +394,22 @@ JS_GetTraceThingInfo(char* buf, size_t b
                ? "substring"
                : "string";
         break;
 
       case JS::TraceKind::Symbol:
         name = "symbol";
         break;
 
+#ifdef ENABLE_BIGINT
+      case JS::TraceKind::BigInt:
+        name = "BigInt";
+        break;
+#endif
+
       default:
         name = "INVALID";
         break;
     }
 
     n = strlen(name);
     if (n > bufsize - 1)
         n = bufsize - 1;
--- a/js/src/js.msg
+++ b/js/src/js.msg
@@ -641,8 +641,17 @@ MSG_DEF(JSMSG_STREAM_INVALID_HIGHWATERMA
 
 // Response-related
 MSG_DEF(JSMSG_ERROR_CONSUMING_RESPONSE,                  0, JSEXN_TYPEERR,  "there was an error consuming the Response")
 MSG_DEF(JSMSG_BAD_RESPONSE_VALUE,                        0, JSEXN_TYPEERR,  "expected Response or Promise resolving to Response")
 MSG_DEF(JSMSG_BAD_RESPONSE_MIME_TYPE,                    0, JSEXN_TYPEERR,  "Response has unsupported MIME type")
 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")
--- a/js/src/jsnum.cpp
+++ b/js/src/jsnum.cpp
@@ -1586,19 +1586,31 @@ js::ToNumberSlow(JSContext* cx, HandleVa
     if (v.isSymbol()) {
         if (!cx->helperThread()) {
             JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
                                       JSMSG_SYMBOL_TO_NUMBER);
         }
         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;
 }
 
 /*
  * Convert a value to an int8_t, according to the WebIDL rules for byte
  * conversion. Return converted value in *out on success, false on failure.
  */
 JS_PUBLIC_API(bool)
 js::ToInt8Slow(JSContext *cx, const HandleValue v, int8_t *out)
--- a/js/src/jspubtd.h
+++ b/js/src/jspubtd.h
@@ -44,16 +44,19 @@ enum JSType {
     JSTYPE_UNDEFINED,           /* undefined */
     JSTYPE_OBJECT,              /* object */
     JSTYPE_FUNCTION,            /* function */
     JSTYPE_STRING,              /* string */
     JSTYPE_NUMBER,              /* number */
     JSTYPE_BOOLEAN,             /* boolean */
     JSTYPE_NULL,                /* null */
     JSTYPE_SYMBOL,              /* symbol */
+#ifdef ENABLE_BIGINT
+    JSTYPE_BIGINT,              /* BigInt */
+#endif
     JSTYPE_LIMIT
 };
 
 /* Dense index into cached prototypes and class atoms for standard objects. */
 enum JSProtoKey {
 #define PROTOKEY_AND_INITIALIZER(name,init,clasp) JSProto_##name,
     JS_FOR_EACH_PROTOTYPE(PROTOKEY_AND_INITIALIZER)
 #undef PROTOKEY_AND_INITIALIZER
--- a/js/src/moz.build
+++ b/js/src/moz.build
@@ -453,16 +453,21 @@ SOURCES += [
     'jsmath.cpp',
     'jsutil.cpp',
     'util/DoubleToString.cpp',
     'vm/Interpreter.cpp',
     'vm/JSAtom.cpp',
     'vm/ProfilingStack.cpp',
 ]
 
+if CONFIG['ENABLE_BIGINT']:
+    SOURCES += [
+        'vm/BigIntType.cpp',
+    ]
+
 if CONFIG['JS_POSIX_NSPR']:
     UNIFIED_SOURCES += [
         'vm/PosixNSPR.cpp',
     ]
 
 if CONFIG['MOZ_INSTRUMENTS']:
     SOURCES += [
         'devtools/Instruments.cpp',
--- a/js/src/util/StringBuffer.cpp
+++ b/js/src/util/StringBuffer.cpp
@@ -159,11 +159,19 @@ js::ValueToStringBufferSlow(JSContext* c
     if (v.isBoolean())
         return BooleanToStringBuffer(v.toBoolean(), sb);
     if (v.isNull())
         return sb.append(cx->names().null);
     if (v.isSymbol()) {
         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);
 }
new file mode 100644
--- /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<BigInt>(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<BigInt>::size(mozilla::MallocSizeOf mallocSizeOf) const
+{
+    MOZ_ASSERT(get().isTenured());
+    return js::gc::Arena::thingSize(get().asTenured().getAllocKind());
+}
new file mode 100644
--- /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<BigInt*> 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
--- a/js/src/vm/CommonPropertyNames.h
+++ b/js/src/vm/CommonPropertyNames.h
@@ -456,11 +456,12 @@
     macro(undefined, undefined, "undefined") \
     macro(object, object, "object") \
     macro(function, function, "function") \
     macro(string, string, "string") \
     macro(number, number, "number") \
     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 */
--- a/js/src/vm/Interpreter.cpp
+++ b/js/src/vm/Interpreter.cpp
@@ -26,16 +26,19 @@
 #include "jit/AtomicOperations.h"
 #include "jit/BaselineJIT.h"
 #include "jit/Ion.h"
 #include "jit/IonAnalysis.h"
 #include "jit/Jit.h"
 #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"
 #include "vm/Iteration.h"
 #include "vm/JSAtom.h"
 #include "vm/JSContext.h"
 #include "vm/JSFunction.h"
 #include "vm/JSObject.h"
@@ -963,16 +966,20 @@ js::TypeOfValue(const Value& v)
     if (v.isNull())
         return JSTYPE_OBJECT;
     if (v.isUndefined())
         return JSTYPE_UNDEFINED;
     if (v.isObject())
         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;
 }
 
 bool
 js::CheckClassHeritageOperation(JSContext* cx, HandleValue heritage)
 {
     if (IsConstructor(heritage))
@@ -4365,17 +4372,20 @@ js::GetProperty(JSContext* cx, HandleVal
     if (name == cx->names().length) {
         // Fast path for strings, arrays and arguments.
         if (GetLengthProperty(v, vp))
             return true;
     }
 
     // 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());
         } else if (v.isString()) {
             proto = GlobalObject::getOrCreateStringPrototype(cx, cx->global());
         } else if (v.isBoolean()) {
             proto = GlobalObject::getOrCreateBooleanPrototype(cx, cx->global());
         } else {
--- a/js/src/vm/JSAtom.cpp
+++ b/js/src/vm/JSAtom.cpp
@@ -631,16 +631,24 @@ ToAtomSlow(JSContext* cx, typename Maybe
     if (v.isSymbol()) {
         MOZ_ASSERT(!cx->helperThread());
         if (allowGC) {
             JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
                                       JSMSG_SYMBOL_TO_STRING);
         }
         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;
 }
 
 template <AllowGC allowGC>
 JSAtom*
 js::ToAtom(JSContext* cx, typename MaybeRooted<Value, allowGC>::HandleType v)
 {
--- a/js/src/vm/JSCompartment-inl.h
+++ b/js/src/vm/JSCompartment-inl.h
@@ -110,16 +110,26 @@ JSCompartment::wrap(JSContext* cx, JS::M
     if (vp.isString()) {
         JS::RootedString str(cx, vp.toString());
         if (!wrap(cx, &str))
             return false;
         vp.setString(str);
         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());
 
     /*
      * All that's left are objects.
      *
      * Object wrapping isn't the fastest thing in the world, in part because
      * we have to unwrap and invoke the prewrap hook to find the identity
      * object before we even start checking the cache. Neither of these
--- a/js/src/vm/JSCompartment.cpp
+++ b/js/src/vm/JSCompartment.cpp
@@ -346,16 +346,33 @@ JSCompartment::wrap(JSContext* cx, Mutab
         return false;
     if (!putWrapper(cx, CrossCompartmentKey(key), StringValue(copy)))
         return false;
 
     strp.set(copy);
     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)
 {
     // Ensure that we have entered a compartment.
     MOZ_ASSERT(cx->global());
 
     // If we have a cross-compartment wrapper, make sure that the cx isn't
     // associated with the self-hosting global. We don't want to create
--- a/js/src/vm/JSCompartment.h
+++ b/js/src/vm/JSCompartment.h
@@ -856,16 +856,19 @@ struct JSCompartment
     ~JSCompartment();
 
     MOZ_MUST_USE bool init(JSContext* maybecx);
     void destroy(js::FreeOp* fop);
 
     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<JS::BigInt*> bi);
+#endif
     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);
     MOZ_MUST_USE bool rewrap(JSContext* cx, JS::MutableHandleObject obj, JS::HandleObject existing);
 
     MOZ_MUST_USE bool putWrapper(JSContext* cx, const js::CrossCompartmentKey& wrapped,
                                  const js::Value& wrapper);
 
--- a/js/src/vm/JSObject.cpp
+++ b/js/src/vm/JSObject.cpp
@@ -3235,19 +3235,30 @@ js::PrimitiveToObject(JSContext* cx, con
     if (v.isString()) {
         Rooted<JSString*> str(cx, v.toString());
         return StringObject::create(cx, str);
     }
     if (v.isNumber())
         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
 }
 
 /*
  * Invokes the ES5 ToObject algorithm on vp, returning the result. If vp might
  * already be an object, use ToObject. reportCantConvert controls how null and
  * undefined errors are reported.
  *
  * Callers must handle the already-object case.
--- a/js/src/vm/MemoryMetrics.cpp
+++ b/js/src/vm/MemoryMetrics.cpp
@@ -8,16 +8,19 @@
 
 #include "gc/GC.h"
 #include "gc/Heap.h"
 #include "gc/Nursery.h"
 #include "gc/PublicIterators.h"
 #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"
 #include "vm/JSScript.h"
 #include "vm/Runtime.h"
 #include "vm/Shape.h"
 #include "vm/StringType.h"
 #include "vm/SymbolType.h"
@@ -550,16 +553,25 @@ StatsCellCallback(JSRuntime* rt, void* d
         }
         break;
       }
 
       case JS::TraceKind::Symbol:
         zStats->symbolsGCHeap += thingSize;
         break;
 
+#ifdef ENABLE_BIGINT
+      case JS::TraceKind::BigInt: {
+        JS::BigInt* bi = static_cast<BigInt*>(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;
         // No malloc-heap measurements.
 
         zStats->shapeInfo.add(info);
         break;
       }
--- a/js/src/vm/StringType.cpp
+++ b/js/src/vm/StringType.cpp
@@ -2019,17 +2019,25 @@ js::ToStringSlow(JSContext* cx, typename
         str = cx->names().null;
     } else if (v.isSymbol()) {
         MOZ_ASSERT(!cx->helperThread());
         if (allowGC) {
             JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
                                       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;
     }
     return str;
 }
 
 template JSString*
 js::ToStringSlow<CanGC>(JSContext* cx, HandleValue arg);
--- a/js/src/vm/TypeInference-inl.h
+++ b/js/src/vm/TypeInference-inl.h
@@ -185,16 +185,20 @@ PrimitiveTypeFlag(JSValueType type)
       case JSVAL_TYPE_INT32:
         return TYPE_FLAG_INT32;
       case JSVAL_TYPE_DOUBLE:
         return TYPE_FLAG_DOUBLE;
       case JSVAL_TYPE_STRING:
         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:
         MOZ_CRASH("Bad JSValueType");
     }
 }
 
 inline JSValueType
@@ -210,16 +214,20 @@ TypeFlagPrimitive(TypeFlags flags)
       case TYPE_FLAG_INT32:
         return JSVAL_TYPE_INT32;
       case TYPE_FLAG_DOUBLE:
         return JSVAL_TYPE_DOUBLE;
       case TYPE_FLAG_STRING:
         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:
         MOZ_CRASH("Bad TypeFlags");
     }
 }
 
 /*
--- a/js/src/vm/TypeInference.cpp
+++ b/js/src/vm/TypeInference.cpp
@@ -106,16 +106,20 @@ TypeSet::NonObjectTypeString(TypeSet::Ty
           case JSVAL_TYPE_INT32:
             return "int";
           case JSVAL_TYPE_DOUBLE:
             return "float";
           case JSVAL_TYPE_STRING:
             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:
             MOZ_CRASH("Bad type");
         }
     }
     if (type.isUnknown())
         return "unknown";
@@ -778,16 +782,20 @@ TypeSet::print(FILE* fp)
     if (flags & TYPE_FLAG_INT32)
         fprintf(fp, " int");
     if (flags & TYPE_FLAG_DOUBLE)
         fprintf(fp, " float");
     if (flags & TYPE_FLAG_STRING)
         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");
 
     uint32_t objectCount = baseObjectCount();
     if (objectCount) {
         fprintf(fp, " object[%u]", objectCount);
 
         unsigned count = getObjectCount();
--- a/js/src/vm/TypeInference.h
+++ b/js/src/vm/TypeInference.h
@@ -55,36 +55,48 @@ class HeapTypeSetKey;
 enum : uint32_t {
     TYPE_FLAG_UNDEFINED =   0x1,
     TYPE_FLAG_NULL      =   0x2,
     TYPE_FLAG_BOOLEAN   =   0x4,
     TYPE_FLAG_INT32     =   0x8,
     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,
 
     /* Whether the contents of this type set are totally unknown. */
     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. */
 
     /*
      * Whether the property has ever been deleted or reconfigured to behave
      * differently from a plain data property, other than making the property
      * non-writable.
      */
@@ -105,16 +117,20 @@ enum : uint32_t {
      * If the property is definite, mask and shift storing the slot + 1.
      * Otherwise these bits are clear.
      */
     TYPE_FLAG_DEFINITE_MASK       = 0xfffc0000,
     TYPE_FLAG_DEFINITE_SHIFT      = 18
 };
 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. */
     OBJECT_FLAG_FROM_ALLOCATION_SITE  = 0x1,
 
     /* Whether this group is associated with a single object. */
     OBJECT_FLAG_SINGLETON             = 0x2,
 
@@ -361,16 +377,19 @@ class TypeSet
 
     static inline Type UndefinedType() { return Type(JSVAL_TYPE_UNDEFINED); }
     static inline Type NullType()      { return Type(JSVAL_TYPE_NULL); }
     static inline Type BooleanType()   { return Type(JSVAL_TYPE_BOOLEAN); }
     static inline Type Int32Type()     { return Type(JSVAL_TYPE_INT32); }
     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); }
 
     static inline Type PrimitiveType(JSValueType type) {
         MOZ_ASSERT(type < JSVAL_TYPE_UNKNOWN);
         return Type(type);
     }
--- a/js/src/vm/UbiNode.cpp
+++ b/js/src/vm/UbiNode.cpp
@@ -17,16 +17,19 @@
 
 #include "jit/IonCode.h"
 #include "js/Debug.h"
 #include "js/TracingAPI.h"
 #include "js/TypeDecls.h"
 #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"
 #include "vm/JSContext.h"
 #include "vm/JSObject.h"
 #include "vm/JSScript.h"
 #include "vm/Scope.h"
 #include "vm/Shape.h"
@@ -198,17 +201,23 @@ Node::exposeToJS() const
             v.setUndefined();
         } else {
             v.setObject(obj);
         }
     } else if (is<JSString>()) {
         v.setString(as<JSString>());
     } else if (is<JS::Symbol>()) {
         v.setSymbol(as<JS::Symbol>());
-    } else {
+    }
+#ifdef ENABLE_BIGINT
+    else if (is<BigInt>()) {
+        v.setBigInt(as<BigInt>());
+    }
+#endif
+    else {
         v.setUndefined();
     }
 
     ExposeValueToActiveJS(v);
 
     return v;
 }
 
@@ -310,16 +319,19 @@ TracerConcrete<Referent>::zone() const
 template JS::Zone* TracerConcrete<JSScript>::zone() const;
 template JS::Zone* TracerConcrete<js::LazyScript>::zone() const;
 template JS::Zone* TracerConcrete<js::Shape>::zone() const;
 template JS::Zone* TracerConcrete<js::BaseShape>::zone() const;
 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;
+#ifdef ENABLE_BIGINT
+template JS::Zone* TracerConcrete<BigInt>::zone() const;
+#endif
 template JS::Zone* TracerConcrete<JSString>::zone() const;
 
 template<typename Referent>
 UniquePtr<EdgeRange>
 TracerConcrete<Referent>::edges(JSContext* cx, bool wantNames) const {
     UniquePtr<SimpleEdgeRange, JS::DeletePolicy<SimpleEdgeRange>> range(js_new<SimpleEdgeRange>());
     if (!range)
         return nullptr;
@@ -333,16 +345,19 @@ TracerConcrete<Referent>::edges(JSContex
 template UniquePtr<EdgeRange> TracerConcrete<JSScript>::edges(JSContext* cx, bool wantNames) const;
 template UniquePtr<EdgeRange> TracerConcrete<js::LazyScript>::edges(JSContext* cx, bool wantNames) const;
 template UniquePtr<EdgeRange> TracerConcrete<js::Shape>::edges(JSContext* cx, bool wantNames) const;
 template UniquePtr<EdgeRange> TracerConcrete<js::BaseShape>::edges(JSContext* cx, bool wantNames) const;
 template UniquePtr<EdgeRange> TracerConcrete<js::ObjectGroup>::edges(JSContext* cx, bool wantNames) const;
 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;
+#ifdef ENABLE_BIGINT
+template UniquePtr<EdgeRange> TracerConcrete<BigInt>::edges(JSContext* cx, bool wantNames) const;
+#endif
 template UniquePtr<EdgeRange> TracerConcrete<JSString>::edges(JSContext* cx, bool wantNames) const;
 
 template<typename Referent>
 JSCompartment*
 TracerConcreteWithCompartment<Referent>::compartment() const
 {
     return TracerBase::get().compartment();
 }
@@ -388,16 +403,19 @@ Concrete<JSObject>::jsObjectConstructorN
     if (!JS_CopyStringChars(cx, chars, name))
         return false;
 
     outName[len] = '\0';
     return true;
 }
 
 const char16_t Concrete<JS::Symbol>::concreteTypeName[] = u"JS::Symbol";
+#ifdef ENABLE_BIGINT
+const char16_t Concrete<BigInt>::concreteTypeName[] = u"JS::BigInt";
+#endif
 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";
 const char16_t Concrete<js::Shape>::concreteTypeName[] = u"js::Shape";
 const char16_t Concrete<js::BaseShape>::concreteTypeName[] = u"js::BaseShape";
 const char16_t Concrete<js::ObjectGroup>::concreteTypeName[] = u"js::ObjectGroup";
 const char16_t Concrete<js::Scope>::concreteTypeName[] = u"js::Scope";
 const char16_t Concrete<js::RegExpShared>::concreteTypeName[] = u"js::RegExpShared";