Skip to content

Commit a5ea6b1

Browse files
committed
v2: -prealloc
1 parent d6a5b80 commit a5ea6b1

5 files changed

Lines changed: 270 additions & 82 deletions

File tree

‎vlib/v2/gen/arm64/arm64.v‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1524,9 +1524,9 @@ fn (g &Gen) lookup_type_from_env(name string, module_name string) ?types.Type {
15241524
return none
15251525
}
15261526
mut scope := &types.Scope(unsafe { nil })
1527-
if s := g.mod.env.get_scope(module_name) {
1527+
if mut s := g.mod.env.get_scope(module_name) {
15281528
scope = s
1529-
} else if s := g.mod.env.get_scope('builtin') {
1529+
} else if mut s := g.mod.env.get_scope('builtin') {
15301530
scope = s
15311531
} else {
15321532
return none

‎vlib/v2/gen/cleanc/cleancnew.v‎

Lines changed: 221 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,18 @@ pub struct Gen {
1414
env &types.Environment = unsafe { nil }
1515
pref &pref.Preferences = unsafe { nil }
1616
mut:
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

282283
pub 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+
310316
pub 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+
741912
fn 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

Comments
 (0)