4.1 The bridge

Overview

The Deno runtime uses Google's v8 engine to execute JavaScript code that it loads. However, Deno's responsibilities don't end there. It can't simply let v8 handle everything.

The v8 engine only supports the features outlined in the ECMAScript specification. Any functionality beyond this specification is the responsibility of the v8 engine's user, not Deno.

For example, the console.log function isn't part of the ECMAScript specification. Therefore, whoever uses the v8 engine must implement this function themselves. Similarly, tasks like making HTTP calls to servers aren't within the scope of the ECMAScript specification. So, the user of the v8 engine is responsible for implementing such functionality.

Many operations fall outside the scope of the ECMAScript specification, including file management, process management, network communications, and system-level tasks. Anything beyond the bounds of the specification requires the user to provide support within the v8 engine.

In summary, it's important to understand that the v8 engine relies on the user for assistance with anything beyond the ECMAScript specification. Deno's role continues even after code is loaded into v8, facilitating the implementation of additional functionalities, making the system functional and versatile.

V8 <-> Deno

The JavaScript application runs using the v8 engine. Deno's primary function is to offer assistance for all the aspects that exist beyond this specific engine's capabilities.

Imagine the connection between the v8 user (which is Deno in this case) and the v8 engine as a bridge. This analogy arises from the distinctions between v8 and Deno. This bridge functions in both directions, resembling a two-way passage. It is important to note that there exists a predetermined way to traverse this bridge while ensuring a smooth round trip. Just like a bridge, Deno acts as a facilitator, allowing the JavaScript code to access functionalities beyond the v8 engine's confines and return seamlessly. This interaction forms an essential part of Deno's role in enhancing the capabilities of the JavaScript application.

In programming, crossing the bridge is like making a function call, but with a difference. This special connection is called a "bridge" because v8 and Deno are different in nature. It's important to understand that Deno and v8 are separate entities with their own identities. To explain further, Deno is a standalone software written in Rust, while v8 is a separate entity written in C++.

Handling (un)known functions

Using external functions follows a straightforward logic. Whenever the V8 engine encounters something that lies beyond the boundaries of the ECMAScript specification, it takes specific actions:

The V8 algorithm outlines the steps it takes when encountering a function call. Here's a breakdown in simpler terms:

When a function is called:

  1. First, the algorithm looks at the name of the function in its internal data records.

  2. If the algorithm recognizes the function (meaning it's a function that follows the rules of ECMAScript and is supported by V8), it proceeds to execute that function.

  3. But if the function isn't recognized by the algorithm, it moves to the next step.

  4. In this case, if the user has given V8 information about an external function in advance, the algorithm temporarily stops its current process.

  5. It then calls the external function provided by the user.

  6. The algorithm waits until a response is received from this external function.

  7. Once the response is ready, the algorithm resumes its work using the obtained response.

  8. If no external function is registered or if the response doesn't come through, the algorithm raises an error to indicate the issue.

These external functions that the algorithm can use are known as external references. Beforehand, these references must be added to the V8's knowledge. This ensures that V8 is aware of these external functions and can use them as needed during its execution. This registration step is important for smooth interaction between the algorithm and external code.

Registration of external references

During its initialization process, Deno systematically records all external references with the v8 engine. This crucial step guarantees that v8 has these references properly set up whenever the fundamental Deno runtime is activated. Below, you will find a compilation of some of the external references that Deno registers, contributing to the seamless functioning of the runtime.

  • Built-in OPs (all the OPs are the basic built-in OPs)

  • Extension OPs (These OPs are provided by extensions)

  • import_meta_resolve

  • catch_dynamic_import_promise_error

  • wasm_async_resolve_promise_callback

  • host_import_module_dynamically_callback

  • host_initialize_import_meta_object_callback

  • import_meta_resolve

  • empty_fn

  • catch_dynamic_import_promise_error

  • etc.

Below is a code snippet that illustrates how external functions are registered with the V8 engine:

references.push(v8::ExternalReference {
  function: call_console.map_fn_to(),
});
references.push(v8::ExternalReference {
  function: import_meta_resolve.map_fn_to(),
});
references.push(v8::ExternalReference {
  function: catch_dynamic_import_promise_error.map_fn_to(),
});
references.push(v8::ExternalReference {
  function: empty_fn.map_fn_to(),
});

Ops

In Deno, aside from just registering functions like the promise reject callback and module resolve callback, there's another noteworthy function it performs. Deno takes the step of registering all the OPs (short for operations) with V8, the underlying JavaScript engine it uses.

for ctx in ops {
    let ctx_ptr = ctx as *const OpCtx as _;
    references.push(v8::ExternalReference { pointer: ctx_ptr });
    references.push(v8::ExternalReference {
      function: ctx.decl.v8_fn_ptr,
    });
    if let Some(fast_fn) = &ctx.decl.fast_fn {
      references.push(v8::ExternalReference {
        pointer: fast_fn.function as _,
      });
      references.push(v8::ExternalReference {
        pointer: ctx.fast_fn_c_info.unwrap().as_ptr() as _,
      });
    }
}

--

Let's now explore some frequently utilized external references in the upcoming sections.

Last updated