#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tm.h"
#include "jcf.h"
#include "tree.h"
#include "java-tree.h"
#include "obstack.h"
#include "toplev.h"
#include "ggc.h"
#include "langhooks-def.h"
static void mangle_class_field (tree);
static void mangle_vtable (tree);
static void mangle_field_decl (tree);
static void mangle_method_decl (tree);
static void mangle_local_cni_method_decl (tree);
static void mangle_type (tree);
static void mangle_pointer_type (tree);
static void mangle_array_type (tree);
static int mangle_record_type (tree, int);
static int find_compression_pointer_match (tree);
static int find_compression_array_match (tree);
static int find_compression_record_match (tree, tree *);
static int find_compression_array_template_match (tree);
static void set_type_package_list (tree);
static int entry_match_pointer_p (tree, int);
static void emit_compression_string (int);
static void init_mangling (void);
static tree finish_mangling (void);
static void compression_table_add (tree);
static void mangle_member_name (tree);
static struct obstack mangle_obstack_1;
struct obstack *mangle_obstack;
#define MANGLE_RAW_STRING(S) \
obstack_grow (mangle_obstack, (S), sizeof (S)-1)
static GTY(()) tree atms;
void
java_mangle_decl (tree decl)
{
if (TREE_CODE (decl) == RECORD_TYPE)
mangle_type (decl);
gcc_assert (TREE_CODE (decl) == FUNCTION_DECL
|| (TREE_CODE (decl) == VAR_DECL
&& (TREE_STATIC (decl)
|| DECL_EXTERNAL (decl)
|| TREE_PUBLIC (decl))));
if (DECL_CONTEXT (decl) && TYPE_P (DECL_CONTEXT (decl)))
{
init_mangling ();
switch (TREE_CODE (decl))
{
case VAR_DECL:
if (DECL_LANG_SPECIFIC (decl))
{
if (DECL_CLASS_FIELD_P (decl))
{
mangle_class_field (decl);
break;
}
else if (DECL_VTABLE_P (decl))
{
mangle_vtable (DECL_CONTEXT (decl));
break;
}
}
mangle_field_decl (decl);
break;
case FUNCTION_DECL:
if (DECL_LANG_SPECIFIC (decl) && DECL_LOCAL_CNI_METHOD_P (decl))
mangle_local_cni_method_decl (decl);
else
mangle_method_decl (decl);
break;
default:
gcc_unreachable ();
}
SET_DECL_ASSEMBLER_NAME (decl, finish_mangling ());
}
else
lhd_set_decl_assembler_name (decl);
}
static void
mangle_class_field (tree decl)
{
tree type = DECL_CONTEXT (decl);
mangle_record_type (type, 0);
if (TREE_CODE (TREE_TYPE (decl)) == RECORD_TYPE)
MANGLE_RAW_STRING ("6class$");
else
MANGLE_RAW_STRING ("7class$$");
obstack_1grow (mangle_obstack, 'E');
}
static void
mangle_vtable (tree type)
{
MANGLE_RAW_STRING ("TV");
mangle_record_type (type, 0);
obstack_1grow (mangle_obstack, 'E');
}
static void
mangle_field_decl (tree decl)
{
mangle_record_type (DECL_CONTEXT (decl), 0);
mangle_member_name (DECL_NAME (decl));
obstack_1grow (mangle_obstack, 'E');
}
static void
mangle_method_decl (tree mdecl)
{
tree method_name = DECL_NAME (mdecl);
tree arglist;
mangle_record_type (DECL_CONTEXT (mdecl), 0);
if (ID_INIT_P (method_name))
obstack_grow (mangle_obstack, "C1", 2);
else
mangle_member_name (method_name);
obstack_1grow (mangle_obstack, 'E');
arglist = TYPE_ARG_TYPES (TREE_TYPE (mdecl));
if (TREE_CODE (TREE_TYPE (mdecl)) == METHOD_TYPE)
arglist = TREE_CHAIN (arglist);
if (!ID_INIT_P (method_name))
{
obstack_1grow (mangle_obstack, 'J');
mangle_type(TREE_TYPE(TREE_TYPE(mdecl)));
}
if (arglist == end_params_node)
obstack_1grow (mangle_obstack, 'v');
else
{
tree arg;
for (arg = arglist; arg != end_params_node; arg = TREE_CHAIN (arg))
mangle_type (TREE_VALUE (arg));
}
}
static void
mangle_local_cni_method_decl (tree decl)
{
MANGLE_RAW_STRING ("GA");
mangle_method_decl (decl);
}
static void
mangle_member_name (tree name)
{
append_gpp_mangled_name (IDENTIFIER_POINTER (name),
IDENTIFIER_LENGTH (name));
if (cxx_keyword_p (IDENTIFIER_POINTER (name), IDENTIFIER_LENGTH (name)))
obstack_1grow (mangle_obstack, '$');
}
static void
mangle_type (tree type)
{
switch (TREE_CODE (type))
{
char code;
case BOOLEAN_TYPE: code = 'b'; goto primitive;
case VOID_TYPE: code = 'v'; goto primitive;
case INTEGER_TYPE:
if (type == char_type_node || type == promoted_char_type_node)
{
code = 'w';
goto primitive;
}
if (type == promoted_short_type_node)
type = short_type_node;
if (type == promoted_byte_type_node)
type = byte_type_node;
switch (TYPE_PRECISION (type))
{
case 8: code = 'c'; goto primitive;
case 16: code = 's'; goto primitive;
case 32: code = 'i'; goto primitive;
case 64: code = 'x'; goto primitive;
default: goto bad_type;
}
primitive:
obstack_1grow (mangle_obstack, code);
break;
case REAL_TYPE:
switch (TYPE_PRECISION (type))
{
case 32: code = 'f'; goto primitive;
case 64: code = 'd'; goto primitive;
default: goto bad_type;
}
case POINTER_TYPE:
if (TYPE_ARRAY_P (TREE_TYPE (type)))
mangle_array_type (type);
else
mangle_pointer_type (type);
break;
bad_type:
default:
gcc_unreachable ();
}
}
static GTY(()) tree compression_table;
static int compression_next;
static int
find_compression_pointer_match (tree type)
{
int i;
for (i = compression_next-1; i >= 0; i--)
if (entry_match_pointer_p (type, i))
return i;
return -1;
}
static int
find_compression_array_match (tree type)
{
return find_compression_pointer_match (type);
}
static int
find_compression_array_template_match (tree string)
{
int i;
for (i = 0; i < compression_next; i++)
if (TREE_VEC_ELT (compression_table, i) == string)
return i;
return -1;
}
static int
find_compression_record_match (tree type, tree *next_current)
{
int i, match = -1;
tree current, saved_current = NULL_TREE;
current = TYPE_PACKAGE_LIST (type);
for (i = 0; i < compression_next; i++)
{
tree compression_entry = TREE_VEC_ELT (compression_table, i);
if (current && compression_entry == TREE_PURPOSE (current))
{
match = i;
saved_current = current;
current = TREE_CHAIN (current);
}
else
while (i < compression_next
&& TREE_CODE (compression_entry) == IDENTIFIER_NODE
&& compression_entry != atms)
compression_entry = TREE_VEC_ELT (compression_table, ++i);
}
if (!next_current)
return match;
if (match >= 0)
*next_current = TREE_CHAIN (saved_current);
if (match < 0)
*next_current = TYPE_PACKAGE_LIST (type);
return match;
}
static int
mangle_record_type (tree type, int for_pointer)
{
tree current;
int match;
int nadded_p = 0;
int qualified;
qualified = QUALIFIED_P (DECL_NAME (TYPE_NAME (type)));
#define ADD_N() \
do { obstack_1grow (mangle_obstack, 'N'); nadded_p = 1; } while (0)
gcc_assert (TREE_CODE (type) == RECORD_TYPE);
if (!TYPE_PACKAGE_LIST (type))
set_type_package_list (type);
match = find_compression_record_match (type, ¤t);
if (match >= 0)
{
if (for_pointer && current)
ADD_N();
emit_compression_string (match);
}
while (current)
{
compression_table_add (TREE_PURPOSE (current));
if ((qualified || !for_pointer) && !nadded_p)
ADD_N();
append_gpp_mangled_name (IDENTIFIER_POINTER (TREE_VALUE (current)),
IDENTIFIER_LENGTH (TREE_VALUE (current)));
current = TREE_CHAIN (current);
}
return nadded_p;
#undef ADD_N
}
static void
mangle_pointer_type (tree type)
{
int match;
tree pointer_type;
if ((match = find_compression_pointer_match (type)) >= 0)
{
emit_compression_string (match);
return;
}
pointer_type = type;
type = TREE_TYPE (type);
gcc_assert (TREE_CODE (type) == RECORD_TYPE);
obstack_1grow (mangle_obstack, 'P');
if (mangle_record_type (type, 1))
obstack_1grow (mangle_obstack, 'E');
compression_table_add (pointer_type);
}
static void
mangle_array_type (tree p_type)
{
tree type, elt_type;
int match;
type = TREE_TYPE (p_type);
gcc_assert (type);
elt_type = TYPE_ARRAY_ELEMENT (type);
if (!atms)
{
atms = get_identifier ("6JArray");
}
if ((match = find_compression_array_match (p_type)) >= 0)
{
emit_compression_string (match);
return;
}
obstack_1grow (mangle_obstack, 'P');
if ((match = find_compression_record_match (type, NULL)) > 0)
{
emit_compression_string (match);
return;
}
if ((match = find_compression_array_template_match (atms)) > 0)
emit_compression_string (match);
else
{
obstack_grow (mangle_obstack,
IDENTIFIER_POINTER (atms), IDENTIFIER_LENGTH (atms));
compression_table_add (atms);
}
obstack_1grow (mangle_obstack, 'I');
mangle_type (elt_type);
obstack_1grow (mangle_obstack, 'E');
compression_table_add (type);
compression_table_add (p_type);
}
static void
emit_compression_string (int i)
{
i -= 1;
obstack_1grow (mangle_obstack, 'S');
if (i >= 0)
{
static const char digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
unsigned HOST_WIDE_INT n;
unsigned HOST_WIDE_INT m=1;
for (n = i; n >= 36; n /= 36, m *=36);
while (m > 0)
{
int digit = i / m;
obstack_1grow (mangle_obstack, digits [digit]);
i -= digit * m;
m /= 36;
}
}
obstack_1grow (mangle_obstack, '_');
}
static int
entry_match_pointer_p (tree type, int i)
{
tree t = TREE_VEC_ELT (compression_table, i);
while (TREE_CODE (type) == POINTER_TYPE
&& TREE_CODE (t) == POINTER_TYPE)
{
t = TREE_TYPE (t);
type = TREE_TYPE (type);
}
return (TREE_CODE (type) == RECORD_TYPE
&& TREE_CODE (t) == RECORD_TYPE
&& t == type);
}
static void
set_type_package_list (tree type)
{
int i;
const char *type_string = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type)));
char *ptr;
int qualifications;
tree list = NULL_TREE, elt;
for (ptr = (char *)type_string, qualifications = 0; *ptr; ptr++)
if (*ptr == '.')
qualifications += 1;
for (ptr = (char *)type_string, i = 0; i < qualifications; ptr++)
{
if (ptr [0] == '.')
{
char c;
tree identifier;
c = ptr [0];
ptr [0] = '\0';
identifier = get_identifier (type_string);
ptr [0] = c;
elt = build_tree_list (identifier, identifier);
TREE_CHAIN (elt) = list;
list = elt;
type_string = ptr+1;
i += 1;
}
}
elt = build_tree_list (type, get_identifier (type_string));
TREE_CHAIN (elt) = list;
list = elt;
TYPE_PACKAGE_LIST (type) = nreverse (list);
}
static void
compression_table_add (tree type)
{
if (compression_next == TREE_VEC_LENGTH (compression_table))
{
tree new = make_tree_vec (2*compression_next);
int i;
for (i = 0; i < compression_next; i++)
TREE_VEC_ELT (new, i) = TREE_VEC_ELT (compression_table, i);
compression_table = new;
}
TREE_VEC_ELT (compression_table, compression_next++) = type;
}
static void
init_mangling (void)
{
if (!mangle_obstack)
{
mangle_obstack = &mangle_obstack_1;
gcc_obstack_init (mangle_obstack);
}
gcc_assert (compression_table == NULL);
compression_table = make_tree_vec (10);
MANGLE_RAW_STRING ("_Z");
}
static tree
finish_mangling (void)
{
tree result;
gcc_assert (compression_table);
compression_table = NULL_TREE;
compression_next = 0;
obstack_1grow (mangle_obstack, '\0');
result = get_identifier (obstack_base (mangle_obstack));
obstack_free (mangle_obstack, obstack_base (mangle_obstack));
return result;
}
#include "gt-java-mangle.h"