Mercurial > hg > Members > anatofuz > MoarVM
view src/instrument/crossthreadwrite.c @ 64:da6d6597bd69 default tip
rollback
author | anatofuz <anatofuz@cr.ie.u-ryukyu.ac.jp> |
---|---|
date | Fri, 15 Feb 2019 20:51:54 +0900 |
parents | 2cf249471370 |
children |
line wrap: on
line source
#include "moar.h" /* Walk graph and insert write check instructions. */ static void prepend_ctw_check(MVMThreadContext *tc, MVMSpeshGraph *g, MVMSpeshBB *bb, MVMSpeshIns *before_ins, MVMSpeshOperand check_reg, MVMint16 guilty) { MVMSpeshIns *ctw_ins = MVM_spesh_alloc(tc, g, sizeof(MVMSpeshIns)); ctw_ins->info = MVM_op_get_op(MVM_OP_ctw_check); ctw_ins->operands = MVM_spesh_alloc(tc, g, 2 * sizeof(MVMSpeshOperand)); ctw_ins->operands[0] = check_reg; ctw_ins->operands[1].lit_i16 = guilty; MVM_spesh_manipulate_insert_ins(tc, bb, before_ins->prev, ctw_ins); } static void instrument_graph(MVMThreadContext *tc, MVMSpeshGraph *g) { MVMSpeshBB *bb = g->entry->linear_next; while (bb) { MVMSpeshIns *ins = bb->first_ins; while (ins) { switch (ins->info->opcode) { case MVM_OP_rebless: prepend_ctw_check(tc, g, bb, ins, ins->operands[0], MVM_CTW_REBLESS); case MVM_OP_bindattr_i: case MVM_OP_bindattr_n: case MVM_OP_bindattr_s: case MVM_OP_bindattr_o: case MVM_OP_bindattrs_i: case MVM_OP_bindattrs_n: case MVM_OP_bindattrs_s: case MVM_OP_bindattrs_o: prepend_ctw_check(tc, g, bb, ins, ins->operands[0], MVM_CTW_BIND_ATTR); break; case MVM_OP_bindpos_i: case MVM_OP_bindpos_n: case MVM_OP_bindpos_s: case MVM_OP_bindpos_o: prepend_ctw_check(tc, g, bb, ins, ins->operands[0], MVM_CTW_BIND_POS); break; case MVM_OP_push_i: case MVM_OP_push_n: case MVM_OP_push_s: case MVM_OP_push_o: prepend_ctw_check(tc, g, bb, ins, ins->operands[0], MVM_CTW_PUSH); break; case MVM_OP_pop_i: case MVM_OP_pop_n: case MVM_OP_pop_s: case MVM_OP_pop_o: prepend_ctw_check(tc, g, bb, ins, ins->operands[1], MVM_CTW_POP); break; case MVM_OP_shift_i: case MVM_OP_shift_n: case MVM_OP_shift_s: case MVM_OP_shift_o: prepend_ctw_check(tc, g, bb, ins, ins->operands[1], MVM_CTW_SHIFT); break; case MVM_OP_unshift_i: case MVM_OP_unshift_n: case MVM_OP_unshift_s: case MVM_OP_unshift_o: prepend_ctw_check(tc, g, bb, ins, ins->operands[0], MVM_CTW_UNSHIFT); break; case MVM_OP_splice: prepend_ctw_check(tc, g, bb, ins, ins->operands[0], MVM_CTW_SPLICE); break; case MVM_OP_bindkey_i: case MVM_OP_bindkey_n: case MVM_OP_bindkey_s: case MVM_OP_bindkey_o: prepend_ctw_check(tc, g, bb, ins, ins->operands[0], MVM_CTW_BIND_KEY); break; case MVM_OP_deletekey: prepend_ctw_check(tc, g, bb, ins, ins->operands[0], MVM_CTW_DELETE_KEY); break; case MVM_OP_assign: case MVM_OP_assignunchecked: case MVM_OP_assign_i: case MVM_OP_assign_n: case MVM_OP_assign_s: prepend_ctw_check(tc, g, bb, ins, ins->operands[0], MVM_CTW_ASSIGN); break; case MVM_OP_bindpos2d_i: case MVM_OP_bindpos2d_n: case MVM_OP_bindpos2d_s: case MVM_OP_bindpos2d_o: case MVM_OP_bindpos3d_i: case MVM_OP_bindpos3d_n: case MVM_OP_bindpos3d_s: case MVM_OP_bindpos3d_o: case MVM_OP_bindposnd_i: case MVM_OP_bindposnd_n: case MVM_OP_bindposnd_s: case MVM_OP_bindposnd_o: prepend_ctw_check(tc, g, bb, ins, ins->operands[0], MVM_CTW_BIND_POS); break; } ins = ins->next; } bb = bb->linear_next; } } /* Adds instrumented version of the unspecialized bytecode. */ static void add_instrumentation(MVMThreadContext *tc, MVMStaticFrame *sf) { MVMSpeshCode *sc; MVMStaticFrameInstrumentation *ins; MVMSpeshGraph *sg = MVM_spesh_graph_create(tc, sf, 1, 0); instrument_graph(tc, sg); sc = MVM_spesh_codegen(tc, sg); ins = MVM_calloc(1, sizeof(MVMStaticFrameInstrumentation)); ins->instrumented_bytecode = sc->bytecode; ins->instrumented_handlers = sc->handlers; ins->instrumented_bytecode_size = sc->bytecode_size; ins->uninstrumented_bytecode = sf->body.bytecode; ins->uninstrumented_handlers = sf->body.handlers; ins->uninstrumented_bytecode_size = sf->body.bytecode_size; sf->body.instrumentation = ins; MVM_spesh_graph_destroy(tc, sg); MVM_free(sc); } /* Instruments code with detection and reporting of cross-thread writes. */ void MVM_cross_thread_write_instrument(MVMThreadContext *tc, MVMStaticFrame *sf) { if (!sf->body.instrumentation || sf->body.bytecode != sf->body.instrumentation->instrumented_bytecode) { /* Handle main, non-specialized, bytecode. */ if (!sf->body.instrumentation) add_instrumentation(tc, sf); sf->body.bytecode = sf->body.instrumentation->instrumented_bytecode; sf->body.handlers = sf->body.instrumentation->instrumented_handlers; sf->body.bytecode_size = sf->body.instrumentation->instrumented_bytecode_size; /* Throw away any argument guard so we'll never resolve prior * specializations again. */ MVM_spesh_arg_guard_discard(tc, sf); } } /* Filter out some special cases to reduce noise. */ static MVMint64 filtered_out(MVMThreadContext *tc, MVMObject *written) { /* If we're holding locks, exclude by default (unless we were asked to * also include these). */ if (tc->num_locks && !tc->instance->cross_thread_write_logging_include_locked) return 1; /* Operations on a concurrent queue are fine 'cus it's concurrent. */ if (REPR(written)->ID == MVM_REPR_ID_ConcBlockingQueue) return 1; /* Write on object from event loop thread is usually shift of invokable. */ if (tc->instance->event_loop_thread) if (written->header.owner == tc->instance->event_loop_thread->thread_id) return 1; /* Filter out writes to Sub and Method, since these are almost always just * multi-dispatch caches. */ if (strncmp( MVM_6model_get_stable_debug_name(tc, written->st), "Method", 6) == 0) return 1; if (strncmp( MVM_6model_get_stable_debug_name(tc, written->st), "Sub", 3) == 0) return 1; /* Otherwise, may be relevant. */ return 0; } /* Squeal if the target of the write wasn't allocated by us. */ void MVM_cross_thread_write_check(MVMThreadContext *tc, MVMObject *written, MVMint16 guilty) { if (written->header.owner != tc->thread_id && !filtered_out(tc, written)) { char *guilty_desc = "did something to"; switch (guilty) { case MVM_CTW_BIND_ATTR: guilty_desc = "bound to an attribute of"; break; case MVM_CTW_BIND_POS: guilty_desc = "bound to an array slot of"; break; case MVM_CTW_PUSH: guilty_desc = "pushed to"; break; case MVM_CTW_POP: guilty_desc = "popped"; break; case MVM_CTW_SHIFT: guilty_desc = "shifted"; break; case MVM_CTW_UNSHIFT: guilty_desc = "unshifted to"; break; case MVM_CTW_SPLICE: guilty_desc = "spliced"; break; case MVM_CTW_BIND_KEY: guilty_desc = "bound to a hash key of"; break; case MVM_CTW_DELETE_KEY: guilty_desc = "deleted a hash key of"; break; case MVM_CTW_ASSIGN: guilty_desc = "assigned to"; break; case MVM_CTW_REBLESS: guilty_desc = "reblessed"; break; } uv_mutex_lock(&(tc->instance->mutex_cross_thread_write_logging)); fprintf(stderr, "Thread %d %s an object (%s) allocated by thread %d\n", tc->thread_id, guilty_desc, MVM_6model_get_debug_name(tc, written), written->header.owner); MVM_dump_backtrace(tc); fprintf(stderr, "\n"); uv_mutex_unlock(&(tc->instance->mutex_cross_thread_write_logging)); } }