diff --git a/examples/chip8.zr b/examples/chip8.zr index 801f202..11e65e3 100644 --- a/examples/chip8.zr +++ b/examples/chip8.zr @@ -22,7 +22,7 @@ struct CHIP8 keyboard_map: Array func chip8_create[] : CHIP8 - c := new CHIP8 + c := new* CHIP8 c->memory = mem.alloc(4096) mem.zero(c->memory, 4096) c->display = mem.alloc(64*32) diff --git a/examples/tcp_server.zr b/examples/tcp_server.zr index 6e7ed00..7028d26 100644 --- a/examples/tcp_server.zr +++ b/examples/tcp_server.zr @@ -2,12 +2,19 @@ func main[] : i64 s : i64 = must(net.listen?(net.pack_addr(127, 0, 0, 1), 8000)) io.println("Listening on port 8000...") + resp := mem.alloc(60000) + addr := mem.alloc(16) while true - conn := net.accept(s) + conn := net.accept(s, addr) if conn < 0 continue + io.printf("%d.%d.%d.%d:%d\n", addr[4], addr[5], addr[6], addr[7], mem.read16be(addr + 2)) + + io.print_sized(resp, n) + io.println("") + n := net.read(conn, resp, 60000) net.send(conn, resp, n) net.close(conn) diff --git a/examples/udp_server.zr b/examples/udp_server.zr index 48f4e5b..ea86539 100644 --- a/examples/udp_server.zr +++ b/examples/udp_server.zr @@ -8,5 +8,10 @@ func main[] : i64 net.UDPPacket.free(pkt) continue + io.printf("%d.%d.%d.%d:%d\n", pkt->source_addr[4], pkt->source_addr[5], pkt->source_addr[6], pkt->source_addr[7], mem.read16be(pkt->source_addr + 2)) + + io.print_sized(pkt->data, pkt->size) + io.println("") + net.udp_send_to(s, pkt->source_addr, pkt->data, pkt->size) net.UDPPacket.free(pkt) diff --git a/src/codegen_x86_64.rs b/src/codegen_x86_64.rs index 67c5ea2..1405c47 100644 --- a/src/codegen_x86_64.rs +++ b/src/codegen_x86_64.rs @@ -12,6 +12,8 @@ struct Var { pub var_type: String, } +const STACK_SIZE: usize = 256; // TODO: eww + pub struct Env { scopes: Vec>, next_offset: usize, @@ -300,7 +302,8 @@ _builtin_environ: emit!(&mut self.output, "{}:", name.lexeme); emit!(&mut self.output, " push rbp"); emit!(&mut self.output, " mov rbp, rsp"); - emit!(&mut self.output, " sub rsp, 256"); // TODO: eww + let stack_size = (STACK_SIZE + 15) & !15; + emit!(&mut self.output, " sub rsp, {}", stack_size); match params { Params::Normal(params) => { @@ -730,16 +733,28 @@ _builtin_environ: return error!(&op.loc, "can only take address of variables and functions"); } }, - ExprKind::New(struct_name) => { + ExprKind::New { + struct_name, + use_heap, + } => { let struct_fields = &self.symbol_table.structs[&struct_name.lexeme]; - let memory_size = struct_fields.len() * 8; - emit!(&mut self.output, " mov rdi, {}", memory_size); - emit!(&mut self.output, " call mem.alloc"); + + if *use_heap { + emit!(&mut self.output, " mov rdi, {}", memory_size); + emit!(&mut self.output, " call mem.alloc"); + emit!(&mut self.output, " push rax"); + } else { + let aligned_size = (memory_size + 15) & !15; + emit!(&mut self.output, " sub rsp, {}", aligned_size); + emit!(&mut self.output, " mov rax, rsp"); + } emit!(&mut self.output, " push rax"); + emit!(&mut self.output, " sub rsp, 8"); emit!(&mut self.output, " mov rdi, rax"); emit!(&mut self.output, " mov rsi, {}", memory_size); emit!(&mut self.output, " call mem.zero"); + emit!(&mut self.output, " add rsp, 8"); emit!(&mut self.output, " pop rax"); } ExprKind::MemberAccess { left, field } => { diff --git a/src/parser.rs b/src/parser.rs index a65f4f6..ad13782 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -121,7 +121,10 @@ pub enum ExprKind { op: Token, expr: Box, }, - New(Token), + New { + struct_name: Token, + use_heap: bool, + }, MemberAccess { left: Box, field: Token, @@ -616,9 +619,13 @@ impl Parser { Ok(Expr::new(ExprKind::ArrayLiteral(xs))) } else if self.match_token(&[TokenType::KeywordNew]) { + let use_heap = self.match_token(&[TokenType::Star]); let struct_name = self.consume(TokenType::Identifier, "expected struct name after 'new'")?; - Ok(Expr::new(ExprKind::New(struct_name))) + Ok(Expr::new(ExprKind::New { + struct_name, + use_heap, + })) } else if self.match_token(&[TokenType::Identifier]) { Ok(Expr::new(ExprKind::Variable(self.previous().clone()))) } else { diff --git a/src/std/net.zr b/src/std/net.zr index 896f532..cba8b5e 100644 --- a/src/std/net.zr +++ b/src/std/net.zr @@ -69,8 +69,9 @@ func net.connect?[packed_host: i64, port: i64] : i64 mem.free(sa) return s -func net.accept[s: i64] : i64 - return _builtin_syscall(SYS_accept, s, 0, 0) +func net.accept[s: i64, addr: ptr] : i64 + let addrlen = 16 + return _builtin_syscall(SYS_accept, s, addr, ^addrlen) func net.send[s: i64, data: ptr, size: i64] : void _builtin_syscall(SYS_sendto, s, data, size, 0, 0, 0) @@ -88,14 +89,9 @@ struct net.UDPSocket fd: i64 addr: ptr -struct net.UDPPacket - data: ptr - source_addr: ptr - size: i64 - func net.create_udp_client?[packed_host: i64, port: i64] : net.UDPSocket err.clear() - s := new net.UDPSocket + s := new* net.UDPSocket s->fd = _builtin_syscall(SYS_socket, AF_INET, SOCK_DGRAM, 0) if s->fd < 0 @@ -131,8 +127,18 @@ func net.create_udp_server?[packed_host: i64, port: i64] : net.UDPSocket func net.udp_send_to[s: net.UDPSocket, addr: ptr, data: ptr, size: i64] : void _builtin_syscall(SYS_sendto, s->fd, data, size, 0, addr, 16) +struct net.UDPPacket + data: ptr + source_addr: ptr + size: i64 + +func net.UDPPacket.free[pkt: net.UDPPacket] : void + mem.free(pkt->data) + mem.free(pkt->source_addr) + mem.free(pkt) + func net.udp_receive[s: net.UDPSocket, size: i64] : net.UDPPacket - pkt := new net.UDPPacket + pkt := new* net.UDPPacket pkt->data = mem.alloc(size) pkt->source_addr = mem.alloc(16) mem.zero(pkt->source_addr, 16) @@ -146,11 +152,6 @@ func net.UDPSocket.close_and_free[s: net.UDPSocket] : void mem.free(s->addr) mem.free(s) -func net.UDPPacket.free[pkt: net.UDPPacket] : void - mem.free(pkt->data) - mem.free(pkt->source_addr) - mem.free(pkt) - const DNS_TYPE_A = 1 const DNS_CLASS_IN = 1 const DNS_RECURSION_DESIRED = 256 @@ -195,7 +196,7 @@ func net.build_dns_query[domain_name: str, record_type: i64] : io.Buffer io.Buffer.free(name) return out -// TODO: dont resolve IPs +// TODO: dont resolve if its already an IP func net.resolve?[domain: str] : i64 err.clear() query := net.build_dns_query(domain, DNS_TYPE_A) diff --git a/src/std/std.zr b/src/std/std.zr index 5394043..1f498ee 100644 --- a/src/std/std.zr +++ b/src/std/std.zr @@ -339,7 +339,7 @@ struct io.Buffer func io.Buffer.alloc?[size: i64] : io.Buffer err.clear() - buffer := new io.Buffer + buffer := new* io.Buffer buffer->size = size buffer->data = mem.alloc?(size) if err.check() @@ -403,7 +403,7 @@ func io.read_binary_file?[path: str] : io.Buffer err.set(ERR_OPEN_FAILED, "io.read_binary_file?: failed to open file") return 0 as io.Buffer - buf := new io.Buffer + buf := new* io.Buffer buf->size = _builtin_syscall(SYS_lseek, fd, 0, 2) _builtin_syscall(SYS_lseek, fd, 0, 0) @@ -777,10 +777,10 @@ struct Array capacity: i64 func array.new[] : Array - return new Array + return new* Array func array.new_preallocated_and_zeroed[size: i64] : Array - xs := new Array + xs := new* Array if size > 0 xs->data = must(mem.realloc?(xs->data, size * 8)) as ptr mem.zero(xs->data, size * 8) @@ -849,7 +849,7 @@ struct HashMap._Node next: HashMap._Node func HashMap.new[] : HashMap - map := new HashMap + map := new* HashMap map->table = array.new_preallocated_and_zeroed(HashMap._TABLE_SIZE) return map @@ -863,7 +863,7 @@ func HashMap.insert[map: HashMap, key: str, value: any] : void return 0 current = current->next - new_node := new HashMap._Node + new_node := new* HashMap._Node new_node->key = str.make_copy(key) new_node->value = value new_node->next = array.nth(map->table, index) @@ -982,12 +982,10 @@ struct os.Timespec func os.sleep[ms: i64] : void if ms < 0 panic("negative time passed to os.sleep") - // TODO: we really shouldnt need a heap allocation to sleep req := new os.Timespec req->tv_sec = ms / 1000 req->tv_nsec = (ms % 1000) * 1000000 _builtin_syscall(SYS_nanosleep, req, 0) - mem.free(req) func os.urandom?[n: i64]: ptr err.clear() @@ -1022,11 +1020,9 @@ struct os.Timeval tv_usec: i64 func os.time[] : i64 - // TODO: we really shouldnt need a heap allocation to check the time tv := new os.Timeval _builtin_syscall(SYS_gettimeofday, tv, 0) out := tv->tv_sec * 1000 + tv->tv_usec / 1000 - mem.free(tv) return out // voodoo magic diff --git a/src/typechecker.rs b/src/typechecker.rs index 6387f36..19a4aa4 100644 --- a/src/typechecker.rs +++ b/src/typechecker.rs @@ -483,7 +483,10 @@ impl<'a> TypeChecker<'a> { error!(&op.loc, "can only take address of variables and functions") } }, - ExprKind::New(struct_name) => { + ExprKind::New { + struct_name, + use_heap: _, + } => { if !self.symbol_table.structs.contains_key(&struct_name.lexeme) { return error!( &struct_name.loc,