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; }
static void trace_dynamic_nominal(compile_t* c, LLVMValueRef ctx, LLVMValueRef object, ast_t* type, ast_t* orig, ast_t* tuple, LLVMBasicBlockRef next_block) { // Skip if a primitive. ast_t* def = (ast_t*)ast_data(type); if(ast_id(def) == TK_PRIMITIVE) return; // If it's not possible to use match or as to extract this type from the // original type, there's no need to trace as this type. if(tuple != NULL) { // We are a tuple element. Our type is in the correct position in the // tuple, everything else is TK_DONTCARE. if(is_matchtype(orig, tuple) != MATCHTYPE_ACCEPT) return; } else { // We aren't a tuple element. if(is_matchtype(orig, type) != MATCHTYPE_ACCEPT) return; } // We aren't always this type. We need to check dynamically. LLVMValueRef desc = gendesc_fetch(c, object); LLVMValueRef test = gendesc_isnominal(c, desc, type); LLVMBasicBlockRef is_true = codegen_block(c, ""); LLVMBasicBlockRef is_false = codegen_block(c, ""); LLVMBuildCondBr(c->builder, test, is_true, is_false); // Trace as this type. LLVMPositionBuilderAtEnd(c->builder, is_true); gentrace(c, ctx, object, type); // If we have traced as known, unknown or actor, we're done with this // element. Otherwise, continue tracing this as if the match had been // unsuccessful. switch(trace_type(type)) { case TRACE_KNOWN: case TRACE_UNKNOWN: case TRACE_KNOWN_VAL: case TRACE_UNKNOWN_VAL: case TRACE_ACTOR: LLVMBuildBr(c->builder, next_block); break; default: LLVMBuildBr(c->builder, is_false); break; } // Carry on, whether we have traced or not. LLVMPositionBuilderAtEnd(c->builder, is_false); }
static LLVMTypeRef send_message(compile_t* c, ast_t* fun, LLVMValueRef to, LLVMValueRef func, uint32_t index) { // Get the parameter types. LLVMTypeRef f_type = LLVMGetElementType(LLVMTypeOf(func)); int count = LLVMCountParamTypes(f_type) + 2; VLA(LLVMTypeRef, f_params, count); LLVMGetParamTypes(f_type, &f_params[2]); // The first one becomes the message size, the second the message ID. f_params[0] = c->i32; f_params[1] = c->i32; f_params[2] = c->void_ptr; LLVMTypeRef msg_type = LLVMStructTypeInContext(c->context, f_params, count, false); LLVMTypeRef msg_type_ptr = LLVMPointerType(msg_type, 0); // Allocate the message, setting its size and ID. size_t msg_size = LLVMABISizeOfType(c->target_data, msg_type); LLVMValueRef args[2]; 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, ""); // Trace while populating the message contents. LLVMValueRef start_trace = gencall_runtime(c, "pony_gc_send", NULL, 0, ""); ast_t* params = ast_childidx(fun, 3); ast_t* param = ast_child(params); bool need_trace = false; for(int i = 3; i < count; i++) { LLVMValueRef arg = LLVMGetParam(func, i - 2); LLVMValueRef arg_ptr = LLVMBuildStructGEP(c->builder, msg_ptr, i, ""); LLVMBuildStore(c->builder, arg, arg_ptr); need_trace |= gentrace(c, arg, ast_type(param)); param = ast_sibling(param); } if(need_trace) gencall_runtime(c, "pony_send_done", NULL, 0, ""); else LLVMInstructionEraseFromParent(start_trace); // Send the message. args[0] = LLVMBuildBitCast(c->builder, to, c->object_ptr, ""); args[1] = msg; gencall_runtime(c, "pony_sendv", args, 2, ""); // Return the type of the message. return msg_type_ptr; }
static bool trace_elements(compile_t* c, gentype_t* g, LLVMValueRef tuple) { bool need_trace = false; for(int i = 0; i < g->field_count; i++) { LLVMValueRef value = LLVMBuildExtractValue(c->builder, tuple, i, ""); need_trace |= gentrace(c, value, g->fields[i]); } return need_trace; }
static void trace_tuple(compile_t* c, LLVMValueRef ctx, LLVMValueRef src_value, LLVMValueRef dst_value, ast_t* src_type, ast_t* dst_type) { int i = 0; // We're a tuple, determined statically. if(ast_id(dst_type) == TK_TUPLETYPE) { ast_t* src_child = ast_child(src_type); ast_t* dst_child = ast_child(dst_type); while((src_child != NULL) && (dst_child != NULL)) { // Extract each element and trace it. LLVMValueRef elem = LLVMBuildExtractValue(c->builder, dst_value, i, ""); gentrace(c, ctx, elem, elem, src_child, dst_child); i++; src_child = ast_sibling(src_child); dst_child = ast_sibling(dst_child); } pony_assert(src_child == NULL && dst_child == NULL); } else { // This is a boxed tuple. Trace the box, then handle the elements. trace_unknown(c, ctx, dst_value, PONY_TRACE_OPAQUE); // Extract the elements from the original unboxed tuple. pony_assert(LLVMGetTypeKind(LLVMTypeOf(src_value)) == LLVMStructTypeKind); ast_t* src_child = ast_child(src_type); while(src_child != NULL) { LLVMValueRef elem = LLVMBuildExtractValue(c->builder, src_value, i, ""); gentrace(c, ctx, elem, elem, src_child, src_child); i++; src_child = ast_sibling(src_child); } } }
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 bool trace_fields(compile_t* c, gentype_t* g, 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, ""); LLVMValueRef value = LLVMBuildLoad(c->builder, field, ""); need_trace |= gentrace(c, value, g->fields[i]); } return need_trace; }
static void trace_array_elements(compile_t* c, reach_type_t* t, LLVMValueRef ctx, LLVMValueRef object, LLVMValueRef pointer) { // Get the type argument for the array. This will be used to generate the // per-element trace call. ast_t* typeargs = ast_childidx(t->ast, 2); ast_t* typearg = ast_child(typeargs); if(!gentrace_needed(typearg)) return; reach_type_t* t_elem = reach_type(c->reach, typearg); pointer = LLVMBuildBitCast(c->builder, pointer, LLVMPointerType(t_elem->use_type, 0), ""); LLVMBasicBlockRef entry_block = LLVMGetInsertBlock(c->builder); LLVMBasicBlockRef cond_block = codegen_block(c, "cond"); LLVMBasicBlockRef body_block = codegen_block(c, "body"); LLVMBasicBlockRef post_block = codegen_block(c, "post"); // Read the size. LLVMValueRef size = field_value(c, object, 1); LLVMBuildBr(c->builder, cond_block); // While the index is less than the size, trace an element. The initial // index when coming from the entry block is zero. LLVMPositionBuilderAtEnd(c->builder, cond_block); LLVMValueRef phi = LLVMBuildPhi(c->builder, c->intptr, ""); LLVMValueRef zero = LLVMConstInt(c->intptr, 0, false); LLVMAddIncoming(phi, &zero, &entry_block, 1); LLVMValueRef test = LLVMBuildICmp(c->builder, LLVMIntULT, phi, size, ""); LLVMBuildCondBr(c->builder, test, body_block, post_block); // The phi node is the index. Get the element and trace it. LLVMPositionBuilderAtEnd(c->builder, body_block); LLVMValueRef elem_ptr = LLVMBuildGEP(c->builder, pointer, &phi, 1, "elem"); LLVMValueRef elem = LLVMBuildLoad(c->builder, elem_ptr, ""); gentrace(c, ctx, elem, typearg); // Add one to the phi node and branch back to the cond block. LLVMValueRef one = LLVMConstInt(c->intptr, 1, false); LLVMValueRef inc = LLVMBuildAdd(c->builder, phi, one, ""); body_block = LLVMGetInsertBlock(c->builder); LLVMAddIncoming(phi, &inc, &body_block, 1); LLVMBuildBr(c->builder, cond_block); LLVMPositionBuilderAtEnd(c->builder, post_block); }
static void trace_tuple(compile_t* c, LLVMValueRef ctx, LLVMValueRef value, ast_t* type) { int i = 0; // We're a tuple, determined statically. for(ast_t* child = ast_child(type); child != NULL; child = ast_sibling(child)) { // Extract each element and trace it. LLVMValueRef elem = LLVMBuildExtractValue(c->builder, value, i, ""); gentrace(c, ctx, elem, child); i++; } }
static void trace_maybe(compile_t* c, LLVMValueRef ctx, LLVMValueRef object, ast_t* type) { // Only trace the element if it isn't NULL. ast_t* type_args = ast_childidx(type, 2); ast_t* elem = ast_child(type_args); LLVMValueRef test = LLVMBuildIsNull(c->builder, object, ""); LLVMBasicBlockRef is_false = codegen_block(c, ""); LLVMBasicBlockRef is_true = codegen_block(c, ""); LLVMBuildCondBr(c->builder, test, is_true, is_false); LLVMPositionBuilderAtEnd(c->builder, is_false); gentrace(c, ctx, object, elem); LLVMBuildBr(c->builder, is_true); LLVMPositionBuilderAtEnd(c->builder, is_true); }
static void trace_maybe(compile_t* c, LLVMValueRef ctx, LLVMValueRef value, ast_t* type, bool tag) { ast_t* type_args = ast_childidx(type, 2); ast_t* elem = ast_child(type_args); if(is_machine_word(elem)) return; LLVMValueRef test = genprim_maybe_is_null(c, elem, value); LLVMBasicBlockRef is_false = codegen_block(c, ""); LLVMBasicBlockRef is_true = codegen_block(c, ""); LLVMBuildCondBr(c->builder, test, is_true, is_false); LLVMPositionBuilderAtEnd(c->builder, is_false); if(tag) trace_tag(c, ctx, value); else gentrace(c, ctx, value, elem); LLVMBuildBr(c->builder, is_true); LLVMPositionBuilderAtEnd(c->builder, is_true); }
static bool make_trace(compile_t* c, reach_type_t* t) { if(t->trace_fn == NULL) return true; if(t->underlying == TK_CLASS) { // Special case the array trace function. AST_GET_CHILDREN(t->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, t); return true; } } // Generate the trace function. codegen_startfun(c, t->trace_fn, NULL, NULL); LLVMSetFunctionCallConv(t->trace_fn, LLVMCCallConv); LLVMSetLinkage(t->trace_fn, LLVMExternalLinkage); LLVMValueRef ctx = LLVMGetParam(t->trace_fn, 0); LLVMValueRef arg = LLVMGetParam(t->trace_fn, 1); LLVMValueRef object = LLVMBuildBitCast(c->builder, arg, t->structure_ptr, "object"); int extra = 0; // Non-structs have a type descriptor. if(t->underlying != TK_STRUCT) extra++; // Actors have a pad. if(t->underlying == TK_ACTOR) extra++; for(uint32_t i = 0; i < t->field_count; i++) { LLVMValueRef field = LLVMBuildStructGEP(c->builder, object, i + extra, ""); if(!t->fields[i].embed) { // Call the trace function indirectly depending on rcaps. LLVMValueRef value = LLVMBuildLoad(c->builder, field, ""); gentrace(c, ctx, value, t->fields[i].ast); } else { // Call the trace function directly without marking the field. LLVMValueRef trace_fn = t->fields[i].type->trace_fn; 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, ""); } } } LLVMBuildRetVoid(c->builder); codegen_finishfun(c); return true; }
void gen_send_message(compile_t* c, reach_method_t* m, LLVMValueRef orig_args[], LLVMValueRef cast_args[], ast_t* args_ast) { // Allocate the message, setting its size and ID. size_t msg_size = (size_t)LLVMABISizeOfType(c->target_data, m->msg_type); LLVMTypeRef msg_type_ptr = LLVMPointerType(m->msg_type, 0); LLVMValueRef msg_args[3]; msg_args[0] = LLVMConstInt(c->i32, ponyint_pool_index(msg_size), false); msg_args[1] = LLVMConstInt(c->i32, m->vtable_index, false); LLVMValueRef msg = gencall_runtime(c, "pony_alloc_msg", msg_args, 2, ""); LLVMValueRef msg_ptr = LLVMBuildBitCast(c->builder, msg, msg_type_ptr, ""); for(unsigned int i = 0; i < m->param_count; i++) { LLVMValueRef arg_ptr = LLVMBuildStructGEP(c->builder, msg_ptr, i + 3, ""); LLVMBuildStore(c->builder, cast_args[i+1], arg_ptr); } // Trace while populating the message contents. ast_t* params = ast_childidx(m->r_fun, 3); ast_t* param = ast_child(params); ast_t* arg_ast = ast_child(args_ast); bool need_trace = false; while(param != NULL) { if(gentrace_needed(c, ast_type(arg_ast), ast_type(param))) { need_trace = true; break; } param = ast_sibling(param); arg_ast = ast_sibling(arg_ast); } LLVMValueRef ctx = codegen_ctx(c); if(need_trace) { gencall_runtime(c, "pony_gc_send", &ctx, 1, ""); param = ast_child(params); arg_ast = ast_child(args_ast); for(size_t i = 0; i < m->param_count; i++) { gentrace(c, ctx, orig_args[i+1], cast_args[i+1], ast_type(arg_ast), ast_type(param)); param = ast_sibling(param); arg_ast = ast_sibling(arg_ast); } gencall_runtime(c, "pony_send_done", &ctx, 1, ""); } // Send the message. msg_args[0] = ctx; msg_args[1] = LLVMBuildBitCast(c->builder, cast_args[0], c->object_ptr, ""); msg_args[2] = msg; gencall_runtime(c, "pony_sendv", msg_args, 3, ""); }
static void trace_dynamic_nominal(compile_t* c, LLVMValueRef ctx, LLVMValueRef object, ast_t* type, ast_t* orig, ast_t* tuple, LLVMBasicBlockRef next_block) { pony_assert(ast_id(type) == TK_NOMINAL); // Skip if a primitive. ast_t* def = (ast_t*)ast_data(type); if(ast_id(def) == TK_PRIMITIVE) return; int mutability = trace_cap_nominal(c->opt, type, orig, tuple); // If we can't extract the element from the original type, there is no need to // trace the element. if(mutability == -1) return; token_id dst_cap = TK_TAG; switch(mutability) { case PONY_TRACE_MUTABLE: dst_cap = TK_ISO; break; case PONY_TRACE_IMMUTABLE: dst_cap = TK_VAL; break; default: {} } ast_t* dst_type = ast_dup(type); ast_t* dst_cap_ast = cap_fetch(dst_type); ast_setid(dst_cap_ast, dst_cap); ast_t* dst_eph = ast_sibling(dst_cap_ast); if(ast_id(dst_eph) == TK_EPHEMERAL) ast_setid(dst_eph, TK_NONE); // We aren't always this type. We need to check dynamically. LLVMValueRef desc = gendesc_fetch(c, object); LLVMValueRef test = gendesc_isnominal(c, desc, type); LLVMBasicBlockRef is_true = codegen_block(c, ""); LLVMBasicBlockRef is_false = codegen_block(c, ""); LLVMBuildCondBr(c->builder, test, is_true, is_false); // Trace as this type. LLVMPositionBuilderAtEnd(c->builder, is_true); gentrace(c, ctx, object, object, type, dst_type); ast_free_unattached(dst_type); // If we have traced as mut or val, we're done with this element. Otherwise, // continue tracing this as if the match had been unsuccessful. if(mutability != PONY_TRACE_OPAQUE) LLVMBuildBr(c->builder, next_block); else LLVMBuildBr(c->builder, is_false); // Carry on, whether we have traced or not. LLVMPositionBuilderAtEnd(c->builder, is_false); }
void gen_send_message(compile_t* c, reach_method_t* m, LLVMValueRef args[], ast_t* args_ast) { // Allocate the message, setting its size and ID. compile_method_t* c_m = (compile_method_t*)m->c_method; size_t msg_size = (size_t)LLVMABISizeOfType(c->target_data, c_m->msg_type); LLVMTypeRef msg_type_ptr = LLVMPointerType(c_m->msg_type, 0); size_t params_buf_size = (m->param_count + 3) * sizeof(LLVMTypeRef); LLVMTypeRef* param_types = (LLVMTypeRef*)ponyint_pool_alloc_size(params_buf_size); LLVMGetStructElementTypes(c_m->msg_type, param_types); size_t args_buf_size = (m->param_count + 1) * sizeof(LLVMValueRef); LLVMValueRef* cast_args = (LLVMValueRef*)ponyint_pool_alloc_size(args_buf_size); size_t arg_types_buf_size = m->param_count * sizeof(ast_t*); ast_t** arg_types = (ast_t**)ponyint_pool_alloc_size(arg_types_buf_size); ast_t* arg_ast = ast_child(args_ast); deferred_reification_t* reify = c->frame->reify; for(size_t i = 0; i < m->param_count; i++) { arg_types[i] = deferred_reify(reify, ast_type(arg_ast), c->opt); cast_args[i+1] = gen_assign_cast(c, param_types[i+3], args[i+1], arg_types[i]); arg_ast = ast_sibling(arg_ast); } LLVMValueRef msg_args[5]; msg_args[0] = LLVMConstInt(c->i32, ponyint_pool_index(msg_size), false); msg_args[1] = LLVMConstInt(c->i32, m->vtable_index, false); LLVMValueRef msg = gencall_runtime(c, "pony_alloc_msg", msg_args, 2, ""); LLVMValueRef md = LLVMMDNodeInContext(c->context, NULL, 0); LLVMSetMetadataStr(msg, "pony.msgsend", md); LLVMValueRef msg_ptr = LLVMBuildBitCast(c->builder, msg, msg_type_ptr, ""); for(unsigned int i = 0; i < m->param_count; i++) { LLVMValueRef arg_ptr = LLVMBuildStructGEP(c->builder, msg_ptr, i + 3, ""); LLVMBuildStore(c->builder, cast_args[i+1], arg_ptr); } // Trace while populating the message contents. bool need_trace = false; for(size_t i = 0; i < m->param_count; i++) { if(gentrace_needed(c, arg_types[i], m->params[i].ast)) { need_trace = true; break; } } LLVMValueRef ctx = codegen_ctx(c); if(need_trace) { LLVMValueRef gc = gencall_runtime(c, "pony_gc_send", &ctx, 1, ""); LLVMSetMetadataStr(gc, "pony.msgsend", md); for(size_t i = 0; i < m->param_count; i++) { gentrace(c, ctx, args[i+1], cast_args[i+1], arg_types[i], m->params[i].ast); } gc = gencall_runtime(c, "pony_send_done", &ctx, 1, ""); LLVMSetMetadataStr(gc, "pony.msgsend", md); } // Send the message. msg_args[0] = ctx; msg_args[1] = LLVMBuildBitCast(c->builder, args[0], c->object_ptr, ""); msg_args[2] = msg; msg_args[3] = msg; msg_args[4] = LLVMConstInt(c->i1, 1, false); LLVMValueRef send; if(ast_id(m->fun->ast) == TK_NEW) send = gencall_runtime(c, "pony_sendv_single", msg_args, 5, ""); else send = gencall_runtime(c, "pony_sendv", msg_args, 5, ""); LLVMSetMetadataStr(send, "pony.msgsend", md); ponyint_pool_free_size(params_buf_size, param_types); ponyint_pool_free_size(args_buf_size, cast_args); for(size_t i = 0; i < m->param_count; i++) ast_free_unattached(arg_types[i]); ponyint_pool_free_size(arg_types_buf_size, arg_types); }
static LLVMTypeRef send_message(compile_t* c, ast_t* params, LLVMValueRef to, LLVMValueRef func, uint32_t index) { // Get the parameter types. LLVMTypeRef f_type = LLVMGetElementType(LLVMTypeOf(func)); int count = LLVMCountParamTypes(f_type) + 2; size_t buf_size = count * sizeof(LLVMTypeRef); LLVMTypeRef* f_params = (LLVMTypeRef*)ponyint_pool_alloc_size(buf_size); LLVMGetParamTypes(f_type, &f_params[2]); // The first one becomes the message size, the second the message ID. f_params[0] = c->i32; f_params[1] = c->i32; f_params[2] = c->void_ptr; LLVMTypeRef msg_type = LLVMStructTypeInContext(c->context, f_params, count, false); LLVMTypeRef msg_type_ptr = LLVMPointerType(msg_type, 0); ponyint_pool_free_size(buf_size, f_params); // Allocate the message, setting its size and ID. size_t msg_size = (size_t)LLVMABISizeOfType(c->target_data, msg_type); LLVMValueRef args[3]; args[0] = LLVMConstInt(c->i32, ponyint_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, ""); for(int i = 3; i < count; i++) { LLVMValueRef arg = LLVMGetParam(func, i - 2); LLVMValueRef arg_ptr = LLVMBuildStructGEP(c->builder, msg_ptr, i, ""); LLVMBuildStore(c->builder, arg, arg_ptr); } // Trace while populating the message contents. LLVMValueRef ctx = codegen_ctx(c); ast_t* param = ast_child(params); bool need_trace = false; while(param != NULL) { if(gentrace_needed(ast_type(param))) { need_trace = true; break; } param = ast_sibling(param); } if(need_trace) { gencall_runtime(c, "pony_gc_send", &ctx, 1, ""); param = ast_child(params); for(int i = 3; i < count; i++) { LLVMValueRef arg = LLVMGetParam(func, i - 2); gentrace(c, ctx, arg, ast_type(param)); param = ast_sibling(param); } gencall_runtime(c, "pony_send_done", &ctx, 1, ""); } // Send the message. args[0] = ctx; args[1] = LLVMBuildBitCast(c->builder, to, c->object_ptr, ""); args[2] = msg; gencall_runtime(c, "pony_sendv", args, 3, ""); // Return the type of the message. return msg_type_ptr; }