Browse Source

Change memory layout of `map` to be 3 words smaller

gingerBill 7 years ago
parent
commit
aa542980ce
12 changed files with 114 additions and 44 deletions
  1. 3 0
      core/mem/alloc.odin
  2. 1 1
      core/mem/raw.odin
  3. 3 0
      core/os/os.odin
  4. 38 9
      core/runtime/core.odin
  5. 15 2
      src/check_decl.cpp
  6. 10 6
      src/check_type.cpp
  7. 8 5
      src/checker.cpp
  8. 1 0
      src/checker.hpp
  9. 5 0
      src/entity.cpp
  10. 15 19
      src/ir.cpp
  11. 1 1
      src/ir_print.cpp
  12. 14 1
      src/types.cpp

+ 3 - 0
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);
 }

+ 1 - 1
core/mem/raw.odin

@@ -27,7 +27,7 @@ Raw_Dynamic_Array :: struct {
 }
 
 Raw_Map :: struct {
-	hashes:  [dynamic]int,
+	hashes:  []int,
 	entries: Raw_Dynamic_Array,
 }
 

+ 3 - 0
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;

+ 38 - 9
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;
 }
 

+ 15 - 2
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");
 	}
 }

+ 10 - 6
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);
 
 

+ 8 - 5
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);
 	}

+ 1 - 0
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;
 

+ 5 - 0
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;

+ 15 - 19
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));
 		}

+ 1 - 1
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);
 			}

+ 14 - 1
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;