-
- guint8 *buf, *code = NULL;
- int i, offset;
-
- if(!code) {
- /* Now we'll create in 'buf' the S/390 trampoline code. This
- is the trampoline code common to all methods */
-
- code = buf = g_malloc(512);
-
- /*-----------------------------------------------------------
- STEP 0: First create a non-standard function prologue with a
- stack size big enough to save our registers.
- -----------------------------------------------------------*/
-
- s390_stmg (buf, s390_r6, s390_r14, STK_BASE, S390_REG_SAVE_OFFSET);
- s390_lgr (buf, s390_r11, s390_r15);
- s390_aghi (buf, STK_BASE, -CREATE_STACK_SIZE);
- s390_stg (buf, s390_r11, 0, STK_BASE, 0);
- s390_stmg (buf, s390_r2, s390_r5, STK_BASE, CREATE_GR_OFFSET);
-
- /* Save the FP registers */
- offset = CREATE_FP_OFFSET;
- for (i = s390_f0; i <= s390_f15; ++i) {
- s390_std (buf, i, 0, STK_BASE, offset);
- offset += 8;
- }
-
- /*----------------------------------------------------------
- STEP 1: call 'mono_get_lmf_addr()' to get the address of our
- LMF. We'll need to restore it after the call to
- 's390_magic_trampoline' and before the call to the native
- method.
- ----------------------------------------------------------*/
-
- s390_basr (buf, s390_r13, 0);
- s390_j (buf, 6);
- s390_llong(buf, mono_get_lmf_addr);
- s390_lg (buf, s390_r1, 0, s390_r13, 4);
- s390_basr (buf, s390_r14, s390_r1);
-
- /*----------------------------------------------------------
- STEP 2: call 's390_magic_trampoline()', who will compile the
- code and fix the method vtable entry for us
- ----------------------------------------------------------*/
-
- /* Set arguments */
-
- /* Arg 1: MonoMethod *method. It was put in r11 by the
- method-specific trampoline code, and then saved before the call
- to mono_get_lmf_addr()'. Restore r13, by the way :-) */
- s390_lg (buf, s390_r2, 0, s390_r11, METHOD_SAVE_OFFSET);
-
- /* Arg 2: code (next address to the instruction that called us) */
- if (tramp_type == MONO_TRAMPOLINE_JUMP) {
- s390_lghi (buf, s390_r3, 0);
- } else {
- s390_lg (buf, s390_r3, 0, s390_r11, S390_RET_ADDR_OFFSET);
- }
-
- /* Arg 3: stack pointer */
- s390_lgr (buf, s390_r4, STK_BASE);
-
- /* Calculate call address and call
- 's390_magic_trampoline'. Return value will be in r2 */
- s390_basr (buf, s390_r13, 0);
- s390_j (buf, 6);
- if (tramp_type == MONO_TRAMPOLINE_CLASS_INIT) {
- s390_llong(buf, s390_class_init_trampoline);
- } else {
- s390_llong(buf, s390_magic_trampoline);
- }
- s390_lg (buf, s390_r1, 0, s390_r13, 4);
- s390_basr (buf, s390_r14, s390_r1);
-
- /* OK, code address is now on r2. Move it to r1, so that we
- can restore r2 and use it from r1 later */
- s390_lgr (buf, s390_r1, s390_r2);
-
-
- /*----------------------------------------------------------
- STEP 3: Restore the LMF
- ----------------------------------------------------------*/
-
- /* XXX Do it !!! */
-
- /*----------------------------------------------------------
- STEP 4: call the compiled method
- ----------------------------------------------------------*/
-
- /* Restore registers */
-
- s390_lmg (buf, s390_r2, s390_r5, STK_BASE, CREATE_GR_OFFSET);
-
- /* Restore the FP registers */
- offset = CREATE_FP_OFFSET;
- for (i = s390_f0; i <= s390_f15; ++i) {
- s390_ld (buf, i, 0, STK_BASE, offset);
- offset += 8;
- }
-
- /* Restore stack pointer and jump to the code -
- R14 contains the return address to our caller */
- s390_lgr (buf, STK_BASE, s390_r11);
- s390_lmg (buf, s390_r6, s390_r14, STK_BASE, S390_REG_SAVE_OFFSET);
- s390_br (buf, s390_r1);
-
- /* Flush instruction cache, since we've generated code */
- mono_arch_flush_icache (code, buf - code);
-
- /* Sanity check */
- g_assert ((buf - code) <= 512);
- }
-
- return code;
+ int reg, lkReg;
+ guchar* base;
+ unsigned short opcode;
+ char *sp;
+
+ // We are passed sp instead of the register array
+ sp = (char*)regs;
+
+ *displacement = 0;
+
+ opcode = *((unsigned short *) (code - 6));
+ if (opcode == 0xc0e5)
+ /* This is the 'brasl' instruction */
+ return NULL;
+
+ /*-----------------------------------*/
+ /* This is a bras r14,Rz instruction */
+ /* If it's preceded by a LG Rx,d(Ry) */
+ /* If Rz == 1 then this is virtual */
+ /* call. */
+ /*-----------------------------------*/
+ code -= 6;
+
+ /*-----------------------------------*/
+ /* If call is preceded by LGR then */
+ /* there's nothing to patch */
+ /*-----------------------------------*/
+ if ((code[0] == 0xb9) &&
+ (code[1] == 0x04))
+ return NULL;
+
+ /*-----------------------------------*/
+ /* We back up until we're pointing at*/
+ /* the base/displacement portion of */
+ /* the LG instruction */
+ /*-----------------------------------*/
+ lkReg = code[5] & 0x0f;
+
+ /*-----------------------------------*/
+ /* The LG instruction has format: */
+ /* E3x0ylllhh04 - where: */
+ /* x = Rx; y = Ry; */
+ /* lll = low 12 bits of displacement */
+ /* hh = high 8 bits of displacement */
+ /*-----------------------------------*/
+ reg = code[0] >> 4;
+ *displacement = (code[2] << 12) +
+ ((code[0] & 0x0f) << 8) +
+ code[1];
+
+ if (reg > 5)
+ base = *((guchar **) (sp + S390_REG_SAVE_OFFSET +
+ sizeof(long)*(reg-6)));
+ else
+ base = *((guchar **) ((sp - CREATE_STACK_SIZE) +
+ CREATE_GR_OFFSET +
+ sizeof(long)*(reg-2)));
+ if (lkReg != 1)
+ /* Non virtual call */
+ return NULL;
+
+ return base;