From aa542980cea146e05cf9bb5f1d792e1f092328ae Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 30 Aug 2018 19:14:10 +0100 Subject: [PATCH] Change memory layout of `map` to be 3 words smaller --- core/mem/alloc.odin | 3 +++ core/mem/raw.odin | 2 +- core/os/os.odin | 3 +++ core/runtime/core.odin | 47 ++++++++++++++++++++++++++++++++++-------- src/check_decl.cpp | 17 +++++++++++++-- src/check_type.cpp | 16 ++++++++------ src/checker.cpp | 13 +++++++----- src/checker.hpp | 1 + src/entity.cpp | 5 +++++ src/ir.cpp | 34 ++++++++++++++---------------- src/ir_print.cpp | 2 +- src/types.cpp | 15 +++++++++++++- 12 files changed, 114 insertions(+), 44 deletions(-) diff --git a/core/mem/alloc.odin b/core/mem/alloc.odin index 0814085f9..c8c0c5855 100644 --- a/core/mem/alloc.odin +++ b/core/mem/alloc.odin @@ -39,9 +39,12 @@ free_all :: inline proc(allocator := context.allocator, loc := #caller_location) } resize :: inline proc(ptr: rawptr, old_size, new_size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> rawptr { + assert(allocator.procedure != nil); if new_size == 0 { free(ptr, allocator, loc); return nil; + } else if ptr == nil { + return allocator.procedure(allocator.data, Allocator_Mode.Alloc, new_size, alignment, nil, 0, 0, loc); } return allocator.procedure(allocator.data, Allocator_Mode.Resize, new_size, alignment, ptr, old_size, 0, loc); } diff --git a/core/mem/raw.odin b/core/mem/raw.odin index 11c2a9404..9d778a72b 100644 --- a/core/mem/raw.odin +++ b/core/mem/raw.odin @@ -27,7 +27,7 @@ Raw_Dynamic_Array :: struct { } Raw_Map :: struct { - hashes: [dynamic]int, + hashes: []int, entries: Raw_Dynamic_Array, } diff --git a/core/os/os.odin b/core/os/os.odin index aa669644e..1ff97d094 100644 --- a/core/os/os.odin +++ b/core/os/os.odin @@ -83,6 +83,9 @@ heap_allocator_proc :: proc(allocator_data: rawptr, mode: mem.Allocator_Mode, // NOTE(bill): Does nothing case Resize: + if old_memory == nil { + return heap_alloc(size); + } ptr := heap_resize(old_memory, size); assert(ptr != nil); return ptr; diff --git a/core/runtime/core.odin b/core/runtime/core.odin index acb71e7ce..3ffc0c289 100644 --- a/core/runtime/core.odin +++ b/core/runtime/core.odin @@ -410,10 +410,11 @@ make :: proc[ clear_map :: inline proc "contextless" (m: ^$T/map[$K]$V) { if m == nil do return; raw_map := (^mem.Raw_Map)(m); - hashes := (^mem.Raw_Dynamic_Array)(&raw_map.hashes); entries := (^mem.Raw_Dynamic_Array)(&raw_map.entries); - hashes.len = 0; entries.len = 0; + for _, i in raw_map.hashes { + raw_map.hashes[i] = -1; + } } @(builtin) @@ -597,6 +598,7 @@ __dynamic_array_reserve :: proc(array_: rawptr, elem_size, elem_align: int, cap: if cap <= array.cap do return true; if array.allocator.procedure == nil { + os.write_string(os.stdout, "HERE\n"); array.allocator = context.allocator; } assert(array.allocator.procedure != nil); @@ -731,20 +733,47 @@ __default_hash :: proc(data: []byte) -> u64 { } __default_hash_string :: proc(s: string) -> u64 do return __default_hash(([]byte)(s)); +__slice_resize :: proc(array_: ^$T/[]$E, new_count: int, allocator: mem.Allocator, loc := #caller_location) -> bool { + array := (^mem.Raw_Slice)(array_); + + if new_count < array.len do return true; + + assert(allocator.procedure != nil); + + old_size := array.len*size_of(T); + new_size := new_count*size_of(T); + + new_data := mem.resize(array.data, old_size, new_size, align_of(T), allocator, loc); + if new_data == nil do return false; + array.data = new_data; + array.len = new_count; + return true; +} + __dynamic_map_reserve :: proc(using header: Map_Header, cap: int, loc := #caller_location) { - __dynamic_array_reserve(&m.hashes, size_of(int), align_of(int), cap, loc); - __dynamic_array_reserve(&m.entries, entry_size, entry_align, cap, loc); + __dynamic_array_reserve(&m.entries, entry_size, entry_align, cap, loc); + + old_len := len(m.hashes); + __slice_resize(&m.hashes, cap, m.entries.allocator, loc); + for i in old_len..len(m.hashes)-1 do m.hashes[i] = -1; + } __dynamic_map_rehash :: proc(using header: Map_Header, new_count: int, loc := #caller_location) #no_bounds_check { new_header: Map_Header = header; nm := mem.Raw_Map{}; + nm.entries.allocator = m.entries.allocator; new_header.m = &nm; - header_hashes := (^mem.Raw_Dynamic_Array)(&header.m.hashes); - nm_hashes := (^mem.Raw_Dynamic_Array)(&nm.hashes); + c := context; + if m.entries.allocator.procedure != nil { + c.allocator = m.entries.allocator; + } + __print_u64(os.stdout, u64(uintptr(c.allocator.data))); os.write_byte(os.stdout, '\n'); + __print_u64(os.stdout, u64(uintptr(m.entries.allocator.data))); os.write_byte(os.stdout, '\n'); + context = c; - __dynamic_array_resize(nm_hashes, size_of(int), align_of(int), new_count, loc); __dynamic_array_reserve(&nm.entries, entry_size, entry_align, m.entries.len, loc); + __slice_resize(&nm.hashes, new_count, m.entries.allocator, loc); for i in 0 .. new_count-1 do nm.hashes[i] = -1; for i in 0 .. m.entries.len-1 { @@ -769,8 +798,8 @@ __dynamic_map_rehash :: proc(using header: Map_Header, new_count: int, loc := #c if __dynamic_map_full(new_header) do __dynamic_map_grow(new_header, loc); } - free(header_hashes.data, header_hashes.allocator, loc); - free(header.m.entries.data, header.m.entries.allocator, loc); + delete(m.hashes, m.entries.allocator, loc); + free(m.entries.data, m.entries.allocator, loc); header.m^ = nm; } diff --git a/src/check_decl.cpp b/src/check_decl.cpp index 8569ee437..efcbbe1d6 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -217,11 +217,22 @@ Ast *remove_type_alias_clutter(Ast *node) { } } +isize total_attribute_count(DeclInfo *decl) { + isize attribute_count = 0; + for_array(i, decl->attributes) { + Ast *attr = decl->attributes[i]; + if (attr->kind != Ast_Attribute) continue; + attribute_count += attr->Attribute.elems.count; + } + return attribute_count; +} + + void check_type_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Type *def) { GB_ASSERT(e->type == nullptr); DeclInfo *decl = decl_info_of_entity(e); - if (decl != nullptr && decl->attributes.count > 0) { + if (decl != nullptr && total_attribute_count(decl) > 0) { error(decl->attributes[0], "Attributes are not allowed on type declarations"); } @@ -290,6 +301,8 @@ void override_entity_in_scope(Entity *original_entity, Entity *new_entity) { map_set(&found_scope->elements, hash_string(original_name), new_entity); } + + void check_const_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Ast *init, Type *named_type) { GB_ASSERT(e->type == nullptr); GB_ASSERT(e->kind == Entity_Constant); @@ -380,7 +393,7 @@ void check_const_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Ast *init, DeclInfo *decl = decl_info_of_entity(e); - if (decl != nullptr && decl->attributes.count > 0) { + if (decl != nullptr && total_attribute_count(decl) > 0) { error(decl->attributes[0], "Attributes are not allowed on constant value declarations"); } } diff --git a/src/check_type.cpp b/src/check_type.cpp index e56b20134..b5c1d7120 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -1008,10 +1008,14 @@ Type *determine_type_from_polymorphic(CheckerContext *ctx, Type *poly_type, Oper return t_invalid; } -bool is_expr_from_another_parameter(CheckerContext *ctx, Ast *expr) { +bool is_expr_from_a_parameter(CheckerContext *ctx, Ast *expr) { + if (expr == nullptr) { + return false; + } + expr = unparen_expr(expr); if (expr->kind == Ast_SelectorExpr) { Ast *lhs = expr->SelectorExpr.expr; - return is_expr_from_another_parameter(ctx, lhs); + return is_expr_from_a_parameter(ctx, lhs); } else if (expr->kind == Ast_Ident) { Operand x= {}; Entity *e = check_ident(ctx, &x, expr, nullptr, nullptr, false); @@ -1025,7 +1029,6 @@ bool is_expr_from_another_parameter(CheckerContext *ctx, Ast *expr) { ParameterValue handle_parameter_value(CheckerContext *ctx, Type *in_type, Type **out_type_, Ast *expr, bool allow_caller_location) { ParameterValue param_value = {}; - // gb_printf_err("HERE\n"); if (expr == nullptr) { return param_value; } @@ -1071,7 +1074,7 @@ ParameterValue handle_parameter_value(CheckerContext *ctx, Type *in_type, Type * if (e->flags & EntityFlag_Param) { error(expr, "Default parameter cannot be another parameter"); } else { - if (is_expr_from_another_parameter(ctx, expr)) { + if (is_expr_from_a_parameter(ctx, expr)) { error(expr, "Default parameter cannot be another parameter"); } else { param_value.kind = ParameterValue_Value; @@ -1689,6 +1692,7 @@ bool check_procedure_type(CheckerContext *ctx, Type *type, Ast *proc_type_node, CheckerContext *c = &c_; c->curr_proc_sig = type; + c->in_proc_sig = true; bool variadic = false; isize variadic_index = -1; @@ -1898,7 +1902,7 @@ void init_map_internal_types(Type *type) { /* struct { - hashes: [dynamic]int; + hashes: []int; entries: [dynamic]EntryType; } */ @@ -1906,7 +1910,7 @@ void init_map_internal_types(Type *type) { Ast *dummy_node = alloc_ast_node(nullptr, Ast_Invalid); Scope *s = create_scope(builtin_scope, a); - Type *hashes_type = alloc_type_dynamic_array(t_int); + Type *hashes_type = alloc_type_slice(t_int); Type *entries_type = alloc_type_dynamic_array(type->Map.entry_type); diff --git a/src/checker.cpp b/src/checker.cpp index 5299e4372..a7b54fb8a 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -905,11 +905,14 @@ void add_entity_and_decl_info(CheckerContext *c, Ast *identifier, Entity *e, Dec if (e->scope != nullptr) { Scope *scope = e->scope; - if ((scope->flags&ScopeFlag_File) && is_entity_kind_exported(e->kind)) { - AstPackage *pkg = scope->file->pkg; - GB_ASSERT(pkg->scope == scope->parent); - GB_ASSERT(c->pkg == pkg); - scope = pkg->scope; + + if (scope->flags & ScopeFlag_File) { + if (is_entity_kind_exported(e->kind)) { + AstPackage *pkg = scope->file->pkg; + GB_ASSERT(pkg->scope == scope->parent); + GB_ASSERT(c->pkg == pkg); + scope = pkg->scope; + } } add_entity(c->checker, scope, identifier, e); } diff --git a/src/checker.hpp b/src/checker.hpp index 4472ad519..5d05d5809 100644 --- a/src/checker.hpp +++ b/src/checker.hpp @@ -301,6 +301,7 @@ struct CheckerContext { String proc_name; DeclInfo * curr_proc_decl; Type * curr_proc_sig; + bool in_proc_sig; ForeignContext foreign_context; gbAllocator allocator; diff --git a/src/entity.cpp b/src/entity.cpp index 5a112e5a2..85e768f2c 100644 --- a/src/entity.cpp +++ b/src/entity.cpp @@ -45,6 +45,7 @@ enum EntityFlag { EntityFlag_Sret = 1<<11, EntityFlag_BitFieldValue = 1<<12, EntityFlag_PolyConst = 1<<13, + EntityFlag_NotExported = 1<<14, EntityFlag_CVarArg = 1<<20, EntityFlag_AutoCast = 1<<21, @@ -172,6 +173,10 @@ bool is_entity_exported(Entity *e) { return false; } + if (e->flags & EntityFlag_NotExported) { + return false; + } + String name = e->token.string; if (name.len == 0) { return false; diff --git a/src/ir.cpp b/src/ir.cpp index 0ef239380..002fdcca3 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -2768,6 +2768,7 @@ irValue *ir_emit_array_epi(irProcedure *proc, irValue *s, i32 index) { irValue *ir_emit_struct_ep(irProcedure *proc, irValue *s, i32 index) { gbAllocator a = ir_allocator(); + GB_ASSERT(is_type_pointer(ir_type(s))); Type *t = base_type(type_deref(ir_type(s))); Type *result_type = nullptr; @@ -2808,18 +2809,18 @@ irValue *ir_emit_struct_ep(irProcedure *proc, irValue *s, i32 index) { case 2: result_type = t_int_ptr; break; case 3: result_type = t_allocator_ptr; break; } - } /* else if (is_type_map(t)) { + } else if (is_type_map(t)) { init_map_internal_types(t); Type *itp = alloc_type_pointer(t->Map.internal_type); - s = ir_emit_load(proc, ir_emit_transmute(proc, s, itp)); + s = ir_emit_transmute(proc, s, itp); - Type *gst = t->Map.generated_struct_type; + Type *gst = t->Map.internal_type; GB_ASSERT(gst->kind == Type_Struct); switch (index) { case 0: result_type = alloc_type_pointer(gst->Struct.fields[0]->type); break; case 1: result_type = alloc_type_pointer(gst->Struct.fields[1]->type); break; } - } */else { + } else { GB_PANIC("TODO(bill): struct_gep type: %s, %d", type_to_string(ir_type(s)), index); } @@ -2887,15 +2888,15 @@ irValue *ir_emit_struct_ev(irProcedure *proc, irValue *s, i32 index) { } break; - // case Type_Map: { - // init_map_internal_types(t); - // Type *gst = t->Map.generated_struct_type; - // switch (index) { - // case 0: result_type = gst->Struct.fields[0]->type; break; - // case 1: result_type = gst->Struct.fields[1]->type; break; - // } - // break; - // } + case Type_Map: { + init_map_internal_types(t); + Type *gst = t->Map.generated_struct_type; + switch (index) { + case 0: result_type = gst->Struct.fields[0]->type; break; + case 1: result_type = gst->Struct.fields[1]->type; break; + } + break; + } default: GB_PANIC("TODO(bill): struct_ev type: %s, %d", type_to_string(ir_type(s)), index); @@ -2962,12 +2963,7 @@ irValue *ir_emit_deep_field_gep(irProcedure *proc, irValue *e, Selection sel) { } else if (type->kind == Type_Array) { e = ir_emit_array_epi(proc, e, index); } else if (type->kind == Type_Map) { - e = ir_emit_struct_ep(proc, e, 1); - switch (index) { - case 0: e = ir_emit_struct_ep(proc, e, 1); break; // count - case 1: e = ir_emit_struct_ep(proc, e, 2); break; // capacity - case 2: e = ir_emit_struct_ep(proc, e, 3); break; // allocator - } + e = ir_emit_struct_ep(proc, e, index); } else { GB_PANIC("un-gep-able type %s", type_to_string(type)); } diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 547235dd0..441835922 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -458,7 +458,7 @@ void ir_print_type(irFileBuffer *f, irModule *m, Type *t, bool in_struct) { ir_print_encoded_local(f, name); } else { // TODO(bill): Is this correct behaviour?! - GB_ASSERT_MSG(name.len > 0, "%.*s %p", LIT(t->Named.name), e); + // GB_ASSERT_MSG(name.len > 0, "%.*s %p", LIT(t->Named.name), e); // gb_printf_err("%.*s %p\n", LIT(t->Named.name), t->Named.type_name); ir_print_type(f, m, bt); } diff --git a/src/types.cpp b/src/types.cpp index 4b3ce2edd..62db34a60 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -1839,13 +1839,26 @@ Selection lookup_field_with_selection(Type *type_, String field_name, bool is_ty // `Raw_Dynamic_Array` type? GB_ASSERT(t_allocator != nullptr); String allocator_str = str_lit("allocator"); - gb_local_persist Entity *entity__allocator = alloc_entity_field(nullptr, make_token_ident(allocator_str), t_allocator, false, 0); + gb_local_persist Entity *entity__allocator = alloc_entity_field(nullptr, make_token_ident(allocator_str), t_allocator, false, 3); if (field_name == allocator_str) { selection_add_index(&sel, 3); sel.entity = entity__allocator; return sel; } + } else if (type->kind == Type_Map) { + // IMPORTANT TODO(bill): Should these members be available to should I only allow them with + // `Raw_Map` type? + GB_ASSERT(t_allocator != nullptr); + String allocator_str = str_lit("allocator"); + gb_local_persist Entity *entity__allocator = alloc_entity_field(nullptr, make_token_ident(allocator_str), t_allocator, false, 3); + + if (field_name == allocator_str) { + selection_add_index(&sel, 1); + selection_add_index(&sel, 3); + sel.entity = entity__allocator; + return sel; + } } return sel;