tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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:
Ajs/src/jit-test/tests/for-of/iterclose-ignore-throw-completion-from-return.js | 26++++++++++++++++++++++++++
Mjs/src/jit/BaselineCacheIRCompiler.cpp | 19++++++++-----------
Mjs/src/jit/CacheIR.cpp | 6+++++-
Mjs/src/jit/CacheIROps.yaml | 1-
Mjs/src/jit/IonCacheIRCompiler.cpp | 29+++++++++++++----------------
Mjs/src/jit/WarpCacheIRTranspiler.cpp | 4----
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