8132051: Better byte behavior
Reviewed-by: bdelsart, roland, kvn, jrose, ahgross
Contributed-by: coleen.phillimore@oracle.com, roland.westerlin@oracle.com, vladimir.kozlov@oracle.com, john.r.rose@oracle.com
--- a/hotspot/src/cpu/sparc/vm/c1_LIRGenerator_sparc.cpp Mon Apr 18 15:39:46 2016 -0700
+++ b/hotspot/src/cpu/sparc/vm/c1_LIRGenerator_sparc.cpp Tue Oct 13 18:13:34 2015 -0400
@@ -344,7 +344,7 @@
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 @@
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());
--- a/hotspot/src/cpu/sparc/vm/interp_masm_sparc.cpp Mon Apr 18 15:39:46 2016 -0700
+++ b/hotspot/src/cpu/sparc/vm/interp_masm_sparc.cpp Tue Oct 13 18:13:34 2015 -0400
@@ -208,6 +208,7 @@
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 @@
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::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 @@
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 @@
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
--- a/hotspot/src/cpu/sparc/vm/interp_masm_sparc.hpp Mon Apr 18 15:39:46 2016 -0700
+++ b/hotspot/src/cpu/sparc/vm/interp_masm_sparc.hpp Tue Oct 13 18:13:34 2015 -0400
@@ -103,6 +103,8 @@
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.
--- a/hotspot/src/cpu/sparc/vm/templateTable_sparc.cpp Mon Apr 18 15:39:46 2016 -0700
+++ b/hotspot/src/cpu/sparc/vm/templateTable_sparc.cpp Tue Oct 13 18:13:34 2015 -0400
@@ -165,6 +165,7 @@
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 @@
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 @@
__ 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 @@
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 @@
// 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 @@
__ 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 @@
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 @@
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 @@
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 @@
// cmp(Rflags, btos);
__ br(Assembler::notEqual, false, Assembler::pt, notByte);
- __ delayed()->cmp(Rflags, ltos);
+ __ delayed()->cmp(Rflags, ztos);
// btos
{
@@ -2664,6 +2701,25 @@
}
__ 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 @@
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;
--- a/hotspot/src/cpu/x86/vm/c1_LIRGenerator_x86.cpp Mon Apr 18 15:39:46 2016 -0700
+++ b/hotspot/src/cpu/x86/vm/c1_LIRGenerator_x86.cpp Tue Oct 13 18:13:34 2015 -0400
@@ -284,7 +284,7 @@
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 @@
// 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);
}
}
--- a/hotspot/src/cpu/x86/vm/interp_masm_x86.cpp Mon Apr 18 15:39:46 2016 -0700
+++ b/hotspot/src/cpu/x86/vm/interp_masm_x86.cpp Tue Oct 13 18:13:34 2015 -0400
@@ -349,6 +349,7 @@
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 @@
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 @@
switch (state) {
case atos: pop_ptr(); break;
case btos:
+ case ztos:
case ctos:
case stos:
case itos: pop_i(); break;
@@ -633,6 +636,7 @@
switch (state) {
case atos: push_ptr(); break;
case btos:
+ case ztos:
case ctos:
case stos:
case itos: push_i(); break;
@@ -668,6 +672,7 @@
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 @@
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 @@
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.
--- a/hotspot/src/cpu/x86/vm/interp_masm_x86.hpp Mon Apr 18 15:39:46 2016 -0700
+++ b/hotspot/src/cpu/x86/vm/interp_masm_x86.hpp Tue Oct 13 18:13:34 2015 -0400
@@ -192,6 +192,9 @@
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)
--- a/hotspot/src/cpu/x86/vm/templateTable_x86.cpp Mon Apr 18 15:39:46 2016 -0700
+++ b/hotspot/src/cpu/x86/vm/templateTable_x86.cpp Tue Oct 13 18:13:34 2015 -0400
@@ -243,6 +243,7 @@
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 @@
// 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::_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 @@
__ 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 @@
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 @@
__ 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 @@
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 @@
}
__ 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 @@
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 @@
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 @@
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;
--- a/hotspot/src/cpu/zero/vm/cppInterpreter_zero.cpp Mon Apr 18 15:39:46 2016 -0700
+++ b/hotspot/src/cpu/zero/vm/cppInterpreter_zero.cpp Tue Oct 13 18:13:34 2015 -0400
@@ -82,6 +82,29 @@
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 @@
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 @@
break;
case btos:
+ case ztos:
SET_LOCALS_INT(object->byte_field_acquire(entry->f2_as_index()), 0);
break;
@@ -570,6 +600,7 @@
break;
case btos:
+ case ztos:
SET_LOCALS_INT(object->byte_field(entry->f2_as_index()), 0);
break;
--- a/hotspot/src/share/vm/c1/c1_Canonicalizer.cpp Mon Apr 18 15:39:46 2016 -0700
+++ b/hotspot/src/share/vm/c1/c1_Canonicalizer.cpp Tue Oct 13 18:13:34 2015 -0400
@@ -305,7 +305,8 @@
// 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;
}
}
--- a/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp Mon Apr 18 15:39:46 2016 -0700
+++ b/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp Tue Oct 13 18:13:34 2015 -0400
@@ -976,7 +976,19 @@
(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 @@
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 @@
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 @@
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 @@
#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 @@
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 {
--- a/hotspot/src/share/vm/c1/c1_Instruction.hpp Mon Apr 18 15:39:46 2016 -0700
+++ b/hotspot/src/share/vm/c1/c1_Instruction.hpp Tue Oct 13 18:13:34 2015 -0400
@@ -974,11 +974,13 @@
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 @@
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; }
--- a/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp Mon Apr 18 15:39:46 2016 -0700
+++ b/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp Tue Oct 13 18:13:34 2015 -0400
@@ -3680,3 +3680,26 @@
}
}
}
+
+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;
+}
--- a/hotspot/src/share/vm/c1/c1_LIRGenerator.hpp Mon Apr 18 15:39:46 2016 -0700
+++ b/hotspot/src/share/vm/c1/c1_LIRGenerator.hpp Tue Oct 13 18:13:34 2015 -0400
@@ -448,6 +448,7 @@
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; }
--- a/hotspot/src/share/vm/classfile/classFileParser.cpp Mon Apr 18 15:39:46 2016 -0700
+++ b/hotspot/src/share/vm/classfile/classFileParser.cpp Tue Oct 13 18:13:34 2015 -0400
@@ -2713,11 +2713,9 @@
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);
--- a/hotspot/src/share/vm/classfile/defaultMethods.cpp Mon Apr 18 15:39:46 2016 -0700
+++ b/hotspot/src/share/vm/classfile/defaultMethods.cpp Tue Oct 13 18:13:34 2015 -0400
@@ -860,10 +860,8 @@
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);
--- a/hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp Mon Apr 18 15:39:46 2016 -0700
+++ b/hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp Tue Oct 13 18:13:34 2015 -0400
@@ -1767,8 +1767,19 @@
((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 @@
} 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 @@
} 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 @@
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 @@
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) {
--- a/hotspot/src/share/vm/interpreter/bytecodes.cpp Mon Apr 18 15:39:46 2016 -0700
+++ b/hotspot/src/share/vm/interpreter/bytecodes.cpp Tue Oct 13 18:13:34 2015 -0400
@@ -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 @@
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 );
--- a/hotspot/src/share/vm/interpreter/bytecodes.hpp Mon Apr 18 15:39:46 2016 -0700
+++ b/hotspot/src/share/vm/interpreter/bytecodes.hpp Tue Oct 13 18:13:34 2015 -0400
@@ -257,6 +257,7 @@
_fast_aputfield ,
_fast_bputfield ,
+ _fast_zputfield ,
_fast_cputfield ,
_fast_dputfield ,
_fast_fputfield ,
--- a/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp Mon Apr 18 15:39:46 2016 -0700
+++ b/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp Tue Oct 13 18:13:34 2015 -0400
@@ -1077,7 +1077,8 @@
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;
--- a/hotspot/src/share/vm/interpreter/templateInterpreter.cpp Mon Apr 18 15:39:46 2016 -0700
+++ b/hotspot/src/share/vm/interpreter/templateInterpreter.cpp Tue Oct 13 18:13:34 2015 -0400
@@ -89,8 +89,9 @@
// 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(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 @@
return
EntryPoint(
_table[btos][i],
+ _table[ztos][i],
_table[ctos][i],
_table[stos][i],
_table[atos][i],
@@ -169,8 +172,9 @@
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);
--- a/hotspot/src/share/vm/interpreter/templateInterpreter.hpp Mon Apr 18 15:39:46 2016 -0700
+++ b/hotspot/src/share/vm/interpreter/templateInterpreter.hpp Tue Oct 13 18:13:34 2015 -0400
@@ -47,7 +47,7 @@
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
--- a/hotspot/src/share/vm/interpreter/templateInterpreterGenerator.cpp Mon Apr 18 15:39:46 2016 -0700
+++ b/hotspot/src/share/vm/interpreter/templateInterpreterGenerator.cpp Tue Oct 13 18:13:34 2015 -0400
@@ -74,6 +74,7 @@
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 @@
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 @@
}
{ 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 @@
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 @@
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 @@
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 @@
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_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 @@
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 @@
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 @@
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.
--- a/hotspot/src/share/vm/interpreter/templateTable.cpp Mon Apr 18 15:39:46 2016 -0700
+++ b/hotspot/src/share/vm/interpreter/templateTable.cpp Tue Oct 13 18:13:34 2015 -0400
@@ -488,6 +488,7 @@
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 );
--- a/hotspot/src/share/vm/oops/constMethod.cpp Mon Apr 18 15:39:46 2016 -0700
+++ b/hotspot/src/share/vm/oops/constMethod.cpp Tue Oct 13 18:13:34 2015 -0400
@@ -66,6 +66,7 @@
set_max_locals(0);
set_method_idnum(0);
set_size_of_parameters(0);
+ set_result_type(T_VOID);
}
// Accessor that copies to metadata.
--- a/hotspot/src/share/vm/oops/constMethod.hpp Mon Apr 18 15:39:46 2016 -0700
+++ b/hotspot/src/share/vm/oops/constMethod.hpp Tue Oct 13 18:13:34 2015 -0400
@@ -210,6 +210,7 @@
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 @@
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 @@
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; }
--- a/hotspot/src/share/vm/oops/cpCache.hpp Mon Apr 18 15:39:46 2016 -0700
+++ b/hotspot/src/share/vm/oops/cpCache.hpp Tue Oct 13 18:13:34 2015 -0400
@@ -77,18 +77,19 @@
// 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 @@
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); }
--- a/hotspot/src/share/vm/oops/klass.hpp Mon Apr 18 15:39:46 2016 -0700
+++ b/hotspot/src/share/vm/oops/klass.hpp Tue Oct 13 18:13:34 2015 -0400
@@ -342,6 +342,21 @@
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;
--- a/hotspot/src/share/vm/oops/method.cpp Mon Apr 18 15:39:46 2016 -0700
+++ b/hotspot/src/share/vm/oops/method.cpp Tue Oct 13 18:13:34 2015 -0400
@@ -1220,10 +1220,8 @@
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(), "");
--- a/hotspot/src/share/vm/oops/oop.inline.hpp Mon Apr 18 15:39:46 2016 -0700
+++ b/hotspot/src/share/vm/oops/oop.inline.hpp Tue Oct 13 18:13:34 2015 -0400
@@ -443,7 +443,7 @@
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 @@
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); }
--- a/hotspot/src/share/vm/opto/memnode.cpp Mon Apr 18 15:39:46 2016 -0700
+++ b/hotspot/src/share/vm/opto/memnode.cpp Tue Oct 13 18:13:34 2015 -0400
@@ -2389,7 +2389,7 @@
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:
--- a/hotspot/src/share/vm/opto/parse1.cpp Mon Apr 18 15:39:46 2016 -0700
+++ b/hotspot/src/share/vm/opto/parse1.cpp Tue Oct 13 18:13:34 2015 -0400
@@ -730,6 +730,26 @@
#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 @@
// 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 @@
}
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);
}
--- a/hotspot/src/share/vm/opto/parse2.cpp Mon Apr 18 15:39:46 2016 -0700
+++ b/hotspot/src/share/vm/opto/parse2.cpp Tue Oct 13 18:13:34 2015 -0400
@@ -64,11 +64,15 @@
//--------------------------------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));
}
--- a/hotspot/src/share/vm/opto/type.cpp Mon Apr 18 15:39:46 2016 -0700
+++ b/hotspot/src/share/vm/opto/type.cpp Tue Oct 13 18:13:34 2015 -0400
@@ -1820,13 +1820,15 @@
break;
case T_OBJECT:
case T_ARRAY:
+ case T_FLOAT:
+ case T_INT:
+ field_array[pos++] = get_const_type(type);
+ break;
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);
+ field_array[pos++] = TypeInt::INT;
break;
default:
ShouldNotReachHere();
--- a/hotspot/src/share/vm/prims/jni.cpp Mon Apr 18 15:39:46 2016 -0700
+++ b/hotspot/src/share/vm/prims/jni.cpp Tue Oct 13 18:13:34 2015 -0400
@@ -2188,6 +2188,7 @@
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 @@
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
--- a/hotspot/src/share/vm/prims/jvmtiEnvBase.cpp Mon Apr 18 15:39:46 2016 -0700
+++ b/hotspot/src/share/vm/prims/jvmtiEnvBase.cpp Tue Oct 13 18:13:34 2015 -0400
@@ -1354,7 +1354,7 @@
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;
}
}
--- a/hotspot/src/share/vm/prims/jvmtiExport.cpp Mon Apr 18 15:39:46 2016 -0700
+++ b/hotspot/src/share/vm/prims/jvmtiExport.cpp Tue Oct 13 18:13:34 2015 -0400
@@ -1702,7 +1702,7 @@
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;
--- a/hotspot/src/share/vm/prims/unsafe.cpp Mon Apr 18 15:39:46 2016 -0700
+++ b/hotspot/src/share/vm/prims/unsafe.cpp Tue Oct 13 18:13:34 2015 -0400
@@ -133,13 +133,22 @@
///// 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 @@
#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.
--- a/hotspot/src/share/vm/runtime/reflection.cpp Mon Apr 18 15:39:46 2016 -0700
+++ b/hotspot/src/share/vm/runtime/reflection.cpp Tue Oct 13 18:13:34 2015 -0400
@@ -1025,7 +1025,7 @@
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;
--- a/hotspot/src/share/vm/utilities/globalDefinitions.hpp Mon Apr 18 15:39:46 2016 -0700
+++ b/hotspot/src/share/vm/utilities/globalDefinitions.hpp Tue Oct 13 18:13:34 2015 -0400
@@ -846,14 +846,15 @@
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 @@
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 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;