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 id27004
push useremorley@mozilla.com
push dateTue, 24 Jun 2014 15:52:34 +0000
treeherdermozilla-central@7b174d47f3cc [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersluke
bugs645416
milestone33.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
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);