perf(ext/web): fast path for TextEncoder.encodeInto (#33675)
## Summary
Every call to `encoder.encodeInto(string, uint8array)` was going through
two WebIDL converters and allocating a fresh `{ allowShared: true }`
options object — the Uint8Array converter's opts is keyword-arg-style,
so a fresh object literal is built on every call. For small inputs the
converter chain plus that allocation is a ~45% tax on top of the
actual op cost.
This PR adds an inline guard at the top of `encodeInto`: if `source`
is already a string and `destination` is already a `Uint8Array`
(`@@toStringTag === "Uint8Array"`), skip both converters and call
`op_encoding_encode_into` directly.
The op handler already replaces lone surrogates with `U+FFFD`,
matching `USVString` semantics — which is why the existing slow path
was using `DOMString` rather than `USVString` and noting the spec
deviation in the comment that this PR keeps.
For the slow path (non-string `source`, non-`Uint8Array` `destination`,
e.g. `encodeInto(123, dataView)`), behaviour is identical: the
converters still run and throw / coerce as before. The shared
`{ allowShared: true }` opts object is hoisted to module scope so
even the slow path no longer allocates it on every call.
## Numbers
`cargo bench -p deno_web --bench encoding`, release, mean of 5 runs:
| bench | before | after | Δ |
|---|---:|---:|---:|
| `bench_encode_into_short` | 297 ns/iter | 161 ns/iter | **−45.8%** |
`ns/iter` is the bench harness loop time for 1000 inner iterations,
so per-call this is ~136 ns saved on a ~285 ns operation. The added
bench encodes a 12-byte string into a 64-byte buffer with a reused
`TextEncoder` — the shape every streaming encoder / incremental writer
hits in a tight loop.