[ES6] Implement Symbol.for and Symbol.keyFor
authorutatane.tea@gmail.com <utatane.tea@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 16 Apr 2015 22:46:35 +0000 (22:46 +0000)
committerutatane.tea@gmail.com <utatane.tea@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 16 Apr 2015 22:46:35 +0000 (22:46 +0000)
commit01e3beb3eddf4b92cf5f255b2bd8246c85e707ee
tree1650045ea86489f7c567cb739c2cc718d215c0cf
parent98a470c2f765e87fc6efc75dcc5708a5b9bf55bb
[ES6] Implement Symbol.for and Symbol.keyFor
https://bugs.webkit.org/show_bug.cgi?id=143404

Reviewed by Geoffrey Garen.

Source/JavaScriptCore:

This patch implements Symbol.for and Symbol.keyFor.
SymbolRegistry maintains registered StringImpl* symbols.
And to make this mapping enabled over realms,
VM owns this mapping (not JSGlobalObject).

While there's Default AtomicStringTable per thread,
SymbolRegistry should not exist over VMs.
So everytime VM is created, SymbolRegistry is also created.

In SymbolRegistry implementation, we don't leverage WeakGCMap (or weak reference design).
Theres are several reasons.
1. StringImpl* which represents identity of Symbols is not GC-managed object.
   So we cannot use WeakGCMap directly.
   While Symbol* is GC-managed object, holding weak reference to Symbol* doesn't maintain JS symbols (exposed primitive values to users) liveness,
   because distinct Symbol* can exist.
   Distinct Symbol* means the Symbol* object that pointer value (Symbol*) is different from weakly referenced Symbol* but held StringImpl* is the same.

2. We don't use WTF::WeakPtr. If we add WeakPtrFactory into StringImpl's member, we can track StringImpl*'s liveness by WeakPtr.
   However there's problem about when we prune staled entries in SymbolRegistry.
   Since the memory allocated for the Symbol is typically occupied by allocated symbolized StringImpl*'s content,
   and it is not in GC-heap.
   While heavily registering Symbols and storing StringImpl* into SymbolRegistry, Heap's EdenSpace is not so occupied.
   So GC typically attempt to perform EdenCollection, and it doesn't call WeakGCMap's pruleStaleEntries callback.
   As a result, before pruning staled entries in SymbolRegistry, fast malloc-ed memory fills up the system memory.

So instead of using Weak reference, we take relatively easy design.
When we register symbolized StringImpl* into SymbolRegistry, symbolized StringImpl* is aware of that.
And when destructing it, it removes its reference from SymbolRegistry as if atomic StringImpl do so with AtomicStringTable.

* CMakeLists.txt:
* DerivedSources.make:
* runtime/SymbolConstructor.cpp:
(JSC::SymbolConstructor::getOwnPropertySlot):
(JSC::symbolConstructorFor):
(JSC::symbolConstructorKeyFor):
* runtime/SymbolConstructor.h:
* runtime/VM.cpp:
* runtime/VM.h:
(JSC::VM::symbolRegistry):
* tests/stress/symbol-registry.js: Added.
(test):

Source/WTF:

When we register symbolized StringImpl* into SymbolRegistry, symbolized StringImpl* is aware of that.
And when destructing it, it removes its reference from SymbolRegistry as if atomic StringImpl do so with AtomicStringTable.
While AtomicStringTable (in WebCore case) exists in thread local storage,
SymbolRegistry exists per VM and StringImpl* has a reference to the registered SymbolRegistry.

Since StringImpl has isSymbol etc. members, it's class is aware of Symbol use cases.
So introduce SymbolRegistry in WTF layers as if AtomicStringTable.

* WTF.vcxproj/WTF.vcxproj:
* WTF.vcxproj/WTF.vcxproj.filters:
* WTF.xcodeproj/project.pbxproj:
* wtf/CMakeLists.txt:
* wtf/text/AtomicString.cpp:
(WTF::AtomicString::addSlowCase):
(WTF::AtomicString::findSlowCase):
(WTF::AtomicString::findInternal):
(WTF::AtomicString::find): Deleted.
* wtf/text/AtomicString.h:
(WTF::AtomicString::find):
* wtf/text/StringImpl.cpp:
(WTF::StringImpl::~StringImpl):
(WTF::StringImpl::createSymbol):
(WTF::StringImpl::createSymbolEmpty):
* wtf/text/StringImpl.h:
(WTF::StringImpl::StringImpl):
(WTF::StringImpl::extractFoldedStringInSymbol):
(WTF::StringImpl::symbolRegistry):
(WTF::StringImpl::createSymbolEmpty): Deleted.
* wtf/text/SymbolRegistry.cpp: Copied from Source/JavaScriptCore/runtime/SymbolConstructor.h.
(WTF::SymbolRegistry::~SymbolRegistry):
(WTF::SymbolRegistry::symbolForKey):
(WTF::SymbolRegistry::keyForSymbol):
(WTF::SymbolRegistry::remove):
* wtf/text/SymbolRegistry.h: Added.
(WTF::SymbolRegistryKey::hash):
(WTF::SymbolRegistryKey::impl):
(WTF::SymbolRegistryKey::isHashTableDeletedValue):
(WTF::SymbolRegistryKey::hashTableDeletedValue):
(WTF::DefaultHash<SymbolRegistryKey>::Hash::hash):
(WTF::DefaultHash<SymbolRegistryKey>::Hash::equal):
(WTF::HashTraits<SymbolRegistryKey>::isEmptyValue):
(WTF::SymbolRegistryKey::SymbolRegistryKey):

LayoutTests:

Add tests to check Symbol's identity over different realms.

* js/dom/cross-frame-symbols-expected.txt: Added.
* js/dom/cross-frame-symbols.html: Added.
* js/dom/script-tests/cross-frame-symbols.js: Added.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@182915 268f45cc-cd09-0410-ab3c-d52691b4dbfc
23 files changed:
LayoutTests/ChangeLog
LayoutTests/js/dom/cross-frame-symbols-expected.txt [new file with mode: 0644]
LayoutTests/js/dom/cross-frame-symbols.html [new file with mode: 0644]
LayoutTests/js/dom/script-tests/cross-frame-symbols.js [new file with mode: 0644]
Source/JavaScriptCore/CMakeLists.txt
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/DerivedSources.make
Source/JavaScriptCore/runtime/SymbolConstructor.cpp
Source/JavaScriptCore/runtime/SymbolConstructor.h
Source/JavaScriptCore/runtime/VM.cpp
Source/JavaScriptCore/runtime/VM.h
Source/JavaScriptCore/tests/stress/symbol-registry.js [new file with mode: 0644]
Source/WTF/ChangeLog
Source/WTF/WTF.vcxproj/WTF.vcxproj
Source/WTF/WTF.vcxproj/WTF.vcxproj.filters
Source/WTF/WTF.xcodeproj/project.pbxproj
Source/WTF/wtf/CMakeLists.txt
Source/WTF/wtf/text/AtomicString.cpp
Source/WTF/wtf/text/AtomicString.h
Source/WTF/wtf/text/StringImpl.cpp
Source/WTF/wtf/text/StringImpl.h
Source/WTF/wtf/text/SymbolRegistry.cpp [new file with mode: 0644]
Source/WTF/wtf/text/SymbolRegistry.h [new file with mode: 0644]