void TemplateTable::float_cmp(bool is_float, int unordered_result) {
if (is_float) {
__ fld_s(at_rsp());
} else {
__ fld_d(at_rsp());
__ pop(rdx);
}
__ pop(rcx);
__ fcmp2int(rax, unordered_result < 0);
}
void TemplateTable::branch(bool is_jsr, bool is_wide) {
__ get_method(rcx); // ECX holds method
__ profile_taken_branch(rax,rbx); // EAX holds updated MDP, EBX holds bumped taken count
const ByteSize be_offset = MethodCounters::backedge_counter_offset() +
InvocationCounter::counter_offset();
const ByteSize inv_offset = MethodCounters::invocation_counter_offset() +
InvocationCounter::counter_offset();
if (is_wide) {
__ movl(rdx, at_bcp(1));
} else {
__ load_signed_short(rdx, at_bcp(1));
}
__ bswapl(rdx);
if (!is_wide) __ sarl(rdx, 16);
LP64_ONLY(__ movslq(rdx, rdx));
if (is_jsr) {
__ load_unsigned_byte(rbx, Address(rsi, rdx, Address::times_1, 0));
__ lea(rax, at_bcp((is_wide ? 5 : 3) - in_bytes(ConstMethod::codes_offset())));
__ subptr(rax, Address(rcx, Method::const_offset()));
__ addptr(rsi, rdx);
__ push_i(rax);
__ dispatch_only_noverify(vtos);
return;
}
__ addptr(rsi, rdx);
assert(UseLoopCounter || !UseOnStackReplacement, "on-stack-replacement requires loop counters");
Label backedge_counter_overflow;
Label profile_method;
Label dispatch;
if (UseLoopCounter) {
__ testl(rdx, rdx); // check if forward or backward branch
__ jcc(Assembler::positive, dispatch); // count only if backward branch
Label has_counters;
__ movptr(rax, Address(rcx, Method::method_counters_offset()));
__ testptr(rax, rax);
__ jcc(Assembler::notZero, has_counters);
__ push(rdx);
__ push(rcx);
__ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::build_method_counters),
rcx);
__ pop(rcx);
__ pop(rdx);
__ movptr(rax, Address(rcx, Method::method_counters_offset()));
__ testptr(rax, rax);
__ jcc(Assembler::zero, dispatch);
__ bind(has_counters);
if (TieredCompilation) {
Label no_mdo;
int increment = InvocationCounter::count_increment;
int mask = ((1 << Tier0BackedgeNotifyFreqLog) - 1) << InvocationCounter::count_shift;
if (ProfileInterpreter) {
__ movptr(rbx, Address(rcx, in_bytes(Method::method_data_offset())));
__ testptr(rbx, rbx);
__ jccb(Assembler::zero, no_mdo);
const Address mdo_backedge_counter(rbx, in_bytes(MethodData::backedge_counter_offset()) +
in_bytes(InvocationCounter::counter_offset()));
__ increment_mask_and_jump(mdo_backedge_counter, increment, mask, rax, false, Assembler::zero,
UseOnStackReplacement ? &backedge_counter_overflow : NULL);
__ jmp(dispatch);
}
__ bind(no_mdo);
__ movptr(rcx, Address(rcx, Method::method_counters_offset()));
__ increment_mask_and_jump(Address(rcx, be_offset), increment, mask,
rax, false, Assembler::zero,
UseOnStackReplacement ? &backedge_counter_overflow : NULL);
} else {
__ movptr(rcx, Address(rcx, Method::method_counters_offset()));
__ movl(rax, Address(rcx, be_offset)); // load backedge counter
__ incrementl(rax, InvocationCounter::count_increment); // increment counter
__ movl(Address(rcx, be_offset), rax); // store counter
__ movl(rax, Address(rcx, inv_offset)); // load invocation counter
__ andl(rax, InvocationCounter::count_mask_value); // and the status bits
__ addl(rax, Address(rcx, be_offset)); // add both counters
if (ProfileInterpreter) {
__ cmp32(rax,
ExternalAddress((address) &InvocationCounter::InterpreterProfileLimit));
__ jcc(Assembler::less, dispatch);
__ test_method_data_pointer(rax, profile_method);
if (UseOnStackReplacement) {
__ cmp32(rbx,
ExternalAddress((address) &InvocationCounter::InterpreterBackwardBranchLimit));
__ jcc(Assembler::below, dispatch);
const int overflow_frequency = 1024;
__ andptr(rbx, overflow_frequency-1);
__ jcc(Assembler::zero, backedge_counter_overflow);
}
} else {
if (UseOnStackReplacement) {
__ cmp32(rax,
ExternalAddress((address) &InvocationCounter::InterpreterBackwardBranchLimit));
__ jcc(Assembler::aboveEqual, backedge_counter_overflow);
}
}
}
__ bind(dispatch);
}
__ load_unsigned_byte(rbx, Address(rsi, 0));
__ dispatch_only(vtos);
if (UseLoopCounter) {
if (ProfileInterpreter) {
__ bind(profile_method);
__ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::profile_method));
__ load_unsigned_byte(rbx, Address(rsi, 0)); // restore target bytecode
__ set_method_data_pointer_for_bcp();
__ jmp(dispatch);
}
if (UseOnStackReplacement) {
__ bind(backedge_counter_overflow);
__ negptr(rdx);
__ addptr(rdx, rsi); // branch bcp
call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::frequency_counter_overflow), rdx);
__ load_unsigned_byte(rbx, Address(rsi, 0)); // restore target bytecode
__ testptr(rax, rax); // test result
__ jcc(Assembler::zero, dispatch); // no osr if null
__ movl(rcx, Address(rax, nmethod::entry_bci_offset()));
__ cmpl(rcx, InvalidOSREntryBci);
__ jcc(Assembler::equal, dispatch);
__ mov(rbx, rax); // save the nmethod
const Register thread = rcx;
__ get_thread(thread);
call_VM(noreg, CAST_FROM_FN_PTR(address, SharedRuntime::OSR_migration_begin));
__ mov(rcx, rax);
__ movptr(rdx, Address(rbp, frame::interpreter_frame_sender_sp_offset * wordSize)); // get sender sp
__ leave(); // remove frame anchor
__ pop(rdi); // get return address
__ mov(rsp, rdx); // set sp to sender sp
__ andptr(rsp, -(StackAlignmentInBytes));
__ push(rdi);
__ jmp(Address(rbx, nmethod::osr_entry_point_offset()));
}
}
}
void TemplateTable::if_0cmp(Condition cc) {
transition(itos, vtos);
Label not_taken;
__ testl(rax, rax);
__ jcc(j_not(cc), not_taken);
branch(false, false);
__ bind(not_taken);
__ profile_not_taken_branch(rax);
}
void TemplateTable::if_icmp(Condition cc) {
transition(itos, vtos);
Label not_taken;
__ pop_i(rdx);
__ cmpl(rdx, rax);
__ jcc(j_not(cc), not_taken);
branch(false, false);
__ bind(not_taken);
__ profile_not_taken_branch(rax);
}
void TemplateTable::if_nullcmp(Condition cc) {
transition(atos, vtos);
Label not_taken;
__ testptr(rax, rax);
__ jcc(j_not(cc), not_taken);
branch(false, false);
__ bind(not_taken);
__ profile_not_taken_branch(rax);
}
void TemplateTable::if_acmp(Condition cc) {
transition(atos, vtos);
Label not_taken;
__ pop_ptr(rdx);
__ cmpptr(rdx, rax);
__ jcc(j_not(cc), not_taken);
branch(false, false);
__ bind(not_taken);
__ profile_not_taken_branch(rax);
}
void TemplateTable::ret() {
transition(vtos, vtos);
locals_index(rbx);
__ movptr(rbx, iaddress(rbx)); // get return bci, compute return bcp
__ profile_ret(rbx, rcx);
__ get_method(rax);
__ movptr(rsi, Address(rax, Method::const_offset()));
__ lea(rsi, Address(rsi, rbx, Address::times_1,
ConstMethod::codes_offset()));
__ dispatch_next(vtos);
}
void TemplateTable::wide_ret() {
transition(vtos, vtos);
locals_index_wide(rbx);
__ movptr(rbx, iaddress(rbx)); // get return bci, compute return bcp
__ profile_ret(rbx, rcx);
__ get_method(rax);
__ movptr(rsi, Address(rax, Method::const_offset()));
__ lea(rsi, Address(rsi, rbx, Address::times_1, ConstMethod::codes_offset()));
__ dispatch_next(vtos);
}
void TemplateTable::tableswitch() {
Label default_case, continue_execution;
transition(itos, vtos);
__ lea(rbx, at_bcp(wordSize));
__ andptr(rbx, -wordSize);
__ movl(rcx, Address(rbx, 1 * wordSize));
__ movl(rdx, Address(rbx, 2 * wordSize));
__ bswapl(rcx);
__ bswapl(rdx);
__ cmpl(rax, rcx);
__ jccb(Assembler::less, default_case);
__ cmpl(rax, rdx);
__ jccb(Assembler::greater, default_case);
__ subl(rax, rcx);
__ movl(rdx, Address(rbx, rax, Address::times_4, 3 * BytesPerInt));
__ profile_switch_case(rax, rbx, rcx);
__ bind(continue_execution);
__ bswapl(rdx);
__ load_unsigned_byte(rbx, Address(rsi, rdx, Address::times_1));
__ addptr(rsi, rdx);
__ dispatch_only(vtos);
__ bind(default_case);
__ profile_switch_default(rax);
__ movl(rdx, Address(rbx, 0));
__ jmp(continue_execution);
}
void TemplateTable::lookupswitch() {
transition(itos, itos);
__ stop("lookupswitch bytecode should have been rewritten");
}
void TemplateTable::fast_linearswitch() {
transition(itos, vtos);
Label loop_entry, loop, found, continue_execution;
__ bswapl(rax);
__ lea(rbx, at_bcp(wordSize)); // btw: should be able to get rid of this instruction (change offsets below)
__ andptr(rbx, -wordSize);
__ movl(rcx, Address(rbx, wordSize));
__ bswapl(rcx);
__ jmpb(loop_entry);
__ bind(loop);
__ cmpl(rax, Address(rbx, rcx, Address::times_8, 2 * wordSize));
__ jccb(Assembler::equal, found);
__ bind(loop_entry);
__ decrementl(rcx);
__ jcc(Assembler::greaterEqual, loop);
__ profile_switch_default(rax);
__ movl(rdx, Address(rbx, 0));
__ jmpb(continue_execution);
__ bind(found);
__ movl(rdx, Address(rbx, rcx, Address::times_8, 3 * wordSize));
__ profile_switch_case(rcx, rax, rbx);
__ bind(continue_execution);
__ bswapl(rdx);
__ load_unsigned_byte(rbx, Address(rsi, rdx, Address::times_1));
__ addptr(rsi, rdx);
__ dispatch_only(vtos);
}
void TemplateTable::fast_binaryswitch() {
transition(itos, vtos);
const Register key = rax; // already set (tosca)
const Register array = rbx;
const Register i = rcx;
const Register j = rdx;
const Register h = rdi; // needs to be restored
const Register temp = rsi;
__ save_bcp();
__ lea(array, at_bcp(3*wordSize)); // btw: should be able to get rid of this instruction (change offsets below)
__ andptr(array, -wordSize);
__ xorl(i, i); // i = 0;
__ movl(j, Address(array, -wordSize)); // j = length(array);
__ bswapl(j);
Label entry;
__ jmp(entry);
{ Label loop;
__ bind(loop);
__ leal(h, Address(i, j, Address::times_1)); // h = i + j;
__ sarl(h, 1); // h = (i + j) >> 1;
__ movl(temp, Address(array, h, Address::times_8, 0*wordSize));
__ bswapl(temp);
__ cmpl(key, temp);
__ cmov32(Assembler::less , j, h);
__ cmov32(Assembler::greaterEqual, i, h);
__ bind(entry);
__ leal(h, Address(i, 1)); // i+1
__ cmpl(h, j); // i+1 < j
__ jcc(Assembler::less, loop);
}
Label default_case;
__ movl(temp, Address(array, i, Address::times_8, 0*wordSize));
__ bswapl(temp);
__ cmpl(key, temp);
__ jcc(Assembler::notEqual, default_case);
__ movl(j , Address(array, i, Address::times_8, 1*wordSize));
__ profile_switch_case(i, key, array);
__ bswapl(j);
LP64_ONLY(__ movslq(j, j));
__ restore_bcp();
__ restore_locals(); // restore rdi
__ load_unsigned_byte(rbx, Address(rsi, j, Address::times_1));
__ addptr(rsi, j);
__ dispatch_only(vtos);
__ bind(default_case);
__ profile_switch_default(i);
__ movl(j, Address(array, -2*wordSize));
__ bswapl(j);
LP64_ONLY(__ movslq(j, j));
__ restore_bcp();
__ restore_locals(); // restore rdi
__ load_unsigned_byte(rbx, Address(rsi, j, Address::times_1));
__ addptr(rsi, j);
__ dispatch_only(vtos);
}
void TemplateTable::_return(TosState state) {
transition(state, state);
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");
__ movptr(rax, aaddress(0));
__ load_klass(rdi, rax);
__ movl(rdi, Address(rdi, Klass::access_flags_offset()));
__ testl(rdi, JVM_ACC_HAS_FINALIZER);
Label skip_register_finalizer;
__ jcc(Assembler::zero, skip_register_finalizer);
__ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::register_finalizer), rax);
__ bind(skip_register_finalizer);
}
if (state == itos) {
__ narrow(rax);
}
__ remove_activation(state, rsi);
__ jmp(rsi);
}
void TemplateTable::volatile_barrier(Assembler::Membar_mask_bits order_constraint ) {
if( !os::is_MP() ) return; // Not needed on single CPU
__ membar(order_constraint);
}
void TemplateTable::resolve_cache_and_index(int byte_no,
Register Rcache,
Register index,
size_t index_size) {
const Register temp = rbx;
assert_different_registers(Rcache, index, temp);
Label resolved;
assert(byte_no == f1_byte || byte_no == f2_byte, "byte_no out of range");
__ get_cache_and_index_and_bytecode_at_bcp(Rcache, index, temp, byte_no, 1, index_size);
__ cmpl(temp, (int) bytecode()); // have we resolved this bytecode?
__ jcc(Assembler::equal, resolved);
address entry;
switch (bytecode()) {
case Bytecodes::_getstatic : // fall through
case Bytecodes::_putstatic : // fall through
case Bytecodes::_getfield : // fall through
case Bytecodes::_putfield : entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_get_put); break;
case Bytecodes::_invokevirtual : // fall through
case Bytecodes::_invokespecial : // fall through
case Bytecodes::_invokestatic : // fall through
case Bytecodes::_invokeinterface: entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_invoke); break;
case Bytecodes::_invokehandle : entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_invokehandle); break;
case Bytecodes::_invokedynamic : entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_invokedynamic); break;
default:
fatal(err_msg("unexpected bytecode: %s", Bytecodes::name(bytecode())));
break;
}
__ movl(temp, (int)bytecode());
__ call_VM(noreg, entry, temp);
__ get_cache_and_index_at_bcp(Rcache, index, 1, index_size);
__ bind(resolved);
}
void TemplateTable::load_field_cp_cache_entry(Register obj,
Register cache,
Register index,
Register off,
Register flags,
bool is_static = false) {
assert_different_registers(cache, index, flags, off);
ByteSize cp_base_offset = ConstantPoolCache::base_offset();
__ movptr(off, Address(cache, index, Address::times_ptr,
in_bytes(cp_base_offset + ConstantPoolCacheEntry::f2_offset())));
__ movl(flags, Address(cache, index, Address::times_ptr,
in_bytes(cp_base_offset + ConstantPoolCacheEntry::flags_offset())));
if (is_static) {
__ movptr(obj, Address(cache, index, Address::times_ptr,
in_bytes(cp_base_offset + ConstantPoolCacheEntry::f1_offset())));
const int mirror_offset = in_bytes(Klass::java_mirror_offset());
__ movptr(obj, Address(obj, mirror_offset));
}
}
void TemplateTable::load_invoke_cp_cache_entry(int byte_no,
Register method,
Register itable_index,
Register flags,
bool is_invokevirtual,
bool is_invokevfinal, /*unused*/
bool is_invokedynamic) {
const Register cache = rcx;
const Register index = rdx;
assert_different_registers(method, flags);
assert_different_registers(method, cache, index);
assert_different_registers(itable_index, flags);
assert_different_registers(itable_index, cache, index);
assert(is_invokevirtual == (byte_no == f2_byte), "is_invokevirtual flag redundant");
const int method_offset = in_bytes(
ConstantPoolCache::base_offset() +
((byte_no == f2_byte)
? ConstantPoolCacheEntry::f2_offset()
: ConstantPoolCacheEntry::f1_offset()));
const int flags_offset = in_bytes(ConstantPoolCache::base_offset() +
ConstantPoolCacheEntry::flags_offset());
const int index_offset = in_bytes(ConstantPoolCache::base_offset() +
ConstantPoolCacheEntry::f2_offset());
size_t index_size = (is_invokedynamic ? sizeof(u4) : sizeof(u2));
resolve_cache_and_index(byte_no, cache, index, index_size);
__ movptr(method, Address(cache, index, Address::times_ptr, method_offset));
if (itable_index != noreg) {
__ movptr(itable_index, Address(cache, index, Address::times_ptr, index_offset));
}
__ movl(flags, Address(cache, index, Address::times_ptr, flags_offset));
}
void TemplateTable::jvmti_post_field_access(Register cache,
Register index,
bool is_static,
bool has_tos) {
if (JvmtiExport::can_post_field_access()) {
Label L1;
assert_different_registers(cache, index, rax);
__ mov32(rax, ExternalAddress((address) JvmtiExport::get_field_access_count_addr()));
__ testl(rax,rax);
__ jcc(Assembler::zero, L1);
__ addptr(cache, in_bytes(ConstantPoolCache::base_offset()));
__ shll(index, LogBytesPerWord);
__ addptr(cache, index);
if (is_static) {
__ xorptr(rax, rax); // NULL object reference
} else {
__ pop(atos); // Get the object
__ verify_oop(rax);
__ push(atos); // Restore stack state
}
__ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::post_field_access),
rax, cache);
__ get_cache_and_index_at_bcp(cache, index, 1);
__ bind(L1);
}
}
void TemplateTable::pop_and_check_object(Register r) {
__ pop_ptr(r);
__ null_check(r); // for field access must check obj.
__ verify_oop(r);
}
void TemplateTable::getfield_or_static(int byte_no, bool is_static) {
transition(vtos, vtos);
const Register cache = rcx;
const Register index = rdx;
const Register obj = rcx;
const Register off = rbx;
const Register flags = rax;
resolve_cache_and_index(byte_no, cache, index, sizeof(u2));
jvmti_post_field_access(cache, index, is_static, false);
load_field_cp_cache_entry(obj, cache, index, off, flags, is_static);
if (!is_static) pop_and_check_object(obj);
const Address lo(obj, off, Address::times_1, 0*wordSize);
const Address hi(obj, off, Address::times_1, 1*wordSize);
Label Done, notByte, notBool, notInt, notShort, notChar, notLong, notFloat, notObj, notDouble;
__ shrl(flags, ConstantPoolCacheEntry::tos_state_shift);
assert(btos == 0, "change code, btos != 0");
__ andptr(flags, ConstantPoolCacheEntry::tos_state_mask);
__ jcc(Assembler::notZero, notByte);
__ load_signed_byte(rax, lo );
__ push(btos);
if (!is_static) {
patch_bytecode(Bytecodes::_fast_bgetfield, rcx, rbx);
}
__ jmp(Done);
__ bind(notByte);
__ cmpl(flags, ztos);
__ jcc(Assembler::notEqual, notBool);
__ load_signed_byte(rax, lo);
__ push(ztos);
if (!is_static) {
patch_bytecode(Bytecodes::_fast_bgetfield, rcx, rbx);
}
__ jmp(Done);
__ bind(notBool);
__ cmpl(flags, itos );
__ jcc(Assembler::notEqual, notInt);
__ movl(rax, lo );
__ push(itos);
if (!is_static) {
patch_bytecode(Bytecodes::_fast_igetfield, rcx, rbx);
}
__ jmp(Done);
__ bind(notInt);
__ cmpl(flags, atos );
__ jcc(Assembler::notEqual, notObj);
__ movl(rax, lo );
__ push(atos);
if (!is_static) {
patch_bytecode(Bytecodes::_fast_agetfield, rcx, rbx);
}
__ jmp(Done);
__ bind(notObj);
__ cmpl(flags, ctos );
__ jcc(Assembler::notEqual, notChar);
__ load_unsigned_short(rax, lo );
__ push(ctos);
if (!is_static) {
patch_bytecode(Bytecodes::_fast_cgetfield, rcx, rbx);
}
__ jmp(Done);
__ bind(notChar);
__ cmpl(flags, stos );
__ jcc(Assembler::notEqual, notShort);
__ load_signed_short(rax, lo );
__ push(stos);
if (!is_static) {
patch_bytecode(Bytecodes::_fast_sgetfield, rcx, rbx);
}
__ jmp(Done);
__ bind(notShort);
__ cmpl(flags, ltos );
__ jcc(Assembler::notEqual, notLong);
__ fild_d(lo); // Must load atomically
__ subptr(rsp,2*wordSize); // Make space for store
__ fistp_d(Address(rsp,0));
__ pop(rax);
__ pop(rdx);
__ push(ltos);
__ jmp(Done);
__ bind(notLong);
__ cmpl(flags, ftos );
__ jcc(Assembler::notEqual, notFloat);
__ fld_s(lo);
__ push(ftos);
if (!is_static) {
patch_bytecode(Bytecodes::_fast_fgetfield, rcx, rbx);
}
__ jmp(Done);
__ bind(notFloat);
__ cmpl(flags, dtos );
__ jcc(Assembler::notEqual, notDouble);
__ fld_d(lo);
__ push(dtos);
if (!is_static) {
patch_bytecode(Bytecodes::_fast_dgetfield, rcx, rbx);
}
__ jmpb(Done);
__ bind(notDouble);
__ stop("Bad state");
__ bind(Done);
}
void TemplateTable::getfield(int byte_no) {
getfield_or_static(byte_no, false);
}
void TemplateTable::getstatic(int byte_no) {
getfield_or_static(byte_no, true);
}
void TemplateTable::jvmti_post_field_mod(Register cache, Register index, bool is_static) {
ByteSize cp_base_offset = ConstantPoolCache::base_offset();
if (JvmtiExport::can_post_field_modification()) {
Label L1;
assert_different_registers(cache, index, rax);
__ mov32(rax, ExternalAddress((address)JvmtiExport::get_field_modification_count_addr()));
__ testl(rax, rax);
__ jcc(Assembler::zero, L1);
__ get_cache_and_index_at_bcp(rax, rdx, 1);
if (is_static) {
__ xorptr(rbx, rbx);
} else {
Label two_word, valsize_known;
__ movl(rcx, Address(rax, rdx, Address::times_ptr, in_bytes(cp_base_offset +
ConstantPoolCacheEntry::flags_offset())));
__ mov(rbx, rsp);
__ shrl(rcx, ConstantPoolCacheEntry::tos_state_shift);
ConstantPoolCacheEntry::verify_tos_state_shift();
__ cmpl(rcx, ltos);
__ jccb(Assembler::equal, two_word);
__ cmpl(rcx, dtos);
__ jccb(Assembler::equal, two_word);
__ addptr(rbx, Interpreter::expr_offset_in_bytes(1)); // one word jvalue (not ltos, dtos)
__ jmpb(valsize_known);
__ bind(two_word);
__ addptr(rbx, Interpreter::expr_offset_in_bytes(2)); // two words jvalue
__ bind(valsize_known);
__ movptr(rbx, Address(rbx, 0));
}
__ addptr(rax, in_bytes(cp_base_offset));
__ shll(rdx, LogBytesPerWord);
__ addptr(rax, rdx);
__ mov(rcx, rsp);
__ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::post_field_modification),
rbx, rax, rcx);
__ get_cache_and_index_at_bcp(cache, index, 1);
__ bind(L1);
}
}
void TemplateTable::putfield_or_static(int byte_no, bool is_static) {
transition(vtos, vtos);
const Register cache = rcx;
const Register index = rdx;
const Register obj = rcx;
const Register off = rbx;
const Register flags = rax;
resolve_cache_and_index(byte_no, cache, index, sizeof(u2));
jvmti_post_field_mod(cache, index, is_static);
load_field_cp_cache_entry(obj, cache, index, off, flags, is_static);
Label notVolatile, Done;
__ movl(rdx, flags);
__ shrl(rdx, ConstantPoolCacheEntry::is_volatile_shift);
__ andl(rdx, 0x1);
const Address lo(obj, off, Address::times_1, 0*wordSize);
const Address hi(obj, off, Address::times_1, 1*wordSize);
Label notByte, notBool, notInt, notShort, notChar, notLong, notFloat, notObj, notDouble;
__ shrl(flags, ConstantPoolCacheEntry::tos_state_shift);
assert(btos == 0, "change code, btos != 0");
__ andl(flags, ConstantPoolCacheEntry::tos_state_mask);
__ jcc(Assembler::notZero, notByte);
{
__ pop(btos);
if (!is_static) pop_and_check_object(obj);
__ movb(lo, rax);
if (!is_static) {
patch_bytecode(Bytecodes::_fast_bputfield, rcx, rbx, true, byte_no);
}
__ jmp(Done);
}
__ bind(notByte);
__ cmpl(flags, ztos);
__ jcc(Assembler::notEqual, notBool);
{
__ pop(ztos);
if (!is_static) pop_and_check_object(obj);
__ andl(rax, 0x1);
__ movb(lo, rax);
if (!is_static) {
patch_bytecode(Bytecodes::_fast_zputfield, rcx, rbx, true, byte_no);
}
__ jmp(Done);
}
__ bind(notBool);
__ cmpl(flags, itos);
__ jcc(Assembler::notEqual, notInt);
{
__ pop(itos);
if (!is_static) pop_and_check_object(obj);
__ movl(lo, rax);
if (!is_static) {
patch_bytecode(Bytecodes::_fast_iputfield, rcx, rbx, true, byte_no);
}
__ jmp(Done);
}
__ bind(notInt);
__ cmpl(flags, atos);
__ jcc(Assembler::notEqual, notObj);
{
__ pop(atos);
if (!is_static) pop_and_check_object(obj);
do_oop_store(_masm, lo, rax, _bs->kind(), false);
if (!is_static) {
patch_bytecode(Bytecodes::_fast_aputfield, rcx, rbx, true, byte_no);
}
__ jmp(Done);
}
__ bind(notObj);
__ cmpl(flags, ctos);
__ jcc(Assembler::notEqual, notChar);
{
__ pop(ctos);
if (!is_static) pop_and_check_object(obj);
__ movw(lo, rax);
if (!is_static) {
patch_bytecode(Bytecodes::_fast_cputfield, rcx, rbx, true, byte_no);
}
__ jmp(Done);
}
__ bind(notChar);
__ cmpl(flags, stos);
__ jcc(Assembler::notEqual, notShort);
{
__ pop(stos);
if (!is_static) pop_and_check_object(obj);
__ movw(lo, rax);
if (!is_static) {
patch_bytecode(Bytecodes::_fast_sputfield, rcx, rbx, true, byte_no);
}
__ jmp(Done);
}
__ bind(notShort);
__ cmpl(flags, ltos);
__ jcc(Assembler::notEqual, notLong);
{
Label notVolatileLong;
__ testl(rdx, rdx);
__ jcc(Assembler::zero, notVolatileLong);
__ pop(ltos); // overwrites rdx, do this after testing volatile.
if (!is_static) pop_and_check_object(obj);
__ push(rdx);
__ push(rax); // Must update atomically with FIST
__ fild_d(Address(rsp,0)); // So load into FPU register
__ fistp_d(lo); // and put into memory atomically
__ addptr(rsp, 2*wordSize);
volatile_barrier(Assembler::Membar_mask_bits(Assembler::StoreLoad |
Assembler::StoreStore));
__ jmp(notVolatile);
__ bind(notVolatileLong);
__ pop(ltos); // overwrites rdx
if (!is_static) pop_and_check_object(obj);
NOT_LP64(__ movptr(hi, rdx));
__ movptr(lo, rax);
if (!is_static) {
patch_bytecode(Bytecodes::_fast_lputfield, rcx, rbx, true, byte_no);
}
__ jmp(notVolatile);
}
__ bind(notLong);
__ cmpl(flags, ftos);
__ jcc(Assembler::notEqual, notFloat);
{
__ pop(ftos);
if (!is_static) pop_and_check_object(obj);
__ fstp_s(lo);
if (!is_static) {
patch_bytecode(Bytecodes::_fast_fputfield, rcx, rbx, true, byte_no);
}
__ jmp(Done);
}
__ bind(notFloat);
#ifdef ASSERT
__ cmpl(flags, dtos);
__ jcc(Assembler::notEqual, notDouble);
#endif
{
__ pop(dtos);
if (!is_static) pop_and_check_object(obj);
__ fstp_d(lo);
if (!is_static) {
patch_bytecode(Bytecodes::_fast_dputfield, rcx, rbx, true, byte_no);
}
__ jmp(Done);
}
#ifdef ASSERT
__ bind(notDouble);
__ stop("Bad state");
#endif
__ bind(Done);
__ testl(rdx, rdx);
__ jcc(Assembler::zero, notVolatile);
volatile_barrier(Assembler::Membar_mask_bits(Assembler::StoreLoad |
Assembler::StoreStore));
__ bind(notVolatile);
}
void TemplateTable::putfield(int byte_no) {
putfield_or_static(byte_no, false);
}
void TemplateTable::putstatic(int byte_no) {
putfield_or_static(byte_no, true);
}
void TemplateTable::jvmti_post_fast_field_mod() {
if (JvmtiExport::can_post_field_modification()) {
Label L2;
__ mov32(rcx, ExternalAddress((address)JvmtiExport::get_field_modification_count_addr()));
__ testl(rcx,rcx);
__ jcc(Assembler::zero, L2);
__ pop_ptr(rbx); // copy the object pointer from tos
__ verify_oop(rbx);
__ push_ptr(rbx); // put the object pointer back on tos
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;
case Bytecodes::_fast_dputfield: __ push_d(); break;
case Bytecodes::_fast_fputfield: __ push_f(); break;
case Bytecodes::_fast_lputfield: __ push_l(rax); break;
default:
ShouldNotReachHere();
}
__ mov(rcx, rsp); // points to jvalue on the stack
__ get_cache_entry_pointer_at_bcp(rax, rdx, 1);
__ verify_oop(rbx);
__ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::post_field_modification), rbx, rax, rcx);
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;
case Bytecodes::_fast_dputfield: __ pop_d(); break;
case Bytecodes::_fast_fputfield: __ pop_f(); break;
case Bytecodes::_fast_lputfield: __ pop_l(rax); break;
}
__ bind(L2);
}
}
void TemplateTable::fast_storefield(TosState state) {
transition(state, vtos);
ByteSize base = ConstantPoolCache::base_offset();
jvmti_post_fast_field_mod();
__ get_cache_and_index_at_bcp(rcx, rbx, 1);
if (bytecode() == Bytecodes::_fast_lputfield) __ push(rdx);
__ movl(rdx, Address(rcx, rbx, Address::times_ptr, in_bytes(base +
ConstantPoolCacheEntry::flags_offset())));
__ movptr(rbx, Address(rcx, rbx, Address::times_ptr, in_bytes(base + ConstantPoolCacheEntry::f2_offset())));
Label notVolatile, Done;
__ shrl(rdx, ConstantPoolCacheEntry::is_volatile_shift);
__ andl(rdx, 0x1);
__ testl(rdx, rdx);
__ jcc(Assembler::zero, notVolatile);
if (bytecode() == Bytecodes::_fast_lputfield) __ pop(rdx);
pop_and_check_object(rcx);
const Address lo(rcx, rbx, Address::times_1, 0*wordSize);
const Address hi(rcx, rbx, Address::times_1, 1*wordSize);
switch (bytecode()) {
case Bytecodes::_fast_zputfield: __ andl(rax, 0x1); // boolean is true if LSB is 1
case Bytecodes::_fast_bputfield: __ movb(lo, rax); break;
case Bytecodes::_fast_sputfield: // fall through
case Bytecodes::_fast_cputfield: __ movw(lo, rax); break;
case Bytecodes::_fast_iputfield: __ movl(lo, rax); break;
case Bytecodes::_fast_lputfield:
NOT_LP64(__ movptr(hi, rdx));
__ movptr(lo, rax);
break;
case Bytecodes::_fast_fputfield: __ fstp_s(lo); break;
case Bytecodes::_fast_dputfield: __ fstp_d(lo); break;
case Bytecodes::_fast_aputfield: {
do_oop_store(_masm, lo, rax, _bs->kind(), false);
break;
}
default:
ShouldNotReachHere();
}
Label done;
volatile_barrier(Assembler::Membar_mask_bits(Assembler::StoreLoad |
Assembler::StoreStore));
__ jmp(done);
__ bind(notVolatile);
if (bytecode() == Bytecodes::_fast_lputfield) __ pop(rdx);
pop_and_check_object(rcx);
switch (bytecode()) {
case Bytecodes::_fast_zputfield: __ andl(rax, 0x1); // boolean is true if LSB is 1
case Bytecodes::_fast_bputfield: __ movb(lo, rax); break;
case Bytecodes::_fast_sputfield: // fall through
case Bytecodes::_fast_cputfield: __ movw(lo, rax); break;
case Bytecodes::_fast_iputfield: __ movl(lo, rax); break;
case Bytecodes::_fast_lputfield:
NOT_LP64(__ movptr(hi, rdx));
__ movptr(lo, rax);
break;
case Bytecodes::_fast_fputfield: __ fstp_s(lo); break;
case Bytecodes::_fast_dputfield: __ fstp_d(lo); break;
case Bytecodes::_fast_aputfield: {
do_oop_store(_masm, lo, rax, _bs->kind(), false);
break;
}
default:
ShouldNotReachHere();
}
__ bind(done);
}
void TemplateTable::fast_accessfield(TosState state) {
transition(atos, state);
if (JvmtiExport::can_post_field_access()) {
Label L1;
__ mov32(rcx, ExternalAddress((address) JvmtiExport::get_field_access_count_addr()));
__ testl(rcx,rcx);
__ jcc(Assembler::zero, L1);
__ get_cache_entry_pointer_at_bcp(rcx, rdx, 1);
__ push_ptr(rax); // save object pointer before call_VM() clobbers it
__ verify_oop(rax);
__ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::post_field_access), rax, rcx);
__ pop_ptr(rax); // restore object pointer
__ bind(L1);
}
__ get_cache_and_index_at_bcp(rcx, rbx, 1);
__ movptr(rbx, Address(rcx,
rbx,
Address::times_ptr,
in_bytes(ConstantPoolCache::base_offset() + ConstantPoolCacheEntry::f2_offset())));
__ verify_oop(rax);
__ null_check(rax);
const Address lo = Address(rax, rbx, Address::times_1, 0*wordSize);
const Address hi = Address(rax, rbx, Address::times_1, 1*wordSize);
switch (bytecode()) {
case Bytecodes::_fast_bgetfield: __ movsbl(rax, lo ); break;
case Bytecodes::_fast_sgetfield: __ load_signed_short(rax, lo ); break;
case Bytecodes::_fast_cgetfield: __ load_unsigned_short(rax, lo ); break;
case Bytecodes::_fast_igetfield: __ movl(rax, lo); break;
case Bytecodes::_fast_lgetfield: __ stop("should not be rewritten"); break;
case Bytecodes::_fast_fgetfield: __ fld_s(lo); break;
case Bytecodes::_fast_dgetfield: __ fld_d(lo); break;
case Bytecodes::_fast_agetfield: __ movptr(rax, lo); __ verify_oop(rax); break;
default:
ShouldNotReachHere();
}
}
void TemplateTable::fast_xaccess(TosState state) {
transition(vtos, state);
__ movptr(rax, aaddress(0));
__ get_cache_and_index_at_bcp(rcx, rdx, 2);
__ movptr(rbx, Address(rcx,
rdx,
Address::times_ptr,
in_bytes(ConstantPoolCache::base_offset() + ConstantPoolCacheEntry::f2_offset())));
__ increment(rsi);
__ null_check(rax);
const Address lo = Address(rax, rbx, Address::times_1, 0*wordSize);
if (state == itos) {
__ movl(rax, lo);
} else if (state == atos) {
__ movptr(rax, lo);
__ verify_oop(rax);
} else if (state == ftos) {
__ fld_s(lo);
} else {
ShouldNotReachHere();
}
__ decrement(rsi);
}
void TemplateTable::count_calls(Register method, Register temp) {
ShouldNotReachHere();
}
void TemplateTable::prepare_invoke(int byte_no,
Register method, // linked method (or i-klass)
Register index, // itable index, MethodType, etc.
Register recv, // if caller wants to see it
Register flags // if caller wants to test it
) {
const Bytecodes::Code code = bytecode();
const bool is_invokeinterface = code == Bytecodes::_invokeinterface;
const bool is_invokedynamic = code == Bytecodes::_invokedynamic;
const bool is_invokehandle = code == Bytecodes::_invokehandle;
const bool is_invokevirtual = code == Bytecodes::_invokevirtual;
const bool is_invokespecial = code == Bytecodes::_invokespecial;
const bool load_receiver = (recv != noreg);
const bool save_flags = (flags != noreg);
assert(load_receiver == (code != Bytecodes::_invokestatic && code != Bytecodes::_invokedynamic), "");
assert(save_flags == (is_invokeinterface || is_invokevirtual), "need flags for vfinal");
assert(flags == noreg || flags == rdx, "");
assert(recv == noreg || recv == rcx, "");
if (recv == noreg) recv = rcx;
if (flags == noreg) flags = rdx;
assert_different_registers(method, index, recv, flags);
__ save_bcp();
load_invoke_cp_cache_entry(byte_no, method, index, flags, is_invokevirtual, false, is_invokedynamic);
if (is_invokedynamic || is_invokehandle) {
Label L_no_push;
__ testl(flags, (1 << ConstantPoolCacheEntry::has_appendix_shift));
__ jccb(Assembler::zero, L_no_push);
__ push(rbx);
__ mov(rbx, index);
assert(ConstantPoolCacheEntry::_indy_resolved_references_appendix_offset == 0, "appendix expected at index+0");
__ load_resolved_reference_at_index(index, rbx);
__ pop(rbx);
__ push(index); // push appendix (MethodType, CallSite, etc.)
__ bind(L_no_push);
}
if (load_receiver) {
__ movl(recv, flags);
__ andl(recv, ConstantPoolCacheEntry::parameter_size_mask);
const int no_return_pc_pushed_yet = -1; // argument slot correction before we push return address
const int receiver_is_at_end = -1; // back off one slot to get receiver
Address recv_addr = __ argument_address(recv, no_return_pc_pushed_yet + receiver_is_at_end);
__ movptr(recv, recv_addr);
__ verify_oop(recv);
}
if (save_flags) {
__ mov(rsi, flags);
}
__ shrl(flags, ConstantPoolCacheEntry::tos_state_shift);
ConstantPoolCacheEntry::verify_tos_state_shift();
{
const address table_addr = (address) Interpreter::invoke_return_entry_table_for(code);
ExternalAddress table(table_addr);
__ movptr(flags, ArrayAddress(table, Address(noreg, flags, Address::times_ptr)));
}
__ push(flags);
if (save_flags) {
__ mov(flags, rsi);
__ restore_bcp();
}
}
void TemplateTable::invokevirtual_helper(Register index,
Register recv,
Register flags) {
assert_different_registers(index, recv, rax, rdx);
assert(index == rbx, "");
assert(recv == rcx, "");
Label notFinal;
__ movl(rax, flags);
__ andl(rax, (1 << ConstantPoolCacheEntry::is_vfinal_shift));
__ jcc(Assembler::zero, notFinal);
const Register method = index; // method must be rbx
assert(method == rbx,
"Method* must be rbx for interpreter calling convention");
__ null_check(recv);
__ profile_final_call(rax);
__ profile_arguments_type(rax, method, rsi, true);
__ jump_from_interpreted(method, rax);
__ bind(notFinal);
__ null_check(recv, oopDesc::klass_offset_in_bytes());
__ load_klass(rax, recv);
__ profile_virtual_call(rax, rdi, rdx);
__ lookup_virtual_method(rax, index, method);
__ profile_arguments_type(rdx, method, rsi, true);
__ jump_from_interpreted(method, rdx);
}
void TemplateTable::invokevirtual(int byte_no) {
transition(vtos, vtos);
assert(byte_no == f2_byte, "use this argument");
prepare_invoke(byte_no,
rbx, // method or vtable index
noreg, // unused itable index
rcx, rdx); // recv, flags
invokevirtual_helper(rbx, rcx, rdx);
}
void TemplateTable::invokespecial(int byte_no) {
transition(vtos, vtos);
assert(byte_no == f1_byte, "use this argument");
prepare_invoke(byte_no, rbx, noreg, // get f1 Method*
rcx); // get receiver also for null check
__ verify_oop(rcx);
__ null_check(rcx);
__ profile_call(rax);
__ profile_arguments_type(rax, rbx, rsi, false);
__ jump_from_interpreted(rbx, rax);
}
void TemplateTable::invokestatic(int byte_no) {
transition(vtos, vtos);
assert(byte_no == f1_byte, "use this argument");
prepare_invoke(byte_no, rbx); // get f1 Method*
__ profile_call(rax);
__ profile_arguments_type(rax, rbx, rsi, false);
__ jump_from_interpreted(rbx, rax);
}
void TemplateTable::fast_invokevfinal(int byte_no) {
transition(vtos, vtos);
assert(byte_no == f2_byte, "use this argument");
__ stop("fast_invokevfinal not used on x86");
}
void TemplateTable::invokeinterface(int byte_no) {
transition(vtos, vtos);
assert(byte_no == f1_byte, "use this argument");
prepare_invoke(byte_no, rax, rbx, // get f1 Klass*, f2 Method*
rcx, rdx); // recv, flags
Label notMethod;
__ movl(rdi, rdx);
__ andl(rdi, (1 << ConstantPoolCacheEntry::is_forced_virtual_shift));
__ jcc(Assembler::zero, notMethod);
invokevirtual_helper(rbx, rcx, rdx);
__ bind(notMethod);
__ restore_locals(); // restore rdi
__ null_check(rcx, oopDesc::klass_offset_in_bytes());
__ load_klass(rdx, rcx);
Label no_such_interface, no_such_method;
__ lookup_interface_method(// inputs: rec. class, interface, itable index
rdx, rax, noreg,
rsi, rdi,
no_such_interface,
__ restore_bcp(); // rbcp was destroyed by receiver type check
__ profile_virtual_call(rdx, rsi, rdi);
__ movptr(rax, Address(rbx, Method::const_offset()));
__ movptr(rax, Address(rax, ConstMethod::constants_offset()));
__ movptr(rax, Address(rax, ConstantPool::pool_holder_offset_in_bytes()));
__ movl(rbx, Address(rbx, Method::itable_index_offset()));
__ subl(rbx, Method::itable_index_max);
__ negl(rbx);
__ lookup_interface_method(// inputs: rec. class, interface, itable index
rdx, rax, rbx,
rbx, rsi,
no_such_interface);
__ testptr(rbx, rbx);
__ jcc(Assembler::zero, no_such_method);
__ profile_arguments_type(rdx, rbx, rsi, true);
__ jump_from_interpreted(rbx, rdx);
__ should_not_reach_here();
__ bind(no_such_method);
__ pop(rbx); // pop return address (pushed by prepare_invoke)
__ restore_bcp(); // rsi must be correct for exception handler (was destroyed)
__ restore_locals(); // make sure locals pointer is correct as well (was destroyed)
__ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_AbstractMethodError));
__ should_not_reach_here();
__ bind(no_such_interface);
__ pop(rbx); // pop return address (pushed by prepare_invoke)
__ restore_bcp(); // rsi must be correct for exception handler (was destroyed)
__ restore_locals(); // make sure locals pointer is correct as well (was destroyed)
__ call_VM(noreg, CAST_FROM_FN_PTR(address,
InterpreterRuntime::throw_IncompatibleClassChangeError));
__ should_not_reach_here();
}
void TemplateTable::invokehandle(int byte_no) {
transition(vtos, vtos);
assert(byte_no == f1_byte, "use this argument");
const Register rbx_method = rbx;
const Register rax_mtype = rax;
const Register rcx_recv = rcx;
const Register rdx_flags = rdx;
if (!EnableInvokeDynamic) {
__ should_not_reach_here();
return;
}
prepare_invoke(byte_no, rbx_method, rax_mtype, rcx_recv);
__ verify_method_ptr(rbx_method);
__ verify_oop(rcx_recv);
__ null_check(rcx_recv);
__ profile_final_call(rax);
__ profile_arguments_type(rdx, rbx_method, rsi, true);
__ jump_from_interpreted(rbx_method, rdx);
}
void TemplateTable::invokedynamic(int byte_no) {
transition(vtos, vtos);
assert(byte_no == f1_byte, "use this argument");
if (!EnableInvokeDynamic) {
__ call_VM(noreg, CAST_FROM_FN_PTR(address,
InterpreterRuntime::throw_IncompatibleClassChangeError));
__ should_not_reach_here();
return;
}
const Register rbx_method = rbx;
const Register rax_callsite = rax;
prepare_invoke(byte_no, rbx_method, rax_callsite);
__ profile_call(rsi);
__ profile_arguments_type(rdx, rbx, rsi, false);
__ verify_oop(rax_callsite);
__ jump_from_interpreted(rbx_method, rdx);
}
void TemplateTable::_new() {
transition(vtos, atos);
__ get_unsigned_2_byte_index_at_bcp(rdx, 1);
Label slow_case;
Label slow_case_no_pop;
Label done;
Label initialize_header;
Label initialize_object; // including clearing the fields
Label allocate_shared;
__ get_cpool_and_tags(rcx, rax);
const int tags_offset = Array<u1>::base_offset_in_bytes();
__ cmpb(Address(rax, rdx, Address::times_1, tags_offset), JVM_CONSTANT_Class);
__ jcc(Assembler::notEqual, slow_case_no_pop);
__ movptr(rcx, Address(rcx, rdx, Address::times_ptr, sizeof(ConstantPool)));
__ push(rcx); // save the contexts of klass for initializing the header
__ cmpb(Address(rcx, InstanceKlass::init_state_offset()), InstanceKlass::fully_initialized);
__ jcc(Assembler::notEqual, slow_case);
__ movl(rdx, Address(rcx, Klass::layout_helper_offset()));
__ testl(rdx, Klass::_lh_instance_slow_path_bit);
__ jcc(Assembler::notZero, slow_case);
const bool allow_shared_alloc =
Universe::heap()->supports_inline_contig_alloc() && !CMSIncrementalMode;
const Register thread = rcx;
if (UseTLAB || allow_shared_alloc) {
__ get_thread(thread);
}
if (UseTLAB) {
__ movptr(rax, Address(thread, in_bytes(JavaThread::tlab_top_offset())));
__ lea(rbx, Address(rax, rdx, Address::times_1));
__ cmpptr(rbx, Address(thread, in_bytes(JavaThread::tlab_end_offset())));
__ jcc(Assembler::above, allow_shared_alloc ? allocate_shared : slow_case);
__ movptr(Address(thread, in_bytes(JavaThread::tlab_top_offset())), rbx);
if (ZeroTLAB) {
__ jmp(initialize_header);
} else {
__ jmp(initialize_object);
}
}
if (allow_shared_alloc) {
__ bind(allocate_shared);
ExternalAddress heap_top((address)Universe::heap()->top_addr());
Label retry;
__ bind(retry);
__ movptr(rax, heap_top);
__ lea(rbx, Address(rax, rdx, Address::times_1));
__ cmpptr(rbx, ExternalAddress((address)Universe::heap()->end_addr()));
__ jcc(Assembler::above, slow_case);
__ locked_cmpxchgptr(rbx, heap_top);
__ jcc(Assembler::notEqual, retry);
__ incr_allocated_bytes(thread, rdx, 0);
}
if (UseTLAB || Universe::heap()->supports_inline_contig_alloc()) {
__ bind(initialize_object);
__ decrement(rdx, sizeof(oopDesc));
__ jcc(Assembler::zero, initialize_header);
__ xorl(rcx, rcx); // use zero reg to clear memory (shorter code)
__ shrl(rdx, LogBytesPerLong); // divide by 2*oopSize and set carry flag if odd
#ifdef ASSERT
Label L;
__ jccb(Assembler::carryClear, L);
__ stop("object size is not multiple of 2 - adjust this code");
__ bind(L);
#endif
{ Label loop;
__ bind(loop);
__ movptr(Address(rax, rdx, Address::times_8, sizeof(oopDesc) - 1*oopSize), rcx);
NOT_LP64(__ movptr(Address(rax, rdx, Address::times_8, sizeof(oopDesc) - 2*oopSize), rcx));
__ decrement(rdx);
__ jcc(Assembler::notZero, loop);
}
__ bind(initialize_header);
if (UseBiasedLocking) {
__ pop(rcx); // get saved klass back in the register.
__ movptr(rbx, Address(rcx, Klass::prototype_header_offset()));
__ movptr(Address(rax, oopDesc::mark_offset_in_bytes ()), rbx);
} else {
__ movptr(Address(rax, oopDesc::mark_offset_in_bytes ()),
(int32_t)markOopDesc::prototype()); // header
__ pop(rcx); // get saved klass back in the register.
}
__ store_klass(rax, rcx); // klass
{
SkipIfEqual skip_if(_masm, &DTraceAllocProbes, 0);
__ push(atos);
__ call_VM_leaf(
CAST_FROM_FN_PTR(address, SharedRuntime::dtrace_object_alloc), rax);
__ pop(atos);
}
__ jmp(done);
}
__ bind(slow_case);
__ pop(rcx); // restore stack pointer to what it was when we came in.
__ bind(slow_case_no_pop);
__ get_constant_pool(rax);
__ get_unsigned_2_byte_index_at_bcp(rdx, 1);
call_VM(rax, CAST_FROM_FN_PTR(address, InterpreterRuntime::_new), rax, rdx);
__ bind(done);
}
void TemplateTable::newarray() {
transition(itos, atos);
__ push_i(rax); // make sure everything is on the stack
__ load_unsigned_byte(rdx, at_bcp(1));
call_VM(rax, CAST_FROM_FN_PTR(address, InterpreterRuntime::newarray), rdx, rax);
__ pop_i(rdx); // discard size
}
void TemplateTable::anewarray() {
transition(itos, atos);
__ get_unsigned_2_byte_index_at_bcp(rdx, 1);
__ get_constant_pool(rcx);
call_VM(rax, CAST_FROM_FN_PTR(address, InterpreterRuntime::anewarray), rcx, rdx, rax);
}
void TemplateTable::arraylength() {
transition(atos, itos);
__ null_check(rax, arrayOopDesc::length_offset_in_bytes());
__ movl(rax, Address(rax, arrayOopDesc::length_offset_in_bytes()));
}
void TemplateTable::checkcast() {
transition(atos, atos);
Label done, is_null, ok_is_subtype, quicked, resolved;
__ testptr(rax, rax); // Object is in EAX
__ jcc(Assembler::zero, is_null);
__ get_cpool_and_tags(rcx, rdx); // ECX=cpool, EDX=tags array
__ get_unsigned_2_byte_index_at_bcp(rbx, 1); // EBX=index
__ cmpb(Address(rdx, rbx, Address::times_1, Array<u1>::base_offset_in_bytes()), JVM_CONSTANT_Class);
__ jcc(Assembler::equal, quicked);
__ push(atos);
call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::quicken_io_cc) );
__ get_thread(rdi);
__ get_vm_result_2(rax, rdi);
__ restore_locals();
__ pop_ptr(rdx);
__ jmpb(resolved);
__ bind(quicked);
__ mov(rdx, rax); // Save object in EDX; EAX needed for subtype check
__ movptr(rax, Address(rcx, rbx, Address::times_ptr, sizeof(ConstantPool)));
__ bind(resolved);
__ load_klass(rbx, rdx);
__ gen_subtype_check( rbx, ok_is_subtype );
__ push(rdx);
__ jump(ExternalAddress(Interpreter::_throw_ClassCastException_entry));
__ bind(ok_is_subtype);
__ mov(rax,rdx); // Restore object in EDX
if (ProfileInterpreter) {
__ jmp(done);
__ bind(is_null);
__ profile_null_seen(rcx);
} else {
__ bind(is_null); // same as 'done'
}
__ bind(done);
}
void TemplateTable::instanceof() {
transition(atos, itos);
Label done, is_null, ok_is_subtype, quicked, resolved;
__ testptr(rax, rax);
__ jcc(Assembler::zero, is_null);
__ get_cpool_and_tags(rcx, rdx); // ECX=cpool, EDX=tags array
__ get_unsigned_2_byte_index_at_bcp(rbx, 1); // EBX=index
__ cmpb(Address(rdx, rbx, Address::times_1, Array<u1>::base_offset_in_bytes()), JVM_CONSTANT_Class);
__ jcc(Assembler::equal, quicked);
__ push(atos);
call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::quicken_io_cc) );
__ get_thread(rdi);
__ get_vm_result_2(rax, rdi);
__ restore_locals();
__ pop_ptr(rdx);
__ load_klass(rdx, rdx);
__ jmp(resolved);
__ bind(quicked);
__ load_klass(rdx, rax);
__ movptr(rax, Address(rcx, rbx, Address::times_ptr, sizeof(ConstantPool)));
__ bind(resolved);
__ gen_subtype_check( rdx, ok_is_subtype );
__ xorl(rax,rax);
__ jmpb(done);
__ bind(ok_is_subtype);
__ movl(rax, 1);
if (ProfileInterpreter) {
__ jmp(done);
__ bind(is_null);
__ profile_null_seen(rcx);
} else {
__ bind(is_null); // same as 'done'
}
__ bind(done);
}
void TemplateTable::_breakpoint() {
transition(vtos, vtos);
__ get_method(rcx);
__ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::get_original_bytecode_at), rcx, rsi);
__ mov(rbx, rax);
__ get_method(rcx);
__ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::_breakpoint), rcx, rsi);
__ dispatch_only_normal(vtos);
}
void TemplateTable::athrow() {
transition(atos, vtos);
__ null_check(rax);
__ jump(ExternalAddress(Interpreter::throw_exception_entry()));
}
void TemplateTable::monitorenter() {
transition(atos, vtos);
__ null_check(rax);
const Address monitor_block_top(rbp, frame::interpreter_frame_monitor_block_top_offset * wordSize);
const Address monitor_block_bot(rbp, frame::interpreter_frame_initial_sp_offset * wordSize);
const int entry_size = ( frame::interpreter_frame_monitor_size() * wordSize);
Label allocated;
__ xorl(rdx, rdx); // points to free slot or NULL
{ Label entry, loop, exit;
__ movptr(rcx, monitor_block_top); // points to current entry, starting with top-most entry
__ lea(rbx, monitor_block_bot); // points to word before bottom of monitor block
__ jmpb(entry);
__ bind(loop);
__ cmpptr(Address(rcx, BasicObjectLock::obj_offset_in_bytes()), (int32_t)NULL_WORD); // check if current entry is used
__ cmovptr(Assembler::equal, rdx, rcx); // if not used then remember entry in rdx
__ cmpptr(rax, Address(rcx, BasicObjectLock::obj_offset_in_bytes())); // check if current entry is for same object
__ jccb(Assembler::equal, exit); // if same object then stop searching
__ addptr(rcx, entry_size); // otherwise advance to next entry
__ bind(entry);
__ cmpptr(rcx, rbx); // check if bottom reached
__ jcc(Assembler::notEqual, loop); // if not at bottom then check this entry
__ bind(exit);
}
__ testptr(rdx, rdx); // check if a slot has been found
__ jccb(Assembler::notZero, allocated); // if found, continue with that one
{ Label entry, loop;
__ movptr(rdx, monitor_block_bot); // rdx: old expression stack bottom
__ subptr(rsp, entry_size); // move expression stack top
__ subptr(rdx, entry_size); // move expression stack bottom
__ mov(rcx, rsp); // set start value for copy loop
__ movptr(monitor_block_bot, rdx); // set new monitor block top
__ jmp(entry);
__ bind(loop);
__ movptr(rbx, Address(rcx, entry_size)); // load expression stack word from old location
__ movptr(Address(rcx, 0), rbx); // and store it at new location
__ addptr(rcx, wordSize); // advance to next word
__ bind(entry);
__ cmpptr(rcx, rdx); // check if bottom reached
__ jcc(Assembler::notEqual, loop); // if not at bottom then copy next word
}
__ bind(allocated);
__ increment(rsi);
__ movptr(Address(rdx, BasicObjectLock::obj_offset_in_bytes()), rax); // store object
__ lock_object(rdx);
__ save_bcp(); // in case of exception
__ generate_stack_overflow_check(0);
__ dispatch_next(vtos);
}
void TemplateTable::monitorexit() {
transition(atos, vtos);
__ null_check(rax);
const Address monitor_block_top(rbp, frame::interpreter_frame_monitor_block_top_offset * wordSize);
const Address monitor_block_bot(rbp, frame::interpreter_frame_initial_sp_offset * wordSize);
const int entry_size = ( frame::interpreter_frame_monitor_size() * wordSize);
Label found;
{ Label entry, loop;
__ movptr(rdx, monitor_block_top); // points to current entry, starting with top-most entry
__ lea(rbx, monitor_block_bot); // points to word before bottom of monitor block
__ jmpb(entry);
__ bind(loop);
__ cmpptr(rax, Address(rdx, BasicObjectLock::obj_offset_in_bytes())); // check if current entry is for same object
__ jcc(Assembler::equal, found); // if same object then stop searching
__ addptr(rdx, entry_size); // otherwise advance to next entry
__ bind(entry);
__ cmpptr(rdx, rbx); // check if bottom reached
__ jcc(Assembler::notEqual, loop); // if not at bottom then check this entry
}
Label end;
__ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_illegal_monitor_state_exception));
__ should_not_reach_here();
__ bind(found);
__ push_ptr(rax); // make sure object is on stack (contract with oopMaps)
__ unlock_object(rdx);
__ pop_ptr(rax); // discard object
__ bind(end);
}
void TemplateTable::wide() {
transition(vtos, vtos);
__ load_unsigned_byte(rbx, at_bcp(1));
ExternalAddress wtable((address)Interpreter::_wentry_point);
__ jump(ArrayAddress(wtable, Address(noreg, rbx, Address::times_ptr)));
}
void TemplateTable::multianewarray() {
transition(vtos, atos);
__ load_unsigned_byte(rax, at_bcp(3)); // get number of dimensions
__ lea( rax, Address(rsp, rax, Interpreter::stackElementScale(), -wordSize));
call_VM(rax, CAST_FROM_FN_PTR(address, InterpreterRuntime::multianewarray), rax); // pass in rax,
__ load_unsigned_byte(rbx, at_bcp(3));
__ lea(rsp, Address(rsp, rbx, Interpreter::stackElementScale())); // get rid of counts
}
#endif /* !CC_INTERP */
C:\hotspot-69087d08d473\src\cpu\x86\vm/templateTable_x86_32.hpp
#ifndef CPU_X86_VM_TEMPLATETABLE_X86_32_HPP
#define CPU_X86_VM_TEMPLATETABLE_X86_32_HPP
static void prepare_invoke(int byte_no,
Register method, // linked method (or i-klass)
Register index = noreg, // itable index, MethodType, etc.
Register recv = noreg, // if caller wants to see it
Register flags = noreg // if caller wants to test it
);
static void invokevirtual_helper(Register index, Register recv,
Register flags);
static void volatile_barrier(Assembler::Membar_mask_bits order_constraint);
static void index_check(Register array, Register index);
static void index_check_without_pop(Register array, Register index);
#endif // CPU_X86_VM_TEMPLATETABLE_X86_32_HPP
C:\hotspot-69087d08d473\src\cpu\x86\vm/templateTable_x86_64.cpp
#include "precompiled.hpp"
#include "asm/macroAssembler.hpp"
#include "interpreter/interpreter.hpp"
#include "interpreter/interpreterRuntime.hpp"
#include "interpreter/templateTable.hpp"
#include "memory/universe.inline.hpp"
#include "oops/methodData.hpp"
#include "oops/objArrayKlass.hpp"
#include "oops/oop.inline.hpp"
#include "prims/methodHandles.hpp"
#include "runtime/sharedRuntime.hpp"
#include "runtime/stubRoutines.hpp"
#include "runtime/synchronizer.hpp"
#include "utilities/macros.hpp"
#ifndef CC_INTERP
#define __ _masm->
void TemplateTable::pd_initialize() {
}
static inline Address iaddress(int n) {
return Address(r14, Interpreter::local_offset_in_bytes(n));
}
static inline Address laddress(int n) {
return iaddress(n + 1);
}
static inline Address faddress(int n) {
return iaddress(n);
}
static inline Address daddress(int n) {
return laddress(n);
}
static inline Address aaddress(int n) {
return iaddress(n);
}
static inline Address iaddress(Register r) {
return Address(r14, r, Address::times_8);
}
static inline Address laddress(Register r) {
return Address(r14, r, Address::times_8, Interpreter::local_offset_in_bytes(1));
}
static inline Address faddress(Register r) {
return iaddress(r);
}
static inline Address daddress(Register r) {
return laddress(r);
}
static inline Address aaddress(Register r) {
return iaddress(r);
}
static inline Address at_rsp() {
return Address(rsp, 0);
}
static inline Address at_tos () {
return Address(rsp, Interpreter::expr_offset_in_bytes(0));
}
static inline Address at_tos_p1() {
return Address(rsp, Interpreter::expr_offset_in_bytes(1));
}
static inline Address at_tos_p2() {
return Address(rsp, Interpreter::expr_offset_in_bytes(2));
}
static Assembler::Condition j_not(TemplateTable::Condition cc) {
switch (cc) {
case TemplateTable::equal : return Assembler::notEqual;
case TemplateTable::not_equal : return Assembler::equal;
case TemplateTable::less : return Assembler::greaterEqual;
case TemplateTable::less_equal : return Assembler::greater;
case TemplateTable::greater : return Assembler::lessEqual;
case TemplateTable::greater_equal: return Assembler::less;
}
ShouldNotReachHere();
return Assembler::zero;
}
static void do_oop_store(InterpreterMacroAssembler* _masm,
Address obj,
Register val,
BarrierSet::Name barrier,
bool precise) {
assert(val == noreg || val == rax, "parameter is just for looks");
switch (barrier) {
#if INCLUDE_ALL_GCS
case BarrierSet::G1SATBCT:
case BarrierSet::G1SATBCTLogging:
{
if (obj.index() == noreg && obj.disp() == 0) {
if (obj.base() != rdx) {
__ movq(rdx, obj.base());
}
} else {
__ leaq(rdx, obj);
}
__ g1_write_barrier_pre(rdx /* obj */,
rbx /* pre_val */,
r15_thread /* thread */,
r8 /* tmp */,
val != noreg /* tosca_live */,
false /* expand_call */);
if (val == noreg) {
__ store_heap_oop_null(Address(rdx, 0));
} else {
Register new_val = val;
if (UseCompressedOops) {
new_val = rbx;
__ movptr(new_val, val);
}
__ store_heap_oop(Address(rdx, 0), val);
__ g1_write_barrier_post(rdx /* store_adr */,
new_val /* new_val */,
r15_thread /* thread */,
r8 /* tmp */,
rbx /* tmp2 */);
}
}
break;
#endif // INCLUDE_ALL_GCS
case BarrierSet::CardTableModRef:
case BarrierSet::CardTableExtension:
{
if (val == noreg) {
__ store_heap_oop_null(obj);
} else {
__ store_heap_oop(obj, val);
if (!precise || (obj.index() == noreg && obj.disp() == 0)) {
__ store_check(obj.base());
} else {
__ leaq(rdx, obj);
__ store_check(rdx);
}
}
}
break;
case BarrierSet::ModRef:
case BarrierSet::Other:
if (val == noreg) {
__ store_heap_oop_null(obj);
} else {
__ store_heap_oop(obj, val);
}
break;
default :
ShouldNotReachHere();
}
}
Address TemplateTable::at_bcp(int offset) {
assert(_desc->uses_bcp(), "inconsistent uses_bcp information");
return Address(r13, offset);
}
void TemplateTable::patch_bytecode(Bytecodes::Code bc, Register bc_reg,
Register temp_reg, bool load_bc_into_bc_reg/*=true*/,
int byte_no) {
if (!RewriteBytecodes) return;
Label L_patch_done;
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:
case Bytecodes::_fast_iputfield:
case Bytecodes::_fast_lputfield:
case Bytecodes::_fast_sputfield:
{
assert(byte_no == f1_byte || byte_no == f2_byte, "byte_no out of range");
assert(load_bc_into_bc_reg, "we use bc_reg as temp");
__ get_cache_and_index_and_bytecode_at_bcp(temp_reg, bc_reg, temp_reg, byte_no, 1);
__ movl(bc_reg, bc);
__ cmpl(temp_reg, (int) 0);
__ jcc(Assembler::zero, L_patch_done); // don't patch
}
break;
default:
assert(byte_no == -1, "sanity");
if (load_bc_into_bc_reg) {
__ movl(bc_reg, bc);
}
}
if (JvmtiExport::can_post_breakpoint()) {
Label L_fast_patch;
__ movzbl(temp_reg, at_bcp(0));
__ cmpl(temp_reg, Bytecodes::_breakpoint);
__ jcc(Assembler::notEqual, L_fast_patch);
__ get_method(temp_reg);
__ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::set_original_bytecode_at), temp_reg, r13, bc_reg);
#ifndef ASSERT
__ jmpb(L_patch_done);
#else
__ jmp(L_patch_done);
#endif
__ bind(L_fast_patch);
}
#ifdef ASSERT
Label L_okay;
__ load_unsigned_byte(temp_reg, at_bcp(0));
__ cmpl(temp_reg, (int) Bytecodes::java_code(bc));
__ jcc(Assembler::equal, L_okay);
__ cmpl(temp_reg, bc_reg);
__ jcc(Assembler::equal, L_okay);
__ stop("patching the wrong bytecode");
__ bind(L_okay);
#endif
__ movb(at_bcp(0), bc_reg);
__ bind(L_patch_done);
}
void TemplateTable::nop() {
transition(vtos, vtos);
}
void TemplateTable::shouldnotreachhere() {
transition(vtos, vtos);
__ stop("shouldnotreachhere bytecode");
}
void TemplateTable::aconst_null() {
transition(vtos, atos);
__ xorl(rax, rax);
}
void TemplateTable::iconst(int value) {
transition(vtos, itos);
if (value == 0) {
__ xorl(rax, rax);
} else {
__ movl(rax, value);
}
}
void TemplateTable::lconst(int value) {
transition(vtos, ltos);
if (value == 0) {
__ xorl(rax, rax);
} else {
__ movl(rax, value);
}
}
void TemplateTable::fconst(int value) {
transition(vtos, ftos);
static float one = 1.0f, two = 2.0f;
switch (value) {
case 0:
__ xorps(xmm0, xmm0);
break;
case 1:
__ movflt(xmm0, ExternalAddress((address) &one));
break;
case 2:
__ movflt(xmm0, ExternalAddress((address) &two));
break;
default:
ShouldNotReachHere();
break;
}
}
void TemplateTable::dconst(int value) {
transition(vtos, dtos);
static double one = 1.0;
switch (value) {
case 0:
__ xorpd(xmm0, xmm0);
break;
case 1:
__ movdbl(xmm0, ExternalAddress((address) &one));
break;
default:
ShouldNotReachHere();
break;
}
}
void TemplateTable::bipush() {
transition(vtos, itos);
__ load_signed_byte(rax, at_bcp(1));
}
void TemplateTable::sipush() {
transition(vtos, itos);
__ load_unsigned_short(rax, at_bcp(1));
__ bswapl(rax);
__ sarl(rax, 16);
}
void TemplateTable::ldc(bool wide) {
transition(vtos, vtos);
Label call_ldc, notFloat, notClass, Done;
if (wide) {
__ get_unsigned_2_byte_index_at_bcp(rbx, 1);
} else {
__ load_unsigned_byte(rbx, at_bcp(1));
}
__ get_cpool_and_tags(rcx, rax);
const int base_offset = ConstantPool::header_size() * wordSize;
const int tags_offset = Array<u1>::base_offset_in_bytes();
__ movzbl(rdx, Address(rax, rbx, Address::times_1, tags_offset));
__ cmpl(rdx, JVM_CONSTANT_UnresolvedClass);
__ jccb(Assembler::equal, call_ldc);
__ cmpl(rdx, JVM_CONSTANT_UnresolvedClassInError);
__ jccb(Assembler::equal, call_ldc);
__ cmpl(rdx, JVM_CONSTANT_Class);
__ jcc(Assembler::notEqual, notClass);
__ bind(call_ldc);
__ movl(c_rarg1, wide);
call_VM(rax, CAST_FROM_FN_PTR(address, InterpreterRuntime::ldc), c_rarg1);
__ push_ptr(rax);
__ verify_oop(rax);
__ jmp(Done);
__ bind(notClass);
__ cmpl(rdx, JVM_CONSTANT_Float);
__ jccb(Assembler::notEqual, notFloat);
__ movflt(xmm0, Address(rcx, rbx, Address::times_8, base_offset));
__ push_f();
__ jmp(Done);
__ bind(notFloat);
#ifdef ASSERT
{
Label L;
__ cmpl(rdx, JVM_CONSTANT_Integer);
__ jcc(Assembler::equal, L);
__ stop("unexpected tag type in ldc");
__ bind(L);
}
#endif
__ movl(rax, Address(rcx, rbx, Address::times_8, base_offset));
__ push_i(rax);
__ bind(Done);
}
void TemplateTable::fast_aldc(bool wide) {
transition(vtos, atos);
Register result = rax;
Register tmp = rdx;
int index_size = wide ? sizeof(u2) : sizeof(u1);
Label resolved;
assert_different_registers(result, tmp);
__ get_cache_index_at_bcp(tmp, 1, index_size);
__ load_resolved_reference_at_index(result, tmp);
__ testl(result, result);
__ jcc(Assembler::notZero, resolved);
address entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_ldc);
__ movl(tmp, (int)bytecode());
__ call_VM(result, entry, tmp);
__ bind(resolved);
if (VerifyOops) {
__ verify_oop(result);
}
}
void TemplateTable::ldc2_w() {
transition(vtos, vtos);
Label Long, Done;
__ get_unsigned_2_byte_index_at_bcp(rbx, 1);
__ get_cpool_and_tags(rcx, rax);
const int base_offset = ConstantPool::header_size() * wordSize;
const int tags_offset = Array<u1>::base_offset_in_bytes();
__ cmpb(Address(rax, rbx, Address::times_1, tags_offset),
JVM_CONSTANT_Double);
__ jccb(Assembler::notEqual, Long);
__ movdbl(xmm0, Address(rcx, rbx, Address::times_8, base_offset));
__ push_d();
__ jmpb(Done);
__ bind(Long);
__ movq(rax, Address(rcx, rbx, Address::times_8, base_offset));
__ push_l();
__ bind(Done);
}
void TemplateTable::locals_index(Register reg, int offset) {
__ load_unsigned_byte(reg, at_bcp(offset));
__ negptr(reg);
}
void TemplateTable::iload() {
transition(vtos, itos);
if (RewriteFrequentPairs) {
Label rewrite, done;
const Register bc = c_rarg3;
assert(rbx != bc, "register damaged");
__ load_unsigned_byte(rbx,
at_bcp(Bytecodes::length_for(Bytecodes::_iload)));
__ cmpl(rbx, Bytecodes::_iload);
__ jcc(Assembler::equal, done);
__ cmpl(rbx, Bytecodes::_fast_iload);
__ movl(bc, Bytecodes::_fast_iload2);
__ jccb(Assembler::equal, rewrite);
__ cmpl(rbx, Bytecodes::_caload);
__ movl(bc, Bytecodes::_fast_icaload);
__ jccb(Assembler::equal, rewrite);
__ movl(bc, Bytecodes::_fast_iload);
__ bind(rewrite);
patch_bytecode(Bytecodes::_iload, bc, rbx, false);
__ bind(done);
}
locals_index(rbx);
__ movl(rax, iaddress(rbx));
}
void TemplateTable::fast_iload2() {
transition(vtos, itos);
locals_index(rbx);
__ movl(rax, iaddress(rbx));
__ push(itos);
locals_index(rbx, 3);
__ movl(rax, iaddress(rbx));
}
void TemplateTable::fast_iload() {
transition(vtos, itos);
locals_index(rbx);
__ movl(rax, iaddress(rbx));
}
void TemplateTable::lload() {
transition(vtos, ltos);
locals_index(rbx);
__ movq(rax, laddress(rbx));
}
void TemplateTable::fload() {
transition(vtos, ftos);
locals_index(rbx);
__ movflt(xmm0, faddress(rbx));
}
void TemplateTable::dload() {
transition(vtos, dtos);
locals_index(rbx);
__ movdbl(xmm0, daddress(rbx));
}
void TemplateTable::aload() {
transition(vtos, atos);
locals_index(rbx);
__ movptr(rax, aaddress(rbx));
}
void TemplateTable::locals_index_wide(Register reg) {
__ load_unsigned_short(reg, at_bcp(2));
__ bswapl(reg);
__ shrl(reg, 16);
__ negptr(reg);
}
void TemplateTable::wide_iload() {
transition(vtos, itos);
locals_index_wide(rbx);
__ movl(rax, iaddress(rbx));
}
void TemplateTable::wide_lload() {
transition(vtos, ltos);
locals_index_wide(rbx);
__ movq(rax, laddress(rbx));
}
void TemplateTable::wide_fload() {
transition(vtos, ftos);
locals_index_wide(rbx);
__ movflt(xmm0, faddress(rbx));
}
void TemplateTable::wide_dload() {
transition(vtos, dtos);
locals_index_wide(rbx);
__ movdbl(xmm0, daddress(rbx));
}
void TemplateTable::wide_aload() {
transition(vtos, atos);
locals_index_wide(rbx);
__ movptr(rax, aaddress(rbx));
}
void TemplateTable::index_check(Register array, Register index) {
__ null_check(array, arrayOopDesc::length_offset_in_bytes());
__ movl2ptr(index, index);
__ cmpl(index, Address(array, arrayOopDesc::length_offset_in_bytes()));
if (index != rbx) {
assert(rbx != array, "different registers");
__ movl(rbx, index);
}
__ jump_cc(Assembler::aboveEqual,
ExternalAddress(Interpreter::_throw_ArrayIndexOutOfBoundsException_entry));
}
void TemplateTable::iaload() {
transition(itos, itos);
__ pop_ptr(rdx);
index_check(rdx, rax); // kills rbx
__ movl(rax, Address(rdx, rax,
Address::times_4,
arrayOopDesc::base_offset_in_bytes(T_INT)));
}
void TemplateTable::laload() {
transition(itos, ltos);
__ pop_ptr(rdx);
index_check(rdx, rax); // kills rbx
__ movq(rax, Address(rdx, rbx,
Address::times_8,
arrayOopDesc::base_offset_in_bytes(T_LONG)));
}
void TemplateTable::faload() {
transition(itos, ftos);
__ pop_ptr(rdx);
index_check(rdx, rax); // kills rbx
__ movflt(xmm0, Address(rdx, rax,
Address::times_4,
arrayOopDesc::base_offset_in_bytes(T_FLOAT)));
}
void TemplateTable::daload() {
transition(itos, dtos);
__ pop_ptr(rdx);
index_check(rdx, rax); // kills rbx
__ movdbl(xmm0, Address(rdx, rax,
Address::times_8,
arrayOopDesc::base_offset_in_bytes(T_DOUBLE)));
}
void TemplateTable::aaload() {
transition(itos, atos);
__ pop_ptr(rdx);
index_check(rdx, rax); // kills rbx
__ load_heap_oop(rax, Address(rdx, rax,
UseCompressedOops ? Address::times_4 : Address::times_8,
arrayOopDesc::base_offset_in_bytes(T_OBJECT)));
}
void TemplateTable::baload() {
transition(itos, itos);
__ pop_ptr(rdx);
index_check(rdx, rax); // kills rbx
__ load_signed_byte(rax,
Address(rdx, rax,
Address::times_1,
arrayOopDesc::base_offset_in_bytes(T_BYTE)));
}
void TemplateTable::caload() {
transition(itos, itos);
__ pop_ptr(rdx);
index_check(rdx, rax); // kills rbx
__ load_unsigned_short(rax,
Address(rdx, rax,
Address::times_2,
arrayOopDesc::base_offset_in_bytes(T_CHAR)));
}
void TemplateTable::fast_icaload() {
transition(vtos, itos);
locals_index(rbx);
__ movl(rax, iaddress(rbx));
__ pop_ptr(rdx);
index_check(rdx, rax); // kills rbx
__ load_unsigned_short(rax,
Address(rdx, rax,
Address::times_2,
arrayOopDesc::base_offset_in_bytes(T_CHAR)));
}
void TemplateTable::saload() {
transition(itos, itos);
__ pop_ptr(rdx);
index_check(rdx, rax); // kills rbx
__ load_signed_short(rax,
Address(rdx, rax,
Address::times_2,
arrayOopDesc::base_offset_in_bytes(T_SHORT)));
}
void TemplateTable::iload(int n) {
transition(vtos, itos);
__ movl(rax, iaddress(n));
}
void TemplateTable::lload(int n) {
transition(vtos, ltos);
__ movq(rax, laddress(n));
}
void TemplateTable::fload(int n) {
transition(vtos, ftos);
__ movflt(xmm0, faddress(n));
}
void TemplateTable::dload(int n) {
transition(vtos, dtos);
__ movdbl(xmm0, daddress(n));
}
void TemplateTable::aload(int n) {
transition(vtos, atos);
__ movptr(rax, aaddress(n));
}
void TemplateTable::aload_0() {
transition(vtos, atos);
if (RewriteFrequentPairs) {
Label rewrite, done;
const Register bc = c_rarg3;
assert(rbx != bc, "register damaged");
__ load_unsigned_byte(rbx,
at_bcp(Bytecodes::length_for(Bytecodes::_aload_0)));
aload(0);
__ cmpl(rbx, Bytecodes::_getfield);
__ jcc(Assembler::equal, done);
assert(Bytecodes::java_code(Bytecodes::_fast_iaccess_0) ==
Bytecodes::_aload_0,
"fix bytecode definition");
__ cmpl(rbx, Bytecodes::_fast_igetfield);
__ movl(bc, Bytecodes::_fast_iaccess_0);
__ jccb(Assembler::equal, rewrite);
assert(Bytecodes::java_code(Bytecodes::_fast_aaccess_0) ==
Bytecodes::_aload_0,
"fix bytecode definition");
__ cmpl(rbx, Bytecodes::_fast_agetfield);
__ movl(bc, Bytecodes::_fast_aaccess_0);
__ jccb(Assembler::equal, rewrite);
assert(Bytecodes::java_code(Bytecodes::_fast_faccess_0) ==
Bytecodes::_aload_0,
"fix bytecode definition");
__ cmpl(rbx, Bytecodes::_fast_fgetfield);
__ movl(bc, Bytecodes::_fast_faccess_0);
__ jccb(Assembler::equal, rewrite);
assert(Bytecodes::java_code(Bytecodes::_fast_aload_0) ==
Bytecodes::_aload_0,
"fix bytecode definition");
__ movl(bc, Bytecodes::_fast_aload_0);
__ bind(rewrite);
patch_bytecode(Bytecodes::_aload_0, bc, rbx, false);
__ bind(done);
} else {
aload(0);
}
}
void TemplateTable::istore() {
transition(itos, vtos);
locals_index(rbx);
__ movl(iaddress(rbx), rax);
}
void TemplateTable::lstore() {
transition(ltos, vtos);
locals_index(rbx);
__ movq(laddress(rbx), rax);
}
void TemplateTable::fstore() {
transition(ftos, vtos);
locals_index(rbx);
__ movflt(faddress(rbx), xmm0);
}
void TemplateTable::dstore() {
transition(dtos, vtos);
locals_index(rbx);
__ movdbl(daddress(rbx), xmm0);
}
void TemplateTable::astore() {
transition(vtos, vtos);
__ pop_ptr(rax);
locals_index(rbx);
__ movptr(aaddress(rbx), rax);
}
void TemplateTable::wide_istore() {
transition(vtos, vtos);
__ pop_i();
locals_index_wide(rbx);
__ movl(iaddress(rbx), rax);
}
void TemplateTable::wide_lstore() {
transition(vtos, vtos);
__ pop_l();
locals_index_wide(rbx);
__ movq(laddress(rbx), rax);
}
void TemplateTable::wide_fstore() {
transition(vtos, vtos);
__ pop_f();
locals_index_wide(rbx);
__ movflt(faddress(rbx), xmm0);
}
void TemplateTable::wide_dstore() {
transition(vtos, vtos);
__ pop_d();
locals_index_wide(rbx);
__ movdbl(daddress(rbx), xmm0);
}
void TemplateTable::wide_astore() {
transition(vtos, vtos);
__ pop_ptr(rax);
locals_index_wide(rbx);
__ movptr(aaddress(rbx), rax);
}
void TemplateTable::iastore() {
transition(itos, vtos);
__ pop_i(rbx);
__ pop_ptr(rdx);
index_check(rdx, rbx); // prefer index in ebx
__ movl(Address(rdx, rbx,
Address::times_4,
arrayOopDesc::base_offset_in_bytes(T_INT)),
rax);
}
void TemplateTable::lastore() {
transition(ltos, vtos);
__ pop_i(rbx);
__ pop_ptr(rdx);
index_check(rdx, rbx); // prefer index in ebx
__ movq(Address(rdx, rbx,
Address::times_8,
arrayOopDesc::base_offset_in_bytes(T_LONG)),
rax);
}
void TemplateTable::fastore() {
transition(ftos, vtos);
__ pop_i(rbx);
__ pop_ptr(rdx);
index_check(rdx, rbx); // prefer index in ebx
__ movflt(Address(rdx, rbx,
Address::times_4,
arrayOopDesc::base_offset_in_bytes(T_FLOAT)),
xmm0);
}
void TemplateTable::dastore() {
transition(dtos, vtos);
__ pop_i(rbx);
__ pop_ptr(rdx);
index_check(rdx, rbx); // prefer index in ebx
__ movdbl(Address(rdx, rbx,
Address::times_8,
arrayOopDesc::base_offset_in_bytes(T_DOUBLE)),
xmm0);
}
void TemplateTable::aastore() {
Label is_null, ok_is_subtype, done;
transition(vtos, vtos);
__ movptr(rax, at_tos()); // value
__ movl(rcx, at_tos_p1()); // index
__ movptr(rdx, at_tos_p2()); // array
Address element_address(rdx, rcx,
UseCompressedOops? Address::times_4 : Address::times_8,
arrayOopDesc::base_offset_in_bytes(T_OBJECT));
index_check(rdx, rcx); // kills rbx
__ testptr(rax, rax);
__ jcc(Assembler::zero, is_null);
__ load_klass(rbx, rax);
__ load_klass(rax, rdx);
__ movptr(rax, Address(rax,
ObjArrayKlass::element_klass_offset()));
__ lea(rdx, element_address);
__ gen_subtype_check(rbx, ok_is_subtype);
__ jump(ExternalAddress(Interpreter::_throw_ArrayStoreException_entry));
__ bind(ok_is_subtype);
__ movptr(rax, at_tos());
do_oop_store(_masm, Address(rdx, 0), rax, _bs->kind(), true);
__ jmp(done);
__ bind(is_null);
__ profile_null_seen(rbx);
do_oop_store(_masm, element_address, noreg, _bs->kind(), true);
__ bind(done);
__ addptr(rsp, 3 * Interpreter::stackElementSize);
}
void TemplateTable::bastore() {
transition(itos, vtos);
__ pop_i(rbx);
__ pop_ptr(rdx);
index_check(rdx, rbx); // prefer index in ebx
__ 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)),
rax);
}
void TemplateTable::castore() {
transition(itos, vtos);
__ pop_i(rbx);
__ pop_ptr(rdx);
index_check(rdx, rbx); // prefer index in ebx
__ movw(Address(rdx, rbx,
Address::times_2,
arrayOopDesc::base_offset_in_bytes(T_CHAR)),
rax);
}
void TemplateTable::sastore() {
castore();
}
void TemplateTable::istore(int n) {
transition(itos, vtos);
__ movl(iaddress(n), rax);
}
void TemplateTable::lstore(int n) {
transition(ltos, vtos);
__ movq(laddress(n), rax);
}
void TemplateTable::fstore(int n) {
transition(ftos, vtos);
__ movflt(faddress(n), xmm0);
}
void TemplateTable::dstore(int n) {
transition(dtos, vtos);
__ movdbl(daddress(n), xmm0);
}
void TemplateTable::astore(int n) {
transition(vtos, vtos);
__ pop_ptr(rax);
__ movptr(aaddress(n), rax);
}
void TemplateTable::pop() {
transition(vtos, vtos);
__ addptr(rsp, Interpreter::stackElementSize);
}
void TemplateTable::pop2() {
transition(vtos, vtos);
__ addptr(rsp, 2 * Interpreter::stackElementSize);
}
void TemplateTable::dup() {
transition(vtos, vtos);
__ load_ptr(0, rax);
__ push_ptr(rax);
}
void TemplateTable::dup_x1() {
transition(vtos, vtos);
__ load_ptr( 0, rax); // load b
__ load_ptr( 1, rcx); // load a
__ store_ptr(1, rax); // store b
__ store_ptr(0, rcx); // store a
__ push_ptr(rax); // push b
}
void TemplateTable::dup_x2() {
transition(vtos, vtos);
__ load_ptr( 0, rax); // load c
__ load_ptr( 2, rcx); // load a
__ store_ptr(2, rax); // store c in a
__ push_ptr(rax); // push c
__ load_ptr( 2, rax); // load b
__ store_ptr(2, rcx); // store a in b
__ store_ptr(1, rax); // store b in c
}
void TemplateTable::dup2() {
transition(vtos, vtos);
__ load_ptr(1, rax); // load a
__ push_ptr(rax); // push a
__ load_ptr(1, rax); // load b
__ push_ptr(rax); // push b
}
void TemplateTable::dup2_x1() {
transition(vtos, vtos);
__ load_ptr( 0, rcx); // load c
__ load_ptr( 1, rax); // load b
__ push_ptr(rax); // push b
__ push_ptr(rcx); // push c
__ store_ptr(3, rcx); // store c in b
__ load_ptr( 4, rcx); // load a
__ store_ptr(2, rcx); // store a in 2nd c
__ store_ptr(4, rax); // store b in a
}
void TemplateTable::dup2_x2() {
transition(vtos, vtos);
__ load_ptr( 0, rcx); // load d
__ load_ptr( 1, rax); // load c
__ push_ptr(rax); // push c
__ push_ptr(rcx); // push d
__ load_ptr( 4, rax); // load b
__ store_ptr(2, rax); // store b in d
__ store_ptr(4, rcx); // store d in b
__ load_ptr( 5, rcx); // load a
__ load_ptr( 3, rax); // load c
__ store_ptr(3, rcx); // store a in c
__ store_ptr(5, rax); // store c in a
}
void TemplateTable::swap() {
transition(vtos, vtos);
__ load_ptr( 1, rcx); // load a
__ load_ptr( 0, rax); // load b
__ store_ptr(0, rcx); // store a in b
__ store_ptr(1, rax); // store b in a
}
void TemplateTable::iop2(Operation op) {
transition(itos, itos);
switch (op) {
case add : __ pop_i(rdx); __ addl (rax, rdx); break;
case sub : __ movl(rdx, rax); __ pop_i(rax); __ subl (rax, rdx); break;
case mul : __ pop_i(rdx); __ imull(rax, rdx); break;
case _and : __ pop_i(rdx); __ andl (rax, rdx); break;
case _or : __ pop_i(rdx); __ orl (rax, rdx); break;
case _xor : __ pop_i(rdx); __ xorl (rax, rdx); break;
case shl : __ movl(rcx, rax); __ pop_i(rax); __ shll (rax); break;
case shr : __ movl(rcx, rax); __ pop_i(rax); __ sarl (rax); break;
case ushr : __ movl(rcx, rax); __ pop_i(rax); __ shrl (rax); break;
default : ShouldNotReachHere();
}
}
void TemplateTable::lop2(Operation op) {
transition(ltos, ltos);
switch (op) {
case add : __ pop_l(rdx); __ addptr(rax, rdx); break;
case sub : __ mov(rdx, rax); __ pop_l(rax); __ subptr(rax, rdx); break;
case _and : __ pop_l(rdx); __ andptr(rax, rdx); break;
case _or : __ pop_l(rdx); __ orptr (rax, rdx); break;
case _xor : __ pop_l(rdx); __ xorptr(rax, rdx); break;
default : ShouldNotReachHere();
}
}
void TemplateTable::idiv() {
transition(itos, itos);
__ movl(rcx, rax);
__ pop_i(rax);
__ corrected_idivl(rcx);
}
void TemplateTable::irem() {
transition(itos, itos);
__ movl(rcx, rax);
__ pop_i(rax);
__ corrected_idivl(rcx);
__ movl(rax, rdx);
}
void TemplateTable::lmul() {
transition(ltos, ltos);
__ pop_l(rdx);
__ imulq(rax, rdx);
}
void TemplateTable::ldiv() {
transition(ltos, ltos);
__ mov(rcx, rax);
__ pop_l(rax);
__ testq(rcx, rcx);
__ jump_cc(Assembler::zero,
ExternalAddress(Interpreter::_throw_ArithmeticException_entry));
__ corrected_idivq(rcx); // kills rbx
}
void TemplateTable::lrem() {
transition(ltos, ltos);
__ mov(rcx, rax);
__ pop_l(rax);
__ testq(rcx, rcx);
__ jump_cc(Assembler::zero,
ExternalAddress(Interpreter::_throw_ArithmeticException_entry));
__ corrected_idivq(rcx); // kills rbx
__ mov(rax, rdx);
}
void TemplateTable::lshl() {
transition(itos, ltos);
__ movl(rcx, rax); // get shift count
__ pop_l(rax); // get shift value
__ shlq(rax);
}
void TemplateTable::lshr() {
transition(itos, ltos);
__ movl(rcx, rax); // get shift count
__ pop_l(rax); // get shift value
__ sarq(rax);
}
void TemplateTable::lushr() {
transition(itos, ltos);
__ movl(rcx, rax); // get shift count
__ pop_l(rax); // get shift value
__ shrq(rax);
}
void TemplateTable::fop2(Operation op) {
transition(ftos, ftos);
switch (op) {
case add:
__ addss(xmm0, at_rsp());
__ addptr(rsp, Interpreter::stackElementSize);
break;
case sub:
__ movflt(xmm1, xmm0);
__ pop_f(xmm0);
__ subss(xmm0, xmm1);
break;
case mul:
__ mulss(xmm0, at_rsp());
__ addptr(rsp, Interpreter::stackElementSize);
break;
case div:
__ movflt(xmm1, xmm0);
__ pop_f(xmm0);
__ divss(xmm0, xmm1);
break;
case rem:
__ movflt(xmm1, xmm0);
__ pop_f(xmm0);
__ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::frem), 2);
break;
default:
ShouldNotReachHere();
break;
}
}
void TemplateTable::dop2(Operation op) {
transition(dtos, dtos);
switch (op) {
case add:
__ addsd(xmm0, at_rsp());
__ addptr(rsp, 2 * Interpreter::stackElementSize);
break;
case sub:
__ movdbl(xmm1, xmm0);
__ pop_d(xmm0);
__ subsd(xmm0, xmm1);
break;
case mul:
__ mulsd(xmm0, at_rsp());
__ addptr(rsp, 2 * Interpreter::stackElementSize);
break;
case div:
__ movdbl(xmm1, xmm0);
__ pop_d(xmm0);
__ divsd(xmm0, xmm1);
break;
case rem:
__ movdbl(xmm1, xmm0);
__ pop_d(xmm0);
__ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::drem), 2);
break;
default:
ShouldNotReachHere();
break;
}
}
void TemplateTable::ineg() {
transition(itos, itos);
__ negl(rax);
}
void TemplateTable::lneg() {
transition(ltos, ltos);
__ negq(rax);
}
static jlong* double_quadword(jlong *adr, jlong lo, jlong hi) {
jlong *operand = (jlong*)(((intptr_t)adr)&((intptr_t)(~0xF)));
operand[0] = lo;
operand[1] = hi;
return operand;
}
static jlong float_signflip_pool[2*2];
static jlong double_signflip_pool[2*2];
void TemplateTable::fneg() {
transition(ftos, ftos);
static jlong *float_signflip = double_quadword(&float_signflip_pool[1], 0x8000000080000000, 0x8000000080000000);
__ xorps(xmm0, ExternalAddress((address) float_signflip));
}
void TemplateTable::dneg() {
transition(dtos, dtos);
static jlong *double_signflip = double_quadword(&double_signflip_pool[1], 0x8000000000000000, 0x8000000000000000);
__ xorpd(xmm0, ExternalAddress((address) double_signflip));
}
void TemplateTable::iinc() {
transition(vtos, vtos);
__ load_signed_byte(rdx, at_bcp(2)); // get constant
locals_index(rbx);
__ addl(iaddress(rbx), rdx);
}
void TemplateTable::wide_iinc() {
transition(vtos, vtos);
__ movl(rdx, at_bcp(4)); // get constant
locals_index_wide(rbx);
__ bswapl(rdx); // swap bytes & sign-extend constant
__ sarl(rdx, 16);
__ addl(iaddress(rbx), rdx);
}
void TemplateTable::convert() {
#ifdef ASSERT
{
TosState tos_in = ilgl;
TosState tos_out = ilgl;
switch (bytecode()) {
case Bytecodes::_i2l: // fall through
case Bytecodes::_i2f: // fall through
case Bytecodes::_i2d: // fall through
case Bytecodes::_i2b: // fall through
case Bytecodes::_i2c: // fall through
case Bytecodes::_i2s: tos_in = itos; break;
case Bytecodes::_l2i: // fall through
case Bytecodes::_l2f: // fall through
case Bytecodes::_l2d: tos_in = ltos; break;
case Bytecodes::_f2i: // fall through
case Bytecodes::_f2l: // fall through
case Bytecodes::_f2d: tos_in = ftos; break;
case Bytecodes::_d2i: // fall through
case Bytecodes::_d2l: // fall through
case Bytecodes::_d2f: tos_in = dtos; break;
default : ShouldNotReachHere();
}
switch (bytecode()) {
case Bytecodes::_l2i: // fall through
case Bytecodes::_f2i: // fall through
case Bytecodes::_d2i: // fall through
case Bytecodes::_i2b: // fall through
case Bytecodes::_i2c: // fall through
case Bytecodes::_i2s: tos_out = itos; break;
case Bytecodes::_i2l: // fall through
case Bytecodes::_f2l: // fall through
case Bytecodes::_d2l: tos_out = ltos; break;
case Bytecodes::_i2f: // fall through
case Bytecodes::_l2f: // fall through
case Bytecodes::_d2f: tos_out = ftos; break;
case Bytecodes::_i2d: // fall through
case Bytecodes::_l2d: // fall through
case Bytecodes::_f2d: tos_out = dtos; break;
default : ShouldNotReachHere();
}
transition(tos_in, tos_out);
}
#endif // ASSERT
static const int64_t is_nan = 0x8000000000000000L;
switch (bytecode()) {
case Bytecodes::_i2l:
__ movslq(rax, rax);
break;
case Bytecodes::_i2f:
__ cvtsi2ssl(xmm0, rax);
break;
case Bytecodes::_i2d:
__ cvtsi2sdl(xmm0, rax);
break;
case Bytecodes::_i2b:
__ movsbl(rax, rax);
break;
case Bytecodes::_i2c:
__ movzwl(rax, rax);
break;
case Bytecodes::_i2s:
__ movswl(rax, rax);
break;
case Bytecodes::_l2i:
__ movl(rax, rax);
break;
case Bytecodes::_l2f:
__ cvtsi2ssq(xmm0, rax);
break;
case Bytecodes::_l2d:
__ cvtsi2sdq(xmm0, rax);
break;
case Bytecodes::_f2i:
{
Label L;
__ cvttss2sil(rax, xmm0);
__ cmpl(rax, 0x80000000); // NaN or overflow/underflow?
__ jcc(Assembler::notEqual, L);
__ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::f2i), 1);
__ bind(L);
}
break;
case Bytecodes::_f2l:
{
Label L;
__ cvttss2siq(rax, xmm0);
__ cmp64(rax, ExternalAddress((address) &is_nan));
__ jcc(Assembler::notEqual, L);
__ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::f2l), 1);
__ bind(L);
}
break;
case Bytecodes::_f2d:
__ cvtss2sd(xmm0, xmm0);
break;
case Bytecodes::_d2i:
{
Label L;
__ cvttsd2sil(rax, xmm0);
__ cmpl(rax, 0x80000000); // NaN or overflow/underflow?
__ jcc(Assembler::notEqual, L);
__ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::d2i), 1);
__ bind(L);
}
break;
case Bytecodes::_d2l:
{
Label L;
__ cvttsd2siq(rax, xmm0);
__ cmp64(rax, ExternalAddress((address) &is_nan));
__ jcc(Assembler::notEqual, L);
__ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::d2l), 1);
__ bind(L);
}
break;
case Bytecodes::_d2f:
__ cvtsd2ss(xmm0, xmm0);
break;
default:
ShouldNotReachHere();
}
}
void TemplateTable::lcmp() {
transition(ltos, itos);
Label done;
__ pop_l(rdx);
__ cmpq(rdx, rax);
__ movl(rax, -1);
__ jccb(Assembler::less, done);
__ setb(Assembler::notEqual, rax);
__ movzbl(rax, rax);
__ bind(done);
}
void TemplateTable::float_cmp(bool is_float, int unordered_result) {
Label done;
if (is_float) {
__ pop_f(xmm1);
__ ucomiss(xmm1, xmm0);
} else {
__ pop_d(xmm1);
__ ucomisd(xmm1, xmm0);
}
if (unordered_result < 0) {
__ movl(rax, -1);
__ jccb(Assembler::parity, done);
__ jccb(Assembler::below, done);
__ setb(Assembler::notEqual, rdx);
__ movzbl(rax, rdx);
} else {
__ movl(rax, 1);
__ jccb(Assembler::parity, done);
__ jccb(Assembler::above, done);
__ movl(rax, 0);
__ jccb(Assembler::equal, done);
__ decrementl(rax);
}
__ bind(done);
}
void TemplateTable::branch(bool is_jsr, bool is_wide) {
__ get_method(rcx); // rcx holds method
__ profile_taken_branch(rax, rbx); // rax holds updated MDP, rbx
const ByteSize be_offset = MethodCounters::backedge_counter_offset() +
InvocationCounter::counter_offset();
const ByteSize inv_offset = MethodCounters::invocation_counter_offset() +
InvocationCounter::counter_offset();
if (is_wide) {
__ movl(rdx, at_bcp(1));
} else {
__ load_signed_short(rdx, at_bcp(1));
}
__ bswapl(rdx);
if (!is_wide) {
__ sarl(rdx, 16);
}
__ movl2ptr(rdx, rdx);
if (is_jsr) {
__ load_unsigned_byte(rbx, Address(r13, rdx, Address::times_1, 0));
__ lea(rax, at_bcp((is_wide ? 5 : 3) -
in_bytes(ConstMethod::codes_offset())));
__ subptr(rax, Address(rcx, Method::const_offset()));
__ addptr(r13, rdx);
__ push_i(rax);
__ dispatch_only(vtos);
return;
}
__ addptr(r13, rdx);
assert(UseLoopCounter || !UseOnStackReplacement,
"on-stack-replacement requires loop counters");
Label backedge_counter_overflow;
Label profile_method;
Label dispatch;
if (UseLoopCounter) {
__ testl(rdx, rdx); // check if forward or backward branch
__ jcc(Assembler::positive, dispatch); // count only if backward branch
Label has_counters;
__ movptr(rax, Address(rcx, Method::method_counters_offset()));
__ testptr(rax, rax);
__ jcc(Assembler::notZero, has_counters);
__ push(rdx);
__ push(rcx);
__ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::build_method_counters),
rcx);
__ pop(rcx);
__ pop(rdx);
__ movptr(rax, Address(rcx, Method::method_counters_offset()));
__ jcc(Assembler::zero, dispatch);
__ bind(has_counters);
if (TieredCompilation) {
Label no_mdo;
int increment = InvocationCounter::count_increment;
int mask = ((1 << Tier0BackedgeNotifyFreqLog) - 1) << InvocationCounter::count_shift;
if (ProfileInterpreter) {
__ movptr(rbx, Address(rcx, in_bytes(Method::method_data_offset())));
__ testptr(rbx, rbx);
__ jccb(Assembler::zero, no_mdo);
const Address mdo_backedge_counter(rbx, in_bytes(MethodData::backedge_counter_offset()) +
in_bytes(InvocationCounter::counter_offset()));
__ increment_mask_and_jump(mdo_backedge_counter, increment, mask, rax, false, Assembler::zero,
UseOnStackReplacement ? &backedge_counter_overflow : NULL);
__ jmp(dispatch);
}
__ bind(no_mdo);
__ movptr(rcx, Address(rcx, Method::method_counters_offset()));
__ increment_mask_and_jump(Address(rcx, be_offset), increment, mask,
rax, false, Assembler::zero,
UseOnStackReplacement ? &backedge_counter_overflow : NULL);
} else {
__ movptr(rcx, Address(rcx, Method::method_counters_offset()));
__ movl(rax, Address(rcx, be_offset)); // load backedge counter
__ incrementl(rax, InvocationCounter::count_increment); // increment counter
__ movl(Address(rcx, be_offset), rax); // store counter
__ movl(rax, Address(rcx, inv_offset)); // load invocation counter
__ andl(rax, InvocationCounter::count_mask_value); // and the status bits
__ addl(rax, Address(rcx, be_offset)); // add both counters
if (ProfileInterpreter) {
__ cmp32(rax,
ExternalAddress((address) &InvocationCounter::InterpreterProfileLimit));
__ jcc(Assembler::less, dispatch);
__ test_method_data_pointer(rax, profile_method);
if (UseOnStackReplacement) {
__ cmp32(rbx,
ExternalAddress((address) &InvocationCounter::InterpreterBackwardBranchLimit));
__ jcc(Assembler::below, dispatch);
const int overflow_frequency = 1024;
__ andl(rbx, overflow_frequency - 1);
__ jcc(Assembler::zero, backedge_counter_overflow);
}
} else {
if (UseOnStackReplacement) {
__ cmp32(rax,
ExternalAddress((address) &InvocationCounter::InterpreterBackwardBranchLimit));
__ jcc(Assembler::aboveEqual, backedge_counter_overflow);
}
}
}
__ bind(dispatch);
}
__ load_unsigned_byte(rbx, Address(r13, 0));
__ dispatch_only(vtos);
if (UseLoopCounter) {
if (ProfileInterpreter) {
__ bind(profile_method);
__ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::profile_method));
__ load_unsigned_byte(rbx, Address(r13, 0)); // restore target bytecode
__ set_method_data_pointer_for_bcp();
__ jmp(dispatch);
}
if (UseOnStackReplacement) {
__ bind(backedge_counter_overflow);
__ negptr(rdx);
__ addptr(rdx, r13); // branch bcp
__ call_VM(noreg,
CAST_FROM_FN_PTR(address,
InterpreterRuntime::frequency_counter_overflow),
rdx);
__ load_unsigned_byte(rbx, Address(r13, 0)); // restore target bytecode
__ testptr(rax, rax); // test result
__ jcc(Assembler::zero, dispatch); // no osr if null
__ movl(rcx, Address(rax, nmethod::entry_bci_offset()));
__ cmpl(rcx, InvalidOSREntryBci);
__ jcc(Assembler::equal, dispatch);
__ mov(r13, rax); // save the nmethod
call_VM(noreg, CAST_FROM_FN_PTR(address, SharedRuntime::OSR_migration_begin));
__ mov(j_rarg0, rax);
const Register retaddr = j_rarg2;
const Register sender_sp = j_rarg1;
__ movptr(sender_sp, Address(rbp, frame::interpreter_frame_sender_sp_offset * wordSize)); // get sender sp
__ leave(); // remove frame anchor
__ pop(retaddr); // get return address
__ mov(rsp, sender_sp); // set sp to sender sp
__ andptr(rsp, -(StackAlignmentInBytes));
__ push(retaddr);
__ jmp(Address(r13, nmethod::osr_entry_point_offset()));
}
}
}
void TemplateTable::if_0cmp(Condition cc) {
transition(itos, vtos);
Label not_taken;
__ testl(rax, rax);
__ jcc(j_not(cc), not_taken);
branch(false, false);
__ bind(not_taken);
__ profile_not_taken_branch(rax);
}
void TemplateTable::if_icmp(Condition cc) {
transition(itos, vtos);
Label not_taken;
__ pop_i(rdx);
__ cmpl(rdx, rax);
__ jcc(j_not(cc), not_taken);
branch(false, false);
__ bind(not_taken);
__ profile_not_taken_branch(rax);
}
void TemplateTable::if_nullcmp(Condition cc) {
transition(atos, vtos);
Label not_taken;
__ testptr(rax, rax);
__ jcc(j_not(cc), not_taken);
branch(false, false);
__ bind(not_taken);
__ profile_not_taken_branch(rax);
}
void TemplateTable::if_acmp(Condition cc) {
transition(atos, vtos);
Label not_taken;
__ pop_ptr(rdx);
__ cmpptr(rdx, rax);
__ jcc(j_not(cc), not_taken);
branch(false, false);
__ bind(not_taken);
__ profile_not_taken_branch(rax);
}
void TemplateTable::ret() {
transition(vtos, vtos);
locals_index(rbx);
__ movslq(rbx, iaddress(rbx)); // get return bci, compute return bcp
__ profile_ret(rbx, rcx);
__ get_method(rax);
__ movptr(r13, Address(rax, Method::const_offset()));
__ lea(r13, Address(r13, rbx, Address::times_1,
ConstMethod::codes_offset()));
__ dispatch_next(vtos);
}
void TemplateTable::wide_ret() {
transition(vtos, vtos);
locals_index_wide(rbx);
__ movptr(rbx, aaddress(rbx)); // get return bci, compute return bcp
__ profile_ret(rbx, rcx);
__ get_method(rax);
__ movptr(r13, Address(rax, Method::const_offset()));
__ lea(r13, Address(r13, rbx, Address::times_1, ConstMethod::codes_offset()));
__ dispatch_next(vtos);
}
void TemplateTable::tableswitch() {
Label default_case, continue_execution;
transition(itos, vtos);
__ lea(rbx, at_bcp(BytesPerInt));
__ andptr(rbx, -BytesPerInt);
__ movl(rcx, Address(rbx, BytesPerInt));
__ movl(rdx, Address(rbx, 2 * BytesPerInt));
__ bswapl(rcx);
__ bswapl(rdx);
__ cmpl(rax, rcx);
__ jcc(Assembler::less, default_case);
__ cmpl(rax, rdx);
__ jcc(Assembler::greater, default_case);
__ subl(rax, rcx);
__ movl(rdx, Address(rbx, rax, Address::times_4, 3 * BytesPerInt));
__ profile_switch_case(rax, rbx, rcx);
__ bind(continue_execution);
__ bswapl(rdx);
__ movl2ptr(rdx, rdx);
__ load_unsigned_byte(rbx, Address(r13, rdx, Address::times_1));
__ addptr(r13, rdx);
__ dispatch_only(vtos);
__ bind(default_case);
__ profile_switch_default(rax);
__ movl(rdx, Address(rbx, 0));
__ jmp(continue_execution);
}
void TemplateTable::lookupswitch() {
transition(itos, itos);
__ stop("lookupswitch bytecode should have been rewritten");
}
void TemplateTable::fast_linearswitch() {
transition(itos, vtos);
Label loop_entry, loop, found, continue_execution;
__ bswapl(rax);
__ lea(rbx, at_bcp(BytesPerInt)); // btw: should be able to get rid of
__ andptr(rbx, -BytesPerInt);
__ movl(rcx, Address(rbx, BytesPerInt));
__ bswapl(rcx);
__ jmpb(loop_entry);
__ bind(loop);
__ cmpl(rax, Address(rbx, rcx, Address::times_8, 2 * BytesPerInt));
__ jcc(Assembler::equal, found);
__ bind(loop_entry);
__ decrementl(rcx);
__ jcc(Assembler::greaterEqual, loop);
__ profile_switch_default(rax);
__ movl(rdx, Address(rbx, 0));
__ jmp(continue_execution);
__ bind(found);
__ movl(rdx, Address(rbx, rcx, Address::times_8, 3 * BytesPerInt));
__ profile_switch_case(rcx, rax, rbx);
__ bind(continue_execution);
__ bswapl(rdx);
__ movl2ptr(rdx, rdx);
__ load_unsigned_byte(rbx, Address(r13, rdx, Address::times_1));
__ addptr(r13, rdx);
__ dispatch_only(vtos);
}
void TemplateTable::fast_binaryswitch() {
transition(itos, vtos);
const Register key = rax; // already set (tosca)
const Register array = rbx;
const Register i = rcx;
const Register j = rdx;
const Register h = rdi;
const Register temp = rsi;
__ lea(array, at_bcp(3 * BytesPerInt)); // btw: should be able to
__ andptr(array, -BytesPerInt);
__ xorl(i, i); // i = 0;
__ movl(j, Address(array, -BytesPerInt)); // j = length(array);
__ bswapl(j);
Label entry;
__ jmp(entry);
{
Label loop;
__ bind(loop);
__ leal(h, Address(i, j, Address::times_1)); // h = i + j;
__ sarl(h, 1); // h = (i + j) >> 1;
__ movl(temp, Address(array, h, Address::times_8));
__ bswapl(temp);
__ cmpl(key, temp);
__ cmovl(Assembler::less, j, h);
__ cmovl(Assembler::greaterEqual, i, h);
__ bind(entry);
__ leal(h, Address(i, 1)); // i+1
__ cmpl(h, j); // i+1 < j
__ jcc(Assembler::less, loop);
}
Label default_case;
__ movl(temp, Address(array, i, Address::times_8));
__ bswapl(temp);
__ cmpl(key, temp);
__ jcc(Assembler::notEqual, default_case);
__ movl(j , Address(array, i, Address::times_8, BytesPerInt));
__ profile_switch_case(i, key, array);
__ bswapl(j);
__ movl2ptr(j, j);
__ load_unsigned_byte(rbx, Address(r13, j, Address::times_1));
__ addptr(r13, j);
__ dispatch_only(vtos);
__ bind(default_case);
__ profile_switch_default(i);
__ movl(j, Address(array, -2 * BytesPerInt));
__ bswapl(j);
__ movl2ptr(j, j);
__ load_unsigned_byte(rbx, Address(r13, j, Address::times_1));
__ addptr(r13, j);
__ dispatch_only(vtos);
}
void TemplateTable::_return(TosState state) {
transition(state, state);
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");
__ movptr(c_rarg1, aaddress(0));
__ load_klass(rdi, c_rarg1);
__ movl(rdi, Address(rdi, Klass::access_flags_offset()));
__ testl(rdi, JVM_ACC_HAS_FINALIZER);
Label skip_register_finalizer;
__ jcc(Assembler::zero, skip_register_finalizer);
__ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::register_finalizer), c_rarg1);
__ bind(skip_register_finalizer);
}
if (state == itos) {
__ narrow(rax);
}
__ remove_activation(state, r13);
__ jmp(r13);
}
void TemplateTable::volatile_barrier(AssemblerMembar_mask_bits
order_constraint) {
if (os::is_MP()) { // Not needed on single CPU
__ membar(order_constraint);
}
}
void TemplateTable::resolve_cache_and_index(int byte_no,
Register Rcache,
Register index,
size_t index_size) {
const Register temp = rbx;
assert_different_registers(Rcache, index, temp);
Label resolved;
assert(byte_no == f1_byte || byte_no == f2_byte, "byte_no out of range");
__ get_cache_and_index_and_bytecode_at_bcp(Rcache, index, temp, byte_no, 1, index_size);
__ cmpl(temp, (int) bytecode()); // have we resolved this bytecode?
__ jcc(Assembler::equal, resolved);
address entry;
switch (bytecode()) {
case Bytecodes::_getstatic:
case Bytecodes::_putstatic:
case Bytecodes::_getfield:
case Bytecodes::_putfield:
entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_get_put);
break;
case Bytecodes::_invokevirtual:
case Bytecodes::_invokespecial:
case Bytecodes::_invokestatic:
case Bytecodes::_invokeinterface:
entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_invoke);
break;
case Bytecodes::_invokehandle:
entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_invokehandle);
break;
case Bytecodes::_invokedynamic:
entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_invokedynamic);
break;
default:
fatal(err_msg("unexpected bytecode: %s", Bytecodes::name(bytecode())));
break;
}
__ movl(temp, (int) bytecode());
__ call_VM(noreg, entry, temp);
__ get_cache_and_index_at_bcp(Rcache, index, 1, index_size);
__ bind(resolved);
}
void TemplateTable::load_field_cp_cache_entry(Register obj,
Register cache,
Register index,
Register off,
Register flags,
bool is_static = false) {
assert_different_registers(cache, index, flags, off);
ByteSize cp_base_offset = ConstantPoolCache::base_offset();
__ movptr(off, Address(cache, index, Address::times_ptr,
in_bytes(cp_base_offset +
ConstantPoolCacheEntry::f2_offset())));
__ movl(flags, Address(cache, index, Address::times_ptr,
in_bytes(cp_base_offset +
ConstantPoolCacheEntry::flags_offset())));
if (is_static) {
__ movptr(obj, Address(cache, index, Address::times_ptr,
in_bytes(cp_base_offset +
ConstantPoolCacheEntry::f1_offset())));
const int mirror_offset = in_bytes(Klass::java_mirror_offset());
__ movptr(obj, Address(obj, mirror_offset));
}
}
void TemplateTable::load_invoke_cp_cache_entry(int byte_no,
Register method,
Register itable_index,
Register flags,
bool is_invokevirtual,
bool is_invokevfinal, /*unused*/
bool is_invokedynamic) {
const Register cache = rcx;
const Register index = rdx;
assert_different_registers(method, flags);
assert_different_registers(method, cache, index);
assert_different_registers(itable_index, flags);
assert_different_registers(itable_index, cache, index);
assert(is_invokevirtual == (byte_no == f2_byte), "is_invokevirtual flag redundant");
const int method_offset = in_bytes(
ConstantPoolCache::base_offset() +
((byte_no == f2_byte)
? ConstantPoolCacheEntry::f2_offset()
: ConstantPoolCacheEntry::f1_offset()));
const int flags_offset = in_bytes(ConstantPoolCache::base_offset() +
ConstantPoolCacheEntry::flags_offset());
const int index_offset = in_bytes(ConstantPoolCache::base_offset() +
ConstantPoolCacheEntry::f2_offset());
size_t index_size = (is_invokedynamic ? sizeof(u4) : sizeof(u2));
resolve_cache_and_index(byte_no, cache, index, index_size);
__ movptr(method, Address(cache, index, Address::times_ptr, method_offset));
if (itable_index != noreg) {
__ movptr(itable_index, Address(cache, index, Address::times_ptr, index_offset));
}
__ movl(flags, Address(cache, index, Address::times_ptr, flags_offset));
}
void TemplateTable::jvmti_post_field_access(Register cache, Register index,
bool is_static, bool has_tos) {
if (JvmtiExport::can_post_field_access()) {
Label L1;
assert_different_registers(cache, index, rax);
__ mov32(rax, ExternalAddress((address) JvmtiExport::get_field_access_count_addr()));
__ testl(rax, rax);
__ jcc(Assembler::zero, L1);
__ get_cache_and_index_at_bcp(c_rarg2, c_rarg3, 1);
__ addptr(c_rarg2, in_bytes(ConstantPoolCache::base_offset()));
__ shll(c_rarg3, LogBytesPerWord);
__ addptr(c_rarg2, c_rarg3);
if (is_static) {
__ xorl(c_rarg1, c_rarg1); // NULL object reference
} else {
__ movptr(c_rarg1, at_tos()); // get object pointer without popping it
__ verify_oop(c_rarg1);
}
__ call_VM(noreg, CAST_FROM_FN_PTR(address,
InterpreterRuntime::post_field_access),
c_rarg1, c_rarg2, c_rarg3);
__ get_cache_and_index_at_bcp(cache, index, 1);
__ bind(L1);
}
}
void TemplateTable::pop_and_check_object(Register r) {
__ pop_ptr(r);
__ null_check(r); // for field access must check obj.
__ verify_oop(r);
}
void TemplateTable::getfield_or_static(int byte_no, bool is_static) {
transition(vtos, vtos);
const Register cache = rcx;
const Register index = rdx;
const Register obj = c_rarg3;
const Register off = rbx;
const Register flags = rax;
const Register bc = c_rarg3; // uses same reg as obj, so don't mix them
resolve_cache_and_index(byte_no, cache, index, sizeof(u2));
jvmti_post_field_access(cache, index, is_static, false);
load_field_cp_cache_entry(obj, cache, index, off, flags, is_static);
if (!is_static) {
pop_and_check_object(obj);
}
const Address field(obj, off, Address::times_1);
Label Done, notByte, notBool, notInt, notShort, notChar,
notLong, notFloat, notObj, notDouble;
__ shrl(flags, ConstantPoolCacheEntry::tos_state_shift);
assert(btos == 0, "change code, btos != 0");
__ andl(flags, ConstantPoolCacheEntry::tos_state_mask);
__ jcc(Assembler::notZero, notByte);
__ load_signed_byte(rax, field);
__ push(btos);
if (!is_static) {
patch_bytecode(Bytecodes::_fast_bgetfield, bc, rbx);
}
__ jmp(Done);
__ bind(notByte);
__ cmpl(flags, ztos);
__ jcc(Assembler::notEqual, notBool);
__ load_signed_byte(rax, field);
__ push(ztos);
if (!is_static) {
patch_bytecode(Bytecodes::_fast_bgetfield, bc, rbx);
}
__ jmp(Done);
__ bind(notBool);
__ cmpl(flags, atos);
__ jcc(Assembler::notEqual, notObj);
__ load_heap_oop(rax, field);
__ push(atos);
if (!is_static) {
patch_bytecode(Bytecodes::_fast_agetfield, bc, rbx);
}
__ jmp(Done);
__ bind(notObj);
__ cmpl(flags, itos);
__ jcc(Assembler::notEqual, notInt);
__ movl(rax, field);
__ push(itos);
if (!is_static) {
patch_bytecode(Bytecodes::_fast_igetfield, bc, rbx);
}
__ jmp(Done);
__ bind(notInt);
__ cmpl(flags, ctos);
__ jcc(Assembler::notEqual, notChar);
__ load_unsigned_short(rax, field);
__ push(ctos);
if (!is_static) {
patch_bytecode(Bytecodes::_fast_cgetfield, bc, rbx);
}
__ jmp(Done);
__ bind(notChar);
__ cmpl(flags, stos);
__ jcc(Assembler::notEqual, notShort);
__ load_signed_short(rax, field);
__ push(stos);
if (!is_static) {
patch_bytecode(Bytecodes::_fast_sgetfield, bc, rbx);
}
__ jmp(Done);
__ bind(notShort);
__ cmpl(flags, ltos);
__ jcc(Assembler::notEqual, notLong);
__ movq(rax, field);
__ push(ltos);
if (!is_static) {
patch_bytecode(Bytecodes::_fast_lgetfield, bc, rbx);
}
__ jmp(Done);
__ bind(notLong);
__ cmpl(flags, ftos);
__ jcc(Assembler::notEqual, notFloat);
__ movflt(xmm0, field);
__ push(ftos);
if (!is_static) {
patch_bytecode(Bytecodes::_fast_fgetfield, bc, rbx);
}
__ jmp(Done);
__ bind(notFloat);
#ifdef ASSERT
__ cmpl(flags, dtos);
__ jcc(Assembler::notEqual, notDouble);
#endif
__ movdbl(xmm0, field);
__ push(dtos);
if (!is_static) {
patch_bytecode(Bytecodes::_fast_dgetfield, bc, rbx);
}
#ifdef ASSERT
__ jmp(Done);
__ bind(notDouble);
__ stop("Bad state");
#endif
__ bind(Done);
}
void TemplateTable::getfield(int byte_no) {
getfield_or_static(byte_no, false);
}
void TemplateTable::getstatic(int byte_no) {
getfield_or_static(byte_no, true);
}
void TemplateTable::jvmti_post_field_mod(Register cache, Register index, bool is_static) {
transition(vtos, vtos);
ByteSize cp_base_offset = ConstantPoolCache::base_offset();
if (JvmtiExport::can_post_field_modification()) {
Label L1;
assert_different_registers(cache, index, rax);
__ mov32(rax, ExternalAddress((address)JvmtiExport::get_field_modification_count_addr()));
__ testl(rax, rax);
__ jcc(Assembler::zero, L1);
__ get_cache_and_index_at_bcp(c_rarg2, rscratch1, 1);
if (is_static) {
__ xorl(c_rarg1, c_rarg1);
} else {
__ movl(c_rarg3, Address(c_rarg2, rscratch1,
Address::times_8,
in_bytes(cp_base_offset +
ConstantPoolCacheEntry::flags_offset())));
__ shrl(c_rarg3, ConstantPoolCacheEntry::tos_state_shift);
ConstantPoolCacheEntry::verify_tos_state_shift();
__ movptr(c_rarg1, at_tos_p1()); // initially assume a one word jvalue
__ cmpl(c_rarg3, ltos);
__ cmovptr(Assembler::equal,
c_rarg1, at_tos_p2()); // ltos (two word jvalue)
__ cmpl(c_rarg3, dtos);
__ cmovptr(Assembler::equal,
c_rarg1, at_tos_p2()); // dtos (two word jvalue)
}
__ addptr(c_rarg2, in_bytes(cp_base_offset));
__ shll(rscratch1, LogBytesPerWord);
__ addptr(c_rarg2, rscratch1);
__ mov(c_rarg3, rsp);
__ call_VM(noreg,
CAST_FROM_FN_PTR(address,
InterpreterRuntime::post_field_modification),
c_rarg1, c_rarg2, c_rarg3);
__ get_cache_and_index_at_bcp(cache, index, 1);
__ bind(L1);
}
}
void TemplateTable::putfield_or_static(int byte_no, bool is_static) {
transition(vtos, vtos);
const Register cache = rcx;
const Register index = rdx;
const Register obj = rcx;
const Register off = rbx;
const Register flags = rax;
const Register bc = c_rarg3;
resolve_cache_and_index(byte_no, cache, index, sizeof(u2));
jvmti_post_field_mod(cache, index, is_static);
load_field_cp_cache_entry(obj, cache, index, off, flags, is_static);
Label notVolatile, Done;
__ movl(rdx, flags);
__ shrl(rdx, ConstantPoolCacheEntry::is_volatile_shift);
__ andl(rdx, 0x1);
const Address field(obj, off, Address::times_1);
Label notByte, notBool, notInt, notShort, notChar,
notLong, notFloat, notObj, notDouble;
__ shrl(flags, ConstantPoolCacheEntry::tos_state_shift);
assert(btos == 0, "change code, btos != 0");
__ andl(flags, ConstantPoolCacheEntry::tos_state_mask);
__ jcc(Assembler::notZero, notByte);
{
__ pop(btos);
if (!is_static) pop_and_check_object(obj);
__ movb(field, rax);
if (!is_static) {
patch_bytecode(Bytecodes::_fast_bputfield, bc, rbx, true, byte_no);
}
__ jmp(Done);
}
__ bind(notByte);
__ cmpl(flags, ztos);
__ jcc(Assembler::notEqual, notBool);
{
__ pop(ztos);
if (!is_static) pop_and_check_object(obj);
__ andl(rax, 0x1);
__ movb(field, rax);
if (!is_static) {
patch_bytecode(Bytecodes::_fast_zputfield, bc, rbx, true, byte_no);
}
__ jmp(Done);
}
__ bind(notBool);
__ cmpl(flags, atos);
__ jcc(Assembler::notEqual, notObj);
{
__ pop(atos);
if (!is_static) pop_and_check_object(obj);
do_oop_store(_masm, field, rax, _bs->kind(), false);
if (!is_static) {
patch_bytecode(Bytecodes::_fast_aputfield, bc, rbx, true, byte_no);
}
__ jmp(Done);
}
__ bind(notObj);
__ cmpl(flags, itos);
__ jcc(Assembler::notEqual, notInt);
{
__ pop(itos);
if (!is_static) pop_and_check_object(obj);
__ movl(field, rax);
if (!is_static) {
patch_bytecode(Bytecodes::_fast_iputfield, bc, rbx, true, byte_no);
}
__ jmp(Done);
}
__ bind(notInt);
__ cmpl(flags, ctos);
__ jcc(Assembler::notEqual, notChar);
{
__ pop(ctos);
if (!is_static) pop_and_check_object(obj);
__ movw(field, rax);
if (!is_static) {
patch_bytecode(Bytecodes::_fast_cputfield, bc, rbx, true, byte_no);
}
__ jmp(Done);
}
__ bind(notChar);
__ cmpl(flags, stos);
__ jcc(Assembler::notEqual, notShort);
{
__ pop(stos);
if (!is_static) pop_and_check_object(obj);
__ movw(field, rax);
if (!is_static) {
patch_bytecode(Bytecodes::_fast_sputfield, bc, rbx, true, byte_no);
}
__ jmp(Done);
}
__ bind(notShort);
__ cmpl(flags, ltos);
__ jcc(Assembler::notEqual, notLong);
{
__ pop(ltos);
if (!is_static) pop_and_check_object(obj);
__ movq(field, rax);
if (!is_static) {
patch_bytecode(Bytecodes::_fast_lputfield, bc, rbx, true, byte_no);
}
__ jmp(Done);
}
__ bind(notLong);
__ cmpl(flags, ftos);
__ jcc(Assembler::notEqual, notFloat);
{
__ pop(ftos);
if (!is_static) pop_and_check_object(obj);
__ movflt(field, xmm0);
if (!is_static) {
patch_bytecode(Bytecodes::_fast_fputfield, bc, rbx, true, byte_no);
}
__ jmp(Done);
}
__ bind(notFloat);
#ifdef ASSERT
__ cmpl(flags, dtos);
__ jcc(Assembler::notEqual, notDouble);
#endif
{
__ pop(dtos);
if (!is_static) pop_and_check_object(obj);
__ movdbl(field, xmm0);
if (!is_static) {
patch_bytecode(Bytecodes::_fast_dputfield, bc, rbx, true, byte_no);
}
}
#ifdef ASSERT
__ jmp(Done);
__ bind(notDouble);
__ stop("Bad state");
#endif
__ bind(Done);
__ testl(rdx, rdx);
__ jcc(Assembler::zero, notVolatile);
volatile_barrier(Assembler::Membar_mask_bits(Assembler::StoreLoad |
Assembler::StoreStore));
__ bind(notVolatile);
}
void TemplateTable::putfield(int byte_no) {
putfield_or_static(byte_no, false);
}
void TemplateTable::putstatic(int byte_no) {
putfield_or_static(byte_no, true);
}
void TemplateTable::jvmti_post_fast_field_mod() {
if (JvmtiExport::can_post_field_modification()) {
Label L2;
__ mov32(c_rarg3, ExternalAddress((address)JvmtiExport::get_field_modification_count_addr()));
__ testl(c_rarg3, c_rarg3);
__ jcc(Assembler::zero, L2);
__ pop_ptr(rbx); // copy the object pointer from tos
__ verify_oop(rbx);
__ push_ptr(rbx); // put the object pointer back on tos
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;
case Bytecodes::_fast_dputfield: __ push_d(); break;
case Bytecodes::_fast_fputfield: __ push_f(); break;
case Bytecodes::_fast_lputfield: __ push_l(rax); break;
default:
ShouldNotReachHere();
}
__ mov(c_rarg3, rsp); // points to jvalue on the stack
__ get_cache_entry_pointer_at_bcp(c_rarg2, rax, 1);
__ verify_oop(rbx);
__ call_VM(noreg,
CAST_FROM_FN_PTR(address,
InterpreterRuntime::post_field_modification),
rbx, c_rarg2, c_rarg3);
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;
case Bytecodes::_fast_dputfield: __ pop_d(); break;
case Bytecodes::_fast_fputfield: __ pop_f(); break;
case Bytecodes::_fast_lputfield: __ pop_l(rax); break;
}
__ bind(L2);
}
}
void TemplateTable::fast_storefield(TosState state) {
transition(state, vtos);
ByteSize base = ConstantPoolCache::base_offset();
jvmti_post_fast_field_mod();
__ get_cache_and_index_at_bcp(rcx, rbx, 1);
__ movl(rdx, Address(rcx, rbx, Address::times_8,
in_bytes(base +
ConstantPoolCacheEntry::flags_offset())));
__ movptr(rbx, Address(rcx, rbx, Address::times_8,
in_bytes(base + ConstantPoolCacheEntry::f2_offset())));
Label notVolatile;
__ shrl(rdx, ConstantPoolCacheEntry::is_volatile_shift);
__ andl(rdx, 0x1);
pop_and_check_object(rcx);
const Address field(rcx, rbx, Address::times_1);
switch (bytecode()) {
case Bytecodes::_fast_aputfield:
do_oop_store(_masm, field, rax, _bs->kind(), false);
break;
case Bytecodes::_fast_lputfield:
__ movq(field, rax);
break;
case Bytecodes::_fast_iputfield:
__ movl(field, rax);
break;
case Bytecodes::_fast_zputfield:
__ andl(rax, 0x1); // boolean is true if LSB is 1
case Bytecodes::_fast_bputfield:
__ movb(field, rax);
break;
case Bytecodes::_fast_sputfield:
case Bytecodes::_fast_cputfield:
__ movw(field, rax);
break;
case Bytecodes::_fast_fputfield:
__ movflt(field, xmm0);
break;
case Bytecodes::_fast_dputfield:
__ movdbl(field, xmm0);
break;
default:
ShouldNotReachHere();
}
__ testl(rdx, rdx);
__ jcc(Assembler::zero, notVolatile);
volatile_barrier(Assembler::Membar_mask_bits(Assembler::StoreLoad |
Assembler::StoreStore));
__ bind(notVolatile);
}
void TemplateTable::fast_accessfield(TosState state) {
transition(atos, state);
if (JvmtiExport::can_post_field_access()) {
Label L1;
__ mov32(rcx, ExternalAddress((address) JvmtiExport::get_field_access_count_addr()));
__ testl(rcx, rcx);
__ jcc(Assembler::zero, L1);
__ get_cache_entry_pointer_at_bcp(c_rarg2, rcx, 1);
__ verify_oop(rax);
__ push_ptr(rax); // save object pointer before call_VM() clobbers it
__ mov(c_rarg1, rax);
__ call_VM(noreg,
CAST_FROM_FN_PTR(address,
InterpreterRuntime::post_field_access),
c_rarg1, c_rarg2);
__ pop_ptr(rax); // restore object pointer
__ bind(L1);
}
__ get_cache_and_index_at_bcp(rcx, rbx, 1);
__ movptr(rbx, Address(rcx, rbx, Address::times_8,
in_bytes(ConstantPoolCache::base_offset() +
ConstantPoolCacheEntry::f2_offset())));
__ verify_oop(rax);
__ null_check(rax);
Address field(rax, rbx, Address::times_1);
switch (bytecode()) {
case Bytecodes::_fast_agetfield:
__ load_heap_oop(rax, field);
__ verify_oop(rax);
break;
case Bytecodes::_fast_lgetfield:
__ movq(rax, field);
break;
case Bytecodes::_fast_igetfield:
__ movl(rax, field);
break;
case Bytecodes::_fast_bgetfield:
__ movsbl(rax, field);
break;
case Bytecodes::_fast_sgetfield:
__ load_signed_short(rax, field);
break;
case Bytecodes::_fast_cgetfield:
__ load_unsigned_short(rax, field);
break;
case Bytecodes::_fast_fgetfield:
__ movflt(xmm0, field);
break;
case Bytecodes::_fast_dgetfield:
__ movdbl(xmm0, field);
break;
default:
ShouldNotReachHere();
}
}
void TemplateTable::fast_xaccess(TosState state) {
transition(vtos, state);
__ movptr(rax, aaddress(0));
__ get_cache_and_index_at_bcp(rcx, rdx, 2);
__ movptr(rbx,
Address(rcx, rdx, Address::times_8,
in_bytes(ConstantPoolCache::base_offset() +
ConstantPoolCacheEntry::f2_offset())));
__ increment(r13);
__ null_check(rax);
switch (state) {
case itos:
__ movl(rax, Address(rax, rbx, Address::times_1));
break;
case atos:
__ load_heap_oop(rax, Address(rax, rbx, Address::times_1));
__ verify_oop(rax);
break;
case ftos:
__ movflt(xmm0, Address(rax, rbx, Address::times_1));
break;
default:
ShouldNotReachHere();
}
__ decrement(r13);
}
void TemplateTable::count_calls(Register method, Register temp) {
ShouldNotReachHere();
}
void TemplateTable::prepare_invoke(int byte_no,
Register method, // linked method (or i-klass)
Register index, // itable index, MethodType, etc.
Register recv, // if caller wants to see it
Register flags // if caller wants to test it
) {
const Bytecodes::Code code = bytecode();
const bool is_invokeinterface = code == Bytecodes::_invokeinterface;
const bool is_invokedynamic = code == Bytecodes::_invokedynamic;
const bool is_invokehandle = code == Bytecodes::_invokehandle;
const bool is_invokevirtual = code == Bytecodes::_invokevirtual;
const bool is_invokespecial = code == Bytecodes::_invokespecial;
const bool load_receiver = (recv != noreg);
const bool save_flags = (flags != noreg);
assert(load_receiver == (code != Bytecodes::_invokestatic && code != Bytecodes::_invokedynamic), "");
assert(save_flags == (is_invokeinterface || is_invokevirtual), "need flags for vfinal");
assert(flags == noreg || flags == rdx, "");
assert(recv == noreg || recv == rcx, "");
if (recv == noreg) recv = rcx;
if (flags == noreg) flags = rdx;
assert_different_registers(method, index, recv, flags);
__ save_bcp();
load_invoke_cp_cache_entry(byte_no, method, index, flags, is_invokevirtual, false, is_invokedynamic);
if (is_invokedynamic || is_invokehandle) {
Label L_no_push;
__ testl(flags, (1 << ConstantPoolCacheEntry::has_appendix_shift));
__ jcc(Assembler::zero, L_no_push);
__ push(rbx);
__ mov(rbx, index);
assert(ConstantPoolCacheEntry::_indy_resolved_references_appendix_offset == 0, "appendix expected at index+0");
__ load_resolved_reference_at_index(index, rbx);
__ pop(rbx);
__ push(index); // push appendix (MethodType, CallSite, etc.)
__ bind(L_no_push);
}
if (load_receiver) {
__ movl(recv, flags);
__ andl(recv, ConstantPoolCacheEntry::parameter_size_mask);
const int no_return_pc_pushed_yet = -1; // argument slot correction before we push return address
const int receiver_is_at_end = -1; // back off one slot to get receiver
Address recv_addr = __ argument_address(recv, no_return_pc_pushed_yet + receiver_is_at_end);
__ movptr(recv, recv_addr);
__ verify_oop(recv);
}
if (save_flags) {
__ movl(r13, flags);
}
__ shrl(flags, ConstantPoolCacheEntry::tos_state_shift);
ConstantPoolCacheEntry::verify_tos_state_shift();
{
const address table_addr = (address) Interpreter::invoke_return_entry_table_for(code);
ExternalAddress table(table_addr);
__ lea(rscratch1, table);
__ movptr(flags, Address(rscratch1, flags, Address::times_ptr));
}
__ push(flags);
if (save_flags) {
__ movl(flags, r13);
__ restore_bcp();
}
}
void TemplateTable::invokevirtual_helper(Register index,
Register recv,
Register flags) {
assert_different_registers(index, recv, rax, rdx);
assert(index == rbx, "");
assert(recv == rcx, "");
Label notFinal;
__ movl(rax, flags);
__ andl(rax, (1 << ConstantPoolCacheEntry::is_vfinal_shift));
__ jcc(Assembler::zero, notFinal);
const Register method = index; // method must be rbx
assert(method == rbx,
"Method* must be rbx for interpreter calling convention");
__ null_check(recv);
__ profile_final_call(rax);
__ profile_arguments_type(rax, method, r13, true);
__ jump_from_interpreted(method, rax);
__ bind(notFinal);
__ null_check(recv, oopDesc::klass_offset_in_bytes());
__ load_klass(rax, recv);
__ profile_virtual_call(rax, r14, rdx);
__ lookup_virtual_method(rax, index, method);
__ profile_arguments_type(rdx, method, r13, true);
__ jump_from_interpreted(method, rdx);
}
void TemplateTable::invokevirtual(int byte_no) {
transition(vtos, vtos);
assert(byte_no == f2_byte, "use this argument");
prepare_invoke(byte_no,
rbx, // method or vtable index
noreg, // unused itable index
rcx, rdx); // recv, flags
invokevirtual_helper(rbx, rcx, rdx);
}
void TemplateTable::invokespecial(int byte_no) {
transition(vtos, vtos);
assert(byte_no == f1_byte, "use this argument");
prepare_invoke(byte_no, rbx, noreg, // get f1 Method*
rcx); // get receiver also for null check
__ verify_oop(rcx);
__ null_check(rcx);
__ profile_call(rax);
__ profile_arguments_type(rax, rbx, r13, false);
__ jump_from_interpreted(rbx, rax);
}
void TemplateTable::invokestatic(int byte_no) {
transition(vtos, vtos);
assert(byte_no == f1_byte, "use this argument");
prepare_invoke(byte_no, rbx); // get f1 Method*
__ profile_call(rax);
__ profile_arguments_type(rax, rbx, r13, false);
__ jump_from_interpreted(rbx, rax);
}
void TemplateTable::fast_invokevfinal(int byte_no) {
transition(vtos, vtos);
assert(byte_no == f2_byte, "use this argument");
__ stop("fast_invokevfinal not used on amd64");
}
void TemplateTable::invokeinterface(int byte_no) {
transition(vtos, vtos);
assert(byte_no == f1_byte, "use this argument");
prepare_invoke(byte_no, rax, rbx, // get f1 Klass*, f2 Method*
rcx, rdx); // recv, flags
Label notMethod;
__ movl(r14, rdx);
__ andl(r14, (1 << ConstantPoolCacheEntry::is_forced_virtual_shift));
__ jcc(Assembler::zero, notMethod);
invokevirtual_helper(rbx, rcx, rdx);
__ bind(notMethod);
__ restore_locals(); // restore r14
__ null_check(rcx, oopDesc::klass_offset_in_bytes());
__ load_klass(rdx, rcx);
Label no_such_interface, no_such_method;
__ lookup_interface_method(// inputs: rec. class, interface, itable index
rdx, rax, noreg,
r13, r14,
no_such_interface,
__ restore_bcp(); // rbcp was destroyed by receiver type check
__ profile_virtual_call(rdx, r13, r14);
__ movptr(rax, Address(rbx, Method::const_offset()));
__ movptr(rax, Address(rax, ConstMethod::constants_offset()));
__ movptr(rax, Address(rax, ConstantPool::pool_holder_offset_in_bytes()));
__ movl(rbx, Address(rbx, Method::itable_index_offset()));
__ subl(rbx, Method::itable_index_max);
__ negl(rbx);
__ lookup_interface_method(// inputs: rec. class, interface, itable index
rdx, rax, rbx,
rbx, r13,
no_such_interface);
__ testptr(rbx, rbx);
__ jcc(Assembler::zero, no_such_method);
__ profile_arguments_type(rdx, rbx, r13, true);
__ jump_from_interpreted(rbx, rdx);
__ should_not_reach_here();
__ bind(no_such_method);
__ pop(rbx); // pop return address (pushed by prepare_invoke)
__ restore_bcp(); // r13 must be correct for exception handler (was destroyed)
__ restore_locals(); // make sure locals pointer is correct as well (was destroyed)
__ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_AbstractMethodError));
__ should_not_reach_here();
__ bind(no_such_interface);
__ pop(rbx); // pop return address (pushed by prepare_invoke)
__ restore_bcp(); // r13 must be correct for exception handler (was destroyed)
__ restore_locals(); // make sure locals pointer is correct as well (was destroyed)
__ call_VM(noreg, CAST_FROM_FN_PTR(address,
InterpreterRuntime::throw_IncompatibleClassChangeError));
__ should_not_reach_here();
}
void TemplateTable::invokehandle(int byte_no) {
transition(vtos, vtos);
assert(byte_no == f1_byte, "use this argument");
const Register rbx_method = rbx;
const Register rax_mtype = rax;
const Register rcx_recv = rcx;
const Register rdx_flags = rdx;
if (!EnableInvokeDynamic) {
__ should_not_reach_here();
return;
}
prepare_invoke(byte_no, rbx_method, rax_mtype, rcx_recv);
__ verify_method_ptr(rbx_method);
__ verify_oop(rcx_recv);
__ null_check(rcx_recv);
__ profile_final_call(rax);
__ profile_arguments_type(rdx, rbx_method, r13, true);
__ jump_from_interpreted(rbx_method, rdx);
}
void TemplateTable::invokedynamic(int byte_no) {
transition(vtos, vtos);
assert(byte_no == f1_byte, "use this argument");
if (!EnableInvokeDynamic) {
__ call_VM(noreg, CAST_FROM_FN_PTR(address,
InterpreterRuntime::throw_IncompatibleClassChangeError));
__ should_not_reach_here();
return;
}
const Register rbx_method = rbx;
const Register rax_callsite = rax;
prepare_invoke(byte_no, rbx_method, rax_callsite);
__ profile_call(r13);
__ profile_arguments_type(rdx, rbx_method, r13, false);
__ verify_oop(rax_callsite);
__ jump_from_interpreted(rbx_method, rdx);
}
void TemplateTable::_new() {
transition(vtos, atos);
__ get_unsigned_2_byte_index_at_bcp(rdx, 1);
Label slow_case;
Label done;
Label initialize_header;
Label initialize_object; // including clearing the fields
Label allocate_shared;
__ get_cpool_and_tags(rsi, rax);
const int tags_offset = Array<u1>::base_offset_in_bytes();
__ cmpb(Address(rax, rdx, Address::times_1, tags_offset),
JVM_CONSTANT_Class);
__ jcc(Assembler::notEqual, slow_case);
__ movptr(rsi, Address(rsi, rdx,
Address::times_8, sizeof(ConstantPool)));
__ cmpb(Address(rsi,
InstanceKlass::init_state_offset()),
InstanceKlass::fully_initialized);
__ jcc(Assembler::notEqual, slow_case);
__ movl(rdx,
Address(rsi,
Klass::layout_helper_offset()));
__ testl(rdx, Klass::_lh_instance_slow_path_bit);
__ jcc(Assembler::notZero, slow_case);
const bool allow_shared_alloc =
Universe::heap()->supports_inline_contig_alloc() && !CMSIncrementalMode;
if (UseTLAB) {
__ movptr(rax, Address(r15_thread, in_bytes(JavaThread::tlab_top_offset())));
__ lea(rbx, Address(rax, rdx, Address::times_1));
__ cmpptr(rbx, Address(r15_thread, in_bytes(JavaThread::tlab_end_offset())));
__ jcc(Assembler::above, allow_shared_alloc ? allocate_shared : slow_case);
__ movptr(Address(r15_thread, in_bytes(JavaThread::tlab_top_offset())), rbx);
if (ZeroTLAB) {
__ jmp(initialize_header);
} else {
__ jmp(initialize_object);
}
}
if (allow_shared_alloc) {
__ bind(allocate_shared);
ExternalAddress top((address)Universe::heap()->top_addr());
ExternalAddress end((address)Universe::heap()->end_addr());
const Register RtopAddr = rscratch1;
const Register RendAddr = rscratch2;
__ lea(RtopAddr, top);
__ lea(RendAddr, end);
__ movptr(rax, Address(RtopAddr, 0));
Label retry;
__ bind(retry);
__ lea(rbx, Address(rax, rdx, Address::times_1));
__ cmpptr(rbx, Address(RendAddr, 0));
__ jcc(Assembler::above, slow_case);
if (os::is_MP()) {
__ lock();
}
__ cmpxchgptr(rbx, Address(RtopAddr, 0));
__ jcc(Assembler::notEqual, retry);
__ incr_allocated_bytes(r15_thread, rdx, 0);
}
if (UseTLAB || Universe::heap()->supports_inline_contig_alloc()) {
__ bind(initialize_object);
__ decrementl(rdx, sizeof(oopDesc));
__ jcc(Assembler::zero, initialize_header);
__ xorl(rcx, rcx); // use zero reg to clear memory (shorter code)
__ shrl(rdx, LogBytesPerLong); // divide by oopSize to simplify the loop
{
Label loop;
__ bind(loop);
__ movq(Address(rax, rdx, Address::times_8,
sizeof(oopDesc) - oopSize),
rcx);
__ decrementl(rdx);
__ jcc(Assembler::notZero, loop);
}
__ bind(initialize_header);
if (UseBiasedLocking) {
__ movptr(rscratch1, Address(rsi, Klass::prototype_header_offset()));
__ movptr(Address(rax, oopDesc::mark_offset_in_bytes()), rscratch1);
} else {
__ movptr(Address(rax, oopDesc::mark_offset_in_bytes()),
(intptr_t) markOopDesc::prototype()); // header (address 0x1)
}
__ xorl(rcx, rcx); // use zero reg to clear memory (shorter code)
__ store_klass_gap(rax, rcx); // zero klass gap for compressed oops
__ store_klass(rax, rsi); // store klass last
{
SkipIfEqual skip(_masm, &DTraceAllocProbes, false);
__ push(atos); // save the return value
__ call_VM_leaf(
CAST_FROM_FN_PTR(address, SharedRuntime::dtrace_object_alloc), rax);
__ pop(atos); // restore the return value
}
__ jmp(done);
}
__ bind(slow_case);
__ get_constant_pool(c_rarg1);
__ get_unsigned_2_byte_index_at_bcp(c_rarg2, 1);
call_VM(rax, CAST_FROM_FN_PTR(address, InterpreterRuntime::_new), c_rarg1, c_rarg2);
__ verify_oop(rax);
__ bind(done);
}
void TemplateTable::newarray() {
transition(itos, atos);
__ load_unsigned_byte(c_rarg1, at_bcp(1));
__ movl(c_rarg2, rax);
call_VM(rax, CAST_FROM_FN_PTR(address, InterpreterRuntime::newarray),
c_rarg1, c_rarg2);
}
void TemplateTable::anewarray() {
transition(itos, atos);
__ get_unsigned_2_byte_index_at_bcp(c_rarg2, 1);
__ get_constant_pool(c_rarg1);
__ movl(c_rarg3, rax);
call_VM(rax, CAST_FROM_FN_PTR(address, InterpreterRuntime::anewarray),
c_rarg1, c_rarg2, c_rarg3);
}
void TemplateTable::arraylength() {
transition(atos, itos);
__ null_check(rax, arrayOopDesc::length_offset_in_bytes());
__ movl(rax, Address(rax, arrayOopDesc::length_offset_in_bytes()));
}
void TemplateTable::checkcast() {
transition(atos, atos);
Label done, is_null, ok_is_subtype, quicked, resolved;
__ testptr(rax, rax); // object is in rax
__ jcc(Assembler::zero, is_null);
__ get_cpool_and_tags(rcx, rdx); // rcx=cpool, rdx=tags array
__ get_unsigned_2_byte_index_at_bcp(rbx, 1); // rbx=index
__ cmpb(Address(rdx, rbx,
Address::times_1,
Array<u1>::base_offset_in_bytes()),
JVM_CONSTANT_Class);
__ jcc(Assembler::equal, quicked);
__ push(atos); // save receiver for result, and for GC
call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::quicken_io_cc));
__ get_vm_result_2(rax, r15_thread);
__ pop_ptr(rdx); // restore receiver
__ jmpb(resolved);
__ bind(quicked);
__ mov(rdx, rax); // Save object in rdx; rax needed for subtype check
__ movptr(rax, Address(rcx, rbx,
Address::times_8, sizeof(ConstantPool)));
__ bind(resolved);
__ load_klass(rbx, rdx);
__ gen_subtype_check(rbx, ok_is_subtype);
__ push_ptr(rdx);
__ jump(ExternalAddress(Interpreter::_throw_ClassCastException_entry));
__ bind(ok_is_subtype);
__ mov(rax, rdx); // Restore object in rdx
if (ProfileInterpreter) {
__ jmp(done);
__ bind(is_null);
__ profile_null_seen(rcx);
} else {
__ bind(is_null); // same as 'done'
}
__ bind(done);
}
void TemplateTable::instanceof() {
transition(atos, itos);
Label done, is_null, ok_is_subtype, quicked, resolved;
__ testptr(rax, rax);
__ jcc(Assembler::zero, is_null);
__ get_cpool_and_tags(rcx, rdx); // rcx=cpool, rdx=tags array
__ get_unsigned_2_byte_index_at_bcp(rbx, 1); // rbx=index
__ cmpb(Address(rdx, rbx,
Address::times_1,
Array<u1>::base_offset_in_bytes()),
JVM_CONSTANT_Class);
__ jcc(Assembler::equal, quicked);
__ push(atos); // save receiver for result, and for GC
call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::quicken_io_cc));
__ get_vm_result_2(rax, r15_thread);
__ pop_ptr(rdx); // restore receiver
__ verify_oop(rdx);
__ load_klass(rdx, rdx);
__ jmpb(resolved);
__ bind(quicked);
__ load_klass(rdx, rax);
__ movptr(rax, Address(rcx, rbx,
Address::times_8, sizeof(ConstantPool)));
__ bind(resolved);
__ gen_subtype_check(rdx, ok_is_subtype);
__ xorl(rax, rax);
__ jmpb(done);
__ bind(ok_is_subtype);
__ movl(rax, 1);
if (ProfileInterpreter) {
__ jmp(done);
__ bind(is_null);
__ profile_null_seen(rcx);
} else {
__ bind(is_null); // same as 'done'
}
__ bind(done);
}
void TemplateTable::_breakpoint() {
transition(vtos, vtos);
__ get_method(c_rarg1);
__ call_VM(noreg,
CAST_FROM_FN_PTR(address,
InterpreterRuntime::get_original_bytecode_at),
c_rarg1, r13);
__ mov(rbx, rax);
__ get_method(c_rarg1);
__ call_VM(noreg,
CAST_FROM_FN_PTR(address, InterpreterRuntime::_breakpoint),
c_rarg1, r13);
__ dispatch_only_normal(vtos);
}
void TemplateTable::athrow() {
transition(atos, vtos);
__ null_check(rax);
__ jump(ExternalAddress(Interpreter::throw_exception_entry()));
}
void TemplateTable::monitorenter() {
transition(atos, vtos);
__ null_check(rax);
const Address monitor_block_top(
rbp, frame::interpreter_frame_monitor_block_top_offset * wordSize);
const Address monitor_block_bot(
rbp, frame::interpreter_frame_initial_sp_offset * wordSize);
const int entry_size = frame::interpreter_frame_monitor_size() * wordSize;
Label allocated;
__ xorl(c_rarg1, c_rarg1); // points to free slot or NULL
{
Label entry, loop, exit;
__ movptr(c_rarg3, monitor_block_top); // points to current entry,
__ lea(c_rarg2, monitor_block_bot); // points to word before bottom
__ jmpb(entry);
__ bind(loop);
__ cmpptr(Address(c_rarg3, BasicObjectLock::obj_offset_in_bytes()), (int32_t) NULL_WORD);
__ cmov(Assembler::equal, c_rarg1, c_rarg3);
__ cmpptr(rax, Address(c_rarg3, BasicObjectLock::obj_offset_in_bytes()));
__ jccb(Assembler::equal, exit);
__ addptr(c_rarg3, entry_size);
__ bind(entry);
__ cmpptr(c_rarg3, c_rarg2);
__ jcc(Assembler::notEqual, loop);
__ bind(exit);
}
__ testptr(c_rarg1, c_rarg1); // check if a slot has been found
__ jcc(Assembler::notZero, allocated); // if found, continue with that one
{
Label entry, loop;
__ movptr(c_rarg1, monitor_block_bot); // c_rarg1: old expression stack bottom
__ subptr(rsp, entry_size); // move expression stack top
__ subptr(c_rarg1, entry_size); // move expression stack bottom
__ mov(c_rarg3, rsp); // set start value for copy loop
__ movptr(monitor_block_bot, c_rarg1); // set new monitor block bottom
__ jmp(entry);
__ bind(loop);
__ movptr(c_rarg2, Address(c_rarg3, entry_size)); // load expression stack
__ movptr(Address(c_rarg3, 0), c_rarg2); // and store it at new location
__ addptr(c_rarg3, wordSize); // advance to next word
__ bind(entry);
__ cmpptr(c_rarg3, c_rarg1); // check if bottom reached
__ jcc(Assembler::notEqual, loop); // if not at bottom then
}
__ bind(allocated);
__ increment(r13);
__ movptr(Address(c_rarg1, BasicObjectLock::obj_offset_in_bytes()), rax);
__ lock_object(c_rarg1);
__ save_bcp(); // in case of exception
__ generate_stack_overflow_check(0);
__ dispatch_next(vtos);
}
void TemplateTable::monitorexit() {
transition(atos, vtos);
__ null_check(rax);
const Address monitor_block_top(
rbp, frame::interpreter_frame_monitor_block_top_offset * wordSize);
const Address monitor_block_bot(
rbp, frame::interpreter_frame_initial_sp_offset * wordSize);
const int entry_size = frame::interpreter_frame_monitor_size() * wordSize;
Label found;
{
Label entry, loop;
__ movptr(c_rarg1, monitor_block_top); // points to current entry,
__ lea(c_rarg2, monitor_block_bot); // points to word before bottom
__ jmpb(entry);
__ bind(loop);
__ cmpptr(rax, Address(c_rarg1, BasicObjectLock::obj_offset_in_bytes()));
__ jcc(Assembler::equal, found);
__ addptr(c_rarg1, entry_size);
__ bind(entry);
__ cmpptr(c_rarg1, c_rarg2);
__ jcc(Assembler::notEqual, loop);
}
__ call_VM(noreg, CAST_FROM_FN_PTR(address,
InterpreterRuntime::throw_illegal_monitor_state_exception));
__ should_not_reach_here();
__ bind(found);
__ push_ptr(rax); // make sure object is on stack (contract with oopMaps)
__ unlock_object(c_rarg1);
__ pop_ptr(rax); // discard object
}
void TemplateTable::wide() {
transition(vtos, vtos);
__ load_unsigned_byte(rbx, at_bcp(1));
__ lea(rscratch1, ExternalAddress((address)Interpreter::_wentry_point));
__ jmp(Address(rscratch1, rbx, Address::times_8));
}
void TemplateTable::multianewarray() {
transition(vtos, atos);
__ load_unsigned_byte(rax, at_bcp(3)); // get number of dimensions
__ lea(c_rarg1, Address(rsp, rax, Address::times_8, -wordSize));
call_VM(rax,
CAST_FROM_FN_PTR(address, InterpreterRuntime::multianewarray),
c_rarg1);
__ load_unsigned_byte(rbx, at_bcp(3));
__ lea(rsp, Address(rsp, rbx, Address::times_8));
}
#endif // !CC_INTERP
C:\hotspot-69087d08d473\src\cpu\x86\vm/templateTable_x86_64.hpp
#ifndef CPU_X86_VM_TEMPLATETABLE_X86_64_HPP
#define CPU_X86_VM_TEMPLATETABLE_X86_64_HPP
static void prepare_invoke(int byte_no,
Register method, // linked method (or i-klass)
Register index = noreg, // itable index, MethodType, etc.
Register recv = noreg, // if caller wants to see it
Register flags = noreg // if caller wants to test it
);
static void invokevirtual_helper(Register index, Register recv,
Register flags);
static void volatile_barrier(Assembler::Membar_mask_bits order_constraint);
static void index_check(Register array, Register index);
static void index_check_without_pop(Register array, Register index);
#endif // CPU_X86_VM_TEMPLATETABLE_X86_64_HPP
C:\hotspot-69087d08d473\src\cpu\x86\vm/vmreg_x86.cpp
#include "precompiled.hpp"
#include "asm/assembler.hpp"
#include "code/vmreg.hpp"
void VMRegImpl::set_regName() {
Register reg = ::as_Register(0);
int i;
for (i = 0; i < ConcreteRegisterImpl::max_gpr ; ) {
regName[i++] = reg->name();
#ifdef AMD64
regName[i++] = reg->name();
#endif // AMD64
reg = reg->successor();
}
FloatRegister freg = ::as_FloatRegister(0);
for ( ; i < ConcreteRegisterImpl::max_fpr ; ) {
regName[i++] = freg->name();
regName[i++] = freg->name();
freg = freg->successor();
}
XMMRegister xreg = ::as_XMMRegister(0);
for ( ; i < ConcreteRegisterImpl::max_xmm ; ) {
for (int j = 0 ; j < 8 ; j++) {
regName[i++] = xreg->name();
}
xreg = xreg->successor();
}
for ( ; i < ConcreteRegisterImpl::number_of_registers ; i ++ ) {
regName[i] = "NON-GPR-FPR-XMM";
}
}
C:\hotspot-69087d08d473\src\cpu\x86\vm/vmreg_x86.hpp
#ifndef CPU_X86_VM_VMREG_X86_HPP
#define CPU_X86_VM_VMREG_X86_HPP
bool is_Register();
Register as_Register();
bool is_FloatRegister();
FloatRegister as_FloatRegister();
bool is_XMMRegister();
XMMRegister as_XMMRegister();
#endif // CPU_X86_VM_VMREG_X86_HPP
C:\hotspot-69087d08d473\src\cpu\x86\vm/vmreg_x86.inline.hpp
#ifndef CPU_X86_VM_VMREG_X86_INLINE_HPP
#define CPU_X86_VM_VMREG_X86_INLINE_HPP
inline VMReg RegisterImpl::as_VMReg() {
if( this==noreg ) return VMRegImpl::Bad();
#ifdef AMD64
return VMRegImpl::as_VMReg(encoding() << 1 );
#else
return VMRegImpl::as_VMReg(encoding() );
#endif // AMD64
}
inline VMReg FloatRegisterImpl::as_VMReg() {
return VMRegImpl::as_VMReg((encoding() << 1) + ConcreteRegisterImpl::max_gpr);
}
inline VMReg XMMRegisterImpl::as_VMReg() {
return VMRegImpl::as_VMReg((encoding() << 3) + ConcreteRegisterImpl::max_fpr);
}
inline bool VMRegImpl::is_Register() {
return (unsigned int) value() < (unsigned int) ConcreteRegisterImpl::max_gpr;
}
inline bool VMRegImpl::is_FloatRegister() {
return value() >= ConcreteRegisterImpl::max_gpr && value() < ConcreteRegisterImpl::max_fpr;
}
inline bool VMRegImpl::is_XMMRegister() {
return value() >= ConcreteRegisterImpl::max_fpr && value() < ConcreteRegisterImpl::max_xmm;
}
inline Register VMRegImpl::as_Register() {
assert( is_Register(), "must be");
#ifdef AMD64
return ::as_Register(value() >> 1);
#else
return ::as_Register(value());
#endif // AMD64
}
inline FloatRegister VMRegImpl::as_FloatRegister() {
assert( is_FloatRegister() && is_even(value()), "must be" );
return ::as_FloatRegister((value() - ConcreteRegisterImpl::max_gpr) >> 1);
}
inline XMMRegister VMRegImpl::as_XMMRegister() {
assert( is_XMMRegister() && is_even(value()), "must be" );
return ::as_XMMRegister((value() - ConcreteRegisterImpl::max_fpr) >> 3);
}
inline bool VMRegImpl::is_concrete() {
assert(is_reg(), "must be");
#ifndef AMD64
if (is_Register()) return true;
#endif // AMD64
return is_even(value());
}
#endif // CPU_X86_VM_VMREG_X86_INLINE_HPP
C:\hotspot-69087d08d473\src\cpu\x86\vm/vmStructs_x86.hpp
#ifndef CPU_X86_VM_VMSTRUCTS_X86_HPP
#define CPU_X86_VM_VMSTRUCTS_X86_HPP
#define VM_STRUCTS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \
\
volatile_nonstatic_field(JavaFrameAnchor, _last_Java_fp, intptr_t*)
#define VM_TYPES_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type)
#define VM_INT_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant)
#define VM_LONG_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant)
#endif // CPU_X86_VM_VMSTRUCTS_X86_HPP
C:\hotspot-69087d08d473\src\cpu\x86\vm/vm_version_ext_x86.cpp
#include "precompiled.hpp"
#include "jvm.h"
#include "utilities/macros.hpp"
#include "asm/macroAssembler.hpp"
#include "asm/macroAssembler.inline.hpp"
#include "memory/allocation.inline.hpp"
#include "memory/resourceArea.hpp"
#include "runtime/java.hpp"
#include "runtime/stubCodeGenerator.hpp"
#include "vm_version_ext_x86.hpp"
typedef enum {
CPU_FAMILY_8086_8088 = 0,
CPU_FAMILY_INTEL_286 = 2,
CPU_FAMILY_INTEL_386 = 3,
CPU_FAMILY_INTEL_486 = 4,
CPU_FAMILY_PENTIUM = 5,
CPU_FAMILY_PENTIUMPRO = 6, // Same family several models
CPU_FAMILY_PENTIUM_4 = 0xF
} FamilyFlag;
typedef enum {
RDTSCP_FLAG = 0x08000000, // bit 27
INTEL64_FLAG = 0x20000000 // bit 29
} _featureExtendedEdxFlag;
#define CPUID_STANDARD_FN 0x0
#define CPUID_STANDARD_FN_1 0x1
#define CPUID_STANDARD_FN_4 0x4
#define CPUID_STANDARD_FN_B 0xb
#define CPUID_EXTENDED_FN 0x80000000
#define CPUID_EXTENDED_FN_1 0x80000001
#define CPUID_EXTENDED_FN_2 0x80000002
#define CPUID_EXTENDED_FN_3 0x80000003
#define CPUID_EXTENDED_FN_4 0x80000004
#define CPUID_EXTENDED_FN_7 0x80000007
#define CPUID_EXTENDED_FN_8 0x80000008
typedef enum {
FPU_FLAG = 0x00000001,
VME_FLAG = 0x00000002,
DE_FLAG = 0x00000004,
PSE_FLAG = 0x00000008,
TSC_FLAG = 0x00000010,
MSR_FLAG = 0x00000020,
PAE_FLAG = 0x00000040,
MCE_FLAG = 0x00000080,
CX8_FLAG = 0x00000100,
APIC_FLAG = 0x00000200,
SEP_FLAG = 0x00000800,
MTRR_FLAG = 0x00001000,
PGE_FLAG = 0x00002000,
MCA_FLAG = 0x00004000,
CMOV_FLAG = 0x00008000,
PAT_FLAG = 0x00010000,
PSE36_FLAG = 0x00020000,
PSNUM_FLAG = 0x00040000,
CLFLUSH_FLAG = 0x00080000,
DTS_FLAG = 0x00200000,
ACPI_FLAG = 0x00400000,
MMX_FLAG = 0x00800000,
FXSR_FLAG = 0x01000000,
SSE_FLAG = 0x02000000,
SSE2_FLAG = 0x04000000,
SS_FLAG = 0x08000000,
HTT_FLAG = 0x10000000,
TM_FLAG = 0x20000000
} FeatureEdxFlag;
static BufferBlob* cpuid_brand_string_stub_blob;
static const int cpuid_brand_string_stub_size = 550;
extern "C" {
typedef void (*getCPUIDBrandString_stub_t)(void*);
}
static getCPUIDBrandString_stub_t getCPUIDBrandString_stub = NULL;
class VM_Version_Ext_StubGenerator: public StubCodeGenerator {
public:
VM_Version_Ext_StubGenerator(CodeBuffer *c) : StubCodeGenerator(c) {}
address generate_getCPUIDBrandString(void) {
const uint32_t HS_EFL_AC = 0x40000;
const uint32_t HS_EFL_ID = 0x200000;
const int CPU_FAMILY_SHIFT = 8;
const uint32_t CPU_FAMILY_386 = (3 << CPU_FAMILY_SHIFT);
const uint32_t CPU_FAMILY_486 = (4 << CPU_FAMILY_SHIFT);
Label detect_486, cpu486, detect_586, done, ext_cpuid;
StubCodeMark mark(this, "VM_Version_Ext", "getCPUIDNameInfo_stub");
# define __ _masm->
address start = __ pc();
__ push(rbp);
#ifdef _LP64
__ mov(rbp, c_rarg0); // cpuid_info address
#else
__ movptr(rbp, Address(rsp, 8)); // cpuid_info address
#endif
__ push(rbx);
__ push(rsi);
__ pushf(); // preserve rbx, and flags
__ pop(rax);
__ push(rax);
__ mov(rcx, rax);
__ xorl(rax, HS_EFL_AC);
__ push(rax);
__ popf();
__ pushf();
__ pop(rax);
__ cmpptr(rax, rcx);
__ jccb(Assembler::notEqual, detect_486);
__ movl(rax, CPU_FAMILY_386);
__ jmp(done);
__ bind(detect_486);
__ mov(rax, rcx);
__ xorl(rax, HS_EFL_ID);
__ push(rax);
__ popf();
__ pushf();
__ pop(rax);
__ cmpptr(rcx, rax);
__ jccb(Assembler::notEqual, detect_586);
__ bind(cpu486);
__ movl(rax, CPU_FAMILY_486);
__ jmp(done);
__ bind(detect_586);
__ xorl(rax, rax);
__ cpuid();
__ orl(rax, rax);
__ jcc(Assembler::equal, cpu486); // if cpuid doesn't support an input
__ bind(ext_cpuid);
__ movl(rax, CPUID_EXTENDED_FN);
__ cpuid();
__ cmpl(rax, CPUID_EXTENDED_FN_4);
__ jcc(Assembler::below, done);
__ movl(rax, CPUID_EXTENDED_FN_2);
__ cpuid();
__ lea(rsi, Address(rbp, in_bytes(VM_Version_Ext::proc_name_0_offset())));
__ movl(Address(rsi, 0), rax);
__ lea(rsi, Address(rbp, in_bytes(VM_Version_Ext::proc_name_1_offset())));
__ movl(Address(rsi, 0), rbx);
__ lea(rsi, Address(rbp, in_bytes(VM_Version_Ext::proc_name_2_offset())));
__ movl(Address(rsi, 0), rcx);
__ lea(rsi, Address(rbp, in_bytes(VM_Version_Ext::proc_name_3_offset())));
__ movl(Address(rsi,0), rdx);
__ movl(rax, CPUID_EXTENDED_FN_3);
__ cpuid();
__ lea(rsi, Address(rbp, in_bytes(VM_Version_Ext::proc_name_4_offset())));
__ movl(Address(rsi, 0), rax);
__ lea(rsi, Address(rbp, in_bytes(VM_Version_Ext::proc_name_5_offset())));
__ movl(Address(rsi, 0), rbx);
__ lea(rsi, Address(rbp, in_bytes(VM_Version_Ext::proc_name_6_offset())));
__ movl(Address(rsi, 0), rcx);
__ lea(rsi, Address(rbp, in_bytes(VM_Version_Ext::proc_name_7_offset())));
__ movl(Address(rsi,0), rdx);
__ movl(rax, CPUID_EXTENDED_FN_4);
__ cpuid();
__ lea(rsi, Address(rbp, in_bytes(VM_Version_Ext::proc_name_8_offset())));
__ movl(Address(rsi, 0), rax);
__ lea(rsi, Address(rbp, in_bytes(VM_Version_Ext::proc_name_9_offset())));
__ movl(Address(rsi, 0), rbx);
__ lea(rsi, Address(rbp, in_bytes(VM_Version_Ext::proc_name_10_offset())));
__ movl(Address(rsi, 0), rcx);
__ lea(rsi, Address(rbp, in_bytes(VM_Version_Ext::proc_name_11_offset())));
__ movl(Address(rsi,0), rdx);
__ bind(done);
__ popf();
__ pop(rsi);
__ pop(rbx);
__ pop(rbp);
__ ret(0);
# undef __
return start;
};
};
const size_t VM_Version_Ext::VENDOR_LENGTH = 13;
const size_t VM_Version_Ext::CPU_EBS_MAX_LENGTH = (3 * 4 * 4 + 1);
const size_t VM_Version_Ext::CPU_TYPE_DESC_BUF_SIZE = 256;
const size_t VM_Version_Ext::CPU_DETAILED_DESC_BUF_SIZE = 4096;
char* VM_Version_Ext::_cpu_brand_string = NULL;
jlong VM_Version_Ext::_max_qualified_cpu_frequency = 0;
int VM_Version_Ext::_no_of_threads = 0;
int VM_Version_Ext::_no_of_cores = 0;
int VM_Version_Ext::_no_of_packages = 0;
void VM_Version_Ext::initialize(void) {
ResourceMark rm;
cpuid_brand_string_stub_blob = BufferBlob::create("getCPUIDBrandString_stub", cpuid_brand_string_stub_size);
if (cpuid_brand_string_stub_blob == NULL) {
vm_exit_during_initialization("Unable to allocate getCPUIDBrandString_stub");
}
CodeBuffer c(cpuid_brand_string_stub_blob);
VM_Version_Ext_StubGenerator g(&c);
getCPUIDBrandString_stub = CAST_TO_FN_PTR(getCPUIDBrandString_stub_t,
g.generate_getCPUIDBrandString());
}
const char* VM_Version_Ext::cpu_model_description(void) {
uint32_t cpu_family = extended_cpu_family();
uint32_t cpu_model = extended_cpu_model();
const char* model = NULL;
if (cpu_family == CPU_FAMILY_PENTIUMPRO) {
for (uint32_t i = 0; i <= cpu_model; i++) {
model = _model_id_pentium_pro[i];
if (model == NULL) {
break;
}
}
}
return model;
}
const char* VM_Version_Ext::cpu_brand_string(void) {
if (_cpu_brand_string == NULL) {
_cpu_brand_string = NEW_C_HEAP_ARRAY_RETURN_NULL(char, CPU_EBS_MAX_LENGTH, mtInternal);
if (NULL == _cpu_brand_string) {
return NULL;
}
int ret_val = cpu_extended_brand_string(_cpu_brand_string, CPU_EBS_MAX_LENGTH);
if (ret_val != OS_OK) {
FREE_C_HEAP_ARRAY(char, _cpu_brand_string, mtInternal);
_cpu_brand_string = NULL;
}
}
return _cpu_brand_string;
}
const char* VM_Version_Ext::cpu_brand(void) {
const char* brand = NULL;
if ((_cpuid_info.std_cpuid1_ebx.value & 0xFF) > 0) {
int brand_num = _cpuid_info.std_cpuid1_ebx.value & 0xFF;
brand = _brand_id[0];
for (int i = 0; brand != NULL && i <= brand_num; i += 1) {
brand = _brand_id[i];
}
}
return brand;
}
bool VM_Version_Ext::cpu_is_em64t(void) {
return ((_cpuid_info.ext_cpuid1_edx.value & INTEL64_FLAG) == INTEL64_FLAG);
}
bool VM_Version_Ext::is_netburst(void) {
return (is_intel() && (extended_cpu_family() == CPU_FAMILY_PENTIUM_4));
}
bool VM_Version_Ext::supports_tscinv_ext(void) {
if (!supports_tscinv_bit()) {
return false;
}
if (is_intel()) {
return true;
}
if (is_amd()) {
return !is_amd_Barcelona();
}
return false;
}
void VM_Version_Ext::resolve_cpu_information_details(void) {
_no_of_threads = os::processor_count();
int threads_per_package = threads_per_core() * cores_per_cpu();
_no_of_packages = _no_of_threads / threads_per_package;
if (0 == _no_of_packages) {
_no_of_packages = 1;
}
_no_of_cores = cores_per_cpu() * _no_of_packages;
}
int VM_Version_Ext::number_of_threads(void) {
if (_no_of_threads == 0) {
resolve_cpu_information_details();
}
return _no_of_threads;
}
int VM_Version_Ext::number_of_cores(void) {
if (_no_of_cores == 0) {
resolve_cpu_information_details();
}
return _no_of_cores;
}
int VM_Version_Ext::number_of_sockets(void) {
if (_no_of_packages == 0) {
resolve_cpu_information_details();
}
return _no_of_packages;
}
const char* VM_Version_Ext::cpu_family_description(void) {
int cpu_family_id = extended_cpu_family();
if (is_amd()) {
return _family_id_amd[cpu_family_id];
}
if (is_intel()) {
if (cpu_family_id == CPU_FAMILY_PENTIUMPRO) {
return cpu_model_description();
}
return _family_id_intel[cpu_family_id];
}
return "Unknown x86";
}
int VM_Version_Ext::cpu_type_description(char* const buf, size_t buf_len) {
assert(buf != NULL, "buffer is NULL!");
assert(buf_len >= CPU_TYPE_DESC_BUF_SIZE, "buffer len should at least be == CPU_TYPE_DESC_BUF_SIZE!");
const char* cpu_type = NULL;
const char* x64 = NULL;
if (is_intel()) {
cpu_type = "Intel";
x64 = cpu_is_em64t() ? " Intel64" : "";
} else if (is_amd()) {
cpu_type = "AMD";
x64 = cpu_is_em64t() ? " AMD64" : "";
} else {
cpu_type = "Unknown x86";
x64 = cpu_is_em64t() ? " x86_64" : "";
}
jio_snprintf(buf, buf_len, "%s %s%s SSE SSE2%s%s%s%s%s%s%s%s",
cpu_type,
cpu_family_description(),
supports_ht() ? " (HT)" : "",
supports_sse3() ? " SSE3" : "",
supports_ssse3() ? " SSSE3" : "",
supports_sse4_1() ? " SSE4.1" : "",
supports_sse4_2() ? " SSE4.2" : "",
supports_sse4a() ? " SSE4A" : "",
is_netburst() ? " Netburst" : "",
is_intel_family_core() ? " Core" : "",
x64);
return OS_OK;
}
int VM_Version_Ext::cpu_extended_brand_string(char* const buf, size_t buf_len) {
assert(buf != NULL, "buffer is NULL!");
assert(buf_len >= CPU_EBS_MAX_LENGTH, "buffer len should at least be == CPU_EBS_MAX_LENGTH!");
assert(getCPUIDBrandString_stub != NULL, "not initialized");
getCPUIDBrandString_stub(&_cpuid_info);
return OS_OK;
}
size_t VM_Version_Ext::cpu_write_support_string(char* const buf, size_t buf_len) {
guarantee(buf != NULL, "buffer is NULL!");
guarantee(buf_len > 0, "buffer len not enough!");
unsigned int flag = 0;
unsigned int fi = 0;
size_t written = 0;
const char* prefix = "";
#define WRITE_TO_BUF(string) \
{ \
int res = jio_snprintf(&buf[written], buf_len - written, "%s%s", prefix, string); \
if (res < 0) { \
return buf_len - 1; \
} \
written += res; \
if (prefix[0] == '\0') { \
prefix = ", "; \
} \
}
for (flag = 1, fi = 0; flag <= 0x20000000 ; flag <<= 1, fi++) {
if (flag == HTT_FLAG && (((_cpuid_info.std_cpuid1_ebx.value >> 16) & 0xff) <= 1)) {
continue; /* no hyperthreading */
} else if (flag == SEP_FLAG && (cpu_family() == CPU_FAMILY_PENTIUMPRO && ((_cpuid_info.std_cpuid1_eax.value & 0xff) < 0x33))) {
continue; /* no fast system call */
}
if ((_cpuid_info.std_cpuid1_edx.value & flag) && strlen(_feature_edx_id[fi]) > 0) {
WRITE_TO_BUF(_feature_edx_id[fi]);
}
}
for (flag = 1, fi = 0; flag <= 0x20000000; flag <<= 1, fi++) {
if ((_cpuid_info.std_cpuid1_ecx.value & flag) && strlen(_feature_ecx_id[fi]) > 0) {
WRITE_TO_BUF(_feature_ecx_id[fi]);
}
}
for (flag = 1, fi = 0; flag <= 0x20000000 ; flag <<= 1, fi++) {
if ((_cpuid_info.ext_cpuid1_ecx.value & flag) && strlen(_feature_extended_ecx_id[fi]) > 0) {
WRITE_TO_BUF(_feature_extended_ecx_id[fi]);
}
}
for (flag = 1, fi = 0; flag <= 0x20000000; flag <<= 1, fi++) {
if ((_cpuid_info.ext_cpuid1_edx.value & flag) && strlen(_feature_extended_edx_id[fi]) > 0) {
WRITE_TO_BUF(_feature_extended_edx_id[fi]);
}
}
if (supports_tscinv_bit()) {
WRITE_TO_BUF("Invariant TSC");
}
return written;
}
int VM_Version_Ext::cpu_detailed_description(char* const buf, size_t buf_len) {
assert(buf != NULL, "buffer is NULL!");
assert(buf_len >= CPU_DETAILED_DESC_BUF_SIZE, "buffer len should at least be == CPU_DETAILED_DESC_BUF_SIZE!");
static const char* unknown = "<unknown>";
char vendor_id[VENDOR_LENGTH];
const char* family = NULL;
const char* model = NULL;
const char* brand = NULL;
int outputLen = 0;
family = cpu_family_description();
if (family == NULL) {
family = unknown;
}
model = cpu_model_description();
if (model == NULL) {
model = unknown;
}
brand = cpu_brand_string();
if (brand == NULL) {
brand = cpu_brand();
if (brand == NULL) {
brand = unknown;
}
}
vendor_id[VENDOR_LENGTH-1] = '\0';
outputLen = jio_snprintf(buf, buf_len, "Brand: %s, Vendor: %s\n"
"Family: %s (0x%x), Model: %s (0x%x), Stepping: 0x%x\n"
"Ext. family: 0x%x, Ext. model: 0x%x, Type: 0x%x, Signature: 0x%8.8x\n"
"Features: ebx: 0x%8.8x, ecx: 0x%8.8x, edx: 0x%8.8x\n"
"Ext. features: eax: 0x%8.8x, ebx: 0x%8.8x, ecx: 0x%8.8x, edx: 0x%8.8x\n"
"Supports: ",
brand,
vendor_id,
family,
extended_cpu_family(),
model,
extended_cpu_model(),
cpu_stepping(),
_cpuid_info.std_cpuid1_eax.bits.ext_family,
_cpuid_info.std_cpuid1_eax.bits.ext_model,
_cpuid_info.std_cpuid1_eax.bits.proc_type,
_cpuid_info.std_cpuid1_eax.value,
_cpuid_info.std_cpuid1_ebx.value,
_cpuid_info.std_cpuid1_ecx.value,
_cpuid_info.std_cpuid1_edx.value,
_cpuid_info.ext_cpuid1_eax,
_cpuid_info.ext_cpuid1_ebx,
_cpuid_info.ext_cpuid1_ecx,
_cpuid_info.ext_cpuid1_edx);
if (outputLen < 0 || (size_t) outputLen >= buf_len - 1) {
if (buf_len > 0) { buf[buf_len-1] = '\0'; }
return OS_ERR;
}
cpu_write_support_string(&buf[outputLen], buf_len - outputLen);
return OS_OK;
}
const char* VM_Version_Ext::cpu_name(void) {
char cpu_type_desc[CPU_TYPE_DESC_BUF_SIZE];
size_t cpu_desc_len = sizeof(cpu_type_desc);
cpu_type_description(cpu_type_desc, cpu_desc_len);
char* tmp = NEW_C_HEAP_ARRAY_RETURN_NULL(char, cpu_desc_len, mtTracing);
if (NULL == tmp) {
return NULL;
}
strncpy(tmp, cpu_type_desc, cpu_desc_len);
return tmp;
}
const char* VM_Version_Ext::cpu_description(void) {
char cpu_detailed_desc_buffer[CPU_DETAILED_DESC_BUF_SIZE];
size_t cpu_detailed_desc_len = sizeof(cpu_detailed_desc_buffer);
cpu_detailed_description(cpu_detailed_desc_buffer, cpu_detailed_desc_len);
char* tmp = NEW_C_HEAP_ARRAY_RETURN_NULL(char, cpu_detailed_desc_len, mtTracing);
if (NULL == tmp) {
return NULL;
}
strncpy(tmp, cpu_detailed_desc_buffer, cpu_detailed_desc_len);
return tmp;
}
jlong VM_Version_Ext::max_qualified_cpu_freq_from_brand_string(void) {
const char* const brand_string = cpu_brand_string();
if (brand_string == NULL) {
return 0;
}
const u8 MEGA = 1000000;
u8 multiplier = 0;
jlong frequency = 0;
const char* Hz_location = strchr(brand_string, 'H');
if (Hz_location != NULL) {
if (*(Hz_location + 1) == 'z') {
switch(*(Hz_location - 1)) {
case 'M' :
multiplier = MEGA;
break;
case 'G' :
multiplier = MEGA * 1000;
break;
case 'T' :
multiplier = MEGA * 1000 * 1000;
break;
}
}
}
if (multiplier > 0) {
if (*(Hz_location - 4) == '.') { // if format is "x.xx"
frequency = (jlong)(*(Hz_location - 5) - '0') * (multiplier);
frequency += (jlong)(*(Hz_location - 3) - '0') * (multiplier / 10);
frequency += (jlong)(*(Hz_location - 2) - '0') * (multiplier / 100);
} else { // format is "xxxx"
frequency = (jlong)(*(Hz_location - 5) - '0') * 1000;
frequency += (jlong)(*(Hz_location - 4) - '0') * 100;
frequency += (jlong)(*(Hz_location - 3) - '0') * 10;
frequency += (jlong)(*(Hz_location - 2) - '0');
frequency *= multiplier;
}
}
return frequency;
}
jlong VM_Version_Ext::maximum_qualified_cpu_frequency(void) {
if (_max_qualified_cpu_frequency == 0) {
_max_qualified_cpu_frequency = max_qualified_cpu_freq_from_brand_string();
}
return _max_qualified_cpu_frequency;
}
const char* const VM_Version_Ext::_family_id_intel[] = {
"8086/8088",
"",
"286",
"386",
"486",
"Pentium",
"Pentium Pro", //or Pentium-M/Woodcrest depeding on model
"",
"",
"",
"",
"",
"",
"",
"",
"Pentium 4"
};
const char* const VM_Version_Ext::_family_id_amd[] = {
"",
"",
"",
"",
"5x86",
"K5/K6",
"Athlon/AthlonXP",
"",
"",
"",
"",
"",
"",
"",
"",
"Opteron/Athlon64",
"Opteron QC/Phenom" // Barcelona et.al.
};
const char* const VM_Version_Ext::_model_id_pentium_pro[] = {
"",
"Pentium Pro",
"",
"Pentium II model 3",
"",
"Pentium II model 5/Xeon/Celeron",
"Celeron",
"Pentium III/Pentium III Xeon",
"Pentium III/Pentium III Xeon",
"Pentium M model 9", // Yonah
"Pentium III, model A",
"Pentium III, model B",
"",
"Pentium M model D", // Dothan
"",
"Core 2", // 0xf Woodcrest/Conroe/Merom/Kentsfield/Clovertown
"",
"",
"",
"",
"",
"",
"Celeron", // 0x16 Celeron 65nm
"Core 2", // 0x17 Penryn / Harpertown
"",
"",
"Core i7", // 0x1A CPU_MODEL_NEHALEM_EP
"Atom", // 0x1B Z5xx series Silverthorn
"",
"Core 2", // 0x1D Dunnington (6-core)
"Nehalem", // 0x1E CPU_MODEL_NEHALEM
"",
"",
"",
"",
"",
"",
"Westmere", // 0x25 CPU_MODEL_WESTMERE
"",
"",
"", // 0x28
"",
"Sandy Bridge", // 0x2a "2nd Generation Intel Core i7, i5, i3"
"",
"Westmere-EP", // 0x2c CPU_MODEL_WESTMERE_EP
"Sandy Bridge-EP", // 0x2d CPU_MODEL_SANDYBRIDGE_EP
"Nehalem-EX", // 0x2e CPU_MODEL_NEHALEM_EX
"Westmere-EX", // 0x2f CPU_MODEL_WESTMERE_EX
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"Ivy Bridge", // 0x3a
"",
"Haswell", // 0x3c "4th Generation Intel Core Processor"
"", // 0x3d "Next Generation Intel Core Processor"
"Ivy Bridge-EP", // 0x3e "Next Generation Intel Xeon Processor E7 Family"
"", // 0x3f "Future Generation Intel Xeon Processor"
"",
"",
"",
"",
"",
"Haswell", // 0x45 "4th Generation Intel Core Processor"
"Haswell", // 0x46 "4th Generation Intel Core Processor"
NULL
};
const char* const VM_Version_Ext::_brand_id[] = {
"",
"Celeron processor",
"Pentium III processor",
"Intel Pentium III Xeon processor",
"",
"",
"",
"",
"Intel Pentium 4 processor",
NULL
};
const char* const VM_Version_Ext::_feature_edx_id[] = {
"On-Chip FPU",
"Virtual Mode Extensions",
"Debugging Extensions",
"Page Size Extensions",
"Time Stamp Counter",
"Model Specific Registers",
"Physical Address Extension",
"Machine Check Exceptions",
"CMPXCHG8B Instruction",
"On-Chip APIC",
"",
"Fast System Call",
"Memory Type Range Registers",
"Page Global Enable",
"Machine Check Architecture",
"Conditional Mov Instruction",
"Page Attribute Table",
"36-bit Page Size Extension",
"Processor Serial Number",
"CLFLUSH Instruction",
"",
"Debug Trace Store feature",
"ACPI registers in MSR space",
"Intel Architecture MMX Technology",
"Fast Float Point Save and Restore",
"Streaming SIMD extensions",
"Streaming SIMD extensions 2",
"Self-Snoop",
"Hyper Threading",
"Thermal Monitor",
"",
"Pending Break Enable"
};
const char* const VM_Version_Ext::_feature_extended_edx_id[] = {
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"SYSCALL/SYSRET",
"",
"",
"",
"",
"",
"",
"",
"",
"Execute Disable Bit",
"",
"",
"",
"",
"",
"",
"RDTSCP",
"",
"Intel 64 Architecture",
"",
""
};
const char* const VM_Version_Ext::_feature_ecx_id[] = {
"Streaming SIMD Extensions 3",
"PCLMULQDQ",
"64-bit DS Area",
"MONITOR/MWAIT instructions",
"CPL Qualified Debug Store",
"Virtual Machine Extensions",
"Safer Mode Extensions",
"Enhanced Intel SpeedStep technology",
"Thermal Monitor 2",
"Supplemental Streaming SIMD Extensions 3",
"L1 Context ID",
"",
"Fused Multiply-Add",
"CMPXCHG16B",
"xTPR Update Control",
"Perfmon and Debug Capability",
"",
"Process-context identifiers",
"Direct Cache Access",
"Streaming SIMD extensions 4.1",
"Streaming SIMD extensions 4.2",
"x2APIC",
"MOVBE",
"Popcount instruction",
"TSC-Deadline",
"AESNI",
"XSAVE",
"OSXSAVE",
"AVX",
"F16C",
"RDRAND",
""
};
const char* const VM_Version_Ext::_feature_extended_ecx_id[] = {
"LAHF/SAHF instruction support",
"Core multi-processor leagacy mode",
"",
"",
"",
"Advanced Bit Manipulations: LZCNT",
"SSE4A: MOVNTSS, MOVNTSD, EXTRQ, INSERTQ",
"Misaligned SSE mode",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
""
};
C:\hotspot-69087d08d473\src\cpu\x86\vm/vm_version_ext_x86.hpp
#ifndef CPU_X86_VM_VM_VERSION_EXT_X86_HPP
#define CPU_X86_VM_VM_VERSION_EXT_X86_HPP
#include "utilities/macros.hpp"
#include "vm_version_x86.hpp"
class VM_Version_Ext : public VM_Version {
private:
static const size_t VENDOR_LENGTH;
static const size_t CPU_EBS_MAX_LENGTH;
static const size_t CPU_TYPE_DESC_BUF_SIZE;
static const size_t CPU_DETAILED_DESC_BUF_SIZE;
static const char* const _family_id_intel[];
static const char* const _family_id_amd[];
static const char* const _brand_id[];
static const char* const _model_id_pentium_pro[];
static const char* const _feature_edx_id[];
static const char* const _feature_extended_edx_id[];
static const char* const _feature_ecx_id[];
static const char* const _feature_extended_ecx_id[];
static int _no_of_threads;
static int _no_of_cores;
static int _no_of_packages;
static char* _cpu_brand_string;
static jlong _max_qualified_cpu_frequency;
static const char* cpu_family_description(void);
static const char* cpu_model_description(void);
static const char* cpu_brand(void);
static const char* cpu_brand_string(void);
static int cpu_type_description(char* const buf, size_t buf_len);
static int cpu_detailed_description(char* const buf, size_t buf_len);
static int cpu_extended_brand_string(char* const buf, size_t buf_len);
static bool cpu_is_em64t(void);
static bool is_netburst(void);
static size_t cpu_write_support_string(char* const buf, size_t buf_len);
static void resolve_cpu_information_details(void);
static jlong max_qualified_cpu_freq_from_brand_string(void);
public:
static ByteSize proc_name_0_offset() { return byte_offset_of(CpuidInfo, proc_name_0); }
static ByteSize proc_name_1_offset() { return byte_offset_of(CpuidInfo, proc_name_1); }
static ByteSize proc_name_2_offset() { return byte_offset_of(CpuidInfo, proc_name_2); }
static ByteSize proc_name_3_offset() { return byte_offset_of(CpuidInfo, proc_name_3); }
static ByteSize proc_name_4_offset() { return byte_offset_of(CpuidInfo, proc_name_4); }
static ByteSize proc_name_5_offset() { return byte_offset_of(CpuidInfo, proc_name_5); }
static ByteSize proc_name_6_offset() { return byte_offset_of(CpuidInfo, proc_name_6); }
static ByteSize proc_name_7_offset() { return byte_offset_of(CpuidInfo, proc_name_7); }
static ByteSize proc_name_8_offset() { return byte_offset_of(CpuidInfo, proc_name_8); }
static ByteSize proc_name_9_offset() { return byte_offset_of(CpuidInfo, proc_name_9); }
static ByteSize proc_name_10_offset() { return byte_offset_of(CpuidInfo, proc_name_10); }
static ByteSize proc_name_11_offset() { return byte_offset_of(CpuidInfo, proc_name_11); }
static int number_of_threads(void);
static int number_of_cores(void);
static int number_of_sockets(void);
static jlong maximum_qualified_cpu_frequency(void);
static bool supports_tscinv_ext(void);
static const char* cpu_name(void);
static const char* cpu_description(void);
static void initialize();
};
#endif // CPU_X86_VM_VM_VERSION_EXT_X86_HPP
C:\hotspot-69087d08d473\src\cpu\x86\vm/vm_version_x86.cpp
#include "precompiled.hpp"
#include "asm/macroAssembler.hpp"
#include "asm/macroAssembler.inline.hpp"
#include "memory/resourceArea.hpp"
#include "runtime/java.hpp"
#include "runtime/stubCodeGenerator.hpp"
#include "vm_version_x86.hpp"
#ifdef TARGET_OS_FAMILY_linux
# include "os_linux.inline.hpp"
#endif
#ifdef TARGET_OS_FAMILY_solaris
# include "os_solaris.inline.hpp"
#endif
#ifdef TARGET_OS_FAMILY_windows
# include "os_windows.inline.hpp"
#endif
#ifdef TARGET_OS_FAMILY_bsd
# include "os_bsd.inline.hpp"
#endif
int VM_Version::_cpu;
int VM_Version::_model;
int VM_Version::_stepping;
int VM_Version::_cpuFeatures;
const char* VM_Version::_features_str = "";
VM_Version::CpuidInfo VM_Version::_cpuid_info = { 0, };
address VM_Version::_cpuinfo_segv_addr = 0;
address VM_Version::_cpuinfo_cont_addr = 0;
static BufferBlob* stub_blob;
static const int stub_size = 600;
extern "C" {
typedef void (*get_cpu_info_stub_t)(void*);
}
static get_cpu_info_stub_t get_cpu_info_stub = NULL;
class VM_Version_StubGenerator: public StubCodeGenerator {
public:
VM_Version_StubGenerator(CodeBuffer *c) : StubCodeGenerator(c) {}
address generate_get_cpu_info() {
const uint32_t HS_EFL_AC = 0x40000;
const uint32_t HS_EFL_ID = 0x200000;
const int CPU_FAMILY_SHIFT = 8;
const uint32_t CPU_FAMILY_386 = (3 << CPU_FAMILY_SHIFT);
const uint32_t CPU_FAMILY_486 = (4 << CPU_FAMILY_SHIFT);
Label detect_486, cpu486, detect_586, std_cpuid1, std_cpuid4;
Label sef_cpuid, ext_cpuid, ext_cpuid1, ext_cpuid5, ext_cpuid7, done;
StubCodeMark mark(this, "VM_Version", "get_cpu_info_stub");
# define __ _masm->
address start = __ pc();
__ push(rbp);
#ifdef _LP64
__ mov(rbp, c_rarg0); // cpuid_info address
#else
__ movptr(rbp, Address(rsp, 8)); // cpuid_info address
#endif
__ push(rbx);
__ push(rsi);
__ pushf(); // preserve rbx, and flags
__ pop(rax);
__ push(rax);
__ mov(rcx, rax);
__ xorl(rax, HS_EFL_AC);
__ push(rax);
__ popf();
__ pushf();
__ pop(rax);
__ cmpptr(rax, rcx);
__ jccb(Assembler::notEqual, detect_486);
__ movl(rax, CPU_FAMILY_386);
__ movl(Address(rbp, in_bytes(VM_Version::std_cpuid1_offset())), rax);
__ jmp(done);
__ bind(detect_486);
__ mov(rax, rcx);
__ xorl(rax, HS_EFL_ID);
__ push(rax);
__ popf();
__ pushf();
__ pop(rax);
__ cmpptr(rcx, rax);
__ jccb(Assembler::notEqual, detect_586);
__ bind(cpu486);
__ movl(rax, CPU_FAMILY_486);
__ movl(Address(rbp, in_bytes(VM_Version::std_cpuid1_offset())), rax);
__ jmp(done);
__ bind(detect_586);
__ xorl(rax, rax);
__ cpuid();
__ orl(rax, rax);
__ jcc(Assembler::equal, cpu486); // if cpuid doesn't support an input
__ lea(rsi, Address(rbp, in_bytes(VM_Version::std_cpuid0_offset())));
__ movl(Address(rsi, 0), rax);
__ movl(Address(rsi, 4), rbx);
__ movl(Address(rsi, 8), rcx);
__ movl(Address(rsi,12), rdx);
__ cmpl(rax, 0xa); // Is cpuid(0xB) supported?
__ jccb(Assembler::belowEqual, std_cpuid4);
__ movl(rax, 0xb);
__ xorl(rcx, rcx); // Threads level
__ cpuid();
__ lea(rsi, Address(rbp, in_bytes(VM_Version::tpl_cpuidB0_offset())));
__ movl(Address(rsi, 0), rax);
__ movl(Address(rsi, 4), rbx);
__ movl(Address(rsi, 8), rcx);
__ movl(Address(rsi,12), rdx);
__ movl(rax, 0xb);
__ movl(rcx, 1); // Cores level
__ cpuid();
__ push(rax);
__ andl(rax, 0x1f); // Determine if valid topology level
__ orl(rax, rbx); // eax[4:0] | ebx[0:15] == 0 indicates invalid level
__ andl(rax, 0xffff);
__ pop(rax);
__ jccb(Assembler::equal, std_cpuid4);
__ lea(rsi, Address(rbp, in_bytes(VM_Version::tpl_cpuidB1_offset())));
__ movl(Address(rsi, 0), rax);
__ movl(Address(rsi, 4), rbx);
__ movl(Address(rsi, 8), rcx);
__ movl(Address(rsi,12), rdx);
__ movl(rax, 0xb);
__ movl(rcx, 2); // Packages level
__ cpuid();
__ push(rax);
__ andl(rax, 0x1f); // Determine if valid topology level
__ orl(rax, rbx); // eax[4:0] | ebx[0:15] == 0 indicates invalid level
__ andl(rax, 0xffff);
__ pop(rax);
__ jccb(Assembler::equal, std_cpuid4);
__ lea(rsi, Address(rbp, in_bytes(VM_Version::tpl_cpuidB2_offset())));
__ movl(Address(rsi, 0), rax);
__ movl(Address(rsi, 4), rbx);
__ movl(Address(rsi, 8), rcx);
__ movl(Address(rsi,12), rdx);
__ bind(std_cpuid4);
__ movl(rax, 4);
__ cmpl(rax, Address(rbp, in_bytes(VM_Version::std_cpuid0_offset()))); // Is cpuid(0x4) supported?
__ jccb(Assembler::greater, std_cpuid1);
__ xorl(rcx, rcx); // L1 cache
__ cpuid();
__ push(rax);
__ andl(rax, 0x1f); // Determine if valid cache parameters used
__ orl(rax, rax); // eax[4:0] == 0 indicates invalid cache
__ pop(rax);
__ jccb(Assembler::equal, std_cpuid1);
__ lea(rsi, Address(rbp, in_bytes(VM_Version::dcp_cpuid4_offset())));
__ movl(Address(rsi, 0), rax);
__ movl(Address(rsi, 4), rbx);
__ movl(Address(rsi, 8), rcx);
__ movl(Address(rsi,12), rdx);
__ bind(std_cpuid1);
__ movl(rax, 1);
__ cpuid();
__ lea(rsi, Address(rbp, in_bytes(VM_Version::std_cpuid1_offset())));
__ movl(Address(rsi, 0), rax);
__ movl(Address(rsi, 4), rbx);
__ movl(Address(rsi, 8), rcx);
__ movl(Address(rsi,12), rdx);
__ andl(rcx, 0x18000000); // cpuid1 bits osxsave | avx
__ cmpl(rcx, 0x18000000);
__ jccb(Assembler::notEqual, sef_cpuid); // jump if AVX is not supported
__ xorl(rcx, rcx); // zero for XCR0 register
__ xgetbv();
__ lea(rsi, Address(rbp, in_bytes(VM_Version::xem_xcr0_offset())));
__ movl(Address(rsi, 0), rax);
__ movl(Address(rsi, 4), rdx);
__ andl(rax, 0x6); // xcr0 bits sse | ymm
__ cmpl(rax, 0x6);
__ jccb(Assembler::notEqual, sef_cpuid); // jump if AVX is not supported
VM_Version::set_avx_cpuFeatures(); // Enable temporary to pass asserts
intx saved_useavx = UseAVX;
intx saved_usesse = UseSSE;
UseAVX = 1;
UseSSE = 2;
__ movl(rcx, VM_Version::ymm_test_value());
__ movdl(xmm0, rcx);
__ pshufd(xmm0, xmm0, 0x00);
__ vinsertf128h(xmm0, xmm0, xmm0);
__ vmovdqu(xmm7, xmm0);
#ifdef _LP64
__ vmovdqu(xmm8, xmm0);
__ vmovdqu(xmm15, xmm0);
#endif
__ xorl(rsi, rsi);
VM_Version::set_cpuinfo_segv_addr( __ pc() );
__ movl(rax, Address(rsi, 0));
VM_Version::set_cpuinfo_cont_addr( __ pc() );
__ lea(rsi, Address(rbp, in_bytes(VM_Version::ymm_save_offset())));
__ vmovdqu(Address(rsi, 0), xmm0);
__ vmovdqu(Address(rsi, 32), xmm7);
#ifdef _LP64
__ vmovdqu(Address(rsi, 64), xmm8);
__ vmovdqu(Address(rsi, 96), xmm15);
#endif
VM_Version::clean_cpuFeatures();
UseAVX = saved_useavx;
UseSSE = saved_usesse;
__ bind(sef_cpuid);
__ movl(rax, 7);
__ cmpl(rax, Address(rbp, in_bytes(VM_Version::std_cpuid0_offset()))); // Is cpuid(0x7) supported?
__ jccb(Assembler::greater, ext_cpuid);
__ xorl(rcx, rcx);
__ cpuid();
__ lea(rsi, Address(rbp, in_bytes(VM_Version::sef_cpuid7_offset())));
__ movl(Address(rsi, 0), rax);
__ movl(Address(rsi, 4), rbx);
__ bind(ext_cpuid);
__ movl(rax, 0x80000000);
__ cpuid();
__ cmpl(rax, 0x80000000); // Is cpuid(0x80000001) supported?
__ jcc(Assembler::belowEqual, done);
__ cmpl(rax, 0x80000004); // Is cpuid(0x80000005) supported?
__ jccb(Assembler::belowEqual, ext_cpuid1);
__ cmpl(rax, 0x80000006); // Is cpuid(0x80000007) supported?
__ jccb(Assembler::belowEqual, ext_cpuid5);
__ cmpl(rax, 0x80000007); // Is cpuid(0x80000008) supported?
__ jccb(Assembler::belowEqual, ext_cpuid7);
__ movl(rax, 0x80000008);
__ cpuid();
__ lea(rsi, Address(rbp, in_bytes(VM_Version::ext_cpuid8_offset())));
__ movl(Address(rsi, 0), rax);
__ movl(Address(rsi, 4), rbx);
__ movl(Address(rsi, 8), rcx);
__ movl(Address(rsi,12), rdx);
__ bind(ext_cpuid7);
__ movl(rax, 0x80000007);
__ cpuid();
__ lea(rsi, Address(rbp, in_bytes(VM_Version::ext_cpuid7_offset())));
__ movl(Address(rsi, 0), rax);
__ movl(Address(rsi, 4), rbx);
__ movl(Address(rsi, 8), rcx);
__ movl(Address(rsi,12), rdx);
__ bind(ext_cpuid5);
__ movl(rax, 0x80000005);
__ cpuid();
__ lea(rsi, Address(rbp, in_bytes(VM_Version::ext_cpuid5_offset())));
__ movl(Address(rsi, 0), rax);
__ movl(Address(rsi, 4), rbx);
__ movl(Address(rsi, 8), rcx);
__ movl(Address(rsi,12), rdx);
__ bind(ext_cpuid1);
__ movl(rax, 0x80000001);
__ cpuid();
__ lea(rsi, Address(rbp, in_bytes(VM_Version::ext_cpuid1_offset())));
__ movl(Address(rsi, 0), rax);
__ movl(Address(rsi, 4), rbx);
__ movl(Address(rsi, 8), rcx);
__ movl(Address(rsi,12), rdx);
__ bind(done);
__ popf();
__ pop(rsi);
__ pop(rbx);
__ pop(rbp);
__ ret(0);
# undef __
return start;
};
};
void VM_Version::get_cpu_info_wrapper() {
get_cpu_info_stub(&_cpuid_info);
}
#ifndef CALL_TEST_FUNC_WITH_WRAPPER_IF_NEEDED
#define CALL_TEST_FUNC_WITH_WRAPPER_IF_NEEDED(f) f()
#endif
void VM_Version::get_processor_features() {
_cpu = 4; // 486 by default
_model = 0;
_stepping = 0;
_cpuFeatures = 0;
_logical_processors_per_package = 1;
_L1_data_cache_line_size = 16;
if (!Use486InstrsOnly) {
CALL_TEST_FUNC_WITH_WRAPPER_IF_NEEDED(get_cpu_info_wrapper);
assert_is_initialized();
_cpu = extended_cpu_family();
_model = extended_cpu_model();
_stepping = cpu_stepping();
if (cpu_family() > 4) { // it supports CPUID
_cpuFeatures = feature_flags();
_logical_processors_per_package = logical_processor_count();
_L1_data_cache_line_size = L1_line_size();
}
}
_supports_cx8 = supports_cmpxchg8();
_supports_atomic_getset4 = true;
_supports_atomic_getadd4 = true;
LP64_ONLY(_supports_atomic_getset8 = true);
LP64_ONLY(_supports_atomic_getadd8 = true);
#ifdef _LP64
if (!VM_Version::supports_sse2()) {
vm_exit_during_initialization("Unknown x64 processor: SSE2 not supported");
}
if (UseSSE < 2) UseSSE = 2;
#endif
#ifdef AMD64
guarantee(_cpuid_info.std_cpuid1_edx.bits.clflush != 0, "clflush is not supported");
guarantee(_cpuid_info.std_cpuid1_ebx.bits.clflush_size == 8, "such clflush size is not supported");
#endif
if (!os::supports_sse())
_cpuFeatures &= ~(CPU_SSE|CPU_SSE2|CPU_SSE3|CPU_SSSE3|CPU_SSE4A|CPU_SSE4_1|CPU_SSE4_2);
if (UseSSE < 4) {
_cpuFeatures &= ~CPU_SSE4_1;
_cpuFeatures &= ~CPU_SSE4_2;
}
if (UseSSE < 3) {
_cpuFeatures &= ~CPU_SSE3;
_cpuFeatures &= ~CPU_SSSE3;
_cpuFeatures &= ~CPU_SSE4A;
}
if (UseSSE < 2)
_cpuFeatures &= ~CPU_SSE2;
if (UseSSE < 1)
_cpuFeatures &= ~CPU_SSE;
if (UseAVX < 2)
_cpuFeatures &= ~CPU_AVX2;
if (UseAVX < 1)
_cpuFeatures &= ~CPU_AVX;
if (!UseAES && !FLAG_IS_DEFAULT(UseAES))
_cpuFeatures &= ~CPU_AES;
if (logical_processors_per_package() == 1) {
_cpuFeatures &= ~CPU_HT;
}
char buf[256];
jio_snprintf(buf, sizeof(buf), "(%u cores per cpu, %u threads per core) family %d model %d stepping %d%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
cores_per_cpu(), threads_per_core(),
cpu_family(), _model, _stepping,
(supports_cmov() ? ", cmov" : ""),
(supports_cmpxchg8() ? ", cx8" : ""),
(supports_fxsr() ? ", fxsr" : ""),
(supports_mmx() ? ", mmx" : ""),
(supports_sse() ? ", sse" : ""),
(supports_sse2() ? ", sse2" : ""),
(supports_sse3() ? ", sse3" : ""),
(supports_ssse3()? ", ssse3": ""),
(supports_sse4_1() ? ", sse4.1" : ""),
(supports_sse4_2() ? ", sse4.2" : ""),
(supports_popcnt() ? ", popcnt" : ""),
(supports_avx() ? ", avx" : ""),
(supports_avx2() ? ", avx2" : ""),
(supports_aes() ? ", aes" : ""),
(supports_clmul() ? ", clmul" : ""),
(supports_erms() ? ", erms" : ""),
(supports_rtm() ? ", rtm" : ""),
(supports_mmx_ext() ? ", mmxext" : ""),
(supports_3dnow_prefetch() ? ", 3dnowpref" : ""),
(supports_lzcnt() ? ", lzcnt": ""),
(supports_sse4a() ? ", sse4a": ""),
(supports_ht() ? ", ht": ""),
(supports_tsc() ? ", tsc": ""),
(supports_tscinv_bit() ? ", tscinvbit": ""),
(supports_tscinv() ? ", tscinv": ""),
(supports_bmi1() ? ", bmi1" : ""),
(supports_bmi2() ? ", bmi2" : ""),
(supports_adx() ? ", adx" : ""));
_features_str = strdup(buf);
if (UseSSE > 4) UseSSE=4;
if (UseSSE < 0) UseSSE=0;
if (!supports_sse4_1()) // Drop to 3 if no SSE4 support
UseSSE = MIN2((intx)3,UseSSE);
if (!supports_sse3()) // Drop to 2 if no SSE3 support
UseSSE = MIN2((intx)2,UseSSE);
if (!supports_sse2()) // Drop to 1 if no SSE2 support
UseSSE = MIN2((intx)1,UseSSE);
if (!supports_sse ()) // Drop to 0 if no SSE support
UseSSE = 0;
if (UseAVX > 2) UseAVX=2;
if (UseAVX < 0) UseAVX=0;
if (!supports_avx2()) // Drop to 1 if no AVX2 support
UseAVX = MIN2((intx)1,UseAVX);
if (!supports_avx ()) // Drop to 0 if no AVX support
UseAVX = 0;
if (supports_aes()) {
if (FLAG_IS_DEFAULT(UseAES)) {
FLAG_SET_DEFAULT(UseAES, true);
}
if (!UseAES) {
if (UseAESIntrinsics && !FLAG_IS_DEFAULT(UseAESIntrinsics)) {
warning("AES intrinsics require UseAES flag to be enabled. Intrinsics will be disabled.");
}
FLAG_SET_DEFAULT(UseAESIntrinsics, false);
} else {
if (UseSSE > 2) {
if (FLAG_IS_DEFAULT(UseAESIntrinsics)) {
FLAG_SET_DEFAULT(UseAESIntrinsics, true);
}
} else {
if (UseAESIntrinsics && !FLAG_IS_DEFAULT(UseAESIntrinsics)) {
warning("X86 AES intrinsics require SSE3 instructions or higher. Intrinsics will be disabled.");
}
FLAG_SET_DEFAULT(UseAESIntrinsics, false);
}
}
} else if (UseAES || UseAESIntrinsics) {
if (UseAES && !FLAG_IS_DEFAULT(UseAES)) {
warning("AES instructions are not available on this CPU");
FLAG_SET_DEFAULT(UseAES, false);
}
if (UseAESIntrinsics && !FLAG_IS_DEFAULT(UseAESIntrinsics)) {
warning("AES intrinsics are not available on this CPU");
FLAG_SET_DEFAULT(UseAESIntrinsics, false);
}
}
if (supports_clmul()) {
if (FLAG_IS_DEFAULT(UseCLMUL)) {
UseCLMUL = true;
}
} else if (UseCLMUL) {
if (!FLAG_IS_DEFAULT(UseCLMUL))
warning("CLMUL instructions not available on this CPU (AVX may also be required)");
FLAG_SET_DEFAULT(UseCLMUL, false);
}
if (UseCLMUL && (UseSSE > 2)) {
if (FLAG_IS_DEFAULT(UseCRC32Intrinsics)) {
UseCRC32Intrinsics = true;
}
} else if (UseCRC32Intrinsics) {
if (!FLAG_IS_DEFAULT(UseCRC32Intrinsics))
warning("CRC32 Intrinsics requires CLMUL instructions (not available on this CPU)");
FLAG_SET_DEFAULT(UseCRC32Intrinsics, false);
}
if (UseCLMUL && (UseSSE > 2)) {
if (FLAG_IS_DEFAULT(UseGHASHIntrinsics)) {
UseGHASHIntrinsics = true;
}
} else if (UseGHASHIntrinsics) {
if (!FLAG_IS_DEFAULT(UseGHASHIntrinsics))
warning("GHASH intrinsic requires CLMUL and SSE2 instructions on this CPU");
FLAG_SET_DEFAULT(UseGHASHIntrinsics, false);
}
if (UseSHA) {
warning("SHA instructions are not available on this CPU");
FLAG_SET_DEFAULT(UseSHA, false);
}
if (UseSHA1Intrinsics || UseSHA256Intrinsics || UseSHA512Intrinsics) {
warning("SHA intrinsics are not available on this CPU");
FLAG_SET_DEFAULT(UseSHA1Intrinsics, false);
FLAG_SET_DEFAULT(UseSHA256Intrinsics, false);
FLAG_SET_DEFAULT(UseSHA512Intrinsics, false);
}
if (!supports_rtm() && UseRTMLocking) {
vm_exit_during_initialization("RTM instructions are not available on this CPU");
}
#if INCLUDE_RTM_OPT
if (UseRTMLocking) {
if (is_intel_family_core()) {
if ((_model == CPU_MODEL_HASWELL_E3) ||
(_model == CPU_MODEL_HASWELL_E7 && _stepping < 3) ||
(_model == CPU_MODEL_BROADWELL && _stepping < 4)) {
if (!UnlockExperimentalVMOptions) {
vm_exit_during_initialization("UseRTMLocking is only available as experimental option on this platform. It must be enabled via -XX:+UnlockExperimentalVMOptions flag.");
} else {
warning("UseRTMLocking is only available as experimental option on this platform.");
}
}
}
if (!FLAG_IS_CMDLINE(UseRTMLocking)) {
vm_exit_during_initialization("UseRTMLocking flag should be only set on command line");
}
if (!is_power_of_2(RTMTotalCountIncrRate)) {
warning("RTMTotalCountIncrRate must be a power of 2, resetting it to 64");
FLAG_SET_DEFAULT(RTMTotalCountIncrRate, 64);
}
if (RTMAbortRatio < 0 || RTMAbortRatio > 100) {
warning("RTMAbortRatio must be in the range 0 to 100, resetting it to 50");
FLAG_SET_DEFAULT(RTMAbortRatio, 50);
}
} else { // !UseRTMLocking
if (UseRTMForStackLocks) {
if (!FLAG_IS_DEFAULT(UseRTMForStackLocks)) {
warning("UseRTMForStackLocks flag should be off when UseRTMLocking flag is off");
}
FLAG_SET_DEFAULT(UseRTMForStackLocks, false);
}
if (UseRTMDeopt) {
FLAG_SET_DEFAULT(UseRTMDeopt, false);
}
if (PrintPreciseRTMLockingStatistics) {
FLAG_SET_DEFAULT(PrintPreciseRTMLockingStatistics, false);
}
}
#else
if (UseRTMLocking) {
vm_exit_during_initialization("RTM locking optimization is not supported in this VM");
}
#endif
#ifdef COMPILER2
if (UseFPUForSpilling) {
if (UseSSE < 2) {
FLAG_SET_DEFAULT(UseFPUForSpilling, false);
}
}
if (MaxVectorSize > 0) {
if (!is_power_of_2(MaxVectorSize)) {
warning("MaxVectorSize must be a power of 2");
FLAG_SET_DEFAULT(MaxVectorSize, 32);
}
if (MaxVectorSize > 32) {
FLAG_SET_DEFAULT(MaxVectorSize, 32);
}
if (MaxVectorSize > 16 && (UseAVX == 0 || !os_supports_avx_vectors())) {
FLAG_SET_DEFAULT(MaxVectorSize, 16);
}
if (UseSSE < 2) {
FLAG_SET_DEFAULT(MaxVectorSize, 0);
}
#ifdef ASSERT
if (supports_avx() && PrintMiscellaneous && Verbose && TraceNewVectors) {
tty->print_cr("State of YMM registers after signal handle:");
int nreg = 2 LP64_ONLY(+2);
const char* ymm_name[4] = {"0", "7", "8", "15"};
for (int i = 0; i < nreg; i++) {
tty->print("YMM%s:", ymm_name[i]);
for (int j = 7; j >=0; j--) {
tty->print(" %x", _cpuid_info.ymm_save[i*8 + j]);
}
tty->cr();
}
}
#endif
}
#ifdef _LP64
if (FLAG_IS_DEFAULT(UseMultiplyToLenIntrinsic)) {
UseMultiplyToLenIntrinsic = true;
}
if (FLAG_IS_DEFAULT(UseSquareToLenIntrinsic)) {
UseSquareToLenIntrinsic = true;
}
if (FLAG_IS_DEFAULT(UseMulAddIntrinsic)) {
UseMulAddIntrinsic = true;
}
if (FLAG_IS_DEFAULT(UseMontgomeryMultiplyIntrinsic)) {
UseMontgomeryMultiplyIntrinsic = true;
}
if (FLAG_IS_DEFAULT(UseMontgomerySquareIntrinsic)) {
UseMontgomerySquareIntrinsic = true;
}
#else
if (UseMultiplyToLenIntrinsic) {
if (!FLAG_IS_DEFAULT(UseMultiplyToLenIntrinsic)) {
warning("multiplyToLen intrinsic is not available in 32-bit VM");
}
FLAG_SET_DEFAULT(UseMultiplyToLenIntrinsic, false);
}
if (UseSquareToLenIntrinsic) {
if (!FLAG_IS_DEFAULT(UseSquareToLenIntrinsic)) {
warning("squareToLen intrinsic is not available in 32-bit VM");
}
FLAG_SET_DEFAULT(UseSquareToLenIntrinsic, false);
}
if (UseMulAddIntrinsic) {
if (!FLAG_IS_DEFAULT(UseMulAddIntrinsic)) {
warning("mulAdd intrinsic is not available in 32-bit VM");
}
FLAG_SET_DEFAULT(UseMulAddIntrinsic, false);
}
if (UseMontgomeryMultiplyIntrinsic) {
if (!FLAG_IS_DEFAULT(UseMontgomeryMultiplyIntrinsic)) {
warning("montgomeryMultiply intrinsic is not available in 32-bit VM");
}
FLAG_SET_DEFAULT(UseMontgomeryMultiplyIntrinsic, false);
}
if (UseMontgomerySquareIntrinsic) {
if (!FLAG_IS_DEFAULT(UseMontgomerySquareIntrinsic)) {
warning("montgomerySquare intrinsic is not available in 32-bit VM");
}
FLAG_SET_DEFAULT(UseMontgomerySquareIntrinsic, false);
}
#endif
#endif // COMPILER2
if( is_amd() ) { // AMD cpus specific settings
if( supports_sse2() && FLAG_IS_DEFAULT(UseAddressNop) ) {
UseAddressNop = true;
}
if( supports_sse2() && FLAG_IS_DEFAULT(UseNewLongLShift) ) {
UseNewLongLShift = true;
}
if( FLAG_IS_DEFAULT(UseXmmLoadAndClearUpper) ) {
if( supports_sse4a() ) {
UseXmmLoadAndClearUpper = true; // use movsd only on '10h' Opteron
} else {
UseXmmLoadAndClearUpper = false;
}
}
if( FLAG_IS_DEFAULT(UseXmmRegToRegMoveAll) ) {
if( supports_sse4a() ) {
UseXmmRegToRegMoveAll = true; // use movaps, movapd only on '10h'
} else {
UseXmmRegToRegMoveAll = false;
}
}
if( FLAG_IS_DEFAULT(UseXmmI2F) ) {
if( supports_sse4a() ) {
UseXmmI2F = true;
} else {
UseXmmI2F = false;
}
}
if( FLAG_IS_DEFAULT(UseXmmI2D) ) {
if( supports_sse4a() ) {
UseXmmI2D = true;
} else {
UseXmmI2D = false;
}
}
if( FLAG_IS_DEFAULT(UseSSE42Intrinsics) ) {
if( supports_sse4_2() && UseSSE >= 4 ) {
UseSSE42Intrinsics = true;
}
}
if ( cpu_family() == 0x15 ) {
if (FLAG_IS_DEFAULT(AllocatePrefetchStyle)) {
AllocatePrefetchStyle = 0;
}
if (FLAG_IS_DEFAULT(AllocatePrefetchInstr)) {
AllocatePrefetchInstr = 3;
}
if (supports_sse2() && FLAG_IS_DEFAULT(UseXMMForArrayCopy)) {
UseXMMForArrayCopy = true;
}
if (supports_sse2() && FLAG_IS_DEFAULT(UseUnalignedLoadStores)) {
UseUnalignedLoadStores = true;
}
}
#ifdef COMPILER2
if (MaxVectorSize > 16) {
FLAG_SET_DEFAULT(MaxVectorSize, 16);
}
#endif // COMPILER2
}
if( is_intel() ) { // Intel cpus specific settings
if( FLAG_IS_DEFAULT(UseStoreImmI16) ) {
UseStoreImmI16 = false; // don't use it on Intel cpus
}
if( cpu_family() == 6 || cpu_family() == 15 ) {
if( FLAG_IS_DEFAULT(UseAddressNop) ) {
UseAddressNop = true;
}
}
if( FLAG_IS_DEFAULT(UseXmmLoadAndClearUpper) ) {
UseXmmLoadAndClearUpper = true; // use movsd on all Intel cpus
}
if( FLAG_IS_DEFAULT(UseXmmRegToRegMoveAll) ) {
if( supports_sse3() ) {
UseXmmRegToRegMoveAll = true; // use movaps, movapd on new Intel cpus
} else {
UseXmmRegToRegMoveAll = false;
}
}
if( cpu_family() == 6 && supports_sse3() ) { // New Intel cpus
#ifdef COMPILER2
if( FLAG_IS_DEFAULT(MaxLoopPad) ) {
MaxLoopPad = 11;
}
#endif // COMPILER2
if (FLAG_IS_DEFAULT(UseXMMForArrayCopy)) {
UseXMMForArrayCopy = true; // use SSE2 movq on new Intel cpus
}
if (supports_sse4_2() && supports_ht()) { // Newest Intel cpus
if (FLAG_IS_DEFAULT(UseUnalignedLoadStores)) {
UseUnalignedLoadStores = true; // use movdqu on newest Intel cpus
}
}
if (supports_sse4_2() && UseSSE >= 4) {
if (FLAG_IS_DEFAULT(UseSSE42Intrinsics)) {
UseSSE42Intrinsics = true;
}
}
}
if ((cpu_family() == 0x06) &&
((extended_cpu_model() == 0x36) || // Centerton
(extended_cpu_model() == 0x37) || // Silvermont
(extended_cpu_model() == 0x4D))) {
#ifdef COMPILER2
if (FLAG_IS_DEFAULT(OptoScheduling)) {
OptoScheduling = true;
}
#endif
if (supports_sse4_2()) { // Silvermont
if (FLAG_IS_DEFAULT(UseUnalignedLoadStores)) {
UseUnalignedLoadStores = true; // use movdqu on newest Intel cpus
}
}
}
if(FLAG_IS_DEFAULT(AllocatePrefetchInstr) && supports_3dnow_prefetch()) {
AllocatePrefetchInstr = 3;
}
}
if (supports_lzcnt()) {
if (FLAG_IS_DEFAULT(UseCountLeadingZerosInstruction)) {
UseCountLeadingZerosInstruction = true;
}
} else if (UseCountLeadingZerosInstruction) {
warning("lzcnt instruction is not available on this CPU");
FLAG_SET_DEFAULT(UseCountLeadingZerosInstruction, false);
}
if (supports_bmi1()) {
if (FLAG_IS_DEFAULT(UseCountTrailingZerosInstruction)) {
if (!UseBMI1Instructions && !FLAG_IS_DEFAULT(UseBMI1Instructions)) {
UseCountTrailingZerosInstruction = false;
} else {
UseCountTrailingZerosInstruction = true;
}
}
} else if (UseCountTrailingZerosInstruction) {
warning("tzcnt instruction is not available on this CPU");
FLAG_SET_DEFAULT(UseCountTrailingZerosInstruction, false);
}
if (supports_bmi1() && supports_avx()) {
if (FLAG_IS_DEFAULT(UseBMI1Instructions)) {
UseBMI1Instructions = true;
}
} else if (UseBMI1Instructions) {
warning("BMI1 instructions are not available on this CPU (AVX is also required)");
FLAG_SET_DEFAULT(UseBMI1Instructions, false);
}
if (supports_bmi2() && supports_avx()) {
if (FLAG_IS_DEFAULT(UseBMI2Instructions)) {
UseBMI2Instructions = true;
}
} else if (UseBMI2Instructions) {
warning("BMI2 instructions are not available on this CPU (AVX is also required)");
FLAG_SET_DEFAULT(UseBMI2Instructions, false);
}
if (supports_popcnt()) {
if (FLAG_IS_DEFAULT(UsePopCountInstruction)) {
UsePopCountInstruction = true;
}
} else if (UsePopCountInstruction) {
warning("POPCNT instruction is not available on this CPU");
FLAG_SET_DEFAULT(UsePopCountInstruction, false);
}
if (supports_erms()) {
if (FLAG_IS_DEFAULT(UseFastStosb)) {
UseFastStosb = true;
}
} else if (UseFastStosb) {
warning("fast-string operations are not available on this CPU");
FLAG_SET_DEFAULT(UseFastStosb, false);
}
#ifdef COMPILER2
if (FLAG_IS_DEFAULT(AlignVector)) {
AlignVector = !UseUnalignedLoadStores;
}
#endif // COMPILER2
assert(0 <= ReadPrefetchInstr && ReadPrefetchInstr <= 3, "invalid value");
assert(0 <= AllocatePrefetchInstr && AllocatePrefetchInstr <= 3, "invalid value");
if( ReadPrefetchInstr < 0 ) ReadPrefetchInstr = 0;
if( ReadPrefetchInstr > 3 ) ReadPrefetchInstr = 3;
if( ReadPrefetchInstr == 3 && !supports_3dnow_prefetch() ) ReadPrefetchInstr = 0;
if( !supports_sse() && supports_3dnow_prefetch() ) ReadPrefetchInstr = 3;
if( AllocatePrefetchInstr < 0 ) AllocatePrefetchInstr = 0;
if( AllocatePrefetchInstr > 3 ) AllocatePrefetchInstr = 3;
if( AllocatePrefetchInstr == 3 && !supports_3dnow_prefetch() ) AllocatePrefetchInstr=0;
if( !supports_sse() && supports_3dnow_prefetch() ) AllocatePrefetchInstr = 3;
intx cache_line_size = prefetch_data_size();
if( cache_line_size > AllocatePrefetchStepSize )
AllocatePrefetchStepSize = cache_line_size;
assert(AllocatePrefetchLines > 0, "invalid value");
if( AllocatePrefetchLines < 1 ) // set valid value in product VM
AllocatePrefetchLines = 3;
assert(AllocateInstancePrefetchLines > 0, "invalid value");
if( AllocateInstancePrefetchLines < 1 ) // set valid value in product VM
AllocateInstancePrefetchLines = 1;
AllocatePrefetchDistance = allocate_prefetch_distance();
AllocatePrefetchStyle = allocate_prefetch_style();
if (is_intel() && cpu_family() == 6 && supports_sse3()) {
if (AllocatePrefetchStyle == 2) { // watermark prefetching on Core
#ifdef _LP64
AllocatePrefetchDistance = 384;
#else
AllocatePrefetchDistance = 320;
#endif
}
if (supports_sse4_2() && supports_ht()) { // Nehalem based cpus
AllocatePrefetchDistance = 192;
AllocatePrefetchLines = 4;
}
#ifdef COMPILER2
if (supports_sse4_2()) {
if (FLAG_IS_DEFAULT(UseFPUForSpilling)) {
FLAG_SET_DEFAULT(UseFPUForSpilling, true);
}
}
#endif
}
assert(AllocatePrefetchDistance % AllocatePrefetchStepSize == 0, "invalid value");
#ifdef _LP64
PrefetchCopyIntervalInBytes = prefetch_copy_interval_in_bytes();
PrefetchScanIntervalInBytes = prefetch_scan_interval_in_bytes();
PrefetchFieldsAhead = prefetch_fields_ahead();
#endif
if (FLAG_IS_DEFAULT(ContendedPaddingWidth) &&
(cache_line_size > ContendedPaddingWidth))
ContendedPaddingWidth = cache_line_size;
#ifndef PRODUCT
if (PrintMiscellaneous && Verbose) {
tty->print_cr("Logical CPUs per core: %u",
logical_processors_per_package());
tty->print_cr("L1 data cache line size: %u", L1_data_cache_line_size());
tty->print("UseSSE=%d", (int) UseSSE);
if (UseAVX > 0) {
tty->print(" UseAVX=%d", (int) UseAVX);
}
if (UseAES) {
tty->print(" UseAES=1");
}
#ifdef COMPILER2
if (MaxVectorSize > 0) {
tty->print(" MaxVectorSize=%d", (int) MaxVectorSize);
}
#endif
tty->cr();
tty->print("Allocation");
if (AllocatePrefetchStyle <= 0 || UseSSE == 0 && !supports_3dnow_prefetch()) {
tty->print_cr(": no prefetching");
} else {
tty->print(" prefetching: ");
if (UseSSE == 0 && supports_3dnow_prefetch()) {
tty->print("PREFETCHW");
} else if (UseSSE >= 1) {
if (AllocatePrefetchInstr == 0) {
tty->print("PREFETCHNTA");
} else if (AllocatePrefetchInstr == 1) {
tty->print("PREFETCHT0");
} else if (AllocatePrefetchInstr == 2) {
tty->print("PREFETCHT2");
} else if (AllocatePrefetchInstr == 3) {
tty->print("PREFETCHW");
}
}
if (AllocatePrefetchLines > 1) {
tty->print_cr(" at distance %d, %d lines of %d bytes", (int) AllocatePrefetchDistance, (int) AllocatePrefetchLines, (int) AllocatePrefetchStepSize);
} else {
tty->print_cr(" at distance %d, one line of %d bytes", (int) AllocatePrefetchDistance, (int) AllocatePrefetchStepSize);
}
}
if (PrefetchCopyIntervalInBytes > 0) {
tty->print_cr("PrefetchCopyIntervalInBytes %d", (int) PrefetchCopyIntervalInBytes);
}
if (PrefetchScanIntervalInBytes > 0) {
tty->print_cr("PrefetchScanIntervalInBytes %d", (int) PrefetchScanIntervalInBytes);
}
if (PrefetchFieldsAhead > 0) {
tty->print_cr("PrefetchFieldsAhead %d", (int) PrefetchFieldsAhead);
}
if (ContendedPaddingWidth > 0) {
tty->print_cr("ContendedPaddingWidth %d", (int) ContendedPaddingWidth);
}
}
#endif // !PRODUCT
}
bool VM_Version::use_biased_locking() {
#if INCLUDE_RTM_OPT
if (UseRTMLocking && UseBiasedLocking) {
if (FLAG_IS_DEFAULT(UseBiasedLocking)) {
FLAG_SET_DEFAULT(UseBiasedLocking, false);
} else {
warning("Biased locking is not supported with RTM locking; ignoring UseBiasedLocking flag." );
UseBiasedLocking = false;
}
}
#endif
return UseBiasedLocking;
}
void VM_Version::initialize() {
ResourceMark rm;
stub_blob = BufferBlob::create("get_cpu_info_stub", stub_size);
if (stub_blob == NULL) {
vm_exit_during_initialization("Unable to allocate get_cpu_info_stub");
}
CodeBuffer c(stub_blob);
VM_Version_StubGenerator g(&c);
get_cpu_info_stub = CAST_TO_FN_PTR(get_cpu_info_stub_t,
g.generate_get_cpu_info());
get_processor_features();
}
C:\hotspot-69087d08d473\src\cpu\x86\vm/vm_version_x86.hpp
#ifndef CPU_X86_VM_VM_VERSION_X86_HPP
#define CPU_X86_VM_VM_VERSION_X86_HPP
#include "runtime/globals_extension.hpp"
#include "runtime/vm_version.hpp"
class VM_Version : public Abstract_VM_Version {
public:
union StdCpuid1Eax {
uint32_t value;
struct {
uint32_t stepping : 4,
model : 4,
family : 4,
proc_type : 2,
: 2,
ext_model : 4,
ext_family : 8,
: 4;
} bits;
};
union StdCpuid1Ebx { // example, unused
uint32_t value;
struct {
uint32_t brand_id : 8,
clflush_size : 8,
threads_per_cpu : 8,
apic_id : 8;
} bits;
};
union StdCpuid1Ecx {
uint32_t value;
struct {
uint32_t sse3 : 1,
clmul : 1,
: 1,
monitor : 1,
: 1,
vmx : 1,
: 1,
est : 1,
: 1,
ssse3 : 1,
cid : 1,
: 2,
cmpxchg16: 1,
: 4,
dca : 1,
sse4_1 : 1,
sse4_2 : 1,
: 2,
popcnt : 1,
: 1,
aes : 1,
: 1,
osxsave : 1,
avx : 1,
: 3;
} bits;
};
union StdCpuid1Edx {
uint32_t value;
struct {
uint32_t : 4,
tsc : 1,
: 3,
cmpxchg8 : 1,
: 6,
cmov : 1,
: 3,
clflush : 1,
: 3,
mmx : 1,
fxsr : 1,
sse : 1,
sse2 : 1,
: 1,
ht : 1,
: 3;
} bits;
};
union DcpCpuid4Eax {
uint32_t value;
struct {
uint32_t cache_type : 5,
: 21,
cores_per_cpu : 6;
} bits;
};
union DcpCpuid4Ebx {
uint32_t value;
struct {
uint32_t L1_line_size : 12,
partitions : 10,
associativity : 10;
} bits;
};
union TplCpuidBEbx {
uint32_t value;
struct {
uint32_t logical_cpus : 16,
: 16;
} bits;
};
union ExtCpuid1Ecx {
uint32_t value;
struct {
uint32_t LahfSahf : 1,
CmpLegacy : 1,
: 3,
lzcnt_intel : 1,
lzcnt : 1,
sse4a : 1,
misalignsse : 1,
prefetchw : 1,
: 22;
} bits;
};
union ExtCpuid1Edx {
uint32_t value;
struct {
uint32_t : 22,
mmx_amd : 1,
mmx : 1,
fxsr : 1,
: 4,
long_mode : 1,
tdnow2 : 1,
tdnow : 1;
} bits;
};
union ExtCpuid5Ex {
uint32_t value;
struct {
uint32_t L1_line_size : 8,
L1_tag_lines : 8,
L1_assoc : 8,
L1_size : 8;
} bits;
};
union ExtCpuid7Edx {
uint32_t value;
struct {
uint32_t : 8,
tsc_invariance : 1,
: 23;
} bits;
};
union ExtCpuid8Ecx {
uint32_t value;
struct {
uint32_t cores_per_cpu : 8,
: 24;
} bits;
};
union SefCpuid7Eax {
uint32_t value;
};
union SefCpuid7Ebx {
uint32_t value;
struct {
uint32_t fsgsbase : 1,
: 2,
bmi1 : 1,
: 1,
avx2 : 1,
: 2,
bmi2 : 1,
erms : 1,
: 1,
rtm : 1,
: 7,
adx : 1,
: 12;
} bits;
};
union XemXcr0Eax {
uint32_t value;
struct {
uint32_t x87 : 1,
sse : 1,
ymm : 1,
: 29;
} bits;
};
protected:
static int _cpu;
static int _model;
static int _stepping;
static int _cpuFeatures; // features returned by the "cpuid" instruction
static const char* _features_str;
static address _cpuinfo_segv_addr; // address of instruction which causes SEGV
static address _cpuinfo_cont_addr; // address of instruction after the one which causes SEGV
enum {
CPU_CX8 = (1 << 0), // next bits are from cpuid 1 (EDX)
CPU_CMOV = (1 << 1),
CPU_FXSR = (1 << 2),
CPU_HT = (1 << 3),
CPU_MMX = (1 << 4),
CPU_3DNOW_PREFETCH = (1 << 5), // Processor supports 3dnow prefetch and prefetchw instructions
CPU_SSE = (1 << 6),
CPU_SSE2 = (1 << 7),
CPU_SSE3 = (1 << 8), // SSE3 comes from cpuid 1 (ECX)
CPU_SSSE3 = (1 << 9),
CPU_SSE4A = (1 << 10),
CPU_SSE4_1 = (1 << 11),
CPU_SSE4_2 = (1 << 12),
CPU_POPCNT = (1 << 13),
CPU_LZCNT = (1 << 14),
CPU_TSC = (1 << 15),
CPU_TSCINV = (1 << 16),
CPU_AVX = (1 << 17),
CPU_AVX2 = (1 << 18),
CPU_AES = (1 << 19),
CPU_ERMS = (1 << 20), // enhanced 'rep movsb/stosb' instructions
CPU_CLMUL = (1 << 21), // carryless multiply for CRC
CPU_BMI1 = (1 << 22),
CPU_BMI2 = (1 << 23),
CPU_RTM = (1 << 24), // Restricted Transactional Memory instructions
CPU_ADX = (1 << 25)
} cpuFeatureFlags;
enum {
CPU_FAMILY_AMD_11H = 0x11,
CPU_FAMILY_INTEL_CORE = 6,
CPU_MODEL_NEHALEM = 0x1e,
CPU_MODEL_NEHALEM_EP = 0x1a,
CPU_MODEL_NEHALEM_EX = 0x2e,
CPU_MODEL_WESTMERE = 0x25,
CPU_MODEL_WESTMERE_EP = 0x2c,
CPU_MODEL_WESTMERE_EX = 0x2f,
CPU_MODEL_SANDYBRIDGE = 0x2a,
CPU_MODEL_SANDYBRIDGE_EP = 0x2d,
CPU_MODEL_IVYBRIDGE_EP = 0x3a,
CPU_MODEL_HASWELL_E3 = 0x3c,
CPU_MODEL_HASWELL_E7 = 0x3f,
CPU_MODEL_BROADWELL = 0x3d
} cpuExtendedFamily;
struct CpuidInfo {
uint32_t std_max_function;
uint32_t std_vendor_name_0;
uint32_t std_vendor_name_1;
uint32_t std_vendor_name_2;
StdCpuid1Eax std_cpuid1_eax;
StdCpuid1Ebx std_cpuid1_ebx;
StdCpuid1Ecx std_cpuid1_ecx;
StdCpuid1Edx std_cpuid1_edx;
DcpCpuid4Eax dcp_cpuid4_eax;
DcpCpuid4Ebx dcp_cpuid4_ebx;
uint32_t dcp_cpuid4_ecx; // unused currently
uint32_t dcp_cpuid4_edx; // unused currently
SefCpuid7Eax sef_cpuid7_eax;
SefCpuid7Ebx sef_cpuid7_ebx;
uint32_t sef_cpuid7_ecx; // unused currently
uint32_t sef_cpuid7_edx; // unused currently
uint32_t tpl_cpuidB0_eax;
TplCpuidBEbx tpl_cpuidB0_ebx;
uint32_t tpl_cpuidB0_ecx; // unused currently
uint32_t tpl_cpuidB0_edx; // unused currently
uint32_t tpl_cpuidB1_eax;
TplCpuidBEbx tpl_cpuidB1_ebx;
uint32_t tpl_cpuidB1_ecx; // unused currently
uint32_t tpl_cpuidB1_edx; // unused currently
uint32_t tpl_cpuidB2_eax;
TplCpuidBEbx tpl_cpuidB2_ebx;
uint32_t tpl_cpuidB2_ecx; // unused currently
uint32_t tpl_cpuidB2_edx; // unused currently
uint32_t ext_max_function;
uint32_t ext_vendor_name_0;
uint32_t ext_vendor_name_1;
uint32_t ext_vendor_name_2;
uint32_t ext_cpuid1_eax; // reserved
uint32_t ext_cpuid1_ebx; // reserved
ExtCpuid1Ecx ext_cpuid1_ecx;
ExtCpuid1Edx ext_cpuid1_edx;
uint32_t proc_name_0, proc_name_1, proc_name_2, proc_name_3;
uint32_t proc_name_4, proc_name_5, proc_name_6, proc_name_7;
uint32_t proc_name_8, proc_name_9, proc_name_10,proc_name_11;
uint32_t ext_cpuid5_eax; // unused currently
uint32_t ext_cpuid5_ebx; // reserved
ExtCpuid5Ex ext_cpuid5_ecx; // L1 data cache info (AMD)
ExtCpuid5Ex ext_cpuid5_edx; // L1 instruction cache info (AMD)
uint32_t ext_cpuid7_eax; // reserved
uint32_t ext_cpuid7_ebx; // reserved
uint32_t ext_cpuid7_ecx; // reserved
ExtCpuid7Edx ext_cpuid7_edx; // tscinv
uint32_t ext_cpuid8_eax; // unused currently
uint32_t ext_cpuid8_ebx; // reserved
ExtCpuid8Ecx ext_cpuid8_ecx;
uint32_t ext_cpuid8_edx; // reserved
XemXcr0Eax xem_xcr0_eax;
uint32_t xem_xcr0_edx; // reserved
int ymm_save[8*4]; // Save ymm0, ymm7, ymm8, ymm15
};
static CpuidInfo _cpuid_info;
static uint32_t extended_cpu_family() {
uint32_t result = _cpuid_info.std_cpuid1_eax.bits.family;
result += _cpuid_info.std_cpuid1_eax.bits.ext_family;
return result;
}
static uint32_t extended_cpu_model() {
uint32_t result = _cpuid_info.std_cpuid1_eax.bits.model;
result |= _cpuid_info.std_cpuid1_eax.bits.ext_model << 4;
return result;
}
static uint32_t cpu_stepping() {
uint32_t result = _cpuid_info.std_cpuid1_eax.bits.stepping;
return result;
}
static uint logical_processor_count() {
uint result = threads_per_core();
return result;
}
static uint32_t feature_flags() {
uint32_t result = 0;
if (_cpuid_info.std_cpuid1_edx.bits.cmpxchg8 != 0)
result |= CPU_CX8;
if (_cpuid_info.std_cpuid1_edx.bits.cmov != 0)
result |= CPU_CMOV;
if (_cpuid_info.std_cpuid1_edx.bits.fxsr != 0 || (is_amd() &&
_cpuid_info.ext_cpuid1_edx.bits.fxsr != 0))
result |= CPU_FXSR;
if (threads_per_core() > 1)
result |= CPU_HT;
if (_cpuid_info.std_cpuid1_edx.bits.mmx != 0 || (is_amd() &&
_cpuid_info.ext_cpuid1_edx.bits.mmx != 0))
result |= CPU_MMX;
if (_cpuid_info.std_cpuid1_edx.bits.sse != 0)
result |= CPU_SSE;
if (_cpuid_info.std_cpuid1_edx.bits.sse2 != 0)
result |= CPU_SSE2;
if (_cpuid_info.std_cpuid1_ecx.bits.sse3 != 0)
result |= CPU_SSE3;
if (_cpuid_info.std_cpuid1_ecx.bits.ssse3 != 0)
result |= CPU_SSSE3;
if (_cpuid_info.std_cpuid1_ecx.bits.sse4_1 != 0)
result |= CPU_SSE4_1;
if (_cpuid_info.std_cpuid1_ecx.bits.sse4_2 != 0)
result |= CPU_SSE4_2;
if (_cpuid_info.std_cpuid1_ecx.bits.popcnt != 0)
result |= CPU_POPCNT;
if (_cpuid_info.std_cpuid1_ecx.bits.avx != 0 &&
_cpuid_info.std_cpuid1_ecx.bits.osxsave != 0 &&
_cpuid_info.xem_xcr0_eax.bits.sse != 0 &&
_cpuid_info.xem_xcr0_eax.bits.ymm != 0) {
result |= CPU_AVX;
if (_cpuid_info.sef_cpuid7_ebx.bits.avx2 != 0)
result |= CPU_AVX2;
}
if(_cpuid_info.sef_cpuid7_ebx.bits.bmi1 != 0)
result |= CPU_BMI1;
if (_cpuid_info.std_cpuid1_edx.bits.tsc != 0)
result |= CPU_TSC;
if (_cpuid_info.ext_cpuid7_edx.bits.tsc_invariance != 0)
result |= CPU_TSCINV;
if (_cpuid_info.std_cpuid1_ecx.bits.aes != 0)
result |= CPU_AES;
if (_cpuid_info.sef_cpuid7_ebx.bits.erms != 0)
result |= CPU_ERMS;
if (_cpuid_info.std_cpuid1_ecx.bits.clmul != 0)
result |= CPU_CLMUL;
if (_cpuid_info.sef_cpuid7_ebx.bits.rtm != 0)
result |= CPU_RTM;
if (is_amd()) {
if ((_cpuid_info.ext_cpuid1_edx.bits.tdnow != 0) ||
(_cpuid_info.ext_cpuid1_ecx.bits.prefetchw != 0))
result |= CPU_3DNOW_PREFETCH;
if (_cpuid_info.ext_cpuid1_ecx.bits.lzcnt != 0)
result |= CPU_LZCNT;
if (_cpuid_info.ext_cpuid1_ecx.bits.sse4a != 0)
result |= CPU_SSE4A;
}
if(is_intel()) {
if(_cpuid_info.sef_cpuid7_ebx.bits.adx != 0)
result |= CPU_ADX;
if(_cpuid_info.sef_cpuid7_ebx.bits.bmi2 != 0)
result |= CPU_BMI2;
if(_cpuid_info.ext_cpuid1_ecx.bits.lzcnt_intel != 0)
result |= CPU_LZCNT;
if (_cpuid_info.ext_cpuid1_ecx.bits.misalignsse != 0) {
result |= CPU_3DNOW_PREFETCH;
}
}
return result;
}
static bool os_supports_avx_vectors() {
if (!supports_avx()) {
return false;
}
int nreg = 2 LP64_ONLY(+2);
for (int i = 0; i < 8 * nreg; i++) { // 32 bytes per ymm register
if (_cpuid_info.ymm_save[i] != ymm_test_value()) {
return false;
}
}
return true;
}
static void get_processor_features();
public:
static ByteSize std_cpuid0_offset() { return byte_offset_of(CpuidInfo, std_max_function); }
static ByteSize std_cpuid1_offset() { return byte_offset_of(CpuidInfo, std_cpuid1_eax); }
static ByteSize dcp_cpuid4_offset() { return byte_offset_of(CpuidInfo, dcp_cpuid4_eax); }
static ByteSize sef_cpuid7_offset() { return byte_offset_of(CpuidInfo, sef_cpuid7_eax); }
static ByteSize ext_cpuid1_offset() { return byte_offset_of(CpuidInfo, ext_cpuid1_eax); }
static ByteSize ext_cpuid5_offset() { return byte_offset_of(CpuidInfo, ext_cpuid5_eax); }
static ByteSize ext_cpuid7_offset() { return byte_offset_of(CpuidInfo, ext_cpuid7_eax); }
static ByteSize ext_cpuid8_offset() { return byte_offset_of(CpuidInfo, ext_cpuid8_eax); }
static ByteSize tpl_cpuidB0_offset() { return byte_offset_of(CpuidInfo, tpl_cpuidB0_eax); }
static ByteSize tpl_cpuidB1_offset() { return byte_offset_of(CpuidInfo, tpl_cpuidB1_eax); }
static ByteSize tpl_cpuidB2_offset() { return byte_offset_of(CpuidInfo, tpl_cpuidB2_eax); }
static ByteSize xem_xcr0_offset() { return byte_offset_of(CpuidInfo, xem_xcr0_eax); }
static ByteSize ymm_save_offset() { return byte_offset_of(CpuidInfo, ymm_save); }
static int ymm_test_value() { return 0xCAFEBABE; }
static void get_cpu_info_wrapper();
static void set_cpuinfo_segv_addr(address pc) { _cpuinfo_segv_addr = pc; }
static bool is_cpuinfo_segv_addr(address pc) { return _cpuinfo_segv_addr == pc; }
static void set_cpuinfo_cont_addr(address pc) { _cpuinfo_cont_addr = pc; }
static address cpuinfo_cont_addr() { return _cpuinfo_cont_addr; }
static void clean_cpuFeatures() { _cpuFeatures = 0; }
static void set_avx_cpuFeatures() { _cpuFeatures = (CPU_SSE | CPU_SSE2 | CPU_AVX); }
static void initialize();
static bool use_biased_locking();
static void assert_is_initialized() {
assert(_cpuid_info.std_cpuid1_eax.bits.family != 0, "VM_Version not initialized");
}
static int cpu_family() { return _cpu;}
static bool is_P6() { return cpu_family() >= 6; }
static bool is_amd() { assert_is_initialized(); return _cpuid_info.std_vendor_name_0 == 0x68747541; } // 'htuA'
static bool is_intel() { assert_is_initialized(); return _cpuid_info.std_vendor_name_0 == 0x756e6547; } // 'uneG'
static bool supports_processor_topology() {
return (_cpuid_info.std_max_function >= 0xB) &&
(((_cpuid_info.tpl_cpuidB0_eax & 0x1f) | _cpuid_info.tpl_cpuidB0_ebx.bits.logical_cpus) != 0);
}
static uint cores_per_cpu() {
uint result = 1;
if (is_intel()) {
bool supports_topology = supports_processor_topology();
if (supports_topology) {
result = _cpuid_info.tpl_cpuidB1_ebx.bits.logical_cpus /
_cpuid_info.tpl_cpuidB0_ebx.bits.logical_cpus;
}
if (!supports_topology || result == 0) {
result = (_cpuid_info.dcp_cpuid4_eax.bits.cores_per_cpu + 1);
}
} else if (is_amd()) {
result = (_cpuid_info.ext_cpuid8_ecx.bits.cores_per_cpu + 1);
}
return result;
}
static uint threads_per_core() {
uint result = 1;
if (is_intel() && supports_processor_topology()) {
result = _cpuid_info.tpl_cpuidB0_ebx.bits.logical_cpus;
} else if (_cpuid_info.std_cpuid1_edx.bits.ht != 0) {
result = _cpuid_info.std_cpuid1_ebx.bits.threads_per_cpu /
cores_per_cpu();
}
return (result == 0 ? 1 : result);
}
static intx L1_line_size() {
intx result = 0;
if (is_intel()) {
result = (_cpuid_info.dcp_cpuid4_ebx.bits.L1_line_size + 1);
} else if (is_amd()) {
result = _cpuid_info.ext_cpuid5_ecx.bits.L1_line_size;
}
if (result < 32) // not defined ?
result = 32; // 32 bytes by default on x86 and other x64
return result;
}
static intx prefetch_data_size() {
return L1_line_size();
}
static bool supports_cpuid() { return _cpuFeatures != 0; }
static bool supports_cmpxchg8() { return (_cpuFeatures & CPU_CX8) != 0; }
static bool supports_cmov() { return (_cpuFeatures & CPU_CMOV) != 0; }
static bool supports_fxsr() { return (_cpuFeatures & CPU_FXSR) != 0; }
static bool supports_ht() { return (_cpuFeatures & CPU_HT) != 0; }
static bool supports_mmx() { return (_cpuFeatures & CPU_MMX) != 0; }
static bool supports_sse() { return (_cpuFeatures & CPU_SSE) != 0; }
static bool supports_sse2() { return (_cpuFeatures & CPU_SSE2) != 0; }
static bool supports_sse3() { return (_cpuFeatures & CPU_SSE3) != 0; }
static bool supports_ssse3() { return (_cpuFeatures & CPU_SSSE3)!= 0; }
static bool supports_sse4_1() { return (_cpuFeatures & CPU_SSE4_1) != 0; }
static bool supports_sse4_2() { return (_cpuFeatures & CPU_SSE4_2) != 0; }
static bool supports_popcnt() { return (_cpuFeatures & CPU_POPCNT) != 0; }
static bool supports_avx() { return (_cpuFeatures & CPU_AVX) != 0; }
static bool supports_avx2() { return (_cpuFeatures & CPU_AVX2) != 0; }
static bool supports_tsc() { return (_cpuFeatures & CPU_TSC) != 0; }
static bool supports_aes() { return (_cpuFeatures & CPU_AES) != 0; }
static bool supports_erms() { return (_cpuFeatures & CPU_ERMS) != 0; }
static bool supports_clmul() { return (_cpuFeatures & CPU_CLMUL) != 0; }
static bool supports_rtm() { return (_cpuFeatures & CPU_RTM) != 0; }
static bool supports_bmi1() { return (_cpuFeatures & CPU_BMI1) != 0; }
static bool supports_bmi2() { return (_cpuFeatures & CPU_BMI2) != 0; }
static bool supports_adx() { return (_cpuFeatures & CPU_ADX) != 0; }
static bool is_intel_family_core() { return is_intel() &&
extended_cpu_family() == CPU_FAMILY_INTEL_CORE; }
static bool is_intel_tsc_synched_at_init() {
if (is_intel_family_core()) {
uint32_t ext_model = extended_cpu_model();
if (ext_model == CPU_MODEL_NEHALEM_EP ||
ext_model == CPU_MODEL_WESTMERE_EP ||
ext_model == CPU_MODEL_SANDYBRIDGE_EP ||
ext_model == CPU_MODEL_IVYBRIDGE_EP) {
return true;
}
}
return false;
}
static bool supports_3dnow_prefetch() { return (_cpuFeatures & CPU_3DNOW_PREFETCH) != 0; }
static bool supports_mmx_ext() { return is_amd() && _cpuid_info.ext_cpuid1_edx.bits.mmx_amd != 0; }
static bool supports_lzcnt() { return (_cpuFeatures & CPU_LZCNT) != 0; }
static bool supports_sse4a() { return (_cpuFeatures & CPU_SSE4A) != 0; }
static bool is_amd_Barcelona() { return is_amd() &&
extended_cpu_family() == CPU_FAMILY_AMD_11H; }
static bool supports_tscinv_bit() {
return (_cpuFeatures & CPU_TSCINV) != 0;
}
static bool supports_tscinv() {
return supports_tscinv_bit() &&
( (is_amd() && !is_amd_Barcelona()) ||
is_intel_tsc_synched_at_init() );
}
static bool has_fast_idiv() { return is_intel() && cpu_family() == 6 &&
supports_sse3() && _model != 0x1C; }
static bool supports_compare_and_exchange() { return true; }
static const char* cpu_features() { return _features_str; }
static intx allocate_prefetch_distance() {
intx count = AllocatePrefetchDistance;
if (count < 0) { // default ?
if (is_amd()) { // AMD
if (supports_sse2())
count = 256; // Opteron
else
count = 128; // Athlon
} else { // Intel
if (supports_sse2())
if (cpu_family() == 6) {
count = 256; // Pentium M, Core, Core2
} else {
count = 512; // Pentium 4
}
else
count = 128; // Pentium 3 (and all other old CPUs)
}
}
return count;
}
static intx allocate_prefetch_style() {
assert(AllocatePrefetchStyle >= 0, "AllocatePrefetchStyle should be positive");
return AllocatePrefetchDistance > 0 ? AllocatePrefetchStyle : 0;
}
static intx prefetch_copy_interval_in_bytes() {
intx interval = PrefetchCopyIntervalInBytes;
return interval >= 0 ? interval : 576;
}
static intx prefetch_scan_interval_in_bytes() {
intx interval = PrefetchScanIntervalInBytes;
return interval >= 0 ? interval : 576;
}
static intx prefetch_fields_ahead() {
intx count = PrefetchFieldsAhead;
return count >= 0 ? count : 1;
}
#ifdef __APPLE__
static bool is_cpu_emulated();
#endif
};
#endif // CPU_X86_VM_VM_VERSION_X86_HPP
C:\hotspot-69087d08d473\src\cpu\x86\vm/vtableStubs_x86_32.cpp
#include "precompiled.hpp"
#include "asm/macroAssembler.hpp"
#include "code/vtableStubs.hpp"
#include "interp_masm_x86.hpp"
#include "memory/resourceArea.hpp"
#include "oops/compiledICHolder.hpp"
#include "oops/instanceKlass.hpp"
#include "oops/klassVtable.hpp"
#include "runtime/sharedRuntime.hpp"
#include "vmreg_x86.inline.hpp"
#ifdef COMPILER2
#include "opto/runtime.hpp"
#endif
#define __ masm->
#ifndef PRODUCT
extern "C" void bad_compiled_vtable_index(JavaThread* thread, oop receiver, int index);
#endif
VtableStub* VtableStubs::create_vtable_stub(int vtable_index) {
const int i486_code_length = VtableStub::pd_code_size_limit(true);
VtableStub* s = new(i486_code_length) VtableStub(true, vtable_index);
if (s == NULL) {
return NULL;
}
ResourceMark rm;
CodeBuffer cb(s->entry_point(), i486_code_length);
MacroAssembler* masm = new MacroAssembler(&cb);
#ifndef PRODUCT
if (CountCompiledCalls) {
__ incrementl(ExternalAddress((address) SharedRuntime::nof_megamorphic_calls_addr()));
}
#endif /* PRODUCT */
assert(VtableStub::receiver_location() == rcx->as_VMReg(), "receiver expected in rcx");
address npe_addr = __ pc();
__ movptr(rax, Address(rcx, oopDesc::klass_offset_in_bytes()));
#ifndef PRODUCT
if (DebugVtables) {
Label L;
__ cmpl(Address(rax, InstanceKlass::vtable_length_offset()*wordSize), vtable_index*vtableEntry::size());
__ jcc(Assembler::greater, L);
__ movl(rbx, vtable_index);
__ call_VM(noreg, CAST_FROM_FN_PTR(address, bad_compiled_vtable_index), rcx, rbx);
__ bind(L);
}
#endif // PRODUCT
const Register method = rbx;
__ lookup_virtual_method(rax, vtable_index, method);
if (DebugVtables) {
Label L;
__ cmpptr(method, (int32_t)NULL_WORD);
__ jcc(Assembler::equal, L);
__ cmpptr(Address(method, Method::from_compiled_offset()), (int32_t)NULL_WORD);
__ jcc(Assembler::notZero, L);
__ stop("Vtable entry is NULL");
__ bind(L);
}
address ame_addr = __ pc();
__ jmp( Address(method, Method::from_compiled_offset()));
masm->flush();
if (PrintMiscellaneous && (WizardMode || Verbose)) {
tty->print_cr("vtable #%d at " PTR_FORMAT "[%d] left over: %d",
vtable_index, p2i(s->entry_point()),
(int)(s->code_end() - s->entry_point()),
(int)(s->code_end() - __ pc()));
}
guarantee(__ pc() <= s->code_end(), "overflowed buffer");
int slop = 3; // 32-bit offset is this much larger than an 8-bit one
assert(vtable_index > 10 || __ pc() + slop <= s->code_end(), "room for 32-bit offset");
s->set_exception_points(npe_addr, ame_addr);
return s;
}
VtableStub* VtableStubs::create_itable_stub(int itable_index) {
const int i486_code_length = VtableStub::pd_code_size_limit(false);
VtableStub* s = new(i486_code_length) VtableStub(false, itable_index);
if (s == NULL) {
return NULL;
}
ResourceMark rm;
CodeBuffer cb(s->entry_point(), i486_code_length);
MacroAssembler* masm = new MacroAssembler(&cb);
#ifndef PRODUCT
if (CountCompiledCalls) {
__ incrementl(ExternalAddress((address) SharedRuntime::nof_megamorphic_calls_addr()));
}
#endif /* PRODUCT */
const Register recv_klass_reg = rsi;
const Register holder_klass_reg = rax; // declaring interface klass (DECC)
const Register resolved_klass_reg = rbx; // resolved interface klass (REFC)
const Register temp_reg = rdi;
const Register icholder_reg = rax;
__ movptr(resolved_klass_reg, Address(icholder_reg, CompiledICHolder::holder_klass_offset()));
__ movptr(holder_klass_reg, Address(icholder_reg, CompiledICHolder::holder_metadata_offset()));
Label L_no_such_interface;
address npe_addr = __ pc();
assert(VtableStub::receiver_location() == rcx->as_VMReg(), "receiver expected in rcx");
__ load_klass(recv_klass_reg, rcx);
__ lookup_interface_method(// inputs: rec. class, interface
recv_klass_reg, resolved_klass_reg, noreg,
recv_klass_reg, temp_reg,
L_no_such_interface,
const Register method = rbx;
__ load_klass(recv_klass_reg, rcx); // restore recv_klass_reg
__ lookup_interface_method(// inputs: rec. class, interface, itable index
recv_klass_reg, holder_klass_reg, itable_index,
method, temp_reg,
L_no_such_interface);
#ifdef ASSERT
if (DebugVtables) {
Label L1;
__ cmpptr(method, (int32_t)NULL_WORD);
__ jcc(Assembler::equal, L1);
__ cmpptr(Address(method, Method::from_compiled_offset()), (int32_t)NULL_WORD);
__ jcc(Assembler::notZero, L1);
__ stop("Method* is null");
__ bind(L1);
}
#endif // ASSERT
address ame_addr = __ pc();
__ jmp(Address(method, Method::from_compiled_offset()));
__ bind(L_no_such_interface);
__ jump(RuntimeAddress(StubRoutines::throw_IncompatibleClassChangeError_entry()));
__ flush();
if (PrintMiscellaneous && (WizardMode || Verbose)) {
tty->print_cr("itable #%d at " PTR_FORMAT "[%d] left over: %d",
itable_index, p2i(s->entry_point()),
(int)(s->code_end() - s->entry_point()),
(int)(s->code_end() - __ pc()));
}
guarantee(__ pc() <= s->code_end(), "overflowed buffer");
int slop = 3; // 32-bit offset is this much larger than an 8-bit one
assert(itable_index > 10 || __ pc() + slop <= s->code_end(), "room for 32-bit offset");
s->set_exception_points(npe_addr, ame_addr);
return s;
}
int VtableStub::pd_code_size_limit(bool is_vtable_stub) {
if (is_vtable_stub) {
return (DebugVtables ? 210 : 16) + (CountCompiledCalls ? 6 : 0);
} else {
return (DebugVtables ? 256 : 116) + (CountCompiledCalls ? 6 : 0);
}
}
int VtableStub::pd_code_alignment() {
return wordSize;
}
C:\hotspot-69087d08d473\src\cpu\x86\vm/vtableStubs_x86_64.cpp
#include "precompiled.hpp"
#include "asm/macroAssembler.hpp"
#include "code/vtableStubs.hpp"
#include "interp_masm_x86.hpp"
#include "memory/resourceArea.hpp"
#include "oops/compiledICHolder.hpp"
#include "oops/instanceKlass.hpp"
#include "oops/klassVtable.hpp"
#include "runtime/sharedRuntime.hpp"
#include "vmreg_x86.inline.hpp"
#ifdef COMPILER2
#include "opto/runtime.hpp"
#endif
PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC
#define __ masm->
#ifndef PRODUCT
extern "C" void bad_compiled_vtable_index(JavaThread* thread,
oop receiver,
int index);
#endif
VtableStub* VtableStubs::create_vtable_stub(int vtable_index) {
const int amd64_code_length = VtableStub::pd_code_size_limit(true);
VtableStub* s = new(amd64_code_length) VtableStub(true, vtable_index);
if (s == NULL) {
return NULL;
}
ResourceMark rm;
CodeBuffer cb(s->entry_point(), amd64_code_length);
MacroAssembler* masm = new MacroAssembler(&cb);
#ifndef PRODUCT
if (CountCompiledCalls) {
__ incrementl(ExternalAddress((address) SharedRuntime::nof_megamorphic_calls_addr()));
}
#endif
assert(VtableStub::receiver_location() == j_rarg0->as_VMReg(), "receiver expected in j_rarg0");
address npe_addr = __ pc();
__ load_klass(rax, j_rarg0);
#ifndef PRODUCT
if (DebugVtables) {
Label L;
__ cmpl(Address(rax, InstanceKlass::vtable_length_offset() * wordSize),
vtable_index * vtableEntry::size());
__ jcc(Assembler::greater, L);
__ movl(rbx, vtable_index);
__ call_VM(noreg,
CAST_FROM_FN_PTR(address, bad_compiled_vtable_index), j_rarg0, rbx);
__ bind(L);
}
#endif // PRODUCT
const Register method = rbx;
__ lookup_virtual_method(rax, vtable_index, method);
if (DebugVtables) {
Label L;
__ cmpptr(method, (int32_t)NULL_WORD);
__ jcc(Assembler::equal, L);
__ cmpptr(Address(method, Method::from_compiled_offset()), (int32_t)NULL_WORD);
__ jcc(Assembler::notZero, L);
__ stop("Vtable entry is NULL");
__ bind(L);
}
address ame_addr = __ pc();
__ jmp( Address(rbx, Method::from_compiled_offset()));
__ flush();
if (PrintMiscellaneous && (WizardMode || Verbose)) {
tty->print_cr("vtable #%d at " PTR_FORMAT "[%d] left over: %d",
vtable_index, s->entry_point(),
(int)(s->code_end() - s->entry_point()),
(int)(s->code_end() - __ pc()));
}
guarantee(__ pc() <= s->code_end(), "overflowed buffer");
int slop = 3; // 32-bit offset is this much larger than an 8-bit one
assert(vtable_index > 10 || __ pc() + slop <= s->code_end(), "room for 32-bit offset");
s->set_exception_points(npe_addr, ame_addr);
return s;
}
VtableStub* VtableStubs::create_itable_stub(int itable_index) {
const int amd64_code_length = VtableStub::pd_code_size_limit(false);
VtableStub* s = new(amd64_code_length) VtableStub(false, itable_index);
if (s == NULL) {
return NULL;
}
ResourceMark rm;
CodeBuffer cb(s->entry_point(), amd64_code_length);
MacroAssembler* masm = new MacroAssembler(&cb);
#ifndef PRODUCT
if (CountCompiledCalls) {
__ incrementl(ExternalAddress((address) SharedRuntime::nof_megamorphic_calls_addr()));
}
#endif
const Register recv_klass_reg = r10;
const Register holder_klass_reg = rax; // declaring interface klass (DECC)
const Register resolved_klass_reg = rbx; // resolved interface klass (REFC)
const Register temp_reg = r11;
Label L_no_such_interface;
const Register icholder_reg = rax;
__ movptr(resolved_klass_reg, Address(icholder_reg, CompiledICHolder::holder_klass_offset()));
__ movptr(holder_klass_reg, Address(icholder_reg, CompiledICHolder::holder_metadata_offset()));
assert(VtableStub::receiver_location() == j_rarg0->as_VMReg(), "receiver expected in j_rarg0");
address npe_addr = __ pc();
__ load_klass(recv_klass_reg, j_rarg0);
__ lookup_interface_method(// inputs: rec. class, interface
recv_klass_reg, resolved_klass_reg, noreg,
recv_klass_reg, temp_reg,
L_no_such_interface,
const Register method = rbx;
__ load_klass(recv_klass_reg, j_rarg0); // restore recv_klass_reg
__ lookup_interface_method(// inputs: rec. class, interface, itable index
recv_klass_reg, holder_klass_reg, itable_index,
method, temp_reg,
L_no_such_interface);
#ifdef ASSERT
if (DebugVtables) {
Label L2;
__ cmpptr(method, (int32_t)NULL_WORD);
__ jcc(Assembler::equal, L2);
__ cmpptr(Address(method, Method::from_compiled_offset()), (int32_t)NULL_WORD);
__ jcc(Assembler::notZero, L2);
__ stop("compiler entrypoint is null");
__ bind(L2);
}
#endif // ASSERT
address ame_addr = __ pc();
__ jmp(Address(method, Method::from_compiled_offset()));
__ bind(L_no_such_interface);
__ jump(RuntimeAddress(StubRoutines::throw_IncompatibleClassChangeError_entry()));
__ flush();
if (PrintMiscellaneous && (WizardMode || Verbose)) {
tty->print_cr("itable #%d at " PTR_FORMAT "[%d] left over: %d",
itable_index, s->entry_point(),
(int)(s->code_end() - s->entry_point()),
(int)(s->code_end() - __ pc()));
}
guarantee(__ pc() <= s->code_end(), "overflowed buffer");
int slop = 3; // 32-bit offset is this much larger than an 8-bit one
assert(itable_index > 10 || __ pc() + slop <= s->code_end(), "room for 32-bit offset");
s->set_exception_points(npe_addr, ame_addr);
return s;
}
int VtableStub::pd_code_size_limit(bool is_vtable_stub) {
if (is_vtable_stub) {
return (DebugVtables ? 512 : 24) + (CountCompiledCalls ? 13 : 0) +
(UseCompressedClassPointers ? MacroAssembler::instr_size_for_decode_klass_not_null() : 0);
} else {
return (DebugVtables ? 512 : 140) + (CountCompiledCalls ? 13 : 0) +
(UseCompressedClassPointers ? 2 * MacroAssembler::instr_size_for_decode_klass_not_null() : 0);
}
}
int VtableStub::pd_code_alignment() {
return wordSize;
}
ccccccccc13
最新推荐文章于 2024-05-10 09:14:14 发布