mirror of
https://github.com/ruby/ruby.git
synced 2026-10-28 08:25:20 +08:00
Use Marshal compat from Ractor courier
For some types (probably most notably Set), Marshal loading is defined with compatibility functions. We should use those when set.
This commit is contained in:
1 parent
742699d231
commit
1bd863dd23
4 files changed
+57
Notes:
git
2026-09-17 16:34:12 +00:00
No files matched your search
@@ -0,0 +1,17 @@
|
||||
#ifndef INTERNAL_MARSHAL_H /*-*-C-*-vi:se ft=c:*/
|
||||
#define INTERNAL_MARSHAL_H
|
||||
/**
|
||||
* @author Ruby developers <ruby-core@ruby-lang.org>
|
||||
* @copyright This file is a part of the programming language Ruby.
|
||||
* Permission is hereby granted, to either redistribute and/or
|
||||
* modify this file, provided that the conditions mentioned in the
|
||||
* file COPYING are met. Consult the file for details.
|
||||
* @brief Internal header for Marshal.
|
||||
*/
|
||||
#include "ruby/internal/stdbool.h" /* for bool */
|
||||
#include "ruby/ruby.h" /* for VALUE */
|
||||
|
||||
/* marshal.c */
|
||||
bool rb_marshal_compat_lookup(VALUE klass, VALUE (**dumper)(VALUE), VALUE (**loader)(VALUE, VALUE));
|
||||
|
||||
#endif /* INTERNAL_MARSHAL_H */
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "internal/encoding.h"
|
||||
#include "internal/error.h"
|
||||
#include "internal/hash.h"
|
||||
#include "internal/marshal.h"
|
||||
#include "internal/numeric.h"
|
||||
#include "internal/object.h"
|
||||
#include "internal/re.h"
|
||||
@@ -155,6 +156,21 @@ rb_marshal_define_compat(VALUE newclass, VALUE oldclass, VALUE (*dumper)(VALUE),
|
||||
RB_OBJ_WRITTEN(compat_allocator_tbl_wrapper, Qundef, oldclass);
|
||||
}
|
||||
|
||||
/* The rb_marshal_define_compat entry for an instance of klass, if any, so the Ractor
|
||||
* courier can dump and load it the way Marshal does. */
|
||||
bool
|
||||
rb_marshal_compat_lookup(VALUE klass, VALUE (**dumper)(VALUE), VALUE (**loader)(VALUE, VALUE))
|
||||
{
|
||||
st_data_t data;
|
||||
rb_alloc_func_t allocator = RCLASS_SINGLETON_P(klass) ? 0 : rb_get_alloc_func(klass);
|
||||
if (!allocator || !st_lookup(compat_allocator_tbl, (st_data_t)allocator, &data)) return false;
|
||||
marshal_compat_t *compat = (marshal_compat_t *)data;
|
||||
if (!compat->dumper || !compat->loader) return false;
|
||||
if (dumper) *dumper = compat->dumper;
|
||||
if (loader) *loader = compat->loader;
|
||||
return true;
|
||||
}
|
||||
|
||||
struct dump_arg {
|
||||
VALUE str, dest;
|
||||
st_table *symbols;
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "internal/variable.h"
|
||||
#include "eval_intern.h"
|
||||
#include "internal/io.h"
|
||||
#include "internal/marshal.h"
|
||||
#include "internal/ractor.h"
|
||||
#include "internal/rational.h"
|
||||
#include "internal/re.h"
|
||||
@@ -2396,6 +2397,7 @@ enum courier_hook {
|
||||
COURIER_HOOK_NONE,
|
||||
COURIER_HOOK_MARSHAL_DUMP, /* marshal_dump -> alloc + marshal_load */
|
||||
COURIER_HOOK_DUMP, /* _dump -> klass._load */
|
||||
COURIER_HOOK_COMPAT, /* rb_marshal_define_compat dumper -> alloc + loader (Set, Process::Status) */
|
||||
COURIER_HOOK_DUMP_DATA, /* _dump_data -> alloc + _load_data */
|
||||
};
|
||||
|
||||
@@ -2405,6 +2407,7 @@ courier_hook_of(VALUE obj)
|
||||
{
|
||||
if (rb_obj_respond_to(obj, id_marshal_dump, TRUE)) return COURIER_HOOK_MARSHAL_DUMP;
|
||||
if (rb_obj_respond_to(obj, id_dump, TRUE)) return COURIER_HOOK_DUMP;
|
||||
if (rb_marshal_compat_lookup(CLASS_OF(obj), NULL, NULL)) return COURIER_HOOK_COMPAT;
|
||||
if (BUILTIN_TYPE(obj) == T_DATA && rb_obj_respond_to(obj, id_dump_data, TRUE)) return COURIER_HOOK_DUMP_DATA;
|
||||
return COURIER_HOOK_NONE;
|
||||
}
|
||||
@@ -2711,6 +2714,12 @@ courier_capture_hooked(struct courier_build *b, VALUE obj, uint32_t id, enum cou
|
||||
case COURIER_HOOK_DUMP_DATA:
|
||||
payload = rb_funcallv(obj, id_dump_data, 0, 0);
|
||||
break;
|
||||
case COURIER_HOOK_COMPAT: {
|
||||
VALUE (*dumper)(VALUE);
|
||||
rb_marshal_compat_lookup(klass, &dumper, NULL);
|
||||
payload = dumper(obj);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
rb_bug("courier_capture_hooked: no dump protocol");
|
||||
}
|
||||
@@ -3390,6 +3399,12 @@ rb_ractor_courier_materialize(struct rb_ractor_courier *c)
|
||||
}
|
||||
rb_funcallv(shell, mid, 1, &payload);
|
||||
break;
|
||||
case COURIER_HOOK_COMPAT: {
|
||||
VALUE (*loader)(VALUE, VALUE);
|
||||
rb_marshal_compat_lookup(klass, NULL, &loader);
|
||||
loader(shell, payload);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
rb_bug("rb_ractor_courier_materialize: no dump protocol");
|
||||
}
|
||||
|
||||
@@ -271,6 +271,15 @@ class TestRactor < Test::Unit::TestCase
|
||||
assert_copy [Time.now, Ractor::Port.new]
|
||||
# Dump hooks run after the courier is sized, so enough of them make it grow.
|
||||
assert_copy Array.new(2000) { |i| Time.at(i) }
|
||||
# Set has no dump hook of its own; it goes through its rb_marshal_define_compat entry.
|
||||
assert_copy Set.new
|
||||
assert_copy Set[1,2,3]
|
||||
assert_copy Set[+"a", [+"b"], {+"c" => Set[+"d"]}]
|
||||
assert_copy Set[1].compare_by_identity
|
||||
assert_copy Class.new(Set)[1, 2]
|
||||
assert_equal true, echo(Set[1].compare_by_identity).compare_by_identity?
|
||||
set = Set[Ractor::Port.new, Ractor::Port.new] # Marshal cannot carry a Port
|
||||
assert_equal set.to_a, echo(set).to_a
|
||||
|
||||
# Time#_dump keeps these as ivars on the dumped string; Time#== ignores the last two.
|
||||
time = Time.at(0, 123456789, :nsec, in: "+09:00")
|
||||
|
||||
Reference in new issue
Block a user