Skip to content
Browse files

Add File.utime, better Fixnum prims, Object#send as prim, and more

* All work done while working to run flexmock and rake
* Added Object#clone and fixed Object#dup
* Added File::Stat.blksize
* Fix private method lookup (should terminate at the private method)
* The comparison meta_ops only fire if both values are immediates.
  • Loading branch information...
1 parent fd7c266 commit 475b9e508b54dd31208616433cb09451e8030ac0 @evanphx evanphx committed Jan 8, 2008
View
14 Rakefile
@@ -256,7 +256,7 @@ Core = CodeGroup.new(files, 'runtime/core', 'core')
Bootstrap = CodeGroup.new 'kernel/bootstrap/*.rb', 'runtime/bootstrap',
'bootstrap'
-Platform = CodeGroup.new 'kernel/platform/*.rb', 'runtime/platform', 'platform'
+PlatformFiles = CodeGroup.new 'kernel/platform/*.rb', 'runtime/platform', 'platform'
file 'runtime/loader.rbc' => 'kernel/loader.rb' do
compile 'kernel/loader.rb', 'runtime/loader.rbc'
@@ -282,7 +282,7 @@ Rake::StructGeneratorTask.new do |t|
t.dest = 'lib/zlib.rb'
end
-AllPreCompiled = Core.output + Bootstrap.output + Platform.output
+AllPreCompiled = Core.output + Bootstrap.output + PlatformFiles.output
AllPreCompiled << "runtime/loader.rbc"
# spec tasks
@@ -571,7 +571,14 @@ file 'runtime/platform.conf' do |t|
sg.name 'struct dirent'
fel = sg.field :d_name
sg.calculate
-
+
+ tg = StructGenerator.new
+ tg.include "sys/time.h"
+ tg.name 'struct timeval'
+ tv_sec = tg.field :tv_sec
+ tv_usec = tg.field :tv_usec
+ tg.calculate
+
# FIXME these constants don't have standard names.
# LOCK_SH == Linux, O_SHLOCK on Bsd/Darwin, etc.
# Binary doesn't exist at all in many non-Unix variants.
@@ -614,6 +621,7 @@ file 'runtime/platform.conf' do |t|
File.open(t.name, "w") do |f|
f.puts "rbx.platform.dir.d_name = #{fel.offset}"
+ f.puts tg.generate_config('timeval')
file_constants.each do | name |
const = cg.constants[name]
f.puts "rbx.platform.file.#{name} = #{const.converted_value}"
View
22 kernel/bootstrap/fixnum.rb
@@ -57,35 +57,29 @@ def divmod(other)
super(other)
end
-
-
def <=>(other)
Ruby.primitive :compare
super(other)
end
- def internal_cmp(other)
- Ruby.primitive :compare
- unless c = (self <=> other)
- raise ArgumentError, "comparison of Fixnum with #{other.class} failed"
- end
- return c
- end
-
def <(o)
- internal_cmp(o) == -1
+ Ruby.primitive :fixnum_lt
+ super(o)
end
def <=(o)
- internal_cmp(o) != 1
+ Ruby.primitive :fixnum_le
+ super(o)
end
def >(o)
- internal_cmp(o) == 1
+ Ruby.primitive :fixnum_gt
+ super(o)
end
def >=(o)
- internal_cmp(o) != -1
+ Ruby.primitive :fixnum_ge
+ super(o)
end
def to_s(base=10)
View
11 kernel/bootstrap/object.rb
@@ -51,7 +51,12 @@ def respond_to?(meth,include_private=false)
!cm.nil?
end
- def __send__(name, *args)
+ def __send__(*args)
+ Ruby.primitive :object_send
+ raise RuntimeError, "send failed"
+ end
+
+ def old__send__(name, *args)
meth = name.to_sym
count = args.size.to_i
@@ -87,6 +92,10 @@ def copy_from(other, start)
def dup
Ruby.primitive :object_dup
end
+
+ def clone
+ Ruby.primitive :object_clone
+ end
def to_s
"#<#{self.class.name}>"
View
51 kernel/core/file.rb
@@ -266,6 +266,29 @@ def chmod(mode)
Platform::POSIX.fchmod(@descriptor, mode)
end
+ class TimeVal < FFI::Struct
+ config 'rbx.platform.timeval', :tv_sec, :tv_usec
+ end
+
+ def self.utime(a_in, m_in, *paths)
+ ptr = MemoryPointer.new(TimeVal, 2)
+ atime = TimeVal.new ptr
+ mtime = TimeVal.new ptr[1]
+ atime[:tv_sec] = a_in.to_i
+ atime[:tv_usec] = 0
+
+ mtime[:tv_sec] = m_in.to_i
+ mtime[:tv_usec] = 0
+
+ paths.each do |path|
+ if Platform::POSIX.utimes(path, ptr) != 0
+ Errno.handle
+ end
+ end
+
+ ptr.free
+ end
+
def self.atime(path)
Time.at stat(path).atime
end
@@ -363,21 +386,23 @@ class << self
end
class Stat
- self.instance_fields = 11
+ self.instance_fields = 12
ivar_as_index :inode => 0, :mode => 1, :kind => 2, :owner => 3, :group => 4,
- :size => 5, :block => 6, :atime => 7, :mtime => 8, :ctime => 9, :path => 10
+ :size => 5, :block => 6, :atime => 7, :mtime => 8, :ctime => 9, :path => 10,
+ :blksize => 11
- def inode; @inode; end
- def mode; @mode; end
- def kind; @kind; end
- def owner; @owner; end
- def group; @group; end
- def size; @size; end
- def block; @block; end
- def atime; @atime; end
- def mtime; @mtime; end
- def ctime; @ctime; end
- def path; @path; end
+ def inode; @inode; end
+ def mode; @mode; end
+ def kind; @kind; end
+ def owner; @owner; end
+ def group; @group; end
+ def size; @size; end
+ def block; @block; end
+ def atime; @atime; end
+ def mtime; @mtime; end
+ def ctime; @ctime; end
+ def path; @path; end
+ def blksize; @blksize; end
def inspect
"#<#{self.class}:0x#{object_id.to_s(16)} path=#{@path} kind=#{@kind}>"
View
1 kernel/platform/posix.rb
@@ -29,6 +29,7 @@ module Platform::POSIX
attach_function 'symlink', [:string, :string], :int
attach_function 'readlink', [:string, :string, :int], :int
attach_function 'rename', [:string, :string], :int
+ attach_function 'utimes', [:string, :pointer], :int
# directories
attach_function 'chdir', [:string], :int
View
18 rakelib/struct_generator.rb
@@ -7,6 +7,7 @@ class Field
attr_reader :name
attr_reader :type
attr_reader :offset
+ attr_accessor :size
def initialize(name, type)
@name = name
@@ -71,7 +72,7 @@ def calculate
@fields.each do |field|
f.puts <<EOF
- printf("%s %u\\n", "#{field.name}", (unsigned int)offsetof(#{@struct_name}, #{field.name}));
+ printf("%s %u %u\\n", "#{field.name}", (unsigned int)offsetof(#{@struct_name}, #{field.name}), (unsigned int)sizeof(((#{@struct_name}*)0)->#{field.name}));
EOF
end
@@ -87,12 +88,23 @@ def calculate
line_no = 0
output.each_line do |line|
- md = line.match(/.+ (\d+)/)
- @fields[line_no].offset = md.captures.first.to_i
+ md = line.match(/.+ (\d+) (\d+)/)
+ @fields[line_no].offset = md[1].to_i
+ @fields[line_no].size = md[2].to_i
line_no += 1
end
end
+
+ def generate_config(name)
+ buf = ""
+ @fields.each_with_index do |field, i|
+ buf << "rbx.platform.#{name}.#{field.name}.offset = #{field.offset}\n"
+ buf << "rbx.platform.#{name}.#{field.name}.size = #{field.size}\n"
+ end
+
+ buf
+ end
def generate_layout
buf = ""
View
10 shotgun/lib/cpu.h
@@ -298,15 +298,15 @@ static inline OBJECT cpu_stack_top(STATE, cpu c) {
#define FIRST_RUNTIME_PRIM 1024
-int cpu_perform_system_primitive(STATE, cpu c, int prim, OBJECT mo, int num_args, OBJECT name, OBJECT mod);
+int cpu_perform_system_primitive(STATE, cpu c, int prim, OBJECT mo, int num_args, OBJECT name, OBJECT mod, OBJECT block);
-int cpu_perform_runtime_primitive(STATE, cpu c, int prim, OBJECT mo, int num_args, OBJECT name, OBJECT mod);
+int cpu_perform_runtime_primitive(STATE, cpu c, int prim, OBJECT mo, int num_args, OBJECT name, OBJECT mod, OBJECT block);
-static inline int cpu_perform_primitive(STATE, cpu c, int prim, OBJECT mo, int args, OBJECT name, OBJECT mod) {
+static inline int cpu_perform_primitive(STATE, cpu c, int prim, OBJECT mo, int args, OBJECT name, OBJECT mod, OBJECT block) {
if(prim < FIRST_RUNTIME_PRIM) {
- return cpu_perform_system_primitive(state, c, prim, mo, args, name, mod);
+ return cpu_perform_system_primitive(state, c, prim, mo, args, name, mod, block);
} else {
- return cpu_perform_runtime_primitive(state, c, prim, mo, args, name, mod);
+ return cpu_perform_runtime_primitive(state, c, prim, mo, args, name, mod, block);
}
}
View
25 shotgun/lib/cpu_instructions.c
@@ -151,12 +151,12 @@ static inline OBJECT cpu_check_for_method(STATE, cpu c, OBJECT hsh, OBJECT name,
if(TUPLE_P(meth)) {
vis = tuple_at(state, meth, 0);
if(vis == state->global->sym_private) {
- /* We skip private methods. */
- return Qnil;
+ /* We stop on private methods. */
+ return Qfalse;
} else if(vis == state->global->sym_protected) {
/* If it's protected, bail if the receiver isn't the same
class as self. */
- if(object_class(state, recv) != object_class(state, c->self)) return Qnil;
+ if(object_class(state, recv) != object_class(state, c->self)) return Qfalse;
}
}
@@ -493,7 +493,7 @@ void cpu_raise_primitive_failure(STATE, cpu c, int primitive_idx) {
cpu_raise_exception(state, c, primitive_failure);
}
-static inline int cpu_try_primitive(STATE, cpu c, OBJECT mo, OBJECT recv, int args, OBJECT sym, OBJECT mod) {
+static inline int cpu_try_primitive(STATE, cpu c, OBJECT mo, OBJECT recv, int args, OBJECT sym, OBJECT mod, OBJECT block) {
int prim, req;
OBJECT prim_obj;
@@ -516,7 +516,7 @@ static inline int cpu_try_primitive(STATE, cpu c, OBJECT mo, OBJECT recv, int ar
if(args == req || req < 0) {
stack_push(recv);
- if(cpu_perform_primitive(state, c, prim, mo, args, sym, mod)) {
+ if(cpu_perform_primitive(state, c, prim, mo, args, sym, mod, block)) {
/* Worked! */
return TRUE;
}
@@ -817,7 +817,7 @@ inline void cpu_goto_method(STATE, cpu c, OBJECT recv, OBJECT meth,
int count, OBJECT name, OBJECT block) {
OBJECT ctx;
- if(cpu_try_primitive(state, c, meth, recv, count, name, Qnil)) { return; }
+ if(cpu_try_primitive(state, c, meth, recv, count, name, Qnil, block)) { return; }
ctx = cpu_create_context(state, c, recv, meth, name,
_real_class(state, recv), (unsigned long int)count, block);
cpu_activate_context(state, c, ctx, ctx, 0);
@@ -852,20 +852,20 @@ inline void cpu_perform_hook(STATE, cpu c, OBJECT recv, OBJECT meth, OBJECT arg)
static inline void _cpu_build_and_activate(STATE, cpu c, OBJECT mo,
OBJECT recv, OBJECT sym, int args, OBJECT block, int missing, OBJECT mod) {
OBJECT ctx;
- c->call_flags = 0;
if(missing) {
args += 1;
stack_push(sym);
// printf("EEK! method_missing!\n");
// abort();
} else {
- if(cpu_try_primitive(state, c, mo, recv, args, sym, mod)) {
+ if(cpu_try_primitive(state, c, mo, recv, args, sym, mod, block)) {
if(EXCESSIVE_TRACING) {
printf("%05d: Called prim %s => %s on %s.\n", c->depth,
rbs_symbol_to_cstring(state, cmethod_get_name(cpu_current_method(state, c))),
rbs_symbol_to_cstring(state, sym), _inspect(recv));
}
+ c->call_flags = 0;
return;
}
}
@@ -881,6 +881,14 @@ static inline void _cpu_build_and_activate(STATE, cpu c, OBJECT mo,
);
}
ctx = cpu_create_context(state, c, recv, mo, sym, mod, (unsigned long int)args, block);
+ /* If it was missing, setup some extra data in the MethodContext for
+ the method_missing method to check out, to see why it was missing. */
+ if(missing) {
+ if(c->call_flags == 1) {
+ methctx_reference(state, ctx);
+ object_set_ivar(state, ctx, SYM("@send_private"), Qtrue);
+ }
+ }
/*
if(RTEST(block)) {
printf("in send to '%s', block %p\n", rbs_symbol_to_cstring(state, sym), block);
@@ -889,6 +897,7 @@ static inline void _cpu_build_and_activate(STATE, cpu c, OBJECT mo,
if(EXCESSIVE_TRACING) {
printf("CTX: running %d\n", (int)ctx);
}
+ c->call_flags = 0;
cpu_activate_context(state, c, ctx, ctx, args);
}
View
4 shotgun/lib/cpu_primitives.c
@@ -86,7 +86,7 @@ int _object_stores_bytes(OBJECT self);
void ffi_call(STATE, cpu c, OBJECT ptr);
-int cpu_perform_system_primitive(STATE, cpu c, int prim, OBJECT mo, int num_args, OBJECT method_name, OBJECT mod) {
+int cpu_perform_system_primitive(STATE, cpu c, int prim, OBJECT mo, int num_args, OBJECT method_name, OBJECT mod, OBJECT block) {
int _ret = TRUE;
OBJECT self, t1, t2, t3, t4;
int j, k, m, _orig_sp;
@@ -105,7 +105,7 @@ int cpu_perform_system_primitive(STATE, cpu c, int prim, OBJECT mo, int num_args
return _ret;
}
-int cpu_perform_runtime_primitive(STATE, cpu c, int prim, OBJECT mo, int num_args, OBJECT method_name, OBJECT mod) {
+int cpu_perform_runtime_primitive(STATE, cpu c, int prim, OBJECT mo, int num_args, OBJECT method_name, OBJECT mod, OBJECT block) {
int _ret = TRUE;
OBJECT self, t1, t2, t3;
int j, _orig_sp;
View
35 shotgun/lib/hash.c
@@ -103,6 +103,41 @@ void hash_setup(STATE, OBJECT hsh, int size) {
hash_set_default(hsh, Qnil);
}
+OBJECT hash_dup(STATE, OBJECT hsh) {
+ int sz, i;
+ OBJECT dup, vals, ent, next, lst, tmp;
+
+ sz = FIXNUM_TO_INT(hash_get_bins(hsh));
+ dup = hash_new_sized(state, sz);
+ dup->klass = object_class(state, hsh);
+
+ hash_set_bins(dup, I2N(sz));
+ hash_set_entries(dup, hash_get_entries(hsh));
+ hash_set_default(dup, hash_get_default(hsh));
+ hash_set_keys(dup, tuple_dup(state, hash_get_keys(hsh)));
+
+ vals = tuple_new(state, sz);
+
+ for(i = 0; i < sz; i++) {
+ tmp = tuple_at(state, hsh, i);
+ if(NIL_P(tmp)) continue;
+
+ ent = tuple_dup(state, tmp);
+ tuple_put(state, vals, i, ent);
+
+ next = tuple_at(state, ent, 3);
+ lst = ent;
+ while(!NIL_P(next)) {
+ next = tuple_dup(state, next);
+ tuple_put(state, lst, 3, next);
+ lst = next;
+ next = tuple_at(state, next, 3);
+ }
+ }
+
+ return dup;
+}
+
static void hash_rehash(STATE, OBJECT hsh, int _ents) {
int new_bins, i, old_bins;
unsigned int bin, hv;
View
1 shotgun/lib/hash.h
@@ -9,6 +9,7 @@ OBJECT hash_delete(STATE, OBJECT self, unsigned int hsh);
OBJECT hash_s_from_tuple(STATE, OBJECT tup);
OBJECT hash_get_undef(STATE, OBJECT hash, unsigned int hsh);
OBJECT hash_find_entry(STATE, OBJECT h, unsigned int hsh);
+OBJECT hash_dup(STATE, OBJECT hsh);
#define hash_find(state, hash, key) (hash_get(state, hash, object_hash_int(state, key)))
View
10 shotgun/lib/instructions.rb
@@ -336,7 +336,7 @@ def send_primitive
// performed on an object? Or should we state that the semantics of a primitive
// will always have an object or else it needs to be an opcode... ?
// If the primitive fails raise an exception
- if( ! cpu_perform_primitive(state, c, j, Qnil, k, Qnil, Qnil) )
+ if( ! cpu_perform_primitive(state, c, j, Qnil, k, Qnil, Qnil, Qnil) )
{
cpu_raise_primitive_failure(state, c, j);
}
@@ -917,8 +917,8 @@ def meta_send_op_equal
<<-CODE
t1 = stack_pop();
t2 = stack_back(0);
- /* If both are fixnums, or one is a symbol, compare the ops directly. */
- if((FIXNUM_P(t1) && FIXNUM_P(t2)) || SYMBOL_P(t1) || SYMBOL_P(t2)) {
+ /* If both are not references, compare them directly. */
+ if(!REFERENCE_P(t1) && !REFERENCE_P(t2)) {
stack_set_top((t1 == t2) ? Qtrue : Qfalse);
} else {
_lit = global->sym_equal;
@@ -933,8 +933,8 @@ def meta_send_op_nequal
<<-CODE
t1 = stack_pop();
t2 = stack_back(0);
- /* If both are fixnums, or one is a symbol, compare the ops directly. */
- if((FIXNUM_P(t1) && FIXNUM_P(t2)) || SYMBOL_P(t1) || SYMBOL_P(t2)) {
+ /* If both are not references, compare them directly. */
+ if(!REFERENCE_P(t1) && !REFERENCE_P(t2)) {
stack_set_top((t1 == t2) ? Qfalse : Qtrue);
} else {
_lit = global->sym_nequal;
View
42 shotgun/lib/object.c
@@ -253,6 +253,48 @@ OBJECT object_get_ivars(STATE, OBJECT self) {
return object_get_instance_variables(self);
}
+void object_copy_ivars(STATE, OBJECT self, OBJECT dest) {
+ OBJECT tbl;
+ if(!REFERENCE_P(self)) {
+ tbl = hash_find(state, state->global->external_ivars, self);
+ } else if(!object_has_ivars(state, self)) {
+ if(metaclass_s_metaclass_p(state, self->klass)) {
+ tbl = metaclass_get_has_ivars(self->klass);
+ } else {
+ return;
+ }
+ } else {
+ tbl = object_get_instance_variables(self);
+ }
+
+ if(NIL_P(tbl)) return;
+
+ if(ISA(tbl, state->global->tuple)) {
+ tbl = tuple_dup(state, tbl);
+ } else {
+ tbl = hash_dup(state, tbl);
+ }
+
+ if(!REFERENCE_P(dest)) {
+ hash_set(state, state->global->external_ivars, dest, tbl);
+ } else if(!object_has_ivars(state, dest)) {
+ metaclass_set_has_ivars(object_metaclass(state, dest), tbl);
+ } else {
+ object_set_instance_variables(dest, tbl);
+ }
+}
+
+void object_copy_metaclass(STATE, OBJECT self, OBJECT dest) {
+ OBJECT meta, new_meta;
+ if(!REFERENCE_P(self)) return;
+
+ meta = self->klass;
+ if(!metaclass_s_metaclass_p(state, meta)) return;
+
+ new_meta = object_metaclass(state, dest);
+ module_set_methods(new_meta, hash_dup(state, module_get_methods(meta)));
+}
+
int object_stores_bytes_p(STATE, OBJECT self) {
if(!REFERENCE_P(self)) return FALSE;
return self->StoresBytes;
View
2 shotgun/lib/object.h
@@ -22,6 +22,8 @@ void object_set_untainted(STATE, OBJECT self);
int object_tainted_p(STATE, OBJECT self);
void object_set_frozen(STATE, OBJECT self);
int object_frozen_p(STATE, OBJECT self);
+void object_copy_ivars(STATE, OBJECT self, OBJECT dest);
+void object_copy_metaclass(STATE, OBJECT self, OBJECT dest);
OBJECT object_make_weak_ref(STATE, OBJECT self);
void object_cleanup_weak_refs(STATE, OBJECT self);
View
12 shotgun/lib/primitive_names.rb
@@ -97,18 +97,18 @@ class Compiler
:move_bytes,
:io_operation,
:bignum_div,
- nil, # :float_pow,
- nil, # :float_to_i,
+ :fixnum_lt,
+ :fixnum_le,
:numeric_coerce,
:hash_delete,
:bignum_compare,
- nil, # :float_compare,
+ :fixnum_gt,
:fixnum_to_f,
:string_to_f,
- nil, # :float_divmod,
+ :fixnum_ge,
:fixnum_divmod,
:set_byte,
- nil, # :float_round,
+ :object_clone,
:find_method,
:bignum_left_shift,
:bignum_right_shift,
@@ -120,7 +120,7 @@ class Compiler
:object_freeze,
:object_frozen_p,
:fastctx_get_field,
- nil,
+ :object_send,
:fixnum_right_shift,
:fixnum_left_shift,
:vm_stats,
View
95 shotgun/lib/primitives.rb
@@ -234,6 +234,51 @@ def compare(_ = fixnum, t1 = fixnum)
CODE
end
+ def fixnum_lt
+ <<-CODE
+ POP(self, FIXNUM);
+ POP(t1, FIXNUM);
+ j = FIXNUM_TO_INT(self);
+ k = FIXNUM_TO_INT(t1);
+
+ stack_push(j < k ? Qtrue : Qfalse);
+ CODE
+ end
+
+ def fixnum_le
+ <<-CODE
+ POP(self, FIXNUM);
+ POP(t1, FIXNUM);
+ j = FIXNUM_TO_INT(self);
+ k = FIXNUM_TO_INT(t1);
+
+ stack_push(j <= k ? Qtrue : Qfalse);
+ CODE
+ end
+
+ def fixnum_gt
+ <<-CODE
+ POP(self, FIXNUM);
+ POP(t1, FIXNUM);
+ j = FIXNUM_TO_INT(self);
+ k = FIXNUM_TO_INT(t1);
+
+ stack_push(j > k ? Qtrue : Qfalse);
+ CODE
+ end
+
+ def fixnum_ge
+ <<-CODE
+ POP(self, FIXNUM);
+ POP(t1, FIXNUM);
+ j = FIXNUM_TO_INT(self);
+ k = FIXNUM_TO_INT(t1);
+
+ stack_push(j >= k ? Qtrue : Qfalse);
+ CODE
+ end
+
+
def at
<<-CODE
self = stack_pop(); GUARD( INDEXED(self) )
@@ -814,7 +859,7 @@ def dup_into
stack_push(t1);
CODE
end
-
+
def bytes_dup_into
<<-CODE
POP(self, REFERENCE);
@@ -851,14 +896,37 @@ def object_dup
}
}
stack_push(t2);
- /* TODO: copy the ivars in slot 0 */
+ object_copy_ivars(state, t1, t2);
cpu_perform_hook(state, c, t2, state->global->sym_init_copy, t1);
} else {
stack_push(t1);
}
CODE
end
+ def object_clone
+ <<-CODE
+ POP(t1, REFERENCE);
+ j = NUM_FIELDS(t1);
+ t2 = NEW_OBJECT(object_class(state, t1), j);
+ if(t1->StoresBytes) {
+ memcpy(object_byte_start(state, t2),
+ object_byte_start(state, t1), SIZE_OF_BODY(t1));
+ t2->StoresBytes = 1;
+ } else {
+ for(k = 0; k < j; k++) {
+ SET_FIELD(t2, k, NTH_FIELD(t1, k));
+ }
+ }
+ stack_push(t2);
+ object_copy_ivars(state, t1, t2);
+ object_copy_metaclass(state, t1, t2);
+ cpu_perform_hook(state, c, t2, state->global->sym_init_copy, t1);
+
+ CODE
+ end
+
+
def fastctx_dup
<<-CODE
POP(self, REFERENCE);
@@ -1051,7 +1119,7 @@ def stat_file
if(j != 0) {
stack_push(Qfalse);
} else {
- t2 = NEW_OBJECT(self, 11);
+ t2 = NEW_OBJECT(self, 12);
tuple_put(state, t2, 0, I2N((int)sb.st_ino));
tuple_put(state, t2, 1, I2N((int)sb.st_mode));
@@ -1095,6 +1163,7 @@ def stat_file
tuple_put(state, t2, 8, UI2N((int)sb.st_mtime));
tuple_put(state, t2, 9, UI2N((int)sb.st_ctime));
tuple_put(state, t2, 10, t1);
+ tuple_put(state, t2, 11, UI2N((unsigned long)sb.st_blksize));
stack_push(t2);
}
@@ -2808,6 +2877,26 @@ def string_equal
}
CODE
end
+
+ def object_send
+ <<-CODE
+ self = stack_pop();
+ GUARD(num_args >= 1);
+ t1 = stack_pop();
+ if(!SYMBOL_P(t1)) {
+ if(STRING_P(t1)) {
+ t1 = string_to_sym(state, t1);
+ } else {
+ GUARD(0);
+ }
+ }
+
+ /* Send is allowed to call private methods. */
+ c->call_flags = 1;
+
+ cpu_unified_send(state, c, self, t1, num_args - 1, block);
+ CODE
+ end
end
View
10 shotgun/lib/tuple.c
@@ -1,5 +1,4 @@
#include <stdarg.h>
-
#include "shotgun/lib/shotgun.h"
#include "shotgun/lib/tuple.h"
@@ -16,6 +15,15 @@ OBJECT tuple_enlarge(STATE, OBJECT tup, int inc) {
return ns;
}
+OBJECT tuple_dup(STATE, OBJECT tup) {
+ OBJECT ns;
+
+ ns = tuple_new(state, NUM_FIELDS(tup));
+ object_copy_fields_from(state, tup, ns, 0, NUM_FIELDS(tup));
+
+ return ns;
+}
+
OBJECT tuple_new2(STATE, int n, ...) {
va_list ar;
OBJECT tup;
View
1 shotgun/lib/tuple.h
@@ -4,3 +4,4 @@
#define tuple_put(state, tup, idx, val) SET_FIELD(tup, idx, val)
OBJECT tuple_new2(STATE, int n, ...);
OBJECT tuple_enlarge(STATE, OBJECT tup, int inc);
+OBJECT tuple_dup(STATE, OBJECT tup);

0 comments on commit 475b9e5

Please sign in to comment.
Something went wrong with that request. Please try again.