Skip to content

Commit a92edcd

Browse files
jbower-fbfacebook-github-bot
authored andcommitted
Remove JIT implementation of RAISE_VARARGS
Summary: There's no need to implement this in the JIT as we just deopt after executing it. Much neater to just deopt immediately and let the interpreter run its implementation of `RAISE_VARARGS`. The motivation for doing this now is something is broken in 3.14 on deopt after `RAISE_VARARGS`. Something to do with the instruction pointer location is a problem in this situation where it wasn't before. Seems easier to just remove this whole situation than trying to work around this difference for 3.14+ only. Reviewed By: alexmalyshev Differential Revision: D80860343 fbshipit-source-id: ef1efbc31dda4c9344017c4256444fff39d7daa9
1 parent ce5da92 commit a92edcd

14 files changed

Lines changed: 69 additions & 191 deletions

File tree

cinderx/Jit/codegen/gen_asm.cpp

Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,7 @@ prepareForDeopt(const uint64_t* regs, Runtime* runtime, std::size_t deopt_idx) {
219219
runtime->guardFailed(deopt_meta);
220220
break;
221221
}
222+
case DeoptReason::kRaise:
222223
case DeoptReason::kYieldFrom: {
223224
break;
224225
}
@@ -233,23 +234,8 @@ prepareForDeopt(const uint64_t* regs, Runtime* runtime, std::size_t deopt_idx) {
233234
break;
234235
case DeoptReason::kUnhandledException:
235236
JIT_ABORT("unhandled exception without error set");
236-
case DeoptReason::kRaise:
237-
// This code mirrors what happens in _PyEval_EvalFrameDefault although
238-
// I'm not sure how to test it. Not clear it can happen with JIT.
239-
#ifdef NDEBUG
240-
if (!PyErr_Occurred()) {
241-
PyErr_SetString(
242-
PyExc_SystemError, "error return without exception set");
243-
}
244-
#else
245-
JIT_CHECK(PyErr_Occurred(), "Error return without exception set");
246-
#endif
247-
break;
248237
case DeoptReason::kRaiseStatic:
249238
JIT_ABORT("Lost exception when raising static exception");
250-
case DeoptReason::kReraise:
251-
PyErr_SetString(PyExc_RuntimeError, "No active exception to reraise");
252-
break;
253239
}
254240
}
255241
return frame;
@@ -272,7 +258,9 @@ PyObject* resumeInInterpreter(
272258
// Resume all of the inlined frames and the caller
273259
const DeoptMetadata& deopt_meta = runtime->getDeoptMetadata(deopt_idx);
274260
int inline_depth = deopt_meta.inline_depth();
275-
int err_occurred = (deopt_meta.reason != DeoptReason::kGuardFailure);
261+
int err_occurred =
262+
(deopt_meta.reason != DeoptReason::kGuardFailure &&
263+
deopt_meta.reason != DeoptReason::kRaise);
276264
while (inline_depth >= 0) {
277265
// Consider skipping resuming frames that do not have try/catch. Will
278266
// require re-adding _PyShadowFrame_Pop back for non-generators and
@@ -322,7 +310,9 @@ PyObject* resumeInInterpreter(
322310
PyThreadState* tstate = PyThreadState_Get();
323311

324312
const DeoptMetadata& deopt_meta = runtime->getDeoptMetadata(deopt_idx);
325-
int err_occurred = (deopt_meta.reason != DeoptReason::kGuardFailure);
313+
int err_occurred =
314+
(deopt_meta.reason != DeoptReason::kGuardFailure &&
315+
deopt_meta.reason != DeoptReason::kRaise);
326316

327317
PyObject* result = nullptr;
328318
// Resume all of the inlined frames and the caller
@@ -340,6 +330,15 @@ PyObject* resumeInInterpreter(
340330
JIT_CHECK(
341331
currentFrame(tstate) == frame, "unexpected frame at top of stack");
342332
setCurrentFrame(tstate, frame->previous);
333+
// The interpreter calls _Py_Instrument() on the initial RESUME opcode in a
334+
// function, but we don't do this in the JIT. Calling it now is a bit
335+
// dubious, because we are splitting execution of the same function between
336+
// instrumented and not. However, if we don't do this and instrumentation
337+
// is enabled we might hit assertions in the deopted execution because the
338+
// code's instrumentation version doesn't match the interpreter's.
339+
JIT_CHECK(
340+
_Py_Instrument(frameCode(frame), tstate->interp) == 0,
341+
"Failed to instrument code on deopt");
343342
result = _PyEval_EvalFrameDefault(tstate, frame, err_occurred);
344343

345344
frame = prev_frame;

cinderx/Jit/deopt.cpp

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,9 @@ static BCIndex getDeoptResumeIndex(
242242
// function's callers then these will be resumed by the interpreter in
243243
// future and will never be a JIT guard failure.
244244
bool is_innermost = &frame == &meta.innermostFrame();
245-
if ((is_innermost && meta.reason == DeoptReason::kGuardFailure) ||
245+
if ((is_innermost &&
246+
(meta.reason == DeoptReason::kGuardFailure ||
247+
meta.reason == DeoptReason::kRaise)) ||
246248
forced_deopt) {
247249
return frame.cause_instr_idx;
248250
}
@@ -390,15 +392,7 @@ static DeoptReason getDeoptReason(const jit::hir::DeoptBase& instr) {
390392
return DeoptReason::kYieldFrom;
391393
}
392394
case jit::hir::Opcode::kRaise: {
393-
auto& raise = static_cast<const hir::Raise&>(instr);
394-
switch (raise.kind()) {
395-
case hir::Raise::Kind::kReraise:
396-
return DeoptReason::kReraise;
397-
case hir::Raise::Kind::kRaiseWithExc:
398-
case hir::Raise::Kind::kRaiseWithExcAndCause:
399-
return DeoptReason::kRaise;
400-
}
401-
JIT_ABORT("invalid raise kind");
395+
return DeoptReason::kRaise;
402396
}
403397
case jit::hir::Opcode::kRaiseStatic: {
404398
return DeoptReason::kRaiseStatic;

cinderx/Jit/deopt.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,6 @@ struct LiveValue {
7676
X(YieldFrom) \
7777
X(Raise) \
7878
X(RaiseStatic) \
79-
X(Reraise) \
8079
X(UnhandledException) \
8180
X(UnhandledUnboundLocal) \
8281
X(UnhandledUnboundFreevar) \

cinderx/Jit/hir/builder.cpp

Lines changed: 3 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1356,7 +1356,7 @@ void HIRBuilder::translate(
13561356
break;
13571357
}
13581358
case RAISE_VARARGS: {
1359-
emitRaiseVarargs(tc, bc_instr);
1359+
emitRaiseVarargs(tc);
13601360
break;
13611361
}
13621362
case YIELD_VALUE: {
@@ -4271,26 +4271,8 @@ void HIRBuilder::emitImportName(
42714271
stack.push(res);
42724272
}
42734273

4274-
void HIRBuilder::emitRaiseVarargs(
4275-
TranslationContext& tc,
4276-
const jit::BytecodeInstruction& bc_instr) {
4277-
auto& stack = tc.frame.stack;
4278-
switch (bc_instr.oparg()) {
4279-
case 2: {
4280-
auto cause = stack.pop();
4281-
auto exc = stack.pop();
4282-
tc.emit<Raise>(2, tc.frame, exc, cause);
4283-
break;
4284-
}
4285-
case 1:
4286-
tc.emit<Raise>(1, tc.frame, stack.pop());
4287-
break;
4288-
case 0:
4289-
tc.emit<Raise>(0, tc.frame);
4290-
break;
4291-
default:
4292-
JIT_ABORT("Unsupported RAISE_VARARGS op: {}", bc_instr.oparg());
4293-
}
4274+
void HIRBuilder::emitRaiseVarargs(TranslationContext& tc) {
4275+
tc.emit<Raise>(tc.frame);
42944276
}
42954277

42964278
void HIRBuilder::emitYieldFrom(TranslationContext& tc, Register* out) {

cinderx/Jit/hir/builder.h

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -343,9 +343,7 @@ class HIRBuilder {
343343
CFG& cfg,
344344
TranslationContext& tc,
345345
const jit::BytecodeInstruction& bc_instr);
346-
void emitRaiseVarargs(
347-
TranslationContext& tc,
348-
const jit::BytecodeInstruction& bc_instr);
346+
void emitRaiseVarargs(TranslationContext& tc);
349347
void emitRefineType(
350348
TranslationContext& tc,
351349
const jit::BytecodeInstruction& bc_instr);

cinderx/Jit/hir/hir.h

Lines changed: 1 addition & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -3697,39 +3697,7 @@ class INSTR_CLASS(
36973697
}
36983698
};
36993699

3700-
// (Re)raises an exception with optional cause.
3701-
class INSTR_CLASS(Raise, (TObject, TObject), Operands<>, DeoptBase) {
3702-
public:
3703-
enum class Kind {
3704-
kReraise,
3705-
kRaiseWithExc,
3706-
kRaiseWithExcAndCause,
3707-
};
3708-
3709-
private:
3710-
Raise(Kind kind, const FrameState& frame) : InstrT(frame), kind_(kind) {}
3711-
3712-
public:
3713-
explicit Raise(const FrameState& frame) : Raise(Kind::kReraise, frame) {}
3714-
3715-
Raise(const FrameState& frame, Register* exc)
3716-
: Raise(Raise::Kind::kRaiseWithExc, frame) {
3717-
SetOperand(0, exc);
3718-
}
3719-
3720-
Raise(const FrameState& frame, Register* exc, Register* cause)
3721-
: Raise(Raise::Kind::kRaiseWithExcAndCause, frame) {
3722-
SetOperand(0, exc);
3723-
SetOperand(1, cause);
3724-
}
3725-
3726-
Kind kind() const {
3727-
return kind_;
3728-
}
3729-
3730-
private:
3731-
const Kind kind_;
3732-
};
3700+
DEFINE_SIMPLE_INSTR(Raise, (), Operands<0>, DeoptBase);
37333701

37343702
// Set an error by calling PyErr_Format() and then raising. This is typically
37353703
// used when a runtime assertion implemented as part of a Python opcode is hit.

cinderx/Jit/jit_rt.cpp

Lines changed: 0 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1455,34 +1455,6 @@ PyObject* JITRT_ImportName(
14551455
import_func, name, globals, locals, fromlist, level, nullptr);
14561456
}
14571457

1458-
void JITRT_DoRaise(PyThreadState* tstate, PyObject* exc, PyObject* cause) {
1459-
// If we re-raise with no error set, deliberately do nothing and let
1460-
// prepareForDeopt() handle this. We can't let do_raise() handle this by
1461-
// raising a RuntimeError as this would mean prepareForDeopt() does not call
1462-
// PyTraceBack_Here().
1463-
if (exc == nullptr) {
1464-
_PyErr_StackItem* exc_info = _PyErr_GetTopmostException(tstate);
1465-
PyObject* type_or_value =
1466-
#if PY_VERSION_HEX < 0x030C0000
1467-
exc_info->exc_type;
1468-
#else
1469-
exc_info->exc_value;
1470-
#endif
1471-
if (Py_IsNone(type_or_value) || type_or_value == nullptr) {
1472-
return;
1473-
}
1474-
}
1475-
// We deliberately discard the return value here. In the interpreter a return
1476-
// value of 1 indicates a _valid_ re-raise which skips:
1477-
// (1) Calling PyTraceBack_Here().
1478-
// (2) Raising a SystemError if no exception is set (no need, do_raise
1479-
// already handles this).
1480-
// (3) Calling tstate->c_tracefunc.
1481-
// We don't support (3) and handle (1) + (2) between the check above and in
1482-
// prepareForDeopt().
1483-
Cix_do_raise(tstate, exc, cause);
1484-
}
1485-
14861458
#if PY_VERSION_HEX < 0x030C0000
14871459
enum class MakeGenObjectMode {
14881460
kAsyncGenerator,

cinderx/Jit/jit_rt.h

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -359,12 +359,6 @@ PyObject* JITRT_ImportName(
359359
PyObject* fromlist,
360360
PyObject* level);
361361

362-
/*
363-
* Wrapper around _Py_DoRaise() which handles the case where we re-raise but no
364-
* active exception is set.
365-
*/
366-
void JITRT_DoRaise(PyThreadState* tstate, PyObject* exc, PyObject* cause);
367-
368362
/*
369363
* Formats a f-string value
370364
*/

cinderx/Jit/lir/generator.cpp

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3082,25 +3082,6 @@ LIRGenerator::TranslatedBlock LIRGenerator::TranslateOneBasicBlock(
30823082
}
30833083
case Opcode::kRaise: {
30843084
const auto& instr = static_cast<const Raise&>(i);
3085-
hir::Register* exc = nullptr;
3086-
hir::Register* cause = nullptr;
3087-
3088-
switch (instr.kind()) {
3089-
case Raise::Kind::kReraise:
3090-
break;
3091-
case Raise::Kind::kRaiseWithExcAndCause:
3092-
cause = instr.GetOperand(1);
3093-
[[fallthrough]];
3094-
case Raise::Kind::kRaiseWithExc:
3095-
exc = instr.GetOperand(0);
3096-
break;
3097-
}
3098-
bbb.appendCallInstruction(
3099-
OutVReg{OperandBase::k32bit},
3100-
Cix_do_raise,
3101-
env_->asm_tstate,
3102-
exc,
3103-
cause);
31043085
appendGuardAlwaysFail(bbb, instr);
31053086
break;
31063087
}

cinderx/RuntimeTests/hir_test.cpp

Lines changed: 42 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1108,31 +1108,49 @@ TEST_F(HIRCloneTest, CanCloneBorrwedRefFields) {
11081108

11091109
TEST_F(HIRCloneTest, CanCloneVariadicOpInstr) {
11101110
Environment env;
1111+
auto out = env.AllocateRegister();
11111112
auto v0 = env.AllocateRegister();
1112-
FrameState raise_fs{BCOffset{10}};
1113-
std::unique_ptr<Instr> raise_exc(Raise::create(1, raise_fs, v0));
1114-
std::unique_ptr<Instr> new_raise_exc(raise_exc->clone());
1115-
ASSERT_NE(raise_exc.get(), new_raise_exc.get());
1116-
ASSERT_TRUE(new_raise_exc->IsRaise());
1117-
1118-
Raise* orig_raise = static_cast<Raise*>(raise_exc.get());
1119-
Raise* dup_raise = static_cast<Raise*>(new_raise_exc.get());
1120-
EXPECT_EQ(orig_raise->kind(), dup_raise->kind());
1121-
EXPECT_EQ(orig_raise->GetOperand(0), dup_raise->GetOperand(0));
1122-
FrameState* orig_raise_fs = orig_raise->frameState();
1123-
EXPECT_EQ(orig_raise_fs->cur_instr_offs, 10);
1124-
EXPECT_NE(orig_raise_fs, dup_raise->frameState());
1125-
1126-
std::unique_ptr<Instr> raise_exc_cause(Raise::create(2, raise_fs, v0, v0));
1127-
std::unique_ptr<Instr> new_raise_exc_cause(raise_exc_cause->clone());
1128-
ASSERT_NE(raise_exc_cause.get(), new_raise_exc_cause.get());
1129-
ASSERT_TRUE(new_raise_exc_cause->IsRaise());
1130-
1131-
orig_raise = static_cast<Raise*>(raise_exc_cause.get());
1132-
dup_raise = static_cast<Raise*>(new_raise_exc_cause.get());
1133-
EXPECT_EQ(orig_raise->kind(), dup_raise->kind());
1134-
EXPECT_EQ(orig_raise->GetOperand(0), dup_raise->GetOperand(0));
1135-
EXPECT_EQ(orig_raise->GetOperand(1), dup_raise->GetOperand(1));
1113+
1114+
// Create a CallStatic with no arguments
1115+
std::unique_ptr<Instr> call_static_no_args(
1116+
CallStatic::create(0, out, nullptr, Type::fromObject(Py_None)));
1117+
std::unique_ptr<Instr> new_call_static_no_args(call_static_no_args->clone());
1118+
ASSERT_NE(call_static_no_args.get(), new_call_static_no_args.get());
1119+
ASSERT_TRUE(new_call_static_no_args->IsCallStatic());
1120+
1121+
CallStatic* orig_call = static_cast<CallStatic*>(call_static_no_args.get());
1122+
CallStatic* dup_call =
1123+
static_cast<CallStatic*>(new_call_static_no_args.get());
1124+
EXPECT_EQ(orig_call->addr(), dup_call->addr());
1125+
EXPECT_EQ(orig_call->ret_type(), dup_call->ret_type());
1126+
1127+
// Create a CallStatic with one argument
1128+
std::unique_ptr<Instr> call_static_one_arg(
1129+
CallStatic::create(1, out, nullptr, Type::fromObject(Py_None), v0));
1130+
std::unique_ptr<Instr> new_call_static_one_arg(call_static_one_arg->clone());
1131+
ASSERT_NE(call_static_one_arg.get(), new_call_static_one_arg.get());
1132+
ASSERT_TRUE(new_call_static_one_arg->IsCallStatic());
1133+
1134+
orig_call = static_cast<CallStatic*>(call_static_one_arg.get());
1135+
dup_call = static_cast<CallStatic*>(new_call_static_one_arg.get());
1136+
EXPECT_EQ(orig_call->addr(), dup_call->addr());
1137+
EXPECT_EQ(orig_call->ret_type(), dup_call->ret_type());
1138+
EXPECT_EQ(orig_call->GetOperand(0), dup_call->GetOperand(0));
1139+
1140+
// Create a CallStatic with two arguments
1141+
std::unique_ptr<Instr> call_static_two_args(
1142+
CallStatic::create(2, out, nullptr, Type::fromObject(Py_None), v0, v0));
1143+
std::unique_ptr<Instr> new_call_static_two_args(
1144+
call_static_two_args->clone());
1145+
ASSERT_NE(call_static_two_args.get(), new_call_static_two_args.get());
1146+
ASSERT_TRUE(new_call_static_two_args->IsCallStatic());
1147+
1148+
orig_call = static_cast<CallStatic*>(call_static_two_args.get());
1149+
dup_call = static_cast<CallStatic*>(new_call_static_two_args.get());
1150+
EXPECT_EQ(orig_call->addr(), dup_call->addr());
1151+
EXPECT_EQ(orig_call->ret_type(), dup_call->ret_type());
1152+
EXPECT_EQ(orig_call->GetOperand(0), dup_call->GetOperand(0));
1153+
EXPECT_EQ(orig_call->GetOperand(1), dup_call->GetOperand(1));
11361154
}
11371155

11381156
TEST_F(HIRCloneTest, CanCloneDeoptBase) {

0 commit comments

Comments
 (0)