text: #ifndef RBX_VM_BUILTIN_OBJECT_HPP
  #define RBX_VM_BUILTIN_OBJECT_HPP
  
  #include <vector>
  
  #include "vm.hpp"
  #include "oop.hpp"
  #include "type_info.hpp"
  #include "executor.hpp"
  #include "object_memory.hpp"
  
  namespace rubinius {
  
  /**
   *  Create a writer method for a slot.
   *
   *  For attr_writer(foo, SomeClass), creates void foo(STATE, SomeClass* obj)
   *  that sets the instance variable foo_ to the object given and runs the write
   *  barrier.
   */
  #define attr_writer(name, type) \
    template <class T> \
    void name(T state, type* obj) { \
      name ## _ = obj; \
      this->write_barrier(state, obj); \
    }
  
  /**
   *  Create a reader method for a slot.
   *
   *  For attr_reader(foo, SomeClass), creates SomeClass* foo() which returns the
   *  instance variable foo_. A const version is also generated.
   */
  #define attr_reader(name, type) \
    type* name() const { return name ## _; }
  
  /**
   *  Ruby-like accessor creation for a slot.
   *
   *  Both attr_writer and attr_reader.
   */
  #define attr_accessor(name, type) \
    attr_reader(name, type) \
    attr_writer(name, type)
  
    /* Forwards */
    class Fixnum;
    class Integer;
    class String;
    class Module;
    class Executable;
    class Array;
    class Object;
  
    /**
     *  Object is the basic Ruby object.
     *
     *  Because of needing to exactly control the in-memory layout of
     *  Objects, none of the subclasses of Object (or ObjectHeader)
     *  is allowed to use define virtual methods. In order to achieve
     *  virtual dispatch for the cases where it is needed (it usually
     *  is not), the TypeInfo class should be used. Each builtin class
     *  defines a contained type Info which inherits--directly or not
     *  from TypeInfo. TypeInfos use virtual methods to achieve dynamism.
     *  Instances of these Info classes are held by the VM, where they
     *  can be retrieved using a given Object's object_type. The Info
     *  object will then dispatch the correct virtual method for the
     *  type. The methods are written to understand the types they are
     *  dealing with.
     *
     *  The class definition layout differs from the normal alphabetic
     *  order in order to group the different aspects involved better
     *  and to simplify finding/adding &c. related methods.
     *
     *  @todo The entire codebase should be reviewed for const
     *        correctness. --rue
     *
     *  @todo Remove the unimplemented definitions? --rue
     *
     *  @see  vm/type_info.hpp
     *
     */
    class Object : public ObjectHeader {
    public:   /* Slots and bookkeeping */
  
      /** Class type identifier. */
      static const object_type type = ObjectType;
  
      static void bootstrap_methods(STATE);
  
    public:   /* GC support, bookkeeping &c. */
  
      /** Provides access to the GC write barrier from any object. */
      void        write_barrier(STATE, void* obj);
      void        write_barrier(VM*, void* obj);
  
      /** Special-case write_barrier() for Fixnums. */
      void        write_barrier(STATE, Fixnum* obj);
      /** Special-case write_barrier() for Symbols. */
      void        write_barrier(STATE, Symbol* obj);
  
      void        write_barrier(ObjectMemory* om, void* obj);
  
      void        setup_allocation_site(STATE, CallFrame* call_frame = NULL);
  
    public:   /* Type information, field access, copy support &c. */
  
      /**
       * Returns a copy of this object. This is NOT the same as Ruby
       * Kernel#dup. Code that needs Kernel#dup semantics MUST call
       * #dup from Ruby. This method is used in the VM to duplicate
       * data structures. It will not call the Ruby allocate() or
       * initialize_copy() methods.
       */
      Object* duplicate(STATE);
  
      Object* copy_object(STATE, Object* other);
  
      /**
       *  Copies the object including any instance variables. Called by
       *  Kernel#dup.
       */
  
      // Rubinius.primitive :object_copy_object
      Object* copy_object_prim(STATE, Object* other, CallFrame* calling_environment);
  
      /**
       * Copies this Object's MetaClass to the other Object. Called
       * by Kernel#clone.
       */
      // Rubinius.primitive :object_copy_singleton_class
      Object* copy_singleton_class(STATE, GCToken gct, Object* other, CallFrame* calling_environment);
  
      /** True if this Object* is actually a Fixnum, false otherwise. */
      bool fixnum_p() const;
  
      /**
       *  Retrieve the Object stored in given field index of this Object.
       *
       *  Uses TypeInfo.
       */
      Object*     get_field(STATE, std::size_t index);
  
      /** Safely return the object type, even if the receiver is an immediate. */
      object_type get_type() const;
  
      /** True if given Module is this Object's class, superclass or an included Module. */
      bool        kind_of_p(STATE, Object* module);
  
      /** Store the given Object at given field index of this Object through TypeInfo. */
      void        set_field(STATE, std::size_t index, Object* val);
  
      /** True if this Object* is actually a Symbol, false otherwise. */
      bool        symbol_p() const;
  
      /** Return the TypeInfo for this Object's type. */
      TypeInfo*   type_info(STATE) const;
  
  
    public:   /* Method dispatch stuff */
  
      /** Actual class for this object. Also handles immediates */
      Class*       direct_class(STATE) const;
  
      /** Module where to start looking for the MethodTable for this Object. */
      Module*      lookup_begin(STATE) const;
  
      /**
       *  Directly send a method to this Object.
       *
       *  Sets up the current task to send the given method name to this
       *  Object, passing the given number of arguments through varargs.
       */
      Object* send(STATE, CallFrame* caller, Symbol* name, Array* args,
          Object* block = cNil, bool allow_private = true);
      Object* send(STATE, CallFrame* caller, Symbol* name, bool allow_private = true);
  
      Object* send_prim(STATE, CallFrame* call_frame, Executable* exec, Module* mod, Arguments& args,
          Symbol* min_visibility);
  
      /**
       *  Ruby #send/#__send__
       */
      // Rubinius.primitive? :object_send
      Object* private_send_prim(STATE, CallFrame* call_frame, Executable* exec, Module* mod, Arguments& args);
  
      /**
       *  Ruby #public_send
       */
      // Rubinius.primitive? :object_public_send
      Object* public_send_prim(STATE, CallFrame* call_frame, Executable* exec, Module* mod, Arguments& args);
  
  
    public:   /* Ruby interface */
  
      /** Returns the Class object of which this Object is an instance. */
      // Rubinius.primitive+ :object_class
      Class*    class_object(STATE) const;
  
      /**
       *  Ruby #equal?.
       *
       *  Returns true if and only if this and the other object are
       *  the SAME object, false otherwise.
       */
      // Rubinius.primitive+ :object_equal
      Object*   equal(STATE, Object* other);
  
      /** Sets the frozen flag. Rubinius does NOT currently support freezing. */
      // Rubinius.primitive :object_freeze
      Object*   freeze(STATE);
  
      /** Returns true if this Object's frozen flag set, false otherwise. */
      // Rubinius.primitive+ :object_frozen_p
      Object*   frozen_p(STATE);
  
      /**
       *  Ruby #instance_variable_get.
       *
       *  Return the Object stored as instance variable under the given
       *  identifier.
       */
      // Rubinius.primitive :object_get_ivar
      Object*   get_ivar_prim(STATE, Symbol* sym);
  
      Object*   get_ivar(STATE, Symbol* sym);
  
      // A version that only attempts to find +sym+ in the ivars slot
      Object*   get_table_ivar(STATE, Symbol* sym);
  
      // Rubinius.primitive :object_del_ivar
      Object*   del_ivar(STATE, Symbol* sym);
      Object*   del_table_ivar(STATE, Symbol* sym, bool* removed = 0);
  
      Object*   table_ivar_defined(STATE, Symbol* sym);
  
      Object*   ivar_defined(STATE, Symbol* sym);
  
      // Rubinius.primitive :object_ivar_defined
      Object*   ivar_defined_prim(STATE, Symbol* sym);
  
      /** Returns the structure containing this object's instance variables. */
      // Rubinius.primitive :object_ivar_names
      Array*   ivar_names(STATE);
  
      Array*   ivar_names(STATE, Array* ary);
  
      /** Calculate a hash value for this object. */
      hashval   hash(STATE);
  
      /** Returns the hash value as an Integer. @see hash(). */
      // Rubinius.primitive+ :object_hash
      Integer*  hash_prim(STATE);
  
      /** Returns an Integer ID for this object. Created as needed. */
      // Rubinius.primitive+ :object_id
      Integer*  id(STATE);
  
      /** Indicates if this object has been assigned an object id. */
      bool has_id(STATE);
  
      /** Reset the object id */
      void reset_id(STATE);
  
      // Rubinius.primitive+ :object_infect
      Object* infect_prim(STATE, Object* obj, Object* other) {
        other->infect(state, obj);
        return obj;
      }
  
      /**
       * Taints other if this is tainted.
       */
      void infect(STATE, Object* other);
  
      /**
       *  Ruby #kind_of?
       *
       *  Returns true if given Module is this Object's class,
       *  superclass or an included Module, false otherwise.
       */
      // Rubinius.primitive+ :object_kind_of
      Object*   kind_of_prim(STATE, Module* klass);
  
      /**
       *  Ruby #instance_of?
       *
       *  Returns true if given Module is this Object's class,
       *  false otherwise.
       */
      // Rubinius.primitive+ :object_instance_of
      Object*   instance_of_prim(STATE, Module* klass);
  
      /** Return object's MetaClass object. Created as needed.
       *  Also fixes up the parent hierarchy if needed */
      Class* singleton_class(STATE);
  
      /** Return object's MetaClass object. Created as needed. */
      Class* singleton_class_instance(STATE);
  
      /**
       *  Ruby #instance_variable_set
       *
       *  Store the given object in the instance variable by
       *  given identifier.
       */
      // Rubinius.primitive :object_set_ivar
      Object*   set_ivar_prim(STATE, Symbol* sym, Object* val);
  
      Object*   set_ivar(STATE, Symbol* sym, Object* val);
  
      // Specialized version that only checks ivars_
      Object*   set_table_ivar(STATE, Symbol* sym, Object* val);
  
      /** String describing this object (through TypeInfo.) */
      // Rubinius.primitive :object_show
      Object*   show(STATE);
      /** Indented String describing this object (through TypeInfo.) */
      Object*   show(STATE, int level);
      /** Shorter String describing this object (through TypeInfo.) */
      Object*   show_simple(STATE);
      /** Shorter indented String describing this object (through TypeInfo.) */
      Object*   show_simple(STATE, int level);
  
      /**
       *  Set tainted flag on this object.
       */
      // Rubinius.primitive :object_taint
      Object*   taint(STATE);
  
      /**
       *  Returns true if this object's tainted flag is set.
       */
      // Rubinius.primitive+ :object_tainted_p
      Object*   tainted_p(STATE);
  
      /**
       *  Clears the tainted flag on this object.
       */
      // Rubinius.primitive :object_untaint
      Object*   untaint(STATE);
  
      /**
       * Returns true if this object's untrusted flag is set.
       */
      // Rubinius.primitive+ :object_untrusted_p
      Object* untrusted_p(STATE);
  
      /**
       * Sets the untrusted flag on this object.
       */
      // Rubinius.primitive :object_untrust
      Object* untrust(STATE);
  
      /**
       * Clears the untrusted flag on this object.
       */
      // Rubinius.primitive :object_trust
      Object* trust(STATE);
  
      /**
       *  Returns an #inspect-like representation of an Object for
       *  use in C++ code.
       *
       *  If address is true, uses the actual address of the object.
       *  Otherwise, uses the object's id().
       */
      std::string to_string(STATE, bool address = false);
  
      /**
       *  Returns an #inspect-like representation of an Object for
       *  use in C++ code. Not called from Ruby code.
       *
       *  If address is true, uses the actual address of the object.
       *  Otherwise, uses the object's id().
       */
      String* to_s(STATE, bool address = false);
  
      /**
       *
       * Returns cTrue if this responds to method +meth+
       */
      // Rubinius.primitive+ :object_respond_to
      Object* respond_to(STATE, Symbol* name, Object* priv, CallFrame* calling_environment);
  
      Object* respond_to(STATE, Symbol* name, Object* priv);
  
      /**
       * Checks if object is frozen and raises RuntimeError if it is.
       * Similar to CRuby rb_check_frozen
       */
      void check_frozen(STATE);
  
    public:   /* accessors */
  
      /* klass_ from ObjectHeader. */
      attr_accessor(klass, Class);
  
      /* ivars_ from ObjectHeader. */
      attr_accessor(ivars, Object);
  
  
    public:   /* TypeInfo */
  
      /**
       *  Static type information for Object.
       */
      class Info : public TypeInfo {
      public:
        virtual ~Info() {}
        Info(object_type type)
          : TypeInfo(type)
        {}
  
        virtual void auto_mark(Object* obj, ObjectMark& mark) {}
      };
    };
  
  /* Object inlines -- Alphabetic, unlike class definition. */
  
    inline bool Object::fixnum_p() const {
      return __FIXNUM_P__(this);
    }
  
    inline Class* Object::direct_class(STATE) const {
      if(reference_p()) {
        return klass_;
      }
  
      return state->globals().special_classes[((uintptr_t)this) & SPECIAL_CLASS_MASK].get();
    }
  
    inline Module* Object::lookup_begin(STATE) const {
      return reinterpret_cast<Module*>(direct_class(state));
    }
  
    inline bool Object::symbol_p() const {
      return __SYMBOL_P__(this);
    }
  
    inline void Object::write_barrier(STATE, Fixnum* obj) {
      /* No-op */
    }
  
    inline void Object::write_barrier(STATE, Symbol* obj) {
      /* No-op */
    }
  
    inline void Object::write_barrier(STATE, void* ptr) {
      Object* obj = reinterpret_cast<Object*>(ptr);
      state->memory()->write_barrier(this, obj);
    }
  
    inline void Object::write_barrier(VM* vm, void* ptr) {
      Object* obj = reinterpret_cast<Object*>(ptr);
      vm->om->write_barrier(this, obj);
    }
  
    // Used in filtering APIs
    class ObjectMatcher {
    public:
      virtual ~ObjectMatcher() {}
      virtual bool match_p(STATE, Object* obj) = 0;
    };
  
    class ObjectMatchAll : public ObjectMatcher {
    public:
      virtual ~ObjectMatchAll() {}
      virtual bool match_p(STATE, Object* obj) { return true; }
    };
  
  }
  
  #endif
  