Exemple #1
0
 def printex(instrs: typing.List[Instruction], prefix=0):
     for e in instrs:
         a = f'           | {" " * prefix}{convention.opcodes[e.code][0]}'
         if e.code in [convention.block, convention.loop, convention.if_]:
             log.debugln(f'{a} {e.immediate_arguments}')
             prefix += 2
         elif e.code == convention.end:
             log.debugln(f'{a}')
             prefix -= 2
         elif e.immediate_arguments is None:
             log.debugln(f'{a}')
         elif isinstance(e.immediate_arguments, list):
             log.debugln(f'{a} {" ".join([str(e) for e in e.immediate_arguments])}')
         else:
             log.debugln(f'{a} {e.immediate_arguments}')
Exemple #2
0
 def exec(self, name: str, args: typing.List):
     # Invoke a function denoted by the function address with the provided arguments.
     func_addr = self.func_addr(name)
     func = self.store.funcs[self.module_instance.funcaddrs[func_addr]]
     # Mapping check for Python valtype to WebAssembly valtype
     for i, e in enumerate(func.functype.args):
         if e in [convention.i32, convention.i64]:
             assert isinstance(args[i], int)
         if e in [convention.f32, convention.f64]:
             assert isinstance(args[i], float)
         args[i] = execution.Value(e, args[i])
     stack = execution.Stack()
     stack.ext(args)
     log.debugln(f'Running function {name}({", ".join([str(e) for e in args])}):')
     r = execution.call(self.module_instance, func_addr, self.store, stack)
     if r:
         return r[0].n
     return None
Exemple #3
0
 def exec(self, name: str, args: typing.List):
     func_addr = self.func_addr(name)
     func = self.store.funcs[self.module_instance.funcaddrs[func_addr]]
     for i, e in enumerate(func.functype.args):
         if e in [convention.i32, convention.i64]:
             assert isinstance(args[i], int)
         if e in [convention.f32, convention.f64]:
             assert isinstance(args[i], float)
         args[i] = execution.Value(e, args[i])
     stack = execution.Stack()
     stack.ext(args)
     frame = execution.Frame(self.module_instance, args,
                             len(func.functype.rets), -1)
     log.debugln(
         f'Running function {name}({", ".join([str(e) for e in args])}):')
     r = execution.call(self.module_instance, func_addr, self.store, stack)
     if r:
         return r[0].n
     return None
Exemple #4
0
    def from_reader(cls, r: typing.BinaryIO) -> 'Module':
        if list(r.read(4)) != [0x00, 0x61, 0x73, 0x6d]:
            raise Exception('pywasm: invalid magic number')
        if list(r.read(4)) != [0x01, 0x00, 0x00, 0x00]:
            raise Exception('pywasm: invalid version')
        mod = Module()
        log.debugln('Sections:')
        log.debugln()
        while True:
            section_id_byte = r.read(1)
            if not section_id_byte:
                break
            section_id = ord(section_id_byte)
            n = common.read_count(r, 32)
            data = r.read(n)
            if len(data) != n:
                raise Exception('pywasm: invalid section size')
            if section_id == convention.custom_section:
                custom_section = CustomSection.from_reader(io.BytesIO(data))
                log.debugln(
                    f'{convention.section[section_id][0]:>9} {custom_section.name}'
                )
            elif section_id == convention.type_section:
                type_section = TypeSection.from_reader(io.BytesIO(data))
                for i, e in enumerate(type_section.vec):
                    log.debugln(
                        f'{convention.section[section_id][0]:>9}[{i}] {e}')
                mod.types = type_section.vec
            elif section_id == convention.import_section:
                import_section = ImportSection.from_reader(io.BytesIO(data))
                for i, e in enumerate(import_section.vec):
                    log.debugln(
                        f'{convention.section[section_id][0]:>9}[{i}] {e}')
                mod.imports = import_section.vec
            elif section_id == convention.function_section:
                function_section = FunctionSection.from_reader(
                    io.BytesIO(data))
                num_imported_funcs = sum(1 for _ in filter(
                    lambda i: i.kind == convention.extern_func, mod.imports))
                for i, e in enumerate(function_section.vec):
                    log.debugln(
                        f'{convention.section[section_id][0]:>9}[{i}] func={num_imported_funcs+i} sig={e}'
                    )
            elif section_id == convention.table_section:
                table_section = TableSection.from_reader(io.BytesIO(data))
                for i, e in enumerate(table_section.vec):
                    log.debugln(
                        f'{convention.section[section_id][0]:>9}[{i}] {e}')
                mod.tables = table_section.vec
            elif section_id == convention.memory_section:
                memory_section = MemorySection.from_reader(io.BytesIO(data))
                for i, e in enumerate(memory_section.vec):
                    log.debugln(
                        f'{convention.section[section_id][0]:>9}[{i}] {e}')
                mod.mems = memory_section.vec
            elif section_id == convention.global_section:
                global_section = GlobalSection.from_reader(io.BytesIO(data))
                for i, e in enumerate(global_section.vec):
                    log.debugln(
                        f'{convention.section[section_id][0]:>9}[{i}] {e}')
                mod.globals = global_section.vec
            elif section_id == convention.export_section:
                export_section = ExportSection.from_reader(io.BytesIO(data))
                for i, e in enumerate(export_section.vec):
                    log.debugln(
                        f'{convention.section[section_id][0]:>9}[{i}] {e}')
                mod.exports = export_section.vec
            elif section_id == convention.start_section:
                start_section = StartSection.from_reader(io.BytesIO(data))
                log.debugln(
                    f'{convention.section[section_id][0]:>12} {start_section.start_function}'
                )
                mod.start = start_section.start_function.funcidx
            elif section_id == convention.element_section:
                element_section = ElementSection.from_reader(io.BytesIO(data))
                for i, e in enumerate(element_section.vec):
                    log.debugln(
                        f'{convention.section[section_id][0]:>9}[{i}] {e}')
                mod.elem = element_section.vec
            elif section_id == convention.code_section:
                code_section = CodeSection.from_reader(io.BytesIO(data))

                def printex(instrs: typing.List[Instruction], prefix=0):
                    for e in instrs:
                        a = f'           | {" " * prefix}{convention.opcodes[e.code][0]}'
                        if e.code in [
                                convention.block, convention.loop,
                                convention.if_
                        ]:
                            log.debugln(
                                f'{a} {convention.blocktype[e.immediate_arguments][0]}'
                            )
                            prefix += 2
                        elif e.code == convention.end:
                            prefix -= 2
                            a = f'           | {" " * prefix}{convention.opcodes[e.code][0]}'
                            log.debugln(f'{a}')
                        elif e.immediate_arguments is None:
                            log.debugln(f'{a}')
                        elif isinstance(e.immediate_arguments, list):
                            log.debugln(
                                f'{a} {" ".join([str(e) for e in e.immediate_arguments])}'
                            )
                        else:
                            log.debugln(f'{a} {e.immediate_arguments}')

                num_imported_funcs = sum(1 for _ in filter(
                    lambda i: i.kind == convention.extern_func, mod.imports))
                for i, e in enumerate(code_section.vec):
                    log.debugln(
                        f'{convention.section[section_id][0]:>9}[{i}] func={num_imported_funcs+i} {e}'
                    )
                    printex(e.expr.data)
                    func = Function()
                    func.typeidx = function_section.vec[i]
                    func.locals = e.locals
                    func.expr = e.expr
                    mod.funcs.append(func)
            elif section_id == convention.data_section:
                data_section = DataSection.from_reader(io.BytesIO(data))
                for i, e in enumerate(data_section.vec):
                    log.debugln(
                        f'{convention.section[section_id][0]:>9}[{i}] {e}')
                mod.data = data_section.vec
            else:
                raise Exception('pywasm: invalid section id')
        log.debugln('')
        return mod
Exemple #5
0
def exec_expr(
    store: Store,
    frame: Frame,
    stack: Stack,
    expr: structure.Expression,
):
    module = frame.module
    if not expr.data:
        raise Exception('pywasm: empty init expr')
    pc = -1
    while True:
        pc += 1
        if pc >= len(expr.data):
            break
        i = expr.data[pc]
        log.debugln(f'{str(i):<18} {stack}')
        opcode = i.code
        if opcode >= convention.unreachable and opcode <= convention.call_indirect:
            if opcode == convention.unreachable:
                raise Exception('pywasm: reached unreachable')
            if opcode == convention.nop:
                continue
            if opcode == convention.block:
                arity = 0 if i.immediate_arguments == convention.empty else 1
                stack.add(Label(arity, expr.composition[pc][-1] + 1))
                continue
            if opcode == convention.loop:
                stack.add(Label(0, expr.composition[pc][0]))
                continue
            if opcode == convention.if_:
                c = stack.pop().n
                arity = 0 if i.immediate_arguments == convention.empty else 1
                stack.add(Label(arity, expr.composition[pc][-1] + 1))
                if c != 0:
                    continue
                if len(expr.composition[pc]) > 2:
                    pc = expr.composition[pc][1]
                    continue
                pc = expr.composition[pc][-1] - 1
                continue
            if opcode == convention.else_:
                for i in range(len(stack.data)):
                    i = -1 - i
                    e = stack.data[i]
                    if isinstance(e, Label):
                        pc = e.continuation - 1
                        del stack.data[i]
                        break
                continue
            if opcode == convention.end:
                # label{instr∗} val* end -> val*
                if stack.status() == Label:
                    for i in range(len(stack.data)):
                        i = -1 - i
                        if isinstance(stack.data[i], Label):
                            del stack.data[i]
                            break
                    continue
                # frame{F} val* end -> val*
                v = [stack.pop() for _ in range(frame.arity)][::-1]
                assert isinstance(stack.pop(), Frame)
                stack.ext(v)
                continue
            if opcode == convention.br:
                pc = spec_br(i.immediate_arguments, stack)
                continue
            if opcode == convention.br_if:
                if stack.pop().n == 0:
                    continue
                pc = spec_br(i.immediate_arguments, stack)
                continue
            if opcode == convention.br_table:
                a = i.immediate_arguments[0]
                l = i.immediate_arguments[1]
                c = stack.pop().n
                if c >= 0 and c < len(a):
                    l = a[c]
                pc = spec_br(l, stack)
                continue
            if opcode == convention.return_:
                v = [stack.pop() for _ in range(frame.arity)][::-1]
                while True:
                    e = stack.pop()
                    if isinstance(e, Frame):
                        stack.add(e)
                        break
                stack.ext(v)
                break
            if opcode == convention.call:
                call(module, module.funcaddrs[i.immediate_arguments], store, stack)
                continue
            if opcode == convention.call_indirect:
                if i.immediate_arguments[1] != 0x00:
                    raise Exception("pywasm: zero byte malformed in call_indirect")
                idx = stack.pop().n
                tab = store.tables[module.tableaddrs[0]]
                if not 0 <= idx < len(tab.elem):
                    raise Exception('pywasm: undefined element index')
                call(module, tab.elem[idx], store, stack)
                continue
            continue
        if opcode == convention.drop:
            stack.pop()
            continue
        if opcode == convention.select:
            cond = stack.pop().n
            a = stack.pop()
            b = stack.pop()
            if cond:
                stack.add(b)
            else:
                stack.add(a)
            continue
        if opcode == convention.get_local:
            stack.add(frame.locals[i.immediate_arguments])
            continue
        if opcode == convention.set_local:
            if i.immediate_arguments >= len(frame.locals):
                frame.locals.extend(
                    [Value.from_i32(0) for _ in range(i.immediate_arguments - len(frame.locals) + 1)]
                )
            frame.locals[i.immediate_arguments] = stack.pop()
            continue
        if opcode == convention.tee_local:
            frame.locals[i.immediate_arguments] = stack.top()
            continue
        if opcode == convention.get_global:
            stack.add(store.globals[module.globaladdrs[i.immediate_arguments]].value)
            continue
        if opcode == convention.set_global:
            store.globals[module.globaladdrs[i.immediate_arguments]] = GlobalInstance(stack.pop(), True)
            continue
        if opcode >= convention.i32_load and opcode <= convention.grow_memory:
            m = store.mems[module.memaddrs[0]]
            if opcode >= convention.i32_load and opcode <= convention.i64_load32_u:
                a = stack.pop().n + i.immediate_arguments[1]
                if a + convention.opcodes[opcode][2] > len(m.data):
                    raise Exception('pywasm: out of bounds memory access')
                if opcode == convention.i32_load:
                    stack.add(Value.from_i32(num.LittleEndian.i32(m.data[a:a + 4])))
                    continue
                if opcode == convention.i64_load:
                    stack.add(Value.from_i64(num.LittleEndian.i64(m.data[a:a + 8])))
                    continue
                if opcode == convention.f32_load:
                    stack.add(Value.from_f32(num.LittleEndian.f32(m.data[a:a + 4])))
                    continue
                if opcode == convention.f64_load:
                    stack.add(Value.from_f64(num.LittleEndian.f64(m.data[a:a + 8])))
                    continue
                if opcode == convention.i32_load8_s:
                    stack.add(Value.from_i32(num.LittleEndian.i8(m.data[a:a + 1])))
                    continue
                if opcode == convention.i32_load8_u:
                    stack.add(Value.from_i32(num.LittleEndian.u8(m.data[a:a + 1])))
                    continue
                if opcode == convention.i32_load16_s:
                    stack.add(Value.from_i32(num.LittleEndian.i16(m.data[a:a + 2])))
                    continue
                if opcode == convention.i32_load16_u:
                    stack.add(Value.from_i32(num.LittleEndian.u16(m.data[a:a + 2])))
                    continue
                if opcode == convention.i64_load8_s:
                    stack.add(Value.from_i64(num.LittleEndian.i8(m.data[a:a + 1])))
                    continue
                if opcode == convention.i64_load8_u:
                    stack.add(Value.from_i64(num.LittleEndian.u8(m.data[a:a + 1])))
                    continue
                if opcode == convention.i64_load16_s:
                    stack.add(Value.from_i64(num.LittleEndian.i16(m.data[a:a + 2])))
                    continue
                if opcode == convention.i64_load16_u:
                    stack.add(Value.from_i64(num.LittleEndian.u16(m.data[a:a + 2])))
                    continue
                if opcode == convention.i64_load32_s:
                    stack.add(Value.from_i64(num.LittleEndian.i32(m.data[a:a + 4])))
                    continue
                if opcode == convention.i64_load32_u:
                    stack.add(Value.from_i64(num.LittleEndian.u32(m.data[a:a + 4])))
                    continue
                continue
            if opcode >= convention.i32_store and opcode <= convention.i64_store32:
                v = stack.pop().n
                a = stack.pop().n + i.immediate_arguments[1]
                if a + convention.opcodes[opcode][2] > len(m.data):
                    raise Exception('pywasm: out of bounds memory access')
                if opcode == convention.i32_store:
                    m.data[a:a + 4] = num.LittleEndian.pack_i32(v)
                    continue
                if opcode == convention.i64_store:
                    m.data[a:a + 8] = num.LittleEndian.pack_i64(v)
                    continue
                if opcode == convention.f32_store:
                    m.data[a:a + 4] = num.LittleEndian.pack_f32(v)
                    continue
                if opcode == convention.f64_store:
                    m.data[a:a + 8] = num.LittleEndian.pack_f64(v)
                    continue
                if opcode == convention.i32_store8:
                    m.data[a:a + 1] = num.LittleEndian.pack_i8(num.int2i8(v))
                    continue
                if opcode == convention.i32_store16:
                    m.data[a:a + 2] = num.LittleEndian.pack_i16(num.int2i16(v))
                    continue
                if opcode == convention.i64_store8:
                    m.data[a:a + 1] = num.LittleEndian.pack_i8(num.int2i8(v))
                    continue
                if opcode == convention.i64_store16:
                    m.data[a:a + 2] = num.LittleEndian.pack_i16(num.int2i16(v))
                    continue
                if opcode == convention.i64_store32:
                    m.data[a:a + 4] = num.LittleEndian.pack_i32(num.int2i32(v))
                    continue
                continue
            if opcode == convention.current_memory:
                stack.add(Value.from_i32(m.size))
                continue
            if opcode == convention.grow_memory:
                cursize = m.size
                m.grow(stack.pop().n)
                stack.add(Value.from_i32(cursize))
                continue
            continue
        if opcode >= convention.i32_const and opcode <= convention.f64_const:
            if opcode == convention.i32_const:
                stack.add(Value.from_i32(i.immediate_arguments))
                continue
            if opcode == convention.i64_const:
                stack.add(Value.from_i64(i.immediate_arguments))
                continue
            if opcode == convention.f32_const:
                stack.add(Value.from_f32(i.immediate_arguments))
                continue
            if opcode == convention.f64_const:
                stack.add(Value.from_f64(i.immediate_arguments))
                continue
            continue
        if opcode == convention.i32_eqz:
            stack.add(Value.from_i32(int(stack.pop().n == 0)))
            continue
        if opcode >= convention.i32_eq and opcode <= convention.i32_geu:
            b = stack.pop().n
            a = stack.pop().n
            if opcode == convention.i32_eq:
                stack.add(Value.from_i32(int(a == b)))
                continue
            if opcode == convention.i32_ne:
                stack.add(Value.from_i32(int(a != b)))
                continue
            if opcode == convention.i32_lts:
                stack.add(Value.from_i32(int(a < b)))
                continue
            if opcode == convention.i32_ltu:
                stack.add(Value.from_i32(int(num.int2u32(a) < num.int2u32(b))))
                continue
            if opcode == convention.i32_gts:
                stack.add(Value.from_i32(int(a > b)))
                continue
            if opcode == convention.i32_gtu:
                stack.add(Value.from_i32(int(num.int2u32(a) > num.int2u32(b))))
                continue
            if opcode == convention.i32_les:
                stack.add(Value.from_i32(int(a <= b)))
                continue
            if opcode == convention.i32_leu:
                stack.add(Value.from_i32(int(num.int2u32(a) <= num.int2u32(b))))
                continue
            if opcode == convention.i32_ges:
                stack.add(Value.from_i32(int(a >= b)))
                continue
            if opcode == convention.i32_geu:
                stack.add(Value.from_i32(int(num.int2u32(a) >= num.int2u32(b))))
                continue
            continue
        if opcode == convention.i64_eqz:
            stack.add(Value.from_i32(int(stack.pop().n == 0)))
            continue
        if opcode >= convention.i64_eq and opcode <= convention.i64_geu:
            b = stack.pop().n
            a = stack.pop().n
            if opcode == convention.i64_eq:
                stack.add(Value.from_i32(int(a == b)))
                continue
            if opcode == convention.i64_ne:
                stack.add(Value.from_i32(int(a != b)))
                continue
            if opcode == convention.i64_lts:
                stack.add(Value.from_i32(int(a < b)))
                continue
            if opcode == convention.i64_ltu:
                stack.add(Value.from_i32(int(num.int2u64(a) < num.int2u64(b))))
                continue
            if opcode == convention.i64_gts:
                stack.add(Value.from_i32(int(a > b)))
                continue
            if opcode == convention.i64_gtu:
                stack.add(Value.from_i32(int(num.int2u64(a) > num.int2u64(b))))
                continue
            if opcode == convention.i64_les:
                stack.add(Value.from_i32(int(a <= b)))
                continue
            if opcode == convention.i64_leu:
                stack.add(Value.from_i32(int(num.int2u64(a) <= num.int2u64(b))))
                continue
            if opcode == convention.i64_ges:
                stack.add(Value.from_i32(int(a >= b)))
                continue
            if opcode == convention.i64_geu:
                stack.add(Value.from_i32(int(num.int2u64(a) >= num.int2u64(b))))
                continue
            continue
        if opcode >= convention.f32_eq and opcode <= convention.f64_ge:
            b = stack.pop().n
            a = stack.pop().n
            if opcode == convention.f32_eq:
                stack.add(Value.from_i32(int(a == b)))
                continue
            if opcode == convention.f32_ne:
                stack.add(Value.from_i32(int(a != b)))
                continue
            if opcode == convention.f32_lt:
                stack.add(Value.from_i32(int(a < b)))
                continue
            if opcode == convention.f32_gt:
                stack.add(Value.from_i32(int(a > b)))
                continue
            if opcode == convention.f32_le:
                stack.add(Value.from_i32(int(a <= b)))
                continue
            if opcode == convention.f32_ge:
                stack.add(Value.from_i32(int(a >= b)))
                continue
            if opcode == convention.f64_eq:
                stack.add(Value.from_i32(int(a == b)))
                continue
            if opcode == convention.f64_ne:
                stack.add(Value.from_i32(int(a != b)))
                continue
            if opcode == convention.f64_lt:
                stack.add(Value.from_i32(int(a < b)))
                continue
            if opcode == convention.f64_gt:
                stack.add(Value.from_i32(int(a > b)))
                continue
            if opcode == convention.f64_le:
                stack.add(Value.from_i32(int(a <= b)))
                continue
            if opcode == convention.f64_ge:
                stack.add(Value.from_i32(int(a >= b)))
                continue
            continue
        if opcode >= convention.i32_clz and opcode <= convention.i32_popcnt:
            a = stack.pop().n
            if opcode == convention.i32_clz:
                c = 0
                while c < 32 and (a & 0x80000000) == 0:
                    c += 1
                    a *= 2
                stack.add(Value.from_i32(c))
                continue
            if opcode == convention.i32_ctz:
                c = 0
                while c < 32 and (a % 2) == 0:
                    c += 1
                    a /= 2
                stack.add(Value.from_i32(c))
                continue
            if opcode == convention.i32_popcnt:
                c = 0
                for i in range(32):
                    if 0x1 & a:
                        c += 1
                    a /= 2
                stack.add(Value.from_i32(c))
                continue
            continue
        if opcode >= convention.i32_add and opcode <= convention.i32_rotr:
            b = stack.pop().n
            a = stack.pop().n
            if opcode in [
                convention.i32_divs,
                convention.i32_divu,
                convention.i32_rems,
                convention.i32_remu,
            ]:
                if b == 0:
                    raise Exception('pywasm: integer divide by zero')
            if opcode == convention.i32_add:
                stack.add(Value.from_i32(num.int2i32(a + b)))
                continue
            if opcode == convention.i32_sub:
                stack.add(Value.from_i32(num.int2i32(a - b)))
                continue
            if opcode == convention.i32_mul:
                stack.add(Value.from_i32(num.int2i32(a * b)))
                continue
            if opcode == convention.i32_divs:
                if a == 0x80000000 and b == -1:
                    raise Exception('pywasm: integer overflow')
                stack.add(Value.from_i32(num.idiv_s(a, b)))
                continue
            if opcode == convention.i32_divu:
                stack.add(Value.from_i32(num.int2i32(num.int2u32(a) // num.int2u32(b))))
                continue
            if opcode == convention.i32_rems:
                stack.add(Value.from_i32(num.irem_s(a, b)))
                continue
            if opcode == convention.i32_remu:
                stack.add(Value.from_i32(num.int2i32(num.int2u32(a) % num.int2u32(b))))
                continue
            if opcode == convention.i32_and:
                stack.add(Value.from_i32(a & b))
                continue
            if opcode == convention.i32_or:
                stack.add(Value.from_i32(a | b))
                continue
            if opcode == convention.i32_xor:
                stack.add(Value.from_i32(a ^ b))
                continue
            if opcode == convention.i32_shl:
                stack.add(Value.from_i32(num.int2i32(a << (b % 0x20))))
                continue
            if opcode == convention.i32_shrs:
                stack.add(Value.from_i32(a >> (b % 0x20)))
                continue
            if opcode == convention.i32_shru:
                stack.add(Value.from_i32(num.int2u32(a) >> (b % 0x20)))
                continue
            if opcode == convention.i32_rotl:
                stack.add(Value.from_i32(num.int2i32(num.rotl_u32(a, b))))
                continue
            if opcode == convention.i32_rotr:
                stack.add(Value.from_i32(num.int2i32(num.rotr_u32(a, b))))
                continue
            continue
        if opcode >= convention.i64_clz and opcode <= convention.i64_popcnt:
            a = stack.pop().n
            if opcode == convention.i64_clz:
                if a < 0:
                    stack.add(Value.from_i32(0))
                    continue
                c = 1
                while c < 63 and (a & 0x4000000000000000) == 0:
                    c += 1
                    a *= 2
                stack.add(Value.from_i64(c))
                continue
            if opcode == convention.i64_ctz:
                c = 0
                while c < 64 and (a % 2) == 0:
                    c += 1
                    a /= 2
                stack.add(Value.from_i64(c))
                continue
            if opcode == convention.i64_popcnt:
                c = 0
                for i in range(64):
                    if 0x1 & a:
                        c += 1
                    a /= 2
                stack.add(Value.from_i64(c))
                continue
            continue
        if opcode >= convention.i64_add and opcode <= convention.i64_rotr:
            b = stack.pop().n
            a = stack.pop().n
            if opcode in [
                convention.i64_divs,
                convention.i64_divu,
                convention.i64_rems,
                convention.i64_remu,
            ]:
                if b == 0:
                    raise Exception('pywasm: integer divide by zero')
            if opcode == convention.i64_add:
                stack.add(Value.from_i64(num.int2i64(a + b)))
                continue
            if opcode == convention.i64_sub:
                stack.add(Value.from_i64(num.int2i64(a - b)))
                continue
            if opcode == convention.i64_mul:
                stack.add(Value.from_i64(num.int2i64(a * b)))
                continue
            if opcode == convention.i64_divs:
                stack.add(Value.from_i64(num.idiv_s(a, b)))
                continue
            if opcode == convention.i64_divu:
                stack.add(Value.from_i64(num.int2i64(num.int2u64(a) // num.int2u64(b))))
                continue
            if opcode == convention.i64_rems:
                stack.add(Value.from_i64(num.irem_s(a, b)))
            if opcode == convention.i64_remu:
                stack.add(Value.from_i64(num.int2u64(a) % num.int2u64(b)))
                continue
            if opcode == convention.i64_and:
                stack.add(Value.from_i64(a & b))
                continue
            if opcode == convention.i64_or:
                stack.add(Value.from_i64(a | b))
                continue
            if opcode == convention.i64_xor:
                stack.add(Value.from_i64(a ^ b))
                continue
            if opcode == convention.i64_shl:
                stack.add(Value.from_i64(num.int2i64(a << (b % 0x40))))
                continue
            if opcode == convention.i64_shrs:
                stack.add(Value.from_i64(a >> (b % 0x40)))
                continue
            if opcode == convention.i64_shru:
                stack.add(Value.from_i64(num.int2u64(a) >> (b % 0x40)))
                continue
            if opcode == convention.i64_rotl:
                stack.add(Value.from_i64(num.int2i64(num.rotl_u64(a, b))))
                continue
            if opcode == convention.i64_rotr:
                stack.add(Value.from_i64(num.int2i64(num.rotr_u64(a, b))))
                continue
            continue
        if opcode >= convention.f32_abs and opcode <= convention.f32_sqrt:
            a = stack.pop().n
            if opcode == convention.f32_abs:
                stack.add(Value.from_f32(abs(a)))
                continue
            if opcode == convention.f32_neg:
                stack.add(Value.from_f32(-a))
                continue
            if opcode == convention.f32_ceil:
                stack.add(Value.from_f32(math.ceil(a)))
                continue
            if opcode == convention.f32_floor:
                stack.add(Value.from_f32(math.floor(a)))
                continue
            if opcode == convention.f32_trunc:
                stack.add(Value.from_f32(math.trunc(a)))
                continue
            if opcode == convention.f32_nearest:
                ceil = math.ceil(a)
                if ceil - a >= 0.5:
                    r = ceil
                else:
                    r = ceil - 1
                stack.add(Value.from_f32(r))
                continue
            if opcode == convention.f32_sqrt:
                stack.add(Value.from_f32(math.sqrt(a)))
                continue
            continue
        if opcode >= convention.f32_add and opcode <= convention.f32_copysign:
            b = stack.pop().n
            a = stack.pop().n
            if opcode == convention.f32_add:
                stack.add(Value.from_f32(a + b))
                continue
            if opcode == convention.f32_sub:
                stack.add(Value.from_f32(a - b))
                continue
            if opcode == convention.f32_mul:
                stack.add(Value.from_f32(a * b))
                continue
            if opcode == convention.f32_div:
                stack.add(Value.from_f32(a / b))
                continue
            if opcode == convention.f32_min:
                stack.add(Value.from_f32(min(a, b)))
                continue
            if opcode == convention.f32_max:
                stack.add(Value.from_f32(max(a, b)))
                continue
            if opcode == convention.f32_copysign:
                stack.add(Value.from_f32(math.copysign(a, b)))
                continue
            continue
        if opcode >= convention.f64_abs and opcode <= convention.f64_sqrt:
            a = stack.pop().n
            if opcode == convention.f64_abs:
                stack.add(Value.from_f64(abs(a)))
                continue
            if opcode == convention.f64_neg:
                stack.add(Value.from_f64(-a))
                continue
            if opcode == convention.f64_ceil:
                stack.add(Value.from_f64(math.ceil(a)))
                continue
            if opcode == convention.f64_floor:
                stack.add(Value.from_f64(math.floor(a)))
                continue
            if opcode == convention.f64_trunc:
                stack.add(Value.from_f64(math.trunc(a)))
                continue
            if opcode == convention.f64_nearest:
                ceil = math.ceil(a)
                if ceil - a >= 0.5:
                    r = ceil
                else:
                    r = ceil - 1
                stack.add(Value.from_f64(r))
                continue
            if opcode == convention.f64_sqrt:
                stack.add(Value.from_f64(math.sqrt(a)))
                continue
            continue
        if opcode >= convention.f64_add and opcode <= convention.f64_copysign:
            b = stack.pop().n
            a = stack.pop().n
            if opcode == convention.f64_add:
                stack.add(Value.from_f64(a + b))
                continue
            if opcode == convention.f64_sub:
                stack.add(Value.from_f64(a - b))
                continue
            if opcode == convention.f64_mul:
                stack.add(Value.from_f64(a * b))
                continue
            if opcode == convention.f64_div:
                stack.add(Value.from_f64(a / b))
                continue
            if opcode == convention.f64_min:
                stack.add(Value.from_f64(min(a, b)))
                continue
            if opcode == convention.f64_max:
                stack.add(Value.from_f64(max(a, b)))
                continue
            if opcode == convention.f64_copysign:
                stack.add(Value.from_f64(math.copysign(a, b)))
                continue
            continue
        if opcode >= convention.i32_wrap_i64 and opcode <= convention.f64_promote_f32:
            a = stack.pop().n
            if opcode in [
                convention.i32_trunc_sf32,
                convention.i32_trunc_uf32,
                convention.i32_trunc_sf64,
                convention.i32_trunc_uf64,
                convention.i64_trunc_sf32,
                convention.i64_trunc_uf32,
                convention.i64_trunc_sf64,
                convention.i64_trunc_uf64,
            ]:
                if math.isnan(a):
                    raise Exception('pywasm: invalid conversion to integer')
            if opcode == convention.i32_wrap_i64:
                stack.add(Value.from_i32(num.int2i32(a)))
                continue
            if opcode == convention.i32_trunc_sf32:
                if a > 2**31 - 1 or a < -2**32:
                    raise Exception('pywasm: integer overflow')
                stack.add(Value.from_i32(int(a)))
                continue
            if opcode == convention.i32_trunc_uf32:
                if a > 2**32 - 1 or a < -1:
                    raise Exception('pywasm: integer overflow')
                stack.add(Value.from_i32(int(a)))
                continue
            if opcode == convention.i32_trunc_sf64:
                if a > 2**31 - 1 or a < -2**32:
                    raise Exception('pywasm: integer overflow')
                stack.add(Value.from_i32(int(a)))
                continue
            if opcode == convention.i32_trunc_uf64:
                if a > 2**32 - 1 or a < -1:
                    raise Exception('pywasm: integer overflow')
                stack.add(Value.from_i32(int(a)))
                continue
            if opcode == convention.i64_extend_si32:
                stack.add(Value.from_i64(a))
                continue
            if opcode == convention.i64_extend_ui32:
                stack.add(Value.from_i64(num.int2u32(a)))
                continue
            if opcode == convention.i64_trunc_sf32:
                if a > 2**63 - 1 or a < -2**63:
                    raise Exception('pywasm: integer overflow')
                stack.add(Value.from_i64(int(a)))
                continue
            if opcode == convention.i64_trunc_uf32:
                if a > 2**63 - 1 or a < -1:
                    raise Exception('pywasm: integer overflow')
                stack.add(Value.from_i64(int(a)))
                continue
            if opcode == convention.i64_trunc_sf64:
                stack.add(Value.from_i64(int(a)))
                continue
            if opcode == convention.i64_trunc_uf64:
                if a < -1:
                    raise Exception('pywasm: integer overflow')
                stack.add(Value.from_i64(int(a)))
                continue
            if opcode == convention.f32_convert_si32:
                stack.add(Value.from_f32(a))
                continue
            if opcode == convention.f32_convert_ui32:
                stack.add(Value.from_f32(num.int2u32(a)))
                continue
            if opcode == convention.f32_convert_si64:
                stack.add(Value.from_f32(a))
                continue
            if opcode == convention.f32_convert_ui64:
                stack.add(Value.from_f32(num.int2u64(a)))
                continue
            if opcode == convention.f32_demote_f64:
                stack.add(Value.from_f32(a))
                continue
            if opcode == convention.f64_convert_si32:
                stack.add(Value.from_f64(a))
                continue
            if opcode == convention.f64_convert_ui32:
                stack.add(Value.from_f64(num.int2u32(a)))
                continue
            if opcode == convention.f64_convert_si64:
                stack.add(Value.from_f64(a))
                continue
            if opcode == convention.f64_convert_ui64:
                stack.add(Value.from_f64(num.int2u64(a)))
                continue
            if opcode == convention.f64_promote_f32:
                stack.add(Value.from_f64(a))
                continue
            continue
        if opcode >= convention.i32_reinterpret_f32 and opcode <= convention.f64_reinterpret_i64:
            a = stack.pop().n
            if opcode == convention.i32_reinterpret_f32:
                stack.add(Value.from_i32(num.f322i32(a)))
                continue
            if opcode == convention.i64_reinterpret_f64:
                stack.add(Value.from_i64(num.f642i64(a)))
                continue
            if opcode == convention.f32_reinterpret_i32:
                stack.add(Value.from_f32(num.i322f32(a)))
                continue
            if opcode == convention.f64_reinterpret_i64:
                stack.add(Value.from_f64(num.i642f64(a)))
                continue
            continue

    return stack.data[-frame.arity:]
Exemple #6
0
    def instantiate(
        self,
        module: structure.Module,
        store: Store,
        externvals: typing.List[ExternValue] = None,
    ):
        self.types = module.types
        # [TODO] If module is not valid, then panic
        # Assert: module is valid with external types classifying its imports
        for e in module.imports:
            assert e.kind in convention.extern_type
        # Assert: number m of imports is equal to the number n of provided external values
        assert len(module.imports) == len(externvals)
        # Assert: externvals matching imports of module
        for i in range(len(externvals)):
            e = externvals[i]
            assert e.extern_type in convention.extern_type
            if e.extern_type == convention.extern_func:
                a = store.funcs[e.addr]
                b = self.types[module.imports[i].desc]
                assert a.functype.args == b.args
                assert a.functype.rets == b.rets
            elif e.extern_type == convention.extern_table:
                a = store.tables[e.addr]
                b = module.imports[i].desc
                assert a.elemtype == b.elemtype
                assert import_matching_limits(b.limits, a.limits)
            elif e.extern_type == convention.extern_mem:
                a = store.mems[e.addr]
                b = module.imports[i].desc
                assert import_matching_limits(b, a)
            elif e.extern_type == convention.extern_global:
                a = store.globals[e.addr]
                b = module.imports[i].desc
                assert a.value.valtype == b.valtype
        # Let vals be the vector of global initialization values determined by module and externvaln
        auxmod = ModuleInstance()
        auxmod.globaladdrs = [e.addr for e in externvals if e.extern_type == convention.extern_global]
        stack = Stack()
        frame = Frame(auxmod, [], 1, -1)
        vals = []
        for glob in module.globals:
            stack.add(frame)
            v = exec_expr(store, frame, stack, glob.expr)[0]
            vals.append(v)
        # Allocation
        self.allocate(module, store, externvals, vals)

        frame = Frame(self, [], 1, -1)
        # For each element segment in module.elem, do:
        for e in module.elem:
            stack.add(frame)
            offset = exec_expr(store, frame, stack, e.expr)[0]
            assert offset.valtype == convention.i32
            t = store.tables[self.tableaddrs[e.tableidx]]
            for i, e in enumerate(e.init):
                t.elem[offset.n + i] = e
        # For each data segment in module.data, do:
        for e in module.data:
            stack.add(frame)
            offset = exec_expr(store, frame, stack, e.expr)[0]
            assert offset.valtype == convention.i32
            m = store.mems[self.memaddrs[e.memidx]]
            end = offset.n + len(e.init)
            assert end <= len(m.data)
            m.data[offset.n: offset.n + len(e.init)] = e.init
        # If the start function module.start is not empty, invoke the function instance
        if module.start is not None:
            log.debugln(f'Running start function {module.start}:')
            call(self, module.start, store, stack)