QtScript in 4.6

As previously described (1, 2), Qt 4.6's QtScript implementation is based on WebKit's JavaScript engine, JavaScriptCore (you might've also heard it being referred to as "SquirrelFish" or "SquirrelFish Extreme"). This blog is an attempt to highlight the major implications of this "under-the-hood" change.

Looking for bars in all the right places

So, is QtScript any faster in 4.6 than in 4.5? As an indicator, I ran the SunSpider benchmark with both versions. Here are the results obtained on my Linux box (longer bars are better; they show speedup over Qt 4.5, so Qt 4.5 results are all 1): Part 1:

Running SunSpider on QtScript with Qt 4.5 vs 4.6

Part 2:

Running SunSpider on QtScript with Qt 4.5 vs 4.6, part 2

Although these results shouldn't really be that surprising (boosting performance was one of the key reasons for switching to JavaScriptCore, after all), I can think of two principal ways of interpreting them. One is to say that pre-4.6 QtScript is dog slow, whereas in 4.6 it has good performance (AKA "It's cat fast"). The other interpretation (my personal favorite) is that pre-4.6, QtScript is sufficient for "scripting in the small/medium", but with 4.6 it gains the ability to better tackle "scripting in the large". It's possible to do more heavy processing on the script side, which effectively means that more use cases for application scripting can be supported.

It's not always going to be faster.

While 4.6 is practically guaranteed to perform better than previous Qt releases for long-running scripts, that's not necessarily the case for small, short-running scripts, however. JavaScriptCore's virtual machine is more complex than the old QtScript VM (it's register-based rather than stack-based, for example) and currently there's no hotspotting, i.e. scripts are always JIT-compiled (on the platforms where JIT is supported & enabled). This means that for small scripts, it can take more time to compile the script than to actually execute the compiled form, and the old and relatively simplistic QtScript VM could do it faster. For "1 + 2", the old VM wins.

In order to mitigate this potential issue in the case where you have a small script that you want to run several times, Qt 4.6 comes with a new class called QScriptProgram. QScriptProgram automatically caches the compiled form of your script. This class was added rather late in the 4.6 development and is marked as internal in the 4.6.0 release, so it won't show up in the documentation, but it's there and we think it's safe to start using it... Here's how:

QScriptEngine engine;
QScriptProgram program("1 + 2");
qDebug() << engine.evaluate(program).toNumber(); // QtScript lazily compiles and executes the program

...

qDebug() << engine.evaluate(program).toNumber(); // QtScript directly executes the compiled program

We are of course interested in hearing what kind of performance experiences you have with QtScript in 4.6, good or bad.

QtScript, JavaScript... What language is it anyway?

The QtScript language is based on the ECMA-262 standard, which is essentially a subset of JavaScript that was standardized after JavaScript was designed. Prior to Qt 4.6, there were two major issues related to QtScript and ECMA-262 compabilitity. First, QtScript wasn't 100% compliant (yes, that's the nuance between "based on" and "strictly adheres to" kicking in), so you as a QtScript script author had to learn and keep in mind where it deviated from the standard.

Second, being 100% compliant to the ECMA-262 standard is not really something to strive for anyway, since it's not the language people use; JavaScript is the "de-facto" ECMAScript variant that's actually in use out there. Ideally, then, the QtScript language should be JavaScript. It certainly shouldn't be something that isn't quite standards-compliant yet doesn't quite support real-world JavaScript either, because that severely limits its scope and ease of use.

In addition to the "QtScript is JavaScript, so I only need to learn JavaScript"-argument, turning the QtScript language into "proper" JavaScript has two major benefits. First, there's a lot of existing and yet-to-be-written JavaScript code that doesn't strictly require a browser to be useful (libraries for doing "class-based" programming, for example). It would be nice if you could just evaluate those scripts with QtScript and be reasonably confident that they won't blow up. In 4.6, you can. Second, Qt has this other component called QtWebKit that also does JavaScript. It would be nice if QtScript spoke the exact same language. In 4.6, it does. It's a good start for a tighter integration between those two components. (Unfortunately, in 4.6 that integration is still not present in terms of actually mixing QtWebKit and QtScript C++ APIs.)

"I used to have behavioral issues, now I'm feeling better"

Prior to 4.6, perhaps the place where QtScript did worst in regard to compliance was how it dealt with Date and RegExp objects. Instead of implementing the semantics defined in ECMA-262, Date and RegExp were essentially wrappers around QDateTime and QRegExp. While this was convenient for us to implement, it meant that you could get some "interesting" behavior compared to that of a more compliant engine. Imagine loading an existing JavaScript library, hundreds or maybe thousands of lines in size, where one of the functions defines this finely tuned regular expression that doesn't quite do what it should in QtScript because QRegExp semantics are not quite the same as those of JavaScript regular expressions... Fun. Actually, that's a story from real life. Not so fun.

With 4.6 we get well-behaved Date and RegExp objects "for free" from JavaScriptCore. There are lots of other compliance issues and bugs that are gone too.

Of course, it can't be all roses and peaches. For example, if you've been relying on evaluating nameless function expressions as statements, you should be aware of this quirk that will be present in 4.6.0.

License change

As of Qt 4.6, due to the dependency on JavaScriptCore, the QtScript module is only available under the LGPL or a compatible license. If you want to use QtScript under the commercial license, see one more section down.

Changes in platform support

Platform-wise, JavaScriptCore is a very interesting beast compared to the old "bread-and-butter" QtScript implementation. As you may know, QtWebKit is disabled on some platforms because it plain doesn't build, or it's not tested in WebKit upstream, so it could break at any time. Since QtScript depends on JavaScriptCore in 4.6, a subset of WebKit needs to be compiled in order to build QtScript. Unfortunately, that subset is quite needy and picky with regard to the tool chain. Consequently, in 4.6 we don't guarantee that QtScript-with-JavaScriptCore works on Tier 2 platforms where QtScript of previous Qt releases did. Yeah, it sucks, but we don't have the resources currently to maintain and test all those platforms and configurations. There haven't been any reports on this matter for the beta and Release Candidate, but in any case there's a backup solution:

Introducing QtScript Classic

Can't live with QtScript gone LGPL? QtScript doesn't build on your platform? Found an (intentional or unintentional) change in QtScript behavior that affects your application when running against Qt 4.6.0? First of all, if your answer is "Yes" to either of the last two questions, we would greatly appreciate it if you report the problem. Second, we are providing the old QtScript back-end as a separate Qt Solution, called QtScript Classic (follow the link for more information and downloads). QtScript Classic can effectively be used to replace the QtScript from 4.6 with the latest from the 4.5 line. Note that Qt 4.6 can be configured with -no-script to avoid building the standard QtScript module. Again, for Tier 2 platforms, if you experience issues with the 4.6.0 release consider trying QtScript Classic.

Conclusion

In Qt 4.6, QtScript should be faster for computation-heavy scripting. It should be more standards-compliant. The C++ API should still behave the same, unless documented otherwise. In short, existing code should mostly continue to work, only faster than before. Please let us know if that's not the case. Reported issues will appear on the QtScript component page in the bug tracker.


Blog Topics:

Comments