Age | Commit message (Collapse) | Author |
|
Aligns the error messages in the ext/fetch folder to be in-line with the
Deno style guide.
https://github.com/denoland/deno/issues/25269
|
|
This is a primordialization effort to improve resistance against users
tampering with the global `Object` prototype.
---------
Co-authored-by: Bartek Iwańczuk <biwanczuk@gmail.com>
|
|
|
|
|
|
This commit refactors how we access "core", "internals" and
"primordials" objects coming from `deno_core`, in our internal JavaScript code.
Instead of capturing them from "globalThis.__bootstrap" namespace, we
import them from recently added "ext:core/mod.js" file.
|
|
|
|
Fixes a WPT in `URL` and `ReadableStream`.
Some unrelated WPT expectation changes due to WPT update.
|
|
This PR optimizes `fromInner*` methods of `Request` / `Header` /
`Response` used by `Deno.serve` and `fetch` by using `new` instead of
`ObjectCreate` from `createBranded`.
The "brand" is created by passing `webidl.brand` to the constructor
instead.
https://github.com/denoland/deno/blob/142449ecab20006c5cfd15462814650596bc034d/ext/webidl/00_webidl.js#L1001-L1005
### Benchmark
```js
const createBranded = Symbol("create branded");
const brand = Symbol("brand");
class B {
constructor(init) {
if (init === createBranded) {
this[brand] = brand;
}
}
}
Deno.bench("Object.create(protoype)", () => {
Object.create(B.prototype);
});
Deno.bench("new Class", () => {
new B(createBranded);
});
```
```
cpu: 13th Gen Intel(R) Core(TM) i9-13900H
runtime: deno 1.37.0 (x86_64-unknown-linux-gnu)
benchmark time (avg) iter/s (min … max) p75 p99 p995
----------------------------------------------------------------------------- -----------------------------
Object.create(protoype) 8.74 ns/iter 114,363,610.3 (7.32 ns … 26.02 ns) 8.65 ns 13.39 ns 14.47 ns
new Class 3.05 ns/iter 328,271,012.2 (2.78 ns … 9.1 ns) 3.06 ns 3.46 ns 3.5 ns
```
|
|
This PR optimizes Node's `IncomingMessageForServer.headers` by replacing
`Object.fromEntries()` with a loop and `headers.entries` with
`headersEntries` which returns the internal array directly instead of an
iterator
## Benchmarks
Using `wrk` with 5 headers
```
wrk -d 10s --latency -H "X-Deno: true" -H "Accept: application/json" -H "X-Foo: bar" -H "User-Agent: wrk" -H "Accept-Encoding: gzip, br" http://127.0.0.1:3000
```
**this PR**
```
Running 10s test @ http://127.0.0.1:3000
2 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 167.53us 136.89us 2.75ms 97.33%
Req/Sec 31.98k 1.38k 36.39k 70.30%
Latency Distribution
50% 134.00us
75% 191.00us
90% 234.00us
99% 544.00us
642548 requests in 10.10s, 45.96MB read
Requests/sec: 63620.36
Transfer/sec: 4.55MB
```
**main**
```
Running 10s test @ http://127.0.0.1:3000
2 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 181.31us 132.54us 3.79ms 97.13%
Req/Sec 29.21k 1.45k 32.93k 79.21%
Latency Distribution
50% 148.00us
75% 198.00us
90% 261.00us
99% 545.00us
586939 requests in 10.10s, 41.98MB read
Requests/sec: 58114.01
Transfer/sec: 4.16MB
```
```js
import express from "npm:express";
const app = express();
app.get("/", function (req, res) {
req.headers;
res.end();
});
app.listen(3000);
```
|
|
This PR makes more optimizations to headers iterable by removing
`ObjectEntries` which was consistently prominent in the flame graph when
benchmarking an express server.
**this PR**
```
cpu: 13th Gen Intel(R) Core(TM) i9-13900H
runtime: deno 1.36.1 (x86_64-unknown-linux-gnu)
benchmark time (avg) iter/s (min … max) p75 p99 p995
------------------------------------------------------------------ -----------------------------
headers iter 9.6 µs/iter 104,134.1 (8.74 µs … 131.31 µs) 9.47 µs 12.61 µs 17.81 µs
```
**main**
```
cpu: 13th Gen Intel(R) Core(TM) i9-13900H
runtime: deno 1.36.1 (x86_64-unknown-linux-gnu)
benchmark time (avg) iter/s (min … max) p75 p99 p995
------------------------------------------------------------------ -----------------------------
headers iter 12.87 µs/iter 77,675.9 (11.97 µs … 132.34 µs) 12.76 µs 16.49 µs 26.4 µs
```
```js
const headers = new Headers({
"Content-Type": "application/json",
"X-Content-Type": "application/json",
"Date": "Thu, 14 Aug 2023 17:45:10 GMT",
"X-Deno": "Deno",
"Powered-By": "Deno",
"Content-Encoding": "gzip",
"Set-Cookie": "__Secure-ID=123; Secure; Domain=example.com",
"Content-Length": "150",
"Vary": "Accept-Encoding, Accept, X-Requested-With",
});
Deno.bench('headers iter', () => {
[...headers]
})
```
|
|
This PR improves the performance of `Headers.get` by using `Regex.test`
instead of `.exec`. Also replaced the `Map` used for caching with an
object which is a bit faster
**This patch**
```
cpu: 13th Gen Intel(R) Core(TM) i9-13900H
runtime: deno 1.36.1 (x86_64-unknown-linux-gnu)
benchmark time (avg) iter/s (min … max) p75 p99 p995
----------------------------------------------------------------------- -----------------------------
Headers.get 124.71 ns/iter 8,018,687.3 (115.11 ns … 265.66 ns) 126.05 ns 136.12 ns 142.37 ns
```
**1.36.1**
```
cpu: 13th Gen Intel(R) Core(TM) i9-13900H
runtime: deno 1.36.0 (x86_64-unknown-linux-gnu)
benchmark time (avg) iter/s (min … max) p75 p99 p995
----------------------------------------------------------------------- -----------------------------
Headers.get 218.91 ns/iter 4,568,172.3 (165.37 ns … 264.44 ns) 241.62 ns 260.94 ns 262.67 ns
```
```js
const headers = new Headers({
"Content-Type": "application/json",
"Date": "Thu, 10 Aug 2023 07:45:10 GMT",
"X-Deno": "Deno",
"Powered-By": "Deno",
"Content-Encoding": "gzip",
"Set-Cookie": "__Secure-ID=123; Secure; Domain=example.com",
"Content-Length": "150",
"Vary": "Accept-Encoding, Accept, X-Requested-With",
});
Deno.bench("Headers.get", () => {
headers.get("x-deno");
});
```
|
|
This PR caches `_iterableHeaders` for immutable `Headers` increasing the
performance of `fetch` & server if headers are iterated.
Should close #19466
I only cached immutable headers to address this comment
https://github.com/denoland/deno/issues/19466#issuecomment-1589892373
since I didn't find any occurrence of header mutation on immutable
headers. We can discuss caching for non-immutable, but I think this is a
great first step.
## BENCHMARK
### Server
```js
const addr = Deno.args[0] ?? "127.0.0.1:4500";
const [hostname, port] = addr.split(":");
const { serve } = Deno;
serve({ hostname, port: Number(port), reusePort: true }, (req) => {
const headers = [...req.headers]; // req.headers are immutable, cannot set/append/delete
return new Response("ok");
});
```
Used `wrk` with 5 headers
```
wrk -d 10s --latency -H "X-Deno: true" -H "Accept: application/json" -H "X-Foo: bar" -H "User-Agent: wrk" -H "Accept-Encoding: gzip, br" http://127.0.0.1:4500
```
**This patch**
```
Running 10s test @ http://127.0.0.1:4500
2 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 70.18us 22.89us 679.00us 81.37%
Req/Sec 71.55k 9.69k 82.18k 89.60%
Latency Distribution
50% 59.00us
75% 89.00us
90% 98.00us
99% 159.00us
1437891 requests in 10.10s, 193.35MB read
Requests/sec: 142369.83
Transfer/sec: 19.14MB
```
**main**
```
Running 10s test @ http://127.0.0.1:4500
2 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 112.78us 36.47us 2.09ms 77.99%
Req/Sec 44.30k 1.65k 49.14k 74.26%
Latency Distribution
50% 99.00us
75% 136.00us
90% 162.00us
99% 213.00us
890588 requests in 10.10s, 118.91MB read
Requests/sec: 88176.37
Transfer/sec: 11.77MB
```
### fetch
```js
const res = await fetch('http://127.0.0.1:4500');
Deno.bench("Headers iterator", () => {
const i = [...res.headers]; // res.headers are immutable, cannot set/append/delete
});
```
**this patch**
```
cpu: 13th Gen Intel(R) Core(TM) i9-13900H
runtime: deno 1.36.1 (x86_64-unknown-linux-gnu)
benchmark time (avg) iter/s (min … max) p75 p99 p995
---------------------------------------------------------------------- -----------------------------
Headers iterator 329.5 ns/iter 3,034,909.0 (318.55 ns … 364.34 ns) 331.1 ns 355.72 ns 364.34 ns
```
**main**
```
cpu: 13th Gen Intel(R) Core(TM) i9-13900H
runtime: deno 1.36.1 (x86_64-unknown-linux-gnu)
benchmark time (avg) iter/s (min … max) p75 p99 p995
---------------------------------------------------------------------- -----------------------------
Headers iterator 2.59 µs/iter 386,372.1 (2.56 µs … 2.68 µs) 2.59 µs 2.68 µs 2.68 µs
```
|
|
This PR optimizes the `getHeader` function by replacing `.filter` and
`.map` with a `for` loop
**this patch**
```
cpu: 13th Gen Intel(R) Core(TM) i9-13900H
runtime: deno 1.36.0 (x86_64-unknown-linux-gnu)
benchmark time (avg) iter/s (min … max) p75 p99 p995
----------------------------------------------------------------- -----------------------------
Headers.get 132.2 ns/iter 7,564,093.4 (125.81 ns … 147.66 ns) 133.79 ns 144.92 ns 145.36 ns
```
**main**
```
cpu: 13th Gen Intel(R) Core(TM) i9-13900H
runtime: deno 1.36.0 (x86_64-unknown-linux-gnu)
benchmark time (avg) iter/s (min … max) p75 p99 p995
----------------------------------------------------------------- -----------------------------
Headers.get 191.48 ns/iter 5,222,523.6 (182.75 ns … 212.22 ns) 193.5 ns 205.96 ns 211.51 ns
```
```js
const headers = new Headers({
"Content-Type": "application/json",
"Date": "Thu, 10 Aug 2023 07:45:10 GMT",
"X-Deno": "Deno",
"Powered-By": "Deno",
"Content-Encoding": "gzip",
"Set-Cookie": "__Secure-ID=123; Secure; Domain=example.com",
"Content-Length": "150",
"Vary": "Accept-Encoding, Accept, X-Requested-With",
});
Deno.bench("Headers.get", () => {
const i = headers.get("x-deno");
});
```
|
|
|
|
Spec change: https://github.com/whatwg/fetch/pull/1346
Tests: https://github.com/web-platform-tests/wpt/pull/31442 (ran against
this PR and they all pass)
---------
Co-authored-by: Bartek Iwańczuk <biwanczuk@gmail.com>
|
|
|
|
Use `Map` to cache validated HTTP headers. Cache
has a capacity of 4096 elements and it's cleared
once that capacity is reached.
In `preactssr` benchmark it lowers the time spent
when adding headers from 180ms to 2.5ms.
|
|
Towards https://github.com/denoland/deno/issues/19330
Shows about 1% improvement in the HTTP benchmark.
|
|
`ObjectPrototypeHasOwnProperty` (#18952)
ES2022 `Object.hasOwn` can be used in snapshot, so I migrate to use it.
|
|
|
|
Creating these options bags is more costly than passing arguments
one-by-one. Especially since `prefix` and `context` are passed to all functions.
|
|
This should produce a little less garbage and using an object here
wasn't really required.
---------
Co-authored-by: Aapo Alasuutari <aapo.alasuutari@gmail.com>
Co-authored-by: Leo Kettmeir <crowlkats@toaxl.com>
|
|
for snapshotted modules (#18041)
This commit renames "deno_core::InternalModuleLoader" to
"ExtModuleLoader" and changes the specifiers used by the
modules loaded from this loader to "ext:".
"internal:" scheme was really ambiguous and it's more characters than
"ext:", which should result in slightly smaller snapshot size.
Closes https://github.com/denoland/deno/issues/18020
|
|
|
|
|
|
This PR refactors all internal js files (except core) to be written as
ES modules.
`__bootstrap`has been mostly replaced with static imports in form in
`internal:[path to file from repo root]`.
To specify if files are ESM, an `esm` method has been added to
`Extension`, similar to the `js` method.
A new ModuleLoader called `InternalModuleLoader` has been added to
enable the loading of internal specifiers, which is used in all
situations except when a snapshot is only loaded, and not a new one is
created from it.
---------
Co-authored-by: Bartek Iwańczuk <biwanczuk@gmail.com>
|
|
|
|
Yearly tradition of creating extra noise in git.
|
|
Introduces `SafeSetIterator` and `SafeMapIterator` to primordials
|
|
This PR fixes invalid header parsing which is flaky because `g` flag is
being used in the regex, which keeps track of `lastIndex`
```javascript
try {
new Headers([["x", "\u0000x"]]); // error
} catch(e) {}
new Headers([["x", "\u0000x"]]); // no error
```
This issue affects `Response` & `Request` constructors as well
|
|
|
|
|
|
|
|
|
|
(#13497)" (#13511)
This reverts commit 884143218fad0e18f7553aaf079d52de703f7601.
|
|
|
|
Co-authored-by: Erfan Safari <erfanshield@outlook.com>
|
|
This reverts commit 49ec3d10ad90851f4d28274a3f0fe96c642204ac.
|
|
Reduces self-time by ~70x (~70ms => ~1ms on 1M iters)
for...in filtered by hasOwnProperty yields the same set of keys as Object.keys()
|
|
Use a regex substring match with a first/last char fastpath instead of 2 regex replaces. Roughly ~400x faster (423ms vs 0.7ms in profiled runs)
|
|
Use a single regex to check for `\0`, `\n`, `\r` instead of 3 `String.includes(...)` calls
|
|
Co-authored-by: Luca Casonato <hello@lcas.dev>
Co-authored-by: Yoshiya Hinosawa <stibium121@gmail.com>
|
|
|
|
|