-{
- MonoInst *arg;
- MonoMethodSignature *tmp_sig;
- MonoInst *sig_arg;
-
- /* FIXME: Add support for signature tokens to AOT */
- cfg->disable_aot = TRUE;
-
- g_assert (cinfo->sig_cookie.storage == ArgOnStack);
-
- /*
- * mono_ArgIterator_Setup assumes the signature cookie is
- * passed first and all the arguments which were before it are
- * passed on the stack after the signature. So compensate by
- * passing a different signature.
- */
- tmp_sig = mono_metadata_signature_dup (call->signature);
- tmp_sig->param_count -= call->signature->sentinelpos;
- tmp_sig->sentinelpos = 0;
- memcpy (tmp_sig->params, call->signature->params + call->signature->sentinelpos, tmp_sig->param_count * sizeof (MonoType*));
-
- MONO_INST_NEW (cfg, sig_arg, OP_ICONST);
- sig_arg->inst_p0 = tmp_sig;
-
- MONO_INST_NEW (cfg, arg, OP_OUTARG);
- arg->inst_left = sig_arg;
- arg->type = STACK_PTR;
-
- /* prepend, so they get reversed */
- arg->next = call->out_args;
- call->out_args = arg;
-}
-
-/*
- * take the arguments and generate the arch-specific
- * instructions to properly call the function in call.
- * This includes pushing, moving arguments to the right register
- * etc.
- */
-MonoCallInst*
-mono_arch_call_opcode (MonoCompile *cfg, MonoBasicBlock* bb, MonoCallInst *call, int is_virtual) {
- MonoInst *arg, *in;
- MonoMethodSignature *sig;
- int i, n, stack_size;
- CallInfo *cinfo;
- ArgInfo *ainfo;
-
- stack_size = 0;
-
- sig = call->signature;
- n = sig->param_count + sig->hasthis;
-
- cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig, sig->pinvoke);
-
- if (cfg->method->save_lmf) {
- MONO_INST_NEW (cfg, arg, OP_AMD64_SAVE_SP_TO_LMF);
- arg->next = call->out_args;
- call->out_args = arg;
- }
-
- for (i = 0; i < n; ++i) {
- ainfo = cinfo->args + i;
-
- if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
- /* Emit the signature cookie just before the implicit arguments */
- emit_sig_cookie (cfg, call, cinfo);
- }
-
- if (is_virtual && i == 0) {
- /* the argument will be attached to the call instruction */
- in = call->args [i];
- } else {
- MONO_INST_NEW (cfg, arg, OP_OUTARG);
- in = call->args [i];
- arg->cil_code = in->cil_code;
- arg->inst_left = in;
- arg->type = in->type;
- /* prepend, so they get reversed */
- arg->next = call->out_args;
- call->out_args = arg;
-#if 0
- if (!cinfo->stack_usage)
- /* Keep the assignments to the arg registers in order if possible */
- MONO_INST_LIST_ADD_TAIL (&arg->node, &call->out_args);
- else
- MONO_INST_LIST_ADD (&arg->node, &call->out_args);
-#endif
-
- if ((i >= sig->hasthis) && (MONO_TYPE_ISSTRUCT(sig->params [i - sig->hasthis]))) {
- guint32 align;
- guint32 size;
-
- if (sig->params [i - sig->hasthis]->type == MONO_TYPE_TYPEDBYREF) {
- size = sizeof (MonoTypedRef);
- align = sizeof (gpointer);
- }
- else
- if (sig->pinvoke)
- size = mono_type_native_stack_size (&in->klass->byval_arg, &align);
- else {
- /*
- * Other backends use mini_type_stack_size (), but that
- * aligns the size to 8, which is larger than the size of
- * the source, leading to reads of invalid memory if the
- * source is at the end of address space.
- */
- size = mono_class_value_size (in->klass, &align);
- }
- if (ainfo->storage == ArgValuetypeInReg) {
- if (ainfo->pair_storage [1] == ArgNone) {
- MonoInst *load;
-
- /* Simpler case */
-
- MONO_INST_NEW (cfg, load, arg_storage_to_ldind (ainfo->pair_storage [0]));
- load->inst_left = in;
-
- add_outarg_reg (cfg, call, arg, ainfo->pair_storage [0], ainfo->pair_regs [0], load);
- }
- else {
- /* Trees can't be shared so make a copy */
- MonoInst *vtaddr = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
- MonoInst *load, *load2, *offset_ins;
-
- /* Reg1 */
- MONO_INST_NEW (cfg, load, CEE_LDIND_I);
- load->ssa_op = MONO_SSA_LOAD;
- load->inst_i0 = (cfg)->varinfo [vtaddr->inst_c0];
-
- NEW_ICONST (cfg, offset_ins, 0);
- MONO_INST_NEW (cfg, load2, CEE_ADD);
- load2->inst_left = load;
- load2->inst_right = offset_ins;
-
- MONO_INST_NEW (cfg, load, arg_storage_to_ldind (ainfo->pair_storage [0]));
- load->inst_left = load2;
-
- add_outarg_reg (cfg, call, arg, ainfo->pair_storage [0], ainfo->pair_regs [0], load);
-
- /* Reg2 */
- MONO_INST_NEW (cfg, load, CEE_LDIND_I);
- load->ssa_op = MONO_SSA_LOAD;
- load->inst_i0 = (cfg)->varinfo [vtaddr->inst_c0];
-
- NEW_ICONST (cfg, offset_ins, 8);
- MONO_INST_NEW (cfg, load2, CEE_ADD);
- load2->inst_left = load;
- load2->inst_right = offset_ins;
-
- MONO_INST_NEW (cfg, load, arg_storage_to_ldind (ainfo->pair_storage [1]));
- load->inst_left = load2;
-
- MONO_INST_NEW (cfg, arg, OP_OUTARG);
- arg->cil_code = in->cil_code;
- arg->type = in->type;
- /* prepend, so they get reversed */
- arg->next = call->out_args;
- call->out_args = arg;
-
- add_outarg_reg (cfg, call, arg, ainfo->pair_storage [1], ainfo->pair_regs [1], load);
-
- /* Prepend a copy inst */
- MONO_INST_NEW (cfg, arg, CEE_STIND_I);
- arg->cil_code = in->cil_code;
- arg->ssa_op = MONO_SSA_STORE;
- arg->inst_left = vtaddr;
- arg->inst_right = in;
- arg->type = in->type;
-
- /* prepend, so they get reversed */
- arg->next = call->out_args;
- call->out_args = arg;
- }
- }
- else if (ainfo->storage == ArgValuetypeAddrInIReg){
-
- /* Add a temp variable to the method*/
- MonoInst *load;
- MonoInst *vtaddr = mono_compile_create_var (cfg, &in->klass->byval_arg, OP_LOCAL);
-
- MONO_INST_NEW (cfg, load, OP_LDADDR);
- load->ssa_op = MONO_SSA_LOAD;
- load->inst_left = vtaddr;
-
- if (ainfo->pair_storage [0] == ArgInIReg) {
- /* Inserted after the copy. Load the address of the temp to the argument regster.*/
- arg->opcode = OP_OUTARG_REG;
- arg->inst_left = load;
- arg->inst_call = call;
- arg->backend.reg3 = ainfo->pair_regs [0];
- }
- else {
- /* Inserted after the copy. Load the address of the temp on the stack.*/
- arg->opcode = OP_OUTARG_VT;
- arg->inst_left = load;
- arg->type = STACK_PTR;
- arg->klass = mono_defaults.int_class;
- arg->backend.is_pinvoke = sig->pinvoke;
- arg->inst_imm = size;
- }
-
- /*Copy the argument to the temp variable.*/
- MONO_INST_NEW (cfg, load, OP_MEMCPY);
- load->backend.memcpy_args = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoMemcpyArgs));
- load->backend.memcpy_args->size = size;
- load->backend.memcpy_args->align = align;
- load->inst_left = (cfg)->varinfo [vtaddr->inst_c0];
- load->inst_right = in->inst_i0;
-
- // FIXME:
- g_assert_not_reached ();
- //MONO_INST_LIST_ADD (&load->node, &call->out_args);
- }
- else {
- arg->opcode = OP_OUTARG_VT;
- arg->klass = in->klass;
- arg->backend.is_pinvoke = sig->pinvoke;
- arg->inst_imm = size;
- }
- }
- else {
- switch (ainfo->storage) {
- case ArgInIReg:
- add_outarg_reg (cfg, call, arg, ainfo->storage, ainfo->reg, in);
- break;
- case ArgInFloatSSEReg:
- case ArgInDoubleSSEReg:
- add_outarg_reg (cfg, call, arg, ainfo->storage, ainfo->reg, in);
- break;
- case ArgOnStack:
- arg->opcode = OP_OUTARG;
- if (!sig->params [i - sig->hasthis]->byref) {
- if (sig->params [i - sig->hasthis]->type == MONO_TYPE_R4)
- arg->opcode = OP_OUTARG_R4;
- else
- if (sig->params [i - sig->hasthis]->type == MONO_TYPE_R8)
- arg->opcode = OP_OUTARG_R8;
- }
- break;
- default:
- g_assert_not_reached ();
- }
- }
- }
- }
-
- /* Handle the case where there are no implicit arguments */
- if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == sig->sentinelpos)) {
- emit_sig_cookie (cfg, call, cinfo);
- }
-
- if (cinfo->ret.storage == ArgValuetypeInReg) {
- /* This is needed by mono_arch_emit_this_vret_args () */
- if (!cfg->arch.vret_addr_loc) {
- cfg->arch.vret_addr_loc = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
- /* Prevent it from being register allocated or optimized away */
- ((MonoInst*)cfg->arch.vret_addr_loc)->flags |= MONO_INST_VOLATILE;
- }
- }
-
- if (cinfo->need_stack_align) {
- MONO_INST_NEW (cfg, arg, OP_AMD64_OUTARG_ALIGN_STACK);
- arg->inst_c0 = 8;
- /* prepend, so they get reversed */
- arg->next = call->out_args;
- call->out_args = arg;
- }
-
-#ifdef PLATFORM_WIN32
- /* Always reserve 32 bytes of stack space on Win64 */
- /*MONO_INST_NEW (cfg, arg, OP_AMD64_OUTARG_ALIGN_STACK);
- arg->inst_c0 = 32;
- MONO_INST_LIST_ADD_TAIL (&arg->node, &call->out_args);*/
- NOT_IMPLEMENTED;
-#endif
-
-#if 0
- if (cfg->method->save_lmf) {
- MONO_INST_NEW (cfg, arg, OP_AMD64_SAVE_SP_TO_LMF);
- MONO_INST_LIST_ADD_TAIL (&arg->node, &call->out_args);
- }
-#endif
-
- call->stack_usage = cinfo->stack_usage;
- cfg->param_area = MAX (cfg->param_area, call->stack_usage);
- cfg->flags |= MONO_CFG_HAS_CALLS;
-
- return call;
-}
-
-static void
-emit_sig_cookie2 (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo)