FazBrowse GitHub Viewer
|
Trending
|
URL:
|
Home
Tools:
[Download Repo ZIP]
[View Raw Code]
[Original HTTPS Page]
daScript/src/misc/gc_node.cpp at master · WhyNot135/daScript · GitHub
WhyNot135
/
daScript
Public
forked from
GaijinEntertainment/daScript
Notifications
You must be signed in to change notification settings
Fork
0
Star
0
Code
Pull requests
0
Actions
Projects
Security and quality
0
Insights
Additional navigation options
Code
Pull requests
Actions
Projects
Security and quality
Insights
Expand file tree
Breadcrumbs
daScript
/
src
/
misc
/
gc_node.cpp
Copy path
More file actions
More file actions
Latest commit
History
History
History
313 lines (276 loc) · 9.85 KB
Breadcrumbs
daScript
/
src
/
misc
/
gc_node.cpp
Copy path
File metadata and controls
313 lines (276 loc) · 9.85 KB
Raw
Copy raw file
Download raw file
Open symbols panel
Edit and raw actions
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
#
include
"
daScript/misc/platform.h
"
#
include
"
daScript/misc/gc_node.h
"
#
include
"
daScript/misc/crash_handler.h
"
#
include
<
inttypes.h
>
#
include
<
stdlib.h
>
namespace
das
{
//
debugging id - to break on
static
uint64_t
gc_break_on_id =
0
;
//
installed by the AST layer (ast_gc_report.cpp); see gc_node.h
DAS_API
gc_describe_fn gc_node_describe_hook =
nullptr
;
//
---- gc_root statics ----
static
thread_local
gc_root s_gc_thread_root;
static
thread_local
gc_root * s_gc_active_root = &s_gc_thread_root;
std::atomic<
uint64_t
> gc_root::gc_next_id {
1
};
static
void
gc_check_break
(
uint64_t
id );
gc_root &
gc_root::gc_get_thread_root
() {
return
s_gc_thread_root;
}
gc_root * &
gc_root::gc_get_active_root
() {
return
s_gc_active_root;
}
//
---- gc_root ----
gc_root::~gc_root
() {
if
( gc_first ) {
gc_sweep
();
}
}
void
gc_root::gc_link
( gc_node * node ) {
DAS_ASSERT
(node &&
"
gc_link: null node
"
);
DAS_ASSERT
(node->
gc_owner
==
nullptr
&&
"
gc_link: node already on a root
"
);
//
gc_check_break(node->gc_id);
node->
gc_owner
=
this
;
node->
gc_prev
= gc_last;
node->
gc_next
=
nullptr
;
if
( gc_last ) {
gc_last->
gc_next
= node;
}
else
{
gc_first = node;
}
gc_last = node;
gc_count++;
}
void
gc_root::gc_unlink
( gc_node * node ) {
DAS_ASSERT
(node &&
"
gc_unlink: null node
"
);
DAS_ASSERT
(node->
gc_owner
==
this
&&
"
gc_unlink: node not on this root
"
);
//
gc_check_break(node->gc_id);
if
( node->
gc_prev
) {
node->
gc_prev
->
gc_next
= node->
gc_next
;
}
else
{
gc_first = node->
gc_next
;
}
if
( node->
gc_next
) {
node->
gc_next
->
gc_prev
= node->
gc_prev
;
}
else
{
gc_last = node->
gc_prev
;
}
node->
gc_prev
=
nullptr
;
node->
gc_next
=
nullptr
;
node->
gc_owner
=
nullptr
;
DAS_ASSERT
(gc_count >
0
);
gc_count--;
}
void
gc_root::gc_sweep
() {
gc_collecting =
true
;
while
( gc_first ) {
auto
node = gc_first;
gc_unlink
(node);
uint32_t
swept_magic =
GC_MAGIC_SWEPT_PREFIX
| (node->
gc_magic
&
0xFFFFu
);
#
if
DAS_GC_DEBUG
//
!!! DO NOT REMOVE !!!
//
Memory poisoning mode for debugging use-after-sweep.
//
Destroys the object but keeps memory allocated with 0xCD fill.
//
gc_magic (with type tag) and gc_id are restored so crashed nodes can be identified.
//
Set DAS_GC_DEBUG=1 to enable, then use DAS_GC_BREAK_ON_ID to find the creator.
{
uint64_t
saved_id = node->
gc_id
;
node->
~gc_node
();
#
ifdef
_MSC_VER
auto
sz =
_msize
(node);
#
elif
defined(__APPLE__)
auto
sz =
malloc_size
(node);
#
else
auto
sz =
malloc_usable_size
(node);
#
endif
memset
(node,
0xCD
, sz);
node->
gc_magic
= swept_magic;
node->
gc_id
= saved_id;
}
#
else
node->
gc_magic
= swept_magic;
delete
node;
#
endif
}
gc_collecting =
false
;
}
void
gc_root::gc_dump_to_thread_root
() {
auto
& threadRoot =
gc_get_thread_root
();
while
( gc_first ) {
auto
node = gc_first;
gc_unlink
(node);
threadRoot.
gc_link
(node);
}
}
void
gc_root::gc_report
()
const
{
DAS_FATAL_LOG
(
"
gc_root %p: count=%
"
PRIu64
"
\n
"
, (
const
void
*)
this
, gc_count);
char
atbuf[
256
];
auto
node = gc_first;
while
( node ) {
atbuf[
0
] =
0
;
if
( gc_node_describe_hook )
gc_node_describe_hook
(node, atbuf, (
int
)
sizeof
(atbuf));
DAS_FATAL_LOG
(
"
node %p: id=%
"
PRIu64
"
type=%s magic=0x%08x %s
\n
"
,
(
const
void
*)node, node->
gc_id
, node->
gc_type_name
(), node->
gc_magic
, atbuf);
node = node->
gc_next
;
}
}
//
---- gc_node debug break ----
//
Set gc_break_on_id via debugger or env DAS_GC_BREAK_ON_ID to break
//
when a specific gc_id is assigned. Useful for tracing where a leaked node was born.
static
uint64_t
gc_init_break_on_id
() {
if
(
auto
env =
getenv
(
"
DAS_GC_BREAK_ON_ID
"
) ) {
return
strtoull
(env,
nullptr
,
0
);
}
return
0
;
}
static
void
gc_check_break
(
uint64_t
id ) {
if
( gc_break_on_id ==
0
) {
static
bool
once =
true
;
if
( once ) { once =
false
; gc_break_on_id =
gc_init_break_on_id
(); }
}
if
( gc_break_on_id && id == gc_break_on_id ) {
DAS_FATAL_LOG
(
"
gc_node break: id=%
"
PRIu64
"
\n
"
, id);
print_current_stack_trace
();
os_debug_break
();
}
}
//
---- gc_node ----
gc_node::gc_node
() {
gc_id = gc_root::gc_next_id.
fetch_add
(
1
, std::memory_order_relaxed);
gc_check_break
(gc_id);
gc_root::gc_get_active_root
()->
gc_link
(
this
);
}
gc_node::gc_node
(
const
gc_node & ) {
//
New node with new ID, linked to the active root. Does NOT copy list position.
gc_id = gc_root::gc_next_id.
fetch_add
(
1
, std::memory_order_relaxed);
gc_check_break
(gc_id);
gc_root::gc_get_active_root
()->
gc_link
(
this
);
}
gc_node::gc_node
( gc_node && src ) {
//
Take over source's list position
gc_magic = src.
gc_magic
;
gc_id = src.
gc_id
;
gc_prev = src.
gc_prev
;
gc_next = src.
gc_next
;
gc_owner = src.
gc_owner
;
//
Patch neighbors to point to us
if
( gc_prev ) {
gc_prev->
gc_next
=
this
;
}
else
if
( gc_owner ) {
gc_owner->
gc_first
=
this
;
}
if
( gc_next ) {
gc_next->
gc_prev
=
this
;
}
else
if
( gc_owner ) {
gc_owner->
gc_last
=
this
;
}
//
Detach source
src.
gc_prev
=
nullptr
;
src.
gc_next
=
nullptr
;
src.
gc_owner
=
nullptr
;
src.
gc_magic
=
GC_MAGIC_DEAD
;
}
gc_node & gc_node::
operator
= ( gc_node && src ) {
if
(
this
== &src )
return
*
this
;
//
Unlink self from current root
if
( gc_owner ) {
gc_owner->
gc_unlink
(
this
);
}
//
Take over source's list position
gc_magic = src.
gc_magic
;
gc_id = src.
gc_id
;
gc_prev = src.
gc_prev
;
gc_next = src.
gc_next
;
gc_owner = src.
gc_owner
;
if
( gc_prev ) {
gc_prev->
gc_next
=
this
;
}
else
if
( gc_owner ) {
gc_owner->
gc_first
=
this
;
}
if
( gc_next ) {
gc_next->
gc_prev
=
this
;
}
else
if
( gc_owner ) {
gc_owner->
gc_last
=
this
;
}
src.
gc_prev
=
nullptr
;
src.
gc_next
=
nullptr
;
src.
gc_owner
=
nullptr
;
src.
gc_magic
=
GC_MAGIC_DEAD
;
return
*
this
;
}
gc_node::~gc_node
() {
gc_check_break
(gc_id);
if
( gc_owner ) {
//
Node is being deleted outside of gc_sweep.
//
During the migration period, this can happen legitimately when old code
//
paths delete TypeDecl. In DAS_GC_DEBUG mode, assert to catch bugs.
#
if
DAS_GC_DEBUG
if
( !gc_owner->
gc_collecting
) {
DAS_FATAL_LOG
(
"
gc_node id=%
"
PRIu64
"
deleted outside of gc_sweep
\n
"
, gc_id);
DAS_ASSERTF
(
false
,
"
gc_node id=%
"
PRIu64
"
deleted outside of gc_sweep
"
, gc_id);
}
#
endif
gc_owner->
gc_unlink
(
this
);
}
if
(
gc_is_alive
() ) {
gc_magic =
GC_MAGIC_DEAD
;
}
}
void
gc_node::gc_unlink
() {
if
( gc_owner ) {
gc_owner->
gc_unlink
(
this
);
}
}
void
gc_node::gc_link
( gc_root * root ) {
DAS_ASSERT
(gc_owner ==
nullptr
&&
"
gc_link: already linked
"
);
root->
gc_link
(
this
);
}
void
gc_node::gc_assign
( gc_root * new_root ) {
if
( gc_owner == new_root )
return
;
if
( gc_owner ) {
gc_owner->
gc_unlink
(
this
);
}
new_root->
gc_link
(
this
);
}
const
char
*
gc_node::gc_type_name
()
const
{
uint16_t
tag = gc_magic &
0xFFFFu
;
switch
( tag ) {
case
GC_TAG_TYPEDECL
:
return
"
TypeDecl
"
;
case
GC_TAG_EXPRESSION
:
return
"
Expression
"
;
case
GC_TAG_MAKEFIELDDECL
:
return
"
MakeFieldDecl
"
;
case
GC_TAG_MAKESTRUCT
:
return
"
MakeStruct
"
;
case
GC_TAG_FUNCTION
:
return
"
Function
"
;
case
GC_TAG_ENUMERATION
:
return
"
Enumeration
"
;
case
GC_TAG_STRUCTURE
:
return
"
Structure
"
;
case
GC_TAG_VARIABLE
:
return
"
Variable
"
;
default
:
return
"
gc_node
"
;
}
}
void
gc_node::gc_verify
()
const
{
if
( !
gc_is_alive
() ) {
const
char
* typeName =
gc_type_name
();
if
( (gc_magic &
0xFFFF0000u
) ==
GC_MAGIC_SWEPT_PREFIX
) {
DAS_FATAL_ERROR
(
"
%s id=%
"
PRIu64
"
was already swept (use-after-sweep)
"
, typeName, gc_id);
}
else
if
( gc_magic ==
GC_MAGIC_DEAD
) {
DAS_FATAL_ERROR
(
"
%s id=%
"
PRIu64
"
was already deleted (use-after-free)
"
, typeName, gc_id);
}
else
{
DAS_FATAL_ERROR
(
"
%s id=%
"
PRIu64
"
has corrupt magic=0x%08x
"
, typeName, gc_id, gc_magic);
}
}
}
//
---- gc_guard ----
gc_guard::gc_guard
() {
saved_thread_root =
gc_root::gc_get_active_root
();
gc_root::gc_get_active_root
() = &guard_root;
}
gc_guard::~gc_guard
() {
gc_root::gc_get_active_root
() = saved_thread_root;
guard_root.
gc_sweep
();
}
gc_active_scope::gc_active_scope
( gc_root * use ) {
saved_active =
gc_root::gc_get_active_root
();
gc_root::gc_get_active_root
() = use;
}
gc_active_scope::~gc_active_scope
() {
gc_root::gc_get_active_root
() = saved_active;
}
}
Back
|
FazBrowse Home
|
New Git URL