Diff
Modified: trunk/JSTests/ChangeLog (282238 => 282239)
--- trunk/JSTests/ChangeLog 2021-09-09 20:58:37 UTC (rev 282238)
+++ trunk/JSTests/ChangeLog 2021-09-09 21:36:38 UTC (rev 282239)
@@ -1,3 +1,17 @@
+2021-09-09 Yusuke Suzuki <[email protected]>
+
+ [JSC] Optimize op_get_property_enumerator further
+ https://bugs.webkit.org/show_bug.cgi?id=230086
+
+ Reviewed by Saam Barati.
+
+ * stress/for-in-cell-other.js: Added.
+ (shouldBe):
+ (forIn):
+ * stress/for-in-null-undefined.js: Added.
+ (shouldBe):
+ (forIn):
+
2021-09-09 Justin Michaud <[email protected]>
Differential testing: incorrect constant propagation around Uint8ClampedArray
Added: trunk/JSTests/stress/for-in-cell-other.js (0 => 282239)
--- trunk/JSTests/stress/for-in-cell-other.js (rev 0)
+++ trunk/JSTests/stress/for-in-cell-other.js 2021-09-09 21:36:38 UTC (rev 282239)
@@ -0,0 +1,22 @@
+function shouldBe(actual, expected) {
+ if (actual !== expected)
+ throw new Error('bad value: ' + actual);
+}
+
+function forIn(object)
+{
+ var iteration = 0;
+ for (var i in object)
+ ++iteration;
+ return iteration;
+}
+noInline(forIn);
+
+var object = { i: 42, i2: 43, i3: 44 };
+var object2 = { i: 42, i2: 43, i3: 44, i4:45 };
+for (var i = 0; i < 1e5; ++i) {
+ shouldBe(forIn(null), 0);
+ shouldBe(forIn(object), 3);
+ shouldBe(forIn(undefined), 0);
+ shouldBe(forIn(object2), 4);
+}
Added: trunk/JSTests/stress/for-in-null-undefined.js (0 => 282239)
--- trunk/JSTests/stress/for-in-null-undefined.js (rev 0)
+++ trunk/JSTests/stress/for-in-null-undefined.js 2021-09-09 21:36:38 UTC (rev 282239)
@@ -0,0 +1,18 @@
+function shouldBe(actual, expected) {
+ if (actual !== expected)
+ throw new Error('bad value: ' + actual);
+}
+
+function forIn(object)
+{
+ var iteration = 0;
+ for (var i in object)
+ ++iteration;
+ return iteration;
+}
+noInline(forIn);
+
+for (var i = 0; i < 1e6; ++i) {
+ shouldBe(forIn(null), 0);
+ shouldBe(forIn(undefined), 0);
+}
Modified: trunk/Source/_javascript_Core/ChangeLog (282238 => 282239)
--- trunk/Source/_javascript_Core/ChangeLog 2021-09-09 20:58:37 UTC (rev 282238)
+++ trunk/Source/_javascript_Core/ChangeLog 2021-09-09 21:36:38 UTC (rev 282239)
@@ -1,3 +1,84 @@
+2021-09-09 Yusuke Suzuki <[email protected]>
+
+ [JSC] Optimize op_get_property_enumerator further
+ https://bugs.webkit.org/show_bug.cgi?id=230086
+
+ Reviewed by Saam Barati.
+
+ 1. This patch adds fast path of op_get_property_enumerator to LLInt and Baseline. Previously, we only had this fast path in DFG and FTL.
+ 2. From the profiled data, Speedometer2/React-Redux-TodoMVC has GetPropertyEnumerator(CellOrOther). However, DFG and FTL only optimized
+ GetPropertyEnumerator(Cell). We add CellOrOther and Other cases: if the argument is Other, then we can constant fold it to the
+ empty enumerator. If the argument is CellOrOther, we can check first, and return empty enumerator for Other case.
+ 3. This patch also cleans up StructureRareData lookup by introducing StructureType to JSType.
+
+ ----------------------------------------------------------------------------------------------------------------------------------
+ | subtest | ms | ms | b / a | pValue (significance using False Discovery Rate) |
+ ----------------------------------------------------------------------------------------------------------------------------------
+ | Elm-TodoMVC |117.388333 |117.680000 |1.002485 | 0.269607 |
+ | VueJS-TodoMVC |24.918333 |24.651667 |0.989298 | 0.157665 |
+ | EmberJS-TodoMVC |126.430000 |126.296667 |0.998945 | 0.673803 |
+ | BackboneJS-TodoMVC |48.695000 |48.411667 |0.994181 | 0.019164 |
+ | Preact-TodoMVC |17.268333 |17.511667 |1.014091 | 0.199775 |
+ | AngularJS-TodoMVC |130.246667 |129.850000 |0.996954 | 0.261543 |
+ | Vanilla-ES2015-TodoMVC |63.626667 |63.611667 |0.999764 | 0.912112 |
+ | Inferno-TodoMVC |63.881667 |63.600000 |0.995591 | 0.385440 |
+ | Flight-TodoMVC |78.158333 |78.606667 |1.005736 | 0.284177 |
+ | Angular2-TypeScript-TodoMVC |39.448333 |39.411667 |0.999071 | 0.890825 |
+ | VanillaJS-TodoMVC |50.858333 |51.130000 |1.005342 | 0.195409 |
+ | jQuery-TodoMVC |225.318333 |226.256667 |1.004164 | 0.011190 |
+ | EmberJS-Debug-TodoMVC |340.150000 |338.450000 |0.995002 | 0.000063 (significant) |
+ | React-TodoMVC |85.703333 |85.606667 |0.998872 | 0.549298 |
+ | React-Redux-TodoMVC |141.985000 |140.418333 |0.988966 | 0.000000 (significant) |
+ | Vanilla-ES2015-Babel-Webpack-TodoMVC |61.505000 |61.705000 |1.003252 | 0.079817 |
+ ----------------------------------------------------------------------------------------------------------------------------------
+ a mean = 260.98021
+ b mean = 261.16020
+ pValue = 0.4985041089
+ (Bigger means are better.)
+ 1.001 times better
+ Results ARE NOT significant
+
+ * bytecode/SpeculatedType.cpp:
+ (JSC::dumpSpeculation):
+ * dfg/DFGFixupPhase.cpp:
+ (JSC::DFG::FixupPhase::fixupNode):
+ * dfg/DFGSpeculativeJIT.cpp:
+ (JSC::DFG::SpeculativeJIT::compileGetPropertyEnumerator):
+ (JSC::DFG::SpeculativeJIT::compileObjectKeysOrObjectGetOwnPropertyNames):
+ * ftl/FTLLowerDFGToB3.cpp:
+ (JSC::FTL::DFG::LowerDFGToB3::compileObjectKeysOrObjectGetOwnPropertyNames):
+ (JSC::FTL::DFG::LowerDFGToB3::compileCompareStrictEq):
+ * jit/AssemblyHelpers.h:
+ (JSC::AssemblyHelpers::branchIfStructure):
+ (JSC::AssemblyHelpers::branchIfNotStructure):
+ * jit/JIT.cpp:
+ (JSC::JIT::privateCompileMainPass):
+ * jit/JIT.h:
+ * jit/JITPropertyAccess.cpp:
+ (JSC::JIT::emit_op_get_property_enumerator):
+ * jit/JITPropertyAccess32_64.cpp:
+ (JSC::JIT::emit_op_get_property_enumerator):
+ * llint/LowLevelInterpreter.asm:
+ * llint/LowLevelInterpreter32_64.asm:
+ * llint/LowLevelInterpreter64.asm:
+ * runtime/BrandedStructure.cpp:
+ (JSC::BrandedStructure::create):
+ * runtime/JSType.cpp:
+ (WTF::printInternal):
+ * runtime/JSType.h:
+ * runtime/Structure.cpp:
+ (JSC::Structure::Structure):
+ (JSC::Structure::create):
+ * runtime/Structure.h:
+ (JSC::Structure::isRareData):
+ (JSC::Structure::isRareData const): Deleted.
+ * runtime/StructureInlines.h:
+ (JSC::Structure::create):
+ (JSC::Structure::createStructure):
+ * runtime/StructureRareData.h:
+ * runtime/VM.cpp:
+ (JSC::VM::VM):
+
2021-09-09 Patrick Angle <[email protected]>
run-webkit-archive crashes with dyld error
Modified: trunk/Source/_javascript_Core/bytecode/SpeculatedType.cpp (282238 => 282239)
--- trunk/Source/_javascript_Core/bytecode/SpeculatedType.cpp 2021-09-09 20:58:37 UTC (rev 282238)
+++ trunk/Source/_javascript_Core/bytecode/SpeculatedType.cpp 2021-09-09 21:36:38 UTC (rev 282239)
@@ -250,6 +250,11 @@
strOut.print("Symbol");
else
isTop = false;
+
+ if (value & SpecHeapBigInt)
+ strOut.print("HeapBigInt");
+ else
+ isTop = false;
}
if (value == SpecInt32Only)
@@ -285,20 +290,11 @@
isTop = false;
}
- if ((value & SpecBigInt) == SpecBigInt)
- strOut.print("BigInt");
#if USE(BIGINT32)
- else {
- if (value & SpecBigInt32)
- strOut.print("BigInt32");
- else
- isTop = false;
-
- if (value & SpecHeapBigInt)
- strOut.print("HeapBigInt");
- else
- isTop = false;
- }
+ if (value & SpecBigInt32)
+ strOut.print("BigInt32");
+ else
+ isTop = false;
#endif
if (value & SpecDoubleImpureNaN)
Modified: trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp (282238 => 282239)
--- trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp 2021-09-09 20:58:37 UTC (rev 282238)
+++ trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp 2021-09-09 21:36:38 UTC (rev 282239)
@@ -2274,6 +2274,11 @@
case GetPropertyEnumerator: {
if (node->child1()->shouldSpeculateCell())
fixEdge<CellUse>(node->child1());
+ else if (node->child1()->shouldSpeculateOther()) {
+ insertCheck<OtherUse>(node->child1().node());
+ m_graph.convertToConstant(node, m_graph.freeze(vm().emptyPropertyNameEnumerator()));
+ } else if (node->child1()->shouldSpeculateCellOrOther())
+ fixEdge<CellOrOtherUse>(node->child1());
break;
}
Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp (282238 => 282239)
--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp 2021-09-09 20:58:37 UTC (rev 282238)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp 2021-09-09 21:36:38 UTC (rev 282239)
@@ -14006,17 +14006,27 @@
void SpeculativeJIT::compileGetPropertyEnumerator(Node* node)
{
- if (node->child1().useKind() == CellUse) {
- SpeculateCellOperand base(this, node->child1());
+ if (node->child1().useKind() == CellUse || node->child1().useKind() == CellOrOtherUse) {
+ JSValueOperand base(this, node->child1(), ManualOperandSpeculation);
GPRTemporary scratch1(this);
GPRTemporary scratch2(this);
- GPRReg baseGPR = base.gpr();
+ speculate(node, node->child1());
+
+ JSValueRegs baseRegs = base.jsValueRegs();
GPRReg scratch1GPR = scratch1.gpr();
GPRReg scratch2GPR = scratch2.gpr();
CCallHelpers::JumpList slowCases;
+ CCallHelpers::JumpList doneCases;
+ if (node->child1().useKind() == CellOrOtherUse) {
+ auto notOther = m_jit.branchIfNotOther(baseRegs, scratch1GPR);
+ m_jit.move(TrustedImmPtr::weakPointer(m_graph, vm().emptyPropertyNameEnumerator()), scratch1GPR);
+ doneCases.append(m_jit.jump());
+ notOther.link(&m_jit);
+ }
+
// We go to the inlined fast path if the object is UndecidedShape / NoIndexingShape for simplicity.
static_assert(!NonArray);
static_assert(ArrayClass == 1);
@@ -14025,26 +14035,56 @@
static_assert(NonArray <= ArrayWithUndecided);
static_assert(ArrayClass <= ArrayWithUndecided);
static_assert(ArrayWithUndecided <= ArrayWithUndecided);
- m_jit.load8(CCallHelpers::Address(baseGPR, JSCell::indexingTypeAndMiscOffset()), scratch1GPR);
- m_jit.and32(CCallHelpers::TrustedImm32(IndexingTypeMask), scratch1GPR);
- slowCases.append(m_jit.branch32(CCallHelpers::Above, scratch1GPR, CCallHelpers::TrustedImm32(ArrayWithUndecided)));
- m_jit.emitLoadStructure(vm(), baseGPR, scratch1GPR, scratch2GPR);
- m_jit.loadPtr(CCallHelpers::Address(scratch1GPR, Structure::previousOrRareDataOffset()), scratch1GPR);
+ AbstractValue& baseValue = m_state.forNode(node->child1());
+ RegisteredStructure onlyStructure;
+ StructureRareData* rareData = nullptr;
+ bool skipIndexingMaskCheck = false;
+ if (baseValue.isType(SpecObject) && baseValue.m_structure.isFinite()) {
+ bool hasIndexing = false;
+ baseValue.m_structure.forEach([&] (RegisteredStructure structure) {
+ if (structure->indexingType() > ArrayWithUndecided)
+ hasIndexing = true;
+ });
+ if (!hasIndexing)
+ skipIndexingMaskCheck = true;
+ _onlyStructure_ = baseValue.m_structure.onlyStructure();
+ if (onlyStructure)
+ rareData = onlyStructure->tryRareData();
+ }
+
+ if (!skipIndexingMaskCheck) {
+ m_jit.load8(CCallHelpers::Address(baseRegs.payloadGPR(), JSCell::indexingTypeAndMiscOffset()), scratch1GPR);
+ m_jit.and32(CCallHelpers::TrustedImm32(IndexingTypeMask), scratch1GPR);
+ slowCases.append(m_jit.branch32(CCallHelpers::Above, scratch1GPR, CCallHelpers::TrustedImm32(ArrayWithUndecided)));
+ }
+
+ if (rareData) {
+ FrozenValue* frozenRareData = m_graph.freeze(rareData);
+ m_jit.move(TrustedImmPtr(frozenRareData), scratch1GPR);
+ m_jit.loadPtr(CCallHelpers::Address(scratch1GPR, StructureRareData::offsetOfCachedPropertyNameEnumerator()), scratch1GPR);
+ } else {
+ if (onlyStructure)
+ m_jit.move(TrustedImmPtr(onlyStructure), scratch1GPR);
+ else
+ m_jit.emitLoadStructure(vm(), baseRegs.payloadGPR(), scratch1GPR, scratch2GPR);
+ m_jit.loadPtr(CCallHelpers::Address(scratch1GPR, Structure::previousOrRareDataOffset()), scratch1GPR);
+ slowCases.append(m_jit.branchTestPtr(CCallHelpers::Zero, scratch1GPR));
+ slowCases.append(m_jit.branchIfStructure(scratch1GPR));
+ m_jit.loadPtr(CCallHelpers::Address(scratch1GPR, StructureRareData::offsetOfCachedPropertyNameEnumerator()), scratch1GPR);
+ }
+
slowCases.append(m_jit.branchTestPtr(CCallHelpers::Zero, scratch1GPR));
- slowCases.append(m_jit.branch32(CCallHelpers::Equal, CCallHelpers::Address(scratch1GPR, JSCell::structureIDOffset()), TrustedImm32(bitwise_cast<int32_t>(vm().structureStructure->structureID()))));
- m_jit.loadPtr(CCallHelpers::Address(scratch1GPR, StructureRareData::offsetOfCachedPropertyNameEnumerator()), scratch1GPR);
- slowCases.append(m_jit.branchTestPtr(CCallHelpers::Zero, scratch1GPR));
slowCases.append(m_jit.branchTest32(CCallHelpers::Zero, CCallHelpers::Address(scratch1GPR, JSPropertyNameEnumerator::flagsOffset()), CCallHelpers::TrustedImm32(JSPropertyNameEnumerator::ValidatedViaWatchpoint)));
- auto done = m_jit.jump();
+ doneCases.append(m_jit.jump());
slowCases.link(&m_jit);
silentSpillAllRegisters(scratch1GPR, scratch2GPR);
- callOperation(operationGetPropertyEnumeratorCell, scratch1GPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), baseGPR);
+ callOperation(operationGetPropertyEnumeratorCell, scratch1GPR, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), baseRegs.payloadGPR());
silentFillAllRegisters();
m_jit.exceptionCheck();
- done.link(&m_jit);
+ doneCases.link(&m_jit);
cellResult(scratch1GPR, node);
return;
}
@@ -14305,7 +14345,7 @@
m_jit.loadPtr(CCallHelpers::Address(structureGPR, Structure::previousOrRareDataOffset()), scratchGPR);
slowCases.append(m_jit.branchTestPtr(CCallHelpers::Zero, scratchGPR));
- slowCases.append(m_jit.branch32(CCallHelpers::Equal, CCallHelpers::Address(scratchGPR, JSCell::structureIDOffset()), TrustedImm32(bitwise_cast<int32_t>(vm().structureStructure->structureID()))));
+ slowCases.append(m_jit.branchIfStructure(scratchGPR));
m_jit.loadPtr(CCallHelpers::Address(scratchGPR, StructureRareData::offsetOfCachedPropertyNames(node->op() == ObjectKeys ? CachedPropertyNamesKind::Keys : CachedPropertyNamesKind::GetOwnPropertyNames)), scratchGPR);
Modified: trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp (282238 => 282239)
--- trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp 2021-09-09 20:58:37 UTC (rev 282238)
+++ trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp 2021-09-09 21:36:38 UTC (rev 282239)
@@ -7207,8 +7207,8 @@
LBasicBlock lastNext = m_out.appendTo(notNullCase, rareDataCase);
m_out.branch(
- m_out.notEqual(m_out.load32(previousOrRareData, m_heaps.JSCell_structureID), m_out.constInt32(m_graph.m_vm.structureStructure->structureID())),
- unsure(rareDataCase), unsure(slowCase));
+ isCellWithType(previousOrRareData, StructureType, std::nullopt),
+ unsure(slowCase), unsure(rareDataCase));
m_out.appendTo(rareDataCase, useCacheCase);
ASSERT(bitwise_cast<uintptr_t>(StructureRareData::cachedPropertyNamesSentinel()) == 1);
@@ -13314,7 +13314,7 @@
void compileGetPropertyEnumerator()
{
JSGlobalObject* globalObject = m_graph.globalObjectFor(m_origin.semantic);
- if (m_node->child1().useKind() == CellUse) {
+ if (m_node->child1().useKind() == CellUse || m_node->child1().useKind() == CellOrOtherUse) {
LBasicBlock checkExistingCase = m_out.newBlock();
LBasicBlock notNullCase = m_out.newBlock();
LBasicBlock rareDataCase = m_out.newBlock();
@@ -13321,9 +13321,19 @@
LBasicBlock validationCase = m_out.newBlock();
LBasicBlock genericCase = m_out.newBlock();
LBasicBlock continuation = m_out.newBlock();
+ LBasicBlock lastNext = nullptr;
- LValue cell = lowCell(m_node->child1());
+ LValue base = lowJSValue(m_node->child1(), ManualOperandSpeculation);
+ speculate(m_node->child1());
+ Vector<ValueFromBlock, 3> results;
+ if (m_node->child1().useKind() == CellOrOtherUse) {
+ LBasicBlock cellCase = m_out.newBlock();
+ results.append(m_out.anchor(weakPointer(m_graph.m_vm.emptyPropertyNameEnumerator())));
+ m_out.branch(isOther(base, provenType(m_node->child1())), unsure(continuation), unsure(cellCase));
+ lastNext = m_out.appendTo(cellCase, checkExistingCase);
+ }
+
// We go to the inlined fast path if the object is UndecidedShape / NoIndexingShape for simplicity.
static_assert(!NonArray);
static_assert(ArrayClass == 1);
@@ -13332,18 +13342,56 @@
static_assert(NonArray <= ArrayWithUndecided);
static_assert(ArrayClass <= ArrayWithUndecided);
static_assert(ArrayWithUndecided <= ArrayWithUndecided);
- LValue indexingType = m_out.bitAnd(m_out.load8ZeroExt32(cell, m_heaps.JSCell_indexingTypeAndMisc), m_out.constInt32(IndexingTypeMask));
- m_out.branch(m_out.belowOrEqual(indexingType, m_out.constInt32(ArrayWithUndecided)), unsure(checkExistingCase), unsure(genericCase));
- LBasicBlock lastNext = m_out.appendTo(checkExistingCase, notNullCase);
- LValue structure = loadStructure(cell);
- LValue previousOrRareData = m_out.loadPtr(structure, m_heaps.Structure_previousOrRareData);
+ AbstractValue& baseValue = m_state.forNode(m_node->child1());
+ RegisteredStructure onlyStructure;
+ StructureRareData* rareData = nullptr;
+ bool skipIndexingMaskCheck = false;
+ if (baseValue.isType(SpecObject) && baseValue.m_structure.isFinite()) {
+ bool hasIndexing = false;
+ baseValue.m_structure.forEach([&] (RegisteredStructure structure) {
+ if (structure->indexingType() > ArrayWithUndecided)
+ hasIndexing = true;
+ });
+ if (!hasIndexing)
+ skipIndexingMaskCheck = true;
+ _onlyStructure_ = baseValue.m_structure.onlyStructure();
+ if (onlyStructure)
+ rareData = onlyStructure->tryRareData();
+ }
+
+ LValue notHavingIndexing = nullptr;
+ if (skipIndexingMaskCheck)
+ notHavingIndexing = m_out.booleanTrue;
+ else {
+ LValue indexingType = m_out.bitAnd(m_out.load8ZeroExt32(base, m_heaps.JSCell_indexingTypeAndMisc), m_out.constInt32(IndexingTypeMask));
+ notHavingIndexing = m_out.belowOrEqual(indexingType, m_out.constInt32(ArrayWithUndecided));
+ }
+ m_out.branch(notHavingIndexing, unsure(checkExistingCase), unsure(genericCase));
+
+ LBasicBlock lastNextCandidate = m_out.appendTo(checkExistingCase, notNullCase);
+ if (!lastNext)
+ lastNext = lastNextCandidate;
+ LValue previousOrRareData = nullptr;
+ if (rareData)
+ previousOrRareData = weakPointer(rareData);
+ else {
+ LValue structure = nullptr;
+ if (onlyStructure)
+ structure = weakStructure(onlyStructure);
+ else
+ structure = loadStructure(base);
+ previousOrRareData = m_out.loadPtr(structure, m_heaps.Structure_previousOrRareData);
+ }
m_out.branch(m_out.notNull(previousOrRareData), unsure(notNullCase), unsure(genericCase));
m_out.appendTo(notNullCase, rareDataCase);
- m_out.branch(
- m_out.notEqual(m_out.load32(previousOrRareData, m_heaps.JSCell_structureID), m_out.constInt32(m_graph.m_vm.structureStructure->structureID())),
- unsure(rareDataCase), unsure(genericCase));
+ LValue isRareData = nullptr;
+ if (rareData)
+ isRareData = m_out.booleanTrue;
+ else
+ isRareData = m_out.logicalNot(isCellWithType(previousOrRareData, StructureType, std::nullopt));
+ m_out.branch(isRareData, unsure(rareDataCase), unsure(genericCase));
m_out.appendTo(rareDataCase, validationCase);
LValue cached = m_out.loadPtr(previousOrRareData, m_heaps.StructureRareData_cachedPropertyNameEnumerator);
@@ -13350,15 +13398,15 @@
m_out.branch(m_out.notNull(cached), unsure(validationCase), unsure(genericCase));
m_out.appendTo(validationCase, genericCase);
- ValueFromBlock fastResult = m_out.anchor(cached);
+ results.append(m_out.anchor(cached));
m_out.branch(m_out.testNonZero32(m_out.load32(cached, m_heaps.JSPropertyNameEnumerator_flags), m_out.constInt32(JSPropertyNameEnumerator::ValidatedViaWatchpoint)), unsure(continuation), unsure(genericCase));
m_out.appendTo(genericCase, continuation);
- ValueFromBlock genericResult = m_out.anchor(vmCall(pointerType(), operationGetPropertyEnumeratorCell, weakPointer(globalObject), cell));
+ results.append(m_out.anchor(vmCall(pointerType(), operationGetPropertyEnumeratorCell, weakPointer(globalObject), base)));
m_out.jump(continuation);
m_out.appendTo(continuation, lastNext);
- setJSValue(m_out.phi(pointerType(), fastResult, genericResult));
+ setJSValue(m_out.phi(pointerType(), results));
return;
}
setJSValue(vmCall(Int64, operationGetPropertyEnumerator, weakPointer(globalObject), lowJSValue(m_node->child1())));
Modified: trunk/Source/_javascript_Core/jit/AssemblyHelpers.h (282238 => 282239)
--- trunk/Source/_javascript_Core/jit/AssemblyHelpers.h 2021-09-09 20:58:37 UTC (rev 282238)
+++ trunk/Source/_javascript_Core/jit/AssemblyHelpers.h 2021-09-09 21:36:38 UTC (rev 282239)
@@ -934,6 +934,8 @@
Jump branchIfNotHeapBigInt(GPRReg cellGPR) { return branchIfNotType(cellGPR, HeapBigIntType); }
Jump branchIfFunction(GPRReg cellGPR) { return branchIfType(cellGPR, JSFunctionType); }
Jump branchIfNotFunction(GPRReg cellGPR) { return branchIfNotType(cellGPR, JSFunctionType); }
+ Jump branchIfStructure(GPRReg cellGPR) { return branchIfType(cellGPR, StructureType); }
+ Jump branchIfNotStructure(GPRReg cellGPR) { return branchIfNotType(cellGPR, StructureType); }
void isEmpty(GPRReg gpr, GPRReg dst)
{
Modified: trunk/Source/_javascript_Core/jit/JIT.cpp (282238 => 282239)
--- trunk/Source/_javascript_Core/jit/JIT.cpp 2021-09-09 20:58:37 UTC (rev 282238)
+++ trunk/Source/_javascript_Core/jit/JIT.cpp 2021-09-09 21:36:38 UTC (rev 282239)
@@ -308,7 +308,6 @@
DEFINE_SLOW_OP(new_array_with_spread)
DEFINE_SLOW_OP(new_array_buffer)
DEFINE_SLOW_OP(spread)
- DEFINE_SLOW_OP(get_property_enumerator)
DEFINE_SLOW_OP(create_direct_arguments)
DEFINE_SLOW_OP(create_scoped_arguments)
DEFINE_SLOW_OP(create_cloned_arguments)
@@ -362,6 +361,7 @@
DEFINE_OP(op_get_by_id_with_this)
DEFINE_OP(op_get_by_id_direct)
DEFINE_OP(op_get_by_val)
+ DEFINE_OP(op_get_property_enumerator)
DEFINE_OP(op_enumerator_next)
DEFINE_OP(op_enumerator_get_by_val)
DEFINE_OP(op_enumerator_in_by_val)
Modified: trunk/Source/_javascript_Core/jit/JIT.h (282238 => 282239)
--- trunk/Source/_javascript_Core/jit/JIT.h 2021-09-09 20:58:37 UTC (rev 282238)
+++ trunk/Source/_javascript_Core/jit/JIT.h 2021-09-09 21:36:38 UTC (rev 282239)
@@ -545,6 +545,7 @@
template<typename OpcodeType>
void generateGetByValSlowCase(const OpcodeType&, Vector<SlowCaseEntry>::iterator&);
+ void emit_op_get_property_enumerator(const Instruction*);
void emit_op_enumerator_next(const Instruction*);
void emit_op_enumerator_get_by_val(const Instruction*);
void emitSlow_op_enumerator_get_by_val(const Instruction*, Vector<SlowCaseEntry>::iterator&);
Modified: trunk/Source/_javascript_Core/jit/JITPropertyAccess.cpp (282238 => 282239)
--- trunk/Source/_javascript_Core/jit/JITPropertyAccess.cpp 2021-09-09 20:58:37 UTC (rev 282238)
+++ trunk/Source/_javascript_Core/jit/JITPropertyAccess.cpp 2021-09-09 21:36:38 UTC (rev 282239)
@@ -2786,6 +2786,40 @@
template void JIT::emit_op_put_by_val<OpPutByVal>(const Instruction*);
+void JIT::emit_op_get_property_enumerator(const Instruction* currentInstruction)
+{
+ auto bytecode = currentInstruction->as<OpGetPropertyEnumerator>();
+
+ VirtualRegister base = bytecode.m_base;
+ VirtualRegister dst = bytecode.m_dst;
+
+ JumpList doneCases;
+ JumpList genericCases;
+
+ emitGetVirtualRegister(base, regT0);
+ genericCases.append(branchIfNotCell(regT0));
+ load8(Address(regT0, JSCell::indexingTypeAndMiscOffset()), regT1);
+ and32(TrustedImm32(IndexingTypeMask), regT1);
+ genericCases.append(branch32(Above, regT1, TrustedImm32(ArrayWithUndecided)));
+
+ emitLoadStructure(vm(), regT0, regT1, regT2);
+ loadPtr(Address(regT1, Structure::previousOrRareDataOffset()), regT1);
+ genericCases.append(branchTestPtr(Zero, regT1));
+ genericCases.append(branchIfStructure(regT1));
+ loadPtr(Address(regT1, StructureRareData::offsetOfCachedPropertyNameEnumerator()), regT1);
+
+ genericCases.append(branchTestPtr(Zero, regT1));
+ genericCases.append(branchTest32(Zero, Address(regT1, JSPropertyNameEnumerator::flagsOffset()), TrustedImm32(JSPropertyNameEnumerator::ValidatedViaWatchpoint)));
+ emitPutVirtualRegister(dst, regT1);
+ doneCases.append(jump());
+
+ genericCases.link(this);
+ JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_get_property_enumerator);
+ slowPathCall.call();
+
+ doneCases.link(this);
+}
+
void JIT::emit_op_enumerator_next(const Instruction* currentInstruction)
{
auto bytecode = currentInstruction->as<OpEnumeratorNext>();
Modified: trunk/Source/_javascript_Core/jit/JITPropertyAccess32_64.cpp (282238 => 282239)
--- trunk/Source/_javascript_Core/jit/JITPropertyAccess32_64.cpp 2021-09-09 20:58:37 UTC (rev 282238)
+++ trunk/Source/_javascript_Core/jit/JITPropertyAccess32_64.cpp 2021-09-09 21:36:38 UTC (rev 282239)
@@ -1385,6 +1385,12 @@
template void JIT::emit_op_put_by_val<OpPutByVal>(const Instruction*);
+void JIT::emit_op_get_property_enumerator(const Instruction* currentInstruction)
+{
+ JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_get_property_enumerator);
+ slowPathCall.call();
+}
+
void JIT::emit_op_enumerator_next(const Instruction* currentInstruction)
{
JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_enumerator_next);
Modified: trunk/Source/_javascript_Core/llint/LowLevelInterpreter.asm (282238 => 282239)
--- trunk/Source/_javascript_Core/llint/LowLevelInterpreter.asm 2021-09-09 20:58:37 UTC (rev 282238)
+++ trunk/Source/_javascript_Core/llint/LowLevelInterpreter.asm 2021-09-09 21:36:38 UTC (rev 282239)
@@ -525,6 +525,7 @@
# Constant for reasoning about butterflies.
const IsArray = constexpr IsArray
const IndexingShapeMask = constexpr IndexingShapeMask
+const IndexingTypeMask = constexpr IndexingTypeMask
const NoIndexingShape = constexpr NoIndexingShape
const Int32Shape = constexpr Int32Shape
const DoubleShape = constexpr DoubleShape
@@ -532,8 +533,10 @@
const ArrayStorageShape = constexpr ArrayStorageShape
const SlowPutArrayStorageShape = constexpr SlowPutArrayStorageShape
const CopyOnWrite = constexpr CopyOnWrite
+const ArrayWithUndecided = constexpr ArrayWithUndecided
# Type constants.
+const StructureType = constexpr StructureType
const StringType = constexpr StringType
const SymbolType = constexpr SymbolType
const ObjectType = constexpr ObjectType
@@ -2051,7 +2054,6 @@
slowPathOp(define_accessor_property)
slowPathOp(define_data_property)
slowPathOp(get_by_val_with_this)
-slowPathOp(get_property_enumerator)
if not JSVALUE64
slowPathOp(get_prototype_of)
Modified: trunk/Source/_javascript_Core/llint/LowLevelInterpreter32_64.asm (282238 => 282239)
--- trunk/Source/_javascript_Core/llint/LowLevelInterpreter32_64.asm 2021-09-09 20:58:37 UTC (rev 282238)
+++ trunk/Source/_javascript_Core/llint/LowLevelInterpreter32_64.asm 2021-09-09 21:36:38 UTC (rev 282239)
@@ -3079,6 +3079,7 @@
dispatch()
end)
+slowPathOp(get_property_enumerator)
slowPathOp(enumerator_next)
slowPathOp(enumerator_get_by_val)
slowPathOp(enumerator_in_by_val)
Modified: trunk/Source/_javascript_Core/llint/LowLevelInterpreter64.asm (282238 => 282239)
--- trunk/Source/_javascript_Core/llint/LowLevelInterpreter64.asm 2021-09-09 20:58:37 UTC (rev 282238)
+++ trunk/Source/_javascript_Core/llint/LowLevelInterpreter64.asm 2021-09-09 21:36:38 UTC (rev 282239)
@@ -3093,6 +3093,30 @@
dispatch()
end)
+llintOpWithReturn(op_get_property_enumerator, OpGetPropertyEnumerator, macro (size, get, dispatch, return)
+ get(m_base, t1)
+ loadConstantOrVariableCell(size, t1, t0, .slowPath)
+
+ loadb JSCell::m_indexingTypeAndMisc[t0], t1
+ andi IndexingTypeMask, t1
+ bia t1, ArrayWithUndecided, .slowPath
+
+ loadStructureWithScratch(t0, t1, t2, t3)
+ loadp Structure::m_previousOrRareData[t1], t1
+ btpz t1, .slowPath
+ bbeq JSCell::m_type[t1], StructureType, .slowPath
+
+ loadp StructureRareData::m_cachedPropertyNameEnumerator[t1], t1
+ btpz t1, .slowPath
+ btiz JSPropertyNameEnumerator::m_flags[t1], (constexpr JSPropertyNameEnumerator::ValidatedViaWatchpoint), .slowPath
+
+ return(t1)
+
+.slowPath:
+ callSlowPath(_slow_path_get_property_enumerator)
+ dispatch()
+end)
+
llintOp(op_enumerator_next, OpEnumeratorNext, macro (size, get, dispatch)
# Note: this will always call the slow path on at least the first/last execution of EnumeratorNext for any given loop.
# The upside this is that we don't have to record any metadata or mode information here as the slow path will do it for us when transitioning from InitMode/IndexedMode to OwnStructureMode, or from OwnStructureMode to GenericMode.
Modified: trunk/Source/_javascript_Core/runtime/BrandedStructure.cpp (282238 => 282239)
--- trunk/Source/_javascript_Core/runtime/BrandedStructure.cpp 2021-09-09 20:58:37 UTC (rev 282238)
+++ trunk/Source/_javascript_Core/runtime/BrandedStructure.cpp 2021-09-09 21:36:38 UTC (rev 282239)
@@ -53,6 +53,7 @@
ASSERT(vm.structureStructure);
BrandedStructure* newStructure = new (NotNull, allocateCell<BrandedStructure>(vm.heap)) BrandedStructure(vm, previous, brandUid, deferred);
newStructure->finishCreation(vm, previous);
+ ASSERT(newStructure->type() == StructureType);
return newStructure;
}
Modified: trunk/Source/_javascript_Core/runtime/JSType.cpp (282238 => 282239)
--- trunk/Source/_javascript_Core/runtime/JSType.cpp 2021-09-09 20:58:37 UTC (rev 282238)
+++ trunk/Source/_javascript_Core/runtime/JSType.cpp 2021-09-09 21:36:38 UTC (rev 282239)
@@ -39,6 +39,7 @@
{
switch (type) {
CASE(CellType)
+ CASE(StructureType)
CASE(StringType)
CASE(SymbolType)
CASE(HeapBigIntType)
Modified: trunk/Source/_javascript_Core/runtime/JSType.h (282238 => 282239)
--- trunk/Source/_javascript_Core/runtime/JSType.h 2021-09-09 20:58:37 UTC (rev 282238)
+++ trunk/Source/_javascript_Core/runtime/JSType.h 2021-09-09 21:36:38 UTC (rev 282239)
@@ -25,6 +25,7 @@
enum JSType : uint8_t {
// The CellType value must come before any JSType that is a JSCell.
CellType,
+ StructureType,
StringType,
HeapBigIntType,
LastMaybeFalsyCellPrimitive = HeapBigIntType,
Modified: trunk/Source/_javascript_Core/runtime/Structure.cpp (282238 => 282239)
--- trunk/Source/_javascript_Core/runtime/Structure.cpp 2021-09-09 20:58:37 UTC (rev 282238)
+++ trunk/Source/_javascript_Core/runtime/Structure.cpp 2021-09-09 21:36:38 UTC (rev 282239)
@@ -236,7 +236,7 @@
const ClassInfo Structure::s_info = { "Structure", nullptr, nullptr, nullptr, CREATE_METHOD_TABLE(Structure) };
-Structure::Structure(VM& vm)
+Structure::Structure(VM& vm, CreatingEarlyCellTag)
: JSCell(CreatingEarlyCell)
, m_inlineCapacity(0)
, m_bitField(0)
@@ -263,7 +263,7 @@
setTransitionOffset(vm, invalidOffset);
setMaxOffset(vm, invalidOffset);
- TypeInfo typeInfo = TypeInfo(CellType, StructureFlags);
+ TypeInfo typeInfo = TypeInfo(StructureType, StructureFlags);
m_blob = StructureIDBlob(vm.heap.structureIDTable().allocateID(this), 0, typeInfo);
m_outOfLineTypeFlags = typeInfo.outOfLineTypeFlags();
@@ -349,6 +349,7 @@
result->setMaxOffset(vm, newMaxOffset);
});
+ ASSERT(result->type() == StructureType);
return result;
}
Modified: trunk/Source/_javascript_Core/runtime/Structure.h (282238 => 282239)
--- trunk/Source/_javascript_Core/runtime/Structure.h 2021-09-09 20:58:37 UTC (rev 282238)
+++ trunk/Source/_javascript_Core/runtime/Structure.h 2021-09-09 21:36:38 UTC (rev 282239)
@@ -742,7 +742,7 @@
friend class LLIntOffsetsExtractor;
JS_EXPORT_PRIVATE Structure(VM&, JSGlobalObject*, JSValue prototype, const TypeInfo&, const ClassInfo*, IndexingType, unsigned inlineCapacity);
- Structure(VM&);
+ Structure(VM&, CreatingEarlyCellTag);
static Structure* create(VM&, Structure*, DeferredStructureTransitionWatchpointFire* = nullptr);
@@ -836,9 +836,9 @@
JS_EXPORT_PRIVATE void pin(const AbstractLocker&, VM&, PropertyTable*);
void pinForCaching(const AbstractLocker&, VM&, PropertyTable*);
- bool isRareData(JSCell* cell) const
+ static bool isRareData(JSCell* cell)
{
- return cell && cell->structureID() != structureID();
+ return cell && cell->type() != StructureType;
}
template<typename DetailsFunc>
Modified: trunk/Source/_javascript_Core/runtime/StructureInlines.h (282238 => 282239)
--- trunk/Source/_javascript_Core/runtime/StructureInlines.h 2021-09-09 20:58:37 UTC (rev 282238)
+++ trunk/Source/_javascript_Core/runtime/StructureInlines.h 2021-09-09 21:36:38 UTC (rev 282239)
@@ -62,6 +62,7 @@
Structure* structure = new (NotNull, allocateCell<Structure>(vm.heap)) Structure(vm, globalObject, prototype, typeInfo, classInfo, indexingModeIncludingHistory, inlineCapacity);
structure->finishCreation(vm);
+ ASSERT(structure->type() == StructureType);
return structure;
}
@@ -68,7 +69,7 @@
inline Structure* Structure::createStructure(VM& vm)
{
ASSERT(!vm.structureStructure);
- Structure* structure = new (NotNull, allocateCell<Structure>(vm.heap)) Structure(vm);
+ Structure* structure = new (NotNull, allocateCell<Structure>(vm.heap)) Structure(vm, CreatingEarlyCell);
structure->finishCreation(vm, CreatingEarlyCell);
return structure;
}
Modified: trunk/Source/_javascript_Core/runtime/StructureRareData.h (282238 => 282239)
--- trunk/Source/_javascript_Core/runtime/StructureRareData.h 2021-09-09 20:58:37 UTC (rev 282238)
+++ trunk/Source/_javascript_Core/runtime/StructureRareData.h 2021-09-09 21:36:38 UTC (rev 282239)
@@ -35,6 +35,7 @@
namespace JSC {
class JSPropertyNameEnumerator;
+class LLIntOffsetsExtractor;
class Structure;
class StructureChain;
class CachedSpecialPropertyAdaptiveStructureWatchpoint;
@@ -119,6 +120,7 @@
void invalidateWatchpointBasedValidation();
private:
+ friend class LLIntOffsetsExtractor;
friend class Structure;
friend class CachedSpecialPropertyAdaptiveStructureWatchpoint;
friend class CachedSpecialPropertyAdaptiveInferredPropertyValueWatchpoint;
Modified: trunk/Source/_javascript_Core/runtime/VM.cpp (282238 => 282239)
--- trunk/Source/_javascript_Core/runtime/VM.cpp 2021-09-09 20:58:37 UTC (rev 282238)
+++ trunk/Source/_javascript_Core/runtime/VM.cpp 2021-09-09 21:36:38 UTC (rev 282239)
@@ -486,6 +486,7 @@
if (Options::useJIT()) {
sentinelMapBucket();
sentinelSetBucket();
+ emptyPropertyNameEnumerator();
}
{
auto* bigInt = JSBigInt::tryCreateFrom(*this, 1);