Skip to content

Commit 711dc7c

Browse files
committed
[GR-19220] Implement rb_get_alloc_func and spec related functions (#1874).
PullRequest: truffleruby/1232
2 parents f5eaf06 + fcbf9cb commit 711dc7c

39 files changed

+174
-40
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ Compatibility:
8181
* Implemented `rb_module_new`, `rb_define_class_id`, `rb_define_module_id`, (#1876, @chrisseaton).
8282
* Implemented `-n` CLI option (#1532).
8383
* Cache the `Symbol` of method names in call nodes only when needed (#1872).
84+
* Implemented `rb_get_alloc_func` and related functions (#1874, @XrXr).
8485

8586
Performance:
8687

lib/truffle/truffle/cext.rb

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ module Truffle::CExt
1414
DATA_HOLDER = Object.new
1515
DATA_MEMSIZER = Object.new
1616
RB_TYPE = Object.new
17+
ALLOCATOR_FUNC = Object.new
1718

1819
extend self
1920

@@ -350,13 +351,14 @@ def rb_tr_find_type(value)
350351
when Symbol
351352
T_SYMBOL
352353
when Integer
353-
#rb_tr_cached_type. The final type must be calculated for each number.
354+
# See #rb_tr_cached_type, the final type must be calculated for each number.
354355
T_FIXNUM
355356
when Time
356357
T_DATA
357358
when Data
358359
T_DATA
359360
when BasicObject
361+
# See #rb_tr_cached_type, the final type must be calculated for each object.
360362
T_NONE
361363
else
362364
raise "unknown type #{value.class}"
@@ -1282,17 +1284,37 @@ def rb_eval_string(str)
12821284
eval(str)
12831285
end
12841286

1287+
def rb_newobj_of(ruby_class)
1288+
ruby_class.__send__(:__layout_allocate__)
1289+
end
1290+
12851291
def rb_define_alloc_func(ruby_class, function)
12861292
ruby_class.singleton_class.define_method(:__allocate__) do
12871293
TrufflePrimitive.cext_unwrap(TrufflePrimitive.call_with_c_mutex(function, [TrufflePrimitive.cext_wrap(self)]))
12881294
end
12891295
class << ruby_class
12901296
private :__allocate__
12911297
end
1298+
hidden_variable_set(ruby_class.singleton_class, ALLOCATOR_FUNC, function)
1299+
end
1300+
1301+
def rb_get_alloc_func(ruby_class)
1302+
return nil unless Class === ruby_class
1303+
begin
1304+
allocate_method = ruby_class.method(:__allocate__).owner
1305+
rescue NameError
1306+
nil
1307+
else
1308+
hidden_variable_get(allocate_method, ALLOCATOR_FUNC)
1309+
end
12921310
end
12931311

12941312
def rb_undef_alloc_func(ruby_class)
12951313
ruby_class.singleton_class.send(:undef_method, :__allocate__)
1314+
rescue NameError
1315+
nil # it's fine to call this on a class that doesn't have an allocator
1316+
else
1317+
hidden_variable_set(ruby_class.singleton_class, ALLOCATOR_FUNC, nil)
12961318
end
12971319

12981320
def rb_alias(mod, new_name, old_name)
@@ -1436,11 +1458,9 @@ def rb_nativethread_lock_destroy(lock)
14361458
NATIVETHREAD_LOCKS.delete(lock)
14371459
end
14381460

1439-
BASIC_OBJECT_ALLOCATE = BasicObject.method(:__allocate__).unbind
1440-
14411461
def rb_data_object_wrap(ruby_class, data, mark, free)
14421462
ruby_class = Object unless ruby_class
1443-
object = BASIC_OBJECT_ALLOCATE.bind(ruby_class).call
1463+
object = ruby_class.__send__(:__layout_allocate__)
14441464
data_holder = DataHolder.new(data)
14451465
hidden_variable_set object, DATA_HOLDER, data_holder
14461466
ObjectSpace.define_finalizer object, data_finalizer(free, data_holder) unless free.nil?
@@ -1450,7 +1470,7 @@ def rb_data_object_wrap(ruby_class, data, mark, free)
14501470

14511471
def rb_data_typed_object_wrap(ruby_class, data, data_type, mark, free, size)
14521472
ruby_class = Object unless ruby_class
1453-
object = BASIC_OBJECT_ALLOCATE.bind(ruby_class).call
1473+
object = ruby_class.__send__(:__layout_allocate__)
14541474
data_holder = DataHolder.new(data)
14551475
hidden_variable_set object, :data_type, data_type
14561476
hidden_variable_set object, DATA_HOLDER, data_holder

spec/ruby/optional/capi/ext/object_spec.c

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,39 @@ static VALUE object_spec_rb_class_inherited_p(VALUE self, VALUE mod, VALUE arg)
345345
return rb_class_inherited_p(mod, arg);
346346
}
347347

348+
static VALUE speced_allocator(VALUE klass) {
349+
VALUE flags = 0;
350+
if (rb_class_inherited_p(klass, rb_cString)) {
351+
flags = T_STRING;
352+
} else if (rb_class_inherited_p(klass, rb_cArray)) {
353+
flags = T_ARRAY;
354+
} else {
355+
flags = T_OBJECT;
356+
}
357+
VALUE instance = rb_newobj_of(klass, flags);
358+
rb_iv_set(instance, "@from_custom_allocator", Qtrue);
359+
return instance;
360+
}
361+
362+
static VALUE define_alloc_func(VALUE self, VALUE klass) {
363+
rb_define_alloc_func(klass, speced_allocator);
364+
return Qnil;
365+
}
366+
367+
static VALUE undef_alloc_func(VALUE self, VALUE klass) {
368+
rb_undef_alloc_func(klass);
369+
return Qnil;
370+
}
371+
372+
static VALUE speced_allocator_p(VALUE self, VALUE klass) {
373+
rb_alloc_func_t allocator = rb_get_alloc_func(klass);
374+
return (allocator == speced_allocator) ? Qtrue : Qfalse;
375+
}
376+
377+
static VALUE custom_alloc_func_p(VALUE self, VALUE klass) {
378+
rb_alloc_func_t allocator = rb_get_alloc_func(klass);
379+
return allocator ? Qtrue : Qfalse;
380+
}
348381

349382
void Init_object_spec(void) {
350383
VALUE cls = rb_define_class("CApiObjectSpecs", rb_cObject);
@@ -412,6 +445,10 @@ void Init_object_spec(void) {
412445
rb_define_method(cls, "rb_ivar_defined", object_spec_rb_ivar_defined, 2);
413446
rb_define_method(cls, "rb_copy_generic_ivar", object_spec_rb_copy_generic_ivar, 2);
414447
rb_define_method(cls, "rb_free_generic_ivar", object_spec_rb_free_generic_ivar, 1);
448+
rb_define_method(cls, "rb_define_alloc_func", define_alloc_func, 1);
449+
rb_define_method(cls, "rb_undef_alloc_func", undef_alloc_func, 1);
450+
rb_define_method(cls, "speced_allocator?", speced_allocator_p, 1);
451+
rb_define_method(cls, "custom_alloc_func?", custom_alloc_func_p, 1);
415452
}
416453

417454
#ifdef __cplusplus

spec/ruby/optional/capi/object_spec.rb

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -892,4 +892,78 @@ def reach
892892
end
893893
end
894894
end
895+
896+
describe "allocator accessors" do
897+
describe "rb_define_alloc_func" do
898+
it "sets up the allocator" do
899+
klass = Class.new
900+
@o.rb_define_alloc_func(klass)
901+
obj = klass.allocate
902+
obj.class.should.equal?(klass)
903+
obj.should have_instance_variable(:@from_custom_allocator)
904+
end
905+
906+
it "sets up the allocator for a subclass of String" do
907+
klass = Class.new(String)
908+
@o.rb_define_alloc_func(klass)
909+
obj = klass.allocate
910+
obj.class.should.equal?(klass)
911+
obj.should have_instance_variable(:@from_custom_allocator)
912+
obj.should == ""
913+
end
914+
915+
it "sets up the allocator for a subclass of Array" do
916+
klass = Class.new(Array)
917+
@o.rb_define_alloc_func(klass)
918+
obj = klass.allocate
919+
obj.class.should.equal?(klass)
920+
obj.should have_instance_variable(:@from_custom_allocator)
921+
obj.should == []
922+
end
923+
end
924+
925+
describe "rb_get_alloc_func" do
926+
it "gets the allocator that is defined directly on a class" do
927+
klass = Class.new
928+
@o.rb_define_alloc_func(klass)
929+
@o.speced_allocator?(Object).should == false
930+
@o.speced_allocator?(klass).should == true
931+
end
932+
933+
it "gets the allocator that is inherited" do
934+
parent = Class.new
935+
@o.rb_define_alloc_func(parent)
936+
klass = Class.new(parent)
937+
@o.speced_allocator?(Object).should == false
938+
@o.speced_allocator?(klass).should == true
939+
end
940+
end
941+
942+
describe "rb_undef_alloc_func" do
943+
it "makes rb_get_alloc_func() return NULL for a class without a custom allocator" do
944+
klass = Class.new
945+
@o.rb_undef_alloc_func(klass)
946+
@o.custom_alloc_func?(klass).should == false
947+
end
948+
949+
it "undefs the allocator for the class" do
950+
klass = Class.new
951+
@o.rb_define_alloc_func(klass)
952+
@o.speced_allocator?(klass).should == true
953+
@o.rb_undef_alloc_func(klass)
954+
@o.custom_alloc_func?(klass).should == false
955+
end
956+
957+
it "undefs the allocator for a class that inherits a allocator" do
958+
parent = Class.new
959+
@o.rb_define_alloc_func(parent)
960+
klass = Class.new(parent)
961+
@o.speced_allocator?(klass).should == true
962+
@o.rb_undef_alloc_func(klass)
963+
@o.custom_alloc_func?(klass).should == false
964+
965+
@o.speced_allocator?(parent).should == true
966+
end
967+
end
968+
end
895969
end

spec/tags/core/process/exec_tags.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,4 @@ slow:Process.exec with a command array raises an ArgumentError if the Array does
2020
slow:Process.exec with an options Hash with Integer option keys maps the key to a file descriptor in the child that inherits the file descriptor from the parent specified by the value
2121
slow:Process.exec with an options Hash with Integer option keys lets the process after exec have specified file descriptor despite close_on_exec
2222
slow:Process.exec with an options Hash with Integer option keys sets close_on_exec to false on specified fd even when it fails
23+
jvm(transient, JDK11, since PR 1232):Process.exec with an options Hash with Integer option keys maps the key to a file descriptor in the child that inherits the file descriptor from the parent specified by the value

src/main/c/cext/ruby.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3698,7 +3698,7 @@ void rb_remove_method_id(VALUE klass, ID mid) {
36983698
}
36993699

37003700
rb_alloc_func_t rb_get_alloc_func(VALUE klass) {
3701-
rb_tr_error("rb_get_alloc_func not implemented");
3701+
return RUBY_CEXT_INVOKE_NO_WRAP("rb_get_alloc_func", klass);
37023702
}
37033703

37043704
void rb_clear_constant_cache(void) {
@@ -4680,7 +4680,8 @@ VALUE rb_newobj(void) {
46804680
}
46814681

46824682
VALUE rb_newobj_of(VALUE klass, VALUE flags) {
4683-
rb_tr_error("rb_newobj_of not implemented");
4683+
// ignore flags for now
4684+
return RUBY_CEXT_INVOKE("rb_newobj_of", klass);
46844685
}
46854686

46864687
VALUE rb_obj_setup(VALUE obj, VALUE klass, VALUE type) {

src/main/java/org/truffleruby/core/array/ArrayNodes.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@
8686
@CoreModule(value = "Array", isClass = true)
8787
public abstract class ArrayNodes {
8888

89-
@CoreMethod(names = "__allocate__", constructor = true, visibility = Visibility.PRIVATE)
89+
@CoreMethod(names = { "__allocate__", "__layout_allocate__" }, constructor = true, visibility = Visibility.PRIVATE)
9090
public abstract static class AllocateNode extends CoreMethodArrayArgumentsNode {
9191

9292
@Child private AllocateObjectNode allocateNode = AllocateObjectNode.create();

src/main/java/org/truffleruby/core/basicobject/BasicObjectNodes.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -509,7 +509,7 @@ protected Object send(VirtualFrame frame, Object self, Object name, Object[] arg
509509
// MRI names it the "allocator function" and it's associated per class and follows the ancestor
510510
// chain. We use a normal Ruby method, different that Class#allocate as Class#allocate
511511
// must be able to instantiate any Ruby object and should not be overridden.
512-
@CoreMethod(names = "__allocate__", constructor = true, visibility = Visibility.PRIVATE)
512+
@CoreMethod(names = { "__allocate__", "__layout_allocate__" }, constructor = true, visibility = Visibility.PRIVATE)
513513
public abstract static class AllocateNode extends CoreMethodArrayArgumentsNode {
514514

515515
@Child private AllocateObjectNode allocateObjectNode = AllocateObjectNode.create();

src/main/java/org/truffleruby/core/binding/BindingNodes.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -391,7 +391,7 @@ protected Object sourceLocation(DynamicObject binding,
391391
}
392392
}
393393

394-
@CoreMethod(names = "__allocate__", constructor = true, visibility = Visibility.PRIVATE)
394+
@CoreMethod(names = { "__allocate__", "__layout_allocate__" }, constructor = true, visibility = Visibility.PRIVATE)
395395
public abstract static class AllocateNode extends UnaryCoreMethodNode {
396396

397397
@TruffleBoundary

src/main/java/org/truffleruby/core/encoding/EncodingConverterNodes.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ private int toJCodingFlags(int flags) {
147147

148148
}
149149

150-
@CoreMethod(names = "__allocate__", constructor = true, visibility = Visibility.PRIVATE)
150+
@CoreMethod(names = { "__allocate__", "__layout_allocate__" }, constructor = true, visibility = Visibility.PRIVATE)
151151
public abstract static class AllocateNode extends CoreMethodArrayArgumentsNode {
152152

153153
@Child private AllocateObjectNode allocateNode = AllocateObjectNode.create();

0 commit comments

Comments
 (0)