static bool trace_fields(compile_t* c, gentype_t* g, LLVMValueRef ctx, LLVMValueRef object, int extra) { bool need_trace = false; for(int i = 0; i < g->field_count; i++) { LLVMValueRef field = LLVMBuildStructGEP(c->builder, object, i + extra, ""); if(g->field_keys[i] != TK_EMBED) { // Call the trace function indirectly depending on rcaps. LLVMValueRef value = LLVMBuildLoad(c->builder, field, ""); need_trace |= gentrace(c, ctx, value, g->fields[i]); } else { // Call the trace function directly without marking the field. const char* fun = genname_trace(genname_type(g->fields[i])); LLVMValueRef trace_fn = LLVMGetNamedFunction(c->module, fun); if(trace_fn != NULL) { LLVMValueRef args[2]; args[0] = ctx; args[1] = LLVMBuildBitCast(c->builder, field, c->object_ptr, ""); LLVMBuildCall(c->builder, trace_fn, args, 2, ""); need_trace = true; } } } return need_trace; }
void gentrace_prototype(compile_t* c, reachable_type_t* t) { switch(t->underlying) { case TK_CLASS: case TK_ACTOR: break; default: return; } bool need_trace = false; for(uint32_t i = 0; i < t->field_count; i++) { if(gentrace_needed(t->fields[i].ast)) { need_trace = true; break; } } if(!need_trace) return; const char* trace_name = genname_trace(t->name); t->trace_fn = codegen_addfun(c, trace_name, c->trace_type); }
void gendesc_init(compile_t* c, gentype_t* g) { // Initialise the global descriptor. uint32_t size = (uint32_t)LLVMABISizeOfType(c->target_data, g->structure); // Generate a separate type ID for every type. LLVMValueRef args[DESC_LENGTH]; args[DESC_ID] = make_type_id(c, g->type_name); args[DESC_SIZE] = LLVMConstInt(c->i32, size, false); args[DESC_TRAIT_COUNT] = make_trait_count(c, g); args[DESC_FIELD_COUNT] = make_field_count(c, g); args[DESC_TRACE] = make_function_ptr(c, genname_trace(g->type_name), c->trace_fn); args[DESC_SERIALISE] = make_function_ptr(c, genname_serialise(g->type_name), c->trace_fn); args[DESC_DESERIALISE] = make_function_ptr(c, genname_deserialise(g->type_name), c->trace_fn); args[DESC_DISPATCH] = make_function_ptr(c, genname_dispatch(g->type_name), c->dispatch_fn); args[DESC_FINALISE] = make_function_ptr(c, genname_finalise(g->type_name), c->final_fn); args[DESC_EVENT_NOTIFY] = LLVMConstInt(c->i32, genfun_vtable_index(c, g, stringtab("_event_notify"), NULL), false); args[DESC_TRAITS] = make_trait_list(c, g); args[DESC_FIELDS] = make_field_list(c, g); args[DESC_VTABLE] = make_vtable(c, g); LLVMValueRef desc = LLVMConstNamedStruct(g->desc_type, args, DESC_LENGTH); LLVMSetInitializer(g->desc, desc); LLVMSetGlobalConstant(g->desc, true); }
static bool trace_known(compile_t* c, LLVMValueRef ctx, LLVMValueRef value, ast_t* type) { gentype_t g; if(!gentype(c, type, &g)) return false; // Get the trace function statically. const char* fun = genname_trace(g.type_name); LLVMValueRef trace_fn = LLVMGetNamedFunction(c->module, fun); // If this type has no trace function, don't try to recurse in the runtime. if(trace_fn != NULL) { // Cast the value to an object pointer. LLVMValueRef args[3]; args[0] = ctx; args[1] = LLVMBuildBitCast(c->builder, value, c->object_ptr, ""); args[2] = trace_fn; gencall_runtime(c, "pony_traceobject", args, 3, ""); } else { // Cast the value to a void pointer. LLVMValueRef args[2]; args[0] = ctx; args[1] = LLVMBuildBitCast(c->builder, value, c->void_ptr, ""); gencall_runtime(c, "pony_trace", args, 2, ""); } return true; }
static bool make_trace(compile_t* c, gentype_t* g) { // Do nothing if we have no fields. if(g->field_count == 0) return true; if(g->underlying == TK_CLASS) { // Special case the array trace function. AST_GET_CHILDREN(g->ast, pkg, id); const char* package = ast_name(pkg); const char* name = ast_name(id); if((package == c->str_builtin) && (name == c->str_Array)) { genprim_array_trace(c, g); return true; } } // Create a trace function. const char* trace_name = genname_trace(g->type_name); LLVMValueRef trace_fn = codegen_addfun(c, trace_name, c->trace_type); codegen_startfun(c, trace_fn, false); LLVMSetFunctionCallConv(trace_fn, LLVMCCallConv); LLVMValueRef ctx = LLVMGetParam(trace_fn, 0); LLVMValueRef arg = LLVMGetParam(trace_fn, 1); LLVMValueRef object = LLVMBuildBitCast(c->builder, arg, g->structure_ptr, "object"); // If we don't ever trace anything, delete this function. int extra = 0; // Non-structs have a type descriptor. if(g->underlying != TK_STRUCT) extra++; // Actors have a pad. if(g->underlying == TK_ACTOR) extra++; bool need_trace = trace_fields(c, g, ctx, object, extra); LLVMBuildRetVoid(c->builder); codegen_finishfun(c); if(!need_trace) LLVMDeleteFunction(trace_fn); return true; }
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); }
static bool make_trace(compile_t* c, gentype_t* g) { // Do nothing if we have no fields. if(g->field_count == 0) return true; if(g->underlying == TK_CLASS) { // Special case the array trace function. AST_GET_CHILDREN(g->ast, pkg, id); const char* package = ast_name(pkg); const char* name = ast_name(id); if((package == c->str_1) && (name == c->str_Array)) { genprim_array_trace(c, g); return true; } } // Create a trace function. const char* trace_name = genname_trace(g->type_name); LLVMValueRef trace_fn = codegen_addfun(c, trace_name, c->trace_type); codegen_startfun(c, trace_fn, false); LLVMSetFunctionCallConv(trace_fn, LLVMCCallConv); LLVMValueRef arg = LLVMGetParam(trace_fn, 0); LLVMValueRef object = LLVMBuildBitCast(c->builder, arg, g->structure_ptr, "object"); // If we don't ever trace anything, delete this function. bool need_trace; if(g->underlying == TK_TUPLETYPE) { // Create another function that traces the tuple members. const char* trace_tuple_name = genname_tracetuple(g->type_name); LLVMTypeRef trace_tuple_type = LLVMFunctionType(c->void_type, &g->primitive, 1, false); LLVMValueRef trace_tuple_fn = codegen_addfun(c, trace_tuple_name, trace_tuple_type); codegen_startfun(c, trace_tuple_fn, false); LLVMSetFunctionCallConv(trace_tuple_fn, LLVMCCallConv); LLVMValueRef arg = LLVMGetParam(trace_tuple_fn, 0); need_trace = trace_elements(c, g, arg); LLVMBuildRetVoid(c->builder); codegen_finishfun(c); if(need_trace) { // Get the tuple primitive. LLVMValueRef tuple_ptr = LLVMBuildStructGEP(c->builder, object, 1, ""); LLVMValueRef tuple = LLVMBuildLoad(c->builder, tuple_ptr, ""); // Call the tuple trace function with the unboxed primitive type. LLVMBuildCall(c->builder, trace_tuple_fn, &tuple, 1, ""); } else { LLVMDeleteFunction(trace_tuple_fn); } } else { int extra = 1; // Actors have a pad. if(g->underlying == TK_ACTOR) extra++; need_trace = trace_fields(c, g, object, extra); } LLVMBuildRetVoid(c->builder); codegen_finishfun(c); if(!need_trace) LLVMDeleteFunction(trace_fn); return true; }