Skip to content

Commit 4c1f3cb

Browse files
committed
Objspace memsize
PullRequest: truffleruby/740
2 parents 50191c9 + e0a7edd commit 4c1f3cb

File tree

7 files changed

+57
-6
lines changed

7 files changed

+57
-6
lines changed

lib/truffle/objspace.rb

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,9 @@ def dump_all(output: :file)
152152
module_function :dump_all
153153

154154
def memsize_of(object)
155-
Truffle::ObjSpace.memsize_of(object)
155+
size = Truffle::ObjSpace.memsize_of(object)
156+
157+
size + Truffle::ObjSpace.sizer(object).call unless Truffle::ObjSpace.sizer(object).nil?
156158
end
157159
module_function :memsize_of
158160

lib/truffle/truffle/cext.rb

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1415,27 +1415,29 @@ def rb_data_object_wrap(ruby_class, data, mark, free)
14151415
object
14161416
end
14171417

1418-
def rb_data_typed_object_wrap(ruby_class, data, data_type, mark, free)
1418+
def rb_data_typed_object_wrap(ruby_class, data, data_type, mark, free, size)
14191419
ruby_class = Object if Truffle::Interop.null?(ruby_class)
14201420
object = BASIC_OBJECT_ALLOCATE.bind(ruby_class).call
14211421
data_holder = DataHolder.new(data)
14221422
hidden_variable_set object, :data_type, data_type
14231423
hidden_variable_set object, :data_holder, data_holder
14241424
ObjectSpace.define_finalizer object, data_finalizer(free, data_holder) unless free.nil?
1425+
Truffle::ObjSpace.define_sizer object, data_sizer(size, data_holder) unless size.nil?
14251426
define_marker object, data_marker(mark, data_holder) unless mark.nil?
14261427
object
14271428
end
14281429

1430+
# These data function are created in separate methods to ensure they
1431+
# will not accidentally capture the objects they operate on, which
1432+
# might prevent garbage collection.
14291433
def data_finalizer(free, data_holder)
1430-
# In a separate method to avoid capturing the object
14311434
raise unless free.respond_to?(:call)
14321435
proc {
14331436
Truffle.invoke_primitive(:interop_call_c_with_mutex, free, [data_holder.data]) unless data_holder.data.nil?
14341437
}
14351438
end
14361439

14371440
def data_marker(mark, data_holder)
1438-
# In a separate method to avoid capturing the object
14391441
raise unless mark.respond_to?(:call)
14401442
proc { |obj|
14411443
create_mark_list
@@ -1444,6 +1446,13 @@ def data_marker(mark, data_holder)
14441446
}
14451447
end
14461448

1449+
def data_sizer(sizer, data_holder)
1450+
raise unless sizer.respond_to?(:call)
1451+
proc {
1452+
Truffle.invoke_primitive(:interop_call_c_with_mutex, sizer, [data_holder.data])
1453+
}
1454+
end
1455+
14471456
def rb_ruby_verbose_ptr
14481457
$VERBOSE
14491458
end

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,11 @@ void sample_typed_wrapped_struct_mark(void* st) {
4343
}
4444

4545
size_t sample_typed_wrapped_struct_memsize(const void* st) {
46-
return sizeof(struct sample_typed_wrapped_struct);
46+
if (st == NULL) {
47+
return 0;
48+
} else {
49+
return ((struct sample_typed_wrapped_struct *)st)->foo;
50+
}
4751
}
4852

4953
static const rb_data_type_t sample_typed_wrapped_struct_data_type = {

spec/ruby/optional/capi/typed_data_spec.rb

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
require_relative 'spec_helper'
2+
require 'objspace'
23

34
load_extension("typed_data")
45

@@ -7,6 +8,14 @@
78
@s = CApiAllocTypedSpecs.new
89
@s.typed_wrapped_data.should == 42 # not defined in initialize
910
end
11+
12+
it "uses the specified memsize function for ObjectSpace.memsize" do
13+
@s = CApiAllocTypedSpecs.new
14+
# The defined memsize function for the type should return 42 as
15+
# the size, and this should be added to the size of the object as
16+
# known by Ruby.
17+
ObjectSpace.memsize_of(@s).should > 42
18+
end
1019
end
1120

1221
describe "CApiWrappedTypedStruct" do

src/main/c/cext/ruby.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2838,7 +2838,7 @@ VALUE rb_data_object_alloc_managed(VALUE klass, size_t size, RUBY_DATA_FUNC dmar
28382838

28392839
VALUE rb_data_typed_object_wrap(VALUE ruby_class, void *data, const rb_data_type_t *data_type) {
28402840
return rb_tr_wrap(polyglot_invoke(RUBY_CEXT, "rb_data_typed_object_wrap",
2841-
rb_tr_unwrap(ruby_class), data, data_type, data_type->function.dmark, rb_tr_free_function(data_type->function.dfree)));
2841+
rb_tr_unwrap(ruby_class), data, data_type, data_type->function.dmark, rb_tr_free_function(data_type->function.dfree), data_type->function.dsize));
28422842
}
28432843

28442844
VALUE rb_data_typed_object_zalloc(VALUE ruby_class, size_t size, const rb_data_type_t *data_type) {

src/main/java/org/truffleruby/Layouts.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ public abstract class Layouts {
104104
public static final HiddenKey ASSOCIATED_IDENTIFIER = new HiddenKey("associated");
105105
public static final HiddenKey FINALIZER_REF_IDENTIFIER = new HiddenKey("finalizerRef");
106106
public static final HiddenKey MARKED_OBJECTS_IDENTIFIER = new HiddenKey("marked_objects");
107+
public static final HiddenKey MEMSIZER_IDENTIFIER = new HiddenKey("memsizer");
107108
public static final HiddenKey VALUE_WRAPPER_IDENTIFIER = new HiddenKey("value_wrapper");
108109

109110
// Generated layouts

src/main/java/org/truffleruby/stdlib/ObjSpaceNodes.java

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@
1919
import org.truffleruby.core.regexp.MatchDataNodes.ValuesNode;
2020
import org.truffleruby.core.string.StringOperations;
2121
import org.truffleruby.language.objects.ObjectGraph;
22+
import org.truffleruby.language.objects.ReadObjectFieldNode;
23+
import org.truffleruby.language.objects.ReadObjectFieldNodeGen;
24+
import org.truffleruby.language.objects.WriteObjectFieldNode;
25+
import org.truffleruby.language.objects.WriteObjectFieldNodeGen;
2226

2327
import java.util.Set;
2428

@@ -65,7 +69,29 @@ public int memsizeOfObject(DynamicObject object) {
6569
public int memsize(Object object) {
6670
return 0;
6771
}
72+
}
73+
74+
@CoreMethod(names = "sizer", isModuleFunction = true, required = 1)
75+
public abstract static class GetMemSizer extends CoreMethodArrayArgumentsNode {
76+
77+
@Child private ReadObjectFieldNode readSizerNode = ReadObjectFieldNodeGen.create(Layouts.MEMSIZER_IDENTIFIER, nil());
78+
79+
@Specialization
80+
public Object hasSizer(DynamicObject object) {
81+
return readSizerNode.execute(object);
82+
}
83+
}
84+
85+
@CoreMethod(names = "define_sizer", isModuleFunction = true, required = 2)
86+
public abstract static class DefineMemSizer extends CoreMethodArrayArgumentsNode {
87+
88+
@Child private WriteObjectFieldNode setSizerNode = WriteObjectFieldNodeGen.create(Layouts.MEMSIZER_IDENTIFIER);
6889

90+
@Specialization
91+
public DynamicObject defineSizer(DynamicObject object, DynamicObject sizer) {
92+
setSizerNode.write(object, sizer);
93+
return nil();
94+
}
6995
}
7096

7197
@CoreMethod(names = "adjacent_objects", isModuleFunction = true, required = 1)

0 commit comments

Comments
 (0)