Replay v0.5: JavaScriptCore is really slow

Before v0.5 of the Replay game engine released last week, Replay was using JavaScriptCore to render a game on iOS.

When you write your Replay game in JavaScript, the Replay Swift package will load it into its own context using JavaScriptCore. From there it calls your loop and render methods and gets all the textures it needs to render as a big dictionary (converted from a JavaScript object).

This provided a lot of flexibility since all of the platform features (like rendering, audio and storage) could be done natively.

However recent tests with a large number of Sprites has shown terrible lag on iOS. The strange thing was, if I played the same game through Safari on the same device, the performance was much better. CPU usage went from 100% down to 10%!

After doing some more research, including finding a great article on why this team migrated to WKWebView, I realised that using an embedded web view would be the only way to achieve great JavaScript performance on iOS. I really feel that all JavaScriptCore tutorials need a big red banner at the top of them warning "JavaScriptCore can be really slow!".

So why is JavaScriptCore so slow? Well, when it uses its JIT (Just-In-Time) compiler it's actually really fast. The JIT compiler can greatly speed up code which is executed multiple times (which certainly happens a lot in a game loop) - you can read more on that here.

But as mentioned in the previous articles, for various security reasons Apple doesn't enable the JIT compiler on iOS except on its own apps like Safari or embedded web views.

So Replay v0.5 has completely refactored the Replay Swift package to just use a WKWebView. There is a way to execute JavaScript code on its own using a WKWebView, however its asynchronous nature made it impossible to interact with the core Replay API as it's designed now.

Instead, it imports the @replay/web package and is essentially running your game as a webpage in Safari. Playing the same game that had 100% CPU usage in v0.4, v0.5 reduced it down to just 4% CPU usage.

It's a shame JavaScriptCore has this limit on performance, but from the iOS player's point of view, the game plays the same and runs really fast!