Does the V8 engine that is used in Chrome and Node.js compile the entire code to machine language once or it compiles the next context to be executed every time for each context that is added to the call stack ?
V8 will likely compile some of your code to machine language and likely not compile all of it to machine language.
The exact representation for any piece of code depends on many factors, including the ever-changing optimization behaviors in the library. None of it is guaranteed and shouldn't be treated as such, even if it behaves a certain way right now.
Related
I recently started some web development, with ASP.NET and some Javascript, and something is confusing me alot.
I always read that JavaScript used to be interpreted until JIT slowly made it so chunks are compiled to machine code (which made browsers alot faster).
This makes no sense to me. How can JavaScript compile to native machine code, if traditional JavaScript apps don't target the machine/CPU to begin with?
I understand if an electron.js app gets compiled to machine code using the NodeJS runtime. That I get. Because it natively compiles to machine code and as far as I understand it, doesn't run in a browser.
If traditional JavaScript apps run in a browser, why must it be compiled to machine code? The browser is responsible for running the code, not the CPU. The CPU runs the browser itself. I actually don't see how the native OS can influence anything that happens in the browser at all or vise versa. Seems like a security issue as well.
Sorry if it's a stupid question, but I can't find any resource that will go beyond saying "Javascript uses JIT"
Thank you!
Lauren
At the end of the day, the CPU has to run the code.
JIT-compiling it down to machine code is one way to make that faster.
How can JavaScript compile to native machine code, if traditional JavaScript apps don't target the machine/CPU to begin with?
It is not "Javascript" that is doing it, it is the browser (or rather, the Javascript execution engine inside the browser), and since it is "JIT" it knowns exactly which CPU to target (this is not done in a generic way, this is done for the specific CPU that the browser is currently running on).
So, yes, there is some mismatch, since Javascript will not use low-level primitive types that the CPU can work with directly, which is why there is a lot of indirection and speculative type inference guess-work. The resulting machine code is much different than you would get from hand-coded assembly, but it can still be a net positive. To help with this, WASM was developed, which is closer to "normal" machine code.
Other intermediate, non-CPU specific formats like JVM bytecode or CLR bytecode or LLVM bitcode are in a similar situation (in that can also be compiled to machine code they do not themselves target directly) -- but they have been "lowered" already from language source code to something close to machine code.
Seems like a security issue as well.
Yes, it can be. The browser has to be careful in what it is doing here, and the OS should sandbox the browser as much as possible.
Executing instructions is easier than running an interpreter, and JIT seeks to take advantage of this for a performance boost. All programs running on your computer become machine code at some point, the only question is which instructions are be executed.
let x=0;
for (let i=0;i<100;++i) {
x+=2;
}
Since it is clear that there are no side effects in a block of code like this, it is faster to compile instructions directly, rather than interpreting each line.
// NIOS 2 assembly, sorry its the only one i know
movi r2,0
movi r3,0
movi r4,100
loop:
addi r2,2
addi r3,1
blt r3,r4,loop
Executing this will be faster than executing the parsing logic for each individual instruction.
TLDR: All programs are always running CPU instructions, so it is faster to minimize the number of instructions by skipping the parsing stage when possible
As far as I understood, JavaScript cannot be compiled ahead of time because of it's dynamic nature. So Interpretation and just in time compilation happens at run time, that affects JavaScript performance. So WebAssembly comes into picture. Languages can be compiled ahead of time into intermediate format (WASM). This gives good performance since there is less runtime overhead.
My question is why JVM cannot be used in place of WebAssembly VM. Java compiled into intermediate format (bytecode). This byte code can be given to browser and JVM can execute it. JVM also supports JIT which helps to achieve near native performance.
So what is the need for new WebAssembly. Why can't JVM be integrated into browser and achieve high performance by leveraging the existing most popular Java language.
There are a great many reasons why the JVM was not deemed a suitable runtime in place of WebAssembly ...
WebAssembly was designed with delivery-over-HTTP and browser-based in mind. For that reason, it supports streaming compilation - i.e. you can start compiling the code while downloading.
WebAssembly was designed to have rapid compilation times (resulting in web pages that load quickly), this is supported by having very simple validation rules compared to Java / JVM languages.
WebAssembly was designed with the concept of a 'host' environment, i.e. the browser.
WebAssembly was designed to be secure and simple, minimising the overall attack surface.
WebAssembly was designed to support a great many languages (C, C++, Rust, ...), whereas the JVM was initially design for a single language, Java.
As a general observation, WebAssembly was designed to support multiple languages on the web. The JVM was designed to support Java on the desktop. It doesn't make either one better than the other in a more general sense.
Finally, the JVM was integrated with the browser (Java Applets), but that didn't work out in the end!
A quote from the High-Level Goals of WebAssembly:
a Minimum Viable Product (MVP) for the standard with roughly the same functionality as asm.js, primarily aimed at C/C++;
So their original goal was running C/C++ program in a web browser, not running Java code.
JVM can run:
JavaScript
Python (Jython)
Ruby (JRuby)
Groovy
Scala
C++ (using JNI)
unfortunately the support for java was removed from the browser, because Sun (former maintainer of java), could not provide adequate support.
Just like the Flash ended up losing.
Is JavaScript running on top of web browser?
Like Java running on top of JVM?
Or Does it actually compiled to binary code and run on machine?
V8 (in Google Chrome) contains a JS interpreter and a JIT (Just-in-time) compiler. JS code is converted to V8-specific bytecode. The bytecode is initially interpreted by the interpreter, called "Ignition". When a function becomes "hot" (it is run a lot), the TurboFan JIT compiler produces optimized machine code from the bytecode.
Other modern JS engines use similar strategies. So JS can be interpreted or compiled to machine code (using a JIT compiler), similar to how JVMs work, yes.
Javascript isn't truly compiled - it's interpreted on the browser, so yes it effectively "runs on top of the browser" on the client side.
EDIT: I should've started by saying at it's base level. As is mentioned on a comment to this, there are more complex engines now.
It has to -- nothing can run on a computer without being the appropriate machine code for the processor.
V8 converts the JavaScript to its own byte code, then is heavily optimized and converted into machine code.
Even the JVM does something similar. The JVM converts the Java byte code into machine code.
The major JavaScript engines of web browsers and nodeJS have had just-in-time compilers for years.
I was just watching a video on Compiler Explorer showing the assembly code output by many compilers for various CPUs.
This reminded me that I've been curious about the code generated by the JS engines' jits.
Do any of those engines have ways for us to see that low-level generated code?
(If this is out of place on SO please feel free to migrate it to the correct SE site.)
For V8, there is a flag --print-opt-code, which prints generated optimized assembly code for each function that gets optimized. Note that functions only get optimized when they're "hot", not right away, so for a short "hello, world" style program the flag won't print anything. You can make functions "hot" by calling them a lot.
In older versions, there was a --print-code flag for unoptimized code, but since the baseline (non-optimizing) compiler has been replaced by an interpreter, there is no unoptimized code any more. You can print the generated bytecode with --print-bytecode.
If you're using Chrome, you can specify flags to be passed to V8 by wrapping them in --js-flags, e.g. --js-flags="--print-opt-code".
One thing you can always do is interrupt your program while it's running, using a debugger.
If it's spending most of its time in JIT-compiled code, then chances are the current instruction-pointer value (RIP) will be inside some JIT-compiled machine code, which your debugger will disassemble for you. (Or at least the part after the current RIP: x86 machine code uses variable-length instructions, so there's no reliable way to go backwards. You might single-step until you reach a backwards branch to get to the top of a loop.)
But without any way to figure out which function name you're seeing JITed asm for, this is probably not very useful unless you only have one hot loop (e.g. in an artificial test / microbenchmark).
Having the JIT engine print the asm as it generates it (#jmrk's answer) is much more usable; I only mention this technique because it works without any support from the JIT engine, so it can work on anything.
I’ve noticed that after making a change to a javascript file, clearing the cache, and reloading; one function in particular runs in about 90ms, the next time I load the page, it runs in 40ms, the next time I run it, it runs in 20ms … then never gets faster.
It kind of looks like IE is compiling my javascript and caching that compiled version somewhere, similar to how SQLServer processes queries.
Is that what is happening?
Does anybody know where I can find a clarification of how browsers process javascript?
You may want to check out Eric Lippert's comment to Peter Torr's blog post Compiled, interpreted, whatever:
JScript Classic acts like a compiled language in the sense that before any JScript Classic program runs, we fully syntax check the code, generate a full parse tree, and generate a bytecode. We then run the bytecode through a bytecode interpreter. In that sense, JScript is every bit as "compiled" as Java. The difference is that JScript does not allow you to persist or examine our proprietary bytecode. Also, the bytecode is much higher-level than the JVM bytecode -- the JScript Classic bytecode language is little more than a linearization of the parse tree, whereas the JVM bytecode is clearly intended to operate on a low-level stack machine.
The post and the comment are from September 2003, but judging from Ralph Sommerer's On JavaScript performance in IE8 post, they haven't changed much in the underlying JScript engine:
Unless the JavaScript engine used in IE (and elsewhere) employs some sort of compilation to native code, it will always lag behind its competitors with respect to performance. From what I gather in their Channel9 appearance they have made improvements in bytecode execution, but their main targets were JavaScript native objects (Array, String, ...) and JavaScript-DOM-interaction.
IE8 is not open-source, so one can only make hypotheses; however, open-source browsers (such as Chromium, Firefox, Webkit) do work roughly as you say, as do many other interpreters in non-browser and not necessarily JS settings (compile new sources when first seen or reloaded, cache or save the compiled version for faster execution in the future), so it seems very reasonable that IE's Javascript approach should be very much the same, as you surmised.
I know you asked about IE8, but here is V8 - Google's engine. Includes videos on how V8 works.
http://code.google.com/p/v8/