Join GitHub today
GitHub is home to over 50 million developers working together to host and review code, manage projects, and build software together.
Sign upImplement Houdini worklets #16814
Implement Houdini worklets #16814
Conversation
highfive
commented
May 11, 2017
|
Heads up! This PR modifies the following files:
|
highfive
commented
May 11, 2017
|
r? @jdm |
|
cc @bfgeek |
|
Some things that should probably be fixed before this lands:
The code is ready for review as-is though. |
|
Hi @bfgeek! This is implementation of worklets in Servo, using a thread pool to ensure worklet execution isn't blocked by GC or by module loading. Mostly the spec was pretty straightforward to implement, you'll be pleased to hear! |
|
The spec issues raised by implementing worklets (and starting on paint worklets):
|
bfgeek
commented
May 12, 2017
|
cc/ @nhiroki who works on our implementation. That's great to see! Thanks for filing spec issues. |
|
|
| // https://drafts.css-houdini.org/worklets/#examples | ||
| partial interface Window { | ||
| [Pref="dom.worklet.testing.enabled", SameObject] readonly attribute Worklet testWorklet; | ||
| [Pref="dom.worklet.testing.enabled"] DOMString? testWorkletLookup(DOMString key); |
This comment has been minimized.
This comment has been minimized.
jdm
May 16, 2017
Member
What if we made a separate DOM interface with a constructor so we don't need to include test-only fields in Window?
This comment has been minimized.
This comment has been minimized.
| pub mem_profiler_chan: mem::ProfilerChan, | ||
| /// Chan to the time profiler | ||
| pub time_profiler_chan: time::ProfilerChan, | ||
| /// Chan to devtools |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
| use style::thread_state; | ||
| use swapper::Swapper; | ||
| use swapper::swapper; | ||
| use uuid::Uuid; |
This comment has been minimized.
This comment has been minimized.
jdm
May 16, 2017
Member
Any reason not to collapse some of these import statements from the same modules?
This comment has been minimized.
This comment has been minimized.
| let global = window.upcast::<GlobalScope>(); | ||
| unsafe { | ||
| WorkletBinding::Wrap(global.get_cx(), global, worklet) | ||
| } |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
asajeffrey
May 16, 2017
Author
Member
I don't think you can use reflect_dom_object to create globals can you?
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
| self.worklet_id | ||
| } | ||
|
|
||
| #[allow(dead_code)] |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
asajeffrey
May 16, 2017
Author
Member
This is dead code, just in for future-proofing. I can get rid of it.
| #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, JSTraceable)] | ||
| pub struct WorkletId(Uuid); | ||
|
|
||
| known_heap_size!(0, WorkletId); |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
| } | ||
|
|
||
| fn decrement_counter_by(&self, offset: isize) -> isize { | ||
| self.0.fetch_sub(offset, Ordering::AcqRel) |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
asajeffrey
May 16, 2017
Author
Member
Using the weakest ordering that does the job. In this case it doesn't matter a huge amount, this isn't hot code.
| debug!("Finished adding script."); | ||
| let old_counter = pending_tasks_struct.decrement_counter_by(1); | ||
| if old_counter == 1 { | ||
| // TODO: trigger a reflow? |
This comment has been minimized.
This comment has been minimized.
jdm
May 16, 2017
Member
This happens automatically when events run in the script thread. Did you mean something more specific?
This comment has been minimized.
This comment has been minimized.
asajeffrey
May 16, 2017
Author
Member
At this point, we have loaded a worklet, but not actually run it (e.g. to get a paint worklet to do its painting).
| } | ||
|
|
||
| /// Fetch and invoke a worklet script. | ||
| ///g https://drafts.css-houdini.org/worklets/#fetch-and-invoke-a-worklet-script |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
|
As usual, I found these changes to be a pleasant and straightforward read. Good job! |
| type_: RequestType::Script, | ||
| destination: Destination::Script, | ||
| credentials_mode: credentials.into(), | ||
| .. RequestInit::default() |
This comment has been minimized.
This comment has been minimized.
jdm
May 16, 2017
Member
We should be using CORS mode here, per https://html.spec.whatwg.org/multipage/webappapis.html#fetch-a-single-module-script. We'll need to include a real origin, too.
This comment has been minimized.
This comment has been minimized.
asajeffrey
May 16, 2017
Author
Member
CORS mode isn't a problem, but I'm not sure which origin to use here. One snag is that this is being done in a different thread, so we don't have access to the MutableOrigin of the window.
This comment has been minimized.
This comment has been minimized.
|
Thanks for the review! |
| // https://drafts.css-houdini.org/worklets/#examples | ||
| partial interface Window { | ||
| [Pref="dom.worklet.testing.enabled", SameObject] readonly attribute Worklet testWorklet; | ||
| [Pref="dom.worklet.testing.enabled"] DOMString? testWorkletLookup(DOMString key); |
This comment has been minimized.
This comment has been minimized.
| pub mem_profiler_chan: mem::ProfilerChan, | ||
| /// Chan to the time profiler | ||
| pub time_profiler_chan: time::ProfilerChan, | ||
| /// Chan to devtools |
This comment has been minimized.
This comment has been minimized.
| use style::thread_state; | ||
| use swapper::Swapper; | ||
| use swapper::swapper; | ||
| use uuid::Uuid; |
This comment has been minimized.
This comment has been minimized.
| let global = window.upcast::<GlobalScope>(); | ||
| unsafe { | ||
| WorkletBinding::Wrap(global.get_cx(), global, worklet) | ||
| } |
This comment has been minimized.
This comment has been minimized.
asajeffrey
May 16, 2017
Author
Member
I don't think you can use reflect_dom_object to create globals can you?
| self.worklet_id | ||
| } | ||
|
|
||
| #[allow(dead_code)] |
This comment has been minimized.
This comment has been minimized.
asajeffrey
May 16, 2017
Author
Member
This is dead code, just in for future-proofing. I can get rid of it.
| #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, JSTraceable)] | ||
| pub struct WorkletId(Uuid); | ||
|
|
||
| known_heap_size!(0, WorkletId); |
This comment has been minimized.
This comment has been minimized.
| } | ||
|
|
||
| fn decrement_counter_by(&self, offset: isize) -> isize { | ||
| self.0.fetch_sub(offset, Ordering::AcqRel) |
This comment has been minimized.
This comment has been minimized.
asajeffrey
May 16, 2017
Author
Member
Using the weakest ordering that does the job. In this case it doesn't matter a huge amount, this isn't hot code.
| } | ||
|
|
||
| /// Fetch and invoke a worklet script. | ||
| ///g https://drafts.css-houdini.org/worklets/#fetch-and-invoke-a-worklet-script |
This comment has been minimized.
This comment has been minimized.
| type_: RequestType::Script, | ||
| destination: Destination::Script, | ||
| credentials_mode: credentials.into(), | ||
| .. RequestInit::default() |
This comment has been minimized.
This comment has been minimized.
asajeffrey
May 16, 2017
Author
Member
CORS mode isn't a problem, but I'm not sure which origin to use here. One snag is that this is being done in a different thread, so we don't have access to the MutableOrigin of the window.
| debug!("Finished adding script."); | ||
| let old_counter = pending_tasks_struct.decrement_counter_by(1); | ||
| if old_counter == 1 { | ||
| // TODO: trigger a reflow? |
This comment has been minimized.
This comment has been minimized.
asajeffrey
May 16, 2017
Author
Member
At this point, we have loaded a worklet, but not actually run it (e.g. to get a paint worklet to do its painting).
|
Squash and r=me. |
|
@bors-servo r=jdm |
|
|
Implement Houdini worklets <!-- Please describe your changes on the following line: --> This PR implements the current draft Houdini Worklets specification (https://drafts.css-houdini.org/worklets/). The implementation is intended to provide a responsive environment for worklet execution, and in particular to ensure that the primary worklet executor does not garbage collect, and does not block loading module code. The implementation does this by providing a thread pool, and performing GC and module loading in a backup thread, not in the primary thread. --- <!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data: --> - [x] `./mach build -d` does not report any errors - [x] `./mach test-tidy` does not report any errors - [x] These changes fix #16206 - [x] There are tests for these changes <!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.--> <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. --> <!-- Reviewable:start --> --- This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/16814) <!-- Reviewable:end -->
|
|
We can either hide the Worklet interface behind an off-by-default pref or update the test to include the interface in the expected list. |
|
I added |
|
|
Implement Houdini worklets <!-- Please describe your changes on the following line: --> This PR implements the current draft Houdini Worklets specification (https://drafts.css-houdini.org/worklets/). The implementation is intended to provide a responsive environment for worklet execution, and in particular to ensure that the primary worklet executor does not garbage collect, and does not block loading module code. The implementation does this by providing a thread pool, and performing GC and module loading in a backup thread, not in the primary thread. --- <!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data: --> - [x] `./mach build -d` does not report any errors - [x] `./mach test-tidy` does not report any errors - [x] These changes fix #16206 - [x] There are tests for these changes <!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.--> <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. --> <!-- Reviewable:start --> --- This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/16814) <!-- Reviewable:end -->
|
|
asajeffrey commentedMay 11, 2017
•
edited by larsbergstrom
This PR implements the current draft Houdini Worklets specification (https://drafts.css-houdini.org/worklets/).
The implementation is intended to provide a responsive environment for worklet execution, and in particular to ensure that the primary worklet executor does not garbage collect, and does not block loading module code. The implementation does this by providing a thread pool, and performing GC and module loading in a backup thread, not in the primary thread.
./mach build -ddoes not report any errors./mach test-tidydoes not report any errorsThis change is