jotting ideas
This commit is contained in:
parent
531cfdd7eb
commit
933e256774
77
2015-05-20-expression_is_slot.md
Normal file
77
2015-05-20-expression_is_slot.md
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
---
|
||||||
|
layout: site
|
||||||
|
author: Torsten
|
||||||
|
---
|
||||||
|
|
||||||
|
Since i got the ideas of Slots and the associated instruction Set, i have been wondering how that
|
||||||
|
fits in with the code generation.
|
||||||
|
|
||||||
|
I moved the patched AST compiler methods to a Compiler, ok. But still what do all those compile
|
||||||
|
methods return.
|
||||||
|
|
||||||
|
## Expression
|
||||||
|
|
||||||
|
In ruby, everything is an expression. To recap "Expressions have a value, while statements do not",
|
||||||
|
or statements represent actions while expressions represent values.
|
||||||
|
|
||||||
|
So in ruby everything represents a value, also statements, or functions. There is no such thing
|
||||||
|
as the return void in C. Even loops and ifs result in a value, for a loop the last computed value
|
||||||
|
and for an if the value of the branch taken.
|
||||||
|
|
||||||
|
Having had a vague grasp of this concept i tried to sort of haphazardly return the kind of value
|
||||||
|
that i though appropriate. Sometimes literals, sometimes slots. Sometimes "Return" , a slot
|
||||||
|
representing the return value of a function.
|
||||||
|
|
||||||
|
## Return slot
|
||||||
|
|
||||||
|
Today i realized that the Slot representing the return value is special.
|
||||||
|
|
||||||
|
It does not hold the value that is returned, but rather the other way around.
|
||||||
|
|
||||||
|
A function returns what is in the Return slot, at the time of return.
|
||||||
|
|
||||||
|
From there it is easy to see that it must be the Return that holds the last computed value.
|
||||||
|
A function can return at any time after all.
|
||||||
|
|
||||||
|
The last computed value is the Expression that is currently evaluated. So the compile, which
|
||||||
|
initiates the evaluation, returns the Return slot. Always. Easy, simple, nice!
|
||||||
|
|
||||||
|
## Example
|
||||||
|
|
||||||
|
Constants: say the expression
|
||||||
|
|
||||||
|
true
|
||||||
|
|
||||||
|
would compile to a
|
||||||
|
|
||||||
|
ConstantLoad(ReturnSlot , TrueConstant)
|
||||||
|
|
||||||
|
While
|
||||||
|
|
||||||
|
2 + 4
|
||||||
|
|
||||||
|
would compile to
|
||||||
|
|
||||||
|
ConstantLoad(ReturnSlot , IntegerConstant(2))
|
||||||
|
Set(ReturnSlot , OtherSlot)
|
||||||
|
ConstantLoad(ReturnSlot , IntegerConstant(4))
|
||||||
|
Set(ReturnSlot , EvenOtherSlot)
|
||||||
|
MethodCall() # unspecified details here
|
||||||
|
|
||||||
|
|
||||||
|
## Optimisations
|
||||||
|
|
||||||
|
But but but i hear that is so totally inefficient. All the time we move data around, to and from
|
||||||
|
that one Return slot, just so that the return is simple. Yes but no.
|
||||||
|
|
||||||
|
It is very easy to optimize the trivial extra away. Many times the expression moves a value to Return
|
||||||
|
just to move it away in the next Instruction. A sequence like in above example
|
||||||
|
|
||||||
|
ConstantLoad(ReturnSlot , IntegerConstant(2))
|
||||||
|
Set(ReturnSlot , OtherSlot)
|
||||||
|
|
||||||
|
can easily be optimized into
|
||||||
|
|
||||||
|
ConstantLoad(OtherSlot , IntegerConstant(2))
|
||||||
|
|
||||||
|
tbc
|
43
2015-06-20-closing-the-chasm.md
Normal file
43
2015-06-20-closing-the-chasm.md
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
---
|
||||||
|
layout: site
|
||||||
|
author: Torsten
|
||||||
|
---
|
||||||
|
|
||||||
|
As noted in previous posts, differentiating between compile- and run-time is one of the more
|
||||||
|
difficult things in doing the vm. That is because the computing that needs to happen is so similar,
|
||||||
|
in other words almost all of the vm - level is available at run-time too.
|
||||||
|
|
||||||
|
But off course we try to do as much as posible at compile-time.
|
||||||
|
|
||||||
|
One hears or reads that exactly this is a topic causing (also) other vms problems.
|
||||||
|
Specifically how one assures that what is compiled at compile-time and and run-time are
|
||||||
|
identical or at least compatible.
|
||||||
|
|
||||||
|
The obvious answer seems to me to **use the same code**.In a way that "just" moves the question
|
||||||
|
around a bit, becuase then one would have to know how to do that. I'll go into that below,
|
||||||
|
but find that the concept is worth exploring first.
|
||||||
|
|
||||||
|
Let's take a simple example of accessing an instance variable. This is off course available at
|
||||||
|
run-time through the function *instance_variable_get* , which could go something like:
|
||||||
|
|
||||||
|
def instance_variable_get name
|
||||||
|
index = @layout.index name
|
||||||
|
return nil unless index
|
||||||
|
at_index(index)
|
||||||
|
end
|
||||||
|
|
||||||
|
Let's assume the *builtin* at_index function and take the layout to be an array like structure.
|
||||||
|
As noted in previous posts, when this is compiled we get a Method with Blocks, and exactly one
|
||||||
|
Block will initiate the return. The previous post detailed how at that time the return value will
|
||||||
|
be in the ReturnSlot.
|
||||||
|
|
||||||
|
So then we get to the idea of how: We "just" need to take the blocks from the method and paste
|
||||||
|
them where the instance variable is accessed. Following code will pick the value from the ReturnSlot
|
||||||
|
as it would any other value and continue.
|
||||||
|
|
||||||
|
The only glitch in this plan is that the code will assume a new message and frame. But if we just
|
||||||
|
paste it it will use message/frame/self from the enclosing method. So that is where the work is:
|
||||||
|
translating slots from the inner, inlined fuction to the outer one. Possibly creating new frame
|
||||||
|
entries.
|
||||||
|
|
||||||
|
tbc
|
Loading…
Reference in New Issue
Block a user