diff --git a/examples/chip8.zr b/examples/chip8.zr index 48d1cc0..bddafec 100644 --- a/examples/chip8.zr +++ b/examples/chip8.zr @@ -22,7 +22,7 @@ struct CHIP8 keyboard_map: Array func chip8_create[] : CHIP8 - let c = new CHIP8 + let c = new* CHIP8 c->memory = mem.alloc(4096) mem.zero(c->memory, 4096) c->display = mem.alloc(64*32) diff --git a/src/codegen_x86_64.rs b/src/codegen_x86_64.rs index c2d5fc9..852b7f8 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 8f694d6..2fc3b60 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, @@ -621,9 +624,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 1e0d5d0..e90625c 100644 --- a/src/std/net.zr +++ b/src/std/net.zr @@ -95,7 +95,7 @@ struct net.UDPPacket func net.create_udp_client?[packed_host: i64, port: i64] : net.UDPSocket err.clear() - let s = new net.UDPSocket + let s = new* net.UDPSocket s->fd = _builtin_syscall(SYS_socket, AF_INET, SOCK_DGRAM, 0) if s->fd < 0 @@ -132,7 +132,7 @@ 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) func net.udp_receive[s: net.UDPSocket, size: i64] : net.UDPPacket - let pkt = new net.UDPPacket + let pkt = new* net.UDPPacket pkt->data = mem.alloc(size) pkt->source_addr = mem.alloc(16) mem.zero(pkt->source_addr, 16) diff --git a/src/std/std.zr b/src/std/std.zr index e9b8349..9907b3a 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() - let buffer = new io.Buffer + let 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 - let buf = new io.Buffer + let 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 - let xs = new Array + let 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 - let map = new HashMap + let 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 - let new_node = new HashMap._Node + let 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 let 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 let tv = new os.Timeval _builtin_syscall(SYS_gettimeofday, tv, 0) let 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 cc90935..055d249 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,