update speaker notes

This commit is contained in:
2026-08-24 19:32:39 -04:00
parent 2bf247b653
commit 617ccaae44
2 changed files with 160 additions and 50 deletions
+113 -1
View File
@@ -7,7 +7,6 @@ paginate: true
footer: <span> <img src="images/qb-logo-mark.png" width="60"/> Sept 2026 </span>
html: "true"
---
<!-- all slideshow styling in one place -->
<style>
/* font setup */
section {
@@ -44,6 +43,13 @@ html: "true"
### Ed Guloien
<!--
Have you ever wanted to add your own crate
Or write your own Web API to your favourite browser?
My name is Ed Guloien and today
I'm going to tell you how.
-->
<!-- disable page numbering on title page -->
<!-- _paginate: false -->
@@ -85,12 +91,26 @@ html: "true"
</div>
</div>
<!--
I'm a Senior Software Developer,
Formerly working on the Web Platform Networking team at Mozilla.
Currently writing rust full time Quantum Bridge working on Distributed Symmetric Key Exchange.
-->
---
## Interop 2025
![bg width:600px](images/interop-2025-2.png)
![bg width:600px](images/interop-2025-3.png)
<!--
There is an initiative to improve web compatibility by improving Web API implementations
across the major browsers.
It's called Interop and it happens every year.
And a hundred years ago, for Interop 2025,
I implemented the URLPattern Web API.
-->
---
## URLPattern Web API
@@ -106,6 +126,11 @@ pattern.test("https://example.com/books/123");
pattern.exec("https://example.com/books/123").pathname.groups
```
<!--
URLPattern is basically pattern matching for URLs and their components.
We can construct a pattern object and match strings against it.
-->
---
## Denoland & Firefox
@@ -113,16 +138,42 @@ pattern.exec("https://example.com/books/123").pathname.groups
![bg width:600px](images/urlpattern-fission.drawio.png)
<!--
Luckily for us there is an existing open source implementation by Denoland, written in rust.
So all we have to do is figure out how to incorporate it into Firefox.
This is Firefox's Fission Architecture,
it isolates web content from other web content.
We need URLPattern everywhere:
* for each web content process
* and for Compression Dictionaries in the main process.
So we add it to libXUL, a common library within Firefox.
-->
-------
## Web API Call Flow
![bg center width:1000px](images/urlpattern-call-flow.drawio.png)
<!--
We fork Denoland's crate by vetting, vendoring and telling the build system to compile it.
This works just ffine.
But Firefox's Browser Engine is mostly C++ and we're missing a call path.
* So we generate JS_callable C++ bindings from a webIDL file
* Implement a DOM wrapper that will forward the calls to our gloue crate
* And Tell the build system about our FFI glue crate
* It uses cbindgen to generate headers for C++ compilation against rust
* And include a C++ convenience wrapper and make our rust call the crate
-->
-----
## Urlpattern Crate API
![bg center width:850px](images/urlpattern-details-simple.drawio.png)
<!--
The crate API exposes a trait called RegExp and a few functions to go with it.
We simply implement trait, and call the functions to create patterns and match against them.
-->
----
## Glue Crate
@@ -133,6 +184,11 @@ let results = quirks::process_match(pattern, input);
// call it a day
```
<!--
Easy Peazy, right?
well,
not so fast.
-->
-----
## Reality Sets In (Memory Concerns)
@@ -154,11 +210,32 @@ glue::process_match(..., res: *mut MatchResults, other: MaybeString)
glue::doing_thing(..., res: &mut ThinVec<>);
```
<!--
Non-POD objects need to be passed-by-reference across the FFI.
* And since our common C ABI doesn't have references, cbindgen degrades our references to raw pointers.
* And if the object exposes internal types unknown to the other side you need an opaque pointer to hide those details.
* This leads to all sorts of unsafe pointer voodoo
Similarly, to represent options we use pointers, or write wrapper bindings to hide the gory details.
But sometimes we get lucky and find a specialized FFI type that can handle the ownership model difference between C++ and Rust
-->
----
## Pattern Re-use; Marshaling
![bg center width:1000px](images/urlpattern-pattern-reuse.drawio.png)
<!--
We get that working and quickly notice that
Pattern construction is the most expensive part of using URLPattern.
So we cannot feasibly do it on every match.
* So to save some cycles we pass the pattern object to the closest persistent object,
* all the way back in the generated DOM bindings,
* and write the additional marshaling to do it.
With that done, when the user requests a match: we pass the pattern along to the crate.
To avoid memory leaks, when the DOM binding goes out of scope the pattern is destroyed by it's rust creator.
-->
------
## 99.8%
@@ -166,13 +243,43 @@ glue::doing_thing(..., res: &mut ThinVec<>);
regex::Regex != EcmaScript Regex
```
<!--
If you get this far
You're pretty much there, with decent performance.
But if you want the whole banana, you have to know
* that rust::regex is not EcmaRegex compliant
* and the urlpattern crate uses rust::regex by default.
Luckily for us, we're in Firefox,
we already HAVE an EcmaRegex in SpiderMonkey, the Javascript engine
-->
----
## Spidermonkey Challenges (many)
![bg center width:825px](images/urlpattern-spidermonkey-challenges.drawio.png)
<!--
But it comes at the cost of toil.
We write similar FFI going the back to C++ to access SpiderMonkey.
But this API was not designed for C++ use.
* It requires JS context, which we lost through all the marshaling.
* It uses Garbage Collection.
* Calling JS can be interrupted to prioritize other JS.
So we cast some spells:
* we spin up a JS context,
* we prevent Spidermonkey from interrupting execution,
* we root the objects to a context that is safe from GC
* AND convert between UTF-8 and 16 as needed.
-->
-----
## And if you do all that...
...
-------
## Phew!
@@ -187,3 +294,8 @@ regex::Regex != EcmaScript Regex
- https://searchfox.org/firefox-main
- https://github.com/denoland/rust-urlpattern
- See also: https://manuelbucher.com/blog/rust-gecko/
<!--
You're done.
Now you can add your own crates and Web API's to your favourite open source browser.
-->
+47 -49
View File
@@ -1,101 +1,99 @@
---------
(Title page)
Have you ever wanted to add your own crate to your favourite open source browser?
Or write your own Web API to your own custom browser fork?
My name is Ed Guloien and today I'm going to tell you how and what to watch out for.
Have you ever wanted to add your own crate
Or write your own Web API to your favourite browser?
My name is Ed Guloien and today
I'm going to tell you how.
(about://ed-guloien)
I'm a Senior Software Developer,
Formerly working on the Web Platform Networking team at Mozilla.
Currently at Quantum Bridge working on Distributed Symmetric Key Exchange
Interested in privacy, security and systems programming
Currently writing rust full time Quantum Bridge working on Distributed Symmetric Key Exchange.
(Interop 2025)
For the unfamiliar there is an initiative to improve web compatibility
by improving pre-selected Web API implementations across all browsers.
It's called Interop.
And a hundred years ago, for Interop 2025, I implemented the URLPattern Web API.
There is an initiative to improve web compatibility by improving Web API implementations
across the major browsers.
It's called Interop and it happens every year.
And a hundred years ago, for Interop 2025,
I implemented the URLPattern Web API.
(URLPattern Web API)
URLPattern is basically pattern matching supporting ECMAScript Regex
for URLs and their components.
From Web JavaScript we construct a pattern and match strings against it.
URLPattern is basically pattern matching for URLs and their components.
We can construct a pattern object and match strings against it.
(Denoland crate and Firefox)
Luckily for me there is an existing open source implementation by Denoland, written in rust.
So all I have to do is figure out how to incorporate it into Firefox.
Luckily for us there is an existing open source implementation by Denoland, written in rust.
So all we have to do is figure out how to incorporate it into Firefox.
This is Firefox's Fission Architecture,
it isolates web content from other web content, roughly by origin.
And we have the main process handling orchestration and networking.
it isolates web content from other web content.
We need URLPattern everywhere:
* for each content process
* for each web content process
* and for Compression Dictionaries in the main process.
So we add it to the very common libXUL library within Firefox.
So we add it to libXUL, a common library within Firefox.
(WebAPI call flow to crate)
We fork Denoland's crate by vetting and vendoring it in to libXUL, inside gkrust.
And that compiles just fine.
But Firefox's Browser Engine, Gecko, is mostly C++.
* So we tell the build system about our FFI glue crate
* We use cbindgen to generate the headers required for compiling C++ against rust.
* Then generate JS-callable-C++-bindings from a webIDL file
* And implement the DOM wrapper that forwards the call to our glue crate.
We fork Denoland's crate by vetting, vendoring and telling the build system to compile it.
This works just ffine.
But Firefox's Browser Engine is mostly C++ and we're missing a call path.
* So we generate JS_callable C++ bindings from a webIDL file
* Implement a DOM wrapper that will forward the calls to our gloue crate
* And Tell the build system about our FFI glue crate
* It uses cbindgen to generate headers for C++ compilation against rust
* And include a C++ convenience wrapper and make our rust call the crate
(UrlPattern crate API)
Then we call the crate from our rust glue.
The crate API exposes a trait called RegExp and a few functions to go with it.
We simply implement trait, and call the functions to create patterns and match against them.
(Glue Crate)
Easy Peazy,
Easy Peazy, right?
well,
not so fast.
(Reality Sets In)
Non-POD objects need to be passed-by-reference across the FFI.
* And since our common C ABI doesn't have references, cbindgen degrades our references to raw pointers.
* And if the object exposes internal types unknown to the other side you need an opaque pointer (a void pointer) to hide those details.
* This leads to unsafe, pointer casts, dereferences, return parameters and so on.
Similarly we use pointers to represent options, or write wrapper bindings to hide the gory details.
But sometimes we are lucky and can use specialized FFI types to that can handle the ownership model difference between C++ and Rust
* And if the object exposes internal types unknown to the other side you need an opaque pointer to hide those details.
* This leads to all sorts of unsafe pointer voodoo
Similarly, to represent options we use pointers, or write wrapper bindings to hide the gory details.
But sometimes we get lucky and find a specialized FFI type that can handle the ownership model difference between C++ and Rust
(Pattern re-use)
We get that working and quickly notice that
Pattern construction is the most expensive part of using URLPattern.
We cannot feasibly do it on every match.
So we cannot feasibly do it on every match.
* So to save some cycles we pass the pattern object to the closest persistent object,
* all the way back in the generated DOM bindings,
* subjecting our pattern object to further marshaling across the ownership models.
But with that done, when the user requests a match or closes the page,
we pass the pattern to the rust crate for use or deletion.
* and write the additional marshaling to do it.
With that done, when the user requests a match: we pass the pattern along to the crate.
To avoid memory leaks, when the DOM binding goes out of scope the pattern is destroyed by it's rust creator.
(99.8%)
If you can get past all that,
If you get this far
You're pretty much there, with decent performance.
But if you want to go all the way you have to know
But if you want the whole banana, you have to know
* that rust::regex is not EcmaRegex compliant
* and the urlpattern crate uses rust::regex by default.
Luckily for us, we're in Firefox,
we already HAVE an EcmaRegex implementation living in the SpiderMonkey Javascript engine
we already HAVE an EcmaRegex in SpiderMonkey, the Javascript engine
(Spidermonkey Challenges)
But it comes at the cost of toil.
We write similar FFI going the back to C++ to access SpiderMonkey.
But this API was not designed for C++ use.
* It requires JS context, which we lost touch with through the marshaling.
* It has a completely different memory model using Garbage Collection.
* A typical Web JS runtime can be interrupted to prioritize other JS.
* AND it uses UTF-16 by default, unlike Rust's UTF-8.
* It requires JS context, which we lost through all the marshaling.
* It uses Garbage Collection.
* Calling JS can be interrupted to prioritize other JS.
So we cast some spells:
* we spin up a JS context,
* we prevent Spidermonkey from interrupting it's execution,
* we root the objects to a context that will prevent the GC from marking them for deletion
* we prevent Spidermonkey from interrupting execution,
* we root the objects to a context that is safe from GC
* AND convert between UTF-8 and 16 as needed.
And if you do all that...
(Phew!)
Phew! All done.
Now you can add your own crates and WebAPI's
to an open source browser.
(references)
You're done.
Now you can add your own crates and Web API's to your favourite open source browser.