wardite 0.1.2 → 0.2.1

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
@@ -5,6 +5,19 @@ require_relative "wardite/version"
5
5
  require_relative "wardite/leb128"
6
6
  require_relative "wardite/const"
7
7
  require_relative "wardite/instruction"
8
+ require_relative "wardite/value"
9
+
10
+ module Wardite
11
+ module Evaluator
12
+ extend Wardite::ValueHelper
13
+ end
14
+ end
15
+ require_relative "wardite/alu_i32.generated"
16
+ require_relative "wardite/alu_i64.generated"
17
+ require_relative "wardite/alu_f32.generated"
18
+ require_relative "wardite/alu_f64.generated"
19
+ require_relative "wardite/convert.generated"
20
+
8
21
  require_relative "wardite/wasi"
9
22
 
10
23
  require "stringio"
@@ -164,7 +177,8 @@ module Wardite
164
177
  end
165
178
 
166
179
  module BinaryLoader
167
- extend Wardite::Leb128Helpers
180
+ extend Wardite::Leb128Helper
181
+ extend Wardite::ValueHelper
168
182
 
169
183
  # @rbs buf: File|StringIO
170
184
  # @rbs import_object: Hash[Symbol, Hash[Symbol, Proc]]
@@ -280,6 +294,10 @@ module Wardite
280
294
  arg << :i32
281
295
  when 0x7e
282
296
  arg << :i64
297
+ when 0x7d
298
+ arg << :f32
299
+ when 0x7c
300
+ arg << :f64
283
301
  else
284
302
  raise NotImplementedError, "unsupported for now: #{ty.inspect}"
285
303
  end
@@ -294,6 +312,10 @@ module Wardite
294
312
  ret << :i32
295
313
  when 0x7e
296
314
  ret << :i64
315
+ when 0x7d
316
+ ret << :f32
317
+ when 0x7c
318
+ ret << :f64
297
319
  else
298
320
  raise NotImplementedError, "unsupported for now: #{ty.inspect}"
299
321
  end
@@ -417,19 +439,43 @@ module Wardite
417
439
  def self.code_body(buf)
418
440
  dest = []
419
441
  while c = buf.read(1)
420
- code = Op.to_sym(c)
442
+ namespace, code = Op.to_sym(c)
421
443
  operand_types = Op.operand_of(code)
422
- operand = [] #: Array[Object]
444
+ operand = [] #: Array[Integer|Float|Block]
423
445
  operand_types.each do |typ|
424
446
  case typ
447
+ when :u8
448
+ ope = buf.read 1
449
+ if ! ope
450
+ raise LoadError, "buffer too short"
451
+ end
452
+ operand << ope.ord
425
453
  when :u32
426
454
  operand << fetch_uleb128(buf)
427
455
  when :i32
428
456
  operand << fetch_sleb128(buf)
429
- when :u8_block # :if specific
457
+ when :i64
458
+ operand << fetch_sleb128(buf)
459
+ when :f32
460
+ data = buf.read 4
461
+ if !data || data.size != 4
462
+ raise LoadError, "buffer too short"
463
+ end
464
+ v = data.unpack("e")[0]
465
+ raise "String#unpack is broken" if !v.is_a?(Float)
466
+ operand << v
467
+ when :f64
468
+ data = buf.read 8
469
+ if !data || data.size != 8
470
+ raise LoadError, "buffer too short"
471
+ end
472
+ v = data.unpack("E")[0]
473
+ raise "String#unpack is broken" if !v.is_a?(Float)
474
+ operand << v
475
+ when :u8_if_block # :if specific
430
476
  block_ope = buf.read 1
431
477
  if ! block_ope
432
- raise "buffer too short for if"
478
+ raise LoadError, "buffer too short for if"
433
479
  end
434
480
  if block_ope.ord == 0x40
435
481
  operand << Block.void
@@ -442,7 +488,7 @@ module Wardite
442
488
  end
443
489
  end
444
490
 
445
- dest << Op.new(code, operand)
491
+ dest << Op.new(namespace, code, operand)
446
492
  end
447
493
 
448
494
  dest
@@ -675,7 +721,10 @@ module Wardite
675
721
  end
676
722
 
677
723
  class Runtime
678
- attr_accessor :stack #: Array[Object]
724
+ include ValueHelper
725
+
726
+ # TODO: add types of class that the stack accomodates
727
+ attr_accessor :stack #: Array[I32|I64|F32|F64]
679
728
 
680
729
  attr_accessor :call_stack #: Array[Frame]
681
730
 
@@ -708,34 +757,14 @@ module Wardite
708
757
  if fn.callsig.size != args.size
709
758
  raise ArgumentError, "unmatch arg size"
710
759
  end
711
- args.each do |arg|
712
- stack.push arg
713
- end
714
-
715
- case fn
716
- when WasmFunction
717
- invoke_internal(fn)
718
- when ExternalFunction
719
- invoke_external(fn)
720
- else
721
- raise GenericError, "registered pointer is not to a function"
722
- end
723
- end
724
-
725
- # @rbs idx: Integer
726
- # @rbs args: Array[Object]
727
- # @rbs return: Object|nil
728
- def call_index(idx, args)
729
- fn = self.instance.store[idx]
730
- if !fn
731
- # TODO: own error NoFunctionError
732
- raise ::NoMethodError, "func #{idx} not found"
733
- end
734
- if fn.callsig.size != args.size
735
- raise ArgumentError, "unmatch arg size"
736
- end
737
- args.each do |arg|
738
- stack.push arg
760
+ args.each_with_index do |arg, idx|
761
+ case fn.callsig[idx]
762
+ when :i32
763
+ raise "type mismatch: i32(#{arg})" unless arg.is_a?(Integer)
764
+ stack.push I32(arg)
765
+ else
766
+ raise "TODO: add me"
767
+ end
739
768
  end
740
769
 
741
770
  case fn
@@ -761,11 +790,12 @@ module Wardite
761
790
  wasm_function.locals_type.each_with_index do |typ, i|
762
791
  case typ
763
792
  when :i32, :u32
764
- # locals.push Local::I32(typ, 0)...
765
- locals.push 0
793
+ locals.push I32(0)
794
+ when :i64, :u64
795
+ locals.push I64(0)
766
796
  else
767
- $stderr.puts "warning: unknown type #{typ.inspect}. default to Object"
768
- locals.push Object.new
797
+ $stderr.puts "warning: unknown type #{typ.inspect}. default to I32"
798
+ locals.push I32(0)
769
799
  end
770
800
  end
771
801
 
@@ -796,7 +826,7 @@ module Wardite
796
826
  end
797
827
 
798
828
  # @rbs external_function: ExternalFunction
799
- # @rbs return: Object|nil
829
+ # @rbs return: I32|I64|F32|F64|nil
800
830
  def invoke_external(external_function)
801
831
  local_start = stack.size - external_function.callsig.size
802
832
  args = stack[local_start..]
@@ -806,7 +836,31 @@ module Wardite
806
836
  self.stack = drained_stack(local_start)
807
837
 
808
838
  proc = external_function.callable
809
- proc[self.instance.store, args]
839
+ val = proc[self.instance.store, args]
840
+ if !val
841
+ return
842
+ end
843
+
844
+ case val
845
+ when I32, I64, F32, F64
846
+ return val
847
+ when Integer
848
+ case external_function.retsig[0]
849
+ when :i32
850
+ return I32(val)
851
+ when :i64
852
+ return I64(val)
853
+ end
854
+ when Float
855
+ case external_function.retsig[0]
856
+ when :f32
857
+ return F32(val)
858
+ when :f64
859
+ return F64(val)
860
+ end
861
+ end
862
+
863
+ raise "invalid type of value returned in proc. val: #{val.inspect}"
810
864
  end
811
865
 
812
866
  # @rbs return: void
@@ -829,88 +883,38 @@ module Wardite
829
883
  # @rbs insn: Op
830
884
  # @rbs return: void
831
885
  def eval_insn(frame, insn)
886
+ case insn.namespace
887
+ when :convert
888
+ return Evaluator.convert_eval_insn(self, frame, insn)
889
+ when :i32
890
+ return Evaluator.i32_eval_insn(self, frame, insn)
891
+ when :i64
892
+ return Evaluator.i64_eval_insn(self, frame, insn)
893
+ when :f32
894
+ return Evaluator.f32_eval_insn(self, frame, insn)
895
+ when :f64
896
+ return Evaluator.f64_eval_insn(self, frame, insn)
897
+ end
898
+
899
+ # unmached namespace...
832
900
  case insn.code
901
+ when :unreachable
902
+ raise Unreachable, "unreachable op"
903
+ when :nop
904
+ return
905
+
833
906
  when :if
834
907
  block = insn.operand[0]
835
908
  raise EvalError, "if op without block" if !block.is_a?(Block)
836
909
  cond = stack.pop
837
- raise EvalError, "cond not found" if !cond.is_a?(Integer)
910
+ raise EvalError, "cond not found" if !cond.is_a?(I32)
838
911
  next_pc = fetch_ops_while_end(frame.body, frame.pc)
839
- if cond.zero?
912
+ if cond.value.zero?
840
913
  frame.pc = next_pc
841
914
  end
842
915
 
843
916
  label = Label.new(:if, next_pc, stack.size, block.result_size)
844
917
  frame.labels.push(label)
845
-
846
- when :local_get
847
- idx = insn.operand[0]
848
- if !idx.is_a?(Integer)
849
- raise EvalError, "[BUG] invalid type of operand"
850
- end
851
- local = frame.locals[idx]
852
- if !local
853
- raise EvalError, "local not found"
854
- end
855
- stack.push(local)
856
- when :local_set
857
- idx = insn.operand[0]
858
- if !idx.is_a?(Integer)
859
- raise EvalError, "[BUG] invalid type of operand"
860
- end
861
- value = stack.pop
862
- if !value
863
- raise EvalError, "value should be pushed"
864
- end
865
- frame.locals[idx] = value
866
-
867
- when :i32_lts
868
- right, left = stack.pop, stack.pop
869
- if !right.is_a?(Integer) || !left.is_a?(Integer)
870
- raise EvalError, "maybe empty stack"
871
- end
872
- value = (left < right) ? 1 : 0
873
- stack.push(value)
874
- when :i32_leu
875
- right, left = stack.pop, stack.pop
876
- if !right.is_a?(Integer) || !left.is_a?(Integer)
877
- raise EvalError, "maybe empty stack"
878
- end
879
- value = (left >= right) ? 1 : 0
880
- stack.push(value)
881
- when :i32_add
882
- right, left = stack.pop, stack.pop
883
- if !right.is_a?(Integer) || !left.is_a?(Integer)
884
- raise EvalError, "maybe empty stack"
885
- end
886
- stack.push(left + right)
887
- when :i32_sub
888
- right, left = stack.pop, stack.pop
889
- if !right.is_a?(Integer) || !left.is_a?(Integer)
890
- raise EvalError, "maybe empty stack"
891
- end
892
- stack.push(left - right)
893
- when :i32_const
894
- const = insn.operand[0]
895
- if !const.is_a?(Integer)
896
- raise EvalError, "[BUG] invalid type of operand"
897
- end
898
- stack.push(const)
899
- when :i32_store
900
- _align = insn.operand[0] # TODO: alignment support?
901
- offset = insn.operand[1]
902
- raise EvalError, "[BUG] invalid type of operand" if !offset.is_a?(Integer)
903
-
904
- value = stack.pop
905
- addr = stack.pop
906
- if !value.is_a?(Integer) || !addr.is_a?(Integer)
907
- raise EvalError, "maybe stack too short"
908
- end
909
-
910
- at = addr + offset
911
- data_end = at + 4 # sizeof(i32)
912
- memory = self.instance.store.memories[0] || raise("[BUG] no memory")
913
- memory.data[at...data_end] = [value].pack("I")
914
918
 
915
919
  when :call
916
920
  idx = insn.operand[0]
@@ -945,7 +949,63 @@ module Wardite
945
949
  end
946
950
  stack_unwind(old_frame.sp, old_frame.arity)
947
951
  end
952
+
953
+ when :drop
954
+ stack.pop
955
+
956
+ when :select
957
+ cond, right, left = stack.pop, stack.pop, stack.pop
958
+ if !cond.is_a?(I32)
959
+ raise EvalError, "invalid stack for select"
960
+ end
961
+ if !right || !left
962
+ raise EvalError, "stack too short"
963
+ end
964
+ stack.push(cond.value != 0 ? left : right)
965
+
966
+ when :local_get
967
+ idx = insn.operand[0]
968
+ if !idx.is_a?(Integer)
969
+ raise EvalError, "[BUG] invalid type of operand"
970
+ end
971
+ local = frame.locals[idx]
972
+ if !local
973
+ raise EvalError, "local not found"
974
+ end
975
+ stack.push(local)
976
+
977
+ when :local_set
978
+ idx = insn.operand[0]
979
+ if !idx.is_a?(Integer)
980
+ raise EvalError, "[BUG] invalid type of operand"
981
+ end
982
+ value = stack.pop
983
+ if !value
984
+ raise EvalError, "value should be pushed"
985
+ end
986
+ frame.locals[idx] = value
987
+
988
+ when :memory_size
989
+ memory = instance.store.memories[0] || raise("[BUG] no memory")
990
+ stack.push(I32(memory.current))
991
+
992
+ when :memory_grow
993
+ delta = stack.pop
994
+ if !delta.is_a?(I32)
995
+ raise EvalError, "maybe stack too short"
996
+ end
997
+ memory = instance.store.memories[0] || raise("[BUG] no memory")
998
+ stack.push(I32(memory.grow(delta.value)))
999
+
1000
+ else
1001
+ raise "TODO! unsupported #{insn.inspect}"
948
1002
  end
1003
+
1004
+ rescue => e
1005
+ require "pp"
1006
+ $stderr.puts "frame:::\n#{frame.pretty_inspect}"
1007
+ $stderr.puts "stack:::\n#{stack.pretty_inspect}"
1008
+ raise e
949
1009
  end
950
1010
 
951
1011
  # @rbs ops: Array[Op]
@@ -996,7 +1056,7 @@ module Wardite
996
1056
  end
997
1057
 
998
1058
  # @rbs finish: Integer
999
- # @rbs return: Array[Object]
1059
+ # @rbs return: Array[I32|I64|F32|F64]
1000
1060
  def drained_stack(finish)
1001
1061
  drained = stack[0...finish]
1002
1062
  if ! drained
@@ -1034,7 +1094,7 @@ module Wardite
1034
1094
 
1035
1095
  attr_accessor :labels #: Array[Label]
1036
1096
 
1037
- attr_accessor :locals #: Array[Object]
1097
+ attr_accessor :locals #: Array[I32|I64|F32|F64]
1038
1098
 
1039
1099
  # @rbs pc: Integer
1040
1100
  # @rbs sp: Integer
@@ -1152,16 +1212,32 @@ module Wardite
1152
1212
  class Memory
1153
1213
  attr_accessor :data #: String
1154
1214
 
1215
+ attr_accessor :current #: Integer
1216
+
1155
1217
  attr_accessor :max #: Integer|nil
1156
1218
 
1157
1219
  # @rbs min: Integer
1158
1220
  # @rbs max: Integer|nil
1159
1221
  # @rbs return: void
1160
1222
  def initialize(min, max)
1161
- @data = String.new("\0" * (min * 64 * 1024), capacity: min * 64 * 1024)
1223
+ @data = String.new("\0" * (min * 64 * 1024))
1224
+ @current = min
1162
1225
  @max = max
1163
1226
  end
1164
1227
 
1228
+ # @rbs delta: Integer
1229
+ # @rbs return: Integer
1230
+ def grow(delta)
1231
+ prev = current
1232
+ newsize = current + delta
1233
+ if max && (newsize > max)
1234
+ return -1
1235
+ end
1236
+
1237
+ @data += String.new("\0" * (delta * 64 * 1024))
1238
+ prev
1239
+ end
1240
+
1165
1241
  def inspect
1166
1242
  "#<Wardite::Memory initial=#{@data.size.inspect} max=#{@max.inspect} @data=#{@data[0...64].inspect}...>"
1167
1243
  end
@@ -1290,6 +1366,7 @@ module Wardite
1290
1366
  class LoadError < StandardError; end
1291
1367
  class ArgumentError < StandardError; end
1292
1368
  class EvalError < StandardError; end
1369
+ class Unreachable < StandardError; end
1293
1370
 
1294
1371
  # @rbs path: String|nil
1295
1372
  # @rbs buffer: File|StringIO|nil