90 lines
4.8 KiB
Markdown
90 lines
4.8 KiB
Markdown
---
|
|
layout: news
|
|
author: Torsten
|
|
---
|
|
|
|
As i said in the last post, a step back and forward, possibly two, was taken and understanding
|
|
grows again. Especially when i think that some way is the way, it always changes and i turn out
|
|
to be at least partially wrong. The way of life, of imperfect intelligence, to strive for that
|
|
perfection that is forever out of reach. Here's the next installment.
|
|
|
|
## Slopes and Ramps
|
|
|
|
When thinking about method caching and how to implement it i came across this thing that i will
|
|
call a Slope for now. The Slope of a function that is. At least that's where the thought started.
|
|
|
|
The Slope of a function is a piece of code that has two main properties:
|
|
|
|
- it is straight, up to the end. i mean it has no branches from the outside.
|
|
It may have internally but that does not affect anything.
|
|
- it ends in a branch that returns (a call), but this is not part of the Slope
|
|
|
|
Those *two* properties would better be called a Ramp. The Ramp the function goes along before it
|
|
jumps of to the next function.
|
|
|
|
The **Slope** is the part before the jump. So a Ramp is a Slope and a Jump.
|
|
|
|
Code in the Slope, it struck me, has the unique possibility of doing a jump, with out worrying about
|
|
returning. After all, it knows there is a call coming. After contemplating this a little i
|
|
found the flaw, which one understands when thinking about where the function returns to. So Slope
|
|
can jump away without caring if (and only if) the return address is set to after that jump (and the
|
|
address is actually set by the code before the jump).
|
|
|
|
Remembering that we set the return address in the caller (not as in c the callee) we can arrange
|
|
for that. And so we can write Slope code that just keeps going. Because once the return address
|
|
is set up, the code can just keep jumping forward. The only thing is that the call must come.
|
|
|
|
In more concrete terms: Method caching can be a series of checks and jumps. If the check is ok
|
|
we call, otherwise jump on. And even the last fail (the switches default case) can be a jump
|
|
to what we would otherwise call a method. A method that determines the real jump target from
|
|
the type (of self, in the message) and calls it. Except it's not a method because it never
|
|
returns, which is symmetrically to us not calling it.
|
|
|
|
So this kind of "method" which is not really a method, but still a fair bit of logic, i'll call
|
|
a Slope.
|
|
|
|
## Links and Chains
|
|
|
|
A Slope, the story continues, is really just a specific case of something else. If we take away
|
|
the expectation that a call is coming, we are left with a sequence of code with jumps to more
|
|
code. This could be called a Chain, and each part of the Chain would be a Link.
|
|
|
|
To define that: a **Link** is sequence of code that ends in a jump. It has no other jumps, just
|
|
the one at the end. And the jump at the end jumps to another Link.
|
|
|
|
The Code i am talking about here is risc level code, one could say assembler instructions.
|
|
|
|
The concept though is very familiar: at a higher level the Link would be a Statement and a
|
|
Chain a sequence of Statements. We're missing the branch abstraction yet, but otherwise this is
|
|
a lower level description of code in a similar way as the typed level Code and Statements are
|
|
a description of higher level code.
|
|
|
|
## Typed level is wrong
|
|
|
|
The level that is nowadays called Typed, and used to be soml, is basically made up of language
|
|
constructs. It does not allow for manipulation of the risc level. As the ruby level is translated
|
|
to the typed level, which in turn is translated to the risc level, the ruby compiler has no
|
|
way of manipulating the risc level. This is as it should be.
|
|
|
|
The problem is just, that the constructs that are currently at the typed level, do not allow
|
|
to express the results needed at the risc level.
|
|
|
|
Through the history of the development the levels have become mixed up. It is relatively clear at
|
|
the ruby level what kind of construct is needed at the risc level. This is what has to drive the
|
|
constructs at the typed level. We need access to these kinds of Slope or Link ideas at the ruby
|
|
level.
|
|
|
|
Another way of looking at the typed level inadequacies is the size of the codes generated. Some of
|
|
the expressions (or statements) resolve to 2 or 3 risc instructions. Others, like the call, are
|
|
15. This is an indication that part of the level is wrong. A good way to architect the layers
|
|
would result in an *even* expansion of the amount of code at every level.
|
|
|
|
## Too little testing
|
|
|
|
The ruby compiler should really drive the development more. The syntax and behavior of ruby are
|
|
quite clear, and i feel the risc layer is quite a solid target. So before removing too much or
|
|
rewriting too much i shall just add more (and more) functionality to the typed layer.
|
|
|
|
At the same time some of the concepts (like a method call) will probably not find any use, but
|
|
as long as they don't harm, i shall leave them lying around.
|