2.9 V8

Overview

V8 is a fundamental component of Deno's architecture, playing a crucial role in the execution of JavaScript code. While Tokio is also essential, V8's presence is indispensable, and its absence would significantly impair Deno's functionality.

V8, developed by Google, is a high-performance JavaScript and WebAssembly engine, released as open-source software. Written in C++, it has evolved into a powerful tool, extending its capabilities beyond Deno to Chrome and Node.js. As a new addition to Deno, V8 continues to empower this innovative runtime.

V8 provides a supportive environment for ECMAScript and WebAssembly, allowing them to thrive. Its compatibility is extensive, supporting various operating systems, including Windows 7 and later, macOS 10.12 and higher, and Linux systems with x64, IA-32, ARM, or MIPS processors. V8 can function as a standalone engine or integrate with C++ applications, significantly enhancing their capabilities.

V8 assumes a multifaceted role, encompassing various critical functions. It initiates its processes by orchestrating the compilation and execution of JavaScript source code, thereby creating virtual environments. Additionally, V8 takes on the responsibility of managing memory allocation for a diverse range of objects, including the graceful removal of unnecessary objects through garbage collection, a unique strength that distinguishes it from other technologies.

The precision of V8's garbage collector is a crucial factor in its exceptional performance. V8 also bridges the gap between C++ and JavaScript, enabling seamless interactions. With remarkable finesse, V8 allows C++ applications to share their objects and functions with JavaScript code, fostering harmonious collaboration. This interaction remains under the control of the application, which can selectively expose objects and functions to the JavaScript domain.

To explore the complex features of V8, one can utilize its comprehensive public API. A wealth of information and resources is available at https://v8.dev/, inviting individuals to investigate and discover the full potential of this powerful engine.

Key concepts

V8, the core of Deno's runtime, is a vast and complex component, consisting of approximately one million lines of code. This powerful engine features a extensive public API, offering numerous functionalities and capabilities. Due to its complexity, navigating V8 in its entirety can be challenging, so we will focus on key concepts to provide a foundational understanding.

To demonstrate V8's importance, consider a simple "hello world" program, which showcases the engine's significance. (ref: https://chromium.googlesource.com/v8/v8/+/refs/tags/11.8.34/samples/hello-world.cc)

// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "include/libplatform/libplatform.h"
#include "include/v8-context.h"
#include "include/v8-initialization.h"
#include "include/v8-isolate.h"
#include "include/v8-local-handle.h"
#include "include/v8-primitive.h"
#include "include/v8-script.h"
int main(int argc, char* argv[]) {
  // Initialize V8.
  v8::V8::InitializeICUDefaultLocation(argv[0]);
  v8::V8::InitializeExternalStartupData(argv[0]);
  std::unique_ptr<v8::Platform> platform = v8::platform::NewDefaultPlatform();
  v8::V8::InitializePlatform(platform.get());
  v8::V8::Initialize();
  // Create a new Isolate and make it the current one.
  v8::Isolate::CreateParams create_params;
  create_params.array_buffer_allocator =
      v8::ArrayBuffer::Allocator::NewDefaultAllocator();
  v8::Isolate* isolate = v8::Isolate::New(create_params);
  {
    v8::Isolate::Scope isolate_scope(isolate);
    // Create a stack-allocated handle scope.
    v8::HandleScope handle_scope(isolate);
    // Create a new context.
    v8::Local<v8::Context> context = v8::Context::New(isolate);
    // Enter the context for compiling and running the hello world script.
    v8::Context::Scope context_scope(context);
    {
      // Create a string containing the JavaScript source code.
      v8::Local<v8::String> source =
          v8::String::NewFromUtf8Literal(isolate, "'Hello' + ', World!'");
      // Compile the source code.
      v8::Local<v8::Script> script =
          v8::Script::Compile(context, source).ToLocalChecked();
      // Run the script to get the result.
      v8::Local<v8::Value> result = script->Run(context).ToLocalChecked();
      // Convert the result to an UTF8 string and print it.
      v8::String::Utf8Value utf8(isolate, result);
      printf("%s\n", *utf8);
    }
    {
      // Use the JavaScript API to generate a WebAssembly module.
      //
      // |bytes| contains the binary format for the following module:
      //
      //     (func (export "add") (param i32 i32) (result i32)
      //       get_local 0
      //       get_local 1
      //       i32.add)
      //
      const char csource[] = R"(
        let bytes = new Uint8Array([
          0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x07, 0x01,
          0x60, 0x02, 0x7f, 0x7f, 0x01, 0x7f, 0x03, 0x02, 0x01, 0x00, 0x07,
          0x07, 0x01, 0x03, 0x61, 0x64, 0x64, 0x00, 0x00, 0x0a, 0x09, 0x01,
          0x07, 0x00, 0x20, 0x00, 0x20, 0x01, 0x6a, 0x0b
        ]);
        let module = new WebAssembly.Module(bytes);
        let instance = new WebAssembly.Instance(module);
        instance.exports.add(3, 4);
      )";
      // Create a string containing the JavaScript source code.
      v8::Local<v8::String> source =
          v8::String::NewFromUtf8Literal(isolate, csource);
      // Compile the source code.
      v8::Local<v8::Script> script =
          v8::Script::Compile(context, source).ToLocalChecked();
      // Run the script to get the result.
      v8::Local<v8::Value> result = script->Run(context).ToLocalChecked();
      // Convert the result to a uint32 and print it.
      uint32_t number = result->Uint32Value(context).ToChecked();
      printf("3 + 4 = %u\n", number);
    }
  }
  // Dispose the isolate and tear down V8.
  isolate->Dispose();
  v8::V8::Dispose();
  v8::V8::DisposePlatform();
  delete create_params.array_buffer_allocator;
  return 0;
}

This straightforward program is designed to display the phrase "hello world." Although it appears simple, the hello world program offers valuable insights into several key V8 concepts. Let's embark on a step-by-step exploration of each concept.

This code's sole purpose is to output the iconic greeting "hello world." Despite its seeming simplicity, the hello world program serves as a gateway to a range of crucial V8 concepts. Let's proceed to examine each concept individually, delving into each one step by step.

Isolate

In V8, an "isolate" represents a separate instance of the engine, responsible for executing JavaScript code. Each isolate operates independently, with its own environment, data, and variables. It's essential to note that objects or elements from one isolate should not be used in another.

When V8 is initialized, it automatically creates a default isolate and sets it as the current context. This default isolate serves as the starting point for V8's activities. However, the programmer (embedder) can create additional isolates, which can run simultaneously, enabling parallel code execution on multiple threads. Note that only one thread can interact with an isolate at a time.

Think of isolates as self-contained virtual machines (VMs), each with a dedicated heap for storing data during runtime. Initializing an isolate is the first step, setting the stage for subsequent actions. By managing isolates effectively, developers can create efficient and organized environments for running JavaScript code.

Context

In V8, a "context" represents a unique execution environment that enables multiple, unrelated JavaScript applications to run within a single V8 instance. To specify a context for executing JS code, a user program must provide the necessary information. Once established, a context can be entered and exited as needed.

Imagine executing JavaScript operations in context A, then seamlessly transitioning to context B, replacing A as the active environment. When exiting context B, context A is reinstated, ensuring a smooth transition.

V8 introduced contexts to create isolated JavaScript environments for elements like windows and iframes in web browsers, preventing interference between their JavaScript activities. The utility of contexts becomes apparent when isolation is crucial for smooth, independent functioning of components within a larger application or system.

Compile and run

The process proceeds with the compilation and execution of JavaScript (JS) code. You may wonder why compilation is necessary, as JS is typically interpreted. However, V8 takes it a step further by incorporating compilation for enhanced performance. This additional step may seem unnecessary, but it's a crucial aspect of V8's functionality.

But why compile JS code? Initially, JS is interpreted, but V8's compilation phase boosts execution speed. The secret to V8's speed lies in Just in Time (JIT) compilation. Here's how it works: JS code is compiled into native machine code via JIT. During execution, this machine code is dynamically analyzed and recompiled for optimal performance. This process ensures that the code is executed efficiently, resulting in faster execution times.

This dynamic approach significantly enhances speed, much like a car's finely-tuned engine constantly adjusting for optimal performance. In V8, continuous machine code analysis and optimization enable swift JS program execution. The end result is a significant boost in speed, making V8 a powerful engine for executing JavaScript code.

--

This section has provided a foundational understanding of V8, but a comprehensive examination of its inner workings requires a more in-depth approach. The topic of V8 is complex and nuanced, necessitating a thorough and detailed analysis to fully grasp its underlying mechanics. A brief overview is insufficient to capture the full scope of V8's complexity, and a more extensive investigation is necessary to gain a complete understanding of its intricate details.

Last updated