Browse files

Migrated README-DEVELOPERS to doc/* files.

  • Loading branch information...
1 parent db7f6cb commit b08b45f0317558f9b09963db361a45fd35d72faa Brian Ford committed Dec 10, 2008

Large diffs are not rendered by default.

Oops, something went wrong.
@@ -1,3 +1,5 @@
+TODO: Break into files in the doc/compiler/ directory.
= Introduction to the Rubinius compiler
This document presents the sequence of transformations that it takes
@@ -0,0 +1,38 @@
+# Compiler Plugins
+TODO: document the compiler plugin architecture.
+## Safe Math Compiler Plugin
+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
+ class Fixnum
+ def +(other)
+ (self + other) % 5
+ 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 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.
+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.
@@ -27,7 +27,7 @@ that the next doc writer can be annoying with other questions.
## Run your code
-You code it often more vicious than the specs. Run your pet project under
+Your code it often more vicious than the specs. Run your pet project under
rubinius and report crashes! See [Howto - Write a
@@ -37,18 +37,19 @@ Search for tags like TODO, HACK, FIXME in the code and fix them. Once you're
finished, submit a ticket with the [PATCH] tag and a small description. See
[Howto - Write a ticket](/howto/write_a_ticket.html)
-I use : `grep -re "TODO\|HACK\|FIXME" .`
+I use : `grep -re "@todo\|TODO\|HACK\|FIXME" .`
-You can also run failing specs and try to fix them. I use `bin/ci -i` and
-`rake todo`
+You can also run failing specs and try to fix them. I use `bin/mspec
+spec/frozen`, `rake todo`, or `bin/mspec tag --list fails spec/frozen`.
## Ask For Help
Anything that we can do to help, we will. Make sure to do your own research
too, if possible. We will certainly accept and appreciate simple bug reports,
but it is extremely helpful if you can actively help us identify (and maybe
-even fix) the problem.
+even fix) the problem. Again, see [Howto - Write a
Q. It is all so confusing! There is the VM, the kernel, the libraries, the
specs, polymorphic caches, pneumatic stegosauruses... How can I possibly
@@ -0,0 +1,111 @@
+## 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
+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 symbols.
+There are two ways to access GDB for Rubinius. You can simply run
+shotgun/rubinius with gdb (use the builtin support so you do not need to worry
+about linking etc.):
+* Run `shotgun/rubinius --gdb`, place a breakpoint (break main, 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+ which uses a
+rather rude but very effective method of stopping 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. Also see ./.gdbinit):
+* rbt
+ Prints the backtrace of the Ruby side of things. Use this in conjunction
+ with gdb's own bt which shows the C backtrace.
+* rp some_obj
+ Prints detailed information about a given Ruby object.
+* rps some_obj
+ Prints brief information about a given Ruby object.
+The gdb rp and rps commands use the C-exported functions __show__ and
+__show_simple__. The default output of these functions is defined on the
+TypeInfo class. The other C++ classes define the show and show_simple
+functions to override the default output. The default output is to show the
+class name and the address of the instance like "#<SomeClass:0x3490301".
+The immediate classes like NilClass, TrueClass, etc. and the numeric classes
+like Fixnum and Bignum define show and show_simple to both output their
+values. More complex classes like CompiledMethod and Tuple use the show_simple
+function to limit the information printed.
+See also vm/type_info.hpp
+### Valgrind
+Valgrind is a program for debugging, profiling and memory-checking programs.
+The invocation is just `shotgun/rubinius --valgrind`. See
+ for usage information.
+### Probes
+The C++ VM uses the TaskProbe class to define and manage several probes that,
+when enabled, print information about VM operations. The probes can be
+enabled from an environmental variable or from Ruby code. To enable all probes
+from the environment, use:
+ PROBE=all vm/vm OR
+ PROBE=1 vm/vm
+To enable only certain probes from the environment, use e.g.:
+ PROBE=start_method,execute_instruction vm/vm
+From Ruby code, enable or disable probes globally with the TaskProbe class
+method. For example:
+ TaskProbe.enable :execute_instruction
+ TaskProbe.disable :start_method
+Or, create a TaskProbe instance and use the #show method with a block:
+ meth = :start_method
+ { # some ruby code here }
+See also kernel/common/taskprobe.rb and vm/builtin/taskprobe.hpp.
@@ -1,62 +1,51 @@
# Foreign Function Interface - FFI
-TODO: Imported from Lighthouse wiki. Likely outdated
-This section is highly underdeveloped.
-## Overview
-To do.
-## Usage
-The main interface function to FFI is `Module#attach_foreign.` Extracted
-documentation on its usage is below:
-### Module#attach_foreign
-Create a wrapper to a function in a C-linked library that exists somewhere in
-the system. If a specific library is not given, the function is assumed to
-exist in the running process, the Rubinius executable. The process contains
-many linked libraries in addition to Rubinius' codebase, libc of course the
-most prominent on the system side. The wrapper method is added to the Module
-as a singleton method or a "class method."
-The function is specified like a declaration: the first argument is the type
-symbol for the return type (see FFI documentation for types), the second
-argument is the name of the function and the third argument is an Array of the
-types of the function's arguments. Currently at most 6 arguments can be given.
- # If you want to wrap this function:
- int foobar(double arg_one, const char* some_string);
- # The arguments to #attach_foreign look like this:
- :int, 'foobar', [:double, :string]
-If the function is from an external library such as, say, libpcre, libcurl
-etc. you can give the name or path of the library. The fourth argument is an
-option hash and the library name should be given in the +:from+ key of the
-hash. The name may (and for portable code, should) omit the file extension. If
-the extension is present, it must be the correct one for the runtime platform.
-The library is searched for in the system library paths but if necessary, the
-full absolute or relative path can be given.
-By default, the new method's name is the same as the function it wraps but in
-some cases it is desirable to change this. You can specify the method name in
-the +:as+ key of the option hash. So if you for whatever reason wanted to
-import the `char* secret(double seed, double watermelon)` function from a
-secret library into your class but name it something else (it *is* secret,
-after all,) the entire invocation looks like this:
- class TotallyNotSecretClass
- attach_foreign :string, :secret,[:double, :double], :from => "libsecret", :as => :completely_public
+## 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. In general they are
+operations that are impossible to do in the Ruby layer such as opening a file.
+Primitives should be used to access the functionality of the VM from inside
+FFI or Foreign Function Interface, on the other hand, is meant as a
+generalised method of accessing system libraries. FFI is able to automatically
+generate the bridge code needed to call out to some library and get the result
+back into Ruby. FFI functions at runtime as real machine code generation so
+that it is not necessary to have anything compiled beforehand. FFI should be
+used to access the code outside of Rubinius, whether it is system libraries or
+some type of extension code, for example.
+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
+## FFI
+Module#attach_function allows a C function to be called from Ruby code using
+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.
+Currently, FFI does not support C functions with more than 6 arguments.
+When the C function will be filling in a String, be sure the Ruby String is
+large enough. For the C function rbx_Digest_MD5_Finish, the digest string is
+allocated with a 16 character length. The string is passed to md5_finish
+which calls rbx_Digest_MD5_Finish 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
+ digest
+ end
- TotallyNotSecretClass.completely_public # => _Whatever it is supposed to do_
+For a complete additional example, see digest/md5.rb.
-The "styling" is completely optional and if you prefer, you can use Symbols
-for the names (except the library name) instead of Strings. I like to make it
-look as much like the C declaration as possible, hence the indentation.
@@ -100,6 +100,43 @@ use the +debug+ subtask:
rake build:debug
+## Running VM Tests
+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
+## Running the Specs
+Rubinius includes a stable copy of the RubySpecs that is tagged so that a
+clean set (i.e. passing 100%) of specs can be run as part of the continuous
+integration (CI) process. To run the CI specs:
+ rake spec
+ bin/mspec ci
+To run the most current version of RubySpec:
+ rake rubyspec:update
+ bin/mspec spec/ruby
+To run a particular spec file, for example, the Array specs:
+ bin/mspec spec/ruby/1.8/core/array
## Installing Rubinius
Run the 'rake install' task to install Rubinius (you may need sudo). Run the
@@ -116,6 +153,10 @@ Rubinius generally works like Ruby from the command-line. For example:
bin/rbx -e 'puts "Hello!"'
+To run a ruby file named 'code.rb':
+ bin/rbx code.rb
## Troubleshooting
Oops, something went wrong.

0 comments on commit b08b45f

Please sign in to comment.