Title: [201825] trunk/Source/_javascript_Core
Revision
201825
Author
keith_mil...@apple.com
Date
2016-06-08 12:40:34 -0700 (Wed, 08 Jun 2016)

Log Message

We should be able to lookup symbols by identifier in builtins
https://bugs.webkit.org/show_bug.cgi?id=158530

Reviewed by Mark Lam.

This patch allows us to lookup the value of a symbol property on a
object by identifier in builtins. Before, it was only possible to
do so if we were directly emitting the bytecodes, such as in a
for-of loop looking for Symbol.iterator. As we tier up we convert
the builtin's get_by_val symbol lookups into get_by_id
lookups. However, there is still a significant performance
difference between get_by_id and get_by_val in the LLInt, where
this transformation does not take place.

In order to make this work we hijack BuiltinNames'
m_publicToPrivateMap so that it points the @<symbol>Symbol to the
appropriate vm symbol. This way when we lex the identifier it will
become the appropriate symbol's identifier.  Currently, if the
symbol is used to name a property in an object literal we will not
keep a cache of the Symbol objects we have already seen. We could
add a map for symbols but since we can only load symbols by
identifier in builtins its likely not worth it. Additionally, even
in builtins it is extremely rare to use Symbols in object
literals.

* builtins/ArrayConstructor.js:
(from):
* builtins/ArrayPrototype.js:
(filter):
(map):
* builtins/BuiltinNames.h:
(JSC::BuiltinNames::BuiltinNames):
* builtins/BuiltinUtils.h:
* builtins/GlobalObject.js:
(speciesConstructor):
* builtins/StringPrototype.js:
(match):
(intrinsic.StringPrototypeReplaceIntrinsic.replace):
(search):
(split):
* builtins/TypedArrayConstructor.js:
(from):
* builtins/TypedArrayPrototype.js:
(map):
(filter):
* bytecode/BytecodeIntrinsicRegistry.cpp:
(JSC::BytecodeIntrinsicRegistry::BytecodeIntrinsicRegistry): Deleted.
* bytecode/BytecodeIntrinsicRegistry.h:
* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::emitLoad):
* parser/Parser.cpp:
(JSC::Parser<LexerType>::parseInner):

Modified Paths

Diff

Modified: trunk/Source/_javascript_Core/ChangeLog (201824 => 201825)


--- trunk/Source/_javascript_Core/ChangeLog	2016-06-08 19:20:52 UTC (rev 201824)
+++ trunk/Source/_javascript_Core/ChangeLog	2016-06-08 19:40:34 UTC (rev 201825)
@@ -1,3 +1,58 @@
+2016-06-08  Keith Miller  <keith_mil...@apple.com>
+
+        We should be able to lookup symbols by identifier in builtins
+        https://bugs.webkit.org/show_bug.cgi?id=158530
+
+        Reviewed by Mark Lam.
+
+        This patch allows us to lookup the value of a symbol property on a
+        object by identifier in builtins. Before, it was only possible to
+        do so if we were directly emitting the bytecodes, such as in a
+        for-of loop looking for Symbol.iterator. As we tier up we convert
+        the builtin's get_by_val symbol lookups into get_by_id
+        lookups. However, there is still a significant performance
+        difference between get_by_id and get_by_val in the LLInt, where
+        this transformation does not take place.
+
+        In order to make this work we hijack BuiltinNames'
+        m_publicToPrivateMap so that it points the @<symbol>Symbol to the
+        appropriate vm symbol. This way when we lex the identifier it will
+        become the appropriate symbol's identifier.  Currently, if the
+        symbol is used to name a property in an object literal we will not
+        keep a cache of the Symbol objects we have already seen. We could
+        add a map for symbols but since we can only load symbols by
+        identifier in builtins its likely not worth it. Additionally, even
+        in builtins it is extremely rare to use Symbols in object
+        literals.
+
+        * builtins/ArrayConstructor.js:
+        (from):
+        * builtins/ArrayPrototype.js:
+        (filter):
+        (map):
+        * builtins/BuiltinNames.h:
+        (JSC::BuiltinNames::BuiltinNames):
+        * builtins/BuiltinUtils.h:
+        * builtins/GlobalObject.js:
+        (speciesConstructor):
+        * builtins/StringPrototype.js:
+        (match):
+        (intrinsic.StringPrototypeReplaceIntrinsic.replace):
+        (search):
+        (split):
+        * builtins/TypedArrayConstructor.js:
+        (from):
+        * builtins/TypedArrayPrototype.js:
+        (map):
+        (filter):
+        * bytecode/BytecodeIntrinsicRegistry.cpp:
+        (JSC::BytecodeIntrinsicRegistry::BytecodeIntrinsicRegistry): Deleted.
+        * bytecode/BytecodeIntrinsicRegistry.h:
+        * bytecompiler/BytecodeGenerator.cpp:
+        (JSC::BytecodeGenerator::emitLoad):
+        * parser/Parser.cpp:
+        (JSC::Parser<LexerType>::parseInner):
+
 2016-06-08  Rawinder Singh  <rawinder.singh-web...@cisra.canon.com.au>
 
         [web-animations] Add Animatable, AnimationEffect, KeyframeEffect and Animation interface

Modified: trunk/Source/_javascript_Core/builtins/ArrayConstructor.js (201824 => 201825)


--- trunk/Source/_javascript_Core/builtins/ArrayConstructor.js	2016-06-08 19:20:52 UTC (rev 201824)
+++ trunk/Source/_javascript_Core/builtins/ArrayConstructor.js	2016-06-08 19:40:34 UTC (rev 201825)
@@ -57,7 +57,7 @@
     if (items == null)
         throw new @TypeError("Array.from requires an array-like object - not null or undefined");
 
-    var iteratorMethod = items[@symbolIterator];
+    var iteratorMethod = items.@iteratorSymbol;
     if (iteratorMethod != null) {
         if (typeof iteratorMethod !== "function")
             throw new @TypeError("Array.from requires that the property of the first argument, items[Symbol.iterator], when exists, be a function");
@@ -71,11 +71,8 @@
         // Since for-of loop once more looks up the @@iterator property of a given iterable,
         // it could be observable if the user defines a getter for @@iterator.
         // To avoid this situation, we define a wrapper object that @@iterator just returns a given iterator.
-        var wrapper = {
-            [@symbolIterator]() {
-                return iterator;
-            }
-        };
+        var wrapper = {}
+        wrapper.@iteratorSymbol = function() { return iterator; };
 
         for (var value of wrapper) {
             if (mapFn)

Modified: trunk/Source/_javascript_Core/builtins/ArrayPrototype.js (201824 => 201825)


--- trunk/Source/_javascript_Core/builtins/ArrayPrototype.js	2016-06-08 19:20:52 UTC (rev 201824)
+++ trunk/Source/_javascript_Core/builtins/ArrayPrototype.js	2016-06-08 19:40:34 UTC (rev 201825)
@@ -226,7 +226,7 @@
         if (@isArrayConstructor(constructor) && @Array !== constructor)
             constructor = @undefined;
         if (@isObject(constructor)) {
-            constructor = constructor[@symbolSpecies];
+            constructor = constructor.@speciesSymbol;
             if (constructor === null)
                 constructor = @undefined;
         }
@@ -278,7 +278,7 @@
         if (@isArrayConstructor(constructor) && @Array !== constructor)
             constructor = @undefined;
         if (@isObject(constructor)) {
-            constructor = constructor[@symbolSpecies];
+            constructor = constructor.@speciesSymbol;
             if (constructor === null)
                 constructor = @undefined;
         }

Modified: trunk/Source/_javascript_Core/builtins/BuiltinNames.h (201824 => 201825)


--- trunk/Source/_javascript_Core/builtins/BuiltinNames.h	2016-06-08 19:20:52 UTC (rev 201824)
+++ trunk/Source/_javascript_Core/builtins/BuiltinNames.h	2016-06-08 19:40:34 UTC (rev 201825)
@@ -35,6 +35,11 @@
 #define INITIALIZE_PRIVATE_TO_PUBLIC_ENTRY(name) m_privateToPublicMap.add(m_##name##PrivateName.impl(), &m_##name);
 #define INITIALIZE_PUBLIC_TO_PRIVATE_ENTRY(name) m_publicToPrivateMap.add(m_##name.impl(), &m_##name##PrivateName);
 
+// We commandeer the publicToPrivateMap to allow us to convert private symbol names into the appropriate symbol.
+// e.g. @iteratorSymbol points to Symbol.iterator in this map rather than to a an actual private name.
+// FIXME: This is a weird hack and we shouldn't need to do this.
+#define INITIALIZE_SYMBOL_PUBLIC_TO_PRIVATE_ENTRY(name) m_publicToPrivateMap.add(m_##name##SymbolPrivateIdentifier.impl(), &m_##name##Symbol);
+
 class BuiltinNames {
     WTF_MAKE_NONCOPYABLE(BuiltinNames); WTF_MAKE_FAST_ALLOCATED;
     
@@ -54,6 +59,7 @@
         JSC_COMMON_PRIVATE_IDENTIFIERS_EACH_PROPERTY_NAME(INITIALIZE_PRIVATE_TO_PUBLIC_ENTRY)
         JSC_FOREACH_BUILTIN_FUNCTION_NAME(INITIALIZE_PUBLIC_TO_PRIVATE_ENTRY)
         JSC_COMMON_PRIVATE_IDENTIFIERS_EACH_PROPERTY_NAME(INITIALIZE_PUBLIC_TO_PRIVATE_ENTRY)
+        JSC_COMMON_PRIVATE_IDENTIFIERS_EACH_WELL_KNOWN_SYMBOL(INITIALIZE_SYMBOL_PUBLIC_TO_PRIVATE_ENTRY)
         m_privateToPublicMap.add(m_dollarVMPrivateName.impl(), &m_dollarVMName);
         m_publicToPrivateMap.add(m_dollarVMName.impl(), &m_dollarVMPrivateName);
     }

Modified: trunk/Source/_javascript_Core/builtins/BuiltinUtils.h (201824 => 201825)


--- trunk/Source/_javascript_Core/builtins/BuiltinUtils.h	2016-06-08 19:20:52 UTC (rev 201824)
+++ trunk/Source/_javascript_Core/builtins/BuiltinUtils.h	2016-06-08 19:40:34 UTC (rev 201825)
@@ -37,8 +37,8 @@
     const JSC::Identifier& name##PublicName() const { return m_##name; } \
     const JSC::Identifier& name##PrivateName() const { return m_##name##PrivateName; }
 
-#define INITIALIZE_BUILTIN_SYMBOLS(name) , m_##name##Symbol(JSC::Identifier::fromUid(JSC::PrivateName(JSC::PrivateName::Description, ASCIILiteral("Symbol." #name))))
-#define DECLARE_BUILTIN_SYMBOLS(name) const JSC::Identifier m_##name##Symbol;
+#define INITIALIZE_BUILTIN_SYMBOLS(name) , m_##name##Symbol(JSC::Identifier::fromUid(JSC::PrivateName(JSC::PrivateName::Description, ASCIILiteral("Symbol." #name)))), m_##name##SymbolPrivateIdentifier(JSC::Identifier::fromString(vm, #name "Symbol"))
+#define DECLARE_BUILTIN_SYMBOLS(name) const JSC::Identifier m_##name##Symbol; const JSC::Identifier m_##name##SymbolPrivateIdentifier;
 #define DECLARE_BUILTIN_SYMBOL_ACCESSOR(name) \
     const JSC::Identifier& name##Symbol() const { return m_##name##Symbol; }
 

Modified: trunk/Source/_javascript_Core/builtins/GlobalObject.js (201824 => 201825)


--- trunk/Source/_javascript_Core/builtins/GlobalObject.js	2016-06-08 19:20:52 UTC (rev 201824)
+++ trunk/Source/_javascript_Core/builtins/GlobalObject.js	2016-06-08 19:40:34 UTC (rev 201825)
@@ -69,7 +69,7 @@
         return defaultConstructor;
     if (!@isObject(constructor))
         throw new @TypeError("|this|.constructor is not an Object or undefined");
-    constructor = constructor[@symbolSpecies];
+    constructor = constructor.@speciesSymbol;
     if (constructor == null)
         return defaultConstructor;
     if (@isConstructor(constructor))

Modified: trunk/Source/_javascript_Core/builtins/StringPrototype.js (201824 => 201825)


--- trunk/Source/_javascript_Core/builtins/StringPrototype.js	2016-06-08 19:20:52 UTC (rev 201824)
+++ trunk/Source/_javascript_Core/builtins/StringPrototype.js	2016-06-08 19:40:34 UTC (rev 201825)
@@ -36,14 +36,14 @@
     }
 
     if (regexp != null) {
-        var matcher = regexp[@symbolMatch];
+        var matcher = regexp.@matchSymbol;
         if (matcher != @undefined)
             return matcher.@call(regexp, this);
     }
 
     let thisString = @toString(this);
     let createdRegExp = @regExpCreate(regexp, @undefined);
-    return createdRegExp[@symbolMatch](thisString);
+    return createdRegExp.@matchSymbol(thisString);
 }
 
 function repeatSlowPath(string, count)
@@ -233,7 +233,7 @@
     }
 
     if (search != null) {
-        let replacer = search[@symbolReplace];
+        let replacer = search.@replaceSymbol;
         if (replacer !== @undefined) {
             if (!@hasObservableSideEffectsForStringReplace(search, replacer))
                 return @toString(this).@replaceUsingRegExp(search, replace);
@@ -291,14 +291,14 @@
     }
 
     if (regexp != null) {
-        var searcher = regexp[@symbolSearch];
+        var searcher = regexp.@searchSymbol;
         if (searcher != @undefined)
             return searcher.@call(regexp, this);
     }
 
     var thisString = @toString(this);
     var createdRegExp = @regExpCreate(regexp, @undefined);
-    return createdRegExp[@symbolSearch](thisString);
+    return createdRegExp.@searchSymbol(thisString);
 }
 
 function split(separator, limit)
@@ -312,7 +312,7 @@
     }
     
     if (separator != null) {
-        var splitter = separator[@symbolSplit];
+        var splitter = separator.@splitSymbol;
         if (splitter != @undefined)
             return splitter.@call(separator, this, limit);
     }

Modified: trunk/Source/_javascript_Core/builtins/TypedArrayConstructor.js (201824 => 201825)


--- trunk/Source/_javascript_Core/builtins/TypedArrayConstructor.js	2016-06-08 19:20:52 UTC (rev 201824)
+++ trunk/Source/_javascript_Core/builtins/TypedArrayConstructor.js	2016-06-08 19:40:34 UTC (rev 201825)
@@ -63,7 +63,7 @@
     if (items == null)
         throw new @TypeError("TypedArray.from requires an array-like object - not null or undefined");
 
-    let iteratorMethod = items[@symbolIterator];
+    let iteratorMethod = items.@iteratorSymbol;
     if (iteratorMethod != null) {
         if (typeof iteratorMethod !== "function")
             throw new @TypeError("TypedArray.from requires that the property of the first argument, items[Symbol.iterator], when exists, be a function");
@@ -76,13 +76,9 @@
         // Since for-of loop once more looks up the @@iterator property of a given iterable,
         // it could be observable if the user defines a getter for @@iterator.
         // To avoid this situation, we define a wrapper object that @@iterator just returns a given iterator.
-        let wrapper = {
-            [@symbolIterator]() {
-                return iterator;
-            }
-        };
+        let wrapper = {};
+        wrapper.@iteratorSymbol = function() { return iterator; }
 
-
         for (let value of wrapper) {
             if (mapFn)
                 @putByValDirect(accumulator, k, thisArg === @undefined ? mapFn(value, k) : mapFn.@call(thisArg, value, k));

Modified: trunk/Source/_javascript_Core/builtins/TypedArrayPrototype.js (201824 => 201825)


--- trunk/Source/_javascript_Core/builtins/TypedArrayPrototype.js	2016-06-08 19:20:52 UTC (rev 201824)
+++ trunk/Source/_javascript_Core/builtins/TypedArrayPrototype.js	2016-06-08 19:40:34 UTC (rev 201825)
@@ -261,7 +261,7 @@
     if (constructor === @undefined)
         result = new (@typedArrayGetOriginalConstructor(this))(length);
     else {
-        var speciesConstructor = @Object(constructor)[@symbolSpecies];
+        var speciesConstructor = @Object(constructor).@speciesSymbol;
         if (speciesConstructor === null || speciesConstructor === @undefined)
             result = new (@typedArrayGetOriginalConstructor(this))(length);
         else {
@@ -302,7 +302,7 @@
     if (constructor === @undefined)
         result = new (@typedArrayGetOriginalConstructor(this))(resultLength);
     else {
-        var speciesConstructor = @Object(constructor)[@symbolSpecies];
+        var speciesConstructor = @Object(constructor).@speciesSymbol;
         if (speciesConstructor === null || speciesConstructor === @undefined)
             result = new (@typedArrayGetOriginalConstructor(this))(resultLength);
         else {

Modified: trunk/Source/_javascript_Core/bytecode/BytecodeIntrinsicRegistry.cpp (201824 => 201825)


--- trunk/Source/_javascript_Core/bytecode/BytecodeIntrinsicRegistry.cpp	2016-06-08 19:20:52 UTC (rev 201824)
+++ trunk/Source/_javascript_Core/bytecode/BytecodeIntrinsicRegistry.cpp	2016-06-08 19:40:34 UTC (rev 201825)
@@ -54,12 +54,6 @@
     m_promiseStatePending.set(m_vm, jsNumber(static_cast<unsigned>(JSPromise::Status::Pending)));
     m_promiseStateFulfilled.set(m_vm, jsNumber(static_cast<unsigned>(JSPromise::Status::Fulfilled)));
     m_promiseStateRejected.set(m_vm, jsNumber(static_cast<unsigned>(JSPromise::Status::Rejected)));
-    m_symbolIterator.set(m_vm, Symbol::create(m_vm, static_cast<SymbolImpl&>(*m_vm.propertyNames->iteratorSymbol.impl())));
-    m_symbolMatch.set(m_vm, Symbol::create(m_vm, static_cast<SymbolImpl&>(*m_vm.propertyNames->matchSymbol.impl())));
-    m_symbolReplace.set(m_vm, Symbol::create(m_vm, static_cast<SymbolImpl&>(*m_vm.propertyNames->replaceSymbol.impl())));
-    m_symbolSearch.set(m_vm, Symbol::create(m_vm, static_cast<SymbolImpl&>(*m_vm.propertyNames->searchSymbol.impl())));
-    m_symbolSpecies.set(m_vm, Symbol::create(m_vm, static_cast<SymbolImpl&>(*m_vm.propertyNames->speciesSymbol.impl())));
-    m_symbolSplit.set(m_vm, Symbol::create(m_vm, static_cast<SymbolImpl&>(*m_vm.propertyNames->splitSymbol.impl())));
     m_GeneratorResumeModeNormal.set(m_vm, jsNumber(static_cast<int32_t>(JSGeneratorFunction::GeneratorResumeMode::NormalMode)));
     m_GeneratorResumeModeThrow.set(m_vm, jsNumber(static_cast<int32_t>(JSGeneratorFunction::GeneratorResumeMode::ThrowMode)));
     m_GeneratorResumeModeReturn.set(m_vm, jsNumber(static_cast<int32_t>(JSGeneratorFunction::GeneratorResumeMode::ReturnMode)));

Modified: trunk/Source/_javascript_Core/bytecode/BytecodeIntrinsicRegistry.h (201824 => 201825)


--- trunk/Source/_javascript_Core/bytecode/BytecodeIntrinsicRegistry.h	2016-06-08 19:20:52 UTC (rev 201824)
+++ trunk/Source/_javascript_Core/bytecode/BytecodeIntrinsicRegistry.h	2016-06-08 19:40:34 UTC (rev 201825)
@@ -57,12 +57,6 @@
     macro(promiseStatePending) \
     macro(promiseStateFulfilled) \
     macro(promiseStateRejected) \
-    macro(symbolIterator) \
-    macro(symbolMatch) \
-    macro(symbolReplace) \
-    macro(symbolSearch) \
-    macro(symbolSpecies) \
-    macro(symbolSplit) \
     macro(GeneratorResumeModeNormal) \
     macro(GeneratorResumeModeThrow) \
     macro(GeneratorResumeModeReturn) \

Modified: trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.cpp (201824 => 201825)


--- trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.cpp	2016-06-08 19:20:52 UTC (rev 201824)
+++ trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.cpp	2016-06-08 19:40:34 UTC (rev 201825)
@@ -1727,9 +1727,11 @@
 
 RegisterID* BytecodeGenerator::emitLoad(RegisterID* dst, const Identifier& identifier)
 {
+    ASSERT(!identifier.isSymbol());
     JSString*& stringInMap = m_stringMap.add(identifier.impl(), nullptr).iterator->value;
     if (!stringInMap)
         stringInMap = jsOwnedString(vm(), identifier.string());
+
     return emitLoad(dst, JSValue(stringInMap));
 }
 

Modified: trunk/Source/_javascript_Core/parser/Parser.cpp (201824 => 201825)


--- trunk/Source/_javascript_Core/parser/Parser.cpp	2016-06-08 19:20:52 UTC (rev 201824)
+++ trunk/Source/_javascript_Core/parser/Parser.cpp	2016-06-08 19:40:34 UTC (rev 201825)
@@ -321,9 +321,8 @@
     if (m_parsingBuiltin && isProgramParseMode(parseMode)) {
         VariableEnvironment& lexicalVariables = scope->lexicalVariables();
         const HashSet<UniquedStringImpl*>& closedVariableCandidates = scope->closedVariableCandidates();
-        const BuiltinNames& builtinNames = m_vm->propertyNames->builtinNames();
         for (UniquedStringImpl* candidate : closedVariableCandidates) {
-            if (!lexicalVariables.contains(candidate) && !varDeclarations.contains(candidate) && !builtinNames.isPrivateName(*candidate)) {
+            if (!lexicalVariables.contains(candidate) && !varDeclarations.contains(candidate) && !candidate->isSymbol()) {
                 dataLog("Bad global capture in builtin: '", candidate, "'\n");
                 dataLog(m_source->view());
                 CRASH();
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to