Skip to content

Conversation

@SurmanPP
Copy link
Contributor

@SurmanPP SurmanPP commented Jan 5, 2026

Previously type_size would incorrectly compute sizes for pointers to structs in struct fields as if they were structs themselves and not pointers to structs leading to an infinite loop for structs containing pointers to themselves besides not handling pointers correctly. Offsets of fields in structs are needed to allocate memory and be able to access these fields these are precomputed now together with symbol sizes and their alignment like it is in the native backend. The code for the function type_size is adapted from the almost equivalent function in the ast module.

Handling structs which contain references to themself no longer segfaults the compiler.

struct Foo {
   i_crash_the_compile &Foo
   field int
}

fn (foo &Foo) print_field() {
   println(foo.field)
}

@SurmanPP SurmanPP marked this pull request as draft January 5, 2026 21:29
@SurmanPP SurmanPP force-pushed the wasm_fix_types branch 4 times, most recently from 20a37b6 to fcec66e Compare January 10, 2026 21:54
@SurmanPP SurmanPP marked this pull request as ready for review January 13, 2026 19:50
@SurmanPP
Copy link
Contributor Author

As it is. This pr is done. However as seen in CI v doc breaks on one of my changes for which I filed an issue(#26348). Secondly there is still another bug persisting. Accessing pointers to structs inside of structs does not seem to work correctly. There may be more issues related to this issue. The implementation is currently simply lacking.

I thought working around the v doc issue for now is best done in a followup commit.

@Krchi
Copy link
Contributor

Krchi commented Jan 14, 2026

just do it

	for f in ti.fields {
		f_size, f_align := if typ.ref() == f.typ {
			p.type_size(ast.voidptr_type)
		} else {
			p.type_size(f.typ)
		}
		if f_size == 0 {
			strc.offsets << 0
			continue
		}
		padding := (f_align - size % f_align) % f_align
		strc.offsets << size + padding
		size += f_size + padding
		if f_align > align {
			align = f_align
		}
	}
 OK    [ 1/15]  2662.852 ms C:\Applications\vlang\vlib\v\gen\wasm\tests\arith.vv
 OK    [ 2/15]   368.712 ms C:\Applications\vlang\vlib\v\gen\wasm\tests\arrays.vv
 OK    [ 3/15]   416.965 ms C:\Applications\vlang\vlib\v\gen\wasm\tests\asm.vv
 OK    [ 4/15]   465.952 ms C:\Applications\vlang\vlib\v\gen\wasm\tests\builtin.vv
 OK    [ 5/15]   366.916 ms C:\Applications\vlang\vlib\v\gen\wasm\tests\cast.vv
 OK    [ 6/15]   367.763 ms C:\Applications\vlang\vlib\v\gen\wasm\tests\comptime.vv
 OK    [ 7/15]   338.020 ms C:\Applications\vlang\vlib\v\gen\wasm\tests\control_flow.vv
 OK    [ 8/15]   344.540 ms C:\Applications\vlang\vlib\v\gen\wasm\tests\for_in_range.vv
 OK    [ 9/15]   355.206 ms C:\Applications\vlang\vlib\v\gen\wasm\tests\labeled_for_inc.vv
 OK    [10/15]   364.367 ms C:\Applications\vlang\vlib\v\gen\wasm\tests\match.vv
 OK    [11/15]   337.863 ms C:\Applications\vlang\vlib\v\gen\wasm\tests\match_ranges.vv
 OK    [12/15]   331.081 ms C:\Applications\vlang\vlib\v\gen\wasm\tests\misc.vv
 OK    [13/15]   328.370 ms C:\Applications\vlang\vlib\v\gen\wasm\tests\multi_expr.vv
 OK    [14/15]   345.923 ms C:\Applications\vlang\vlib\v\gen\wasm\tests\structs.vv
 OK    [15/15]   322.932 ms C:\Applications\vlang\vlib\v\gen\wasm\tests\wasi_api.vv
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Summary for wasm: 15 passed, 15 total. Elapsed time: 7720 ms.
PS C:\Applications\vlang> ./v -b wasm run C:\Applications\vlang\vlib\v\gen\wasm\tests\misc.vv
⠁ Compiling to WebAssembly                                                                                                                                                          struct containing pointer to itself
ptr_arith
12
14
102
before defer
defer_if: start
defer_if: defer!
defer_if: start
defer!
constants
100
hello

888
const refs
53
53
53
enums
30
8
PS C:\Applications\vlang> 
Snipaste_2026-01-14_13-47-29

@Krchi
Copy link
Contributor

Krchi commented Jan 14, 2026

pub fn (mut p Pool) type_size(typ ast.Type) (int, int) {
	ts := p.table.sym(typ)
	if ts.size != -1 && typ.idx() in p.structs {
		return ts.size, ts.align
	}

	if ts.info is ast.Enum {
		return p.table.type_size(ts.info.typ)
	}

	if ts.info !is ast.Struct {
		return p.table.type_size(typ)
	}

	ti := ts.info as ast.Struct

	// code borrowed from native, inserted in wasm, and now here!

	mut strc := StructInfo{}
	mut size := 0
	mut align := 1
	mut structs := []ast.Type{}
	for f in ti.fields {
		sym := p.table.sym(f.typ)
		f_size, f_align := if typ.is_ptr() {
			if sym.info is ast.Struct && !p.structs.keys().contains(typ.clear_ref()) {
				structs << typ.clear_ref()
			}
			p.type_size(ast.voidptr_type)
		} else {
			p.type_size(f.typ)
		}
		if f_size == 0 {
			strc.offsets << 0
			continue
		}
		padding := (f_align - size % f_align) % f_align
		strc.offsets << size + padding
		size += f_size + padding
		if f_align > align {
			align = f_align
		}
	}
	size = (size + align - 1) / align * align
	p.structs[typ.idx()] = strc

	for s in structs {
		p.type_size(s)
	}

	mut ts_ := p.table.sym(typ)
	ts_.size = size
	ts_.align = align

	return size, align
}

@SurmanPP
Copy link
Contributor Author

To simplify it the "nr_muls > 0" check at the beginning of the function is already enough. But I choose not to do that. Thinking more about it, I am not sure anymore why I did it this way.

@Krchi
Copy link
Contributor

Krchi commented Jan 14, 2026

To simplify it the "nr_muls > 0" check at the beginning of the function is already enough. But I choose not to do that. Thinking more about it, I am not sure anymore why I did it this way.

no problem, i found some wrong in padding caculate

@SurmanPP
Copy link
Contributor Author

Closing in favor of #26357

@SurmanPP SurmanPP closed this Jan 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants