@@ -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
977980template <typename SlowOperation>
978981void 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
10971312void LOLJIT::emit_op_to_number (const JSInstruction* currentInstruction)
0 commit comments