Skip to content

Commit 7dc9597

Browse files
committed
[GR-15903] [GR-15993] Fix FFI coercion and add missing FFI::Pointer#clear.
PullRequest: truffleruby/854
2 parents de7b25a + 834b6bf commit 7dc9597

File tree

6 files changed

+93
-47
lines changed

6 files changed

+93
-47
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,13 @@ Bug fixes:
1111
* Calling `Kernel#raise` with a raised exception will no longer set the cause of the exception to itself (#1682).
1212
* Return a `FFI::Function` correctly for functions returning a callback.
1313
* Convert to intuitive Ruby exceptions when INVOKE fails (#1690).
14+
* Implemented `FFI::Pointer#clear` (#1687).
1415

1516
Compatibility
1617

1718
* `String#-@` now performs string deduplication (#1608).
1819
* `Hash#merge` now preserves the key order from the original hash for merged values (#1650).
20+
* Coerce values given to `FFI::Pointer` methods.
1921

2022
Changes:
2123

spec/ffi/struct_spec.rb

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,19 @@ class StringMember < FFI::Struct
129129
expect(s[:string]).to be_nil
130130
end
131131

132+
it "Struct#clear sets the memory to zero" do
133+
klass = Class.new(FFI::Struct) do
134+
layout :a, :int, :b, :long
135+
end
136+
137+
s = klass.new
138+
s[:a] = 1
139+
s[:b] = 2
140+
s.clear
141+
expect(s[:a]).to eq(0)
142+
expect(s[:b]).to eq(0)
143+
end
144+
132145
it "Struct#layout works with :name, :type pairs" do
133146
class PairLayout < FFI::Struct
134147
layout :a, :int, :b, :long_long
@@ -326,6 +339,17 @@ def test_num_field(type, v)
326339
expect(s.pointer.send("get_#{type.to_s}", 0)).to eq(v)
327340
s.pointer.send("put_#{type.to_s}", 0, 0)
328341
expect(s[:v]).to eq(0)
342+
343+
# Test coercion
344+
obj = double("coerce")
345+
expect(obj).to receive(:to_int).and_return(v)
346+
s[:v] = obj
347+
expect(s.pointer.send("get_#{type.to_s}", 0)).to eq(v)
348+
349+
zero = double("zero")
350+
expect(zero).to receive(:to_int).and_return(0)
351+
s.pointer.send("put_#{type.to_s}", 0, zero)
352+
expect(s[:v]).to eq(0)
329353
end
330354
def self.int_field_test(type, values)
331355
values.each do |v|
@@ -358,6 +382,15 @@ def self.int_field_test(type, values)
358382
value = 1.23456
359383
s[:v] = value
360384
expect((s.pointer.get_float(0) - value).abs).to be < 0.0001
385+
386+
# Test coercion
387+
obj = double("coerce")
388+
expect(obj).to receive(:to_f).and_return(42.0)
389+
s[:v] = obj
390+
expect((s.pointer.get_float(0) - 42.0).abs).to be < 0.0001
391+
392+
s.pointer.put_float(0, 1.0)
393+
expect(s.pointer.get_float(0)).to eq(1.0)
361394
end
362395

363396
it ":double field r/w" do
@@ -368,6 +401,15 @@ def self.int_field_test(type, values)
368401
value = 1.23456
369402
s[:v] = value
370403
expect((s.pointer.get_double(0) - value).abs).to be < 0.0001
404+
405+
# Test coercion
406+
obj = double("coerce")
407+
expect(obj).to receive(:to_f).and_return(42.0)
408+
s[:v] = obj
409+
expect((s.pointer.get_double(0) - 42.0).abs).to be < 0.0001
410+
411+
s.pointer.put_double(0, 1.0)
412+
expect(s.pointer.get_double(0)).to eq(1.0)
371413
end
372414
module EnumFields
373415
extend FFI::Library

src/main/ruby/core/truffle/ffi/pointer.rb

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,11 @@ def initialize_copy(from)
8686
self
8787
end
8888

89+
def clear
90+
raise RuntimeError, 'cannot clear unbounded memory area' unless @total
91+
Truffle.invoke_primitive :pointer_clear, self, @total
92+
end
93+
8994
def inspect
9095
# Don't have this print the data at the location. It can crash everything.
9196
addr = address()

src/main/ruby/core/truffle/ffi/pointer_access.rb

Lines changed: 30 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ def read_char
4545
alias :read_int8 :read_char
4646

4747
def write_char(value)
48-
Truffle.invoke_primitive :pointer_write_char, address, value
48+
Truffle.invoke_primitive :pointer_write_char, address, Truffle::Type.rb_to_int(value)
4949
self
5050
end
5151
alias :write_int8 :write_char
@@ -56,7 +56,7 @@ def get_char(offset)
5656
alias :get_int8 :get_char
5757

5858
def put_char(offset, value)
59-
Truffle.invoke_primitive :pointer_write_char, address + offset, value
59+
Truffle.invoke_primitive :pointer_write_char, address + offset, Truffle::Type.rb_to_int(value)
6060
self
6161
end
6262
alias :put_int8 :put_char
@@ -70,7 +70,7 @@ def read_array_of_char(length)
7070

7171
def write_array_of_char(ary)
7272
ary.each_with_index do |value, i|
73-
Truffle.invoke_primitive :pointer_write_char, address + (i * 1), value
73+
Truffle.invoke_primitive :pointer_write_char, address + (i * 1), Truffle::Type.rb_to_int(value)
7474
end
7575
self
7676
end
@@ -95,7 +95,7 @@ def read_uchar
9595
alias :read_uint8 :read_uchar
9696

9797
def write_uchar(value)
98-
Truffle.invoke_primitive :pointer_write_uchar, address, value
98+
Truffle.invoke_primitive :pointer_write_uchar, address, Truffle::Type.rb_to_int(value)
9999
self
100100
end
101101
alias :write_uint8 :write_uchar
@@ -106,7 +106,7 @@ def get_uchar(offset)
106106
alias :get_uint8 :get_uchar
107107

108108
def put_uchar(offset, value)
109-
Truffle.invoke_primitive :pointer_write_uchar, address + offset, value
109+
Truffle.invoke_primitive :pointer_write_uchar, address + offset, Truffle::Type.rb_to_int(value)
110110
self
111111
end
112112
alias :put_uint8 :put_uchar
@@ -120,7 +120,7 @@ def read_array_of_uchar(length)
120120

121121
def write_array_of_uchar(ary)
122122
ary.each_with_index do |value, i|
123-
Truffle.invoke_primitive :pointer_write_uchar, address + (i * 1), value
123+
Truffle.invoke_primitive :pointer_write_uchar, address + (i * 1), Truffle::Type.rb_to_int(value)
124124
end
125125
self
126126
end
@@ -145,7 +145,7 @@ def read_short
145145
alias :read_int16 :read_short
146146

147147
def write_short(value)
148-
Truffle.invoke_primitive :pointer_write_short, address, value
148+
Truffle.invoke_primitive :pointer_write_short, address, Truffle::Type.rb_to_int(value)
149149
self
150150
end
151151
alias :write_int16 :write_short
@@ -156,7 +156,7 @@ def get_short(offset)
156156
alias :get_int16 :get_short
157157

158158
def put_short(offset, value)
159-
Truffle.invoke_primitive :pointer_write_short, address + offset, value
159+
Truffle.invoke_primitive :pointer_write_short, address + offset, Truffle::Type.rb_to_int(value)
160160
self
161161
end
162162
alias :put_int16 :put_short
@@ -170,7 +170,7 @@ def read_array_of_short(length)
170170

171171
def write_array_of_short(ary)
172172
ary.each_with_index do |value, i|
173-
Truffle.invoke_primitive :pointer_write_short, address + (i * 2), value
173+
Truffle.invoke_primitive :pointer_write_short, address + (i * 2), Truffle::Type.rb_to_int(value)
174174
end
175175
self
176176
end
@@ -195,7 +195,7 @@ def read_ushort
195195
alias :read_uint16 :read_ushort
196196

197197
def write_ushort(value)
198-
Truffle.invoke_primitive :pointer_write_ushort, address, value
198+
Truffle.invoke_primitive :pointer_write_ushort, address, Truffle::Type.rb_to_int(value)
199199
self
200200
end
201201
alias :write_uint16 :write_ushort
@@ -206,7 +206,7 @@ def get_ushort(offset)
206206
alias :get_uint16 :get_ushort
207207

208208
def put_ushort(offset, value)
209-
Truffle.invoke_primitive :pointer_write_ushort, address + offset, value
209+
Truffle.invoke_primitive :pointer_write_ushort, address + offset, Truffle::Type.rb_to_int(value)
210210
self
211211
end
212212
alias :put_uint16 :put_ushort
@@ -220,7 +220,7 @@ def read_array_of_ushort(length)
220220

221221
def write_array_of_ushort(ary)
222222
ary.each_with_index do |value, i|
223-
Truffle.invoke_primitive :pointer_write_ushort, address + (i * 2), value
223+
Truffle.invoke_primitive :pointer_write_ushort, address + (i * 2), Truffle::Type.rb_to_int(value)
224224
end
225225
self
226226
end
@@ -245,7 +245,7 @@ def read_int
245245
alias :read_int32 :read_int
246246

247247
def write_int(value)
248-
Truffle.invoke_primitive :pointer_write_int, address, value
248+
Truffle.invoke_primitive :pointer_write_int, address, Truffle::Type.rb_to_int(value)
249249
self
250250
end
251251
alias :write_int32 :write_int
@@ -256,7 +256,7 @@ def get_int(offset)
256256
alias :get_int32 :get_int
257257

258258
def put_int(offset, value)
259-
Truffle.invoke_primitive :pointer_write_int, address + offset, value
259+
Truffle.invoke_primitive :pointer_write_int, address + offset, Truffle::Type.rb_to_int(value)
260260
self
261261
end
262262
alias :put_int32 :put_int
@@ -270,7 +270,7 @@ def read_array_of_int(length)
270270

271271
def write_array_of_int(ary)
272272
ary.each_with_index do |value, i|
273-
Truffle.invoke_primitive :pointer_write_int, address + (i * 4), value
273+
Truffle.invoke_primitive :pointer_write_int, address + (i * 4), Truffle::Type.rb_to_int(value)
274274
end
275275
self
276276
end
@@ -295,7 +295,7 @@ def read_uint
295295
alias :read_uint32 :read_uint
296296

297297
def write_uint(value)
298-
Truffle.invoke_primitive :pointer_write_uint, address, value
298+
Truffle.invoke_primitive :pointer_write_uint, address, Truffle::Type.rb_to_int(value)
299299
self
300300
end
301301
alias :write_uint32 :write_uint
@@ -306,7 +306,7 @@ def get_uint(offset)
306306
alias :get_uint32 :get_uint
307307

308308
def put_uint(offset, value)
309-
Truffle.invoke_primitive :pointer_write_uint, address + offset, value
309+
Truffle.invoke_primitive :pointer_write_uint, address + offset, Truffle::Type.rb_to_int(value)
310310
self
311311
end
312312
alias :put_uint32 :put_uint
@@ -320,7 +320,7 @@ def read_array_of_uint(length)
320320

321321
def write_array_of_uint(ary)
322322
ary.each_with_index do |value, i|
323-
Truffle.invoke_primitive :pointer_write_uint, address + (i * 4), value
323+
Truffle.invoke_primitive :pointer_write_uint, address + (i * 4), Truffle::Type.rb_to_int(value)
324324
end
325325
self
326326
end
@@ -346,7 +346,7 @@ def read_long
346346
alias :read_long_long :read_long
347347

348348
def write_long(value)
349-
Truffle.invoke_primitive :pointer_write_long, address, value
349+
Truffle.invoke_primitive :pointer_write_long, address, Truffle::Type.rb_to_int(value)
350350
self
351351
end
352352
alias :write_int64 :write_long
@@ -359,7 +359,7 @@ def get_long(offset)
359359
alias :get_long_long :get_long
360360

361361
def put_long(offset, value)
362-
Truffle.invoke_primitive :pointer_write_long, address + offset, value
362+
Truffle.invoke_primitive :pointer_write_long, address + offset, Truffle::Type.rb_to_int(value)
363363
self
364364
end
365365
alias :put_int64 :put_long
@@ -375,7 +375,7 @@ def read_array_of_long(length)
375375

376376
def write_array_of_long(ary)
377377
ary.each_with_index do |value, i|
378-
Truffle.invoke_primitive :pointer_write_long, address + (i * 8), value
378+
Truffle.invoke_primitive :pointer_write_long, address + (i * 8), Truffle::Type.rb_to_int(value)
379379
end
380380
self
381381
end
@@ -404,7 +404,7 @@ def read_ulong
404404
alias :read_ulong_long :read_ulong
405405

406406
def write_ulong(value)
407-
Truffle.invoke_primitive :pointer_write_ulong, address, value
407+
Truffle.invoke_primitive :pointer_write_ulong, address, Truffle::Type.rb_to_int(value)
408408
self
409409
end
410410
alias :write_uint64 :write_ulong
@@ -417,7 +417,7 @@ def get_ulong(offset)
417417
alias :get_ulong_long :get_ulong
418418

419419
def put_ulong(offset, value)
420-
Truffle.invoke_primitive :pointer_write_ulong, address + offset, value
420+
Truffle.invoke_primitive :pointer_write_ulong, address + offset, Truffle::Type.rb_to_int(value)
421421
self
422422
end
423423
alias :put_uint64 :put_ulong
@@ -433,7 +433,7 @@ def read_array_of_ulong(length)
433433

434434
def write_array_of_ulong(ary)
435435
ary.each_with_index do |value, i|
436-
Truffle.invoke_primitive :pointer_write_ulong, address + (i * 8), value
436+
Truffle.invoke_primitive :pointer_write_ulong, address + (i * 8), Truffle::Type.rb_to_int(value)
437437
end
438438
self
439439
end
@@ -461,7 +461,7 @@ def read_float
461461
alias :read_float32 :read_float
462462

463463
def write_float(value)
464-
Truffle.invoke_primitive :pointer_write_float, address, value
464+
Truffle.invoke_primitive :pointer_write_float, address, Truffle::Type.rb_to_f(value)
465465
self
466466
end
467467
alias :write_float32 :write_float
@@ -472,7 +472,7 @@ def get_float(offset)
472472
alias :get_float32 :get_float
473473

474474
def put_float(offset, value)
475-
Truffle.invoke_primitive :pointer_write_float, address + offset, value
475+
Truffle.invoke_primitive :pointer_write_float, address + offset, Truffle::Type.rb_to_f(value)
476476
self
477477
end
478478
alias :put_float32 :put_float
@@ -486,7 +486,7 @@ def read_array_of_float(length)
486486

487487
def write_array_of_float(ary)
488488
ary.each_with_index do |value, i|
489-
Truffle.invoke_primitive :pointer_write_float, address + (i * 4), value
489+
Truffle.invoke_primitive :pointer_write_float, address + (i * 4), Truffle::Type.rb_to_f(value)
490490
end
491491
self
492492
end
@@ -511,7 +511,7 @@ def read_double
511511
alias :read_float64 :read_double
512512

513513
def write_double(value)
514-
Truffle.invoke_primitive :pointer_write_double, address, value
514+
Truffle.invoke_primitive :pointer_write_double, address, Truffle::Type.rb_to_f(value)
515515
self
516516
end
517517
alias :write_float64 :write_double
@@ -522,7 +522,7 @@ def get_double(offset)
522522
alias :get_float64 :get_double
523523

524524
def put_double(offset, value)
525-
Truffle.invoke_primitive :pointer_write_double, address + offset, value
525+
Truffle.invoke_primitive :pointer_write_double, address + offset, Truffle::Type.rb_to_f(value)
526526
self
527527
end
528528
alias :put_float64 :put_double
@@ -536,7 +536,7 @@ def read_array_of_double(length)
536536

537537
def write_array_of_double(ary)
538538
ary.each_with_index do |value, i|
539-
Truffle.invoke_primitive :pointer_write_double, address + (i * 8), value
539+
Truffle.invoke_primitive :pointer_write_double, address + (i * 8), Truffle::Type.rb_to_f(value)
540540
end
541541
self
542542
end

0 commit comments

Comments
 (0)