Skip to content

Commit 613c428

Browse files
committed
[JSC] Optimize @regExpStringIteratorCreate in DFG/FTL
https://bugs.webkit.org/show_bug.cgi?id=298809 Reviewed by Yusuke Suzuki. This patch changes to optimize `@regExpStringIteratorCreate` in DFG/FTL. * JSTests/microbenchmarks/regexp-string-iterator.js: Added. (test): * JSTests/stress/regexp-string-iterator-jit.js: Added. (shouldBe): (test): * Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp: (JSC::DFG::ByteCodeParser::handleIntrinsicCall): * Source/JavaScriptCore/dfg/DFGObjectAllocationSinkingPhase.cpp: * Source/JavaScriptCore/dfg/DFGOperations.cpp: (JSC::DFG::JSC_DEFINE_JIT_OPERATION): * Source/JavaScriptCore/dfg/DFGOperations.h: * Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp: * Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp: (JSC::FTL::DFG::LowerDFGToB3::compileNewInternalFieldObject): * Source/JavaScriptCore/runtime/Intrinsic.h: * Source/JavaScriptCore/runtime/JSGlobalObject.cpp: (JSC::JSGlobalObject::init): (JSC::JSGlobalObject::visitChildrenImpl): * Source/JavaScriptCore/runtime/JSGlobalObject.h: (JSC::JSGlobalObject::regExpStringIteratorStructure const): Canonical link: https://commits.webkit.org/299943@main
1 parent c07db62 commit 613c428

File tree

11 files changed

+100
-9
lines changed

11 files changed

+100
-9
lines changed
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
function test(regexp, string) {
2+
return String.prototype.matchAll.call(string, regexp);
3+
}
4+
noInline(test);
5+
6+
const regexp = /test/g;
7+
const string = "test test test";
8+
9+
for (let i = 0; i < testLoopCount; i++) {
10+
test(regexp, string);
11+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
function shouldBe(a, b) {
2+
if (a !== b)
3+
throw new Error(`Expected ${b} but got ${a}`);
4+
}
5+
6+
function test(regexp, string) {
7+
const iterator = String.prototype.matchAll.call(string, regexp);
8+
let count = 0;
9+
for (const match of iterator) {
10+
count++;
11+
}
12+
return count;
13+
}
14+
noInline(test);
15+
16+
const globalRegexp = /t(e)(s)t/g;
17+
const testString = "test test test";
18+
19+
for (let i = 0; i < testLoopCount; i++) {
20+
const result = test(globalRegexp, testString);
21+
shouldBe(result, 3);
22+
}
23+
24+
const unicodeRegexp = /[\u{1F600}-\u{1F64F}]/gu;
25+
const emojiString = "Hello 😀 World 😃!";
26+
27+
for (let i = 0; i < testLoopCount; i++) {
28+
const result = test(unicodeRegexp, emojiString);
29+
shouldBe(result, 2);
30+
}
31+
32+
const emptyRegexp = /(?:)/g;
33+
const emptyTestString = "abc";
34+
35+
for (let i = 0; i < testLoopCount; i++) {
36+
const result = test(emptyRegexp, emptyTestString);
37+
shouldBe(result, 4);
38+
}

Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@
6565
#include "JSArrayIterator.h"
6666
#include "JSAsyncFromSyncIterator.h"
6767
#include "JSBoundFunction.h"
68+
#include "JSRegExpStringIterator.h"
6869
#include "JSCInlines.h"
6970
#include "JSCellButterfly.h"
7071
#include "JSInternalPromise.h"
@@ -4498,6 +4499,25 @@ auto ByteCodeParser::handleIntrinsicCall(Node* callee, Operand resultOperand, Ca
44984499
return CallOptimizationResult::Inlined;
44994500
}
45004501

4502+
case RegExpStringIteratorCreateIntrinsic: {
4503+
if (argumentCountIncludingThis < 5)
4504+
return CallOptimizationResult::DidNothing;
4505+
4506+
insertChecks();
4507+
JSGlobalObject* globalObject = m_graph.globalObjectFor(currentNodeOrigin().semantic);
4508+
Node* regExp = get(virtualRegisterForArgumentIncludingThis(1, registerOffset));
4509+
Node* string = get(virtualRegisterForArgumentIncludingThis(2, registerOffset));
4510+
Node* global = get(virtualRegisterForArgumentIncludingThis(3, registerOffset));
4511+
Node* fullUnicode = get(virtualRegisterForArgumentIncludingThis(4, registerOffset));
4512+
Node* regExpStringIterator = addToGraph(NewInternalFieldObject, OpInfo(m_graph.registerStructure(globalObject->regExpStringIteratorStructure())));
4513+
addToGraph(PutInternalField, OpInfo(static_cast<uint32_t>(JSRegExpStringIterator::Field::RegExp)), regExpStringIterator, regExp);
4514+
addToGraph(PutInternalField, OpInfo(static_cast<uint32_t>(JSRegExpStringIterator::Field::String)), regExpStringIterator, string);
4515+
addToGraph(PutInternalField, OpInfo(static_cast<uint32_t>(JSRegExpStringIterator::Field::Global)), regExpStringIterator, global);
4516+
addToGraph(PutInternalField, OpInfo(static_cast<uint32_t>(JSRegExpStringIterator::Field::FullUnicode)), regExpStringIterator, fullUnicode);
4517+
setResult(regExpStringIterator);
4518+
return CallOptimizationResult::Inlined;
4519+
}
4520+
45014521
default:
45024522
return CallOptimizationResult::DidNothing;
45034523
}

Source/JavaScriptCore/dfg/DFGObjectAllocationSinkingPhase.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
#include "JSInternalPromise.h"
4646
#include "JSIteratorHelper.h"
4747
#include "JSMapIterator.h"
48+
#include "JSRegExpStringIterator.h"
4849
#include "JSSetIterator.h"
4950
#include "JSWrapForValidIterator.h"
5051
#include "StructureInlines.h"
@@ -1145,6 +1146,9 @@ class ObjectAllocationSinkingPhase : public Phase {
11451146
case JSAsyncFromSyncIteratorType:
11461147
target = handleInternalFieldClass<JSAsyncFromSyncIterator>(node, writes);
11471148
break;
1149+
case JSRegExpStringIteratorType:
1150+
target = handleInternalFieldClass<JSRegExpStringIterator>(node, writes);
1151+
break;
11481152
case JSPromiseType:
11491153
if (node->structure()->classInfoForCells() == JSInternalPromise::info())
11501154
target = handleInternalFieldClass<JSInternalPromise>(node, writes);

Source/JavaScriptCore/dfg/DFGOperations.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@
6868
#include "JSMapIterator.h"
6969
#include "JSPromiseConstructor.h"
7070
#include "JSPropertyNameEnumerator.h"
71+
#include "JSRegExpStringIterator.h"
7172
#include "JSSet.h"
7273
#include "JSSetIterator.h"
7374
#include "JSWeakMapInlines.h"
@@ -2359,6 +2360,16 @@ JSC_DEFINE_JIT_OPERATION(operationNewAsyncFromSyncIterator, JSCell*, (VM* vmPoin
23592360
OPERATION_RETURN(scope, JSAsyncFromSyncIterator::createWithInitialValues(vm, structure));
23602361
}
23612362

2363+
JSC_DEFINE_JIT_OPERATION(operationNewRegExpStringIterator, JSCell*, (VM* vmPointer, Structure* structure))
2364+
{
2365+
VM& vm = *vmPointer;
2366+
CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
2367+
JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
2368+
auto scope = DECLARE_THROW_SCOPE(vm);
2369+
2370+
OPERATION_RETURN(scope, JSRegExpStringIterator::createWithInitialValues(vm, structure));
2371+
}
2372+
23622373
JSC_DEFINE_JIT_OPERATION(operationCreateActivationDirect, JSCell*, (VM* vmPointer, Structure* structure, JSScope* jsScope, SymbolTable* table, EncodedJSValue initialValueEncoded))
23632374
{
23642375
VM& vm = *vmPointer;

Source/JavaScriptCore/dfg/DFGOperations.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,7 @@ JSC_DECLARE_JIT_OPERATION(operationNewSetIterator, JSCell*, (VM*, Structure*));
176176
JSC_DECLARE_JIT_OPERATION(operationNewIteratorHelper, JSCell*, (VM*, Structure*));
177177
JSC_DECLARE_JIT_OPERATION(operationNewWrapForValidIterator, JSCell*, (VM*, Structure*));
178178
JSC_DECLARE_JIT_OPERATION(operationNewAsyncFromSyncIterator, JSCell*, (VM*, Structure*));
179+
JSC_DECLARE_JIT_OPERATION(operationNewRegExpStringIterator, JSCell*, (VM*, Structure*));
179180

180181
JSC_DECLARE_JIT_OPERATION(operationPutByValCellStringStrict, void, (JSGlobalObject*, JSCell*, JSCell* string, EncodedJSValue encodedValue));
181182
JSC_DECLARE_JIT_OPERATION(operationPutByValCellStringSloppy, void, (JSGlobalObject*, JSCell*, JSCell* string, EncodedJSValue encodedValue));

Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ WTF_ALLOW_UNSAFE_BUFFER_USAGE_BEGIN
6767
#include "JSLexicalEnvironment.h"
6868
#include "JSMapIterator.h"
6969
#include "JSPropertyNameEnumerator.h"
70+
#include "JSRegExpStringIterator.h"
7071
#include "JSSetIterator.h"
7172
#include "JSWebAssemblyInstance.h"
7273
#include "JSWrapForValidIterator.h"
@@ -15550,6 +15551,9 @@ void SpeculativeJIT::compileNewInternalFieldObject(Node* node)
1555015551
case JSAsyncFromSyncIteratorType:
1555115552
compileNewInternalFieldObjectImpl<JSAsyncFromSyncIterator>(node, operationNewAsyncFromSyncIterator);
1555215553
break;
15554+
case JSRegExpStringIteratorType:
15555+
compileNewInternalFieldObjectImpl<JSRegExpStringIterator>(node, operationNewRegExpStringIterator);
15556+
break;
1555315557
case JSPromiseType: {
1555415558
if (node->structure()->classInfoForCells() == JSInternalPromise::info())
1555515559
compileNewInternalFieldObjectImpl<JSInternalPromise>(node, operationNewInternalPromise);

Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@
9191
#include "JSIteratorHelper.h"
9292
#include "JSLexicalEnvironment.h"
9393
#include "JSMapIterator.h"
94+
#include "JSRegExpStringIterator.h"
9495
#include "JSSetIterator.h"
9596
#include "JSWebAssemblyInstance.h"
9697
#include "JSWrapForValidIterator.h"
@@ -9396,6 +9397,9 @@ IGNORE_CLANG_WARNINGS_END
93969397
case JSAsyncFromSyncIteratorType:
93979398
compileNewInternalFieldObjectImpl<JSAsyncFromSyncIterator>(operationNewAsyncFromSyncIterator);
93989399
break;
9400+
case JSRegExpStringIteratorType:
9401+
compileNewInternalFieldObjectImpl<JSRegExpStringIterator>(operationNewRegExpStringIterator);
9402+
break;
93999403
case JSPromiseType:
94009404
if (m_node->structure()->classInfoForCells() == JSInternalPromise::info())
94019405
compileNewInternalFieldObjectImpl<JSInternalPromise>(operationNewInternalPromise);

Source/JavaScriptCore/runtime/Intrinsic.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,7 @@ namespace JSC {
198198
macro(IteratorHelperCreateIntrinsic) \
199199
macro(WrapForValidIteratorCreateIntrinsic) \
200200
macro(AsyncFromSyncIteratorCreateIntrinsic) \
201+
macro(RegExpStringIteratorCreateIntrinsic) \
201202
\
202203
/* Getter intrinsics. */ \
203204
macro(TypedArrayLengthIntrinsic) \

Source/JavaScriptCore/runtime/JSGlobalObject.cpp

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1202,11 +1202,8 @@ void JSGlobalObject::init(VM& vm)
12021202
auto* asyncFromSyncIteratorPrototype = AsyncFromSyncIteratorPrototype::create(vm, this, AsyncFromSyncIteratorPrototype::createStructure(vm, this, m_iteratorPrototype.get()));
12031203
m_asyncFromSyncIteratorStructure.set(vm, this, JSAsyncFromSyncIterator::createStructure(vm, this, asyncFromSyncIteratorPrototype));
12041204

1205-
m_regExpStringIteratorStructure.initLater(
1206-
[] (const Initializer<Structure>& init) {
1207-
auto* regExpStringIteratorPrototype = RegExpStringIteratorPrototype::create(init.vm, init.owner, RegExpStringIteratorPrototype::createStructure(init.vm, init.owner, init.owner->m_iteratorPrototype.get()));
1208-
init.set(JSRegExpStringIterator::createStructure(init.vm, init.owner, regExpStringIteratorPrototype));
1209-
});
1205+
auto* regExpStringIteratorPrototype = RegExpStringIteratorPrototype::create(vm, this, RegExpStringIteratorPrototype::createStructure(vm, this, m_iteratorPrototype.get()));
1206+
m_regExpStringIteratorStructure.set(vm, this, JSRegExpStringIterator::createStructure(vm, this, regExpStringIteratorPrototype));
12101207

12111208
m_linkTimeConstants[static_cast<unsigned>(LinkTimeConstant::sentinelString)].set(vm, this, vm.smallStrings.sentinelString());
12121209

@@ -1606,7 +1603,7 @@ capitalName ## Constructor* lowerName ## Constructor = featureFlag ? capitalName
16061603

16071604
// RegExpStringIteratorHelpers
16081605
m_linkTimeConstants[static_cast<unsigned>(LinkTimeConstant::regExpStringIteratorCreate)].initLater([](const Initializer<JSCell>& init) {
1609-
init.set(JSFunction::create(init.vm, jsCast<JSGlobalObject*>(init.owner), 0, "regExpStringIteratorCreate"_s, regExpStringIteratorPrivateFuncCreate, ImplementationVisibility::Private));
1606+
init.set(JSFunction::create(init.vm, jsCast<JSGlobalObject*>(init.owner), 4, "regExpStringIteratorCreate"_s, regExpStringIteratorPrivateFuncCreate, ImplementationVisibility::Private, RegExpStringIteratorCreateIntrinsic));
16101607
});
16111608

16121609
// WrapForValidIterator Helpers
@@ -2719,7 +2716,7 @@ void JSGlobalObject::visitChildrenImpl(JSCell* cell, Visitor& visitor)
27192716
visitor.append(thisObject->m_setIteratorStructure);
27202717
visitor.append(thisObject->m_wrapForValidIteratorStructure);
27212718
visitor.append(thisObject->m_asyncFromSyncIteratorStructure);
2722-
thisObject->m_regExpStringIteratorStructure.visit(visitor);
2719+
visitor.append(thisObject->m_regExpStringIteratorStructure);
27232720
thisObject->m_iteratorResultObjectStructure.visit(visitor);
27242721
thisObject->m_dataPropertyDescriptorObjectStructure.visit(visitor);
27252722
thisObject->m_accessorPropertyDescriptorObjectStructure.visit(visitor);

0 commit comments

Comments
 (0)