carray-jit 0.1.2 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +917 -3
  3. data/README.md +14 -12
  4. data/carray-jit.gemspec +1 -3
  5. data/docs/00_Introduction.md +5 -3
  6. data/docs/01_GettingStarted.md +1 -1
  7. data/docs/02_KernelShapes.md +94 -15
  8. data/docs/03_SupportedFeatures.md +665 -32
  9. data/docs/04_Compiling.md +34 -7
  10. data/docs/05_DesignNotes.md +3 -3
  11. data/docs/06_Cheatsheet.md +200 -7
  12. data/docs/07_StepByStep.ja.md +533 -0
  13. data/docs/07_StepByStep.md +534 -0
  14. data/docs/08_LanguageReference.md +427 -0
  15. data/examples/README.md +12 -0
  16. data/examples/applications/alarm.rb +121 -0
  17. data/examples/applications/collatz.rb +105 -0
  18. data/examples/applications/cubic_spline.rb +331 -0
  19. data/examples/applications/dithering.rb +144 -0
  20. data/examples/applications/group_stats.rb +115 -0
  21. data/examples/applications/lookup.rb +126 -0
  22. data/examples/applications/median_filter.rb +153 -0
  23. data/examples/applications/parcel_ascent.rb +220 -0
  24. data/examples/applications/point_in_polygon.rb +111 -0
  25. data/examples/applications/random_walk.rb +98 -0
  26. data/examples/applications/van_der_pol.rb +186 -0
  27. data/examples/applications/wet_bulb.rb +140 -0
  28. data/examples/features/10_complex.rb +14 -4
  29. data/examples/features/15_loops.rb +7 -1
  30. data/lib/carray/jit/access.rb +14 -0
  31. data/lib/carray/jit/analyzer.rb +2218 -140
  32. data/lib/carray/jit/block_reader.rb +37 -6
  33. data/lib/carray/jit/c_function.rb +961 -86
  34. data/lib/carray/jit/c_generator.rb +1970 -191
  35. data/lib/carray/jit/call.rb +68 -0
  36. data/lib/carray/jit/compiler.rb +102 -14
  37. data/lib/carray/jit/expression.rb +271 -33
  38. data/lib/carray/jit/kernel.rb +382 -32
  39. data/lib/carray/jit/node.rb +374 -9
  40. data/lib/carray/jit/sorting_networks.rb +182 -0
  41. data/lib/carray/jit/type_assignment.rb +424 -35
  42. data/lib/carray/jit/version.rb +1 -1
  43. data/lib/carray/jit.rb +547 -77
  44. metadata +23 -8
  45. data/ext/carray_jit_access/carray_jit_access.c +0 -460
  46. data/ext/carray_jit_access/extconf.rb +0 -8
@@ -26,6 +26,18 @@ class CArray
26
26
  pointer && !element.nil?
27
27
  end
28
28
 
29
+ # A C99 complex passed or returned by value. Fiddle cannot carry one,
30
+ # so a call from Ruby goes through a shim; a call from a kernel is C
31
+ # calling C and needs nothing.
32
+ def complex?
33
+ !pointer && CDeclaration::COMPLEX_CODES.value?(fiddle)
34
+ end
35
+
36
+ # `CMPLX` for a double complex, `CMPLXF` for a float one.
37
+ def complex_build
38
+ fiddle == :float_complex ? "CMPLXF" : "CMPLX"
39
+ end
40
+
29
41
  # C's own declarator puts an array's length where a reader can see it,
30
42
  # so `const double coef[3]` and `const double *coef` are different
31
43
  # declarations of the same ABI. The length is kept rather than folded
@@ -63,6 +75,20 @@ class CArray
63
75
  # flag, no library path at compile time, and a compiled kernel that does
64
76
  # not depend on which library the function came from -- so `f.call(a)`
65
77
  # compiles once and serves every function of that signature.
78
+ # The namespace every symbol this compiler writes sits in, and that is
79
+ # not tidiness. A name the C already knows is the dangerous case, and
80
+ # the dangerous case is the one that does *not* fail: `double
81
+ # sin(double)` matches math.h's declaration, so the generated file
82
+ # defines libm's `sin` and the shared object exports it -- where symbols
83
+ # are interposable, that replaces sine for whatever loads it later. A
84
+ # mismatched signature is a compile error and would have been noticed;
85
+ # this one would not.
86
+ #
87
+ # Here rather than beside `function_symbol`, which writes the names,
88
+ # because `CFunction#c_source_as` has to refuse one as well: a caller
89
+ # naming its own symbol may not name one in here.
90
+ PREFIX = "carray_jit_"
91
+
66
92
  class CFunction
67
93
 
68
94
  # @!attribute [r] name
@@ -72,17 +98,32 @@ class CArray
72
98
  # @!attribute [r] c_source
73
99
  # @return [String, nil] the C compiled for a body written here, or
74
100
  # `nil` for one found elsewhere.
75
- attr_reader :name, :prototype, :return_type, :parameters, :pointer,
101
+ attr_reader :name, :symbol, :prototype, :return_type, :parameters, :pointer,
76
102
  :block, :c_source, :origin, :definition, :helpers,
103
+ # The compiled functions this body calls. Whoever pastes
104
+ # the definition has to paste these beside it: it reaches
105
+ # them by symbol, and the symbol is only there if the
106
+ # definition is.
107
+ :dependencies,
77
108
  # What `raise` in the body said, by the code it reports.
78
109
  # The kernel that pastes it answers for these too.
79
110
  :raise_messages
80
111
 
81
112
  def initialize (name, prototype, return_type, parameters, pointer,
82
- block: nil, c_source: nil, origin: nil, error: nil,
113
+ symbol: nil,
114
+ block: nil, c_source: nil, origin: nil,
83
115
  definition: nil, helpers: nil, takes_error: false,
84
- raise_messages: {})
116
+ raise_messages: {}, dependencies: [], shim: nil,
117
+ error_state: nil)
118
+ # The name the declaration gave, which is what a reader wrote and
119
+ # what an error should say. It is nil where the declaration gave
120
+ # none -- `double (*)(double)` names no function.
85
121
  @name = name && name.to_sym
122
+ # The name in the object, which is what a call reaches and what two
123
+ # functions have to differ by. For one bound from a library they
124
+ # are the same; for one compiled here the symbol carries a digest of
125
+ # the body, so that two bodies declared alike stay apart.
126
+ @symbol = (symbol || name)&.to_sym
86
127
  @prototype = prototype
87
128
  @return_type = return_type
88
129
  @parameters = parameters
@@ -95,15 +136,21 @@ class CArray
95
136
  # what it wants from a preamble -- what a kernel needs to paste it.
96
137
  @definition = definition
97
138
  @helpers = helpers
139
+ @dependencies = dependencies
98
140
  # True when that definition ends in an `int32_t *`: the body can report
99
141
  # a failure, and pasted it reports into the caller's slot rather than
100
142
  # into the flag in its own object.
101
143
  @takes_error = takes_error
102
144
  @raise_messages = raise_messages
103
145
  @origin = origin
104
- # Where the compiled body says a division had no divisor, or a
105
- # subscript ran off its array. Nil when the body can do neither.
106
- @error = error
146
+ # What the object answers when asked where this thread's flag, hook
147
+ # and stand-in stand. Nil when the body can neither divide by zero
148
+ # nor raise, and so has none of them.
149
+ @error_state = error_state
150
+ # The address of the entry point a call from Ruby takes where the
151
+ # signature carries a complex by value; nil where it does not, which
152
+ # is every other signature and every borrowed function.
153
+ @shim = shim
107
154
  @function = nil
108
155
  end
109
156
 
@@ -130,6 +177,16 @@ class CArray
130
177
  pasted? && @takes_error
131
178
  end
132
179
 
180
+ # The declaration under the name the block reached it by. What a
181
+ # message about a call should say: the caller wrote `f`, and the symbol
182
+ # a body compiled here carries -- `carray_jit_two_<digest>` -- along
183
+ # with the file it was written in are answers to a question nobody
184
+ # asked there. Those stay in `to_s`, which names the object rather
185
+ # than the call.
186
+ def declaration_as (name)
187
+ "#{@return_type.text} #{name}(#{@parameters.map(&:text).join(', ')})"
188
+ end
189
+
133
190
  # The signature, without the address.
134
191
  def signature
135
192
  [@return_type.text, @parameters.map(&:text)]
@@ -147,7 +204,54 @@ class CArray
147
204
  # the same way. Splitting the cache costs a compile per body; sharing
148
205
  # it would hand back the wrong answer, and would do it quietly.
149
206
  def kernel_key
150
- compiled? ? [signature, @name] : signature
207
+ compiled? ? [signature, @symbol] : signature
208
+ end
209
+
210
+ # What to call this in a message: the name its declaration gave, and
211
+ # the symbol where it gave none.
212
+ def label
213
+ @name || @symbol
214
+ end
215
+
216
+ # The C this was compiled from, under a symbol of the caller's
217
+ # choosing.
218
+ #
219
+ # For a caller writing the C into a file of its own rather than letting
220
+ # this compile it: the symbol here carries a digest of the body, which
221
+ # is right for an object in a cache and wrong for one in a repository,
222
+ # where the same build has to give the same name every time.
223
+ #
224
+ # It is a rename rather than a second run of the generator, and that is
225
+ # exact rather than close enough: the symbol is the only thing in the
226
+ # generated file that the choice of symbol decides. Two compilations
227
+ # of one block under two declared names differ in nothing else once
228
+ # both symbols are levelled, which the suite checks.
229
+ #
230
+ # The caller owns the name it picks, and with it the one hazard the
231
+ # generator's own prefix exists to close: a body declared `sin`
232
+ # emitted as `sin` defines libm's, and the object exports it. What is
233
+ # refused here is a name C cannot spell, and the generator's own
234
+ # namespace -- an object built under `carray_jit_...` would answer to
235
+ # a symbol a cached kernel is entitled to.
236
+ def c_source_as (symbol)
237
+ symbol = symbol.to_s
238
+ unless @c_source
239
+ raise Unsupported,
240
+ "`#{label}` was bound from a library rather than compiled " \
241
+ "here, so there is no C of its own to write out"
242
+ end
243
+ unless symbol =~ /\A[A-Za-z_][A-Za-z0-9_]*\z/
244
+ raise Unsupported,
245
+ "`#{symbol}` is not a C identifier, so nothing could be " \
246
+ "defined under it"
247
+ end
248
+ if symbol.start_with?(PREFIX)
249
+ raise Unsupported,
250
+ "`#{symbol}` is in this compiler's own namespace " \
251
+ "(`#{PREFIX}`), where a cached kernel is entitled to the " \
252
+ "name; pick one of your own"
253
+ end
254
+ @c_source.gsub(@symbol.to_s, symbol)
151
255
  end
152
256
 
153
257
  # @return [Integer] how many arguments the function takes.
@@ -198,9 +302,16 @@ class CArray
198
302
  "wrong number of arguments (given #{arguments.size}, " \
199
303
  "expected #{@parameters.size})"
200
304
  end
305
+ return call_through_shim(arguments) if @shim
306
+ if carries_a_complex?
307
+ raise Unsupported,
308
+ "`#{self}` carries a C99 complex by value, which Fiddle has " \
309
+ "no type for, so it cannot be called from Ruby; a kernel " \
310
+ "calls it as C calls it"
311
+ end
201
312
  @function ||= Fiddle::Function.new(@pointer, argument_types,
202
313
  @return_type.fiddle,
203
- name: @name.to_s)
314
+ name: label.to_s)
204
315
  arrays = []
205
316
  prepared = arguments.zip(@parameters).map { |argument, type|
206
317
  next argument unless type.indexable? && argument.is_a?(CArray)
@@ -208,18 +319,31 @@ class CArray
208
319
  arrays << [argument, buffer, type]
209
320
  buffer
210
321
  }
211
- clear_error
212
- Access.open(arrays.map { |_, buffer, _| buffer },
213
- arrays.map { |_, _, type| !type.const },
214
- arrays.map { nil }, arrays.map { nil }) do |bases|
215
- slot = -1
216
- prepared = prepared.map { |value|
217
- next value unless arrays.any? { |_, buffer, _| buffer.equal?(value) }
218
- Fiddle::Pointer.new(bases[slot += 1][:pointer])
219
- }
220
- @result = @function.call(*prepared)
322
+ # Borrowed rather than cleared, and borrowed here rather than on the
323
+ # way in: a call made inside a window -- someone else is holding this
324
+ # function's address and watching the same flag -- must answer for
325
+ # itself without disarming them. The checks above never reach the C
326
+ # and so never touch the flag at all.
327
+ outer = error_code
328
+ write_error(0)
329
+ hook = disarm_hook
330
+ begin
331
+ Access.open(arrays.map { |_, buffer, _| buffer },
332
+ arrays.map { |_, _, type| !type.const },
333
+ arrays.map { nil }, arrays.map { nil }) do |bases|
334
+ slot = -1
335
+ prepared = prepared.map { |value|
336
+ next value unless arrays.any? { |_, buffer, _| buffer.equal?(value) }
337
+ Fiddle::Pointer.new(bases[slot += 1][:pointer])
338
+ }
339
+ @result = @function.call(*prepared)
340
+ end
341
+ code = error_code
342
+ ensure
343
+ write_error(outer)
344
+ rearm_hook(hook)
221
345
  end
222
- report_error
346
+ raise_for(code)
223
347
  # A view was copied to be made contiguous; a writable one is copied
224
348
  # back, because the C wrote into the copy.
225
349
  arrays.each do |array, buffer, type|
@@ -230,6 +354,79 @@ class CArray
230
354
 
231
355
  alias [] call
232
356
 
357
+ # Whether a call from Ruby has to go round through the shim.
358
+ def carries_a_complex?
359
+ @return_type.complex? || @parameters.any?(&:complex?)
360
+ end
361
+
362
+ # Fiddle carries no complex, so the shim takes each complex argument as
363
+ # a pair of doubles and writes a complex result back the same way.
364
+ # Everything else keeps the type the declaration gave it and goes
365
+ # through Fiddle as before -- including a pointer parameter, which is
366
+ # still a CArray on this side.
367
+ #
368
+ # It is the same compiled body either way: the shim calls the function,
369
+ # it does not reimplement it.
370
+ def call_through_shim (arguments)
371
+ returns_complex = @return_type.complex?
372
+ types = @parameters.map { |type|
373
+ type.complex? ? Fiddle::TYPE_VOIDP : type.fiddle
374
+ }
375
+ types << Fiddle::TYPE_VOIDP if returns_complex
376
+ @shim_function ||=
377
+ Fiddle::Function.new(@shim, types,
378
+ returns_complex ? Fiddle::TYPE_VOID
379
+ : @return_type.fiddle)
380
+ result = returns_complex ? String.new("\0" * 16) : nil
381
+ arrays = []
382
+ prepared = arguments.zip(@parameters).map { |argument, type|
383
+ next pack_complex(argument, type) if type.complex?
384
+ next argument unless type.indexable? && argument.is_a?(CArray)
385
+ buffer = check_array(argument, type)
386
+ arrays << [argument, buffer, type]
387
+ buffer
388
+ }
389
+ outer = error_code
390
+ write_error(0)
391
+ hook = disarm_hook
392
+ begin
393
+ Access.open(arrays.map { |_, buffer, _| buffer },
394
+ arrays.map { |_, _, type| !type.const },
395
+ arrays.map { nil }, arrays.map { nil }) do |bases|
396
+ slot = -1
397
+ passed = prepared.map { |value|
398
+ next value unless arrays.any? { |_, buffer, _| buffer.equal?(value) }
399
+ Fiddle::Pointer.new(bases[slot += 1][:pointer])
400
+ }
401
+ passed << result if returns_complex
402
+ @result = @shim_function.call(*passed)
403
+ end
404
+ code = error_code
405
+ ensure
406
+ write_error(outer)
407
+ rearm_hook(hook)
408
+ end
409
+ raise_for(code)
410
+ arrays.each do |array, buffer, type|
411
+ array[] = buffer unless type.const || array.equal?(buffer)
412
+ end
413
+ @result = Complex(*result.unpack("dd")) if returns_complex
414
+ @result
415
+ end
416
+
417
+ # A Ruby number of any kind arrives as the two doubles the shim reads.
418
+ # `Complex()` is what Ruby itself converts with, so an Integer and a
419
+ # Float are taken where a Complex is asked for, as they are in Ruby.
420
+ def pack_complex (value, type)
421
+ number = begin
422
+ Complex(value)
423
+ rescue TypeError, ArgumentError
424
+ raise Unsupported,
425
+ "`#{type.text}` takes a number, got #{value.class}"
426
+ end
427
+ String.new([number.real.to_f, number.imaginary.to_f].pack("dd"))
428
+ end
429
+
233
430
  # @return [String] the function's name.
234
431
  def to_s
235
432
  text = "#{@return_type.text} #{@name}" \
@@ -242,40 +439,284 @@ class CArray
242
439
  "#<CArray::JIT::CFunction #{self}>"
243
440
  end
244
441
 
245
- private
442
+ # The window a caller opens when it hands the address out.
443
+ #
444
+ # `#call` is one call, and answers for it before it returns. A library
445
+ # given `#pointer` calls whenever it likes, as often as it likes, and
446
+ # what wants an answer is the whole of that -- so the flag is put down
447
+ # once, the address is lent for as long as the block runs, and what
448
+ # happened is asked for once at the end. It is the arrangement a kernel
449
+ # already keeps with its own slot, which is cleared before a sweep and
450
+ # read after it, never per cell.
451
+ #
452
+ # f.watching do
453
+ # Integration.qags(f.pointer, 0.0, 1.0)
454
+ # end
455
+ #
456
+ # A failure inside the block outranks whatever the library made of it.
457
+ # A body that fails returns a stand-in, so the library is the first to
458
+ # complain -- that the endpoints do not straddle, that the iteration did
459
+ # not converge -- and those complaints are the failure's consequences,
460
+ # not what happened. So the flag is read before that exception is let
461
+ # through, and only where nothing stands does the library's own story
462
+ # get to be the story.
463
+ #
464
+ # Windows nest, and a call made inside one leaves it armed: both borrow
465
+ # the flag and put it back as they found it, so an inner window answers
466
+ # for its own block and no other.
467
+ #
468
+ # `stand_in:` is the number a call answers C with once the flag stands,
469
+ # for a library that reads the return value as a status rather than as
470
+ # a value -- GSL's callbacks return `int`, and 0 is `GSL_SUCCESS`
471
+ # there, so a failed body reporting 0 tells GSL the step went well. It
472
+ # is cast to whatever the body returns and is 0 until a window says
473
+ # otherwise, which is what a failed call has always answered. Set for
474
+ # the length of the window, and put back afterwards.
475
+ def watching (stand_in: nil)
476
+ opened = open_window(nil, JIT.send(:window_stand_in, stand_in))
477
+ code = 0
478
+ begin
479
+ result = yield
480
+ rescue StandardError
481
+ # The library is complaining about what a stand-in did. The body's
482
+ # own failure is the cause, so it is the one that comes out.
483
+ code = close_window(opened)
484
+ opened = nil
485
+ raise_for(code)
486
+ raise
487
+ ensure
488
+ code = close_window(opened) if opened
489
+ end
490
+ raise_for(code)
491
+ result
492
+ end
246
493
 
247
- # What a pointer parameter will accept, and what has to be true of it.
248
- # The length is checked only where the declaration carried one: C's own
249
- # rule is that an unsized pointer is the caller's responsibility, and
250
- # writing `coef[3]` is how the caller asks to be checked.
494
+ # Put the flag down, before lending the address to something that will
495
+ # call it more than once. `#watching` is this and #report_error with
496
+ # the lending in between, and is what to reach for where the window is a
497
+ # block; these two are here for a window that is not -- one opened in
498
+ # one method and closed in another, or one whose block belongs to
499
+ # somebody else.
251
500
  def clear_error
252
- @error[0, 4] = [0].pack("l") if @error
501
+ write_error(0)
253
502
  end
254
503
 
255
504
  # What the kernel raises for the same code, since it is the same thing
256
505
  # that happened: `6 % 0` is a ZeroDivisionError wherever it is written,
257
506
  # and the compiled body cannot raise it itself. A caller reaching the
258
- # address from C sees the number the helper returned and the flag
507
+ # address from C sees the stand-in the helper returned and the flag
259
508
  # standing, which is C's own arrangement for a function that has to
260
509
  # return something whatever happened.
510
+ #
511
+ # Quiet where nothing stands, so that a caller may ask having no idea
512
+ # whether anything failed -- which is the position a caller is in after
513
+ # handing the address to a library. Asking does not put the flag down:
514
+ # it reads, and the window that put it down is what picks it up.
261
515
  def report_error
262
- return unless @error
263
- code = @error[0, 4].unpack1("l")
516
+ raise_for(error_code)
517
+ end
518
+
519
+ # A C function to call when the body fails, so that whoever holds the
520
+ # address can be told to stop rather than go on being handed stand-ins:
521
+ #
522
+ # f.on_error(nlopt["nlopt_force_stop"], opt)
523
+ # f.watching { nlopt_optimize.call(opt, x, minf) }
524
+ #
525
+ # `hook` is the address of a `void (*)(void *)` -- a Fiddle::Pointer,
526
+ # an Integer, or anything answering #to_i -- and `data` is the one
527
+ # argument it is called with. It is called once, from the call whose
528
+ # body put the flag up, and not again until the flag has been put down
529
+ # and has gone up again; nothing about it reaches Ruby, so it may be
530
+ # called from a thread that holds no GVL. `nil` takes it away.
531
+ #
532
+ # `#call` does not call it: that is one call made from Ruby, and it
533
+ # answers for itself by raising, as it does inside a window. A body
534
+ # that cannot fail has no flag to go up, so for it this is accepted
535
+ # and never called.
536
+ #
537
+ # Like the flag, it belongs to the thread that set it: a body lent from
538
+ # two threads at once has a hook and a flag in each of them, and this
539
+ # sets the one belonging to the thread that calls it. So it is set on
540
+ # the thread that will lend the address, which is where `#watching` is
541
+ # written anyway.
542
+ #
543
+ # Returns self.
544
+ def on_error (hook, data = nil)
545
+ state = error_state
546
+ return self unless state
547
+ address = hook.nil? ? 0 : hook.to_i
548
+ state.data[0, Fiddle::SIZEOF_VOIDP] =
549
+ [data.nil? ? 0 : data.to_i].pack("J")
550
+ state.hook[0, Fiddle::SIZEOF_VOIDP] = [address].pack("J")
551
+ state.held = hook.nil? ? nil : [hook, data]
552
+ self
553
+ end
554
+
555
+ private
556
+
557
+ # One thread's copy of the four the compiled object carries -- the
558
+ # flag, the hook's address, the pointer it is handed, and what a failed
559
+ # call answers C with -- with the Ruby objects `#on_error` was given
560
+ # held beside them, so that nothing the C may still call is collected.
561
+ ErrorState = Struct.new(:flag, :hook, :data, :standin, :held)
562
+ private_constant :ErrorState
563
+
564
+ # Where those copies are kept, per thread. A thread variable rather
565
+ # than a fiber-local one, because what is being tracked is the C's own
566
+ # storage: every fiber running on a thread reaches that thread's copy.
567
+ THREAD_STATES = :carray_jit_error_states
568
+ private_constant :THREAD_STATES
569
+
570
+ # This thread's, resolved by asking the object where they stand and
571
+ # kept for as long as the thread lives -- a thread's copies do not
572
+ # move. Nil where the body cannot fail at all: one that neither
573
+ # divides nor raises is compiled without a flag, and has no failure to
574
+ # report rather than an unread one.
575
+ def error_state
576
+ return nil unless @error_state
577
+ thread = Thread.current
578
+ kept = thread.thread_variable_get(THREAD_STATES)
579
+ unless kept
580
+ kept = {}
581
+ thread.thread_variable_set(THREAD_STATES, kept)
582
+ end
583
+ # By symbol, which carries a digest of the body: two functions with
584
+ # the same symbol are one compiled object and one set of copies.
585
+ kept[@symbol] ||= resolve_error_state
586
+ end
587
+
588
+ def resolve_error_state
589
+ out = String.new("\0" * (4 * Fiddle::SIZEOF_VOIDP))
590
+ @error_state.call(out)
591
+ flag, hook, data, standin = out.unpack("J4")
592
+ ErrorState.new(Fiddle::Pointer.new(flag, 4),
593
+ Fiddle::Pointer.new(hook, Fiddle::SIZEOF_VOIDP),
594
+ Fiddle::Pointer.new(data, Fiddle::SIZEOF_VOIDP),
595
+ Fiddle::Pointer.new(standin, 8),
596
+ nil)
597
+ end
598
+
599
+ # 0 where the body cannot fail at all.
600
+ def error_code
601
+ state = error_state
602
+ state ? state.flag[0, 4].unpack1("l") : 0
603
+ end
604
+
605
+ def write_error (code)
606
+ state = error_state
607
+ state.flag[0, 4] = [code].pack("l") if state
608
+ end
609
+
610
+ # The hook's address, cleared for the length of one call from Ruby,
611
+ # and put back afterwards.
612
+ def disarm_hook
613
+ state = error_state
614
+ return nil unless state
615
+ held = state.hook[0, Fiddle::SIZEOF_VOIDP]
616
+ state.hook[0, Fiddle::SIZEOF_VOIDP] = "\0" * Fiddle::SIZEOF_VOIDP
617
+ held
618
+ end
619
+
620
+ def rearm_hook (held)
621
+ state = error_state
622
+ state.hook[0, Fiddle::SIZEOF_VOIDP] = held if state && held
623
+ end
624
+
625
+ # What a window does at its two ends. `#watching` is these with a
626
+ # block between them, and `CArray::JIT.watching` is these over several
627
+ # functions at once -- which is why they are named rather than written
628
+ # inline in the one method that had them.
629
+ #
630
+ # `hook` is the `[address, data]` a window wants a hook of its own for,
631
+ # and `standin` what it wants a failed call to answer C with; nil for
632
+ # either leaves whatever is set alone.
633
+ def open_window (hook = nil, standin = nil)
634
+ outer = error_code
635
+ write_error(0)
636
+ [outer, hook && hold_hook(*hook), standin && hold_standin(standin)]
637
+ end
638
+
639
+ # What this window's calls reported, with the flag, the hook and the
640
+ # stand-in put back as they were found.
641
+ def close_window (opened)
642
+ outer, held, standin = opened
643
+ code = error_code
644
+ write_error(outer)
645
+ restore_hook(held)
646
+ restore_standin(standin)
647
+ code
648
+ end
649
+
650
+ # This window's hook set and the one it displaced handed back, so that
651
+ # the window can put it there again. `#on_error` writes these two
652
+ # pointers; what it has no way to do is read them, and a window that
653
+ # brings a hook of its own has to -- otherwise it leaves with the
654
+ # owner's gone and nothing said about it.
655
+ def hold_hook (address, data)
656
+ state = error_state
657
+ return nil unless state
658
+ held = [state.hook[0, Fiddle::SIZEOF_VOIDP],
659
+ state.data[0, Fiddle::SIZEOF_VOIDP], state.held]
660
+ on_error(address, data)
661
+ held
662
+ end
663
+
664
+ def restore_hook (held)
665
+ state = error_state
666
+ return unless state && held
667
+ state.hook[0, Fiddle::SIZEOF_VOIDP] = held[0]
668
+ state.data[0, Fiddle::SIZEOF_VOIDP] = held[1]
669
+ state.held = held[2]
670
+ end
671
+
672
+ # This window's stand-in written, and the one it displaced handed back.
673
+ # Held as the eight bytes rather than as a number, so that whatever was
674
+ # there goes back exactly as it stood.
675
+ def hold_standin (value)
676
+ state = error_state
677
+ return nil unless state
678
+ held = state.standin[0, 8]
679
+ state.standin[0, 8] = [value].pack("q")
680
+ held
681
+ end
682
+
683
+ def restore_standin (held)
684
+ state = error_state
685
+ state.standin[0, 8] = held if state && held
686
+ end
687
+
688
+ def raise_for (code)
689
+ if (failure = CGenerator::FIXED_FAILURES[code])
690
+ raise failure[0], failure[1]
691
+ end
264
692
  case code
265
693
  when 0 then nil
266
694
  when 1 then raise ZeroDivisionError, "divided by 0"
695
+ when 2 then raise IndexError, "index out of range"
696
+ when 3 then raise ArgumentError,
697
+ "min argument must be less than or equal to " \
698
+ "max argument"
699
+ when 4 then raise ArgumentError,
700
+ "comparison with a NaN failed, so `clamp` has " \
701
+ "no answer"
702
+ when 5 then raise Math::DomainError,
703
+ "Numerical argument is out of domain - gamma"
267
704
  else
268
705
  # `raise "..."` in the body. The message did not come back through
269
706
  # the C -- it was registered when this was compiled -- so it is
270
707
  # looked up here, and a kernel that pasted the same body looks the
271
708
  # same message up under the same code.
272
709
  message = @raise_messages[code]
273
- raise Error, "#{@name} reported #{code}, which is no failure it " \
710
+ raise Error, "#{label} reported #{code}, which is no failure it " \
274
711
  "was compiled to report" unless message
275
712
  raise RuntimeError, message
276
713
  end
277
714
  end
278
715
 
716
+ # What a pointer parameter will accept, and what has to be true of it.
717
+ # The length is checked only where the declaration carried one: C's own
718
+ # rule is that an unsized pointer is the caller's responsibility, and
719
+ # writing `coef[3]` is how the caller asks to be checked.
279
720
  def check_array (array, type)
280
721
  wanted = CDeclaration::DATA_TYPES.fetch(type.element.fiddle)
281
722
  unless array.data_type_name == wanted.to_s
@@ -317,7 +758,7 @@ class CArray
317
758
  def computation_of (type, role)
318
759
  return type.computation unless type.opaque?
319
760
  raise Unsupported,
320
- "`#{@name}` #{role} `#{type.text}`, which is a slot in the " \
761
+ "`#{label}` #{role} `#{type.text}`, which is a slot in the " \
321
762
  "signature rather than a value a kernel can compute with"
322
763
  end
323
764
 
@@ -342,24 +783,51 @@ class CArray
342
783
  # aliases and its floating types are `float` and `double`.
343
784
  KEYWORDS = %w[
344
785
  const unsigned signed void char short int long float double
786
+ _Complex complex
345
787
  int8_t int16_t int32_t int64_t
346
788
  uint8_t uint16_t uint32_t uint64_t
347
789
  size_t ssize_t ptrdiff_t intptr_t uintptr_t
348
790
  ].freeze
349
791
 
792
+ # Fiddle has no code for a C99 complex -- its parser does not know the
793
+ # word and the ABI it answers for has nowhere to put one -- so these
794
+ # stand where a Fiddle code stands elsewhere. Symbols rather than
795
+ # numbers, so that one reaching Fiddle by mistake is a TypeError there
796
+ # and not a silently wrong width.
797
+ COMPLEX_CODES = { "double" => :double_complex,
798
+ "float" => :float_complex }.freeze
799
+
800
+ # `double complex` is `<complex.h>`'s spelling of `double _Complex`,
801
+ # and both are written; which words a declaration used says nothing
802
+ # about what it declared.
803
+ COMPLEX_WORDS = %w[_Complex complex].freeze
804
+
350
805
  # Fiddle answers `long double` with the code for `long`, silently, so it
351
806
  # is refused by name rather than trusted.
352
807
  REFUSED = {
353
808
  "long double" => "`long double` is not a type this reads: Fiddle " \
354
809
  "reports it as `long`, which would be the wrong " \
355
810
  "width without saying so",
811
+ "long double _Complex" =>
812
+ "`long double _Complex` is not a type this reads: there is no " \
813
+ "long double here to make one of",
356
814
  }.freeze
357
815
 
816
+ # The words C builds its integer types from. They may come in any
817
+ # order and `int` may be left out -- `unsigned`, `long unsigned int`
818
+ # and `int unsigned` are all C -- while Fiddle reads only some of those
819
+ # orders, fails on a bare `unsigned`, and reads `int unsigned` as a
820
+ # signed int without saying so. So a spelling made only of these is
821
+ # counted here and handed to Fiddle in the one order it reads.
822
+ INTEGER_WORDS = %w[signed unsigned char short int long].freeze
823
+
358
824
  # The CArray data type a pointer parameter takes, by the code Fiddle
359
825
  # gave its element. This is the table CGenerator::STORAGE_C_TYPES
360
826
  # already holds, read the other way round -- nothing new is decided
361
827
  # here about how a C type and a CArray type correspond.
362
828
  DATA_TYPES = {
829
+ :double_complex => :cmplx128,
830
+ :float_complex => :cmplx64,
363
831
  Fiddle::TYPE_DOUBLE => :float64,
364
832
  Fiddle::TYPE_FLOAT => :float32,
365
833
  Fiddle::TYPE_CHAR => :int8,
@@ -380,6 +848,11 @@ class CArray
380
848
  # Absent means the type may be written down but holds no value a body
381
849
  # can compute with -- `void`, and a pointer to it.
382
850
  COMPUTATION = {
851
+ # A `float _Complex` computes in double complex, as a `float`
852
+ # computes in double: the declaration says what the signature is,
853
+ # and the body works in what Ruby would have worked in.
854
+ :double_complex => :complex,
855
+ :float_complex => :complex,
383
856
  Fiddle::TYPE_DOUBLE => :double,
384
857
  Fiddle::TYPE_FLOAT => :double,
385
858
  Fiddle::TYPE_CHAR => :int64,
@@ -440,9 +913,40 @@ class CArray
440
913
  text.split(",").map(&:strip)
441
914
  end
442
915
 
916
+ # The names a declaration gave its parameters, in order, with `nil`
917
+ # where it gave none.
918
+ #
919
+ # `read_type` drops them, and for every other spelling that is right:
920
+ # nothing reads a parameter's name for a function bound from a library,
921
+ # and one compiled from a block takes its parameters from the block.
922
+ # `jit_call` is where they stop being decorative -- there the names are
923
+ # what binds the call to the locals around it -- so they are read here
924
+ # rather than kept on a type, where a name does not belong.
925
+ def parameter_names (prototype)
926
+ text = prototype.strip.sub(/;\z/, "")
927
+ _, _, parameter_text = split(text, prototype)
928
+ parts = split_parameters(parameter_text)
929
+ return [] if parts.size == 1 && parts.first.strip == "void"
930
+ parts.map { |part| parameter_name(part) }
931
+ end
932
+
933
+ # The same grammar `read_type` reads, answering the name it throws
934
+ # away. Written out beside it rather than folded into it: `read_type`
935
+ # is asked about a return type too, and a return type has no name.
936
+ def parameter_name (text)
937
+ stripped = text.strip.sub(/\[\s*\d*\s*\]\s*\z/, "")
938
+ words = stripped.split(/\s+|(?=\*)|(?<=\*)/).reject(&:empty?)
939
+ words.shift while words.first && KEYWORDS.include?(words.first)
940
+ words.shift while words.first == "*"
941
+ last = words.first
942
+ # A Symbol, which is what a block's parameters are and what the rest
943
+ # of the compiler compares names as.
944
+ last.to_sym if last&.match?(/\A[A-Za-z_]\w*\z/)
945
+ end
946
+
443
947
  # `[const] <keywords> [*] [name] [[]]` is the whole grammar there is.
444
- # A parameter's own name is dropped: nothing reads it for a bound
445
- # function, and a compiled one uses the block's parameter names.
948
+ # A parameter's own name is dropped here; `parameter_names` above reads
949
+ # it for the one spelling that needs it.
446
950
  def read_type (text, prototype)
447
951
  array = nil
448
952
  stripped = text.strip.sub(/\[\s*(\d*)\s*\]\s*\z/) {
@@ -473,6 +977,7 @@ class CArray
473
977
  if (reason = REFUSED[spelling])
474
978
  raise Unsupported, "#{reason} (in `#{prototype}`)"
475
979
  end
980
+ spelling = integer_spelling(spelling, text, prototype)
476
981
  # A parameter written as an array is a pointer at the ABI, whatever
477
982
  # its declarator says.
478
983
  pointer ||= !array.nil?
@@ -484,12 +989,17 @@ class CArray
484
989
  else
485
990
  ""
486
991
  end
487
- code = fiddle_code(pointer ? "void *" : spelling, text, prototype)
992
+ code = if !pointer && (complex = complex_code(spelling))
993
+ complex
994
+ else
995
+ fiddle_code(pointer ? "void *" : spelling, text, prototype)
996
+ end
488
997
  # What it points at, for a pointer that points at numbers. `void *`
489
998
  # has no element, which is what keeps it a slot.
490
999
  element = nil
491
1000
  if pointer && spelling != "void"
492
- element_code = fiddle_code(spelling, text, prototype)
1001
+ element_code = complex_code(spelling) ||
1002
+ fiddle_code(spelling, text, prototype)
493
1003
  if COMPUTATION[element_code]
494
1004
  element = CType.new(spelling, element_code,
495
1005
  COMPUTATION[element_code], false, nil, nil,
@@ -500,6 +1010,42 @@ class CArray
500
1010
  array, element, keywords.include?("const"))
501
1011
  end
502
1012
 
1013
+ # `long unsigned int` as `unsigned long`, `unsigned` as `unsigned int`:
1014
+ # the order Fiddle reads, for a spelling made only of INTEGER_WORDS.
1015
+ # Anything else is handed back untouched. A combination C does not
1016
+ # have -- `signed unsigned`, `short long`, three `long`s -- is refused
1017
+ # here rather than left to a parser that has been seen to guess.
1018
+ def integer_spelling (spelling, text, prototype)
1019
+ words = spelling.split(/\s+/)
1020
+ return spelling unless words.all? { |word| INTEGER_WORDS.include?(word) }
1021
+ count = words.tally
1022
+ longs = count.fetch("long", 0)
1023
+ base = count.keys & %w[char short]
1024
+ if count.values_at("signed", "unsigned", "char", "short", "int")
1025
+ .any? { |n| n.to_i > 1 } ||
1026
+ (count.key?("signed") && count.key?("unsigned")) ||
1027
+ base.size > 1 || (base.any? && longs > 0) || longs > 2 ||
1028
+ (count.key?("char") && count.key?("int"))
1029
+ raise Unsupported,
1030
+ "`#{text.strip}` in `#{prototype}` is not a C integer type"
1031
+ end
1032
+ sign = count.key?("unsigned") ? "unsigned " : ""
1033
+ width = base.first || { 0 => "int", 1 => "long", 2 => "long long" }.fetch(longs)
1034
+ # `signed char` is a type of its own in C, apart from plain `char`,
1035
+ # and Fiddle reads both as the one byte they are.
1036
+ sign = "signed " if width == "char" && count.key?("signed")
1037
+ "#{sign}#{width}"
1038
+ end
1039
+
1040
+ # The code for a complex spelling, or nil for anything else. `float
1041
+ # _Complex`, `complex float`, `float complex` -- the word may sit on
1042
+ # either side, as C allows.
1043
+ def complex_code (spelling)
1044
+ words = spelling.split(/\s+/)
1045
+ return nil unless (words & COMPLEX_WORDS).any?
1046
+ COMPLEX_CODES[(words - COMPLEX_WORDS).join(" ")]
1047
+ end
1048
+
503
1049
  def fiddle_code (spelling, text, prototype)
504
1050
  PARSER.parse_ctype(spelling)
505
1051
  rescue StandardError
@@ -560,7 +1106,77 @@ class CArray
560
1106
  # What comes back is the same object `jit_extern` hands out, so a kernel
561
1107
  # calls either without knowing which it has; `compiled?` is where the
562
1108
  # difference is still visible, along with the block, which it keeps.
563
- def function (prototype, &block)
1109
+ # `CArray.jit_call`: compile the block, read the locals the declaration
1110
+ # named, call.
1111
+ #
1112
+ # Kept per call site rather than per body. A block literal is a fresh
1113
+ # Proc every time the line runs, but its instruction sequence is the
1114
+ # site's and does not change -- which is the key `read_block` already
1115
+ # caches a block's source under.
1116
+ def call_here (prototype, block)
1117
+ site = RubyVM::InstructionSequence.of(block) if
1118
+ defined?(RubyVM::InstructionSequence)
1119
+ entry = site && call_sites[site]
1120
+ unless entry
1121
+ names = CDeclaration.parameter_names(prototype)
1122
+ if (missing = names.index(nil))
1123
+ raise Unsupported,
1124
+ "`#{prototype}` gives parameter #{missing + 1} no name, " \
1125
+ "and a name is what `jit_call` binds by -- it is the local " \
1126
+ "the call reads"
1127
+ end
1128
+ # A compiled function may already exist somewhere other than this
1129
+ # compiler's cache: built ahead of the program and shipped in a
1130
+ # shared object, which is what carray-jit-aot does with these same call
1131
+ # sites. A provider is asked before anything is compiled and
1132
+ # answers nil for a site that is not its own -- the same position
1133
+ # `jit_extern` puts a function from a library in, said about a call
1134
+ # rather than about a name.
1135
+ compiled = call_provider &&
1136
+ call_provider.call(prototype, block, names)
1137
+ unless compiled
1138
+ # Nothing answered, so this one is compiled -- and the compiler
1139
+ # is loaded here rather than beside the method, so a program
1140
+ # whose sites were all answered never loads it. `require` is
1141
+ # idempotent and this runs once per site.
1142
+ require "carray/jit"
1143
+ compiled = function(prototype, declared_parameters: names, &block)
1144
+ end
1145
+ entry = [compiled, names]
1146
+ call_sites[site] = entry if site
1147
+ end
1148
+ compiled, names = entry
1149
+ scope = block.binding
1150
+ compiled.call(*names.map { |local|
1151
+ begin
1152
+ scope.local_variable_get(local)
1153
+ rescue NameError
1154
+ raise Unsupported,
1155
+ "`#{prototype}` declares `#{local}`, and there is no local " \
1156
+ "by that name where the call stands. A declaration's " \
1157
+ "parameter names are what `jit_call` binds to"
1158
+ end
1159
+ })
1160
+ end
1161
+
1162
+ def call_sites
1163
+ @call_sites ||= {}.compare_by_identity
1164
+ end
1165
+
1166
+ # Asked at a `jit_call` site before anything is compiled, and answering
1167
+ # nil means "not mine, compile it". What it is handed is the
1168
+ # prototype, the block -- whose binding says which method and which
1169
+ # module the site is in -- and the names the declaration gave. What it
1170
+ # answers is anything that responds to `call`.
1171
+ #
1172
+ # There is one client and it is carray-jit-aot, which builds these same
1173
+ # sites into a shared object ahead of the program; a machine running
1174
+ # that gem then reaches no compiler. Left here rather than patched in
1175
+ # from there, because a gem reaching into another's method to change
1176
+ # what it does is the arrangement that breaks quietly.
1177
+ attr_accessor :call_provider
1178
+
1179
+ def function (prototype, declared_parameters: nil, &block)
564
1180
  unless block
565
1181
  raise Unsupported,
566
1182
  "a function is compiled from a block, and none was given -- " \
@@ -568,11 +1184,131 @@ class CArray
568
1184
  "`CArray.jit_extern(#{prototype.inspect})`"
569
1185
  end
570
1186
  name, return_type, parameters = CDeclaration.parse(prototype)
571
- compile_c_function(prototype, name, return_type, parameters, block)
1187
+ compile_c_function(prototype, name, return_type, parameters, block,
1188
+ declared_parameters)
1189
+ end
1190
+
1191
+ # One window over several functions, for a call that is handed more
1192
+ # than one address:
1193
+ #
1194
+ # CArray::JIT.watching(objective, gradient) do
1195
+ # NLopt.optimize(option, x, minimum)
1196
+ # end
1197
+ #
1198
+ # Every flag is put down before the block, and every one is read after
1199
+ # it -- because a flag nobody reads is a failure that becomes a wrong
1200
+ # answer, and then surfaces on an unrelated later window. Whichever
1201
+ # failure comes first in the argument list is the one raised, and a
1202
+ # failure raised this way outranks whatever the block raised, for the
1203
+ # reason `CFunction#watching` gives: the library is complaining about
1204
+ # a stand-in, and the stand-in is the consequence.
1205
+ #
1206
+ # `on_error:` is the `[hook, data]` pair `CFunction#on_error` takes,
1207
+ # set on every function for the length of the window and taken off
1208
+ # again afterwards -- with whatever hook was there before put back.
1209
+ # That is the difference from calling `#on_error` around the block:
1210
+ # the pair can be read back here and cannot be read back from Ruby, so
1211
+ # a window that brings its own hook is the only way to borrow one
1212
+ # without leaving the owner's gone.
1213
+ #
1214
+ # `stand_in:` is the number a failed call answers C with, as
1215
+ # `CFunction#watching` takes it, and is set on every function watched.
1216
+ # Which number is right belongs to the window and not to the body: the
1217
+ # same `int (*)(...)` may be handed to a routine that stops on a
1218
+ # non-zero status and to one that reads it as a rejected step and tries
1219
+ # again, and the body has no way of knowing which it was given to.
1220
+ #
1221
+ # `nil` in the list is skipped, so an optional gradient or jacobian may
1222
+ # be passed as it stands, and a function named twice is watched once.
1223
+ # A body that cannot fail has no flag, no hook and no stand-in, and
1224
+ # passing one changes nothing -- which is what lets a binding watch
1225
+ # what it was given without asking which kind of body it is.
1226
+ def watching (*functions, on_error: nil, stand_in: nil)
1227
+ armed = functions.compact
1228
+ armed.each do |function|
1229
+ next if function.is_a?(CFunction)
1230
+ raise TypeError,
1231
+ "`CArray::JIT.watching` watches compiled functions, and " \
1232
+ "#{function.class} is not one -- pass what `jit_function` " \
1233
+ "or `jit_extern` answered"
1234
+ end
1235
+ armed = armed.uniq
1236
+ hook = window_hook(on_error)
1237
+ standin = window_stand_in(stand_in)
1238
+ return yield if armed.empty?
1239
+ opened = armed.map { |function|
1240
+ function.send(:open_window, hook, standin)
1241
+ }
1242
+ codes = []
1243
+ begin
1244
+ result = yield
1245
+ rescue StandardError
1246
+ # Closed here rather than in the ensure below, so that the failure
1247
+ # raised next is raised from inside this rescue and carries the
1248
+ # library's own complaint as its cause.
1249
+ codes = close_windows(armed, opened)
1250
+ opened = nil
1251
+ raise_first_failure(armed, codes)
1252
+ raise
1253
+ ensure
1254
+ codes = close_windows(armed, opened) if opened
1255
+ end
1256
+ raise_first_failure(armed, codes)
1257
+ result
572
1258
  end
573
1259
 
574
1260
  private
575
1261
 
1262
+ # Every window closed, in the order they were opened, and what each of
1263
+ # them saw. All of them, whatever happened in the block: a flag nobody
1264
+ # reads is one that surfaces on an unrelated later window.
1265
+ def close_windows (armed, opened)
1266
+ armed.zip(opened).map { |function, state|
1267
+ function.send(:close_window, state)
1268
+ }
1269
+ end
1270
+
1271
+ # The first failure among the flags just read, raised as the function
1272
+ # that reported it would raise it. A code of 0 is no failure and is
1273
+ # passed over, so this walks the list in the order it was written and
1274
+ # stops at the first that has something to say.
1275
+ def raise_first_failure (armed, codes)
1276
+ armed.zip(codes).each do |function, code|
1277
+ function.send(:raise_for, code)
1278
+ end
1279
+ end
1280
+
1281
+ # The number a window hands the C as a failed call's answer. An
1282
+ # Integer because that is what the object carries it in -- one 64-bit
1283
+ # word, cast at the return -- and because a status is a whole number
1284
+ # wherever one is read.
1285
+ def window_stand_in (stand_in)
1286
+ return nil if stand_in.nil?
1287
+ unless stand_in.is_a?(Integer)
1288
+ raise TypeError,
1289
+ "`stand_in:` is the number a failed call answers C with, " \
1290
+ "and #{stand_in.class} is not one -- it is cast to whatever " \
1291
+ "the body returns, so what is given here is an Integer"
1292
+ end
1293
+ unless (-(2**63)...2**63).cover?(stand_in)
1294
+ raise RangeError,
1295
+ "`stand_in:` is carried in one 64-bit word, and " \
1296
+ "#{stand_in} does not fit in one"
1297
+ end
1298
+ stand_in
1299
+ end
1300
+
1301
+ def window_hook (on_error)
1302
+ return nil if on_error.nil?
1303
+ unless on_error.is_a?(Array) && (1..2).cover?(on_error.size)
1304
+ raise ArgumentError,
1305
+ "`on_error:` takes the hook and the one pointer it is " \
1306
+ "handed, as `CFunction#on_error` does -- " \
1307
+ "`on_error: [handle[\"nlopt_force_stop\"], option]`"
1308
+ end
1309
+ [on_error[0], on_error[1]]
1310
+ end
1311
+
576
1312
  def bind_c_function (prototype, name, return_type, parameters, from)
577
1313
  handle = library_handle(from)
578
1314
  begin
@@ -592,28 +1328,80 @@ class CArray
592
1328
  # see one name for all of them. So an anonymous one carries its own
593
1329
  # digest, and a named one carries the name it was given.
594
1330
  #
595
- # Always behind a prefix, though, and that is not tidiness. A name the
596
- # C already knows is the dangerous case, and the dangerous case is the
597
- # one that does *not* fail: `double sin(double)` matches math.h's
598
- # declaration, so the generated file defines libm's `sin` and the
599
- # shared object exports it -- where symbols are interposable, that
600
- # replaces sine for whatever loads it later. A mismatched signature is
601
- # a compile error and would have been noticed; this one would not.
602
- PREFIX = "carray_jit_"
1331
+ # Always behind `PREFIX`, though, for the reason stated where it is
1332
+ # defined.
603
1333
 
604
1334
  def function_symbol (name, key)
605
1335
  digest = Digest::SHA256.hexdigest(key.inspect)[0, 12]
606
1336
  "#{PREFIX}#{name || "function"}_#{digest}"
607
1337
  end
608
1338
 
609
- def compile_c_function (prototype, name, return_type, parameters, block)
1339
+ def compile_c_function (prototype, name, return_type, parameters, block,
1340
+ declared_parameters = nil)
610
1341
  node, source, origin = read_block(block)
611
- key = [source, return_type.text, parameters.map(&:text), name]
1342
+ # A function this body calls is pasted into it, so which one it is
1343
+ # belongs in the key beside the body's own text. Two blocks spelled
1344
+ # the same that reach different functions are different functions,
1345
+ # and without this the first compiled would be handed back for the
1346
+ # second -- quietly, since nothing about them differs to look at.
1347
+ # `kernel_key` is what a kernel already keys a pasted body by: the
1348
+ # signature and the symbol, which carries the digest of the body. A
1349
+ # symbol rather than an address, so the key means the same thing in
1350
+ # the next process as in this one.
1351
+ called = called_functions(source, node, block, name)
1352
+ key = [source, return_type.text, parameters.map(&:text), name,
1353
+ declared_parameters, called.values.map(&:kernel_key)]
612
1354
  found = function_registry[key]
613
1355
  return found if found
614
1356
  function_registry[key] =
615
1357
  build_c_function(prototype, name, return_type, parameters,
616
- source, node, origin, block, function_symbol(name, key))
1358
+ source, node, origin, block, function_symbol(name, key),
1359
+ called, declared_parameters)
1360
+ end
1361
+
1362
+ # The compiled functions the block reaches for, by the name it reaches
1363
+ # them by. Only these: everything else it closes over is refused, and
1364
+ # `refuse_captures` is where that is said. This runs before the
1365
+ # registry is consulted, because the key cannot be built without it.
1366
+ def called_functions (source, node, block, own_name)
1367
+ names = capture_names(source, node) - block.parameters.map(&:last)
1368
+ names -= [own_name.to_sym] if own_name
1369
+ binding = binding_of(block)
1370
+ names.each_with_object({}) do |captured, found|
1371
+ value = captured_value(captured, binding)
1372
+ # A function compiled here is pasted into this one; one bound from
1373
+ # a library is declared and called by its name, which is what it
1374
+ # has and what a linker resolves. Both are functions this body
1375
+ # calls, so both are here.
1376
+ found[captured] = value if value.is_a?(CFunction)
1377
+ end
1378
+ end
1379
+
1380
+ # What a name held where the block was written, or nil for one that
1381
+ # held nothing. A constant is looked up as well as a local, because a
1382
+ # method body closes over nothing: a `def` that compiles a function
1383
+ # reaches the one it calls by a constant or not at all.
1384
+ def captured_value (name, binding)
1385
+ if name.to_s.start_with?(/[A-Z]/)
1386
+ binding.eval(name.to_s)
1387
+ elsif binding.local_variable_defined?(name)
1388
+ binding.local_variable_get(name)
1389
+ end
1390
+ rescue NameError
1391
+ nil
1392
+ end
1393
+
1394
+ # Whether the name held anything at all, which `captured_value` cannot
1395
+ # say: a name holding nil and a name that is not there both come back
1396
+ # as nil, and only one of them is worth a different message.
1397
+ def captured_name_defined? (name, binding)
1398
+ if name.to_s.start_with?(/[A-Z]/)
1399
+ binding.eval("defined?(#{name})") ? true : false
1400
+ else
1401
+ binding.local_variable_defined?(name)
1402
+ end
1403
+ rescue NameError
1404
+ false
617
1405
  end
618
1406
 
619
1407
  def function_registry
@@ -621,19 +1409,24 @@ class CArray
621
1409
  end
622
1410
 
623
1411
  def build_c_function (prototype, name, return_type, parameters,
624
- source, node, origin, block, symbol)
1412
+ source, node, origin, block, symbol, called = {},
1413
+ declared_parameters = nil)
625
1414
  # A function is a function of its parameters. Whatever else the block
626
1415
  # reaches for is refused, and the reason differs by what it is -- so
627
1416
  # the captures are looked at before the body is walked, or the body
628
1417
  # would raise first and say something less useful.
629
- names = block.parameters.map(&:last)
1418
+ # A body written for `jit_call` takes no parameters -- the
1419
+ # declaration named them, and the same names are the locals the call
1420
+ # reads -- so the arity is the declaration's to state.
1421
+ names = declared_parameters || block.parameters.map(&:last)
630
1422
  unless names.size == parameters.size
631
1423
  raise Unsupported,
632
1424
  "`#{prototype}` names #{parameters.size} " \
633
1425
  "#{parameters.size == 1 ? 'parameter' : 'parameters'}, and " \
634
1426
  "the block takes #{names.size}"
635
1427
  end
636
- refuse_captures(source, node, block, names, name && name.to_sym)
1428
+ refuse_captures(source, node, block, names + called.keys,
1429
+ name && name.to_sym)
637
1430
 
638
1431
  # `void` is a return type a body may have: a function whose work is
639
1432
  # through its pointer parameters has nothing to hand back, and C says
@@ -659,6 +1452,9 @@ class CArray
659
1452
  .to_h { |name, type|
660
1453
  [name, type.indexable? ? !type.const : nil]
661
1454
  }
1455
+ pointer_lengths = names.zip(parameters)
1456
+ .select { |_, type| type.indexable? && type.sized? }
1457
+ .to_h { |name, type| [name, type.array] }
662
1458
  pointer_types = names.zip(parameters).select { |_, type| type.indexable? }
663
1459
  .to_h { |name, type| [name, type.element.computation] }
664
1460
 
@@ -666,8 +1462,11 @@ class CArray
666
1462
  # own body, as C does, so the body can call itself. An anonymous one
667
1463
  # has nothing to call itself by, and gets no recursion.
668
1464
  analyzer = Analyzer.new(source, node: node, function: true,
1465
+ declared_parameters: declared_parameters,
669
1466
  returns: !returns_nothing,
670
1467
  pointers: pointers,
1468
+ pointer_lengths: pointer_lengths,
1469
+ c_functions: called,
671
1470
  recursion: (name && [name.to_sym, parameters,
672
1471
  return_type.computation]))
673
1472
  names = analyzer.parameter_names
@@ -682,45 +1481,59 @@ class CArray
682
1481
  raise Unsupported,
683
1482
  (if type.indexable?
684
1483
  "`#{loose}` is declared `#{type.text}`, which is a pointer; " \
685
- "index it, as in `#{loose}[0]`"
1484
+ "index it, as in `#{loose}[0]`, or ask whether one came, " \
1485
+ "as in `if #{loose}` or `#{loose}.nil?`"
686
1486
  else
687
1487
  "`#{loose}` is declared `#{type.text}`, which is a slot in " \
688
- "the signature rather than a value; the body cannot read it"
1488
+ "the signature rather than a value; the body cannot read " \
1489
+ "it, only ask whether it was filled, as in `#{loose}.nil?`"
689
1490
  end)
690
1491
  end
691
- # A body is handed its values through the kernel's three scalar buses,
692
- # which carry doubles, int64s and complexes. A uint64 argument is the
693
- # one numeric type none of them can carry whole -- that is what having
694
- # its own computation type means -- so it is refused here, where the
695
- # declaration is, rather than deeper down as a kernel that cannot be
696
- # built. A `uint64_t *` reaches an array of them, and a uint64_t
697
- # value comes back out of a body unharmed.
698
- names.zip(parameters).each do |parameter, type|
699
- next if type.pointer || type.computation != :uint64
700
- raise Unsupported,
701
- "`#{parameter}` is declared `#{type.text}`, and a value is " \
702
- "handed to a body as a double, an int64 or a complex -- a " \
703
- "uint64 fits none of them without losing a bit. Take " \
704
- "`#{type.text} *` and index it, or take an int64 where the " \
705
- "values are small enough to be one"
706
- end
1492
+ # A parameter of any computation type the body can work in, uint64
1493
+ # included. A kernel's captures have three buses to travel in and
1494
+ # uint64 is not one of them, but these are not captures: they are the
1495
+ # parameters of this function's own C signature, and arrive in the
1496
+ # type the declaration named. So `size_t n` is a value the body can
1497
+ # be handed, which is the point -- it is how the C that counts bytes
1498
+ # is spelled.
707
1499
  types = names.zip(parameters).reject { |_, type| type.pointer }
708
1500
  .to_h { |parameter, type| [parameter, type.computation] }
709
1501
 
710
- assignment = TypeAssignment.new(analyzer.body, {}, {}, {},
1502
+ assignment = TypeAssignment.new(analyzer.body, {}, {}, called,
711
1503
  scalar_types: types,
712
1504
  pointer_types: pointer_types)
713
1505
  generator = CGenerator.new(analyzer, {}, assignment.scalar_types,
714
- origin: origin, block_source: source)
1506
+ c_functions: called,
1507
+ origin: origin, block_source: source,
1508
+ scalar_parameters: types.keys)
715
1509
  c_source = generator.generate_function(
716
1510
  symbol, names, parameters, return_type.text, return_type.computation)
1511
+ # A signature carrying a complex by value gets a second entry point
1512
+ # for Ruby to reach it by, since Fiddle has no such type to call
1513
+ # with. Only such a signature: everything else is called directly,
1514
+ # and pays nothing for a road it does not take.
1515
+ shim_symbol = nil
1516
+ if return_type.complex? || parameters.any?(&:complex?)
1517
+ shim_symbol = "#{symbol}_from_ruby"
1518
+ c_source += shim_source(shim_symbol, symbol, names, parameters,
1519
+ return_type)
1520
+ end
717
1521
  handle, = Compiler.build(c_source, symbol, header: generator.provenance)
718
1522
  # Where the body can divide by zero or reach outside an array, the
719
1523
  # object carries a place to say so. Reading it is what lets a call
720
1524
  # from Ruby raise what the same expression raises in Ruby.
721
- error = if generator.uses_error_flag?
722
- Fiddle::Pointer.new(handle[CGenerator::ERROR_FLAG], 4)
723
- end
1525
+ #
1526
+ # The place is the calling thread's, and a thread-local is not a name
1527
+ # the loader can hand an address for, so what is taken here is the
1528
+ # accessor beside it -- called once per thread, from that thread. It
1529
+ # is named after the body, the four it answers for being `static`, so
1530
+ # that two objects generated this way can be linked side by side.
1531
+ error_state = if generator.uses_error_flag?
1532
+ accessor = CGenerator.error_state_name(symbol)
1533
+ Fiddle::Function.new(handle[accessor],
1534
+ [Fiddle::TYPE_VOIDP],
1535
+ Fiddle::TYPE_VOID, name: accessor)
1536
+ end
724
1537
  # A body that reports failures is generated a second time for pasting,
725
1538
  # with the flag as a parameter. A second generator rather than the
726
1539
  # same one twice: what it emitted is what it holds, and the two forms
@@ -728,20 +1541,68 @@ class CArray
728
1541
  pasted = generator
729
1542
  if generator.uses_error_flag?
730
1543
  pasted = CGenerator.new(analyzer, {}, assignment.scalar_types,
731
- origin: origin, block_source: source)
1544
+ c_functions: called,
1545
+ origin: origin, block_source: source,
1546
+ scalar_parameters: types.keys)
732
1547
  pasted.generate_function(symbol, names, parameters, return_type.text,
733
1548
  return_type.computation,
734
1549
  error_parameter: true)
735
1550
  end
736
- CFunction.new(symbol, prototype, return_type, parameters, handle[symbol],
1551
+ CFunction.new(name, prototype, return_type, parameters, handle[symbol],
1552
+ symbol: symbol,
1553
+ shim: shim_symbol && handle[shim_symbol],
737
1554
  block: block, c_source: generator.provenance + c_source,
738
- origin: origin, error: error,
1555
+ origin: origin, error_state: error_state,
739
1556
  definition: pasted.function_definition,
740
1557
  helpers: pasted.helper_needs,
1558
+ dependencies: called.values,
741
1559
  takes_error: generator.uses_error_flag?,
742
1560
  raise_messages: generator.raise_messages)
743
1561
  end
744
1562
 
1563
+ # The entry point a call from Ruby takes where the signature carries a
1564
+ # complex by value. Each complex argument arrives as the two doubles
1565
+ # C99 lays one out as, and a complex result is written back the same
1566
+ # way; every other parameter keeps its own type, so a pointer is still
1567
+ # a pointer and an integer is still that integer.
1568
+ #
1569
+ # It calls the function rather than repeating it, so there is one body
1570
+ # and both roads reach it.
1571
+ def shim_source (shim_symbol, symbol, names, parameters, return_type)
1572
+ declarations = names.zip(parameters).map { |name, type|
1573
+ type.complex? ? "const double *#{name}" : type.declare(name)
1574
+ }
1575
+ passed = names.zip(parameters).map { |name, type|
1576
+ next name unless type.complex?
1577
+ "#{type.complex_build}(#{name}[0], #{name}[1])"
1578
+ }
1579
+ call = "#{symbol}(#{passed.join(', ')})"
1580
+ if return_type.complex?
1581
+ declarations << "double *carray_jit_result"
1582
+ body = <<~C
1583
+ #{return_type.text} carray_jit_value = #{call};
1584
+ carray_jit_result[0] = creal(carray_jit_value);
1585
+ carray_jit_result[1] = cimag(carray_jit_value);
1586
+ C
1587
+ head = "void"
1588
+ else
1589
+ body = "#{return_type.computation ? 'return ' : ''}#{call};\n"
1590
+ head = return_type.text
1591
+ end
1592
+ <<~C
1593
+
1594
+ /* Fiddle has no type for a C99 complex, so a call from Ruby comes
1595
+ through here: the complex arguments arrive as the two doubles
1596
+ one is laid out as, and a complex result goes back the same way.
1597
+ A kernel calls the function above directly, C to C. */
1598
+ #{head}
1599
+ #{shim_symbol} (#{declarations.join(', ')})
1600
+ {
1601
+ #{body.strip}
1602
+ }
1603
+ C
1604
+ end
1605
+
745
1606
  # Nothing outside the parameter list may be reached. A number could in
746
1607
  # principle be written into the C as a literal, and another c_function's
747
1608
  # address as a constant -- but both would put something in the compiled
@@ -766,16 +1627,30 @@ class CArray
766
1627
  captured -= [own_name] if own_name
767
1628
  return if captured.empty?
768
1629
  name = captured.first
769
- value = begin
770
- binding_of(block).local_variable_get(name)
771
- rescue NameError
772
- nil
773
- end
774
- kind = case value
775
- when CArray then "an array"
776
- when CFunction then "another C function"
777
- else "a value"
778
- end
1630
+ value = captured_value(name, binding_of(block))
1631
+ # A CFunction never reaches here: `called_functions` took both
1632
+ # kinds above -- compiled ones to paste, borrowed ones to declare and
1633
+ # call by name -- so neither is a capture by the time this runs.
1634
+ if value.is_a?(CArray::Rng)
1635
+ # A generator has state, and a compiled function has nowhere to
1636
+ # keep one -- the same reason a borrowed address is refused above.
1637
+ # A kernel is handed its operands at every call and can be given
1638
+ # the state among them; a function's arguments are the ones its
1639
+ # declaration named, and adding one behind the caller's back would
1640
+ # change the C signature it was promised. So the state is named,
1641
+ # and the body draws from it the way the generator's own C does.
1642
+ raise Unsupported,
1643
+ "this function reaches `#{name}`, which is a generator; a " \
1644
+ "compiled function has nowhere to keep its state. Take the " \
1645
+ "state as a parameter -- declare `int64_t state[4]` and pass " \
1646
+ "`#{name}.state` -- or draw in the kernel that calls this, " \
1647
+ "where `random(rng: #{name})` works"
1648
+ end
1649
+ unless captured_name_defined?(name, binding_of(block))
1650
+ raise Unsupported,
1651
+ "`#{name}` is not defined where the block was written"
1652
+ end
1653
+ kind = value.is_a?(CArray) ? "an array" : "a value"
779
1654
  raise Unsupported,
780
1655
  "this function reaches `#{name}`, which is #{kind} outside it; " \
781
1656
  "a compiled function takes everything it needs through its " \