static LLVMValueRef make_trait_list(compile_t* c, gentype_t* g, uint32_t* final_count) { // The list is an array of integers. uint32_t* tid; size_t tid_size; uint32_t count = trait_count(c, g, &tid, &tid_size); // If we have no traits, return a null pointer to a list. if(count == 0) return LLVMConstNull(LLVMPointerType(LLVMArrayType(c->i32, 0), 0)); // Create a constant array of trait identifiers. size_t list_size = count * sizeof(LLVMValueRef); LLVMValueRef* list = (LLVMValueRef*)pool_alloc_size(list_size); for(uint32_t i = 0; i < count; i++) list[i] = LLVMConstInt(c->i32, tid[i], false); LLVMValueRef trait_array = LLVMConstArray(c->i32, list, count); // Create a global to hold the array. const char* name = genname_traitlist(g->type_name); LLVMTypeRef type = LLVMArrayType(c->i32, count); LLVMValueRef global = LLVMAddGlobal(c->module, type, name); LLVMSetGlobalConstant(global, true); LLVMSetLinkage(global, LLVMInternalLinkage); LLVMSetInitializer(global, trait_array); pool_free_size(tid_size, tid); pool_free_size(list_size, list); *final_count = count; return global; }
static bool make_struct(compile_t* c, gentype_t* g) { LLVMTypeRef type; int extra = 0; if(g->underlying != TK_TUPLETYPE) { type = g->structure; extra++; } else { type = g->primitive; } if(g->underlying == TK_ACTOR) extra++; size_t buf_size = (g->field_count + extra) * sizeof(LLVMTypeRef); LLVMTypeRef* elements = (LLVMTypeRef*)pool_alloc_size(buf_size); // Create the type descriptor as element 0. if(g->underlying != TK_TUPLETYPE) elements[0] = LLVMPointerType(g->desc_type, 0); // Create the actor pad as element 1. if(g->underlying == TK_ACTOR) elements[1] = c->actor_pad; // Get a preliminary type for each field and set the struct body. This is // needed in case a struct for the type being generated here is required when // generating a field. for(int i = 0; i < g->field_count; i++) { gentype_t field_g; if(!gentype_prelim(c, g->fields[i], &field_g)) { pool_free_size(buf_size, elements); return false; } elements[i + extra] = field_g.use_type; } LLVMStructSetBody(type, elements, g->field_count + extra, false); // Create a box type for tuples. if(g->underlying == TK_TUPLETYPE) make_box_type(c, g); pool_free_size(buf_size, elements); return true; }
static bool link_lib(compile_t* c, const char* file_o) { #if defined(PLATFORM_IS_POSIX_BASED) const char* file_lib = suffix_filename(c->opt->output, "lib", c->filename, ".a"); printf("Archiving %s\n", file_lib); size_t len = 32 + strlen(file_lib) + strlen(file_o); char* cmd = (char*)pool_alloc_size(len); snprintf(cmd, len, "ar -rcs %s %s", file_lib, file_o); if(system(cmd) != 0) { errorf(NULL, "unable to link"); pool_free_size(len, cmd); return false; } pool_free_size(len, cmd); #elif defined(PLATFORM_IS_WINDOWS) const char* file_lib = suffix_filename(c->opt->output, "", c->filename, ".lib"); printf("Archiving %s\n", file_lib); vcvars_t vcvars; if(!vcvars_get(&vcvars)) { errorf(NULL, "unable to link"); return false; } size_t len = 128 + strlen(file_lib) + strlen(file_o); char* cmd = (char*)pool_alloc_size(len); snprintf(cmd, len, "cmd /C \"\"%s\" /NOLOGO /OUT:%s %s\"", vcvars.ar, file_lib, file_o); if(system(cmd) == -1) { errorf(NULL, "unable to link"); pool_free_size(len, cmd); return false; } pool_free_size(len, cmd); #endif return true; }
static LLVMTypeRef get_signature(compile_t* c, gentype_t* g, ast_t* fun) { // Get a type for the result. ast_t* rtype = ast_childidx(fun, 4); gentype_t rtype_g; if(!gentype(c, rtype, &rtype_g)) { ast_error(rtype, "couldn't generate result type"); return NULL; } // Count the parameters, including the receiver. ast_t* params = ast_childidx(fun, 3); size_t count = ast_childcount(params) + 1; size_t buf_size = count *sizeof(LLVMTypeRef); LLVMTypeRef* tparams = (LLVMTypeRef*)pool_alloc_size(buf_size); count = 0; // Get a type for the receiver. tparams[count++] = g->use_type; // Get a type for each parameter. ast_t* param = ast_child(params); while(param != NULL) { ast_t* ptype = ast_childidx(param, 1); gentype_t ptype_g; if(!gentype(c, ptype, &ptype_g)) { ast_error(ptype, "couldn't generate parameter type"); pool_free_size(buf_size, tparams); return NULL; } tparams[count++] = ptype_g.use_type; param = ast_sibling(param); } LLVMTypeRef result = rtype_g.use_type; // Generate the function type. LLVMTypeRef r = LLVMFunctionType(result, tparams, (int)count, false); pool_free_size(buf_size, tparams); return r; }
static LLVMValueRef make_unbox_function(compile_t* c, gentype_t* g, const char* name) { LLVMValueRef fun = LLVMGetNamedFunction(c->module, name); if(fun == NULL) return LLVMConstNull(c->void_ptr); // Create a new unboxing function that forwards to the real function. LLVMTypeRef f_type = LLVMGetElementType(LLVMTypeOf(fun)); int count = LLVMCountParamTypes(f_type); // If it takes no arguments, it's a special number constructor. Don't put it // in the vtable. if(count == 0) return LLVMConstNull(c->void_ptr); size_t buf_size = count *sizeof(LLVMTypeRef); LLVMTypeRef* params = (LLVMTypeRef*)pool_alloc_size(buf_size); LLVMGetParamTypes(f_type, params); LLVMTypeRef ret_type = LLVMGetReturnType(f_type); // It's the same type, but it takes the boxed type instead of the primitive // type as the receiver. params[0] = g->structure_ptr; const char* unbox_name = genname_unbox(name); LLVMTypeRef unbox_type = LLVMFunctionType(ret_type, params, count, false); LLVMValueRef unbox_fun = codegen_addfun(c, unbox_name, unbox_type); codegen_startfun(c, unbox_fun, false); // Extract the primitive type from element 1 and call the real function. LLVMValueRef this_ptr = LLVMGetParam(unbox_fun, 0); LLVMValueRef primitive_ptr = LLVMBuildStructGEP(c->builder, this_ptr, 1, ""); LLVMValueRef primitive = LLVMBuildLoad(c->builder, primitive_ptr, ""); LLVMValueRef* args = (LLVMValueRef*)pool_alloc_size(buf_size); args[0] = primitive; for(int i = 1; i < count; i++) args[i] = LLVMGetParam(unbox_fun, i); LLVMValueRef result = codegen_call(c, fun, args, count); LLVMBuildRet(c->builder, result); codegen_finishfun(c); pool_free_size(buf_size, params); pool_free_size(buf_size, args); return LLVMConstBitCast(unbox_fun, c->void_ptr); }
static LLVMValueRef make_trait_list(compile_t* c, gentype_t* g) { // The list is an array of integers. uint32_t count = trait_count(c, g); // If we have no traits, return a null pointer to a list. if(count == 0) return LLVMConstNull(LLVMPointerType(LLVMArrayType(c->i32, 0), 0)); // Sort the trait identifiers. size_t tid_size = count * sizeof(uint32_t); uint32_t* tid = (uint32_t*)pool_alloc_size(tid_size); reachable_type_t* t = reach_type(c->reachable, g->type_name); assert(t != NULL); size_t i = HASHMAP_BEGIN; size_t index = 0; reachable_type_t* provide; while((provide = reachable_type_cache_next(&t->subtypes, &i)) != NULL) tid[index++] = provide->type_id; qsort(tid, index, sizeof(uint32_t), cmp_uint32); index = unique_uint32(tid, index); // Create a constant array of trait identifiers. size_t list_size = index * sizeof(LLVMValueRef); LLVMValueRef* list = (LLVMValueRef*)pool_alloc_size(list_size); for(i = 0; i < index; i++) list[i] = LLVMConstInt(c->i32, tid[i], false); count = (uint32_t)index; LLVMValueRef trait_array = LLVMConstArray(c->i32, list, count); // Create a global to hold the array. const char* name = genname_traitlist(g->type_name); LLVMTypeRef type = LLVMArrayType(c->i32, count); LLVMValueRef global = LLVMAddGlobal(c->module, type, name); LLVMSetGlobalConstant(global, true); LLVMSetLinkage(global, LLVMInternalLinkage); LLVMSetInitializer(global, trait_array); pool_free_size(tid_size, tid); pool_free_size(list_size, list); return global; }
// Delete all the files in the specified directory static void doc_rm_star(const char* path) { assert(path != NULL); PONY_ERRNO err; PONY_DIRINFO entry; PONY_DIRINFO* result; PONY_DIR* dir = pony_opendir(path, &err); if(dir == NULL) return; while(pony_dir_entry_next(dir, &entry, &result) && (result != NULL)) { char* name = pony_dir_info_name(result); if(strcmp(name, ".") != 0 && strcmp(name, "..") != 0) { // Delete this file size_t buf_len; char* buf = doc_cat(path, name, "", "", "", &buf_len); #ifdef PLATFORM_IS_WINDOWS DeleteFile(buf); #else remove(buf); #endif pool_free_size(buf_len, buf); } } pony_closedir(dir); }
static LLVMValueRef get_prototype(compile_t* c, gentype_t* g, const char *name, ast_t* typeargs, ast_t* fun) { // Behaviours and actor constructors also have sender functions. bool sender = false; switch(ast_id(fun)) { case TK_NEW: sender = g->underlying == TK_ACTOR; break; case TK_BE: sender = true; break; default: {} } // Get a fully qualified name: starts with the type name, followed by the // type arguments, followed by the function name, followed by the function // level type arguments. const char* funname = genname_fun(g->type_name, name, typeargs); // If the function already exists, just return it. LLVMValueRef func = LLVMGetNamedFunction(c->module, funname); if(func != NULL) return func; LLVMTypeRef ftype = get_signature(c, g, fun); if(ftype == NULL) return NULL; // If the function exists now, just return it. func = LLVMGetNamedFunction(c->module, funname); if(func != NULL) return func; if(sender) { // Generate the sender prototype. const char* be_name = genname_be(funname); func = codegen_addfun(c, be_name, ftype); // Change the return type to void for the handler. size_t count = LLVMCountParamTypes(ftype); size_t buf_size = count *sizeof(LLVMTypeRef); LLVMTypeRef* tparams = (LLVMTypeRef*)pool_alloc_size(buf_size); LLVMGetParamTypes(ftype, tparams); ftype = LLVMFunctionType(c->void_type, tparams, (int)count, false); pool_free_size(buf_size, tparams); } // Generate the function prototype. return codegen_addfun(c, funname, ftype); }
static void destroy_large(chunk_t* chunk) { // We could clear the pagemap here. if(chunk->m != NULL) pool_free_size(chunk->size, chunk->m); POOL_FREE(chunk_t, chunk); }
static LLVMValueRef make_vtable(compile_t* c, gentype_t* g) { uint32_t vtable_size = genfun_vtable_size(c, g); if(vtable_size == 0) return LLVMConstArray(c->void_ptr, NULL, 0); size_t buf_size = vtable_size * sizeof(LLVMValueRef); LLVMValueRef* vtable = (LLVMValueRef*)pool_alloc_size(buf_size); memset(vtable, 0, buf_size); reachable_type_t* t = reach_type(c->reachable, g->type_name); size_t i = HASHMAP_BEGIN; reachable_method_name_t* n; while((n = reachable_method_names_next(&t->methods, &i)) != NULL) { size_t j = HASHMAP_BEGIN; reachable_method_t* m; while((m = reachable_methods_next(&n->r_methods, &j)) != NULL) { const char* fullname = genname_fun(t->name, n->name, m->typeargs); token_id t = ast_id(m->r_fun); switch(t) { case TK_NEW: case TK_BE: if(g->underlying == TK_ACTOR) fullname = genname_be(fullname); break; default: {} } uint32_t index = m->vtable_index; assert(index != (uint32_t)-1); assert(vtable[index] == NULL); if(g->primitive != NULL) vtable[index] = make_unbox_function(c, g, fullname, t); else vtable[index] = make_function_ptr(c, fullname, c->void_ptr); } } for(uint32_t i = 0; i < vtable_size; i++) { if(vtable[i] == NULL) vtable[i] = LLVMConstNull(c->void_ptr); } LLVMValueRef r = LLVMConstArray(c->void_ptr, vtable, vtable_size); pool_free_size(buf_size, vtable); return r; }
static void destroy_large(chunk_t* chunk) { large_pagemap(chunk->m, chunk->size, NULL); if(chunk->m != NULL) pool_free_size(chunk->size, chunk->m); POOL_FREE(chunk_t, chunk); }
static void genfun_dwarf(compile_t* c, gentype_t* g, const char *name, ast_t* typeargs, ast_t* fun) { if(!codegen_hassource(c)) return; // Get the function. const char* funname = genname_fun(g->type_name, name, typeargs); LLVMValueRef func = LLVMGetNamedFunction(c->module, funname); assert(func != NULL); // Count the parameters, including the receiver. ast_t* params = ast_childidx(fun, 3); size_t count = ast_childcount(params) + 1; size_t buf_size = (count + 1) * sizeof(const char*); const char** pnames = (const char**)pool_alloc_size(buf_size); count = 0; // Return value type name and receiver type name. pnames[count++] = genname_type(ast_childidx(fun, 4)); pnames[count++] = g->type_name; // Get a type name for each parameter. ast_t* param = ast_child(params); while(param != NULL) { ast_t* ptype = ast_childidx(param, 1); pnames[count++] = genname_type(ptype); param = ast_sibling(param); } // Dwarf the method type dwarf_method(&c->dwarf, fun, name, funname, pnames, count, func); // Dwarf the receiver pointer. LLVMBasicBlockRef entry = LLVMGetEntryBasicBlock(codegen_fun(c)); LLVMValueRef argument = codegen_getlocal(c, stringtab("this")); dwarf_this(&c->dwarf, fun, g->type_name, entry, argument); // Dwarf locals for parameters param = ast_child(params); size_t index = 1; while(param != NULL) { argument = codegen_getlocal(c, ast_name(ast_child(param))); dwarf_parameter(&c->dwarf, param, pnames[index + 1], entry, argument, index); param = ast_sibling(param); index++; } pool_free_size(buf_size, pnames); }
void generate_docs(ast_t* program, pass_opt_t* options) { assert(program != NULL); if(ast_id(program) != TK_PROGRAM) return; docgen_t docgen; doc_setup_dirs(&docgen, program, options); // Open the index and home files docgen.index_file = doc_open_file(&docgen, false, "mkdocs", ".yml"); docgen.home_file = doc_open_file(&docgen, true, "index", ".md"); docgen.type_file = NULL; // Write documentation files if(docgen.index_file != NULL && docgen.home_file != NULL) { ast_t* package = ast_child(program); const char* name = package_filename(package); fprintf(docgen.home_file, "Packages\n\n"); fprintf(docgen.index_file, "site_name: %s\n", name); fprintf(docgen.index_file, "theme: readthedocs\n"); fprintf(docgen.index_file, "pages:\n"); fprintf(docgen.index_file, "- %s: index.md\n", name); doc_packages(&docgen, program); } // Tidy up if(docgen.index_file != NULL) fclose(docgen.index_file); if(docgen.home_file != NULL) fclose(docgen.home_file); if(docgen.base_dir != NULL) pool_free_size(docgen.base_dir_buf_len, (void*)docgen.base_dir); if(docgen.sub_dir != NULL) pool_free_size(docgen.sub_dir_buf_len, (void*)docgen.sub_dir); }
void source_close(source_t* source) { if(source == NULL) return; if(source->m != NULL) pool_free_size(source->len, source->m); POOL_FREE(source_t, source); }
void token_free(token_t* token) { if(token == NULL) return; if(token->printed != NULL) pool_free_size(64, token->printed); POOL_FREE(token_t, token); }
static LLVMValueRef make_field_list(compile_t* c, gentype_t* g) { // The list is an array of field descriptors. int count; if(g->underlying == TK_TUPLETYPE) count = g->field_count; else count = 0; LLVMTypeRef type = LLVMArrayType(c->field_descriptor, count); // If we aren't a tuple, return a null pointer to a list. if(count == 0) return LLVMConstNull(LLVMPointerType(type, 0)); // Create a constant array of field descriptors. size_t buf_size = count *sizeof(LLVMValueRef); LLVMValueRef* list = (LLVMValueRef*)pool_alloc_size(buf_size); for(int i = 0; i < count; i++) { gentype_t fg; if(!gentype(c, g->fields[i], &fg)) return NULL; LLVMValueRef fdesc[2]; fdesc[0] = LLVMConstInt(c->i32, LLVMOffsetOfElement(c->target_data, g->primitive, i), false); if(fg.desc != NULL) { // We are a concrete type. fdesc[1] = LLVMConstBitCast(fg.desc, c->descriptor_ptr); } else { // We aren't a concrete type. fdesc[1] = LLVMConstNull(c->descriptor_ptr); } list[i] = LLVMConstStructInContext(c->context, fdesc, 2, false); } LLVMValueRef field_array = LLVMConstArray(c->field_descriptor, list, count); // Create a global to hold the array. const char* name = genname_fieldlist(g->type_name); LLVMValueRef global = LLVMAddGlobal(c->module, type, name); LLVMSetGlobalConstant(global, true); LLVMSetLinkage(global, LLVMInternalLinkage); LLVMSetInitializer(global, field_array); pool_free_size(buf_size, list); return global; }
void buildflagset_free(buildflagset_t* set) { if(set != NULL) { flagtab_destroy(set->flags); POOL_FREE(flagtab_t, set->flags); if(set->buffer_size > 0) pool_free_size(set->buffer_size, set->text_buffer); POOL_FREE(buildflagset_t, set); } }
static void add_dispatch_case(compile_t* c, gentype_t* g, ast_t* fun, uint32_t index, LLVMValueRef handler, LLVMTypeRef type) { // Add a case to the dispatch function to handle this message. codegen_startfun(c, g->dispatch_fn, false); LLVMBasicBlockRef block = codegen_block(c, "handler"); LLVMValueRef id = LLVMConstInt(c->i32, index, false); LLVMAddCase(g->dispatch_switch, id, block); // Destructure the message. LLVMPositionBuilderAtEnd(c->builder, block); LLVMValueRef ctx = LLVMGetParam(g->dispatch_fn, 0); LLVMValueRef this_ptr = LLVMGetParam(g->dispatch_fn, 1); LLVMValueRef msg = LLVMBuildBitCast(c->builder, LLVMGetParam(g->dispatch_fn, 2), type, ""); int count = LLVMCountParams(handler); size_t buf_size = count * sizeof(LLVMValueRef); LLVMValueRef* args = (LLVMValueRef*)pool_alloc_size(buf_size); args[0] = LLVMBuildBitCast(c->builder, this_ptr, g->use_type, ""); // Trace the message. LLVMValueRef start_trace = gencall_runtime(c, "pony_gc_recv", &ctx, 1, ""); ast_t* params = ast_childidx(fun, 3); ast_t* param = ast_child(params); bool need_trace = false; for(int i = 1; i < count; i++) { LLVMValueRef field = LLVMBuildStructGEP(c->builder, msg, i + 2, ""); args[i] = LLVMBuildLoad(c->builder, field, ""); need_trace |= gentrace(c, ctx, args[i], ast_type(param)); param = ast_sibling(param); } if(need_trace) { gencall_runtime(c, "pony_recv_done", &ctx, 1, ""); } else { LLVMInstructionEraseFromParent(start_trace); } // Call the handler. codegen_call(c, handler, args, count); LLVMBuildRetVoid(c->builder); codegen_finishfun(c); pool_free_size(buf_size, args); }
static LLVMValueRef assign_to_tuple(compile_t* c, LLVMTypeRef l_type, LLVMValueRef r_value, ast_t* type) { // Cast each component. assert(ast_id(type) == TK_TUPLETYPE); int count = LLVMCountStructElementTypes(l_type); size_t buf_size = count * sizeof(LLVMTypeRef); LLVMTypeRef* elements = (LLVMTypeRef*)pool_alloc_size(buf_size); LLVMGetStructElementTypes(l_type, elements); LLVMValueRef result = LLVMGetUndef(l_type); ast_t* type_child = ast_child(type); int i = 0; while(type_child != NULL) { LLVMValueRef r_child = LLVMBuildExtractValue(c->builder, r_value, i, ""); LLVMValueRef cast_value = gen_assign_cast(c, elements[i], r_child, type_child); if(cast_value == NULL) { pool_free_size(buf_size, elements); return NULL; } result = LLVMBuildInsertValue(c->builder, result, cast_value, i, ""); type_child = ast_sibling(type_child); i++; } pool_free_size(buf_size, elements); return result; }
// Write the given package home page to its own file static void doc_package_home(docgen_t* docgen, ast_t* package, ast_t* doc_string) { assert(docgen != NULL); assert(docgen->index_file != NULL); assert(docgen->home_file != NULL); assert(docgen->type_file == NULL); assert(package != NULL); assert(ast_id(package) == TK_PACKAGE); // First open a file size_t tqfn_len; char* tqfn = write_tqfn(package, "-index", &tqfn_len); // Package group fprintf(docgen->index_file, "- package %s:\n", package_qualified_name(package)); docgen->type_file = doc_open_file(docgen, true, tqfn, ".md"); if(docgen->type_file == NULL) return; // Add reference to new file to index file fprintf(docgen->index_file, " - Package: \"%s.md\"\n", tqfn); // Add reference to package to home file fprintf(docgen->home_file, "* [%s](%s)\n", package_qualified_name(package), tqfn); // Now we can write the actual documentation for the package if(doc_string != NULL) { assert(ast_id(doc_string) == TK_STRING); fprintf(docgen->type_file, "%s", ast_name(doc_string)); } else { fprintf(docgen->type_file, "No package doc string provided for %s.", package_qualified_name(package)); } pool_free_size(tqfn_len, tqfn); fclose(docgen->type_file); docgen->type_file = NULL; }
static uint32_t trait_count(compile_t* c, gentype_t* g, uint32_t** list, size_t* list_size) { switch(g->underlying) { case TK_PRIMITIVE: case TK_CLASS: case TK_ACTOR: { reachable_type_t* t = reach_type(c->reachable, g->type_name); assert(t != NULL); uint32_t count = (uint32_t)reachable_type_cache_size(&t->subtypes); if(count == 0) return 0; // Sort the trait identifiers. size_t tid_size = count * sizeof(uint32_t); uint32_t* tid = (uint32_t*)pool_alloc_size(tid_size); size_t i = HASHMAP_BEGIN; size_t index = 0; reachable_type_t* provide; while((provide = reachable_type_cache_next(&t->subtypes, &i)) != NULL) tid[index++] = provide->type_id; qsort(tid, index, sizeof(uint32_t), cmp_uint32); count = (uint32_t)unique_uint32(tid, index); if(list != NULL) { *list = tid; *list_size = tid_size; } else { pool_free_size(tid_size, tid); } return count; } default: {} } return 0; }
// Free everything we've allocated static void painter_tidy(painter_t* painter) { assert(painter != NULL); size_t map_byte_count = painter->typemap_size * sizeof(uint64_t); name_records_destroy(&painter->names); colour_record_t* c = painter->colours; while(c != NULL) { colour_record_t* next = c->next; pool_free_size(map_byte_count, c->type_map); POOL_FREE(sizeof(colour_record_t), c); c = next; } }
// Append the given character to the current token text static void append_to_token(lexer_t* lexer, char c) { if(lexer->buflen >= lexer->alloc) { size_t new_len = (lexer->alloc > 0) ? lexer->alloc << 1 : 64; char* new_buf = (char*)pool_alloc_size(new_len); memcpy(new_buf, lexer->buffer, lexer->alloc); if(lexer->alloc > 0) pool_free_size(lexer->alloc, lexer->buffer); lexer->buffer = new_buf; lexer->alloc = new_len; } lexer->buffer[lexer->buflen] = c; lexer->buflen++; }
const char* buildflagset_print(buildflagset_t* set) { assert(set != NULL); assert(set->flags != NULL); char* p = set->text_buffer; // First the mutually exclusive flags. if(set->have_os_flags) print_flag(_os_flags[set->enum_os_flags], true, set, &p); if(set->have_size_flags) print_flag(_size_flags[set->enum_size_flags], true, set, &p); // Next the normal flags, in any order. size_t i = HASHMAP_BEGIN; flag_t* flag; while((flag = flagtab_next(set->flags, &i)) != NULL) print_flag(flag->name, flag->value, set, &p); if(p == set->text_buffer) // No flags, all configs match. print_str("all configs", set, &p); // Check buffer was big enough for it all. size_t size_needed = (p - set->text_buffer) + 1; // +1 for terminator. if(size_needed > set->buffer_size) { // Buffer we have isn't big enough, make it bigger then go round again. if(set->buffer_size > 0) pool_free_size(set->buffer_size, set->text_buffer); set->text_buffer = (char*)pool_alloc_size(size_needed); set->buffer_size = size_needed; set->text_buffer[0] = '\0'; buildflagset_print(set); } // Add terminator. assert(set->text_buffer != NULL); set->text_buffer[size_needed - 1] = '\0'; return set->text_buffer; }
const char* suffix_filename(const char* dir, const char* prefix, const char* file, const char* extension) { // Copy to a string with space for a suffix. size_t len = strlen(dir) + strlen(prefix) + strlen(file) + strlen(extension) + 4; char* filename = (char*)pool_alloc_size(len); // Start with no suffix. #ifdef PLATFORM_IS_WINDOWS snprintf(filename, len, "%s\\%s%s%s", dir, prefix, file, extension); #else snprintf(filename, len, "%s/%s%s%s", dir, prefix, file, extension); #endif int suffix = 0; while(suffix < 100) { // Overwrite files but not directories. struct stat s; int err = stat(filename, &s); if((err == -1) || !S_ISDIR(s.st_mode)) break; #ifdef PLATFORM_IS_WINDOWS snprintf(filename, len, "%s\\%s%s%d%s", dir, prefix, file, ++suffix, extension); #else snprintf(filename, len, "%s/%s%s%d%s", dir, prefix, file, ++suffix, extension); #endif } if(suffix >= 100) { errorf(NULL, "couldn't pick an unused file name"); pool_free_size(len, filename); return NULL; } return stringtab_consume(filename, len); }
source_t* source_open(const char* file) { FILE* fp = fopen(file, "rb"); if(fp == NULL) { errorf(file, "can't open file"); return NULL; } fseek(fp, 0, SEEK_END); ssize_t size = ftell(fp); if(size < 0) { errorf(file, "can't determine length of file"); fclose(fp); return NULL; } fseek(fp, 0, SEEK_SET); source_t* source = POOL_ALLOC(source_t); source->file = stringtab(file); source->m = (char*)pool_alloc_size(size); source->len = size; ssize_t read = fread(source->m, sizeof(char), size, fp); if(read < size) { errorf(file, "failed to read entire file"); pool_free_size(source->len, source->m); POOL_FREE(source_t, source); fclose(fp); return NULL; } fclose(fp); return source; }
// Open a file with the specified info. // The given filename extension should include a dot if one is needed. // The returned file handle must be fclosed() with no longer needed. // If the specified file cannot be opened an error will be generated and NULL // returned. static FILE* doc_open_file(docgen_t* docgen, bool in_sub_dir, const char* filename, const char* extn) { assert(docgen != NULL); assert(filename != NULL); assert(extn != NULL); // Build the type file name in a buffer. // Full file name is: // directory/filenameextn const char* dir = in_sub_dir ? docgen->sub_dir : docgen->base_dir; size_t buf_len; char* buffer = doc_cat(dir, filename, extn, "", "", &buf_len); // Now we have the file name open the file FILE* file = fopen(buffer, "w"); if(file == NULL) errorf(NULL, "Could not write documentation to file %s", buffer); pool_free_size(buf_len, buffer); return file; }
static LLVMValueRef make_trait_list(compile_t* c, gentype_t* g) { // The list is an array of integers. uint32_t count = trait_count(c, g); LLVMTypeRef type = LLVMArrayType(c->i32, count); // If we have no traits, return a null pointer to a list. if(count == 0) return LLVMConstNull(LLVMPointerType(type, 0)); // Create a constant array of trait identifiers. size_t buf_size = count *sizeof(LLVMValueRef); LLVMValueRef* list = (LLVMValueRef*)pool_alloc_size(buf_size); reachable_type_t* t = reach_type(c->reachable, g->type_name); assert(t != NULL); size_t i = HASHMAP_BEGIN; size_t index = 0; reachable_type_t* provide; while((provide = reachable_type_cache_next(&t->subtypes, &i)) != NULL) list[index++] = make_type_id(c, provide->name); LLVMValueRef trait_array = LLVMConstArray(c->i32, list, count); // Create a global to hold the array. const char* name = genname_traitlist(g->type_name); LLVMValueRef global = LLVMAddGlobal(c->module, type, name); LLVMSetGlobalConstant(global, true); LLVMSetLinkage(global, LLVMInternalLinkage); LLVMSetInitializer(global, trait_array); pool_free_size(buf_size, list); return global; }
void heap_free(chunk_t* chunk, void* p) { if(chunk->size >= HEAP_SIZECLASSES) { if(p == chunk->m) { pool_free_size(chunk->size, chunk->m); chunk->m = NULL; chunk->slots = 1; } return; } // Calculate the external pointer. void* ext = EXTERNAL_PTR(p, chunk->size); if(p == ext) { // Shift to account for smallest allocation size. uint32_t slot = FIND_SLOT(ext, chunk->m); chunk->slots |= slot; } }
static bool make_struct(compile_t* c, gentype_t* g) { LLVMTypeRef type; int extra = 0; if(g->underlying != TK_TUPLETYPE) { type = g->structure; if(g->underlying != TK_STRUCT) extra++; } else { type = g->primitive; } if(g->underlying == TK_ACTOR) extra++; size_t buf_size = (g->field_count + extra) * sizeof(LLVMTypeRef); LLVMTypeRef* elements = (LLVMTypeRef*)pool_alloc_size(buf_size); // Create the type descriptor as element 0. if(extra > 0) elements[0] = LLVMPointerType(g->desc_type, 0); // Create the actor pad as element 1. if(g->underlying == TK_ACTOR) elements[1] = c->actor_pad; // Get a preliminary type for each field and set the struct body. This is // needed in case a struct for the type being generated here is required when // generating a field. for(int i = 0; i < g->field_count; i++) { gentype_t field_g; bool ok; if((g->field_keys != NULL) && (g->field_keys[i] == TK_EMBED)) { ok = gentype(c, g->fields[i], &field_g); elements[i + extra] = field_g.structure; } else { ok = gentype_prelim(c, g->fields[i], &field_g); elements[i + extra] = field_g.use_type; } if(!ok) { pool_free_size(buf_size, elements); return false; } } // An embedded field may have caused the current type to be fully generated // at this point. If so, finish gracefully. if(!LLVMIsOpaqueStruct(type)) { g->done = true; return true; } LLVMStructSetBody(type, elements, g->field_count + extra, false); // Create a box type for tuples. if(g->underlying == TK_TUPLETYPE) make_box_type(c, g); pool_free_size(buf_size, elements); return true; }