Skip to content

Commit 04bcc9f

Browse files
committed
[LOL] Add remaining jump bytecodes
https://bugs.webkit.org/show_bug.cgi?id=306589 rdar://169232660 Reviewed by Yusuke Suzuki. Add the remaining jump bytecodes. Mostly just a direct translation. Also, added some jitAsserts for op_jbelow(eq) to to Baseline as well as JIT_COMMENTS to the various jitAssert functions too. No new tests, no behavior changes. Covered by existing tests. Canonical link: https://commits.webkit.org/306564@main
1 parent 9572c36 commit 04bcc9f

5 files changed

Lines changed: 369 additions & 0 deletions

File tree

‎Source/JavaScriptCore/jit/AssemblyHelpers.cpp‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ void AssemblyHelpers::jitAssertIsInt32(GPRReg gpr)
119119
if (!Options::useJITAsserts())
120120
return;
121121
#if CPU(X86_64) || CPU(ARM64)
122+
JIT_COMMENT(*this, "ASSERT is unboxed int32");
122123
Jump checkInt32 = branch64(BelowOrEqual, gpr, TrustedImm64(static_cast<uintptr_t>(0xFFFFFFFFu)));
123124
abortWithReason(AHIsNotInt32);
124125
checkInt32.link(this);
@@ -131,6 +132,7 @@ void AssemblyHelpers::jitAssertIsJSInt32(GPRReg gpr)
131132
{
132133
if (!Options::useJITAsserts())
133134
return;
135+
JIT_COMMENT(*this, "ASSERT is JS boxed int32");
134136
Jump checkJSInt32 = branch64(AboveOrEqual, gpr, GPRInfo::numberTagRegister);
135137
abortWithReason(AHIsNotJSInt32);
136138
checkJSInt32.link(this);
@@ -140,6 +142,7 @@ void AssemblyHelpers::jitAssertIsJSNumber(GPRReg gpr)
140142
{
141143
if (!Options::useJITAsserts())
142144
return;
145+
JIT_COMMENT(*this, "ASSERT is JS boxed number");
143146
Jump checkJSNumber = branchTest64(MacroAssembler::NonZero, gpr, GPRInfo::numberTagRegister);
144147
abortWithReason(AHIsNotJSNumber);
145148
checkJSNumber.link(this);
@@ -149,6 +152,7 @@ void AssemblyHelpers::jitAssertIsJSDouble(GPRReg gpr)
149152
{
150153
if (!Options::useJITAsserts())
151154
return;
155+
JIT_COMMENT(*this, "ASSERT is JS boxed double (non-int32 number)");
152156
Jump checkJSInt32 = branch64(AboveOrEqual, gpr, GPRInfo::numberTagRegister);
153157
Jump checkJSNumber = branchTest64(MacroAssembler::NonZero, gpr, GPRInfo::numberTagRegister);
154158
checkJSInt32.link(this);
@@ -160,6 +164,7 @@ void AssemblyHelpers::jitAssertIsCell(GPRReg gpr)
160164
{
161165
if (!Options::useJITAsserts())
162166
return;
167+
JIT_COMMENT(*this, "ASSERT is JSCell");
163168
Jump checkCell = branchTest64(MacroAssembler::Zero, gpr, GPRInfo::notCellMaskRegister);
164169
abortWithReason(AHIsNotCell);
165170
checkCell.link(this);

‎Source/JavaScriptCore/jit/JITArithmetic.cpp‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -290,15 +290,19 @@ void JIT::emit_compareUnsignedAndJumpImpl(VirtualRegister op1, VirtualRegister o
290290
{
291291
if (isOperandConstantInt(op2)) {
292292
emitGetVirtualRegisterPayload(op1, regT0);
293+
jitAssertIsJSInt32(regT0);
293294
int32_t op2imm = getOperandConstantInt(op2);
294295
addJump(branch32(condition, regT0, Imm32(op2imm)), target);
295296
} else if (isOperandConstantInt(op1)) {
296297
emitGetVirtualRegisterPayload(op2, regT1);
298+
jitAssertIsJSInt32(regT1);
297299
int32_t op1imm = getOperandConstantInt(op1);
298300
addJump(branch32(commute(condition), regT1, Imm32(op1imm)), target);
299301
} else {
300302
emitGetVirtualRegisterPayload(op1, regT0);
301303
emitGetVirtualRegisterPayload(op2, regT1);
304+
jitAssertIsJSInt32(regT0);
305+
jitAssertIsJSInt32(regT1);
302306
addJump(branch32(condition, regT0, regT1), target);
303307
}
304308
}

‎Source/JavaScriptCore/lol/LOLJIT.cpp‎

Lines changed: 215 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -738,6 +738,8 @@ void LOLJIT::privateCompileSlowCases()
738738
REPLAY_ALLOCATION_FOR_OP(op_jnundefined_or_null, OpJnundefinedOrNull)
739739
REPLAY_ALLOCATION_FOR_OP(op_jeq_ptr, OpJeqPtr)
740740
REPLAY_ALLOCATION_FOR_OP(op_jneq_ptr, OpJneqPtr)
741+
REPLAY_ALLOCATION_FOR_OP(op_jbelow, OpJbelow)
742+
REPLAY_ALLOCATION_FOR_OP(op_jbeloweq, OpJbeloweq)
741743

742744
default:
743745
RELEASE_ASSERT_NOT_REACHED();
@@ -974,6 +976,7 @@ void LOLJIT::emitCompareSlow(const JSInstruction* instruction, DoubleCondition c
974976
emitCompareSlowImpl(allocations, op1, op1Regs, op2, op2Regs, dstRegs, operation, iter, emitDoubleCompare);
975977
}
976978

979+
// FIXME: Maybe this should take a shouldBox template parameter instead of relying on !dstRegs
977980
template<typename SlowOperation>
978981
void LOLJIT::emitCompareSlowImpl(const auto& allocations, VirtualRegister lhs, JSValueRegs lhsRegs, VirtualRegister rhs, JSValueRegs rhsRegs, JSValueRegs dstRegs, SlowOperation operation, Vector<SlowCaseEntry>::iterator& iter, const Invocable<void(FPRReg, FPRReg)> auto& emitDoubleCompare)
979982
{
@@ -1092,6 +1095,218 @@ void LOLJIT::emitSlow_op_greatereq(const JSInstruction* currentInstruction, Vect
10921095
emitCompareSlow<OpGreatereq>(currentInstruction, DoubleGreaterThanOrEqualAndOrdered, operationCompareGreaterEq, iter);
10931096
}
10941097

1098+
// Jump compare bytecodes
1099+
1100+
template<typename Op>
1101+
void LOLJIT::emitCompareAndJump(const JSInstruction* instruction, RelationalCondition condition)
1102+
{
1103+
auto bytecode = instruction->as<Op>();
1104+
VirtualRegister op1 = bytecode.m_lhs;
1105+
VirtualRegister op2 = bytecode.m_rhs;
1106+
unsigned class="pl-c1">jumpTarget(instruction, bytecode.m_targetLabel);
1107+
auto allocations = m_fastAllocator.allocate(*this, bytecode, m_bytecodeIndex);
1108+
auto [ op1Regs, op2Regs ] = allocations.uses;
1109+
1110+
auto emitCompareAndJump = [&](RelationalCondition cond, JSValueRegs leftJSR, auto right) {
1111+
addJump(branch32(cond, leftJSR.payloadGPR(), right), target);
1112+
};
1113+
emitCompareImpl(op1, op1Regs, op2, op2Regs, condition, emitCompareAndJump);
1114+
m_fastAllocator.releaseScratches(allocations);
1115+
}
1116+
1117+
template<typename Op, typename SlowOperation>
1118+
void LOLJIT::emitCompareAndJumpSlow(const JSInstruction* instruction, DoubleCondition condition, SlowOperation operation, bool invertOperationResult, Vector<SlowCaseEntry>::iterator& iter)
1119+
{
1120+
auto bytecode = instruction->as<Op>();
1121+
unsigned class="pl-c1">jumpTarget(instruction, bytecode.m_targetLabel);
1122+
1123+
VirtualRegister op1 = bytecode.m_lhs;
1124+
VirtualRegister op2 = bytecode.m_rhs;
1125+
auto allocations = m_replayAllocator.allocate(*this, bytecode, m_bytecodeIndex);
1126+
auto [ op1Regs, op2Regs ] = allocations.uses;
1127+
1128+
auto emitDoubleCompare = [&](FPRReg left, FPRReg right) {
1129+
emitJumpSlowToHot(branchDouble(condition, left, right), target);
1130+
};
1131+
// Pass empty dstRegs since we're doing a jump, not storing a result, result will be in returnValueGPR
1132+
emitCompareSlowImpl(allocations, op1, op1Regs, op2, op2Regs, JSValueRegs(), operation, iter, emitDoubleCompare);
1133+
1134+
emitJumpSlowToHot(branchTest32(invertOperationResult ? Zero : NonZero, returnValueGPR), target);
1135+
1136+
m_replayAllocator.releaseScratches(allocations);
1137+
}
1138+
1139+
void LOLJIT::emit_op_jless(const JSInstruction* currentInstruction)
1140+
{
1141+
emitCompareAndJump<OpJless>(currentInstruction, LessThan);
1142+
}
1143+
1144+
void LOLJIT::emit_op_jlesseq(const JSInstruction* currentInstruction)
1145+
{
1146+
emitCompareAndJump<OpJlesseq>(currentInstruction, LessThanOrEqual);
1147+
}
1148+
1149+
void LOLJIT::emit_op_jgreater(const JSInstruction* currentInstruction)
1150+
{
1151+
emitCompareAndJump<OpJgreater>(currentInstruction, GreaterThan);
1152+
}
1153+
1154+
void LOLJIT::emit_op_jgreatereq(const JSInstruction* currentInstruction)
1155+
{
1156+
emitCompareAndJump<OpJgreatereq>(currentInstruction, GreaterThanOrEqual);
1157+
}
1158+
1159+
void LOLJIT::emit_op_jnless(const JSInstruction* currentInstruction)
1160+
{
1161+
emitCompareAndJump<OpJnless>(currentInstruction, GreaterThanOrEqual);
1162+
}
1163+
1164+
void LOLJIT::emit_op_jnlesseq(const JSInstruction* currentInstruction)
1165+
{
1166+
emitCompareAndJump<OpJnlesseq>(currentInstruction, GreaterThan);
1167+
}
1168+
1169+
void LOLJIT::emit_op_jngreater(const JSInstruction* currentInstruction)
1170+
{
1171+
emitCompareAndJump<OpJngreater>(currentInstruction, LessThanOrEqual);
1172+
}
1173+
1174+
void LOLJIT::emit_op_jngreatereq(const JSInstruction* currentInstruction)
1175+
{
1176+
emitCompareAndJump<OpJngreatereq>(currentInstruction, LessThan);
1177+
}
1178+
1179+
void LOLJIT::emitSlow_op_jless(const JSInstruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
1180+
{
1181+
emitCompareAndJumpSlow<OpJless>(currentInstruction, DoubleLessThanAndOrdered, operationCompareLess, false, iter);
1182+
}
1183+
1184+
void LOLJIT::emitSlow_op_jlesseq(const JSInstruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
1185+
{
1186+
emitCompareAndJumpSlow<OpJlesseq>(currentInstruction, DoubleLessThanOrEqualAndOrdered, operationCompareLessEq, false, iter);
1187+
}
1188+
1189+
void LOLJIT::emitSlow_op_jgreater(const JSInstruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
1190+
{
1191+
emitCompareAndJumpSlow<OpJgreater>(currentInstruction, DoubleGreaterThanAndOrdered, operationCompareGreater, false, iter);
1192+
}
1193+
1194+
void LOLJIT::emitSlow_op_jgreatereq(const JSInstruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
1195+
{
1196+
emitCompareAndJumpSlow<OpJgreatereq>(currentInstruction, DoubleGreaterThanOrEqualAndOrdered, operationCompareGreaterEq, false, iter);
1197+
}
1198+
1199+
void LOLJIT::emitSlow_op_jnless(const JSInstruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
1200+
{
1201+
emitCompareAndJumpSlow<OpJnless>(currentInstruction, DoubleGreaterThanOrEqualOrUnordered, operationCompareLess, true, iter);
1202+
}
1203+
1204+
void LOLJIT::emitSlow_op_jnlesseq(const JSInstruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
1205+
{
1206+
emitCompareAndJumpSlow<OpJnlesseq>(currentInstruction, DoubleGreaterThanOrUnordered, operationCompareLessEq, true, iter);
1207+
}
1208+
1209+
void LOLJIT::emitSlow_op_jngreater(const JSInstruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
1210+
{
1211+
emitCompareAndJumpSlow<OpJngreater>(currentInstruction, DoubleLessThanOrEqualOrUnordered, operationCompareGreater, true, iter);
1212+
}
1213+
1214+
void LOLJIT::emitSlow_op_jngreatereq(const JSInstruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
1215+
{
1216+
emitCompareAndJumpSlow<OpJngreatereq>(currentInstruction, DoubleLessThanOrUnordered, operationCompareGreaterEq, true, iter);
1217+
}
1218+
1219+
// Strict equality jumps
1220+
1221+
template<typename Op>
1222+
void LOLJIT::emitStrictEqJumpImpl(const JSInstruction* currentInstruction, RelationalCondition condition)
1223+
{
1224+
auto bytecode = currentInstruction->as<Op>();
1225+
unsigned class="pl-c1">jumpTarget(currentInstruction, bytecode.m_targetLabel);
1226+
auto allocations = m_fastAllocator.allocate(*this, bytecode, m_bytecodeIndex);
1227+
auto [ lhsRegs, rhsRegs ] = allocations.uses;
1228+
1229+
// Fast path: both are integers
1230+
addSlowCase(branchIfNotInt32(lhsRegs));
1231+
addSlowCase(branchIfNotInt32(rhsRegs));
1232+
1233+
addJump(branch32(condition, lhsRegs.payloadGPR(), rhsRegs.payloadGPR()), target);
1234+
1235+
m_fastAllocator.releaseScratches(allocations);
1236+
}
1237+
1238+
template<typename Op>
1239+
void LOLJIT::emitStrictEqJumpSlowImpl(const JSInstruction* currentInstruction, ResultCondition condition, Vector<SlowCaseEntry>::iterator& iter)
1240+
{
1241+
auto bytecode = currentInstruction->as<Op>();
1242+
unsigned class="pl-c1">jumpTarget(currentInstruction, bytecode.m_targetLabel);
1243+
auto allocations = m_replayAllocator.allocate(*this, bytecode, m_bytecodeIndex);
1244+
auto [ lhsRegs, rhsRegs ] = allocations.uses;
1245+
1246+
linkAllSlowCases(iter);
1247+
1248+
ASSERT(m_replayAllocator.allocatedRegisters().isEmpty());
1249+
loadGlobalObject(s_scratch);
1250+
callOperation(operationCompareStrictEq, s_scratch, lhsRegs, rhsRegs);
1251+
1252+
emitJumpSlowToHot(branchTest32(condition, returnValueGPR), target);
1253+
1254+
m_replayAllocator.releaseScratches(allocations);
1255+
}
1256+
1257+
void LOLJIT::emit_op_jstricteq(const JSInstruction* currentInstruction)
1258+
{
1259+
emitStrictEqJumpImpl<OpJstricteq>(currentInstruction, Equal);
1260+
}
1261+
1262+
void LOLJIT::emitSlow_op_jstricteq(const JSInstruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
1263+
{
1264+
emitStrictEqJumpSlowImpl<OpJstricteq>(currentInstruction, NonZero, iter);
1265+
}
1266+
1267+
void LOLJIT::emit_op_jnstricteq(const JSInstruction* currentInstruction)
1268+
{
1269+
emitStrictEqJumpImpl<OpJnstricteq>(currentInstruction, NotEqual);
1270+
}
1271+
1272+
void LOLJIT::emitSlow_op_jnstricteq(const JSInstruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
1273+
{
1274+
emitStrictEqJumpSlowImpl<OpJnstricteq>(currentInstruction, Zero, iter);
1275+
}
1276+
1277+
template<typename Op>
1278+
void LOLJIT::emitCompareUnsignedAndJumpImpl(const JSInstruction* currentInstruction, RelationalCondition condition)
1279+
{
1280+
auto bytecode = currentInstruction->as<Op>();
1281+
unsigned class="pl-c1">jumpTarget(currentInstruction, bytecode.m_targetLabel);
1282+
auto allocations = m_fastAllocator.allocate(*this, bytecode, m_bytecodeIndex);
1283+
auto [ lhsRegs, rhsRegs ] = allocations.uses;
1284+
1285+
if (isOperandConstantInt(bytecode.m_rhs)) {
1286+
jitAssertIsJSInt32(lhsRegs.payloadGPR());
1287+
addJump(branch32(condition, lhsRegs.payloadGPR(), Imm32(getOperandConstantInt(bytecode.m_rhs))), target);
1288+
} else if (isOperandConstantInt(bytecode.m_lhs)) {
1289+
jitAssertIsJSInt32(rhsRegs.payloadGPR());
1290+
addJump(branch32(commute(condition), rhsRegs.payloadGPR(), Imm32(getOperandConstantInt(bytecode.m_lhs))), target);
1291+
} else {
1292+
jitAssertIsJSInt32(lhsRegs.payloadGPR());
1293+
jitAssertIsJSInt32(rhsRegs.payloadGPR());
1294+
addJump(branch32(condition, lhsRegs.payloadGPR(), rhsRegs.payloadGPR()), target);
1295+
}
1296+
1297+
m_fastAllocator.releaseScratches(allocations);
1298+
}
1299+
1300+
void LOLJIT::emit_op_jbelow(const JSInstruction* currentInstruction)
1301+
{
1302+
emitCompareUnsignedAndJumpImpl<OpJbelow>(currentInstruction, Below);
1303+
}
1304+
1305+
void LOLJIT::emit_op_jbeloweq(const JSInstruction* currentInstruction)
1306+
{
1307+
emitCompareUnsignedAndJumpImpl<OpJbeloweq>(currentInstruction, BelowOrEqual);
1308+
}
1309+
10951310
// Conversion
10961311

10971312
void LOLJIT::emit_op_to_number(const JSInstruction* currentInstruction)

‎Source/JavaScriptCore/lol/LOLJIT.h‎

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,18 @@ namespace JSC::LOL {
9696
macro(op_jneq_ptr) \
9797
macro(op_jeq) \
9898
macro(op_jneq) \
99+
macro(op_jless) \
100+
macro(op_jlesseq) \
101+
macro(op_jgreater) \
102+
macro(op_jgreatereq) \
103+
macro(op_jnless) \
104+
macro(op_jnlesseq) \
105+
macro(op_jngreater) \
106+
macro(op_jngreatereq) \
107+
macro(op_jstricteq) \
108+
macro(op_jnstricteq) \
109+
macro(op_jbelow) \
110+
macro(op_jbeloweq) \
99111

100112

101113
#define FOR_EACH_OP_WITH_SLOW_CASE(macro) \
@@ -377,11 +389,24 @@ class LOLJIT : public JIT, public ReplayBackend {
377389
template <typename EmitCompareFunctor>
378390
void emitCompareImpl(VirtualRegister op1, JSValueRegs op1Regs, VirtualRegister op2, JSValueRegs op2Regs, RelationalCondition, const EmitCompareFunctor&);
379391

392+
template<typename Op>
393+
void emitCompareAndJump(const JSInstruction*, RelationalCondition);
394+
380395
template<typename Op, typename SlowOperation>
381396
void emitCompareSlow(const JSInstruction*, DoubleCondition, SlowOperation, Vector<SlowCaseEntry>::iterator&);
382397
template<typename SlowOperation>
383398
void emitCompareSlowImpl(const auto& allocations, VirtualRegister op1, JSValueRegs op1Regs, VirtualRegister op2, JSValueRegs op2Regs, JSValueRegs dstRegs, SlowOperation, Vector<SlowCaseEntry>::iterator&, const Invocable<void(FPRReg, FPRReg)> auto&);
384399

400+
template<typename Op, typename SlowOperation>
401+
void emitCompareAndJumpSlow(const JSInstruction*, DoubleCondition, SlowOperation, bool invertOperationResult, Vector<SlowCaseEntry>::iterator&);
402+
403+
template<typename Op>
404+
void emitCompareUnsignedAndJumpImpl(const JSInstruction*, RelationalCondition);
405+
406+
template<typename Op>
407+
void emitStrictEqJumpImpl(const JSInstruction*, RelationalCondition);
408+
template<typename Op>
409+
void emitStrictEqJumpSlowImpl(const JSInstruction*, ResultCondition, Vector<SlowCaseEntry>::iterator&);
385410

386411
static MacroAssemblerCodeRef<JITThunkPtrTag> slow_op_get_from_scopeGenerator(VM&);
387412
static MacroAssemblerCodeRef<JITThunkPtrTag> slow_op_resolve_scopeGenerator(VM&);

0 commit comments

Comments
 (0)