g_free (pair);
}
-static MonoMethodSignature*
-sig_to_rgctx_sig (MonoMethodSignature *sig)
-{
- // FIXME: memory allocation
- MonoMethodSignature *res;
- int i;
-
- res = (MonoMethodSignature *)g_malloc (MONO_SIZEOF_METHOD_SIGNATURE + (sig->param_count + 1) * sizeof (MonoType*));
- memcpy (res, sig, MONO_SIZEOF_METHOD_SIGNATURE);
- res->param_count = sig->param_count + 1;
- for (i = 0; i < sig->param_count; ++i)
- res->params [i] = sig->params [i];
- res->params [sig->param_count] = &mono_defaults.int_class->byval_arg;
- return res;
-}
-
MonoMethod *
mono_marshal_get_delegate_invoke_internal (MonoMethod *method, gboolean callvirt, gboolean static_method_with_first_arg_bound, MonoMethod *target_method)
{
SignaturePointerPair key;
SignaturePointerPair *new_key;
int local_i, local_len, local_delegates, local_d, local_target, local_res;
- int pos0, pos1, pos2, pos3, pos4;
+ int pos0, pos1, pos2;
char *name;
MonoClass *target_class = NULL;
gboolean closed_over_null = FALSE;
// FIXME:
mono_mb_emit_exception_full (mb, "System", "NotImplementedException", "");
} else {
- MonoMethodSignature *rgctx_sig;
-
- // FIXME: Support this for the other cases as well
- mono_mb_emit_ldarg (mb, 0);
- mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoDelegate, rgctx));
- mono_mb_emit_byte (mb, CEE_LDIND_I);
- pos3 = mono_mb_emit_branch (mb, CEE_BRFALSE);
-
- /* Rgctx case */
- rgctx_sig = sig_to_rgctx_sig (sig);
-
mono_mb_emit_ldloc (mb, local_target);
for (i = 0; i < sig->param_count; ++i)
mono_mb_emit_ldarg (mb, i + 1);
mono_mb_emit_ldarg (mb, 0);
mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr));
mono_mb_emit_byte (mb, CEE_LDIND_I);
- mono_mb_emit_op (mb, CEE_CALLI, rgctx_sig);
- pos4 = mono_mb_emit_branch (mb, CEE_BR);
-
- /* Non-rgctx case */
- mono_mb_patch_branch (mb, pos3);
- mono_mb_emit_ldloc (mb, local_target);
- for (i = 0; i < sig->param_count; ++i)
- mono_mb_emit_ldarg (mb, i + 1);
- mono_mb_emit_ldarg (mb, 0);
- mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr));
- mono_mb_emit_byte (mb, CEE_LDIND_I );
- mono_mb_emit_op (mb, CEE_CALLI, sig);
-
- mono_mb_patch_branch (mb, pos4);
-
+ mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
+ mono_mb_emit_op (mb, CEE_MONO_CALLI_EXTRA_ARG, sig);
mono_mb_emit_byte (mb, CEE_RET);
}
mono_mb_emit_op (mb, CEE_CALL, target_method);
}
} else {
- MonoMethodSignature *rgctx_sig;
-
- mono_mb_emit_ldarg (mb, 0);
- mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoDelegate, rgctx));
- mono_mb_emit_byte (mb, CEE_LDIND_I);
- pos3 = mono_mb_emit_branch (mb, CEE_BRFALSE);
-
- /* Rgctx case */
- rgctx_sig = sig_to_rgctx_sig (invoke_sig);
-
if (static_method_with_first_arg_bound) {
mono_mb_emit_ldloc (mb, local_target);
if (!MONO_TYPE_IS_REFERENCE (invoke_sig->params[0]))
mono_mb_emit_ldarg (mb, 0);
mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr));
mono_mb_emit_byte (mb, CEE_LDIND_I);
- mono_mb_emit_op (mb, CEE_CALLI, rgctx_sig);
- pos4 = mono_mb_emit_branch (mb, CEE_BR);
-
- /* Non-rgctx case */
- mono_mb_patch_branch (mb, pos3);
- if (static_method_with_first_arg_bound) {
- mono_mb_emit_ldloc (mb, local_target);
- if (!MONO_TYPE_IS_REFERENCE (invoke_sig->params[0]))
- mono_mb_emit_op (mb, CEE_UNBOX_ANY, mono_class_from_mono_type (invoke_sig->params[0]));
- }
- for (i = 0; i < sig->param_count; ++i)
- mono_mb_emit_ldarg (mb, i + 1);
- mono_mb_emit_ldarg (mb, 0);
- mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr));
- mono_mb_emit_byte (mb, CEE_LDIND_I);
- mono_mb_emit_op (mb, CEE_CALLI, invoke_sig);
-
- mono_mb_patch_branch (mb, pos4);
+ mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
+ mono_mb_emit_op (mb, CEE_MONO_CALLI_EXTRA_ARG, invoke_sig);
}
mono_mb_emit_byte (mb, CEE_RET);
ip += 2;
break;
}
+ case CEE_MONO_CALLI_EXTRA_ARG: {
+ MonoInst *addr;
+ MonoMethodSignature *fsig;
+ MonoInst *arg;
+
+ /*
+ * This is the same as CEE_CALLI, but passes an additional argument
+ * to the called method in llvmonly mode.
+ * This is only used by delegate invoke wrappers to call the
+ * actual delegate method.
+ */
+ g_assert (method->wrapper_type == MONO_WRAPPER_DELEGATE_INVOKE);
+
+ CHECK_OPSIZE (6);
+ token = read32 (ip + 2);
+
+ ins = NULL;
+
+ cmethod = NULL;
+ CHECK_STACK (1);
+ --sp;
+ addr = *sp;
+ fsig = mini_get_signature (method, token, generic_context);
+
+ n = fsig->param_count + fsig->hasthis + 1;
+
+ CHECK_STACK (n);
+
+ sp -= n;
+ arg = sp [n - 1];
+
+ if (cfg->llvm_only) {
+ if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) {
+ MonoInst *callee = addr;
+
+ GSHAREDVT_FAILURE (*ip);
+
+ addr = emit_get_rgctx_sig (cfg, context_used,
+ fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
+ ins = emit_extra_arg_calli (cfg, fsig, sp, arg->dreg, callee);
+ } else {
+ ins = emit_extra_arg_calli (cfg, fsig, sp, arg->dreg, addr);
+ }
+ } else {
+ /* Same as CEE_CALLI */
+ if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) {
+ /*
+ * We pass the address to the gsharedvt trampoline in the rgctx reg
+ */
+ MonoInst *callee = addr;
+
+ addr = emit_get_rgctx_sig (cfg, context_used,
+ fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
+ ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, callee);
+ } else {
+ ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
+ }
+ }
+
+ if (!MONO_TYPE_IS_VOID (fsig->ret))
+ *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
+
+ CHECK_CFG_EXCEPTION;
+
+ ip += 6;
+ ins_flag = 0;
+ constrained_class = NULL;
+ break;
+ }
default:
g_error ("opcode 0x%02x 0x%02x not handled", MONO_CUSTOM_PREFIX, ip [1]);
break;