I want to mention couple of issues with latest changes to debug system. When DEBUGUI_xyz defines were replaced with DEBUG_IF and DEBUG_VALUE macros in day 213/214 there are now two issues not handled:
1) if DEBUG_IF macro will be nested and top level if is false, then debug system will not see nested if or other nested variables. This means during recompilation debug system will not be able to generate GlobalConstants_xyz define in "handmade_config.h" file. Before this was not a problem, because all variables were manually listed. Now it is a problem. For example:
| DEBUG_IF(Something_UseFoo)
{
DEBUG_IF(SomethingElse_UseBar)
{
DEBUG_VARIABLE(r32, Renderer_Camera, DebugDistance);
DistanceAboveTarget += DebugDistance;
}
}
|
If "Something_UseFoo" is false then debug system won't be able to generate these two lines:
| #define GlobalConstants_SomethingElse_UseBar 0
#define GlobalConstants_Renderer_Camera_DebugDistance 25.0f
|
This means code won't compile after "handmade_config.h" file is regenerated.
2) local "static" variables (local_persist) are
NOT thread-safe in MSVC 2013. In C++ standard local static variables are thread safe only starting with C++11 compiler. This means if compiler supports C++11 it is required to generate thread-safe code for local static variables. Otherwise it can do whatever it wants. MSVC 2013 (and lower) are not C++11 compatible compiler, so it generates non thread-safe code. MSVC 2015 is C++11 compatible compiler - it generates thread-safe code. GCC recent versions always generate thread safe code.
Here's an example:
| int f(int x)
{
static int a = x;
return a;
}
|
MSVC 2013 generates following assembly (x64):
1
2
3
4
5
6
7
8
9
10
11
12 | ?f@@YAHH@Z PROC ; f, COMDAT
mov eax, ecx
mov ecx, DWORD PTR ?$S1@?1??f@@YAHH@Z@4IA
test cl, 1
jne SHORT $LN4@f
or ecx, 1
mov DWORD PTR ?a@?1??f@@YAHH@Z@4HA, eax
mov DWORD PTR ?$S1@?1??f@@YAHH@Z@4IA, ecx
ret 0
$LN4@f:
mov eax, DWORD PTR ?a@?1??f@@YAHH@Z@4HA
ret 0
|
MSVC 2015 generates following assembly (x64):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 | ?f@@YAHH@Z PROC ; f, COMDAT
push rbx
sub rsp, 32 ; 00000020H
mov edx, DWORD PTR _tls_index
mov ebx, ecx
mov rax, QWORD PTR gs:88
mov ecx, OFFSET FLAT:_Init_thread_epoch
mov rax, QWORD PTR [rax+rdx*8]
mov edx, DWORD PTR [rcx+rax]
cmp DWORD PTR ?$TSS0@?1??f@@YAHH@Z@4HA, edx
jle SHORT $LN4@f
lea rcx, OFFSET FLAT:?$TSS0@?1??f@@YAHH@Z@4HA
call _Init_thread_header
cmp DWORD PTR ?$TSS0@?1??f@@YAHH@Z@4HA, -1
jne SHORT $LN4@f
lea rcx, OFFSET FLAT:?$TSS0@?1??f@@YAHH@Z@4HA
mov DWORD PTR ?a@?1??f@@YAHH@Z@4HA, ebx
call _Init_thread_footer
$LN4@f:
mov eax, DWORD PTR ?a@?1??f@@YAHH@Z@4HA
add rsp, 32 ; 00000020H
pop rbx
ret 0
|
gcc 5.2.0 generates following assembly (x64):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 | _Z1fi:
pushq %rbx
subq $32, %rsp
cmpb $0, _ZGVZ1fiE1a(%rip)
movl %ecx, %ebx
je .L7
.L5:
movl _ZZ1fiE1a(%rip), %eax
addq $32, %rsp
popq %rbx
ret
.L7:
leaq _ZGVZ1fiE1a(%rip), %rcx
call __cxa_guard_acquire
testl %eax, %eax
je .L5
leaq _ZGVZ1fiE1a(%rip), %rcx
movl %ebx, _ZZ1fiE1a(%rip)
call __cxa_guard_release
movl %ebx, %eax
addq $32, %rsp
popq %rbx
ret
|
As you can see both MSVC 2015 and gcc use some internal C runtime functions to guarantee that local static variable is initialized only once. MSVC 2013 doesn't.
You can actually make statics non thread-safe if you want - use "-fno-threadsafe-statics" for gcc and "/Zc:threadSafeInit" for MSVC 2015.
clang generates either gcc or msvc style of code - depeneding on what runtime you are targeting.
So on MSVC 2013 this can potentially lead to duplicate allocation of variables in debug system.