@@ -7,7 +7,7 @@ authors: boa-dev
77
88In this post we dive into how ECMAScript engines store variables.
99We go over storage optimizations and learn about scope analysis.
10- If you are a ECMAScript developer you will get some practical tips to improve the performance of your code.
10+ If you are an ECMAScript developer you will get some practical tips to improve the performance of your code.
1111If you write your own ECMAScript engine or any interpreter or compiler you might get some implementation ideas.
1212
1313<!-- truncate-->
@@ -18,7 +18,7 @@ Before we start, let's get some disclaimers out of the way:
1818 Other engines might do things different, so take everything with a grain of salt.
1919- This post omits some implementation details to focus on the most relevant parts.
2020- This post contains data structures written in pseudo Rust.
21- These are only for visualization and you do not need to understand Rust.
21+ These are only for visualization, and you do not need to understand Rust.
2222
2323## Scopes and Variables
2424
@@ -60,7 +60,7 @@ const a = 1;
6060```
6161
6262In this example our two variables have different identifiers.
63- Notice that when we access the variable ` a ` from the block scope, it's value is resolved as expected.
63+ Notice that when we access the variable ` a ` from the block scope, its value is resolved as expected.
6464This is because scopes are nested.
6565When we cannot find a variable in the current scope, we look for the same identifier in the outer scope.
6666In this case we have to look for ` a ` in the block scope and then in the global scope.
@@ -91,7 +91,7 @@ console.log(a); // 1
9191You can see that variables are tied to their scopes.
9292All three variables ` a ` never change their values.
9393They just exist in their respective scopes and as soon as the scope has ended they are no longer accessible.
94- Instead the previous outer scope returns to being the current scope and it's variables are accessible.
94+ Instead, the previous outer scope returns to being the current scope and its variables are accessible.
9595
9696You can see that in addition to blocks, functions also have scopes.
9797There are some more details to function scopes and how ` let ` , ` const ` and ` var ` differ.
@@ -118,10 +118,10 @@ struct Scope {
118118```
119119
120120This is a nice and easy data structure for our variables.
121- And because most languages come with a hashmap builtin , we do not have implement much!
121+ And because most languages come with a hashmap built-in , we do not have implement much!
122122
123123Let's add the ability to nest our scopes.
124- Since all scopes are the same, we can just build a self referential data structure:
124+ Since all scopes are the same, we can just build a self- referential data structure:
125125
126126``` rust
127127struct Scope {
@@ -138,7 +138,7 @@ This was the approach we used in Boa before we switched to a different implement
138138
139139You may already have spotted some performance issues with this data structure.
140140Consider that accessing variables is one of the things happening all the time in most languages.
141- Therefore the runtime performance of variable access operations should be highly optimized.
141+ Therefore, the runtime performance of variable access operations should be highly optimized.
142142With this current data structure we have to perform at least one hashmap lookup per variable access.
143143Most hashmap implementations will incur significant cost compared to accessing a fixed location in memory.
144144This problem gets worse when the variable we want to access is not in our current scope.
@@ -148,11 +148,11 @@ How would you optimize this data structure for runtime performance?
148148Can you find a way to locate each variable without accessing multiple hashmaps?
149149
150150When we read code, we can use our mental model of variables and scopes to see how each variable is unique.
151- We just have apply that knowledge to our data structure.
152- In practice we can assign each variable two indices that make it unique and give it a defined location in memory:
151+ We just have to apply that knowledge to our data structure.
152+ In practice, we can assign each variable two indices that make it unique and give it a defined location in memory:
153153
154154- ` scope index ` : The index of the scope that the variable is declared in.
155- - ` variable index ` : The index of the variable in it's scope.
155+ - ` variable index ` : The index of the variable in its scope.
156156
157157Let's visualize this in an example:
158158
@@ -196,12 +196,12 @@ struct Scope {
196196}
197197```
198198
199- Instead of having a self referential data structure, we now have a two dimensional array.
199+ Instead of having a self- referential data structure, we now have a two- dimensional array.
200200
201201While this is our runtime data structure, we still have to calculate the variable indices before running the code.
202202For that we can use our previous approach with some slight modifications.
203- Instead of storing the value of the variable, we just store it's index.
204- Additionally we store an index in every scope to easily access our scope indices:
203+ Instead of storing the value of the variable, we just store its index.
204+ Additionally, we store an index in every scope to easily access our scope indices:
205205
206206``` rust
207207struct Scope {
@@ -215,7 +215,7 @@ struct Variable {
215215}
216216```
217217
218- While this data structure still works based on self referential hashmaps, we only need it before running code.
218+ While this data structure still works based on self- referential hashmaps, we only need it before running code.
219219Instead of doing a lookup on every variable access at runtime, we just have to do it once.
220220
221221## Local Variables
@@ -233,18 +233,18 @@ function addOne(a) {
233233addOne (2 );
234234```
235235
236- Currently we store ` a ` and ` one ` in our scopes and access them when performing the addition.
236+ Currently, we store ` a ` and ` one ` in our scopes and access them when performing the addition.
237237But why do we need the special data structure for variables and scopes at all?
238238What if we could just store the variables directly where we need them?
239239
240240A typical ECMAScript engine uses a virtual machine (VM) to execute your code.
241241VMs use dedicated memory for values they operate on; a stack or registers.
242- For the purpose of this post, we use registers but the stack would work in the same way.
242+ For the purpose of this post, we use registers, but the stack would work in the same way.
243243Let's try to use registers to store variables.
244244While compiling the ECMAScript code into operations for our VM we assign each variable to a register.
245245Then we modify our variable operations to use registers instead of scopes to access variables.
246246
247- When we test our example from above, it works fine with this changes.
247+ When we test our example from above, it works fine with these changes.
248248Let's write down what exactly happens:
249249
2502501 . The function ` addOne ` is called. Registers for ` a ` and ` one ` are allocated.
@@ -297,8 +297,8 @@ To determine which variables can be stored in registers, we analyze them prior t
297297We can reuse our previously established scope structure based on hashmaps.
298298It just needs some additional information to make our analysis work.
299299Each scope needs to be flagged to indicate if it is a function scope.
300- This is important, because we have to track if a variable is every accessed from a nested function.
301- Additionally each variable needs a flag to indicate if it can be a local variable.
300+ This is important, because we have to track if a variable is ever accessed from a nested function.
301+ Additionally, each variable needs a flag to indicate if it can be a local variable.
302302
303303Our adjusted scope structure looks like this:
304304
@@ -390,7 +390,7 @@ When we encounter a variable that cannot be local, we use or old VM operations f
390390### Other Exceptions
391391
392392There are some more situations that prevent us from using local variables.
393- We have to account for every case where a variable might be accessed from outside it's function.
393+ We have to account for every case where a variable might be accessed from outside its function.
394394Without going into detail on each of these cases, we can find all of them via scope analysis.
395395
396396Here is a quick overview:
@@ -451,7 +451,7 @@ Here is a quick overview:
451451
452452 In the first loop execution ` a1` is the variable.
453453 In the second loop execution ` a1` is the object property.
454- As a result of this behavior, every variable accessed inside of a ` with` statement cannot be local.
454+ As a result of this behavior, every variable accessed inside a ` with` statement cannot be local.
455455
456456## Conclusion
457457
0 commit comments