-
Notifications
You must be signed in to change notification settings - Fork 108
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: Pure JS custom host objects #207
Conversation
Is it possible that you are getting a |
dd58fec
to
0410188
Compare
Have tracked this down to a rusty_v8 bug and filed denoland/rusty_v8#1323. |
fde7947
to
13b7d75
Compare
13b7d75
to
62a0fed
Compare
I think this is now ready for review. The relevant tests in deno pass:
|
Running some benchmarks with this branch it looks like the ~30% slowdown I observed in benchmarking my changes to Deno.serve came specifically from calling I had thought that function fromInnerRequest(inner, signal, guard) {
const request = core.createHostObject(RequestPrototype);
request[webidl.brand] = webidl.brand;
request[_request] = inner;
request[_signal] = signal;
request[_getHeaders] = () => headersFromHeaderList(inner.headerList, guard);
return request;
} ... is as slow as the old code with: function fromInnerRequest(inner, signal, guard) {
const request = ops.op_create_host_object();
ObjectSetPrototypeOf(request, RequestPrototype);
request[_request] = inner;
request[_signal] = signal;
request[_getHeaders] = () => headersFromHeaderList(inner.headerList, guard);
return request;
} ... and is 30% slower than both: function fromInnerRequest(inner, signal, guard) {
const request = webidl.createBranded(Request);
request[core.hostObjectBrand] = core.hostObjectBrand;
request[_request] = inner;
request[_signal] = signal;
request[_getHeaders] = () => headersFromHeaderList(inner.headerList, guard);
return request;
} .. or: function fromInnerRequest(inner, signal, guard) {
const request = ObjectCreate(RequestPrototype);
request[webidl.brand] = webidl.brand;
request[core.hostObjectBrand] = core.hostObjectBrand;
request[_request] = inner;
request[_signal] = signal;
request[_getHeaders] = () => headersFromHeaderList(inner.headerList, guard);
return request;
} But either way, deno currently has 32 calls to |
62a0fed
to
71083d1
Compare
Hey @lrowe, sorry for a slow turnaround. I will review all your PRs in the coming days 👍 |
439f03f
to
39ee635
Compare
Unfortunately it's not possible to run the CI workflow when rusty_v8 is set to a git checkout:
|
@bartlomieju it would be great if you could take a look at the associated rusty_v8 change first, denoland/rusty_v8#1322. Not having to recompile v8 makes development much easier. |
39ee635
to
2c918bb
Compare
@lrowe so sorry for a slow turnaround. I'm in the process of doing a rusty_v8 release which will include you PR. I'll ping you here again once it's all done. |
@lrowe |
2c918bb
to
5143d5c
Compare
Question for reviewers: What's the best way to deprecate Per the comment above, it is much slower than assigning the brand directly. The only place it is currently used is in the deno MessagePort code (PR changing that: denoland/deno#21358.) Should we simply remove |
It's fine to remove it outright, no need to deprecate this one since it's mostly "internal" API |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One suggestion, but otherwise LGTM 👍
5143d5c
to
c4149dc
Compare
UPDATE: added Benchmark from denoland/deno#20730 with addition of Deno.bench("structuredClone object", () => {
structuredClone({ foo: "bar" });
});
Deno.bench("structuredClone transferables", () => {
const buf = new Uint8Array([97]);
structuredClone(buf, {
transfer: [buf.buffer],
});
});
Deno.bench("structuredClone many objects", (b) => {
const array = Array.from({ length: 1000 }, (_, index) => ({ index }));
b.start();
structuredClone(array);
b.end();
});
Deno.bench("new MessageChannel", () => {
new MessageChannel();
}); This PR with
This PR with alternative
Current main at base commit:
UPDATE: This PR with looking up symbol once:
|
c4149dc
to
3e4e100
Compare
With the benchmark above showing 6x faster usage of host objects vs 50% slower structuredClone of many objects I wonder if we can minimize the structuredClone performance penalty when dealing with many objects. I could try looking up the In addition to the code from this PR in Does that scope object need to be created per invocation of |
3e4e100
to
153cf31
Compare
So stashing the symbol global in the serializer cuts out most of the overhead for many objects. Benchmark added above, it's about ~12% hit which seems acceptable given the much larger speed up for working with host objects. |
Avoids substantial slowdown caused by host objects with embedder fields. * Depends on: denoland/rusty_v8#1322 * Depends on: denoland/rusty_v8#1324 * Deno bug: denoland/deno#12067
153cf31
to
0d87a9d
Compare
I think this is ready to merge now. I've tweaked it so that the global symbol is only looked up in op_serializer and not op_deserializer. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, looking forward to improvements in Deno!
Thanks @bartlomieju! Note that denoland/deno#21358 will need to be merged when deno's deno_core dependency is updated since createHostObject has been removed. |
Yup, I'll cut another release this week |
Avoids substantial slowdown caused by host objects with embedder fields.
for_global
in favour offor_key
andfor_api
rusty_v8#1324