Search code examples
javascriptv8

When is a JavaScript function optimized in a V8 environment?


I'm trying to learn whether or not and at which point and to what extent is the following TypeScript function optimized on its way from JavaScript to machine code in some V8 environment for example:

function foo(): number {
  const a = 1;
  const b = a;
  const c = b + 1;
  return c;
}

The function operates with constants with no parameters so it's always equivalent to the following function:

function foo(): number {
  return 1 + 1;
}

And eventually in whatever bytecode or machine code just assign the number 2 to some register, without intermediary assignments of values or pointers from one register to another.

Assuming optimizing such simple logic is trivial, I could imagine a few potential steps where it could happen:

  1. Compiling TypeScript to JavaScript
  2. Generating abstract syntax tree from the JavaScript
  3. Generating bytecode from the AST
  4. Generating machine code from the bytecode
  5. Repeating step 4 as per just-in-time compilation

Does this optimization happen, or is it a bad practice from the performance point of view to assign expressions to constants for better readability?


Solution

  • (V8 developer here.)

    Does this optimization happen

    Yes, it happens if and when the function runs hot enough to get optimized. Optimized code will indeed just write 2 into the return register.

    Parsers, interpreters, and baseline compilers typically don't apply any optimizations. The reason is that identifying opportunities for optimizations tends to take more time than simply executing a few operations, so doing that work only pays off when the function is executed a lot.

    Also, if you were to set a breakpoint in the middle of that function and inspect the local state in a debugger, you would want to see all three local variables and how they're being assigned step by step, so engines have to account for that possibility as well.

    is it a bad practice from the performance point of view to assign expressions to constants for better readability?

    No, it's totally fine to do that. Even if it did cost you a machine instruction or two, having readable code is usually more important.

    This is true in particular when a more readable implementation lets you realize that you could simplify the whole algorithm. CPUs can execute billions of instructions per second, so saving a handful of instructions won't change much; but if you have an opportunity to, say, replace a linear scan with a constant-time lookup, that can save enough computational work (once your data becomes big enough) to make a huge difference.