wardite 0.2.2 → 0.4.0

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.
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