Changeset 245669 in webkit
- Timestamp:
- May 22, 2019, 6:47:29 PM (7 years ago)
- Location:
- trunk/Source/JavaScriptCore
- Files:
-
- 1 added
- 10 edited
-
ChangeLog (modified) (1 diff)
-
JavaScriptCore.xcodeproj/project.pbxproj (modified) (2 diffs)
-
Sources.txt (modified) (1 diff)
-
bytecode/MetadataTable.cpp (modified) (1 diff)
-
bytecode/MetadataTable.h (modified) (3 diffs)
-
bytecode/Opcode.cpp (modified) (2 diffs)
-
bytecode/UnlinkedMetadataTable.cpp (added)
-
bytecode/UnlinkedMetadataTable.h (modified) (3 diffs)
-
bytecode/UnlinkedMetadataTableInlines.h (modified) (7 diffs)
-
llint/LowLevelInterpreter.asm (modified) (2 diffs)
-
runtime/CachedTypes.cpp (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/JavaScriptCore/ChangeLog
r245667 r245669 1 2019-05-22 Yusuke Suzuki <ysuzuki@apple.com> 2 3 [JSC] UnlinkedMetadataTable's offset table should be small 4 https://bugs.webkit.org/show_bug.cgi?id=197910 5 6 Reviewed by Saam Barati. 7 8 In Gmail, we found that massive # of UnlinkedMetadataTable (21979 - 24727) exists. Each UnlinkedMetadataTable takes at least 204 bytes 9 because of large (unsinged) offset table. This patch reduces the size of offset table by introducing 16bit version offset table. 10 Previously our code for looking up Metadata is like this. 11 12 offset = offsetTable32[opcode] 13 metadata = (SomeOp::Metadata*)table[offset] + id 14 15 Instead, we introduce uint16_t offset table. The lookup code becomes like this. 16 17 offset = offsetTable16[opcode] 18 if (!offset) 19 offset = offsetTable32[opcode] 20 metadata = (SomeOp::Metadata*)table[offset] + id 21 22 We use 0 offset as a marker to indicate that we have 32bit offset table. This is OK since 0 offset does not appear since all the offsets 23 included in this table is larger than s_offset16TableSize. 24 25 32bit offset table is allocated only when the offset exceeds 16bit range. It means that this will be used only when Metadata table is larger 26 than almost 64KB. Even in Gmail, such MetadataTable is rare, and additional 32bit offset table size does not matter much in this case since 27 MetadataTable is already so large. 28 29 Based on the # of UnlinkedMetadataTables, this optimization should improve Gmail steady state memory by 2MB. 30 31 * JavaScriptCore.xcodeproj/project.pbxproj: 32 * Sources.txt: 33 * bytecode/MetadataTable.cpp: 34 (JSC::MetadataTable::~MetadataTable): 35 (JSC::MetadataTable::destroy): 36 * bytecode/MetadataTable.h: 37 (JSC::MetadataTable::ref): 38 (JSC::MetadataTable::deref): 39 (JSC::MetadataTable::buffer): 40 (JSC::MetadataTable::is32Bit const): 41 (JSC::MetadataTable::offsetTable16 const): 42 (JSC::MetadataTable::offsetTable32 const): 43 (JSC::MetadataTable::totalSize const): 44 (JSC::MetadataTable::getOffset const): 45 (JSC::MetadataTable::getImpl): 46 (JSC::MetadataTable::ref const): Deleted. 47 (JSC::MetadataTable::deref const): Deleted. 48 * bytecode/Opcode.cpp: 49 * bytecode/UnlinkedMetadataTable.cpp: Added. 50 (JSC::UnlinkedMetadataTable::finalize): 51 * bytecode/UnlinkedMetadataTable.h: 52 (JSC::UnlinkedMetadataTable::create): 53 (JSC::UnlinkedMetadataTable::totalSize const): 54 (JSC::UnlinkedMetadataTable::offsetTableSize const): 55 (JSC::UnlinkedMetadataTable::preprocessBuffer const): 56 (JSC::UnlinkedMetadataTable::buffer const): 57 (JSC::UnlinkedMetadataTable::offsetTable16 const): 58 (JSC::UnlinkedMetadataTable::offsetTable32 const): 59 * bytecode/UnlinkedMetadataTableInlines.h: 60 (JSC::UnlinkedMetadataTable::UnlinkedMetadataTable): 61 (JSC::UnlinkedMetadataTable::addEntry): 62 (JSC::UnlinkedMetadataTable::sizeInBytes): 63 (JSC::UnlinkedMetadataTable::link): 64 (JSC::UnlinkedMetadataTable::unlink): 65 (JSC::UnlinkedMetadataTable::finalize): Deleted. 66 * llint/LowLevelInterpreter.asm: 67 * runtime/CachedTypes.cpp: 68 (JSC::CachedMetadataTable::encode): 69 (JSC::CachedMetadataTable::decode const): 70 1 71 2019-05-22 Yusuke Suzuki <ysuzuki@apple.com> 2 72 -
trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
r245564 r245669 4725 4725 E18E3A560DF9278C00D90B34 /* VM.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = VM.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; 4726 4726 E18E3A570DF9278C00D90B34 /* VM.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; path = VM.cpp; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.cpp; }; 4727 E3060128228F978100FAABDF /* UnlinkedMetadataTable.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = UnlinkedMetadataTable.cpp; sourceTree = "<group>"; }; 4727 4728 E30677971B8BC6F5003F87F0 /* ModuleLoader.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = ModuleLoader.js; sourceTree = "<group>"; }; 4728 4729 E31179A92288385D00514B2C /* SymbolTableOrScopeDepth.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SymbolTableOrScopeDepth.h; sourceTree = "<group>"; }; … … 8068 8069 14142E501B796ECE00F4BF4B /* UnlinkedFunctionExecutable.h */, 8069 8070 14AD911C1DCA9FA40014F9FE /* UnlinkedGlobalCodeBlock.h */, 8071 E3060128228F978100FAABDF /* UnlinkedMetadataTable.cpp */, 8070 8072 142D52BE21762958002DB086 /* UnlinkedMetadataTable.h */, 8071 8073 142D52BD21762957002DB086 /* UnlinkedMetadataTableInlines.h */, -
trunk/Source/JavaScriptCore/Sources.txt
r245214 r245669 274 274 bytecode/UnlinkedFunctionCodeBlock.cpp 275 275 bytecode/UnlinkedFunctionExecutable.cpp 276 bytecode/UnlinkedMetadataTable.cpp 276 277 bytecode/UnlinkedModuleProgramCodeBlock.cpp 277 278 bytecode/UnlinkedProgramCodeBlock.cpp -
trunk/Source/JavaScriptCore/bytecode/MetadataTable.cpp
r244088 r245669 57 57 for (unsigned i = 0; i < NUMBER_OF_BYTECODE_WITH_METADATA; i++) 58 58 getOpcodeType<DeallocTable>(static_cast<OpcodeID>(i), this); 59 Ref<UnlinkedMetadataTable> unlinkedMetadata = WTFMove(linkingData().unlinkedMetadata);60 59 linkingData().~LinkingData(); 60 } 61 62 void MetadataTable::destroy(MetadataTable* table) 63 { 64 Ref<UnlinkedMetadataTable> unlinkedMetadata = WTFMove(table->linkingData().unlinkedMetadata); 65 table->~MetadataTable(); 61 66 // Since UnlinkedMetadata::unlink frees the underlying memory of MetadataTable. 62 67 // We need to destroy LinkingData before calling it. 63 unlinkedMetadata->unlink(*t his);68 unlinkedMetadata->unlink(*table); 64 69 } 65 70 -
trunk/Source/JavaScriptCore/bytecode/MetadataTable.h
r245658 r245669 64 64 size_t sizeInBytes(); 65 65 66 void ref() const66 void ref() 67 67 { 68 68 ++linkingData().refCount; 69 69 } 70 70 71 void deref() const71 void deref() 72 72 { 73 73 unsigned tempRefCount = linkingData().refCount - 1; 74 74 if (!tempRefCount) { 75 this->~MetadataTable();75 MetadataTable::destroy(this); 76 76 return; 77 77 } … … 92 92 MetadataTable(UnlinkedMetadataTable&); 93 93 94 UnlinkedMetadataTable::Offset16* offsetTable16() const { return bitwise_cast<UnlinkedMetadataTable::Offset16*>(this); } 95 UnlinkedMetadataTable::Offset32* offsetTable32() const { return bitwise_cast<UnlinkedMetadataTable::Offset32*>(bitwise_cast<uint8_t*>(this) + UnlinkedMetadataTable::s_offset16TableSize); } 96 97 size_t totalSize() const 98 { 99 return getOffset(UnlinkedMetadataTable::s_offsetTableEntries - 1); 100 } 101 94 102 UnlinkedMetadataTable::LinkingData& linkingData() const 95 103 { … … 97 105 } 98 106 99 UnlinkedMetadataTable::Offset* buffer() 107 void* buffer() { return this; } 108 109 bool is32Bit() const { return !offsetTable16()[0]; } 110 111 ALWAYS_INLINE unsigned getOffset(unsigned i) const 100 112 { 101 return bitwise_cast<UnlinkedMetadataTable::Offset*>(this); 113 unsigned offset = offsetTable16()[i]; 114 if (offset) 115 return offset; 116 return offsetTable32()[i]; 102 117 } 103 118 104 119 ALWAYS_INLINE uint8_t* getImpl(unsigned i) 105 120 { 106 return bitwise_cast<uint8_t*>(this) + buffer()[i];121 return bitwise_cast<uint8_t*>(this) + getOffset(i); 107 122 } 123 124 static void destroy(MetadataTable*); 108 125 }; 109 126 -
trunk/Source/JavaScriptCore/bytecode/Opcode.cpp
r243633 r245669 204 204 #endif 205 205 206 static unsigned metadataSizes[] = {206 static const unsigned metadataSizes[] = { 207 207 208 208 #define METADATA_SIZE(size) size, … … 212 212 }; 213 213 214 static unsigned metadataAlignments[] = {214 static const unsigned metadataAlignments[] = { 215 215 216 216 #define METADATA_ALIGNMENT(size) size, -
trunk/Source/JavaScriptCore/bytecode/UnlinkedMetadataTable.h
r244019 r245669 38 38 friend class MetadataTable; 39 39 friend class CachedMetadataTable; 40 public: 41 static constexpr unsigned s_maxMetadataAlignment = 8; 40 42 41 public:42 43 struct LinkingData { 43 44 Ref<UnlinkedMetadataTable> unlinkedMetadata; … … 62 63 private: 63 64 UnlinkedMetadataTable(); 65 UnlinkedMetadataTable(bool is32Bit); 66 67 static Ref<UnlinkedMetadataTable> create(bool is32Bit) 68 { 69 return adoptRef(*new UnlinkedMetadataTable(is32Bit)); 70 } 64 71 65 72 void unlink(MetadataTable&); … … 67 74 size_t sizeInBytes(MetadataTable&); 68 75 69 using Offset = unsigned; 76 unsigned totalSize() const 77 { 78 ASSERT(m_isFinalized); 79 if (m_is32Bit) 80 return offsetTable32()[s_offsetTableEntries - 1]; 81 return offsetTable16()[s_offsetTableEntries - 1]; 82 } 83 84 unsigned offsetTableSize() const 85 { 86 ASSERT(m_isFinalized); 87 if (m_is32Bit) 88 return s_offset16TableSize + s_offset32TableSize; 89 return s_offset16TableSize; 90 } 91 92 using Offset32 = uint32_t; 93 using Offset16 = uint16_t; 70 94 71 95 static constexpr unsigned s_offsetTableEntries = NUMBER_OF_BYTECODE_WITH_METADATA + 1; // one extra entry for the "end" offset; 72 static constexpr unsigned s_offsetTableSize = s_offsetTableEntries * sizeof(UnlinkedMetadataTable::Offset);73 96 74 Offset* buffer() const { return bitwise_cast<Offset*>(bitwise_cast<uint8_t*>(m_rawBuffer) + sizeof(LinkingData)); } 97 // Not to break alignment of 32bit offset table, we round up size with sizeof(Offset32). 98 static constexpr unsigned s_offset16TableSize = roundUpToMultipleOf<sizeof(Offset32)>(s_offsetTableEntries * sizeof(Offset16)); 99 // Not to break alignment of the metadata calculated based on the alignment of s_offset16TableSize, s_offset32TableSize must be rounded by 8. 100 // Then, s_offset16TableSize and s_offset16TableSize + s_offset32TableSize offer the same alignment characteristics for subsequent Metadata. 101 static constexpr unsigned s_offset32TableSize = roundUpToMultipleOf<s_maxMetadataAlignment>(s_offsetTableEntries * sizeof(Offset32)); 102 103 Offset32* preprocessBuffer() const { return bitwise_cast<Offset32*>(m_rawBuffer + sizeof(LinkingData)); } 104 void* buffer() const { return m_rawBuffer + sizeof(LinkingData); } 105 106 Offset16* offsetTable16() const 107 { 108 ASSERT(!m_is32Bit); 109 return bitwise_cast<Offset16*>(m_rawBuffer + sizeof(LinkingData)); 110 } 111 Offset32* offsetTable32() const 112 { 113 ASSERT(m_is32Bit); 114 return bitwise_cast<Offset32*>(m_rawBuffer + sizeof(LinkingData) + s_offset16TableSize); 115 } 75 116 76 117 bool m_hasMetadata : 1; 77 118 bool m_isFinalized : 1; 78 119 bool m_isLinked : 1; 79 void* m_rawBuffer; 120 bool m_is32Bit : 1; 121 uint8_t* m_rawBuffer; 80 122 }; 81 123 -
trunk/Source/JavaScriptCore/bytecode/UnlinkedMetadataTableInlines.h
r240915 r245669 36 36 , m_isFinalized(false) 37 37 , m_isLinked(false) 38 , m_rawBuffer(fastZeroedMalloc(sizeof(LinkingData) + s_offsetTableSize)) 38 , m_is32Bit(false) 39 , m_rawBuffer(static_cast<uint8_t*>(fastZeroedMalloc(sizeof(LinkingData) + s_offset32TableSize))) 40 { 41 } 42 43 ALWAYS_INLINE UnlinkedMetadataTable::UnlinkedMetadataTable(bool is32Bit) 44 : m_hasMetadata(false) 45 , m_isFinalized(false) 46 , m_isLinked(false) 47 , m_is32Bit(is32Bit) 48 , m_rawBuffer(static_cast<uint8_t*>(fastZeroedMalloc(sizeof(LinkingData) + (is32Bit ? s_offset16TableSize + s_offset32TableSize : s_offset16TableSize)))) 39 49 { 40 50 } … … 51 61 ASSERT(!m_isFinalized && opcodeID < s_offsetTableEntries - 1); 52 62 m_hasMetadata = true; 53 return buffer()[opcodeID]++;63 return preprocessBuffer()[opcodeID]++; 54 64 } 55 65 … … 59 69 return 0; 60 70 61 return s_offsetTableSize; 71 if (m_is32Bit) 72 return s_offset16TableSize + s_offset32TableSize; 73 return s_offset16TableSize; 62 74 } 63 75 … … 68 80 // In this case, we return the size of the table minus the offset table, 69 81 // which was already accounted for in the UnlinkedCodeBlock. 82 size_t result = totalSize(); 70 83 if (metadataTable.buffer() == buffer()) { 71 84 ASSERT(m_isLinked); 72 return buffer()[s_offsetTableEntries - 1] - s_offsetTableSize; 85 if (m_is32Bit) 86 return result - (s_offset16TableSize + s_offset32TableSize); 87 return result - s_offset16TableSize; 73 88 } 74 75 return metadataTable.buffer()[s_offsetTableEntries - 1]; 76 } 77 78 ALWAYS_INLINE void UnlinkedMetadataTable::finalize() 79 { 80 ASSERT(!m_isFinalized); 81 m_isFinalized = true; 82 if (!m_hasMetadata) { 83 fastFree(m_rawBuffer); 84 m_rawBuffer = nullptr; 85 return; 86 } 87 88 unsigned offset = s_offsetTableSize; 89 for (unsigned i = 0; i < s_offsetTableEntries - 1; i++) { 90 unsigned numberOfEntries = buffer()[i]; 91 92 if (numberOfEntries > 0) { 93 offset = roundUpToMultipleOf(metadataAlignment(static_cast<OpcodeID>(i)), offset); 94 buffer()[i] = offset; 95 offset += numberOfEntries * metadataSize(static_cast<OpcodeID>(i)); 96 } else 97 buffer()[i] = offset; 98 } 99 buffer()[s_offsetTableEntries - 1] = offset; 89 return result; 100 90 } 101 91 … … 107 97 return nullptr; 108 98 109 unsigned totalSize = buffer()[s_offsetTableEntries - 1]; 99 unsigned totalSize = this->totalSize(); 100 unsigned offsetTableSize = this->offsetTableSize(); 110 101 uint8_t* buffer; 111 102 if (!m_isLinked) { … … 114 105 } else { 115 106 buffer = reinterpret_cast<uint8_t*>(fastMalloc(sizeof(LinkingData) + totalSize)); 116 memcpy(buffer, m_rawBuffer, sizeof(LinkingData) + s_offsetTableSize);107 memcpy(buffer, m_rawBuffer, sizeof(LinkingData) + offsetTableSize); 117 108 } 118 memset(buffer + sizeof(LinkingData) + s_offsetTableSize, 0, totalSize - s_offsetTableSize);109 memset(buffer + sizeof(LinkingData) + offsetTableSize, 0, totalSize - offsetTableSize); 119 110 return adoptRef(*new (buffer + sizeof(LinkingData)) MetadataTable(*this)); 120 111 } … … 129 120 ASSERT(m_isLinked); 130 121 m_isLinked = false; 131 m_rawBuffer = fastRealloc(m_rawBuffer, sizeof(LinkingData) + s_offsetTableSize);122 m_rawBuffer = static_cast<uint8_t*>(fastRealloc(m_rawBuffer, sizeof(LinkingData) + offsetTableSize())); 132 123 return; 133 124 } -
trunk/Source/JavaScriptCore/llint/LowLevelInterpreter.asm
r243254 r245669 181 181 const FirstArgumentOffset = ThisArgumentOffset + SlotSize 182 182 const CallFrameHeaderSize = ThisArgumentOffset 183 184 const MetadataOffsetTable16Offset = 0 185 const MetadataOffsetTable32Offset = constexpr UnlinkedMetadataTable::s_offset16TableSize 183 186 184 187 # Some value representation constants. … … 337 340 338 341 macro metadata(size, opcode, dst, scratch) 339 loadi constexpr %opcode%::opcodeID * 4[metadataTable], dst # offset = metadataTable<unsigned*>[opcodeID] 342 loadh (constexpr %opcode%::opcodeID * 2 + MetadataOffsetTable16Offset)[metadataTable], dst # offset = metadataTable<uint16_t*>[opcodeID] 343 btinz dst, .setUpOffset 344 loadi (constexpr %opcode%::opcodeID * 4 + MetadataOffsetTable32Offset)[metadataTable], dst # offset = metadataTable<uint32_t*>[opcodeID] 345 .setUpOffset: 340 346 getu(size, opcode, m_metadataID, scratch) # scratch = bytecode.m_metadataID 341 347 muli sizeof %opcode%::Metadata, scratch # scratch *= sizeof(Op::Metadata) -
trunk/Source/JavaScriptCore/runtime/CachedTypes.cpp
r245563 r245669 1349 1349 if (!m_hasMetadata) 1350 1350 return; 1351 for (unsigned i = UnlinkedMetadataTable::s_offsetTableEntries; i--;) 1352 m_metadata[i] = metadataTable.buffer()[i]; 1351 m_is32Bit = metadataTable.m_is32Bit; 1352 if (m_is32Bit) { 1353 for (unsigned i = UnlinkedMetadataTable::s_offsetTableEntries; i--;) 1354 m_metadata[i] = metadataTable.offsetTable32()[i]; 1355 } else { 1356 for (unsigned i = UnlinkedMetadataTable::s_offsetTableEntries; i--;) 1357 m_metadata[i] = metadataTable.offsetTable16()[i]; 1358 } 1353 1359 } 1354 1360 1355 1361 Ref<UnlinkedMetadataTable> decode(Decoder&) const 1356 1362 { 1357 Ref<UnlinkedMetadataTable> metadataTable = UnlinkedMetadataTable::create( );1363 Ref<UnlinkedMetadataTable> metadataTable = UnlinkedMetadataTable::create(m_is32Bit); 1358 1364 metadataTable->m_isFinalized = true; 1359 1365 metadataTable->m_isLinked = false; 1360 1366 metadataTable->m_hasMetadata = m_hasMetadata; 1361 for (unsigned i = UnlinkedMetadataTable::s_offsetTableEntries; i--;) 1362 metadataTable->buffer()[i] = m_metadata[i]; 1367 if (m_is32Bit) { 1368 for (unsigned i = UnlinkedMetadataTable::s_offsetTableEntries; i--;) 1369 metadataTable->offsetTable32()[i] = m_metadata[i]; 1370 } else { 1371 for (unsigned i = UnlinkedMetadataTable::s_offsetTableEntries; i--;) 1372 metadataTable->offsetTable16()[i] = m_metadata[i]; 1373 } 1363 1374 return metadataTable; 1364 1375 } … … 1366 1377 private: 1367 1378 bool m_hasMetadata; 1379 bool m_is32Bit; 1368 1380 std::array<unsigned, UnlinkedMetadataTable::s_offsetTableEntries> m_metadata; 1369 1381 };
Note:
See TracChangeset
for help on using the changeset viewer.