Implement ES6 symbol registry and predefined symbols
authorrossberg@chromium.org <rossberg@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 20 Mar 2014 12:26:27 +0000 (12:26 +0000)
committerrossberg@chromium.org <rossberg@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 20 Mar 2014 12:26:27 +0000 (12:26 +0000)
R=mstarzinger@chromium.org, arv@chromium.org
BUG=
LOG=Y

Review URL: https://codereview.chromium.org/203243004

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@20118 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

include/v8.h
src/heap.cc
src/heap.h
src/messages.js
src/runtime.cc
src/runtime.h
src/symbol.js
test/mjsunit/harmony/private.js
test/mjsunit/harmony/symbols.js

index 126a6f7..7a153b0 100644 (file)
@@ -5552,7 +5552,7 @@ class Internals {
   static const int kNullValueRootIndex = 7;
   static const int kTrueValueRootIndex = 8;
   static const int kFalseValueRootIndex = 9;
-  static const int kEmptyStringRootIndex = 144;
+  static const int kEmptyStringRootIndex = 145;
 
   static const int kNodeClassIdOffset = 1 * kApiPointerSize;
   static const int kNodeFlagsOffset = 1 * kApiPointerSize + 3;
index e2b83f5..0691947 100644 (file)
@@ -3288,6 +3288,14 @@ bool Heap::CreateInitialObjects() {
   }
   set_undefined_cell(Cell::cast(obj));
 
+  // Allocate objects to hold symbol registry.
+  { MaybeObject* maybe_obj = AllocateMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
+    if (!maybe_obj->ToObject(&obj)) return false;
+    maybe_obj = AllocateJSObjectFromMap(Map::cast(obj));
+    if (!maybe_obj->ToObject(&obj)) return false;
+  }
+  set_symbol_registry(JSObject::cast(obj));
+
   // Allocate object to hold object observation state.
   { MaybeObject* maybe_obj = AllocateMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
     if (!maybe_obj->ToObject(&obj)) return false;
index 4c280aa..0446a98 100644 (file)
@@ -190,6 +190,7 @@ namespace internal {
   V(Cell, undefined_cell, UndefineCell)                                        \
   V(JSObject, observation_state, ObservationState)                             \
   V(Map, external_map, ExternalMap)                                            \
+  V(JSObject, symbol_registry, SymbolRegistry)                                 \
   V(Symbol, frozen_symbol, FrozenSymbol)                                       \
   V(Symbol, nonexistent_symbol, NonExistentSymbol)                             \
   V(Symbol, elements_transition_symbol, ElementsTransitionSymbol)              \
index e6365a4..6abaa4e 100644 (file)
@@ -103,6 +103,7 @@ var kMessages = {
   invalid_argument:              ["invalid_argument"],
   data_view_not_array_buffer:    ["First argument to DataView constructor must be an ArrayBuffer"],
   constructor_not_function:      ["Constructor ", "%0", " requires 'new'"],
+  not_a_symbol:                  ["%0", " is not a symbol"],
   not_a_promise:                 ["%0", " is not a promise"],
   resolver_not_a_function:       ["Promise resolver ", "%0", " is not a function"],
   promise_cyclic:                ["Chaining cycle detected for promise ", "%0"],
index 762b7a5..f3cf01b 100644 (file)
@@ -636,6 +636,13 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_SymbolDescription) {
 }
 
 
+RUNTIME_FUNCTION(MaybeObject*, Runtime_SymbolRegistry) {
+  SealHandleScope shs(isolate);
+  ASSERT(args.length() == 0);
+  return isolate->heap()->symbol_registry();
+}
+
+
 RUNTIME_FUNCTION(MaybeObject*, Runtime_SymbolIsPrivate) {
   SealHandleScope shs(isolate);
   ASSERT(args.length() == 1);
index 0060639..3c8077f 100644 (file)
@@ -314,6 +314,7 @@ namespace internal {
   F(CreatePrivateSymbol, 1, 1) \
   F(NewSymbolWrapper, 1, 1) \
   F(SymbolDescription, 1, 1) \
+  F(SymbolRegistry, 0, 1) \
   F(SymbolIsPrivate, 1, 1) \
   \
   /* Harmony proxies */ \
index 8cb1927..49f9096 100644 (file)
@@ -63,6 +63,46 @@ function SymbolValueOf() {
 }
 
 
+function GetSymbolRegistry() {
+  var registry = %SymbolRegistry();
+  if (!('internal' in registry)) {
+    registry.internal = {__proto__: null};
+    registry.for = {__proto__: null};
+    registry.keyFor = {__proto__: null};
+  }
+  return registry;
+}
+
+
+function InternalSymbol(key) {
+  var registry = GetSymbolRegistry();
+  if (!(key in registry.internal)) {
+    registry.internal[key] = %CreateSymbol(key);
+  }
+  return registry.internal[key];
+}
+
+
+function SymbolFor(key) {
+  key = TO_STRING_INLINE(key);
+  var registry = GetSymbolRegistry();
+  if (!(key in registry.for)) {
+    var symbol = %CreateSymbol(key);
+    registry.for[key] = symbol;
+    registry.keyFor[symbol] = key;
+  }
+  return registry.for[key];
+}
+
+
+function SymbolKeyFor(symbol) {
+  if (!IS_SYMBOL(symbol)) {
+    throw MakeTypeError("not_a_symbol", [symbol]);
+  }
+  return GetSymbolRegistry().keyFor[symbol];
+}
+
+
 // ES6 19.1.2.8
 function ObjectGetOwnPropertySymbols(obj) {
   if (!IS_SPEC_OBJECT(obj)) {
@@ -78,12 +118,36 @@ function ObjectGetOwnPropertySymbols(obj) {
 
 //-------------------------------------------------------------------
 
+var symbolCreate = InternalSymbol("@@create");
+var symbolHasInstance = InternalSymbol("@@hasInstance");
+var symbolIsConcatSpreadable = InternalSymbol("@@isConcatSpreadable");
+var symbolIsRegExp = InternalSymbol("@@isRegExp");
+var symbolIterator = InternalSymbol("@@iterator");
+var symbolToStringTag = InternalSymbol("@@toStringTag");
+var symbolUnscopables = InternalSymbol("@@unscopables");
+
+
+//-------------------------------------------------------------------
+
 function SetUpSymbol() {
   %CheckIsBootstrapping();
 
   %SetCode($Symbol, SymbolConstructor);
   %FunctionSetPrototype($Symbol, new $Object());
 
+  %SetProperty($Symbol, "create", symbolCreate, DONT_ENUM);
+  %SetProperty($Symbol, "hasInstance", symbolHasInstance, DONT_ENUM);
+  %SetProperty($Symbol, "isConcatSpreadable",
+      symbolIsConcatSpreadable, DONT_ENUM);
+  %SetProperty($Symbol, "isRegExp", symbolIsRegExp, DONT_ENUM);
+  %SetProperty($Symbol, "iterator", symbolIterator, DONT_ENUM);
+  %SetProperty($Symbol, "toStringTag", symbolToStringTag, DONT_ENUM);
+  %SetProperty($Symbol, "unscopables", symbolUnscopables, DONT_ENUM);
+  InstallFunctions($Symbol, DONT_ENUM, $Array(
+    "for", SymbolFor,
+    "keyFor", SymbolKeyFor
+  ));
+
   %SetProperty($Symbol.prototype, "constructor", $Symbol, DONT_ENUM);
   InstallFunctions($Symbol.prototype, DONT_ENUM, $Array(
     "toString", SymbolToString,
index 9c9bf2c..a14afe0 100644 (file)
@@ -328,3 +328,17 @@ function TestCachedKeyAfterScavenge() {
   }
 }
 TestCachedKeyAfterScavenge();
+
+
+function TestGetOwnPropertySymbols() {
+  var privateSymbol = %CreatePrivateSymbol("private")
+  var publicSymbol = Symbol()
+  var publicSymbol2 = Symbol()
+  var obj = {}
+  obj[publicSymbol] = 1
+  obj[privateSymbol] = 2
+  obj[publicSymbol2] = 3
+  var syms = Object.getOwnPropertySymbols(obj)
+  assertEquals(syms, [publicSymbol, publicSymbol2])
+}
+TestGetOwnPropertySymbols()
index 26adb74..d19aece 100644 (file)
@@ -410,15 +410,42 @@ function TestGetOwnPropertySymbolsWithProto() {
 TestGetOwnPropertySymbolsWithProto()
 
 
-function TestGetOwnPropertySymbolsWithPrivateSymbols() {
-  var privateSymbol = %CreatePrivateSymbol("private")
-  var publicSymbol = Symbol()
-  var publicSymbol2 = Symbol()
-  var obj = {}
-  obj[publicSymbol] = 1
-  obj[privateSymbol] = 2
-  obj[publicSymbol2] = 3
-  var syms = Object.getOwnPropertySymbols(obj)
-  assertEquals(syms, [publicSymbol, publicSymbol2])
+function TestRegistry() {
+  assertFalse(Symbol.for("@@create") === Symbol.create)
+  assertFalse(Symbol.for("@@iterator") === Symbol.iterator)
+  assertTrue(Symbol.keyFor(Symbol.create) === undefined)
+  assertTrue(Symbol.keyFor(Symbol.iterator) === undefined)
+
+  var symbol1 = Symbol.for("x1")
+  var symbol2 = Symbol.for("x2")
+  assertFalse(symbol1 === symbol2)
+
+  assertSame(symbol1, Symbol.for("x1"))
+  assertSame(symbol2, Symbol.for("x2"))
+  assertSame("x1", Symbol.keyFor(symbol1))
+  assertSame("x2", Symbol.keyFor(symbol2))
+
+  assertSame(Symbol.for("1"), Symbol.for(1))
+  assertThrows(function() { Symbol.keyFor("bla") }, TypeError)
+  assertThrows(function() { Symbol.keyFor({}) }, TypeError)
+
+  var realm = Realm.create()
+  assertFalse(Symbol === Realm.eval(realm, "Symbol"))
+  assertFalse(Symbol.for === Realm.eval(realm, "Symbol.for"))
+  assertFalse(Symbol.keyFor === Realm.eval(realm, "Symbol.keyFor"))
+  assertSame(Symbol.create, Realm.eval(realm, "Symbol.create"))
+  assertSame(Symbol.iterator, Realm.eval(realm, "Symbol.iterator"))
+
+  assertSame(symbol1, Realm.eval(realm, "Symbol.for")("x1"))
+  assertSame(symbol1, Realm.eval(realm, "Symbol.for('x1')"))
+  assertSame("x1", Realm.eval(realm, "Symbol.keyFor")(symbol1))
+  Realm.shared = symbol1
+  assertSame("x1", Realm.eval(realm, "Symbol.keyFor(Realm.shared)"))
+
+  var symbol3 = Realm.eval(realm, "Symbol.for('x3')")
+  assertFalse(symbol1 === symbol3)
+  assertFalse(symbol2 === symbol3)
+  assertSame(symbol3, Symbol.for("x3"))
+  assertSame("x3", Symbol.keyFor(symbol3))
 }
-TestGetOwnPropertySymbolsWithPrivateSymbols()
+TestRegistry()