Bug 2065986 - pt1. Introduce bailout stubs in the baseline interpreter and fallback ics r=jandem,iain

Add bailout stubs to the Baseline Interpreter and the Fallback IC compiler. These
are currently a no-op - but will be jumped to by the bailout tail after copying
a single frame's contents. This allows the frame's return address, that is presently
directly copied into the stack, to be materialized with an actual call - making
bailout compatible with CET shadow stack on x86_64.

Differential Revision: https://phabricator.services.mozilla.com/D320791
This commit is contained in:
Abhishek Sharma
2026-09-12 08:11:42 +00:00
committed by jdemooij@mozilla.com
parent 9a17117b7b
commit de748cf25a
6 changed files with 68 additions and 25 deletions
+33 -13
View File
@@ -7145,6 +7145,23 @@ bool BaselineCompiler::emitBody() {
return true;
}
void BaselineInterpreterGenerator::emitICBailoutStub() {
MOZ_ASSERT(handler.currentOp());
mozilla::DebugOnly<JSOp> op = *handler.currentOp();
MOZ_ASSERT(BytecodeOpHasIC(op) && IsIonInlinableOp(op));
auto& entry = handler.icReturnOffsets().back();
MOZ_ASSERT(entry.op == op);
Label icReturn;
icReturn.bind(entry.offset);
entry.bailoutStubOffset = masm.currentOffset();
// The bailoutTail jumps here when performing bailout stack
// reconstruction.
// TODO: call the bailout stub handler.
masm.jump(&icReturn);
}
bool BaselineInterpreterGenerator::emitDebugTrap() {
CodeOffset offset = masm.nopPatchableToCall();
if (!debugTrapOffsets_.append(offset.offset())) {
@@ -7234,19 +7251,22 @@ bool BaselineInterpreterGenerator::emitInterpreterLoop() {
// Emit code for each bytecode op.
Label opLabels[JSOP_LIMIT];
#define EMIT_OP(OP, ...) \
{ \
AutoCreatedBy acb(masm, "op=" #OP); \
perfSpewer_.recordOffset(masm, JSOp::OP); \
masm.bind(&opLabels[uint8_t(JSOp::OP)]); \
handler.setCurrentOp(JSOp::OP); \
if (!this->emit_##OP()) { \
return false; \
} \
if (!opEpilogue(JSOp::OP, JSOpLength_##OP)) { \
return false; \
} \
handler.resetCurrentOp(); \
#define EMIT_OP(OP, ...) \
{ \
AutoCreatedBy acb(masm, "op=" #OP); \
perfSpewer_.recordOffset(masm, JSOp::OP); \
masm.bind(&opLabels[uint8_t(JSOp::OP)]); \
handler.setCurrentOp(JSOp::OP); \
if (!this->emit_##OP()) { \
return false; \
} \
if (!opEpilogue(JSOp::OP, JSOpLength_##OP)) { \
return false; \
} \
if (BytecodeOpHasIC(JSOp::OP) && IsIonInlinableOp(JSOp::OP)) { \
this->emitICBailoutStub(); \
} \
handler.resetCurrentOp(); \
}
FOR_EACH_OPCODE(EMIT_OP)
#undef EMIT_OP
+1
View File
@@ -629,6 +629,7 @@ class BaselineInterpreterGenerator final : private BaselineInterpreterCodeGen {
private:
[[nodiscard]] bool emitInterpreterLoop();
[[nodiscard]] bool emitDebugTrap();
void emitICBailoutStub();
void emitOutOfLineCodeCoverageInstrumentation();
[[nodiscard]] bool emitOutOfLineGeneratorResumePrologue();
+16 -12
View File
@@ -69,6 +69,7 @@ class MOZ_RAII FallbackICCodeCompiler final {
[[nodiscard]] bool emitCall(bool isSpread, bool isConstructing);
[[nodiscard]] bool emitGetElem(bool hasReceiver);
[[nodiscard]] bool emitGetProp(bool hasReceiver);
void emitBailoutStub(BailoutReturnKind kind);
public:
FallbackICCodeCompiler(JSContext* cx, BaselineICFallbackCode& code,
@@ -646,6 +647,14 @@ void FallbackICCodeCompiler::enterStubFrame(MacroAssembler& masm,
#endif
}
void FallbackICCodeCompiler::emitBailoutStub(BailoutReturnKind kind) {
code.initBailoutStubOffset(kind, masm.currentOffset());
// The bailoutTail jumps here when performing bailout stack
// reconstruction.
// TODO: call the bailout stub handler.
code.initBailoutReturnOffset(kind, masm.currentOffset());
}
void FallbackICCodeCompiler::assumeStubFrame() {
MOZ_ASSERT(!inStubFrame_);
inStubFrame_ = true;
@@ -830,11 +839,9 @@ bool FallbackICCodeCompiler::emitGetElem(bool hasReceiver) {
// will point here.
assumeStubFrame();
if (hasReceiver) {
code.initBailoutReturnOffset(BailoutReturnKind::GetElemSuper,
masm.currentOffset());
emitBailoutStub(BailoutReturnKind::GetElemSuper);
} else {
code.initBailoutReturnOffset(BailoutReturnKind::GetElem,
masm.currentOffset());
emitBailoutStub(BailoutReturnKind::GetElem);
}
leaveStubFrame(masm);
@@ -1416,11 +1423,9 @@ bool FallbackICCodeCompiler::emitGetProp(bool hasReceiver) {
// will point here.
assumeStubFrame();
if (hasReceiver) {
code.initBailoutReturnOffset(BailoutReturnKind::GetPropSuper,
masm.currentOffset());
emitBailoutStub(BailoutReturnKind::GetPropSuper);
} else {
code.initBailoutReturnOffset(BailoutReturnKind::GetProp,
masm.currentOffset());
emitBailoutStub(BailoutReturnKind::GetProp);
}
leaveStubFrame(masm);
@@ -1619,8 +1624,7 @@ bool FallbackICCodeCompiler::emit_SetProp() {
// Ion inlined frames. The return address pushed onto reconstructed stack
// will point here.
assumeStubFrame();
code.initBailoutReturnOffset(BailoutReturnKind::SetProp,
masm.currentOffset());
emitBailoutStub(BailoutReturnKind::SetProp);
leaveStubFrame(masm);
EmitReturnFromIC(masm);
@@ -1917,9 +1921,9 @@ bool FallbackICCodeCompiler::emitCall(bool isSpread, bool isConstructing) {
MOZ_ASSERT(!isSpread);
if (isConstructing) {
code.initBailoutReturnOffset(BailoutReturnKind::New, masm.currentOffset());
emitBailoutStub(BailoutReturnKind::New);
} else {
code.initBailoutReturnOffset(BailoutReturnKind::Call, masm.currentOffset());
emitBailoutStub(BailoutReturnKind::Call);
}
// Load passed-in ThisV into R1 just in case it's needed. Need to do this
+9
View File
@@ -1379,6 +1379,15 @@ uint8_t* BaselineInterpreter::retAddrForIC(JSOp op) const {
MOZ_CRASH("Unexpected op");
}
uint8_t* BaselineInterpreter::bailoutStubAddrForIC(JSOp op) const {
for (const ICReturnOffset& entry : icReturnOffsets_) {
if (entry.op == op) {
return codeAtOffset(entry.bailoutStubOffset);
}
}
MOZ_CRASH("Unexpected op");
}
bool jit::GenerateBaselineInterpreter(JSContext* cx,
BaselineInterpreter& interpreter) {
if (IsBaselineInterpreterEnabled()) {
+2
View File
@@ -484,6 +484,7 @@ class BaselineInterpreter {
};
struct ICReturnOffset {
uint32_t offset;
uint32_t bailoutStubOffset = 0;
JSOp op;
ICReturnOffset(uint32_t offset, JSOp op) : offset(offset), op(op) {}
};
@@ -575,6 +576,7 @@ class BaselineInterpreter {
}
uint8_t* retAddrForIC(JSOp op) const;
uint8_t* bailoutStubAddrForIC(JSOp op) const;
TrampolinePtr interpretOpAddr() const {
return TrampolinePtr(codeAtOffset(interpretOpOffset_));
+7
View File
@@ -84,6 +84,7 @@ class BaselineICFallbackCode {
mozilla::EnumeratedArray<BailoutReturnKind, uint32_t,
size_t(BailoutReturnKind::Count)>;
BailoutReturnArray bailoutReturnOffsets_ = {};
BailoutReturnArray bailoutStubOffsets_ = {};
public:
BaselineICFallbackCode() = default;
@@ -97,12 +98,18 @@ class BaselineICFallbackCode {
void initBailoutReturnOffset(BailoutReturnKind kind, uint32_t offset) {
bailoutReturnOffsets_[kind] = offset;
}
void initBailoutStubOffset(BailoutReturnKind kind, uint32_t offset) {
bailoutStubOffsets_[kind] = offset;
}
TrampolinePtr addr(BaselineICFallbackKind kind) const {
return TrampolinePtr(code_->raw() + offsets_[kind]);
}
uint8_t* bailoutReturnAddr(BailoutReturnKind kind) const {
return code_->raw() + bailoutReturnOffsets_[kind];
}
uint8_t* bailoutStubAddr(BailoutReturnKind kind) const {
return code_->raw() + bailoutStubOffsets_[kind];
}
};
enum class DebugTrapHandlerKind { Interpreter, Compiler, Count };