GC_PTR GC_local_malloc_atomic(size_t bytes) { if (EXPECT(!SMALL_ENOUGH(bytes), 0)) { return(GC_malloc_atomic(bytes)); } else { int index = INDEX_FROM_BYTES(bytes); ptr_t * my_fl = ((GC_thread)GC_getspecific(GC_thread_key)) -> ptrfree_freelists + index; ptr_t my_entry = *my_fl; if (EXPECT((word)my_entry >= HBLKSIZE, 1)) { GC_PTR result = (GC_PTR)my_entry; *my_fl = obj_link(my_entry); return result; } else if ((word)my_entry - 1 < DIRECT_GRANULES) { *my_fl = my_entry + index + 1; return GC_malloc_atomic(bytes); } else { GC_generic_malloc_many(BYTES_FROM_INDEX(index), PTRFREE, my_fl); /* *my_fl is updated while the collector is excluded; */ /* the free list is always visible to the collector as */ /* such. */ if (*my_fl == 0) return GC_oom_fn(bytes); return GC_local_malloc_atomic(bytes); } } }
GC_PTR GC_local_malloc(size_t bytes) { if (EXPECT(!SMALL_ENOUGH(bytes),0)) { return(GC_malloc(bytes)); } else { int index = INDEX_FROM_BYTES(bytes); ptr_t * my_fl; ptr_t my_entry; # if defined(REDIRECT_MALLOC) && !defined(USE_PTHREAD_SPECIFIC) GC_key_t k = GC_thread_key; # endif void * tsd; # if defined(REDIRECT_MALLOC) && !defined(USE_PTHREAD_SPECIFIC) if (EXPECT(0 == k, 0)) { /* This can happen if we get called when the world is */ /* being initialized. Whether we can actually complete */ /* the initialization then is unclear. */ GC_init_parallel(); k = GC_thread_key; } # endif tsd = GC_getspecific(GC_thread_key); # ifdef GC_ASSERTIONS LOCK(); GC_ASSERT(tsd == (void *)GC_lookup_thread(pthread_self())); UNLOCK(); # endif my_fl = ((GC_thread)tsd) -> normal_freelists + index; my_entry = *my_fl; if (EXPECT((word)my_entry >= HBLKSIZE, 1)) { ptr_t next = obj_link(my_entry); GC_PTR result = (GC_PTR)my_entry; *my_fl = next; obj_link(my_entry) = 0; PREFETCH_FOR_WRITE(next); return result; } else if ((word)my_entry - 1 < DIRECT_GRANULES) { *my_fl = my_entry + index + 1; return GC_malloc(bytes); } else { GC_generic_malloc_many(BYTES_FROM_INDEX(index), NORMAL, my_fl); if (*my_fl == 0) return GC_oom_fn(bytes); return GC_local_malloc(bytes); } } }
GC_PTR GC_local_gcj_malloc(size_t bytes, void * ptr_to_struct_containing_descr) { GC_ASSERT(GC_gcj_malloc_initialized); if (EXPECT(!SMALL_ENOUGH(bytes), 0)) { return GC_gcj_malloc(bytes, ptr_to_struct_containing_descr); } else { int index = INDEX_FROM_BYTES(bytes); ptr_t * my_fl = ((GC_thread)GC_getspecific(GC_thread_key)) -> gcj_freelists + index; ptr_t my_entry = *my_fl; if (EXPECT((word)my_entry >= HBLKSIZE, 1)) { GC_PTR result = (GC_PTR)my_entry; GC_ASSERT(!GC_incremental); /* We assert that any concurrent marker will stop us. */ /* Thus it is impossible for a mark procedure to see the */ /* allocation of the next object, but to see this object */ /* still containing a free list pointer. Otherwise the */ /* marker might find a random "mark descriptor". */ *(volatile ptr_t *)my_fl = obj_link(my_entry); /* We must update the freelist before we store the pointer. */ /* Otherwise a GC at this point would see a corrupted */ /* free list. */ /* A memory barrier is probably never needed, since the */ /* action of stopping this thread will cause prior writes */ /* to complete. */ GC_ASSERT(((void * volatile *)result)[1] == 0); *(void * volatile *)result = ptr_to_struct_containing_descr; return result; } else if ((word)my_entry - 1 < DIRECT_GRANULES) { if (!GC_incremental) *my_fl = my_entry + index + 1; /* In the incremental case, we always have to take this */ /* path. Thus we leave the counter alone. */ return GC_gcj_malloc(bytes, ptr_to_struct_containing_descr); } else { GC_generic_malloc_many(BYTES_FROM_INDEX(index), GC_gcj_kind, my_fl); if (*my_fl == 0) return GC_oom_fn(bytes); return GC_local_gcj_malloc(bytes, ptr_to_struct_containing_descr); } } }
MonoMethod* mono_gc_get_managed_allocator (MonoClass *klass, gboolean for_box, gboolean known_instance_size) { int offset = -1; int atype; MONO_THREAD_VAR_OFFSET (GC_thread_tls, offset); /*g_print ("thread tls: %d\n", offset);*/ if (offset == -1) return NULL; if (!SMALL_ENOUGH (klass->instance_size)) return NULL; if (mono_class_has_finalizer (klass) || mono_class_is_marshalbyref (klass) || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS)) return NULL; if (klass->rank) return NULL; if (mono_class_is_open_constructed_type (&klass->byval_arg)) return NULL; if (klass->byval_arg.type == MONO_TYPE_STRING) { atype = ATYPE_STRING; } else if (!known_instance_size) { return NULL; } else if (!klass->has_references) { if (for_box) atype = ATYPE_FREEPTR_FOR_BOX; else atype = ATYPE_FREEPTR; } else { return NULL; /* * disabled because we currently do a runtime choice anyway, to * deal with multiple appdomains. if (vtable->gc_descr != GC_NO_DESCRIPTOR) atype = ATYPE_GCJ; else atype = ATYPE_NORMAL; */ } return mono_gc_get_managed_allocator_by_type (atype, FALSE); }