diff --git a/core/encoding/json/marshal.odin b/core/encoding/json/marshal.odin index 7df0493b9..df5a0754e 100644 --- a/core/encoding/json/marshal.odin +++ b/core/encoding/json/marshal.odin @@ -210,11 +210,7 @@ marshal_arg :: proc(b: ^strings.Builder, v: any) -> Marshal_Error { data := uintptr(entries.data) + uintptr(i*entry_size); header := cast(^Map_Entry_Header)data; - if reflect.is_string(info.key) { - marshal_arg(b, header.key.str); - } else { - marshal_arg(b, any{rawptr(&header.key.hash), info.key.id}); - } + marshal_arg(b, any{rawptr(&header.key.key.val), info.key.id}); write_string(b, ": "); diff --git a/core/fmt/fmt.odin b/core/fmt/fmt.odin index c710c54cd..ad2f99b16 100644 --- a/core/fmt/fmt.odin +++ b/core/fmt/fmt.odin @@ -1501,10 +1501,10 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) { header := cast(^runtime.Map_Entry_Header)data; if reflect.is_string(info.key) { - strings.write_string(fi.buf, header.key.str); + strings.write_string(fi.buf, header.key.key.str); } else { fi := Info{buf = fi.buf}; - fmt_arg(&fi, any{rawptr(&header.key.hash), info.key.id}, 'v'); + fmt_arg(&fi, any{rawptr(&header.key.key.val), info.key.id}, 'v'); } strings.write_string(fi.buf, "="); diff --git a/core/runtime/core.odin b/core/runtime/core.odin index ebfab6b66..5e6c572da 100644 --- a/core/runtime/core.odin +++ b/core/runtime/core.odin @@ -349,7 +349,17 @@ INITIAL_MAP_CAP :: 16; Map_Key :: struct { hash: u64, - str: string, + /* NOTE(bill) + size_of(Map_Key) == 16 Bytes on 32-bit systems + size_of(Map_Key) == 24 Bytes on 64-bit systems + + This does mean that an extra word is wasted for each map when a string is not used on 64-bit systems + however, this is probably not a huge problem in terms of memory usage + */ + key: struct #raw_union { + str: string, + val: u64, + }, } Map_Find_Result :: struct { @@ -1407,28 +1417,34 @@ __get_map_key :: proc "contextless" (k: $K) -> Map_Key { T :: intrinsics.type_core_type(K); when intrinsics.type_is_integer(T) { + map_key.hash = default_hash_ptr(&key, size_of(T)); + sz :: 8*size_of(T); - when sz == 8 do map_key.hash = u64(( ^u8)(&key)^); - else when sz == 16 do map_key.hash = u64((^u16)(&key)^); - else when sz == 32 do map_key.hash = u64((^u32)(&key)^); - else when sz == 64 do map_key.hash = u64((^u64)(&key)^); - else do #assert(false, "Unhandled integer size"); + when sz == 8 do map_key.key.val = u64(( ^u8)(&key)^); + else when sz == 16 do map_key.key.val = u64((^u16)(&key)^); + else when sz == 32 do map_key.key.val = u64((^u32)(&key)^); + else when sz == 64 do map_key.key.val = u64((^u64)(&key)^); + else do #panic("Unhandled integer size"); } else when intrinsics.type_is_rune(T) { - map_key.hash = u64((^rune)(&key)^); + map_key.hash = default_hash_ptr(&key, size_of(T)); + map_key.key.val = u64((^rune)(&key)^); } else when intrinsics.type_is_pointer(T) { - map_key.hash = u64(uintptr((^rawptr)(&key)^)); + map_key.hash = default_hash_ptr(&key, size_of(T)); + map_key.key.val = u64(uintptr((^rawptr)(&key)^)); } else when intrinsics.type_is_float(T) { + map_key.hash = default_hash_ptr(&key, size_of(T)); + sz :: 8*size_of(T); - when sz == 32 do map_key.hash = u64((^u32)(&key)^); - else when sz == 64 do map_key.hash = u64((^u64)(&key)^); - else do #assert(false, "Unhandled float size"); + when sz == 32 do map_key.key.val = u64((^u32)(&key)^); + else when sz == 64 do map_key.key.val = u64((^u64)(&key)^); + else do #panic("Unhandled float size"); } else when intrinsics.type_is_string(T) { #assert(T == string); str := (^string)(&key)^; map_key.hash = default_hash_string(str); - map_key.str = str; + map_key.key.str = str; } else { - #assert(false, "Unhandled map key type"); + #panic("Unhandled map key type"); } return map_key; @@ -1443,10 +1459,18 @@ _fnv64a :: proc "contextless" (data: []byte, seed: u64 = 0xcbf29ce484222325) -> } -default_hash :: proc "contextless" (data: []byte) -> u64 { +default_hash :: inline proc "contextless" (data: []byte) -> u64 { + context = default_context(); + os.write_string(os.stdout, "here - default_hash\n"); return _fnv64a(data); } -default_hash_string :: proc "contextless" (s: string) -> u64 do return default_hash(transmute([]byte)(s)); +default_hash_string :: inline proc "contextless" (s: string) -> u64 { + return default_hash(transmute([]byte)(s)); +} +default_hash_ptr :: inline proc "contextless" (data: rawptr, size: int) -> u64 { + s := Raw_Slice{data, size}; + return default_hash(transmute([]byte)(s)); +} source_code_location_hash :: proc(s: Source_Code_Location) -> u64 { @@ -1582,7 +1606,11 @@ __dynamic_map_full :: inline proc(using h: Map_Header) -> bool { __dynamic_map_hash_equal :: proc(h: Map_Header, a, b: Map_Key) -> bool { if a.hash == b.hash { - if h.is_key_string do return a.str == b.str; + if h.is_key_string { + return a.key.str == b.key.str; + } else { + return a.key.val == b.key.val; + } return true; } return false; diff --git a/core/sys/windows/types.odin b/core/sys/windows/types.odin index 005820e04..0d8ed94aa 100644 --- a/core/sys/windows/types.odin +++ b/core/sys/windows/types.odin @@ -17,6 +17,8 @@ HANDLE :: distinct LPVOID; HINSTANCE :: HANDLE; HMODULE :: distinct HINSTANCE; HRESULT :: distinct LONG; +HWND :: distinct HANDLE; +HMONITOR :: distinct HANDLE; BOOL :: distinct b32; BYTE :: distinct u8; BOOLEAN :: distinct b8; diff --git a/src/check_type.cpp b/src/check_type.cpp index 7be70c11d..118c9a622 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -2794,6 +2794,8 @@ void check_map_type(CheckerContext *ctx, Type *type, Ast *node) { if (is_type_string(key)) { add_package_dependency(ctx, "runtime", "default_hash_string"); + } else { + add_package_dependency(ctx, "runtime", "default_hash_ptr"); } diff --git a/src/ir.cpp b/src/ir.cpp index 77d40dc52..7c2e6d0c5 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -3593,27 +3593,8 @@ irValue *ir_gen_map_key(irProcedure *proc, irValue *key, Type *key_type) { irValue *v = ir_add_local_generated(proc, t_map_key, true); Type *t = base_type(ir_type(key)); key = ir_emit_conv(proc, key, key_type); - if (is_type_integer(t)) { - ir_emit_store(proc, ir_emit_struct_ep(proc, v, 0), ir_emit_conv(proc, key, hash_type)); - } else if (is_type_enum(t)) { - ir_emit_store(proc, ir_emit_struct_ep(proc, v, 0), ir_emit_conv(proc, key, hash_type)); - } else if (is_type_typeid(t)) { - irValue *i = ir_emit_bitcast(proc, key, t_uint); - ir_emit_store(proc, ir_emit_struct_ep(proc, v, 0), ir_emit_conv(proc, i, hash_type)); - } else if (is_type_pointer(t)) { - irValue *p = ir_emit_conv(proc, key, t_uintptr); - ir_emit_store(proc, ir_emit_struct_ep(proc, v, 0), ir_emit_conv(proc, p, hash_type)); - } else if (is_type_float(t)) { - irValue *bits = nullptr; - i64 size = type_size_of(t); - switch (8*size) { - case 32: bits = ir_emit_transmute(proc, key, t_u32); break; - case 64: bits = ir_emit_transmute(proc, key, t_u64); break; - default: GB_PANIC("Unhandled float size: %lld bits", size); break; - } - ir_emit_store(proc, ir_emit_struct_ep(proc, v, 0), ir_emit_conv(proc, bits, hash_type)); - } else if (is_type_string(t)) { + if (is_type_string(t)) { irValue *str = ir_emit_conv(proc, key, t_string); irValue *hashed_str = nullptr; @@ -3628,9 +3609,27 @@ irValue *ir_gen_map_key(irProcedure *proc, irValue *key, Type *key_type) { hashed_str = ir_emit_runtime_call(proc, "default_hash_string", args); } ir_emit_store(proc, ir_emit_struct_ep(proc, v, 0), hashed_str); - ir_emit_store(proc, ir_emit_struct_ep(proc, v, 1), str); + + irValue *key_data = ir_emit_struct_ep(proc, v, 1); + key_data = ir_emit_conv(proc, key_data, alloc_type_pointer(key_type)); + ir_emit_store(proc, key_data, str); } else { - GB_PANIC("Unhandled map key type"); + i64 sz = type_size_of(t); + GB_ASSERT(sz <= 8); + if (sz != 0) { + auto args = array_make(ir_allocator(), 2); + args[0] = ir_address_from_load_or_generate_local(proc, key); + args[1] = ir_const_int(sz); + irValue *hash = ir_emit_runtime_call(proc, "default_hash_ptr", args); + + + irValue *hash_ptr = ir_emit_struct_ep(proc, v, 0); + irValue *key_data = ir_emit_struct_ep(proc, v, 1); + key_data = ir_emit_conv(proc, key_data, alloc_type_pointer(key_type)); + + ir_emit_store(proc, hash_ptr, hash); + ir_emit_store(proc, key_data, key); + } } return ir_emit_load(proc, v); @@ -9818,8 +9817,6 @@ void ir_build_range_indexed(irProcedure *proc, irValue *expr, Type *val_type, ir break; } case Type_Map: { - irValue *key = ir_add_local_generated(proc, expr_type->Map.key, true); - irValue *entries = ir_map_entries_ptr(proc, expr); irValue *elem = ir_emit_struct_ep(proc, entries, 0); elem = ir_emit_load(proc, elem); @@ -9827,15 +9824,9 @@ void ir_build_range_indexed(irProcedure *proc, irValue *expr, Type *val_type, ir irValue *entry = ir_emit_ptr_offset(proc, elem, idx); val = ir_emit_load(proc, ir_emit_struct_ep(proc, entry, 2)); - irValue *hash = ir_emit_struct_ep(proc, entry, 0); - if (is_type_string(expr_type->Map.key)) { - irValue *str = ir_emit_struct_ep(proc, hash, 1); - ir_emit_store(proc, key, ir_emit_load(proc, str)); - } else { - irValue *hash_ptr = ir_emit_struct_ep(proc, hash, 0); - hash_ptr = ir_emit_conv(proc, hash_ptr, ir_type(key)); - ir_emit_store(proc, key, ir_emit_load(proc, hash_ptr)); - } + irValue *key_raw = ir_emit_struct_ep(proc, entry, 0); + key_raw = ir_emit_struct_ep(proc, key_raw, 1); + irValue *key = ir_emit_conv(proc, key_raw, alloc_type_pointer(expr_type->Map.key)); idx = ir_emit_load(proc, key); diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 1d0bb7259..706de7d6c 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -3077,8 +3077,6 @@ void lb_build_range_indexed(lbProcedure *p, lbValue expr, Type *val_type, lbValu break; } case Type_Map: { - lbAddr key = lb_add_local_generated(p, expr_type->Map.key, true); - lbValue entries = lb_map_entries_ptr(p, expr); lbValue elem = lb_emit_struct_ep(p, entries, 0); elem = lb_emit_load(p, elem); @@ -3086,17 +3084,11 @@ void lb_build_range_indexed(lbProcedure *p, lbValue expr, Type *val_type, lbValu lbValue entry = lb_emit_ptr_offset(p, elem, idx); val = lb_emit_load(p, lb_emit_struct_ep(p, entry, 2)); - lbValue hash = lb_emit_struct_ep(p, entry, 0); - if (is_type_string(expr_type->Map.key)) { - lbValue str = lb_emit_struct_ep(p, hash, 1); - lb_addr_store(p, key, lb_emit_load(p, str)); - } else { - lbValue hash_ptr = lb_emit_struct_ep(p, hash, 0); - hash_ptr = lb_emit_conv(p, hash_ptr, key.addr.type); - lb_addr_store(p, key, lb_emit_load(p, hash_ptr)); - } + lbValue key_raw = lb_emit_struct_ep(p, entry, 0); + key_raw = lb_emit_struct_ep(p, key_raw, 1); + lbValue key = lb_emit_conv(p, key_raw, alloc_type_pointer(expr_type->Map.key)); - idx = lb_addr_load(p, key); + idx = lb_emit_load(p, key); break; } @@ -9655,45 +9647,45 @@ lbValue lb_gen_map_header(lbProcedure *p, lbValue map_val_ptr, Type *map_type) { lbValue lb_gen_map_key(lbProcedure *p, lbValue key, Type *key_type) { Type *hash_type = t_u64; lbAddr v = lb_add_local_generated(p, t_map_key, true); + lbValue vp = lb_addr_get_ptr(p, v); Type *t = base_type(key.type); key = lb_emit_conv(p, key, key_type); - if (is_type_integer(t)) { - lb_emit_store(p, lb_emit_struct_ep(p, v.addr, 0), lb_emit_conv(p, key, hash_type)); - } else if (is_type_enum(t)) { - lb_emit_store(p, lb_emit_struct_ep(p, v.addr, 0), lb_emit_conv(p, key, hash_type)); - } else if (is_type_typeid(t)) { - lbValue i = lb_emit_transmute(p, key, t_uint); - lb_emit_store(p, lb_emit_struct_ep(p, v.addr, 0), lb_emit_conv(p, i, hash_type)); - } else if (is_type_pointer(t)) { - lbValue ptr = lb_emit_conv(p, key, t_uintptr); - lb_emit_store(p, lb_emit_struct_ep(p, v.addr, 0), lb_emit_conv(p, ptr, hash_type)); - } else if (is_type_float(t)) { - lbValue bits = {}; - i64 size = type_size_of(t); - switch (8*size) { - case 32: bits = lb_emit_transmute(p, key, t_u32); break; - case 64: bits = lb_emit_transmute(p, key, t_u64); break; - default: GB_PANIC("Unhandled float size: %lld bits", size); break; - } - lb_emit_store(p, lb_emit_struct_ep(p, v.addr, 0), lb_emit_conv(p, bits, hash_type)); - } else if (is_type_string(t)) { + if (is_type_string(t)) { lbValue str = lb_emit_conv(p, key, t_string); lbValue hashed_str = {}; - if (false && lb_is_const(str)) { - String value = lb_get_const_string(p->module, str); - u64 hs = fnv64a(value.text, value.len); - hashed_str = lb_const_value(p->module, t_u64, exact_value_u64(hs)); + if (lb_is_const(str)) { + String v = lb_get_const_string(p->module, str); + u64 hs = fnv64a(v.text, v.len); + hashed_str = lb_const_int(p->module, t_u64, hs); } else { auto args = array_make(heap_allocator(), 1); args[0] = str; hashed_str = lb_emit_runtime_call(p, "default_hash_string", args); } - lb_emit_store(p, lb_emit_struct_ep(p, v.addr, 0), hashed_str); - lb_emit_store(p, lb_emit_struct_ep(p, v.addr, 1), str); + lb_emit_store(p, lb_emit_struct_ep(p, vp, 0), hashed_str); + + lbValue key_data = lb_emit_struct_ep(p, vp, 1); + key_data = lb_emit_conv(p, key_data, alloc_type_pointer(key_type)); + lb_emit_store(p, key_data, str); } else { - GB_PANIC("Unhandled map key type"); + i64 sz = type_size_of(t); + GB_ASSERT(sz <= 8); + if (sz != 0) { + auto args = array_make(heap_allocator(), 2); + args[0] = lb_address_from_load_or_generate_local(p, key); + args[1] = lb_const_int(p->module, t_int, sz); + lbValue hash = lb_emit_runtime_call(p, "default_hash_ptr", args); + + + lbValue hash_ptr = lb_emit_struct_ep(p, vp, 0); + lbValue key_data = lb_emit_struct_ep(p, vp, 1); + key_data = lb_emit_conv(p, key_data, alloc_type_pointer(key_type)); + + lb_emit_store(p, hash_ptr, hash); + lb_emit_store(p, key_data, key); + } } return lb_addr_load(p, v);