wardite 0.5.0 → 0.6.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/wasi.rb CHANGED
@@ -1,16 +1,161 @@
1
1
  # rbs_inline: enabled
2
+
3
+ require "wardite/wasm_module"
4
+ require "wardite/wasi/consts"
5
+ require "securerandom"
6
+ require "fcntl"
7
+
2
8
  module Wardite
3
9
  class WasiSnapshotPreview1
4
10
  include ValueHelper
11
+ include WasmModule
5
12
 
6
- attr_accessor :fd_table #: Array[IO]
13
+ attr_accessor :fd_table #: Array[(IO|File)]
14
+ attr_accessor :argv #: Array[String]
7
15
 
8
- def initialize
16
+ # @rbs argv: Array[String]
17
+ # @rbs return: void
18
+ def initialize(argv: [])
9
19
  @fd_table = [
10
20
  STDIN,
11
21
  STDOUT,
12
22
  STDERR,
13
23
  ]
24
+ @argv = argv
25
+ end
26
+
27
+ # @rbs store: Store
28
+ # @rbs args: Array[wasmValue]
29
+ # @rbs return: Object
30
+ def args_get(store, args)
31
+ arg_offsets_p = args[0].value
32
+ arg_data_buf_p = args[1].value
33
+ if !arg_data_buf_p.is_a?(Integer)
34
+ raise ArgumentError, "invalid type of args: #{args.inspect}"
35
+ end
36
+
37
+ arg_offsets = [] #: Array[Integer]
38
+ arg_data_slice = [] #: Array[String]
39
+ current_offset = arg_data_buf_p
40
+ @argv.each do |arg|
41
+ arg_offsets << current_offset
42
+ arg_data_slice << arg
43
+ current_offset += arg.size + 1
44
+ end
45
+ arg_data = arg_data_slice.join("\0") + "\0"
46
+
47
+ memory = store.memories[0]
48
+ memory.data[arg_data_buf_p...(arg_data_buf_p + arg_data.size)] = arg_data
49
+
50
+ arg_offsets.each_with_index do |offset, i|
51
+ data_begin = arg_offsets_p + i * 4
52
+ memory.data[data_begin...(data_begin + 4)] = [offset].pack("I!")
53
+ end
54
+
55
+ 0
56
+ end
57
+
58
+ # @rbs store: Store
59
+ # @rbs args: Array[wasmValue]
60
+ # @rbs return: Object
61
+ def args_sizes_get(store, args)
62
+ argc_p = args[0].value
63
+ arglen_p = args[1].value
64
+ argc = @argv.length
65
+ arglen = @argv.map{|arg| arg.size + 1}.sum
66
+
67
+ memory = store.memories[0]
68
+ memory.data[argc_p...(argc_p+4)] = [argc].pack("I!")
69
+ memory.data[arglen_p...(arglen_p+4)] = [arglen].pack("I!")
70
+ 0
71
+ end
72
+
73
+ # @rbs store: Store
74
+ # @rbs args: Array[wasmValue]
75
+ # @rbs return: Object
76
+ def environ_sizes_get(store, args)
77
+ envc_p = args[0].value
78
+ envlen_p = args[1].value
79
+ envc = ENV.length
80
+ envlen = ENV.map{|k,v| k.size + v.size + 1}.sum
81
+
82
+ memory = store.memories[0]
83
+ memory.data[envc_p...(envc_p+4)] = [envc].pack("I!")
84
+ memory.data[envlen_p...(envlen_p+4)] = [envlen].pack("I!")
85
+ 0
86
+ end
87
+
88
+ # @rbs store: Store
89
+ # @rbs args: Array[wasmValue]
90
+ # @rbs return: Object
91
+ def environ_get(store, args)
92
+ environ_offsets_p = args[0].value
93
+ environ_data_buf_p = args[1].value
94
+ if !environ_data_buf_p.is_a?(Integer)
95
+ raise ArgumentError, "invalid type of args: #{args.inspect}"
96
+ end
97
+
98
+ environ_offsets = [] #: Array[Integer]
99
+ environ_data_slice = [] #: Array[String]
100
+ current_offset = environ_data_buf_p
101
+ ENV.each do |k, v|
102
+ environ_offsets << current_offset
103
+ environ_data_slice << "#{k}=#{v}"
104
+ current_offset += "#{k}=#{v}".size + 1
105
+ end
106
+ environ_data = environ_data_slice.join("\0") + "\0"
107
+
108
+ memory = store.memories[0]
109
+ memory.data[environ_data_buf_p...(environ_data_buf_p + environ_data.size)] = environ_data
110
+
111
+ environ_offsets.each_with_index do |offset, i|
112
+ data_begin = environ_offsets_p + i * 4
113
+ memory.data[data_begin...(data_begin + 4)] = [offset].pack("I!")
114
+ end
115
+
116
+ 0
117
+ end
118
+
119
+ # @rbs store: Store
120
+ # @rbs args: Array[wasmValue]
121
+ # @rbs return: Object
122
+ def clock_time_get(store, args)
123
+ clock_id = args[0].value
124
+ # we dont use precision...
125
+ _precision = args[1].value
126
+ timebuf64 = args[2].value
127
+ if clock_id != 0 # - CLOCKID_REALTIME
128
+ # raise NotImplementedError, "CLOCKID_REALTIME is an only supported id"
129
+ return -255
130
+ end
131
+ # timestamp in nanoseconds
132
+ now = Time.now.to_i * 1_000_000
133
+
134
+ memory = store.memories[0]
135
+ now_packed = [now].pack("Q!")
136
+ memory.data[timebuf64...(timebuf64+8)] = now_packed
137
+ 0
138
+ end
139
+
140
+ # @rbs store: Store
141
+ # @rbs args: Array[wasmValue]
142
+ # @rbs return: Object
143
+ def fd_prestat_get(store, args)
144
+ fd = args[0].value.to_i
145
+ prestat_offset = args[1].value.to_i
146
+ if fd >= @fd_table.size
147
+ return Wasi::EBADF
148
+ end
149
+ file = @fd_table[fd]
150
+ if !file.is_a?(File)
151
+ return Wasi::EBADF
152
+ end
153
+ name = file.path
154
+ memory = store.memories[0]
155
+ # Zero-value 8-bit tag, and 3-byte zero-value padding
156
+ memory.data[prestat_offset...(prestat_offset+4)] = [0].pack("I!")
157
+ memory.data[(prestat_offset+4)...(prestat_offset+8)] = [name.size].pack("I!")
158
+ 0
14
159
  end
15
160
 
16
161
  # @rbs store: Store
@@ -29,6 +174,7 @@ module Wardite
29
174
  raise Wardite::ArgumentError, "args too short"
30
175
  end
31
176
  file = self.fd_table[fd]
177
+ return Wasi::EBADF if !file
32
178
  memory = store.memories[0]
33
179
  nwritten = 0
34
180
  iovs_len.times do
@@ -45,11 +191,126 @@ module Wardite
45
191
  0
46
192
  end
47
193
 
48
- # @rbs return: Hash[Symbol, wasmCallable]
49
- def to_module
50
- {
51
- fd_write: lambda{|store, args| self.fd_write(store, args) },
52
- }
194
+ # @rbs store: Store
195
+ # @rbs args: Array[wasmValue]
196
+ # @rbs return: Object
197
+ def fd_read(store, args)
198
+ iargs = args.map do |elm|
199
+ if elm.is_a?(I32)
200
+ elm.value
201
+ else
202
+ raise Wardite::ArgumentError, "invalid type of args: #{args.inspect}"
203
+ end
204
+ end #: Array[Integer]
205
+ fd, iovs, iovs_len, rp = *iargs
206
+ if !fd || !iovs || !iovs_len || !rp
207
+ raise Wardite::ArgumentError, "args too short"
208
+ end
209
+ file = self.fd_table[fd]
210
+ return Wasi::EBADF if !file
211
+ memory = store.memories[0]
212
+ nread = 0
213
+
214
+ iovs_len.times do
215
+ start = unpack_le_int(memory.data[iovs...(iovs+4)])
216
+ iovs += 4
217
+ slen = unpack_le_int(memory.data[iovs...(iovs+4)])
218
+ iovs += 4
219
+ buf = file.read(slen)
220
+ if !buf
221
+ return Wasi::EFAULT
222
+ end
223
+ memory.data[start...(start+slen)] = buf
224
+ nread += slen
225
+ end
226
+
227
+ memory.data[rp...(rp+4)] = [nread].pack("I!")
228
+ 0
229
+ end
230
+
231
+ # @rbs store: Store
232
+ # @rbs args: Array[wasmValue]
233
+ # @rbs return: Object
234
+ def fd_fdstat_get(store, args)
235
+ fd = args[0].value.to_i
236
+ fdstat_offset = args[1].value.to_i
237
+ if fd >= @fd_table.size
238
+ return Wasi::EBADF
239
+ end
240
+ file = @fd_table[fd]
241
+ fdflags = 0
242
+ if file.is_a?(IO)
243
+ fdflags |= Wasi::FD_APPEND
244
+ else
245
+ if (Fcntl::O_APPEND & file.fcntl(Fcntl::F_GETFL, 0)) != 0
246
+ fdflags |= Wasi::FD_APPEND
247
+ end
248
+ end
249
+
250
+ if (Fcntl::O_NONBLOCK & file.fcntl(Fcntl::F_GETFL, 0)) != 0
251
+ fdflags |= Wasi::FD_NONBLOCK
252
+ end
253
+
254
+ stat = file.stat #: File::Stat
255
+ ftype = Wasi.to_ftype(stat.ftype)
256
+
257
+ fs_right_base = 0
258
+ fs_right_inheriting = 0
259
+
260
+ case ftype
261
+ when Wasi::FILETYPE_DIRECTORY
262
+ fs_right_base = Wasi::RIGHT_DIR_RIGHT_BASE
263
+ fs_right_inheriting = Wasi::RIGHT_FILE_RIGHT_BASE | Wasi::RIGHT_DIR_RIGHT_BASE
264
+ when Wasi::FILETYPE_CHARACTER_DEVICE
265
+ fs_right_base = Wasi::RIGHT_FILE_RIGHT_BASE & \
266
+ (~Wasi::RIGHT_FD_SEEK) & (~Wasi::RIGHT_FD_TELL)
267
+ else
268
+ fs_right_base = Wasi::RIGHT_FILE_RIGHT_BASE
269
+ end
270
+
271
+ memory = store.memories[0]
272
+
273
+ binformat = [fdflags, ftype, 0, 0, 0, 0, fs_right_base, fs_right_inheriting]
274
+ .pack("SSC4QQ")
275
+ memory.data[fdstat_offset...(fdstat_offset+binformat.size)] = binformat
276
+ 0
277
+ end
278
+
279
+ # @rbs store: Store
280
+ # @rbs args: Array[wasmValue]
281
+ # @rbs return: Object
282
+ def fd_filestat_get(store, args)
283
+ fd = args[0].value.to_i
284
+ filestat_offset = args[1].value.to_i
285
+ if fd >= @fd_table.size
286
+ return Wasi::EBADF
287
+ end
288
+ file = @fd_table[fd]
289
+ stat = file.stat #: File::Stat
290
+ memory = store.memories[0]
291
+ binformat = [stat.dev, stat.ino, Wasi.to_ftype(stat.ftype), stat.nlink, stat.size, stat.atime.to_i, stat.mtime.to_i, stat.ctime.to_i].pack("Q8")
292
+ memory.data[filestat_offset...(filestat_offset+binformat.size)] = binformat
293
+ 0
294
+ end
295
+
296
+ # @rbs store: Store
297
+ # @rbs args: Array[wasmValue]
298
+ # @rbs return: Object
299
+ def proc_exit(store, args)
300
+ exit_code = args[0].value
301
+ exit(exit_code)
302
+ end
303
+
304
+ # @rbs store: Store
305
+ # @rbs args: Array[wasmValue]
306
+ # @rbs return: Object
307
+ def random_get(store, args)
308
+ buf = args[0].value.to_i
309
+ buflen = args[1].value.to_i
310
+ randoms = SecureRandom.random_bytes(buflen) #: String
311
+ memory = store.memories[0]
312
+ memory.data[buf...(buf+buflen)] = randoms
313
+ 0
53
314
  end
54
315
 
55
316
  private
@@ -0,0 +1,53 @@
1
+ # rbs_inline: enabled
2
+
3
+ module Wardite
4
+ # @rbs!
5
+ # interface _WasmCallable
6
+ # def call: (Store, Array[wasmValue]) -> wasmFuncReturn
7
+ # def []: (Store, Array[wasmValue]) -> wasmFuncReturn
8
+ # end
9
+
10
+ # @rbs!
11
+ # type wasmModuleSrc = Hash[Symbol, _WasmCallable] | WasmModule | HashModule
12
+ # type wasmModule = WasmModule | HashModule
13
+
14
+ module WasmModule
15
+ # @rbs fnname: Symbol
16
+ # @rbs store: Store
17
+ # @rbs args: Array[wasmValue]
18
+ # @rbs return: wasmFuncReturn
19
+ def invoke(fnname, store, *args)
20
+ self.__send__(fnname, store, args)
21
+ end
22
+
23
+ # @rbs fnname: Symbol
24
+ # @rbs return: _WasmCallable
25
+ def callable(fnname)
26
+ self.method(fnname)
27
+ end
28
+ end
29
+
30
+ class HashModule
31
+ attr_accessor :hash #: Hash[Symbol, _WasmCallable]
32
+
33
+ # @rbs ha: Hash[Symbol, _WasmCallable]
34
+ def initialize(hash)
35
+ @hash = hash
36
+ end
37
+
38
+ # @rbs fnname: Symbol
39
+ # @rbs store: Store
40
+ # @rbs args: Array[wasmValue]
41
+ # @rbs return: wasmFuncReturn
42
+ def invoke(fnname, store, *args)
43
+ fn = self.hash[fnname.to_sym]
44
+ fn.call(store, args)
45
+ end
46
+
47
+ # @rbs fnname: Symbol
48
+ # @rbs return: _WasmCallable
49
+ def callable(fnname)
50
+ self.hash[fnname.to_sym]
51
+ end
52
+ end
53
+ end
data/lib/wardite.rb CHANGED
@@ -20,8 +20,6 @@ require_relative "wardite/alu_f32.generated"
20
20
  require_relative "wardite/alu_f64.generated"
21
21
  require_relative "wardite/convert.generated"
22
22
 
23
- require_relative "wardite/wasi"
24
-
25
23
  require "stringio"
26
24
 
27
25
  module Wardite
@@ -38,13 +36,23 @@ module Wardite
38
36
 
39
37
  attr_accessor :exports #: Exports
40
38
 
41
- attr_reader :import_object #: Hash[Symbol, Hash[Symbol, wasmCallable]]
39
+ attr_reader :import_object #: Hash[Symbol, wasmModule]
40
+
41
+ attr_accessor :wasi #: WasiSnapshotPreview1?
42
42
 
43
- # @rbs import_object: Hash[Symbol, Hash[Symbol, wasmCallable]]
43
+ # @rbs import_object: Hash[Symbol, wasmModuleSrc]
44
44
  # @rbs &blk: (Instance) -> void
45
45
  def initialize(import_object, &blk)
46
+ @wasi = nil
47
+
46
48
  blk.call(self)
47
- @import_object = import_object
49
+ import_object.each_pair do |k, v|
50
+ if v.is_a?(Hash)
51
+ import_object[k] = HashModule.new(v)
52
+ end
53
+ end
54
+
55
+ @import_object = import_object #: Hash[Symbol, wasmModule]
48
56
 
49
57
  @store = Store.new(self)
50
58
  @exports = Exports.new(self.export_section, store)
@@ -281,7 +289,8 @@ module Wardite
281
289
 
282
290
  case fn
283
291
  when WasmFunction
284
- invoke_internal(fn)
292
+ r = invoke_internal(fn)
293
+ r
285
294
  when ExternalFunction
286
295
  invoke_external(fn)
287
296
  else
@@ -313,25 +322,7 @@ module Wardite
313
322
  raise LoadError, "stack too short"
314
323
  end
315
324
  self.stack = drained_stack(local_start)
316
-
317
- wasm_function.locals_count.each_with_index do |count, i|
318
- typ = wasm_function.locals_type[i]
319
- count.times do
320
- case typ
321
- when :i32, :u32
322
- locals.push I32(0)
323
- when :i64, :u64
324
- locals.push I64(0)
325
- when :f32
326
- locals.push F32(0.0)
327
- when :f64
328
- locals.push F64(0.0)
329
- else
330
- $stderr.puts "warning: unknown type #{typ.inspect}. default to I32"
331
- locals.push I32(0)
332
- end
333
- end
334
- end
325
+ locals.concat(wasm_function.default_locals)
335
326
 
336
327
  arity = wasm_function.retsig.size
337
328
  frame = Frame.new(-1, stack.size, wasm_function.body, arity, locals)
@@ -473,7 +464,7 @@ module Wardite
473
464
  when :block
474
465
  block = insn.operand[0]
475
466
  raise EvalError, "block op without block" if !block.is_a?(Block)
476
- next_pc = fetch_ops_while_end(frame.body, frame.pc)
467
+ next_pc = insn.meta[:end_pos]
477
468
  label = Label.new(:block, next_pc, stack.size, block.result_size)
478
469
  frame.labels.push(label)
479
470
 
@@ -481,19 +472,19 @@ module Wardite
481
472
  block = insn.operand[0]
482
473
  raise EvalError, "loop op without block" if !block.is_a?(Block)
483
474
  start = frame.pc
484
- end_pc = fetch_ops_while_end(frame.body, frame.pc)
485
- label = Label.new(:loop, end_pc, stack.size, block.result_size, start)
475
+ next_pc = insn.meta[:end_pos]
476
+ label = Label.new(:loop, next_pc, stack.size, block.result_size, start)
486
477
  frame.labels.push(label)
487
478
 
488
479
  when :if
489
480
  block = insn.operand[0]
490
481
  raise EvalError, "if op without block" if !block.is_a?(Block)
491
- cond = stack.pop
482
+ cond = stack.pop
492
483
  raise EvalError, "cond not found" if !cond.is_a?(I32)
493
- next_pc = fetch_ops_while_end(frame.body, frame.pc)
484
+ next_pc = insn.meta[:end_pos]
494
485
 
495
486
  if cond.value.zero?
496
- frame.pc = fetch_ops_while_else_or_end(frame.body, frame.pc)
487
+ frame.pc = insn.meta[:else_pos]
497
488
  end
498
489
 
499
490
  if frame.pc == next_pc
@@ -740,38 +731,6 @@ module Wardite
740
731
  raise e
741
732
  end
742
733
 
743
- # @rbs ops: Array[Op]
744
- # @rbs pc_start: Integer
745
- # @rbs return: Integer
746
- def fetch_ops_while_else_or_end(ops, pc_start)
747
- cursor = pc_start
748
- depth = 0
749
- loop {
750
- cursor += 1
751
- inst = ops[cursor]
752
- case inst&.code
753
- when nil
754
- raise EvalError, "end op not found"
755
- when :if
756
- depth += 1
757
- when :else
758
- if depth == 0
759
- return cursor
760
- end
761
- # do not touch depth
762
- when :end
763
- if depth == 0
764
- return cursor
765
- else
766
- depth -= 1
767
- end
768
- else
769
- # nop
770
- end
771
- }
772
- raise "[BUG] unreachable"
773
- end
774
-
775
734
  # @rbs labels: Array[Label]
776
735
  # @rbs stack: Array[wasmValue]
777
736
  # @rbs level: Integer
@@ -797,33 +756,6 @@ module Wardite
797
756
  pc
798
757
  end
799
758
 
800
- # @rbs ops: Array[Op]
801
- # @rbs pc_start: Integer
802
- # @rbs return: Integer
803
- def fetch_ops_while_end(ops, pc_start)
804
- cursor = pc_start
805
- depth = 0
806
- loop {
807
- cursor += 1
808
- inst = ops[cursor]
809
- case inst&.code
810
- when nil
811
- raise EvalError, "end op not found"
812
- when :if, :block, :loop
813
- depth += 1
814
- when :end
815
- if depth == 0
816
- return cursor
817
- else
818
- depth -= 1
819
- end
820
- else
821
- # nop
822
- end
823
- }
824
- raise "[BUG] unreachable"
825
- end
826
-
827
759
  # unwind the stack and put return value if exists
828
760
  # @rbs sp: Integer
829
761
  # @rbs arity: Integer
@@ -947,7 +879,7 @@ module Wardite
947
879
  class Store
948
880
  attr_accessor :funcs #: Array[WasmFunction|ExternalFunction]
949
881
 
950
- # FIXME: attr_accessor :modules
882
+ attr_accessor :modules #: Hash[Symbol, wasmModule]
951
883
 
952
884
  attr_accessor :memories #: Array[Memory]
953
885
 
@@ -966,21 +898,19 @@ module Wardite
966
898
 
967
899
  import_section = inst.import_section
968
900
  @funcs = []
901
+ @modules = inst.import_object
969
902
 
970
903
  if type_section && func_section && code_section
971
904
  import_section.imports.each do |desc|
972
905
  callsig = type_section.defined_types[desc.sig_index]
973
906
  retsig = type_section.defined_results[desc.sig_index]
974
- imported_module = inst.import_object[desc.module_name.to_sym]
975
- if !imported_module
907
+ target_module = self.modules[desc.module_name.to_sym]
908
+ if target_module.nil?
976
909
  raise ::NameError, "module #{desc.module_name} not found"
977
910
  end
978
- imported_proc = imported_module[desc.name.to_sym]
979
- if !imported_proc
980
- raise ::NameError, "function #{desc.module_name}.#{desc.name} not found"
981
- end
911
+ target_name = desc.name.to_sym
982
912
 
983
- ext_function = ExternalFunction.new(callsig, retsig, imported_proc)
913
+ ext_function = ExternalFunction.new(target_module, target_name, callsig, retsig)
984
914
  self.funcs << ext_function
985
915
  end
986
916
 
@@ -1272,7 +1202,10 @@ module Wardite
1272
1202
  end
1273
1203
 
1274
1204
  # TODO: common interface btw. WasmFunction and ExternalFunction?
1205
+ # may be _WasmCallable?
1275
1206
  class WasmFunction
1207
+ include ValueHelper
1208
+
1276
1209
  attr_accessor :callsig #: Array[Symbol]
1277
1210
 
1278
1211
  attr_accessor :retsig #: Array[Symbol]
@@ -1281,6 +1214,8 @@ module Wardite
1281
1214
 
1282
1215
  attr_accessor :findex #: Integer
1283
1216
 
1217
+ attr_accessor :default_locals #: Array[wasmValue]
1218
+
1284
1219
  # @rbs callsig: Array[Symbol]
1285
1220
  # @rbs retsig: Array[Symbol]
1286
1221
  # @rbs code_body: CodeSection::CodeBody
@@ -1291,6 +1226,7 @@ module Wardite
1291
1226
 
1292
1227
  @code_body = code_body
1293
1228
  @findex = 0 # for debug
1229
+ @default_locals = construct_default_locals
1294
1230
  end
1295
1231
 
1296
1232
  # @rbs return: Array[Op]
@@ -1308,6 +1244,30 @@ module Wardite
1308
1244
  code_body.locals_count
1309
1245
  end
1310
1246
 
1247
+ # @rbs return: Array[wasmValue]
1248
+ def construct_default_locals
1249
+ locals = [] #: Array[wasmValue]
1250
+ locals_count.each_with_index do |count, i|
1251
+ typ = locals_type[i]
1252
+ count.times do
1253
+ case typ
1254
+ when :i32, :u32
1255
+ locals.push I32(0)
1256
+ when :i64, :u64
1257
+ locals.push I64(0)
1258
+ when :f32
1259
+ locals.push F32(0.0)
1260
+ when :f64
1261
+ locals.push F64(0.0)
1262
+ else
1263
+ $stderr.puts "warning: unknown type #{typ.inspect}. default to I32"
1264
+ locals.push I32(0)
1265
+ end
1266
+ end
1267
+ end
1268
+ locals
1269
+ end
1270
+
1311
1271
  # @rbs override_type: Type?
1312
1272
  # @rbs return: WasmFunction
1313
1273
  def clone(override_type: nil)
@@ -1322,23 +1282,32 @@ module Wardite
1322
1282
 
1323
1283
  # @rbs!
1324
1284
  # type wasmFuncReturn = Object|nil
1325
- # type wasmCallable = ^(Store, Array[wasmValue]) -> wasmFuncReturn
1326
1285
 
1327
1286
  class ExternalFunction
1287
+ attr_accessor :target_module #: wasmModule
1288
+
1289
+ attr_accessor :name #: Symbol
1290
+
1328
1291
  attr_accessor :callsig #: Array[Symbol]
1329
1292
 
1330
1293
  attr_accessor :retsig #: Array[Symbol]
1331
1294
 
1332
- attr_accessor :callable #: wasmCallable
1295
+ #attr_accessor :callable #: _WasmCallable
1333
1296
 
1334
1297
  # @rbs callsig: Array[Symbol]
1335
1298
  # @rbs retsig: Array[Symbol]
1336
- # @rbs callable: wasmCallable
1299
+ # @rbs callable: _WasmCallable
1337
1300
  # @rbs return: void
1338
- def initialize(callsig, retsig, callable)
1301
+ def initialize(target_module, name, callsig, retsig)
1302
+ @target_module = target_module
1303
+ @name = name
1339
1304
  @callsig = callsig
1340
1305
  @retsig = retsig
1341
- @callable = callable
1306
+ end
1307
+
1308
+ # @rbs return: _WasmCallable
1309
+ def callable()
1310
+ target_module.callable(self.name)
1342
1311
  end
1343
1312
 
1344
1313
  # @rbs override_type: Type?
@@ -1346,9 +1315,9 @@ module Wardite
1346
1315
  def clone(override_type: nil)
1347
1316
  if override_type
1348
1317
  # callable is assumed to be frozen, so we can copy its ref
1349
- ExternalFunction.new(override_type.callsig, override_type.retsig, callable)
1318
+ ExternalFunction.new(target_module, name, override_type.callsig, override_type.retsig)
1350
1319
  else
1351
- ExternalFunction.new(callsig, retsig, callable)
1320
+ ExternalFunction.new(target_module, name, callsig, retsig)
1352
1321
  end
1353
1322
  end
1354
1323
  end