Skip to content

Commit d4c4d4b

Browse files
committed
[JSC] Add Array::OriginalArray DFG::ArrayMode, which can handle both CoW array and non-CoW array
https://bugs.webkit.org/show_bug.cgi?id=272259 rdar://125997646 Reviewed by Alexey Shvayka. This extends DFG::ArrayMode and introduces OriginalArray. And we rename old OriginalArray to OriginalNonCopyOnWriteArray. OriginalArray can handle both CoW and non-CoW original arrays. The purpose of this is telling DFG / FTL that we still see original arrays. This allows some of optimizations because it makes clobberising rules more precise. * Source/JavaScriptCore/bytecode/StructureSet.h: * Source/JavaScriptCore/dfg/DFGArrayMode.cpp: (JSC::DFG::ArrayMode::originalArrayStructures const): (JSC::DFG::ArrayMode::alreadyChecked const): (JSC::DFG::arrayClassToString): (JSC::DFG::ArrayMode::originalArrayStructure const): Deleted. * Source/JavaScriptCore/dfg/DFGArrayMode.h: (JSC::DFG::ArrayMode::withProfile const): (JSC::DFG::ArrayMode::isJSArray const): (JSC::DFG::ArrayMode::isJSArrayWithOriginalStructure const): (JSC::DFG::ArrayMode::arrayModesWithIndexingShapes const): * Source/JavaScriptCore/dfg/DFGFixupPhase.cpp: (JSC::DFG::FixupPhase::checkArray): * Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp: (JSC::DFG::SpeculativeJIT::jumpSlowForUnwantedArrayMode): * Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp: (JSC::FTL::DFG::LowerDFGToB3::compileCompareStrictEq): Canonical link: https://commits.webkit.org/277174@main
1 parent 5e4d30e commit d4c4d4b

6 files changed

Lines changed: 107 additions & 56 deletions

File tree

‎Source/JavaScriptCore/bytecode/StructureSet.h‎

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,16 +39,14 @@ class StructureSet : public TinyPtrSet<Structure*> {
3939
// using TinyPtrSet::TinyPtrSet;
4040
//
4141
// But I can't because Windows.
42-
43-
StructureSet()
44-
{
45-
}
46-
42+
43+
StructureSet() = default;
44+
4745
StructureSet(Structure* structure)
4846
: TinyPtrSet(structure)
4947
{
5048
}
51-
49+
5250
Structure* onlyStructure() const
5351
{
5452
return onlyEntry();

‎Source/JavaScriptCore/dfg/DFGArrayMode.cpp‎

Lines changed: 76 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -364,63 +364,94 @@ ArrayMode ArrayMode::refine(
364364
}
365365
}
366366

367-
Structure* ArrayMode::originalArrayStructure(Graph& graph, const CodeOrigin& codeOrigin) const
367+
StructureSet ArrayMode::originalArrayStructures(Graph& graph, const CodeOrigin& codeOrigin) const
368368
{
369369
JSGlobalObject* globalObject = graph.globalObjectFor(codeOrigin);
370-
371-
switch (arrayClass()) {
372-
case Array::OriginalCopyOnWriteArray: {
373-
if (conversion() == Array::AsIs) {
374-
switch (type()) {
375-
case Array::Int32:
376-
return globalObject->originalArrayStructureForIndexingType(CopyOnWriteArrayWithInt32);
377-
case Array::Double:
378-
return globalObject->originalArrayStructureForIndexingType(CopyOnWriteArrayWithDouble);
379-
case Array::Contiguous:
380-
return globalObject->originalArrayStructureForIndexingType(CopyOnWriteArrayWithContiguous);
381-
default:
382-
CRASH();
383-
return nullptr;
384-
}
385-
}
386-
FALLTHROUGH;
387-
}
388370

389-
case Array::OriginalArray: {
371+
auto addNonCopyOnWriteStructures = [&](StructureSet& set) {
390372
switch (type()) {
391373
case Array::Int32:
392-
return globalObject->originalArrayStructureForIndexingType(ArrayWithInt32);
374+
set.add(globalObject->originalArrayStructureForIndexingType(ArrayWithInt32));
375+
return;
393376
case Array::Double:
394-
return globalObject->originalArrayStructureForIndexingType(ArrayWithDouble);
377+
set.add(globalObject->originalArrayStructureForIndexingType(ArrayWithDouble));
378+
return;
395379
case Array::Contiguous:
396-
return globalObject->originalArrayStructureForIndexingType(ArrayWithContiguous);
380+
set.add(globalObject->originalArrayStructureForIndexingType(ArrayWithContiguous));
381+
return;
397382
case Array::Undecided:
398-
return globalObject->originalArrayStructureForIndexingType(ArrayWithUndecided);
383+
set.add(globalObject->originalArrayStructureForIndexingType(ArrayWithUndecided));
384+
return;
399385
case Array::ArrayStorage:
400-
return globalObject->originalArrayStructureForIndexingType(ArrayWithArrayStorage);
386+
set.add(globalObject->originalArrayStructureForIndexingType(ArrayWithArrayStorage));
387+
return;
401388
default:
402389
CRASH();
403-
return nullptr;
390+
return;
404391
}
392+
};
393+
394+
auto addCopyOnWriteStructures = [&](StructureSet& set) {
395+
switch (type()) {
396+
case Array::Int32:
397+
set.add(globalObject->originalArrayStructureForIndexingType(CopyOnWriteArrayWithInt32));
398+
return;
399+
case Array::Double:
400+
set.add(globalObject->originalArrayStructureForIndexingType(CopyOnWriteArrayWithDouble));
401+
return;
402+
case Array::Contiguous:
403+
set.add(globalObject->originalArrayStructureForIndexingType(CopyOnWriteArrayWithContiguous));
404+
return;
405+
default:
406+
return;
407+
}
408+
};
409+
410+
switch (arrayClass()) {
411+
case Array::OriginalArray: {
412+
StructureSet set;
413+
if (conversion() == Array::AsIs) {
414+
addCopyOnWriteStructures(set);
415+
addNonCopyOnWriteStructures(set);
416+
return set;
417+
}
418+
addNonCopyOnWriteStructures(set);
419+
return set;
405420
}
406-
421+
422+
case Array::OriginalCopyOnWriteArray: {
423+
StructureSet set;
424+
if (conversion() == Array::AsIs) {
425+
addCopyOnWriteStructures(set);
426+
return set;
427+
}
428+
addNonCopyOnWriteStructures(set);
429+
return set;
430+
}
431+
432+
case Array::OriginalNonCopyOnWriteArray: {
433+
StructureSet set;
434+
addNonCopyOnWriteStructures(set);
435+
return set;
436+
}
437+
407438
case Array::OriginalNonArray: {
408439
TypedArrayType type = typedArrayType();
409440
if (type == NotTypedArray)
410-
return nullptr;
441+
return { };
411442

412443
bool isResizableOrGrowableShared = false;
413-
return globalObject->typedArrayStructureConcurrently(type, isResizableOrGrowableShared);
444+
return { globalObject->typedArrayStructureConcurrently(type, isResizableOrGrowableShared) };
414445
}
415-
446+
416447
default:
417-
return nullptr;
448+
return { };
418449
}
419450
}
420451

421-
Structure* ArrayMode::originalArrayStructure(Graph& graph, Node* node) const
452+
StructureSet ArrayMode::originalArrayStructures(Graph& graph, Node* node) const
422453
{
423-
return originalArrayStructure(graph, node->origin.semantic);
454+
return originalArrayStructures(graph, node->origin.semantic);
424455
}
425456

426457
bool ArrayMode::alreadyChecked(Graph& graph, Node* node, const AbstractValue& value, IndexingType shape) const
@@ -474,16 +505,21 @@ bool ArrayMode::alreadyChecked(Graph& graph, Node* node, const AbstractValue& va
474505
return true;
475506
}
476507

477-
// If ArrayMode is Array::OriginalCopyOnWriteArray or Array::OriginalArray, CheckArray is never emitted. Instead, we always emit CheckStructure.
508+
// If ArrayMode is Array::OriginalArray, Array::OriginalCopyOnWriteArray, or Array::OriginalNonCopyOnWriteArray, CheckArray is never emitted. Instead, we always emit CheckStructure.
478509
// So, we should perform the same check to the CheckStructure here.
479510
case Array::OriginalArray:
511+
case Array::OriginalNonCopyOnWriteArray:
480512
case Array::OriginalCopyOnWriteArray: {
481513
if (!value.m_structure.isFinite())
482514
return false;
483-
Structure* originalStructure = originalArrayStructure(graph, node);
484-
if (value.m_structure.size() != 1)
515+
if (!value.m_structure.size())
485516
return false;
486-
return value.m_structure.onlyStructure().get() == originalStructure;
517+
auto originalStructures = originalArrayStructures(graph, node);
518+
bool pass = true;
519+
value.m_structure.forEach([&](auto structure) {
520+
pass &= originalStructures.contains(structure.get());
521+
});
522+
return pass;
487523
}
488524
}
489525
return false;
@@ -519,6 +555,7 @@ bool ArrayMode::alreadyChecked(Graph& graph, Node* node, const AbstractValue& va
519555
case Array::SlowPutArrayStorage:
520556
switch (arrayClass()) {
521557
case Array::OriginalArray:
558+
case Array::OriginalNonCopyOnWriteArray:
522559
case Array::OriginalCopyOnWriteArray: {
523560
CRASH();
524561
return false;
@@ -708,6 +745,8 @@ const char* arrayClassToString(Array::Class arrayClass)
708745
return "Array";
709746
case Array::OriginalArray:
710747
return "OriginalArray";
748+
case Array::OriginalNonCopyOnWriteArray:
749+
return "OriginalNonCopyOnWriteArray";
711750
case Array::OriginalCopyOnWriteArray:
712751
return "OriginalCopyOnWriteArray";
713752
case Array::NonArray:

‎Source/JavaScriptCore/dfg/DFGArrayMode.h‎

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929

3030
#include "ArrayProfile.h"
3131
#include "SpeculatedType.h"
32+
#include "StructureSet.h"
3233

3334
namespace JSC {
3435

@@ -85,7 +86,8 @@ enum Class : uint8_t {
8586
NonArray, // Definitely some object that is not a JSArray.
8687
OriginalNonArray, // Definitely some object that is not a JSArray, but that object has the original structure.
8788
Array, // Definitely a JSArray, and may or may not have custom properties or have undergone some other bizarre transitions.
88-
OriginalArray, // Definitely a JSArray, and still has one of the primordial JSArray structures for the global object that this code block (possibly inlined code block) belongs to.
89+
OriginalArray, // Definitely a JSArray, and still has one of the primordial JSArray structures and/or copy on write structures for the global object that this code block (possibly inlined code block) belongs to.
90+
OriginalNonCopyOnWriteArray, // Definitely a JSArray, and still has one of the primordial JSArray structures for the global object that this code block (possibly inlined code block) belongs to.
8991
OriginalCopyOnWriteArray, // Definitely a copy on write JSArray, and still has one of the primordial JSArray copy on write structures for the global object that this code block (possibly inlined code block) belongs to.
9092
PossiblyArray // Some object that may or may not be a JSArray.
9193
};
@@ -241,9 +243,9 @@ class ArrayMode {
241243
if (hasSeenCopyOnWriteArray(arrayModes) && !hasSeenWritableArray(arrayModes))
242244
myArrayClass = Array::OriginalCopyOnWriteArray;
243245
else if (!hasSeenCopyOnWriteArray(arrayModes) && hasSeenWritableArray(arrayModes))
244-
myArrayClass = Array::OriginalArray;
246+
myArrayClass = Array::OriginalNonCopyOnWriteArray;
245247
else
246-
myArrayClass = Array::Array;
248+
myArrayClass = Array::OriginalArray;
247249
} else
248250
myArrayClass = Array::Array;
249251
} else
@@ -283,6 +285,7 @@ class ArrayMode {
283285
switch (arrayClass()) {
284286
case Array::Array:
285287
case Array::OriginalArray:
288+
case Array::OriginalNonCopyOnWriteArray:
286289
case Array::OriginalCopyOnWriteArray:
287290
return true;
288291
default:
@@ -292,7 +295,14 @@ class ArrayMode {
292295

293296
bool isJSArrayWithOriginalStructure() const
294297
{
295-
return arrayClass() == Array::OriginalArray || arrayClass() == Array::OriginalCopyOnWriteArray;
298+
switch (arrayClass()) {
299+
case Array::OriginalArray:
300+
case Array::OriginalNonCopyOnWriteArray:
301+
case Array::OriginalCopyOnWriteArray:
302+
return true;
303+
default:
304+
return false;
305+
}
296306
}
297307

298308
bool isInBoundsSaneChain() const
@@ -446,9 +456,8 @@ class ArrayMode {
446456
}
447457
}
448458

449-
// Returns 0 if this is not OriginalArray.
450-
Structure* originalArrayStructure(Graph&, const CodeOrigin&) const;
451-
Structure* originalArrayStructure(Graph&, Node*) const;
459+
StructureSet originalArrayStructures(Graph&, const CodeOrigin&) const;
460+
StructureSet originalArrayStructures(Graph&, Node*) const;
452461

453462
bool doesConversion() const
454463
{
@@ -562,11 +571,12 @@ class ArrayMode {
562571
case Array::OriginalCopyOnWriteArray:
563572
ASSERT(hasInt32(shape) || hasDouble(shape) || hasContiguous(shape));
564573
return asArrayModesIgnoringTypedArrays(shape | IsArray) | asArrayModesIgnoringTypedArrays(shape | IsArray | CopyOnWrite);
574+
case Array::OriginalArray:
565575
case Array::Array:
566576
if (hasInt32(shape) || hasDouble(shape) || hasContiguous(shape))
567577
return asArrayModesIgnoringTypedArrays(shape | IsArray) | asArrayModesIgnoringTypedArrays(shape | IsArray | CopyOnWrite);
568578
FALLTHROUGH;
569-
case Array::OriginalArray:
579+
case Array::OriginalNonCopyOnWriteArray:
570580
return asArrayModesIgnoringTypedArrays(shape | IsArray);
571581
case Array::PossiblyArray:
572582
if (hasInt32(shape) || hasDouble(shape) || hasContiguous(shape))

‎Source/JavaScriptCore/dfg/DFGFixupPhase.cpp‎

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4061,25 +4061,25 @@ class FixupPhase : public Phase {
40614061
} else {
40624062
// Note that we only need to be using a structure check if we opt for InBoundsSaneChain, since
40634063
// that needs to protect against JSArray's __proto__ being changed.
4064-
Structure* structure = arrayMode.originalArrayStructure(m_graph, origin.semantic);
4064+
auto structures = arrayMode.originalArrayStructures(m_graph, origin.semantic);
40654065

40664066
Edge indexEdge = index ? Edge(index, Int32Use) : Edge();
40674067

40684068
if (arrayMode.doesConversion()) {
4069-
if (structure) {
4069+
if (!structures.isEmpty() && structures.size() == 1) {
40704070
m_insertionSet.insertNode(
40714071
m_indexInBlock, SpecNone, ArrayifyToStructure, origin,
4072-
OpInfo(m_graph.registerStructure(structure)), OpInfo(arrayMode.asWord()), Edge(array, CellUse), indexEdge);
4072+
OpInfo(m_graph.registerStructure(structures.onlyStructure())), OpInfo(arrayMode.asWord()), Edge(array, CellUse), indexEdge);
40734073
} else {
40744074
m_insertionSet.insertNode(
40754075
m_indexInBlock, SpecNone, Arrayify, origin,
40764076
OpInfo(arrayMode.asWord()), Edge(array, CellUse), indexEdge);
40774077
}
40784078
} else {
4079-
if (structure) {
4079+
if (!structures.isEmpty()) {
40804080
m_insertionSet.insertNode(
40814081
m_indexInBlock, SpecNone, CheckStructure, origin,
4082-
OpInfo(m_graph.addStructureSet(structure)), Edge(array, CellUse));
4082+
OpInfo(m_graph.addStructureSet(structures)), Edge(array, CellUse));
40834083
} else {
40844084
m_insertionSet.insertNode(
40854085
m_indexInBlock, SpecNone, CheckArray, origin,

‎Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1016,6 +1016,7 @@ JITCompiler::JumpList SpeculativeJIT::jumpSlowForUnwantedArrayMode(GPRReg tempGP
10161016
IndexingType shape = arrayMode.shapeMask();
10171017
switch (arrayMode.arrayClass()) {
10181018
case Array::OriginalArray:
1019+
case Array::OriginalNonCopyOnWriteArray:
10191020
case Array::OriginalCopyOnWriteArray:
10201021
RELEASE_ASSERT_NOT_REACHED();
10211022
return result;
@@ -1048,6 +1049,7 @@ JITCompiler::JumpList SpeculativeJIT::jumpSlowForUnwantedArrayMode(GPRReg tempGP
10481049

10491050
switch (arrayMode.arrayClass()) {
10501051
case Array::OriginalArray:
1052+
case Array::OriginalNonCopyOnWriteArray:
10511053
case Array::OriginalCopyOnWriteArray:
10521054
RELEASE_ASSERT_NOT_REACHED();
10531055
return result;

‎Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21862,6 +21862,7 @@ IGNORE_CLANG_WARNINGS_END
2186221862

2186321863
switch (arrayMode.arrayClass()) {
2186421864
case Array::OriginalArray:
21865+
case Array::OriginalNonCopyOnWriteArray:
2186521866
case Array::OriginalCopyOnWriteArray:
2186621867
DFG_CRASH(m_graph, m_node, "Unexpected original array");
2186721868
return nullptr;
@@ -21904,6 +21905,7 @@ IGNORE_CLANG_WARNINGS_END
2190421905
LBasicBlock lastNext = m_out.appendTo(checkCase, trueCase);
2190521906
switch (arrayMode.arrayClass()) {
2190621907
case Array::OriginalArray:
21908+
case Array::OriginalNonCopyOnWriteArray:
2190721909
case Array::OriginalCopyOnWriteArray:
2190821910
DFG_CRASH(m_graph, m_node, "Unexpected original array");
2190921911
return nullptr;

0 commit comments

Comments
 (0)