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