Bug 645416, part 2 - Add support for symbols to JS::Value. r=luke.
authorJason Orendorff <jorendorff@mozilla.com>
Mon, 23 Jun 2014 10:55:51 -0500
changeset 190269 192a1527e6f1dc845a542fa9f7ee8e4e5ded0e14
parent 190268 c319984f3156092d7f9bfe7fef9d2e42c9252fac
child 190270 537d97cbf684826ee4153e15d2287fa31fd6e761
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
reviewersluke
bugs645416
milestone33.0a1
Bug 645416, part 2 - Add support for symbols to JS::Value. r=luke. The API for symbol Values is much like the API for strings. The implementation behind all this is in a later patch. Here, a class JS::Symbol is declared, but not defined anywhere yet. The constants being deleted from js/public/Value.h probably haven't been used since Tracemonkey days.
js/public/TypeDecls.h
js/public/Value.h
--- a/js/public/TypeDecls.h
+++ b/js/public/TypeDecls.h
@@ -32,16 +32,17 @@ class JSAddonId;
 struct jsid;
 
 typedef char16_t jschar;
 
 namespace JS {
 
 typedef unsigned char Latin1Char;
 
+class Symbol;
 class Value;
 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;
--- a/js/public/Value.h
+++ b/js/public/Value.h
@@ -91,16 +91,17 @@ JS_STATIC_ASSERT(sizeof(JSValueType) == 
 
 /* Remember to propagate changes to the C defines below. */
 JS_ENUM_HEADER(JSValueTag, uint32_t)
 {
     JSVAL_TAG_CLEAR                = 0xFFFFFF80,
     JSVAL_TAG_INT32                = JSVAL_TAG_CLEAR | JSVAL_TYPE_INT32,
     JSVAL_TAG_UNDEFINED            = JSVAL_TAG_CLEAR | JSVAL_TYPE_UNDEFINED,
     JSVAL_TAG_STRING               = JSVAL_TAG_CLEAR | JSVAL_TYPE_STRING,
+    JSVAL_TAG_SYMBOL               = JSVAL_TAG_CLEAR | JSVAL_TYPE_SYMBOL,
     JSVAL_TAG_BOOLEAN              = JSVAL_TAG_CLEAR | JSVAL_TYPE_BOOLEAN,
     JSVAL_TAG_MAGIC                = JSVAL_TAG_CLEAR | JSVAL_TYPE_MAGIC,
     JSVAL_TAG_NULL                 = JSVAL_TAG_CLEAR | JSVAL_TYPE_NULL,
     JSVAL_TAG_OBJECT               = JSVAL_TAG_CLEAR | JSVAL_TYPE_OBJECT
 } JS_ENUM_FOOTER(JSValueTag);
 
 JS_STATIC_ASSERT(sizeof(JSValueTag) == 4);
 
@@ -108,30 +109,32 @@ JS_STATIC_ASSERT(sizeof(JSValueTag) == 4
 
 /* Remember to propagate changes to the C defines below. */
 JS_ENUM_HEADER(JSValueTag, uint32_t)
 {
     JSVAL_TAG_MAX_DOUBLE           = 0x1FFF0,
     JSVAL_TAG_INT32                = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_INT32,
     JSVAL_TAG_UNDEFINED            = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_UNDEFINED,
     JSVAL_TAG_STRING               = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_STRING,
+    JSVAL_TAG_SYMBOL               = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_SYMBOL,
     JSVAL_TAG_BOOLEAN              = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_BOOLEAN,
     JSVAL_TAG_MAGIC                = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_MAGIC,
     JSVAL_TAG_NULL                 = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_NULL,
     JSVAL_TAG_OBJECT               = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_OBJECT
 } JS_ENUM_FOOTER(JSValueTag);
 
 JS_STATIC_ASSERT(sizeof(JSValueTag) == sizeof(uint32_t));
 
 JS_ENUM_HEADER(JSValueShiftedTag, uint64_t)
 {
     JSVAL_SHIFTED_TAG_MAX_DOUBLE   = ((((uint64_t)JSVAL_TAG_MAX_DOUBLE) << JSVAL_TAG_SHIFT) | 0xFFFFFFFF),
     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_STRING       = (((uint64_t)JSVAL_TAG_STRING)     << JSVAL_TAG_SHIFT),
+    JSVAL_SHIFTED_TAG_SYMBOL       = (((uint64_t)JSVAL_TAG_SYMBOL)     << 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_NULL         = (((uint64_t)JSVAL_TAG_NULL)       << JSVAL_TAG_SHIFT),
     JSVAL_SHIFTED_TAG_OBJECT       = (((uint64_t)JSVAL_TAG_OBJECT)     << JSVAL_TAG_SHIFT)
 } JS_ENUM_FOOTER(JSValueShiftedTag);
 
 JS_STATIC_ASSERT(sizeof(JSValueShiftedTag) == sizeof(uint64_t));
 
@@ -141,62 +144,61 @@ JS_STATIC_ASSERT(sizeof(JSValueShiftedTa
 
 typedef uint8_t JSValueType;
 #define JSVAL_TYPE_DOUBLE            ((uint8_t)0x00)
 #define JSVAL_TYPE_INT32             ((uint8_t)0x01)
 #define JSVAL_TYPE_UNDEFINED         ((uint8_t)0x02)
 #define JSVAL_TYPE_BOOLEAN           ((uint8_t)0x03)
 #define JSVAL_TYPE_MAGIC             ((uint8_t)0x04)
 #define JSVAL_TYPE_STRING            ((uint8_t)0x05)
-#define JSVAL_TYPE_NULL              ((uint8_t)0x06)
-#define JSVAL_TYPE_OBJECT            ((uint8_t)0x07)
+#define JSVAL_TYPE_SYMBOL            ((uint8_t)0x06)
+#define JSVAL_TYPE_NULL              ((uint8_t)0x07)
+#define JSVAL_TYPE_OBJECT            ((uint8_t)0x08)
 #define JSVAL_TYPE_UNKNOWN           ((uint8_t)0x20)
 
 #if defined(JS_NUNBOX32)
 
 typedef uint32_t JSValueTag;
 #define JSVAL_TAG_CLEAR              ((uint32_t)(0xFFFFFF80))
 #define JSVAL_TAG_INT32              ((uint32_t)(JSVAL_TAG_CLEAR | JSVAL_TYPE_INT32))
 #define JSVAL_TAG_UNDEFINED          ((uint32_t)(JSVAL_TAG_CLEAR | JSVAL_TYPE_UNDEFINED))
 #define JSVAL_TAG_STRING             ((uint32_t)(JSVAL_TAG_CLEAR | JSVAL_TYPE_STRING))
+#define JSVAL_TAG_SYMBOL             ((uint32_t)(JSVAL_TAG_CLEAR | JSVAL_TYPE_SYMBOL))
 #define JSVAL_TAG_BOOLEAN            ((uint32_t)(JSVAL_TAG_CLEAR | JSVAL_TYPE_BOOLEAN))
 #define JSVAL_TAG_MAGIC              ((uint32_t)(JSVAL_TAG_CLEAR | JSVAL_TYPE_MAGIC))
 #define JSVAL_TAG_NULL               ((uint32_t)(JSVAL_TAG_CLEAR | JSVAL_TYPE_NULL))
 #define JSVAL_TAG_OBJECT             ((uint32_t)(JSVAL_TAG_CLEAR | JSVAL_TYPE_OBJECT))
 
 #elif defined(JS_PUNBOX64)
 
 typedef uint32_t JSValueTag;
 #define JSVAL_TAG_MAX_DOUBLE         ((uint32_t)(0x1FFF0))
 #define JSVAL_TAG_INT32              (uint32_t)(JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_INT32)
 #define JSVAL_TAG_UNDEFINED          (uint32_t)(JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_UNDEFINED)
 #define JSVAL_TAG_STRING             (uint32_t)(JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_STRING)
+#define JSVAL_TAG_SYMBOL             (uint32_t)(JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_SYMBOL)
 #define JSVAL_TAG_BOOLEAN            (uint32_t)(JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_BOOLEAN)
 #define JSVAL_TAG_MAGIC              (uint32_t)(JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_MAGIC)
 #define JSVAL_TAG_NULL               (uint32_t)(JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_NULL)
 #define JSVAL_TAG_OBJECT             (uint32_t)(JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_OBJECT)
 
 typedef uint64_t JSValueShiftedTag;
 #define JSVAL_SHIFTED_TAG_MAX_DOUBLE ((((uint64_t)JSVAL_TAG_MAX_DOUBLE) << JSVAL_TAG_SHIFT) | 0xFFFFFFFF)
 #define JSVAL_SHIFTED_TAG_INT32      (((uint64_t)JSVAL_TAG_INT32)      << JSVAL_TAG_SHIFT)
 #define JSVAL_SHIFTED_TAG_UNDEFINED  (((uint64_t)JSVAL_TAG_UNDEFINED)  << JSVAL_TAG_SHIFT)
 #define JSVAL_SHIFTED_TAG_STRING     (((uint64_t)JSVAL_TAG_STRING)     << JSVAL_TAG_SHIFT)
+#define JSVAL_SHIFTED_TAG_SYMBOL     (((uint64_t)JSVAL_TAG_SYMBOL)     << JSVAL_TAG_SHIFT)
 #define JSVAL_SHIFTED_TAG_BOOLEAN    (((uint64_t)JSVAL_TAG_BOOLEAN)    << JSVAL_TAG_SHIFT)
 #define JSVAL_SHIFTED_TAG_MAGIC      (((uint64_t)JSVAL_TAG_MAGIC)      << JSVAL_TAG_SHIFT)
 #define JSVAL_SHIFTED_TAG_NULL       (((uint64_t)JSVAL_TAG_NULL)       << JSVAL_TAG_SHIFT)
 #define JSVAL_SHIFTED_TAG_OBJECT     (((uint64_t)JSVAL_TAG_OBJECT)     << JSVAL_TAG_SHIFT)
 
 #endif  /* JS_PUNBOX64 */
 #endif  /* !defined(__SUNPRO_CC) && !defined(__xlC__) */
 
-#define JSVAL_LOWER_INCL_TYPE_OF_OBJ_OR_NULL_SET        JSVAL_TYPE_NULL
-#define JSVAL_UPPER_EXCL_TYPE_OF_PRIMITIVE_SET          JSVAL_TYPE_OBJECT
-#define JSVAL_UPPER_INCL_TYPE_OF_NUMBER_SET             JSVAL_TYPE_INT32
-#define JSVAL_LOWER_INCL_TYPE_OF_PTR_PAYLOAD_SET        JSVAL_TYPE_MAGIC
-
 #if defined(JS_NUNBOX32)
 
 #define JSVAL_TYPE_TO_TAG(type)      ((JSValueTag)(JSVAL_TAG_CLEAR | (type)))
 
 #define JSVAL_LOWER_INCL_TAG_OF_OBJ_OR_NULL_SET         JSVAL_TAG_NULL
 #define JSVAL_UPPER_EXCL_TAG_OF_PRIMITIVE_SET           JSVAL_TAG_OBJECT
 #define JSVAL_UPPER_INCL_TAG_OF_NUMBER_SET              JSVAL_TAG_INT32
 #define JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET             JSVAL_TAG_STRING
@@ -250,16 +252,17 @@ typedef union jsval_layout
 {
     uint64_t asBits;
     struct {
         union {
             int32_t        i32;
             uint32_t       u32;
             uint32_t       boo;     // Don't use |bool| -- it must be four bytes.
             JSString       *str;
+            JS::Symbol     *sym;
             JSObject       *obj;
             js::gc::Cell   *cell;
             void           *ptr;
             JSWhyMagic     why;
             size_t         word;
             uintptr_t      uintptr;
         } payload;
         JSValueTag tag;
@@ -469,16 +472,38 @@ STRING_TO_JSVAL_IMPL(JSString *str)
 
 static inline JSString *
 JSVAL_TO_STRING_IMPL(jsval_layout l)
 {
     return l.s.payload.str;
 }
 
 static inline bool
+JSVAL_IS_SYMBOL_IMPL(jsval_layout l)
+{
+    return l.s.tag == JSVAL_TAG_SYMBOL;
+}
+
+static inline jsval_layout
+SYMBOL_TO_JSVAL_IMPL(JS::Symbol *sym)
+{
+    jsval_layout l;
+    MOZ_ASSERT(uintptr_t(sym) > 0x1000);
+    l.s.tag = JSVAL_TAG_SYMBOL;
+    l.s.payload.sym = sym;
+    return l;
+}
+
+static inline JS::Symbol *
+JSVAL_TO_SYMBOL_IMPL(jsval_layout l)
+{
+    return l.s.payload.sym;
+}
+
+static inline bool
 JSVAL_IS_BOOLEAN_IMPL(jsval_layout l)
 {
     return l.s.tag == JSVAL_TAG_BOOLEAN;
 }
 
 static inline bool
 JSVAL_TO_BOOLEAN_IMPL(jsval_layout l)
 {
@@ -566,22 +591,16 @@ JSVAL_IS_GCTHING_IMPL(jsval_layout l)
 }
 
 static inline js::gc::Cell *
 JSVAL_TO_GCTHING_IMPL(jsval_layout l)
 {
     return l.s.payload.cell;
 }
 
-static inline bool
-JSVAL_IS_TRACEABLE_IMPL(jsval_layout l)
-{
-    return l.s.tag == JSVAL_TAG_STRING || l.s.tag == JSVAL_TAG_OBJECT;
-}
-
 static inline uint32_t
 JSVAL_TRACE_KIND_IMPL(jsval_layout l)
 {
     return (uint32_t)(bool)JSVAL_IS_STRING_IMPL(l);
 }
 
 static inline bool
 JSVAL_IS_SPECIFIC_INT32_IMPL(jsval_layout l, int32_t i32)
@@ -700,16 +719,39 @@ STRING_TO_JSVAL_IMPL(JSString *str)
 
 static inline JSString *
 JSVAL_TO_STRING_IMPL(jsval_layout l)
 {
     return (JSString *)(l.asBits & JSVAL_PAYLOAD_MASK);
 }
 
 static inline bool
+JSVAL_IS_SYMBOL_IMPL(jsval_layout l)
+{
+    return (uint32_t)(l.asBits >> JSVAL_TAG_SHIFT) == JSVAL_TAG_SYMBOL;
+}
+
+static inline jsval_layout
+SYMBOL_TO_JSVAL_IMPL(JS::Symbol *sym)
+{
+    jsval_layout l;
+    uint64_t symBits = (uint64_t)sym;
+    MOZ_ASSERT(uintptr_t(sym) > 0x1000);
+    MOZ_ASSERT((symBits >> JSVAL_TAG_SHIFT) == 0);
+    l.asBits = symBits | JSVAL_SHIFTED_TAG_SYMBOL;
+    return l;
+}
+
+static inline JS::Symbol *
+JSVAL_TO_SYMBOL_IMPL(jsval_layout l)
+{
+    return (JS::Symbol *)(l.asBits & JSVAL_PAYLOAD_MASK);
+}
+
+static inline bool
 JSVAL_IS_BOOLEAN_IMPL(jsval_layout l)
 {
     return (uint32_t)(l.asBits >> JSVAL_TAG_SHIFT) == JSVAL_TAG_BOOLEAN;
 }
 
 static inline bool
 JSVAL_TO_BOOLEAN_IMPL(jsval_layout l)
 {
@@ -784,22 +826,16 @@ JSVAL_IS_GCTHING_IMPL(jsval_layout l)
 static inline js::gc::Cell *
 JSVAL_TO_GCTHING_IMPL(jsval_layout l)
 {
     uint64_t ptrBits = l.asBits & JSVAL_PAYLOAD_MASK;
     MOZ_ASSERT((ptrBits & 0x7) == 0);
     return reinterpret_cast<js::gc::Cell *>(ptrBits);
 }
 
-static inline bool
-JSVAL_IS_TRACEABLE_IMPL(jsval_layout l)
-{
-    return JSVAL_IS_GCTHING_IMPL(l) && !JSVAL_IS_NULL_IMPL(l);
-}
-
 static inline uint32_t
 JSVAL_TRACE_KIND_IMPL(jsval_layout l)
 {
     return (uint32_t)(bool)!(JSVAL_IS_OBJECT_IMPL(l));
 }
 
 static inline jsval_layout
 PRIVATE_PTR_TO_JSVAL_IMPL(void *ptr)
@@ -860,16 +896,22 @@ JSVAL_EXTRACT_NON_DOUBLE_TYPE_IMPL(jsval
 {
    uint64_t type = (l.asBits >> JSVAL_TAG_SHIFT) & 0xF;
    MOZ_ASSERT(type > JSVAL_TYPE_DOUBLE);
    return (JSValueType)type;
 }
 
 #endif  /* JS_PUNBOX64 */
 
+static inline bool
+JSVAL_IS_TRACEABLE_IMPL(jsval_layout l)
+{
+    return JSVAL_IS_GCTHING_IMPL(l) && !JSVAL_IS_NULL_IMPL(l);
+}
+
 static inline jsval_layout JSVAL_TO_IMPL(JS::Value v);
 static inline JS_VALUE_CONSTEXPR JS::Value IMPL_TO_JSVAL(jsval_layout l);
 
 namespace JS {
 
 static inline JS_VALUE_CONSTEXPR JS::Value UndefinedValue();
 
 /**
@@ -900,17 +942,17 @@ CanonicalizeNaN(double d)
 #endif
 
 /*
  * 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, Boolean, Undefined, Null, Object, Magic }
+ *     { Int32, Double, String, Symbol, 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
@@ -974,16 +1016,21 @@ class Value
         return data.asDouble;
     }
 
     void setString(JSString *str) {
         MOZ_ASSERT(!IsPoisonedPtr(str));
         data = STRING_TO_JSVAL_IMPL(str);
     }
 
+    void setSymbol(JS::Symbol *sym) {
+        MOZ_ASSERT(!IsPoisonedPtr(sym));
+        data = SYMBOL_TO_JSVAL_IMPL(sym);
+    }
+
     void setObject(JSObject &obj) {
         MOZ_ASSERT(!IsPoisonedPtr(&obj));
         data = OBJECT_TO_JSVAL_IMPL(&obj);
     }
 
     void setBoolean(bool b) {
         data = BOOLEAN_TO_JSVAL_IMPL(b);
     }
@@ -1059,16 +1106,20 @@ class Value
     bool isNumber() const {
         return JSVAL_IS_NUMBER_IMPL(data);
     }
 
     bool isString() const {
         return JSVAL_IS_STRING_IMPL(data);
     }
 
+    bool isSymbol() const {
+        return JSVAL_IS_SYMBOL_IMPL(data);
+    }
+
     bool isObject() const {
         return JSVAL_IS_OBJECT_IMPL(data);
     }
 
     bool isPrimitive() const {
         return JSVAL_IS_PRIMITIVE_IMPL(data);
     }
 
@@ -1149,16 +1200,21 @@ class Value
         return isDouble() ? toDouble() : double(toInt32());
     }
 
     JSString *toString() const {
         MOZ_ASSERT(isString());
         return JSVAL_TO_STRING_IMPL(data);
     }
 
+    JS::Symbol *toSymbol() const {
+        MOZ_ASSERT(isSymbol());
+        return JSVAL_TO_SYMBOL_IMPL(data);
+    }
+
     JSObject &toObject() const {
         MOZ_ASSERT(isObject());
         return *JSVAL_TO_OBJECT_IMPL(data);
     }
 
     JSObject *toObjectOrNull() const {
         MOZ_ASSERT(isObjectOrNull());
         return JSVAL_TO_OBJECT_IMPL(data);
@@ -1270,16 +1326,18 @@ class Value
     friend Value JS_VALUE_CONSTEXPR (JS::UndefinedValue)();
 };
 
 inline bool
 IsPoisonedValue(const Value &v)
 {
     if (v.isString())
         return IsPoisonedPtr(v.toString());
+    if (v.isSymbol())
+        return IsPoisonedPtr(v.toSymbol());
     if (v.isObject())
         return IsPoisonedPtr(&v.toObject());
     return false;
 }
 
 inline bool
 IsOptimizedPlaceholderMagicValue(const Value &v)
 {
@@ -1355,16 +1413,24 @@ static inline Value
 StringValue(JSString *str)
 {
     Value v;
     v.setString(str);
     return v;
 }
 
 static inline Value
+SymbolValue(JS::Symbol *sym)
+{
+    Value v;
+    v.setSymbol(sym);
+    return v;
+}
+
+static inline Value
 BooleanValue(bool boo)
 {
     Value v;
     v.setBoolean(boo);
     return v;
 }
 
 static inline Value
@@ -1595,31 +1661,33 @@ class ValueOperations
     bool isNull() const { return value()->isNull(); }
     bool isBoolean() const { return value()->isBoolean(); }
     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 isDouble() const { return value()->isDouble(); }
     bool isString() const { return value()->isString(); }
+    bool isSymbol() const { return value()->isSymbol(); }
     bool isObject() const { return value()->isObject(); }
     bool isMagic() const { return value()->isMagic(); }
     bool isMagic(JSWhyMagic why) const { return value()->isMagic(why); }
     bool isMarkable() const { return value()->isMarkable(); }
     bool isPrimitive() const { return value()->isPrimitive(); }
     bool isGCThing() const { return value()->isGCThing(); }
 
     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(); }
     JSObject &toObject() const { return value()->toObject(); }
     JSObject *toObjectOrNull() const { return value()->toObjectOrNull(); }
     void *toGCThing() const { return value()->toGCThing(); }
     uint64_t asRawBits() const { return value()->asRawBits(); }
 
     JSValueType extractNonDoubleType() const { return value()->extractNonDoubleType(); }
     uint32_t toPrivateUint32() const { return value()->toPrivateUint32(); }
 
@@ -1644,16 +1712,17 @@ class MutableValueOperations : public Va
     void setInt32(int32_t i) { value()->setInt32(i); }
     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); }
     void setObject(JSObject &obj) { this->value()->setObject(obj); }
     void setObjectOrNull(JSObject *arg) { this->value()->setObjectOrNull(arg); }
 };
 
 /*
  * Augment the generic Heap<T> interface when T = Value with
  * type-querying, value-extracting, and mutating operations.
  */
@@ -1674,16 +1743,17 @@ class HeapBase<JS::Value> : public Value
     void setNull() { setBarriered(JS::NullValue()); }
     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)); }
     void setObject(JSObject &obj) { setBarriered(JS::ObjectValue(obj)); }
 
     bool setNumber(uint32_t ui) {
         if (ui > JSVAL_INT_MAX) {
             setDouble((double)ui);
             return false;
         } else {
             setInt32((int32_t)ui);