WebKit Bugzilla
New
Browse
Search+
Log In
×
Sign in with GitHub
or
Remember my login
Create Account
·
Forgot Password
Forgotten password account recovery
[patch]
patch
c-backup.diff (text/plain), 157.64 KB, created by
Saam Barati
on 2016-09-01 19:23:32 PDT
(
hide
)
Description:
patch
Filename:
MIME Type:
Creator:
Saam Barati
Created:
2016-09-01 19:23:32 PDT
Size:
157.64 KB
patch
obsolete
>Index: PerformanceTests/ChangeLog >=================================================================== >--- PerformanceTests/ChangeLog (revision 205331) >+++ PerformanceTests/ChangeLog (working copy) >@@ -1,3 +1,12 @@ >+2016-09-01 Saam Barati <sbarati@apple.com> >+ >+ Make JSMap and JSSet faster >+ https://bugs.webkit.org/show_bug.cgi?id=160989 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ * ES6SampleBench/cli.js: >+ > 2016-08-23 Saam Barati <sbarati@apple.com> > > It should be easy to run ES6SampleBench from the jsc shell >Index: PerformanceTests/ES6SampleBench/cli.js >=================================================================== >--- PerformanceTests/ES6SampleBench/cli.js (revision 205305) >+++ PerformanceTests/ES6SampleBench/cli.js (working copy) >@@ -30,4 +30,4 @@ load("air_benchmark.js"); > load("basic_benchmark.js"); > load("glue.js"); > >-driver.start(10); >+driver.start(4); >Index: Source/JavaScriptCore/ChangeLog >=================================================================== >--- Source/JavaScriptCore/ChangeLog (revision 205305) >+++ Source/JavaScriptCore/ChangeLog (working copy) >@@ -1,3 +1,300 @@ >+2016-09-01 Saam Barati <sbarati@apple.com> >+ >+ Make JSMap and JSSet faster >+ https://bugs.webkit.org/show_bug.cgi?id=160989 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ This patch revamps how we implement Map and Set. It uses >+ a new hash map implementation. The hash map uses linear >+ probing and it uses Wang's 64 bit hash function for JSValues >+ that aren't strings. Strings use StringImpl's hash function. >+ The reason I wanted to roll our own HashTable is twofold: >+ I didn't want to inline WTF::HashMap's implementation into our >+ JIT, since that seems error prone and unmaintainable. Also, I wanted >+ a different structure for hash map buckets where buckets also exist in >+ a linked list. >+ >+ The reason for making buckets part of a linked list is that iteration >+ is now simple. Iteration works by just traversing a linked list. >+ This design also allows for a simple implementation when doing iteration >+ while the hash table is mutating. Whenever we remove a bucket from >+ the hash table, it is removed from the list, meaning items in the >+ list don't point to it. However, the removed bucket will still point >+ to things that are either in the list, or have also been removed. >+ e.g, from a removed bucket, you can always follow pointers until you >+ either find an item in the list, or you find the tail of the list. >+ This is a really nice property because it means that a Map or Set >+ does not need to reason about the all the iterators that point >+ into its list. Also, whenever we add items to the Map or Set, we >+ hijack the tail as the new item, and make the new item point to a newly >+ created tail. This means that any iterator that pointed to the "tail" now >+ points to non-tail items. This makes the implementation of adding things >+ to the Map/Set while iterating easy. >+ >+ I also made Map.prototype.get, Map.prototype.has, and Set.prototype.has >+ into intrinsics in the DFG. The IR can now reason about hash map >+ operations and can even do CSE over Wang's hash function, hash map >+ bucket lookups, hash map bucket loads, and testing if a key is in >+ the hash table. This makes code patterns for Map like so, super fast >+ in the FTL, since we will only be doing a single hash and hash bucket lookup: >+ >+ ``` >+ function getKeyIfPresent(map, key) { >+ if (map.has(key)) >+ return map.get(key); >+ } >+ ``` >+ >+ This patch is roughly an 8% speedup on ES6SampleBench. >+ >+ * CMakeLists.txt: >+ * JavaScriptCore.xcodeproj/project.pbxproj: >+ * bytecode/SpeculatedType.cpp: >+ (JSC::speculationFromClassInfo): >+ * bytecode/SpeculatedType.h: >+ * dfg/DFGAbstractInterpreterInlines.h: >+ (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): >+ (JSC::DFG::AbstractInterpreter<AbstractStateType>::execute): >+ * dfg/DFGByteCodeParser.cpp: >+ (JSC::DFG::ByteCodeParser::handleIntrinsicCall): >+ * dfg/DFGClobberize.h: >+ (JSC::DFG::clobberize): >+ * dfg/DFGDoesGC.cpp: >+ (JSC::DFG::doesGC): >+ * dfg/DFGEdge.h: >+ (JSC::DFG::Edge::shift): >+ (JSC::DFG::Edge::makeWord): >+ * 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::speculateMapObject): >+ (JSC::DFG::SpeculativeJIT::speculateSetObject): >+ (JSC::DFG::SpeculativeJIT::speculate): >+ * 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/FTLAbstractHeapRepository.h: >+ * ftl/FTLCapabilities.cpp: >+ (JSC::FTL::canCompile): >+ * ftl/FTLLowerDFGToB3.cpp: >+ (JSC::FTL::DFG::LowerDFGToB3::compileNode): >+ (JSC::FTL::DFG::LowerDFGToB3::compileMapHash): >+ (JSC::FTL::DFG::LowerDFGToB3::compileGetMapBucket): >+ (JSC::FTL::DFG::LowerDFGToB3::compileLoadFromJSMapBucket): >+ (JSC::FTL::DFG::LowerDFGToB3::compileIsNonEmptyMapBucket): >+ (JSC::FTL::DFG::LowerDFGToB3::lowMapObject): >+ (JSC::FTL::DFG::LowerDFGToB3::lowSetObject): >+ (JSC::FTL::DFG::LowerDFGToB3::lowMapBucket): >+ (JSC::FTL::DFG::LowerDFGToB3::speculate): >+ (JSC::FTL::DFG::LowerDFGToB3::speculateMapObject): >+ (JSC::FTL::DFG::LowerDFGToB3::speculateSetObject): >+ (JSC::FTL::DFG::LowerDFGToB3::setMapBucket): >+ (JSC::FTL::DFG::LowerDFGToB3::lowRegExpObject): Deleted. >+ (JSC::FTL::DFG::LowerDFGToB3::lowStorage): Deleted. >+ (JSC::FTL::DFG::LowerDFGToB3::speculateRegExpObject): Deleted. >+ (JSC::FTL::DFG::LowerDFGToB3::setStorage): Deleted. >+ * jit/AssemblyHelpers.cpp: >+ (JSC::AssemblyHelpers::WangsInt64Hash): >+ * jit/AssemblyHelpers.h: >+ (JSC::AssemblyHelpers::emitAllocateDestructibleObject): Deleted. >+ * jit/JITOperations.h: >+ * parser/ModuleAnalyzer.cpp: >+ (JSC::ModuleAnalyzer::ModuleAnalyzer): >+ * runtime/HashMapImpl.cpp: Added. >+ (JSC::HashMapBucket<Data>::visitChildren): >+ (JSC::HashMapImpl<HashMapBucket>::visitChildren): >+ (JSC::HashMapImpl<HashMapBucket>::copyBackingStore): >+ * runtime/HashMapImpl.h: Added. >+ (JSC::HashMapBucket::selectStructure): >+ (JSC::HashMapBucket::createStructure): >+ (JSC::HashMapBucket::create): >+ (JSC::HashMapBucket::HashMapBucket): >+ (JSC::HashMapBucket::setNext): >+ (JSC::HashMapBucket::setPrev): >+ (JSC::HashMapBucket::setKey): >+ (JSC::HashMapBucket::setValue): >+ (JSC::HashMapBucket::key): >+ (JSC::HashMapBucket::value): >+ (JSC::HashMapBucket::next): >+ (JSC::HashMapBucket::prev): >+ (JSC::HashMapBucket::deleted): >+ (JSC::HashMapBucket::setDeleted): >+ (JSC::HashMapBucket::offsetOfKey): >+ (JSC::HashMapBucket::offsetOfValue): >+ (JSC::HashMapBuffer::allocationSize): >+ (JSC::HashMapBuffer::buffer): >+ (JSC::HashMapBuffer::create): >+ (JSC::areKeysEqual): >+ (JSC::normalizeMapKey): >+ (JSC::jsMapHash): >+ (JSC::HashMapImpl::selectStructure): >+ (JSC::HashMapImpl::createStructure): >+ (JSC::HashMapImpl::create): >+ (JSC::HashMapImpl::HashMapImpl): >+ (JSC::HashMapImpl::buffer): >+ (JSC::HashMapImpl::finishCreation): >+ (JSC::HashMapImpl::emptyValue): >+ (JSC::HashMapImpl::isEmpty): >+ (JSC::HashMapImpl::deletedValue): >+ (JSC::HashMapImpl::isDeleted): >+ (JSC::HashMapImpl::findBucket): >+ (JSC::HashMapImpl::get): >+ (JSC::HashMapImpl::has): >+ (JSC::HashMapImpl::add): >+ (JSC::HashMapImpl::remove): >+ (JSC::HashMapImpl::size): >+ (JSC::HashMapImpl::clear): >+ (JSC::HashMapImpl::bufferSizeInBytes): >+ (JSC::HashMapImpl::offsetOfBuffer): >+ (JSC::HashMapImpl::offsetOfCapacity): >+ (JSC::HashMapImpl::head): >+ (JSC::HashMapImpl::tail): >+ (JSC::HashMapImpl::approximateSize): >+ (JSC::HashMapImpl::findBucketAlreadyHashedAndNormalized): >+ (JSC::HashMapImpl::rehash): >+ (JSC::HashMapImpl::makeAndSetNewBuffer): >+ * runtime/Intrinsic.h: >+ * runtime/JSCJSValue.h: >+ * runtime/JSCJSValueInlines.h: >+ (JSC::sameValue): >+ * runtime/JSGlobalObject.cpp: >+ (JSC::JSGlobalObject::init): >+ * runtime/JSMap.cpp: >+ (JSC::JSMap::destroy): Deleted. >+ (JSC::JSMap::estimatedSize): Deleted. >+ (JSC::JSMap::visitChildren): Deleted. >+ (JSC::JSMap::copyBackingStore): Deleted. >+ (JSC::JSMap::has): Deleted. >+ (JSC::JSMap::size): Deleted. >+ (JSC::JSMap::get): Deleted. >+ (JSC::JSMap::set): Deleted. >+ (JSC::JSMap::clear): Deleted. >+ (JSC::JSMap::remove): Deleted. >+ * runtime/JSMap.h: >+ (JSC::JSMap::createStructure): >+ (JSC::JSMap::create): >+ (JSC::JSMap::get): >+ (JSC::JSMap::set): >+ (JSC::JSMap::JSMap): >+ (JSC::JSMap::Entry::key): Deleted. >+ (JSC::JSMap::Entry::value): Deleted. >+ (JSC::JSMap::Entry::visitChildren): Deleted. >+ (JSC::JSMap::Entry::setKey): Deleted. >+ (JSC::JSMap::Entry::setKeyWithoutWriteBarrier): Deleted. >+ (JSC::JSMap::Entry::setValue): Deleted. >+ (JSC::JSMap::Entry::clear): Deleted. >+ * runtime/JSMapIterator.cpp: >+ (JSC::JSMapIterator::finishCreation): >+ (JSC::JSMapIterator::visitChildren): >+ (JSC::JSMapIterator::clone): >+ * runtime/JSMapIterator.h: >+ (JSC::JSMapIterator::advanceIter): >+ (JSC::JSMapIterator::next): >+ (JSC::JSMapIterator::nextKeyValue): >+ (JSC::JSMapIterator::JSMapIterator): >+ (JSC::JSMapIterator::setIterator): >+ (JSC::JSMapIterator::finish): Deleted. >+ (JSC::JSMapIterator::iteratorData): Deleted. >+ * runtime/JSModuleLoader.cpp: >+ (JSC::JSModuleLoader::finishCreation): >+ * runtime/JSModuleLoader.h: >+ (JSC::JSModuleLoader::create): >+ * runtime/JSModuleRecord.cpp: >+ (JSC::JSModuleRecord::finishCreation): >+ * runtime/JSModuleRecord.h: >+ (JSC::JSModuleRecord::create): >+ * runtime/JSSet.cpp: >+ (JSC::JSSet::destroy): Deleted. >+ (JSC::JSSet::estimatedSize): Deleted. >+ (JSC::JSSet::visitChildren): Deleted. >+ (JSC::JSSet::copyBackingStore): Deleted. >+ (JSC::JSSet::has): Deleted. >+ (JSC::JSSet::size): Deleted. >+ (JSC::JSSet::add): Deleted. >+ (JSC::JSSet::clear): Deleted. >+ (JSC::JSSet::remove): Deleted. >+ * runtime/JSSet.h: >+ (JSC::JSSet::createStructure): >+ (JSC::JSSet::create): >+ (JSC::JSSet::add): >+ (JSC::JSSet::JSSet): >+ (JSC::JSSet::Entry::key): Deleted. >+ (JSC::JSSet::Entry::value): Deleted. >+ (JSC::JSSet::Entry::visitChildren): Deleted. >+ (JSC::JSSet::Entry::setKey): Deleted. >+ (JSC::JSSet::Entry::setKeyWithoutWriteBarrier): Deleted. >+ (JSC::JSSet::Entry::setValue): Deleted. >+ (JSC::JSSet::Entry::clear): Deleted. >+ * runtime/JSSetIterator.cpp: >+ (JSC::JSSetIterator::finishCreation): >+ (JSC::JSSetIterator::visitChildren): >+ (JSC::JSSetIterator::clone): >+ * runtime/JSSetIterator.h: >+ (JSC::JSSetIterator::advanceIter): >+ (JSC::JSSetIterator::next): >+ (JSC::JSSetIterator::JSSetIterator): >+ (JSC::JSSetIterator::setIterator): >+ (JSC::JSSetIterator::finish): Deleted. >+ (JSC::JSSetIterator::iteratorData): Deleted. >+ * runtime/JSType.h: >+ * runtime/MapBase.cpp: Added. >+ (JSC::MapBase<HashMapBucketType>::visitChildren): >+ (JSC::MapBase<HashMapBucketType>::estimatedSize): >+ * runtime/MapBase.h: Added. >+ (JSC::MapBase::size): >+ (JSC::MapBase::has): >+ (JSC::MapBase::clear): >+ (JSC::MapBase::remove): >+ (JSC::MapBase::findBucket): >+ (JSC::MapBase::offsetOfHashMapImpl): >+ (JSC::MapBase::impl): >+ (JSC::MapBase::finishCreation): >+ (JSC::MapBase::MapBase): >+ * runtime/MapConstructor.cpp: >+ (JSC::constructMap): >+ * runtime/MapIteratorPrototype.cpp: >+ (JSC::MapIteratorPrototypeFuncNext): >+ * runtime/MapPrototype.cpp: >+ (JSC::MapPrototype::finishCreation): >+ (JSC::getMap): >+ (JSC::privateFuncIsMap): >+ (JSC::privateFuncMapIteratorNext): >+ * runtime/PropertyDescriptor.cpp: >+ (JSC::sameValue): Deleted. >+ * runtime/PropertyDescriptor.h: >+ * runtime/SetConstructor.cpp: >+ (JSC::constructSet): >+ * runtime/SetIteratorPrototype.cpp: >+ (JSC::SetIteratorPrototypeFuncNext): >+ * runtime/SetPrototype.cpp: >+ (JSC::SetPrototype::finishCreation): >+ (JSC::getSet): >+ (JSC::privateFuncSetIteratorNext): >+ * runtime/VM.cpp: >+ (JSC::VM::VM): >+ * runtime/VM.h: >+ > 2016-09-01 Filip Pizlo <fpizlo@apple.com> > > ObjectAllocationSinkingPhase::insertOSRHintsForUpdate() fails to emit updated hints in some cases >Index: Source/JavaScriptCore/CMakeLists.txt >=================================================================== >--- Source/JavaScriptCore/CMakeLists.txt (revision 205305) >+++ Source/JavaScriptCore/CMakeLists.txt (working copy) >@@ -667,6 +667,7 @@ set(JavaScriptCore_SOURCES > runtime/GeneratorFunctionPrototype.cpp > runtime/GeneratorPrototype.cpp > runtime/GetterSetter.cpp >+ runtime/HashMapImpl.cpp > runtime/Identifier.cpp > runtime/IndexingType.cpp > runtime/InferredType.cpp >@@ -752,6 +753,7 @@ set(JavaScriptCore_SOURCES > runtime/LazyClassStructure.cpp > runtime/LiteralParser.cpp > runtime/Lookup.cpp >+ runtime/MapBase.cpp > runtime/MapConstructor.cpp > runtime/MapIteratorPrototype.cpp > runtime/MapPrototype.cpp >Index: Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj >=================================================================== >--- Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj (revision 205305) >+++ Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj (working copy) >@@ -1300,10 +1300,14 @@ > 79233C2B1D34715700C5A834 /* JITMathIC.h in Headers */ = {isa = PBXBuildFile; fileRef = 79233C291D34715700C5A834 /* JITMathIC.h */; settings = {ATTRIBUTES = (Private, ); }; }; > 792CB3491C4EED5C00D13AF3 /* PCToCodeOriginMap.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 792CB3471C4EED5C00D13AF3 /* PCToCodeOriginMap.cpp */; }; > 792CB34A1C4EED5C00D13AF3 /* PCToCodeOriginMap.h in Headers */ = {isa = PBXBuildFile; fileRef = 792CB3481C4EED5C00D13AF3 /* PCToCodeOriginMap.h */; settings = {ATTRIBUTES = (Private, ); }; }; >+ 795B19971D78BE3500262FA0 /* MapBase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 795B19951D78BE3500262FA0 /* MapBase.cpp */; }; >+ 795B19981D78BE3500262FA0 /* MapBase.h in Headers */ = {isa = PBXBuildFile; fileRef = 795B19961D78BE3500262FA0 /* MapBase.h */; settings = {ATTRIBUTES = (Private, ); }; }; > 7964656A1B952FF0003059EE /* GetPutInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 796465681B952FF0003059EE /* GetPutInfo.h */; settings = {ATTRIBUTES = (Private, ); }; }; > 797E07A91B8FCFB9008400BA /* JSGlobalLexicalEnvironment.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 797E07A71B8FCFB9008400BA /* JSGlobalLexicalEnvironment.cpp */; }; > 797E07AA1B8FCFB9008400BA /* JSGlobalLexicalEnvironment.h in Headers */ = {isa = PBXBuildFile; fileRef = 797E07A81B8FCFB9008400BA /* JSGlobalLexicalEnvironment.h */; settings = {ATTRIBUTES = (Private, ); }; }; > 799EF7C41C56ED96002B0534 /* B3PCToOriginMap.h in Headers */ = {isa = PBXBuildFile; fileRef = 799EF7C31C56ED96002B0534 /* B3PCToOriginMap.h */; settings = {ATTRIBUTES = (Private, ); }; }; >+ 79A0907F1D768465008B889B /* HashMapImpl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 79A0907D1D768465008B889B /* HashMapImpl.cpp */; }; >+ 79A090801D768465008B889B /* HashMapImpl.h in Headers */ = {isa = PBXBuildFile; fileRef = 79A0907E1D768465008B889B /* HashMapImpl.h */; settings = {ATTRIBUTES = (Private, ); }; }; > 79A228351D35D71E00D8E067 /* ArithProfile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 79A228331D35D71E00D8E067 /* ArithProfile.cpp */; }; > 79A228361D35D71F00D8E067 /* ArithProfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 79A228341D35D71E00D8E067 /* ArithProfile.h */; }; > 79AF0BE41D3EFD4C00E95FA5 /* JITMathICInlineResult.h in Headers */ = {isa = PBXBuildFile; fileRef = 79AF0BE31D3EFD4C00E95FA5 /* JITMathICInlineResult.h */; settings = {ATTRIBUTES = (Private, ); }; }; >@@ -3533,10 +3537,14 @@ > 79233C291D34715700C5A834 /* JITMathIC.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JITMathIC.h; sourceTree = "<group>"; }; > 792CB3471C4EED5C00D13AF3 /* PCToCodeOriginMap.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PCToCodeOriginMap.cpp; sourceTree = "<group>"; }; > 792CB3481C4EED5C00D13AF3 /* PCToCodeOriginMap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PCToCodeOriginMap.h; sourceTree = "<group>"; }; >+ 795B19951D78BE3500262FA0 /* MapBase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MapBase.cpp; sourceTree = "<group>"; }; >+ 795B19961D78BE3500262FA0 /* MapBase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MapBase.h; sourceTree = "<group>"; }; > 796465681B952FF0003059EE /* GetPutInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GetPutInfo.h; sourceTree = "<group>"; }; > 797E07A71B8FCFB9008400BA /* JSGlobalLexicalEnvironment.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSGlobalLexicalEnvironment.cpp; sourceTree = "<group>"; }; > 797E07A81B8FCFB9008400BA /* JSGlobalLexicalEnvironment.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSGlobalLexicalEnvironment.h; sourceTree = "<group>"; }; > 799EF7C31C56ED96002B0534 /* B3PCToOriginMap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = B3PCToOriginMap.h; path = b3/B3PCToOriginMap.h; sourceTree = "<group>"; }; >+ 79A0907D1D768465008B889B /* HashMapImpl.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = HashMapImpl.cpp; sourceTree = "<group>"; }; >+ 79A0907E1D768465008B889B /* HashMapImpl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HashMapImpl.h; sourceTree = "<group>"; }; > 79A228331D35D71E00D8E067 /* ArithProfile.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ArithProfile.cpp; sourceTree = "<group>"; }; > 79A228341D35D71E00D8E067 /* ArithProfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ArithProfile.h; sourceTree = "<group>"; }; > 79A899FE1D38612E00D18C73 /* JITMathICForwards.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JITMathICForwards.h; sourceTree = "<group>"; }; >@@ -5774,6 +5782,8 @@ > 796465681B952FF0003059EE /* GetPutInfo.h */, > BC02E9B80E184545000F9297 /* GetterSetter.cpp */, > BC337BDE0E1AF0B80076918A /* GetterSetter.h */, >+ 79A0907D1D768465008B889B /* HashMapImpl.cpp */, >+ 79A0907E1D768465008B889B /* HashMapImpl.h */, > 933A349D038AE80F008635CE /* Identifier.cpp */, > 933A349A038AE7C6008635CE /* Identifier.h */, > 8606DDE918DA44AB00A383D0 /* IdentifierInlines.h */, >@@ -5982,6 +5992,8 @@ > A7E2EA690FB460CF00601F06 /* LiteralParser.h */, > F692A8680255597D01FF60F7 /* Lookup.cpp */, > F692A8690255597D01FF60F7 /* Lookup.h */, >+ 795B19951D78BE3500262FA0 /* MapBase.cpp */, >+ 795B19961D78BE3500262FA0 /* MapBase.h */, > A700873717CBE85300C3E643 /* MapConstructor.cpp */, > A700873817CBE85300C3E643 /* MapConstructor.h */, > A78507D517CBC6FD0011F6E7 /* MapData.h */, >@@ -7271,6 +7283,7 @@ > 0F64B27A1A7957B2006E4E66 /* CallEdge.h in Headers */, > 1429D8DE0ED2205B00B89619 /* CallFrame.h in Headers */, > 62EC9BB71B7EB07C00303AD1 /* CallFrameShuffleData.h in Headers */, >+ 795B19981D78BE3500262FA0 /* MapBase.h in Headers */, > 62D755D71B84FB4A001801FA /* CallFrameShuffler.h in Headers */, > 0F0B83B114BCF71800885B4F /* CallLinkInfo.h in Headers */, > 0F93329E14CA7DC50085F3C6 /* CallLinkStatus.h in Headers */, >@@ -7437,6 +7450,7 @@ > 0F9D339717FFC4E60073C2BC /* DFGFlushedAt.h in Headers */, > A7D89CF817A0B8CC00773AD8 /* DFGFlushFormat.h in Headers */, > 0F2DD8151AB3D8BE00BBB8E8 /* DFGForAllKills.h in Headers */, >+ 79A090801D768465008B889B /* HashMapImpl.h in Headers */, > 0F69CC89193AC60A0045759E /* DFGFrozenValue.h in Headers */, > 86EC9DC61328DF82002B2AD7 /* DFGGenerationInfo.h in Headers */, > 86EC9DC81328DF82002B2AD7 /* DFGGraph.h in Headers */, >@@ -9157,6 +9171,7 @@ > 0F0332C018ADFAE1005F979A /* ExitingJITType.cpp in Sources */, > 0FB105851675480F00F8AB6E /* ExitKind.cpp in Sources */, > 0FEA0A1C1708B00700BB722C /* FTLAbstractHeap.cpp in Sources */, >+ 79A0907F1D768465008B889B /* HashMapImpl.cpp in Sources */, > 0FEA0A1E1708B00700BB722C /* FTLAbstractHeapRepository.cpp in Sources */, > 0F93274D1C1F66AA00CF6564 /* GPRInfo.cpp in Sources */, > 0F485327187DFDEC0083B687 /* FTLAvailableRecovery.cpp in Sources */, >@@ -9201,6 +9216,7 @@ > 52B310FD1974AE870080857C /* FunctionHasExecutedCache.cpp in Sources */, > FE4BFF2B1AD476E700088F87 /* FunctionOverrides.cpp in Sources */, > 147F39CC107EC37600427A48 /* FunctionPrototype.cpp in Sources */, >+ 795B19971D78BE3500262FA0 /* MapBase.cpp in Sources */, > 62D2D38F1ADF103F000206C1 /* FunctionRareData.cpp in Sources */, > 2AACE63C18CA5A0300ED0191 /* GCActivityCallback.cpp in Sources */, > 0F766D2F15A8DCE0008F363E /* GCAwareJITStubRoutine.cpp in Sources */, >Index: Source/JavaScriptCore/bytecode/SpeculatedType.cpp >=================================================================== >--- Source/JavaScriptCore/bytecode/SpeculatedType.cpp (revision 205305) >+++ Source/JavaScriptCore/bytecode/SpeculatedType.cpp (working copy) >@@ -30,9 +30,11 @@ > #include "SpeculatedType.h" > > #include "DirectArguments.h" >+#include "JSCInlines.h" > #include "JSArray.h" > #include "JSFunction.h" >-#include "JSCInlines.h" >+#include "JSMap.h" >+#include "JSSet.h" > #include "ScopedArguments.h" > #include "StringObject.h" > #include "ValueProfile.h" >@@ -346,6 +348,12 @@ SpeculatedType speculationFromClassInfo( > > if (classInfo == RegExpObject::info()) > return SpecRegExpObject; >+ >+ if (classInfo == JSMap::info()) >+ return SpecMapObject; >+ >+ if (classInfo == JSSet::info()) >+ return SpecSetObject; > > if (classInfo->isSubClassOf(JSFunction::info())) > return SpecFunction; >Index: Source/JavaScriptCore/bytecode/SpeculatedType.h >=================================================================== >--- Source/JavaScriptCore/bytecode/SpeculatedType.h (revision 205305) >+++ Source/JavaScriptCore/bytecode/SpeculatedType.h (working copy) >@@ -39,41 +39,43 @@ class Structure; > > typedef uint64_t SpeculatedType; > static const SpeculatedType SpecNone = 0; // We don't know anything yet. >-static const SpeculatedType SpecFinalObject = 1u << 0; // It's definitely a JSFinalObject. >-static const SpeculatedType SpecArray = 1u << 1; // It's definitely a JSArray. >-static const SpeculatedType SpecFunction = 1u << 2; // It's definitely a JSFunction. >-static const SpeculatedType SpecInt8Array = 1u << 3; // It's definitely an Int8Array or one of its subclasses. >-static const SpeculatedType SpecInt16Array = 1u << 4; // It's definitely an Int16Array or one of its subclasses. >-static const SpeculatedType SpecInt32Array = 1u << 5; // It's definitely an Int32Array or one of its subclasses. >-static const SpeculatedType SpecUint8Array = 1u << 6; // It's definitely an Uint8Array or one of its subclasses. >-static const SpeculatedType SpecUint8ClampedArray = 1u << 7; // It's definitely an Uint8ClampedArray or one of its subclasses. >-static const SpeculatedType SpecUint16Array = 1u << 8; // It's definitely an Uint16Array or one of its subclasses. >-static const SpeculatedType SpecUint32Array = 1u << 9; // It's definitely an Uint32Array or one of its subclasses. >-static const SpeculatedType SpecFloat32Array = 1u << 10; // It's definitely an Uint16Array or one of its subclasses. >-static const SpeculatedType SpecFloat64Array = 1u << 11; // It's definitely an Uint16Array or one of its subclasses. >+static const SpeculatedType SpecFinalObject = 1ull << 0; // It's definitely a JSFinalObject. >+static const SpeculatedType SpecArray = 1ull << 1; // It's definitely a JSArray. >+static const SpeculatedType SpecFunction = 1ull << 2; // It's definitely a JSFunction. >+static const SpeculatedType SpecInt8Array = 1ull << 3; // It's definitely an Int8Array or one of its subclasses. >+static const SpeculatedType SpecInt16Array = 1ull << 4; // It's definitely an Int16Array or one of its subclasses. >+static const SpeculatedType SpecInt32Array = 1ull << 5; // It's definitely an Int32Array or one of its subclasses. >+static const SpeculatedType SpecUint8Array = 1ull << 6; // It's definitely an Uint8Array or one of its subclasses. >+static const SpeculatedType SpecUint8ClampedArray = 1ull << 7; // It's definitely an Uint8ClampedArray or one of its subclasses. >+static const SpeculatedType SpecUint16Array = 1ull << 8; // It's definitely an Uint16Array or one of its subclasses. >+static const SpeculatedType SpecUint32Array = 1ull << 9; // It's definitely an Uint32Array or one of its subclasses. >+static const SpeculatedType SpecFloat32Array = 1ull << 10; // It's definitely an Uint16Array or one of its subclasses. >+static const SpeculatedType SpecFloat64Array = 1ull << 11; // It's definitely an Uint16Array or one of its subclasses. > static const SpeculatedType SpecTypedArrayView = SpecInt8Array | SpecInt16Array | SpecInt32Array | SpecUint8Array | SpecUint8ClampedArray | SpecUint16Array | SpecUint32Array | SpecFloat32Array | SpecFloat64Array; >-static const SpeculatedType SpecDirectArguments = 1u << 12; // It's definitely a DirectArguments object. >-static const SpeculatedType SpecScopedArguments = 1u << 13; // It's definitely a ScopedArguments object. >-static const SpeculatedType SpecStringObject = 1u << 14; // It's definitely a StringObject. >-static const SpeculatedType SpecRegExpObject = 1u << 15; // It's definitely a RegExpObject (and not any subclass of RegExpObject). >-static const SpeculatedType SpecObjectOther = 1u << 16; // It's definitely an object but not JSFinalObject, JSArray, or JSFunction. >-static const SpeculatedType SpecObject = SpecFinalObject | SpecArray | SpecFunction | SpecTypedArrayView | SpecDirectArguments | SpecScopedArguments | SpecStringObject | SpecRegExpObject | SpecObjectOther; // Bitmask used for testing for any kind of object prediction. >-static const SpeculatedType SpecStringIdent = 1u << 17; // It's definitely a JSString, and it's an identifier. >-static const SpeculatedType SpecStringVar = 1u << 18; // It's definitely a JSString, and it's not an identifier. >+static const SpeculatedType SpecDirectArguments = 1ull << 12; // It's definitely a DirectArguments object. >+static const SpeculatedType SpecScopedArguments = 1ull << 13; // It's definitely a ScopedArguments object. >+static const SpeculatedType SpecStringObject = 1ull << 14; // It's definitely a StringObject. >+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 Map object (can it be a subclass? FIXME). >+static const SpeculatedType SpecSetObject = 1ull << 17; // It's definitely s Set object (can it be a subclass? FIXME). >+static const SpeculatedType SpecObjectOther = 1ull << 18; // 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 | SpecObjectOther; // Bitmask used for testing for any kind of object prediction. >+static const SpeculatedType SpecStringIdent = 1ull << 19; // It's definitely a JSString, and it's an identifier. >+static const SpeculatedType SpecStringVar = 1ull << 20; // 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 = 1u << 19; // It's definitely a Symbol. >-static const SpeculatedType SpecCellOther = 1u << 20; // It's definitely a JSCell but not a subclass of JSObject and definitely not a JSString or a Symbol. FIXME: This shouldn't be part of heap-top or bytecode-top. https://bugs.webkit.org/show_bug.cgi?id=133078 >+static const SpeculatedType SpecSymbol = 1ull << 21; // It's definitely a Symbol. >+static const SpeculatedType SpecCellOther = 1ull << 22; // It's definitely a JSCell but not a subclass of JSObject and definitely not a JSString or a Symbol. FIXME: This shouldn't be part of heap-top or bytecode-top. https://bugs.webkit.org/show_bug.cgi?id=133078 > static const SpeculatedType SpecCell = SpecObject | SpecString | SpecSymbol | SpecCellOther; // It's definitely a JSCell. >-static const SpeculatedType SpecBoolInt32 = 1u << 21; // It's definitely an Int32 with value 0 or 1. >-static const SpeculatedType SpecNonBoolInt32 = 1u << 22; // It's definitely an Int32 with value other than 0 or 1. >+static const SpeculatedType SpecBoolInt32 = 1ull << 23; // It's definitely an Int32 with value 0 or 1. >+static const SpeculatedType SpecNonBoolInt32 = 1ull << 24; // 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 = 1u << 23; // It's definitely an Int52 and we intend it to unbox it. It's also definitely not an Int32. >+static const SpeculatedType SpecInt52Only = 1ull << 25; // 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 = 1u << 24; // It's definitely an Int52 and it's inside a double. >-static const SpeculatedType SpecNonIntAsDouble = 1u << 25; // It's definitely not an Int52 but it's a real number and it's a double. >+static const SpeculatedType SpecAnyIntAsDouble = 1ull << 26; // It's definitely an Int52 and it's inside a double. >+static const SpeculatedType SpecNonIntAsDouble = 1ull << 27; // 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 = 1u << 26; // It's definitely a NaN that is sae to tag (i.e. pure). >-static const SpeculatedType SpecDoubleImpureNaN = 1u << 27; // It's definitely a NaN that is unsafe to tag (i.e. impure). >+static const SpeculatedType SpecDoublePureNaN = 1ull << 28; // It's definitely a NaN that is sae to tag (i.e. pure). >+static const SpeculatedType SpecDoubleImpureNaN = 1ull << 29; // 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. >@@ -81,12 +83,12 @@ static const SpeculatedType SpecBytecode > 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 = 1u << 28; // It's definitely a Boolean. >-static const SpeculatedType SpecOther = 1u << 29; // It's definitely either Null or Undefined. >+static const SpeculatedType SpecBoolean = 1ull << 30; // It's definitely a Boolean. >+static const SpeculatedType SpecOther = 1ull << 31; // 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 = 1u << 30; // It's definitely an empty value marker. >+static const SpeculatedType SpecEmpty = 1ull << 32; // 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. > >Index: Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h (revision 205305) >+++ Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h (working copy) >@@ -977,6 +977,22 @@ bool AbstractInterpreter<AbstractStateTy > break; > } > >+ case MapHash: >+ forNode(node).setType(SpecInt32Only); >+ break; >+ >+ case LoadFromJSMapBucket: >+ forNode(node).makeHeapTop(); >+ break; >+ >+ case GetMapBucket: >+ forNode(node).setType(m_graph, SpecCellOther); >+ break; >+ >+ case IsNonEmptyMapBucket: >+ forNode(node).setType(SpecBoolean); >+ break; >+ > case IsEmpty: > case IsJSArray: > case IsUndefined: >@@ -2883,7 +2899,7 @@ template<typename AbstractStateType> > bool AbstractInterpreter<AbstractStateType>::execute(unsigned indexInBlock) > { > Node* node = m_state.block()->at(indexInBlock); >- >+ > startExecuting(); > executeEdges(node); > return executeEffects(indexInBlock, node); >Index: Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp (revision 205305) >+++ Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp (working copy) >@@ -2538,7 +2538,37 @@ bool ByteCodeParser::handleIntrinsicCall > set(VirtualRegister(resultOperand), get(operand)); > return true; > } >- >+ >+ case JSMapGetIntrinsic: { >+ if (argumentCountIncludingThis != 2) >+ return false; >+ >+ insertChecks(); >+ Node* map = get(virtualRegisterForArgument(0, registerOffset)); >+ Node* key = get(virtualRegisterForArgument(1, registerOffset)); >+ Node* hash = addToGraph(MapHash, key); >+ Node* bucket = addToGraph(GetMapBucket, Edge(map, MapObjectUse), Edge(key), Edge(hash)); >+ Node* result = addToGraph(LoadFromJSMapBucket, OpInfo(), OpInfo(prediction), bucket); >+ set(VirtualRegister(resultOperand), result); >+ return true; >+ } >+ >+ case JSSetHasIntrinsic: >+ case JSMapHasIntrinsic: { >+ if (argumentCountIncludingThis != 2) >+ return false; >+ >+ insertChecks(); >+ Node* mapOrSet = get(virtualRegisterForArgument(0, registerOffset)); >+ Node* key = get(virtualRegisterForArgument(1, registerOffset)); >+ Node* hash = addToGraph(MapHash, key); >+ UseKind useKind = intrinsic == JSSetHasIntrinsic ? SetObjectUse : MapObjectUse; >+ Node* bucket = addToGraph(GetMapBucket, OpInfo(0), Edge(mapOrSet, useKind), Edge(key), Edge(hash)); >+ Node* result = addToGraph(IsNonEmptyMapBucket, bucket); >+ set(VirtualRegister(resultOperand), result); >+ return true; >+ } >+ > default: > return false; > } >Index: Source/JavaScriptCore/dfg/DFGClobberize.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGClobberize.h (revision 205305) >+++ Source/JavaScriptCore/dfg/DFGClobberize.h (working copy) >@@ -1243,6 +1243,27 @@ void clobberize(Graph& graph, Node* node > case LogShadowChickenTail: > write(SideState); > return; >+ >+ case MapHash: >+ def(PureValue(node)); >+ return; >+ case GetMapBucket: { >+ read(MiscFields); >+ Edge& mapEdge = node->child1(); >+ Edge& keyEdge = node->child2(); >+ def(HeapLocation(MapBucketLoc, MiscFields, mapEdge, keyEdge), LazyNode(node)); >+ return; >+ } >+ case LoadFromJSMapBucket: { >+ read(MiscFields); >+ Edge& bucketEdge = node->child1(); >+ def(HeapLocation(JSMapGetLoc, MiscFields, bucketEdge), LazyNode(node)); >+ return; >+ } >+ case IsNonEmptyMapBucket: >+ read(MiscFields); >+ def(HeapLocation(MapHasLoc, MiscFields, node->child1()), LazyNode(node)); >+ return; > > case LastNodeType: > RELEASE_ASSERT_NOT_REACHED(); >Index: Source/JavaScriptCore/dfg/DFGDoesGC.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGDoesGC.cpp (revision 205305) >+++ Source/JavaScriptCore/dfg/DFGDoesGC.cpp (working copy) >@@ -185,6 +185,10 @@ bool doesGC(Graph& graph, Node* node) > case ForceOSRExit: > case CheckWatchdogTimer: > case StringFromCharCode: >+ case MapHash: >+ case GetMapBucket: >+ case LoadFromJSMapBucket: >+ case IsNonEmptyMapBucket: > case Unreachable: > case ExtractOSREntryLocal: > case CheckTierUpInLoop: >Index: Source/JavaScriptCore/dfg/DFGEdge.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGEdge.h (revision 205305) >+++ Source/JavaScriptCore/dfg/DFGEdge.h (working copy) >@@ -189,7 +189,7 @@ private: > friend class AdjacencyList; > > #if USE(JSVALUE64) >- static uint32_t shift() { return 7; } >+ static constexpr uint32_t shift() { return 8; } > > static uintptr_t makeWord(Node* node, UseKind useKind, ProofStatus proofStatus, KillStatus killStatus) > { >@@ -197,8 +197,21 @@ private: > uintptr_t shiftedValue = bitwise_cast<uintptr_t>(node) << shift(); > ASSERT((shiftedValue >> shift()) == bitwise_cast<uintptr_t>(node)); > ASSERT(useKind >= 0 && useKind < LastUseKind); >- ASSERT((static_cast<uintptr_t>(LastUseKind) << 2) <= (static_cast<uintptr_t>(2) << shift())); >- return shiftedValue | (static_cast<uintptr_t>(useKind) << 2) | (DFG::doesKill(killStatus) << 1) | static_cast<uintptr_t>(DFG::isProved(proofStatus)); >+ static_assert((static_cast<uintptr_t>(LastUseKind) << 2) < (static_cast<uintptr_t>(1) << shift()), "We rely on this being true to not clobber the node pointer."); >+ uintptr_t result = shiftedValue | (static_cast<uintptr_t>(useKind) << 2) | (DFG::doesKill(killStatus) << 1) | static_cast<uintptr_t>(DFG::isProved(proofStatus)); >+ if (!ASSERT_DISABLED) { >+ union U { >+ U() { word = 0; } >+ uintptr_t word; >+ Edge edge; >+ } u; >+ u.word = result; >+ ASSERT(u.edge.useKindUnchecked() == useKind); >+ ASSERT(u.edge.node() == node); >+ ASSERT(u.edge.proofStatusUnchecked() == proofStatus); >+ ASSERT(u.edge.killStatusUnchecked() == killStatus); >+ } >+ return result; > } > > #else >Index: Source/JavaScriptCore/dfg/DFGFixupPhase.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGFixupPhase.cpp (revision 205305) >+++ Source/JavaScriptCore/dfg/DFGFixupPhase.cpp (working copy) >@@ -1545,6 +1545,29 @@ private: > break; > } > >+ case GetMapBucket: >+ if (node->child1().useKind() == MapObjectUse) >+ fixEdge<MapObjectUse>(node->child1()); >+ else if (node->child1().useKind() == SetObjectUse) >+ fixEdge<SetObjectUse>(node->child1()); >+ else >+ RELEASE_ASSERT_NOT_REACHED(); >+ fixEdge<UntypedUse>(node->child2()); >+ fixEdge<Int32Use>(node->child3()); >+ break; >+ >+ case LoadFromJSMapBucket: >+ fixEdge<KnownCellUse>(node->child1()); >+ break; >+ >+ case IsNonEmptyMapBucket: >+ fixEdge<KnownCellUse>(node->child1()); >+ break; >+ >+ case MapHash: >+ fixEdge<UntypedUse>(node->child1()); >+ break; >+ > #if !ASSERT_DISABLED > // Have these no-op cases here to ensure that nobody forgets to add handlers for new opcodes. > case SetArgument: >Index: Source/JavaScriptCore/dfg/DFGHeapLocation.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGHeapLocation.cpp (revision 205305) >+++ Source/JavaScriptCore/dfg/DFGHeapLocation.cpp (working copy) >@@ -143,6 +143,15 @@ void printInternal(PrintStream& out, Loc > case RegExpObjectLastIndexLoc: > out.print("RegExpObjectLastIndexLoc"); > return; >+ case MapBucketLoc: >+ out.print("MapBucketLoc"); >+ return; >+ case JSMapGetLoc: >+ out.print("JSMapGetLoc"); >+ return; >+ case MapHasLoc: >+ out.print("MapHasLoc"); >+ return; > } > > RELEASE_ASSERT_NOT_REACHED(); >Index: Source/JavaScriptCore/dfg/DFGHeapLocation.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGHeapLocation.h (revision 205305) >+++ Source/JavaScriptCore/dfg/DFGHeapLocation.h (working copy) >@@ -58,7 +58,10 @@ enum LocationKind { > StructureLoc, > TypedArrayByteOffsetLoc, > StackLoc, >- StackPayloadLoc >+ StackPayloadLoc, >+ MapBucketLoc, >+ JSMapGetLoc, >+ MapHasLoc > }; > > class HeapLocation { >Index: Source/JavaScriptCore/dfg/DFGNode.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGNode.h (revision 205305) >+++ Source/JavaScriptCore/dfg/DFGNode.h (working copy) >@@ -1419,6 +1419,7 @@ public: > case StringReplace: > case StringReplaceRegExp: > case ToNumber: >+ case LoadFromJSMapBucket: > return true; > default: > return false; >Index: Source/JavaScriptCore/dfg/DFGNodeType.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGNodeType.h (revision 205305) >+++ Source/JavaScriptCore/dfg/DFGNodeType.h (working copy) >@@ -388,7 +388,12 @@ namespace JSC { namespace DFG { > macro(GetPropertyEnumerator, NodeMustGenerate | NodeResultJS) \ > macro(GetEnumeratorStructurePname, NodeMustGenerate | NodeResultJS) \ > macro(GetEnumeratorGenericPname, NodeMustGenerate | NodeResultJS) \ >- macro(ToIndexString, NodeResultJS) >+ macro(ToIndexString, NodeResultJS) \ >+ /* Hashing nodes for JSMap and JSSet */ \ >+ macro(MapHash, NodeResultInt32) \ >+ macro(GetMapBucket, NodeResultJS) \ >+ macro(LoadFromJSMapBucket, NodeResultJS) \ >+ macro(IsNonEmptyMapBucket, NodeResultBoolean) \ > > // This enum generates a monotonically increasing id for all Node types, > // and is used by the subsequent enum to fill out the id (as accessed via the NodeIdMask). >Index: Source/JavaScriptCore/dfg/DFGOperations.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGOperations.cpp (revision 205305) >+++ Source/JavaScriptCore/dfg/DFGOperations.cpp (working copy) >@@ -50,6 +50,8 @@ > #include "JSCInlines.h" > #include "JSGenericTypedArrayViewConstructorInlines.h" > #include "JSLexicalEnvironment.h" >+#include "JSMap.h" >+#include "JSSet.h" > #include "ObjectConstructor.h" > #include "Repatch.h" > #include "ScopedArguments.h" >@@ -1803,6 +1805,34 @@ void JIT_OPERATION operationPutDynamicVa > scope->methodTable()->put(scope, exec, ident, JSValue::decode(value), slot); > } > >+int32_t JIT_OPERATION operationMapHash(ExecState* exec, EncodedJSValue input) >+{ >+ VM& vm = exec->vm(); >+ NativeCallFrameTracer tracer(&vm, exec); >+ >+ return jsMapHash(exec, vm, normalizeMapKey(JSValue::decode(input))); >+} >+ >+JSCell* JIT_OPERATION operationJSMapFindBucket(ExecState* exec, JSCell* map, EncodedJSValue key, int32_t hash) >+{ >+ VM& vm = exec->vm(); >+ NativeCallFrameTracer tracer(&vm, exec); >+ JSMap::BucketType** bucket = jsCast<JSMap*>(map)->findBucket(exec, JSValue::decode(key), hash); >+ if (!bucket) >+ return nullptr; >+ return *bucket; >+} >+ >+JSCell* JIT_OPERATION operationJSSetFindBucket(ExecState* exec, JSCell* map, EncodedJSValue key, int32_t hash) >+{ >+ VM& vm = exec->vm(); >+ NativeCallFrameTracer tracer(&vm, exec); >+ JSSet::BucketType** bucket = jsCast<JSSet*>(map)->findBucket(exec, JSValue::decode(key), hash); >+ if (!bucket) >+ return nullptr; >+ return *bucket; >+} >+ > extern "C" void JIT_OPERATION triggerReoptimizationNow(CodeBlock* codeBlock, OSRExitBase* exit) > { > // It's sort of preferable that we don't GC while in here. Anyways, doing so wouldn't >Index: Source/JavaScriptCore/dfg/DFGOperations.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGOperations.h (revision 205305) >+++ Source/JavaScriptCore/dfg/DFGOperations.h (working copy) >@@ -142,6 +142,10 @@ char* JIT_OPERATION operationEnsureArray > StringImpl* JIT_OPERATION operationResolveRope(ExecState*, JSString*); > JSString* JIT_OPERATION operationSingleCharacterString(ExecState*, int32_t); > >+int32_t JIT_OPERATION operationMapHash(ExecState*, EncodedJSValue input); >+JSCell* JIT_OPERATION operationJSMapFindBucket(ExecState*, JSCell*, EncodedJSValue, int32_t); >+JSCell* JIT_OPERATION operationJSSetFindBucket(ExecState*, JSCell*, EncodedJSValue, int32_t); >+ > JSCell* JIT_OPERATION operationNewStringObject(ExecState*, JSString*, Structure*); > JSCell* JIT_OPERATION operationToStringOnCell(ExecState*, JSCell*); > JSCell* JIT_OPERATION operationToString(ExecState*, EncodedJSValue); >Index: Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp (revision 205305) >+++ Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp (working copy) >@@ -711,6 +711,7 @@ private: > case GetGlobalLexicalVariable: > case GetClosureVar: > case GetFromArguments: >+ case LoadFromJSMapBucket: > case ToNumber: { > setPrediction(m_currentNode->getHeapPrediction()); > break; >@@ -741,6 +742,16 @@ private: > break; > } > >+ case MapHash: >+ setPrediction(SpecInt32Only); >+ break; >+ case GetMapBucket: >+ setPrediction(SpecCellOther); >+ break; >+ case IsNonEmptyMapBucket: >+ setPrediction(SpecBoolean); >+ break; >+ > case GetRestLength: { > setPrediction(SpecInt32Only); > break; >Index: Source/JavaScriptCore/dfg/DFGSafeToExecute.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGSafeToExecute.h (revision 205305) >+++ Source/JavaScriptCore/dfg/DFGSafeToExecute.h (working copy) >@@ -58,6 +58,8 @@ public: > case FunctionUse: > case FinalObjectUse: > case RegExpObjectUse: >+ case MapObjectUse: >+ case SetObjectUse: > case ObjectOrOtherUse: > case StringIdentUse: > case StringUse: >@@ -355,6 +357,10 @@ bool safeToExecute(AbstractStateType& st > case GetDynamicVar: > case PutDynamicVar: > case ResolveScope: >+ case MapHash: >+ case GetMapBucket: >+ case LoadFromJSMapBucket: >+ case IsNonEmptyMapBucket: > return true; > > case BottomValue: >Index: Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp (revision 205305) >+++ Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp (working copy) >@@ -37,6 +37,7 @@ > #include "DFGSlowPathGenerator.h" > #include "DirectArguments.h" > #include "GetterSetter.h" >+#include "HashMapImpl.h" > #include "JSEnvironmentRecord.h" > #include "JSLexicalEnvironment.h" > #include "JSPropertyNameEnumerator.h" >@@ -4720,6 +4721,82 @@ void SpeculativeJIT::compile(Node* node) > break; > } > >+ case MapHash: { >+ JSValueOperand input(this, node->child1()); >+ >+ JSValueRegs inputRegs = input.jsValueRegs(); >+ >+ GPRFlushedCallResult result(this); >+ GPRReg resultGPR = result.gpr(); >+ >+ flushRegisters(); >+ callOperation(operationMapHash, resultGPR, inputRegs); >+ m_jit.exceptionCheck(); >+ int32Result(resultGPR, node); >+ break; >+ } >+ >+ case GetMapBucket: { >+ SpeculateCellOperand map(this, node->child1()); >+ JSValueOperand key(this, node->child2()); >+ SpeculateInt32Operand hash(this, node->child3()); >+ GPRFlushedCallResult result(this); >+ >+ GPRReg mapGPR = map.gpr(); >+ JSValueRegs keyRegs = key.jsValueRegs(); >+ GPRReg hashGPR = hash.gpr(); >+ GPRReg resultGPR = result.gpr(); >+ >+ if (node->child1().useKind() == MapObjectUse) >+ speculateMapObject(node->child1(), mapGPR); >+ else if (node->child1().useKind() == SetObjectUse) >+ speculateSetObject(node->child1(), mapGPR); >+ else >+ RELEASE_ASSERT_NOT_REACHED(); >+ >+ flushRegisters(); >+ if (node->child1().useKind() == MapObjectUse) >+ callOperation(operationJSMapFindBucket, resultGPR, mapGPR, keyRegs, hashGPR); >+ else >+ callOperation(operationJSSetFindBucket, resultGPR, mapGPR, keyRegs, hashGPR); >+ m_jit.exceptionCheck(); >+ cellResult(resultGPR, node); >+ break; >+ } >+ >+ case LoadFromJSMapBucket: { >+ SpeculateCellOperand bucket(this, node->child1()); >+ GPRTemporary resultPayload(this); >+ GPRTemporary resultTag(this); >+ >+ GPRReg bucketGPR = bucket.gpr(); >+ GPRReg resultPayloadGPR = resultPayload.gpr(); >+ GPRReg resultTagGPR = resultTag.gpr(); >+ >+ auto notBucket = m_jit.branchTestPtr(MacroAssembler::Zero, bucketGPR); >+ m_jit.loadValue(MacroAssembler::Address(bucketGPR, HashMapBucket<HashMapBucketDataKeyValue>::offsetOfValue()), JSValueRegs(resultTagGPR, resultPayloadGPR)); >+ auto done = m_jit.jump(); >+ >+ notBucket.link(&m_jit); >+ m_jit.move(TrustedImm32(JSValue::UndefinedTag), resultTagGPR); >+ m_jit.move(TrustedImm32(0), resultPayloadGPR); >+ done.link(&m_jit); >+ jsValueResult(resultTagGPR, resultPayloadGPR, node); >+ break; >+ } >+ >+ case IsNonEmptyMapBucket: { >+ SpeculateCellOperand bucket(this, node->child1()); >+ GPRTemporary result(this); >+ >+ GPRReg bucketGPR = bucket.gpr(); >+ GPRReg resultGPR = result.gpr(); >+ >+ m_jit.comparePtr(MacroAssembler::NotEqual, bucketGPR, TrustedImm32(0), resultGPR); >+ booleanResult(resultGPR, node); >+ break; >+ } >+ > case Flush: > break; > >Index: Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp (revision 205305) >+++ Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp (working copy) >@@ -39,7 +39,9 @@ > #include "JSCInlines.h" > #include "JSEnvironmentRecord.h" > #include "JSLexicalEnvironment.h" >+#include "JSMap.h" > #include "JSPropertyNameEnumerator.h" >+#include "JSSet.h" > #include "ObjectPrototype.h" > #include "SetupVarargsFrame.h" > #include "SpillRegistersMode.h" >@@ -4615,6 +4617,168 @@ void SpeculativeJIT::compile(Node* node) > break; > } > >+ case MapHash: { >+ JSValueOperand input(this, node->child1()); >+ GPRTemporary temp(this); >+ GPRTemporary result(this); >+ >+ GPRReg inputGPR = input.gpr(); >+ GPRReg resultGPR = result.gpr(); >+ GPRReg tempGPR = temp.gpr(); >+ >+ MacroAssembler::JumpList straightHash; >+ MacroAssembler::JumpList done; >+ auto isNotCell = m_jit.branchIfNotCell(inputGPR); >+ MacroAssembler::JumpList slowPath; >+ straightHash.append(m_jit.branch8(MacroAssembler::NotEqual, MacroAssembler::Address(inputGPR, JSCell::typeInfoTypeOffset()), TrustedImm32(StringType))); >+ m_jit.loadPtr(MacroAssembler::Address(inputGPR, JSString::offsetOfValue()), resultGPR); >+ slowPath.append(m_jit.branchTestPtr(MacroAssembler::Zero, resultGPR)); >+ m_jit.load32(MacroAssembler::Address(resultGPR, StringImpl::flagsOffset()), resultGPR); >+ m_jit.urshift64(MacroAssembler::TrustedImm32(6), resultGPR); >+ slowPath.append(m_jit.branchTest32(MacroAssembler::Zero, resultGPR)); >+ done.append(m_jit.jump()); >+ >+ isNotCell.link(&m_jit); >+ straightHash.append(m_jit.branchIfNotNumber(inputGPR)); >+ straightHash.append(m_jit.branchIfInt32(JSValueRegs(inputGPR))); >+ slowPath.append(m_jit.jump()); >+ >+ straightHash.link(&m_jit); >+ m_jit.move(inputGPR, resultGPR); >+ m_jit.WangsInt64Hash(resultGPR, tempGPR); >+ done.append(m_jit.jump()); >+ >+ slowPath.link(&m_jit); >+ silentSpillAllRegisters(resultGPR); >+ callOperation(operationMapHash, resultGPR, inputGPR); >+ silentFillAllRegisters(resultGPR); >+ m_jit.exceptionCheck(); >+ >+ done.link(&m_jit); >+ int32Result(resultGPR, node); >+ break; >+ } >+ case GetMapBucket: { >+ SpeculateCellOperand map(this, node->child1()); >+ JSValueOperand key(this, node->child2()); >+ SpeculateInt32Operand hash(this, node->child3()); >+ GPRTemporary mask(this); >+ GPRTemporary index(this); >+ GPRTemporary buffer(this); >+ GPRTemporary bucket(this); >+ GPRTemporary result(this); >+ >+ GPRReg hashGPR = hash.gpr(); >+ GPRReg mapGPR = map.gpr(); >+ GPRReg maskGPR = mask.gpr(); >+ GPRReg indexGPR = index.gpr(); >+ GPRReg bufferGPR = buffer.gpr(); >+ GPRReg bucketGPR = bucket.gpr(); >+ GPRReg keyGPR = key.gpr(); >+ GPRReg resultGPR = result.gpr(); >+ >+ if (node->child1().useKind() == MapObjectUse) >+ speculateMapObject(node->child1(), mapGPR); >+ else if (node->child1().useKind() == SetObjectUse) >+ speculateSetObject(node->child1(), mapGPR); >+ else >+ RELEASE_ASSERT_NOT_REACHED(); >+ >+ m_jit.loadPtr(MacroAssembler::Address(mapGPR, node->child1().useKind() == MapObjectUse ? JSMap::offsetOfHashMapImpl() : JSSet::offsetOfHashMapImpl()), bufferGPR); >+ m_jit.load32(MacroAssembler::Address(bufferGPR, HashMapImpl<HashMapBucket<HashMapBucketDataKey>>::offsetOfCapacity()), maskGPR); >+ m_jit.loadPtr(MacroAssembler::Address(bufferGPR, HashMapImpl<HashMapBucket<HashMapBucketDataKey>>::offsetOfBuffer()), bufferGPR); >+ m_jit.sub32(TrustedImm32(1), maskGPR); >+ m_jit.move(hashGPR, indexGPR); >+ >+ MacroAssembler::Label loop = m_jit.label(); >+ MacroAssembler::JumpList done; >+ MacroAssembler::JumpList slowPathCases; >+ MacroAssembler::JumpList loopAround; >+ >+ m_jit.and32(maskGPR, indexGPR); >+ m_jit.loadPtr(MacroAssembler::BaseIndex(bufferGPR, indexGPR, MacroAssembler::TimesEight), bucketGPR); >+ m_jit.move(bucketGPR, resultGPR); >+ auto notPresentInTable = m_jit.branchPtr(MacroAssembler::Equal, >+ bucketGPR, TrustedImmPtr(HashMapImpl<HashMapBucket<HashMapBucketDataKey>>::emptyValue())); >+ loopAround.append(m_jit.branchPtr(MacroAssembler::Equal, >+ bucketGPR, TrustedImmPtr(HashMapImpl<HashMapBucket<HashMapBucketDataKey>>::deletedValue()))); >+ >+ m_jit.load64(MacroAssembler::Address(bucketGPR, HashMapBucket<HashMapBucketDataKey>::offsetOfKey()), bucketGPR); >+ >+ // Perform Object.is() >+ done.append(m_jit.branch64(MacroAssembler::Equal, bucketGPR, keyGPR)); // They're definitely the same value, we found the bucket we were looking for! >+ auto oneIsntCell = m_jit.branchIfNotCell(JSValueRegs(bucketGPR)); >+ // first is a cell here. >+ loopAround.append(m_jit.branchIfNotCell(JSValueRegs(keyGPR))); >+ // Both are cells here. >+ loopAround.append(m_jit.branch8(JITCompiler::NotEqual, >+ JITCompiler::Address(bucketGPR, JSCell::typeInfoTypeOffset()), TrustedImm32(StringType))); >+ // The first is a string here. >+ slowPathCases.append(m_jit.branch8(JITCompiler::Equal, >+ JITCompiler::Address(keyGPR, JSCell::typeInfoTypeOffset()), TrustedImm32(StringType))); >+ // The first is a string, but the second is not, we continue to loop around. >+ loopAround.append(m_jit.jump()); >+ >+ oneIsntCell.link(&m_jit); >+ // We've already done a 64-bit compare at this point, so if one is not a number, they're definitely not equal. >+ loopAround.append(m_jit.branchIfNotNumber(bucketGPR)); >+ loopAround.append(m_jit.branchIfNotNumber(keyGPR)); >+ // Both are definitely numbers. If we see a double, we go to the slow path. >+ slowPathCases.append(m_jit.branchIfNotInt32(bucketGPR)); >+ slowPathCases.append(m_jit.branchIfNotInt32(keyGPR)); >+ >+ loopAround.link(&m_jit); >+ m_jit.add32(TrustedImm32(1), indexGPR); >+ m_jit.jump().linkTo(loop, &m_jit); >+ >+ slowPathCases.link(&m_jit); >+ silentSpillAllRegisters(indexGPR); >+ if (node->child1().useKind() == MapObjectUse) >+ callOperation(operationJSMapFindBucket, resultGPR, mapGPR, keyGPR, hashGPR); >+ else >+ callOperation(operationJSSetFindBucket, resultGPR, mapGPR, keyGPR, hashGPR); >+ silentFillAllRegisters(indexGPR); >+ m_jit.exceptionCheck(); >+ done.append(m_jit.jump()); >+ >+ notPresentInTable.link(&m_jit); >+ m_jit.move(TrustedImmPtr(nullptr), resultGPR); >+ done.link(&m_jit); >+ cellResult(resultGPR, node); >+ break; >+ } >+ >+ case LoadFromJSMapBucket: { >+ SpeculateCellOperand bucket(this, node->child1()); >+ GPRTemporary result(this); >+ >+ GPRReg bucketGPR = bucket.gpr(); >+ GPRReg resultGPR = result.gpr(); >+ >+ auto notBucket = m_jit.branchTestPtr(MacroAssembler::Zero, bucketGPR); >+ m_jit.load64(MacroAssembler::Address(bucketGPR, HashMapBucket<HashMapBucketDataKeyValue>::offsetOfValue()), resultGPR); >+ auto done = m_jit.jump(); >+ >+ notBucket.link(&m_jit); >+ m_jit.move(MacroAssembler::TrustedImm64(JSValue::encode(jsUndefined())), resultGPR); >+ done.link(&m_jit); >+ jsValueResult(resultGPR, node); >+ break; >+ } >+ >+ case IsNonEmptyMapBucket: { >+ SpeculateCellOperand bucket(this, node->child1()); >+ GPRTemporary result(this); >+ >+ GPRReg bucketGPR = bucket.gpr(); >+ GPRReg resultGPR = result.gpr(); >+ >+ m_jit.comparePtr(MacroAssembler::NotEqual, bucketGPR, TrustedImm32(0), resultGPR); >+ m_jit.or32(TrustedImm32(ValueFalse), resultGPR); >+ jsValueResult(resultGPR, node, DataFormatJSBoolean); >+ break; >+ } >+ > case IsObject: { > JSValueOperand value(this, node->child1()); > GPRTemporary result(this, Reuse, value); >Index: Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp (revision 205305) >+++ Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp (working copy) >@@ -7381,6 +7381,34 @@ void SpeculativeJIT::speculateRegExpObje > speculateRegExpObject(edge, operand.gpr()); > } > >+void SpeculativeJIT::speculateMapObject(Edge edge, GPRReg cell) >+{ >+ speculateCellType(edge, cell, SpecMapObject, JSMapType); >+} >+ >+void SpeculativeJIT::speculateMapObject(Edge edge) >+{ >+ if (!needsTypeCheck(edge, SpecMapObject)) >+ return; >+ >+ SpeculateCellOperand operand(this, edge); >+ speculateMapObject(edge, operand.gpr()); >+} >+ >+void SpeculativeJIT::speculateSetObject(Edge edge, GPRReg cell) >+{ >+ speculateCellType(edge, cell, SpecSetObject, JSSetType); >+} >+ >+void SpeculativeJIT::speculateSetObject(Edge edge) >+{ >+ if (!needsTypeCheck(edge, SpecSetObject)) >+ return; >+ >+ SpeculateCellOperand operand(this, edge); >+ speculateSetObject(edge, operand.gpr()); >+} >+ > void SpeculativeJIT::speculateObjectOrOther(Edge edge) > { > if (!needsTypeCheck(edge, SpecObject | SpecOther)) >@@ -7668,6 +7696,12 @@ void SpeculativeJIT::speculate(Node*, Ed > case RegExpObjectUse: > speculateRegExpObject(edge); > break; >+ case MapObjectUse: >+ speculateMapObject(edge); >+ break; >+ case SetObjectUse: >+ speculateSetObject(edge); >+ break; > case ObjectOrOtherUse: > speculateObjectOrOther(edge); > break; >Index: Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h (revision 205305) >+++ Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h (working copy) >@@ -1291,6 +1291,12 @@ public: > > #if USE(JSVALUE64) > >+ JITCompiler::Call callOperation(C_JITOperation_ECJZ operation, GPRReg result, GPRReg arg1, GPRReg arg2, GPRReg arg3) >+ { >+ m_jit.setupArgumentsWithExecState(arg1, arg2, arg3); >+ return appendCallSetResult(operation, result); >+ } >+ > JITCompiler::Call callOperation(J_JITOperation_EJJMic operation, JSValueRegs result, JSValueRegs arg1, JSValueRegs arg2, TrustedImmPtr mathIC) > { > m_jit.setupArgumentsWithExecState(arg1.gpr(), arg2.gpr(), mathIC); >@@ -1671,6 +1677,12 @@ public: > return appendCall(operation); > } > >+ JITCompiler::Call callOperation(Z_JITOperation_EJ operation, GPRReg result, GPRReg arg1) >+ { >+ m_jit.setupArgumentsWithExecState(arg1); >+ return appendCallSetResult(operation, result); >+ } >+ > JITCompiler::Call callOperation(Z_JITOperation_EJZZ operation, GPRReg result, GPRReg arg1, unsigned arg2, unsigned arg3) > { > m_jit.setupArgumentsWithExecState(arg1, TrustedImm32(arg2), TrustedImm32(arg3)); >@@ -1719,6 +1731,18 @@ public: > } > #else // USE(JSVALUE32_64) > >+ JITCompiler::Call callOperation(C_JITOperation_ECJZ operation, GPRReg result, GPRReg arg1, JSValueRegs arg2, GPRReg arg3) >+ { >+ m_jit.setupArgumentsWithExecState(arg1, arg2.payloadGPR(), arg2.tagGPR(), arg3); >+ return appendCallSetResult(operation, result); >+ } >+ >+ JITCompiler::Call callOperation(Z_JITOperation_EJ operation, GPRReg result, JSValueRegs arg1) >+ { >+ m_jit.setupArgumentsWithExecState(EABI_32BIT_DUMMY_ARG arg1.payloadGPR(), arg1.tagGPR()); >+ return appendCallSetResult(operation, result); >+ } >+ > JITCompiler::Call callOperation(J_JITOperation_EJJMic operation, JSValueRegs result, JSValueRegs arg1, JSValueRegs arg2, TrustedImmPtr mathIC) > { > m_jit.setupArgumentsWithExecState(EABI_32BIT_DUMMY_ARG arg1.payloadGPR(), arg1.tagGPR(), arg2.payloadGPR(), arg2.tagGPR(), mathIC); >@@ -2656,6 +2680,10 @@ public: > void speculateFinalObject(Edge); > void speculateRegExpObject(Edge, GPRReg cell); > void speculateRegExpObject(Edge); >+ void speculateMapObject(Edge); >+ void speculateMapObject(Edge, GPRReg cell); >+ void speculateSetObject(Edge); >+ void speculateSetObject(Edge, GPRReg cell); > void speculateObjectOrOther(Edge); > void speculateString(Edge edge, GPRReg cell); > void speculateStringIdentAndLoadStorage(Edge edge, GPRReg string, GPRReg storage); >Index: Source/JavaScriptCore/dfg/DFGUseKind.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGUseKind.cpp (revision 205305) >+++ Source/JavaScriptCore/dfg/DFGUseKind.cpp (working copy) >@@ -94,6 +94,12 @@ void printInternal(PrintStream& out, Use > case RegExpObjectUse: > out.print("RegExpObject"); > return; >+ case MapObjectUse: >+ out.print("MapObjectUse"); >+ return; >+ case SetObjectUse: >+ out.print("SetObjectUse"); >+ return; > case ObjectOrOtherUse: > out.print("ObjectOrOther"); > return; >Index: Source/JavaScriptCore/dfg/DFGUseKind.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGUseKind.h (revision 205305) >+++ Source/JavaScriptCore/dfg/DFGUseKind.h (working copy) >@@ -63,6 +63,8 @@ enum UseKind { > KnownStringUse, > KnownPrimitiveUse, // This bizarre type arises for op_strcat, which has a bytecode guarantee that it will only see primitives (i.e. not objects). > SymbolUse, >+ MapObjectUse, >+ SetObjectUse, > StringObjectUse, > StringOrStringObjectUse, > NotStringVarUse, >@@ -134,6 +136,10 @@ inline SpeculatedType typeFilterFor(UseK > return SpecHeapTop & ~SpecObject; > case SymbolUse: > return SpecSymbol; >+ case MapObjectUse: >+ return SpecMapObject; >+ case SetObjectUse: >+ return SpecSetObject; > case StringObjectUse: > return SpecStringObject; > case StringOrStringObjectUse: >@@ -221,6 +227,8 @@ inline bool isCell(UseKind kind) > case SymbolUse: > case StringObjectUse: > case StringOrStringObjectUse: >+ case MapObjectUse: >+ case SetObjectUse: > return true; > default: > return false; >Index: Source/JavaScriptCore/ftl/FTLAbstractHeapRepository.h >=================================================================== >--- Source/JavaScriptCore/ftl/FTLAbstractHeapRepository.h (revision 205305) >+++ Source/JavaScriptCore/ftl/FTLAbstractHeapRepository.h (working copy) >@@ -32,6 +32,8 @@ > #include "DFGArrayMode.h" > #include "FTLAbstractHeap.h" > #include "IndexingType.h" >+#include "JSMap.h" >+#include "JSSet.h" > > namespace JSC { namespace FTL { > >@@ -102,7 +104,13 @@ namespace JSC { namespace FTL { > macro(Structure_classInfo, Structure::classInfoOffset()) \ > macro(Structure_globalObject, Structure::globalObjectOffset()) \ > macro(Structure_prototype, Structure::prototypeOffset()) \ >- macro(Structure_structureID, Structure::structureIDOffset()) >+ macro(Structure_structureID, Structure::structureIDOffset()) \ >+ macro(JSMap_hashMapImpl, JSMap::offsetOfHashMapImpl()) \ >+ macro(JSSet_hashMapImpl, JSSet::offsetOfHashMapImpl()) \ >+ macro(HashMapImpl_capacity, HashMapImpl<HashMapBucket<HashMapBucketDataKey>>::offsetOfCapacity()) \ >+ macro(HashMapImpl_buffer, HashMapImpl<HashMapBucket<HashMapBucketDataKey>>::offsetOfBuffer()) \ >+ macro(HashMapBucket_value, HashMapBucket<HashMapBucketDataKeyValue>::offsetOfValue()) \ >+ macro(HashMapBucket_key, HashMapBucket<HashMapBucketDataKeyValue>::offsetOfKey()) \ > > #define FOR_EACH_INDEXED_ABSTRACT_HEAP(macro) \ > macro(DirectArguments_storage, DirectArguments::storageOffset(), sizeof(EncodedJSValue)) \ >Index: Source/JavaScriptCore/ftl/FTLCapabilities.cpp >=================================================================== >--- Source/JavaScriptCore/ftl/FTLCapabilities.cpp (revision 205305) >+++ Source/JavaScriptCore/ftl/FTLCapabilities.cpp (working copy) >@@ -180,6 +180,10 @@ inline CapabilityLevel canCompile(Node* > case ThrowReferenceError: > case Unreachable: > case IsJSArray: >+ case MapHash: >+ case GetMapBucket: >+ case LoadFromJSMapBucket: >+ case IsNonEmptyMapBucket: > case IsEmpty: > case IsUndefined: > case IsBoolean: >@@ -437,6 +441,8 @@ CapabilityLevel canCompile(Graph& graph) > case StringObjectUse: > case StringOrStringObjectUse: > case SymbolUse: >+ case MapObjectUse: >+ case SetObjectUse: > case FinalObjectUse: > case RegExpObjectUse: > case NotCellUse: >Index: Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp >=================================================================== >--- Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp (revision 205305) >+++ Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp (working copy) >@@ -70,6 +70,7 @@ > #include "JSCInlines.h" > #include "JSGeneratorFunction.h" > #include "JSLexicalEnvironment.h" >+#include "JSMap.h" > #include "OperandsInlines.h" > #include "ScopedArguments.h" > #include "ScopedArgumentsTable.h" >@@ -898,6 +899,18 @@ private: > case IsJSArray: > compileIsJSArray(); > break; >+ case MapHash: >+ compileMapHash(); >+ break; >+ case GetMapBucket: >+ compileGetMapBucket(); >+ break; >+ case LoadFromJSMapBucket: >+ compileLoadFromJSMapBucket(); >+ break; >+ case IsNonEmptyMapBucket: >+ compileIsNonEmptyMapBucket(); >+ break; > case IsObject: > compileIsObject(); > break; >@@ -6351,6 +6364,228 @@ private: > setBoolean(m_out.phi(Int32, notCellResult, cellResult)); > } > >+ void compileMapHash() >+ { >+ LValue value = lowJSValue(m_node->child1()); >+ >+ LBasicBlock isCellCase = m_out.newBlock(); >+ LBasicBlock notCell = m_out.newBlock(); >+ LBasicBlock slowCase = m_out.newBlock(); >+ LBasicBlock straightHash = m_out.newBlock(); >+ LBasicBlock isNumberCase = m_out.newBlock(); >+ LBasicBlock isStringCase = m_out.newBlock(); >+ LBasicBlock nonEmptyStringCase = m_out.newBlock(); >+ LBasicBlock continuation = m_out.newBlock(); >+ >+ m_out.branch( >+ isCell(value, provenType(m_node->child1())), unsure(isCellCase), unsure(notCell)); >+ >+ LBasicBlock lastNext = m_out.appendTo(isCellCase, isStringCase); >+ LValue isString = m_out.equal(m_out.load8ZeroExt32(value, m_heaps.JSCell_typeInfoType), m_out.constInt32(StringType)); >+ m_out.branch( >+ isString, unsure(isStringCase), unsure(straightHash)); >+ >+ m_out.appendTo(isStringCase, nonEmptyStringCase); >+ LValue stringImpl = m_out.loadPtr(value, m_heaps.JSString_value); >+ m_out.branch( >+ m_out.equal(stringImpl, m_out.constIntPtr(0)), rarely(slowCase), usually(nonEmptyStringCase)); >+ >+ m_out.appendTo(nonEmptyStringCase, notCell); >+ LValue hash = m_out.lShr(m_out.load32(stringImpl, m_heaps.StringImpl_hashAndFlags), m_out.constInt32(6)); >+ ValueFromBlock nonEmptyStringHashResult = m_out.anchor(hash); >+ m_out.branch(m_out.equal(hash, m_out.constInt32(0)), >+ rarely(slowCase), usually(continuation)); >+ >+ m_out.appendTo(notCell, isNumberCase); >+ m_out.branch( >+ isNumber(value), unsure(isNumberCase), unsure(straightHash)); >+ >+ m_out.appendTo(isNumberCase, straightHash); >+ m_out.branch( >+ isInt32(value), unsure(straightHash), unsure(slowCase)); >+ >+ m_out.appendTo(straightHash, slowCase); >+ // key += ~(key << 32); >+ LValue key = value; >+ LValue temp = key; >+ temp = m_out.shl(temp, m_out.constInt32(32)); >+ temp = m_out.bitNot(temp); >+ key = m_out.add(key, temp); >+ // key ^= (key >> 22); >+ temp = key; >+ temp = m_out.lShr(temp, m_out.constInt32(22)); >+ key = m_out.bitXor(key, temp); >+ // key += ~(key << 13); >+ temp = key; >+ temp = m_out.shl(temp, m_out.constInt32(13)); >+ temp = m_out.bitNot(temp); >+ key = m_out.add(key, temp); >+ // key ^= (key >> 8); >+ temp = key; >+ temp = m_out.lShr(temp, m_out.constInt32(8)); >+ key = m_out.bitXor(key, temp); >+ // key += (key << 3); >+ temp = key; >+ temp = m_out.shl(temp, m_out.constInt32(3)); >+ key = m_out.add(key, temp); >+ // key ^= (key >> 15); >+ temp = key; >+ temp = m_out.lShr(temp, m_out.constInt32(15)); >+ key = m_out.bitXor(key, temp); >+ // key += ~(key << 27); >+ temp = key; >+ temp = m_out.shl(temp, m_out.constInt32(27)); >+ temp = m_out.bitNot(temp); >+ key = m_out.add(key, temp); >+ // key ^= (key >> 31); >+ temp = key; >+ temp = m_out.lShr(temp, m_out.constInt32(31)); >+ key = m_out.bitXor(key, temp); >+ key = m_out.castToInt32(key); >+ >+ ValueFromBlock fastResult = m_out.anchor(key); >+ m_out.jump(continuation); >+ >+ m_out.appendTo(slowCase, continuation); >+ ValueFromBlock slowResult = m_out.anchor( >+ vmCall(Int32, m_out.operation(operationMapHash), m_callFrame, value)); >+ m_out.jump(continuation); >+ >+ m_out.appendTo(continuation, lastNext); >+ setInt32(m_out.phi(Int32, fastResult, slowResult, nonEmptyStringHashResult)); >+ } >+ >+ void compileGetMapBucket() >+ { >+ >+ LBasicBlock loopStart = m_out.newBlock(); >+ LBasicBlock loopAround = m_out.newBlock(); >+ LBasicBlock slowPath = m_out.newBlock(); >+ LBasicBlock notPresentInTable = m_out.newBlock(); >+ LBasicBlock notEmptyValue = m_out.newBlock(); >+ LBasicBlock notDeletedValue = m_out.newBlock(); >+ LBasicBlock notBitEqual = m_out.newBlock(); >+ LBasicBlock bucketKeyNotCell = m_out.newBlock(); >+ LBasicBlock bucketKeyIsCell = m_out.newBlock(); >+ LBasicBlock bothAreCells = m_out.newBlock(); >+ LBasicBlock bucketKeyIsString = m_out.newBlock(); >+ LBasicBlock bucketKeyIsNumber = m_out.newBlock(); >+ LBasicBlock bothAreNumbers = m_out.newBlock(); >+ LBasicBlock bucketKeyIsInt32 = m_out.newBlock(); >+ LBasicBlock continuation = m_out.newBlock(); >+ >+ LValue map; >+ if (m_node->child1().useKind() == MapObjectUse) >+ map = lowMapObject(m_node->child1()); >+ else if (m_node->child1().useKind() == SetObjectUse) >+ map = lowSetObject(m_node->child1()); >+ else >+ RELEASE_ASSERT_NOT_REACHED(); >+ >+ LValue key = lowJSValue(m_node->child2()); >+ LValue hash = lowInt32(m_node->child3()); >+ >+ LValue hashMapImpl = m_out.loadPtr(map, m_node->child1().useKind() == MapObjectUse ? m_heaps.JSMap_hashMapImpl : m_heaps.JSSet_hashMapImpl); >+ LValue buffer = m_out.loadPtr(hashMapImpl, m_heaps.HashMapImpl_buffer); >+ LValue mask = m_out.sub(m_out.load32(hashMapImpl, m_heaps.HashMapImpl_capacity), m_out.int32One); >+ >+ ValueFromBlock indexStart = m_out.anchor(hash); >+ m_out.jump(loopStart); >+ >+ LBasicBlock lastNext = m_out.appendTo(loopStart, notEmptyValue); >+ LValue unmaskedIndex = m_out.phi(Int32, indexStart); >+ LValue index = m_out.bitAnd(mask, unmaskedIndex); >+ LValue hashMapBucket = m_out.load64(m_out.baseIndex(m_heaps.properties.atAnyNumber(), buffer, m_out.zeroExt(index, Int64), ScaleEight)); >+ ValueFromBlock bucketResult = m_out.anchor(hashMapBucket); >+ m_out.branch(m_out.equal(hashMapBucket, m_out.constIntPtr(HashMapImpl<HashMapBucket<HashMapBucketDataKey>>::emptyValue())), >+ unsure(notPresentInTable), unsure(notEmptyValue)); >+ >+ m_out.appendTo(notEmptyValue, notDeletedValue); >+ m_out.branch(m_out.equal(hashMapBucket, m_out.constIntPtr(HashMapImpl<HashMapBucket<HashMapBucketDataKey>>::deletedValue())), >+ unsure(loopAround), unsure(notDeletedValue)); >+ >+ m_out.appendTo(notDeletedValue, notBitEqual); >+ LValue bucketKey = m_out.load64(hashMapBucket, m_heaps.HashMapBucket_key); >+ // Perform Object.is() >+ m_out.branch(m_out.equal(key, bucketKey), >+ unsure(continuation), unsure(notBitEqual)); >+ >+ m_out.appendTo(notBitEqual, bucketKeyIsCell); >+ m_out.branch(isCell(bucketKey), >+ unsure(bucketKeyIsCell), unsure(bucketKeyNotCell)); >+ >+ m_out.appendTo(bucketKeyIsCell, bothAreCells); >+ m_out.branch(isCell(key), >+ unsure(bothAreCells), unsure(loopAround)); >+ >+ m_out.appendTo(bothAreCells, bucketKeyIsString); >+ m_out.branch(isString(bucketKey), >+ unsure(bucketKeyIsString), unsure(loopAround)); >+ >+ m_out.appendTo(bucketKeyIsString, bucketKeyNotCell); >+ m_out.branch(isString(key), >+ unsure(slowPath), unsure(loopAround)); >+ >+ m_out.appendTo(bucketKeyNotCell, bucketKeyIsNumber); >+ m_out.branch(isNotNumber(bucketKey), >+ unsure(loopAround), unsure(bucketKeyIsNumber)); >+ >+ m_out.appendTo(bucketKeyIsNumber, bothAreNumbers); >+ m_out.branch(isNotNumber(key), >+ unsure(loopAround), unsure(bothAreNumbers)); >+ >+ m_out.appendTo(bothAreNumbers, bucketKeyIsInt32); >+ m_out.branch(isNotInt32(bucketKey), >+ unsure(slowPath), unsure(bucketKeyIsInt32)); >+ >+ m_out.appendTo(bucketKeyIsInt32, loopAround); >+ m_out.branch(isNotInt32(key), >+ unsure(slowPath), unsure(loopAround)); >+ >+ m_out.appendTo(loopAround, slowPath); >+ m_out.addIncomingToPhi(unmaskedIndex, m_out.anchor(m_out.add(index, m_out.int32One))); >+ m_out.jump(loopStart); >+ >+ m_out.appendTo(slowPath, notPresentInTable); >+ ValueFromBlock slowPathResult = m_out.anchor(vmCall(pointerType(), >+ m_out.operation(m_node->child1().useKind() == MapObjectUse ? operationJSMapFindBucket : operationJSSetFindBucket), m_callFrame, map, key, hash)); >+ m_out.jump(continuation); >+ >+ m_out.appendTo(notPresentInTable, continuation); >+ ValueFromBlock notPresentResult = m_out.anchor(m_out.constIntPtr(0)); >+ m_out.jump(continuation); >+ >+ m_out.appendTo(continuation, lastNext); >+ setMapBucket(m_out.phi(pointerType(), bucketResult, slowPathResult, notPresentResult)); >+ } >+ >+ void compileLoadFromJSMapBucket() >+ { >+ LValue mapBucket = lowMapBucket(m_node->child1()); >+ >+ LBasicBlock continuation = m_out.newBlock(); >+ LBasicBlock hasBucket = m_out.newBlock(); >+ >+ ValueFromBlock noBucketResult = m_out.anchor(m_out.constInt64(JSValue::encode(jsUndefined()))); >+ >+ m_out.branch(m_out.equal(mapBucket, m_out.constIntPtr(0)), >+ unsure(continuation), unsure(hasBucket)); >+ >+ LBasicBlock lastNext = m_out.appendTo(hasBucket, continuation); >+ ValueFromBlock bucketResult = m_out.anchor(m_out.load64(mapBucket, m_heaps.HashMapBucket_value)); >+ m_out.jump(continuation); >+ >+ m_out.appendTo(continuation, lastNext); >+ setJSValue(m_out.phi(Int64, noBucketResult, bucketResult)); >+ } >+ >+ void compileIsNonEmptyMapBucket() >+ { >+ LValue bucket = lowMapBucket(m_node->child1()); >+ LValue result = m_out.notEqual(bucket, m_out.constIntPtr(0)); >+ setBoolean(result); >+ } >+ > void compileIsObjectOrNull() > { > JSGlobalObject* globalObject = m_graph.globalObjectFor(m_node->origin.semantic); >@@ -9928,6 +10163,20 @@ private: > speculateRegExpObject(edge, result); > return result; > } >+ >+ LValue lowMapObject(Edge edge) >+ { >+ LValue result = lowCell(edge); >+ speculateMapObject(edge, result); >+ return result; >+ } >+ >+ LValue lowSetObject(Edge edge) >+ { >+ LValue result = lowCell(edge); >+ speculateSetObject(edge, result); >+ return result; >+ } > > LValue lowString(Edge edge, OperandSpeculationMode mode = AutomaticOperandSpeculation) > { >@@ -10051,6 +10300,17 @@ private: > setStorage(edge.node(), result); > return result; > } >+ >+ LValue lowMapBucket(Edge edge) >+ { >+ LoweredNodeValue value = m_mapBucketValues.get(edge.node()); >+ if (isValid(value)) >+ return value.value(); >+ >+ LValue result = lowCell(edge); >+ setStorage(edge.node(), result); >+ return result; >+ } > > LValue strictInt52ToInt32(Edge edge, LValue value) > { >@@ -10354,6 +10614,12 @@ private: > case RegExpObjectUse: > speculateRegExpObject(edge); > break; >+ case MapObjectUse: >+ speculateMapObject(edge); >+ break; >+ case SetObjectUse: >+ speculateSetObject(edge); >+ break; > case StringUse: > speculateString(edge); > break; >@@ -10682,6 +10948,28 @@ private: > { > speculateRegExpObject(edge, lowCell(edge)); > } >+ >+ void speculateMapObject(Edge edge, LValue cell) >+ { >+ FTL_TYPE_CHECK( >+ jsValueValue(cell), edge, SpecMapObject, isNotType(cell, JSMapType)); >+ } >+ >+ void speculateMapObject(Edge edge) >+ { >+ speculateMapObject(edge, lowCell(edge)); >+ } >+ >+ void speculateSetObject(Edge edge, LValue cell) >+ { >+ FTL_TYPE_CHECK( >+ jsValueValue(cell), edge, SpecSetObject, isNotType(cell, JSSetType)); >+ } >+ >+ void speculateSetObject(Edge edge) >+ { >+ speculateSetObject(edge, lowCell(edge)); >+ } > > void speculateString(Edge edge, LValue cell) > { >@@ -11450,6 +11738,10 @@ private: > { > m_storageValues.set(node, LoweredNodeValue(value, m_highBlock)); > } >+ void setMapBucket(Node* node, LValue value) >+ { >+ m_mapBucketValues.set(node, LoweredNodeValue(value, m_highBlock)); >+ } > void setDouble(Node* node, LValue value) > { > m_doubleValues.set(node, LoweredNodeValue(value, m_highBlock)); >@@ -11483,6 +11775,10 @@ private: > { > setStorage(m_node, value); > } >+ void setMapBucket(LValue value) >+ { >+ setMapBucket(m_node, value); >+ } > void setDouble(LValue value) > { > setDouble(m_node, value); >@@ -11666,6 +11962,7 @@ private: > HashMap<Node*, LoweredNodeValue> m_jsValueValues; > HashMap<Node*, LoweredNodeValue> m_booleanValues; > HashMap<Node*, LoweredNodeValue> m_storageValues; >+ HashMap<Node*, LoweredNodeValue> m_mapBucketValues; > HashMap<Node*, LoweredNodeValue> m_doubleValues; > > // This is a bit of a hack. It prevents B3 from having to do CSE on loading of arguments. >Index: Source/JavaScriptCore/jit/AssemblyHelpers.cpp >=================================================================== >--- Source/JavaScriptCore/jit/AssemblyHelpers.cpp (revision 205305) >+++ Source/JavaScriptCore/jit/AssemblyHelpers.cpp (working copy) >@@ -626,6 +626,52 @@ void AssemblyHelpers::emitDumbVirtualCal > }); > } > >+#if USE(JSVALUE64) >+void AssemblyHelpers::WangsInt64Hash(GPRReg inputAndResult, GPRReg scratch) >+{ >+ GPRReg input = inputAndResult; >+ // key += ~(key << 32); >+ move(input, scratch); >+ lshift64(TrustedImm32(32), scratch); >+ not64(scratch); >+ add64(scratch, input); >+ // key ^= (key >> 22); >+ move(input, scratch); >+ urshift64(TrustedImm32(22), scratch); >+ xor64(scratch, input); >+ // key += ~(key << 13); >+ move(input, scratch); >+ lshift64(TrustedImm32(13), scratch); >+ not64(scratch); >+ add64(scratch, input); >+ // key ^= (key >> 8); >+ move(input, scratch); >+ urshift64(TrustedImm32(8), scratch); >+ xor64(scratch, input); >+ // key += (key << 3); >+ move(input, scratch); >+ lshift64(TrustedImm32(3), scratch); >+ add64(scratch, input); >+ // key ^= (key >> 15); >+ move(input, scratch); >+ urshift64(TrustedImm32(15), scratch); >+ xor64(scratch, input); >+ // key += ~(key << 27); >+ move(input, scratch); >+ lshift64(TrustedImm32(27), scratch); >+ not64(scratch); >+ add64(scratch, input); >+ // key ^= (key >> 31); >+ move(input, scratch); >+ urshift64(TrustedImm32(31), scratch); >+ xor64(scratch, input); >+ >+ // return static_cast<unsigned>(result) >+ void* mask = bitwise_cast<void*>(static_cast<uintptr_t>(UINT_MAX)); >+ and64(TrustedImmPtr(mask), inputAndResult); >+} >+#endif // USE(JSVALUE64) >+ > } // namespace JSC > > #endif // ENABLE(JIT) >Index: Source/JavaScriptCore/jit/AssemblyHelpers.h >=================================================================== >--- Source/JavaScriptCore/jit/AssemblyHelpers.h (revision 205305) >+++ Source/JavaScriptCore/jit/AssemblyHelpers.h (working copy) >@@ -61,7 +61,7 @@ public: > ASSERT(m_baselineCodeBlock->jitType() == JITCode::None || JITCode::isBaselineCode(m_baselineCodeBlock->jitType())); > } > } >- >+ > CodeBlock* codeBlock() { return m_codeBlock; } > VM* vm() { return m_vm; } > AssemblerType_T& assembler() { return m_assembler; } >@@ -1489,6 +1489,10 @@ public: > emitAllocateJSObject<ClassType>(resultGPR, TrustedImmPtr(structure), TrustedImmPtr(0), scratchGPR1, scratchGPR2, slowPath); > storePtr(TrustedImmPtr(structure->classInfo()), Address(resultGPR, JSDestructibleObject::classInfoOffset())); > } >+ >+#if USE(JSVALUE64) >+ void WangsInt64Hash(GPRReg inputAndResult, GPRReg scratch); >+#endif > > protected: > VM* m_vm; >Index: Source/JavaScriptCore/jit/JITOperations.h >=================================================================== >--- Source/JavaScriptCore/jit/JITOperations.h (revision 205305) >+++ Source/JavaScriptCore/jit/JITOperations.h (working copy) >@@ -194,6 +194,7 @@ typedef JSCell* (JIT_OPERATION *C_JITOpe > typedef JSCell* (JIT_OPERATION *C_JITOperation_EStZZ)(ExecState*, Structure*, int32_t, int32_t); > typedef JSCell* (JIT_OPERATION *C_JITOperation_EZ)(ExecState*, int32_t); > typedef JSCell* (JIT_OPERATION *C_JITOperation_EJscI)(ExecState*, JSScope*, UniquedStringImpl*); >+typedef JSCell* (JIT_OPERATION *C_JITOperation_ECJZ)(ExecState*, JSCell*, EncodedJSValue, int32_t); > typedef double (JIT_OPERATION *D_JITOperation_D)(double); > typedef double (JIT_OPERATION *D_JITOperation_G)(JSGlobalObject*); > typedef double (JIT_OPERATION *D_JITOperation_DD)(double, double); >Index: Source/JavaScriptCore/parser/ModuleAnalyzer.cpp >=================================================================== >--- Source/JavaScriptCore/parser/ModuleAnalyzer.cpp (revision 205305) >+++ Source/JavaScriptCore/parser/ModuleAnalyzer.cpp (working copy) >@@ -39,7 +39,7 @@ namespace JSC { > > ModuleAnalyzer::ModuleAnalyzer(ExecState* exec, const Identifier& moduleKey, const SourceCode& sourceCode, const VariableEnvironment& declaredVariables, const VariableEnvironment& lexicalVariables) > : m_vm(&exec->vm()) >- , m_moduleRecord(exec->vm(), JSModuleRecord::create(exec->vm(), exec->lexicalGlobalObject()->moduleRecordStructure(), moduleKey, sourceCode, declaredVariables, lexicalVariables)) >+ , m_moduleRecord(exec->vm(), JSModuleRecord::create(exec, exec->vm(), exec->lexicalGlobalObject()->moduleRecordStructure(), moduleKey, sourceCode, declaredVariables, lexicalVariables)) > { > } > >Index: Source/JavaScriptCore/runtime/HashMapImpl.cpp >=================================================================== >--- Source/JavaScriptCore/runtime/HashMapImpl.cpp (nonexistent) >+++ Source/JavaScriptCore/runtime/HashMapImpl.cpp (working copy) >@@ -0,0 +1,94 @@ >+/* >+ * Copyright (C) 2016 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. >+ */ >+ >+#include "config.h" >+#include "HashMapImpl.h" >+ >+#include "CopiedBlockInlines.h" >+#include "CopyVisitorInlines.h" >+#include "SlotVisitorInlines.h" >+ >+namespace JSC { >+ >+template<> >+const ClassInfo HashMapBucket<HashMapBucketDataKey>::s_info = >+ { "HashMapBucket", nullptr, 0, CREATE_METHOD_TABLE(HashMapBucket<HashMapBucketDataKey>) }; >+ >+template<> >+const ClassInfo HashMapBucket<HashMapBucketDataKeyValue>::s_info = >+ { "HashMapBucket", nullptr, 0, CREATE_METHOD_TABLE(HashMapBucket<HashMapBucketDataKeyValue>) }; >+ >+template <typename Data> >+void HashMapBucket<Data>::visitChildren(JSCell* cell, SlotVisitor& visitor) >+{ >+ HashMapBucket* thisObject = jsCast<HashMapBucket*>(cell); >+ ASSERT_GC_OBJECT_INHERITS(thisObject, info()); >+ Base::visitChildren(thisObject, visitor); >+ >+ visitor.append(&thisObject->m_next); >+ visitor.append(&thisObject->m_prev); >+ >+ static_assert(sizeof(Data) % sizeof(WriteBarrier<Unknown>) == 0, "We assume that these are filled with WriteBarrier<Unknown> members only."); >+ visitor.appendValues(bitwise_cast<WriteBarrier<Unknown>*>(&thisObject->m_data), sizeof(Data) / sizeof(WriteBarrier<Unknown>)); >+} >+ >+template<> >+const ClassInfo HashMapImpl<HashMapBucket<HashMapBucketDataKey>>::s_info = >+ { "HashMapImpl", nullptr, 0, CREATE_METHOD_TABLE(HashMapImpl<HashMapBucket<HashMapBucketDataKey>>) }; >+ >+template<> >+const ClassInfo HashMapImpl<HashMapBucket<HashMapBucketDataKeyValue>>::s_info = >+ { "HashMapImpl", nullptr, 0, CREATE_METHOD_TABLE(HashMapImpl<HashMapBucket<HashMapBucketDataKeyValue>>) }; >+ >+template <typename HashMapBucket> >+void HashMapImpl<HashMapBucket>::visitChildren(JSCell* cell, SlotVisitor& visitor) >+{ >+ HashMapImpl* thisObject = jsCast<HashMapImpl*>(cell); >+ ASSERT_GC_OBJECT_INHERITS(thisObject, info()); >+ Base::visitChildren(thisObject, visitor); >+ >+ visitor.append(&thisObject->m_head); >+ visitor.append(&thisObject->m_tail); >+ >+ visitor.copyLater(thisObject, MapBackingStoreCopyToken, thisObject->m_buffer.get(), thisObject->bufferSizeInBytes()); >+} >+ >+template <typename HashMapBucket> >+void HashMapImpl<HashMapBucket>::copyBackingStore(JSCell* cell, CopyVisitor& visitor, CopyToken token) >+{ >+ Base::copyBackingStore(cell, visitor, token); >+ >+ HashMapImpl* thisObject = jsCast<HashMapImpl*>(cell); >+ if (token == MapBackingStoreCopyToken && visitor.checkIfShouldCopy(thisObject->m_buffer.get())) { >+ HashMapBufferType* oldBuffer = thisObject->m_buffer.get(); >+ size_t bufferSizeInBytes = thisObject->bufferSizeInBytes(); >+ HashMapBufferType* newBuffer = static_cast<HashMapBufferType*>(visitor.allocateNewSpace(bufferSizeInBytes)); >+ memcpy(newBuffer, oldBuffer, bufferSizeInBytes); >+ thisObject->m_buffer.setWithoutBarrier(newBuffer); >+ visitor.didCopy(oldBuffer, bufferSizeInBytes); >+ } >+} >+ >+} // namespace JSC >Index: Source/JavaScriptCore/runtime/HashMapImpl.h >=================================================================== >--- Source/JavaScriptCore/runtime/HashMapImpl.h (nonexistent) >+++ Source/JavaScriptCore/runtime/HashMapImpl.h (working copy) >@@ -0,0 +1,532 @@ >+/* >+ * Copyright (C) 2016 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 "JSCJSValueInlines.h" >+#include "JSObject.h" >+ >+namespace JSC { >+ >+struct HashMapBucketDataKey { >+ WriteBarrier<Unknown> key; >+}; >+ >+struct HashMapBucketDataKeyValue { >+ WriteBarrier<Unknown> key; >+ WriteBarrier<Unknown> value; >+}; >+ >+template <typename Data> >+class HashMapBucket : public JSCell { >+ typedef JSCell Base; >+ >+ template <typename T = Data> >+ static typename std::enable_if<std::is_same<T, HashMapBucketDataKey>::value, Structure*>::type selectStructure(VM& vm) >+ { >+ return vm.hashMapBucketSetStructure.get(); >+ } >+ >+ template <typename T = Data> >+ static typename std::enable_if<std::is_same<T, HashMapBucketDataKeyValue>::value, Structure*>::type selectStructure(VM& vm) >+ { >+ return vm.hashMapBucketMapStructure.get(); >+ } >+ >+public: >+ static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) >+ { >+ return Structure::create(vm, globalObject, prototype, TypeInfo(CellType, StructureFlags), info()); >+ } >+ >+ static HashMapBucket* create(VM& vm) >+ { >+ HashMapBucket* bucket = new (NotNull, allocateCell<HashMapBucket>(vm.heap)) HashMapBucket(vm, selectStructure(vm)); >+ bucket->finishCreation(vm); >+ ASSERT(!bucket->next()); >+ ASSERT(!bucket->prev()); >+ return bucket; >+ } >+ >+ DECLARE_EXPORT_INFO; >+ >+ HashMapBucket(VM& vm, Structure* structure) >+ : Base(vm, structure) >+ { } >+ >+ ALWAYS_INLINE void setNext(VM& vm, HashMapBucket* bucket) >+ { >+ m_next.set(vm, this, bucket); >+ } >+ ALWAYS_INLINE void setPrev(VM& vm, HashMapBucket* bucket) >+ { >+ m_prev.set(vm, this, bucket); >+ } >+ >+ ALWAYS_INLINE void setKey(VM& vm, JSValue key) >+ { >+ m_data.key.set(vm, this, key); >+ } >+ >+ template <typename T = Data> >+ ALWAYS_INLINE typename std::enable_if<std::is_same<T, HashMapBucketDataKeyValue>::value>::type setValue(VM& vm, JSValue value) >+ { >+ m_data.value.set(vm, this, value); >+ } >+ template <typename T = Data> >+ ALWAYS_INLINE typename std::enable_if<std::is_same<T, HashMapBucketDataKey>::value>::type setValue(VM&, JSValue) { } >+ >+ ALWAYS_INLINE JSValue key() const { return m_data.key.get(); } >+ >+ template <typename T = Data> >+ ALWAYS_INLINE typename std::enable_if<std::is_same<T, HashMapBucketDataKeyValue>::value, JSValue>::type value() const >+ { >+ return m_data.value.get(); >+ } >+ >+ static void visitChildren(JSCell*, SlotVisitor&); >+ >+ ALWAYS_INLINE HashMapBucket* next() const { return m_next.get(); } >+ ALWAYS_INLINE HashMapBucket* prev() const { return m_prev.get(); } >+ >+ ALWAYS_INLINE bool deleted() const { return m_deleted; } >+ ALWAYS_INLINE void setDeleted(bool deleted) { m_deleted = deleted; } >+ >+ static ptrdiff_t offsetOfKey() >+ { >+ return OBJECT_OFFSETOF(HashMapBucket, m_data) + OBJECT_OFFSETOF(Data, key); >+ } >+ >+ template <typename T = Data> >+ static typename std::enable_if<std::is_same<T, HashMapBucketDataKeyValue>::value, ptrdiff_t>::type offsetOfValue() >+ { >+ return OBJECT_OFFSETOF(HashMapBucket, m_data) + OBJECT_OFFSETOF(Data, value); >+ } >+ >+private: >+ Data m_data; >+ WriteBarrier<HashMapBucket> m_next; >+ WriteBarrier<HashMapBucket> m_prev; >+ bool m_deleted { false }; >+}; >+ >+template <typename BucketType> >+class HashMapBuffer { >+public: >+ HashMapBuffer() = delete; >+ >+ static size_t allocationSize(uint32_t capacity) >+ { >+ return capacity * sizeof(BucketType*); >+ } >+ >+ ALWAYS_INLINE BucketType** buffer() const >+ { >+ return bitwise_cast<BucketType**>(this); >+ } >+ >+ static HashMapBuffer* create(ExecState* exec, VM& vm, JSCell* owner, uint32_t capacity) >+ { >+ auto scope = DECLARE_THROW_SCOPE(vm); >+ size_t allocationSize = HashMapBuffer::allocationSize(capacity); >+ void* data = nullptr; >+ DeferGCForAWhile defer(vm.heap); >+ if (!vm.heap.tryAllocateStorage(owner, allocationSize, &data)) { >+ throwOutOfMemoryError(exec, scope); >+ return nullptr; >+ } >+ >+ HashMapBuffer* buffer = static_cast<HashMapBuffer*>(data); >+ memset(buffer, -1, allocationSize); >+ return buffer; >+ } >+ >+}; >+ >+ALWAYS_INLINE static bool areKeysEqual(ExecState* exec, JSValue a, JSValue b) >+{ >+ // We want +0 and -0 to be compared to true here. sameValue() itself doesn't >+ // guarantee that, however, we normalize all keys before comparing and storing >+ // them in the map. The normalization will convert -0.0 and 0.0 to the integer >+ // representation for 0. >+ return sameValue(exec, a, b); >+} >+ >+ALWAYS_INLINE JSValue normalizeMapKey(JSValue key) >+{ >+ if (!key.isNumber()) >+ return key; >+ >+ if (key.isInt32()) >+ return key; >+ >+ double d = key.asDouble(); >+ if (std::isnan(d)) >+ return key; >+ >+ int i = static_cast<int>(d); >+ if (i == d) { >+ // When a key is -0, we convert it to positive zero. >+ // When a key is the double representation for an integer, we convert it to an integer. >+ return jsNumber(i); >+ } >+ // This means key is definitely not negative zero, and it's definitely not a double representation of an integer. >+ return key; >+} >+ >+ALWAYS_INLINE uint32_t jsMapHash(ExecState* exec, VM& vm, JSValue value) >+{ >+ ASSERT_WITH_MESSAGE(normalizeMapKey(value) == value, "We expect normalized values flowing into this function."); >+ >+ auto scope = DECLARE_THROW_SCOPE(vm); >+ >+ if (value.isDouble()) { >+ double d = value.asDouble(); >+ if (!std::isnan(d)) { >+ int i = static_cast<int>(d); >+ if (i == d) >+ value = jsNumber(i); >+ } >+ } >+ if (value.isString()) { >+ JSString* string = asString(value); >+ const String& wtfString = string->value(exec); >+ if (UNLIKELY(scope.exception())) >+ return UINT_MAX; >+ return wtfString.impl()->hash(); >+ } >+ >+ auto WangsInt64Hash = [] (uint64_t key) -> uint32_t { >+ key += ~(key << 32); >+ key ^= (key >> 22); >+ key += ~(key << 13); >+ key ^= (key >> 8); >+ key += (key << 3); >+ key ^= (key >> 15); >+ key += ~(key << 27); >+ key ^= (key >> 31); >+ return static_cast<unsigned>(key); >+ }; >+ uint64_t rawValue = JSValue::encode(value); >+ return WangsInt64Hash(rawValue); >+} >+ >+template <typename HashMapBucketType> >+class HashMapImpl : public JSCell { >+ typedef JSCell Base; >+ typedef HashMapBuffer<HashMapBucketType> HashMapBufferType; >+ >+ template <typename T = HashMapBucketType> >+ static typename std::enable_if<std::is_same<T, HashMapBucket<HashMapBucketDataKey>>::value, Structure*>::type selectStructure(VM& vm) >+ { >+ return vm.hashMapImplSetStructure.get(); >+ } >+ >+ template <typename T = HashMapBucketType> >+ static typename std::enable_if<std::is_same<T, HashMapBucket<HashMapBucketDataKeyValue>>::value, Structure*>::type selectStructure(VM& vm) >+ { >+ return vm.hashMapImplMapStructure.get(); >+ } >+ >+public: >+ DECLARE_EXPORT_INFO; >+ >+ static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) >+ { >+ return Structure::create(vm, globalObject, prototype, TypeInfo(CellType, StructureFlags), info()); >+ } >+ >+ static HashMapImpl* create(ExecState* exec, VM& vm) >+ { >+ ASSERT_WITH_MESSAGE(HashMapBucket<HashMapBucketDataKey>::offsetOfKey() == HashMapBucket<HashMapBucketDataKeyValue>::offsetOfKey(), "We assume this to be true in the DFG and FTL JIT."); >+ >+ HashMapImpl* impl = new (NotNull, allocateCell<HashMapImpl>(vm.heap)) HashMapImpl(vm, selectStructure(vm)); >+ impl->finishCreation(exec, vm); >+ return impl; >+ } >+ >+ static void visitChildren(JSCell*, SlotVisitor&); >+ static void copyBackingStore(JSCell*, CopyVisitor&, CopyToken); >+ >+ HashMapImpl(VM& vm, Structure* structure) >+ : Base(vm, structure) >+ , m_size(0) >+ , m_deleteCount(0) >+ , m_capacity(4) >+ { >+ } >+ >+ ALWAYS_INLINE HashMapBucketType** buffer() const >+ { >+ return m_buffer.get()->buffer(); >+ } >+ >+ void finishCreation(ExecState* exec, VM& vm) >+ { >+ auto scope = DECLARE_THROW_SCOPE(vm); >+ Base::finishCreation(vm); >+ >+ makeAndSetNewBuffer(exec, vm); >+ if (UNLIKELY(scope.exception())) >+ return; >+ >+ m_head.set(vm, this, HashMapBucketType::create(vm)); >+ m_tail.set(vm, this, HashMapBucketType::create(vm)); >+ >+ m_head->setNext(vm, m_tail.get()); >+ m_tail->setPrev(vm, m_head.get()); >+ m_head->setDeleted(true); >+ m_tail->setDeleted(true); >+ >+ } >+ >+ static HashMapBucketType* emptyValue() >+ { >+ return bitwise_cast<HashMapBucketType*>(static_cast<uintptr_t>(-1)); >+ } >+ >+ static ALWAYS_INLINE bool isEmpty(HashMapBucketType* bucket) >+ { >+ return bucket == emptyValue(); >+ } >+ >+ static HashMapBucketType* deletedValue() >+ { >+ return bitwise_cast<HashMapBucketType*>(static_cast<uintptr_t>(-3)); >+ } >+ >+ static ALWAYS_INLINE bool isDeleted(HashMapBucketType* bucket) >+ { >+ return bucket == deletedValue(); >+ } >+ >+ ALWAYS_INLINE HashMapBucketType** findBucket(ExecState* exec, JSValue key) >+ { >+ VM& vm = exec->vm(); >+ uint32_t hash = jsMapHash(exec, vm, key); >+ auto scope = DECLARE_THROW_SCOPE(vm); >+ if (UNLIKELY(scope.exception())) >+ return nullptr; >+ return findBucket(exec, key, hash); >+ } >+ >+ ALWAYS_INLINE HashMapBucketType** findBucket(ExecState* exec, JSValue key, uint32_t hash) >+ { >+ key = normalizeMapKey(key); >+ return findBucketAlreadyHashedAndNormalized(exec, key, hash); >+ } >+ >+ ALWAYS_INLINE JSValue get(ExecState* exec, JSValue key) >+ { >+ if (HashMapBucketType** bucket = findBucket(exec, key)) >+ return (*bucket)->value(); >+ return jsUndefined(); >+ } >+ >+ ALWAYS_INLINE bool has(ExecState* exec, JSValue key) >+ { >+ return !!findBucket(exec, key); >+ } >+ >+ ALWAYS_INLINE void add(ExecState* exec, JSValue key, JSValue value = JSValue()) >+ { >+ key = normalizeMapKey(key); >+ >+ VM& vm = exec->vm(); >+ auto scope = DECLARE_THROW_SCOPE(vm); >+ >+ const uint32_t mask = m_capacity - 1; >+ uint32_t index = jsMapHash(exec, vm, key) & mask; >+ if (UNLIKELY(scope.exception())) >+ return; >+ HashMapBucketType** buffer = this->buffer(); >+ HashMapBucketType* bucket = buffer[index]; >+ while (!isEmpty(bucket)) { >+ if (!isDeleted(bucket) && areKeysEqual(exec, key, bucket->key())) { >+ bucket->setValue(vm, value); >+ return; >+ } >+ index = (index + 1) & mask; >+ bucket = buffer[index]; >+ } >+ >+ HashMapBucketType* newEntry = m_tail.get(); >+ buffer[index] = newEntry; >+ newEntry->setKey(vm, key); >+ newEntry->setValue(vm, value); >+ newEntry->setDeleted(false); >+ HashMapBucketType* newTail = HashMapBucketType::create(vm); >+ m_tail.set(vm, this, newTail); >+ newTail->setPrev(vm, newEntry); >+ newTail->setDeleted(true); >+ newEntry->setNext(vm, newTail); >+ uint32_t newSize = ++m_size; >+ if (2*newSize > m_capacity) >+ rehash(exec); >+ } >+ >+ ALWAYS_INLINE bool remove(ExecState* exec, JSValue key) >+ { >+ HashMapBucketType** bucket = findBucket(exec, key); >+ if (!bucket) >+ return false; >+ >+ VM& vm = exec->vm(); >+ HashMapBucketType* impl = *bucket; >+ impl->next()->setPrev(vm, impl->prev()); >+ impl->prev()->setNext(vm, impl->next()); >+ impl->setDeleted(true); >+ >+ *bucket = deletedValue(); >+ >+ m_deleteCount++; >+ >+ return true; >+ } >+ >+ ALWAYS_INLINE uint32_t size() const >+ { >+ RELEASE_ASSERT(m_size >= m_deleteCount); >+ return m_size - m_deleteCount; >+ } >+ >+ ALWAYS_INLINE void clear(ExecState* exec) >+ { >+ VM& vm = exec->vm(); >+ m_size = 0; >+ m_deleteCount = 0; >+ HashMapBucketType* head = m_head.get(); >+ HashMapBucketType* bucket = m_head->next(); >+ HashMapBucketType* tail = m_tail.get(); >+ while (bucket != tail) { >+ HashMapBucketType* next = bucket->next(); >+ // We restart each iterator by pointing it to the head of the list. >+ bucket->setNext(vm, head); >+ bucket = next; >+ } >+ m_head->setNext(vm, m_tail.get()); >+ m_tail->setPrev(vm, m_head.get()); >+ m_capacity = 4; >+ makeAndSetNewBuffer(exec, vm); >+ } >+ >+ ALWAYS_INLINE size_t bufferSizeInBytes() const >+ { >+ return m_capacity * sizeof(HashMapBucketType*); >+ } >+ >+ static ptrdiff_t offsetOfBuffer() >+ { >+ return OBJECT_OFFSETOF(HashMapImpl<HashMapBucketType>, m_buffer); >+ } >+ >+ static ptrdiff_t offsetOfCapacity() >+ { >+ return OBJECT_OFFSETOF(HashMapImpl<HashMapBucketType>, m_capacity); >+ } >+ >+ HashMapBucketType* head() { return m_head.get(); } >+ HashMapBucketType* tail() { return m_tail.get(); } >+ >+ size_t approximateSize() const >+ { >+ size_t size = sizeof(HashMapImpl); >+ size += bufferSizeInBytes(); >+ size += 2 * sizeof(HashMapBucketType); // Head and tail members. >+ size += (m_deleteCount + m_size) * sizeof(HashMapBucketType); // Number of members on the list. >+ return size; >+ } >+ >+private: >+ ALWAYS_INLINE HashMapBucketType** findBucketAlreadyHashedAndNormalized(ExecState* exec, JSValue key, uint32_t hash) >+ { >+ const uint32_t mask = m_capacity - 1; >+ uint32_t index = hash & mask; >+ HashMapBucketType** buffer = this->buffer(); >+ HashMapBucketType* bucket = buffer[index]; >+ >+ while (!isEmpty(bucket)) { >+ if (!isDeleted(bucket) && areKeysEqual(exec, key, bucket->key())) >+ return buffer + index; >+ index = (index + 1) & mask; >+ bucket = buffer[index]; >+ } >+ return nullptr; >+ } >+ >+ void rehash(ExecState* exec) >+ { >+ VM& vm = exec->vm(); >+ auto scope = DECLARE_THROW_SCOPE(vm); >+ >+ m_capacity = m_capacity * 2; >+ makeAndSetNewBuffer(exec, vm); >+ if (UNLIKELY(scope.exception())) >+ return; >+ >+ HashMapBucketType* iter = m_head->next(); >+ HashMapBucketType* end = m_tail.get(); >+ const uint32_t mask = m_capacity - 1; >+ RELEASE_ASSERT(!(m_capacity & (m_capacity - 1))); >+ HashMapBucketType** buffer = this->buffer(); >+ while (iter != end) { >+ uint32_t index = jsMapHash(exec, vm, iter->key()) & mask; >+ ASSERT_WITH_MESSAGE(!scope.exception(), "All keys should already be hashed before, so this should not throw because it won't resolve ropes."); >+ { >+ HashMapBucketType* bucket = buffer[index]; >+ while (!isEmpty(bucket)) { >+ index = (index + 1) & mask; >+ bucket = buffer[index]; >+ } >+ } >+ buffer[index] = iter; >+ iter = iter->next(); >+ } >+ } >+ >+ void makeAndSetNewBuffer(ExecState* exec, VM& vm) >+ { >+ ASSERT(!(m_capacity & (m_capacity - 1))); >+ >+ HashMapBufferType* buffer = HashMapBufferType::create(exec, vm, this, m_capacity); >+ if (UNLIKELY(!buffer)) >+ return; >+ >+ m_buffer.set(vm, this, buffer); >+ if (!ASSERT_DISABLED) { >+ for (unsigned i = 0; i < m_capacity; i++) >+ ASSERT(isEmpty(this->buffer()[i])); >+ } >+ } >+ >+ WriteBarrier<HashMapBucketType> m_head; >+ WriteBarrier<HashMapBucketType> m_tail; >+ CopyBarrier<HashMapBufferType> m_buffer; >+ uint32_t m_size; >+ uint32_t m_deleteCount; >+ uint32_t m_capacity; >+}; >+ >+} // namespace JSC >Index: Source/JavaScriptCore/runtime/Intrinsic.h >=================================================================== >--- Source/JavaScriptCore/runtime/Intrinsic.h (revision 205305) >+++ Source/JavaScriptCore/runtime/Intrinsic.h (working copy) >@@ -62,6 +62,9 @@ enum JS_EXPORT_PRIVATE Intrinsic { > IsRegExpObjectIntrinsic, > IsTypedArrayViewIntrinsic, > BoundThisNoArgsFunctionCallIntrinsic, >+ JSMapGetIntrinsic, >+ JSMapHasIntrinsic, >+ JSSetHasIntrinsic, > > // Getter intrinsics. > TypedArrayLengthIntrinsic, >Index: Source/JavaScriptCore/runtime/JSCJSValue.h >=================================================================== >--- Source/JavaScriptCore/runtime/JSCJSValue.h (revision 205305) >+++ Source/JavaScriptCore/runtime/JSCJSValue.h (working copy) >@@ -606,6 +606,9 @@ inline bool operator!=(const JSCell* a, > > bool isThisValueAltered(const PutPropertySlot&, JSObject* baseObject); > >+// See section 7.2.9: https://tc39.github.io/ecma262/#sec-samevalue >+bool sameValue(ExecState*, JSValue a, JSValue b); >+ > } // namespace JSC > > #endif // JSCJSValue_h >Index: Source/JavaScriptCore/runtime/JSCJSValueInlines.h >=================================================================== >--- Source/JavaScriptCore/runtime/JSCJSValueInlines.h (revision 205305) >+++ Source/JavaScriptCore/runtime/JSCJSValueInlines.h (working copy) >@@ -1058,6 +1058,22 @@ ALWAYS_INLINE bool isThisValueAltered(co > return true; > } > >+// See section 7.2.9: https://tc39.github.io/ecma262/#sec-samevalue >+ALWAYS_INLINE bool sameValue(ExecState* exec, JSValue a, JSValue b) >+{ >+ if (!a.isNumber()) >+ return JSValue::strictEqual(exec, a, b); >+ if (!b.isNumber()) >+ return false; >+ double x = a.asNumber(); >+ double y = b.asNumber(); >+ bool xIsNaN = std::isnan(x); >+ bool yIsNaN = std::isnan(y); >+ if (xIsNaN || yIsNaN) >+ return xIsNaN && yIsNaN; >+ return bitwise_cast<uint64_t>(x) == bitwise_cast<uint64_t>(y); >+} >+ > } // namespace JSC > > #endif // JSValueInlines_h >Index: Source/JavaScriptCore/runtime/JSGlobalObject.cpp >=================================================================== >--- Source/JavaScriptCore/runtime/JSGlobalObject.cpp (revision 205305) >+++ Source/JavaScriptCore/runtime/JSGlobalObject.cpp (working copy) >@@ -641,7 +641,7 @@ putDirectWithoutTransition(vm, vm.proper > putDirectWithoutTransition(vm, vm.propertyNames->Reflect, reflectObject, DontEnum); > > m_moduleLoaderStructure.set(vm, this, JSModuleLoader::createStructure(vm, this, m_moduleLoaderPrototype.get())); >- m_moduleLoader.set(vm, this, JSModuleLoader::create(vm, this, m_moduleLoaderStructure.get())); >+ m_moduleLoader.set(vm, this, JSModuleLoader::create(globalExec(), vm, this, m_moduleLoaderStructure.get())); > if (Options::exposeInternalModuleLoader()) > putDirectWithoutTransition(vm, vm.propertyNames->Loader, m_moduleLoader.get(), DontEnum); > >Index: Source/JavaScriptCore/runtime/JSMap.cpp >=================================================================== >--- Source/JavaScriptCore/runtime/JSMap.cpp (revision 205305) >+++ Source/JavaScriptCore/runtime/JSMap.cpp (working copy) >@@ -26,78 +26,13 @@ > #include "config.h" > #include "JSMap.h" > >-#include "CopiedBlockInlines.h" >-#include "JSCJSValueInlines.h" >-#include "JSMapIterator.h" >-#include "MapDataInlines.h" >-#include "SlotVisitorInlines.h" >-#include "StructureInlines.h" >- > namespace JSC { > > const ClassInfo JSMap::s_info = { "Map", &Base::s_info, 0, CREATE_METHOD_TABLE(JSMap) }; > >-void JSMap::destroy(JSCell* cell) >-{ >- JSMap* thisObject = jsCast<JSMap*>(cell); >- thisObject->JSMap::~JSMap(); >-} >- >-size_t JSMap::estimatedSize(JSCell* cell) >-{ >- JSMap* thisObject = jsCast<JSMap*>(cell); >- size_t mapDataSize = thisObject->m_mapData.capacityInBytes(); >- return Base::estimatedSize(cell) + mapDataSize; >-} >- > String JSMap::toStringName(const JSObject*, ExecState*) > { > return ASCIILiteral("Object"); > } > >-void JSMap::visitChildren(JSCell* cell, SlotVisitor& visitor) >-{ >- Base::visitChildren(cell, visitor); >- jsCast<JSMap*>(cell)->m_mapData.visitChildren(cell, visitor); >-} >- >-void JSMap::copyBackingStore(JSCell* cell, CopyVisitor& visitor, CopyToken token) >-{ >- Base::copyBackingStore(cell, visitor, token); >- jsCast<JSMap*>(cell)->m_mapData.copyBackingStore(visitor, token); >-} >- >-bool JSMap::has(ExecState* exec, JSValue key) >-{ >- return m_mapData.contains(exec, key); >-} >- >-size_t JSMap::size(ExecState* exec) >-{ >- return m_mapData.size(exec); >-} >- >-JSValue JSMap::get(ExecState* exec, JSValue key) >-{ >- JSValue result = m_mapData.get(exec, key); >- if (!result) >- return jsUndefined(); >- return result; >-} >- >-void JSMap::set(ExecState* exec, JSValue key, JSValue value) >-{ >- m_mapData.set(exec, this, key, value); >-} >- >-void JSMap::clear(ExecState*) >-{ >- m_mapData.clear(); >-} >- >-bool JSMap::remove(ExecState* exec, JSValue key) >-{ >- return m_mapData.remove(exec, key); >-} >- > } >Index: Source/JavaScriptCore/runtime/JSMap.h >=================================================================== >--- Source/JavaScriptCore/runtime/JSMap.h (revision 205305) >+++ Source/JavaScriptCore/runtime/JSMap.h (working copy) >@@ -26,108 +26,49 @@ > #ifndef JSMap_h > #define JSMap_h > >-#include "JSDestructibleObject.h" > #include "JSObject.h" >-#include "MapData.h" >+#include "MapBase.h" > > namespace JSC { > > class JSMapIterator; > >-class JSMap : public JSDestructibleObject { >+class JSMap : public MapBase<HashMapBucket<HashMapBucketDataKeyValue>> { >+ typedef MapBase<HashMapBucket<HashMapBucketDataKeyValue>> Base; > public: >- typedef JSDestructibleObject Base; >- > friend class JSMapIterator; > >- // Our marking functions expect Entry to maintain this layout, and have all >- // fields be WriteBarrier<Unknown> >- class Entry { >- private: >- WriteBarrier<Unknown> m_key; >- WriteBarrier<Unknown> m_value; >- >- public: >- const WriteBarrier<Unknown>& key() const >- { >- return m_key; >- } >- >- const WriteBarrier<Unknown>& value() const >- { >- return m_value; >- } >- >- void visitChildren(SlotVisitor& visitor) >- { >- visitor.append(&m_key); >- visitor.append(&m_value); >- } >- >- void setKey(VM& vm, const JSCell* owner, JSValue key) >- { >- m_key.set(vm, owner, key); >- } >- >- void setKeyWithoutWriteBarrier(JSValue key) >- { >- m_key.setWithoutWriteBarrier(key); >- } >- >- void setValue(VM& vm, const JSCell* owner, JSValue value) >- { >- m_value.set(vm, owner, value); >- } >- >- void clear() >- { >- m_key.clear(); >- m_value.clear(); >- } >- }; >- >- typedef MapDataImpl<Entry, JSMapIterator> MapData; >- > DECLARE_EXPORT_INFO; > > 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(JSMapType, StructureFlags), info()); > } > >- static JSMap* create(VM& vm, Structure* structure) >+ static JSMap* create(ExecState* exec, VM& vm, Structure* structure) > { > JSMap* instance = new (NotNull, allocateCell<JSMap>(vm.heap)) JSMap(vm, structure); >- instance->finishCreation(vm); >+ instance->finishCreation(exec, vm); > return instance; > } > >- static JSMap* create(ExecState* exec, Structure* structure) >+ ALWAYS_INLINE JSValue get(ExecState* exec, JSValue key) > { >- return create(exec->vm(), structure); >+ return m_map->get(exec, key); > } > >- bool has(ExecState*, JSValue); >- size_t size(ExecState*); >- JSValue get(ExecState*, JSValue); >- JS_EXPORT_PRIVATE void set(ExecState*, JSValue key, JSValue value); >- void clear(ExecState*); >- bool remove(ExecState*, JSValue); >+ ALWAYS_INLINE void set(ExecState* exec, JSValue key, JSValue value) >+ { >+ m_map->add(exec, key, value); >+ } > > private: > JSMap(VM& vm, Structure* structure) > : Base(vm, structure) >- , m_mapData(vm, this) > { > } > >- static void destroy(JSCell*); >- static size_t estimatedSize(JSCell*); >- static void visitChildren(JSCell*, SlotVisitor&); >- static void copyBackingStore(JSCell*, CopyVisitor&, CopyToken); > static String toStringName(const JSObject*, ExecState*); >- >- MapData m_mapData; > }; > > } >Index: Source/JavaScriptCore/runtime/JSMapIterator.cpp >=================================================================== >--- Source/JavaScriptCore/runtime/JSMapIterator.cpp (revision 205305) >+++ Source/JavaScriptCore/runtime/JSMapIterator.cpp (working copy) >@@ -26,6 +26,9 @@ > #include "config.h" > #include "JSMapIterator.h" > >+#include "BuiltinNames.h" >+#include "CommonIdentifiers.h" >+#include "IdentifierInlines.h" > #include "JSCJSValueInlines.h" > #include "JSCellInlines.h" > #include "JSMap.h" >@@ -41,6 +44,7 @@ void JSMapIterator::finishCreation(VM& v > { > Base::finishCreation(vm); > m_map.set(vm, this, iteratedObject); >+ setIterator(vm, m_map->impl()->head()); > } > > void JSMapIterator::visitChildren(JSCell* cell, SlotVisitor& visitor) >@@ -49,6 +53,7 @@ void JSMapIterator::visitChildren(JSCell > ASSERT_GC_OBJECT_INHERITS(thisObject, info()); > Base::visitChildren(thisObject, visitor); > visitor.append(&thisObject->m_map); >+ visitor.append(&thisObject->m_iter); > } > > JSValue JSMapIterator::createPair(CallFrame* callFrame, JSValue key, JSValue value) >@@ -62,8 +67,9 @@ JSValue JSMapIterator::createPair(CallFr > > JSMapIterator* JSMapIterator::clone(ExecState* exec) > { >- auto clone = JSMapIterator::create(exec->vm(), exec->callee()->globalObject()->mapIteratorStructure(), m_map.get(), m_kind); >- clone->m_iterator = m_iterator; >+ VM& vm = exec->vm(); >+ auto clone = JSMapIterator::create(vm, exec->callee()->globalObject()->mapIteratorStructure(), m_map.get(), m_kind); >+ clone->setIterator(vm, m_iter.get()); > return clone; > } > >Index: Source/JavaScriptCore/runtime/JSMapIterator.h >=================================================================== >--- Source/JavaScriptCore/runtime/JSMapIterator.h (revision 205305) >+++ Source/JavaScriptCore/runtime/JSMapIterator.h (working copy) >@@ -34,6 +34,7 @@ > namespace JSC { > > class JSMapIterator : public JSNonFinalObject { >+ typedef HashMapBucket<HashMapBucketDataKeyValue> HashMapBucket; > public: > typedef JSNonFinalObject Base; > >@@ -51,52 +52,62 @@ public: > return instance; > } > >- bool next(CallFrame* callFrame, JSValue& value) >+ ALWAYS_INLINE HashMapBucket* advanceIter(ExecState* exec) > { >- WTF::KeyValuePair<JSValue, JSValue> pair; >- if (!m_iterator.next(pair)) >+ HashMapBucket* prev = m_iter.get(); >+ if (!prev) >+ return nullptr; >+ HashMapBucket* bucket = m_iter->next(); >+ while (bucket && bucket->deleted()) { >+ prev = bucket; >+ bucket = bucket->next(); >+ } >+ if (!bucket) { >+ setIterator(exec->vm(), nullptr); >+ return nullptr; >+ } >+ setIterator(exec->vm(), bucket); // We keep m_iter on the last value since the first thing we do in this function is call next(). >+ return bucket; >+ } >+ bool next(ExecState* exec, JSValue& value) >+ { >+ HashMapBucket* bucket = advanceIter(exec); >+ if (!bucket) > return false; > > if (m_kind == IterateValue) >- value = pair.value; >+ value = bucket->value(); > else if (m_kind == IterateKey) >- value = pair.key; >+ value = bucket->key(); > else >- value = createPair(callFrame, pair.key, pair.value); >+ value = createPair(exec, bucket->key(), bucket->value()); > return true; > } > >- bool nextKeyValue(JSValue& key, JSValue& value) >+ bool nextKeyValue(ExecState* exec, JSValue& key, JSValue& value) > { >- WTF::KeyValuePair<JSValue, JSValue> pair; >- if (!m_iterator.next(pair)) >+ HashMapBucket* bucket = advanceIter(exec); >+ if (!bucket) > return false; > >- key = pair.key; >- value = pair.value; >+ key = bucket->key(); >+ value = bucket->value(); > return true; > } > >- void finish() >- { >- m_iterator.finish(); >- } >- > IterationKind kind() const { return m_kind; } > JSValue iteratedValue() const { return m_map.get(); } > JSMapIterator* clone(ExecState*); > >- JSMap::MapData::IteratorData* iteratorData() >- { >- return &m_iterator; >- } >- > private: >- JSMapIterator(VM& vm, Structure* structure, JSMap* iteratedObject, IterationKind kind) >+ JSMapIterator(VM& vm, Structure* structure, JSMap*, IterationKind kind) > : Base(vm, structure) >- , m_iterator(iteratedObject->m_mapData.createIteratorData(this)) > , m_kind(kind) >+ { } >+ >+ void setIterator(VM& vm, HashMapBucket* bucket) > { >+ m_iter.setMayBeNull(vm, this, bucket); > } > > JS_EXPORT_PRIVATE void finishCreation(VM&, JSMap*); >@@ -104,7 +115,7 @@ private: > static void visitChildren(JSCell*, SlotVisitor&); > > WriteBarrier<JSMap> m_map; >- JSMap::MapData::IteratorData m_iterator; >+ WriteBarrier<HashMapBucket> m_iter; > IterationKind m_kind; > }; > STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(JSMapIterator); >Index: Source/JavaScriptCore/runtime/JSModuleLoader.cpp >=================================================================== >--- Source/JavaScriptCore/runtime/JSModuleLoader.cpp (revision 205305) >+++ Source/JavaScriptCore/runtime/JSModuleLoader.cpp (working copy) >@@ -55,11 +55,14 @@ JSModuleLoader::JSModuleLoader(VM& vm, S > { > } > >-void JSModuleLoader::finishCreation(VM& vm, JSGlobalObject* globalObject) >+void JSModuleLoader::finishCreation(ExecState* exec, VM& vm, JSGlobalObject* globalObject) > { > Base::finishCreation(vm); > ASSERT(inherits(info())); >- putDirect(vm, Identifier::fromString(&vm, "registry"), JSMap::create(vm, globalObject->mapStructure())); >+ auto scope = DECLARE_THROW_SCOPE(vm); >+ JSMap* map = JSMap::create(exec, vm, globalObject->mapStructure()); >+ RELEASE_ASSERT(!scope.exception()); >+ putDirect(vm, Identifier::fromString(&vm, "registry"), map); > } > > // ------------------------------ Functions -------------------------------- >Index: Source/JavaScriptCore/runtime/JSModuleLoader.h >=================================================================== >--- Source/JavaScriptCore/runtime/JSModuleLoader.h (revision 205305) >+++ Source/JavaScriptCore/runtime/JSModuleLoader.h (working copy) >@@ -47,10 +47,10 @@ public: > Ready = 6, > }; > >- static JSModuleLoader* create(VM& vm, JSGlobalObject* globalObject, Structure* structure) >+ static JSModuleLoader* create(ExecState* exec, VM& vm, JSGlobalObject* globalObject, Structure* structure) > { > JSModuleLoader* object = new (NotNull, allocateCell<JSModuleLoader>(vm.heap)) JSModuleLoader(vm, structure); >- object->finishCreation(vm, globalObject); >+ object->finishCreation(exec, vm, globalObject); > return object; > } > >@@ -77,7 +77,7 @@ public: > JSValue evaluate(ExecState*, JSValue key, JSValue moduleRecord, JSValue initiator); > > protected: >- void finishCreation(VM&, JSGlobalObject*); >+ void finishCreation(ExecState*, VM&, JSGlobalObject*); > }; > > } // namespace JSC >Index: Source/JavaScriptCore/runtime/JSModuleRecord.cpp >=================================================================== >--- Source/JavaScriptCore/runtime/JSModuleRecord.cpp (revision 205305) >+++ Source/JavaScriptCore/runtime/JSModuleRecord.cpp (working copy) >@@ -47,14 +47,17 @@ void JSModuleRecord::destroy(JSCell* cel > thisObject->JSModuleRecord::~JSModuleRecord(); > } > >-void JSModuleRecord::finishCreation(VM& vm) >+void JSModuleRecord::finishCreation(ExecState* exec, VM& vm) > { > Base::finishCreation(vm); > ASSERT(inherits(info())); > putDirect(vm, Identifier::fromString(&vm, ASCIILiteral("registryEntry")), jsUndefined()); > putDirect(vm, Identifier::fromString(&vm, ASCIILiteral("evaluated")), jsBoolean(false)); > >- m_dependenciesMap.set(vm, this, JSMap::create(vm, globalObject()->mapStructure())); >+ auto scope = DECLARE_THROW_SCOPE(vm); >+ JSMap* map = JSMap::create(exec, vm, globalObject()->mapStructure()); >+ RELEASE_ASSERT(!scope.exception()); >+ m_dependenciesMap.set(vm, this, map); > putDirect(vm, Identifier::fromString(&vm, ASCIILiteral("dependenciesMap")), m_dependenciesMap.get()); > } > >Index: Source/JavaScriptCore/runtime/JSModuleRecord.h >=================================================================== >--- Source/JavaScriptCore/runtime/JSModuleRecord.h (revision 205305) >+++ Source/JavaScriptCore/runtime/JSModuleRecord.h (working copy) >@@ -87,10 +87,10 @@ public: > return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); > } > >- static JSModuleRecord* create(VM& vm, Structure* structure, const Identifier& moduleKey, const SourceCode& sourceCode, const VariableEnvironment& declaredVariables, const VariableEnvironment& lexicalVariables) >+ static JSModuleRecord* create(ExecState* exec, VM& vm, Structure* structure, const Identifier& moduleKey, const SourceCode& sourceCode, const VariableEnvironment& declaredVariables, const VariableEnvironment& lexicalVariables) > { > JSModuleRecord* instance = new (NotNull, allocateCell<JSModuleRecord>(vm.heap)) JSModuleRecord(vm, structure, moduleKey, sourceCode, declaredVariables, lexicalVariables); >- instance->finishCreation(vm); >+ instance->finishCreation(exec, vm); > return instance; > } > >@@ -152,7 +152,7 @@ private: > { > } > >- void finishCreation(VM&); >+ void finishCreation(ExecState*, VM&); > > JSModuleNamespaceObject* getModuleNamespace(ExecState*); > >Index: Source/JavaScriptCore/runtime/JSSet.cpp >=================================================================== >--- Source/JavaScriptCore/runtime/JSSet.cpp (revision 205305) >+++ Source/JavaScriptCore/runtime/JSSet.cpp (working copy) >@@ -26,70 +26,13 @@ > #include "config.h" > #include "JSSet.h" > >-#include "CopiedBlockInlines.h" >-#include "JSCJSValueInlines.h" >-#include "JSSetIterator.h" >-#include "MapDataInlines.h" >-#include "SlotVisitorInlines.h" >-#include "StructureInlines.h" >- > namespace JSC { > > const ClassInfo JSSet::s_info = { "Set", &Base::s_info, 0, CREATE_METHOD_TABLE(JSSet) }; > >-void JSSet::destroy(JSCell* cell) >-{ >- JSSet* thisObject = jsCast<JSSet*>(cell); >- thisObject->JSSet::~JSSet(); >-} >- > String JSSet::toStringName(const JSObject*, ExecState*) > { > return ASCIILiteral("Object"); > } > >-size_t JSSet::estimatedSize(JSCell* cell) >-{ >- JSSet* thisObject = jsCast<JSSet*>(cell); >- size_t setDataSize = thisObject->m_setData.capacityInBytes(); >- return Base::estimatedSize(cell) + setDataSize; >-} >- >-void JSSet::visitChildren(JSCell* cell, SlotVisitor& visitor) >-{ >- Base::visitChildren(cell, visitor); >- jsCast<JSSet*>(cell)->m_setData.visitChildren(cell, visitor); >-} >- >-void JSSet::copyBackingStore(JSCell* cell, CopyVisitor& visitor, CopyToken token) >-{ >- Base::copyBackingStore(cell, visitor, token); >- jsCast<JSSet*>(cell)->m_setData.copyBackingStore(visitor, token); >-} >- >-bool JSSet::has(ExecState* exec, JSValue value) >-{ >- return m_setData.contains(exec, value); >-} >- >-size_t JSSet::size(ExecState* exec) >-{ >- return m_setData.size(exec); >-} >- >-void JSSet::add(ExecState* exec, JSValue value) >-{ >- m_setData.set(exec, this, value, value); >-} >- >-void JSSet::clear(ExecState*) >-{ >- m_setData.clear(); >-} >- >-bool JSSet::remove(ExecState* exec, JSValue value) >-{ >- return m_setData.remove(exec, value); >-} >- > } >Index: Source/JavaScriptCore/runtime/JSSet.h >=================================================================== >--- Source/JavaScriptCore/runtime/JSSet.h (revision 205305) >+++ Source/JavaScriptCore/runtime/JSSet.h (working copy) >@@ -26,103 +26,45 @@ > #ifndef JSSet_h > #define JSSet_h > >-#include "JSDestructibleObject.h" > #include "JSObject.h" >-#include "MapData.h" >+#include "MapBase.h" > > namespace JSC { > > class JSSetIterator; > >-class JSSet : public JSDestructibleObject { >+class JSSet : public MapBase<HashMapBucket<HashMapBucketDataKey>> { >+ typedef MapBase<HashMapBucket<HashMapBucketDataKey>> Base; > public: >- typedef JSDestructibleObject Base; > > friend class JSSetIterator; > >- // Our marking functions expect Entry to maintain this layout, and have all >- // fields be WriteBarrier<Unknown> >- class Entry { >- private: >- WriteBarrier<Unknown> m_key; >- >- public: >- const WriteBarrier<Unknown>& key() const >- { >- return m_key; >- } >- >- const WriteBarrier<Unknown>& value() const >- { >- return m_key; >- } >- >- void visitChildren(SlotVisitor& visitor) >- { >- visitor.append(&m_key); >- } >- >- void setKey(VM& vm, const JSCell* owner, JSValue key) >- { >- m_key.set(vm, owner, key); >- } >- >- void setKeyWithoutWriteBarrier(JSValue key) >- { >- m_key.setWithoutWriteBarrier(key); >- } >- >- void setValue(VM&, const JSCell*, JSValue) >- { >- } >- >- void clear() >- { >- m_key.clear(); >- } >- }; >- >- typedef MapDataImpl<Entry, JSSetIterator> SetData; >- > DECLARE_EXPORT_INFO; > > 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(JSSetType, StructureFlags), info()); > } > >- static JSSet* create(VM& vm, Structure* structure) >+ static JSSet* create(ExecState* exec, VM& vm, Structure* structure) > { > JSSet* instance = new (NotNull, allocateCell<JSSet>(vm.heap)) JSSet(vm, structure); >- instance->finishCreation(vm); >+ instance->finishCreation(exec, vm); > return instance; > } > >- static JSSet* create(ExecState* exec, Structure* structure) >+ ALWAYS_INLINE void add(ExecState* exec, JSValue key) > { >- return create(exec->vm(), structure); >+ m_map->add(exec, key); > } > >- bool has(ExecState*, JSValue); >- size_t size(ExecState*); >- JS_EXPORT_PRIVATE void add(ExecState*, JSValue); >- void clear(ExecState*); >- bool remove(ExecState*, JSValue); >- > private: > JSSet(VM& vm, Structure* structure) > : Base(vm, structure) >- , m_setData(vm, this) > { > } > >- static void destroy(JSCell*); >- static size_t estimatedSize(JSCell*); >- static void visitChildren(JSCell*, SlotVisitor&); >- static void copyBackingStore(JSCell*, CopyVisitor&, CopyToken); > static String toStringName(const JSObject*, ExecState*); >- >- SetData m_setData; > }; > > } >Index: Source/JavaScriptCore/runtime/JSSetIterator.cpp >=================================================================== >--- Source/JavaScriptCore/runtime/JSSetIterator.cpp (revision 205305) >+++ Source/JavaScriptCore/runtime/JSSetIterator.cpp (working copy) >@@ -41,6 +41,7 @@ void JSSetIterator::finishCreation(VM& v > { > Base::finishCreation(vm); > m_set.set(vm, this, iteratedObject); >+ setIterator(vm, m_set->impl()->head()); > } > > void JSSetIterator::visitChildren(JSCell* cell, SlotVisitor& visitor) >@@ -49,6 +50,7 @@ void JSSetIterator::visitChildren(JSCell > ASSERT_GC_OBJECT_INHERITS(thisObject, info()); > Base::visitChildren(thisObject, visitor); > visitor.append(&thisObject->m_set); >+ visitor.append(&thisObject->m_iter); > } > > JSValue JSSetIterator::createPair(CallFrame* callFrame, JSValue key, JSValue value) >@@ -62,8 +64,9 @@ JSValue JSSetIterator::createPair(CallFr > > JSSetIterator* JSSetIterator::clone(ExecState* exec) > { >- auto clone = JSSetIterator::create(exec->vm(), exec->callee()->globalObject()->setIteratorStructure(), m_set.get(), m_kind); >- clone->m_iterator = m_iterator; >+ VM& vm = exec->vm(); >+ auto clone = JSSetIterator::create(vm, exec->callee()->globalObject()->setIteratorStructure(), m_set.get(), m_kind); >+ clone->setIterator(vm, m_iter.get()); > return clone; > } > >Index: Source/JavaScriptCore/runtime/JSSetIterator.h >=================================================================== >--- Source/JavaScriptCore/runtime/JSSetIterator.h (revision 205305) >+++ Source/JavaScriptCore/runtime/JSSetIterator.h (working copy) >@@ -35,6 +35,7 @@ > namespace JSC { > > class JSSetIterator : public JSNonFinalObject { >+ typedef HashMapBucket<HashMapBucketDataKey> HashMapBucket; > public: > typedef JSNonFinalObject Base; > >@@ -52,46 +53,59 @@ public: > return instance; > } > >- bool next(CallFrame* callFrame, JSValue& value) >+ ALWAYS_INLINE HashMapBucket* advanceIter(ExecState* exec) > { >- WTF::KeyValuePair<JSValue, JSValue> pair; >- if (!m_iterator.next(pair)) >+ HashMapBucket* prev = m_iter.get(); >+ if (!prev) >+ return nullptr; >+ HashMapBucket* bucket = m_iter->next(); >+ while (bucket && bucket->deleted()) { >+ prev = bucket; >+ bucket = bucket->next(); >+ } >+ if (!bucket) { >+ setIterator(exec->vm(), nullptr); >+ return nullptr; >+ } >+ setIterator(exec->vm(), bucket); // We keep m_iter on the last value since the first thing we do in this function is call next(). >+ return bucket; >+ } >+ >+ bool next(ExecState* exec, JSValue& value) >+ { >+ HashMapBucket* bucket = advanceIter(exec); >+ if (!bucket) > return false; >+ > if (m_kind == IterateValue || m_kind == IterateKey) >- value = pair.key; >+ value = bucket->key(); > else >- value = createPair(callFrame, pair.key, pair.key); >+ value = createPair(exec, bucket->key(), bucket->key()); > return true; > } > >- void finish() >- { >- m_iterator.finish(); >- } >- > IterationKind kind() const { return m_kind; } > JSValue iteratedValue() const { return m_set.get(); } > JSSetIterator* clone(ExecState*); > >- JSSet::SetData::IteratorData* iteratorData() >- { >- return &m_iterator; >- } >- > private: >- JSSetIterator(VM& vm, Structure* structure, JSSet* iteratedObject, IterationKind kind) >+ JSSetIterator(VM& vm, Structure* structure, JSSet*, IterationKind kind) > : Base(vm, structure) >- , m_iterator(iteratedObject->m_setData.createIteratorData(this)) > , m_kind(kind) > { > } > >+ void setIterator(VM& vm, HashMapBucket* bucket) >+ { >+ m_iter.setMayBeNull(vm, this, bucket); >+ } >+ > JS_EXPORT_PRIVATE void finishCreation(VM&, JSSet*); > JS_EXPORT_PRIVATE JSValue createPair(CallFrame*, JSValue, JSValue); > static void visitChildren(JSCell*, SlotVisitor&); > > WriteBarrier<JSSet> m_set; >- JSSet::SetData::IteratorData m_iterator; >+ WriteBarrier<HashMapBucket> m_iter; > IterationKind m_kind; > }; > STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(JSSetIterator); >Index: Source/JavaScriptCore/runtime/JSType.h >=================================================================== >--- Source/JavaScriptCore/runtime/JSType.h (revision 205305) >+++ Source/JavaScriptCore/runtime/JSType.h (working copy) >@@ -82,8 +82,10 @@ enum JSType : uint8_t { > ModuleEnvironmentType, > RegExpObjectType, > ProxyObjectType, >+ JSMapType, >+ JSSetType, > >- LastJSCObjectType = ProxyObjectType, >+ LastJSCObjectType = JSSetType, > }; > > COMPILE_ASSERT(sizeof(JSType) == sizeof(uint8_t), sizeof_jstype_is_one_byte); >Index: Source/JavaScriptCore/runtime/MapBase.cpp >=================================================================== >--- Source/JavaScriptCore/runtime/MapBase.cpp (nonexistent) >+++ Source/JavaScriptCore/runtime/MapBase.cpp (working copy) >@@ -0,0 +1,50 @@ >+/* >+ * Copyright (C) 2016 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. >+ */ >+ >+#include "config.h" >+#include "MapBase.h" >+ >+#include "SlotVisitorInlines.h" >+ >+namespace JSC { >+ >+template <typename HashMapBucketType> >+void MapBase<HashMapBucketType>::visitChildren(JSCell* cell, SlotVisitor& visitor) >+{ >+ MapBase* thisObject = static_cast<MapBase*>(cell); >+ Base::visitChildren(thisObject, visitor); >+ visitor.append(&thisObject->m_map); >+} >+ >+template <typename HashMapBucketType> >+size_t MapBase<HashMapBucketType>::estimatedSize(JSCell* cell) >+{ >+ return Base::estimatedSize(cell) + static_cast<MapBase*>(cell)->m_map->approximateSize(); >+} >+ >+template class MapBase<HashMapBucket<HashMapBucketDataKeyValue>>; >+template class MapBase<HashMapBucket<HashMapBucketDataKey>>; >+ >+} // namespace JSC >Index: Source/JavaScriptCore/runtime/MapBase.h >=================================================================== >--- Source/JavaScriptCore/runtime/MapBase.h (nonexistent) >+++ Source/JavaScriptCore/runtime/MapBase.h (working copy) >@@ -0,0 +1,95 @@ >+/* >+ * Copyright (C) 2016 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 "HashMapImpl.h" >+#include "JSObject.h" >+ >+namespace JSC { >+ >+template <typename HashMapBucketType> >+class MapBase : public JSNonFinalObject { >+ typedef HashMapImpl<HashMapBucketType> HashMapImpl; >+ typedef JSNonFinalObject Base; >+public: >+ >+ typedef HashMapBucketType BucketType; >+ >+ ALWAYS_INLINE size_t size(ExecState*) >+ { >+ return m_map->size(); >+ } >+ >+ ALWAYS_INLINE bool has(ExecState* exec, JSValue key) >+ { >+ return m_map->has(exec, key); >+ } >+ >+ ALWAYS_INLINE void clear(ExecState* exec) >+ { >+ m_map->clear(exec); >+ } >+ >+ ALWAYS_INLINE bool remove(ExecState* exec, JSValue key) >+ { >+ return m_map->remove(exec, key); >+ } >+ >+ ALWAYS_INLINE HashMapBucketType** findBucket(ExecState* exec, JSValue key, uint32_t hash) >+ { >+ return m_map->findBucket(exec, key, hash); >+ } >+ >+ static ptrdiff_t offsetOfHashMapImpl() >+ { >+ return OBJECT_OFFSETOF(MapBase<HashMapBucketType>, m_map); >+ } >+ >+ ALWAYS_INLINE HashMapImpl* impl() { return m_map.get(); } >+ >+ void finishCreation(ExecState* exec, VM& vm) >+ { >+ Base::finishCreation(vm); >+ auto scope = DECLARE_THROW_SCOPE(vm); >+ HashMapImpl* impl = HashMapImpl::create(exec, vm); >+ if (UNLIKELY(scope.exception())) >+ return; >+ m_map.set(vm, this, impl); >+ } >+ >+protected: >+ MapBase(VM& vm, Structure* structure) >+ : Base(vm, structure) >+ { >+ } >+ >+ static size_t estimatedSize(JSCell*); >+ static void visitChildren(JSCell*, SlotVisitor&); >+ >+ WriteBarrier<HashMapImpl> m_map; >+}; >+ >+} // namespace JSC >Index: Source/JavaScriptCore/runtime/MapConstructor.cpp >=================================================================== >--- Source/JavaScriptCore/runtime/MapConstructor.cpp (revision 205305) >+++ Source/JavaScriptCore/runtime/MapConstructor.cpp (working copy) >@@ -62,9 +62,11 @@ static EncodedJSValue JSC_HOST_CALL cons > > JSGlobalObject* globalObject = asInternalFunction(exec->callee())->globalObject(); > Structure* mapStructure = InternalFunction::createSubclassStructure(exec, exec->newTarget(), globalObject->mapStructure()); >- if (exec->hadException()) >+ if (UNLIKELY(scope.exception())) >+ return JSValue::encode(JSValue()); >+ JSMap* map = JSMap::create(exec, vm, mapStructure); >+ if (UNLIKELY(scope.exception())) > return JSValue::encode(JSValue()); >- JSMap* map = JSMap::create(exec, mapStructure); > JSValue iterable = exec->argument(0); > if (iterable.isUndefinedOrNull()) > return JSValue::encode(map); >Index: Source/JavaScriptCore/runtime/MapIteratorPrototype.cpp >=================================================================== >--- Source/JavaScriptCore/runtime/MapIteratorPrototype.cpp (revision 205305) >+++ Source/JavaScriptCore/runtime/MapIteratorPrototype.cpp (working copy) >@@ -60,7 +60,6 @@ EncodedJSValue JSC_HOST_CALL MapIterator > JSValue result; > if (iterator->next(callFrame, result)) > return JSValue::encode(createIteratorResultObject(callFrame, result, false)); >- iterator->finish(); > return JSValue::encode(createIteratorResultObject(callFrame, jsUndefined(), true)); > } > >Index: Source/JavaScriptCore/runtime/MapPrototype.cpp >=================================================================== >--- Source/JavaScriptCore/runtime/MapPrototype.cpp (revision 205305) >+++ Source/JavaScriptCore/runtime/MapPrototype.cpp (working copy) >@@ -70,14 +70,13 @@ void MapPrototype::finishCreation(VM& vm > > JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->clear, mapProtoFuncClear, DontEnum, 0); > JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->deleteKeyword, mapProtoFuncDelete, DontEnum, 1); >- JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->get, mapProtoFuncGet, DontEnum, 1); >- JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->has, mapProtoFuncHas, DontEnum, 1); >+ JSC_NATIVE_INTRINSIC_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->get, mapProtoFuncGet, DontEnum, 1, JSMapGetIntrinsic); >+ JSC_NATIVE_INTRINSIC_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->has, mapProtoFuncHas, DontEnum, 1, JSMapHasIntrinsic); > JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->set, mapProtoFuncSet, DontEnum, 2); > JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->builtinNames().keysPublicName(), mapProtoFuncKeys, DontEnum, 0); > JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->builtinNames().valuesPublicName(), mapProtoFuncValues, DontEnum, 0); > >- // Private get / set operations. >- JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->builtinNames().getPrivateName(), mapProtoFuncGet, DontEnum, 1); >+ JSC_NATIVE_INTRINSIC_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->builtinNames().getPrivateName(), mapProtoFuncGet, DontEnum, 1, JSMapGetIntrinsic); > JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->builtinNames().setPrivateName(), mapProtoFuncSet, DontEnum, 2); > > JSFunction* entries = JSFunction::create(vm, globalObject, 0, vm.propertyNames->builtinNames().entriesPublicName().string(), mapProtoFuncEntries); >@@ -93,16 +92,21 @@ ALWAYS_INLINE static JSMap* getMap(CallF > VM& vm = callFrame->vm(); > auto scope = DECLARE_THROW_SCOPE(vm); > >- if (!thisValue.isObject()) { >+ if (UNLIKELY(!thisValue.isCell())) { > throwVMError(callFrame, scope, createNotAnObjectError(callFrame, thisValue)); > return nullptr; > } >- JSMap* map = jsDynamicCast<JSMap*>(thisValue); >- if (!map) { >- throwTypeError(callFrame, scope, ASCIILiteral("Map operation called on non-Map object")); >- return nullptr; >- } >- return map; >+ >+ if (LIKELY(thisValue.asCell()->type() == JSMapType)) >+ return jsCast<JSMap*>(thisValue); >+ throwTypeError(callFrame, scope, ASCIILiteral("Map operation called on non-Map object")); >+ return nullptr; >+} >+ >+EncodedJSValue JSC_HOST_CALL privateFuncIsMap(ExecState* exec) >+{ >+ JSValue value = exec->uncheckedArgument(0); >+ return JSValue::encode(jsBoolean(value.isCell() && value.asCell()->type() == JSMapType)); > } > > EncodedJSValue JSC_HOST_CALL mapProtoFuncClear(CallFrame* callFrame) >@@ -189,11 +193,6 @@ EncodedJSValue JSC_HOST_CALL mapProtoFun > return JSValue::encode(JSMapIterator::create(vm, callFrame->callee()->globalObject()->mapIteratorStructure(), thisObj, IterateKey)); > } > >-EncodedJSValue JSC_HOST_CALL privateFuncIsMap(ExecState* exec) >-{ >- return JSValue::encode(jsBoolean(jsDynamicCast<JSMap*>(exec->uncheckedArgument(0)))); >-} >- > EncodedJSValue JSC_HOST_CALL privateFuncMapIterator(ExecState* exec) > { > ASSERT(jsDynamicCast<JSMap*>(exec->uncheckedArgument(0))); >@@ -206,13 +205,12 @@ EncodedJSValue JSC_HOST_CALL privateFunc > ASSERT(jsDynamicCast<JSMapIterator*>(exec->thisValue())); > JSMapIterator* iterator = jsCast<JSMapIterator*>(exec->thisValue()); > JSValue key, value; >- if (iterator->nextKeyValue(key, value)) { >+ if (iterator->nextKeyValue(exec, key, value)) { > JSArray* resultArray = jsCast<JSArray*>(exec->uncheckedArgument(0)); > resultArray->putDirectIndex(exec, 0, key); > resultArray->putDirectIndex(exec, 1, value); > return JSValue::encode(jsBoolean(false)); > } >- iterator->finish(); > return JSValue::encode(jsBoolean(true)); > } > >Index: Source/JavaScriptCore/runtime/PropertyDescriptor.cpp >=================================================================== >--- Source/JavaScriptCore/runtime/PropertyDescriptor.cpp (revision 205305) >+++ Source/JavaScriptCore/runtime/PropertyDescriptor.cpp (working copy) >@@ -191,22 +191,6 @@ void PropertyDescriptor::setGetter(JSVal > m_attributes &= ~ReadOnly; > } > >-// See ES5.1 9.12 >-bool sameValue(ExecState* exec, JSValue a, JSValue b) >-{ >- if (!a.isNumber()) >- return JSValue::strictEqual(exec, a, b); >- if (!b.isNumber()) >- return false; >- double x = a.asNumber(); >- double y = b.asNumber(); >- bool xIsNaN = std::isnan(x); >- bool yIsNaN = std::isnan(y); >- if (xIsNaN || yIsNaN) >- return xIsNaN && yIsNaN; >- return bitwise_cast<uint64_t>(x) == bitwise_cast<uint64_t>(y); >-} >- > bool PropertyDescriptor::equalTo(ExecState* exec, const PropertyDescriptor& other) const > { > if (other.m_value.isEmpty() != m_value.isEmpty() >Index: Source/JavaScriptCore/runtime/PropertyDescriptor.h >=================================================================== >--- Source/JavaScriptCore/runtime/PropertyDescriptor.h (revision 205305) >+++ Source/JavaScriptCore/runtime/PropertyDescriptor.h (working copy) >@@ -32,9 +32,6 @@ namespace JSC { > > class GetterSetter; > >-// See ES5.1 9.12 >-bool sameValue(ExecState*, JSValue, JSValue); >- > class PropertyDescriptor { > public: > PropertyDescriptor() >Index: Source/JavaScriptCore/runtime/SetConstructor.cpp >=================================================================== >--- Source/JavaScriptCore/runtime/SetConstructor.cpp (revision 205305) >+++ Source/JavaScriptCore/runtime/SetConstructor.cpp (working copy) >@@ -63,9 +63,11 @@ static EncodedJSValue JSC_HOST_CALL cons > > JSGlobalObject* globalObject = asInternalFunction(exec->callee())->globalObject(); > Structure* setStructure = InternalFunction::createSubclassStructure(exec, exec->newTarget(), globalObject->setStructure()); >- if (exec->hadException()) >+ if (UNLIKELY(scope.exception())) >+ return JSValue::encode(JSValue()); >+ JSSet* set = JSSet::create(exec, vm, setStructure); >+ if (UNLIKELY(scope.exception())) > return JSValue::encode(JSValue()); >- JSSet* set = JSSet::create(exec, setStructure); > JSValue iterable = exec->argument(0); > if (iterable.isUndefinedOrNull()) > return JSValue::encode(set); >Index: Source/JavaScriptCore/runtime/SetIteratorPrototype.cpp >=================================================================== >--- Source/JavaScriptCore/runtime/SetIteratorPrototype.cpp (revision 205305) >+++ Source/JavaScriptCore/runtime/SetIteratorPrototype.cpp (working copy) >@@ -60,7 +60,6 @@ EncodedJSValue JSC_HOST_CALL SetIterator > > if (iterator->next(callFrame, result)) > return JSValue::encode(createIteratorResultObject(callFrame, result, false)); >- iterator->finish(); > return JSValue::encode(createIteratorResultObject(callFrame, jsUndefined(), true)); > } > >Index: Source/JavaScriptCore/runtime/SetPrototype.cpp >=================================================================== >--- Source/JavaScriptCore/runtime/SetPrototype.cpp (revision 205305) >+++ Source/JavaScriptCore/runtime/SetPrototype.cpp (working copy) >@@ -70,7 +70,7 @@ void SetPrototype::finishCreation(VM& vm > JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->add, setProtoFuncAdd, DontEnum, 1); > JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->clear, setProtoFuncClear, DontEnum, 0); > JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->deleteKeyword, setProtoFuncDelete, DontEnum, 1); >- JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->has, setProtoFuncHas, DontEnum, 1); >+ JSC_NATIVE_INTRINSIC_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->has, setProtoFuncHas, DontEnum, 1, JSSetHasIntrinsic); > JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->builtinNames().entriesPublicName(), setProtoFuncEntries, DontEnum, 0); > > JSFunction* values = JSFunction::create(vm, globalObject, 0, vm.propertyNames->builtinNames().valuesPublicName().string(), setProtoFuncValues); >@@ -87,16 +87,14 @@ ALWAYS_INLINE static JSSet* getSet(CallF > VM& vm = callFrame->vm(); > auto scope = DECLARE_THROW_SCOPE(vm); > >- if (!thisValue.isObject()) { >+ if (UNLIKELY(!thisValue.isCell())) { > throwVMError(callFrame, scope, createNotAnObjectError(callFrame, thisValue)); > return nullptr; > } >- JSSet* set = jsDynamicCast<JSSet*>(thisValue); >- if (!set) { >- throwTypeError(callFrame, scope, ASCIILiteral("Set operation called on non-Set object")); >- return nullptr; >- } >- return set; >+ if (LIKELY(thisValue.asCell()->type() == JSSetType)) >+ return jsCast<JSSet*>(thisValue); >+ throwTypeError(callFrame, scope, ASCIILiteral("Set operation called on non-Set object")); >+ return nullptr; > } > > EncodedJSValue JSC_HOST_CALL setProtoFuncAdd(CallFrame* callFrame) >@@ -186,7 +184,6 @@ EncodedJSValue JSC_HOST_CALL privateFunc > resultArray->putDirectIndex(exec, 0, result); > return JSValue::encode(jsBoolean(false)); > } >- iterator->finish(); > return JSValue::encode(jsBoolean(true)); > } > >Index: Source/JavaScriptCore/runtime/VM.cpp >=================================================================== >--- Source/JavaScriptCore/runtime/VM.cpp (revision 205305) >+++ Source/JavaScriptCore/runtime/VM.cpp (working copy) >@@ -65,6 +65,7 @@ > #include "JSInternalPromiseDeferred.h" > #include "JSLexicalEnvironment.h" > #include "JSLock.h" >+#include "JSMap.h" > #include "JSPromiseDeferred.h" > #include "JSPropertyNameEnumerator.h" > #include "JSTemplateRegistryKey.h" >@@ -249,6 +250,10 @@ VM::VM(VMType vmType, HeapType heapType) > #if ENABLE(WEBASSEMBLY) > webAssemblyCodeBlockStructure.set(*this, WebAssemblyCodeBlock::createStructure(*this, 0, jsNull())); > #endif >+ hashMapBucketSetStructure.set(*this, HashMapBucket<HashMapBucketDataKey>::createStructure(*this, 0, jsNull())); >+ hashMapBucketMapStructure.set(*this, HashMapBucket<HashMapBucketDataKeyValue>::createStructure(*this, 0, jsNull())); >+ hashMapImplSetStructure.set(*this, HashMapImpl<HashMapBucket<HashMapBucketDataKey>>::createStructure(*this, 0, jsNull())); >+ hashMapImplMapStructure.set(*this, HashMapImpl<HashMapBucket<HashMapBucketDataKeyValue>>::createStructure(*this, 0, jsNull())); > > iterationTerminator.set(*this, JSFinalObject::create(*this, JSFinalObject::createStructure(*this, 0, jsNull(), 1))); > nativeStdFunctionCellStructure.set(*this, NativeStdFunctionCell::createStructure(*this, 0, jsNull())); >Index: Source/JavaScriptCore/runtime/VM.h >=================================================================== >--- Source/JavaScriptCore/runtime/VM.h (revision 205305) >+++ Source/JavaScriptCore/runtime/VM.h (working copy) >@@ -331,6 +331,10 @@ public: > Strong<Structure> evalCodeBlockStructure; > Strong<Structure> functionCodeBlockStructure; > Strong<Structure> webAssemblyCodeBlockStructure; >+ Strong<Structure> hashMapBucketSetStructure; >+ Strong<Structure> hashMapBucketMapStructure; >+ Strong<Structure> hashMapImplSetStructure; >+ Strong<Structure> hashMapImplMapStructure; > > Strong<JSCell> iterationTerminator; > Strong<JSCell> emptyPropertyNameEnumerator; >Index: Source/WebCore/ChangeLog >=================================================================== >--- Source/WebCore/ChangeLog (revision 205305) >+++ Source/WebCore/ChangeLog (working copy) >@@ -1,3 +1,17 @@ >+2016-09-01 Saam Barati <sbarati@apple.com> >+ >+ Make JSMap and JSSet faster >+ https://bugs.webkit.org/show_bug.cgi?id=160989 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ No new tests (OOPS!). >+ >+ * ForwardingHeaders/runtime/MapBase.h: Added. >+ * bindings/js/SerializedScriptValue.cpp: >+ (WebCore::CloneSerializer::serialize): >+ (WebCore::CloneDeserializer::deserialize): >+ > 2016-09-01 Alex Christensen <achristensen@webkit.org> > > Fix Mac CMake build after r205266. >Index: Source/WebCore/ForwardingHeaders/runtime/MapBase.h >=================================================================== >--- Source/WebCore/ForwardingHeaders/runtime/MapBase.h (nonexistent) >+++ Source/WebCore/ForwardingHeaders/runtime/MapBase.h (working copy) >@@ -0,0 +1,4 @@ >+#ifndef WebCore_FWD_MapBase_h >+#define WebCore_FWD_MapBase_h >+#include <JavaScriptCore/MapBase.h> >+#endif >Index: Source/WebCore/bindings/js/SerializedScriptValue.cpp >=================================================================== >--- Source/WebCore/bindings/js/SerializedScriptValue.cpp (revision 205305) >+++ Source/WebCore/bindings/js/SerializedScriptValue.cpp (working copy) >@@ -1368,7 +1368,7 @@ SerializationReturnCode CloneSerializer: > case MapDataStartVisitEntry: { > JSMapIterator* iterator = mapIteratorStack.last(); > JSValue key, value; >- if (!iterator->nextKeyValue(key, value)) { >+ if (!iterator->nextKeyValue(m_exec, key, value)) { > mapIteratorStack.removeLast(); > JSObject* object = inputObjectStack.last(); > ASSERT(jsDynamicCast<JSMap*>(object)); >@@ -2545,7 +2545,9 @@ DeserializationResult CloneDeserializer: > mapObjectStartState: { > if (outputObjectStack.size() > maximumFilterRecursion) > return std::make_pair(JSValue(), StackOverflowError); >- JSMap* map = JSMap::create(m_exec->vm(), m_globalObject->mapStructure()); >+ JSMap* map = JSMap::create(m_exec, m_exec->vm(), m_globalObject->mapStructure()); >+ if (UNLIKELY(m_exec->hadException())) >+ goto error; > m_gcBuffer.append(map); > outputObjectStack.append(map); > mapStack.append(map); >@@ -2574,7 +2576,9 @@ DeserializationResult CloneDeserializer: > setObjectStartState: { > if (outputObjectStack.size() > maximumFilterRecursion) > return std::make_pair(JSValue(), StackOverflowError); >- JSSet* set = JSSet::create(m_exec->vm(), m_globalObject->setStructure()); >+ JSSet* set = JSSet::create(m_exec, m_exec->vm(), m_globalObject->setStructure()); >+ if (UNLIKELY(m_exec->hadException())) >+ goto error; > m_gcBuffer.append(set); > outputObjectStack.append(set); > setStack.append(set);
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 160989
:
286435
|
286517
|
286940
|
286953
|
287064
|
287143
|
287367
|
287466
|
287475
|
287592
|
287687
|
287700
|
287702
|
287714
|
287782
|
287802
|
287803
|
288038
|
288041
|
288057