diff options
author | Anthony Green <green@gcc.gnu.org> | 1998-09-06 15:36:06 +0000 |
---|---|---|
committer | Anthony Green <green@gcc.gnu.org> | 1998-09-06 15:36:06 +0000 |
commit | e04a16fbeee9504247e0d069171a627096225028 (patch) | |
tree | b78f906318225a5e7bd3471f008be772727bdcea /gcc/java/constants.c | |
parent | fc08e32958a1df77493bfe4abc52f88c7ade6251 (diff) | |
download | gcc-e04a16fbeee9504247e0d069171a627096225028.zip gcc-e04a16fbeee9504247e0d069171a627096225028.tar.gz gcc-e04a16fbeee9504247e0d069171a627096225028.tar.bz2 |
Initial revision
From-SVN: r22299
Diffstat (limited to 'gcc/java/constants.c')
-rw-r--r-- | gcc/java/constants.c | 453 |
1 files changed, 453 insertions, 0 deletions
diff --git a/gcc/java/constants.c b/gcc/java/constants.c new file mode 100644 index 0000000..696f684 --- /dev/null +++ b/gcc/java/constants.c @@ -0,0 +1,453 @@ +/* Handle the constant pool of the Java(TM) Virtual Machine. + Copyright (C) 1997 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. + +Java and all Java-based marks are trademarks or registered trademarks +of Sun Microsystems, Inc. in the United States and other countries. +The Free Software Foundation is independent of Sun Microsystems, Inc. */ + +#include "config.h" +#include "tree.h" +#include "java-tree.h" +#include "jcf.h" +#include "system.h" + +extern struct obstack permanent_obstack; + +/* Set the INDEX'th constant in CPOOL to have the given TAG and VALUE. */ + +void +set_constant_entry (cpool, index, tag, value) + CPool *cpool; + int index; + int tag; + jword value; +{ + if (cpool->data == NULL) + { + cpool->capacity = 100; + cpool->tags = (uint8*) xmalloc (sizeof(uint8) * cpool->capacity); + cpool->data = (jword*) xmalloc (sizeof(jword) * cpool->capacity); + cpool->count = 1; + } + if (index >= cpool->capacity) + { + cpool->capacity *= 2; + if (index >= cpool->capacity) + cpool->capacity = index + 10; + cpool->tags = (uint8*) xrealloc (cpool->tags, + sizeof(uint8) * cpool->capacity); + cpool->data = (jword*) xrealloc (cpool->data, + sizeof(jword) * cpool->capacity); + } + if (index >= cpool->count) + cpool->count = index + 1; + cpool->tags[index] = tag; + cpool->data[index] = value; +} + +/* Find (or create) a constant pool entry matching TAG and VALUE. */ + +int +find_constant1 (cpool, tag, value) + CPool *cpool; + int tag; + jword value; +{ + int i; + for (i = cpool->count; --i > 0; ) + { + if (cpool->tags[i] == tag && cpool->data[i] == value) + return i; + } + i = cpool->count == 0 ? 1 : cpool->count; + set_constant_entry (cpool, i, tag, value); + return i; +} + +/* Find a double-word constant pool entry matching TAG and WORD1/WORD2. */ + +int +find_constant2 (cpool, tag, word1, word2) + CPool *cpool; + int tag; + jword word1, word2; +{ + int i; + for (i = cpool->count - 1; --i > 0; ) + { + if (cpool->tags[i] == tag + && cpool->data[i] == word1 + && cpool->data[i+1] == word2) + return i; + } + i = cpool->count == 0 ? 1 : cpool->count; + set_constant_entry (cpool, i, tag, word1); + set_constant_entry (cpool, i+1, 0, word2); + return i; +} + +int +find_utf8_constant (cpool, name) + CPool *cpool; + tree name; +{ + if (name == NULL_TREE) + return 0; + return find_constant1 (cpool, CONSTANT_Utf8, (jword) name); +} + +int +find_class_or_string_constant (cpool, tag, name) + CPool *cpool; + int tag; + tree name; +{ + int j = find_utf8_constant (cpool, name); + int i; + for (i = cpool->count; --i > 0; ) + { + if (cpool->tags[i] == tag && cpool->data[i] == j) + return i; + } + i = cpool->count; + set_constant_entry (cpool, i, tag, (jword) j); + return i; +} + +int +find_class_constant (cpool, type) + CPool *cpool; + tree type; +{ + return find_class_or_string_constant (cpool, CONSTANT_Class, + build_internal_class_name (type)); +} + +/* Find (or create) a CONSTANT_NameAndType matching NAME and TYPE. + Return its index in the constant pool CPOOL. */ + +int +find_name_and_type_constant (cpool, name, type) + CPool *cpool; + tree name; + tree type; +{ + int name_index = find_utf8_constant (cpool, name); + int type_index = find_utf8_constant (cpool, build_java_signature (type)); + return find_constant1 (cpool, CONSTANT_NameAndType, + (name_index << 16) | type_index); +} + +/* Find (or create) a CONSTANT_Fieldref for DECL (a FIELD_DECL or VAR_DECL). + Return its index in the constant pool CPOOL. */ + +int +find_fieldref_index (cpool, decl) + CPool *cpool; + tree decl; +{ + int class_index = find_class_constant (cpool, DECL_CONTEXT (decl)); + int name_type_index + = find_name_and_type_constant (cpool, DECL_NAME (decl), TREE_TYPE (decl)); + return find_constant1 (cpool, CONSTANT_Fieldref, + (class_index << 16) | name_type_index); +} + +/* Find (or create) a CONSTANT_Methodref for DECL (a FUNCTION_DECL). + Return its index in the constant pool CPOOL. */ + +int +find_methodref_index (cpool, decl) + CPool *cpool; + tree decl; +{ + int class_index = find_class_constant (cpool, DECL_CONTEXT (decl)); + tree name = DECL_CONSTRUCTOR_P (decl) ? init_identifier_node + : DECL_NAME (decl); + int name_type_index + = find_name_and_type_constant (cpool, name, TREE_TYPE (decl)); + /* Methodref or INterfacemethodRef - FIXME */ + return find_constant1 (cpool, CONSTANT_Methodref, + (class_index << 16) | name_type_index); +} + +#define PUT1(X) (*ptr++ = (X)) +#define PUT2(X) (PUT1((X) >> 8), PUT1(X)) +#define PUT4(X) (PUT2((X) >> 16), PUT2(X)) +#define PUTN(P, N) (bcopy(P, ptr, N), ptr += (N)) + +/* Give the number of bytes needed in a .class file for the CPOOL + constant pool. Includes the 2-byte constant_pool_count. */ + +int +count_constant_pool_bytes (cpool) + CPool *cpool; +{ + int size = 2; + int i = 1; + jword *datap = &cpool->data[1];; + for ( ; i < cpool->count; i++, datap++) + { + size++; + switch (cpool->tags[i]) + { + case CONSTANT_NameAndType: + case CONSTANT_Fieldref: + case CONSTANT_Methodref: + case CONSTANT_InterfaceMethodref: + case CONSTANT_Float: + case CONSTANT_Integer: + size += 4; + break; + case CONSTANT_Class: + case CONSTANT_String: + size += 2; + break; + case CONSTANT_Long: + case CONSTANT_Double: + size += 4; + break; + case CONSTANT_Utf8: + { + tree t = (tree) *datap; + int len = IDENTIFIER_LENGTH (t); + size += len + 2; + } + break; + } + } + return size; +} + +/* Write the constant pool CPOOL into BUFFER. + The length of BUFFER is LENGTH, which must match the needed length. */ + +void +write_constant_pool (cpool, buffer, length) + CPool *cpool; + unsigned char* buffer; + int length; +{ + unsigned char* ptr = buffer; + int i = 1; + jword *datap = &cpool->data[1]; + PUT2 (cpool->count); + for ( ; i < cpool->count; i++, datap++) + { + int tag = cpool->tags[i]; + PUT1 (tag); + switch (tag) + { + case CONSTANT_NameAndType: + case CONSTANT_Fieldref: + case CONSTANT_Methodref: + case CONSTANT_InterfaceMethodref: + case CONSTANT_Float: + case CONSTANT_Integer: + PUT4 (*datap); + break; + case CONSTANT_Class: + case CONSTANT_String: + PUT2 (*datap); + break; + break; + case CONSTANT_Long: + case CONSTANT_Double: + PUT4(*datap); + i++; + datap++; + PUT4 (*datap); + break; + case CONSTANT_Utf8: + { + tree t = (tree) *datap; + int len = IDENTIFIER_LENGTH (t); + PUT2 (len); + PUTN (IDENTIFIER_POINTER (t), len); + } + break; + } + } + if (ptr != buffer + length) + fatal("internal error - incorrect constant pool"); +} + +CPool *outgoing_cpool; + +/* If non-NULL, an ADDR_EXPR referencing a VAR_DECL containing + the constant data array for the current class. */ +tree current_constant_pool_data_ref; + +/* A Cache for build_int_2 (CONSTANT_XXX, 0). */ +static tree tag_nodes[13]; + +tree +get_tag_node (tag) + int tag; +{ + if (tag_nodes[tag] == NULL_TREE) + { + push_obstacks (&permanent_obstack, &permanent_obstack); + tag_nodes[tag] = build_int_2 (tag, 0); + pop_obstacks (); + } + return tag_nodes[tag]; +} + +/* Look for a constant pool entry that matches TAG and NAME. + Creates a new entry if not found. + TAG is one of CONSTANT_Utf8, CONSTANT_String or CONSTANT_Class. + NAME is an IDENTIFIER_NODE naming the Utf8 constant, string, or class. + Returns the index of the entry. */ + +int +alloc_name_constant (tag, name) + int tag; + tree name; +{ + return find_constant1 (outgoing_cpool, tag, (jword) name); +} + +/* Build an identifier for the internal name of reference type TYPE. */ + +tree +build_internal_class_name (type) + tree type; +{ + tree name; + if (TYPE_ARRAY_P (type)) + name = build_java_signature (type); + else + { + name = TYPE_NAME (type); + if (TREE_CODE (name) != IDENTIFIER_NODE) + name = DECL_NAME (name); + name = identifier_subst (name, "", '.', '/', ""); + } + return name; +} + +/* Look for a CONSTANT_Class entry for CLAS, creating a new one if needed. */ + +int +alloc_class_constant (clas) + tree clas; +{ + + return alloc_name_constant (CONSTANT_Class, + build_internal_class_name (clas)); +} + +/* Return a reference to the data array of the current constant pool. */ + +tree +build_constant_data_ref () +{ + if (current_constant_pool_data_ref == NULL_TREE) + { + tree decl; + tree decl_name = mangled_classname ("_CD_", current_class); + push_obstacks (&permanent_obstack, &permanent_obstack); + decl = build_decl (VAR_DECL, decl_name, + build_array_type (ptr_type_node, + one_elt_array_domain_type)); + TREE_STATIC (decl) = 1; + make_decl_rtl (decl, NULL, 1); + pop_obstacks (); + current_constant_pool_data_ref + = build1 (ADDR_EXPR, ptr_type_node, decl); + } + return current_constant_pool_data_ref; +} + +/* Get the pointer value at the INDEX'th element of the constant pool. */ + +tree +build_ref_from_constant_pool (index) + int index; +{ + tree t = build_constant_data_ref (); + index *= int_size_in_bytes (ptr_type_node); + t = fold (build (PLUS_EXPR, ptr_type_node, + t, build_int_2 (index, 0))); + return build1 (INDIRECT_REF, ptr_type_node, t); +} + +/* Build an initializer for the constants field of the current constal pool. + Should only be called at top-level, since it may emit declarations. */ + +tree +build_constants_constructor () +{ + tree tags_value, data_value; + tree cons; + tree tags_list = NULL_TREE; + tree data_list = NULL_TREE; + int i; + for (i = outgoing_cpool->count; --i > 0; ) + { + tags_list + = tree_cons (NULL_TREE, get_tag_node (outgoing_cpool->tags[i]), + tags_list); + data_list + = tree_cons (NULL_TREE, build_utf8_ref ((tree)outgoing_cpool->data[i]), + data_list); + } + if (outgoing_cpool->count > 0) + { + tree index_type; + tree data_decl, tags_decl, tags_type; + tree max_index = build_int_2 (outgoing_cpool->count - 1, 0); + TREE_TYPE (max_index) = sizetype; + index_type = build_index_type (max_index); + + /* Add dummy 0'th element of constant pool. */ + tags_list = tree_cons (NULL_TREE, get_tag_node (0), tags_list); + data_list = tree_cons (NULL_TREE, null_pointer_node, data_list); + + data_decl = TREE_OPERAND (build_constant_data_ref (), 0); + TREE_TYPE (data_decl) = build_array_type (ptr_type_node, index_type), + DECL_INITIAL (data_decl) = build (CONSTRUCTOR, TREE_TYPE (data_decl), + NULL_TREE, data_list); + DECL_SIZE (data_decl) = TYPE_SIZE (TREE_TYPE (data_decl)); + rest_of_decl_compilation (data_decl, (char*) 0, 1, 0); + data_value = build_address_of (data_decl); + + tags_type = build_array_type (unsigned_byte_type_node, index_type); + tags_decl = build_decl (VAR_DECL, mangled_classname ("_CT_", + current_class), + tags_type); + TREE_STATIC (tags_decl) = 1; + DECL_INITIAL (tags_decl) = build (CONSTRUCTOR, tags_type, + NULL_TREE, tags_list); + rest_of_decl_compilation (tags_decl, (char*) 0, 1, 0); + tags_value = build_address_of (tags_decl); + } + else + { + data_value = null_pointer_node; + tags_value = null_pointer_node; + } + START_RECORD_CONSTRUCTOR (cons, constants_type_node); + PUSH_FIELD_VALUE (cons, "size", build_int_2 (outgoing_cpool->count, 0)); + PUSH_FIELD_VALUE (cons, "tags", tags_value); + PUSH_FIELD_VALUE (cons, "data", data_value); + FINISH_RECORD_CONSTRUCTOR (cons); + return cons; +} |