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); }
bool gentrace_needed(ast_t* type) { switch(trace_type(type)) { case TRACE_NONE: assert(0); return false; case TRACE_PRIMITIVE: return false; case TRACE_TUPLE: { for(ast_t* child = ast_child(type); child != NULL; child = ast_sibling(child)) { if(gentrace_needed(child)) return true; } return false; } default: break; } return true; }
bool gentrace_needed(compile_t* c, ast_t* src_type, ast_t* dst_type) { switch(trace_type(src_type)) { case TRACE_NONE: pony_assert(0); return false; case TRACE_MACHINE_WORD: { if(ast_id(dst_type) == TK_NOMINAL) { ast_t* def = (ast_t*)ast_data(dst_type); if(ast_id(def) == TK_PRIMITIVE) return false; } return true; } case TRACE_PRIMITIVE: return false; case TRACE_TUPLE: { 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)) { if(gentrace_needed(c, src_child, dst_child)) return true; 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. We'll have to trace the box anyway. return true; } return false; } default: break; } return true; }
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); }
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, ""); }
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 void add_dispatch_case(compile_t* c, reachable_type_t* t, ast_t* params, uint32_t index, LLVMValueRef handler, LLVMTypeRef type) { // Add a case to the dispatch function to handle this message. codegen_startfun(c, t->dispatch_fn, NULL, NULL); LLVMBasicBlockRef block = codegen_block(c, "handler"); LLVMValueRef id = LLVMConstInt(c->i32, index, false); LLVMAddCase(t->dispatch_switch, id, block); // Destructure the message. LLVMPositionBuilderAtEnd(c->builder, block); LLVMValueRef ctx = LLVMGetParam(t->dispatch_fn, 0); LLVMValueRef this_ptr = LLVMGetParam(t->dispatch_fn, 1); LLVMValueRef msg = LLVMBuildBitCast(c->builder, LLVMGetParam(t->dispatch_fn, 2), type, ""); int count = LLVMCountParams(handler); size_t buf_size = count * sizeof(LLVMValueRef); LLVMValueRef* args = (LLVMValueRef*)ponyint_pool_alloc_size(buf_size); args[0] = LLVMBuildBitCast(c->builder, this_ptr, t->use_type, ""); for(int i = 1; i < count; i++) { LLVMValueRef field = LLVMBuildStructGEP(c->builder, msg, i + 2, ""); args[i] = LLVMBuildLoad(c->builder, field, ""); } // Trace the message. 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) { param = ast_child(params); gencall_runtime(c, "pony_gc_recv", &ctx, 1, ""); for(int i = 1; i < count; i++) { gentrace(c, ctx, args[i], ast_type(param)); param = ast_sibling(param); } gencall_runtime(c, "pony_recv_done", &ctx, 1, ""); } // Call the handler. codegen_call(c, handler, args, count); LLVMBuildRetVoid(c->builder); codegen_finishfun(c); ponyint_pool_free_size(buf_size, args); }
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; }