From ff6d0c4e7dd28051258bbfbeb3d7be0ed39f5091 Mon Sep 17 00:00:00 2001 From: Pauli Date: Wed, 4 Jul 2018 23:35:07 +0300 Subject: [PATCH] Fix memory return calling convention in ruby bindings Calling convention for memory return is that caller allocates (in stack) memory to hold returned object. Then caller passes the pointer to callee as implicit first parameter. references: https://github.com/hjl-tools/x86-psABI/wiki/X86-psABI https://msdn.microsoft.com/en-us/library/7572ztz4.aspx Fixes #1209 --- plugins/ruby/codegen.pl | 19 ++++++++++++++++++- plugins/ruby/ruby-autogen-defs.rb | 8 ++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/plugins/ruby/codegen.pl b/plugins/ruby/codegen.pl index ad5f4b239..2a12a1bea 100755 --- a/plugins/ruby/codegen.pl +++ b/plugins/ruby/codegen.pl @@ -462,8 +462,13 @@ sub render_class_vmethods { push @lines_rb, "def $name(" . join(', ', @argnames) . ')'; indent_rb { my $args = join('', map { ", $_" } @argargs); - my $call = "DFHack.vmethod_call(self, $voff$args)"; my $ret = $meth->findnodes('child::ret-type')->[0]; + my $call; + if (!$ret or $ret->getAttribute('ld:meta') ne 'primitive') { + $call = "DFHack.vmethod_call(self, $voff$args)"; + } else { + $call = "DFHack.vmethod_call_mem_return(self, $voff, rv$args)"; + } render_class_vmethod_ret($call, $ret); }; push @lines_rb, 'end'; @@ -534,6 +539,18 @@ sub render_class_vmethod_ret { }; push @lines_rb, "end._at(ptr) if ptr != 0"; } + elsif ($retmeta eq 'primitive') + { + my $subtype = $ret->getAttribute('ld:subtype'); + if ($subtype eq 'stl-string') { + push @lines_rb, "rv = DFHack::StlString.cpp_new"; + push @lines_rb, $call; + push @lines_rb, "rv"; + } else { + print "Unknown return subtype for $call\n"; + push @lines_rb, "nil"; + } + } else { print "vmethod unkret $call\n"; diff --git a/plugins/ruby/ruby-autogen-defs.rb b/plugins/ruby/ruby-autogen-defs.rb index ca5d82393..10727894d 100644 --- a/plugins/ruby/ruby-autogen-defs.rb +++ b/plugins/ruby/ruby-autogen-defs.rb @@ -994,6 +994,14 @@ module DFHack vmethod_arg(a3), vmethod_arg(a4), vmethod_arg(a5)) end + def self.vmethod_call_mem_return(obj, voff, r0=0, a0=0, a1=0, a2=0, a3=0, a4=0) + this = obj._memaddr + vt = df.get_vtable_ptr(this) + fptr = df.memory_read_ptr(vt + voff) + vmethod_do_call(vmethod_arg(r0), fptr, this, vmethod_arg(a0), vmethod_arg(a1), vmethod_arg(a2), + vmethod_arg(a3), vmethod_arg(a4)) + end + def self.vmethod_arg(arg) case arg when nil, false; 0