Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: rubinius/rubinius
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 2bf206d50c0f
Choose a base ref
...
head repository: rubinius/rubinius
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 636abb1a37df
Choose a head ref

Commits on Aug 31, 2015

  1. Copy the full SHA
    7444a80 View commit details
  2. Copy the full SHA
    2560bb8 View commit details
  3. Copy the full SHA
    7277010 View commit details
  4. Removed GCToken.

    This was a well-intentioned idea but not practical or useful.
    
    The idea was to have the compiler help check where in call paths a
    garbage-collection cycle could run. Unfortnately, adding this in as an
    after-thought resulted in all the places where GCTokens are created from thin
    air deep in some call path. It didn't change the fact that GC could happen
    pretty much anywhere.
    
    In a managed runtime, either GC can happen everywhere or it should only happen
    at a very small number of extremely well-defined points.  The middle ground of
    "it can happen at all these places" is an invitation for a low budget horror
    movie, dismembered objects strewn throughout the code.
    
    Along with the rework of the stop-the-world mechanism, the removal of GCToken
    and restricting the invocation of a GC cycle to a single well-defined method
    call in a few well-defined locations, and finally, making all allocation paths
    GC-safe (ie GC will NOT run when allocating an object), Rubinius will have much
    better defined GC behavior.
    
    The GC safe allocation path is important for cases like the string_dup
    instruction, where a young GC cycle could run when allocating the dup and the
    original String (eg a literal String in a method) is in the young generation
    and moved. Since the original String is on the C stack and not in a GC root
    object, the dup fails when copying the contents of the original String. It's
    better to make allocation GC-safe than to accept the performance cost of the GC
    root in these sorts of cases. Also, that case is only one well-defined instance
    of the issue. There are more complicated ones.
    brixen committed Aug 31, 2015
    Copy the full SHA
    bace448 View commit details
  5. Reworked allocation.

    These changes introduce a couple things:
    
    1. All allocation paths are GC-safe.
    
    What that means is that when requesting a new object be created, the request
    will be fulfilled *unless* the system (or process limits prevent it) *without*
    GC running. In other words, there are two possible results of allocating an
    object: 1) a new object, or 2) an exception because no more memory is
    available to the process.
    
    In either case, from the point the object is requested until that request
    returns (or the return is bypassed by the exception unwind), the GC will not
    run.
    
    There is a trade-off here between running the GC at the instant that some
    threshold is breached (eg the eden space is exhausted) and loosening some
    requirements that must be maintained for a generational, moving garbage
    collector (ie every object reference must be known to the GC at the time the
    GC runs). Since we run GC on method entry and loop back branches, there is no
    reasonable scenario in which deferring GC until allocation has completed will
    result in unwanted object graph thresholds being breached pathologically (eg
    an execution path where allocation can grow unbounded).
    
    2. All objects are allocated from the various heaps *uninitialized* and a
    protocol is established to call an initialization routine on the objects.
    
    The initialization routine is `T::initialize(State* state, T* obj)`, where T is
    the type of object being allocated. The method is a static method of the class
    of the object. This breaks with the protocol that Ruby uses where `new` is a
    module method and `initialize` is an instance method. The primary reason for
    choosing a static (ie C++ class) is to avoid an instance method operating on
    an incompletely initialized object.
    
    One purpose of this initialization protocol is to eliminate or reduce the
    double initialization that we were doing (ie setting all fields to nil and
    then initializing them to other default values). The main initialization
    method shown above may be an empty body, in which case the compiler will elide
    it anyway and there's no overhead to the protocol. In that case, another
    initialization method should be called on the newly created object. Since the
    allocation method is templated and if the initialization method is visible (ie
    in the header file), the compiler should be able to elide remaining double
    initialization in most contexts.
    brixen committed Aug 31, 2015
    Copy the full SHA
    ca3011d View commit details
  6. Fixed VM tests.

    brixen committed Aug 31, 2015
    Copy the full SHA
    3fde9fb View commit details
  7. Fixed triggering GC.

    brixen committed Aug 31, 2015
    Copy the full SHA
    3c05ffa View commit details
  8. Fixed some class creation.

    brixen committed Aug 31, 2015
    Copy the full SHA
    08372d6 View commit details
  9. Copy the full SHA
    1743a37 View commit details
  10. Copy the full SHA
    10323d5 View commit details
  11. Delay tracking VM objects until Thread is running.

    In the case of `Thread.new`, the OS thread will never run because a
    ThreadError exception is raised when no block is passed. If we track the VM
    object that would ultimately contain the reference to the OS thread, we either
    need a way to remove the VM object when eg `Thread.new` raises an exception or
    we will leak these objects. Instead of tracking and then untracking the VM
    object, we create the object untracked and track it if the OS thread starts
    executing.
    brixen committed Aug 31, 2015
    Copy the full SHA
    66fca42 View commit details
  12. Copy the full SHA
    2834234 View commit details
  13. Copy the full SHA
    37da04e View commit details
  14. Fixes to build on Trusty.

    brixen committed Aug 31, 2015
    Copy the full SHA
    efa33da View commit details
  15. Copy the full SHA
    dc4ad6e View commit details
  16. Copy the full SHA
    8d2a439 View commit details
  17. Copy the full SHA
    87821c5 View commit details

Commits on Sep 2, 2015

  1. Properly guard JIT specs.

    brixen committed Sep 2, 2015
    Copy the full SHA
    b5975f2 View commit details
  2. Copy the full SHA
    3291521 View commit details
  3. Reworked when GC is invoked.

    brixen committed Sep 2, 2015
    Copy the full SHA
    bb3864e View commit details
  4. Copy the full SHA
    6c2f41f View commit details

Commits on Sep 5, 2015

  1. Copy the full SHA
    f8271d2 View commit details
  2. Improve triggering GC.

    brixen committed Sep 5, 2015
    Copy the full SHA
    5a588d5 View commit details
  3. Copy the full SHA
    10b38c2 View commit details
  4. Copy the full SHA
    6dc58e3 View commit details
  5. Copy the full SHA
    951aeb0 View commit details
  6. Copy the full SHA
    0521c3b View commit details
  7. Copy the full SHA
    1f4f82d View commit details

Commits on Sep 12, 2015

  1. Immix sets collect flag.

    brixen committed Sep 12, 2015
    Copy the full SHA
    5daca40 View commit details

Commits on Nov 30, 2015

  1. Pulled check outside of loop.

    brixen committed Nov 30, 2015
    Copy the full SHA
    ff93ae9 View commit details

Commits on Dec 30, 2015

  1. Merge branch 'master' into stw

    brixen committed Dec 30, 2015
    Copy the full SHA
    891bbce View commit details
  2. Fixed VM tests.

    brixen committed Dec 30, 2015
    Copy the full SHA
    899dca7 View commit details

Commits on Dec 31, 2015

  1. Copy the full SHA
    d265ed9 View commit details
  2. Satisfy gcc 4.8.4.

    brixen committed Dec 31, 2015
    Copy the full SHA
    d43ae9c View commit details

Commits on Jan 17, 2016

  1. Copy the full SHA
    aa242ae View commit details
  2. Copy the full SHA
    a8fec90 View commit details

Commits on Jan 18, 2016

  1. Copy the full SHA
    5d651e9 View commit details
  2. Copy the full SHA
    172e032 View commit details
  3. Copy the full SHA
    f03ab0a View commit details

Commits on Jan 19, 2016

  1. Reworked ThreadNexus.

    brixen committed Jan 19, 2016
    Copy the full SHA
    ce0c08d View commit details
  2. Copy the full SHA
    6224161 View commit details
  3. Copy the full SHA
    d332e3e View commit details
  4. Copy the full SHA
    b603b61 View commit details

Commits on Jan 20, 2016

  1. Reworked triggering GC.

    brixen committed Jan 20, 2016
    Copy the full SHA
    78235a0 View commit details
  2. Copy the full SHA
    b5197aa View commit details

Commits on Jan 23, 2016

  1. Copy the full SHA
    20cd1d3 View commit details
  2. Copy the full SHA
    0d1859b View commit details

Commits on Jan 24, 2016

  1. Removed BakerGC.

    brixen committed Jan 24, 2016
    Copy the full SHA
    03f8943 View commit details
  2. Introduce SleepPhase.

    Thread semantics are ad hoc in Ruby so we make a best effort to mimic them
    where possible. The behavior of process exit when one or more threads are
    suspended in a sleep state is not well-defined. We assume that no sleeping
    thread should block the process from exiting. We introduce a specific "sleep
    phase" as one state a thread may be in. We then ignore sleeping threads when
    executing a process exit.
    
    Unfortunately, this is more complex than it appears on its face. While
    executing a process exit, we are essentially racing any sleeping threads that
    may wake up and attempt to access resources that are being destroyed (something
    like one of those scenes from Inception with the buildings crumbling around the
    participants). We cannot waking thread proceed once process exit has started,
    so we permanently lock a mutex that every waking thread must acquire before
    progressing.
    
    Ultimately, these lock resources will need to be in the program's data segment,
    so they are static memory, not dynamically allocated, as they are now.
    brixen committed Jan 24, 2016
    Copy the full SHA
    903aae1 View commit details

Commits on Jan 25, 2016

  1. Copy the full SHA
    4918136 View commit details
Showing 680 changed files with 10,186 additions and 10,690 deletions.
17 changes: 6 additions & 11 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -73,25 +73,20 @@ Gemfile.installed.lock
# don't ignore spec/tags
!/spec/tags

/vm/log
/vm/.deps
/vm/vm.exe
/machine/log
/machine/.deps
/machine/vm.exe

/vm/test/ruby.h
/machine/test/ruby.h

# rubysl-digest installs this header
vm/include/capi/ruby/digest.h
machine/include/capi/ruby/digest.h

/core/signature.rb
/core/build_config.rb

# Generated documentation
doc/generated/vm
web/doc/*/*.bak
web/doc/*/*.new

# Ignore generated DTrace header
vm/dtrace/probes.h
machine/dtrace/probes.h

# Ignore rubygems except bundled ones
vendor/cache/*
2 changes: 1 addition & 1 deletion Rakefile
Original file line number Diff line number Diff line change
@@ -32,7 +32,7 @@ BUILD_CONFIG = {} unless Object.const_defined? :BUILD_CONFIG

def load_configuration
config_rb = File.expand_path "../config.rb", __FILE__
config_h = File.expand_path "../vm/gen/config.h", __FILE__
config_h = File.expand_path "../machine/gen/config.h", __FILE__

unless File.exist?(config_rb) and File.exist?(config_h)
if $cleaning
18 changes: 9 additions & 9 deletions configure
Original file line number Diff line number Diff line change
@@ -100,12 +100,12 @@ class Configure

@stagingdir = nil
@build_prefix = nil
@capi_includedir = "#{@sourcedir}/vm/include/capi"
@capi_includedir = "#{@sourcedir}/machine/include/capi"

@runtime_gems_dir = nil
@bootstrap_gems_dir = nil

@vm_release_h = File.join(root, "/vm/gen/release.h")
@vm_release_h = File.join(root, "/machine/gen/release.h")

@preserve_prefix = false

@@ -241,7 +241,7 @@ class Configure
@vendordir = @prefixdir + "/vendor" unless @vendordir
@mandir = @prefixdir + "/man" unless @mandir
@gemsdir = @prefixdir + "/gems" unless @gemsdir
@includedir = @prefixdir + "/vm/include/capi" unless @includedir
@includedir = @prefixdir + "/machine/include/capi" unless @includedir

@encdir = @libdir + "/encoding/converter"

@@ -1626,9 +1626,9 @@ int main() { return tgetnum(""); }
FileUtils.cp @config, "#{@sourcedir}/core/build_config.rb"

# Write the config file used to build the C++ VM.
Dir.mkdir "vm/gen" unless File.directory? "vm/gen"
Dir.mkdir "machine/gen" unless File.directory? "machine/gen"

vm_paths_h = "vm/gen/paths.h"
vm_paths_h = "machine/gen/paths.h"
File.open vm_paths_h, "wb" do |f|
f.puts <<-EOF
#define RBX_PREFIX_PATH "#{@prefixdir}"
@@ -1645,7 +1645,7 @@ int main() { return tgetnum(""); }
EOF
end

vm_config_h = "vm/gen/config.h"
vm_config_h = "machine/gen/config.h"
File.open vm_config_h, "wb" do |f|
f.puts <<-EOC
#define RBX_PROGRAM_NAME "#{@program_name}"
@@ -1746,8 +1746,8 @@ int main() { return tgetnum(""); }
end
end

# Create C-API header for vm/test
File.open "vm/test/ruby.h", "w" do |f|
# Create C-API header for machine/test
File.open "machine/test/ruby.h", "w" do |f|
f.puts %[#include "#{@capi_includedir}/ruby.h"]
end
end
@@ -1758,7 +1758,7 @@ int main() { return tgetnum(""); }
cat("config.rb")
puts "\nSetting the following defines for the VM"
puts "----------------------------------------"
cat("vm/gen/config.h")
cat("machine/gen/config.h")
end

def cat(file)
2 changes: 1 addition & 1 deletion core/class.rb
Original file line number Diff line number Diff line change
@@ -14,7 +14,7 @@ def set_superclass(sup)

def initialize(sclass=Object, name=nil, under=nil)
raise TypeError, "already initialized class" if @instance_type
raise TypeError, "can't make subclass of Class" if sclass.equal?(Class)
raise TypeError, "can't make subclass of Class" if Class.equal?(sclass)

set_superclass sclass

2 changes: 1 addition & 1 deletion core/compiled_code.rb
Original file line number Diff line number Diff line change
@@ -173,7 +173,7 @@ def block_index
#
# @return [String]
def inspect
"#<#{self.class.name} #{@name} file=#{@file}>"
"#<#{self.class.name}:0x#{object_id.to_s(16)} #{@name} file=#{@file}>"
end

##
5 changes: 5 additions & 0 deletions core/iseq.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
module Rubinius
class InstructionSequence
def self.allocate
Rubinius.primitive :instruction_sequence_allocate
raise PrimitiveFailure, "Rubinius::InstructionSequence.allocate primitive failed"
end

def initialize(size)
if size.kind_of? Tuple
@opcodes = size
191 changes: 41 additions & 150 deletions core/thread.rb
Original file line number Diff line number Diff line change
@@ -6,30 +6,54 @@
class Thread
attr_reader :recursive_objects
attr_reader :pid
attr_reader :exception

def self.start(*args)
raise ArgumentError.new("no block passed to Thread.start") unless block_given?
def self.new(*args, &block)
thr = Rubinius.invoke_primitive :thread_s_new, args, block, self

thr = Rubinius.invoke_primitive :thread_allocate, self

Rubinius.asm(args, thr) do |args, obj|
run obj
dup
Rubinius::VariableScope.of_sender.locked!

run args
push_block
send_with_splat :__thread_initialize__, 0, true
# no pop here, as .asm blocks imply a pop as they're not
# allowed to leak a stack value
unless thr.send :initialized?
raise ThreadError, "Thread#initialize not called"
end

return thr
end

def self.start(*args, &block)
raise ArgumentError.new("no block passed to Thread.start") unless block

Rubinius.invoke_primitive :thread_s_start, args, block, self
end

class << self
alias_method :fork, :start
end

def initialize(*args, &block)
unless block
Kernel.raise ThreadError, "no block passed to Thread#initialize"
end

if @initialized
Kernel.raise ThreadError, "already initialized thread"
end

@args = args
@block = block
@initialized = true

Thread.current.group.add self
end

alias_method :__thread_initialize__, :initialize

def initialized?
@initialized
end

private :initialized?

def self.current
Rubinius.primitive :thread_current
Kernel.raise PrimitiveFailure, "Thread.current primitive failed"
@@ -54,21 +78,6 @@ def self.stop
nil
end

def fork
Rubinius.primitive :thread_fork
Kernel.raise ThreadError, "Thread#fork failed, thread already started or dead"
end

def raise_prim(exc)
Rubinius.primitive :thread_raise
Kernel.raise PrimitiveFailure, "Thread#raise primitive failed"
end

def kill_prim
Rubinius.primitive :thread_kill
Kernel.raise PrimitiveFailure, "Thread#kill primitive failed"
end

def wakeup
Rubinius.primitive :thread_wakeup
Kernel.raise ThreadError, "Thread#wakeup primitive failed, thread may be dead"
@@ -95,21 +104,6 @@ def mri_backtrace
Kernel.raise PrimitiveFailure, "Thread#mri_backtrace primitive failed"
end

def unlock_locks
Rubinius.primitive :thread_unlock_locks
Kernel.raise PrimitiveFailure, "Thread#unlock_locks primitive failed"
end

def current_exception
Rubinius.primitive :thread_current_exception
Kernel.raise PrimitiveFailure, "Thread#current_exception primitive failed"
end

def set_exception(exception)
Rubinius.primitive :thread_set_exception
Kernel.raise PrimitiveFailure, "Thread#set_exception primitive failed"
end

@abort_on_exception = false

def self.abort_on_exception
@@ -138,50 +132,6 @@ def inspect

alias_method :to_s, :inspect

def self.new(*args)
thr = Rubinius.invoke_primitive :thread_allocate, self

Rubinius::VariableScope.of_sender.locked!

Rubinius.asm(args, thr) do |args, obj|
run obj
dup

run args
push_block
send_with_splat :initialize, 0, true
# no pop here, as .asm blocks imply a pop as they're not
# allowed to leak a stack value
end

unless thr.thread_is_setup?
raise ThreadError, "Thread#initialize not called"
end

return thr
end

def initialize(*args, &block)
unless block
Kernel.raise ThreadError, "no block passed to Thread#initialize"
end

@args = args
@block = block

th_group = Thread.current.group

th_group.add self

fork
end

alias_method :__thread_initialize__, :initialize

def thread_is_setup?
@block != nil
end

def alive?
Rubinius.synchronize(self) do
@alive
@@ -233,14 +183,9 @@ def group
end

def raise(exc=undefined, msg=nil, trace=nil)
Rubinius.lock(self)

unless @alive
Rubinius.unlock(self)
return self
end
Rubinius.synchronize(self) do
return self unless @alive

begin
if undefined.equal? exc
no_argument = true
exc = active_exception
@@ -265,13 +210,10 @@ def raise(exc=undefined, msg=nil, trace=nil)
if self == Thread.current
Kernel.raise exc
else
raise_prim exc
Rubinius.invoke_primitive :thread_raise, self, exc
end
ensure
Rubinius.unlock(self)
end
end
private :raise_prim

def [](key)
locals_aref(Rubinius::Type.coerce_to_symbol(key))
@@ -355,61 +297,10 @@ def self.kill(thread)

alias_method :run, :wakeup

# Called by Thread#fork in the new thread
#
def __run__
begin
begin
Rubinius.unlock(self)
@result = @block.call(*@args)
ensure
begin
# We must lock self in a careful way.
#
# At this point, it's possible that an other thread does Thread#raise
# and then our execution is interrupted AT ANY GIVEN TIME. We
# absolutely must make sure to lock self as soon as possible to lock
# out interrupts from other threads.
#
# Rubinius.uninterrupted_lock(self) just does that.
#
# Notice that this can't be moved to other methods and there should be
# no preceding code before it in the enclosing ensure clause.
# These are to prevent any interrupted lock failures.
Rubinius.uninterrupted_lock(self)

# Now, we locked self. No other thread can interrupt this thread
# anymore.
# If there is any not-triggered interrupt, check and process it. In
# either case, we jump to the following ensure clause.
Rubinius.check_interrupts
ensure
unlock_locks
end
end
rescue Exception => e
set_exception e

STDERR.puts "Exception in thread: #{e.message} (#{e.class})" if $DEBUG

if abort_on_exception or Thread.abort_on_exception
Thread.main.raise e
end
ensure
Rubinius::Mirror.reflect(@group).remove self

if Rubinius.thread_state[0] == :thread_kill
@killed = true
end

Rubinius.unlock(self)
end
end

def kill
@sleep = false
Rubinius.synchronize(self) do
kill_prim
Rubinius.invoke_primitive :thread_kill, self
end
self
end
@@ -419,7 +310,7 @@ def kill

def value
join
@killed ? nil : @result
@value
end

def active_exception
14 changes: 14 additions & 0 deletions core/thread_mirror.rb
Original file line number Diff line number Diff line change
@@ -4,6 +4,20 @@ class Thread < Mirror
def group=(group)
Rubinius.invoke_primitive :object_set_ivar, @object, :@group, group
end

def finish
Rubinius::Mirror.reflect(@object.group).remove @object

if exception = @object.exception
if $DEBUG
STDERR.puts "Exception in thread: #{exception.message} (#{exception.class})"
end

if @object.abort_on_exception or Thread.abort_on_exception
Thread.main.raise exception
end
end
end
end
end
end
4 changes: 2 additions & 2 deletions core/vm.rb
Original file line number Diff line number Diff line change
@@ -5,11 +5,11 @@ class Rubinius::VM
# Rubinius::VariableScope object that can be used to access the frames
# running information like locals, self, etc.
#
def self.backtrace(frames_to_skip, include_vars=false)
def self.backtrace(frames_to_skip)
Rubinius.primitive :vm_backtrace

# Add the + 1 to skip this frame
backtrace(Integer(frames_to_skip) + 1, include_vars)
backtrace Integer(frames_to_skip) + 1
end

def self.stats
15 changes: 11 additions & 4 deletions library/rubinius/configuration.rb
Original file line number Diff line number Diff line change
@@ -10,6 +10,13 @@
"Path for the compiled code cache CodeDB"
end

c.section "memory" do |s|
s.section "collection" do |c|
c.vm_variable "log", false,
"Log when collections are triggered and run"
end
end

c.section "gc" do |s|
s.vm_variable "young_bytes", (30 * 1024 * 1024),
"The number of bytes the young generation of the GC should use"
@@ -20,7 +27,7 @@
s.vm_variable "large_object", (1024 * 1024),
"The size (in bytes) of the large object threshold"

s.vm_variable "immix.concurrent", true,
s.vm_variable "immix.concurrent", false,
"Set whether we want the Immix mark phase to run concurrently"

s.vm_variable "immix.debug", :bool,
@@ -87,9 +94,9 @@
"The JIT will emit code to be sure JITd methods can be profiled"

s.section "inline" do |i|
i.vm_variable "generic", true, "Have the JIT inline generic methods"
i.vm_variable "generic", false, "Have the JIT inline generic methods"

i.vm_variable "blocks", true,
i.vm_variable "blocks", false,
"Have the JIT try to inline methods and their literal blocks"

i.vm_variable "debug", false,
@@ -138,7 +145,7 @@
"Lock around using CAPI methods"
end

c.vm_variable "int", false,
c.vm_variable "int", true,
:as => "jit_disabled",
:description => "Force the JIT to never turn on"

File renamed without changes.
File renamed without changes.
12 changes: 8 additions & 4 deletions vm/accessor_primitives.cpp → machine/accessor_primitives.cpp
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
#include "prelude.hpp"
#include "vm.hpp"
#include "primitives.hpp"
#include "gen/includes.hpp"
#include "arguments.hpp"
#include "call_frame.hpp"
#include "defines.hpp"
#include "primitives.hpp"
#include "state.hpp"
#include "vm.hpp"

#include "builtin/class.hpp"

#include "gen/includes.hpp"

#include "instruments/tooling.hpp"

23 changes: 23 additions & 0 deletions machine/alloc.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#ifndef RBX_ALLOC_HPP
#define RBX_ALLOC_HPP

#include <stddef.h>

namespace rubinius {
#define FREE(obj) free(obj)
#define ALLOC_N(type, size) ((type*)calloc((size), sizeof(type)))
#define ALLOC(t) (t*)XMALLOC(sizeof(t))
#define REALLOC_N(v,t,n) (v)=(t*)realloc((void*)(v), sizeof(t)*n)

#define ALLOCA_N(type, size) ((type*)alloca(sizeof(type) * (size)))
#define ALLOCA(type) ((type*)alloca(sizeof(type)))
};

extern "C" {
void* XMALLOC(size_t bytes);
void XFREE(void* ptr);
void* XREALLOC(void* ptr, size_t bytes);
void* XCALLOC(size_t items, size_t bytes);
}

#endif
21 changes: 16 additions & 5 deletions vm/arguments.cpp → machine/arguments.cpp
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
#include "arguments.hpp"
#include "memory.hpp"
#include "state.hpp"
#include "vm.hpp"

#include "builtin/tuple.hpp"

namespace rubinius {
void Arguments::append(STATE, Array* ary) {
Tuple* tup = Tuple::create_dirty(state, ary->size() + total());
Tuple* tup =
state->memory()->new_fields<Tuple>(state, G(tuple), ary->size() + total());

for(uint32_t i = 0; i < total(); i++) {
tup->put(state, i, get_argument(i));
@@ -17,7 +23,8 @@ namespace rubinius {
}

void Arguments::prepend(STATE, Array* ary) {
Tuple* tup = Tuple::create_dirty(state, ary->size() + total());
Tuple* tup =
state->memory()->new_fields<Tuple>(state, G(tuple), ary->size() + total());

for(native_int i = 0; i < ary->size(); i++) {
tup->put(state, i, ary->get(state, i));
@@ -42,7 +49,8 @@ namespace rubinius {
}

void Arguments::unshift(STATE, Object* val) {
Tuple* tup = Tuple::create_dirty(state, total() + 1);
Tuple* tup =
state->memory()->new_fields<Tuple>(state, G(tuple), total() + 1);

tup->put(state, 0, val);

@@ -54,7 +62,8 @@ namespace rubinius {
}

void Arguments::unshift2(STATE, Object* one, Object* two) {
Tuple* tup = Tuple::create_dirty(state, total() + 2);
Tuple* tup =
state->memory()->new_fields<Tuple>(state, G(tuple), total() + 2);

tup->put(state, 0, one);
tup->put(state, 1, two);
@@ -70,7 +79,9 @@ namespace rubinius {
Object* first = arguments_[0];

if(argument_container_) {
Tuple* tup = Tuple::create_dirty(state, total() - 1);
Tuple* tup =
state->memory()->new_fields<Tuple>(state, G(tuple), total() - 1);

for(uint32_t i = 1; i < total_; i++) {
tup->put(state, i - 1, get_argument(i));
}
6 changes: 4 additions & 2 deletions vm/arguments.hpp → machine/arguments.hpp
Original file line number Diff line number Diff line change
@@ -6,9 +6,11 @@
#include "builtin/tuple.hpp"

namespace rubinius {
class Array;
namespace memory {
class GarbageCollector;
}

class GarbageCollector;
class Array;

class Arguments {
Symbol* name_;
2 changes: 2 additions & 0 deletions vm/bug.hpp → machine/bug.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#ifndef RBX_BUG_HPP
#define RBX_BUG_HPP

#include <sys/types.h>

#ifndef NORETURN
#define NORETURN(x) __attribute__ ((noreturn)) x
#endif
Original file line number Diff line number Diff line change
@@ -1,56 +1,50 @@
#include "arguments.hpp"
#include "object_utils.hpp"
#include "memory.hpp"

#include "builtin/access_variable.hpp"
#include "builtin/class.hpp"
#include "builtin/executable.hpp"
#include "builtin/exception.hpp"
#include "builtin/packed_object.hpp"
#include "builtin/symbol.hpp"
#include "object_utils.hpp"
#include "object_memory.hpp"
#include "ontology.hpp"

namespace rubinius {

void AccessVariable::init(STATE) {
// HACK test superclass of AccessVariable
GO(access_variable).set(ontology::new_class(state,
"AccessVariable", G(executable), G(rubinius)));
G(access_variable)->set_object_type(state, AccessVariableType);
void AccessVariable::bootstrap(STATE) {
GO(access_variable).set(state->memory()->new_class<Class, AccessVariable>(
state, G(executable), G(rubinius), "AccessVariable"));
}

AccessVariable* AccessVariable::allocate(STATE) {
AccessVariable* av = state->new_object<AccessVariable>(G(access_variable));
av->inliners_ = 0;
av->prim_index_ = -1;
av->custom_call_site_ = false;
av->set_executor(AccessVariable::access_execute);
return av;
return state->memory()->new_object<AccessVariable>(state, G(access_variable));
}

Object* AccessVariable::access_read_regular_ivar(STATE, CallFrame* call_frame, Executable* exec, Module* mod,
Arguments& args) {
Object* AccessVariable::access_read_regular_ivar(STATE,
Executable* exec, Module* mod, Arguments& args)
{
AccessVariable* access = as<AccessVariable>(exec);
if(unlikely(args.total() != 0)) {
Exception::argument_error(state, 0, args.total());
Exception::raise_argument_error(state, 0, args.total());
return NULL;
}

Object* recv = args.recv();
return recv->get_ivar(state, access->name());
}

Object* AccessVariable::access_write_regular_ivar(STATE, CallFrame* call_frame, Executable* exec, Module* mod,
Object* AccessVariable::access_write_regular_ivar(STATE, Executable* exec, Module* mod,
Arguments& args) {
AccessVariable* access = as<AccessVariable>(exec);
if(unlikely(args.total() != 1)) {
Exception::argument_error(state, 1, args.total());
Exception::raise_argument_error(state, 1, args.total());
return NULL;
}

Object* recv = args.recv();

if(CBOOL(recv->frozen_p(state)) && CBOOL(recv->frozen_mod_disallowed(state))) {
Exception::frozen_error(state, call_frame, recv);
Exception::frozen_error(state, recv);
return 0;
}

@@ -59,20 +53,20 @@ namespace rubinius {

/* Run when an AccessVariable is executed. Uses the details in exec
* to access instance variables of args.recv() */
Object* AccessVariable::access_execute(STATE, CallFrame* call_frame, Executable* exec, Module* mod,
Object* AccessVariable::access_execute(STATE, Executable* exec, Module* mod,
Arguments& args) {
AccessVariable* access = as<AccessVariable>(exec);
Object* const self = args.recv();

/* The writer case. */
if(access->write()->true_p()) {
if(CBOOL(self->frozen_p(state)) && CBOOL(self->frozen_mod_disallowed(state))) {
Exception::frozen_error(state, call_frame, self);
Exception::frozen_error(state, self);
return 0;
}

if(args.total() != 1) {
Exception::argument_error(state, 1, args.total());
Exception::raise_argument_error(state, 1, args.total());
return NULL;
}

@@ -98,7 +92,7 @@ namespace rubinius {

/* The read case. */
if(args.total() != 0) {
Exception::argument_error(state, 0, args.total());
Exception::raise_argument_error(state, 0, args.total());
return NULL;
}

Original file line number Diff line number Diff line change
@@ -25,12 +25,19 @@ namespace rubinius {

/* interface */

static void init(STATE);
static void bootstrap(STATE);
static void initialize(STATE, AccessVariable* av) {
Executable::initialize(state, av, AccessVariable::access_execute);

av->name_ = nil<Symbol>();
av->write_ = nil<Object>();
}

// Rubinius.primitive :accessvariable_allocate
static AccessVariable* allocate(STATE);
static Object* access_execute(STATE, CallFrame* call_frame, Executable* exec, Module* mod, Arguments& args);
static Object* access_read_regular_ivar(STATE, CallFrame* call_frame, Executable* exec, Module* mod, Arguments& args);
static Object* access_write_regular_ivar(STATE, CallFrame* call_frame, Executable* exec, Module* mod, Arguments& args);
static Object* access_execute(STATE, Executable* exec, Module* mod, Arguments& args);
static Object* access_read_regular_ivar(STATE, Executable* exec, Module* mod, Arguments& args);
static Object* access_write_regular_ivar(STATE, Executable* exec, Module* mod, Arguments& args);

class Info : public Executable::Info {
public:
30 changes: 30 additions & 0 deletions machine/builtin/alias.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#include "memory.hpp"

#include "builtin/alias.hpp"
#include "builtin/class.hpp"
#include "builtin/exception.hpp"

namespace rubinius {
void Alias::bootstrap(STATE) {
GO(alias).set(state->memory()->new_class<Class, Alias>(
state, G(executable), G(rubinius), "Alias"));
}

Object* Alias::executor(STATE, Executable* exe,
Module* mod, Arguments& args)
{
Exception::type_error(state, "Unable to directly execute a Alias");
return 0;
}

// Create a new Alias object
Alias* Alias::create(STATE, Symbol* name, Module* mod, Executable* exec) {
Alias* alias = state->memory()->new_object<Alias>(state, G(alias));

alias->original_name(state, name);
alias->original_module(state, mod);
alias->original_exec(state, exec);

return alias;
}
}
15 changes: 14 additions & 1 deletion vm/builtin/alias.hpp → machine/builtin/alias.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#ifndef RBX_BUILTIN_ALIAS_HPP
#define RBX_BUILTIN_ALIAS_HPP

#include "object_utils.hpp"

#include "builtin/executable.hpp"

namespace rubinius {
@@ -18,7 +20,18 @@ namespace rubinius {
attr_accessor(original_module, Module);
attr_accessor(original_exec, Executable);

static void init(STATE);
static Object* executor(STATE,
Executable* exe, Module* mod, Arguments& args);

static void bootstrap(STATE);
static void initialize(STATE, Alias* alias) {
Executable::initialize(state, alias, Alias::executor);

alias->original_name_ = nil<Symbol>();
alias->original_module_ = nil<Module>();
alias->original_exec_ = nil<Executable>();
}

static Alias* create(STATE, Symbol* name, Module* mod, Executable* exec);

class Info : public Executable::Info {
117 changes: 71 additions & 46 deletions vm/builtin/array.cpp → machine/builtin/array.cpp
Original file line number Diff line number Diff line change
@@ -1,20 +1,25 @@
#include "arguments.hpp"
#include "configuration.hpp"
#include "dispatch.hpp"
#include "object_utils.hpp"
#include "memory.hpp"
#include "on_stack.hpp"

#include "builtin/array.hpp"
#include "builtin/class.hpp"
#include "builtin/exception.hpp"
#include "builtin/fixnum.hpp"
#include "builtin/tuple.hpp"
#include "configuration.hpp"
#include "dispatch.hpp"
#include "object_utils.hpp"
#include "ontology.hpp"

/* Implementation certain Array methods. These methods are just
* the ones the VM requires, not the entire set of all Array methods.
* This includes methods required to implement certain Array
* primitives. */

namespace rubinius {
void Array::bootstrap(STATE) {
GO(array).set(Class::bootstrap_class(state, G(object), ArrayType));
}

native_int Array::size() {
return total_->to_native();
@@ -29,21 +34,27 @@ namespace rubinius {
}

Array* Array::create(STATE, native_int size) {
Array* ary;
ary = state->new_object_dirty<Array>(G(array));
ary->tuple(state, Tuple::create(state, size));
ary->start(state, Fixnum::from(0));
ary->total(state, Fixnum::from(0));
Array* ary = state->memory()->new_object<Array>(state, G(array));
Tuple* tup = Tuple::create(state, size);

if(ary->young_object_p()) {
ary->tuple_ = tup;
} else {
ary->tuple(state, tup);
}

return ary;
}

Array* Array::create_dirty(STATE, native_int size) {
Array* ary;
ary = state->new_object_dirty<Array>(G(array));
ary->tuple(state, Tuple::create_dirty(state, size));
ary->start(state, Fixnum::from(0));
ary->total(state, Fixnum::from(0));
Array* ary = state->memory()->new_object<Array>(state, G(array));
Tuple* tup = state->memory()->new_fields<Tuple>(state, G(tuple), size);

if(ary->young_object_p()) {
ary->tuple_ = tup;
} else {
ary->tuple(state, tup);
}

return ary;
}
@@ -61,7 +72,7 @@ namespace rubinius {
native_int size = sub->total()->to_native();
if(size < 0) return force_as<Array>(Primitives::failure());

Array* ary = state->new_object_dirty<Array>(G(array));
Array* ary = state->memory()->new_object<Array>(state, G(array));
ary->start(state, Fixnum::from(0));
ary->total(state, Fixnum::from(size));
ary->tuple(state, Tuple::create(state, size < 1 ? 1 : size));
@@ -72,31 +83,38 @@ namespace rubinius {
}

Array* Array::new_range(STATE, Fixnum* start, Fixnum* count) {
Array* ary = state->new_object_dirty<Array>(class_object(state));
ary->total(state, count);
ary->start(state, Fixnum::from(0));
Array* ary = state->memory()->new_object<Array>(state, class_object(state));

native_int total = count->to_native();
if(total <= 0) {
ary->total(state, Fixnum::from(0));
ary->tuple(state, Tuple::create(state, 0));
} else {
Tuple* tup = Tuple::create_dirty(state, total);
Tuple* orig = tuple_;
ary->total(state, count);

for(native_int i = 0, j = start->to_native(); i < total; i++, j++) {
tup->put(state, i, orig->at(state, j));
Tuple* tup = state->memory()->new_fields<Tuple>(state, G(tuple), total);

if(tup->young_object_p()) {
for(native_int i = 0, j = start->to_native(); i < total; i++, j++) {
tup->field[i] = tuple_->field[j];
}
} else {
for(native_int i = 0, j = start->to_native(); i < total; i++, j++) {
tup->put(state, i, tuple_->field[j]);
}
}

ary->tuple(state, tup);
if(ary->young_object_p()) {
ary->tuple_ = tup;
} else {
ary->tuple(state, tup);
}
}

return ary;
}

Array* Array::new_reserved(STATE, Fixnum* count) {
Array* ary = state->new_object_dirty<Array>(class_object(state));
ary->start(state, Fixnum::from(0));
ary->total(state, Fixnum::from(0));
Array* ary = state->memory()->new_object<Array>(state, class_object(state));

native_int total = count->to_native();
if(total <= 0) total = 1;
@@ -116,29 +134,28 @@ namespace rubinius {
return ary;
}

Array* Array::to_ary(STATE, Object* value, CallFrame* call_frame) {
Array* Array::to_ary(STATE, Object* value) {
if(Tuple* tup = try_as<Tuple>(value)) {
return Array::from_tuple(state, tup);
}

if(CBOOL(value->respond_to(state, G(sym_to_ary), cTrue))) {
Object* res = value->send(state, call_frame, G(sym_to_ary));
Object* res = value->send(state, G(sym_to_ary));
if(!res) return 0;

if(Array* ary = try_as<Array>(res)) {
return ary;
}

if(!res->nil_p()) {
Exception::type_error(state, "to_ary should return an Array", call_frame);
Exception::type_error(state, "to_ary should return an Array");
return 0;
}

// NOTE: On >= 1.9, if res is nil just fall through and return [value]
}

Array* ary = Array::create(state, 1);
ary->set(state, 0, value);

return ary;
}

@@ -206,19 +223,24 @@ namespace rubinius {
if(size == 0) size = 2;
while(size <= new_size) size *= 2;

Tuple* nt = Tuple::create_dirty(state, size);
Tuple* nt = state->memory()->new_fields<Tuple>(state, G(tuple), size);
nt->copy_from(state, tuple_, start_, total_, Fixnum::from(0));
nt->copy_from(state, other->tuple(), other->start(), other->total(), total_);

for(native_int i = new_size; i < size; i++) {
nt->put_nil(i);
nt->field[i] = cNil;
}

tuple(state, nt);
start(state, Fixnum::from(0));
if(young_object_p()) {
tuple_ = nt;
} else {
tuple(state, nt);
}

start_ = Fixnum::from(0);
}

total(state, Fixnum::from(new_size));
total_ = Fixnum::from(new_size);

return this;
}
@@ -270,16 +292,17 @@ namespace rubinius {

if(lend > 0) {
tuple_->put(state, lend-1, val);
start(state, Fixnum::from(lend-1));
total(state, Fixnum::from(new_size));
start_ = Fixnum::from(lend-1);
total_ = Fixnum::from(new_size);
} else {
Tuple* nt = Tuple::create_dirty(state, new_size);
nt->copy_from(state, tuple_, start_, total_,
Fixnum::from(1));
Tuple* nt = state->memory()->new_fields<Tuple>(state, G(tuple), new_size);

nt->copy_from(state, tuple_, start_, total_, Fixnum::from(1));
nt->put(state, 0, val);

total(state, Fixnum::from(new_size));
start(state, Fixnum::from(0));
total_ = Fixnum::from(new_size);
start_ = Fixnum::from(0);

tuple(state, nt);
}
}
@@ -288,10 +311,12 @@ namespace rubinius {
native_int cnt = total_->to_native();

if(cnt == 0) return cNil;

Object* obj = get(state, 0);
set(state, 0, cNil);
start(state, Fixnum::from(start_->to_native() + 1));
total(state, Fixnum::from(cnt - 1));
start_ = Fixnum::from(start_->to_native() + 1);
total_ = Fixnum::from(cnt - 1);

return obj;
}

16 changes: 14 additions & 2 deletions vm/builtin/array.hpp → machine/builtin/array.hpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
#ifndef RBX_ARRAY_HPP
#define RBX_ARRAY_HPP

#include "object_utils.hpp"

#include "builtin/fixnum.hpp"
#include "builtin/object.hpp"
#include "builtin/tuple.hpp"

namespace rubinius {
class Tuple;
@@ -28,10 +32,18 @@ namespace rubinius {
native_int size();
native_int offset();
void set_size(native_int size);

static void bootstrap(STATE);
static void initialize(STATE, Array* array) {
array->total_ = Fixnum::from(0);
array->tuple_ = nil<Tuple>();
array->start_ = Fixnum::from(0);
}

static Array* create(STATE, native_int size);
static Array* create_dirty(STATE, native_int size);
static Array* from_tuple(STATE, Tuple* tup);
static Array* to_ary(STATE, Object* obj, CallFrame* frame);
static Array* to_ary(STATE, Object* obj);

// Rubinius.primitive :array_allocate
static Array* allocate(STATE, Object* self);
@@ -55,7 +67,7 @@ namespace rubinius {
Array* concat(STATE, Array* other);

// Rubinius.primitive :array_pack
String* pack(STATE, String* directives, CallFrame* calling_environment);
String* pack(STATE, String* directives);

Object* get(STATE, native_int idx);
Object* set(STATE, native_int idx, Object* val);
15 changes: 7 additions & 8 deletions vm/builtin/atomic.cpp → machine/builtin/atomic.cpp
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
#include "memory.hpp"

#include "builtin/atomic.hpp"
#include "builtin/class.hpp"
#include "ontology.hpp"

namespace rubinius {
void AtomicReference::init(STATE) {
GO(atomic_ref).set(ontology::new_class(state,
"AtomicReference", G(object), G(rubinius)));

G(atomic_ref)->set_object_type(state, AtomicReferenceType);
void AtomicReference::bootstrap(STATE) {
GO(atomic_ref).set(state->memory()->new_class<Class, AtomicReference>(
state, G(rubinius), "AtomicReference"));
}

AtomicReference* AtomicReference::allocate(STATE) {
return state->new_object<AtomicReference>(G(atomic_ref));
return state->memory()->new_object<AtomicReference>(state, G(atomic_ref));
}

AtomicReference* AtomicReference::create(STATE, Object* obj) {
@@ -24,7 +23,7 @@ namespace rubinius {
Object** pp = &value_;

if(atomic::compare_and_swap((void**)pp, old, new_)) {
this->write_barrier(state, new_);
state->memory()->write_barrier(this, new_);
return cTrue;
} else {
return cFalse;
8 changes: 7 additions & 1 deletion vm/builtin/atomic.hpp → machine/builtin/atomic.hpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
#ifndef RBX_BUILTIN_ATOMIC_HPP
#define RBX_BUILTIN_ATOMIC_HPP

#include "object_utils.hpp"

#include "builtin/object.hpp"

#include "util/atomic.hpp"

namespace rubinius {
@@ -17,7 +20,10 @@ namespace rubinius {
attr_accessor(value, Object);

public:
static void init(STATE);
static void bootstrap(STATE);
static void initialize(STATE, AtomicReference* ref) {
ref->value_ = nil<Object>();
}

static AtomicReference* allocate(STATE);
static AtomicReference* create(STATE, Object* val);
58 changes: 58 additions & 0 deletions machine/builtin/autoload.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
#include "helpers.hpp"
#include "memory.hpp"
#include "on_stack.hpp"

#include "builtin/autoload.hpp"
#include "builtin/class.hpp"

namespace rubinius {
void Autoload::bootstrap(STATE) {
GO(autoload).set(state->memory()->new_class<Class, Autoload>(state, "Autoload"));
}

Autoload* Autoload::create(STATE) {
return state->memory()->new_object<Autoload>(state, G(autoload));
}

Object* Autoload::resolve(STATE, Module* under, bool honor_require) {
Autoload* self = this;
OnStack<2> os(state, self, under);

Object* res = send(state, state->symbol("resolve"));
if(!res) return NULL;

if(CBOOL(res) || !honor_require) {
ConstantMissingReason reason = vNonExistent;
Object* constant = Helpers::const_get_under(
state, under, self->name(), &reason, self, true);

if(!constant) return NULL;
if(reason == vFound) return constant;

return Helpers::const_missing_under(state, under, self->name());
}

return cNil;
}

Object* Autoload::resolve(STATE, bool honor_require) {
Autoload* self = this;
OnStack<1> os(state, self);

Object* res = send(state, state->symbol("resolve"));
if(!res) return NULL;

if(CBOOL(res) || !honor_require) {
ConstantMissingReason reason = vNonExistent;
Object* constant = Helpers::const_get(
state, self->name(), &reason, self, true);

if(!constant) return NULL;
if(reason == vFound) return constant;

return Helpers::const_missing(state, self->name());
}

return cNil;
}
}
19 changes: 16 additions & 3 deletions vm/builtin/autoload.hpp → machine/builtin/autoload.hpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
#ifndef RBX_BUILTIN_AUTOLOAD_HPP
#define RBX_BUILTIN_AUTOLOAD_HPP

#include "object_utils.hpp"

#include "builtin/module.hpp"
#include "builtin/object.hpp"
#include "builtin/symbol.hpp"
#include "builtin/thread.hpp"

namespace rubinius {
struct CallFrame;
@@ -28,13 +33,21 @@ namespace rubinius {
attr_accessor(loaded, Object);

/** Register class with the VM. */
static void init(STATE);
static void bootstrap(STATE);
static void initialize(STATE, Autoload* obj) {
obj->name_ = nil<Symbol>();
obj->scope_ = nil<Module>();
obj->path_ = nil<Object>();
obj->constant_ = nil<Object>();
obj->thread_ = nil<Thread>();
obj->loaded_ = nil<Object>();
}

// Rubinius.primitive :autoload_allocate
static Autoload* create(STATE);

Object* resolve(STATE, GCToken gct, CallFrame* call_frame, Module* under, bool honor_require = false);
Object* resolve(STATE, GCToken gct, CallFrame* call_frame, bool honor_require = false);
Object* resolve(STATE, Module* under, bool honor_require = false);
Object* resolve(STATE, bool honor_require = false);

public: /* TypeInfo */

11 changes: 11 additions & 0 deletions machine/builtin/basic_object.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#include "memory.hpp"
#include "object_utils.hpp"

#include "builtin/basic_object.hpp"
#include "builtin/class.hpp"

namespace rubinius {
void BasicObject::bootstrap(STATE) {
GO(basicobject).set(Class::bootstrap_class(state, nil<Class>(), ObjectType));
}
}
Original file line number Diff line number Diff line change
@@ -10,7 +10,7 @@ namespace rubinius {
/** Class type identifier. */
static const object_type type = BasicObjectType;

static void init(STATE);
static void bootstrap(STATE);

public: /* accessors */

51 changes: 29 additions & 22 deletions vm/builtin/bignum.cpp → machine/builtin/bignum.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
#include <sstream>
#include "configuration.hpp"
#include "object_utils.hpp"
#include "memory.hpp"

#include "builtin/array.hpp"
#include "builtin/class.hpp"
@@ -8,10 +10,10 @@
#include "builtin/float.hpp"
#include "builtin/string.hpp"
#include "builtin/byte_array.hpp"
#include "configuration.hpp"

#include <sstream>

#include "missing/math.h"
#include "object_utils.hpp"
#include "ontology.hpp"

#define NEW_STRUCT(obj, str) \
obj = Bignum::create(state); \
@@ -136,15 +138,17 @@ namespace rubinius {
mp_clear(&b);
}

void Bignum::init(STATE) {
GO(bignum).set(ontology::new_class(state, "Bignum", G(integer)));
G(bignum)->set_object_type(state, BignumType);
void Bignum::bootstrap(STATE) {
GO(bignum).set(state->memory()->new_class<Class, Bignum>(
state, G(integer), "Bignum"));
}

namespace {
// Cripped and modified from bn_mp_init.c
// Cribbed and modified from bn_mp_init.c
void mp_init_managed(STATE, mp_int* a) {
ByteArray* storage = ByteArray::create_dirty(state, sizeof (mp_digit) * MP_PREC);
ByteArray* storage =
state->memory()->new_bytes<ByteArray>(
state, G(bytearray), sizeof (mp_digit) * MP_PREC);
a->managed = reinterpret_cast<void*>(storage);

/* allocate memory required and clear it */
@@ -163,11 +167,13 @@ namespace rubinius {
}
}

void Bignum::initialize(STATE, Bignum* obj) {
mp_init_managed(state, obj->mp_val());
obj->set_frozen();
}

Bignum* Bignum::create(STATE) {
Bignum* o = state->new_object_dirty<Bignum>(G(bignum));
mp_init_managed(state, o->mp_val());
o->set_frozen();
return o;
return state->memory()->new_object<Bignum>(state, G(bignum));
}

Bignum* Bignum::initialize_copy(STATE, Bignum* other) {
@@ -426,7 +432,7 @@ namespace rubinius {

Integer* Bignum::divide(STATE, Fixnum* denominator, Integer** remainder) {
if(denominator->to_native() == 0) {
Exception::zero_division_error(state, "divided by 0");
Exception::raise_zero_division_error(state, "divided by 0");
}

NMP;
@@ -459,7 +465,7 @@ namespace rubinius {

Integer* Bignum::divide(STATE, Bignum* b, Integer** remainder) {
if(mp_iszero(b->mp_val())) {
Exception::zero_division_error(state, "divided by 0");
Exception::raise_zero_division_error(state, "divided by 0");
}

NMP;
@@ -940,14 +946,14 @@ namespace rubinius {
native_int b = base->to_native();
mp_int* self = mp_val();
if(b < 2 || b > 36) {
Exception::argument_error(state, "base must be between 2 and 36");
Exception::raise_argument_error(state, "base must be between 2 and 36");
}

int sz = 0;
int digits;
mp_radix_size(self, b, &sz);
if(sz == 0) {
Exception::runtime_error(state, "couldn't convert bignum to string");
Exception::raise_runtime_error(state, "couldn't convert bignum to string");
}

String* str = String::create(state, Fixnum::from(sz));
@@ -1070,9 +1076,9 @@ namespace rubinius {
value = (d < 0) ? -d : d;

if(isinf(d)) {
Exception::float_domain_error(state, d < 0 ? "-Infinity" : "Infinity");
Exception::raise_float_domain_error(state, d < 0 ? "-Infinity" : "Infinity");
} else if(isnan(d)) {
Exception::float_domain_error(state, "NaN");
Exception::raise_float_domain_error(state, "NaN");
}

while(!(value <= (LONG_MAX >> 1)) || 0 != (long)value) {
@@ -1135,7 +1141,7 @@ namespace rubinius {
if(bits > size) {
std::ostringstream msg;
msg << "Bignum too large to fit in " << size << " bits";
Exception::range_error(state, msg.str().c_str());
Exception::raise_range_error(state, msg.str().c_str());
}
}

@@ -1161,7 +1167,8 @@ namespace rubinius {
assert(s);
State* state = reinterpret_cast<State*>(s);

ByteArray* storage = ByteArray::create_dirty(state, bytes);
ByteArray* storage =
state->memory()->new_bytes<ByteArray>(state, G(bytearray), bytes);
a->managed = reinterpret_cast<void*>(storage);

// Be sure to use the smaller value!
@@ -1175,7 +1182,7 @@ namespace rubinius {
return storage->raw_bytes();
}

void Bignum::Info::mark(Object* obj, ObjectMark& mark) {
void Bignum::Info::mark(Object* obj, memory::ObjectMark& mark) {
Bignum* big = force_as<Bignum>(obj);

mp_int* n = big->mp_val();
8 changes: 5 additions & 3 deletions vm/builtin/bignum.hpp → machine/builtin/bignum.hpp
Original file line number Diff line number Diff line change
@@ -17,7 +17,9 @@ namespace rubinius {

mp_int mp_val_;

static void init(STATE);
static void bootstrap(STATE);
static void initialize(STATE, Bignum* obj);

static Bignum* create(STATE);

static Bignum* from(STATE, int num);
@@ -209,10 +211,10 @@ namespace rubinius {
allow_user_allocate = false;
}

virtual void mark(Object* t, ObjectMark& mark);
virtual void mark(Object* t, memory::ObjectMark& mark);
virtual void show(STATE, Object* self, int level);
virtual void show_simple(STATE, Object* self, int level);
virtual void auto_mark(Object* obj, ObjectMark& mark) {}
virtual void auto_mark(Object* obj, memory::ObjectMark& mark) {}
};
};

Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
#include "arguments.hpp"
#include "call_frame.hpp"
#include "configuration.hpp"
#include "object_utils.hpp"
#include "memory.hpp"

#include "builtin/block_as_method.hpp"
#include "builtin/block_environment.hpp"
#include "builtin/class.hpp"
#include "builtin/exception.hpp"
#include "builtin/location.hpp"
#include "call_frame.hpp"
#include "configuration.hpp"
#include "object_utils.hpp"

namespace rubinius {
BlockAsMethod* BlockAsMethod::create(STATE, Object* self, BlockEnvironment* be) {
BlockAsMethod* pe = state->new_object<BlockAsMethod>(as<Class>(self));
BlockAsMethod* pe = state->memory()->new_object<BlockAsMethod>(state, as<Class>(self));
pe->block_env(state, be);
pe->inliners_ = 0;
pe->prim_index_ = -1;
@@ -19,7 +21,7 @@ namespace rubinius {
return pe;
}

Object* BlockAsMethod::block_executor(STATE, CallFrame* call_frame, Executable* exec, Module* mod,
Object* BlockAsMethod::block_executor(STATE, Executable* exec, Module* mod,
Arguments& args)
{
BlockAsMethod* bm = as<BlockAsMethod>(exec);
@@ -67,7 +69,7 @@ namespace rubinius {
if(exception) {
Exception* exc =
Exception::make_argument_error(state, expected, args.total(), args.name());
exc->locations(state, Location::from_call_stack(state, call_frame));
exc->locations(state, Location::from_call_stack(state));
state->raise_exception(exc);
return NULL;
}
@@ -78,7 +80,7 @@ namespace rubinius {

invocation.module = mod;

return bm->block_env()->invoke(state, call_frame,
return bm->block_env()->invoke(state,
bm->block_env(), args, invocation);
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
#ifndef RBX_BUILTIN_BLOCK_AS_METHOD_HPP
#define RBX_BUILTIN_BLOCK_AS_METHOD_HPP

#include "object_utils.hpp"

#include "builtin/block_environment.hpp"
#include "builtin/executable.hpp"

namespace rubinius {
@@ -19,10 +22,16 @@ namespace rubinius {
public:
attr_accessor(block_env, BlockEnvironment);

static void initialize(STATE, BlockAsMethod* obj) {
Executable::initialize(state, obj);

obj->block_env_ = nil<BlockEnvironment>();
}

// Rubinius.primitive :block_as_method_create
static BlockAsMethod* create(STATE, Object* self, BlockEnvironment* be);

static Object* block_executor(STATE, CallFrame* call_frame,
static Object* block_executor(STATE,
Executable* exec, Module* mod, Arguments& args);

class Info : public Executable::Info {

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
#ifndef RBX_BUILTIN_BLOCK_ENVIRONMENT_HPP
#define RBX_BUILTIN_BLOCK_ENVIRONMENT_HPP

#include "builtin/object.hpp"
#include "executor.hpp"
#include "object_utils.hpp"

#include "builtin/compiled_code.hpp"
#include "builtin/constant_scope.hpp"
#include "builtin/module.hpp"
#include "builtin/object.hpp"
#include "builtin/string.hpp"
#include "builtin/variable_scope.hpp"

namespace rubinius {
class CompiledCode;
@@ -28,7 +35,7 @@ namespace rubinius {
{}
};

typedef Object* (*BlockExecutor)(STATE, CallFrame*, BlockEnvironment* const,
typedef Object* (*BlockExecutor)(STATE, BlockEnvironment* const,
Arguments&, BlockInvocation& invocation);

class BlockEnvironment : public Object {
@@ -42,7 +49,7 @@ namespace rubinius {
ConstantScope* constant_scope_; // slot
Module* module_; // slot

MachineCode* machine_code(STATE, GCToken gct, CallFrame* call_frame);
MachineCode* machine_code(STATE);

public:
/* accessors */
@@ -54,35 +61,41 @@ namespace rubinius {

/* interface */

static void init(STATE);
static void bootstrap(STATE);
static void bootstrap_methods(STATE);

static void initialize(STATE, BlockEnvironment* obj) {
obj->scope_ = nil<VariableScope>();
obj->top_scope_ = nil<VariableScope>();
obj->compiled_code_ = nil<CompiledCode>();
obj->constant_scope_ = nil<ConstantScope>();
obj->module_ = nil<Module>();
}

// Rubinius.primitive :blockenvironment_allocate
static BlockEnvironment* allocate(STATE);

static Object* invoke(STATE, CallFrame* previous,
BlockEnvironment* env, Arguments& args,
BlockInvocation& invocation);
static Object* invoke(STATE, BlockEnvironment* env, Arguments& args,
BlockInvocation& invocation);

static BlockEnvironment* under_call_frame(STATE, GCToken gct, CompiledCode* cm,
MachineCode* caller, CallFrame* call_frame);
static BlockEnvironment* under_call_frame(STATE, CompiledCode* cm, MachineCode* caller);

static Object* execute_interpreter(STATE, CallFrame* previous,
static Object* execute_interpreter(STATE,
BlockEnvironment* env, Arguments& args,
BlockInvocation& invocation);

Object* call(STATE, CallFrame* call_frame, Arguments& args, int flags=0);
Object* call(STATE, Arguments& args, int flags=0);

// Rubinius.primitive? :block_call
Object* call_prim(STATE, CallFrame* call_frame, Executable* exec, Module* mod, Arguments& args);
Object* call_prim(STATE, Executable* exec, Module* mod, Arguments& args);

Object* call_on_object(STATE, CallFrame* call_frame, Arguments& args, int flags=0);
Object* call_on_object(STATE, Arguments& args, int flags=0);

// Rubinius.primitive? :block_call_under
Object* call_under(STATE, CallFrame* call_frame, Executable* exec, Module* mod, Arguments& args);
Object* call_under(STATE, Executable* exec, Module* mod, Arguments& args);

// Rubinius.primitive :block_env_of_sender
static Object* of_sender(STATE, CallFrame* calling_environment);
static Object* of_sender(STATE);

void lock_scope(STATE);

110 changes: 35 additions & 75 deletions vm/builtin/byte_array.cpp → machine/builtin/byte_array.cpp
Original file line number Diff line number Diff line change
@@ -1,97 +1,56 @@
#include "alloc.hpp"
#include "object_utils.hpp"
#include "memory.hpp"

#include "builtin/byte_array.hpp"
#include "builtin/class.hpp"
#include "builtin/exception.hpp"
#include "builtin/fixnum.hpp"
#include "builtin/string.hpp"
#include "builtin/tuple.hpp"
#include "object_utils.hpp"
#include "object_memory.hpp"
#include "ontology.hpp"

namespace rubinius {

uintptr_t ByteArray::bytes_offset;

void ByteArray::init(STATE) {
GO(bytearray).set(ontology::new_class_under(state,
"ByteArray", G(rubinius)));
G(bytearray)->set_object_type(state, ByteArrayType);
void ByteArray::bootstrap(STATE) {
GO(bytearray).set(state->memory()->new_class<Class, ByteArray>(
state, G(rubinius), "ByteArray"));

ByteArray* ba = ALLOCA(ByteArray);
bytes_offset = (uintptr_t)&(ba->bytes) - (uintptr_t)ba;
}

ByteArray* ByteArray::create(STATE, native_int bytes) {
if(bytes < 0) {
rubinius::bug("Invalid byte array size");
Exception::raise_argument_error(state, "negative byte array size");
} else if(bytes == 0) {
bytes = 1;
}
if(bytes == 0) bytes = 1;

size_t body = bytes;
ByteArray* ba = state->vm()->new_object_bytes_dirty<ByteArray>(G(bytearray), body);
ByteArray* ba =
state->memory()->new_bytes<ByteArray>(state, G(bytearray), bytes);
memset(ba->bytes, 0, ba->full_size_ - bytes_offset);

if(unlikely(!ba)) {
Exception::memory_error(state);
} else {
ba->full_size_ = body;
memset(ba->bytes, 0, body - bytes_offset);
}
return ba;
}

ByteArray* ByteArray::create_pinned(STATE, native_int bytes) {
if(bytes < 0) {
rubinius::bug("Invalid byte array size");
Exception::raise_argument_error(state, "negative byte array size");
} else if(bytes == 0) {
bytes = 1;
}
if(bytes == 0) bytes = 1;

size_t body = bytes;
ByteArray* ba = state->memory()->new_object_bytes_mature_dirty<ByteArray>(state, G(bytearray), body);
if(unlikely(!ba)) {
Exception::memory_error(state);
return NULL;
}
ByteArray* ba =
state->memory()->new_bytes_pinned<ByteArray>(state, G(bytearray), bytes);
memset(ba->bytes, 0, ba->full_size_ - bytes_offset);

if(!ba->pin()) {
rubinius::bug("unable to allocate pinned ByteArray");
} else {
ba->full_size_ = body;
memset(ba->bytes, 0, body - bytes_offset);
}
return ba;
}

ByteArray* ByteArray::create_dirty(STATE, native_int bytes) {
if(bytes < 0) {
rubinius::bug("Invalid byte array size");
}
if(bytes == 0) bytes = 1;

size_t body = bytes;
ByteArray* ba = state->vm()->new_object_bytes_dirty<ByteArray>(G(bytearray), body);

if(unlikely(!ba)) {
Exception::memory_error(state);
} else {
ba->full_size_ = body;
// Ensure to zero the last bytes that might be more
// because we always pad the size to a machine word.
// The caller is responsible to fill either the
// requested bytes or clear it all if it needs to
if(bytes > 0) {
size_t last = bytes_to_fields(body);
ba->pointer_to_body()[last - 1] = 0;
}
}
return ba;
}

ByteArray* ByteArray::allocate(STATE, Fixnum* bytes) {
native_int size = bytes->to_native();
if(size < 0) {
Exception::argument_error(state, "negative byte array size");
}
return ByteArray::create(state, size);
return ByteArray::create(state, bytes->to_native());
}

Fixnum* ByteArray::size(STATE) {
@@ -102,7 +61,7 @@ namespace rubinius {
native_int idx = index->to_native();

if(idx < 0 || idx >= size()) {
Exception::object_bounds_exceeded_error(state, "index out of bounds");
Exception::raise_object_bounds_exceeded_error(state, "index out of bounds");
}

return Fixnum::from(this->bytes[idx]);
@@ -112,7 +71,7 @@ namespace rubinius {
native_int idx = index->to_native();

if(idx < 0 || idx >= size()) {
Exception::object_bounds_exceeded_error(state, "index out of bounds");
Exception::raise_object_bounds_exceeded_error(state, "index out of bounds");
}

this->bytes[idx] = value->to_native();
@@ -125,15 +84,15 @@ namespace rubinius {
native_int dst = dest->to_native();

if(src < 0) {
Exception::object_bounds_exceeded_error(state, "start less than zero");
Exception::raise_object_bounds_exceeded_error(state, "start less than zero");
} else if(dst < 0) {
Exception::object_bounds_exceeded_error(state, "dest less than zero");
Exception::raise_object_bounds_exceeded_error(state, "dest less than zero");
} else if(cnt < 0) {
Exception::object_bounds_exceeded_error(state, "count less than zero");
Exception::raise_object_bounds_exceeded_error(state, "count less than zero");
} else if((dst + cnt) > size()) {
Exception::object_bounds_exceeded_error(state, "move is beyond end of bytearray");
Exception::raise_object_bounds_exceeded_error(state, "move is beyond end of bytearray");
} else if((src + cnt) > size()) {
Exception::object_bounds_exceeded_error(state, "move is more than available bytes");
Exception::raise_object_bounds_exceeded_error(state, "move is more than available bytes");
}

memmove(this->bytes + dst, this->bytes + src, cnt);
@@ -146,14 +105,15 @@ namespace rubinius {
native_int cnt = count->to_native();

if(src < 0) {
Exception::object_bounds_exceeded_error(state, "start less than zero");
Exception::raise_object_bounds_exceeded_error(state, "start less than zero");
} else if(cnt < 0) {
Exception::object_bounds_exceeded_error(state, "count less than zero");
Exception::raise_object_bounds_exceeded_error(state, "count less than zero");
} else if((src + cnt) > size()) {
Exception::object_bounds_exceeded_error(state, "fetch is more than available bytes");
Exception::raise_object_bounds_exceeded_error(state, "fetch is more than available bytes");
}

ByteArray* ba = ByteArray::create_dirty(state, cnt + 1);
ByteArray* ba =
state->memory()->new_bytes<ByteArray>(state, G(bytearray), cnt + 1);
memcpy(ba->bytes, this->bytes + src, cnt);
ba->bytes[cnt] = 0;

@@ -193,10 +153,10 @@ namespace rubinius {
native_int olim = b->to_native();

if(slim < 0) {
Exception::object_bounds_exceeded_error(state,
Exception::raise_object_bounds_exceeded_error(state,
"bytes of self to compare is less than zero");
} else if(olim < 0) {
Exception::object_bounds_exceeded_error(state,
Exception::raise_object_bounds_exceeded_error(state,
"bytes of other to compare is less than zero");
}

@@ -259,7 +219,7 @@ namespace rubinius {
return ba->full_size_;
}

void ByteArray::Info::mark(Object* t, ObjectMark& mark) {
void ByteArray::Info::mark(Object* t, memory::ObjectMark& mark) {
// @todo implement
}
}
12 changes: 8 additions & 4 deletions vm/builtin/byte_array.hpp → machine/builtin/byte_array.hpp
Original file line number Diff line number Diff line change
@@ -16,17 +16,21 @@ namespace rubinius {
uint8_t bytes[0];

public:
static void init(STATE);
static void bootstrap(STATE);

static ByteArray* create(STATE, native_int bytes);
static ByteArray* create_pinned(STATE, native_int bytes);
static ByteArray* create_dirty(STATE, native_int bytes);

template <typename Any>
static ByteArray* from_body(Any obj) {
uintptr_t ptr = reinterpret_cast<uintptr_t>(obj);
return reinterpret_cast<ByteArray*>(ptr - bytes_offset);
}

void set_full_size(native_int size) {
full_size_ = size;
}

// Rubinius.primitive :bytearray_allocate
static ByteArray* allocate(STATE, Fixnum* bytes);

@@ -80,8 +84,8 @@ namespace rubinius {
allow_user_allocate = false;
}

virtual void mark(Object* t, ObjectMark& mark);
virtual void auto_mark(Object* obj, ObjectMark& mark) {}
virtual void mark(Object* t, memory::ObjectMark& mark);
virtual void auto_mark(Object* obj, memory::ObjectMark& mark) {}
virtual size_t object_size(const ObjectHeader* object);
};

Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
#include "memory.hpp"

#include "builtin/call_custom_cache.hpp"
#include "builtin/call_unit.hpp"
#include "builtin/class.hpp"
#include "ontology.hpp"

namespace rubinius {

void CallCustomCache::init(STATE) {
GO(call_custom_cache).set(
ontology::new_class(state, "CallCustomCache",
G(call_site), G(rubinius)));
G(call_custom_cache)->set_object_type(state, CallCustomCacheType);
void CallCustomCache::bootstrap(STATE) {
GO(call_custom_cache).set(state->memory()->new_class<Class, CallCustomCache>(
state, G(call_site), G(rubinius), "CallCustomCache"));
}

CallCustomCache* CallCustomCache::create(STATE, CallSite* call_site, CallUnit* call_unit) {
CallCustomCache* cache = state->new_object_dirty<CallCustomCache>(G(call_custom_cache));
CallCustomCache* cache =
state->memory()->new_object<CallCustomCache>(state, G(call_custom_cache));

cache->name_ = call_site->name();
cache->executable(state, call_site->executable());
cache->ip_ = call_site->ip();
@@ -22,20 +23,19 @@ namespace rubinius {
cache->updater_ = NULL;
cache->call_unit(state, call_unit);
cache->hits_ = 0;

return cache;
}

Object* CallCustomCache::check_cache(STATE, CallSite* call_site,
CallFrame* call_frame, Arguments& args)
{
Object* CallCustomCache::check_cache(STATE, CallSite* call_site, Arguments& args) {
CallCustomCache* cache = static_cast<CallCustomCache*>(call_site);

CallUnit* cu = cache->call_unit_;
return cu->execute(state, call_frame, cu,
return cu->execute(state, cu,
cu->executable(), cu->module(), args);
}

void CallCustomCache::Info::mark(Object* obj, ObjectMark& mark) {
void CallCustomCache::Info::mark(Object* obj, memory::ObjectMark& mark) {
auto_mark(obj, mark);
}
}
Original file line number Diff line number Diff line change
@@ -2,6 +2,7 @@
#define RBX_CALL_CUSTOM_CACHE_HPP

#include "builtin/call_site.hpp"
#include "builtin/call_unit.hpp"

namespace rubinius {
struct CallFrame;
@@ -18,7 +19,14 @@ namespace rubinius {
public:
attr_accessor(call_unit, CallUnit);

static void init(STATE);
static void bootstrap(STATE);
static void initialize(STATE, CallCustomCache* obj) {
CallSite::initialize(state, obj);

obj->call_unit_ = nil<CallUnit>();
obj->hits_ = 0;
}

static CallCustomCache* create(STATE, CallSite* call_site, CallUnit* call_unit);

int hits() {
@@ -31,7 +39,7 @@ namespace rubinius {
class Info : public CallSite::Info {
public:
BASIC_TYPEINFO(CallSite::Info)
virtual void mark(Object* t, ObjectMark& mark);
virtual void mark(Object* t, memory::ObjectMark& mark);
};

};
187 changes: 94 additions & 93 deletions vm/builtin/call_site.cpp → machine/builtin/call_site.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
#include "arguments.hpp"
#include "call_frame.hpp"
#include "global_cache.hpp"
#include "lookup_data.hpp"
#include "object_utils.hpp"
#include "memory.hpp"

#include "builtin/class.hpp"
#include "builtin/call_custom_cache.hpp"
#include "builtin/call_site.hpp"
@@ -8,169 +14,160 @@
#include "builtin/mono_inline_cache.hpp"
#include "builtin/object.hpp"
#include "builtin/poly_inline_cache.hpp"
#include "call_frame.hpp"
#include "global_cache.hpp"
#include "lookup_data.hpp"
#include "object_utils.hpp"
#include "ontology.hpp"

#include <sstream>

namespace rubinius {

void CallSite::init(STATE) {
GO(call_site).set(ontology::new_class(state, "CallSite", G(object), G(rubinius)));
G(call_site)->set_object_type(state, CallSiteType);
void CallSite::bootstrap(STATE) {
GO(call_site).set(state->memory()->new_class<Class, CallSite>(
state, G(rubinius), "CallSite"));
}

CallSite* CallSite::empty(STATE, Symbol* name, Executable* executable, int ip) {
CallSite* cache =
state->new_object_dirty<CallSite>(G(call_site));
CallSite* cache = state->memory()->new_object<CallSite>(state, G(call_site));

cache->name_ = name;
cache->executor_ = empty_cache;
cache->fallback_ = empty_cache;
cache->updater_ = empty_cache_updater;
cache->executable(state, executable);
cache->ip_ = ip;

return cache;
}

Integer* CallSite::ip_prim(STATE) {
return Integer::from(state, ip_);
}

Object* CallSite::empty_cache_custom(STATE, CallSite* call_site, CallFrame* call_frame,
Arguments& args)
{
Object* CallSite::empty_cache_custom(STATE, CallSite* call_site, Arguments& args) {
Object* const recv = args.recv();

Array* ary = Array::create(state, args.total() + 2);
Array* ary = Array::create(state, args.total() + 2);
ary->set(state, 0, recv);
ary->set(state, 1, call_site->name_);

for(size_t i = 0; i < args.total(); i++) {
ary->set(state, i + 2, args.get_argument(i));
}

Object* ret = G(rubinius)->send(state, call_frame, state->symbol("bind_call"), ary);
Object* ret = G(rubinius)->send(state, state->symbol("bind_call"), ary);

if(CallUnit* cu = try_as<CallUnit>(ret)) {
CallCustomCache* cache = CallCustomCache::create(state, call_site, cu);
call_site->update_call_site(state, cache);
return cu->execute(state, call_frame, cu, cu->executable(), cu->module(), args);
return cu->execute(state, cu, cu->executable(), cu->module(), args);
} else {
Exception::internal_error(state, call_frame, "bind_call must return CallUnit");
Exception::internal_error(state, "bind_call must return CallUnit");
return 0;
}
}

Object* CallSite::empty_cache(STATE, CallSite* call_site, CallFrame* call_frame,
Arguments& args)
{
Object* CallSite::empty_cache(STATE, CallSite* call_site, Arguments& args) {
Object* const self = state->vm()->call_frame()->self();
Object* const recv = args.recv();
Class* const recv_class = recv->direct_class(state);

LookupData lookup(call_frame->self(), recv->lookup_begin(state), G(sym_public));
Dispatch dis(call_site->name());
LookupData lookup(self, recv->lookup_begin(state), G(sym_public));
Dispatch dispatch(call_site->name());

if(!dis.resolve(state, call_site->name(), lookup)) {
if(!lookup_method_missing(state, call_frame, args,
dis, call_frame->self(), recv->lookup_begin(state))) {
if(!dispatch.resolve(state, call_site->name(), lookup)) {
if(!lookup_method_missing(state, args,
dispatch, self, recv->lookup_begin(state))) {
return NULL;
}
}

state->vm()->metrics().machine.methods_invoked++;

call_site->update(state, recv_class, dis);
call_site->update(state, recv_class, dispatch);

Executable* meth = dis.method;
Module* mod = dis.module;
Executable* meth = dispatch.method;
Module* mod = dispatch.module;

if(meth->custom_call_site_p()) {
CallSiteInformation info(call_site->executable(), call_site->ip());
state->set_call_site_information(&info);
Object* res = meth->execute(state, call_frame, meth, mod, args);
Object* res = meth->execute(state, meth, mod, args);
state->set_call_site_information(NULL);
return res;
} else {
return meth->execute(state, call_frame, meth, mod, args);
return meth->execute(state, meth, mod, args);
}
}

Object* CallSite::empty_cache_private(STATE, CallSite* call_site, CallFrame* call_frame,
Object* CallSite::empty_cache_private(STATE, CallSite* call_site,
Arguments& args)
{
Object* const self = state->vm()->call_frame()->self();
Object* const recv = args.recv();
Class* const recv_class = recv->direct_class(state);

LookupData lookup(call_frame->self(), recv->lookup_begin(state), G(sym_private));
Dispatch dis(call_site->name());
LookupData lookup(self, recv->lookup_begin(state), G(sym_private));
Dispatch dispatch(call_site->name());

if(!dis.resolve(state, dis.name, lookup)) {
if(!lookup_method_missing(state, call_frame, args,
dis, call_frame->self(), recv->lookup_begin(state))) {
if(!dispatch.resolve(state, dispatch.name, lookup)) {
if(!lookup_method_missing(state, args,
dispatch, self, recv->lookup_begin(state))) {
return NULL;
}
}

state->vm()->metrics().machine.methods_invoked++;

call_site->update(state, recv_class, dis);
call_site->update(state, recv_class, dispatch);

Executable* meth = dis.method;
Module* mod = dis.module;
Executable* meth = dispatch.method;
Module* mod = dispatch.module;

if(meth->custom_call_site_p()) {
CallSiteInformation info(call_site->executable(), call_site->ip());
state->set_call_site_information(&info);
Object* res = meth->execute(state, call_frame, meth, mod, args);
Object* res = meth->execute(state, meth, mod, args);
state->set_call_site_information(NULL);
return res;
} else {
return meth->execute(state, call_frame, meth, mod, args);
return meth->execute(state, meth, mod, args);
}
}

Object* CallSite::empty_cache_vcall(STATE, CallSite* call_site, CallFrame* call_frame,
Arguments& args)
{

Object* CallSite::empty_cache_vcall(STATE, CallSite* call_site, Arguments& args) {
Object* const self = state->vm()->call_frame()->self();
Object* const recv = args.recv();
Class* const recv_class = recv->direct_class(state);

LookupData lookup(call_frame->self(), recv->lookup_begin(state), G(sym_private));
Dispatch dis(call_site->name());
LookupData lookup(self, recv->lookup_begin(state), G(sym_private));
Dispatch dispatch(call_site->name());

if(!dis.resolve(state, call_site->name(), lookup)) {
dis.method_missing = eVCall;
if(!lookup_method_missing(state, call_frame, args,
dis, call_frame->self(), recv->lookup_begin(state))) {
if(!dispatch.resolve(state, call_site->name(), lookup)) {
dispatch.method_missing = eVCall;
if(!lookup_method_missing(state, args,
dispatch, self, recv->lookup_begin(state))) {
return NULL;
}
}

state->vm()->metrics().machine.methods_invoked++;

call_site->update(state, recv_class, dis);
call_site->update(state, recv_class, dispatch);

Executable* meth = dis.method;
Module* mod = dis.module;
Executable* meth = dispatch.method;
Module* mod = dispatch.module;

if(meth->custom_call_site_p()) {
CallSiteInformation info(call_site->executable(), call_site->ip());
state->set_call_site_information(&info);
Object* res = meth->execute(state, call_frame, meth, mod, args);
Object* res = meth->execute(state, meth, mod, args);
state->set_call_site_information(NULL);
return res;
} else {
return meth->execute(state, call_frame, meth, mod, args);
return meth->execute(state, meth, mod, args);
}
}

Object* CallSite::empty_cache_super(STATE, CallSite* call_site, CallFrame* call_frame,
Object* CallSite::empty_cache_super(STATE, CallSite* call_site,
Arguments& args)
{
CallFrame* call_frame = state->vm()->call_frame();

Symbol* original_name = call_frame->original_name();
if(call_site->name_ != original_name) {
call_site->name_ = original_name;
@@ -182,46 +179,47 @@ namespace rubinius {
Module* const start = call_frame->module()->superclass();

LookupData lookup(call_frame->self(), start, G(sym_private));
Dispatch dis(call_site->name());
Dispatch dispatch(call_site->name());

if(start->nil_p() || !dis.resolve(state, call_site->name(), lookup)) {
if(start->nil_p() || !dispatch.resolve(state, call_site->name(), lookup)) {

LookupData missing_lookup(call_frame->self(), recv->lookup_begin(state), G(sym_private));
Dispatch missing_dis(G(sym_method_missing));
LookupData missing_lookup(call_frame->self(),
recv->lookup_begin(state), G(sym_private));
Dispatch missing_dispatch(G(sym_method_missing));

if(!missing_dis.resolve(state, G(sym_method_missing), missing_lookup)) {
if(!missing_dispatch.resolve(state, G(sym_method_missing), missing_lookup)) {
std::ostringstream msg;
msg << "no method_missing for ";
msg << recv_class->to_string(state);
msg << "#" << call_site->name()->to_string(state);

Exception::internal_error(state, call_frame, msg.str().c_str());
Exception::internal_error(state, msg.str().c_str());
return 0;
}

args.unshift(state, call_site->name());
dis.method = missing_dis.method;
dis.module = missing_dis.module;
dis.method_missing = eSuper;
state->vm()->set_method_missing_reason(dis.method_missing);
dispatch.method = missing_dispatch.method;
dispatch.module = missing_dispatch.module;
dispatch.method_missing = eSuper;
state->vm()->set_method_missing_reason(dispatch.method_missing);
state->vm()->global_cache()->add_seen(state, call_site->name());
}

state->vm()->metrics().machine.methods_invoked++;

call_site->update(state, recv_class, dis);
call_site->update(state, recv_class, dispatch);

Executable* meth = dis.method;
Module* mod = dis.module;
Executable* meth = dispatch.method;
Module* mod = dispatch.module;

if(meth->custom_call_site_p()) {
CallSiteInformation info(call_site->executable(), call_site->ip());
state->set_call_site_information(&info);
Object* res = meth->execute(state, call_frame, meth, mod, args);
Object* res = meth->execute(state, meth, mod, args);
state->set_call_site_information(NULL);
return res;
} else {
return meth->execute(state, call_frame, meth, mod, args);
return meth->execute(state, meth, mod, args);
}
}

@@ -230,8 +228,7 @@ namespace rubinius {
call_site->update_call_site(state, cache);
}

bool CallSite::update_and_validate(STATE, CallFrame* call_frame, Object* recv, Symbol* vis, int serial) {

bool CallSite::update_and_validate(STATE, Object* recv, Symbol* vis, int serial) {
Class* const recv_class = recv->direct_class(state);

if(MonoInlineCache* mono = try_as<MonoInlineCache>(this)) {
@@ -245,39 +242,43 @@ namespace rubinius {
if(likely(ice)) return ice->method()->serial()->to_native() == serial;
}

LookupData lookup(call_frame->self(), recv->lookup_begin(state), G(sym_public));
Dispatch dis(name_);
LookupData lookup(state->vm()->call_frame()->self(),
recv->lookup_begin(state), G(sym_public));
Dispatch dispatch(name_);

if(dis.resolve(state, name_, lookup)) {
update(state, recv_class, dis);
return dis.method->serial()->to_native() == serial;
if(dispatch.resolve(state, name_, lookup)) {
update(state, recv_class, dispatch);
return dispatch.method->serial()->to_native() == serial;
}
return false;
}

bool CallSite::lookup_method_missing(STATE, CallFrame* call_frame, Arguments& args, Dispatch& dis, Object* self, Module* begin) {
bool CallSite::lookup_method_missing(STATE,
Arguments& args, Dispatch& dispatch, Object* self, Module* begin)
{
LookupData missing_lookup(self, begin, G(sym_private));
Dispatch missing_dis(G(sym_method_missing));
Dispatch missing_dispatch(G(sym_method_missing));

if(!missing_dis.resolve(state, G(sym_method_missing), missing_lookup)) {
if(!missing_dispatch.resolve(state, G(sym_method_missing), missing_lookup)) {
std::ostringstream msg;
msg << "no method_missing for ";
msg << begin->to_string(state);
msg << "#" << dis.name->to_string(state);
msg << "#" << dispatch.name->to_string(state);

Exception::internal_error(state, call_frame, msg.str().c_str());
Exception::internal_error(state, msg.str().c_str());
return false;
}

args.unshift(state, dis.name);
dis.method = missing_dis.method;
dis.module = missing_dis.module;
state->vm()->set_method_missing_reason(dis.method_missing);
state->vm()->global_cache()->add_seen(state, dis.name);
args.unshift(state, dispatch.name);
dispatch.method = missing_dispatch.method;
dispatch.module = missing_dispatch.module;
state->vm()->set_method_missing_reason(dispatch.method_missing);
state->vm()->global_cache()->add_seen(state, dispatch.name);

return true;
}

void CallSite::Info::mark(Object* obj, ObjectMark& mark) {
void CallSite::Info::mark(Object* obj, memory::ObjectMark& mark) {
auto_mark(obj, mark);
}

34 changes: 22 additions & 12 deletions vm/builtin/call_site.hpp → machine/builtin/call_site.hpp
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
#ifndef RBX_BUILTIN_CALL_SITE_HPP
#define RBX_BUILTIN_CALL_SITE_HPP

#include "builtin/object.hpp"
#include "machine_code.hpp"
#include "object_utils.hpp"

#include "builtin/executable.hpp"
#include "builtin/object.hpp"

namespace rubinius {

class Dispatch;

typedef Object* (CacheExecuteFunc)(STATE, CallSite*, CallFrame*, Arguments&);
typedef Object* (FallbackExecuteFunc)(STATE, CallSite*, CallFrame*, Arguments&);
typedef Object* (CacheExecuteFunc)(STATE, CallSite*, Arguments&);
typedef Object* (FallbackExecuteFunc)(STATE, CallSite*, Arguments&);
typedef void (CacheUpdateFunc)(STATE, CallSite*, Class*, Dispatch&);

typedef CacheExecuteFunc* CacheExecutor;
@@ -44,7 +46,15 @@ namespace rubinius {
attr_accessor(name, Symbol);
attr_accessor(executable, Executable);

static void init(STATE);
static void bootstrap(STATE);
static void initialize(STATE, CallSite* obj) {
obj->name_ = nil<Symbol>();
obj->executor_ = empty_cache;
obj->fallback_ = empty_cache;
obj->updater_ = empty_cache_updater;
obj->executable_ = nil<Executable>();
obj->ip_ = 0;
}

int ip() const {
return ip_;
@@ -67,7 +77,7 @@ namespace rubinius {
return type_id() == MonoInlineCacheType || type_id() == PolyInlineCacheType;
}

bool update_and_validate(STATE, CallFrame* call_frame, Object* recv, Symbol* vis, int serial);
bool update_and_validate(STATE, Object* recv, Symbol* vis, int serial);

void set_is_private() {
executor_ = empty_cache_private;
@@ -102,14 +112,14 @@ namespace rubinius {
}
}

static bool lookup_method_missing(STATE, CallFrame* call_frame, Arguments& args, Dispatch& dis, Object* self, Module* begin);
static bool lookup_method_missing(STATE, Arguments& args, Dispatch& dis, Object* self, Module* begin);

Object* execute(STATE, CallFrame* call_frame, Arguments& args) {
return (*executor_)(state, this, call_frame, args);
Object* execute(STATE, Arguments& args) {
return (*executor_)(state, this, args);
}

Object* fallback(STATE, CallFrame* call_frame, Arguments& args) {
return (*fallback_)(state, this, call_frame, args);
Object* fallback(STATE, Arguments& args) {
return (*fallback_)(state, this, args);
}

void update(STATE, Class* klass, Dispatch& dispatch) {
@@ -124,8 +134,8 @@ namespace rubinius {
allow_user_allocate = false;
}

virtual void mark(Object* obj, ObjectMark& mark);
virtual void auto_mark(Object* obj, ObjectMark& mark);
virtual void mark(Object* obj, memory::ObjectMark& mark);
virtual void auto_mark(Object* obj, memory::ObjectMark& mark);
virtual void set_field(STATE, Object* target, size_t index, Object* val);
virtual Object* get_field(STATE, Object* target, size_t index);
virtual void populate_slot_locations();
105 changes: 105 additions & 0 deletions machine/builtin/call_unit.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
#include "arguments.hpp"
#include "call_frame.hpp"
#include "object_utils.hpp"
#include "memory.hpp"

#include "builtin/call_unit.hpp"
#include "builtin/class.hpp"
#include "builtin/location.hpp"

namespace rubinius {
CallUnit* CallUnit::create_constant_value(STATE, Object* self, Object* val) {
CallUnit* pe = state->memory()->new_object<CallUnit>(state, as<Class>(self));

pe->kind_ = CallUnit::eConstantValue;
pe->value(state, val);
pe->execute = constant_value_executor;

return pe;
}

CallUnit* CallUnit::create_for_method(STATE, Object* self,
Module* mod, Executable* exec, Symbol* name)
{
CallUnit* pe = state->memory()->new_object<CallUnit>(state, as<Class>(self));

pe->kind_ = CallUnit::eForMethod;
pe->module(state, mod);
pe->executable(state, exec);
pe->name(state, name);
pe->execute = method_executor;

return pe;
}

CallUnit* CallUnit::create_test(STATE, Object* self,
CallUnit* cond, CallUnit* c_then, CallUnit* c_else)
{
CallUnit* pe = state->memory()->new_object<CallUnit>(state, as<Class>(self));

pe->kind_ = CallUnit::eTest;
pe->test_condition(state, cond);
pe->test_then(state, c_then);
pe->test_else(state, c_else);
pe->execute = test_executor;

return pe;
}

CallUnit* CallUnit::create_kind_of(STATE, Object* self, Module* mod, Fixnum* which) {
CallUnit* pe = state->memory()->new_object<CallUnit>(state, as<Class>(self));

pe->kind_ = CallUnit::eKindOf;
pe->value(state, mod);
pe->which_ = which->to_native();
pe->execute = kind_of_executor;

return pe;
}

Object* CallUnit::constant_value_executor(STATE,
CallUnit* unit, Executable* exec, Module* mod, Arguments& args)
{
return unit->value();
}

Object* CallUnit::method_executor(STATE,
CallUnit* unit, Executable* exec, Module* mod, Arguments& args)
{
args.set_name(unit->name());
return unit->executable()->execute(state,
unit->executable(), unit->module(), args);
}

Object* CallUnit::test_executor(STATE,
CallUnit* unit, Executable* exec, Module* mod, Arguments& args)
{
Object* ret = unit->test_condition()->execute(
state, unit->test_condition(), exec, mod, args);
if(!ret) return ret;
if(CBOOL(ret)) {
return unit->test_then()->execute(state, unit->test_then(), exec, mod, args);
} else {
return unit->test_else()->execute(state, unit->test_else(), exec, mod, args);
}
}

Object* CallUnit::kind_of_executor(STATE,
CallUnit* unit, Executable* exec, Module* mod, Arguments& args)
{
Object* obj;
if(unit->which_ == -1) {
obj = args.recv();
} else if(unit->which_ < (int)args.total()) {
obj = args.get_argument(unit->which_);
} else {
return cFalse;
}

if(Module* mod = try_as<Module>(unit->value())) {
return RBOOL(obj->kind_of_p(state, mod));
} else {
return cFalse;
}
}
}
27 changes: 22 additions & 5 deletions vm/builtin/call_unit.hpp → machine/builtin/call_unit.hpp
Original file line number Diff line number Diff line change
@@ -1,21 +1,27 @@
#ifndef RBX_BUILTIN_CALL_UNIT_HPP
#define RBX_BUILTIN_CALL_UNIT_HPP

#include "object_utils.hpp"

#include "builtin/executable.hpp"
#include "builtin/module.hpp"
#include "builtin/object.hpp"
#include "builtin/symbol.hpp"

namespace rubinius {
class CallUnit : public Object {
public:
const static object_type type = CallUnitType;

enum Kind {
eUnset,
eConstantValue,
eForMethod,
eTest,
eKindOf
};

typedef Object* (*Execute)(State*, CallFrame*, CallUnit* unit,
typedef Object* (*Execute)(State*, CallUnit* unit,
Executable* exec, Module* mod, Arguments& args);

private:
@@ -45,6 +51,17 @@ namespace rubinius {
attr_accessor(test_then, CallUnit);
attr_accessor(test_else, CallUnit);

static void initialize(STATE, CallUnit* obj) {
obj-> kind_ = eUnset;
obj->value_ = nil<Object>();
obj->module_ = nil<Module>();
obj->executable_ = nil<Executable>();
obj->name_ = nil<Symbol>();
obj->test_condition_ = nil<CallUnit>();
obj->test_then_ = nil<CallUnit>();
obj->test_else_ = nil<CallUnit>();
}

// Rubinius.primitive :callunit_constant_value
static CallUnit* create_constant_value(STATE, Object* self, Object* val);

@@ -57,22 +74,22 @@ namespace rubinius {
// Rubinius.primitive :callunit_kind_of
static CallUnit* create_kind_of(STATE, Object* self, Module* mod, Fixnum* which);

static Object* constant_value_executor(STATE, CallFrame* call_frame,
static Object* constant_value_executor(STATE,
CallUnit* unit,
Executable* exec, Module* mod,
Arguments& args);

static Object* method_executor(STATE, CallFrame* call_frame,
static Object* method_executor(STATE,
CallUnit* unit,
Executable* exec, Module* mod,
Arguments& args);

static Object* test_executor(STATE, CallFrame* call_frame,
static Object* test_executor(STATE,
CallUnit* unit,
Executable* exec, Module* mod,
Arguments& args);

static Object* kind_of_executor(STATE, CallFrame* call_frame,
static Object* kind_of_executor(STATE,
CallUnit* unit,
Executable* exec, Module* mod,
Arguments& args);
26 changes: 26 additions & 0 deletions machine/builtin/call_unit_adapter.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#include "object_utils.hpp"
#include "memory.hpp"

#include "builtin/call_unit_adapter.hpp"
#include "builtin/call_unit.hpp"
#include "builtin/class.hpp"

namespace rubinius {
CallUnitAdapter* CallUnitAdapter::create(STATE, Object* self, CallUnit* unit) {
CallUnitAdapter* pe =
state->memory()->new_object<CallUnitAdapter>(state, as<Class>(self));

pe->unit(state, unit);

return pe;
}

Object* CallUnitAdapter::adapter_executor(STATE,
Executable* exec, Module* mod, Arguments& args)
{
CallUnitAdapter* adapter = as<CallUnitAdapter>(exec);
CallUnit* unit = adapter->unit_;

return unit->execute(state, unit, exec, mod, args);
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#ifndef RBX_BUILTIN_CALL_UNIT_ADAPTER_HPP
#define RBX_BUILTIN_CALL_UNIT_ADAPTER_HPP

#include "object_utils.hpp"

#include "builtin/executable.hpp"

namespace rubinius {
@@ -18,10 +20,16 @@ namespace rubinius {
public:
attr_accessor(unit, CallUnit);

static void initialize(STATE, CallUnitAdapter* obj) {
Executable::initialize(state, obj);

obj->unit_ = nil<CallUnit>();
}

// Rubinius.primitive :callunitadapter_create
static CallUnitAdapter* create(STATE, Object* self, CallUnit* unit);

static Object* adapter_executor(STATE, CallFrame* call_frame,
static Object* adapter_executor(STATE,
Executable* exec, Module* mod, Arguments& args);

class Info : public Executable::Info {
41 changes: 21 additions & 20 deletions vm/builtin/channel.cpp → machine/builtin/channel.cpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
#include "object_utils.hpp"
#include "on_stack.hpp"
#include "memory.hpp"
#include "thread_phase.hpp"

#include "builtin/class.hpp"
#include "builtin/channel.hpp"
#include "builtin/fixnum.hpp"
@@ -6,22 +11,18 @@
#include "builtin/list.hpp"
#include "builtin/object.hpp"
#include "builtin/thread.hpp"
#include "object_utils.hpp"
#include "on_stack.hpp"
#include "ontology.hpp"

#include <sys/time.h>

namespace rubinius {

void Channel::init(STATE) {
GO(channel).set(ontology::new_class(state, "Channel",
G(object), G(rubinius)));
G(channel)->set_object_type(state, Channel::type);
void Channel::bootstrap(STATE) {
GO(channel).set(state->memory()->new_class<Class, Channel>(
state, G(rubinius), "Channel"));
}

Channel* Channel::create(STATE) {
Channel* chan = state->vm()->new_object_mature<Channel>(G(channel));
Channel* chan = state->memory()->new_object_pinned<Channel>(state, G(channel));
chan->waiters_ = 0;
chan->semaphore_count_ = 0;

@@ -34,12 +35,12 @@ namespace rubinius {
return chan;
}

Object* Channel::send(STATE, GCToken gct, Object* val, CallFrame* calling_environment) {
Object* Channel::send(STATE, Object* val) {
Channel* self = this;

OnStack<2> os(state, val, self);

GCLockGuard lg(state, gct, calling_environment, mutex_);
MutexLockUnmanaged lock_unmanaged(state, mutex_);

if(val->nil_p()) {
self->semaphore_count_++;
@@ -61,11 +62,11 @@ namespace rubinius {
return cNil;
}

Object* Channel::try_receive(STATE, GCToken gct, CallFrame* calling_environment) {
Object* Channel::try_receive(STATE) {
Channel* self = this;
OnStack<1> os(state, self);

GCLockGuard lg(state, gct, calling_environment, mutex_);
MutexLockUnmanaged lock_unmanaged(state, mutex_);

if(self->semaphore_count_ > 0) {
self->semaphore_count_--;
@@ -76,12 +77,12 @@ namespace rubinius {
return self->value_->shift(state);
}

Object* Channel::receive(STATE, GCToken gct, CallFrame* call_frame) {
return receive_timeout(state, gct, cNil, call_frame);
Object* Channel::receive(STATE) {
return receive_timeout(state, cNil);
}

#define NANOSECONDS 1000000000
Object* Channel::receive_timeout(STATE, GCToken gct, Object* duration, CallFrame* call_frame) {
Object* Channel::receive_timeout(STATE, Object* duration) {
// Passing control away means that the GC might run. So we need
// to stash this into a root, and read it back out again after
// control is returned.
@@ -94,7 +95,7 @@ namespace rubinius {
Channel* self = this;
OnStack<2> os(state, self, duration);

GCLockGuard lg(state, gct, call_frame, mutex_);
MutexLockUnmanaged lock_unmanaged(state, mutex_);

if(self->semaphore_count_ > 0) {
self->semaphore_count_--;
@@ -133,7 +134,7 @@ namespace rubinius {
ts.tv_nsec = nano % NANOSECONDS;
}

if(!state->check_async(call_frame)) {
if(!state->check_async(state)) {
return NULL;
}

@@ -145,7 +146,7 @@ namespace rubinius {

for(;;) {
{
GCIndependent gc_guard(state, call_frame);
UnmanagedPhase unmanaged(state);

if(use_timed_wait) {
if(self->condition_.wait_until(self->mutex_, &ts) == utilities::thread::cTimedOut) break;
@@ -156,7 +157,7 @@ namespace rubinius {

// or there are values available.
if(self->semaphore_count_ > 0 || !self->value()->empty_p()) break;
if(!state->check_async(call_frame)) {
if(!state->check_async(state)) {
exception = true;
break;
}
@@ -168,7 +169,7 @@ namespace rubinius {
self->unpin();
self->waiters_--;

if(exception || !state->check_async(call_frame)) return NULL;
if(exception || !state->check_async(state)) return NULL;

if(self->semaphore_count_ > 0) {
self->semaphore_count_--;
23 changes: 16 additions & 7 deletions vm/builtin/channel.hpp → machine/builtin/channel.hpp
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
#ifndef RBX_CHANNEL_HPP
#define RBX_CHANNEL_HPP

#include "object_utils.hpp"

#include "builtin/list.hpp"
#include "builtin/object.hpp"
#include "builtin/string.hpp"

namespace rubinius {
class List;
class IO;
class IOBuffer;
class Executable;
@@ -14,7 +17,7 @@ namespace rubinius {
public:

/** Register class. */
static void init(STATE);
static void bootstrap(STATE);

const static object_type type = ChannelType;

@@ -32,29 +35,35 @@ namespace rubinius {
attr_accessor(value, List);

/* interface */
static void initialize(STATE, Channel* obj) {
obj->value_ = nil<List>();
obj->condition_.init();
obj->mutex_.init();
obj->waiters_ = 0;
obj->semaphore_count_ = 0;
}

// Rubinius.primitive :channel_new
static Channel* create(STATE);

// Rubinius.primitive :channel_send
Object* send(STATE, GCToken gct, Object* val, CallFrame* calling_environment);
Object* send(STATE, Object* val);

// Rubinius.primitive :channel_receive
Object* receive(STATE, GCToken gct, CallFrame* calling_environment);
Object* receive(STATE);

// Rubinius.primitive :channel_try_receive
Object* try_receive(STATE, GCToken gct, CallFrame* calling_environment);
Object* try_receive(STATE);

// Rubinius.primitive :channel_receive_timeout
Object* receive_timeout(STATE, GCToken gct, Object* duration, CallFrame* calling_environment);
Object* receive_timeout(STATE, Object* duration);

class Info : public TypeInfo {
public:
BASIC_TYPEINFO(TypeInfo)
};

};

}

#endif
17 changes: 8 additions & 9 deletions vm/builtin/character.cpp → machine/builtin/character.cpp
Original file line number Diff line number Diff line change
@@ -2,28 +2,27 @@
#include "regenc.h"
#include "transcoder.h"

#include "object_utils.hpp"
#include "memory.hpp"

#include "builtin/byte_array.hpp"
#include "builtin/character.hpp"
#include "builtin/class.hpp"
#include "builtin/encoding.hpp"
#include "builtin/object.hpp"
#include "object_utils.hpp"
#include "ontology.hpp"

namespace rubinius {
void Character::init(STATE) {
GO(character).set(ontology::new_class(state, "Character", G(string), G(rubinius)));
G(character)->set_object_type(state, CharacterType);
void Character::bootstrap(STATE) {
GO(character).set(state->memory()->new_class<Class, Character>(
state, G(string), G(rubinius), "Character"));
}

Character* Character::allocate(STATE, Object* self) {
Character* chr = state->new_object<Character>(G(character));
chr->klass(state, as<Class>(self));
return chr;
return state->memory()->new_object<Character>(state, as<Class>(self));
}

Character* Character::create(STATE, native_int size) {
Character* chr = state->new_object_dirty<Character>(G(character));
Character* chr = Character::allocate(state, G(character));

chr->num_bytes(state, Fixnum::from(size));
chr->num_chars(state, nil<Fixnum>());
2 changes: 1 addition & 1 deletion vm/builtin/character.hpp → machine/builtin/character.hpp
Original file line number Diff line number Diff line change
@@ -8,7 +8,7 @@ namespace rubinius {
public:
const static object_type type = CharacterType;

static void init(STATE);
static void bootstrap(STATE);

// Rubinius.primitive :character_allocate
static Character* allocate(STATE, Object* self);
Loading