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
3885dfa7
Commit
3885dfa7
authored
Nov 12, 1998
by
Per Bothner
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
*** empty log message ***
From-SVN: r23619
parent
421fb085
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
740 additions
and
83 deletions
+740
-83
gcc/java/jcf-write.c
+740
-83
No files found.
gcc/java/jcf-write.c
View file @
3885dfa7
...
@@ -23,6 +23,7 @@ The Free Software Foundation is independent of Sun Microsystems, Inc. */
...
@@ -23,6 +23,7 @@ The Free Software Foundation is independent of Sun Microsystems, Inc. */
#include "config.h"
#include "config.h"
#include "system.h"
#include "system.h"
#include <string.h>
#include "tree.h"
#include "tree.h"
#include "java-tree.h"
#include "java-tree.h"
#include "jcf.h"
#include "jcf.h"
...
@@ -112,6 +113,8 @@ struct jcf_block
...
@@ -112,6 +113,8 @@ struct jcf_block
int
linenumber
;
int
linenumber
;
/* After finish_jcf_block is called, The actual instructions contained in this block.
Before than NULL, and the instructions are in state->bytecode. */
struct
chunk
*
chunk
;
struct
chunk
*
chunk
;
union
{
union
{
...
@@ -124,20 +127,27 @@ struct jcf_block
...
@@ -124,20 +127,27 @@ struct jcf_block
}
u
;
}
u
;
};
};
#define SWITCH_ALIGN_RELOC 4
#define BLOCK_START_RELOC 1
struct
jcf_relocation
struct
jcf_relocation
{
{
/* Next relocation for the current jcf_block. */
/* Next relocation for the current jcf_block. */
struct
jcf_relocation
*
next
;
struct
jcf_relocation
*
next
;
/* The (byte) offset within the current block that needs to be relocated. */
/* The (byte) offset within the current block that needs to be relocated. */
int
offset
;
HOST_WIDE_INT
offset
;
/* 0 if offset is a 4-byte relative offset.
/* 0 if offset is a 4-byte relative offset.
4 (SWITCH_ALIGN_RELOC) if offset points to 0-3 padding bytes inserted
for proper alignment in tableswitch/lookupswitch instructions.
1 (BLOCK_START_RELOC) if offset points to a 4-byte offset relative
to the start of the containing block.
-1 if offset is a 2-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
<
-1
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
that does not have a corresponding 4-byte offset version, in which
case the absolute value of kind is the inverted opcode.
case the absolute value of kind is the inverted opcode.
>
0
if offset is the address of an instruction (such as jsr) with a
>
4
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,
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). */
in which case kind is the opcode of the 4-byte version (such as jsr_w). */
int
kind
;
int
kind
;
...
@@ -146,6 +156,32 @@ struct jcf_relocation
...
@@ -146,6 +156,32 @@ struct jcf_relocation
struct
jcf_block
*
label
;
struct
jcf_block
*
label
;
};
};
/* State for single catch clause. */
struct
jcf_handler
{
struct
jcf_handler
*
next
;
struct
jcf_block
*
start_label
;
struct
jcf_block
*
end_label
;
struct
jcf_block
*
handler_label
;
/* The sub-class of Throwable handled, or NULL_TREE (for finally). */
tree
type
;
};
/* State for the current switch statement. */
struct
jcf_switch_state
{
struct
jcf_switch_state
*
prev
;
struct
jcf_block
*
default_label
;
struct
jcf_relocation
*
cases
;
int
num_cases
;
HOST_WIDE_INT
min_case
,
max_case
;
};
/* This structure is used to contain the various pieces that will
/* This structure is used to contain the various pieces that will
become a .class file. */
become a .class file. */
...
@@ -186,6 +222,18 @@ struct jcf_partial
...
@@ -186,6 +222,18 @@ struct jcf_partial
/* The buffer allocated for bytecode for the current jcf_block. */
/* The buffer allocated for bytecode for the current jcf_block. */
struct
buffer
bytecode
;
struct
buffer
bytecode
;
/* Chain of exception handlers for the current method. */
struct
jcf_handler
*
handlers
;
/* Last element in handlers chain. */
struct
jcf_handler
*
last_handler
;
/* Number of exception handlers for the current method. */
int
num_handlers
;
/* Information about the current switch statemenet. */
struct
jcf_switch_state
*
sw_state
;
};
};
static
void
generate_bytecode_insns
PROTO
((
tree
,
int
,
struct
jcf_partial
*
));
static
void
generate_bytecode_insns
PROTO
((
tree
,
int
,
struct
jcf_partial
*
));
...
@@ -197,7 +245,7 @@ static void generate_bytecode_insns PROTO ((tree, int, struct jcf_partial *));
...
@@ -197,7 +245,7 @@ static void generate_bytecode_insns PROTO ((tree, int, struct jcf_partial *));
#define PUT1(X) (*ptr++ = (X))
#define PUT1(X) (*ptr++ = (X))
#define PUT2(X) (PUT1((X) >> 8), PUT1((X) & 0xFF))
#define PUT2(X) (PUT1((X) >> 8), PUT1((X) & 0xFF))
#define PUT4(X) (PUT2((X) >> 16), PUT2((X) & 0xFFFF))
#define PUT4(X) (PUT2((X) >> 16), PUT2((X) & 0xFFFF))
#define PUTN(P, N) (
bcopy(P, ptr
, N), ptr += (N))
#define PUTN(P, N) (
memcpy(ptr, P
, N), ptr += (N))
/* Allocate a new chunk on obstack WORK, and link it in after LAST.
/* Allocate a new chunk on obstack WORK, and link it in after LAST.
...
@@ -244,7 +292,7 @@ append_chunk_copy (data, size, state)
...
@@ -244,7 +292,7 @@ append_chunk_copy (data, size, state)
struct
jcf_partial
*
state
;
struct
jcf_partial
*
state
;
{
{
unsigned
char
*
ptr
=
append_chunk
(
NULL
,
size
,
state
);
unsigned
char
*
ptr
=
append_chunk
(
NULL
,
size
,
state
);
bcopy
(
data
,
ptr
,
size
);
memcpy
(
ptr
,
data
,
size
);
}
}
struct
jcf_block
*
struct
jcf_block
*
...
@@ -265,9 +313,9 @@ finish_jcf_block (state)
...
@@ -265,9 +313,9 @@ finish_jcf_block (state)
{
{
struct
jcf_block
*
block
=
state
->
last_block
;
struct
jcf_block
*
block
=
state
->
last_block
;
struct
jcf_relocation
*
reloc
;
struct
jcf_relocation
*
reloc
;
int
code_length
=
BUFFER_LENGTH
(
&
state
->
bytecode
);
int
pc
=
state
->
code_length
;
int
pc
=
state
->
code_length
;
append_chunk_copy
(
state
->
bytecode
.
data
,
BUFFER_LENGTH
(
&
state
->
bytecode
),
append_chunk_copy
(
state
->
bytecode
.
data
,
code_length
,
state
);
state
);
BUFFER_RESET
(
&
state
->
bytecode
);
BUFFER_RESET
(
&
state
->
bytecode
);
block
->
chunk
=
state
->
chunk
;
block
->
chunk
=
state
->
chunk
;
...
@@ -276,7 +324,9 @@ finish_jcf_block (state)
...
@@ -276,7 +324,9 @@ finish_jcf_block (state)
for
(
reloc
=
block
->
u
.
relocations
;
reloc
!=
NULL
;
reloc
=
reloc
->
next
)
for
(
reloc
=
block
->
u
.
relocations
;
reloc
!=
NULL
;
reloc
=
reloc
->
next
)
{
{
int
kind
=
reloc
->
kind
;
int
kind
=
reloc
->
kind
;
if
(
kind
>
0
)
if
(
kind
==
SWITCH_ALIGN_RELOC
)
pc
+=
3
;
else
if
(
kind
>
BLOCK_START_RELOC
)
pc
+=
2
;
/* 2-byte offset may grow to 4-byte offset */
pc
+=
2
;
/* 2-byte offset may grow to 4-byte offset */
else
if
(
kind
<
-
1
)
else
if
(
kind
<
-
1
)
pc
+=
5
;
/* May need to add a goto_w. */
pc
+=
5
;
/* May need to add a goto_w. */
...
@@ -326,6 +376,30 @@ put_linenumber (line, state)
...
@@ -326,6 +376,30 @@ put_linenumber (line, state)
state
->
linenumber_count
++
;
state
->
linenumber_count
++
;
}
}
/* Allocate a new jcf_handler, for a catch clause that catches exceptions
in the range (START_LABEL, END_LABEL). */
static
struct
jcf_handler
*
alloc_handler
(
start_label
,
end_label
,
state
)
struct
jcf_block
*
start_label
;
struct
jcf_block
*
end_label
;
struct
jcf_partial
*
state
;
{
struct
jcf_handler
*
handler
=
(
struct
jcf_handler
*
)
obstack_alloc
(
state
->
chunk_obstack
,
sizeof
(
struct
jcf_handler
));
handler
->
start_label
=
start_label
;
handler
->
end_label
=
end_label
;
handler
->
handler_label
=
get_jcf_label_here
(
state
);
if
(
state
->
handlers
==
NULL
)
state
->
handlers
=
handler
;
else
state
->
last_handler
->
next
=
handler
;
state
->
last_handler
=
handler
;
handler
->
next
=
NULL
;
state
->
num_handlers
++
;
return
handler
;
}
/* The index of jvm local variable allocated for this DECL.
/* The index of jvm local variable allocated for this DECL.
This is assigned when generating .class files;
This is assigned when generating .class files;
...
@@ -347,7 +421,7 @@ struct localvar_info
...
@@ -347,7 +421,7 @@ struct localvar_info
#define localvar_max \
#define localvar_max \
((struct localvar_info**) state->localvars.ptr - localvar_buffer)
((struct localvar_info**) state->localvars.ptr - localvar_buffer)
void
int
localvar_alloc
(
decl
,
state
)
localvar_alloc
(
decl
,
state
)
tree
decl
;
tree
decl
;
struct
jcf_partial
*
state
;
struct
jcf_partial
*
state
;
...
@@ -403,6 +477,7 @@ localvar_free (decl, state)
...
@@ -403,6 +477,7 @@ localvar_free (decl, state)
register
struct
localvar_info
**
ptr
=
&
localvar_buffer
[
index
];
register
struct
localvar_info
**
ptr
=
&
localvar_buffer
[
index
];
register
struct
localvar_info
*
info
=
*
ptr
;
register
struct
localvar_info
*
info
=
*
ptr
;
int
wide
=
TYPE_IS_WIDE
(
TREE_TYPE
(
decl
));
int
wide
=
TYPE_IS_WIDE
(
TREE_TYPE
(
decl
));
int
i
;
info
->
end_label
=
end_label
;
info
->
end_label
=
end_label
;
...
@@ -493,6 +568,7 @@ push_constant1 (index, state)
...
@@ -493,6 +568,7 @@ push_constant1 (index, state)
int
index
;
int
index
;
struct
jcf_partial
*
state
;
struct
jcf_partial
*
state
;
{
{
RESERVE
(
3
);
if
(
index
<
256
)
if
(
index
<
256
)
{
{
OP1
(
OPCODE_ldc
);
OP1
(
OPCODE_ldc
);
...
@@ -540,7 +616,7 @@ push_int_const (i, state)
...
@@ -540,7 +616,7 @@ push_int_const (i, state)
else
else
{
{
i
=
find_constant1
(
&
state
->
cpool
,
CONSTANT_Integer
,
i
&
0xFFFFFFFF
);
i
=
find_constant1
(
&
state
->
cpool
,
CONSTANT_Integer
,
i
&
0xFFFFFFFF
);
push_constant1
(
i
);
push_constant1
(
i
,
state
);
}
}
}
}
...
@@ -557,21 +633,19 @@ push_long_const (lo, hi, state)
...
@@ -557,21 +633,19 @@ push_long_const (lo, hi, state)
RESERVE
(
1
);
RESERVE
(
1
);
OP1
(
OPCODE_lconst_0
+
lo
);
OP1
(
OPCODE_lconst_0
+
lo
);
}
}
#if 0
else
if
((
hi
==
0
&&
lo
<
32768
)
||
(
hi
==
-
1
&&
lo
>=
-
32768
))
else if ((jlong) (jint) i == i)
{
{
push_int_const (
(jint) i
, state);
push_int_const
(
lo
,
state
);
RESERVE
(
1
);
RESERVE
(
1
);
OP1
(
OPCODE_i2l
);
OP1
(
OPCODE_i2l
);
}
}
#endif
else
else
{
{
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_constant
1
(
&
state
->
cpool
,
CONSTANT_Long
,
hi
=
find_constant
2
(
&
state
->
cpool
,
CONSTANT_Long
,
w1
&
0xFFFFFFFF
,
lo
&
0xFFFFFFFF
);
w1
&
0xFFFFFFFF
,
lo
&
0xFFFFFFFF
);
push_constant2
(
hi
);
push_constant2
(
hi
,
state
);
}
}
}
}
...
@@ -592,22 +666,23 @@ field_op (field, opcode, state)
...
@@ -592,22 +666,23 @@ field_op (field, opcode, state)
opcodes typically depend on the operand type. */
opcodes typically depend on the operand type. */
int
int
adjust_typed_op
(
type
)
adjust_typed_op
(
type
,
max
)
tree
type
;
tree
type
;
int
max
;
{
{
switch
(
TREE_CODE
(
type
))
switch
(
TREE_CODE
(
type
))
{
{
case
POINTER_TYPE
:
case
POINTER_TYPE
:
case
RECORD_TYPE
:
return
4
;
case
RECORD_TYPE
:
return
4
;
case
BOOLEAN_TYPE
:
case
BOOLEAN_TYPE
:
return
TYPE_PRECISION
(
type
)
==
32
?
0
:
5
;
return
TYPE_PRECISION
(
type
)
==
32
||
max
<
5
?
0
:
5
;
case
CHAR_TYPE
:
case
CHAR_TYPE
:
return
TYPE_PRECISION
(
type
)
==
32
?
0
:
6
;
return
TYPE_PRECISION
(
type
)
==
32
||
max
<
6
?
0
:
6
;
case
INTEGER_TYPE
:
case
INTEGER_TYPE
:
switch
(
TYPE_PRECISION
(
type
))
switch
(
TYPE_PRECISION
(
type
))
{
{
case
8
:
return
5
;
case
8
:
return
max
<
5
?
0
:
5
;
case
16
:
return
7
;
case
16
:
return
max
<
7
?
0
:
7
;
case
32
:
return
0
;
case
32
:
return
0
;
case
64
:
return
1
;
case
64
:
return
1
;
}
}
...
@@ -619,6 +694,8 @@ adjust_typed_op (type)
...
@@ -619,6 +694,8 @@ adjust_typed_op (type)
case
64
:
return
3
;
case
64
:
return
3
;
}
}
break
;
break
;
default
:
break
;
}
}
abort
();
abort
();
}
}
...
@@ -705,11 +782,12 @@ emit_iinc (var, value, state)
...
@@ -705,11 +782,12 @@ emit_iinc (var, value, state)
static
void
static
void
emit_load_or_store
(
var
,
opcode
,
state
)
emit_load_or_store
(
var
,
opcode
,
state
)
tree
var
;
tree
var
;
/* Variable to load from or store into. */
int
opcode
;
/* Either OPCODE_iload or OPCODE_istore. */
struct
jcf_partial
*
state
;
struct
jcf_partial
*
state
;
{
{
tree
type
=
TREE_TYPE
(
var
);
tree
type
=
TREE_TYPE
(
var
);
int
kind
=
adjust_typed_op
(
type
);
int
kind
=
adjust_typed_op
(
type
,
4
);
int
index
=
DECL_LOCAL_INDEX
(
var
);
int
index
=
DECL_LOCAL_INDEX
(
var
);
if
(
index
<=
3
)
if
(
index
<=
3
)
{
{
...
@@ -717,7 +795,7 @@ emit_load_or_store (var, opcode, state)
...
@@ -717,7 +795,7 @@ emit_load_or_store (var, opcode, state)
OP1
(
opcode
+
5
+
4
*
kind
+
index
);
/* [ilfda]{load,store}_[0123] */
OP1
(
opcode
+
5
+
4
*
kind
+
index
);
/* [ilfda]{load,store}_[0123] */
}
}
else
else
maybe_wide
(
opcode
+
kind
,
index
);
/* [ilfda]{load,store} */
maybe_wide
(
opcode
+
kind
,
index
,
state
);
/* [ilfda]{load,store} */
}
}
static
void
static
void
...
@@ -739,6 +817,17 @@ emit_store (var, state)
...
@@ -739,6 +817,17 @@ emit_store (var, state)
}
}
static
void
static
void
emit_unop
(
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
);
}
static
void
emit_binop
(
opcode
,
type
,
state
)
emit_binop
(
opcode
,
type
,
state
)
enum
java_opcode
opcode
;
enum
java_opcode
opcode
;
tree
type
;
tree
type
;
...
@@ -750,13 +839,11 @@ emit_binop (opcode, type, state)
...
@@ -750,13 +839,11 @@ emit_binop (opcode, type, state)
NOTE_POP
(
size
);
NOTE_POP
(
size
);
}
}
/* Emit a conditional jump to TARGET with a 2-byte relative jump offset
static
struct
jcf_relocation
*
The opcode is OPCODE, the inverted opcode is INV_OPCODE. */
emit_reloc
(
value
,
kind
,
target
,
state
)
HOST_WIDE_INT
value
;
static
void
int
kind
;
emit_if
(
target
,
opcode
,
inv_opcode
,
state
)
struct
jcf_block
*
target
;
struct
jcf_block
*
target
;
int
opcode
,
inv_opcode
;
struct
jcf_partial
*
state
;
struct
jcf_partial
*
state
;
{
{
struct
jcf_relocation
*
reloc
=
(
struct
jcf_relocation
*
)
struct
jcf_relocation
*
reloc
=
(
struct
jcf_relocation
*
)
...
@@ -764,29 +851,51 @@ emit_if (target, opcode, inv_opcode, state)
...
@@ -764,29 +851,51 @@ emit_if (target, opcode, inv_opcode, state)
struct
jcf_block
*
block
=
state
->
last_block
;
struct
jcf_block
*
block
=
state
->
last_block
;
reloc
->
next
=
block
->
u
.
relocations
;
reloc
->
next
=
block
->
u
.
relocations
;
block
->
u
.
relocations
=
reloc
;
block
->
u
.
relocations
=
reloc
;
OP1
(
opcode
);
reloc
->
offset
=
BUFFER_LENGTH
(
&
state
->
bytecode
);
reloc
->
offset
=
BUFFER_LENGTH
(
&
state
->
bytecode
);
OP2
(
1
);
// 1 byte from reloc back to start of instruction.
reloc
->
kind
=
-
inv_opcode
;
reloc
->
label
=
target
;
reloc
->
label
=
target
;
reloc
->
kind
=
kind
;
if
(
kind
==
0
||
kind
==
BLOCK_START_RELOC
)
OP4
(
value
);
else
if
(
kind
!=
SWITCH_ALIGN_RELOC
)
OP2
(
value
);
}
}
static
void
static
void
emit_goto_or_jsr
(
target
,
opcode
,
opcode_w
,
state
)
emit_switch_reloc
(
label
,
state
)
struct
jcf_block
*
target
;
struct
jcf_block
*
label
;
int
opcode
,
opcode_w
;
struct
jcf_partial
*
state
;
{
emit_reloc
(
0
,
BLOCK_START_RELOC
,
label
,
state
);
}
/* Similar to emit_switch_reloc,
but re-uses an existing case reloc. */
static
void
emit_case_reloc
(
reloc
,
state
)
struct
jcf_relocation
*
reloc
;
struct
jcf_partial
*
state
;
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
;
struct
jcf_block
*
block
=
state
->
last_block
;
reloc
->
next
=
block
->
u
.
relocations
;
reloc
->
next
=
block
->
u
.
relocations
;
block
->
u
.
relocations
=
reloc
;
block
->
u
.
relocations
=
reloc
;
OP1
(
opcode
);
reloc
->
offset
=
BUFFER_LENGTH
(
&
state
->
bytecode
);
reloc
->
offset
=
BUFFER_LENGTH
(
&
state
->
bytecode
);
OP2
(
1
);
// 1 byte from reloc back to start of instruction.
reloc
->
kind
=
BLOCK_START_RELOC
;
reloc
->
kind
=
opcode_w
;
OP4
(
0
);
reloc
->
label
=
target
;
}
/* 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
;
{
OP1
(
opcode
);
// value is 1 byte from reloc back to start of instruction.
emit_reloc
(
1
,
-
inv_opcode
,
target
,
state
);
}
}
static
void
static
void
...
@@ -794,7 +903,9 @@ emit_goto (target, state)
...
@@ -794,7 +903,9 @@ emit_goto (target, state)
struct
jcf_block
*
target
;
struct
jcf_block
*
target
;
struct
jcf_partial
*
state
;
struct
jcf_partial
*
state
;
{
{
emit_goto_or_jsr
(
target
,
OPCODE_goto
,
OPCODE_goto_w
,
state
);
OP1
(
OPCODE_goto
);
// Value is 1 byte from reloc back to start of instruction.
emit_reloc
(
1
,
OPCODE_goto_w
,
target
,
state
);
}
}
static
void
static
void
...
@@ -802,7 +913,9 @@ emit_jsr (target, state)
...
@@ -802,7 +913,9 @@ emit_jsr (target, state)
struct
jcf_block
*
target
;
struct
jcf_block
*
target
;
struct
jcf_partial
*
state
;
struct
jcf_partial
*
state
;
{
{
emit_goto_or_jsr
(
target
,
OPCODE_jsr
,
OPCODE_jsr_w
,
state
);
OP1
(
OPCODE_jsr
);
// Value is 1 byte from reloc back to start of instruction.
emit_reloc
(
1
,
OPCODE_jsr_w
,
target
,
state
);
}
}
/* Generate code to evaluate EXP. If the result is true,
/* Generate code to evaluate EXP. If the result is true,
...
@@ -850,6 +963,10 @@ generate_bytecode_conditional (exp, true_label, false_label,
...
@@ -850,6 +963,10 @@ generate_bytecode_conditional (exp, true_label, false_label,
fatal
(
"internal error non-matching SP"
);
fatal
(
"internal error non-matching SP"
);
}
}
break
;
break
;
case
TRUTH_NOT_EXPR
:
generate_bytecode_conditional
(
TREE_OPERAND
(
exp
,
0
),
false_label
,
true_label
,
!
true_branch_first
,
state
);
break
;
case
TRUTH_ANDIF_EXPR
:
case
TRUTH_ANDIF_EXPR
:
{
{
struct
jcf_block
*
next_label
=
gen_jcf_label
(
state
);
struct
jcf_block
*
next_label
=
gen_jcf_label
(
state
);
...
@@ -915,6 +1032,7 @@ generate_bytecode_conditional (exp, true_label, false_label,
...
@@ -915,6 +1032,7 @@ generate_bytecode_conditional (exp, true_label, false_label,
type
=
TREE_TYPE
(
exp0
);
type
=
TREE_TYPE
(
exp0
);
switch
(
TREE_CODE
(
type
))
switch
(
TREE_CODE
(
type
))
{
{
int
opf
;
case
POINTER_TYPE
:
case
RECORD_TYPE
:
case
POINTER_TYPE
:
case
RECORD_TYPE
:
switch
(
TREE_CODE
(
exp
))
switch
(
TREE_CODE
(
exp
))
{
{
...
@@ -936,7 +1054,22 @@ generate_bytecode_conditional (exp, true_label, false_label,
...
@@ -936,7 +1054,22 @@ generate_bytecode_conditional (exp, true_label, false_label,
NOTE_POP
(
2
);
NOTE_POP
(
2
);
goto
compare_2
;
goto
compare_2
;
case
REAL_TYPE
:
case
REAL_TYPE
:
fatal
(
"float comparison not implemented"
);
generate_bytecode_insns
(
exp0
,
STACK_TARGET
,
state
);
generate_bytecode_insns
(
exp1
,
STACK_TARGET
,
state
);
if
(
op
==
OPCODE_if_icmplt
||
op
==
op
==
OPCODE_if_icmple
)
opf
=
OPCODE_fcmpg
;
else
opf
=
OPCODE_fcmpl
;
if
(
TYPE_PRECISION
(
type
)
>
32
)
{
opf
+=
2
;
NOTE_POP
(
4
);
}
else
NOTE_POP
(
2
);
RESERVE
(
1
);
OP1
(
opf
);
goto
compare_1
;
case
INTEGER_TYPE
:
case
INTEGER_TYPE
:
if
(
TYPE_PRECISION
(
type
)
>
32
)
if
(
TYPE_PRECISION
(
type
)
>
32
)
{
{
...
@@ -967,6 +1100,8 @@ generate_bytecode_conditional (exp, true_label, false_label,
...
@@ -967,6 +1100,8 @@ generate_bytecode_conditional (exp, true_label, false_label,
case
OPCODE_if_icmple
:
case
OPCODE_if_icmple
:
op
-=
2
;
op
-=
2
;
break
;
break
;
default
:
break
;
}
}
generate_bytecode_insns
(
exp1
,
STACK_TARGET
,
state
);
generate_bytecode_insns
(
exp1
,
STACK_TARGET
,
state
);
NOTE_POP
(
1
);
NOTE_POP
(
1
);
...
@@ -994,7 +1129,7 @@ generate_bytecode_conditional (exp, true_label, false_label,
...
@@ -994,7 +1129,7 @@ generate_bytecode_conditional (exp, true_label, false_label,
break
;
break
;
}
}
if
(
save_SP
!=
state
->
code_SP
)
if
(
save_SP
!=
state
->
code_SP
)
fatal
(
"in
et
rnal error - SP mismatch"
);
fatal
(
"in
te
rnal error - SP mismatch"
);
}
}
/* Generate bytecode for sub-expression EXP of METHOD.
/* Generate bytecode for sub-expression EXP of METHOD.
...
@@ -1025,13 +1160,20 @@ generate_bytecode_insns (exp, target, state)
...
@@ -1025,13 +1160,20 @@ generate_bytecode_insns (exp, target, state)
if
(
BLOCK_EXPR_BODY
(
exp
))
if
(
BLOCK_EXPR_BODY
(
exp
))
{
{
tree
local
;
tree
local
;
tree
body
=
BLOCK_EXPR_BODY
(
exp
);
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
,
state
);
localvar_alloc
(
local
,
state
);
local
=
next
;
local
=
next
;
}
}
generate_bytecode_insns
(
BLOCK_EXPR_BODY
(
exp
),
target
,
state
);
/* Avoid deep recursion for long blocks. */
while
(
TREE_CODE
(
body
)
==
COMPOUND_EXPR
)
{
generate_bytecode_insns
(
TREE_OPERAND
(
body
,
0
),
target
,
state
);
body
=
TREE_OPERAND
(
body
,
1
);
}
generate_bytecode_insns
(
body
,
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
);
...
@@ -1079,6 +1221,32 @@ generate_bytecode_insns (exp, target, state)
...
@@ -1079,6 +1221,32 @@ generate_bytecode_insns (exp, target, state)
NOTE_PUSH
(
2
);
NOTE_PUSH
(
2
);
}
}
break
;
break
;
case
REAL_CST
:
switch
(
TYPE_PRECISION
(
type
))
{
long
words
[
2
];
int
index
;
case
32
:
words
[
0
]
=
etarsingle
(
TREE_REAL_CST
(
exp
))
&
0xFFFFFFFF
;
index
=
find_constant1
(
&
state
->
cpool
,
CONSTANT_Float
,
words
[
0
]);
push_constant1
(
index
,
state
);
NOTE_PUSH
(
1
);
break
;
case
64
:
etardouble
(
TREE_REAL_CST
(
exp
),
words
);
index
=
find_constant2
(
&
state
->
cpool
,
CONSTANT_Double
,
words
[
1
-
FLOAT_WORDS_BIG_ENDIAN
]
&
0xFFFFFFFF
,
words
[
FLOAT_WORDS_BIG_ENDIAN
]
&
0xFFFFFFFF
);
push_constant2
(
index
,
state
);
NOTE_PUSH
(
2
);
break
;
default
:
abort
();
}
break
;
case
STRING_CST
:
push_constant1
(
find_string_constant
(
&
state
->
cpool
,
exp
),
state
);
break
;
case
VAR_DECL
:
case
VAR_DECL
:
if
(
TREE_STATIC
(
exp
))
if
(
TREE_STATIC
(
exp
))
{
{
...
@@ -1090,6 +1258,7 @@ generate_bytecode_insns (exp, target, state)
...
@@ -1090,6 +1258,7 @@ generate_bytecode_insns (exp, target, state)
case
PARM_DECL
:
case
PARM_DECL
:
emit_load
(
exp
,
state
);
emit_load
(
exp
,
state
);
break
;
break
;
case
NON_LVALUE_EXPR
:
case
INDIRECT_REF
:
case
INDIRECT_REF
:
generate_bytecode_insns
(
TREE_OPERAND
(
exp
,
0
),
target
,
state
);
generate_bytecode_insns
(
TREE_OPERAND
(
exp
,
0
),
target
,
state
);
break
;
break
;
...
@@ -1098,10 +1267,11 @@ generate_bytecode_insns (exp, target, state)
...
@@ -1098,10 +1267,11 @@ generate_bytecode_insns (exp, target, state)
generate_bytecode_insns
(
TREE_OPERAND
(
exp
,
1
),
target
,
state
);
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
,
7
);
RESERVE
(
1
);
RESERVE
(
1
);
OP1
(
jopcode
);
OP1
(
jopcode
);
NOTE_POP
(
2
);
if
(
!
TYPE_IS_WIDE
(
type
))
NOTE_POP
(
1
);
}
}
break
;
break
;
case
COMPONENT_REF
:
case
COMPONENT_REF
:
...
@@ -1162,12 +1332,186 @@ generate_bytecode_insns (exp, target, state)
...
@@ -1162,12 +1332,186 @@ generate_bytecode_insns (exp, target, state)
then_label
,
else_label
,
1
,
state
);
then_label
,
else_label
,
1
,
state
);
define_jcf_label
(
then_label
,
state
);
define_jcf_label
(
then_label
,
state
);
generate_bytecode_insns
(
TREE_OPERAND
(
exp
,
1
),
target
,
state
);
generate_bytecode_insns
(
TREE_OPERAND
(
exp
,
1
),
target
,
state
);
if
(
CAN_COMPLETE_NORMALLY
(
TREE_OPERAND
(
exp
,
1
))
/* Not all expressions have CAN_COMPLETE_NORMALLY set properly. */
||
TREE_CODE
(
TREE_TYPE
(
exp
))
!=
VOID_TYPE
)
emit_goto
(
end_label
,
state
);
emit_goto
(
end_label
,
state
);
define_jcf_label
(
else_label
,
state
);
define_jcf_label
(
else_label
,
state
);
generate_bytecode_insns
(
TREE_OPERAND
(
exp
,
2
),
target
,
state
);
generate_bytecode_insns
(
TREE_OPERAND
(
exp
,
2
),
target
,
state
);
define_jcf_label
(
end_label
,
state
);
define_jcf_label
(
end_label
,
state
);
}
}
break
;
break
;
case
CASE_EXPR
:
{
struct
jcf_switch_state
*
sw_state
=
state
->
sw_state
;
struct
jcf_relocation
*
reloc
=
(
struct
jcf_relocation
*
)
obstack_alloc
(
state
->
chunk_obstack
,
sizeof
(
struct
jcf_relocation
));
HOST_WIDE_INT
case_value
=
TREE_INT_CST_LOW
(
TREE_OPERAND
(
exp
,
0
));
reloc
->
kind
=
0
;
reloc
->
label
=
get_jcf_label_here
(
state
);
reloc
->
offset
=
case_value
;
reloc
->
next
=
sw_state
->
cases
;
sw_state
->
cases
=
reloc
;
if
(
sw_state
->
num_cases
==
0
)
{
sw_state
->
min_case
=
case_value
;
sw_state
->
max_case
=
case_value
;
}
else
{
if
(
case_value
<
sw_state
->
min_case
)
sw_state
->
min_case
=
case_value
;
if
(
case_value
>
sw_state
->
max_case
)
sw_state
->
max_case
=
case_value
;
}
sw_state
->
num_cases
++
;
}
break
;
case
DEFAULT_EXPR
:
state
->
sw_state
->
default_label
=
get_jcf_label_here
(
state
);
break
;
case
SWITCH_EXPR
:
{
/* The SWITCH_EXPR has three parts, generated in the following order:
1. the switch_expression (the value used to select the correct case);
2. the switch_body;
3. the switch_instruction (the tableswitch/loopupswitch instruction.).
After code generation, we will re-order then in the order 1, 3, 2.
This is to avoid an extra GOTOs. */
struct
jcf_switch_state
sw_state
;
struct
jcf_block
*
expression_last
;
/* Last block of the switch_expression. */
struct
jcf_block
*
body_last
;
/* Last block of the switch_body. */
struct
jcf_block
*
switch_instruction
;
/* First block of switch_instruction. */
struct
jcf_block
*
instruction_last
;
/* Last block of the switch_instruction. */
struct
jcf_block
*
body_block
;
int
switch_length
;
sw_state
.
prev
=
state
->
sw_state
;
state
->
sw_state
=
&
sw_state
;
sw_state
.
cases
=
NULL
;
sw_state
.
num_cases
=
0
;
sw_state
.
default_label
=
NULL
;
generate_bytecode_insns
(
TREE_OPERAND
(
exp
,
0
),
STACK_TARGET
,
state
);
expression_last
=
state
->
last_block
;
body_block
=
get_jcf_label_here
(
state
);
/* Force a new block here. */
generate_bytecode_insns
(
TREE_OPERAND
(
exp
,
1
),
IGNORE_TARGET
,
state
);
body_last
=
state
->
last_block
;
if
(
sw_state
.
default_label
==
NULL
)
sw_state
.
default_label
=
gen_jcf_label
(
state
);
switch_instruction
=
get_jcf_label_here
(
state
);
if
(
sw_state
.
num_cases
<=
1
)
{
if
(
sw_state
.
num_cases
==
0
)
{
emit_pop
(
1
,
state
);
NOTE_POP
(
1
);
}
else
{
push_int_const
(
sw_state
.
cases
->
offset
,
state
);
emit_if
(
sw_state
.
cases
->
label
,
OPCODE_ifeq
,
OPCODE_ifne
,
state
);
}
emit_goto
(
sw_state
.
default_label
,
state
);
}
else
{
HOST_WIDE_INT
i
;
/* Copy the chain of relocs into a sorted array. */
struct
jcf_relocation
**
relocs
=
(
struct
jcf_relocation
**
)
xmalloc
(
sw_state
.
num_cases
*
sizeof
(
struct
jcf_relocation
*
));
/* The relocs arrays is a buffer with a gap.
The assumption is that cases will normally come in "runs". */
int
gap_start
=
0
;
int
gap_end
=
sw_state
.
num_cases
;
struct
jcf_relocation
*
reloc
;
for
(
reloc
=
sw_state
.
cases
;
reloc
!=
NULL
;
reloc
=
reloc
->
next
)
{
HOST_WIDE_INT
case_value
=
reloc
->
offset
;
while
(
gap_end
<
sw_state
.
num_cases
)
{
struct
jcf_relocation
*
end
=
relocs
[
gap_end
];
if
(
case_value
<=
end
->
offset
)
break
;
relocs
[
gap_start
++
]
=
end
;
gap_end
++
;
}
while
(
gap_start
>
0
)
{
struct
jcf_relocation
*
before
=
relocs
[
gap_start
-
1
];
if
(
case_value
>=
before
->
offset
)
break
;
relocs
[
--
gap_end
]
=
before
;
gap_start
--
;
}
relocs
[
gap_start
++
]
=
reloc
;
/* Note we don't check for duplicates. FIXME! */
}
if
(
2
*
sw_state
.
num_cases
>=
sw_state
.
max_case
-
sw_state
.
min_case
)
{
/* Use tableswitch. */
int
index
=
0
;
RESERVE
(
13
+
4
*
(
sw_state
.
max_case
-
sw_state
.
min_case
+
1
));
OP1
(
OPCODE_tableswitch
);
emit_reloc
(
0
,
SWITCH_ALIGN_RELOC
,
NULL
,
state
);
emit_switch_reloc
(
sw_state
.
default_label
,
state
);
OP4
(
sw_state
.
min_case
);
OP4
(
sw_state
.
max_case
);
for
(
i
=
sw_state
.
min_case
;
;
)
{
if
(
i
==
sw_state
.
min_case
+
index
)
emit_case_reloc
(
relocs
[
index
++
],
state
);
else
emit_switch_reloc
(
sw_state
.
default_label
,
state
);
if
(
i
==
sw_state
.
max_case
)
break
;
i
++
;
}
}
else
{
/* Use lookupswitch. */
RESERVE
(
9
+
8
*
sw_state
.
num_cases
);
OP1
(
OPCODE_lookupswitch
);
emit_reloc
(
0
,
SWITCH_ALIGN_RELOC
,
NULL
,
state
);
emit_switch_reloc
(
sw_state
.
default_label
,
state
);
OP4
(
sw_state
.
num_cases
);
for
(
i
=
0
;
i
<
sw_state
.
num_cases
;
i
++
)
{
struct
jcf_relocation
*
reloc
=
relocs
[
i
];
OP4
(
reloc
->
offset
);
emit_case_reloc
(
reloc
,
state
);
}
}
free
(
relocs
);
}
instruction_last
=
state
->
last_block
;
if
(
sw_state
.
default_label
->
pc
<
0
)
define_jcf_label
(
sw_state
.
default_label
,
state
);
else
/* Force a new block. */
sw_state
.
default_label
=
get_jcf_label_here
(
state
);
/* Now re-arrange the blocks so the switch_instruction
comes before the switch_body. */
switch_length
=
state
->
code_length
-
switch_instruction
->
pc
;
switch_instruction
->
pc
=
body_block
->
pc
;
instruction_last
->
next
=
body_block
;
instruction_last
->
chunk
->
next
=
body_block
->
chunk
;
expression_last
->
next
=
switch_instruction
;
expression_last
->
chunk
->
next
=
switch_instruction
->
chunk
;
body_last
->
next
=
sw_state
.
default_label
;
body_last
->
chunk
->
next
=
NULL
;
state
->
chunk
=
body_last
->
chunk
;
for
(;
body_block
!=
sw_state
.
default_label
;
body_block
=
body_block
->
next
)
body_block
->
pc
+=
switch_length
;
free
(
sw_state
.
cases
);
state
->
sw_state
=
sw_state
.
prev
;
break
;
}
case
RETURN_EXPR
:
case
RETURN_EXPR
:
if
(
!
TREE_OPERAND
(
exp
,
0
))
if
(
!
TREE_OPERAND
(
exp
,
0
))
op
=
OPCODE_return
;
op
=
OPCODE_return
;
...
@@ -1177,7 +1521,7 @@ generate_bytecode_insns (exp, target, state)
...
@@ -1177,7 +1521,7 @@ generate_bytecode_insns (exp, target, state)
if
(
TREE_CODE
(
exp
)
!=
MODIFY_EXPR
)
if
(
TREE_CODE
(
exp
)
!=
MODIFY_EXPR
)
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
)
,
4
);
generate_bytecode_insns
(
exp
,
STACK_TARGET
,
state
);
generate_bytecode_insns
(
exp
,
STACK_TARGET
,
state
);
}
}
RESERVE
(
1
);
RESERVE
(
1
);
...
@@ -1288,7 +1632,7 @@ generate_bytecode_insns (exp, target, state)
...
@@ -1288,7 +1632,7 @@ generate_bytecode_insns (exp, target, state)
generate_bytecode_insns
(
TREE_OPERAND
(
exp
,
1
),
STACK_TARGET
,
state
);
generate_bytecode_insns
(
TREE_OPERAND
(
exp
,
1
),
STACK_TARGET
,
state
);
emit_dup
(
2
,
0
,
state
);
emit_dup
(
2
,
0
,
state
);
/* Stack: ..., array, index, array, index. */
/* Stack: ..., array, index, array, index. */
jopcode
=
OPCODE_iaload
+
adjust_typed_op
(
TREE_TYPE
(
exp
));
jopcode
=
OPCODE_iaload
+
adjust_typed_op
(
TREE_TYPE
(
exp
)
,
7
);
RESERVE
(
1
);
RESERVE
(
1
);
OP1
(
jopcode
);
OP1
(
jopcode
);
NOTE_POP
(
2
-
size
);
NOTE_POP
(
2
-
size
);
...
@@ -1311,7 +1655,7 @@ generate_bytecode_insns (exp, target, state)
...
@@ -1311,7 +1655,7 @@ generate_bytecode_insns (exp, target, state)
/* Stack, otherwise: ..., [result, ] oldvalue. */
/* Stack, otherwise: ..., [result, ] oldvalue. */
push_int_const
(
value
,
state
);
/* FIXME - assumes int! */
push_int_const
(
value
,
state
);
/* FIXME - assumes int! */
NOTE_PUSH
(
1
);
NOTE_PUSH
(
1
);
emit_binop
(
OPCODE_iadd
+
adjust_typed_op
(
type
),
type
,
state
);
emit_binop
(
OPCODE_iadd
+
adjust_typed_op
(
type
,
3
),
type
,
state
);
if
(
target
!=
IGNORE_TARGET
&&
!
post_op
)
if
(
target
!=
IGNORE_TARGET
&&
!
post_op
)
emit_dup
(
size
,
offset
,
state
);
emit_dup
(
size
,
offset
,
state
);
/* Stack: ..., [result,] newvalue. */
/* Stack: ..., [result,] newvalue. */
...
@@ -1399,7 +1743,7 @@ generate_bytecode_insns (exp, target, state)
...
@@ -1399,7 +1743,7 @@ generate_bytecode_insns (exp, target, state)
else
if
(
TREE_CODE
(
exp
)
==
ARRAY_REF
)
else
if
(
TREE_CODE
(
exp
)
==
ARRAY_REF
)
{
{
NOTE_POP
(
2
);
NOTE_POP
(
2
);
jopcode
=
OPCODE_iastore
+
adjust_typed_op
(
TREE_TYPE
(
exp
));
jopcode
=
OPCODE_iastore
+
adjust_typed_op
(
TREE_TYPE
(
exp
)
,
7
);
RESERVE
(
1
);
RESERVE
(
1
);
OP1
(
jopcode
);
OP1
(
jopcode
);
NOTE_PUSH
(
TYPE_IS_WIDE
(
TREE_TYPE
(
exp
))
?
2
:
1
);
NOTE_PUSH
(
TYPE_IS_WIDE
(
TREE_TYPE
(
exp
))
?
2
:
1
);
...
@@ -1408,49 +1752,289 @@ generate_bytecode_insns (exp, target, state)
...
@@ -1408,49 +1752,289 @@ generate_bytecode_insns (exp, target, state)
fatal
(
"internal error (bad lhs to MODIFY_EXPR)"
);
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
;
goto
binop
;
goto
binop
;
case
MINUS_EXPR
:
case
MINUS_EXPR
:
jopcode
=
OPCODE_isub
+
adjust_typed_op
(
type
)
;
jopcode
=
OPCODE_isub
;
goto
binop
;
goto
binop
;
case
MULT_EXPR
:
case
MULT_EXPR
:
jopcode
=
OPCODE_imul
+
adjust_typed_op
(
type
)
;
jopcode
=
OPCODE_imul
;
goto
binop
;
goto
binop
;
case
TRUNC_DIV_EXPR
:
case
TRUNC_DIV_EXPR
:
case
RDIV_EXPR
:
case
RDIV_EXPR
:
jopcode
=
OPCODE_idiv
+
adjust_typed_op
(
type
)
;
jopcode
=
OPCODE_idiv
;
goto
binop
;
goto
binop
;
case
TRUNC_MOD_EXPR
:
jopcode
=
OPCODE_irem
;
goto
binop
;
case
LSHIFT_EXPR
:
jopcode
=
OPCODE_ishl
;
goto
binop
;
case
RSHIFT_EXPR
:
jopcode
=
OPCODE_ishr
;
goto
binop
;
case
URSHIFT_EXPR
:
jopcode
=
OPCODE_iushr
;
goto
binop
;
case
BIT_AND_EXPR
:
jopcode
=
OPCODE_iand
;
goto
binop
;
case
BIT_IOR_EXPR
:
jopcode
=
OPCODE_ior
;
goto
binop
;
case
BIT_XOR_EXPR
:
jopcode
=
OPCODE_ixor
;
goto
binop
;
binop
:
binop
:
generate_bytecode_insns
(
TREE_OPERAND
(
exp
,
0
),
target
,
state
);
{
generate_bytecode_insns
(
TREE_OPERAND
(
exp
,
1
),
target
,
state
);
tree
arg0
=
TREE_OPERAND
(
exp
,
0
);
tree
arg1
=
TREE_OPERAND
(
exp
,
1
);
jopcode
+=
adjust_typed_op
(
type
,
3
);
if
(
arg0
==
arg1
&&
TREE_CODE
(
arg0
)
==
SAVE_EXPR
)
{
/* fold may (e.g) convert 2*x to x+x. */
generate_bytecode_insns
(
TREE_OPERAND
(
arg0
,
0
),
target
,
state
);
emit_dup
(
TYPE_PRECISION
(
TREE_TYPE
(
arg0
))
>
32
?
2
:
1
,
0
,
state
);
}
else
{
generate_bytecode_insns
(
arg0
,
target
,
state
);
generate_bytecode_insns
(
arg1
,
target
,
state
);
}
if
(
target
==
STACK_TARGET
)
if
(
target
==
STACK_TARGET
)
emit_binop
(
jopcode
,
type
,
state
);
emit_binop
(
jopcode
,
type
,
state
);
break
;
break
;
}
case
TRUTH_NOT_EXPR
:
case
BIT_NOT_EXPR
:
generate_bytecode_insns
(
TREE_OPERAND
(
exp
,
0
),
target
,
state
);
if
(
target
==
STACK_TARGET
)
{
int
is_long
=
TYPE_PRECISION
(
TREE_TYPE
(
exp
))
>
32
;
push_int_const
(
TREE_CODE
(
exp
)
==
BIT_NOT_EXPR
?
-
1
:
1
,
state
);
RESERVE
(
2
);
if
(
is_long
)
OP1
(
OPCODE_i2l
);
OP1
(
OPCODE_ixor
+
is_long
);
}
break
;
case
NEGATE_EXPR
:
jopcode
=
OPCODE_ineg
;
jopcode
+=
adjust_typed_op
(
type
,
3
);
generate_bytecode_insns
(
TREE_OPERAND
(
exp
,
0
),
target
,
state
);
if
(
target
==
STACK_TARGET
)
emit_unop
(
jopcode
,
type
,
state
);
break
;
case
INSTANCEOF_EXPR
:
{
int
index
=
find_class_constant
(
&
state
->
cpool
,
TREE_OPERAND
(
exp
,
1
));
generate_bytecode_insns
(
TREE_OPERAND
(
exp
,
0
),
target
,
state
);
RESERVE
(
3
);
OP1
(
OPCODE_instanceof
);
OP2
(
index
);
}
break
;
case
CONVERT_EXPR
:
case
NOP_EXPR
:
case
FLOAT_EXPR
:
case
FIX_TRUNC_EXPR
:
{
tree
src
=
TREE_OPERAND
(
exp
,
0
);
tree
src_type
=
TREE_TYPE
(
src
);
tree
dst_type
=
TREE_TYPE
(
exp
);
generate_bytecode_insns
(
TREE_OPERAND
(
exp
,
0
),
target
,
state
);
if
(
target
==
IGNORE_TARGET
||
src_type
==
dst_type
)
break
;
if
(
TREE_CODE
(
dst_type
)
==
POINTER_TYPE
)
{
if
(
TREE_CODE
(
exp
)
==
CONVERT_EXPR
)
{
int
index
=
find_class_constant
(
&
state
->
cpool
,
TREE_TYPE
(
dst_type
));
RESERVE
(
3
);
OP1
(
OPCODE_checkcast
);
OP2
(
index
);
}
}
else
/* Convert numeric types. */
{
int
wide_src
=
TYPE_PRECISION
(
src_type
)
>
32
;
int
wide_dst
=
TYPE_PRECISION
(
dst_type
)
>
32
;
NOTE_POP
(
1
+
wide_src
);
RESERVE
(
1
);
if
(
TREE_CODE
(
dst_type
)
==
REAL_TYPE
)
{
if
(
TREE_CODE
(
src_type
)
==
REAL_TYPE
)
OP1
(
wide_dst
?
OPCODE_f2d
:
OPCODE_d2f
);
else
if
(
TYPE_PRECISION
(
src_type
)
==
64
)
OP1
(
OPCODE_l2f
+
wide_dst
);
else
OP1
(
OPCODE_i2f
+
wide_dst
);
}
else
/* Convert to integral type. */
{
if
(
TREE_CODE
(
src_type
)
==
REAL_TYPE
)
OP1
(
OPCODE_f2i
+
wide_dst
+
3
*
wide_src
);
else
if
(
wide_dst
)
OP1
(
OPCODE_i2l
);
else
if
(
wide_src
)
OP1
(
OPCODE_l2i
);
if
(
TYPE_PRECISION
(
dst_type
)
<
32
)
{
RESERVE
(
1
);
/* Already converted to int, if needed. */
if
(
TYPE_PRECISION
(
dst_type
)
<=
8
)
OP1
(
OPCODE_i2b
);
else
if
(
TREE_UNSIGNED
(
dst_type
))
OP1
(
OPCODE_i2c
);
else
OP1
(
OPCODE_i2s
);
}
}
NOTE_PUSH
(
1
+
wide_dst
);
}
}
break
;
case
TRY_EXPR
:
{
tree
try_clause
=
TREE_OPERAND
(
exp
,
0
);
tree
finally
=
TREE_OPERAND
(
exp
,
2
);
struct
jcf_block
*
start_label
=
get_jcf_label_here
(
state
);
struct
jcf_block
*
end_label
;
/* End of try clause. */
struct
jcf_block
*
finally_label
;
/* Finally subroutine. */
struct
jcf_block
*
finished_label
=
gen_jcf_label
(
state
);
tree
clause
=
TREE_OPERAND
(
exp
,
1
);
if
(
finally
)
{
finally
=
FINALLY_EXPR_BLOCK
(
finally
);
finally_label
=
gen_jcf_label
(
state
);
}
if
(
target
!=
IGNORE_TARGET
)
abort
();
generate_bytecode_insns
(
try_clause
,
IGNORE_TARGET
,
state
);
end_label
=
get_jcf_label_here
(
state
);
if
(
CAN_COMPLETE_NORMALLY
(
try_clause
))
emit_goto
(
finished_label
,
state
);
for
(
;
clause
!=
NULL_TREE
;
clause
=
TREE_CHAIN
(
clause
))
{
tree
catch_clause
=
TREE_OPERAND
(
clause
,
0
);
tree
exception_decl
=
BLOCK_EXPR_DECLS
(
catch_clause
);
struct
jcf_handler
*
handler
=
alloc_handler
(
start_label
,
end_label
,
state
);
handler
->
type
=
TREE_TYPE
(
TREE_TYPE
(
exception_decl
));
generate_bytecode_insns
(
catch_clause
,
IGNORE_TARGET
,
state
);
if
(
CAN_COMPLETE_NORMALLY
(
catch_clause
))
emit_goto
(
finished_label
,
state
);
}
if
(
finally
)
{
tree
return_link
;
tree
exception_type
=
build_pointer_type
(
throwable_type_node
);
tree
exception_decl
=
build_decl
(
VAR_DECL
,
NULL_TREE
,
exception_type
);
struct
jcf_handler
*
handler
=
alloc_handler
(
start_label
,
NULL_TREE
,
state
);
handler
->
end_label
=
handler
->
handler_label
;
handler
->
type
=
NULL_TREE
;
localvar_alloc
(
exception_decl
,
state
);
NOTE_PUSH
(
1
);
emit_store
(
exception_decl
,
state
);
emit_jsr
(
finally_label
,
state
);
emit_load
(
exception_decl
,
state
);
RESERVE
(
1
);
OP1
(
OPCODE_athrow
);
NOTE_POP
(
1
);
localvar_free
(
exception_decl
,
state
);
/* The finally block. */
return_link
=
build_decl
(
VAR_DECL
,
NULL_TREE
,
return_address_type_node
);
define_jcf_label
(
finally_label
,
state
);
NOTE_PUSH
(
1
);
localvar_alloc
(
return_link
,
state
);
emit_store
(
return_link
,
state
);
generate_bytecode_insns
(
finally
,
IGNORE_TARGET
,
state
);
maybe_wide
(
OPCODE_ret
,
DECL_LOCAL_INDEX
(
return_link
),
state
);
localvar_free
(
return_link
,
state
);
}
define_jcf_label
(
finished_label
,
state
);
if
(
finally
)
emit_jsr
(
finally_label
,
state
);
}
break
;
case
THROW_EXPR
:
generate_bytecode_insns
(
TREE_OPERAND
(
exp
,
0
),
STACK_TARGET
,
state
);
RESERVE
(
1
);
OP1
(
OPCODE_athrow
);
break
;
case
NEW_CLASS_EXPR
:
{
tree
class
=
TREE_TYPE
(
TREE_TYPE
(
exp
));
int
index
=
find_class_constant
(
&
state
->
cpool
,
class
);
RESERVE
(
4
);
OP1
(
OPCODE_new
);
OP2
(
index
);
OP1
(
OPCODE_dup
);
NOTE_PUSH
(
1
);
}
/* ... fall though ... */
case
CALL_EXPR
:
case
CALL_EXPR
:
{
{
tree
t
;
tree
f
=
TREE_OPERAND
(
exp
,
0
);
tree
x
=
TREE_OPERAND
(
exp
,
1
);
int
save_SP
=
state
->
code_SP
;
int
save_SP
=
state
->
code_SP
;
for
(
t
=
TREE_OPERAND
(
exp
,
1
);
t
!=
NULL_TREE
;
t
=
TREE_CHAIN
(
t
))
if
(
TREE_CODE
(
f
)
==
ADDR_EXPR
)
f
=
TREE_OPERAND
(
f
,
0
);
if
(
f
==
soft_newarray_node
)
{
int
type_code
=
TREE_INT_CST_LOW
(
TREE_VALUE
(
x
));
generate_bytecode_insns
(
TREE_VALUE
(
TREE_CHAIN
(
x
)),
STACK_TARGET
,
state
);
RESERVE
(
2
);
OP1
(
OPCODE_newarray
);
OP1
(
type_code
);
break
;
}
else
if
(
f
==
soft_multianewarray_node
)
{
int
ndims
;
int
idim
;
int
index
=
find_class_constant
(
&
state
->
cpool
,
TREE_TYPE
(
TREE_TYPE
(
exp
)));
x
=
TREE_CHAIN
(
x
);
/* Skip class argument. */
ndims
=
TREE_INT_CST_LOW
(
TREE_VALUE
(
x
));
for
(
idim
=
ndims
;
--
idim
>=
0
;
)
{
x
=
TREE_CHAIN
(
x
);
generate_bytecode_insns
(
TREE_VALUE
(
x
),
STACK_TARGET
,
state
);
}
RESERVE
(
4
);
OP1
(
OPCODE_multianewarray
);
OP2
(
index
);
OP1
(
ndims
);
break
;
}
else
if
(
f
==
soft_anewarray_node
)
{
{
generate_bytecode_insns
(
TREE_VALUE
(
t
),
STACK_TARGET
,
state
);
tree
cl
=
TYPE_ARRAY_ELEMENT
(
TREE_TYPE
(
TREE_TYPE
(
exp
)));
int
index
=
find_class_constant
(
&
state
->
cpool
,
TREE_TYPE
(
cl
));
generate_bytecode_insns
(
TREE_VALUE
(
x
),
STACK_TARGET
,
state
);
RESERVE
(
3
);
OP1
(
OPCODE_anewarray
);
OP2
(
index
);
break
;
}
else
if
(
exp
==
soft_exceptioninfo_call_node
)
{
NOTE_PUSH
(
1
);
/* Pushed by exception system. */
break
;
}
for
(
;
x
!=
NULL_TREE
;
x
=
TREE_CHAIN
(
x
))
{
generate_bytecode_insns
(
TREE_VALUE
(
x
),
STACK_TARGET
,
state
);
}
}
t
=
TREE_OPERAND
(
exp
,
0
);
state
->
code_SP
=
save_SP
;
state
->
code_SP
=
save_SP
;
if
(
TREE_CODE
(
t
)
==
FUNCTION_DECL
)
if
(
TREE_CODE
(
f
)
==
FUNCTION_DECL
&&
DECL_CONTEXT
(
f
)
!=
NULL_TREE
)
{
{
int
index
=
find_methodref_index
(
&
state
->
cpool
,
t
);
int
index
=
find_methodref_index
(
&
state
->
cpool
,
f
);
RESERVE
(
3
);
RESERVE
(
3
);
if
(
DECL_CONSTRUCTOR_P
(
t
))
if
(
DECL_CONSTRUCTOR_P
(
f
))
OP1
(
OPCODE_invokespecial
);
OP1
(
OPCODE_invokespecial
);
else
if
(
METHOD_STATIC
(
t
))
else
if
(
METHOD_STATIC
(
f
))
OP1
(
OPCODE_invokestatic
);
OP1
(
OPCODE_invokestatic
);
else
else
OP1
(
OPCODE_invokevirtual
);
OP1
(
OPCODE_invokevirtual
);
OP2
(
index
);
OP2
(
index
);
t
=
TREE_TYPE
(
TREE_TYPE
(
t
));
f
=
TREE_TYPE
(
TREE_TYPE
(
f
));
if
(
TREE_CODE
(
t
)
!=
VOID_TYPE
)
if
(
TREE_CODE
(
f
)
!=
VOID_TYPE
)
{
{
int
size
=
TYPE_IS_WIDE
(
t
)
?
2
:
1
;
int
size
=
TYPE_IS_WIDE
(
f
)
?
2
:
1
;
if
(
target
==
IGNORE_TARGET
)
if
(
target
==
IGNORE_TARGET
)
emit_pop
(
size
,
state
);
emit_pop
(
size
,
state
);
else
else
...
@@ -1476,7 +2060,13 @@ perform_relocations (state)
...
@@ -1476,7 +2060,13 @@ perform_relocations (state)
int
pc
;
int
pc
;
int
shrink
;
int
shrink
;
/* Figure out the actual locations of each block. */
/* Before we start, the pc field of each block is an upper bound on
the block's start pc (it may be less, if previous blocks need less
than their maximum).
The minimum size of each block is in the block's chunk->size. */
/* First, figure out the actual locations of each block. */
pc
=
0
;
pc
=
0
;
shrink
=
0
;
shrink
=
0
;
for
(
block
=
state
->
blocks
;
block
!=
NULL
;
block
=
block
->
next
)
for
(
block
=
state
->
blocks
;
block
!=
NULL
;
block
=
block
->
next
)
...
@@ -1489,9 +2079,9 @@ perform_relocations (state)
...
@@ -1489,9 +2079,9 @@ perform_relocations (state)
Assumes relocations are in reverse order. */
Assumes relocations are in reverse order. */
reloc
=
block
->
u
.
relocations
;
reloc
=
block
->
u
.
relocations
;
while
(
reloc
!=
NULL
while
(
reloc
!=
NULL
&&
reloc
->
kind
==
OPCODE_goto_w
&&
reloc
->
label
->
pc
==
block
->
next
->
pc
&&
reloc
->
label
->
pc
==
block
->
next
->
pc
&&
reloc
->
offset
+
2
==
block_size
&&
reloc
->
offset
+
2
==
block_size
)
&&
reloc
->
kind
==
OPCODE_goto_w
)
{
{
reloc
=
reloc
->
next
;
reloc
=
reloc
->
next
;
block
->
u
.
relocations
=
reloc
;
block
->
u
.
relocations
=
reloc
;
...
@@ -1502,7 +2092,15 @@ perform_relocations (state)
...
@@ -1502,7 +2092,15 @@ perform_relocations (state)
for
(
reloc
=
block
->
u
.
relocations
;
reloc
!=
NULL
;
reloc
=
reloc
->
next
)
for
(
reloc
=
block
->
u
.
relocations
;
reloc
!=
NULL
;
reloc
=
reloc
->
next
)
{
{
if
(
reloc
->
kind
<
-
1
||
reloc
->
kind
>
0
)
if
(
reloc
->
kind
==
SWITCH_ALIGN_RELOC
)
{
/* We assume this is the first relocation in this block,
so we know its final pc. */
int
where
=
pc
+
reloc
->
offset
;
int
pad
=
((
where
+
3
)
&
~
3
)
-
where
;
block_size
+=
pad
;
}
else
if
(
reloc
->
kind
<
-
1
||
reloc
->
kind
>
BLOCK_START_RELOC
)
{
{
int
delta
=
reloc
->
label
->
pc
-
(
pc
+
reloc
->
offset
-
1
);
int
delta
=
reloc
->
label
->
pc
-
(
pc
+
reloc
->
offset
-
1
);
int
expand
=
reloc
->
kind
>
0
?
2
:
5
;
int
expand
=
reloc
->
kind
>
0
?
2
:
5
;
...
@@ -1536,16 +2134,26 @@ perform_relocations (state)
...
@@ -1536,16 +2134,26 @@ perform_relocations (state)
{
{
chunk
->
data
=
(
unsigned
char
*
)
chunk
->
data
=
(
unsigned
char
*
)
obstack_alloc
(
state
->
chunk_obstack
,
new_size
);
obstack_alloc
(
state
->
chunk_obstack
,
new_size
);
chunk
->
size
=
new_size
;
}
}
new_ptr
=
chunk
->
data
+
new_size
;
new_ptr
=
chunk
->
data
+
new_size
;
/* We do the relocations from back to front, because
/* We do the relocations from back to front, because
th
r
e relocations are in reverse order. */
the relocations are in reverse order. */
for
(
reloc
=
block
->
u
.
relocations
;
;
reloc
=
reloc
->
next
)
for
(
reloc
=
block
->
u
.
relocations
;
;
reloc
=
reloc
->
next
)
{
{
/* Lower old index of piece to be copied with no relocation. */
/* new_ptr and old_ptr point into the old and new buffers,
respectively. (If no relocations cause the buffer to
grow, the buffer will be the same buffer, and new_ptr==old_ptr.)
The bytes at higher adress have been copied and relocations
handled; those at lower addresses remain to process. */
/* Lower old index of piece to be copied with no relocation.
I.e. high index of the first piece that does need relocation. */
int
start
=
reloc
==
NULL
?
0
int
start
=
reloc
==
NULL
?
0
:
reloc
->
kind
==
0
?
reloc
->
offset
+
4
:
reloc
->
kind
==
SWITCH_ALIGN_RELOC
?
reloc
->
offset
:
(
reloc
->
kind
==
0
||
reloc
->
kind
==
BLOCK_START_RELOC
)
?
reloc
->
offset
+
4
:
reloc
->
offset
+
2
;
:
reloc
->
offset
+
2
;
int32
value
;
int32
value
;
int
new_offset
;
int
new_offset
;
...
@@ -1553,21 +2161,36 @@ perform_relocations (state)
...
@@ -1553,21 +2161,36 @@ perform_relocations (state)
new_ptr
-=
n
;
new_ptr
-=
n
;
old_ptr
-=
n
;
old_ptr
-=
n
;
if
(
n
>
0
)
if
(
n
>
0
)
bcopy
(
old_ptr
,
new
_ptr
,
n
);
memcpy
(
new_ptr
,
old
_ptr
,
n
);
if
(
old_ptr
==
old_buffer
)
if
(
old_ptr
==
old_buffer
)
break
;
break
;
new_offset
=
new_ptr
-
chunk
->
data
;
new_offset
-=
(
reloc
->
kind
==
-
1
?
2
:
4
);
if
(
reloc
->
kind
==
0
)
if
(
reloc
->
kind
==
0
)
{
{
old_ptr
-=
4
;
old_ptr
-=
4
;
value
=
GET_u4
(
old_ptr
);
value
=
GET_u4
(
old_ptr
);
}
}
else
if
(
reloc
->
kind
==
BLOCK_START_RELOC
)
{
old_ptr
-=
4
;
value
=
0
;
new_offset
=
0
;
}
else
if
(
reloc
->
kind
==
SWITCH_ALIGN_RELOC
)
{
int
where
=
block
->
pc
+
reloc
->
offset
;
int
pad
=
((
where
+
3
)
&
~
3
)
-
where
;
while
(
--
pad
>=
0
)
*--
new_ptr
=
0
;
continue
;
}
else
else
{
{
old_ptr
-=
2
;
old_ptr
-=
2
;
value
=
GET_u2
(
old_ptr
);
value
=
GET_u2
(
old_ptr
);
}
}
new_offset
=
new_ptr
-
chunk
->
data
-
(
reloc
->
kind
==
-
1
?
2
:
4
);
value
+=
reloc
->
label
->
pc
-
(
block
->
pc
+
new_offset
);
value
+=
reloc
->
label
->
pc
-
(
block
->
pc
+
new_offset
);
*--
new_ptr
=
(
unsigned
char
)
value
;
value
>>=
8
;
*--
new_ptr
=
(
unsigned
char
)
value
;
value
>>=
8
;
*--
new_ptr
=
(
unsigned
char
)
value
;
value
>>=
8
;
*--
new_ptr
=
(
unsigned
char
)
value
;
value
>>=
8
;
...
@@ -1576,7 +2199,7 @@ perform_relocations (state)
...
@@ -1576,7 +2199,7 @@ perform_relocations (state)
*--
new_ptr
=
(
unsigned
char
)
value
;
value
>>=
8
;
*--
new_ptr
=
(
unsigned
char
)
value
;
value
>>=
8
;
*--
new_ptr
=
(
unsigned
char
)
value
;
*--
new_ptr
=
(
unsigned
char
)
value
;
}
}
if
(
reloc
->
kind
>
0
)
if
(
reloc
->
kind
>
BLOCK_START_RELOC
)
{
{
/* Convert: OP TARGET to: OP_w TARGET; (OP is goto or jsr). */
/* Convert: OP TARGET to: OP_w TARGET; (OP is goto or jsr). */
--
old_ptr
;
--
old_ptr
;
...
@@ -1624,6 +2247,9 @@ init_jcf_method (state, method)
...
@@ -1624,6 +2247,9 @@ init_jcf_method (state, method)
BUFFER_RESET
(
&
state
->
localvars
);
BUFFER_RESET
(
&
state
->
localvars
);
state
->
code_SP
=
0
;
state
->
code_SP
=
0
;
state
->
code_SP_max
=
0
;
state
->
code_SP_max
=
0
;
state
->
handlers
=
NULL
;
state
->
last_handler
=
NULL
;
state
->
num_handlers
=
0
;
}
}
void
void
...
@@ -1731,6 +2357,7 @@ generate_classfile (clas, state)
...
@@ -1731,6 +2357,7 @@ generate_classfile (clas, state)
static
tree
Code_node
=
NULL_TREE
;
static
tree
Code_node
=
NULL_TREE
;
tree
t
;
tree
t
;
char
*
attr_len_ptr
;
char
*
attr_len_ptr
;
struct
jcf_handler
*
handler
;
if
(
Code_node
==
NULL_TREE
)
if
(
Code_node
==
NULL_TREE
)
Code_node
=
get_identifier
(
"Code"
);
Code_node
=
get_identifier
(
"Code"
);
ptr
=
append_chunk
(
NULL
,
14
,
state
);
ptr
=
append_chunk
(
NULL
,
14
,
state
);
...
@@ -1741,13 +2368,20 @@ generate_classfile (clas, state)
...
@@ -1741,13 +2368,20 @@ generate_classfile (clas, state)
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
,
state
);
localvar_alloc
(
t
,
state
);
generate_bytecode_insns
(
body
,
IGNORE_TARGET
,
state
);
generate_bytecode_insns
(
body
,
IGNORE_TARGET
,
state
);
if
(
CAN_COMPLETE_NORMALLY
(
body
))
{
if
(
TREE_CODE
(
TREE_TYPE
(
type
))
!=
VOID_TYPE
)
abort
();
RESERVE
(
1
);
OP1
(
OPCODE_return
);
}
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
,
state
);
localvar_free
(
t
,
state
);
finish_jcf_block
(
state
);
finish_jcf_block
(
state
);
perform_relocations
(
state
);
perform_relocations
(
state
);
ptr
=
attr_len_ptr
;
ptr
=
attr_len_ptr
;
i
=
8
+
state
->
code_length
+
4
;
i
=
8
+
state
->
code_length
+
4
+
8
*
state
->
num_handlers
;
if
(
state
->
linenumber_count
>
0
)
if
(
state
->
linenumber_count
>
0
)
{
{
code_attributes_count
++
;
code_attributes_count
++
;
...
@@ -1762,8 +2396,26 @@ generate_classfile (clas, state)
...
@@ -1762,8 +2396,26 @@ generate_classfile (clas, state)
PUT2
(
state
->
code_SP_max
);
/* max_stack */
PUT2
(
state
->
code_SP_max
);
/* max_stack */
PUT2
(
localvar_max
);
/* max_locals */
PUT2
(
localvar_max
);
/* max_locals */
PUT4
(
state
->
code_length
);
PUT4
(
state
->
code_length
);
ptr
=
append_chunk
(
NULL
,
4
,
state
);
PUT2
(
0
);
/* exception_table_length */
/* Emit the exception table. */
ptr
=
append_chunk
(
NULL
,
2
+
8
*
state
->
num_handlers
,
state
);
PUT2
(
state
->
num_handlers
);
/* exception_table_length */
handler
=
state
->
handlers
;
for
(;
handler
!=
NULL
;
handler
=
handler
->
next
)
{
int
type_index
;
PUT2
(
handler
->
start_label
->
pc
);
PUT2
(
handler
->
end_label
->
pc
);
PUT2
(
handler
->
handler_label
->
pc
);
if
(
handler
->
type
==
NULL_TREE
)
type_index
=
0
;
else
type_index
=
find_class_constant
(
&
state
->
cpool
,
handler
->
type
);
PUT2
(
type_index
);
}
ptr
=
append_chunk
(
NULL
,
2
,
state
);
PUT2
(
code_attributes_count
);
PUT2
(
code_attributes_count
);
/* Write the LineNumberTable attribute. */
/* Write the LineNumberTable attribute. */
...
@@ -1877,3 +2529,8 @@ write_classfile (clas)
...
@@ -1877,3 +2529,8 @@ write_classfile (clas)
fatal
(
"failed to close after writing `%s'"
,
class_file_name
);
fatal
(
"failed to close after writing `%s'"
,
class_file_name
);
release_jcf_state
(
state
);
release_jcf_state
(
state
);
}
}
/* TODO:
string concatenation
synchronized statement
*/
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