Bug 1328386 - Part 5: Add Intl.[[FallbackSymbol]] to support ECMA402, 4th edition legacy constructor semantics. r=Waldo
authorAndré Bargull <andre.bargull@gmail.com>
Mon, 23 Jan 2017 08:33:40 -0800
changeset 331047 985a0c1baa892278e078fb4d796fc87a730aaeb4
parent 331046 e1415ba91dd2620247fab41c5472f42b33cbc299
child 331048 91080dad0ff8d9211948e470500a12cbb3bcf515
push id86156
push userryanvm@gmail.com
push dateWed, 25 Jan 2017 22:49:02 +0000
treeherdermozilla-inbound@f35fe2367a4d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersWaldo
bugs1328386
milestone54.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 1328386 - Part 5: Add Intl.[[FallbackSymbol]] to support ECMA402, 4th edition legacy constructor semantics. r=Waldo
js/src/builtin/Intl.js
js/src/builtin/SymbolObject.cpp
js/src/builtin/SymbolObject.h
js/src/builtin/Utilities.js
js/src/vm/GlobalObject.cpp
--- a/js/src/builtin/Intl.js
+++ b/js/src/builtin/Intl.js
@@ -1192,16 +1192,35 @@ function GetNumberOption(options, proper
     // Step 3.
     return fallback;
 }
 
 
 /********** Property access for Intl objects **********/
 
 
+// Symbols in the self-hosting compartment can't be cloned, use a separate
+// object to hold the actual symbol value.
+// TODO: Can we add support to clone symbols?
+var intlFallbackSymbolHolder = { value: undefined };
+
+/**
+ * The [[FallbackSymbol]] symbol of the %Intl% intrinsic object.
+ *
+ * This symbol is used to implement the legacy constructor semantics for
+ * Intl.DateTimeFormat and Intl.NumberFormat.
+ */
+function intlFallbackSymbol() {
+    var fallbackSymbol = intlFallbackSymbolHolder.value;
+    if (!fallbackSymbol)
+        intlFallbackSymbolHolder.value = fallbackSymbol = std_Symbol();
+    return fallbackSymbol;
+}
+
+
 /**
  * Weak map used to track the initialize-as-Intl status (and, if an object has
  * been so initialized, the Intl-specific internal properties) of all objects.
  * Presence of an object as a key within this map indicates that the object has
  * its [[initializedIntlObject]] internal property set to true.  The associated
  * value is an object whose structure is documented in |initializeIntlObject|
  * below.
  *
--- a/js/src/builtin/SymbolObject.cpp
+++ b/js/src/builtin/SymbolObject.cpp
@@ -45,51 +45,59 @@ const JSFunctionSpec SymbolObject::metho
 
 const JSFunctionSpec SymbolObject::staticMethods[] = {
     JS_FN("for", for_, 1, 0),
     JS_FN("keyFor", keyFor, 1, 0),
     JS_FS_END
 };
 
 JSObject*
-SymbolObject::initClass(JSContext* cx, HandleObject obj)
+SymbolObject::initClass(JSContext* cx, HandleObject obj, bool defineMembers)
 {
     Handle<GlobalObject*> global = obj.as<GlobalObject>();
 
     // This uses &JSObject::class_ because: "The Symbol prototype object is an
     // ordinary object. It is not a Symbol instance and does not have a
     // [[SymbolData]] internal slot." (ES6 rev 24, 19.4.3)
     RootedObject proto(cx, GlobalObject::createBlankPrototype<PlainObject>(cx, global));
     if (!proto)
         return nullptr;
 
     RootedFunction ctor(cx, GlobalObject::createConstructor(cx, construct,
                                                             ClassName(JSProto_Symbol, cx), 0));
     if (!ctor)
         return nullptr;
 
-    // Define the well-known symbol properties, such as Symbol.iterator.
-    ImmutablePropertyNamePtr* names = cx->names().wellKnownSymbolNames();
-    RootedValue value(cx);
-    unsigned attrs = JSPROP_READONLY | JSPROP_PERMANENT;
-    WellKnownSymbols* wks = cx->runtime()->wellKnownSymbols;
-    for (size_t i = 0; i < JS::WellKnownSymbolLimit; i++) {
-        value.setSymbol(wks->get(i));
-        if (!NativeDefineProperty(cx, ctor, names[i], value, nullptr, nullptr, attrs))
-            return nullptr;
+    if (defineMembers) {
+        // Define the well-known symbol properties, such as Symbol.iterator.
+        ImmutablePropertyNamePtr* names = cx->names().wellKnownSymbolNames();
+        RootedValue value(cx);
+        unsigned attrs = JSPROP_READONLY | JSPROP_PERMANENT;
+        WellKnownSymbols* wks = cx->runtime()->wellKnownSymbols;
+        for (size_t i = 0; i < JS::WellKnownSymbolLimit; i++) {
+            value.setSymbol(wks->get(i));
+            if (!NativeDefineProperty(cx, ctor, names[i], value, nullptr, nullptr, attrs))
+                return nullptr;
+        }
     }
 
-    if (!LinkConstructorAndPrototype(cx, ctor, proto) ||
-        !DefinePropertiesAndFunctions(cx, proto, properties, methods) ||
-        !DefineToStringTag(cx, proto, cx->names().Symbol) ||
-        !DefinePropertiesAndFunctions(cx, ctor, nullptr, staticMethods) ||
-        !GlobalObject::initBuiltinConstructor(cx, global, JSProto_Symbol, ctor, proto))
-    {
+    if (!LinkConstructorAndPrototype(cx, ctor, proto))
         return nullptr;
+
+    if (defineMembers) {
+        if (!DefinePropertiesAndFunctions(cx, proto, properties, methods) ||
+            !DefineToStringTag(cx, proto, cx->names().Symbol) ||
+            !DefinePropertiesAndFunctions(cx, ctor, nullptr, staticMethods))
+        {
+            return nullptr;
+        }
     }
+
+    if (!GlobalObject::initBuiltinConstructor(cx, global, JSProto_Symbol, ctor, proto))
+        return nullptr;
     return proto;
 }
 
 // ES6 rev 24 (2014 Apr 27) 19.4.1.1 and 19.4.1.2
 bool
 SymbolObject::construct(JSContext* cx, unsigned argc, Value* vp)
 {
     // According to a note in the draft standard, "Symbol has ordinary
@@ -225,10 +233,16 @@ SymbolObject::toPrimitive(JSContext* cx,
     // The specification gives exactly the same algorithm for @@toPrimitive as
     // for valueOf, so reuse the valueOf implementation.
     return CallNonGenericMethod<IsSymbol, valueOf_impl>(cx, args);
 }
 
 JSObject*
 js::InitSymbolClass(JSContext* cx, HandleObject obj)
 {
-    return SymbolObject::initClass(cx, obj);
+    return SymbolObject::initClass(cx, obj, true);
 }
+
+JSObject*
+js::InitBareSymbolCtor(JSContext* cx, HandleObject obj)
+{
+    return SymbolObject::initClass(cx, obj, false);
+}
--- a/js/src/builtin/SymbolObject.h
+++ b/js/src/builtin/SymbolObject.h
@@ -17,17 +17,17 @@ class SymbolObject : public NativeObject
     /* Stores this Symbol object's [[PrimitiveValue]]. */
     static const unsigned PRIMITIVE_VALUE_SLOT = 0;
 
   public:
     static const unsigned RESERVED_SLOTS = 1;
 
     static const Class class_;
 
-    static JSObject* initClass(JSContext* cx, js::HandleObject obj);
+    static JSObject* initClass(JSContext* cx, js::HandleObject obj, bool defineMembers);
 
     /*
      * Creates a new Symbol object boxing the given primitive Symbol.  The
      * object's [[Prototype]] is determined from context.
      */
     static SymbolObject* create(JSContext* cx, JS::HandleSymbol symbol);
 
     JS::Symbol* unbox() const {
@@ -55,11 +55,14 @@ class SymbolObject : public NativeObject
     static const JSPropertySpec properties[];
     static const JSFunctionSpec methods[];
     static const JSFunctionSpec staticMethods[];
 };
 
 extern JSObject*
 InitSymbolClass(JSContext* cx, HandleObject obj);
 
+extern JSObject*
+InitBareSymbolCtor(JSContext* cx, HandleObject obj);
+
 } /* namespace js */
 
 #endif /* builtin_SymbolObject_h */
--- a/js/src/builtin/Utilities.js
+++ b/js/src/builtin/Utilities.js
@@ -38,16 +38,18 @@
 
 // All C++-implemented standard builtins library functions used in self-hosted
 // code are installed via the std_functions JSFunctionSpec[] in
 // SelfHosting.cpp.
 //
 // Do not create an alias to a self-hosted builtin, otherwise it will be cloned
 // twice.
 //
+// Symbol is a bare constructor without properties or methods.
+var std_Symbol = Symbol;
 // WeakMap is a bare constructor without properties or methods.
 var std_WeakMap = WeakMap;
 // StopIteration is a bare constructor without properties or methods.
 var std_StopIteration = StopIteration;
 
 
 /********** List specification type **********/
 
--- a/js/src/vm/GlobalObject.cpp
+++ b/js/src/vm/GlobalObject.cpp
@@ -525,16 +525,17 @@ GlobalObject::initSelfHostingBuiltins(JS
     {
         return false;
     }
 
     return InitBareBuiltinCtor(cx, global, JSProto_Array) &&
            InitBareBuiltinCtor(cx, global, JSProto_TypedArray) &&
            InitBareBuiltinCtor(cx, global, JSProto_Uint8Array) &&
            InitBareBuiltinCtor(cx, global, JSProto_Int32Array) &&
+           InitBareSymbolCtor(cx, global) &&
            InitBareWeakMapCtor(cx, global) &&
            InitStopIterationClass(cx, global) &&
            DefineFunctions(cx, global, builtins, AsIntrinsic);
 }
 
 /* static */ bool
 GlobalObject::isRuntimeCodeGenEnabled(JSContext* cx, Handle<GlobalObject*> global)
 {