Mercurial > hg > Members > anatofuz > MoarVM
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 } |