From daa55388e74cfa4bd289372bfcefebfdc31acacc Mon Sep 17 00:00:00 2001 From: Benoit Daloze Date: Tue, 26 Mar 2024 14:27:07 +0100 Subject: [PATCH 1/5] Cleanup --- src/main/java/org/truffleruby/cext/IsNativeObjectNode.java | 2 +- src/main/java/org/truffleruby/cext/ValueWrapperManager.java | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/truffleruby/cext/IsNativeObjectNode.java b/src/main/java/org/truffleruby/cext/IsNativeObjectNode.java index edabd7a655e5..1ae69063a451 100644 --- a/src/main/java/org/truffleruby/cext/IsNativeObjectNode.java +++ b/src/main/java/org/truffleruby/cext/IsNativeObjectNode.java @@ -28,7 +28,7 @@ public abstract class IsNativeObjectNode extends RubyBaseNode { /** Returns true if handle was natively allocated. */ - public abstract Object execute(Node node, Object handle); + public abstract boolean execute(Node node, Object handle); @Specialization static boolean isNativeObjectTaggedObject(long handle) { diff --git a/src/main/java/org/truffleruby/cext/ValueWrapperManager.java b/src/main/java/org/truffleruby/cext/ValueWrapperManager.java index bbf7374b5cf8..83bde3b7d820 100644 --- a/src/main/java/org/truffleruby/cext/ValueWrapperManager.java +++ b/src/main/java/org/truffleruby/cext/ValueWrapperManager.java @@ -434,7 +434,7 @@ protected boolean isExecutable() { } @ExportMessage - protected Object execute(Object[] arguments, + protected ValueWrapper execute(Object[] arguments, @Cached WrapNode wrapNode) { return wrapNode.execute(arguments[0]); } @@ -450,7 +450,7 @@ protected boolean isExecutable() { } @ExportMessage - protected Object execute(Object[] arguments, + protected boolean execute(Object[] arguments, @Cached IsNativeObjectNode isNativeObjectNode, @Bind("$node") Node node) { return isNativeObjectNode.execute(node, arguments[0]); @@ -467,7 +467,7 @@ protected boolean isExecutable() { } @ExportMessage - protected Object execute(Object[] arguments, + protected long execute(Object[] arguments, @CachedLibrary(limit = "1") InteropLibrary values) throws UnsupportedMessageException { values.toNative(arguments[0]); return values.asPointer(arguments[0]); From bff5f60f2292a5e761ff7ec407ea4341ce118817 Mon Sep 17 00:00:00 2001 From: Benoit Daloze Date: Tue, 9 Apr 2024 13:50:37 +0200 Subject: [PATCH 2/5] Clarify spec --- spec/ruby/optional/capi/ext/kernel_spec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/ruby/optional/capi/ext/kernel_spec.c b/spec/ruby/optional/capi/ext/kernel_spec.c index 1761599081a9..04252b28488a 100644 --- a/spec/ruby/optional/capi/ext/kernel_spec.c +++ b/spec/ruby/optional/capi/ext/kernel_spec.c @@ -221,7 +221,7 @@ static VALUE kernel_spec_rb_eval_string_protect(VALUE self, VALUE str, VALUE ary VALUE kernel_spec_rb_sys_fail(VALUE self, VALUE msg) { errno = 1; if (msg == Qnil) { - rb_sys_fail(0); + rb_sys_fail(NULL); } else if (self != Qundef) { rb_sys_fail(StringValuePtr(msg)); } From 8843340fbcd655d05512bacfcc6ebb2f0c4d657d Mon Sep 17 00:00:00 2001 From: Benoit Daloze Date: Tue, 9 Apr 2024 13:56:00 +0200 Subject: [PATCH 3/5] make_errno_exc_str should be static, it is an internal helper function --- src/main/c/cext/exception.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/c/cext/exception.c b/src/main/c/cext/exception.c index 89d2169e7e69..69788651f241 100644 --- a/src/main/c/cext/exception.c +++ b/src/main/c/cext/exception.c @@ -85,7 +85,7 @@ VALUE rb_syserr_new_str(int n, VALUE mesg) { return RUBY_CEXT_INVOKE("rb_syserr_new", INT2FIX(n), mesg); } -VALUE make_errno_exc_str(VALUE mesg) { +static VALUE make_errno_exc_str(VALUE mesg) { int n = errno; errno = 0; From 7802c09bb7d607091b952b28c45fa447ad898d0f Mon Sep 17 00:00:00 2001 From: Benoit Daloze Date: Tue, 9 Apr 2024 13:42:20 +0200 Subject: [PATCH 4/5] Implement rb_bug() and rb_fatal() to show the error message passed to them --- lib/cext/ABI_check.txt | 2 +- lib/truffle/truffle/cext.rb | 8 ++++++++ src/main/c/cext/exception.c | 12 ++++++++++-- 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/lib/cext/ABI_check.txt b/lib/cext/ABI_check.txt index d00491fd7e5b..0cfbf08886fc 100644 --- a/lib/cext/ABI_check.txt +++ b/lib/cext/ABI_check.txt @@ -1 +1 @@ -1 +2 diff --git a/lib/truffle/truffle/cext.rb b/lib/truffle/truffle/cext.rb index 2b434b0301ad..65c1d0b20270 100644 --- a/lib/truffle/truffle/cext.rb +++ b/lib/truffle/truffle/cext.rb @@ -1784,6 +1784,14 @@ def rb_f_notimplement raise NotImplementedError, "#{function}() function is unimplemented on this machine" end + def rb_bug(message) + raise Exception, "rb_bug: #{message}" + end + + def rb_fatal(message) + raise Exception, "rb_fatal: #{message}" + end + def test_kwargs(kwargs, raise_error) return false if Primitive.nil?(kwargs) diff --git a/src/main/c/cext/exception.c b/src/main/c/cext/exception.c index 69788651f241..509aa8bceed9 100644 --- a/src/main/c/cext/exception.c +++ b/src/main/c/cext/exception.c @@ -156,11 +156,19 @@ void rb_eof_error(void) { } void rb_tr_bug_va_list(const char *fmt, va_list args) { - rb_tr_not_implemented("rb_bug"); + char buffer[1024]; + vsnprintf(buffer, 1024, fmt, args); + VALUE message = rb_str_new_cstr(buffer); + RUBY_CEXT_INVOKE_NO_WRAP("rb_bug", message); + UNREACHABLE; } void rb_tr_fatal_va_list(const char *fmt, va_list args) { - rb_tr_not_implemented("rb_fatal"); + char buffer[1024]; + vsnprintf(buffer, 1024, fmt, args); + VALUE message = rb_str_new_cstr(buffer); + RUBY_CEXT_INVOKE_NO_WRAP("rb_fatal", message); + UNREACHABLE; } VALUE rb_make_exception(int argc, const VALUE *argv) { From 4c08267816f37f95589b63cb64d597e9edae108a Mon Sep 17 00:00:00 2001 From: Benoit Daloze Date: Fri, 23 Feb 2024 16:43:52 +0100 Subject: [PATCH 5/5] Use the Truffle NFI Panama backend for upcalls on JVM * This is significantly faster, about 2.7x as fast as the default libffi backend for a JSON.dump benchmark using the gem C extension. It is even 3.25x as fast as before the Truffle NFI PR adding createNativeClosure(). --- lib/truffle/truffle/cext.rb | 10 +++++++++- src/main/java/org/truffleruby/options/Options.java | 5 +++++ src/options.yml | 1 + .../truffleruby/shared/options/OptionsCatalog.java | 12 ++++++++++++ 4 files changed, 27 insertions(+), 1 deletion(-) diff --git a/lib/truffle/truffle/cext.rb b/lib/truffle/truffle/cext.rb index 65c1d0b20270..a0ba7179f5b0 100644 --- a/lib/truffle/truffle/cext.rb +++ b/lib/truffle/truffle/cext.rb @@ -190,7 +190,15 @@ def self.init_libtrufflerubytrampoline(libtrampoline) init_functions = libtrampoline[:rb_tr_trampoline_init_functions] init_functions = Primitive.interop_eval_nfi('(env,(string):pointer):void').bind(init_functions) - init_functions.call(-> name { LIBTRUFFLERUBY[name] }) + if Truffle::Boot.get_option 'cexts-panama' and Primitive.vm_java_version >= 22 and !TruffleRuby.native? + init_functions.call(-> name { + closure = LIBTRUFFLERUBY[name].createNativeClosure('panama') + keep_alive << closure + closure + }) + else + init_functions.call(-> name { LIBTRUFFLERUBY[name] }) + end init_constants = libtrampoline[:rb_tr_trampoline_init_global_constants] init_constants = Primitive.interop_eval_nfi('((string):pointer):void').bind(init_constants) diff --git a/src/main/java/org/truffleruby/options/Options.java b/src/main/java/org/truffleruby/options/Options.java index 18ddae869636..78f9f56ed765 100644 --- a/src/main/java/org/truffleruby/options/Options.java +++ b/src/main/java/org/truffleruby/options/Options.java @@ -107,6 +107,8 @@ public final class Options { public final boolean CEXTS; /** --cexts-lock=true */ public final boolean CEXT_LOCK; + /** --cexts-panama=false */ + public final boolean CEXTS_PANAMA; /** --options-log=false */ public final boolean OPTIONS_LOG; /** --log-load=false */ @@ -250,6 +252,7 @@ public Options(Env env, OptionValues options, LanguageOptions languageOptions) { BACKTRACE_ON_NEW_FIBER = options.get(OptionsCatalog.BACKTRACE_ON_NEW_FIBER_KEY); CEXTS = options.get(OptionsCatalog.CEXTS_KEY); CEXT_LOCK = options.get(OptionsCatalog.CEXT_LOCK_KEY); + CEXTS_PANAMA = options.get(OptionsCatalog.CEXTS_PANAMA_KEY); OPTIONS_LOG = options.get(OptionsCatalog.OPTIONS_LOG_KEY); LOG_LOAD = options.get(OptionsCatalog.LOG_LOAD_KEY); LOG_AUTOLOAD = options.get(OptionsCatalog.LOG_AUTOLOAD_KEY); @@ -386,6 +389,8 @@ public Object fromDescriptor(OptionDescriptor descriptor) { return CEXTS; case "ruby.cexts-lock": return CEXT_LOCK; + case "ruby.cexts-panama": + return CEXTS_PANAMA; case "ruby.options-log": return OPTIONS_LOG; case "ruby.log-load": diff --git a/src/options.yml b/src/options.yml index a8604741b9bd..afc1d234513f 100644 --- a/src/options.yml +++ b/src/options.yml @@ -133,6 +133,7 @@ EXPERT: # C extension options CEXTS: [cexts, boolean, true, Enable use of C extensions] CEXT_LOCK: [cexts-lock, boolean, true, Use a Global Lock when running C extensions] + CEXTS_PANAMA: [cexts-panama, boolean, false, 'Use Panama for native to Ruby calls in C extensions. Only available in --jvm mode on JDK 22+.'] # Debugging the values of options OPTIONS_LOG: [options-log, boolean, false, Log the final value of all options] diff --git a/src/shared/java/org/truffleruby/shared/options/OptionsCatalog.java b/src/shared/java/org/truffleruby/shared/options/OptionsCatalog.java index b5c6775e6aae..61c97d962e91 100644 --- a/src/shared/java/org/truffleruby/shared/options/OptionsCatalog.java +++ b/src/shared/java/org/truffleruby/shared/options/OptionsCatalog.java @@ -71,6 +71,7 @@ public final class OptionsCatalog { public static final OptionKey BACKTRACE_ON_NEW_FIBER_KEY = new OptionKey<>(false); public static final OptionKey CEXTS_KEY = new OptionKey<>(true); public static final OptionKey CEXT_LOCK_KEY = new OptionKey<>(true); + public static final OptionKey CEXTS_PANAMA_KEY = new OptionKey<>(false); public static final OptionKey OPTIONS_LOG_KEY = new OptionKey<>(false); public static final OptionKey LOG_LOAD_KEY = new OptionKey<>(false); public static final OptionKey LOG_AUTOLOAD_KEY = new OptionKey<>(false); @@ -573,6 +574,14 @@ public final class OptionsCatalog { .usageSyntax("") .build(); + public static final OptionDescriptor CEXTS_PANAMA = OptionDescriptor + .newBuilder(CEXTS_PANAMA_KEY, "ruby.cexts-panama") + .help("Use Panama for native to Ruby calls in C extensions. Only available in --jvm mode on JDK 22+.") + .category(OptionCategory.EXPERT) + .stability(OptionStability.EXPERIMENTAL) + .usageSyntax("") + .build(); + public static final OptionDescriptor OPTIONS_LOG = OptionDescriptor .newBuilder(OPTIONS_LOG_KEY, "ruby.options-log") .help("Log the final value of all options") @@ -1421,6 +1430,8 @@ public static OptionDescriptor fromName(String name) { return CEXTS; case "ruby.cexts-lock": return CEXT_LOCK; + case "ruby.cexts-panama": + return CEXTS_PANAMA; case "ruby.options-log": return OPTIONS_LOG; case "ruby.log-load": @@ -1665,6 +1676,7 @@ public static OptionDescriptor[] allDescriptors() { BACKTRACE_ON_NEW_FIBER, CEXTS, CEXT_LOCK, + CEXTS_PANAMA, OPTIONS_LOG, LOG_LOAD, LOG_AUTOLOAD,