Commit 2b965469 authored by Sebastian Erdweg's avatar Sebastian Erdweg
Browse files

debugging interval to byte encoding

parent 2660f10f
Pipeline #284161 failed with stage
in 1 minute and 45 seconds
......@@ -140,15 +140,18 @@ given ConcreteConvertIntBytes: ConvertIntBytes[Int, Seq[Byte]] with
given ConcreteConvertBytesInt: ConvertBytesInt[Seq[Byte], Int] with
override def apply(from: Seq[Byte], conf: config.BytesSize && SomeCC[ByteOrder] && config.Bits): Int =
val buf = ByteBuffer.wrap(from.toArray)
buf.order(conf.c1.c2.t)
(conf.c1.c1, conf.c2) match
case (config.BytesSize.Byte, config.Bits.Signed) => buf.get.toInt
case (config.BytesSize.Byte, config.Bits.Unsigned) => buf.get & 0xFF
case (config.BytesSize.Short, config.Bits.Signed) => buf.getShort.toInt
case (config.BytesSize.Short, config.Bits.Unsigned) => buf.getShort & 0xFFFF
case (config.BytesSize.Int, _) => buf.getInt
case _ => throw UnsupportedConfiguration(conf, this.getClass.getSimpleName)
decode(from, conf)
def decode(from: Seq[Byte], conf: config.BytesSize && SomeCC[ByteOrder] && config.Bits): Int =
val buf = ByteBuffer.wrap(from.toArray)
buf.order(conf.c1.c2.t)
(conf.c1.c1, conf.c2) match
case (config.BytesSize.Byte, config.Bits.Signed) => buf.get.toInt
case (config.BytesSize.Byte, config.Bits.Unsigned) => buf.get & 0xFF
case (config.BytesSize.Short, config.Bits.Signed) => buf.getShort.toInt
case (config.BytesSize.Short, config.Bits.Unsigned) => buf.getShort & 0xFFFF
case (config.BytesSize.Int, _) => buf.getInt
case _ => throw UnsupportedConfiguration(conf, this.getClass.getSimpleName)
given ConcreteIntUnsignedOrderingOps: UnsignedOrderingOps[Int, Boolean] with
override def ltUnsigned(v1: Int, v2: Int): Boolean = Integer.compareUnsigned(v1, v2) < 0
......
......@@ -286,44 +286,51 @@ given ConvertNumericIntervalToBytes[From, To, I, B, Config <: ConvertConfig[_]]
(using convert: Convert[From, To, I, Seq[B], config.BytesSize && Config])
(using Failure, EffectStack, Ordering[B])
: Convert[From, To, NumericInterval[I], Seq[NumericInterval[B]], config.BytesSize && Config] with
def apply(i: NumericInterval[I], conf: config.BytesSize && Config): Seq[NumericInterval[B]] = i match
case NumericInterval.Top() =>
val bytes = Seq.fill(conf._1.bytes)(NumericInterval.Top[B]())
safeConversion(conf, bytes)
case NumericInterval.Bounded(l, h) =>
val lowBytes = convert(l, conf)
val highBytes = convert(h, conf)
val bytes = lowBytes.zip(highBytes).map(NumericInterval.fromBounds)
bytes
def apply(i: NumericInterval[I], conf: config.BytesSize && Config): Seq[NumericInterval[B]] =
encode(i, conf)
given ConvertBytesToNumericInterval[From, To, I, B]
(using convert: Convert[From, To, Seq[B], I, config.BytesSize && SomeCC[ByteOrder] && config.Bits])
(using Failure, EffectStack, Ordering[I])
: Convert[From, To, Seq[NumericInterval[B]], NumericInterval[I], config.BytesSize && SomeCC[ByteOrder] && config.Bits] with
def apply(bytes: Seq[NumericInterval[B]], conf: config.BytesSize && SomeCC[ByteOrder] && config.Bits): NumericInterval[I] =
val boundedBytes: Seq[NumericInterval.Bounded[B]] = bytes.map {
case NumericInterval.Top() => return NumericInterval.Top()
case b@NumericInterval.Bounded(_, _) => b
decode(bytes, conf)
def encode[From, To, I, B, Config <: ConvertConfig[_]](i: NumericInterval[I], conf: config.BytesSize && Config)(using convert: Convert[From, To, I, Seq[B], config.BytesSize && Config])
(using Failure, EffectStack, Ordering[B]): Seq[NumericInterval[B]] = i match
case NumericInterval.Top() =>
val bytes = Seq.fill(conf._1.bytes)(NumericInterval.Top[B]())
safeConversion(conf, bytes)
case NumericInterval.Bounded(l, h) =>
val lowBytes = convert(l, conf)
val highBytes = convert(h, conf)
val value = lowBytes.zip(highBytes)
val bytes = value.map(NumericInterval.fromBounds)
bytes
def decode[B, I, From, To](bytes: Seq[NumericInterval[B]], conf: config.BytesSize && SomeCC[ByteOrder] && config.Bits)(using convert: Convert[From, To, Seq[B], I, config.BytesSize && SomeCC[ByteOrder] && config.Bits])
(using Failure, EffectStack, Ordering[I]): NumericInterval[I] =
val boundedBytes: Seq[NumericInterval.Bounded[B]] = bytes.map {
case NumericInterval.Top() => return NumericInterval.Top()
case b@NumericInterval.Bounded(_, _) => b
}
val (msb, bigEndianRest) =
if (conf.c1.c2.t == ByteOrder.BIG_ENDIAN) {
(boundedBytes.head, boundedBytes.tail)
} else {
val rev = boundedBytes.reverse
(rev.head, rev.tail)
}
val (msb, bigEndianRest) =
if (conf.c1.c2.t == ByteOrder.BIG_ENDIAN) {
(boundedBytes.head, boundedBytes.tail)
} else {
val rev = boundedBytes.reverse
(rev.head, rev.tail)
}
val bigEndianConf = conf.c1.c1 && SomeCC(ByteOrder.BIG_ENDIAN, false) && conf.c2
val l1 = Convert(msb.low +: bigEndianRest.map(_.low), bigEndianConf)
val h1 = Convert(msb.high +: bigEndianRest.map(_.high), bigEndianConf)
val iv1 = NumericInterval.fromBounds(l1, h1)
val l2 = Convert(msb.low +: bigEndianRest.map(_.high), bigEndianConf)
val h2 = Convert(msb.high +: bigEndianRest.map(_.low), bigEndianConf)
val iv2 = NumericInterval.fromBounds(l2, h2)
val bigEndianConf = conf.c1.c1 && SomeCC(ByteOrder.BIG_ENDIAN, false) && conf.c2
Join(iv1, iv2).get
val l1 = Convert(msb.low +: bigEndianRest.map(_.low), bigEndianConf)
val h1 = Convert(msb.high +: bigEndianRest.map(_.high), bigEndianConf)
val iv1 = NumericInterval.fromBounds(l1, h1)
val l2 = Convert(msb.low +: bigEndianRest.map(_.high), bigEndianConf)
val h2 = Convert(msb.high +: bigEndianRest.map(_.low), bigEndianConf)
val iv2 = NumericInterval.fromBounds(l2, h2)
Join(iv1, iv2).get
;; Functions
(module $Mf
(func (export "call") (result i32) (call $g))
(func $g (result i32) (i32.const 2))
)
(register "Mf" $Mf)
(module $Nf
(func $f (import "Mf" "call") (result i32))
(export "Mf.call" (func $f))
(func (export "call Mf.call") (result i32) (call $f))
(func (export "call") (result i32) (call $g))
(func $g (result i32) (i32.const 3))
)
(assert_return (invoke $Mf "call") (i32.const 2))
(assert_return (invoke $Nf "Mf.call") (i32.const 2))
(assert_return (invoke $Nf "call") (i32.const 3))
(assert_return (invoke $Nf "call Mf.call") (i32.const 2))
(module
(import "spectest" "print_i32" (func $f (param i32)))
(export "print" (func $f))
)
(register "reexport_f")
;;(assert_unlinkable
;; (module (import "reexport_f" "print" (func (param i64))))
;; "incompatible import type"
;;)
;;(assert_unlinkable
;; (module (import "reexport_f" "print" (func (param i32) (result i32))))
;; "incompatible import type"
;;)
;; Globals
(module $Mg
(global $glob (export "glob") i32 (i32.const 42))
(func (export "get") (result i32) (global.get $glob))
;; export mutable globals
(global $mut_glob (export "mut_glob") (mut i32) (i32.const 142))
(func (export "get_mut") (result i32) (global.get $mut_glob))
(func (export "set_mut") (param i32) (global.set $mut_glob (local.get 0)))
)
(register "Mg" $Mg)
(module $Ng
(global $x (import "Mg" "glob") i32)
(global $mut_glob (import "Mg" "mut_glob") (mut i32))
(func $f (import "Mg" "get") (result i32))
(func $get_mut (import "Mg" "get_mut") (result i32))
(func $set_mut (import "Mg" "set_mut") (param i32))
(export "Mg.glob" (global $x))
(export "Mg.get" (func $f))
(global $glob (export "glob") i32 (i32.const 43))
(func (export "get") (result i32) (global.get $glob))
(export "Mg.mut_glob" (global $mut_glob))
(export "Mg.get_mut" (func $get_mut))
(export "Mg.set_mut" (func $set_mut))
)
(assert_return (get $Mg "glob") (i32.const 42))
(assert_return (get $Ng "Mg.glob") (i32.const 42))
(assert_return (get $Ng "glob") (i32.const 43))
(assert_return (invoke $Mg "get") (i32.const 42))
(assert_return (invoke $Ng "Mg.get") (i32.const 42))
(assert_return (invoke $Ng "get") (i32.const 43))
(assert_return (get $Mg "mut_glob") (i32.const 142))
(assert_return (get $Ng "Mg.mut_glob") (i32.const 142))
(assert_return (invoke $Mg "get_mut") (i32.const 142))
(assert_return (invoke $Ng "Mg.get_mut") (i32.const 142))
(assert_return (invoke $Mg "set_mut" (i32.const 241)))
(assert_return (get $Mg "mut_glob") (i32.const 241))
(assert_return (get $Ng "Mg.mut_glob") (i32.const 241))
(assert_return (invoke $Mg "get_mut") (i32.const 241))
(assert_return (invoke $Ng "Mg.get_mut") (i32.const 241))
(assert_unlinkable
(module (import "Mg" "mut_glob" (global i32)))
"incompatible import type"
)
(assert_unlinkable
(module (import "Mg" "glob" (global (mut i32))))
"incompatible import type"
)
;; Tables
(module $Mt
(type (func (result i32)))
(type (func))
(table (export "tab") 10 funcref)
(elem (i32.const 2) $g $g $g $g)
(func $g (result i32) (i32.const 4))
(func (export "h") (result i32) (i32.const -4))
(func (export "call") (param i32) (result i32)
(call_indirect (type 0) (local.get 0))
)
)
(register "Mt" $Mt)
(module $Nt
(type (func))
(type (func (result i32)))
(func $f (import "Mt" "call") (param i32) (result i32))
(func $h (import "Mt" "h") (result i32))
(table funcref (elem $g $g $g $h $f))
(func $g (result i32) (i32.const 5))
(export "Mt.call" (func $f))
(func (export "call Mt.call") (param i32) (result i32)
(call $f (local.get 0))
)
(func (export "call") (param i32) (result i32)
(call_indirect (type 1) (local.get 0))
)
)
(assert_return (invoke $Mt "call" (i32.const 2)) (i32.const 4))
(assert_return (invoke $Nt "Mt.call" (i32.const 2)) (i32.const 4))
(assert_return (invoke $Nt "call" (i32.const 2)) (i32.const 5))
(assert_return (invoke $Nt "call Mt.call" (i32.const 2)) (i32.const 4))
(assert_trap (invoke $Mt "call" (i32.const 1)) "uninitialized")
(assert_trap (invoke $Nt "Mt.call" (i32.const 1)) "uninitialized")
(assert_return (invoke $Nt "call" (i32.const 1)) (i32.const 5))
(assert_trap (invoke $Nt "call Mt.call" (i32.const 1)) "uninitialized")
(assert_trap (invoke $Mt "call" (i32.const 0)) "uninitialized")
(assert_trap (invoke $Nt "Mt.call" (i32.const 0)) "uninitialized")
(assert_return (invoke $Nt "call" (i32.const 0)) (i32.const 5))
(assert_trap (invoke $Nt "call Mt.call" (i32.const 0)) "uninitialized")
(assert_trap (invoke $Mt "call" (i32.const 20)) "undefined")
(assert_trap (invoke $Nt "Mt.call" (i32.const 20)) "undefined")
(assert_trap (invoke $Nt "call" (i32.const 7)) "undefined")
(assert_trap (invoke $Nt "call Mt.call" (i32.const 20)) "undefined")
(assert_return (invoke $Nt "call" (i32.const 3)) (i32.const -4))
(assert_trap (invoke $Nt "call" (i32.const 4)) "indirect call")
(module $Ot
(type (func (result i32)))
(func $h (import "Mt" "h") (result i32))
(table (import "Mt" "tab") 5 funcref)
(elem (i32.const 1) $i $h)
(func $i (result i32) (i32.const 6))
(func (export "call") (param i32) (result i32)
(call_indirect (type 0) (local.get 0))
)
)
(assert_return (invoke $Mt "call" (i32.const 3)) (i32.const 4))
(assert_return (invoke $Nt "Mt.call" (i32.const 3)) (i32.const 4))
(assert_return (invoke $Nt "call Mt.call" (i32.const 3)) (i32.const 4))
(assert_return (invoke $Ot "call" (i32.const 3)) (i32.const 4))
(assert_return (invoke $Mt "call" (i32.const 2)) (i32.const -4))
(assert_return (invoke $Nt "Mt.call" (i32.const 2)) (i32.const -4))
(assert_return (invoke $Nt "call" (i32.const 2)) (i32.const 5))
(assert_return (invoke $Nt "call Mt.call" (i32.const 2)) (i32.const -4))
(assert_return (invoke $Ot "call" (i32.const 2)) (i32.const -4))
(assert_return (invoke $Mt "call" (i32.const 1)) (i32.const 6))
(assert_return (invoke $Nt "Mt.call" (i32.const 1)) (i32.const 6))
(assert_return (invoke $Nt "call" (i32.const 1)) (i32.const 5))
(assert_return (invoke $Nt "call Mt.call" (i32.const 1)) (i32.const 6))
(assert_return (invoke $Ot "call" (i32.const 1)) (i32.const 6))
(assert_trap (invoke $Mt "call" (i32.const 0)) "uninitialized")
(assert_trap (invoke $Nt "Mt.call" (i32.const 0)) "uninitialized")
(assert_return (invoke $Nt "call" (i32.const 0)) (i32.const 5))
(assert_trap (invoke $Nt "call Mt.call" (i32.const 0)) "uninitialized")
(assert_trap (invoke $Ot "call" (i32.const 0)) "uninitialized")
(assert_trap (invoke $Ot "call" (i32.const 20)) "undefined")
(module
(table (import "Mt" "tab") 0 funcref)
(elem (i32.const 9) $f)
(func $f)
)
(module $G1 (global (export "g") i32 (i32.const 5)))
(register "G1" $G1)
(module $G2
(global (import "G1" "g") i32)
(global (export "g") i32 (global.get 0))
)
(assert_return (get $G2 "g") (i32.const 5))
(assert_unlinkable
(module
(table (import "Mt" "tab") 0 funcref)
(elem (i32.const 10) $f)
(func $f)
)
"elements segment does not fit"
)
(assert_unlinkable
(module
(table (import "Mt" "tab") 10 funcref)
(memory (import "Mt" "mem") 1) ;; does not exist
(func $f (result i32) (i32.const 0))
(elem (i32.const 7) $f)
(elem (i32.const 9) $f)
)
"unknown import"
)
(assert_trap (invoke $Mt "call" (i32.const 7)) "uninitialized")
(assert_unlinkable
(module
(table (import "Mt" "tab") 10 funcref)
(func $f (result i32) (i32.const 0))
(elem (i32.const 7) $f)
(elem (i32.const 12) $f) ;; out of bounds
)
"elements segment does not fit"
)
(assert_trap (invoke $Mt "call" (i32.const 7)) "uninitialized")
(assert_unlinkable
(module
(table (import "Mt" "tab") 10 funcref)
(func $f (result i32) (i32.const 0))
(elem (i32.const 7) $f)
(memory 1)
(data (i32.const 0x10000) "d") ;; out of bounds
)
"data segment does not fit"
)
(assert_trap (invoke $Mt "call" (i32.const 7)) "uninitialized")
;; Memories
......@@ -272,117 +26,6 @@
)
)
(assert_return (invoke $Mm "load" (i32.const 12)) (i32.const 2))
(assert_return (invoke $Nm "Mm.load" (i32.const 12)) (i32.const 2))
(assert_return (invoke $Nm "load" (i32.const 12)) (i32.const 0xf2))
(module $Om
(memory (import "Mm" "mem") 1)
(data (i32.const 5) "\a0\a1\a2\a3\a4\a5\a6\a7")
(func (export "load") (param $a i32) (result i32)
(i32.load8_u (local.get 0))
)
)
(assert_return (invoke $Mm "load" (i32.const 12)) (i32.const 0xa7))
(assert_return (invoke $Nm "Mm.load" (i32.const 12)) (i32.const 0xa7))
;;(assert_return (invoke $Mm "load" (i32.const 12)) (i32.const 2))
;;(assert_return (invoke $Nm "Mm.load" (i32.const 12)) (i32.const 2))
(assert_return (invoke $Nm "load" (i32.const 12)) (i32.const 0xf2))
(assert_return (invoke $Om "load" (i32.const 12)) (i32.const 0xa7))
(module
(memory (import "Mm" "mem") 0)
(data (i32.const 0xffff) "a")
)
(assert_unlinkable
(module
(memory (import "Mm" "mem") 0)
(data (i32.const 0x10000) "a")
)
"data segment does not fit"
)
(module $Pm
(memory (import "Mm" "mem") 1 8)
(func (export "grow") (param $a i32) (result i32)
(memory.grow (local.get 0))
)
)
(assert_return (invoke $Pm "grow" (i32.const 0)) (i32.const 1))
(assert_return (invoke $Pm "grow" (i32.const 2)) (i32.const 1))
(assert_return (invoke $Pm "grow" (i32.const 0)) (i32.const 3))
(assert_return (invoke $Pm "grow" (i32.const 1)) (i32.const 3))
(assert_return (invoke $Pm "grow" (i32.const 1)) (i32.const 4))
(assert_return (invoke $Pm "grow" (i32.const 0)) (i32.const 5))
(assert_return (invoke $Pm "grow" (i32.const 1)) (i32.const -1))
(assert_return (invoke $Pm "grow" (i32.const 0)) (i32.const 5))
(assert_unlinkable
(module
(func $host (import "spectest" "print"))
(memory (import "Mm" "mem") 1)
(table (import "Mm" "tab") 0 funcref) ;; does not exist
(data (i32.const 0) "abc")
)
"unknown import"
)
(assert_return (invoke $Mm "load" (i32.const 0)) (i32.const 0))
(assert_unlinkable
(module
(memory (import "Mm" "mem") 1)
(data (i32.const 0) "abc")
(data (i32.const 0x50000) "d") ;; out of bounds
)
"data segment does not fit"
)
(assert_return (invoke $Mm "load" (i32.const 0)) (i32.const 0))
(assert_unlinkable
(module
(memory (import "Mm" "mem") 1)
(data (i32.const 0) "abc")
(table 0 funcref)
(func)
(elem (i32.const 0) 0) ;; out of bounds
)
"elements segment does not fit"
)
(assert_return (invoke $Mm "load" (i32.const 0)) (i32.const 0))
;; Store is modified if the start function traps.
(module $Ms
(type $t (func (result i32)))
(memory (export "memory") 1)
(table (export "table") 1 funcref)
(func (export "get memory[0]") (type $t)
(i32.load8_u (i32.const 0))
)
(func (export "get table[0]") (type $t)
(call_indirect (type $t) (i32.const 0))
)
)
(register "Ms" $Ms)
(assert_trap
(module
(import "Ms" "memory" (memory 1))
(import "Ms" "table" (table 1 funcref))
(data (i32.const 0) "hello")
(elem (i32.const 0) $f)
(func $f (result i32)
(i32.const 0xdead)
)
(func $main
(unreachable)
)
(start $main)
)
"unreachable"
)
(assert_return (invoke $Ms "get memory[0]") (i32.const 104)) ;; 'h'
(assert_return (invoke $Ms "get table[0]") (i32.const 0xdead))
......@@ -59,13 +59,13 @@ class IntervalAnalysisTestScript extends AnyFlatSpec, Matchers:
)
Fixpoint.DEBUG = false
Files.list(Paths.get(uri)).toScala(List).filter(p => p.toString.endsWith(".wast")).sorted.foreach { p =>
Files.list(Paths.get(uri)).toScala(List).filter(p => p.toString.endsWith("linking.wast")).sorted.foreach { p =>
for (aInterp <- analyses) {
it must s"execute ${p.getFileName} with ${aInterp()}" in {
println(s"Executing TestScript constant analysis on ${p.getFileName}")
val script = Parsing.testscript(p)
val interp = IntervalAnalysisTestScriptInterpreter(Some(spectest), aInterp())
interp.run(script)
// val interp = IntervalAnalysisTestScriptInterpreter(Some(spectest), aInterp())
// interp.run(script)
val interpTop = IntervalAnalysisTestScriptInterpreter(Some(spectest), aInterp(), true)
interpTop.run(script)
}
......@@ -124,6 +124,7 @@ class IntervalAnalysisTestScriptInterpreter(spectest: Option[Module] = None, aIn
case Some(name) => aModules(name)
def eval(c: Command): Unit =
println(c)
c match
case ValidModule(m) =>
// validate and compile module
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment