Title: [252825] trunk/Source/_javascript_Core
Revision
252825
Author
[email protected]
Date
2019-11-22 20:45:14 -0800 (Fri, 22 Nov 2019)

Log Message

Use LLInt profiling to rule out generating an IC for get_by_val
https://bugs.webkit.org/show_bug.cgi?id=204536

Reviewed by Yusuke Suzuki.

When I landed the get_by_val polymorphic inline caching patch, the prepack
benchmark in JetStream2 slowed down by 10%. Through some analysis, I found
out that we were slowing down because of the time we spent in the JITs
actually generating inline caches. This patch skips generating an inline
cache when it seems like it won't be profitable. The heuristic for doing this
is simple:
- If we see more than 4 identifiers in the LLInt, we won't generate an IC
in the upper tiers.
- If we see a non-identifier JSString in the LLInt, we won't generate an IC
in the upper tiers.

This patch recovers the regression on prepack.

* bytecode/BytecodeList.rb:
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::parseBlock):
* dfg/DFGOperations.cpp:
* dfg/DFGOperations.h:
* generator/main.rb:
* heap/TinyBloomFilter.h:
(JSC::TinyBloomFilter::bits const):
(JSC::TinyBloomFilter::TinyBloomFilter):
* jit/JIT.h:
* jit/JITOperations.cpp:
* jit/JITOperations.h:
* jit/JITPropertyAccess.cpp:
(JSC::JIT::emit_op_get_by_val):
(JSC::JIT::emitSlow_op_get_by_val):
* llint/LLIntSlowPaths.cpp:
(JSC::LLInt::LLINT_SLOW_PATH_DECL):
* runtime/Operations.h:
(JSC::getByValWithIndex):
* runtime/OptionsList.h:

Modified Paths

Added Paths

Diff

Modified: trunk/Source/_javascript_Core/ChangeLog (252824 => 252825)


--- trunk/Source/_javascript_Core/ChangeLog	2019-11-23 04:28:46 UTC (rev 252824)
+++ trunk/Source/_javascript_Core/ChangeLog	2019-11-23 04:45:14 UTC (rev 252825)
@@ -1,3 +1,44 @@
+2019-11-22  Saam Barati  <[email protected]>
+
+        Use LLInt profiling to rule out generating an IC for get_by_val
+        https://bugs.webkit.org/show_bug.cgi?id=204536
+
+        Reviewed by Yusuke Suzuki.
+
+        When I landed the get_by_val polymorphic inline caching patch, the prepack
+        benchmark in JetStream2 slowed down by 10%. Through some analysis, I found
+        out that we were slowing down because of the time we spent in the JITs
+        actually generating inline caches. This patch skips generating an inline
+        cache when it seems like it won't be profitable. The heuristic for doing this
+        is simple:
+        - If we see more than 4 identifiers in the LLInt, we won't generate an IC
+        in the upper tiers.
+        - If we see a non-identifier JSString in the LLInt, we won't generate an IC
+        in the upper tiers.
+        
+        This patch recovers the regression on prepack.
+
+        * bytecode/BytecodeList.rb:
+        * dfg/DFGByteCodeParser.cpp:
+        (JSC::DFG::ByteCodeParser::parseBlock):
+        * dfg/DFGOperations.cpp:
+        * dfg/DFGOperations.h:
+        * generator/main.rb:
+        * heap/TinyBloomFilter.h:
+        (JSC::TinyBloomFilter::bits const):
+        (JSC::TinyBloomFilter::TinyBloomFilter):
+        * jit/JIT.h:
+        * jit/JITOperations.cpp:
+        * jit/JITOperations.h:
+        * jit/JITPropertyAccess.cpp:
+        (JSC::JIT::emit_op_get_by_val):
+        (JSC::JIT::emitSlow_op_get_by_val):
+        * llint/LLIntSlowPaths.cpp:
+        (JSC::LLInt::LLINT_SLOW_PATH_DECL):
+        * runtime/Operations.h:
+        (JSC::getByValWithIndex):
+        * runtime/OptionsList.h:
+
 2019-11-22  Per Arne Vollan  <[email protected]>
 
         Fix compile error in release mode

Modified: trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj (252824 => 252825)


--- trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj	2019-11-23 04:28:46 UTC (rev 252824)
+++ trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj	2019-11-23 04:45:14 UTC (rev 252825)
@@ -890,6 +890,7 @@
 		451539B912DC994500EF7AC4 /* Yarr.h in Headers */ = {isa = PBXBuildFile; fileRef = 451539B812DC994500EF7AC4 /* Yarr.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		473DA4A4764C45FE871B0485 /* DefinePropertyAttributes.h in Headers */ = {isa = PBXBuildFile; fileRef = 169948EDE68D4054B01EF797 /* DefinePropertyAttributes.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		4BAA07CEB81F49A296E02203 /* WasmSignatureInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = 30A5F403F11C4F599CD596D5 /* WasmSignatureInlines.h */; settings = {ATTRIBUTES = (Private, ); }; };
+		520D99F12388CC81000509A3 /* GetByValHistory.h in Headers */ = {isa = PBXBuildFile; fileRef = 520D99F02388CC78000509A3 /* GetByValHistory.h */; };
 		521131F71F82BF14007CCEEE /* PolyProtoAccessChain.h in Headers */ = {isa = PBXBuildFile; fileRef = 521131F61F82BF11007CCEEE /* PolyProtoAccessChain.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		521322461ECBCE8200F65615 /* WebAssemblyFunctionBase.h in Headers */ = {isa = PBXBuildFile; fileRef = 521322441ECBCE8200F65615 /* WebAssemblyFunctionBase.h */; };
 		522927D5235FD0B9005CB169 /* GCMemoryOperations.h in Headers */ = {isa = PBXBuildFile; fileRef = 5272987B235FC8BA005C982C /* GCMemoryOperations.h */; settings = {ATTRIBUTES = (Private, ); }; };
@@ -3534,6 +3535,7 @@
 		4CE978E385A8498199052153 /* ModuleNamespaceAccessCase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ModuleNamespaceAccessCase.h; sourceTree = "<group>"; };
 		51F0EB6105C86C6B00E6DF1B /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = "<absolute>"; };
 		51F0EC0705C86C9A00E6DF1B /* libobjc.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libobjc.dylib; path = /usr/lib/libobjc.dylib; sourceTree = "<absolute>"; };
+		520D99F02388CC78000509A3 /* GetByValHistory.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GetByValHistory.h; sourceTree = "<group>"; };
 		521131F51F82BF11007CCEEE /* PolyProtoAccessChain.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = PolyProtoAccessChain.cpp; sourceTree = "<group>"; };
 		521131F61F82BF11007CCEEE /* PolyProtoAccessChain.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PolyProtoAccessChain.h; sourceTree = "<group>"; };
 		521322431ECBCE8200F65615 /* WebAssemblyFunctionBase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = WebAssemblyFunctionBase.cpp; path = js/WebAssemblyFunctionBase.cpp; sourceTree = "<group>"; };
@@ -8215,6 +8217,7 @@
 				0F93329614CA7DC10085F3C6 /* GetByStatus.h */,
 				0F0332C118B01763005F979A /* GetByIdVariant.cpp */,
 				0F0332C218B01763005F979A /* GetByIdVariant.h */,
+				520D99F02388CC78000509A3 /* GetByValHistory.h */,
 				14AD91081DCA92940014F9FE /* GlobalCodeBlock.h */,
 				0F0B83A814BCF55E00885B4F /* HandlerInfo.h */,
 				0F44A7AB20BF685E0022B171 /* ICStatusMap.cpp */,
@@ -9053,6 +9056,7 @@
 				65B8392E1BACAD360044E824 /* CachedRecovery.h in Headers */,
 				14F09C2A2231923100CF88EB /* CachedTypes.h in Headers */,
 				1409ECC1225E178C00BEDD54 /* CachePayload.h in Headers */,
+				520D99F12388CC81000509A3 /* GetByValHistory.h in Headers */,
 				1409ECC0225E178100BEDD54 /* CacheUpdate.h in Headers */,
 				0FEC3C601F379F5300F59B6C /* CagedBarrierPtr.h in Headers */,
 				BC18C3ED0E16F5CD00B34460 /* CallData.h in Headers */,

Modified: trunk/Source/_javascript_Core/bytecode/BytecodeList.rb (252824 => 252825)


--- trunk/Source/_javascript_Core/bytecode/BytecodeList.rb	2019-11-23 04:28:46 UTC (rev 252824)
+++ trunk/Source/_javascript_Core/bytecode/BytecodeList.rb	2019-11-23 04:45:14 UTC (rev 252825)
@@ -30,6 +30,7 @@
     :ErrorType,
     :GetByIdMode,
     :GetByIdModeMetadata,
+    :GetByValHistory,
     :GetPutInfo,
     :IndexingType,
     :JSCell,
@@ -534,6 +535,7 @@
     metadata: {
         profile: ValueProfile,
         arrayProfile: ArrayProfile,
+        seenIdentifiers: GetByValHistory,
     }
 
 op :put_by_val,

Added: trunk/Source/_javascript_Core/bytecode/GetByValHistory.h (0 => 252825)


--- trunk/Source/_javascript_Core/bytecode/GetByValHistory.h	                        (rev 0)
+++ trunk/Source/_javascript_Core/bytecode/GetByValHistory.h	2019-11-23 04:45:14 UTC (rev 252825)
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2019 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include "TinyBloomFilter.h"
+#include <wtf/text/UniquedStringImpl.h>
+
+namespace JSC {
+
+struct GetByValHistory {
+    void observeNonUID()
+    {
+        uint64_t count = Options::getByValICMaxNumberOfIdentifiers() + 1;
+        update(count, filter());
+    }
+
+    void observe(const UniquedStringImpl* impl)
+    {
+        if (!impl) {
+            observeNonUID();
+            return;
+        }
+
+        uint64_t count = this->count();
+        uint64_t filter = this->filter();
+
+        TinyBloomFilter bloomFilter(filter);
+        uint64_t implBits = static_cast<uint64_t>(bitwise_cast<uintptr_t>(impl));
+        ASSERT(((implBits << 8) >> 8) == implBits);
+        if (bloomFilter.ruleOut(implBits)) {
+            bloomFilter.add(implBits);
+            ++count;
+        }
+
+        update(count, bloomFilter.bits());
+    }
+
+    uint64_t count() const { return m_payload >> 56; }
+
+private:
+    uint64_t filter() const { return (m_payload << 8) >> 8; }
+
+    void update(uint64_t count, uint64_t filter)
+    {
+        ASSERT(((filter << 8) >> 8) == filter);
+        m_payload = (count << 56) | filter;
+    }
+
+    uint64_t m_payload { 0 };
+};
+
+} // namespace JSC

Modified: trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp (252824 => 252825)


--- trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp	2019-11-23 04:28:46 UTC (rev 252824)
+++ trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp	2019-11-23 04:45:14 UTC (rev 252825)
@@ -5627,21 +5627,18 @@
             bool shouldCompileAsGetById = false;
             GetByStatus getByStatus = GetByStatus::computeFor(m_inlineStackTop->m_profiledBlock, m_inlineStackTop->m_baselineMap, m_icContextStack, currentCodeOrigin(), GetByStatus::TrackIdentifiers::Yes);
             unsigned identifierNumber = 0;
-            {
-                // FIXME: When the bytecode is not compiled in the baseline JIT, byValInfo becomes null.
-                // At that time, there is no information.
-                if (!m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadIdent)
-                    && !m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadType)
-                    && !m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadCell)) {
 
-                    // FIXME: In the future, we should be able to do something like MultiGetByOffset in a multi identifier mode.
-                    // That way, we could both switch on multiple structures and multiple identifiers (or int 32 properties).
-                    // https://bugs.webkit.org/show_bug.cgi?id=204216
-                    if (Box<Identifier> impl = getByStatus.singleIdentifier()) {
-                        identifierNumber = m_graph.identifiers().ensure(impl);
-                        shouldCompileAsGetById = true;
-                        addToGraph(CheckIdent, OpInfo(impl->impl()), property);
-                    }
+            if (!m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadIdent)
+                && !m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadType)
+                && !m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadCell)) {
+
+                // FIXME: In the future, we should be able to do something like MultiGetByOffset in a multi identifier mode.
+                // That way, we could both switch on multiple structures and multiple identifiers (or int 32 properties).
+                // https://bugs.webkit.org/show_bug.cgi?id=204216
+                if (Box<Identifier> impl = getByStatus.singleIdentifier()) {
+                    identifierNumber = m_graph.identifiers().ensure(impl);
+                    shouldCompileAsGetById = true;
+                    addToGraph(CheckIdent, OpInfo(impl->impl()), property);
                 }
             }
 
@@ -5658,7 +5655,7 @@
                 Node* getByVal = addToGraph(Node::VarArg, GetByVal, OpInfo(arrayMode.asWord()), OpInfo(prediction));
                 m_exitOK = false; // GetByVal must be treated as if it clobbers exit state, since FixupPhase may make it generic.
                 set(bytecode.m_dst, getByVal);
-                if (getByStatus.observedStructureStubInfoSlowPath())
+                if (getByStatus.observedStructureStubInfoSlowPath() || bytecode.metadata(codeBlock).m_seenIdentifiers.count() > Options::getByValICMaxNumberOfIdentifiers())
                     m_graph.m_slowGetByVal.add(getByVal);
             }
 

Modified: trunk/Source/_javascript_Core/dfg/DFGOperations.cpp (252824 => 252825)


--- trunk/Source/_javascript_Core/dfg/DFGOperations.cpp	2019-11-23 04:28:46 UTC (rev 252824)
+++ trunk/Source/_javascript_Core/dfg/DFGOperations.cpp	2019-11-23 04:45:14 UTC (rev 252825)
@@ -804,62 +804,6 @@
     return JSValue::encode(jsNumber(truncatedValueOfArgument));
 }
 
-static ALWAYS_INLINE EncodedJSValue getByVal(JSGlobalObject* globalObject, JSCell* base, uint32_t index)
-{
-    if (base->isObject()) {
-        JSObject* object = asObject(base);
-        if (object->canGetIndexQuickly(index))
-            return JSValue::encode(object->getIndexQuickly(index));
-    }
-
-    if (isJSString(base) && asString(base)->canGetIndex(index))
-        return JSValue::encode(asString(base)->getIndex(globalObject, index));
-
-    return JSValue::encode(JSValue(base).get(globalObject, index));
-}
-
-EncodedJSValue JIT_OPERATION operationGetByVal(JSGlobalObject* globalObject, EncodedJSValue encodedBase, EncodedJSValue encodedProperty)
-{
-    VM& vm = globalObject->vm();
-    CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
-    JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
-    auto scope = DECLARE_THROW_SCOPE(vm);
-
-    JSValue baseValue = JSValue::decode(encodedBase);
-    JSValue property = JSValue::decode(encodedProperty);
-
-    if (LIKELY(baseValue.isCell())) {
-        JSCell* base = baseValue.asCell();
-
-        if (property.isUInt32())
-            RELEASE_AND_RETURN(scope, getByVal(globalObject, base, property.asUInt32()));
-
-        if (property.isDouble()) {
-            double propertyAsDouble = property.asDouble();
-            uint32_t propertyAsUInt32 = static_cast<uint32_t>(propertyAsDouble);
-            if (propertyAsUInt32 == propertyAsDouble && isIndex(propertyAsUInt32))
-                RELEASE_AND_RETURN(scope, getByVal(globalObject, base, propertyAsUInt32));
-
-        } else if (property.isString()) {
-            Structure& structure = *base->structure(vm);
-            if (JSCell::canUseFastGetOwnProperty(structure)) {
-                RefPtr<AtomStringImpl> existingAtomString = asString(property)->toExistingAtomString(globalObject);
-                RETURN_IF_EXCEPTION(scope, encodedJSValue());
-                if (existingAtomString) {
-                    if (JSValue result = base->fastGetOwnProperty(vm, structure, existingAtomString.get()))
-                        return JSValue::encode(result);
-                }
-            }
-        }
-    }
-
-    baseValue.requireObjectCoercible(globalObject);
-    RETURN_IF_EXCEPTION(scope, encodedJSValue());
-    auto propertyName = property.toPropertyKey(globalObject);
-    RETURN_IF_EXCEPTION(scope, encodedJSValue());
-    RELEASE_AND_RETURN(scope, JSValue::encode(baseValue.get(globalObject, propertyName)));
-}
-
 EncodedJSValue JIT_OPERATION operationGetByValCell(JSGlobalObject* globalObject, JSCell* base, EncodedJSValue encodedProperty)
 {
     VM& vm = globalObject->vm();
@@ -870,13 +814,13 @@
     JSValue property = JSValue::decode(encodedProperty);
 
     if (property.isUInt32())
-        RELEASE_AND_RETURN(scope, getByVal(globalObject, base, property.asUInt32()));
+        RELEASE_AND_RETURN(scope, getByValWithIndex(globalObject, base, property.asUInt32()));
 
     if (property.isDouble()) {
         double propertyAsDouble = property.asDouble();
         uint32_t propertyAsUInt32 = static_cast<uint32_t>(propertyAsDouble);
         if (propertyAsUInt32 == propertyAsDouble)
-            RELEASE_AND_RETURN(scope, getByVal(globalObject, base, propertyAsUInt32));
+            RELEASE_AND_RETURN(scope, getByValWithIndex(globalObject, base, propertyAsUInt32));
 
     } else if (property.isString()) {
         Structure& structure = *base->structure(vm);

Modified: trunk/Source/_javascript_Core/dfg/DFGOperations.h (252824 => 252825)


--- trunk/Source/_javascript_Core/dfg/DFGOperations.h	2019-11-23 04:28:46 UTC (rev 252824)
+++ trunk/Source/_javascript_Core/dfg/DFGOperations.h	2019-11-23 04:45:14 UTC (rev 252825)
@@ -85,7 +85,6 @@
 EncodedJSValue JIT_OPERATION operationArithFloor(JSGlobalObject*, EncodedJSValue) WTF_INTERNAL;
 EncodedJSValue JIT_OPERATION operationArithCeil(JSGlobalObject*, EncodedJSValue) WTF_INTERNAL;
 EncodedJSValue JIT_OPERATION operationArithTrunc(JSGlobalObject*, EncodedJSValue) WTF_INTERNAL;
-EncodedJSValue JIT_OPERATION operationGetByVal(JSGlobalObject*, EncodedJSValue encodedBase, EncodedJSValue encodedProperty) WTF_INTERNAL;
 EncodedJSValue JIT_OPERATION operationGetByValCell(JSGlobalObject*, JSCell*, EncodedJSValue encodedProperty) WTF_INTERNAL;
 EncodedJSValue JIT_OPERATION operationGetByValObjectInt(JSGlobalObject*, JSObject*, int32_t) WTF_INTERNAL;
 EncodedJSValue JIT_OPERATION operationGetByValStringInt(JSGlobalObject*, JSString*, int32_t) WTF_INTERNAL;

Modified: trunk/Source/_javascript_Core/generator/DSL.rb (252824 => 252825)


--- trunk/Source/_javascript_Core/generator/DSL.rb	2019-11-23 04:28:46 UTC (rev 252824)
+++ trunk/Source/_javascript_Core/generator/DSL.rb	2019-11-23 04:45:14 UTC (rev 252825)
@@ -136,6 +136,7 @@
 #include "BytecodeDumper.h"
 #include "Fits.h"
 #include "GetByIdMetadata.h"
+#include "GetByValHistory.h"
 #include "Instruction.h"
 #include "Opcode.h"
 #include "PutByIdStatus.h"

Modified: trunk/Source/_javascript_Core/heap/TinyBloomFilter.h (252824 => 252825)


--- trunk/Source/_javascript_Core/heap/TinyBloomFilter.h	2019-11-23 04:28:46 UTC (rev 252824)
+++ trunk/Source/_javascript_Core/heap/TinyBloomFilter.h	2019-11-23 04:45:14 UTC (rev 252825)
@@ -31,19 +31,21 @@
 
 class TinyBloomFilter {
 public:
-    TinyBloomFilter();
+    TinyBloomFilter() = default;
+    TinyBloomFilter(Bits);
 
     void add(Bits);
     void add(TinyBloomFilter&);
     bool ruleOut(Bits) const; // True for 0.
     void reset();
+    Bits bits() const { return m_bits; }
 
 private:
-    Bits m_bits;
+    Bits m_bits { 0 };
 };
 
-inline TinyBloomFilter::TinyBloomFilter()
-    : m_bits(0)
+inline TinyBloomFilter::TinyBloomFilter(Bits bits)
+    : m_bits(bits)
 {
 }
 

Modified: trunk/Source/_javascript_Core/jit/JIT.h (252824 => 252825)


--- trunk/Source/_javascript_Core/jit/JIT.h	2019-11-23 04:28:46 UTC (rev 252824)
+++ trunk/Source/_javascript_Core/jit/JIT.h	2019-11-23 04:45:14 UTC (rev 252825)
@@ -739,6 +739,12 @@
             linkAllSlowCasesForBytecodeIndex(m_slowCases, iter, m_bytecodeIndex);
         }
 
+        bool hasAnySlowCases(Vector<SlowCaseEntry>& slowCases, Vector<SlowCaseEntry>::iterator&, BytecodeIndex bytecodeOffset);
+        bool hasAnySlowCases(Vector<SlowCaseEntry>::iterator& iter)
+        {
+            return hasAnySlowCases(m_slowCases, iter, m_bytecodeIndex);
+        }
+
         MacroAssembler::Call appendCallWithExceptionCheck(const FunctionPtr<CFunctionPtrTag>);
 #if OS(WINDOWS) && CPU(X86_64)
         MacroAssembler::Call appendCallWithExceptionCheckAndSlowPathReturnType(const FunctionPtr<CFunctionPtrTag>);

Modified: trunk/Source/_javascript_Core/jit/JITInlines.h (252824 => 252825)


--- trunk/Source/_javascript_Core/jit/JITInlines.h	2019-11-23 04:28:46 UTC (rev 252824)
+++ trunk/Source/_javascript_Core/jit/JITInlines.h	2019-11-23 04:45:14 UTC (rev 252825)
@@ -179,6 +179,13 @@
         linkSlowCase(iter);
 }
 
+ALWAYS_INLINE bool JIT::hasAnySlowCases(Vector<SlowCaseEntry>& slowCases, Vector<SlowCaseEntry>::iterator& iter, BytecodeIndex bytecodeIndex)
+{
+    if (iter != slowCases.end() && iter->to == bytecodeIndex)
+        return true;
+    return false;
+}
+
 ALWAYS_INLINE void JIT::addSlowCase(Jump jump)
 {
     ASSERT(m_bytecodeIndex); // This method should only be called during hot/cold path generation, so that m_bytecodeIndex is set.

Modified: trunk/Source/_javascript_Core/jit/JITOperations.cpp (252824 => 252825)


--- trunk/Source/_javascript_Core/jit/JITOperations.cpp	2019-11-23 04:28:46 UTC (rev 252824)
+++ trunk/Source/_javascript_Core/jit/JITOperations.cpp	2019-11-23 04:45:14 UTC (rev 252825)
@@ -2046,6 +2046,48 @@
     RELEASE_AND_RETURN(scope, JSValue::encode(getByVal(globalObject, callFrame, profile, baseValue, subscript)));
 }
 
+EncodedJSValue JIT_OPERATION operationGetByVal(JSGlobalObject* globalObject, EncodedJSValue encodedBase, EncodedJSValue encodedProperty)
+{
+    VM& vm = globalObject->vm();
+    CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
+    JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
+    auto scope = DECLARE_THROW_SCOPE(vm);
+
+    JSValue baseValue = JSValue::decode(encodedBase);
+    JSValue property = JSValue::decode(encodedProperty);
+
+    if (LIKELY(baseValue.isCell())) {
+        JSCell* base = baseValue.asCell();
+
+        if (property.isUInt32())
+            RELEASE_AND_RETURN(scope, getByValWithIndex(globalObject, base, property.asUInt32()));
+
+        if (property.isDouble()) {
+            double propertyAsDouble = property.asDouble();
+            uint32_t propertyAsUInt32 = static_cast<uint32_t>(propertyAsDouble);
+            if (propertyAsUInt32 == propertyAsDouble && isIndex(propertyAsUInt32))
+                RELEASE_AND_RETURN(scope, getByValWithIndex(globalObject, base, propertyAsUInt32));
+        } else if (property.isString()) {
+            Structure& structure = *base->structure(vm);
+            if (JSCell::canUseFastGetOwnProperty(structure)) {
+                RefPtr<AtomStringImpl> existingAtomString = asString(property)->toExistingAtomString(globalObject);
+                RETURN_IF_EXCEPTION(scope, encodedJSValue());
+                if (existingAtomString) {
+                    if (JSValue result = base->fastGetOwnProperty(vm, structure, existingAtomString.get()))
+                        return JSValue::encode(result);
+                }
+            }
+        }
+    }
+
+    baseValue.requireObjectCoercible(globalObject);
+    RETURN_IF_EXCEPTION(scope, encodedJSValue());
+    auto propertyName = property.toPropertyKey(globalObject);
+    RETURN_IF_EXCEPTION(scope, encodedJSValue());
+    RELEASE_AND_RETURN(scope, JSValue::encode(baseValue.get(globalObject, propertyName)));
+}
+
+
 EncodedJSValue JIT_OPERATION operationHasIndexedPropertyDefault(JSGlobalObject* globalObject, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript, ByValInfo* byValInfo)
 {
     VM& vm = globalObject->vm();

Modified: trunk/Source/_javascript_Core/jit/JITOperations.h (252824 => 252825)


--- trunk/Source/_javascript_Core/jit/JITOperations.h	2019-11-23 04:28:46 UTC (rev 252824)
+++ trunk/Source/_javascript_Core/jit/JITOperations.h	2019-11-23 04:45:14 UTC (rev 252825)
@@ -248,6 +248,7 @@
 
 EncodedJSValue JIT_OPERATION operationGetByValOptimize(JSGlobalObject*, StructureStubInfo*, ArrayProfile*, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript) WTF_INTERNAL;
 EncodedJSValue JIT_OPERATION operationGetByValGeneric(JSGlobalObject*, StructureStubInfo*, ArrayProfile*, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript) WTF_INTERNAL;
+EncodedJSValue JIT_OPERATION operationGetByVal(JSGlobalObject*, EncodedJSValue encodedBase, EncodedJSValue encodedProperty) WTF_INTERNAL;
 EncodedJSValue JIT_OPERATION operationHasIndexedPropertyDefault(JSGlobalObject*, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript, ByValInfo*) WTF_INTERNAL;
 EncodedJSValue JIT_OPERATION operationHasIndexedPropertyGeneric(JSGlobalObject*, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript, ByValInfo*) WTF_INTERNAL;
 EncodedJSValue JIT_OPERATION operationDeleteByIdJSResult(JSGlobalObject*, EncodedJSValue base, UniquedStringImpl*) WTF_INTERNAL;

Modified: trunk/Source/_javascript_Core/jit/JITPropertyAccess.cpp (252824 => 252825)


--- trunk/Source/_javascript_Core/jit/JITPropertyAccess.cpp	2019-11-23 04:28:46 UTC (rev 252824)
+++ trunk/Source/_javascript_Core/jit/JITPropertyAccess.cpp	2019-11-23 04:45:14 UTC (rev 252825)
@@ -64,37 +64,47 @@
 
     emitGetVirtualRegister(base, regT0);
     emitGetVirtualRegister(property, regT1);
-    emitJumpSlowCaseIfNotJSCell(regT0, base);
-    emitArrayProfilingSiteWithCell(regT0, regT2, profile);
 
-    JITGetByValGenerator gen(
-        m_codeBlock, CodeOrigin(m_bytecodeIndex), CallSiteIndex(m_bytecodeIndex), RegisterSet::stubUnavailableRegisters(),
-        JSValueRegs(regT0), JSValueRegs(regT1), JSValueRegs(regT0));
-    if (isOperandConstantInt(property))
-        gen.stubInfo()->propertyIsInt32 = true;
-    gen.generateFastPath(*this);
-    addSlowCase(gen.slowPathJump());
-    m_getByVals.append(gen);
+    if (metadata.m_seenIdentifiers.count() > Options::getByValICMaxNumberOfIdentifiers()) {
+        auto notCell = branchIfNotCell(regT0);
+        emitArrayProfilingSiteWithCell(regT0, regT2, profile);
+        notCell.link(this);
+        callOperationWithProfile(bytecode.metadata(m_codeBlock), operationGetByVal, dst, TrustedImmPtr(m_codeBlock->globalObject()), regT0, regT1);
+    } else {
+        emitJumpSlowCaseIfNotJSCell(regT0, base);
+        emitArrayProfilingSiteWithCell(regT0, regT2, profile);
 
-    emitValueProfilingSite(bytecode.metadata(m_codeBlock));
-    emitPutVirtualRegister(dst);
+        JITGetByValGenerator gen(
+            m_codeBlock, CodeOrigin(m_bytecodeIndex), CallSiteIndex(m_bytecodeIndex), RegisterSet::stubUnavailableRegisters(),
+            JSValueRegs(regT0), JSValueRegs(regT1), JSValueRegs(regT0));
+        if (isOperandConstantInt(property))
+            gen.stubInfo()->propertyIsInt32 = true;
+        gen.generateFastPath(*this);
+        addSlowCase(gen.slowPathJump());
+        m_getByVals.append(gen);
+
+        emitValueProfilingSite(bytecode.metadata(m_codeBlock));
+        emitPutVirtualRegister(dst);
+    }
+
 }
 
 void JIT::emitSlow_op_get_by_val(const Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
 {
-    auto bytecode = currentInstruction->as<OpGetByVal>();
-    int dst = bytecode.m_dst.offset();
-    auto& metadata = bytecode.metadata(m_codeBlock);
-    ArrayProfile* profile = ""
+    if (hasAnySlowCases(iter)) {
+        auto bytecode = currentInstruction->as<OpGetByVal>();
+        int dst = bytecode.m_dst.offset();
+        auto& metadata = bytecode.metadata(m_codeBlock);
+        ArrayProfile* profile = ""
 
-    JITGetByValGenerator& gen = m_getByVals[m_getByValIndex];
-    ++m_getByValIndex;
+        linkAllSlowCases(iter);
 
-    linkAllSlowCases(iter);
-
-    Label coldPathBegin = label();
-    Call call = callOperationWithProfile(bytecode.metadata(m_codeBlock), operationGetByValOptimize, dst, TrustedImmPtr(m_codeBlock->globalObject()), gen.stubInfo(), profile, regT0, regT1);
-    gen.reportSlowPathCall(coldPathBegin, call);
+        JITGetByValGenerator& gen = m_getByVals[m_getByValIndex];
+        ++m_getByValIndex;
+        Label coldPathBegin = label();
+        Call call = callOperationWithProfile(bytecode.metadata(m_codeBlock), operationGetByValOptimize, dst, TrustedImmPtr(m_codeBlock->globalObject()), gen.stubInfo(), profile, regT0, regT1);
+        gen.reportSlowPathCall(coldPathBegin, call);
+    }
 }
 
 void JIT::emit_op_put_by_val_direct(const Instruction* currentInstruction)

Modified: trunk/Source/_javascript_Core/llint/LLIntSlowPaths.cpp (252824 => 252825)


--- trunk/Source/_javascript_Core/llint/LLIntSlowPaths.cpp	2019-11-23 04:28:46 UTC (rev 252824)
+++ trunk/Source/_javascript_Core/llint/LLIntSlowPaths.cpp	2019-11-23 04:45:14 UTC (rev 252825)
@@ -989,6 +989,25 @@
     auto bytecode = pc->as<OpGetByVal>();
     JSValue baseValue = getOperand(callFrame, bytecode.m_base);
     JSValue subscript = getOperand(callFrame, bytecode.m_property);
+
+    if (subscript.isString() || subscript.isSymbol()) {
+        auto& metadata = bytecode.metadata(codeBlock);
+        if (metadata.m_seenIdentifiers.count() <= Options::getByValICMaxNumberOfIdentifiers()) {
+            const UniquedStringImpl* impl = nullptr;
+            if (subscript.isSymbol())
+                impl = &jsCast<Symbol*>(subscript)->privateName().uid();
+            else {
+                JSString* string = asString(subscript);
+                if (auto* maybeUID = string->tryGetValueImpl()) {
+                    if (maybeUID->isAtom())
+                        impl = static_cast<const UniquedStringImpl*>(maybeUID);
+                }
+            }
+
+            metadata.m_seenIdentifiers.observe(impl);
+        }
+    }
+    
     LLINT_RETURN_PROFILED(getByVal(vm, globalObject, codeBlock, baseValue, subscript, bytecode));
 }
 

Modified: trunk/Source/_javascript_Core/runtime/Operations.h (252824 => 252825)


--- trunk/Source/_javascript_Core/runtime/Operations.h	2019-11-23 04:28:46 UTC (rev 252824)
+++ trunk/Source/_javascript_Core/runtime/Operations.h	2019-11-23 04:45:14 UTC (rev 252825)
@@ -519,4 +519,18 @@
     }
 }
 
+ALWAYS_INLINE EncodedJSValue getByValWithIndex(JSGlobalObject* globalObject, JSCell* base, uint32_t index)
+{
+    if (base->isObject()) {
+        JSObject* object = asObject(base);
+        if (object->canGetIndexQuickly(index))
+            return JSValue::encode(object->getIndexQuickly(index));
+    }
+
+    if (isJSString(base) && asString(base)->canGetIndex(index))
+        return JSValue::encode(asString(base)->getIndex(globalObject, index));
+
+    return JSValue::encode(JSValue(base).get(globalObject, index));
+}
+
 } // namespace JSC

Modified: trunk/Source/_javascript_Core/runtime/OptionsList.h (252824 => 252825)


--- trunk/Source/_javascript_Core/runtime/OptionsList.h	2019-11-23 04:28:46 UTC (rev 252824)
+++ trunk/Source/_javascript_Core/runtime/OptionsList.h	2019-11-23 04:45:14 UTC (rev 252825)
@@ -489,6 +489,7 @@
     v(Double, dumpJITMemoryFlushInterval, 10, Restricted, "Maximum time in between flushes of the JIT memory dump in seconds.") \
     v(Bool, useUnlinkedCodeBlockJettisoning, false, Normal, "If true, UnlinkedCodeBlock can be jettisoned.") \
     v(Bool, forceOSRExitToLLInt, false, Normal, "If true, we always exit to the LLInt. If false, we exit to whatever is most convenient.") \
+    v(Unsigned, getByValICMaxNumberOfIdentifiers, 4, Normal, "Number of identifiers we see in the LLInt that could cause us to bail on generating an IC for get_by_val.") \
 
 enum OptionEquivalence {
     SameOption,
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to