]>
Commit | Line | Data |
---|---|---|
e04a16fb | 1 | /* Write out a Java(TM) class file. |
986dc4e5 | 2 | Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004 |
f309ff0a | 3 | Free Software Foundation, Inc. |
e04a16fb | 4 | |
f309ff0a | 5 | This file is part of GCC. |
e04a16fb | 6 | |
f309ff0a | 7 | GCC is free software; you can redistribute it and/or modify |
e04a16fb AG |
8 | it under the terms of the GNU General Public License as published by |
9 | the Free Software Foundation; either version 2, or (at your option) | |
10 | any later version. | |
11 | ||
f309ff0a | 12 | GCC is distributed in the hope that it will be useful, |
e04a16fb AG |
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | GNU General Public License for more details. | |
16 | You should have received a copy of the GNU General Public License | |
f309ff0a | 17 | along with GCC; see the file COPYING. If not, write to |
e04a16fb AG |
18 | the Free Software Foundation, 59 Temple Place - Suite 330, |
19 | Boston, MA 02111-1307, USA. | |
20 | ||
21 | Java and all Java-based marks are trademarks or registered trademarks | |
22 | of Sun Microsystems, Inc. in the United States and other countries. | |
23 | The Free Software Foundation is independent of Sun Microsystems, Inc. */ | |
24 | ||
25 | #include "config.h" | |
1f43f4b4 | 26 | #include "system.h" |
4977bab6 ZW |
27 | #include "coretypes.h" |
28 | #include "tm.h" | |
4bcde32e | 29 | #include "jcf.h" |
e04a16fb | 30 | #include "tree.h" |
1cde1d05 | 31 | #include "real.h" |
e04a16fb | 32 | #include "java-tree.h" |
e04a16fb | 33 | #include "obstack.h" |
e04a16fb | 34 | #include "rtl.h" |
80d8e475 | 35 | #include "flags.h" |
e04a16fb AG |
36 | #include "java-opcodes.h" |
37 | #include "parse.h" /* for BLOCK_EXPR_BODY */ | |
38 | #include "buffer.h" | |
d4476be2 | 39 | #include "toplev.h" |
19e223db | 40 | #include "ggc.h" |
a1fb4e91 | 41 | #include "tm_p.h" |
df66b566 | 42 | |
e04a16fb AG |
43 | extern struct obstack temporary_obstack; |
44 | ||
df66b566 TT |
45 | /* Base directory in which `.class' files should be written. |
46 | NULL means to put the file into the same directory as the | |
47 | corresponding .java file. */ | |
95ca6d8b | 48 | const char *jcf_write_base_directory = NULL; |
df66b566 | 49 | |
e04a16fb AG |
50 | /* Make sure bytecode.data is big enough for at least N more bytes. */ |
51 | ||
52 | #define RESERVE(N) \ | |
9bbc7d9f PB |
53 | do { CHECK_OP(state); \ |
54 | if (state->bytecode.ptr + (N) > state->bytecode.limit) \ | |
e4de5a10 | 55 | buffer_grow (&state->bytecode, N); } while (0) |
e04a16fb AG |
56 | |
57 | /* Add a 1-byte instruction/operand I to bytecode.data, | |
58 | assuming space has already been RESERVE'd. */ | |
59 | ||
89b894e1 | 60 | #define OP1(I) (*state->bytecode.ptr++ = (I), CHECK_OP(state)) |
e04a16fb AG |
61 | |
62 | /* Like OP1, but I is a 2-byte big endian integer. */ | |
63 | ||
64 | #define OP2(I) \ | |
9bbc7d9f | 65 | do { int _i = (I); OP1 (_i >> 8); OP1 (_i); CHECK_OP(state); } while (0) |
e04a16fb AG |
66 | |
67 | /* Like OP1, but I is a 4-byte big endian integer. */ | |
68 | ||
69 | #define OP4(I) \ | |
4f01de5c | 70 | do { int _i = (I); OP1 (_i >> 24); OP1 (_i >> 16); \ |
9bbc7d9f | 71 | OP1 (_i >> 8); OP1 (_i); CHECK_OP(state); } while (0) |
e04a16fb AG |
72 | |
73 | /* Macro to call each time we push I words on the JVM stack. */ | |
74 | ||
75 | #define NOTE_PUSH(I) \ | |
e4de5a10 PB |
76 | do { state->code_SP += (I); \ |
77 | if (state->code_SP > state->code_SP_max) \ | |
78 | state->code_SP_max = state->code_SP; } while (0) | |
e04a16fb AG |
79 | |
80 | /* Macro to call each time we pop I words from the JVM stack. */ | |
81 | ||
82 | #define NOTE_POP(I) \ | |
e4de5a10 | 83 | do { state->code_SP -= (I); if (state->code_SP < 0) abort(); } while (0) |
e04a16fb AG |
84 | |
85 | /* A chunk or segment of a .class file. */ | |
86 | ||
87 | struct chunk | |
88 | { | |
89 | /* The next segment of this .class file. */ | |
90 | struct chunk *next; | |
91 | ||
92 | /* The actual data in this segment to be written to the .class file. */ | |
93 | unsigned char *data; | |
94 | ||
95 | /* The size of the segment to be written to the .class file. */ | |
96 | int size; | |
97 | }; | |
98 | ||
45b44fbe PB |
99 | #define PENDING_CLEANUP_PC (-3) |
100 | #define PENDING_EXIT_PC (-2) | |
101 | #define UNDEFINED_PC (-1) | |
102 | ||
e4de5a10 PB |
103 | /* Each "block" represents a label plus the bytecode instructions following. |
104 | There may be branches out of the block, but no incoming jumps, except | |
45b44fbe PB |
105 | to the beginning of the block. |
106 | ||
107 | If (pc < 0), the jcf_block is not an actual block (i.e. it has no | |
a83f01f0 | 108 | associated code yet), but it is an undefined label. |
45b44fbe | 109 | */ |
e4de5a10 PB |
110 | |
111 | struct jcf_block | |
112 | { | |
113 | /* For blocks that that are defined, the next block (in pc order). | |
fa029f45 | 114 | For blocks that are not-yet-defined the end label of a LABELED_BLOCK_EXPR |
aedcdb65 | 115 | or a cleanup expression (from a TRY_FINALLY_EXPR), |
45b44fbe | 116 | this is the next (outer) such end label, in a stack headed by |
e4de5a10 PB |
117 | labeled_blocks in jcf_partial. */ |
118 | struct jcf_block *next; | |
119 | ||
45b44fbe PB |
120 | /* In the not-yet-defined end label for an unfinished EXIT_BLOCK_EXPR. |
121 | pc is PENDING_EXIT_PC. | |
122 | In the not-yet-defined end label for pending cleanup subroutine, | |
123 | pc is PENDING_CLEANUP_PC. | |
124 | For other not-yet-defined labels, pc is UNDEFINED_PC. | |
125 | ||
126 | If the label has been defined: | |
127 | Until perform_relocations is finished, this is the maximum possible | |
634661fe | 128 | value of the bytecode offset at the beginning of this block. |
e4de5a10 PB |
129 | After perform_relocations, it is the actual offset (pc). */ |
130 | int pc; | |
131 | ||
132 | int linenumber; | |
133 | ||
fa029f45 PB |
134 | /* After finish_jcf_block is called, the actual instructions |
135 | contained in this block. Before that NULL, and the instructions | |
c7303e41 | 136 | are in state->bytecode. */ |
45b44fbe PB |
137 | union { |
138 | struct chunk *chunk; | |
139 | ||
140 | /* If pc==PENDING_CLEANUP_PC, start_label is the start of the region | |
c7303e41 | 141 | covered by the cleanup. */ |
45b44fbe PB |
142 | struct jcf_block *start_label; |
143 | } v; | |
e4de5a10 PB |
144 | |
145 | union { | |
146 | /* Set of relocations (in reverse offset order) for this block. */ | |
147 | struct jcf_relocation *relocations; | |
148 | ||
149 | /* If this block is that of the not-yet-defined end label of | |
45b44fbe PB |
150 | a LABELED_BLOCK_EXPR, where LABELED_BLOCK is that LABELED_BLOCK_EXPR. |
151 | If pc==PENDING_CLEANUP_PC, the cleanup that needs to be run. */ | |
e4de5a10 PB |
152 | tree labeled_block; |
153 | } u; | |
154 | }; | |
155 | ||
9bbc7d9f PB |
156 | /* A "relocation" type for the 0-3 bytes of padding at the start |
157 | of a tableswitch or a lookupswitch. */ | |
3885dfa7 | 158 | #define SWITCH_ALIGN_RELOC 4 |
9bbc7d9f PB |
159 | |
160 | /* A relocation type for the labels in a tableswitch or a lookupswitch; | |
161 | these are relative to the start of the instruction, but (due to | |
162 | th 0-3 bytes of padding), we don't know the offset before relocation. */ | |
3885dfa7 PB |
163 | #define BLOCK_START_RELOC 1 |
164 | ||
e4de5a10 PB |
165 | struct jcf_relocation |
166 | { | |
167 | /* Next relocation for the current jcf_block. */ | |
168 | struct jcf_relocation *next; | |
169 | ||
170 | /* The (byte) offset within the current block that needs to be relocated. */ | |
3885dfa7 | 171 | HOST_WIDE_INT offset; |
e4de5a10 PB |
172 | |
173 | /* 0 if offset is a 4-byte relative offset. | |
3885dfa7 PB |
174 | 4 (SWITCH_ALIGN_RELOC) if offset points to 0-3 padding bytes inserted |
175 | for proper alignment in tableswitch/lookupswitch instructions. | |
176 | 1 (BLOCK_START_RELOC) if offset points to a 4-byte offset relative | |
177 | to the start of the containing block. | |
e4de5a10 | 178 | -1 if offset is a 2-byte relative offset. |
3885dfa7 | 179 | < -1 if offset is the address of an instruction with a 2-byte offset |
e4de5a10 PB |
180 | that does not have a corresponding 4-byte offset version, in which |
181 | case the absolute value of kind is the inverted opcode. | |
3885dfa7 | 182 | > 4 if offset is the address of an instruction (such as jsr) with a |
e4de5a10 PB |
183 | 2-byte offset that does have a corresponding 4-byte offset version, |
184 | in which case kind is the opcode of the 4-byte version (such as jsr_w). */ | |
185 | int kind; | |
186 | ||
187 | /* The label the relocation wants to actually transfer to. */ | |
188 | struct jcf_block *label; | |
189 | }; | |
190 | ||
cacc154e | 191 | #define RELOCATION_VALUE_0 ((HOST_WIDE_INT)0) |
b5edd133 | 192 | #define RELOCATION_VALUE_1 ((HOST_WIDE_INT)1) |
cacc154e | 193 | |
3885dfa7 PB |
194 | /* State for single catch clause. */ |
195 | ||
196 | struct jcf_handler | |
197 | { | |
198 | struct jcf_handler *next; | |
199 | ||
200 | struct jcf_block *start_label; | |
201 | struct jcf_block *end_label; | |
202 | struct jcf_block *handler_label; | |
203 | ||
204 | /* The sub-class of Throwable handled, or NULL_TREE (for finally). */ | |
205 | tree type; | |
206 | }; | |
207 | ||
208 | /* State for the current switch statement. */ | |
209 | ||
210 | struct jcf_switch_state | |
211 | { | |
212 | struct jcf_switch_state *prev; | |
213 | struct jcf_block *default_label; | |
214 | ||
215 | struct jcf_relocation *cases; | |
216 | int num_cases; | |
217 | HOST_WIDE_INT min_case, max_case; | |
218 | }; | |
219 | ||
e4de5a10 PB |
220 | /* This structure is used to contain the various pieces that will |
221 | become a .class file. */ | |
222 | ||
223 | struct jcf_partial | |
224 | { | |
225 | struct chunk *first; | |
226 | struct chunk *chunk; | |
227 | struct obstack *chunk_obstack; | |
228 | tree current_method; | |
229 | ||
230 | /* List of basic blocks for the current method. */ | |
231 | struct jcf_block *blocks; | |
232 | struct jcf_block *last_block; | |
233 | ||
234 | struct localvar_info *first_lvar; | |
235 | struct localvar_info *last_lvar; | |
236 | int lvar_count; | |
237 | ||
238 | CPool cpool; | |
239 | ||
240 | int linenumber_count; | |
241 | ||
242 | /* Until perform_relocations, this is a upper bound on the number | |
243 | of bytes (so far) in the instructions for the current method. */ | |
244 | int code_length; | |
245 | ||
246 | /* Stack of undefined ending labels for LABELED_BLOCK_EXPR. */ | |
247 | struct jcf_block *labeled_blocks; | |
248 | ||
249 | /* The current stack size (stack pointer) in the current method. */ | |
250 | int code_SP; | |
251 | ||
252 | /* The largest extent of stack size (stack pointer) in the current method. */ | |
253 | int code_SP_max; | |
254 | ||
255 | /* Contains a mapping from local var slot number to localvar_info. */ | |
256 | struct buffer localvars; | |
257 | ||
258 | /* The buffer allocated for bytecode for the current jcf_block. */ | |
259 | struct buffer bytecode; | |
3885dfa7 PB |
260 | |
261 | /* Chain of exception handlers for the current method. */ | |
262 | struct jcf_handler *handlers; | |
263 | ||
264 | /* Last element in handlers chain. */ | |
265 | struct jcf_handler *last_handler; | |
266 | ||
267 | /* Number of exception handlers for the current method. */ | |
268 | int num_handlers; | |
269 | ||
45b44fbe PB |
270 | /* Number of finalizers we are currently nested within. */ |
271 | int num_finalizers; | |
272 | ||
273 | /* If non-NULL, use this for the return value. */ | |
274 | tree return_value_decl; | |
275 | ||
c7303e41 | 276 | /* Information about the current switch statement. */ |
3885dfa7 | 277 | struct jcf_switch_state *sw_state; |
72f339d2 | 278 | |
67264b4f | 279 | /* The count of jsr instructions that have been emitted. */ |
72f339d2 | 280 | long num_jsrs; |
e4de5a10 PB |
281 | }; |
282 | ||
d2097937 KG |
283 | static void generate_bytecode_insns (tree, int, struct jcf_partial *); |
284 | static struct chunk * alloc_chunk (struct chunk *, unsigned char *, | |
285 | int, struct obstack *); | |
286 | static unsigned char * append_chunk (unsigned char *, int, | |
287 | struct jcf_partial *); | |
288 | static void append_chunk_copy (unsigned char *, int, struct jcf_partial *); | |
289 | static struct jcf_block * gen_jcf_label (struct jcf_partial *); | |
290 | static void finish_jcf_block (struct jcf_partial *); | |
291 | static void define_jcf_label (struct jcf_block *, struct jcf_partial *); | |
292 | static struct jcf_block * get_jcf_label_here (struct jcf_partial *); | |
293 | static void put_linenumber (int, struct jcf_partial *); | |
294 | static void localvar_alloc (tree, struct jcf_partial *); | |
72f339d2 | 295 | static void maybe_free_localvar (tree, struct jcf_partial *, int); |
d2097937 KG |
296 | static int get_access_flags (tree); |
297 | static void write_chunks (FILE *, struct chunk *); | |
298 | static int adjust_typed_op (tree, int); | |
299 | static void generate_bytecode_conditional (tree, struct jcf_block *, | |
300 | struct jcf_block *, int, | |
301 | struct jcf_partial *); | |
302 | static void generate_bytecode_return (tree, struct jcf_partial *); | |
303 | static void perform_relocations (struct jcf_partial *); | |
304 | static void init_jcf_state (struct jcf_partial *, struct obstack *); | |
305 | static void init_jcf_method (struct jcf_partial *, tree); | |
306 | static void release_jcf_state (struct jcf_partial *); | |
307 | static struct chunk * generate_classfile (tree, struct jcf_partial *); | |
308 | static struct jcf_handler *alloc_handler (struct jcf_block *, | |
309 | struct jcf_block *, | |
310 | struct jcf_partial *); | |
311 | static void emit_iinc (tree, HOST_WIDE_INT, struct jcf_partial *); | |
312 | static void emit_reloc (HOST_WIDE_INT, int, struct jcf_block *, | |
313 | struct jcf_partial *); | |
314 | static void push_constant1 (HOST_WIDE_INT, struct jcf_partial *); | |
315 | static void push_constant2 (HOST_WIDE_INT, struct jcf_partial *); | |
316 | static void push_int_const (HOST_WIDE_INT, struct jcf_partial *); | |
317 | static int find_constant_wide (HOST_WIDE_INT, HOST_WIDE_INT, | |
318 | struct jcf_partial *); | |
319 | static void push_long_const (HOST_WIDE_INT, HOST_WIDE_INT, | |
320 | struct jcf_partial *); | |
321 | static int find_constant_index (tree, struct jcf_partial *); | |
322 | static void push_long_const (HOST_WIDE_INT, HOST_WIDE_INT, | |
323 | struct jcf_partial *); | |
324 | static void field_op (tree, int, struct jcf_partial *); | |
325 | static void maybe_wide (int, int, struct jcf_partial *); | |
326 | static void emit_dup (int, int, struct jcf_partial *); | |
327 | static void emit_pop (int, struct jcf_partial *); | |
328 | static void emit_load_or_store (tree, int, struct jcf_partial *); | |
329 | static void emit_load (tree, struct jcf_partial *); | |
330 | static void emit_store (tree, struct jcf_partial *); | |
331 | static void emit_unop (enum java_opcode, tree, struct jcf_partial *); | |
332 | static void emit_binop (enum java_opcode, tree, struct jcf_partial *); | |
333 | static void emit_reloc (HOST_WIDE_INT, int, struct jcf_block *, | |
334 | struct jcf_partial *); | |
335 | static void emit_switch_reloc (struct jcf_block *, struct jcf_partial *); | |
336 | static void emit_case_reloc (struct jcf_relocation *, struct jcf_partial *); | |
337 | static void emit_if (struct jcf_block *, int, int, struct jcf_partial *); | |
338 | static void emit_goto (struct jcf_block *, struct jcf_partial *); | |
339 | static void emit_jsr (struct jcf_block *, struct jcf_partial *); | |
340 | static void call_cleanups (struct jcf_block *, struct jcf_partial *); | |
341 | static char *make_class_file_name (tree); | |
342 | static unsigned char *append_synthetic_attribute (struct jcf_partial *); | |
f94ae540 | 343 | static void append_deprecated_attribute (struct jcf_partial *); |
d2097937 KG |
344 | static void append_innerclasses_attribute (struct jcf_partial *, tree); |
345 | static void append_innerclasses_attribute_entry (struct jcf_partial *, tree, tree); | |
346 | static void append_gcj_attribute (struct jcf_partial *, tree); | |
e4de5a10 | 347 | |
e04a16fb AG |
348 | /* Utility macros for appending (big-endian) data to a buffer. |
349 | We assume a local variable 'ptr' points into where we want to | |
b124f72e | 350 | write next, and we assume enough space has been allocated. */ |
e04a16fb | 351 | |
9a7ab4b3 | 352 | #ifdef ENABLE_JC1_CHECKING |
d2097937 | 353 | static int CHECK_PUT (void *, struct jcf_partial *, int); |
ffb1f63d KG |
354 | |
355 | static int | |
0a2f0c54 | 356 | CHECK_PUT (void *ptr, struct jcf_partial *state, int i) |
9bbc7d9f | 357 | { |
400500c4 RK |
358 | if ((unsigned char *) ptr < state->chunk->data |
359 | || (unsigned char *) ptr + i > state->chunk->data + state->chunk->size) | |
360 | abort (); | |
361 | ||
9bbc7d9f PB |
362 | return 0; |
363 | } | |
364 | #else | |
45b44fbe | 365 | #define CHECK_PUT(PTR, STATE, I) ((void)0) |
9bbc7d9f PB |
366 | #endif |
367 | ||
368 | #define PUT1(X) (CHECK_PUT(ptr, state, 1), *ptr++ = (X)) | |
e04a16fb AG |
369 | #define PUT2(X) (PUT1((X) >> 8), PUT1((X) & 0xFF)) |
370 | #define PUT4(X) (PUT2((X) >> 16), PUT2((X) & 0xFFFF)) | |
9bbc7d9f | 371 | #define PUTN(P, N) (CHECK_PUT(ptr, state, N), memcpy(ptr, P, N), ptr += (N)) |
e04a16fb | 372 | |
ab150fb1 AG |
373 | /* There are some cases below where CHECK_PUT is guaranteed to fail. |
374 | Use the following macros in those specific cases. */ | |
375 | #define UNSAFE_PUT1(X) (*ptr++ = (X)) | |
376 | #define UNSAFE_PUT2(X) (UNSAFE_PUT1((X) >> 8), UNSAFE_PUT1((X) & 0xFF)) | |
377 | #define UNSAFE_PUT4(X) (UNSAFE_PUT2((X) >> 16), UNSAFE_PUT2((X) & 0xFFFF)) | |
378 | #define UNSAFE_PUTN(P, N) (memcpy(ptr, P, N), ptr += (N)) | |
379 | ||
e04a16fb | 380 | \f |
e4de5a10 PB |
381 | /* Allocate a new chunk on obstack WORK, and link it in after LAST. |
382 | Set the data and size fields to DATA and SIZE, respectively. | |
383 | However, if DATA is NULL and SIZE>0, allocate a buffer as well. */ | |
384 | ||
4bcde32e | 385 | static struct chunk * |
0a2f0c54 KG |
386 | alloc_chunk (struct chunk *last, unsigned char *data, |
387 | int size, struct obstack *work) | |
e4de5a10 | 388 | { |
c68b0a84 | 389 | struct chunk *chunk = obstack_alloc (work, sizeof(struct chunk)); |
e4de5a10 PB |
390 | |
391 | if (data == NULL && size > 0) | |
392 | data = obstack_alloc (work, size); | |
393 | ||
394 | chunk->next = NULL; | |
395 | chunk->data = data; | |
396 | chunk->size = size; | |
397 | if (last != NULL) | |
398 | last->next = chunk; | |
399 | return chunk; | |
400 | } | |
401 | ||
9a7ab4b3 | 402 | #ifdef ENABLE_JC1_CHECKING |
d2097937 | 403 | static int CHECK_OP (struct jcf_partial *); |
ffb1f63d KG |
404 | |
405 | static int | |
0a2f0c54 | 406 | CHECK_OP (struct jcf_partial *state) |
9bbc7d9f PB |
407 | { |
408 | if (state->bytecode.ptr > state->bytecode.limit) | |
400500c4 RK |
409 | abort (); |
410 | ||
9bbc7d9f PB |
411 | return 0; |
412 | } | |
413 | #else | |
400500c4 | 414 | #define CHECK_OP(STATE) ((void) 0) |
9bbc7d9f PB |
415 | #endif |
416 | ||
4bcde32e | 417 | static unsigned char * |
0a2f0c54 | 418 | append_chunk (unsigned char *data, int size, struct jcf_partial *state) |
e4de5a10 PB |
419 | { |
420 | state->chunk = alloc_chunk (state->chunk, data, size, state->chunk_obstack); | |
421 | if (state->first == NULL) | |
422 | state->first = state->chunk; | |
423 | return state->chunk->data; | |
424 | } | |
425 | ||
4bcde32e | 426 | static void |
0a2f0c54 | 427 | append_chunk_copy (unsigned char *data, int size, struct jcf_partial *state) |
e4de5a10 PB |
428 | { |
429 | unsigned char *ptr = append_chunk (NULL, size, state); | |
3885dfa7 | 430 | memcpy (ptr, data, size); |
e4de5a10 PB |
431 | } |
432 | \f | |
4bcde32e | 433 | static struct jcf_block * |
0a2f0c54 | 434 | gen_jcf_label (struct jcf_partial *state) |
e4de5a10 | 435 | { |
c68b0a84 KG |
436 | struct jcf_block *block |
437 | = obstack_alloc (state->chunk_obstack, sizeof (struct jcf_block)); | |
e4de5a10 PB |
438 | block->next = NULL; |
439 | block->linenumber = -1; | |
45b44fbe | 440 | block->pc = UNDEFINED_PC; |
e4de5a10 PB |
441 | return block; |
442 | } | |
443 | ||
4bcde32e | 444 | static void |
0a2f0c54 | 445 | finish_jcf_block (struct jcf_partial *state) |
e4de5a10 PB |
446 | { |
447 | struct jcf_block *block = state->last_block; | |
448 | struct jcf_relocation *reloc; | |
3885dfa7 | 449 | int code_length = BUFFER_LENGTH (&state->bytecode); |
e4de5a10 | 450 | int pc = state->code_length; |
3885dfa7 | 451 | append_chunk_copy (state->bytecode.data, code_length, state); |
e4de5a10 | 452 | BUFFER_RESET (&state->bytecode); |
45b44fbe | 453 | block->v.chunk = state->chunk; |
e4de5a10 PB |
454 | |
455 | /* Calculate code_length to the maximum value it can have. */ | |
45b44fbe | 456 | pc += block->v.chunk->size; |
e4de5a10 PB |
457 | for (reloc = block->u.relocations; reloc != NULL; reloc = reloc->next) |
458 | { | |
459 | int kind = reloc->kind; | |
3885dfa7 PB |
460 | if (kind == SWITCH_ALIGN_RELOC) |
461 | pc += 3; | |
462 | else if (kind > BLOCK_START_RELOC) | |
e4de5a10 PB |
463 | pc += 2; /* 2-byte offset may grow to 4-byte offset */ |
464 | else if (kind < -1) | |
465 | pc += 5; /* May need to add a goto_w. */ | |
466 | } | |
467 | state->code_length = pc; | |
468 | } | |
469 | ||
4bcde32e | 470 | static void |
0a2f0c54 | 471 | define_jcf_label (struct jcf_block *label, struct jcf_partial *state) |
e4de5a10 PB |
472 | { |
473 | if (state->last_block != NULL) | |
474 | finish_jcf_block (state); | |
475 | label->pc = state->code_length; | |
476 | if (state->blocks == NULL) | |
477 | state->blocks = label; | |
478 | else | |
479 | state->last_block->next = label; | |
480 | state->last_block = label; | |
481 | label->next = NULL; | |
482 | label->u.relocations = NULL; | |
483 | } | |
484 | ||
4bcde32e | 485 | static struct jcf_block * |
0a2f0c54 | 486 | get_jcf_label_here (struct jcf_partial *state) |
e4de5a10 PB |
487 | { |
488 | if (state->last_block != NULL && BUFFER_LENGTH (&state->bytecode) == 0) | |
489 | return state->last_block; | |
490 | else | |
491 | { | |
492 | struct jcf_block *label = gen_jcf_label (state); | |
493 | define_jcf_label (label, state); | |
494 | return label; | |
495 | } | |
496 | } | |
e04a16fb | 497 | |
e4de5a10 | 498 | /* Note a line number entry for the current PC and given LINE. */ |
e04a16fb | 499 | |
4bcde32e | 500 | static void |
0a2f0c54 | 501 | put_linenumber (int line, struct jcf_partial *state) |
e04a16fb | 502 | { |
63a212ed PB |
503 | struct jcf_block *label = get_jcf_label_here (state); |
504 | if (label->linenumber > 0) | |
505 | { | |
506 | label = gen_jcf_label (state); | |
507 | define_jcf_label (label, state); | |
508 | } | |
509 | label->linenumber = line; | |
e4de5a10 | 510 | state->linenumber_count++; |
e04a16fb | 511 | } |
e4de5a10 | 512 | |
3885dfa7 PB |
513 | /* Allocate a new jcf_handler, for a catch clause that catches exceptions |
514 | in the range (START_LABEL, END_LABEL). */ | |
515 | ||
516 | static struct jcf_handler * | |
0a2f0c54 KG |
517 | alloc_handler (struct jcf_block *start_label, struct jcf_block *end_label, |
518 | struct jcf_partial *state) | |
3885dfa7 | 519 | { |
c68b0a84 KG |
520 | struct jcf_handler *handler |
521 | = obstack_alloc (state->chunk_obstack, sizeof (struct jcf_handler)); | |
3885dfa7 PB |
522 | handler->start_label = start_label; |
523 | handler->end_label = end_label; | |
524 | handler->handler_label = get_jcf_label_here (state); | |
525 | if (state->handlers == NULL) | |
526 | state->handlers = handler; | |
527 | else | |
528 | state->last_handler->next = handler; | |
529 | state->last_handler = handler; | |
530 | handler->next = NULL; | |
531 | state->num_handlers++; | |
532 | return handler; | |
533 | } | |
534 | ||
e04a16fb AG |
535 | \f |
536 | /* The index of jvm local variable allocated for this DECL. | |
e4de5a10 PB |
537 | This is assigned when generating .class files; |
538 | contrast DECL_LOCAL_SLOT_NUMBER which is set when *reading* a .class file. | |
634661fe | 539 | (We don't allocate DECL_LANG_SPECIFIC for locals from Java source code.) */ |
e04a16fb AG |
540 | |
541 | #define DECL_LOCAL_INDEX(DECL) DECL_ALIGN(DECL) | |
542 | ||
543 | struct localvar_info | |
544 | { | |
e4de5a10 | 545 | struct localvar_info *next; |
e04a16fb | 546 | |
e4de5a10 PB |
547 | tree decl; |
548 | struct jcf_block *start_label; | |
549 | struct jcf_block *end_label; | |
e04a16fb AG |
550 | }; |
551 | ||
e4de5a10 PB |
552 | #define localvar_buffer ((struct localvar_info**) state->localvars.data) |
553 | #define localvar_max \ | |
554 | ((struct localvar_info**) state->localvars.ptr - localvar_buffer) | |
e04a16fb | 555 | |
4bcde32e | 556 | static void |
0a2f0c54 | 557 | localvar_alloc (tree decl, struct jcf_partial *state) |
e04a16fb | 558 | { |
e4de5a10 | 559 | struct jcf_block *start_label = get_jcf_label_here (state); |
e04a16fb AG |
560 | int wide = TYPE_IS_WIDE (TREE_TYPE (decl)); |
561 | int index; | |
3a976c72 KH |
562 | struct localvar_info *info; |
563 | struct localvar_info **ptr = localvar_buffer; | |
564 | struct localvar_info **limit | |
e4de5a10 PB |
565 | = (struct localvar_info**) state->localvars.ptr; |
566 | for (index = 0; ptr < limit; index++, ptr++) | |
e04a16fb | 567 | { |
e4de5a10 PB |
568 | if (ptr[0] == NULL |
569 | && (! wide || ((ptr+1) < limit && ptr[1] == NULL))) | |
e04a16fb AG |
570 | break; |
571 | } | |
e4de5a10 | 572 | if (ptr == limit) |
e04a16fb | 573 | { |
e4de5a10 PB |
574 | buffer_grow (&state->localvars, 2 * sizeof (struct localvar_info*)); |
575 | ptr = (struct localvar_info**) state->localvars.data + index; | |
576 | state->localvars.ptr = (unsigned char *) (ptr + 1 + wide); | |
e04a16fb | 577 | } |
c68b0a84 | 578 | info = obstack_alloc (state->chunk_obstack, sizeof (struct localvar_info)); |
e4de5a10 | 579 | ptr[0] = info; |
e04a16fb | 580 | if (wide) |
e4de5a10 | 581 | ptr[1] = (struct localvar_info *)(~0); |
e04a16fb | 582 | DECL_LOCAL_INDEX (decl) = index; |
e4de5a10 PB |
583 | info->decl = decl; |
584 | info->start_label = start_label; | |
e04a16fb | 585 | |
80d8e475 PB |
586 | if (debug_info_level > DINFO_LEVEL_TERSE |
587 | && DECL_NAME (decl) != NULL_TREE) | |
e04a16fb AG |
588 | { |
589 | /* Generate debugging info. */ | |
e4de5a10 PB |
590 | info->next = NULL; |
591 | if (state->last_lvar != NULL) | |
592 | state->last_lvar->next = info; | |
593 | else | |
594 | state->first_lvar = info; | |
595 | state->last_lvar = info; | |
596 | state->lvar_count++; | |
e04a16fb | 597 | } |
e04a16fb AG |
598 | } |
599 | ||
cd531a2e | 600 | static void |
72f339d2 | 601 | maybe_free_localvar (tree decl, struct jcf_partial *state, int really) |
e04a16fb | 602 | { |
e4de5a10 | 603 | struct jcf_block *end_label = get_jcf_label_here (state); |
e04a16fb | 604 | int index = DECL_LOCAL_INDEX (decl); |
3a976c72 KH |
605 | struct localvar_info **ptr = &localvar_buffer [index]; |
606 | struct localvar_info *info = *ptr; | |
e04a16fb | 607 | int wide = TYPE_IS_WIDE (TREE_TYPE (decl)); |
e04a16fb | 608 | |
e4de5a10 | 609 | info->end_label = end_label; |
e04a16fb AG |
610 | |
611 | if (info->decl != decl) | |
612 | abort (); | |
72f339d2 AH |
613 | if (! really) |
614 | return; | |
e4de5a10 | 615 | ptr[0] = NULL; |
e04a16fb AG |
616 | if (wide) |
617 | { | |
e4de5a10 | 618 | if (ptr[1] != (struct localvar_info *)(~0)) |
e04a16fb | 619 | abort (); |
e4de5a10 | 620 | ptr[1] = NULL; |
e04a16fb | 621 | } |
e04a16fb AG |
622 | } |
623 | ||
624 | \f | |
625 | #define STACK_TARGET 1 | |
626 | #define IGNORE_TARGET 2 | |
627 | ||
e04a16fb AG |
628 | /* Get the access flags of a class (TYPE_DECL), a method (FUNCTION_DECL), or |
629 | a field (FIELD_DECL or VAR_DECL, if static), as encoded in a .class file. */ | |
630 | ||
4bcde32e | 631 | static int |
0a2f0c54 | 632 | get_access_flags (tree decl) |
e04a16fb AG |
633 | { |
634 | int flags = 0; | |
635 | int isfield = TREE_CODE (decl) == FIELD_DECL || TREE_CODE (decl) == VAR_DECL; | |
eb34af89 | 636 | |
e04a16fb AG |
637 | if (isfield || TREE_CODE (decl) == FUNCTION_DECL) |
638 | { | |
639 | if (TREE_PROTECTED (decl)) | |
640 | flags |= ACC_PROTECTED; | |
641 | if (TREE_PRIVATE (decl)) | |
642 | flags |= ACC_PRIVATE; | |
643 | } | |
644 | else if (TREE_CODE (decl) == TYPE_DECL) | |
645 | { | |
eb34af89 RK |
646 | if (CLASS_PUBLIC (decl)) |
647 | flags |= ACC_PUBLIC; | |
648 | if (CLASS_FINAL (decl)) | |
649 | flags |= ACC_FINAL; | |
e04a16fb AG |
650 | if (CLASS_SUPER (decl)) |
651 | flags |= ACC_SUPER; | |
652 | if (CLASS_ABSTRACT (decl)) | |
653 | flags |= ACC_ABSTRACT; | |
654 | if (CLASS_INTERFACE (decl)) | |
655 | flags |= ACC_INTERFACE; | |
c2952b01 APB |
656 | if (CLASS_STATIC (decl)) |
657 | flags |= ACC_STATIC; | |
097684ce BM |
658 | if (CLASS_PRIVATE (decl)) |
659 | flags |= ACC_PRIVATE; | |
660 | if (CLASS_PROTECTED (decl)) | |
661 | flags |= ACC_PROTECTED; | |
c2952b01 APB |
662 | if (ANONYMOUS_CLASS_P (TREE_TYPE (decl)) |
663 | || LOCAL_CLASS_P (TREE_TYPE (decl))) | |
664 | flags |= ACC_PRIVATE; | |
6b6294f1 TT |
665 | if (CLASS_STRICTFP (decl)) |
666 | flags |= ACC_STRICT; | |
e04a16fb AG |
667 | } |
668 | else | |
400500c4 RK |
669 | abort (); |
670 | ||
e04a16fb AG |
671 | if (TREE_CODE (decl) == FUNCTION_DECL) |
672 | { | |
eb34af89 RK |
673 | if (METHOD_PUBLIC (decl)) |
674 | flags |= ACC_PUBLIC; | |
675 | if (METHOD_FINAL (decl)) | |
676 | flags |= ACC_FINAL; | |
e04a16fb AG |
677 | if (METHOD_NATIVE (decl)) |
678 | flags |= ACC_NATIVE; | |
679 | if (METHOD_STATIC (decl)) | |
680 | flags |= ACC_STATIC; | |
e04a16fb AG |
681 | if (METHOD_SYNCHRONIZED (decl)) |
682 | flags |= ACC_SYNCHRONIZED; | |
683 | if (METHOD_ABSTRACT (decl)) | |
684 | flags |= ACC_ABSTRACT; | |
6b6294f1 TT |
685 | if (METHOD_STRICTFP (decl)) |
686 | flags |= ACC_STRICT; | |
e04a16fb AG |
687 | } |
688 | if (isfield) | |
689 | { | |
eb34af89 RK |
690 | if (FIELD_PUBLIC (decl)) |
691 | flags |= ACC_PUBLIC; | |
692 | if (FIELD_FINAL (decl)) | |
693 | flags |= ACC_FINAL; | |
e04a16fb AG |
694 | if (FIELD_STATIC (decl)) |
695 | flags |= ACC_STATIC; | |
696 | if (FIELD_VOLATILE (decl)) | |
697 | flags |= ACC_VOLATILE; | |
698 | if (FIELD_TRANSIENT (decl)) | |
699 | flags |= ACC_TRANSIENT; | |
700 | } | |
701 | return flags; | |
702 | } | |
703 | ||
704 | /* Write the list of segments starting at CHUNKS to STREAM. */ | |
705 | ||
4bcde32e | 706 | static void |
0a2f0c54 | 707 | write_chunks (FILE* stream, struct chunk *chunks) |
e04a16fb AG |
708 | { |
709 | for (; chunks != NULL; chunks = chunks->next) | |
710 | fwrite (chunks->data, chunks->size, 1, stream); | |
711 | } | |
712 | ||
9bbc7d9f PB |
713 | /* Push a 1-word constant in the constant pool at the given INDEX. |
714 | (Caller is responsible for doing NOTE_PUSH.) */ | |
715 | ||
e4de5a10 | 716 | static void |
0a2f0c54 | 717 | push_constant1 (HOST_WIDE_INT index, struct jcf_partial *state) |
e04a16fb | 718 | { |
3885dfa7 | 719 | RESERVE (3); |
e04a16fb AG |
720 | if (index < 256) |
721 | { | |
722 | OP1 (OPCODE_ldc); | |
723 | OP1 (index); | |
724 | } | |
725 | else | |
726 | { | |
727 | OP1 (OPCODE_ldc_w); | |
728 | OP2 (index); | |
729 | } | |
730 | } | |
731 | ||
9bbc7d9f PB |
732 | /* Push a 2-word constant in the constant pool at the given INDEX. |
733 | (Caller is responsible for doing NOTE_PUSH.) */ | |
734 | ||
e4de5a10 | 735 | static void |
0a2f0c54 | 736 | push_constant2 (HOST_WIDE_INT index, struct jcf_partial *state) |
e04a16fb AG |
737 | { |
738 | RESERVE (3); | |
739 | OP1 (OPCODE_ldc2_w); | |
740 | OP2 (index); | |
741 | } | |
742 | ||
e4de5a10 PB |
743 | /* Push 32-bit integer constant on VM stack. |
744 | Caller is responsible for doing NOTE_PUSH. */ | |
745 | ||
746 | static void | |
0a2f0c54 | 747 | push_int_const (HOST_WIDE_INT i, struct jcf_partial *state) |
e04a16fb AG |
748 | { |
749 | RESERVE(3); | |
750 | if (i >= -1 && i <= 5) | |
751 | OP1(OPCODE_iconst_0 + i); | |
752 | else if (i >= -128 && i < 128) | |
753 | { | |
754 | OP1(OPCODE_bipush); | |
755 | OP1(i); | |
756 | } | |
757 | else if (i >= -32768 && i < 32768) | |
758 | { | |
759 | OP1(OPCODE_sipush); | |
760 | OP2(i); | |
761 | } | |
762 | else | |
763 | { | |
cacc154e APB |
764 | i = find_constant1 (&state->cpool, CONSTANT_Integer, |
765 | (jword)(i & 0xFFFFFFFF)); | |
3885dfa7 | 766 | push_constant1 (i, state); |
e04a16fb AG |
767 | } |
768 | } | |
769 | ||
23a7b8f5 | 770 | static int |
0a2f0c54 KG |
771 | find_constant_wide (HOST_WIDE_INT lo, HOST_WIDE_INT hi, |
772 | struct jcf_partial *state) | |
23a7b8f5 PB |
773 | { |
774 | HOST_WIDE_INT w1, w2; | |
775 | lshift_double (lo, hi, -32, 64, &w1, &w2, 1); | |
776 | return find_constant2 (&state->cpool, CONSTANT_Long, | |
cacc154e | 777 | (jword)(w1 & 0xFFFFFFFF), (jword)(lo & 0xFFFFFFFF)); |
df1e6be5 PB |
778 | } |
779 | ||
780 | /* Find or allocate a constant pool entry for the given VALUE. | |
781 | Return the index in the constant pool. */ | |
782 | ||
783 | static int | |
0a2f0c54 | 784 | find_constant_index (tree value, struct jcf_partial *state) |
df1e6be5 PB |
785 | { |
786 | if (TREE_CODE (value) == INTEGER_CST) | |
787 | { | |
788 | if (TYPE_PRECISION (TREE_TYPE (value)) <= 32) | |
789 | return find_constant1 (&state->cpool, CONSTANT_Integer, | |
cacc154e | 790 | (jword)(TREE_INT_CST_LOW (value) & 0xFFFFFFFF)); |
df1e6be5 PB |
791 | else |
792 | return find_constant_wide (TREE_INT_CST_LOW (value), | |
793 | TREE_INT_CST_HIGH (value), state); | |
794 | } | |
795 | else if (TREE_CODE (value) == REAL_CST) | |
796 | { | |
797 | long words[2]; | |
efdc7e19 RH |
798 | |
799 | real_to_target (words, &TREE_REAL_CST (value), | |
800 | TYPE_MODE (TREE_TYPE (value))); | |
801 | words[0] &= 0xffffffff; | |
802 | words[1] &= 0xffffffff; | |
803 | ||
df1e6be5 | 804 | if (TYPE_PRECISION (TREE_TYPE (value)) == 32) |
efdc7e19 | 805 | return find_constant1 (&state->cpool, CONSTANT_Float, (jword)words[0]); |
df1e6be5 | 806 | else |
efdc7e19 RH |
807 | return find_constant2 (&state->cpool, CONSTANT_Double, |
808 | (jword)words[1-FLOAT_WORDS_BIG_ENDIAN], | |
809 | (jword)words[FLOAT_WORDS_BIG_ENDIAN]); | |
df1e6be5 PB |
810 | } |
811 | else if (TREE_CODE (value) == STRING_CST) | |
400500c4 RK |
812 | return find_string_constant (&state->cpool, value); |
813 | ||
df1e6be5 | 814 | else |
400500c4 | 815 | abort (); |
df1e6be5 | 816 | } |
23a7b8f5 | 817 | |
e4de5a10 PB |
818 | /* Push 64-bit long constant on VM stack. |
819 | Caller is responsible for doing NOTE_PUSH. */ | |
820 | ||
821 | static void | |
0a2f0c54 | 822 | push_long_const (HOST_WIDE_INT lo, HOST_WIDE_INT hi, struct jcf_partial *state) |
e04a16fb | 823 | { |
a2761d68 AH |
824 | HOST_WIDE_INT highpart, dummy; |
825 | jint lowpart = WORD_TO_INT (lo); | |
826 | ||
827 | rshift_double (lo, hi, 32, 64, &highpart, &dummy, 1); | |
828 | ||
829 | if (highpart == 0 && (lowpart == 0 || lowpart == 1)) | |
e04a16fb AG |
830 | { |
831 | RESERVE(1); | |
a2761d68 | 832 | OP1(OPCODE_lconst_0 + lowpart); |
e04a16fb | 833 | } |
a2761d68 AH |
834 | else if ((highpart == 0 && lowpart > 0 && lowpart < 32768) |
835 | || (highpart == -1 && lowpart < 0 && lowpart >= -32768)) | |
e04a16fb | 836 | { |
a2761d68 | 837 | push_int_const (lowpart, state); |
e04a16fb AG |
838 | RESERVE (1); |
839 | OP1 (OPCODE_i2l); | |
840 | } | |
e04a16fb | 841 | else |
23a7b8f5 | 842 | push_constant2 (find_constant_wide (lo, hi, state), state); |
e04a16fb AG |
843 | } |
844 | ||
e4de5a10 | 845 | static void |
0a2f0c54 | 846 | field_op (tree field, int opcode, struct jcf_partial *state) |
e04a16fb | 847 | { |
e4de5a10 | 848 | int index = find_fieldref_index (&state->cpool, field); |
e04a16fb AG |
849 | RESERVE (3); |
850 | OP1 (opcode); | |
851 | OP2 (index); | |
852 | } | |
853 | ||
854 | /* Returns an integer in the range 0 (for 'int') through 4 (for object | |
855 | reference) to 7 (for 'short') which matches the pattern of how JVM | |
856 | opcodes typically depend on the operand type. */ | |
857 | ||
4bcde32e | 858 | static int |
0a2f0c54 | 859 | adjust_typed_op (tree type, int max) |
e04a16fb AG |
860 | { |
861 | switch (TREE_CODE (type)) | |
862 | { | |
e04a16fb AG |
863 | case POINTER_TYPE: |
864 | case RECORD_TYPE: return 4; | |
e4de5a10 | 865 | case BOOLEAN_TYPE: |
3885dfa7 | 866 | return TYPE_PRECISION (type) == 32 || max < 5 ? 0 : 5; |
e4de5a10 | 867 | case CHAR_TYPE: |
3885dfa7 | 868 | return TYPE_PRECISION (type) == 32 || max < 6 ? 0 : 6; |
e04a16fb AG |
869 | case INTEGER_TYPE: |
870 | switch (TYPE_PRECISION (type)) | |
871 | { | |
3885dfa7 PB |
872 | case 8: return max < 5 ? 0 : 5; |
873 | case 16: return max < 7 ? 0 : 7; | |
e04a16fb AG |
874 | case 32: return 0; |
875 | case 64: return 1; | |
876 | } | |
877 | break; | |
878 | case REAL_TYPE: | |
879 | switch (TYPE_PRECISION (type)) | |
880 | { | |
881 | case 32: return 2; | |
882 | case 64: return 3; | |
883 | } | |
884 | break; | |
3885dfa7 PB |
885 | default: |
886 | break; | |
e04a16fb AG |
887 | } |
888 | abort (); | |
889 | } | |
890 | ||
e4de5a10 | 891 | static void |
0a2f0c54 | 892 | maybe_wide (int opcode, int index, struct jcf_partial *state) |
e04a16fb AG |
893 | { |
894 | if (index >= 256) | |
895 | { | |
896 | RESERVE (4); | |
e4de5a10 | 897 | OP1 (OPCODE_wide); |
e04a16fb AG |
898 | OP1 (opcode); |
899 | OP2 (index); | |
900 | } | |
901 | else | |
902 | { | |
903 | RESERVE (2); | |
904 | OP1 (opcode); | |
905 | OP1 (index); | |
906 | } | |
907 | } | |
908 | ||
e4de5a10 PB |
909 | /* Compile code to duplicate with offset, where |
910 | SIZE is the size of the stack item to duplicate (1 or 2), abd | |
911 | OFFSET is where to insert the result (must be 0, 1, or 2). | |
912 | (The new words get inserted at stack[SP-size-offset].) */ | |
e04a16fb | 913 | |
e4de5a10 | 914 | static void |
0a2f0c54 | 915 | emit_dup (int size, int offset, struct jcf_partial *state) |
e4de5a10 PB |
916 | { |
917 | int kind; | |
918 | if (size == 0) | |
919 | return; | |
920 | RESERVE(1); | |
921 | if (offset == 0) | |
922 | kind = size == 1 ? OPCODE_dup : OPCODE_dup2; | |
923 | else if (offset == 1) | |
924 | kind = size == 1 ? OPCODE_dup_x1 : OPCODE_dup2_x1; | |
925 | else if (offset == 2) | |
926 | kind = size == 1 ? OPCODE_dup_x2 : OPCODE_dup2_x2; | |
927 | else | |
928 | abort(); | |
929 | OP1 (kind); | |
930 | NOTE_PUSH (size); | |
931 | } | |
932 | ||
933 | static void | |
0a2f0c54 | 934 | emit_pop (int size, struct jcf_partial *state) |
e4de5a10 PB |
935 | { |
936 | RESERVE (1); | |
937 | OP1 (OPCODE_pop - 1 + size); | |
938 | } | |
939 | ||
940 | static void | |
0a2f0c54 | 941 | emit_iinc (tree var, HOST_WIDE_INT value, struct jcf_partial *state) |
e4de5a10 PB |
942 | { |
943 | int slot = DECL_LOCAL_INDEX (var); | |
944 | ||
945 | if (value < -128 || value > 127 || slot >= 256) | |
946 | { | |
947 | RESERVE (6); | |
948 | OP1 (OPCODE_wide); | |
949 | OP1 (OPCODE_iinc); | |
950 | OP2 (slot); | |
951 | OP2 (value); | |
952 | } | |
953 | else | |
954 | { | |
955 | RESERVE (3); | |
956 | OP1 (OPCODE_iinc); | |
957 | OP1 (slot); | |
958 | OP1 (value); | |
959 | } | |
960 | } | |
961 | ||
962 | static void | |
0a2f0c54 KG |
963 | emit_load_or_store (tree var, /* Variable to load from or store into. */ |
964 | int opcode, /* Either OPCODE_iload or OPCODE_istore. */ | |
965 | struct jcf_partial *state) | |
e4de5a10 PB |
966 | { |
967 | tree type = TREE_TYPE (var); | |
3885dfa7 | 968 | int kind = adjust_typed_op (type, 4); |
e4de5a10 PB |
969 | int index = DECL_LOCAL_INDEX (var); |
970 | if (index <= 3) | |
971 | { | |
972 | RESERVE (1); | |
973 | OP1 (opcode + 5 + 4 * kind + index); /* [ilfda]{load,store}_[0123] */ | |
974 | } | |
975 | else | |
3885dfa7 | 976 | maybe_wide (opcode + kind, index, state); /* [ilfda]{load,store} */ |
e4de5a10 PB |
977 | } |
978 | ||
979 | static void | |
0a2f0c54 | 980 | emit_load (tree var, struct jcf_partial *state) |
e4de5a10 PB |
981 | { |
982 | emit_load_or_store (var, OPCODE_iload, state); | |
983 | NOTE_PUSH (TYPE_IS_WIDE (TREE_TYPE (var)) ? 2 : 1); | |
984 | } | |
985 | ||
986 | static void | |
0a2f0c54 | 987 | emit_store (tree var, struct jcf_partial *state) |
e4de5a10 PB |
988 | { |
989 | emit_load_or_store (var, OPCODE_istore, state); | |
990 | NOTE_POP (TYPE_IS_WIDE (TREE_TYPE (var)) ? 2 : 1); | |
991 | } | |
992 | ||
3885dfa7 | 993 | static void |
0a2f0c54 KG |
994 | emit_unop (enum java_opcode opcode, tree type ATTRIBUTE_UNUSED, |
995 | struct jcf_partial *state) | |
3885dfa7 | 996 | { |
3885dfa7 PB |
997 | RESERVE(1); |
998 | OP1 (opcode); | |
999 | } | |
1000 | ||
e4de5a10 | 1001 | static void |
0a2f0c54 | 1002 | emit_binop (enum java_opcode opcode, tree type, struct jcf_partial *state) |
e4de5a10 PB |
1003 | { |
1004 | int size = TYPE_IS_WIDE (type) ? 2 : 1; | |
1005 | RESERVE(1); | |
1006 | OP1 (opcode); | |
1007 | NOTE_POP (size); | |
1008 | } | |
1009 | ||
45b44fbe | 1010 | static void |
0a2f0c54 KG |
1011 | emit_reloc (HOST_WIDE_INT value, int kind, |
1012 | struct jcf_block *target, struct jcf_partial *state) | |
e4de5a10 | 1013 | { |
c68b0a84 KG |
1014 | struct jcf_relocation *reloc |
1015 | = obstack_alloc (state->chunk_obstack, sizeof (struct jcf_relocation)); | |
e4de5a10 PB |
1016 | struct jcf_block *block = state->last_block; |
1017 | reloc->next = block->u.relocations; | |
1018 | block->u.relocations = reloc; | |
e4de5a10 | 1019 | reloc->offset = BUFFER_LENGTH (&state->bytecode); |
e4de5a10 | 1020 | reloc->label = target; |
3885dfa7 PB |
1021 | reloc->kind = kind; |
1022 | if (kind == 0 || kind == BLOCK_START_RELOC) | |
1023 | OP4 (value); | |
1024 | else if (kind != SWITCH_ALIGN_RELOC) | |
1025 | OP2 (value); | |
e4de5a10 PB |
1026 | } |
1027 | ||
1028 | static void | |
0a2f0c54 | 1029 | emit_switch_reloc (struct jcf_block *label, struct jcf_partial *state) |
3885dfa7 | 1030 | { |
cacc154e | 1031 | emit_reloc (RELOCATION_VALUE_0, BLOCK_START_RELOC, label, state); |
3885dfa7 PB |
1032 | } |
1033 | ||
1034 | /* Similar to emit_switch_reloc, | |
1035 | but re-uses an existing case reloc. */ | |
1036 | ||
1037 | static void | |
0a2f0c54 | 1038 | emit_case_reloc (struct jcf_relocation *reloc, struct jcf_partial *state) |
e4de5a10 | 1039 | { |
e4de5a10 PB |
1040 | struct jcf_block *block = state->last_block; |
1041 | reloc->next = block->u.relocations; | |
1042 | block->u.relocations = reloc; | |
e4de5a10 | 1043 | reloc->offset = BUFFER_LENGTH (&state->bytecode); |
3885dfa7 PB |
1044 | reloc->kind = BLOCK_START_RELOC; |
1045 | OP4 (0); | |
1046 | } | |
1047 | ||
1048 | /* Emit a conditional jump to TARGET with a 2-byte relative jump offset | |
1049 | The opcode is OPCODE, the inverted opcode is INV_OPCODE. */ | |
1050 | ||
1051 | static void | |
0a2f0c54 KG |
1052 | emit_if (struct jcf_block *target, int opcode, int inv_opcode, |
1053 | struct jcf_partial *state) | |
3885dfa7 | 1054 | { |
f85cedde | 1055 | RESERVE(3); |
3885dfa7 | 1056 | OP1 (opcode); |
5f9ee695 | 1057 | /* value is 1 byte from reloc back to start of instruction. */ |
cacc154e | 1058 | emit_reloc (RELOCATION_VALUE_1, - inv_opcode, target, state); |
e4de5a10 PB |
1059 | } |
1060 | ||
1061 | static void | |
0a2f0c54 | 1062 | emit_goto (struct jcf_block *target, struct jcf_partial *state) |
e4de5a10 | 1063 | { |
f85cedde | 1064 | RESERVE(3); |
3885dfa7 | 1065 | OP1 (OPCODE_goto); |
5f9ee695 | 1066 | /* Value is 1 byte from reloc back to start of instruction. */ |
cacc154e | 1067 | emit_reloc (RELOCATION_VALUE_1, OPCODE_goto_w, target, state); |
e4de5a10 PB |
1068 | } |
1069 | ||
1070 | static void | |
0a2f0c54 | 1071 | emit_jsr (struct jcf_block *target, struct jcf_partial *state) |
e4de5a10 | 1072 | { |
f85cedde | 1073 | RESERVE(3); |
3885dfa7 | 1074 | OP1 (OPCODE_jsr); |
5f9ee695 | 1075 | /* Value is 1 byte from reloc back to start of instruction. */ |
cacc154e | 1076 | emit_reloc (RELOCATION_VALUE_1, OPCODE_jsr_w, target, state); |
72f339d2 | 1077 | state->num_jsrs++; |
e4de5a10 PB |
1078 | } |
1079 | ||
1080 | /* Generate code to evaluate EXP. If the result is true, | |
1081 | branch to TRUE_LABEL; otherwise, branch to FALSE_LABEL. | |
634661fe | 1082 | TRUE_BRANCH_FIRST is a code generation hint that the |
e4de5a10 PB |
1083 | TRUE_LABEL may follow right after this. (The idea is that we |
1084 | may be able to optimize away GOTO TRUE_LABEL; TRUE_LABEL:) */ | |
e04a16fb | 1085 | |
4bcde32e | 1086 | static void |
0a2f0c54 KG |
1087 | generate_bytecode_conditional (tree exp, |
1088 | struct jcf_block *true_label, | |
1089 | struct jcf_block *false_label, | |
1090 | int true_branch_first, | |
1091 | struct jcf_partial *state) | |
e4de5a10 | 1092 | { |
e4de5a10 PB |
1093 | tree exp0, exp1, type; |
1094 | int save_SP = state->code_SP; | |
1095 | enum java_opcode op, negop; | |
1096 | switch (TREE_CODE (exp)) | |
1097 | { | |
1098 | case INTEGER_CST: | |
1099 | emit_goto (integer_zerop (exp) ? false_label : true_label, state); | |
1100 | break; | |
1101 | case COND_EXPR: | |
1102 | { | |
1103 | struct jcf_block *then_label = gen_jcf_label (state); | |
1104 | struct jcf_block *else_label = gen_jcf_label (state); | |
1105 | int save_SP_before, save_SP_after; | |
1106 | generate_bytecode_conditional (TREE_OPERAND (exp, 0), | |
1107 | then_label, else_label, 1, state); | |
1108 | define_jcf_label (then_label, state); | |
1109 | save_SP_before = state->code_SP; | |
1110 | generate_bytecode_conditional (TREE_OPERAND (exp, 1), | |
1111 | true_label, false_label, 1, state); | |
1112 | save_SP_after = state->code_SP; | |
1113 | state->code_SP = save_SP_before; | |
1114 | define_jcf_label (else_label, state); | |
1115 | generate_bytecode_conditional (TREE_OPERAND (exp, 2), | |
1116 | true_label, false_label, | |
1117 | true_branch_first, state); | |
1118 | if (state->code_SP != save_SP_after) | |
400500c4 | 1119 | abort (); |
e4de5a10 PB |
1120 | } |
1121 | break; | |
3885dfa7 | 1122 | case TRUTH_NOT_EXPR: |
400500c4 RK |
1123 | generate_bytecode_conditional (TREE_OPERAND (exp, 0), false_label, |
1124 | true_label, ! true_branch_first, state); | |
3885dfa7 | 1125 | break; |
e4de5a10 PB |
1126 | case TRUTH_ANDIF_EXPR: |
1127 | { | |
1128 | struct jcf_block *next_label = gen_jcf_label (state); | |
1129 | generate_bytecode_conditional (TREE_OPERAND (exp, 0), | |
1130 | next_label, false_label, 1, state); | |
1131 | define_jcf_label (next_label, state); | |
1132 | generate_bytecode_conditional (TREE_OPERAND (exp, 1), | |
1133 | true_label, false_label, 1, state); | |
1134 | } | |
1135 | break; | |
1136 | case TRUTH_ORIF_EXPR: | |
1137 | { | |
1138 | struct jcf_block *next_label = gen_jcf_label (state); | |
1139 | generate_bytecode_conditional (TREE_OPERAND (exp, 0), | |
1140 | true_label, next_label, 1, state); | |
1141 | define_jcf_label (next_label, state); | |
1142 | generate_bytecode_conditional (TREE_OPERAND (exp, 1), | |
1143 | true_label, false_label, 1, state); | |
1144 | } | |
1145 | break; | |
1146 | compare_1: | |
1147 | /* Assuming op is one of the 2-operand if_icmp<COND> instructions, | |
1148 | set it to the corresponding 1-operand if<COND> instructions. */ | |
1149 | op = op - 6; | |
1150 | /* FALLTHROUGH */ | |
1151 | compare_2: | |
1152 | /* The opcodes with their inverses are allocated in pairs. | |
1153 | E.g. The inverse of if_icmplt (161) is if_icmpge (162). */ | |
1154 | negop = (op & 1) ? op + 1 : op - 1; | |
1155 | compare_2_ptr: | |
1156 | if (true_branch_first) | |
1157 | { | |
1158 | emit_if (false_label, negop, op, state); | |
1159 | emit_goto (true_label, state); | |
1160 | } | |
1161 | else | |
1162 | { | |
1163 | emit_if (true_label, op, negop, state); | |
1164 | emit_goto (false_label, state); | |
1165 | } | |
1166 | break; | |
1167 | case EQ_EXPR: | |
1168 | op = OPCODE_if_icmpeq; | |
1169 | goto compare; | |
1170 | case NE_EXPR: | |
1171 | op = OPCODE_if_icmpne; | |
1172 | goto compare; | |
1173 | case GT_EXPR: | |
1174 | op = OPCODE_if_icmpgt; | |
1175 | goto compare; | |
1176 | case LT_EXPR: | |
1177 | op = OPCODE_if_icmplt; | |
1178 | goto compare; | |
1179 | case GE_EXPR: | |
1180 | op = OPCODE_if_icmpge; | |
1181 | goto compare; | |
1182 | case LE_EXPR: | |
1183 | op = OPCODE_if_icmple; | |
1184 | goto compare; | |
1185 | compare: | |
1186 | exp0 = TREE_OPERAND (exp, 0); | |
1187 | exp1 = TREE_OPERAND (exp, 1); | |
1188 | type = TREE_TYPE (exp0); | |
1189 | switch (TREE_CODE (type)) | |
1190 | { | |
3885dfa7 | 1191 | int opf; |
e4de5a10 PB |
1192 | case POINTER_TYPE: case RECORD_TYPE: |
1193 | switch (TREE_CODE (exp)) | |
1194 | { | |
1195 | case EQ_EXPR: op = OPCODE_if_acmpeq; break; | |
1196 | case NE_EXPR: op = OPCODE_if_acmpne; break; | |
1197 | default: abort(); | |
1198 | } | |
1199 | if (integer_zerop (exp1) || integer_zerop (exp0)) | |
1200 | { | |
81baa09a | 1201 | generate_bytecode_insns (integer_zerop (exp0) ? exp1 : exp0, |
e4de5a10 PB |
1202 | STACK_TARGET, state); |
1203 | op = op + (OPCODE_ifnull - OPCODE_if_acmpeq); | |
1204 | negop = (op & 1) ? op - 1 : op + 1; | |
1205 | NOTE_POP (1); | |
1206 | goto compare_2_ptr; | |
1207 | } | |
1208 | generate_bytecode_insns (exp0, STACK_TARGET, state); | |
1209 | generate_bytecode_insns (exp1, STACK_TARGET, state); | |
1210 | NOTE_POP (2); | |
1211 | goto compare_2; | |
1212 | case REAL_TYPE: | |
3885dfa7 PB |
1213 | generate_bytecode_insns (exp0, STACK_TARGET, state); |
1214 | generate_bytecode_insns (exp1, STACK_TARGET, state); | |
de7b168e | 1215 | if (op == OPCODE_if_icmplt || op == OPCODE_if_icmple) |
3885dfa7 PB |
1216 | opf = OPCODE_fcmpg; |
1217 | else | |
1218 | opf = OPCODE_fcmpl; | |
1219 | if (TYPE_PRECISION (type) > 32) | |
1220 | { | |
1221 | opf += 2; | |
1222 | NOTE_POP (4); | |
1223 | } | |
1224 | else | |
1225 | NOTE_POP (2); | |
1226 | RESERVE (1); | |
1227 | OP1 (opf); | |
1228 | goto compare_1; | |
e4de5a10 PB |
1229 | case INTEGER_TYPE: |
1230 | if (TYPE_PRECISION (type) > 32) | |
1231 | { | |
1232 | generate_bytecode_insns (exp0, STACK_TARGET, state); | |
1233 | generate_bytecode_insns (exp1, STACK_TARGET, state); | |
1234 | NOTE_POP (4); | |
1235 | RESERVE (1); | |
1236 | OP1 (OPCODE_lcmp); | |
1237 | goto compare_1; | |
1238 | } | |
0d42c3c2 | 1239 | /* FALLTHROUGH */ |
e4de5a10 PB |
1240 | default: |
1241 | if (integer_zerop (exp1)) | |
1242 | { | |
1243 | generate_bytecode_insns (exp0, STACK_TARGET, state); | |
1244 | NOTE_POP (1); | |
1245 | goto compare_1; | |
1246 | } | |
1247 | if (integer_zerop (exp0)) | |
1248 | { | |
1249 | switch (op) | |
1250 | { | |
1251 | case OPCODE_if_icmplt: | |
1252 | case OPCODE_if_icmpge: | |
1253 | op += 2; | |
1254 | break; | |
1255 | case OPCODE_if_icmpgt: | |
1256 | case OPCODE_if_icmple: | |
1257 | op -= 2; | |
1258 | break; | |
3885dfa7 PB |
1259 | default: |
1260 | break; | |
e4de5a10 PB |
1261 | } |
1262 | generate_bytecode_insns (exp1, STACK_TARGET, state); | |
1263 | NOTE_POP (1); | |
1264 | goto compare_1; | |
1265 | } | |
1266 | generate_bytecode_insns (exp0, STACK_TARGET, state); | |
1267 | generate_bytecode_insns (exp1, STACK_TARGET, state); | |
1268 | NOTE_POP (2); | |
1269 | goto compare_2; | |
1270 | } | |
1271 | ||
1272 | default: | |
1273 | generate_bytecode_insns (exp, STACK_TARGET, state); | |
1274 | NOTE_POP (1); | |
1275 | if (true_branch_first) | |
1276 | { | |
1277 | emit_if (false_label, OPCODE_ifeq, OPCODE_ifne, state); | |
1278 | emit_goto (true_label, state); | |
1279 | } | |
1280 | else | |
1281 | { | |
1282 | emit_if (true_label, OPCODE_ifne, OPCODE_ifeq, state); | |
1283 | emit_goto (false_label, state); | |
1284 | } | |
1285 | break; | |
1286 | } | |
1287 | if (save_SP != state->code_SP) | |
400500c4 | 1288 | abort (); |
e4de5a10 PB |
1289 | } |
1290 | ||
2d93b924 | 1291 | /* Call pending cleanups i.e. those for surrounding TRY_FINALLY_EXPRs. |
45b44fbe PB |
1292 | but only as far out as LIMIT (since we are about to jump to the |
1293 | emit label that is LIMIT). */ | |
1294 | ||
1295 | static void | |
0a2f0c54 | 1296 | call_cleanups (struct jcf_block *limit, struct jcf_partial *state) |
45b44fbe PB |
1297 | { |
1298 | struct jcf_block *block = state->labeled_blocks; | |
1299 | for (; block != limit; block = block->next) | |
1300 | { | |
1301 | if (block->pc == PENDING_CLEANUP_PC) | |
1302 | emit_jsr (block, state); | |
1303 | } | |
1304 | } | |
1305 | ||
4bcde32e | 1306 | static void |
0a2f0c54 | 1307 | generate_bytecode_return (tree exp, struct jcf_partial *state) |
bb6e881c PB |
1308 | { |
1309 | tree return_type = TREE_TYPE (TREE_TYPE (state->current_method)); | |
1310 | int returns_void = TREE_CODE (return_type) == VOID_TYPE; | |
1311 | int op; | |
1312 | again: | |
1313 | if (exp != NULL) | |
1314 | { | |
1315 | switch (TREE_CODE (exp)) | |
1316 | { | |
1317 | case COMPOUND_EXPR: | |
1318 | generate_bytecode_insns (TREE_OPERAND (exp, 0), IGNORE_TARGET, | |
1319 | state); | |
1320 | exp = TREE_OPERAND (exp, 1); | |
1321 | goto again; | |
1322 | case COND_EXPR: | |
1323 | { | |
1324 | struct jcf_block *then_label = gen_jcf_label (state); | |
1325 | struct jcf_block *else_label = gen_jcf_label (state); | |
1326 | generate_bytecode_conditional (TREE_OPERAND (exp, 0), | |
1327 | then_label, else_label, 1, state); | |
1328 | define_jcf_label (then_label, state); | |
1329 | generate_bytecode_return (TREE_OPERAND (exp, 1), state); | |
1330 | define_jcf_label (else_label, state); | |
1331 | generate_bytecode_return (TREE_OPERAND (exp, 2), state); | |
1332 | } | |
1333 | return; | |
1334 | default: | |
1335 | generate_bytecode_insns (exp, | |
1336 | returns_void ? IGNORE_TARGET | |
1337 | : STACK_TARGET, state); | |
1338 | } | |
1339 | } | |
1340 | if (returns_void) | |
1341 | { | |
1342 | op = OPCODE_return; | |
3e411c3f | 1343 | call_cleanups (NULL, state); |
bb6e881c PB |
1344 | } |
1345 | else | |
1346 | { | |
1347 | op = OPCODE_ireturn + adjust_typed_op (return_type, 4); | |
1348 | if (state->num_finalizers > 0) | |
1349 | { | |
1350 | if (state->return_value_decl == NULL_TREE) | |
1351 | { | |
1352 | state->return_value_decl | |
1353 | = build_decl (VAR_DECL, NULL_TREE, TREE_TYPE (exp)); | |
1354 | localvar_alloc (state->return_value_decl, state); | |
1355 | } | |
1356 | emit_store (state->return_value_decl, state); | |
3e411c3f | 1357 | call_cleanups (NULL, state); |
bb6e881c | 1358 | emit_load (state->return_value_decl, state); |
72f339d2 | 1359 | /* If we call maybe_free_localvar (state->return_value_decl, state, 1), |
bb6e881c PB |
1360 | then we risk the save decl erroneously re-used in the |
1361 | finalizer. Instead, we keep the state->return_value_decl | |
1362 | allocated through the rest of the method. This is not | |
1363 | the greatest solution, but it is at least simple and safe. */ | |
1364 | } | |
1365 | } | |
1366 | RESERVE (1); | |
1367 | OP1 (op); | |
1368 | } | |
1369 | ||
e4de5a10 PB |
1370 | /* Generate bytecode for sub-expression EXP of METHOD. |
1371 | TARGET is one of STACK_TARGET or IGNORE_TARGET. */ | |
1372 | ||
1373 | static void | |
0a2f0c54 | 1374 | generate_bytecode_insns (tree exp, int target, struct jcf_partial *state) |
e04a16fb | 1375 | { |
1a27eec1 | 1376 | tree type, arg; |
e04a16fb AG |
1377 | enum java_opcode jopcode; |
1378 | int op; | |
e4de5a10 PB |
1379 | HOST_WIDE_INT value; |
1380 | int post_op; | |
1381 | int size; | |
1382 | int offset; | |
1383 | ||
1384 | if (exp == NULL && target == IGNORE_TARGET) | |
1385 | return; | |
1386 | ||
1387 | type = TREE_TYPE (exp); | |
1388 | ||
e04a16fb AG |
1389 | switch (TREE_CODE (exp)) |
1390 | { | |
1391 | case BLOCK: | |
1392 | if (BLOCK_EXPR_BODY (exp)) | |
1393 | { | |
1394 | tree local; | |
3885dfa7 | 1395 | tree body = BLOCK_EXPR_BODY (exp); |
72f339d2 | 1396 | long jsrs = state->num_jsrs; |
e04a16fb AG |
1397 | for (local = BLOCK_EXPR_DECLS (exp); local; ) |
1398 | { | |
1399 | tree next = TREE_CHAIN (local); | |
e4de5a10 | 1400 | localvar_alloc (local, state); |
e04a16fb AG |
1401 | local = next; |
1402 | } | |
3885dfa7 PB |
1403 | /* Avoid deep recursion for long blocks. */ |
1404 | while (TREE_CODE (body) == COMPOUND_EXPR) | |
1405 | { | |
1406 | generate_bytecode_insns (TREE_OPERAND (body, 0), target, state); | |
1407 | body = TREE_OPERAND (body, 1); | |
1408 | } | |
1409 | generate_bytecode_insns (body, target, state); | |
72f339d2 | 1410 | |
e04a16fb AG |
1411 | for (local = BLOCK_EXPR_DECLS (exp); local; ) |
1412 | { | |
1413 | tree next = TREE_CHAIN (local); | |
72f339d2 | 1414 | maybe_free_localvar (local, state, state->num_jsrs <= jsrs); |
e04a16fb AG |
1415 | local = next; |
1416 | } | |
1417 | } | |
1418 | break; | |
f3ca28bf | 1419 | case COMPOUND_EXPR: |
afc390b1 | 1420 | generate_bytecode_insns (TREE_OPERAND (exp, 0), IGNORE_TARGET, state); |
84a944b3 TT |
1421 | /* Normally the first operand to a COMPOUND_EXPR must complete |
1422 | normally. However, in the special case of a do-while | |
1423 | statement this is not necessarily the case. */ | |
1424 | if (CAN_COMPLETE_NORMALLY (TREE_OPERAND (exp, 0))) | |
1425 | generate_bytecode_insns (TREE_OPERAND (exp, 1), target, state); | |
e04a16fb AG |
1426 | break; |
1427 | case EXPR_WITH_FILE_LOCATION: | |
1428 | { | |
436fac17 | 1429 | location_t saved_location = input_location; |
63a212ed | 1430 | tree body = EXPR_WFL_NODE (exp); |
6de9cd9a | 1431 | if (IS_EMPTY_STMT (body)) |
63a212ed | 1432 | break; |
e04a16fb | 1433 | input_filename = EXPR_WFL_FILENAME (exp); |
d479d37f NS |
1434 | input_line = EXPR_WFL_LINENO (exp); |
1435 | if (EXPR_WFL_EMIT_LINE_NOTE (exp) && input_line > 0 | |
80d8e475 | 1436 | && debug_info_level > DINFO_LEVEL_NONE) |
d479d37f | 1437 | put_linenumber (input_line, state); |
63a212ed | 1438 | generate_bytecode_insns (body, target, state); |
436fac17 | 1439 | input_location = saved_location; |
e04a16fb AG |
1440 | } |
1441 | break; | |
1442 | case INTEGER_CST: | |
1443 | if (target == IGNORE_TARGET) ; /* do nothing */ | |
1444 | else if (TREE_CODE (type) == POINTER_TYPE) | |
1445 | { | |
1446 | if (! integer_zerop (exp)) | |
1447 | abort(); | |
1448 | RESERVE(1); | |
1449 | OP1 (OPCODE_aconst_null); | |
1450 | NOTE_PUSH (1); | |
1451 | } | |
1452 | else if (TYPE_PRECISION (type) <= 32) | |
1453 | { | |
e4de5a10 | 1454 | push_int_const (TREE_INT_CST_LOW (exp), state); |
e04a16fb AG |
1455 | NOTE_PUSH (1); |
1456 | } | |
1457 | else | |
1458 | { | |
e4de5a10 PB |
1459 | push_long_const (TREE_INT_CST_LOW (exp), TREE_INT_CST_HIGH (exp), |
1460 | state); | |
e04a16fb AG |
1461 | NOTE_PUSH (2); |
1462 | } | |
1463 | break; | |
3885dfa7 | 1464 | case REAL_CST: |
bb6e881c PB |
1465 | { |
1466 | int prec = TYPE_PRECISION (type) >> 5; | |
1467 | RESERVE(1); | |
1cde1d05 | 1468 | if (real_zerop (exp) && ! REAL_VALUE_MINUS_ZERO (TREE_REAL_CST (exp))) |
bb6e881c PB |
1469 | OP1 (prec == 1 ? OPCODE_fconst_0 : OPCODE_dconst_0); |
1470 | else if (real_onep (exp)) | |
1471 | OP1 (prec == 1 ? OPCODE_fconst_1 : OPCODE_dconst_1); | |
a490d1be RS |
1472 | else if (prec == 1 && real_twop (exp)) |
1473 | OP1 (OPCODE_fconst_2); | |
1474 | /* ??? We could also use iconst_3/ldc followed by i2f/i2d | |
bb6e881c PB |
1475 | for other float/double when the value is a small integer. */ |
1476 | else | |
1477 | { | |
1478 | offset = find_constant_index (exp, state); | |
1479 | if (prec == 1) | |
1480 | push_constant1 (offset, state); | |
1481 | else | |
1482 | push_constant2 (offset, state); | |
1483 | } | |
1484 | NOTE_PUSH (prec); | |
1485 | } | |
3885dfa7 PB |
1486 | break; |
1487 | case STRING_CST: | |
1488 | push_constant1 (find_string_constant (&state->cpool, exp), state); | |
9bbc7d9f | 1489 | NOTE_PUSH (1); |
3885dfa7 | 1490 | break; |
e04a16fb AG |
1491 | case VAR_DECL: |
1492 | if (TREE_STATIC (exp)) | |
1493 | { | |
e4de5a10 PB |
1494 | field_op (exp, OPCODE_getstatic, state); |
1495 | NOTE_PUSH (TYPE_IS_WIDE (TREE_TYPE (exp)) ? 2 : 1); | |
e04a16fb AG |
1496 | break; |
1497 | } | |
1498 | /* ... fall through ... */ | |
1499 | case PARM_DECL: | |
e4de5a10 | 1500 | emit_load (exp, state); |
e04a16fb | 1501 | break; |
3885dfa7 | 1502 | case NON_LVALUE_EXPR: |
e04a16fb | 1503 | case INDIRECT_REF: |
e4de5a10 | 1504 | generate_bytecode_insns (TREE_OPERAND (exp, 0), target, state); |
e04a16fb AG |
1505 | break; |
1506 | case ARRAY_REF: | |
e4de5a10 PB |
1507 | generate_bytecode_insns (TREE_OPERAND (exp, 0), target, state); |
1508 | generate_bytecode_insns (TREE_OPERAND (exp, 1), target, state); | |
e04a16fb AG |
1509 | if (target != IGNORE_TARGET) |
1510 | { | |
3885dfa7 | 1511 | jopcode = OPCODE_iaload + adjust_typed_op (type, 7); |
e04a16fb AG |
1512 | RESERVE(1); |
1513 | OP1 (jopcode); | |
3885dfa7 PB |
1514 | if (! TYPE_IS_WIDE (type)) |
1515 | NOTE_POP (1); | |
e04a16fb AG |
1516 | } |
1517 | break; | |
1518 | case COMPONENT_REF: | |
1519 | { | |
1520 | tree obj = TREE_OPERAND (exp, 0); | |
1521 | tree field = TREE_OPERAND (exp, 1); | |
1522 | int is_static = FIELD_STATIC (field); | |
e4de5a10 PB |
1523 | generate_bytecode_insns (obj, |
1524 | is_static ? IGNORE_TARGET : target, state); | |
e04a16fb AG |
1525 | if (target != IGNORE_TARGET) |
1526 | { | |
1527 | if (DECL_NAME (field) == length_identifier_node && !is_static | |
1528 | && TYPE_ARRAY_P (TREE_TYPE (obj))) | |
1529 | { | |
1530 | RESERVE (1); | |
1531 | OP1 (OPCODE_arraylength); | |
1532 | } | |
1533 | else | |
e4de5a10 PB |
1534 | { |
1535 | field_op (field, is_static ? OPCODE_getstatic : OPCODE_getfield, | |
1536 | state); | |
1537 | if (! is_static) | |
1538 | NOTE_POP (1); | |
1539 | NOTE_PUSH (TYPE_IS_WIDE (TREE_TYPE (field)) ? 2 : 1); | |
1540 | } | |
e04a16fb AG |
1541 | } |
1542 | } | |
1543 | break; | |
e4de5a10 PB |
1544 | case TRUTH_ANDIF_EXPR: |
1545 | case TRUTH_ORIF_EXPR: | |
1546 | case EQ_EXPR: | |
1547 | case NE_EXPR: | |
1548 | case GT_EXPR: | |
1549 | case LT_EXPR: | |
1550 | case GE_EXPR: | |
1551 | case LE_EXPR: | |
1552 | { | |
1553 | struct jcf_block *then_label = gen_jcf_label (state); | |
1554 | struct jcf_block *else_label = gen_jcf_label (state); | |
1555 | struct jcf_block *end_label = gen_jcf_label (state); | |
1556 | generate_bytecode_conditional (exp, | |
1557 | then_label, else_label, 1, state); | |
1558 | define_jcf_label (then_label, state); | |
1559 | push_int_const (1, state); | |
1560 | emit_goto (end_label, state); | |
1561 | define_jcf_label (else_label, state); | |
1562 | push_int_const (0, state); | |
1563 | define_jcf_label (end_label, state); | |
1564 | NOTE_PUSH (1); | |
1565 | } | |
1566 | break; | |
1567 | case COND_EXPR: | |
1568 | { | |
1569 | struct jcf_block *then_label = gen_jcf_label (state); | |
1570 | struct jcf_block *else_label = gen_jcf_label (state); | |
1571 | struct jcf_block *end_label = gen_jcf_label (state); | |
1572 | generate_bytecode_conditional (TREE_OPERAND (exp, 0), | |
1573 | then_label, else_label, 1, state); | |
1574 | define_jcf_label (then_label, state); | |
1575 | generate_bytecode_insns (TREE_OPERAND (exp, 1), target, state); | |
3885dfa7 PB |
1576 | if (CAN_COMPLETE_NORMALLY (TREE_OPERAND (exp, 1)) |
1577 | /* Not all expressions have CAN_COMPLETE_NORMALLY set properly. */ | |
1578 | || TREE_CODE (TREE_TYPE (exp)) != VOID_TYPE) | |
1579 | emit_goto (end_label, state); | |
e4de5a10 PB |
1580 | define_jcf_label (else_label, state); |
1581 | generate_bytecode_insns (TREE_OPERAND (exp, 2), target, state); | |
1582 | define_jcf_label (end_label, state); | |
6b924cc5 APB |
1583 | /* COND_EXPR can be used in a binop. The stack must be adjusted. */ |
1584 | if (TREE_TYPE (exp) != void_type_node) | |
105a8d1c | 1585 | NOTE_POP (TYPE_IS_WIDE (TREE_TYPE (exp)) ? 2 : 1); |
e4de5a10 PB |
1586 | } |
1587 | break; | |
3885dfa7 PB |
1588 | case CASE_EXPR: |
1589 | { | |
1590 | struct jcf_switch_state *sw_state = state->sw_state; | |
c68b0a84 KG |
1591 | struct jcf_relocation *reloc |
1592 | = obstack_alloc (state->chunk_obstack, sizeof (struct jcf_relocation)); | |
3885dfa7 PB |
1593 | HOST_WIDE_INT case_value = TREE_INT_CST_LOW (TREE_OPERAND (exp, 0)); |
1594 | reloc->kind = 0; | |
1595 | reloc->label = get_jcf_label_here (state); | |
1596 | reloc->offset = case_value; | |
1597 | reloc->next = sw_state->cases; | |
1598 | sw_state->cases = reloc; | |
1599 | if (sw_state->num_cases == 0) | |
1600 | { | |
1601 | sw_state->min_case = case_value; | |
1602 | sw_state->max_case = case_value; | |
1603 | } | |
1604 | else | |
1605 | { | |
1606 | if (case_value < sw_state->min_case) | |
1607 | sw_state->min_case = case_value; | |
1608 | if (case_value > sw_state->max_case) | |
1609 | sw_state->max_case = case_value; | |
1610 | } | |
1611 | sw_state->num_cases++; | |
1612 | } | |
1613 | break; | |
1614 | case DEFAULT_EXPR: | |
1615 | state->sw_state->default_label = get_jcf_label_here (state); | |
1616 | break; | |
1617 | ||
1618 | case SWITCH_EXPR: | |
1619 | { | |
1620 | /* The SWITCH_EXPR has three parts, generated in the following order: | |
1621 | 1. the switch_expression (the value used to select the correct case); | |
1622 | 2. the switch_body; | |
1623 | 3. the switch_instruction (the tableswitch/loopupswitch instruction.). | |
2d93b924 TT |
1624 | After code generation, we will re-order them in the order 1, 3, 2. |
1625 | This is to avoid any extra GOTOs. */ | |
3885dfa7 PB |
1626 | struct jcf_switch_state sw_state; |
1627 | struct jcf_block *expression_last; /* Last block of the switch_expression. */ | |
1628 | struct jcf_block *body_last; /* Last block of the switch_body. */ | |
1629 | struct jcf_block *switch_instruction; /* First block of switch_instruction. */ | |
1630 | struct jcf_block *instruction_last; /* Last block of the switch_instruction. */ | |
1631 | struct jcf_block *body_block; | |
1632 | int switch_length; | |
1633 | sw_state.prev = state->sw_state; | |
1634 | state->sw_state = &sw_state; | |
1635 | sw_state.cases = NULL; | |
1636 | sw_state.num_cases = 0; | |
1637 | sw_state.default_label = NULL; | |
1638 | generate_bytecode_insns (TREE_OPERAND (exp, 0), STACK_TARGET, state); | |
1639 | expression_last = state->last_block; | |
f3ca28bf TT |
1640 | /* Force a new block here. */ |
1641 | body_block = gen_jcf_label (state); | |
1642 | define_jcf_label (body_block, state); | |
3885dfa7 PB |
1643 | generate_bytecode_insns (TREE_OPERAND (exp, 1), IGNORE_TARGET, state); |
1644 | body_last = state->last_block; | |
1645 | ||
23a7b8f5 PB |
1646 | switch_instruction = gen_jcf_label (state); |
1647 | define_jcf_label (switch_instruction, state); | |
3885dfa7 PB |
1648 | if (sw_state.default_label == NULL) |
1649 | sw_state.default_label = gen_jcf_label (state); | |
3885dfa7 PB |
1650 | |
1651 | if (sw_state.num_cases <= 1) | |
1652 | { | |
1653 | if (sw_state.num_cases == 0) | |
1654 | { | |
1655 | emit_pop (1, state); | |
1656 | NOTE_POP (1); | |
1657 | } | |
1658 | else | |
1659 | { | |
1660 | push_int_const (sw_state.cases->offset, state); | |
7a91449c | 1661 | NOTE_PUSH (1); |
3885dfa7 | 1662 | emit_if (sw_state.cases->label, |
8789b9fa | 1663 | OPCODE_if_icmpeq, OPCODE_if_icmpne, state); |
3885dfa7 PB |
1664 | } |
1665 | emit_goto (sw_state.default_label, state); | |
1666 | } | |
1667 | else | |
1668 | { | |
1669 | HOST_WIDE_INT i; | |
913746e3 | 1670 | unsigned HOST_WIDE_INT delta; |
3885dfa7 | 1671 | /* Copy the chain of relocs into a sorted array. */ |
c68b0a84 KG |
1672 | struct jcf_relocation **relocs |
1673 | = xmalloc (sw_state.num_cases * sizeof (struct jcf_relocation *)); | |
3885dfa7 PB |
1674 | /* The relocs arrays is a buffer with a gap. |
1675 | The assumption is that cases will normally come in "runs". */ | |
1676 | int gap_start = 0; | |
1677 | int gap_end = sw_state.num_cases; | |
1678 | struct jcf_relocation *reloc; | |
1679 | for (reloc = sw_state.cases; reloc != NULL; reloc = reloc->next) | |
1680 | { | |
1681 | HOST_WIDE_INT case_value = reloc->offset; | |
1682 | while (gap_end < sw_state.num_cases) | |
1683 | { | |
1684 | struct jcf_relocation *end = relocs[gap_end]; | |
1685 | if (case_value <= end->offset) | |
1686 | break; | |
1687 | relocs[gap_start++] = end; | |
1688 | gap_end++; | |
1689 | } | |
1690 | while (gap_start > 0) | |
1691 | { | |
1692 | struct jcf_relocation *before = relocs[gap_start-1]; | |
1693 | if (case_value >= before->offset) | |
1694 | break; | |
1695 | relocs[--gap_end] = before; | |
1696 | gap_start--; | |
1697 | } | |
1698 | relocs[gap_start++] = reloc; | |
5a21a051 TT |
1699 | /* Note we don't check for duplicates. This is |
1700 | handled by the parser. */ | |
3885dfa7 PB |
1701 | } |
1702 | ||
913746e3 TT |
1703 | /* We could have DELTA < 0 if sw_state.min_case is |
1704 | something like Integer.MIN_VALUE. That is why delta is | |
1705 | unsigned. */ | |
1706 | delta = sw_state.max_case - sw_state.min_case; | |
fc555370 | 1707 | if (2 * (unsigned) sw_state.num_cases >= delta) |
3885dfa7 PB |
1708 | { /* Use tableswitch. */ |
1709 | int index = 0; | |
1710 | RESERVE (13 + 4 * (sw_state.max_case - sw_state.min_case + 1)); | |
1711 | OP1 (OPCODE_tableswitch); | |
cacc154e APB |
1712 | emit_reloc (RELOCATION_VALUE_0, |
1713 | SWITCH_ALIGN_RELOC, NULL, state); | |
3885dfa7 PB |
1714 | emit_switch_reloc (sw_state.default_label, state); |
1715 | OP4 (sw_state.min_case); | |
1716 | OP4 (sw_state.max_case); | |
1717 | for (i = sw_state.min_case; ; ) | |
1718 | { | |
9bbc7d9f PB |
1719 | reloc = relocs[index]; |
1720 | if (i == reloc->offset) | |
1721 | { | |
1722 | emit_case_reloc (reloc, state); | |
1723 | if (i == sw_state.max_case) | |
1724 | break; | |
1725 | index++; | |
1726 | } | |
3885dfa7 PB |
1727 | else |
1728 | emit_switch_reloc (sw_state.default_label, state); | |
3885dfa7 PB |
1729 | i++; |
1730 | } | |
1731 | } | |
1732 | else | |
1733 | { /* Use lookupswitch. */ | |
1734 | RESERVE(9 + 8 * sw_state.num_cases); | |
1735 | OP1 (OPCODE_lookupswitch); | |
cacc154e APB |
1736 | emit_reloc (RELOCATION_VALUE_0, |
1737 | SWITCH_ALIGN_RELOC, NULL, state); | |
3885dfa7 PB |
1738 | emit_switch_reloc (sw_state.default_label, state); |
1739 | OP4 (sw_state.num_cases); | |
1740 | for (i = 0; i < sw_state.num_cases; i++) | |
1741 | { | |
1742 | struct jcf_relocation *reloc = relocs[i]; | |
1743 | OP4 (reloc->offset); | |
1744 | emit_case_reloc (reloc, state); | |
1745 | } | |
1746 | } | |
1747 | free (relocs); | |
1748 | } | |
1749 | ||
1750 | instruction_last = state->last_block; | |
1751 | if (sw_state.default_label->pc < 0) | |
1752 | define_jcf_label (sw_state.default_label, state); | |
1753 | else /* Force a new block. */ | |
1754 | sw_state.default_label = get_jcf_label_here (state); | |
1755 | /* Now re-arrange the blocks so the switch_instruction | |
1756 | comes before the switch_body. */ | |
1757 | switch_length = state->code_length - switch_instruction->pc; | |
1758 | switch_instruction->pc = body_block->pc; | |
1759 | instruction_last->next = body_block; | |
45b44fbe | 1760 | instruction_last->v.chunk->next = body_block->v.chunk; |
3885dfa7 | 1761 | expression_last->next = switch_instruction; |
45b44fbe | 1762 | expression_last->v.chunk->next = switch_instruction->v.chunk; |
3885dfa7 | 1763 | body_last->next = sw_state.default_label; |
45b44fbe PB |
1764 | body_last->v.chunk->next = NULL; |
1765 | state->chunk = body_last->v.chunk; | |
3885dfa7 PB |
1766 | for (; body_block != sw_state.default_label; body_block = body_block->next) |
1767 | body_block->pc += switch_length; | |
1768 | ||
3885dfa7 PB |
1769 | state->sw_state = sw_state.prev; |
1770 | break; | |
1771 | } | |
1772 | ||
e04a16fb | 1773 | case RETURN_EXPR: |
bb6e881c PB |
1774 | exp = TREE_OPERAND (exp, 0); |
1775 | if (exp == NULL_TREE) | |
6de9cd9a | 1776 | exp = build_java_empty_stmt (); |
bb6e881c PB |
1777 | else if (TREE_CODE (exp) != MODIFY_EXPR) |
1778 | abort (); | |
e04a16fb | 1779 | else |
bb6e881c PB |
1780 | exp = TREE_OPERAND (exp, 1); |
1781 | generate_bytecode_return (exp, state); | |
e04a16fb | 1782 | break; |
e4de5a10 | 1783 | case LABELED_BLOCK_EXPR: |
e04a16fb | 1784 | { |
e4de5a10 PB |
1785 | struct jcf_block *end_label = gen_jcf_label (state); |
1786 | end_label->next = state->labeled_blocks; | |
1787 | state->labeled_blocks = end_label; | |
45b44fbe | 1788 | end_label->pc = PENDING_EXIT_PC; |
e4de5a10 PB |
1789 | end_label->u.labeled_block = exp; |
1790 | if (LABELED_BLOCK_BODY (exp)) | |
1791 | generate_bytecode_insns (LABELED_BLOCK_BODY (exp), target, state); | |
1792 | if (state->labeled_blocks != end_label) | |
1793 | abort(); | |
1794 | state->labeled_blocks = end_label->next; | |
1795 | define_jcf_label (end_label, state); | |
1796 | } | |
1797 | break; | |
1798 | case LOOP_EXPR: | |
1799 | { | |
1800 | tree body = TREE_OPERAND (exp, 0); | |
e04a16fb | 1801 | #if 0 |
e4de5a10 PB |
1802 | if (TREE_CODE (body) == COMPOUND_EXPR |
1803 | && TREE_CODE (TREE_OPERAND (body, 0)) == EXIT_EXPR) | |
e04a16fb | 1804 | { |
e4de5a10 PB |
1805 | /* Optimize: H: if (TEST) GOTO L; BODY; GOTO H; L: |
1806 | to: GOTO L; BODY; L: if (!TEST) GOTO L; */ | |
1807 | struct jcf_block *head_label; | |
1808 | struct jcf_block *body_label; | |
1809 | struct jcf_block *end_label = gen_jcf_label (state); | |
1810 | struct jcf_block *exit_label = state->labeled_blocks; | |
1811 | head_label = gen_jcf_label (state); | |
1812 | emit_goto (head_label, state); | |
1813 | body_label = get_jcf_label_here (state); | |
1814 | generate_bytecode_insns (TREE_OPERAND (body, 1), target, state); | |
1815 | define_jcf_label (head_label, state); | |
1816 | generate_bytecode_conditional (TREE_OPERAND (body, 0), | |
1817 | end_label, body_label, 1, state); | |
1818 | define_jcf_label (end_label, state); | |
e04a16fb | 1819 | } |
e4de5a10 | 1820 | else |
e04a16fb | 1821 | #endif |
e04a16fb | 1822 | { |
e4de5a10 PB |
1823 | struct jcf_block *head_label = get_jcf_label_here (state); |
1824 | generate_bytecode_insns (body, IGNORE_TARGET, state); | |
84a944b3 TT |
1825 | if (CAN_COMPLETE_NORMALLY (body)) |
1826 | emit_goto (head_label, state); | |
e04a16fb | 1827 | } |
e4de5a10 PB |
1828 | } |
1829 | break; | |
1830 | case EXIT_EXPR: | |
1831 | { | |
1832 | struct jcf_block *label = state->labeled_blocks; | |
1833 | struct jcf_block *end_label = gen_jcf_label (state); | |
1834 | generate_bytecode_conditional (TREE_OPERAND (exp, 0), | |
1835 | label, end_label, 0, state); | |
1836 | define_jcf_label (end_label, state); | |
1837 | } | |
1838 | break; | |
1839 | case EXIT_BLOCK_EXPR: | |
1840 | { | |
1841 | struct jcf_block *label = state->labeled_blocks; | |
1842 | if (TREE_OPERAND (exp, 1) != NULL) goto notimpl; | |
1843 | while (label->u.labeled_block != TREE_OPERAND (exp, 0)) | |
1844 | label = label->next; | |
45b44fbe | 1845 | call_cleanups (label, state); |
e4de5a10 PB |
1846 | emit_goto (label, state); |
1847 | } | |
1848 | break; | |
1849 | ||
1850 | case PREDECREMENT_EXPR: value = -1; post_op = 0; goto increment; | |
1851 | case PREINCREMENT_EXPR: value = 1; post_op = 0; goto increment; | |
1852 | case POSTDECREMENT_EXPR: value = -1; post_op = 1; goto increment; | |
1853 | case POSTINCREMENT_EXPR: value = 1; post_op = 1; goto increment; | |
1854 | increment: | |
1855 | ||
1a27eec1 | 1856 | arg = TREE_OPERAND (exp, 1); |
e4de5a10 PB |
1857 | exp = TREE_OPERAND (exp, 0); |
1858 | type = TREE_TYPE (exp); | |
1859 | size = TYPE_IS_WIDE (type) ? 2 : 1; | |
1860 | if ((TREE_CODE (exp) == VAR_DECL || TREE_CODE (exp) == PARM_DECL) | |
1861 | && ! TREE_STATIC (exp) | |
1862 | && TREE_CODE (type) == INTEGER_TYPE | |
1863 | && TYPE_PRECISION (type) == 32) | |
1864 | { | |
1865 | if (target != IGNORE_TARGET && post_op) | |
1866 | emit_load (exp, state); | |
1867 | emit_iinc (exp, value, state); | |
9bbc7d9f PB |
1868 | if (target != IGNORE_TARGET && ! post_op) |
1869 | emit_load (exp, state); | |
e4de5a10 PB |
1870 | break; |
1871 | } | |
1872 | if (TREE_CODE (exp) == COMPONENT_REF) | |
1873 | { | |
1874 | generate_bytecode_insns (TREE_OPERAND (exp, 0), STACK_TARGET, state); | |
1875 | emit_dup (1, 0, state); | |
1876 | /* Stack: ..., objectref, objectref. */ | |
6466fce8 | 1877 | field_op (TREE_OPERAND (exp, 1), OPCODE_getfield, state); |
63a212ed | 1878 | NOTE_PUSH (size-1); |
e4de5a10 PB |
1879 | /* Stack: ..., objectref, oldvalue. */ |
1880 | offset = 1; | |
1881 | } | |
1882 | else if (TREE_CODE (exp) == ARRAY_REF) | |
1883 | { | |
1884 | generate_bytecode_insns (TREE_OPERAND (exp, 0), STACK_TARGET, state); | |
1885 | generate_bytecode_insns (TREE_OPERAND (exp, 1), STACK_TARGET, state); | |
1886 | emit_dup (2, 0, state); | |
1887 | /* Stack: ..., array, index, array, index. */ | |
3885dfa7 | 1888 | jopcode = OPCODE_iaload + adjust_typed_op (TREE_TYPE (exp), 7); |
e4de5a10 PB |
1889 | RESERVE(1); |
1890 | OP1 (jopcode); | |
1891 | NOTE_POP (2-size); | |
1892 | /* Stack: ..., array, index, oldvalue. */ | |
1893 | offset = 2; | |
1894 | } | |
1895 | else if (TREE_CODE (exp) == VAR_DECL || TREE_CODE (exp) == PARM_DECL) | |
1896 | { | |
1897 | generate_bytecode_insns (exp, STACK_TARGET, state); | |
1898 | /* Stack: ..., oldvalue. */ | |
1899 | offset = 0; | |
1900 | } | |
1901 | else | |
1902 | abort (); | |
1903 | ||
1904 | if (target != IGNORE_TARGET && post_op) | |
1905 | emit_dup (size, offset, state); | |
1906 | /* Stack, if ARRAY_REF: ..., [result, ] array, index, oldvalue. */ | |
1907 | /* Stack, if COMPONENT_REF: ..., [result, ] objectref, oldvalue. */ | |
1908 | /* Stack, otherwise: ..., [result, ] oldvalue. */ | |
1a27eec1 PB |
1909 | generate_bytecode_insns (arg, STACK_TARGET, state); |
1910 | emit_binop ((value >= 0 ? OPCODE_iadd : OPCODE_isub) | |
1911 | + adjust_typed_op (type, 3), | |
1912 | type, state); | |
e4de5a10 PB |
1913 | if (target != IGNORE_TARGET && ! post_op) |
1914 | emit_dup (size, offset, state); | |
63a212ed PB |
1915 | /* Stack, if ARRAY_REF: ..., [result, ] array, index, newvalue. */ |
1916 | /* Stack, if COMPONENT_REF: ..., [result, ] objectref, newvalue. */ | |
1917 | /* Stack, otherwise: ..., [result, ] newvalue. */ | |
e4de5a10 PB |
1918 | goto finish_assignment; |
1919 | ||
1920 | case MODIFY_EXPR: | |
1921 | { | |
1922 | tree lhs = TREE_OPERAND (exp, 0); | |
1923 | tree rhs = TREE_OPERAND (exp, 1); | |
23a7b8f5 | 1924 | int offset = 0; |
e4de5a10 PB |
1925 | |
1926 | /* See if we can use the iinc instruction. */ | |
1927 | if ((TREE_CODE (lhs) == VAR_DECL || TREE_CODE (lhs) == PARM_DECL) | |
1928 | && ! TREE_STATIC (lhs) | |
1929 | && TREE_CODE (TREE_TYPE (lhs)) == INTEGER_TYPE | |
1930 | && TYPE_PRECISION (TREE_TYPE (lhs)) == 32 | |
1931 | && (TREE_CODE (rhs) == PLUS_EXPR || TREE_CODE (rhs) == MINUS_EXPR)) | |
e04a16fb | 1932 | { |
e4de5a10 PB |
1933 | tree arg0 = TREE_OPERAND (rhs, 0); |
1934 | tree arg1 = TREE_OPERAND (rhs, 1); | |
1935 | HOST_WIDE_INT min_value = -32768; | |
1936 | HOST_WIDE_INT max_value = 32767; | |
1937 | if (TREE_CODE (rhs) == MINUS_EXPR) | |
e04a16fb | 1938 | { |
e4de5a10 PB |
1939 | min_value++; |
1940 | max_value++; | |
e04a16fb | 1941 | } |
e4de5a10 | 1942 | else if (arg1 == lhs) |
e04a16fb | 1943 | { |
e4de5a10 PB |
1944 | arg0 = arg1; |
1945 | arg1 = TREE_OPERAND (rhs, 0); | |
1946 | } | |
1947 | if (lhs == arg0 && TREE_CODE (arg1) == INTEGER_CST) | |
1948 | { | |
1949 | HOST_WIDE_INT hi_value = TREE_INT_CST_HIGH (arg1); | |
1950 | value = TREE_INT_CST_LOW (arg1); | |
1951 | if ((hi_value == 0 && value <= max_value) | |
1952 | || (hi_value == -1 && value >= min_value)) | |
e04a16fb | 1953 | { |
e4de5a10 PB |
1954 | if (TREE_CODE (rhs) == MINUS_EXPR) |
1955 | value = -value; | |
1956 | emit_iinc (lhs, value, state); | |
478e7ed6 PB |
1957 | if (target != IGNORE_TARGET) |
1958 | emit_load (lhs, state); | |
e4de5a10 | 1959 | break; |
e04a16fb AG |
1960 | } |
1961 | } | |
1962 | } | |
e4de5a10 PB |
1963 | |
1964 | if (TREE_CODE (lhs) == COMPONENT_REF) | |
23a7b8f5 PB |
1965 | { |
1966 | generate_bytecode_insns (TREE_OPERAND (lhs, 0), | |
1967 | STACK_TARGET, state); | |
1968 | offset = 1; | |
1969 | } | |
e04a16fb AG |
1970 | else if (TREE_CODE (lhs) == ARRAY_REF) |
1971 | { | |
23a7b8f5 PB |
1972 | generate_bytecode_insns (TREE_OPERAND(lhs, 0), |
1973 | STACK_TARGET, state); | |
1974 | generate_bytecode_insns (TREE_OPERAND(lhs, 1), | |
1975 | STACK_TARGET, state); | |
1976 | offset = 2; | |
e04a16fb | 1977 | } |
23a7b8f5 PB |
1978 | else |
1979 | offset = 0; | |
8aeb42d0 TT |
1980 | |
1981 | /* If the rhs is a binary expression and the left operand is | |
1982 | `==' to the lhs then we have an OP= expression. In this | |
1983 | case we must do some special processing. */ | |
1984 | if (TREE_CODE_CLASS (TREE_CODE (rhs)) == '2' | |
1985 | && lhs == TREE_OPERAND (rhs, 0)) | |
1986 | { | |
1987 | if (TREE_CODE (lhs) == COMPONENT_REF) | |
1988 | { | |
1989 | tree field = TREE_OPERAND (lhs, 1); | |
1990 | if (! FIELD_STATIC (field)) | |
1991 | { | |
1992 | /* Duplicate the object reference so we can get | |
1993 | the field. */ | |
1994 | emit_dup (TYPE_IS_WIDE (field) ? 2 : 1, 0, state); | |
1995 | NOTE_POP (1); | |
1996 | } | |
1997 | field_op (field, (FIELD_STATIC (field) | |
1998 | ? OPCODE_getstatic | |
1999 | : OPCODE_getfield), | |
2000 | state); | |
2001 | ||
2002 | NOTE_PUSH (TYPE_IS_WIDE (TREE_TYPE (field)) ? 2 : 1); | |
2003 | } | |
2004 | else if (TREE_CODE (lhs) == VAR_DECL | |
2005 | || TREE_CODE (lhs) == PARM_DECL) | |
2006 | { | |
2007 | if (FIELD_STATIC (lhs)) | |
2008 | { | |
2009 | field_op (lhs, OPCODE_getstatic, state); | |
2010 | NOTE_PUSH (TYPE_IS_WIDE (TREE_TYPE (lhs)) ? 2 : 1); | |
2011 | } | |
2012 | else | |
2013 | emit_load (lhs, state); | |
2014 | } | |
2015 | else if (TREE_CODE (lhs) == ARRAY_REF) | |
2016 | { | |
2017 | /* Duplicate the array and index, which are on the | |
2018 | stack, so that we can load the old value. */ | |
2019 | emit_dup (2, 0, state); | |
2020 | NOTE_POP (2); | |
2021 | jopcode = OPCODE_iaload + adjust_typed_op (TREE_TYPE (lhs), 7); | |
2022 | RESERVE (1); | |
2023 | OP1 (jopcode); | |
2024 | NOTE_PUSH (TYPE_IS_WIDE (TREE_TYPE (lhs)) ? 2 : 1); | |
2025 | } | |
2026 | else | |
2027 | abort (); | |
2028 | ||
2029 | /* This function correctly handles the case where the LHS | |
2030 | of a binary expression is NULL_TREE. */ | |
2031 | rhs = build (TREE_CODE (rhs), TREE_TYPE (rhs), | |
2032 | NULL_TREE, TREE_OPERAND (rhs, 1)); | |
2033 | } | |
2034 | ||
e4de5a10 PB |
2035 | generate_bytecode_insns (rhs, STACK_TARGET, state); |
2036 | if (target != IGNORE_TARGET) | |
23a7b8f5 | 2037 | emit_dup (TYPE_IS_WIDE (type) ? 2 : 1 , offset, state); |
e4de5a10 | 2038 | exp = lhs; |
e04a16fb | 2039 | } |
0d42c3c2 | 2040 | /* FALLTHROUGH */ |
e4de5a10 PB |
2041 | |
2042 | finish_assignment: | |
2043 | if (TREE_CODE (exp) == COMPONENT_REF) | |
2044 | { | |
2045 | tree field = TREE_OPERAND (exp, 1); | |
2046 | if (! FIELD_STATIC (field)) | |
2047 | NOTE_POP (1); | |
2048 | field_op (field, | |
63a212ed | 2049 | FIELD_STATIC (field) ? OPCODE_putstatic : OPCODE_putfield, |
e4de5a10 PB |
2050 | state); |
2051 | ||
63a212ed | 2052 | NOTE_POP (TYPE_IS_WIDE (TREE_TYPE (field)) ? 2 : 1); |
e4de5a10 PB |
2053 | } |
2054 | else if (TREE_CODE (exp) == VAR_DECL | |
2055 | || TREE_CODE (exp) == PARM_DECL) | |
2056 | { | |
2057 | if (FIELD_STATIC (exp)) | |
2058 | { | |
2059 | field_op (exp, OPCODE_putstatic, state); | |
63a212ed | 2060 | NOTE_POP (TYPE_IS_WIDE (TREE_TYPE (exp)) ? 2 : 1); |
e4de5a10 PB |
2061 | } |
2062 | else | |
2063 | emit_store (exp, state); | |
2064 | } | |
2065 | else if (TREE_CODE (exp) == ARRAY_REF) | |
2066 | { | |
3885dfa7 | 2067 | jopcode = OPCODE_iastore + adjust_typed_op (TREE_TYPE (exp), 7); |
400500c4 | 2068 | RESERVE (1); |
e4de5a10 | 2069 | OP1 (jopcode); |
63a212ed | 2070 | NOTE_POP (TYPE_IS_WIDE (TREE_TYPE (exp)) ? 4 : 3); |
e4de5a10 PB |
2071 | } |
2072 | else | |
400500c4 | 2073 | abort (); |
e04a16fb AG |
2074 | break; |
2075 | case PLUS_EXPR: | |
3885dfa7 | 2076 | jopcode = OPCODE_iadd; |
e04a16fb AG |
2077 | goto binop; |
2078 | case MINUS_EXPR: | |
3885dfa7 | 2079 | jopcode = OPCODE_isub; |
e04a16fb AG |
2080 | goto binop; |
2081 | case MULT_EXPR: | |
3885dfa7 | 2082 | jopcode = OPCODE_imul; |
e04a16fb AG |
2083 | goto binop; |
2084 | case TRUNC_DIV_EXPR: | |
2085 | case RDIV_EXPR: | |
3885dfa7 PB |
2086 | jopcode = OPCODE_idiv; |
2087 | goto binop; | |
2088 | case TRUNC_MOD_EXPR: | |
2089 | jopcode = OPCODE_irem; | |
e04a16fb | 2090 | goto binop; |
3885dfa7 PB |
2091 | case LSHIFT_EXPR: jopcode = OPCODE_ishl; goto binop; |
2092 | case RSHIFT_EXPR: jopcode = OPCODE_ishr; goto binop; | |
2093 | case URSHIFT_EXPR: jopcode = OPCODE_iushr; goto binop; | |
81f4eddd | 2094 | case TRUTH_AND_EXPR: |
3885dfa7 | 2095 | case BIT_AND_EXPR: jopcode = OPCODE_iand; goto binop; |
81f4eddd | 2096 | case TRUTH_OR_EXPR: |
3885dfa7 | 2097 | case BIT_IOR_EXPR: jopcode = OPCODE_ior; goto binop; |
81f4eddd | 2098 | case TRUTH_XOR_EXPR: |
3885dfa7 | 2099 | case BIT_XOR_EXPR: jopcode = OPCODE_ixor; goto binop; |
e04a16fb | 2100 | binop: |
3885dfa7 PB |
2101 | { |
2102 | tree arg0 = TREE_OPERAND (exp, 0); | |
2103 | tree arg1 = TREE_OPERAND (exp, 1); | |
2104 | jopcode += adjust_typed_op (type, 3); | |
87750fef | 2105 | if (arg0 != NULL_TREE && operand_equal_p (arg0, arg1, 0)) |
3885dfa7 PB |
2106 | { |
2107 | /* fold may (e.g) convert 2*x to x+x. */ | |
87750fef | 2108 | generate_bytecode_insns (arg0, target, state); |
3885dfa7 PB |
2109 | emit_dup (TYPE_PRECISION (TREE_TYPE (arg0)) > 32 ? 2 : 1, 0, state); |
2110 | } | |
2111 | else | |
2112 | { | |
8aeb42d0 TT |
2113 | /* ARG0 will be NULL_TREE if we're handling an `OP=' |
2114 | expression. In this case the stack already holds the | |
2115 | LHS. See the MODIFY_EXPR case. */ | |
2116 | if (arg0 != NULL_TREE) | |
2117 | generate_bytecode_insns (arg0, target, state); | |
f8989a66 APB |
2118 | if (jopcode >= OPCODE_lshl && jopcode <= OPCODE_lushr) |
2119 | arg1 = convert (int_type_node, arg1); | |
3885dfa7 PB |
2120 | generate_bytecode_insns (arg1, target, state); |
2121 | } | |
63a212ed PB |
2122 | /* For most binary operations, both operands and the result have the |
2123 | same type. Shift operations are different. Using arg1's type | |
f8989a66 | 2124 | gets us the correct SP adjustment in all cases. */ |
e04a16fb | 2125 | if (target == STACK_TARGET) |
63a212ed | 2126 | emit_binop (jopcode, TREE_TYPE (arg1), state); |
e04a16fb | 2127 | break; |
3885dfa7 PB |
2128 | } |
2129 | case TRUTH_NOT_EXPR: | |
2130 | case BIT_NOT_EXPR: | |
2131 | generate_bytecode_insns (TREE_OPERAND (exp, 0), target, state); | |
2132 | if (target == STACK_TARGET) | |
2133 | { | |
2134 | int is_long = TYPE_PRECISION (TREE_TYPE (exp)) > 32; | |
2135 | push_int_const (TREE_CODE (exp) == BIT_NOT_EXPR ? -1 : 1, state); | |
2136 | RESERVE (2); | |
2137 | if (is_long) | |
2138 | OP1 (OPCODE_i2l); | |
23a7b8f5 | 2139 | NOTE_PUSH (1 + is_long); |
3885dfa7 | 2140 | OP1 (OPCODE_ixor + is_long); |
23a7b8f5 | 2141 | NOTE_POP (1 + is_long); |
3885dfa7 PB |
2142 | } |
2143 | break; | |
2144 | case NEGATE_EXPR: | |
2145 | jopcode = OPCODE_ineg; | |
2146 | jopcode += adjust_typed_op (type, 3); | |
2147 | generate_bytecode_insns (TREE_OPERAND (exp, 0), target, state); | |
2148 | if (target == STACK_TARGET) | |
2149 | emit_unop (jopcode, type, state); | |
2150 | break; | |
2151 | case INSTANCEOF_EXPR: | |
2152 | { | |
2153 | int index = find_class_constant (&state->cpool, TREE_OPERAND (exp, 1)); | |
2154 | generate_bytecode_insns (TREE_OPERAND (exp, 0), target, state); | |
2155 | RESERVE (3); | |
2156 | OP1 (OPCODE_instanceof); | |
2157 | OP2 (index); | |
2158 | } | |
2159 | break; | |
c2952b01 | 2160 | case SAVE_EXPR: |
d186e676 RS |
2161 | /* Because the state associated with a SAVE_EXPR tree node must |
2162 | be a RTL expression, we use it to store the DECL_LOCAL_INDEX | |
2163 | of a temporary variable in a CONST_INT. */ | |
2164 | if (! SAVE_EXPR_RTL (exp)) | |
2165 | { | |
2166 | tree type = TREE_TYPE (exp); | |
2167 | tree decl = build_decl (VAR_DECL, NULL_TREE, type); | |
2168 | generate_bytecode_insns (TREE_OPERAND (exp, 0), | |
2169 | STACK_TARGET, state); | |
2170 | localvar_alloc (decl, state); | |
2171 | SAVE_EXPR_RTL (exp) = GEN_INT (DECL_LOCAL_INDEX (decl)); | |
2172 | emit_dup (TYPE_IS_WIDE (type) ? 2 : 1, 0, state); | |
2173 | emit_store (decl, state); | |
2174 | } | |
2175 | else | |
2176 | { | |
2177 | /* The following code avoids creating a temporary DECL just | |
2178 | to pass to emit_load. This code could be factored with | |
2179 | the similar implementation in emit_load_or_store. */ | |
2180 | tree type = TREE_TYPE (exp); | |
2181 | int kind = adjust_typed_op (type, 4); | |
2182 | int index = (int) INTVAL (SAVE_EXPR_RTL (exp)); | |
2183 | if (index <= 3) | |
2184 | { | |
2185 | RESERVE (1); /* [ilfda]load_[0123] */ | |
2186 | OP1 (OPCODE_iload + 5 + 4*kind + index); | |
2187 | } | |
2188 | else /* [ilfda]load */ | |
2189 | maybe_wide (OPCODE_iload + kind, index, state); | |
2190 | NOTE_PUSH (TYPE_IS_WIDE (type) ? 2 : 1); | |
2191 | } | |
c2952b01 | 2192 | break; |
3885dfa7 PB |
2193 | case CONVERT_EXPR: |
2194 | case NOP_EXPR: | |
2195 | case FLOAT_EXPR: | |
2196 | case FIX_TRUNC_EXPR: | |
2197 | { | |
2198 | tree src = TREE_OPERAND (exp, 0); | |
2199 | tree src_type = TREE_TYPE (src); | |
2200 | tree dst_type = TREE_TYPE (exp); | |
89b894e1 | 2201 | generate_bytecode_insns (TREE_OPERAND (exp, 0), target, state); |
3885dfa7 PB |
2202 | if (target == IGNORE_TARGET || src_type == dst_type) |
2203 | break; | |
2204 | if (TREE_CODE (dst_type) == POINTER_TYPE) | |
2205 | { | |
2206 | if (TREE_CODE (exp) == CONVERT_EXPR) | |
2207 | { | |
afc390b1 APB |
2208 | int index = find_class_constant (&state->cpool, |
2209 | TREE_TYPE (dst_type)); | |
3885dfa7 PB |
2210 | RESERVE (3); |
2211 | OP1 (OPCODE_checkcast); | |
2212 | OP2 (index); | |
2213 | } | |
2214 | } | |
2215 | else /* Convert numeric types. */ | |
2216 | { | |
2217 | int wide_src = TYPE_PRECISION (src_type) > 32; | |
2218 | int wide_dst = TYPE_PRECISION (dst_type) > 32; | |
2219 | NOTE_POP (1 + wide_src); | |
2220 | RESERVE (1); | |
2221 | if (TREE_CODE (dst_type) == REAL_TYPE) | |
2222 | { | |
2223 | if (TREE_CODE (src_type) == REAL_TYPE) | |
2224 | OP1 (wide_dst ? OPCODE_f2d : OPCODE_d2f); | |
2225 | else if (TYPE_PRECISION (src_type) == 64) | |
2226 | OP1 (OPCODE_l2f + wide_dst); | |
2227 | else | |
2228 | OP1 (OPCODE_i2f + wide_dst); | |
2229 | } | |
2230 | else /* Convert to integral type. */ | |
2231 | { | |
2232 | if (TREE_CODE (src_type) == REAL_TYPE) | |
2233 | OP1 (OPCODE_f2i + wide_dst + 3 * wide_src); | |
2234 | else if (wide_dst) | |
2235 | OP1 (OPCODE_i2l); | |
2236 | else if (wide_src) | |
2237 | OP1 (OPCODE_l2i); | |
2238 | if (TYPE_PRECISION (dst_type) < 32) | |
2239 | { | |
2240 | RESERVE (1); | |
2241 | /* Already converted to int, if needed. */ | |
2242 | if (TYPE_PRECISION (dst_type) <= 8) | |
2243 | OP1 (OPCODE_i2b); | |
8df83eae | 2244 | else if (TYPE_UNSIGNED (dst_type)) |
3885dfa7 PB |
2245 | OP1 (OPCODE_i2c); |
2246 | else | |
2247 | OP1 (OPCODE_i2s); | |
2248 | } | |
2249 | } | |
2250 | NOTE_PUSH (1 + wide_dst); | |
2251 | } | |
2252 | } | |
2253 | break; | |
45b44fbe | 2254 | |
3885dfa7 PB |
2255 | case TRY_EXPR: |
2256 | { | |
2257 | tree try_clause = TREE_OPERAND (exp, 0); | |
3885dfa7 PB |
2258 | struct jcf_block *start_label = get_jcf_label_here (state); |
2259 | struct jcf_block *end_label; /* End of try clause. */ | |
3885dfa7 PB |
2260 | struct jcf_block *finished_label = gen_jcf_label (state); |
2261 | tree clause = TREE_OPERAND (exp, 1); | |
3885dfa7 PB |
2262 | if (target != IGNORE_TARGET) |
2263 | abort (); | |
2264 | generate_bytecode_insns (try_clause, IGNORE_TARGET, state); | |
2265 | end_label = get_jcf_label_here (state); | |
fa029f45 PB |
2266 | if (end_label == start_label) |
2267 | break; | |
3885dfa7 PB |
2268 | if (CAN_COMPLETE_NORMALLY (try_clause)) |
2269 | emit_goto (finished_label, state); | |
a7d8d81f | 2270 | while (clause != NULL_TREE) |
3885dfa7 PB |
2271 | { |
2272 | tree catch_clause = TREE_OPERAND (clause, 0); | |
2273 | tree exception_decl = BLOCK_EXPR_DECLS (catch_clause); | |
2d93b924 TT |
2274 | struct jcf_handler *handler = alloc_handler (start_label, |
2275 | end_label, state); | |
4c22d9c8 PB |
2276 | if (exception_decl == NULL_TREE) |
2277 | handler->type = NULL_TREE; | |
2278 | else | |
2279 | handler->type = TREE_TYPE (TREE_TYPE (exception_decl)); | |
3885dfa7 | 2280 | generate_bytecode_insns (catch_clause, IGNORE_TARGET, state); |
a7d8d81f PB |
2281 | clause = TREE_CHAIN (clause); |
2282 | if (CAN_COMPLETE_NORMALLY (catch_clause) && clause != NULL_TREE) | |
3885dfa7 PB |
2283 | emit_goto (finished_label, state); |
2284 | } | |
a7d8d81f PB |
2285 | define_jcf_label (finished_label, state); |
2286 | } | |
2287 | break; | |
aedcdb65 | 2288 | |
a7d8d81f PB |
2289 | case TRY_FINALLY_EXPR: |
2290 | { | |
2d93b924 TT |
2291 | struct jcf_block *finished_label = NULL; |
2292 | struct jcf_block *finally_label, *start_label, *end_label; | |
2a1ed9c1 | 2293 | struct jcf_handler *handler; |
a7d8d81f PB |
2294 | tree try_block = TREE_OPERAND (exp, 0); |
2295 | tree finally = TREE_OPERAND (exp, 1); | |
fa029f45 | 2296 | tree return_link = NULL_TREE, exception_decl = NULL_TREE; |
0e9137bb | 2297 | |
fa029f45 | 2298 | tree exception_type; |
a7d8d81f | 2299 | |
fa029f45 PB |
2300 | finally_label = gen_jcf_label (state); |
2301 | start_label = get_jcf_label_here (state); | |
2d93b924 TT |
2302 | /* If the `finally' clause can complete normally, we emit it |
2303 | as a subroutine and let the other clauses call it via | |
2304 | `jsr'. If it can't complete normally, then we simply emit | |
2305 | `goto's directly to it. */ | |
2306 | if (CAN_COMPLETE_NORMALLY (finally)) | |
2307 | { | |
2308 | finally_label->pc = PENDING_CLEANUP_PC; | |
2309 | finally_label->next = state->labeled_blocks; | |
2310 | state->labeled_blocks = finally_label; | |
2311 | state->num_finalizers++; | |
2312 | } | |
fa029f45 PB |
2313 | |
2314 | generate_bytecode_insns (try_block, target, state); | |
2d93b924 TT |
2315 | |
2316 | if (CAN_COMPLETE_NORMALLY (finally)) | |
2317 | { | |
2318 | if (state->labeled_blocks != finally_label) | |
2319 | abort(); | |
2320 | state->labeled_blocks = finally_label->next; | |
2321 | } | |
fa029f45 | 2322 | end_label = get_jcf_label_here (state); |
2a1ed9c1 | 2323 | |
fa029f45 | 2324 | if (end_label == start_label) |
2a1ed9c1 | 2325 | { |
fa029f45 PB |
2326 | state->num_finalizers--; |
2327 | define_jcf_label (finally_label, state); | |
2328 | generate_bytecode_insns (finally, IGNORE_TARGET, state); | |
2329 | break; | |
2a1ed9c1 | 2330 | } |
3885dfa7 | 2331 | |
2d93b924 TT |
2332 | if (CAN_COMPLETE_NORMALLY (finally)) |
2333 | { | |
2334 | return_link = build_decl (VAR_DECL, NULL_TREE, | |
2335 | return_address_type_node); | |
2336 | finished_label = gen_jcf_label (state); | |
2337 | } | |
2a1ed9c1 | 2338 | |
fa029f45 | 2339 | if (CAN_COMPLETE_NORMALLY (try_block)) |
2a1ed9c1 | 2340 | { |
2d93b924 TT |
2341 | if (CAN_COMPLETE_NORMALLY (finally)) |
2342 | { | |
2343 | emit_jsr (finally_label, state); | |
2344 | emit_goto (finished_label, state); | |
2345 | } | |
2346 | else | |
2347 | emit_goto (finally_label, state); | |
2a1ed9c1 APB |
2348 | } |
2349 | ||
2d93b924 | 2350 | /* Handle exceptions. */ |
2a1ed9c1 | 2351 | |
fa029f45 | 2352 | exception_type = build_pointer_type (throwable_type_node); |
2d93b924 TT |
2353 | if (CAN_COMPLETE_NORMALLY (finally)) |
2354 | { | |
2355 | /* We're going to generate a subroutine, so we'll need to | |
2356 | save and restore the exception around the `jsr'. */ | |
2357 | exception_decl = build_decl (VAR_DECL, NULL_TREE, exception_type); | |
2358 | localvar_alloc (return_link, state); | |
2359 | } | |
fa029f45 | 2360 | handler = alloc_handler (start_label, end_label, state); |
a7d8d81f | 2361 | handler->type = NULL_TREE; |
2d93b924 TT |
2362 | if (CAN_COMPLETE_NORMALLY (finally)) |
2363 | { | |
2364 | localvar_alloc (exception_decl, state); | |
2365 | NOTE_PUSH (1); | |
2366 | emit_store (exception_decl, state); | |
2367 | emit_jsr (finally_label, state); | |
2368 | emit_load (exception_decl, state); | |
2369 | RESERVE (1); | |
2370 | OP1 (OPCODE_athrow); | |
2371 | NOTE_POP (1); | |
2372 | } | |
2373 | else | |
2374 | { | |
2375 | /* We're not generating a subroutine. In this case we can | |
2376 | simply have the exception handler pop the exception and | |
2377 | then fall through to the `finally' block. */ | |
2378 | NOTE_PUSH (1); | |
2379 | emit_pop (1, state); | |
2380 | NOTE_POP (1); | |
2381 | } | |
2382 | ||
2383 | /* The finally block. If we're generating a subroutine, first | |
2384 | save return PC into return_link. Otherwise, just generate | |
2385 | the code for the `finally' block. */ | |
a7d8d81f | 2386 | define_jcf_label (finally_label, state); |
2d93b924 TT |
2387 | if (CAN_COMPLETE_NORMALLY (finally)) |
2388 | { | |
2389 | NOTE_PUSH (1); | |
2390 | emit_store (return_link, state); | |
2391 | } | |
a7d8d81f PB |
2392 | |
2393 | generate_bytecode_insns (finally, IGNORE_TARGET, state); | |
2d93b924 TT |
2394 | if (CAN_COMPLETE_NORMALLY (finally)) |
2395 | { | |
2396 | maybe_wide (OPCODE_ret, DECL_LOCAL_INDEX (return_link), state); | |
72f339d2 AH |
2397 | maybe_free_localvar (exception_decl, state, 1); |
2398 | maybe_free_localvar (return_link, state, 1); | |
2d93b924 TT |
2399 | define_jcf_label (finished_label, state); |
2400 | } | |
3885dfa7 PB |
2401 | } |
2402 | break; | |
2403 | case THROW_EXPR: | |
2404 | generate_bytecode_insns (TREE_OPERAND (exp, 0), STACK_TARGET, state); | |
2405 | RESERVE (1); | |
2406 | OP1 (OPCODE_athrow); | |
2407 | break; | |
df1e6be5 PB |
2408 | case NEW_ARRAY_INIT: |
2409 | { | |
63a212ed | 2410 | tree values = CONSTRUCTOR_ELTS (TREE_OPERAND (exp, 0)); |
df1e6be5 PB |
2411 | tree array_type = TREE_TYPE (TREE_TYPE (exp)); |
2412 | tree element_type = TYPE_ARRAY_ELEMENT (array_type); | |
2413 | HOST_WIDE_INT length = java_array_type_length (array_type); | |
63a212ed PB |
2414 | if (target == IGNORE_TARGET) |
2415 | { | |
2416 | for ( ; values != NULL_TREE; values = TREE_CHAIN (values)) | |
2417 | generate_bytecode_insns (TREE_VALUE (values), target, state); | |
2418 | break; | |
2419 | } | |
df1e6be5 PB |
2420 | push_int_const (length, state); |
2421 | NOTE_PUSH (1); | |
2422 | RESERVE (3); | |
2423 | if (JPRIMITIVE_TYPE_P (element_type)) | |
2424 | { | |
2425 | int atype = encode_newarray_type (element_type); | |
2426 | OP1 (OPCODE_newarray); | |
2427 | OP1 (atype); | |
2428 | } | |
2429 | else | |
2430 | { | |
2431 | int index = find_class_constant (&state->cpool, | |
2432 | TREE_TYPE (element_type)); | |
2433 | OP1 (OPCODE_anewarray); | |
2434 | OP2 (index); | |
2435 | } | |
df1e6be5 PB |
2436 | offset = 0; |
2437 | jopcode = OPCODE_iastore + adjust_typed_op (element_type, 7); | |
2438 | for ( ; values != NULL_TREE; values = TREE_CHAIN (values), offset++) | |
2439 | { | |
2440 | int save_SP = state->code_SP; | |
2441 | emit_dup (1, 0, state); | |
2442 | push_int_const (offset, state); | |
63a212ed | 2443 | NOTE_PUSH (1); |
df1e6be5 PB |
2444 | generate_bytecode_insns (TREE_VALUE (values), STACK_TARGET, state); |
2445 | RESERVE (1); | |
2446 | OP1 (jopcode); | |
2447 | state->code_SP = save_SP; | |
2448 | } | |
2449 | } | |
2450 | break; | |
f17f1898 | 2451 | case JAVA_EXC_OBJ_EXPR: |
52a11cbf RH |
2452 | NOTE_PUSH (1); /* Pushed by exception system. */ |
2453 | break; | |
1319e88e AH |
2454 | case MIN_EXPR: |
2455 | case MAX_EXPR: | |
2456 | { | |
2457 | /* This copes with cases where fold() has created MIN or MAX | |
2458 | from a conditional expression. */ | |
2459 | enum tree_code code = TREE_CODE (exp) == MIN_EXPR ? LT_EXPR : GT_EXPR; | |
2460 | tree op0 = TREE_OPERAND (exp, 0); | |
2461 | tree op1 = TREE_OPERAND (exp, 1); | |
2462 | tree x; | |
2463 | if (TREE_SIDE_EFFECTS (op0) || TREE_SIDE_EFFECTS (op1)) | |
2464 | abort (); | |
2465 | x = build (COND_EXPR, TREE_TYPE (exp), | |
2466 | build (code, boolean_type_node, op0, op1), | |
2467 | op0, op1); | |
2468 | generate_bytecode_insns (x, target, state); | |
2469 | break; | |
2470 | } | |
3885dfa7 PB |
2471 | case NEW_CLASS_EXPR: |
2472 | { | |
2473 | tree class = TREE_TYPE (TREE_TYPE (exp)); | |
23a7b8f5 | 2474 | int need_result = target != IGNORE_TARGET; |
3885dfa7 PB |
2475 | int index = find_class_constant (&state->cpool, class); |
2476 | RESERVE (4); | |
2477 | OP1 (OPCODE_new); | |
2478 | OP2 (index); | |
23a7b8f5 PB |
2479 | if (need_result) |
2480 | OP1 (OPCODE_dup); | |
2481 | NOTE_PUSH (1 + need_result); | |
3885dfa7 PB |
2482 | } |
2483 | /* ... fall though ... */ | |
e04a16fb AG |
2484 | case CALL_EXPR: |
2485 | { | |
3885dfa7 PB |
2486 | tree f = TREE_OPERAND (exp, 0); |
2487 | tree x = TREE_OPERAND (exp, 1); | |
e4de5a10 | 2488 | int save_SP = state->code_SP; |
23a7b8f5 | 2489 | int nargs; |
3885dfa7 PB |
2490 | if (TREE_CODE (f) == ADDR_EXPR) |
2491 | f = TREE_OPERAND (f, 0); | |
2492 | if (f == soft_newarray_node) | |
e04a16fb | 2493 | { |
3885dfa7 PB |
2494 | int type_code = TREE_INT_CST_LOW (TREE_VALUE (x)); |
2495 | generate_bytecode_insns (TREE_VALUE (TREE_CHAIN (x)), | |
2496 | STACK_TARGET, state); | |
2497 | RESERVE (2); | |
2498 | OP1 (OPCODE_newarray); | |
2499 | OP1 (type_code); | |
2500 | break; | |
2501 | } | |
2502 | else if (f == soft_multianewarray_node) | |
2503 | { | |
2504 | int ndims; | |
2505 | int idim; | |
2506 | int index = find_class_constant (&state->cpool, | |
2507 | TREE_TYPE (TREE_TYPE (exp))); | |
2508 | x = TREE_CHAIN (x); /* Skip class argument. */ | |
2509 | ndims = TREE_INT_CST_LOW (TREE_VALUE (x)); | |
2510 | for (idim = ndims; --idim >= 0; ) | |
2511 | { | |
2512 | x = TREE_CHAIN (x); | |
2513 | generate_bytecode_insns (TREE_VALUE (x), STACK_TARGET, state); | |
2514 | } | |
2515 | RESERVE (4); | |
2516 | OP1 (OPCODE_multianewarray); | |
2517 | OP2 (index); | |
2518 | OP1 (ndims); | |
2519 | break; | |
2520 | } | |
2521 | else if (f == soft_anewarray_node) | |
2522 | { | |
2523 | tree cl = TYPE_ARRAY_ELEMENT (TREE_TYPE (TREE_TYPE (exp))); | |
2524 | int index = find_class_constant (&state->cpool, TREE_TYPE (cl)); | |
2525 | generate_bytecode_insns (TREE_VALUE (x), STACK_TARGET, state); | |
2526 | RESERVE (3); | |
2527 | OP1 (OPCODE_anewarray); | |
2528 | OP2 (index); | |
2529 | break; | |
2530 | } | |
4c22d9c8 PB |
2531 | else if (f == soft_monitorenter_node |
2532 | || f == soft_monitorexit_node | |
ce1c98ea | 2533 | || f == throw_node) |
4c22d9c8 PB |
2534 | { |
2535 | if (f == soft_monitorenter_node) | |
2536 | op = OPCODE_monitorenter; | |
2537 | else if (f == soft_monitorexit_node) | |
2538 | op = OPCODE_monitorexit; | |
2539 | else | |
2540 | op = OPCODE_athrow; | |
2541 | generate_bytecode_insns (TREE_VALUE (x), STACK_TARGET, state); | |
2542 | RESERVE (1); | |
2543 | OP1 (op); | |
2544 | NOTE_POP (1); | |
2545 | break; | |
2546 | } | |
3885dfa7 PB |
2547 | for ( ; x != NULL_TREE; x = TREE_CHAIN (x)) |
2548 | { | |
2549 | generate_bytecode_insns (TREE_VALUE (x), STACK_TARGET, state); | |
e04a16fb | 2550 | } |
23a7b8f5 | 2551 | nargs = state->code_SP - save_SP; |
e4de5a10 | 2552 | state->code_SP = save_SP; |
cff699c1 PB |
2553 | if (f == soft_fmod_node) |
2554 | { | |
2555 | RESERVE (1); | |
2556 | OP1 (OPCODE_drem); | |
2557 | NOTE_PUSH (2); | |
2558 | break; | |
2559 | } | |
23a7b8f5 PB |
2560 | if (TREE_CODE (exp) == NEW_CLASS_EXPR) |
2561 | NOTE_POP (1); /* Pop implicit this. */ | |
3885dfa7 | 2562 | if (TREE_CODE (f) == FUNCTION_DECL && DECL_CONTEXT (f) != NULL_TREE) |
e04a16fb | 2563 | { |
8789b9fa | 2564 | tree context = DECL_CONTEXT (f); |
cedea510 | 2565 | int index, interface = 0; |
23a7b8f5 | 2566 | RESERVE (5); |
63a212ed PB |
2567 | if (METHOD_STATIC (f)) |
2568 | OP1 (OPCODE_invokestatic); | |
2569 | else if (DECL_CONSTRUCTOR_P (f) || CALL_USING_SUPER (exp) | |
23a7b8f5 | 2570 | || METHOD_PRIVATE (f)) |
e04a16fb | 2571 | OP1 (OPCODE_invokespecial); |
e04a16fb | 2572 | else |
cedea510 | 2573 | { |
8789b9fa PB |
2574 | if (CLASS_INTERFACE (TYPE_NAME (context))) |
2575 | { | |
2576 | tree arg1 = TREE_VALUE (TREE_OPERAND (exp, 1)); | |
2577 | context = TREE_TYPE (TREE_TYPE (arg1)); | |
2578 | if (CLASS_INTERFACE (TYPE_NAME (context))) | |
2579 | interface = 1; | |
2580 | } | |
2581 | if (interface) | |
2582 | OP1 (OPCODE_invokeinterface); | |
2583 | else | |
2584 | OP1 (OPCODE_invokevirtual); | |
cedea510 | 2585 | } |
8789b9fa | 2586 | index = find_methodref_with_class_index (&state->cpool, f, context); |
e04a16fb | 2587 | OP2 (index); |
34d4df06 APB |
2588 | if (interface) |
2589 | { | |
81baa09a | 2590 | if (nargs <= 0) |
400500c4 RK |
2591 | abort (); |
2592 | ||
34d4df06 APB |
2593 | OP1 (nargs); |
2594 | OP1 (0); | |
2595 | } | |
3885dfa7 PB |
2596 | f = TREE_TYPE (TREE_TYPE (f)); |
2597 | if (TREE_CODE (f) != VOID_TYPE) | |
e4de5a10 | 2598 | { |
3885dfa7 | 2599 | int size = TYPE_IS_WIDE (f) ? 2 : 1; |
e4de5a10 PB |
2600 | if (target == IGNORE_TARGET) |
2601 | emit_pop (size, state); | |
2602 | else | |
2603 | NOTE_PUSH (size); | |
2604 | } | |
e04a16fb AG |
2605 | break; |
2606 | } | |
2607 | } | |
2608 | /* fall through */ | |
e4de5a10 | 2609 | notimpl: |
e04a16fb | 2610 | default: |
165f37bc | 2611 | error("internal error in generate_bytecode_insn - tree code not implemented: %s", |
e4de5a10 | 2612 | tree_code_name [(int) TREE_CODE (exp)]); |
e04a16fb AG |
2613 | } |
2614 | } | |
2615 | ||
4bcde32e | 2616 | static void |
0a2f0c54 | 2617 | perform_relocations (struct jcf_partial *state) |
e4de5a10 PB |
2618 | { |
2619 | struct jcf_block *block; | |
2620 | struct jcf_relocation *reloc; | |
2621 | int pc; | |
2622 | int shrink; | |
2623 | ||
3885dfa7 PB |
2624 | /* Before we start, the pc field of each block is an upper bound on |
2625 | the block's start pc (it may be less, if previous blocks need less | |
2626 | than their maximum). | |
2627 | ||
2628 | The minimum size of each block is in the block's chunk->size. */ | |
2629 | ||
2630 | /* First, figure out the actual locations of each block. */ | |
e4de5a10 PB |
2631 | pc = 0; |
2632 | shrink = 0; | |
2633 | for (block = state->blocks; block != NULL; block = block->next) | |
2634 | { | |
45b44fbe | 2635 | int block_size = block->v.chunk->size; |
e4de5a10 PB |
2636 | |
2637 | block->pc = pc; | |
2638 | ||
2639 | /* Optimize GOTO L; L: by getting rid of the redundant goto. | |
2640 | Assumes relocations are in reverse order. */ | |
2641 | reloc = block->u.relocations; | |
2642 | while (reloc != NULL | |
3885dfa7 | 2643 | && reloc->kind == OPCODE_goto_w |
e4de5a10 | 2644 | && reloc->label->pc == block->next->pc |
3885dfa7 | 2645 | && reloc->offset + 2 == block_size) |
e4de5a10 PB |
2646 | { |
2647 | reloc = reloc->next; | |
2648 | block->u.relocations = reloc; | |
45b44fbe | 2649 | block->v.chunk->size -= 3; |
e4de5a10 PB |
2650 | block_size -= 3; |
2651 | shrink += 3; | |
2652 | } | |
2653 | ||
f06cafdf TT |
2654 | /* Optimize GOTO L; ... L: GOTO X by changing the first goto to |
2655 | jump directly to X. We're careful here to avoid an infinite | |
2656 | loop if the `goto's themselves form one. We do this | |
2657 | optimization because we can generate a goto-to-goto for some | |
2658 | try/finally blocks. */ | |
2659 | while (reloc != NULL | |
2660 | && reloc->kind == OPCODE_goto_w | |
2661 | && reloc->label != block | |
2662 | && reloc->label->v.chunk->data != NULL | |
2663 | && reloc->label->v.chunk->data[0] == OPCODE_goto) | |
2664 | { | |
2665 | /* Find the reloc for the first instruction of the | |
2666 | destination block. */ | |
2667 | struct jcf_relocation *first_reloc; | |
2668 | for (first_reloc = reloc->label->u.relocations; | |
2669 | first_reloc; | |
2670 | first_reloc = first_reloc->next) | |
2671 | { | |
2672 | if (first_reloc->offset == 1 | |
2673 | && first_reloc->kind == OPCODE_goto_w) | |
2674 | { | |
2675 | reloc->label = first_reloc->label; | |
2676 | break; | |
2677 | } | |
2678 | } | |
2679 | ||
2680 | /* If we didn't do anything, exit the loop. */ | |
2681 | if (first_reloc == NULL) | |
2682 | break; | |
2683 | } | |
2684 | ||
e4de5a10 PB |
2685 | for (reloc = block->u.relocations; reloc != NULL; reloc = reloc->next) |
2686 | { | |
3885dfa7 PB |
2687 | if (reloc->kind == SWITCH_ALIGN_RELOC) |
2688 | { | |
2689 | /* We assume this is the first relocation in this block, | |
2690 | so we know its final pc. */ | |
2691 | int where = pc + reloc->offset; | |
2692 | int pad = ((where + 3) & ~3) - where; | |
2693 | block_size += pad; | |
2694 | } | |
2695 | else if (reloc->kind < -1 || reloc->kind > BLOCK_START_RELOC) | |
e4de5a10 PB |
2696 | { |
2697 | int delta = reloc->label->pc - (pc + reloc->offset - 1); | |
2698 | int expand = reloc->kind > 0 ? 2 : 5; | |
2699 | ||
2700 | if (delta > 0) | |
2701 | delta -= shrink; | |
2702 | if (delta >= -32768 && delta <= 32767) | |
2703 | { | |
2704 | shrink += expand; | |
2705 | reloc->kind = -1; | |
2706 | } | |
2707 | else | |
2708 | block_size += expand; | |
2709 | } | |
2710 | } | |
2711 | pc += block_size; | |
2712 | } | |
2713 | ||
2714 | for (block = state->blocks; block != NULL; block = block->next) | |
2715 | { | |
45b44fbe | 2716 | struct chunk *chunk = block->v.chunk; |
e4de5a10 PB |
2717 | int old_size = chunk->size; |
2718 | int next_pc = block->next == NULL ? pc : block->next->pc; | |
2719 | int new_size = next_pc - block->pc; | |
e4de5a10 PB |
2720 | unsigned char *new_ptr; |
2721 | unsigned char *old_buffer = chunk->data; | |
2722 | unsigned char *old_ptr = old_buffer + old_size; | |
e4de5a10 PB |
2723 | if (new_size != old_size) |
2724 | { | |
c68b0a84 | 2725 | chunk->data = obstack_alloc (state->chunk_obstack, new_size); |
3885dfa7 | 2726 | chunk->size = new_size; |
e4de5a10 PB |
2727 | } |
2728 | new_ptr = chunk->data + new_size; | |
2729 | ||
2730 | /* We do the relocations from back to front, because | |
3885dfa7 | 2731 | the relocations are in reverse order. */ |
e4de5a10 PB |
2732 | for (reloc = block->u.relocations; ; reloc = reloc->next) |
2733 | { | |
3885dfa7 PB |
2734 | /* new_ptr and old_ptr point into the old and new buffers, |
2735 | respectively. (If no relocations cause the buffer to | |
2736 | grow, the buffer will be the same buffer, and new_ptr==old_ptr.) | |
a83f01f0 | 2737 | The bytes at higher address have been copied and relocations |
3885dfa7 PB |
2738 | handled; those at lower addresses remain to process. */ |
2739 | ||
2740 | /* Lower old index of piece to be copied with no relocation. | |
2741 | I.e. high index of the first piece that does need relocation. */ | |
e4de5a10 | 2742 | int start = reloc == NULL ? 0 |
3885dfa7 PB |
2743 | : reloc->kind == SWITCH_ALIGN_RELOC ? reloc->offset |
2744 | : (reloc->kind == 0 || reloc->kind == BLOCK_START_RELOC) | |
2745 | ? reloc->offset + 4 | |
e4de5a10 PB |
2746 | : reloc->offset + 2; |
2747 | int32 value; | |
2748 | int new_offset; | |
2749 | int n = (old_ptr - old_buffer) - start; | |
2750 | new_ptr -= n; | |
2751 | old_ptr -= n; | |
2752 | if (n > 0) | |
3885dfa7 | 2753 | memcpy (new_ptr, old_ptr, n); |
e4de5a10 PB |
2754 | if (old_ptr == old_buffer) |
2755 | break; | |
2756 | ||
3885dfa7 PB |
2757 | new_offset = new_ptr - chunk->data; |
2758 | new_offset -= (reloc->kind == -1 ? 2 : 4); | |
e4de5a10 PB |
2759 | if (reloc->kind == 0) |
2760 | { | |
2761 | old_ptr -= 4; | |
2762 | value = GET_u4 (old_ptr); | |
2763 | } | |
3885dfa7 PB |
2764 | else if (reloc->kind == BLOCK_START_RELOC) |
2765 | { | |
2766 | old_ptr -= 4; | |
2767 | value = 0; | |
2768 | new_offset = 0; | |
2769 | } | |
2770 | else if (reloc->kind == SWITCH_ALIGN_RELOC) | |
2771 | { | |
2772 | int where = block->pc + reloc->offset; | |
2773 | int pad = ((where + 3) & ~3) - where; | |
2774 | while (--pad >= 0) | |
2775 | *--new_ptr = 0; | |
2776 | continue; | |
2777 | } | |
e4de5a10 PB |
2778 | else |
2779 | { | |
2780 | old_ptr -= 2; | |
2781 | value = GET_u2 (old_ptr); | |
2782 | } | |
e4de5a10 PB |
2783 | value += reloc->label->pc - (block->pc + new_offset); |
2784 | *--new_ptr = (unsigned char) value; value >>= 8; | |
2785 | *--new_ptr = (unsigned char) value; value >>= 8; | |
2786 | if (reloc->kind != -1) | |
2787 | { | |
2788 | *--new_ptr = (unsigned char) value; value >>= 8; | |
2789 | *--new_ptr = (unsigned char) value; | |
2790 | } | |
3885dfa7 | 2791 | if (reloc->kind > BLOCK_START_RELOC) |
e4de5a10 PB |
2792 | { |
2793 | /* Convert: OP TARGET to: OP_w TARGET; (OP is goto or jsr). */ | |
2794 | --old_ptr; | |
2795 | *--new_ptr = reloc->kind; | |
2796 | } | |
2797 | else if (reloc->kind < -1) | |
2798 | { | |
2799 | /* Convert: ifCOND TARGET to: ifNCOND T; goto_w TARGET; T: */ | |
2800 | --old_ptr; | |
2801 | *--new_ptr = OPCODE_goto_w; | |
2802 | *--new_ptr = 3; | |
2803 | *--new_ptr = 0; | |
2804 | *--new_ptr = - reloc->kind; | |
2805 | } | |
2806 | } | |
3865d508 | 2807 | if (new_ptr != chunk->data) |
400500c4 | 2808 | abort (); |
e4de5a10 PB |
2809 | } |
2810 | state->code_length = pc; | |
2811 | } | |
2812 | ||
4bcde32e | 2813 | static void |
0a2f0c54 | 2814 | init_jcf_state (struct jcf_partial *state, struct obstack *work) |
e4de5a10 PB |
2815 | { |
2816 | state->chunk_obstack = work; | |
2817 | state->first = state->chunk = NULL; | |
2818 | CPOOL_INIT (&state->cpool); | |
2819 | BUFFER_INIT (&state->localvars); | |
2820 | BUFFER_INIT (&state->bytecode); | |
2821 | } | |
2822 | ||
4bcde32e | 2823 | static void |
0a2f0c54 | 2824 | init_jcf_method (struct jcf_partial *state, tree method) |
e4de5a10 PB |
2825 | { |
2826 | state->current_method = method; | |
2827 | state->blocks = state->last_block = NULL; | |
2828 | state->linenumber_count = 0; | |
2829 | state->first_lvar = state->last_lvar = NULL; | |
2830 | state->lvar_count = 0; | |
2831 | state->labeled_blocks = NULL; | |
2832 | state->code_length = 0; | |
2833 | BUFFER_RESET (&state->bytecode); | |
2834 | BUFFER_RESET (&state->localvars); | |
2835 | state->code_SP = 0; | |
2836 | state->code_SP_max = 0; | |
3885dfa7 PB |
2837 | state->handlers = NULL; |
2838 | state->last_handler = NULL; | |
2839 | state->num_handlers = 0; | |
45b44fbe PB |
2840 | state->num_finalizers = 0; |
2841 | state->return_value_decl = NULL_TREE; | |
e4de5a10 PB |
2842 | } |
2843 | ||
4bcde32e | 2844 | static void |
0a2f0c54 | 2845 | release_jcf_state (struct jcf_partial *state) |
e4de5a10 PB |
2846 | { |
2847 | CPOOL_FINISH (&state->cpool); | |
2848 | obstack_free (state->chunk_obstack, state->first); | |
2849 | } | |
2850 | ||
e04a16fb AG |
2851 | /* Generate and return a list of chunks containing the class CLAS |
2852 | in the .class file representation. The list can be written to a | |
2853 | .class file using write_chunks. Allocate chunks from obstack WORK. */ | |
2854 | ||
e2500fed | 2855 | static GTY(()) tree SourceFile_node; |
4bcde32e | 2856 | static struct chunk * |
0a2f0c54 | 2857 | generate_classfile (tree clas, struct jcf_partial *state) |
e04a16fb | 2858 | { |
e04a16fb | 2859 | struct chunk *cpool_chunk; |
3b304f5b | 2860 | const char *source_file, *s; |
e04a16fb AG |
2861 | char *ptr; |
2862 | int i; | |
2863 | char *fields_count_ptr; | |
2864 | int fields_count = 0; | |
2865 | char *methods_count_ptr; | |
2866 | int methods_count = 0; | |
2867 | tree part; | |
2868 | int total_supers | |
2869 | = clas == object_type_node ? 0 | |
2870 | : TREE_VEC_LENGTH (TYPE_BINFO_BASETYPES (clas)); | |
e4de5a10 PB |
2871 | |
2872 | ptr = append_chunk (NULL, 8, state); | |
e04a16fb AG |
2873 | PUT4 (0xCafeBabe); /* Magic number */ |
2874 | PUT2 (3); /* Minor version */ | |
2875 | PUT2 (45); /* Major version */ | |
2876 | ||
e4de5a10 PB |
2877 | append_chunk (NULL, 0, state); |
2878 | cpool_chunk = state->chunk; | |
e04a16fb | 2879 | |
67264b4f | 2880 | /* Next allocate the chunk containing access_flags through fields_count. */ |
e04a16fb AG |
2881 | if (clas == object_type_node) |
2882 | i = 10; | |
2883 | else | |
2884 | i = 8 + 2 * total_supers; | |
e4de5a10 | 2885 | ptr = append_chunk (NULL, i, state); |
2728f622 PB |
2886 | i = get_access_flags (TYPE_NAME (clas)); |
2887 | if (! (i & ACC_INTERFACE)) | |
2888 | i |= ACC_SUPER; | |
67264b4f | 2889 | PUT2 (i); /* access_flags */ |
e4de5a10 | 2890 | i = find_class_constant (&state->cpool, clas); PUT2 (i); /* this_class */ |
e04a16fb AG |
2891 | if (clas == object_type_node) |
2892 | { | |
2893 | PUT2(0); /* super_class */ | |
2894 | PUT2(0); /* interfaces_count */ | |
2895 | } | |
2896 | else | |
2897 | { | |
2898 | tree basetypes = TYPE_BINFO_BASETYPES (clas); | |
2899 | tree base = BINFO_TYPE (TREE_VEC_ELT (basetypes, 0)); | |
e4de5a10 PB |
2900 | int j = find_class_constant (&state->cpool, base); |
2901 | PUT2 (j); /* super_class */ | |
e04a16fb AG |
2902 | PUT2 (total_supers - 1); /* interfaces_count */ |
2903 | for (i = 1; i < total_supers; i++) | |
2904 | { | |
2905 | base = BINFO_TYPE (TREE_VEC_ELT (basetypes, i)); | |
e4de5a10 | 2906 | j = find_class_constant (&state->cpool, base); |
e04a16fb AG |
2907 | PUT2 (j); |
2908 | } | |
2909 | } | |
2910 | fields_count_ptr = ptr; | |
2911 | ||
2912 | for (part = TYPE_FIELDS (clas); part; part = TREE_CHAIN (part)) | |
2913 | { | |
c2952b01 | 2914 | int have_value, attr_count = 0; |
63a212ed | 2915 | if (DECL_NAME (part) == NULL_TREE || DECL_ARTIFICIAL (part)) |
e04a16fb | 2916 | continue; |
e4de5a10 | 2917 | ptr = append_chunk (NULL, 8, state); |
e04a16fb | 2918 | i = get_access_flags (part); PUT2 (i); |
e4de5a10 | 2919 | i = find_utf8_constant (&state->cpool, DECL_NAME (part)); PUT2 (i); |
c2952b01 APB |
2920 | i = find_utf8_constant (&state->cpool, |
2921 | build_java_signature (TREE_TYPE (part))); | |
e04a16fb | 2922 | PUT2(i); |
629d4b4d | 2923 | have_value = DECL_INITIAL (part) != NULL_TREE |
1b9ee723 | 2924 | && FIELD_STATIC (part) && CONSTANT_VALUE_P (DECL_INITIAL (part)) |
be0c7ff4 PB |
2925 | && FIELD_FINAL (part) |
2926 | && (JPRIMITIVE_TYPE_P (TREE_TYPE (part)) | |
2927 | || TREE_TYPE (part) == string_ptr_type_node); | |
c2952b01 APB |
2928 | if (have_value) |
2929 | attr_count++; | |
2930 | ||
f94ae540 TT |
2931 | if (FIELD_THISN (part) || FIELD_LOCAL_ALIAS (part) |
2932 | || FIELD_SYNTHETIC (part)) | |
c2952b01 | 2933 | attr_count++; |
f94ae540 TT |
2934 | if (FIELD_DEPRECATED (part)) |
2935 | attr_count++; | |
c2952b01 APB |
2936 | |
2937 | PUT2 (attr_count); /* attributes_count */ | |
23a7b8f5 PB |
2938 | if (have_value) |
2939 | { | |
2940 | tree init = DECL_INITIAL (part); | |
2941 | static tree ConstantValue_node = NULL_TREE; | |
731866ba | 2942 | if (TREE_TYPE (part) != TREE_TYPE (init)) |
357351e5 | 2943 | fatal_error ("field initializer type mismatch"); |
23a7b8f5 PB |
2944 | ptr = append_chunk (NULL, 8, state); |
2945 | if (ConstantValue_node == NULL_TREE) | |
2946 | ConstantValue_node = get_identifier ("ConstantValue"); | |
2947 | i = find_utf8_constant (&state->cpool, ConstantValue_node); | |
2948 | PUT2 (i); /* attribute_name_index */ | |
2949 | PUT4 (2); /* attribute_length */ | |
df1e6be5 | 2950 | i = find_constant_index (init, state); PUT2 (i); |
23a7b8f5 | 2951 | } |
c6226a7e TT |
2952 | /* Emit the "Synthetic" attribute for val$<x> and this$<n> |
2953 | fields and other fields which need it. */ | |
2954 | if (FIELD_THISN (part) || FIELD_LOCAL_ALIAS (part) | |
2955 | || FIELD_SYNTHETIC (part)) | |
c2952b01 | 2956 | ptr = append_synthetic_attribute (state); |
f94ae540 TT |
2957 | if (FIELD_DEPRECATED (part)) |
2958 | append_deprecated_attribute (state); | |
e04a16fb AG |
2959 | fields_count++; |
2960 | } | |
ab150fb1 | 2961 | ptr = fields_count_ptr; UNSAFE_PUT2 (fields_count); |
e04a16fb | 2962 | |
e4de5a10 | 2963 | ptr = methods_count_ptr = append_chunk (NULL, 2, state); |
e04a16fb AG |
2964 | PUT2 (0); |
2965 | ||
2966 | for (part = TYPE_METHODS (clas); part; part = TREE_CHAIN (part)) | |
2967 | { | |
e4de5a10 | 2968 | struct jcf_block *block; |
9bbc7d9f PB |
2969 | tree function_body = DECL_FUNCTION_BODY (part); |
2970 | tree body = function_body == NULL_TREE ? NULL_TREE | |
2971 | : BLOCK_EXPR_BODY (function_body); | |
e4de5a10 PB |
2972 | tree name = DECL_CONSTRUCTOR_P (part) ? init_identifier_node |
2973 | : DECL_NAME (part); | |
2974 | tree type = TREE_TYPE (part); | |
63a212ed | 2975 | tree save_function = current_function_decl; |
c2952b01 | 2976 | int synthetic_p = 0; |
aecf4109 TT |
2977 | |
2978 | /* Invisible Miranda methods shouldn't end up in the .class | |
2979 | file. */ | |
2980 | if (METHOD_INVISIBLE (part)) | |
2981 | continue; | |
2982 | ||
63a212ed | 2983 | current_function_decl = part; |
e4de5a10 | 2984 | ptr = append_chunk (NULL, 8, state); |
e04a16fb | 2985 | i = get_access_flags (part); PUT2 (i); |
e4de5a10 PB |
2986 | i = find_utf8_constant (&state->cpool, name); PUT2 (i); |
2987 | i = find_utf8_constant (&state->cpool, build_java_signature (type)); | |
e04a16fb | 2988 | PUT2 (i); |
2d5a5193 | 2989 | i = (body != NULL_TREE) + (DECL_FUNCTION_THROWS (part) != NULL_TREE); |
c2952b01 APB |
2990 | |
2991 | /* Make room for the Synthetic attribute (of zero length.) */ | |
17126208 APB |
2992 | if (DECL_FINIT_P (part) |
2993 | || DECL_INSTINIT_P (part) | |
165f37bc APB |
2994 | || OUTER_FIELD_ACCESS_IDENTIFIER_P (DECL_NAME (part)) |
2995 | || TYPE_DOT_CLASS (clas) == part) | |
c2952b01 APB |
2996 | { |
2997 | i++; | |
2998 | synthetic_p = 1; | |
2999 | } | |
f94ae540 TT |
3000 | /* Make room for Deprecated attribute. */ |
3001 | if (METHOD_DEPRECATED (part)) | |
3002 | i++; | |
c2952b01 | 3003 | |
2d5a5193 | 3004 | PUT2 (i); /* attributes_count */ |
c2952b01 APB |
3005 | |
3006 | if (synthetic_p) | |
3007 | ptr = append_synthetic_attribute (state); | |
3008 | ||
e04a16fb AG |
3009 | if (body != NULL_TREE) |
3010 | { | |
3011 | int code_attributes_count = 0; | |
e04a16fb AG |
3012 | static tree Code_node = NULL_TREE; |
3013 | tree t; | |
3014 | char *attr_len_ptr; | |
3885dfa7 | 3015 | struct jcf_handler *handler; |
e04a16fb AG |
3016 | if (Code_node == NULL_TREE) |
3017 | Code_node = get_identifier ("Code"); | |
e4de5a10 PB |
3018 | ptr = append_chunk (NULL, 14, state); |
3019 | i = find_utf8_constant (&state->cpool, Code_node); PUT2 (i); | |
e04a16fb | 3020 | attr_len_ptr = ptr; |
e4de5a10 PB |
3021 | init_jcf_method (state, part); |
3022 | get_jcf_label_here (state); /* Force a first block. */ | |
e04a16fb | 3023 | for (t = DECL_ARGUMENTS (part); t != NULL_TREE; t = TREE_CHAIN (t)) |
e4de5a10 | 3024 | localvar_alloc (t, state); |
72f339d2 | 3025 | state->num_jsrs = 0; |
e4de5a10 | 3026 | generate_bytecode_insns (body, IGNORE_TARGET, state); |
3885dfa7 PB |
3027 | if (CAN_COMPLETE_NORMALLY (body)) |
3028 | { | |
3029 | if (TREE_CODE (TREE_TYPE (type)) != VOID_TYPE) | |
3030 | abort(); | |
3031 | RESERVE (1); | |
3032 | OP1 (OPCODE_return); | |
3033 | } | |
e04a16fb | 3034 | for (t = DECL_ARGUMENTS (part); t != NULL_TREE; t = TREE_CHAIN (t)) |
72f339d2 | 3035 | maybe_free_localvar (t, state, 1); |
45b44fbe | 3036 | if (state->return_value_decl != NULL_TREE) |
72f339d2 | 3037 | maybe_free_localvar (state->return_value_decl, state, 1); |
e4de5a10 PB |
3038 | finish_jcf_block (state); |
3039 | perform_relocations (state); | |
3040 | ||
e04a16fb | 3041 | ptr = attr_len_ptr; |
3885dfa7 | 3042 | i = 8 + state->code_length + 4 + 8 * state->num_handlers; |
e4de5a10 | 3043 | if (state->linenumber_count > 0) |
e04a16fb AG |
3044 | { |
3045 | code_attributes_count++; | |
e4de5a10 | 3046 | i += 8 + 4 * state->linenumber_count; |
e04a16fb | 3047 | } |
e4de5a10 | 3048 | if (state->lvar_count > 0) |
e04a16fb AG |
3049 | { |
3050 | code_attributes_count++; | |
e4de5a10 | 3051 | i += 8 + 10 * state->lvar_count; |
e04a16fb | 3052 | } |
ab150fb1 AG |
3053 | UNSAFE_PUT4 (i); /* attribute_length */ |
3054 | UNSAFE_PUT2 (state->code_SP_max); /* max_stack */ | |
3055 | UNSAFE_PUT2 (localvar_max); /* max_locals */ | |
3056 | UNSAFE_PUT4 (state->code_length); | |
3885dfa7 PB |
3057 | |
3058 | /* Emit the exception table. */ | |
3059 | ptr = append_chunk (NULL, 2 + 8 * state->num_handlers, state); | |
3060 | PUT2 (state->num_handlers); /* exception_table_length */ | |
3061 | handler = state->handlers; | |
3062 | for (; handler != NULL; handler = handler->next) | |
3063 | { | |
3064 | int type_index; | |
3065 | PUT2 (handler->start_label->pc); | |
3066 | PUT2 (handler->end_label->pc); | |
3067 | PUT2 (handler->handler_label->pc); | |
3068 | if (handler->type == NULL_TREE) | |
3069 | type_index = 0; | |
3070 | else | |
3071 | type_index = find_class_constant (&state->cpool, | |
3072 | handler->type); | |
3073 | PUT2 (type_index); | |
3074 | } | |
3075 | ||
3076 | ptr = append_chunk (NULL, 2, state); | |
e04a16fb AG |
3077 | PUT2 (code_attributes_count); |
3078 | ||
3079 | /* Write the LineNumberTable attribute. */ | |
e4de5a10 | 3080 | if (state->linenumber_count > 0) |
e04a16fb AG |
3081 | { |
3082 | static tree LineNumberTable_node = NULL_TREE; | |
c2952b01 APB |
3083 | ptr = append_chunk (NULL, |
3084 | 8 + 4 * state->linenumber_count, state); | |
e04a16fb AG |
3085 | if (LineNumberTable_node == NULL_TREE) |
3086 | LineNumberTable_node = get_identifier ("LineNumberTable"); | |
e4de5a10 | 3087 | i = find_utf8_constant (&state->cpool, LineNumberTable_node); |
e04a16fb | 3088 | PUT2 (i); /* attribute_name_index */ |
e4de5a10 PB |
3089 | i = 2+4*state->linenumber_count; PUT4(i); /* attribute_length */ |
3090 | i = state->linenumber_count; PUT2 (i); | |
3091 | for (block = state->blocks; block != NULL; block = block->next) | |
3092 | { | |
3093 | int line = block->linenumber; | |
3094 | if (line > 0) | |
3095 | { | |
3096 | PUT2 (block->pc); | |
3097 | PUT2 (line); | |
3098 | } | |
3099 | } | |
e04a16fb AG |
3100 | } |
3101 | ||
3102 | /* Write the LocalVariableTable attribute. */ | |
e4de5a10 | 3103 | if (state->lvar_count > 0) |
e04a16fb AG |
3104 | { |
3105 | static tree LocalVariableTable_node = NULL_TREE; | |
e4de5a10 PB |
3106 | struct localvar_info *lvar = state->first_lvar; |
3107 | ptr = append_chunk (NULL, 8 + 10 * state->lvar_count, state); | |
e04a16fb AG |
3108 | if (LocalVariableTable_node == NULL_TREE) |
3109 | LocalVariableTable_node = get_identifier("LocalVariableTable"); | |
e4de5a10 | 3110 | i = find_utf8_constant (&state->cpool, LocalVariableTable_node); |
e04a16fb | 3111 | PUT2 (i); /* attribute_name_index */ |
e4de5a10 PB |
3112 | i = 2 + 10 * state->lvar_count; PUT4 (i); /* attribute_length */ |
3113 | i = state->lvar_count; PUT2 (i); | |
3114 | for ( ; lvar != NULL; lvar = lvar->next) | |
3115 | { | |
3116 | tree name = DECL_NAME (lvar->decl); | |
3117 | tree sig = build_java_signature (TREE_TYPE (lvar->decl)); | |
3118 | i = lvar->start_label->pc; PUT2 (i); | |
3119 | i = lvar->end_label->pc - i; PUT2 (i); | |
3120 | i = find_utf8_constant (&state->cpool, name); PUT2 (i); | |
3121 | i = find_utf8_constant (&state->cpool, sig); PUT2 (i); | |
3122 | i = DECL_LOCAL_INDEX (lvar->decl); PUT2 (i); | |
3123 | } | |
e04a16fb AG |
3124 | } |
3125 | } | |
2d5a5193 PB |
3126 | if (DECL_FUNCTION_THROWS (part) != NULL_TREE) |
3127 | { | |
3128 | tree t = DECL_FUNCTION_THROWS (part); | |
3129 | int throws_count = list_length (t); | |
3130 | static tree Exceptions_node = NULL_TREE; | |
3131 | if (Exceptions_node == NULL_TREE) | |
3132 | Exceptions_node = get_identifier ("Exceptions"); | |
3133 | ptr = append_chunk (NULL, 8 + 2 * throws_count, state); | |
3134 | i = find_utf8_constant (&state->cpool, Exceptions_node); | |
3135 | PUT2 (i); /* attribute_name_index */ | |
3136 | i = 2 + 2 * throws_count; PUT4(i); /* attribute_length */ | |
3137 | i = throws_count; PUT2 (i); | |
3138 | for (; t != NULL_TREE; t = TREE_CHAIN (t)) | |
3139 | { | |
3140 | i = find_class_constant (&state->cpool, TREE_VALUE (t)); | |
3141 | PUT2 (i); | |
3142 | } | |
3143 | } | |
f94ae540 TT |
3144 | |
3145 | if (METHOD_DEPRECATED (part)) | |
3146 | append_deprecated_attribute (state); | |
3147 | ||
e04a16fb | 3148 | methods_count++; |
63a212ed | 3149 | current_function_decl = save_function; |
e04a16fb | 3150 | } |
ab150fb1 | 3151 | ptr = methods_count_ptr; UNSAFE_PUT2 (methods_count); |
e04a16fb | 3152 | |
f31686a3 | 3153 | source_file = DECL_SOURCE_FILE (TYPE_NAME (clas)); |
3b304f5b | 3154 | for (s = source_file; ; s++) |
e4de5a10 | 3155 | { |
062edaed | 3156 | char ch = *s; |
e4de5a10 PB |
3157 | if (ch == '\0') |
3158 | break; | |
3159 | if (ch == '/' || ch == '\\') | |
3b304f5b | 3160 | source_file = s+1; |
e4de5a10 PB |
3161 | } |
3162 | ptr = append_chunk (NULL, 10, state); | |
c2952b01 | 3163 | |
b124f72e APB |
3164 | i = 1; /* Source file always exists as an attribute */ |
3165 | if (INNER_CLASS_TYPE_P (clas) || DECL_INNER_CLASS_LIST (TYPE_NAME (clas))) | |
3166 | i++; | |
3167 | if (clas == object_type_node) | |
3168 | i++; | |
f94ae540 TT |
3169 | if (CLASS_DEPRECATED (TYPE_NAME (clas))) |
3170 | i++; | |
3171 | ||
49b973cb TT |
3172 | PUT2 (i); /* attributes_count */ |
3173 | ||
e4de5a10 PB |
3174 | /* generate the SourceFile attribute. */ |
3175 | if (SourceFile_node == NULL_TREE) | |
19e223db MM |
3176 | { |
3177 | SourceFile_node = get_identifier ("SourceFile"); | |
19e223db MM |
3178 | } |
3179 | ||
e4de5a10 PB |
3180 | i = find_utf8_constant (&state->cpool, SourceFile_node); |
3181 | PUT2 (i); /* attribute_name_index */ | |
3182 | PUT4 (2); | |
3183 | i = find_utf8_constant (&state->cpool, get_identifier (source_file)); | |
3184 | PUT2 (i); | |
b124f72e | 3185 | append_gcj_attribute (state, clas); |
c2952b01 | 3186 | append_innerclasses_attribute (state, clas); |
f94ae540 TT |
3187 | if (CLASS_DEPRECATED (TYPE_NAME (clas))) |
3188 | append_deprecated_attribute (state); | |
e04a16fb AG |
3189 | |
3190 | /* New finally generate the contents of the constant pool chunk. */ | |
e4de5a10 PB |
3191 | i = count_constant_pool_bytes (&state->cpool); |
3192 | ptr = obstack_alloc (state->chunk_obstack, i); | |
e04a16fb AG |
3193 | cpool_chunk->data = ptr; |
3194 | cpool_chunk->size = i; | |
e4de5a10 PB |
3195 | write_constant_pool (&state->cpool, ptr, i); |
3196 | return state->first; | |
e04a16fb AG |
3197 | } |
3198 | ||
e2500fed | 3199 | static GTY(()) tree Synthetic_node; |
c2952b01 | 3200 | static unsigned char * |
0a2f0c54 | 3201 | append_synthetic_attribute (struct jcf_partial *state) |
c2952b01 | 3202 | { |
c2952b01 APB |
3203 | unsigned char *ptr = append_chunk (NULL, 6, state); |
3204 | int i; | |
3205 | ||
3206 | if (Synthetic_node == NULL_TREE) | |
19e223db MM |
3207 | { |
3208 | Synthetic_node = get_identifier ("Synthetic"); | |
19e223db | 3209 | } |
c2952b01 APB |
3210 | i = find_utf8_constant (&state->cpool, Synthetic_node); |
3211 | PUT2 (i); /* Attribute string index */ | |
3212 | PUT4 (0); /* Attribute length */ | |
3213 | ||
3214 | return ptr; | |
3215 | } | |
3216 | ||
f94ae540 TT |
3217 | static void |
3218 | append_deprecated_attribute (struct jcf_partial *state) | |
3219 | { | |
3220 | unsigned char *ptr = append_chunk (NULL, 6, state); | |
3221 | int i; | |
3222 | ||
3223 | i = find_utf8_constant (&state->cpool, get_identifier ("Deprecated")); | |
3224 | PUT2 (i); /* Attribute string index */ | |
3225 | PUT4 (0); /* Attribute length */ | |
3226 | } | |
3227 | ||
b124f72e | 3228 | static void |
0a2f0c54 | 3229 | append_gcj_attribute (struct jcf_partial *state, tree class) |
b124f72e APB |
3230 | { |
3231 | unsigned char *ptr; | |
3232 | int i; | |
3233 | ||
3234 | if (class != object_type_node) | |
3235 | return; | |
3236 | ||
3237 | ptr = append_chunk (NULL, 6, state); /* 2+4 */ | |
3238 | i = find_utf8_constant (&state->cpool, | |
3239 | get_identifier ("gnu.gcj.gcj-compiled")); | |
3240 | PUT2 (i); /* Attribute string index */ | |
3241 | PUT4 (0); /* Attribute length */ | |
3242 | } | |
3243 | ||
e2500fed | 3244 | static tree InnerClasses_node; |
c2952b01 | 3245 | static void |
0a2f0c54 | 3246 | append_innerclasses_attribute (struct jcf_partial *state, tree class) |
c2952b01 | 3247 | { |
c2952b01 APB |
3248 | tree orig_decl = TYPE_NAME (class); |
3249 | tree current, decl; | |
3250 | int length = 0, i; | |
3251 | unsigned char *ptr, *length_marker, *number_marker; | |
3252 | ||
3253 | if (!INNER_CLASS_TYPE_P (class) && !DECL_INNER_CLASS_LIST (orig_decl)) | |
3254 | return; | |
3255 | ||
3256 | ptr = append_chunk (NULL, 8, state); /* 2+4+2 */ | |
3257 | ||
19e223db MM |
3258 | if (InnerClasses_node == NULL_TREE) |
3259 | { | |
3260 | InnerClasses_node = get_identifier ("InnerClasses"); | |
19e223db | 3261 | } |
c2952b01 APB |
3262 | i = find_utf8_constant (&state->cpool, InnerClasses_node); |
3263 | PUT2 (i); | |
3264 | length_marker = ptr; PUT4 (0); /* length, to be later patched */ | |
3265 | number_marker = ptr; PUT2 (0); /* number of classes, tblp */ | |
3266 | ||
3267 | /* Generate the entries: all inner classes visible from the one we | |
3268 | process: itself, up and down. */ | |
3269 | while (class && INNER_CLASS_TYPE_P (class)) | |
3270 | { | |
63ad61ed | 3271 | const char *n; |
c2952b01 APB |
3272 | |
3273 | decl = TYPE_NAME (class); | |
3274 | n = IDENTIFIER_POINTER (DECL_NAME (decl)) + | |
3275 | IDENTIFIER_LENGTH (DECL_NAME (decl)); | |
3276 | ||
3277 | while (n[-1] != '$') | |
3278 | n--; | |
3279 | append_innerclasses_attribute_entry (state, decl, get_identifier (n)); | |
3280 | length++; | |
3281 | ||
3282 | class = TREE_TYPE (DECL_CONTEXT (TYPE_NAME (class))); | |
3283 | } | |
3284 | ||
3285 | decl = orig_decl; | |
3286 | for (current = DECL_INNER_CLASS_LIST (decl); | |
3287 | current; current = TREE_CHAIN (current)) | |
3288 | { | |
3289 | append_innerclasses_attribute_entry (state, TREE_PURPOSE (current), | |
3290 | TREE_VALUE (current)); | |
3291 | length++; | |
3292 | } | |
3293 | ||
3294 | ptr = length_marker; PUT4 (8*length+2); | |
3295 | ptr = number_marker; PUT2 (length); | |
3296 | } | |
3297 | ||
3298 | static void | |
0a2f0c54 KG |
3299 | append_innerclasses_attribute_entry (struct jcf_partial *state, |
3300 | tree decl, tree name) | |
c2952b01 | 3301 | { |
493d561d APB |
3302 | int icii, icaf; |
3303 | int ocii = 0, ini = 0; | |
c2952b01 APB |
3304 | unsigned char *ptr = append_chunk (NULL, 8, state); |
3305 | ||
493d561d APB |
3306 | icii = find_class_constant (&state->cpool, TREE_TYPE (decl)); |
3307 | ||
3308 | /* Sun's implementation seems to generate ocii to 0 for inner | |
3309 | classes (which aren't considered members of the class they're | |
3310 | in.) The specs are saying that if the class is anonymous, | |
3311 | inner_name_index must be zero. */ | |
3312 | if (!ANONYMOUS_CLASS_P (TREE_TYPE (decl))) | |
19e223db | 3313 | { |
493d561d APB |
3314 | ocii = find_class_constant (&state->cpool, |
3315 | TREE_TYPE (DECL_CONTEXT (decl))); | |
3316 | ini = find_utf8_constant (&state->cpool, name); | |
19e223db | 3317 | } |
c2952b01 | 3318 | icaf = get_access_flags (decl); |
493d561d | 3319 | |
c2952b01 APB |
3320 | PUT2 (icii); PUT2 (ocii); PUT2 (ini); PUT2 (icaf); |
3321 | } | |
3322 | ||
df66b566 | 3323 | static char * |
0a2f0c54 | 3324 | make_class_file_name (tree clas) |
e04a16fb | 3325 | { |
63ad61ed ZW |
3326 | const char *dname, *cname, *slash; |
3327 | char *r; | |
df66b566 | 3328 | struct stat sb; |
630287af | 3329 | char sep; |
df66b566 TT |
3330 | |
3331 | cname = IDENTIFIER_POINTER (identifier_subst (DECL_NAME (TYPE_NAME (clas)), | |
3332 | "", '.', DIR_SEPARATOR, | |
3333 | ".class")); | |
3334 | if (jcf_write_base_directory == NULL) | |
3335 | { | |
3336 | /* Make sure we put the class file into the .java file's | |
3337 | directory, and not into some subdirectory thereof. */ | |
3338 | char *t; | |
f31686a3 | 3339 | dname = DECL_SOURCE_FILE (TYPE_NAME (clas)); |
df66b566 | 3340 | slash = strrchr (dname, DIR_SEPARATOR); |
630287af | 3341 | #ifdef DIR_SEPARATOR_2 |
df66b566 | 3342 | if (! slash) |
630287af RM |
3343 | slash = strrchr (dname, DIR_SEPARATOR_2); |
3344 | #endif | |
3345 | if (! slash) | |
3346 | { | |
3347 | dname = "."; | |
3348 | slash = dname + 1; | |
3349 | sep = DIR_SEPARATOR; | |
3350 | } | |
3351 | else | |
3352 | sep = *slash; | |
3353 | ||
df66b566 TT |
3354 | t = strrchr (cname, DIR_SEPARATOR); |
3355 | if (t) | |
3356 | cname = t + 1; | |
3357 | } | |
3358 | else | |
3359 | { | |
630287af RM |
3360 | char *s; |
3361 | ||
df66b566 | 3362 | dname = jcf_write_base_directory; |
630287af RM |
3363 | |
3364 | s = strrchr (dname, DIR_SEPARATOR); | |
3365 | #ifdef DIR_SEPARATOR_2 | |
3366 | if (! s) | |
3367 | s = strrchr (dname, DIR_SEPARATOR_2); | |
3368 | #endif | |
3369 | if (s) | |
3370 | sep = *s; | |
3371 | else | |
3372 | sep = DIR_SEPARATOR; | |
3373 | ||
df66b566 TT |
3374 | slash = dname + strlen (dname); |
3375 | } | |
3376 | ||
3377 | r = xmalloc (slash - dname + strlen (cname) + 2); | |
3378 | strncpy (r, dname, slash - dname); | |
630287af | 3379 | r[slash - dname] = sep; |
df66b566 TT |
3380 | strcpy (&r[slash - dname + 1], cname); |
3381 | ||
3382 | /* We try to make new directories when we need them. We only do | |
3383 | this for directories which "might not" exist. For instance, we | |
3384 | assume the `-d' directory exists, but we don't assume that any | |
3385 | subdirectory below it exists. It might be worthwhile to keep | |
3386 | track of which directories we've created to avoid gratuitous | |
3387 | stat()s. */ | |
3388 | dname = r + (slash - dname) + 1; | |
3389 | while (1) | |
3390 | { | |
630287af | 3391 | char *s = strchr (dname, sep); |
63ad61ed | 3392 | if (s == NULL) |
df66b566 | 3393 | break; |
63ad61ed | 3394 | *s = '\0'; |
986dc4e5 | 3395 | /* Try to make directory if it doesn't already exist. */ |
400500c4 | 3396 | if (stat (r, &sb) == -1 |
986dc4e5 TT |
3397 | && mkdir (r, 0755) == -1 |
3398 | /* The directory might have been made by another process. */ | |
3399 | && errno != EEXIST) | |
fa6ef813 | 3400 | fatal_error ("can't create directory %s: %m", r); |
400500c4 | 3401 | |
630287af | 3402 | *s = sep; |
df66b566 | 3403 | /* Skip consecutive separators. */ |
630287af | 3404 | for (dname = s + 1; *dname && *dname == sep; ++dname) |
df66b566 TT |
3405 | ; |
3406 | } | |
3407 | ||
3408 | return r; | |
e04a16fb AG |
3409 | } |
3410 | ||
634661fe | 3411 | /* Write out the contents of a class (RECORD_TYPE) CLAS, as a .class file. |
e04a16fb AG |
3412 | The output .class file name is make_class_file_name(CLAS). */ |
3413 | ||
3414 | void | |
0a2f0c54 | 3415 | write_classfile (tree clas) |
e04a16fb AG |
3416 | { |
3417 | struct obstack *work = &temporary_obstack; | |
e4de5a10 | 3418 | struct jcf_partial state[1]; |
e04a16fb AG |
3419 | char *class_file_name = make_class_file_name (clas); |
3420 | struct chunk *chunks; | |
df66b566 TT |
3421 | |
3422 | if (class_file_name != NULL) | |
3423 | { | |
281524f4 MM |
3424 | FILE *stream; |
3425 | char *temporary_file_name; | |
3426 | ||
3427 | /* The .class file is initially written to a ".tmp" file so that | |
3428 | if multiple instances of the compiler are running at once | |
3429 | they do not see partially formed class files. */ | |
2f9a2cd7 | 3430 | temporary_file_name = concat (class_file_name, ".tmp", NULL); |
281524f4 | 3431 | stream = fopen (temporary_file_name, "wb"); |
df66b566 | 3432 | if (stream == NULL) |
fa6ef813 | 3433 | fatal_error ("can't open %s for writing: %m", temporary_file_name); |
400500c4 | 3434 | |
df66b566 TT |
3435 | jcf_dependency_add_target (class_file_name); |
3436 | init_jcf_state (state, work); | |
3437 | chunks = generate_classfile (clas, state); | |
3438 | write_chunks (stream, chunks); | |
3439 | if (fclose (stream)) | |
fa6ef813 | 3440 | fatal_error ("error closing %s: %m", temporary_file_name); |
34744d4e RM |
3441 | |
3442 | /* If a file named by the string pointed to by `new' exists | |
ed2f11fa | 3443 | prior to the call to the `rename' function, the behavior |
34744d4e RM |
3444 | is implementation-defined. ISO 9899-1990 7.9.4.2. |
3445 | ||
3446 | For example, on Win32 with MSVCRT, it is an error. */ | |
3447 | ||
3448 | unlink (class_file_name); | |
3449 | ||
281524f4 | 3450 | if (rename (temporary_file_name, class_file_name) == -1) |
2f9a2cd7 MM |
3451 | { |
3452 | remove (temporary_file_name); | |
fa6ef813 | 3453 | fatal_error ("can't create %s: %m", class_file_name); |
2f9a2cd7 | 3454 | } |
281524f4 | 3455 | free (temporary_file_name); |
df66b566 TT |
3456 | free (class_file_name); |
3457 | } | |
e4de5a10 | 3458 | release_jcf_state (state); |
e04a16fb | 3459 | } |
3885dfa7 PB |
3460 | |
3461 | /* TODO: | |
3462 | string concatenation | |
3463 | synchronized statement | |
3464 | */ | |
e2500fed GK |
3465 | |
3466 | #include "gt-java-jcf-write.h" |