def free(self, size: int): if size < 0: raise errors.AtomCVMRuntimeError("negative size") if self._sp - size < 0: raise errors.AtomCVMRuntimeError("stack buffer underflow") self._sp -= size self._stack[self._sp:self._sp + size] = _sentinel(0xDEADBEEF, size)
def push(self, value, value_type: DataType): if not isinstance(value, value_type.python_type): raise errors.AtomCVMRuntimeError("wrong value type for push") try: self._push_bytes(struct.pack(value_type.fmt, value)) except struct.error as e: raise errors.AtomCVMRuntimeError(f"push error: {str(e)}")
def alloc(self, size: int): if size < 0: raise errors.AtomCVMRuntimeError("negative size") if self._sp + size > self._size: raise errors.AtomCVMRuntimeError("out of stack memory") ret = self._sp self._stack[self._sp:self._sp + size] = _sentinel(0xBAADF00D, size) self._sp += size return ret
def read_string(self, addr: int) -> str: if addr < 0: raise errors.AtomCVMRuntimeError("out-of-bounds memory access") end = addr while self._stack[end] != 0 and end < self._size: end += 1 if end >= self._size: raise errors.AtomCVMRuntimeError( "stack overflow while reading string") return self._stack[addr:end].decode('utf8')
def pop(self, value_type: DataType): try: return value_type.python_type( struct.unpack(value_type.fmt, bytes(self._pop_bytes(value_type.size)))[0]) except struct.error as e: raise errors.AtomCVMRuntimeError(f"pop error: {str(e)}")
def ip(self, addr: int): if addr not in range(0, len(self.program)): raise errors.AtomCVMRuntimeError( "Instruction pointer jumped out of program memory") self._ip = addr self._ip_jumped = True self._print_debug(f"ip jumped to {self.ip}")
def exec_builtin(name: str, st: 'stack.DataStack'): if name == 'put_s': _stdout(st.read_string(st.popa())) elif name == 'put_i': _stdout(st.popi()) elif name == 'put_d': _stdout(st.popd()) elif name == 'put_c': _stdout(chr(st.popc())) elif name == 'get_s': addr = st.popa() data = _stdin() st.write_at(addr, data.encode('utf8') + b'\0') st.pusha(addr) _stdout(data + '\n') elif name == 'get_i': val = int(_stdin()) st.pushi(val) _stdout(str(val) + '\n') elif name == 'get_d': val = float(_stdin()) st.pushd(val) _stdout(str(val) + '\n') elif name == 'get_c': val = ord(_stdin()) st.pushc(val) _stdout(str(val) + '\n') elif name == 'seconds': st.pushd(float(time.monotonic())) else: raise errors.AtomCVMRuntimeError(f"Undefined builtin function {name}")
def execute(self): while not self._halted: if self.ip not in range(0, len(self.program)): raise errors.AtomCVMRuntimeError( "Instruction pointer outside program memory") instr = self.program[self._ip] self._ip_jumped = False self._print_debug(f"executing `{instr}`@{instr.lineno}") instr.execute(self) if not self._ip_jumped: self._ip += 1
def _pop_bytes(self, count: int) -> bytearray: if self._sp - count < 0: raise errors.AtomCVMRuntimeError("stack buffer underflow") self._sp -= count return self._stack[self._sp:self._sp + count]
def _push_bytes(self, data: bytes): if self._sp + len(data) > self._size: raise errors.AtomCVMRuntimeError("out of stack memory") self._sp += len(data) self._stack[self._sp - len(data):self._sp] = data
def ret(self) -> int: if not self.stack: raise errors.AtomCVMRuntimeError("unbalanced call stack") return self.stack.pop()
def write_at(self, addr: int, data: bytes): if addr < 0 or addr + len(data) >= self._size: raise errors.AtomCVMRuntimeError("out-of-bounds memory access") self._stack[addr:addr + len(data)] = data
def read_from(self, addr: int, size: int) -> bytes: if size < 0: raise errors.AtomCVMRuntimeError("negative size") if addr < 0 or size < 0 or addr + size >= self._size: raise errors.AtomCVMRuntimeError("out-of-bounds memory access") return bytes(self._stack[addr:addr + size])
def __init__(self, from_type: 'stack.DataStack.DataType', to_type: 'stack.DataStack.DataType', lineno: int): super().__init__(f'CAST_{self.type_suffix(from_type)}_{self.type_suffix(to_type)}', lineno) self.from_type = from_type self.to_type = to_type if from_type == stack.ADDR or to_type == stack.ADDR: raise errors.AtomCVMRuntimeError(f"CAST cannot operate on addresses")
def __init__(self, data_type: 'stack.DataStack.DataType', op, mnemonic: str, lineno: int): super().__init__(mnemonic, lineno) self.data_type = data_type self.op = op if data_type == stack.ADDR: raise errors.AtomCVMRuntimeError("pointer arithmetic is not allowed")
def __init__(self, data_type: 'stack.DataStack.DataType', lineno: int): super().__init__('NEG_' + self.type_suffix(data_type), lineno) self.data_type = data_type if data_type == stack.ADDR: raise errors.AtomCVMRuntimeError("pointer arithmetic is not allowed")