# LibWeb: Browsing Contexts and Navigables **NOTE: This document is a work in progress!** ## Introduction: How does code execute, really? Before we can dive into how LibWeb and Ladybird implement the HTML web page navigation operations, we need to dive into some fundamental specification concepts. Starting with, how does code actually execute in a (possibly virtual) machine? Next we'll look at what that means for the ECMAScript Specification (JavaScript), and finally how the ECMAScript code execution model ties into the HTML specification to model how to display web content into a browser tab. ### Native Code Execution: A Primer When modeling the execution of a native program written in a popular systems language like C, C++, or Rust, most systems programmers should be familiar with the concepts of *threads* and *processes*. In a "hosted" environment, the execution of one's userspace program generally starts with an underlying operating system creating a process for the application to run in. This process will contain a memory space for program data and code to live in, and an initial, or main thread to start execution on. In order for the operating system to change which thread is executing on a particular CPU core, it needs to save and restore the *Execution Context* for that thread. The Execution Context for a native thread generally consists of a set of CPU registers, any floating point state, a program counter that tracks which instruction should be loaded next, and a stack pointer that points to the local data the thread was using to track its function call stack and local variables. The programmer can also request additional threads through a system call, providing a set of thread attributes and a function to call as the entry point. For traditional compiled programs, the concept of accessing variables and functions is split into two phases. At compile time, local variables and arguments are folded into stack slots and allocated into registers. Exported variables and functions are written into the executable object file (ELF, Mach-O, PE, etc.) and are visible to external tools as symbols, as referenced by a symbol table contained within the object file format. Normally local variable and argument names and locations are lost in the compile+link steps, but the compiler can be configured to emit extra debug information to allow debuggers to access and modify them at runtime. In order to support something like the dynamic imports of interpreted languages, the programmer has to call a platform-specific function to load the new module (e.g. ``dlopen`` or ``LoadLibrary``). But after the module is opened, in order to actually refer to any exported symbols from that module the programmer has to retrieve the address of each symbol through another platform specific function (e.g. ``dlsym`` or ``GetProcAddress``), once per symbol. ### ECMAScript Execution Model: Realms and Agents The ECMAScript specification has analogs for almost all of these concepts in the section on [Executable Code and Execution Contexts](https://tc39.es/ecma262/#sec-executable-code-and-execution-contexts). Working in the other direction from the native code explanation, ECMAScript describes the accessibility and scopes of functions, variables, and arguments in terms of [*Environment Records*](https://tc39.es/ecma262/#sec-environment-records). Note that these Environment Records are not actually visible to executing code, and are simply a mechanism used by the specification authors to model the language. Every function and module has a type of Environment Record that contains the variables, functions, catch clause bindings, and other language constructs that affect which names are visible at any location in the code. These Environment Records are nested, in a tree-like structure that somewhat matches the Abstract Syntax Tree (AST). The root of the tree of Environment Records is the Global Environment Record, which corresponds to the Global Object and its properties. In JavaScript, there is always a ``this`` value representing the current object context. At global scope, the Global Object normally takes that responsibility. In a REPL, that might be some REPL specific global object that has global functions to call for doing things like loading from the filesystem, or even be as complex as Node or Bun. In a Browser context, the Global object is normally the Window, unless there's a Worker involved. For historical reasons the global ``this`` binding for Window contexts is actually a WindowProxy that wraps the Window. This concept is quite different from a native executable, where there's no actual object representing the global scope, simply symbols that the linker and loader make available to each module. While the Global Object and its Global Environment represent the root of the tree of identifiers visible to the executing JavaScript code, the Global Object isn't sufficient to model all the state around a conceptual thread of execution in ECMAScript. This is where the two concepts of [*Realms*](https://tc39.es/ecma262/#sec-code-realms) and [*Execution Contexts*](https://tc39.es/ecma262/#sec-execution-contexts) come into play. A [*Realm Record*](https://tc39.es/ecma262/#realm-record) is a container that holds a global object, its associated Global Environment, a set of intrinsic objects, and any *host* (also called an *embedder* in some specification documents) defined extra state that needs to be associated with the realm. In LibWeb, the Host Defined slot holds an object that has the HTML Environment Settings Object for each realm, as well as all the prototypes, constructors, and namespaces that need to be exposed on the Global Object for Web APIs. On top of the Realm abstraction, ECMAScript uses the Execution Context to model the state of execution of one particular script or module. Each Execution Context belongs to an [*execution context stack*](https://tc39.es/ecma262/#execution-context-stack) with the topmost context named the [*running execution context*](https://tc39.es/ecma262/#running-execution-context). An Execution Context has information about the current function, the script or module that the current code block belongs to, additional Environment Records required to access names in the current scope, any running generator state, and most importantly to the thread analogy, the state needed to suspend and resume execution of that script. As with Environment Records, Realms and Execution contexts are not directly accessible to running JavaScript code. The final missing piece for the JavaScript execution model is how these stacks of Execution Contexts are actually scheduled to run by the ECMAScript implementation. In the most common case, this means directly mapping the ECMAScript model to the earlier native concepts of threads and processes in a way that allows for flexibility in the implementation strategies. The last thing that the specification authors want to do is constrain implementations so much that innovation and experimentation becomes impossible. The method for this mapping is the two related specification mechanisms [*Agents*](https://tc39.es/ecma262/#sec-agents) and [*Agent Clusters*](https://tc39.es/ecma262/#sec-agent-clusters). The Execution Context stack mentioned above actually belongs to an Agent, which holds said stack, a set of metadata about the memory model, and a shared reference to an [*executing thread*](https://tc39.es/ecma262/#executing-thread). According to ECMAScript, there should always be at least one Execution Context on the stack, to allow concepts such as the running execution context to always refer to the topmost Execution Context of the [*surrounding agent*](https://tc39.es/ecma262/#surrounding-agent). However, the HTML specification opts to remove the default execution context from the execution context stack at creation, and instead manually pushes and pops execution contexts for script, module, and callback execution. The relationship between Realms and Agents is not 1-1, but N-1. In the ECMAScript specification, this manifests as a part of the [*Shadow Realm proposal*](https://tc39.es/proposal-shadowrealm/), while the Web platform requires multiple Realms per Agent to specify the historical behavior of ``