wardite 0.2.2 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
data/lib/wardite.rb CHANGED
@@ -31,13 +31,15 @@ module Wardite
31
31
 
32
32
  attr_accessor :runtime #: Runtime
33
33
 
34
+ attr_accessor :types #: Array[Type]
35
+
34
36
  attr_accessor :store #: Store
35
37
 
36
38
  attr_accessor :exports #: Exports
37
39
 
38
- attr_reader :import_object #: Hash[Symbol, Hash[Symbol, Proc]]
40
+ attr_reader :import_object #: Hash[Symbol, Hash[Symbol, wasmCallable]]
39
41
 
40
- # @rbs import_object: Hash[Symbol, Hash[Symbol, Proc]]
42
+ # @rbs import_object: Hash[Symbol, Hash[Symbol, wasmCallable]]
41
43
  # @rbs &blk: (Instance) -> void
42
44
  def initialize(import_object, &blk)
43
45
  blk.call(self)
@@ -46,6 +48,31 @@ module Wardite
46
48
  @store = Store.new(self)
47
49
  @exports = Exports.new(self.export_section, store)
48
50
  @runtime = Runtime.new(self)
51
+
52
+ @types = []
53
+ type_section = self.type_section
54
+ if type_section
55
+ type_section.defined_types.each_with_index do |calltype, idx|
56
+ rettype = type_section.defined_results[idx]
57
+ @types << Type.new(calltype, rettype)
58
+ end
59
+ end
60
+
61
+ check_data_count
62
+ end
63
+
64
+ # @rbs return: void
65
+ def check_data_count
66
+ data_count = self.data_count_section&.count
67
+ if data_count
68
+ actual_count = self.data_section&.segments&.size
69
+ if !actual_count
70
+ raise LoadError, "invalid data segment count"
71
+ end
72
+ if (data_count != actual_count)
73
+ raise LoadError, "invalid data segment count"
74
+ end
75
+ end
49
76
  end
50
77
 
51
78
  # @rbs return: ImportSection
@@ -82,6 +109,18 @@ module Wardite
82
109
  sec
83
110
  end
84
111
 
112
+ # @rbs return: StartSection|nil
113
+ def start_section
114
+ sec = @sections.find{|s| s.code == Const::SectionStart }
115
+ if !sec
116
+ return nil
117
+ end
118
+ if !sec.is_a?(StartSection)
119
+ raise(GenericError, "[BUG] found invalid start section")
120
+ end
121
+ sec
122
+ end
123
+
85
124
  # @rbs return: GlobalSection|nil
86
125
  def global_section
87
126
  sec = @sections.find{|s| s.code == Const::SectionGlobal }
@@ -106,6 +145,18 @@ module Wardite
106
145
  sec
107
146
  end
108
147
 
148
+ # @rbs return: DataCountSection|nil
149
+ def data_count_section
150
+ sec = @sections.find{|s| s.code == Const::SectionDataCount }
151
+ if !sec
152
+ return nil
153
+ end
154
+ if !sec.is_a?(DataCountSection)
155
+ raise(GenericError, "[BUG] found invalid data section")
156
+ end
157
+ sec
158
+ end
159
+
109
160
  # @rbs return: FunctionSection|nil
110
161
  def function_section
111
162
  sec = @sections.find{|s| s.code == Const::SectionFunction }
@@ -118,6 +169,30 @@ module Wardite
118
169
  sec
119
170
  end
120
171
 
172
+ # @rbs return: TableSection?
173
+ def table_section
174
+ sec = @sections.find{|s| s.code == Const::SectionTable }
175
+ if !sec
176
+ return nil
177
+ end
178
+ if !sec.is_a?(TableSection)
179
+ raise(GenericError, "instance doesn't have required section")
180
+ end
181
+ sec
182
+ end
183
+
184
+ # @rbs return: ElemSection?
185
+ def elem_section
186
+ sec = @sections.find{|s| s.code == Const::SectionElement }
187
+ if !sec
188
+ return nil
189
+ end
190
+ if !sec.is_a?(ElemSection)
191
+ raise(GenericError, "instance doesn't have required section")
192
+ end
193
+ sec
194
+ end
195
+
121
196
  # @rbs return: CodeSection|nil
122
197
  def code_section
123
198
  sec = @sections.find{|s| s.code == Const::SectionCode }
@@ -147,7 +222,7 @@ module Wardite
147
222
  include ValueHelper
148
223
 
149
224
  # TODO: add types of class that the stack accomodates
150
- attr_accessor :stack #: Array[I32|I64|F32|F64]
225
+ attr_accessor :stack #: Array[wasmValue]
151
226
 
152
227
  attr_accessor :call_stack #: Array[Frame]
153
228
 
@@ -158,6 +233,16 @@ module Wardite
158
233
  @stack = []
159
234
  @call_stack = []
160
235
  @instance = inst
236
+
237
+ invoke_start_section
238
+ end
239
+
240
+ # @rbs return: void
241
+ def invoke_start_section
242
+ start_section = instance.start_section
243
+ if start_section
244
+ call_by_index(start_section.func_index)
245
+ end
161
246
  end
162
247
 
163
248
  # @rbs name: String|Symbol
@@ -200,6 +285,21 @@ module Wardite
200
285
  end
201
286
  end
202
287
 
288
+ # @rbs idx: Integer
289
+ # @rbs return: void
290
+ def call_by_index(idx)
291
+ fn = @instance.store.funcs[idx]
292
+
293
+ case fn
294
+ when WasmFunction
295
+ invoke_internal(fn)
296
+ when ExternalFunction
297
+ invoke_external(fn)
298
+ else
299
+ raise GenericError, "registered pointer is not to a function"
300
+ end
301
+ end
302
+
203
303
  # @rbs wasm_function: WasmFunction
204
304
  # @rbs return: void
205
305
  def push_frame(wasm_function)
@@ -249,7 +349,7 @@ module Wardite
249
349
  end
250
350
 
251
351
  # @rbs external_function: ExternalFunction
252
- # @rbs return: I32|I64|F32|F64|nil
352
+ # @rbs return: wasmValue|nil
253
353
  def invoke_external(external_function)
254
354
  local_start = stack.size - external_function.callsig.size
255
355
  args = stack[local_start..]
@@ -326,19 +426,80 @@ module Wardite
326
426
  when :nop
327
427
  return
328
428
 
429
+ when :br
430
+ level = insn.operand[0]
431
+ raise EvalError, "br op without level" if !level.is_a?(Integer)
432
+ pc = do_branch(frame.labels, stack, level)
433
+ frame.pc = pc
434
+
435
+ when :br_if
436
+ level = insn.operand[0]
437
+ raise EvalError, "br op without level" if !level.is_a?(Integer)
438
+ cond = stack.pop
439
+ raise EvalError, "cond not found" if !cond.is_a?(I32)
440
+ if cond.value.zero?
441
+ return
442
+ end
443
+ pc = do_branch(frame.labels, stack, level)
444
+ frame.pc = pc
445
+
446
+ when :br_table
447
+ level_vec = insn.operand[0]
448
+ raise EvalError, "no level vector" if !level_vec.is_a?(Array)
449
+ default = insn.operand[1]
450
+ raise EvalError, "no default specified" if !default.is_a?(Integer)
451
+ idx = stack.pop
452
+ raise EvalError, "idx not found" if !idx.is_a?(I32)
453
+ level = if idx.value_s < 0 || idx.value_s >= level_vec.size
454
+ default
455
+ else
456
+ level_vec[idx.value_s]
457
+ end
458
+ pc = do_branch(frame.labels, stack, level)
459
+ frame.pc = pc
460
+
461
+ when :block
462
+ block = insn.operand[0]
463
+ raise EvalError, "block op without block" if !block.is_a?(Block)
464
+ next_pc = fetch_ops_while_end(frame.body, frame.pc)
465
+ label = Label.new(:block, next_pc, stack.size, block.result_size)
466
+ frame.labels.push(label)
467
+
468
+ when :loop
469
+ block = insn.operand[0]
470
+ raise EvalError, "loop op without block" if !block.is_a?(Block)
471
+ start = frame.pc
472
+ end_pc = fetch_ops_while_end(frame.body, frame.pc)
473
+ label = Label.new(:loop, end_pc, stack.size, block.result_size, start)
474
+ frame.labels.push(label)
475
+
329
476
  when :if
330
477
  block = insn.operand[0]
331
478
  raise EvalError, "if op without block" if !block.is_a?(Block)
332
479
  cond = stack.pop
333
480
  raise EvalError, "cond not found" if !cond.is_a?(I32)
334
481
  next_pc = fetch_ops_while_end(frame.body, frame.pc)
482
+
335
483
  if cond.value.zero?
336
- frame.pc = next_pc
484
+ frame.pc = fetch_ops_while_else_or_end(frame.body, frame.pc)
485
+ end
486
+
487
+ if frame.pc == next_pc
488
+ # This means if block has no else instr.
489
+ return
337
490
  end
338
491
 
339
492
  label = Label.new(:if, next_pc, stack.size, block.result_size)
340
493
  frame.labels.push(label)
341
494
 
495
+ when :else
496
+ if old_label = frame.labels.pop
497
+ frame.pc = old_label.pc
498
+ stack_unwind(old_label.sp, old_label.arity)
499
+ else
500
+ raise EvalError, "else should be in if block"
501
+ end
502
+
342
503
  when :call
343
504
  idx = insn.operand[0]
344
505
  raise EvalError, "[BUG] local operand not found" if !idx.is_a?(Integer)
@@ -353,6 +514,45 @@ module Wardite
353
514
  raise GenericError, "got a non-function pointer"
354
515
  end
355
516
 
517
+ when :call_indirect
518
+ table = self.instance.store.tables[0]
519
+ raise EvalError, "table required but not found" if !table
520
+ type_idx = insn.operand[0]
521
+ raise EvalError, "[BUG] index operand invalid" if !type_idx.is_a?(Integer)
522
+ nullbyte = insn.operand[1]
523
+ raise EvalError, "[BUG] invalid bytearray of call_indirect" if nullbyte != 0x0
524
+ table_idx = stack.pop
525
+ raise EvalError, "[BUG] index stack invalid" if !table_idx.is_a?(I32)
526
+ fntype = self.instance.types[type_idx]
527
+ if !fntype
528
+ raise EvalError, "undefined type index: idx=#{type_idx}"
529
+ end
530
+ refs = self.instance.store.tables[0]&.refs
531
+ if !refs
532
+ raise EvalError, "uninitialized element idx:#{table_idx}"
533
+ end
534
+
535
+ fn = refs[table_idx.value]
536
+ case fn
537
+ when WasmFunction
538
+ if table.type != :funcref
539
+ raise EvalError, "invalid type of elem; expected: #{table.type}"
540
+ end
541
+ fn = fn.clone(override_type: fntype)
542
+ push_frame(fn)
543
+ when ExternalFunction
544
+ if table.type != :externref
545
+ raise EvalError, "invalid type of elem; expected: #{table.type}"
546
+ end
547
+ fn = fn.clone(override_type: fntype)
548
+ ret = invoke_external(fn)
549
+ self.stack.push ret if ret
550
+ when nil
551
+ raise EvalError, "uninitialized element idx:#{table_idx.value}"
552
+ else
553
+ raise EvalError, "[BUG] unknwon function type #{fn}"
554
+ end
555
+
356
556
  when :return
357
557
  old_frame = call_stack.pop
358
558
  if !old_frame
@@ -408,6 +608,18 @@ module Wardite
408
608
  end
409
609
  frame.locals[idx] = value
410
610
 
611
+ when :local_tee
612
+ idx = insn.operand[0]
613
+ if !idx.is_a?(Integer)
614
+ raise EvalError, "[BUG] invalid type of operand"
615
+ end
616
+ value = stack.pop
617
+ if !value
618
+ raise EvalError, "value should be pushed"
619
+ end
620
+ frame.locals[idx] = value
621
+ stack.push value
622
+
411
623
  when :global_get
412
624
  idx = insn.operand[0]
413
625
  if !idx.is_a?(Integer)
@@ -450,17 +662,126 @@ module Wardite
450
662
  memory = instance.store.memories[0] || raise("[BUG] no memory")
451
663
  stack.push(I32(memory.grow(delta.value)))
452
664
 
665
+ when :memory_init
666
+ idx = insn.operand[0]
667
+ if !idx.is_a?(Integer)
668
+ raise EvalError, "[BUG] invalid type of operand"
669
+ end
670
+ if insn.operand[1] != 0x0
671
+ $stderr.puts "warning: :memory_init is not ending with 0x00"
672
+ end
673
+ data_sec = instance.data_section
674
+ if !data_sec
675
+ raise EvalError, "data segment out of range"
676
+ end
677
+ data_seg = data_sec.segments[idx]
678
+ if !data_seg
679
+ raise EvalError, "data segment out of range"
680
+ end
681
+
682
+ memory = instance.store.memories[0] || raise("[BUG] no memory")
683
+ length, src_offset, dest_offset = stack.pop, stack.pop, stack.pop
684
+ if !length.is_a?(I32) || !src_offset.is_a?(I32) || !dest_offset.is_a?(I32)
685
+ raise EvalError, "invalid stack values"
686
+ end
687
+ source = data_seg.data[src_offset.value...(src_offset.value+length.value)]
688
+ raise EvalError, "invalid source range" if !source
689
+ memory.data[dest_offset.value...(dest_offset.value+length.value)] = source
690
+
691
+ when :memory_copy
692
+ if insn.operand[0] != 0x0 || insn.operand[1] != 0x0
693
+ $stderr.puts "warning: :memory_copy is not ending with 0x00"
694
+ end
695
+ length, src_offset, dest_offset = stack.pop, stack.pop, stack.pop
696
+ if !length.is_a?(I32) || !src_offset.is_a?(I32) || !dest_offset.is_a?(I32)
697
+ raise EvalError, "invalid stack values"
698
+ end
699
+ memory = instance.store.memories[0] || raise("[BUG] no memory")
700
+ source = memory.data[src_offset.value...(src_offset.value+length.value)]
701
+ raise EvalError, "invalid source range" if !source
702
+ memory.data[dest_offset.value...(dest_offset.value+length.value)] = source
703
+
704
+ when :memory_fill
705
+ if insn.operand[0] != 0x0
706
+ $stderr.puts "warning: :memory_fill is not ending with 0x00"
707
+ end
708
+ length, byte, dest_offset = stack.pop, stack.pop, stack.pop
709
+ if !length.is_a?(I32) || !byte.is_a?(I32) || !dest_offset.is_a?(I32)
710
+ raise EvalError, "invalid stack values"
711
+ end
712
+ memory = instance.store.memories[0] || raise("[BUG] no memory")
713
+ source = byte.value.chr * length.value
714
+ memory.data[dest_offset.value...(dest_offset.value+length.value)] = source
715
+
453
716
  else
454
717
  raise "TODO! unsupported #{insn.inspect}"
455
718
  end
456
719
 
457
720
  rescue => e
458
721
  require "pp"
722
+ $stderr.puts "instance:::\n#{self.instance.pretty_inspect}"
459
723
  $stderr.puts "frame:::\n#{frame.pretty_inspect}"
460
724
  $stderr.puts "stack:::\n#{stack.pretty_inspect}"
461
725
  raise e
462
726
  end
463
727
 
728
+ # @rbs ops: Array[Op]
729
+ # @rbs pc_start: Integer
730
+ # @rbs return: Integer
731
+ def fetch_ops_while_else_or_end(ops, pc_start)
732
+ cursor = pc_start
733
+ depth = 0
734
+ loop {
735
+ cursor += 1
736
+ inst = ops[cursor]
737
+ case inst&.code
738
+ when nil
739
+ raise EvalError, "end op not found"
740
+ when :if
741
+ depth += 1
742
+ when :else
743
+ if depth == 0
744
+ return cursor
745
+ end
746
+ # do not touch depth
747
+ when :end
748
+ if depth == 0
749
+ return cursor
750
+ else
751
+ depth -= 1
752
+ end
753
+ else
754
+ # nop
755
+ end
756
+ }
757
+ raise "[BUG] unreachable"
758
+ end
759
+
760
+ # @rbs labels: Array[Label]
761
+ # @rbs stack: Array[wasmValue]
762
+ # @rbs level: Integer
763
+ # @rbs return: Integer
764
+ def do_branch(labels, stack, level)
765
+ idx = labels.size - 1 - level
766
+ label = labels[idx]
767
+ pc = if label.kind == :loop
768
+ # keep the top of labels for loop again...
769
+ while labels.size > idx + 1
770
+ labels.pop
771
+ end
772
+ stack_unwind(label.sp, 0)
773
+ label.start || raise(EvalError, "loop withour start")
774
+ else
775
+ while labels.size > idx
776
+ labels.pop
777
+ end
778
+ stack_unwind(label.sp, label.arity)
779
+ label.pc
780
+ end
781
+
782
+ pc
783
+ end
784
+
464
785
  # @rbs ops: Array[Op]
465
786
  # @rbs pc_start: Integer
466
787
  # @rbs return: Integer
@@ -473,7 +794,7 @@ module Wardite
473
794
  case inst&.code
474
795
  when nil
475
796
  raise EvalError, "end op not found"
476
- when :i
797
+ when :if, :block, :loop
477
798
  depth += 1
478
799
  when :end
479
800
  if depth == 0
@@ -509,7 +830,7 @@ module Wardite
509
830
  end
510
831
 
511
832
  # @rbs finish: Integer
512
- # @rbs return: Array[I32|I64|F32|F64]
833
+ # @rbs return: Array[wasmValue]
513
834
  def drained_stack(finish)
514
835
  drained = stack[0...finish]
515
836
  if ! drained
@@ -537,6 +858,20 @@ module Wardite
537
858
  end
538
859
  end
539
860
 
861
+ class Type
862
+ attr_accessor :callsig #: Array[Symbol]
863
+
864
+ attr_accessor :retsig #: Array[Symbol]
865
+
866
+ # @rbs callsig: Array[Symbol]
867
+ # @rbs retsig: Array[Symbol]
868
+ # @rbs returb: void
869
+ def initialize(callsig, retsig)
870
+ @callsig = callsig
871
+ @retsig = retsig
872
+ end
873
+ end
874
+
540
875
  class Frame
541
876
  attr_accessor :pc #: Integer
542
877
  attr_accessor :sp #: Integer
@@ -547,13 +882,13 @@ module Wardite
547
882
 
548
883
  attr_accessor :labels #: Array[Label]
549
884
 
550
- attr_accessor :locals #: Array[I32|I64|F32|F64]
885
+ attr_accessor :locals #: Array[wasmValue]
551
886
 
552
887
  # @rbs pc: Integer
553
888
  # @rbs sp: Integer
554
889
  # @rbs body: Array[Op]
555
890
  # @rbs arity: Integer
556
- # @rbs locals: Array[Object]
891
+ # @rbs locals: Array[wasmValue]
557
892
  # @rbs returb: void
558
893
  def initialize(pc, sp, body, arity, locals)
559
894
  @pc = pc
@@ -573,16 +908,20 @@ module Wardite
573
908
 
574
909
  attr_accessor :arity #: Integer
575
910
 
911
+ attr_accessor :start #: Integer|nil
912
+
576
913
  # @rbs kind: (:if|:loop|:block)
577
914
  # @rbs pc: Integer
578
915
  # @rbs sp: Integer
579
916
  # @rbs arity: Integer
580
- # @rbs returb: void
581
- def initialize(kind, pc, sp, arity)
917
+ # @rbs start: Integer|nil
918
+ # @rbs return: void
919
+ def initialize(kind, pc, sp, arity, start=nil)
582
920
  @kind = kind
583
921
  @pc = pc
584
922
  @sp = sp
585
923
  @arity = arity
924
+ @start = start
586
925
  end
587
926
  end
588
927
 
@@ -595,6 +934,10 @@ module Wardite
595
934
 
596
935
  attr_accessor :globals #: Array[Global]
597
936
 
937
+ attr_accessor :tables #: Array[Table]
938
+
939
+ attr_accessor :elements #: Array[[Symbol, Integer, Array[Integer]]]
940
+
598
941
  # @rbs inst: Instance
599
942
  # @rbs return: void
600
943
  def initialize(inst)
@@ -641,9 +984,12 @@ module Wardite
641
984
  data_section = inst.data_section
642
985
  if data_section
643
986
  data_section.segments.each do |segment|
644
- memory = self.memories[segment.flags]
987
+ if segment.mode != :active
988
+ next
989
+ end
990
+ memory = self.memories[segment.mem_index]
645
991
  if !memory
646
- raise GenericError, "invalid memory index: #{segment.flags}"
992
+ raise GenericError, "invalid memory index: #{segment.mem_index}"
647
993
  end
648
994
 
649
995
  data_start = segment.offset
@@ -669,6 +1015,56 @@ module Wardite
669
1015
  end
670
1016
  end
671
1017
  end
1018
+
1019
+ @tables = []
1020
+ @elements = []
1021
+ table_section = inst.table_section
1022
+ if table_section
1023
+ table_section.table_types.each_with_index do |typ, idx|
1024
+ init, max = *table_section.table_limits[idx]
1025
+ if !init
1026
+ raise LoadError, "empty limits"
1027
+ end
1028
+ table = Table.new(typ, init, max)
1029
+ @tables << table
1030
+ end
1031
+ end
1032
+
1033
+ elem_section = inst.elem_section
1034
+ if elem_section
1035
+ elem_section.table_indices.each_with_index do |tidx, idx|
1036
+ table = @tables[tidx]
1037
+ if !table
1038
+ raise LoadError, "invalid table index #{tidx}"
1039
+ end
1040
+ typ = table.type
1041
+ offset = elem_section.table_offsets[idx]
1042
+ if !offset
1043
+ raise LoadError, "invalid element index #{idx}"
1044
+ end
1045
+ indices = elem_section.element_indices[idx]
1046
+ if !indices
1047
+ raise LoadError, "invalid element index #{idx}"
1048
+ end
1049
+ elms = [typ, offset, indices] #: [Symbol, Integer, Array[Integer]]
1050
+ @elements << elms
1051
+ end
1052
+ end
1053
+
1054
+ @elements.each_with_index do |(typ, offset, indices), idx|
1055
+ table = @tables[idx]
1056
+ if !table
1057
+ raise LoadError, "invalid table index #{idx}"
1058
+ end
1059
+ indices.each_with_index do |eidx, tidx|
1060
+ case typ
1061
+ when :funcref
1062
+ table.set(offset + tidx, @funcs[eidx])
1063
+ when :externref
1064
+ raise NotImplementedError, "no support :externref"
1065
+ end
1066
+ end
1067
+ end
672
1068
  end
673
1069
 
674
1070
  # @rbs idx: Integer
@@ -711,6 +1107,38 @@ module Wardite
711
1107
  end
712
1108
  end
713
1109
 
1110
+ class Table
1111
+ attr_accessor :type #: Symbol
1112
+
1113
+ attr_accessor :current #: Integer
1114
+
1115
+ attr_accessor :max #: Integer|nil
1116
+
1117
+ attr_accessor :refs #: Array[WasmFunction|ExternalFunction|nil]
1118
+
1119
+ # @rbs type: Symbol
1120
+ # @rbs init: Integer
1121
+ # @rbs max: Integer|nil
1122
+ # @rbs return: void
1123
+ def initialize(type, init, max)
1124
+ @type = type
1125
+ @current = init
1126
+ @max = max
1127
+
1128
+ @refs = Array.new(3, nil)
1129
+ end
1130
+
1131
+ # @rbs idx: Integer
1132
+ # @rbs elem: WasmFunction|ExternalFunction|nil
1133
+ # @rbs return: void
1134
+ def set(idx, elem)
1135
+ if idx >= @current
1136
+ raise GenericError, "idx too large for table"
1137
+ end
1138
+ @refs[idx] = elem
1139
+ end
1140
+ end
1141
+
714
1142
  class Global
715
1143
  attr_accessor :type #: Symbol
716
1144
 
@@ -719,7 +1147,7 @@ module Wardite
719
1147
  # TODO: unused in wasm 1.0 spec?
720
1148
  attr_accessor :shared #: bool
721
1149
 
722
- attr_accessor :value #: I32|I64|F32|F64
1150
+ attr_accessor :value #: wasmValue
723
1151
 
724
1152
  # @rbs &blk: (Global) -> void
725
1153
  # @rbs return: void
@@ -829,25 +1257,51 @@ module Wardite
829
1257
  # @rbs return: Array[Integer]
830
1258
  def locals_count
831
1259
  code_body.locals_count
832
- end
1260
+ end
1261
+
1262
+ # @rbs override_type: Type?
1263
+ # @rbs return: WasmFunction
1264
+ def clone(override_type: nil)
1265
+ if override_type
1266
+ # code_body is assumed to be frozen, so we can copy its ref
1267
+ WasmFunction.new(override_type.callsig, override_type.retsig, code_body)
1268
+ else
1269
+ WasmFunction.new(callsig, retsig, code_body)
1270
+ end
1271
+ end
833
1272
  end
834
1273
 
1274
+ # @rbs!
1275
+ # type wasmFuncReturn = Object|nil
1276
+ # type wasmCallable = ^(Store, Array[wasmValue]) -> wasmFuncReturn
1277
+
835
1278
  class ExternalFunction
836
1279
  attr_accessor :callsig #: Array[Symbol]
837
1280
 
838
1281
  attr_accessor :retsig #: Array[Symbol]
839
1282
 
840
- attr_accessor :callable #: Proc
1283
+ attr_accessor :callable #: wasmCallable
841
1284
 
842
1285
  # @rbs callsig: Array[Symbol]
843
1286
  # @rbs retsig: Array[Symbol]
844
- # @rbs callable: Proc
1287
+ # @rbs callable: wasmCallable
845
1288
  # @rbs return: void
846
1289
  def initialize(callsig, retsig, callable)
847
1290
  @callsig = callsig
848
1291
  @retsig = retsig
849
1292
  @callable = callable
850
1293
  end
1294
+
1295
+ # @rbs override_type: Type?
1296
+ # @rbs return: ExternalFunction
1297
+ def clone(override_type: nil)
1298
+ if override_type
1299
+ # callable is assumed to be frozen, so we can copy its ref
1300
+ ExternalFunction.new(override_type.callsig, override_type.retsig, callable)
1301
+ else
1302
+ ExternalFunction.new(callsig, retsig, callable)
1303
+ end
1304
+ end
851
1305
  end
852
1306
 
853
1307
  class GenericError < StandardError; end