# 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

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, Executable* exec, Task* task, Message& msg) {
    OBJECT ret;
    if(msg.args() != 1)
      goto fail;

    Float* recv;
    if((recv = as<Float>(msg.recv)) == NULL)
      goto fail;

    if(Float* arg = try_as<Float>(msg.get_argument(0))) {
      ret = recv->mul(state, arg);
    } else   if(Integer* arg = try_as<Integer>(msg.get_argument(0))) {
      ret = recv->mul(state, arg);
    } else   goto fail;
    if(ret == reinterpret_cast<Object*>(kPrimitiveFailed))
      goto fail;

    task->primitive_return(ret, msg);
    return false;

  fail:
    return VMMethod::execute(state, exec, task, msg);
  }

To have a primitive fail, the primitive body should return
Primitives::failure(). This will cause the code following the Ruby.primitive
line in the kernel to be run. This provides a fallback so that 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 other exceptions.


## Testing Primitive

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.
