mozilla

Mozilla Nederland LogoDe Nederlandse
Mozilla-gemeenschap

Mozilla and BMZ Announce Cooperation to Open Up Voice Technology for African Languages

Mozilla Blog - ma, 25/11/2019 - 09:11

Mozilla and the German Ministry for Economic Cooperation and Development (BMZ) to jointly build new alliance to foster open voice data and technology in Africa and beyond

Berlin – 25 November 2019. Today, Mozilla and the German Ministry for Economic Cooperation and Development (BMZ) have announced to join forces in the collection of open speech data in local languages, as well as the development of local innovation ecosystems for voice-enabled products and technologies. The initiative builds on the pilot project, which our Open Innovation team and the Machine Learning Group started together with the organization “Digital Umuganda” earlier this year. The Rwandan start-up collects language data in Kinyarwanda, an African language spoken by over 12 million people. Further languages in Africa and Asia are going to be added.

Kelly Davis, Head of Mozilla’s Machine Learning Group, explaining the design and technology behind Deep Speech and Common Voice at a Hackathon in Kigali

Kelly Davis, Head of Mozilla’s Machine Learning Group, explaining the design and technology behind Deep Speech and Common Voice at a Hackathon in Kigali, February 2019.

Mozilla’s projects Common Voice and Deep Speech will be the heart of the joint initiative, which aims at collecting diverse voice data and opening up a common, public database. Mozilla and the BMZ are planning to partner and collaborate with African start-ups, which need respective training data in order to develop locally suitable, voice-enabled products or technologies that are relevant to their Sustainable Development Goals (SDGs). Mozilla and the BMZ are also inviting like-minded companies and identifying further countries interested in joining their efforts to open up language data.

The German Ministry and Mozilla share a similar vision and work towards the responsible use of automated decision-making and artificial intelligence for sustainable development on scale. Supporting partner countries in reaching the SDGs, today, the BMZ is carrying out more than 470 digitally enhanced projects in over 90 countries around the world. As part of the National Strategy for Artificial Intelligence, the Federal German Government has agreed to support developing countries in building up capacities and knowledge on opportunities and challenges of AI – an area of expertise that the Mozilla Foundation has heavily invested in with their work on trustworthy AI.

“Artificial Intelligence is changing and shaping our societies globally. It is critical that these technologies are both trustworthy and truly serve everyone. And that means they need to be developed with local needs and expertise in mind, diverse, decentralized, and not driven by monopolies,” says Mark Surman, Executive Director of the Mozilla Foundation.

“Innovating in AI poses complex technological, regulatory and ethical challenges. This is why I am very pleased to see multiple teams within Mozilla working together in this promising cooperation with the BMZ, building on our shared visions and objectives for a positive digital future,” adds Katharina Borchert, Chief Open Innovation Officer of the Mozilla Corporation.

The cooperation was announced at Internet Governance Forum (IGF) in Berlin and will be part of the BMZ initiative “Artificial Intelligence for All: FAIR FORWARD”. A Memorandum of Understanding (MoU) was signed at Mozilla’s headquarters in Mountain View on November 14.

Representatives of the BMz and Mozilla signing the Memorandom of Understanding

From left to right: Björn Richter, Head of Digital Development Sector Program, GIZ, Dr. Andreas Foerster, Head of Division Digital Technologies in Development Cooperation, BMZ, Katharina Borchert, Chief Open Innovation Officer, Mozilla, Ashley Boyd, VP, Advocacy Mozilla Foundation, and Udbhav Tiwari, Public Policy Advisor, Mozilla

Mozilla believes that the internet is a global public resource that must remain open and accessible for all people, no matter where they are and which language they speak. With projects such as Common Voice and Deep Speech, Mozilla’s Machine Learning Group is working on advancing and democratizing voice recognition technology on the web.

Useful Links:

The post Mozilla and BMZ Announce Cooperation to Open Up Voice Technology for African Languages appeared first on The Mozilla Blog.

Categorieën: Mozilla-nl planet

Cameron Kaiser: And now for something completely different: An Outbound Notebook resurrected

Mozilla planet - ma, 25/11/2019 - 08:23
It surprises people to know that there were authorized non-Apple Macintoshes, and not just the infamous Power Mac clones during the Spindler-Amelio years (or the notoriously overhyped NuTek machines, which tried to get around Apple by reverse-engineering the Mac OS, and not with much success). The most interesting of these were probably the early portables prior to the PowerBook 100, which was a true revolution and ended up eating everybody's lunch (and put most of these companies out of business). Until then these machines had the market all to themselves, even (or especially) when Apple brought out the 16-pound Macintosh Portable, which was big and dumb and today a collector's item but sprawled across most of a desk and gave people hernias just by looking at them.

The 68K laptop manufacturers got around Apple's (later well-founded) clone phobia by importing various components from functioning Macs sold at retail or licensing the chips; some required lobotomizing an otherwise functional machine for its ROMs or even its entire logic board, though at these machines' cheaper price point it was probably still worth it. The big three companies in this particular market were Colby, Dynamac and Outbound. Colby made the WalkMac, which was smaller than the Portable but not much lighter, and required either an SE or SE/30 motherboard. Still, it sold well enough for Sony to threaten to sue them over the Walkman trademark and for Chuck Colby to even develop a tablet version based on the Mac Classic. Dynamac's two models used Mac Plus motherboards (which Apple would only sell to them as entire units, requiring Dynamac to pay for and dispose of the screens and cases they never used), but the EL variant was especially noteworthy for its distinctive 9" amber electroluminescent display.

However, my personal favourite was Outbound. The sprightly kangaroo logo on the case and on the boot screen made people think it was an Australian company (they were actually headquartered in Colorado), including my subsequently disappointed Aussie wife when I landed one for my collection. Outbound distinguished themselves in this market by developing their own logic boards and hardware and only requiring the ROMs from a donor Mac (usually an SE or Plus). Their first was the 1989 Outbound Laptop, which was a briefcase portable not unlike the Compaq Portables of the time, and running at a then-impressive 15MHz. The keyboard connected by infrared, which causes a little PTSD in me because I remember how hideous the IBM PCjr's infrared keyboard was. However, the pointing device was a "trackbar" (trademarked as "Isopoint"), a unique rolling rod that rolled forward and back and side to side. You just put your finger on it and rolled or slid the rod to move the pointer. Besides the obvious space savings, using it was effortless and simple; even at its side extents the pointer would still move if you pushed the bar in the right direction. The Outbound Laptop also let you plug it back into the donor Mac to use that Mac with its ROMs in the Outbound, something they called "hive mode." Best of all, it ran on ordinary VHS camcorder batteries, which you can still find today, and although it was a bit bulky it was about half the weight of the Mac Portable. At a time when the Portable sold for around $6500 it was just $3995.

In 1991 Outbound negotiated a deal with Apple to actually get ROMs from them without having to sacrifice another Mac in the process. They used these to construct the Outbound Notebook, which of the two (today rather rare) Outbound machines is easily the more commonly found. The first model 2000 used the same 68000 as the Laptop, boosting it to 20MHz, but the 2030 series moved to the 68030 and ran up to 40MHz. These could even take a 68882 FPU, though they were still limited to 4MB RAM like the Laptop (anything more was turned into a "Silicon" RAM disk supported by an included CDEV). They featured a very nice keyboard and the same innovative trackbar, also took VHS camcorder batteries, and folded to a very trim letter size dimension (about 2" thick) weighing just over six pounds. Thanks to its modular construction it could even be upgraded: the RAM was ordinary 30-pin SIMMs attached to a removable CPU daughtercard where the ROMs, FPU and main CPU connected, and the 2.5" IDE hard drive could also be easily removed, though Outbound put a warranty sticker on it to discourage third-party replacements. For desktop use it had ADB and the $949 Outbound Outrigger monitor plugged into the SCSI port to provide an external display (yes, there were SCSI video devices).

Unlike the other Mac clones, the Outbound Notebook was a serious threat to Apple's portable line at the time. Even though the contemporary PowerBook 100 was rather cheaper ($2300 vs the 40MHz 2030V at $3500) and could take up to 8MB of RAM, it was still the 16MHz 68000 of the Portable era because it was, in fact, simply a miniaturized Mac Portable. Only the simultaneously-introduced PowerBook 170 was anywhere near the same performance ballpark (25MHz '030) as the Notebook, and it was $4600. Apple decided to adopt a contractual solution: while the agreement compelled Apple to still offer SE ROMs to Outbound, they were not similarly obligated to sell ROMs from any later model, and thus they refused and in doing so put an end to the development of a successor. Deprived of subsequent products, Outbound went out of business by the end of 1992, leaving the machines eternally stuck at 7.1.

A couple years ago I picked up a complete 33MHz '030 Outbound Notebook system from a sale, even coming with a small dot matrix printer and the official Outbound car charger (!). Some of you at the Vintage Computer Festival 2017 saw this machine as a terminal for my Apple Network Server 500. It was a bit yellowed and had been clearly heavily used, but worked pretty well right up until it didn't (eventually it went to a garbage screen and wouldn't enter POST). I put it back in the closet for a few months in Odinsleep until an "untested" unit showed up on eBay a couple weeks ago. Now, keep in mind that "untested" is eBay-speak for "it's not working but I'm going to pretend I don't know," so I was pretty sure it was defective, but the case was in nice condition and I figured I could probably pull a few parts off it to try. Indeed, although the kangaroo screen came up, the hard drive started making warbling noises and the machine froze before even getting to the Happy Mac. I put in the hard disk from my dead unit and it didn't do any better, so I swapped the CPU cards as well and ... it booted!

At 33MHz System 7.1 flies, and it has Connectix Compact Virtual (the direct ancestor of RAM Doubler), which at the cost of disabling the Silicon Disk gives me a 16MB addressing space. At some point I'll get around to configuring it for SCSI Ethernet, another fun thing you can do over SCSI that people have forgotten about.

Besides the case, floppy drive and trackbar, the keyboard was also in excellent condition. Let's compare it with what I think is the best keyboard on any Apple laptop past or present, the PowerBook 1400:

This is my personal PowerBook 1400 workhorse which still sees occasional use for classic software. The 1400 was my first Mac laptop, so I'm rather fond of them, and I have a stack of them for spare parts including my original 117cs. This one is almost maximally upgraded, too: it has a Sonnet 466MHz G3, 64MB of RAM, a 4GB IDE drive, Ethernet and modem PCMCIA cards and the Apple 8-bit video card. All it needs is a 16-bit video card and the solar cover (it just has the interchangeable inserts), and it would be the envy of all who behold it.

The 1400 has the keyboard against which all Mac laptops are measured because of its firmness, key travel and pre-scissor construction. It isn't quite as long travel as the IBM ThinkPads of the era, but it easily exceeds any other Apple laptop keyboard then or now, and is highly reliable and easily replaced if necessary (mine has never been necessary). The Outbound's keyboard is a bit stiff by comparison but has decent travel and is less mushy than my other 68K PowerBooks (or for that matter even my iBook G4). While the Portable's keyboard is nice and clicky, it's practically a desktop keyboard, so it's cheating. Score another one for the clone.

For that matter, the 1400 and the Outbound have another thing in common: surprising modularity. Like the Outbound, the 1400's CPU is on a removable daughtercard behind just a couple screws, and the hard disk and RAM can be upgraded easily (though the 1400's wonky stacked RAM system can sometimes be mechanically fraught with peril). It's just a shame it has a custom battery instead of an off-the-shelf one, but that's Apple for you. Neither of them have an easily accessed logic board but that's hardly unusual for laptops. I'm just glad the logic board on this unit was working, because it's nice to have the Outbound revived again for more good times. It's a great historical reminder that sometimes the best Macintoshes didn't come from Cupertino.

Categorieën: Mozilla-nl planet

Chris H-C: This Week in Glean: Glean in Private

Mozilla planet - vr, 22/11/2019 - 18:18

(“This Week in Glean” is a series of blog posts that the Glean Team at Mozilla is using to try to communicate better about our work. They could be release notes, documentation, hopes, dreams, or whatever: so long as it is inspired by Glean.)

In the Kotlin implementation of the Glean SDK we have a glean.private package. (( Ideally anything that was actually private in the Glean SDK would actually _be_ private and inaccessible, but in order to support our SDK magic (okay, so that the SDK could work properly by generating the Specific Metrics API in subcomponents) we needed something public that we just didn’t want anyone to use. )) For a little while this week it looked like the use of the Java keyword private in the name was going to be problematic. Here are some of the alternatives we came up with:

Fortunately (or unfortunately) :mdboom (whom I might have to start calling Dr. Boom) came up with a way to make it work with the package private intact, so we’ll never know which one we would’ve gone with.

Alas.

I guess I’ll just have to console myself with the knowledge that we’ve deployed this fix to Fenix, Python bindings are becoming a reality, and the first code supporting the FOGotype might be landing in mozilla-central. (More to come on all of that, later)

:chutten

Categorieën: Mozilla-nl planet

Marco Zehe: My extended advent calendar

Mozilla planet - vr, 22/11/2019 - 13:00

This year, I have a special treat for my readers. On Monday, November 25, at 12 PM UTC, I will start a 30 day series about everything and anything. Could be an accessibility tip, an how-to about using a feature in an app I use frequently, some personal opinion on something, a link to something great I came across on the web… I am totally not certain yet. I have ideas about some things I want to blog about, but by far not 30 of them yet.

Are you as excited about where this 30 day journey will take us as I am? Well then feel free to join me! You can like this blog in the section at the bottom, follow the RSS feed, follow my Twitter or Mastodon timelines, or like my shiny new Facebook page for the blog. The new posts will appear every day at 12 PM UTC. For those in Europe and Africa this is great, for the U.S. and other parts of the north, central, and south American content it’s earlier, and for those in Asia and Australia it’s late in the day.

I look forward to your comments about what I’ll be posting! Let’s all have some end of year fun together!

Categorieën: Mozilla-nl planet

Karl Dubost: Week notes - 2019 w47 - worklog

Mozilla planet - vr, 22/11/2019 - 09:00
Week Notes?

Week Notes. I'm not sure I will be able to commit to this. But they have a bit of revival around my blogging reading echo chamber. Per revival, I mean I see them again.

The Open Data Institute just started one with a round about them. I subscribed again to the feed of Brian Suda and his own week notes. Alice Bartlett has also a very cool personal, down to earth and simple summary of her week. I love that she calls them weaknotes She's on week 63 by now.

So these will not be personal but more covering a bit of the things I (we?) do, learn, fail about webcompat. The only way to do that is to write down properly things. The possible issues: redundancy in writing things elsewhere, the fatigue associated with the regularity. I did a stretch of worklogs in the past.

Bugs Firefox Usage Counters

I need to better understand how counters are working inside Firefox so the numbers become more meaningful. And probably it would be good to understand how they operate at Chrome too. How the counter works when a property is used inside a condition. For example in JavaScript with a construct like:

var mypath = event.path || event.composedPath()

These are probably questions for Boris Bzarsky. Maybe a presentation at All Hands Berlin would be cool on the topic.

  • What is happening if the browser implements both, how are they counted?
  • What is happening if the browser implements one of these, how are they counted?
  • Is the order matters for the counter?
  • What are the induced differences if the counter is tracking only one of the property and not the two?
  • Can a counter track something which is in the source code but not implemented in the engine. For instance, tracking event.path which is undefined.
Python tests

We currently do AB testing for webcompat.com for a new form with the goal to improve the quality of the bugs reported. The development has not been an entirely smooth road, and there are still a lot of things to fix, and particulary the missing tests. Our objective is that if the AB testing experiment is successful. We will be rewriting properly the code, and more specifically the tests. So instead of fixing the code, I was thinking that we could just add the tests, so we have a solid base when it's time for rewriting. We'll see. Then Mike was worried that we would break continuous integration. We use nose for running our unittest tests. There is a plugin in nose for creating groups of tests by setting an attr.

from nose.plugins.attrib import attr @attr(form='wizard') class WizardFormTest: def test_exclusive_wizard(self): pass

So we could probably deactivate these specific tests. So this is something to explore.

Webcompat dev
  • Discussions with Kate about DB migrations.
  • Trying to understand what GitHub really does with linked images, because it might have consequences for our own images hosting.
  • Making a local prototype of image upload with the Bottle framework. So I can think differently about it. Bottle is super nice for quick prototyping/thinking. That looks doable. In the end it will be probably done with Flask. It helped identified some issues and some cool things we do.
Writings Reading
  • I have the feeling I could write a counterpart for this blog post about work commuting. There's probably something about work and the circumstances of your country.
  • This blog post was followed by a series of internal discussions on the nature of commuting, the reason to commute or not, etc. As usual, a lot of things need to be unpacked when we talk about commuting.
  • Impressive and interesting to look at the differences. Female developers in the world from hackerrank
System abuse? or goofing
  • A user reported two invalid bugs and deleted his accounts. It's always for me a surprise when people try to abuse a system which has no power.
Some notes about the week notes
  • Should adding pieces be about a linear timeline of events when they happen OR should it be about categories like I did above?
  • Was it too long? Oversharing? All of these are notes taken on the last 5 days. And I'm surprised by the amount.
  • My work is not linear on one task, which means updates to many tasks are happening in a couple of hours or days.

Otsukare!

Categorieën: Mozilla-nl planet

Niko Matsakis: Announcing the Async Interviews

Mozilla planet - vr, 22/11/2019 - 06:00

Hello all! I’m going to be trying something new, which I call the “Async Interviews”. These interviews are going to be a series of recorded video calls with various “luminaries” from Rust’s Async I/O effort. In each one, I’m going to be asking roughly the same question: Now that the async-await MVP is stable, what should we be doing next? After each call, I’ll post the recording from the interview, along with a blog post that leaves a brief summary.

My intention in these interviews is to really get into details. That is, I want to talk about what our big picture goals should be, but also what the specific concerns are around stabilizing particular traits or macros. What sorts of libraries do they enable? And so forth. (You can view my rough interview script, but I plan to tailor the meetings as I go.)

I view these interviews as serving a few purposes:

  • Help to survey what different folks are thinking and transmit that thinking out to the community.
  • Help me to understand better what some of the tradeoffs are, especially around discussions that occurred before I was following closely.
  • Experiment with a new form of Rust discussion, where we substitute 1-on-1 exploration and discussion for bigger discussion threads.
First video: Rust and WebAssembly

The first video in this series, which I expect to post next week, will be me chatting with Alex Crichton and Nick Fitzgerald about Async I/O and WebAssembly. This video is a bit different from the others, since it’s still early days in that area – as a result, we talked more about what role Async I/O (and Rust!) might eventually play, and less about immediate priorities for Rust. Along with the video, I’ll post a blog post summarizing the main points that came up in the conversation, so you don’t necessarily have to watch the video itself.

What videos will come after that?

My plan is to be posting a fresh async interview roughly once a week. I’m not sure how long I’ll keep doing this – I guess as long as it seems like I’m still learning things. I’ll announce the people I plan to speak to as I go, but I’m also very open to suggestions!

I’d like to talk to folks who are working on projects at all levels of the “async stack”, such as runtimes, web frameworks, protocols, and consumers thereof. If you can think of a project or a person that you think would provide a useful perspective, I’d love to hear about it. Drop me a line via e-mail or on Zulip or Discord.

Creating design notes

One thing that I have found in trying to get up to speed on the design of Async I/O is that the discussions are often quite distributed, spread amongst issues, RFCs, and the like. I’d like to do a better job of organizing this information.

Therefore, as part of this effort to talk to folks, one of the things I plan to be doing is to collect and catalog the concerns, issues, and unknowns that are being brought up. I’d love to find people to help in this effort! If that is something that interests you, come join the #wg-async-foundations stream on the rust-lang Zulip and say hi!

So what are the things we might do now that async-await is stable?

If you take a look at my rough interview script, you’ll see a long list of possibilities. But I think they break down into two big categories:

  • improving interoperability
  • extending expressive power, convenience, and ergonomics

Let’s look a bit more at those choices.

Improving interoperability

A long time back, Rust actually had a built-in green-threading library. It was removed in RFC #230, and a big part of the motivation was that we knew we were unlikely to find a single runtime design that was useful for all tasks. And, even if we could, we certainly knew we hadn’t found it yet. Therefore, we opted to pare back the stdlib to just expose the primitives that the O/S had to offer.

Learning from this, our current design is intentionally much more “open-ended” and permits runtimes to be added as simple crates on crates.io. Right now, to my knowledge, we have at least five distinct async runtimes for Rust, and I wouldn’t be surprised if I’ve forgotten a few:1

  • fuschia’s runtime, used for the Fuschia work at Google;
  • tokio, a venerable, efficient runtime with a rich feature set;
  • async-std, a newer contender which aims to couple libstd-like APIs with highly efficient primitives;
  • bastion, exploring a resilient, Erlang-like model2;
  • embrio-rs, exploring the embedded space.

I think this is great: I love to see people experimenting with different tradeoffs and priorities. Not only do I think we’ll wind up with better APIs and more efficient implementations, this also means we can target ‘exotic’ environments like the Fuschia operating system or smaller embedded platforms. Very cool stuff.

However, that flexibility does come with some real risks. Most notably, I want us to be sure that it is possible to “mix and match” libraries from the ecosystem. No matter what base runtime you are using, it should be possible to take a protocol implementation like quinn, combine it with “middleware” crates like async-compression, and starting sending payloads.

In my mind, the best way to ensure interoperability is to ensure that we offer standard traits that define the interfaces between libraries. Adding the std::Future trait was a huge step in this direction – it means that you can create all kinds of combinators and things that are fully portable between runtimes. But what are the next steps we can take to help improve things further?

One obvious set of things we can do improve interop is to try and stabilize additional traits. Currently, the futures crate contains a number of interfaces that have been evolving over time, such as Stream, AsyncRead, and AsyncWrite. Maybe some of these traits are good candidates to be moved to the standard library next?

Here are some of the main things I’d like to discuss around interop:

  • As a meta-point, should we be moving the crates to the standard library, or should we move try to promote the futures crate (or, more likely, some of its subcrates, such as futures-io) as the standard for interop? I’ve found from talking to folks that there is a fair amount of confusion on “how standard” the futures crates are and what the plan is there.
  • Regardless of how we signal stability, I also want to talk about the specific traits or other things we might stabilizing. For each such item, there are two things I’d like to drill into:
    • What kinds of interop would be enabled by stabilizing this item? What are some examples of the sorts of libraries that could now exist independently of a runtime because of the existence of this item?
    • What are the specific concerns that remain about the design of this item? The AsyncRead and AsyncWrite traits, for example, presently align quite closely with their synchronous counterparts Read and Write. However, this interface does require that the buffer used to store data must be zeroed. The tokio crate is considering altering its own local definition of AsyncRead for this reason, is that something we should consider as well? If so, how?
  • On a broader note, what are the sorts of things crates need to truly operate that are not covered by the existing traits? For example, the global executors that boats recently proposed would give people the ability to “spawn tasks” into some ambient context… is that a capability that would enable more interop? Perhaps access to task-local data? Inquiring minds want to know.
Improving expressive power, convenience, and ergonomics

Interoperability isn’t the only thing that we might try to improve. We might also focus on language extensions that either grow our expressive power or add convenience and ergonomics. Something like supporting async fn in traits or async closures, for example, could be a huge enabler, even if there are some real difficulties to making them work.

Here are some of the specific features we might discuss:

  • Async destructors. As boats described in this blog post, there is sometimes a need to “await” things when running destructors, and our current system can’t support that.
  • Async fn in traits. We support async fn in free functions and inherent methods, but not in traits. As I explained in this blog post, there are a lot of challenges to support async fn in traits properly (but consider using the async-trait crate).
  • Async closures. Currently, we support async blocks (async move { .. }), which evaluate to a future, and async functions (async fn foo()), which are a function that returns a future. But, at least on stable, we have no way to make a closure that returns a future. Presumably this would be something like async || { ... }. (In fact, on nightly, we do have support for async closures, but there are some issues in the design that we need to work out.)
  • Combinator methods like map, or macros like join! and select!. The futures crate offers a number of useful combinators and macros. Maybe we should move some of those to the standard library?
Conclusion

I think these interviews are going to be a lot of fun, and I expect to learn a lot. Stay tuned for the first blog post, coming next week, about Async I/O and WebAssembly.

Comments?

There is a thread on the Rust users forum for questions and discussion.

Footnotes
  1. Indeed, shortly after I published this post, I was directed to the drone-os project. 

  2. Woohoo! I just want to say that I’ve been hoping to see something like OTP for Rust for…quite some time. 

Categorieën: Mozilla-nl planet

Cameron Kaiser: TenFourFox FPR17b1 available

Mozilla planet - vr, 22/11/2019 - 04:09
TenFourFox Feature Parity Release 17 beta 1 is now available (downloads, hashes, release notes). SourceForge seems to have fixed whatever was making TenFourFox barf on its end which now might actually be an issue over key exchange. For a variety of reasons, but most importantly backwards compatibility, my preference has been to patch up the NSS security library in TenFourFox to support new crypto and ciphers rather than just drop in a later version. We will see if the issue recurs.

This release fixes the "infinite loop" issue on Github with a trivial "hack" mitigation. This mitigation makes JavaScript slightly faster as a side-effect but it's because it relaxes some syntax constraints in the runtime, so I don't consider this a win really. It also gets rid of some debug-specific functions that are web-observable and clashed on a few pages, an error Firefox corrected some time ago but missed my notice. Additionally, since 68ESR newly adds the ability to generate and click on links without embedding them in the DOM, I backported that patch so that we can do that now too (a 4-year-old bug only recently addressed in Firefox 70). Apparently this functionality is required for certain sites' download features and evidently this was important enough to merit putting in an extended support release, so we will follow suit.

I also did an update to cookie security, with more to come, and cleared my backlog of some old performance patches I had been meaning to backport. The most important of these substantially reduces the amount of junk strings JavaScript has hanging around, which in turn reduces memory pressure (important on our 32-bit systems) and garbage collection frequency. Another enables a fast path for layout frames with no properties so we don't have to check the hash tables as frequently.

By user request, this version of TenFourFox also restores the old general.useragent.override.* site-specific override pref feature. This was removed in bug 896114 for performance reasons and we certainly don't need anything that makes the browser any slower, so instead of just turning it back on I also took the incomplete patch in that bug as well and fixed and finished it. This means, in the default state with no site-specific overrides, there is no penalty. This is the only officially supported state. I do not have any plans to expose this feature to the UI because I think it will be troublesome to manage and the impact on loading can be up to 9-10%, so if you choose to use this, you do so at your own risk. I've intentionally declined to mention it in the release notes or to explain any further how this works since only the people who already know what it does and how it operates and most importantly why they need it should be using it. For everyone else, the only official support for changing the user agent remains the global selector in the TenFourFox preference pane (which I might add now allows you to select Firefox 68 if needed). Note that if you change the global setting and have site-specific overrides at the same time, the browser's behaviour becomes "officially undefined." Don't file any bug reports on that, please.

Finally, this release also updates the ATSUI font blacklist and basic adblock database, and has the usual security, certificate, pin, HSTS and TLD updates. Assuming no issues, it will go live on December 2nd or thereabouts.

For FPR18, one thing I would like to improve further is the built-in Reader mode to at least get it more consistent with current Firefox releases. Since layout is rapidly approaching its maximum evolution (as determined by the codebase, the level of work required and my rapidly dissipating free time), the Reader mode is probably the best means for dealing with the (fortunately relatively small) number of sites right now that lay out problematically. There are some other backlogged minor changes I would like to consider for that release as well. However, FPR18 will be parallel with the first of the 4-week cadence Firefox releases and as I have mentioned before I need to consider how sustainable that is with my other workloads, especially as most of the low-hanging fruit has long since been picked.

Categorieën: Mozilla-nl planet

The Firefox Frontier: Princesses make terrible passwords

Mozilla planet - do, 21/11/2019 - 22:46

When the Disney+ streaming service rolled out, millions of people flocked to set up accounts. And within a week, thousands of poor unfortunate souls reported that their Disney passwords were … Read more

The post Princesses make terrible passwords appeared first on The Firefox Frontier.

Categorieën: Mozilla-nl planet

The Firefox Frontier: Two ways Firefox protects your holiday shopping

Mozilla planet - do, 21/11/2019 - 18:04

We’re entering another holiday shopping season, and while you’re browsing around on the internet looking for thoughtful presents for friends and loved ones, it’s also a good time to give … Read more

The post Two ways Firefox protects your holiday shopping appeared first on The Firefox Frontier.

Categorieën: Mozilla-nl planet

Hacks.Mozilla.Org: Multi-Value All The Wasm!

Mozilla planet - do, 21/11/2019 - 17:50

This article is cross-posted on the Bytecode Alliance web site.

Multi-value is a proposed extension to core WebAssembly that enables functions to return many values, among other things. It is also a pre-requisite for Wasm interface types.

I’ve been adding multi-value support all over the place recently:

  • I added multi-value support to all the various crates in the Rust and WebAssembly toolchain, so that Rust projects can compile down to Wasm code that uses multi-value features.

  • I added multi-value support to Wasmtime, the WebAssembly runtime built on top of the Cranelift code generator, so that it can run Wasm code that uses multi-value features.

Now, as my multi-value efforts are wrapping up, it seems like a good time to reflect on the experience and write up everything that’s been required to get all this support in all these places.

Wait — What is Multi-Value Wasm?

In core WebAssembly, there are a couple of arity restrictions on the language:

  • functions can only return either zero or one value, and
  • instruction sequences like blocks, ifs, and loops cannot consume any stack values, and may only produce zero or one resulting stack value.

The multi-value proposal is an extension to the WebAssembly standard that lifts these arity restrictions. Under the new multi-value Wasm rules:

  • functions can return an arbitrary number of values, and
  • instruction sequences can consume and produce an arbitrary number of stack values.

The following snippets are only valid under the new rules introduced in the multi-value Wasm proposal:

;; A function that takes an `i64` and returns ;; three `i32`s. (func (param i64) (result i32 i32 i32) ...) ;; A loop that consumes an `i32` stack value ;; at the start of each iteration. loop (param i32) ... end ;; A block that produces two `i32` stack values. block (result i32 i32) ... end

The multi-value proposal is currently at phase 3 of the WebAssembly standardization process.

But Why Should I Care? Code Size

There are a few scenarios where compilers are forced to jump through hoops when producing multiple stack values for core Wasm. Workarounds include introducing temporary local variables, and using local.get and local.set instructions, because the arity restrictions on blocks mean that the values cannot be left on the stack.

Consider a scenario where we are computing two stack values: the pointer to a string in linear memory, and its length. Furthermore, imagine we are choosing between two different strings (which therefore have different pointer-and-length pairs) based on some condition. But whichever string we choose, we’re going to process the string in the same fashion, so we just want to push the pointer-and-length pair for our chosen string onto the stack, and control flow can join afterwards.

With multi-value, we can do this in a straightforward fashion:

call $compute_condition if (result i32 i32) call $get_first_string_pointer call $get_first_string_length else call $get_second_string_pointer call $get_second_string_length end

This encoding is also compact: only sixteen bytes!

When we’re targeting core Wasm, and multi-value isn’t available, we’re forced to pursue alternative, more convoluted forms. We can smuggle the stack values out of each if and else arm via temporary local values:

;; Introduce a pair of locals to hold the values ;; across the instruction sequence boundary. (local $string i32) (local $length i32) call $compute_condition if call $get_first_string_pointer local.set $string call $get_first_string_length local.set $length else call $get_second_string_pointer local.set $string call $get_second_string_length local.set $length end ;; Restore the values onto the stack, from their ;; temporaries. local.get $string local.get $length

This encoding requires 30 bytes, an overhead of fourteen bytes more than the ideal multi-value version. And if we were computing three values instead of two, there would be even more overhead, and the same is true for four values, etc… The additional overhead is proportional to how many values we’re producing in the if and else arms.

We can actually go a little smaller than that — still with core Wasm — by jumping through a different hoop. We can split this into two if ... else ... end blocks and duplicate the condition check to avoid introducing temporaries for each of the computed values themselves:

;; Introduce a local for the condition, so that ;; we only re-check it, and don't recompute it. (local $condition i32) ;; Compute and save the condition. call $compute_condition local.set $condition ;; Compute the first stack value. local.get $condition if (result i32) call $get_first_string_pointer else call $get_second_string_pointer end ;; Compute the second stack value. local.get $condition if (result i32) call $get_first_string_length else call $get_second_string_length end

This gets us down to 28 bytes. Two fewer than the last version, but still an overhead of twelve bytes compared to the multi-value encoding. And the overhead is still proportional to how many values we’re computing.

There’s no way around it: we need multi-value to get the most compact code here.

New Instructions

The multi-value proposal opens up the possibility for new instructions that produce multiple values:

  • An i32.divmod instruction of type [i32 i32] -> [i32 i32] that takes a numerator and divisor and produces both their quotient and remainder.

  • Arithmetic operations with an additional carry result. These could be used to better implement big ints, overflow checks, and saturating arithmetic.

Returning Small Structs More Efficiently

Returning multiple values from functions will allow us to more efficiently return small structures like Rust’s Results. Without multi-value returns, these relatively small structs that still don’t fit in a single Wasm value type get placed in linear memory temporarily. With multi-value returns, the values don’t escape to linear memory, and instead stay on the stack. This can be more efficient, since Wasm stack values are generally more amenable to optimization than loads and stores from linear memory.

Interface Types

Shrinking code size is great, and new instructions would be fancy, but here’s what I’m really excited about: WebAssembly interface types. Interface types used to be called “host bindings,” and they are the key to unlocking:

  • direct, optimized access to the browser’s DOM methods on the Web,
  • “shared-nothing linking” of WebAssembly modules, and
  • defining language-neutral interfaces, like WASI.

For all three use cases, we might want to return a string from a callee Wasm module. The caller that is consuming this string might be a Web browser, or it might be another Wasm module, or it might be a WASI-compatible Wasm runtime. In any case, a natural way to return the string is as two i32s:

  1. a pointer to the start of the string in linear memory, and
  2. the byte length of the string.

The interface adapter can then lift that pair of i32s into an abstract string type, and then lower it into the caller’s concrete string representation on the other side. Interface types are designed such that in most cases, this lifting and lowering can be optimized into a quick memory copy from the callee’s linear memory to the caller’s.

But before the interface adapters can do that lifting and lowering, they need access to the pointer and length pair, which means the callee Wasm function needs to return two values, which means we need multi-value Wasm for interface types.

All The Implementing!

Now that we know what multi-value Wasm is, and why it’s exciting, I’ll recount the tale of implementing support for it all over the place. I started with implementing multi-value support in the Rust and WebAssembly toolchain, and then I added support to the Wasmtime runtime, and the Cranelift code generator it’s built on top of.

Rust and WebAssembly Toolchain

What falls under the Rust and Wasm toolchain umbrella? It is a superset of the general Rust toolchain:

  • cargo: Manages builds and dependencies.
  • rustc: Compiles Rust sources into code.
  • LLVM: Used by rustc under the covers to optimize and generate code.

And then additionally, when targeting Wasm, we also use a few more moving parts:

  • wasm-bindgen: Part library and part Wasm post-processor, wasm-bindgen generates bindings for consuming and producing interfaces defined with interface types (and much more!)
  • walrus: A library for transforming and rewriting WebAssembly modules, used by wasm-bindgen‘s post-processor.
  • wasmparser: An event-style parser for WebAssembly binaries, used by walrus.

Here’s a summary of the toolchain’s pipeline, showing the inputs and outputs between tools:

A diagram showing the pipeline of the Rust and Wasm toolchain.

My goal is to unlock interface types with multi-value functions. For now, I haven’t been focusing on code size wins from generating multi-value blocks. For my purposes, I only need to introduce multi-value functions at the edges of the Wasm module that talk to interface adapters; I don’t need to make all function bodies use the optimal multi-value instruction sequence constructs. Therefore, I decided to have wasm-bindgen‘s post-processor rewrite certain functions to use multi-value returns, rather than add support in LLVM.0 With this approach I only needed to add support to the following tools:

  • cargo
  • rustc
  • LLVM
  • wasm-bindgen
  • walrus
  • wasmparser
wasmparser

wasmparser is an event-style parser for WebAssembly binaries. It may seem strange that adding toolchain support for generating multi-value Wasm began with parsing multi-value Wasm. But it is necessary to make testing easy and painless, and we needed it eventually for Wasmtime anyways, which also uses wasmparser.

In core Wasm, the optional value type result of a block, loop, or if is encoded directly in the instruction:

  • a 0x40 byte means there is no result
  • a 0x7f byte means there is a single i32 result
  • a 0x7e byte means there is a single i64 result
  • etc…

With multi-value Wasm, there are not only zero or one resulting value types, there are also parameter types. Blocks can have the same set of types that functions can have. Functions already de-duplicate their types in the “Type” section of a Wasm binary and reference them via index. With multi-value, blocks do that now as well. But how does this co-exist with non-multi-value block types?

The index is encoded as a signed variable-length integer, using the LEB128 encoding. If we interpret non-multi-value blocks’ optional result value type as a signed LEB128, we get:

  • -64 (the smallest number that can be encoded as a single byte with signed LEB128) means there is no result
  • -1 means there is a single i32 result
  • -2 means there is a single i64 result
  • etc..

They’re all negative, leaving the positive numbers to be interpreted as indices into the “Type” section for multi-value blocks! A nice little encoding trick and bit of foresight from the WebAssembly standards folks.

Adding support for parsing these was straightforward, but wasmparser also supports validating the Wasm as it parses it. Adding validation support was a little bit more involved.

wasmparser‘s validation implementation is similar to the validation algorithm presented in the appendix of the WebAssembly spec: it abstractly interprets the Wasm instructions, maintaining a stack of types, rather than a stack of values. If any operation uses operands of the wrong type — for example the stack has an f32 at its top when we are executing an i32.add instruction, and therefore expect two i32s on top of the stack — then validation fails. If there are no type errors, then it succeeds. There are some complications when dealing with stack-polymorphic instructions, like drop, but they don’t really interact with multi-value.

Whenever wasmparser encounters a block, loop, or if instruction, it pushes an associated control frame, that keeps track of how deep in the stack instructions within this block can access. Before multi-value, the limit was always the length of the stack upon entering the block, because blocks didn’t take any values from the stack. With multi-value, this limit becomes stack.len() - block.num_params(). When exiting a block, wasmparser pops the associated control frame. It check that the top n types on the stack match the block’s result types, and that the stack’s length is frame.depth + n. Before multi-value, n was always either 0 or 1, but now it can be any non-negative integer.

The final bit of validation that is impacted by multi-value is when an if needs to have an else or not. In core Wasm, if the if does not produce a resulting value on the stack, it doesn’t need an else arm since the whole if‘s typing is [] -> [] which is also the typing for a no-op. With multi-value this is generalized to any if where the inputs and outputs are the same types: [t*] -> [t*]. Easy to implement, but also very easy to overlook (like I originally did!)

Multi-value support was added to wasmparser in these pull requests:

walrus

walrus is a WebAssembly to WebAssembly transformation library. We use it to generate glue code in wasm-bindgen and to polyfill WebAssembly features.

walrus constructs its own intermediate representation (IR) for WebAssembly. Similar to how wasmparser validates Wasm instructions, walrus also abstractly interprets the instructions while building up its IR. This meant that adding support for constructing multi-value IR to walrus was very similar to adding multi-value validation support to wasmparser. In fact, walrus also validates the Wasm while it is constructing its IR.

But multi-value has big implications for the IR itself. Before multi-value, you could view Wasm’s stack-based instructions as a post-order encoding of an expression tree.

Consider the expression (a + b) * (c - d). As an expression tree, it looks like this:

* / \ / \ + - / \ / \ a b c d

A post-order traversal of a tree is where a node is visited after its children. A post-order traversal of our example expression tree would be:

a b + c d - *

Assume that a, b, c, and d are Wasm locals of type i32, with the values 9, 7, 5, and 3 respectively. We can convert this post-order directly into a sequence of Wasm instructions that build up their results on the Wasm stack:

;; Instructions ;; Stack ;;;;;;;;;;;;;;;;;;;;;;;;;;;;; local.get $a ;; [9] local.get $b ;; [9, 7] i32.add ;; [16] local.get $c ;; [16, 5] local.get $d ;; [16, 5, 3] i32.sub ;; [16, 2] i32.mul ;; [32]

This correspondence between trees and Wasm stack instructions made using a tree-like IR in walrus, where nodes are instructions and a node’s children are the instructions that produce the parent’s input values, very natural.1 Our IR used to look something like this:

pub enum Expr { // A `local.get` instruction. LocalGet(LocalId), // An `i32.add` instruction. I32Add(ExprId, ExprId), // Etc... }

But multi-value threw a wrench in this tree-like representation: now that an instruction can produce multiple values, when we have a parent⟶child edge in the tree, how do we know which of the child’s resulting values the parent wants to use? And also, if two different parents are each using one of the two values an instruction generates, we fundamentally don’t have a tree anymore, we have a directed, acyclic graph (DAG).

We considered generalizing our tree representation into a DAG, and labeling edges with n to represent using the nth resulting value of an instruction. We weighed the complexity of implementing this representation against what our current use cases in wasm-bindgen demand, along with any future use cases we could think of. Ultimately, we decided it wasn’t worth the effort, since we don’t need that level of detail for any of the transformations or manipulations that wasm-bindgen performs, or that we foresee it doing in the future.

Instead, we decided that within a block, representing instructions as a simple list is good enough for our use cases, so now our IR looks something like this:

pub struct Block(Vec); pub enum Instr { // A `local.get` instruction. LocalGet(LocalId), // An `i32.add` instruction. Note that its // children are left implicit now. I32Add, // Etc... }

Additionally, it turns out it is faster to construct and traverse this list-based representation, so switching representations in walrus also gave wasm-bindgen a nice little speed up.

The walrus support for multi-value was implemented in these pull requests:

wasm-bindgen

wasm-bindgen facilitates high-level interactions between Wasm modules and their host. Often that host is a Web browser and its DOM methods, or some user-written JavaScript. Other times it is an outside-the-Web Wasm runtime, like Wasmtime, using WASI and interface types. wasm-bindgen acts as a polyfill for the interface types proposal, plus some extra batteries included for a powerful user experience.

One of wasm-bindgen‘s responsibilities is translating the return value of a Wasm function into something that the host caller can understand. When using interface types directly with Wasmtime, this means generating interface adapters that lift the concrete Wasm return values into abstract interface types. When the caller is some JavaScript code on the Web, it means generating some JavaScript code to convert the Wasm values into JavaScript values.

Let’s take a look at some Rust functions and the Wasm they get compiled down into.

First, consider when we are returning a single integer from a Rust function:

// random.rs #[no_mangle] pub extern "C" fn get_random_int() -> i32 { // Chosen by fair dice roll. 4 }

And here is the disassembly of that Rust code compiled to Wasm:

;; random.wasm (func $get_random_int (result i32) i32.const 4 )

The resulting Wasm function’s signature is effectively identical to the Rust function’s signature. No surprises here. It is easy for wasm-bindgen to translate the resulting Wasm value to whatever is needed because wasm-bindgen has direct access to it; it’s right there.

Now let’s look at returning compound structures from Rust that don’t fit in a single Wasm value:

// pair.rs #[no_mangle] pub extern "C" fn make_pair(a: i32, b: i32) -> [i32; 2] { [a, b] }

And here is the disassembly of this new Rust code compiled to Wasm:

;; pair.wasm (func $make_pair (param i32 i32 i32) local.get 0 local.get 2 i32.store offset=4 local.get 0 local.get 1 i32.store )

The signature for the make_pair function in pair.wasm doesn’t look like its corresponding signature in pair.rs! It has three parameters instead of two, and it isn’t returning any values, let alone a pair.

What’s happening is that LLVM doesn’t support multi-value yet so it can’t return two i32s directly from the function. Instead, callers pass in a “struct return” pointer to some space that they’ve reserved for the return value, and make_pair will write its return value through that struct return pointer into the reserved space. By convention, LLVM uses the first parameter as the struct return pointer, so the second Wasm parameter is our original a parameter in Rust and the third Wasm parameter is our original b parameter in Rust. We can see that the Wasm function is writing the b field first, and then the a field second.

How is space reserved for the struct return? Distinct from the Wasm standard’s stack that instructions push values to and pop values from, LLVM emits code to maintain a “shadow stack” in linear memory. There is a global dedicated as the stack pointer, and always points to the top of the stack. Non-leaf functions that need some scratch space of their own will decrement the stack pointer to allocate some space on entry (since the stack grows down, and its “top” of the stack is its lowest address) and will increment it to deallocate that space on exit. Leaf functions that don’t call any other function can skip incrementing and decrementing this stack pointer, which is exactly why we didn’t see make_pair messing with the stack pointer.

To verify that callers are allocating space for the return struct in the shadow stack, let’s create a function that calls make_pair and then inspect its disassembly:

// pair.rs #[no_mangle] pub extern "C" fn make_default_pair() -> [i32; 2] { make_pair(42, 1337) }

I’ve annotated default_make_pair‘s disassembly below to make it clear how the shadow stack pointer is manipulated to create space for return values and how the pointer to that space is passed to make_pair:

;; pair.wasm (func $make_default_pair (param i32) (local i32) ;; Reserve 16 bytes of space in the shadow ;; stack. We only need 8 bytes, but LLVM keeps ;; the stack pointer 16-byte aligned. Global 0 ;; is the stack pointer. global.get 0 i32.const 16 i32.sub local.tee 1 global.set 0 ;; Get a pointer to the last 8 bytes of our ;; shadow stack space. This is our struct ;; return pointer argument, where the result ;; of `make_pair` will be written to. local.get 1 i32.const 8 i32.add ;; Call `make_pair` with the struct return ;; pointer and our default values. i32.const 42 i32.const 1337 call $make_pair ;; Copy the resulting pair into our own struct ;; return pointer's space. LLVM optimized this ;; into a single `i64` load and store, instead ;; of two `i32` load and stores. local.get 0 local.get 1 i64.load offset=8 i64.store align=4 ;; Restore the stack pointer to the original ;; value it had upon entering this function, ;; deallocating our shadow stack frame. local.get 1 i32.const 16 i32.add global.set 0 end )

When the caller is JavaScript, wasm-bindgen can use its knowledge of these calling conventions to generate JavaScript glue code that allocates shadow stack space, calls the function with the struct return pointer argument, reads the values out of linear memory, and finally deallocates the shadow stack space before converting the Wasm values into some JavaScript value.

But when using interface types directly, rather than polyfilling them, we can’t rely on generating glue code that has access to the Wasm module’s linear memory. First, the memory might not be exported. Second, the only glue code we have is interface adapters, not arbitrary JavaScript code. We want those values as proper return values, rather than through a side channel.

So I wrote a walrus transform in wasm-bindgen that converts functions that use a struct return pointer parameter without any actual Wasm return values, into multi-value functions that don’t take a struct return pointer parameter but return multiple resulting Wasm values instead. This transform is essentially a “reverse polyfill” for multi-value functions.

;; Before. ;; ;; First parameter is a struct return pointer. No ;; return values, as they are stored through the ;; struct return pointer. (func $make_pair (param i32 i32 i32) ;; ... ) ;; After. ;; ;; No more struct return pointer parameter. Return ;; values are actual Wasm results. (func $make_pair (param i32 i32) (result i32 i32) ;; ... )

The transform is only applied to exported functions that take a struct return pointer parameter, and rather than rewriting the source function in place, the transform leaves it unmodified but removes it from the Wasm module’s exports list. It generates a new function that replaces the old one in the Wasm module’s exports list. This new function allocates shadow stack space for the return value, calls the original function, reads the values out of the shadow stack onto the Wasm value stack, and finally deallocates the shadow stack space before returning.

For our running make_pair example, the transform produces an exported wrapper function like this:

;; pair.wasm (func $new_make_pair (param i32 i32) (result i32 i32) ;; Our struct return pointer that points to the ;; scratch space we are allocating on the shadow ;; stack for calling `$make_pair`. (local i32) ;; Allocate space on the shadow stack for the ;; result. global.get $shadow_stack_pointer i32.const 8 i32.sub local.tee 2 global.set $shadow_stack_pointer ;; Call the original `$make_pair` with our ;; allocated shadow stack space for its ;; results. local.get 2 local.get 0 local.get 1 call $make_pair ;; Read the return values out of the shadow ;; stack and place them onto the Wasm stack. local.get 2 i32.load local.get 2 i32.load offset=4 ;; Finally, restore the shadow stack pointer. local.get 2 i32.const 8 i32.add global.set $shadow_stack_pointer )

With this transform in place, wasm-bindgen can now generate multi-value function exports along with associated interface adapters that lift the concrete Wasm return values into abstract interface types.

The multi-value support and transform were implemented in wasm-bindgen in these pull requests:

Wasmtime and Cranelift

Ok, so at this point, we can generate multi-value Wasm binaries with the Rust and Wasm toolchain — woo! But now we need to be able to run these binaries.

Enter Wasmtime, the WebAssembly runtime built on top of the Cranelift code generator. Wasmtime translates WebAssembly into Cranelift’s IR with the cranelift-wasm crate, and then Cranelift compiles the IR down to native machine code.

Pipeline from a Wasm binary through Wasmtime and Cranelift to native code

Implementing multi-value Wasm support in Wasmtime and Cranelift roughly involved two steps:

  1. Translating multi-value Wasm into Cranelift IR
  2. Supporting arbitrary numbers of return values in Cranelift
Translating Multi-Value Wasm into Cranelift IR

Cranelift has its own intermediate representation that it manipulates, optimizes, and legalizes before generating machine code for the target architecture. In order for Cranelift to compile some code, you need to translate whatever you’re working with into Cranelift’s IR. In our case, that means translating Wasm into Cranelift’s IR. This process is analogous to rustc converting its mid-level intermediate representation (MIR) to LLVM’s IR.2

Cranelift’s IR is made up of (extended) basic blocks3 containing code in single, static-assignment form (SSA). SSA, as the name implies, means that variables can only be assigned to when defined, and can’t ever be re-assigned:

;; `42 + 1337` in Cranelift IR v0 = iconst.32 42 v1 = iconst.32 1337 v2 = iadd v0, v1

When translating to SSA form, most re-assignments to a variable x can be handled by defining a fresh x1 and replacing subsequent uses of x with x1, and then turning the next re-assignment into x2, etc. But that doesn’t work for points where control flow joins, such as the block following the consequent and alternative arms of an if/else.

Consider this Rust code, and how we might translate it into SSA:

let x; if some_condition() { // This version of `x` becomes `x0` when // translated to SSA. x = foo(); } else { // This version of `x` becomes `x1` when // translated to SSA. x = bar(); } // Does this use `x0` or `x1`?? do_stuff(x);

Should the do_stuff call at the bottom use x0 or x1 when translated into SSA? Neither!

SSA uses Φ (phi) functions to handle these cases. A phi function takes a number of mutually exclusive, control flow-dependent parameters and returns the one that was defined where control flow came from. In our example we would have x2 = Φ(x0, x1), and if some_condition() was true then x2 would get its value from x0. Otherwise, x2 would get its value from x1.

If SSA and phi functions are new to you and you’re feeling confused, don’t worry! It was confusing for me too when I first learned about this stuff. But Cranelift IR doesn’t use phi functions per se, it has something that I think is more intuitive: blocks can have formal parameters.

Translating our example to Cranelift IR, we get this:

;; Head of the `if`/`else`. ebb0: v0 = call some_condition() brnz v0, ebb1 jump ebb2 ;; Consequent. ebb1: v1 = call foo() jump ebb3(v1) ;; Alternative. ebb2: v2 = call bar() jump ebb3(v2) ;; Code following the `if`/`else`. ebb3(v3: i32): call do_stuff(v3)

Note that ebb3 takes a parameter for the control flow-dependent value that we should pass to do_stuff! And the jumps in ebb1 and ebb2 pass their locally-defined values “into” ebb3! This is equivalent to phi functions, but I find it much more intuitive.

Anyways, translating WebAssembly code into Cranelift IR happens in the cranelift-wasm crate. It uses wasmparser to decode the given blob of Wasm and validate it, and then constructs Cranelift IR via (you guessed it!) abstract interpretation. As cranelift-wasm interprets Wasm instructions, rather than pushing and popping Wasm values, it maintains a stack of Cranelift IR SSA values. As cranelift-wasm enters and exits Wasm control frames, it creates Cranelift IR basic blocks.

This process is fairly similar to walrus‘s IR construction, which was pretty similar to wasmparser‘s validation, and the whole thing felt pretty familiar by now. There were just a couple tricky bits.

The first tricky bit was remembering to add parameters (phi functions) to the first basic block for a Wasm loop‘s body, representing its Wasm stack parameters. This is necessary, because control flow joins from two places at the top of the loop body: from where we were when we first entered the loop, and from the bottom of the loop when we finish an iteration and are starting another. In terms of the abstract interpretation, this means you need to pop off the particular SSA values you have on the stack at the start of the loop, construct SSA values for the loop’s parameters, and then push those onto the stack instead. I originally overlooked this, resulting in a fair bit of head scratching and debugging mis-translated IR. Whoops!

Second, cranelift-wasm will track reachability during translation, and if some Wasm code is unreachable, we don’t even bother constructing Cranelift IR for it. But that boundary between unreachable and reachable code, and when one transitions to the other, can be a bit subtle. You can be in an unreachable state, fall through the current block into the following block, and become reachable once again. Throw in ifs with elses, and ifs without elses, and unconditional branches, and early returns, and it is easy for bugs to sneak in. And in the process of adding multi-value Wasm support, bugs did, in fact, sneak in. This time involving an if that was initially reachable, and whose consequent arm also ends reachable, but whose alternative arm ends unreachable. Given that, should the block following the consequent and alternative be reachable? Yes, but we were incorrectly computing that it shouldn’t be.

To fix this bug, I refactored how cranelift-wasm computes reachablity of code following an if. It now correctly determines that the following block is reachable if the head of the if is reachable and any of the following are true:

  • The consequent or alternative end reachable, in which case they will continue to the following block.
  • The consequent or alternative do an early branch (potentially a conditional branch) to the following block, and that branch is reachable.
  • There is no alternative, so if the if‘s condition is false, we go directly to the following block.

To be sure that we are handling all these edge cases correctly, I added tests enumerating every combination of reachability of an if‘s arms as well as early branches. Phew!

Finally, this bug first manifested itself in a 39 KiB Wasm file, and figuring out what was going on was made so much easier thanks to tools like wasm-reduce (a tool that is part of binaryen) and creduce (working on the WAT disassembly, rather than the binary Wasm). I forget which one I used this time, but I’ve successfully used both to turn big, complicated Wasm test cases into small, isolated test cases that highlight the bug at hand. These tools are real life savers so it is worth broadcasting their existence just in case anyone doesn’t know about them!

Translating multi-value Wasm into Cranelift IR happened in these pull requests:

Supporting Many Return Values in Cranelift

Cranelift IR the language supports returning arbitrarily many values from a function, but Cranelift the implementation only supported returning as many values as there are available registers in the calling convention that the function is using. For example, with the System V calling convention, you could return up to three pointer-sized values, and with the Windows fastcall calling convention, you could only return a single pointer-sized value.

So the question was:

How to return more values than can fit in registers?

This should trigger some deja vu: when compiling to Wasm, how was LLVM returning structures larger than could fit in a single Wasm value? Struct return pointer parameters! This is nothing new, and in fact its use is dictated by certain calling conventions, we just hadn’t implemented support for it in Cranelift yet. So that’s what I set out to do.

When Cranelift is given some initial IR, the IR is generally portable and machine independent. As the IR moves through Cranelift, eventually it reaches a legalization phase where instructions that don’t have a direct mapping to an machine code instruction in the target architecture are replaced with ones that do. For example, on 32-bit x86, Cranelift legalizes 64-bit arithmetic by expanding it into a series of 32-bit operations. During this process, we also legalize function signatures: passing a value that is larger than can fit in a register may need to be split into multiple parameters, each of which can fit in registers, for example. Signature legalization also assigns locations to formal parameters based on the function’s calling convention: this parameter should be in this register, and that parameter should be at this stack offset, etc.

My plan for implementing arbitrary numbers of return values via struct return pointer parameters was to hook into Cranelift’s legalization phase during signature legalization, legalizing return instructions, and legalizing call instructions.

When legalizing signatures, we need to determine whether a struct return pointer is required, and if so, update the signature to reflect that.

;; Before legalization. fn() -> i64, i64, i64, i64 fast ;; After legalization. fn (v0: i64 sret [%rdi]) -> i64 sret [%rax] fast

Here, fast means the signature is using our internal, unstable “fast” calling convention. The sret is an annotation for a parameter or return value, in this case documenting that it is being used as a struct return pointer. The %rdi and %rax are the registers assigned to the parameter and return value by the calling convention.4

After legalization, we’ve added the struct return pointer parameter, but we also removed the old returns, and we also return the struct return pointer parameter as well. Returning the struct return pointer is mandated by the System V ABI’s calling conventions, but we currently do the same thing for our internal, unstable calling convention as well.

After signatures are legalized, we need to legalize call and return instructions as well, so that they match the new, legalized signatures. Let’s turn our attention to the latter first.

Legalizing a return instruction removes the return values from the return instruction itself, and creates a series of preceding store instructions that write the return values through the struct return pointer. Here’s an example that is returning four i32 values:

;; Before legalization. ebb0: ;; ... return v0, v1, v2, v3 ;; After legalization. ebb0(v4: i64): ;; ... store notrap aligned v0, v4 store notrap aligned v1, v4+4 store notrap aligned v2, v4+8 store notrap aligned v3, v4+12 return v4

The new v4 value is the struct return pointer parameter. The notrap annotation on the store instruction is saying that this store can’t trigger a trap. It is the caller’s responsibility to give us a valid struct return pointer that is pointing to enough space to fit all of our return values. The aligned annotation is similar, saying that the pointer we are storing through is properly four-byte aligned for an i32. Again, the responsibility is on the caller to ensure the struct return pointer has at least the maximum alignment required by the return values’ types. The +4, +8, and +12 are static immediates that specify an offset to be added to the actual v4 operand to compute the destination address for the store.

Legalizing a call instruction has comparatively more responsibilities than legalizing a return instruction. Yes, it involves adding the struct return pointer argument to the call instruction itself, and then loading the values out of the struct return space after the callee returns to us. But it additionally must allocate the space for the struct return in the caller function’s stack frame, and it must ensure that the size and alignment invariants that the callee and its return instructions rely on are upheld.

Let’s take a look at an example of some caller function calling a callee function that returns four i32s:

;; Before legalization. function %caller() { fn0 = colocated %callee() -> i32, i32, i32, i32 ebb0: v0, v1, v2, v3 = call fn0() return } ;; After legalization. function %caller() { ss0 = sret_slot 16 sig0 = (i64 sret [%rdi]) -> i64 sret [%rax] fast fn0 = colocated %callee sig0 ebb0: v4 = stack_addr.i64 ss0 v5 = call fn0(v4) v6 = load.i32 notrap aligned v5 v0 -> v6 v7 = load.i32 notrap aligned v5+4 v1 -> v7 v8 = load.i32 notrap aligned v5+8 v2 -> v8 v9 = load.i32 notrap aligned v5+12 v3 -> v9 return }

The ss0 = sret_slot 16 is a sixteen byte stack slot that we created for the struct return space. It is also aligned to sixteen bytes, which is greater than necessary in this case, since we only need four byte alignment for the i32s. Similar to the stores in the legalized return, the loads in the legalized call are also annotated with notrap and aligned. v0 -> v6 establishes that v0 is another name for v6, and we don’t have to eagerly rewrite all the following uses of v0 into uses of v6 (even though there don’t happen to be any in this particular example).

With signature, call, and return legalization that all understand when and how to use struct return pointers, we now have full support for arbitrarily many multi-value returns in Cranelift and Wasmtime. This support was implemented in these pull requests:

Putting It All Together

Finally, let’s put everything together and create a multi-value Wasm binary with the Rust and Wasm toolchain and then run it in Wasmtime!

First, let’s create a new library crate with cargo:

$ cargo new --lib hello-multi-value Created library `hello-multi-value` package $ cd hello-multi-value/

We’re going to use wasm-bindgen to return a string from our Wasm function, so lets add it as a dependency. Additionally, we’re going to create a Wasm library, rather than an executable, so specify that this is a “cdylib”:

# Cargo.toml [lib] crate-type = ["cdylib"] [dependencies] wasm-bindgen = "0.2.54"

Let’s fill out src/lib.rs with our string-returning function:

use wasm_bindgen::prelude::*; #[wasm_bindgen] pub fn hello(name: &str) -> String { format!("Hello, {}!", name) }

We can build our Wasm library with cargo wasi:

$ cargo wasi build --release

This will automatically build a Wasm file for the wasm32-wasi target and then run wasm-bindgen‘s post-processor to add interface types and introduce multi-value. We can verify this with the wasm-objdump tool from WABT:

$ wasm-objdump -x \ target/wasm32-wasi/release/hello_multi_value.wasm hello_multi_value.wasm: file format wasm 0x1 Section Details: Type[14]: ... - type[6] (i32, i32) -> (i32, i32) ... Function[151]: ... - func[93] sig=6 ... Export[5]: - func[93] -> "hello" ...

We can see that the function is exported as `"hello"` and that it has the multi-value type `(i32, i32) -> (i32, i32)`. This shim function is indeed the one introduced by our multi-value transform we added to `wasm-bindgen` to wrap the original function and turn its struct return pointer into multi-value.

Finally, we can load this Wasm library into Wasmtime, which will use Cranelift to just-in-time (JIT) compile it to machine code, and then invoke the hello export with the string "multi-value Wasm":

$ wasmtime \ target/wasm32-wasi/release/hello_multi_value.wasm \ --invoke hello "multi-value Wasm" Hello, multi-value Wasm!

It works!!

Conclusion

The Rust and WebAssembly toolchain now supports generating Wasm binaries that make use of the multi-value proposal, and Cranelift and Wasmtime can compile and run multi-value Wasm binaries. This has been — I hope! — an interesting tale of implementing a Wasm feature through the whole vertical ecosystem, start to finish.

Lastly, and definitely not leastly, I’d like to thank Dan Gohman, Benjamin Bouvier, Alex Crichton, Yury Delendik, @bjorn3, and @iximeow for providing reviews and implementation suggestions for different pieces of this journey at various stages. Additionally, thanks again to Alex and Dan, and to Lin Clark and Till Schneidereit for all providing feedback on early drafts of this piece.

0 Additionally, Thomas Lively and some other folks are already working on adding multi-value Wasm support directly to LLVM, so that is definitely coming in the future, and it made sense for me to focus my attention elsewhere. ↩

1 There are some “stack-y” forms that don’t quite directly map to a tree. For example, you can insert stack-neutral, side-effectual instruction sequences in the middle of any part of the post-order encoding of an expression tree. Here is a call that produces some value, followed by a drop of that value, inserted into the middle of the post-order encoding of 1 + 2:

;; Instructions ;; Stack ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; i32.const 1 ;; [1] call $foo ;; [1, $result_of_foo] drop ;; [1] i32.const 2 ;; [1, 2] i32.add ;; [3]

These stack-y forms can be represented by introducing blocks that don’t also introduce labels for control flow branches. You can think of them as sort of similar to Common Lisp’s progn and prog0 forms or Scheme’s (begin ...) ↩

2 Fun fact: there is also ongoing work to make Cranelift a viable alternative backend for rustc! See the goals write up and the bjorn3/rustc_codegen_cranelift repo for details. ↩

3 Originally, Cranelift was designed to use extended basic blocks, rather than regular basic blocks. Both can only be entered at their head, but basic blocks additionally can only exit at their tail, while extended basic blocks can have conditional exits from the block in their middle. The idea is that extended basic blocks more directly match machine code which falls through untaken conditional branches to continue executing the next instruction. However, Cranelift is in the process of switching over to regular basic blocks, and removing support for extended basic blocks. The reasoning is that all its optimization passes end up essentially constructing and keeping track of basic blocks anyways, which added complexity, and the extended basic blocks weren’t ultimately carrying their weight. ↩

4 Semi-confusingly, the square brackets are just the syntax that Cranelift decided to use to surround parameter locations, and they do not represent dereferencing the way they would in Intel-flavored assembly syntax. ↩

The post Multi-Value All The Wasm! appeared first on Mozilla Hacks - the Web developer blog.

Categorieën: Mozilla-nl planet

The Mozilla Blog: State of Mozilla 2018: Annual Report

Mozilla planet - do, 21/11/2019 - 11:00

The State of Mozilla annual report for 2018 is now available here.

This report details how Mozilla operates and includes details from our financial reports for 2018. The State of Mozilla report release is timed to coincide with when we submit the Mozilla non-profit tax filing for the previous calendar year.

The 2018 State of Mozilla report focuses on how Mozilla leverages its unique structure and multi-pronged approach to influence some of the most pressing challenges people face online today. From misinformation to online privacy and security, in the last two years Mozilla has used its resources, influence and product know-how to push for systemic change that helps put people back at the center of online life.

This year’s report outlines Mozilla’s collective impact as a creator of consumer technology products, an advocacy organization and a key contributor to the development of internet policy and online standards and protocols that help ensure the internet is open and accessible to all.

Mozilla continues to believe that the internet can and should be a positive force for individuals and for societies. However, there are deep problems to be solved to make this true in an enduring way for the future. An obvious first step is to help people understand and protect themselves from current online harms. This gives Mozilla better knowledge to address the problems at a deeper level — to create new and better experiences where respect and security for the individual are built into our core product.

We measure our success not only by the adoption of our products, but also by our ability to increase the control people have in their online lives, our impact on the internet, our contribution to standards, and how we work to protect the overall health of the web.

None of the work we do or the impact we have would be possible without the dedication of our global community of contributors and loyal Firefox users. We are incredibly grateful for the support and we will continue to fight for the open internet.

We encourage you to get involved to help protect the future of the internet, join Mozilla.

The post State of Mozilla 2018: Annual Report appeared first on The Mozilla Blog.

Categorieën: Mozilla-nl planet

Nick Fitzgerald: Multi-Value All The Wasm!

Mozilla planet - do, 21/11/2019 - 09:00

Note: I am cross-posting this to my personal blog from the Bytecode Alliance blog and the Mozilla Hacks blog.

Multi-value is a proposed extension to core WebAssembly that enables functions to return many values, among other things. It is also a pre-requisite for Wasm interface types.

I’ve been adding multi-value support all over the place recently:

  • I added multi-value support to all the various crates in the Rust and WebAssembly toolchain, so that Rust projects can compile down to Wasm code that uses multi-value features.

  • I added multi-value support to Wasmtime, the WebAssembly runtime built on top of the Cranelift code generator, so that it can run Wasm code that uses multi-value features.

Now, as my multi-value efforts are wrapping up, it seems like a good time to reflect on the experience and write up everything that’s been required to get all this support in all these places.

Wait — What is Multi-Value Wasm?

In core WebAssembly, there are a couple of arity restrictions on the language:

  • functions can only return either zero or one value, and
  • instruction sequences like blocks, ifs, and loops cannot consume any stack values, and may only produce zero or one resulting stack value.

The multi-value proposal is an extension to the WebAssembly standard that lifts these arity restrictions. Under the new multi-value Wasm rules:

  • functions can return an arbitrary number of values, and
  • instruction sequences can consume and produce an arbitrary number of stack values.

The following snippets are only valid under the new rules introduced in the multi-value Wasm proposal:

;; A function that takes an `i64` and returns ;; three `i32`s. (func (param i64) (result i32 i32 i32) ...) ;; A loop that consumes an `i32` stack value ;; at the start of each iteration. loop (param i32) ... end ;; A block that produces two `i32` stack values. block (result i32 i32) ... end

The multi-value proposal is currently at phase 3 of the WebAssembly standardization process.

But Why Should I Care? Code Size

There are a few scenarios where compilers are forced to jump through hoops when producing multiple stack values for core Wasm. Workarounds include introducing temporary local variables, and using local.get and local.set instructions, because the arity restrictions on blocks mean that the values cannot be left on the stack.

Consider a scenario where we are computing two stack values: the pointer to a string in linear memory, and its length. Furthermore, imagine we are choosing between two different strings (which therefore have different pointer-and-length pairs) based on some condition. But whichever string we choose, we’re going to process the string in the same fashion, so we just want to push the pointer-and-length pair for our chosen string onto the stack, and control flow can join afterwards.

With multi-value, we can do this in a straightforward fashion:

call $compute_condition if (result i32 i32) call $get_first_string_pointer call $get_first_string_length else call $get_second_string_pointer call $get_second_string_length end

This encoding is also compact: only sixteen bytes!

When we’re targeting core Wasm, and multi-value isn’t available, we’re forced to pursue alternative, more convoluted forms. We can smuggle the stack values out of each if and else arm via temporary local values:

;; Introduce a pair of locals to hold the values ;; across the instruction sequence boundary. (local $string i32) (local $length i32) call $compute_condition if call $get_first_string_pointer local.set $string call $get_first_string_length local.set $length else call $get_second_string_pointer local.set $string call $get_second_string_length local.set $length end ;; Restore the values onto the stack, from their ;; temporaries. local.get $string local.get $length

This encoding requires 30 bytes, an overhead of fourteen bytes more than the ideal multi-value version. And if we were computing three values instead of two, there would be even more overhead, and the same is true for four values, etc… The additional overhead is proportional to how many values we’re producing in the if and else arms.

We can actually go a little smaller than that — still with core Wasm — by jumping through a different hoop. We can split this into two if ... else ... end blocks and duplicate the condition check to avoid introducing temporaries for each of the computed values themselves:

;; Introduce a local for the condition, so that ;; we only re-check it, and don't recompute it. (local $condition i32) ;; Compute and save the condition. call $compute_condition local.set $condition ;; Compute the first stack value. local.get $condition if (result i32) call $get_first_string_pointer else call $get_second_string_pointer end ;; Compute the second stack value. local.get $condition if (result i32) call $get_first_string_length else call $get_second_string_length end

This gets us down to 28 bytes. Two fewer than the last version, but still an overhead of twelve bytes compared to the multi-value encoding. And the overhead is still proportional to how many values we’re computing.

There’s no way around it: we need multi-value to get the most compact code here.

New Instructions

The multi-value proposal opens up the possibility for new instructions that produce multiple values:

  • An i32.divmod instruction of type [i32 i32] -> [i32 i32] that takes a numerator and divisor and produces both their quotient and remainder.

  • Arithmetic operations with an additional carry result. These could be used to better implement big ints, overflow checks, and saturating arithmetic.

Returning Small Structs More Efficiently

Returning multiple values from functions will allow us to more efficiently return small structures like Rust’s Results. Without multi-value returns, these relatively small structs that still don’t fit in a single Wasm value type get placed in linear memory temporarily. With multi-value returns, the values don’t escape to linear memory, and instead stay on the stack. This can be more efficient, since Wasm stack values are generally more amenable to optimization than loads and stores from linear memory.

Interface Types

Shrinking code size is great, and new instructions would be fancy, but here’s what I’m really excited about: WebAssembly interface types. Interface types used to be called “host bindings,” and they are the key to unlocking:

  • direct, optimized access to the browser’s DOM methods on the Web,
  • “shared-nothing linking” of WebAssembly modules, and
  • defining language-neutral interfaces, like WASI.

For all three use cases, we might want to return a string from a callee Wasm module. The caller that is consuming this string might be a Web browser, or it might be another Wasm module, or it might be a WASI-compatible Wasm runtime. In any case, a natural way to return the string is as two i32s:

  1. a pointer to the start of the string in linear memory, and
  2. the byte length of the string.

The interface adapter can then lift that pair of i32s into an abstract string type, and then lower it into the caller’s concrete string representation on the other side. Interface types are designed such that in most cases, this lifting and lowering can be optimized into a quick memory copy from the callee’s linear memory to the caller’s.

But before the interface adapters can do that lifting and lowering, they need access to the pointer and length pair, which means the callee Wasm function needs to return two values, which means we need multi-value Wasm for interface types.

All The Implementing!

Now that we know what multi-value Wasm is, and why it’s exciting, I’ll recount the tale of implementing support for it all over the place. I started with implementing multi-value support in the Rust and WebAssembly toolchain, and then I added support to the Wasmtime runtime, and the Cranelift code generator it’s built on top of.

Rust and WebAssembly Toolchain

What falls under the Rust and Wasm toolchain umbrella? It is a superset of the general Rust toolchain:

  • cargo: Manages builds and dependencies.
  • rustc: Compiles Rust sources into code.
  • LLVM: Used by rustc under the covers to optimize and generate code.

And then additionally, when targeting Wasm, we also use a few more moving parts:

  • wasm-bindgen: Part library and part Wasm post-processor, wasm-bindgen generates bindings for consuming and producing interfaces defined with interface types (and much more!)
  • walrus: A library for transforming and rewriting WebAssembly modules, used by wasm-bindgen’s post-processor.
  • wasmparser: An event-style parser for WebAssembly binaries, used by walrus.

Here’s a summary of the toolchain’s pipeline, showing the inputs and outputs between tools:

A diagram showing the pipeline of the Rust and Wasm toolchain.

My goal is to unlock interface types with multi-value functions. For now, I haven’t been focusing on code size wins from generating multi-value blocks. For my purposes, I only need to introduce multi-value functions at the edges of the Wasm module that talk to interface adapters; I don’t need to make all function bodies use the optimal multi-value instruction sequence constructs. Therefore, I decided to have wasm-bindgen’s post-processor rewrite certain functions to use multi-value returns, rather than add support in LLVM.0 With this approach I only needed to add support to the following tools:

  • cargo
  • rustc
  • LLVM
  • wasm-bindgen
  • walrus
  • wasmparser
wasmparser

wasmparser is an event-style parser for WebAssembly binaries. It may seem strange that adding toolchain support for generating multi-value Wasm began with parsing multi-value Wasm. But it is necessary to make testing easy and painless, and we needed it eventually for Wasmtime anyways, which also uses wasmparser.

In core Wasm, the optional value type result of a block, loop, or if is encoded directly in the instruction:

  • a 0x40 byte means there is no result
  • a 0x7f byte means there is a single i32 result
  • a 0x7e byte means there is a single i64 result
  • etc…

With multi-value Wasm, there are not only zero or one resulting value types, there are also parameter types. Blocks can have the same set of types that functions can have. Functions already de-duplicate their types in the “Type” section of a Wasm binary and reference them via index. With multi-value, blocks do that now as well. But how does this co-exist with non-multi-value block types?

The index is encoded as a signed variable-length integer, using the LEB128 encoding. If we interpret non-multi-value blocks’ optional result value type as a signed LEB128, we get:

  • -64 (the smallest number that can be encoded as a single byte with signed LEB128) means there is no result
  • -1 means there is a single i32 result
  • -2 means there is a single i64 result
  • etc..

They’re all negative, leaving the positive numbers to be interpreted as indices into the “Type” section for multi-value blocks! A nice little encoding trick and bit of foresight from the WebAssembly standards folks.

Adding support for parsing these was straightforward, but wasmparser also supports validating the Wasm as it parses it. Adding validation support was a little bit more involved.

wasmparser’s validation implementation is similar to the validation algorithm presented in the appendix of the WebAssembly spec: it abstractly interprets the Wasm instructions, maintaining a stack of types, rather than a stack of values. If any operation uses operands of the wrong type — for example the stack has an f32 at its top when we are executing an i32.add instruction, and therefore expect two i32s on top of the stack — then validation fails. If there are no type errors, then it succeeds. There are some complications when dealing with stack-polymorphic instructions, like drop, but they don’t really interact with multi-value.

Whenever wasmparser encounters a block, loop, or if instruction, it pushes an associated control frame, that keeps track of how deep in the stack instructions within this block can access. Before multi-value, the limit was always the length of the stack upon entering the block, because blocks didn’t take any values from the stack. With multi-value, this limit becomes stack.len() - block.num_params(). When exiting a block, wasmparser pops the associated control frame. It check that the top n types on the stack match the block’s result types, and that the stack’s length is frame.depth + n. Before multi-value, n was always either 0 or 1, but now it can be any non-negative integer.

The final bit of validation that is impacted by multi-value is when an if needs to have an else or not. In core Wasm, if the if does not produce a resulting value on the stack, it doesn’t need an else arm since the whole if’s typing is [] -> [] which is also the typing for a no-op. With multi-value this is generalized to any if where the inputs and outputs are the same types: [t*] -> [t*]. Easy to implement, but also very easy to overlook (like I originally did!)

Multi-value support was added to wasmparser in these pull requests:

walrus

walrus is a WebAssembly to WebAssembly transformation library. We use it to generate glue code in wasm-bindgen and to polyfill WebAssembly features.

walrus constructs its own intermediate representation (IR) for WebAssembly. Similar to how wasmparser validates Wasm instructions, walrus also abstractly interprets the instructions while building up its IR. This meant that adding support for constructing multi-value IR to walrus was very similar to adding multi-value validation support to wasmparser. In fact, walrus also validates the Wasm while it is constructing its IR.

But multi-value has big implications for the IR itself. Before multi-value, you could view Wasm’s stack-based instructions as a post-order encoding of an expression tree.

Consider the expression (a + b) * (c - d). As an expression tree, it looks like this:

* / \ / \ + - / \ / \ a b c d

A post-order traversal of a tree is where a node is visited after its children. A post-order traversal of our example expression tree would be:

a b + c d - *

Assume that a, b, c, and d are Wasm locals of type i32, with the values 9, 7, 5, and 3 respectively. We can convert this post-order directly into a sequence of Wasm instructions that build up their results on the Wasm stack:

;; Instructions ;; Stack ;;;;;;;;;;;;;;;;;;;;;;;;;;;;; local.get $a ;; [9] local.get $b ;; [9, 7] i32.add ;; [16] local.get $c ;; [16, 5] local.get $d ;; [16, 5, 3] i32.sub ;; [16, 2] i32.mul ;; [32]

This correspondence between trees and Wasm stack instructions made using a tree-like IR in walrus, where nodes are instructions and a node’s children are the instructions that produce the parent’s input values, very natural.1 Our IR used to look something like this:

pub enum Expr { // A `local.get` instruction. LocalGet(LocalId), // An `i32.add` instruction. I32Add(ExprId, ExprId), // Etc... }

But multi-value threw a wrench in this tree-like representation: now that an instruction can produce multiple values, when we have a parent⟶child edge in the tree, how do we know which of the child’s resulting values the parent wants to use? And also, if two different parents are each using one of the two values an instruction generates, we fundamentally don’t have a tree anymore, we have a directed, acyclic graph (DAG).

We considered generalizing our tree representation into a DAG, and labeling edges with n to represent using the nth resulting value of an instruction. We weighed the complexity of implementing this representation against what our current use cases in wasm-bindgen demand, along with any future use cases we could think of. Ultimately, we decided it wasn’t worth the effort, since we don’t need that level of detail for any of the transformations or manipulations that wasm-bindgen performs, or that we foresee it doing in the future.

Instead, we decided that within a block, representing instructions as a simple list is good enough for our use cases, so now our IR looks something like this:

pub struct Block(Vec<Instr>); pub enum Instr { // A `local.get` instruction. LocalGet(LocalId), // An `i32.add` instruction. Note that its // children are left implicit now. I32Add, // Etc... }

Additionally, it turns out it is faster to construct and traverse this list-based representation, so switching representations in walrus also gave wasm-bindgen a nice little speed up.

The walrus support for multi-value was implemented in these pull requests:

wasm-bindgen

wasm-bindgen facilitates high-level interactions between Wasm modules and their host. Often that host is a Web browser and its DOM methods, or some user-written JavaScript. Other times it is an outside-the-Web Wasm runtime, like Wasmtime, using WASI and interface types. wasm-bindgen acts as a polyfill for the interface types proposal, plus some extra batteries included for a powerful user experience.

One of wasm-bindgen’s responsibilities is translating the return value of a Wasm function into something that the host caller can understand. When using interface types directly with Wasmtime, this means generating interface adapters that lift the concrete Wasm return values into abstract interface types. When the caller is some JavaScript code on the Web, it means generating some JavaScript code to convert the Wasm values into JavaScript values.

Let’s take a look at some Rust functions and the Wasm they get compiled down into.

First, consider when we are returning a single integer from a Rust function:

// random.rs #[no_mangle] pub extern "C" fn get_random_int() -> i32 { // Chosen by fair dice roll. 4 }

And here is the disassembly of that Rust code compiled to Wasm:

;; random.wasm (func $get_random_int (result i32) i32.const 4 )

The resulting Wasm function’s signature is effectively identical to the Rust function’s signature. No surprises here. It is easy for wasm-bindgen to translate the resulting Wasm value to whatever is needed because wasm-bindgen has direct access to it; it’s right there.

Now let’s look at returning compound structures from Rust that don’t fit in a single Wasm value:

// pair.rs #[no_mangle] pub extern "C" fn make_pair(a: i32, b: i32) -> [i32; 2] { [a, b] }

And here is the disassembly of this new Rust code compiled to Wasm:

;; pair.wasm (func $make_pair (param i32 i32 i32) local.get 0 local.get 2 i32.store offset=4 local.get 0 local.get 1 i32.store )

The signature for the make_pair function in pair.wasm doesn’t look like its corresponding signature in pair.rs! It has three parameters instead of two, and it isn’t returning any values, let alone a pair.

What’s happening is that LLVM doesn’t support multi-value yet so it can’t return two i32s directly from the function. Instead, callers pass in a “struct return” pointer to some space that they’ve reserved for the return value, and make_pair will write its return value through that struct return pointer into the reserved space. By convention, LLVM uses the first parameter as the struct return pointer, so the second Wasm parameter is our original a parameter in Rust and the third Wasm parameter is our original b parameter in Rust. We can see that the Wasm function is writing the b field first, and then the a field second.

How is space reserved for the struct return? Distinct from the Wasm standard’s stack that instructions push values to and pop values from, LLVM emits code to maintain a “shadow stack” in linear memory. There is a global dedicated as the stack pointer, and always points to the top of the stack. Non-leaf functions that need some scratch space of their own will decrement the stack pointer to allocate some space on entry (since the stack grows down, and its “top” of the stack is its lowest address) and will increment it to deallocate that space on exit. Leaf functions that don’t call any other function can skip incrementing and decrementing this stack pointer, which is exactly why we didn’t see make_pair messing with the stack pointer.

To verify that callers are allocating space for the return struct in the shadow stack, let’s create a function that calls make_pair and then inspect its disassembly:

// pair.rs #[no_mangle] pub extern "C" fn make_default_pair() -> [i32; 2] { make_pair(42, 1337) }

I’ve annotated default_make_pair’s disassembly below to make it clear how the shadow stack pointer is manipulated to create space for return values and how the pointer to that space is passed to make_pair:

;; pair.wasm (func $make_default_pair (param i32) (local i32) ;; Reserve 16 bytes of space in the shadow ;; stack. We only need 8 bytes, but LLVM keeps ;; the stack pointer 16-byte aligned. Global 0 ;; is the stack pointer. global.get 0 i32.const 16 i32.sub local.tee 1 global.set 0 ;; Get a pointer to the last 8 bytes of our ;; shadow stack space. This is our struct ;; return pointer argument, where the result ;; of `make_pair` will be written to. local.get 1 i32.const 8 i32.add ;; Call `make_pair` with the struct return ;; pointer and our default values. i32.const 42 i32.const 1337 call $make_pair ;; Copy the resulting pair into our own struct ;; return pointer's space. LLVM optimized this ;; into a single `i64` load and store, instead ;; of two `i32` load and stores. local.get 0 local.get 1 i64.load offset=8 i64.store align=4 ;; Restore the stack pointer to the original ;; value it had upon entering this function, ;; deallocating our shadow stack frame. local.get 1 i32.const 16 i32.add global.set 0 end )

When the caller is JavaScript, wasm-bindgen can use its knowledge of these calling conventions to generate JavaScript glue code that allocates shadow stack space, calls the function with the struct return pointer argument, reads the values out of linear memory, and finally deallocates the shadow stack space before converting the Wasm values into some JavaScript value.

But when using interface types directly, rather than polyfilling them, we can’t rely on generating glue code that has access to the Wasm module’s linear memory. First, the memory might not be exported. Second, the only glue code we have is interface adapters, not arbitrary JavaScript code. We want those values as proper return values, rather than through a side channel.

So I wrote a walrus transform in wasm-bindgen that converts functions that use a struct return pointer parameter without any actual Wasm return values, into multi-value functions that don’t take a struct return pointer parameter but return multiple resulting Wasm values instead. This transform is essentially a “reverse polyfill” for multi-value functions.

;; Before. ;; ;; First parameter is a struct return pointer. No ;; return values, as they are stored through the ;; struct return pointer. (func $make_pair (param i32 i32 i32) ;; ... ) ;; After. ;; ;; No more struct return pointer parameter. Return ;; values are actual Wasm results. (func $make_pair (param i32 i32) (result i32 i32) ;; ... )

The transform is only applied to exported functions that take a struct return pointer parameter, and rather than rewriting the source function in place, the transform leaves it unmodified but removes it from the Wasm module’s exports list. It generates a new function that replaces the old one in the Wasm module’s exports list. This new function allocates shadow stack space for the return value, calls the original function, reads the values out of the shadow stack onto the Wasm value stack, and finally deallocates the shadow stack space before returning.

For our running make_pair example, the transform produces an exported wrapper function like this:

;; pair.wasm (func $new_make_pair (param i32 i32) (result i32 i32) ;; Our struct return pointer that points to the ;; scratch space we are allocating on the shadow ;; stack for calling `$make_pair`. (local i32) ;; Allocate space on the shadow stack for the ;; result. global.get $shadow_stack_pointer i32.const 8 i32.sub local.tee 2 global.set $shadow_stack_pointer ;; Call the original `$make_pair` with our ;; allocated shadow stack space for its ;; results. local.get 2 local.get 0 local.get 1 call $make_pair ;; Read the return values out of the shadow ;; stack and place them onto the Wasm stack. local.get 2 i32.load local.get 2 i32.load offset=4 ;; Finally, restore the shadow stack pointer. local.get 2 i32.const 8 i32.add global.set $shadow_stack_pointer )

With this transform in place, wasm-bindgen can now generate multi-value function exports along with associated interface adapters that lift the concrete Wasm return values into abstract interface types.

The multi-value support and transform were implemented in wasm-bindgen in these pull requests:

Wasmtime and Cranelift

Ok, so at this point, we can generate multi-value Wasm binaries with the Rust and Wasm toolchain — woo! But now we need to be able to run these binaries.

Enter Wasmtime, the WebAssembly runtime built on top of the Cranelift code generator. Wasmtime translates WebAssembly into Cranelift’s IR with the cranelift-wasm crate, and then Cranelift compiles the IR down to native machine code.

Pipeline from a Wasm binary through Wasmtime and Cranelift to native code

Implementing multi-value Wasm support in Wasmtime and Cranelift roughly involved two steps:

  1. Translating multi-value Wasm into Cranelift IR
  2. Supporting arbitrary numbers of return values in Cranelift
Translating Multi-Value Wasm into Cranelift IR

Cranelift has its own intermediate representation that it manipulates, optimizes, and legalizes before generating machine code for the target architecture. In order for Cranelift to compile some code, you need to translate whatever you’re working with into Cranelift’s IR. In our case, that means translating Wasm into Cranelift’s IR. This process is analogous to rustc converting its mid-level intermediate representation (MIR) to LLVM’s IR.2

Cranelift’s IR is made up of (extended) basic blocks3 containing code in single, static-assignment form (SSA). SSA, as the name implies, means that variables can only be assigned to when defined, and can’t ever be re-assigned:

;; `42 + 1337` in Cranelift IR v0 = iconst.32 42 v1 = iconst.32 1337 v2 = iadd v0, v1

When translating to SSA form, most re-assignments to a variable x can be handled by defining a fresh x1 and replacing subsequent uses of x with x1, and then turning the next re-assignment into x2, etc. But that doesn’t work for points where control flow joins, such as the block following the consequent and alternative arms of an if/else.

Consider this Rust code, and how we might translate it into SSA:

let x; if some_condition() { // This version of `x` becomes `x0` when // translated to SSA. x = foo(); } else { // This version of `x` becomes `x1` when // translated to SSA. x = bar(); } // Does this use `x0` or `x1`?? do_stuff(x);

Should the do_stuff call at the bottom use x0 or x1 when translated into SSA? Neither!

SSA uses Φ (phi) functions to handle these cases. A phi function takes a number of mutually exclusive, control flow-dependent parameters and returns the one that was defined where control flow came from. In our example we would have x2 = Φ(x0, x1), and if some_condition() was true then x2 would get its value from x0. Otherwise, x2 would get its value from x1.

If SSA and phi functions are new to you and you’re feeling confused, don’t worry! It was confusing for me too when I first learned about this stuff. But Cranelift IR doesn’t use phi functions per se, it has something that I think is more intuitive: blocks can have formal parameters.

Translating our example to Cranelift IR, we get this:

;; Head of the `if`/`else`. ebb0: v0 = call some_condition() brnz v0, ebb1 jump ebb2 ;; Consequent. ebb1: v1 = call foo() jump ebb3(v1) ;; Alternative. ebb2: v2 = call bar() jump ebb3(v2) ;; Code following the `if`/`else`. ebb3(v3: i32): call do_stuff(v3)

Note that ebb3 takes a parameter for the control flow-dependent value that we should pass to do_stuff! And the jumps in ebb1 and ebb2 pass their locally-defined values “into” ebb3! This is equivalent to phi functions, but I find it much more intuitive.

Anyways, translating WebAssembly code into Cranelift IR happens in the cranelift-wasm crate. It uses wasmparser to decode the given blob of Wasm and validate it, and then constructs Cranelift IR via (you guessed it!) abstract interpretation. As cranelift-wasm interprets Wasm instructions, rather than pushing and popping Wasm values, it maintains a stack of Cranelift IR SSA values. As cranelift-wasm enters and exits Wasm control frames, it creates Cranelift IR basic blocks.

This process is fairly similar to walrus’s IR construction, which was pretty similar to wasmparser’s validation, and the whole thing felt pretty familiar by now. There were just a couple tricky bits.

The first tricky bit was remembering to add parameters (phi functions) to the first basic block for a Wasm loop’s body, representing its Wasm stack parameters. This is necessary, because control flow joins from two places at the top of the loop body: from where we were when we first entered the loop, and from the bottom of the loop when we finish an iteration and are starting another. In terms of the abstract interpretation, this means you need to pop off the particular SSA values you have on the stack at the start of the loop, construct SSA values for the loop’s parameters, and then push those onto the stack instead. I originally overlooked this, resulting in a fair bit of head scratching and debugging mis-translated IR. Whoops!

Second, cranelift-wasm will track reachability during translation, and if some Wasm code is unreachable, we don’t even bother constructing Cranelift IR for it. But that boundary between unreachable and reachable code, and when one transitions to the other, can be a bit subtle. You can be in an unreachable state, fall through the current block into the following block, and become reachable once again. Throw in ifs with elses, and ifs without elses, and unconditional branches, and early returns, and it is easy for bugs to sneak in. And in the process of adding multi-value Wasm support, bugs did, in fact, sneak in. This time involving an if that was initially reachable, and whose consequent arm also ends reachable, but whose alternative arm ends unreachable. Given that, should the block following the consequent and alternative be reachable? Yes, but we were incorrectly computing that it shouldn’t be.

To fix this bug, I refactored how cranelift-wasm computes reachablity of code following an if. It now correctly determines that the following block is reachable if the head of the if is reachable and any of the following are true:

  • The consequent or alternative end reachable, in which case they will continue to the following block.
  • The consequent or alternative do an early branch (potentially a conditional branch) to the following block, and that branch is reachable.
  • There is no alternative, so if the if’s condition is false, we go directly to the following block.

To be sure that we are handling all these edge cases correctly, I added tests enumerating every combination of reachability of an if’s arms as well as early branches. Phew!

Finally, this bug first manifested itself in a 39 KiB Wasm file, and figuring out what was going on was made so much easier thanks to tools like wasm-reduce (a tool that is part of binaryen) and creduce (working on the WAT disassembly, rather than the binary Wasm). I forget which one I used this time, but I’ve successfully used both to turn big, complicated Wasm test cases into small, isolated test cases that highlight the bug at hand. These tools are real life savers so it is worth broadcasting their existence just in case anyone doesn’t know about them!

Translating multi-value Wasm into Cranelift IR happened in these pull requests:

Supporting Many Return Values in Cranelift

Cranelift IR the language supports returning arbitrarily many values from a function, but Cranelift the implementation only supported returning as many values as there are available registers in the calling convention that the function is using. For example, with the System V calling convention, you could return up to three pointer-sized values, and with the Windows fastcall calling convention, you could only return a single pointer-sized value.

So the question was:

How to return more values than can fit in registers?

This should trigger some deja vu: when compiling to Wasm, how was LLVM returning structures larger than could fit in a single Wasm value? Struct return pointer parameters! This is nothing new, and in fact its use is dictated by certain calling conventions, we just hadn’t implemented support for it in Cranelift yet. So that’s what I set out to do.

When Cranelift is given some initial IR, the IR is generally portable and machine independent. As the IR moves through Cranelift, eventually it reaches a legalization phase where instructions that don’t have a direct mapping to an machine code instruction in the target architecture are replaced with ones that do. For example, on 32-bit x86, Cranelift legalizes 64-bit arithmetic by expanding it into a series of 32-bit operations. During this process, we also legalize function signatures: passing a value that is larger than can fit in a register may need to be split into multiple parameters, each of which can fit in registers, for example. Signature legalization also assigns locations to formal parameters based on the function’s calling convention: this parameter should be in this register, and that parameter should be at this stack offset, etc.

My plan for implementing arbitrary numbers of return values via struct return pointer parameters was to hook into Cranelift’s legalization phase during signature legalization, legalizing return instructions, and legalizing call instructions.

When legalizing signatures, we need to determine whether a struct return pointer is required, and if so, update the signature to reflect that.

;; Before legalization. fn() -> i64, i64, i64, i64 fast ;; After legalization. fn (v0: i64 sret [%rdi]) -> i64 sret [%rax] fast

Here, fast means the signature is using our internal, unstable “fast” calling convention. The sret is an annotation for a parameter or return value, in this case documenting that it is being used as a struct return pointer. The %rdi and %rax are the registers assigned to the parameter and return value by the calling convention.4

After legalization, we’ve added the struct return pointer parameter, but we also removed the old returns, and we also return the struct return pointer parameter as well. Returning the struct return pointer is mandated by the System V ABI’s calling conventions, but we currently do the same thing for our internal, unstable calling convention as well.

After signatures are legalized, we need to legalize call and return instructions as well, so that they match the new, legalized signatures. Let’s turn our attention to the latter first.

Legalizing a return instruction removes the return values from the return instruction itself, and creates a series of preceding store instructions that write the return values through the struct return pointer. Here’s an example that is returning four i32 values:

;; Before legalization. ebb0: ;; ... return v0, v1, v2, v3 ;; After legalization. ebb0(v4: i64): ;; ... store notrap aligned v0, v4 store notrap aligned v1, v4+4 store notrap aligned v2, v4+8 store notrap aligned v3, v4+12 return v4

The new v4 value is the struct return pointer parameter. The notrap annotation on the store instruction is saying that this store can’t trigger a trap. It is the caller’s responsibility to give us a valid struct return pointer that is pointing to enough space to fit all of our return values. The aligned annotation is similar, saying that the pointer we are storing through is properly four-byte aligned for an i32. Again, the responsibility is on the caller to ensure the struct return pointer has at least the maximum alignment required by the return values’ types. The +4, +8, and +12 are static immediates that specify an offset to be added to the actual v4 operand to compute the destination address for the store.

Legalizing a call instruction has comparatively more responsibilities than legalizing a return instruction. Yes, it involves adding the struct return pointer argument to the call instruction itself, and then loading the values out of the struct return space after the callee returns to us. But it additionally must allocate the space for the struct return in the caller function’s stack frame, and it must ensure that the size and alignment invariants that the callee and its return instructions rely on are upheld.

Let’s take a look at an example of some caller function calling a callee function that returns four i32s:

;; Before legalization. function %caller() { fn0 = colocated %callee() -> i32, i32, i32, i32 ebb0: v0, v1, v2, v3 = call fn0() return } ;; After legalization. function %caller() { ss0 = sret_slot 16 sig0 = (i64 sret [%rdi]) -> i64 sret [%rax] fast fn0 = colocated %callee sig0 ebb0: v4 = stack_addr.i64 ss0 v5 = call fn0(v4) v6 = load.i32 notrap aligned v5 v0 -> v6 v7 = load.i32 notrap aligned v5+4 v1 -> v7 v8 = load.i32 notrap aligned v5+8 v2 -> v8 v9 = load.i32 notrap aligned v5+12 v3 -> v9 return }

The ss0 = sret_slot 16 is a sixteen byte stack slot that we created for the struct return space. It is also aligned to sixteen bytes, which is greater than necessary in this case, since we only need four byte alignment for the i32s. Similar to the stores in the legalized return, the loads in the legalized call are also annotated with notrap and aligned. v0 -> v6 establishes that v0 is another name for v6, and we don’t have to eagerly rewrite all the following uses of v0 into uses of v6 (even though there don’t happen to be any in this particular example).

With signature, call, and return legalization that all understand when and how to use struct return pointers, we now have full support for arbitrarily many multi-value returns in Cranelift and Wasmtime. This support was implemented in these pull requests:

Putting It All Together

Finally, let’s put everything together and create a multi-value Wasm binary with the Rust and Wasm toolchain and then run it in Wasmtime!

First, let’s create a new library crate with cargo:

$ cargo new --lib hello-multi-value Created library `hello-multi-value` package $ cd hello-multi-value/

We’re going to use wasm-bindgen to return a string from our Wasm function, so lets add it as a dependency. Additionally, we’re going to create a Wasm library, rather than an executable, so specify that this is a “cdylib”:

# Cargo.toml [lib] crate-type = ["cdylib"] [dependencies] wasm-bindgen = "0.2.54"

Let’s fill out src/lib.rs with our string-returning function:

use wasm_bindgen::prelude::*; #[wasm_bindgen] pub fn hello(name: &str) -> String { format!("Hello, {}!", name) }

We can build our Wasm library with cargo wasi:

$ cargo wasi build --release

This will automatically build a Wasm file for the wasm32-wasi target and then run wasm-bindgen’s post-processor to add interface types and introduce multi-value. We can verify this with the wasm-objdump tool from WABT:

$ wasm-objdump -x \ target/wasm32-wasi/release/hello_multi_value.wasm hello_multi_value.wasm: file format wasm 0x1 Section Details: Type[14]: ... - type[6] (i32, i32) -> (i32, i32) ... Function[151]: ... - func[93] sig=6 <hello multivalue shim> ... Export[5]: - func[93] <hello multivalue shim> -> "hello" ...

We can see that the <hello multivalue shim> function is exported as "hello" and that it has the multi-value type (i32, i32) -> (i32, i32). This shim function is indeed the one introduced by our multi-value transform we added to wasm-bindgen to wrap the original <hello> function and turn its struct return pointer into multi-value.

Finally, we can load this Wasm library into Wasmtime, which will use Cranelift to just-in-time (JIT) compile it to machine code, and then invoke the hello export with the string "multi-value Wasm":

$ wasmtime \ target/wasm32-wasi/release/hello_multi_value.wasm \ --invoke hello "multi-value Wasm" Hello, multi-value Wasm!

It works!!

Conclusion

The Rust and WebAssembly toolchain now supports generating Wasm binaries that make use of the multi-value proposal, and Cranelift and Wasmtime can compile and run multi-value Wasm binaries. This has been — I hope! — an interesting tale of implementing a Wasm feature through the whole vertical ecosystem, start to finish.

Lastly, and definitely not leastly, I’d like to thank Dan Gohman, Benjamin Bouvier, Alex Crichton, Yury Delendik, @bjorn3, and @iximeow for providing reviews and implementation suggestions for different pieces of this journey at various stages. Additionally, thanks again to Alex and Dan, and to Lin Clark and Till Schneidereit for all providing feedback on early drafts of this piece.

0 Additionally, Thomas Lively and some other folks are already working on adding multi-value Wasm support directly to LLVM, so that is definitely coming in the future, and it made sense for me to focus my attention elsewhere.

1 There are some “stack-y” forms that don’t quite directly map to a tree. For example, you can insert stack-neutral, side-effectual instruction sequences in the middle of any part of the post-order encoding of an expression tree. Here is a call that produces some value, followed by a drop of that value, inserted into the middle of the post-order encoding of 1 + 2:

;; Instructions ;; Stack ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; i32.const 1 ;; [1] call $foo ;; [1, $result_of_foo] drop ;; [1] i32.const 2 ;; [1, 2] i32.add ;; [3]

These stack-y forms can be represented by introducing blocks that don’t also introduce labels for control flow branches. You can think of them as sort of similar to Common Lisp’s progn and prog0 forms or Scheme’s (begin ...)

2 Fun fact: there is also ongoing work to make Cranelift a viable alternative backend for rustc! See the goals write up and the bjorn3/rustc_codegen_cranelift repo for details.

3 Originally, Cranelift was designed to use extended basic blocks, rather than regular basic blocks. Both can only be entered at their head, but basic blocks additionally can only exit at their tail, while extended basic blocks can have conditional exits from the block in their middle. The idea is that extended basic blocks more directly match machine code which falls through untaken conditional branches to continue executing the next instruction. However, Cranelift is in the process of switching over to regular basic blocks, and removing support for extended basic blocks. The reasoning is that all its optimization passes end up essentially constructing and keeping track of basic blocks anyways, which added complexity, and the extended basic blocks weren’t ultimately carrying their weight.

4 Semi-confusingly, the square brackets are just the syntax that Cranelift decided to use to surround parameter locations, and they do not represent dereferencing the way they would in Intel-flavored assembly syntax.

Categorieën: Mozilla-nl planet

Karl Dubost: Saving Webcompat images as a microservice

Mozilla planet - do, 21/11/2019 - 02:40

Update: You may want to fast forward to the latest part… of this blog post. (Head explodes).

Thinking out loud on separating our images into a separate service. The initial goal was to push the images to the cloud, but I think we could probably have a first step. We could keep the images on our server, but instead of the current save, we could send them to another service, let say upload.webcompat.com with a HTTP PUT. And this service would save them locally.

That way it would allow us two things:

  1. Virtualize the core app on heroku if needed
  2. Replace when we are ready the microservice by another cloud hosting solution.

All of this is mainly thinking for now.

Anatomy of our environment

config/environment.py defines:

UPLOADS_DEFAULT_DEST = os.environ.get('PROD_UPLOADS_DEFAULT_DEST') UPLOADS_DEFAULT_URL = os.environ.get('PROD_UPLOADS_DEFAULT_URL')

The maximum limit for images is defined in __init__.py Currently in views.py, there is a route for localhost upload.

# set limit of 5.5MB for file uploads # in practice, this is ~4MB (5.5 / 1.37) # after the data URI is saved to disk app.config['MAX_CONTENT_LENGTH'] = 5.5 * 1024 * 1024

The localhost part would probably not changed much. This is just for reading the images URL.

if app.config['LOCALHOST']: @app.route('/uploads/<path:filename>') def download_file(filename): """Route just for local environments to send uploaded images. In production, nginx handles this without needing to touch the Python app. """ return send_from_directory( app.config['UPLOADS_DEFAULT_DEST'], filename)

then the api for uploads is defined in api/uploads.py

This is where the production route is defined.

@uploads.route('/', methods=['POST']) def upload(): '''Endpoint to upload an image. If the image asset passes validation, it's saved as: UPLOADS_DEFAULT_DEST + /year/month/random-uuid.ext Returns a JSON string that contains the filename and url. ''' … # cut some stuff. try: upload = Upload(imagedata) upload.save() data = { 'filename': upload.get_filename(upload.image_path), 'url': upload.get_url(upload.image_path), 'thumb_url': upload.get_url(upload.thumb_path) } return (json.dumps(data), 201, {'content-type': JSON_MIME}) except (TypeError, IOError): abort(415) except RequestEntityTooLarge: abort(413)

upload.save is basically where we should replace this by an HTTP PUT to a micro service.

What is Amazon S3 doing?

In these musings, I wonder if we could mimick the way Amazon S3 operates at a very high level. No need to replicate everything. We just need to save some bytes into a folder structure.

boto 3 has a documentation for uploading files.

def upload_file(file_name, bucket, object_name=None): """Upload a file to an S3 bucket :param file_name: File to upload :param bucket: Bucket to upload to :param object_name: S3 object name. If not specified then file_name is used :return: True if file was uploaded, else False """ # If S3 object_name was not specified, use file_name if object_name is None: object_name = file_name # Upload the file s3_client = boto3.client('s3') try: response = s3_client.upload_file(file_name, bucket, object_name) except ClientError as e: logging.error(e) return False return True

We could keep the image validation on the size of webcompat.com, but then the naming and checking is done. We can save this to a service the same way aws is doing.

So our priviledged service could accept images and save them locally in the same folder structure a separate flask structure. And later on, we could adjust it to use S3.

Surprise. Surprise.

I just found out that each time you put an image in an issue or a comment. GitHub is making a private copy of this image. Not sure if it's borderline with regards to property.

If you enter:

!['m root](http://www.la-grange.net/2019/01/01/2535-misere)

Then it creates this markup.

<p><a target="_blank" rel="noopener noreferrer" href="https://camo.githubusercontent.com/a285646de4a7c3b3cdd3e82d599e46607df8d3cc/687474703a2f2f7777772e6c612d6772616e67652e6e65742f323031392f30312f30312f323533352d6d6973657265"><img src="https://camo.githubusercontent.com/a285646de4a7c3b3cdd3e82d599e46607df8d3cc/687474703a2f2f7777772e6c612d6772616e67652e6e65742f323031392f30312f30312f323533352d6d6973657265" alt="I'm root" data-canonical-src="http://www.la-grange.net/2019/01/01/2535-misere" style="max-width:100%;"></a></p>

And we can notice that the img src is pointing to… GitHub?

I checked in my server logs to be sure. And I found…

140.82.115.251 - - [20/Nov/2019:06:44:54 +0000] "GET /2019/01/01/2535-misere HTTP/1.1" 200 62673 "-" "github-camo (876de43e)"

That will seriously challenge the OKR for this quarter.

Update: 2019-11-21 So I tried to decipher what was really happening. It seems GitHub acts as a proxy using camo, but still has a caching system keeping a real copy of the images, instead of just a proxy. And this can become a problem in the context of webcompat.com.

Early on, we had added s3.amazonaws.com to our connect-src since we had uses that were making requests to https://s3.amazonaws.com/github-cloud. However, this effectively opened up our connect-src to any Amazon S3 bucket. We refactored our URL generation and switched all call sites and our connect-src to use https://github-cloud.s3.amazonaws.com to reference our bucket.

GitHub is hosting the images on Amazon S3.

Otsukare!

Categorieën: Mozilla-nl planet

The Firefox Frontier: Firefox Extension Spotlight: Image Search Options

Mozilla planet - wo, 20/11/2019 - 23:29

Let’s say you stumble upon an interesting image on the web and you want to learn more about it, like… where did it come from? Who are the people in … Read more

The post Firefox Extension Spotlight: Image Search Options appeared first on The Firefox Frontier.

Categorieën: Mozilla-nl planet

The Mozilla Blog: Can Your Holiday Gift Spy on You?

Mozilla planet - wo, 20/11/2019 - 16:57
Mozilla is unveiling its annual holiday ranking of the creepiest and safest connected devices. Our researchers reviewed the security and privacy features and flaws of 76 popular gifts for 2019’s *Privacy Not Included guide

Mozilla today launches the third-annual *Privacy Not Included, a report and shopping guide identifying which connected gadgets and toys are secure and trustworthy — and which aren’t. The goal is two-fold: arm shoppers with the information they need to choose gifts that protect the privacy of their friends and family. And, spur the tech industry to do more to safeguard consumers.

Mozilla researchers reviewed 76 popular connected gifts available for purchase in the United States across six categories: Toys & Games; Smart Home; Entertainment; Wearables; Health & Exercise; and Pets. Researchers combed through privacy policies, sifted through product and app specifications, reached out to companies about their encryption and bug bounty programs, and more. As a result, we can answer questions like: How accessible is the privacy policy, if there is one? Does the product require strong passwords? Does it collect biometric data? And, Are there automatic security updates?

The guide also showcases the Creep-O-Meter, an interactive tool allowing shoppers to rate the creepiness of a product using an emoji sliding scale from “Super Creepy” to “Not Creepy.

Says Ashley Boyd, Mozilla’s Vice President of Advocacy: “This year we found that many of the big tech companies like Apple and Google are doing pretty well at securing their products, and you’ll see that most products in the guide meet our Minimum Security Standards. But don’t let that fool you. Even though devices are secure, we found they are collecting more and more personal information on users, who often don’t have a whole lot of control over that data.”

For the first time ever, this year’s guide is launching alongside new longform research from Mozilla’s Internet Health Report. Two companion articles are debuting alongside the guide and provide additional context and insight into the realm of connected devices: what’s working, what’s not, and how consumers can wrestle back control. The articles include “How Smart Homes Could Be Wiser,” an exploration of why trustworthy connected devices are so scarce, and what consumers can do to remedy this. And “5 key decisions for every smart device,” a look at five key areas manufacturers should address when designing private and secure connected devices.

*Privacy Not Included highlights include:

Top trends identified by Mozilla researchers include:

  • Good on security, questionable on privacy: Many of the big tech companies like Apple and Google are doing pretty well at securing their products. But even when devices are secure, they can still collect a lot of data about users. This year saw an expansion of smart home ecosystems from big tech companies, allowing companies like Amazon to reach deeper into user’s lives. Customer data is also being used in ways users may not have anticipated, even if it’s stated in the privacy policy. For instance, Ring users may not realize their videos are being used in marketing campaigns and that photos of all visitors are stored on servers.
  • Small companies are not doing so well on privacy and security: Smaller companies often do not have the resources to prioritize the privacy and security of their products. Many of the products in the pet category, for example, seem weak on privacy and security. Mozilla could only confirm four of the 13 products meet our Minimum Security Standards. The $500 Litter Robot 3 Connect didn’t even have a privacy policy for the device or the app the device uses. Also, it appears to use the default password “neverscoop” to connect the device to WiFi.
  • Privacy policy readability is improving: Companies are making strides in how they present privacy information, with a lot more privacy pages — like those by Roomba and Apple — being written in simple, accessible language and housed in one central place.
  • Products are becoming more privacy friendly, but sometimes at a cost to consumers: Sonos removed the microphone for the Sonos One SL to make it more privacy-friendly, while Parrot, which made one of the creepiest products in the 2018 guide, launched the Anafi drone, which met the Minimum Security Standards. However, Parrot left the low end consumer market: the Anafi drone costs $700.

 

*Privacy Not Included builds on Mozilla’s work to ensure the internet remains open, safe, and accessible to all people. Mozilla’s initiatives include its annual Internet Health Report; its roster of Fellows who develop research, policies, and products around privacy, security, and other internet health issues; and its advocacy campaigns, such as putting public pressure on apps like Snapchat and Instagram to let users know if they are using facial emotion recognition software.

 

About Mozilla

Mozilla is a nonprofit that believes the internet must always remain a global public resource, open and accessible to all. Its work is guided by the Mozilla Manifesto. The direct work of the Mozilla Foundation focuses on fueling the movement for an open Internet. Mozilla does this by connecting open Internet leaders with each other and by mobilizing grassroots activists around the world. The Foundation is also the sole shareholder in the Mozilla Corporation, the maker of Firefox and other open source tools. Mozilla Corporation functions as a self-sustaining social enterprise — money earned through its products is reinvested into the organization.

The post Can Your Holiday Gift Spy on You? appeared first on The Mozilla Blog.

Categorieën: Mozilla-nl planet

Hacks.Mozilla.Org: Multiple-column Layout and column-span in Firefox 71

Mozilla planet - wo, 20/11/2019 - 16:13

Firefox 71 is an exciting release for anyone who cares about CSS Layout. While I am very excited to have subgrid available in Firefox, there is another property that I’ve been keeping an eye on. Firefox 71 implements column-span from Multiple-column Layout. In this post I’ll explain what it is and a little about the progress of the Multiple-column Layout specification.

Multiple-column Layout, usually referred to as multicol, is a layout method that does something quite different to layout methods such as flexbox and grid. If you have some content marked up and displaying in Normal Flow, and turn that into a multicol container using the column-width or column-count properties, it will display as a set of columns. Unlike Flexbox or Grid however, the content inside the columns flows just as it did in Normal Flow. The difference is that it now flows into a number of anonymous column boxes, much like content in a newspaper.

See the Pen
Columns with multicol
by rachelandrew (@rachelandrew)
on CodePen.

Multicol is described as fragmenting the content when it creates these anonymous column boxes to display content. It does not act on the direct children of the multicol container in a flex or grid-like way. In this way it is most similar to the fragmentation that happens when we print a web document, and the content is split between pages. A column-box is essentially the same thing as a page.

What is column-span?

We can use the column-span property to take an element appearing in a column, and cause it to span across all of the columns. This is a pattern common in print design. In the CodePen below I have two such spanning elements:

  • The h1 is inside the article as the first child element and is spanning all of the columns.
  • The h2 is inside the second section, and also spans all of the columns.

See the Pen
Columns with multicol and column-span
by rachelandrew (@rachelandrew)
on CodePen.

This example highlights a few things about column-span. Firstly, it is only possible to span all of the columns, or no columns. The allowable values for column-span are all, or none.

Secondly, when a span interrupts the column boxes, we end up with two lines of columns. The columns are created in the inline direction above the spanning element, then they restart below. Content in the columns does not “jump over” the spanning element and continue.

In addition, the h1 is a direct child of the multicol container, however the h2 is not. The h2 is nested inside a section. This demonstrates the fact that items do not need to be a direct child to have column-span applied to them.

Firefox has now joined other browsers in implementing the column-span property. This means that we have good support for the property across all major browsers, as the Compat data for column-span shows.

The compat data for column-span on MDN

The multicol specification

My interest in the implementation of column-span is partly because I am one of the editors of the multicol specification. I volunteered to edit the multicol specification as it had been stalled for some time, with past resolutions by the WG not having been edited into the spec. There were also a number of unresolved issues, many of which were to do with the column-span feature. I started work by digging through the mailing list archives to find these issues and resolutions where we had them. I then began working through them and editing them into the spec.

At the time I started working on the specification it was at Candidate Recommendation (CR) status, which infers that the specification is deemed to be fairly complete. Given the number of issues, the WG decided to return it to Working Draft (WD) status while these issues were resolved.

CSS development needs teamwork between browsers and spec editors

As a spec editor, it’s exciting when features are being implemented, as it helps to progress the spec. CSS is created via an iterative and collaborative process; the CSS WG do not create a complete specification and fling it over the wall at browser engineers. The process involves working on a feature in the WG, which browser engineers try to implement. Questions and problems discovered during that implementation phase are brought back to the working group. The WG then have to decide what to do about such issues, and the spec editor then gets the job of clarifying the spec based on the resolution. The process repeats — each time we tease out issues. Any lack of clarity could cause an interoperability issue if two browsers interpreted the description of the feature in a different way.

Based on the work that Mozilla have been doing to implement column-span, several issues were brought to the CSS WG and discussed in our calls and face-to-face meetings. We’ve been able to make the specification much clearer on a number of issues with column-span and related issues. Therefore, I’m very happy to have a new property implemented across browsers, and also happy to have a more resilient spec! We recently published an updated WD of multicol, which includes many changes made during the time Mozilla were implementing multicol in Firefox.

Other multicol related issues

With the implementation of column-span, multicol will work in much the same way across browsers. We do have an outstanding issue with regards to the column-fill property, which controls how the columns are filled. The default way that multicol fills columns is to try to balance the content, so equal amounts of content end up in each column.

By using the column-fill property, you can change this behavior to fill columns sequentially. This would mean that a multicol container with a height could fill columns to the specified height, potentially leaving empty columns if there was not enough content.

See the Pen
Columns with multicol and column-fill
by rachelandrew (@rachelandrew)
on CodePen.

Due to specification ambiguity, Firefox and Chrome do different things if the multicol container does not have a height. Chrome ignores the column-fill property and balances, whereas Firefox fills the first column with all of the content. This is the kind of issue that arises when we have a vague or unclear spec. It’s not a case of a browser “getting things wrong”, or trying to make the lives of web developers hard. It’s what happens when specifications aren’t crystal clear! For anyone interested, the somewhat lengthy issue trying to resolve this is here. Most developers won’t come across this issue in practice. However, if you are seeing differences when using column-fill, it is worth knowing about.

The implementation of column-span is a step towards making multicol robust and useful on the web. To read more about multicol and possible use cases see the Guides to Multicol on MDN, and my article When And How To Use Multiple-column Layout.

The post Multiple-column Layout and column-span in Firefox 71 appeared first on Mozilla Hacks - the Web developer blog.

Categorieën: Mozilla-nl planet

Mozilla Security Blog: Updates to the Mozilla Web Security Bounty Program

Mozilla planet - di, 19/11/2019 - 16:10

Mozilla was one of the first companies to establish a bug bounty program and we continually adjust it so that it stays as relevant now as it always has been. To celebrate the 15 years of the 1.0 release of Firefox, we are making significant enhancements to the web bug bounty program.

Increasing Bounty Payouts

We are doubling all web payouts for critical, core and other Mozilla sites as per the Web and Services Bug Bounty Program page. In addition we are tripling payouts to $15,000 for Remote Code Execution payouts on critical sites!

Adding New Critical Sites to the Program

As we are constantly improving the services behind Firefox, we also need to ensure that sites we consider critical to our mission get the appropriate attention from the security community. Hence we have extended our web bug bounty program by the following sites in the last 6 months:

  • Autograph – a cryptographic signature service that signs Mozilla products.
  • Lando – Mozilla’s new automatic code-landing service which allows us to easily commit Phabricator revisions to their destination repository.
  • Phabricator – a code management tool used for reviewing Firefox code changes.
  • Taskcluster  the task execution framework that supports Mozilla’s continuous integration and release processes (promoted from core to critical).
Adding New Core Sites to the Program

The sites we consider core to our mission have also been extended to include:

  • Firefox Monitor – a site where you can register your email address so that you can be informed if your account details are part of a data breach.
  • Localization – a service contributors can use to help localize Mozilla products.
  • Payment Subscription – a service that is used as the interface in front of the payment provide (Stripe).
  • Firefox Private Network – a site from which you can download a desktop extension that helps secure and protect your connection everywhere you use Firefox.
  • Ship It – a system that accepts requests for releases from humans and translates them into information and requests that our Buildbot-based release automation can process.
  • Speak To Me – Mozilla’s Speech Recognition API.

The new payouts have already been applied to the most recently reported web bugs.

We hope the new sites and increased payments will encourage you to have another look at our sites and help us keep them safe for everyone who uses the web.

Happy Birthday, Firefox. And happy bug hunting to you all!

The post Updates to the Mozilla Web Security Bounty Program appeared first on Mozilla Security Blog.

Categorieën: Mozilla-nl planet

Hacks.Mozilla.Org: Creating UI Extensions for WebThings Gateway

Mozilla planet - di, 19/11/2019 - 16:00

Version 0.10 of Mozilla’s WebThings Gateway brings support for extension-type add-ons. Released last week, this powerful new capability lets developers modify the user interface (UI) to their liking with JavaScript and CSS.

Although the initial set of extension APIs is fairly minimal, we believe that they will already enable a large amount of functionality. To go along with the UI extensions, developers can also extend the gateway’s REST API with their own handlers, allowing for back-end analytics, for example.

In this post, we’ll walk through a simple example to get you started with building your own extension.

The Basics

If you’re completely new to building add-ons for the WebThings Gateway, there are a couple things you should know.

An add-on is a set of code that runs alongside the gateway. In the case of extensions, the code runs as part of the UI in the browser. Add-ons can provide all sorts of functionality, including support for new devices, the ability to notify users via some outlet, and now, extending the user interface.

Add-ons are packaged up in a specific way and can then be published to the add-on list, so that they can be installed by other users. For best results, developers should abide by these basic guidelines.

Furthermore, add-ons can theoretically be written in any language, as long as they know how to speak to the gateway via IPC (interprocess communication). We provide libraries for Node.js and Python.

The New APIs

There are two new groups of APIs you should know about.

First, the front end APIs. Your extension should extend the Extension class, which is global to the browser window. This gives you access to all of the new APIs. In this 0.10 release, extensions can add new entries to the top-level menu and show and hide top-level buttons. Each extension gets an empty block element that they can draw to as they please, which can be accessed via the menu entry or some other means.

Second, the back end APIs. An add-on can register a new APIHandler. When an authenticated request is made to /extensions/<extension-id>/api/*, your API handler will be invoked with request information. It should send back the appropriate response.

Basic Example

Now that we’ve covered the basics, let’s walk through a simple example. You can find the code for this example on GitHub. Want to see the example in Python, instead of JavaScript? It’s available here.

This next example is really basic: create a form, submit the form, and echo the result back as JSON.

Let’s go ahead and create our API handler. For this example, we’ll just echo back what we received.

const {APIHandler, APIResponse} = require('gateway-addon'); const manifest = require('./manifest.json'); /** * Example API handler. */ class ExampleAPIHandler extends APIHandler { constructor(addonManager) { super(addonManager, manifest.id); addonManager.addAPIHandler(this); } async handleRequest(request) { if (request.method !== 'POST' || request.path !== '/example-api') { return new APIResponse({status: 404}); } // echo back the body return new APIResponse({ status: 200, contentType: 'application/json', content: JSON.stringify(request.body), }); } } module.exports = ExampleAPIHandler;

The gateway-addon library provides nice wrappers for the API requests and responses. You fill in the basics: status code, content type, and content. If there is no content, you can omit those fields.

Now, let’s create a UI that can actually use the new API we’ve just made.

(function() { class ExampleExtension extends window.Extension { constructor() { super('example-extension'); this.addMenuEntry('Example Extension'); this.content = ''; fetch(`/extensions/${this.id}/views/content.html`) .then((res) => res.text()) .then((text) => { this.content = text; }) .catch((e) => console.error('Failed to fetch content:', e)); } show() { this.view.innerHTML = this.content; const key = document.getElementById('extension-example-extension-form-key'); const value = document.getElementById('extension-example-extension-form-value'); const submit = document.getElementById('extension-example-extension-form-submit'); const pre = document.getElementById('extension-example-extension-response-data'); submit.addEventListener('click', () => { window.API.postJson( `/extensions/${this.id}/api/example-api`, {[key.value]: value.value} ).then((body) => { pre.innerText = JSON.stringify(body, null, 2); }).catch((e) => { pre.innerText = e.toString(); }); }); } } new ExampleExtension(); })();

The above code does the following things:

  1. Adds a top-level menu entry for our extension.
  2. Loads some HTML asynchronously from the server.
  3. Sets up an event listener for the form to submit it and display the results.

The HTML loaded from the server is not a full document, but rather a snippet, since we’re using it to fill in a <section> tag. You could do all this synchronously within the JavaScript, but it can be nice to keep the view content separate. The manifest for this add-on instructs the gateway which resources to load, and which are allowed to be accessed via the web:

{ "author": "Mozilla IoT", "content_scripts": [ { "css": [ "css/extension.css" ], "js": [ "js/extension.js" ] } ], "description": "Example extension add-on for Mozilla WebThings Gateway", "gateway_specific_settings": { "webthings": { "exec": "{nodeLoader} {path}", "primary_type": "extension", "strict_max_version": "*", "strict_min_version": "0.10.0" } }, "homepage_url": "https://github.com/mozilla-iot/example-extension", "id": "example-extension", "license": "MPL-2.0", "manifest_version": 1, "name": "Example Extension", "short_name": "Example", "version": "0.0.3", "web_accessible_resources": [ "css/*.css", "images/*.svg", "js/*.js", "views/*.html" ] }

The content_scripts property of the manifest tells the gateway which CSS and JavaScript files to load into the UI. Meanwhile, the web_accessible_resources tells it which files can be accessed by the extension over HTTP. This format is based on the WebExtension manifest.json format, so if you’ve ever built a browser extension, it may look familiar to you.

As a quick note to developers, this new manifest.json format is required for all add-ons now, as it replaces the old package.json format.

Testing the Add-on

To test, you can do the following on your Raspberry Pi or development machine.

  1. Clone the repository: cd ~/.mozilla-iot/addons git clone https://github.com/mozilla-iot/example-extension
  2. Restart the gateway: sudo systemctl restart mozilla-iot-gateway
  3. Enable the add-on by navigating to Settings -> Add-ons in the UI. Click the Enable button for “Example Extension”. You then need to refresh the page for your extension to show up in the UI, as extensions are loaded when the page first loads.
Wrapping Up

Hopefully this has been helpful. The example itself is not very useful, but it should give you a nice skeleton to start from.

Another possible use case we’ve identified is creating a custom UI for complex devices, where the auto-generated UI is less than ideal. For instance, an adapter add-on could add an alternate UI link which just links to the extension, e.g. /extensions/<extension-id>. When accessed, the UI will bring up the extension’s interface.

If you have more questions, you can always reach out on Discourse, GitHub, or IRC (#iot). We can’t wait to see what you build!

The post Creating UI Extensions for WebThings Gateway appeared first on Mozilla Hacks - the Web developer blog.

Categorieën: Mozilla-nl planet

Alessio Placitelli: GeckoView + Glean = Fenix performance metrics

Mozilla planet - di, 19/11/2019 - 14:48
(“This Week in Glean” is a series of blog posts that the Glean Team at Mozilla is using to try to communicate better about our work. They could be release notes, documentation, hopes, dreams, or whatever: so long as it is inspired by Glean. The previous post of the series lives here.) This week in … →
Categorieën: Mozilla-nl planet

Pagina's