From ba1e3c4b23566582ca4a824833673bddba384683 Mon Sep 17 00:00:00 2001 From: jj Date: Thu, 3 May 2012 18:49:12 +0200 Subject: [PATCH] ruby: vmethod call --- plugins/ruby/codegen.pl | 45 ++++++++++++++++++++++++++++++++-- plugins/ruby/ruby-memstruct.rb | 16 +++++++++++- plugins/ruby/ruby.cpp | 16 ++++++++++++ 3 files changed, 74 insertions(+), 3 deletions(-) diff --git a/plugins/ruby/codegen.pl b/plugins/ruby/codegen.pl index 9adff9d20..079410791 100755 --- a/plugins/ruby/codegen.pl +++ b/plugins/ruby/codegen.pl @@ -29,7 +29,7 @@ sub rb_ucase { my %global_type_renderer = ( 'enum-type' => \&render_global_enum, - 'struct-type' => \&render_global_class, + 'struct-type' => \&render_global_struct, 'class-type' => \&render_global_class, 'bitfield-type' => \&render_global_bitfield, ); @@ -150,7 +150,24 @@ sub render_bitfield_fields { } -my $cpp_var_counter = 0; +sub render_global_struct { + my ($name, $type) = @_; + + my $rbname = rb_ucase($name); + + my $cppns = "df::$name"; + push @lines_cpp, "}" if @include_cpp; + push @lines_cpp, "void cpp_$name(FILE *fout) {"; + push @include_cpp, $name; + + push @lines_rb, "class $rbname < MemHack::Compound"; + indent_rb { + my $sz = query_cpp("sizeof($cppns)"); + push @lines_rb, "sizeof $sz"; + render_struct_fields($type, "$cppns"); + }; + push @lines_rb, "end\n"; +} my %seen_class; sub render_global_class { my ($name, $type) = @_; @@ -184,6 +201,8 @@ sub render_global_class { push @lines_rb, "sizeof $sz"; push @lines_rb, "rtti_classname :$rtti_name" if $rtti_name; render_struct_fields($type, "$cppns"); + my $vms = $type->findnodes('child::virtual-methods')->[0]; + render_class_vmethods($vms) if $vms; }; push @lines_rb, "end\n"; } @@ -206,6 +225,28 @@ sub render_struct_fields { push @lines_rb, "}"; } } +sub render_class_vmethods { + my ($vms) = @_; + my $voff = 0; + for my $meth ($vms->findnodes('child::vmethod')) { + my $name = $meth->getAttribute('name'); + if ($name) { + my @argnames; + for my $arg ($meth->findnodes('child::ld:field')) { + my $nr = $#argnames + 1; + push @argnames, lcfirst($arg->getAttribute('name') || "arg$nr"); + } + push @lines_rb, "def $name(" . join(', ', @argnames) . ')'; + indent_rb { + push @lines_rb, "DFHack.vmethod_call(self, $voff" . join('', map { ", $_" } @argnames) . ')' + # TODO interpret return type (eg pointer to vector) + }; + push @lines_rb, 'end'; + } + $voff += 4; + } + +} sub render_global_objects { my (@objects) = @_; diff --git a/plugins/ruby/ruby-memstruct.rb b/plugins/ruby/ruby-memstruct.rb index 82b158779..e5da44f10 100644 --- a/plugins/ruby/ruby-memstruct.rb +++ b/plugins/ruby/ruby-memstruct.rb @@ -191,7 +191,6 @@ class Number < MemStruct end end class Float < MemStruct - # _get/_set defined in ruby.cpp def _get DFHack.memory_read_float(@_memaddr) end @@ -710,6 +709,21 @@ def self.rtti_getvtable(cppname) v if v != 0 end +def self.vmethod_call(obj, voff, a0=0, a1=0, a2=0, a3=0, a4=0) + vmethod_do_call(obj._memaddr, voff, vmethod_arg(a0), vmethod_arg(a1), vmethod_arg(a2), vmethod_arg(a3)) +end + +def self.vmethod_arg(arg) + case arg + when nil, false; 0 + when true; 1 + when Integer; arg + #when String; [arg].pack('p').unpack('L')[0] # raw pointer to buffer + when MemHack::Compound; arg._memaddr + else raise "bad vmethod arg #{arg.class}" + end +end + end diff --git a/plugins/ruby/ruby.cpp b/plugins/ruby/ruby.cpp index 159b48a75..76d6a0431 100644 --- a/plugins/ruby/ruby.cpp +++ b/plugins/ruby/ruby.cpp @@ -630,6 +630,21 @@ static VALUE rb_dfmemory_bitarray_set(VALUE self, VALUE addr, VALUE idx, VALUE v } +/* call an arbitrary object virtual method */ +static VALUE rb_dfvcall(VALUE self, VALUE cppobj, VALUE cppvoff, VALUE a0, VALUE a1, VALUE a2, VALUE a3) +{ +#ifdef WIN32 + __thiscall +#endif + int (*fptr)(char **me, int, int, int, int); + char **that = (char**)rb_num2ulong(cppobj); + int ret; + fptr = (decltype(fptr))*(void**)(*that + rb_num2ulong(cppvoff)); + ret = fptr(that, rb_num2ulong(a0), rb_num2ulong(a1), rb_num2ulong(a2), rb_num2ulong(a3)); + return rb_uint2inum(ret); +} + + // define module DFHack and its methods static void ruby_bind_dfhack(void) { @@ -649,6 +664,7 @@ static void ruby_bind_dfhack(void) { rb_define_singleton_method(rb_cDFHack, "print_err", RUBY_METHOD_FUNC(rb_dfprint_err), 1); rb_define_singleton_method(rb_cDFHack, "malloc", RUBY_METHOD_FUNC(rb_dfmalloc), 1); rb_define_singleton_method(rb_cDFHack, "free", RUBY_METHOD_FUNC(rb_dffree), 1); + rb_define_singleton_method(rb_cDFHack, "vmethod_do_call", RUBY_METHOD_FUNC(rb_dfvcall), 6); rb_define_const(rb_cDFHack, "REBASE_DELTA", rb_dfrebase_delta()); rb_define_singleton_method(rb_cDFHack, "memory_read", RUBY_METHOD_FUNC(rb_dfmemory_read), 2);