Changeset 242096 in webkit
- Timestamp:
- Feb 26, 2019 11:41:21 AM (5 years ago)
- Location:
- trunk/Source/JavaScriptCore
- Files:
-
- 10 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/JavaScriptCore/ChangeLog
r242087 r242096 1 2019-02-26 Mark Lam <mark.lam@apple.com> 2 3 [Re-landing] Add some randomness into the StructureID. 4 https://bugs.webkit.org/show_bug.cgi?id=194989 5 <rdar://problem/47975563> 6 7 Reviewed by Yusuke Suzuki. 8 9 1. On 64-bit, the StructureID will now be encoded as: 10 11 ---------------------------------------------------------------- 12 | 1 Nuke Bit | 24 StructureIDTable index bits | 7 entropy bits | 13 ---------------------------------------------------------------- 14 15 The entropy bits are chosen at random and assigned when a StructureID is 16 allocated. 17 18 2. Instead of Structure pointers, the StructureIDTable will now contain 19 encodedStructureBits, which is encoded as such: 20 21 ---------------------------------------------------------------- 22 | 7 entropy bits | 57 structure pointer bits | 23 ---------------------------------------------------------------- 24 25 The entropy bits here are the same 7 bits used in the encoding of the 26 StructureID for this structure entry in the StructureIDTable. 27 28 3. Retrieval of the structure pointer given a StructureID is now computed as 29 follows: 30 31 index = structureID >> 7; // with arithmetic shift. 32 encodedStructureBits = structureIDTable[index]; 33 structure = encodedStructureBits ^ (structureID << 57); 34 35 We use an arithmetic shift for the right shift because that will preserve 36 the nuke bit in the high bit of the index if the StructureID was not 37 decontaminated before use as expected. 38 39 4. Remove unused function loadArgumentWithSpecificClass() in SpecializedThunkJIT. 40 41 5. Define StructureIDTable::m_size to be the number of allocated StructureIDs 42 instead of always being the same as m_capacity. 43 44 6. Change StructureIDTable::s_unusedID's value to 0. 45 46 Its previous value of unusedPointer i.e. 0xd1e7beef, does not make sense for 47 StructureID on 64-bit. Also, there was never any code that initializes unused 48 IDs to the s_unusedID. The only meaningful value for s_unusedID is 0, which 49 is the ID we'll get when the freelist is empty, prompting a resize of the 50 structureIDTable. 51 52 This patch appears to be perf neutral on JetStream 2 run via the cli on a 53 11" MacBook Air, 13" MacBook Pro, iPhone 6S, and iPhone XR. 54 55 * ftl/FTLLowerDFGToB3.cpp: 56 (JSC::FTL::DFG::LowerDFGToB3::loadStructure): 57 * heap/SlotVisitor.cpp: 58 (JSC::SlotVisitor::appendJSCellOrAuxiliary): 59 * jit/AssemblyHelpers.cpp: 60 (JSC::AssemblyHelpers::emitLoadStructure): 61 * jit/AssemblyHelpers.h: 62 * jit/SpecializedThunkJIT.h: 63 (JSC::SpecializedThunkJIT::loadArgumentWithSpecificClass): Deleted. 64 * llint/LowLevelInterpreter.asm: 65 * llint/LowLevelInterpreter64.asm: 66 * runtime/StructureIDTable.cpp: 67 (JSC::StructureIDTable::StructureIDTable): 68 (JSC::StructureIDTable::makeFreeListFromRange): 69 (JSC::StructureIDTable::resize): 70 (JSC::StructureIDTable::allocateID): 71 (JSC::StructureIDTable::deallocateID): 72 * runtime/StructureIDTable.h: 73 (JSC::StructureIDTable::decode): 74 (JSC::StructureIDTable::encode): 75 (JSC::StructureIDTable::get): 76 (JSC::StructureIDTable::isValid): 77 1 78 2019-02-26 Ryan Haddad <ryanhaddad@apple.com> 2 79 -
trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp
r242087 r242096 16945 16945 LValue loadStructure(LValue value) 16946 16946 { 16947 LValue tableIndex = m_out.load32(value, m_heaps.JSCell_structureID); 16948 LValue tableBase = m_out.loadPtr( 16949 m_out.absolute(vm().heap.structureIDTable().base())); 16950 TypedPointer address = m_out.baseIndex( 16951 m_heaps.structureTable, tableBase, m_out.zeroExtPtr(tableIndex)); 16952 return m_out.loadPtr(address); 16947 LValue structureID = m_out.load32(value, m_heaps.JSCell_structureID); 16948 LValue tableBase = m_out.loadPtr(m_out.absolute(vm().heap.structureIDTable().base())); 16949 LValue tableIndex = m_out.aShr(structureID, m_out.constInt32(StructureIDTable::s_numberOfEntropyBits)); 16950 LValue entropyBits = m_out.shl(m_out.zeroExtPtr(structureID), m_out.constInt32(StructureIDTable::s_entropyBitsShiftForStructurePointer)); 16951 TypedPointer address = m_out.baseIndex(m_heaps.structureTable, tableBase, m_out.zeroExtPtr(tableIndex)); 16952 LValue encodedStructureBits = m_out.loadPtr(address); 16953 return m_out.bitXor(encodedStructureBits, entropyBits); 16953 16954 } 16954 16955 -
trunk/Source/JavaScriptCore/heap/SlotVisitor.cpp
r242087 r242096 1 1 /* 2 * Copyright (C) 2012-201 8Apple Inc. All rights reserved.2 * Copyright (C) 2012-2019 Apple Inc. All rights reserved. 3 3 * 4 4 * Redistribution and use in source and binary forms, with or without … … 199 199 #if USE(JSVALUE64) 200 200 // This detects the worst of the badness. 201 if ( structureID >= heap()->structureIDTable().size())202 die("GC scan found corrupt object: structureID is out of bounds!\n");201 if (!heap()->structureIDTable().isValid(structureID)) 202 die("GC scan found corrupt object: structureID is invalid!\n"); 203 203 #endif 204 204 }; -
trunk/Source/JavaScriptCore/jit/AssemblyHelpers.cpp
r242087 r242096 1 1 /* 2 * Copyright (C) 2011-201 8Apple Inc. All rights reserved.2 * Copyright (C) 2011-2019 Apple Inc. All rights reserved. 3 3 * 4 4 * Redistribution and use in source and binary forms, with or without … … 370 370 { 371 371 #if USE(JSVALUE64) 372 #if CPU(ARM64) 373 RegisterID scratch2 = dataTempRegister; 374 #elif CPU(X86_64) 375 RegisterID scratch2 = scratchRegister(); 376 #else 377 #error "Unsupported cpu" 378 #endif 379 372 380 ASSERT(dest != scratch); 373 load32(MacroAssembler::Address(source, JSCell::structureIDOffset()), dest); 381 ASSERT(dest != scratch2); 382 ASSERT(scratch != scratch2); 383 384 load32(MacroAssembler::Address(source, JSCell::structureIDOffset()), scratch2); 374 385 loadPtr(vm.heap.structureIDTable().base(), scratch); 386 rshift32(scratch2, TrustedImm32(StructureIDTable::s_numberOfEntropyBits), dest); 375 387 loadPtr(MacroAssembler::BaseIndex(scratch, dest, MacroAssembler::TimesEight), dest); 376 #else 388 lshiftPtr(TrustedImm32(StructureIDTable::s_entropyBitsShiftForStructurePointer), scratch2); 389 xorPtr(scratch2, dest); 390 #else // not USE(JSVALUE64) 377 391 UNUSED_PARAM(scratch); 392 UNUSED_PARAM(scratch2); 378 393 UNUSED_PARAM(vm); 379 394 loadPtr(MacroAssembler::Address(source, JSCell::structureIDOffset()), dest); 380 #endif 395 #endif // not USE(JSVALUE64) 381 396 } 382 397 -
trunk/Source/JavaScriptCore/jit/AssemblyHelpers.h
r242087 r242096 1 1 /* 2 * Copyright (C) 2011-201 8Apple Inc. All rights reserved.2 * Copyright (C) 2011-2019 Apple Inc. All rights reserved. 3 3 * 4 4 * Redistribution and use in source and binary forms, with or without … … 1783 1783 } 1784 1784 1785 JumpList branchIfValue(VM&, JSValueRegs value, GPRReg scratch, GPRReg scratchIfShouldCheckMasqueradesAsUndefined, FPRReg, FPRReg, bool shouldCheckMasqueradesAsUndefined, JSGlobalObject*, bool negateResult);1785 JumpList branchIfValue(VM&, JSValueRegs, GPRReg scratch, GPRReg scratchIfShouldCheckMasqueradesAsUndefined, FPRReg, FPRReg, bool shouldCheckMasqueradesAsUndefined, JSGlobalObject*, bool negateResult); 1786 1786 JumpList branchIfTruthy(VM& vm, JSValueRegs value, GPRReg scratch, GPRReg scratchIfShouldCheckMasqueradesAsUndefined, FPRReg scratchFPR0, FPRReg scratchFPR1, bool shouldCheckMasqueradesAsUndefined, JSGlobalObject* globalObject) 1787 1787 { … … 1792 1792 return branchIfValue(vm, value, scratch, scratchIfShouldCheckMasqueradesAsUndefined, scratchFPR0, scratchFPR1, shouldCheckMasqueradesAsUndefined, globalObject, true); 1793 1793 } 1794 void emitConvertValueToBoolean(VM&, JSValueRegs value, GPRReg result, GPRReg scratchIfShouldCheckMasqueradesAsUndefined, FPRReg, FPRReg, bool shouldCheckMasqueradesAsUndefined, JSGlobalObject*, bool negateResult = false);1794 void emitConvertValueToBoolean(VM&, JSValueRegs, GPRReg result, GPRReg scratchIfShouldCheckMasqueradesAsUndefined, FPRReg, FPRReg, bool shouldCheckMasqueradesAsUndefined, JSGlobalObject*, bool negateResult = false); 1795 1795 1796 1796 template<typename ClassType> -
trunk/Source/JavaScriptCore/jit/SpecializedThunkJIT.h
r242087 r242096 1 1 /* 2 * Copyright (C) 2010-201 8Apple Inc. All rights reserved.2 * Copyright (C) 2010-2019 Apple Inc. All rights reserved. 3 3 * 4 4 * Redistribution and use in source and binary forms, with or without … … 72 72 } 73 73 74 void loadArgumentWithSpecificClass(const ClassInfo* classInfo, int argument, RegisterID dst, RegisterID scratch)75 {76 loadCellArgument(argument, dst);77 emitLoadStructure(*vm(), dst, scratch, dst);78 appendFailure(branchPtr(NotEqual, Address(scratch, Structure::classInfoOffset()), TrustedImmPtr(PoisonedClassInfoPtr(classInfo).bits())));79 // We have to reload the argument since emitLoadStructure clobbered it.80 loadCellArgument(argument, dst);81 }82 83 74 void loadInt32Argument(int argument, RegisterID dst, Jump& failTarget) 84 75 { -
trunk/Source/JavaScriptCore/llint/LowLevelInterpreter.asm
r242087 r242096 203 203 const DeletedValueTag = constexpr JSValue::DeletedValueTag 204 204 const LowestTag = constexpr JSValue::LowestTag 205 end 206 207 if JSVALUE64 208 const NumberOfStructureIDEntropyBits = constexpr StructureIDTable::s_numberOfEntropyBits 209 const StructureEntropyBitsShift = constexpr StructureIDTable::s_entropyBitsShiftForStructurePointer 205 210 end 206 211 -
trunk/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm
r242087 r242096 531 531 end 532 532 533 macro structureIDToStructureWithScratch(structureIDThenStructure, scratch )533 macro structureIDToStructureWithScratch(structureIDThenStructure, scratch, scratch2) 534 534 loadp CodeBlock[cfr], scratch 535 move structureIDThenStructure, scratch2 535 536 loadp CodeBlock::m_vm[scratch], scratch 537 rshifti NumberOfStructureIDEntropyBits, scratch2 536 538 loadp VM::heap + Heap::m_structureIDTable + StructureIDTable::m_table[scratch], scratch 537 loadp [scratch, structureIDThenStructure, PtrSize], structureIDThenStructure 538 end 539 540 macro loadStructureWithScratch(cell, structure, scratch) 539 loadp [scratch, scratch2, PtrSize], scratch2 540 lshiftp StructureEntropyBitsShift, structureIDThenStructure 541 xorp scratch2, structureIDThenStructure 542 end 543 544 macro loadStructureWithScratch(cell, structure, scratch, scratch2) 541 545 loadi JSCell::m_structureID[cell], structure 542 structureIDToStructureWithScratch(structure, scratch )546 structureIDToStructureWithScratch(structure, scratch, scratch2) 543 547 end 544 548 … … 695 699 btqnz t0, tagMask, .opToThisSlow 696 700 bbneq JSCell::m_type[t0], FinalObjectType, .opToThisSlow 697 loadStructureWithScratch(t0, t1, t2 )701 loadStructureWithScratch(t0, t1, t2, t3) 698 702 metadata(t2, t3) 699 703 loadp OpToThis::Metadata::m_cachedStructure[t2], t2 … … 765 769 jmp .done 766 770 .masqueradesAsUndefined: 767 loadStructureWithScratch(t0, t2, t1 )771 loadStructureWithScratch(t0, t2, t1, t3) 768 772 loadp CodeBlock[cfr], t0 769 773 loadp CodeBlock::m_globalObject[t0], t0 … … 1183 1187 return(t1) 1184 1188 .masqueradesAsUndefined: 1185 loadStructureWithScratch(t0, t3, t1 )1189 loadStructureWithScratch(t0, t3, t1, t2) 1186 1190 loadp CodeBlock[cfr], t1 1187 1191 loadp CodeBlock::m_globalObject[t1], t1 … … 1354 1358 btpz t3, .opPutByIdTransitionDirect 1355 1359 1356 structureIDToStructureWithScratch(t2, t1 )1360 structureIDToStructureWithScratch(t2, t1, t3) 1357 1361 1358 1362 # reload the StructureChain since we used t3 as a scratch above … … 1692 1696 loadq [cfr, t0, 8], t0 1693 1697 btqnz t0, tagMask, .immediate 1694 loadStructureWithScratch(t0, t2, t1 )1698 loadStructureWithScratch(t0, t2, t1, t3) 1695 1699 cellHandler(t2, JSCell::m_flags[t0], .target) 1696 1700 dispatch() … … 2215 2219 get(m_scope, t0) 2216 2220 loadq [cfr, t0, 8], t0 2217 loadStructureWithScratch(t0, t2, t1 )2221 loadStructureWithScratch(t0, t2, t1, t3) 2218 2222 loadp %opcodeStruct%::Metadata::m_structure[t5], t1 2219 2223 bpneq t2, t1, slowPath -
trunk/Source/JavaScriptCore/runtime/StructureIDTable.cpp
r242087 r242096 36 36 StructureIDTable::StructureIDTable() 37 37 : m_table(makeUniqueArray<StructureOrOffset>(s_initialSize)) 38 , m_size(1) 38 39 , m_capacity(s_initialSize) 39 40 { 40 41 // We pre-allocate the first offset so that the null Structure 41 42 // can still be represented as the StructureID '0'. 42 table()[0]. structure = nullptr;43 table()[0].encodedStructureBits = 0; 43 44 44 45 makeFreeListFromRange(1, m_capacity - 1); 45 ASSERT(m_size == m_capacity);46 46 } 47 47 … … 96 96 m_firstFreeOffset = head; 97 97 m_lastFreeOffset = tail; 98 m_size = m_capacity;99 98 } 100 99 101 100 void StructureIDTable::resize(size_t newCapacity) 102 101 { 102 if (newCapacity > s_maximumNumberOfStructures) 103 newCapacity = s_maximumNumberOfStructures; 104 103 105 // Create the new table. 104 106 auto newTable = makeUniqueArray<StructureOrOffset>(newCapacity); … … 129 131 StructureID StructureIDTable::allocateID(Structure* structure) 130 132 { 131 if (!m_firstFreeOffset) { 132 RELEASE_ASSERT(m_capacity <= UINT_MAX); 133 if (m_size == m_capacity) 134 resize(m_capacity * 2); 133 if (UNLIKELY(!m_firstFreeOffset)) { 134 RELEASE_ASSERT(m_capacity <= s_maximumNumberOfStructures); 135 135 ASSERT(m_size == m_capacity); 136 resize(m_capacity * 2); 137 ASSERT(m_size < m_capacity); 136 138 ASSERT(m_firstFreeOffset); 137 139 } … … 139 141 ASSERT(m_firstFreeOffset != s_unusedID); 140 142 141 StructureID result = m_firstFreeOffset; 143 // entropyBits must not be zero. This ensures that if a corrupted 144 // structureID is encountered (with incorrect entropyBits), the decoded 145 // structure pointer for that ID will be always be a bad pointer with 146 // high bits set. 147 constexpr uint32_t entropyBitsMask = (1 << s_numberOfEntropyBits) - 1; 148 uint32_t entropyBits = m_weakRandom.getUint32() & entropyBitsMask; 149 if (UNLIKELY(!entropyBits)) { 150 constexpr uint32_t numberOfValuesToPickFrom = entropyBitsMask; 151 entropyBits = (m_weakRandom.getUint32() % numberOfValuesToPickFrom) + 1; 152 } 153 154 uint32_t structureIndex = m_firstFreeOffset; 142 155 m_firstFreeOffset = table()[m_firstFreeOffset].offset; 143 156 if (!m_firstFreeOffset) 144 157 m_lastFreeOffset = 0; 145 158 146 table()[result].structure = structure; 159 StructureID result = (structureIndex << s_numberOfEntropyBits) | entropyBits; 160 table()[structureIndex].encodedStructureBits = encode(structure, result); 161 m_size++; 147 162 ASSERT(!isNuked(result)); 148 163 return result; … … 152 167 { 153 168 ASSERT(structureID != s_unusedID); 154 RELEASE_ASSERT(table()[structureID].structure == structure); 155 169 uint32_t structureIndex = structureID >> s_numberOfEntropyBits; 170 ASSERT(structureIndex && structureIndex < s_maximumNumberOfStructures); 171 RELEASE_ASSERT(table()[structureIndex].encodedStructureBits == encode(structure, structureID)); 172 m_size--; 156 173 if (!m_firstFreeOffset) { 157 table()[structureI D].offset = 0;158 m_firstFreeOffset = structureI D;159 m_lastFreeOffset = structureI D;174 table()[structureIndex].offset = 0; 175 m_firstFreeOffset = structureIndex; 176 m_lastFreeOffset = structureIndex; 160 177 return; 161 178 } … … 163 180 bool insertAtHead = m_weakRandom.getUint32() & 1; 164 181 if (insertAtHead) { 165 table()[structureI D].offset = m_firstFreeOffset;166 m_firstFreeOffset = structureI D;182 table()[structureIndex].offset = m_firstFreeOffset; 183 m_firstFreeOffset = structureIndex; 167 184 } else { 168 table()[structureI D].offset = 0;169 table()[m_lastFreeOffset].offset = structureI D;170 m_lastFreeOffset = structureI D;185 table()[structureIndex].offset = 0; 186 table()[m_lastFreeOffset].offset = structureIndex; 187 m_lastFreeOffset = structureIndex; 171 188 } 172 189 } -
trunk/Source/JavaScriptCore/runtime/StructureIDTable.h
r242087 r242096 83 83 #if USE(JSVALUE64) 84 84 85 using EncodedStructureBits = uintptr_t; 86 85 87 class StructureIDTable { 86 88 friend class LLIntOffsetsExtractor; … … 90 92 void** base() { return reinterpret_cast<void**>(&m_table); } 91 93 94 bool isValid(StructureID); 92 95 Structure* get(StructureID); 93 96 void deallocateID(Structure*, StructureID); … … 105 108 WTF_MAKE_FAST_ALLOCATED; 106 109 public: 107 Structure* structure;110 EncodedStructureBits encodedStructureBits; 108 111 StructureID offset; 109 112 }; 110 113 111 114 StructureOrOffset* table() const { return m_table.get(); } 112 115 static Structure* decode(EncodedStructureBits, StructureID); 116 static EncodedStructureBits encode(Structure*, StructureID); 117 113 118 static constexpr size_t s_initialSize = 512; 114 119 … … 124 129 WeakRandom m_weakRandom; 125 130 126 static const StructureID s_unusedID = unusedPointer; 131 static constexpr StructureID s_unusedID = 0; 132 133 public: 134 static constexpr uint32_t s_numberOfNukeBits = 1; 135 static constexpr uint32_t s_numberOfEntropyBits = 7; 136 static constexpr uint32_t s_entropyBitsShiftForStructurePointer = (sizeof(intptr_t) * 8) - s_numberOfEntropyBits; 137 138 static constexpr uint32_t s_maximumNumberOfStructures = 1 << (32 - s_numberOfEntropyBits - s_numberOfNukeBits); 127 139 }; 140 141 ALWAYS_INLINE Structure* StructureIDTable::decode(EncodedStructureBits bits, StructureID structureID) 142 { 143 return reinterpret_cast<Structure*>(bits ^ (static_cast<uintptr_t>(structureID) << s_entropyBitsShiftForStructurePointer)); 144 } 145 146 ALWAYS_INLINE EncodedStructureBits StructureIDTable::encode(Structure* structure, StructureID structureID) 147 { 148 return reinterpret_cast<EncodedStructureBits>(structure) ^ (static_cast<EncodedStructureBits>(structureID) << s_entropyBitsShiftForStructurePointer); 149 } 128 150 129 151 inline Structure* StructureIDTable::get(StructureID structureID) … … 131 153 ASSERT_WITH_SECURITY_IMPLICATION(structureID); 132 154 ASSERT_WITH_SECURITY_IMPLICATION(!isNuked(structureID)); 133 ASSERT_WITH_SECURITY_IMPLICATION(structureID < m_capacity); 134 return table()[structureID].structure; 155 uint32_t structureIndex = structureID >> s_numberOfEntropyBits; 156 ASSERT_WITH_SECURITY_IMPLICATION(structureIndex < m_capacity); 157 return decode(table()[structureIndex].encodedStructureBits, structureID); 158 } 159 160 inline bool StructureIDTable::isValid(StructureID structureID) 161 { 162 if (!structureID) 163 return false; 164 uint32_t structureIndex = structureID >> s_numberOfEntropyBits; 165 if (structureIndex >= m_capacity) 166 return false; 167 #if CPU(ADDRESS64) 168 Structure* structure = decode(table()[structureIndex].encodedStructureBits, structureID); 169 if (reinterpret_cast<uintptr_t>(structure) >> s_entropyBitsShiftForStructurePointer) 170 return false; 171 #endif 172 return true; 135 173 } 136 174
Note: See TracChangeset
for help on using the changeset viewer.