Repository navigation
Update dependency Jint to 4.17.0 - #1192
Open
renovate[bot] wants to merge 1 commit into
Open
renovate[bot] wants to merge 1 commit into
renovate[bot] wants to merge 1 commit into
Conversation
renovate
Bot
force-pushed
the
renovate/jint-4.x
branch
2 times, most recently
from
September 2, 2026 12:54
09e2589 to
957ed55
Compare
renovate
Bot
force-pushed
the
renovate/jint-4.x
branch
2 times, most recently
from
September 9, 2026 19:57
c0ef7dc to
fb3e086
Compare
renovate
Bot
force-pushed
the
renovate/jint-4.x
branch
from
September 19, 2026 12:19
fb3e086 to
b218deb
Compare
renovate
Bot
force-pushed
the
renovate/jint-4.x
branch
2 times, most recently
from
September 25, 2026 10:44
23b28f0 to
23c46a2
Compare
renovate
Bot
force-pushed
the
renovate/jint-4.x
branch
from
October 1, 2026 02:57
23c46a2 to
5939aff
Compare
renovate
Bot
force-pushed
the
renovate/jint-4.x
branch
from
October 7, 2026 05:57
5939aff to
c20c978
Compare
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR contains the following updates:
4.16.0→4.17.0Release Notes
sebastienros/jint (Jint)
v4.17.0Jint 4.17.0 is a release from the
4.xbranch. It backports correctness and conformance fixes frommain(four of them for scripts that could end the host process), linear string building, and two new opt-in APIs for hosts. That is why it is a minor release rather than a patch. Nothing in it changes an existing API or an existing default, so it is a drop-in update from 4.16.4.Highlights
A pooled engine can let go of a finished request's objects. Hosts that reuse one engine across many evaluations (
CaptureGlobalSnapshotonce,RestoreGlobalSnapshotbetween runs) keep the interpreter's warmed caches, and that is the point of reusing it. But a warmed call site remembers the last function it called, and a warmed member read remembers the last object it read from. In a pooled web host, that can be a delegate built from a finished request's services, which then stay alive until the same script runs again. The newEngine.Advanced.DiscardInterpreterCaches()drops those caches, so the objects can be collected. The engine, its intrinsics and its global object stay as they are. The next run of each script rebuilds its cache, which costs roughly what a first run on a new engine costs, minus building the engine. A good place to call it is when an engine has been idle for a while, rather than after every use (#4229, from #4227).A host can carry its own state across
await. Jint now runs ECMAScript's HostMakeJobCallback and HostCallJobCallback steps for every promise reaction, every thenable job and theFinalizationRegistrycleanup callback. A host can take part through the newOptions.Host.JobCallbacks, which accepts aJobCallbackHookswithCapture,EnterandExitcallbacks. That lets each branch of aPromise.allfan-out keep its own host context, such as a logging scope or ambient request data, through everyawait(#4231, from #4230; issue #4200). The default is no hooks, in which case each promise registration costs one null check and nothing a script can observe changes.Four more ways for a script to end the host process are closed.
TypeErrorcopy from inside thecatchthat was handling the original failure. That added a nested exception dispatch at every hop, and no stack check could see it. Even with the stack-overflow guard on, a long chain of wrapped functions ended the process on the way back out, and a three-line script with anamegetter needed no chain at all. Building that copy also ran script (toString, getters, proxy traps); it no longer does. A failedimportValuenow reports the import failure instead of an unrelated error (#4220, from #4176 and #4183).instanceofandeval.instanceofnow checks the native stack before calling a customSymbol.hasInstancemethod, andevalchecks it before parsing. A self-referencingSymbol.hasInstance, orvar s = 'eval(s)'; eval(s), now raises aRangeErrorthe script can catch instead of ending the process. On theMaxExecutionStackCountpath,evalalso stopped hopping to a new thread at each overflow without ever throwing.instanceofover a bound function now consults every bound link's ownSymbol.hasInstance, as the specification requires (#4221, from #4172, #4184 and #4187).Options.Constraints.StackOverflowGuardis on, so turn it on for any script you do not fully trust.Building a string with
s = s + xis linear. A+whose result reaches 512 characters now produces a deferred string instead of copying both sides. Building withs = s + x,s = x + sands = s + a + btherefore becomes linear, ass += xalready was. Short concatenations take a separate path and pay nothing for this. The deferred string is safe to read from several engines that share onePrepared<Script>, and it is charged toLimitMemorywhen it is built, so a memory limit still bounds it. Binding an already-bound function also no longer copies its whole"bound …"name at every level (#4160, from #3386, #3571, #4130, #4164 and #4173).Array.prototype.concatspreads host arrays and lists. Since 4.14, CLR arrays and lists reach script as live views by default.concatadded such a view as a single element instead of spreading its items, soa.concat(b)returned the two wrappers. It now spreads anything script sees as an array (#4219, from #4216; issue #4201).TypedArray.prototype.withsurvives a shrinking coercion. When converting the index or the value made a resizable buffer shorter,withcopied past its new end and let a CLRArgumentExceptionescape. It now copies only what the buffer still holds (#4218, from #4157).Verification
Every backport was verified failing-first: its tests were run against the unfixed
4.xtree on .NET 10 and .NET Framework 4.7.2, then with the change. The release candidate was measured against 4.16.4 on SunSpider and Dromaeo in six paired rounds, alternating which build ran first in each round. The four DromaeoObjectRegExprows ran 12–15% faster and SunSpider's3d-raytrace2.3% faster. No row regressed by 1% or more; the two rows whose interval did not include zero (one DromaeoCubevariant, +0.70%, and SunSpider'scontrolflow-recursive, +0.88%) are within this machine's run-to-run noise.What's Changed
Full Changelog: sebastienros/jint@v4.16.4...v4.17.0
v4.16.4Jint 4.16.4 is a maintenance release from the
4.xbranch. It backports correctness and conformance fixes frommain— three of them for scripts that could end the host process — together with a few measured performance improvements, and nothing in it changes an existing API or an existing default. If you are on 4.16.3 it is a drop-in update — every public signature is the one 4.16.0 shipped, on all five target frameworks, and the per-framework snapshots inJint.Tests.PublicInterface/Verify/are unchanged.mainremains 5.0.0 development; what is coming there is recorded as it lands indocs/v5-migration.md.Highlights
A number reads as the same double on every target framework. Before .NET 9, the runtime's
ulong-to-doubleand string-to-doubleconversions double-round, and Jint inherited that: a whole-number literal in [2⁶³, 2⁶⁴) held a different double on .NET Framework and .NET 8 than on .NET 10 (#3531);parseFloat,NumberandJSON.parsemis-rounded past their integer window on .NET Framework, andJSON.parse('1e999')threw a CLROverflowExceptionout of the engine instead of answeringInfinity(#3535); a fraction or exponent literal could land one ULP away on .NET Framework (#3538); andparseIntand wide radix literals now hold the Number nearest the integer they denote on every framework, with a legacy octal no longer re-read as decimal (#3537). The string-to-number lanes andtrimnow accept exactly the white space the parser does — U+0085 NEL no longer counts, and a byte-order mark no longer breaksNumberorBigInt(#3542) — and an exponent scan no longer clamps at 10⁶ (#3593). All six arrive together as #4120, because they share one parser. This changes numeric results — to the correct ones. The literal and string-to-number fixes change answers on .NET Framework only;parseInt, radix literals, the white-space set and the exponent clamp change them on every framework.BigInt('+12')is12n. The decimal spelling of aStringIntegerLiteralmay carry a sign, so a leading+is accepted there and only there;BigInt('+0x10')stays aSyntaxError(#4121).A
splitkeeps its segments when a constraint runs script.String.prototype.splitfilled a thread-shared scratch list and checks constraints every 10,000 segments; a hostConstraintthat ran script on the same thread could clear the list an outersplitwas still filling, which then returned only the segments added afterwards (#4122).An overload is not a fit for a number it cannot hold. Overload scoring gated
float,short,byteand their kin on the value fitting, but notintandlong— so3000000000was a perfect match for anintparameter, the wider overload beside it was never tried, and the host saw a CLROverflowExceptionrather than a catchable JavaScript error (#4123).Intl's locale lookup stops paying for a culture it does not need.
BestAvailableLocaleresolved aCultureInfoon every truncation step even though the available-locale set answers almost every lookup by itself; it now resolves one only when the set cannot answer (#4124).Intl.Localecanonicalizes every Unicode extension keyword value. UTS #35 canonicalizes a keyword's value in two halves — the CLDR bcp47 aliases, and the removal of a value of"true"— and Jint did only the first, whileIntl.Locale's own tag scanner did neither. Soen-u-ca-truekept itstrue,en-u-kb-yeskept itsyesalthough the data aliases it totrue, anden-u-ks-primarywas never aliased tolevel1on the tag path. ThefirstDayOfWeekoption was read as a Number before a String and cast toint, so0.5resolved to"sun"where the spec rejects it, andNaNandInfinitybecame whatever the framework's cast made of them — which differed between .NET and .NET Framework (#4156).An object used as a rotating cache stops compacting forever. A property removed from an object's store leaves a tombstone, so that a re-added key keeps its creation order. Removing the newest entry already reclaimed its slot; removing the oldest — the shape of a bounded cache, a fresh name in and the oldest out — left a hole each time, and the table compacted every
capacity − liveadditions although the live set never grew: a 16-key rotation settled on a capacity of 64 and compacted 209 times per 10,000 steps. The entries are now a window that may wrap around the array, so a removal at either end retires its slot; the same rotation never resizes and settles on 32 (#4155).Chains that script can make as long as it likes no longer end the process. Resolving a property through a prototype chain recursed one native frame per link, so a 20,000-deep
{ __proto__: x }chain overflowed the native stack on a read, a write, aninor awithlookup and ended the process — nothing thrown, nothing for acatchto see (#4170, from #4078; issue #4076, reported by @Tielem).[[Get]],[[Set]]and[[HasProperty]]now walk the chain in a loop, so an ordinary or shaped-host-prototype chain of any depth simply answers.Function.prototype.bindchains had the same shape inIsConstructorand in the realm lookupnewandReflect.constructperform, and those are loops now too (#4169, from #4165); on .NET Framework the JIT happened to turn both into tail calls, so the process death was a .NET 8 / .NET 10 one.Two chains cannot be flattened, because each link has work of its own to do on the way back out: a proxy forwarding to a proxy, and host object wrappers stacked on each other (#4170, from #4125; issue #4087). Those are probed instead, and raise a catchable
RangeError— whenOptions.Constraints.StackOverflowGuardis on. On 4.x that guard remains opt-in (it becomes the default only in 5.0), so an engine left at its defaults still ends the process on a deep enough proxy chain. If you run script you do not control, turn the guard on; with it on, a 20,000-link proxy chain used as an array'sconstructoror asReflect.construct'snewTargetnow raisesRangeErrorwhere it used to end the process.%stops allocating for numbers. The remainder operator now takes the unboxed numeric lane multiplication and division already used, sosum += i % 97reads a numeric counter without materialising aJsNumberper step — on the benchmark's arithmetic loop, allocation per run drops from 2.87 MB to under 1 KB (#4167, from #4154).Intl.Locale.prototype.getWeekInforeads the region the specification picks. It read CLDR's week data for the tag's literal region subtag only, so a tag without one got the world's week and the-u-rg-and-u-sd-keywords were ignored. It now follows RegionPreference: a-u-rg-override, then the region subtag, then a-u-sd-subdivision's region, then the region Add Likely Subtags supplies, then001. This changes answers —new Intl.Locale('en').getWeekInfo().firstDayis now7(en is likely en-US, where the week starts on Sunday) rather than1, anden-US-u-rg-gbzzzzanswers1rather than7— in each case to what the specification and every browser give (#4168, from #4163).Verification
Every backport was verified failing-first: its tests were run against the unfixed
4.xtree on .NET 10 and .NET Framework 4.7.2, then with the change.JsonTests, 170parseInt, 124; radix literals, 21StringToBigInt, 46Intl.Localecanonicalization, 81getWeekInforegion preference, 26; test262getWeekInforegion files, 8PlainObjectcensusRelease diagnostics on the tagged commit's tree (
a19802dda703), in Release:Jint.Tests7,655 (net10.0) and 7,570 (net472);Jint.Tests.PublicInterface1,903 and 1,895;Jint.Tests.CommonScripts28 and 28;Jint.Tests.SourceGenerators52; the host-contract verification leg (JINT_HOST_CONTRACT_VERIFICATION=1) 7,655 / 7,570 and 1,907 / 1,899 — zero failures anywhere, and the PublicInterface surface snapshots unchanged. test262: 102,509 passed, 0 failed, 175 skipped — the 4.x control plus the eightgetWeekInfocases #4168 un-excluded. CI passed the same tree on Linux x64, Linux ARM64, Windows, macOS and the host-contract leg.The release was gated before the tag on a paired comparison against 4.16.3 —
DefaultJob, alternating order, on an idle machine with nothing else running and Defender's real-time scanning off — measuring the exact tree that was tagged. A three-round screen over 98 rows (SunSpider, Dromaeo, and the benchmarks for each backported lane) was followed by an eight-round re-measurement of every row that agreed in sign across the screen.HostPrototypeShape.AbsentNameMissOverChainPrototypeChainRead.AbsentNameReadHostPrototypeShape.DeepHitOverChain%without allocation (#4167)ModuloMaterialization.ArithmeticNumberParse.ParseFloatLoopNumberParse.NumberCoercePropertyDeleteChurn.RotateOldest[64]Json.Parse/Json.StringifyOne small, confirmed cost:
PropertyDeleteChurn.RotateBehindPinnedKey— rotating keys through an object whose oldest key is never deleted — is ~2% slower (+2.33% [+0.92, +2.46] 8/8 and +1.97% [+1.30, +2.77] 7/8). It is the one shape #4155's window cannot help, because the pinned key stops the window advancing and the store falls back to compacting as before;maincarries the identical code. It is the price of removing the unbounded compaction the ordinary rotation paid.What's Changed
Full Changelog: sebastienros/jint@v4.16.3...v4.16.4
v4.16.3Jint 4.16.3 is a maintenance release from the
4.xbranch: correctness and conformance fixes backported frommain, and nothing that changes an existing API or an existing default. If you are on 4.16.2 it is a drop-in update — every public signature is the one 4.16.0 shipped, on all five target frameworks, and the per-framework snapshots inJint.Tests.PublicInterface/Verify/are unchanged.mainremains 5.0.0 development; what is coming there is recorded as it lands indocs/v5-migration.md.Highlights
A long-lived engine stops accumulating what it has already run.
Evaluate(string)andExecute(string)parse a freshScripton every call, and the engine kept every one of them. Three of the four per-engine handler-tree caches already reset wholesale at 2048 entries so a host streaming endless distinct sources cannot grow them without bound; the fourth,_evaluatedScripts, never got that ceiling and held its keys strongly, retaining the AST of every distinct script the engine had ever evaluated — about 528 bytes per call, climbing forever and reclaimed by nothing short of dropping the engine (#4116). The realm's tagged-template map had the same shape and a harder constraint:Realm._templateMapwas aDictionary<Node, JsArray>, strong on both ends and never cleared, costing roughly 1.35 KB per call for a frozen array and its raw array. A ceiling is no remedy there, because evicting a live template site is script-visible —f() === f()must hold for one site — so it becomes aConditionalWeakTable<Node, WeakReference<JsArray>>, weak on both halves (#4119). Both matter most to exactly the embedding that looks innocuous: one engine, kept for the lifetime of the process, handed ad-hoc source.A suspended frame no longer dereferences what the suspension produced.
awaitandyieldsuspend by returning a plainundefined, and the enclosing member link turns that into a sentinel reference that every consumer must recognise before reading. Nine did not, so they readundefined.undefinedand raised aTypeErrorinside a frame that was already suspended.AsyncBlockStartswallowed that throw, but not before the statement-list resume position had been cleared on the way out — so the resume replayed the body from the first statement: one extra run of every un-awaited side effect per suspension point, and a re-entrancy guard silently truncating the rest. In a generator nothing swallows it and theTypeErrorcomes straight out ofnext(). Two shapes were wrong answers rather than repeated ones —(await p).x = 1rejected the promise, ando[await k] = 1assigned to the literal key"undefined"instead of the real one — andfor await ((await p).a of it)never terminated at all. Optional chaining was not the trigger despite where the report put it: the guarded fast lane needs a literal property name, so every computed member read of an awaited or yielded value fell through,(await p)[0]as much as(await p)[k](#4089, reported by @salihvatanseverv in #4086).Verification
Every change was verified failing-first against the unfixed branch. The suspension fix is pinned by 35 new cases in
Jint.Tests/Runtime/SuspendedOptionalChainTests.cs: against 4.16.2's code 28 fail and 6 pass on both .NET 10 and .NET Framework 4.7.2, with a 35th — thefor awaitshape — hanging the test host outright rather than failing; after the fix all 35 pass on both. The retention fixes are pinned byJint.Tests/Runtime/GarbageCollectionTests.csandTaggedTemplateCacheTests.cs.Release diagnostics on the tagged commit, in Release:
Jint.Tests7,170 (net10.0) and 7,085 (net472);Jint.Tests.PublicInterface1,852 and 1,844;Jint.Tests.CommonScripts28 and 28;Jint.Tests.SourceGenerators52; the host-contract verification leg (JINT_HOST_CONTRACT_VERIFICATION=1) 7,170 / 7,085 and 1,856 / 1,848 — zero failures anywhere. test262: 102,498 passed, 183 skipped, with three files crossing the engine's default 30-second budget under whole-suite CPU contention and passing in three seconds when run alone.The paired SunSpider and Dromaeo comparison against 4.16.2 was run after the tag rather than before it, which is a departure from how 4.16.2 was gated; it is recorded here because the result is what the release notes should carry, not the order it arrived in. No row regressed. Fifty-one rows, paired, alternating order,
DefaultJob, on an idle machine: the three-round screen left two candidates clearing the sign-agreement and magnitude bar, both of themDromaeo.StringBase64, and re-measuring those at eight rounds read −1.72% [−3.01, +1.98] and +0.30% [−3.10, +4.26] — no change, with a third parameter combination coming out faster.StringBase64is the rowJint.Benchmark/AGENTS.mdalready documents as a three-round false positive, and it behaved as documented. TheCubecontrol rows moved +0.6% to +0.8%, which is this machine's floor on rows the change cannot reach.Nothing here is a performance change by intent. #4119 does move a tagged-template lookup from a
Dictionaryto aConditionalWeakTableand #4089 adds suspension checks to several interpreter lanes, and neither is visible above the noise floor.What's Changed
Full Changelog: sebastienros/jint@v4.16.2...v4.16.3
v4.16.2Jint 4.16.2 is a maintenance release from the
4.xbranch: correctness and conformance fixes backported frommain, and nothing that changes an existing API or an existing default. If you are on 4.16.1 it is a drop-in update — every public signature is the one 4.16.0 shipped, on all five target frameworks, and the per-framework snapshots inJint.Tests.PublicInterface/Verify/are unchanged.mainremains 5.0.0 development; what is coming there is recorded as it lands indocs/v5-migration.md.Highlights
Failures that used to end the process, or never end. A native error raised while a call's arguments are being evaluated is propagated instead of leaving an empty value behind, which on 4.16.1 could recurse until the process died —
decodeURIComponenton a malformed sequence was enough (#4009). Native recursion and the forwarding paths through bound functions and proxies are guarded so a deep native chain raises a catchable error (#4007). A module graph too deep to link raises an error the host can catch instead of overflowing the stack (#3548). Temporal and Intl parsing cannot throw an uncatchableRegexMatchTimeoutExceptionbecause the machine was busy (#3543), a Temporal difference past a calendar's range raisesRangeErrorinstead of spinning forever (#3555), and the process-wide Intl culture cache and Temporal zone cache are read-only and bounded, with a rejected zone no longer remembered — closing a script-driven unbounded growth (#3546).Generators and built-ins, step by step. A
yield*delegation reached again by a loop both re-delegates and keeps its place:countdown(3)in a loop no longer hangs, and a delegating generator no longer returns the memoized first result (#3545).Array.prototype.mapandslicehand a@@speciesconstructor the lengthToLengthproduced, and a non-callablemapargument is aTypeError(#3547). A trailing NUL pads neither a numeric string nor an array index (#3552). A removed property slot is a tombstone rather than a free slot to reuse, so enumeration order survives a delete-and-readd (#3318), andLengthOfArrayLikeno longer clamps through auintoverload (#3328).Interop that answers for the right engine. Two engines in one process no longer decide each other's conversions and operators (#3559), a host type converter's answer stays with the engine whose converter gave it (#3563), and a value the host registers on a
ShadowRealm— and the members its wrapper builds eagerly — belong to that realm (#3557). Realm construction state is restored after nesting or a failure (#4008). Overload selection is by the arguments in hand: an operator overload is chosen that way (#3611), aparamsoverload is chosen by the array's element type with a failing element declining rather than throwing (#3782), an overload the argument cannot bind to is not a match, and a host operator that throws reports what it threw (#3554). An index on a wrapped host collection is one property however it is spelled, and a member filter that hides the indexer hides it (#3562); a read-only host collection refuses a write with a JavaScriptTypeErrorrather than the CLR'sNotSupportedException(#3556).Internationalization and Temporal. The Persian calendar extends into proleptic years on its 33-year cycle, so the ends of Temporal's range land in the right Persian year (#4006); a calendar that counts Gregorian months writes their names (#3612); and a
-u-extension carrying more than one key is read whole (#3613).Errors. Only a string-valued
stackcounts as a pre-existing stack when aJavaScriptExceptionis built, so an accessor or non-stringstackon a thrown object no longer breaks error reporting (#3677, reported by @jeske).Every change was verified failing-first against the unfixed branch on both .NET Framework and .NET 10, and the release was gated on a paired SunSpider and Dromaeo comparison against 4.16.1 on an idle machine: no row regressed outside run-to-run noise, most run 1–4 % faster.
What's Changed
-u-extension carrying more than one key is read whole (backport of #3594) by @lahma in #3613Full Changelog: sebastienros/jint@v4.16.1...v4.16.2
v4.16.1: 4.16.1Jint 4.16.1 is the first release from the new
4.xmaintenance branch, and it marks the point where the two lines separate:mainis now 5.0.0 development, and4.xis where the 4.16.x line continues.What that means for you. If you are on 4.16.0, this is a drop-in update — it is correctness and conformance work only, no API change and no changed default. Every public signature is the same one 4.16.0 shipped, on all five target frameworks. If you want the 4.x line, take it from
4.xand expect fixes rather than features. If you want to follow where the engine is going, watchmain— v5 brings breaking API changes, an opt-in WHATWG web API surface, Web Workers, Node compatibility and a raised .NET Framework floor, and every one of them is recorded as it lands indocs/v5-migration.md.From this release onward the 4.x public surface is snapshotted per target framework in
Jint.Tests.PublicInterface/Verify/, so "did the API move?" is a diff rather than a judgement call — on this branch a diff there is a bug, and comparing those files againstmain's is the v4→v5 delta.Highlights
Conformance, from a suite that now runs more of test262. The
staging/directory is generated and executed for the first time (#3016), which is roughly 2,800 additional cases — largely SpiderMonkey's own suite contributed upstream, covConfiguration
📅 Schedule: (UTC)
🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.
♻ Rebasing: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.
🔕 Ignore: Close this PR and you won't be reminded about this update again.
This PR was generated by Mend Renovate. View the repository job log.