src/main.rs
, we would find these 2 lines of code:Isolate::new
in src/isolate.rs
:libdeno
: deno_init
and deno_new
. These two functions, unlike many other functions used, are defined from libdeno/api.cc
, and are made available thanks to FFI and libc
. Their Rust interface is provided through src/libdeno.rs
.libdeno/api.cc
:deno_init
is used to initialize the V8 platform, while deno_new
is used to create a new isolated VM instance on this platform. (A few V8 embedding APIs are used here. To learn more about V8 embedding, check out https://v8.dev/docs/embed for concepts, and https://denolib.github.io/v8-docs/ for API Reference.)deno_new
that might not be immediately clear: DenoIsolate
and InitializeContext
. It turns out DenoIsolate
serves more or less as a collection of Isolate information. Instead, InitializeContext
is the more interesting one. (It seems to be invoked here only when there is no snapshot provided. However, you'll also find the function being used in deno_new_snapshotter
in libdeno/api.cc
to create a new snapshot, so it is always an inevitable step):libdeno
API on the TypeScript end, the above names wrapped in deno::v8_str
might sound familiar to you. In fact, this is where the very few C++ bindings onto JavaScript are attached: we get the global object of current Context
(a V8 execution environment that allows separate code to run) and add some extra properties onto it, from C++.libdeno.send(...)
from TypeScript (you'll find such usage in sendInternal
of js/dispatch.ts
), you are actually calling into a C++ function called Send
. Similar things happens to libdeno.print
.console.log(...)
is defined asprintFunc
is a private field in class Console
, and its initial value is provided throughlibdeno.print
here. From the above bindings code, we know that calling to libdeno.print
from TypeScript is equivalent to calling Print
in libdeno/binding.cc
, inside of which we would discoverconsole.log
is in fact just indirectly calling fwrite/fprintf
!Print
, Send
and Recv
in libdeno/binding.cc
to understand what is happening behind the scene.src/main.rs
, immediately following isolate creation, we finddenoMain
is a TypeScript side function. isolate.execute
is used to run the code. Let's extract its definition from src/isolate.rs
:libdeno::deno_execute
. We can find its actual definition in libdeno/api.cc
again:deno::Execute
:Execute
is eventually submitting the code to v8::Script::Compile
, which compiles the JavaScript code and call Run
on it. Any exceptions, compile time or runtime, are further processed through HandleException
:d->last_exception_
to be an error message formatted in JSON, which was read in deno_last_exception
:Isolate::last_exception
from Rust:Isolate::execute
to decide if error handling is necessary.