]>
Commit | Line | Data |
---|---|---|
e04a16fb | 1 | /* Handle the constant pool of the Java(TM) Virtual Machine. |
6c418184 | 2 | Copyright (C) 1997, 1998, 1999, 2000, 2001 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 | You should have received a copy of the GNU General Public License | |
16 | along with GNU CC; see the file COPYING. If not, write to | |
17 | the Free Software Foundation, 59 Temple Place - Suite 330, | |
18 | Boston, MA 02111-1307, USA. | |
19 | ||
20 | Java and all Java-based marks are trademarks or registered trademarks | |
21 | of Sun Microsystems, Inc. in the United States and other countries. | |
22 | The Free Software Foundation is independent of Sun Microsystems, Inc. */ | |
23 | ||
24 | #include "config.h" | |
1f43f4b4 | 25 | #include "system.h" |
4bcde32e | 26 | #include "jcf.h" |
e04a16fb AG |
27 | #include "tree.h" |
28 | #include "java-tree.h" | |
1f43f4b4 | 29 | #include "toplev.h" |
19e223db | 30 | #include "ggc.h" |
e04a16fb AG |
31 | |
32 | extern struct obstack permanent_obstack; | |
33 | ||
df32d2ce KG |
34 | static void set_constant_entry PARAMS ((CPool *, int, int, jword)); |
35 | static int find_class_or_string_constant PARAMS ((CPool *, int, tree)); | |
36 | static int find_name_and_type_constant PARAMS ((CPool *, tree, tree)); | |
37 | static tree get_tag_node PARAMS ((int)); | |
38 | static tree build_constant_data_ref PARAMS ((void)); | |
4bcde32e | 39 | |
e04a16fb AG |
40 | /* Set the INDEX'th constant in CPOOL to have the given TAG and VALUE. */ |
41 | ||
4bcde32e | 42 | static void |
e04a16fb AG |
43 | set_constant_entry (cpool, index, tag, value) |
44 | CPool *cpool; | |
45 | int index; | |
46 | int tag; | |
47 | jword value; | |
48 | { | |
49 | if (cpool->data == NULL) | |
50 | { | |
51 | cpool->capacity = 100; | |
52 | cpool->tags = (uint8*) xmalloc (sizeof(uint8) * cpool->capacity); | |
53 | cpool->data = (jword*) xmalloc (sizeof(jword) * cpool->capacity); | |
54 | cpool->count = 1; | |
55 | } | |
56 | if (index >= cpool->capacity) | |
57 | { | |
58 | cpool->capacity *= 2; | |
59 | if (index >= cpool->capacity) | |
60 | cpool->capacity = index + 10; | |
61 | cpool->tags = (uint8*) xrealloc (cpool->tags, | |
62 | sizeof(uint8) * cpool->capacity); | |
63 | cpool->data = (jword*) xrealloc (cpool->data, | |
64 | sizeof(jword) * cpool->capacity); | |
65 | } | |
66 | if (index >= cpool->count) | |
67 | cpool->count = index + 1; | |
68 | cpool->tags[index] = tag; | |
69 | cpool->data[index] = value; | |
70 | } | |
71 | ||
72 | /* Find (or create) a constant pool entry matching TAG and VALUE. */ | |
73 | ||
74 | int | |
75 | find_constant1 (cpool, tag, value) | |
76 | CPool *cpool; | |
77 | int tag; | |
78 | jword value; | |
79 | { | |
80 | int i; | |
81 | for (i = cpool->count; --i > 0; ) | |
82 | { | |
83 | if (cpool->tags[i] == tag && cpool->data[i] == value) | |
84 | return i; | |
85 | } | |
86 | i = cpool->count == 0 ? 1 : cpool->count; | |
87 | set_constant_entry (cpool, i, tag, value); | |
88 | return i; | |
89 | } | |
90 | ||
91 | /* Find a double-word constant pool entry matching TAG and WORD1/WORD2. */ | |
92 | ||
93 | int | |
94 | find_constant2 (cpool, tag, word1, word2) | |
95 | CPool *cpool; | |
96 | int tag; | |
97 | jword word1, word2; | |
98 | { | |
99 | int i; | |
100 | for (i = cpool->count - 1; --i > 0; ) | |
101 | { | |
102 | if (cpool->tags[i] == tag | |
103 | && cpool->data[i] == word1 | |
104 | && cpool->data[i+1] == word2) | |
105 | return i; | |
106 | } | |
107 | i = cpool->count == 0 ? 1 : cpool->count; | |
108 | set_constant_entry (cpool, i, tag, word1); | |
109 | set_constant_entry (cpool, i+1, 0, word2); | |
110 | return i; | |
111 | } | |
112 | ||
113 | int | |
114 | find_utf8_constant (cpool, name) | |
115 | CPool *cpool; | |
116 | tree name; | |
117 | { | |
118 | if (name == NULL_TREE) | |
119 | return 0; | |
120 | return find_constant1 (cpool, CONSTANT_Utf8, (jword) name); | |
121 | } | |
122 | ||
4bcde32e | 123 | static int |
e04a16fb AG |
124 | find_class_or_string_constant (cpool, tag, name) |
125 | CPool *cpool; | |
126 | int tag; | |
127 | tree name; | |
128 | { | |
129 | int j = find_utf8_constant (cpool, name); | |
130 | int i; | |
131 | for (i = cpool->count; --i > 0; ) | |
132 | { | |
7e21fe59 | 133 | if (cpool->tags[i] == tag && cpool->data[i] == (jword) j) |
e04a16fb AG |
134 | return i; |
135 | } | |
136 | i = cpool->count; | |
137 | set_constant_entry (cpool, i, tag, (jword) j); | |
138 | return i; | |
139 | } | |
140 | ||
141 | int | |
142 | find_class_constant (cpool, type) | |
143 | CPool *cpool; | |
144 | tree type; | |
145 | { | |
146 | return find_class_or_string_constant (cpool, CONSTANT_Class, | |
147 | build_internal_class_name (type)); | |
148 | } | |
149 | ||
d640220c PB |
150 | /* Allocate a CONSTANT_string entry given a STRING_CST. */ |
151 | ||
152 | int | |
153 | find_string_constant (cpool, string) | |
154 | CPool *cpool; | |
155 | tree string; | |
156 | { | |
157 | string = get_identifier (TREE_STRING_POINTER (string)); | |
158 | return find_class_or_string_constant (cpool, CONSTANT_String, string); | |
159 | ||
160 | } | |
161 | ||
e04a16fb AG |
162 | /* Find (or create) a CONSTANT_NameAndType matching NAME and TYPE. |
163 | Return its index in the constant pool CPOOL. */ | |
164 | ||
4bcde32e | 165 | static int |
e04a16fb AG |
166 | find_name_and_type_constant (cpool, name, type) |
167 | CPool *cpool; | |
168 | tree name; | |
169 | tree type; | |
170 | { | |
171 | int name_index = find_utf8_constant (cpool, name); | |
172 | int type_index = find_utf8_constant (cpool, build_java_signature (type)); | |
173 | return find_constant1 (cpool, CONSTANT_NameAndType, | |
174 | (name_index << 16) | type_index); | |
175 | } | |
176 | ||
177 | /* Find (or create) a CONSTANT_Fieldref for DECL (a FIELD_DECL or VAR_DECL). | |
178 | Return its index in the constant pool CPOOL. */ | |
179 | ||
180 | int | |
181 | find_fieldref_index (cpool, decl) | |
182 | CPool *cpool; | |
183 | tree decl; | |
184 | { | |
185 | int class_index = find_class_constant (cpool, DECL_CONTEXT (decl)); | |
186 | int name_type_index | |
187 | = find_name_and_type_constant (cpool, DECL_NAME (decl), TREE_TYPE (decl)); | |
188 | return find_constant1 (cpool, CONSTANT_Fieldref, | |
189 | (class_index << 16) | name_type_index); | |
190 | } | |
191 | ||
192 | /* Find (or create) a CONSTANT_Methodref for DECL (a FUNCTION_DECL). | |
193 | Return its index in the constant pool CPOOL. */ | |
194 | ||
195 | int | |
196 | find_methodref_index (cpool, decl) | |
197 | CPool *cpool; | |
198 | tree decl; | |
199 | { | |
8789b9fa PB |
200 | return find_methodref_with_class_index (cpool, decl, DECL_CONTEXT (decl)); |
201 | } | |
202 | ||
203 | int | |
204 | find_methodref_with_class_index (cpool, decl, mclass) | |
205 | CPool *cpool; | |
206 | tree decl; | |
207 | tree mclass; | |
208 | { | |
72a0aac6 | 209 | int class_index = find_class_constant (cpool, mclass); |
e04a16fb AG |
210 | tree name = DECL_CONSTRUCTOR_P (decl) ? init_identifier_node |
211 | : DECL_NAME (decl); | |
48aedbca | 212 | int name_type_index; |
48aedbca AG |
213 | name_type_index = |
214 | find_name_and_type_constant (cpool, name, TREE_TYPE (decl)); | |
72a0aac6 PB |
215 | return find_constant1 (cpool, |
216 | CLASS_INTERFACE (TYPE_NAME (mclass)) | |
217 | ? CONSTANT_InterfaceMethodref | |
218 | : CONSTANT_Methodref, | |
e04a16fb AG |
219 | (class_index << 16) | name_type_index); |
220 | } | |
221 | ||
222 | #define PUT1(X) (*ptr++ = (X)) | |
223 | #define PUT2(X) (PUT1((X) >> 8), PUT1(X)) | |
224 | #define PUT4(X) (PUT2((X) >> 16), PUT2(X)) | |
cb9b7a8c | 225 | #define PUTN(P, N) (memcpy(ptr, (P), (N)), ptr += (N)) |
e04a16fb AG |
226 | |
227 | /* Give the number of bytes needed in a .class file for the CPOOL | |
228 | constant pool. Includes the 2-byte constant_pool_count. */ | |
229 | ||
230 | int | |
231 | count_constant_pool_bytes (cpool) | |
232 | CPool *cpool; | |
233 | { | |
234 | int size = 2; | |
235 | int i = 1; | |
d640220c | 236 | for ( ; i < cpool->count; i++) |
e04a16fb AG |
237 | { |
238 | size++; | |
239 | switch (cpool->tags[i]) | |
240 | { | |
241 | case CONSTANT_NameAndType: | |
242 | case CONSTANT_Fieldref: | |
243 | case CONSTANT_Methodref: | |
244 | case CONSTANT_InterfaceMethodref: | |
245 | case CONSTANT_Float: | |
246 | case CONSTANT_Integer: | |
247 | size += 4; | |
248 | break; | |
249 | case CONSTANT_Class: | |
250 | case CONSTANT_String: | |
251 | size += 2; | |
252 | break; | |
253 | case CONSTANT_Long: | |
254 | case CONSTANT_Double: | |
d640220c PB |
255 | size += 8; |
256 | i++; | |
e04a16fb AG |
257 | break; |
258 | case CONSTANT_Utf8: | |
259 | { | |
d640220c | 260 | tree t = (tree) cpool->data[i]; |
e04a16fb AG |
261 | int len = IDENTIFIER_LENGTH (t); |
262 | size += len + 2; | |
263 | } | |
264 | break; | |
d640220c PB |
265 | default: |
266 | /* Second word of CONSTANT_Long and CONSTANT_Double. */ | |
267 | size--; | |
e04a16fb AG |
268 | } |
269 | } | |
270 | return size; | |
271 | } | |
272 | ||
273 | /* Write the constant pool CPOOL into BUFFER. | |
274 | The length of BUFFER is LENGTH, which must match the needed length. */ | |
275 | ||
276 | void | |
277 | write_constant_pool (cpool, buffer, length) | |
278 | CPool *cpool; | |
400500c4 | 279 | unsigned char *buffer; |
e04a16fb AG |
280 | int length; |
281 | { | |
400500c4 | 282 | unsigned char *ptr = buffer; |
e04a16fb AG |
283 | int i = 1; |
284 | jword *datap = &cpool->data[1]; | |
285 | PUT2 (cpool->count); | |
286 | for ( ; i < cpool->count; i++, datap++) | |
287 | { | |
288 | int tag = cpool->tags[i]; | |
289 | PUT1 (tag); | |
290 | switch (tag) | |
291 | { | |
292 | case CONSTANT_NameAndType: | |
293 | case CONSTANT_Fieldref: | |
294 | case CONSTANT_Methodref: | |
295 | case CONSTANT_InterfaceMethodref: | |
296 | case CONSTANT_Float: | |
297 | case CONSTANT_Integer: | |
298 | PUT4 (*datap); | |
299 | break; | |
300 | case CONSTANT_Class: | |
301 | case CONSTANT_String: | |
302 | PUT2 (*datap); | |
303 | break; | |
304 | break; | |
305 | case CONSTANT_Long: | |
306 | case CONSTANT_Double: | |
307 | PUT4(*datap); | |
308 | i++; | |
309 | datap++; | |
310 | PUT4 (*datap); | |
311 | break; | |
312 | case CONSTANT_Utf8: | |
313 | { | |
314 | tree t = (tree) *datap; | |
315 | int len = IDENTIFIER_LENGTH (t); | |
316 | PUT2 (len); | |
317 | PUTN (IDENTIFIER_POINTER (t), len); | |
318 | } | |
319 | break; | |
320 | } | |
321 | } | |
400500c4 | 322 | |
e04a16fb | 323 | if (ptr != buffer + length) |
400500c4 | 324 | abort (); |
e04a16fb AG |
325 | } |
326 | ||
327 | CPool *outgoing_cpool; | |
328 | ||
4bcde32e | 329 | static tree |
e04a16fb AG |
330 | get_tag_node (tag) |
331 | int tag; | |
332 | { | |
19e223db MM |
333 | /* A Cache for build_int_2 (CONSTANT_XXX, 0). */ |
334 | static tree tag_nodes[13]; | |
335 | static int initialized_p; | |
336 | ||
337 | /* Register the TAG_NODES with the garbage collector. */ | |
338 | if (!initialized_p) | |
339 | { | |
340 | ggc_add_tree_root (tag_nodes, 13); | |
341 | initialized_p = 1; | |
342 | } | |
343 | ||
e04a16fb | 344 | if (tag_nodes[tag] == NULL_TREE) |
1f8f4a0b | 345 | tag_nodes[tag] = build_int_2 (tag, 0); |
e04a16fb AG |
346 | return tag_nodes[tag]; |
347 | } | |
348 | ||
349 | /* Look for a constant pool entry that matches TAG and NAME. | |
350 | Creates a new entry if not found. | |
351 | TAG is one of CONSTANT_Utf8, CONSTANT_String or CONSTANT_Class. | |
352 | NAME is an IDENTIFIER_NODE naming the Utf8 constant, string, or class. | |
353 | Returns the index of the entry. */ | |
354 | ||
355 | int | |
356 | alloc_name_constant (tag, name) | |
357 | int tag; | |
358 | tree name; | |
359 | { | |
360 | return find_constant1 (outgoing_cpool, tag, (jword) name); | |
361 | } | |
362 | ||
363 | /* Build an identifier for the internal name of reference type TYPE. */ | |
364 | ||
365 | tree | |
366 | build_internal_class_name (type) | |
367 | tree type; | |
368 | { | |
369 | tree name; | |
370 | if (TYPE_ARRAY_P (type)) | |
371 | name = build_java_signature (type); | |
372 | else | |
373 | { | |
374 | name = TYPE_NAME (type); | |
375 | if (TREE_CODE (name) != IDENTIFIER_NODE) | |
376 | name = DECL_NAME (name); | |
377 | name = identifier_subst (name, "", '.', '/', ""); | |
378 | } | |
379 | return name; | |
380 | } | |
381 | ||
382 | /* Look for a CONSTANT_Class entry for CLAS, creating a new one if needed. */ | |
383 | ||
384 | int | |
385 | alloc_class_constant (clas) | |
386 | tree clas; | |
387 | { | |
7e57923c AH |
388 | tree class_name = build_internal_class_name (clas); |
389 | ||
e04a16fb | 390 | return alloc_name_constant (CONSTANT_Class, |
7e57923c AH |
391 | (unmangle_classname |
392 | (IDENTIFIER_POINTER(class_name), | |
393 | IDENTIFIER_LENGTH(class_name)))); | |
e04a16fb AG |
394 | } |
395 | ||
396 | /* Return a reference to the data array of the current constant pool. */ | |
397 | ||
4bcde32e | 398 | static tree |
e04a16fb AG |
399 | build_constant_data_ref () |
400 | { | |
c2952b01 APB |
401 | if (TYPE_CPOOL_DATA_REF (current_class)) |
402 | current_constant_pool_data_ref = TYPE_CPOOL_DATA_REF (current_class); | |
403 | ||
404 | else if (current_constant_pool_data_ref == NULL_TREE) | |
e04a16fb AG |
405 | { |
406 | tree decl; | |
407 | tree decl_name = mangled_classname ("_CD_", current_class); | |
e04a16fb AG |
408 | decl = build_decl (VAR_DECL, decl_name, |
409 | build_array_type (ptr_type_node, | |
410 | one_elt_array_domain_type)); | |
411 | TREE_STATIC (decl) = 1; | |
6c418184 | 412 | make_decl_rtl (decl, NULL); |
c2952b01 | 413 | TYPE_CPOOL_DATA_REF (current_class) = current_constant_pool_data_ref |
e04a16fb AG |
414 | = build1 (ADDR_EXPR, ptr_type_node, decl); |
415 | } | |
416 | return current_constant_pool_data_ref; | |
417 | } | |
418 | ||
419 | /* Get the pointer value at the INDEX'th element of the constant pool. */ | |
420 | ||
421 | tree | |
422 | build_ref_from_constant_pool (index) | |
423 | int index; | |
424 | { | |
425 | tree t = build_constant_data_ref (); | |
426 | index *= int_size_in_bytes (ptr_type_node); | |
427 | t = fold (build (PLUS_EXPR, ptr_type_node, | |
428 | t, build_int_2 (index, 0))); | |
429 | return build1 (INDIRECT_REF, ptr_type_node, t); | |
430 | } | |
431 | ||
432 | /* Build an initializer for the constants field of the current constal pool. | |
433 | Should only be called at top-level, since it may emit declarations. */ | |
434 | ||
435 | tree | |
436 | build_constants_constructor () | |
437 | { | |
438 | tree tags_value, data_value; | |
439 | tree cons; | |
440 | tree tags_list = NULL_TREE; | |
441 | tree data_list = NULL_TREE; | |
442 | int i; | |
443 | for (i = outgoing_cpool->count; --i > 0; ) | |
444 | { | |
445 | tags_list | |
446 | = tree_cons (NULL_TREE, get_tag_node (outgoing_cpool->tags[i]), | |
447 | tags_list); | |
448 | data_list | |
449 | = tree_cons (NULL_TREE, build_utf8_ref ((tree)outgoing_cpool->data[i]), | |
450 | data_list); | |
451 | } | |
452 | if (outgoing_cpool->count > 0) | |
453 | { | |
454 | tree index_type; | |
455 | tree data_decl, tags_decl, tags_type; | |
456 | tree max_index = build_int_2 (outgoing_cpool->count - 1, 0); | |
457 | TREE_TYPE (max_index) = sizetype; | |
458 | index_type = build_index_type (max_index); | |
459 | ||
460 | /* Add dummy 0'th element of constant pool. */ | |
461 | tags_list = tree_cons (NULL_TREE, get_tag_node (0), tags_list); | |
462 | data_list = tree_cons (NULL_TREE, null_pointer_node, data_list); | |
463 | ||
464 | data_decl = TREE_OPERAND (build_constant_data_ref (), 0); | |
465 | TREE_TYPE (data_decl) = build_array_type (ptr_type_node, index_type), | |
466 | DECL_INITIAL (data_decl) = build (CONSTRUCTOR, TREE_TYPE (data_decl), | |
467 | NULL_TREE, data_list); | |
468 | DECL_SIZE (data_decl) = TYPE_SIZE (TREE_TYPE (data_decl)); | |
06ceef4e RK |
469 | DECL_SIZE_UNIT (data_decl) = TYPE_SIZE_UNIT (TREE_TYPE (data_decl)); |
470 | rest_of_decl_compilation (data_decl, (char *) 0, 1, 0); | |
e04a16fb AG |
471 | data_value = build_address_of (data_decl); |
472 | ||
473 | tags_type = build_array_type (unsigned_byte_type_node, index_type); | |
474 | tags_decl = build_decl (VAR_DECL, mangled_classname ("_CT_", | |
475 | current_class), | |
476 | tags_type); | |
477 | TREE_STATIC (tags_decl) = 1; | |
478 | DECL_INITIAL (tags_decl) = build (CONSTRUCTOR, tags_type, | |
479 | NULL_TREE, tags_list); | |
480 | rest_of_decl_compilation (tags_decl, (char*) 0, 1, 0); | |
481 | tags_value = build_address_of (tags_decl); | |
482 | } | |
483 | else | |
484 | { | |
485 | data_value = null_pointer_node; | |
486 | tags_value = null_pointer_node; | |
487 | } | |
488 | START_RECORD_CONSTRUCTOR (cons, constants_type_node); | |
489 | PUSH_FIELD_VALUE (cons, "size", build_int_2 (outgoing_cpool->count, 0)); | |
490 | PUSH_FIELD_VALUE (cons, "tags", tags_value); | |
491 | PUSH_FIELD_VALUE (cons, "data", data_value); | |
492 | FINISH_RECORD_CONSTRUCTOR (cons); | |
493 | return cons; | |
494 | } |