comparison src/instrument/crossthreadwrite.c @ 0:2cf249471370

convert mercurial for git
author Takahiro SHIMIZU <anatofuz@cr.ie.u-ryukyu.ac.jp>
date Tue, 08 May 2018 16:09:12 +0900
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:2cf249471370
1 #include "moar.h"
2
3 /* Walk graph and insert write check instructions. */
4 static void prepend_ctw_check(MVMThreadContext *tc, MVMSpeshGraph *g, MVMSpeshBB *bb,
5 MVMSpeshIns *before_ins, MVMSpeshOperand check_reg,
6 MVMint16 guilty) {
7 MVMSpeshIns *ctw_ins = MVM_spesh_alloc(tc, g, sizeof(MVMSpeshIns));
8 ctw_ins->info = MVM_op_get_op(MVM_OP_ctw_check);
9 ctw_ins->operands = MVM_spesh_alloc(tc, g, 2 * sizeof(MVMSpeshOperand));
10 ctw_ins->operands[0] = check_reg;
11 ctw_ins->operands[1].lit_i16 = guilty;
12 MVM_spesh_manipulate_insert_ins(tc, bb, before_ins->prev, ctw_ins);
13 }
14 static void instrument_graph(MVMThreadContext *tc, MVMSpeshGraph *g) {
15 MVMSpeshBB *bb = g->entry->linear_next;
16 while (bb) {
17 MVMSpeshIns *ins = bb->first_ins;
18 while (ins) {
19 switch (ins->info->opcode) {
20 case MVM_OP_rebless:
21 prepend_ctw_check(tc, g, bb, ins, ins->operands[0], MVM_CTW_REBLESS);
22 case MVM_OP_bindattr_i:
23 case MVM_OP_bindattr_n:
24 case MVM_OP_bindattr_s:
25 case MVM_OP_bindattr_o:
26 case MVM_OP_bindattrs_i:
27 case MVM_OP_bindattrs_n:
28 case MVM_OP_bindattrs_s:
29 case MVM_OP_bindattrs_o:
30 prepend_ctw_check(tc, g, bb, ins, ins->operands[0], MVM_CTW_BIND_ATTR);
31 break;
32 case MVM_OP_bindpos_i:
33 case MVM_OP_bindpos_n:
34 case MVM_OP_bindpos_s:
35 case MVM_OP_bindpos_o:
36 prepend_ctw_check(tc, g, bb, ins, ins->operands[0], MVM_CTW_BIND_POS);
37 break;
38 case MVM_OP_push_i:
39 case MVM_OP_push_n:
40 case MVM_OP_push_s:
41 case MVM_OP_push_o:
42 prepend_ctw_check(tc, g, bb, ins, ins->operands[0], MVM_CTW_PUSH);
43 break;
44 case MVM_OP_pop_i:
45 case MVM_OP_pop_n:
46 case MVM_OP_pop_s:
47 case MVM_OP_pop_o:
48 prepend_ctw_check(tc, g, bb, ins, ins->operands[1], MVM_CTW_POP);
49 break;
50 case MVM_OP_shift_i:
51 case MVM_OP_shift_n:
52 case MVM_OP_shift_s:
53 case MVM_OP_shift_o:
54 prepend_ctw_check(tc, g, bb, ins, ins->operands[1], MVM_CTW_SHIFT);
55 break;
56 case MVM_OP_unshift_i:
57 case MVM_OP_unshift_n:
58 case MVM_OP_unshift_s:
59 case MVM_OP_unshift_o:
60 prepend_ctw_check(tc, g, bb, ins, ins->operands[0], MVM_CTW_UNSHIFT);
61 break;
62 case MVM_OP_splice:
63 prepend_ctw_check(tc, g, bb, ins, ins->operands[0], MVM_CTW_SPLICE);
64 break;
65 case MVM_OP_bindkey_i:
66 case MVM_OP_bindkey_n:
67 case MVM_OP_bindkey_s:
68 case MVM_OP_bindkey_o:
69 prepend_ctw_check(tc, g, bb, ins, ins->operands[0], MVM_CTW_BIND_KEY);
70 break;
71 case MVM_OP_deletekey:
72 prepend_ctw_check(tc, g, bb, ins, ins->operands[0], MVM_CTW_DELETE_KEY);
73 break;
74 case MVM_OP_assign:
75 case MVM_OP_assignunchecked:
76 case MVM_OP_assign_i:
77 case MVM_OP_assign_n:
78 case MVM_OP_assign_s:
79 prepend_ctw_check(tc, g, bb, ins, ins->operands[0], MVM_CTW_ASSIGN);
80 break;
81 case MVM_OP_bindpos2d_i:
82 case MVM_OP_bindpos2d_n:
83 case MVM_OP_bindpos2d_s:
84 case MVM_OP_bindpos2d_o:
85 case MVM_OP_bindpos3d_i:
86 case MVM_OP_bindpos3d_n:
87 case MVM_OP_bindpos3d_s:
88 case MVM_OP_bindpos3d_o:
89 case MVM_OP_bindposnd_i:
90 case MVM_OP_bindposnd_n:
91 case MVM_OP_bindposnd_s:
92 case MVM_OP_bindposnd_o:
93 prepend_ctw_check(tc, g, bb, ins, ins->operands[0], MVM_CTW_BIND_POS);
94 break;
95 }
96 ins = ins->next;
97 }
98 bb = bb->linear_next;
99 }
100 }
101
102 /* Adds instrumented version of the unspecialized bytecode. */
103 static void add_instrumentation(MVMThreadContext *tc, MVMStaticFrame *sf) {
104 MVMSpeshCode *sc;
105 MVMStaticFrameInstrumentation *ins;
106 MVMSpeshGraph *sg = MVM_spesh_graph_create(tc, sf, 1, 0);
107 instrument_graph(tc, sg);
108 sc = MVM_spesh_codegen(tc, sg);
109 ins = MVM_calloc(1, sizeof(MVMStaticFrameInstrumentation));
110 ins->instrumented_bytecode = sc->bytecode;
111 ins->instrumented_handlers = sc->handlers;
112 ins->instrumented_bytecode_size = sc->bytecode_size;
113 ins->uninstrumented_bytecode = sf->body.bytecode;
114 ins->uninstrumented_handlers = sf->body.handlers;
115 ins->uninstrumented_bytecode_size = sf->body.bytecode_size;
116 sf->body.instrumentation = ins;
117 MVM_spesh_graph_destroy(tc, sg);
118 MVM_free(sc);
119 }
120
121 /* Instruments code with detection and reporting of cross-thread writes. */
122 void MVM_cross_thread_write_instrument(MVMThreadContext *tc, MVMStaticFrame *sf) {
123 if (!sf->body.instrumentation || sf->body.bytecode != sf->body.instrumentation->instrumented_bytecode) {
124 /* Handle main, non-specialized, bytecode. */
125 if (!sf->body.instrumentation)
126 add_instrumentation(tc, sf);
127 sf->body.bytecode = sf->body.instrumentation->instrumented_bytecode;
128 sf->body.handlers = sf->body.instrumentation->instrumented_handlers;
129 sf->body.bytecode_size = sf->body.instrumentation->instrumented_bytecode_size;
130
131 /* Throw away any argument guard so we'll never resolve prior
132 * specializations again. */
133 MVM_spesh_arg_guard_discard(tc, sf);
134 }
135 }
136
137 /* Filter out some special cases to reduce noise. */
138 static MVMint64 filtered_out(MVMThreadContext *tc, MVMObject *written) {
139 /* If we're holding locks, exclude by default (unless we were asked to
140 * also include these). */
141 if (tc->num_locks && !tc->instance->cross_thread_write_logging_include_locked)
142 return 1;
143
144 /* Operations on a concurrent queue are fine 'cus it's concurrent. */
145 if (REPR(written)->ID == MVM_REPR_ID_ConcBlockingQueue)
146 return 1;
147
148 /* Write on object from event loop thread is usually shift of invokable. */
149 if (tc->instance->event_loop_thread)
150 if (written->header.owner == tc->instance->event_loop_thread->thread_id)
151 return 1;
152
153 /* Filter out writes to Sub and Method, since these are almost always just
154 * multi-dispatch caches. */
155 if (strncmp( MVM_6model_get_stable_debug_name(tc, written->st), "Method", 6) == 0)
156 return 1;
157 if (strncmp( MVM_6model_get_stable_debug_name(tc, written->st), "Sub", 3) == 0)
158 return 1;
159
160 /* Otherwise, may be relevant. */
161 return 0;
162 }
163
164 /* Squeal if the target of the write wasn't allocated by us. */
165 void MVM_cross_thread_write_check(MVMThreadContext *tc, MVMObject *written, MVMint16 guilty) {
166 if (written->header.owner != tc->thread_id && !filtered_out(tc, written)) {
167 char *guilty_desc = "did something to";
168 switch (guilty) {
169 case MVM_CTW_BIND_ATTR:
170 guilty_desc = "bound to an attribute of";
171 break;
172 case MVM_CTW_BIND_POS:
173 guilty_desc = "bound to an array slot of";
174 break;
175 case MVM_CTW_PUSH:
176 guilty_desc = "pushed to";
177 break;
178 case MVM_CTW_POP:
179 guilty_desc = "popped";
180 break;
181 case MVM_CTW_SHIFT:
182 guilty_desc = "shifted";
183 break;
184 case MVM_CTW_UNSHIFT:
185 guilty_desc = "unshifted to";
186 break;
187 case MVM_CTW_SPLICE:
188 guilty_desc = "spliced";
189 break;
190 case MVM_CTW_BIND_KEY:
191 guilty_desc = "bound to a hash key of";
192 break;
193 case MVM_CTW_DELETE_KEY:
194 guilty_desc = "deleted a hash key of";
195 break;
196 case MVM_CTW_ASSIGN:
197 guilty_desc = "assigned to";
198 break;
199 case MVM_CTW_REBLESS:
200 guilty_desc = "reblessed";
201 break;
202 }
203 uv_mutex_lock(&(tc->instance->mutex_cross_thread_write_logging));
204 fprintf(stderr, "Thread %d %s an object (%s) allocated by thread %d\n",
205 tc->thread_id, guilty_desc, MVM_6model_get_debug_name(tc, written), written->header.owner);
206 MVM_dump_backtrace(tc);
207 fprintf(stderr, "\n");
208 uv_mutex_unlock(&(tc->instance->mutex_cross_thread_write_logging));
209 }
210 }