This process is pretty complicated, those who want to dive deeper into compilation/translation technologies/techniques, it is suggested to read the Dragon book (still I haven’t read it, I didn’t even start, though I’ve read the Contents section, the About section, the Acknowledgement section, well, as usual with all my books). During the compiling process, compiler generates object code as its output, some pretty optimized object code (yes, the machine code). Some developers insist that compiler optimizes and produces better code than the developer itself. I can’t argue with that.

So there goes the linker, which is another tool meant to combine those object files, doing some address relocations, symbol resolution etc. (it’s easy to find more info on linkers, really advised to do so). The meaning of the linker is really important, it glues the generated object code units into one big file, the executable. The file that could be run as a program. Program. Someone must run the program. Not the user, user is just initiating the start by double-clicking on the corresponding icon. There is another tool, the loader. The loader does what its name says, just like Hurry hurries, the Loader loads. The contents of the executable file must be loaded into the virtual memory by the operating system (loader is the part of the OS). So the loader just copies our executable file contents into virtual machine, sets the corresponding instruction pointer registers of the CPU to the starting routine (main function?) and voila, the program begins to run. (The most abstract description of a hard process). So no lookbacks, the code already compiled, the code is fully a machine code, generated for the particular machine architecture. No interpretation, the CPU just executes the instructions (machine code instructions) one by one (well, suppose we have a straight CPU). That’s why people started to name this compilation AoT compilation. Ahead of Time (AoT), like “there is no need to compile it now, but, yep, you did it ahead of time”. The opposite of this is for sure the popular JIT compilation. Just in Time (JiT), like “compile it when you need it”. It’s like some Nike slogan, Just Compile It!

So here’s how the Just in Time compilation (aka interpretation-compilation, or you might say intercompilation) works in my point of view.

Just in Time compilation

Again, we have a source code (no preprocessing here, no C# allowed), the source code is being interpreted by the interpreter. Remember Hurry? Hurry hurried, interpreter interprets. Interpreter is a tool just meant to help the Virtual Machine. Virtual Machine is a program that is being installed on users computer and supposed to run the code we write. In this particular case the “user’s computer” is our backend server, and the server runs our Node.js code. So the interpreter does not generate a machine code. It doesn’t need to know the different architectures/machines/platforms (Intel, AMD, Windows, Linux, …). The interpreter just needs to know about the virtual machine, well the virtual machine has to know about the architectures/machines/platforms. So the interpreter generates “code”, some “intermediate code” understandable by the virtual machine, and the virtual machine must generate the actual machine code to run the program. I thought it was just translating a higher level code into a lower level code line by line and executing each of it. Turns out, the interpreter and the virtual machine do some really tough stuff. Why so? Why not to compile directly into a machine code? That’s a long story, a long and another story. The short answer is “the platforms”. There are so many…

Just cutting to the chase, interpreting is bad, compiling is good. Mm, more practically, interpreting is slow, the execution of a compiled program is faster. But there are many other “bad” things about JavaScript particularly. First of all, the weak typing. C++ is a strictly typed language, JavaScript is weakly typed. What does that mean? That means we can be free.

Strict typing is good, at least for the compiler itself. Compiler must strictly know the corresponding types of variables. Why? Because the compiler has to generate code. It has to place those variables in the right places, allocate fixed size boxes for them, place them as optimized as possible. The compiler can’t afford to place a 4 byte integer into a 20 byte box just because it could be transformed into some string.

Strict typing helps compiler to generate correct code

Compiler places variables exactly where they “should be”.

Instead of this, you can write something like this in JavaScript without any feel of incompetence (a little).

var some = "this is a string"; // declaring a string

some = 36; // change the type on the fly

some = 3.14;

Weak typing slows down the execution

How should the interpreter interpret the variable ‘a’ above (sometimes I use interpreter, virtual machine and execution engine interchangeably)? Should it place “a” in a large (just in case) box? Should store hidden variables for each of the “a”s type? Anything the interpreter (or virtual machine) will do to support this “language quirks”, will slow down the execution of the code.

There is more coming…

What about the objects that can “change” their properties dynamically, on the fly? See below.

Stress testing the virtual machine

All we care is the object layout. See, C++ compiler generates objects smoothly laid out, while JavaScript’s “execution engine” struggles on the thinking, how to frakin do that?

Object memory layout

I call this illustrations “pseudo-illustrations” as sometimes they contain some invalid but not significant details. In the illustration above we see that in C++, A’s instance is laid out “smoothly”, “a” property takes 4 bytes (just an assumption, like a said, pseudo-illustration) and starts from the address 0xA0. The object itself (A’s instance) starts at address 0xA0, so the first property, “a”, placed at the address 0xA0 + the corresponding offset (0 in this case, as the “a” property is the very first property of the instance). So as “a” takes 4 bytes, the next (2nd) property “b” starts at 0xA0 + 4 (the size took by “a” property). “c” starts at 0xA0 + 12 (plus the size used by “a” and “b”). There is an aligning factor we omitted (not a major case in this context).

So now look at the right side of the same illustration. How should JS place an instance of A and its properties? How should it guess the type, what if they would change? What should it do? Where shall it go?