wardite 0.1.2 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
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