Why every execution context has Realm? - javascript

I'm reading ECMAScript 2023.
It say all execution contexts has "Realm" state component.
And it describes,
a realm consists of a set of intrinsic objects, an ECMAScript global environment, all of the ECMAScript code that is loaded within the scope of that global environment, and other associated state and resources.
I understand realm is for global environment like window(browser), global(node).
And I understand "Global Environment Records" already define global environment once on first code evaluation.
I wonder why a Realm for a execution context is needed.
I'm reading https://tc39.es/ecma262/#sec-execution-contexts.

You can find the current Realm record as "the value of the Realm component of the running execution context".
That term is referenced multiple times across the specification, mostly for bookkeeping to carry-over the value, but in the end to lookup intrinsic prototypes or cached template strings from the current realm.

Related

What is the purpose of passing WindowProxy as the global this value?

Background
The HTML spec introduces the concept of the WindowProxy.
It says:
A WindowProxy is an exotic object that wraps a Window ordinary object,
indirecting most operations through to the wrapped object. Each
browsing context has an associated WindowProxy object. When the
browsing context is navigated, the Window object wrapped by the
browsing context's associated WindowProxy object is changed.
The WindowProxy platform object is created when the browsing context is created by the host, as defined in ECMAScript's InitializeHostDefinedRealm (step 8). It is directly set to be the global this value.
At that same point, the Window object is created, set to be the global object.
Through the ECMAScript spec, we see that whenever a lookup of an identifier happens, it first searches the environment record of the current execution context, and if not found continues out all the way out to the Global Environment Record, which in turn looks for the identifier on the global object.
As far as I can see, this set of operations never uses the global this value.
Questions
Are there any operations in ECMAScript that use the global this value? If so, which?
How exactly does setting the global this value to WindowProxy result in the desired proxy behavior?
Edit
This StackOverflow question answers the high-level purpose of WindowProxy. My question above is related to the ECMAScript spec and how exactly the standard built-in operations get delegated to the WindowProxy object, by virtue of it being the global this value.
Article with some interesting, but vague, information not related to the ECMAScript spec.
I'm not sure if this is the only reason, but this at least allows to have the built-ins bound to the WindowProxy instead of on the Window, which may not be unique to the browsing-context.
This is done in https://tc39.es/ecma262/#sec-global-environment-records
A Global Environment Record is logically a single record but it is specified as a composite encapsulating an Object Environment Record and a Declarative Environment Record. The Object Environment Record has as its base object the global object of the associated Realm Record. This global object is the value returned by the Global Environment Record's GetThisBinding concrete method. The Object Environment Record component of a Global Environment Record contains the bindings for all built-in globals (clause 19) and all bindings introduced by a FunctionDeclaration, GeneratorDeclaration, AsyncFunctionDeclaration, AsyncGeneratorDeclaration, or VariableStatement contained in global code. The bindings for all other ECMAScript declarations in global code are contained in the Declarative Environment Record component of the Global Environment Record.
You can see an example where this is observable in this JSFiddle* where we store the built-in function eval (hereafter storedEval) originating from a same-origin <iframe>.
From the <iframe>'s context we declare a global variable window.foo = "first frame".
Calling storedEval("this.foo") from the parent document we get back the string "first frame". This means that our storedEval function correctly is bound with the <iframe>'s context.
Then we navigate the <iframe> to a new document. At this point, the global object has been replaced, this.foo is undefined in the new <iframe> context.
Now, if we call again storedEval("this.foo") from the parent document, we also get undefined. And if we then set window.foo in the new <iframe> document, we'd get that new value.
This is because the built-in eval is bound to the WindowProxy, and not to the global Window object. Failing to do so, we'd keep a reference of the previous Window, even after its document has been navigated away.
* The example is outsourced because StackSnippet's null-orgined iframes don't allow cross-access, even from srcdoc

Is the global execution context the same as the global object in JavaScript?

As I understand it, every time a JavaScript program begins running, the engine first creates an execution context, pushes this execution context into the call stack/execution stack, and then it creates a global object (window in the browser and global in Node) as well.
To create the execution context, the engine first goes through the creation phase, where it allocates space in memory for entire function definitions and variable declarations (hoisting). It maintains a reference to the outer scope (this creates the scope chain, but in the global execution context there isn't anything above it), and it also creates the this property within the execution context and sets it to the window object in the browser and module.exports in Node. Lastly, the engine then goes through the execution phase, where it executes the code line by line and assigns a value to each variable.
Am I right in differentiating the global execution context creation from the creation of the global object itself? I view both of them as operations that happen side by side but are not the exact same thing.
Yes, it's fair to say that the global context and the global object are separate concepts. One illustrating distinction is the this binding: a context defines what this refers to (in case of the global context: to the global object); whereas the global object has no property named "this".
At the same time, global context and global object are somewhat coupled insofar as local variables in the former are properties on the latter.
Note that "execution context" is mostly an abstract concept, that means an engine only has to behave "as if" it did what the spec describes. Chances are that high-performance engines will take certain shortcuts (e.g., optimized code might keep some local variables in registers or on the machine stack, never putting them into any context at all).

Does the Lexical Environment of a JavaScript code contain ThisBinding or does an Execution Context contain it?

My apologies if this question has been asked already, but I am a little confused about the structure of a JavaScript execution context during the creation phase. I was going through a couple of tutorials where one said that the ThisBinding was a component of an execution context whereas another said the same was a component of a Lexical Environment
this article here seems to say that the this keyword is a part of Lexical Environment structure. If true, this would mean that every Lexical Environment component created will have its this keyword.
this article here says that the this keyword is rather a part of the bigger execution context. If true, this would mean for every execution context created, there would exist only one this keyword regardless of how many Lexical Environment components it has.
Which one is correct here?

Why variable object was changed to lexical environment in ES5?

ES5 changed variable object(VO) to lexical environment. What's the motivation of such change since VO is already very obvious as perception?
I think variable objects are more analogous to environment records.
An Environment Record records the identifier bindings that are created
within the scope of its associated Lexical Environment.
In ES5 there are two different kinds of environment records:
Declarative environment records are used to define the effect of
ECMAScript language syntactic elements such as FunctionDeclarations,
VariableDeclarations, and Catch clauses that directly associate identifier bindings with ECMAScript language values. Object
environment records are used to define the effect of ECMAScript
elements such as Program and WithStatement that associate
identifier bindings with the properties of some object.
So the question would be why declarative environment records were introduced instead of only using object environment records just like ES3 variable objects. The difference is that declarative environment records can have immutable bindings:
In addition to the mutable bindings supported by all Environment
Records, declarative environment records also provide for immutable
bindings. An immutable binding is one where the association between an
identifier and a value may not be modified once it has been
established.
Immutable bindings don't have a direct equivalent in objects. A property can be defined as both non-configurable and non-writable, becoming immutable. However,
Creation and initialisation of immutable binding are distinct steps so
it is possible for such bindings to exist in either an initialised or
uninitialised state.
But you can't have an uninitialized property. If you define a non-configurable non-writable property with value undefined, then you won't be able to initialize it to the desired value.
I don't think it's possible to have uninitialized immutable bindings in ES5. CreateImmutableBinding is only used in Declaration Binding Instantiation and Function Definition, and in both cases it's immediately initialized with InitializeImmutableBinding.
But possibly this was done to allow uninitialized immutable bindings as extensions of the language, like the JavaScript 1.5 const. Or maybe they already had in mind ES6 const.
The same author whose ES3 article you linked wrote also about ES5 (and even linked that section there). I'll quote Mr. Soshnikov from his "Declarative environment record" section in ECMA-262-5 in detail. Chapter 3.2. Lexical environments: ECMAScript implementation:
In general case the bindings of declarative records are assumed to be stored directly at low level of the implementation (for example, in registers of a virtual machine, thus providing fast access). This is the main difference from the old activation object concept used in ES3.
That is, the specification doesn’t require (and even indirectly doesn’t recommend) to implement declarative records as simple objects which are inefficient in this case. The consequence from this fact is that declarative environment records are not assumed to be exposed directly to the user-level, which means we cannot access these bindings as e.g. properties of the record. Actually, we couldn’t also before, even in ES3 — there activation object also was inaccessible directly to a user (except though Rhino implementation which nevertheless exposed it via __parent__ property).
Potentially, declarative records allow to use complete lexical addressing technique, that is to get the direct access to needed variables without any scope chain lookup — regardless the depth of the nested scope (if the storage is fixed and unchangeable, all variable addresses can be known even at compile time). However, ES5 spec doesn’t mention this fact directly.
So once again, the main thing which we should understand why it was needed to replace old activation object concept with the declarative environment record is first of all the efficiency of the implementation.
Thus, as Brendan Eich also mentioned (the last paragraph) — the activation object implementation in ES3 was just “a bug”: “I will note that there are some real improvements in ES5, in particular to Chapter 10 which now uses declarative binding environments. ES1-3’s abuse of objects for scopes (again I’m to blame for doing so in JS in 1995, economizing on objects needed to implement the language in a big hurry) was a bug, not a feature”.
I don't think I could express this any better.

Is there a defined name for the execution context that encapsulates all others in JavaScript?

Is there a defined name for the execution context that encapsulates all others in JavaScript?
For example is it called the "global execution context". That phrase is not mentioned in the ES6 spec as far as I can find.
It's called "the global environment" as per the ES5 spec (or see the equivalent section of the ES6 spec):
The global environment is a unique Lexical Environment which is created before any ECMAScript code is executed. The global environment’s Environment Record is an object environment record whose binding object is the global object (15.1). The global environment’s outer environment reference is null.
Or perhaps you are looking for the "initial global execution context", whose lexical and variable environment are references to the global environment.
I don't believe there's any term more specific than simply "global environment" or "global environment record" (to draw a distinction with its binding object) which is used several places in the ES6 pecification such as §8.1 and §8.1.14 (draft spec, those section numbers may drift).

Categories

Resources