From: Zoltan Varga Date: Mon, 9 Nov 2009 01:44:40 +0000 (-0000) Subject: 2009-11-09 Zoltan Varga X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=commitdiff_plain;h=2dca3e8c65bb476a1050615df17d4605724133b9;p=mono.git 2009-11-09 Zoltan Varga * mini-arm.c (mono_arch_emit_prolog): Implement support for varargs. * mini-ops.h: Add documentation for the OP_ARGLIST opcode. svn path=/trunk/mono/; revision=145697 --- diff --git a/mono/mini/ChangeLog b/mono/mini/ChangeLog index 43643ff1912..09efc89f6f9 100644 --- a/mono/mini/ChangeLog +++ b/mono/mini/ChangeLog @@ -1,3 +1,9 @@ +2009-11-09 Zoltan Varga + + * mini-arm.c (mono_arch_emit_prolog): Implement support for varargs. + + * mini-ops.h: Add documentation for the OP_ARGLIST opcode. + 2009-11-08 Zoltan Varga * mini-arm.c: Compute the stack space used by arguments using diff --git a/mono/mini/mini-arm.c b/mono/mini/mini-arm.c index f331d2961f5..40949a3355f 100644 --- a/mono/mini/mini-arm.c +++ b/mono/mini/mini-arm.c @@ -83,6 +83,27 @@ int mono_exc_esp_offset = 0; #define ADD_LR_PC_4 ((ARMCOND_AL << ARMCOND_SHIFT) | (1 << 25) | (1 << 23) | (ARMREG_PC << 16) | (ARMREG_LR << 12) | 4) #define MOV_LR_PC ((ARMCOND_AL << ARMCOND_SHIFT) | (1 << 24) | (0xa << 20) | (ARMREG_LR << 12) | ARMREG_PC) #define DEBUG_IMT 0 + +/* A variant of ARM_LDR_IMM which can handle large offsets */ +#define ARM_LDR_IMM_GENERAL(code, dreg, basereg, offset, scratch_reg) do { \ + if (arm_is_imm12 ((offset))) { \ + ARM_LDR_IMM (code, (dreg), (basereg), (offset)); \ + } else { \ + g_assert ((scratch_reg) != (basereg)); \ + code = mono_arm_emit_load_imm (code, (scratch_reg), (offset)); \ + ARM_LDR_REG_REG (code, (dreg), (basereg), (scratch_reg)); \ + } \ + } while (0) + +#define ARM_STR_IMM_GENERAL(code, dreg, basereg, offset, scratch_reg) do { \ + if (arm_is_imm12 ((offset))) { \ + ARM_STR_IMM (code, (dreg), (basereg), (offset)); \ + } else { \ + g_assert ((scratch_reg) != (basereg)); \ + code = mono_arm_emit_load_imm (code, (scratch_reg), (offset)); \ + ARM_STR_REG_REG (code, (dreg), (basereg), (scratch_reg)); \ + } \ + } while (0) const char* mono_arch_regname (int reg) @@ -831,13 +852,13 @@ get_call_info (MonoMemPool *mp, MonoMethodSignature *sig, gboolean is_pinvoke) DEBUG(printf("params: %d\n", sig->param_count)); for (i = 0; i < sig->param_count; ++i) { if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) { - /* Prevent implicit arguments and sig_cookie from + /* Prevent implicit arguments and sig_cookie from being passed in registers */ - gr = ARMREG_R3 + 1; - /* Emit the signature cookie just before the implicit arguments */ - add_general (&gr, &stack_size, &cinfo->sig_cookie, TRUE); - } - DEBUG(printf("param %d: ", i)); + gr = ARMREG_R3 + 1; + /* Emit the signature cookie just before the implicit arguments */ + add_general (&gr, &stack_size, &cinfo->sig_cookie, TRUE); + } + DEBUG(printf("param %d: ", i)); if (sig->params [i]->byref) { DEBUG(printf("byref\n")); add_general (&gr, &stack_size, cinfo->args + n, TRUE); @@ -949,6 +970,15 @@ get_call_info (MonoMemPool *mp, MonoMethodSignature *sig, gboolean is_pinvoke) } } + /* Handle the case where there are no implicit arguments */ + if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) { + /* Prevent implicit arguments and sig_cookie from + being passed in registers */ + gr = ARMREG_R3 + 1; + /* Emit the signature cookie just before the implicit arguments */ + add_general (&gr, &stack_size, &cinfo->sig_cookie, TRUE); + } + { simpletype = mini_type_get_underlying_type (NULL, sig->ret); switch (simpletype->type) { @@ -1095,11 +1125,6 @@ mono_arch_allocate_vars (MonoCompile *cfg) offset += 8; /* the MonoLMF structure is stored just below the stack pointer */ - - if (sig->call_convention == MONO_CALL_VARARG) { - cfg->sig_cookie = 0; - } - if (MONO_TYPE_ISSTRUCT (sig->ret)) { if (cinfo->ret.storage == RegTypeStructByVal) { cfg->ret->opcode = OP_REGOFFSET; @@ -1120,8 +1145,6 @@ mono_arch_allocate_vars (MonoCompile *cfg) } } offset += sizeof(gpointer); - if (sig->call_convention == MONO_CALL_VARARG) - cfg->sig_cookie += sizeof (gpointer); } curinst = cfg->locals_start; @@ -1164,14 +1187,24 @@ mono_arch_allocate_vars (MonoCompile *cfg) offset &= ~(sizeof (gpointer) - 1); inst->inst_offset = offset; offset += sizeof (gpointer); - if (sig->call_convention == MONO_CALL_VARARG) - cfg->sig_cookie += sizeof (gpointer); } curinst++; } + if (sig->call_convention == MONO_CALL_VARARG) { + size = 4; + align = 4; + + /* Allocate a local slot to hold the sig cookie address */ + offset += align - 1; + offset &= ~(align - 1); + cfg->sig_cookie = offset; + offset += size; + } + for (i = 0; i < sig->param_count; ++i) { inst = cfg->args [curinst]; + if (inst->opcode != OP_REGVAR) { inst->opcode = OP_REGOFFSET; inst->inst_basereg = frame_reg; @@ -1188,8 +1221,6 @@ mono_arch_allocate_vars (MonoCompile *cfg) offset &= ~(align - 1); inst->inst_offset = offset; offset += size; - if ((sig->call_convention == MONO_CALL_VARARG) && (i < sig->sentinelpos)) - cfg->sig_cookie += size; } curinst++; } @@ -1237,6 +1268,39 @@ mono_arch_create_vars (MonoCompile *cfg) } } +static void +emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo) +{ + MonoMethodSignature *tmp_sig; + MonoInst *sig_arg; + + if (call->tail_call) + NOT_IMPLEMENTED; + + /* FIXME: Add support for signature tokens to AOT */ + cfg->disable_aot = TRUE; + + g_assert (cinfo->sig_cookie.storage == RegTypeBase); + + /* + * 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->dreg = mono_alloc_ireg (cfg); + sig_arg->inst_p0 = tmp_sig; + MONO_ADD_INS (cfg->cbb, sig_arg); + + MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, ARMREG_SP, cinfo->sig_cookie.offset, sig_arg->dreg); +} + void mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call) { @@ -1261,8 +1325,8 @@ mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call) t = mini_type_get_underlying_type (NULL, t); if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) { - /* FIXME: */ - NOT_IMPLEMENTED; + /* Emit the signature cookie just before the implicit arguments */ + emit_sig_cookie (cfg, call, cinfo); } in = call->args [i]; @@ -1420,6 +1484,10 @@ mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call) } } + /* 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 (sig->ret && MONO_TYPE_ISSTRUCT (sig->ret)) { MonoInst *vtarg; @@ -3459,15 +3527,9 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) ARM_LDR_IMM (code, ARMREG_LR, ins->sreg1, 0); break; case OP_ARGLIST: { -#if ARM_PORT - if (ppc_is_imm16 (cfg->sig_cookie + cfg->stack_usage)) { - ppc_addi (code, ppc_r11, cfg->frame_reg, cfg->sig_cookie + cfg->stack_usage); - } else { - ppc_load (code, ppc_r11, cfg->sig_cookie + cfg->stack_usage); - ppc_add (code, ppc_r11, cfg->frame_reg, ppc_r11); - } - ppc_stw (code, ppc_r11, 0, ins->sreg1); -#endif + g_assert (cfg->sig_cookie < 128); + ARM_LDR_IMM (code, ARMREG_IP, cfg->frame_reg, cfg->sig_cookie); + ARM_STR_IMM (code, ARMREG_IP, ins->sreg1, 0); break; } case OP_FCALL: @@ -4423,6 +4485,19 @@ mono_arch_emit_prolog (MonoCompile *cfg) g_assert (arm_is_imm12 (inst->inst_offset)); ARM_STR_IMM (code, ainfo->reg, inst->inst_basereg, inst->inst_offset); } + + if (sig->call_convention == MONO_CALL_VARARG) { + ArgInfo *cookie = &cinfo->sig_cookie; + + /* Save the sig cookie address */ + g_assert (cookie->storage == RegTypeBase); + + g_assert (arm_is_imm12 (prev_sp_offset + cookie->offset)); + g_assert (arm_is_imm12 (cfg->sig_cookie)); + ARM_ADD_REG_IMM8 (code, ARMREG_IP, cfg->frame_reg, prev_sp_offset + cookie->offset); + ARM_STR_IMM (code, ARMREG_IP, cfg->frame_reg, cfg->sig_cookie); + } + for (i = 0; i < sig->param_count + sig->hasthis; ++i) { ArgInfo *ainfo = cinfo->args + i; inst = cfg->args [pos]; diff --git a/mono/mini/mini-ops.h b/mono/mini/mini-ops.h index b5b0ebb142e..0a6a08d9bb3 100644 --- a/mono/mini/mini-ops.h +++ b/mono/mini/mini-ops.h @@ -17,7 +17,6 @@ MINI_OP(OP_ICOMPARE_IMM, "icompare_imm", NONE, IREG, NONE) MINI_OP(OP_LCOMPARE_IMM, "lcompare_imm", NONE, LREG, NONE) MINI_OP(OP_LOCAL, "local", NONE, NONE, NONE) MINI_OP(OP_ARG, "arg", NONE, NONE, NONE) -MINI_OP(OP_ARGLIST, "oparglist", NONE, IREG, NONE) MINI_OP(OP_OUTARG_VT, "outarg_vt", NONE, VREG, NONE) MINI_OP(OP_OUTARG_VTRETADDR, "outarg_vtretaddr", IREG, NONE, NONE) MINI_OP(OP_SETRET, "setret", NONE, IREG, NONE) @@ -66,6 +65,23 @@ MINI_OP(OP_SWITCH, "switch", NONE, IREG, NONE) MINI_OP(OP_THROW, "throw", NONE, IREG, NONE) MINI_OP(OP_RETHROW, "rethrow", NONE, IREG, NONE) +/* + * Vararg calls are implemented as follows: + * - the caller emits a hidden argument just before the varargs argument. this + * 'signature cookie' argument contains the signature describing the the call. + * - all implicit arguments are passed in memory right after the signature cookie, i.e. + * the stack will look like this: + * + * .. + * + * + * - the OP_ARGLIST opcode in the callee computes the address of the sig cookie argument + * on the stack and saves it into its sreg1. + * - mono_ArgIterator_Setup receives this value and uses it to find the signature and + * the arguments. + */ +MINI_OP(OP_ARGLIST, "oparglist", NONE, IREG, NONE) + /* MONO_IS_STORE_MEMBASE depends on the order here */ MINI_OP(OP_STORE_MEMBASE_REG,"store_membase_reg", IREG, IREG, NONE) MINI_OP(OP_STOREI1_MEMBASE_REG, "storei1_membase_reg", IREG, IREG, NONE)