Significant disambiguation between host and target. (#10969)
[mono-project.git] / mono / mini / mini-profiler.c
blobeb67e817cc48486d7fc540a2902888a0932da413
1 /*
2 * Licensed to the .NET Foundation under one or more agreements.
3 * The .NET Foundation licenses this file to you under the MIT license.
4 * See the LICENSE file in the project root for more information.
5 */
7 #include <config.h>
9 #include <mono/metadata/abi-details.h>
10 #include <mono/metadata/mono-debug.h>
12 #include "interp/interp.h"
13 #include "ir-emit.h"
14 #include "mini.h"
16 #ifndef DISABLE_JIT
18 static MonoInst *
19 emit_fill_call_ctx (MonoCompile *cfg, MonoInst *method, MonoInst *ret)
21 cfg->flags |= MONO_CFG_HAS_ALLOCA;
23 MonoInst *alloc, *size, *fill_ctx;
25 EMIT_NEW_ICONST (cfg, size, sizeof (MonoProfilerCallContext));
26 MONO_INST_NEW (cfg, alloc, OP_LOCALLOC);
27 alloc->dreg = alloc_preg (cfg);
28 alloc->sreg1 = size->dreg;
29 alloc->flags |= MONO_INST_INIT;
30 MONO_ADD_INS (cfg->cbb, alloc);
31 MONO_INST_NEW (cfg, fill_ctx, OP_FILL_PROF_CALL_CTX);
32 fill_ctx->sreg1 = alloc->dreg;
33 MONO_ADD_INS (cfg->cbb, fill_ctx);
34 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, alloc->dreg, MONO_STRUCT_OFFSET (MonoProfilerCallContext, method), method->dreg);
36 if (ret) {
37 MonoInst *var = mono_compile_create_var (cfg, mono_method_signature (cfg->method)->ret, OP_LOCAL);
39 MonoInst *store, *addr;
41 EMIT_NEW_TEMPSTORE (cfg, store, var->inst_c0, ret);
42 EMIT_NEW_VARLOADA (cfg, addr, var, NULL);
43 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, alloc->dreg, MONO_STRUCT_OFFSET (MonoProfilerCallContext, return_value), addr->dreg);
46 return alloc;
49 void
50 mini_profiler_emit_enter (MonoCompile *cfg)
52 if (!MONO_CFG_PROFILE (cfg, ENTER) || cfg->current_method != cfg->method)
53 return;
55 MonoInst *iargs [2];
57 EMIT_NEW_METHODCONST (cfg, iargs [0], cfg->method);
59 if (MONO_CFG_PROFILE (cfg, ENTER_CONTEXT) && !cfg->llvm_only)
60 iargs [1] = emit_fill_call_ctx (cfg, iargs [0], NULL);
61 else
62 EMIT_NEW_PCONST (cfg, iargs [1], NULL);
64 /* void mono_profiler_raise_method_enter (MonoMethod *method, MonoProfilerCallContext *ctx) */
65 mono_emit_jit_icall (cfg, mono_profiler_raise_method_enter, iargs);
68 void
69 mini_profiler_emit_leave (MonoCompile *cfg, MonoInst *ret)
71 if (!MONO_CFG_PROFILE (cfg, LEAVE) || cfg->current_method != cfg->method)
72 return;
74 MonoInst *iargs [2];
76 EMIT_NEW_METHODCONST (cfg, iargs [0], cfg->method);
78 if (MONO_CFG_PROFILE (cfg, LEAVE_CONTEXT) && !cfg->llvm_only)
79 iargs [1] = emit_fill_call_ctx (cfg, iargs [0], ret);
80 else
81 EMIT_NEW_PCONST (cfg, iargs [1], NULL);
83 /* void mono_profiler_raise_method_leave (MonoMethod *method, MonoProfilerCallContext *ctx) */
84 mono_emit_jit_icall (cfg, mono_profiler_raise_method_leave, iargs);
87 void
88 mini_profiler_emit_tail_call (MonoCompile *cfg, MonoMethod *target)
90 if (!MONO_CFG_PROFILE (cfg, TAIL_CALL) || cfg->current_method != cfg->method)
91 return;
93 g_assert (cfg->current_method == cfg->method);
95 MonoInst *iargs [2];
97 EMIT_NEW_METHODCONST (cfg, iargs [0], cfg->method);
99 if (target)
100 EMIT_NEW_METHODCONST (cfg, iargs [1], target);
101 else
102 EMIT_NEW_PCONST (cfg, iargs [1], NULL);
104 /* void mono_profiler_raise_method_tail_call (MonoMethod *method, MonoMethod *target) */
105 mono_emit_jit_icall (cfg, mono_profiler_raise_method_tail_call, iargs);
108 void
109 mini_profiler_emit_call_finally (MonoCompile *cfg, MonoMethodHeader *header, unsigned char *ip,
110 guint32 index, MonoExceptionClause *clause)
112 if (!G_UNLIKELY (mono_profiler_clauses_enabled ()))
113 return;
115 MonoBasicBlock *ebb;
117 NEW_BBLOCK (cfg, ebb);
119 MonoInst *ins = mini_emit_runtime_constant (cfg, MONO_PATCH_INFO_PROFILER_CLAUSE_COUNT, NULL);
120 MonoInst *count_ins = mini_emit_memory_load (cfg, m_class_get_byval_arg (mono_defaults.uint32_class), ins, 0, 0);
121 EMIT_NEW_BIALU_IMM (cfg, ins, OP_ICOMPARE_IMM, -1, count_ins->dreg, 0);
122 ins->flags |= MONO_INST_LIKELY;
123 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, ebb);
125 MonoInst *iargs [4];
127 EMIT_NEW_METHODCONST (cfg, iargs [0], cfg->current_method);
128 EMIT_NEW_ICONST (cfg, iargs [1], index);
129 EMIT_NEW_ICONST (cfg, iargs [2], clause->flags);
131 MonoExceptionClause *cclause = NULL;
133 // Are we leaving a catch clause?
134 for (guint32 i = 0; i < header->num_clauses; i++) {
135 MonoExceptionClause *hclause = &header->clauses [i];
136 guint32 offset = ip - header->code;
138 if (hclause->flags != MONO_EXCEPTION_CLAUSE_NONE && hclause->flags != MONO_EXCEPTION_CLAUSE_FILTER)
139 continue;
141 if (!MONO_OFFSET_IN_HANDLER (hclause, offset))
142 continue;
144 if (offset + (*ip == CEE_LEAVE ? 5 : 2) <= hclause->handler_offset + hclause->handler_len) {
145 cclause = hclause;
146 break;
150 // If so, find the exception object and pass it along.
151 if (cclause)
152 EMIT_NEW_TEMPLOAD (cfg, iargs [3], mono_find_exvar_for_offset (cfg, cclause->handler_offset)->inst_c0);
153 else
154 EMIT_NEW_PCONST (cfg, iargs [3], NULL);
156 /* void mono_profiler_raise_exception_clause (MonoMethod *method, uint32_t index, MonoExceptionEnum type, MonoObject *exception) */
157 mono_emit_jit_icall (cfg, mono_profiler_raise_exception_clause, iargs);
159 MONO_START_BB (cfg, ebb);
162 #endif
164 void
165 mini_profiler_context_enable (void)
167 if (!mono_debug_enabled ())
168 mono_debug_init (MONO_DEBUG_FORMAT_MONO);
171 static gpointer
172 memdup_with_type (gpointer data, MonoType *t)
174 int dummy;
176 return g_memdup (data, mono_type_size (t, &dummy));
179 static guint8 *
180 get_int_reg (MonoContext *ctx, guint32 reg)
182 return (guint8 *)(gsize)mono_arch_context_get_int_reg (ctx, reg);
185 static gpointer
186 get_variable_buffer (MonoDebugMethodJitInfo *jit, MonoDebugVarInfo *var, MonoContext *ctx)
188 guint32 flags = var->index & MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS;
189 guint32 reg = var->index & ~MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS;
191 switch (flags) {
192 case MONO_DEBUG_VAR_ADDRESS_MODE_REGISTER: {
194 * This is kind of a special case: All other address modes ultimately
195 * produce an address to where the actual value is located, but this
196 * address mode gets us the value itself as an host_mgreg_t value.
198 host_mgreg_t value = (host_mgreg_t) get_int_reg (ctx, reg);
200 return memdup_with_type (&value, var->type);
202 case MONO_DEBUG_VAR_ADDRESS_MODE_REGOFFSET:
203 return memdup_with_type (get_int_reg (ctx, reg) + (gint32) var->offset, var->type);
204 case MONO_DEBUG_VAR_ADDRESS_MODE_REGOFFSET_INDIR:
205 case MONO_DEBUG_VAR_ADDRESS_MODE_VTADDR:
206 return memdup_with_type (*(guint8 **) (get_int_reg (ctx, reg) + (gint32) var->offset), var->type);
207 case MONO_DEBUG_VAR_ADDRESS_MODE_GSHAREDVT_LOCAL: {
208 guint32 idx = reg;
210 MonoDebugVarInfo *info_var = jit->gsharedvt_info_var;
212 flags = info_var->index & MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS;
213 reg = info_var->index & ~MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS;
215 MonoGSharedVtMethodRuntimeInfo *info;
217 switch (flags) {
218 case MONO_DEBUG_VAR_ADDRESS_MODE_REGISTER:
219 info = (MonoGSharedVtMethodRuntimeInfo *) get_int_reg (ctx, reg);
220 break;
221 case MONO_DEBUG_VAR_ADDRESS_MODE_REGOFFSET:
222 info = *(MonoGSharedVtMethodRuntimeInfo **) (get_int_reg (ctx, reg) + (gint32) info_var->offset);
223 break;
224 default:
225 g_assert_not_reached ();
228 MonoDebugVarInfo *locals_var = jit->gsharedvt_locals_var;
230 flags = locals_var->index & MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS;
231 reg = locals_var->index & ~MONO_DEBUG_VAR_ADDRESS_MODE_FLAGS;
233 guint8 *locals;
235 switch (flags) {
236 case MONO_DEBUG_VAR_ADDRESS_MODE_REGISTER:
237 locals = get_int_reg (ctx, reg);
238 break;
239 case MONO_DEBUG_VAR_ADDRESS_MODE_REGOFFSET:
240 locals = *(guint8 **) (get_int_reg (ctx, reg) + (gint32) info_var->offset);
241 break;
242 default:
243 g_assert_not_reached ();
246 return memdup_with_type (locals + (gsize) info->entries [idx], var->type);
248 default:
249 g_assert_not_reached ();
250 return NULL;
254 gpointer
255 mini_profiler_context_get_this (MonoProfilerCallContext *ctx)
257 if (!mono_method_signature (ctx->method)->hasthis)
258 return NULL;
260 if (ctx->interp_frame)
261 return memdup_with_type (mini_get_interp_callbacks ()->frame_get_this (ctx->interp_frame), m_class_get_this_arg (ctx->method->klass));
263 MonoDebugMethodJitInfo *info = mono_debug_find_method (ctx->method, mono_domain_get ());
265 if (!info)
266 return NULL;
268 return get_variable_buffer (info, info->this_var, &ctx->context);
271 gpointer
272 mini_profiler_context_get_argument (MonoProfilerCallContext *ctx, guint32 pos)
274 MonoMethodSignature *sig = mono_method_signature (ctx->method);
276 if (pos >= sig->param_count)
277 return NULL;
279 if (ctx->interp_frame)
280 return memdup_with_type (mini_get_interp_callbacks ()->frame_get_arg (ctx->interp_frame, pos), sig->params [pos]);
282 MonoDebugMethodJitInfo *info = mono_debug_find_method (ctx->method, mono_domain_get ());
284 if (!info)
285 return NULL;
287 return get_variable_buffer (info, &info->params [pos], &ctx->context);
290 gpointer
291 mini_profiler_context_get_local (MonoProfilerCallContext *ctx, guint32 pos)
293 ERROR_DECL (error);
294 MonoMethodHeader *header = mono_method_get_header_checked (ctx->method, error);
295 mono_error_assert_ok (error); // Must be a valid method at this point.
297 if (pos >= header->num_locals) {
298 mono_metadata_free_mh (header);
299 return NULL;
302 MonoType *t = header->locals [pos];
304 mono_metadata_free_mh (header);
306 if (ctx->interp_frame)
307 return memdup_with_type (mini_get_interp_callbacks ()->frame_get_local (ctx->interp_frame, pos), t);
309 MonoDebugMethodJitInfo *info = mono_debug_find_method (ctx->method, mono_domain_get ());
311 if (!info)
312 return NULL;
314 return get_variable_buffer (info, &info->locals [pos], &ctx->context);
317 gpointer
318 mini_profiler_context_get_result (MonoProfilerCallContext *ctx)
320 if (!ctx->return_value)
321 return NULL;
323 return memdup_with_type (ctx->return_value, mono_method_signature (ctx->method)->ret);
326 void
327 mini_profiler_context_free_buffer (void *buffer)
329 g_free (buffer);