diff --git a/core/encoding/json/unmarshal.odin b/core/encoding/json/unmarshal.odin index ba646b0b7..8c21098fb 100644 --- a/core/encoding/json/unmarshal.odin +++ b/core/encoding/json/unmarshal.odin @@ -370,13 +370,13 @@ unmarshal_object :: proc(p: ^Parser, v: any, end_token: Token_Kind) -> (err: Unm fields := reflect.struct_fields_zipped(ti.id) - field_test :: #force_inline proc "contextless" (field_used: [^]byte, index: int) -> bool { - prev_set := field_used[index/8] & byte(index&7) != 0 - field_used[index/8] |= byte(index&7) + field_test :: #force_inline proc "contextless" (field_used: [^]byte, offset: uintptr) -> bool { + prev_set := field_used[offset/8] & byte(offset&7) != 0 + field_used[offset/8] |= byte(offset&7) return prev_set } - field_used_bytes := (len(fields)+7)/8 + field_used_bytes := (reflect.size_of_typeid(ti.id)+7)/8 field_used := intrinsics.alloca(field_used_bytes, 1) intrinsics.mem_zero(field_used, field_used_bytes) @@ -399,13 +399,45 @@ unmarshal_object :: proc(p: ^Parser, v: any, end_token: Token_Kind) -> (err: Unm } } - if use_field_idx >= 0 { - if field_test(field_used, use_field_idx) { + check_children_using_fields :: proc(key: string, parent: typeid) -> ( + offset: uintptr, + type: ^reflect.Type_Info, + found: bool, + ) { + for field in reflect.struct_fields_zipped(parent) { + if field.is_using && field.name == "_" { + offset, type, found = check_children_using_fields(key, field.type.id) + if found { + offset += field.offset + return + } + } + + if field.name == key { + offset = field.offset + type = field.type + found = true + return + } + } + return + } + + offset: uintptr + type: ^reflect.Type_Info + field_found: bool = use_field_idx >= 0 + + if field_found { + offset = fields[use_field_idx].offset + type = fields[use_field_idx].type + } else { + offset, type, field_found = check_children_using_fields(key, ti.id) + } + + if field_found { + if field_test(field_used, offset) { return .Multiple_Use_Field } - offset := fields[use_field_idx].offset - type := fields[use_field_idx].type - name := fields[use_field_idx].name field_ptr := rawptr(uintptr(v.data) + offset) field := any{field_ptr, type.id} diff --git a/core/sys/info/platform_darwin.odin b/core/sys/info/platform_darwin.odin index e8006d175..b95a48bd0 100644 --- a/core/sys/info/platform_darwin.odin +++ b/core/sys/info/platform_darwin.odin @@ -525,6 +525,7 @@ macos_release_map: map[string]Darwin_To_Release = { "23D56" = {{23, 3, 0}, "macOS", {"Sonoma", {14, 3, 0}}}, "23D60" = {{23, 3, 0}, "macOS", {"Sonoma", {14, 3, 1}}}, "23E214" = {{23, 4, 0}, "macOS", {"Sonoma", {14, 4, 0}}}, + "23E224" = {{23, 4, 0}, "macOS", {"Sonoma", {14, 4, 1}}}, } @(private) @@ -568,4 +569,4 @@ map_darwin_kernel_version_to_macos_release :: proc(build: string, darwin: [3]int } else { return nearest, .Nearest } -} \ No newline at end of file +} diff --git a/src/bug_report.cpp b/src/bug_report.cpp index 7b4999943..e919ba67b 100644 --- a/src/bug_report.cpp +++ b/src/bug_report.cpp @@ -888,6 +888,7 @@ gb_internal void report_os_info() { {"23D56", {23, 3, 0}, "macOS", {"Sonoma", {14, 3, 0}}}, {"23D60", {23, 3, 0}, "macOS", {"Sonoma", {14, 3, 1}}}, {"23E214", {23, 4, 0}, "macOS", {"Sonoma", {14, 4, 0}}}, + {"23E224", {23, 4, 0}, "macOS", {"Sonoma", {14, 4, 1}}}, }; diff --git a/src/build_settings.cpp b/src/build_settings.cpp index 3a9951cb2..1ac9e451f 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -1189,12 +1189,24 @@ gb_internal String path_to_fullpath(gbAllocator a, String s, bool *ok_) { return result; } #elif defined(GB_SYSTEM_OSX) || defined(GB_SYSTEM_UNIX) + +struct PathToFullpathResult { + String result; + bool ok; +}; + gb_internal String path_to_fullpath(gbAllocator a, String s, bool *ok_) { + static gb_thread_local StringMap cache; + + PathToFullpathResult *cached = string_map_get(&cache, s); + if (cached != nullptr) { + if (ok_) *ok_ = cached->ok; + return copy_string(a, cached->result); + } + char *p; - mutex_lock(&fullpath_mutex); p = realpath(cast(char *)s.text, 0); defer (free(p)); - mutex_unlock(&fullpath_mutex); if(p == nullptr) { if (ok_) *ok_ = false; @@ -1207,10 +1219,24 @@ gb_internal String path_to_fullpath(gbAllocator a, String s, bool *ok_) { // // I have opted for 2 because it is much simpler + we already return `ok = false` + further // checks and processes will use the path and cause errors (which we want). - return copy_string(a, s); + String result = copy_string(a, s); + + PathToFullpathResult cached_result = {}; + cached_result.result = copy_string(permanent_allocator(), result); + cached_result.ok = false; + string_map_set(&cache, copy_string(permanent_allocator(), s), cached_result); + + return result; } if (ok_) *ok_ = true; - return copy_string(a, make_string_c(p)); + String result = copy_string(a, make_string_c(p)); + + PathToFullpathResult cached_result = {}; + cached_result.result = copy_string(permanent_allocator(), result); + cached_result.ok = true; + string_map_set(&cache, copy_string(permanent_allocator(), s), cached_result); + + return result; } #else #error Implement system diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 3a275729f..c7a1b460a 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -2419,10 +2419,6 @@ gb_internal bool check_is_not_addressable(CheckerContext *c, Operand *o) { } gb_internal void check_old_for_or_switch_value_usage(Ast *expr) { - if (!(build_context.strict_style || (check_vet_flags(expr) & VetFlag_Style))) { - return; - } - Entity *e = entity_of_node(expr); if (e != nullptr && (e->flags & EntityFlag_OldForOrSwitchValue) != 0) { GB_ASSERT(e->kind == Entity_Variable); diff --git a/src/check_type.cpp b/src/check_type.cpp index 40a7ec947..609b73229 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -2477,10 +2477,6 @@ gb_internal Type *get_map_cell_type(Type *type) { return type; } - if (is_power_of_two(len)) { - return type; - } - i64 padding = size - len*elem_size; GB_ASSERT(padding > 0); @@ -2526,18 +2522,16 @@ gb_internal void init_map_internal_types(Type *type) { gb_unused(type_size_of(metadata_type)); - // NOTE(bill): [0]^struct{key: Key, value: Value, hash: uintptr} - // This is a zero array to a pointer to keep the alignment to that of a pointer, and not effective the size of the final struct - metadata_type = alloc_type_array(alloc_type_pointer(metadata_type), 0);; + // NOTE(bill): ^struct{key: Key, value: Value, hash: uintptr} + metadata_type = alloc_type_pointer(metadata_type); Scope *scope = create_scope(nullptr, nullptr); Type *debug_type = alloc_type_struct(); - debug_type->Struct.fields = slice_make(permanent_allocator(), 4); - debug_type->Struct.fields[0] = alloc_entity_field(scope, make_token_ident("data"), t_uintptr, false, 0, EntityState_Resolved); + debug_type->Struct.fields = slice_make(permanent_allocator(), 3); + debug_type->Struct.fields[0] = alloc_entity_field(scope, make_token_ident("data"), metadata_type, false, 0, EntityState_Resolved); debug_type->Struct.fields[1] = alloc_entity_field(scope, make_token_ident("len"), t_int, false, 1, EntityState_Resolved); debug_type->Struct.fields[2] = alloc_entity_field(scope, make_token_ident("allocator"), t_allocator, false, 2, EntityState_Resolved); - debug_type->Struct.fields[3] = alloc_entity_field(scope, make_token_ident("__metadata"), metadata_type, false, 3, EntityState_Resolved); debug_type->Struct.scope = scope; debug_type->Struct.node = nullptr; wait_signal_set(&debug_type->Struct.fields_wait_signal); diff --git a/src/gb/gb.h b/src/gb/gb.h index 702647121..868e11a16 100644 --- a/src/gb/gb.h +++ b/src/gb/gb.h @@ -144,8 +144,6 @@ extern "C" { #error Unknown CPU Type #endif - - #ifndef GB_STATIC_ASSERT #define GB_STATIC_ASSERT3(cond, msg) typedef char static_assertion_##msg[(!!(cond))*2-1] // NOTE(bill): Token pasting madness!! @@ -480,6 +478,13 @@ typedef i32 b32; // NOTE(bill): Prefer this!!! #endif #endif +#if !defined(gb_no_asan) + #if defined(_MSC_VER) + #define gb_no_asan __declspec(no_sanitize_address) + #else + #define gb_no_asan __attribute__((disable_sanitizer_instrumentation)) + #endif +#endif // NOTE(bill): Easy to grep // NOTE(bill): Not needed in macros @@ -3573,7 +3578,7 @@ gb_inline void gb_str_to_upper(char *str) { } -gb_inline isize gb_strlen(char const *str) { +gb_no_asan isize gb_strlen(char const *str) { char const *begin = str; isize const *w; if (str == NULL) { @@ -5679,7 +5684,7 @@ char *gb_path_get_full_name(gbAllocator a, char const *path) { isize path_len = gb_strlen(path); isize cwd_len = gb_strlen(cwd); len = cwd_len + 1 + path_len + 1; - result = gb_alloc_array(a, char, len); + result = gb_alloc_array(a, char, len+1); gb_memmove(result, (void *)cwd, cwd_len); result[cwd_len] = '/'; diff --git a/src/llvm_abi.cpp b/src/llvm_abi.cpp index 5f5f734fb..724e4e35a 100644 --- a/src/llvm_abi.cpp +++ b/src/llvm_abi.cpp @@ -876,7 +876,8 @@ namespace lbAbiAmd64SysV { if (types.count == 1) { return types[0]; } - return LLVMStructTypeInContext(c, types.data, cast(unsigned)types.count, true); + // TODO(bill): this should be packed but it causes code generation issues + return LLVMStructTypeInContext(c, types.data, cast(unsigned)types.count, false); } gb_internal void classify_with(LLVMTypeRef t, Array *cls, i64 ix, i64 off) { @@ -1165,7 +1166,8 @@ namespace lbAbiArm64 { size_copy -= 8; } GB_ASSERT(size_copy <= 0); - cast_type = LLVMStructTypeInContext(c, types, count, true); + // TODO(bill): this should be packed but it causes code generation issues + cast_type = LLVMStructTypeInContext(c, types, count, false); } return lb_arg_type_direct(return_type, cast_type, nullptr, nullptr); } else { diff --git a/src/llvm_backend_const.cpp b/src/llvm_backend_const.cpp index bbb0b8387..1ca5f4965 100644 --- a/src/llvm_backend_const.cpp +++ b/src/llvm_backend_const.cpp @@ -730,9 +730,21 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo return res; case ExactValue_Float: if (is_type_different_to_arch_endianness(type)) { - u64 u = bit_cast(value.value_float); - u = gb_endian_swap64(u); - res.value = LLVMConstReal(lb_type(m, original_type), bit_cast(u)); + if (type->Basic.kind == Basic_f32le || type->Basic.kind == Basic_f32be) { + f32 f = static_cast(value.value_float); + u32 u = bit_cast(f); + u = gb_endian_swap32(u); + res.value = LLVMConstReal(lb_type(m, original_type), bit_cast(u)); + } else if (type->Basic.kind == Basic_f16le || type->Basic.kind == Basic_f16be) { + f32 f = static_cast(value.value_float); + u16 u = f32_to_f16(f); + u = gb_endian_swap16(u); + res.value = LLVMConstReal(lb_type(m, original_type), f16_to_f32(u)); + } else { + u64 u = bit_cast(value.value_float); + u = gb_endian_swap64(u); + res.value = LLVMConstReal(lb_type(m, original_type), bit_cast(u)); + } } else { res.value = LLVMConstReal(lb_type(m, original_type), value.value_float); } diff --git a/src/llvm_backend_debug.cpp b/src/llvm_backend_debug.cpp index c06026568..048f5f933 100644 --- a/src/llvm_backend_debug.cpp +++ b/src/llvm_backend_debug.cpp @@ -652,7 +652,9 @@ gb_internal void lb_debug_complete_types(lbModule *m) { for_array(debug_incomplete_type_index, m->debug_incomplete_types) { TEMPORARY_ALLOCATOR_GUARD(); - auto const &idt = m->debug_incomplete_types[debug_incomplete_type_index]; + // NOTE(laytan): don't make this a pointer, the array could resize while in this iteration + // and cause a use-after-free at the end. + auto const idt = m->debug_incomplete_types[debug_incomplete_type_index]; GB_ASSERT(idt.type != nullptr); GB_ASSERT(idt.metadata != nullptr); @@ -746,8 +748,8 @@ gb_internal void lb_debug_complete_types(lbModule *m) { case Type_Map: GB_ASSERT(t_raw_map != nullptr); - // bt = base_type(bt->Map.debug_metadata_type); - bt = base_type(t_raw_map); + bt = base_type(bt->Map.debug_metadata_type); + // bt = base_type(t_raw_map); GB_ASSERT(bt->kind == Type_Struct); /*fallthrough*/ case Type_Struct: diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index 3c6a51bdc..a77e2ad15 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -2121,16 +2121,18 @@ gb_internal LLVMTypeRef lb_type_internal(lbModule *m, Type *type) { array_add(&fields, padding_type); } - i64 padding_offset = 0; + i64 prev_offset = 0; for (i32 field_index : struct_fields_index_by_increasing_offset(temporary_allocator(), type)) { Entity *field = type->Struct.fields[field_index]; - i64 padding = type->Struct.offsets[field_index] - padding_offset; + i64 offset = type->Struct.offsets[field_index]; + GB_ASSERT(offset >= prev_offset); + i64 padding = offset - prev_offset; if (padding != 0) { LLVMTypeRef padding_type = lb_type_padding_filler(m, padding, type_align_of(field->type)); array_add(&fields, padding_type); } - + field_remapping[field_index] = cast(i32)fields.count; Type *field_type = field->type; @@ -2141,14 +2143,11 @@ gb_internal LLVMTypeRef lb_type_internal(lbModule *m, Type *type) { } array_add(&fields, lb_type(m, field_type)); - - if (!type->Struct.is_packed) { - padding_offset = align_formula(padding_offset, type_align_of(field->type)); - } - padding_offset += type_size_of(field->type); + + prev_offset = offset + type_size_of(field->type); } - i64 end_padding = full_type_size-padding_offset; + i64 end_padding = full_type_size-prev_offset; if (end_padding > 0) { array_add(&fields, lb_type_padding_filler(m, end_padding, 1)); } diff --git a/src/timings.cpp b/src/timings.cpp index baa8b80da..712e804cb 100644 --- a/src/timings.cpp +++ b/src/timings.cpp @@ -33,22 +33,23 @@ gb_internal u64 win32_time_stamp__freq(void) { #include +gb_internal mach_timebase_info_data_t osx_init_timebase_info(void) { + mach_timebase_info_data_t data; + data.numer = 0; + data.denom = 0; + kern_return_t r = mach_timebase_info(&data); + GB_ASSERT(r == KERN_SUCCESS); + + return data; +} + gb_internal u64 osx_time_stamp_time_now(void) { return mach_absolute_time(); } gb_internal u64 osx_time_stamp__freq(void) { - mach_timebase_info_data_t data; - data.numer = 0; - data.denom = 0; - mach_timebase_info(&data); -#if defined(GB_CPU_ARM) - // NOTE(bill, 2021-02-25): M1 Chip seems to have a different freq count - // TODO(bill): Is this truly correct? - return (1000000llu * cast(u64)data.numer) / cast(u64)data.denom; -#else - return (1000000000llu * cast(u64)data.numer) / cast(u64)data.denom; -#endif + gb_local_persist mach_timebase_info_data_t data = osx_init_timebase_info(); + return 1000000000ull * cast(u64)data.denom / cast(u64)data.numer; } #elif defined(GB_SYSTEM_UNIX)