]>
Commit | Line | Data |
---|---|---|
e04a16fb | 1 | /* Parser for Java(TM) .class files. |
df32d2ce | 2 | Copyright (C) 1996, 1998, 1999, 2000 Free Software Foundation, Inc. |
e04a16fb AG |
3 | |
4 | This file is part of GNU CC. | |
5 | ||
6 | GNU CC is free software; you can redistribute it and/or modify | |
7 | it under the terms of the GNU General Public License as published by | |
8 | the Free Software Foundation; either version 2, or (at your option) | |
9 | any later version. | |
10 | ||
11 | GNU CC is distributed in the hope that it will be useful, | |
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | GNU General Public License for more details. | |
15 | ||
16 | You should have received a copy of the GNU General Public License | |
17 | along with GNU CC; see the file COPYING. If not, write to | |
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 | /* Written by Per Bothner <bothner@cygnus.com> */ | |
26 | ||
e04a16fb | 27 | #include "config.h" |
1f43f4b4 | 28 | #include "system.h" |
e04a16fb AG |
29 | #include "tree.h" |
30 | #include "obstack.h" | |
31 | #include "flags.h" | |
32 | #include "java-except.h" | |
33 | #include "input.h" | |
34 | #include "java-tree.h" | |
d4476be2 | 35 | #include "toplev.h" |
8e1f2d4c | 36 | #include "parse.h" |
e04a16fb AG |
37 | |
38 | /* A CONSTANT_Utf8 element is converted to an IDENTIFIER_NODE at parse time. */ | |
39 | #define JPOOL_UTF(JCF, INDEX) CPOOL_UTF(&(JCF)->cpool, INDEX) | |
40 | #define JPOOL_UTF_LENGTH(JCF, INDEX) IDENTIFIER_LENGTH (JPOOL_UTF (JCF, INDEX)) | |
41 | #define JPOOL_UTF_DATA(JCF, INDEX) \ | |
c8e7d2e6 | 42 | ((const unsigned char *) IDENTIFIER_POINTER (JPOOL_UTF (JCF, INDEX))) |
e04a16fb AG |
43 | #define HANDLE_CONSTANT_Utf8(JCF, INDEX, LENGTH) \ |
44 | do { \ | |
45 | unsigned char save; unsigned char *text; \ | |
46 | JCF_FILL (JCF, (LENGTH)+1); /* Make sure we read 1 byte beyond string. */ \ | |
47 | text = (JCF)->read_ptr; \ | |
48 | save = text[LENGTH]; \ | |
49 | text[LENGTH] = 0; \ | |
50 | (JCF)->cpool.data[INDEX] = (jword) get_identifier (text); \ | |
51 | text[LENGTH] = save; \ | |
52 | JCF_SKIP (JCF, LENGTH); } while (0) | |
53 | ||
54 | #include "jcf.h" | |
e04a16fb AG |
55 | |
56 | extern struct obstack *saveable_obstack; | |
57 | extern struct obstack temporary_obstack; | |
58 | extern struct obstack permanent_obstack; | |
59 | ||
60 | /* The class we are currently processing. */ | |
61 | tree current_class = NULL_TREE; | |
62 | ||
63 | /* The class we started with. */ | |
64 | tree main_class = NULL_TREE; | |
65 | ||
23a79c61 APB |
66 | /* List of all class DECL seen so far. */ |
67 | tree all_class_list = NULL_TREE; | |
68 | ||
69 | /* The FIELD_DECL for the current field. */ | |
e04a16fb AG |
70 | static tree current_field = NULL_TREE; |
71 | ||
5e942c50 | 72 | /* The METHOD_DECL for the current method. */ |
e04a16fb AG |
73 | static tree current_method = NULL_TREE; |
74 | ||
4f65832d KG |
75 | /* The Java .class file that provides main_class; the main input file. */ |
76 | static struct JCF main_jcf[1]; | |
77 | ||
5e942c50 | 78 | /* Declarations of some functions used here. */ |
df32d2ce KG |
79 | static tree give_name_to_class PARAMS ((JCF *jcf, int index)); |
80 | static void parse_zip_file_entries PARAMS ((void)); | |
81 | static void process_zip_dir PARAMS ((void)); | |
82 | static void parse_source_file PARAMS ((tree)); | |
83 | static void jcf_parse_source PARAMS ((void)); | |
84 | static int jcf_figure_file_type PARAMS ((JCF *)); | |
85 | static int find_in_current_zip PARAMS ((const char *, struct JCF **)); | |
86 | static void parse_class_file PARAMS ((void)); | |
87 | static void set_source_filename PARAMS ((JCF *, int)); | |
88 | static int predefined_filename_p PARAMS ((tree)); | |
e04a16fb AG |
89 | |
90 | /* Handle "SourceFile" attribute. */ | |
91 | ||
c8e7d2e6 | 92 | static void |
e04a16fb AG |
93 | set_source_filename (jcf, index) |
94 | JCF *jcf; | |
95 | int index; | |
96 | { | |
97 | tree sfname_id = get_name_constant (jcf, index); | |
98 | char *sfname = IDENTIFIER_POINTER (sfname_id); | |
99 | if (input_filename != NULL) | |
100 | { | |
101 | int old_len = strlen (input_filename); | |
102 | int new_len = IDENTIFIER_LENGTH (sfname_id); | |
103 | /* Use the current input_filename (derived from the class name) | |
104 | if it has a directory prefix, but otherwise matches sfname. */ | |
105 | if (old_len > new_len | |
106 | && strcmp (sfname, input_filename + old_len - new_len) == 0 | |
107 | && (input_filename[old_len - new_len - 1] == '/' | |
108 | || input_filename[old_len - new_len - 1] == '\\')) | |
109 | return; | |
110 | } | |
111 | input_filename = sfname; | |
112 | DECL_SOURCE_FILE (TYPE_NAME (current_class)) = sfname; | |
113 | if (current_class == main_class) main_input_filename = input_filename; | |
114 | } | |
115 | ||
116 | #define HANDLE_SOURCEFILE(INDEX) set_source_filename (jcf, INDEX) | |
117 | ||
118 | #define HANDLE_CLASS_INFO(ACCESS_FLAGS, THIS, SUPER, INTERFACES_COUNT) \ | |
119 | { tree super_class = SUPER==0 ? NULL_TREE : get_class_constant (jcf, SUPER); \ | |
120 | current_class = give_name_to_class (jcf, THIS); \ | |
121 | set_super_info (ACCESS_FLAGS, current_class, super_class, INTERFACES_COUNT);} | |
122 | ||
123 | #define HANDLE_CLASS_INTERFACE(INDEX) \ | |
124 | add_interface (current_class, get_class_constant (jcf, INDEX)) | |
125 | ||
126 | #define HANDLE_START_FIELD(ACCESS_FLAGS, NAME, SIGNATURE, ATTRIBUTE_COUNT) \ | |
127 | { int sig_index = SIGNATURE; \ | |
128 | current_field = add_field (current_class, get_name_constant (jcf, NAME), \ | |
129 | parse_signature (jcf, sig_index), ACCESS_FLAGS); \ | |
130 | set_java_signature (TREE_TYPE (current_field), JPOOL_UTF (jcf, sig_index)); } | |
131 | ||
132 | #define HANDLE_END_FIELDS() \ | |
133 | (current_field = NULL_TREE) | |
134 | ||
135 | #define HANDLE_CONSTANTVALUE(INDEX) \ | |
136 | { tree constant; int index = INDEX; \ | |
f868ca8f | 137 | if (! flag_emit_class_files && JPOOL_TAG (jcf, index) == CONSTANT_String) { \ |
e04a16fb AG |
138 | tree name = get_name_constant (jcf, JPOOL_USHORT1 (jcf, index)); \ |
139 | constant = build_utf8_ref (name); \ | |
140 | } \ | |
141 | else \ | |
142 | constant = get_constant (jcf, index); \ | |
143 | set_constant_value (current_field, constant); } | |
144 | ||
145 | #define HANDLE_METHOD(ACCESS_FLAGS, NAME, SIGNATURE, ATTRIBUTE_COUNT) \ | |
146 | (current_method = add_method (current_class, ACCESS_FLAGS, \ | |
147 | get_name_constant (jcf, NAME), \ | |
148 | get_name_constant (jcf, SIGNATURE)), \ | |
149 | DECL_LOCALVARIABLES_OFFSET (current_method) = 0, \ | |
150 | DECL_LINENUMBERS_OFFSET (current_method) = 0) | |
151 | ||
152 | #define HANDLE_END_METHODS() \ | |
153 | { tree handle_type = CLASS_TO_HANDLE_TYPE (current_class); \ | |
154 | if (handle_type != current_class) layout_type (handle_type); } | |
155 | ||
156 | #define HANDLE_CODE_ATTRIBUTE(MAX_STACK, MAX_LOCALS, CODE_LENGTH) \ | |
157 | { DECL_MAX_STACK (current_method) = (MAX_STACK); \ | |
158 | DECL_MAX_LOCALS (current_method) = (MAX_LOCALS); \ | |
159 | DECL_CODE_LENGTH (current_method) = (CODE_LENGTH); \ | |
160 | DECL_CODE_OFFSET (current_method) = JCF_TELL (jcf); } | |
161 | ||
162 | #define HANDLE_LOCALVARIABLETABLE_ATTRIBUTE(COUNT) \ | |
163 | { int n = (COUNT); \ | |
164 | DECL_LOCALVARIABLES_OFFSET (current_method) = JCF_TELL (jcf) - 2; \ | |
165 | JCF_SKIP (jcf, n * 10); } | |
166 | ||
167 | #define HANDLE_LINENUMBERTABLE_ATTRIBUTE(COUNT) \ | |
168 | { int n = (COUNT); \ | |
169 | DECL_LINENUMBERS_OFFSET (current_method) = JCF_TELL (jcf) - 2; \ | |
170 | JCF_SKIP (jcf, n * 4); } | |
171 | ||
0ef38928 PB |
172 | #define HANDLE_EXCEPTIONS_ATTRIBUTE(COUNT) \ |
173 | { \ | |
174 | int n = COUNT; \ | |
175 | tree list = DECL_FUNCTION_THROWS (current_method); \ | |
176 | while (--n >= 0) \ | |
177 | { \ | |
178 | tree thrown_class = get_class_constant (jcf, JCF_readu2 (jcf)); \ | |
179 | list = tree_cons (NULL_TREE, thrown_class, list); \ | |
180 | } \ | |
181 | DECL_FUNCTION_THROWS (current_method) = nreverse (list); \ | |
182 | } | |
183 | ||
e04a16fb AG |
184 | #include "jcf-reader.c" |
185 | ||
186 | static int yydebug; | |
187 | ||
188 | tree | |
189 | parse_signature (jcf, sig_index) | |
190 | JCF *jcf; | |
191 | int sig_index; | |
192 | { | |
193 | if (sig_index <= 0 || sig_index >= JPOOL_SIZE(jcf) | |
194 | || JPOOL_TAG (jcf, sig_index) != CONSTANT_Utf8) | |
195 | fatal ("invalid field/method signature"); | |
196 | else | |
197 | { | |
198 | return parse_signature_string (JPOOL_UTF_DATA (jcf, sig_index), | |
199 | JPOOL_UTF_LENGTH (jcf, sig_index)); | |
200 | } | |
201 | } | |
202 | ||
203 | void | |
204 | init_lex () | |
205 | { | |
206 | /* Make identifier nodes long enough for the language-specific slots. */ | |
207 | set_identifier_size (sizeof (struct lang_identifier)); | |
208 | } | |
209 | ||
210 | void | |
211 | set_yydebug (value) | |
212 | int value; | |
213 | { | |
214 | yydebug = value; | |
215 | } | |
216 | ||
217 | tree | |
218 | get_constant (jcf, index) | |
219 | JCF *jcf; | |
220 | int index; | |
221 | { | |
222 | tree value; | |
223 | int tag; | |
224 | if (index <= 0 || index >= JPOOL_SIZE(jcf)) | |
225 | goto bad; | |
226 | tag = JPOOL_TAG (jcf, index); | |
227 | if ((tag & CONSTANT_ResolvedFlag) || tag == CONSTANT_Utf8) | |
228 | return (tree) jcf->cpool.data[index]; | |
229 | push_obstacks (&permanent_obstack, &permanent_obstack); | |
230 | switch (tag) | |
231 | { | |
232 | case CONSTANT_Integer: | |
233 | { | |
234 | jint num = JPOOL_INT(jcf, index); | |
235 | value = build_int_2 (num, num < 0 ? -1 : 0); | |
236 | TREE_TYPE (value) = int_type_node; | |
237 | break; | |
238 | } | |
239 | case CONSTANT_Long: | |
240 | { | |
241 | jint num = JPOOL_INT (jcf, index); | |
242 | HOST_WIDE_INT lo, hi; | |
243 | lshift_double (num, 0, 32, 64, &lo, &hi, 0); | |
244 | num = JPOOL_INT (jcf, index+1); | |
245 | add_double (lo, hi, num, 0, &lo, &hi); | |
246 | value = build_int_2 (lo, hi); | |
247 | TREE_TYPE (value) = long_type_node; | |
248 | force_fit_type (value, 0); | |
249 | break; | |
250 | } | |
251 | #if TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT | |
252 | case CONSTANT_Float: | |
253 | { | |
254 | jint num = JPOOL_INT(jcf, index); | |
255 | REAL_VALUE_TYPE d; | |
256 | #ifdef REAL_ARITHMETIC | |
257 | d = REAL_VALUE_FROM_TARGET_SINGLE (num); | |
258 | #else | |
259 | union { float f; jint i; } u; | |
260 | u.i = num; | |
261 | d = u.f; | |
262 | #endif | |
263 | value = build_real (float_type_node, d); | |
264 | break; | |
265 | } | |
266 | case CONSTANT_Double: | |
267 | { | |
268 | HOST_WIDE_INT num[2]; | |
269 | REAL_VALUE_TYPE d; | |
270 | HOST_WIDE_INT lo, hi; | |
271 | num[0] = JPOOL_INT (jcf, index); | |
272 | lshift_double (num[0], 0, 32, 64, &lo, &hi, 0); | |
273 | num[0] = JPOOL_INT (jcf, index+1); | |
274 | add_double (lo, hi, num[0], 0, &lo, &hi); | |
275 | if (FLOAT_WORDS_BIG_ENDIAN) | |
276 | { | |
277 | num[0] = hi; | |
278 | num[1] = lo; | |
279 | } | |
280 | else | |
281 | { | |
282 | num[0] = lo; | |
283 | num[1] = hi; | |
284 | } | |
285 | #ifdef REAL_ARITHMETIC | |
286 | d = REAL_VALUE_FROM_TARGET_DOUBLE (num); | |
287 | #else | |
2fe47729 AH |
288 | { |
289 | union { double d; jint i[2]; } u; | |
290 | u.i[0] = (jint) num[0]; | |
291 | u.i[1] = (jint) num[1]; | |
292 | d = u.d; | |
293 | } | |
e04a16fb AG |
294 | #endif |
295 | value = build_real (double_type_node, d); | |
296 | break; | |
297 | } | |
298 | #endif /* TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT */ | |
299 | case CONSTANT_String: | |
300 | { | |
301 | extern struct obstack *expression_obstack; | |
302 | tree name = get_name_constant (jcf, JPOOL_USHORT1 (jcf, index)); | |
c8e7d2e6 | 303 | const char *utf8_ptr = IDENTIFIER_POINTER (name); |
e04a16fb AG |
304 | unsigned char *str_ptr; |
305 | int utf8_len = IDENTIFIER_LENGTH (name); | |
c8e7d2e6 | 306 | const unsigned char *str = (const unsigned char *)utf8_ptr; |
e04a16fb AG |
307 | int i = utf8_len; |
308 | int str_len; | |
309 | ||
310 | /* Count the number of Unicode characters in the string, | |
311 | while checking for a malformed Utf8 string. */ | |
312 | for (str_len = 0; i > 0; str_len++) | |
313 | { | |
314 | int char_len = UT8_CHAR_LENGTH (*str); | |
315 | if (char_len < 0 || char_len > 2 || char_len > i) | |
316 | fatal ("bad string constant"); | |
317 | str += char_len; | |
318 | i -= char_len; | |
319 | } | |
320 | ||
321 | value = make_node (STRING_CST); | |
f868ca8f | 322 | TREE_TYPE (value) = build_pointer_type (string_type_node); |
e04a16fb AG |
323 | TREE_STRING_LENGTH (value) = 2 * str_len; |
324 | TREE_STRING_POINTER (value) | |
325 | = obstack_alloc (expression_obstack, 2 * str_len); | |
326 | str_ptr = (unsigned char *) TREE_STRING_POINTER (value); | |
c8e7d2e6 | 327 | str = (const unsigned char *)utf8_ptr; |
e04a16fb AG |
328 | for (i = 0; i < str_len; i++) |
329 | { | |
330 | int char_value; | |
331 | int char_len = UT8_CHAR_LENGTH (*str); | |
332 | switch (char_len) | |
333 | { | |
334 | case 1: | |
335 | char_value = *str++; | |
336 | break; | |
337 | case 2: | |
338 | char_value = *str++ & 0x1F; | |
339 | char_value = (char_value << 6) | (*str++ & 0x3F); | |
340 | break; | |
341 | case 3: | |
342 | char_value = *str_ptr++ & 0x0F; | |
343 | char_value = (char_value << 6) | (*str++ & 0x3F); | |
344 | char_value = (char_value << 6) | (*str++ & 0x3F); | |
345 | break; | |
346 | default: | |
347 | goto bad; | |
348 | } | |
349 | if (BYTES_BIG_ENDIAN) | |
350 | { | |
351 | *str_ptr++ = char_value >> 8; | |
352 | *str_ptr++ = char_value & 0xFF; | |
353 | } | |
354 | else | |
355 | { | |
356 | *str_ptr++ = char_value & 0xFF; | |
357 | *str_ptr++ = char_value >> 8; | |
358 | } | |
359 | } | |
360 | } | |
361 | break; | |
362 | default: | |
363 | goto bad; | |
364 | } | |
365 | pop_obstacks (); | |
366 | JPOOL_TAG(jcf, index) = tag | CONSTANT_ResolvedFlag; | |
367 | jcf->cpool.data [index] = (jword) value; | |
368 | return value; | |
369 | bad: | |
370 | fatal ("bad value constant type %d, index %d", | |
371 | JPOOL_TAG( jcf, index ), index); | |
372 | } | |
373 | ||
374 | tree | |
375 | get_name_constant (jcf, index) | |
376 | JCF *jcf; | |
377 | int index; | |
378 | { | |
379 | tree name = get_constant (jcf, index); | |
380 | if (TREE_CODE (name) != IDENTIFIER_NODE) | |
381 | fatal ("bad nameandtype index %d", index); | |
382 | return name; | |
383 | } | |
384 | ||
385 | static tree | |
386 | give_name_to_class (jcf, i) | |
387 | JCF *jcf; | |
388 | int i; | |
389 | { | |
390 | if (i <= 0 || i >= JPOOL_SIZE(jcf) | |
391 | || JPOOL_TAG (jcf, i) != CONSTANT_Class) | |
392 | fatal ("bad class index %d", i); | |
393 | else | |
394 | { | |
395 | tree this_class; | |
396 | int j = JPOOL_USHORT1 (jcf, i); | |
397 | /* verify_constant_pool confirmed that j is a CONSTANT_Utf8. */ | |
398 | tree class_name = unmangle_classname (JPOOL_UTF_DATA (jcf, j), | |
399 | JPOOL_UTF_LENGTH (jcf, j)); | |
400 | this_class = lookup_class (class_name); | |
401 | input_filename = DECL_SOURCE_FILE (TYPE_NAME (this_class)); | |
402 | lineno = 0; | |
403 | if (main_input_filename == NULL && jcf == main_jcf) | |
404 | main_input_filename = input_filename; | |
405 | ||
406 | jcf->cpool.data[i] = (jword) this_class; | |
407 | JPOOL_TAG (jcf, i) = CONSTANT_ResolvedClass; | |
408 | return this_class; | |
409 | } | |
410 | } | |
411 | ||
412 | /* Get the class of the CONSTANT_Class whose constant pool index is I. */ | |
413 | ||
414 | tree | |
415 | get_class_constant (JCF *jcf , int i) | |
416 | { | |
417 | tree type; | |
418 | if (i <= 0 || i >= JPOOL_SIZE(jcf) | |
419 | || (JPOOL_TAG (jcf, i) & ~CONSTANT_ResolvedFlag) != CONSTANT_Class) | |
420 | fatal ("bad class index %d", i); | |
421 | ||
422 | if (JPOOL_TAG (jcf, i) != CONSTANT_ResolvedClass) | |
423 | { | |
424 | int name_index = JPOOL_USHORT1 (jcf, i); | |
425 | /* verify_constant_pool confirmed that name_index is a CONSTANT_Utf8. */ | |
c8e7d2e6 | 426 | const char *name = JPOOL_UTF_DATA (jcf, name_index); |
e04a16fb AG |
427 | int nlength = JPOOL_UTF_LENGTH (jcf, name_index); |
428 | if (name[0] == '[') /* Handle array "classes". */ | |
e4de5a10 | 429 | type = TREE_TYPE (parse_signature_string (name, nlength)); |
e04a16fb AG |
430 | else |
431 | { | |
432 | tree cname = unmangle_classname (name, nlength); | |
433 | type = lookup_class (cname); | |
434 | } | |
435 | jcf->cpool.data[i] = (jword) type; | |
436 | JPOOL_TAG (jcf, i) = CONSTANT_ResolvedClass; | |
437 | } | |
438 | else | |
439 | type = (tree) jcf->cpool.data[i]; | |
440 | return type; | |
441 | } | |
442 | ||
bc3ca41b PB |
443 | /* Read a class with the fully qualified-name NAME. |
444 | Return 1 iff we read the requested file. | |
445 | (It is still possible we failed if the file did not | |
446 | define the class it is supposed to.) */ | |
447 | ||
448 | int | |
449 | read_class (name) | |
450 | tree name; | |
e04a16fb AG |
451 | { |
452 | JCF this_jcf, *jcf; | |
e04a16fb AG |
453 | tree save_current_class = current_class; |
454 | char *save_input_filename = input_filename; | |
455 | JCF *save_current_jcf = current_jcf; | |
8e1f2d4c | 456 | long saved_pos = 0; |
e04a16fb AG |
457 | if (current_jcf->read_state) |
458 | saved_pos = ftell (current_jcf->read_state); | |
459 | ||
460 | push_obstacks (&permanent_obstack, &permanent_obstack); | |
461 | ||
e04a16fb | 462 | /* Search in current zip first. */ |
8e1f2d4c | 463 | if (find_in_current_zip (IDENTIFIER_POINTER (name), &jcf) == 0) |
1ba305b5 APB |
464 | { |
465 | if (find_class (IDENTIFIER_POINTER (name), IDENTIFIER_LENGTH (name), | |
466 | &this_jcf, 1) == 0) | |
467 | { | |
468 | pop_obstacks (); /* FIXME: one pop_obstack() per function */ | |
469 | return 0; | |
470 | } | |
471 | else | |
472 | { | |
473 | this_jcf.seen_in_zip = 0; | |
474 | current_jcf = &this_jcf; | |
1ba305b5 APB |
475 | } |
476 | } | |
e04a16fb AG |
477 | else |
478 | current_jcf = jcf; | |
479 | ||
480 | if (current_jcf->java_source) | |
8e1f2d4c | 481 | jcf_parse_source (); |
e04a16fb | 482 | else { |
23a79c61 APB |
483 | java_parser_context_save_global (); |
484 | java_push_parser_context (); | |
e04a16fb AG |
485 | input_filename = current_jcf->filename; |
486 | jcf_parse (current_jcf); | |
23a79c61 APB |
487 | java_pop_parser_context (0); |
488 | java_parser_context_restore_global (); | |
e04a16fb AG |
489 | } |
490 | ||
491 | if (!current_jcf->seen_in_zip) | |
492 | JCF_FINISH (current_jcf); | |
e04a16fb AG |
493 | pop_obstacks (); |
494 | ||
495 | current_class = save_current_class; | |
496 | input_filename = save_input_filename; | |
497 | current_jcf = save_current_jcf; | |
498 | if (current_jcf->read_state) | |
499 | fseek (current_jcf->read_state, saved_pos, SEEK_SET); | |
bc3ca41b PB |
500 | return 1; |
501 | } | |
502 | ||
503 | /* Load CLASS_OR_NAME. CLASS_OR_NAME can be a mere identifier if | |
504 | called from the parser, otherwise it's a RECORD_TYPE node. If | |
505 | VERBOSE is 1, print error message on failure to load a class. */ | |
506 | ||
507 | /* Replace calls to load_class by having callers call read_class directly | |
508 | - and then perhaps rename read_class to load_class. FIXME */ | |
509 | ||
510 | void | |
511 | load_class (class_or_name, verbose) | |
512 | tree class_or_name; | |
513 | int verbose; | |
514 | { | |
515 | tree name; | |
516 | ||
517 | /* class_or_name can be the name of the class we want to load */ | |
518 | if (TREE_CODE (class_or_name) == IDENTIFIER_NODE) | |
519 | name = class_or_name; | |
520 | /* In some cases, it's a dependency that we process earlier that | |
521 | we though */ | |
522 | else if (TREE_CODE (class_or_name) == TREE_LIST) | |
523 | name = TYPE_NAME (TREE_PURPOSE (class_or_name)); | |
524 | /* Or it's a type in the making */ | |
525 | else | |
526 | name = DECL_NAME (TYPE_NAME (class_or_name)); | |
527 | ||
528 | if (read_class (name) == 0 && verbose) | |
529 | { | |
530 | error ("Cannot find file for class %s.", | |
531 | IDENTIFIER_POINTER (name)); | |
532 | if (TREE_CODE (class_or_name) == RECORD_TYPE) | |
533 | TYPE_SIZE (class_or_name) = error_mark_node; | |
534 | #if 0 | |
535 | /* FIXME: what to do here? */ | |
536 | if (!strcmp (classpath, DEFAULT_CLASS_PATH)) | |
537 | fatal ("giving up"); | |
538 | #endif | |
539 | return; | |
540 | } | |
e04a16fb AG |
541 | } |
542 | ||
b351b287 | 543 | /* Parse a source file when JCF refers to a source file. */ |
e04a16fb | 544 | |
8e1f2d4c KG |
545 | static void |
546 | jcf_parse_source () | |
e04a16fb | 547 | { |
5e942c50 | 548 | tree file; |
e04a16fb | 549 | |
5e942c50 APB |
550 | java_parser_context_save_global (); |
551 | java_push_parser_context (); | |
e04a16fb | 552 | input_filename = current_jcf->filename; |
5e942c50 | 553 | file = get_identifier (input_filename); |
23a79c61 APB |
554 | if (!HAS_BEEN_ALREADY_PARSED_P (file)) |
555 | { | |
556 | if (!(finput = fopen (input_filename, "r"))) | |
557 | fatal ("input file `%s' just disappeared - jcf_parse_source", | |
558 | input_filename); | |
559 | parse_source_file (file); | |
560 | if (fclose (finput)) | |
561 | fatal ("can't close input file `%s' stream - jcf_parse_source", | |
562 | input_filename); | |
563 | } | |
5e942c50 | 564 | java_pop_parser_context (IS_A_COMMAND_LINE_FILENAME_P (file)); |
e04a16fb AG |
565 | java_parser_context_restore_global (); |
566 | } | |
567 | ||
568 | /* Parse the .class file JCF. */ | |
569 | ||
1c7f3673 | 570 | void |
e04a16fb AG |
571 | jcf_parse (jcf) |
572 | JCF* jcf; | |
573 | { | |
574 | int i, code; | |
575 | ||
576 | if (jcf_parse_preamble (jcf) != 0) | |
577 | fatal ("Not a valid Java .class file.\n"); | |
578 | code = jcf_parse_constant_pool (jcf); | |
579 | if (code != 0) | |
580 | fatal ("error while parsing constant pool"); | |
581 | code = verify_constant_pool (jcf); | |
582 | if (code > 0) | |
583 | fatal ("error in constant pool entry #%d\n", code); | |
584 | ||
585 | jcf_parse_class (jcf); | |
586 | if (main_class == NULL_TREE) | |
587 | main_class = current_class; | |
588 | if (! quiet_flag && TYPE_NAME (current_class)) | |
48aedbca AG |
589 | fprintf (stderr, " %s %s", |
590 | (jcf->access_flags & ACC_INTERFACE) ? "interface" : "class", | |
e04a16fb | 591 | IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (current_class)))); |
0b4d333e APB |
592 | if (CLASS_LOADED_P (current_class)) |
593 | return; | |
e04a16fb AG |
594 | CLASS_LOADED_P (current_class) = 1; |
595 | ||
596 | for (i = 1; i < JPOOL_SIZE(jcf); i++) | |
597 | { | |
598 | switch (JPOOL_TAG (jcf, i)) | |
599 | { | |
600 | case CONSTANT_Class: | |
601 | get_class_constant (jcf, i); | |
602 | break; | |
603 | } | |
604 | } | |
605 | ||
606 | code = jcf_parse_fields (jcf); | |
607 | if (code != 0) | |
608 | fatal ("error while parsing fields"); | |
609 | code = jcf_parse_methods (jcf); | |
610 | if (code != 0) | |
611 | fatal ("error while parsing methods"); | |
612 | code = jcf_parse_final_attributes (jcf); | |
613 | if (code != 0) | |
614 | fatal ("error while parsing final attributes"); | |
615 | ||
616 | /* The fields of class_type_node are already in correct order. */ | |
617 | if (current_class != class_type_node && current_class != object_type_node) | |
618 | TYPE_FIELDS (current_class) = nreverse (TYPE_FIELDS (current_class)); | |
619 | ||
620 | push_obstacks (&permanent_obstack, &permanent_obstack); | |
621 | layout_class (current_class); | |
23a79c61 APB |
622 | if (current_class == object_type_node) |
623 | layout_class_methods (object_type_node); | |
624 | else | |
625 | all_class_list = tree_cons (NULL_TREE, | |
626 | TYPE_NAME (current_class), all_class_list ); | |
e04a16fb AG |
627 | pop_obstacks (); |
628 | } | |
629 | ||
630 | void | |
631 | init_outgoing_cpool () | |
632 | { | |
633 | current_constant_pool_data_ref = NULL_TREE; | |
634 | if (outgoing_cpool == NULL) | |
635 | { | |
636 | static CPool outgoing_cpool_buffer; | |
637 | outgoing_cpool = &outgoing_cpool_buffer; | |
638 | CPOOL_INIT(outgoing_cpool); | |
639 | } | |
640 | else | |
641 | { | |
642 | CPOOL_REINIT(outgoing_cpool); | |
643 | } | |
644 | } | |
645 | ||
4bcde32e | 646 | static void |
e04a16fb AG |
647 | parse_class_file () |
648 | { | |
649 | tree method; | |
650 | char *save_input_filename = input_filename; | |
651 | int save_lineno = lineno; | |
652 | ||
1886c9d8 | 653 | java_layout_seen_class_methods (); |
23a79c61 | 654 | |
e04a16fb AG |
655 | input_filename = DECL_SOURCE_FILE (TYPE_NAME (current_class)); |
656 | lineno = 0; | |
657 | debug_start_source_file (input_filename); | |
658 | init_outgoing_cpool (); | |
659 | ||
660 | for ( method = TYPE_METHODS (CLASS_TO_HANDLE_TYPE (current_class)); | |
661 | method != NULL_TREE; method = TREE_CHAIN (method)) | |
662 | { | |
663 | JCF *jcf = current_jcf; | |
664 | ||
665 | if (METHOD_NATIVE (method) || METHOD_ABSTRACT (method)) | |
666 | continue; | |
667 | ||
668 | if (DECL_CODE_OFFSET (method) == 0) | |
669 | { | |
670 | error ("missing Code attribute"); | |
671 | continue; | |
672 | } | |
673 | ||
674 | lineno = 0; | |
675 | if (DECL_LINENUMBERS_OFFSET (method)) | |
676 | { | |
677 | register int i; | |
678 | register unsigned char *ptr; | |
679 | JCF_SEEK (jcf, DECL_LINENUMBERS_OFFSET (method)); | |
680 | linenumber_count = i = JCF_readu2 (jcf); | |
681 | linenumber_table = ptr = jcf->read_ptr; | |
682 | ||
683 | for (ptr += 2; --i >= 0; ptr += 4) | |
684 | { | |
685 | int line = GET_u2 (ptr); | |
686 | /* Set initial lineno lineno to smallest linenumber. | |
687 | * Needs to be set before init_function_start. */ | |
688 | if (lineno == 0 || line < lineno) | |
689 | lineno = line; | |
690 | } | |
691 | } | |
692 | else | |
693 | { | |
694 | linenumber_table = NULL; | |
695 | linenumber_count = 0; | |
696 | } | |
697 | ||
698 | start_java_method (method); | |
699 | ||
700 | give_name_to_locals (jcf); | |
701 | ||
702 | /* Actually generate code. */ | |
703 | expand_byte_code (jcf, method); | |
704 | ||
705 | end_java_method (); | |
706 | } | |
707 | ||
708 | if (flag_emit_class_files) | |
709 | write_classfile (current_class); | |
de4c7b02 | 710 | |
d593dd8c | 711 | finish_class (); |
e04a16fb AG |
712 | |
713 | debug_end_source_file (save_lineno); | |
714 | input_filename = save_input_filename; | |
715 | lineno = save_lineno; | |
716 | } | |
717 | ||
5e942c50 | 718 | /* Parse a source file, as pointed by the current value of INPUT_FILENAME. */ |
e04a16fb AG |
719 | |
720 | static void | |
5e942c50 APB |
721 | parse_source_file (file) |
722 | tree file; | |
e04a16fb | 723 | { |
bc3ca41b | 724 | int save_error_count = java_error_count; |
b351b287 | 725 | /* Mark the file as parsed */ |
5e942c50 | 726 | HAS_BEEN_ALREADY_PARSED_P (file) = 1; |
b351b287 | 727 | |
51ae4071 TT |
728 | jcf_dependency_add_file (input_filename, 0); |
729 | ||
e04a16fb | 730 | lang_init_source (1); /* Error msgs have no method prototypes */ |
bc3ca41b | 731 | |
e04a16fb AG |
732 | java_init_lex (); /* Initialize the parser */ |
733 | java_parse_abort_on_error (); | |
bc3ca41b | 734 | |
e04a16fb AG |
735 | java_parse (); /* Parse and build partial tree nodes. */ |
736 | java_parse_abort_on_error (); | |
737 | java_complete_class (); /* Parse unsatisfied class decl. */ | |
738 | java_parse_abort_on_error (); | |
739 | java_check_circular_reference (); /* Check on circular references */ | |
740 | java_parse_abort_on_error (); | |
e920ebc9 APB |
741 | java_fix_constructors (); /* Fix the constructors */ |
742 | java_parse_abort_on_error (); | |
e04a16fb AG |
743 | } |
744 | ||
5423609c APB |
745 | static int |
746 | predefined_filename_p (node) | |
747 | tree node; | |
748 | { | |
749 | int i; | |
750 | for (i = 0; i < predef_filenames_size; i++) | |
751 | if (predef_filenames [i] == node) | |
752 | return 1; | |
753 | return 0; | |
754 | } | |
755 | ||
e04a16fb AG |
756 | int |
757 | yyparse () | |
758 | { | |
b351b287 | 759 | int several_files = 0; |
c2e3db92 | 760 | char *list = xstrdup (input_filename), *next; |
b351b287 | 761 | tree node, current_file_list = NULL_TREE; |
e04a16fb | 762 | |
b351b287 | 763 | do |
e04a16fb | 764 | { |
b351b287 APB |
765 | next = strchr (list, '&'); |
766 | if (next) | |
767 | { | |
768 | *next++ = '\0'; | |
769 | several_files = 1; | |
770 | } | |
771 | ||
772 | if (list[0]) | |
773 | { | |
5e1db167 | 774 | char *value; |
5423609c APB |
775 | tree id; |
776 | int twice = 0; | |
8603f9c5 | 777 | |
5e1db167 | 778 | int len = strlen (list); |
b351b287 APB |
779 | |
780 | if (*list != '/' && several_files) | |
781 | obstack_grow (&temporary_obstack, "./", 2); | |
8603f9c5 TT |
782 | |
783 | obstack_grow0 (&temporary_obstack, list, len); | |
b351b287 | 784 | value = obstack_finish (&temporary_obstack); |
5423609c APB |
785 | |
786 | /* Exclude file that we see twice on the command line. For | |
787 | all files except {Class,Error,Object,RuntimeException,String, | |
788 | Throwable}.java we can rely on maybe_get_identifier. For | |
789 | these files, we need to do a linear search of | |
790 | current_file_list. This search happens only for these | |
791 | files, presumably only when we're recompiling libgcj. */ | |
792 | ||
793 | if ((id = maybe_get_identifier (value))) | |
794 | { | |
795 | if (predefined_filename_p (id)) | |
796 | { | |
797 | tree c; | |
798 | for (c = current_file_list; c; c = TREE_CHAIN (c)) | |
799 | if (TREE_VALUE (c) == id) | |
800 | twice = 1; | |
801 | } | |
802 | else | |
803 | twice = 1; | |
804 | } | |
805 | ||
806 | if (twice) | |
807 | { | |
808 | char *saved_input_filename = input_filename; | |
809 | input_filename = value; | |
c63b98cd | 810 | warning ("source file seen twice on command line and will be compiled only once."); |
5423609c APB |
811 | input_filename = saved_input_filename; |
812 | } | |
813 | else | |
814 | { | |
815 | node = get_identifier (value); | |
816 | IS_A_COMMAND_LINE_FILENAME_P (node) = 1; | |
817 | current_file_list = tree_cons (NULL_TREE, node, | |
818 | current_file_list); | |
819 | } | |
b351b287 APB |
820 | } |
821 | list = next; | |
822 | } | |
823 | while (next); | |
824 | ||
22eed1e6 | 825 | current_jcf = main_jcf; |
b351b287 APB |
826 | current_file_list = nreverse (current_file_list); |
827 | for (node = current_file_list; node; node = TREE_CHAIN (node)) | |
828 | { | |
22eed1e6 | 829 | tree name = TREE_VALUE (node); |
b351b287 | 830 | |
22eed1e6 APB |
831 | /* Skip already parsed files */ |
832 | if (HAS_BEEN_ALREADY_PARSED_P (name)) | |
833 | continue; | |
834 | ||
835 | /* Close previous descriptor, if any */ | |
836 | if (main_jcf->read_state && fclose (main_jcf->read_state)) | |
837 | fatal ("failed to close input file `%s' - yyparse", | |
838 | (main_jcf->filename ? main_jcf->filename : "<unknown>")); | |
839 | ||
840 | /* Set jcf up and open a new file */ | |
841 | JCF_ZERO (main_jcf); | |
1c7f3673 | 842 | main_jcf->read_state = fopen (IDENTIFIER_POINTER (name), "rb"); |
22eed1e6 APB |
843 | if (main_jcf->read_state == NULL) |
844 | pfatal_with_name (IDENTIFIER_POINTER (name)); | |
845 | ||
846 | /* Set new input_filename and finput */ | |
847 | finput = main_jcf->read_state; | |
848 | #ifdef IO_BUFFER_SIZE | |
849 | setvbuf (finput, (char *) xmalloc (IO_BUFFER_SIZE), | |
850 | _IOFBF, IO_BUFFER_SIZE); | |
851 | #endif | |
852 | input_filename = IDENTIFIER_POINTER (name); | |
853 | main_jcf->filbuf = jcf_filbuf_from_stdio; | |
b351b287 APB |
854 | |
855 | switch (jcf_figure_file_type (current_jcf)) | |
856 | { | |
857 | case JCF_ZIP: | |
858 | parse_zip_file_entries (); | |
b351b287 APB |
859 | break; |
860 | case JCF_CLASS: | |
861 | jcf_parse (current_jcf); | |
862 | parse_class_file (); | |
b351b287 APB |
863 | break; |
864 | case JCF_SOURCE: | |
5e942c50 APB |
865 | java_push_parser_context (); |
866 | java_parser_context_save_global (); | |
867 | parse_source_file (name); | |
868 | java_parser_context_restore_global (); | |
869 | java_pop_parser_context (1); | |
b351b287 APB |
870 | break; |
871 | } | |
e04a16fb | 872 | } |
c877974e | 873 | |
b351b287 | 874 | java_expand_classes (); |
66b48140 | 875 | if (!java_report_errors () && !flag_syntax_only) |
866e9df8 | 876 | emit_register_classes (); |
e04a16fb AG |
877 | return 0; |
878 | } | |
879 | ||
880 | static struct ZipFileCache *localToFile; | |
881 | ||
882 | /* Process all class entries found in the zip file. */ | |
4bcde32e | 883 | static void |
e04a16fb AG |
884 | parse_zip_file_entries (void) |
885 | { | |
886 | struct ZipDirectory *zdir; | |
887 | int i; | |
888 | ||
889 | for (i = 0, zdir = (ZipDirectory *)localToFile->z.central_directory; | |
890 | i < localToFile->z.count; i++, zdir = ZIPDIR_NEXT (zdir)) | |
891 | { | |
892 | tree class; | |
893 | ||
894 | /* We don't need to consider those files. */ | |
895 | if (!zdir->size || !zdir->filename_offset) | |
896 | continue; | |
897 | ||
898 | class = lookup_class (get_identifier (ZIPDIR_FILENAME (zdir))); | |
899 | current_jcf = TYPE_LANG_SPECIFIC (class)->jcf; | |
900 | current_class = class; | |
901 | ||
902 | if ( !CLASS_LOADED_P (class)) | |
903 | { | |
904 | fseek (current_jcf->read_state, current_jcf->zip_offset, SEEK_SET); | |
905 | jcf_parse (current_jcf); | |
906 | } | |
907 | ||
22eed1e6 APB |
908 | if (TYPE_SIZE (current_class) != error_mark_node) |
909 | { | |
910 | input_filename = current_jcf->filename; | |
911 | parse_class_file (); | |
912 | FREE (current_jcf->buffer); /* No longer necessary */ | |
913 | /* Note: there is a way to free this buffer right after a | |
914 | class seen in a zip file has been parsed. The idea is the | |
915 | set its jcf in such a way that buffer will be reallocated | |
916 | the time the code for the class will be generated. FIXME. */ | |
917 | } | |
e04a16fb AG |
918 | } |
919 | } | |
920 | ||
921 | /* Read all the entries of the zip file, creates a class and a JCF. Sets the | |
922 | jcf up for further processing and link it to the created class. */ | |
923 | ||
4bcde32e | 924 | static void process_zip_dir() |
e04a16fb AG |
925 | { |
926 | int i; | |
927 | ZipDirectory *zdir; | |
928 | ||
929 | for (i = 0, zdir = (ZipDirectory *)localToFile->z.central_directory; | |
930 | i < localToFile->z.count; i++, zdir = ZIPDIR_NEXT (zdir)) | |
931 | { | |
932 | char *class_name, *file_name, *class_name_in_zip_dir; | |
933 | tree class; | |
934 | JCF *jcf; | |
935 | int j; | |
936 | ||
937 | class_name_in_zip_dir = ZIPDIR_FILENAME (zdir); | |
938 | ||
939 | /* We choose to not to process entries with a zero size or entries | |
940 | not bearing the .class extention. */ | |
941 | if (!zdir->size || !zdir->filename_offset || | |
942 | strncmp (&class_name_in_zip_dir[zdir->filename_length-6], | |
943 | ".class", 6)) | |
944 | { | |
945 | /* So it will be skipped in parse_zip_file_entries */ | |
946 | zdir->size = 0; | |
947 | continue; | |
948 | } | |
949 | ||
950 | class_name = ALLOC (zdir->filename_length+1-6); | |
951 | file_name = ALLOC (zdir->filename_length+1); | |
952 | jcf = ALLOC (sizeof (JCF)); | |
953 | JCF_ZERO (jcf); | |
954 | ||
955 | strncpy (class_name, class_name_in_zip_dir, zdir->filename_length-6); | |
956 | class_name [zdir->filename_length-6] = '\0'; | |
957 | strncpy (file_name, class_name_in_zip_dir, zdir->filename_length); | |
958 | file_name [zdir->filename_length] = '\0'; | |
959 | ||
960 | for (j=0; class_name[j]; j++) | |
961 | class_name [j] = (class_name [j] == '/' ? '.' : class_name [j]); | |
962 | ||
963 | /* Yes, we write back the true class name into the zip directory. */ | |
964 | strcpy (class_name_in_zip_dir, class_name); | |
965 | zdir->filename_length = j; | |
966 | class = lookup_class (get_identifier (class_name)); | |
967 | ||
968 | jcf->read_state = finput; | |
969 | jcf->filbuf = jcf_filbuf_from_stdio; | |
970 | jcf->seen_in_zip = 1; | |
971 | jcf->java_source = 0; | |
972 | jcf->zip_offset = zdir->filestart; | |
973 | jcf->classname = class_name; | |
974 | jcf->filename = file_name; | |
975 | ||
976 | TYPE_LANG_SPECIFIC (class) = | |
977 | (struct lang_type *) perm_calloc (1, sizeof (struct lang_type)); | |
978 | TYPE_LANG_SPECIFIC (class)->jcf = jcf; | |
979 | } | |
980 | } | |
981 | ||
982 | /* Lookup class NAME and figure whether is a class already found in the current | |
983 | zip file. */ | |
4bcde32e | 984 | static int |
e04a16fb | 985 | DEFUN(find_in_current_zip, (name, length, jcf), |
c8e7d2e6 | 986 | const char *name AND JCF **jcf) |
e04a16fb AG |
987 | { |
988 | JCF *local_jcf; | |
989 | tree class_name = maybe_get_identifier (name), class, icv; | |
990 | ||
991 | if (!class_name) | |
992 | return 0; | |
993 | ||
994 | if (!(icv = IDENTIFIER_CLASS_VALUE (class_name))) | |
995 | return 0; | |
996 | ||
997 | class = TREE_TYPE (icv); | |
998 | ||
999 | /* Doesn't have jcf specific info ? It's not ours */ | |
1000 | if (!TYPE_LANG_SPECIFIC (class) || !TYPE_LANG_SPECIFIC (class)->jcf) | |
1001 | return 0; | |
1002 | ||
1003 | *jcf = local_jcf = TYPE_LANG_SPECIFIC (class)->jcf; | |
1004 | fseek (local_jcf->read_state, local_jcf->zip_offset, SEEK_SET); | |
1005 | return 1; | |
1006 | } | |
1007 | ||
1008 | /* Figure what kind of file we're dealing with */ | |
8e1f2d4c | 1009 | static int |
e04a16fb AG |
1010 | DEFUN(jcf_figure_file_type, (jcf), |
1011 | JCF *jcf) | |
1012 | { | |
1013 | unsigned char magic_string[4]; | |
1014 | uint32 magic; | |
1015 | ||
1016 | if (fread (magic_string, 1, 4, jcf->read_state) != 4) | |
1017 | jcf_unexpected_eof (jcf, 4); | |
1018 | ||
1019 | fseek (jcf->read_state, 0L, SEEK_SET); | |
1020 | magic = GET_u4 (magic_string); | |
1021 | ||
1022 | if (magic == 0xcafebabe) | |
1023 | return JCF_CLASS; | |
1024 | ||
8603f9c5 | 1025 | /* FIXME: is it a system file? */ |
63a212ed PB |
1026 | if (magic == (JCF_u4)ZIPMAGIC |
1027 | && !open_in_zip (jcf, input_filename, NULL, 0)) | |
e04a16fb AG |
1028 | { |
1029 | localToFile = ALLOC (sizeof (struct ZipFileCache)); | |
4504ead1 | 1030 | bcopy ((PTR) SeenZipFiles, (PTR) localToFile, sizeof (struct ZipFileCache)); |
e04a16fb AG |
1031 | process_zip_dir (); /* Register all the class defined there */ |
1032 | return JCF_ZIP; | |
1033 | } | |
1034 | ||
1035 | return JCF_SOURCE; | |
1036 | } | |
1037 |