12

Newer versions of Android ( > 2.2) include the v8 javascript engine, while older versions only had JSC. However, according to http://blogs.nitobi.com/joe/2011/01/14/android-your-js-engine-is-not-always-v8/, which javascript engine is used at runtime seems to depend on an environment variable present at build-time (JS_ENGINE), as well as the hardware specs of the device:

# The default / alternative engine depends on the device class.
# On devices with a lot of memory (e.g. Passion/Sholes), the
# default is V8. On everything else, the only choice is JSC.

My question is this: is there any way that I can determine which javascript engine is in use from within a webpage, an embedded WebView, or an application?

If the answer is no, does anybody know which JS engine is used by the Android emulator?


The reason I'm asking this is because of this issue: http://code.google.com/p/android/issues/detail?id=12987

Basically, it may be that the javascript-to-java bridge in JSC is broken on Android 2.3.X, and this impacts the application I'm trying to write. I'm seeing a segfault from somewhere deep in the JNI on my emulator, but not on the handful of physical devices I've tested. I'm trying to determine if this is an emulator-only thing, a JSC-only thing, or something different altogether.

digitalbath
  • 7,008
  • 2
  • 17
  • 15

3 Answers3

19

I think the better question is: Why do you care? You're basically falling into the "browser detection" trap that a lot of people fell into in the late 90's / early 00's. Since then, though, we've learned that it's feature detection that's the more useful approach, not least because the features supported in a given browser were (mostly) a moving target. There's code now, running on IE9 with its dramatically-improved DOM and JavaScript support, that's not using those features because it's doing browser detection and falling back on IE6 techniques.

So rather than worrying about V8 vs. JSC, just worry about the features you want. I don't know anything about JSC, but for instance let's assume it doesn't have the forEach method on arrays that V8 has (part of the ECMAScript 5th edition standard). Rather than throwing a big "V8 vs. JSC" lever, you'd do:

if (typeof Array.prototype.forEach === "function") {
    // Code that expects `forEach`
} else {
    // Code that falls back
}

(Your "code that falls back" might add forEach to the prototype, or maybe this test is in your own iterator function and you want to know whether to defer to a native implementation or supply your own.)

And similarly for other features you want to use that may or may not be present.


But if you really need to detect V8 vs. JSC (and from your comment it seems you may), this page seems to demonstrate a means of doing so, though it seems awfully fragile. Here's my slightly-edited version (not least to replace window.devicePixelRatio with the test for WebkitAppearance — the former gives false positives on at least some other browsers [Firefox, for instance, which uses Gecko, not WebKit]):

var v8string = "function%20javaEnabled%28%29%20%7B%20%5Bnative%20code%5D%20%7D";

if ("WebkitAppearance" in document.documentElement.style) {
    // If (probably) WebKit browser
    if (escape(navigator.javaEnabled.toString()) === v8string) {
        console.log("V8 detected");
    } else {
        console.log("JSC detected");
    }
} else {
    console.log("Not a WebKit browser");
}

Works for me detecting the difference between Chrome (which also uses V8) and Safari (which also uses JSC).

It's unclear why that code uses escape and compares to an escaped string, though; the difference appears to be just the kind of whitespace used (newlines for JSC, spaces for V8). Ive also made this one friendly to the idea that javaEnabled may not even exist at some point in the future:

var v8string = "function javaEnabled() { [native code] }";

if ("WebkitAppearance" in document.documentElement.style) {
    // If (probably) WebKit browser
    if (String(navigator.javaEnabled) === v8string) {
        console.log("V8 detected");
    } else {
        console.log("JSC detected");
    }
} else {
    console.log("Not a WebKit browser");
}
T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • 10
    I care because of this issue: http://code.google.com/p/android/issues/detail?id=12987 - basically, it may be that the javascript-to-java bridge in JSC is broken on Android 2.3.X, and this impacts the application I'm trying to write. I'm seeing a segfault from somewhere deep in the JNI on my emulator, and I'm trying to determine if this is an emulator-only thing, a JSC-only thing, or something different altogether. – digitalbath Jul 20 '11 at 21:11
  • 2
    @digitalbath: Ah. Lovely. (Seven months and basically no clarification from Google. Not good.) I've updated the answer to point to something I hope helps. Best, – T.J. Crowder Jul 20 '11 at 21:29
  • Awesome piece of information. I just tested a non-browser implementation in a framework which allows to use javascript for making augmented reality apps. I found out that it is using JSC at the core. but i totally agree with the point that we should go for 'features availibility' rather then the battle between JS engines. – Wahib Ul Haq Sep 20 '13 at 13:23
  • Aside note: The v8String condition also applies to the Presto Engine. – hexalys May 16 '14 at 01:25
  • why does the v8String condition escape the function's string for no reason? you can simply compare to `'function javaEnabled() { [native code] }'` – Taureon Feb 03 '23 at 10:02
  • @Taureon - I don't know, that's from the [quoted source](http://www.byond.com/members/Kunark?command=view_post&post=53727), I didn't audit the code. But there doesn't seem to be any reason, the difference appears to just be the kind of whitespace each engine uses. I've added the more direct comparison. – T.J. Crowder Feb 03 '23 at 10:24
6

Although the answer above points out the best methods, I thought I'd point out another way of doing this from inside a native library.

void *dlWebCoreHandle = dlopen("libwebcore.so", RTLD_NOW);
void *v8GetVersion = dlsym(dlWebCoreHandle, "_ZN2v82V810GetVersionEv");
if (v8GetVersion == NULL) {
    /* does not appear to be V8 */
} ... etc.

The exported symbols are mangled, unfortunately, so there is no 100% guarantee that the compiler used by your firmware manufacturer mangled the symbol in the same way (use nm --defined-only libwebcore.so -g on a library with symbols). One would expose this function via the JNI and check from inside Java code.

The libwebcore.so library also lists V8_Fatal as one of the symbols, which is not susceptible to mangling.

JSC will have some other exported symbols that you can check for from inside a native library. If both are non-existent you can fallback to other methods.

soulseekah
  • 8,770
  • 3
  • 53
  • 58
2

var s = '';
for (x in {
    3: 3,
    1: 1
  }) {
  s += x
}
if (s === '31') {
  alert('JSC');
} else {
  alert('V8');
}

By the way this will categorize Firefox as 'JSC' and newer IE versions will look like V8.

My blog post has more V8 sniffing tricks: http://erikcorry.blogspot.dk/2012/12/which-version-of-v8-do-i-have.html

Rich
  • 3,928
  • 4
  • 37
  • 66
Erik Corry
  • 650
  • 4
  • 7