From 0f71f617998dacd8c2ed8e7fa98c3e8ece4090d8 Mon Sep 17 00:00:00 2001 From: "rossberg@chromium.org" Date: Thu, 20 Mar 2014 12:26:27 +0000 Subject: [PATCH] Implement ES6 symbol registry and predefined symbols 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 | 2 +- src/heap.cc | 8 ++++++ src/heap.h | 1 + src/messages.js | 1 + src/runtime.cc | 7 +++++ src/runtime.h | 1 + src/symbol.js | 64 +++++++++++++++++++++++++++++++++++++++++ test/mjsunit/harmony/private.js | 14 +++++++++ test/mjsunit/harmony/symbols.js | 49 ++++++++++++++++++++++++------- 9 files changed, 135 insertions(+), 12 deletions(-) diff --git a/include/v8.h b/include/v8.h index 126a6f7..7a153b0 100644 --- a/include/v8.h +++ b/include/v8.h @@ -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; diff --git a/src/heap.cc b/src/heap.cc index e2b83f5..0691947 100644 --- a/src/heap.cc +++ b/src/heap.cc @@ -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; diff --git a/src/heap.h b/src/heap.h index 4c280aa..0446a98 100644 --- a/src/heap.h +++ b/src/heap.h @@ -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) \ diff --git a/src/messages.js b/src/messages.js index e6365a4..6abaa4e 100644 --- a/src/messages.js +++ b/src/messages.js @@ -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"], diff --git a/src/runtime.cc b/src/runtime.cc index 762b7a5..f3cf01b 100644 --- a/src/runtime.cc +++ b/src/runtime.cc @@ -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); diff --git a/src/runtime.h b/src/runtime.h index 0060639..3c8077f 100644 --- a/src/runtime.h +++ b/src/runtime.h @@ -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 */ \ diff --git a/src/symbol.js b/src/symbol.js index 8cb1927..49f9096 100644 --- a/src/symbol.js +++ b/src/symbol.js @@ -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, diff --git a/test/mjsunit/harmony/private.js b/test/mjsunit/harmony/private.js index 9c9bf2c..a14afe0 100644 --- a/test/mjsunit/harmony/private.js +++ b/test/mjsunit/harmony/private.js @@ -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() diff --git a/test/mjsunit/harmony/symbols.js b/test/mjsunit/harmony/symbols.js index 26adb74..d19aece 100644 --- a/test/mjsunit/harmony/symbols.js +++ b/test/mjsunit/harmony/symbols.js @@ -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() -- 2.7.4