@@ -14,17 +14,18 @@ pub struct Gen {
1414 env & types.Environment = unsafe { nil }
1515 pref & pref.Preferences = unsafe { nil }
1616mut :
17- sb strings.Builder
18- indent int
19- cur_fn_scope & types.Scope = unsafe { nil }
20- cur_fn_name string
21- cur_fn_ret_type string
22- cur_module string
23- emitted_types map [string ]bool
24- fn_param_is_ptr map [string ][]bool
25- fn_param_types map [string ][]string
26- fn_return_types map [string ]string
27- runtime_local_types map [string ]string
17+ sb strings.Builder
18+ indent int
19+ cur_fn_scope & types.Scope = unsafe { nil }
20+ cur_fn_name string
21+ cur_fn_ret_type string
22+ cur_module string
23+ emitted_types map [string ]bool
24+ fn_param_is_ptr map [string ][]bool
25+ fn_param_types map [string ][]string
26+ fn_return_types map [string ]string
27+ fn_names_in_decl_order []string
28+ runtime_local_types map [string ]string
2829
2930 fixed_array_fields map [string ]bool
3031 fixed_array_field_elem map [string ]string
@@ -281,14 +282,15 @@ pub fn Gen.new_with_env(files []ast.File, env &types.Environment) &Gen {
281282
282283pub fn Gen .new_with_env_and_pref (files []ast.File, env & types.Environment, p & pref.Preferences) & Gen {
283284 return & Gen{
284- files: files
285- env: unsafe { env }
286- pref: unsafe { p }
287- sb: strings.new_builder (4096 )
288- fn_param_is_ptr: map [string ][]bool {}
289- fn_param_types: map [string ][]string {}
290- fn_return_types: map [string ]string {}
291- runtime_local_types: map [string ]string {}
285+ files: files
286+ env: unsafe { env }
287+ pref: unsafe { p }
288+ sb: strings.new_builder (4096 )
289+ fn_param_is_ptr: map [string ][]bool {}
290+ fn_param_types: map [string ][]string {}
291+ fn_return_types: map [string ]string {}
292+ fn_names_in_decl_order: []string {}
293+ runtime_local_types: map [string ]string {}
292294
293295 fixed_array_fields: map [string ]bool {}
294296 fixed_array_field_elem: map [string ]string {}
@@ -307,6 +309,10 @@ pub fn Gen.new_with_env_and_pref(files []ast.File, env &types.Environment, p &pr
307309 }
308310}
309311
312+ fn (g &Gen) use_prealloc_allocator () bool {
313+ return g.pref != unsafe { nil } && g.pref.use_prealloc_allocator
314+ }
315+
310316pub fn (mut g Gen) gen () string {
311317 g.write_preamble ()
312318 g.collect_module_type_names ()
@@ -478,8 +484,7 @@ pub fn (mut g Gen) gen() string {
478484 if fn_name == 'main' {
479485 has_main = true
480486 }
481- if stmt.name.starts_with ('test_' ) && ! stmt.is_method
482- && stmt.typ.params.len == 0 {
487+ if stmt.name.starts_with ('test_' ) && ! stmt.is_method && stmt.typ.params.len == 0 {
483488 test_fn_names << fn_name
484489 }
485490 if g.env != unsafe { nil } {
@@ -533,8 +538,7 @@ fn (mut g Gen) emit_interface_method_wrappers() {
533538 mut emitted := map [string ]bool {}
534539 mut iface_names := g.interface_methods.keys ()
535540 iface_names.sort ()
536- mut fn_names := g.fn_param_is_ptr.keys ()
537- fn_names.sort ()
541+ fn_names := g.fn_names_in_decl_order
538542 for iface_name in iface_names {
539543 methods := g.interface_methods[iface_name]
540544 for method in methods {
@@ -649,6 +653,9 @@ fn (mut g Gen) write_preamble() {
649653 g.sb.writeln ('typedef void* chan;' )
650654 g.sb.writeln ('typedef double float_literal;' )
651655 g.sb.writeln ('typedef int64_t int_literal;' )
656+ if g.use_prealloc_allocator () {
657+ g.write_prealloc_allocator_preamble ()
658+ }
652659 // wyhash implementation used by builtin/map and hash modules.
653660 g.sb.writeln ('#ifndef wyhash_final_version_4_2' )
654661 g.sb.writeln ('#define wyhash_final_version_4_2' )
@@ -738,6 +745,170 @@ fn (mut g Gen) write_preamble() {
738745 g.sb.writeln ('' )
739746}
740747
748+ fn (mut g Gen) write_prealloc_allocator_preamble () {
749+ preamble := [
750+ '// prealloc arena allocator (enabled by -prealloc)' ,
751+ 'static void* (*v2_sys_malloc_fn)(size_t) = malloc;' ,
752+ 'static void* (*v2_sys_realloc_fn)(void*, size_t) = realloc;' ,
753+ 'static void (*v2_sys_free_fn)(void*) = free;' ,
754+ 'typedef struct v2_realloc_chunk {' ,
755+ ' u8* data;' ,
756+ ' size_t used;' ,
757+ ' size_t cap;' ,
758+ ' struct v2_realloc_chunk* prev;' ,
759+ '} v2_realloc_chunk;' ,
760+ 'typedef union v2_realloc_header {' ,
761+ ' struct {' ,
762+ ' size_t size;' ,
763+ ' } meta;' ,
764+ ' max_align_t _align;' ,
765+ '} v2_realloc_header;' ,
766+ 'static v2_realloc_chunk* v2_realloc_current_chunk = NULL;' ,
767+ 'static int v2_realloc_cleanup_registered = 0;' ,
768+ 'static const size_t v2_realloc_min_chunk_cap = ((size_t)64 * 1024 * 1024);' ,
769+ 'static void v2_realloc_alloc_panic(size_t bytes) {' ,
770+ ' fprintf(stderr, "v2 -prealloc arena: allocation failed for %zu bytes\\ n", bytes);' ,
771+ ' exit(1);' ,
772+ '}' ,
773+ 'static size_t v2_realloc_align_up(size_t value, size_t align) {' ,
774+ ' if (align == 0) {' ,
775+ ' return value;' ,
776+ ' }' ,
777+ ' size_t rem = value % align;' ,
778+ ' return rem == 0 ? value : value + (align - rem);' ,
779+ '}' ,
780+ 'static void v2_realloc_cleanup(void) {' ,
781+ ' v2_realloc_chunk* chunk = v2_realloc_current_chunk;' ,
782+ ' while (chunk != NULL) {' ,
783+ ' v2_realloc_chunk* prev = chunk->prev;' ,
784+ ' v2_sys_free_fn(chunk->data);' ,
785+ ' v2_sys_free_fn(chunk);' ,
786+ ' chunk = prev;' ,
787+ ' }' ,
788+ ' v2_realloc_current_chunk = NULL;' ,
789+ '}' ,
790+ 'static void v2_realloc_add_chunk(size_t min_cap) {' ,
791+ ' size_t cap = v2_realloc_min_chunk_cap;' ,
792+ ' if (v2_realloc_current_chunk != NULL && v2_realloc_current_chunk->cap > cap) {' ,
793+ ' cap = v2_realloc_current_chunk->cap;' ,
794+ ' }' ,
795+ ' while (cap < min_cap) {' ,
796+ ' size_t next = cap * 2;' ,
797+ ' if (next <= cap) {' ,
798+ ' cap = min_cap;' ,
799+ ' break;' ,
800+ ' }' ,
801+ ' cap = next;' ,
802+ ' }' ,
803+ ' v2_realloc_chunk* chunk = (v2_realloc_chunk*)v2_sys_malloc_fn(sizeof(v2_realloc_chunk));' ,
804+ ' if (chunk == NULL) {' ,
805+ ' v2_realloc_alloc_panic(sizeof(v2_realloc_chunk));' ,
806+ ' }' ,
807+ ' chunk->data = (u8*)v2_sys_realloc_fn(NULL, cap);' ,
808+ ' if (chunk->data == NULL) {' ,
809+ ' v2_realloc_alloc_panic(cap);' ,
810+ ' }' ,
811+ ' chunk->used = 0;' ,
812+ ' chunk->cap = cap;' ,
813+ ' chunk->prev = v2_realloc_current_chunk;' ,
814+ ' v2_realloc_current_chunk = chunk;' ,
815+ ' if (!v2_realloc_cleanup_registered) {' ,
816+ ' atexit(v2_realloc_cleanup);' ,
817+ ' v2_realloc_cleanup_registered = 1;' ,
818+ ' }' ,
819+ '}' ,
820+ 'static v2_realloc_chunk* v2_realloc_find_chunk(const u8* ptr) {' ,
821+ ' for (v2_realloc_chunk* chunk = v2_realloc_current_chunk; chunk != NULL; chunk = chunk->prev) {' ,
822+ ' const u8* start = chunk->data;' ,
823+ ' const u8* end = chunk->data + chunk->used;' ,
824+ ' if (ptr > start && ptr <= end) {' ,
825+ ' return chunk;' ,
826+ ' }' ,
827+ ' }' ,
828+ ' return NULL;' ,
829+ '}' ,
830+ 'static void* v2_realloc_malloc(size_t size) {' ,
831+ ' if (size == 0) {' ,
832+ ' size = 1;' ,
833+ ' }' ,
834+ ' size_t align = sizeof(max_align_t);' ,
835+ ' size_t needed = sizeof(v2_realloc_header) + size;' ,
836+ ' if (v2_realloc_current_chunk == NULL) {' ,
837+ ' v2_realloc_add_chunk(needed + align);' ,
838+ ' }' ,
839+ ' size_t offset = v2_realloc_align_up(v2_realloc_current_chunk->used, align);' ,
840+ ' if (offset + needed > v2_realloc_current_chunk->cap) {' ,
841+ ' v2_realloc_add_chunk(needed + align);' ,
842+ ' offset = v2_realloc_align_up(v2_realloc_current_chunk->used, align);' ,
843+ ' }' ,
844+ ' v2_realloc_header* header = (v2_realloc_header*)(v2_realloc_current_chunk->data + offset);' ,
845+ ' header->meta.size = size;' ,
846+ ' v2_realloc_current_chunk->used = offset + needed;' ,
847+ ' return (void*)(header + 1);' ,
848+ '}' ,
849+ 'static void* v2_realloc_calloc(size_t count, size_t size) {' ,
850+ ' if (count == 0 || size == 0) {' ,
851+ ' return v2_realloc_malloc(1);' ,
852+ ' }' ,
853+ ' if (count > ((size_t)-1) / size) {' ,
854+ ' v2_realloc_alloc_panic((size_t)-1);' ,
855+ ' }' ,
856+ ' size_t total = count * size;' ,
857+ ' void* ptr = v2_realloc_malloc(total);' ,
858+ ' memset(ptr, 0, total);' ,
859+ ' return ptr;' ,
860+ '}' ,
861+ 'static void* v2_realloc_realloc(void* ptr, size_t new_size) {' ,
862+ ' if (ptr == NULL) {' ,
863+ ' return v2_realloc_malloc(new_size);' ,
864+ ' }' ,
865+ ' if (new_size == 0) {' ,
866+ ' new_size = 1;' ,
867+ ' }' ,
868+ ' v2_realloc_chunk* chunk = v2_realloc_find_chunk((const u8*)ptr);' ,
869+ ' if (chunk == NULL) {' ,
870+ ' void* out = v2_sys_realloc_fn(ptr, new_size);' ,
871+ ' if (out == NULL) {' ,
872+ ' v2_realloc_alloc_panic(new_size);' ,
873+ ' }' ,
874+ ' return out;' ,
875+ ' }' ,
876+ ' v2_realloc_header* header = ((v2_realloc_header*)ptr) - 1;' ,
877+ ' size_t old_size = header->meta.size;' ,
878+ ' size_t header_offset = (size_t)((u8*)header - chunk->data);' ,
879+ ' size_t alloc_start = header_offset + sizeof(v2_realloc_header);' ,
880+ ' size_t alloc_end = alloc_start + old_size;' ,
881+ ' if (chunk == v2_realloc_current_chunk && alloc_end == chunk->used) {' ,
882+ ' size_t new_end = alloc_start + new_size;' ,
883+ ' if (new_end <= chunk->cap) {' ,
884+ ' header->meta.size = new_size;' ,
885+ ' chunk->used = new_end;' ,
886+ ' return ptr;' ,
887+ ' }' ,
888+ ' }' ,
889+ ' void* new_ptr = v2_realloc_malloc(new_size);' ,
890+ ' size_t copy_size = old_size < new_size ? old_size : new_size;' ,
891+ ' memcpy(new_ptr, ptr, copy_size);' ,
892+ ' return new_ptr;' ,
893+ '}' ,
894+ 'static void v2_realloc_free(void* ptr) {' ,
895+ ' if (ptr == NULL) {' ,
896+ ' return;' ,
897+ ' }' ,
898+ ' if (v2_realloc_find_chunk((const u8*)ptr) != NULL) {' ,
899+ ' return;' ,
900+ ' }' ,
901+ ' v2_sys_free_fn(ptr);' ,
902+ '}' ,
903+ '#define malloc(n) v2_realloc_malloc((size_t)(n))' ,
904+ '#define calloc(c, n) v2_realloc_calloc((size_t)(c), (size_t)(n))' ,
905+ '#define realloc(p, n) v2_realloc_realloc((p), (size_t)(n))' ,
906+ '#define free(p) v2_realloc_free((p))' ,
907+ ].join ('\n ' )
908+ g.sb.write_string (preamble)
909+ g.sb.write_string ('\n\n ' )
910+ }
911+
741912fn is_c_identifier_like (name string ) bool {
742913 if name.len == 0 {
743914 return false
@@ -885,6 +1056,7 @@ fn (mut g Gen) collect_fn_signatures() {
8851056 g.fn_param_is_ptr[fn_name] = params
8861057 g.fn_param_types[fn_name] = param_types
8871058 g.fn_return_types[fn_name] = ret_type
1059+ g.fn_names_in_decl_order << fn_name
8881060 }
8891061 else {}
8901062 }
@@ -3484,20 +3656,33 @@ fn escape_char_literal_content(raw string) string {
34843656 return sb.str ()
34853657}
34863658
3487- fn escape_c_string_literal_content (raw string ) string {
3659+ fn escape_c_string_literal_content (raw string , kind ast.StringLiteralKind ) string {
34883660 mut sb := strings.new_builder (raw.len + 8 )
34893661 for ch in raw {
3490- if ch == `"` {
3491- sb.write_u8 (`\\ ` )
3492- sb.write_u8 (`"` )
3493- } else if ch == `\n ` {
3494- sb.write_u8 (`\\ ` )
3495- sb.write_u8 (`n` )
3496- } else if ch == `\r ` {
3497- sb.write_u8 (`\\ ` )
3498- sb.write_u8 (`r` )
3499- } else {
3500- sb.write_u8 (ch)
3662+ match ch {
3663+ `"` {
3664+ sb.write_u8 (`\\ ` )
3665+ sb.write_u8 (`"` )
3666+ }
3667+ `\n ` {
3668+ sb.write_string ('\\ n' )
3669+ }
3670+ `\r ` {
3671+ sb.write_string ('\\ r' )
3672+ }
3673+ `\t ` {
3674+ sb.write_string ('\\ t' )
3675+ }
3676+ `\\ ` {
3677+ if kind == .raw {
3678+ sb.write_string ('\\\\ ' )
3679+ } else {
3680+ sb.write_u8 (`\\ ` )
3681+ }
3682+ }
3683+ else {
3684+ sb.write_u8 (ch)
3685+ }
35013686 }
35023687 }
35033688 return sb.str ()
@@ -3726,7 +3911,7 @@ fn (mut g Gen) gen_expr(node ast.Expr) {
37263911 }
37273912 ast.StringLiteral {
37283913 val := strip_literal_quotes (node.value)
3729- escaped := escape_c_string_literal_content (val)
3914+ escaped := escape_c_string_literal_content (val, node.kind )
37303915 if node.kind == .c {
37313916 // C string literal: emit raw C string
37323917 g.sb.write_u8 (`"` )
0 commit comments