ip = frame->imethod->code;
MINT_IN_BREAK;
}
+ MINT_IN_CASE(MINT_CALL_DELEGATE) {
+ MonoMethodSignature *csignature = (MonoMethodSignature*)frame->imethod->data_items [ip [1]];
+ is_void = csignature->ret->type == MONO_TYPE_VOID;
+ int param_count = csignature->param_count;
+ MonoDelegate *del = (MonoDelegate*) sp [-param_count - 1].data.o;
+ gboolean is_multicast = del->method == NULL;
+ InterpMethod *del_imethod = (InterpMethod*)del->interp_invoke_impl;
+
+ frame->ip = ip;
+ if (!del_imethod) {
+ if (is_multicast) {
+ error_init_reuse (error);
+ MonoMethod *invoke = mono_get_delegate_invoke_internal (del->object.vtable->klass);
+ del_imethod = mono_interp_get_imethod (del->object.vtable->domain, mono_marshal_get_delegate_invoke (invoke, del), error);
+ del->interp_invoke_impl = del_imethod;
+ mono_error_assert_ok (error);
+ } else if (!del->interp_method) {
+ // Not created from interpreted code
+ error_init_reuse (error);
+ g_assert (del->method);
+ del_imethod = mono_interp_get_imethod (del->object.vtable->domain, del->method, error);
+ del->interp_method = del_imethod;
+ del->interp_invoke_impl = del_imethod;
+ mono_error_assert_ok (error);
+ } else {
+ del_imethod = (InterpMethod*)del->interp_method;
+ if (del_imethod->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
+ error_init_reuse (error);
+ del_imethod = mono_interp_get_imethod (frame->imethod->domain, mono_marshal_get_native_wrapper (del_imethod->method, FALSE, FALSE), error);
+ mono_error_assert_ok (error);
+ del->interp_invoke_impl = del_imethod;
+ } else if (del_imethod->method->flags & METHOD_ATTRIBUTE_VIRTUAL && !del->target) {
+ // 'this' is passed dynamically, we need to recompute the target method
+ // with each call
+ del_imethod = get_virtual_method (del_imethod, sp [-param_count].data.o->vtable);
+ } else {
+ del->interp_invoke_impl = del_imethod;
+ }
+ }
+ }
+ cmethod = del_imethod;
+ retval = sp;
+ sp->data.p = vt_sp;
+ sp -= param_count + 1;
+ if (!is_multicast) {
+ if (cmethod->param_count == param_count + 1) {
+ // Target method is static but the delegate has a target object. We handle
+ // this separately from the case below, because, for these calls, the instance
+ // is allowed to be null.
+ sp [0].data.o = del->target;
+ } else if (del->target) {
+ MonoObject *this_arg = del->target;
+
+ // replace the MonoDelegate* on the stack with 'this' pointer
+ if (m_class_is_valuetype (this_arg->vtable->klass)) {
+ gpointer unboxed = mono_object_unbox_internal (this_arg);
+ sp [0].data.p = unboxed;
+ } else {
+ sp [0].data.o = this_arg;
+ }
+ } else {
+ // skip the delegate pointer for static calls
+ // FIXME we could avoid memmove
+ memmove (sp, sp + 1, param_count * sizeof (stackval));
+ }
+ }
+ ip += 2;
+
+ goto call;
+ }
MINT_IN_CASE(MINT_CALLI) {
MonoMethodSignature *csignature;
OPDEF(MINT_VCALLVIRT, "vcallvirt", 3, VarPop, Push0, MintOpMethodToken)
OPDEF(MINT_CALLVIRT_FAST, "callvirt.fast", 3, VarPop, Push1, MintOpMethodToken)
OPDEF(MINT_VCALLVIRT_FAST, "vcallvirt.fast", 3, VarPop, Push0, MintOpMethodToken)
+OPDEF(MINT_CALL_DELEGATE, "call.delegate", 2, VarPop, VarPush, MintOpMethodToken)
OPDEF(MINT_CALLI, "calli", 2, VarPop, VarPush, MintOpMethodToken)
OPDEF(MINT_CALLI_NAT, "calli.nat", 3, VarPop, VarPush, MintOpMethodToken)
OPDEF(MINT_CALLI_NAT_FAST, "calli.nat.fast", 4, VarPop, VarPush, MintOpMethodToken)
int native = 0;
int is_void = 0;
int need_null_check = is_virtual;
+ gboolean is_delegate_invoke = FALSE;
guint32 token = read32 (td->ip + 1);
/* We need to convert delegate invoke to a indirect call on the interp_invoke_impl field */
if (target_method && m_class_get_parent (target_method->klass) == mono_defaults.multicastdelegate_class) {
const char *name = target_method->name;
- if (*name == 'I' && (strcmp (name, "Invoke") == 0)) {
- calli = TRUE;
- interp_add_ins (td, MINT_LD_DELEGATE_INVOKE_IMPL);
- td->last_ins->data [0] = csignature->param_count + 1;
- PUSH_SIMPLE_TYPE (td, STACK_TYPE_I);
- }
+ if (*name == 'I' && (strcmp (name, "Invoke") == 0))
+ is_delegate_invoke = TRUE;
}
/* Pop the function pointer */
td->last_ins->data [1] = get_data_item_index (td, mono_method_signature_internal (target_method));
}
#endif
- } else if (!calli && !is_virtual && mono_interp_jit_call_supported (target_method, csignature)) {
+ } else if (!calli && !is_delegate_invoke && !is_virtual && mono_interp_jit_call_supported (target_method, csignature)) {
interp_add_ins (td, MINT_JIT_CALL);
td->last_ins->data [0] = get_data_item_index (td, (void *)mono_interp_get_imethod (domain, target_method, error));
mono_error_assert_ok (error);
#endif
if (csignature->call_convention == MONO_CALL_VARARG)
interp_add_ins (td, MINT_CALL_VARARG);
+ else if (is_delegate_invoke)
+ interp_add_ins (td, MINT_CALL_DELEGATE);
else if (calli)
interp_add_ins (td, native ? ((op != -1) ? MINT_CALLI_NAT_FAST : MINT_CALLI_NAT) : MINT_CALLI);
else if (is_virtual && !mono_class_is_marshalbyref (target_method->klass))
else
interp_add_ins (td, is_void ? MINT_VCALL : MINT_CALL);
- if (calli) {
+ if (is_delegate_invoke) {
+ td->last_ins->data [0] = get_data_item_index (td, (void *)csignature);
+ } else if (calli) {
td->last_ins->data [0] = get_data_item_index (td, (void *)csignature);
if (op != -1) {
td->last_ins->data[1] = op;
break;
}
#endif
+ case MINT_CALL_DELEGATE: {
+ MonoMethodSignature *csignature = (MonoMethodSignature*) td->data_items [ins->data [0]];
+ *pop = csignature->param_count + 1;
+ *push = csignature->ret->type != MONO_TYPE_VOID;
+ break;
+ }
case MINT_CALLI:
case MINT_CALLI_NAT:
case MINT_CALLI_NAT_FAST: {