Skip to content

Commit

Permalink
Cherry-pick a36c251. rdar://122674588
Browse files Browse the repository at this point in the history
    [JSC] Spew strict-eq Baseline JIT code with constant strings
    https://bugs.webkit.org/show_bug.cgi?id=269106
    rdar://122674588

    Reviewed by Alexey Shvayka.

    Let's leverage the fact that there are many `"string" === x` comparisons.
    In that case, we can emit very specific optimized code even in Baseline JIT easily.
    This patch adds `StringIdent === x` case optimizations in Baseline JIT.

    Furthermore, we found that

    ```
        switch (expr) {
        case "string1":
            ...
        case "string2":
            ...
        case variable:
            ...
        }
    ```

    case is emitting very inefficient bytecode, which does not use constant register directly with `jstricteq`.
    As a result, my new optimization does not kick in with this. This patch also fixes BytecodeGenerator to make
    this new optimization work well by emitting `jstricteq constant, x`.

    * Source/JavaScriptCore/jit/JITOpcodes.cpp:
    (JSC::JIT::compileOpStrictEq):
    (JSC::JIT::compileOpStrictEqJump):

    Canonical link: https://commits.webkit.org/274418@main

Identifier: 272448.534@safari-7618-branch
  • Loading branch information
Constellation authored and Dan Robson committed Feb 12, 2024
1 parent 2988b6f commit 742e383
Show file tree
Hide file tree
Showing 2 changed files with 101 additions and 4 deletions.
6 changes: 2 additions & 4 deletions Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4710,16 +4710,14 @@ void CaseBlockNode::emitBytecodeForBlock(BytecodeGenerator& generator, RegisterI
} else {
// Setup jumps
for (ClauseListNode* list = m_list1; list; list = list->getNext()) {
RefPtr<RegisterID> clauseVal = generator.newTemporary();
generator.emitNode(clauseVal.get(), list->getClause()->expr());
RefPtr<RegisterID> clauseVal = generator.emitNode(list->getClause()->expr());
Ref<Label> clauseLabel = generator.newLabel();
labelVector.append(clauseLabel);
generator.emitJumpIfTrue(generator.emitEqualityOp<OpStricteq>(generator.newTemporary(), clauseVal.get(), switchExpression), clauseLabel.get());
}

for (ClauseListNode* list = m_list2; list; list = list->getNext()) {
RefPtr<RegisterID> clauseVal = generator.newTemporary();
generator.emitNode(clauseVal.get(), list->getClause()->expr());
RefPtr<RegisterID> clauseVal = generator.emitNode(list->getClause()->expr());
Ref<Label> clauseLabel = generator.newLabel();
labelVector.append(clauseLabel);
generator.emitJumpIfTrue(generator.emitEqualityOp<OpStricteq>(generator.newTemporary(), clauseVal.get(), switchExpression), clauseLabel.get());
Expand Down
99 changes: 99 additions & 0 deletions Source/JavaScriptCore/jit/JITOpcodes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -760,6 +760,54 @@ void JIT::compileOpStrictEq(const JSInstruction* currentInstruction)
emitGetVirtualRegister(src1, regT0);
emitGetVirtualRegister(src2, regT1);

auto tryGetAtomStringConstant = [&](VirtualRegister src) -> JSString* {
if (!src.isConstant())
return nullptr;
if (!m_profiledCodeBlock->isConstantOwnedByUnlinkedCodeBlock(src))
return nullptr;
JSValue value = m_unlinkedCodeBlock->getConstant(src);
if (!value.isString())
return nullptr;
JSString* string = asString(value);
auto* impl = string->tryGetValueImpl();
if (!impl)
return nullptr;
if (!impl->isAtom())
return nullptr;
return string;
};

auto emitStringConstantFastPath = [&](GPRReg stringGPR, GPRReg knownStringGPR, JSString* string) {
JumpList fallThrough;
JumpList equals;
moveTrustedValue(jsBoolean(!std::is_same_v<Op, OpStricteq>), jsRegT32);

equals.append(branch64(Equal, stringGPR, knownStringGPR));
fallThrough.append(branchIfNotCell(stringGPR));

fallThrough.append(branchIfNotString(stringGPR));
loadPtr(Address(stringGPR, JSString::offsetOfValue()), regT5);
addSlowCase(branchIfRopeStringImpl(regT5));
addSlowCase(branchTest32(Zero, Address(regT5, StringImpl::flagsOffset()), TrustedImm32(StringImpl::flagIsAtom())));
fallThrough.append(branchPtr(NotEqual, regT5, TrustedImmPtr(string->tryGetValueImpl())));

equals.link(this);
moveTrustedValue(jsBoolean(std::is_same_v<Op, OpStricteq>), jsRegT32);

fallThrough.link(this);
emitPutVirtualRegister(dst, jsRegT32);
};

if (auto* string = tryGetAtomStringConstant(src1)) {
emitStringConstantFastPath(regT1, regT0, string);
return;
}

if (auto* string = tryGetAtomStringConstant(src2)) {
emitStringConstantFastPath(regT0, regT1, string);
return;
}

#if USE(BIGINT32)
/* At a high level we do (assuming 'type' to be StrictEq):
If (left is Double || right is Double)
Expand Down Expand Up @@ -846,6 +894,57 @@ void JIT::compileOpStrictEqJump(const JSInstruction* currentInstruction)
emitGetVirtualRegister(src1, regT0);
emitGetVirtualRegister(src2, regT1);

auto tryGetAtomStringConstant = [&](VirtualRegister src) -> JSString* {
if (!src.isConstant())
return nullptr;
if (!m_profiledCodeBlock->isConstantOwnedByUnlinkedCodeBlock(src))
return nullptr;
JSValue value = m_unlinkedCodeBlock->getConstant(src);
if (!value.isString())
return nullptr;
JSString* string = asString(value);
auto* impl = string->tryGetValueImpl();
if (!impl)
return nullptr;
if (!impl->isAtom())
return nullptr;
return string;
};

auto emitStringConstantFastPath = [&](GPRReg stringGPR, GPRReg knownStringGPR, JSString* string) {
JumpList fallThrough;
if constexpr (std::is_same_v<Op, OpJstricteq>) {
addJump(branch64(Equal, stringGPR, knownStringGPR), target);
fallThrough.append(branchIfNotCell(stringGPR));

fallThrough.append(branchIfNotString(stringGPR));
loadPtr(Address(stringGPR, JSString::offsetOfValue()), regT2);
addSlowCase(branchIfRopeStringImpl(regT2));
addSlowCase(branchTest32(Zero, Address(regT2, StringImpl::flagsOffset()), TrustedImm32(StringImpl::flagIsAtom())));
addJump(branchPtr(Equal, regT2, TrustedImmPtr(string->tryGetValueImpl())), target);
} else {
fallThrough.append(branch64(Equal, stringGPR, knownStringGPR));
addJump(branchIfNotCell(stringGPR), target);

addJump(branchIfNotString(stringGPR), target);
loadPtr(Address(stringGPR, JSString::offsetOfValue()), regT2);
addSlowCase(branchIfRopeStringImpl(regT2));
addSlowCase(branchTest32(Zero, Address(regT2, StringImpl::flagsOffset()), TrustedImm32(StringImpl::flagIsAtom())));
addJump(branchPtr(NotEqual, regT2, TrustedImmPtr(string->tryGetValueImpl())), target);
}
fallThrough.link(this);
};

if (auto* string = tryGetAtomStringConstant(src1)) {
emitStringConstantFastPath(regT1, regT0, string);
return;
}

if (auto* string = tryGetAtomStringConstant(src2)) {
emitStringConstantFastPath(regT0, regT1, string);
return;
}

#if USE(BIGINT32)
/* At a high level we do (assuming 'type' to be StrictEq):
If (left is Double || right is Double)
Expand Down

0 comments on commit 742e383

Please sign in to comment.