Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
R
riscv-gcc-1
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
lvzhengyang
riscv-gcc-1
Commits
e4de5a10
Commit
e4de5a10
authored
Oct 12, 1998
by
Per Bothner
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
�
Merge from Cygnus internal source tree. From-SVN: r23025
parent
8376a32e
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
1749 additions
and
524 deletions
+1749
-524
gcc/java/Makefile.in
+11
-5
gcc/java/buffer.h
+3
-0
gcc/java/except.c
+34
-18
gcc/java/expr.c
+105
-37
gcc/java/gjavah.c
+256
-125
gcc/java/jcf-parse.c
+1
-1
gcc/java/jcf-write.c
+1228
-313
gcc/java/lang.c
+48
-0
gcc/java/parse.h
+60
-22
gcc/java/verify.c
+3
-3
No files found.
gcc/java/Makefile.in
View file @
e4de5a10
...
@@ -148,10 +148,12 @@ ALL_CFLAGS = $(INTERNAL_CFLAGS) $(X_CFLAGS) $(T_CFLAGS) $(CFLAGS) $(XCFLAGS)
...
@@ -148,10 +148,12 @@ ALL_CFLAGS = $(INTERNAL_CFLAGS) $(X_CFLAGS) $(T_CFLAGS) $(CFLAGS) $(XCFLAGS)
# Likewise.
# Likewise.
ALL_CPPFLAGS
=
$(CPPFLAGS)
$(X_CPPFLAGS)
$(T_CPPFLAGS)
ALL_CPPFLAGS
=
$(CPPFLAGS)
$(X_CPPFLAGS)
$(T_CPPFLAGS)
# CYGNUS LOCAL: SUBDIR_USE_ALLOCA is different from FSF.
# Even if ALLOCA is set, don't use it if compiling with GCC.
# Even if ALLOCA is set, don't use it if compiling with GCC.
SUBDIR_OBSTACK
=
`
if
[
x
$(OBSTACK)
!=
x
]
;
then
echo
../
$(OBSTACK)
;
else
true
;
fi
`
SUBDIR_OBSTACK
=
`
if
[
x
$(OBSTACK)
!=
x
]
;
then
echo
../
$(OBSTACK)
;
else
true
;
fi
`
SUBDIR_USE_ALLOCA
=
`
case
"
${
CC
}
"
in
"
${
OLDCC
}
"
)
if
[
x
$(ALLOCA)
!=
x
]
;
then
echo
../
$(ALLOCA)
;
else
true
;
fi
;;
esac
`
#SUBDIR_USE_ALLOCA = `case "${CC}" in "${OLDCC}") if [ x$(ALLOCA) != x ]; then echo ../$(ALLOCA); else true; fi ;; esac`
SUBDIR_USE_ALLOCA
=
`
if
[
x
$(ALLOCA)
!=
x
]
;
then
echo
../
$(ALLOCA)
;
else
true
;
fi
`
SUBDIR_MALLOC
=
`
if
[
x
$(MALLOC)
!=
x
]
;
then
echo
../
$(MALLOC)
;
else
true
;
fi
`
SUBDIR_MALLOC
=
`
if
[
x
$(MALLOC)
!=
x
]
;
then
echo
../
$(MALLOC)
;
else
true
;
fi
`
# How to link with both our special library facilities
# How to link with both our special library facilities
...
@@ -226,19 +228,22 @@ RTL_H = $(srcdir)/../rtl.h $(srcdir)/../rtl.def \
...
@@ -226,19 +228,22 @@ RTL_H = $(srcdir)/../rtl.h $(srcdir)/../rtl.def \
$(srcdir)
/../machmode.h
$(srcdir)
/../machmode.def
$(srcdir)
/../machmode.h
$(srcdir)
/../machmode.def
EXPR_H
=
$(srcdir)
/../expr.h ../insn-codes.h
EXPR_H
=
$(srcdir)
/../expr.h ../insn-codes.h
# CYGNUS LOCAL: we put these files into the build dir.
PARSE_C
=
parse.c
PARSE_SCAN_C
=
parse-scan.c
PARSE_H
=
$(srcdir)
/parse.h
PARSE_H
=
$(srcdir)
/parse.h
PARSE_C
=
$(srcdir)
/parse.c
PARSE_SCAN_C
=
$(srcdir)
/parse-scan.c
$(PARSE_C)
:
$(srcdir)/parse.y $(srcdir)/lex.c $(PARSE_H) $(srcdir)/lex.h
$(PARSE_C)
:
$(srcdir)/parse.y $(srcdir)/lex.c $(PARSE_H) $(srcdir)/lex.h
$(BISON)
-t
-v
$(BISONFLAGS)
$(JAVABISONFLAGS)
-o
$(PARSE_C)
\
$(BISON)
-t
-v
$(BISONFLAGS)
$(JAVABISONFLAGS)
-o
$(PARSE_C)
\
$(srcdir)
/parse.y
$(srcdir)
/parse.y
$(PARSE_SCAN_C)
:
$(srcdir)/parse-scan.y $(srcdir)/lex.c $(PARSE_H)
\
$(PARSE_SCAN_C)
:
$(srcdir)/parse-scan.y $(srcdir)/lex.c $(PARSE_H)
\
$(srcdir)/lex.h
$(srcdir)/lex.h
$(BISON)
-t
-v
$(BISONFLAGS)
-o
$(PARSE_SCAN_C)
$(srcdir)
/parse-scan.y
$(BISON)
-t
-v
$(BISONFLAGS)
-o
$(PARSE_SCAN_C)
$(srcdir)
/parse-scan.y
lex.c
:
keyword.h lex.h
lex.c
:
keyword.h lex.h
lang.o
:
$(srcdir)/java-tree.def
keyword.h
:
keyword.gperf
keyword.h
:
keyword.gperf
gperf
-L
KR-C
-F
', 0'
-p
-t
-j1
-i
1
-g
-o
-N
java_keyword
-k1
,3,
$$
\
gperf
-L
KR-C
-F
', 0'
-p
-t
-j1
-i
1
-g
-o
-N
java_keyword
-k1
,3,
$$
\
keyword.gperf
>
keyword.h
keyword.gperf
>
keyword.h
...
@@ -258,8 +263,9 @@ TAGS: force
...
@@ -258,8 +263,9 @@ TAGS: force
mostlyclean
:
mostlyclean
:
rm
-f
*
.o
rm
-f
*
.o
# CYGNUS LOCAL: Remove these files, as they are in the build dir.
clean
:
mostlyclean
clean
:
mostlyclean
rm
-f
parse.c
rm
-f
parse.c
parse-scan.c
force
:
force
:
...
...
gcc/java/buffer.h
View file @
e4de5a10
...
@@ -36,6 +36,9 @@ struct buffer
...
@@ -36,6 +36,9 @@ struct buffer
#define NULL_BUFFER { (void*) 0, (void*) 0, (void*) 0 }
#define NULL_BUFFER { (void*) 0, (void*) 0, (void*) 0 }
#define BUFFER_INIT(BUFP) \
((BUFP)->data = NULL, (BUFP)->ptr = NULL, (BUFP)->limit = NULL)
#define BUFFER_LENGTH(BUFP) ((BUFP)->ptr - (BUFP)->data)
#define BUFFER_LENGTH(BUFP) ((BUFP)->ptr - (BUFP)->data)
#define BUFFER_RESET(BUFP) ((BUFP)->ptr = (BUFP)->data)
#define BUFFER_RESET(BUFP) ((BUFP)->ptr = (BUFP)->data)
...
...
gcc/java/except.c
View file @
e4de5a10
...
@@ -161,6 +161,12 @@ method_init_exceptions ()
...
@@ -161,6 +161,12 @@ method_init_exceptions ()
whole_range
.
first_child
=
NULL
;
whole_range
.
first_child
=
NULL
;
whole_range
.
next_sibling
=
NULL
;
whole_range
.
next_sibling
=
NULL
;
cache_range_start
=
0xFFFFFF
;
cache_range_start
=
0xFFFFFF
;
java_set_exception_lang_code
();
}
void
java_set_exception_lang_code
()
{
set_exception_lang_code
(
EH_LANG_Java
);
set_exception_lang_code
(
EH_LANG_Java
);
set_exception_version_code
(
1
);
set_exception_version_code
(
1
);
}
}
...
@@ -183,6 +189,32 @@ expand_start_java_handler (range)
...
@@ -183,6 +189,32 @@ expand_start_java_handler (range)
expand_eh_region_start
();
expand_eh_region_start
();
}
}
tree
prepare_eh_table_type
(
type
)
tree
type
;
{
tree
exp
;
/* The "type" (metch_info) in a (Java) exception table is one:
* a) NULL - meaning match any type in a try-finally.
* b) a pointer to a (ccmpiled) class (low-order bit 0).
* c) a pointer to the Utf8Const name of the class, plus one
* (which yields a value with low-order bit 1). */
push_obstacks
(
&
permanent_obstack
,
&
permanent_obstack
);
if
(
type
==
NULL_TREE
)
exp
=
null_pointer_node
;
else
if
(
is_compiled_class
(
type
))
exp
=
build_class_ref
(
type
);
else
exp
=
fold
(
build
(
PLUS_EXPR
,
ptr_type_node
,
build_utf8_ref
(
build_internal_class_name
(
type
)),
size_one_node
));
pop_obstacks
();
return
exp
;
}
/* if there are any handlers for this range, isssue end of range,
/* if there are any handlers for this range, isssue end of range,
and then all handler blocks */
and then all handler blocks */
void
void
...
@@ -193,24 +225,8 @@ expand_end_java_handler (range)
...
@@ -193,24 +225,8 @@ expand_end_java_handler (range)
expand_start_all_catch
();
expand_start_all_catch
();
for
(
;
handler
!=
NULL_TREE
;
handler
=
TREE_CHAIN
(
handler
))
for
(
;
handler
!=
NULL_TREE
;
handler
=
TREE_CHAIN
(
handler
))
{
{
tree
type
=
TREE_PURPOSE
(
handler
);
start_catch_handler
(
prepare_eh_table_type
(
TREE_PURPOSE
(
handler
)));
tree
exp
;
/* Push the thrown object on the top of the stack */
/* The "type" (metch_info) in a (Java) exception table is one:
* a) NULL - meaning match any type in a try-finally.
* b) a pointer to a (ccmpiled) class (low-order bit 0).
* c) a pointer to the Utf8Const name of the class, plus one
* (which yields a value with low-order bit 1). */
push_obstacks
(
&
permanent_obstack
,
&
permanent_obstack
);
if
(
type
==
NULL_TREE
)
exp
=
null_pointer_node
;
else
if
(
is_compiled_class
(
type
))
exp
=
build_class_ref
(
type
);
else
exp
=
fold
(
build
(
PLUS_EXPR
,
ptr_type_node
,
build_utf8_ref
(
build_internal_class_name
(
type
)),
size_one_node
));
pop_obstacks
();
start_catch_handler
(
exp
);
expand_goto
(
TREE_VALUE
(
handler
));
expand_goto
(
TREE_VALUE
(
handler
));
}
}
expand_end_all_catch
();
expand_end_all_catch
();
...
...
gcc/java/expr.c
View file @
e4de5a10
...
@@ -460,7 +460,7 @@ java_stack_dup (size, offset)
...
@@ -460,7 +460,7 @@ java_stack_dup (size, offset)
}
}
}
}
/* Calls
soft_at
hrow. Discard the contents of the value stack. */
/* Calls
_Jv_T
hrow. Discard the contents of the value stack. */
tree
tree
build_java_athrow
(
node
)
build_java_athrow
(
node
)
...
@@ -526,15 +526,16 @@ decode_newarray_type (int atype)
...
@@ -526,15 +526,16 @@ decode_newarray_type (int atype)
}
}
}
}
/* Build a call to
soft_badarrayindex(), the ArrayIndexOfBoundsException
/* Build a call to
_Jv_ThrowBadArrayIndex(), the
exception handler. */
ArrayIndexOfBoundsException
exception handler. */
static
tree
static
tree
build_java_throw_out_of_bounds_exception
()
build_java_throw_out_of_bounds_exception
(
index
)
tree
index
;
{
{
tree
node
=
build
(
CALL_EXPR
,
int_type_node
,
tree
node
=
build
(
CALL_EXPR
,
int_type_node
,
build_address_of
(
soft_badarrayindex_node
),
build_address_of
(
soft_badarrayindex_node
),
NULL_TREE
,
NULL_TREE
);
build_tree_list
(
NULL_TREE
,
index
),
NULL_TREE
);
TREE_SIDE_EFFECTS
(
node
)
=
1
;
/* Allows expansion within ANDIF */
TREE_SIDE_EFFECTS
(
node
)
=
1
;
/* Allows expansion within ANDIF */
return
(
node
);
return
(
node
);
}
}
...
@@ -629,7 +630,7 @@ build_java_arrayaccess (array, type, index)
...
@@ -629,7 +630,7 @@ build_java_arrayaccess (array, type, index)
if
(
!
integer_zerop
(
test
))
if
(
!
integer_zerop
(
test
))
{
{
throw
=
build
(
TRUTH_ANDIF_EXPR
,
int_type_node
,
test
,
throw
=
build
(
TRUTH_ANDIF_EXPR
,
int_type_node
,
test
,
build_java_throw_out_of_bounds_exception
());
build_java_throw_out_of_bounds_exception
(
index
));
/* allows expansion within COMPOUND */
/* allows expansion within COMPOUND */
TREE_SIDE_EFFECTS
(
throw
)
=
1
;
TREE_SIDE_EFFECTS
(
throw
)
=
1
;
}
}
...
@@ -677,7 +678,7 @@ build_java_check_indexed_type (array_node, indexed_type)
...
@@ -677,7 +678,7 @@ build_java_check_indexed_type (array_node, indexed_type)
return
indexed_type
;
return
indexed_type
;
}
}
/* newarray triggers a call to
soft_newa
rray. This function should be called
/* newarray triggers a call to
_Jv_NewA
rray. This function should be called
with an integer code (the type of array to create) and get from the stack
with an integer code (the type of array to create) and get from the stack
the size of the dimmension. */
the size of the dimmension. */
...
@@ -706,7 +707,7 @@ build_anewarray (class_type, length)
...
@@ -706,7 +707,7 @@ build_anewarray (class_type, length)
tree
class_type
;
tree
class_type
;
tree
length
;
tree
length
;
{
{
tree
type
=
build_java_array_type
(
promote_type
(
class_type
)
,
tree
type
=
build_java_array_type
(
class_type
,
TREE_CODE
(
length
)
==
INTEGER_CST
TREE_CODE
(
length
)
==
INTEGER_CST
?
TREE_INT_CST_LOW
(
length
)
?
TREE_INT_CST_LOW
(
length
)
:
-
1
);
:
-
1
);
...
@@ -719,9 +720,9 @@ build_anewarray (class_type, length)
...
@@ -719,9 +720,9 @@ build_anewarray (class_type, length)
NULL_TREE
);
NULL_TREE
);
}
}
/* Generates a call to
multianewarray. multianewarray expects a class pointer,
/* Generates a call to
_Jv_NewMultiArray. multianewarray expects a
a number of dimensions and the matching number of dimensions. The argument
class pointer, a number of dimensions and the matching number of
list is NULL terminated. */
dimensions. The argument
list is NULL terminated. */
void
void
expand_java_multianewarray
(
class_type
,
ndim
)
expand_java_multianewarray
(
class_type
,
ndim
)
...
@@ -829,8 +830,8 @@ expand_java_array_length ()
...
@@ -829,8 +830,8 @@ expand_java_array_length ()
push_value
(
build_java_arraynull_check
(
array
,
length
,
int_type_node
));
push_value
(
build_java_arraynull_check
(
array
,
length
,
int_type_node
));
}
}
/* Emit code for the call to
soft_monitor{enter,exit}. CALL can be either
/* Emit code for the call to
_Jv_Monitor{Enter,Exit}. CALL can be
soft_monitorenter_node or soft_monitorexit_node. */
either
soft_monitorenter_node or soft_monitorexit_node. */
tree
tree
build_java_monitor
(
call
,
object
)
build_java_monitor
(
call
,
object
)
...
@@ -1147,6 +1148,18 @@ lookup_label (pc)
...
@@ -1147,6 +1148,18 @@ lookup_label (pc)
}
}
}
}
/* Generate a unique name for the purpose of loops and switches
labels, and try-catch-finally blocks label or temporary variables. */
tree
generate_name
()
{
static
int
l_number
=
0
;
char
buff
[
20
];
sprintf
(
buff
,
"$L%d"
,
l_number
++
);
return
get_identifier
(
buff
);
}
tree
tree
create_label_decl
(
name
)
create_label_decl
(
name
)
tree
name
;
tree
name
;
...
@@ -1175,7 +1188,6 @@ note_label (current_pc, target_pc)
...
@@ -1175,7 +1188,6 @@ note_label (current_pc, target_pc)
/* Emit code to jump to TARGET_PC if VALUE1 CONDITION VALUE2,
/* Emit code to jump to TARGET_PC if VALUE1 CONDITION VALUE2,
where CONDITION is one of one the compare operators. */
where CONDITION is one of one the compare operators. */
void
void
expand_compare
(
condition
,
value1
,
value2
,
target_pc
)
expand_compare
(
condition
,
value1
,
value2
,
target_pc
)
enum
tree_code
condition
;
enum
tree_code
condition
;
...
@@ -1279,7 +1291,14 @@ pop_arguments (arg_types)
...
@@ -1279,7 +1291,14 @@ pop_arguments (arg_types)
if
(
TREE_CODE
(
arg_types
)
==
TREE_LIST
)
if
(
TREE_CODE
(
arg_types
)
==
TREE_LIST
)
{
{
tree
tail
=
pop_arguments
(
TREE_CHAIN
(
arg_types
));
tree
tail
=
pop_arguments
(
TREE_CHAIN
(
arg_types
));
return
tree_cons
(
NULL_TREE
,
pop_value
(
TREE_VALUE
(
arg_types
)),
tail
);
tree
type
=
TREE_VALUE
(
arg_types
);
tree
arg
=
pop_value
(
type
);
#ifdef PROMOTE_PROTOTYPES
if
(
TYPE_PRECISION
(
type
)
<
TYPE_PRECISION
(
integer_type_node
)
&&
INTEGRAL_TYPE_P
(
type
))
arg
=
convert
(
integer_type_node
,
arg
);
#endif
return
tree_cons
(
NULL_TREE
,
arg
,
tail
);
}
}
abort
();
abort
();
}
}
...
@@ -1490,17 +1509,6 @@ expand_invoke (opcode, method_ref_index, nargs)
...
@@ -1490,17 +1509,6 @@ expand_invoke (opcode, method_ref_index, nargs)
arg_list
=
pop_arguments
(
TYPE_ARG_TYPES
(
method_type
));
arg_list
=
pop_arguments
(
TYPE_ARG_TYPES
(
method_type
));
flush_quick_stack
();
flush_quick_stack
();
if
(
opcode
==
OPCODE_invokestatic
||
opcode
==
OPCODE_invokespecial
&&
!
inherits_from_p
(
current_class
,
self_type
))
{
/* FIXME probably not needed for invokespecial if done by NEW. */
/* Ensure self_type is initialized. */
func
=
build
(
CALL_EXPR
,
void_type_node
,
soft_initclass_node
,
build_tree_list
(
NULL_TREE
,
build_class_ref
(
self_type
)),
NULL_TREE
);
expand_expr_stmt
(
func
);
}
func
=
NULL_TREE
;
func
=
NULL_TREE
;
if
(
opcode
==
OPCODE_invokestatic
||
opcode
==
OPCODE_invokespecial
if
(
opcode
==
OPCODE_invokestatic
||
opcode
==
OPCODE_invokespecial
||
(
opcode
==
OPCODE_invokevirtual
||
(
opcode
==
OPCODE_invokevirtual
...
@@ -1515,9 +1523,9 @@ expand_invoke (opcode, method_ref_index, nargs)
...
@@ -1515,9 +1523,9 @@ expand_invoke (opcode, method_ref_index, nargs)
func
=
build_invokevirtual
(
dtable
,
method
);
func
=
build_invokevirtual
(
dtable
,
method
);
else
else
{
{
/* We expand invokeinterface here.
soft_lookupinterfacemethod () will
/* We expand invokeinterface here.
ensure that the selected method exists, is public and not abstract
_Jv_LookupInterfaceMethod() will ensure that the selected
nor static. */
method exists, is public and not abstract
nor static. */
tree
lookup_arg
;
tree
lookup_arg
;
...
@@ -1543,12 +1551,6 @@ expand_invoke (opcode, method_ref_index, nargs)
...
@@ -1543,12 +1551,6 @@ expand_invoke (opcode, method_ref_index, nargs)
call
=
build
(
CALL_EXPR
,
TREE_TYPE
(
method_type
),
func
,
arg_list
,
NULL_TREE
);
call
=
build
(
CALL_EXPR
,
TREE_TYPE
(
method_type
),
func
,
arg_list
,
NULL_TREE
);
TREE_SIDE_EFFECTS
(
call
)
=
1
;
TREE_SIDE_EFFECTS
(
call
)
=
1
;
if
(
opcode
==
OPCODE_invokestatic
||
opcode
==
OPCODE_invokespecial
)
{
/* FIXME probably not needed for invokespecial if done by NEW. */
/* Ensure self_type is initialized. */
call
=
build_class_init
(
self_type
,
call
);
}
if
(
TREE_CODE
(
TREE_TYPE
(
method_type
))
==
VOID_TYPE
)
if
(
TREE_CODE
(
TREE_TYPE
(
method_type
))
==
VOID_TYPE
)
expand_expr_stmt
(
call
);
expand_expr_stmt
(
call
);
else
else
...
@@ -1600,7 +1602,7 @@ expand_java_field_op (is_static, is_putting, field_ref_index)
...
@@ -1600,7 +1602,7 @@ expand_java_field_op (is_static, is_putting, field_ref_index)
if
(
is_error
)
if
(
is_error
)
{
{
if
(
!
is_putting
)
if
(
!
is_putting
)
push_value
(
convert
(
promote_type
(
field_type
)
,
integer_zero_node
));
push_value
(
convert
(
field_type
,
integer_zero_node
));
flush_quick_stack
();
flush_quick_stack
();
return
;
return
;
}
}
...
@@ -1610,7 +1612,7 @@ expand_java_field_op (is_static, is_putting, field_ref_index)
...
@@ -1610,7 +1612,7 @@ expand_java_field_op (is_static, is_putting, field_ref_index)
this is also needed to avoid circularities in the implementation
this is also needed to avoid circularities in the implementation
of these fields in libjava. */
of these fields in libjava. */
if
(
field_name
==
TYPE_identifier_node
&&
!
is_putting
if
(
field_name
==
TYPE_identifier_node
&&
!
is_putting
&&
field_type
==
class_
type_nod
e
&&
field_type
==
class_
ptr_typ
e
&&
strncmp
(
self_name
,
"java.lang."
,
10
)
==
0
)
&&
strncmp
(
self_name
,
"java.lang."
,
10
)
==
0
)
{
{
char
*
class_name
=
self_name
+
10
;
char
*
class_name
=
self_name
+
10
;
...
@@ -1693,6 +1695,8 @@ java_lang_expand_expr (exp, target, tmode, modifier)
...
@@ -1693,6 +1695,8 @@ java_lang_expand_expr (exp, target, tmode, modifier)
tree
type
=
TREE_TYPE
(
exp
);
tree
type
=
TREE_TYPE
(
exp
);
register
enum
machine_mode
mode
=
TYPE_MODE
(
type
);
register
enum
machine_mode
mode
=
TYPE_MODE
(
type
);
int
unsignedp
=
TREE_UNSIGNED
(
type
);
int
unsignedp
=
TREE_UNSIGNED
(
type
);
tree
node
,
current
;
int
has_finally_p
;
switch
(
TREE_CODE
(
exp
))
switch
(
TREE_CODE
(
exp
))
{
{
...
@@ -1719,6 +1723,61 @@ java_lang_expand_expr (exp, target, tmode, modifier)
...
@@ -1719,6 +1723,61 @@ java_lang_expand_expr (exp, target, tmode, modifier)
}
}
break
;
break
;
case
SWITCH_EXPR
:
java_expand_switch
(
exp
);
return
const0_rtx
;
case
TRY_EXPR
:
/* We expand a try[-catch][-finally] block */
/* Expand the try block */
expand_eh_region_start
();
expand_expr_stmt
(
TREE_OPERAND
(
exp
,
0
));
expand_start_all_catch
();
has_finally_p
=
(
TREE_OPERAND
(
exp
,
2
)
?
1
:
0
);
/* Expand all catch clauses (EH handlers) */
for
(
current
=
TREE_OPERAND
(
exp
,
1
);
current
;
current
=
TREE_CHAIN
(
current
))
{
extern
rtx
return_label
;
tree
type
;
/* If we have a finally, the last exception handler is the
one that is supposed to catch everything. */
if
(
has_finally_p
&&
!
TREE_CHAIN
(
current
))
type
=
NULL_TREE
;
else
{
tree
catch
=
java_get_catch_block
(
current
,
has_finally_p
);
tree
decl
=
BLOCK_EXPR_DECLS
(
catch
);
type
=
TREE_TYPE
(
TREE_TYPE
(
decl
));
}
start_catch_handler
(
prepare_eh_table_type
(
type
));
expand_expr_stmt
(
TREE_OPERAND
(
current
,
0
));
/* Need to expand a goto to the end of the function here,
but not for the catch everything handler. */
if
(
type
)
{
if
(
return_label
)
emit_jump
(
return_label
);
else
fatal
(
"No return_label for this function - "
"java_lang_expand_expr"
);
}
end_catch_handler
();
}
/* Expand the finally block, if any */
if
(
has_finally_p
)
{
tree
finally
=
TREE_OPERAND
(
exp
,
2
);
emit_label
(
label_rtx
(
FINALLY_EXPR_LABEL
(
finally
)));
expand_expr_stmt
(
FINALLY_EXPR_BLOCK
(
finally
));
}
expand_end_all_catch
();
break
;
default
:
default
:
fatal
(
"Can't expand '%s' tree - java_lang_expand_expr"
,
fatal
(
"Can't expand '%s' tree - java_lang_expand_expr"
,
tree_code_name
[
TREE_CODE
(
exp
)]);
tree_code_name
[
TREE_CODE
(
exp
)]);
...
@@ -1984,6 +2043,15 @@ process_jvm_instruction (PC, byte_ops, length)
...
@@ -1984,6 +2043,15 @@ process_jvm_instruction (PC, byte_ops, length)
{
{
char
*
opname
;
/* Temporary ??? */
char
*
opname
;
/* Temporary ??? */
int
oldpc
=
PC
;
/* PC at instruction start. */
int
oldpc
=
PC
;
/* PC at instruction start. */
/* If the instruction is at the beginning of a exception handler,
replace the top of the stack with the thrown object reference */
if
(
instruction_bits
[
PC
]
&
BCODE_EXCEPTION_TARGET
)
{
pop_value
(
ptr_type_node
);
push_value
(
soft_exceptioninfo_call_node
);
}
switch
(
byte_ops
[
PC
++
])
switch
(
byte_ops
[
PC
++
])
{
{
#define JAVAOP(OPNAME, OPCODE, OPKIND, OPERAND_TYPE, OPERAND_VALUE) \
#define JAVAOP(OPNAME, OPCODE, OPKIND, OPERAND_TYPE, OPERAND_VALUE) \
...
...
gcc/java/gjavah.c
View file @
e4de5a10
...
@@ -84,11 +84,21 @@ static JCF_u2 last_access;
...
@@ -84,11 +84,21 @@ static JCF_u2 last_access;
#define ACC_VISIBILITY (ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED)
#define ACC_VISIBILITY (ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED)
int
seen_fields
=
0
;
/* We keep a linked list of all method names we have seen. This lets
us determine if a method name and a field name are in conflict. */
struct
method_name
{
unsigned
char
*
name
;
int
length
;
struct
method_name
*
next
;
};
/* List of method names we've seen. */
static
struct
method_name
*
method_name_list
;
static
void
print_field_info
PROTO
((
FILE
*
,
JCF
*
,
int
,
int
,
JCF_u2
));
static
void
print_field_info
PROTO
((
FILE
*
,
JCF
*
,
int
,
int
,
JCF_u2
));
static
void
print_method_info
PROTO
((
FILE
*
,
JCF
*
,
int
,
int
,
JCF_u2
));
static
void
print_method_info
PROTO
((
FILE
*
,
JCF
*
,
int
,
int
,
JCF_u2
));
static
void
print_c_decl
PROTO
((
FILE
*
,
JCF
*
,
int
,
int
,
JCF_u2
,
int
));
static
void
print_c_decl
PROTO
((
FILE
*
,
JCF
*
,
int
,
int
,
JCF_u2
,
int
,
char
*
));
JCF_u2
current_field_name
;
JCF_u2
current_field_name
;
JCF_u2
current_field_value
;
JCF_u2
current_field_value
;
...
@@ -99,9 +109,15 @@ JCF_u2 current_field_flags;
...
@@ -99,9 +109,15 @@ JCF_u2 current_field_flags;
( current_field_name = (NAME), current_field_signature = (SIGNATURE), \
( current_field_name = (NAME), current_field_signature = (SIGNATURE), \
current_field_flags = (ACCESS_FLAGS), current_field_value = 0)
current_field_flags = (ACCESS_FLAGS), current_field_value = 0)
/* We pass over fields twice. The first time we just note the start
of the methods. Then we go back and parse the fields for real.
This is ugly. */
static
int
field_pass
;
#define HANDLE_END_FIELD() \
#define HANDLE_END_FIELD() \
print_field_info (out, jcf, current_field_name, current_field_signature, \
if (field_pass) print_field_info (out, jcf, current_field_name, \
current_field_flags);
current_field_signature, \
current_field_flags);
#define HANDLE_CONSTANTVALUE(VALUEINDEX) current_field_value = (VALUEINDEX)
#define HANDLE_CONSTANTVALUE(VALUEINDEX) current_field_value = (VALUEINDEX)
...
@@ -242,11 +258,29 @@ generate_access (stream, flags)
...
@@ -242,11 +258,29 @@ generate_access (stream, flags)
}
}
}
}
/* See if NAME is already the name of a method. */
static
int
name_is_method_p
(
name
,
length
)
unsigned
char
*
name
;
int
length
;
{
struct
method_name
*
p
;
for
(
p
=
method_name_list
;
p
!=
NULL
;
p
=
p
->
next
)
{
if
(
p
->
length
==
length
&&
!
memcmp
(
p
->
name
,
name
,
length
))
return
1
;
}
return
0
;
}
static
void
static
void
DEFUN
(
print_field_info
,
(
stream
,
jcf
,
name_index
,
sig_index
,
flags
),
DEFUN
(
print_field_info
,
(
stream
,
jcf
,
name_index
,
sig_index
,
flags
),
FILE
*
stream
AND
JCF
*
jcf
FILE
*
stream
AND
JCF
*
jcf
AND
int
name_index
AND
int
sig_index
AND
JCF_u2
flags
)
AND
int
name_index
AND
int
sig_index
AND
JCF_u2
flags
)
{
{
char
*
override
=
NULL
;
if
(
flags
&
ACC_FINAL
)
if
(
flags
&
ACC_FINAL
)
{
{
if
(
current_field_value
>
0
)
if
(
current_field_value
>
0
)
...
@@ -305,12 +339,42 @@ DEFUN(print_field_info, (stream, jcf, name_index, sig_index, flags),
...
@@ -305,12 +339,42 @@ DEFUN(print_field_info, (stream, jcf, name_index, sig_index, flags),
generate_access
(
stream
,
flags
);
generate_access
(
stream
,
flags
);
fputs
(
" "
,
out
);
fputs
(
" "
,
out
);
if
(
flags
&
ACC_STATIC
)
if
(
(
flags
&
ACC_STATIC
)
)
fputs
(
"static "
,
out
);
fputs
(
"static "
,
out
);
print_c_decl
(
out
,
jcf
,
name_index
,
sig_index
,
flags
,
0
);
if
(
JPOOL_TAG
(
jcf
,
name_index
)
!=
CONSTANT_Utf8
)
{
fprintf
(
stream
,
"<not a UTF8 constant>"
);
found_error
=
1
;
}
else
{
unsigned
char
*
name
=
JPOOL_UTF_DATA
(
jcf
,
name_index
);
int
length
=
JPOOL_UTF_LENGTH
(
jcf
,
name_index
);
if
(
name_is_method_p
(
name
,
length
))
{
/* This field name matches a method. So override the name
with a dummy name. This is yucky, but it isn't clear
what else to do. FIXME: if the field is static, then
we'll be in real trouble. */
if
((
flags
&
ACC_STATIC
))
{
fprintf
(
stderr
,
"static field has same name as method
\n
"
);
found_error
=
1
;
}
override
=
(
char
*
)
malloc
(
length
+
3
);
memcpy
(
override
,
name
,
length
);
strcpy
(
override
+
length
,
"__"
);
}
}
print_c_decl
(
out
,
jcf
,
name_index
,
sig_index
,
flags
,
0
,
override
);
fputs
(
";
\n
"
,
out
);
fputs
(
";
\n
"
,
out
);
if
(
!
(
flags
&
ACC_STATIC
))
seen_fields
++
;
if
(
override
)
free
(
override
);
}
}
static
void
static
void
...
@@ -320,6 +384,7 @@ DEFUN(print_method_info, (stream, jcf, name_index, sig_index, flags),
...
@@ -320,6 +384,7 @@ DEFUN(print_method_info, (stream, jcf, name_index, sig_index, flags),
{
{
unsigned
char
*
str
;
unsigned
char
*
str
;
int
length
,
is_init
=
0
;
int
length
,
is_init
=
0
;
char
*
override
=
NULL
;
if
(
JPOOL_TAG
(
jcf
,
name_index
)
!=
CONSTANT_Utf8
)
if
(
JPOOL_TAG
(
jcf
,
name_index
)
!=
CONSTANT_Utf8
)
fprintf
(
stream
,
"<not a UTF8 constant>"
);
fprintf
(
stream
,
"<not a UTF8 constant>"
);
...
@@ -334,13 +399,33 @@ DEFUN(print_method_info, (stream, jcf, name_index, sig_index, flags),
...
@@ -334,13 +399,33 @@ DEFUN(print_method_info, (stream, jcf, name_index, sig_index, flags),
else
else
return
;
return
;
}
}
else
{
struct
method_name
*
nn
;
nn
=
(
struct
method_name
*
)
malloc
(
sizeof
(
struct
method_name
));
nn
->
name
=
(
char
*
)
malloc
(
length
);
memcpy
(
nn
->
name
,
str
,
length
);
nn
->
length
=
length
;
nn
->
next
=
method_name_list
;
method_name_list
=
nn
;
}
/* We can't generate a method whose name is a C++ reserved word.
/* We can't generate a method whose name is a C++ reserved word.
For now the only problem has been `delete'; add more here as
For now the only problem has been `delete'; add more here as
required. FIXME: we need a better solution than just ignoring
required. We can't just ignore the function, because that will
the method. */
cause incorrect code to be generated if the function is virtual
(not only for calls to this function for for other functions
after it in the vtbl). So we give it a dummy name instead. */
if
(
!
utf8_cmp
(
str
,
length
,
"delete"
))
if
(
!
utf8_cmp
(
str
,
length
,
"delete"
))
return
;
{
/* If the method is static, we can safely skip it. If we don't
skip it then we'll have problems since the mangling will be
wrong. FIXME. */
if
((
flags
&
ACC_STATIC
))
return
;
override
=
"__dummy_delete"
;
}
generate_access
(
stream
,
flags
);
generate_access
(
stream
,
flags
);
...
@@ -353,7 +438,7 @@ DEFUN(print_method_info, (stream, jcf, name_index, sig_index, flags),
...
@@ -353,7 +438,7 @@ DEFUN(print_method_info, (stream, jcf, name_index, sig_index, flags),
if
(
!
is_init
)
if
(
!
is_init
)
fputs
(
"virtual "
,
out
);
fputs
(
"virtual "
,
out
);
}
}
print_c_decl
(
out
,
jcf
,
name_index
,
sig_index
,
flags
,
is_init
);
print_c_decl
(
out
,
jcf
,
name_index
,
sig_index
,
flags
,
is_init
,
override
);
/* FIXME: it would be nice to decompile small methods here. That
/* FIXME: it would be nice to decompile small methods here. That
would allow for inlining. */
would allow for inlining. */
...
@@ -361,154 +446,185 @@ DEFUN(print_method_info, (stream, jcf, name_index, sig_index, flags),
...
@@ -361,154 +446,185 @@ DEFUN(print_method_info, (stream, jcf, name_index, sig_index, flags),
fprintf
(
out
,
";
\n
"
);
fprintf
(
out
,
";
\n
"
);
}
}
/* Print one piece of a signature. Returns pointer to next parseable
character on success, NULL on error. */
static
unsigned
char
*
decode_signature_piece
(
stream
,
signature
,
limit
,
need_space
)
FILE
*
stream
;
unsigned
char
*
signature
,
*
limit
;
int
*
need_space
;
{
char
*
ctype
;
switch
(
signature
[
0
])
{
case
'['
:
for
(
signature
++
;
(
signature
<
limit
&&
*
signature
>=
'0'
&&
*
signature
<=
'9'
);
signature
++
)
;
switch
(
*
signature
)
{
case
'B'
:
ctype
=
"jbyteArray"
;
goto
printit
;
case
'C'
:
ctype
=
"jcharArray"
;
goto
printit
;
case
'D'
:
ctype
=
"jdoubleArray"
;
goto
printit
;
case
'F'
:
ctype
=
"jfloatArray"
;
goto
printit
;
case
'I'
:
ctype
=
"jintArray"
;
goto
printit
;
case
'S'
:
ctype
=
"jshortArray"
;
goto
printit
;
case
'J'
:
ctype
=
"jlongArray"
;
goto
printit
;
case
'Z'
:
ctype
=
"jbooleanArray"
;
goto
printit
;
case
'['
:
ctype
=
"jobjectArray"
;
goto
printit
;
case
'L'
:
/* We have to generate a reference to JArray here,
so that our output matches what the compiler
does. */
++
signature
;
fputs
(
"JArray<"
,
stream
);
while
(
signature
<
limit
&&
*
signature
!=
';'
)
{
int
ch
=
UTF8_GET
(
signature
,
limit
);
if
(
ch
==
'/'
)
fputs
(
"::"
,
stream
);
else
jcf_print_char
(
stream
,
ch
);
}
fputs
(
" *> *"
,
stream
);
*
need_space
=
0
;
++
signature
;
break
;
default
:
/* Unparseable signature. */
return
NULL
;
}
break
;
case
'('
:
case
')'
:
/* This shouldn't happen. */
return
NULL
;
case
'B'
:
ctype
=
"jbyte"
;
goto
printit
;
case
'C'
:
ctype
=
"jchar"
;
goto
printit
;
case
'D'
:
ctype
=
"jdouble"
;
goto
printit
;
case
'F'
:
ctype
=
"jfloat"
;
goto
printit
;
case
'I'
:
ctype
=
"jint"
;
goto
printit
;
case
'J'
:
ctype
=
"jlong"
;
goto
printit
;
case
'S'
:
ctype
=
"jshort"
;
goto
printit
;
case
'Z'
:
ctype
=
"jboolean"
;
goto
printit
;
case
'V'
:
ctype
=
"void"
;
goto
printit
;
case
'L'
:
++
signature
;
while
(
*
signature
&&
*
signature
!=
';'
)
{
int
ch
=
UTF8_GET
(
signature
,
limit
);
if
(
ch
==
'/'
)
fputs
(
"::"
,
stream
);
else
jcf_print_char
(
stream
,
ch
);
}
fputs
(
" *"
,
stream
);
if
(
*
signature
==
';'
)
signature
++
;
*
need_space
=
0
;
break
;
default
:
*
need_space
=
1
;
jcf_print_char
(
stream
,
*
signature
++
);
break
;
printit
:
signature
++
;
*
need_space
=
1
;
fputs
(
ctype
,
stream
);
break
;
}
return
signature
;
}
static
void
static
void
DEFUN
(
print_c_decl
,
(
stream
,
jcf
,
name_index
,
signature_index
,
flags
,
is_init
),
DEFUN
(
print_c_decl
,
(
stream
,
jcf
,
name_index
,
signature_index
,
flags
,
is_init
,
name_override
),
FILE
*
stream
AND
JCF
*
jcf
FILE
*
stream
AND
JCF
*
jcf
AND
int
name_index
AND
int
signature_index
AND
JCF_u2
flags
AND
int
name_index
AND
int
signature_index
AND
JCF_u2
flags
AND
int
is_init
)
AND
int
is_init
AND
char
*
name_override
)
{
{
if
(
JPOOL_TAG
(
jcf
,
signature_index
)
!=
CONSTANT_Utf8
)
if
(
JPOOL_TAG
(
jcf
,
signature_index
)
!=
CONSTANT_Utf8
)
fprintf
(
stream
,
"<not a UTF8 constant>"
);
{
fprintf
(
stream
,
"<not a UTF8 constant>"
);
found_error
=
1
;
}
else
else
{
{
int
length
=
JPOOL_UTF_LENGTH
(
jcf
,
signature_index
);
int
length
=
JPOOL_UTF_LENGTH
(
jcf
,
signature_index
);
unsigned
char
*
str0
=
JPOOL_UTF_DATA
(
jcf
,
signature_index
);
unsigned
char
*
str0
=
JPOOL_UTF_DATA
(
jcf
,
signature_index
);
register
unsigned
char
*
str
=
str0
;
register
unsigned
char
*
str
=
str0
;
unsigned
char
*
limit
=
str
+
length
;
unsigned
char
*
limit
=
str
+
length
;
int
j
;
char
*
ctype
;
int
need_space
=
0
;
int
need_space
=
0
;
int
is_method
=
str
[
0
]
==
'('
;
int
is_method
=
str
[
0
]
==
'('
;
unsigned
char
*
next
;
if
(
is_method
)
/* If printing a method, skip to the return signature and print
that first. However, there is no return value if this is a
constructor. */
if
(
is_method
&&
!
is_init
)
{
{
/* Skip to the return signature, and print that first.
while
(
str
<
limit
)
However, don't do this is we are printing a construtcor.
*/
if
(
is_init
)
{
{
str
=
str0
+
1
;
int
ch
=
*
str
++
;
/* FIXME: Most programmers love Celtic knots because
if
(
ch
==
')'
)
they see their own code in the interconnected loops.
break
;
That is, this is spaghetti. */
goto
have_constructor
;
}
else
{
while
(
str
<
limit
)
{
int
ch
=
*
str
++
;
if
(
ch
==
')'
)
break
;
}
}
}
}
}
again
:
/* If printing a field or an ordinary method, then print the
while
(
str
<
limit
)
"return value" now. */
if
(
!
is_method
||
!
is_init
)
{
{
switch
(
str
[
0
])
next
=
decode_signature_piece
(
stream
,
str
,
limit
,
&
need_space
);
if
(
!
next
)
{
{
case
'['
:
fprintf
(
stderr
,
"unparseable signature: `%s'
\n
"
,
str0
);
for
(
str
++
;
str
<
limit
&&
*
str
>=
'0'
&&
*
str
<=
'9'
;
str
++
)
found_error
=
1
;
;
switch
(
*
str
)
{
case
'B'
:
ctype
=
"jbyteArray"
;
goto
printit
;
case
'C'
:
ctype
=
"jcharArray"
;
goto
printit
;
case
'D'
:
ctype
=
"jdoubleArray"
;
goto
printit
;
case
'F'
:
ctype
=
"jfloatArray"
;
goto
printit
;
case
'I'
:
ctype
=
"jintArray"
;
goto
printit
;
case
'S'
:
ctype
=
"jshortArray"
;
goto
printit
;
case
'J'
:
ctype
=
"jlongArray"
;
goto
printit
;
case
'Z'
:
ctype
=
"jbooleanArray"
;
goto
printit
;
case
'['
:
ctype
=
"jobjectArray"
;
goto
printit
;
case
'L'
:
/* We have to generate a reference to JArray here,
so that our output matches what the compiler
does. */
++
str
;
fputs
(
"JArray<"
,
out
);
while
(
str
<
limit
&&
*
str
!=
';'
)
{
int
ch
=
UTF8_GET
(
str
,
limit
);
if
(
ch
==
'/'
)
fputs
(
"::"
,
stream
);
else
jcf_print_char
(
stream
,
ch
);
}
fputs
(
" *> *"
,
out
);
need_space
=
0
;
++
str
;
break
;
default
:
fprintf
(
stderr
,
"unparseable signature `%s'
\n
"
,
str0
);
found_error
=
1
;
ctype
=
"???"
;
goto
printit
;
}
break
;
case
'('
:
fputc
(
*
str
++
,
stream
);
continue
;
case
')'
:
fputc
(
*
str
++
,
stream
);
/* the return signature was printed in the first pass. */
return
;
return
;
case
'B'
:
ctype
=
"jbyte"
;
goto
printit
;
case
'C'
:
ctype
=
"jchar"
;
goto
printit
;
case
'D'
:
ctype
=
"jdouble"
;
goto
printit
;
case
'F'
:
ctype
=
"jfloat"
;
goto
printit
;
case
'I'
:
ctype
=
"jint"
;
goto
printit
;
case
'J'
:
ctype
=
"jlong"
;
goto
printit
;
case
'S'
:
ctype
=
"jshort"
;
goto
printit
;
case
'Z'
:
ctype
=
"jboolean"
;
goto
printit
;
case
'V'
:
ctype
=
"void"
;
goto
printit
;
case
'L'
:
++
str
;
while
(
*
str
&&
*
str
!=
';'
)
{
int
ch
=
UTF8_GET
(
str
,
limit
);
if
(
ch
==
'/'
)
fputs
(
"::"
,
stream
);
else
jcf_print_char
(
stream
,
ch
);
}
fputs
(
" *"
,
stream
);
if
(
*
str
==
';'
)
str
++
;
need_space
=
0
;
break
;
default
:
need_space
=
1
;
jcf_print_char
(
stream
,
*
str
++
);
break
;
printit
:
str
++
;
need_space
=
1
;
fputs
(
ctype
,
stream
);
break
;
}
}
if
(
is_method
&&
str
<
limit
&&
*
str
!=
')'
)
fputs
(
", "
,
stream
);
}
}
have_constructor
:
if
(
name_index
)
/* Now print the name of the thing. */
if
(
need_space
)
fputs
(
" "
,
stream
);
if
(
name_override
)
fputs
(
name_override
,
stream
);
else
if
(
name_index
)
{
{
if
(
need_space
)
fprintf
(
stream
,
" "
);
/* Declare constructors specially. */
/* Declare constructors specially. */
if
(
is_init
)
if
(
is_init
)
print_base_classname
(
stream
,
jcf
,
jcf
->
this_class
);
print_base_classname
(
stream
,
jcf
,
jcf
->
this_class
);
else
else
print_name
(
stream
,
jcf
,
name_index
);
print_name
(
stream
,
jcf
,
name_index
);
}
}
if
(
is_method
)
if
(
is_method
)
{
{
/* Have a method or a constructor. Print signature pieces
until done. */
fputs
(
" ("
,
stream
);
fputs
(
" ("
,
stream
);
/* Go to beginning, skipping '('. */
str
=
str0
+
1
;
str
=
str0
+
1
;
goto
again
;
/* To handle argument signatures. */
while
(
str
<
limit
&&
*
str
!=
')'
)
{
next
=
decode_signature_piece
(
stream
,
str
,
limit
,
&
need_space
);
if
(
!
next
)
{
fprintf
(
stderr
,
"unparseable signature: `%s'
\n
"
,
str0
);
found_error
=
1
;
return
;
}
if
(
next
<
limit
&&
*
next
!=
')'
)
fputs
(
", "
,
stream
);
str
=
next
;
}
fputs
(
")"
,
stream
);
}
}
}
}
}
}
...
@@ -613,6 +729,7 @@ DEFUN(process_file, (jcf, out),
...
@@ -613,6 +729,7 @@ DEFUN(process_file, (jcf, out),
JCF
*
jcf
AND
FILE
*
out
)
JCF
*
jcf
AND
FILE
*
out
)
{
{
int
code
,
i
;
int
code
,
i
;
uint32
field_start
,
method_end
;
current_jcf
=
main_jcf
=
jcf
;
current_jcf
=
main_jcf
=
jcf
;
...
@@ -700,8 +817,22 @@ DEFUN(process_file, (jcf, out),
...
@@ -700,8 +817,22 @@ DEFUN(process_file, (jcf, out),
as we see them. We have to list the methods in the same order
as we see them. We have to list the methods in the same order
that they appear in the class file, so that the Java and C++
that they appear in the class file, so that the Java and C++
vtables have the same layout. */
vtables have the same layout. */
/* We want to parse the methods first. But we need to find where
they start. So first we skip the fields, then parse the
methods. Then we parse the fields and skip the methods. FIXME:
this is ugly. */
field_pass
=
0
;
field_start
=
JCF_TELL
(
jcf
);
jcf_parse_fields
(
jcf
);
jcf_parse_fields
(
jcf
);
jcf_parse_methods
(
jcf
);
jcf_parse_methods
(
jcf
);
method_end
=
JCF_TELL
(
jcf
);
field_pass
=
1
;
JCF_SEEK
(
jcf
,
field_start
);
jcf_parse_fields
(
jcf
);
JCF_SEEK
(
jcf
,
method_end
);
jcf_parse_final_attributes
(
jcf
);
jcf_parse_final_attributes
(
jcf
);
/* Generate friend decl if we still must. */
/* Generate friend decl if we still must. */
...
...
gcc/java/jcf-parse.c
View file @
e4de5a10
...
@@ -408,7 +408,7 @@ get_class_constant (JCF *jcf , int i)
...
@@ -408,7 +408,7 @@ get_class_constant (JCF *jcf , int i)
char
*
name
=
JPOOL_UTF_DATA
(
jcf
,
name_index
);
char
*
name
=
JPOOL_UTF_DATA
(
jcf
,
name_index
);
int
nlength
=
JPOOL_UTF_LENGTH
(
jcf
,
name_index
);
int
nlength
=
JPOOL_UTF_LENGTH
(
jcf
,
name_index
);
if
(
name
[
0
]
==
'['
)
/* Handle array "classes". */
if
(
name
[
0
]
==
'['
)
/* Handle array "classes". */
type
=
parse_signature_string
(
name
,
nlength
);
type
=
TREE_TYPE
(
parse_signature_string
(
name
,
nlength
)
);
else
else
{
{
tree
cname
=
unmangle_classname
(
name
,
nlength
);
tree
cname
=
unmangle_classname
(
name
,
nlength
);
...
...
gcc/java/jcf-write.c
View file @
e4de5a10
...
@@ -35,19 +35,16 @@ The Free Software Foundation is independent of Sun Microsystems, Inc. */
...
@@ -35,19 +35,16 @@ The Free Software Foundation is independent of Sun Microsystems, Inc. */
extern
struct
obstack
temporary_obstack
;
extern
struct
obstack
temporary_obstack
;
/* The buffer allocated for bytecode for the current method. */
struct
buffer
bytecode
=
NULL_BUFFER
;
/* Make sure bytecode.data is big enough for at least N more bytes. */
/* Make sure bytecode.data is big enough for at least N more bytes. */
#define RESERVE(N) \
#define RESERVE(N) \
do { if (bytecode.ptr + (N) > bytecode.limit) buffer_grow (&bytecode, N); } while (0)
do { if (state->bytecode.ptr + (N) > state->bytecode.limit) \
buffer_grow (&state->bytecode, N); } while (0)
/* Add a 1-byte instruction/operand I to bytecode.data,
/* Add a 1-byte instruction/operand I to bytecode.data,
assuming space has already been RESERVE'd. */
assuming space has already been RESERVE'd. */
#define OP1(I) (*bytecode.ptr++ = (I))
#define OP1(I) (*
state->
bytecode.ptr++ = (I))
/* Like OP1, but I is a 2-byte big endian integer. */
/* Like OP1, but I is a 2-byte big endian integer. */
...
@@ -73,12 +70,14 @@ CPool *code_cpool;
...
@@ -73,12 +70,14 @@ CPool *code_cpool;
/* Macro to call each time we push I words on the JVM stack. */
/* Macro to call each time we push I words on the JVM stack. */
#define NOTE_PUSH(I) \
#define NOTE_PUSH(I) \
do { code_SP += (I); if (code_SP > code_SP_max) code_SP_max = code_SP; } while (0)
do { state->code_SP += (I); \
if (state->code_SP > state->code_SP_max) \
state->code_SP_max = state->code_SP; } while (0)
/* Macro to call each time we pop I words from the JVM stack. */
/* Macro to call each time we pop I words from the JVM stack. */
#define NOTE_POP(I) \
#define NOTE_POP(I) \
do {
code_SP -= (I); if (
code_SP < 0) abort(); } while (0)
do {
state->code_SP -= (I); if (state->
code_SP < 0) abort(); } while (0)
/* A chunk or segment of a .class file. */
/* A chunk or segment of a .class file. */
...
@@ -94,6 +93,103 @@ struct chunk
...
@@ -94,6 +93,103 @@ struct chunk
int
size
;
int
size
;
};
};
/* Each "block" represents a label plus the bytecode instructions following.
There may be branches out of the block, but no incoming jumps, except
to the beginning of the block. */
struct
jcf_block
{
/* For blocks that that are defined, the next block (in pc order).
For blocks that are the not-yet-defined end label of a LABELED_BLOCK_EXPR,
this is the next (outer) such end label, in a stack heaed by
labeled_blocks in jcf_partial. */
struct
jcf_block
*
next
;
/* Until perform_relocations is finished, this is the maximum possible
value of the bytecode offset at the begnning of this block.
After perform_relocations, it is the actual offset (pc). */
int
pc
;
int
linenumber
;
struct
chunk
*
chunk
;
union
{
/* Set of relocations (in reverse offset order) for this block. */
struct
jcf_relocation
*
relocations
;
/* If this block is that of the not-yet-defined end label of
a LABELED_BLOCK_EXPR, where LABELED_BLOCK is that LABELED_BLOCK_EXPR. */
tree
labeled_block
;
}
u
;
};
struct
jcf_relocation
{
/* Next relocation for the current jcf_block. */
struct
jcf_relocation
*
next
;
/* The (byte) offset within the current block that needs to be relocated. */
int
offset
;
/* 0 if offset is a 4-byte relative offset.
-1 if offset is a 2-byte relative offset.
< 0 if offset is the address of an instruction with a 2-byte offset
that does not have a corresponding 4-byte offset version, in which
case the absolute value of kind is the inverted opcode.
> 0 if offset is the address of an instruction (such as jsr) with a
2-byte offset that does have a corresponding 4-byte offset version,
in which case kind is the opcode of the 4-byte version (such as jsr_w). */
int
kind
;
/* The label the relocation wants to actually transfer to. */
struct
jcf_block
*
label
;
};
/* This structure is used to contain the various pieces that will
become a .class file. */
struct
jcf_partial
{
struct
chunk
*
first
;
struct
chunk
*
chunk
;
struct
obstack
*
chunk_obstack
;
tree
current_method
;
/* List of basic blocks for the current method. */
struct
jcf_block
*
blocks
;
struct
jcf_block
*
last_block
;
struct
localvar_info
*
first_lvar
;
struct
localvar_info
*
last_lvar
;
int
lvar_count
;
CPool
cpool
;
int
linenumber_count
;
/* Until perform_relocations, this is a upper bound on the number
of bytes (so far) in the instructions for the current method. */
int
code_length
;
/* Stack of undefined ending labels for LABELED_BLOCK_EXPR. */
struct
jcf_block
*
labeled_blocks
;
/* The current stack size (stack pointer) in the current method. */
int
code_SP
;
/* The largest extent of stack size (stack pointer) in the current method. */
int
code_SP_max
;
/* Contains a mapping from local var slot number to localvar_info. */
struct
buffer
localvars
;
/* The buffer allocated for bytecode for the current jcf_block. */
struct
buffer
bytecode
;
};
static
void
generate_bytecode_insns
PROTO
((
tree
,
int
,
struct
jcf_partial
*
));
/* Utility macros for appending (big-endian) data to a buffer.
/* Utility macros for appending (big-endian) data to a buffer.
We assume a local variable 'ptr' points into where we want to
We assume a local variable 'ptr' points into where we want to
write next, and we assume enoygh space has been allocated. */
write next, and we assume enoygh space has been allocated. */
...
@@ -104,162 +200,228 @@ struct chunk
...
@@ -104,162 +200,228 @@ struct chunk
#define PUTN(P, N) (bcopy(P, ptr, N), ptr += (N))
#define PUTN(P, N) (bcopy(P, ptr, N), ptr += (N))
/* A buffer for storing line number entries for the current method. */
/* Allocate a new chunk on obstack WORK, and link it in after LAST.
struct
buffer
linenumbers
=
NULL_BUFFER
;
Set the data and size fields to DATA and SIZE, respectively.
However, if DATA is NULL and SIZE>0, allocate a buffer as well. */
struct
chunk
*
alloc_chunk
(
last
,
data
,
size
,
work
)
struct
chunk
*
last
;
unsigned
char
*
data
;
int
size
;
struct
obstack
*
work
;
{
struct
chunk
*
chunk
=
(
struct
chunk
*
)
obstack_alloc
(
work
,
sizeof
(
struct
chunk
));
if
(
data
==
NULL
&&
size
>
0
)
data
=
obstack_alloc
(
work
,
size
);
chunk
->
next
=
NULL
;
chunk
->
data
=
data
;
chunk
->
size
=
size
;
if
(
last
!=
NULL
)
last
->
next
=
chunk
;
return
chunk
;
}
unsigned
char
*
append_chunk
(
data
,
size
,
state
)
unsigned
char
*
data
;
int
size
;
struct
jcf_partial
*
state
;
{
state
->
chunk
=
alloc_chunk
(
state
->
chunk
,
data
,
size
,
state
->
chunk_obstack
);
if
(
state
->
first
==
NULL
)
state
->
first
=
state
->
chunk
;
return
state
->
chunk
->
data
;
}
void
append_chunk_copy
(
data
,
size
,
state
)
unsigned
char
*
data
;
int
size
;
struct
jcf_partial
*
state
;
{
unsigned
char
*
ptr
=
append_chunk
(
NULL
,
size
,
state
);
bcopy
(
data
,
ptr
,
size
);
}
struct
jcf_block
*
gen_jcf_label
(
state
)
struct
jcf_partial
*
state
;
{
struct
jcf_block
*
block
=
(
struct
jcf_block
*
)
obstack_alloc
(
state
->
chunk_obstack
,
sizeof
(
struct
jcf_block
));
block
->
next
=
NULL
;
block
->
linenumber
=
-
1
;
block
->
pc
=
-
1
;
return
block
;
}
void
finish_jcf_block
(
state
)
struct
jcf_partial
*
state
;
{
struct
jcf_block
*
block
=
state
->
last_block
;
struct
jcf_relocation
*
reloc
;
int
pc
=
state
->
code_length
;
append_chunk_copy
(
state
->
bytecode
.
data
,
BUFFER_LENGTH
(
&
state
->
bytecode
),
state
);
BUFFER_RESET
(
&
state
->
bytecode
);
block
->
chunk
=
state
->
chunk
;
/* Calculate code_length to the maximum value it can have. */
pc
+=
block
->
chunk
->
size
;
for
(
reloc
=
block
->
u
.
relocations
;
reloc
!=
NULL
;
reloc
=
reloc
->
next
)
{
int
kind
=
reloc
->
kind
;
if
(
kind
>
0
)
pc
+=
2
;
/* 2-byte offset may grow to 4-byte offset */
else
if
(
kind
<
-
1
)
pc
+=
5
;
/* May need to add a goto_w. */
}
state
->
code_length
=
pc
;
}
void
define_jcf_label
(
label
,
state
)
struct
jcf_block
*
label
;
struct
jcf_partial
*
state
;
{
if
(
state
->
last_block
!=
NULL
)
finish_jcf_block
(
state
);
label
->
pc
=
state
->
code_length
;
if
(
state
->
blocks
==
NULL
)
state
->
blocks
=
label
;
else
state
->
last_block
->
next
=
label
;
state
->
last_block
=
label
;
label
->
next
=
NULL
;
label
->
u
.
relocations
=
NULL
;
}
struct
jcf_block
*
get_jcf_label_here
(
state
)
struct
jcf_partial
*
state
;
{
if
(
state
->
last_block
!=
NULL
&&
BUFFER_LENGTH
(
&
state
->
bytecode
)
==
0
)
return
state
->
last_block
;
else
{
struct
jcf_block
*
label
=
gen_jcf_label
(
state
);
define_jcf_label
(
label
,
state
);
return
label
;
}
}
/* Append a line number entry for the given PC and LINE into
/* Note a line number entry for the current PC and given LINE. */
linenumbers.data. This will later before a LineNumberTable attribute. */
void
void
put_linenumber
(
pc
,
line
)
put_linenumber
(
line
,
state
)
int
pc
,
line
;
int
line
;
struct
jcf_partial
*
state
;
{
{
register
unsigned
char
*
ptr
;
(
get_jcf_label_here
(
state
))
->
linenumber
=
line
;
if
(
linenumbers
.
ptr
==
linenumbers
.
limit
)
state
->
linenumber_count
++
;
buffer_grow
(
&
linenumbers
,
4
);
ptr
=
linenumbers
.
ptr
;
PUT2
(
pc
);
PUT2
(
line
);
linenumbers
.
ptr
=
ptr
;
}
}
/* The index of jvm local variable allocated for this DECL.
/* The index of jvm local variable allocated for this DECL.
This is assign when generating .class files;
This is assign
ed
when generating .class files;
contrast DECL_LOCAL_SLOT_NUMBER wh
ci
h is set when *reading* a .class file.
contrast DECL_LOCAL_SLOT_NUMBER wh
ic
h is set when *reading* a .class file.
(We don't allocate DECL_LANG_SPECIFIC for locals from Java sourc code.) */
(We don't allocate DECL_LANG_SPECIFIC for locals from Java sourc code.) */
#define DECL_LOCAL_INDEX(DECL) DECL_ALIGN(DECL)
#define DECL_LOCAL_INDEX(DECL) DECL_ALIGN(DECL)
struct
localvar_info
struct
localvar_info
{
{
tree
decl
;
struct
localvar_info
*
next
;
int
start_pc
;
tree
decl
;
struct
jcf_block
*
start_label
;
/* Offset in LocalVariableTable. */
struct
jcf_block
*
end_label
;
int
debug_offset
;
};
};
struct
buffer
localvars
=
NULL_BUFFER
;
#define localvar_buffer ((struct localvar_info**) state->localvars.data)
#define localvar_max \
#define localvar_buffer ((struct localvar_info*) localvars.data)
((struct localvar_info**) state->localvars.ptr - localvar_buffer)
#define localvar_max ((struct localvar_info*) localvars.ptr - localvar_buffer)
/* A buffer for storing LocalVariableTable entries entries. */
struct
buffer
localvartable
=
NULL_BUFFER
;
int
int
localvar_alloc
(
decl
,
sta
rt_pc
)
localvar_alloc
(
decl
,
sta
te
)
tree
decl
;
tree
decl
;
int
start_pc
;
struct
jcf_partial
*
state
;
{
{
struct
jcf_block
*
start_label
=
get_jcf_label_here
(
state
);
int
wide
=
TYPE_IS_WIDE
(
TREE_TYPE
(
decl
));
int
wide
=
TYPE_IS_WIDE
(
TREE_TYPE
(
decl
));
int
index
;
int
index
;
register
struct
localvar_info
*
info
=
(
struct
localvar_info
*
)
localvars
.
data
;
register
struct
localvar_info
*
info
;
register
struct
localvar_info
*
limit
=
(
struct
localvar_info
*
)
localvars
.
ptr
;
register
struct
localvar_info
**
ptr
=
localvar_buffer
;
for
(
index
=
0
;
info
<
limit
;
index
++
,
info
++
)
register
struct
localvar_info
**
limit
=
(
struct
localvar_info
**
)
state
->
localvars
.
ptr
;
for
(
index
=
0
;
ptr
<
limit
;
index
++
,
ptr
++
)
{
{
if
(
info
->
decl
==
NULL_TREE
if
(
ptr
[
0
]
==
NULL
&&
(
!
wide
||
(
info
+
1
)
->
decl
==
NULL_TREE
))
&&
(
!
wide
||
(
(
ptr
+
1
)
<
limit
&&
ptr
[
1
]
==
NULL
)
))
break
;
break
;
}
}
if
(
info
==
limit
)
if
(
ptr
==
limit
)
{
{
buffer_grow
(
&
localvars
,
sizeof
(
struct
localvar_info
));
buffer_grow
(
&
state
->
localvars
,
2
*
sizeof
(
struct
localvar_info
*
));
info
=
(
struct
localvar_info
*
)
localvars
.
data
+
index
;
ptr
=
(
struct
localvar_info
**
)
state
->
localvars
.
data
+
index
;
localvars
.
ptr
=
(
unsigned
char
*
)
(
info
+
1
+
wide
);
state
->
localvars
.
ptr
=
(
unsigned
char
*
)
(
ptr
+
1
+
wide
);
}
}
info
->
decl
=
decl
;
info
=
(
struct
localvar_info
*
)
obstack_alloc
(
state
->
chunk_obstack
,
sizeof
(
struct
localvar_info
));
ptr
[
0
]
=
info
;
if
(
wide
)
if
(
wide
)
(
info
+
1
)
->
decl
=
TYPE_SECOND
;
ptr
[
1
]
=
(
struct
localvar_info
*
)(
~
0
)
;
DECL_LOCAL_INDEX
(
decl
)
=
index
;
DECL_LOCAL_INDEX
(
decl
)
=
index
;
info
->
start_pc
=
start_pc
;
info
->
decl
=
decl
;
info
->
start_label
=
start_label
;
if
(
DECL_NAME
(
decl
)
!=
NULL_TREE
)
if
(
DECL_NAME
(
decl
)
!=
NULL_TREE
)
{
{
/* Generate debugging info. */
/* Generate debugging info. */
int
i
;
info
->
next
=
NULL
;
register
unsigned
char
*
ptr
;
if
(
state
->
last_lvar
!=
NULL
)
buffer_grow
(
&
localvartable
,
10
);
state
->
last_lvar
->
next
=
info
;
ptr
=
localvartable
.
ptr
;
else
info
->
debug_offset
=
ptr
-
localvartable
.
data
;
state
->
first_lvar
=
info
;
PUT2
(
start_pc
);
state
->
last_lvar
=
info
;
PUT2
(
0
);
/* length - fill in later */
state
->
lvar_count
++
;
i
=
find_utf8_constant
(
code_cpool
,
DECL_NAME
(
decl
));
PUT2
(
i
);
/* name_index*/
i
=
find_utf8_constant
(
code_cpool
,
build_java_signature
(
TREE_TYPE
(
decl
)));
PUT2
(
i
);
/* descriptor_index */
PUT2
(
index
);
localvartable
.
ptr
=
ptr
;
}
}
else
info
->
debug_offset
=
-
1
;
}
}
int
int
localvar_free
(
decl
,
end_pc
)
localvar_free
(
decl
,
state
)
tree
decl
;
tree
decl
;
int
end_pc
;
struct
jcf_partial
*
state
;
{
{
register
unsigned
char
*
ptr
;
struct
jcf_block
*
end_label
=
get_jcf_label_here
(
state
)
;
int
index
=
DECL_LOCAL_INDEX
(
decl
);
int
index
=
DECL_LOCAL_INDEX
(
decl
);
register
struct
localvar_info
*
info
=
&
localvar_buffer
[
index
];
register
struct
localvar_info
**
ptr
=
&
localvar_buffer
[
index
];
register
struct
localvar_info
*
info
=
*
ptr
;
int
wide
=
TYPE_IS_WIDE
(
TREE_TYPE
(
decl
));
int
wide
=
TYPE_IS_WIDE
(
TREE_TYPE
(
decl
));
int
i
;
int
i
;
i
=
info
->
debug_offset
;
info
->
end_label
=
end_label
;
if
(
i
>=
0
)
{
register
unsigned
char
*
ptr
;
/* Point to length field of local_variable_table. */
ptr
=
localvartable
.
data
+
i
+
2
;
i
=
end_pc
-
info
->
start_pc
;
PUT2
(
i
);
}
if
(
info
->
decl
!=
decl
)
if
(
info
->
decl
!=
decl
)
abort
();
abort
();
info
->
decl
=
NULL_TREE
;
ptr
[
0
]
=
NULL
;
if
(
wide
)
if
(
wide
)
{
{
info
++
;
if
(
ptr
[
1
]
!=
(
struct
localvar_info
*
)(
~
0
))
if
(
info
->
decl
!=
TYPE_SECOND
)
abort
();
abort
();
info
->
decl
=
NULL_TREE
;
ptr
[
1
]
=
NULL
;
}
}
}
}
#define STACK_TARGET 1
#define STACK_TARGET 1
#define IGNORE_TARGET 2
#define IGNORE_TARGET 2
/* Allocate a new chunk on obstack WORK, and link it in after LAST.
Set the data and size fields to DATA and SIZE, respectively.
However, if DATA is NULL and SIZE>0, allocate a buffer as well. */
struct
chunk
*
alloc_chunk
(
last
,
data
,
size
,
work
)
struct
chunk
*
last
;
unsigned
char
*
data
;
int
size
;
struct
obstack
*
work
;
{
struct
chunk
*
chunk
=
(
struct
chunk
*
)
obstack_alloc
(
work
,
sizeof
(
struct
chunk
));
if
(
data
==
NULL
&&
size
>
0
)
data
=
obstack_alloc
(
work
,
size
);
chunk
->
next
=
NULL
;
chunk
->
data
=
data
;
chunk
->
size
=
size
;
last
->
next
=
chunk
;
return
chunk
;
}
/* Get the access flags of a class (TYPE_DECL), a method (FUNCTION_DECL), or
/* Get the access flags of a class (TYPE_DECL), a method (FUNCTION_DECL), or
a field (FIELD_DECL or VAR_DECL, if static), as encoded in a .class file. */
a field (FIELD_DECL or VAR_DECL, if static), as encoded in a .class file. */
...
@@ -327,9 +489,10 @@ write_chunks (stream, chunks)
...
@@ -327,9 +489,10 @@ write_chunks (stream, chunks)
fwrite
(
chunks
->
data
,
chunks
->
size
,
1
,
stream
);
fwrite
(
chunks
->
data
,
chunks
->
size
,
1
,
stream
);
}
}
void
static
void
push_constant1
(
index
)
push_constant1
(
index
,
state
)
int
index
;
int
index
;
struct
jcf_partial
*
state
;
{
{
if
(
index
<
256
)
if
(
index
<
256
)
{
{
...
@@ -343,18 +506,23 @@ push_constant1 (index)
...
@@ -343,18 +506,23 @@ push_constant1 (index)
}
}
}
}
void
static
void
push_constant2
(
index
)
push_constant2
(
index
,
state
)
int
index
;
int
index
;
struct
jcf_partial
*
state
;
{
{
RESERVE
(
3
);
RESERVE
(
3
);
OP1
(
OPCODE_ldc2_w
);
OP1
(
OPCODE_ldc2_w
);
OP2
(
index
);
OP2
(
index
);
}
}
void
/* Push 32-bit integer constant on VM stack.
push_int_const
(
i
)
Caller is responsible for doing NOTE_PUSH. */
static
void
push_int_const
(
i
,
state
)
HOST_WIDE_INT
i
;
HOST_WIDE_INT
i
;
struct
jcf_partial
*
state
;
{
{
RESERVE
(
3
);
RESERVE
(
3
);
if
(
i
>=
-
1
&&
i
<=
5
)
if
(
i
>=
-
1
&&
i
<=
5
)
...
@@ -368,17 +536,22 @@ push_int_const (i)
...
@@ -368,17 +536,22 @@ push_int_const (i)
{
{
OP1
(
OPCODE_sipush
);
OP1
(
OPCODE_sipush
);
OP2
(
i
);
OP2
(
i
);
NOTE_PUSH
(
1
);
}
}
else
else
{
{
i
=
find_constant1
(
code_
cpool
,
CONSTANT_Integer
,
i
&
0xFFFFFFFF
);
i
=
find_constant1
(
&
state
->
cpool
,
CONSTANT_Integer
,
i
&
0xFFFFFFFF
);
push_constant1
(
i
);
push_constant1
(
i
);
}
}
}
}
void
/* Push 64-bit long constant on VM stack.
push_long_const
(
lo
,
hi
)
Caller is responsible for doing NOTE_PUSH. */
static
void
push_long_const
(
lo
,
hi
,
state
)
HOST_WIDE_INT
lo
,
hi
;
HOST_WIDE_INT
lo
,
hi
;
struct
jcf_partial
*
state
;
{
{
if
(
hi
==
0
&&
lo
>=
0
&&
lo
<=
1
)
if
(
hi
==
0
&&
lo
>=
0
&&
lo
<=
1
)
{
{
...
@@ -388,7 +561,7 @@ push_long_const (lo, hi)
...
@@ -388,7 +561,7 @@ push_long_const (lo, hi)
#if 0
#if 0
else if ((jlong) (jint) i == i)
else if ((jlong) (jint) i == i)
{
{
push_int_const ((jint) i);
push_int_const ((jint) i
, state
);
RESERVE (1);
RESERVE (1);
OP1 (OPCODE_i2l);
OP1 (OPCODE_i2l);
}
}
...
@@ -397,18 +570,19 @@ push_long_const (lo, hi)
...
@@ -397,18 +570,19 @@ push_long_const (lo, hi)
{
{
HOST_WIDE_INT
w1
,
w2
;
HOST_WIDE_INT
w1
,
w2
;
lshift_double
(
lo
,
hi
,
-
32
,
64
,
&
w1
,
&
w2
,
1
);
lshift_double
(
lo
,
hi
,
-
32
,
64
,
&
w1
,
&
w2
,
1
);
hi
=
find_constant1
(
code_
cpool
,
CONSTANT_Long
,
hi
=
find_constant1
(
&
state
->
cpool
,
CONSTANT_Long
,
w1
&
0xFFFFFFFF
,
lo
&
0xFFFFFFFF
);
w1
&
0xFFFFFFFF
,
lo
&
0xFFFFFFFF
);
push_constant2
(
hi
);
push_constant2
(
hi
);
}
}
}
}
void
static
void
field_op
(
field
,
opcode
)
field_op
(
field
,
opcode
,
state
)
tree
field
;
tree
field
;
int
opcode
;
int
opcode
;
struct
jcf_partial
*
state
;
{
{
int
index
=
find_fieldref_index
(
code_
cpool
,
field
);
int
index
=
find_fieldref_index
(
&
state
->
cpool
,
field
);
RESERVE
(
3
);
RESERVE
(
3
);
OP1
(
opcode
);
OP1
(
opcode
);
OP2
(
index
);
OP2
(
index
);
...
@@ -424,10 +598,12 @@ adjust_typed_op (type)
...
@@ -424,10 +598,12 @@ adjust_typed_op (type)
{
{
switch
(
TREE_CODE
(
type
))
switch
(
TREE_CODE
(
type
))
{
{
case
BOOLEAN_TYPE
:
return
5
;
case
CHAR_TYPE
:
return
6
;
case
POINTER_TYPE
:
case
POINTER_TYPE
:
case
RECORD_TYPE
:
return
4
;
case
RECORD_TYPE
:
return
4
;
case
BOOLEAN_TYPE
:
return
TYPE_PRECISION
(
type
)
==
32
?
0
:
5
;
case
CHAR_TYPE
:
return
TYPE_PRECISION
(
type
)
==
32
?
0
:
6
;
case
INTEGER_TYPE
:
case
INTEGER_TYPE
:
switch
(
TYPE_PRECISION
(
type
))
switch
(
TYPE_PRECISION
(
type
))
{
{
...
@@ -448,14 +624,15 @@ adjust_typed_op (type)
...
@@ -448,14 +624,15 @@ adjust_typed_op (type)
abort
();
abort
();
}
}
void
static
void
maybe_wide
(
opcode
,
index
)
maybe_wide
(
opcode
,
index
,
state
)
int
opcode
,
index
;
int
opcode
,
index
;
struct
jcf_partial
*
state
;
{
{
if
(
index
>=
256
)
if
(
index
>=
256
)
{
{
RESERVE
(
4
);
RESERVE
(
4
);
OP1
(
196
);
/* wide */
OP1
(
OPCODE_wide
);
OP1
(
opcode
);
OP1
(
opcode
);
OP2
(
index
);
OP2
(
index
);
}
}
...
@@ -467,21 +644,382 @@ maybe_wide (opcode, index)
...
@@ -467,21 +644,382 @@ maybe_wide (opcode, index)
}
}
}
}
#define PC BUFFER_LENGTH(&bytecode)
/* Compile code to duplicate with offset, where
SIZE is the size of the stack item to duplicate (1 or 2), abd
OFFSET is where to insert the result (must be 0, 1, or 2).
(The new words get inserted at stack[SP-size-offset].) */
/* Generate byetcode for sub-expression EXP of METHOD.
static
void
TARGET is one of STACK_TARGET or IGNORE_TARGET. */
emit_dup
(
size
,
offset
,
state
)
int
size
,
offset
;
struct
jcf_partial
*
state
;
{
int
kind
;
if
(
size
==
0
)
return
;
RESERVE
(
1
);
if
(
offset
==
0
)
kind
=
size
==
1
?
OPCODE_dup
:
OPCODE_dup2
;
else
if
(
offset
==
1
)
kind
=
size
==
1
?
OPCODE_dup_x1
:
OPCODE_dup2_x1
;
else
if
(
offset
==
2
)
kind
=
size
==
1
?
OPCODE_dup_x2
:
OPCODE_dup2_x2
;
else
abort
();
OP1
(
kind
);
NOTE_PUSH
(
size
);
}
static
void
emit_pop
(
size
,
state
)
int
size
;
struct
jcf_partial
*
state
;
{
RESERVE
(
1
);
OP1
(
OPCODE_pop
-
1
+
size
);
}
static
void
emit_iinc
(
var
,
value
,
state
)
tree
var
;
int
value
;
struct
jcf_partial
*
state
;
{
int
slot
=
DECL_LOCAL_INDEX
(
var
);
if
(
value
<
-
128
||
value
>
127
||
slot
>=
256
)
{
RESERVE
(
6
);
OP1
(
OPCODE_wide
);
OP1
(
OPCODE_iinc
);
OP2
(
slot
);
OP2
(
value
);
}
else
{
RESERVE
(
3
);
OP1
(
OPCODE_iinc
);
OP1
(
slot
);
OP1
(
value
);
}
}
static
void
emit_load_or_store
(
var
,
opcode
,
state
)
tree
var
;
struct
jcf_partial
*
state
;
{
tree
type
=
TREE_TYPE
(
var
);
int
kind
=
adjust_typed_op
(
type
);
int
index
=
DECL_LOCAL_INDEX
(
var
);
if
(
index
<=
3
)
{
RESERVE
(
1
);
OP1
(
opcode
+
5
+
4
*
kind
+
index
);
/* [ilfda]{load,store}_[0123] */
}
else
maybe_wide
(
opcode
+
kind
,
index
);
/* [ilfda]{load,store} */
}
static
void
emit_load
(
var
,
state
)
tree
var
;
struct
jcf_partial
*
state
;
{
emit_load_or_store
(
var
,
OPCODE_iload
,
state
);
NOTE_PUSH
(
TYPE_IS_WIDE
(
TREE_TYPE
(
var
))
?
2
:
1
);
}
static
void
emit_store
(
var
,
state
)
tree
var
;
struct
jcf_partial
*
state
;
{
emit_load_or_store
(
var
,
OPCODE_istore
,
state
);
NOTE_POP
(
TYPE_IS_WIDE
(
TREE_TYPE
(
var
))
?
2
:
1
);
}
static
void
emit_binop
(
opcode
,
type
,
state
)
enum
java_opcode
opcode
;
tree
type
;
struct
jcf_partial
*
state
;
{
int
size
=
TYPE_IS_WIDE
(
type
)
?
2
:
1
;
RESERVE
(
1
);
OP1
(
opcode
);
NOTE_POP
(
size
);
}
/* Emit a conditional jump to TARGET with a 2-byte relative jump offset
The opcode is OPCODE, the inverted opcode is INV_OPCODE. */
static
void
emit_if
(
target
,
opcode
,
inv_opcode
,
state
)
struct
jcf_block
*
target
;
int
opcode
,
inv_opcode
;
struct
jcf_partial
*
state
;
{
struct
jcf_relocation
*
reloc
=
(
struct
jcf_relocation
*
)
obstack_alloc
(
state
->
chunk_obstack
,
sizeof
(
struct
jcf_relocation
));
struct
jcf_block
*
block
=
state
->
last_block
;
reloc
->
next
=
block
->
u
.
relocations
;
block
->
u
.
relocations
=
reloc
;
OP1
(
opcode
);
reloc
->
offset
=
BUFFER_LENGTH
(
&
state
->
bytecode
);
OP2
(
1
);
// 1 byte from reloc back to start of instruction.
reloc
->
kind
=
-
inv_opcode
;
reloc
->
label
=
target
;
}
static
void
emit_goto_or_jsr
(
target
,
opcode
,
opcode_w
,
state
)
struct
jcf_block
*
target
;
int
opcode
,
opcode_w
;
struct
jcf_partial
*
state
;
{
struct
jcf_relocation
*
reloc
=
(
struct
jcf_relocation
*
)
obstack_alloc
(
state
->
chunk_obstack
,
sizeof
(
struct
jcf_relocation
));
struct
jcf_block
*
block
=
state
->
last_block
;
reloc
->
next
=
block
->
u
.
relocations
;
block
->
u
.
relocations
=
reloc
;
OP1
(
opcode
);
reloc
->
offset
=
BUFFER_LENGTH
(
&
state
->
bytecode
);
OP2
(
1
);
// 1 byte from reloc back to start of instruction.
reloc
->
kind
=
opcode_w
;
reloc
->
label
=
target
;
}
static
void
emit_goto
(
target
,
state
)
struct
jcf_block
*
target
;
struct
jcf_partial
*
state
;
{
emit_goto_or_jsr
(
target
,
OPCODE_goto
,
OPCODE_goto_w
,
state
);
}
static
void
emit_jsr
(
target
,
state
)
struct
jcf_block
*
target
;
struct
jcf_partial
*
state
;
{
emit_goto_or_jsr
(
target
,
OPCODE_jsr
,
OPCODE_jsr_w
,
state
);
}
/* Generate code to evaluate EXP. If the result is true,
branch to TRUE_LABEL; otherwise, branch to FALSE_LABEL.
TRUE_BRANCH_FIRST is a code geneation hint that the
TRUE_LABEL may follow right after this. (The idea is that we
may be able to optimize away GOTO TRUE_LABEL; TRUE_LABEL:) */
void
void
generate_bytecode_insns
(
method
,
exp
,
target
)
generate_bytecode_conditional
(
exp
,
true_label
,
false_label
,
tree
method
;
true_branch_first
,
state
)
tree
exp
;
struct
jcf_block
*
true_label
;
struct
jcf_block
*
false_label
;
int
true_branch_first
;
struct
jcf_partial
*
state
;
{
int
kind
;
tree
exp0
,
exp1
,
type
;
int
save_SP
=
state
->
code_SP
;
enum
java_opcode
op
,
negop
;
switch
(
TREE_CODE
(
exp
))
{
case
INTEGER_CST
:
emit_goto
(
integer_zerop
(
exp
)
?
false_label
:
true_label
,
state
);
break
;
case
COND_EXPR
:
{
struct
jcf_block
*
then_label
=
gen_jcf_label
(
state
);
struct
jcf_block
*
else_label
=
gen_jcf_label
(
state
);
int
save_SP_before
,
save_SP_after
;
generate_bytecode_conditional
(
TREE_OPERAND
(
exp
,
0
),
then_label
,
else_label
,
1
,
state
);
define_jcf_label
(
then_label
,
state
);
save_SP_before
=
state
->
code_SP
;
generate_bytecode_conditional
(
TREE_OPERAND
(
exp
,
1
),
true_label
,
false_label
,
1
,
state
);
save_SP_after
=
state
->
code_SP
;
state
->
code_SP
=
save_SP_before
;
define_jcf_label
(
else_label
,
state
);
generate_bytecode_conditional
(
TREE_OPERAND
(
exp
,
2
),
true_label
,
false_label
,
true_branch_first
,
state
);
if
(
state
->
code_SP
!=
save_SP_after
)
fatal
(
"internal error non-matching SP"
);
}
break
;
case
TRUTH_ANDIF_EXPR
:
{
struct
jcf_block
*
next_label
=
gen_jcf_label
(
state
);
generate_bytecode_conditional
(
TREE_OPERAND
(
exp
,
0
),
next_label
,
false_label
,
1
,
state
);
define_jcf_label
(
next_label
,
state
);
generate_bytecode_conditional
(
TREE_OPERAND
(
exp
,
1
),
true_label
,
false_label
,
1
,
state
);
}
break
;
case
TRUTH_ORIF_EXPR
:
{
struct
jcf_block
*
next_label
=
gen_jcf_label
(
state
);
generate_bytecode_conditional
(
TREE_OPERAND
(
exp
,
0
),
true_label
,
next_label
,
1
,
state
);
define_jcf_label
(
next_label
,
state
);
generate_bytecode_conditional
(
TREE_OPERAND
(
exp
,
1
),
true_label
,
false_label
,
1
,
state
);
}
break
;
compare_1
:
/* Assuming op is one of the 2-operand if_icmp<COND> instructions,
set it to the corresponding 1-operand if<COND> instructions. */
op
=
op
-
6
;
/* FALLTHROUGH */
compare_2
:
/* The opcodes with their inverses are allocated in pairs.
E.g. The inverse of if_icmplt (161) is if_icmpge (162). */
negop
=
(
op
&
1
)
?
op
+
1
:
op
-
1
;
compare_2_ptr
:
if
(
true_branch_first
)
{
emit_if
(
false_label
,
negop
,
op
,
state
);
emit_goto
(
true_label
,
state
);
}
else
{
emit_if
(
true_label
,
op
,
negop
,
state
);
emit_goto
(
false_label
,
state
);
}
break
;
case
EQ_EXPR
:
op
=
OPCODE_if_icmpeq
;
goto
compare
;
case
NE_EXPR
:
op
=
OPCODE_if_icmpne
;
goto
compare
;
case
GT_EXPR
:
op
=
OPCODE_if_icmpgt
;
goto
compare
;
case
LT_EXPR
:
op
=
OPCODE_if_icmplt
;
goto
compare
;
case
GE_EXPR
:
op
=
OPCODE_if_icmpge
;
goto
compare
;
case
LE_EXPR
:
op
=
OPCODE_if_icmple
;
goto
compare
;
compare
:
exp0
=
TREE_OPERAND
(
exp
,
0
);
exp1
=
TREE_OPERAND
(
exp
,
1
);
type
=
TREE_TYPE
(
exp0
);
switch
(
TREE_CODE
(
type
))
{
case
POINTER_TYPE
:
case
RECORD_TYPE
:
switch
(
TREE_CODE
(
exp
))
{
case
EQ_EXPR
:
op
=
OPCODE_if_acmpeq
;
break
;
case
NE_EXPR
:
op
=
OPCODE_if_acmpne
;
break
;
default
:
abort
();
}
if
(
integer_zerop
(
exp1
)
||
integer_zerop
(
exp0
))
{
generate_bytecode_insns
(
integer_zerop
(
exp1
)
?
exp0
:
exp0
,
STACK_TARGET
,
state
);
op
=
op
+
(
OPCODE_ifnull
-
OPCODE_if_acmpeq
);
negop
=
(
op
&
1
)
?
op
-
1
:
op
+
1
;
NOTE_POP
(
1
);
goto
compare_2_ptr
;
}
generate_bytecode_insns
(
exp0
,
STACK_TARGET
,
state
);
generate_bytecode_insns
(
exp1
,
STACK_TARGET
,
state
);
NOTE_POP
(
2
);
goto
compare_2
;
case
REAL_TYPE
:
fatal
(
"float comparison not implemented"
);
case
INTEGER_TYPE
:
if
(
TYPE_PRECISION
(
type
)
>
32
)
{
generate_bytecode_insns
(
exp0
,
STACK_TARGET
,
state
);
generate_bytecode_insns
(
exp1
,
STACK_TARGET
,
state
);
NOTE_POP
(
4
);
RESERVE
(
1
);
OP1
(
OPCODE_lcmp
);
goto
compare_1
;
}
/* FALLTHOUGH */
default
:
if
(
integer_zerop
(
exp1
))
{
generate_bytecode_insns
(
exp0
,
STACK_TARGET
,
state
);
NOTE_POP
(
1
);
goto
compare_1
;
}
if
(
integer_zerop
(
exp0
))
{
switch
(
op
)
{
case
OPCODE_if_icmplt
:
case
OPCODE_if_icmpge
:
op
+=
2
;
break
;
case
OPCODE_if_icmpgt
:
case
OPCODE_if_icmple
:
op
-=
2
;
break
;
}
generate_bytecode_insns
(
exp1
,
STACK_TARGET
,
state
);
NOTE_POP
(
1
);
goto
compare_1
;
}
generate_bytecode_insns
(
exp0
,
STACK_TARGET
,
state
);
generate_bytecode_insns
(
exp1
,
STACK_TARGET
,
state
);
NOTE_POP
(
2
);
goto
compare_2
;
}
default
:
generate_bytecode_insns
(
exp
,
STACK_TARGET
,
state
);
NOTE_POP
(
1
);
if
(
true_branch_first
)
{
emit_if
(
false_label
,
OPCODE_ifeq
,
OPCODE_ifne
,
state
);
emit_goto
(
true_label
,
state
);
}
else
{
emit_if
(
true_label
,
OPCODE_ifne
,
OPCODE_ifeq
,
state
);
emit_goto
(
false_label
,
state
);
}
break
;
}
if
(
save_SP
!=
state
->
code_SP
)
fatal
(
"inetrnal error - SP mismatch"
);
}
/* Generate bytecode for sub-expression EXP of METHOD.
TARGET is one of STACK_TARGET or IGNORE_TARGET. */
static
void
generate_bytecode_insns
(
exp
,
target
,
state
)
tree
exp
;
tree
exp
;
int
target
;
int
target
;
struct
jcf_partial
*
state
;
{
{
rtx
value
;
tree
type
;
tree
type
=
TREE_TYPE
(
exp
);
enum
java_opcode
jopcode
;
enum
java_opcode
jopcode
;
int
op
;
int
op
;
HOST_WIDE_INT
value
;
int
post_op
;
int
size
;
int
offset
;
if
(
exp
==
NULL
&&
target
==
IGNORE_TARGET
)
return
;
type
=
TREE_TYPE
(
exp
);
switch
(
TREE_CODE
(
exp
))
switch
(
TREE_CODE
(
exp
))
{
{
case
BLOCK
:
case
BLOCK
:
...
@@ -491,21 +1029,21 @@ generate_bytecode_insns (method, exp, target)
...
@@ -491,21 +1029,21 @@ generate_bytecode_insns (method, exp, target)
for
(
local
=
BLOCK_EXPR_DECLS
(
exp
);
local
;
)
for
(
local
=
BLOCK_EXPR_DECLS
(
exp
);
local
;
)
{
{
tree
next
=
TREE_CHAIN
(
local
);
tree
next
=
TREE_CHAIN
(
local
);
localvar_alloc
(
local
,
PC
);
localvar_alloc
(
local
,
state
);
local
=
next
;
local
=
next
;
}
}
generate_bytecode_insns
(
method
,
BLOCK_EXPR_BODY
(
exp
),
target
);
generate_bytecode_insns
(
BLOCK_EXPR_BODY
(
exp
),
target
,
state
);
for
(
local
=
BLOCK_EXPR_DECLS
(
exp
);
local
;
)
for
(
local
=
BLOCK_EXPR_DECLS
(
exp
);
local
;
)
{
{
tree
next
=
TREE_CHAIN
(
local
);
tree
next
=
TREE_CHAIN
(
local
);
localvar_free
(
local
,
PC
);
localvar_free
(
local
,
state
);
local
=
next
;
local
=
next
;
}
}
}
}
break
;
break
;
case
COMPOUND_EXPR
:
case
COMPOUND_EXPR
:
generate_bytecode_insns
(
method
,
TREE_OPERAND
(
exp
,
0
),
IGNORE_TARGET
);
generate_bytecode_insns
(
TREE_OPERAND
(
exp
,
0
),
IGNORE_TARGET
,
state
);
generate_bytecode_insns
(
method
,
TREE_OPERAND
(
exp
,
1
),
target
);
generate_bytecode_insns
(
TREE_OPERAND
(
exp
,
1
),
target
,
state
);
break
;
break
;
case
EXPR_WITH_FILE_LOCATION
:
case
EXPR_WITH_FILE_LOCATION
:
{
{
...
@@ -514,8 +1052,8 @@ generate_bytecode_insns (method, exp, target)
...
@@ -514,8 +1052,8 @@ generate_bytecode_insns (method, exp, target)
input_filename
=
EXPR_WFL_FILENAME
(
exp
);
input_filename
=
EXPR_WFL_FILENAME
(
exp
);
lineno
=
EXPR_WFL_LINENO
(
exp
);
lineno
=
EXPR_WFL_LINENO
(
exp
);
if
(
EXPR_WFL_EMIT_LINE_NOTE
(
exp
))
if
(
EXPR_WFL_EMIT_LINE_NOTE
(
exp
))
put_linenumber
(
PC
,
EXPR_WFL_LINENO
(
exp
)
);
put_linenumber
(
EXPR_WFL_LINENO
(
exp
),
state
);
generate_bytecode_insns
(
method
,
EXPR_WFL_NODE
(
exp
),
target
);
generate_bytecode_insns
(
EXPR_WFL_NODE
(
exp
),
target
,
state
);
input_filename
=
saved_input_filename
;
input_filename
=
saved_input_filename
;
lineno
=
saved_lineno
;
lineno
=
saved_lineno
;
}
}
...
@@ -532,46 +1070,39 @@ generate_bytecode_insns (method, exp, target)
...
@@ -532,46 +1070,39 @@ generate_bytecode_insns (method, exp, target)
}
}
else
if
(
TYPE_PRECISION
(
type
)
<=
32
)
else
if
(
TYPE_PRECISION
(
type
)
<=
32
)
{
{
push_int_const
(
TREE_INT_CST_LOW
(
exp
));
push_int_const
(
TREE_INT_CST_LOW
(
exp
)
,
state
);
NOTE_PUSH
(
1
);
NOTE_PUSH
(
1
);
}
}
else
else
{
{
push_long_const
(
TREE_INT_CST_LOW
(
exp
),
TREE_INT_CST_HIGH
(
exp
));
push_long_const
(
TREE_INT_CST_LOW
(
exp
),
TREE_INT_CST_HIGH
(
exp
),
state
);
NOTE_PUSH
(
2
);
NOTE_PUSH
(
2
);
}
}
break
;
break
;
case
VAR_DECL
:
case
VAR_DECL
:
if
(
TREE_STATIC
(
exp
))
if
(
TREE_STATIC
(
exp
))
{
{
field_op
(
exp
,
OPCODE_getstatic
);
field_op
(
exp
,
OPCODE_getstatic
,
state
);
NOTE_PUSH
(
TYPE_IS_WIDE
(
TREE_TYPE
(
exp
))
?
2
:
1
);
break
;
break
;
}
}
/* ... fall through ... */
/* ... fall through ... */
case
PARM_DECL
:
case
PARM_DECL
:
{
emit_load
(
exp
,
state
);
int
kind
=
adjust_typed_op
(
type
);
int
index
=
DECL_LOCAL_INDEX
(
exp
);
if
(
index
<=
3
)
{
RESERVE
(
1
);
OP1
(
26
+
4
*
kind
+
index
);
/* [ilfda]load_[0123] */
}
else
maybe_wide
(
21
+
kind
,
index
);
/* [ilfda]load */
}
break
;
break
;
case
INDIRECT_REF
:
case
INDIRECT_REF
:
generate_bytecode_insns
(
method
,
TREE_OPERAND
(
exp
,
0
),
target
);
generate_bytecode_insns
(
TREE_OPERAND
(
exp
,
0
),
target
,
state
);
break
;
break
;
case
ARRAY_REF
:
case
ARRAY_REF
:
generate_bytecode_insns
(
method
,
TREE_OPERAND
(
exp
,
0
),
target
);
generate_bytecode_insns
(
TREE_OPERAND
(
exp
,
0
),
target
,
state
);
generate_bytecode_insns
(
method
,
TREE_OPERAND
(
exp
,
1
),
target
);
generate_bytecode_insns
(
TREE_OPERAND
(
exp
,
1
),
target
,
state
);
if
(
target
!=
IGNORE_TARGET
)
if
(
target
!=
IGNORE_TARGET
)
{
{
jopcode
=
OPCODE_iaload
+
adjust_typed_op
(
type
);
jopcode
=
OPCODE_iaload
+
adjust_typed_op
(
type
);
RESERVE
(
1
);
RESERVE
(
1
);
OP1
(
jopcode
);
OP1
(
jopcode
);
NOTE_POP
(
2
);
}
}
break
;
break
;
case
COMPONENT_REF
:
case
COMPONENT_REF
:
...
@@ -579,8 +1110,8 @@ generate_bytecode_insns (method, exp, target)
...
@@ -579,8 +1110,8 @@ generate_bytecode_insns (method, exp, target)
tree
obj
=
TREE_OPERAND
(
exp
,
0
);
tree
obj
=
TREE_OPERAND
(
exp
,
0
);
tree
field
=
TREE_OPERAND
(
exp
,
1
);
tree
field
=
TREE_OPERAND
(
exp
,
1
);
int
is_static
=
FIELD_STATIC
(
field
);
int
is_static
=
FIELD_STATIC
(
field
);
generate_bytecode_insns
(
method
,
obj
,
generate_bytecode_insns
(
obj
,
is_static
?
IGNORE_TARGET
:
target
);
is_static
?
IGNORE_TARGET
:
target
,
state
);
if
(
target
!=
IGNORE_TARGET
)
if
(
target
!=
IGNORE_TARGET
)
{
{
if
(
DECL_NAME
(
field
)
==
length_identifier_node
&&
!
is_static
if
(
DECL_NAME
(
field
)
==
length_identifier_node
&&
!
is_static
...
@@ -590,10 +1121,54 @@ generate_bytecode_insns (method, exp, target)
...
@@ -590,10 +1121,54 @@ generate_bytecode_insns (method, exp, target)
OP1
(
OPCODE_arraylength
);
OP1
(
OPCODE_arraylength
);
}
}
else
else
field_op
(
field
,
is_static
?
OPCODE_getstatic
:
OPCODE_getfield
);
{
field_op
(
field
,
is_static
?
OPCODE_getstatic
:
OPCODE_getfield
,
state
);
if
(
!
is_static
)
NOTE_POP
(
1
);
NOTE_PUSH
(
TYPE_IS_WIDE
(
TREE_TYPE
(
field
))
?
2
:
1
);
}
}
}
}
}
break
;
break
;
case
TRUTH_ANDIF_EXPR
:
case
TRUTH_ORIF_EXPR
:
case
EQ_EXPR
:
case
NE_EXPR
:
case
GT_EXPR
:
case
LT_EXPR
:
case
GE_EXPR
:
case
LE_EXPR
:
{
struct
jcf_block
*
then_label
=
gen_jcf_label
(
state
);
struct
jcf_block
*
else_label
=
gen_jcf_label
(
state
);
struct
jcf_block
*
end_label
=
gen_jcf_label
(
state
);
generate_bytecode_conditional
(
exp
,
then_label
,
else_label
,
1
,
state
);
define_jcf_label
(
then_label
,
state
);
push_int_const
(
1
,
state
);
emit_goto
(
end_label
,
state
);
define_jcf_label
(
else_label
,
state
);
push_int_const
(
0
,
state
);
define_jcf_label
(
end_label
,
state
);
NOTE_PUSH
(
1
);
}
break
;
case
COND_EXPR
:
{
struct
jcf_block
*
then_label
=
gen_jcf_label
(
state
);
struct
jcf_block
*
else_label
=
gen_jcf_label
(
state
);
struct
jcf_block
*
end_label
=
gen_jcf_label
(
state
);
generate_bytecode_conditional
(
TREE_OPERAND
(
exp
,
0
),
then_label
,
else_label
,
1
,
state
);
define_jcf_label
(
then_label
,
state
);
generate_bytecode_insns
(
TREE_OPERAND
(
exp
,
1
),
target
,
state
);
emit_goto
(
end_label
,
state
);
define_jcf_label
(
else_label
,
state
);
generate_bytecode_insns
(
TREE_OPERAND
(
exp
,
2
),
target
,
state
);
define_jcf_label
(
end_label
,
state
);
}
break
;
case
RETURN_EXPR
:
case
RETURN_EXPR
:
if
(
!
TREE_OPERAND
(
exp
,
0
))
if
(
!
TREE_OPERAND
(
exp
,
0
))
op
=
OPCODE_return
;
op
=
OPCODE_return
;
...
@@ -604,89 +1179,234 @@ generate_bytecode_insns (method, exp, target)
...
@@ -604,89 +1179,234 @@ generate_bytecode_insns (method, exp, target)
abort
();
abort
();
exp
=
TREE_OPERAND
(
exp
,
1
);
exp
=
TREE_OPERAND
(
exp
,
1
);
op
=
OPCODE_ireturn
+
adjust_typed_op
(
TREE_TYPE
(
exp
));
op
=
OPCODE_ireturn
+
adjust_typed_op
(
TREE_TYPE
(
exp
));
generate_bytecode_insns
(
method
,
exp
,
STACK_TARGET
);
generate_bytecode_insns
(
exp
,
STACK_TARGET
,
state
);
}
}
RESERVE
(
1
);
RESERVE
(
1
);
OP1
(
op
);
OP1
(
op
);
break
;
break
;
case
MODIFY
_EXPR
:
case
LABELED_BLOCK
_EXPR
:
{
{
tree
lhs
=
TREE_OPERAND
(
exp
,
0
);
struct
jcf_block
*
end_label
=
gen_jcf_label
(
state
);
tree
rhs
=
TREE_OPERAND
(
exp
,
1
);
end_label
->
next
=
state
->
labeled_blocks
;
HOST_WIDE_INT
value
;
state
->
labeled_blocks
=
end_label
;
end_label
->
u
.
labeled_block
=
exp
;
if
(
LABELED_BLOCK_BODY
(
exp
))
generate_bytecode_insns
(
LABELED_BLOCK_BODY
(
exp
),
target
,
state
);
if
(
state
->
labeled_blocks
!=
end_label
)
abort
();
state
->
labeled_blocks
=
end_label
->
next
;
define_jcf_label
(
end_label
,
state
);
}
break
;
case
LOOP_EXPR
:
{
tree
body
=
TREE_OPERAND
(
exp
,
0
);
#if 0
#if 0
if (TREE_CODE (rhs) == PLUS_EXPR
if (TREE_CODE (body) == COMPOUND_EXPR
&& TREE_CODE (lhs) == VAR_DECL
&& TREE_CODE (TREE_OPERAND (body, 0)) == EXIT_EXPR)
/* && FIXME lhs is a local variable */
&& TYPE_MODE (TREE)TYPE (lhs) == SImode /* ??? */
&& TREE_OPERAND (rhs, 0) == lhs
&& TREE_CODE (TREE_OPERAND (rhs, 1)) == INTEGER_CST
/* or vice versa FIXME */
&& (value = TREE_INT_CST_LOW (TREE_OPERAND (rhs, 1)),
(value >= -32768 && value <= 32767)))
{
{
emit_insn (gen_rtx (SET, SImode,
/* Optimize: H: if (TEST) GOTO L; BODY; GOTO H; L:
DECL_RTL (lhs),
to: GOTO L; BODY; L: if (!TEST) GOTO L; */
gen_rtx (PLUS, SImode,
struct jcf_block *head_label;
DECL_RTL (lhs),
struct jcf_block *body_label;
gen_rtx_CONST_INT (SImode, value))));
struct jcf_block *end_label = gen_jcf_label (state);
return DECL_RTL (lhs);
struct jcf_block *exit_label = state->labeled_blocks;
head_label = gen_jcf_label (state);
emit_goto (head_label, state);
body_label = get_jcf_label_here (state);
generate_bytecode_insns (TREE_OPERAND (body, 1), target, state);
define_jcf_label (head_label, state);
generate_bytecode_conditional (TREE_OPERAND (body, 0),
end_label, body_label, 1, state);
define_jcf_label (end_label, state);
}
}
else
#endif
#endif
if
(
TREE_CODE
(
lhs
)
==
COMPONENT_REF
)
generate_bytecode_insns
(
method
,
TREE_OPERAND
(
lhs
,
0
),
STACK_TARGET
);
else
if
(
TREE_CODE
(
lhs
)
==
ARRAY_REF
)
{
generate_bytecode_insns
(
method
,
TREE_OPERAND
(
lhs
,
0
),
STACK_TARGET
);
generate_bytecode_insns
(
method
,
TREE_OPERAND
(
lhs
,
1
),
STACK_TARGET
);
}
generate_bytecode_insns
(
method
,
rhs
,
STACK_TARGET
);
if
(
target
!=
IGNORE_TARGET
)
{
RESERVE
(
1
);
OP1
(
TYPE_IS_WIDE
(
type
)
?
OPCODE_dup2_x1
:
OPCODE_dup_x1
);
}
if
(
TREE_CODE
(
lhs
)
==
COMPONENT_REF
)
{
{
tree
field
=
TREE_OPERAND
(
lhs
,
1
);
struct
jcf_block
*
head_label
=
get_jcf_label_here
(
state
);
field_op
(
field
,
generate_bytecode_insns
(
body
,
IGNORE_TARGET
,
state
);
FIELD_STATIC
(
field
)
?
OPCODE_putstatic
emit_goto
(
head_label
,
state
);
:
OPCODE_putfield
);
}
}
else
if
(
TREE_CODE
(
lhs
)
==
VAR_DECL
}
||
TREE_CODE
(
lhs
)
==
PARM_DECL
)
break
;
case
EXIT_EXPR
:
{
struct
jcf_block
*
label
=
state
->
labeled_blocks
;
struct
jcf_block
*
end_label
=
gen_jcf_label
(
state
);
generate_bytecode_conditional
(
TREE_OPERAND
(
exp
,
0
),
label
,
end_label
,
0
,
state
);
define_jcf_label
(
end_label
,
state
);
}
break
;
case
EXIT_BLOCK_EXPR
:
{
struct
jcf_block
*
label
=
state
->
labeled_blocks
;
if
(
TREE_OPERAND
(
exp
,
1
)
!=
NULL
)
goto
notimpl
;
while
(
label
->
u
.
labeled_block
!=
TREE_OPERAND
(
exp
,
0
))
label
=
label
->
next
;
emit_goto
(
label
,
state
);
}
break
;
case
PREDECREMENT_EXPR
:
value
=
-
1
;
post_op
=
0
;
goto
increment
;
case
PREINCREMENT_EXPR
:
value
=
1
;
post_op
=
0
;
goto
increment
;
case
POSTDECREMENT_EXPR
:
value
=
-
1
;
post_op
=
1
;
goto
increment
;
case
POSTINCREMENT_EXPR
:
value
=
1
;
post_op
=
1
;
goto
increment
;
increment
:
exp
=
TREE_OPERAND
(
exp
,
0
);
type
=
TREE_TYPE
(
exp
);
size
=
TYPE_IS_WIDE
(
type
)
?
2
:
1
;
if
((
TREE_CODE
(
exp
)
==
VAR_DECL
||
TREE_CODE
(
exp
)
==
PARM_DECL
)
&&
!
TREE_STATIC
(
exp
)
&&
TREE_CODE
(
type
)
==
INTEGER_TYPE
&&
TYPE_PRECISION
(
type
)
==
32
)
{
if
(
target
!=
IGNORE_TARGET
&&
post_op
)
emit_load
(
exp
,
state
);
emit_iinc
(
exp
,
value
,
state
);
if
(
target
!=
IGNORE_TARGET
)
{
if
(
!
post_op
)
emit_load
(
exp
,
state
);
NOTE_PUSH
(
1
);
}
break
;
}
if
(
TREE_CODE
(
exp
)
==
COMPONENT_REF
)
{
generate_bytecode_insns
(
TREE_OPERAND
(
exp
,
0
),
STACK_TARGET
,
state
);
emit_dup
(
1
,
0
,
state
);
/* Stack: ..., objectref, objectref. */
field_op
(
TREE_OPERAND
(
exp
,
1
),
OPCODE_getstatic
,
state
);
NOTE_PUSH
(
size
);
/* Stack: ..., objectref, oldvalue. */
offset
=
1
;
}
else
if
(
TREE_CODE
(
exp
)
==
ARRAY_REF
)
{
generate_bytecode_insns
(
TREE_OPERAND
(
exp
,
0
),
STACK_TARGET
,
state
);
generate_bytecode_insns
(
TREE_OPERAND
(
exp
,
1
),
STACK_TARGET
,
state
);
emit_dup
(
2
,
0
,
state
);
/* Stack: ..., array, index, array, index. */
jopcode
=
OPCODE_iaload
+
adjust_typed_op
(
TREE_TYPE
(
exp
));
RESERVE
(
1
);
OP1
(
jopcode
);
NOTE_POP
(
2
-
size
);
/* Stack: ..., array, index, oldvalue. */
offset
=
2
;
}
else
if
(
TREE_CODE
(
exp
)
==
VAR_DECL
||
TREE_CODE
(
exp
)
==
PARM_DECL
)
{
generate_bytecode_insns
(
exp
,
STACK_TARGET
,
state
);
/* Stack: ..., oldvalue. */
offset
=
0
;
}
else
abort
();
if
(
target
!=
IGNORE_TARGET
&&
post_op
)
emit_dup
(
size
,
offset
,
state
);
/* Stack, if ARRAY_REF: ..., [result, ] array, index, oldvalue. */
/* Stack, if COMPONENT_REF: ..., [result, ] objectref, oldvalue. */
/* Stack, otherwise: ..., [result, ] oldvalue. */
push_int_const
(
value
,
state
);
/* FIXME - assumes int! */
NOTE_PUSH
(
1
);
emit_binop
(
OPCODE_iadd
+
adjust_typed_op
(
type
),
type
,
state
);
if
(
target
!=
IGNORE_TARGET
&&
!
post_op
)
emit_dup
(
size
,
offset
,
state
);
/* Stack: ..., [result,] newvalue. */
goto
finish_assignment
;
case
MODIFY_EXPR
:
{
tree
lhs
=
TREE_OPERAND
(
exp
,
0
);
tree
rhs
=
TREE_OPERAND
(
exp
,
1
);
/* See if we can use the iinc instruction. */
if
((
TREE_CODE
(
lhs
)
==
VAR_DECL
||
TREE_CODE
(
lhs
)
==
PARM_DECL
)
&&
!
TREE_STATIC
(
lhs
)
&&
TREE_CODE
(
TREE_TYPE
(
lhs
))
==
INTEGER_TYPE
&&
TYPE_PRECISION
(
TREE_TYPE
(
lhs
))
==
32
&&
(
TREE_CODE
(
rhs
)
==
PLUS_EXPR
||
TREE_CODE
(
rhs
)
==
MINUS_EXPR
))
{
{
if
(
FIELD_STATIC
(
lhs
))
tree
arg0
=
TREE_OPERAND
(
rhs
,
0
);
tree
arg1
=
TREE_OPERAND
(
rhs
,
1
);
HOST_WIDE_INT
min_value
=
-
32768
;
HOST_WIDE_INT
max_value
=
32767
;
if
(
TREE_CODE
(
rhs
)
==
MINUS_EXPR
)
{
{
field_op
(
lhs
,
OPCODE_putstatic
);
min_value
++
;
max_value
++
;
}
}
else
else
if
(
arg1
==
lhs
)
{
{
int
index
=
DECL_LOCAL_INDEX
(
lhs
)
;
arg0
=
arg1
;
int
opcode
=
adjust_typed_op
(
TREE_TYPE
(
lhs
)
);
arg1
=
TREE_OPERAND
(
rhs
,
0
);
if
(
index
<=
3
)
}
{
if
(
lhs
==
arg0
&&
TREE_CODE
(
arg1
)
==
INTEGER_CST
)
RESERVE
(
1
);
{
opcode
=
59
+
4
*
opcode
+
index
;
HOST_WIDE_INT
hi_value
=
TREE_INT_CST_HIGH
(
arg1
)
;
OP1
(
opcode
);
/* [ilfda]store_[0123] */
value
=
TREE_INT_CST_LOW
(
arg1
);
}
if
((
hi_value
==
0
&&
value
<=
max_value
)
else
||
(
hi_value
==
-
1
&&
value
>=
min_value
))
{
{
maybe_wide
(
54
+
opcode
,
index
);
/* [ilfda]store */
if
(
TREE_CODE
(
rhs
)
==
MINUS_EXPR
)
value
=
-
value
;
emit_iinc
(
lhs
,
value
,
state
);
break
;
}
}
}
}
}
}
if
(
TREE_CODE
(
lhs
)
==
COMPONENT_REF
)
generate_bytecode_insns
(
TREE_OPERAND
(
lhs
,
0
),
STACK_TARGET
,
state
);
else
if
(
TREE_CODE
(
lhs
)
==
ARRAY_REF
)
else
if
(
TREE_CODE
(
lhs
)
==
ARRAY_REF
)
{
{
jopcode
=
OPCODE_iastore
+
adjust_typed_op
(
TREE_TYPE
(
lhs
));
generate_bytecode_insns
(
TREE_OPERAND
(
lhs
,
0
),
STACK_TARGET
,
state
);
RESERVE
(
1
);
generate_bytecode_insns
(
TREE_OPERAND
(
lhs
,
1
),
STACK_TARGET
,
state
);
OP1
(
jopcode
);
}
}
else
generate_bytecode_insns
(
rhs
,
STACK_TARGET
,
state
);
fatal
(
"internal error (bad lhs to MODIFY_EXPR)"
);
if
(
target
!=
IGNORE_TARGET
)
emit_dup
(
TYPE_IS_WIDE
(
type
)
?
2
:
1
,
1
,
state
);
exp
=
lhs
;
}
}
/* FALLTHOUGH */
finish_assignment
:
if
(
TREE_CODE
(
exp
)
==
COMPONENT_REF
)
{
tree
field
=
TREE_OPERAND
(
exp
,
1
);
if
(
!
FIELD_STATIC
(
field
))
NOTE_POP
(
1
);
field_op
(
field
,
FIELD_STATIC
(
field
)
?
OPCODE_putstatic
:
OPCODE_putfield
,
state
);
NOTE_PUSH
(
TYPE_IS_WIDE
(
TREE_TYPE
(
field
))
?
2
:
1
);
}
else
if
(
TREE_CODE
(
exp
)
==
VAR_DECL
||
TREE_CODE
(
exp
)
==
PARM_DECL
)
{
if
(
FIELD_STATIC
(
exp
))
{
field_op
(
exp
,
OPCODE_putstatic
,
state
);
NOTE_PUSH
(
TYPE_IS_WIDE
(
TREE_TYPE
(
exp
))
?
2
:
1
);
}
else
emit_store
(
exp
,
state
);
}
else
if
(
TREE_CODE
(
exp
)
==
ARRAY_REF
)
{
NOTE_POP
(
2
);
jopcode
=
OPCODE_iastore
+
adjust_typed_op
(
TREE_TYPE
(
exp
));
RESERVE
(
1
);
OP1
(
jopcode
);
NOTE_PUSH
(
TYPE_IS_WIDE
(
TREE_TYPE
(
exp
))
?
2
:
1
);
}
else
fatal
(
"internal error (bad lhs to MODIFY_EXPR)"
);
break
;
break
;
case
PLUS_EXPR
:
case
PLUS_EXPR
:
jopcode
=
OPCODE_iadd
+
adjust_typed_op
(
type
);
jopcode
=
OPCODE_iadd
+
adjust_typed_op
(
type
);
...
@@ -702,25 +1422,24 @@ generate_bytecode_insns (method, exp, target)
...
@@ -702,25 +1422,24 @@ generate_bytecode_insns (method, exp, target)
jopcode
=
OPCODE_idiv
+
adjust_typed_op
(
type
);
jopcode
=
OPCODE_idiv
+
adjust_typed_op
(
type
);
goto
binop
;
goto
binop
;
binop
:
binop
:
generate_bytecode_insns
(
method
,
TREE_OPERAND
(
exp
,
0
),
target
);
generate_bytecode_insns
(
TREE_OPERAND
(
exp
,
0
),
target
,
state
);
generate_bytecode_insns
(
method
,
TREE_OPERAND
(
exp
,
1
),
target
);
generate_bytecode_insns
(
TREE_OPERAND
(
exp
,
1
),
target
,
state
);
if
(
target
==
STACK_TARGET
)
if
(
target
==
STACK_TARGET
)
{
emit_binop
(
jopcode
,
type
,
state
);
RESERVE
(
1
);
OP1
(
jopcode
);
}
break
;
break
;
case
CALL_EXPR
:
case
CALL_EXPR
:
{
{
tree
t
;
tree
t
;
int
save_SP
=
state
->
code_SP
;
for
(
t
=
TREE_OPERAND
(
exp
,
1
);
t
!=
NULL_TREE
;
t
=
TREE_CHAIN
(
t
))
for
(
t
=
TREE_OPERAND
(
exp
,
1
);
t
!=
NULL_TREE
;
t
=
TREE_CHAIN
(
t
))
{
{
generate_bytecode_insns
(
method
,
TREE_VALUE
(
t
),
STACK_TARGET
);
generate_bytecode_insns
(
TREE_VALUE
(
t
),
STACK_TARGET
,
state
);
}
}
t
=
TREE_OPERAND
(
exp
,
0
);
t
=
TREE_OPERAND
(
exp
,
0
);
state
->
code_SP
=
save_SP
;
if
(
TREE_CODE
(
t
)
==
FUNCTION_DECL
)
if
(
TREE_CODE
(
t
)
==
FUNCTION_DECL
)
{
{
int
index
=
find_methodref_index
(
code_
cpool
,
t
);
int
index
=
find_methodref_index
(
&
state
->
cpool
,
t
);
RESERVE
(
3
);
RESERVE
(
3
);
if
(
DECL_CONSTRUCTOR_P
(
t
))
if
(
DECL_CONSTRUCTOR_P
(
t
))
OP1
(
OPCODE_invokespecial
);
OP1
(
OPCODE_invokespecial
);
...
@@ -729,59 +1448,232 @@ generate_bytecode_insns (method, exp, target)
...
@@ -729,59 +1448,232 @@ generate_bytecode_insns (method, exp, target)
else
else
OP1
(
OPCODE_invokevirtual
);
OP1
(
OPCODE_invokevirtual
);
OP2
(
index
);
OP2
(
index
);
t
=
TREE_TYPE
(
TREE_TYPE
(
t
));
if
(
TREE_CODE
(
t
)
!=
VOID_TYPE
)
{
int
size
=
TYPE_IS_WIDE
(
t
)
?
2
:
1
;
if
(
target
==
IGNORE_TARGET
)
emit_pop
(
size
,
state
);
else
NOTE_PUSH
(
size
);
}
break
;
break
;
}
}
}
}
/* fall through */
/* fall through */
notimpl
:
default
:
default
:
error
(
"internal error - tree code not implemented: "
,
TREE_CODE
(
exp
));
error
(
"internal error - tree code not implemented: %s"
,
tree_code_name
[(
int
)
TREE_CODE
(
exp
)]);
}
}
}
}
void
perform_relocations
(
state
)
struct
jcf_partial
*
state
;
{
struct
jcf_block
*
block
;
struct
jcf_relocation
*
reloc
;
int
pc
;
int
shrink
;
/* Figure out the actual locations of each block. */
pc
=
0
;
shrink
=
0
;
for
(
block
=
state
->
blocks
;
block
!=
NULL
;
block
=
block
->
next
)
{
int
block_size
=
block
->
chunk
->
size
;
block
->
pc
=
pc
;
/* Optimize GOTO L; L: by getting rid of the redundant goto.
Assumes relocations are in reverse order. */
reloc
=
block
->
u
.
relocations
;
while
(
reloc
!=
NULL
&&
reloc
->
label
->
pc
==
block
->
next
->
pc
&&
reloc
->
offset
+
2
==
block_size
&&
reloc
->
kind
==
OPCODE_goto_w
)
{
reloc
=
reloc
->
next
;
block
->
u
.
relocations
=
reloc
;
block
->
chunk
->
size
-=
3
;
block_size
-=
3
;
shrink
+=
3
;
}
for
(
reloc
=
block
->
u
.
relocations
;
reloc
!=
NULL
;
reloc
=
reloc
->
next
)
{
if
(
reloc
->
kind
<
-
1
||
reloc
->
kind
>
0
)
{
int
delta
=
reloc
->
label
->
pc
-
(
pc
+
reloc
->
offset
-
1
);
int
expand
=
reloc
->
kind
>
0
?
2
:
5
;
if
(
delta
>
0
)
delta
-=
shrink
;
if
(
delta
>=
-
32768
&&
delta
<=
32767
)
{
shrink
+=
expand
;
reloc
->
kind
=
-
1
;
}
else
block_size
+=
expand
;
}
}
pc
+=
block_size
;
}
for
(
block
=
state
->
blocks
;
block
!=
NULL
;
block
=
block
->
next
)
{
struct
chunk
*
chunk
=
block
->
chunk
;
int
old_size
=
chunk
->
size
;
int
next_pc
=
block
->
next
==
NULL
?
pc
:
block
->
next
->
pc
;
int
new_size
=
next_pc
-
block
->
pc
;
int
offset
=
0
;
unsigned
char
*
new_ptr
;
unsigned
char
*
old_buffer
=
chunk
->
data
;
unsigned
char
*
old_ptr
=
old_buffer
+
old_size
;
int
new_end
=
new_size
;
if
(
new_size
!=
old_size
)
{
chunk
->
data
=
(
unsigned
char
*
)
obstack_alloc
(
state
->
chunk_obstack
,
new_size
);
}
new_ptr
=
chunk
->
data
+
new_size
;
/* We do the relocations from back to front, because
thre relocations are in reverse order. */
for
(
reloc
=
block
->
u
.
relocations
;
;
reloc
=
reloc
->
next
)
{
/* Lower old index of piece to be copied with no relocation. */
int
start
=
reloc
==
NULL
?
0
:
reloc
->
kind
==
0
?
reloc
->
offset
+
4
:
reloc
->
offset
+
2
;
int32
value
;
int
new_offset
;
int
n
=
(
old_ptr
-
old_buffer
)
-
start
;
new_ptr
-=
n
;
old_ptr
-=
n
;
if
(
n
>
0
)
bcopy
(
old_ptr
,
new_ptr
,
n
);
if
(
old_ptr
==
old_buffer
)
break
;
if
(
reloc
->
kind
==
0
)
{
old_ptr
-=
4
;
value
=
GET_u4
(
old_ptr
);
}
else
{
old_ptr
-=
2
;
value
=
GET_u2
(
old_ptr
);
}
new_offset
=
new_ptr
-
chunk
->
data
-
(
reloc
->
kind
==
-
1
?
2
:
4
);
value
+=
reloc
->
label
->
pc
-
(
block
->
pc
+
new_offset
);
*--
new_ptr
=
(
unsigned
char
)
value
;
value
>>=
8
;
*--
new_ptr
=
(
unsigned
char
)
value
;
value
>>=
8
;
if
(
reloc
->
kind
!=
-
1
)
{
*--
new_ptr
=
(
unsigned
char
)
value
;
value
>>=
8
;
*--
new_ptr
=
(
unsigned
char
)
value
;
}
if
(
reloc
->
kind
>
0
)
{
/* Convert: OP TARGET to: OP_w TARGET; (OP is goto or jsr). */
--
old_ptr
;
*--
new_ptr
=
reloc
->
kind
;
}
else
if
(
reloc
->
kind
<
-
1
)
{
/* Convert: ifCOND TARGET to: ifNCOND T; goto_w TARGET; T: */
--
old_ptr
;
*--
new_ptr
=
OPCODE_goto_w
;
*--
new_ptr
=
3
;
*--
new_ptr
=
0
;
*--
new_ptr
=
-
reloc
->
kind
;
}
}
}
state
->
code_length
=
pc
;
}
void
init_jcf_state
(
state
,
work
)
struct
jcf_partial
*
state
;
struct
obstack
*
work
;
{
state
->
chunk_obstack
=
work
;
state
->
first
=
state
->
chunk
=
NULL
;
CPOOL_INIT
(
&
state
->
cpool
);
BUFFER_INIT
(
&
state
->
localvars
);
BUFFER_INIT
(
&
state
->
bytecode
);
}
void
init_jcf_method
(
state
,
method
)
struct
jcf_partial
*
state
;
tree
method
;
{
state
->
current_method
=
method
;
state
->
blocks
=
state
->
last_block
=
NULL
;
state
->
linenumber_count
=
0
;
state
->
first_lvar
=
state
->
last_lvar
=
NULL
;
state
->
lvar_count
=
0
;
state
->
labeled_blocks
=
NULL
;
state
->
code_length
=
0
;
BUFFER_RESET
(
&
state
->
bytecode
);
BUFFER_RESET
(
&
state
->
localvars
);
state
->
code_SP
=
0
;
state
->
code_SP_max
=
0
;
}
void
release_jcf_state
(
state
)
struct
jcf_partial
*
state
;
{
CPOOL_FINISH
(
&
state
->
cpool
);
obstack_free
(
state
->
chunk_obstack
,
state
->
first
);
}
/* Generate and return a list of chunks containing the class CLAS
/* Generate and return a list of chunks containing the class CLAS
in the .class file representation. The list can be written to a
in the .class file representation. The list can be written to a
.class file using write_chunks. Allocate chunks from obstack WORK. */
.class file using write_chunks. Allocate chunks from obstack WORK. */
/* Currently does not write any attributes i.e. no code. */
struct
chunk
*
struct
chunk
*
generate_classfile
(
clas
,
work
)
generate_classfile
(
clas
,
state
)
tree
clas
;
tree
clas
;
struct
obstack
*
work
;
struct
jcf_partial
*
state
;
{
{
CPool
cpool
;
struct
chunk
head
;
struct
chunk
*
chunk
;
struct
chunk
*
cpool_chunk
;
struct
chunk
*
cpool_chunk
;
char
*
source_file
;
char
*
ptr
;
char
*
ptr
;
int
i
;
int
i
;
char
*
fields_count_ptr
;
char
*
fields_count_ptr
;
int
fields_count
=
0
;
int
fields_count
=
0
;
char
*
methods_count_ptr
;
char
*
methods_count_ptr
;
int
methods_count
=
0
;
int
methods_count
=
0
;
static
tree
SourceFile_node
=
NULL_TREE
;
tree
part
;
tree
part
;
int
total_supers
int
total_supers
=
clas
==
object_type_node
?
0
=
clas
==
object_type_node
?
0
:
TREE_VEC_LENGTH
(
TYPE_BINFO_BASETYPES
(
clas
));
:
TREE_VEC_LENGTH
(
TYPE_BINFO_BASETYPES
(
clas
));
chunk
=
alloc_chunk
(
&
head
,
NULL
,
8
,
work
);
ptr
=
append_chunk
(
NULL
,
8
,
state
);
ptr
=
chunk
->
data
;
PUT4
(
0xCafeBabe
);
/* Magic number */
PUT4
(
0xCafeBabe
);
/* Magic number */
PUT2
(
3
);
/* Minor version */
PUT2
(
3
);
/* Minor version */
PUT2
(
45
);
/* Major version */
PUT2
(
45
);
/* Major version */
CPOOL_INIT
(
&
cpool
);
append_chunk
(
NULL
,
0
,
state
);
cpool_chunk
=
chunk
=
alloc_chunk
(
chunk
,
NULL
,
0
,
work
)
;
cpool_chunk
=
state
->
chunk
;
/* Next allocate the chunk containing acces_flags through fields_counr. */
/* Next allocate the chunk containing acces_flags through fields_counr. */
if
(
clas
==
object_type_node
)
if
(
clas
==
object_type_node
)
i
=
10
;
i
=
10
;
else
else
i
=
8
+
2
*
total_supers
;
i
=
8
+
2
*
total_supers
;
chunk
=
alloc_chunk
(
chunk
,
NULL
,
i
,
work
);
ptr
=
append_chunk
(
NULL
,
i
,
state
);
ptr
=
chunk
->
data
;
i
=
get_access_flags
(
TYPE_NAME
(
clas
));
PUT2
(
i
);
/* acces_flags */
i
=
get_access_flags
(
TYPE_NAME
(
clas
));
PUT2
(
i
);
/* acces_flags */
i
=
find_class_constant
(
&
cpool
,
clas
);
PUT2
(
i
);
/* this_class */
i
=
find_class_constant
(
&
state
->
cpool
,
clas
);
PUT2
(
i
);
/* this_class */
if
(
clas
==
object_type_node
)
if
(
clas
==
object_type_node
)
{
{
PUT2
(
0
);
/* super_class */
PUT2
(
0
);
/* super_class */
...
@@ -791,12 +1683,13 @@ generate_classfile (clas, work)
...
@@ -791,12 +1683,13 @@ generate_classfile (clas, work)
{
{
tree
basetypes
=
TYPE_BINFO_BASETYPES
(
clas
);
tree
basetypes
=
TYPE_BINFO_BASETYPES
(
clas
);
tree
base
=
BINFO_TYPE
(
TREE_VEC_ELT
(
basetypes
,
0
));
tree
base
=
BINFO_TYPE
(
TREE_VEC_ELT
(
basetypes
,
0
));
int
j
=
find_class_constant
(
&
cpool
,
base
);
PUT2
(
j
);
/* super_class */
int
j
=
find_class_constant
(
&
state
->
cpool
,
base
);
PUT2
(
j
);
/* super_class */
PUT2
(
total_supers
-
1
);
/* interfaces_count */
PUT2
(
total_supers
-
1
);
/* interfaces_count */
for
(
i
=
1
;
i
<
total_supers
;
i
++
)
for
(
i
=
1
;
i
<
total_supers
;
i
++
)
{
{
base
=
BINFO_TYPE
(
TREE_VEC_ELT
(
basetypes
,
i
));
base
=
BINFO_TYPE
(
TREE_VEC_ELT
(
basetypes
,
i
));
j
=
find_class_constant
(
&
cpool
,
base
);
j
=
find_class_constant
(
&
state
->
cpool
,
base
);
PUT2
(
j
);
PUT2
(
j
);
}
}
}
}
...
@@ -806,11 +1699,10 @@ generate_classfile (clas, work)
...
@@ -806,11 +1699,10 @@ generate_classfile (clas, work)
{
{
if
(
DECL_NAME
(
part
)
==
NULL_TREE
)
if
(
DECL_NAME
(
part
)
==
NULL_TREE
)
continue
;
continue
;
chunk
=
alloc_chunk
(
chunk
,
NULL
,
8
,
work
);
ptr
=
append_chunk
(
NULL
,
8
,
state
);
ptr
=
chunk
->
data
;
i
=
get_access_flags
(
part
);
PUT2
(
i
);
i
=
get_access_flags
(
part
);
PUT2
(
i
);
i
=
find_utf8_constant
(
&
cpool
,
DECL_NAME
(
part
));
PUT2
(
i
);
i
=
find_utf8_constant
(
&
state
->
cpool
,
DECL_NAME
(
part
));
PUT2
(
i
);
i
=
find_utf8_constant
(
&
cpool
,
build_java_signature
(
TREE_TYPE
(
part
)));
i
=
find_utf8_constant
(
&
state
->
cpool
,
build_java_signature
(
TREE_TYPE
(
part
)));
PUT2
(
i
);
PUT2
(
i
);
PUT2
(
0
);
/* attributes_count */
PUT2
(
0
);
/* attributes_count */
/* FIXME - emit ConstantValue attribute when appropriate */
/* FIXME - emit ConstantValue attribute when appropriate */
...
@@ -818,120 +1710,141 @@ generate_classfile (clas, work)
...
@@ -818,120 +1710,141 @@ generate_classfile (clas, work)
}
}
ptr
=
fields_count_ptr
;
PUT2
(
fields_count
);
ptr
=
fields_count_ptr
;
PUT2
(
fields_count
);
chunk
=
alloc_chunk
(
chunk
,
NULL
,
2
,
work
);
ptr
=
methods_count_ptr
=
append_chunk
(
NULL
,
2
,
state
);
ptr
=
methods_count_ptr
=
chunk
->
data
;
PUT2
(
0
);
PUT2
(
0
);
for
(
part
=
TYPE_METHODS
(
clas
);
part
;
part
=
TREE_CHAIN
(
part
))
for
(
part
=
TYPE_METHODS
(
clas
);
part
;
part
=
TREE_CHAIN
(
part
))
{
{
struct
jcf_block
*
block
;
tree
body
=
BLOCK_EXPR_BODY
(
DECL_FUNCTION_BODY
(
part
));
tree
body
=
BLOCK_EXPR_BODY
(
DECL_FUNCTION_BODY
(
part
));
int
linenumber_size
;
/* 4 * number of line number entries */
tree
name
=
DECL_CONSTRUCTOR_P
(
part
)
?
init_identifier_node
chunk
=
alloc_chunk
(
chunk
,
NULL
,
8
,
work
);
:
DECL_NAME
(
part
);
ptr
=
chunk
->
data
;
tree
type
=
TREE_TYPE
(
part
);
ptr
=
append_chunk
(
NULL
,
8
,
state
);
i
=
get_access_flags
(
part
);
PUT2
(
i
);
i
=
get_access_flags
(
part
);
PUT2
(
i
);
i
=
find_utf8_constant
(
&
cpool
,
DECL_NAME
(
part
)
);
PUT2
(
i
);
i
=
find_utf8_constant
(
&
state
->
cpool
,
name
);
PUT2
(
i
);
i
=
find_utf8_constant
(
&
cpool
,
build_java_signature
(
TREE_TYPE
(
part
)
));
i
=
find_utf8_constant
(
&
state
->
cpool
,
build_java_signature
(
type
));
PUT2
(
i
);
PUT2
(
i
);
PUT2
(
body
!=
NULL_TREE
?
1
:
0
);
/* attributes_count */
PUT2
(
body
!=
NULL_TREE
?
1
:
0
);
/* attributes_count */
if
(
body
!=
NULL_TREE
)
if
(
body
!=
NULL_TREE
)
{
{
int
code_attributes_count
=
0
;
int
code_attributes_count
=
0
;
int
linenumber_size
;
/* 4 * number of line number entries */
int
localvartable_size
;
/* 10 * number of local variable entries */
static
tree
Code_node
=
NULL_TREE
;
static
tree
Code_node
=
NULL_TREE
;
tree
t
;
tree
t
;
char
*
attr_len_ptr
;
char
*
attr_len_ptr
;
int
code_length
;
if
(
Code_node
==
NULL_TREE
)
if
(
Code_node
==
NULL_TREE
)
Code_node
=
get_identifier
(
"Code"
);
Code_node
=
get_identifier
(
"Code"
);
chunk
=
alloc_chunk
(
chunk
,
NULL
,
14
,
work
);
ptr
=
append_chunk
(
NULL
,
14
,
state
);
ptr
=
chunk
->
data
;
i
=
find_utf8_constant
(
&
state
->
cpool
,
Code_node
);
PUT2
(
i
);
i
=
find_utf8_constant
(
&
cpool
,
Code_node
);
PUT2
(
i
);
attr_len_ptr
=
ptr
;
attr_len_ptr
=
ptr
;
BUFFER_RESET
(
&
bytecode
);
init_jcf_method
(
state
,
part
);
BUFFER_RESET
(
&
localvartable
);
get_jcf_label_here
(
state
);
/* Force a first block. */
BUFFER_RESET
(
&
linenumbers
);
BUFFER_RESET
(
&
localvars
);
code_SP
=
0
;
code_SP_max
=
0
;
code_cpool
=
&
cpool
;
for
(
t
=
DECL_ARGUMENTS
(
part
);
t
!=
NULL_TREE
;
t
=
TREE_CHAIN
(
t
))
for
(
t
=
DECL_ARGUMENTS
(
part
);
t
!=
NULL_TREE
;
t
=
TREE_CHAIN
(
t
))
localvar_alloc
(
t
,
0
);
localvar_alloc
(
t
,
state
);
generate_bytecode_insns
(
part
,
body
,
IGNORE_TARGET
);
generate_bytecode_insns
(
body
,
IGNORE_TARGET
,
state
);
code_length
=
PC
;
for
(
t
=
DECL_ARGUMENTS
(
part
);
t
!=
NULL_TREE
;
t
=
TREE_CHAIN
(
t
))
for
(
t
=
DECL_ARGUMENTS
(
part
);
t
!=
NULL_TREE
;
t
=
TREE_CHAIN
(
t
))
localvar_free
(
t
,
code_length
);
localvar_free
(
t
,
state
);
linenumber_size
=
BUFFER_LENGTH
(
&
linenumbers
);
finish_jcf_block
(
state
);
localvartable_size
=
BUFFER_LENGTH
(
&
localvartable
);
perform_relocations
(
state
);
chunk
=
alloc_chunk
(
chunk
,
NULL
,
code_length
,
work
);
bcopy
(
bytecode
.
data
,
chunk
->
data
,
code_length
);
ptr
=
attr_len_ptr
;
ptr
=
attr_len_ptr
;
i
=
8
+
code_length
+
4
;
i
=
8
+
state
->
code_length
+
4
;
if
(
linenumber_size
>
0
)
if
(
state
->
linenumber_count
>
0
)
{
{
code_attributes_count
++
;
code_attributes_count
++
;
i
+=
8
+
linenumber_size
;
i
+=
8
+
4
*
state
->
linenumber_count
;
}
}
if
(
localvartable_size
>
0
)
if
(
state
->
lvar_count
>
0
)
{
{
code_attributes_count
++
;
code_attributes_count
++
;
i
+=
8
+
localvartable_size
;
i
+=
8
+
10
*
state
->
lvar_count
;
}
}
PUT4
(
i
);
/* attribute_length */
PUT4
(
i
);
/* attribute_length */
PUT2
(
code_SP_max
);
/* max_stack */
PUT2
(
state
->
code_SP_max
);
/* max_stack */
PUT2
(
localvar_max
);
/* max_locals */
PUT2
(
localvar_max
);
/* max_locals */
PUT4
(
code_length
);
PUT4
(
state
->
code_length
);
chunk
=
alloc_chunk
(
chunk
,
NULL
,
4
,
work
);
ptr
=
append_chunk
(
NULL
,
4
,
state
);
ptr
=
chunk
->
data
;
PUT2
(
0
);
/* exception_table_length */
PUT2
(
0
);
/* exception_table_length */
PUT2
(
code_attributes_count
);
PUT2
(
code_attributes_count
);
/* Write the LineNumberTable attribute. */
/* Write the LineNumberTable attribute. */
if
(
linenumber_size
>
0
)
if
(
state
->
linenumber_count
>
0
)
{
{
static
tree
LineNumberTable_node
=
NULL_TREE
;
static
tree
LineNumberTable_node
=
NULL_TREE
;
chunk
=
alloc_chunk
(
chunk
,
NULL
,
8
+
linenumber_size
,
work
);
ptr
=
append_chunk
(
NULL
,
8
+
4
*
state
->
linenumber_count
,
state
);
ptr
=
chunk
->
data
;
if
(
LineNumberTable_node
==
NULL_TREE
)
if
(
LineNumberTable_node
==
NULL_TREE
)
LineNumberTable_node
=
get_identifier
(
"LineNumberTable"
);
LineNumberTable_node
=
get_identifier
(
"LineNumberTable"
);
i
=
find_utf8_constant
(
&
cpool
,
LineNumberTable_node
);
i
=
find_utf8_constant
(
&
state
->
cpool
,
LineNumberTable_node
);
PUT2
(
i
);
/* attribute_name_index */
PUT2
(
i
);
/* attribute_name_index */
i
=
2
+
linenumber_size
;
PUT4
(
i
);
/* attribute_length */
i
=
2
+
4
*
state
->
linenumber_count
;
PUT4
(
i
);
/* attribute_length */
i
=
linenumber_size
>>
2
;
PUT2
(
i
);
i
=
state
->
linenumber_count
;
PUT2
(
i
);
PUTN
(
linenumbers
.
data
,
linenumber_size
);
for
(
block
=
state
->
blocks
;
block
!=
NULL
;
block
=
block
->
next
)
{
int
line
=
block
->
linenumber
;
if
(
line
>
0
)
{
PUT2
(
block
->
pc
);
PUT2
(
line
);
}
}
}
}
/* Write the LocalVariableTable attribute. */
/* Write the LocalVariableTable attribute. */
if
(
localvartable_size
>
0
)
if
(
state
->
lvar_count
>
0
)
{
{
static
tree
LocalVariableTable_node
=
NULL_TREE
;
static
tree
LocalVariableTable_node
=
NULL_TREE
;
chunk
=
alloc_chunk
(
chunk
,
NULL
,
8
+
localvartable_size
,
work
)
;
struct
localvar_info
*
lvar
=
state
->
first_lvar
;
ptr
=
chunk
->
data
;
ptr
=
append_chunk
(
NULL
,
8
+
10
*
state
->
lvar_count
,
state
)
;
if
(
LocalVariableTable_node
==
NULL_TREE
)
if
(
LocalVariableTable_node
==
NULL_TREE
)
LocalVariableTable_node
=
get_identifier
(
"LocalVariableTable"
);
LocalVariableTable_node
=
get_identifier
(
"LocalVariableTable"
);
i
=
find_utf8_constant
(
&
cpool
,
LocalVariableTable_node
);
i
=
find_utf8_constant
(
&
state
->
cpool
,
LocalVariableTable_node
);
PUT2
(
i
);
/* attribute_name_index */
PUT2
(
i
);
/* attribute_name_index */
i
=
2
+
localvartable_size
;
PUT4
(
i
);
/* attribute_length */
i
=
2
+
10
*
state
->
lvar_count
;
PUT4
(
i
);
/* attribute_length */
i
=
localvartable_size
/
10
;
PUT2
(
i
);
i
=
state
->
lvar_count
;
PUT2
(
i
);
PUTN
(
localvartable
.
data
,
localvartable_size
);
for
(
;
lvar
!=
NULL
;
lvar
=
lvar
->
next
)
{
tree
name
=
DECL_NAME
(
lvar
->
decl
);
tree
sig
=
build_java_signature
(
TREE_TYPE
(
lvar
->
decl
));
i
=
lvar
->
start_label
->
pc
;
PUT2
(
i
);
i
=
lvar
->
end_label
->
pc
-
i
;
PUT2
(
i
);
i
=
find_utf8_constant
(
&
state
->
cpool
,
name
);
PUT2
(
i
);
i
=
find_utf8_constant
(
&
state
->
cpool
,
sig
);
PUT2
(
i
);
i
=
DECL_LOCAL_INDEX
(
lvar
->
decl
);
PUT2
(
i
);
}
}
}
}
}
methods_count
++
;
methods_count
++
;
}
}
ptr
=
methods_count_ptr
;
PUT2
(
methods_count
);
ptr
=
methods_count_ptr
;
PUT2
(
methods_count
);
chunk
=
alloc_chunk
(
chunk
,
NULL
,
2
,
work
);
source_file
=
DECL_SOURCE_FILE
(
TYPE_NAME
(
clas
));
ptr
=
chunk
->
data
;
for
(
ptr
=
source_file
;
;
ptr
++
)
PUT2
(
0
);
/* attributes_count */
{
char
ch
=
*
ptr
;
if
(
ch
==
'\0'
)
break
;
if
(
ch
==
'/'
||
ch
==
'\\'
)
source_file
=
ptr
+
1
;
}
ptr
=
append_chunk
(
NULL
,
10
,
state
);
PUT2
(
1
);
/* attributes_count */
/* generate the SourceFile attribute. */
if
(
SourceFile_node
==
NULL_TREE
)
SourceFile_node
=
get_identifier
(
"SourceFile"
);
i
=
find_utf8_constant
(
&
state
->
cpool
,
SourceFile_node
);
PUT2
(
i
);
/* attribute_name_index */
PUT4
(
2
);
i
=
find_utf8_constant
(
&
state
->
cpool
,
get_identifier
(
source_file
));
PUT2
(
i
);
/* New finally generate the contents of the constant pool chunk. */
/* New finally generate the contents of the constant pool chunk. */
i
=
count_constant_pool_bytes
(
&
cpool
);
i
=
count_constant_pool_bytes
(
&
state
->
cpool
);
ptr
=
obstack_alloc
(
wor
k
,
i
);
ptr
=
obstack_alloc
(
state
->
chunk_obstac
k
,
i
);
cpool_chunk
->
data
=
ptr
;
cpool_chunk
->
data
=
ptr
;
cpool_chunk
->
size
=
i
;
cpool_chunk
->
size
=
i
;
write_constant_pool
(
&
cpool
,
ptr
,
i
);
write_constant_pool
(
&
state
->
cpool
,
ptr
,
i
);
CPOOL_FINISH
(
&
cpool
);
return
state
->
first
;
return
head
.
next
;
}
}
char
*
char
*
...
@@ -951,14 +1864,16 @@ write_classfile (clas)
...
@@ -951,14 +1864,16 @@ write_classfile (clas)
tree
clas
;
tree
clas
;
{
{
struct
obstack
*
work
=
&
temporary_obstack
;
struct
obstack
*
work
=
&
temporary_obstack
;
struct
jcf_partial
state
[
1
];
char
*
class_file_name
=
make_class_file_name
(
clas
);
char
*
class_file_name
=
make_class_file_name
(
clas
);
struct
chunk
*
chunks
;
struct
chunk
*
chunks
;
FILE
*
stream
=
fopen
(
class_file_name
,
"wb"
);
FILE
*
stream
=
fopen
(
class_file_name
,
"wb"
);
if
(
stream
==
NULL
)
if
(
stream
==
NULL
)
fatal
(
"failed to open `%s' for writing"
,
class_file_name
);
fatal
(
"failed to open `%s' for writing"
,
class_file_name
);
chunks
=
generate_classfile
(
clas
,
work
);
init_jcf_state
(
state
,
work
);
chunks
=
generate_classfile
(
clas
,
state
);
write_chunks
(
stream
,
chunks
);
write_chunks
(
stream
,
chunks
);
if
(
fclose
(
stream
))
if
(
fclose
(
stream
))
fatal
(
"failed to close after writing `%s'"
,
class_file_name
);
fatal
(
"failed to close after writing `%s'"
,
class_file_name
);
obstack_free
(
work
,
chunks
);
release_jcf_state
(
state
);
}
}
gcc/java/lang.c
View file @
e4de5a10
...
@@ -32,6 +32,40 @@ The Free Software Foundation is independent of Sun Microsystems, Inc. */
...
@@ -32,6 +32,40 @@ The Free Software Foundation is independent of Sun Microsystems, Inc. */
#include "jcf.h"
#include "jcf.h"
#include "toplev.h"
#include "toplev.h"
/* Table indexed by tree code giving a string containing a character
classifying the tree code. Possibilities are
t, d, s, c, r, <, 1 and 2. See java/java-tree.def for details. */
#define DEFTREECODE(SYM, NAME, TYPE, LENGTH) TYPE,
char
java_tree_code_type
[]
=
{
'x'
,
#include "java-tree.def"
};
#undef DEFTREECODE
/* Table indexed by tree code giving number of expression
operands beyond the fixed part of the node structure.
Not used for types or decls. */
#define DEFTREECODE(SYM, NAME, TYPE, LENGTH) LENGTH,
int
java_tree_code_length
[]
=
{
0
,
#include "java-tree.def"
};
#undef DEFTREECODE
/* Names of tree components.
Used for printing out the tree and error messages. */
#define DEFTREECODE(SYM, NAME, TYPE, LEN) NAME,
char
*
java_tree_code_name
[]
=
{
"@@dummy"
,
#include "java-tree.def"
};
#undef DEFTREECODE
int
compiling_from_source
;
int
compiling_from_source
;
char
*
language_string
=
"GNU Java"
;
char
*
language_string
=
"GNU Java"
;
...
@@ -320,6 +354,20 @@ lang_init ()
...
@@ -320,6 +354,20 @@ lang_init ()
current_jcf
=
main_jcf
;
current_jcf
=
main_jcf
;
flag_exceptions
=
1
;
flag_exceptions
=
1
;
/* Append to Gcc tree node definition arrays */
bcopy
(
java_tree_code_type
,
tree_code_type
+
(
int
)
LAST_AND_UNUSED_TREE_CODE
,
(
int
)
LAST_JAVA_TREE_CODE
-
(
int
)
LAST_AND_UNUSED_TREE_CODE
);
bcopy
((
char
*
)
java_tree_code_length
,
(
char
*
)(
tree_code_length
+
(
int
)
LAST_AND_UNUSED_TREE_CODE
),
(
LAST_JAVA_TREE_CODE
-
(
int
)
LAST_AND_UNUSED_TREE_CODE
)
*
sizeof
(
int
));
bcopy
((
char
*
)
java_tree_code_name
,
(
char
*
)(
tree_code_name
+
(
int
)
LAST_AND_UNUSED_TREE_CODE
),
(
LAST_JAVA_TREE_CODE
-
(
int
)
LAST_AND_UNUSED_TREE_CODE
)
*
sizeof
(
char
*
));
}
}
/* This doesn't do anything on purpose. It's used to satisfy the
/* This doesn't do anything on purpose. It's used to satisfy the
...
...
gcc/java/parse.h
View file @
e4de5a10
...
@@ -148,22 +148,32 @@ extern tree stabilize_reference PROTO ((tree));
...
@@ -148,22 +148,32 @@ extern tree stabilize_reference PROTO ((tree));
EXPR_WFL_EMIT_LINE_NOTE (node) = 1, node : node)
EXPR_WFL_EMIT_LINE_NOTE (node) = 1, node : node)
/* Types classification, according to the JLS, section 4.2 */
/* Types classification, according to the JLS, section 4.2 */
#define JFLOAT_TYPE_P(TYPE) (TREE_CODE ((TYPE)) == REAL_TYPE)
#define JFLOAT_TYPE_P(TYPE) (TYPE && TREE_CODE ((TYPE)) == REAL_TYPE)
#define JINTEGRAL_TYPE_P(TYPE) ((TREE_CODE ((TYPE)) == INTEGER_TYPE) \
#define JINTEGRAL_TYPE_P(TYPE) ((TYPE) \
|| (TREE_CODE ((TYPE)) == CHAR_TYPE))
&& (TREE_CODE ((TYPE)) == INTEGER_TYPE \
#define JNUMERIC_TYPE_P(TYPE) (JFLOAT_TYPE_P ((TYPE)) \
|| TREE_CODE ((TYPE)) == CHAR_TYPE))
|| JINTEGRAL_TYPE_P ((TYPE)))
#define JNUMERIC_TYPE_P(TYPE) ((TYPE) \
#define JPRIMITIVE_TYPE_P(TYPE) (JNUMERIC_TYPE_P ((TYPE)) \
&& (JFLOAT_TYPE_P ((TYPE)) \
|| (TREE_CODE ((TYPE)) == BOOLEAN_TYPE))
|| JINTEGRAL_TYPE_P ((TYPE))))
#define JPRIMITIVE_TYPE_P(TYPE) ((TYPE) \
&& (JNUMERIC_TYPE_P ((TYPE)) \
|| TREE_CODE ((TYPE)) == BOOLEAN_TYPE))
/* Not defined in the LRM */
/* Not defined in the LRM */
#define JSTRING_TYPE_P(TYPE) ((TYPE) == string_type_node || \
#define JSTRING_TYPE_P(TYPE) ((TYPE) \
(TREE_CODE (TYPE) == POINTER_TYPE && \
&& ((TYPE) == string_type_node || \
TREE_TYPE (op1_type) == string_type_node))
(TREE_CODE (TYPE) == POINTER_TYPE && \
TREE_TYPE (TYPE) == string_type_node)))
#define JREFERENCE_TYPE_P(TYPE) (TREE_CODE (TYPE) == RECORD_TYPE || \
#define JSTRING_P(NODE) ((NODE) \
(TREE_CODE (TYPE) == POINTER_TYPE && \
&& (TREE_CODE (NODE) == STRING_CST \
TREE_CODE (TREE_TYPE (TYPE)) == RECORD_TYPE))
|| IS_CRAFTED_STRING_BUFFER_P (NODE) \
|| JSTRING_TYPE_P (TREE_TYPE (NODE))))
#define JREFERENCE_TYPE_P(TYPE) ((TYPE) \
&& (TREE_CODE (TYPE) == RECORD_TYPE \
|| (TREE_CODE (TYPE) == POINTER_TYPE \
&& TREE_CODE (TREE_TYPE (TYPE)) == \
RECORD_TYPE)))
/* Other predicate */
/* Other predicate */
#define DECL_P(NODE) (NODE && (TREE_CODE (NODE) == PARM_DECL \
#define DECL_P(NODE) (NODE && (TREE_CODE (NODE) == PARM_DECL \
...
@@ -198,12 +208,12 @@ extern tree stabilize_reference PROTO ((tree));
...
@@ -198,12 +208,12 @@ extern tree stabilize_reference PROTO ((tree));
#define ERROR_VARIABLE_NOT_INITIALIZED(WFL, V) \
#define ERROR_VARIABLE_NOT_INITIALIZED(WFL, V) \
parse_error_context \
parse_error_context \
((WFL), "Variable `%s' may not have been initialized",
\
((WFL), "Variable `%s' may not have been initialized", \
IDENTIFIER_POINTER (V))
IDENTIFIER_POINTER (V))
/* Definition for loop handling. This
Java's own definition of a loop
/* Definition for loop handling. This
is Java's own definition of a
body. See parse.y for documentation. It's valid once you hold a
loop body. See parse.y for documentation. It's valid once you hold
loop's body (LOOP_EXPR_BODY) */
a
loop's body (LOOP_EXPR_BODY) */
/* The loop main block is the one hold the condition and the loop body */
/* The loop main block is the one hold the condition and the loop body */
#define LOOP_EXPR_BODY_MAIN_BLOCK(NODE) TREE_OPERAND (NODE, 0)
#define LOOP_EXPR_BODY_MAIN_BLOCK(NODE) TREE_OPERAND (NODE, 0)
...
@@ -252,7 +262,6 @@ extern tree stabilize_reference PROTO ((tree));
...
@@ -252,7 +262,6 @@ extern tree stabilize_reference PROTO ((tree));
}
}
#define POP_LOOP() ctxp->current_loop = TREE_CHAIN (ctxp->current_loop)
#define POP_LOOP() ctxp->current_loop = TREE_CHAIN (ctxp->current_loop)
/* Invocation modes, as returned by invocation_mode (). */
/* Invocation modes, as returned by invocation_mode (). */
enum
{
enum
{
INVOKE_STATIC
,
INVOKE_STATIC
,
...
@@ -414,6 +423,14 @@ static jdeplist *reverse_jdep_list ();
...
@@ -414,6 +423,14 @@ static jdeplist *reverse_jdep_list ();
#define COMPLETE_CHECK_OP_0(NODE) COMPLETE_CHECK_OP(NODE, 0)
#define COMPLETE_CHECK_OP_0(NODE) COMPLETE_CHECK_OP(NODE, 0)
#define COMPLETE_CHECK_OP_1(NODE) COMPLETE_CHECK_OP(NODE, 1)
#define COMPLETE_CHECK_OP_1(NODE) COMPLETE_CHECK_OP(NODE, 1)
/* Building invocations: append(ARG) and StringBuffer(ARG) */
#define BUILD_APPEND(ARG) \
build_method_invocation (wfl_append, \
(ARG ? build_tree_list (NULL, (ARG)): NULL_TREE))
#define BUILD_STRING_BUFFER(ARG) \
build_new_invocation (wfl_string_buffer, \
(ARG ? build_tree_list (NULL, (ARG)) : NULL_TREE))
/* Parser context data structure. */
/* Parser context data structure. */
struct
parser_ctxt
{
struct
parser_ctxt
{
...
@@ -472,7 +489,8 @@ struct parser_ctxt {
...
@@ -472,7 +489,8 @@ struct parser_ctxt {
#ifndef JC1_LITE
#ifndef JC1_LITE
static
char
*
java_accstring_lookup
PROTO
((
int
));
static
char
*
java_accstring_lookup
PROTO
((
int
));
static
void
parse_error
PROTO
((
char
*
));
static
void
parse_error
PROTO
((
char
*
));
static
void
redefinition_error
PROTO
((
char
*
,
tree
,
tree
,
tree
));
static
void
classitf_redefinition_error
PROTO
((
char
*
,
tree
,
tree
,
tree
));
static
void
variable_redefinition_error
PROTO
((
tree
,
tree
,
tree
,
int
));
static
void
check_modifiers
PROTO
((
char
*
,
int
,
int
));
static
void
check_modifiers
PROTO
((
char
*
,
int
,
int
));
static
tree
create_class
PROTO
((
int
,
tree
,
tree
,
tree
));
static
tree
create_class
PROTO
((
int
,
tree
,
tree
,
tree
));
static
tree
create_interface
PROTO
((
int
,
tree
,
tree
));
static
tree
create_interface
PROTO
((
int
,
tree
,
tree
));
...
@@ -490,6 +508,7 @@ static tree method_header PROTO ((int, tree, tree, tree));
...
@@ -490,6 +508,7 @@ static tree method_header PROTO ((int, tree, tree, tree));
static
tree
method_declarator
PROTO
((
tree
,
tree
));
static
tree
method_declarator
PROTO
((
tree
,
tree
));
static
void
parse_error_context
VPROTO
((
tree
cl
,
char
*
msg
,
...));
static
void
parse_error_context
VPROTO
((
tree
cl
,
char
*
msg
,
...));
static
void
parse_warning_context
VPROTO
((
tree
cl
,
char
*
msg
,
...));
static
void
parse_warning_context
VPROTO
((
tree
cl
,
char
*
msg
,
...));
static
tree
parse_jdk1_1_error
PROTO
((
char
*
));
static
void
complete_class_report_errors
PROTO
((
jdep
*
));
static
void
complete_class_report_errors
PROTO
((
jdep
*
));
static
int
process_imports
PROTO
((
void
));
static
int
process_imports
PROTO
((
void
));
static
void
read_import_dir
PROTO
((
tree
));
static
void
read_import_dir
PROTO
((
tree
));
...
@@ -514,7 +533,9 @@ static tree resolve_and_layout PROTO ((tree, tree));
...
@@ -514,7 +533,9 @@ static tree resolve_and_layout PROTO ((tree, tree));
static
tree
resolve_no_layout
PROTO
((
tree
,
tree
));
static
tree
resolve_no_layout
PROTO
((
tree
,
tree
));
static
int
identical_subpath_p
PROTO
((
tree
,
tree
));
static
int
identical_subpath_p
PROTO
((
tree
,
tree
));
static
int
invocation_mode
PROTO
((
tree
,
int
));
static
int
invocation_mode
PROTO
((
tree
,
int
));
static
tree
refine_accessible_methods_list
PROTO
((
int
,
tree
));
static
tree
find_applicable_accessible_methods_list
PROTO
((
tree
,
tree
,
tree
));
static
tree
find_most_specific_methods_list
PROTO
((
tree
));
static
int
argument_types_convertible
PROTO
((
tree
,
tree
));
static
tree
patch_invoke
PROTO
((
tree
,
tree
,
tree
,
tree
));
static
tree
patch_invoke
PROTO
((
tree
,
tree
,
tree
,
tree
));
static
tree
lookup_method_invoke
PROTO
((
int
,
tree
,
tree
,
tree
,
tree
));
static
tree
lookup_method_invoke
PROTO
((
int
,
tree
,
tree
,
tree
,
tree
));
static
tree
register_incomplete_type
PROTO
((
int
,
tree
,
tree
,
tree
));
static
tree
register_incomplete_type
PROTO
((
int
,
tree
,
tree
,
tree
));
...
@@ -525,10 +546,12 @@ static int unresolved_type_p PROTO ((tree, tree *));
...
@@ -525,10 +546,12 @@ static int unresolved_type_p PROTO ((tree, tree *));
static
void
create_jdep_list
PROTO
((
struct
parser_ctxt
*
));
static
void
create_jdep_list
PROTO
((
struct
parser_ctxt
*
));
static
tree
build_expr_block
PROTO
((
tree
,
tree
));
static
tree
build_expr_block
PROTO
((
tree
,
tree
));
static
tree
enter_block
PROTO
((
void
));
static
tree
enter_block
PROTO
((
void
));
static
tree
enter_a_block
PROTO
((
tree
));
static
tree
exit_block
PROTO
((
void
));
static
tree
exit_block
PROTO
((
void
));
static
tree
lookup_name_in_blocks
PROTO
((
tree
));
static
tree
lookup_name_in_blocks
PROTO
((
tree
));
static
void
maybe_absorb_scoping_blocks
PROTO
((
void
));
static
void
maybe_absorb_scoping_blocks
PROTO
((
void
));
static
tree
build_method_invocation
PROTO
((
tree
,
tree
));
static
tree
build_method_invocation
PROTO
((
tree
,
tree
));
static
tree
build_new_invocation
PROTO
((
tree
,
tree
));
static
tree
build_assignment
PROTO
((
int
,
int
,
tree
,
tree
));
static
tree
build_assignment
PROTO
((
int
,
int
,
tree
,
tree
));
static
tree
build_binop
PROTO
((
enum
tree_code
,
int
,
tree
,
tree
));
static
tree
build_binop
PROTO
((
enum
tree_code
,
int
,
tree
,
tree
));
static
tree
patch_assignment
PROTO
((
tree
,
tree
,
tree
));
static
tree
patch_assignment
PROTO
((
tree
,
tree
,
tree
));
...
@@ -539,7 +562,11 @@ static tree patch_unaryop PROTO ((tree, tree));
...
@@ -539,7 +562,11 @@ static tree patch_unaryop PROTO ((tree, tree));
static
tree
build_cast
PROTO
((
int
,
tree
,
tree
));
static
tree
build_cast
PROTO
((
int
,
tree
,
tree
));
static
tree
patch_cast
PROTO
((
tree
,
tree
,
tree
));
static
tree
patch_cast
PROTO
((
tree
,
tree
,
tree
));
static
int
valid_ref_assignconv_cast_p
PROTO
((
tree
,
tree
,
int
));
static
int
valid_ref_assignconv_cast_p
PROTO
((
tree
,
tree
,
int
));
static
int
can_cast_to_p
PROTO
((
tree
,
tree
));
static
int
valid_builtin_assignconv_identity_widening_p
PROTO
((
tree
,
tree
));
static
int
valid_cast_to_p
PROTO
((
tree
,
tree
));
static
int
valid_method_invocation_conversion_p
PROTO
((
tree
,
tree
));
static
tree
try_builtin_assignconv
PROTO
((
tree
,
tree
,
tree
));
static
tree
try_reference_assignconv
PROTO
((
tree
,
tree
));
static
tree
build_unresolved_array_type
PROTO
((
tree
));
static
tree
build_unresolved_array_type
PROTO
((
tree
));
static
tree
build_array_ref
PROTO
((
int
,
tree
,
tree
));
static
tree
build_array_ref
PROTO
((
int
,
tree
,
tree
));
static
tree
patch_array_ref
PROTO
((
tree
,
tree
,
tree
));
static
tree
patch_array_ref
PROTO
((
tree
,
tree
,
tree
));
...
@@ -565,6 +592,7 @@ static int class_in_current_package PROTO ((tree));
...
@@ -565,6 +592,7 @@ static int class_in_current_package PROTO ((tree));
static
tree
build_if_else_statement
PROTO
((
int
,
tree
,
tree
,
tree
));
static
tree
build_if_else_statement
PROTO
((
int
,
tree
,
tree
,
tree
));
static
tree
patch_if_else_statement
PROTO
((
tree
));
static
tree
patch_if_else_statement
PROTO
((
tree
));
static
tree
add_stmt_to_compound
PROTO
((
tree
,
tree
,
tree
));
static
tree
add_stmt_to_compound
PROTO
((
tree
,
tree
,
tree
));
static
tree
add_stmt_to_block
PROTO
((
tree
,
tree
,
tree
));
static
tree
patch_exit_expr
PROTO
((
tree
));
static
tree
patch_exit_expr
PROTO
((
tree
));
static
tree
build_labeled_block
PROTO
((
int
,
tree
,
tree
));
static
tree
build_labeled_block
PROTO
((
int
,
tree
,
tree
));
static
tree
generate_labeled_block
PROTO
(());
static
tree
generate_labeled_block
PROTO
(());
...
@@ -577,6 +605,14 @@ static tree build_loop_body PROTO ((int, tree, int));
...
@@ -577,6 +605,14 @@ static tree build_loop_body PROTO ((int, tree, int));
static
tree
complete_loop_body
PROTO
((
int
,
tree
,
tree
,
int
));
static
tree
complete_loop_body
PROTO
((
int
,
tree
,
tree
,
int
));
static
tree
build_debugable_stmt
PROTO
((
int
,
tree
));
static
tree
build_debugable_stmt
PROTO
((
int
,
tree
));
static
tree
complete_for_loop
PROTO
((
int
,
tree
,
tree
,
tree
));
static
tree
complete_for_loop
PROTO
((
int
,
tree
,
tree
,
tree
));
static
tree
patch_switch_statement
PROTO
((
tree
));
static
tree
string_constant_concatenation
PROTO
((
tree
,
tree
));
static
tree
build_string_concatenation
PROTO
((
tree
,
tree
));
static
tree
patch_string_cst
PROTO
((
tree
));
static
tree
patch_string
PROTO
((
tree
));
static
tree
build_jump_to_finally
PROTO
((
tree
,
tree
,
tree
,
tree
));
static
tree
build_try_statement
PROTO
((
int
,
tree
,
tree
,
tree
));
static
tree
patch_try_statement
PROTO
((
tree
));
void
safe_layout_class
PROTO
((
tree
));
void
safe_layout_class
PROTO
((
tree
));
void
java_complete_class
PROTO
((
void
));
void
java_complete_class
PROTO
((
void
));
...
@@ -586,6 +622,8 @@ void java_check_methods PROTO ((void));
...
@@ -586,6 +622,8 @@ void java_check_methods PROTO ((void));
void
java_layout_classes
PROTO
((
void
));
void
java_layout_classes
PROTO
((
void
));
tree
java_method_add_stmt
PROTO
((
tree
,
tree
));
tree
java_method_add_stmt
PROTO
((
tree
,
tree
));
char
*
java_get_line_col
PROTO
((
char
*
,
int
,
int
));
char
*
java_get_line_col
PROTO
((
char
*
,
int
,
int
));
void
java_expand_switch
PROTO
((
tree
));
tree
java_get_catch_block
PROTO
((
tree
,
int
));
#endif
/* JC1_LITE */
#endif
/* JC1_LITE */
/* Always in use, no matter what you compile */
/* Always in use, no matter what you compile */
...
...
gcc/java/verify.c
View file @
e4de5a10
...
@@ -930,14 +930,14 @@ verify_jvm_instructions (jcf, byte_ops, length)
...
@@ -930,14 +930,14 @@ verify_jvm_instructions (jcf, byte_ops, length)
case
OPCODE_instanceof
:
case
OPCODE_instanceof
:
pop_type
(
ptr_type_node
);
pop_type
(
ptr_type_node
);
get_class_constant
(
current_jcf
,
IMMEDIATE_u2
);
get_class_constant
(
current_jcf
,
IMMEDIATE_u2
);
push_type
(
int
eger
_type_node
);
push_type
(
int_type_node
);
break
;
break
;
case
OPCODE_tableswitch
:
case
OPCODE_tableswitch
:
{
{
jint
default_val
,
low
,
high
;
jint
default_val
,
low
,
high
;
pop_type
(
int
eger
_type_node
);
pop_type
(
int_type_node
);
while
(
PC
%
4
)
while
(
PC
%
4
)
{
{
if
(
byte_ops
[
PC
++
])
if
(
byte_ops
[
PC
++
])
...
@@ -959,7 +959,7 @@ verify_jvm_instructions (jcf, byte_ops, length)
...
@@ -959,7 +959,7 @@ verify_jvm_instructions (jcf, byte_ops, length)
{
{
jint
npairs
,
last
,
not_registered
=
1
;
jint
npairs
,
last
,
not_registered
=
1
;
pop_type
(
int
eger
_type_node
);
pop_type
(
int_type_node
);
while
(
PC
%
4
)
while
(
PC
%
4
)
{
{
if
(
byte_ops
[
PC
++
])
if
(
byte_ops
[
PC
++
])
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment