-
Notifications
You must be signed in to change notification settings - Fork 2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Global variables are now loaded from _ENV. #11
Conversation
Can you benchmark a couple of programs that do simple global read/writes before/after this PR? |
I have a hunch that programs before this PR are slightly faster, but only because I implemented globals without considering _ENV. But yes, I can try to create a few programs, and benchmark the interpreter on them! |
aafb8f0
to
8261df0
Compare
8261df0
to
2fe812c
Compare
I would like to merge this PR before writing any benchmarks. I am going to implement functions and loops first, and then come back to optimizing the |
98e3941
to
6a8d0f7
Compare
As an extra example, Example program: x = 2 -- equivalent to _ENV["x"] = 2 The compiler generates the following bytecode:
and the tables:
Every The VM only executes |
I guess I was expecting something more like "GLOBAL_ASSIGN 0 2" where "0" == "print" and "1" is register 1 (which, presumably, holds the value 1). However, this is something we can optimise / change later. |
I see what you mean. That might speed things up, and the changes should be easy to make even later on. |
@@ -1,5 +1,8 @@ | |||
use std::{collections::HashMap, vec::Vec}; | |||
|
|||
/// The register in which `_ENV` lives. | |||
pub const ENV_REG: usize = 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it worth using up a register for ENV? We could stick it in a special variable inside the VM?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would say yes, because most of the time you use functions from the standard library. I could introduce new instructions such as GET/SET_ENV
, or have a special instruction which loads the _ENV
into a variable, and then use GET/SET_ATTR
on the register which has _ENV
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes to which question?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh sorry, yes to the first question. I think I am starting to see your point. But if I special case _ENV
, that means that I will need special instructions as well, which will have _ENV
as an implicit argument.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed. Let's leave that to a later PR.
luavm/src/lib/instructions/tables.rs
Outdated
let from = &vm.registers[arg2]; | ||
let attr = &vm.registers[third_arg(instr) as usize]; | ||
match attr.get_constant_index() { | ||
Some(i) if arg2 == ENV_REG => vm.env_attrs[i].clone(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It feels a bit weird that nothing in the if
arm references the left hand-side. The logic feels sort of inside-out to me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see a reason why it should. The left hand-side is the register in which the value is copied. I am only interested to see if the value comes from _ENV
or not. Either way, the value is copied here in the left hand-side. I hope I am not misunderstanding your comment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What I mean is that the logic here feels like it should be something like:
if arg2 == ENV_REG {
if let Some(i) = attr.get_constant_index() {
...
}
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh I see, but then I would only be able to write this:
if arg2 == ENV_REG {
if let Some(i) = attr.get_constant_index() {
vm.env_attrs[i].clone()
} else {
from.get_attr(attr)?
}
} else {
from.get_attr(attr)?
}
I prefer my initial solution, but this might be slightly more efficient and more readable?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I saw this merged, but I don't think it is part of stable. At least it doesn't work on rust playground (I made sure to check rust 2018).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe:
match attr.get_constant_index() {
Some(i) => if arg2 == ENV_REG { vm.env_attrs[i].clone() } else { from.get_attr(attr)? }
None => ...
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will duplicate from.get_attr(attr)?
this way. Is that fine?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Your call. It feels clearer to me, but I don't feel strongly about it.
luavm/src/lib/instructions/tables.rs
Outdated
let val = vm.registers[third_arg(instr) as usize].clone(); | ||
let arg1 = first_arg(instr) as usize; | ||
match attr.get_constant_index() { | ||
Some(i) if arg1 == ENV_REG => vm.env_attrs[i] = val, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same comment as above.
Ready for another review! |
In the Lua specification, the global variables are loaded from a global table called `_ENV`. Programs can overwrite this variable as well, and can read and write from/to it. There are a few changes: * The compiler: * assumes that `_ENV` is always stored in register 0 * replaces all global variable writing, and reading with `GetAttr`, and `SetAttr` instructions * The vm: * always creates a `LuaTable` and stores it in register 0, so that globals can be easily accessed. * can now set and get attributes of `LuaTable`s
Please squash. |
ee8361c
to
0ec46ba
Compare
Squashed! |
In the Lua specification, the global variables are loaded from a global
table called
_ENV
. Programs can overwrite this variable as well, andcan read and write from/to it.
There are a few changes:
_ENV
is always stored in register 0GetAttr
, andSetAttr
instructionsLuaTable
and stores it in register 0, so that globalscan be easily accessed.
LuaTable
s