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}')
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
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
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
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:]
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)