static bool genfun_allocator(compile_t* c, gentype_t* g) { // No allocator for primitive types or pointers. if((g->primitive != NULL) || is_pointer(g->ast)) return true; const char* funname = genname_fun(g->type_name, "Alloc", NULL); LLVMTypeRef ftype = LLVMFunctionType(g->use_type, NULL, 0, false); LLVMValueRef fun = codegen_addfun(c, funname, ftype); codegen_startfun(c, fun, false); LLVMValueRef result; switch(g->underlying) { case TK_PRIMITIVE: case TK_CLASS: // Allocate the object or return the global instance. result = gencall_alloc(c, g); break; case TK_ACTOR: // Allocate the actor. result = gencall_create(c, g); break; default: assert(0); return false; } LLVMBuildRet(c->builder, result); codegen_finishfun(c); return true; }
static void add_rmethod(reachable_method_stack_t** s, reachable_type_t* t, reachable_method_name_t* n, ast_t* typeargs) { const char* name = genname_fun(NULL, n->name, typeargs); reachable_method_t* m = reach_method(n, name); if(m == NULL) { m = POOL_ALLOC(reachable_method_t); m->name = name; m->typeargs = ast_dup(typeargs); m->vtable_index = (uint32_t)-1; ast_t* fun = lookup(NULL, NULL, t->type, n->name); if(typeargs != NULL) { // Reify the method with its typeargs, if it has any. AST_GET_CHILDREN(fun, cap, id, typeparams, params, result, can_error, body); ast_t* r_fun = reify(fun, typeparams, typeargs); ast_free_unattached(fun); fun = r_fun; } m->r_fun = ast_dup(fun); ast_free_unattached(fun); reachable_methods_put(&n->r_methods, m); // Put on a stack of reachable methods to trace. *s = reachable_method_stack_push(*s, m); } }
LLVMValueRef genfun_proto(compile_t* c, gentype_t* g, const char *name, ast_t* typeargs) { ast_t* fun = get_fun(g, name, typeargs); LLVMValueRef func = get_prototype(c, g, name, typeargs, fun); // Disable debugloc on calls to methods that have no debug info. if(!ast_debug(fun)) dwarf_location(&c->dwarf, NULL); switch(ast_id(fun)) { case TK_NEW: case TK_BE: if(g->underlying == TK_ACTOR) { const char* fun_name = genname_fun(g->type_name, name, typeargs); const char* be_name = genname_be(fun_name); func = LLVMGetNamedFunction(c->module, be_name); } break; default: {} } ast_free_unattached(fun); return func; }
static LLVMValueRef get_sender(compile_t* c, gentype_t* g, const char* name, ast_t* typeargs) { const char* fun_name = genname_fun(g->type_name, name, typeargs); const char* be_name = genname_be(fun_name); return LLVMGetNamedFunction(c->module, be_name); }
reach_method_t* reach_method(reach_type_t* t, token_id cap, const char* name, ast_t* typeargs) { reach_method_name_t* n = reach_method_name(t, name); if(n == NULL) return NULL; if((n->id == TK_FUN) && ((n->cap == TK_BOX) || (n->cap == TK_TAG))) { switch(cap) { case TK_ISO: case TK_TRN: cap = TK_REF; break; case TK_REF: case TK_VAL: case TK_BOX: break; default: cap = n->cap; } } else { cap = n->cap; } name = genname_fun(cap, n->name, typeargs); return reach_rmethod(n, name); }
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 print_method(compile_t* c, printbuf_t* buf, reachable_type_t* t, const char* name, ast_t* typeargs) { const char* funname = genname_fun(t->name, name, typeargs); LLVMValueRef func = LLVMGetNamedFunction(c->module, funname); if(func == NULL) return; // Get a reified function. ast_t* fun = get_fun(t->ast, name, typeargs); if(fun == NULL) return; AST_GET_CHILDREN(fun, cap, id, typeparams, params, rtype, can_error, body, docstring); // Print the docstring if we have one. if(ast_id(docstring) == TK_STRING) { printbuf(buf, "/*\n" "%s" "*/\n", ast_name(docstring) ); } // Print the function signature. print_type_name(c, buf, rtype); printbuf(buf, " %s", funname); switch(ast_id(fun)) { case TK_NEW: case TK_BE: { ast_t* def = (ast_t*)ast_data(t->ast); if(ast_id(def) == TK_ACTOR) printbuf(buf, "__send"); break; } default: {} } printbuf(buf, "("); print_type_name(c, buf, t->ast); printbuf(buf, " self"); print_params(c, buf, params); printbuf(buf, ");\n\n"); ast_free_unattached(fun); }
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 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); }
reachable_method_t* reach_method_instance(reachable_method_name_t* n, ast_t* typeargs) { const char* name = n->name; if(typeargs != NULL) name = genname_fun(NULL, n->name, typeargs); reachable_method_t k; k.name = name; return reachable_methods_get(&n->r_methods, &k); }
LLVMTypeRef genfun_sig(compile_t* c, gentype_t* g, const char *name, ast_t* typeargs) { // If the function already exists, return its type. const char* funname = genname_fun(g->type_name, name, typeargs); LLVMValueRef func = LLVMGetNamedFunction(c->module, funname); if(func != NULL) return LLVMGetElementType(LLVMTypeOf(func)); ast_t* fun = get_fun(g, name, typeargs); LLVMTypeRef type = get_signature(c, g, fun); ast_free_unattached(fun); return type; }
static reach_method_t* add_rmethod(reach_t* r, reach_type_t* t, reach_method_name_t* n, token_id cap, ast_t* typeargs, pass_opt_t* opt) { const char* name = genname_fun(cap, n->name, typeargs); reach_method_t* m = reach_rmethod(n, name); if(m != NULL) return m; m = POOL_ALLOC(reach_method_t); memset(m, 0, sizeof(reach_method_t)); m->name = name; m->cap = cap; m->typeargs = ast_dup(typeargs); m->vtable_index = (uint32_t)-1; ast_t* r_ast = set_cap_and_ephemeral(t->ast, cap, TK_NONE); ast_t* fun = lookup(NULL, NULL, r_ast, n->name); ast_free_unattached(r_ast); if(typeargs != NULL) { // Reify the method with its typeargs, if it has any. AST_GET_CHILDREN(fun, cap, id, typeparams, params, result, can_error, body); fun = reify(fun, typeparams, typeargs, opt, false); } m->r_fun = fun; set_method_types(r, m, opt); m->mangled_name = make_mangled_name(m); m->full_name = make_full_name(t, m); // Add to both tables. reach_methods_put(&n->r_methods, m); reach_mangled_put(&n->r_mangled, m); // Put on a stack of reachable methods to trace. r->stack = reach_method_stack_push(r->stack, m); // Add the method to any subtypes. add_rmethod_to_subtypes(r, t, n, m, opt); return m; }
static uint32_t vtable_index(compile_t* c, const char* type_name, const char* name, ast_t* typeargs) { reachable_type_t* t = reach_type(c->reachable, type_name); if(t == NULL) return -1; reachable_method_name_t* n = reach_method_name(t, name); if(n == NULL) return -1; if(typeargs != NULL) name = genname_fun(NULL, name, typeargs); reachable_method_t* m = reach_method(n, name); if(m == NULL) return -1; assert(m->vtable_index != (uint32_t)-1); return m->vtable_index; }
static void gen_main(compile_t* c, gentype_t* main_g, gentype_t* env_g) { LLVMTypeRef params[3]; params[0] = c->i32; params[1] = LLVMPointerType(LLVMPointerType(c->i8, 0), 0); params[2] = LLVMPointerType(LLVMPointerType(c->i8, 0), 0); LLVMTypeRef ftype = LLVMFunctionType(c->i32, params, 3, false); LLVMValueRef func = LLVMAddFunction(c->module, "main", ftype); codegen_startfun(c, func, false); LLVMValueRef args[3]; args[0] = LLVMGetParam(func, 0); LLVMSetValueName(args[0], "argc"); args[1] = LLVMGetParam(func, 1); LLVMSetValueName(args[1], "argv"); args[2] = LLVMGetParam(func, 2); LLVMSetValueName(args[1], "envp"); // Initialise the pony runtime with argc and argv, getting a new argc. args[0] = gencall_runtime(c, "pony_init", args, 2, "argc"); // Create the main actor and become it. LLVMValueRef main_actor = create_main(c, main_g); // Create an Env on the main actor's heap. const char* env_name = "Env"; const char* env_create = genname_fun(env_name, "_create", NULL); LLVMValueRef env_args[4]; env_args[0] = gencall_alloc(c, env_g); env_args[1] = LLVMBuildZExt(c->builder, args[0], c->i64, ""); env_args[2] = args[1]; env_args[3] = args[2]; LLVMValueRef env = gencall_runtime(c, env_create, env_args, 4, "env"); LLVMSetInstructionCallConv(env, GEN_CALLCONV); // Run primitive initialisers using the main actor's heap. primitive_call(c, stringtab("_init"), env); // Create a type for the message. LLVMTypeRef f_params[4]; f_params[0] = c->i32; f_params[1] = c->i32; f_params[2] = c->void_ptr; f_params[3] = LLVMTypeOf(env); LLVMTypeRef msg_type = LLVMStructTypeInContext(c->context, f_params, 4, false); LLVMTypeRef msg_type_ptr = LLVMPointerType(msg_type, 0); // Allocate the message, setting its size and ID. uint32_t index = genfun_vtable_index(c, main_g, stringtab("create"), NULL); size_t msg_size = LLVMABISizeOfType(c->target_data, msg_type); args[0] = LLVMConstInt(c->i32, pool_index(msg_size), false); args[1] = LLVMConstInt(c->i32, index, false); LLVMValueRef msg = gencall_runtime(c, "pony_alloc_msg", args, 2, ""); LLVMValueRef msg_ptr = LLVMBuildBitCast(c->builder, msg, msg_type_ptr, ""); // Set the message contents. LLVMValueRef env_ptr = LLVMBuildStructGEP(c->builder, msg_ptr, 3, ""); LLVMBuildStore(c->builder, env, env_ptr); // Trace the message. gencall_runtime(c, "pony_gc_send", NULL, 0, ""); const char* env_trace = genname_trace(env_name); args[0] = LLVMBuildBitCast(c->builder, env, c->object_ptr, ""); args[1] = LLVMGetNamedFunction(c->module, env_trace); gencall_runtime(c, "pony_traceobject", args, 2, ""); gencall_runtime(c, "pony_send_done", NULL, 0, ""); // Send the message. args[0] = main_actor; args[1] = msg; gencall_runtime(c, "pony_sendv", args, 2, ""); // Start the runtime. LLVMValueRef zero = LLVMConstInt(c->i32, 0, false); LLVMValueRef rc = gencall_runtime(c, "pony_start", &zero, 1, ""); // Run primitive finalisers. We create a new main actor as a context to run // the finalisers in, but we do not initialise or schedule it. LLVMValueRef final_actor = create_main(c, main_g); primitive_call(c, stringtab("_final"), NULL); args[0] = final_actor; gencall_runtime(c, "pony_destroy", args, 1, ""); // Return the runtime exit code. LLVMBuildRet(c->builder, rc); codegen_finishfun(c); // External linkage for main(). LLVMSetLinkage(func, LLVMExternalLinkage); }