2017-08-29 17:38:51 +02:00
|
|
|
[![Build Status](https://travis-ci.org/ruby-x/rubyx.svg?branch=master)](https://travis-ci.org/ruby-x/rubyx)
|
2017-01-01 23:47:11 +01:00
|
|
|
[![Code Climate](https://codeclimate.com/github/ruby-x/rubyx/badges/gpa.svg)](https://codeclimate.com/github/ruby-x/rubyx)
|
|
|
|
[![Test Coverage](https://codeclimate.com/github/ruby-x/rubyx/badges/coverage.svg)](https://codeclimate.com/github/ruby-x/rubyx)
|
2014-05-30 13:49:34 +02:00
|
|
|
|
2017-01-01 23:29:20 +01:00
|
|
|
# RubyX
|
2014-04-14 14:51:44 +02:00
|
|
|
|
2017-01-01 23:47:11 +01:00
|
|
|
RubyX is about native code generation in and of ruby.
|
2018-03-20 11:10:22 +01:00
|
|
|
In other words, compiling ruby to binary, in ruby.
|
2017-01-01 23:47:11 +01:00
|
|
|
|
2018-07-07 16:34:08 +02:00
|
|
|
X can be read as X times faster, or a decade away, depending on mindset.
|
2014-04-14 15:46:17 +02:00
|
|
|
|
2018-07-07 16:34:08 +02:00
|
|
|
The last rewrite clarified the roles of the different layers
|
|
|
|
of the system, see below. The overhaul is done and rubyx produces working binaries.
|
2015-03-15 12:58:17 +01:00
|
|
|
|
2018-03-20 11:10:22 +01:00
|
|
|
Processing goes through layers: Ruby --> Vool --> Mom --> Risc --> Arm --> binary .
|
2017-01-01 23:47:11 +01:00
|
|
|
|
2018-08-14 10:23:19 +02:00
|
|
|
Currently most basic constructs work to some (usable) degree, ie if, while,
|
|
|
|
assignment, ivars, calling and dynamic dispatch all work. Simple blocks, those
|
|
|
|
that ruby passes implicitly also work (lambdas not).
|
|
|
|
|
|
|
|
Work continues on memory management, which turns out to be pretty basic to do just about
|
|
|
|
anything, even counting to a million.
|
2015-03-15 12:58:17 +01:00
|
|
|
|
2018-03-20 11:10:22 +01:00
|
|
|
## Layers
|
2015-03-15 12:58:17 +01:00
|
|
|
|
2018-03-20 11:10:22 +01:00
|
|
|
### Ruby
|
2015-11-30 19:25:17 +01:00
|
|
|
|
2018-07-25 10:08:39 +02:00
|
|
|
Ruby is input layer, we use whitequarks parser to parse ruby. The untyped ast is then
|
|
|
|
transformed into a typed version. The classes and fields follow the ast output pretty
|
|
|
|
much one to one. The we transform to Vool, removing much of ruby's "fluff".
|
2015-11-30 19:25:17 +01:00
|
|
|
|
2018-03-20 11:10:22 +01:00
|
|
|
### Vool
|
2015-11-30 19:25:17 +01:00
|
|
|
|
2018-03-20 11:10:22 +01:00
|
|
|
Vool is a Virtual Object Oriented Language. Virtual in that is has no own syntax. But
|
|
|
|
it has semantics, and those are substantially simpler than ruby.
|
2015-11-30 19:25:17 +01:00
|
|
|
|
2018-03-20 11:10:22 +01:00
|
|
|
Vool is Ruby without the fluff. No unless, no reverse if/while, no splats. Just simple
|
|
|
|
oo. (Without this level the step down to the next layer was just too big)
|
2015-11-30 19:25:17 +01:00
|
|
|
|
2018-03-20 11:10:22 +01:00
|
|
|
|
|
|
|
### Mom
|
|
|
|
|
|
|
|
The Minimal Object Machine layer is the first machine layer. This means it has instructions
|
|
|
|
rather than statements. Instructions (in all machine layers) are a linked list.
|
|
|
|
|
|
|
|
Mom has no concept of memory yet, only objects. Data is transferred directly from object
|
|
|
|
to object with one of Mom's main instructions, the SlotLoad.
|
|
|
|
|
|
|
|
Mainly Mom is an easy to understand step on the way down. A mix of oo and machine. In
|
|
|
|
practise it means that the amount of instructions that need to be generated in vool
|
|
|
|
is much smaller (easier to understand) and the mapping down to risc is quite straightforward.
|
|
|
|
|
2018-03-20 11:22:16 +01:00
|
|
|
### Risc
|
2018-03-20 11:10:22 +01:00
|
|
|
|
|
|
|
The risc cpu architecture approach was a simplification of the cpu instruction set to a
|
2018-07-25 10:08:39 +02:00
|
|
|
minimum. Arm, our main target, is a risc architecture, and much like Vool uncrinkles
|
|
|
|
Ruby, the Risc layer simplifies ARM.
|
2018-03-20 11:10:22 +01:00
|
|
|
|
2018-03-20 11:22:16 +01:00
|
|
|
The Risc layer here abstracts the Arm in a minimal and independent way. It does not model
|
|
|
|
any real RISC cpu instruction set, but rather implements what is needed for rubyx.
|
2018-03-20 11:10:22 +01:00
|
|
|
|
|
|
|
Instructions are derived from a base class, so the instruction set is extensible. This
|
2018-03-20 11:22:16 +01:00
|
|
|
way additional functionality may be added by external code.
|
2018-03-20 11:10:22 +01:00
|
|
|
|
|
|
|
Risc knows memory and has a small set of registers. It allows memory to register transfer
|
2018-07-25 10:08:39 +02:00
|
|
|
and back, and inter register transfer. But has no memory to memory transfer like Mom.
|
2018-03-20 11:10:22 +01:00
|
|
|
|
|
|
|
### Arm
|
|
|
|
|
|
|
|
There is a minimal Arm assembler that transforms Risc instructions to Arm instructions.
|
|
|
|
This is mostly a one to one mapping, though it does introduce the quirks that ARM has
|
|
|
|
and that were left out of the Risc layer.
|
|
|
|
|
|
|
|
### Elf
|
|
|
|
|
|
|
|
Arm instructions assemble themselves into binary code. A minimal Elf implementation is
|
|
|
|
able to create executable binaries from the assembled code and Parfait objects.
|
|
|
|
|
|
|
|
### Parfait
|
|
|
|
|
|
|
|
Generating code (by descending above layers) is only half the story in an oo system.
|
|
|
|
The other half is classes, types, constant objects and a minimal run-time. This is
|
|
|
|
what is Parfait is.
|
|
|
|
|
2018-07-07 16:34:08 +02:00
|
|
|
Parfait has basic clases like string/array/hash, and also anything that is really needed
|
|
|
|
to express code, ie Class/Type/Method/Block.
|
|
|
|
|
|
|
|
Parfait is used at compile time, and the objects get serialised into the executable to
|
|
|
|
make up, or make up the executable, and are thus available at run time. Currently the
|
|
|
|
methods are not parsed yet, so do not exist at runtime yet.
|
|
|
|
|
|
|
|
### Builtin
|
|
|
|
|
|
|
|
There are a small number of methods that can not be coded in ruby. For example an
|
|
|
|
integer addition, or a instance variable access. These methods exists in any compiler,
|
|
|
|
and are called builtin here.
|
|
|
|
|
|
|
|
Builtin methods are coded at the risc level with a dsl. Even though basically assembler,
|
2018-07-25 10:08:39 +02:00
|
|
|
they are
|
|
|
|
([quite readable](https://github.com/ruby-x/rubyx/blob/2f07cc34f3f56c72d05c7d822f40fa6c15fd6a08/lib/risc/builtin/object.rb#L48))
|
|
|
|
through the ruby magic.
|
2018-07-07 16:34:08 +02:00
|
|
|
|
2018-03-20 11:10:22 +01:00
|
|
|
## Types and classes, static vs dynamic
|
|
|
|
|
2018-07-07 16:34:08 +02:00
|
|
|
Classes in dynamic languages are open. They can change at any time, meaning you can
|
|
|
|
add/remove methods and use any instance variable. This is the reason dynamic
|
|
|
|
languages are interpreted.
|
2018-03-20 11:10:22 +01:00
|
|
|
|
|
|
|
For Types to make any sense, they have to be static, immutable.
|
|
|
|
|
|
|
|
Some people have equated Classes with Types, this is a basic mistake in dynamic languages.
|
|
|
|
|
|
|
|
In rubyx a Type implements a Class (at a certain time of that classes lifetime). It
|
|
|
|
defines the methods and instance variables available. This is key to generating
|
|
|
|
efficient code that uses type information to access instance variables.
|
|
|
|
|
|
|
|
When a class changes, say a new method is added that uses a new instance variable, a
|
|
|
|
**new** Type is generated to describe the class at that point. **New** code is generated
|
|
|
|
for this new Type.
|
|
|
|
|
2018-07-07 16:34:08 +02:00
|
|
|
In essence the Class always **has a** current Type and **many** Types implement (different versions of) a Class.
|
2018-03-20 11:10:22 +01:00
|
|
|
|
2018-03-20 11:22:16 +01:00
|
|
|
All Objects have a Type, as their first member (also integers!). The Type points to the
|
|
|
|
Class that the object has in oo terms.
|
2018-03-20 11:10:22 +01:00
|
|
|
|
|
|
|
Classes are defined by ruby code, but the methods of a Type (that are executed) are defined
|
|
|
|
by Mom and Risc only.
|
|
|
|
|
|
|
|
## Other
|
2015-10-07 10:32:48 +02:00
|
|
|
|
|
|
|
### Interpreter
|
|
|
|
|
|
|
|
After doing some debugging on the generated binaries i opted to write an interpreter for the
|
2018-03-20 11:22:16 +01:00
|
|
|
risc layer. That way tests run on the interpreter reveal most issues.
|
2015-10-07 10:32:48 +02:00
|
|
|
|
|
|
|
### Debugger
|
|
|
|
|
2017-08-29 17:38:51 +02:00
|
|
|
And after the interpreter was done, i wrote a [visual debugger](https://github.com/ruby-x/rubyx-debugger).
|
2018-03-20 11:22:16 +01:00
|
|
|
It is a simple opal application that nevertheless has proven a great help, both in figuring
|
|
|
|
out what is going on, and in finding bugs.
|
2015-05-17 19:07:52 +02:00
|
|
|
|
2015-10-07 10:32:48 +02:00
|
|
|
## Status
|
2015-05-17 19:07:52 +02:00
|
|
|
|
2018-07-07 16:34:08 +02:00
|
|
|
The above architecture is implemented. At the top level the RubyXCompiler works
|
|
|
|
pretty much as you'd expect, by falling down the layers. And when it get's
|
|
|
|
to the Risc layer it slots the builtin in there as if is were just normal code.
|
|
|
|
|
|
|
|
Specifically here is a list of what works:
|
|
|
|
- if (with or without else)
|
|
|
|
- while
|
|
|
|
- return
|
|
|
|
- assignment (local/args/ivar)
|
|
|
|
- static calling (where method is determined at compile time)
|
|
|
|
- dynamic dispatch with caching
|
2018-08-14 10:23:19 +02:00
|
|
|
- implicit blocks, ie the ones that ruby passes implicitly and are used in enumerating
|
2018-07-07 16:34:08 +02:00
|
|
|
|
|
|
|
|
2018-07-25 10:08:39 +02:00
|
|
|
## Contributing to rubyx
|
|
|
|
|
|
|
|
Probably best to talk to me, if it's not a typo or so.
|
|
|
|
|
2018-08-14 10:23:19 +02:00
|
|
|
I've started to put some github issues out, some basic some not so. Also there is a todo
|
|
|
|
for the adventurous (bigger things, no BIG things).
|
2014-05-30 13:49:34 +02:00
|
|
|
|
2018-08-14 10:23:19 +02:00
|
|
|
Actual tasks that result in pulls, should start their life as a github issue.
|
|
|
|
There we can discuss details so that no work is done
|
|
|
|
in vain. If you're interested in an existing issues, just comment on it.
|
2014-05-30 13:49:34 +02:00
|
|
|
|
2018-08-14 10:23:19 +02:00
|
|
|
Fork and create a branch before sending pulls.
|
2014-05-30 13:49:34 +02:00
|
|
|
|
2018-07-25 10:08:39 +02:00
|
|
|
## Copyright
|
2014-04-14 15:46:17 +02:00
|
|
|
|
2018-03-20 11:22:16 +01:00
|
|
|
Copyright (c) 2014-8 Torsten Ruger.
|
|
|
|
|
2015-11-30 19:25:17 +01:00
|
|
|
See LICENSE.txt for further details.
|