Source/JavaScriptCore/ChangeLog

 12020-02-17 Yusuke Suzuki <ysuzuki@apple.com>
 2
 3 [JSC] Shrink Structure
 4 https://bugs.webkit.org/show_bug.cgi?id=207827
 5
 6 Reviewed by NOBODY (OOPS!).
 7
 8 This patch shrinks sizeof(Structure) from 112 to 96 (16 bytes) in 64 bit architectures.
 9 Structure is one of the most frequently allocated JSCell in JSC. So it is worth doing
 10 all the sort of bit hacks to make it compact as much as possible.
 11
 12 1. StringHasher is always generating 24 bits hashes so far. By leveraging this fact,
 13 we store hash code in Structure in 3 bytes (24 bits) for property-hash and seen-property-hash.
 14 2. Instead of using bloom-filter of pointers for seen-properties, we should use bloom-filter of hash-codes.
 15 3. Used PackedPtr for C++ non-concurrently accessed data structures.
 16 4. Put outOfLineTypeFlags, maxOffset and transitionOffset into highest bits of m_propertyTableUnsafe,
 17 m_cachedPrototypeChain, and m_classInfo. Do not use PackedPtr here since some of them are concurrently accessed
 18 by GC.
 19 5. Put m_inlineCapacity into lower 8 bits of m_propertyHash.
 20 6. Remove m_lock, and use Structure::cellLock() instead.
 21
 22 Combining all of the above techniques and getting 16 bytes.
 23
 24 * dfg/DFGSpeculativeJIT.cpp:
 25 (JSC::DFG::SpeculativeJIT::compileCheckSubClass):
 26 (JSC::DFG::SpeculativeJIT::compileCreateThis):
 27 (JSC::DFG::SpeculativeJIT::compileCreatePromise):
 28 (JSC::DFG::SpeculativeJIT::compileCreateInternalFieldObject):
 29 * ftl/FTLAbstractHeapRepository.h:
 30 * ftl/FTLLowerDFGToB3.cpp:
 31 (JSC::FTL::DFG::LowerDFGToB3::compileCreatePromise):
 32 (JSC::FTL::DFG::LowerDFGToB3::compileCreateInternalFieldObject):
 33 (JSC::FTL::DFG::LowerDFGToB3::compileCheckSubClass):
 34 * jit/JITOpcodes.cpp:
 35 (JSC::JIT::emit_op_create_this):
 36 * jit/JITOpcodes32_64.cpp:
 37 (JSC::JIT::emit_op_create_this):
 38 * runtime/ClonedArguments.cpp:
 39 (JSC::ClonedArguments::createStructure):
 40 * runtime/ConcurrentJSLock.h:
 41 (JSC::ConcurrentJSLockerBase::ConcurrentJSLockerBase):
 42 (JSC::GCSafeConcurrentJSLockerImpl::GCSafeConcurrentJSLockerImpl):
 43 (JSC::GCSafeConcurrentJSLockerImpl::~GCSafeConcurrentJSLockerImpl):
 44 (JSC::ConcurrentJSLockerImpl::ConcurrentJSLockerImpl):
 45 (JSC::GCSafeConcurrentJSLocker::GCSafeConcurrentJSLocker): Deleted.
 46 (JSC::GCSafeConcurrentJSLocker::~GCSafeConcurrentJSLocker): Deleted.
 47 (JSC::ConcurrentJSLocker::ConcurrentJSLocker): Deleted.
 48 * runtime/JSCell.h:
 49 * runtime/JSObject.cpp:
 50 (JSC::JSObject::deleteProperty):
 51 (JSC::JSObject::shiftButterflyAfterFlattening):
 52 * runtime/JSObject.h:
 53 (JSC::JSObject::getDirectConcurrently const):
 54 * runtime/JSObjectInlines.h:
 55 (JSC::JSObject::prepareToPutDirectWithoutTransition):
 56 * runtime/Structure.cpp:
 57 (JSC::StructureTransitionTable::setSingleTransition):
 58 (JSC::Structure::dumpStatistics):
 59 (JSC::Structure::Structure):
 60 (JSC::Structure::create):
 61 (JSC::Structure::findStructuresAndMapForMaterialization):
 62 (JSC::Structure::materializePropertyTable):
 63 (JSC::Structure::addPropertyTransitionToExistingStructureConcurrently):
 64 (JSC::Structure::addNewPropertyTransition):
 65 (JSC::Structure::removeNewPropertyTransition):
 66 (JSC::Structure::changePrototypeTransition):
 67 (JSC::Structure::attributeChangeTransition):
 68 (JSC::Structure::toDictionaryTransition):
 69 (JSC::Structure::takePropertyTableOrCloneIfPinned):
 70 (JSC::Structure::nonPropertyTransitionSlow):
 71 (JSC::Structure::flattenDictionaryStructure):
 72 (JSC::Structure::ensurePropertyReplacementWatchpointSet):
 73 (JSC::Structure::copyPropertyTableForPinning):
 74 (JSC::Structure::add):
 75 (JSC::Structure::remove):
 76 (JSC::Structure::visitChildren):
 77 (JSC::Structure::canCachePropertyNameEnumerator const):
 78 * runtime/Structure.h:
 79 * runtime/StructureInlines.h:
 80 (JSC::Structure::get):
 81 (JSC::Structure::forEachPropertyConcurrently):
 82 (JSC::Structure::cachedPrototypeChain const):
 83 (JSC::Structure::setCachedPrototypeChain):
 84 (JSC::Structure::clearCachedPrototypeChain):
 85 (JSC::Structure::prototypeChain const):
 86 (JSC::Structure::propertyReplacementWatchpointSet):
 87 (JSC::Structure::checkOffsetConsistency const):
 88 (JSC::Structure::add):
 89 (JSC::Structure::remove):
 90 (JSC::Structure::removePropertyWithoutTransition):
 91 (JSC::Structure::setPropertyTable):
 92 (JSC::Structure::clearPropertyTable):
 93 (JSC::Structure::setOutOfLineTypeFlags):
 94 (JSC::Structure::setClassInfo):
 95 * runtime/StructureTransitionTable.h:
 96 (JSC::toAttributes):
 97 (JSC::StructureTransitionTable::StructureTransitionTable):
 98 (JSC::StructureTransitionTable::isUsingSingleSlot const):
 99 (JSC::StructureTransitionTable::map const):
 100 (JSC::StructureTransitionTable::weakImpl const):
 101 (JSC::StructureTransitionTable::setMap):
 102 * runtime/WriteBarrier.h:
 103 * wasm/js/WebAssemblyFunction.cpp:
 104 (JSC::WebAssemblyFunction::jsCallEntrypointSlow):
 105
11062020-02-17 Per Arne Vollan <pvollan@apple.com>
2107
3108 Mach lookup to com.apple.webinspector should not be allowed in WebKit's WebContent process

Source/WTF/ChangeLog

 12020-02-17 Yusuke Suzuki <ysuzuki@apple.com>
 2
 3 [JSC] Shrink Structure
 4 https://bugs.webkit.org/show_bug.cgi?id=207827
 5
 6 Reviewed by NOBODY (OOPS!).
 7
 8 * wtf/text/StringImpl.h:
 9 * wtf/text/SymbolImpl.h:
 10 (WTF::SymbolImpl::hashForSymbol const):
 11
1122020-02-17 Víctor Manuel Jáquez Leal <vjaquez@igalia.com>
213
314 a lot gcc warnings because of %{public}s format specifier

Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp

@@void SpeculativeJIT::compileCheckSubClass(Node* node)
96059605 GPRReg specifiedGPR = specified.gpr();
96069606
96079607 m_jit.emitLoadStructure(vm(), baseGPR, otherGPR, specifiedGPR);
9608  m_jit.loadPtr(CCallHelpers::Address(otherGPR, Structure::classInfoOffset()), otherGPR);
 9608#if CPU(ADDRESS64)
 9609 m_jit.loadPtr(CCallHelpers::Address(otherGPR, Structure::offsetOfTransitionOffsetAndClassInfo()), otherGPR);
 9610 m_jit.andPtr(CCallHelpers::TrustedImmPtr(bitwise_cast<void*>(Structure::classInfoMask)), otherGPR);
 9611#else
 9612 m_jit.loadPtr(CCallHelpers::Address(otherGPR, Structure::offsetOfClassInfo()), otherGPR);
 9613#endif
96099614 m_jit.move(CCallHelpers::TrustedImmPtr(node->classInfo()), specifiedGPR);
96109615
96119616 CCallHelpers::Label loop = m_jit.label();

@@void SpeculativeJIT::compileCreateThis(Node* node)
1283912844 auto butterfly = TrustedImmPtr(nullptr);
1284012845 emitAllocateJSObject(resultGPR, JITAllocator::variable(), allocatorGPR, structureGPR, butterfly, scratchGPR, slowPath);
1284112846
12842  m_jit.load8(JITCompiler::Address(structureGPR, Structure::inlineCapacityOffset()), inlineCapacityGPR);
 12847 m_jit.load8(JITCompiler::Address(structureGPR, Structure::offsetOfInlineCapacity()), inlineCapacityGPR);
1284312848 m_jit.emitInitializeInlineStorage(resultGPR, inlineCapacityGPR);
1284412849 m_jit.mutatorFence(vm());
1284512850

@@void SpeculativeJIT::compileCreatePromise(Node* node)
1287712882 slowCases.append(m_jit.branchTestPtr(MacroAssembler::Zero, rareDataGPR, CCallHelpers::TrustedImm32(JSFunction::rareDataTag)));
1287812883 m_jit.loadPtr(JITCompiler::Address(rareDataGPR, FunctionRareData::offsetOfInternalFunctionAllocationProfile() + InternalFunctionAllocationProfile::offsetOfStructure() - JSFunction::rareDataTag), structureGPR);
1287912884 slowCases.append(m_jit.branchTestPtr(CCallHelpers::Zero, structureGPR));
12880  m_jit.move(TrustedImmPtr(node->isInternalPromise() ? JSInternalPromise::info() : JSPromise::info()), scratch1GPR);
12881  slowCases.append(m_jit.branchPtr(CCallHelpers::NotEqual, scratch1GPR, CCallHelpers::Address(structureGPR, Structure::classInfoOffset())));
 12885#if CPU(ADDRESS64)
 12886 m_jit.loadPtr(CCallHelpers::Address(structureGPR, Structure::offsetOfTransitionOffsetAndClassInfo()), scratch1GPR);
 12887 m_jit.andPtr(CCallHelpers::TrustedImmPtr(bitwise_cast<void*>(Structure::classInfoMask)), scratch1GPR);
 12888#else
 12889 m_jit.loadPtr(CCallHelpers::Address(structureGPR, Structure::offsetOfClassInfo()), scratch1GPR);
 12890#endif
 12891 slowCases.append(m_jit.branchPtr(CCallHelpers::NotEqual, scratch1GPR, TrustedImmPtr(node->isInternalPromise() ? JSInternalPromise::info() : JSPromise::info())));
1288212892 m_jit.move(TrustedImmPtr::weakPointer(m_jit.graph(), globalObject), scratch1GPR);
1288312893 slowCases.append(m_jit.branchPtr(CCallHelpers::NotEqual, scratch1GPR, CCallHelpers::Address(structureGPR, Structure::globalObjectOffset())));
1288412894

@@void SpeculativeJIT::compileCreateInternalFieldObject(Node* node, Operation oper
1292512935 slowCases.append(m_jit.branchTestPtr(MacroAssembler::Zero, rareDataGPR, CCallHelpers::TrustedImm32(JSFunction::rareDataTag)));
1292612936 m_jit.loadPtr(JITCompiler::Address(rareDataGPR, FunctionRareData::offsetOfInternalFunctionAllocationProfile() + InternalFunctionAllocationProfile::offsetOfStructure() - JSFunction::rareDataTag), structureGPR);
1292712937 slowCases.append(m_jit.branchTestPtr(CCallHelpers::Zero, structureGPR));
12928  m_jit.move(TrustedImmPtr(JSClass::info()), scratch1GPR);
12929  slowCases.append(m_jit.branchPtr(CCallHelpers::NotEqual, scratch1GPR, CCallHelpers::Address(structureGPR, Structure::classInfoOffset())));
 12938#if CPU(ADDRESS64)
 12939 m_jit.loadPtr(CCallHelpers::Address(structureGPR, Structure::offsetOfTransitionOffsetAndClassInfo()), scratch1GPR);
 12940 m_jit.andPtr(CCallHelpers::TrustedImmPtr(bitwise_cast<void*>(Structure::classInfoMask)), scratch1GPR);
 12941#else
 12942 m_jit.loadPtr(CCallHelpers::Address(structureGPR, Structure::offsetOfClassInfo()), scratch1GPR);
 12943#endif
 12944 slowCases.append(m_jit.branchPtr(CCallHelpers::NotEqual, scratch1GPR, TrustedImmPtr(JSClass::info())));
1293012945 m_jit.move(TrustedImmPtr::weakPointer(m_jit.graph(), globalObject), scratch1GPR);
1293112946 slowCases.append(m_jit.branchPtr(CCallHelpers::NotEqual, scratch1GPR, CCallHelpers::Address(structureGPR, Structure::globalObjectOffset())));
1293212947

Source/JavaScriptCore/ftl/FTLAbstractHeapRepository.h

@@namespace JSC { namespace FTL {
139139 macro(StringImpl_data, StringImpl::dataOffset()) \
140140 macro(StringImpl_hashAndFlags, StringImpl::flagsOffset()) \
141141 macro(StringImpl_length, StringImpl::lengthMemoryOffset()) \
142  macro(Structure_classInfo, Structure::classInfoOffset()) \
 142 macro(Structure_transitionOffsetAndClassInfo, Structure::offsetOfTransitionOffsetAndClassInfo()) \
143143 macro(Structure_globalObject, Structure::globalObjectOffset()) \
144144 macro(Structure_indexingModeIncludingHistory, Structure::indexingModeIncludingHistoryOffset()) \
145  macro(Structure_inlineCapacity, Structure::inlineCapacityOffset()) \
 145 macro(Structure_inlineCapacity, Structure::offsetOfInlineCapacity()) \
146146 macro(Structure_previousOrRareData, Structure::previousOrRareDataOffset()) \
147147 macro(Structure_prototype, Structure::prototypeOffset()) \
148148 macro(Structure_structureID, Structure::structureIDOffset()) \

Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp

@@class LowerDFGToB3 {
66756675 m_out.branch(m_out.isZero64(structure), rarely(slowCase), usually(hasStructure));
66766676
66776677 m_out.appendTo(hasStructure, checkGlobalObjectCase);
6678  m_out.branch(m_out.equal(m_out.loadPtr(structure, m_heaps.Structure_classInfo), m_out.constIntPtr(m_node->isInternalPromise() ? JSInternalPromise::info() : JSPromise::info())), usually(checkGlobalObjectCase), rarely(slowCase));
 6678 LValue classInfo = m_out.bitAnd(m_out.loadPtr(structure, m_heaps.Structure_transitionOffsetAndClassInfo), m_out.constIntPtr(Structure::classInfoMask));
 6679 m_out.branch(m_out.equal(classInfo, m_out.constIntPtr(m_node->isInternalPromise() ? JSInternalPromise::info() : JSPromise::info())), usually(checkGlobalObjectCase), rarely(slowCase));
66796680
66806681 m_out.appendTo(checkGlobalObjectCase, fastAllocationCase);
66816682 ValueFromBlock derivedStructure = m_out.anchor(structure);

@@class LowerDFGToB3 {
67306731 m_out.branch(m_out.isZero64(structure), rarely(slowCase), usually(hasStructure));
67316732
67326733 m_out.appendTo(hasStructure, checkGlobalObjectCase);
6733  m_out.branch(m_out.equal(m_out.loadPtr(structure, m_heaps.Structure_classInfo), m_out.constIntPtr(JSClass::info())), usually(checkGlobalObjectCase), rarely(slowCase));
 6734 LValue classInfo = m_out.bitAnd(m_out.loadPtr(structure, m_heaps.Structure_transitionOffsetAndClassInfo), m_out.constIntPtr(Structure::classInfoMask));
 6735 m_out.branch(m_out.equal(classInfo, m_out.constIntPtr(JSClass::info())), usually(checkGlobalObjectCase), rarely(slowCase));
67346736
67356737 m_out.appendTo(checkGlobalObjectCase, fastAllocationCase);
67366738 m_out.branch(m_out.equal(m_out.loadPtr(structure, m_heaps.Structure_globalObject), weakPointer(globalObject)), usually(fastAllocationCase), rarely(slowCase));

@@class LowerDFGToB3 {
1320813210 LBasicBlock continuation = m_out.newBlock();
1320913211
1321013212 LValue structure = loadStructure(cell);
13211  LValue classInfo = m_out.loadPtr(structure, m_heaps.Structure_classInfo);
 13213 LValue classInfo = m_out.bitAnd(m_out.loadPtr(structure, m_heaps.Structure_transitionOffsetAndClassInfo), m_out.constIntPtr(Structure::classInfoMask));
1321213214 ValueFromBlock otherAtStart = m_out.anchor(classInfo);
1321313215 m_out.jump(loop);
1321413216

Source/JavaScriptCore/jit/JITOpcodes.cpp

@@void JIT::emit_op_create_this(const Instruction* currentInstruction)
979979 JumpList slowCases;
980980 auto butterfly = TrustedImmPtr(nullptr);
981981 emitAllocateJSObject(resultReg, JITAllocator::variable(), allocatorReg, structureReg, butterfly, scratchReg, slowCases);
982  load8(Address(structureReg, Structure::inlineCapacityOffset()), scratchReg);
 982 load8(Address(structureReg, Structure::offsetOfInlineCapacity()), scratchReg);
983983 emitInitializeInlineStorage(resultReg, scratchReg);
984984 addSlowCase(slowCases);
985985 emitPutVirtualRegister(bytecode.m_dst);

Source/JavaScriptCore/jit/JITOpcodes32_64.cpp

@@void JIT::emit_op_create_this(const Instruction* currentInstruction)
10931093 JumpList slowCases;
10941094 auto butterfly = TrustedImmPtr(nullptr);
10951095 emitAllocateJSObject(resultReg, JITAllocator::variable(), allocatorReg, structureReg, butterfly, scratchReg, slowCases);
1096  load8(Address(structureReg, Structure::inlineCapacityOffset()), scratchReg);
 1096 load8(Address(structureReg, Structure::offsetOfInlineCapacity()), scratchReg);
10971097 emitInitializeInlineStorage(resultReg, scratchReg);
10981098 addSlowCase(slowCases);
10991099 emitStoreCell(bytecode.m_dst, resultReg);

Source/JavaScriptCore/runtime/ClonedArguments.cpp

@@Structure* ClonedArguments::createStructure(VM& vm, JSGlobalObject* globalObject
153153 Structure* structure = Structure::create(vm, globalObject, prototype, TypeInfo(ClonedArgumentsType, StructureFlags), info(), indexingType);
154154 structure->addPropertyWithoutTransition(
155155 vm, vm.propertyNames->length, static_cast<unsigned>(PropertyAttribute::DontEnum),
156  [&] (const GCSafeConcurrentJSLocker&, PropertyOffset offset, PropertyOffset newMaxOffset) {
 156 [&] (const GCSafeConcurrentJSCellLocker&, PropertyOffset offset, PropertyOffset newMaxOffset) {
157157 RELEASE_ASSERT(offset == clonedArgumentsLengthPropertyOffset);
158158 structure->setMaxOffset(vm, newMaxOffset);
159159 });

Source/JavaScriptCore/runtime/ConcurrentJSLock.h

3333namespace JSC {
3434
3535using ConcurrentJSLock = Lock;
36 using ConcurrentJSLockerImpl = LockHolder;
3736
3837static_assert(sizeof(ConcurrentJSLock) == 1, "Regardless of status of concurrent JS flag, size of ConurrentJSLock is always one byte.");
3938
 39template<typename Lock>
4040class ConcurrentJSLockerBase : public AbstractLocker {
4141 WTF_MAKE_NONCOPYABLE(ConcurrentJSLockerBase);
4242public:
43  explicit ConcurrentJSLockerBase(ConcurrentJSLock& lockable)
 43 explicit ConcurrentJSLockerBase(Lock& lockable)
4444 : m_locker(&lockable)
4545 {
4646 }
47  explicit ConcurrentJSLockerBase(ConcurrentJSLock* lockable)
 47 explicit ConcurrentJSLockerBase(Lock* lockable)
4848 : m_locker(lockable)
4949 {
5050 }

@@class ConcurrentJSLockerBase : public AbstractLocker {
6464 }
6565
6666private:
67  ConcurrentJSLockerImpl m_locker;
 67 Locker<Lock> m_locker;
6868};
6969
70 class GCSafeConcurrentJSLocker : public ConcurrentJSLockerBase {
 70template<typename Lock>
 71class GCSafeConcurrentJSLockerImpl : public ConcurrentJSLockerBase<Lock> {
7172public:
72  GCSafeConcurrentJSLocker(ConcurrentJSLock& lockable, Heap& heap)
73  : ConcurrentJSLockerBase(lockable)
 73 GCSafeConcurrentJSLockerImpl(Lock& lockable, Heap& heap)
 74 : ConcurrentJSLockerBase<Lock>(lockable)
7475 , m_deferGC(heap)
7576 {
7677 }
7778
78  GCSafeConcurrentJSLocker(ConcurrentJSLock* lockable, Heap& heap)
79  : ConcurrentJSLockerBase(lockable)
 79 GCSafeConcurrentJSLockerImpl(Lock* lockable, Heap& heap)
 80 : ConcurrentJSLockerBase<Lock>(lockable)
8081 , m_deferGC(heap)
8182 {
8283 }
8384
84  ~GCSafeConcurrentJSLocker()
 85 ~GCSafeConcurrentJSLockerImpl()
8586 {
8687 // We have to unlock early due to the destruction order of base
8788 // vs. derived classes. If we didn't, then we would destroy the
8889 // DeferGC object before unlocking the lock which could cause a GC
8990 // and resulting deadlock.
90  unlockEarly();
 91 ConcurrentJSLockerBase<Lock>::unlockEarly();
9192 }
9293
9394private:
9495 DeferGC m_deferGC;
9596};
9697
97 class ConcurrentJSLocker : public ConcurrentJSLockerBase {
 98template<typename Lock>
 99class ConcurrentJSLockerImpl : public ConcurrentJSLockerBase<Lock> {
98100public:
99  ConcurrentJSLocker(ConcurrentJSLock& lockable)
100  : ConcurrentJSLockerBase(lockable)
 101 ConcurrentJSLockerImpl(Lock& lockable)
 102 : ConcurrentJSLockerBase<Lock>(lockable)
101103#if !defined(NDEBUG)
102104 , m_disallowGC(std::in_place)
103105#endif
104106 {
105107 }
106108
107  ConcurrentJSLocker(ConcurrentJSLock* lockable)
108  : ConcurrentJSLockerBase(lockable)
 109 ConcurrentJSLockerImpl(Lock* lockable)
 110 : ConcurrentJSLockerBase<Lock>(lockable)
109111#if !defined(NDEBUG)
110112 , m_disallowGC(std::in_place)
111113#endif
112114 {
113115 }
114116
115  ConcurrentJSLocker(NoLockingNecessaryTag)
116  : ConcurrentJSLockerBase(NoLockingNecessary)
 117 ConcurrentJSLockerImpl(NoLockingNecessaryTag)
 118 : ConcurrentJSLockerBase<Lock>(NoLockingNecessary)
117119#if !defined(NDEBUG)
118120 , m_disallowGC(WTF::nullopt)
119121#endif
120122 {
121123 }
122124
123  ConcurrentJSLocker(int) = delete;
 125 ConcurrentJSLockerImpl(int) = delete;
124126
125127#if !defined(NDEBUG)
126128private:

@@class ConcurrentJSLocker : public ConcurrentJSLockerBase {
128130#endif
129131};
130132
 133using ConcurrentJSLocker = ConcurrentJSLockerImpl<ConcurrentJSLock>;
 134using GCSafeConcurrentJSLocker = GCSafeConcurrentJSLockerImpl<ConcurrentJSLock>;
 135
131136} // namespace JSC

Source/JavaScriptCore/runtime/JSCell.h

2424
2525#include "CallData.h"
2626#include "CellState.h"
 27#include "ConcurrentJSLock.h"
2728#include "ConstructData.h"
2829#include "EnumerationMode.h"
2930#include "Heap.h"

@@class JSCellLock : public JSCell {
288289 JS_EXPORT_PRIVATE void unlockSlow();
289290};
290291
 292using ConcurrentJSCellLocker = ConcurrentJSLockerImpl<JSCellLock>;
 293using GCSafeConcurrentJSCellLocker = GCSafeConcurrentJSLockerImpl<JSCellLock>;
 294
291295// FIXME: Refer to Subspace by reference.
292296// https://bugs.webkit.org/show_bug.cgi?id=166988
293297template<typename Type>

Source/JavaScriptCore/runtime/JSObject.cpp

@@bool JSObject::deleteProperty(JSCell* cell, JSGlobalObject* globalObject, Proper
20052005
20062006 PropertyOffset offset = invalidOffset;
20072007 if (structure->isUncacheableDictionary())
2008  offset = structure->removePropertyWithoutTransition(vm, propertyName, [] (const GCSafeConcurrentJSLocker&, PropertyOffset, PropertyOffset) { });
 2008 offset = structure->removePropertyWithoutTransition(vm, propertyName, [](const GCSafeConcurrentJSCellLocker&, PropertyOffset, PropertyOffset) { });
20092009 else {
20102010 structure = Structure::removePropertyTransition(vm, structure, propertyName, offset, &deferredWatchpointFire);
20112011 if (thisObject->m_butterfly && !structure->outOfLineCapacity() && !structure->hasIndexingHeader(thisObject)) {

@@void JSObject::convertToDictionary(VM& vm)
37663766 vm, Structure::toCacheableDictionaryTransition(vm, structure(vm), &deferredWatchpointFire));
37673767}
37683768
3769 void JSObject::shiftButterflyAfterFlattening(const GCSafeConcurrentJSLocker&, VM& vm, Structure* structure, size_t outOfLineCapacityAfter)
 3769void JSObject::shiftButterflyAfterFlattening(const GCSafeConcurrentJSCellLocker&, VM& vm, Structure* structure, size_t outOfLineCapacityAfter)
37703770{
37713771 // This could interleave visitChildren because some old structure could have been a non
37723772 // dictionary structure. We have to be crazy careful. But, we are guaranteed to be holding

Source/JavaScriptCore/runtime/JSObject.h

@@class JSObject : public JSCell {
815815 {
816816 structure(vm)->flattenDictionaryStructure(vm, this);
817817 }
818  void shiftButterflyAfterFlattening(const GCSafeConcurrentJSLocker&, VM&, Structure* structure, size_t outOfLineCapacityAfter);
 818 void shiftButterflyAfterFlattening(const GCSafeConcurrentJSCellLocker&, VM&, Structure*, size_t outOfLineCapacityAfter);
819819
820820 JSGlobalObject* globalObject() const
821821 {

@@inline JSValue JSObject::getPrototype(VM& vm, JSGlobalObject* globalObject)
13291329// flatten an object.
13301330inline JSValue JSObject::getDirectConcurrently(Structure* structure, PropertyOffset offset) const
13311331{
1332  ConcurrentJSLocker locker(structure->lock());
 1332 ConcurrentJSCellLocker locker(structure->cellLock());
13331333 if (!structure->isValidOffset(offset))
13341334 return { };
13351335 return getDirect(offset);

Source/JavaScriptCore/runtime/JSObjectInlines.h

@@ALWAYS_INLINE PropertyOffset JSObject::prepareToPutDirectWithoutTransition(VM& v
216216 PropertyOffset result;
217217 structure->addPropertyWithoutTransition(
218218 vm, propertyName, attributes,
219  [&] (const GCSafeConcurrentJSLocker&, PropertyOffset offset, PropertyOffset newMaxOffset) {
 219 [&] (const GCSafeConcurrentJSCellLocker&, PropertyOffset offset, PropertyOffset newMaxOffset) {
220220 unsigned newOutOfLineCapacity = Structure::outOfLineCapacity(newMaxOffset);
221221 if (newOutOfLineCapacity != oldOutOfLineCapacity) {
222222 Butterfly* butterfly = allocateMoreOutOfLineStorage(vm, oldOutOfLineCapacity, newOutOfLineCapacity);

Source/JavaScriptCore/runtime/Structure.cpp

@@class SingleSlotTransitionWeakOwner final : public WeakHandleOwner {
5858 StructureTransitionTable* table = reinterpret_cast<StructureTransitionTable*>(context);
5959 ASSERT(table->isUsingSingleSlot());
6060 WeakSet::deallocate(table->weakImpl());
61  table->m_data = StructureTransitionTable::UsingSingleSlotFlag;
 61 table->m_data = bitwise_cast<uint8_t*>(StructureTransitionTable::UsingSingleSlotFlag);
6262 }
6363};
6464

@@inline void StructureTransitionTable::setSingleTransition(Structure* structure)
8484 if (WeakImpl* impl = this->weakImpl())
8585 WeakSet::deallocate(impl);
8686 WeakImpl* impl = WeakSet::allocate(structure, &singleSlotTransitionWeakOwner(), this);
87  m_data = bitwise_cast<intptr_t>(impl) | UsingSingleSlotFlag;
 87 m_data = bitwise_cast<uint8_t*>(bitwise_cast<intptr_t>(impl) | UsingSingleSlotFlag);
8888}
8989
9090bool StructureTransitionTable::contains(UniquedStringImpl* rep, unsigned attributes, bool isAddition) const

@@void Structure::dumpStatistics()
151151 break;
152152 }
153153
154  if (PropertyTable* table = structure->propertyTableOrNull()) {
 154 if (PropertyTable* table = structure->propertyTableUnsafeOrNull()) {
155155 ++numberWithPropertyMaps;
156156 totalPropertyMapsSize += table->sizeInMemory();
157157 }

@@void Structure::dumpStatistics()
174174Structure::Structure(VM& vm, JSGlobalObject* globalObject, JSValue prototype, const TypeInfo& typeInfo, const ClassInfo* classInfo, IndexingType indexingType, unsigned inlineCapacity)
175175 : JSCell(vm, vm.structureStructure.get())
176176 , m_blob(vm.heap.structureIDTable().allocateID(this), indexingType, typeInfo)
177  , m_outOfLineTypeFlags(typeInfo.outOfLineTypeFlags())
178  , m_inlineCapacity(inlineCapacity)
179  , m_bitField(0)
180177 , m_globalObject(vm, this, globalObject, WriteBarrier<JSGlobalObject>::MayBeNull)
181178 , m_prototype(vm, this, prototype)
182  , m_classInfo(classInfo)
183179 , m_transitionWatchpointSet(IsWatched)
184  , m_propertyHash(0)
 180 , m_propertyHashAndInlineCapacity(inlineCapacity)
185181{
 182 setClassInfo(classInfo);
186183 setDictionaryKind(NoneDictionaryKind);
187184 setIsPinnedPropertyTable(false);
188185 setHasGetterSetterProperties(classInfo->hasStaticSetterOrReadonlyProperties());

@@Structure::Structure(VM& vm, JSGlobalObject* globalObject, JSValue prototype, co
200197 setIsPropertyDeletionTransition(false);
201198 setTransitionOffset(vm, invalidOffset);
202199 setMaxOffset(vm, invalidOffset);
203 
 200 setOutOfLineTypeFlags(typeInfo.outOfLineTypeFlags());
 201
204202 ASSERT(inlineCapacity <= JSFinalObject::maxInlineCapacity());
205203 ASSERT(static_cast<PropertyOffset>(inlineCapacity) < firstOutOfLineOffset);
206204 ASSERT(!hasRareData());
207  ASSERT(hasReadOnlyOrGetterSetterPropertiesExcludingProto() || !m_classInfo->hasStaticSetterOrReadonlyProperties());
208  ASSERT(hasGetterSetterProperties() || !m_classInfo->hasStaticSetterOrReadonlyProperties());
209  ASSERT(!this->typeInfo().overridesGetCallData() || m_classInfo->methodTable.getCallData != &JSCell::getCallData);
 205 ASSERT(hasReadOnlyOrGetterSetterPropertiesExcludingProto() || !this->classInfo()->hasStaticSetterOrReadonlyProperties());
 206 ASSERT(hasGetterSetterProperties() || !this->classInfo()->hasStaticSetterOrReadonlyProperties());
 207 ASSERT(!this->typeInfo().overridesGetCallData() || this->classInfo()->methodTable.getCallData != &JSCell::getCallData);
210208}
211209
212210const ClassInfo Structure::s_info = { "Structure", nullptr, nullptr, nullptr, CREATE_METHOD_TABLE(Structure) };
213211
214212Structure::Structure(VM& vm)
215213 : JSCell(CreatingEarlyCell)
216  , m_inlineCapacity(0)
217  , m_bitField(0)
218214 , m_prototype(vm, this, jsNull())
219  , m_classInfo(info())
220215 , m_transitionWatchpointSet(IsWatched)
221  , m_propertyHash(0)
 216 , m_propertyHashAndInlineCapacity(0)
222217{
 218 setClassInfo(info());
223219 setDictionaryKind(NoneDictionaryKind);
224220 setIsPinnedPropertyTable(false);
225  setHasGetterSetterProperties(m_classInfo->hasStaticSetterOrReadonlyProperties());
 221 setHasGetterSetterProperties(classInfo()->hasStaticSetterOrReadonlyProperties());
226222 setHasCustomGetterSetterProperties(false);
227  setHasReadOnlyOrGetterSetterPropertiesExcludingProto(m_classInfo->hasStaticSetterOrReadonlyProperties());
 223 setHasReadOnlyOrGetterSetterPropertiesExcludingProto(classInfo()->hasStaticSetterOrReadonlyProperties());
228224 setHasUnderscoreProtoPropertyExcludingOriginalProto(false);
229225 setIsQuickPropertyAccessAllowedForEnumeration(true);
230226 setTransitionPropertyAttributes(0);

@@Structure::Structure(VM& vm)
240236
241237 TypeInfo typeInfo = TypeInfo(CellType, StructureFlags);
242238 m_blob = StructureIDBlob(vm.heap.structureIDTable().allocateID(this), 0, typeInfo);
243  m_outOfLineTypeFlags = typeInfo.outOfLineTypeFlags();
 239 setOutOfLineTypeFlags(typeInfo.outOfLineTypeFlags());
244240
245  ASSERT(hasReadOnlyOrGetterSetterPropertiesExcludingProto() || !m_classInfo->hasStaticSetterOrReadonlyProperties());
246  ASSERT(hasGetterSetterProperties() || !m_classInfo->hasStaticSetterOrReadonlyProperties());
247  ASSERT(!this->typeInfo().overridesGetCallData() || m_classInfo->methodTable.getCallData != &JSCell::getCallData);
 241 ASSERT(hasReadOnlyOrGetterSetterPropertiesExcludingProto() || !classInfo()->hasStaticSetterOrReadonlyProperties());
 242 ASSERT(hasGetterSetterProperties() || !classInfo()->hasStaticSetterOrReadonlyProperties());
 243 ASSERT(!this->typeInfo().overridesGetCallData() || classInfo()->methodTable.getCallData != &JSCell::getCallData);
248244}
249245
250246Structure::Structure(VM& vm, Structure* previous, DeferredStructureTransitionWatchpointFire* deferred)
251247 : JSCell(vm, vm.structureStructure.get())
252  , m_inlineCapacity(previous->m_inlineCapacity)
253  , m_bitField(0)
254248 , m_prototype(vm, this, previous->m_prototype.get())
255  , m_classInfo(previous->m_classInfo)
256249 , m_transitionWatchpointSet(IsWatched)
257  , m_propertyHash(previous->m_propertyHash)
 250 , m_propertyHashAndInlineCapacity(previous->m_propertyHashAndInlineCapacity)
258251 , m_seenProperties(previous->m_seenProperties)
259252{
 253 setClassInfo(previous->classInfo());
260254 setDictionaryKind(previous->dictionaryKind());
261255 setIsPinnedPropertyTable(false);
262256 setHasBeenFlattenedBefore(previous->hasBeenFlattenedBefore());

@@Structure::Structure(VM& vm, Structure* previous, DeferredStructureTransitionWat
277271
278272 TypeInfo typeInfo = previous->typeInfo();
279273 m_blob = StructureIDBlob(vm.heap.structureIDTable().allocateID(this), previous->indexingModeIncludingHistory(), typeInfo);
280  m_outOfLineTypeFlags = typeInfo.outOfLineTypeFlags();
 274 setOutOfLineTypeFlags(typeInfo.outOfLineTypeFlags());
281275
282276 ASSERT(!previous->typeInfo().structureIsImmortal());
283277 setPreviousID(vm, previous);

@@Structure::Structure(VM& vm, Structure* previous, DeferredStructureTransitionWat
289283
290284 if (previous->m_globalObject)
291285 m_globalObject.set(vm, this, previous->m_globalObject.get());
292  ASSERT(hasReadOnlyOrGetterSetterPropertiesExcludingProto() || !m_classInfo->hasStaticSetterOrReadonlyProperties());
293  ASSERT(hasGetterSetterProperties() || !m_classInfo->hasStaticSetterOrReadonlyProperties());
294  ASSERT(!this->typeInfo().overridesGetCallData() || m_classInfo->methodTable.getCallData != &JSCell::getCallData);
 286 ASSERT(hasReadOnlyOrGetterSetterPropertiesExcludingProto() || !classInfo()->hasStaticSetterOrReadonlyProperties());
 287 ASSERT(hasGetterSetterProperties() || !classInfo()->hasStaticSetterOrReadonlyProperties());
 288 ASSERT(!this->typeInfo().overridesGetCallData() || classInfo()->methodTable.getCallData != &JSCell::getCallData);
295289}
296290
297291Structure::~Structure()

@@Structure* Structure::create(PolyProtoTag, VM& vm, JSGlobalObject* globalObject,
313307 unsigned oldOutOfLineCapacity = result->outOfLineCapacity();
314308 result->addPropertyWithoutTransition(
315309 vm, vm.propertyNames->builtinNames().polyProtoName(), static_cast<unsigned>(PropertyAttribute::DontEnum),
316  [&] (const GCSafeConcurrentJSLocker&, PropertyOffset offset, PropertyOffset newMaxOffset) {
 310 [&] (const GCSafeConcurrentJSCellLocker&, PropertyOffset offset, PropertyOffset newMaxOffset) {
317311 RELEASE_ASSERT(Structure::outOfLineCapacity(newMaxOffset) == oldOutOfLineCapacity);
318312 RELEASE_ASSERT(offset == knownPolyProtoOffset);
319313 RELEASE_ASSERT(isInlineOffset(knownPolyProtoOffset));

@@void Structure::findStructuresAndMapForMaterialization(Vector<Structure*, 8>& st
335329 table = 0;
336330
337331 for (structure = this; structure; structure = structure->previousID()) {
338  structure->m_lock.lock();
 332 structure->cellLock().lock();
339333
340  table = structure->propertyTableOrNull();
 334 table = structure->propertyTableUnsafeOrNull();
341335 if (table) {
342336 // Leave the structure locked, so that the caller can do things to it atomically
343337 // before it loses its property table.

@@void Structure::findStructuresAndMapForMaterialization(Vector<Structure*, 8>& st
345339 }
346340
347341 structures.append(structure);
348  structure->m_lock.unlock();
 342 structure->cellLock().unlock();
349343 }
350344
351345 ASSERT(!structure);

@@PropertyTable* Structure::materializePropertyTable(VM& vm, bool setPropertyTable
365359
366360 findStructuresAndMapForMaterialization(structures, structure, table);
367361
368  unsigned capacity = numberOfSlotsForMaxOffset(maxOffset(), m_inlineCapacity);
 362 unsigned capacity = numberOfSlotsForMaxOffset(maxOffset(), inlineCapacity());
369363 if (table) {
370364 table = table->copy(vm, capacity);
371  structure->m_lock.unlock();
 365 structure->cellLock().unlock();
372366 } else
373367 table = PropertyTable::create(vm, capacity);
374368
375369 // Must hold the lock on this structure, since we will be modifying this structure's
376370 // property map. We don't want getConcurrently() to see the property map in a half-baked
377371 // state.
378  GCSafeConcurrentJSLocker locker(m_lock, vm.heap);
 372 GCSafeConcurrentJSCellLocker locker(cellLock(), vm.heap);
379373 if (setPropertyTable)
380374 this->setPropertyTable(vm, table);
381375

@@Structure* Structure::addPropertyTransitionToExistingStructure(Structure* struct
436430
437431Structure* Structure::addPropertyTransitionToExistingStructureConcurrently(Structure* structure, UniquedStringImpl* uid, unsigned attributes, PropertyOffset& offset)
438432{
439  ConcurrentJSLocker locker(structure->m_lock);
 433 ConcurrentJSCellLocker locker(structure->cellLock());
440434 return addPropertyTransitionToExistingStructureImpl(structure, uid, attributes, offset);
441435}
442436

@@Structure* Structure::addNewPropertyTransition(VM& vm, Structure* structure, Pro
497491 }
498492
499493 Structure* transition = create(vm, structure, deferred);
500 
501  transition->m_cachedPrototypeChain.setMayBeNull(vm, transition, structure->m_cachedPrototypeChain.get());
 494 transition->setCachedPrototypeChain(vm, structure->cachedPrototypeChain());
502495
503496 // While we are adding the property, rematerializing the property table is super weird: we already
504497 // have a m_transitionPropertyName and transitionPropertyAttributes but the m_transitionOffset is still wrong. If the

@@Structure* Structure::addNewPropertyTransition(VM& vm, Structure* structure, Pro
510503 // case all is well. If it wasn't for the lock, the GC would have TOCTOU: if could read
511504 // protectPropertyTableWhileTransitioning before we set it to true, and then blow the table away after.
512505 {
513  ConcurrentJSLocker locker(transition->m_lock);
 506 ConcurrentJSCellLocker locker(transition->cellLock());
514507 transition->setProtectPropertyTableWhileTransitioning(true);
515508 }
516509

@@Structure* Structure::addNewPropertyTransition(VM& vm, Structure* structure, Pro
530523
531524 checkOffset(transition->transitionOffset(), transition->inlineCapacity());
532525 {
533  GCSafeConcurrentJSLocker locker(structure->m_lock, vm.heap);
 526 GCSafeConcurrentJSCellLocker locker(structure->cellLock(), vm.heap);
534527 structure->m_transitionTable.add(vm, transition);
535528 }
536529 transition->checkOffsetConsistency();

@@Structure* Structure::removeNewPropertyTransition(VM& vm, Structure* structure,
587580 }
588581
589582 Structure* transition = create(vm, structure, deferred);
590  transition->m_cachedPrototypeChain.setMayBeNull(vm, transition, structure->m_cachedPrototypeChain.get());
 583 transition->setCachedPrototypeChain(vm, structure->cachedPrototypeChain());
591584
592585 // While we are deleting the property, we need to make sure the table is not cleared.
593586 {
594  ConcurrentJSLocker locker(transition->m_lock);
 587 ConcurrentJSCellLocker locker(transition->cellLock());
595588 transition->setProtectPropertyTableWhileTransitioning(true);
596589 }
597590

@@Structure* Structure::removeNewPropertyTransition(VM& vm, Structure* structure,
612605
613606 checkOffset(transition->transitionOffset(), transition->inlineCapacity());
614607 {
615  GCSafeConcurrentJSLocker locker(structure->m_lock, vm.heap);
 608 GCSafeConcurrentJSCellLocker locker(structure->cellLock(), vm.heap);
616609 structure->m_transitionTable.add(vm, transition);
617610 }
618611 transition->checkOffsetConsistency();

@@Structure* Structure::changePrototypeTransition(VM& vm, Structure* structure, JS
630623 transition->m_prototype.set(vm, transition, prototype);
631624
632625 PropertyTable* table = structure->copyPropertyTableForPinning(vm);
633  transition->pin(holdLock(transition->m_lock), vm, table);
 626 transition->pin(holdLock(transition->cellLock()), vm, table);
634627 transition->setMaxOffset(vm, structure->maxOffset());
635628
636629 transition->checkOffsetConsistency();

@@Structure* Structure::attributeChangeTransition(VM& vm, Structure* structure, Pr
643636 Structure* transition = create(vm, structure);
644637
645638 PropertyTable* table = structure->copyPropertyTableForPinning(vm);
646  transition->pin(holdLock(transition->m_lock), vm, table);
 639 transition->pin(holdLock(transition->cellLock()), vm, table);
647640 transition->setMaxOffset(vm, structure->maxOffset());
648641
649642 structure = transition;

@@Structure* Structure::toDictionaryTransition(VM& vm, Structure* structure, Dicti
665658 Structure* transition = create(vm, structure, deferred);
666659
667660 PropertyTable* table = structure->copyPropertyTableForPinning(vm);
668  transition->pin(holdLock(transition->m_lock), vm, table);
 661 transition->pin(holdLock(transition->cellLock()), vm, table);
669662 transition->setMaxOffset(vm, structure->maxOffset());
670663 transition->setDictionaryKind(kind);
671664 transition->setHasBeenDictionary(true);

@@Structure* Structure::preventExtensionsTransition(VM& vm, Structure* structure)
702695PropertyTable* Structure::takePropertyTableOrCloneIfPinned(VM& vm)
703696{
704697 // This must always return a property table. It can't return null.
705  PropertyTable* result = propertyTableOrNull();
 698 PropertyTable* result = propertyTableUnsafeOrNull();
706699 if (result) {
707700 if (isPinnedPropertyTable())
708701 return result->copy(vm, result->size() + 1);
709  ConcurrentJSLocker locker(m_lock);
 702 ConcurrentJSCellLocker locker(cellLock());
710703 setPropertyTable(vm, nullptr);
711704 return result;
712705 }

@@Structure* Structure::nonPropertyTransitionSlow(VM& vm, Structure* structure, No
743736 // table doesn't know how to take into account such wholesale edits.
744737
745738 PropertyTable* table = structure->copyPropertyTableForPinning(vm);
746  transition->pinForCaching(holdLock(transition->m_lock), vm, table);
 739 transition->pinForCaching(holdLock(transition->cellLock()), vm, table);
747740 transition->setMaxOffset(vm, structure->maxOffset());
748741
749  table = transition->propertyTableOrNull();
 742 table = transition->propertyTableUnsafeOrNull();
750743 RELEASE_ASSERT(table);
751744 for (auto& entry : *table) {
752745 if (setsDontDeleteOnAllProperties(transitionKind))

@@Structure* Structure::nonPropertyTransitionSlow(VM& vm, Structure* structure, No
761754 }
762755
763756 if (setsReadOnlyOnNonAccessorProperties(transitionKind)
764  && !transition->propertyTableOrNull()->isEmpty())
 757 && !transition->propertyTableUnsafeOrNull()->isEmpty())
765758 transition->setHasReadOnlyOrGetterSetterPropertiesExcludingProto(true);
766759
767760 if (structure->isDictionary()) {
768761 PropertyTable* table = transition->ensurePropertyTable(vm);
769  transition->pin(holdLock(transition->m_lock), vm, table);
 762 transition->pin(holdLock(transition->cellLock()), vm, table);
770763 } else {
771  auto locker = holdLock(structure->m_lock);
 764 auto locker = holdLock(structure->cellLock());
772765 structure->m_transitionTable.add(vm, transition);
773766 }
774767

@@Structure* Structure::flattenDictionaryStructure(VM& vm, JSObject* object)
820813 ASSERT(isDictionary());
821814 ASSERT(object->structure(vm) == this);
822815
823  GCSafeConcurrentJSLocker locker(m_lock, vm.heap);
 816 GCSafeConcurrentJSCellLocker locker(cellLock(), vm.heap);
824817
825818 object->setStructureIDDirectly(nuke(id()));
826819 WTF::storeStoreFence();
827820
828821 size_t beforeOutOfLineCapacity = this->outOfLineCapacity();
829822 if (isUncacheableDictionary()) {
830  PropertyTable* table = propertyTableOrNull();
 823 PropertyTable* table = propertyTableUnsafeOrNull();
831824 ASSERT(table);
832825
833826 size_t propertyCount = table->size();

@@Structure* Structure::flattenDictionaryStructure(VM& vm, JSObject* object)
841834 auto offset = invalidOffset;
842835 for (PropertyTable::iterator iter = table->begin(); iter != end; ++iter, ++i) {
843836 values[i] = object->getDirect(iter->offset);
844  offset = iter->offset = offsetForPropertyNumber(i, m_inlineCapacity);
 837 offset = iter->offset = offsetForPropertyNumber(i, inlineCapacity());
845838 }
846839 setMaxOffset(vm, offset);
847840 ASSERT(transitionOffset() == invalidOffset);
848841
849842 // Copies in our values to their compacted locations.
850843 for (unsigned i = 0; i < propertyCount; i++)
851  object->putDirect(vm, offsetForPropertyNumber(i, m_inlineCapacity), values[i]);
 844 object->putDirect(vm, offsetForPropertyNumber(i, inlineCapacity()), values[i]);
852845
853846 table->clearDeletedOffsets();
854847

@@WatchpointSet* Structure::ensurePropertyReplacementWatchpointSet(VM& vm, Propert
928921
929922 if (!hasRareData())
930923 allocateRareData(vm);
931  ConcurrentJSLocker locker(m_lock);
 924 ConcurrentJSCellLocker locker(cellLock());
932925 StructureRareData* rareData = this->rareData();
933926 if (!rareData->m_replacementWatchpointSets) {
934927 rareData->m_replacementWatchpointSets =

@@PropertyMapStatisticsExitLogger::~PropertyMapStatisticsExitLogger()
998991
999992PropertyTable* Structure::copyPropertyTableForPinning(VM& vm)
1000993{
1001  if (PropertyTable* table = propertyTableOrNull())
 994 if (PropertyTable* table = propertyTableUnsafeOrNull())
1002995 return PropertyTable::clone(vm, *table);
1003996 bool setPropertyTable = false;
1004997 return materializePropertyTable(vm, setPropertyTable);

@@PropertyOffset Structure::add(VM& vm, PropertyName propertyName, unsigned attrib
10381031{
10391032 return add<ShouldPin::No>(
10401033 vm, propertyName, attributes,
1041  [this, &vm] (const GCSafeConcurrentJSLocker&, PropertyOffset, PropertyOffset newMaxOffset) {
 1034 [this, &vm](const GCSafeConcurrentJSCellLocker&, PropertyOffset, PropertyOffset newMaxOffset) {
10421035 setMaxOffset(vm, newMaxOffset);
10431036 });
10441037}
10451038
10461039PropertyOffset Structure::remove(VM& vm, PropertyName propertyName)
10471040{
1048  return remove<ShouldPin::No>(vm, propertyName, [this, &vm] (const GCSafeConcurrentJSLocker&, PropertyOffset, PropertyOffset newMaxOffset) {
 1041 return remove<ShouldPin::No>(vm, propertyName, [this, &vm](const GCSafeConcurrentJSCellLocker&, PropertyOffset, PropertyOffset newMaxOffset) {
10491042 setMaxOffset(vm, newMaxOffset);
10501043 });
10511044}

@@void Structure::visitChildren(JSCell* cell, SlotVisitor& visitor)
11161109
11171110 Base::visitChildren(thisObject, visitor);
11181111
1119  ConcurrentJSLocker locker(thisObject->m_lock);
 1112 ConcurrentJSCellLocker locker(thisObject->cellLock());
11201113
11211114 visitor.append(thisObject->m_globalObject);
11221115 if (!thisObject->isObject())
1123  thisObject->m_cachedPrototypeChain.clear();
 1116 thisObject->clearCachedPrototypeChain();
11241117 else {
11251118 visitor.append(thisObject->m_prototype);
1126  visitor.append(thisObject->m_cachedPrototypeChain);
 1119 visitor.appendUnbarriered(thisObject->cachedPrototypeChain());
11271120 }
11281121 visitor.append(thisObject->m_previousOrRareData);
11291122
11301123 if (thisObject->isPinnedPropertyTable() || thisObject->protectPropertyTableWhileTransitioning()) {
11311124 // NOTE: This can interleave in pin(), in which case it may see a null property table.
11321125 // That's fine, because then the barrier will fire and we will scan this again.
1133  visitor.append(thisObject->m_propertyTableUnsafe);
 1126 visitor.appendUnbarriered(thisObject->propertyTableUnsafeOrNull());
11341127 } else if (visitor.isAnalyzingHeap())
1135  visitor.append(thisObject->m_propertyTableUnsafe);
1136  else if (thisObject->m_propertyTableUnsafe)
1137  thisObject->m_propertyTableUnsafe.clear();
 1128 visitor.appendUnbarriered(thisObject->propertyTableUnsafeOrNull());
 1129 else if (thisObject->propertyTableUnsafeOrNull())
 1130 thisObject->clearPropertyTable();
11381131}
11391132
11401133bool Structure::isCheapDuringGC(VM& vm)

@@bool Structure::canCachePropertyNameEnumerator(VM& vm) const
12901283 if (!this->canCacheOwnKeys())
12911284 return false;
12921285
1293  StructureChain* structureChain = m_cachedPrototypeChain.get();
 1286 StructureChain* structureChain = cachedPrototypeChain();
12941287 ASSERT(structureChain);
12951288 StructureID* currentStructureID = structureChain->head();
12961289 while (true) {

Source/JavaScriptCore/runtime/Structure.h

@@class Structure final : public JSCell {
258258 {
259259 return typeInfo().getOwnPropertySlotIsImpure();
260260 }
 261
 262 TypeInfo::OutOfLineTypeFlags outOfLineTypeFlags() const
 263 {
 264#if CPU(ADDRESS64)
 265 return static_cast<TypeInfo::OutOfLineTypeFlags>(m_outOfLineTypeFlagsAndPropertyTableUnsafe >> outOfLineTypeFlagsShift);
 266#else
 267 return m_outOfLineTypeFlags;
 268#endif
 269 }
261270
262271 // Type accessors.
263  TypeInfo typeInfo() const { return m_blob.typeInfo(m_outOfLineTypeFlags); }
 272 TypeInfo typeInfo() const { return m_blob.typeInfo(outOfLineTypeFlags()); }
264273 bool isObject() const { return typeInfo().isObject(); }
265274
266275 IndexingType indexingType() const { return m_blob.indexingModeIncludingHistory() & AllWritableArrayTypes; }

@@class Structure final : public JSCell {
359368
360369 PropertyOffset maxOffset() const
361370 {
 371#if CPU(ADDRESS64)
 372 uint16_t maxOffset = m_maxOffsetAndCachedPrototypeChain >> maxOffsetShift;
 373#else
362374 uint16_t maxOffset = m_maxOffset;
 375#endif
363376 if (maxOffset == shortInvalidOffset)
364377 return invalidOffset;
365378 if (maxOffset == useRareDataFlag)

@@class Structure final : public JSCell {
369382
370383 void setMaxOffset(VM& vm, PropertyOffset offset)
371384 {
372  if (offset == invalidOffset)
373  m_maxOffset = shortInvalidOffset;
374  else if (offset < useRareDataFlag && offset < shortInvalidOffset)
375  m_maxOffset = offset;
376  else if (m_maxOffset == useRareDataFlag)
 385 auto commit = [&](uint16_t value) {
 386#if CPU(ADDRESS64)
 387 uintptr_t result = (m_maxOffsetAndCachedPrototypeChain & cachedPrototypeChainMask) | (static_cast<uintptr_t>(value) << maxOffsetShift);
 388 m_maxOffsetAndCachedPrototypeChain = result;
 389#else
 390 m_maxOffset = value;
 391#endif
 392 };
 393
 394 if (offset == invalidOffset) {
 395 commit(shortInvalidOffset);
 396 return;
 397 }
 398 if (offset < useRareDataFlag && offset < shortInvalidOffset) {
 399 commit(offset);
 400 return;
 401 }
 402#if CPU(ADDRESS64)
 403 uint16_t maxOffset = m_maxOffsetAndCachedPrototypeChain >> maxOffsetShift;
 404#else
 405 uint16_t maxOffset = m_maxOffset;
 406#endif
 407 if (maxOffset == useRareDataFlag) {
377408 rareData()->m_maxOffset = offset;
378  else {
379  ensureRareData(vm)->m_maxOffset = offset;
380  WTF::storeStoreFence();
381  m_maxOffset = useRareDataFlag;
 409 return;
382410 }
 411
 412 ensureRareData(vm)->m_maxOffset = offset;
 413 WTF::storeStoreFence();
 414 commit(useRareDataFlag);
383415 }
384416
385417 PropertyOffset transitionOffset() const
386418 {
 419#if CPU(ADDRESS64)
 420 uint16_t transitionOffset = m_transitionOffsetAndClassInfo >> transitionOffsetShift;
 421#else
387422 uint16_t transitionOffset = m_transitionOffset;
 423#endif
388424 if (transitionOffset == shortInvalidOffset)
389425 return invalidOffset;
390426 if (transitionOffset == useRareDataFlag)

@@class Structure final : public JSCell {
394430
395431 void setTransitionOffset(VM& vm, PropertyOffset offset)
396432 {
397  if (offset == invalidOffset)
398  m_transitionOffset = shortInvalidOffset;
399  else if (offset < useRareDataFlag && offset < shortInvalidOffset)
400  m_transitionOffset = offset;
401  else if (m_transitionOffset == useRareDataFlag)
 433 auto commit = [&](uint16_t value) {
 434#if CPU(ADDRESS64)
 435 uintptr_t result = (m_transitionOffsetAndClassInfo & classInfoMask) | (static_cast<uintptr_t>(value) << transitionOffsetShift);
 436 m_transitionOffsetAndClassInfo = result;
 437#else
 438 m_transitionOffset = value;
 439#endif
 440 };
 441
 442 if (offset == invalidOffset) {
 443 commit(shortInvalidOffset);
 444 return;
 445 }
 446 if (offset < useRareDataFlag && offset < shortInvalidOffset) {
 447 commit(offset);
 448 return;
 449 }
 450#if CPU(ADDRESS64)
 451 uint16_t transitionOffset = m_transitionOffsetAndClassInfo >> transitionOffsetShift;
 452#else
 453 uint16_t transitionOffset = m_transitionOffset;
 454#endif
 455 if (transitionOffset == useRareDataFlag) {
402456 rareData()->m_transitionOffset = offset;
403  else {
404  ensureRareData(vm)->m_transitionOffset = offset;
405  WTF::storeStoreFence();
406  m_transitionOffset = useRareDataFlag;
 457 return;
407458 }
 459
 460 ensureRareData(vm)->m_transitionOffset = offset;
 461 WTF::storeStoreFence();
 462 commit(useRareDataFlag);
408463 }
409464
410465 static unsigned outOfLineCapacity(PropertyOffset maxOffset)

@@class Structure final : public JSCell {
442497 }
443498 bool hasInlineStorage() const
444499 {
445  return !!m_inlineCapacity;
446  }
447  unsigned inlineCapacity() const
448  {
449  return m_inlineCapacity;
 500 return !!inlineCapacity();
450501 }
 502 unsigned inlineCapacity() const { return m_propertyHashAndInlineCapacity & inlineCapacityMask; }
451503 unsigned inlineSize() const
452504 {
453  return std::min<unsigned>(maxOffset() + 1, m_inlineCapacity);
 505 return std::min<unsigned>(maxOffset() + 1, inlineCapacity());
454506 }
455507 unsigned totalStorageCapacity() const
456508 {

@@class Structure final : public JSCell {
462514 {
463515 return JSC::isValidOffset(offset)
464516 && offset <= maxOffset()
465  && (offset < m_inlineCapacity || offset >= firstOutOfLineOffset);
 517 && (offset < static_cast<int>(inlineCapacity()) || offset >= firstOutOfLineOffset);
466518 }
467519
468520 bool hijacksIndexingHeader() const
469521 {
470  return isTypedView(m_classInfo->typedArrayStorageType);
 522 return isTypedView(classInfo()->typedArrayStorageType);
471523 }
472524
473525 bool couldHaveIndexingHeader() const

@@class Structure final : public JSCell {
535587
536588 void setObjectToStringValue(JSGlobalObject*, VM&, JSString* value, PropertySlot toStringTagSymbolSlot);
537589
538  const ClassInfo* classInfo() const { return m_classInfo; }
 590 const ClassInfo* classInfo() const
 591 {
 592#if CPU(ADDRESS64)
 593 return bitwise_cast<const ClassInfo*>(m_transitionOffsetAndClassInfo & classInfoMask);
 594#else
 595 return m_classInfo;
 596#endif
 597 }
539598
540599 static ptrdiff_t structureIDOffset()
541600 {

@@class Structure final : public JSCell {
552611 return OBJECT_OFFSETOF(Structure, m_globalObject);
553612 }
554613
555  static ptrdiff_t classInfoOffset()
 614#if CPU(ADDRESS64)
 615 static ptrdiff_t offsetOfTransitionOffsetAndClassInfo()
 616 {
 617 return OBJECT_OFFSETOF(Structure, m_transitionOffsetAndClassInfo);
 618 }
 619#else
 620 static ptrdiff_t offsetOfClassInfo()
556621 {
557622 return OBJECT_OFFSETOF(Structure, m_classInfo);
558623 }
559 
 624#endif
 625
560626 static ptrdiff_t indexingModeIncludingHistoryOffset()
561627 {
562628 return OBJECT_OFFSETOF(Structure, m_blob) + StructureIDBlob::indexingModeIncludingHistoryOffset();
563629 }
564 
565  static ptrdiff_t propertyTableUnsafeOffset()
566  {
567  return OBJECT_OFFSETOF(Structure, m_propertyTableUnsafe);
568  }
569630
570  static ptrdiff_t inlineCapacityOffset()
 631#if CPU(LITTLE_ENDIAN)
 632 static ptrdiff_t offsetOfInlineCapacity()
571633 {
572  return OBJECT_OFFSETOF(Structure, m_inlineCapacity);
 634 return OBJECT_OFFSETOF(Structure, m_propertyHashAndInlineCapacity);
573635 }
 636#endif
574637
575638 static ptrdiff_t previousOrRareDataOffset()
576639 {

@@class Structure final : public JSCell {
653716
654717 static void dumpContextHeader(PrintStream&);
655718
656  ConcurrentJSLock& lock() { return m_lock; }
657 
658  unsigned propertyHash() const { return m_propertyHash; }
 719 static constexpr unsigned propertyHashShift = 8;
 720 static constexpr uint32_t inlineCapacityMask = (1U << propertyHashShift) - 1;
 721 static_assert(inlineCapacityMask == 0xff, "Lowest 8 bits are for inlineCapacity, this is required to access them through load8 in JIT");
 722 unsigned propertyHash() const { return m_propertyHashAndInlineCapacity >> propertyHashShift; }
 723 void setPropertyHash(unsigned hash)
 724 {
 725 m_propertyHashAndInlineCapacity = (m_propertyHashAndInlineCapacity & inlineCapacityMask) | (hash << propertyHashShift);
 726 }
659727
660728 static bool shouldConvertToPolyProto(const Structure* a, const Structure* b);
661729

@@class Structure final : public JSCell {
684752 {\
685753 m_bitField &= ~(s_##lowerName##Mask << offset);\
686754 m_bitField |= (newValue & s_##lowerName##Mask) << offset;\
 755 ASSERT(newValue == lowerName());\
687756 }
688757
689758 DEFINE_BITFIELD(DictionaryKind, dictionaryKind, DictionaryKind, 2, 0);

@@class Structure final : public JSCell {
691760 DEFINE_BITFIELD(bool, hasGetterSetterProperties, HasGetterSetterProperties, 1, 3);
692761 DEFINE_BITFIELD(bool, hasReadOnlyOrGetterSetterPropertiesExcludingProto, HasReadOnlyOrGetterSetterPropertiesExcludingProto, 1, 4);
693762 DEFINE_BITFIELD(bool, isQuickPropertyAccessAllowedForEnumeration, IsQuickPropertyAccessAllowedForEnumeration, 1, 5);
694  DEFINE_BITFIELD(unsigned, transitionPropertyAttributes, TransitionPropertyAttributes, 14, 6);
695  DEFINE_BITFIELD(bool, didPreventExtensions, DidPreventExtensions, 1, 20);
696  DEFINE_BITFIELD(bool, didTransition, DidTransition, 1, 21);
697  DEFINE_BITFIELD(bool, staticPropertiesReified, StaticPropertiesReified, 1, 22);
698  DEFINE_BITFIELD(bool, hasBeenFlattenedBefore, HasBeenFlattenedBefore, 1, 23);
699  DEFINE_BITFIELD(bool, hasCustomGetterSetterProperties, HasCustomGetterSetterProperties, 1, 24);
700  DEFINE_BITFIELD(bool, didWatchInternalProperties, DidWatchInternalProperties, 1, 25);
701  DEFINE_BITFIELD(bool, transitionWatchpointIsLikelyToBeFired, TransitionWatchpointIsLikelyToBeFired, 1, 26);
702  DEFINE_BITFIELD(bool, hasBeenDictionary, HasBeenDictionary, 1, 27);
703  DEFINE_BITFIELD(bool, protectPropertyTableWhileTransitioning, ProtectPropertyTableWhileTransitioning, 1, 28);
704  DEFINE_BITFIELD(bool, hasUnderscoreProtoPropertyExcludingOriginalProto, HasUnderscoreProtoPropertyExcludingOriginalProto, 1, 29);
705  DEFINE_BITFIELD(bool, isPropertyDeletionTransition, IsPropertyDeletionTransition, 1, 30);
 763 DEFINE_BITFIELD(unsigned, transitionPropertyAttributes, TransitionPropertyAttributes, 8, 6);
 764 DEFINE_BITFIELD(bool, didPreventExtensions, DidPreventExtensions, 1, 14);
 765 DEFINE_BITFIELD(bool, didTransition, DidTransition, 1, 15);
 766 DEFINE_BITFIELD(bool, staticPropertiesReified, StaticPropertiesReified, 1, 16);
 767 DEFINE_BITFIELD(bool, hasBeenFlattenedBefore, HasBeenFlattenedBefore, 1, 17);
 768 DEFINE_BITFIELD(bool, hasCustomGetterSetterProperties, HasCustomGetterSetterProperties, 1, 18);
 769 DEFINE_BITFIELD(bool, didWatchInternalProperties, DidWatchInternalProperties, 1, 19);
 770 DEFINE_BITFIELD(bool, transitionWatchpointIsLikelyToBeFired, TransitionWatchpointIsLikelyToBeFired, 1, 20);
 771 DEFINE_BITFIELD(bool, hasBeenDictionary, HasBeenDictionary, 1, 21);
 772 DEFINE_BITFIELD(bool, protectPropertyTableWhileTransitioning, ProtectPropertyTableWhileTransitioning, 1, 22);
 773 DEFINE_BITFIELD(bool, hasUnderscoreProtoPropertyExcludingOriginalProto, HasUnderscoreProtoPropertyExcludingOriginalProto, 1, 23);
 774 DEFINE_BITFIELD(bool, isPropertyDeletionTransition, IsPropertyDeletionTransition, 1, 24);
706775
707776 static_assert(s_bitWidthOfTransitionPropertyAttributes <= sizeof(TransitionPropertyAttributes) * 8);
708777

@@class Structure final : public JSCell {
738807 // This may grab the lock, or not. Do not call when holding the Structure's lock.
739808 PropertyTable* ensurePropertyTableIfNotEmpty(VM& vm)
740809 {
741  if (PropertyTable* result = m_propertyTableUnsafe.get())
 810 if (PropertyTable* result = propertyTableUnsafeOrNull())
742811 return result;
743812 if (!previousID())
744813 return nullptr;

@@class Structure final : public JSCell {
748817 // This may grab the lock, or not. Do not call when holding the Structure's lock.
749818 PropertyTable* ensurePropertyTable(VM& vm)
750819 {
751  if (PropertyTable* result = m_propertyTableUnsafe.get())
 820 if (PropertyTable* result = propertyTableUnsafeOrNull())
752821 return result;
753822 return materializePropertyTable(vm);
754823 }
755824
756  PropertyTable* propertyTableOrNull() const
 825 PropertyTable* propertyTableUnsafeOrNull() const
757826 {
 827#if CPU(ADDRESS64)
 828 return bitwise_cast<PropertyTable*>(m_outOfLineTypeFlagsAndPropertyTableUnsafe & propertyTableUnsafeMask);
 829#else
758830 return m_propertyTableUnsafe.get();
 831#endif
759832 }
760833
761834 // This will grab the lock. Do not call when holding the Structure's lock.
762835 JS_EXPORT_PRIVATE PropertyTable* materializePropertyTable(VM&, bool setPropertyTable = true);
763836
764837 void setPropertyTable(VM& vm, PropertyTable* table);
 838 void clearPropertyTable();
765839
766840 PropertyTable* takePropertyTableOrCloneIfPinned(VM&);
767841 PropertyTable* copyPropertyTableForPinning(VM&);

@@class Structure final : public JSCell {
780854 {
781855 // Since the number of transitions is often the same as the last offset (except if there are deletes)
782856 // we keep the size of Structure down by not storing both.
783  return numberOfSlotsForMaxOffset(maxOffset(), m_inlineCapacity);
 857 return numberOfSlotsForMaxOffset(maxOffset(), inlineCapacity());
784858 }
785859
786860 bool isValid(JSGlobalObject*, StructureChain* cachedPrototypeChain, JSObject* base) const;

@@class Structure final : public JSCell {
802876
803877 void startWatchingInternalProperties(VM&);
804878
 879 StructureChain* cachedPrototypeChain() const;
 880 void setCachedPrototypeChain(VM&, StructureChain*);
 881 void clearCachedPrototypeChain();
 882
 883 void setOutOfLineTypeFlags(TypeInfo::OutOfLineTypeFlags);
 884 void setClassInfo(const ClassInfo*);
 885
805886 static constexpr int s_maxTransitionLength = 64;
806887 static constexpr int s_maxTransitionLengthForNonEvalPutById = 512;
807888
808889 // These need to be properly aligned at the beginning of the 'Structure'
809890 // part of the object.
810891 StructureIDBlob m_blob;
811  TypeInfo::OutOfLineTypeFlags m_outOfLineTypeFlags;
812 
813  uint8_t m_inlineCapacity;
814892
815  ConcurrentJSLock m_lock;
 893 // Should be accessed through ensurePropertyTable(). During GC, it may be set to 0 by another thread.
 894 // During a Heap Snapshot GC we avoid clearing the table so it is safe to use.
 895#if CPU(ADDRESS64)
 896 // Highest 16 bits are for m_outOfLineTypeFlags. Remaining bits are for m_propertyTableUnsafe.
 897public:
 898 static constexpr unsigned outOfLineTypeFlagsShift = 48;
 899 static constexpr uintptr_t propertyTableUnsafeMask = (1ULL << 48) - 1;
 900 static constexpr uintptr_t outOfLineTypeFlagsShiftedMask = ~propertyTableUnsafeMask;
 901 static_assert(sizeof(TypeInfo::OutOfLineTypeFlags) == 2);
 902
 903 // Highest 16 bits are for m_transitionOffset. Remaining bits are for m_classInfo.
 904 static constexpr unsigned transitionOffsetShift = 48;
 905 static constexpr uintptr_t classInfoMask = (1ULL << 48) - 1;
 906 static constexpr uintptr_t transitionOffsetShiftedMask = ~classInfoMask;
 907
 908 // Highest 16 bits are for m_maxOffset. Remaining bits are for m_cachedPrototypeChain.
 909 static constexpr unsigned maxOffsetShift = 48;
 910 static constexpr uintptr_t cachedPrototypeChainMask = (1ULL << 48) - 1;
 911 static constexpr uintptr_t maxOffsetShiftedMask = ~cachedPrototypeChainMask;
 912private:
 913 UnsafeCellPointer m_outOfLineTypeFlagsAndPropertyTableUnsafe { 0 };
 914 UnsafeCellPointer m_maxOffsetAndCachedPrototypeChain { 0 };
 915 uintptr_t m_transitionOffsetAndClassInfo { 0 };
 916 PackedRefPtr<UniquedStringImpl> m_transitionPropertyName;
 917#else
 918 TypeInfo::OutOfLineTypeFlags m_outOfLineTypeFlags { 0 };
 919 uint16_t m_transitionOffset { 0 };
 920 uint16_t m_maxOffset { 0 };
 921 WriteBarrier<PropertyTable> m_propertyTableUnsafe;
 922 const ClassInfo* m_classInfo { nullptr };
 923 mutable WriteBarrier<StructureChain> m_cachedPrototypeChain;
 924 RefPtr<UniquedStringImpl> m_transitionPropertyName;
 925#endif
 926 StructureTransitionTable m_transitionTable;
816927
817  uint32_t m_bitField;
 928 uint32_t m_bitField { 0 };
818929
819930 WriteBarrier<JSGlobalObject> m_globalObject;
820931 WriteBarrier<Unknown> m_prototype;
821  mutable WriteBarrier<StructureChain> m_cachedPrototypeChain;
822932
823933 WriteBarrier<JSCell> m_previousOrRareData;
824934
825  RefPtr<UniquedStringImpl> m_transitionPropertyName;
826 
827  const ClassInfo* m_classInfo;
828 
829  StructureTransitionTable m_transitionTable;
830 
831  // Should be accessed through ensurePropertyTable(). During GC, it may be set to 0 by another thread.
832  // During a Heap Snapshot GC we avoid clearing the table so it is safe to use.
833  WriteBarrier<PropertyTable> m_propertyTableUnsafe;
834 
835935 mutable InlineWatchpointSet m_transitionWatchpointSet;
836936
837937 COMPILE_ASSERT(firstOutOfLineOffset < 256, firstOutOfLineOffset_fits);
838938
839  uint16_t m_transitionOffset;
840  uint16_t m_maxOffset;
841 
842  uint32_t m_propertyHash;
843  TinyBloomFilter m_seenProperties;
 939 uint32_t m_propertyHashAndInlineCapacity;
 940 uint32_t m_seenProperties { 0 };
844941
845942 friend class VMInspector;
846943 friend class JSDollarVMHelper;
847944};
 945#if CPU(ADDRESS64)
 946static_assert(sizeof(Structure) <= 96, "Do not increase sizeof(Structure), it immediately causes memory regression");
 947#endif
848948
849949} // namespace JSC

Source/JavaScriptCore/runtime/StructureInlines.h

@@ALWAYS_INLINE PropertyOffset Structure::get(VM& vm, PropertyName propertyName, u
144144 ASSERT(!isCompilationThread());
145145 ASSERT(structure(vm)->classInfo() == info());
146146
147  if (m_seenProperties.ruleOut(bitwise_cast<uintptr_t>(propertyName.uid())))
 147 unsigned hashCode = propertyName.uid()->symbolAwareHash();
 148 ASSERT(hashCode); // StringImpl hash never gets zero.
 149 if ((m_seenProperties & hashCode) != hashCode)
148150 return invalidOffset;
149151
150152 PropertyTable* propertyTable = ensurePropertyTableIfNotEmpty(vm);

@@void Structure::forEachPropertyConcurrently(const Functor& functor)
181183
182184 if (!functor(PropertyMapEntry(structure->m_transitionPropertyName.get(), structure->transitionOffset(), structure->transitionPropertyAttributes()))) {
183185 if (table)
184  tableStructure->m_lock.unlock();
 186 tableStructure->cellLock().unlock();
185187 return;
186188 }
187189 }

@@void Structure::forEachPropertyConcurrently(const Functor& functor)
192194 continue;
193195
194196 if (!functor(entry)) {
195  tableStructure->m_lock.unlock();
 197 tableStructure->cellLock().unlock();
196198 return;
197199 }
198200 }
199  tableStructure->m_lock.unlock();
 201 tableStructure->cellLock().unlock();
200202 }
201203}
202204

@@inline JSValue Structure::prototypeForLookup(JSGlobalObject* globalObject, JSCel
302304 return prototypeForLookupPrimitiveImpl(globalObject, this);
303305}
304306
 307inline StructureChain* Structure::cachedPrototypeChain() const
 308{
 309#if CPU(ADDRESS64)
 310 return bitwise_cast<StructureChain*>(m_maxOffsetAndCachedPrototypeChain & cachedPrototypeChainMask);
 311#else
 312 return m_cachedPrototypeChain.get();
 313#endif
 314}
 315
 316inline void Structure::setCachedPrototypeChain(VM& vm, StructureChain* chain)
 317{
 318#if CPU(ADDRESS64)
 319 uintptr_t value = bitwise_cast<uintptr_t>(chain) | (m_maxOffsetAndCachedPrototypeChain & maxOffsetShiftedMask);
 320 m_maxOffsetAndCachedPrototypeChain = value;
 321 vm.heap.writeBarrier(this, chain);
 322#else
 323 m_cachedPrototypeChain.set(vm, this, chain);
 324#endif
 325}
 326
 327inline void Structure::clearCachedPrototypeChain()
 328{
 329#if CPU(ADDRESS64)
 330 uintptr_t value = m_maxOffsetAndCachedPrototypeChain & maxOffsetShiftedMask;
 331 m_maxOffsetAndCachedPrototypeChain = value;
 332#else
 333 m_cachedPrototypeChain.clear();
 334#endif
 335}
 336
305337inline StructureChain* Structure::prototypeChain(VM& vm, JSGlobalObject* globalObject, JSObject* base) const
306338{
307339 ASSERT(base->structure(vm) == this);
308340 // We cache our prototype chain so our clients can share it.
309  if (!isValid(globalObject, m_cachedPrototypeChain.get(), base)) {
 341 if (!isValid(globalObject, cachedPrototypeChain(), base)) {
310342 JSValue prototype = prototypeForLookup(globalObject, base);
311  m_cachedPrototypeChain.set(vm, this, StructureChain::create(vm, prototype.isNull() ? nullptr : asObject(prototype)));
 343 const_cast<Structure*>(this)->setCachedPrototypeChain(vm, StructureChain::create(vm, prototype.isNull() ? nullptr : asObject(prototype)));
312344 }
313  return m_cachedPrototypeChain.get();
 345 return cachedPrototypeChain();
314346}
315347
316348inline StructureChain* Structure::prototypeChain(JSGlobalObject* globalObject, JSObject* base) const

@@inline void Structure::didReplaceProperty(PropertyOffset offset)
350382
351383inline WatchpointSet* Structure::propertyReplacementWatchpointSet(PropertyOffset offset)
352384{
353  ConcurrentJSLocker locker(m_lock);
 385 ConcurrentJSCellLocker locker(cellLock());
354386 if (!hasRareData())
355387 return nullptr;
356388 WTF::loadLoadFence();

@@ALWAYS_INLINE bool Structure::checkOffsetConsistency(PropertyTable* propertyTabl
371403 return true;
372404
373405 unsigned totalSize = propertyTable->propertyStorageSize();
374  unsigned inlineOverflowAccordingToTotalSize = totalSize < m_inlineCapacity ? 0 : totalSize - m_inlineCapacity;
 406 unsigned inlineOverflowAccordingToTotalSize = totalSize < inlineCapacity() ? 0 : totalSize - inlineCapacity();
375407
376408 auto fail = [&] (const char* description) {
377409 dataLog("Detected offset inconsistency: ", description, "!\n");
378410 dataLog("this = ", RawPointer(this), "\n");
379411 dataLog("transitionOffset = ", transitionOffset(), "\n");
380412 dataLog("maxOffset = ", maxOffset(), "\n");
381  dataLog("m_inlineCapacity = ", m_inlineCapacity, "\n");
 413 dataLog("m_inlineCapacity = ", inlineCapacity(), "\n");
382414 dataLog("propertyTable = ", RawPointer(propertyTable), "\n");
383  dataLog("numberOfSlotsForMaxOffset = ", numberOfSlotsForMaxOffset(maxOffset(), m_inlineCapacity), "\n");
 415 dataLog("numberOfSlotsForMaxOffset = ", numberOfSlotsForMaxOffset(maxOffset(), inlineCapacity()), "\n");
384416 dataLog("totalSize = ", totalSize, "\n");
385417 dataLog("inlineOverflowAccordingToTotalSize = ", inlineOverflowAccordingToTotalSize, "\n");
386418 dataLog("numberOfOutOfLineSlotsForMaxOffset = ", numberOfOutOfLineSlotsForMaxOffset(maxOffset()), "\n");

@@ALWAYS_INLINE bool Structure::checkOffsetConsistency(PropertyTable* propertyTabl
388420 UNREACHABLE_FOR_PLATFORM();
389421 };
390422
391  if (numberOfSlotsForMaxOffset(maxOffset(), m_inlineCapacity) != totalSize)
 423 if (numberOfSlotsForMaxOffset(maxOffset(), inlineCapacity()) != totalSize)
392424 fail("numberOfSlotsForMaxOffset doesn't match totalSize");
393425 if (inlineOverflowAccordingToTotalSize != numberOfOutOfLineSlotsForMaxOffset(maxOffset()))
394426 fail("inlineOverflowAccordingToTotalSize doesn't match numberOfOutOfLineSlotsForMaxOffset");

@@ALWAYS_INLINE bool Structure::checkOffsetConsistency(PropertyTable* propertyTabl
398430
399431ALWAYS_INLINE bool Structure::checkOffsetConsistency() const
400432{
401  PropertyTable* propertyTable = propertyTableOrNull();
 433 PropertyTable* propertyTable = propertyTableUnsafeOrNull();
402434
403435 if (!propertyTable) {
404436 ASSERT(!isPinnedPropertyTable());

@@inline PropertyOffset Structure::add(VM& vm, PropertyName propertyName, unsigned
439471{
440472 PropertyTable* table = ensurePropertyTable(vm);
441473
442  GCSafeConcurrentJSLocker locker(m_lock, vm.heap);
 474 GCSafeConcurrentJSCellLocker locker(cellLock(), vm.heap);
443475
444476 switch (shouldPin) {
445477 case ShouldPin::Yes:

@@inline PropertyOffset Structure::add(VM& vm, PropertyName propertyName, unsigned
460492
461493 auto rep = propertyName.uid();
462494
463  PropertyOffset newOffset = table->nextOffset(m_inlineCapacity);
 495 PropertyOffset newOffset = table->nextOffset(inlineCapacity());
464496
465  m_propertyHash = m_propertyHash ^ rep->existingSymbolAwareHash();
466  m_seenProperties.add(bitwise_cast<uintptr_t>(rep));
 497 unsigned hashCode = rep->existingSymbolAwareHash();
 498 setPropertyHash(propertyHash() ^ hashCode);
 499 m_seenProperties = m_seenProperties | hashCode;
467500
468501 auto result = table->add(PropertyMapEntry(rep, newOffset, attributes));
469502 ASSERT_UNUSED(result, result.second);

@@template<Structure::ShouldPin shouldPin, typename Func>
482515inline PropertyOffset Structure::remove(VM& vm, PropertyName propertyName, const Func& func)
483516{
484517 PropertyTable* table = ensurePropertyTable(vm);
485  GCSafeConcurrentJSLocker locker(m_lock, vm.heap);
 518 GCSafeConcurrentJSCellLocker locker(cellLock(), vm.heap);
486519
487520 switch (shouldPin) {
488521 case ShouldPin::Yes:

@@inline PropertyOffset Structure::removePropertyWithoutTransition(VM& vm, Propert
532565{
533566 ASSERT(isUncacheableDictionary());
534567 ASSERT(isPinnedPropertyTable());
535  ASSERT(propertyTableOrNull());
 568 ASSERT(propertyTableUnsafeOrNull());
536569
537570 return remove<ShouldPin::Yes>(vm, propertyName, func);
538571}

@@ALWAYS_INLINE void Structure::setGlobalObject(VM& vm, JSGlobalObject* globalObje
550583
551584ALWAYS_INLINE void Structure::setPropertyTable(VM& vm, PropertyTable* table)
552585{
 586#if CPU(ADDRESS64)
 587 uintptr_t value = bitwise_cast<uintptr_t>(table) | (m_outOfLineTypeFlagsAndPropertyTableUnsafe & outOfLineTypeFlagsShiftedMask);
 588 m_outOfLineTypeFlagsAndPropertyTableUnsafe = value;
 589 vm.heap.writeBarrier(this, table);
 590#else
553591 m_propertyTableUnsafe.setMayBeNull(vm, this, table);
 592#endif
 593}
 594
 595ALWAYS_INLINE void Structure::clearPropertyTable()
 596{
 597#if CPU(ADDRESS64)
 598 uintptr_t value = m_outOfLineTypeFlagsAndPropertyTableUnsafe & outOfLineTypeFlagsShiftedMask;
 599 m_outOfLineTypeFlagsAndPropertyTableUnsafe = value;
 600#else
 601 m_propertyTableUnsafe.clear();
 602#endif
 603}
 604
 605ALWAYS_INLINE void Structure::setOutOfLineTypeFlags(TypeInfo::OutOfLineTypeFlags outOfLineTypeFlags)
 606{
 607#if CPU(ADDRESS64)
 608 uintptr_t value = (static_cast<uintptr_t>(outOfLineTypeFlags) << outOfLineTypeFlagsShift) | (m_outOfLineTypeFlagsAndPropertyTableUnsafe & propertyTableUnsafeMask);
 609 m_outOfLineTypeFlagsAndPropertyTableUnsafe = value;
 610#else
 611 m_outOfLineTypeFlags = outOfLineTypeFlags;
 612#endif
 613}
 614
 615ALWAYS_INLINE void Structure::setClassInfo(const ClassInfo* classInfo)
 616{
 617#if CPU(ADDRESS64)
 618 uintptr_t value = bitwise_cast<uintptr_t>(classInfo) | (m_transitionOffsetAndClassInfo & transitionOffsetShiftedMask);
 619 m_transitionOffsetAndClassInfo = value;
 620#else
 621 m_classInfo = classInfo;
 622#endif
554623}
555624
556625ALWAYS_INLINE void Structure::setPreviousID(VM& vm, Structure* structure)

Source/JavaScriptCore/runtime/StructureTransitionTable.h

@@static constexpr unsigned FirstInternalAttribute = 1 << 6; // Use for transition
3939
4040// Support for attributes used to indicate transitions not related to properties.
4141// If any of these are used, the string portion of the key should be 0.
42 enum class NonPropertyTransition : unsigned {
43  AllocateUndecided,
 42enum class NonPropertyTransition : uint8_t {
 43 AllocateUndecided = 0,
4444 AllocateInt32,
4545 AllocateDouble,
4646 AllocateContiguous,

@@enum class NonPropertyTransition : unsigned {
5050 AddIndexedAccessors,
5151 PreventExtensions,
5252 Seal,
53  Freeze
 53 Freeze,
 54 LastOfNonPropertyTransition = Freeze,
5455};
55 using TransitionPropertyAttributes = uint16_t;
 56using TransitionPropertyAttributes = uint8_t;
5657
57 inline unsigned toAttributes(NonPropertyTransition transition)
 58inline constexpr uint8_t toAttributes(NonPropertyTransition transition)
5859{
5960 return static_cast<unsigned>(transition) + FirstInternalAttribute;
6061}
 62static_assert(toAttributes(NonPropertyTransition::LastOfNonPropertyTransition) <= UINT8_MAX);
6163
6264inline bool changesIndexingType(NonPropertyTransition transition)
6365{

@@class StructureTransitionTable {
231233
232234public:
233235 StructureTransitionTable()
234  : m_data(UsingSingleSlotFlag)
 236 : m_data(bitwise_cast<uint8_t*>(UsingSingleSlotFlag))
235237 {
236238 }
237239

@@class StructureTransitionTable {
257259
258260 bool isUsingSingleSlot() const
259261 {
260  return m_data & UsingSingleSlotFlag;
 262 return bitwise_cast<uintptr_t>(m_data.get()) & UsingSingleSlotFlag;
261263 }
262264
263265 TransitionMap* map() const
264266 {
265267 ASSERT(!isUsingSingleSlot());
266  return bitwise_cast<TransitionMap*>(m_data);
 268 return bitwise_cast<TransitionMap*>(m_data.get());
267269 }
268270
269271 WeakImpl* weakImpl() const
270272 {
271273 ASSERT(isUsingSingleSlot());
272  return bitwise_cast<WeakImpl*>(m_data & ~UsingSingleSlotFlag);
 274 return bitwise_cast<WeakImpl*>(bitwise_cast<uintptr_t>(m_data.get()) & ~UsingSingleSlotFlag);
273275 }
274276
275277 void setMap(TransitionMap* map)

@@class StructureTransitionTable {
280282 WeakSet::deallocate(impl);
281283
282284 // This implicitly clears the flag that indicates we're using a single transition
283  m_data = bitwise_cast<intptr_t>(map);
 285 m_data = bitwise_cast<uint8_t*>(map);
284286
285287 ASSERT(!isUsingSingleSlot());
286288 }

@@class StructureTransitionTable {
288290 Structure* singleTransition() const;
289291 void setSingleTransition(Structure*);
290292
291  intptr_t m_data;
 293#if CPU(ADDRESS64)
 294 PackedPtr<uint8_t> m_data;
 295#else
 296 NakedPtr<uint8_t> m_data;
 297#endif
292298};
293299
294300} // namespace JSC

Source/JavaScriptCore/runtime/WriteBarrier.h

@@inline bool operator==(const WriteBarrierBase<U, TraitsU>& lhs, const WriteBarri
248248 return lhs.get() == rhs.get();
249249}
250250
 251using UnsafeCellPointer = uintptr_t;
 252
251253} // namespace JSC

Source/JavaScriptCore/wasm/js/WebAssemblyFunction.cpp

@@MacroAssemblerCodePtr<JSEntryPtrTag> WebAssemblyFunction::jsCallEntrypointSlow()
274274
275275 stackLimitGPRIsClobbered = true;
276276 jit.emitLoadStructure(vm, scratchGPR, scratchGPR, stackLimitGPR);
277  jit.loadPtr(CCallHelpers::Address(scratchGPR, Structure::classInfoOffset()), scratchGPR);
 277 jit.loadPtr(CCallHelpers::Address(scratchGPR, Structure::offsetOfTransitionOffsetAndClassInfo()), scratchGPR);
 278 jit.andPtr(CCallHelpers::TrustedImmPtr(bitwise_cast<void*>(Structure::classInfoMask)), scratchGPR);
278279
279280 static_assert(std::is_final<WebAssemblyFunction>::value, "We do not check for subtypes below");
280281 static_assert(std::is_final<WebAssemblyWrapperFunction>::value, "We do not check for subtypes below");

Source/WTF/wtf/text/StringImpl.h

@@class StringImpl : private StringImplShape {
189189
190190 static constexpr unsigned MaxLength = StringImplShape::MaxLength;
191191
192  // The bottom 6 bits in the hash are flags.
193  static constexpr const unsigned s_flagCount = 6;
 192 // The bottom 6 bits in the hash are flags, but reserve 8 bits since StringHash only has 24 bits anyway.
 193 static constexpr const unsigned s_flagCount = 8;
194194
195195private:
196196 static constexpr const unsigned s_flagMask = (1u << s_flagCount) - 1;

Source/WTF/wtf/text/SymbolImpl.h

@@class SymbolImpl : public UniquedStringImpl {
4141 static constexpr Flags s_flagIsRegistered = 0b010u;
4242 static constexpr Flags s_flagIsPrivate = 0b100u;
4343
44  unsigned hashForSymbol() const { return m_hashForSymbol; }
 44 unsigned hashForSymbol() const { return m_hashForSymbol >> s_flagCount; }
4545 bool isNullSymbol() const { return m_flags & s_flagIsNullSymbol; }
4646 bool isRegistered() const { return m_flags & s_flagIsRegistered; }
4747 bool isPrivate() const { return m_flags & s_flagIsPrivate; }

LayoutTests/ChangeLog

 12020-02-17 Yusuke Suzuki <ysuzuki@apple.com>
 2
 3 [JSC] Shrink Structure
 4 https://bugs.webkit.org/show_bug.cgi?id=207827
 5
 6 Reviewed by NOBODY (OOPS!).
 7
 8 This test is half-broken since it relies on HashMap's order implicitly.
 9 We changed SymbolImpl's hash code, so it makes the result different.
 10
 11 * inspector/debugger/tail-deleted-frames/tail-deleted-frames-this-value-expected.txt:
 12
1132020-02-17 Zalan Bujtas <zalan@apple.com>
214
315 [LFC][Out-of-flow] FormattingContext::computeOutOfFlowHorizontalGeometry needs verticalConstraints

LayoutTests/inspector/debugger/tail-deleted-frames/tail-deleted-frames-this-value-expected.txt

@@CALL STACK:
14143: [F] startABC
1515 this: undefined
16164: [P] Global Code
17  this: c -
 17 this: a -
1818RESUMED
1919