* src/vm/jit/arm/codegen.c (codegen_emit): Allow larger displacements for
[cacao.git] / src / vm / jit / arm / md.c
1 /* src/vm/jit/arm/md.c - machine dependent ARM functions
2
3    Copyright (C) 1996-2005, 2006, 2007, 2008
4    CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
5
6    This file is part of CACAO.
7
8    This program is free software; you can redistribute it and/or
9    modify it under the terms of the GNU General Public License as
10    published by the Free Software Foundation; either version 2, or (at
11    your option) any later version.
12
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16    General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21    02110-1301, USA.
22
23 */
24
25
26 #include "config.h"
27
28 #include <assert.h>
29 #include <stdint.h>
30
31 #include "vm/jit/arm/codegen.h"
32 #include "vm/jit/arm/md.h"
33 #include "vm/jit/arm/md-abi.h"
34
35
36 /* md_init *********************************************************************
37
38    Do some machine dependent initialization.
39
40 *******************************************************************************/
41
42 void md_init(void)
43 {
44         /* do nothing here */
45 }
46
47
48 /* md_jit_method_patch_address *************************************************
49
50    Gets the patch address of the currently compiled method. The offset
51    is extracted from the load instruction(s) before the jump and added
52    to the right base address (PV or REG_METHODPTR).
53
54    Machine code:
55
56    e51cc040    ldr   ip, [ip, #-64]
57    e1a0e00f    mov   lr, pc
58    e1a0f00c    mov   pc, ip
59
60    or
61
62    e590b000    ldr   fp, [r0]
63    e59bc004    ldr   ip, [fp, #4]
64    e1a0e00f    mov   lr, pc
65    e1a0f00c    mov   pc, ip
66
67    or
68
69    e590b000    ldr      fp, [r0]
70    e28bca01    add      ip, fp, #4096   ; 0x1000
71    e59cc004    ldr      ip, [ip, #4]
72    e1a0e00f    mov      lr, pc
73    e1a0f00c    mov      pc, ip
74
75    How we find out the patching address to store new method pointer:
76     - loaded IP with LDR IP,[METHODPTR]?
77         yes=INVOKEVIRTUAL or INVOKEINTERFACE (things are easy!)
78     - loaded IP from data segment
79         yes=INVOKESTATIC or INVOKESPECIAL (things are complicated)
80         recompute pointer to data segment, maybe larger offset 
81
82 *******************************************************************************/
83
84 void *md_jit_method_patch_address(void *pv, void *ra, void *mptr)
85 {
86         uint32_t *pc;
87         uint32_t  mcode;
88         int32_t   disp;
89         void     *pa;                       /* patch address                      */
90
91         /* Go back to the actual load instruction. */
92
93         pc = ((uint32_t *) ra) - 3;
94
95         /* Get first instruction word on current PC. */
96
97         mcode = pc[0];
98
99         /* Sanity check: Are we inside jit code? */
100
101         assert(pc[1] == 0xe1a0e00f /*MOV LR,PC*/);
102         assert(pc[2] == 0xe1a0f00c /*MOV PC,IP*/);
103
104         /* Sanity check: We unconditionally loaded a word into REG_PV? */
105
106         assert ((mcode & 0xff70f000) == 0xe510c000);
107
108         /* Get load displacement. */
109
110         disp = (int32_t) (mcode & 0x0fff);
111
112         /* Case: We loaded from base REG_PV with negative displacement. */
113
114         if (M_MEM_GET_Rbase(mcode) == REG_PV && (mcode & 0x00800000) == 0) {
115                 /* We loaded from data segment, displacement can be larger. */
116
117                 mcode = pc[-1];
118
119                 /* check for "SUB IP, IP, #??, ROTL 12" */
120
121                 if ((mcode & 0xffffff00) == 0xe24cca00)
122                         disp += (int32_t) ((mcode & 0x00ff) << 12);
123
124                 /* and get the final data segment address */
125
126                 pa = ((uint8_t *) pv) - disp;
127         }
128
129         /* Case: We loaded from base REG_METHODPTR with positive displacement. */
130
131         else if (M_MEM_GET_Rbase(mcode) == REG_METHODPTR && (mcode & 0x00800000) == 0x00800000) {
132                 /* return NULL if no mptr was specified (used for replacement) */
133
134                 if (mptr == NULL)
135                         return NULL;
136
137                 /* we loaded from REG_METHODPTR */
138
139                 pa = ((uint8_t *) mptr) + disp;
140         }
141
142         /* Case: We loaded from base REG_PV with positive offset. */
143
144         else if (M_MEM_GET_Rbase(mcode) == REG_PV && (mcode & 0x00800000) == 0x00800000) {
145                 /* We loaded from REG_METHODPTR with a larger displacement */
146
147                 mcode = pc[-1];
148
149                 /* check for "ADD IP, FP, #??, ROTL 12" */
150
151                 if ((mcode & 0xffffff00) == 0xe28bca00)
152                         disp += (int32_t) ((mcode & 0x00ff) << 12);
153                 else
154                         vm_abort_disassemble(pc - 1, 4, "md_jit_method_patch_address: unknown instruction %x", mcode);
155
156                 /* we loaded from REG_METHODPTR */
157
158                 pa = ((uint8_t *) mptr) + disp;
159         }
160
161         /* Case is not covered, something is severely wrong. */
162
163         else {
164                 vm_abort_disassemble(pc, 3, "md_jit_method_patch_address: unknown instruction %x", mcode);
165
166                 /* Keep compiler happy. */
167
168                 pa = NULL;
169         }
170
171         return pa;
172 }
173
174
175 /**
176  * Patch the given replacement point.
177  */
178 #if defined(ENABLE_REPLACEMENT)
179 void md_patch_replacement_point(u1 *pc, u1 *savedmcode, bool revert)
180 {
181         vm_abort("md_patch_replacement_point: IMPLEMENT ME!");
182 }
183 #endif
184
185
186 /*
187  * These are local overrides for various environment variables in Emacs.
188  * Please do not remove this and leave it at the end of the file, where
189  * Emacs will automagically detect them.
190  * ---------------------------------------------------------------------
191  * Local variables:
192  * mode: c
193  * indent-tabs-mode: t
194  * c-basic-offset: 4
195  * tab-width: 4
196  * End:
197  * vim:noexpandtab:sw=4:ts=4:
198  */