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,