Hacker News new | past | comments | ask | show | jobs | submit login
Hermes, a JavaScript engine optimized for React Native (hermesengine.dev)
194 points by dgellow on March 24, 2021 | hide | past | favorite | 73 comments



This site doesn't seem to describe much about the history or internals. This FB blog post seems to have more details on how and why:

https://engineering.fb.com/2019/07/12/android/hermes/


From the docs: "Hermes is an open-source JavaScript engine optimized for running React Native apps on Android."

Looks like it's available for iOS now too :)

Announcing React Native 0.64 with Hermes on iOS https://reactnative.dev/blog/2021/03/12/version-0.64


Interesting - I would have thought custom JS engines/runtimes would be a no go for both iOS and the iOS App Store.


Beyond any TOS issues there has always been a technical issue where an app store app cannot write to memory that is marked executable for security purposes.

This prevents JIT's but does not prevent an interpreter from functioning since an interpreter does not directly generate machine code and execute it, it simply reads the code to interpret as data and executes through its own engine.

Most modern JS engines JIT which is why you don't see say electron / node / chromium based stuff on iOS, a lot of it has to do with V8 requiring the ability to JIT.

Hermes does not JIT so it sidesteps the technical limitations on iOS then its just a matter of passing review.

There where some ways around this that have been patched and Apple has recent introduced an official entitlement but does not allow it in the app store yet:

https://saagarjha.com/blog/2020/02/23/jailed-just-in-time-co...

https://9to5mac.com/2020/11/06/ios-14-2-brings-jit-compilati...


Sadly, Apple removed the JIT support in 14.4, so not even sideloaded apps can use it any more.

https://twitter.com/altstoreio/status/1354096048650809349


Unfortunate but I was surprised Apple looked like they where changing it at all since it would lessen security allowing some common attack vectors.

I haven't followed it for some time however, it does look like V8 supports a JITless mode now which allows it to possibly be used on iOS and other platforms with NX set, albeit with significant performance loss:

https://v8.dev/blog/jitless

Looks like JavaScriptCore still disables JIT when run in a non entitled app. Always thought they might figure out a way to at least let their own JS engine JIT since its trusted in Safari on the open web, but I believe its an all or nothing thing for the process/app and not per module thing.


JavaScriptCore could use a daemon process with elevated privileges that does the JIT-ting and then shares back the executable memory pages with the sandboxed process. It's simply a matter of Apple wanting to curb React Native because it threatens their control over app development.


Out of process mean a loss in performance itself due to marshaling cross process calls and data. When your dealing with UI orchestration its probably better / faster to run an interpreter with no cross process overhead than a JIT with the overhead. Think Web Workers which have similar issues, you have to keep your communication with worker chunky for good performance.


You're misunderstanding what I've described. Only the JITting would occur in a separate process. The sandboxed app would give the JS code to the JITter daemon, then the JITted code would be mapped to the address space of the sandboxed app, where it would run just as if it was part of the native app binary. There's no marshalling other than sending JS code to the JIT daemon.


Yes I did misunderstand and that may work to get around the NX restriction being per process it would probably be a significant change to the JIT architecture in order for it to work out of process. This also would probably have security implications since it looks like old MS Edge did this for mitigation and Google found possible exploits: https://googleprojectzero.blogspot.com/2018/05/bypassing-mit...


You can run JavaScript out of process with the JIT through WKWebView.


Yep, that's pretty much what I've described, and it is the reason why I'm certain that there's no technical limitation at play here. Apple just chose to not allow this for political/strategic reasons.


Which is fine if you're doing an HTML UI (PhoneGap) since the DOM and JS engine share the same process. If you're doing a native UI with JS then it must marshal cross process to affect the UI then you have to decide which is worse, no JIT or cross process overhead.


Definitely fine for Android (there's plenty of them), but I would've thought the same for iOS.

Now that I think of it though, I think the Apple ToS that prohibit browsers are about function (app used to browse the web) rather than internals (language support in the engine).


I think the issue is if you interpret dynamically fetched code. So you couldn't use this for out-of-band updates to internals (unless you're important enough).


I'm not sure that's true. When you use react native you can update your javascript bundle and push it to an application already deployed to the App Store and that doesn't seem to be an issue. The application can check at startup if a new bundle is available, otherwise defaults to the local bundle.

See the expo documentation for details: https://docs.expo.io/bare/updating-your-app/.


Apparently Apple is ok with out-of-band updates as long as they don't add or change features. If it's used to fix a bug then it's ok (at least they haven't cracked down on React-native apps using codepush/expo's auto update feature, yet.). There have been reports of Apple's reviewers asking for clarification on why apps have the ability to update, and as long as the answer is "bug fixes" then they approve the app.


Apple's ToS prevent any kind of interpreted language in iOS apps.

> 2.5.2 Apps should be self-contained in their bundles, and may not read or write data outside the designated container area, nor may they download, install, or execute code which introduces or changes features or functionality of the app, including other apps. Educational apps designed to teach, develop, or allow students to test executable code may, in limited circumstances, download code provided that such code is not used for other purposes. Such apps must make the source code provided by the Application completely viewable and editable by the user.

Basically embedding any interpreted language inside the app is frowned upon by apple. But historically they have allowed JavaScript and Lua scripts to be embedded in apps.


"Such apps must make the source code provided by the Application completely viewable and editable by the user."

arguably the ability to view source was what created the possibilities of the Web, and as such I don't read this term to be restrictive but instead merely trying to get the best outcome for everyone.

disclaimer being that I have spent a large part of the past year evaluating a ios app for commercial release that both relies on decades of proprietary design and which probably doesn't have a significant future unless it is opened extensively or completely.


That does not ban the interpreters. It prevents interpretation of downloaded code. But as long the sources to be interpreted are bundled with app, it is OK at least from that section.


I mean, it depends on what they mean by "execute", right? As far as iOS knows your app is just looping through some binary data.


They used to be. I can't remember the exact part now but the TOS used to ban anything that wasn't iOS's own JavaScriptCore runtime. They changed it a few years ago.


I don’t think interpreters were ever banned, if you weren’t executing code downloaded from the internet: at least, there’s always been a variety of lisp/Python/Ruby environments available to play with.


And with "React Native for Windows" and "React Native for macOS" (both are still experimental): https://microsoft.github.io/react-native-windows/docs/hermes


Microsoft just gain a ton of respect by putting it out, upfront description etc, I’m impressed by collaboration and plain statements.


Yeah. Never thought I'd read how to use a facebook javascript engine for macOS on a microsoft site.


Why not?

Microsoft and Facebook have been lovers since the beginning.. Even in terms of UI design of the earliest of facebook.


Also, Microsoft has a long history of being one of the largest software developers for macOS. Even when deep in the worst Windows versus Mac OS competitive years, Microsoft still shipped a lot of software to Mac OS. (Most of it Office products.)


And on Windows it uses WinUI/UWP actually.

The recent XBox dashboard has been remade with it.


On Windows native components can be in C++/WinRT or C#, which is quite nice. Typescript for the glue, managed C++ for the heavy lifting. That's a great compromise IMHO, at least in theory. I'm still a bit skeptical because I haven't seen yet WinUI or UWP applications with a passable user experience.


Agreed, you can see how I have been an heavy advocate of it, and see it not only as a much better COM, but also what .NET v1.0 should have been (it was the original idea anyway, Ext-VOS).

However nowadays I have become quite sceptical on what it will ever be, and looking forward to what news BUILD 2021 might bring.

C++/WinRT tooling still doesn't match C++/CX, doing UI in .NET or ReactNative (QML style) seems to be the workaround for it, endless list of Github issues on WinUI, Reunion and all WinRT bindings, community talks with lots of previews, and state of current tooling.

Then the various UI teams seem to be competing to which of them will get more developer mindshare.

So it is a mess, that I hope BUILD will get a more clear picture.


totally understand that kind of pain : actively thinking about writing driver primitives to shim into the ui library layers to get the eventual sensibility we need.

I've spent a inordinate amount of time on figuring out how to hire a truly dedicated windows native interface team and the only solid conclusion that I've come to is it's necessary to also recruit to write tooling for the designers to work with. we have a application that happily doesn't need a gui but to be used widely needs a excellent gui. it looks like we'll need at least as many people on interface as for our core application. the tooling, oh the tooling..


Woz dug the windows phone in the earlier lumia stages prior to the wp8 NT kernel with everything else gutting.

this is the one book I most want for Christmas - the true account of what happened to the windows phone interface. I was constantly in awe to behold the developments as they happened ; literally "too good to be true" electrocuted me in my chair every time I read the latest.


All of these JavaScript frameworks are recreating native runtimes on top of “standard” JavaScript engines. It seems wrong to me to tailor a JavaScript engine to a particular framework. Ideally the goal would be to move native framework-less JavaScript forward so that we don’t need all these over-complex competing frameworks.


The primary React Native performance issue on iOS is that Apple disables the JIT when using JavaScriptCore. If you run some JS in a WKWebView you should see it speed up by 5 to 10x. (WKWebView runs in a different process, so they allow the JIT)


Arguably the primary React Native performance issue is that JS is single-threaded. Does React Native provide any useful tools for that?


That's not the primary issue. The main issue that there isn't (or wasn't until recently) a fast, low overhead way to communicate between JavaScript and native code. That's changing with JSI, and I think we might find React Native gets a lot faster in practice if they ever complete the work.


You can run things in workers:

https://github.com/devfd/react-native-workers


To be anal, the root cause of that is using javascript instead of building a native app.

I get that Facebook has the biggest apps on any platform and they run into platform limitations (like number of classes on Android) and build cycles so for them it makes sense to make a dynamic partial-hot-reloading-in-place app development framework, but they're still beholden to the runtime that Apple offers them.

(In theory they could compile JS to a compiled binary that Apple's reviewers are okay with, but I don't know enough about any of that)


The security implications of running JS in an interpreter and running native bytecode are very different, though. Native apps also routinely request much more permissions and gather extra user data such as contacts, just because it is possible to do so.


Shouldn’t this be a hidden layer under React native? The thing you suggest is impossible without having Google or Apple take up the initiative.

All JS improvements for the last 10 years required a lot of bypassing of browser and device maker’s implementation.


That’s what programmers tend to do. Inception :-). Abstraction over virtualization over abstraction over virtualization etc.

And still there are root exploits that are about to go all the way back up

I like react-native, as in the architecture (nativescript has a better bridge). Unfortunately it’s JavaScript. I guess we’ll have to deal with it another 40 years min.


I'm not an expert on JS engine internals, but every time I used Hermes on a reasonably large React Native app, on Android performance absolutely tanked. It's been like that for over a year, and I just ended up disabling it, or enabling the debugger so the engine turns to Chrome's. There's always been some activity around it on the issue tracker[0] but not many solutions.

[0] https://github.com/facebook/react-native/issues/25986 and related issues


Is there any performance comparison with the "default" js engine of react native?


Yes, here: https://engineering.fb.com/2019/07/12/android/hermes/

Scroll down to: How Hermes improves React Native performance


I find this interesting:

> Hermes today has no JIT compiler. This means that Hermes underperforms some benchmarks, especially those that depend on CPU performance. This was an intentional choice: These benchmarks are generally not representative of mobile application workloads.

What workloads are different from mobile application workloads, other than server-side code?


If you continue, just after the bloc you quoted:

> Because JITs must warm up when an application starts, they have trouble improving TTI and may even hurt TTI. Also, a JIT adds to native code size and memory consumption, which negatively affects our primary metrics. A JIT is likely to hurt the metrics we care about most, so we chose not to implement a JIT.

So it seems to be specific to their TTI (Time To Interact) metric. A server application generally has the time to warm-up to reach best-performances (pretty common in the java world for example) while a mobile application has to react to user inputs as soon as possible.


Does this mean that V8 (which uses a JIT compiler) is a bad fit for web browsers?

I think they exaggerate:

> A JIT is likely to hurt the metrics we care about most

And they ruled out the possibility of having both a JIT and ahead of time compilation.


Probably to limit scope / complexity. Remember that the JS engine here (in React Native) is basically pulling strings to orchestrate a bunch of native modules, not doing any of the heavy lifting. It’s quite different from the current web environment.


V8 has an interpreter (Ignition) and a JIT (TurboFan) [1] but can be used without the JIT: https://v8.dev/blog/jitless


If JS code is few event listeners to verify/massage the data to submit to the server, then the answer is yes. But for more complex web pages the answer is now. For example, React on web and similar framework may not be feasible without JIT.


V8 also has an interpreter which runs first while code is being compiled or has yet to be identified as a JIT candidate.


Hermes does have a tier 1 JIT, though it is not a primary focus yet.


Do you have more information on this? I remember looking into it a couple months ago, and being told the jit wasn’t going to be developed further. Thanks!


Benchmarks that are designed to measure absolute performance often don't test the factors that make real world software feel fast or slow. They're designed to output a number that allows you to compare the performance of the VMs in certain scenarios.

The speed of a JS vm factoring primes doesn't indicate how laggy it'll feel scrolling through a list because it's garbage collecting every few hundred millis.


Non-mobile web application workloads?


I'm looking forward to using Hermes in our RN project when it's fully featured. For us, it's sadly still missing Intl.Collator, which we need to correctly sort international characters, although it's in the works!


Unlike support for something like Proxies (which was recently added), isn't Intl.Collator fairly easily polyfilled?


How does it compare to QuickJS?


According to this benchmark much larger binary size, but similar performance: https://bellard.org/quickjs/bench.html

that was a while ago though.


Also, standard support is abysmal in Hermes, whereas full ES6 support is already there for QuickJS.


Hermes is ES6 compliant to my knowledge.


Not exactly by the looks of things. Kangax says 71% compliant. We tried Hermes at work and had to turn it off again because our app was crashing. That was before they implemented Proxy support, but I'm a little loathe to try it again.

https://kangax.github.io/compat-table/es6/#hermes0_7_0


My mistake, looks like some of the ES6 work is yet to be finished.


Formatting C++

code with

80 column hard

limit

looks bad.


Does Hermes use a custom bytecode or is it using wasm?


Custom bytecode from what I get from their documentation (https://hermesengine.dev/docs/design#hermes-bytecode-generat...). You can check the playground to see it in action: https://hermesengine.dev/playground/.


Don't use FB made tools, please. The company is cancer.


What’s the reasoning here? Facebook will change the way they operate when people boycott paying the $0 to use their open source projects?


But my small company isn't. And using ReactNative gets us there easier/faster/cheaper than we ever could without it.


Agreed. With a two person team and we can do things we couldn't otherwise. Having one shared code base for web, android, and iOS is better for two people IMO.


Using tools made by FB doesn't imply support for the company. Ultimately having FB open source React/RN has been great for open source - by the time it hits public release it's already been battle tested internally.


You can have negative views of FB, but this comment doesn't belong on HN.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: