1 /* src/vm/jit/m68k/codegen.c
3 Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel,
4 C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
5 E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
6 J. Wenninger, Institut f. Computersprachen - TU Wien
8 This file is part of CACAO.
10 This program is free software; you can redistribute it and/or
11 modify it under the terms of the GNU General Public License as
12 published by the Free Software Foundation; either version 2, or (at
13 your option) any later version.
15 This program is distributed in the hope that it will be useful, but
16 WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
37 #include "vm/jit/m68k/codegen.h"
38 #include "vm/jit/m68k/emit.h"
40 #include "mm/memory.h"
41 #include "native/jni.h"
42 #include "native/localref.h"
43 #include "native/native.h"
45 #include "threads/lock-common.h"
47 #include "vm/builtin.h"
48 #include "vm/exceptions.h"
49 #include "vm/global.h"
50 #include "vm/stringlocal.h"
53 #include "vm/jit/asmpart.h"
54 #include "vm/jit/codegen-common.h"
55 #include "vm/jit/patcher-common.h"
56 #include "vm/jit/dseg.h"
57 #include "vm/jit/emit-common.h"
58 #include "vm/jit/jit.h"
59 #include "vm/jit/abi.h"
60 #include "vm/jit/parse.h"
61 #include "vm/jit/reg.h"
62 #include "vm/jit/replace.h"
63 #include "vm/jit/stacktrace.h"
64 #include "vm/jit/md.h"
66 #include "vmcore/loader.h"
67 #include "vmcore/options.h"
68 #include "vmcore/utf8.h"
71 bool codegen_emit(jitdata *jd)
77 s4 len, s1, s2, s3, d, disp;
82 methodinfo *lm; /* local methodinfo for ICMD_INVOKE* */
83 unresolved_method *um;
84 builtintable_entry *bte;
91 /* get required compiler data */
98 /* prevent compiler warnings */
106 /* save calle saved registers */
107 s4 savedregs_num = 0;
109 savedregs_num += (INT_SAV_CNT - rd->savintreguse);
110 savedregs_num += (ADR_SAV_CNT - rd->savadrreguse);
111 savedregs_num += (FLT_SAV_CNT - rd->savfltreguse);
113 cd->stackframesize = rd->memuse + savedregs_num;
115 /* we always add 2 stack slots.
116 * 1 word the lock word, which may be unused and resides @ rd->memuse * 8
117 * + 2 words to either save the return value for LOCK_monitor_exit @ rd->memuse * 8 + 8
118 * on the other hand we could use 2 words when a builtin returns a doulbe which are
119 * returned in %d0, %d1 and need to be stored onto the stack and read in used a fmovemd
120 * so we always _need_ at least 2 slots, and this keeps the code simple */
121 cd->stackframesize += 2;
123 cd->stackframesize *= 8; /* we use 8 byte stack slots */
126 #if defined(ENABLE_THREADS)
127 /* we need additional space to save argument of monitor_enter */
128 if (checksync && code_is_synchronized(code)) {
129 if (IS_2_WORD_TYPE(m->parseddesc->returntype.type)) {
130 cd->stackframesize += 2;
132 cd->stackframesize += 1;
138 /* create method header */
139 (void) dseg_add_unique_address(cd, code); /* CodeinfoPointer */
140 (void) dseg_add_unique_s4(cd, cd->stackframesize); /* FrameSize */
142 code->synchronizedoffset = rd->memuse * 8;
144 /* REMOVEME: We still need it for exception handling in assembler. */
146 if (code_is_leafmethod(code))
147 (void) dseg_add_unique_s4(cd, 1);
149 (void) dseg_add_unique_s4(cd, 0);
151 /* XXX we use the IntSave a split field for the adr now */
152 (void) dseg_add_unique_s4(cd, (ADR_SAV_CNT - rd->savadrreguse) << 16 | (INT_SAV_CNT - rd->savintreguse)); /* IntSave */
153 (void) dseg_add_unique_s4(cd, FLT_SAV_CNT - rd->savfltreguse); /* FltSave */
155 dseg_addlinenumbertablesize(cd);
157 #if defined(ENABLE_PROFILING)
162 emit_verbosecall_enter(jd);
164 /* create stack frame */
165 M_AADD_IMM(-(cd->stackframesize), REG_SP);
167 /* save used callee saved registers */
168 p = cd->stackframesize;
169 for (i=INT_SAV_CNT-1; i>=rd->savintreguse; --i) {
170 p-=8; M_IST(rd->savintregs[i], REG_SP, p);
172 for (i=ADR_SAV_CNT-1; i>=rd->savadrreguse; --i) {
173 p-=8; M_AST(rd->savadrregs[i], REG_SP, p);
175 #if !defined(ENABLE_SOFTFLOAT)
176 for (i=FLT_SAV_CNT-1; i>=rd->savfltreguse; --i) {
177 p-=8; M_FSTORE(rd->savfltregs[i], REG_SP, p);
180 assert(FLT_SAV_CNT == 0);
181 assert(rd->savfltreguse == 0);
183 /* take arguments out of stack frame */
185 for (p = 0, l = 0; p < md->paramcount; p++) {
186 t = md->paramtypes[p].type;
187 varindex = jd->local_map[l * 5 + t];
190 if (IS_2_WORD_TYPE(t)) /* increment local counter for 2 word types */
193 if (varindex == UNUSED)
198 s1 = md->params[p].regoff;
199 assert(md->params[p].inmemory); /* all args are on stack */
202 #if defined(ENABLE_SOFTFLOAT)
208 if (!IS_INMEMORY(var->flags)) { /* stack arg -> register */
209 if (IS_2_WORD_TYPE(t)) {
210 M_LLD(var->vv.regoff, REG_SP, cd->stackframesize + s1 + 4);
212 M_ILD(var->vv.regoff, REG_SP, cd->stackframesize + s1 + 4);
214 } else { /* stack arg -> spilled */
215 M_ILD(REG_ITMP1, REG_SP, cd->stackframesize + s1 + 4);
216 M_IST(REG_ITMP1, REG_SP, var->vv.regoff);
217 if (IS_2_WORD_TYPE(t)) {
218 M_ILD(REG_ITMP1, REG_SP, cd->stackframesize + s1 + 4 + 4);
219 M_IST(REG_ITMP1, REG_SP, var->vv.regoff + 4);
223 #if !defined(ENABLE_SOFTFLOAT)
226 if (!IS_INMEMORY(var->flags)) { /* stack-arg -> register */
227 if (IS_2_WORD_TYPE(t)) {
228 M_DLD(var->vv.regoff, REG_SP, cd->stackframesize + s1 + 4);
230 M_FLD(var->vv.regoff, REG_SP, cd->stackframesize + s1 + 4);
232 } else { /* stack-arg -> spilled */
233 if (IS_2_WORD_TYPE(t)) {
234 M_DLD(REG_FTMP1, REG_SP, cd->stackframesize + s1 + 4);
235 M_DST(REG_FTMP1, REG_SP, var->vv.regoff);
237 M_FLD(REG_FTMP1, REG_SP, cd->stackframesize + s1 + 4);
238 M_FST(REG_FTMP1, REG_SP, var->vv.regoff);
242 #endif /* SOFTFLOAT */
244 if (!IS_INMEMORY(var->flags)) { /* stack-arg -> register */
245 M_ALD(var->vv.regoff, REG_SP, cd->stackframesize + s1 + 4);
246 } else { /* stack-arg -> spilled */
247 M_ALD(REG_ATMP1, REG_SP, cd->stackframesize + s1 + 4);
248 M_AST(REG_ATMP1, REG_SP, var->vv.regoff);
253 } /* end for argument out of stack*/
255 #if defined(ENABLE_THREADS)
256 /* call lock_monitor_enter function */
257 if (checksync && code_is_synchronized(code)) {
258 if (m->flags & ACC_STATIC) {
259 M_AMOV_IMM((&m->class->object.header), REG_ATMP1);
261 /* for non-static case the first arg is the object */
262 M_ALD(REG_ATMP1, REG_SP, cd->stackframesize + 4);
265 M_TRAP(M68K_EXCEPTION_HARDWARE_NULLPOINTER);
268 M_AST(REG_ATMP1, REG_SP, rd->memuse * 8);
269 M_AST(REG_ATMP1, REG_SP, 0 * 4);
270 M_JSR_IMM(LOCK_monitor_enter);
276 /* create replacement points */
277 REPLACEMENT_POINTS_INIT(cd, jd);
279 /* foreach basic block */
280 for (bptr = jd->basicblocks; bptr != NULL; bptr = bptr->next) {
282 bptr->mpc = (s4) (cd->mcodeptr - cd->mcodebase);
284 if (bptr->flags >= BBREACHED) {
286 /* branch resolving */
287 codegen_resolve_branchrefs(cd, bptr);
289 /* handle replacement points */
290 REPLACEMENT_POINT_BLOCK_START(cd, bptr);
292 #if defined(ENABLE_PROFILING)
295 /* FIXME there are still some constrcuts to copy in here */
297 #if defined(ENABLE_LSRA)
301 /* copy interface registers to their destination */
307 var = VAR(bptr->invars[len]);
308 if ((len == bptr->indepth-1) && (bptr->type == BBTYPE_EXH)) {
309 d = codegen_reg_of_var(0, var, REG_ATMP1_XPTR);
310 M_ADRMOVE(REG_ATMP1_XPTR, d);
311 emit_store(jd, NULL, var, d);
314 assert((var->flags & INOUT));
318 /* walk through all instructions */
322 for (iptr = bptr->iinstr; len > 0; len--, iptr++) {
323 if (iptr->line != currentline) {
324 dseg_addlinenumber(cd, iptr->line);
325 currentline = iptr->line;
328 MCODECHECK(1024); /* 1kB should be enough */
331 case ICMD_NOP: /* ... ==> ... */
332 case ICMD_POP: /* ..., value ==> ... */
333 case ICMD_POP2: /* ..., value, value ==> ... */
336 case ICMD_INLINE_START:
338 REPLACEMENT_POINT_INLINE_START(cd, iptr);
341 case ICMD_INLINE_BODY:
343 REPLACEMENT_POINT_INLINE_BODY(cd, iptr);
344 dseg_addlinenumber_inline_start(cd, iptr);
345 dseg_addlinenumber(cd, iptr->line);
348 case ICMD_INLINE_END:
350 dseg_addlinenumber_inline_end(cd, iptr);
351 dseg_addlinenumber(cd, iptr->line);
354 case ICMD_CHECKNULL: /* ..., objectref ==> ..., objectref */
356 s1 = emit_load_s1(jd, iptr, REG_ITMP1);
357 assert(VAROP(iptr->s1)->type == TYPE_ADR);
358 emit_nullpointer_check(cd, iptr, s1);
362 /* CONST **************************************************************/
363 case ICMD_ICONST: /* ... ==> ..., constant */
364 d = codegen_reg_of_dst(jd, iptr, REG_ITMP1);
365 M_IMOV_IMM(iptr->sx.val.i, d);
366 emit_store_dst(jd, iptr, d);
369 case ICMD_LCONST: /* ... ==> ..., constant */
371 d = codegen_reg_of_dst(jd, iptr, REG_ITMP12_PACKED);
372 LCONST(iptr->sx.val.l, d);
373 emit_store_dst(jd, iptr, d);
376 case ICMD_FCONST: /* ... ==> ..., constant */
378 #if defined(ENABLE_SOFTFLOAT)
379 d = codegen_reg_of_dst(jd, iptr, REG_ITMP1);
380 M_IMOV_IMM(iptr->sx.val.i, d);
381 emit_store_dst(jd, iptr, d);
383 d = codegen_reg_of_dst(jd, iptr, REG_FTMP1);
384 FCONST(iptr->sx.val.i, d);
385 emit_store_dst(jd, iptr, d);
389 case ICMD_DCONST: /* ... ==> ..., constant */
391 #if defined(ENABLE_SOFTFLOAT)
392 d = codegen_reg_of_dst(jd, iptr, REG_ITMP12_PACKED);
393 LCONST(iptr->sx.val.l, d);
394 emit_store_dst(jd, iptr, d);
396 d = codegen_reg_of_dst(jd, iptr, REG_FTMP1);
397 disp = dseg_add_double(cd, iptr->sx.val.d);
398 M_AMOV_IMM(0, REG_ATMP1);
400 M_DLD(d, REG_ATMP1, disp);
401 emit_store_dst(jd, iptr, d);
406 /* some long operations *********************************************/
407 case ICMD_LADD: /* ..., val1, val2 ==> ..., val1 + val2 */
408 s1 = emit_load_s1_low(jd, iptr, REG_ITMP3);
409 s2 = emit_load_s2_low(jd, iptr, REG_ITMP1);
410 d = codegen_reg_of_dst(jd, iptr, REG_ITMP12_PACKED);
411 M_INTMOVE(s2, REG_ITMP1);
412 M_IADD(s1, REG_ITMP1); /* low word */
413 s1 = emit_load_s1_high(jd, iptr, REG_ITMP3);
414 s2 = emit_load_s2_high(jd, iptr, REG_ITMP2);
415 M_INTMOVE(s2, REG_ITMP2);
416 M_IADDX(s1, REG_ITMP2); /* high word */
417 emit_store_dst(jd, iptr, d);
420 case ICMD_LADDCONST: /* ..., value ==> ..., value + constant */
421 /* sx.val.l = constant */
422 s1 = emit_load_s1_low(jd, iptr, REG_ITMP1);
423 s2 = emit_load_s1_high(jd, iptr, REG_ITMP2);
424 d = codegen_reg_of_dst(jd, iptr, REG_ITMP12_PACKED);
426 M_IMOV_IMM(iptr->sx.val.l >> 32, REG_ITMP3);
428 s3 = iptr->sx.val.l & 0xffffffff;
429 M_INTMOVE(s1, REG_ITMP1);
430 M_IADD_IMM(s3, REG_ITMP1); /* lower word in REG_ITMP1 now */
432 M_IADDX(REG_ITMP3, REG_ITMP2); /* high word in REG_ITMP2 now */
433 M_LNGMOVE(REG_ITMP12_PACKED, d);
434 emit_store_dst(jd, iptr, d);
437 case ICMD_LSUB: /* ..., val1, val2 ==> ..., val1 - val2 */
438 s1 = emit_load_s1_low(jd, iptr, REG_ITMP1);
439 s2 = emit_load_s2_low(jd, iptr, REG_ITMP3);
440 d = codegen_reg_of_dst(jd, iptr, REG_ITMP12_PACKED);
441 M_INTMOVE(s1, REG_ITMP1);
442 M_ISUB(s2, REG_ITMP1); /* low word */
443 s1 = emit_load_s1_high(jd, iptr, REG_ITMP2);
444 s2 = emit_load_s2_high(jd, iptr, REG_ITMP3);
445 M_INTMOVE(s1, REG_ITMP2);
446 M_ISUBX(s2, REG_ITMP2); /* high word */
447 emit_store_dst(jd, iptr, d);
450 case ICMD_LSUBCONST: /* ..., value ==> ..., value - constant */
451 /* sx.val.l = constant */
452 s1 = emit_load_s1_low(jd, iptr, REG_ITMP1);
453 s2 = emit_load_s1_high(jd, iptr, REG_ITMP2);
454 d = codegen_reg_of_dst(jd, iptr, REG_ITMP12_PACKED);
456 M_IMOV_IMM( (-iptr->sx.val.l) >> 32, REG_ITMP3);
458 s3 = (-iptr->sx.val.l) & 0xffffffff;
459 M_INTMOVE(s1, REG_ITMP1);
460 M_IADD_IMM(s3, REG_ITMP1); /* lower word in REG_ITMP1 now */
462 M_IADDX(REG_ITMP3, REG_ITMP2); /* high word in REG_ITMP2 now */
463 M_LNGMOVE(REG_ITMP12_PACKED, d);
464 emit_store_dst(jd, iptr, d);
467 case ICMD_LNEG: /* ..., value ==> ..., - value */
468 s1 = emit_load_s1(jd, iptr, REG_ITMP12_PACKED);
469 d = codegen_reg_of_dst(jd, iptr, REG_ITMP12_PACKED);
470 M_LNGMOVE(s1, REG_ITMP12_PACKED);
471 M_INEG(GET_LOW_REG(REG_ITMP12_PACKED));
472 M_INEGX(GET_HIGH_REG(REG_ITMP12_PACKED));
473 M_LNGMOVE(REG_ITMP12_PACKED, d);
474 emit_store_dst(jd, iptr, d);
477 /* integer operations ************************************************/
478 case ICMD_INEG: /* ..., value ==> ..., - value */
480 s1 = emit_load_s1(jd, iptr, REG_ITMP1);
481 d = codegen_reg_of_dst(jd, iptr, REG_ITMP1);
482 M_INTMOVE(s1, REG_ITMP1);
484 M_INTMOVE(REG_ITMP1, d);
485 emit_store_dst(jd, iptr, d);
488 case ICMD_I2L: /* ..., value ==> ..., value */
490 s1 = emit_load_s1(jd, iptr, REG_ITMP3);
491 d = codegen_reg_of_dst(jd, iptr, REG_ITMP12_PACKED);
492 M_IMOV(s1, GET_LOW_REG(d)); /* sets negativ bit */
494 M_ISET(GET_HIGH_REG(d));
496 M_ICLR(GET_HIGH_REG(d));
498 emit_store_dst(jd, iptr, d);
501 case ICMD_L2I: /* ..., value ==> ..., value */
503 s1 = emit_load_s1_low(jd, iptr, REG_ITMP2);
504 d = codegen_reg_of_dst(jd, iptr, REG_ITMP2);
506 emit_store_dst(jd, iptr, d);
508 case ICMD_INT2BYTE: /* ..., value ==> ..., value */
510 s1 = emit_load_s1(jd, iptr, REG_ITMP1);
511 d = codegen_reg_of_dst(jd, iptr, REG_ITMP2);
513 emit_store_dst(jd, iptr, d);
516 case ICMD_INT2CHAR: /* ..., value ==> ..., value */
518 s1 = emit_load_s1(jd, iptr, REG_ITMP1);
519 d = codegen_reg_of_dst(jd, iptr, REG_ITMP2);
521 emit_store_dst(jd, iptr, d);
524 case ICMD_INT2SHORT: /* ..., value ==> ..., value */
526 s1 = emit_load_s1(jd, iptr, REG_ITMP1);
527 d = codegen_reg_of_dst(jd, iptr, REG_ITMP2);
529 emit_store_dst(jd, iptr, d);
534 case ICMD_IADD: /* ..., val1, val2 ==> ..., val1 + val2 */
536 s1 = emit_load_s1(jd, iptr, REG_ITMP1);
537 s2 = emit_load_s2(jd, iptr, REG_ITMP2);
538 d = codegen_reg_of_dst(jd, iptr, REG_ITMP2);
539 M_INTMOVE(s2, REG_ITMP2);
540 M_IADD(s1, REG_ITMP2);
541 M_INTMOVE(REG_ITMP2, d);
542 emit_store_dst(jd, iptr, d);
545 /* s1.localindex = variable, sx.val.i = constant*/
550 s1 = emit_load_s1(jd, iptr, REG_ITMP1);
551 d = codegen_reg_of_dst(jd, iptr, REG_ITMP1);
552 M_INTMOVE(s1, REG_ITMP1);
553 M_IADD_IMM(iptr->sx.val.i, REG_ITMP1);
554 M_INTMOVE(REG_ITMP1, d);
555 emit_store_dst(jd, iptr, d);
558 case ICMD_ISUB: /* ..., val1, val2 ==> ..., val1 - val2 */
560 s1 = emit_load_s1(jd, iptr, REG_ITMP1);
561 s2 = emit_load_s2(jd, iptr, REG_ITMP2);
562 d = codegen_reg_of_dst(jd, iptr, REG_ITMP1);
563 M_INTMOVE(s1, REG_ITMP1);
564 M_ISUB(s2, REG_ITMP1);
565 M_INTMOVE(REG_ITMP1, d);
566 emit_store_dst(jd, iptr, d);
569 case ICMD_ISUBCONST: /* ..., value ==> ..., value + constant */
570 /* sx.val.i = constant */
572 s1 = emit_load_s1(jd, iptr, REG_ITMP1);
573 d = codegen_reg_of_dst(jd, iptr, REG_ITMP1);
574 M_INTMOVE(s1, REG_ITMP1);
575 M_IADD_IMM(-iptr->sx.val.i, REG_ITMP1);
576 M_INTMOVE(REG_ITMP1, d);
577 emit_store_dst(jd, iptr, d);
580 case ICMD_IDIV: /* ..., val1, val2 ==> ..., val1 / val2 */
581 s1 = emit_load_s1(jd, iptr, REG_ITMP1);
582 s2 = emit_load_s2(jd, iptr, REG_ITMP2);
583 d = codegen_reg_of_dst(jd, iptr, REG_ITMP1);
584 emit_arithmetic_check(cd, iptr, s2);
585 M_INTMOVE(s1, REG_ITMP1);
586 M_IDIV(s2, REG_ITMP1);
587 M_INTMOVE(REG_ITMP1, d);
588 emit_store_dst(jd, iptr, d);
591 case ICMD_IDIVPOW2: /* ..., value ==> ..., value << constant */
592 s1 = emit_load_s1(jd, iptr, REG_ITMP1);
593 d = codegen_reg_of_dst(jd, iptr, REG_ITMP1);
594 M_INTMOVE(s1, REG_ITMP1);
598 M_IADD_IMM((1 << iptr->sx.val.i) - 1, REG_ITMP1);
600 M_IMOV_IMM(iptr->sx.val.i, REG_ITMP2);
601 M_ISSR(REG_ITMP2, REG_ITMP1);
602 M_INTMOVE(REG_ITMP1, d);
603 emit_store_dst(jd, iptr, d);
606 case ICMD_IREM: /* ..., val1, val2 ==> ..., val1 % val2 */
607 s1 = emit_load_s1(jd, iptr, REG_ITMP1);
608 s2 = emit_load_s2(jd, iptr, REG_ITMP2);
609 d = codegen_reg_of_dst(jd, iptr, REG_ITMP3);
610 emit_arithmetic_check(cd, iptr, s2);
612 M_ICMP_IMM(0x80000000, s1);
617 M_TPFL; /* hides the next instruction */
618 M_IREM(s2, s1, REG_ITMP3);
620 M_INTMOVE(REG_ITMP3, d);
622 emit_store_dst(jd, iptr, d);
625 case ICMD_IREMPOW2: /* ..., value ==> ..., value << constant */
626 s1 = emit_load_s1(jd, iptr, REG_ITMP1);
627 d = codegen_reg_of_dst(jd, iptr, REG_ITMP2);
629 M_IMOV(s1, REG_ITMP1);
633 M_IAND_IMM(iptr->sx.val.i, d);
635 M_BGE(2 + 2 + 6 + 2);
636 M_IMOV(s1, d); /* don't use M_INTMOVE, so we know the jump offset */
638 M_IAND_IMM(iptr->sx.val.i, d); /* use 32-bit for jump offset */
641 emit_store_dst(jd, iptr, d);
645 case ICMD_LDIV: /* ..., val1, val2 ==> ..., val1 / val2 */
646 case ICMD_LREM: /* ..., val1, val2 ==> ..., val1 % val2 */
648 bte = iptr->sx.s23.s3.bte;
651 s2 = emit_load_s2(jd, iptr, REG_ITMP12_PACKED);
652 M_INTMOVE(GET_LOW_REG(s2), REG_ITMP3);
653 M_IOR(GET_HIGH_REG(s2), REG_ITMP3);
654 /* XXX could be optimized */
655 emit_arithmetic_check(cd, iptr, REG_ITMP3);
657 M_LST(s2, REG_SP, 2 * 4);
658 s1 = emit_load_s1(jd, iptr, REG_ITMP12_PACKED);
659 M_LST(s1, REG_SP, 0 * 4);
663 d = codegen_reg_of_dst(jd, iptr, REG_RESULT_PACKED);
664 M_LNGMOVE(REG_RESULT_PACKED, d);
665 emit_store_dst(jd, iptr, d);
668 case ICMD_IMUL: /* ..., val1, val2 ==> ..., val1 * val2 */
670 s1 = emit_load_s1(jd, iptr, REG_ITMP1);
671 s2 = emit_load_s2(jd, iptr, REG_ITMP2);
672 d = codegen_reg_of_dst(jd, iptr, REG_ITMP2);
673 M_INTMOVE(s2, REG_ITMP2);
674 M_IMUL(s1, REG_ITMP2);
675 M_INTMOVE(REG_ITMP2, d);
676 emit_store_dst(jd, iptr, d);
679 case ICMD_IMULCONST: /* ..., value ==> ..., value * constant */
680 /* sx.val.i = constant */
681 s1 = emit_load_s1(jd, iptr, REG_ITMP1);
682 d = codegen_reg_of_dst(jd, iptr, REG_ITMP2);
683 M_IMOV_IMM(iptr->sx.val.i, REG_ITMP2);
684 M_IMUL(s1, REG_ITMP2);
685 M_INTMOVE(REG_ITMP2, d);
686 emit_store_dst(jd, iptr, d);
689 case ICMD_ISHL: /* ..., val1, val2 ==> ..., val1 << val2 */
691 s1 = emit_load_s1(jd, iptr, REG_ITMP1);
692 s2 = emit_load_s2(jd, iptr, REG_ITMP2);
693 d = codegen_reg_of_dst(jd, iptr, REG_ITMP1);
694 M_INTMOVE(s1, REG_ITMP1);
695 M_INTMOVE(s2, REG_ITMP2);
696 M_IAND_IMM(0x1f, REG_ITMP2);
697 M_ISSL(REG_ITMP2, REG_ITMP1);
698 M_INTMOVE(REG_ITMP1, d);
699 emit_store_dst(jd, iptr, d);
702 case ICMD_ISHLCONST: /* ..., value ==> ..., value << constant */
703 /* sx.val.i = constant */
705 s1 = emit_load_s1(jd, iptr, REG_ITMP1);
706 d = codegen_reg_of_dst(jd, iptr, REG_ITMP1);
707 if (iptr->sx.val.i & 0x1f) {
708 M_INTMOVE(s1, REG_ITMP1)
709 if ((iptr->sx.val.i & 0x1f) <= 7) {
710 M_ISSL_IMM(iptr->sx.val.i & 0x1f, REG_ITMP1);
712 M_IMOV_IMM(iptr->sx.val.i & 0x1f, REG_ITMP2);
713 M_ISSL(REG_ITMP2, REG_ITMP1);
715 M_INTMOVE(REG_ITMP1, d);
719 emit_store_dst(jd, iptr, d);
722 case ICMD_ISHR: /* ..., val1, val2 ==> ..., val1 >> val2 */
724 s1 = emit_load_s1(jd, iptr, REG_ITMP1);
725 s2 = emit_load_s2(jd, iptr, REG_ITMP2);
726 d = codegen_reg_of_dst(jd, iptr, REG_ITMP1);
727 M_INTMOVE(s1, REG_ITMP1);
728 M_INTMOVE(s2, REG_ITMP2);
729 M_IAND_IMM(0x1f, REG_ITMP2);
730 M_ISSR(REG_ITMP2, REG_ITMP1);
731 M_INTMOVE(REG_ITMP1, d);
732 emit_store_dst(jd, iptr, d);
735 case ICMD_ISHRCONST: /* ..., value ==> ..., value >> constant */
736 /* sx.val.i = constant */
738 s1 = emit_load_s1(jd, iptr, REG_ITMP1);
739 d = codegen_reg_of_dst(jd, iptr, REG_ITMP1);
740 if (iptr->sx.val.i & 0x1f) {
741 M_INTMOVE(s1, REG_ITMP1)
742 if ((iptr->sx.val.i & 0x1f) <= 7) {
743 M_ISSR_IMM(iptr->sx.val.i & 0x1f, REG_ITMP1);
745 M_IMOV_IMM(iptr->sx.val.i & 0x1f, REG_ITMP2);
746 M_ISSR(REG_ITMP2, REG_ITMP1);
748 M_INTMOVE(REG_ITMP1, d);
752 emit_store_dst(jd, iptr, d);
755 case ICMD_IUSHR: /* ..., val1, val2 ==> ..., val1 >>> val2 */
757 s1 = emit_load_s1(jd, iptr, REG_ITMP1);
758 s2 = emit_load_s2(jd, iptr, REG_ITMP2);
759 d = codegen_reg_of_dst(jd, iptr, REG_ITMP1);
760 M_INTMOVE(s1, REG_ITMP1);
761 M_INTMOVE(s2, REG_ITMP2);
762 M_IAND_IMM(0x1f, REG_ITMP2);
763 M_IUSR(REG_ITMP2, REG_ITMP1);
764 M_INTMOVE(REG_ITMP1, d);
765 emit_store_dst(jd, iptr, d);
768 case ICMD_IUSHRCONST: /* ..., value ==> ..., value >>> constant */
769 /* sx.val.i = constant */
770 s1 = emit_load_s1(jd, iptr, REG_ITMP1);
771 d = codegen_reg_of_dst(jd, iptr, REG_ITMP1);
772 if (iptr->sx.val.i & 0x1f) {
773 M_INTMOVE(s1, REG_ITMP1)
774 if ((iptr->sx.val.i & 0x1f) <= 7) {
775 M_IUSR_IMM(iptr->sx.val.i & 0x1f, REG_ITMP1);
777 M_IMOV_IMM(iptr->sx.val.i & 0x1f, REG_ITMP2);
778 M_IUSR(REG_ITMP2, REG_ITMP1);
780 M_INTMOVE(REG_ITMP1, d);
784 emit_store_dst(jd, iptr, d);
787 case ICMD_IAND: /* ..., val1, val2 ==> ..., val1 & val2 */
789 s1 = emit_load_s1(jd, iptr, REG_ITMP1);
790 s2 = emit_load_s2(jd, iptr, REG_ITMP2);
791 d = codegen_reg_of_dst(jd, iptr, REG_ITMP2);
792 M_INTMOVE(s2, REG_ITMP2);
793 M_IAND(s1, REG_ITMP2);
794 M_INTMOVE(REG_ITMP2, d);
795 emit_store_dst(jd, iptr, d);
798 case ICMD_IANDCONST: /* ..., value ==> ..., value & constant */
799 /* sx.val.i = constant */
801 s1 = emit_load_s1(jd, iptr, REG_ITMP1);
802 d = codegen_reg_of_dst(jd, iptr, REG_ITMP1);
803 M_INTMOVE(s1, REG_ITMP1);
804 M_IAND_IMM(iptr->sx.val.i, REG_ITMP1);
805 M_INTMOVE(REG_ITMP1, d);
806 emit_store_dst(jd, iptr, d);
809 case ICMD_IOR: /* ..., val1, val2 ==> ..., val1 | val2 */
810 s1 = emit_load_s1(jd, iptr, REG_ITMP1);
811 s2 = emit_load_s2(jd, iptr, REG_ITMP2);
812 d = codegen_reg_of_dst(jd, iptr, REG_ITMP2);
813 M_INTMOVE(s2, REG_ITMP2);
814 M_IOR(s1, REG_ITMP2);
815 M_INTMOVE(REG_ITMP2, d);
816 emit_store_dst(jd, iptr, d);
819 case ICMD_IORCONST: /* ..., value ==> ..., value | constant */
820 /* sx.val.i = constant */
821 s1 = emit_load_s1(jd, iptr, REG_ITMP1);
822 d = codegen_reg_of_dst(jd, iptr, REG_ITMP1);
823 M_INTMOVE(s1, REG_ITMP1);
824 M_IOR_IMM(iptr->sx.val.i, REG_ITMP1);
825 M_INTMOVE(REG_ITMP1, d);
826 emit_store_dst(jd, iptr, d);
829 case ICMD_IXOR: /* ..., val1, val2 ==> ..., val1 | val2 */
830 s1 = emit_load_s1(jd, iptr, REG_ITMP1);
831 s2 = emit_load_s2(jd, iptr, REG_ITMP2);
832 d = codegen_reg_of_dst(jd, iptr, REG_ITMP2);
833 M_INTMOVE(s2, REG_ITMP2);
834 M_IXOR(s1, REG_ITMP2);
835 M_INTMOVE(REG_ITMP2, d);
836 emit_store_dst(jd, iptr, d);
839 case ICMD_IXORCONST: /* ..., value ==> ..., value | constant */
840 /* sx.val.i = constant */
841 s1 = emit_load_s1(jd, iptr, REG_ITMP1);
842 d = codegen_reg_of_dst(jd, iptr, REG_ITMP1);
843 M_INTMOVE(s1, REG_ITMP1);
844 M_IXOR_IMM(iptr->sx.val.i, REG_ITMP1);
845 M_INTMOVE(REG_ITMP1, d);
846 emit_store_dst(jd, iptr, d);
849 /* floating point operations ******************************************/
850 #if !defined(ENABLE_SOFTFLOAT)
851 case ICMD_FCMPL: /* ..., val1, val2 ==> ..., val1 fcmpl val2 */
853 s1 = emit_load_s1(jd, iptr, REG_FTMP1);
854 s2 = emit_load_s2(jd, iptr, REG_FTMP2);
855 d = codegen_reg_of_dst(jd, iptr, REG_ITMP1);
858 M_BFUN(14); /* result is -1, branch to end */
859 M_BFLT(10); /* result is -1, branch to end */
861 M_BFEQ(4) /* result is 0, branch to end */
863 emit_store_dst(jd, iptr, d);
866 case ICMD_FCMPG: /* ..., val1, val2 ==> ..., val1 fcmpg val2 */
868 s1 = emit_load_s1(jd, iptr, REG_FTMP1);
869 s2 = emit_load_s2(jd, iptr, REG_FTMP2);
870 d = codegen_reg_of_dst(jd, iptr, REG_ITMP1);
873 M_BFUN(16); /* result is +1, branch to end */
874 M_BFGT(14); /* result is +1, branch to end */
876 M_BFEQ(8) /* result is 0, branch to end */
878 emit_store_dst(jd, iptr, d);
881 case ICMD_FMUL: /* ..., val1, val2 ==> ..., val1 * val2 */
882 s1 = emit_load_s1(jd, iptr, REG_FTMP1);
883 s2 = emit_load_s2(jd, iptr, REG_FTMP2);
884 d = codegen_reg_of_dst(jd, iptr, REG_FTMP2);
885 M_FLTMOVE(s2, REG_FTMP2);
886 M_FMUL(s1, REG_FTMP2);
887 M_FLTMOVE(REG_FTMP2, d);
888 emit_store_dst(jd, iptr, d);
891 case ICMD_DMUL: /* ..., val1, val2 ==> ..., val1 * val2 */
892 s1 = emit_load_s1(jd, iptr, REG_FTMP1);
893 s2 = emit_load_s2(jd, iptr, REG_FTMP2);
894 d = codegen_reg_of_dst(jd, iptr, REG_FTMP2);
895 M_DBLMOVE(s2, REG_FTMP2);
896 M_DMUL(s1, REG_FTMP2);
897 M_DBLMOVE(REG_FTMP2, d);
898 emit_store_dst(jd, iptr, d);
901 case ICMD_FDIV: /* ..., val1, val2 ==> ..., val1 / val2 */
902 s1 = emit_load_s1(jd, iptr, REG_FTMP1);
903 s2 = emit_load_s2(jd, iptr, REG_FTMP2);
904 d = codegen_reg_of_dst(jd, iptr, REG_FTMP1);
905 M_FLTMOVE(s1, REG_FTMP1);
906 M_FDIV(s2, REG_FTMP1);
907 M_FLTMOVE(REG_FTMP1, d);
908 emit_store_dst(jd, iptr, d);
911 case ICMD_DDIV: /* ..., val1, val2 ==> ..., val1 / val2 */
912 s1 = emit_load_s1(jd, iptr, REG_FTMP1);
913 s2 = emit_load_s2(jd, iptr, REG_FTMP2);
914 d = codegen_reg_of_dst(jd, iptr, REG_FTMP1);
915 M_DBLMOVE(s1, REG_FTMP1);
916 M_DDIV(s2, REG_FTMP1);
917 M_DBLMOVE(REG_FTMP1, d);
918 emit_store_dst(jd, iptr, d);
921 case ICMD_FADD: /* ..., val1, val2 ==> ..., val1 + val2 */
922 s1 = emit_load_s1(jd, iptr, REG_FTMP1);
923 s2 = emit_load_s2(jd, iptr, REG_FTMP2);
924 d = codegen_reg_of_dst(jd, iptr, REG_FTMP2);
925 M_FLTMOVE(s2, REG_FTMP2);
926 M_FADD(s1, REG_FTMP2);
927 M_FLTMOVE(REG_FTMP2, d);
928 emit_store_dst(jd, iptr, d);
931 case ICMD_DADD: /* ..., val1, val2 ==> ..., val1 + val2 */
932 s1 = emit_load_s1(jd, iptr, REG_FTMP1);
933 s2 = emit_load_s2(jd, iptr, REG_FTMP2);
934 d = codegen_reg_of_dst(jd, iptr, REG_FTMP2);
935 M_DBLMOVE(s2, REG_FTMP2);
936 M_DADD(s1, REG_FTMP2);
937 M_DBLMOVE(REG_FTMP2, d);
938 emit_store_dst(jd, iptr, d);
941 case ICMD_FSUB: /* ..., val1, val2 ==> ..., val1 - val2 */
942 s1 = emit_load_s1(jd, iptr, REG_FTMP1);
943 s2 = emit_load_s2(jd, iptr, REG_FTMP2);
944 d = codegen_reg_of_dst(jd, iptr, REG_FTMP2);
945 M_FLTMOVE(s1, REG_FTMP1);
946 M_FSUB(s2, REG_FTMP1);
947 M_FLTMOVE(REG_FTMP1, d);
948 emit_store_dst(jd, iptr, d);
951 case ICMD_DSUB: /* ..., val1, val2 ==> ..., val1 - val2 */
952 s1 = emit_load_s1(jd, iptr, REG_FTMP1);
953 s2 = emit_load_s2(jd, iptr, REG_FTMP2);
954 d = codegen_reg_of_dst(jd, iptr, REG_FTMP2);
955 M_DBLMOVE(s1, REG_FTMP1);
956 M_DSUB(s2, REG_FTMP1);
957 M_DBLMOVE(REG_FTMP1, d);
958 emit_store_dst(jd, iptr, d);
961 case ICMD_F2D: /* ..., value ==> ..., (double) value */
962 s1 = emit_load_s1(jd, iptr, REG_FTMP1);
963 d = codegen_reg_of_dst(jd, iptr, REG_FTMP2);
965 emit_store_dst(jd, iptr, d);
968 case ICMD_D2F: /* ..., value ==> ..., (float) value */
969 s1 = emit_load_s1(jd, iptr, REG_FTMP1);
970 d = codegen_reg_of_dst(jd, iptr, REG_FTMP2);
972 emit_store_dst(jd, iptr, d);
975 case ICMD_FNEG: /* ..., value ==> ..., - value */
976 s1 = emit_load_s1(jd, iptr, REG_FTMP1);
977 d = codegen_reg_of_dst(jd, iptr, REG_FTMP2);
979 emit_store_dst(jd, iptr, d);
982 case ICMD_DNEG: /* ..., value ==> ..., - value */
983 s1 = emit_load_s1(jd, iptr, REG_FTMP1);
984 d = codegen_reg_of_dst(jd, iptr, REG_FTMP2);
986 emit_store_dst(jd, iptr, d);
991 /* load/store/copy/move operations ************************************/
993 case ICMD_ILOAD: /* ... ==> ..., content of local variable */
994 case ICMD_ALOAD: /* s1 = local variable */
998 case ICMD_ISTORE: /* ..., value ==> ... */
1005 emit_copy(jd, iptr);
1010 if (!(iptr->flags.bits & INS_FLAG_RETADDR))
1011 emit_copy(jd, iptr);
1015 case ICMD_ACONST: /* ... ==> ..., constant */
1016 d = codegen_reg_of_dst(jd, iptr, REG_ITMP1);
1018 if (INSTRUCTION_IS_UNRESOLVED(iptr)) {
1019 constant_classref *cr = iptr->sx.val.c.ref;;
1020 patcher_add_patch_ref(jd, PATCHER_resolve_classref_to_classinfo, cr, 0);
1023 M_AMOV_IMM(iptr->sx.val.anyptr, d);
1025 emit_store_dst(jd, iptr, d);
1027 /* BRANCH *************************************************************/
1029 case ICMD_ATHROW: /* ..., objectref ==> ... (, objectref) */
1031 s1 = emit_load_s1(jd, iptr, REG_ATMP1);
1032 M_ADRMOVE(s1, REG_ATMP1_XPTR);
1034 #ifdef ENABLE_VERIFIER
1035 if (INSTRUCTION_IS_UNRESOLVED(iptr)) {
1036 unresolved_class *uc = iptr->sx.s23.s2.uc;
1038 patcher_add_patch_ref(jd, PATCHER_resolve_class, uc, 0);
1040 #endif /* ENABLE_VERIFIER */
1041 M_JSR_PCREL(2); /* get current PC */
1044 M_AMOV_IMM(asm_handle_exception, REG_ATMP3);
1049 case ICMD_GOTO: /* ... ==> ... */
1050 case ICMD_RET: /* ... ==> ... */
1052 emit_br(cd, iptr->dst.block);
1056 case ICMD_JSR: /* ... ==> ... */
1058 emit_br(cd, iptr->sx.s23.s3.jsrtarget.block);
1064 case ICMD_IFNULL: /* ..., value ==> ... */
1065 case ICMD_IFNONNULL:
1066 assert(IS_ADR_TYPE(VAROP(iptr->s1)->type));
1067 s1 = emit_load_s1(jd, iptr, REG_ATMP1);
1069 emit_bcc(cd, iptr->dst.block, iptr->opc - ICMD_IFNULL, BRANCH_OPT_NONE);
1077 case ICMD_IFEQ: /* ..., value ==> ... */
1079 s1 = emit_load_s1(jd, iptr, REG_ITMP1);
1080 assert (VAROP(iptr->s1)->type == TYPE_INT);
1081 M_ICMP_IMM(iptr->sx.val.i, s1);
1082 emit_bcc(cd, iptr->dst.block, iptr->opc - ICMD_IFEQ, BRANCH_OPT_NONE);
1085 case ICMD_IF_ICMPEQ: /* ..., value, value ==> ... */
1086 case ICMD_IF_ICMPNE:
1087 case ICMD_IF_ICMPLT:
1088 case ICMD_IF_ICMPGT:
1089 case ICMD_IF_ICMPLE:
1090 case ICMD_IF_ICMPGE:
1092 s1 = emit_load_s1(jd, iptr, REG_ITMP1);
1093 s2 = emit_load_s2(jd, iptr, REG_ITMP2);
1095 emit_bcc(cd, iptr->dst.block, iptr->opc - ICMD_IF_ICMPEQ, BRANCH_OPT_NONE);
1098 case ICMD_IF_ACMPEQ: /* op1 = target JavaVM pc */
1099 case ICMD_IF_ACMPNE:
1101 s1 = emit_load_s1(jd, iptr, REG_ATMP1);
1102 s2 = emit_load_s2(jd, iptr, REG_ATMP2);
1104 emit_bcc(cd, iptr->dst.block, iptr->opc - ICMD_IF_ACMPEQ, BRANCH_OPT_NONE);
1108 /* MEMORY *************************************************************/
1110 case ICMD_GETSTATIC: /* ... ==> ..., value */
1112 if (INSTRUCTION_IS_UNRESOLVED(iptr)) {
1113 uf = iptr->sx.s23.s3.uf;
1114 fieldtype = uf->fieldref->parseddesc.fd->type;
1117 patcher_add_patch_ref(jd, PATCHER_get_putstatic, uf, 0);
1120 fi = iptr->sx.s23.s3.fmiref->p.field;
1121 fieldtype = fi->type;
1122 disp = (intptr_t) fi->value;
1124 if (!CLASS_IS_OR_ALMOST_INITIALIZED(fi->class)) {
1125 patcher_add_patch_ref(jd, PATCHER_initialize_class, fi->class,
1130 M_AMOV_IMM(disp, REG_ATMP1);
1131 switch (fieldtype) {
1132 #if defined(ENABLE_SOFTFLOAT)
1136 d = codegen_reg_of_dst(jd, iptr, REG_ITMP1);
1137 M_ILD(d, REG_ATMP1, 0);
1140 d = codegen_reg_of_dst(jd, iptr, REG_ITMP1);
1141 M_ALD(d, REG_ATMP1, 0);
1143 #if defined(ENABLE_SOFTFLOAT)
1147 d = codegen_reg_of_dst(jd, iptr, REG_ITMP23_PACKED);
1148 M_LLD(d, REG_ATMP1, 0);
1150 #if !defined(ENABLE_SOFTFLOAT)
1152 d = codegen_reg_of_dst(jd, iptr, REG_FTMP1);
1153 M_FLD(d, REG_ATMP1, 0);
1156 d = codegen_reg_of_dst(jd, iptr, REG_FTMP1);
1157 M_DLD(d, REG_ATMP1, 0);
1161 emit_store_dst(jd, iptr, d);
1164 case ICMD_PUTSTATIC: /* ..., value ==> ... */
1166 if (INSTRUCTION_IS_UNRESOLVED(iptr)) {
1167 uf = iptr->sx.s23.s3.uf;
1168 fieldtype = uf->fieldref->parseddesc.fd->type;
1171 patcher_add_patch_ref(jd, PATCHER_get_putstatic, uf, 0);
1174 fi = iptr->sx.s23.s3.fmiref->p.field;
1175 fieldtype = fi->type;
1176 disp = (intptr_t) fi->value;
1178 if (!CLASS_IS_OR_ALMOST_INITIALIZED(fi->class))
1179 patcher_add_patch_ref(jd, PATCHER_initialize_class, fi->class,
1183 M_AMOV_IMM(disp, REG_ATMP1);
1184 switch (fieldtype) {
1185 #if defined(ENABLE_SOFTFLOAT)
1189 s1 = emit_load_s1(jd, iptr, REG_ITMP2);
1190 M_IST(s1, REG_ATMP1, 0);
1192 #if defined(ENABLE_SOFTFLOAT)
1196 s1 = emit_load_s1(jd, iptr, REG_ITMP23_PACKED);
1197 M_LST(s1, REG_ATMP1, 0);
1200 s1 = emit_load_s1(jd, iptr, REG_ITMP2);
1201 M_AST(s1, REG_ATMP1, 0);
1203 #if !defined(ENABLE_SOFTFLOAT)
1205 s1 = emit_load_s1(jd, iptr, REG_FTMP2);
1206 M_FST(s1, REG_ATMP1, 0);
1209 s1 = emit_load_s1(jd, iptr, REG_FTMP2);
1210 M_DST(s1, REG_ATMP1, 0);
1217 case ICMD_GETFIELD: /* ... ==> ..., value */
1219 s1 = emit_load_s1(jd, iptr, REG_ATMP1);
1221 if (INSTRUCTION_IS_UNRESOLVED(iptr)) {
1222 uf = iptr->sx.s23.s3.uf;
1223 fieldtype = uf->fieldref->parseddesc.fd->type;
1226 patcher_add_patch_ref(jd, PATCHER_get_putfield, uf, 0);
1229 fi = iptr->sx.s23.s3.fmiref->p.field;
1230 fieldtype = fi->type;
1234 /* implicit null-pointer check */
1235 switch (fieldtype) {
1236 #if defined(ENABLE_SOFTFLOAT)
1240 d = codegen_reg_of_dst(jd, iptr, REG_ITMP2);
1243 #if defined(ENABLE_SOFTFLOAT)
1247 d = codegen_reg_of_dst(jd, iptr, REG_ITMP12_PACKED);
1251 d = codegen_reg_of_dst(jd, iptr, REG_ITMP2);
1254 #if !defined(ENABLE_SOFTFLOAT)
1256 d = codegen_reg_of_dst(jd, iptr, REG_FTMP1);
1260 d = codegen_reg_of_dst(jd, iptr, REG_FTMP1);
1265 emit_store_dst(jd, iptr, d);
1268 case ICMD_PUTFIELD: /* ..., value ==> ... */
1270 s1 = emit_load_s1(jd, iptr, REG_ATMP1);
1272 if (INSTRUCTION_IS_UNRESOLVED(iptr)) {
1273 uf = iptr->sx.s23.s3.uf;
1274 fieldtype = uf->fieldref->parseddesc.fd->type;
1278 fi = iptr->sx.s23.s3.fmiref->p.field;
1279 fieldtype = fi->type;
1283 if (IS_INT_LNG_TYPE(fieldtype)) {
1284 if (IS_2_WORD_TYPE(fieldtype)) {
1285 s2 = emit_load_s2(jd, iptr, REG_ITMP23_PACKED);
1287 s2 = emit_load_s2(jd, iptr, REG_ITMP2);
1290 s2 = emit_load_s2(jd, iptr, REG_FTMP2);
1293 if (INSTRUCTION_IS_UNRESOLVED(iptr))
1294 patcher_add_patch_ref(jd, PATCHER_get_putfield, uf, 0);
1296 /* implicit null-pointer check */
1297 switch (fieldtype) {
1298 #if defined(ENABLE_SOFTFLOAT)
1302 M_IST(s2, s1, disp);
1305 #if defined(ENABLE_SOFTFLOAT)
1309 M_LST(s2, s1, disp);
1312 M_AST(s2, s1, disp);
1314 #if !defined(ENABLE_SOFTFLOAT)
1316 M_FST(s2, s1, disp);
1319 M_DST(s2, s1, disp);
1325 case ICMD_ARRAYLENGTH: /* ..., arrayref ==> ..., length */
1327 s1 = emit_load_s1(jd, iptr, REG_ATMP1);
1328 d = codegen_reg_of_dst(jd, iptr, REG_ITMP2);
1329 /* implicit null-pointer check */
1330 M_ILD(d, s1, OFFSET(java_array_t, size));
1331 emit_store_dst(jd, iptr, d);
1334 case ICMD_BALOAD: /* ..., arrayref, index ==> ..., value */
1336 s1 = emit_load_s1(jd, iptr, REG_ATMP1);
1337 s2 = emit_load_s2(jd, iptr, REG_ITMP2);
1338 d = codegen_reg_of_dst(jd, iptr, REG_ITMP2);
1339 emit_arrayindexoutofbounds_check(cd, iptr, s1, s2);
1340 M_INTMOVE(s2, REG_ITMP2);
1341 M_IADD_IMM(OFFSET(java_bytearray_t, data[0]), REG_ITMP2);
1342 M_ADRMOVE(s1, REG_ATMP1);
1343 M_AADDINT(REG_ITMP2, REG_ATMP1);
1344 /* implicit null-pointer check */
1345 M_LBZX(REG_ATMP1, d);
1347 emit_store_dst(jd, iptr, d);
1350 case ICMD_CALOAD: /* ..., arrayref, index ==> ..., value */
1352 s1 = emit_load_s1(jd, iptr, REG_ATMP1);
1353 s2 = emit_load_s2(jd, iptr, REG_ITMP2);
1354 d = codegen_reg_of_dst(jd, iptr, REG_ITMP1);
1355 emit_arrayindexoutofbounds_check(cd, iptr, s1, s2);
1356 M_INTMOVE(s2, REG_ITMP2);
1357 M_ISSL_IMM(1, REG_ITMP2);
1358 M_IADD_IMM(OFFSET(java_chararray_t, data[0]), REG_ITMP2);
1359 M_ADRMOVE(s1, REG_ATMP1);
1360 M_AADDINT(REG_ITMP2, REG_ATMP1);
1361 /* implicit null-pointer check */
1362 M_LHZX(REG_ATMP1, d);
1364 emit_store_dst(jd, iptr, d);
1367 case ICMD_SALOAD: /* ..., arrayref, index ==> ..., value */
1369 s1 = emit_load_s1(jd, iptr, REG_ATMP1);
1370 s2 = emit_load_s2(jd, iptr, REG_ITMP2);
1371 d = codegen_reg_of_dst(jd, iptr, REG_ITMP2);
1372 emit_arrayindexoutofbounds_check(cd, iptr, s1, s2);
1373 M_INTMOVE(s2, REG_ITMP2);
1374 M_ISSL_IMM(1, REG_ITMP2);
1375 M_IADD_IMM(OFFSET(java_shortarray_t, data[0]), REG_ITMP2);
1376 M_ADRMOVE(s1, REG_ATMP1);
1377 M_AADDINT(REG_ITMP2, REG_ATMP1);
1379 /* implicit null-pointer check */
1380 M_LHZX(REG_ATMP1, d);
1382 emit_store_dst(jd, iptr, d);
1385 case ICMD_IALOAD: /* ..., arrayref, index ==> ..., value */
1387 s1 = emit_load_s1(jd, iptr, REG_ATMP1);
1388 s2 = emit_load_s2(jd, iptr, REG_ITMP2);
1389 d = codegen_reg_of_dst(jd, iptr, REG_ITMP2);
1390 emit_arrayindexoutofbounds_check(cd, iptr, s1, s2);
1391 M_INTMOVE(s2, REG_ITMP2);
1392 M_ISSL_IMM(2, REG_ITMP2);
1393 M_IADD_IMM(OFFSET(java_intarray_t, data[0]), REG_ITMP2);
1394 M_ADRMOVE(s1, REG_ATMP1);
1395 M_AADDINT(REG_ITMP2, REG_ATMP1);
1396 /* implicit null-pointer check */
1397 M_LWZX(REG_ATMP1, d);
1398 emit_store_dst(jd, iptr, d);
1401 case ICMD_LALOAD: /* ..., arrayref, index ==> ..., value */
1402 s1 = emit_load_s1(jd, iptr, REG_ATMP1);
1403 s2 = emit_load_s2(jd, iptr, REG_ITMP1);
1404 d = codegen_reg_of_dst(jd, iptr, REG_ITMP12_PACKED);
1405 /* implicit null-pointer check */
1406 emit_arrayindexoutofbounds_check(cd, iptr, s1, s2);
1407 M_INTMOVE(s2, REG_ITMP1);
1408 M_ISSL_IMM(3, REG_ITMP1);
1409 M_IADD_IMM(OFFSET(java_longarray_t, data[0]), REG_ITMP1);
1410 M_ADRMOVE(s1, REG_ATMP1);
1411 M_AADDINT(REG_ITMP1, REG_ATMP1);
1412 /* implicit null-pointer check */
1413 M_LLD(d, REG_ATMP1, 0);
1414 emit_store_dst(jd, iptr, d);
1417 case ICMD_FALOAD: /* ..., arrayref, index ==> ..., value */
1418 s1 = emit_load_s1(jd, iptr, REG_ATMP1);
1419 s2 = emit_load_s2(jd, iptr, REG_ITMP2);
1420 emit_arrayindexoutofbounds_check(cd, iptr, s1, s2);
1421 M_INTMOVE(s2, REG_ITMP2);
1422 M_ISSL_IMM(2, REG_ITMP2);
1423 M_IADD_IMM(OFFSET(java_floatarray_t, data[0]), REG_ITMP2);
1424 M_ADRMOVE(s1, REG_ATMP1);
1425 M_AADDINT(REG_ITMP2, REG_ATMP1);
1426 /* implicit null-pointer check */
1427 #if !defined(ENABLE_SOFTFLOAT)
1428 d = codegen_reg_of_dst(jd, iptr, REG_FTMP1);
1429 M_FLD(d, REG_ATMP1, 0);
1431 d = codegen_reg_of_dst(jd, iptr, REG_ITMP1);
1432 M_LWZX(REG_ATMP1, d);
1434 emit_store_dst(jd, iptr, d);
1437 case ICMD_DALOAD: /* ..., arrayref, index ==> ..., value */
1438 s1 = emit_load_s1(jd, iptr, REG_ATMP1);
1439 s2 = emit_load_s2(jd, iptr, REG_ITMP2);
1440 emit_arrayindexoutofbounds_check(cd, iptr, s1, s2);
1441 M_INTMOVE(s2, REG_ITMP2);
1442 M_ISSL_IMM(3, REG_ITMP2);
1443 M_IADD_IMM(OFFSET(java_doublearray_t, data[0]), REG_ITMP2);
1444 M_ADRMOVE(s1, REG_ATMP1);
1445 M_AADDINT(REG_ITMP2, REG_ATMP1);
1446 /* implicit null-pointer check */
1447 #if !defined(ENABLE_SOFTFLOAT)
1448 d = codegen_reg_of_dst(jd, iptr, REG_FTMP1);
1449 M_DLD(d, REG_ATMP1, 0);
1451 d = codegen_reg_of_dst(jd, iptr, REG_ITMP12_PACKED);
1452 M_LLD(d, REG_ATMP1, 0);
1454 emit_store_dst(jd, iptr, d);
1457 case ICMD_AALOAD: /* ..., arrayref, index ==> ..., value */
1458 s1 = emit_load_s1(jd, iptr, REG_ATMP1);
1459 s2 = emit_load_s2(jd, iptr, REG_ITMP2);
1460 d = codegen_reg_of_dst(jd, iptr, REG_ITMP2);
1461 emit_arrayindexoutofbounds_check(cd, iptr, s1, s2);
1462 M_INTMOVE(s2, REG_ITMP2);
1463 M_ISSL_IMM(2, REG_ITMP2);
1464 M_IADD_IMM(OFFSET(java_objectarray_t, data[0]), REG_ITMP2);
1465 M_ADRMOVE(s1, REG_ATMP1);
1466 M_AADDINT(REG_ITMP2, REG_ATMP1);
1468 /* implicit null-pointer check */
1469 M_LAX(REG_ATMP1, d);
1470 emit_store_dst(jd, iptr, d);
1474 case ICMD_BASTORE: /* ..., arrayref, index, value ==> ... */
1475 s1 = emit_load_s1(jd, iptr, REG_ATMP1);
1476 s2 = emit_load_s2(jd, iptr, REG_ITMP2);
1477 emit_arrayindexoutofbounds_check(cd, iptr, s1, s2);
1478 s3 = emit_load_s3(jd, iptr, REG_ITMP3);
1479 M_INTMOVE(s2, REG_ITMP2);
1480 M_IADD_IMM(OFFSET(java_bytearray_t, data[0]), REG_ITMP2);
1481 M_ADRMOVE(s1, REG_ATMP1);
1482 M_AADDINT(REG_ITMP2, REG_ATMP1);
1483 /* implicit null-pointer check */
1484 M_STBX(REG_ATMP1, s3);
1487 case ICMD_CASTORE: /* ..., arrayref, index, value ==> ... */
1488 s1 = emit_load_s1(jd, iptr, REG_ITMP1);
1489 s2 = emit_load_s2(jd, iptr, REG_ITMP2);
1490 emit_arrayindexoutofbounds_check(cd, iptr, s1, s2);
1491 s3 = emit_load_s3(jd, iptr, REG_ITMP3);
1492 M_INTMOVE(s2, REG_ITMP2);
1493 M_ISSL_IMM(1, REG_ITMP2);
1494 M_IADD_IMM(OFFSET(java_chararray_t, data[0]), REG_ITMP2);
1495 M_ADRMOVE(s1, REG_ATMP1);
1496 M_AADDINT(REG_ITMP2, REG_ATMP1);
1497 /* implicit null-pointer check */
1498 M_STHX(REG_ATMP1, s3);
1501 case ICMD_SASTORE: /* ..., arrayref, index, value ==> ... */
1502 s1 = emit_load_s1(jd, iptr, REG_ITMP1);
1503 s2 = emit_load_s2(jd, iptr, REG_ITMP2);
1504 emit_arrayindexoutofbounds_check(cd, iptr, s1, s2);
1505 s3 = emit_load_s3(jd, iptr, REG_ITMP3);
1506 M_INTMOVE(s2, REG_ITMP2);
1507 M_ISSL_IMM(1, REG_ITMP2);
1508 M_IADD_IMM(OFFSET(java_shortarray_t, data[0]), REG_ITMP2);
1509 M_ADRMOVE(s1, REG_ATMP1);
1510 M_AADDINT(REG_ITMP2, REG_ATMP1);
1511 /* implicit null-pointer check */
1512 M_STHX(REG_ATMP1, s3);
1515 case ICMD_IASTORE: /* ..., arrayref, index, value ==> ... */
1516 s1 = emit_load_s1(jd, iptr, REG_ITMP1);
1517 s2 = emit_load_s2(jd, iptr, REG_ITMP2);
1518 emit_arrayindexoutofbounds_check(cd, iptr, s1, s2);
1519 s3 = emit_load_s3(jd, iptr, REG_ITMP3);
1520 M_INTMOVE(s2, REG_ITMP2);
1521 M_ISSL_IMM(2, REG_ITMP2);
1522 M_IADD_IMM(OFFSET(java_intarray_t, data[0]), REG_ITMP2);
1523 M_ADRMOVE(s1, REG_ATMP1);
1524 M_AADDINT(REG_ITMP2, REG_ATMP1);
1525 /* implicit null-pointer check */
1526 M_STWX(REG_ATMP1, s3);
1529 case ICMD_LASTORE: /* ..., arrayref, index, value ==> ... */
1530 s1 = emit_load_s1(jd, iptr, REG_ATMP1);
1531 s2 = emit_load_s2(jd, iptr, REG_ITMP1);
1532 emit_arrayindexoutofbounds_check(cd, iptr, s1, s2);
1534 M_INTMOVE(s2, REG_ITMP1);
1535 M_ISSL_IMM(3, REG_ITMP1);
1536 M_IADD_IMM(OFFSET(java_longarray_t, data[0]), REG_ITMP1);
1537 M_ADRMOVE(s1, REG_ATMP1);
1538 M_AADDINT(REG_ITMP1, REG_ATMP1);
1539 /* implicit null-pointer check */
1540 s3 = emit_load_s3(jd, iptr, REG_ITMP12_PACKED);
1541 M_LST(s3, REG_ATMP1, 0);
1544 case ICMD_FASTORE: /* ..., arrayref, index, value ==> ... */
1545 s1 = emit_load_s1(jd, iptr, REG_ITMP1);
1546 s2 = emit_load_s2(jd, iptr, REG_ITMP2);
1547 emit_arrayindexoutofbounds_check(cd, iptr, s1, s2);
1548 M_INTMOVE(s2, REG_ITMP2);
1549 M_ISSL_IMM(2, REG_ITMP2);
1550 M_IADD_IMM(OFFSET(java_floatarray_t, data[0]), REG_ITMP2);
1551 M_ADRMOVE(s1, REG_ATMP1);
1552 M_AADDINT(REG_ITMP2, REG_ATMP1);
1553 /* implicit null-pointer check */
1554 #if !defined(ENABLE_SOFTFLOAT)
1555 s3 = emit_load_s3(jd, iptr, REG_FTMP3);
1556 M_FST(s3, REG_ATMP1, 0);
1558 s3 = emit_load_s3(jd, iptr, REG_ITMP3);
1559 M_STWX(REG_ATMP1, s3);
1563 case ICMD_DASTORE: /* ..., arrayref, index, value ==> ... */
1564 s1 = emit_load_s1(jd, iptr, REG_ITMP1);
1565 s2 = emit_load_s2(jd, iptr, REG_ITMP2);
1566 emit_arrayindexoutofbounds_check(cd, iptr, s1, s2);
1567 M_INTMOVE(s2, REG_ITMP2);
1568 M_ISSL_IMM(3, REG_ITMP2);
1569 M_IADD_IMM(OFFSET(java_doublearray_t, data[0]), REG_ITMP2);
1570 M_ADRMOVE(s1, REG_ATMP1);
1571 M_AADDINT(REG_ITMP2, REG_ATMP1);
1572 /* implicit null-pointer check */
1573 #if !defined(ENABLE_SOFTFLOAT)
1574 s3 = emit_load_s3(jd, iptr, REG_FTMP3);
1575 M_DST(s3, REG_ATMP1, 0);
1577 s3 = emit_load_s3(jd, iptr, REG_ITMP12_PACKED);
1578 /* implicit null-pointer check */
1579 M_LST(s3, REG_ATMP1, 0);
1583 case ICMD_AASTORE: /* ..., arrayref, index, value ==> ... */
1585 s1 = emit_load_s1(jd, iptr, REG_ATMP1);
1586 s2 = emit_load_s2(jd, iptr, REG_ITMP1);
1587 emit_arrayindexoutofbounds_check(cd, iptr, s1, s2);
1588 s3 = emit_load_s3(jd, iptr, REG_ATMP2);
1590 /* XXX what if array is NULL */
1591 disp = dseg_add_functionptr(cd, BUILTIN_FAST_canstore);
1593 M_AST(s1, REG_SP, 0*4);
1594 M_AST(s3, REG_SP, 1*4);
1595 M_JSR_IMM(BUILTIN_FAST_canstore);
1596 emit_arraystore_check(cd, iptr);
1598 s1 = emit_load_s1(jd, iptr, REG_ATMP1);
1599 s2 = emit_load_s2(jd, iptr, REG_ITMP1);
1600 s3 = emit_load_s3(jd, iptr, REG_ATMP2);
1601 M_INTMOVE(s2, REG_ITMP1);
1602 M_ISSL_IMM(2, REG_ITMP1);
1603 M_IADD_IMM(OFFSET(java_objectarray_t, data[0]), REG_ITMP1);
1604 M_ADRMOVE(s1, REG_ATMP1);
1605 M_AADDINT(REG_ITMP1, REG_ATMP1);
1606 /* implicit null-pointer check */
1607 M_STAX(REG_ATMP1, s3);
1612 /* METHOD INVOCATION *********************************************************/
1613 case ICMD_BUILTIN: /* ..., [arg1, [arg2 ...]] ==> ... */
1614 REPLACEMENT_POINT_FORGC_BUILTIN(cd, iptr);
1616 bte = iptr->sx.s23.s3.bte;
1620 case ICMD_INVOKESTATIC: /* ..., [arg1, [arg2 ...]] ==> ... */
1621 case ICMD_INVOKESPECIAL:/* ..., objectref, [arg1, [arg2 ...]] ==> ... */
1622 case ICMD_INVOKEVIRTUAL:/* op1 = arg count, val.a = method pointer */
1623 case ICMD_INVOKEINTERFACE:
1624 REPLACEMENT_POINT_INVOKE(cd, iptr);
1626 if (INSTRUCTION_IS_UNRESOLVED(iptr)) {
1628 um = iptr->sx.s23.s3.um;
1629 md = um->methodref->parseddesc.md;
1632 lm = iptr->sx.s23.s3.fmiref->p.method;
1634 md = lm->parseddesc;
1637 s3 = md->paramcount;
1639 MCODECHECK((s3 << 1) + 64);
1641 /* copy arguments to stack */
1642 for (s3 = s3 - 1; s3 >= 0; s3--) {
1643 var = VAR(iptr->sx.s23.s2.args[s3]);
1644 /* already preallocated */
1645 if (var->flags & PREALLOC) continue;
1647 if (!md->params[s3].inmemory) assert(0);
1649 switch (var->type) {
1650 #if defined(ENABLE_SOFTFLOAT)
1654 d = emit_load(jd, iptr, var, REG_ITMP12_PACKED);
1655 M_LST(d, REG_SP, md->params[s3].regoff);
1657 #if defined(ENABLE_SOFTFLOAT)
1661 d = emit_load(jd, iptr, var, REG_ITMP1);
1662 M_IST(d, REG_SP, md->params[s3].regoff);
1665 d = emit_load(jd, iptr, var, REG_ATMP1);
1666 M_AST(d, REG_SP, md->params[s3].regoff);
1668 #if !defined(ENABLE_SOFTFLOAT)
1670 d = emit_load(jd, iptr, var, REG_FTMP1);
1671 M_FST(d, REG_SP, md->params[s3].regoff);
1674 d = emit_load(jd, iptr, var, REG_FTMP1);
1675 M_DST(d, REG_SP, md->params[s3].regoff);
1683 /* arguments in place now */
1686 if (bte->stub == NULL)
1687 disp = (ptrint) bte->fp;
1689 disp = (ptrint) bte->stub;
1690 d = md->returntype.type;
1693 REPLACEMENT_POINT_INVOKE_RETURN(cd, iptr);
1696 case ICMD_INVOKESPECIAL:
1697 /* adress register for sure */
1698 M_ALD(REG_ATMP1, REG_SP, 0);
1699 emit_nullpointer_check(cd, iptr, REG_ATMP1);
1701 case ICMD_INVOKESTATIC:
1703 patcher_add_patch_ref(jd, PATCHER_invokestatic_special, um, 0);
1705 M_AMOV_IMM(disp, REG_ATMP1);
1707 disp = lm->stubroutine;
1708 M_AMOV_IMM(disp, REG_ATMP1);
1711 /* generate the actual call */
1713 REPLACEMENT_POINT_INVOKE_RETURN(cd, iptr);
1717 case ICMD_INVOKEVIRTUAL:
1719 patcher_add_patch_ref(jd, PATCHER_invokevirtual, um, 0);
1722 s1 = OFFSET(vftbl_t, table[0]) + sizeof(methodptr) * lm->vftblindex;
1724 /* load object pointer (==argument 0) */
1725 M_ALD(REG_ATMP1, REG_SP, 0);
1726 /* implicit null-pointer check */
1727 M_ALD(REG_METHODPTR, REG_ATMP1, OFFSET(java_object_t, vftbl));
1728 M_ALD(REG_ATMP3, REG_METHODPTR, s1);
1729 /* generate the actual call */
1732 case ICMD_INVOKEINTERFACE:
1734 patcher_add_patch_ref(jd, PATCHER_invokeinterface, um, 0);
1739 s1 = OFFSET(vftbl_t, interfacetable[0]) - sizeof(methodptr*) * lm->class->index;
1740 s2 = sizeof(methodptr) * (lm - lm->class->methods);
1742 /* load object pointer (==argument 0) */
1743 M_ALD(REG_ATMP1, REG_SP, 0);
1745 /* implicit null-pointer check */
1746 M_ALD(REG_METHODPTR, REG_ATMP1, OFFSET(java_object_t, vftbl));
1747 M_ALD(REG_METHODPTR, REG_METHODPTR, s1);
1748 M_ALD(REG_ATMP3, REG_METHODPTR, s2);
1750 /* generate the actual call */
1752 REPLACEMENT_POINT_INVOKE_RETURN(cd, iptr);
1756 } /* switch (iptr->opc) */
1758 REPLACEMENT_POINT_INVOKE_RETURN(cd, iptr);
1759 REPLACEMENT_POINT_FORGC_BUILTIN_RETURN(cd, iptr);
1761 /* store return value */
1762 d = md->returntype.type;
1765 case TYPE_VOID: break;
1766 #if defined(ENABLE_SOFTFLOAT)
1770 s1 = codegen_reg_of_dst(jd, iptr, REG_RESULT);
1771 M_INTMOVE(REG_RESULT, s1);
1773 #if defined(ENABLE_SOFTFLOAT)
1777 s1 = codegen_reg_of_dst(jd, iptr, REG_RESULT_PACKED);
1778 M_LNGMOVE(REG_RESULT_PACKED, s1);
1781 s1 = codegen_reg_of_dst(jd, iptr, REG_ATMP1);
1782 /* all stuff is returned in %d0 */
1783 M_INT2ADRMOVE(REG_RESULT, s1);
1785 #if !defined(ENABLE_SOFTFLOAT)
1787 * for BUILTINS float values are returned in %d0,%d1
1788 * within cacao we use %fp0 for that.
1791 s1 = codegen_reg_of_dst(jd, iptr, REG_FTMP1);
1792 if (iptr->opc == ICMD_BUILTIN) {
1793 M_INT2FLTMOVE(REG_FRESULT, s1);
1795 M_FLTMOVE(REG_FRESULT, s1);
1799 s1 = codegen_reg_of_dst(jd, iptr, REG_FTMP1);
1800 if (iptr->opc == ICMD_BUILTIN) {
1801 M_LST(REG_RESULT_PACKED, REG_SP, rd->memuse * 4 + 4);
1802 M_DLD(s1, REG_SP, rd->memuse * 4 + 4);
1804 M_DBLMOVE(REG_FRESULT, s1);
1811 if (d != TYPE_VOID) emit_store_dst(jd, iptr, s1);
1812 break; /* ICMD_INVOKE* */
1814 #if defined(ENABLE_SOFTFLOAT)
1817 case ICMD_IRETURN: /* ..., retvalue ==> ... */
1819 REPLACEMENT_POINT_RETURN(cd, iptr);
1820 s1 = emit_load_s1(jd, iptr, REG_RESULT);
1821 M_INTMOVE(s1, REG_RESULT);
1822 goto nowperformreturn;
1824 case ICMD_ARETURN: /* ..., retvalue ==> ... */
1826 REPLACEMENT_POINT_RETURN(cd, iptr);
1827 s1 = emit_load_s1(jd, iptr, REG_RESULT);
1828 assert(VAROP(iptr->s1)->type == TYPE_ADR);
1829 M_ADR2INTMOVE(s1, REG_RESULT);
1831 #ifdef ENABLE_VERIFIER
1832 if (INSTRUCTION_IS_UNRESOLVED(iptr)) {
1833 unresolved_class *uc = iptr->sx.s23.s2.uc;
1835 patcher_add_patch_ref(jd, PATCHER_resolve_class, uc, 0);
1837 #endif /* ENABLE_VERIFIER */
1838 goto nowperformreturn;
1840 #if defined(ENABLE_SOFTFLOAT)
1843 case ICMD_LRETURN: /* ..., retvalue ==> ... */
1844 REPLACEMENT_POINT_RETURN(cd, iptr);
1845 s1 = emit_load_s1(jd, iptr, REG_RESULT_PACKED);
1846 M_LNGMOVE(s1, REG_RESULT_PACKED);
1847 goto nowperformreturn;
1849 #if !defined(ENABLE_SOFTFLOAT)
1850 case ICMD_FRETURN: /* ..., retvalue ==> ... */
1851 REPLACEMENT_POINT_RETURN(cd, iptr);
1852 s1 = emit_load_s1(jd, iptr, REG_FRESULT);
1853 M_FLTMOVE(s1, REG_FRESULT);
1854 goto nowperformreturn;
1857 REPLACEMENT_POINT_RETURN(cd, iptr);
1858 s1 = emit_load_s1(jd, iptr, REG_FRESULT);
1859 M_DBLMOVE(s1, REG_FRESULT);
1860 goto nowperformreturn;
1864 case ICMD_RETURN: /* ... ==> ... */
1866 REPLACEMENT_POINT_RETURN(cd, iptr);
1872 p = cd->stackframesize;
1874 /* call trace function */
1875 #if !defined(NDEBUG)
1876 emit_verbosecall_exit(jd);
1879 #if defined(ENABLE_THREADS)
1880 /* call lock_monitor_exit */
1881 if (checksync && code_is_synchronized(code)) {
1882 M_ILD(REG_ITMP3, REG_SP, rd->memuse * 8);
1884 /* we need to save the proper return value */
1885 /* we do not care for the long -> doubel convert space here */
1886 switch (iptr->opc) {
1887 #if defined(ENABLE_SOFTFLOAT)
1891 M_LST(REG_RESULT_PACKED, REG_SP, rd->memuse * 8 + 8);
1893 #if defined(ENABLE_SOFTFLOAT)
1898 M_IST(REG_RESULT , REG_SP, rd->memuse * 8 + 8);
1900 #if !defined(ENABLE_SOFTFLOAT)
1902 M_FST(REG_FRESULT, REG_SP, rd->memuse * 8 + 8);
1905 M_DST(REG_FRESULT, REG_SP, rd->memuse * 8 + 8);
1910 M_IST(REG_ITMP3, REG_SP, 0 * 4);
1911 M_JSR_IMM(LOCK_monitor_exit);
1913 /* and now restore the proper return value */
1914 switch (iptr->opc) {
1916 #if defined(ENABLE_SOFTFLOAT)
1920 M_LLD(REG_RESULT_PACKED, REG_SP, rd->memuse * 8 + 8);
1922 #if defined(ENABLE_SOFTFLOAT)
1927 M_ILD(REG_RESULT , REG_SP, rd->memuse * 8 + 8);
1929 #if !defined(ENABLE_SOFTFLOAT)
1931 M_FLD(REG_FRESULT, REG_SP, rd->memuse * 8 + 8);
1934 M_DLD(REG_FRESULT, REG_SP, rd->memuse * 8 + 8);
1942 /* restore return address */
1944 if (!code_is_leafmethod(code)) {
1945 /* ATTENTION: Don't use REG_ZERO (r0) here, as M_ALD
1946 may have a displacement overflow. */
1948 M_ALD(REG_ITMP1, REG_SP, p * 4 + LA_LR_OFFSET);
1952 /* restore saved registers */
1954 for (i = INT_SAV_CNT - 1; i >= rd->savintreguse; i--) {
1955 p-=8; M_ILD(rd->savintregs[i], REG_SP, p);
1957 for (i=ADR_SAV_CNT-1; i>=rd->savadrreguse; --i) {
1958 p-=8; M_ALD(rd->savadrregs[i], REG_SP, p);
1960 #if !defined(ENABLE_SOFTFLOAT)
1961 for (i = FLT_SAV_CNT - 1; i >= rd->savfltreguse; i--) {
1962 p-=8; M_FLOAD(rd->savfltregs[i], REG_SP, p);
1965 /* deallocate stack */
1966 M_AADD_IMM(cd->stackframesize, REG_SP);
1972 case ICMD_INSTANCEOF: /* ..., objectref ==> ..., intresult */
1973 /* val.a: (classinfo*) superclass */
1975 /* superclass is an interface:
1977 * return (sub != NULL) &&
1978 * (sub->vftbl->interfacetablelength > super->index) &&
1979 * (sub->vftbl->interfacetable[-super->index] != NULL);
1981 * superclass is a class:
1983 * return ((sub != NULL) && (0
1984 * <= (sub->vftbl->baseval - super->vftbl->baseval) <=
1985 * super->vftbl->diffvall));
1992 if (INSTRUCTION_IS_UNRESOLVED(iptr)) {
1997 super = iptr->sx.s23.s3.c.cls;
1998 superindex = super->index;
2001 if ((super == NULL) || !(super->flags & ACC_INTERFACE))
2002 CODEGEN_CRITICAL_SECTION_NEW;
2004 s1 = emit_load_s1(jd, iptr, REG_ATMP1);
2005 d = codegen_reg_of_dst(jd, iptr, REG_ITMP2);
2007 assert(VAROP(iptr->s1 )->type == TYPE_ADR);
2008 assert(VAROP(iptr->dst)->type == TYPE_INT);
2012 /* if class is not resolved, check which code to call */
2014 if (super == NULL) {
2016 emit_label_beq(cd, BRANCH_LABEL_1);
2018 patcher_add_patch_ref(jd, PATCHER_resolve_classref_to_flags, iptr->sx.s23.s3.c.ref, 0);
2020 M_IMOV_IMM32(0, REG_ITMP3);
2021 M_IAND_IMM(ACC_INTERFACE, REG_ITMP3);
2022 emit_label_beq(cd, BRANCH_LABEL_2);
2025 /* interface instanceof code */
2027 if ((super == NULL) || (super->flags & ACC_INTERFACE)) {
2028 if (super == NULL) {
2029 patcher_add_patch_ref(jd, PATCHER_instanceof_interface, iptr->sx.s23.s3.c.ref, 0);
2032 emit_label_beq(cd, BRANCH_LABEL_3);
2035 M_ALD(REG_ATMP1, s1, OFFSET(java_object_t, vftbl));
2036 M_ILD(REG_ITMP3, REG_ATMP1, OFFSET(vftbl_t, interfacetablelength));
2037 M_IADD_IMM(-superindex, REG_ITMP3); /* -superindex may be patched patched */
2040 M_ALD(REG_ATMP1, REG_ATMP1, OFFSET(vftbl_t, interfacetable[0]) - superindex * sizeof(methodptr*)); /* patch here too! */
2046 emit_label_br(cd, BRANCH_LABEL_4);
2048 emit_label(cd, BRANCH_LABEL_3);
2051 /* class instanceof code */
2053 if ((super == NULL) || !(super->flags & ACC_INTERFACE)) {
2054 if (super == NULL) {
2055 emit_label(cd, BRANCH_LABEL_2);
2057 patcher_add_patch_ref(jd, PATCHER_resolve_classref_to_vftbl, iptr->sx.s23.s3.c.ref, 0);
2058 M_AMOV_IMM(0, REG_ATMP2);
2060 M_AMOV_IMM(super->vftbl, REG_ATMP2);
2062 emit_label_beq(cd, BRANCH_LABEL_5);
2065 M_ALD(REG_ATMP1, s1, OFFSET(java_object_t, vftbl));
2067 CODEGEN_CRITICAL_SECTION_START;
2069 M_ILD(REG_ITMP1, REG_ATMP1, OFFSET(vftbl_t, baseval));
2070 M_ILD(REG_ITMP3, REG_ATMP2, OFFSET(vftbl_t, baseval));
2071 M_ILD(REG_ITMP2, REG_ATMP2, OFFSET(vftbl_t, diffval));
2073 CODEGEN_CRITICAL_SECTION_END;
2075 M_ISUB(REG_ITMP3, REG_ITMP1);
2076 M_ICMP(REG_ITMP2, REG_ITMP1);
2079 M_TPFW; /* overlaps next instruction */
2083 emit_label(cd, BRANCH_LABEL_5);
2086 if (super == NULL) {
2087 emit_label(cd, BRANCH_LABEL_1);
2088 emit_label(cd, BRANCH_LABEL_4);
2091 emit_store_dst(jd, iptr, d);
2095 case ICMD_CHECKCAST: /* ..., objectref ==> ..., objectref */
2096 /* val.a: (classinfo*) superclass */
2098 /* superclass is an interface:
2100 * OK if ((sub == NULL) ||
2101 * (sub->vftbl->interfacetablelength > super->index) &&
2102 * (sub->vftbl->interfacetable[-super->index] != NULL));
2104 * superclass is a class:
2106 * OK if ((sub == NULL) || (0
2107 * <= (sub->vftbl->baseval - super->vftbl->baseval) <=
2108 * super->vftbl->diffvall));
2111 if (!(iptr->flags.bits & INS_FLAG_ARRAY)) {
2112 /* object type cast-check */
2117 if (INSTRUCTION_IS_UNRESOLVED(iptr)) {
2122 super = iptr->sx.s23.s3.c.cls;
2123 superindex = super->index;
2126 if ((super == NULL) || !(super->flags & ACC_INTERFACE))
2127 CODEGEN_CRITICAL_SECTION_NEW;
2129 s1 = emit_load_s1(jd, iptr, REG_ATMP1);
2130 assert(VAROP(iptr->s1)->type == TYPE_ADR);
2132 /* if class is not resolved, check which code to call */
2134 if (super == NULL) {
2136 emit_label_beq(cd, BRANCH_LABEL_1);
2138 patcher_add_patch_ref(jd, PATCHER_resolve_classref_to_flags, iptr->sx.s23.s3.c.ref, 0);
2140 M_IMOV_IMM32(0, REG_ITMP2);
2141 M_IAND_IMM(ACC_INTERFACE, REG_ITMP2);
2142 emit_label_beq(cd, BRANCH_LABEL_2);
2145 /* interface checkcast code */
2147 if ((super == NULL) || (super->flags & ACC_INTERFACE)) {
2148 if (super == NULL) {
2149 patcher_add_patch_ref(jd, PATCHER_checkcast_interface, iptr->sx.s23.s3.c.ref, 0);
2152 emit_label_beq(cd, BRANCH_LABEL_3);
2155 M_ALD(REG_ATMP2, s1, OFFSET(java_object_t, vftbl));
2156 M_ILD(REG_ITMP3, REG_ATMP2, OFFSET(vftbl_t, interfacetablelength));
2158 M_IADD_IMM(-superindex, REG_ITMP3); /* superindex patched */
2160 emit_classcast_check(cd, iptr, BRANCH_LE, REG_ITMP3, s1);
2162 M_ALD(REG_ATMP3, REG_ATMP2, OFFSET(vftbl_t, interfacetable[0]) - superindex * sizeof(methodptr*)); /* patched*/
2164 emit_classcast_check(cd, iptr, BRANCH_EQ, REG_ATMP3, s1);
2167 emit_label_br(cd, BRANCH_LABEL_4);
2169 emit_label(cd, BRANCH_LABEL_3);
2172 /* class checkcast code */
2174 if ((super == NULL) || !(super->flags & ACC_INTERFACE)) {
2175 if (super == NULL) {
2176 emit_label(cd, BRANCH_LABEL_2);
2178 patcher_add_patch_ref(jd, PATCHER_resolve_classref_to_vftbl, iptr->sx.s23.s3.c.ref, 0);
2179 M_AMOV_IMM(0, REG_ATMP3);
2181 M_AMOV_IMM(super->vftbl, REG_ATMP3);
2183 emit_label_beq(cd, BRANCH_LABEL_5);
2186 M_ALD(REG_ATMP2, s1, OFFSET(java_object_t, vftbl));
2188 CODEGEN_CRITICAL_SECTION_START;
2190 M_ILD(REG_ITMP3, REG_ATMP2, OFFSET(vftbl_t, baseval)); /* REG_ITMP3 == sub->vftbl->baseval */
2191 M_ILD(REG_ITMP1, REG_ATMP3, OFFSET(vftbl_t, baseval));
2192 M_ILD(REG_ITMP2, REG_ATMP3, OFFSET(vftbl_t, diffval));
2194 CODEGEN_CRITICAL_SECTION_END;
2196 M_ISUB(REG_ITMP1, REG_ITMP3);
2197 M_ICMP(REG_ITMP2, REG_ITMP3); /* XXX was CMPU */
2199 emit_classcast_check(cd, iptr, BRANCH_UGT, REG_ITMP3, s1); /* XXX was BRANCH_GT */
2202 emit_label(cd, BRANCH_LABEL_5);
2205 if (super == NULL) {
2206 emit_label(cd, BRANCH_LABEL_1);
2207 emit_label(cd, BRANCH_LABEL_4);
2210 d = codegen_reg_of_dst(jd, iptr, s1);
2212 /* array type cast-check */
2214 s1 = emit_load_s1(jd, iptr, REG_ATMP2);
2216 if (INSTRUCTION_IS_UNRESOLVED(iptr)) {
2217 patcher_add_patch_ref(jd, PATCHER_resolve_classref_to_classinfo, iptr->sx.s23.s3.c.ref, 0);
2218 M_AMOV_IMM(0, REG_ATMP1);
2220 M_AMOV_IMM(iptr->sx.s23.s3.c.cls, REG_ATMP1);
2225 M_JSR_IMM(BUILTIN_arraycheckcast);
2226 M_AADD_IMM(2*4, REG_SP); /* pop arguments off stack */
2228 emit_classcast_check(cd, iptr, BRANCH_EQ, REG_RESULT, s1);
2230 s1 = emit_load_s1(jd, iptr, REG_ITMP1);
2231 d = codegen_reg_of_dst(jd, iptr, s1);
2233 assert(VAROP(iptr->dst)->type == TYPE_ADR);
2235 emit_store_dst(jd, iptr, d);
2238 case ICMD_TABLESWITCH: /* ..., index ==> ... */
2241 branch_target_t *table;
2243 table = iptr->dst.table;
2245 l = iptr->sx.s23.s2.tablelow;
2246 i = iptr->sx.s23.s3.tablehigh;
2248 s1 = emit_load_s1(jd, iptr, REG_ITMP1);
2249 M_INTMOVE(s1, REG_ITMP1);
2250 if (l != 0) M_ISUB_IMM(l, REG_ITMP1);
2255 M_ICMP_IMM(i - 1, REG_ITMP1);
2256 emit_bugt(cd, table[0].block);
2258 /* build jump table top down and use address of lowest entry */
2262 dseg_add_target(cd, table->block);
2266 /* length of dataseg after last dseg_add_target is used by load */
2267 M_AMOV_IMM(0, REG_ATMP2);
2270 M_ISSL_IMM(2, REG_ITMP1); /* index * 4 == offset in table */
2271 M_AADDINT(REG_ITMP1, REG_ATMP2); /* offset in table */
2272 M_AADD_IMM(-(cd->dseglen), REG_ATMP2); /* start of table in dseg */
2273 M_ALD(REG_ATMP1, REG_ATMP2, 0);
2280 case ICMD_LOOKUPSWITCH: /* ..., key ==> ... */
2283 lookup_target_t *lookup;
2285 lookup = iptr->dst.lookup;
2287 i = iptr->sx.s23.s2.lookupcount;
2289 MCODECHECK((i<<2)+8);
2290 s1 = emit_load_s1(jd, iptr, REG_ITMP1);
2293 M_ICMP_IMM(lookup->value, s1);
2294 emit_beq(cd, lookup->target.block);
2298 emit_br(cd, iptr->sx.s23.s3.lookupdefault.block);
2303 case ICMD_MULTIANEWARRAY:/* ..., cnt1, [cnt2, ...] ==> ..., arrayref */
2305 /* check for negative sizes and copy sizes to stack if necessary */
2306 MCODECHECK((iptr->s1.argcount << 1) + 64);
2308 for (s1 = iptr->s1.argcount; --s1 >= 0;) {
2309 var = VAR(iptr->sx.s23.s2.args[s1]);
2311 /* Already Preallocated? */
2312 if (!(var->flags & PREALLOC)) {
2313 s2 = emit_load(jd, iptr, var, REG_ITMP1);
2314 M_IST(s2, REG_SP, (s1 + 3) * 4);
2318 /* a0 = dimension count */
2319 M_IMOV_IMM(iptr->s1.argcount, REG_ITMP1);
2320 M_IST(REG_ITMP1, REG_SP, 0*4);
2322 /* a1 = arraydescriptor */
2323 if (INSTRUCTION_IS_UNRESOLVED(iptr)) {
2324 patcher_add_patch_ref(jd, PATCHER_resolve_classref_to_classinfo, iptr->sx.s23.s3.c.ref, 0);
2325 M_AMOV_IMM(0, REG_ATMP1);
2327 M_AMOV_IMM(iptr->sx.s23.s3.c.cls, REG_ATMP1);
2329 M_AST(REG_ATMP1, REG_SP, 1*4);
2331 /* a2 = pointer to dimensions = stack pointer */
2332 M_AMOV(REG_SP, REG_ATMP1);
2333 M_AADD_IMM(3*4, REG_ATMP1);
2334 M_AST(REG_ATMP1, REG_SP, 2*4);
2336 M_JSR_IMM(BUILTIN_multianewarray);
2338 /* check for exception before result assignment */
2339 emit_exception_check(cd, iptr);
2341 assert(VAROP(iptr->dst)->type == TYPE_ADR);
2342 d = codegen_reg_of_dst(jd, iptr, REG_RESULT);
2343 M_INT2ADRMOVE(REG_RESULT, d);
2344 emit_store_dst(jd, iptr, d);
2350 printf("UNKNOWN OPCODE %d\n", iptr->opc);
2351 exceptions_throw_internalerror("Unknown ICMD %d during code generation", iptr->opc);
2354 /* M_TPF; */ /* nop after each ICMD */
2355 } /* for each instruction */
2357 /* At the end of a basic block we may have to append some nops,
2358 because the patcher stub calling code might be longer than the
2359 actual instruction. So codepatching does not change the
2360 following block unintentionally. */
2362 if (cd->mcodeptr < cd->lastmcodeptr) {
2363 while (cd->mcodeptr < cd->lastmcodeptr) {
2369 } /* if (btpre->flags >= BBREACHED) */
2370 } /* for each basic block */
2372 dseg_createlinenumbertable(cd);
2374 /* generate stubs */
2375 emit_patcher_traps(jd);
2380 /* codegen_emit_stub_compiler **************************************************
2382 Emits a stub routine which calls the compiler.
2384 *******************************************************************************/
2386 void codegen_emit_stub_compiler(jitdata *jd)
2391 /* get required compiler data */
2396 /* code for the stub */
2398 M_AMOV_IMM(m, REG_ATMP1);
2399 M_AMOV_IMM(asm_call_jit_compiler, REG_ATMP3);
2404 /* codegen_emit_stub_native ****************************************************
2406 Emits a stub routine which calls a native method.
2408 *******************************************************************************/
2410 void codegen_emit_stub_native(jitdata *jd, methoddesc *nmd, functionptr f, int skipparams)
2419 /* get required compiler data */
2428 /* calc stackframe size */
2429 cd->stackframesize =
2430 sizeof(stackframeinfo_t) / SIZEOF_VOID_P +
2431 sizeof(localref_table) / SIZEOF_VOID_P +
2433 1 + /* functionptr */
2434 4; /* args for codegen_start_native_call */
2436 /* create method header */
2437 (void) dseg_add_unique_address(cd, code); /* CodeinfoPointer */
2438 (void) dseg_add_unique_s4(cd, cd->stackframesize * 8); /* FrameSize */
2439 (void) dseg_add_unique_s4(cd, 0); /* IsSync */
2440 (void) dseg_add_unique_s4(cd, 0); /* IsLeaf */
2441 (void) dseg_add_unique_s4(cd, 0); /* IntSave */
2442 (void) dseg_add_unique_s4(cd, 0); /* FltSave */
2443 (void) dseg_addlinenumbertablesize(cd);
2444 (void) dseg_add_unique_s4(cd, 0); /* ExTableSize */
2446 /* print call trace */
2447 #if !defined(NDEBUG)
2448 if (JITDATA_HAS_FLAG_VERBOSECALL(jd)) {
2449 emit_verbosecall_enter(jd);
2454 M_AADD_IMM(-(cd->stackframesize*8), REG_SP);
2456 /* get function address (this must happen before the stackframeinfo) */
2458 patcher_add_patch_ref(jd, PATCHER_resolve_native_function, m, 0);
2461 M_AMOV_IMM(f, REG_ATMP2); /* do not move this line, the patcher is needed */
2463 M_AST(REG_ATMP2, REG_SP, 4 * 4);
2465 /* put arguments for codegen_start_native_call onto stack */
2466 /* void codegen_start_native_call(u1 *datasp, u1 *pv, u1 *sp, u1 *ra) */
2468 M_AMOV(REG_SP, REG_ATMP1);
2469 M_AST(REG_ATMP1, REG_SP, 0 * 4); /* currentsp */
2471 M_AMOV_IMM(0, REG_ATMP2); /* 0 needs to patched */
2472 dseg_adddata(cd); /* this patches it */
2474 M_AST(REG_ATMP2, REG_SP, 1 * 4); /* pv */
2476 M_JSR_IMM(codegen_start_native_call);
2478 /* remember class argument */
2479 if (m->flags & ACC_STATIC)
2480 M_INT2ADRMOVE(REG_RESULT, REG_ATMP3);
2482 /* load function pointer */
2483 M_ALD(REG_ATMP2, REG_SP, 4 * 4);
2485 /* copy arguments into stackframe */
2486 for (i = md->paramcount -1, j = i + skipparams; i >= 0; --i, --j) {
2487 t = md->paramtypes[i].type;
2488 /* all arguments via stack */
2489 assert(md->params[i].inmemory);
2491 s1 = md->params[i].regoff + cd->stackframesize * 8 + 4;
2492 s2 = nmd->params[j].regoff;
2494 /* simply copy argument stack */
2495 M_ILD(REG_ITMP1, REG_SP, s1);
2496 M_IST(REG_ITMP1, REG_SP, s2);
2497 if (IS_2_WORD_TYPE(t)) {
2498 M_ILD(REG_ITMP1, REG_SP, s1 + 4);
2499 M_IST(REG_ITMP1, REG_SP, s2 + 4);
2503 /* for static function class as second arg */
2504 if (m->flags & ACC_STATIC)
2505 M_AST(REG_ATMP3, REG_SP, 1 * 4);
2507 /* env ist first argument */
2508 M_AMOV_IMM(_Jv_env, REG_ATMP1);
2509 M_AST(REG_ATMP1, REG_SP, 0 * 4);
2511 /* call the native function */
2514 /* save return value */
2515 switch (md->returntype.type) {
2516 case TYPE_VOID: break;
2518 /* natives return float arguments in %d0, %d1, cacao expects them in %fp0 */
2521 M_IST(REG_D1, REG_SP, 2 * 8);
2527 M_IST(REG_D0, REG_SP, 2 * 8); /* XXX can this be correct ? */
2533 /* print call trace */
2534 #if ! defined(NDEBUG)
2535 if (JITDATA_HAS_FLAG_VERBOSECALL(jd)) {
2536 emit_verbosecall_exit(jd);
2539 /* remove native stackframe info */
2540 /* therefore we call: java_objectheader *codegen_finish_native_call(u1 *datasp) */
2542 M_AMOV(REG_SP, REG_ATMP1);
2543 M_AST(REG_ATMP1, REG_SP, 0 * 4); /* currentsp */
2545 M_AMOV_IMM(0, REG_ATMP2); /* 0 needs to patched */
2546 dseg_adddata(cd); /* this patches it */
2548 M_AST(REG_ATMP2, REG_SP, 1 * 4); /* pv */
2550 M_JSR_IMM(codegen_finish_native_call);
2552 M_INT2ADRMOVE(REG_RESULT, REG_ATMP1);
2553 /* restore return value */
2554 switch (md->returntype.type) {
2555 case TYPE_VOID: break;
2558 case TYPE_LNG: M_ILD(REG_D1, REG_SP, 2 * 8);
2563 M_ILD(REG_D0, REG_SP, 2 * 8); /* XXX */
2568 #if !defined(ENABLE_SOFTFLOAT)
2569 /* additionally load values into floating points registers
2570 * as cacao jit code expects them there */
2571 switch (md->returntype.type) {
2573 M_FLD(REG_D0, REG_SP, 2 * 8);
2576 M_DLD(REG_D0, REG_SP, 2 * 8); /* XXX */
2580 /* restore saved registers */
2582 M_AADD_IMM(cd->stackframesize*8, REG_SP);
2583 /* check for exception */
2588 /* handle exception, REG_ATMP1 already contains exception object, REG_ATMP2 holds address */
2590 M_ALD(REG_ATMP2_XPC, REG_SP, 0); /* take return address as faulting instruction */
2591 M_AADD_IMM(-2, REG_ATMP2_XPC); /* which is off by 2 */
2592 M_JMP_IMM(asm_handle_nat_exception);
2594 /* should never be reached from within jit code*/
2597 /* generate patcher stub call code */
2598 emit_patcher_traps(jd);
2603 * These are local overrides for various environment variables in Emacs.
2604 * Please do not remove this and leave it at the end of the file, where
2605 * Emacs will automagically detect them.
2606 * ---------------------------------------------------------------------
2609 * indent-tabs-mode: t
2613 * vim:noexpandtab:sw=4:ts=4: