Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

macOS compatibility #24

Draft
wants to merge 3 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ OBJECTS = build/immix.o \
build/global_allocator.o \
build/local_allocator.o \
build/collector.o \
build/hash.o
build/hash.o \
build/segments.o \
build/dynamic_loading.o

all: immix.a

Expand Down
1 change: 1 addition & 0 deletions include/array.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#define GC_ARRAY_H

#include <stdlib.h>
#include <stdio.h> // needed for perror

typedef struct {
long capacity;
Expand Down
6 changes: 6 additions & 0 deletions include/dynamic_loading.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#ifndef GC_DYNLOAD_H
#define GC_DYNLOAD_H

void GC_init_dyld();

#endif
21 changes: 21 additions & 0 deletions include/segments.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#ifndef __SEGMENTS_H__
#define __SEGMENTS_H__

#include "array.h"

typedef struct GC_segment {
void *start;
void *end;
char *name;
} Segment;

typedef void (Segments_iterator_t)(void *, Segment *);

static Array segments;

void Segments_init();

void Segments_add_segment(void* start, void* end, char *name);

void Segments_each(void *data, Segments_iterator_t callback);
#endif
22 changes: 20 additions & 2 deletions src/collector.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,25 @@
#include "line_header.h"
#include "memory.h"
#include "utils.h"
#include "segments.h"

#ifdef DARWIN
#include "dynamic_loading.h"
#endif

void GC_Collector_init(Collector *self, GlobalAllocator *allocator) {
self->global_allocator = allocator;
self->collect_callback = NULL;
Stack_init(&self->roots, GC_getMemoryLimit());
self->is_collecting = 0;

Segments_init();
#ifdef DARWIN
GC_init_dyld();
#else
Segments_add_segment(GC_DATA_START, GC_DATA_END, ".data");
Segments_add_segment(GC_BSS_START, GC_BSS_END, ".bss");
#endif
}

static inline void Collector_unmarkSmallObjects(Collector *self) {
Expand Down Expand Up @@ -205,6 +218,12 @@ static inline void Collector_sweep(Collector *self) {
//#endif
}

void GC_Collector_add_segment(void *self, Segment *segment) {
DEBUG("GC: add root %p %p %s\n", segment->start, segment->end, segment->name);

Collector_addRoots((Collector*)self, segment->start, segment->end, segment->name);
}

void GC_Collector_collect(Collector *self) {
DEBUG("GC: collect start\n");

Expand All @@ -213,8 +232,7 @@ void GC_Collector_collect(Collector *self) {
Collector_unmarkLargeObjects(self);

// 2. collect stack roots
Collector_addRoots(self, GC_DATA_START, GC_DATA_END, ".data");
Collector_addRoots(self, GC_BSS_START, GC_BSS_END, ".bss");
Segments_each(self, &GC_Collector_add_segment);
Collector_callCollectCallback(self);

// 3. search reachable objects to mark (recursively)
Expand Down
104 changes: 104 additions & 0 deletions src/dynamic_loading.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
#ifdef DARWIN

#include <mach-o/dyld.h>
#include <mach-o/getsect.h>
#include "dynamic_loading.h"
#include "segments.h"
#include "utils.h"

/* Currently, mach-o will allow up to the max of 2^15 alignment */
/* in an object file. */
#ifndef L2_MAX_OFILE_ALIGNMENT
# define L2_MAX_OFILE_ALIGNMENT 15
#endif

/* Writable sections generally available on Darwin. */
static const struct dyld_sections_s {
const char *seg;
const char *sect;
} GC_dyld_sections[] = {
{ SEG_DATA, SECT_DATA },
/* Used by FSF GCC, but not by OS X system tools, so far. */
{ SEG_DATA, "__static_data" },
{ SEG_DATA, SECT_BSS },
{ SEG_DATA, SECT_COMMON },
/* FSF GCC - zero-sized object sections for targets */
/*supporting section anchors. */
{ SEG_DATA, "__zobj_data" },
{ SEG_DATA, "__zobj_bss" }
};

/* Additional writable sections: */
/* GCC on Darwin constructs aligned sections "on demand", where */
/* the alignment size is embedded in the section name. */
/* Furthermore, there are distinctions between sections */
/* containing private vs. public symbols. It also constructs */
/* sections specifically for zero-sized objects, when the */
/* target supports section anchors. */
static const char * const GC_dyld_add_sect_fmts[] = {
"__bss%u",
"__pu_bss%u",
"__zo_bss%u",
"__zo_pu_bss%u"
};

void GC_dyld_add_image(const struct mach_header64* hdr, intptr_t vmaddr_slide) {
unsigned long start, end;
unsigned i, j;
const struct section_64 *sec;
const char *name;

for (i = 0; i < sizeof(GC_dyld_sections)/sizeof(GC_dyld_sections[0]); i++) {
sec = getsectbynamefromheader_64(hdr, GC_dyld_sections[i].seg,
GC_dyld_sections[i].sect);
if (sec == NULL || sec->size < sizeof(void*))
continue;
start = vmaddr_slide + sec->addr;
end = start + sec->size;
Segments_add_segment((void*)start, (void*)end, GC_dyld_sections[i].sect);
}

/* Sections constructed on demand. */
for (j = 0; j < sizeof(GC_dyld_add_sect_fmts) / sizeof(char *); j++) {
const char *fmt = GC_dyld_add_sect_fmts[j];

/* Add our manufactured aligned BSS sections. */
for (i = 0; i <= L2_MAX_OFILE_ALIGNMENT; i++) {
char secnam[16];

(void)snprintf(secnam, sizeof(secnam), fmt, (unsigned)i);
secnam[sizeof(secnam) - 1] = '\0';
sec = getsectbynamefromheader_64(hdr, SEG_DATA, secnam);
if (sec == NULL || sec->size == 0)
continue;
start = vmaddr_slide + sec->addr;
end = start + sec->size;
//TODO: probably need to change fmt by secnam (but secnam is local)
Segments_add_segment(start, end, fmt);
}
}
}

void GC_init_dyld(void)
{
DEBUG("GC: Registering segments\n");
/* Apple's Documentation:
When you call _dyld_register_func_for_add_image, the dynamic linker
runtime calls the specified callback (func) once for each of the images
that is currently loaded into the program. When a new image is added to
the program, your callback is called again with the mach_header for the
new image, and the virtual memory slide amount of the new image.

This WILL properly register already linked libraries and libraries
linked in the future.
*/
_dyld_register_func_for_add_image(
(void (*)(const struct mach_header*, intptr_t))GC_dyld_add_image);
// _dyld_register_func_for_remove_image(
// (void (*)(const struct mach_header*, intptr_t))GC_dyld_image_remove);
/* Structure mach_header64 has the same fields */
/* as mach_header except for the reserved one */
/* at the end, so these casts are OK. */
}

#endif // DARWIN
3 changes: 3 additions & 0 deletions src/immix.c
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,10 @@ void GC_init() {
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); // => ERRORCHECK
#if !defined(__APPLE__) // `setrobust` is part of SUSv7 and macOS only supports SUSv2
pthread_mutexattr_setrobust(&attr, PTHREAD_MUTEX_ROBUST);
#endif

pthread_mutex_init(GC_mutex, &attr);

global_allocator = malloc(sizeof(GlobalAllocator));
Expand Down
2 changes: 2 additions & 0 deletions src/immix.cr
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,8 @@ module GC
def self.current_thread_stack_bottom
{% if flag?(:linux) && flag?(:gnu) %}
return {Pointer(Void).null, LibC.__libc_stack_end}
{% elsif flag?(:darwin) %}
return {Pointer(Void).null, LibC.pthread_get_stackaddr_np LibC.pthread_self}
{% else %}
{% raise "GC: unsupported target (only <arch>-linux-gnu is supported)" %}
{% end %}
Expand Down
2 changes: 2 additions & 0 deletions src/lib_immix.cr
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ lib LibC

{% if flag?(:linux) && flag?(:gnu) %}
$__libc_stack_end : Void*
{% elsif flag?(:darwin) %}
fun pthread_get_stackaddr_np(x0 : PthreadT) : Void*
{% end %}

fun abort() : Void
Expand Down
22 changes: 22 additions & 0 deletions src/segments.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#include "segments.h"
#include "utils.h"

void Segments_init() {
Array_init(&segments, 4);
}

void Segments_add_segment(void* start, void* end, char *name) {
DEBUG("GC: Adding segment %p, %p, %s\n", start, end, name);
Segment *segment = malloc(sizeof(Segment));
segment->start = start;
segment->end = end;
segment->name = name;
Array_push(&segments, segment);
}

void Segments_each(void *data, Segments_iterator_t callback) {
for (int i = 0; i < Array_size(&segments); i++) {
Segment *segment = Array_get(&segments, i);
callback(data, segment);
}
}