void gendesc_table(compile_t* c) { uint32_t len = c->reach->next_type_id; size_t size = len * sizeof(LLVMValueRef); LLVMValueRef* args = (LLVMValueRef*)ponyint_pool_alloc_size(size); reach_type_t* t; size_t i = HASHMAP_BEGIN; while((t = reach_types_next(&c->reach->types, &i)) != NULL) { LLVMValueRef desc; if(t->desc != NULL) desc = LLVMBuildBitCast(c->builder, t->desc, c->descriptor_ptr, ""); else desc = LLVMConstNull(c->descriptor_ptr); args[t->type_id] = desc; } LLVMTypeRef type = LLVMArrayType(c->descriptor_ptr, len); LLVMValueRef table = LLVMAddGlobal(c->module, type, "__DescTable"); LLVMValueRef value = LLVMConstArray(c->descriptor_ptr, args, len); LLVMSetInitializer(table, value); LLVMSetGlobalConstant(table, true); LLVMValueRef table_size = LLVMAddGlobal(c->module, c->intptr, "__DescTableSize"); LLVMSetInitializer(table_size, LLVMConstInt(c->intptr, len, false)); LLVMSetGlobalConstant(table_size, true); ponyint_pool_free_size(size, args); }
static LLVMValueRef make_trait_list(compile_t* c, reach_type_t* t, uint32_t* final_count) { // The list is an array of integers. uint32_t* tid; size_t tid_size; uint32_t count = trait_count(t, &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*)ponyint_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(t->name); LLVMTypeRef list_type = LLVMArrayType(c->i32, count); LLVMValueRef global = LLVMAddGlobal(c->module, list_type, name); LLVMSetGlobalConstant(global, true); LLVMSetLinkage(global, LLVMPrivateLinkage); LLVMSetInitializer(global, trait_array); ponyint_pool_free_size(tid_size, tid); ponyint_pool_free_size(list_size, list); *final_count = count; return global; }
LLVMValueRef gen_tuple(compile_t* c, ast_t* ast) { ast_t* child = ast_child(ast); if(ast_sibling(child) == NULL) return gen_expr(c, child); deferred_reification_t* reify = c->frame->reify; ast_t* type = deferred_reify(reify, ast_type(ast), c->opt); // If we contain '_', we have no usable value. if(contains_dontcare(type)) { ast_free_unattached(type); return GEN_NOTNEEDED; } reach_type_t* t = reach_type(c->reach, type); compile_type_t* c_t = (compile_type_t*)t->c_type; int count = LLVMCountStructElementTypes(c_t->primitive); size_t buf_size = count * sizeof(LLVMTypeRef); LLVMTypeRef* elements = (LLVMTypeRef*)ponyint_pool_alloc_size(buf_size); LLVMGetStructElementTypes(c_t->primitive, elements); LLVMValueRef tuple = LLVMGetUndef(c_t->primitive); int i = 0; while(child != NULL) { LLVMValueRef value = gen_expr(c, child); if(value == NULL) { ponyint_pool_free_size(buf_size, elements); return NULL; } // We'll have an undefined element if one of our source elements is a // variable declaration. This is ok, since the tuple value will never be // used. if(value == GEN_NOVALUE || value == GEN_NOTNEEDED) { ponyint_pool_free_size(buf_size, elements); return value; } ast_t* child_type = deferred_reify(reify, ast_type(child), c->opt); value = gen_assign_cast(c, elements[i], value, child_type); ast_free_unattached(child_type); tuple = LLVMBuildInsertValue(c->builder, tuple, value, i++, ""); child = ast_sibling(child); } ponyint_pool_free_size(buf_size, elements); return tuple; }
static void ponyint_sched_shutdown() { uint32_t start; start = 0; for(uint32_t i = start; i < scheduler_count; i++) ponyint_thread_join(scheduler[i].tid); DTRACE0(RT_END); ponyint_cycle_terminate(&scheduler[0].ctx); for(uint32_t i = 0; i < scheduler_count; i++) { while(ponyint_messageq_pop(&scheduler[i].mq) != NULL); ponyint_messageq_destroy(&scheduler[i].mq); ponyint_mpmcq_destroy(&scheduler[i].q); } ponyint_pool_free_size(scheduler_count * sizeof(scheduler_t), scheduler); scheduler = NULL; scheduler_count = 0; ponyint_mpmcq_destroy(&inject); }
static void print_params(compile_t* c, printbuf_t* buf, ast_t* params) { ast_t* param = ast_child(params); while(param != NULL) { AST_GET_CHILDREN(param, id, ptype); // Print the parameter. printbuf(buf, ", "); print_type_name(c, buf, ptype); // Smash trailing primes to underscores. const char* name = ast_name(id); size_t len = strlen(name) + 1; size_t buf_size = len; char* buffer = (char*)ponyint_pool_alloc_size(buf_size); memcpy(buffer, name, len); len--; while(buffer[--len] == '\'') buffer[len] = '_'; printbuf(buf, " %s", buffer); param = ast_sibling(param); ponyint_pool_free_size(buf_size, buffer); } }
static void tuple_indices_destroy(call_tuple_indices_t* ti) { ponyint_pool_free_size(ti->alloc * sizeof(size_t), ti->data); ti->data = NULL; ti->count = 0; ti->alloc = 0; }
// Delete all the files in the specified directory static void doc_rm_star(const char* path) { assert(path != NULL); PONY_ERRNO err; PONY_DIR* dir = pony_opendir(path, &err); if(dir == NULL) return; PONY_DIRINFO* result; while((result = pony_dir_entry_next(dir)) != 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 ponyint_pool_free_size(buf_len, buf); } } pony_closedir(dir); }
void package_group_free(package_group_t* group) { if(group->signature != NULL) ponyint_pool_free_size(SIGNATURE_LENGTH, group->signature); package_set_destroy(&group->members); POOL_FREE(package_group_t, group); }
void generate_docs(ast_t* program, pass_opt_t* options) { assert(program != NULL); if(ast_id(program) != TK_PROGRAM) return; docgen_t docgen; docgen.errors = options->check.errors; 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) ponyint_pool_free_size(docgen.base_dir_buf_len, (void*)docgen.base_dir); if(docgen.sub_dir != NULL) ponyint_pool_free_size(docgen.sub_dir_buf_len, (void*)docgen.sub_dir); }
void program_free(program_t* program) { pony_assert(program != NULL); package_group_list_free(program->package_groups); if(program->signature != NULL) ponyint_pool_free_size(SIGNATURE_LENGTH, program->signature); strlist_free(program->libpaths); strlist_free(program->libs); if(program->lib_args != NULL) ponyint_pool_free_size(program->lib_args_alloced, program->lib_args); POOL_FREE(program_t, program); }
// 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->package_file == NULL); assert(docgen->test_types == NULL); assert(docgen->public_types == NULL); assert(docgen->private_types == 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)); } ponyint_pool_free_size(tqfn_len, tqfn); docgen->test_types = printbuf_new(); docgen->public_types = printbuf_new(); docgen->private_types = printbuf_new(); docgen->package_file = docgen->type_file; docgen->type_file = NULL; }
static void reach_mangled_free(reach_method_t* m) { ast_free(m->typeargs); ast_free(m->r_fun); if(m->param_count > 0) ponyint_pool_free_size(m->param_count * sizeof(reach_param_t), m->params); POOL_FREE(reach_method_t, m); }
void source_close(source_t* source) { if(source == NULL) return; if(source->m != NULL) ponyint_pool_free_size(source->len, source->m); POOL_FREE(source_t, source); }
static void destroy_large(chunk_t* chunk, uint32_t mark) { (void)mark; large_pagemap(chunk->m, chunk->size, NULL); if(chunk->m != NULL) ponyint_pool_free_size(chunk->size, chunk->m); POOL_FREE(chunk_t, chunk); }
static void tuple_indices_push(call_tuple_indices_t* ti, size_t idx) { if(ti->count == ti->alloc) { size_t* tmp_data = (size_t*)ponyint_pool_alloc_size(2 * ti->alloc * sizeof(size_t)); memcpy(tmp_data, ti->data, ti->count * sizeof(size_t)); ponyint_pool_free_size(ti->alloc * sizeof(size_t), ti->data); ti->alloc *= 2; ti->data = tmp_data; } ti->data[ti->count++] = idx; }
static void reachable_method_free(reachable_method_t* m) { ast_free(m->typeargs); ast_free(m->r_fun); if(m->param_count > 0) { ponyint_pool_free_size(m->param_count * sizeof(reachable_type_t*), m->params); } POOL_FREE(reachable_method_t, m); }
void buildflagset_free(buildflagset_t* set) { if(set != NULL) { flagtab_destroy(set->flags); POOL_FREE(flagtab_t, set->flags); if(set->buffer_size > 0) ponyint_pool_free_size(set->buffer_size, set->text_buffer); POOL_FREE(buildflagset_t, set); } }
static LLVMValueRef make_field_list(compile_t* c, reach_type_t* t) { // The list is an array of field descriptors. uint32_t count; if(t->underlying == TK_TUPLETYPE) count = t->field_count; else count = 0; LLVMTypeRef field_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(field_type, 0)); // Create a constant array of field descriptors. size_t buf_size = count * sizeof(LLVMValueRef); LLVMValueRef* list = (LLVMValueRef*)ponyint_pool_alloc_size(buf_size); for(uint32_t i = 0; i < count; i++) { LLVMValueRef fdesc[2]; fdesc[0] = LLVMConstInt(c->i32, LLVMOffsetOfElement(c->target_data, t->primitive, i), false); if(t->fields[i].type->desc != NULL) { // We are a concrete type. fdesc[1] = LLVMConstBitCast(t->fields[i].type->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(t->name); LLVMValueRef global = LLVMAddGlobal(c->module, field_type, name); LLVMSetGlobalConstant(global, true); LLVMSetLinkage(global, LLVMPrivateLinkage); LLVMSetInitializer(global, field_array); ponyint_pool_free_size(buf_size, list); return global; }
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*)ponyint_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) { ponyint_pool_free_size(buf_size, elements); return NULL; } result = LLVMBuildInsertValue(c->builder, result, cast_value, i, ""); type_child = ast_sibling(type_child); i++; } ponyint_pool_free_size(buf_size, elements); return result; }
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_arch_flags) print_flag(_arch_flags[set->enum_arch_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) ponyint_pool_free_size(set->buffer_size, set->text_buffer); set->text_buffer = (char*)ponyint_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; }
static void make_debug_fields(compile_t* c, reach_type_t* t) { LLVMMetadataRef fields = NULL; if(t->field_count > 0) { size_t buf_size = t->field_count * sizeof(LLVMMetadataRef); LLVMMetadataRef* data = (LLVMMetadataRef*)ponyint_pool_alloc_size( buf_size); for(uint32_t i = 0; i < t->field_count; i++) data[i] = make_debug_field(c, t, i); fields = LLVMDIBuilderGetOrCreateArray(c->di, data, t->field_count); ponyint_pool_free_size(buf_size, data); } LLVMTypeRef type; if(t->underlying != TK_TUPLETYPE) type = t->structure; else type = t->primitive; uint64_t size = 0; uint64_t align = 0; if(type != NULL) { size = LLVMABISizeOfType(c->target_data, type); align = LLVMABIAlignmentOfType(c->target_data, type); } LLVMMetadataRef di_type = LLVMDIBuilderCreateStructType(c->di, c->di_unit, t->name, t->di_file, (unsigned) ast_line(t->ast), 8 * size, 8 * align, fields); if(t->underlying != TK_TUPLETYPE) { LLVMMetadataReplaceAllUsesWith(t->di_type_embed, di_type); t->di_type_embed = di_type; } else { LLVMMetadataReplaceAllUsesWith(t->di_type, di_type); t->di_type = di_type; } }
// 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*)ponyint_pool_alloc_size(new_len); memcpy(new_buf, lexer->buffer, lexer->alloc); if(lexer->alloc > 0) ponyint_pool_free_size(lexer->alloc, lexer->buffer); lexer->buffer = new_buf; lexer->alloc = new_len; } lexer->buffer[lexer->buflen] = c; lexer->buflen++; }
static uint32_t trait_count(reach_type_t* t, uint32_t** list, size_t* list_size) { switch(t->underlying) { case TK_PRIMITIVE: case TK_CLASS: case TK_ACTOR: { uint32_t count = (uint32_t)reach_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*)ponyint_pool_alloc_size(tid_size); size_t i = HASHMAP_BEGIN; size_t index = 0; reach_type_t* provide; while((provide = reach_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 { ponyint_pool_free_size(tid_size, tid); } return count; } default: {} } return 0; }
const char* suffix_filename(compile_t* c, 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*)ponyint_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(c->opt->check.errors, NULL, "couldn't pick an unused file name"); ponyint_pool_free_size(len, filename); return NULL; } return stringtab_consume(filename, len); }
static bool query_registry(HKEY key, bool query_subkeys, query_callback_fn fn, search_t* p) { DWORD sub_keys; DWORD largest_subkey; // Processing a leaf node in the registry, give it to the callback. if(!query_subkeys) { fn(key, NULL, p); return true; } get_child_count(key, &sub_keys, &largest_subkey); if(sub_keys == 0) return false; largest_subkey += 1; HKEY node; DWORD size = largest_subkey; char* name = (char*)ponyint_pool_alloc_size(largest_subkey); bool r = true; for(DWORD i = 0; i < sub_keys; ++i) { if(RegEnumKeyEx(key, i, name, &size, NULL, NULL, NULL, NULL) != ERROR_SUCCESS || RegOpenKeyEx(key, name, 0, KEY_QUERY_VALUE, &node) != ERROR_SUCCESS) { r = false; break; } fn(node, name, p); RegCloseKey(node); size = largest_subkey; } ponyint_pool_free_size(largest_subkey, name); return true; }
source_t* source_open(const char* file, const char** error_msgp) { FILE* fp = fopen(file, "rb"); if(fp == NULL) { *error_msgp = "can't open file"; return NULL; } fseek(fp, 0, SEEK_END); ssize_t size = ftell(fp); if(size < 0) { *error_msgp = "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*)ponyint_pool_alloc_size(size + 1); source->len = size + 1; ssize_t read = fread(source->m, sizeof(char), size, fp); source->m[size] = '\0'; if(read < size) { *error_msgp = "failed to read entire file"; ponyint_pool_free_size(source->len, source->m); POOL_FREE(source_t, source); fclose(fp); return NULL; } fclose(fp); return source; }
// Append the given text to the program's lib args, handling reallocs. static void append_to_args(program_t* program, const char* text) { pony_assert(program != NULL); pony_assert(text != NULL); size_t text_len = strlen(text); size_t new_len = program->lib_args_size + text_len + 1; // +1 for terminator if(new_len > program->lib_args_alloced) { size_t new_alloc = 2 * new_len; // 2* so there's spare space for next arg char* new_args = (char*)ponyint_pool_alloc_size(new_alloc); memcpy(new_args, program->lib_args, program->lib_args_size + 1); ponyint_pool_free_size(program->lib_args_alloced, program->lib_args); program->lib_args = new_args; program->lib_args_alloced = new_alloc; } strcat(program->lib_args, text); program->lib_args_size = new_len - 1; // Don't add terminator to length }
static void print_token(FILE* fp, token_t* token) { switch(token_get_id(token)) { case TK_STRING: { char* escaped = token_print_escaped(token); fprintf(fp, "\"%s\"", escaped); ponyint_pool_free_size(strlen(escaped), escaped); break; } case TK_ID: fprintf(fp, "(id %s)", token_print(token)); break; default: fprintf(fp, "%s", token_print(token)); break; } }
static LLVMValueRef make_vtable(compile_t* c, reach_type_t* t) { if(t->vtable_size == 0) return LLVMConstArray(c->void_ptr, NULL, 0); size_t buf_size = t->vtable_size * sizeof(LLVMValueRef); LLVMValueRef* vtable = (LLVMValueRef*)ponyint_pool_alloc_size(buf_size); memset(vtable, 0, buf_size); size_t i = HASHMAP_BEGIN; reach_method_name_t* n; while((n = reach_method_names_next(&t->methods, &i)) != NULL) { size_t j = HASHMAP_BEGIN; reach_method_t* m; while((m = reach_mangled_next(&n->r_mangled, &j)) != NULL) { uint32_t index = m->vtable_index; assert(index != (uint32_t)-1); assert(vtable[index] == NULL); if(t->primitive != NULL) vtable[index] = make_unbox_function(c, t, m); else vtable[index] = make_desc_ptr(m->func, c->void_ptr); } } for(uint32_t i = 0; i < t->vtable_size; i++) { if(vtable[i] == NULL) vtable[i] = LLVMConstNull(c->void_ptr); } LLVMValueRef r = LLVMConstArray(c->void_ptr, vtable, t->vtable_size); ponyint_pool_free_size(buf_size, vtable); return r; }
// TODO: Make group signature indiependent of package load order. const char* package_group_signature(package_group_t* group) { if(group->signature == NULL) { pony_ctx_t ctx; memset(&ctx, 0, sizeof(pony_ctx_t)); ponyint_array_t array; memset(&array, 0, sizeof(ponyint_array_t)); char* buf = (char*)ponyint_pool_alloc_size(SIGNATURE_LENGTH); pony_serialise(&ctx, group, package_group_signature_pony_type(), &array, s_alloc_fn, s_throw_fn); int status = blake2b(buf, SIGNATURE_LENGTH, array.ptr, array.size, NULL, 0); (void)status; pony_assert(status == 0); group->signature = buf; ponyint_pool_free_size(array.size, array.ptr); } return group->signature; }