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