cgen: sort globals and consts definitions (#14739)

master
yuyi 2022-06-11 22:17:49 +08:00 committed by GitHub
parent c7a619d16e
commit cdf4ffc513
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 192 additions and 103 deletions

View File

@ -10,6 +10,7 @@ import v.dotgraph
struct DepGraphNode { struct DepGraphNode {
pub mut: pub mut:
name string name string
value i64
deps []string deps []string
} }
@ -17,6 +18,7 @@ struct DepGraph {
pub mut: pub mut:
acyclic bool acyclic bool
nodes []DepGraphNode nodes []DepGraphNode
values map[string]i64
} }
struct OrderedDepMap { struct OrderedDepMap {
@ -43,7 +45,6 @@ pub fn (mut o OrderedDepMap) add(name string, deps []string) {
for dep in deps { for dep in deps {
if dep !in d { if dep !in d {
d << dep d << dep
} else {
} }
} }
o.set(name, d) o.set(name, d)
@ -95,6 +96,17 @@ pub fn (mut graph DepGraph) add(mod string, deps []string) {
deps: deps.clone() deps: deps.clone()
} }
graph.nodes << new_node graph.nodes << new_node
graph.values[mod] = 0
}
pub fn (mut graph DepGraph) add_with_value(mod string, deps []string, value i64) {
new_node := DepGraphNode{
name: mod
value: value
deps: deps.clone()
}
graph.nodes << new_node
graph.values[mod] = value
} }
pub fn (graph &DepGraph) resolve() &DepGraph { pub fn (graph &DepGraph) resolve() &DepGraph {
@ -119,14 +131,14 @@ pub fn (graph &DepGraph) resolve() &DepGraph {
mut g := new_dep_graph() mut g := new_dep_graph()
g.acyclic = false g.acyclic = false
for name in node_deps.keys { for name in node_deps.keys {
g.add(name, node_names.get(name)) g.add_with_value(name, node_names.get(name), graph.values[name])
} }
return g return g
} }
for name in ready_set { for name in ready_set {
node_deps.delete(name) node_deps.delete(name)
resolved_deps := node_names.get(name) resolved_deps := node_names.get(name)
resolved.add(name, resolved_deps) resolved.add_with_value(name, resolved_deps, graph.values[name])
} }
for name in node_deps.keys { for name in node_deps.keys {
node_deps.apply_diff(name, ready_set) node_deps.apply_diff(name, ready_set)

View File

@ -61,10 +61,6 @@ mut:
hotcode_definitions strings.Builder // -live declarations & functions hotcode_definitions strings.Builder // -live declarations & functions
channel_definitions strings.Builder // channel related code channel_definitions strings.Builder // channel related code
comptime_definitions strings.Builder // custom defines, given by -d/-define flags on the CLI comptime_definitions strings.Builder // custom defines, given by -d/-define flags on the CLI
global_inits map[string]strings.Builder // default initializers for globals (goes in _vinit())
global_init strings.Builder // thread local of the above
inits map[string]strings.Builder // contents of `void _vinit/2{}`
init strings.Builder
cleanup strings.Builder cleanup strings.Builder
cleanups map[string]strings.Builder // contents of `void _vcleanup(){}` cleanups map[string]strings.Builder // contents of `void _vcleanup(){}`
gowrappers strings.Builder // all go callsite wrappers gowrappers strings.Builder // all go callsite wrappers
@ -79,6 +75,8 @@ mut:
out_results strings.Builder // `result_xxxx` types out_results strings.Builder // `result_xxxx` types
json_forward_decls strings.Builder // json type forward decls json_forward_decls strings.Builder // json type forward decls
sql_buf strings.Builder // for writing exprs to args via `sqlite3_bind_int()` etc sql_buf strings.Builder // for writing exprs to args via `sqlite3_bind_int()` etc
global_const_defs map[string]GlobalConstDef
sorted_global_const_names []string
file &ast.File file &ast.File
unique_file_path_hash u64 // a hash of file.path, used for making auxilary fn generation unique (like `compare_xyz`) unique_file_path_hash u64 // a hash of file.path, used for making auxilary fn generation unique (like `compare_xyz`)
fn_decl &ast.FnDecl // pointer to the FnDecl we are currently inside otherwise 0 fn_decl &ast.FnDecl // pointer to the FnDecl we are currently inside otherwise 0
@ -215,6 +213,15 @@ mut:
use_segfault_handler bool = true use_segfault_handler bool = true
} }
// global or const variable definition string
struct GlobalConstDef {
mod string // module name
def string // definition
init string // init later (in _vinit)
dep_names []string // the names of all the consts, that this const depends on
order int // -1 for simple defines, string literals, anonymous function names, extern declarations etc
}
pub fn gen(files []&ast.File, table &ast.Table, pref &pref.Preferences) string { pub fn gen(files []&ast.File, table &ast.Table, pref &pref.Preferences) string {
// println('start cgen2') // println('start cgen2')
mut module_built := '' mut module_built := ''
@ -245,7 +252,6 @@ pub fn gen(files []&ast.File, table &ast.Table, pref &pref.Preferences) string {
comptime_definitions: strings.new_builder(100) comptime_definitions: strings.new_builder(100)
definitions: strings.new_builder(100) definitions: strings.new_builder(100)
gowrappers: strings.new_builder(100) gowrappers: strings.new_builder(100)
stringliterals: strings.new_builder(100)
auto_str_funcs: strings.new_builder(100) auto_str_funcs: strings.new_builder(100)
dump_funcs: strings.new_builder(100) dump_funcs: strings.new_builder(100)
pcs_declarations: strings.new_builder(100) pcs_declarations: strings.new_builder(100)
@ -266,7 +272,6 @@ pub fn gen(files []&ast.File, table &ast.Table, pref &pref.Preferences) string {
timers: util.new_timers(should_print: timers_should_print, label: 'global_cgen') timers: util.new_timers(should_print: timers_should_print, label: 'global_cgen')
inner_loop: &ast.EmptyStmt{} inner_loop: &ast.EmptyStmt{}
field_data_type: ast.Type(table.find_type_idx('FieldData')) field_data_type: ast.Type(table.find_type_idx('FieldData'))
init: strings.new_builder(100)
is_cc_msvc: pref.ccompiler == 'msvc' is_cc_msvc: pref.ccompiler == 'msvc'
use_segfault_handler: !('no_segfault_handler' in pref.compile_defines || pref.os == .wasm32) use_segfault_handler: !('no_segfault_handler' in pref.compile_defines || pref.os == .wasm32)
} }
@ -278,8 +283,6 @@ pub fn gen(files []&ast.File, table &ast.Table, pref &pref.Preferences) string {
global_g.timers.start('cgen init') global_g.timers.start('cgen init')
for mod in global_g.table.modules { for mod in global_g.table.modules {
global_g.inits[mod] = strings.new_builder(200)
global_g.global_inits[mod] = strings.new_builder(100)
global_g.cleanups[mod] = strings.new_builder(100) global_g.cleanups[mod] = strings.new_builder(100)
} }
global_g.init() global_g.init()
@ -315,6 +318,9 @@ pub fn gen(files []&ast.File, table &ast.Table, pref &pref.Preferences) string {
global_g.force_main_console = global_g.force_main_console || g.force_main_console global_g.force_main_console = global_g.force_main_console || g.force_main_console
// merge maps // merge maps
for k, v in g.global_const_defs {
global_g.global_const_defs[k] = v
}
for k, v in g.shareds { for k, v in g.shareds {
global_g.shareds[k] = v global_g.shareds[k] = v
} }
@ -342,8 +348,6 @@ pub fn gen(files []&ast.File, table &ast.Table, pref &pref.Preferences) string {
global_g.sql_buf.write(g.sql_buf) or { panic(err) } global_g.sql_buf.write(g.sql_buf) or { panic(err) }
global_g.cleanups[g.file.mod.name].write(g.cleanup) or { panic(err) } // strings.Builder.write never fails; it is like that in the source global_g.cleanups[g.file.mod.name].write(g.cleanup) or { panic(err) } // strings.Builder.write never fails; it is like that in the source
global_g.inits[g.file.mod.name].write(g.init) or { panic(err) }
global_g.global_inits[g.file.mod.name].write(g.global_init) or { panic(err) }
for str_type in g.str_types { for str_type in g.str_types {
global_g.str_types << str_type global_g.str_types << str_type
@ -374,10 +378,7 @@ pub fn gen(files []&ast.File, table &ast.Table, pref &pref.Preferences) string {
for file in files { for file in files {
global_g.file = file global_g.file = file
global_g.gen_file() global_g.gen_file()
global_g.inits[file.mod.name].drain_builder(mut global_g.init, 100)
global_g.cleanups[file.mod.name].drain_builder(mut global_g.cleanup, 100) global_g.cleanups[file.mod.name].drain_builder(mut global_g.cleanup, 100)
global_g.global_inits[file.mod.name].drain_builder(mut global_g.global_init,
100)
} }
global_g.timers.start('cgen unification') global_g.timers.start('cgen unification')
} }
@ -399,6 +400,7 @@ pub fn gen(files []&ast.File, table &ast.Table, pref &pref.Preferences) string {
global_g.gen_array_index_methods() global_g.gen_array_index_methods()
global_g.gen_equality_fns() global_g.gen_equality_fns()
global_g.gen_free_methods() global_g.gen_free_methods()
global_g.sort_globals_consts()
global_g.timers.show('cgen unification') global_g.timers.show('cgen unification')
mut g := global_g mut g := global_g
@ -462,6 +464,12 @@ pub fn gen(files []&ast.File, table &ast.Table, pref &pref.Preferences) string {
b.write_string(g.json_forward_decls.str()) b.write_string(g.json_forward_decls.str())
b.writeln('\n// V definitions:') b.writeln('\n// V definitions:')
b.write_string(g.definitions.str()) b.write_string(g.definitions.str())
b.writeln('\n// V global/const definitions:')
for var_name in g.sorted_global_const_names {
if var := g.global_const_defs[var_name] {
b.writeln(var.def)
}
}
interface_table := g.interface_table() interface_table := g.interface_table()
if interface_table.len > 0 { if interface_table.len > 0 {
b.writeln('\n// V interface table:') b.writeln('\n// V interface table:')
@ -545,7 +553,6 @@ fn cgen_process_one_file_cb(p &pool.PoolProcessor, idx int, wid int) &Gen {
alias_definitions: strings.new_builder(100) alias_definitions: strings.new_builder(100)
definitions: strings.new_builder(100) definitions: strings.new_builder(100)
gowrappers: strings.new_builder(100) gowrappers: strings.new_builder(100)
stringliterals: strings.new_builder(100)
auto_str_funcs: strings.new_builder(100) auto_str_funcs: strings.new_builder(100)
comptime_definitions: strings.new_builder(100) comptime_definitions: strings.new_builder(100)
pcs_declarations: strings.new_builder(100) pcs_declarations: strings.new_builder(100)
@ -559,8 +566,6 @@ fn cgen_process_one_file_cb(p &pool.PoolProcessor, idx int, wid int) &Gen {
json_forward_decls: strings.new_builder(100) json_forward_decls: strings.new_builder(100)
enum_typedefs: strings.new_builder(100) enum_typedefs: strings.new_builder(100)
sql_buf: strings.new_builder(100) sql_buf: strings.new_builder(100)
init: strings.new_builder(100)
global_init: strings.new_builder(0)
cleanup: strings.new_builder(100) cleanup: strings.new_builder(100)
table: global_g.table table: global_g.table
pref: global_g.pref pref: global_g.pref
@ -599,8 +604,6 @@ pub fn (mut g Gen) free_builders() {
g.type_definitions.free() g.type_definitions.free()
g.alias_definitions.free() g.alias_definitions.free()
g.definitions.free() g.definitions.free()
g.global_init.free()
g.init.free()
g.cleanup.free() g.cleanup.free()
g.gowrappers.free() g.gowrappers.free()
g.stringliterals.free() g.stringliterals.free()
@ -618,12 +621,6 @@ pub fn (mut g Gen) free_builders() {
g.json_forward_decls.free() g.json_forward_decls.free()
g.enum_typedefs.free() g.enum_typedefs.free()
g.sql_buf.free() g.sql_buf.free()
for _, mut v in g.global_inits {
v.free()
}
for _, mut v in g.inits {
v.free()
}
for _, mut v in g.cleanups { for _, mut v in g.cleanups {
v.free() v.free()
} }
@ -707,14 +704,6 @@ pub fn (mut g Gen) init() {
g.write_sorted_types() g.write_sorted_types()
g.write_multi_return_types() g.write_multi_return_types()
g.definitions.writeln('// end of definitions #endif') g.definitions.writeln('// end of definitions #endif')
//
if !g.pref.no_builtin {
g.stringliterals.writeln('')
g.stringliterals.writeln('// >> string literal consts')
if g.pref.build_mode != .build_module {
g.stringliterals.writeln('void vinit_string_literals(void){')
}
}
if g.pref.compile_defines_all.len > 0 { if g.pref.compile_defines_all.len > 0 {
g.comptime_definitions.writeln('// V compile time defines by -d or -define flags:') g.comptime_definitions.writeln('// V compile time defines by -d or -define flags:')
g.comptime_definitions.writeln('// All custom defines : ' + g.comptime_definitions.writeln('// All custom defines : ' +
@ -796,13 +785,6 @@ pub fn (mut g Gen) init() {
} }
pub fn (mut g Gen) finish() { pub fn (mut g Gen) finish() {
if !g.pref.no_builtin {
if g.pref.build_mode != .build_module {
g.stringliterals.writeln('}')
}
g.stringliterals.writeln('// << string literal consts')
g.stringliterals.writeln('')
}
if g.pref.is_prof && g.pref.build_mode != .build_module { if g.pref.is_prof && g.pref.build_mode != .build_module {
g.gen_vprint_profile_stats() g.gen_vprint_profile_stats()
} }
@ -4383,6 +4365,44 @@ fn (mut g Gen) return_stmt(node ast.Return) {
} }
} }
fn (mut g Gen) dependent_var_names(expr ast.Expr) []string {
mut vars := []string{}
match expr {
ast.Ident {
if expr.kind in [.global, .constant] {
vars << util.no_dots(expr.name)
}
}
ast.ArrayInit {
for elem_expr in expr.exprs {
vars << g.dependent_var_names(elem_expr)
}
}
ast.StructInit {
for field in expr.fields {
vars << g.dependent_var_names(field.expr)
}
}
ast.InfixExpr {
vars << g.dependent_var_names(expr.left)
vars << g.dependent_var_names(expr.right)
}
ast.PostfixExpr {
vars << g.dependent_var_names(expr.expr)
}
ast.PrefixExpr {
vars << g.dependent_var_names(expr.right)
}
ast.CallExpr {
for arg in expr.args {
vars << g.dependent_var_names(arg.expr)
}
}
else {}
}
return vars
}
fn (mut g Gen) const_decl(node ast.ConstDecl) { fn (mut g Gen) const_decl(node ast.ConstDecl) {
g.inside_const = true g.inside_const = true
defer { defer {
@ -4409,21 +4429,23 @@ fn (mut g Gen) const_decl(node ast.ConstDecl) {
ast.ArrayInit { ast.ArrayInit {
if field.expr.is_fixed { if field.expr.is_fixed {
styp := g.typ(field.expr.typ) styp := g.typ(field.expr.typ)
if g.pref.build_mode != .build_module {
val := g.expr_string(field.expr) val := g.expr_string(field.expr)
g.definitions.writeln('$styp $const_name = $val; // fixed array const') g.global_const_defs[util.no_dots(field.name)] = GlobalConstDef{
} else { mod: field.mod
g.definitions.writeln('$styp $const_name; // fixed array const') def: '$styp $const_name = $val; // fixed array const'
dep_names: g.dependent_var_names(field_expr)
} }
} else { } else {
g.const_decl_init_later(field.mod, name, field.expr, field.typ, false) g.const_decl_init_later(field.mod, name, field.expr, field.typ, false)
} }
} }
ast.StringLiteral { ast.StringLiteral {
g.definitions.writeln('string $const_name; // a string literal, inited later')
if g.pref.build_mode != .build_module {
val := g.expr_string(field.expr) val := g.expr_string(field.expr)
g.stringliterals.writeln('\t$const_name = $val;') g.global_const_defs[util.no_dots(field.name)] = GlobalConstDef{
mod: field.mod
def: 'string $const_name; // a string literal, inited later'
init: '\t$const_name = $val;'
order: -1
} }
} }
ast.CallExpr { ast.CallExpr {
@ -4450,7 +4472,9 @@ fn (mut g Gen) const_decl(node ast.ConstDecl) {
use_cache_mode := g.pref.build_mode == .build_module || g.pref.use_cache use_cache_mode := g.pref.build_mode == .build_module || g.pref.use_cache
if !use_cache_mode { if !use_cache_mode {
if ct_value := field.comptime_expr_value() { if ct_value := field.comptime_expr_value() {
if g.const_decl_precomputed(field.mod, name, ct_value, field.typ) { if g.const_decl_precomputed(field.mod, name, field.name, ct_value,
field.typ)
{
continue continue
} }
} }
@ -4458,7 +4482,7 @@ fn (mut g Gen) const_decl(node ast.ConstDecl) {
if field.is_simple_define_const() { if field.is_simple_define_const() {
// "Simple" expressions are not going to need multiple statements, // "Simple" expressions are not going to need multiple statements,
// only the ones which are inited later, so it's safe to use expr_string // only the ones which are inited later, so it's safe to use expr_string
g.const_decl_simple_define(field.name, g.expr_string(field_expr)) g.const_decl_simple_define(field.mod, field.name, g.expr_string(field_expr))
} else { } else {
g.const_decl_init_later(field.mod, name, field.expr, field.typ, false) g.const_decl_init_later(field.mod, name, field.expr, field.typ, false)
} }
@ -4467,7 +4491,7 @@ fn (mut g Gen) const_decl(node ast.ConstDecl) {
} }
} }
fn (mut g Gen) const_decl_precomputed(mod string, name string, ct_value ast.ComptTimeConstValue, typ ast.Type) bool { fn (mut g Gen) const_decl_precomputed(mod string, name string, field_name string, ct_value ast.ComptTimeConstValue, typ ast.Type) bool {
mut styp := g.typ(typ) mut styp := g.typ(typ)
cname := if g.pref.translated && !g.is_builtin_mod { name } else { '_const_$name' } cname := if g.pref.translated && !g.is_builtin_mod { name } else { '_const_$name' }
$if trace_const_precomputed ? { $if trace_const_precomputed ? {
@ -4475,13 +4499,13 @@ fn (mut g Gen) const_decl_precomputed(mod string, name string, ct_value ast.Comp
} }
match ct_value { match ct_value {
i8 { i8 {
g.const_decl_write_precomputed(styp, cname, ct_value.str()) g.const_decl_write_precomputed(mod, styp, cname, field_name, ct_value.str())
} }
i16 { i16 {
g.const_decl_write_precomputed(styp, cname, ct_value.str()) g.const_decl_write_precomputed(mod, styp, cname, field_name, ct_value.str())
} }
int { int {
g.const_decl_write_precomputed(styp, cname, ct_value.str()) g.const_decl_write_precomputed(mod, styp, cname, field_name, ct_value.str())
} }
i64 { i64 {
if typ == ast.i64_type { if typ == ast.i64_type {
@ -4493,32 +4517,32 @@ fn (mut g Gen) const_decl_precomputed(mod string, name string, ct_value ast.Comp
// with -cstrict. Add checker errors for overflows instead, // with -cstrict. Add checker errors for overflows instead,
// so V can catch them earlier, instead of relying on the // so V can catch them earlier, instead of relying on the
// C compiler for that. // C compiler for that.
g.const_decl_simple_define(name, ct_value.str()) g.const_decl_simple_define(mod, name, ct_value.str())
return true return true
} }
if typ == ast.u64_type { if typ == ast.u64_type {
g.const_decl_write_precomputed(styp, cname, ct_value.str() + 'U') g.const_decl_write_precomputed(mod, styp, cname, field_name, ct_value.str() + 'U')
} else { } else {
g.const_decl_write_precomputed(styp, cname, ct_value.str()) g.const_decl_write_precomputed(mod, styp, cname, field_name, ct_value.str())
} }
} }
u8 { u8 {
g.const_decl_write_precomputed(styp, cname, ct_value.str()) g.const_decl_write_precomputed(mod, styp, cname, field_name, ct_value.str())
} }
u16 { u16 {
g.const_decl_write_precomputed(styp, cname, ct_value.str()) g.const_decl_write_precomputed(mod, styp, cname, field_name, ct_value.str())
} }
u32 { u32 {
g.const_decl_write_precomputed(styp, cname, ct_value.str()) g.const_decl_write_precomputed(mod, styp, cname, field_name, ct_value.str())
} }
u64 { u64 {
g.const_decl_write_precomputed(styp, cname, ct_value.str() + 'U') g.const_decl_write_precomputed(mod, styp, cname, field_name, ct_value.str() + 'U')
} }
f32 { f32 {
g.const_decl_write_precomputed(styp, cname, ct_value.str()) g.const_decl_write_precomputed(mod, styp, cname, field_name, ct_value.str())
} }
f64 { f64 {
g.const_decl_write_precomputed(styp, cname, ct_value.str()) g.const_decl_write_precomputed(mod, styp, cname, field_name, ct_value.str())
} }
rune { rune {
rune_code := u32(ct_value) rune_code := u32(ct_value)
@ -4527,9 +4551,9 @@ fn (mut g Gen) const_decl_precomputed(mod string, name string, ct_value ast.Comp
return false return false
} }
escval := util.smart_quote(u8(rune_code).ascii_str(), false) escval := util.smart_quote(u8(rune_code).ascii_str(), false)
g.const_decl_write_precomputed(styp, cname, "'$escval'") g.const_decl_write_precomputed(mod, styp, cname, field_name, "'$escval'")
} else { } else {
g.const_decl_write_precomputed(styp, cname, u32(ct_value).str()) g.const_decl_write_precomputed(mod, styp, cname, field_name, u32(ct_value).str())
} }
} }
string { string {
@ -4538,8 +4562,12 @@ fn (mut g Gen) const_decl_precomputed(mod string, name string, ct_value ast.Comp
// TODO: ^ the above for strings, cause: // TODO: ^ the above for strings, cause:
// `error C2099: initializer is not a constant` errors in MSVC, // `error C2099: initializer is not a constant` errors in MSVC,
// so fall back to the delayed initialisation scheme: // so fall back to the delayed initialisation scheme:
g.definitions.writeln('$styp $cname; // str inited later') g.global_const_defs[util.no_dots(field_name)] = GlobalConstDef{
g.init.writeln('\t$cname = _SLIT("$escaped_val");') mod: mod
def: '$styp $cname; // str inited later'
init: '\t$cname = _SLIT("$escaped_val");'
order: -1
}
if g.is_autofree { if g.is_autofree {
g.cleanups[mod].writeln('\tstring_free(&$cname);') g.cleanups[mod].writeln('\tstring_free(&$cname);')
} }
@ -4551,11 +4579,14 @@ fn (mut g Gen) const_decl_precomputed(mod string, name string, ct_value ast.Comp
return true return true
} }
fn (mut g Gen) const_decl_write_precomputed(styp string, cname string, ct_value string) { fn (mut g Gen) const_decl_write_precomputed(mod string, styp string, cname string, field_name string, ct_value string) {
g.definitions.writeln('$styp $cname = $ct_value; // precomputed') g.global_const_defs[util.no_dots(field_name)] = GlobalConstDef{
mod: mod
def: '$styp $cname = $ct_value; // precomputed'
}
} }
fn (mut g Gen) const_decl_simple_define(name string, val string) { fn (mut g Gen) const_decl_simple_define(mod string, name string, val string) {
// Simple expressions should use a #define // Simple expressions should use a #define
// so that we don't pollute the binary with unnecessary global vars // so that we don't pollute the binary with unnecessary global vars
// Do not do this when building a module, otherwise the consts // Do not do this when building a module, otherwise the consts
@ -4571,13 +4602,17 @@ fn (mut g Gen) const_decl_simple_define(name string, val string) {
x = '_const_$x' x = '_const_$x'
} }
if g.pref.translated { if g.pref.translated {
g.definitions.write_string('const int $x = ') g.global_const_defs[util.no_dots(name)] = GlobalConstDef{
} else { mod: mod
g.definitions.write_string('#define $x ') def: 'const int $x = $val;'
order: -1
}
} else {
g.global_const_defs[util.no_dots(name)] = GlobalConstDef{
mod: mod
def: '#define $x $val'
order: -1
} }
g.definitions.writeln(val)
if g.pref.translated {
g.definitions.write_string(';')
} }
} }
@ -4586,22 +4621,27 @@ fn (mut g Gen) const_decl_init_later(mod string, name string, expr ast.Expr, typ
// (C doesn't allow init expressions that can't be resolved at compile time). // (C doesn't allow init expressions that can't be resolved at compile time).
mut styp := g.typ(typ) mut styp := g.typ(typ)
cname := if g.pref.translated && !g.is_builtin_mod { name } else { '_const_$name' } cname := if g.pref.translated && !g.is_builtin_mod { name } else { '_const_$name' }
g.definitions.writeln('$styp $cname; // inited later') mut init := strings.new_builder(100)
if cname == '_const_os__args' { if cname == '_const_os__args' {
if g.pref.os == .windows { if g.pref.os == .windows {
g.init.writeln('\t_const_os__args = os__init_os_args_wide(___argc, (byteptr*)___argv);') init.writeln('\t_const_os__args = os__init_os_args_wide(___argc, (byteptr*)___argv);')
} else { } else {
g.init.writeln('\t_const_os__args = os__init_os_args(___argc, (byte**)___argv);') init.writeln('\t_const_os__args = os__init_os_args(___argc, (byte**)___argv);')
} }
} else { } else {
if unwrap_option { if unwrap_option {
g.init.writeln('{') init.writeln('{')
g.init.writeln(g.expr_string_surround('\t$cname = *($styp*)', expr, '.data;')) init.writeln(g.expr_string_surround('\t$cname = *($styp*)', expr, '.data;'))
g.init.writeln('}') init.writeln('}')
} else { } else {
g.init.writeln(g.expr_string_surround('\t$cname = ', expr, ';')) init.writeln(g.expr_string_surround('\t$cname = ', expr, ';'))
} }
} }
g.global_const_defs[util.no_dots(name)] = GlobalConstDef{
mod: mod
def: '$styp $cname; // inited later'
init: init.str()
}
if g.is_autofree { if g.is_autofree {
sym := g.table.sym(typ) sym := g.table.sym(typ)
if styp.starts_with('Array_') { if styp.starts_with('Array_') {
@ -4654,40 +4694,57 @@ fn (mut g Gen) global_decl(node ast.GlobalDecl) {
if field.has_expr && mut anon_fn_expr is ast.AnonFn { if field.has_expr && mut anon_fn_expr is ast.AnonFn {
g.gen_anon_fn_decl(mut anon_fn_expr) g.gen_anon_fn_decl(mut anon_fn_expr)
fn_type_name := g.get_anon_fn_type_name(mut anon_fn_expr, field.name) fn_type_name := g.get_anon_fn_type_name(mut anon_fn_expr, field.name)
g.definitions.writeln('$fn_type_name = ${g.table.sym(field.typ).name}; // global2') g.global_const_defs[util.no_dots(fn_type_name)] = GlobalConstDef{
mod: node.mod
def: '$fn_type_name = ${g.table.sym(field.typ).name}; // global2'
order: -1
}
continue continue
} }
mut def_builder := strings.new_builder(100)
mut init := ''
extern := if cextern { 'extern ' } else { '' } extern := if cextern { 'extern ' } else { '' }
modifier := if field.is_volatile { ' volatile ' } else { '' } modifier := if field.is_volatile { ' volatile ' } else { '' }
g.definitions.write_string('$extern$visibility_kw$modifier$styp $attributes $field.name') def_builder.write_string('$extern$visibility_kw$modifier$styp $attributes $field.name')
if cextern { if cextern {
g.definitions.writeln('; // global5') def_builder.writeln('; // global5')
g.global_const_defs[util.no_dots(field.name)] = GlobalConstDef{
mod: node.mod
def: def_builder.str()
order: -1
}
continue continue
} }
if field.has_expr || cinit { if field.has_expr || cinit {
if g.pref.translated { if g.pref.translated {
g.definitions.write_string(' = ${g.expr_string(field.expr)}') def_builder.write_string(' = ${g.expr_string(field.expr)}')
} else if (field.expr.is_literal() && should_init) || cinit } else if (field.expr.is_literal() && should_init) || cinit
|| (field.expr is ast.ArrayInit && (field.expr as ast.ArrayInit).is_fixed) { || (field.expr is ast.ArrayInit && (field.expr as ast.ArrayInit).is_fixed) {
// Simple literals can be initialized right away in global scope in C. // Simple literals can be initialized right away in global scope in C.
// e.g. `int myglobal = 10;` // e.g. `int myglobal = 10;`
g.definitions.write_string(' = ${g.expr_string(field.expr)}') def_builder.write_string(' = ${g.expr_string(field.expr)}')
} else { } else {
// More complex expressions need to be moved to `_vinit()` // More complex expressions need to be moved to `_vinit()`
// e.g. `__global ( mygblobal = 'hello ' + world' )` // e.g. `__global ( mygblobal = 'hello ' + world' )`
g.global_init.writeln('\t$field.name = ${g.expr_string(field.expr)}; // 3global') init = '\t$field.name = ${g.expr_string(field.expr)}; // 3global'
} }
} else if !g.pref.translated { // don't zero globals from C code } else if !g.pref.translated { // don't zero globals from C code
default_initializer := g.type_default(field.typ) default_initializer := g.type_default(field.typ)
if default_initializer == '{0}' && should_init { if default_initializer == '{0}' && should_init {
g.definitions.write_string(' = {0}') def_builder.write_string(' = {0}')
} else { } else {
if field.name !in ['as_cast_type_indexes', 'g_memory_block', 'global_allocator'] { if field.name !in ['as_cast_type_indexes', 'g_memory_block', 'global_allocator'] {
g.global_init.writeln('\t$field.name = *($styp*)&(($styp[]){${g.type_default(field.typ)}}[0]); // global') init = '\t$field.name = *($styp*)&(($styp[]){${g.type_default(field.typ)}}[0]); // global'
} }
} }
} }
g.definitions.writeln('; // global4') def_builder.writeln('; // global4')
g.global_const_defs[util.no_dots(field.name)] = GlobalConstDef{
mod: node.mod
def: def_builder.str()
init: init
dep_names: g.dependent_var_names(field.expr)
}
} }
} }
@ -4769,17 +4826,21 @@ fn (mut g Gen) write_init_function() {
// calling module init functions too, just in case they do fail... // calling module init functions too, just in case they do fail...
g.write('\tas_cast_type_indexes = ') g.write('\tas_cast_type_indexes = ')
g.writeln(g.as_cast_name_table()) g.writeln(g.as_cast_name_table())
//
g.writeln('\tbuiltin_init();') g.writeln('\tbuiltin_init();')
g.writeln('\tvinit_string_literals();')
//
if g.nr_closures > 0 { if g.nr_closures > 0 {
g.writeln('\t_closure_mtx_init();') g.writeln('\t_closure_mtx_init();')
} }
for mod_name in g.table.modules { for mod_name in g.table.modules {
g.writeln('\t{ // Initializations for module $mod_name :') g.writeln('\t{ // Initializations for module $mod_name :')
g.write(g.inits[mod_name].str()) // write globals and consts init later
g.write(g.global_inits[mod_name].str()) for var_name in g.sorted_global_const_names {
if var := g.global_const_defs[var_name] {
if var.mod == mod_name && var.init.len > 0 {
g.writeln(var.init)
}
}
}
init_fn_name := '${mod_name}.init' init_fn_name := '${mod_name}.init'
if initfn := g.table.find_fn(init_fn_name) { if initfn := g.table.find_fn(init_fn_name) {
if initfn.return_type == ast.void_type && initfn.params.len == 0 { if initfn.return_type == ast.void_type && initfn.params.len == 0 {
@ -5059,6 +5120,22 @@ fn (mut g Gen) write_types(symbols []&ast.TypeSymbol) {
} }
} }
fn (mut g Gen) sort_globals_consts() {
g.sorted_global_const_names.clear()
mut dep_graph := depgraph.new_dep_graph()
for var_name, var_info in g.global_const_defs {
dep_graph.add_with_value(var_name, var_info.dep_names, var_info.order)
}
dep_graph_sorted := dep_graph.resolve()
for order in [-1, 0] {
for node in dep_graph_sorted.nodes {
if node.value == order {
g.sorted_global_const_names << node.name
}
}
}
}
// sort structs by dependant fields // sort structs by dependant fields
fn (mut g Gen) sort_structs(typesa []&ast.TypeSymbol) []&ast.TypeSymbol { fn (mut g Gen) sort_structs(typesa []&ast.TypeSymbol) []&ast.TypeSymbol {
util.timing_start(@METHOD) util.timing_start(@METHOD)

View File

@ -152,7 +152,7 @@ $enc_fn_dec {
dec.writeln('\topt_ok2(&res, ($option_name*)&ret, sizeof(res));') dec.writeln('\topt_ok2(&res, ($option_name*)&ret, sizeof(res));')
dec.writeln('\treturn ret;\n}') dec.writeln('\treturn ret;\n}')
enc.writeln('\treturn o;\n}') enc.writeln('\treturn o;\n}')
g.definitions.writeln(dec.str()) g.gowrappers.writeln(dec.str())
g.gowrappers.writeln(enc.str()) g.gowrappers.writeln(enc.str())
} }
} }