https://bugs.webkit.org/show_bug.cgi?id=176010
Reviewed by Filip Pizlo.
JSTests:
* microbenchmarks/weak-map-key.js: Added.
(assert):
(objectKey):
(let.start.Date.now):
Source/JavaScriptCore:
It reveals that Ember.js consumes 3.8% of execution time for WeakMap#get.
It is used for meta property for objects (see peekMeta function in Ember.js).
This patch optimizes WeakMap#get.
1. We use inlineGet to inline WeakMap#get operation in the native function.
Since this native function itself is very small, we should inline HashMap#get
entirely in this function.
2. We add JSWeakMapType and JSWeakSetType. This allows us to perform `isJSWeakMap()`
very fast. And this patch wires this to DFG and FTL to add WeakMapObjectUse and WeakSetObjectUse
to drop unnecessary type checking. We add fixup rules for WeakMapGet DFG node by using WeakMapObjectUse,
ObjectUse, and Int32Use.
3. We add intrinsic for WeakMap#get, and handle it in DFG and FTL. We use MapHash to
calculate hash value for the key's Object and use this hash value to look up value from
JSWeakMap's HashMap. Currently, we just call the operationWeakMapGet function in DFG and FTL.
It is worth considering that implementing this operation entirely in JIT, like GetMapBucket.
But anyway, the current one already optimizes the performance, so we leave this for the subsequent
patches.
We currently do not implement any other intrinsics (like, WeakMap#has, WeakSet) because they are
not used in Ember.js right now.
This patch optimizes WeakMap#get by 50%.
baseline patched
weak-map-key 88.6456+-3.9564 ^ 59.1502+-2.2406 ^ definitely 1.4987x faster
* bytecode/DirectEvalCodeCache.h:
(JSC::DirectEvalCodeCache::tryGet):
* bytecode/SpeculatedType.cpp:
(JSC::dumpSpeculation):
(JSC::speculationFromClassInfo):
(JSC::speculationFromJSType):
(JSC::speculationFromString):
* bytecode/SpeculatedType.h:
* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::handleIntrinsicCall):
* dfg/DFGClobberize.h:
(JSC::DFG::clobberize):
* dfg/DFGDoesGC.cpp:
(JSC::DFG::doesGC):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
* dfg/DFGHeapLocation.cpp:
(WTF::printInternal):
* dfg/DFGHeapLocation.h:
* dfg/DFGNode.h:
(JSC::DFG::Node::hasHeapPrediction):
* dfg/DFGNodeType.h:
* dfg/DFGOperations.cpp:
* dfg/DFGOperations.h:
* dfg/DFGPredictionPropagationPhase.cpp:
* dfg/DFGSafeToExecute.h:
(JSC::DFG::SafeToExecuteEdge::operator()):
(JSC::DFG::safeToExecute):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::speculateWeakMapObject):
(JSC::DFG::SpeculativeJIT::speculateWeakSetObject):
(JSC::DFG::SpeculativeJIT::speculate):
(JSC::DFG::SpeculativeJIT::compileWeakMapGet):
* dfg/DFGSpeculativeJIT.h:
(JSC::DFG::SpeculativeJIT::callOperation):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGUseKind.cpp:
(WTF::printInternal):
* dfg/DFGUseKind.h:
(JSC::DFG::typeFilterFor):
(JSC::DFG::isCell):
* ftl/FTLCapabilities.cpp:
(JSC::FTL::canCompile):
* ftl/FTLLowerDFGToB3.cpp:
(JSC::FTL::DFG::LowerDFGToB3::compileNode):
(JSC::FTL::DFG::LowerDFGToB3::compileWeakMapGet):
(JSC::FTL::DFG::LowerDFGToB3::lowWeakMapObject):
(JSC::FTL::DFG::LowerDFGToB3::lowWeakSetObject):
(JSC::FTL::DFG::LowerDFGToB3::speculate):
(JSC::FTL::DFG::LowerDFGToB3::speculateWeakMapObject):
(JSC::FTL::DFG::LowerDFGToB3::speculateWeakSetObject):
* jit/JITOperations.h:
* runtime/Intrinsic.cpp:
(JSC::intrinsicName):
* runtime/Intrinsic.h:
* runtime/JSType.h:
* runtime/JSWeakMap.h:
(JSC::isJSWeakMap):
* runtime/JSWeakSet.h:
(JSC::isJSWeakSet):
* runtime/WeakMapBase.cpp:
(JSC::WeakMapBase::get):
* runtime/WeakMapBase.h:
(JSC::WeakMapBase::HashTranslator::hash):
(JSC::WeakMapBase::HashTranslator::equal):
(JSC::WeakMapBase::inlineGet):
* runtime/WeakMapPrototype.cpp:
(JSC::WeakMapPrototype::finishCreation):
(JSC::getWeakMap):
(JSC::protoFuncWeakMapGet):
* runtime/WeakSetPrototype.cpp:
(JSC::getWeakSet):
Source/WebCore:
* platform/network/curl/CurlJobManager.cpp:
(WebCore::CurlJobList::finishJobs):
Source/WTF:
Add inlineGet method with HashTranslator.
* wtf/HashMap.h:
(WTF::X>::inlineGet const):
(WTF::MappedTraits>::inlineGet const):
(WTF::MappedTraits>::fastGet const): Deleted.
* wtf/LoggingHashMap.h:
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@221854
268f45cc-cd09-0410-ab3c-
d52691b4dbfc
+2017-09-03 Yusuke Suzuki <utatane.tea@gmail.com>
+
+ [DFG] Optimize WeakMap::get by adding intrinsic and fixup
+ https://bugs.webkit.org/show_bug.cgi?id=176010
+
+ Reviewed by Filip Pizlo.
+
+ * microbenchmarks/weak-map-key.js: Added.
+ (assert):
+ (objectKey):
+ (let.start.Date.now):
+
2017-09-09 Yusuke Suzuki <utatane.tea@gmail.com>
[JSC] Optimize Object.keys by using careful array allocation
--- /dev/null
+function assert(b) {
+ if (!b)
+ throw new Error("Bad!");
+}
+noInline(assert);
+
+let weakMap = new WeakMap;
+
+function objectKey(o) {
+ return weakMap.get(o);
+}
+noInline(objectKey);
+
+const iters = 300000;
+let start = Date.now();
+
+{
+ let o = {f: 20};
+ var array = [];
+ for (var i = 0; i < 10; i++) {
+ let newObject = { f: i };
+ weakMap.set(newObject, i);
+ array[i] = newObject;
+ }
+
+ for (var j = 0; j < iters; ++j) {
+ for (let i = 0; i < 10; i++)
+ assert(objectKey(array[i]) === i);
+ }
+}
+
+const verbose = false;
+if (verbose)
+ print(Date.now() - start);
+2017-09-03 Yusuke Suzuki <utatane.tea@gmail.com>
+
+ [DFG] Optimize WeakMap::get by adding intrinsic and fixup
+ https://bugs.webkit.org/show_bug.cgi?id=176010
+
+ Reviewed by Filip Pizlo.
+
+ It reveals that Ember.js consumes 3.8% of execution time for WeakMap#get.
+ It is used for meta property for objects (see peekMeta function in Ember.js).
+
+ This patch optimizes WeakMap#get.
+
+ 1. We use inlineGet to inline WeakMap#get operation in the native function.
+ Since this native function itself is very small, we should inline HashMap#get
+ entirely in this function.
+
+ 2. We add JSWeakMapType and JSWeakSetType. This allows us to perform `isJSWeakMap()`
+ very fast. And this patch wires this to DFG and FTL to add WeakMapObjectUse and WeakSetObjectUse
+ to drop unnecessary type checking. We add fixup rules for WeakMapGet DFG node by using WeakMapObjectUse,
+ ObjectUse, and Int32Use.
+
+ 3. We add intrinsic for WeakMap#get, and handle it in DFG and FTL. We use MapHash to
+ calculate hash value for the key's Object and use this hash value to look up value from
+ JSWeakMap's HashMap. Currently, we just call the operationWeakMapGet function in DFG and FTL.
+ It is worth considering that implementing this operation entirely in JIT, like GetMapBucket.
+ But anyway, the current one already optimizes the performance, so we leave this for the subsequent
+ patches.
+
+ We currently do not implement any other intrinsics (like, WeakMap#has, WeakSet) because they are
+ not used in Ember.js right now.
+
+ This patch optimizes WeakMap#get by 50%.
+
+ baseline patched
+
+ weak-map-key 88.6456+-3.9564 ^ 59.1502+-2.2406 ^ definitely 1.4987x faster
+
+ * bytecode/DirectEvalCodeCache.h:
+ (JSC::DirectEvalCodeCache::tryGet):
+ * bytecode/SpeculatedType.cpp:
+ (JSC::dumpSpeculation):
+ (JSC::speculationFromClassInfo):
+ (JSC::speculationFromJSType):
+ (JSC::speculationFromString):
+ * bytecode/SpeculatedType.h:
+ * dfg/DFGAbstractInterpreterInlines.h:
+ (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
+ * dfg/DFGByteCodeParser.cpp:
+ (JSC::DFG::ByteCodeParser::handleIntrinsicCall):
+ * dfg/DFGClobberize.h:
+ (JSC::DFG::clobberize):
+ * dfg/DFGDoesGC.cpp:
+ (JSC::DFG::doesGC):
+ * dfg/DFGFixupPhase.cpp:
+ (JSC::DFG::FixupPhase::fixupNode):
+ * dfg/DFGHeapLocation.cpp:
+ (WTF::printInternal):
+ * dfg/DFGHeapLocation.h:
+ * dfg/DFGNode.h:
+ (JSC::DFG::Node::hasHeapPrediction):
+ * dfg/DFGNodeType.h:
+ * dfg/DFGOperations.cpp:
+ * dfg/DFGOperations.h:
+ * dfg/DFGPredictionPropagationPhase.cpp:
+ * dfg/DFGSafeToExecute.h:
+ (JSC::DFG::SafeToExecuteEdge::operator()):
+ (JSC::DFG::safeToExecute):
+ * dfg/DFGSpeculativeJIT.cpp:
+ (JSC::DFG::SpeculativeJIT::speculateWeakMapObject):
+ (JSC::DFG::SpeculativeJIT::speculateWeakSetObject):
+ (JSC::DFG::SpeculativeJIT::speculate):
+ (JSC::DFG::SpeculativeJIT::compileWeakMapGet):
+ * dfg/DFGSpeculativeJIT.h:
+ (JSC::DFG::SpeculativeJIT::callOperation):
+ * dfg/DFGSpeculativeJIT32_64.cpp:
+ (JSC::DFG::SpeculativeJIT::compile):
+ * dfg/DFGSpeculativeJIT64.cpp:
+ (JSC::DFG::SpeculativeJIT::compile):
+ * dfg/DFGUseKind.cpp:
+ (WTF::printInternal):
+ * dfg/DFGUseKind.h:
+ (JSC::DFG::typeFilterFor):
+ (JSC::DFG::isCell):
+ * ftl/FTLCapabilities.cpp:
+ (JSC::FTL::canCompile):
+ * ftl/FTLLowerDFGToB3.cpp:
+ (JSC::FTL::DFG::LowerDFGToB3::compileNode):
+ (JSC::FTL::DFG::LowerDFGToB3::compileWeakMapGet):
+ (JSC::FTL::DFG::LowerDFGToB3::lowWeakMapObject):
+ (JSC::FTL::DFG::LowerDFGToB3::lowWeakSetObject):
+ (JSC::FTL::DFG::LowerDFGToB3::speculate):
+ (JSC::FTL::DFG::LowerDFGToB3::speculateWeakMapObject):
+ (JSC::FTL::DFG::LowerDFGToB3::speculateWeakSetObject):
+ * jit/JITOperations.h:
+ * runtime/Intrinsic.cpp:
+ (JSC::intrinsicName):
+ * runtime/Intrinsic.h:
+ * runtime/JSType.h:
+ * runtime/JSWeakMap.h:
+ (JSC::isJSWeakMap):
+ * runtime/JSWeakSet.h:
+ (JSC::isJSWeakSet):
+ * runtime/WeakMapBase.cpp:
+ (JSC::WeakMapBase::get):
+ * runtime/WeakMapBase.h:
+ (JSC::WeakMapBase::HashTranslator::hash):
+ (JSC::WeakMapBase::HashTranslator::equal):
+ (JSC::WeakMapBase::inlineGet):
+ * runtime/WeakMapPrototype.cpp:
+ (JSC::WeakMapPrototype::finishCreation):
+ (JSC::getWeakMap):
+ (JSC::protoFuncWeakMapGet):
+ * runtime/WeakSetPrototype.cpp:
+ (JSC::getWeakSet):
+
2017-09-09 Yusuke Suzuki <utatane.tea@gmail.com>
[JSC] Optimize Object.keys by using careful array allocation
DirectEvalExecutable* tryGet(const String& evalSource, CallSiteIndex callSiteIndex)
{
- return m_cacheMap.fastGet(CacheKey(evalSource, callSiteIndex)).get();
+ return m_cacheMap.inlineGet(CacheKey(evalSource, callSiteIndex)).get();
}
void set(ExecState* exec, JSCell* owner, const String& evalSource, CallSiteIndex callSiteIndex, DirectEvalExecutable* evalExecutable)
#include "JSFunction.h"
#include "JSMap.h"
#include "JSSet.h"
+#include "JSWeakMap.h"
+#include "JSWeakSet.h"
#include "ProxyObject.h"
#include "RegExpObject.h"
#include "ScopedArguments.h"
else
isTop = false;
+ if (value & SpecWeakMapObject)
+ strOut.print("WeakMapObject");
+ else
+ isTop = false;
+
+ if (value & SpecWeakSetObject)
+ strOut.print("WeakSetObject");
+ else
+ isTop = false;
+
if (value & SpecProxyObject)
strOut.print("ProxyObject");
else
if (classInfo == JSSet::info())
return SpecSetObject;
+ if (classInfo == JSWeakMap::info())
+ return SpecWeakMapObject;
+
+ if (classInfo == JSWeakSet::info())
+ return SpecWeakSetObject;
+
if (classInfo == ProxyObject::info())
return SpecProxyObject;
return SpecMapObject;
case JSSetType:
return SpecSetObject;
+ case JSWeakMapType:
+ return SpecWeakMapObject;
+ case JSWeakSetType:
+ return SpecWeakSetObject;
default:
ASSERT_NOT_REACHED();
}
return SpecMapObject;
if (!strncmp(speculation, "SpecSetObject", strlen("SpecSetObject")))
return SpecSetObject;
+ if (!strncmp(speculation, "SpecWeakMapObject", strlen("SpecWeakMapObject")))
+ return SpecWeakMapObject;
+ if (!strncmp(speculation, "SpecWeakSetObject", strlen("SpecWeakSetObject")))
+ return SpecWeakSetObject;
if (!strncmp(speculation, "SpecProxyObject", strlen("SpecProxyObject")))
return SpecProxyObject;
if (!strncmp(speculation, "SpecDerivedArray", strlen("SpecDerivedArray")))
static const SpeculatedType SpecRegExpObject = 1ull << 15; // It's definitely a RegExpObject (and not any subclass of RegExpObject).
static const SpeculatedType SpecMapObject = 1ull << 16; // It's definitely a Map object or one of its subclasses.
static const SpeculatedType SpecSetObject = 1ull << 17; // It's definitely a Set object or one of its subclasses.
-static const SpeculatedType SpecProxyObject = 1ull << 18; // It's definitely a Proxy object or one of its subclasses.
-static const SpeculatedType SpecDerivedArray = 1ull << 19; // It's definitely a DerivedArray object.
-static const SpeculatedType SpecObjectOther = 1ull << 20; // It's definitely an object but not JSFinalObject, JSArray, or JSFunction.
-static const SpeculatedType SpecObject = SpecFinalObject | SpecArray | SpecFunction | SpecTypedArrayView | SpecDirectArguments | SpecScopedArguments | SpecStringObject | SpecRegExpObject | SpecMapObject | SpecSetObject | SpecProxyObject | SpecDerivedArray | SpecObjectOther; // Bitmask used for testing for any kind of object prediction.
-static const SpeculatedType SpecStringIdent = 1ull << 21; // It's definitely a JSString, and it's an identifier.
-static const SpeculatedType SpecStringVar = 1ull << 22; // It's definitely a JSString, and it's not an identifier.
+static const SpeculatedType SpecWeakMapObject = 1ull << 18; // It's definitely a WeakMap object or one of its subclasses.
+static const SpeculatedType SpecWeakSetObject = 1ull << 19; // It's definitely a WeakSet object or one of its subclasses.
+static const SpeculatedType SpecProxyObject = 1ull << 20; // It's definitely a Proxy object or one of its subclasses.
+static const SpeculatedType SpecDerivedArray = 1ull << 21; // It's definitely a DerivedArray object.
+static const SpeculatedType SpecObjectOther = 1ull << 22; // It's definitely an object but not JSFinalObject, JSArray, or JSFunction.
+static const SpeculatedType SpecObject = SpecFinalObject | SpecArray | SpecFunction | SpecTypedArrayView | SpecDirectArguments | SpecScopedArguments | SpecStringObject | SpecRegExpObject | SpecMapObject | SpecSetObject | SpecWeakMapObject | SpecWeakSetObject | SpecProxyObject | SpecDerivedArray | SpecObjectOther; // Bitmask used for testing for any kind of object prediction.
+static const SpeculatedType SpecStringIdent = 1ull << 23; // It's definitely a JSString, and it's an identifier.
+static const SpeculatedType SpecStringVar = 1ull << 24; // It's definitely a JSString, and it's not an identifier.
static const SpeculatedType SpecString = SpecStringIdent | SpecStringVar; // It's definitely a JSString.
-static const SpeculatedType SpecSymbol = 1ull << 23; // It's definitely a Symbol.
-static const SpeculatedType SpecCellOther = 1ull << 24; // It's definitely a JSCell but not a subclass of JSObject and definitely not a JSString or a Symbol.
+static const SpeculatedType SpecSymbol = 1ull << 25; // It's definitely a Symbol.
+static const SpeculatedType SpecCellOther = 1ull << 26; // It's definitely a JSCell but not a subclass of JSObject and definitely not a JSString or a Symbol.
static const SpeculatedType SpecCell = SpecObject | SpecString | SpecSymbol | SpecCellOther; // It's definitely a JSCell.
-static const SpeculatedType SpecBoolInt32 = 1ull << 25; // It's definitely an Int32 with value 0 or 1.
-static const SpeculatedType SpecNonBoolInt32 = 1ull << 26; // It's definitely an Int32 with value other than 0 or 1.
+static const SpeculatedType SpecBoolInt32 = 1ull << 27; // It's definitely an Int32 with value 0 or 1.
+static const SpeculatedType SpecNonBoolInt32 = 1ull << 28; // It's definitely an Int32 with value other than 0 or 1.
static const SpeculatedType SpecInt32Only = SpecBoolInt32 | SpecNonBoolInt32; // It's definitely an Int32.
-static const SpeculatedType SpecInt52Only = 1ull << 27; // It's definitely an Int52 and we intend it to unbox it. It's also definitely not an Int32.
+static const SpeculatedType SpecInt52Only = 1ull << 29; // It's definitely an Int52 and we intend it to unbox it. It's also definitely not an Int32.
static const SpeculatedType SpecAnyInt = SpecInt32Only | SpecInt52Only; // It's something that we can do machine int arithmetic on.
-static const SpeculatedType SpecAnyIntAsDouble = 1ull << 28; // It's definitely an Int52 and it's inside a double.
-static const SpeculatedType SpecNonIntAsDouble = 1ull << 29; // It's definitely not an Int52 but it's a real number and it's a double.
+static const SpeculatedType SpecAnyIntAsDouble = 1ull << 30; // It's definitely an Int52 and it's inside a double.
+static const SpeculatedType SpecNonIntAsDouble = 1ull << 31; // It's definitely not an Int52 but it's a real number and it's a double.
static const SpeculatedType SpecDoubleReal = SpecNonIntAsDouble | SpecAnyIntAsDouble; // It's definitely a non-NaN double.
-static const SpeculatedType SpecDoublePureNaN = 1ull << 30; // It's definitely a NaN that is safe to tag (i.e. pure).
-static const SpeculatedType SpecDoubleImpureNaN = 1ull << 31; // It's definitely a NaN that is unsafe to tag (i.e. impure).
+static const SpeculatedType SpecDoublePureNaN = 1ull << 32; // It's definitely a NaN that is safe to tag (i.e. pure).
+static const SpeculatedType SpecDoubleImpureNaN = 1ull << 33; // It's definitely a NaN that is unsafe to tag (i.e. impure).
static const SpeculatedType SpecDoubleNaN = SpecDoublePureNaN | SpecDoubleImpureNaN; // It's definitely some kind of NaN.
static const SpeculatedType SpecBytecodeDouble = SpecDoubleReal | SpecDoublePureNaN; // It's either a non-NaN or a NaN double, but it's definitely not impure NaN.
static const SpeculatedType SpecFullDouble = SpecDoubleReal | SpecDoubleNaN; // It's either a non-NaN or a NaN double.
static const SpeculatedType SpecFullRealNumber = SpecAnyInt | SpecDoubleReal; // It's either an Int32 or a DoubleReal, or a Int52.
static const SpeculatedType SpecBytecodeNumber = SpecInt32Only | SpecBytecodeDouble; // It's either an Int32 or a Double, and the Double cannot be an impure NaN.
static const SpeculatedType SpecFullNumber = SpecAnyInt | SpecFullDouble; // It's either an Int32, Int52, or a Double, and the Double can be impure NaN.
-static const SpeculatedType SpecBoolean = 1ull << 32; // It's definitely a Boolean.
-static const SpeculatedType SpecOther = 1ull << 33; // It's definitely either Null or Undefined.
+static const SpeculatedType SpecBoolean = 1ull << 34; // It's definitely a Boolean.
+static const SpeculatedType SpecOther = 1ull << 35; // It's definitely either Null or Undefined.
static const SpeculatedType SpecMisc = SpecBoolean | SpecOther; // It's definitely either a boolean, Null, or Undefined.
static const SpeculatedType SpecHeapTop = SpecCell | SpecBytecodeNumber | SpecMisc; // It can be any of the above, except for SpecInt52Only and SpecDoubleImpureNaN.
static const SpeculatedType SpecPrimitive = SpecString | SpecSymbol | SpecBytecodeNumber | SpecMisc; // It's any non-Object JSValue.
-static const SpeculatedType SpecEmpty = 1ull << 34; // It's definitely an empty value marker.
+static const SpeculatedType SpecEmpty = 1ull << 36; // It's definitely an empty value marker.
static const SpeculatedType SpecBytecodeTop = SpecHeapTop | SpecEmpty; // It can be any of the above, except for SpecInt52Only and SpecDoubleImpureNaN. Corresponds to what could be found in a bytecode local.
static const SpeculatedType SpecFullTop = SpecBytecodeTop | SpecFullNumber; // It can be anything that bytecode could see plus exotic encodings of numbers.
}
break;
+ case WeakMapGet:
+ forNode(node).makeHeapTop();
+ break;
+
case IsEmpty:
case IsUndefined:
case IsBoolean:
return true;
}
+ case JSWeakMapGetIntrinsic: {
+ if (argumentCountIncludingThis != 2)
+ return false;
+
+ if (m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadType))
+ return false;
+
+ insertChecks();
+ Node* map = get(virtualRegisterForArgument(0, registerOffset));
+ Node* key = get(virtualRegisterForArgument(1, registerOffset));
+ Node* hash = addToGraph(MapHash, key);
+ Node* result = addToGraph(WeakMapGet, OpInfo(), OpInfo(prediction), map, key, hash);
+ set(VirtualRegister(resultOperand), result);
+ return true;
+ }
+
case HasOwnPropertyIntrinsic: {
if (argumentCountIncludingThis != 2)
return false;
case MapHash:
def(PureValue(node));
return;
+
case GetMapBucket: {
read(MiscFields);
Edge& mapEdge = node->child1();
def(HeapLocation(MapBucketLoc, MiscFields, mapEdge, keyEdge), LazyNode(node));
return;
}
+
case GetMapBucketHead: {
read(MiscFields);
Edge& mapEdge = node->child1();
def(HeapLocation(MapBucketHeadLoc, MiscFields, mapEdge), LazyNode(node));
return;
}
+
case GetMapBucketNext: {
read(MiscFields);
LocationKind locationKind = MapBucketMapNextLoc;
def(HeapLocation(locationKind, MiscFields, bucketEdge), LazyNode(node));
return;
}
+
case LoadKeyFromMapBucket: {
read(MiscFields);
Edge& bucketEdge = node->child1();
def(HeapLocation(MapBucketKeyLoc, MiscFields, bucketEdge), LazyNode(node));
return;
}
+
case LoadValueFromMapBucket: {
read(MiscFields);
Edge& bucketEdge = node->child1();
return;
}
+ case WeakMapGet: {
+ read(MiscFields);
+ Edge& mapEdge = node->child1();
+ Edge& keyEdge = node->child2();
+ def(HeapLocation(WeakMapGetLoc, MiscFields, mapEdge, keyEdge), LazyNode(node));
+ return;
+ }
+
case ToLowerCase:
def(PureValue(node));
return;
case GetMapBucketNext:
case LoadKeyFromMapBucket:
case LoadValueFromMapBucket:
+ case WeakMapGet:
case Unreachable:
case ExtractCatchLocal:
case ExtractOSREntryLocal:
break;
}
+ case WeakMapGet: {
+ fixEdge<WeakMapObjectUse>(node->child1());
+ fixEdge<ObjectUse>(node->child2());
+ fixEdge<Int32Use>(node->child3());
+ break;
+ }
+
case DefineDataProperty: {
fixEdge<CellUse>(m_graph.varArgChild(node, 0));
Edge& propertyEdge = m_graph.varArgChild(node, 1);
case RegExpObjectLastIndexLoc:
out.print("RegExpObjectLastIndexLoc");
return;
+
case MapBucketLoc:
out.print("MapBucketLoc");
return;
+
case MapBucketHeadLoc:
out.print("MapBucketHeadLoc");
return;
+
case MapBucketKeyLoc:
out.print("MapBucketKeyLoc");
return;
+
case MapBucketValueLoc:
out.print("MapBucketValueLoc");
return;
+
case MapBucketMapNextLoc:
out.print("MapBucketMapNextLoc");
return;
+
case MapBucketSetNextLoc:
out.print("MapBucketSetNextLoc");
return;
+
+ case WeakMapGetLoc:
+ out.print("WeakMapGetLoc");
+ return;
+
case DOMStateLoc:
out.print("DOMStateLoc");
return;
MapBucketKeyLoc,
MapBucketMapNextLoc,
MapBucketSetNextLoc,
+ WeakMapGetLoc,
DOMStateLoc,
};
case AtomicsSub:
case AtomicsXor:
case GetDynamicVar:
+ case WeakMapGet:
return true;
default:
return false;
macro(GetMapBucketNext, NodeResultJS) \
macro(LoadKeyFromMapBucket, NodeResultJS) \
macro(LoadValueFromMapBucket, NodeResultJS) \
+ /* Nodes for JSWeakMap and JSWeakSet */ \
+ macro(WeakMapGet, NodeResultJS) \
\
macro(ToLowerCase, NodeResultJS) \
/* Nodes for DOM JIT */\
#include "JSLexicalEnvironment.h"
#include "JSMap.h"
#include "JSSet.h"
+#include "JSWeakMap.h"
#include "ObjectConstructor.h"
#include "Operations.h"
#include "ParseInt.h"
return JSValue::encode(asRegExpObject(base)->exec(exec, globalObject, input));
}
+EncodedJSValue JIT_OPERATION operationWeakMapGet(ExecState* exec, JSCell* weakMap, JSCell* object, int32_t hash)
+{
+ VM& vm = exec->vm();
+ NativeCallFrameTracer tracer(&vm, exec);
+ return JSValue::encode(jsCast<JSWeakMap*>(weakMap)->inlineGet(asObject(object), hash));
+}
+
EncodedJSValue JIT_OPERATION operationParseIntNoRadixGeneric(ExecState* exec, EncodedJSValue value)
{
VM& vm = exec->vm();
EncodedJSValue JIT_OPERATION operationRegExpExecString(ExecState*, JSGlobalObject*, RegExpObject*, JSString*) WTF_INTERNAL;
EncodedJSValue JIT_OPERATION operationRegExpExec(ExecState*, JSGlobalObject*, RegExpObject*, EncodedJSValue) WTF_INTERNAL;
EncodedJSValue JIT_OPERATION operationRegExpExecGeneric(ExecState*, JSGlobalObject*, EncodedJSValue, EncodedJSValue) WTF_INTERNAL;
+EncodedJSValue JIT_OPERATION operationWeakMapGet(ExecState*, JSCell*, JSCell*, int32_t) WTF_INTERNAL;
// These comparisons return a boolean within a size_t such that the value is zero extended to fill the register.
size_t JIT_OPERATION operationRegExpTestString(ExecState*, JSGlobalObject*, RegExpObject*, JSString*) WTF_INTERNAL;
size_t JIT_OPERATION operationRegExpTest(ExecState*, JSGlobalObject*, RegExpObject*, EncodedJSValue) WTF_INTERNAL;
case ToNumber:
case GetArgument:
case CallDOMGetter:
- case GetDynamicVar: {
+ case GetDynamicVar:
+ case WeakMapGet: {
setPrediction(m_currentNode->getHeapPrediction());
break;
}
case DerivedArrayUse:
case MapObjectUse:
case SetObjectUse:
+ case WeakMapObjectUse:
+ case WeakSetObjectUse:
case ObjectOrOtherUse:
case StringIdentUse:
case StringUse:
case GetMapBucketNext:
case LoadKeyFromMapBucket:
case LoadValueFromMapBucket:
+ case WeakMapGet:
case AtomicsAdd:
case AtomicsAnd:
case AtomicsCompareExchange:
speculateSetObject(edge, operand.gpr());
}
+void SpeculativeJIT::speculateWeakMapObject(Edge edge, GPRReg cell)
+{
+ speculateCellType(edge, cell, SpecWeakMapObject, JSWeakMapType);
+}
+
+void SpeculativeJIT::speculateWeakMapObject(Edge edge)
+{
+ if (!needsTypeCheck(edge, SpecWeakMapObject))
+ return;
+
+ SpeculateCellOperand operand(this, edge);
+ speculateWeakMapObject(edge, operand.gpr());
+}
+
+void SpeculativeJIT::speculateWeakSetObject(Edge edge, GPRReg cell)
+{
+ speculateCellType(edge, cell, SpecWeakSetObject, JSWeakSetType);
+}
+
+void SpeculativeJIT::speculateWeakSetObject(Edge edge)
+{
+ if (!needsTypeCheck(edge, SpecWeakSetObject))
+ return;
+
+ SpeculateCellOperand operand(this, edge);
+ speculateWeakSetObject(edge, operand.gpr());
+}
+
void SpeculativeJIT::speculateObjectOrOther(Edge edge)
{
if (!needsTypeCheck(edge, SpecObject | SpecOther))
case SetObjectUse:
speculateSetObject(edge);
break;
+ case WeakMapObjectUse:
+ speculateWeakMapObject(edge);
+ break;
+ case WeakSetObjectUse:
+ speculateWeakSetObject(edge);
+ break;
case ObjectOrOtherUse:
speculateObjectOrOther(edge);
break;
noResult(node);
}
+void SpeculativeJIT::compileWeakMapGet(Node* node)
+{
+ SpeculateCellOperand weakMap(this, node->child1());
+ SpeculateCellOperand object(this, node->child2());
+ SpeculateInt32Operand hash(this, node->child3());
+ JSValueRegsTemporary result(this);
+
+ GPRReg weakMapGPR = weakMap.gpr();
+ GPRReg objectGPR = object.gpr();
+ GPRReg hashGPR = hash.gpr();
+ JSValueRegs resultRegs = result.regs();
+
+ speculateWeakMapObject(node->child1(), weakMapGPR);
+ speculateObject(node->child2(), objectGPR);
+
+ flushRegisters();
+ callOperation(operationWeakMapGet, resultRegs, weakMapGPR, objectGPR, hashGPR);
+ m_jit.exceptionCheck();
+
+ jsValueResult(resultRegs, node);
+}
+
} } // namespace JSC::DFG
#endif
m_jit.setupArgumentsWithExecState(arg1, arg2);
return appendCallSetResult(operation, result);
}
+ JITCompiler::Call callOperation(J_JITOperation_ECCZ operation, JSValueRegs result, GPRReg arg1, GPRReg arg2, GPRReg arg3)
+ {
+ m_jit.setupArgumentsWithExecState(arg1, arg2, arg3);
+ return appendCallSetResult(operation, result.payloadGPR());
+ }
JITCompiler::Call callOperation(J_JITOperation_ECJ operation, GPRReg result, GPRReg arg1, GPRReg arg2)
{
m_jit.setupArgumentsWithExecState(arg1, arg2);
m_jit.setupArgumentsWithExecState(arg1, arg2);
return appendCallSetResult(operation, result.payloadGPR(), result.tagGPR());
}
+ JITCompiler::Call callOperation(J_JITOperation_ECCZ operation, JSValueRegs result, GPRReg arg1, GPRReg arg2, GPRReg arg3)
+ {
+ m_jit.setupArgumentsWithExecState(arg1, arg2, arg3);
+ return appendCallSetResult(operation, result.payloadGPR(), result.tagGPR());
+ }
JITCompiler::Call callOperation(V_JITOperation_EOZD operation, GPRReg arg1, GPRReg arg2, FPRReg arg3)
{
void compileCheckSubClass(Node*);
void compileGetMapBucketHead(Node*);
void compileGetMapBucketNext(Node*);
+ void compileWeakMapGet(Node*);
void compileLoadKeyFromMapBucket(Node*);
void compileLoadValueFromMapBucket(Node*);
void speculateMapObject(Edge, GPRReg cell);
void speculateSetObject(Edge);
void speculateSetObject(Edge, GPRReg cell);
+ void speculateWeakMapObject(Edge);
+ void speculateWeakMapObject(Edge, GPRReg cell);
+ void speculateWeakSetObject(Edge);
+ void speculateWeakSetObject(Edge, GPRReg cell);
void speculateObjectOrOther(Edge);
void speculateString(Edge edge, GPRReg cell);
void speculateStringIdentAndLoadStorage(Edge edge, GPRReg string, GPRReg storage);
compileLoadValueFromMapBucket(node);
break;
+ case WeakMapGet:
+ compileWeakMapGet(node);
+ break;
+
case Flush:
break;
compileLoadValueFromMapBucket(node);
break;
+ case WeakMapGet:
+ compileWeakMapGet(node);
+ break;
+
case ToLowerCase: {
compileToLowerCase(node);
break;
case SetObjectUse:
out.print("SetObjectUse");
return;
+ case WeakMapObjectUse:
+ out.print("WeakMapObjectUse");
+ return;
+ case WeakSetObjectUse:
+ out.print("WeakSetObjectUse");
+ return;
case ObjectOrOtherUse:
out.print("ObjectOrOther");
return;
SymbolUse,
MapObjectUse,
SetObjectUse,
+ WeakMapObjectUse,
+ WeakSetObjectUse,
StringObjectUse,
StringOrStringObjectUse,
NotStringVarUse,
return SpecMapObject;
case SetObjectUse:
return SpecSetObject;
+ case WeakMapObjectUse:
+ return SpecWeakMapObject;
+ case WeakSetObjectUse:
+ return SpecWeakSetObject;
case StringObjectUse:
return SpecStringObject;
case StringOrStringObjectUse:
case StringOrStringObjectUse:
case MapObjectUse:
case SetObjectUse:
+ case WeakMapObjectUse:
+ case WeakSetObjectUse:
return true;
default:
return false;
case GetMapBucketNext:
case LoadKeyFromMapBucket:
case LoadValueFromMapBucket:
+ case WeakMapGet:
case IsEmpty:
case IsUndefined:
case IsBoolean:
case SymbolUse:
case MapObjectUse:
case SetObjectUse:
+ case WeakMapObjectUse:
+ case WeakSetObjectUse:
case FinalObjectUse:
case RegExpObjectUse:
case ProxyObjectUse:
case LoadValueFromMapBucket:
compileLoadValueFromMapBucket();
break;
+ case WeakMapGet:
+ compileWeakMapGet();
+ break;
case IsObject:
compileIsObject();
break;
setJSValue(m_out.load64(mapBucket, m_heaps.HashMapBucket_key));
}
+ void compileWeakMapGet()
+ {
+ LValue weakMap = lowWeakMapObject(m_node->child1());
+ LValue object = lowObject(m_node->child2());
+ LValue hash = lowInt32(m_node->child3());
+
+ setJSValue(vmCall(Int64, m_out.operation(operationWeakMapGet), m_callFrame, weakMap, object, hash));
+ }
+
void compileIsObjectOrNull()
{
JSGlobalObject* globalObject = m_graph.globalObjectFor(m_node->origin.semantic);
speculateSetObject(edge, result);
return result;
}
+
+ LValue lowWeakMapObject(Edge edge)
+ {
+ LValue result = lowCell(edge);
+ speculateWeakMapObject(edge, result);
+ return result;
+ }
+
+ LValue lowWeakSetObject(Edge edge)
+ {
+ LValue result = lowCell(edge);
+ speculateWeakSetObject(edge, result);
+ return result;
+ }
LValue lowString(Edge edge, OperandSpeculationMode mode = AutomaticOperandSpeculation)
{
case SetObjectUse:
speculateSetObject(edge);
break;
+ case WeakMapObjectUse:
+ speculateWeakMapObject(edge);
+ break;
+ case WeakSetObjectUse:
+ speculateWeakSetObject(edge);
+ break;
case StringUse:
speculateString(edge);
break;
{
speculateSetObject(edge, lowCell(edge));
}
+
+ void speculateWeakMapObject(Edge edge, LValue cell)
+ {
+ FTL_TYPE_CHECK(
+ jsValueValue(cell), edge, SpecWeakMapObject, isNotType(cell, JSWeakMapType));
+ }
+
+ void speculateWeakMapObject(Edge edge)
+ {
+ speculateWeakMapObject(edge, lowCell(edge));
+ }
+
+ void speculateWeakSetObject(Edge edge, LValue cell)
+ {
+ FTL_TYPE_CHECK(
+ jsValueValue(cell), edge, SpecWeakSetObject, isNotType(cell, JSWeakSetType));
+ }
+
+ void speculateWeakSetObject(Edge edge)
+ {
+ speculateWeakSetObject(edge, lowCell(edge));
+ }
void speculateString(Edge edge, LValue cell)
{
typedef EncodedJSValue (JIT_OPERATION *J_JITOperation_EAapJcpZ)(ExecState*, ArrayAllocationProfile*, const JSValue*, int32_t);
typedef EncodedJSValue (JIT_OPERATION *J_JITOperation_EC)(ExecState*, JSCell*);
typedef EncodedJSValue (JIT_OPERATION *J_JITOperation_ECC)(ExecState*, JSCell*, JSCell*);
+typedef EncodedJSValue (JIT_OPERATION *J_JITOperation_ECCZ)(ExecState*, JSCell*, JSCell*, int32_t);
typedef EncodedJSValue (JIT_OPERATION *J_JITOperation_ECI)(ExecState*, JSCell*, UniquedStringImpl*);
typedef EncodedJSValue (JIT_OPERATION *J_JITOperation_ECJ)(ExecState*, JSCell*, EncodedJSValue);
typedef EncodedJSValue (JIT_OPERATION *J_JITOperation_ECZ)(ExecState*, JSCell*, int32_t);
return "JSSetBucketNextIntrinsic";
case JSSetBucketKeyIntrinsic:
return "JSSetBucketKeyIntrinsic";
+ case JSWeakMapGetIntrinsic:
+ return "JSWeakMapGetIntrinsic";
case HasOwnPropertyIntrinsic:
return "HasOwnPropertyIntrinsic";
case AtomicsAddIntrinsic:
JSSetBucketHeadIntrinsic,
JSSetBucketNextIntrinsic,
JSSetBucketKeyIntrinsic,
+ JSWeakMapGetIntrinsic,
HasOwnPropertyIntrinsic,
AtomicsAddIntrinsic,
AtomicsAndIntrinsic,
ProxyObjectType,
JSMapType,
JSSetType,
+ JSWeakMapType,
+ JSWeakSetType,
WebAssemblyFunctionType,
static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
{
- return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
+ return Structure::create(vm, globalObject, prototype, TypeInfo(JSWeakMapType, StructureFlags), info());
}
static JSWeakMap* create(VM& vm, Structure* structure)
static String toStringName(const JSObject*, ExecState*);
};
+inline bool isJSWeakMap(JSCell* from)
+{
+ static_assert(std::is_final<JSWeakMap>::value, "");
+ return from->type() == JSWeakMapType;
+}
+
+inline bool isJSWeakMap(JSValue from)
+{
+ static_assert(std::is_final<JSWeakMap>::value, "");
+ return from.isCell() && from.asCell()->type() == JSWeakMapType;
+}
+
} // namespace JSC
static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
{
- return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
+ return Structure::create(vm, globalObject, prototype, TypeInfo(JSWeakSetType, StructureFlags), info());
}
static JSWeakSet* create(VM& vm, Structure* structure)
static String toStringName(const JSObject*, ExecState*);
};
+inline bool isJSWeakSet(JSCell* from)
+{
+ static_assert(std::is_final<JSWeakSet>::value, "");
+ return from->type() == JSWeakSetType;
+}
+
+inline bool isJSWeakSet(JSValue from)
+{
+ static_assert(std::is_final<JSWeakSet>::value, "");
+ return from.isCell() && from.asCell()->type() == JSWeakSetType;
+}
+
} // namespace JSC
visitor.reportExtraMemoryVisited(thisObj->m_map.capacity() * (sizeof(JSObject*) + sizeof(WriteBarrier<Unknown>)));
}
+JSValue WeakMapBase::get(JSObject* key)
+{
+ return inlineGet(key);
+}
+
void WeakMapBase::set(VM& vm, JSObject* key, JSValue value)
{
// Here we force the write barrier on the key.
result.iterator->value.set(vm, this, value);
}
-JSValue WeakMapBase::get(JSObject* key)
-{
- auto iter = m_map.find(key);
- if (iter == m_map.end())
- return jsUndefined();
- return iter->value.get();
-}
-
bool WeakMapBase::remove(JSObject* key)
{
return m_map.remove(key);
void set(VM&, JSObject*, JSValue);
JSValue get(JSObject*);
+ JSValue inlineGet(JSObject*);
+ JSValue inlineGet(JSObject*, int32_t hash);
bool remove(JSObject*);
bool contains(JSObject*);
void clear();
WeakMapBase(VM&, Structure*);
static void destroy(JSCell*);
+ using KeyWithHash = std::pair<JSObject*, unsigned>;
+ struct HashTranslator {
+ static inline unsigned hash(const KeyWithHash& keyWithHash)
+ {
+ return keyWithHash.second;
+ }
+
+ static inline bool equal(JSObject* key, const KeyWithHash& keyWithHash)
+ {
+ return key == keyWithHash.first;
+ }
+ };
+
class DeadKeyCleaner : public UnconditionalFinalizer, public WeakReferenceHarvester {
public:
WeakMapBase* target();
MapType m_map;
};
+ALWAYS_INLINE JSValue WeakMapBase::inlineGet(JSObject* key)
+{
+ if (auto result = m_map.inlineGet(key))
+ return result.get();
+ return jsUndefined();
+}
+
+ALWAYS_INLINE JSValue WeakMapBase::inlineGet(JSObject* key, int32_t hash)
+{
+ KeyWithHash keyWithHash { key, hash };
+ if (auto result = m_map.inlineGet<HashTranslator>(keyWithHash))
+ return result.get();
+ return jsUndefined();
+}
+
} // namespace JSC
vm.prototypeMap.addPrototype(this);
JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->deleteKeyword, protoFuncWeakMapDelete, DontEnum, 1);
- JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->get, protoFuncWeakMapGet, DontEnum, 1);
+ JSC_NATIVE_INTRINSIC_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->get, protoFuncWeakMapGet, DontEnum, 1, JSWeakMapGetIntrinsic);
JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->has, protoFuncWeakMapHas, DontEnum, 1);
JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->set, protoFuncWeakMapSet, DontEnum, 2);
putDirectWithoutTransition(vm, vm.propertyNames->toStringTagSymbol, jsString(&vm, "WeakMap"), DontEnum | ReadOnly);
}
-static JSWeakMap* getWeakMap(CallFrame* callFrame, JSValue value)
+ALWAYS_INLINE static JSWeakMap* getWeakMap(CallFrame* callFrame, JSValue value)
{
VM& vm = callFrame->vm();
auto scope = DECLARE_THROW_SCOPE(vm);
- if (!value.isObject()) {
+ if (UNLIKELY(!value.isObject())) {
throwTypeError(callFrame, scope, WTF::ASCIILiteral("Called WeakMap function on non-object"));
return nullptr;
}
- if (JSWeakMap* weakMap = jsDynamicCast<JSWeakMap*>(vm, value))
- return weakMap;
+ if (LIKELY(isJSWeakMap(asObject(value))))
+ return jsCast<JSWeakMap*>(value);
throwTypeError(callFrame, scope, WTF::ASCIILiteral("Called WeakMap function on a non-WeakMap object"));
return nullptr;
JSValue key = callFrame->argument(0);
if (!key.isObject())
return JSValue::encode(jsUndefined());
- return JSValue::encode(map->get(asObject(key)));
+ return JSValue::encode(map->inlineGet(asObject(key)));
}
EncodedJSValue JSC_HOST_CALL protoFuncWeakMapHas(CallFrame* callFrame)
putDirectWithoutTransition(vm, vm.propertyNames->toStringTagSymbol, jsString(&vm, "WeakSet"), DontEnum | ReadOnly);
}
-static JSWeakSet* getWeakSet(CallFrame* callFrame, JSValue value)
+ALWAYS_INLINE static JSWeakSet* getWeakSet(CallFrame* callFrame, JSValue value)
{
VM& vm = callFrame->vm();
auto scope = DECLARE_THROW_SCOPE(vm);
- if (!value.isObject()) {
+ if (UNLIKELY(!value.isObject())) {
throwTypeError(callFrame, scope, WTF::ASCIILiteral("Called WeakSet function on non-object"));
return nullptr;
}
- if (JSWeakSet* weakSet = jsDynamicCast<JSWeakSet*>(vm, value))
- return weakSet;
+ if (LIKELY(isJSWeakSet(asObject(value))))
+ return jsCast<JSWeakSet*>(value);
throwTypeError(callFrame, scope, WTF::ASCIILiteral("Called WeakSet function on a non-WeakSet object"));
return nullptr;
+2017-09-03 Yusuke Suzuki <utatane.tea@gmail.com>
+
+ [DFG] Optimize WeakMap::get by adding intrinsic and fixup
+ https://bugs.webkit.org/show_bug.cgi?id=176010
+
+ Reviewed by Filip Pizlo.
+
+ Add inlineGet method with HashTranslator.
+
+ * wtf/HashMap.h:
+ (WTF::X>::inlineGet const):
+ (WTF::MappedTraits>::inlineGet const):
+ (WTF::MappedTraits>::fastGet const): Deleted.
+ * wtf/LoggingHashMap.h:
+
2017-09-07 Myles C. Maxfield <mmaxfield@apple.com>
[PAL] Unify PlatformUserPreferredLanguages.h with Language.h
MappedPeekType get(const KeyType&) const;
// Same as get(), but aggressively inlined.
- MappedPeekType fastGet(const KeyType&) const;
+ MappedPeekType inlineGet(const KeyType&) const;
// Replaces the value but not the key if the key is already present.
// Return value includes both an iterator to the key location,
template<typename HashTranslator, typename T> const_iterator find(const T&) const;
template<typename HashTranslator, typename T> bool contains(const T&) const;
template<typename HashTranslator, typename T> MappedPeekType get(const T&) const;
+ template<typename HashTranslator, typename T> MappedPeekType inlineGet(const T&) const;
// An alternate version of add() that finds the object by hashing and comparing
// with some other type, to avoid the cost of type conversion if the object is already
template<typename T, typename U, typename V, typename W, typename X>
template<typename HashTranslator, typename TYPE>
+auto HashMap<T, U, V, W, X>::inlineGet(const TYPE& value) const -> MappedPeekType
+{
+ auto* entry = const_cast<HashTableType&>(m_impl).template inlineLookup<HashMapTranslatorAdapter<KeyValuePairTraits, HashTranslator>>(value);
+ if (!entry)
+ return MappedTraits::peek(MappedTraits::emptyValue());
+ return MappedTraits::peek(entry->value);
+}
+
+template<typename T, typename U, typename V, typename W, typename X>
+template<typename HashTranslator, typename TYPE>
inline bool HashMap<T, U, V, W, X>::contains(const TYPE& value) const
{
return m_impl.template contains<HashMapTranslatorAdapter<KeyValuePairTraits, HashTranslator>>(value);
}
template<typename T, typename U, typename V, typename W, typename MappedTraits>
-ALWAYS_INLINE auto HashMap<T, U, V, W, MappedTraits>::fastGet(const KeyType& key) const -> MappedPeekType
+ALWAYS_INLINE auto HashMap<T, U, V, W, MappedTraits>::inlineGet(const KeyType& key) const -> MappedPeekType
{
KeyValuePairType* entry = const_cast<HashTableType&>(m_impl).template inlineLookup<IdentityTranslatorType>(key);
if (!entry)
return m_map.get(key);
}
- MappedPeekType fastGet(const KeyType& key) const
+ MappedPeekType inlineGet(const KeyType& key) const
{
find(key);
- return m_map.fastGet(key);
+ return m_map.inlineGet(key);
}
template<typename PassedType>
+2017-09-03 Yusuke Suzuki <utatane.tea@gmail.com>
+
+ [DFG] Optimize WeakMap::get by adding intrinsic and fixup
+ https://bugs.webkit.org/show_bug.cgi?id=176010
+
+ Reviewed by Filip Pizlo.
+
+ * platform/network/curl/CurlJobManager.cpp:
+ (WebCore::CurlJobList::finishJobs):
+
2017-09-10 Zan Dobersek <zdobersek@igalia.com>
[GStreamer] Drop libgcrypt initialization in webkit_media_clear_key_decrypt_init()
if (!m_activeJobs.contains(ticket))
continue;
removeHandle(ticket);
- notifyResult(m_activeJobs.fastGet(ticket), result);
+ notifyResult(m_activeJobs.inlineGet(ticket), result);
m_activeJobs.remove(ticket);
}
}