Skip to content

Commit

Permalink
0.5.4: Hash variables accept designated initializers. @safemacro over…
Browse files Browse the repository at this point in the history
…rides the need for `@` in macro names. Fixes to macro context evaluation. Updated allocator api. Removed install_win_reqs.bat. Deterministic @init for MacOS.
  • Loading branch information
lerno committed Jan 24, 2024
1 parent 104766e commit 5b29d39
Show file tree
Hide file tree
Showing 14 changed files with 978 additions and 43 deletions.
4 changes: 2 additions & 2 deletions lib/std/core/mem.c3
Original file line number Diff line number Diff line change
Expand Up @@ -557,12 +557,12 @@ macro new_temp_clear($Type) @deprecated("use mem::temp_new")

macro new_array($Type, usz elements) @nodiscard
{
return allocator::new_array(heap(), $Type, elements);
return allocator::new_array(allocator::heap(), $Type, elements);
}

macro alloc_array($Type, usz elements) @nodiscard
{
return allocator::alloc_array(heap(), $Type, elements);
return allocator::alloc_array(allocator::heap(), $Type, elements);
}

macro talloc_array($Type, usz elements) @nodiscard @deprecated("use mem::temp_alloc_array")
Expand Down
254 changes: 254 additions & 0 deletions lib/std/core/private/macho_runtime.c3
Original file line number Diff line number Diff line change
@@ -0,0 +1,254 @@
module std::core::machoruntime @if(env::DARWIN) @private;

struct SegmentCommand64
{
uint cmd;
uint cmdsize;
char[16] segname;
ulong vmaddr;
ulong vmsize;
ulong fileoff;
ulong filesize;
uint maxprot;
uint initprot;
uint nsects;
uint flags;
}

struct LoadCommand
{
uint cmd;
uint cmdsize;
}

struct Section64
{
char[16] sectname;
char[16] segname;
ulong addr;
ulong size;
uint offset;
uint align;
uint reloff;
uint nreloc;
uint flags;
uint reserved1;
uint reserved2;
uint reserved3;
}

struct MachHeader
{
uint magic;
uint cputype;
uint cpusubtype;
uint filetype;
uint ncmds;
uint sizeofcmds;
uint flags;
}

struct MachHeader64
{
inline MachHeader header;
uint reserved;
}

const LC_SEGMENT_64 = 0x19;

fault MachoSearch
{
NOT_FOUND
}
fn bool name_cmp(char* a, char[16]* b)
{
for (usz i = 0; i < 16; i++)
{
if (a[i] != (*b)[i]) return false;
if (a[i] == '\0') return true;
}
return false;
}

fn SegmentCommand64*! find_segment(MachHeader* header, char* segname)
{
LoadCommand* command = (void*)header + MachHeader64.sizeof;
for (uint i = 0; i < header.ncmds; i++)
{
if (command.cmd == LC_SEGMENT_64)
{
SegmentCommand64* segment = (SegmentCommand64*)command;
if (name_cmp(segname, &segment.segname)) return segment;
}
command = (void*)command + command.cmdsize;
}
return MachoSearch.NOT_FOUND?;
}
fn Section64*! find_section(SegmentCommand64* command, char* sectname)
{
Section64* section = (void*)command + SegmentCommand64.sizeof;
for (uint i = 0; i < command.nsects; i++)
{
if (name_cmp(sectname, &section.sectname)) return section;
section++;
}
return MachoSearch.NOT_FOUND?;
}

macro find_segment_section_body(MachHeader* header, char* segname, char* sectname, $Type)
{

Section64*! section = find_section(find_segment(header, segname), sectname);
if (catch section)
{
return $Type[] {};
}
$Type* ptr = (void*)header + section.offset;
return ptr[:section.size / $Type.sizeof];
}

def DyldCallback = fn void (MachHeader* mh, isz vmaddr_slide);

extern fn void _dyld_register_func_for_add_image(DyldCallback);


struct DlInfo
{
char* dli_fname;
void* dli_fbase;
char* dli_sname;
void* dli_saddr;
}

extern fn void printf(char*, ...);
extern fn int dladdr(MachHeader* mh, DlInfo* dlinfo);
extern fn void* realloc(void* ptr, usz size);
extern fn void* malloc(usz size);
extern fn void free(void* ptr);

def CallbackFn = fn void();
struct Callback
{
uint priority;
CallbackFn xtor;
Callback* next;
}
struct DynamicMethod
{
void* fn_ptr;
char* sel;
union
{
DynamicMethod* next;
TypeId* type;
}
}

enum StartupState
{
NOT_STARTED,
INIT,
RUN_CTORS,
READ_DYLIB,
RUN_DYLIB_CTORS,
RUN_DTORS,
SHUTDOWN
}

StartupState runtime_state = NOT_STARTED;

Callback* ctor_first;
Callback* dtor_first;

fn void runtime_startup() @public @export("__c3_runtime_startup")
{
if (runtime_state != NOT_STARTED) return;
runtime_state = INIT;
_dyld_register_func_for_add_image(&dl_reg_callback);
assert(runtime_state == INIT);
runtime_state = RUN_CTORS;
Callback* ctor = ctor_first;
while (ctor)
{
ctor.xtor();
ctor = ctor.next;
}
assert(runtime_state == RUN_CTORS);
runtime_state = READ_DYLIB;
ctor = null;
}

fn void runtime_finalize() @public @export("__c3_runtime_finalize")
{
if (runtime_state != READ_DYLIB) return;
runtime_state = RUN_DTORS;
Callback* dtor = dtor_first;
while (dtor)
{
dtor.xtor();
dtor = dtor.next;
}
assert(runtime_state == RUN_DTORS);
runtime_state = SHUTDOWN;
}

fn void append_xxlizer(Callback** ref, Callback* cb)
{
while (Callback* current = *ref, current)
{
if (current.priority > cb.priority)
{
cb.next = current;
break;
}
ref = &current.next;
}
*ref = cb;
}

struct TypeId
{
char type;
TypeId* parentof;
DynamicMethod* dtable;
usz sizeof;
TypeId* inner;
usz len;
typeid[*] additional;
}

fn void dl_reg_callback(MachHeader* mh, isz vmaddr_slide)
{
usz size = 0;
assert(runtime_state == INIT || runtime_state == READ_DYLIB, "State was %s", runtime_state);
foreach (&dm : find_segment_section_body(mh, "__DATA", "__c3_dynamic", DynamicMethod))
{
TypeId* type = dm.type;
dm.next = type.dtable;
type.dtable = dm;
DynamicMethod* m = dm;
while (m)
{
m = m.next;
}
}
foreach (&cb : find_segment_section_body(mh, "__DATA", "__c3dtor", Callback))
{
append_xxlizer(&dtor_first, cb);
}
foreach (&cb : find_segment_section_body(mh, "__DATA", "__c3ctor", Callback))
{
append_xxlizer(&ctor_first, cb);
}
if (runtime_state != READ_DYLIB) return;
runtime_state = RUN_DYLIB_CTORS;
Callback* ctor = ctor_first;
ctor_first = null;
while (ctor)
{
ctor.xtor();
ctor = ctor.next;
}
assert(runtime_state == RUN_DYLIB_CTORS);
runtime_state = READ_DYLIB;
}
2 changes: 2 additions & 0 deletions releasenotes.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@
- More information available with debug log in non debug builds.
- Removed install_win_reqs.bat which didn't work well.
- Support `**` to mean `./**`
- MacOS init/finalizer now respects priority.

### Fixes
- Fixes to macro context evaluation with macro varargs.
- Dynamic methods registered before init functions on MacOS.

### Stdlib changes
- Deprecated `Allocator` helper functions.
Expand Down
1 change: 0 additions & 1 deletion src/compiler/enums.h
Original file line number Diff line number Diff line change
Expand Up @@ -850,7 +850,6 @@ typedef enum

typedef enum
{

BUILTIN_ABS,
BUILTIN_ANY_MAKE,
BUILTIN_ATOMIC_LOAD,
Expand Down
42 changes: 42 additions & 0 deletions src/compiler/llvm_codegen.c
Original file line number Diff line number Diff line change
Expand Up @@ -134,8 +134,50 @@ LLVMValueRef llvm_get_selector(GenContext *c, const char *name)
return selector;
}


void llvm_emit_macho_xtor(GenContext *c, LLVMValueRef *list, const char *name)
{
unsigned len = vec_size(list);
if (!len) return;
scratch_buffer_clear();
scratch_buffer_append(".list$");
scratch_buffer_append(name);
LLVMValueRef array = LLVMConstArray(c->xtor_entry_type, list, vec_size(list));
LLVMValueRef global = LLVMAddGlobal(c->module, LLVMTypeOf(array), scratch_buffer_to_string());
scratch_buffer_clear();
scratch_buffer_append("__DATA,__");
scratch_buffer_append(name);
LLVMSetLinkage(global, LLVMInternalLinkage);
LLVMSetInitializer(global, array);
LLVMSetSection(global, scratch_buffer_to_string());
LLVMSetAlignment(global, llvm_abi_alignment(c, c->xtor_entry_type));
}

void llvm_emit_constructors_and_destructors(GenContext *c)
{
if (platform_target.object_format == OBJ_FORMAT_MACHO)
{
llvm_emit_macho_xtor(c, c->constructors, "c3ctor");
llvm_emit_macho_xtor(c, c->destructors, "c3dtor");

LLVMValueRef runtime_start = LLVMGetNamedFunction(c->module, "__c3_runtime_startup");
if (!runtime_start || !LLVMGetFirstBasicBlock(runtime_start)) return;
LLVMValueRef vals[3] = { llvm_const_int(c, type_int, 65535), runtime_start, llvm_get_zero(c, type_voidptr) };
LLVMValueRef entry = LLVMConstNamedStruct(c->xtor_entry_type, vals, 3);
LLVMValueRef array = LLVMConstArray(c->xtor_entry_type, &entry, 1);
LLVMValueRef global_ctor = LLVMAddGlobal(c->module, LLVMTypeOf(array), "llvm.global_ctors");
LLVMSetLinkage(global_ctor, LLVMAppendingLinkage);
LLVMSetInitializer(global_ctor, array);
LLVMValueRef runtime_end = LLVMGetNamedFunction(c->module, "__c3_runtime_finalize");
if (!runtime_end || !LLVMGetFirstBasicBlock(runtime_end)) error_exit("Failed to find __c3_runtime_finalize in the same module as __c3_runtime_startup.");
vals[1] = runtime_end;
entry = LLVMConstNamedStruct(c->xtor_entry_type, vals, 3);
array = LLVMConstArray(c->xtor_entry_type, &entry, 1);
LLVMValueRef global_dtor = LLVMAddGlobal(c->module, LLVMTypeOf(array), "llvm.global_dtors");
LLVMSetLinkage(global_dtor, LLVMAppendingLinkage);
LLVMSetInitializer(global_dtor, array);
return;
}
llvm_emit_xtor(c, c->constructors, "llvm.global_ctors");
llvm_emit_xtor(c, c->destructors, "llvm.global_dtors");
}
Expand Down
Loading

0 comments on commit 5b29d39

Please sign in to comment.