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