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.
- checksums.yaml +4 -4
- data/Rakefile +178 -0
- data/Steepfile +1 -0
- data/examples/consts.wat +12 -0
- data/lib/wardite/alu_f32.generated.rb +250 -0
- data/lib/wardite/alu_f64.generated.rb +250 -0
- data/lib/wardite/alu_i32.generated.rb +457 -0
- data/lib/wardite/alu_i64.generated.rb +514 -0
- data/lib/wardite/convert.generated.rb +234 -0
- data/lib/wardite/instruction.rb +82 -33
- data/lib/wardite/leb128.rb +1 -1
- data/lib/wardite/value.rb +627 -0
- data/lib/wardite/version.rb +1 -1
- data/lib/wardite/wasi.rb +6 -4
- data/lib/wardite.rb +192 -115
- data/scripts/gen_alu.rb +750 -0
- data/scripts/gen_conv.rb +76 -0
- data/scripts/templates/alu_module.rb.tmpl +18 -0
- data/scripts/templates/conv_module.rb.tmpl +18 -0
- data/sig/generated/wardite/alu_f32.generated.rbs +11 -0
- data/sig/generated/wardite/alu_f64.generated.rbs +11 -0
- data/sig/generated/wardite/alu_i32.generated.rbs +11 -0
- data/sig/generated/wardite/alu_i64.generated.rbs +11 -0
- data/sig/generated/wardite/convert.generated.rbs +11 -0
- data/sig/generated/wardite/instruction.rbs +15 -6
- data/sig/generated/wardite/leb128.rbs +1 -1
- data/sig/generated/wardite/value.rbs +302 -0
- data/sig/generated/wardite/wasi.rbs +4 -2
- data/sig/generated/wardite.rbs +27 -12
- metadata +19 -2
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::
|
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[
|
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 :
|
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
|
-
|
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.
|
712
|
-
|
713
|
-
|
714
|
-
|
715
|
-
|
716
|
-
|
717
|
-
|
718
|
-
|
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
|
-
|
765
|
-
|
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
|
768
|
-
locals.push
|
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:
|
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?(
|
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[
|
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[
|
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)
|
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
|