少年修仙传客户端基础资源
hch
2024-04-01 d01413b00ef631ac20347716b23818b0b811f65f
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
/**
 * \file
 * This is where objects are copied.
 *
 * Copyright 2001-2003 Ximian, Inc
 * Copyright 2003-2010 Novell, Inc.
 * Copyright (C) 2012 Xamarin Inc
 *
 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
 */
 
/*
 * Defines
 *
 *     GCObject* copy_object_no_checks (GCObject *obj, SgenGrayQueue *queue)
 *
 * which allocates new space for `obj`, copies it there, forwards `obj` to its new location,
 * and enqueues the copy into `queue`.
 *
 * To be defined by the includer:
 *
 *     COLLECTOR_SERIAL_ALLOC_FOR_PROMOTION(vt, obj, objsize, has_refs)
 *
 * Allocates space for promoting object `obj`, with size `objsize`, and initizializes the
 * vtable with `vt`.  `has_refs` indicates whether the object contains references.
 *
 *     collector_pin_object(obj, queue)
 *
 * Called when no space for `obj` could be allocated.  It must pin `obj` and enqueue it into
 * `queue` for scanning.
 */
 
extern guint64 stat_copy_object_called_nursery;
extern guint64 stat_objects_copied_nursery;
 
extern guint64 stat_nursery_copy_object_failed_from_space;
extern guint64 stat_nursery_copy_object_failed_forwarded;
extern guint64 stat_nursery_copy_object_failed_pinned;
 
extern guint64 stat_slots_allocated_in_vain;
 
/*
 * This function can be used even if the vtable of obj is not valid
 * anymore, which is the case in the parallel collector.
 */
static MONO_ALWAYS_INLINE void
par_copy_object_no_checks (char *destination, GCVTable vt, void *obj, mword objsize)
{
    sgen_client_pre_copy_checks (destination, vt, obj, objsize);
    binary_protocol_copy (obj, destination, vt, objsize);
 
    /* FIXME: assumes object layout */
    memcpy ((char*)destination + sizeof (mword), (char*)obj + sizeof (mword), objsize - sizeof (mword));
 
    /* adjust array->bounds */
    SGEN_ASSERT (9, sgen_vtable_get_descriptor (vt), "vtable %p has no gc descriptor", vt);
 
    sgen_client_update_copied_object (destination, vt, obj, objsize);
}
 
/*
 * Copies an object and enqueues it if a queue is given.
 * This can return OBJ itself on OOM.
 */
static MONO_NEVER_INLINE GCObject *
copy_object_no_checks (GCObject *obj, SgenGrayQueue *queue)
{
    GCVTable vt = SGEN_LOAD_VTABLE_UNCHECKED (obj);
    gboolean has_references = SGEN_VTABLE_HAS_REFERENCES (vt);
    mword objsize = SGEN_ALIGN_UP (sgen_client_par_object_get_size (vt, obj));
    void *destination = COLLECTOR_SERIAL_ALLOC_FOR_PROMOTION (vt, obj, objsize, has_references);
 
    if (G_UNLIKELY (!destination)) {
        /* FIXME: Is this path ever tested? */
        collector_pin_object (obj, queue);
        sgen_set_pinned_from_failed_allocation (objsize);
        return obj;
    }
 
    par_copy_object_no_checks ((char *)destination, vt, obj, objsize);
 
    /* set the forwarding pointer */
    SGEN_FORWARD_OBJECT (obj, destination);
 
    if (has_references) {
        SGEN_LOG (9, "Enqueuing gray object %p (%s)", destination, sgen_client_vtable_get_name (vt));
        GRAY_OBJECT_ENQUEUE_SERIAL (queue, (GCObject *)destination, sgen_vtable_get_descriptor (vt));
    }
 
    return (GCObject *)destination;
}
 
#if defined(COPY_OR_MARK_PARALLEL)
static MONO_NEVER_INLINE GCObject *
copy_object_no_checks_par (GCObject *obj, SgenGrayQueue *queue)
{
    mword vtable_word = *(mword*)obj;
    GCObject *destination;
 
    destination = (GCObject*) SGEN_VTABLE_IS_FORWARDED (vtable_word);
 
    if (!destination) {
        GCVTable vt = (GCVTable) vtable_word;
        GCObject *final_destination;
        /*
         * At this point we know vt is not tagged and we shouldn't access the vtable through obj
         * since it could get copied at any time by another thread.
         */
        gboolean has_references = SGEN_VTABLE_HAS_REFERENCES (vt);
        mword objsize = SGEN_ALIGN_UP (sgen_client_par_object_get_size (vt, obj));
        destination = COLLECTOR_PARALLEL_ALLOC_FOR_PROMOTION (vt, obj, objsize, has_references);
 
        par_copy_object_no_checks ((char*)destination, vt, obj, objsize);
 
        /* FIXME we might need a membar here so other threads see the vtable before we forward */
 
        /* set the forwarding pointer */
        SGEN_FORWARD_OBJECT_PAR (obj, destination, final_destination);
 
        if (destination == final_destination) {
            /* In a racing case, only the worker that allocated the object enqueues it */
            if (has_references) {
                SGEN_LOG (9, "Enqueuing gray object %p (%s)", destination, sgen_client_vtable_get_name (vt));
                GRAY_OBJECT_ENQUEUE_PARALLEL (queue, (GCObject *)destination, sgen_vtable_get_descriptor (vt));
            }
        } else {
            /*
             * Unlikely case. Clear the allocated object so it doesn't confuse nursery
             * card table scanning, since it can contain old invalid refs.
             * FIXME make sure it is not a problem if another threads scans it while we clear
             */
            mono_gc_bzero_aligned (destination, objsize);
            destination = final_destination;
        }
    }
 
    return destination;
}
#endif
 
#undef COLLECTOR_SERIAL_ALLOC_FOR_PROMOTION
#undef COLLECTOR_PARALLEL_ALLOC_FOR_PROMOTION
#undef collector_pin_object
#undef COPY_OR_MARK_PARALLEL