Skip to content

Commit 38b59eb

Browse files
committed
Minor grammer fixes
1 parent 7b0aab2 commit 38b59eb

File tree

1 file changed

+21
-21
lines changed

1 file changed

+21
-21
lines changed

blog/2024-10-01-local-variables.md

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ authors: boa-dev
77

88
In this post we dive into how ECMAScript engines store variables.
99
We 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.
1111
If 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

6262
In 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.
6464
This is because scopes are nested.
6565
When we cannot find a variable in the current scope, we look for the same identifier in the outer scope.
6666
In 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
9191
You can see that variables are tied to their scopes.
9292
All three variables `a` never change their values.
9393
They 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

9696
You can see that in addition to blocks, functions also have scopes.
9797
There are some more details to function scopes and how `let`, `const` and `var` differ.
@@ -118,10 +118,10 @@ struct Scope {
118118
```
119119

120120
This 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

123123
Let'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
127127
struct Scope {
@@ -138,7 +138,7 @@ This was the approach we used in Boa before we switched to a different implement
138138

139139
You may already have spotted some performance issues with this data structure.
140140
Consider 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.
142142
With this current data structure we have to perform at least one hashmap lookup per variable access.
143143
Most hashmap implementations will incur significant cost compared to accessing a fixed location in memory.
144144
This 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?
148148
Can you find a way to locate each variable without accessing multiple hashmaps?
149149

150150
When 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

157157
Let'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

201201
While this is our runtime data structure, we still have to calculate the variable indices before running the code.
202202
For 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
207207
struct 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.
219219
Instead 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) {
233233
addOne(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.
237237
But why do we need the special data structure for variables and scopes at all?
238238
What if we could just store the variables directly where we need them?
239239

240240
A typical ECMAScript engine uses a virtual machine (VM) to execute your code.
241241
VMs 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.
243243
Let's try to use registers to store variables.
244244
While compiling the ECMAScript code into operations for our VM we assign each variable to a register.
245245
Then 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.
248248
Let's write down what exactly happens:
249249

250250
1. 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
297297
We can reuse our previously established scope structure based on hashmaps.
298298
It just needs some additional information to make our analysis work.
299299
Each 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

303303
Our 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

392392
There 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.
394394
Without going into detail on each of these cases, we can find all of them via scope analysis.
395395

396396
Here 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

Comments
 (0)