]> gcc.gnu.org Git - gcc.git/blob - gcc/java/jcf-write.c
jcf-io.c (find_class): Use saw_java_source to determine when to look for `.java'...
[gcc.git] / gcc / java / jcf-write.c
1 /* Write out a Java(TM) class file.
2 Copyright (C) 1998 Free Software Foundation, Inc.
3
4 This file is part of GNU CC.
5
6 GNU CC is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10
11 GNU CC is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with GNU CC; see the file COPYING. If not, write to
17 the Free Software Foundation, 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19
20 Java and all Java-based marks are trademarks or registered trademarks
21 of Sun Microsystems, Inc. in the United States and other countries.
22 The Free Software Foundation is independent of Sun Microsystems, Inc. */
23
24 #include "config.h"
25 #include "system.h"
26 #include "tree.h"
27 #include "java-tree.h"
28 #include "jcf.h"
29 #include "obstack.h"
30 #undef AND
31 #include "rtl.h"
32 #include "java-opcodes.h"
33 #include "parse.h" /* for BLOCK_EXPR_BODY */
34 #include "buffer.h"
35
36 extern struct obstack temporary_obstack;
37
38 /* Make sure bytecode.data is big enough for at least N more bytes. */
39
40 #define RESERVE(N) \
41 do { if (state->bytecode.ptr + (N) > state->bytecode.limit) \
42 buffer_grow (&state->bytecode, N); } while (0)
43
44 /* Add a 1-byte instruction/operand I to bytecode.data,
45 assuming space has already been RESERVE'd. */
46
47 #define OP1(I) (*state->bytecode.ptr++ = (I))
48
49 /* Like OP1, but I is a 2-byte big endian integer. */
50
51 #define OP2(I) \
52 do { int _i = (I); OP1 (_i >> 8); OP1 (_i); } while (0)
53
54 /* Like OP1, but I is a 4-byte big endian integer. */
55
56 #define OP4(I) \
57 do { int _i = (I); OP1 (_i >> 24); OP1 (_i >> 16); \
58 OP1 (_i >> 8); OP1 (_i); } while (0)
59
60 /* The current stack size (stack pointer) in the current method. */
61
62 int code_SP = 0;
63
64 /* The largest extent of stack size (stack pointer) in the current method. */
65
66 int code_SP_max = 0;
67
68 CPool *code_cpool;
69
70 /* Macro to call each time we push I words on the JVM stack. */
71
72 #define NOTE_PUSH(I) \
73 do { state->code_SP += (I); \
74 if (state->code_SP > state->code_SP_max) \
75 state->code_SP_max = state->code_SP; } while (0)
76
77 /* Macro to call each time we pop I words from the JVM stack. */
78
79 #define NOTE_POP(I) \
80 do { state->code_SP -= (I); if (state->code_SP < 0) abort(); } while (0)
81
82 /* A chunk or segment of a .class file. */
83
84 struct chunk
85 {
86 /* The next segment of this .class file. */
87 struct chunk *next;
88
89 /* The actual data in this segment to be written to the .class file. */
90 unsigned char *data;
91
92 /* The size of the segment to be written to the .class file. */
93 int size;
94 };
95
96 /* Each "block" represents a label plus the bytecode instructions following.
97 There may be branches out of the block, but no incoming jumps, except
98 to the beginning of the block. */
99
100 struct jcf_block
101 {
102 /* For blocks that that are defined, the next block (in pc order).
103 For blocks that are the not-yet-defined end label of a LABELED_BLOCK_EXPR,
104 this is the next (outer) such end label, in a stack heaed by
105 labeled_blocks in jcf_partial. */
106 struct jcf_block *next;
107
108 /* Until perform_relocations is finished, this is the maximum possible
109 value of the bytecode offset at the begnning of this block.
110 After perform_relocations, it is the actual offset (pc). */
111 int pc;
112
113 int linenumber;
114
115 struct chunk *chunk;
116
117 union {
118 /* Set of relocations (in reverse offset order) for this block. */
119 struct jcf_relocation *relocations;
120
121 /* If this block is that of the not-yet-defined end label of
122 a LABELED_BLOCK_EXPR, where LABELED_BLOCK is that LABELED_BLOCK_EXPR. */
123 tree labeled_block;
124 } u;
125 };
126
127 struct jcf_relocation
128 {
129 /* Next relocation for the current jcf_block. */
130 struct jcf_relocation *next;
131
132 /* The (byte) offset within the current block that needs to be relocated. */
133 int offset;
134
135 /* 0 if offset is a 4-byte relative offset.
136 -1 if offset is a 2-byte relative offset.
137 < 0 if offset is the address of an instruction with a 2-byte offset
138 that does not have a corresponding 4-byte offset version, in which
139 case the absolute value of kind is the inverted opcode.
140 > 0 if offset is the address of an instruction (such as jsr) with a
141 2-byte offset that does have a corresponding 4-byte offset version,
142 in which case kind is the opcode of the 4-byte version (such as jsr_w). */
143 int kind;
144
145 /* The label the relocation wants to actually transfer to. */
146 struct jcf_block *label;
147 };
148
149 /* This structure is used to contain the various pieces that will
150 become a .class file. */
151
152 struct jcf_partial
153 {
154 struct chunk *first;
155 struct chunk *chunk;
156 struct obstack *chunk_obstack;
157 tree current_method;
158
159 /* List of basic blocks for the current method. */
160 struct jcf_block *blocks;
161 struct jcf_block *last_block;
162
163 struct localvar_info *first_lvar;
164 struct localvar_info *last_lvar;
165 int lvar_count;
166
167 CPool cpool;
168
169 int linenumber_count;
170
171 /* Until perform_relocations, this is a upper bound on the number
172 of bytes (so far) in the instructions for the current method. */
173 int code_length;
174
175 /* Stack of undefined ending labels for LABELED_BLOCK_EXPR. */
176 struct jcf_block *labeled_blocks;
177
178 /* The current stack size (stack pointer) in the current method. */
179 int code_SP;
180
181 /* The largest extent of stack size (stack pointer) in the current method. */
182 int code_SP_max;
183
184 /* Contains a mapping from local var slot number to localvar_info. */
185 struct buffer localvars;
186
187 /* The buffer allocated for bytecode for the current jcf_block. */
188 struct buffer bytecode;
189 };
190
191 static void generate_bytecode_insns PROTO ((tree, int, struct jcf_partial *));
192
193 /* Utility macros for appending (big-endian) data to a buffer.
194 We assume a local variable 'ptr' points into where we want to
195 write next, and we assume enoygh space has been allocated. */
196
197 #define PUT1(X) (*ptr++ = (X))
198 #define PUT2(X) (PUT1((X) >> 8), PUT1((X) & 0xFF))
199 #define PUT4(X) (PUT2((X) >> 16), PUT2((X) & 0xFFFF))
200 #define PUTN(P, N) (bcopy(P, ptr, N), ptr += (N))
201
202 \f
203 /* Allocate a new chunk on obstack WORK, and link it in after LAST.
204 Set the data and size fields to DATA and SIZE, respectively.
205 However, if DATA is NULL and SIZE>0, allocate a buffer as well. */
206
207 struct chunk *
208 alloc_chunk (last, data, size, work)
209 struct chunk *last;
210 unsigned char *data;
211 int size;
212 struct obstack *work;
213 {
214 struct chunk *chunk = (struct chunk *)
215 obstack_alloc (work, sizeof(struct chunk));
216
217 if (data == NULL && size > 0)
218 data = obstack_alloc (work, size);
219
220 chunk->next = NULL;
221 chunk->data = data;
222 chunk->size = size;
223 if (last != NULL)
224 last->next = chunk;
225 return chunk;
226 }
227
228 unsigned char *
229 append_chunk (data, size, state)
230 unsigned char *data;
231 int size;
232 struct jcf_partial *state;
233 {
234 state->chunk = alloc_chunk (state->chunk, data, size, state->chunk_obstack);
235 if (state->first == NULL)
236 state->first = state->chunk;
237 return state->chunk->data;
238 }
239
240 void
241 append_chunk_copy (data, size, state)
242 unsigned char *data;
243 int size;
244 struct jcf_partial *state;
245 {
246 unsigned char *ptr = append_chunk (NULL, size, state);
247 bcopy (data, ptr, size);
248 }
249 \f
250 struct jcf_block *
251 gen_jcf_label (state)
252 struct jcf_partial *state;
253 {
254 struct jcf_block *block = (struct jcf_block *)
255 obstack_alloc (state->chunk_obstack, sizeof (struct jcf_block));
256 block->next = NULL;
257 block->linenumber = -1;
258 block->pc = -1;
259 return block;
260 }
261
262 void
263 finish_jcf_block (state)
264 struct jcf_partial *state;
265 {
266 struct jcf_block *block = state->last_block;
267 struct jcf_relocation *reloc;
268 int pc = state->code_length;
269 append_chunk_copy (state->bytecode.data, BUFFER_LENGTH (&state->bytecode),
270 state);
271 BUFFER_RESET (&state->bytecode);
272 block->chunk = state->chunk;
273
274 /* Calculate code_length to the maximum value it can have. */
275 pc += block->chunk->size;
276 for (reloc = block->u.relocations; reloc != NULL; reloc = reloc->next)
277 {
278 int kind = reloc->kind;
279 if (kind > 0)
280 pc += 2; /* 2-byte offset may grow to 4-byte offset */
281 else if (kind < -1)
282 pc += 5; /* May need to add a goto_w. */
283 }
284 state->code_length = pc;
285 }
286
287 void
288 define_jcf_label (label, state)
289 struct jcf_block *label;
290 struct jcf_partial *state;
291 {
292 if (state->last_block != NULL)
293 finish_jcf_block (state);
294 label->pc = state->code_length;
295 if (state->blocks == NULL)
296 state->blocks = label;
297 else
298 state->last_block->next = label;
299 state->last_block = label;
300 label->next = NULL;
301 label->u.relocations = NULL;
302 }
303
304 struct jcf_block *
305 get_jcf_label_here (state)
306 struct jcf_partial *state;
307 {
308 if (state->last_block != NULL && BUFFER_LENGTH (&state->bytecode) == 0)
309 return state->last_block;
310 else
311 {
312 struct jcf_block *label = gen_jcf_label (state);
313 define_jcf_label (label, state);
314 return label;
315 }
316 }
317
318 /* Note a line number entry for the current PC and given LINE. */
319
320 void
321 put_linenumber (line, state)
322 int line;
323 struct jcf_partial *state;
324 {
325 (get_jcf_label_here (state))->linenumber = line;
326 state->linenumber_count++;
327 }
328
329 \f
330 /* The index of jvm local variable allocated for this DECL.
331 This is assigned when generating .class files;
332 contrast DECL_LOCAL_SLOT_NUMBER which is set when *reading* a .class file.
333 (We don't allocate DECL_LANG_SPECIFIC for locals from Java sourc code.) */
334
335 #define DECL_LOCAL_INDEX(DECL) DECL_ALIGN(DECL)
336
337 struct localvar_info
338 {
339 struct localvar_info *next;
340
341 tree decl;
342 struct jcf_block *start_label;
343 struct jcf_block *end_label;
344 };
345
346 #define localvar_buffer ((struct localvar_info**) state->localvars.data)
347 #define localvar_max \
348 ((struct localvar_info**) state->localvars.ptr - localvar_buffer)
349
350 void
351 localvar_alloc (decl, state)
352 tree decl;
353 struct jcf_partial *state;
354 {
355 struct jcf_block *start_label = get_jcf_label_here (state);
356 int wide = TYPE_IS_WIDE (TREE_TYPE (decl));
357 int index;
358 register struct localvar_info *info;
359 register struct localvar_info **ptr = localvar_buffer;
360 register struct localvar_info **limit
361 = (struct localvar_info**) state->localvars.ptr;
362 for (index = 0; ptr < limit; index++, ptr++)
363 {
364 if (ptr[0] == NULL
365 && (! wide || ((ptr+1) < limit && ptr[1] == NULL)))
366 break;
367 }
368 if (ptr == limit)
369 {
370 buffer_grow (&state->localvars, 2 * sizeof (struct localvar_info*));
371 ptr = (struct localvar_info**) state->localvars.data + index;
372 state->localvars.ptr = (unsigned char *) (ptr + 1 + wide);
373 }
374 info = (struct localvar_info *)
375 obstack_alloc (state->chunk_obstack, sizeof (struct localvar_info));
376 ptr[0] = info;
377 if (wide)
378 ptr[1] = (struct localvar_info *)(~0);
379 DECL_LOCAL_INDEX (decl) = index;
380 info->decl = decl;
381 info->start_label = start_label;
382
383 if (DECL_NAME (decl) != NULL_TREE)
384 {
385 /* Generate debugging info. */
386 info->next = NULL;
387 if (state->last_lvar != NULL)
388 state->last_lvar->next = info;
389 else
390 state->first_lvar = info;
391 state->last_lvar = info;
392 state->lvar_count++;
393 }
394 }
395
396 int
397 localvar_free (decl, state)
398 tree decl;
399 struct jcf_partial *state;
400 {
401 struct jcf_block *end_label = get_jcf_label_here (state);
402 int index = DECL_LOCAL_INDEX (decl);
403 register struct localvar_info **ptr = &localvar_buffer [index];
404 register struct localvar_info *info = *ptr;
405 int wide = TYPE_IS_WIDE (TREE_TYPE (decl));
406
407 info->end_label = end_label;
408
409 if (info->decl != decl)
410 abort ();
411 ptr[0] = NULL;
412 if (wide)
413 {
414 if (ptr[1] != (struct localvar_info *)(~0))
415 abort ();
416 ptr[1] = NULL;
417 }
418 }
419
420 \f
421 #define STACK_TARGET 1
422 #define IGNORE_TARGET 2
423
424 /* Get the access flags of a class (TYPE_DECL), a method (FUNCTION_DECL), or
425 a field (FIELD_DECL or VAR_DECL, if static), as encoded in a .class file. */
426
427 int
428 get_access_flags (decl)
429 tree decl;
430 {
431 int flags = 0;
432 int isfield = TREE_CODE (decl) == FIELD_DECL || TREE_CODE (decl) == VAR_DECL;
433 if (CLASS_PUBLIC (decl)) /* same as FIELD_PUBLIC and METHOD_PUBLIC */
434 flags |= ACC_PUBLIC;
435 if (CLASS_FINAL (decl)) /* same as FIELD_FINAL and METHOD_FINAL */
436 flags |= ACC_PUBLIC;
437 if (isfield || TREE_CODE (decl) == FUNCTION_DECL)
438 {
439 if (TREE_PROTECTED (decl))
440 flags |= ACC_PROTECTED;
441 if (TREE_PRIVATE (decl))
442 flags |= ACC_PRIVATE;
443 }
444 else if (TREE_CODE (decl) == TYPE_DECL)
445 {
446 if (CLASS_SUPER (decl))
447 flags |= ACC_SUPER;
448 if (CLASS_ABSTRACT (decl))
449 flags |= ACC_ABSTRACT;
450 if (CLASS_INTERFACE (decl))
451 flags |= ACC_INTERFACE;
452 }
453 else
454 fatal ("internal error - bad argument to get_access_flags");
455 if (TREE_CODE (decl) == FUNCTION_DECL)
456 {
457 if (METHOD_NATIVE (decl))
458 flags |= ACC_NATIVE;
459 if (METHOD_STATIC (decl))
460 flags |= ACC_STATIC;
461 if (METHOD_FINAL (decl))
462 flags |= ACC_FINAL;
463 if (METHOD_SYNCHRONIZED (decl))
464 flags |= ACC_SYNCHRONIZED;
465 if (METHOD_ABSTRACT (decl))
466 flags |= ACC_ABSTRACT;
467 }
468 if (isfield)
469 {
470 if (FIELD_STATIC (decl))
471 flags |= ACC_STATIC;
472 if (FIELD_VOLATILE (decl))
473 flags |= ACC_VOLATILE;
474 if (FIELD_TRANSIENT (decl))
475 flags |= ACC_TRANSIENT;
476 }
477 return flags;
478 }
479
480 /* Write the list of segments starting at CHUNKS to STREAM. */
481
482 void
483 write_chunks (stream, chunks)
484 FILE* stream;
485 struct chunk *chunks;
486 {
487 for (; chunks != NULL; chunks = chunks->next)
488 fwrite (chunks->data, chunks->size, 1, stream);
489 }
490
491 static void
492 push_constant1 (index, state)
493 int index;
494 struct jcf_partial *state;
495 {
496 if (index < 256)
497 {
498 OP1 (OPCODE_ldc);
499 OP1 (index);
500 }
501 else
502 {
503 OP1 (OPCODE_ldc_w);
504 OP2 (index);
505 }
506 }
507
508 static void
509 push_constant2 (index, state)
510 int index;
511 struct jcf_partial *state;
512 {
513 RESERVE (3);
514 OP1 (OPCODE_ldc2_w);
515 OP2 (index);
516 }
517
518 /* Push 32-bit integer constant on VM stack.
519 Caller is responsible for doing NOTE_PUSH. */
520
521 static void
522 push_int_const (i, state)
523 HOST_WIDE_INT i;
524 struct jcf_partial *state;
525 {
526 RESERVE(3);
527 if (i >= -1 && i <= 5)
528 OP1(OPCODE_iconst_0 + i);
529 else if (i >= -128 && i < 128)
530 {
531 OP1(OPCODE_bipush);
532 OP1(i);
533 }
534 else if (i >= -32768 && i < 32768)
535 {
536 OP1(OPCODE_sipush);
537 OP2(i);
538 NOTE_PUSH (1);
539 }
540 else
541 {
542 i = find_constant1 (&state->cpool, CONSTANT_Integer, i & 0xFFFFFFFF);
543 push_constant1 (i);
544 }
545 }
546
547 /* Push 64-bit long constant on VM stack.
548 Caller is responsible for doing NOTE_PUSH. */
549
550 static void
551 push_long_const (lo, hi, state)
552 HOST_WIDE_INT lo, hi;
553 struct jcf_partial *state;
554 {
555 if (hi == 0 && lo >= 0 && lo <= 1)
556 {
557 RESERVE(1);
558 OP1(OPCODE_lconst_0 + lo);
559 }
560 #if 0
561 else if ((jlong) (jint) i == i)
562 {
563 push_int_const ((jint) i, state);
564 RESERVE (1);
565 OP1 (OPCODE_i2l);
566 }
567 #endif
568 else
569 {
570 HOST_WIDE_INT w1, w2;
571 lshift_double (lo, hi, -32, 64, &w1, &w2, 1);
572 hi = find_constant1 (&state->cpool, CONSTANT_Long,
573 w1 & 0xFFFFFFFF, lo & 0xFFFFFFFF);
574 push_constant2 (hi);
575 }
576 }
577
578 static void
579 field_op (field, opcode, state)
580 tree field;
581 int opcode;
582 struct jcf_partial *state;
583 {
584 int index = find_fieldref_index (&state->cpool, field);
585 RESERVE (3);
586 OP1 (opcode);
587 OP2 (index);
588 }
589
590 /* Returns an integer in the range 0 (for 'int') through 4 (for object
591 reference) to 7 (for 'short') which matches the pattern of how JVM
592 opcodes typically depend on the operand type. */
593
594 int
595 adjust_typed_op (type)
596 tree type;
597 {
598 switch (TREE_CODE (type))
599 {
600 case POINTER_TYPE:
601 case RECORD_TYPE: return 4;
602 case BOOLEAN_TYPE:
603 return TYPE_PRECISION (type) == 32 ? 0 : 5;
604 case CHAR_TYPE:
605 return TYPE_PRECISION (type) == 32 ? 0 : 6;
606 case INTEGER_TYPE:
607 switch (TYPE_PRECISION (type))
608 {
609 case 8: return 5;
610 case 16: return 7;
611 case 32: return 0;
612 case 64: return 1;
613 }
614 break;
615 case REAL_TYPE:
616 switch (TYPE_PRECISION (type))
617 {
618 case 32: return 2;
619 case 64: return 3;
620 }
621 break;
622 }
623 abort ();
624 }
625
626 static void
627 maybe_wide (opcode, index, state)
628 int opcode, index;
629 struct jcf_partial *state;
630 {
631 if (index >= 256)
632 {
633 RESERVE (4);
634 OP1 (OPCODE_wide);
635 OP1 (opcode);
636 OP2 (index);
637 }
638 else
639 {
640 RESERVE (2);
641 OP1 (opcode);
642 OP1 (index);
643 }
644 }
645
646 /* Compile code to duplicate with offset, where
647 SIZE is the size of the stack item to duplicate (1 or 2), abd
648 OFFSET is where to insert the result (must be 0, 1, or 2).
649 (The new words get inserted at stack[SP-size-offset].) */
650
651 static void
652 emit_dup (size, offset, state)
653 int size, offset;
654 struct jcf_partial *state;
655 {
656 int kind;
657 if (size == 0)
658 return;
659 RESERVE(1);
660 if (offset == 0)
661 kind = size == 1 ? OPCODE_dup : OPCODE_dup2;
662 else if (offset == 1)
663 kind = size == 1 ? OPCODE_dup_x1 : OPCODE_dup2_x1;
664 else if (offset == 2)
665 kind = size == 1 ? OPCODE_dup_x2 : OPCODE_dup2_x2;
666 else
667 abort();
668 OP1 (kind);
669 NOTE_PUSH (size);
670 }
671
672 static void
673 emit_pop (size, state)
674 int size;
675 struct jcf_partial *state;
676 {
677 RESERVE (1);
678 OP1 (OPCODE_pop - 1 + size);
679 }
680
681 static void
682 emit_iinc (var, value, state)
683 tree var;
684 int value;
685 struct jcf_partial *state;
686 {
687 int slot = DECL_LOCAL_INDEX (var);
688
689 if (value < -128 || value > 127 || slot >= 256)
690 {
691 RESERVE (6);
692 OP1 (OPCODE_wide);
693 OP1 (OPCODE_iinc);
694 OP2 (slot);
695 OP2 (value);
696 }
697 else
698 {
699 RESERVE (3);
700 OP1 (OPCODE_iinc);
701 OP1 (slot);
702 OP1 (value);
703 }
704 }
705
706 static void
707 emit_load_or_store (var, opcode, state)
708 tree var;
709 struct jcf_partial *state;
710 {
711 tree type = TREE_TYPE (var);
712 int kind = adjust_typed_op (type);
713 int index = DECL_LOCAL_INDEX (var);
714 if (index <= 3)
715 {
716 RESERVE (1);
717 OP1 (opcode + 5 + 4 * kind + index); /* [ilfda]{load,store}_[0123] */
718 }
719 else
720 maybe_wide (opcode + kind, index); /* [ilfda]{load,store} */
721 }
722
723 static void
724 emit_load (var, state)
725 tree var;
726 struct jcf_partial *state;
727 {
728 emit_load_or_store (var, OPCODE_iload, state);
729 NOTE_PUSH (TYPE_IS_WIDE (TREE_TYPE (var)) ? 2 : 1);
730 }
731
732 static void
733 emit_store (var, state)
734 tree var;
735 struct jcf_partial *state;
736 {
737 emit_load_or_store (var, OPCODE_istore, state);
738 NOTE_POP (TYPE_IS_WIDE (TREE_TYPE (var)) ? 2 : 1);
739 }
740
741 static void
742 emit_binop (opcode, type, state)
743 enum java_opcode opcode;
744 tree type;
745 struct jcf_partial *state;
746 {
747 int size = TYPE_IS_WIDE (type) ? 2 : 1;
748 RESERVE(1);
749 OP1 (opcode);
750 NOTE_POP (size);
751 }
752
753 /* Emit a conditional jump to TARGET with a 2-byte relative jump offset
754 The opcode is OPCODE, the inverted opcode is INV_OPCODE. */
755
756 static void
757 emit_if (target, opcode, inv_opcode, state)
758 struct jcf_block *target;
759 int opcode, inv_opcode;
760 struct jcf_partial *state;
761 {
762 struct jcf_relocation *reloc = (struct jcf_relocation *)
763 obstack_alloc (state->chunk_obstack, sizeof (struct jcf_relocation));
764 struct jcf_block *block = state->last_block;
765 reloc->next = block->u.relocations;
766 block->u.relocations = reloc;
767 OP1 (opcode);
768 reloc->offset = BUFFER_LENGTH (&state->bytecode);
769 OP2 (1); // 1 byte from reloc back to start of instruction.
770 reloc->kind = - inv_opcode;
771 reloc->label = target;
772 }
773
774 static void
775 emit_goto_or_jsr (target, opcode, opcode_w, state)
776 struct jcf_block *target;
777 int opcode, opcode_w;
778 struct jcf_partial *state;
779 {
780 struct jcf_relocation *reloc = (struct jcf_relocation *)
781 obstack_alloc (state->chunk_obstack, sizeof (struct jcf_relocation));
782 struct jcf_block *block = state->last_block;
783 reloc->next = block->u.relocations;
784 block->u.relocations = reloc;
785 OP1 (opcode);
786 reloc->offset = BUFFER_LENGTH (&state->bytecode);
787 OP2 (1); // 1 byte from reloc back to start of instruction.
788 reloc->kind = opcode_w;
789 reloc->label = target;
790 }
791
792 static void
793 emit_goto (target, state)
794 struct jcf_block *target;
795 struct jcf_partial *state;
796 {
797 emit_goto_or_jsr (target, OPCODE_goto, OPCODE_goto_w, state);
798 }
799
800 static void
801 emit_jsr (target, state)
802 struct jcf_block *target;
803 struct jcf_partial *state;
804 {
805 emit_goto_or_jsr (target, OPCODE_jsr, OPCODE_jsr_w, state);
806 }
807
808 /* Generate code to evaluate EXP. If the result is true,
809 branch to TRUE_LABEL; otherwise, branch to FALSE_LABEL.
810 TRUE_BRANCH_FIRST is a code geneation hint that the
811 TRUE_LABEL may follow right after this. (The idea is that we
812 may be able to optimize away GOTO TRUE_LABEL; TRUE_LABEL:) */
813
814 void
815 generate_bytecode_conditional (exp, true_label, false_label,
816 true_branch_first, state)
817 tree exp;
818 struct jcf_block *true_label;
819 struct jcf_block *false_label;
820 int true_branch_first;
821 struct jcf_partial *state;
822 {
823 int kind;
824 tree exp0, exp1, type;
825 int save_SP = state->code_SP;
826 enum java_opcode op, negop;
827 switch (TREE_CODE (exp))
828 {
829 case INTEGER_CST:
830 emit_goto (integer_zerop (exp) ? false_label : true_label, state);
831 break;
832 case COND_EXPR:
833 {
834 struct jcf_block *then_label = gen_jcf_label (state);
835 struct jcf_block *else_label = gen_jcf_label (state);
836 int save_SP_before, save_SP_after;
837 generate_bytecode_conditional (TREE_OPERAND (exp, 0),
838 then_label, else_label, 1, state);
839 define_jcf_label (then_label, state);
840 save_SP_before = state->code_SP;
841 generate_bytecode_conditional (TREE_OPERAND (exp, 1),
842 true_label, false_label, 1, state);
843 save_SP_after = state->code_SP;
844 state->code_SP = save_SP_before;
845 define_jcf_label (else_label, state);
846 generate_bytecode_conditional (TREE_OPERAND (exp, 2),
847 true_label, false_label,
848 true_branch_first, state);
849 if (state->code_SP != save_SP_after)
850 fatal ("internal error non-matching SP");
851 }
852 break;
853 case TRUTH_ANDIF_EXPR:
854 {
855 struct jcf_block *next_label = gen_jcf_label (state);
856 generate_bytecode_conditional (TREE_OPERAND (exp, 0),
857 next_label, false_label, 1, state);
858 define_jcf_label (next_label, state);
859 generate_bytecode_conditional (TREE_OPERAND (exp, 1),
860 true_label, false_label, 1, state);
861 }
862 break;
863 case TRUTH_ORIF_EXPR:
864 {
865 struct jcf_block *next_label = gen_jcf_label (state);
866 generate_bytecode_conditional (TREE_OPERAND (exp, 0),
867 true_label, next_label, 1, state);
868 define_jcf_label (next_label, state);
869 generate_bytecode_conditional (TREE_OPERAND (exp, 1),
870 true_label, false_label, 1, state);
871 }
872 break;
873 compare_1:
874 /* Assuming op is one of the 2-operand if_icmp<COND> instructions,
875 set it to the corresponding 1-operand if<COND> instructions. */
876 op = op - 6;
877 /* FALLTHROUGH */
878 compare_2:
879 /* The opcodes with their inverses are allocated in pairs.
880 E.g. The inverse of if_icmplt (161) is if_icmpge (162). */
881 negop = (op & 1) ? op + 1 : op - 1;
882 compare_2_ptr:
883 if (true_branch_first)
884 {
885 emit_if (false_label, negop, op, state);
886 emit_goto (true_label, state);
887 }
888 else
889 {
890 emit_if (true_label, op, negop, state);
891 emit_goto (false_label, state);
892 }
893 break;
894 case EQ_EXPR:
895 op = OPCODE_if_icmpeq;
896 goto compare;
897 case NE_EXPR:
898 op = OPCODE_if_icmpne;
899 goto compare;
900 case GT_EXPR:
901 op = OPCODE_if_icmpgt;
902 goto compare;
903 case LT_EXPR:
904 op = OPCODE_if_icmplt;
905 goto compare;
906 case GE_EXPR:
907 op = OPCODE_if_icmpge;
908 goto compare;
909 case LE_EXPR:
910 op = OPCODE_if_icmple;
911 goto compare;
912 compare:
913 exp0 = TREE_OPERAND (exp, 0);
914 exp1 = TREE_OPERAND (exp, 1);
915 type = TREE_TYPE (exp0);
916 switch (TREE_CODE (type))
917 {
918 case POINTER_TYPE: case RECORD_TYPE:
919 switch (TREE_CODE (exp))
920 {
921 case EQ_EXPR: op = OPCODE_if_acmpeq; break;
922 case NE_EXPR: op = OPCODE_if_acmpne; break;
923 default: abort();
924 }
925 if (integer_zerop (exp1) || integer_zerop (exp0))
926 {
927 generate_bytecode_insns (integer_zerop (exp1) ? exp0 : exp0,
928 STACK_TARGET, state);
929 op = op + (OPCODE_ifnull - OPCODE_if_acmpeq);
930 negop = (op & 1) ? op - 1 : op + 1;
931 NOTE_POP (1);
932 goto compare_2_ptr;
933 }
934 generate_bytecode_insns (exp0, STACK_TARGET, state);
935 generate_bytecode_insns (exp1, STACK_TARGET, state);
936 NOTE_POP (2);
937 goto compare_2;
938 case REAL_TYPE:
939 fatal ("float comparison not implemented");
940 case INTEGER_TYPE:
941 if (TYPE_PRECISION (type) > 32)
942 {
943 generate_bytecode_insns (exp0, STACK_TARGET, state);
944 generate_bytecode_insns (exp1, STACK_TARGET, state);
945 NOTE_POP (4);
946 RESERVE (1);
947 OP1 (OPCODE_lcmp);
948 goto compare_1;
949 }
950 /* FALLTHOUGH */
951 default:
952 if (integer_zerop (exp1))
953 {
954 generate_bytecode_insns (exp0, STACK_TARGET, state);
955 NOTE_POP (1);
956 goto compare_1;
957 }
958 if (integer_zerop (exp0))
959 {
960 switch (op)
961 {
962 case OPCODE_if_icmplt:
963 case OPCODE_if_icmpge:
964 op += 2;
965 break;
966 case OPCODE_if_icmpgt:
967 case OPCODE_if_icmple:
968 op -= 2;
969 break;
970 }
971 generate_bytecode_insns (exp1, STACK_TARGET, state);
972 NOTE_POP (1);
973 goto compare_1;
974 }
975 generate_bytecode_insns (exp0, STACK_TARGET, state);
976 generate_bytecode_insns (exp1, STACK_TARGET, state);
977 NOTE_POP (2);
978 goto compare_2;
979 }
980
981 default:
982 generate_bytecode_insns (exp, STACK_TARGET, state);
983 NOTE_POP (1);
984 if (true_branch_first)
985 {
986 emit_if (false_label, OPCODE_ifeq, OPCODE_ifne, state);
987 emit_goto (true_label, state);
988 }
989 else
990 {
991 emit_if (true_label, OPCODE_ifne, OPCODE_ifeq, state);
992 emit_goto (false_label, state);
993 }
994 break;
995 }
996 if (save_SP != state->code_SP)
997 fatal ("inetrnal error - SP mismatch");
998 }
999
1000 /* Generate bytecode for sub-expression EXP of METHOD.
1001 TARGET is one of STACK_TARGET or IGNORE_TARGET. */
1002
1003 static void
1004 generate_bytecode_insns (exp, target, state)
1005 tree exp;
1006 int target;
1007 struct jcf_partial *state;
1008 {
1009 tree type;
1010 enum java_opcode jopcode;
1011 int op;
1012 HOST_WIDE_INT value;
1013 int post_op;
1014 int size;
1015 int offset;
1016
1017 if (exp == NULL && target == IGNORE_TARGET)
1018 return;
1019
1020 type = TREE_TYPE (exp);
1021
1022 switch (TREE_CODE (exp))
1023 {
1024 case BLOCK:
1025 if (BLOCK_EXPR_BODY (exp))
1026 {
1027 tree local;
1028 for (local = BLOCK_EXPR_DECLS (exp); local; )
1029 {
1030 tree next = TREE_CHAIN (local);
1031 localvar_alloc (local, state);
1032 local = next;
1033 }
1034 generate_bytecode_insns (BLOCK_EXPR_BODY (exp), target, state);
1035 for (local = BLOCK_EXPR_DECLS (exp); local; )
1036 {
1037 tree next = TREE_CHAIN (local);
1038 localvar_free (local, state);
1039 local = next;
1040 }
1041 }
1042 break;
1043 case COMPOUND_EXPR:
1044 generate_bytecode_insns (TREE_OPERAND (exp, 0), IGNORE_TARGET, state);
1045 generate_bytecode_insns (TREE_OPERAND (exp, 1), target, state);
1046 break;
1047 case EXPR_WITH_FILE_LOCATION:
1048 {
1049 char *saved_input_filename = input_filename;
1050 int saved_lineno = lineno;
1051 input_filename = EXPR_WFL_FILENAME (exp);
1052 lineno = EXPR_WFL_LINENO (exp);
1053 if (EXPR_WFL_EMIT_LINE_NOTE (exp))
1054 put_linenumber (EXPR_WFL_LINENO (exp), state);
1055 generate_bytecode_insns (EXPR_WFL_NODE (exp), target, state);
1056 input_filename = saved_input_filename;
1057 lineno = saved_lineno;
1058 }
1059 break;
1060 case INTEGER_CST:
1061 if (target == IGNORE_TARGET) ; /* do nothing */
1062 else if (TREE_CODE (type) == POINTER_TYPE)
1063 {
1064 if (! integer_zerop (exp))
1065 abort();
1066 RESERVE(1);
1067 OP1 (OPCODE_aconst_null);
1068 NOTE_PUSH (1);
1069 }
1070 else if (TYPE_PRECISION (type) <= 32)
1071 {
1072 push_int_const (TREE_INT_CST_LOW (exp), state);
1073 NOTE_PUSH (1);
1074 }
1075 else
1076 {
1077 push_long_const (TREE_INT_CST_LOW (exp), TREE_INT_CST_HIGH (exp),
1078 state);
1079 NOTE_PUSH (2);
1080 }
1081 break;
1082 case VAR_DECL:
1083 if (TREE_STATIC (exp))
1084 {
1085 field_op (exp, OPCODE_getstatic, state);
1086 NOTE_PUSH (TYPE_IS_WIDE (TREE_TYPE (exp)) ? 2 : 1);
1087 break;
1088 }
1089 /* ... fall through ... */
1090 case PARM_DECL:
1091 emit_load (exp, state);
1092 break;
1093 case INDIRECT_REF:
1094 generate_bytecode_insns (TREE_OPERAND (exp, 0), target, state);
1095 break;
1096 case ARRAY_REF:
1097 generate_bytecode_insns (TREE_OPERAND (exp, 0), target, state);
1098 generate_bytecode_insns (TREE_OPERAND (exp, 1), target, state);
1099 if (target != IGNORE_TARGET)
1100 {
1101 jopcode = OPCODE_iaload + adjust_typed_op (type);
1102 RESERVE(1);
1103 OP1 (jopcode);
1104 NOTE_POP (2);
1105 }
1106 break;
1107 case COMPONENT_REF:
1108 {
1109 tree obj = TREE_OPERAND (exp, 0);
1110 tree field = TREE_OPERAND (exp, 1);
1111 int is_static = FIELD_STATIC (field);
1112 generate_bytecode_insns (obj,
1113 is_static ? IGNORE_TARGET : target, state);
1114 if (target != IGNORE_TARGET)
1115 {
1116 if (DECL_NAME (field) == length_identifier_node && !is_static
1117 && TYPE_ARRAY_P (TREE_TYPE (obj)))
1118 {
1119 RESERVE (1);
1120 OP1 (OPCODE_arraylength);
1121 }
1122 else
1123 {
1124 field_op (field, is_static ? OPCODE_getstatic : OPCODE_getfield,
1125 state);
1126 if (! is_static)
1127 NOTE_POP (1);
1128 NOTE_PUSH (TYPE_IS_WIDE (TREE_TYPE (field)) ? 2 : 1);
1129 }
1130 }
1131 }
1132 break;
1133 case TRUTH_ANDIF_EXPR:
1134 case TRUTH_ORIF_EXPR:
1135 case EQ_EXPR:
1136 case NE_EXPR:
1137 case GT_EXPR:
1138 case LT_EXPR:
1139 case GE_EXPR:
1140 case LE_EXPR:
1141 {
1142 struct jcf_block *then_label = gen_jcf_label (state);
1143 struct jcf_block *else_label = gen_jcf_label (state);
1144 struct jcf_block *end_label = gen_jcf_label (state);
1145 generate_bytecode_conditional (exp,
1146 then_label, else_label, 1, state);
1147 define_jcf_label (then_label, state);
1148 push_int_const (1, state);
1149 emit_goto (end_label, state);
1150 define_jcf_label (else_label, state);
1151 push_int_const (0, state);
1152 define_jcf_label (end_label, state);
1153 NOTE_PUSH (1);
1154 }
1155 break;
1156 case COND_EXPR:
1157 {
1158 struct jcf_block *then_label = gen_jcf_label (state);
1159 struct jcf_block *else_label = gen_jcf_label (state);
1160 struct jcf_block *end_label = gen_jcf_label (state);
1161 generate_bytecode_conditional (TREE_OPERAND (exp, 0),
1162 then_label, else_label, 1, state);
1163 define_jcf_label (then_label, state);
1164 generate_bytecode_insns (TREE_OPERAND (exp, 1), target, state);
1165 emit_goto (end_label, state);
1166 define_jcf_label (else_label, state);
1167 generate_bytecode_insns (TREE_OPERAND (exp, 2), target, state);
1168 define_jcf_label (end_label, state);
1169 }
1170 break;
1171 case RETURN_EXPR:
1172 if (!TREE_OPERAND (exp, 0))
1173 op = OPCODE_return;
1174 else
1175 {
1176 exp = TREE_OPERAND (exp, 0);
1177 if (TREE_CODE (exp) != MODIFY_EXPR)
1178 abort ();
1179 exp = TREE_OPERAND (exp, 1);
1180 op = OPCODE_ireturn + adjust_typed_op (TREE_TYPE (exp));
1181 generate_bytecode_insns (exp, STACK_TARGET, state);
1182 }
1183 RESERVE (1);
1184 OP1 (op);
1185 break;
1186 case LABELED_BLOCK_EXPR:
1187 {
1188 struct jcf_block *end_label = gen_jcf_label (state);
1189 end_label->next = state->labeled_blocks;
1190 state->labeled_blocks = end_label;
1191 end_label->u.labeled_block = exp;
1192 if (LABELED_BLOCK_BODY (exp))
1193 generate_bytecode_insns (LABELED_BLOCK_BODY (exp), target, state);
1194 if (state->labeled_blocks != end_label)
1195 abort();
1196 state->labeled_blocks = end_label->next;
1197 define_jcf_label (end_label, state);
1198 }
1199 break;
1200 case LOOP_EXPR:
1201 {
1202 tree body = TREE_OPERAND (exp, 0);
1203 #if 0
1204 if (TREE_CODE (body) == COMPOUND_EXPR
1205 && TREE_CODE (TREE_OPERAND (body, 0)) == EXIT_EXPR)
1206 {
1207 /* Optimize: H: if (TEST) GOTO L; BODY; GOTO H; L:
1208 to: GOTO L; BODY; L: if (!TEST) GOTO L; */
1209 struct jcf_block *head_label;
1210 struct jcf_block *body_label;
1211 struct jcf_block *end_label = gen_jcf_label (state);
1212 struct jcf_block *exit_label = state->labeled_blocks;
1213 head_label = gen_jcf_label (state);
1214 emit_goto (head_label, state);
1215 body_label = get_jcf_label_here (state);
1216 generate_bytecode_insns (TREE_OPERAND (body, 1), target, state);
1217 define_jcf_label (head_label, state);
1218 generate_bytecode_conditional (TREE_OPERAND (body, 0),
1219 end_label, body_label, 1, state);
1220 define_jcf_label (end_label, state);
1221 }
1222 else
1223 #endif
1224 {
1225 struct jcf_block *head_label = get_jcf_label_here (state);
1226 generate_bytecode_insns (body, IGNORE_TARGET, state);
1227 emit_goto (head_label, state);
1228 }
1229 }
1230 break;
1231 case EXIT_EXPR:
1232 {
1233 struct jcf_block *label = state->labeled_blocks;
1234 struct jcf_block *end_label = gen_jcf_label (state);
1235 generate_bytecode_conditional (TREE_OPERAND (exp, 0),
1236 label, end_label, 0, state);
1237 define_jcf_label (end_label, state);
1238 }
1239 break;
1240 case EXIT_BLOCK_EXPR:
1241 {
1242 struct jcf_block *label = state->labeled_blocks;
1243 if (TREE_OPERAND (exp, 1) != NULL) goto notimpl;
1244 while (label->u.labeled_block != TREE_OPERAND (exp, 0))
1245 label = label->next;
1246 emit_goto (label, state);
1247 }
1248 break;
1249
1250 case PREDECREMENT_EXPR: value = -1; post_op = 0; goto increment;
1251 case PREINCREMENT_EXPR: value = 1; post_op = 0; goto increment;
1252 case POSTDECREMENT_EXPR: value = -1; post_op = 1; goto increment;
1253 case POSTINCREMENT_EXPR: value = 1; post_op = 1; goto increment;
1254 increment:
1255
1256 exp = TREE_OPERAND (exp, 0);
1257 type = TREE_TYPE (exp);
1258 size = TYPE_IS_WIDE (type) ? 2 : 1;
1259 if ((TREE_CODE (exp) == VAR_DECL || TREE_CODE (exp) == PARM_DECL)
1260 && ! TREE_STATIC (exp)
1261 && TREE_CODE (type) == INTEGER_TYPE
1262 && TYPE_PRECISION (type) == 32)
1263 {
1264 if (target != IGNORE_TARGET && post_op)
1265 emit_load (exp, state);
1266 emit_iinc (exp, value, state);
1267 if (target != IGNORE_TARGET)
1268 {
1269 if (! post_op)
1270 emit_load (exp, state);
1271 NOTE_PUSH (1);
1272 }
1273 break;
1274 }
1275 if (TREE_CODE (exp) == COMPONENT_REF)
1276 {
1277 generate_bytecode_insns (TREE_OPERAND (exp, 0), STACK_TARGET, state);
1278 emit_dup (1, 0, state);
1279 /* Stack: ..., objectref, objectref. */
1280 field_op (TREE_OPERAND (exp, 1), OPCODE_getstatic, state);
1281 NOTE_PUSH (size);
1282 /* Stack: ..., objectref, oldvalue. */
1283 offset = 1;
1284 }
1285 else if (TREE_CODE (exp) == ARRAY_REF)
1286 {
1287 generate_bytecode_insns (TREE_OPERAND (exp, 0), STACK_TARGET, state);
1288 generate_bytecode_insns (TREE_OPERAND (exp, 1), STACK_TARGET, state);
1289 emit_dup (2, 0, state);
1290 /* Stack: ..., array, index, array, index. */
1291 jopcode = OPCODE_iaload + adjust_typed_op (TREE_TYPE (exp));
1292 RESERVE(1);
1293 OP1 (jopcode);
1294 NOTE_POP (2-size);
1295 /* Stack: ..., array, index, oldvalue. */
1296 offset = 2;
1297 }
1298 else if (TREE_CODE (exp) == VAR_DECL || TREE_CODE (exp) == PARM_DECL)
1299 {
1300 generate_bytecode_insns (exp, STACK_TARGET, state);
1301 /* Stack: ..., oldvalue. */
1302 offset = 0;
1303 }
1304 else
1305 abort ();
1306
1307 if (target != IGNORE_TARGET && post_op)
1308 emit_dup (size, offset, state);
1309 /* Stack, if ARRAY_REF: ..., [result, ] array, index, oldvalue. */
1310 /* Stack, if COMPONENT_REF: ..., [result, ] objectref, oldvalue. */
1311 /* Stack, otherwise: ..., [result, ] oldvalue. */
1312 push_int_const (value, state); /* FIXME - assumes int! */
1313 NOTE_PUSH (1);
1314 emit_binop (OPCODE_iadd + adjust_typed_op (type), type, state);
1315 if (target != IGNORE_TARGET && ! post_op)
1316 emit_dup (size, offset, state);
1317 /* Stack: ..., [result,] newvalue. */
1318 goto finish_assignment;
1319
1320 case MODIFY_EXPR:
1321 {
1322 tree lhs = TREE_OPERAND (exp, 0);
1323 tree rhs = TREE_OPERAND (exp, 1);
1324
1325 /* See if we can use the iinc instruction. */
1326 if ((TREE_CODE (lhs) == VAR_DECL || TREE_CODE (lhs) == PARM_DECL)
1327 && ! TREE_STATIC (lhs)
1328 && TREE_CODE (TREE_TYPE (lhs)) == INTEGER_TYPE
1329 && TYPE_PRECISION (TREE_TYPE (lhs)) == 32
1330 && (TREE_CODE (rhs) == PLUS_EXPR || TREE_CODE (rhs) == MINUS_EXPR))
1331 {
1332 tree arg0 = TREE_OPERAND (rhs, 0);
1333 tree arg1 = TREE_OPERAND (rhs, 1);
1334 HOST_WIDE_INT min_value = -32768;
1335 HOST_WIDE_INT max_value = 32767;
1336 if (TREE_CODE (rhs) == MINUS_EXPR)
1337 {
1338 min_value++;
1339 max_value++;
1340 }
1341 else if (arg1 == lhs)
1342 {
1343 arg0 = arg1;
1344 arg1 = TREE_OPERAND (rhs, 0);
1345 }
1346 if (lhs == arg0 && TREE_CODE (arg1) == INTEGER_CST)
1347 {
1348 HOST_WIDE_INT hi_value = TREE_INT_CST_HIGH (arg1);
1349 value = TREE_INT_CST_LOW (arg1);
1350 if ((hi_value == 0 && value <= max_value)
1351 || (hi_value == -1 && value >= min_value))
1352 {
1353 if (TREE_CODE (rhs) == MINUS_EXPR)
1354 value = -value;
1355 emit_iinc (lhs, value, state);
1356 break;
1357 }
1358 }
1359 }
1360
1361 if (TREE_CODE (lhs) == COMPONENT_REF)
1362 generate_bytecode_insns (TREE_OPERAND (lhs, 0), STACK_TARGET, state);
1363 else if (TREE_CODE (lhs) == ARRAY_REF)
1364 {
1365 generate_bytecode_insns (TREE_OPERAND(lhs, 0), STACK_TARGET, state);
1366 generate_bytecode_insns (TREE_OPERAND(lhs, 1), STACK_TARGET, state);
1367 }
1368 generate_bytecode_insns (rhs, STACK_TARGET, state);
1369 if (target != IGNORE_TARGET)
1370 emit_dup (TYPE_IS_WIDE (type) ? 2 : 1 , 1, state);
1371 exp = lhs;
1372 }
1373 /* FALLTHOUGH */
1374
1375 finish_assignment:
1376 if (TREE_CODE (exp) == COMPONENT_REF)
1377 {
1378 tree field = TREE_OPERAND (exp, 1);
1379 if (! FIELD_STATIC (field))
1380 NOTE_POP (1);
1381 field_op (field,
1382 FIELD_STATIC (field) ? OPCODE_putstatic
1383 : OPCODE_putfield,
1384 state);
1385
1386 NOTE_PUSH (TYPE_IS_WIDE (TREE_TYPE (field)) ? 2 : 1);
1387 }
1388 else if (TREE_CODE (exp) == VAR_DECL
1389 || TREE_CODE (exp) == PARM_DECL)
1390 {
1391 if (FIELD_STATIC (exp))
1392 {
1393 field_op (exp, OPCODE_putstatic, state);
1394 NOTE_PUSH (TYPE_IS_WIDE (TREE_TYPE (exp)) ? 2 : 1);
1395 }
1396 else
1397 emit_store (exp, state);
1398 }
1399 else if (TREE_CODE (exp) == ARRAY_REF)
1400 {
1401 NOTE_POP (2);
1402 jopcode = OPCODE_iastore + adjust_typed_op (TREE_TYPE (exp));
1403 RESERVE(1);
1404 OP1 (jopcode);
1405 NOTE_PUSH (TYPE_IS_WIDE (TREE_TYPE (exp)) ? 2 : 1);
1406 }
1407 else
1408 fatal ("internal error (bad lhs to MODIFY_EXPR)");
1409 break;
1410 case PLUS_EXPR:
1411 jopcode = OPCODE_iadd + adjust_typed_op (type);
1412 goto binop;
1413 case MINUS_EXPR:
1414 jopcode = OPCODE_isub + adjust_typed_op (type);
1415 goto binop;
1416 case MULT_EXPR:
1417 jopcode = OPCODE_imul + adjust_typed_op (type);
1418 goto binop;
1419 case TRUNC_DIV_EXPR:
1420 case RDIV_EXPR:
1421 jopcode = OPCODE_idiv + adjust_typed_op (type);
1422 goto binop;
1423 binop:
1424 generate_bytecode_insns (TREE_OPERAND (exp, 0), target, state);
1425 generate_bytecode_insns (TREE_OPERAND (exp, 1), target, state);
1426 if (target == STACK_TARGET)
1427 emit_binop (jopcode, type, state);
1428 break;
1429 case CALL_EXPR:
1430 {
1431 tree t;
1432 int save_SP = state->code_SP;
1433 for (t = TREE_OPERAND (exp, 1); t != NULL_TREE; t = TREE_CHAIN (t))
1434 {
1435 generate_bytecode_insns (TREE_VALUE (t), STACK_TARGET, state);
1436 }
1437 t = TREE_OPERAND (exp, 0);
1438 state->code_SP = save_SP;
1439 if (TREE_CODE (t) == FUNCTION_DECL)
1440 {
1441 int index = find_methodref_index (&state->cpool, t);
1442 RESERVE (3);
1443 if (DECL_CONSTRUCTOR_P (t))
1444 OP1 (OPCODE_invokespecial);
1445 else if (METHOD_STATIC (t))
1446 OP1 (OPCODE_invokestatic);
1447 else
1448 OP1 (OPCODE_invokevirtual);
1449 OP2 (index);
1450 t = TREE_TYPE (TREE_TYPE (t));
1451 if (TREE_CODE (t) != VOID_TYPE)
1452 {
1453 int size = TYPE_IS_WIDE (t) ? 2 : 1;
1454 if (target == IGNORE_TARGET)
1455 emit_pop (size, state);
1456 else
1457 NOTE_PUSH (size);
1458 }
1459 break;
1460 }
1461 }
1462 /* fall through */
1463 notimpl:
1464 default:
1465 error("internal error - tree code not implemented: %s",
1466 tree_code_name [(int) TREE_CODE (exp)]);
1467 }
1468 }
1469
1470 void
1471 perform_relocations (state)
1472 struct jcf_partial *state;
1473 {
1474 struct jcf_block *block;
1475 struct jcf_relocation *reloc;
1476 int pc;
1477 int shrink;
1478
1479 /* Figure out the actual locations of each block. */
1480 pc = 0;
1481 shrink = 0;
1482 for (block = state->blocks; block != NULL; block = block->next)
1483 {
1484 int block_size = block->chunk->size;
1485
1486 block->pc = pc;
1487
1488 /* Optimize GOTO L; L: by getting rid of the redundant goto.
1489 Assumes relocations are in reverse order. */
1490 reloc = block->u.relocations;
1491 while (reloc != NULL
1492 && reloc->label->pc == block->next->pc
1493 && reloc->offset + 2 == block_size
1494 && reloc->kind == OPCODE_goto_w)
1495 {
1496 reloc = reloc->next;
1497 block->u.relocations = reloc;
1498 block->chunk->size -= 3;
1499 block_size -= 3;
1500 shrink += 3;
1501 }
1502
1503 for (reloc = block->u.relocations; reloc != NULL; reloc = reloc->next)
1504 {
1505 if (reloc->kind < -1 || reloc->kind > 0)
1506 {
1507 int delta = reloc->label->pc - (pc + reloc->offset - 1);
1508 int expand = reloc->kind > 0 ? 2 : 5;
1509
1510 if (delta > 0)
1511 delta -= shrink;
1512 if (delta >= -32768 && delta <= 32767)
1513 {
1514 shrink += expand;
1515 reloc->kind = -1;
1516 }
1517 else
1518 block_size += expand;
1519 }
1520 }
1521 pc += block_size;
1522 }
1523
1524 for (block = state->blocks; block != NULL; block = block->next)
1525 {
1526 struct chunk *chunk = block->chunk;
1527 int old_size = chunk->size;
1528 int next_pc = block->next == NULL ? pc : block->next->pc;
1529 int new_size = next_pc - block->pc;
1530 int offset = 0;
1531 unsigned char *new_ptr;
1532 unsigned char *old_buffer = chunk->data;
1533 unsigned char *old_ptr = old_buffer + old_size;
1534 int new_end = new_size;
1535 if (new_size != old_size)
1536 {
1537 chunk->data = (unsigned char *)
1538 obstack_alloc (state->chunk_obstack, new_size);
1539 }
1540 new_ptr = chunk->data + new_size;
1541
1542 /* We do the relocations from back to front, because
1543 thre relocations are in reverse order. */
1544 for (reloc = block->u.relocations; ; reloc = reloc->next)
1545 {
1546 /* Lower old index of piece to be copied with no relocation. */
1547 int start = reloc == NULL ? 0
1548 : reloc->kind == 0 ? reloc->offset + 4
1549 : reloc->offset + 2;
1550 int32 value;
1551 int new_offset;
1552 int n = (old_ptr - old_buffer) - start;
1553 new_ptr -= n;
1554 old_ptr -= n;
1555 if (n > 0)
1556 bcopy (old_ptr, new_ptr, n);
1557 if (old_ptr == old_buffer)
1558 break;
1559
1560 if (reloc->kind == 0)
1561 {
1562 old_ptr -= 4;
1563 value = GET_u4 (old_ptr);
1564 }
1565 else
1566 {
1567 old_ptr -= 2;
1568 value = GET_u2 (old_ptr);
1569 }
1570 new_offset = new_ptr - chunk->data - (reloc->kind == -1 ? 2 : 4);
1571 value += reloc->label->pc - (block->pc + new_offset);
1572 *--new_ptr = (unsigned char) value; value >>= 8;
1573 *--new_ptr = (unsigned char) value; value >>= 8;
1574 if (reloc->kind != -1)
1575 {
1576 *--new_ptr = (unsigned char) value; value >>= 8;
1577 *--new_ptr = (unsigned char) value;
1578 }
1579 if (reloc->kind > 0)
1580 {
1581 /* Convert: OP TARGET to: OP_w TARGET; (OP is goto or jsr). */
1582 --old_ptr;
1583 *--new_ptr = reloc->kind;
1584 }
1585 else if (reloc->kind < -1)
1586 {
1587 /* Convert: ifCOND TARGET to: ifNCOND T; goto_w TARGET; T: */
1588 --old_ptr;
1589 *--new_ptr = OPCODE_goto_w;
1590 *--new_ptr = 3;
1591 *--new_ptr = 0;
1592 *--new_ptr = - reloc->kind;
1593 }
1594 }
1595 }
1596 state->code_length = pc;
1597 }
1598
1599 void
1600 init_jcf_state (state, work)
1601 struct jcf_partial *state;
1602 struct obstack *work;
1603 {
1604 state->chunk_obstack = work;
1605 state->first = state->chunk = NULL;
1606 CPOOL_INIT (&state->cpool);
1607 BUFFER_INIT (&state->localvars);
1608 BUFFER_INIT (&state->bytecode);
1609 }
1610
1611 void
1612 init_jcf_method (state, method)
1613 struct jcf_partial *state;
1614 tree method;
1615 {
1616 state->current_method = method;
1617 state->blocks = state->last_block = NULL;
1618 state->linenumber_count = 0;
1619 state->first_lvar = state->last_lvar = NULL;
1620 state->lvar_count = 0;
1621 state->labeled_blocks = NULL;
1622 state->code_length = 0;
1623 BUFFER_RESET (&state->bytecode);
1624 BUFFER_RESET (&state->localvars);
1625 state->code_SP = 0;
1626 state->code_SP_max = 0;
1627 }
1628
1629 void
1630 release_jcf_state (state)
1631 struct jcf_partial *state;
1632 {
1633 CPOOL_FINISH (&state->cpool);
1634 obstack_free (state->chunk_obstack, state->first);
1635 }
1636
1637 /* Generate and return a list of chunks containing the class CLAS
1638 in the .class file representation. The list can be written to a
1639 .class file using write_chunks. Allocate chunks from obstack WORK. */
1640
1641 struct chunk *
1642 generate_classfile (clas, state)
1643 tree clas;
1644 struct jcf_partial *state;
1645 {
1646 struct chunk *cpool_chunk;
1647 char *source_file;
1648 char *ptr;
1649 int i;
1650 char *fields_count_ptr;
1651 int fields_count = 0;
1652 char *methods_count_ptr;
1653 int methods_count = 0;
1654 static tree SourceFile_node = NULL_TREE;
1655 tree part;
1656 int total_supers
1657 = clas == object_type_node ? 0
1658 : TREE_VEC_LENGTH (TYPE_BINFO_BASETYPES (clas));
1659
1660 ptr = append_chunk (NULL, 8, state);
1661 PUT4 (0xCafeBabe); /* Magic number */
1662 PUT2 (3); /* Minor version */
1663 PUT2 (45); /* Major version */
1664
1665 append_chunk (NULL, 0, state);
1666 cpool_chunk = state->chunk;
1667
1668 /* Next allocate the chunk containing acces_flags through fields_counr. */
1669 if (clas == object_type_node)
1670 i = 10;
1671 else
1672 i = 8 + 2 * total_supers;
1673 ptr = append_chunk (NULL, i, state);
1674 i = get_access_flags (TYPE_NAME (clas)); PUT2 (i); /* acces_flags */
1675 i = find_class_constant (&state->cpool, clas); PUT2 (i); /* this_class */
1676 if (clas == object_type_node)
1677 {
1678 PUT2(0); /* super_class */
1679 PUT2(0); /* interfaces_count */
1680 }
1681 else
1682 {
1683 tree basetypes = TYPE_BINFO_BASETYPES (clas);
1684 tree base = BINFO_TYPE (TREE_VEC_ELT (basetypes, 0));
1685 int j = find_class_constant (&state->cpool, base);
1686 PUT2 (j); /* super_class */
1687 PUT2 (total_supers - 1); /* interfaces_count */
1688 for (i = 1; i < total_supers; i++)
1689 {
1690 base = BINFO_TYPE (TREE_VEC_ELT (basetypes, i));
1691 j = find_class_constant (&state->cpool, base);
1692 PUT2 (j);
1693 }
1694 }
1695 fields_count_ptr = ptr;
1696
1697 for (part = TYPE_FIELDS (clas); part; part = TREE_CHAIN (part))
1698 {
1699 if (DECL_NAME (part) == NULL_TREE)
1700 continue;
1701 ptr = append_chunk (NULL, 8, state);
1702 i = get_access_flags (part); PUT2 (i);
1703 i = find_utf8_constant (&state->cpool, DECL_NAME (part)); PUT2 (i);
1704 i = find_utf8_constant (&state->cpool, build_java_signature (TREE_TYPE (part)));
1705 PUT2(i);
1706 PUT2 (0); /* attributes_count */
1707 /* FIXME - emit ConstantValue attribute when appropriate */
1708 fields_count++;
1709 }
1710 ptr = fields_count_ptr; PUT2 (fields_count);
1711
1712 ptr = methods_count_ptr = append_chunk (NULL, 2, state);
1713 PUT2 (0);
1714
1715 for (part = TYPE_METHODS (clas); part; part = TREE_CHAIN (part))
1716 {
1717 struct jcf_block *block;
1718 tree body = BLOCK_EXPR_BODY (DECL_FUNCTION_BODY (part));
1719 tree name = DECL_CONSTRUCTOR_P (part) ? init_identifier_node
1720 : DECL_NAME (part);
1721 tree type = TREE_TYPE (part);
1722 ptr = append_chunk (NULL, 8, state);
1723 i = get_access_flags (part); PUT2 (i);
1724 i = find_utf8_constant (&state->cpool, name); PUT2 (i);
1725 i = find_utf8_constant (&state->cpool, build_java_signature (type));
1726 PUT2 (i);
1727 PUT2 (body != NULL_TREE ? 1 : 0); /* attributes_count */
1728 if (body != NULL_TREE)
1729 {
1730 int code_attributes_count = 0;
1731 static tree Code_node = NULL_TREE;
1732 tree t;
1733 char *attr_len_ptr;
1734 if (Code_node == NULL_TREE)
1735 Code_node = get_identifier ("Code");
1736 ptr = append_chunk (NULL, 14, state);
1737 i = find_utf8_constant (&state->cpool, Code_node); PUT2 (i);
1738 attr_len_ptr = ptr;
1739 init_jcf_method (state, part);
1740 get_jcf_label_here (state); /* Force a first block. */
1741 for (t = DECL_ARGUMENTS (part); t != NULL_TREE; t = TREE_CHAIN (t))
1742 localvar_alloc (t, state);
1743 generate_bytecode_insns (body, IGNORE_TARGET, state);
1744 for (t = DECL_ARGUMENTS (part); t != NULL_TREE; t = TREE_CHAIN (t))
1745 localvar_free (t, state);
1746 finish_jcf_block (state);
1747 perform_relocations (state);
1748
1749 ptr = attr_len_ptr;
1750 i = 8 + state->code_length + 4;
1751 if (state->linenumber_count > 0)
1752 {
1753 code_attributes_count++;
1754 i += 8 + 4 * state->linenumber_count;
1755 }
1756 if (state->lvar_count > 0)
1757 {
1758 code_attributes_count++;
1759 i += 8 + 10 * state->lvar_count;
1760 }
1761 PUT4 (i); /* attribute_length */
1762 PUT2 (state->code_SP_max); /* max_stack */
1763 PUT2 (localvar_max); /* max_locals */
1764 PUT4 (state->code_length);
1765 ptr = append_chunk (NULL, 4, state);
1766 PUT2 (0); /* exception_table_length */
1767 PUT2 (code_attributes_count);
1768
1769 /* Write the LineNumberTable attribute. */
1770 if (state->linenumber_count > 0)
1771 {
1772 static tree LineNumberTable_node = NULL_TREE;
1773 ptr = append_chunk (NULL, 8 + 4 * state->linenumber_count, state);
1774 if (LineNumberTable_node == NULL_TREE)
1775 LineNumberTable_node = get_identifier ("LineNumberTable");
1776 i = find_utf8_constant (&state->cpool, LineNumberTable_node);
1777 PUT2 (i); /* attribute_name_index */
1778 i = 2+4*state->linenumber_count; PUT4(i); /* attribute_length */
1779 i = state->linenumber_count; PUT2 (i);
1780 for (block = state->blocks; block != NULL; block = block->next)
1781 {
1782 int line = block->linenumber;
1783 if (line > 0)
1784 {
1785 PUT2 (block->pc);
1786 PUT2 (line);
1787 }
1788 }
1789 }
1790
1791 /* Write the LocalVariableTable attribute. */
1792 if (state->lvar_count > 0)
1793 {
1794 static tree LocalVariableTable_node = NULL_TREE;
1795 struct localvar_info *lvar = state->first_lvar;
1796 ptr = append_chunk (NULL, 8 + 10 * state->lvar_count, state);
1797 if (LocalVariableTable_node == NULL_TREE)
1798 LocalVariableTable_node = get_identifier("LocalVariableTable");
1799 i = find_utf8_constant (&state->cpool, LocalVariableTable_node);
1800 PUT2 (i); /* attribute_name_index */
1801 i = 2 + 10 * state->lvar_count; PUT4 (i); /* attribute_length */
1802 i = state->lvar_count; PUT2 (i);
1803 for ( ; lvar != NULL; lvar = lvar->next)
1804 {
1805 tree name = DECL_NAME (lvar->decl);
1806 tree sig = build_java_signature (TREE_TYPE (lvar->decl));
1807 i = lvar->start_label->pc; PUT2 (i);
1808 i = lvar->end_label->pc - i; PUT2 (i);
1809 i = find_utf8_constant (&state->cpool, name); PUT2 (i);
1810 i = find_utf8_constant (&state->cpool, sig); PUT2 (i);
1811 i = DECL_LOCAL_INDEX (lvar->decl); PUT2 (i);
1812 }
1813 }
1814 }
1815 methods_count++;
1816 }
1817 ptr = methods_count_ptr; PUT2 (methods_count);
1818
1819 source_file = DECL_SOURCE_FILE (TYPE_NAME (clas));
1820 for (ptr = source_file; ; ptr++)
1821 {
1822 char ch = *ptr;
1823 if (ch == '\0')
1824 break;
1825 if (ch == '/' || ch == '\\')
1826 source_file = ptr+1;
1827 }
1828 ptr = append_chunk (NULL, 10, state);
1829 PUT2 (1); /* attributes_count */
1830
1831 /* generate the SourceFile attribute. */
1832 if (SourceFile_node == NULL_TREE)
1833 SourceFile_node = get_identifier ("SourceFile");
1834 i = find_utf8_constant (&state->cpool, SourceFile_node);
1835 PUT2 (i); /* attribute_name_index */
1836 PUT4 (2);
1837 i = find_utf8_constant (&state->cpool, get_identifier (source_file));
1838 PUT2 (i);
1839
1840 /* New finally generate the contents of the constant pool chunk. */
1841 i = count_constant_pool_bytes (&state->cpool);
1842 ptr = obstack_alloc (state->chunk_obstack, i);
1843 cpool_chunk->data = ptr;
1844 cpool_chunk->size = i;
1845 write_constant_pool (&state->cpool, ptr, i);
1846 return state->first;
1847 }
1848
1849 char*
1850 make_class_file_name (clas)
1851 tree clas;
1852 {
1853 /* Should prepend an output directly, but need an option to specify it. */
1854 return IDENTIFIER_POINTER (identifier_subst (DECL_NAME (TYPE_NAME (clas)),
1855 "", '.', '/', ".class"));
1856 }
1857
1858 /* Write out the contens of a class (RECORD_TYPE) CLAS, as a .class file.
1859 The output .class file name is make_class_file_name(CLAS). */
1860
1861 void
1862 write_classfile (clas)
1863 tree clas;
1864 {
1865 struct obstack *work = &temporary_obstack;
1866 struct jcf_partial state[1];
1867 char *class_file_name = make_class_file_name (clas);
1868 struct chunk *chunks;
1869 FILE* stream = fopen (class_file_name, "wb");
1870 if (stream == NULL)
1871 fatal ("failed to open `%s' for writing", class_file_name);
1872 jcf_dependency_add_target (class_file_name);
1873 init_jcf_state (state, work);
1874 chunks = generate_classfile (clas, state);
1875 write_chunks (stream, chunks);
1876 if (fclose (stream))
1877 fatal ("failed to close after writing `%s'", class_file_name);
1878 release_jcf_state (state);
1879 }
This page took 0.126951 seconds and 6 git commands to generate.