2014-08-22 16:27:57 +02:00
|
|
|
Register Machine
|
2014-04-25 12:29:12 +02:00
|
|
|
===============
|
|
|
|
|
2014-08-28 18:12:46 +02:00
|
|
|
This is the logic that uses the compiled virtual object space to produce code and an executable binary.
|
2014-04-25 12:29:12 +02:00
|
|
|
|
2014-08-28 21:32:53 +02:00
|
|
|
There is a mechanism for an actual machine (derived class) to generate harware specific instructions (as the
|
2014-08-28 18:12:46 +02:00
|
|
|
plain ones in this directory don't assemble to binary). Currently there is only the Arm module to actually do
|
|
|
|
that.
|
2014-04-25 12:29:12 +02:00
|
|
|
|
2014-08-28 18:12:46 +02:00
|
|
|
The elf module is used to generate the actual binary from the final BootSpace. BootSpace is a virtual class representing
|
|
|
|
all objects that will be in the executable. Other than CompiledMethods, objects get transformed to data.
|
2014-05-25 09:57:56 +02:00
|
|
|
|
2014-08-28 18:12:46 +02:00
|
|
|
But CompiledMethods, which are made up of Blocks, are compiled into a stream of bytes, which are the binary code for the
|
|
|
|
function.
|
2014-05-25 09:57:56 +02:00
|
|
|
|
2014-08-28 18:12:46 +02:00
|
|
|
Virtual Objects
|
|
|
|
----------------
|
2014-05-25 09:57:56 +02:00
|
|
|
|
2014-08-28 18:12:46 +02:00
|
|
|
There are four virtual objects that are accessible (we can access their variables):
|
2014-05-25 09:57:56 +02:00
|
|
|
|
2014-08-28 18:12:46 +02:00
|
|
|
- Self
|
|
|
|
- Message (arguments, method name, self)
|
|
|
|
- Frame (local and tmp variables)
|
|
|
|
- NewMessage ( to build the next message sent)
|
2014-05-25 09:57:56 +02:00
|
|
|
|
2015-03-25 16:29:39 +01:00
|
|
|
These are pretty much the first four registers. When the code goes from virtual to register,
|
|
|
|
we use register instructions to replace virtual ones.
|
2014-05-25 09:57:56 +02:00
|
|
|
|
2015-03-25 16:29:39 +01:00
|
|
|
Eg: A Virtual::Set can move data around inside those objects.
|
|
|
|
And since in Arm this can not be done in one instruction, we use two, one to move to an unused register
|
|
|
|
and then into the destination. And then we need some fiddling of bits to shift the type info.
|
2014-05-25 09:57:56 +02:00
|
|
|
|
2015-03-25 16:29:39 +01:00
|
|
|
Another simple example is a Call. A simple case of a Class function call resolves the class object,
|
|
|
|
and with the method name the function to be found at compile-time.
|
|
|
|
And so this results in a Register::Call, which is an Arm instruction.
|
2014-05-25 09:57:56 +02:00
|
|
|
|
2014-08-28 18:12:46 +02:00
|
|
|
A C call
|
|
|
|
---------
|
|
|
|
|
2015-03-25 16:29:39 +01:00
|
|
|
Ok, there are no c calls. But syscalls are very similar.
|
|
|
|
This is not at all as simple as the nice Class call described above.
|
2014-08-28 18:12:46 +02:00
|
|
|
|
2015-03-25 16:29:39 +01:00
|
|
|
For syscall in Arm (linux) you have to load registers 0-x (depending on call), load R7 with the
|
|
|
|
syscall number and then issue the software interupt instruction.
|
|
|
|
If you get back something back, it's in R0.
|
2014-08-28 18:12:46 +02:00
|
|
|
|
2015-03-25 16:29:39 +01:00
|
|
|
In short, lots of shuffling. And to make it fit with our four object architecture,
|
|
|
|
we need the Message to hold the data for the call and Sys (module) to be self.
|
|
|
|
And then the actual functions do the shuffle, saving the data and restoring it.
|
2014-08-28 18:12:46 +02:00
|
|
|
And setting type information according to kernel documentation (as there is no runtime info)
|