mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-27 23:04:50 +02:00
8132051: Better byte behavior
Co-authored-by: Roland Westerlin <roland.westerlin@oracle.com> Co-authored-by: Vladimir Kozlov <vladimir.kozlov@oracle.com> Co-authored-by: John Rose <john.r.rose@oracle.com> Reviewed-by: bdelsart, roland, kvn, jrose, ahgross
This commit is contained in:
parent
ed18f94d21
commit
200784d505
40 changed files with 514 additions and 88 deletions
|
@ -344,7 +344,7 @@ void LIRGenerator::do_StoreIndexed(StoreIndexed* x) {
|
|||
length.set_instruction(x->length());
|
||||
length.load_item();
|
||||
}
|
||||
if (needs_store_check) {
|
||||
if (needs_store_check || x->check_boolean()) {
|
||||
value.load_item();
|
||||
} else {
|
||||
value.load_for_store(x->elt_type());
|
||||
|
@ -389,7 +389,8 @@ void LIRGenerator::do_StoreIndexed(StoreIndexed* x) {
|
|||
pre_barrier(LIR_OprFact::address(array_addr), LIR_OprFact::illegalOpr /* pre_val */,
|
||||
true /* do_load */, false /* patch */, NULL);
|
||||
}
|
||||
__ move(value.result(), array_addr, null_check_info);
|
||||
LIR_Opr result = maybe_mask_boolean(x, array.result(), value.result(), null_check_info);
|
||||
__ move(result, array_addr, null_check_info);
|
||||
if (obj_store) {
|
||||
// Precise card mark
|
||||
post_barrier(LIR_OprFact::address(array_addr), value.result());
|
||||
|
|
|
@ -208,6 +208,7 @@ void InterpreterMacroAssembler::load_earlyret_value(TosState state) {
|
|||
case atos: ld_ptr(oop_addr, Otos_l);
|
||||
st_ptr(G0, oop_addr); break;
|
||||
case btos: // fall through
|
||||
case ztos: // fall through
|
||||
case ctos: // fall through
|
||||
case stos: // fall through
|
||||
case itos: ld(val_addr, Otos_l1); break;
|
||||
|
@ -452,9 +453,10 @@ void InterpreterMacroAssembler::push(TosState state) {
|
|||
interp_verify_oop(Otos_i, state, __FILE__, __LINE__);
|
||||
switch (state) {
|
||||
case atos: push_ptr(); break;
|
||||
case btos: push_i(); break;
|
||||
case ctos:
|
||||
case stos: push_i(); break;
|
||||
case btos: // fall through
|
||||
case ztos: // fall through
|
||||
case ctos: // fall through
|
||||
case stos: // fall through
|
||||
case itos: push_i(); break;
|
||||
case ltos: push_l(); break;
|
||||
case ftos: push_f(); break;
|
||||
|
@ -468,9 +470,10 @@ void InterpreterMacroAssembler::push(TosState state) {
|
|||
void InterpreterMacroAssembler::pop(TosState state) {
|
||||
switch (state) {
|
||||
case atos: pop_ptr(); break;
|
||||
case btos: pop_i(); break;
|
||||
case ctos:
|
||||
case stos: pop_i(); break;
|
||||
case btos: // fall through
|
||||
case ztos: // fall through
|
||||
case ctos: // fall through
|
||||
case stos: // fall through
|
||||
case itos: pop_i(); break;
|
||||
case ltos: pop_l(); break;
|
||||
case ftos: pop_f(); break;
|
||||
|
@ -1103,6 +1106,49 @@ void InterpreterMacroAssembler::unlock_if_synchronized_method(TosState state,
|
|||
interp_verify_oop(Otos_i, state, __FILE__, __LINE__);
|
||||
}
|
||||
|
||||
void InterpreterMacroAssembler::narrow(Register result) {
|
||||
|
||||
ld_ptr(Address(Lmethod, Method::const_offset()), G3_scratch);
|
||||
ldub(G3_scratch, in_bytes(ConstMethod::result_type_offset()), G3_scratch);
|
||||
|
||||
Label notBool, notByte, notChar, done;
|
||||
|
||||
// common case first
|
||||
cmp(G3_scratch, T_INT);
|
||||
br(Assembler::equal, true, pn, done);
|
||||
delayed()->nop();
|
||||
|
||||
cmp(G3_scratch, T_BOOLEAN);
|
||||
br(Assembler::notEqual, true, pn, notBool);
|
||||
delayed()->cmp(G3_scratch, T_BYTE);
|
||||
and3(result, 1, result);
|
||||
ba(done);
|
||||
delayed()->nop();
|
||||
|
||||
bind(notBool);
|
||||
// cmp(G3_scratch, T_BYTE);
|
||||
br(Assembler::notEqual, true, pn, notByte);
|
||||
delayed()->cmp(G3_scratch, T_CHAR);
|
||||
sll(result, 24, result);
|
||||
sra(result, 24, result);
|
||||
ba(done);
|
||||
delayed()->nop();
|
||||
|
||||
bind(notByte);
|
||||
// cmp(G3_scratch, T_CHAR);
|
||||
sll(result, 16, result);
|
||||
br(Assembler::notEqual, true, pn, done);
|
||||
delayed()->sra(result, 16, result);
|
||||
// sll(result, 16, result);
|
||||
srl(result, 16, result);
|
||||
|
||||
// bind(notChar);
|
||||
// must be short, instructions already executed in delay slot
|
||||
// sll(result, 16, result);
|
||||
// sra(result, 16, result);
|
||||
|
||||
bind(done);
|
||||
}
|
||||
|
||||
// remove activation
|
||||
//
|
||||
|
@ -1151,6 +1197,7 @@ void InterpreterMacroAssembler::remove_activation(TosState state,
|
|||
case ltos: mov(Otos_l2, Otos_l2->after_save()); // fall through // O1 -> I1
|
||||
#endif
|
||||
case btos: // fall through
|
||||
case ztos: // fall through
|
||||
case ctos:
|
||||
case stos: // fall through
|
||||
case atos: // fall through
|
||||
|
|
|
@ -103,6 +103,8 @@ class InterpreterMacroAssembler: public MacroAssembler {
|
|||
void dispatch_via (TosState state, address* table);
|
||||
|
||||
|
||||
void narrow(Register result);
|
||||
|
||||
// Removes the current activation (incl. unlocking of monitors).
|
||||
// Additionally this code is used for earlyReturn in which case we
|
||||
// want to skip throwing an exception and installing an exception.
|
||||
|
|
|
@ -165,6 +165,7 @@ void TemplateTable::patch_bytecode(Bytecodes::Code bc, Register bc_reg,
|
|||
switch (bc) {
|
||||
case Bytecodes::_fast_aputfield:
|
||||
case Bytecodes::_fast_bputfield:
|
||||
case Bytecodes::_fast_zputfield:
|
||||
case Bytecodes::_fast_cputfield:
|
||||
case Bytecodes::_fast_dputfield:
|
||||
case Bytecodes::_fast_fputfield:
|
||||
|
@ -922,8 +923,20 @@ void TemplateTable::bastore() {
|
|||
transition(itos, vtos);
|
||||
__ pop_i(O2); // index
|
||||
// Otos_i: val
|
||||
// O2: index
|
||||
// O3: array
|
||||
__ index_check(O3, O2, 0, G3_scratch, O2);
|
||||
// Need to check whether array is boolean or byte
|
||||
// since both types share the bastore bytecode.
|
||||
__ load_klass(O3, G4_scratch);
|
||||
__ ld(G4_scratch, in_bytes(Klass::layout_helper_offset()), G4_scratch);
|
||||
__ set(Klass::layout_helper_boolean_diffbit(), G3_scratch);
|
||||
__ andcc(G3_scratch, G4_scratch, G0);
|
||||
Label L_skip;
|
||||
__ br(Assembler::zero, false, Assembler::pn, L_skip);
|
||||
__ delayed()->nop();
|
||||
__ and3(Otos_i, 1, Otos_i); // if it is a T_BOOLEAN array, mask the stored value to 0/1
|
||||
__ bind(L_skip);
|
||||
__ stb(Otos_i, O2, arrayOopDesc::base_offset_in_bytes(T_BYTE));
|
||||
}
|
||||
|
||||
|
@ -2008,6 +2021,12 @@ void TemplateTable::_return(TosState state) {
|
|||
__ bind(skip_register_finalizer);
|
||||
}
|
||||
|
||||
// Narrow result if state is itos but result type is smaller.
|
||||
// Need to narrow in the return bytecode rather than in generate_return_entry
|
||||
// since compiled code callers expect the result to already be narrowed.
|
||||
if (state == itos) {
|
||||
__ narrow(Otos_i);
|
||||
}
|
||||
__ remove_activation(state, /* throw_monitor_exception */ true);
|
||||
|
||||
// The caller's SP was adjusted upon method entry to accomodate
|
||||
|
@ -2218,7 +2237,7 @@ void TemplateTable::getfield_or_static(int byte_no, bool is_static, RewriteContr
|
|||
Label checkVolatile;
|
||||
|
||||
// compute field type
|
||||
Label notByte, notInt, notShort, notChar, notLong, notFloat, notObj;
|
||||
Label notByte, notBool, notInt, notShort, notChar, notLong, notFloat, notObj;
|
||||
__ srl(Rflags, ConstantPoolCacheEntry::tos_state_shift, Rflags);
|
||||
// Make sure we don't need to mask Rflags after the above shift
|
||||
ConstantPoolCacheEntry::verify_tos_state_shift();
|
||||
|
@ -2273,7 +2292,7 @@ void TemplateTable::getfield_or_static(int byte_no, bool is_static, RewriteContr
|
|||
|
||||
// cmp(Rflags, btos);
|
||||
__ br(Assembler::notEqual, false, Assembler::pt, notByte);
|
||||
__ delayed() ->cmp(Rflags, ctos);
|
||||
__ delayed() ->cmp(Rflags, ztos);
|
||||
|
||||
// btos
|
||||
__ ldsb(Rclass, Roffset, Otos_i);
|
||||
|
@ -2286,6 +2305,22 @@ void TemplateTable::getfield_or_static(int byte_no, bool is_static, RewriteContr
|
|||
|
||||
__ bind(notByte);
|
||||
|
||||
// cmp(Rflags, ztos);
|
||||
__ br(Assembler::notEqual, false, Assembler::pt, notBool);
|
||||
__ delayed() ->cmp(Rflags, ctos);
|
||||
|
||||
// ztos
|
||||
__ ldsb(Rclass, Roffset, Otos_i);
|
||||
__ push(itos);
|
||||
if (!is_static && rc == may_rewrite) {
|
||||
// use btos rewriting, no truncating to t/f bit is needed for getfield.
|
||||
patch_bytecode(Bytecodes::_fast_bgetfield, G3_scratch, G4_scratch);
|
||||
}
|
||||
__ ba(checkVolatile);
|
||||
__ delayed()->tst(Lscratch);
|
||||
|
||||
__ bind(notBool);
|
||||
|
||||
// cmp(Rflags, ctos);
|
||||
__ br(Assembler::notEqual, false, Assembler::pt, notChar);
|
||||
__ delayed() ->cmp(Rflags, stos);
|
||||
|
@ -2449,6 +2484,7 @@ void TemplateTable::jvmti_post_fast_field_mod() {
|
|||
switch (bytecode()) { // save tos values before call_VM() clobbers them
|
||||
case Bytecodes::_fast_aputfield: __ push_ptr(Otos_i); break;
|
||||
case Bytecodes::_fast_bputfield: // fall through
|
||||
case Bytecodes::_fast_zputfield: // fall through
|
||||
case Bytecodes::_fast_sputfield: // fall through
|
||||
case Bytecodes::_fast_cputfield: // fall through
|
||||
case Bytecodes::_fast_iputfield: __ push_i(Otos_i); break;
|
||||
|
@ -2466,6 +2502,7 @@ void TemplateTable::jvmti_post_fast_field_mod() {
|
|||
switch (bytecode()) { // restore tos values
|
||||
case Bytecodes::_fast_aputfield: __ pop_ptr(Otos_i); break;
|
||||
case Bytecodes::_fast_bputfield: // fall through
|
||||
case Bytecodes::_fast_zputfield: // fall through
|
||||
case Bytecodes::_fast_sputfield: // fall through
|
||||
case Bytecodes::_fast_cputfield: // fall through
|
||||
case Bytecodes::_fast_iputfield: __ pop_i(Otos_i); break;
|
||||
|
@ -2581,7 +2618,7 @@ void TemplateTable::putfield_or_static(int byte_no, bool is_static, RewriteContr
|
|||
ConstantPoolCacheEntry::verify_tos_state_shift();
|
||||
|
||||
// compute field type
|
||||
Label notInt, notShort, notChar, notObj, notByte, notLong, notFloat;
|
||||
Label notInt, notShort, notChar, notObj, notByte, notBool, notLong, notFloat;
|
||||
|
||||
if (is_static) {
|
||||
// putstatic with object type most likely, check that first
|
||||
|
@ -2649,7 +2686,7 @@ void TemplateTable::putfield_or_static(int byte_no, bool is_static, RewriteContr
|
|||
|
||||
// cmp(Rflags, btos);
|
||||
__ br(Assembler::notEqual, false, Assembler::pt, notByte);
|
||||
__ delayed()->cmp(Rflags, ltos);
|
||||
__ delayed()->cmp(Rflags, ztos);
|
||||
|
||||
// btos
|
||||
{
|
||||
|
@ -2664,6 +2701,25 @@ void TemplateTable::putfield_or_static(int byte_no, bool is_static, RewriteContr
|
|||
}
|
||||
|
||||
__ bind(notByte);
|
||||
|
||||
// cmp(Rflags, btos);
|
||||
__ br(Assembler::notEqual, false, Assembler::pt, notBool);
|
||||
__ delayed()->cmp(Rflags, ltos);
|
||||
|
||||
// ztos
|
||||
{
|
||||
__ pop_i();
|
||||
if (!is_static) pop_and_check_object(Rclass);
|
||||
__ and3(Otos_i, 1, Otos_i);
|
||||
__ stb(Otos_i, Rclass, Roffset);
|
||||
if (!is_static && rc == may_rewrite) {
|
||||
patch_bytecode(Bytecodes::_fast_zputfield, G3_scratch, G4_scratch, true, byte_no);
|
||||
}
|
||||
__ ba(checkVolatile);
|
||||
__ delayed()->tst(Lscratch);
|
||||
}
|
||||
|
||||
__ bind(notBool);
|
||||
// cmp(Rflags, ltos);
|
||||
__ br(Assembler::notEqual, false, Assembler::pt, notLong);
|
||||
__ delayed()->cmp(Rflags, ctos);
|
||||
|
@ -2787,6 +2843,7 @@ void TemplateTable::fast_storefield(TosState state) {
|
|||
pop_and_check_object(Rclass);
|
||||
|
||||
switch (bytecode()) {
|
||||
case Bytecodes::_fast_zputfield: __ and3(Otos_i, 1, Otos_i); // fall through to bputfield
|
||||
case Bytecodes::_fast_bputfield: __ stb(Otos_i, Rclass, Roffset); break;
|
||||
case Bytecodes::_fast_cputfield: /* fall through */
|
||||
case Bytecodes::_fast_sputfield: __ sth(Otos_i, Rclass, Roffset); break;
|
||||
|
|
|
@ -284,7 +284,7 @@ void LIRGenerator::do_StoreIndexed(StoreIndexed* x) {
|
|||
length.load_item();
|
||||
|
||||
}
|
||||
if (needs_store_check) {
|
||||
if (needs_store_check || x->check_boolean()) {
|
||||
value.load_item();
|
||||
} else {
|
||||
value.load_for_store(x->elt_type());
|
||||
|
@ -332,7 +332,8 @@ void LIRGenerator::do_StoreIndexed(StoreIndexed* x) {
|
|||
// Seems to be a precise
|
||||
post_barrier(LIR_OprFact::address(array_addr), value.result());
|
||||
} else {
|
||||
__ move(value.result(), array_addr, null_check_info);
|
||||
LIR_Opr result = maybe_mask_boolean(x, array.result(), value.result(), null_check_info);
|
||||
__ move(result, array_addr, null_check_info);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -349,6 +349,7 @@ void InterpreterMacroAssembler::load_earlyret_value(TosState state) {
|
|||
verify_oop(rax, state); break;
|
||||
case ltos: movptr(rax, val_addr); break;
|
||||
case btos: // fall through
|
||||
case ztos: // fall through
|
||||
case ctos: // fall through
|
||||
case stos: // fall through
|
||||
case itos: movl(rax, val_addr); break;
|
||||
|
@ -370,6 +371,7 @@ void InterpreterMacroAssembler::load_earlyret_value(TosState state) {
|
|||
case ltos:
|
||||
movl(rdx, val_addr1); // fall through
|
||||
case btos: // fall through
|
||||
case ztos: // fall through
|
||||
case ctos: // fall through
|
||||
case stos: // fall through
|
||||
case itos: movl(rax, val_addr); break;
|
||||
|
@ -616,6 +618,7 @@ void InterpreterMacroAssembler::pop(TosState state) {
|
|||
switch (state) {
|
||||
case atos: pop_ptr(); break;
|
||||
case btos:
|
||||
case ztos:
|
||||
case ctos:
|
||||
case stos:
|
||||
case itos: pop_i(); break;
|
||||
|
@ -633,6 +636,7 @@ void InterpreterMacroAssembler::push(TosState state) {
|
|||
switch (state) {
|
||||
case atos: push_ptr(); break;
|
||||
case btos:
|
||||
case ztos:
|
||||
case ctos:
|
||||
case stos:
|
||||
case itos: push_i(); break;
|
||||
|
@ -668,6 +672,7 @@ void InterpreterMacroAssembler::pop(TosState state) {
|
|||
switch (state) {
|
||||
case atos: pop_ptr(rax); break;
|
||||
case btos: // fall through
|
||||
case ztos: // fall through
|
||||
case ctos: // fall through
|
||||
case stos: // fall through
|
||||
case itos: pop_i(rax); break;
|
||||
|
@ -716,6 +721,7 @@ void InterpreterMacroAssembler::push(TosState state) {
|
|||
switch (state) {
|
||||
case atos: push_ptr(rax); break;
|
||||
case btos: // fall through
|
||||
case ztos: // fall through
|
||||
case ctos: // fall through
|
||||
case stos: // fall through
|
||||
case itos: push_i(rax); break;
|
||||
|
@ -849,6 +855,51 @@ void InterpreterMacroAssembler::dispatch_via(TosState state, address* table) {
|
|||
dispatch_base(state, table);
|
||||
}
|
||||
|
||||
void InterpreterMacroAssembler::narrow(Register result) {
|
||||
|
||||
// Get method->_constMethod->_result_type
|
||||
movptr(rcx, Address(rbp, frame::interpreter_frame_method_offset * wordSize));
|
||||
movptr(rcx, Address(rcx, Method::const_offset()));
|
||||
load_unsigned_byte(rcx, Address(rcx, ConstMethod::result_type_offset()));
|
||||
|
||||
Label done, notBool, notByte, notChar;
|
||||
|
||||
// common case first
|
||||
cmpl(rcx, T_INT);
|
||||
jcc(Assembler::equal, done);
|
||||
|
||||
// mask integer result to narrower return type.
|
||||
cmpl(rcx, T_BOOLEAN);
|
||||
jcc(Assembler::notEqual, notBool);
|
||||
andl(result, 0x1);
|
||||
jmp(done);
|
||||
|
||||
bind(notBool);
|
||||
cmpl(rcx, T_BYTE);
|
||||
jcc(Assembler::notEqual, notByte);
|
||||
LP64_ONLY(movsbl(result, result);)
|
||||
NOT_LP64(shll(result, 24);) // truncate upper 24 bits
|
||||
NOT_LP64(sarl(result, 24);) // and sign-extend byte
|
||||
jmp(done);
|
||||
|
||||
bind(notByte);
|
||||
cmpl(rcx, T_CHAR);
|
||||
jcc(Assembler::notEqual, notChar);
|
||||
LP64_ONLY(movzwl(result, result);)
|
||||
NOT_LP64(andl(result, 0xFFFF);) // truncate upper 16 bits
|
||||
jmp(done);
|
||||
|
||||
bind(notChar);
|
||||
// cmpl(rcx, T_SHORT); // all that's left
|
||||
// jcc(Assembler::notEqual, done);
|
||||
LP64_ONLY(movswl(result, result);)
|
||||
NOT_LP64(shll(result, 16);) // truncate upper 16 bits
|
||||
NOT_LP64(sarl(result, 16);) // and sign-extend short
|
||||
|
||||
// Nothing to do for T_INT
|
||||
bind(done);
|
||||
}
|
||||
|
||||
// remove activation
|
||||
//
|
||||
// Unlock the receiver if this is a synchronized method.
|
||||
|
|
|
@ -192,6 +192,9 @@ class InterpreterMacroAssembler: public MacroAssembler {
|
|||
void prepare_to_jump_from_interpreted();
|
||||
void jump_from_interpreted(Register method, Register temp);
|
||||
|
||||
// narrow int return value
|
||||
void narrow(Register result);
|
||||
|
||||
// Returning from interpreted functions
|
||||
//
|
||||
// Removes the current activation (incl. unlocking of monitors)
|
||||
|
|
|
@ -243,6 +243,7 @@ void TemplateTable::patch_bytecode(Bytecodes::Code bc, Register bc_reg,
|
|||
switch (bc) {
|
||||
case Bytecodes::_fast_aputfield:
|
||||
case Bytecodes::_fast_bputfield:
|
||||
case Bytecodes::_fast_zputfield:
|
||||
case Bytecodes::_fast_cputfield:
|
||||
case Bytecodes::_fast_dputfield:
|
||||
case Bytecodes::_fast_fputfield:
|
||||
|
@ -1082,6 +1083,16 @@ void TemplateTable::bastore() {
|
|||
// rbx: index
|
||||
// rdx: array
|
||||
index_check(rdx, rbx); // prefer index in rbx
|
||||
// Need to check whether array is boolean or byte
|
||||
// since both types share the bastore bytecode.
|
||||
__ load_klass(rcx, rdx);
|
||||
__ movl(rcx, Address(rcx, Klass::layout_helper_offset()));
|
||||
int diffbit = Klass::layout_helper_boolean_diffbit();
|
||||
__ testl(rcx, diffbit);
|
||||
Label L_skip;
|
||||
__ jccb(Assembler::zero, L_skip);
|
||||
__ andl(rax, 1); // if it is a T_BOOLEAN array, mask the stored value to 0/1
|
||||
__ bind(L_skip);
|
||||
__ movb(Address(rdx, rbx,
|
||||
Address::times_1,
|
||||
arrayOopDesc::base_offset_in_bytes(T_BYTE)),
|
||||
|
@ -2540,13 +2551,12 @@ void TemplateTable::fast_binaryswitch() {
|
|||
void TemplateTable::_return(TosState state) {
|
||||
transition(state, state);
|
||||
|
||||
Register robj = LP64_ONLY(c_rarg1) NOT_LP64(rax);
|
||||
|
||||
assert(_desc->calls_vm(),
|
||||
"inconsistent calls_vm information"); // call in remove_activation
|
||||
|
||||
if (_desc->bytecode() == Bytecodes::_return_register_finalizer) {
|
||||
assert(state == vtos, "only valid state");
|
||||
Register robj = LP64_ONLY(c_rarg1) NOT_LP64(rax);
|
||||
__ movptr(robj, aaddress(0));
|
||||
__ load_klass(rdi, robj);
|
||||
__ movl(rdi, Address(rdi, Klass::access_flags_offset()));
|
||||
|
@ -2559,7 +2569,14 @@ void TemplateTable::_return(TosState state) {
|
|||
__ bind(skip_register_finalizer);
|
||||
}
|
||||
|
||||
// Narrow result if state is itos but result type is smaller.
|
||||
// Need to narrow in the return bytecode rather than in generate_return_entry
|
||||
// since compiled code callers expect the result to already be narrowed.
|
||||
if (state == itos) {
|
||||
__ narrow(rax);
|
||||
}
|
||||
__ remove_activation(state, rbcp);
|
||||
|
||||
__ jmp(rbcp);
|
||||
}
|
||||
|
||||
|
@ -2754,7 +2771,7 @@ void TemplateTable::getfield_or_static(int byte_no, bool is_static, RewriteContr
|
|||
const Address field(obj, off, Address::times_1, 0*wordSize);
|
||||
NOT_LP64(const Address hi(obj, off, Address::times_1, 1*wordSize));
|
||||
|
||||
Label Done, notByte, notInt, notShort, notChar, notLong, notFloat, notObj, notDouble;
|
||||
Label Done, notByte, notBool, notInt, notShort, notChar, notLong, notFloat, notObj, notDouble;
|
||||
|
||||
__ shrl(flags, ConstantPoolCacheEntry::tos_state_shift);
|
||||
// Make sure we don't need to mask edx after the above shift
|
||||
|
@ -2773,6 +2790,20 @@ void TemplateTable::getfield_or_static(int byte_no, bool is_static, RewriteContr
|
|||
__ jmp(Done);
|
||||
|
||||
__ bind(notByte);
|
||||
__ cmpl(flags, ztos);
|
||||
__ jcc(Assembler::notEqual, notBool);
|
||||
|
||||
// ztos (same code as btos)
|
||||
__ load_signed_byte(rax, field);
|
||||
__ push(ztos);
|
||||
// Rewrite bytecode to be faster
|
||||
if (!is_static && rc == may_rewrite) {
|
||||
// use btos rewriting, no truncating to t/f bit is needed for getfield.
|
||||
patch_bytecode(Bytecodes::_fast_bgetfield, bc, rbx);
|
||||
}
|
||||
__ jmp(Done);
|
||||
|
||||
__ bind(notBool);
|
||||
__ cmpl(flags, atos);
|
||||
__ jcc(Assembler::notEqual, notObj);
|
||||
// atos
|
||||
|
@ -3006,7 +3037,7 @@ void TemplateTable::putfield_or_static(int byte_no, bool is_static, RewriteContr
|
|||
const Address field(obj, off, Address::times_1, 0*wordSize);
|
||||
NOT_LP64( const Address hi(obj, off, Address::times_1, 1*wordSize);)
|
||||
|
||||
Label notByte, notInt, notShort, notChar,
|
||||
Label notByte, notBool, notInt, notShort, notChar,
|
||||
notLong, notFloat, notObj, notDouble;
|
||||
|
||||
__ shrl(flags, ConstantPoolCacheEntry::tos_state_shift);
|
||||
|
@ -3027,6 +3058,22 @@ void TemplateTable::putfield_or_static(int byte_no, bool is_static, RewriteContr
|
|||
}
|
||||
|
||||
__ bind(notByte);
|
||||
__ cmpl(flags, ztos);
|
||||
__ jcc(Assembler::notEqual, notBool);
|
||||
|
||||
// ztos
|
||||
{
|
||||
__ pop(ztos);
|
||||
if (!is_static) pop_and_check_object(obj);
|
||||
__ andl(rax, 0x1);
|
||||
__ movb(field, rax);
|
||||
if (!is_static && rc == may_rewrite) {
|
||||
patch_bytecode(Bytecodes::_fast_zputfield, bc, rbx, true, byte_no);
|
||||
}
|
||||
__ jmp(Done);
|
||||
}
|
||||
|
||||
__ bind(notBool);
|
||||
__ cmpl(flags, atos);
|
||||
__ jcc(Assembler::notEqual, notObj);
|
||||
|
||||
|
@ -3214,6 +3261,7 @@ void TemplateTable::jvmti_post_fast_field_mod() {
|
|||
switch (bytecode()) { // load values into the jvalue object
|
||||
case Bytecodes::_fast_aputfield: __ push_ptr(rax); break;
|
||||
case Bytecodes::_fast_bputfield: // fall through
|
||||
case Bytecodes::_fast_zputfield: // fall through
|
||||
case Bytecodes::_fast_sputfield: // fall through
|
||||
case Bytecodes::_fast_cputfield: // fall through
|
||||
case Bytecodes::_fast_iputfield: __ push_i(rax); break;
|
||||
|
@ -3238,6 +3286,7 @@ void TemplateTable::jvmti_post_fast_field_mod() {
|
|||
switch (bytecode()) { // restore tos values
|
||||
case Bytecodes::_fast_aputfield: __ pop_ptr(rax); break;
|
||||
case Bytecodes::_fast_bputfield: // fall through
|
||||
case Bytecodes::_fast_zputfield: // fall through
|
||||
case Bytecodes::_fast_sputfield: // fall through
|
||||
case Bytecodes::_fast_cputfield: // fall through
|
||||
case Bytecodes::_fast_iputfield: __ pop_i(rax); break;
|
||||
|
@ -3297,6 +3346,9 @@ void TemplateTable::fast_storefield(TosState state) {
|
|||
case Bytecodes::_fast_iputfield:
|
||||
__ movl(field, rax);
|
||||
break;
|
||||
case Bytecodes::_fast_zputfield:
|
||||
__ andl(rax, 0x1); // boolean is true if LSB is 1
|
||||
// fall through to bputfield
|
||||
case Bytecodes::_fast_bputfield:
|
||||
__ movb(field, rax);
|
||||
break;
|
||||
|
|
|
@ -82,6 +82,29 @@ int CppInterpreter::normal_entry(Method* method, intptr_t UNUSED, TRAPS) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
intptr_t narrow(BasicType type, intptr_t result) {
|
||||
// mask integer result to narrower return type.
|
||||
switch (type) {
|
||||
case T_BOOLEAN:
|
||||
return result&1;
|
||||
case T_BYTE:
|
||||
return (intptr_t)(jbyte)result;
|
||||
case T_CHAR:
|
||||
return (intptr_t)(uintptr_t)(jchar)result;
|
||||
case T_SHORT:
|
||||
return (intptr_t)(jshort)result;
|
||||
case T_OBJECT: // nothing to do fall through
|
||||
case T_LONG:
|
||||
case T_INT:
|
||||
case T_FLOAT:
|
||||
case T_DOUBLE:
|
||||
case T_VOID:
|
||||
return result;
|
||||
default : ShouldNotReachHere();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CppInterpreter::main_loop(int recurse, TRAPS) {
|
||||
JavaThread *thread = (JavaThread *) THREAD;
|
||||
ZeroStack *stack = thread->zero_stack();
|
||||
|
@ -195,8 +218,14 @@ void CppInterpreter::main_loop(int recurse, TRAPS) {
|
|||
stack->set_sp(stack->sp() + method->max_locals());
|
||||
|
||||
// Push our result
|
||||
for (int i = 0; i < result_slots; i++)
|
||||
stack->push(result[-i]);
|
||||
for (int i = 0; i < result_slots; i++) {
|
||||
// Adjust result to smaller
|
||||
intptr_t res = result[-i];
|
||||
if (result_slots == 1) {
|
||||
res = narrow(result_type_of(method), res);
|
||||
}
|
||||
stack->push(res);
|
||||
}
|
||||
}
|
||||
|
||||
int CppInterpreter::native_entry(Method* method, intptr_t UNUSED, TRAPS) {
|
||||
|
@ -532,6 +561,7 @@ int CppInterpreter::accessor_entry(Method* method, intptr_t UNUSED, TRAPS) {
|
|||
break;
|
||||
|
||||
case btos:
|
||||
case ztos:
|
||||
SET_LOCALS_INT(object->byte_field_acquire(entry->f2_as_index()), 0);
|
||||
break;
|
||||
|
||||
|
@ -570,6 +600,7 @@ int CppInterpreter::accessor_entry(Method* method, intptr_t UNUSED, TRAPS) {
|
|||
break;
|
||||
|
||||
case btos:
|
||||
case ztos:
|
||||
SET_LOCALS_INT(object->byte_field(entry->f2_as_index()), 0);
|
||||
break;
|
||||
|
||||
|
|
|
@ -305,7 +305,8 @@ void Canonicalizer::do_StoreIndexed (StoreIndexed* x) {
|
|||
// limit this optimization to current block
|
||||
if (value != NULL && in_current_block(conv)) {
|
||||
set_canonical(new StoreIndexed(x->array(), x->index(), x->length(),
|
||||
x->elt_type(), value, x->state_before()));
|
||||
x->elt_type(), value, x->state_before(),
|
||||
x->check_boolean()));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -976,7 +976,19 @@ void GraphBuilder::store_indexed(BasicType type) {
|
|||
(array->as_NewArray() && array->as_NewArray()->length() && array->as_NewArray()->length()->type()->is_constant())) {
|
||||
length = append(new ArrayLength(array, state_before));
|
||||
}
|
||||
StoreIndexed* result = new StoreIndexed(array, index, length, type, value, state_before);
|
||||
ciType* array_type = array->declared_type();
|
||||
bool check_boolean = false;
|
||||
if (array_type != NULL) {
|
||||
if (array_type->is_loaded() &&
|
||||
array_type->as_array_klass()->element_type()->basic_type() == T_BOOLEAN) {
|
||||
assert(type == T_BYTE, "boolean store uses bastore");
|
||||
Value mask = append(new Constant(new IntConstant(1)));
|
||||
value = append(new LogicOp(Bytecodes::_iand, value, mask));
|
||||
}
|
||||
} else if (type == T_BYTE) {
|
||||
check_boolean = true;
|
||||
}
|
||||
StoreIndexed* result = new StoreIndexed(array, index, length, type, value, state_before, check_boolean);
|
||||
append(result);
|
||||
_memory->store_value(value);
|
||||
|
||||
|
@ -1443,6 +1455,36 @@ void GraphBuilder::method_return(Value x) {
|
|||
need_mem_bar = true;
|
||||
}
|
||||
|
||||
BasicType bt = method()->return_type()->basic_type();
|
||||
switch (bt) {
|
||||
case T_BYTE:
|
||||
{
|
||||
Value shift = append(new Constant(new IntConstant(24)));
|
||||
x = append(new ShiftOp(Bytecodes::_ishl, x, shift));
|
||||
x = append(new ShiftOp(Bytecodes::_ishr, x, shift));
|
||||
break;
|
||||
}
|
||||
case T_SHORT:
|
||||
{
|
||||
Value shift = append(new Constant(new IntConstant(16)));
|
||||
x = append(new ShiftOp(Bytecodes::_ishl, x, shift));
|
||||
x = append(new ShiftOp(Bytecodes::_ishr, x, shift));
|
||||
break;
|
||||
}
|
||||
case T_CHAR:
|
||||
{
|
||||
Value mask = append(new Constant(new IntConstant(0xFFFF)));
|
||||
x = append(new LogicOp(Bytecodes::_iand, x, mask));
|
||||
break;
|
||||
}
|
||||
case T_BOOLEAN:
|
||||
{
|
||||
Value mask = append(new Constant(new IntConstant(1)));
|
||||
x = append(new LogicOp(Bytecodes::_iand, x, mask));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Check to see whether we are inlining. If so, Return
|
||||
// instructions become Gotos to the continuation point.
|
||||
if (continuation() != NULL) {
|
||||
|
@ -1611,6 +1653,10 @@ void GraphBuilder::access_field(Bytecodes::Code code) {
|
|||
if (state_before == NULL) {
|
||||
state_before = copy_state_for_exception();
|
||||
}
|
||||
if (field->type()->basic_type() == T_BOOLEAN) {
|
||||
Value mask = append(new Constant(new IntConstant(1)));
|
||||
val = append(new LogicOp(Bytecodes::_iand, val, mask));
|
||||
}
|
||||
append(new StoreField(append(obj), offset, field, val, true, state_before, needs_patching));
|
||||
break;
|
||||
}
|
||||
|
@ -1672,6 +1718,10 @@ void GraphBuilder::access_field(Bytecodes::Code code) {
|
|||
if (state_before == NULL) {
|
||||
state_before = copy_state_for_exception();
|
||||
}
|
||||
if (field->type()->basic_type() == T_BOOLEAN) {
|
||||
Value mask = append(new Constant(new IntConstant(1)));
|
||||
val = append(new LogicOp(Bytecodes::_iand, val, mask));
|
||||
}
|
||||
StoreField* store = new StoreField(obj, offset, field, val, false, state_before, needs_patching);
|
||||
if (!needs_patching) store = _memory->store(store);
|
||||
if (store != NULL) {
|
||||
|
@ -4134,7 +4184,12 @@ void GraphBuilder::append_unsafe_put_obj(ciMethod* callee, BasicType t, bool is_
|
|||
#ifndef _LP64
|
||||
offset = append(new Convert(Bytecodes::_l2i, offset, as_ValueType(T_INT)));
|
||||
#endif
|
||||
Instruction* op = append(new UnsafePutObject(t, args->at(1), offset, args->at(3), is_volatile));
|
||||
Value val = args->at(3);
|
||||
if (t == T_BOOLEAN) {
|
||||
Value mask = append(new Constant(new IntConstant(1)));
|
||||
val = append(new LogicOp(Bytecodes::_iand, val, mask));
|
||||
}
|
||||
Instruction* op = append(new UnsafePutObject(t, args->at(1), offset, val, is_volatile));
|
||||
compilation()->set_has_unsafe_access(true);
|
||||
kill_all();
|
||||
}
|
||||
|
@ -4208,7 +4263,7 @@ void GraphBuilder::append_char_access(ciMethod* callee, bool is_store) {
|
|||
Value index = args->at(1);
|
||||
if (is_store) {
|
||||
Value value = args->at(2);
|
||||
Instruction* store = append(new StoreIndexed(array, index, NULL, T_CHAR, value, state_before));
|
||||
Instruction* store = append(new StoreIndexed(array, index, NULL, T_CHAR, value, state_before, false));
|
||||
store->set_flag(Instruction::NeedsRangeCheckFlag, false);
|
||||
_memory->store_value(value);
|
||||
} else {
|
||||
|
|
|
@ -974,11 +974,13 @@ LEAF(StoreIndexed, AccessIndexed)
|
|||
|
||||
ciMethod* _profiled_method;
|
||||
int _profiled_bci;
|
||||
bool _check_boolean;
|
||||
|
||||
public:
|
||||
// creation
|
||||
StoreIndexed(Value array, Value index, Value length, BasicType elt_type, Value value, ValueStack* state_before)
|
||||
StoreIndexed(Value array, Value index, Value length, BasicType elt_type, Value value, ValueStack* state_before, bool check_boolean)
|
||||
: AccessIndexed(array, index, length, elt_type, state_before)
|
||||
, _value(value), _profiled_method(NULL), _profiled_bci(0)
|
||||
, _value(value), _profiled_method(NULL), _profiled_bci(0), _check_boolean(check_boolean)
|
||||
{
|
||||
set_flag(NeedsWriteBarrierFlag, (as_ValueType(elt_type)->is_object()));
|
||||
set_flag(NeedsStoreCheckFlag, (as_ValueType(elt_type)->is_object()));
|
||||
|
@ -990,6 +992,7 @@ LEAF(StoreIndexed, AccessIndexed)
|
|||
Value value() const { return _value; }
|
||||
bool needs_write_barrier() const { return check_flag(NeedsWriteBarrierFlag); }
|
||||
bool needs_store_check() const { return check_flag(NeedsStoreCheckFlag); }
|
||||
bool check_boolean() const { return _check_boolean; }
|
||||
// Helpers for MethodData* profiling
|
||||
void set_should_profile(bool value) { set_flag(ProfileMDOFlag, value); }
|
||||
void set_profiled_method(ciMethod* method) { _profiled_method = method; }
|
||||
|
|
|
@ -3680,3 +3680,26 @@ void LIRGenerator::do_MemBar(MemBar* x) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
LIR_Opr LIRGenerator::maybe_mask_boolean(StoreIndexed* x, LIR_Opr array, LIR_Opr value, CodeEmitInfo*& null_check_info) {
|
||||
if (x->check_boolean()) {
|
||||
LIR_Opr value_fixed = rlock_byte(T_BYTE);
|
||||
if (TwoOperandLIRForm) {
|
||||
__ move(value, value_fixed);
|
||||
__ logical_and(value_fixed, LIR_OprFact::intConst(1), value_fixed);
|
||||
} else {
|
||||
__ logical_and(value, LIR_OprFact::intConst(1), value_fixed);
|
||||
}
|
||||
LIR_Opr klass = new_register(T_METADATA);
|
||||
__ move(new LIR_Address(array, oopDesc::klass_offset_in_bytes(), T_ADDRESS), klass, null_check_info);
|
||||
null_check_info = NULL;
|
||||
LIR_Opr layout = new_register(T_INT);
|
||||
__ move(new LIR_Address(klass, in_bytes(Klass::layout_helper_offset()), T_INT), layout);
|
||||
int diffbit = Klass::layout_helper_boolean_diffbit();
|
||||
__ logical_and(layout, LIR_OprFact::intConst(diffbit), layout);
|
||||
__ cmp(lir_cond_notEqual, layout, LIR_OprFact::intConst(0));
|
||||
__ cmove(lir_cond_notEqual, value_fixed, value, value_fixed, T_BYTE);
|
||||
value = value_fixed;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
|
|
@ -448,6 +448,7 @@ class LIRGenerator: public InstructionVisitor, public BlockClosure {
|
|||
void profile_arguments(ProfileCall* x);
|
||||
void profile_parameters(Base* x);
|
||||
void profile_parameters_at_call(ProfileCall* x);
|
||||
LIR_Opr maybe_mask_boolean(StoreIndexed* x, LIR_Opr array, LIR_Opr value, CodeEmitInfo*& null_check_info);
|
||||
|
||||
public:
|
||||
Compilation* compilation() const { return _compilation; }
|
||||
|
|
|
@ -2713,11 +2713,9 @@ Method* ClassFileParser::parse_method(const ClassFileStream* const cfs,
|
|||
m->set_constants(_cp);
|
||||
m->set_name_index(name_index);
|
||||
m->set_signature_index(signature_index);
|
||||
#ifdef CC_INTERP
|
||||
// hmm is there a gc issue here??
|
||||
|
||||
ResultTypeFinder rtf(cp->symbol_at(signature_index));
|
||||
m->set_result_index(rtf.type());
|
||||
#endif
|
||||
m->constMethod()->set_result_type(rtf.type());
|
||||
|
||||
if (args_size >= 0) {
|
||||
m->set_size_of_parameters(args_size);
|
||||
|
|
|
@ -860,10 +860,8 @@ static Method* new_method(
|
|||
m->set_constants(NULL); // This will get filled in later
|
||||
m->set_name_index(cp->utf8(name));
|
||||
m->set_signature_index(cp->utf8(sig));
|
||||
#ifdef CC_INTERP
|
||||
ResultTypeFinder rtf(sig);
|
||||
m->set_result_index(rtf.type());
|
||||
#endif
|
||||
m->constMethod()->set_result_type(rtf.type());
|
||||
m->set_size_of_parameters(params);
|
||||
m->set_max_stack(max_stack);
|
||||
m->set_max_locals(params);
|
||||
|
|
|
@ -1767,8 +1767,19 @@ run:
|
|||
((objArrayOop) arrObj)->obj_at_put(index, rhsObject);
|
||||
UPDATE_PC_AND_TOS_AND_CONTINUE(1, -3);
|
||||
}
|
||||
CASE(_bastore):
|
||||
ARRAY_STOREFROM32(T_BYTE, jbyte, "%d", STACK_INT, 0);
|
||||
CASE(_bastore): {
|
||||
ARRAY_INTRO(-3);
|
||||
int item = STACK_INT(-1);
|
||||
// if it is a T_BOOLEAN array, mask the stored value to 0/1
|
||||
if (arrObj->klass() == Universe::boolArrayKlassObj()) {
|
||||
item &= 1;
|
||||
} else {
|
||||
assert(arrObj->klass() == Universe::byteArrayKlassObj(),
|
||||
"should be byte array otherwise");
|
||||
}
|
||||
((typeArrayOop)arrObj)->byte_at_put(index, item);
|
||||
UPDATE_PC_AND_TOS_AND_CONTINUE(1, -3);
|
||||
}
|
||||
CASE(_castore):
|
||||
ARRAY_STOREFROM32(T_CHAR, jchar, "%d", STACK_INT, 0);
|
||||
CASE(_sastore):
|
||||
|
@ -1999,7 +2010,7 @@ run:
|
|||
} else if (tos_type == ltos) {
|
||||
SET_STACK_LONG(obj->long_field_acquire(field_offset), 0);
|
||||
MORE_STACK(1);
|
||||
} else if (tos_type == btos) {
|
||||
} else if (tos_type == btos || tos_type == ztos) {
|
||||
SET_STACK_INT(obj->byte_field_acquire(field_offset), -1);
|
||||
} else if (tos_type == ctos) {
|
||||
SET_STACK_INT(obj->char_field_acquire(field_offset), -1);
|
||||
|
@ -2020,7 +2031,7 @@ run:
|
|||
} else if (tos_type == ltos) {
|
||||
SET_STACK_LONG(obj->long_field(field_offset), 0);
|
||||
MORE_STACK(1);
|
||||
} else if (tos_type == btos) {
|
||||
} else if (tos_type == btos || tos_type == ztos) {
|
||||
SET_STACK_INT(obj->byte_field(field_offset), -1);
|
||||
} else if (tos_type == ctos) {
|
||||
SET_STACK_INT(obj->char_field(field_offset), -1);
|
||||
|
@ -2109,6 +2120,9 @@ run:
|
|||
obj->release_obj_field_put(field_offset, STACK_OBJECT(-1));
|
||||
} else if (tos_type == btos) {
|
||||
obj->release_byte_field_put(field_offset, STACK_INT(-1));
|
||||
} else if (tos_type == ztos) {
|
||||
int bool_field = STACK_INT(-1); // only store LSB
|
||||
obj->release_byte_field_put(field_offset, (bool_field & 1));
|
||||
} else if (tos_type == ltos) {
|
||||
obj->release_long_field_put(field_offset, STACK_LONG(-1));
|
||||
} else if (tos_type == ctos) {
|
||||
|
@ -2129,6 +2143,9 @@ run:
|
|||
obj->obj_field_put(field_offset, STACK_OBJECT(-1));
|
||||
} else if (tos_type == btos) {
|
||||
obj->byte_field_put(field_offset, STACK_INT(-1));
|
||||
} else if (tos_type == ztos) {
|
||||
int bool_field = STACK_INT(-1); // only store LSB
|
||||
obj->byte_field_put(field_offset, (bool_field & 1));
|
||||
} else if (tos_type == ltos) {
|
||||
obj->long_field_put(field_offset, STACK_LONG(-1));
|
||||
} else if (tos_type == ctos) {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2015, 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
|
||||
|
@ -496,6 +496,7 @@ void Bytecodes::initialize() {
|
|||
|
||||
def(_fast_aputfield , "fast_aputfield" , "bJJ" , NULL , T_OBJECT , 0, true , _putfield );
|
||||
def(_fast_bputfield , "fast_bputfield" , "bJJ" , NULL , T_INT , 0, true , _putfield );
|
||||
def(_fast_zputfield , "fast_zputfield" , "bJJ" , NULL , T_INT , 0, true , _putfield );
|
||||
def(_fast_cputfield , "fast_cputfield" , "bJJ" , NULL , T_CHAR , 0, true , _putfield );
|
||||
def(_fast_dputfield , "fast_dputfield" , "bJJ" , NULL , T_DOUBLE , 0, true , _putfield );
|
||||
def(_fast_fputfield , "fast_fputfield" , "bJJ" , NULL , T_FLOAT , 0, true , _putfield );
|
||||
|
|
|
@ -257,6 +257,7 @@ class Bytecodes: AllStatic {
|
|||
|
||||
_fast_aputfield ,
|
||||
_fast_bputfield ,
|
||||
_fast_zputfield ,
|
||||
_fast_cputfield ,
|
||||
_fast_dputfield ,
|
||||
_fast_fputfield ,
|
||||
|
|
|
@ -1077,7 +1077,8 @@ IRT_ENTRY(void, InterpreterRuntime::post_field_modification(JavaThread *thread,
|
|||
char sig_type = '\0';
|
||||
|
||||
switch(cp_entry->flag_state()) {
|
||||
case btos: sig_type = 'Z'; break;
|
||||
case btos: sig_type = 'B'; break;
|
||||
case ztos: sig_type = 'Z'; break;
|
||||
case ctos: sig_type = 'C'; break;
|
||||
case stos: sig_type = 'S'; break;
|
||||
case itos: sig_type = 'I'; break;
|
||||
|
|
|
@ -89,8 +89,9 @@ void TemplateInterpreter::initialize() {
|
|||
// Implementation of EntryPoint
|
||||
|
||||
EntryPoint::EntryPoint() {
|
||||
assert(number_of_states == 9, "check the code below");
|
||||
assert(number_of_states == 10, "check the code below");
|
||||
_entry[btos] = NULL;
|
||||
_entry[ztos] = NULL;
|
||||
_entry[ctos] = NULL;
|
||||
_entry[stos] = NULL;
|
||||
_entry[atos] = NULL;
|
||||
|
@ -102,9 +103,10 @@ EntryPoint::EntryPoint() {
|
|||
}
|
||||
|
||||
|
||||
EntryPoint::EntryPoint(address bentry, address centry, address sentry, address aentry, address ientry, address lentry, address fentry, address dentry, address ventry) {
|
||||
assert(number_of_states == 9, "check the code below");
|
||||
EntryPoint::EntryPoint(address bentry, address zentry, address centry, address sentry, address aentry, address ientry, address lentry, address fentry, address dentry, address ventry) {
|
||||
assert(number_of_states == 10, "check the code below");
|
||||
_entry[btos] = bentry;
|
||||
_entry[ztos] = zentry;
|
||||
_entry[ctos] = centry;
|
||||
_entry[stos] = sentry;
|
||||
_entry[atos] = aentry;
|
||||
|
@ -155,6 +157,7 @@ EntryPoint DispatchTable::entry(int i) const {
|
|||
return
|
||||
EntryPoint(
|
||||
_table[btos][i],
|
||||
_table[ztos][i],
|
||||
_table[ctos][i],
|
||||
_table[stos][i],
|
||||
_table[atos][i],
|
||||
|
@ -169,8 +172,9 @@ EntryPoint DispatchTable::entry(int i) const {
|
|||
|
||||
void DispatchTable::set_entry(int i, EntryPoint& entry) {
|
||||
assert(0 <= i && i < length, "index out of bounds");
|
||||
assert(number_of_states == 9, "check the code below");
|
||||
assert(number_of_states == 10, "check the code below");
|
||||
_table[btos][i] = entry.entry(btos);
|
||||
_table[ztos][i] = entry.entry(ztos);
|
||||
_table[ctos][i] = entry.entry(ctos);
|
||||
_table[stos][i] = entry.entry(stos);
|
||||
_table[atos][i] = entry.entry(atos);
|
||||
|
|
|
@ -47,7 +47,7 @@ class EntryPoint VALUE_OBJ_CLASS_SPEC {
|
|||
public:
|
||||
// Construction
|
||||
EntryPoint();
|
||||
EntryPoint(address bentry, address centry, address sentry, address aentry, address ientry, address lentry, address fentry, address dentry, address ventry);
|
||||
EntryPoint(address bentry, address zentry, address centry, address sentry, address aentry, address ientry, address lentry, address fentry, address dentry, address ventry);
|
||||
|
||||
// Attributes
|
||||
address entry(TosState state) const; // return target address for a given tosca state
|
||||
|
|
|
@ -74,6 +74,7 @@ void TemplateInterpreterGenerator::generate_all() {
|
|||
Interpreter::_trace_code =
|
||||
EntryPoint(
|
||||
generate_trace_code(btos),
|
||||
generate_trace_code(ztos),
|
||||
generate_trace_code(ctos),
|
||||
generate_trace_code(stos),
|
||||
generate_trace_code(atos),
|
||||
|
@ -94,6 +95,7 @@ void TemplateInterpreterGenerator::generate_all() {
|
|||
generate_return_entry_for(itos, i, index_size),
|
||||
generate_return_entry_for(itos, i, index_size),
|
||||
generate_return_entry_for(itos, i, index_size),
|
||||
generate_return_entry_for(itos, i, index_size),
|
||||
generate_return_entry_for(atos, i, index_size),
|
||||
generate_return_entry_for(itos, i, index_size),
|
||||
generate_return_entry_for(ltos, i, index_size),
|
||||
|
@ -105,13 +107,16 @@ void TemplateInterpreterGenerator::generate_all() {
|
|||
}
|
||||
|
||||
{ CodeletMark cm(_masm, "invoke return entry points");
|
||||
const TosState states[] = {itos, itos, itos, itos, ltos, ftos, dtos, atos, vtos};
|
||||
// These states are in order specified in TosState, except btos/ztos/ctos/stos are
|
||||
// really the same as itos since there is no top of stack optimization for these types
|
||||
const TosState states[] = {itos, itos, itos, itos, itos, ltos, ftos, dtos, atos, vtos, ilgl};
|
||||
const int invoke_length = Bytecodes::length_for(Bytecodes::_invokestatic);
|
||||
const int invokeinterface_length = Bytecodes::length_for(Bytecodes::_invokeinterface);
|
||||
const int invokedynamic_length = Bytecodes::length_for(Bytecodes::_invokedynamic);
|
||||
|
||||
for (int i = 0; i < Interpreter::number_of_return_addrs; i++) {
|
||||
TosState state = states[i];
|
||||
assert(state != ilgl, "states array is wrong above");
|
||||
Interpreter::_invoke_return_entry[i] = generate_return_entry_for(state, invoke_length, sizeof(u2));
|
||||
Interpreter::_invokeinterface_return_entry[i] = generate_return_entry_for(state, invokeinterface_length, sizeof(u2));
|
||||
Interpreter::_invokedynamic_return_entry[i] = generate_return_entry_for(state, invokedynamic_length, sizeof(u4));
|
||||
|
@ -122,6 +127,7 @@ void TemplateInterpreterGenerator::generate_all() {
|
|||
Interpreter::_earlyret_entry =
|
||||
EntryPoint(
|
||||
generate_earlyret_entry_for(btos),
|
||||
generate_earlyret_entry_for(ztos),
|
||||
generate_earlyret_entry_for(ctos),
|
||||
generate_earlyret_entry_for(stos),
|
||||
generate_earlyret_entry_for(atos),
|
||||
|
@ -140,6 +146,7 @@ void TemplateInterpreterGenerator::generate_all() {
|
|||
generate_deopt_entry_for(itos, i),
|
||||
generate_deopt_entry_for(itos, i),
|
||||
generate_deopt_entry_for(itos, i),
|
||||
generate_deopt_entry_for(itos, i),
|
||||
generate_deopt_entry_for(atos, i),
|
||||
generate_deopt_entry_for(itos, i),
|
||||
generate_deopt_entry_for(ltos, i),
|
||||
|
@ -167,6 +174,7 @@ void TemplateInterpreterGenerator::generate_all() {
|
|||
Interpreter::_continuation_entry =
|
||||
EntryPoint(
|
||||
generate_continuation_for(btos),
|
||||
generate_continuation_for(ztos),
|
||||
generate_continuation_for(ctos),
|
||||
generate_continuation_for(stos),
|
||||
generate_continuation_for(atos),
|
||||
|
@ -182,6 +190,7 @@ void TemplateInterpreterGenerator::generate_all() {
|
|||
Interpreter::_safept_entry =
|
||||
EntryPoint(
|
||||
generate_safept_entry_for(btos, CAST_FROM_FN_PTR(address, InterpreterRuntime::at_safepoint)),
|
||||
generate_safept_entry_for(ztos, CAST_FROM_FN_PTR(address, InterpreterRuntime::at_safepoint)),
|
||||
generate_safept_entry_for(ctos, CAST_FROM_FN_PTR(address, InterpreterRuntime::at_safepoint)),
|
||||
generate_safept_entry_for(stos, CAST_FROM_FN_PTR(address, InterpreterRuntime::at_safepoint)),
|
||||
generate_safept_entry_for(atos, CAST_FROM_FN_PTR(address, InterpreterRuntime::at_safepoint)),
|
||||
|
@ -301,7 +310,7 @@ void TemplateInterpreterGenerator::set_safepoints_for_all_bytes() {
|
|||
|
||||
void TemplateInterpreterGenerator::set_unimplemented(int i) {
|
||||
address e = _unimplemented_bytecode;
|
||||
EntryPoint entry(e, e, e, e, e, e, e, e, e);
|
||||
EntryPoint entry(e, e, e, e, e, e, e, e, e, e);
|
||||
Interpreter::_normal_table.set_entry(i, entry);
|
||||
Interpreter::_wentry_point[i] = _unimplemented_bytecode;
|
||||
}
|
||||
|
@ -316,6 +325,7 @@ void TemplateInterpreterGenerator::set_entry_points(Bytecodes::Code code) {
|
|||
assert(_unimplemented_bytecode != NULL, "should have been generated before");
|
||||
assert(_illegal_bytecode_sequence != NULL, "should have been generated before");
|
||||
address bep = _illegal_bytecode_sequence;
|
||||
address zep = _illegal_bytecode_sequence;
|
||||
address cep = _illegal_bytecode_sequence;
|
||||
address sep = _illegal_bytecode_sequence;
|
||||
address aep = _illegal_bytecode_sequence;
|
||||
|
@ -337,7 +347,7 @@ void TemplateInterpreterGenerator::set_entry_points(Bytecodes::Code code) {
|
|||
set_wide_entry_point(t, wep);
|
||||
}
|
||||
// set entry points
|
||||
EntryPoint entry(bep, cep, sep, aep, iep, lep, fep, dep, vep);
|
||||
EntryPoint entry(bep, zep, cep, sep, aep, iep, lep, fep, dep, vep);
|
||||
Interpreter::_normal_table.set_entry(code, entry);
|
||||
Interpreter::_wentry_point[code] = wep;
|
||||
CodeCacheExtensions::completed_template_interpreter_entries(_masm, code);
|
||||
|
@ -355,6 +365,7 @@ void TemplateInterpreterGenerator::set_short_entry_points(Template* t, address&
|
|||
assert(t->is_valid(), "template must exist");
|
||||
switch (t->tos_in()) {
|
||||
case btos:
|
||||
case ztos:
|
||||
case ctos:
|
||||
case stos:
|
||||
ShouldNotReachHere(); // btos/ctos/stos should use itos.
|
||||
|
|
|
@ -488,6 +488,7 @@ void TemplateTable::initialize() {
|
|||
|
||||
def(Bytecodes::_fast_aputfield , ubcp|____|____|____, atos, vtos, fast_storefield , atos );
|
||||
def(Bytecodes::_fast_bputfield , ubcp|____|____|____, itos, vtos, fast_storefield , itos );
|
||||
def(Bytecodes::_fast_zputfield , ubcp|____|____|____, itos, vtos, fast_storefield , itos );
|
||||
def(Bytecodes::_fast_cputfield , ubcp|____|____|____, itos, vtos, fast_storefield , itos );
|
||||
def(Bytecodes::_fast_dputfield , ubcp|____|____|____, dtos, vtos, fast_storefield , dtos );
|
||||
def(Bytecodes::_fast_fputfield , ubcp|____|____|____, ftos, vtos, fast_storefield , ftos );
|
||||
|
|
|
@ -66,6 +66,7 @@ ConstMethod::ConstMethod(int byte_code_size,
|
|||
set_max_locals(0);
|
||||
set_method_idnum(0);
|
||||
set_size_of_parameters(0);
|
||||
set_result_type(T_VOID);
|
||||
}
|
||||
|
||||
// Accessor that copies to metadata.
|
||||
|
|
|
@ -210,6 +210,7 @@ private:
|
|||
|
||||
int _constMethod_size;
|
||||
u2 _flags;
|
||||
u1 _result_type; // BasicType of result
|
||||
|
||||
// Size of Java bytecodes allocated immediately after Method*.
|
||||
u2 _code_size;
|
||||
|
@ -494,6 +495,8 @@ public:
|
|||
static ByteSize size_of_parameters_offset()
|
||||
{ return byte_offset_of(ConstMethod, _size_of_parameters); }
|
||||
|
||||
static ByteSize result_type_offset()
|
||||
{ return byte_offset_of(ConstMethod, _result_type); }
|
||||
|
||||
// Unique id for the method
|
||||
static const u2 MAX_IDNUM;
|
||||
|
@ -516,6 +519,8 @@ public:
|
|||
int size_of_parameters() const { return _size_of_parameters; }
|
||||
void set_size_of_parameters(int size) { _size_of_parameters = size; }
|
||||
|
||||
void set_result_type(BasicType rt) { assert(rt < 16, "result type too large");
|
||||
_result_type = (u1)rt; }
|
||||
// Deallocation for RedefineClasses
|
||||
void deallocate_contents(ClassLoaderData* loader_data);
|
||||
bool is_klass() const { return false; }
|
||||
|
|
|
@ -77,18 +77,19 @@ class PSPromotionManager;
|
|||
// f2 flag true if f2 contains an oop (e.g., virtual final method)
|
||||
// fv flag true if invokeinterface used for method in class Object
|
||||
//
|
||||
// The flags 31, 30, 29, 28 together build a 4 bit number 0 to 8 with the
|
||||
// The flags 31, 30, 29, 28 together build a 4 bit number 0 to 16 with the
|
||||
// following mapping to the TosState states:
|
||||
//
|
||||
// btos: 0
|
||||
// ctos: 1
|
||||
// stos: 2
|
||||
// itos: 3
|
||||
// ltos: 4
|
||||
// ftos: 5
|
||||
// dtos: 6
|
||||
// atos: 7
|
||||
// vtos: 8
|
||||
// ztos: 1
|
||||
// ctos: 2
|
||||
// stos: 3
|
||||
// itos: 4
|
||||
// ltos: 5
|
||||
// ftos: 6
|
||||
// dtos: 7
|
||||
// atos: 8
|
||||
// vtos: 9
|
||||
//
|
||||
// Entry specific: field entries:
|
||||
// _indices = get (b1 section) and put (b2 section) bytecodes, original constant pool index
|
||||
|
@ -352,14 +353,8 @@ class ConstantPoolCacheEntry VALUE_OBJ_CLASS_SPEC {
|
|||
bool has_method_type() const { return (!is_f1_null()) && (_flags & (1 << has_method_type_shift)) != 0; }
|
||||
bool is_method_entry() const { return (_flags & (1 << is_field_entry_shift)) == 0; }
|
||||
bool is_field_entry() const { return (_flags & (1 << is_field_entry_shift)) != 0; }
|
||||
bool is_byte() const { return flag_state() == btos; }
|
||||
bool is_char() const { return flag_state() == ctos; }
|
||||
bool is_short() const { return flag_state() == stos; }
|
||||
bool is_int() const { return flag_state() == itos; }
|
||||
bool is_long() const { return flag_state() == ltos; }
|
||||
bool is_float() const { return flag_state() == ftos; }
|
||||
bool is_double() const { return flag_state() == dtos; }
|
||||
bool is_object() const { return flag_state() == atos; }
|
||||
TosState flag_state() const { assert((uint)number_of_states <= (uint)tos_state_mask+1, "");
|
||||
return (TosState)((_flags >> tos_state_shift) & tos_state_mask); }
|
||||
|
||||
|
|
|
@ -342,6 +342,21 @@ protected:
|
|||
assert(btvalue >= T_BOOLEAN && btvalue <= T_OBJECT, "sanity");
|
||||
return (BasicType) btvalue;
|
||||
}
|
||||
|
||||
// Want a pattern to quickly diff against layout header in register
|
||||
// find something less clever!
|
||||
static int layout_helper_boolean_diffbit() {
|
||||
jint zlh = array_layout_helper(T_BOOLEAN);
|
||||
jint blh = array_layout_helper(T_BYTE);
|
||||
assert(zlh != blh, "array layout helpers must differ");
|
||||
int diffbit = 1;
|
||||
while ((diffbit & (zlh ^ blh)) == 0 && (diffbit & zlh) == 0) {
|
||||
diffbit <<= 1;
|
||||
assert(diffbit != 0, "make sure T_BOOLEAN has a different bit than T_BYTE");
|
||||
}
|
||||
return diffbit;
|
||||
}
|
||||
|
||||
static int layout_helper_log2_element_size(jint lh) {
|
||||
assert(lh < (jint)_lh_neutral_value, "must be array");
|
||||
int l2esz = (lh >> _lh_log2_element_size_shift) & _lh_log2_element_size_mask;
|
||||
|
|
|
@ -1220,10 +1220,8 @@ methodHandle Method::make_method_handle_intrinsic(vmIntrinsics::ID iid,
|
|||
m->set_signature_index(_imcp_invoke_signature);
|
||||
assert(MethodHandles::is_signature_polymorphic_name(m->name()), "");
|
||||
assert(m->signature() == signature, "");
|
||||
#ifdef CC_INTERP
|
||||
ResultTypeFinder rtf(signature);
|
||||
m->set_result_index(rtf.type());
|
||||
#endif
|
||||
m->constMethod()->set_result_type(rtf.type());
|
||||
m->compute_size_of_parameters(THREAD);
|
||||
m->init_intrinsic_id();
|
||||
assert(m->is_method_handle_intrinsic(), "");
|
||||
|
|
|
@ -443,7 +443,7 @@ jchar oopDesc::char_field(int offset) const { return (jchar) *
|
|||
void oopDesc::char_field_put(int offset, jchar contents) { *char_field_addr(offset) = (jint) contents; }
|
||||
|
||||
jboolean oopDesc::bool_field(int offset) const { return (jboolean) *bool_field_addr(offset); }
|
||||
void oopDesc::bool_field_put(int offset, jboolean contents) { *bool_field_addr(offset) = (jint) contents; }
|
||||
void oopDesc::bool_field_put(int offset, jboolean contents) { *bool_field_addr(offset) = (((jint) contents) & 1); }
|
||||
|
||||
jint oopDesc::int_field(int offset) const { return *int_field_addr(offset); }
|
||||
void oopDesc::int_field_put(int offset, jint contents) { *int_field_addr(offset) = contents; }
|
||||
|
@ -483,7 +483,7 @@ jchar oopDesc::char_field_acquire(int offset) const { return O
|
|||
void oopDesc::release_char_field_put(int offset, jchar contents) { OrderAccess::release_store(char_field_addr(offset), contents); }
|
||||
|
||||
jboolean oopDesc::bool_field_acquire(int offset) const { return OrderAccess::load_acquire(bool_field_addr(offset)); }
|
||||
void oopDesc::release_bool_field_put(int offset, jboolean contents) { OrderAccess::release_store(bool_field_addr(offset), contents); }
|
||||
void oopDesc::release_bool_field_put(int offset, jboolean contents) { OrderAccess::release_store(bool_field_addr(offset), (contents & 1)); }
|
||||
|
||||
jint oopDesc::int_field_acquire(int offset) const { return OrderAccess::load_acquire(int_field_addr(offset)); }
|
||||
void oopDesc::release_int_field_put(int offset, jint contents) { OrderAccess::release_store(int_field_addr(offset), contents); }
|
||||
|
|
|
@ -2389,7 +2389,7 @@ StoreNode* StoreNode::make(PhaseGVN& gvn, Node* ctl, Node* mem, Node* adr, const
|
|||
ctl != NULL, "raw memory operations should have control edge");
|
||||
|
||||
switch (bt) {
|
||||
case T_BOOLEAN:
|
||||
case T_BOOLEAN: val = gvn.transform(new AndINode(val, gvn.intcon(0x1))); // Fall through to T_BYTE case
|
||||
case T_BYTE: return new StoreBNode(ctl, mem, adr, adr_type, val, mo);
|
||||
case T_INT: return new StoreINode(ctl, mem, adr, adr_type, val, mo);
|
||||
case T_CHAR:
|
||||
|
|
|
@ -730,6 +730,26 @@ void Parse::do_all_blocks() {
|
|||
#endif
|
||||
}
|
||||
|
||||
static Node* mask_int_value(Node* v, BasicType bt, PhaseGVN* gvn) {
|
||||
switch (bt) {
|
||||
case T_BYTE:
|
||||
v = gvn->transform(new LShiftINode(v, gvn->intcon(24)));
|
||||
v = gvn->transform(new RShiftINode(v, gvn->intcon(24)));
|
||||
break;
|
||||
case T_SHORT:
|
||||
v = gvn->transform(new LShiftINode(v, gvn->intcon(16)));
|
||||
v = gvn->transform(new RShiftINode(v, gvn->intcon(16)));
|
||||
break;
|
||||
case T_CHAR:
|
||||
v = gvn->transform(new AndINode(v, gvn->intcon(0xFFFF)));
|
||||
break;
|
||||
case T_BOOLEAN:
|
||||
v = gvn->transform(new AndINode(v, gvn->intcon(0x1)));
|
||||
break;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
//-------------------------------build_exits----------------------------------
|
||||
// Build normal and exceptional exit merge points.
|
||||
void Parse::build_exits() {
|
||||
|
@ -754,6 +774,16 @@ void Parse::build_exits() {
|
|||
// Add a return value to the exit state. (Do not push it yet.)
|
||||
if (tf()->range()->cnt() > TypeFunc::Parms) {
|
||||
const Type* ret_type = tf()->range()->field_at(TypeFunc::Parms);
|
||||
if (ret_type->isa_int()) {
|
||||
BasicType ret_bt = method()->return_type()->basic_type();
|
||||
if (ret_bt == T_BOOLEAN ||
|
||||
ret_bt == T_CHAR ||
|
||||
ret_bt == T_BYTE ||
|
||||
ret_bt == T_SHORT) {
|
||||
ret_type = TypeInt::INT;
|
||||
}
|
||||
}
|
||||
|
||||
// Don't "bind" an unloaded return klass to the ret_phi. If the klass
|
||||
// becomes loaded during the subsequent parsing, the loaded and unloaded
|
||||
// types will not join when we transform and push in do_exits().
|
||||
|
@ -1014,6 +1044,10 @@ void Parse::do_exits() {
|
|||
}
|
||||
return;
|
||||
}
|
||||
if (ret_type->isa_int()) {
|
||||
BasicType ret_bt = method()->return_type()->basic_type();
|
||||
ret_phi = mask_int_value(ret_phi, ret_bt, &_gvn);
|
||||
}
|
||||
_exits.push_node(ret_type->basic_type(), ret_phi);
|
||||
}
|
||||
|
||||
|
|
|
@ -64,11 +64,15 @@ void Parse::array_load(BasicType elem_type) {
|
|||
|
||||
//--------------------------------array_store----------------------------------
|
||||
void Parse::array_store(BasicType elem_type) {
|
||||
Node* adr = array_addressing(elem_type, 1);
|
||||
const Type* elem = Type::TOP;
|
||||
Node* adr = array_addressing(elem_type, 1, &elem);
|
||||
if (stopped()) return; // guaranteed null or range check
|
||||
Node* val = pop();
|
||||
dec_sp(2); // Pop array and index
|
||||
const TypeAryPtr* adr_type = TypeAryPtr::get_array_body_type(elem_type);
|
||||
if (elem == TypeInt::BOOL) {
|
||||
elem_type = T_BOOLEAN;
|
||||
}
|
||||
store_to_memory(control(), adr, val, elem_type, adr_type, StoreNode::release_if_reference(elem_type));
|
||||
}
|
||||
|
||||
|
|
|
@ -1820,14 +1820,16 @@ const TypeTuple *TypeTuple::make_domain(ciInstanceKlass* recv, ciSignature* sig)
|
|||
break;
|
||||
case T_OBJECT:
|
||||
case T_ARRAY:
|
||||
case T_BOOLEAN:
|
||||
case T_CHAR:
|
||||
case T_FLOAT:
|
||||
case T_BYTE:
|
||||
case T_SHORT:
|
||||
case T_INT:
|
||||
field_array[pos++] = get_const_type(type);
|
||||
break;
|
||||
case T_BOOLEAN:
|
||||
case T_CHAR:
|
||||
case T_BYTE:
|
||||
case T_SHORT:
|
||||
field_array[pos++] = TypeInt::INT;
|
||||
break;
|
||||
default:
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
|
|
|
@ -2188,6 +2188,7 @@ JNI_QUICK_ENTRY(void, jni_Set##Result##Field(JNIEnv *env, jobject obj, jfieldID
|
|||
field_value.unionType = value; \
|
||||
o = JvmtiExport::jni_SetField_probe_nh(thread, obj, o, k, fieldID, false, SigType, (jvalue *)&field_value); \
|
||||
} \
|
||||
if (SigType == 'Z') { value = ((jboolean)value) & 1; } \
|
||||
o->Fieldname##_field_put(offset, value); \
|
||||
ReturnProbe; \
|
||||
JNI_END
|
||||
|
@ -2387,6 +2388,7 @@ JNI_ENTRY(void, jni_SetStatic##Result##Field(JNIEnv *env, jclass clazz, jfieldID
|
|||
field_value.unionType = value; \
|
||||
JvmtiExport::jni_SetField_probe(thread, NULL, NULL, id->holder(), fieldID, true, SigType, (jvalue *)&field_value); \
|
||||
} \
|
||||
if (SigType == 'Z') { value = ((jboolean)value) & 1; } \
|
||||
id->holder()->java_mirror()-> Fieldname##_field_put (id->offset(), value); \
|
||||
ReturnProbe;\
|
||||
JNI_END
|
||||
|
|
|
@ -1354,7 +1354,7 @@ JvmtiEnvBase::check_top_frame(JavaThread* current_thread, JavaThread* java_threa
|
|||
ResultTypeFinder rtf(signature);
|
||||
TosState fr_tos = as_TosState(rtf.type());
|
||||
if (fr_tos != tos) {
|
||||
if (tos != itos || (fr_tos != btos && fr_tos != ctos && fr_tos != stos)) {
|
||||
if (tos != itos || (fr_tos != btos && fr_tos != ztos && fr_tos != ctos && fr_tos != stos)) {
|
||||
return JVMTI_ERROR_TYPE_MISMATCH;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1702,7 +1702,7 @@ void JvmtiExport::post_raw_field_modification(JavaThread *thread, Method* method
|
|||
address location, KlassHandle field_klass, Handle object, jfieldID field,
|
||||
char sig_type, jvalue *value) {
|
||||
|
||||
if (sig_type == 'I' || sig_type == 'Z' || sig_type == 'C' || sig_type == 'S') {
|
||||
if (sig_type == 'I' || sig_type == 'Z' || sig_type == 'B' || sig_type == 'C' || sig_type == 'S') {
|
||||
// 'I' instructions are used for byte, char, short and int.
|
||||
// determine which it really is, and convert
|
||||
fieldDescriptor fd;
|
||||
|
|
|
@ -133,13 +133,22 @@ jlong Unsafe_field_offset_from_byte_offset(jlong byte_offset) {
|
|||
|
||||
///// Data in the Java heap.
|
||||
|
||||
#define truncate_jboolean(x) ((x) & 1)
|
||||
#define truncate_jbyte(x) (x)
|
||||
#define truncate_jshort(x) (x)
|
||||
#define truncate_jchar(x) (x)
|
||||
#define truncate_jint(x) (x)
|
||||
#define truncate_jlong(x) (x)
|
||||
#define truncate_jfloat(x) (x)
|
||||
#define truncate_jdouble(x) (x)
|
||||
|
||||
#define GET_FIELD(obj, offset, type_name, v) \
|
||||
oop p = JNIHandles::resolve(obj); \
|
||||
type_name v = *(type_name*)index_oop_from_field_offset_long(p, offset)
|
||||
|
||||
#define SET_FIELD(obj, offset, type_name, x) \
|
||||
oop p = JNIHandles::resolve(obj); \
|
||||
*(type_name*)index_oop_from_field_offset_long(p, offset) = x
|
||||
*(type_name*)index_oop_from_field_offset_long(p, offset) = truncate_##type_name(x)
|
||||
|
||||
#define GET_FIELD_VOLATILE(obj, offset, type_name, v) \
|
||||
oop p = JNIHandles::resolve(obj); \
|
||||
|
@ -150,7 +159,7 @@ jlong Unsafe_field_offset_from_byte_offset(jlong byte_offset) {
|
|||
|
||||
#define SET_FIELD_VOLATILE(obj, offset, type_name, x) \
|
||||
oop p = JNIHandles::resolve(obj); \
|
||||
OrderAccess::release_store_fence((volatile type_name*)index_oop_from_field_offset_long(p, offset), x);
|
||||
OrderAccess::release_store_fence((volatile type_name*)index_oop_from_field_offset_long(p, offset), truncate_##type_name(x));
|
||||
|
||||
|
||||
// Get/SetObject must be special-cased, since it works with handles.
|
||||
|
|
|
@ -1025,7 +1025,7 @@ static BasicType basic_type_mirror_to_basic_type(oop basic_type_mirror, TRAPS) {
|
|||
static void narrow(jvalue* value, BasicType narrow_type, TRAPS) {
|
||||
switch (narrow_type) {
|
||||
case T_BOOLEAN:
|
||||
value->z = (jboolean)value->i;
|
||||
value->z = (jboolean) (value->i & 1);
|
||||
return;
|
||||
case T_BYTE:
|
||||
value->b = (jbyte)value->i;
|
||||
|
|
|
@ -846,14 +846,15 @@ class JavaValue {
|
|||
|
||||
enum TosState { // describes the tos cache contents
|
||||
btos = 0, // byte, bool tos cached
|
||||
ctos = 1, // char tos cached
|
||||
stos = 2, // short tos cached
|
||||
itos = 3, // int tos cached
|
||||
ltos = 4, // long tos cached
|
||||
ftos = 5, // float tos cached
|
||||
dtos = 6, // double tos cached
|
||||
atos = 7, // object cached
|
||||
vtos = 8, // tos not cached
|
||||
ztos = 1, // byte, bool tos cached
|
||||
ctos = 2, // char tos cached
|
||||
stos = 3, // short tos cached
|
||||
itos = 4, // int tos cached
|
||||
ltos = 5, // long tos cached
|
||||
ftos = 6, // float tos cached
|
||||
dtos = 7, // double tos cached
|
||||
atos = 8, // object cached
|
||||
vtos = 9, // tos not cached
|
||||
number_of_states,
|
||||
ilgl // illegal state: should not occur
|
||||
};
|
||||
|
@ -862,7 +863,7 @@ enum TosState { // describes the tos cache contents
|
|||
inline TosState as_TosState(BasicType type) {
|
||||
switch (type) {
|
||||
case T_BYTE : return btos;
|
||||
case T_BOOLEAN: return btos; // FIXME: Add ztos
|
||||
case T_BOOLEAN: return ztos;
|
||||
case T_CHAR : return ctos;
|
||||
case T_SHORT : return stos;
|
||||
case T_INT : return itos;
|
||||
|
@ -878,8 +879,8 @@ inline TosState as_TosState(BasicType type) {
|
|||
|
||||
inline BasicType as_BasicType(TosState state) {
|
||||
switch (state) {
|
||||
//case ztos: return T_BOOLEAN;//FIXME
|
||||
case btos : return T_BYTE;
|
||||
case ztos : return T_BOOLEAN;
|
||||
case ctos : return T_CHAR;
|
||||
case stos : return T_SHORT;
|
||||
case itos : return T_INT;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue