mirror of
https://github.com/openjdk/jdk.git
synced 2026-06-01 16:22:31 +00:00
Merge
This commit is contained in:
commit
c7a54bbb06
@ -3331,7 +3331,6 @@ const bool Matcher::match_rule_supported(int opcode) {
|
||||
|
||||
switch (opcode) {
|
||||
case Op_StrComp:
|
||||
case Op_StrIndexOf:
|
||||
if (CompactStrings) return false;
|
||||
break;
|
||||
default:
|
||||
@ -4744,7 +4743,8 @@ encode %{
|
||||
__ br(Assembler::EQ, cont);
|
||||
} else {
|
||||
Label retry_load;
|
||||
__ prfm(Address(oop), PSTL1STRM);
|
||||
if ((VM_Version::features() & VM_Version::CPU_STXR_PREFETCH))
|
||||
__ prfm(Address(oop), PSTL1STRM);
|
||||
__ bind(retry_load);
|
||||
__ ldaxr(tmp, oop);
|
||||
__ cmp(tmp, disp_hdr);
|
||||
@ -4799,7 +4799,8 @@ encode %{
|
||||
__ cmp(rscratch1, disp_hdr);
|
||||
} else {
|
||||
Label retry_load, fail;
|
||||
__ prfm(Address(tmp), PSTL1STRM);
|
||||
if ((VM_Version::features() & VM_Version::CPU_STXR_PREFETCH))
|
||||
__ prfm(Address(tmp), PSTL1STRM);
|
||||
__ bind(retry_load);
|
||||
__ ldaxr(rscratch1, tmp);
|
||||
__ cmp(disp_hdr, rscratch1);
|
||||
@ -4893,7 +4894,8 @@ encode %{
|
||||
__ cmp(tmp, box);
|
||||
} else {
|
||||
Label retry_load;
|
||||
__ prfm(Address(oop), PSTL1STRM);
|
||||
if ((VM_Version::features() & VM_Version::CPU_STXR_PREFETCH))
|
||||
__ prfm(Address(oop), PSTL1STRM);
|
||||
__ bind(retry_load);
|
||||
__ ldxr(tmp, oop);
|
||||
__ cmp(box, tmp);
|
||||
@ -14953,26 +14955,83 @@ instruct string_compareU(iRegP_R1 str1, iRegI_R2 cnt1, iRegP_R3 str2, iRegI_R4 c
|
||||
ins_pipe(pipe_class_memory);
|
||||
%}
|
||||
|
||||
instruct string_indexof(iRegP_R1 str1, iRegI_R4 cnt1, iRegP_R3 str2, iRegI_R2 cnt2,
|
||||
instruct string_indexofUU(iRegP_R1 str1, iRegI_R4 cnt1, iRegP_R3 str2, iRegI_R2 cnt2,
|
||||
iRegI_R0 result, iRegI tmp1, iRegI tmp2, iRegI tmp3, iRegI tmp4, rFlagsReg cr)
|
||||
%{
|
||||
predicate(((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::UU);
|
||||
match(Set result (StrIndexOf (Binary str1 cnt1) (Binary str2 cnt2)));
|
||||
effect(USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2,
|
||||
TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, KILL cr);
|
||||
format %{ "String IndexOf $str1,$cnt1,$str2,$cnt2 -> $result" %}
|
||||
format %{ "String IndexOf $str1,$cnt1,$str2,$cnt2 -> $result (UU)" %}
|
||||
|
||||
ins_encode %{
|
||||
__ string_indexof($str1$$Register, $str2$$Register,
|
||||
$cnt1$$Register, $cnt2$$Register,
|
||||
$tmp1$$Register, $tmp2$$Register,
|
||||
$tmp3$$Register, $tmp4$$Register,
|
||||
-1, $result$$Register);
|
||||
-1, $result$$Register, StrIntrinsicNode::UU);
|
||||
%}
|
||||
ins_pipe(pipe_class_memory);
|
||||
%}
|
||||
|
||||
instruct string_indexof_con(iRegP_R1 str1, iRegI_R4 cnt1, iRegP_R3 str2,
|
||||
instruct string_indexofLL(iRegP_R1 str1, iRegI_R4 cnt1, iRegP_R3 str2, iRegI_R2 cnt2,
|
||||
iRegI_R0 result, iRegI tmp1, iRegI tmp2, iRegI tmp3, iRegI tmp4, rFlagsReg cr)
|
||||
%{
|
||||
predicate(((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::LL);
|
||||
match(Set result (StrIndexOf (Binary str1 cnt1) (Binary str2 cnt2)));
|
||||
effect(USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2,
|
||||
TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, KILL cr);
|
||||
format %{ "String IndexOf $str1,$cnt1,$str2,$cnt2 -> $result (LL)" %}
|
||||
|
||||
ins_encode %{
|
||||
__ string_indexof($str1$$Register, $str2$$Register,
|
||||
$cnt1$$Register, $cnt2$$Register,
|
||||
$tmp1$$Register, $tmp2$$Register,
|
||||
$tmp3$$Register, $tmp4$$Register,
|
||||
-1, $result$$Register, StrIntrinsicNode::LL);
|
||||
%}
|
||||
ins_pipe(pipe_class_memory);
|
||||
%}
|
||||
|
||||
instruct string_indexofUL(iRegP_R1 str1, iRegI_R4 cnt1, iRegP_R3 str2, iRegI_R2 cnt2,
|
||||
iRegI_R0 result, iRegI tmp1, iRegI tmp2, iRegI tmp3, iRegI tmp4, rFlagsReg cr)
|
||||
%{
|
||||
predicate(((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::UL);
|
||||
match(Set result (StrIndexOf (Binary str1 cnt1) (Binary str2 cnt2)));
|
||||
effect(USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2,
|
||||
TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, KILL cr);
|
||||
format %{ "String IndexOf $str1,$cnt1,$str2,$cnt2 -> $result (UL)" %}
|
||||
|
||||
ins_encode %{
|
||||
__ string_indexof($str1$$Register, $str2$$Register,
|
||||
$cnt1$$Register, $cnt2$$Register,
|
||||
$tmp1$$Register, $tmp2$$Register,
|
||||
$tmp3$$Register, $tmp4$$Register,
|
||||
-1, $result$$Register, StrIntrinsicNode::UL);
|
||||
%}
|
||||
ins_pipe(pipe_class_memory);
|
||||
%}
|
||||
|
||||
instruct string_indexofLU(iRegP_R1 str1, iRegI_R4 cnt1, iRegP_R3 str2, iRegI_R2 cnt2,
|
||||
iRegI_R0 result, iRegI tmp1, iRegI tmp2, iRegI tmp3, iRegI tmp4, rFlagsReg cr)
|
||||
%{
|
||||
predicate(((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::LU);
|
||||
match(Set result (StrIndexOf (Binary str1 cnt1) (Binary str2 cnt2)));
|
||||
effect(USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2,
|
||||
TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, KILL cr);
|
||||
format %{ "String IndexOf $str1,$cnt1,$str2,$cnt2 -> $result (LU)" %}
|
||||
|
||||
ins_encode %{
|
||||
__ string_indexof($str1$$Register, $str2$$Register,
|
||||
$cnt1$$Register, $cnt2$$Register,
|
||||
$tmp1$$Register, $tmp2$$Register,
|
||||
$tmp3$$Register, $tmp4$$Register,
|
||||
-1, $result$$Register, StrIntrinsicNode::LU);
|
||||
%}
|
||||
ins_pipe(pipe_class_memory);
|
||||
%}
|
||||
|
||||
instruct string_indexof_conUU(iRegP_R1 str1, iRegI_R4 cnt1, iRegP_R3 str2,
|
||||
immI_le_4 int_cnt2, iRegI_R0 result, iRegI tmp1, iRegI tmp2,
|
||||
iRegI tmp3, iRegI tmp4, rFlagsReg cr)
|
||||
%{
|
||||
@ -14980,7 +15039,7 @@ instruct string_indexof_con(iRegP_R1 str1, iRegI_R4 cnt1, iRegP_R3 str2,
|
||||
match(Set result (StrIndexOf (Binary str1 cnt1) (Binary str2 int_cnt2)));
|
||||
effect(USE_KILL str1, USE_KILL str2, USE_KILL cnt1,
|
||||
TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, KILL cr);
|
||||
format %{ "String IndexOf $str1,$cnt1,$str2,$int_cnt2 -> $result" %}
|
||||
format %{ "String IndexOf $str1,$cnt1,$str2,$int_cnt2 -> $result (UU)" %}
|
||||
|
||||
ins_encode %{
|
||||
int icnt2 = (int)$int_cnt2$$constant;
|
||||
@ -14988,7 +15047,70 @@ instruct string_indexof_con(iRegP_R1 str1, iRegI_R4 cnt1, iRegP_R3 str2,
|
||||
$cnt1$$Register, zr,
|
||||
$tmp1$$Register, $tmp2$$Register,
|
||||
$tmp3$$Register, $tmp4$$Register,
|
||||
icnt2, $result$$Register);
|
||||
icnt2, $result$$Register, StrIntrinsicNode::UU);
|
||||
%}
|
||||
ins_pipe(pipe_class_memory);
|
||||
%}
|
||||
|
||||
instruct string_indexof_conLL(iRegP_R1 str1, iRegI_R4 cnt1, iRegP_R3 str2,
|
||||
immI_le_4 int_cnt2, iRegI_R0 result, iRegI tmp1, iRegI tmp2,
|
||||
iRegI tmp3, iRegI tmp4, rFlagsReg cr)
|
||||
%{
|
||||
predicate(((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::LL);
|
||||
match(Set result (StrIndexOf (Binary str1 cnt1) (Binary str2 int_cnt2)));
|
||||
effect(USE_KILL str1, USE_KILL str2, USE_KILL cnt1,
|
||||
TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, KILL cr);
|
||||
format %{ "String IndexOf $str1,$cnt1,$str2,$int_cnt2 -> $result (LL)" %}
|
||||
|
||||
ins_encode %{
|
||||
int icnt2 = (int)$int_cnt2$$constant;
|
||||
__ string_indexof($str1$$Register, $str2$$Register,
|
||||
$cnt1$$Register, zr,
|
||||
$tmp1$$Register, $tmp2$$Register,
|
||||
$tmp3$$Register, $tmp4$$Register,
|
||||
icnt2, $result$$Register, StrIntrinsicNode::LL);
|
||||
%}
|
||||
ins_pipe(pipe_class_memory);
|
||||
%}
|
||||
|
||||
instruct string_indexof_conUL(iRegP_R1 str1, iRegI_R4 cnt1, iRegP_R3 str2,
|
||||
immI_1 int_cnt2, iRegI_R0 result, iRegI tmp1, iRegI tmp2,
|
||||
iRegI tmp3, iRegI tmp4, rFlagsReg cr)
|
||||
%{
|
||||
predicate(((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::UL);
|
||||
match(Set result (StrIndexOf (Binary str1 cnt1) (Binary str2 int_cnt2)));
|
||||
effect(USE_KILL str1, USE_KILL str2, USE_KILL cnt1,
|
||||
TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, KILL cr);
|
||||
format %{ "String IndexOf $str1,$cnt1,$str2,$int_cnt2 -> $result (UL)" %}
|
||||
|
||||
ins_encode %{
|
||||
int icnt2 = (int)$int_cnt2$$constant;
|
||||
__ string_indexof($str1$$Register, $str2$$Register,
|
||||
$cnt1$$Register, zr,
|
||||
$tmp1$$Register, $tmp2$$Register,
|
||||
$tmp3$$Register, $tmp4$$Register,
|
||||
icnt2, $result$$Register, StrIntrinsicNode::UL);
|
||||
%}
|
||||
ins_pipe(pipe_class_memory);
|
||||
%}
|
||||
|
||||
instruct string_indexof_conLU(iRegP_R1 str1, iRegI_R4 cnt1, iRegP_R3 str2,
|
||||
immI_1 int_cnt2, iRegI_R0 result, iRegI tmp1, iRegI tmp2,
|
||||
iRegI tmp3, iRegI tmp4, rFlagsReg cr)
|
||||
%{
|
||||
predicate(((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::LU);
|
||||
match(Set result (StrIndexOf (Binary str1 cnt1) (Binary str2 int_cnt2)));
|
||||
effect(USE_KILL str1, USE_KILL str2, USE_KILL cnt1,
|
||||
TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, KILL cr);
|
||||
format %{ "String IndexOf $str1,$cnt1,$str2,$int_cnt2 -> $result (LU)" %}
|
||||
|
||||
ins_encode %{
|
||||
int icnt2 = (int)$int_cnt2$$constant;
|
||||
__ string_indexof($str1$$Register, $str2$$Register,
|
||||
$cnt1$$Register, zr,
|
||||
$tmp1$$Register, $tmp2$$Register,
|
||||
$tmp3$$Register, $tmp4$$Register,
|
||||
icnt2, $result$$Register, StrIntrinsicNode::LU);
|
||||
%}
|
||||
ins_pipe(pipe_class_memory);
|
||||
%}
|
||||
|
||||
@ -23,8 +23,8 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CPU_X86_VM_C1_LIRASSEMBLER_X86_HPP
|
||||
#define CPU_X86_VM_C1_LIRASSEMBLER_X86_HPP
|
||||
#ifndef CPU_AARCH64_VM_C1_LIRASSEMBLER_AARCH64_HPP
|
||||
#define CPU_AARCH64_VM_C1_LIRASSEMBLER_AARCH64_HPP
|
||||
|
||||
// ArrayCopyStub needs access to bailout
|
||||
friend class ArrayCopyStub;
|
||||
@ -78,4 +78,4 @@ enum { call_stub_size = 12 * NativeInstruction::instruction_size,
|
||||
exception_handler_size = DEBUG_ONLY(1*K) NOT_DEBUG(175),
|
||||
deopt_handler_size = 7 * NativeInstruction::instruction_size };
|
||||
|
||||
#endif // CPU_X86_VM_C1_LIRASSEMBLER_X86_HPP
|
||||
#endif // CPU_AARCH64_VM_C1_LIRASSEMBLER_AARCH64_HPP
|
||||
|
||||
@ -1643,7 +1643,8 @@ void MacroAssembler::atomic_incw(Register counter_addr, Register tmp, Register t
|
||||
return;
|
||||
}
|
||||
Label retry_load;
|
||||
prfm(Address(counter_addr), PSTL1STRM);
|
||||
if ((VM_Version::features() & VM_Version::CPU_STXR_PREFETCH))
|
||||
prfm(Address(counter_addr), PSTL1STRM);
|
||||
bind(retry_load);
|
||||
// flush and load exclusive from the memory location
|
||||
ldxrw(tmp, counter_addr);
|
||||
@ -2084,7 +2085,8 @@ void MacroAssembler::cmpxchgptr(Register oldv, Register newv, Register addr, Reg
|
||||
membar(AnyAny);
|
||||
} else {
|
||||
Label retry_load, nope;
|
||||
prfm(Address(addr), PSTL1STRM);
|
||||
if ((VM_Version::features() & VM_Version::CPU_STXR_PREFETCH))
|
||||
prfm(Address(addr), PSTL1STRM);
|
||||
bind(retry_load);
|
||||
// flush and load exclusive from the memory location
|
||||
// and fail if it is not what we expect
|
||||
@ -2120,7 +2122,8 @@ void MacroAssembler::cmpxchgw(Register oldv, Register newv, Register addr, Regis
|
||||
membar(AnyAny);
|
||||
} else {
|
||||
Label retry_load, nope;
|
||||
prfm(Address(addr), PSTL1STRM);
|
||||
if ((VM_Version::features() & VM_Version::CPU_STXR_PREFETCH))
|
||||
prfm(Address(addr), PSTL1STRM);
|
||||
bind(retry_load);
|
||||
// flush and load exclusive from the memory location
|
||||
// and fail if it is not what we expect
|
||||
@ -2155,7 +2158,8 @@ void MacroAssembler::cmpxchg(Register addr, Register expected,
|
||||
} else {
|
||||
BLOCK_COMMENT("cmpxchg {");
|
||||
Label retry_load, done;
|
||||
prfm(Address(addr), PSTL1STRM);
|
||||
if ((VM_Version::features() & VM_Version::CPU_STXR_PREFETCH))
|
||||
prfm(Address(addr), PSTL1STRM);
|
||||
bind(retry_load);
|
||||
load_exclusive(tmp, addr, size, acquire);
|
||||
if (size == xword)
|
||||
@ -2194,7 +2198,8 @@ void MacroAssembler::atomic_##NAME(Register prev, RegisterOrConstant incr, Regis
|
||||
result = different(prev, incr, addr) ? prev : rscratch2; \
|
||||
\
|
||||
Label retry_load; \
|
||||
prfm(Address(addr), PSTL1STRM); \
|
||||
if ((VM_Version::features() & VM_Version::CPU_STXR_PREFETCH)) \
|
||||
prfm(Address(addr), PSTL1STRM); \
|
||||
bind(retry_load); \
|
||||
LDXR(result, addr); \
|
||||
OP(rscratch1, result, incr); \
|
||||
@ -2224,7 +2229,8 @@ void MacroAssembler::atomic_##OP(Register prev, Register newv, Register addr) {
|
||||
result = different(prev, newv, addr) ? prev : rscratch2; \
|
||||
\
|
||||
Label retry_load; \
|
||||
prfm(Address(addr), PSTL1STRM); \
|
||||
if ((VM_Version::features() & VM_Version::CPU_STXR_PREFETCH)) \
|
||||
prfm(Address(addr), PSTL1STRM); \
|
||||
bind(retry_load); \
|
||||
LDXR(result, addr); \
|
||||
STXR(rscratch1, newv, addr); \
|
||||
@ -4136,13 +4142,14 @@ void MacroAssembler::remove_frame(int framesize) {
|
||||
}
|
||||
}
|
||||
|
||||
typedef void (MacroAssembler::* chr_insn)(Register Rt, const Address &adr);
|
||||
|
||||
// Search for str1 in str2 and return index or -1
|
||||
void MacroAssembler::string_indexof(Register str2, Register str1,
|
||||
Register cnt2, Register cnt1,
|
||||
Register tmp1, Register tmp2,
|
||||
Register tmp3, Register tmp4,
|
||||
int icnt1, Register result) {
|
||||
int icnt1, Register result, int ae) {
|
||||
Label BM, LINEARSEARCH, DONE, NOMATCH, MATCH;
|
||||
|
||||
Register ch1 = rscratch1;
|
||||
@ -4153,6 +4160,21 @@ void MacroAssembler::string_indexof(Register str2, Register str1,
|
||||
Register cnt2_neg = cnt2;
|
||||
Register result_tmp = tmp4;
|
||||
|
||||
bool isL = ae == StrIntrinsicNode::LL;
|
||||
|
||||
bool str1_isL = ae == StrIntrinsicNode::LL || ae == StrIntrinsicNode::UL;
|
||||
bool str2_isL = ae == StrIntrinsicNode::LL || ae == StrIntrinsicNode::LU;
|
||||
int str1_chr_shift = str1_isL ? 0:1;
|
||||
int str2_chr_shift = str2_isL ? 0:1;
|
||||
int str1_chr_size = str1_isL ? 1:2;
|
||||
int str2_chr_size = str2_isL ? 1:2;
|
||||
chr_insn str1_load_1chr = str1_isL ? (chr_insn)&MacroAssembler::ldrb :
|
||||
(chr_insn)&MacroAssembler::ldrh;
|
||||
chr_insn str2_load_1chr = str2_isL ? (chr_insn)&MacroAssembler::ldrb :
|
||||
(chr_insn)&MacroAssembler::ldrh;
|
||||
chr_insn load_2chr = isL ? (chr_insn)&MacroAssembler::ldrh : (chr_insn)&MacroAssembler::ldrw;
|
||||
chr_insn load_4chr = isL ? (chr_insn)&MacroAssembler::ldrw : (chr_insn)&MacroAssembler::ldr;
|
||||
|
||||
// Note, inline_string_indexOf() generates checks:
|
||||
// if (substr.count > string.count) return -1;
|
||||
// if (substr.count == 0) return 0;
|
||||
@ -4242,7 +4264,7 @@ void MacroAssembler::string_indexof(Register str2, Register str1,
|
||||
mov(cnt1tmp, 0);
|
||||
sub(cnt1end, cnt1, 1);
|
||||
BIND(BCLOOP);
|
||||
ldrh(ch1, Address(str1, cnt1tmp, Address::lsl(1)));
|
||||
(this->*str1_load_1chr)(ch1, Address(str1, cnt1tmp, Address::lsl(str1_chr_shift)));
|
||||
cmp(ch1, 128);
|
||||
add(cnt1tmp, cnt1tmp, 1);
|
||||
br(HS, BCSKIP);
|
||||
@ -4254,36 +4276,36 @@ void MacroAssembler::string_indexof(Register str2, Register str1,
|
||||
mov(result_tmp, str2);
|
||||
|
||||
sub(cnt2, cnt2, cnt1);
|
||||
add(str2end, str2, cnt2, LSL, 1);
|
||||
add(str2end, str2, cnt2, LSL, str2_chr_shift);
|
||||
BIND(BMLOOPSTR2);
|
||||
sub(cnt1tmp, cnt1, 1);
|
||||
ldrh(ch1, Address(str1, cnt1tmp, Address::lsl(1)));
|
||||
ldrh(skipch, Address(str2, cnt1tmp, Address::lsl(1)));
|
||||
(this->*str1_load_1chr)(ch1, Address(str1, cnt1tmp, Address::lsl(str1_chr_shift)));
|
||||
(this->*str2_load_1chr)(skipch, Address(str2, cnt1tmp, Address::lsl(str2_chr_shift)));
|
||||
cmp(ch1, skipch);
|
||||
br(NE, BMSKIP);
|
||||
subs(cnt1tmp, cnt1tmp, 1);
|
||||
br(LT, BMMATCH);
|
||||
BIND(BMLOOPSTR1);
|
||||
ldrh(ch1, Address(str1, cnt1tmp, Address::lsl(1)));
|
||||
ldrh(ch2, Address(str2, cnt1tmp, Address::lsl(1)));
|
||||
(this->*str1_load_1chr)(ch1, Address(str1, cnt1tmp, Address::lsl(str1_chr_shift)));
|
||||
(this->*str2_load_1chr)(ch2, Address(str2, cnt1tmp, Address::lsl(str2_chr_shift)));
|
||||
cmp(ch1, ch2);
|
||||
br(NE, BMSKIP);
|
||||
subs(cnt1tmp, cnt1tmp, 1);
|
||||
br(GE, BMLOOPSTR1);
|
||||
BIND(BMMATCH);
|
||||
sub(result_tmp, str2, result_tmp);
|
||||
lsr(result, result_tmp, 1);
|
||||
sub(result, str2, result_tmp);
|
||||
if (!str2_isL) lsr(result, result, 1);
|
||||
add(sp, sp, 128);
|
||||
b(DONE);
|
||||
BIND(BMADV);
|
||||
add(str2, str2, 2);
|
||||
add(str2, str2, str2_chr_size);
|
||||
b(BMCHECKEND);
|
||||
BIND(BMSKIP);
|
||||
cmp(skipch, 128);
|
||||
br(HS, BMADV);
|
||||
ldrb(ch2, Address(sp, skipch));
|
||||
add(str2, str2, cnt1, LSL, 1);
|
||||
sub(str2, str2, ch2, LSL, 1);
|
||||
add(str2, str2, cnt1, LSL, str2_chr_shift);
|
||||
sub(str2, str2, ch2, LSL, str2_chr_shift);
|
||||
BIND(BMCHECKEND);
|
||||
cmp(str2, str2end);
|
||||
br(LE, BMLOOPSTR2);
|
||||
@ -4300,119 +4322,113 @@ void MacroAssembler::string_indexof(Register str2, Register str1,
|
||||
|
||||
if (icnt1 == -1)
|
||||
{
|
||||
Label DOSHORT, FIRST_LOOP, STR2_NEXT, STR1_LOOP, STR1_NEXT, LAST_WORD;
|
||||
Label DOSHORT, FIRST_LOOP, STR2_NEXT, STR1_LOOP, STR1_NEXT;
|
||||
|
||||
cmp(cnt1, 4);
|
||||
cmp(cnt1, str1_isL == str2_isL ? 4 : 2);
|
||||
br(LT, DOSHORT);
|
||||
|
||||
sub(cnt2, cnt2, cnt1);
|
||||
sub(cnt1, cnt1, 4);
|
||||
mov(result_tmp, cnt2);
|
||||
|
||||
lea(str1, Address(str1, cnt1, Address::uxtw(1)));
|
||||
lea(str2, Address(str2, cnt2, Address::uxtw(1)));
|
||||
sub(cnt1_neg, zr, cnt1, LSL, 1);
|
||||
sub(cnt2_neg, zr, cnt2, LSL, 1);
|
||||
ldr(first, Address(str1, cnt1_neg));
|
||||
lea(str1, Address(str1, cnt1, Address::lsl(str1_chr_shift)));
|
||||
lea(str2, Address(str2, cnt2, Address::lsl(str2_chr_shift)));
|
||||
sub(cnt1_neg, zr, cnt1, LSL, str1_chr_shift);
|
||||
sub(cnt2_neg, zr, cnt2, LSL, str2_chr_shift);
|
||||
(this->*str1_load_1chr)(first, Address(str1, cnt1_neg));
|
||||
|
||||
BIND(FIRST_LOOP);
|
||||
ldr(ch2, Address(str2, cnt2_neg));
|
||||
(this->*str2_load_1chr)(ch2, Address(str2, cnt2_neg));
|
||||
cmp(first, ch2);
|
||||
br(EQ, STR1_LOOP);
|
||||
BIND(STR2_NEXT);
|
||||
adds(cnt2_neg, cnt2_neg, 2);
|
||||
adds(cnt2_neg, cnt2_neg, str2_chr_size);
|
||||
br(LE, FIRST_LOOP);
|
||||
b(NOMATCH);
|
||||
|
||||
BIND(STR1_LOOP);
|
||||
adds(cnt1tmp, cnt1_neg, 8);
|
||||
add(cnt2tmp, cnt2_neg, 8);
|
||||
br(GE, LAST_WORD);
|
||||
adds(cnt1tmp, cnt1_neg, str1_chr_size);
|
||||
add(cnt2tmp, cnt2_neg, str2_chr_size);
|
||||
br(GE, MATCH);
|
||||
|
||||
BIND(STR1_NEXT);
|
||||
ldr(ch1, Address(str1, cnt1tmp));
|
||||
ldr(ch2, Address(str2, cnt2tmp));
|
||||
(this->*str1_load_1chr)(ch1, Address(str1, cnt1tmp));
|
||||
(this->*str2_load_1chr)(ch2, Address(str2, cnt2tmp));
|
||||
cmp(ch1, ch2);
|
||||
br(NE, STR2_NEXT);
|
||||
adds(cnt1tmp, cnt1tmp, 8);
|
||||
add(cnt2tmp, cnt2tmp, 8);
|
||||
adds(cnt1tmp, cnt1tmp, str1_chr_size);
|
||||
add(cnt2tmp, cnt2tmp, str2_chr_size);
|
||||
br(LT, STR1_NEXT);
|
||||
|
||||
BIND(LAST_WORD);
|
||||
ldr(ch1, Address(str1));
|
||||
sub(str2tmp, str2, cnt1_neg); // adjust to corresponding
|
||||
ldr(ch2, Address(str2tmp, cnt2_neg)); // word in str2
|
||||
cmp(ch1, ch2);
|
||||
br(NE, STR2_NEXT);
|
||||
b(MATCH);
|
||||
|
||||
BIND(DOSHORT);
|
||||
if (str1_isL == str2_isL) {
|
||||
cmp(cnt1, 2);
|
||||
br(LT, DO1);
|
||||
br(GT, DO3);
|
||||
}
|
||||
}
|
||||
|
||||
if (icnt1 == 4) {
|
||||
Label CH1_LOOP;
|
||||
|
||||
ldr(ch1, str1);
|
||||
(this->*load_4chr)(ch1, str1);
|
||||
sub(cnt2, cnt2, 4);
|
||||
mov(result_tmp, cnt2);
|
||||
lea(str2, Address(str2, cnt2, Address::uxtw(1)));
|
||||
sub(cnt2_neg, zr, cnt2, LSL, 1);
|
||||
lea(str2, Address(str2, cnt2, Address::lsl(str2_chr_shift)));
|
||||
sub(cnt2_neg, zr, cnt2, LSL, str2_chr_shift);
|
||||
|
||||
BIND(CH1_LOOP);
|
||||
ldr(ch2, Address(str2, cnt2_neg));
|
||||
(this->*load_4chr)(ch2, Address(str2, cnt2_neg));
|
||||
cmp(ch1, ch2);
|
||||
br(EQ, MATCH);
|
||||
adds(cnt2_neg, cnt2_neg, 2);
|
||||
adds(cnt2_neg, cnt2_neg, str2_chr_size);
|
||||
br(LE, CH1_LOOP);
|
||||
b(NOMATCH);
|
||||
}
|
||||
|
||||
if (icnt1 == -1 || icnt1 == 2) {
|
||||
if ((icnt1 == -1 && str1_isL == str2_isL) || icnt1 == 2) {
|
||||
Label CH1_LOOP;
|
||||
|
||||
BIND(DO2);
|
||||
ldrw(ch1, str1);
|
||||
(this->*load_2chr)(ch1, str1);
|
||||
sub(cnt2, cnt2, 2);
|
||||
mov(result_tmp, cnt2);
|
||||
lea(str2, Address(str2, cnt2, Address::uxtw(1)));
|
||||
sub(cnt2_neg, zr, cnt2, LSL, 1);
|
||||
lea(str2, Address(str2, cnt2, Address::lsl(str2_chr_shift)));
|
||||
sub(cnt2_neg, zr, cnt2, LSL, str2_chr_shift);
|
||||
|
||||
BIND(CH1_LOOP);
|
||||
ldrw(ch2, Address(str2, cnt2_neg));
|
||||
(this->*load_2chr)(ch2, Address(str2, cnt2_neg));
|
||||
cmp(ch1, ch2);
|
||||
br(EQ, MATCH);
|
||||
adds(cnt2_neg, cnt2_neg, 2);
|
||||
adds(cnt2_neg, cnt2_neg, str2_chr_size);
|
||||
br(LE, CH1_LOOP);
|
||||
b(NOMATCH);
|
||||
}
|
||||
|
||||
if (icnt1 == -1 || icnt1 == 3) {
|
||||
if ((icnt1 == -1 && str1_isL == str2_isL) || icnt1 == 3) {
|
||||
Label FIRST_LOOP, STR2_NEXT, STR1_LOOP;
|
||||
|
||||
BIND(DO3);
|
||||
ldrw(first, str1);
|
||||
ldrh(ch1, Address(str1, 4));
|
||||
(this->*load_2chr)(first, str1);
|
||||
(this->*str1_load_1chr)(ch1, Address(str1, 2*str1_chr_size));
|
||||
|
||||
sub(cnt2, cnt2, 3);
|
||||
mov(result_tmp, cnt2);
|
||||
lea(str2, Address(str2, cnt2, Address::uxtw(1)));
|
||||
sub(cnt2_neg, zr, cnt2, LSL, 1);
|
||||
lea(str2, Address(str2, cnt2, Address::lsl(str2_chr_shift)));
|
||||
sub(cnt2_neg, zr, cnt2, LSL, str2_chr_shift);
|
||||
|
||||
BIND(FIRST_LOOP);
|
||||
ldrw(ch2, Address(str2, cnt2_neg));
|
||||
(this->*load_2chr)(ch2, Address(str2, cnt2_neg));
|
||||
cmpw(first, ch2);
|
||||
br(EQ, STR1_LOOP);
|
||||
BIND(STR2_NEXT);
|
||||
adds(cnt2_neg, cnt2_neg, 2);
|
||||
adds(cnt2_neg, cnt2_neg, str2_chr_size);
|
||||
br(LE, FIRST_LOOP);
|
||||
b(NOMATCH);
|
||||
|
||||
BIND(STR1_LOOP);
|
||||
add(cnt2tmp, cnt2_neg, 4);
|
||||
ldrh(ch2, Address(str2, cnt2tmp));
|
||||
add(cnt2tmp, cnt2_neg, 2*str2_chr_size);
|
||||
(this->*str2_load_1chr)(ch2, Address(str2, cnt2tmp));
|
||||
cmp(ch1, ch2);
|
||||
br(NE, STR2_NEXT);
|
||||
b(MATCH);
|
||||
@ -4423,24 +4439,31 @@ void MacroAssembler::string_indexof(Register str2, Register str1,
|
||||
Label DO1_SHORT, DO1_LOOP;
|
||||
|
||||
BIND(DO1);
|
||||
ldrh(ch1, str1);
|
||||
cmp(cnt2, 4);
|
||||
(this->*str1_load_1chr)(ch1, str1);
|
||||
cmp(cnt2, 8);
|
||||
br(LT, DO1_SHORT);
|
||||
|
||||
if (str2_isL) {
|
||||
if (!str1_isL) {
|
||||
tst(ch1, 0xff00);
|
||||
br(NE, NOMATCH);
|
||||
}
|
||||
orr(ch1, ch1, ch1, LSL, 8);
|
||||
}
|
||||
orr(ch1, ch1, ch1, LSL, 16);
|
||||
orr(ch1, ch1, ch1, LSL, 32);
|
||||
|
||||
sub(cnt2, cnt2, 4);
|
||||
sub(cnt2, cnt2, 8/str2_chr_size);
|
||||
mov(result_tmp, cnt2);
|
||||
lea(str2, Address(str2, cnt2, Address::uxtw(1)));
|
||||
sub(cnt2_neg, zr, cnt2, LSL, 1);
|
||||
lea(str2, Address(str2, cnt2, Address::lsl(str2_chr_shift)));
|
||||
sub(cnt2_neg, zr, cnt2, LSL, str2_chr_shift);
|
||||
|
||||
mov(tmp3, 0x0001000100010001);
|
||||
mov(tmp3, str2_isL ? 0x0101010101010101 : 0x0001000100010001);
|
||||
BIND(CH1_LOOP);
|
||||
ldr(ch2, Address(str2, cnt2_neg));
|
||||
eor(ch2, ch1, ch2);
|
||||
sub(tmp1, ch2, tmp3);
|
||||
orr(tmp2, ch2, 0x7fff7fff7fff7fff);
|
||||
orr(tmp2, ch2, str2_isL ? 0x7f7f7f7f7f7f7f7f : 0x7fff7fff7fff7fff);
|
||||
bics(tmp1, tmp1, tmp2);
|
||||
br(NE, HAS_ZERO);
|
||||
adds(cnt2_neg, cnt2_neg, 8);
|
||||
@ -4459,13 +4482,13 @@ void MacroAssembler::string_indexof(Register str2, Register str1,
|
||||
|
||||
BIND(DO1_SHORT);
|
||||
mov(result_tmp, cnt2);
|
||||
lea(str2, Address(str2, cnt2, Address::uxtw(1)));
|
||||
sub(cnt2_neg, zr, cnt2, LSL, 1);
|
||||
lea(str2, Address(str2, cnt2, Address::lsl(str2_chr_shift)));
|
||||
sub(cnt2_neg, zr, cnt2, LSL, str2_chr_shift);
|
||||
BIND(DO1_LOOP);
|
||||
ldrh(ch2, Address(str2, cnt2_neg));
|
||||
(this->*str2_load_1chr)(ch2, Address(str2, cnt2_neg));
|
||||
cmpw(ch1, ch2);
|
||||
br(EQ, MATCH);
|
||||
adds(cnt2_neg, cnt2_neg, 2);
|
||||
adds(cnt2_neg, cnt2_neg, str2_chr_size);
|
||||
br(LT, DO1_LOOP);
|
||||
}
|
||||
}
|
||||
@ -4473,7 +4496,7 @@ void MacroAssembler::string_indexof(Register str2, Register str1,
|
||||
mov(result, -1);
|
||||
b(DONE);
|
||||
BIND(MATCH);
|
||||
add(result, result_tmp, cnt2_neg, ASR, 1);
|
||||
add(result, result_tmp, cnt2_neg, ASR, str2_chr_shift);
|
||||
BIND(DONE);
|
||||
}
|
||||
|
||||
|
||||
@ -545,6 +545,15 @@ public:
|
||||
mrs(0b011, 0b0000, 0b0000, 0b111, reg);
|
||||
}
|
||||
|
||||
// CTR_EL0: op1 == 011
|
||||
// CRn == 0000
|
||||
// CRm == 0000
|
||||
// op2 == 001
|
||||
inline void get_ctr_el0(Register reg)
|
||||
{
|
||||
mrs(0b011, 0b0000, 0b0000, 0b001, reg);
|
||||
}
|
||||
|
||||
// idiv variant which deals with MINLONG as dividend and -1 as divisor
|
||||
int corrected_idivl(Register result, Register ra, Register rb,
|
||||
bool want_remainder, Register tmp = rscratch1);
|
||||
@ -1217,7 +1226,7 @@ public:
|
||||
Register cnt1, Register cnt2,
|
||||
Register tmp1, Register tmp2,
|
||||
Register tmp3, Register tmp4,
|
||||
int int_cnt1, Register result);
|
||||
int int_cnt1, Register result, int ae);
|
||||
private:
|
||||
void add2_with_carry(Register final_dest_hi, Register dest_hi, Register dest_lo,
|
||||
Register src1, Register src2);
|
||||
|
||||
@ -105,6 +105,9 @@ class VM_Version_StubGenerator: public StubCodeGenerator {
|
||||
__ get_dczid_el0(rscratch1);
|
||||
__ strw(rscratch1, Address(c_rarg0, in_bytes(VM_Version::dczid_el0_offset())));
|
||||
|
||||
__ get_ctr_el0(rscratch1);
|
||||
__ strw(rscratch1, Address(c_rarg0, in_bytes(VM_Version::ctr_el0_offset())));
|
||||
|
||||
__ leave();
|
||||
__ ret(lr);
|
||||
|
||||
@ -124,16 +127,20 @@ void VM_Version::get_processor_features() {
|
||||
|
||||
getPsrInfo_stub(&_psr_info);
|
||||
|
||||
int dcache_line = VM_Version::dcache_line_size();
|
||||
|
||||
if (FLAG_IS_DEFAULT(AllocatePrefetchDistance))
|
||||
FLAG_SET_DEFAULT(AllocatePrefetchDistance, 256);
|
||||
FLAG_SET_DEFAULT(AllocatePrefetchDistance, 3*dcache_line);
|
||||
if (FLAG_IS_DEFAULT(AllocatePrefetchStepSize))
|
||||
FLAG_SET_DEFAULT(AllocatePrefetchStepSize, 64);
|
||||
FLAG_SET_DEFAULT(PrefetchScanIntervalInBytes, 256);
|
||||
FLAG_SET_DEFAULT(PrefetchFieldsAhead, 256);
|
||||
FLAG_SET_DEFAULT(AllocatePrefetchStepSize, dcache_line);
|
||||
if (FLAG_IS_DEFAULT(PrefetchScanIntervalInBytes))
|
||||
FLAG_SET_DEFAULT(PrefetchScanIntervalInBytes, 3*dcache_line);
|
||||
if (FLAG_IS_DEFAULT(PrefetchCopyIntervalInBytes))
|
||||
FLAG_SET_DEFAULT(PrefetchCopyIntervalInBytes, 256);
|
||||
if ((PrefetchCopyIntervalInBytes & 7) || (PrefetchCopyIntervalInBytes >= 32768)) {
|
||||
warning("PrefetchCopyIntervalInBytes must be a multiple of 8 and < 32768");
|
||||
FLAG_SET_DEFAULT(PrefetchCopyIntervalInBytes, 3*dcache_line);
|
||||
|
||||
if (PrefetchCopyIntervalInBytes != -1 &&
|
||||
((PrefetchCopyIntervalInBytes & 7) || (PrefetchCopyIntervalInBytes >= 32768))) {
|
||||
warning("PrefetchCopyIntervalInBytes must be -1, or a multiple of 8 and < 32768");
|
||||
PrefetchCopyIntervalInBytes &= ~7;
|
||||
if (PrefetchCopyIntervalInBytes >= 32768)
|
||||
PrefetchCopyIntervalInBytes = 32760;
|
||||
@ -170,6 +177,7 @@ void VM_Version::get_processor_features() {
|
||||
// Enable vendor specific features
|
||||
if (_cpu == CPU_CAVIUM && _variant == 0) _features |= CPU_DMB_ATOMICS;
|
||||
if (_cpu == CPU_ARM && (_model == 0xd03 || _model2 == 0xd03)) _features |= CPU_A53MAC;
|
||||
if (_cpu == CPU_ARM && (_model == 0xd07 || _model2 == 0xd07)) _features |= CPU_STXR_PREFETCH;
|
||||
// If an olde style /proc/cpuinfo (cpu_lines == 1) then if _model is an A57 (0xd07)
|
||||
// we assume the worst and assume we could be on a big little system and have
|
||||
// undisclosed A53 cores which we could be swapped to at any stage
|
||||
|
||||
@ -42,6 +42,7 @@ protected:
|
||||
|
||||
struct PsrInfo {
|
||||
uint32_t dczid_el0;
|
||||
uint32_t ctr_el0;
|
||||
};
|
||||
static PsrInfo _psr_info;
|
||||
static void get_processor_features();
|
||||
@ -78,6 +79,7 @@ public:
|
||||
CPU_SHA2 = (1<<6),
|
||||
CPU_CRC32 = (1<<7),
|
||||
CPU_LSE = (1<<8),
|
||||
CPU_STXR_PREFETCH= (1 << 29),
|
||||
CPU_A53MAC = (1 << 30),
|
||||
CPU_DMB_ATOMICS = (1 << 31),
|
||||
};
|
||||
@ -88,6 +90,7 @@ public:
|
||||
static int cpu_variant() { return _variant; }
|
||||
static int cpu_revision() { return _revision; }
|
||||
static ByteSize dczid_el0_offset() { return byte_offset_of(PsrInfo, dczid_el0); }
|
||||
static ByteSize ctr_el0_offset() { return byte_offset_of(PsrInfo, ctr_el0); }
|
||||
static bool is_zva_enabled() {
|
||||
// Check the DZP bit (bit 4) of dczid_el0 is zero
|
||||
// and block size (bit 0~3) is not zero.
|
||||
@ -98,6 +101,12 @@ public:
|
||||
assert(is_zva_enabled(), "ZVA not available");
|
||||
return 4 << (_psr_info.dczid_el0 & 0xf);
|
||||
}
|
||||
static int icache_line_size() {
|
||||
return (1 << (_psr_info.ctr_el0 & 0x0f)) * 4;
|
||||
}
|
||||
static int dcache_line_size() {
|
||||
return (1 << ((_psr_info.ctr_el0 >> 16) & 0x0f)) * 4;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // CPU_AARCH64_VM_VM_VERSION_AARCH64_HPP
|
||||
|
||||
@ -1712,7 +1712,8 @@ public class CommandProcessor {
|
||||
// called after debuggee attach
|
||||
private void postAttach() {
|
||||
// create JavaScript engine and start it
|
||||
jsengine = new JSJavaScriptEngine() {
|
||||
try {
|
||||
jsengine = new JSJavaScriptEngine() {
|
||||
private ObjectReader reader = new ObjectReader();
|
||||
private JSJavaFactory factory = new JSJavaFactoryImpl();
|
||||
public ObjectReader getObjectReader() {
|
||||
@ -1735,17 +1736,24 @@ public class CommandProcessor {
|
||||
return err;
|
||||
}
|
||||
};
|
||||
try {
|
||||
jsengine.defineFunction(this,
|
||||
try {
|
||||
jsengine.defineFunction(this,
|
||||
this.getClass().getMethod("registerCommand",
|
||||
new Class[] {
|
||||
String.class, String.class, String.class
|
||||
}));
|
||||
} catch (NoSuchMethodException exp) {
|
||||
// should not happen, see below...!!
|
||||
exp.printStackTrace();
|
||||
} catch (NoSuchMethodException exp) {
|
||||
// should not happen, see below...!!
|
||||
exp.printStackTrace();
|
||||
}
|
||||
jsengine.start();
|
||||
}
|
||||
catch (Exception ex) {
|
||||
System.out.println("Warning! JS Engine can't start, some commands will not be available.");
|
||||
if (verboseExceptions) {
|
||||
ex.printStackTrace(out);
|
||||
}
|
||||
}
|
||||
jsengine.start();
|
||||
}
|
||||
|
||||
public void registerCommand(String cmd, String usage, final String func) {
|
||||
|
||||
@ -704,13 +704,14 @@ Method* ciEnv::lookup_method(InstanceKlass* accessor,
|
||||
InstanceKlass* holder,
|
||||
Symbol* name,
|
||||
Symbol* sig,
|
||||
Bytecodes::Code bc) {
|
||||
Bytecodes::Code bc,
|
||||
constantTag tag) {
|
||||
EXCEPTION_CONTEXT;
|
||||
KlassHandle h_accessor(THREAD, accessor);
|
||||
KlassHandle h_holder(THREAD, holder);
|
||||
LinkResolver::check_klass_accessability(h_accessor, h_holder, KILL_COMPILE_ON_FATAL_(NULL));
|
||||
methodHandle dest_method;
|
||||
LinkInfo link_info(h_holder, name, sig, h_accessor, /*check_access*/true);
|
||||
LinkInfo link_info(h_holder, name, sig, h_accessor, LinkInfo::needs_access_check, tag);
|
||||
switch (bc) {
|
||||
case Bytecodes::_invokestatic:
|
||||
dest_method =
|
||||
@ -796,7 +797,9 @@ ciMethod* ciEnv::get_method_by_index_impl(const constantPoolHandle& cpool,
|
||||
|
||||
if (holder_is_accessible) { // Our declared holder is loaded.
|
||||
InstanceKlass* lookup = declared_holder->get_instanceKlass();
|
||||
Method* m = lookup_method(accessor->get_instanceKlass(), lookup, name_sym, sig_sym, bc);
|
||||
constantTag tag = cpool->tag_ref_at(index);
|
||||
assert(accessor->get_instanceKlass() == cpool->pool_holder(), "not the pool holder?");
|
||||
Method* m = lookup_method(accessor->get_instanceKlass(), lookup, name_sym, sig_sym, bc, tag);
|
||||
if (m != NULL &&
|
||||
(bc == Bytecodes::_invokestatic
|
||||
? m->method_holder()->is_not_initialized()
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -156,7 +156,8 @@ private:
|
||||
InstanceKlass* holder,
|
||||
Symbol* name,
|
||||
Symbol* sig,
|
||||
Bytecodes::Code bc);
|
||||
Bytecodes::Code bc,
|
||||
constantTag tag);
|
||||
|
||||
// Get a ciObject from the object factory. Ensures uniqueness
|
||||
// of ciObjects.
|
||||
|
||||
@ -789,7 +789,8 @@ ciMethod* ciMethod::resolve_invoke(ciKlass* caller, ciKlass* exact_receiver, boo
|
||||
Symbol* h_name = name()->get_symbol();
|
||||
Symbol* h_signature = signature()->get_symbol();
|
||||
|
||||
LinkInfo link_info(h_resolved, h_name, h_signature, caller_klass, check_access);
|
||||
LinkInfo link_info(h_resolved, h_name, h_signature, caller_klass,
|
||||
check_access ? LinkInfo::needs_access_check : LinkInfo::skip_access_check);
|
||||
methodHandle m;
|
||||
// Only do exact lookup if receiver klass has been linked. Otherwise,
|
||||
// the vtable has not been setup, and the LinkResolver will fail.
|
||||
|
||||
@ -231,6 +231,7 @@ LinkInfo::LinkInfo(const constantPoolHandle& pool, int index, TRAPS) {
|
||||
// Get name, signature, and static klass
|
||||
_name = pool->name_ref_at(index);
|
||||
_signature = pool->signature_ref_at(index);
|
||||
_tag = pool->tag_ref_at(index);
|
||||
_current_klass = KlassHandle(THREAD, pool->pool_holder());
|
||||
|
||||
// Coming from the constant pool always checks access
|
||||
@ -573,7 +574,7 @@ methodHandle LinkResolver::resolve_method_statically(Bytecodes::Code code,
|
||||
Symbol* method_signature = pool->signature_ref_at(index);
|
||||
KlassHandle current_klass(THREAD, pool->pool_holder());
|
||||
LinkInfo link_info(resolved_klass, method_name, method_signature, current_klass);
|
||||
return resolve_method(link_info, /*require_methodref*/false, THREAD);
|
||||
return resolve_method(link_info, code, THREAD);
|
||||
}
|
||||
|
||||
LinkInfo link_info(pool, index, CHECK_NULL);
|
||||
@ -591,9 +592,9 @@ methodHandle LinkResolver::resolve_method_statically(Bytecodes::Code code,
|
||||
if (code == Bytecodes::_invokeinterface) {
|
||||
return resolve_interface_method(link_info, code, THREAD);
|
||||
} else if (code == Bytecodes::_invokevirtual) {
|
||||
return resolve_method(link_info, /*require_methodref*/true, THREAD);
|
||||
return resolve_method(link_info, code, THREAD);
|
||||
} else if (!resolved_klass->is_interface()) {
|
||||
return resolve_method(link_info, /*require_methodref*/false, THREAD);
|
||||
return resolve_method(link_info, code, THREAD);
|
||||
} else {
|
||||
return resolve_interface_method(link_info, code, THREAD);
|
||||
}
|
||||
@ -663,13 +664,13 @@ void LinkResolver::check_field_loader_constraints(Symbol* field, Symbol* sig,
|
||||
}
|
||||
|
||||
methodHandle LinkResolver::resolve_method(const LinkInfo& link_info,
|
||||
bool require_methodref, TRAPS) {
|
||||
Bytecodes::Code code, TRAPS) {
|
||||
|
||||
Handle nested_exception;
|
||||
KlassHandle resolved_klass = link_info.resolved_klass();
|
||||
|
||||
// 1. check if methodref required, that resolved_klass is not interfacemethodref
|
||||
if (require_methodref && resolved_klass->is_interface()) {
|
||||
// 1. For invokevirtual, cannot call an interface method
|
||||
if (code == Bytecodes::_invokevirtual && resolved_klass->is_interface()) {
|
||||
ResourceMark rm(THREAD);
|
||||
char buf[200];
|
||||
jio_snprintf(buf, sizeof(buf), "Found interface %s, but class was expected",
|
||||
@ -677,11 +678,20 @@ methodHandle LinkResolver::resolve_method(const LinkInfo& link_info,
|
||||
THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), buf);
|
||||
}
|
||||
|
||||
// 2. lookup method in resolved klass and its super klasses
|
||||
// 2. check constant pool tag for called method - must be JVM_CONSTANT_Methodref
|
||||
if (!link_info.tag().is_invalid() && !link_info.tag().is_method()) {
|
||||
ResourceMark rm(THREAD);
|
||||
char buf[200];
|
||||
jio_snprintf(buf, sizeof(buf), "Method %s must be Methodref constant", link_info.method_string());
|
||||
THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), buf);
|
||||
}
|
||||
|
||||
|
||||
// 3. lookup method in resolved klass and its super klasses
|
||||
methodHandle resolved_method = lookup_method_in_klasses(link_info, true, false, CHECK_NULL);
|
||||
|
||||
// 4. lookup method in all the interfaces implemented by the resolved klass
|
||||
if (resolved_method.is_null() && !resolved_klass->is_array_klass()) { // not found in the class hierarchy
|
||||
// 3. lookup method in all the interfaces implemented by the resolved klass
|
||||
resolved_method = lookup_method_in_interfaces(link_info, CHECK_NULL);
|
||||
|
||||
if (resolved_method.is_null()) {
|
||||
@ -694,8 +704,8 @@ methodHandle LinkResolver::resolve_method(const LinkInfo& link_info,
|
||||
}
|
||||
}
|
||||
|
||||
// 5. method lookup failed
|
||||
if (resolved_method.is_null()) {
|
||||
// 4. method lookup failed
|
||||
ResourceMark rm(THREAD);
|
||||
THROW_MSG_CAUSE_(vmSymbols::java_lang_NoSuchMethodError(),
|
||||
Method::name_and_sig_as_C_string(resolved_klass(),
|
||||
@ -704,7 +714,7 @@ methodHandle LinkResolver::resolve_method(const LinkInfo& link_info,
|
||||
nested_exception, NULL);
|
||||
}
|
||||
|
||||
// 5. access checks, access checking may be turned off when calling from within the VM.
|
||||
// 6. access checks, access checking may be turned off when calling from within the VM.
|
||||
KlassHandle current_klass = link_info.current_klass();
|
||||
if (link_info.check_access()) {
|
||||
assert(current_klass.not_null() , "current_klass should not be null");
|
||||
@ -766,6 +776,14 @@ methodHandle LinkResolver::resolve_interface_method(const LinkInfo& link_info, B
|
||||
THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), buf);
|
||||
}
|
||||
|
||||
// check constant pool tag for called method - must be JVM_CONSTANT_InterfaceMethodref
|
||||
if (!link_info.tag().is_invalid() && !link_info.tag().is_interface_method()) {
|
||||
ResourceMark rm(THREAD);
|
||||
char buf[200];
|
||||
jio_snprintf(buf, sizeof(buf), "Method %s must be InterfaceMethodref constant", link_info.method_string());
|
||||
THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), buf);
|
||||
}
|
||||
|
||||
// lookup method in this interface or its super, java.lang.Object
|
||||
// JDK8: also look for static methods
|
||||
methodHandle resolved_method = lookup_method_in_klasses(link_info, false, true, CHECK_NULL);
|
||||
@ -956,7 +974,8 @@ void LinkResolver::resolve_static_call(CallInfo& result,
|
||||
resolved_klass->initialize(CHECK);
|
||||
// Use updated LinkInfo (to reresolve with resolved_klass as method_holder?)
|
||||
LinkInfo new_info(resolved_klass, link_info.name(), link_info.signature(),
|
||||
link_info.current_klass(), link_info.check_access());
|
||||
link_info.current_klass(),
|
||||
link_info.check_access() ? LinkInfo::needs_access_check : LinkInfo::skip_access_check);
|
||||
resolved_method = linktime_resolve_static_method(new_info, CHECK);
|
||||
}
|
||||
|
||||
@ -971,7 +990,7 @@ methodHandle LinkResolver::linktime_resolve_static_method(const LinkInfo& link_i
|
||||
KlassHandle resolved_klass = link_info.resolved_klass();
|
||||
methodHandle resolved_method;
|
||||
if (!resolved_klass->is_interface()) {
|
||||
resolved_method = resolve_method(link_info, /*require_methodref*/false, CHECK_NULL);
|
||||
resolved_method = resolve_method(link_info, Bytecodes::_invokestatic, CHECK_NULL);
|
||||
} else {
|
||||
resolved_method = resolve_interface_method(link_info, Bytecodes::_invokestatic, CHECK_NULL);
|
||||
}
|
||||
@ -1014,7 +1033,7 @@ methodHandle LinkResolver::linktime_resolve_special_method(const LinkInfo& link_
|
||||
methodHandle resolved_method;
|
||||
|
||||
if (!resolved_klass->is_interface()) {
|
||||
resolved_method = resolve_method(link_info, /*require_methodref*/false, CHECK_NULL);
|
||||
resolved_method = resolve_method(link_info, Bytecodes::_invokespecial, CHECK_NULL);
|
||||
} else {
|
||||
resolved_method = resolve_interface_method(link_info, Bytecodes::_invokespecial, CHECK_NULL);
|
||||
}
|
||||
@ -1164,7 +1183,7 @@ void LinkResolver::resolve_virtual_call(CallInfo& result, Handle recv, KlassHand
|
||||
methodHandle LinkResolver::linktime_resolve_virtual_method(const LinkInfo& link_info,
|
||||
TRAPS) {
|
||||
// normal method resolution
|
||||
methodHandle resolved_method = resolve_method(link_info, /*require_methodref*/true, CHECK_NULL);
|
||||
methodHandle resolved_method = resolve_method(link_info, Bytecodes::_invokevirtual, CHECK_NULL);
|
||||
|
||||
assert(resolved_method->name() != vmSymbols::object_initializer_name(), "should have been checked in verifier");
|
||||
assert(resolved_method->name() != vmSymbols::class_initializer_name (), "should have been checked in verifier");
|
||||
@ -1173,6 +1192,7 @@ methodHandle LinkResolver::linktime_resolve_virtual_method(const LinkInfo& link_
|
||||
KlassHandle resolved_klass = link_info.resolved_klass();
|
||||
KlassHandle current_klass = link_info.current_klass();
|
||||
|
||||
// This is impossible, if resolve_klass is an interface, we've thrown icce in resolve_method
|
||||
if (resolved_klass->is_interface() && resolved_method->is_private()) {
|
||||
ResourceMark rm(THREAD);
|
||||
char buf[200];
|
||||
@ -1482,7 +1502,7 @@ void LinkResolver::resolve_invoke(CallInfo& result, Handle& recv,
|
||||
KlassHandle defc = attached_method->method_holder();
|
||||
Symbol* name = attached_method->name();
|
||||
Symbol* type = attached_method->signature();
|
||||
LinkInfo link_info(defc, name, type, KlassHandle(), /*check_access=*/false);
|
||||
LinkInfo link_info(defc, name, type);
|
||||
switch(byte) {
|
||||
case Bytecodes::_invokevirtual:
|
||||
resolve_virtual_call(result, recv, recv->klass(), link_info,
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -137,20 +137,35 @@ class LinkInfo : public StackObj {
|
||||
KlassHandle _resolved_klass; // class that the constant pool entry points to
|
||||
KlassHandle _current_klass; // class that owns the constant pool
|
||||
bool _check_access;
|
||||
constantTag _tag;
|
||||
public:
|
||||
enum AccessCheck {
|
||||
needs_access_check,
|
||||
skip_access_check
|
||||
};
|
||||
|
||||
LinkInfo(const constantPoolHandle& pool, int index, TRAPS);
|
||||
|
||||
// Condensed information from other call sites within the vm.
|
||||
LinkInfo(KlassHandle resolved_klass, Symbol* name, Symbol* signature,
|
||||
KlassHandle current_klass, bool check_access = true) :
|
||||
LinkInfo(KlassHandle resolved_klass, Symbol* name, Symbol* signature, KlassHandle current_klass,
|
||||
AccessCheck check_access = needs_access_check,
|
||||
constantTag tag = JVM_CONSTANT_Invalid) :
|
||||
_resolved_klass(resolved_klass),
|
||||
_name(name), _signature(signature), _current_klass(current_klass),
|
||||
_check_access(check_access) {}
|
||||
_check_access(check_access == needs_access_check), _tag(tag) {}
|
||||
|
||||
// Case where we just find the method and don't check access against the current class
|
||||
LinkInfo(KlassHandle resolved_klass, Symbol*name, Symbol* signature) :
|
||||
_resolved_klass(resolved_klass),
|
||||
_name(name), _signature(signature), _current_klass(NULL),
|
||||
_check_access(false), _tag(JVM_CONSTANT_Invalid) {}
|
||||
|
||||
// accessors
|
||||
Symbol* name() const { return _name; }
|
||||
Symbol* signature() const { return _signature; }
|
||||
KlassHandle resolved_klass() const { return _resolved_klass; }
|
||||
KlassHandle current_klass() const { return _current_klass; }
|
||||
constantTag tag() const { return _tag; }
|
||||
bool check_access() const { return _check_access; }
|
||||
char* method_string() const;
|
||||
|
||||
@ -192,7 +207,7 @@ class LinkResolver: AllStatic {
|
||||
KlassHandle sel_klass, TRAPS);
|
||||
|
||||
static methodHandle resolve_interface_method(const LinkInfo& link_info, Bytecodes::Code code, TRAPS);
|
||||
static methodHandle resolve_method (const LinkInfo& link_info, bool require_methodref, TRAPS);
|
||||
static methodHandle resolve_method (const LinkInfo& link_info, Bytecodes::Code code, TRAPS);
|
||||
|
||||
static methodHandle linktime_resolve_static_method (const LinkInfo& link_info, TRAPS);
|
||||
static methodHandle linktime_resolve_special_method (const LinkInfo& link_info, TRAPS);
|
||||
|
||||
@ -661,8 +661,7 @@ C2V_VMENTRY(jobject, resolveMethod, (JNIEnv *, jobject, jobject receiver_jvmci_t
|
||||
Symbol* h_name = method->name();
|
||||
Symbol* h_signature = method->signature();
|
||||
|
||||
bool check_access = true;
|
||||
LinkInfo link_info(h_resolved, h_name, h_signature, caller_klass, check_access);
|
||||
LinkInfo link_info(h_resolved, h_name, h_signature, caller_klass);
|
||||
methodHandle m;
|
||||
// Only do exact lookup if receiver klass has been linked. Otherwise,
|
||||
// the vtable has not been setup, and the LinkResolver will fail.
|
||||
|
||||
@ -286,11 +286,12 @@ methodHandle JVMCIEnv::lookup_method(instanceKlassHandle h_accessor,
|
||||
instanceKlassHandle h_holder,
|
||||
Symbol* name,
|
||||
Symbol* sig,
|
||||
Bytecodes::Code bc) {
|
||||
Bytecodes::Code bc,
|
||||
constantTag tag) {
|
||||
JVMCI_EXCEPTION_CONTEXT;
|
||||
LinkResolver::check_klass_accessability(h_accessor, h_holder, KILL_COMPILE_ON_FATAL_(NULL));
|
||||
methodHandle dest_method;
|
||||
LinkInfo link_info(h_holder, name, sig, h_accessor, /*check_access*/true);
|
||||
LinkInfo link_info(h_holder, name, sig, h_accessor, LinkInfo::needs_access_check, tag);
|
||||
switch (bc) {
|
||||
case Bytecodes::_invokestatic:
|
||||
dest_method =
|
||||
@ -363,7 +364,8 @@ methodHandle JVMCIEnv::get_method_by_index_impl(const constantPoolHandle& cpool,
|
||||
|
||||
if (holder_is_accessible) { // Our declared holder is loaded.
|
||||
instanceKlassHandle lookup = get_instance_klass_for_declared_method_holder(holder);
|
||||
methodHandle m = lookup_method(accessor, lookup, name_sym, sig_sym, bc);
|
||||
constantTag tag = cpool->tag_ref_at(index);
|
||||
methodHandle m = lookup_method(accessor, lookup, name_sym, sig_sym, bc, tag);
|
||||
if (!m.is_null() &&
|
||||
(bc == Bytecodes::_invokestatic
|
||||
? InstanceKlass::cast(m->method_holder())->is_not_initialized()
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -130,7 +130,8 @@ private:
|
||||
instanceKlassHandle holder,
|
||||
Symbol* name,
|
||||
Symbol* sig,
|
||||
Bytecodes::Code bc);
|
||||
Bytecodes::Code bc,
|
||||
constantTag tag);
|
||||
|
||||
private:
|
||||
|
||||
|
||||
@ -417,6 +417,19 @@ int ConstantPool::impl_name_and_type_ref_index_at(int which, bool uncached) {
|
||||
return extract_high_short_from_int(ref_index);
|
||||
}
|
||||
|
||||
constantTag ConstantPool::impl_tag_ref_at(int which, bool uncached) {
|
||||
int pool_index = which;
|
||||
if (!uncached && cache() != NULL) {
|
||||
if (ConstantPool::is_invokedynamic_index(which)) {
|
||||
// Invokedynamic index is index into resolved_references
|
||||
pool_index = invokedynamic_cp_cache_entry_at(which)->constant_pool_index();
|
||||
} else {
|
||||
// change byte-ordering and go via cache
|
||||
pool_index = remap_instruction_operand_from_cache(which);
|
||||
}
|
||||
}
|
||||
return tag_at(pool_index);
|
||||
}
|
||||
|
||||
int ConstantPool::impl_klass_ref_index_at(int which, bool uncached) {
|
||||
guarantee(!ConstantPool::is_invokedynamic_index(which),
|
||||
@ -672,6 +685,7 @@ oop ConstantPool::resolve_constant_at_impl(const constantPoolHandle& this_cp, in
|
||||
int callee_index = this_cp->method_handle_klass_index_at(index);
|
||||
Symbol* name = this_cp->method_handle_name_ref_at(index);
|
||||
Symbol* signature = this_cp->method_handle_signature_ref_at(index);
|
||||
constantTag m_tag = this_cp->tag_at(this_cp->method_handle_index_at(index));
|
||||
{ ResourceMark rm(THREAD);
|
||||
log_debug(class, resolve)("resolve JVM_CONSTANT_MethodHandle:%d [%d/%d/%d] %s.%s",
|
||||
ref_kind, index, this_cp->method_handle_index_at(index),
|
||||
@ -681,6 +695,15 @@ oop ConstantPool::resolve_constant_at_impl(const constantPoolHandle& this_cp, in
|
||||
{ Klass* k = klass_at_impl(this_cp, callee_index, true, CHECK_NULL);
|
||||
callee = KlassHandle(THREAD, k);
|
||||
}
|
||||
if ((callee->is_interface() && m_tag.is_method()) ||
|
||||
(!callee->is_interface() && m_tag.is_interface_method())) {
|
||||
ResourceMark rm(THREAD);
|
||||
char buf[200];
|
||||
jio_snprintf(buf, sizeof(buf), "Inconsistent constant data for %s.%s%s at index %d",
|
||||
callee->name()->as_C_string(), name->as_C_string(), signature->as_C_string(), index);
|
||||
THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), buf);
|
||||
}
|
||||
|
||||
KlassHandle klass(THREAD, this_cp->pool_holder());
|
||||
Handle value = SystemDictionary::link_method_handle_constant(klass, ref_kind,
|
||||
callee, name, signature,
|
||||
|
||||
@ -643,6 +643,8 @@ class ConstantPool : public Metadata {
|
||||
|
||||
int remap_instruction_operand_from_cache(int operand); // operand must be biased by CPCACHE_INDEX_TAG
|
||||
|
||||
constantTag tag_ref_at(int cp_cache_index) { return impl_tag_ref_at(cp_cache_index, false); }
|
||||
|
||||
// Lookup for entries consisting of (name_index, signature_index)
|
||||
int name_ref_index_at(int which_nt); // == low-order jshort of name_and_type_at(which_nt)
|
||||
int signature_ref_index_at(int which_nt); // == high-order jshort of name_and_type_at(which_nt)
|
||||
@ -763,6 +765,7 @@ class ConstantPool : public Metadata {
|
||||
Symbol* impl_signature_ref_at(int which, bool uncached);
|
||||
int impl_klass_ref_index_at(int which, bool uncached);
|
||||
int impl_name_and_type_ref_index_at(int which, bool uncached);
|
||||
constantTag impl_tag_ref_at(int which, bool uncached);
|
||||
|
||||
// Used while constructing constant pool (only by ClassFileParser)
|
||||
jint klass_index_at(int which) {
|
||||
|
||||
@ -713,12 +713,16 @@ Handle MethodHandles::resolve_MemberName(Handle mname, KlassHandle caller, TRAPS
|
||||
TempNewSymbol type = lookup_signature(type_str(), (mh_invoke_id != vmIntrinsics::_none), CHECK_(empty));
|
||||
if (type == NULL) return empty; // no such signature exists in the VM
|
||||
|
||||
LinkInfo::AccessCheck access_check = caller.not_null() ?
|
||||
LinkInfo::needs_access_check :
|
||||
LinkInfo::skip_access_check;
|
||||
|
||||
// Time to do the lookup.
|
||||
switch (flags & ALL_KINDS) {
|
||||
case IS_METHOD:
|
||||
{
|
||||
CallInfo result;
|
||||
LinkInfo link_info(defc, name, type, caller, caller.not_null());
|
||||
LinkInfo link_info(defc, name, type, caller, access_check);
|
||||
{
|
||||
assert(!HAS_PENDING_EXCEPTION, "");
|
||||
if (ref_kind == JVM_REF_invokeStatic) {
|
||||
@ -755,7 +759,7 @@ Handle MethodHandles::resolve_MemberName(Handle mname, KlassHandle caller, TRAPS
|
||||
case IS_CONSTRUCTOR:
|
||||
{
|
||||
CallInfo result;
|
||||
LinkInfo link_info(defc, name, type, caller, caller.not_null());
|
||||
LinkInfo link_info(defc, name, type, caller, access_check);
|
||||
{
|
||||
assert(!HAS_PENDING_EXCEPTION, "");
|
||||
if (name == vmSymbols::object_initializer_name()) {
|
||||
@ -776,7 +780,7 @@ Handle MethodHandles::resolve_MemberName(Handle mname, KlassHandle caller, TRAPS
|
||||
fieldDescriptor result; // find_field initializes fd if found
|
||||
{
|
||||
assert(!HAS_PENDING_EXCEPTION, "");
|
||||
LinkInfo link_info(defc, name, type, caller, /*check_access*/false);
|
||||
LinkInfo link_info(defc, name, type, caller, LinkInfo::skip_access_check);
|
||||
LinkResolver::resolve_field(result, link_info, Bytecodes::_nop, false, THREAD);
|
||||
if (HAS_PENDING_EXCEPTION) {
|
||||
return empty;
|
||||
|
||||
@ -183,7 +183,7 @@ void JavaCalls::call_virtual(JavaValue* result, KlassHandle spec_klass, Symbol*
|
||||
CallInfo callinfo;
|
||||
Handle receiver = args->receiver();
|
||||
KlassHandle recvrKlass(THREAD, receiver.is_null() ? (Klass*)NULL : receiver->klass());
|
||||
LinkInfo link_info(spec_klass, name, signature, KlassHandle(), /*check_access*/false);
|
||||
LinkInfo link_info(spec_klass, name, signature);
|
||||
LinkResolver::resolve_virtual_call(
|
||||
callinfo, receiver, recvrKlass, link_info, true, CHECK);
|
||||
methodHandle method = callinfo.selected_method();
|
||||
@ -220,7 +220,7 @@ void JavaCalls::call_virtual(JavaValue* result, Handle receiver, KlassHandle spe
|
||||
|
||||
void JavaCalls::call_special(JavaValue* result, KlassHandle klass, Symbol* name, Symbol* signature, JavaCallArguments* args, TRAPS) {
|
||||
CallInfo callinfo;
|
||||
LinkInfo link_info(klass, name, signature, KlassHandle(), /*check_access*/false);
|
||||
LinkInfo link_info(klass, name, signature);
|
||||
LinkResolver::resolve_special_call(callinfo, link_info, CHECK);
|
||||
methodHandle method = callinfo.selected_method();
|
||||
assert(method.not_null(), "should have thrown exception");
|
||||
@ -255,7 +255,7 @@ void JavaCalls::call_special(JavaValue* result, Handle receiver, KlassHandle kla
|
||||
|
||||
void JavaCalls::call_static(JavaValue* result, KlassHandle klass, Symbol* name, Symbol* signature, JavaCallArguments* args, TRAPS) {
|
||||
CallInfo callinfo;
|
||||
LinkInfo link_info(klass, name, signature, KlassHandle(), /*check_access*/false);
|
||||
LinkInfo link_info(klass, name, signature);
|
||||
LinkResolver::resolve_static_call(callinfo, link_info, true, CHECK);
|
||||
methodHandle method = callinfo.selected_method();
|
||||
assert(method.not_null(), "should have thrown exception");
|
||||
|
||||
@ -998,7 +998,7 @@ static methodHandle resolve_interface_call(instanceKlassHandle klass,
|
||||
Symbol* signature = method->signature();
|
||||
Symbol* name = method->name();
|
||||
LinkResolver::resolve_interface_call(info, receiver, recv_klass,
|
||||
LinkInfo(klass, name, signature, KlassHandle(), false),
|
||||
LinkInfo(klass, name, signature),
|
||||
true,
|
||||
CHECK_(methodHandle()));
|
||||
return info.selected_method();
|
||||
|
||||
@ -3084,49 +3084,25 @@ JRT_END
|
||||
|
||||
frame SharedRuntime::look_for_reserved_stack_annotated_method(JavaThread* thread, frame fr) {
|
||||
frame activation;
|
||||
int decode_offset = 0;
|
||||
nmethod* nm = NULL;
|
||||
frame prv_fr = fr;
|
||||
CompiledMethod* nm = NULL;
|
||||
int count = 1;
|
||||
|
||||
assert(fr.is_java_frame(), "Must start on Java frame");
|
||||
|
||||
while (!fr.is_first_frame()) {
|
||||
while (true) {
|
||||
Method* method = NULL;
|
||||
// Compiled java method case.
|
||||
if (decode_offset != 0) {
|
||||
DebugInfoReadStream stream(nm, decode_offset);
|
||||
decode_offset = stream.read_int();
|
||||
method = (Method*)nm->metadata_at(stream.read_int());
|
||||
if (fr.is_interpreted_frame()) {
|
||||
method = fr.interpreter_frame_method();
|
||||
} else {
|
||||
if (fr.is_first_java_frame()) break;
|
||||
address pc = fr.pc();
|
||||
prv_fr = fr;
|
||||
if (fr.is_interpreted_frame()) {
|
||||
method = fr.interpreter_frame_method();
|
||||
fr = fr.java_sender();
|
||||
} else {
|
||||
CodeBlob* cb = fr.cb();
|
||||
fr = fr.java_sender();
|
||||
if (cb == NULL || !cb->is_nmethod()) {
|
||||
continue;
|
||||
}
|
||||
nm = (nmethod*)cb;
|
||||
if (nm->method()->is_native()) {
|
||||
method = nm->method();
|
||||
} else {
|
||||
PcDesc* pd = nm->pc_desc_at(pc);
|
||||
assert(pd != NULL, "PcDesc must not be NULL");
|
||||
decode_offset = pd->scope_decode_offset();
|
||||
// if decode_offset is not equal to 0, it will execute the
|
||||
// "compiled java method case" at the beginning of the loop.
|
||||
continue;
|
||||
}
|
||||
CodeBlob* cb = fr.cb();
|
||||
if (cb != NULL && cb->is_compiled()) {
|
||||
nm = cb->as_compiled_method();
|
||||
method = nm->method();
|
||||
}
|
||||
}
|
||||
if (method->has_reserved_stack_access()) {
|
||||
if ((method != NULL) && method->has_reserved_stack_access()) {
|
||||
ResourceMark rm(thread);
|
||||
activation = prv_fr;
|
||||
activation = fr;
|
||||
warning("Potentially dangerous stack overflow in "
|
||||
"ReservedStackAccess annotated method %s [%d]",
|
||||
method->name_and_sig_as_C_string(), count++);
|
||||
@ -3136,6 +3112,11 @@ frame SharedRuntime::look_for_reserved_stack_annotated_method(JavaThread* thread
|
||||
event.commit();
|
||||
}
|
||||
}
|
||||
if (fr.is_first_java_frame()) {
|
||||
break;
|
||||
} else {
|
||||
fr = fr.java_sender();
|
||||
}
|
||||
}
|
||||
return activation;
|
||||
}
|
||||
|
||||
@ -73,6 +73,7 @@ public class MultiCommand extends AbstractTestBase {
|
||||
public void test() {
|
||||
Scenario.Builder builder = Scenario.getBuilder();
|
||||
builder.addFlag("-Xmixed");
|
||||
builder.addFlag("-XX:CompilerDirectivesLimit=101");
|
||||
for (CompileCommand cc : testCases) {
|
||||
cc.print();
|
||||
builder.add(cc);
|
||||
|
||||
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright 2016 Azul Systems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @test TestOnSpinWaitEnableDisable
|
||||
* @summary Test to ensure basic functioning of java.lang.Thread.onSpinWait
|
||||
* @bug 8157683
|
||||
* @run main TestOnSpinWaitEnableDisable
|
||||
* @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:DisableIntrinsic=_onSpinWait TestOnSpinWaitEnableDisable
|
||||
*/
|
||||
|
||||
public class TestOnSpinWaitEnableDisable {
|
||||
public static void main(String[] args) {
|
||||
for (int i = 0; i < 50_000; i++) {
|
||||
java.lang.Thread.onSpinWait();
|
||||
}
|
||||
}
|
||||
}
|
||||
254
hotspot/test/runtime/ConstantPool/BadMethodHandles.java
Normal file
254
hotspot/test/runtime/ConstantPool/BadMethodHandles.java
Normal file
@ -0,0 +1,254 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8087223
|
||||
* @summary Adding constantTag to keep method call consistent with it.
|
||||
* @library /testlibrary
|
||||
* @modules java.base/jdk.internal.org.objectweb.asm
|
||||
* java.base/jdk.internal.misc
|
||||
* java.management
|
||||
* @compile -XDignore.symbol.file BadMethodHandles.java
|
||||
* @run main/othervm BadMethodHandles
|
||||
*/
|
||||
|
||||
import jdk.internal.org.objectweb.asm.*;
|
||||
import java.io.FileOutputStream;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.*;
|
||||
|
||||
public class BadMethodHandles {
|
||||
|
||||
static byte[] dumpBadInterfaceMethodref() {
|
||||
ClassWriter cw = new ClassWriter(0);
|
||||
cw.visit(52, ACC_PUBLIC | ACC_SUPER, "BadInterfaceMethodref", null, "java/lang/Object", null);
|
||||
Handle handle1 =
|
||||
new Handle(Opcodes.H_INVOKEINTERFACE, "BadInterfaceMethodref", "m", "()V");
|
||||
Handle handle2 =
|
||||
new Handle(Opcodes.H_INVOKEINTERFACE, "BadInterfaceMethodref", "staticM", "()V");
|
||||
|
||||
{
|
||||
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
|
||||
mv.visitCode();
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
|
||||
mv.visitInsn(RETURN);
|
||||
mv.visitMaxs(1, 1);
|
||||
mv.visitEnd();
|
||||
}
|
||||
{
|
||||
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "m", "()V", null, null);
|
||||
mv.visitCode();
|
||||
mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
|
||||
mv.visitLdcInsn("hello from m");
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false/*intf*/);
|
||||
mv.visitInsn(RETURN);
|
||||
mv.visitMaxs(3, 1);
|
||||
mv.visitEnd();
|
||||
}
|
||||
{
|
||||
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "staticM", "()V", null, null);
|
||||
mv.visitCode();
|
||||
mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
|
||||
mv.visitLdcInsn("hello from staticM");
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false/*intf*/);
|
||||
mv.visitInsn(RETURN);
|
||||
mv.visitMaxs(3, 1);
|
||||
mv.visitEnd();
|
||||
}
|
||||
|
||||
{
|
||||
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "runm", "()V", null, null);
|
||||
mv.visitCode();
|
||||
// REF_invokeStatic
|
||||
mv.visitLdcInsn(handle1);
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandle", "invoke", "()V", false);
|
||||
mv.visitInsn(RETURN);
|
||||
mv.visitMaxs(1, 1);
|
||||
mv.visitEnd();
|
||||
}
|
||||
|
||||
{
|
||||
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "runStaticM", "()V", null, null);
|
||||
mv.visitCode();
|
||||
// REF_invokeStatic
|
||||
mv.visitLdcInsn(handle2);
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandle", "invoke", "()V", false);
|
||||
mv.visitInsn(RETURN);
|
||||
mv.visitMaxs(1, 1);
|
||||
mv.visitEnd();
|
||||
}
|
||||
|
||||
cw.visitEnd();
|
||||
return cw.toByteArray();
|
||||
}
|
||||
|
||||
static byte[] dumpIBad() {
|
||||
ClassWriter cw = new ClassWriter(0);
|
||||
cw.visit(52, ACC_PUBLIC | ACC_ABSTRACT | ACC_INTERFACE, "IBad", null, "java/lang/Object", null);
|
||||
{
|
||||
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "m", "()V", null, null);
|
||||
mv.visitCode();
|
||||
mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
|
||||
mv.visitLdcInsn("hello from m");
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false/*intf*/);
|
||||
mv.visitInsn(RETURN);
|
||||
mv.visitMaxs(3, 1);
|
||||
mv.visitEnd();
|
||||
}
|
||||
{
|
||||
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "staticM", "()V", null, null);
|
||||
mv.visitCode();
|
||||
mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
|
||||
mv.visitLdcInsn("hello from staticM");
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false/*intf*/);
|
||||
mv.visitInsn(RETURN);
|
||||
mv.visitMaxs(3, 1);
|
||||
mv.visitEnd();
|
||||
}
|
||||
cw.visitEnd();
|
||||
return cw.toByteArray();
|
||||
}
|
||||
|
||||
static byte[] dumpBadMethodref() {
|
||||
ClassWriter cw = new ClassWriter(0);
|
||||
cw.visit(52, ACC_PUBLIC | ACC_SUPER, "BadMethodref", null, "java/lang/Object", new String[]{"IBad"});
|
||||
Handle handle1 =
|
||||
new Handle(Opcodes.H_INVOKEINTERFACE, "BadMethodref", "m", "()V");
|
||||
Handle handle2 =
|
||||
new Handle(Opcodes.H_INVOKEINTERFACE, "BadMethodref", "staticM", "()V");
|
||||
|
||||
{
|
||||
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
|
||||
mv.visitCode();
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
|
||||
mv.visitInsn(RETURN);
|
||||
mv.visitMaxs(1, 1);
|
||||
mv.visitEnd();
|
||||
}
|
||||
|
||||
{
|
||||
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "runm", "()V", null, null);
|
||||
mv.visitCode();
|
||||
// REF_invokeStatic
|
||||
mv.visitLdcInsn(handle1);
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandle", "invoke", "()V", false);
|
||||
mv.visitInsn(RETURN);
|
||||
mv.visitMaxs(1, 1);
|
||||
mv.visitEnd();
|
||||
}
|
||||
|
||||
{
|
||||
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "runStaticM", "()V", null, null);
|
||||
mv.visitCode();
|
||||
// REF_invokeStatic
|
||||
mv.visitLdcInsn(handle2);
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandle", "invoke", "()V", false);
|
||||
mv.visitInsn(RETURN);
|
||||
mv.visitMaxs(1, 1);
|
||||
mv.visitEnd();
|
||||
}
|
||||
|
||||
cw.visitEnd();
|
||||
return cw.toByteArray();
|
||||
}
|
||||
static class CL extends ClassLoader {
|
||||
@Override
|
||||
protected Class<?> findClass(String name) throws ClassNotFoundException {
|
||||
byte[] classBytes = null;
|
||||
switch (name) {
|
||||
case "BadInterfaceMethodref": classBytes = dumpBadInterfaceMethodref(); break;
|
||||
case "BadMethodref" : classBytes = dumpBadMethodref(); break;
|
||||
case "IBad" : classBytes = dumpIBad(); break;
|
||||
default : throw new ClassNotFoundException(name);
|
||||
}
|
||||
return defineClass(name, classBytes, 0, classBytes.length);
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Throwable {
|
||||
try (FileOutputStream fos = new FileOutputStream("BadInterfaceMethodref.class")) {
|
||||
fos.write(dumpBadInterfaceMethodref());
|
||||
}
|
||||
try (FileOutputStream fos = new FileOutputStream("IBad.class")) {
|
||||
fos.write(dumpIBad());
|
||||
}
|
||||
try (FileOutputStream fos = new FileOutputStream("BadMethodref.class")) {
|
||||
fos.write(dumpBadMethodref());
|
||||
}
|
||||
|
||||
Class<?> cls = (new CL()).loadClass("BadInterfaceMethodref");
|
||||
String[] methods = {"runm", "runStaticM"};
|
||||
System.out.println("Test BadInterfaceMethodref:");
|
||||
int success = 0;
|
||||
for (String name : methods) {
|
||||
try {
|
||||
System.out.printf("invoke %s: \n", name);
|
||||
cls.getMethod(name).invoke(cls.newInstance());
|
||||
System.out.println("FAILED - ICCE should be thrown");
|
||||
} catch (Throwable e) {
|
||||
if (e instanceof InvocationTargetException && e.getCause() != null &&
|
||||
e.getCause() instanceof IncompatibleClassChangeError) {
|
||||
System.out.println("PASSED - expected ICCE thrown");
|
||||
success++;
|
||||
continue;
|
||||
} else {
|
||||
System.out.println("FAILED with wrong exception" + e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (success != methods.length) {
|
||||
throw new Exception("BadInterfaceMethodRef Failed to catch IncompatibleClassChangeError");
|
||||
}
|
||||
System.out.println("Test BadMethodref:");
|
||||
cls = (new CL()).loadClass("BadMethodref");
|
||||
success = 0;
|
||||
for (String name : methods) {
|
||||
try {
|
||||
System.out.printf("invoke %s: \n", name);
|
||||
cls.getMethod(name).invoke(cls.newInstance());
|
||||
System.out.println("FAILED - ICCE should be thrown");
|
||||
} catch (Throwable e) {
|
||||
if (e instanceof InvocationTargetException && e.getCause() != null &&
|
||||
e.getCause() instanceof IncompatibleClassChangeError) {
|
||||
System.out.println("PASSED - expected ICCE thrown");
|
||||
success++;
|
||||
continue;
|
||||
} else {
|
||||
System.out.println("FAILED with wrong exception" + e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (success != methods.length) {
|
||||
throw new Exception("BadMethodRef Failed to catch IncompatibleClassChangeError");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
160
hotspot/test/runtime/ConstantPool/IntfMethod.java
Normal file
160
hotspot/test/runtime/ConstantPool/IntfMethod.java
Normal file
@ -0,0 +1,160 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* $bug 8087223
|
||||
* @summary Adding constantTag to keep method call consistent with it.
|
||||
* @library /testlibrary
|
||||
* @modules java.base/jdk.internal.org.objectweb.asm
|
||||
* java.base/jdk.internal.misc
|
||||
* java.management
|
||||
* @compile -XDignore.symbol.file IntfMethod.java
|
||||
* @run main/othervm IntfMethod
|
||||
* @run main/othervm -Xint IntfMethod
|
||||
* @run main/othervm -Xcomp IntfMethod
|
||||
*/
|
||||
|
||||
|
||||
import jdk.internal.org.objectweb.asm.*;
|
||||
import java.io.FileOutputStream;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.*;
|
||||
|
||||
public class IntfMethod {
|
||||
static byte[] dumpC() {
|
||||
ClassWriter cw = new ClassWriter(0);
|
||||
cw.visit(52, ACC_PUBLIC | ACC_SUPER, "C", null, "java/lang/Object", new String[]{"I"});
|
||||
{
|
||||
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
|
||||
mv.visitCode();
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
|
||||
mv.visitInsn(RETURN);
|
||||
mv.visitMaxs(1, 1);
|
||||
mv.visitEnd();
|
||||
}
|
||||
{
|
||||
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "testSpecialIntf", "()V", null, null);
|
||||
mv.visitCode();
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitMethodInsn(INVOKESPECIAL, "I", "f1", "()V", /*itf=*/false);
|
||||
mv.visitInsn(RETURN);
|
||||
mv.visitMaxs(1, 1);
|
||||
mv.visitEnd();
|
||||
}
|
||||
{
|
||||
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "testStaticIntf", "()V", null, null);
|
||||
mv.visitCode();
|
||||
mv.visitMethodInsn(INVOKESTATIC, "I", "f2", "()V", /*itf=*/false);
|
||||
mv.visitInsn(RETURN);
|
||||
mv.visitMaxs(1, 1);
|
||||
mv.visitEnd();
|
||||
}
|
||||
{
|
||||
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "testSpecialClass", "()V", null, null);
|
||||
mv.visitCode();
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitMethodInsn(INVOKESPECIAL, "C", "f1", "()V", /*itf=*/true);
|
||||
mv.visitInsn(RETURN);
|
||||
mv.visitMaxs(1, 1);
|
||||
mv.visitEnd();
|
||||
}
|
||||
|
||||
{
|
||||
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "f2", "()V", null, null);
|
||||
mv.visitCode();
|
||||
mv.visitInsn(RETURN);
|
||||
mv.visitMaxs(0, 1);
|
||||
mv.visitEnd();
|
||||
}
|
||||
{
|
||||
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "testStaticClass", "()V", null, null);
|
||||
mv.visitCode();
|
||||
mv.visitMethodInsn(INVOKESTATIC, "C", "f2", "()V", /*itf=*/true);
|
||||
mv.visitInsn(RETURN);
|
||||
mv.visitMaxs(1, 1);
|
||||
mv.visitEnd();
|
||||
}
|
||||
cw.visitEnd();
|
||||
return cw.toByteArray();
|
||||
}
|
||||
|
||||
static byte[] dumpI() {
|
||||
ClassWriter cw = new ClassWriter(0);
|
||||
cw.visit(52, ACC_PUBLIC | ACC_ABSTRACT | ACC_INTERFACE, "I", null, "java/lang/Object", null);
|
||||
{
|
||||
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "f1", "()V", null, null);
|
||||
mv.visitCode();
|
||||
mv.visitInsn(RETURN);
|
||||
mv.visitMaxs(0, 1);
|
||||
mv.visitEnd();
|
||||
}
|
||||
{
|
||||
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "f2", "()V", null, null);
|
||||
mv.visitCode();
|
||||
mv.visitInsn(RETURN);
|
||||
mv.visitMaxs(0, 1);
|
||||
mv.visitEnd();
|
||||
}
|
||||
cw.visitEnd();
|
||||
return cw.toByteArray();
|
||||
}
|
||||
|
||||
static class CL extends ClassLoader {
|
||||
@Override
|
||||
protected Class<?> findClass(String name) throws ClassNotFoundException {
|
||||
byte[] classFile;
|
||||
switch (name) {
|
||||
case "I": classFile = dumpI(); break;
|
||||
case "C": classFile = dumpC(); break;
|
||||
default:
|
||||
throw new ClassNotFoundException(name);
|
||||
}
|
||||
return defineClass(name, classFile, 0, classFile.length);
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Throwable {
|
||||
Class<?> cls = (new CL()).loadClass("C");
|
||||
try (FileOutputStream fos = new FileOutputStream("I.class")) { fos.write(dumpI()); }
|
||||
try (FileOutputStream fos = new FileOutputStream("C.class")) { fos.write(dumpC()); }
|
||||
|
||||
int success = 0;
|
||||
for (String name : new String[] { "testSpecialIntf", "testStaticIntf", "testSpecialClass", "testStaticClass"}) {
|
||||
System.out.printf("%s: ", name);
|
||||
try {
|
||||
cls.getMethod(name).invoke(cls.newInstance());
|
||||
System.out.println("FAILED - ICCE not thrown");
|
||||
} catch (Throwable e) {
|
||||
if (e instanceof InvocationTargetException &&
|
||||
e.getCause() != null && e.getCause() instanceof IncompatibleClassChangeError) {
|
||||
System.out.println("PASSED - expected ICCE thrown");
|
||||
success++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (success != 4) throw new Exception("Failed to catch ICCE");
|
||||
}
|
||||
}
|
||||
@ -72,6 +72,6 @@ class Clazz extends ClassConstruct {
|
||||
public Clazz(String name, String extending, int access, int classFileVersion, int index, String... implementing) {
|
||||
super(name, extending == null ? "java/lang/Object" : extending, access + ACC_SUPER, classFileVersion, index, implementing);
|
||||
// Add the default constructor
|
||||
addMethod("<init>", "()V", ACC_PUBLIC).makeConstructor(extending);
|
||||
addMethod("<init>", "()V", ACC_PUBLIC).makeConstructor(extending, false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -59,14 +59,12 @@ class Method {
|
||||
private final String ownerClassName;
|
||||
private final ClassVisitor cv;
|
||||
private final MethodVisitor mv;
|
||||
private final boolean isInterface;
|
||||
private final ClassBuilder.ExecutionMode execMode;
|
||||
|
||||
public Method(ClassConstruct ownerClass, ClassVisitor cv, String name, String descriptor, int access,
|
||||
ClassBuilder.ExecutionMode execMode) {
|
||||
this.ownerClassName = ownerClass.getName();
|
||||
this.ownerClass = ownerClass;
|
||||
this.isInterface = ownerClass.isInterface();
|
||||
this.execMode = execMode;
|
||||
this.cv = cv;
|
||||
mv = cv.visitMethod(access, name, descriptor, null, null);
|
||||
@ -91,12 +89,12 @@ class Method {
|
||||
|
||||
public void makeSuperCallMethod(int invokeInstruction, String className) {
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
makeCall(invokeInstruction, className);
|
||||
makeCall(invokeInstruction, className, false);
|
||||
mv.visitInsn(POP);
|
||||
done();
|
||||
}
|
||||
|
||||
public void defaultInvoke(int instr, String className, String objectRef) {
|
||||
public void defaultInvoke(int instr, String className, String objectRef, boolean isInterface) {
|
||||
switch (instr) {
|
||||
case INVOKEVIRTUAL:
|
||||
defaultInvokeVirtual(className, objectRef);
|
||||
@ -105,10 +103,10 @@ class Method {
|
||||
defaultInvokeInterface(className, objectRef);
|
||||
break;
|
||||
case INVOKESTATIC:
|
||||
defaultInvokeStatic(className);
|
||||
defaultInvokeStatic(className, isInterface);
|
||||
break;
|
||||
case INVOKESPECIAL:
|
||||
defaultInvokeSpecial(className, objectRef);
|
||||
defaultInvokeSpecial(className, objectRef, isInterface);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@ -118,30 +116,26 @@ class Method {
|
||||
mv.visitEnd();
|
||||
}
|
||||
|
||||
public void defaultInvokeVirtual(String className, String objectRef) {
|
||||
private void defaultInvokeVirtual(String className, String objectRef) {
|
||||
String objectRefPackageName = objectRef.substring(0, objectRef.lastIndexOf("/"));
|
||||
makeNewObject(objectRef, objectRefPackageName);
|
||||
makeCall(INVOKEVIRTUAL, className, false);
|
||||
}
|
||||
|
||||
public void defaultInvokeInterface(String className, String objectRef) {
|
||||
private void defaultInvokeInterface(String className, String objectRef) {
|
||||
String objectRefPackageName = objectRef.substring(0, objectRef.lastIndexOf("/"));
|
||||
makeNewObject(objectRef, objectRefPackageName);
|
||||
makeCall(INVOKEINTERFACE, className, true);
|
||||
}
|
||||
|
||||
public void defaultInvokeSpecial(String className, String objectRef) {
|
||||
private void defaultInvokeSpecial(String className, String objectRef, boolean isInterface) {
|
||||
String objectRefPackageName = objectRef.substring(0, objectRef.lastIndexOf("/"));
|
||||
makeNewObject(objectRef, objectRefPackageName);
|
||||
makeCall(INVOKESPECIAL, className, false);
|
||||
makeCall(INVOKESPECIAL, className, isInterface);
|
||||
}
|
||||
|
||||
public void defaultInvokeStatic(String className) {
|
||||
makeCall(INVOKESTATIC, className);
|
||||
}
|
||||
|
||||
private Method makeCall(int invokeInstruction, String className) {
|
||||
return makeCall(invokeInstruction, className, isInterface);
|
||||
private void defaultInvokeStatic(String className, boolean isInterface) {
|
||||
makeCall(INVOKESTATIC, className, isInterface);
|
||||
}
|
||||
|
||||
private Method makeCall(int invokeInstruction, String className, boolean isInterface) {
|
||||
@ -219,7 +213,7 @@ class Method {
|
||||
String className = objectRef.substring(objectRef.lastIndexOf("/") + 1);
|
||||
makeStaticCall( objectRefPackageName + "/Helper",
|
||||
"get" + className,
|
||||
"()L" + objectRef + ";");
|
||||
"()L" + objectRef + ";", false);
|
||||
mv.visitVarInsn(ASTORE, 1);
|
||||
mv.visitVarInsn(ALOAD, 1);
|
||||
}
|
||||
@ -236,12 +230,12 @@ class Method {
|
||||
mv.visitEnd();
|
||||
}
|
||||
|
||||
public Method makeStaticCall(String classname, String method, String descriptor) {
|
||||
public Method makeStaticCall(String classname, String method, String descriptor, boolean isInterface) {
|
||||
mv.visitMethodInsn(INVOKESTATIC, classname, method, descriptor, isInterface);
|
||||
return this;
|
||||
}
|
||||
|
||||
public void makeConstructor(String extending) {
|
||||
public void makeConstructor(String extending, boolean isInterface) {
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitMethodInsn(INVOKESPECIAL, extending == null ? "java/lang/Object" : extending, "<init>", "()V", isInterface);
|
||||
mv.visitInsn(RETURN);
|
||||
|
||||
@ -53,9 +53,10 @@ class TestBuilder extends Builder {
|
||||
Method m = clazz.addMethod("test", "()Ljava/lang/Integer;", ACC_PUBLIC + ACC_STATIC, execMode);
|
||||
m.defaultInvoke(getInvokeInstruction(testcase.invoke),
|
||||
getName(testcase.methodref),
|
||||
getName(testcase.objectref));
|
||||
getName(testcase.objectref),
|
||||
testcase.hier.isInterface(testcase.methodref));
|
||||
|
||||
mainMethod.makeStaticCall(clazz.getName(), "test", "()Ljava/lang/Integer;").done();
|
||||
mainMethod.makeStaticCall(clazz.getName(), "test", "()Ljava/lang/Integer;", false).done();
|
||||
}
|
||||
|
||||
private static int getInvokeInstruction(SelectionResolutionTestCase.InvokeInstruction instr) {
|
||||
|
||||
@ -33,6 +33,7 @@ import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Arrays;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@ -52,14 +53,16 @@ public class JitTesterDriver {
|
||||
throw new Error("Unexpected exception on test jvm start :" + e, e);
|
||||
}
|
||||
|
||||
Pattern splitOut = Pattern.compile("\\n"); // tests use \n only in stdout
|
||||
Pattern splitErr = Pattern.compile("\\r?\\n"); // can handle both \r\n and \n
|
||||
Path testDir = Paths.get(Utils.TEST_SRC);
|
||||
String goldOut = formatOutput(streamGoldFile(testDir, args[0], "out"), s -> true);
|
||||
Asserts.assertEQ(oa.getStdout(), goldOut, "Actual stdout isn't equal to golden one");
|
||||
|
||||
String anlzOut = formatOutput(Arrays.stream(splitOut.split(oa.getStdout())), s -> true);
|
||||
Asserts.assertEQ(anlzOut, goldOut, "Actual stdout isn't equal to golden one");
|
||||
// TODO: add a comment why we skip such lines
|
||||
Predicate<String> notStartWhitespaces = s -> !(s.startsWith("\t") || s.startsWith(" "));
|
||||
String goldErr = formatOutput(streamGoldFile(testDir, args[0], "err"), notStartWhitespaces);
|
||||
String anlzErr = formatOutput(Arrays.stream(oa.getStderr().split(Utils.NEW_LINE)),
|
||||
String anlzErr = formatOutput(Arrays.stream(splitErr.split(oa.getStderr())),
|
||||
notStartWhitespaces);
|
||||
Asserts.assertEQ(anlzErr, goldErr, "Actual stderr isn't equal to golden one");
|
||||
|
||||
|
||||
@ -37,7 +37,6 @@ import jdk.test.lib.jittester.Nothing;
|
||||
import jdk.test.lib.jittester.Operator;
|
||||
import jdk.test.lib.jittester.OperatorKind;
|
||||
import jdk.test.lib.jittester.PrintVariables;
|
||||
import jdk.test.lib.jittester.ProductionFailedException;
|
||||
import jdk.test.lib.jittester.Statement;
|
||||
import jdk.test.lib.jittester.StaticMemberVariable;
|
||||
import jdk.test.lib.jittester.Symbol;
|
||||
@ -171,22 +170,22 @@ public class FixedTrees {
|
||||
TryCatchBlock tryCatch1 = new TryCatchBlock(tryNode, nothing, catchBlocks1, 3);
|
||||
TypeKlass printStreamKlass = new TypeKlass("java.io.PrintStream");
|
||||
TypeKlass systemKlass = new TypeKlass("java.lang.System");
|
||||
FunctionInfo systemOutPrintlnInfo = new FunctionInfo("println", printStreamKlass,
|
||||
FunctionInfo systemOutPrintInfo = new FunctionInfo("print", printStreamKlass,
|
||||
TypeList.VOID, 0, FunctionInfo.PUBLIC,
|
||||
new VariableInfo("this", owner, printStreamKlass, VariableInfo.LOCAL | VariableInfo.INITIALIZED),
|
||||
new VariableInfo("t", owner, TypeList.OBJECT,
|
||||
VariableInfo.LOCAL | VariableInfo.INITIALIZED));
|
||||
List<IRNode> printlnArgs = new ArrayList<>();
|
||||
List<IRNode> printArgs = new ArrayList<>();
|
||||
VariableInfo systemOutInfo = new VariableInfo("out", systemKlass, printStreamKlass,
|
||||
VariableInfo.STATIC | VariableInfo.PUBLIC);
|
||||
StaticMemberVariable systemOutVar = new StaticMemberVariable(owner, systemOutInfo);
|
||||
printlnArgs.add(systemOutVar);
|
||||
printlnArgs.add(tVar);
|
||||
Function println = new Function(printStreamKlass, systemOutPrintlnInfo, printlnArgs);
|
||||
ArrayList<IRNode> printlnBlockContent = new ArrayList<>();
|
||||
printlnBlockContent.add(new Statement(println, true));
|
||||
Block printlnBlock = new Block(owner, TypeList.VOID, printlnBlockContent, 3);
|
||||
TryCatchBlock tryCatch2 = new TryCatchBlock(printlnBlock, nothing, catchBlocks2, 3);
|
||||
printArgs.add(systemOutVar);
|
||||
printArgs.add(tVar);
|
||||
Function print = new Function(printStreamKlass, systemOutPrintInfo, printArgs);
|
||||
ArrayList<IRNode> printBlockContent = new ArrayList<>();
|
||||
printBlockContent.add(new Statement(print, true));
|
||||
Block printBlock = new Block(owner, TypeList.VOID, printBlockContent, 3);
|
||||
TryCatchBlock tryCatch2 = new TryCatchBlock(printBlock, nothing, catchBlocks2, 3);
|
||||
|
||||
List<IRNode> mainTryCatchBlockContent = new ArrayList<>();
|
||||
mainTryCatchBlockContent.add(new Statement(testInit, true));
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user