commit 54cfe2b0ceb73aede1442d2e01106f7fbd031de8
parent 2be25aae43d145fc7e28633e4045d9eced869fcb
Author: André Bargull <andre.bargull@gmail.com>
Date: Wed, 17 Dec 2025 10:49:20 +0000
Bug 2005583: Don't attach a scripted-return CloseIter IC for throw completions. r=iain
Don't attach an IC because the generated JIT code doesn't clear new exceptions
thrown when calling scripted functions.
Differential Revision: https://phabricator.services.mozilla.com/D276159
Diffstat:
6 files changed, 52 insertions(+), 33 deletions(-)
diff --git a/js/src/jit-test/tests/for-of/iterclose-ignore-throw-completion-from-return.js b/js/src/jit-test/tests/for-of/iterclose-ignore-throw-completion-from-return.js
@@ -0,0 +1,26 @@
+var iterable = {
+ [Symbol.iterator]() {
+ return this;
+ },
+ next() {
+ return { done: false };
+ },
+ return() {
+ // This exception should be ignored.
+ throw "ReturnError";
+ }
+};
+
+function test() {
+ try {
+ for (var v of iterable) {
+ throw "NextError";
+ }
+ } catch (e) {
+ assertEq(e, "NextError");
+ }
+}
+
+for (var i = 0; i < 100; ++i) {
+ test();
+}
diff --git a/js/src/jit/BaselineCacheIRCompiler.cpp b/js/src/jit/BaselineCacheIRCompiler.cpp
@@ -3717,8 +3717,7 @@ bool BaselineCacheIRCompiler::emitNewFunctionCloneResult(
}
bool BaselineCacheIRCompiler::emitCloseIterScriptedResult(
- ObjOperandId iterId, ObjOperandId calleeId, CompletionKind kind,
- uint32_t calleeNargs) {
+ ObjOperandId iterId, ObjOperandId calleeId, uint32_t calleeNargs) {
JitSpew(JitSpew_Codegen, "%s", __FUNCTION__);
Register iter = allocator.useRegister(masm, iterId);
Register callee = allocator.useRegister(masm, calleeId);
@@ -3744,17 +3743,15 @@ bool BaselineCacheIRCompiler::emitCloseIterScriptedResult(
masm.callJit(code);
- if (kind != CompletionKind::Throw) {
- // Verify that the return value is an object.
- Label success;
- masm.branchTestObject(Assembler::Equal, JSReturnOperand, &success);
+ // Verify that the return value is an object.
+ Label success;
+ masm.branchTestObject(Assembler::Equal, JSReturnOperand, &success);
- masm.Push(Imm32(int32_t(CheckIsObjectKind::IteratorReturn)));
- using Fn = bool (*)(JSContext*, CheckIsObjectKind);
- callVM<Fn, ThrowCheckIsObject>(masm);
+ masm.Push(Imm32(int32_t(CheckIsObjectKind::IteratorReturn)));
+ using Fn = bool (*)(JSContext*, CheckIsObjectKind);
+ callVM<Fn, ThrowCheckIsObject>(masm);
- masm.bind(&success);
- }
+ masm.bind(&success);
stubFrame.leave(masm);
return true;
diff --git a/js/src/jit/CacheIR.cpp b/js/src/jit/CacheIR.cpp
@@ -16867,6 +16867,10 @@ AttachDecision CloseIterIRGenerator::tryAttachNoReturnMethod() {
}
AttachDecision CloseIterIRGenerator::tryAttachScriptedReturn() {
+ if (kind_ == CompletionKind::Throw) {
+ return AttachDecision::NoAction;
+ }
+
Maybe<PropertyInfo> prop;
NativeObject* holder = nullptr;
@@ -16906,7 +16910,7 @@ AttachDecision CloseIterIRGenerator::tryAttachScriptedReturn() {
ObjOperandId calleeId = writer.guardToObject(calleeValId);
emitCalleeGuard(calleeId, callee);
- writer.closeIterScriptedResult(objId, calleeId, kind_, callee->nargs());
+ writer.closeIterScriptedResult(objId, calleeId, callee->nargs());
writer.returnFromIC();
trackAttached("CloseIter.ScriptedReturn");
diff --git a/js/src/jit/CacheIROps.yaml b/js/src/jit/CacheIROps.yaml
@@ -3799,7 +3799,6 @@
args:
iter: ObjId
callee: ObjId
- kind: CompletionKindImm
targetNargs: UInt32Imm
- name: CallPrintString
diff --git a/js/src/jit/IonCacheIRCompiler.cpp b/js/src/jit/IonCacheIRCompiler.cpp
@@ -1639,7 +1639,7 @@ bool IonCacheIRCompiler::emitLoadStringCharResult(
volatileRegs.takeUnchecked(output);
masm.PushRegsInMask(volatileRegs);
- using Fn = JSLinearString* (*)(JSContext* cx, int32_t code);
+ using Fn = JSLinearString* (*)(JSContext * cx, int32_t code);
masm.setupUnalignedABICall(scratch2);
masm.loadJSContext(scratch2);
masm.passABIArg(scratch2);
@@ -2154,7 +2154,6 @@ bool IonCacheIRCompiler::emitCallStringObjectConcatResult(ValOperandId lhsId,
bool IonCacheIRCompiler::emitCloseIterScriptedResult(ObjOperandId iterId,
ObjOperandId calleeId,
- CompletionKind kind,
uint32_t calleeNargs) {
JitSpew(JitSpew_Codegen, "%s", __FUNCTION__);
AutoSaveLiveRegisters save(*this);
@@ -2192,23 +2191,21 @@ bool IonCacheIRCompiler::emitCloseIterScriptedResult(ObjOperandId iterId,
masm.loadJitCodeRaw(callee, callee);
masm.callJit(callee);
- if (kind != CompletionKind::Throw) {
- // Verify that the return value is an object.
- Label success;
- masm.branchTestObject(Assembler::Equal, JSReturnOperand, &success);
+ // Verify that the return value is an object.
+ Label success;
+ masm.branchTestObject(Assembler::Equal, JSReturnOperand, &success);
- // We can reuse the same stub frame, but we first have to pop the arguments
- // from the previous call.
- uint32_t framePushedAfterCall = masm.framePushed();
- masm.freeStack(masm.framePushed() - stubFramePushed);
+ // We can reuse the same stub frame, but we first have to pop the arguments
+ // from the previous call.
+ uint32_t framePushedAfterCall = masm.framePushed();
+ masm.freeStack(masm.framePushed() - stubFramePushed);
- masm.push(Imm32(int32_t(CheckIsObjectKind::IteratorReturn)));
- using Fn = bool (*)(JSContext*, CheckIsObjectKind);
- callVM<Fn, ThrowCheckIsObject>(masm);
+ masm.push(Imm32(int32_t(CheckIsObjectKind::IteratorReturn)));
+ using Fn = bool (*)(JSContext*, CheckIsObjectKind);
+ callVM<Fn, ThrowCheckIsObject>(masm);
- masm.bind(&success);
- masm.setFramePushed(framePushedAfterCall);
- }
+ masm.bind(&success);
+ masm.setFramePushed(framePushedAfterCall);
// Restore the frame pointer and stack pointer.
masm.loadPtr(Address(FramePointer, 0), FramePointer);
diff --git a/js/src/jit/WarpCacheIRTranspiler.cpp b/js/src/jit/WarpCacheIRTranspiler.cpp
@@ -7139,7 +7139,6 @@ bool WarpCacheIRTranspiler::emitNewFunctionCloneResult(uint32_t canonicalOffset,
bool WarpCacheIRTranspiler::emitCloseIterScriptedResult(ObjOperandId iterId,
ObjOperandId calleeId,
- CompletionKind kind,
uint32_t calleeNargs) {
MDefinition* iter = getOperand(iterId);
MDefinition* callee = getOperand(calleeId);
@@ -7159,9 +7158,6 @@ bool WarpCacheIRTranspiler::emitCloseIterScriptedResult(ObjOperandId iterId,
return false;
}
addEffectful(call);
- if (kind == CompletionKind::Throw) {
- return resumeAfter(call);
- }
// If we bail out here, after the call but before the CheckIsObj, we
// can't simply resume in the baseline interpreter. If we resume