rlang 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +10 -0
  3. data/.rake_tasks~ +0 -0
  4. data/.travis.yml +7 -0
  5. data/CODE_OF_CONDUCT.md +74 -0
  6. data/Gemfile +4 -0
  7. data/LICENSE +373 -0
  8. data/README.md +61 -0
  9. data/Rakefile +10 -0
  10. data/bin/rlang +164 -0
  11. data/docs/RlangCompiler.md +37 -0
  12. data/docs/RlangManual.md +391 -0
  13. data/lib/builder/ext/tempfile.rb +7 -0
  14. data/lib/builder/ext.rb +5 -0
  15. data/lib/builder/rlang/builder.rb +31 -0
  16. data/lib/builder/rlang.rb +2 -0
  17. data/lib/builder/wat/builder.rb +52 -0
  18. data/lib/builder/wat/renderer.rb +28 -0
  19. data/lib/builder/wat.rb +3 -0
  20. data/lib/builder.rb +7 -0
  21. data/lib/rlang/lib/malloc.c +97 -0
  22. data/lib/rlang/lib/malloc.rb +169 -0
  23. data/lib/rlang/lib/memory.rb +11 -0
  24. data/lib/rlang/lib/type/i32.rb +7 -0
  25. data/lib/rlang/lib/type/i64.rb +7 -0
  26. data/lib/rlang/lib/type.rb +6 -0
  27. data/lib/rlang/lib/unistd.rb +47 -0
  28. data/lib/rlang/lib.rb +10 -0
  29. data/lib/rlang/parser/const.rb +15 -0
  30. data/lib/rlang/parser/cvar.rb +44 -0
  31. data/lib/rlang/parser/data.rb +105 -0
  32. data/lib/rlang/parser/export.rb +22 -0
  33. data/lib/rlang/parser/ext/integer.rb +5 -0
  34. data/lib/rlang/parser/ext/string.rb +5 -0
  35. data/lib/rlang/parser/ext/type.rb +64 -0
  36. data/lib/rlang/parser/global.rb +65 -0
  37. data/lib/rlang/parser/lvar.rb +29 -0
  38. data/lib/rlang/parser/marg.rb +30 -0
  39. data/lib/rlang/parser/method.rb +76 -0
  40. data/lib/rlang/parser/wattr.rb +65 -0
  41. data/lib/rlang/parser/wgenerator.rb +509 -0
  42. data/lib/rlang/parser/winstruction.rb +148 -0
  43. data/lib/rlang/parser/wnode.rb +455 -0
  44. data/lib/rlang/parser/wtree.rb +19 -0
  45. data/lib/rlang/parser/wtype.rb +116 -0
  46. data/lib/rlang/parser.rb +1842 -0
  47. data/lib/rlang/version.rb +3 -0
  48. data/lib/rlang.rb +4 -0
  49. data/lib/simul/classes/data.rb +80 -0
  50. data/lib/simul/classes/global.rb +38 -0
  51. data/lib/simul/classes/memory.rb +131 -0
  52. data/lib/utils/log.rb +32 -0
  53. data/rlang.gemspec +38 -0
  54. metadata +158 -0
@@ -0,0 +1,509 @@
1
+ # Rubinius WebAssembly VM
2
+ # Copyright (c) 2019, Laurent Julliard and contributors
3
+ # All rights reserved.
4
+
5
+ # WAT generator for Rlang
6
+ # Rlang is a subset of the Ruby language that can be transpiled
7
+ # to WAT and then compiled to WASM. The Rubinius WASM virtual
8
+ # machine is written in Rlang.
9
+
10
+ # TODO: write a short documentation about what subset of Ruby is
11
+ # supported in Rlang
12
+
13
+ require_relative '../../utils/log'
14
+ require_relative './wnode'
15
+
16
+ module Rlang::Parser
17
+
18
+ ARITHMETIC_OPS_MAP = {
19
+ :+ => :add,
20
+ :- => :sub,
21
+ :* => :mul,
22
+ :/ => :div_u,
23
+ :% => :rem_u,
24
+ :& => :and,
25
+ :| => :or,
26
+ :^ => :xor,
27
+ :>> => :shr_u,
28
+ :<< => :shl
29
+ }
30
+
31
+ RELATIONAL_OPS_MAP = {
32
+ :== => :eq,
33
+ :!= => :ne,
34
+ :'<s' => :lt_s,
35
+ :< => :lt_u,
36
+ :'>s' => :gt_s,
37
+ :> => :gt_u,
38
+ :'<=s' => :le_s,
39
+ :<= => :le_u,
40
+ :'>=s' => :ge_s,
41
+ :>= => :ge_u
42
+ }
43
+
44
+ BOOLEAN_OPS_MAP = {
45
+ :and => :and,
46
+ :or => :or
47
+ }
48
+
49
+ UNARY_OPS_MAP = {
50
+ :'!' => :eqz
51
+ }
52
+
53
+ # Matrix of how to cast a WASM type to another
54
+ CAST_OPS = {
55
+ I32: { I32: :cast_nope, I64: :cast_extend, F32: :cast_notyet, F64: :cast_notyet, Class: :cast_wtype, none: :cast_error},
56
+ I64: { I32: :cast_wrap, I64: :cast_nope, F32: :cast_notyet, F64: :cast_notyet, Class: :cast_error, none: :cast_error},
57
+ F32: { I32: :cast_notyet, I64: :cast_notyet, F32: :cast_nope, F64: :cast_notyet, Class: :cast_error, none: :cast_error},
58
+ F64: { I32: :cast_notyet, I64: :cast_notyet, F32: :cast_notyet, F64: :cast_nope, Class: :cast_error, none: :cast_error},
59
+ Class: { I32: :cast_wtype, I64: :cast_extend, F32: :cast_error, F64: :cast_error, Class: :cast_wtype, none: :cast_error},
60
+ none: { I32: :cast_error, I64: :cast_error, F32: :cast_error, F64: :cast_error, Class: :cast_error, none: :cast_error},
61
+ }
62
+
63
+ # Generate the wasm nodes and tree structure
64
+ # ***IMPORTANT NOTE***
65
+ # Unless otherwise stated all methods receive
66
+ # the parent wnode as their first argument
67
+ # and must generate child nodes of this parent
68
+ class WGenerator
69
+ include Log
70
+ attr_accessor :parser
71
+ attr_reader :root
72
+
73
+ def initialize(parser)
74
+ @parser = parser
75
+ @root = WTree.new().root
76
+ @new_count = 0
77
+ end
78
+
79
+ def klass(wnode, klass_name)
80
+ # First see if that class already exist
81
+ # If not create it.
82
+ unless (cwn = wnode.find_class(klass_name))
83
+ cwn = WNode.new(:class, wnode)
84
+ cwn.class_name = klass_name
85
+ cwn.wtype = WType.new(cwn.class_name)
86
+ WNode.root.class_wnodes << cwn
87
+ end
88
+ cwn
89
+ end
90
+
91
+ def attributes(wnode)
92
+ wnc = wnode.class_wnode
93
+ return if wnc.wattrs.empty?
94
+ # Process each declared attribute
95
+ offset = 0
96
+ wnc.wattrs.each do |wa|
97
+ logger.debug("Generating accessors for attribute #{wa}")
98
+ # Generate getter and setter methods wnode
99
+ wattr_setter(wnc, wa, offset)
100
+ wattr_getter(wnc, wa, offset)
101
+ # Update offset
102
+ offset += wa.wtype.size
103
+ end
104
+
105
+ # Also generate the Class::size method
106
+ size_method = wnc.create_method(:size, nil, WType::DEFAULT, :class)
107
+ wns = WNode.new(:insn, wnc, true)
108
+ wns.wtype = WType::DEFAULT
109
+ wns.c(:class_size, func_name: size_method.wasm_name,
110
+ wtype: wns.wasm_type, size: wnc.class_size)
111
+ end
112
+
113
+ # Generate attribute setter method wnode
114
+ def wattr_setter(wnode, wattr, offset)
115
+ wnc = wnode.class_wnode
116
+ wn_set = WNode.new(:insn, wnc, true)
117
+ wn_set.c(:wattr_writer, func_name: wattr.setter.wasm_name,
118
+ wattr_name: wattr.wasm_name, wtype: wattr.wasm_type,
119
+ offset: offset)
120
+ wn_set
121
+ end
122
+
123
+ # Generate attribute getter method wnode
124
+ def wattr_getter(wnode, wattr, offset)
125
+ wnc = wnode.class_wnode
126
+ wn_get = WNode.new(:insn, wnc, true)
127
+ wn_get.c(:wattr_reader, func_name: wattr.getter.wasm_name,
128
+ wattr_name: wattr.wasm_name, wtype: wattr.wasm_type,
129
+ offset: offset)
130
+ wn_get
131
+ end
132
+
133
+ def instance_method(wnode, method)
134
+ logger.debug("Generating wnode for instance method #{method.inspect}")
135
+ wn = WNode.new(:method, wnode)
136
+ wn.method = method # must be set before calling func_name
137
+ wn.wtype = method.wtype
138
+ wn.c(:func, func_name: wn.method.wasm_name)
139
+ # Also declare a "hidden" parameter representing the
140
+ # pointer to the instance (always default wtype)
141
+ wn.create_marg(:_self_)
142
+ logger.debug("MEthod built: #{wn.method.inspect}")
143
+ wn
144
+ end
145
+
146
+ def class_method(wnode, method)
147
+ logger.debug("Generating wnode for class method #{method}")
148
+ wn = WNode.new(:method, wnode)
149
+ wn.method = method # must be set before calling func_name
150
+ wn.wtype = method.wtype
151
+ wn.c(:func, func_name: wn.method.wasm_name)
152
+ logger.debug("Building method: wn.wtype #{wn.wtype}, wn.method #{wn.method}")
153
+ wn
154
+ end
155
+
156
+ def params(wnode)
157
+ wnode = wnode.method_wnode
158
+ # use reverse to preserve proper param order
159
+ wnode.margs.reverse.each do |marg|
160
+ logger.debug("Prepending param #{marg}")
161
+ wn = WNode.new(:insn, wnode, true)
162
+ wn.wtype = marg.wtype
163
+ wn.c(:param, name: marg.wasm_name)
164
+ end
165
+ end
166
+
167
+ def result(wnode)
168
+ unless wnode.wtype.blank?
169
+ wn = WNode.new(:insn, wnode, true)
170
+ wn.wtype = wnode.wtype
171
+ wn.c(:result)
172
+ end
173
+ end
174
+
175
+ def locals(wnode)
176
+ wnode = wnode.method_wnode
177
+ wnode.lvars.reverse.each do |lvar|
178
+ logger.debug("Prepending local #{lvar.inspect}")
179
+ wn = WNode.new(:insn, wnode, true)
180
+ wn.wtype = lvar.wtype
181
+ wn.c(:local, name: lvar.wasm_name)
182
+ end
183
+ end
184
+
185
+ def inline(wnode, code, wtype=Type::I32)
186
+ wn = WNode.new(:insn, wnode)
187
+ wn.wtype = wnode.wtype
188
+ wn.c(:inline, code: code)
189
+ wn
190
+ end
191
+
192
+ # Constant assignment doesn't generate any code
193
+ # A Data object is instantiated and initialized
194
+ # when the Const object is created in parser
195
+ def casgn(wnode, const)
196
+ end
197
+
198
+ # Read class variable
199
+ def const(wnode, const)
200
+ (wn = WNode.new(:insn, wnode)).wtype = const.wtype
201
+ wn.c(:load, wtype: const.wtype, var_name: const.wasm_name)
202
+ WNode.new(:insn, wn).c(:addr, value: const.address)
203
+ wn
204
+ end
205
+
206
+ # Global variable assignment
207
+ def gvasgn(wnode, gvar)
208
+ (wn = WNode.new(:insn, wnode)).wtype = gvar.wtype
209
+ wn.c(:global_set, var_name: gvar.name)
210
+ wn
211
+ end
212
+
213
+ # Global variable read
214
+ def gvar(wnode, gvar)
215
+ (wn = WNode.new(:insn, wnode)).wtype = gvar.wtype
216
+ wn.c(:global_get, var_name: gvar.name)
217
+ wn
218
+ end
219
+
220
+ # Create the class variable storage node and
221
+ # an empty expression node to populate later
222
+ def cvasgn(wnode, cvar)
223
+ (wn = WNode.new(:insn, wnode)).wtype = cvar.wtype
224
+ wn.c(:store, wtype: cvar.wtype)
225
+ WNode.new(:insn, wn).c(:addr, value: cvar.address)
226
+ wn
227
+ end
228
+
229
+ # Read class variable
230
+ def cvar(wnode, cvar)
231
+ (wn = WNode.new(:insn, wnode)).wtype = cvar.wtype
232
+ wn.c(:load, wtype: cvar.wtype, var_name: cvar.wasm_name)
233
+ WNode.new(:insn, wn).c(:addr, value: cvar.address)
234
+ wn
235
+ end
236
+
237
+ # Create the local variable storage node
238
+ def lvasgn(wnode, lvar)
239
+ (wn = WNode.new(:insn, wnode)).wtype = lvar.wtype
240
+ wn.c(:local_set, wtype: lvar.wtype, var_name: lvar.wasm_name)
241
+ wn
242
+ end
243
+
244
+ # Read local variable
245
+ def lvar(wnode, lvar)
246
+ (wn = WNode.new(:insn, wnode)).wtype = lvar.wtype
247
+ wn.c(:local_get, wtype: lvar.wtype, var_name: lvar.wasm_name)
248
+ wn
249
+ end
250
+
251
+ def drop(wnode)
252
+ logger.debug "dropping result of #{wnode}, caller: #{caller_locations}"
253
+ (wn = WNode.new(:insn, wnode)).c(:drop)
254
+ wn
255
+ end
256
+
257
+ def nop(wnode)
258
+ (wn = WNode.new(:insn, wnode)).c(:nop)
259
+ wn
260
+ end
261
+
262
+ def int(wnode, wtype, value)
263
+ (wn = WNode.new(:insn, wnode)).wtype = wtype
264
+ wn.c(:const, wtype: wtype, value: value)
265
+ wn
266
+ end
267
+
268
+ def float(wnode, wtype, value)
269
+ (wn = WNode.new(:insn, wnode)).wtype = wtype
270
+ wn.c(:const, wtype: wtype, value: value)
271
+ wn
272
+ end
273
+
274
+ # All the cast_xxxx methods below returns
275
+ # the new wnode doing the cast operation
276
+ # or the same wnode if there is no additional code
277
+ # for the cast operation
278
+ def cast_nope(wnode, wtype, signed)
279
+ # Do nothing
280
+ wnode
281
+ end
282
+
283
+ def cast_extend(wnode, wtype, signed)
284
+ if (wnode.template == :const)
285
+ # it's a WASM const, simply change the wtype
286
+ wnode.wtype = wtype
287
+ wn_cast_op = wnode
288
+ else
289
+ wn_cast_op = wnode.insert(:insn)
290
+ wn_cast_op.wtype = wtype
291
+ wn_cast_op.c(signed ? :extend_i32_s : :extend_i32_u , wtype: wtype)
292
+ end
293
+ wn_cast_op
294
+ end
295
+
296
+ def cast_wtype(wnode, wtype, signed)
297
+ if (wnode.wtype.default? && wtype.class?) ||
298
+ (wnode.wtype.class? && wtype.default?) ||
299
+ (wnode.wtype.class? && wtype.class?)
300
+ wnode.wtype = wtype
301
+ else
302
+ cast_error(wnode, wtype, signed)
303
+ end
304
+ wnode
305
+ end
306
+
307
+ def cast_wrap(wnode, wtype, signed)
308
+ if (wnode.template == :const)
309
+ # it's a WASM const, simply change the wtype
310
+ wnode.wtype = wtype
311
+ wn_cast_op = wnode
312
+ else
313
+ wn_cast_op = wnode.insert(:insn)
314
+ wn_cast_op.wtype = wtype
315
+ wn_cast_op.c(:wrap_i64, wtype: wtype)
316
+ end
317
+ wn_cast_op
318
+ end
319
+
320
+ def cast_notyet(wnode, wtype, signed)
321
+ raise "Type cast from #{wnode.wtype} to #{wtype} not supported yet"
322
+ end
323
+
324
+ def cast_error(wnode, wtype, signed)
325
+ raise "Cannot cast type #{src} to #{dest}. Time to fix your code :-)"
326
+ end
327
+
328
+ # cast an expression to a different type
329
+ # if same type do nothing
330
+ # - wnode: the wnode to type cast
331
+ # - wtype: the wtype to cast wnode to
332
+ # - signed: whether the cast wnode must be interpreted as a signed value
333
+ #
334
+ # TODO: simplify this complex method (possibly by using
335
+ # a conversion table source type -> destination type)
336
+ def cast(wnode, wtype, signed=false)
337
+ logger.debug "wnode: #{wnode}, wtype: #{wtype}"
338
+ src_type = (wnode.wtype.native? ? wnode.wtype.name : :Class)
339
+ dest_type = (wtype.native? ? wtype.name : :Class)
340
+ cast_method = CAST_OPS[src_type] && CAST_OPS[src_type][dest_type] || :cast_error
341
+
342
+ wn_cast_op = self.send(cast_method, wnode, wtype, signed)
343
+ logger.debug "After type cast: wnode: #{wn_cast_op}, wtype: #{wtype}"
344
+ wn_cast_op
345
+ end
346
+
347
+ # just create a wnode for the WASM operator
348
+ # Do not set wtype or a code template yet,
349
+ # wait until operands type is known (see
350
+ # operands below)
351
+ def operator(wnode, operator, wtype=WType.new(:none))
352
+ if (op = (ARITHMETIC_OPS_MAP[operator] ||
353
+ RELATIONAL_OPS_MAP[operator] ||
354
+ BOOLEAN_OPS_MAP[operator] ||
355
+ UNARY_OPS_MAP[operator] ))
356
+ (wn_op = WNode.new(:insn, wnode)).c(:operator, operator: op)
357
+ wn_op.wtype = wtype
358
+ wn_op
359
+ else
360
+ raise "operator '#{operator}' not supported"
361
+ end
362
+ end
363
+
364
+ # finish the setting of the operator node and
365
+ # attach operands
366
+ def operands(wnode_op, wnode_recv, wnode_args)
367
+ raise "only 0 or 1 operand expected (got #{wnode_args.count})" if wnode_args.count > 1
368
+ op = wnode_op.wargs[:operator]
369
+ # First find out the wtype that has precedence
370
+ wtype = self.class.leading_wtype(wnode_recv, *wnode_args)
371
+
372
+ wnode_op.wtype = wtype
373
+ logger.debug "leading type cast: #{wtype}"
374
+
375
+ # Attach receiver and argument to the operator wnode
376
+ # type casting them if necessary
377
+ self.cast(wnode_recv, wtype).reparent_to(wnode_op)
378
+ self.cast(wnode_args.first, wtype).reparent_to(wnode_op) unless wnode_args.empty?
379
+
380
+ # if the receiver is a class object and not
381
+ # a native integer then pointer arithmetic
382
+ # applies (like in C)
383
+ if wnode_recv.wtype.class?
384
+ legal_ops = RELATIONAL_OPS_MAP.values + [:add, :sub]
385
+ raise "Only #{legal_ops.join(', ')} operators are supported on objects (got #{op} in #{wnode_op})" \
386
+ unless legal_ops.include?(op)
387
+ # if + or - operator then multiply arg by size of object
388
+ if [:add, :sub].include? wnode_op.wargs[:operator]
389
+ (wn_mulop = WNode.new(:insn, wnode_op)).c(:operator, operator: :mul)
390
+ WNode.new(:insn, wn_mulop).c(:const,
391
+ value: lambda { wnode_recv.find_class(wnode_recv.wtype.name).class_size })
392
+ wnode_args.first.reparent_to(wn_mulop)
393
+ else
394
+ # It's a relational operator. In this case
395
+ # the type of the operator node is always the
396
+ # default type because a comparison between
397
+ # object pointers gives a boolean (0 or 1)
398
+ wnode_op.wtype = WType::DEFAULT
399
+ end
400
+ end
401
+ wnode_op
402
+ end
403
+
404
+ # Statically allocate an object in data segment
405
+ # with the size of the class
406
+ def new(wnode, class_name)
407
+ class_wnode = wnode.find_class(class_name)
408
+ if class_wnode.class_size > 0
409
+ data_label = "#{class_name}_new_#{@new_count += 1}"
410
+ data = DAta.new(data_label.to_sym, "\x00"*class_wnode.class_size)
411
+ address = data.address
412
+ else
413
+ # TODO: point to address 0. It is not safe but normally
414
+ # this class is without attribute so the code will never
415
+ # use memory address to access attribute
416
+ address = 0
417
+ end
418
+ (wn_object_addr = WNode.new(:insn, wnode)).c(:addr, value: address)
419
+ # VERY IMPORTANT the wtype of this node is the Class name !!!
420
+ wn_object_addr.wtype = WType.new(class_name.to_sym)
421
+ wn_object_addr
422
+ end
423
+
424
+ def call(wnode, class_name, method_name, method_type)
425
+ method = wnode.find_or_create_method(method_name, class_name, method_type)
426
+ logger.debug "found method #{method.inspect}"
427
+ (wn_call = WNode.new(:insn, wnode)).c(:call, func_name: method.wasm_name)
428
+ wn_call.wtype = method.wtype
429
+ wn_call
430
+ end
431
+
432
+ # self in an instance context is passed as the first argument
433
+ # of a method call
434
+ def _self(wnode)
435
+ (wns = WNode.new(:insn, wnode)).c(:local_get, var_name: '$_self_')
436
+ wns.wtype = WType.new(wnode.class_name)
437
+ wns
438
+ end
439
+
440
+ def return(wnode)
441
+ (wn = WNode.new(:insn, wnode)).c(:return)
442
+ wn
443
+ end
444
+
445
+ def if(wnode)
446
+ (wn = WNode.new(:insn, wnode)).c(:if)
447
+ wn
448
+ end
449
+
450
+ def then(wnode)
451
+ (wn = WNode.new(:insn, wnode)).c(:then)
452
+ wn
453
+ end
454
+
455
+ def else(wnode)
456
+ (wn = WNode.new(:insn, wnode)).c(:else)
457
+ wn
458
+ end
459
+
460
+ def while(wnode)
461
+ (wnb = WNode.new(:insn, wnode)).c(:block)
462
+ (wnl = WNode.new(:insn, wnb)).c(:loop)
463
+ (wnbi = WNode.new(:insn, wnl)).c(:br_if, label: wnb.label)
464
+ return wnb,wnbi,wnl
465
+ end
466
+
467
+ # This is a post processing of the while
468
+ # exp wnode because br_if requires to
469
+ # negate the original while condition
470
+ def while_cond(wnode, wnode_cond_exp)
471
+ wn_eqz = WNode.new(:insn, wnode)
472
+ wn_eqz.c(:eqz, wtype: wnode_cond_exp.wtype)
473
+ wnode_cond_exp.reparent_to(wn_eqz)
474
+ wn_eqz
475
+ end
476
+
477
+ # add the unconditional looping branch at
478
+ # the end of the while
479
+ def while_end(wnode)
480
+ (wnwe = WNode.new(:insn, wnode)).c(:br, label: wnode.label)
481
+ wnwe
482
+ end
483
+
484
+ def break(wnode)
485
+ # look for block wnode upper in the tree
486
+ # and branch to that label
487
+ (wn = WNode.new(:insn, wnode)).c(:br, label: wnode.block_wnode.label)
488
+ wn
489
+ end
490
+
491
+ def next(wnode)
492
+ # look for loop wnode upper in the tree
493
+ # branch to that label
494
+ (wn = WNode.new(:insn, wnode)).c(:br, label: wnode.loop_wnode.label)
495
+ wn
496
+ end
497
+
498
+ private
499
+ # Determine which wasm type has precedence among
500
+ # all wnodes
501
+ def self.leading_wtype(*wnodes)
502
+ begin
503
+ WType.leading(wnodes.map(&:wtype))
504
+ rescue
505
+ raise "#{wnodes.map(&:to_s)}"
506
+ end
507
+ end
508
+ end
509
+ end
@@ -0,0 +1,148 @@
1
+ # Rubinius WebAssembly VM
2
+ # Copyright (c) 2019, Laurent Julliard and contributors
3
+ # All rights reserved.
4
+ #
5
+ # WASM instructions data
6
+
7
+ module Rlang::Parser
8
+
9
+ class WInstruction
10
+ @@instructions = {}
11
+
12
+ attr_reader :insn, :stk_ins, :stk_outs
13
+
14
+ # inputs and outputs are respectively what an
15
+ # instruction pops from the stack and what it
16
+ # pushes back as a result
17
+ def initialize(insn, stk_ins, stk_outs)
18
+ @insn = insn
19
+ @stk_ins = stk_ins
20
+ @stk_outs = stk_outs
21
+ @@instructions[insn] = self
22
+ end
23
+
24
+ def self.load(insn_data)
25
+ insn_data.each { |elt| WInstruction.new(*elt) }
26
+ end
27
+ end
28
+
29
+ WInstruction.load(
30
+ [
31
+ ['unreachable', [:any], [:any]],
32
+ ['nop', [], []],
33
+ ['block', [], [:any]],
34
+ ['loop', [], [:any]],
35
+ ['if', [:I32], [:any]],
36
+ ['then', [], [:any]],
37
+ ['else', [], [:any]],
38
+ ['br', [], []],
39
+ ['br_if', [:I32], []],
40
+ ['br_table', [:I32], []],
41
+ ['return', [], [:any]],
42
+ ['call', [:any], [:any]],
43
+ ['call_indirect', [:any, :I32], [:any]],
44
+ ['drop', [:any], []],
45
+ ['select', [:one, :one, :I32], []],
46
+ ['func', [], []],
47
+ ['param', [], []],
48
+ ['result', [], []],
49
+ ['i32.load', [:I32], [:I32]],
50
+ ['i64.load', [:I32], [:I64]],
51
+ ['i32.load8_s', [:I32], [:I32]],
52
+ ['i32.load8_u', [:I32], [:I32]],
53
+ ['i32.load16_s', [:I32], [:I32]],
54
+ ['i32.load16_u', [:I32], [:I32]],
55
+ ['i64.load8_s', [:I32], [:I64]],
56
+ ['i64.load8_u', [:I32], [:I64]],
57
+ ['i64.load16_s', [:I32], [:I64]],
58
+ ['i64.load16_u', [:I32], [:I64]],
59
+ ['i64.load32_s', [:I32], [:I64]],
60
+ ['i64.load32_u', [:I32], [:I64]],
61
+ ['i32.store', [:I32, :I32], []],
62
+ ['i64.store', [:I32, :I64], []],
63
+ ['i32.store8', [:I32, :I32], []],
64
+ ['i32.store16', [:I32, :I32], []],
65
+ ['i64.store8', [:I32, :I64], []],
66
+ ['i64.store16', [:I32, :I64], []],
67
+ ['i64.store32', [:I32, :I64], []],
68
+ ['memory.size', [], [:I32]],
69
+ ['memory.grow', [:I32], [:I32]],
70
+ ['i32.const', [], [:I32]],
71
+ ['i64.const', [], [:I64]],
72
+ ['i32.eqz', [:I32], [:I32]],
73
+ ['i32.eq', [:I32, :I32], [:I32]],
74
+ ['i32.lt_s', [:I32, :I32], [:I32]],
75
+ ['i32.lt_u', [:I32, :I32], [:I32]],
76
+ ['i32.gt_s', [:I32, :I32], [:I32]],
77
+ ['i32.gt_u', [:I32, :I32], [:I32]],
78
+ ['i32.le_s', [:I32, :I32], [:I32]],
79
+ ['i32.le_u', [:I32, :I32], [:I32]],
80
+ ['i32.ge_s', [:I32, :I32], [:I32]],
81
+ ['i32.ge_u', [:I32, :I32], [:I32]],
82
+ ['i64.eqz', [:I64], [:I32]],
83
+ ['i64.eq', [:I64, :I64], [:I32]],
84
+ ['i64.lt_s', [:I64, :I64], [:I32]],
85
+ ['i64.lt_u', [:I64, :I64], [:I32]],
86
+ ['i64.gt_s', [:I64, :I64], [:I32]],
87
+ ['i64.gt_u', [:I64, :I64], [:I32]],
88
+ ['i64.le_s', [:I64, :I64], [:I32]],
89
+ ['i64.le_u', [:I64, :I64], [:I32]],
90
+ ['i64.ge_s', [:I64, :I64], [:I32]],
91
+ ['i64.ge_u', [:I64, :I64], [:I32]],
92
+ ['call', [:any], [:any]],
93
+ ['local.get', [], [:one]],
94
+ ['local.set', [:one], []],
95
+ ['local.tee', [:one], [:one]],
96
+ ['global.get', [], [:one]],
97
+ ['global.set', [:one], []],
98
+ ['i32.clz', [:I32], [:I32]],
99
+ ['i32.ctz', [:I32], [:I32]],
100
+ ['i32.popcnt', [:I32], [:I32]],
101
+ ['i32.add', [:I32, :I32], [:I32]],
102
+ ['i32.sub', [:I32, :I32], [:I32]],
103
+ ['i32.mul', [:I32, :I32], [:I32]],
104
+ ['i32.div_s', [:I32, :I32], [:I32]],
105
+ ['i32.div_u', [:I32, :I32], [:I32]],
106
+ ['i32.rem_s', [:I32, :I32], [:I32]],
107
+ ['i32.rem_u', [:I32, :I32], [:I32]],
108
+ ['i32.and', [:I32, :I32], [:I32]],
109
+ ['i32.or', [:I32, :I32], [:I32]],
110
+ ['i32.or', [:I32, :I32], [:I32]],
111
+ ['i32.xor', [:I32, :I32], [:I32]],
112
+ ['i32.shl', [:I32, :I32], [:I32]],
113
+ ['i32.shr_s', [:I32, :I32], [:I32]],
114
+ ['i32.shr_u', [:I32, :I32], [:I32]],
115
+ ['i32.rotl', [:I32, :I32], [:I32]],
116
+ ['i32.rotr', [:I32, :I32], [:I32]],
117
+ ['i64.clz', [:I64], [:I64]],
118
+ ['i64.ctz', [:I64], [:I64]],
119
+ ['i64.popcnt', [:I32], [:I32]],
120
+ ['i64.add', [:I64, :I64], [:I64]],
121
+ ['i64.sub', [:I64, :I64], [:I64]],
122
+ ['i64.mul', [:I64, :I64], [:I64]],
123
+ ['i64.div_s', [:I64, :I64], [:I64]],
124
+ ['i64.div_u', [:I64, :I64], [:I64]],
125
+ ['i64.rem_s', [:I64, :I64], [:I64]],
126
+ ['i64.rem_u', [:I64, :I64], [:I64]],
127
+ ['i64.and', [:I64, :I64], [:I64]],
128
+ ['i64.or', [:I64, :I64], [:I64]],
129
+ ['i64.or', [:I64, :I64], [:I64]],
130
+ ['i64.xor', [:I64, :I64], [:I64]],
131
+ ['i64.shl', [:I64, :I64], [:I64]],
132
+ ['i64.shr_s', [:I64, :I64], [:I64]],
133
+ ['i64.shr_u', [:I64, :I64], [:I64]],
134
+ ['i64.rotl', [:I64, :I64], [:I64]],
135
+ ['i64.rotr', [:I64, :I64], [:I64]],
136
+ ['i32.wrap_64', [:I64], [:I32]],
137
+ ['i64.extend_i32_s', [:I32], [:I64]],
138
+ ['i64.extend_i32_u', [:I32], [:I64]],
139
+ ['i64.trunc_f32_s', [:F32], [:I64]],
140
+ ['i64.trunc_f32_u', [:F32], [:I64]],
141
+ ['i64.trunc_f64_s', [:F64], [:I64]],
142
+ ['i64.trunc_f64_u', [:F64], [:I64]],
143
+ ['i64.trunc_f32_s', [:F64], [:I64]],
144
+ ['i64.trunc_f32_u', [:F64], [:I64]],
145
+ ] )
146
+
147
+ end
148
+ end