-
Notifications
You must be signed in to change notification settings - Fork 2
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # 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