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.
9 #include <mono/metadata/abi-details.h>
10 #include <mono/metadata/mono-debug.h>
12 #include "interp/interp.h"
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
);
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
);
50 mini_profiler_emit_enter (MonoCompile
*cfg
)
52 if (!MONO_CFG_PROFILE (cfg
, ENTER
) || cfg
->current_method
!= cfg
->method
)
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
);
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
);
69 mini_profiler_emit_leave (MonoCompile
*cfg
, MonoInst
*ret
)
71 if (!MONO_CFG_PROFILE (cfg
, LEAVE
) || cfg
->current_method
!= cfg
->method
)
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
);
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
);
88 mini_profiler_emit_tail_call (MonoCompile
*cfg
, MonoMethod
*target
)
90 if (!MONO_CFG_PROFILE (cfg
, TAIL_CALL
) || cfg
->current_method
!= cfg
->method
)
93 g_assert (cfg
->current_method
== cfg
->method
);
97 EMIT_NEW_METHODCONST (cfg
, iargs
[0], cfg
->method
);
100 EMIT_NEW_METHODCONST (cfg
, iargs
[1], target
);
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
);
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 ()))
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
);
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
)
141 if (!MONO_OFFSET_IN_HANDLER (hclause
, offset
))
144 if (offset
+ (*ip
== CEE_LEAVE
? 5 : 2) <= hclause
->handler_offset
+ hclause
->handler_len
) {
150 // If so, find the exception object and pass it along.
152 EMIT_NEW_TEMPLOAD (cfg
, iargs
[3], mono_find_exvar_for_offset (cfg
, cclause
->handler_offset
)->inst_c0
);
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
);
165 mini_profiler_context_enable (void)
167 if (!mono_debug_enabled ())
168 mono_debug_init (MONO_DEBUG_FORMAT_MONO
);
172 memdup_with_type (gpointer data
, MonoType
*t
)
176 return g_memdup (data
, mono_type_size (t
, &dummy
));
180 get_int_reg (MonoContext
*ctx
, guint32 reg
)
182 return (guint8
*)(gsize
)mono_arch_context_get_int_reg (ctx
, reg
);
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
;
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
: {
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
;
218 case MONO_DEBUG_VAR_ADDRESS_MODE_REGISTER
:
219 info
= (MonoGSharedVtMethodRuntimeInfo
*) get_int_reg (ctx
, reg
);
221 case MONO_DEBUG_VAR_ADDRESS_MODE_REGOFFSET
:
222 info
= *(MonoGSharedVtMethodRuntimeInfo
**) (get_int_reg (ctx
, reg
) + (gint32
) info_var
->offset
);
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
;
236 case MONO_DEBUG_VAR_ADDRESS_MODE_REGISTER
:
237 locals
= get_int_reg (ctx
, reg
);
239 case MONO_DEBUG_VAR_ADDRESS_MODE_REGOFFSET
:
240 locals
= *(guint8
**) (get_int_reg (ctx
, reg
) + (gint32
) info_var
->offset
);
243 g_assert_not_reached ();
246 return memdup_with_type (locals
+ (gsize
) info
->entries
[idx
], var
->type
);
249 g_assert_not_reached ();
255 mini_profiler_context_get_this (MonoProfilerCallContext
*ctx
)
257 if (!mono_method_signature (ctx
->method
)->hasthis
)
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 ());
268 return get_variable_buffer (info
, info
->this_var
, &ctx
->context
);
272 mini_profiler_context_get_argument (MonoProfilerCallContext
*ctx
, guint32 pos
)
274 MonoMethodSignature
*sig
= mono_method_signature (ctx
->method
);
276 if (pos
>= sig
->param_count
)
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 ());
287 return get_variable_buffer (info
, &info
->params
[pos
], &ctx
->context
);
291 mini_profiler_context_get_local (MonoProfilerCallContext
*ctx
, guint32 pos
)
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
);
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 ());
314 return get_variable_buffer (info
, &info
->locals
[pos
], &ctx
->context
);
318 mini_profiler_context_get_result (MonoProfilerCallContext
*ctx
)
320 if (!ctx
->return_value
)
323 return memdup_with_type (ctx
->return_value
, mono_method_signature (ctx
->method
)->ret
);
327 mini_profiler_context_free_buffer (void *buffer
)