Search code examples
javascriptv8

When does V8 starts compiling and executing the code in relation to the event loop stack?


I have been curious of how js code is executed from beginning to the end.

I have read about the event loop and seen this great video, how stack frames look like here,and also read about how the V8 engine compiles js code here.

Question :

When does V8 starts compiling and executing the code in relation to the event loop stack ?

is it when the function is about to get popped out of the stack?

or do all functions get compiled, right before they are placed on the stack ?

therefore the proccess of putting other function on top is acctually only dealing with machine code, if so does the execution of that machine code occurs when popping the function from the stack ?

In case my question is not understood, i believe via this example it would be better understood

Example :

function foo() {
    var name=`foo`;
    var obj = {
        number: 6
    }
    console.log(obj.number);
}

function baz() {
    var name = `baz`;
    console.log(a);
    foo();
}

baz();
  1. the first process that occurs is lazy parsing, where all the file is being parsed for syntax errors, but not fully parsed so it takes less time.
  2. going through the function declerations

    • does the v8 engine now compiles the function declaration code to machine code ? or its not his turn yet..
  3. baz is called , baz is placed on bottom of the stack ,and in its stack frame the name variable value is stored (since its a primitive).

    • when exactly does buz gets parsed and converted to machine code ? before its placed on the stack ? or when it pops off ?
  4. console.log placed on top of baz and is executed, - console shows baz

    • is this is the place where the console.log js code is compiled to machine code and executed ?
  5. console.logs pops of the stack.

  6. foo is placed on top of baz, obj is placed in heap (since its a reference type), and name=foo is placed in foo`s stack frame.

  7. console.log goes on top of foo, and is executed , console shows 6.

  8. console.log pops off.
  9. foo pops off, along with its local variable value.
  10. baz pops off along with its name=baz local variable

Solution

  • There is no such thing as "the event loop stack".

    One concept is the "call stack", which is a term for the fact that when functions call each other, they form a stack-like current state of things. This is mostly a theoretical concept, but as it happens, there is indeed an area of memory that is called "the stack" and is used for functions' local variables, but it is not a data structure with a push/pop interface: the act of calling a function places its data on this stack, and returning from the function removes it again, returning control to the calling function.

    This answers part of your function: starting to execute a function is literally exactly the same as having this function placed on the call stack. Those are two descriptions for the same thing.

    Another concept is the event queue. You can think of it as a queue of functions waiting to be executed; whenever no other function is executing, the next function from this queue is called. Putting a function into the queue does not require it to have been parsed or compiled. In your example snippet, the event queue is not used at all.

    Compiling functions is really unrelated to all this. When a function is called (by another function, or by the event loop), it has to be executable in some form -- but depending on your JavaScript engine, it could get interpreted without any compilation, or it could get compiled to bytecode, or it could get compiled to machine code, or the engine could use this opportunity to switch from one to the other.

    Since you asked about V8 specifically: in current versions, when V8 sees a function definition like function f() { ... }, it doesn't do anything anything yet (except for a few cases where V8 guesses that the function will be executed soon, in which case it creates bytecode for it immediately). If the function gets queued as a callback, still no parsing or compilation happens. When a function is called for the first time, V8 creates bytecode for it. When the function is called again, the bytecode exists already, so no additional work is required. When a function runs hot enough, V8 eventually decides to compile optimized machine code for it, usually on a background thread. Additional calls to it are opportunities for V8 to check whether the background thread is done producing machine code already; if so, then the next call will use that optimized code instead of interpreting the function's bytecode like the earlier calls did. Note that these implementation details can and will change over time.

    One more note for clarification:

    in its stack frame the name variable value is stored (since its a primitive).

    Not quite. The variable itself is stored in the stack frame, but only as a reference. Whether it refers to a primitive value or not doesn't matter; strings and objects are both allocated on the heap. The local variable will be destroyed when the function returns and its stack frame is torn down; the respective object or string on the heap will (eventually, at some indeterminate time) be cleaned up by the garbage collector.