Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Merge stuff between cpp's README and master's, merge -C++ and -DEVELO…

…PERS
  • Loading branch information...
commit 504682ab96f65f86176e5c5ff5ad4e183cfa4621 1 parent 22bc836
@drbrain drbrain authored
Showing with 381 additions and 263 deletions.
  1. +20 −7 README
  2. +361 −256 README-DEVELOPERS
View
27 README
@@ -1,8 +1,9 @@
1. What is Rubinius
-Rubinius is a next-generation virtual machine and compiler for Ruby. Based
-loosely on the Smalltalk-80 'Blue Book' design, Rubinius will provide a rich,
-high-performance environment for running Ruby code.
+Rubinius is an execution environment for the Ruby programming language.
+It is comprised of three major pieces: a compiler, a 'kernel' (otherwise
+known as the Ruby Core Library), and a virtual machine.
+The project's goal is to create a top-of-the-line Ruby implementation.
2. Running Rubinius
@@ -10,10 +11,13 @@ Refer to the INSTALL file for instructions on getting and building Rubinius.
3. Status
-Rubinius is under heavy development, and currently supports the basic Ruby
-classes and kernel methods. The code base is written in a mixture of ANSI C and
-Ruby; with more Ruby and less C as the project proceeds. You should not run
-your mission-critical Rails apps under Rubinius yet.
+Rubinius is under heavy development and currently supports the core Ruby
+classes and kernel methods. The majority of the existing Ruby libraries
+should run without modification. If your MRI 1.8.6-compatible code does not
+run under Rubinius, please open a bug ticket.
+
+As Rubinius becomes more and more compatible with Ruby 1.8, the development
+effort is shifting toward performance, rather than completeness.
4. Goals
@@ -35,3 +39,12 @@ support. One possible way to help is implement Ruby library classes. Visit
http://rubinius.lighthouseapp.com for documentation on how to begin hacking
Rubinius.
+6. Architecture
+
+While most of the Rubinius features are implemented in Ruby, the VM itself
+is written in C++. This is likely to continue to be the case in the coming
+months, partly to ease the integration of LLVM into the Rubinius system.
+
+The compiler, assembler, and bytecode generators are all written in Ruby, and
+can be found under the ./lib/compiler directory.
+
View
617 README-DEVELOPERS
@@ -2,261 +2,375 @@
General help and instructions on writing code for Rubinius.
+== Further Reading
-0. Further Reading
-==================
At some point, you should read everything in doc/. It is not
necessary to understand or memorise everything but it will
help with the big picture at least!
+== Files and Directories
-1. Files and Directories
-========================
Get to know your way around the place!
-* .load_order.txt
+.load_order.txt::
Explains the dependencies between files so the VM can load them
in the correct order.
-* kernel/
+kernel/::
The Ruby half of the implementation. The classes, methods etc.
that make up the Ruby language environment are defined here.
Further divided into..
-* kernel/platform.conf
- kernel/platform/
+kernel/platform/::
Platform-dependent code wrappers that can then be used in other
- kernel code. platform.conf is an autogenerated file that defines
- various platform-dependent constants, offsets etc.
+ kernel code. kernel/platform.conf is an autogenerated file that
+ defines various platform-dependent constants, offsets etc.
-* kernel/bootstrap/
+kernel/bootstrap/::
Minimal set of incomplete core classes that is used to load up
the rest of the system. Any code that requires Rubinius' special
abilities needs to be here too.
-* kernel/common/
+kernel/common/::
Complete implementation of the core classes. Builds on and/or
overrides bootstrap/. Theoretically this code should be portable
so all Rubinius-dependent stuff such as primitives goes in
bootstrap/ also.
-* kernel/delta/
+kernel/delta/::
Some methods have proto-implementations to enable loading
kernel/common. Redefine these methods in kernel/delta to provide
the complete implementation. Also the place to put any code that
needs to run after kernel/common has completed loading.
-* runtime/
+runtime/::
Contains run-time compiled files for Rubinius. You'll use these
files when running shotgun/rubinius
-* runtime/stable/*
- Known-good versions of the Ruby libraries that are used by the
- compiler to make sure you can recompile in case you break one
+runtime/stable/::
+ Known-good versions of the Ruby libraries that are used by the
+ compiler to make sure you can recompile in case you break one
of the core classes.
-* shotgun/
- The C parts. This top-level directory contains most of the build
- process configuration as well as the very short main.c.
+vm/::
+ All of the C code that implements the VM as well as the
+ extremely bare-bones versions of some Ruby constructs.
-* shotgun/lib/
- All of the C code that implements the VM as well as the extremely
- bare-bones versions of some Ruby constructs.
-
-* shotgun/external_libs/
+vm/external_libs/::
Libraries required by Rubinius, bundled for convenience.
-* lib/
- All Ruby Stdlib libraries that are verified to work as well as
- any Rubinius-specific standard libraries. Of special interest
- here are three subdirectories:
+lib/::
+ All Ruby standard libraries that are verified to work as well
+ as any Rubinius-specific standard libraries. Of special
+ interest here are three subdirectories:
-* lib/bin/
+lib/bin/::
Some utility programs such as lib/bin/compile.rb which is used
to compile files during the build process.
-* lib/ext/
+lib/ext/::
C extensions that use Subtend.
-* lib/compiler/
+lib/compiler/::
This is the compiler (implemented completely in Ruby.)
-* stdlib/
+stdlib/::
This is the Ruby Stdlib, copied straight from the distribution.
- These libraries do not yet work on Rubinius (or have not been
- tried.) When a library is verified to work, it is copied to
- lib/ instead.
+ These libraries may not yet work on Rubinius (at least, have
+ not been tried.) When a library is verified to work, it is
+ copied to lib/ instead.
-* bin/
+bin/::
Various utility programs like bin/mspec and bin/ci.
-* benchmark/
+benchmark/::
All benchmarks live here. The rubinius/ subdirectory is not in
any way Rubinius-only, all those benchmarks were just written
as part of this project (the rest are from somewhere else.)
-* spec/ and test/
- These contain the behaviour specification and verification files.
- See section 3 for information about specs. The test/ directory is
- deprecated but some old test code lives here.
+spec/ and test/::
+ These contain the behaviour specification and verification
+ files. See the specs section for information about specs. The
+ test/ directory is deprecated but some old test code lives
+ here.
+Notes: Occasionally working with kernel/ you may seem classes
+that are not completely defined or looks strange. Remember that
+some classes are set up in the VM and we are basically just
+reopening those classes.
-Notes: Occasionally working with kernel/ you may seem classes that
- are not completely defined or looks strange. Remember that
- some classes are set up in the VM and we are basically just
- reopening those classes.
+== Getting the C++ branch
+Make a new clone of the repository to avoid mixups with master.
+For current committers:
-2. Working with Kernel classes
-==============================
+ cd $WHEREVER
+ git clone git@github.com:evanphx/rubinius.git cpp
-Any time you make a change here -- or anywhere else for that
-matter -- make sure you do a full rebuild to pick up the changes,
-then run the related specs, and then run bin/ci to make sure
-that also the *unrelated* specs still work (minimal-seeming
-changes may have broad consequences.)
-
-There are a few special forms that are used in bootstrap/ as well
-as core/ such as @ivar_as_index@ (see 2.2) which maps instance
-variable names to internal fields. These impose special restrictions
-on their usage so it is best to follow the example of existing
-code when dealing with these. Broadly speaking, if something looks
-"unrubyish", there is probably a good reason for it so make sure
-to ask before doing any "cosmetic" changes -- and to run CI after.
+For others:
-If you modify a kernel class, you need to `rake build` after to
-have the changes picked up. With some exceptions, you should not
-regenerate the stable files. They will in most cases work just fine
-even without the newest code. `rake build:stable` is the command
-for that.
+ cd $WHEREVER
+ git clone git://github.com/evanphx/rubinius.git cpp
-If you create a new file in one of the kernel subdirectories, it
-will be necessary to regenerate the .load_order.txt file in the
-equivalent runtime subdirectory in order to get your class loaded
-when Rubinius starts up. Use the rake task build:load_order to
-regenerate the .load_order.txt files.
+After the clone, enter into the newly-created directory.
+
+To switch to the C++ branch:
+
+ git branch --track cpp origin/cpp
+ git checkout cpp
+
+The --track allows you to push and pull directly to/from the
+branch.
+
+If you want to name your local branch something other than 'cpp',
+please make sure you understand what `man git-push` is saying
+about pushing branches.
+
+== VM
+
+=== Building the VM
+
+To build the codebase:
+
+ rake build
+
+Build and run the tests:
+
+ rake vm:test
+
+To run only one test suite, use:
+
+ rake vm:test[SomeClass]
+
+If you want to run a single test suite under gdb, use:
+
+ SUITE="SomeClass" gdb vm/test/runner
+
+You can use `git pull` or `rake git:pull to get updatesa.
+
+Use `git push` or `rake git:push` to send back any of your
+commits to the C++ branch.
+
+You can use `git push origin cpp` to specify that you only want
+to push your local 'cpp' branch changes to the remote 'cpp'
+branch. By default, git will try to push 'master' and 'cpp'.
+
+=== Compiling to .rbc with MRI
+
+MRI can be used to compile Ruby files to bytecode, which can then be run by
+the VM. To compile 'file.rb' to 'file.rbc':
+
+ # in the root of the cpp directory
+ $ rake compile_ruby[file.rb]
+ # Depending on your shell, you may need to escape the brackets
+
+=== Running code with the VM
-Due to the dependencies inherent in writing the Core in Ruby, there
-is one idiom used that may confuse on first sight. Many methods are
-called #some_method_cv and the _cv stands for 'core version,' not
-one of the other things you thought it might be. The idea is that
-a simple version of a given method is used until everything is
-safely loaded, at which point it is replaced by the real version.
-This happens in WhateverClass.after_loaded (and it is NOT automated.)
+A Ruby file can be run by the VM with the following command:
+ rake run_ruby[file.rb]
-2.1 Safe Math Compiler Plugin
------------------------------
+Add -t to enable printing of probes in the vm to see various information on
+your screen. Alternately, run the vm by hand:
-Since the core libraries are built of the same blocks as any other
-Ruby code and since Ruby is a dynamic language with open classes and
-late binding, it is possible to change fundamental classes like
-Fixnum in ways that violate the semantics that other classes depend
-on. For example, imagine we did the following:
+ rake -t run_ruby[file.rb]
+ PROBE=1 vm/vm file.rbc
- class Fixnum
- def +(other)
- (self + other) % 5
- end
+=== Examining C++ exceptions
+
+If the vm exits with a C++ exceptions you may not get much useful
+information. Re-run with gdb to examine the cause of the
+failure. To start:
+
+ $ gdb vm/vm
+ (gdb) break rubinius::ExceptionClass::raise
+ (gdb) run file.rbc
+ [normal gdb usage here]
+
+See below for some functions rubinius provides for making gdb
+debugging easier.
+
+=== Primitives
+
+Primitives are normal methods on C++ classes. Comment annotation
+links the C++ method to a symbol with which the primitive is
+accessed in Ruby code.
+
+For example, consider the Ruby Fixnum class:
+
+ class Fixnum
+ def -@
+ Ruby.primitive :fixnum_neg
+ raise PrimitiveFailure, "Fixnum#-@ primitive failed"
end
+ end
-While it is certainly possible to redefine fixed point arithmetic plus
-to be modulo 5, doing so will certainly cause some class like Array to
-be unable to calculate the correct length when it needs to. The dynamic
-nature of Ruby is one of its cherished features but it is also truly a
-double-edged sword in some respects.
+In the C++ file, vm/builtin_fixnum.hpp, the primitive is annotated:
+
+ namespace rubinius {
+
+ class Fixnum : public Integer {
+ // ...
+
+ // Ruby.primitive :fixnum_neg
+ INTEGER neg(STATE) {
+
+The magic for this happens in vm/codegen/field_extract.rb and the
+output goes to vm/gen/primitives_declare.hpp and
+vm/gen/primitives_glue.gen.cpp.
+
+There are two ways to annotate the C++ methods as primitives. If
+there is a single C++ method, use 'Ruby.primitive
+:name_of_primitive'.
+
+If there are multiple C++ methods (i.e. overloaded methods), use
+'Ruby.primitive! :name_of_primitive'. The '!' annotation is used
+for each overloaded method and uses the argument types to
+determine which implementation method to call for the primitive.
+
+The resulting glue code for overloaded methods looks something
+like the following, but please do not assume this sample is
+up-to-date:
+
+ bool Primitives::float_mul(STATE, VMExecutable* exec,
+ Task* task, Message& msg) {
+ OBJECT ret;
+ try {
+ // Attempt to treat the argument as a Float, but do not
+ // raise an exception if it is not.
+ // as<Float>, by contrast, would fail if the argument was
+ // not actually a Float instance.
+ if(Float* arg = try_as<Float>(msg.get_argument(0))) {
+ return as<Float>(msg.recv)->mul(state, arg);
+ }
+ if(Integer* arg = try_as<Integer>(msg.get_argument(0))) {
+ return as<Float>(msg.recv)->mul(state, arg);
+ }
+ else {
+ throw new Assertion("unable to resolve primitive float_mul types");
+ }
+ } catch(PrimitiveFailed& e) {
+ abort(); // The real behavior here is fancier than this example.
+ return true;
+ }
+ task->primitive_return(ret, msg);
+ return false;
+ }
+
+==== Primitive tests
+
+Since the "primitives" are ordinary C++ methods, tests for them
+are written along with the other VM tests. Each builtin_xxx.cpp
+method has a corresponding vm/test/test_xxx.hpp method. See the
+existing files for more examples.
+
+== Working with Kernel classes
-In Stdlib, the 'mathn' library redefines Fixnum#/ in an unsafe and
-incompatible manner. The library aliases Fixnum#/ to Fixnum#quo,
-which returns a Float by default.
+Any time you make a change here -- or anywhere else for that
+matter -- make sure you do a full rebuild (rake kernel:build) to
+pick up the changes, then run the related specs, and then run
+bin/ci to make sure that also the *unrelated* specs still work
+(minimal-seeming changes may have broad consequences.)
-Because of this there is a special compiler plugin that emits a different
-method name when it encounters the #/ method. The compiler emits #divide
-instead of #/. The numeric classes Fixnum, Bignum, Float, and Numeric all
-define this method.
+If you modify a kernel class, you need to `rake build` after to
+have the changes picked up. With some exceptions, you should not
+regenerate the stable files. They will in most cases work just
+fine even without the newest code. `rake build:stable` is the
+command for that.
-The `-frbx-safe-math` switch is used during the compilation of the Core
-libraries to enable the plugin. During regular 'user code' compilation,
-the plugin is not enabled. This enables us to support mathn without
-breaking the core libraries or forcing inconvenient practices.
+If you create a new file in one of the kernel subdirectories, it
+will be necessary to regenerate the .load_order.txt file in the
+equivalent runtime subdirectory in order to get your class loaded
+when Rubinius starts up. Use the rake task build:load_order to
+regenerate the .load_order.txt files.
+=== Safe Math Compiler Plugin
-2.2 ivar_as_index
------------------
+Since the core libraries are built of the same blocks as any
+other Ruby code and since Ruby is a dynamic language with open
+classes and late binding, it is possible to change fundamental
+classes like Fixnum in ways that violate the semantics that other
+classes depend on. For example, imagine we did the following:
-As described above, you'll see calls to @ivar_as_index@ kernel code.
-This maps the class's numbered fields to ivar names, but ONLY for
-that file.
+ class Fixnum
+ def +(other)
+ (self + other) % 5
+ end
+ end
-You can NOT access those names using the @name syntax outside of that
-file. (Doing so will cause maddeningly odd behavior and errors.)
+While it is certainly possible to redefine fixed point arithmetic
+plus to be modulo 5, doing so will certainly cause some class
+like Array to be unable to calculate the correct length when it
+needs to. The dynamic nature of Ruby is one of its cherished
+features but it is also truly a double-edged sword in some
+respects.
-For instance, if you make a subclass of IO, you can NOT access @descriptor
-directly in your subclass. You must go through methods to access it only.
-Notably, you can NOT just use the @#attr_*@ methods for this. The methods
-must be completely written out so that the instance variable label can
-be picked up to be translated.
+In the standard library the 'mathn' library redefines Fixnum#/ in
+an unsafe and incompatible manner. The library aliases Fixnum#/
+to Fixnum#quo, which returns a Float by default.
+Because of this there is a special compiler plugin that emits a
+different method name when it encounters the #/ method. The
+compiler emits #divide instead of #/. The numeric classes Fixnum,
+Bignum, Float, and Numeric all define this method.
-2.3 Kernel- and user-land
--------------------------
+The `-frbx-safe-math` switch is used during the compilation of
+the Core libraries to enable the plugin. During regular 'user
+code' compilation, the plugin is not enabled. This enables us to
+support mathn without breaking the core libraries or forcing
+inconvenient practices.
-Rubinius is in many ways architected like an operating system, so some
-OS world terms may be easiest to describe the two modes that Rubinius
-operates under:
+=== Kernel-land and user-land
-'Kernel-land' describes how code in kernel/ is executed. Everything else
-is 'user-land.'
+Rubinius is in many ways architected like an operating system, so
+some OS world terms may be easiest to describe the two modes that
+Rubinius operates under:
-Kernel-land has a number of restrictions to keep things sane and simple:
+'Kernel-land' describes how code in kernel/ is executed.
+Everything else is 'user-land.'
-* #public, #private, #protected, #module_function require method names
- as arguments. The 0-argument version that allows toggling visibility
- in a class or module body is not available.
+Kernel-land has a number of restrictions to keep things sane and
+simple:
-* Restricted use of executable code in class, module and script (file)
- bodies. @SOME_CONSTANT = :foo@ is perfectly fine, of course, but for
- example different 'memoizations' or other calculation should not be
- present. Code inside methods has no restrictions, broadly speaking,
- but keep dependency issues in mind for methods that may get called
- during the instantiation of the rest of the kernel code.
+* #public, #private, #protected, #module_function require method
+ names as arguments. The 0-argument version that allows toggling
+ visibility in a class or module body is not available.
-* @#after_loaded@ hooks can be used to perform more complex/extended
- setup or calculations for kernel classes. The @_cv@ methods mentioned
- above, for example, are replaced over the simpler bootstrap versions
- in the @#after_loaded@ hooks of the respective classes. @#after_loaded@
- is not magic, and will not be automatically called. If adding a new
- one, have kernel/loader.rb call it (at this point the system is
- fully up.)
+* Restricted use of executable code in class, module and script
+ (file) bodies. <tt>SOME_CONSTANT = :foo<tt> is perfectly fine,
+ of course, but for example different 'memoizations' or other
+ calculation should not be present. Code inside methods has no
+ restrictions, broadly speaking, but keep dependency issues in
+ mind for methods that may get called during the instantiation
+ of the rest of the kernel code.
* Kernel-land code does not use handle defining methods through
- @Module#__add_method__@ nor @MetaClass#attach_method@. It adds
+ Module#__add_method__ nor MetaClass#attach_method. It adds
and attaches methods directly in the VM. This is necessary for
bootstrapping.
-* Any use of string-based eval in the kernel must go through discussion.
-
+* Any use of string-based eval in the kernel must go through
+ discussion.
-3. Specs (Specifications)
-=========================
+== Specs (Specifications)
Probably the first or second thing you hear about Rubinius when
speaking to any of the developers is a mention of The Specs. It
is a crucial part of Rubinius.
-Rubinius itself is being developed using the Behaviour-Driven
+Rubinius itself is being developed using the Behaviour-Driven
Design approach (a refinement of Test-Driven Design) where each
-aspect of the behaviour of the code is first specified using
-the spec format and only then implemented to pass those specs.
+aspect of the behaviour of the code is first specified using the
+spec format and only then implemented to pass those specs.
In addition to this, we have undertaken the ambitious task of
-specifying the entirety of the Ruby language as well as its
-Core and Stdlib libraries in this format which both allows us
-to ensure our implementation is conformant with the Ruby standard
+specifying the entirety of the Ruby language as well as its Core
+and Stdlib libraries in this format which both allows us to
+ensure our implementation is conformant with the Ruby standard
and, more importantly, to actually *define* that standard since
there currently is no formal specification of Ruby.
-The de facto standard of BDD is set by "RSpec":http://rspec.info,
+The de facto standard of BDD is set by RSpec[http://rspec.info],
the project conceived to implement the then-new way of coding.
Their website is fairly useful as a tutorial as well, although
the spec syntax (particularly as used in Rubinius) is not very
@@ -264,47 +378,44 @@ complex at all.
Currently we actually use a compatible but vastly simpler
implementation specifically developed as a part of Rubinius
-called MSpec (for mini-RSpec, as it was originally needed
-because the code in RSpec was too complex to be run on our
+called MSpec (for mini-RSpec, as it was originally needed because
+the code in RSpec was too complex to be run on our
not-yet-complete Ruby implementation.)
Specs live in the spec/ directory. spec/ruby/ specifies our
-current target implementation, Ruby 1.8.6-p111 and it is
-further split to various subdirectories such as language/
-for language-level constructs such as, for example, the
-@if@ statement and core/ for Core library code such as
-@Array@.
+current target implementation, Ruby 1.8.6-p111 and it is further
+split to various subdirectories such as language/ for
+language-level constructs such as, for example, the +if+
+statement and core/ for Core library code such as +Array+.
Parallel to this the top-level spec/ directory itself has the
subdirectories for Rubinius-specific specs: additions and/or
-deviations from the standard, Rubinius language constructs
-etc. For example, the standard @String@ specs live under the
+deviations from the standard, Rubinius language constructs etc.
+For example, the standard +String+ specs live under the
spec/ruby/1.8/core/string/ directory and if Rubinius implements
-an additional method @String#to_morse@, the specs for it can
-be found in spec/core/string/. Completely new classes such as
-@CompiledMethod@ find their specs here as well.
+an additional method +String#to_morse+, the specs for it can be
+found in spec/core/string/. Completely new classes such as
++CompiledMethod+ find their specs here as well.
The way to run the specs is contained in two small programs:
bin/mspec and bin/ci. The former is the "full" version that
allows a wider range of options and the latter is a streamlined
-way of running Continuous Integration (CI) testing. CI is a
-set of "known-good" specs picked out from the entirety of
-them (which is what bin/mspec works with) using an automatic
-exclusion mechanism. CI is very important for any Rubinius
-developer: before each commit, bin/ci should be run and found
-to finish without error. It makes it very easy to ensure that
-your change did not break other, seemingly unrelated things
-because it exercises all areas of specs. A clean bin/ci run
-gives confidence that your code is correct.
+way of running Continuous Integration (CI) testing. CI is a set
+of "known-good" specs picked out from the entirety of them (which
+is what bin/mspec works with) using an automatic exclusion
+mechanism. CI is very important for any Rubinius developer:
+before each commit, bin/ci should be run and found to finish
+without error. It makes it very easy to ensure that your change
+did not break other, seemingly unrelated things because it
+exercises all areas of specs. A clean bin/ci run gives confidence
+that your code is correct.
For a deeper overview, tutorials, help and other information
about Rubinius' specs, start here:
http://rubinius.lighthouseapp.com/projects/5089/specs-overview
-
-4. Libraries and C: Primitives vs. FFI
-======================================
+== Libraries and C: Primitives vs. FFI
There are two ways to "drop to C" in Rubinius. Firstly, primitives
are special instructions that are specifically defined in the VM.
@@ -325,9 +436,8 @@ There is also a specific Rubinius extension layer called Subtend.
It emulates the extension interface of Ruby to allow old Ruby
extensions to work with Rubinius.
+=== Primitives
-4.1 Primitives
-==============
Using the above rationale, if you need to implement a primitive:
* Give the primitive a sane name
@@ -338,12 +448,12 @@ Using the above rationale, if you need to implement a primitive:
* `rake build`
This makes your primitive available in the Ruby layer using the
-special form @Ruby.primitive :primitive_name@. Primitives have a
-few rules and chief among them is that a primitive must be the
-first instruction in the method that it appears in. Partially for
-this reason all primitives should reside in a wrapper method in
-bootstrap/ (the other part is that core/ should be implementation
-independent and primitives are not.)
+special form <tt>Ruby.primitive :primitive_name</tt>. Primitives
+have a few rules and chief among them is that a primitive must be
+the first instruction in the method that it appears in. Partially
+for this reason all primitives should reside in a wrapper method
+in bootstrap/ (the other part is that core/ should be
+implementation independent and primitives are not.)
In addition to this, primitives have another property that may
seem unintuitive: anything that appears below the primitive form
@@ -351,17 +461,17 @@ in the wrapper method is executed if the primitive FAILS and only
if it fails. There is no exception handling syntax involved. So
this is a typical pattern:
- # kernel/bootstrap/whatever.rb
- def self.prim_primitive_name()
- Ruby.primitive :primitive_name
- raise SomeError, "Whatever I was doing just failed."
- end
-
- # kernel/core/whatever.rb
- def self.primitive_name()
- self.prim_primitive_name
- ...
- end
+ # kernel/bootstrap/whatever.rb
+ def self.prim_primitive_name()
+ Ruby.primitive :primitive_name
+ raise SomeError, "Whatever I was doing just failed."
+ end
+
+ # kernel/core/whatever.rb
+ def self.primitive_name()
+ self.prim_primitive_name
+ ...
+ end
To have a primitive fail, the primitive body (in primitives.rb)
should return FALSE; this will cause the code following the
@@ -370,11 +480,12 @@ the operation can be retried in Ruby.
If a primitive cannot be retried in Ruby or if there is some
additional information that needs to be passed along to create
-the exception, it may raise an exception using a couple of macros:
+the exception, it may raise an exception using a couple of
+macros:
* RAISE(exc_class, msg) will raise an exception of type exc_class
and with a message of msg, e.g.
-
+
RAISE("ArgumentError", "Invalid argument");
* RAISE_FROM_ERRNO(msg) will raise an Errno exception with the
@@ -382,23 +493,24 @@ the exception, it may raise an exception using a couple of macros:
If you need to change the signature of a primitive, follow this
procedure:
- 1. change the signature of the kernel method that calls the
- VM primitive
- 2. change any calls to the kernel method in the kernel/**
- code to use the new signature, then recompile
- 3. run rake build:stable
- 4. change the actual primitive in the VM and recompile again
- 5. run bin/ci
-4.2 FFI
--------
+1. change the signature of the kernel method that calls the
+ VM primitive
+2. change any calls to the kernel method in the kernel/**
+ code to use the new signature, then recompile
+3. run rake build:stable
+4. change the actual primitive in the VM and recompile again
+5. run bin/ci
+
+=== FFI
Module#attach_function allows a C function to be called from Ruby
code using FFI.
Module#attach_function takes the C function name, the ruby module
-function to bind it to, the C argument types, and the C return type.
-For a list of C argument types, see kernel/platform/ffi.rb.
+function to bind it to, the C argument types, and the C return
+type. For a list of C argument types, see
+kernel/platform/ffi.rb.
Currently, FFI does not support C functions with more than 6
arguments.
@@ -412,7 +524,7 @@ which fills in the string with the digest.
class Digest::MD5
attach_function nil, 'rbx_Digest_MD5_Finish', :md5_finish,
[:pointer, :string], :void
-
+
def finish
digest = ' ' * 16
self.class.md5_finish @context, digest
@@ -422,45 +534,41 @@ which fills in the string with the digest.
For a complete additional example, see digest/md5.rb.
-
-5. Debugging: debugger, GDB, valgrind
-=====================================
+== Debugging: debugger, GDB, valgrind
With Rubinius, there are two distinct things that may need
-debugging (sometimes at the same time.) There is the Ruby
-code, for which 'debugger' exists. debugger is a full-speed
-debugger, which means that there is no extra compilation or
-flags to enable it but at the same time, code normally does
-not suffer a performance penalty from the infrastructure.
-This is achieved using a combination of bytecode substitution
-and Rubinius' Channel IO interface. Multithreaded debugging
-is supported (credit for the debugger goes to Adam Gardiner.)
-
-On the C side, the trusty workhorse is the Gnu Debugger or
-GDB. In addition there is support built in for Valgrind, a
-memory checker/lint/debugger/analyzer hybrid.
-
-
-5.1 debugger
-------------
-The nonchalantly named debugger is specifically the debugger
-for Ruby code, although it does also allow examining the VM
-as it runs. The easiest way to start it is to insert either
-a @breakpoint@ or @debugger@ method call anywhere in your
-source code. Upon running this method, the debugger starts
-up and awaits your command at the instruction where the
-@breakpoint@ or @debugger@ method used to be. For a full
-explanation of the debugger, refer to [currently the source
-but hopefully docs shortly.] You will see this prompt and
-there is a trusty command you can try to get started:
-
- rbx:debug> help
-
-
-5.2 GDB
--------
+debugging (sometimes at the same time.) There is the Ruby code,
+for which 'debugger' exists. debugger is a full-speed debugger,
+which means that there is no extra compilation or flags to enable
+it but at the same time, code normally does not suffer a
+performance penalty from the infrastructure. This is achieved
+using a combination of bytecode substitution and Rubinius'
+Channel IO interface. Multithreaded debugging is supported
+(credit for the debugger goes to Adam Gardiner.)
+
+On the C side, the trusty workhorse is the Gnu Debugger or GDB.
+In addition there is support built in for Valgrind, a memory
+checker/lint/debugger/analyzer hybrid.
+
+=== debugger
+
+The nonchalantly named debugger is specifically the debugger for
+Ruby code, although it does also allow examining the VM as it
+runs. The easiest way to start it is to insert either a
++breakpoint+ or +debugger+ method call anywhere in your source
+code. Upon running this method, the debugger starts up and awaits
+your command at the instruction where the +breakpoint+ or
++debugger+ method used to be. For a full explanation of the
+debugger, refer to [currently the source but hopefully docs
+shortly.] You will see this prompt and there is a trusty command
+you can try to get started:
+
+ rbx:debug> help
+
+=== GDB
+
To really be able to use GDB, make sure that you build Rubinius
-with DEV=1 set. This disables optimisations and adds debugging
+with DEV=1 set. This disables optimisations and adds debugging
symbols.
There are two ways to access GDB for Rubinius. You can simply
@@ -471,34 +579,31 @@ do not need to worry about linking etc.):
for example) and then r(un.)
* Alternatively, you can run and then hit ^C to interrupt.
-You can also drop into GDB from Ruby code with @Kernel#yield_gdb@
+You can also drop into GDB from Ruby code with +Kernel#yield_gdb+
which uses a rather rude but very effective method of stopping
-execution to start up GDB. To continue past the @yield_gdb@,
+execution to start up GDB. To continue past the +yield_gdb+,
j(ump) to one line after the line that you have stopped on.
Useful gdb commands and functions (remember, using the p(rint)
command in GDB you can access pretty much any C function in
Rubinius):
-* rbt
- Prints the backtrace of the Ruby side of things. Use this in
+rbt::
+ Prints the backtrace of the Ruby side of things. Use this in
conjunction with gdb's own bt which shows the C backtrace.
-* p _inspect(OBJECT)
+rp _inspect(OBJECT)::
Useful information about a given Ruby object.
+=== Valgrind
-5.3 Valgrind
-------------
Valgrind is a program for debugging, profiling and memory-checking
programs. The invocation is just `shotgun/rubinius --valgrind`.
See http://valgrind.org for usage information.
-5.4 Tracing
------------
+=== Tracing
Excessive tracing can rapidly fill your screen up with crap. To enable it,
RBX=rbx.debug.trace shotgun/rubinius ...
-=== END ===
Please sign in to comment.
Something went wrong with that request. Please try again.