/home/travis/build/MoarVM/MoarVM/src/gc/allocation.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Allocation of managed memory - that is, from the memory space that is |
2 | | * managed by the garbage collector. Memory that is in turn owned by a |
3 | | * GC-able object will be allocated separately and freed explicitly by |
4 | | * its REPR gc_free routine. */ |
5 | | |
6 | | #include "moar.h" |
7 | | |
8 | | /* Allocate the specified amount of memory from the nursery. Will |
9 | | * trigger a GC run if there is not enough. */ |
10 | 32.6M | void * MVM_gc_allocate_nursery(MVMThreadContext *tc, size_t size) { |
11 | 32.6M | void *allocated; |
12 | 32.6M | |
13 | 32.6M | /* Before an allocation is a GC safe-point and thus a good GC sync point |
14 | 32.6M | * also; check if we've been signalled to collect. */ |
15 | 32.6M | /* Don't use a MVM_load(&tc->gc_status) here for performance, it's okay |
16 | 32.6M | * if the interrupt is delayed a bit. */ |
17 | 32.6M | if (tc->gc_status) |
18 | 2 | MVM_gc_enter_from_interrupt(tc); |
19 | 32.6M | |
20 | 32.6M | /* Guard against 0-byte allocation. */ |
21 | 32.6M | if (size > 0) { |
22 | 32.6M | /* Do a GC run if this allocation won't fit in what we have |
23 | 32.6M | * left in the nursery. Note this is a loop to handle a |
24 | 32.6M | * pathological case: all the objects in the nursery are very |
25 | 32.6M | * young and thus survive in the nursery, meaning that no space |
26 | 32.6M | * actually gets freed up. The next run will promote them to the |
27 | 32.6M | * second generation. Note that this circumstance is exceptionally |
28 | 32.6M | * unlikely in any non-contrived situation. */ |
29 | 32.6M | while ((char *)tc->nursery_alloc + size >= (char *)tc->nursery_alloc_limit) { |
30 | 313 | if (size > MVM_NURSERY_SIZE) |
31 | 0 | MVM_panic(MVM_exitcode_gcalloc, "Attempt to allocate more than the maximum nursery size"); |
32 | 313 | MVM_gc_enter_from_allocator(tc); |
33 | 313 | } |
34 | 32.6M | |
35 | 32.6M | /* Allocate (just bump the pointer). */ |
36 | 32.6M | allocated = tc->nursery_alloc; |
37 | 32.6M | tc->nursery_alloc = (char *)tc->nursery_alloc + size; |
38 | 32.6M | } |
39 | 0 | else { |
40 | 0 | MVM_panic(MVM_exitcode_gcalloc, "Cannot allocate 0 bytes of memory in the nursery"); |
41 | 0 | } |
42 | 32.6M | |
43 | 32.6M | return allocated; |
44 | 32.6M | } |
45 | | |
46 | | /* Same as MVM_gc_allocate, but promises that the memory will be zeroed. */ |
47 | 36.8M | void * MVM_gc_allocate_zeroed(MVMThreadContext *tc, size_t size) { |
48 | 36.8M | /* At present, MVM_gc_allocate always returns zeroed memory. */ |
49 | 36.8M | return MVM_gc_allocate(tc, size); |
50 | 36.8M | } |
51 | | |
52 | | /* Allocates a new STable, based on the specified thread context, REPR |
53 | | * and meta-object. */ |
54 | 32.3k | MVMSTable * MVM_gc_allocate_stable(MVMThreadContext *tc, const MVMREPROps *repr, MVMObject *how) { |
55 | 32.3k | MVMSTable *st; |
56 | 32.3k | MVMROOT(tc, how, { |
57 | 32.3k | st = MVM_gc_allocate_zeroed(tc, sizeof(MVMSTable)); |
58 | 32.3k | st->header.flags |= MVM_CF_STABLE; |
59 | 32.3k | st->header.size = sizeof(MVMSTable); |
60 | 32.3k | st->header.owner = tc->thread_id; |
61 | 32.3k | st->REPR = repr; |
62 | 32.3k | st->invoke = MVM_6model_invoke_default; |
63 | 32.3k | st->type_cache_id = MVM_6model_next_type_cache_id(tc); |
64 | 32.3k | st->debug_name = NULL; |
65 | 32.3k | MVM_ASSIGN_REF(tc, &(st->header), st->HOW, how); |
66 | 32.3k | }); |
67 | 32.3k | return st; |
68 | 32.3k | } |
69 | | |
70 | | /* Allocates a new type object. */ |
71 | 32.2k | MVMObject * MVM_gc_allocate_type_object(MVMThreadContext *tc, MVMSTable *st) { |
72 | 32.2k | MVMObject *obj; |
73 | 32.2k | MVMROOT(tc, st, { |
74 | 32.2k | obj = MVM_gc_allocate_zeroed(tc, sizeof(MVMObject)); |
75 | 32.2k | obj->header.flags |= MVM_CF_TYPE_OBJECT; |
76 | 32.2k | obj->header.size = sizeof(MVMObject); |
77 | 32.2k | obj->header.owner = tc->thread_id; |
78 | 32.2k | MVM_ASSIGN_REF(tc, &(obj->header), obj->st, st); |
79 | 32.2k | }); |
80 | 32.2k | return obj; |
81 | 32.2k | } |
82 | | |
83 | | /* Allocates a new object, and points it at the specified STable. */ |
84 | 29.5M | MVMObject * MVM_gc_allocate_object(MVMThreadContext *tc, MVMSTable *st) { |
85 | 29.5M | MVMObject *obj; |
86 | 29.5M | MVMROOT(tc, st, { |
87 | 29.5M | obj = MVM_gc_allocate_zeroed(tc, st->size); |
88 | 29.5M | obj->header.size = (MVMuint16)st->size; |
89 | 29.5M | obj->header.owner = tc->thread_id; |
90 | 29.5M | MVM_ASSIGN_REF(tc, &(obj->header), obj->st, st); |
91 | 29.5M | if (st->mode_flags & MVM_FINALIZE_TYPE) |
92 | 29.5M | MVM_gc_finalize_add_to_queue(tc, obj); |
93 | 29.5M | }); |
94 | 29.5M | return obj; |
95 | 29.5M | } |
96 | | |
97 | | /* Allocates a new heap frame. */ |
98 | 960k | MVMFrame * MVM_gc_allocate_frame(MVMThreadContext *tc) { |
99 | 960k | MVMFrame *f = MVM_gc_allocate_zeroed(tc, sizeof(MVMFrame)); |
100 | 960k | f->header.flags |= MVM_CF_FRAME; |
101 | 960k | f->header.size = sizeof(MVMFrame); |
102 | 960k | f->header.owner = tc->thread_id; |
103 | 960k | return f; |
104 | 960k | } |
105 | | |
106 | | /* Sets allocate for this thread to be from the second generation by |
107 | | * default. */ |
108 | 2.28M | void MVM_gc_allocate_gen2_default_set(MVMThreadContext *tc) { |
109 | 2.28M | tc->allocate_in_gen2++; |
110 | 2.28M | } |
111 | | |
112 | | /* Sets allocation for this thread to be from the nursery by default. */ |
113 | 2.28M | void MVM_gc_allocate_gen2_default_clear(MVMThreadContext *tc) { |
114 | 2.28M | if (tc->allocate_in_gen2 <= 0) |
115 | 0 | MVM_oops(tc, "Cannot leave gen2 allocation without entering it"); |
116 | 2.28M | tc->allocate_in_gen2--; |
117 | 2.28M | } |