Merge
This commit is contained in:
commit
e1fbf928ef
@ -53,6 +53,8 @@ LIR_Opr FrameMap::map_to_opr(BasicType type, VMRegPair* reg, bool outgoing) {
|
||||
opr = as_long_opr(reg);
|
||||
} else if (type == T_OBJECT || type == T_ARRAY) {
|
||||
opr = as_oop_opr(reg);
|
||||
} else if (type == T_METADATA) {
|
||||
opr = as_metadata_opr(reg);
|
||||
} else {
|
||||
opr = as_opr(reg);
|
||||
}
|
||||
|
@ -2565,7 +2565,7 @@ void LIR_Assembler::type_profile_helper(Register mdo, int mdo_offset_bias,
|
||||
Address receiver_addr(mdo, md->byte_offset_of_slot(data, ReceiverTypeData::receiver_offset(i)) -
|
||||
mdo_offset_bias);
|
||||
__ ld_ptr(receiver_addr, tmp1);
|
||||
__ verify_oop(tmp1);
|
||||
__ verify_klass_ptr(tmp1);
|
||||
__ cmp_and_brx_short(recv, tmp1, Assembler::notEqual, Assembler::pt, next_test);
|
||||
Address data_addr(mdo, md->byte_offset_of_slot(data, ReceiverTypeData::receiver_count_offset(i)) -
|
||||
mdo_offset_bias);
|
||||
|
@ -404,7 +404,9 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
|
||||
if (id == fast_new_instance_init_check_id) {
|
||||
// make sure the klass is initialized
|
||||
__ ldub(G5_klass, in_bytes(InstanceKlass::init_state_offset()), G3_t1);
|
||||
__ cmp_and_br_short(G3_t1, InstanceKlass::fully_initialized, Assembler::notEqual, Assembler::pn, slow_path);
|
||||
__ cmp(G3_t1, InstanceKlass::fully_initialized);
|
||||
__ br(Assembler::notEqual, false, Assembler::pn, slow_path);
|
||||
__ delayed()->nop();
|
||||
}
|
||||
#ifdef ASSERT
|
||||
// assert object can be fast path allocated
|
||||
@ -515,7 +517,9 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
|
||||
|
||||
// check that array length is small enough for fast path
|
||||
__ set(C1_MacroAssembler::max_array_allocation_length, G3_t1);
|
||||
__ cmp_and_br_short(G4_length, G3_t1, Assembler::greaterUnsigned, Assembler::pn, slow_path);
|
||||
__ cmp(G4_length, G3_t1);
|
||||
__ br(Assembler::greaterUnsigned, false, Assembler::pn, slow_path);
|
||||
__ delayed()->nop();
|
||||
|
||||
// if we got here then the TLAB allocation failed, so try
|
||||
// refilling the TLAB or allocating directly from eden.
|
||||
|
@ -3333,7 +3333,8 @@ void MacroAssembler::tlab_refill(Label& retry, Label& try_eden, Label& slow_case
|
||||
|
||||
if (CMSIncrementalMode || !Universe::heap()->supports_inline_contig_alloc()) {
|
||||
// No allocation in the shared eden.
|
||||
ba_short(slow_case);
|
||||
ba(slow_case);
|
||||
delayed()->nop();
|
||||
}
|
||||
|
||||
ld_ptr(G2_thread, in_bytes(JavaThread::tlab_top_offset()), top);
|
||||
@ -3358,7 +3359,8 @@ void MacroAssembler::tlab_refill(Label& retry, Label& try_eden, Label& slow_case
|
||||
add(t2, 1, t2);
|
||||
stw(t2, G2_thread, in_bytes(JavaThread::tlab_slow_allocations_offset()));
|
||||
}
|
||||
ba_short(try_eden);
|
||||
ba(try_eden);
|
||||
delayed()->nop();
|
||||
|
||||
bind(discard_tlab);
|
||||
if (TLABStats) {
|
||||
@ -3420,7 +3422,8 @@ void MacroAssembler::tlab_refill(Label& retry, Label& try_eden, Label& slow_case
|
||||
sub(top, ThreadLocalAllocBuffer::alignment_reserve_in_bytes(), top);
|
||||
st_ptr(top, G2_thread, in_bytes(JavaThread::tlab_end_offset()));
|
||||
verify_tlab();
|
||||
ba_short(retry);
|
||||
ba(retry);
|
||||
delayed()->nop();
|
||||
}
|
||||
|
||||
void MacroAssembler::incr_allocated_bytes(RegisterOrConstant size_in_bytes,
|
||||
|
@ -2022,6 +2022,10 @@ const RegMask Matcher::mathExactI_result_proj_mask() {
|
||||
return G1_REGI_mask();
|
||||
}
|
||||
|
||||
const RegMask Matcher::mathExactL_result_proj_mask() {
|
||||
return G1_REGL_mask();
|
||||
}
|
||||
|
||||
const RegMask Matcher::mathExactI_flags_proj_mask() {
|
||||
return INT_FLAGS_mask();
|
||||
}
|
||||
|
@ -1405,6 +1405,15 @@ void Assembler::imull(Register dst, Register src, int value) {
|
||||
}
|
||||
}
|
||||
|
||||
void Assembler::imull(Register dst, Address src) {
|
||||
InstructionMark im(this);
|
||||
prefix(src, dst);
|
||||
emit_int8(0x0F);
|
||||
emit_int8((unsigned char) 0xAF);
|
||||
emit_operand(dst, src);
|
||||
}
|
||||
|
||||
|
||||
void Assembler::incl(Address dst) {
|
||||
// Don't use it directly. Use MacroAssembler::increment() instead.
|
||||
InstructionMark im(this);
|
||||
@ -5024,6 +5033,14 @@ void Assembler::imulq(Register dst, Register src, int value) {
|
||||
}
|
||||
}
|
||||
|
||||
void Assembler::imulq(Register dst, Address src) {
|
||||
InstructionMark im(this);
|
||||
prefixq(src, dst);
|
||||
emit_int8(0x0F);
|
||||
emit_int8((unsigned char) 0xAF);
|
||||
emit_operand(dst, src);
|
||||
}
|
||||
|
||||
void Assembler::incl(Register dst) {
|
||||
// Don't use it directly. Use MacroAssembler::incrementl() instead.
|
||||
// Use two-byte form (one-byte from is a REX prefix in 64-bit mode)
|
||||
|
@ -1162,9 +1162,13 @@ private:
|
||||
|
||||
void imull(Register dst, Register src);
|
||||
void imull(Register dst, Register src, int value);
|
||||
void imull(Register dst, Address src);
|
||||
|
||||
void imulq(Register dst, Register src);
|
||||
void imulq(Register dst, Register src, int value);
|
||||
#ifdef _LP64
|
||||
void imulq(Register dst, Address src);
|
||||
#endif
|
||||
|
||||
|
||||
// jcc is the generic conditional branch generator to run-
|
||||
|
@ -40,11 +40,8 @@
|
||||
#include "runtime/synchronizer.hpp"
|
||||
#include "runtime/vframeArray.hpp"
|
||||
#include "utilities/debug.hpp"
|
||||
#ifdef TARGET_ARCH_MODEL_x86_32
|
||||
# include "interp_masm_x86_32.hpp"
|
||||
#endif
|
||||
#ifdef TARGET_ARCH_MODEL_x86_64
|
||||
# include "interp_masm_x86_64.hpp"
|
||||
#ifdef TARGET_ARCH_x86
|
||||
# include "interp_masm_x86.hpp"
|
||||
#endif
|
||||
|
||||
#ifdef CC_INTERP
|
||||
|
@ -52,6 +52,8 @@ LIR_Opr FrameMap::map_to_opr(BasicType type, VMRegPair* reg, bool) {
|
||||
#endif // _LP64
|
||||
} else if (type == T_OBJECT || type == T_ARRAY) {
|
||||
opr = as_oop_opr(reg);
|
||||
} else if (type == T_METADATA) {
|
||||
opr = as_metadata_opr(reg);
|
||||
} else {
|
||||
opr = as_opr(reg);
|
||||
}
|
||||
|
@ -432,15 +432,16 @@ int LIR_Assembler::emit_unwind_handler() {
|
||||
int offset = code_offset();
|
||||
|
||||
// Fetch the exception from TLS and clear out exception related thread state
|
||||
__ get_thread(rsi);
|
||||
__ movptr(rax, Address(rsi, JavaThread::exception_oop_offset()));
|
||||
__ movptr(Address(rsi, JavaThread::exception_oop_offset()), (intptr_t)NULL_WORD);
|
||||
__ movptr(Address(rsi, JavaThread::exception_pc_offset()), (intptr_t)NULL_WORD);
|
||||
Register thread = NOT_LP64(rsi) LP64_ONLY(r15_thread);
|
||||
NOT_LP64(__ get_thread(rsi));
|
||||
__ movptr(rax, Address(thread, JavaThread::exception_oop_offset()));
|
||||
__ movptr(Address(thread, JavaThread::exception_oop_offset()), (intptr_t)NULL_WORD);
|
||||
__ movptr(Address(thread, JavaThread::exception_pc_offset()), (intptr_t)NULL_WORD);
|
||||
|
||||
__ bind(_unwind_handler_entry);
|
||||
__ verify_not_null_oop(rax);
|
||||
if (method()->is_synchronized() || compilation()->env()->dtrace_method_probes()) {
|
||||
__ mov(rsi, rax); // Preserve the exception
|
||||
__ mov(rbx, rax); // Preserve the exception (rbx is always callee-saved)
|
||||
}
|
||||
|
||||
// Preform needed unlocking
|
||||
@ -448,19 +449,24 @@ int LIR_Assembler::emit_unwind_handler() {
|
||||
if (method()->is_synchronized()) {
|
||||
monitor_address(0, FrameMap::rax_opr);
|
||||
stub = new MonitorExitStub(FrameMap::rax_opr, true, 0);
|
||||
__ unlock_object(rdi, rbx, rax, *stub->entry());
|
||||
__ unlock_object(rdi, rsi, rax, *stub->entry());
|
||||
__ bind(*stub->continuation());
|
||||
}
|
||||
|
||||
if (compilation()->env()->dtrace_method_probes()) {
|
||||
#ifdef _LP64
|
||||
__ mov(rdi, r15_thread);
|
||||
__ mov_metadata(rsi, method()->constant_encoding());
|
||||
#else
|
||||
__ get_thread(rax);
|
||||
__ movptr(Address(rsp, 0), rax);
|
||||
__ mov_metadata(Address(rsp, sizeof(void*)), method()->constant_encoding());
|
||||
#endif
|
||||
__ call(RuntimeAddress(CAST_FROM_FN_PTR(address, SharedRuntime::dtrace_method_exit)));
|
||||
}
|
||||
|
||||
if (method()->is_synchronized() || compilation()->env()->dtrace_method_probes()) {
|
||||
__ mov(rax, rsi); // Restore the exception
|
||||
__ mov(rax, rbx); // Restore the exception
|
||||
}
|
||||
|
||||
// remove the activation and dispatch to the unwind handler
|
||||
@ -1206,6 +1212,10 @@ void LIR_Assembler::mem2reg(LIR_Opr src, LIR_Opr dest, BasicType type, LIR_Patch
|
||||
LIR_Address* addr = src->as_address_ptr();
|
||||
Address from_addr = as_Address(addr);
|
||||
|
||||
if (addr->base()->type() == T_OBJECT) {
|
||||
__ verify_oop(addr->base()->as_pointer_register());
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case T_BOOLEAN: // fall through
|
||||
case T_BYTE: // fall through
|
||||
|
@ -79,7 +79,7 @@ define_pd_global(bool, UseMembar, false);
|
||||
// GC Ergo Flags
|
||||
define_pd_global(uintx, CMSYoungGenPerWorker, 64*M); // default max size of CMS young gen, per GC worker thread
|
||||
|
||||
define_pd_global(uintx, TypeProfileLevel, 11);
|
||||
define_pd_global(uintx, TypeProfileLevel, 111);
|
||||
|
||||
#define ARCH_FLAGS(develop, product, diagnostic, experimental, notproduct) \
|
||||
\
|
||||
|
229
hotspot/src/cpu/x86/vm/interp_masm_x86.cpp
Normal file
229
hotspot/src/cpu/x86/vm/interp_masm_x86.cpp
Normal file
@ -0,0 +1,229 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "interp_masm_x86.hpp"
|
||||
#include "interpreter/interpreter.hpp"
|
||||
#include "oops/methodData.hpp"
|
||||
|
||||
#ifndef CC_INTERP
|
||||
void InterpreterMacroAssembler::profile_obj_type(Register obj, const Address& mdo_addr) {
|
||||
Label update, next, none;
|
||||
|
||||
verify_oop(obj);
|
||||
|
||||
testptr(obj, obj);
|
||||
jccb(Assembler::notZero, update);
|
||||
orptr(mdo_addr, TypeEntries::null_seen);
|
||||
jmpb(next);
|
||||
|
||||
bind(update);
|
||||
load_klass(obj, obj);
|
||||
|
||||
xorptr(obj, mdo_addr);
|
||||
testptr(obj, TypeEntries::type_klass_mask);
|
||||
jccb(Assembler::zero, next); // klass seen before, nothing to
|
||||
// do. The unknown bit may have been
|
||||
// set already but no need to check.
|
||||
|
||||
testptr(obj, TypeEntries::type_unknown);
|
||||
jccb(Assembler::notZero, next); // already unknown. Nothing to do anymore.
|
||||
|
||||
cmpptr(mdo_addr, 0);
|
||||
jccb(Assembler::equal, none);
|
||||
cmpptr(mdo_addr, TypeEntries::null_seen);
|
||||
jccb(Assembler::equal, none);
|
||||
// There is a chance that the checks above (re-reading profiling
|
||||
// data from memory) fail if another thread has just set the
|
||||
// profiling to this obj's klass
|
||||
xorptr(obj, mdo_addr);
|
||||
testptr(obj, TypeEntries::type_klass_mask);
|
||||
jccb(Assembler::zero, next);
|
||||
|
||||
// different than before. Cannot keep accurate profile.
|
||||
orptr(mdo_addr, TypeEntries::type_unknown);
|
||||
jmpb(next);
|
||||
|
||||
bind(none);
|
||||
// first time here. Set profile type.
|
||||
movptr(mdo_addr, obj);
|
||||
|
||||
bind(next);
|
||||
}
|
||||
|
||||
void InterpreterMacroAssembler::profile_arguments_type(Register mdp, Register callee, Register tmp, bool is_virtual) {
|
||||
if (!ProfileInterpreter) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (MethodData::profile_arguments() || MethodData::profile_return()) {
|
||||
Label profile_continue;
|
||||
|
||||
test_method_data_pointer(mdp, profile_continue);
|
||||
|
||||
int off_to_start = is_virtual ? in_bytes(VirtualCallData::virtual_call_data_size()) : in_bytes(CounterData::counter_data_size());
|
||||
|
||||
cmpb(Address(mdp, in_bytes(DataLayout::tag_offset()) - off_to_start), is_virtual ? DataLayout::virtual_call_type_data_tag : DataLayout::call_type_data_tag);
|
||||
jcc(Assembler::notEqual, profile_continue);
|
||||
|
||||
if (MethodData::profile_arguments()) {
|
||||
Label done;
|
||||
int off_to_args = in_bytes(TypeEntriesAtCall::args_data_offset());
|
||||
addptr(mdp, off_to_args);
|
||||
|
||||
for (int i = 0; i < TypeProfileArgsLimit; i++) {
|
||||
if (i > 0 || MethodData::profile_return()) {
|
||||
// If return value type is profiled we may have no argument to profile
|
||||
movptr(tmp, Address(mdp, in_bytes(TypeEntriesAtCall::cell_count_offset())-off_to_args));
|
||||
subl(tmp, i*TypeStackSlotEntries::per_arg_count());
|
||||
cmpl(tmp, TypeStackSlotEntries::per_arg_count());
|
||||
jcc(Assembler::less, done);
|
||||
}
|
||||
movptr(tmp, Address(callee, Method::const_offset()));
|
||||
load_unsigned_short(tmp, Address(tmp, ConstMethod::size_of_parameters_offset()));
|
||||
// stack offset o (zero based) from the start of the argument
|
||||
// list, for n arguments translates into offset n - o - 1 from
|
||||
// the end of the argument list
|
||||
subptr(tmp, Address(mdp, in_bytes(TypeEntriesAtCall::stack_slot_offset(i))-off_to_args));
|
||||
subl(tmp, 1);
|
||||
Address arg_addr = argument_address(tmp);
|
||||
movptr(tmp, arg_addr);
|
||||
|
||||
Address mdo_arg_addr(mdp, in_bytes(TypeEntriesAtCall::argument_type_offset(i))-off_to_args);
|
||||
profile_obj_type(tmp, mdo_arg_addr);
|
||||
|
||||
int to_add = in_bytes(TypeStackSlotEntries::per_arg_size());
|
||||
addptr(mdp, to_add);
|
||||
off_to_args += to_add;
|
||||
}
|
||||
|
||||
if (MethodData::profile_return()) {
|
||||
movptr(tmp, Address(mdp, in_bytes(TypeEntriesAtCall::cell_count_offset())-off_to_args));
|
||||
subl(tmp, TypeProfileArgsLimit*TypeStackSlotEntries::per_arg_count());
|
||||
}
|
||||
|
||||
bind(done);
|
||||
|
||||
if (MethodData::profile_return()) {
|
||||
// We're right after the type profile for the last
|
||||
// argument. tmp is the number of cell left in the
|
||||
// CallTypeData/VirtualCallTypeData to reach its end. Non null
|
||||
// if there's a return to profile.
|
||||
assert(ReturnTypeEntry::static_cell_count() < TypeStackSlotEntries::per_arg_count(), "can't move past ret type");
|
||||
shll(tmp, exact_log2(DataLayout::cell_size));
|
||||
addptr(mdp, tmp);
|
||||
}
|
||||
movptr(Address(rbp, frame::interpreter_frame_mdx_offset * wordSize), mdp);
|
||||
} else {
|
||||
assert(MethodData::profile_return(), "either profile call args or call ret");
|
||||
update_mdp_by_constant(mdp, in_bytes(ReturnTypeEntry::size()));
|
||||
}
|
||||
|
||||
// mdp points right after the end of the
|
||||
// CallTypeData/VirtualCallTypeData, right after the cells for the
|
||||
// return value type if there's one
|
||||
|
||||
bind(profile_continue);
|
||||
}
|
||||
}
|
||||
|
||||
void InterpreterMacroAssembler::profile_return_type(Register mdp, Register ret, Register tmp) {
|
||||
assert_different_registers(mdp, ret, tmp, _bcp_register);
|
||||
if (ProfileInterpreter && MethodData::profile_return()) {
|
||||
Label profile_continue, done;
|
||||
|
||||
test_method_data_pointer(mdp, profile_continue);
|
||||
|
||||
if (MethodData::profile_return_jsr292_only()) {
|
||||
// If we don't profile all invoke bytecodes we must make sure
|
||||
// it's a bytecode we indeed profile. We can't go back to the
|
||||
// begining of the ProfileData we intend to update to check its
|
||||
// type because we're right after it and we don't known its
|
||||
// length
|
||||
Label do_profile;
|
||||
cmpb(Address(_bcp_register, 0), Bytecodes::_invokedynamic);
|
||||
jcc(Assembler::equal, do_profile);
|
||||
cmpb(Address(_bcp_register, 0), Bytecodes::_invokehandle);
|
||||
jcc(Assembler::equal, do_profile);
|
||||
get_method(tmp);
|
||||
cmpb(Address(tmp, Method::intrinsic_id_offset_in_bytes()), vmIntrinsics::_compiledLambdaForm);
|
||||
jcc(Assembler::notEqual, profile_continue);
|
||||
|
||||
bind(do_profile);
|
||||
}
|
||||
|
||||
Address mdo_ret_addr(mdp, -in_bytes(ReturnTypeEntry::size()));
|
||||
mov(tmp, ret);
|
||||
profile_obj_type(tmp, mdo_ret_addr);
|
||||
|
||||
bind(profile_continue);
|
||||
}
|
||||
}
|
||||
|
||||
void InterpreterMacroAssembler::profile_parameters_type(Register mdp, Register tmp1, Register tmp2) {
|
||||
if (ProfileInterpreter && MethodData::profile_parameters()) {
|
||||
Label profile_continue, done;
|
||||
|
||||
test_method_data_pointer(mdp, profile_continue);
|
||||
|
||||
// Load the offset of the area within the MDO used for
|
||||
// parameters. If it's negative we're not profiling any parameters
|
||||
movl(tmp1, Address(mdp, in_bytes(MethodData::parameters_type_data_di_offset()) - in_bytes(MethodData::data_offset())));
|
||||
testl(tmp1, tmp1);
|
||||
jcc(Assembler::negative, profile_continue);
|
||||
|
||||
// Compute a pointer to the area for parameters from the offset
|
||||
// and move the pointer to the slot for the last
|
||||
// parameters. Collect profiling from last parameter down.
|
||||
// mdo start + parameters offset + array length - 1
|
||||
addptr(mdp, tmp1);
|
||||
movptr(tmp1, Address(mdp, in_bytes(ArrayData::array_len_offset())));
|
||||
decrement(tmp1, TypeStackSlotEntries::per_arg_count());
|
||||
|
||||
Label loop;
|
||||
bind(loop);
|
||||
|
||||
int off_base = in_bytes(ParametersTypeData::stack_slot_offset(0));
|
||||
int type_base = in_bytes(ParametersTypeData::type_offset(0));
|
||||
Address::ScaleFactor per_arg_scale = Address::times(DataLayout::cell_size);
|
||||
Address arg_off(mdp, tmp1, per_arg_scale, off_base);
|
||||
Address arg_type(mdp, tmp1, per_arg_scale, type_base);
|
||||
|
||||
// load offset on the stack from the slot for this parameter
|
||||
movptr(tmp2, arg_off);
|
||||
negptr(tmp2);
|
||||
// read the parameter from the local area
|
||||
movptr(tmp2, Address(_locals_register, tmp2, Interpreter::stackElementScale()));
|
||||
|
||||
// profile the parameter
|
||||
profile_obj_type(tmp2, arg_type);
|
||||
|
||||
// go to next parameter
|
||||
decrement(tmp1, TypeStackSlotEntries::per_arg_count());
|
||||
jcc(Assembler::positive, loop);
|
||||
|
||||
bind(profile_continue);
|
||||
}
|
||||
}
|
||||
#endif
|
60
hotspot/src/cpu/x86/vm/interp_masm_x86.hpp
Normal file
60
hotspot/src/cpu/x86/vm/interp_masm_x86.hpp
Normal file
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CPU_X86_VM_INTERP_MASM_X86_HPP
|
||||
#define CPU_X86_VM_INTERP_MASM_X86_HPP
|
||||
|
||||
#include "asm/macroAssembler.hpp"
|
||||
#include "asm/macroAssembler.inline.hpp"
|
||||
#include "interpreter/invocationCounter.hpp"
|
||||
#include "runtime/frame.hpp"
|
||||
|
||||
// This file specializes the assember with interpreter-specific macros
|
||||
|
||||
|
||||
class InterpreterMacroAssembler: public MacroAssembler {
|
||||
|
||||
#ifdef TARGET_ARCH_MODEL_x86_32
|
||||
# include "interp_masm_x86_32.hpp"
|
||||
#endif
|
||||
#ifdef TARGET_ARCH_MODEL_x86_64
|
||||
# include "interp_masm_x86_64.hpp"
|
||||
#endif
|
||||
|
||||
private:
|
||||
|
||||
Register _locals_register; // register that contains the pointer to the locals
|
||||
Register _bcp_register; // register that contains the bcp
|
||||
|
||||
public:
|
||||
#ifndef CC_INTERP
|
||||
void profile_obj_type(Register obj, const Address& mdo_addr);
|
||||
void profile_arguments_type(Register mdp, Register callee, Register tmp, bool is_virtual);
|
||||
void profile_return_type(Register mdp, Register ret, Register tmp);
|
||||
void profile_parameters_type(Register mdp, Register tmp1, Register tmp2);
|
||||
#endif /* !CC_INTERP */
|
||||
|
||||
};
|
||||
|
||||
#endif // CPU_X86_VM_INTERP_MASM_X86_HPP
|
@ -23,7 +23,7 @@
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "interp_masm_x86_32.hpp"
|
||||
#include "interp_masm_x86.hpp"
|
||||
#include "interpreter/interpreter.hpp"
|
||||
#include "interpreter/interpreterRuntime.hpp"
|
||||
#include "oops/arrayOop.hpp"
|
||||
@ -1046,159 +1046,6 @@ void InterpreterMacroAssembler::profile_not_taken_branch(Register mdp) {
|
||||
}
|
||||
}
|
||||
|
||||
void InterpreterMacroAssembler::profile_obj_type(Register obj, const Address& mdo_addr) {
|
||||
Label update, next, none;
|
||||
|
||||
verify_oop(obj);
|
||||
|
||||
testptr(obj, obj);
|
||||
jccb(Assembler::notZero, update);
|
||||
orptr(mdo_addr, TypeEntries::null_seen);
|
||||
jmpb(next);
|
||||
|
||||
bind(update);
|
||||
load_klass(obj, obj);
|
||||
|
||||
xorptr(obj, mdo_addr);
|
||||
testptr(obj, TypeEntries::type_klass_mask);
|
||||
jccb(Assembler::zero, next); // klass seen before, nothing to
|
||||
// do. The unknown bit may have been
|
||||
// set already but no need to check.
|
||||
|
||||
testptr(obj, TypeEntries::type_unknown);
|
||||
jccb(Assembler::notZero, next); // already unknown. Nothing to do anymore.
|
||||
|
||||
cmpptr(mdo_addr, 0);
|
||||
jccb(Assembler::equal, none);
|
||||
cmpptr(mdo_addr, TypeEntries::null_seen);
|
||||
jccb(Assembler::equal, none);
|
||||
// There is a chance that the checks above (re-reading profiling
|
||||
// data from memory) fail if another thread has just set the
|
||||
// profiling to this obj's klass
|
||||
xorptr(obj, mdo_addr);
|
||||
testptr(obj, TypeEntries::type_klass_mask);
|
||||
jccb(Assembler::zero, next);
|
||||
|
||||
// different than before. Cannot keep accurate profile.
|
||||
orptr(mdo_addr, TypeEntries::type_unknown);
|
||||
jmpb(next);
|
||||
|
||||
bind(none);
|
||||
// first time here. Set profile type.
|
||||
movptr(mdo_addr, obj);
|
||||
|
||||
bind(next);
|
||||
}
|
||||
|
||||
void InterpreterMacroAssembler::profile_arguments_type(Register mdp, Register callee, Register tmp, bool is_virtual) {
|
||||
if (!ProfileInterpreter) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (MethodData::profile_arguments() || MethodData::profile_return()) {
|
||||
Label profile_continue;
|
||||
|
||||
test_method_data_pointer(mdp, profile_continue);
|
||||
|
||||
int off_to_start = is_virtual ? in_bytes(VirtualCallData::virtual_call_data_size()) : in_bytes(CounterData::counter_data_size());
|
||||
|
||||
cmpb(Address(mdp, in_bytes(DataLayout::tag_offset()) - off_to_start), is_virtual ? DataLayout::virtual_call_type_data_tag : DataLayout::call_type_data_tag);
|
||||
jcc(Assembler::notEqual, profile_continue);
|
||||
|
||||
if (MethodData::profile_arguments()) {
|
||||
Label done;
|
||||
int off_to_args = in_bytes(TypeEntriesAtCall::args_data_offset());
|
||||
addptr(mdp, off_to_args);
|
||||
|
||||
for (int i = 0; i < TypeProfileArgsLimit; i++) {
|
||||
if (i > 0 || MethodData::profile_return()) {
|
||||
// If return value type is profiled we may have no argument to profile
|
||||
movl(tmp, Address(mdp, in_bytes(TypeEntriesAtCall::cell_count_offset())-off_to_args));
|
||||
subl(tmp, i*TypeStackSlotEntries::per_arg_count());
|
||||
cmpl(tmp, TypeStackSlotEntries::per_arg_count());
|
||||
jcc(Assembler::less, done);
|
||||
}
|
||||
movptr(tmp, Address(callee, Method::const_offset()));
|
||||
load_unsigned_short(tmp, Address(tmp, ConstMethod::size_of_parameters_offset()));
|
||||
// stack offset o (zero based) from the start of the argument
|
||||
// list, for n arguments translates into offset n - o - 1 from
|
||||
// the end of the argument list
|
||||
subl(tmp, Address(mdp, in_bytes(TypeEntriesAtCall::stack_slot_offset(i))-off_to_args));
|
||||
subl(tmp, 1);
|
||||
Address arg_addr = argument_address(tmp);
|
||||
movptr(tmp, arg_addr);
|
||||
|
||||
Address mdo_arg_addr(mdp, in_bytes(TypeEntriesAtCall::argument_type_offset(i))-off_to_args);
|
||||
profile_obj_type(tmp, mdo_arg_addr);
|
||||
|
||||
int to_add = in_bytes(TypeStackSlotEntries::per_arg_size());
|
||||
addptr(mdp, to_add);
|
||||
off_to_args += to_add;
|
||||
}
|
||||
|
||||
if (MethodData::profile_return()) {
|
||||
movl(tmp, Address(mdp, in_bytes(TypeEntriesAtCall::cell_count_offset())-off_to_args));
|
||||
subl(tmp, TypeProfileArgsLimit*TypeStackSlotEntries::per_arg_count());
|
||||
}
|
||||
|
||||
bind(done);
|
||||
|
||||
if (MethodData::profile_return()) {
|
||||
// We're right after the type profile for the last
|
||||
// argument. tmp is the number of cell left in the
|
||||
// CallTypeData/VirtualCallTypeData to reach its end. Non null
|
||||
// if there's a return to profile.
|
||||
assert(ReturnTypeEntry::static_cell_count() < TypeStackSlotEntries::per_arg_count(), "can't move past ret type");
|
||||
shll(tmp, exact_log2(DataLayout::cell_size));
|
||||
addptr(mdp, tmp);
|
||||
}
|
||||
movptr(Address(rbp, frame::interpreter_frame_mdx_offset * wordSize), mdp);
|
||||
} else {
|
||||
assert(MethodData::profile_return(), "either profile call args or call ret");
|
||||
update_mdp_by_constant(mdp, in_bytes(ReturnTypeEntry::size()));
|
||||
}
|
||||
|
||||
// mdp points right after the end of the
|
||||
// CallTypeData/VirtualCallTypeData, right after the cells for the
|
||||
// return value type if there's one
|
||||
|
||||
bind(profile_continue);
|
||||
}
|
||||
}
|
||||
|
||||
void InterpreterMacroAssembler::profile_return_type(Register mdp, Register ret, Register tmp) {
|
||||
assert_different_registers(mdp, ret, tmp, rsi);
|
||||
if (ProfileInterpreter && MethodData::profile_return()) {
|
||||
Label profile_continue, done;
|
||||
|
||||
test_method_data_pointer(mdp, profile_continue);
|
||||
|
||||
if (MethodData::profile_return_jsr292_only()) {
|
||||
// If we don't profile all invoke bytecodes we must make sure
|
||||
// it's a bytecode we indeed profile. We can't go back to the
|
||||
// begining of the ProfileData we intend to update to check its
|
||||
// type because we're right after it and we don't known its
|
||||
// length
|
||||
Label do_profile;
|
||||
cmpb(Address(rsi, 0), Bytecodes::_invokedynamic);
|
||||
jcc(Assembler::equal, do_profile);
|
||||
cmpb(Address(rsi, 0), Bytecodes::_invokehandle);
|
||||
jcc(Assembler::equal, do_profile);
|
||||
get_method(tmp);
|
||||
cmpb(Address(tmp, Method::intrinsic_id_offset_in_bytes()), vmIntrinsics::_compiledLambdaForm);
|
||||
jcc(Assembler::notEqual, profile_continue);
|
||||
|
||||
bind(do_profile);
|
||||
}
|
||||
|
||||
Address mdo_ret_addr(mdp, -in_bytes(ReturnTypeEntry::size()));
|
||||
mov(tmp, ret);
|
||||
profile_obj_type(tmp, mdo_ret_addr);
|
||||
|
||||
bind(profile_continue);
|
||||
}
|
||||
}
|
||||
|
||||
void InterpreterMacroAssembler::profile_call(Register mdp) {
|
||||
if (ProfileInterpreter) {
|
||||
Label profile_continue;
|
||||
|
@ -22,18 +22,6 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CPU_X86_VM_INTERP_MASM_X86_32_HPP
|
||||
#define CPU_X86_VM_INTERP_MASM_X86_32_HPP
|
||||
|
||||
#include "asm/macroAssembler.hpp"
|
||||
#include "asm/macroAssembler.inline.hpp"
|
||||
#include "interpreter/invocationCounter.hpp"
|
||||
#include "runtime/frame.hpp"
|
||||
|
||||
// This file specializes the assember with interpreter-specific macros
|
||||
|
||||
|
||||
class InterpreterMacroAssembler: public MacroAssembler {
|
||||
#ifndef CC_INTERP
|
||||
protected:
|
||||
// Interpreter specific version of call_VM_base
|
||||
@ -59,7 +47,7 @@ class InterpreterMacroAssembler: public MacroAssembler {
|
||||
#endif /* CC_INTERP */
|
||||
|
||||
public:
|
||||
InterpreterMacroAssembler(CodeBuffer* code) : MacroAssembler(code) {}
|
||||
InterpreterMacroAssembler(CodeBuffer* code) : MacroAssembler(code), _locals_register(rdi), _bcp_register(rsi) {}
|
||||
|
||||
void load_earlyret_value(TosState state);
|
||||
|
||||
@ -215,9 +203,6 @@ class InterpreterMacroAssembler: public MacroAssembler {
|
||||
|
||||
void profile_taken_branch(Register mdp, Register bumped_count);
|
||||
void profile_not_taken_branch(Register mdp);
|
||||
void profile_obj_type(Register obj, const Address& mdo_addr);
|
||||
void profile_arguments_type(Register mdp, Register callee, Register tmp, bool is_virtual);
|
||||
void profile_return_type(Register mdp, Register ret, Register tmp);
|
||||
void profile_call(Register mdp);
|
||||
void profile_final_call(Register mdp);
|
||||
void profile_virtual_call(Register receiver, Register mdp, Register scratch2,
|
||||
@ -236,7 +221,3 @@ class InterpreterMacroAssembler: public MacroAssembler {
|
||||
// support for jvmti
|
||||
void notify_method_entry();
|
||||
void notify_method_exit(TosState state, NotifyMethodExitMode mode);
|
||||
|
||||
};
|
||||
|
||||
#endif // CPU_X86_VM_INTERP_MASM_X86_32_HPP
|
||||
|
@ -23,7 +23,7 @@
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "interp_masm_x86_64.hpp"
|
||||
#include "interp_masm_x86.hpp"
|
||||
#include "interpreter/interpreter.hpp"
|
||||
#include "interpreter/interpreterRuntime.hpp"
|
||||
#include "oops/arrayOop.hpp"
|
||||
@ -1067,160 +1067,6 @@ void InterpreterMacroAssembler::profile_not_taken_branch(Register mdp) {
|
||||
}
|
||||
}
|
||||
|
||||
void InterpreterMacroAssembler::profile_obj_type(Register obj, const Address& mdo_addr) {
|
||||
Label update, next, none;
|
||||
|
||||
verify_oop(obj);
|
||||
|
||||
testptr(obj, obj);
|
||||
jccb(Assembler::notZero, update);
|
||||
orptr(mdo_addr, TypeEntries::null_seen);
|
||||
jmpb(next);
|
||||
|
||||
bind(update);
|
||||
load_klass(obj, obj);
|
||||
|
||||
xorptr(obj, mdo_addr);
|
||||
testptr(obj, TypeEntries::type_klass_mask);
|
||||
jccb(Assembler::zero, next); // klass seen before, nothing to
|
||||
// do. The unknown bit may have been
|
||||
// set already but no need to check.
|
||||
|
||||
testptr(obj, TypeEntries::type_unknown);
|
||||
jccb(Assembler::notZero, next); // already unknown. Nothing to do anymore.
|
||||
|
||||
// There is a chance that by the time we do these checks (re-reading
|
||||
// profiling data from memory) another thread has set the profling
|
||||
// to this obj's klass and we set the profiling as unknow
|
||||
// erroneously
|
||||
cmpptr(mdo_addr, 0);
|
||||
jccb(Assembler::equal, none);
|
||||
cmpptr(mdo_addr, TypeEntries::null_seen);
|
||||
jccb(Assembler::equal, none);
|
||||
// There is a chance that the checks above (re-reading profiling
|
||||
// data from memory) fail if another thread has just set the
|
||||
// profiling to this obj's klass
|
||||
xorptr(obj, mdo_addr);
|
||||
testptr(obj, TypeEntries::type_klass_mask);
|
||||
jccb(Assembler::zero, next);
|
||||
|
||||
// different than before. Cannot keep accurate profile.
|
||||
orptr(mdo_addr, TypeEntries::type_unknown);
|
||||
jmpb(next);
|
||||
|
||||
bind(none);
|
||||
// first time here. Set profile type.
|
||||
movptr(mdo_addr, obj);
|
||||
|
||||
bind(next);
|
||||
}
|
||||
|
||||
void InterpreterMacroAssembler::profile_arguments_type(Register mdp, Register callee, Register tmp, bool is_virtual) {
|
||||
if (!ProfileInterpreter) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (MethodData::profile_arguments() || MethodData::profile_return()) {
|
||||
Label profile_continue;
|
||||
|
||||
test_method_data_pointer(mdp, profile_continue);
|
||||
|
||||
int off_to_start = is_virtual ? in_bytes(VirtualCallData::virtual_call_data_size()) : in_bytes(CounterData::counter_data_size());
|
||||
|
||||
cmpb(Address(mdp, in_bytes(DataLayout::tag_offset()) - off_to_start), is_virtual ? DataLayout::virtual_call_type_data_tag : DataLayout::call_type_data_tag);
|
||||
jcc(Assembler::notEqual, profile_continue);
|
||||
|
||||
if (MethodData::profile_arguments()) {
|
||||
Label done;
|
||||
int off_to_args = in_bytes(TypeEntriesAtCall::args_data_offset());
|
||||
addptr(mdp, off_to_args);
|
||||
|
||||
for (int i = 0; i < TypeProfileArgsLimit; i++) {
|
||||
if (i > 0 || MethodData::profile_return()) {
|
||||
// If return value type is profiled we may have no argument to profile
|
||||
movq(tmp, Address(mdp, in_bytes(TypeEntriesAtCall::cell_count_offset())-off_to_args));
|
||||
subl(tmp, i*TypeStackSlotEntries::per_arg_count());
|
||||
cmpl(tmp, TypeStackSlotEntries::per_arg_count());
|
||||
jcc(Assembler::less, done);
|
||||
}
|
||||
movptr(tmp, Address(callee, Method::const_offset()));
|
||||
load_unsigned_short(tmp, Address(tmp, ConstMethod::size_of_parameters_offset()));
|
||||
subq(tmp, Address(mdp, in_bytes(TypeEntriesAtCall::stack_slot_offset(i))-off_to_args));
|
||||
subl(tmp, 1);
|
||||
Address arg_addr = argument_address(tmp);
|
||||
movptr(tmp, arg_addr);
|
||||
|
||||
Address mdo_arg_addr(mdp, in_bytes(TypeEntriesAtCall::argument_type_offset(i))-off_to_args);
|
||||
profile_obj_type(tmp, mdo_arg_addr);
|
||||
|
||||
int to_add = in_bytes(TypeStackSlotEntries::per_arg_size());
|
||||
addptr(mdp, to_add);
|
||||
off_to_args += to_add;
|
||||
}
|
||||
|
||||
if (MethodData::profile_return()) {
|
||||
movq(tmp, Address(mdp, in_bytes(TypeEntriesAtCall::cell_count_offset())-off_to_args));
|
||||
subl(tmp, TypeProfileArgsLimit*TypeStackSlotEntries::per_arg_count());
|
||||
}
|
||||
|
||||
bind(done);
|
||||
|
||||
if (MethodData::profile_return()) {
|
||||
// We're right after the type profile for the last
|
||||
// argument. tmp is the number of cell left in the
|
||||
// CallTypeData/VirtualCallTypeData to reach its end. Non null
|
||||
// if there's a return to profile.
|
||||
assert(ReturnTypeEntry::static_cell_count() < TypeStackSlotEntries::per_arg_count(), "can't move past ret type");
|
||||
shll(tmp, exact_log2(DataLayout::cell_size));
|
||||
addptr(mdp, tmp);
|
||||
}
|
||||
movptr(Address(rbp, frame::interpreter_frame_mdx_offset * wordSize), mdp);
|
||||
} else {
|
||||
assert(MethodData::profile_return(), "either profile call args or call ret");
|
||||
update_mdp_by_constant(mdp, in_bytes(ReturnTypeEntry::size()));
|
||||
}
|
||||
|
||||
// mdp points right after the end of the
|
||||
// CallTypeData/VirtualCallTypeData, right after the cells for the
|
||||
// return value type if there's one
|
||||
|
||||
bind(profile_continue);
|
||||
}
|
||||
}
|
||||
|
||||
void InterpreterMacroAssembler::profile_return_type(Register mdp, Register ret, Register tmp) {
|
||||
assert_different_registers(mdp, ret, tmp, r13);
|
||||
if (ProfileInterpreter && MethodData::profile_return()) {
|
||||
Label profile_continue, done;
|
||||
|
||||
test_method_data_pointer(mdp, profile_continue);
|
||||
|
||||
if (MethodData::profile_return_jsr292_only()) {
|
||||
// If we don't profile all invoke bytecodes we must make sure
|
||||
// it's a bytecode we indeed profile. We can't go back to the
|
||||
// begining of the ProfileData we intend to update to check its
|
||||
// type because we're right after it and we don't known its
|
||||
// length
|
||||
Label do_profile;
|
||||
cmpb(Address(r13, 0), Bytecodes::_invokedynamic);
|
||||
jcc(Assembler::equal, do_profile);
|
||||
cmpb(Address(r13, 0), Bytecodes::_invokehandle);
|
||||
jcc(Assembler::equal, do_profile);
|
||||
get_method(tmp);
|
||||
cmpb(Address(tmp, Method::intrinsic_id_offset_in_bytes()), vmIntrinsics::_compiledLambdaForm);
|
||||
jcc(Assembler::notEqual, profile_continue);
|
||||
|
||||
bind(do_profile);
|
||||
}
|
||||
|
||||
Address mdo_ret_addr(mdp, -in_bytes(ReturnTypeEntry::size()));
|
||||
mov(tmp, ret);
|
||||
profile_obj_type(tmp, mdo_ret_addr);
|
||||
|
||||
bind(profile_continue);
|
||||
}
|
||||
}
|
||||
|
||||
void InterpreterMacroAssembler::profile_call(Register mdp) {
|
||||
if (ProfileInterpreter) {
|
||||
Label profile_continue;
|
||||
|
@ -22,18 +22,6 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CPU_X86_VM_INTERP_MASM_X86_64_HPP
|
||||
#define CPU_X86_VM_INTERP_MASM_X86_64_HPP
|
||||
|
||||
#include "asm/macroAssembler.hpp"
|
||||
#include "asm/macroAssembler.inline.hpp"
|
||||
#include "interpreter/invocationCounter.hpp"
|
||||
#include "runtime/frame.hpp"
|
||||
|
||||
// This file specializes the assember with interpreter-specific macros
|
||||
|
||||
|
||||
class InterpreterMacroAssembler: public MacroAssembler {
|
||||
#ifndef CC_INTERP
|
||||
protected:
|
||||
// Interpreter specific version of call_VM_base
|
||||
@ -55,7 +43,7 @@ class InterpreterMacroAssembler: public MacroAssembler {
|
||||
#endif // CC_INTERP
|
||||
|
||||
public:
|
||||
InterpreterMacroAssembler(CodeBuffer* code) : MacroAssembler(code) {}
|
||||
InterpreterMacroAssembler(CodeBuffer* code) : MacroAssembler(code), _locals_register(r14), _bcp_register(r13) {}
|
||||
|
||||
void load_earlyret_value(TosState state);
|
||||
|
||||
@ -224,9 +212,6 @@ class InterpreterMacroAssembler: public MacroAssembler {
|
||||
|
||||
void profile_taken_branch(Register mdp, Register bumped_count);
|
||||
void profile_not_taken_branch(Register mdp);
|
||||
void profile_obj_type(Register obj, const Address& mdo_addr);
|
||||
void profile_arguments_type(Register mdp, Register callee, Register tmp, bool is_virtual);
|
||||
void profile_return_type(Register mdp, Register ret, Register tmp);
|
||||
void profile_call(Register mdp);
|
||||
void profile_final_call(Register mdp);
|
||||
void profile_virtual_call(Register receiver, Register mdp,
|
||||
@ -253,6 +238,3 @@ class InterpreterMacroAssembler: public MacroAssembler {
|
||||
// support for jvmti/dtrace
|
||||
void notify_method_entry();
|
||||
void notify_method_exit(TosState state, NotifyMethodExitMode mode);
|
||||
};
|
||||
|
||||
#endif // CPU_X86_VM_INTERP_MASM_X86_64_HPP
|
||||
|
@ -26,11 +26,8 @@
|
||||
#include "asm/assembler.hpp"
|
||||
#include "asm/register.hpp"
|
||||
#include "register_x86.hpp"
|
||||
#ifdef TARGET_ARCH_MODEL_x86_32
|
||||
# include "interp_masm_x86_32.hpp"
|
||||
#endif
|
||||
#ifdef TARGET_ARCH_MODEL_x86_64
|
||||
# include "interp_masm_x86_64.hpp"
|
||||
#ifdef TARGET_ARCH_x86
|
||||
# include "interp_masm_x86.hpp"
|
||||
#endif
|
||||
|
||||
REGISTER_DEFINITION(Register, noreg);
|
||||
|
@ -34,9 +34,9 @@
|
||||
// Run with +PrintInterpreter to get the VM to print out the size.
|
||||
// Max size with JVMTI
|
||||
#ifdef AMD64
|
||||
const static int InterpreterCodeSize = 208 * 1024;
|
||||
const static int InterpreterCodeSize = 256 * 1024;
|
||||
#else
|
||||
const static int InterpreterCodeSize = 176 * 1024;
|
||||
const static int InterpreterCodeSize = 224 * 1024;
|
||||
#endif // AMD64
|
||||
|
||||
#endif // CPU_X86_VM_TEMPLATEINTERPRETER_X86_HPP
|
||||
|
@ -1490,6 +1490,7 @@ address InterpreterGenerator::generate_normal_entry(bool synchronized) {
|
||||
in_bytes(JavaThread::do_not_unlock_if_synchronized_offset()));
|
||||
__ movbool(do_not_unlock_if_synchronized, true);
|
||||
|
||||
__ profile_parameters_type(rax, rcx, rdx);
|
||||
// increment invocation count & check for overflow
|
||||
Label invocation_counter_overflow;
|
||||
Label profile_method;
|
||||
|
@ -1497,6 +1497,7 @@ address InterpreterGenerator::generate_normal_entry(bool synchronized) {
|
||||
in_bytes(JavaThread::do_not_unlock_if_synchronized_offset()));
|
||||
__ movbool(do_not_unlock_if_synchronized, true);
|
||||
|
||||
__ profile_parameters_type(rax, rcx, rdx);
|
||||
// increment invocation count & check for overflow
|
||||
Label invocation_counter_overflow;
|
||||
Label profile_method;
|
||||
|
@ -25,7 +25,7 @@
|
||||
#include "precompiled.hpp"
|
||||
#include "asm/macroAssembler.hpp"
|
||||
#include "code/vtableStubs.hpp"
|
||||
#include "interp_masm_x86_32.hpp"
|
||||
#include "interp_masm_x86.hpp"
|
||||
#include "memory/resourceArea.hpp"
|
||||
#include "oops/instanceKlass.hpp"
|
||||
#include "oops/klassVtable.hpp"
|
||||
|
@ -25,7 +25,7 @@
|
||||
#include "precompiled.hpp"
|
||||
#include "asm/macroAssembler.hpp"
|
||||
#include "code/vtableStubs.hpp"
|
||||
#include "interp_masm_x86_64.hpp"
|
||||
#include "interp_masm_x86.hpp"
|
||||
#include "memory/resourceArea.hpp"
|
||||
#include "oops/instanceKlass.hpp"
|
||||
#include "oops/klassVtable.hpp"
|
||||
|
@ -1538,6 +1538,11 @@ const RegMask Matcher::mathExactI_result_proj_mask() {
|
||||
return EAX_REG_mask();
|
||||
}
|
||||
|
||||
const RegMask Matcher::mathExactL_result_proj_mask() {
|
||||
ShouldNotReachHere();
|
||||
return RegMask();
|
||||
}
|
||||
|
||||
const RegMask Matcher::mathExactI_flags_proj_mask() {
|
||||
return INT_FLAGS_mask();
|
||||
}
|
||||
@ -7519,7 +7524,7 @@ instruct cmovL_regUCF(cmpOpUCF cop, eFlagsRegUCF cr, eRegL dst, eRegL src) %{
|
||||
//----------Arithmetic Instructions--------------------------------------------
|
||||
//----------Addition Instructions----------------------------------------------
|
||||
|
||||
instruct addExactI_rReg(eAXRegI dst, rRegI src, eFlagsReg cr)
|
||||
instruct addExactI_eReg(eAXRegI dst, rRegI src, eFlagsReg cr)
|
||||
%{
|
||||
match(AddExactI dst src);
|
||||
effect(DEF cr);
|
||||
@ -7531,7 +7536,7 @@ instruct addExactI_rReg(eAXRegI dst, rRegI src, eFlagsReg cr)
|
||||
ins_pipe(ialu_reg_reg);
|
||||
%}
|
||||
|
||||
instruct addExactI_rReg_imm(eAXRegI dst, immI src, eFlagsReg cr)
|
||||
instruct addExactI_eReg_imm(eAXRegI dst, immI src, eFlagsReg cr)
|
||||
%{
|
||||
match(AddExactI dst src);
|
||||
effect(DEF cr);
|
||||
@ -7543,6 +7548,20 @@ instruct addExactI_rReg_imm(eAXRegI dst, immI src, eFlagsReg cr)
|
||||
ins_pipe(ialu_reg_reg);
|
||||
%}
|
||||
|
||||
instruct addExactI_eReg_mem(eAXRegI dst, memory src, eFlagsReg cr)
|
||||
%{
|
||||
match(AddExactI dst (LoadI src));
|
||||
effect(DEF cr);
|
||||
|
||||
ins_cost(125);
|
||||
format %{ "ADD $dst,$src\t# addExact int" %}
|
||||
ins_encode %{
|
||||
__ addl($dst$$Register, $src$$Address);
|
||||
%}
|
||||
ins_pipe( ialu_reg_mem );
|
||||
%}
|
||||
|
||||
|
||||
// Integer Addition Instructions
|
||||
instruct addI_eReg(rRegI dst, rRegI src, eFlagsReg cr) %{
|
||||
match(Set dst (AddI dst src));
|
||||
@ -7851,6 +7870,44 @@ instruct xchgP( memory mem, pRegP newval) %{
|
||||
%}
|
||||
|
||||
//----------Subtraction Instructions-------------------------------------------
|
||||
|
||||
instruct subExactI_eReg(eAXRegI dst, rRegI src, eFlagsReg cr)
|
||||
%{
|
||||
match(SubExactI dst src);
|
||||
effect(DEF cr);
|
||||
|
||||
format %{ "SUB $dst, $src\t# subExact int" %}
|
||||
ins_encode %{
|
||||
__ subl($dst$$Register, $src$$Register);
|
||||
%}
|
||||
ins_pipe(ialu_reg_reg);
|
||||
%}
|
||||
|
||||
instruct subExactI_eReg_imm(eAXRegI dst, immI src, eFlagsReg cr)
|
||||
%{
|
||||
match(SubExactI dst src);
|
||||
effect(DEF cr);
|
||||
|
||||
format %{ "SUB $dst, $src\t# subExact int" %}
|
||||
ins_encode %{
|
||||
__ subl($dst$$Register, $src$$constant);
|
||||
%}
|
||||
ins_pipe(ialu_reg_reg);
|
||||
%}
|
||||
|
||||
instruct subExactI_eReg_mem(eAXRegI dst, memory src, eFlagsReg cr)
|
||||
%{
|
||||
match(SubExactI dst (LoadI src));
|
||||
effect(DEF cr);
|
||||
|
||||
ins_cost(125);
|
||||
format %{ "SUB $dst,$src\t# subExact int" %}
|
||||
ins_encode %{
|
||||
__ subl($dst$$Register, $src$$Address);
|
||||
%}
|
||||
ins_pipe( ialu_reg_mem );
|
||||
%}
|
||||
|
||||
// Integer Subtraction Instructions
|
||||
instruct subI_eReg(rRegI dst, rRegI src, eFlagsReg cr) %{
|
||||
match(Set dst (SubI dst src));
|
||||
@ -7919,6 +7976,16 @@ instruct negI_eReg(rRegI dst, immI0 zero, eFlagsReg cr) %{
|
||||
ins_pipe( ialu_reg );
|
||||
%}
|
||||
|
||||
instruct negExactI_eReg(eAXRegI dst, eFlagsReg cr) %{
|
||||
match(NegExactI dst);
|
||||
effect(DEF cr);
|
||||
|
||||
format %{ "NEG $dst\t# negExact int"%}
|
||||
ins_encode %{
|
||||
__ negl($dst$$Register);
|
||||
%}
|
||||
ins_pipe(ialu_reg);
|
||||
%}
|
||||
|
||||
//----------Multiplication/Division Instructions-------------------------------
|
||||
// Integer Multiplication Instructions
|
||||
@ -8131,6 +8198,46 @@ instruct mulL_eReg_con(eADXRegL dst, immL_127 src, rRegI tmp, eFlagsReg cr) %{
|
||||
ins_pipe( pipe_slow );
|
||||
%}
|
||||
|
||||
instruct mulExactI_eReg(eAXRegI dst, rRegI src, eFlagsReg cr)
|
||||
%{
|
||||
match(MulExactI dst src);
|
||||
effect(DEF cr);
|
||||
|
||||
ins_cost(300);
|
||||
format %{ "IMUL $dst, $src\t# mulExact int" %}
|
||||
ins_encode %{
|
||||
__ imull($dst$$Register, $src$$Register);
|
||||
%}
|
||||
ins_pipe(ialu_reg_reg_alu0);
|
||||
%}
|
||||
|
||||
instruct mulExactI_eReg_imm(eAXRegI dst, rRegI src, immI imm, eFlagsReg cr)
|
||||
%{
|
||||
match(MulExactI src imm);
|
||||
effect(DEF cr);
|
||||
|
||||
ins_cost(300);
|
||||
format %{ "IMUL $dst, $src, $imm\t# mulExact int" %}
|
||||
ins_encode %{
|
||||
__ imull($dst$$Register, $src$$Register, $imm$$constant);
|
||||
%}
|
||||
ins_pipe(ialu_reg_reg_alu0);
|
||||
%}
|
||||
|
||||
instruct mulExactI_eReg_mem(eAXRegI dst, memory src, eFlagsReg cr)
|
||||
%{
|
||||
match(MulExactI dst (LoadI src));
|
||||
effect(DEF cr);
|
||||
|
||||
ins_cost(350);
|
||||
format %{ "IMUL $dst, $src\t# mulExact int" %}
|
||||
ins_encode %{
|
||||
__ imull($dst$$Register, $src$$Address);
|
||||
%}
|
||||
ins_pipe(ialu_reg_mem_alu0);
|
||||
%}
|
||||
|
||||
|
||||
// Integer DIV with Register
|
||||
instruct divI_eReg(eAXRegI rax, eDXRegI rdx, eCXRegI div, eFlagsReg cr) %{
|
||||
match(Set rax (DivI rax div));
|
||||
|
@ -1653,6 +1653,10 @@ const RegMask Matcher::mathExactI_result_proj_mask() {
|
||||
return INT_RAX_REG_mask();
|
||||
}
|
||||
|
||||
const RegMask Matcher::mathExactL_result_proj_mask() {
|
||||
return LONG_RAX_REG_mask();
|
||||
}
|
||||
|
||||
const RegMask Matcher::mathExactI_flags_proj_mask() {
|
||||
return INT_FLAGS_mask();
|
||||
}
|
||||
@ -6962,6 +6966,58 @@ instruct addExactI_rReg_imm(rax_RegI dst, immI src, rFlagsReg cr)
|
||||
ins_pipe(ialu_reg_reg);
|
||||
%}
|
||||
|
||||
instruct addExactI_rReg_mem(rax_RegI dst, memory src, rFlagsReg cr)
|
||||
%{
|
||||
match(AddExactI dst (LoadI src));
|
||||
effect(DEF cr);
|
||||
|
||||
ins_cost(125); // XXX
|
||||
format %{ "addl $dst, $src\t# addExact int" %}
|
||||
ins_encode %{
|
||||
__ addl($dst$$Register, $src$$Address);
|
||||
%}
|
||||
|
||||
ins_pipe(ialu_reg_mem);
|
||||
%}
|
||||
|
||||
instruct addExactL_rReg(rax_RegL dst, rRegL src, rFlagsReg cr)
|
||||
%{
|
||||
match(AddExactL dst src);
|
||||
effect(DEF cr);
|
||||
|
||||
format %{ "addq $dst, $src\t# addExact long" %}
|
||||
ins_encode %{
|
||||
__ addq($dst$$Register, $src$$Register);
|
||||
%}
|
||||
ins_pipe(ialu_reg_reg);
|
||||
%}
|
||||
|
||||
instruct addExactL_rReg_imm(rax_RegL dst, immL32 src, rFlagsReg cr)
|
||||
%{
|
||||
match(AddExactL dst src);
|
||||
effect(DEF cr);
|
||||
|
||||
format %{ "addq $dst, $src\t# addExact long" %}
|
||||
ins_encode %{
|
||||
__ addq($dst$$Register, $src$$constant);
|
||||
%}
|
||||
ins_pipe(ialu_reg_reg);
|
||||
%}
|
||||
|
||||
instruct addExactL_rReg_mem(rax_RegL dst, memory src, rFlagsReg cr)
|
||||
%{
|
||||
match(AddExactL dst (LoadL src));
|
||||
effect(DEF cr);
|
||||
|
||||
ins_cost(125); // XXX
|
||||
format %{ "addq $dst, $src\t# addExact long" %}
|
||||
ins_encode %{
|
||||
__ addq($dst$$Register, $src$$Address);
|
||||
%}
|
||||
|
||||
ins_pipe(ialu_reg_mem);
|
||||
%}
|
||||
|
||||
instruct addI_rReg(rRegI dst, rRegI src, rFlagsReg cr)
|
||||
%{
|
||||
match(Set dst (AddI dst src));
|
||||
@ -7574,6 +7630,80 @@ instruct subI_mem_imm(memory dst, immI src, rFlagsReg cr)
|
||||
ins_pipe(ialu_mem_imm);
|
||||
%}
|
||||
|
||||
instruct subExactI_rReg(rax_RegI dst, rRegI src, rFlagsReg cr)
|
||||
%{
|
||||
match(SubExactI dst src);
|
||||
effect(DEF cr);
|
||||
|
||||
format %{ "subl $dst, $src\t# subExact int" %}
|
||||
ins_encode %{
|
||||
__ subl($dst$$Register, $src$$Register);
|
||||
%}
|
||||
ins_pipe(ialu_reg_reg);
|
||||
%}
|
||||
|
||||
instruct subExactI_rReg_imm(rax_RegI dst, immI src, rFlagsReg cr)
|
||||
%{
|
||||
match(SubExactI dst src);
|
||||
effect(DEF cr);
|
||||
|
||||
format %{ "subl $dst, $src\t# subExact int" %}
|
||||
ins_encode %{
|
||||
__ subl($dst$$Register, $src$$constant);
|
||||
%}
|
||||
ins_pipe(ialu_reg_reg);
|
||||
%}
|
||||
|
||||
instruct subExactI_rReg_mem(rax_RegI dst, memory src, rFlagsReg cr)
|
||||
%{
|
||||
match(SubExactI dst (LoadI src));
|
||||
effect(DEF cr);
|
||||
|
||||
ins_cost(125);
|
||||
format %{ "subl $dst, $src\t# subExact int" %}
|
||||
ins_encode %{
|
||||
__ subl($dst$$Register, $src$$Address);
|
||||
%}
|
||||
ins_pipe(ialu_reg_mem);
|
||||
%}
|
||||
|
||||
instruct subExactL_rReg(rax_RegL dst, rRegL src, rFlagsReg cr)
|
||||
%{
|
||||
match(SubExactL dst src);
|
||||
effect(DEF cr);
|
||||
|
||||
format %{ "subq $dst, $src\t# subExact long" %}
|
||||
ins_encode %{
|
||||
__ subq($dst$$Register, $src$$Register);
|
||||
%}
|
||||
ins_pipe(ialu_reg_reg);
|
||||
%}
|
||||
|
||||
instruct subExactL_rReg_imm(rax_RegL dst, immL32 src, rFlagsReg cr)
|
||||
%{
|
||||
match(SubExactL dst (LoadL src));
|
||||
effect(DEF cr);
|
||||
|
||||
format %{ "subq $dst, $src\t# subExact long" %}
|
||||
ins_encode %{
|
||||
__ subq($dst$$Register, $src$$constant);
|
||||
%}
|
||||
ins_pipe(ialu_reg_reg);
|
||||
%}
|
||||
|
||||
instruct subExactL_rReg_mem(rax_RegI dst, memory src, rFlagsReg cr)
|
||||
%{
|
||||
match(SubExactI dst src);
|
||||
effect(DEF cr);
|
||||
|
||||
ins_cost(125);
|
||||
format %{ "subq $dst, $src\t# subExact long" %}
|
||||
ins_encode %{
|
||||
__ subq($dst$$Register, $src$$Address);
|
||||
%}
|
||||
ins_pipe(ialu_reg_mem);
|
||||
%}
|
||||
|
||||
instruct subL_rReg(rRegL dst, rRegL src, rFlagsReg cr)
|
||||
%{
|
||||
match(Set dst (SubL dst src));
|
||||
@ -7690,6 +7820,30 @@ instruct negL_mem(memory dst, immL0 zero, rFlagsReg cr)
|
||||
ins_pipe(ialu_reg);
|
||||
%}
|
||||
|
||||
instruct negExactI_rReg(rax_RegI dst, rFlagsReg cr)
|
||||
%{
|
||||
match(NegExactI dst);
|
||||
effect(KILL cr);
|
||||
|
||||
format %{ "negl $dst\t# negExact int" %}
|
||||
ins_encode %{
|
||||
__ negl($dst$$Register);
|
||||
%}
|
||||
ins_pipe(ialu_reg);
|
||||
%}
|
||||
|
||||
instruct negExactL_rReg(rax_RegL dst, rFlagsReg cr)
|
||||
%{
|
||||
match(NegExactL dst);
|
||||
effect(KILL cr);
|
||||
|
||||
format %{ "negq $dst\t# negExact long" %}
|
||||
ins_encode %{
|
||||
__ negq($dst$$Register);
|
||||
%}
|
||||
ins_pipe(ialu_reg);
|
||||
%}
|
||||
|
||||
|
||||
//----------Multiplication/Division Instructions-------------------------------
|
||||
// Integer Multiplication Instructions
|
||||
@ -7807,6 +7961,86 @@ instruct mulHiL_rReg(rdx_RegL dst, no_rax_RegL src, rax_RegL rax, rFlagsReg cr)
|
||||
ins_pipe(ialu_reg_reg_alu0);
|
||||
%}
|
||||
|
||||
|
||||
instruct mulExactI_rReg(rax_RegI dst, rRegI src, rFlagsReg cr)
|
||||
%{
|
||||
match(MulExactI dst src);
|
||||
effect(DEF cr);
|
||||
|
||||
ins_cost(300);
|
||||
format %{ "imull $dst, $src\t# mulExact int" %}
|
||||
ins_encode %{
|
||||
__ imull($dst$$Register, $src$$Register);
|
||||
%}
|
||||
ins_pipe(ialu_reg_reg_alu0);
|
||||
%}
|
||||
|
||||
|
||||
instruct mulExactI_rReg_imm(rax_RegI dst, rRegI src, immI imm, rFlagsReg cr)
|
||||
%{
|
||||
match(MulExactI src imm);
|
||||
effect(DEF cr);
|
||||
|
||||
ins_cost(300);
|
||||
format %{ "imull $dst, $src, $imm\t# mulExact int" %}
|
||||
ins_encode %{
|
||||
__ imull($dst$$Register, $src$$Register, $imm$$constant);
|
||||
%}
|
||||
ins_pipe(ialu_reg_reg_alu0);
|
||||
%}
|
||||
|
||||
instruct mulExactI_rReg_mem(rax_RegI dst, memory src, rFlagsReg cr)
|
||||
%{
|
||||
match(MulExactI dst (LoadI src));
|
||||
effect(DEF cr);
|
||||
|
||||
ins_cost(350);
|
||||
format %{ "imull $dst, $src\t# mulExact int" %}
|
||||
ins_encode %{
|
||||
__ imull($dst$$Register, $src$$Address);
|
||||
%}
|
||||
ins_pipe(ialu_reg_mem_alu0);
|
||||
%}
|
||||
|
||||
instruct mulExactL_rReg(rax_RegL dst, rRegL src, rFlagsReg cr)
|
||||
%{
|
||||
match(MulExactL dst src);
|
||||
effect(DEF cr);
|
||||
|
||||
ins_cost(300);
|
||||
format %{ "imulq $dst, $src\t# mulExact long" %}
|
||||
ins_encode %{
|
||||
__ imulq($dst$$Register, $src$$Register);
|
||||
%}
|
||||
ins_pipe(ialu_reg_reg_alu0);
|
||||
%}
|
||||
|
||||
instruct mulExactL_rReg_imm(rax_RegL dst, rRegL src, immL32 imm, rFlagsReg cr)
|
||||
%{
|
||||
match(MulExactL src imm);
|
||||
effect(DEF cr);
|
||||
|
||||
ins_cost(300);
|
||||
format %{ "imulq $dst, $src, $imm\t# mulExact long" %}
|
||||
ins_encode %{
|
||||
__ imulq($dst$$Register, $src$$Register, $imm$$constant);
|
||||
%}
|
||||
ins_pipe(ialu_reg_reg_alu0);
|
||||
%}
|
||||
|
||||
instruct mulExactL_rReg_mem(rax_RegL dst, memory src, rFlagsReg cr)
|
||||
%{
|
||||
match(MulExactL dst (LoadL src));
|
||||
effect(DEF cr);
|
||||
|
||||
ins_cost(350);
|
||||
format %{ "imulq $dst, $src\t# mulExact long" %}
|
||||
ins_encode %{
|
||||
__ imulq($dst$$Register, $src$$Address);
|
||||
%}
|
||||
ins_pipe(ialu_reg_mem_alu0);
|
||||
%}
|
||||
|
||||
instruct divI_rReg(rax_RegI rax, rdx_RegI rdx, no_rax_rdx_RegI div,
|
||||
rFlagsReg cr)
|
||||
%{
|
||||
|
@ -1193,6 +1193,13 @@ void ArchDesc::buildMustCloneMap(FILE *fp_hpp, FILE *fp_cpp) {
|
||||
|| strcmp(idealName,"FastLock") == 0
|
||||
|| strcmp(idealName,"FastUnlock") == 0
|
||||
|| strcmp(idealName,"AddExactI") == 0
|
||||
|| strcmp(idealName,"AddExactL") == 0
|
||||
|| strcmp(idealName,"SubExactI") == 0
|
||||
|| strcmp(idealName,"SubExactL") == 0
|
||||
|| strcmp(idealName,"MulExactI") == 0
|
||||
|| strcmp(idealName,"MulExactL") == 0
|
||||
|| strcmp(idealName,"NegExactI") == 0
|
||||
|| strcmp(idealName,"NegExactL") == 0
|
||||
|| strcmp(idealName,"FlagsProj") == 0
|
||||
|| strcmp(idealName,"Bool") == 0
|
||||
|| strcmp(idealName,"Binary") == 0 ) {
|
||||
|
@ -536,12 +536,6 @@ bool InstructForm::rematerialize(FormDict &globals, RegisterForm *registers ) {
|
||||
if( data_type != Form::none )
|
||||
rematerialize = true;
|
||||
|
||||
// Ugly: until a better fix is implemented, disable rematerialization for
|
||||
// negD nodes because they are proved to be problematic.
|
||||
if (is_ideal_negD()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Constants
|
||||
if( _components.count() == 1 && _components[0]->is(Component::USE_DEF) )
|
||||
rematerialize = true;
|
||||
|
@ -238,7 +238,18 @@ class Compilation: public StackObj {
|
||||
return env()->comp_level() == CompLevel_full_profile &&
|
||||
C1UpdateMethodData && C1ProfileCheckcasts;
|
||||
}
|
||||
|
||||
bool profile_parameters() {
|
||||
return env()->comp_level() == CompLevel_full_profile &&
|
||||
C1UpdateMethodData && MethodData::profile_parameters();
|
||||
}
|
||||
bool profile_arguments() {
|
||||
return env()->comp_level() == CompLevel_full_profile &&
|
||||
C1UpdateMethodData && MethodData::profile_arguments();
|
||||
}
|
||||
bool profile_return() {
|
||||
return env()->comp_level() == CompLevel_full_profile &&
|
||||
C1UpdateMethodData && MethodData::profile_return();
|
||||
}
|
||||
// will compilation make optimistic assumptions that might lead to
|
||||
// deoptimization and that the runtime will account for?
|
||||
bool is_optimistic() const {
|
||||
|
@ -1470,7 +1470,7 @@ void GraphBuilder::method_return(Value x) {
|
||||
set_state(state()->caller_state()->copy_for_parsing());
|
||||
if (x != NULL) {
|
||||
state()->push(x->type(), x);
|
||||
if (profile_calls() && MethodData::profile_return() && x->type()->is_object_kind()) {
|
||||
if (profile_return() && x->type()->is_object_kind()) {
|
||||
ciMethod* caller = state()->scope()->method();
|
||||
ciMethodData* md = caller->method_data_or_null();
|
||||
ciProfileData* data = md->bci_to_data(invoke_bci);
|
||||
@ -1672,15 +1672,23 @@ Dependencies* GraphBuilder::dependency_recorder() const {
|
||||
}
|
||||
|
||||
// How many arguments do we want to profile?
|
||||
Values* GraphBuilder::args_list_for_profiling(int& start, bool may_have_receiver) {
|
||||
Values* GraphBuilder::args_list_for_profiling(ciMethod* target, int& start, bool may_have_receiver) {
|
||||
int n = 0;
|
||||
assert(start == 0, "should be initialized");
|
||||
if (MethodData::profile_arguments()) {
|
||||
bool has_receiver = may_have_receiver && Bytecodes::has_receiver(method()->java_code_at_bci(bci()));
|
||||
start = has_receiver ? 1 : 0;
|
||||
if (profile_arguments()) {
|
||||
ciProfileData* data = method()->method_data()->bci_to_data(bci());
|
||||
if (data->is_CallTypeData() || data->is_VirtualCallTypeData()) {
|
||||
n = data->is_CallTypeData() ? data->as_CallTypeData()->number_of_arguments() : data->as_VirtualCallTypeData()->number_of_arguments();
|
||||
bool has_receiver = may_have_receiver && Bytecodes::has_receiver(method()->java_code_at_bci(bci()));
|
||||
start = has_receiver ? 1 : 0;
|
||||
}
|
||||
}
|
||||
// If we are inlining then we need to collect arguments to profile parameters for the target
|
||||
if (profile_parameters() && target != NULL) {
|
||||
if (target->method_data() != NULL && target->method_data()->parameters_type_data() != NULL) {
|
||||
// The receiver is profiled on method entry so it's included in
|
||||
// the number of parameters but here we're only interested in
|
||||
// actual arguments.
|
||||
n = MAX2(n, target->method_data()->parameters_type_data()->number_of_parameters() - start);
|
||||
}
|
||||
}
|
||||
if (n > 0) {
|
||||
@ -1690,9 +1698,9 @@ Values* GraphBuilder::args_list_for_profiling(int& start, bool may_have_receiver
|
||||
}
|
||||
|
||||
// Collect arguments that we want to profile in a list
|
||||
Values* GraphBuilder::collect_args_for_profiling(Values* args, bool may_have_receiver) {
|
||||
Values* GraphBuilder::collect_args_for_profiling(Values* args, ciMethod* target, bool may_have_receiver) {
|
||||
int start = 0;
|
||||
Values* obj_args = args_list_for_profiling(start, may_have_receiver);
|
||||
Values* obj_args = args_list_for_profiling(target, start, may_have_receiver);
|
||||
if (obj_args == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
@ -2006,7 +2014,7 @@ void GraphBuilder::invoke(Bytecodes::Code code) {
|
||||
} else if (exact_target != NULL) {
|
||||
target_klass = exact_target->holder();
|
||||
}
|
||||
profile_call(target, recv, target_klass, collect_args_for_profiling(args, false), false);
|
||||
profile_call(target, recv, target_klass, collect_args_for_profiling(args, NULL, false), false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2021,7 +2029,7 @@ void GraphBuilder::invoke(Bytecodes::Code code) {
|
||||
push(result_type, result);
|
||||
}
|
||||
}
|
||||
if (profile_calls() && MethodData::profile_return() && result_type->is_object_kind()) {
|
||||
if (profile_return() && result_type->is_object_kind()) {
|
||||
profile_return_type(result, target);
|
||||
}
|
||||
}
|
||||
@ -3561,7 +3569,7 @@ bool GraphBuilder::try_inline_intrinsics(ciMethod* callee) {
|
||||
recv = args->at(0);
|
||||
null_check(recv);
|
||||
}
|
||||
profile_call(callee, recv, NULL, collect_args_for_profiling(args, true), true);
|
||||
profile_call(callee, recv, NULL, collect_args_for_profiling(args, callee, true), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3572,7 +3580,7 @@ bool GraphBuilder::try_inline_intrinsics(ciMethod* callee) {
|
||||
Value value = append_split(result);
|
||||
if (result_type != voidType) push(result_type, value);
|
||||
|
||||
if (callee != method() && profile_calls() && MethodData::profile_return() && result_type->is_object_kind()) {
|
||||
if (callee != method() && profile_return() && result_type->is_object_kind()) {
|
||||
profile_return_type(result, callee);
|
||||
}
|
||||
|
||||
@ -3760,6 +3768,7 @@ bool GraphBuilder::try_inline_full(ciMethod* callee, bool holder_known, Bytecode
|
||||
|
||||
// now perform tests that are based on flag settings
|
||||
if (callee->force_inline()) {
|
||||
if (inline_level() > MaxForceInlineLevel) INLINE_BAILOUT("MaxForceInlineLevel");
|
||||
print_inlining(callee, "force inline by annotation");
|
||||
} else if (callee->should_inline()) {
|
||||
print_inlining(callee, "force inline by CompileOracle");
|
||||
@ -3820,7 +3829,7 @@ bool GraphBuilder::try_inline_full(ciMethod* callee, bool holder_known, Bytecode
|
||||
|
||||
if (profile_calls()) {
|
||||
int start = 0;
|
||||
Values* obj_args = args_list_for_profiling(start, has_receiver);
|
||||
Values* obj_args = args_list_for_profiling(callee, start, has_receiver);
|
||||
if (obj_args != NULL) {
|
||||
int s = obj_args->size();
|
||||
// if called through method handle invoke, some arguments may have been popped
|
||||
|
@ -386,9 +386,12 @@ class GraphBuilder VALUE_OBJ_CLASS_SPEC {
|
||||
bool profile_calls() { return _compilation->profile_calls(); }
|
||||
bool profile_inlined_calls() { return _compilation->profile_inlined_calls(); }
|
||||
bool profile_checkcasts() { return _compilation->profile_checkcasts(); }
|
||||
bool profile_parameters() { return _compilation->profile_parameters(); }
|
||||
bool profile_arguments() { return _compilation->profile_arguments(); }
|
||||
bool profile_return() { return _compilation->profile_return(); }
|
||||
|
||||
Values* args_list_for_profiling(int& start, bool may_have_receiver);
|
||||
Values* collect_args_for_profiling(Values* args, bool may_have_receiver);
|
||||
Values* args_list_for_profiling(ciMethod* target, int& start, bool may_have_receiver);
|
||||
Values* collect_args_for_profiling(Values* args, ciMethod* target, bool may_have_receiver);
|
||||
|
||||
public:
|
||||
NOT_PRODUCT(void print_stats();)
|
||||
|
@ -183,10 +183,10 @@ char LIR_OprDesc::type_char(BasicType t) {
|
||||
case T_LONG:
|
||||
case T_OBJECT:
|
||||
case T_ADDRESS:
|
||||
case T_METADATA:
|
||||
case T_VOID:
|
||||
return ::type2char(t);
|
||||
|
||||
case T_METADATA:
|
||||
return 'M';
|
||||
case T_ILLEGAL:
|
||||
return '?';
|
||||
|
||||
|
@ -1175,7 +1175,7 @@ void LIRGenerator::do_Return(Return* x) {
|
||||
if (compilation()->env()->dtrace_method_probes()) {
|
||||
BasicTypeList signature;
|
||||
signature.append(LP64_ONLY(T_LONG) NOT_LP64(T_INT)); // thread
|
||||
signature.append(T_OBJECT); // Method*
|
||||
signature.append(T_METADATA); // Method*
|
||||
LIR_OprList* args = new LIR_OprList();
|
||||
args->append(getThreadPointer());
|
||||
LIR_Opr meth = new_register(T_METADATA);
|
||||
@ -1265,6 +1265,7 @@ void LIRGenerator::do_getClass(Intrinsic* x) {
|
||||
|
||||
LIRItem rcvr(x->argument_at(0), this);
|
||||
rcvr.load_item();
|
||||
LIR_Opr temp = new_register(T_METADATA);
|
||||
LIR_Opr result = rlock_result(x);
|
||||
|
||||
// need to perform the null check on the rcvr
|
||||
@ -1272,8 +1273,11 @@ void LIRGenerator::do_getClass(Intrinsic* x) {
|
||||
if (x->needs_null_check()) {
|
||||
info = state_for(x);
|
||||
}
|
||||
__ move(new LIR_Address(rcvr.result(), oopDesc::klass_offset_in_bytes(), T_ADDRESS), result, info);
|
||||
__ move_wide(new LIR_Address(result, in_bytes(Klass::java_mirror_offset()), T_OBJECT), result);
|
||||
|
||||
// FIXME T_ADDRESS should actually be T_METADATA but it can't because the
|
||||
// meaning of these two is mixed up (see JDK-8026837).
|
||||
__ move(new LIR_Address(rcvr.result(), oopDesc::klass_offset_in_bytes(), T_ADDRESS), temp, info);
|
||||
__ move_wide(new LIR_Address(temp, in_bytes(Klass::java_mirror_offset()), T_OBJECT), result);
|
||||
}
|
||||
|
||||
|
||||
@ -2643,6 +2647,39 @@ ciKlass* LIRGenerator::profile_arg_type(ciMethodData* md, int md_base_offset, in
|
||||
return result;
|
||||
}
|
||||
|
||||
// profile parameters on entry to the root of the compilation
|
||||
void LIRGenerator::profile_parameters(Base* x) {
|
||||
if (compilation()->profile_parameters()) {
|
||||
CallingConvention* args = compilation()->frame_map()->incoming_arguments();
|
||||
ciMethodData* md = scope()->method()->method_data_or_null();
|
||||
assert(md != NULL, "Sanity");
|
||||
|
||||
if (md->parameters_type_data() != NULL) {
|
||||
ciParametersTypeData* parameters_type_data = md->parameters_type_data();
|
||||
ciTypeStackSlotEntries* parameters = parameters_type_data->parameters();
|
||||
LIR_Opr mdp = LIR_OprFact::illegalOpr;
|
||||
for (int java_index = 0, i = 0, j = 0; j < parameters_type_data->number_of_parameters(); i++) {
|
||||
LIR_Opr src = args->at(i);
|
||||
assert(!src->is_illegal(), "check");
|
||||
BasicType t = src->type();
|
||||
if (t == T_OBJECT || t == T_ARRAY) {
|
||||
intptr_t profiled_k = parameters->type(j);
|
||||
Local* local = x->state()->local_at(java_index)->as_Local();
|
||||
ciKlass* exact = profile_arg_type(md, md->byte_offset_of_slot(parameters_type_data, ParametersTypeData::type_offset(0)),
|
||||
in_bytes(ParametersTypeData::type_offset(j)) - in_bytes(ParametersTypeData::type_offset(0)),
|
||||
profiled_k, local, mdp, false, local->declared_type()->as_klass());
|
||||
// If the profile is known statically set it once for all and do not emit any code
|
||||
if (exact != NULL) {
|
||||
md->set_parameter_type(j, exact);
|
||||
}
|
||||
j++;
|
||||
}
|
||||
java_index += type2size[t];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LIRGenerator::do_Base(Base* x) {
|
||||
__ std_entry(LIR_OprFact::illegalOpr);
|
||||
// Emit moves from physical registers / stack slots to virtual registers
|
||||
@ -2683,7 +2720,7 @@ void LIRGenerator::do_Base(Base* x) {
|
||||
if (compilation()->env()->dtrace_method_probes()) {
|
||||
BasicTypeList signature;
|
||||
signature.append(LP64_ONLY(T_LONG) NOT_LP64(T_INT)); // thread
|
||||
signature.append(T_OBJECT); // Method*
|
||||
signature.append(T_METADATA); // Method*
|
||||
LIR_OprList* args = new LIR_OprList();
|
||||
args->append(getThreadPointer());
|
||||
LIR_Opr meth = new_register(T_METADATA);
|
||||
@ -2718,6 +2755,7 @@ void LIRGenerator::do_Base(Base* x) {
|
||||
|
||||
// increment invocation counters if needed
|
||||
if (!method()->is_accessor()) { // Accessors do not have MDOs, so no counting.
|
||||
profile_parameters(x);
|
||||
CodeEmitInfo* info = new CodeEmitInfo(scope()->start()->state()->copy(ValueStack::StateBefore, SynchronizationEntryBCI), NULL, false);
|
||||
increment_invocation_counter(info);
|
||||
}
|
||||
@ -3077,11 +3115,12 @@ void LIRGenerator::do_Intrinsic(Intrinsic* x) {
|
||||
}
|
||||
|
||||
void LIRGenerator::profile_arguments(ProfileCall* x) {
|
||||
if (MethodData::profile_arguments()) {
|
||||
if (compilation()->profile_arguments()) {
|
||||
int bci = x->bci_of_invoke();
|
||||
ciMethodData* md = x->method()->method_data_or_null();
|
||||
ciProfileData* data = md->bci_to_data(bci);
|
||||
if (data->is_CallTypeData() || data->is_VirtualCallTypeData()) {
|
||||
if ((data->is_CallTypeData() && data->as_CallTypeData()->has_arguments()) ||
|
||||
(data->is_VirtualCallTypeData() && data->as_VirtualCallTypeData()->has_arguments())) {
|
||||
ByteSize extra = data->is_CallTypeData() ? CallTypeData::args_data_offset() : VirtualCallTypeData::args_data_offset();
|
||||
int base_offset = md->byte_offset_of_slot(data, extra);
|
||||
LIR_Opr mdp = LIR_OprFact::illegalOpr;
|
||||
@ -3107,6 +3146,71 @@ void LIRGenerator::profile_arguments(ProfileCall* x) {
|
||||
md->set_argument_type(bci, i, exact);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
#ifdef ASSERT
|
||||
Bytecodes::Code code = x->method()->raw_code_at_bci(x->bci_of_invoke());
|
||||
int n = x->nb_profiled_args();
|
||||
assert(MethodData::profile_parameters() && x->inlined() &&
|
||||
((code == Bytecodes::_invokedynamic && n <= 1) || (code == Bytecodes::_invokehandle && n <= 2)),
|
||||
"only at JSR292 bytecodes");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// profile parameters on entry to an inlined method
|
||||
void LIRGenerator::profile_parameters_at_call(ProfileCall* x) {
|
||||
if (compilation()->profile_parameters() && x->inlined()) {
|
||||
ciMethodData* md = x->callee()->method_data_or_null();
|
||||
if (md != NULL) {
|
||||
ciParametersTypeData* parameters_type_data = md->parameters_type_data();
|
||||
if (parameters_type_data != NULL) {
|
||||
ciTypeStackSlotEntries* parameters = parameters_type_data->parameters();
|
||||
LIR_Opr mdp = LIR_OprFact::illegalOpr;
|
||||
bool has_receiver = !x->callee()->is_static();
|
||||
ciSignature* sig = x->callee()->signature();
|
||||
ciSignatureStream sig_stream(sig, has_receiver ? x->callee()->holder() : NULL);
|
||||
int i = 0; // to iterate on the Instructions
|
||||
Value arg = x->recv();
|
||||
bool not_null = false;
|
||||
int bci = x->bci_of_invoke();
|
||||
Bytecodes::Code bc = x->method()->java_code_at_bci(bci);
|
||||
// The first parameter is the receiver so that's what we start
|
||||
// with if it exists. On exception if method handle call to
|
||||
// virtual method has receiver in the args list
|
||||
if (arg == NULL || !Bytecodes::has_receiver(bc)) {
|
||||
i = 1;
|
||||
arg = x->profiled_arg_at(0);
|
||||
not_null = !x->arg_needs_null_check(0);
|
||||
}
|
||||
int k = 0; // to iterate on the profile data
|
||||
for (;;) {
|
||||
intptr_t profiled_k = parameters->type(k);
|
||||
ciKlass* exact = profile_arg_type(md, md->byte_offset_of_slot(parameters_type_data, ParametersTypeData::type_offset(0)),
|
||||
in_bytes(ParametersTypeData::type_offset(k)) - in_bytes(ParametersTypeData::type_offset(0)),
|
||||
profiled_k, arg, mdp, not_null, sig_stream.next_klass());
|
||||
// If the profile is known statically set it once for all and do not emit any code
|
||||
if (exact != NULL) {
|
||||
md->set_parameter_type(k, exact);
|
||||
}
|
||||
k++;
|
||||
if (k >= parameters_type_data->number_of_parameters()) {
|
||||
#ifdef ASSERT
|
||||
int extra = 0;
|
||||
if (MethodData::profile_arguments() && TypeProfileParmsLimit != -1 &&
|
||||
x->nb_profiled_args() >= TypeProfileParmsLimit &&
|
||||
x->recv() != NULL && Bytecodes::has_receiver(bc)) {
|
||||
extra += 1;
|
||||
}
|
||||
assert(i == x->nb_profiled_args() - extra || (TypeProfileParmsLimit != -1 && TypeProfileArgsLimit > TypeProfileParmsLimit), "unused parameters?");
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
arg = x->profiled_arg_at(i);
|
||||
not_null = !x->arg_needs_null_check(i);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3122,6 +3226,11 @@ void LIRGenerator::do_ProfileCall(ProfileCall* x) {
|
||||
profile_arguments(x);
|
||||
}
|
||||
|
||||
// profile parameters on inlined method entry including receiver
|
||||
if (x->recv() != NULL || x->nb_profiled_args() > 0) {
|
||||
profile_parameters_at_call(x);
|
||||
}
|
||||
|
||||
if (x->recv() != NULL) {
|
||||
LIRItem value(x->recv(), this);
|
||||
value.load_item();
|
||||
@ -3222,7 +3331,7 @@ void LIRGenerator::do_RuntimeCall(RuntimeCall* x) {
|
||||
BasicTypeList* signature = new BasicTypeList(x->number_of_arguments());
|
||||
|
||||
if (x->pass_thread()) {
|
||||
signature->append(T_ADDRESS);
|
||||
signature->append(LP64_ONLY(T_LONG) NOT_LP64(T_INT)); // thread
|
||||
args->append(getThreadPointer());
|
||||
}
|
||||
|
||||
|
@ -436,6 +436,8 @@ class LIRGenerator: public InstructionVisitor, public BlockClosure {
|
||||
#endif
|
||||
ciKlass* profile_arg_type(ciMethodData* md, int md_first_offset, int md_offset, intptr_t profiled_k, Value arg, LIR_Opr& mdp, bool not_null, ciKlass* signature_k);
|
||||
void profile_arguments(ProfileCall* x);
|
||||
void profile_parameters(Base* x);
|
||||
void profile_parameters_at_call(ProfileCall* x);
|
||||
|
||||
public:
|
||||
Compilation* compilation() const { return _compilation; }
|
||||
|
@ -75,9 +75,9 @@
|
||||
|
||||
// Map BasicType to spill size in 32-bit words, matching VMReg's notion of words
|
||||
#ifdef _LP64
|
||||
static int type2spill_size[T_CONFLICT+1]={ -1, 0, 0, 0, 1, 1, 1, 2, 1, 1, 1, 2, 2, 2, 0, 1, -1};
|
||||
static int type2spill_size[T_CONFLICT+1]={ -1, 0, 0, 0, 1, 1, 1, 2, 1, 1, 1, 2, 2, 2, 0, 2, 1, 2, 1, -1};
|
||||
#else
|
||||
static int type2spill_size[T_CONFLICT+1]={ -1, 0, 0, 0, 1, 1, 1, 2, 1, 1, 1, 2, 1, 1, 0, 1, -1};
|
||||
static int type2spill_size[T_CONFLICT+1]={ -1, 0, 0, 0, 1, 1, 1, 2, 1, 1, 1, 2, 1, 1, 0, 1, -1, 1, 1, -1};
|
||||
#endif
|
||||
|
||||
|
||||
|
@ -341,6 +341,8 @@
|
||||
diagnostic(bool, C1PatchInvokeDynamic, true, \
|
||||
"Patch invokedynamic appendix not known at compile time") \
|
||||
\
|
||||
develop(intx, MaxForceInlineLevel, 100, \
|
||||
"maximum number of nested @ForceInline calls that are inlined") \
|
||||
\
|
||||
|
||||
|
||||
|
@ -565,6 +565,116 @@ void ciCallProfile::add_receiver(ciKlass* receiver, int receiver_count) {
|
||||
if (_limit < MorphismLimit) _limit++;
|
||||
}
|
||||
|
||||
|
||||
void ciMethod::assert_virtual_call_type_ok(int bci) {
|
||||
assert(java_code_at_bci(bci) == Bytecodes::_invokevirtual ||
|
||||
java_code_at_bci(bci) == Bytecodes::_invokeinterface, err_msg("unexpected bytecode %s", Bytecodes::name(java_code_at_bci(bci))));
|
||||
}
|
||||
|
||||
void ciMethod::assert_call_type_ok(int bci) {
|
||||
assert(java_code_at_bci(bci) == Bytecodes::_invokestatic ||
|
||||
java_code_at_bci(bci) == Bytecodes::_invokespecial ||
|
||||
java_code_at_bci(bci) == Bytecodes::_invokedynamic, err_msg("unexpected bytecode %s", Bytecodes::name(java_code_at_bci(bci))));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether profiling provides a type for the argument i to the
|
||||
* call at bci bci
|
||||
*
|
||||
* @param bci bci of the call
|
||||
* @param i argument number
|
||||
* @return profiled type
|
||||
*
|
||||
* If the profile reports that the argument may be null, return false
|
||||
* at least for now.
|
||||
*/
|
||||
ciKlass* ciMethod::argument_profiled_type(int bci, int i) {
|
||||
if (MethodData::profile_parameters() && method_data() != NULL && method_data()->is_mature()) {
|
||||
ciProfileData* data = method_data()->bci_to_data(bci);
|
||||
if (data != NULL) {
|
||||
if (data->is_VirtualCallTypeData()) {
|
||||
assert_virtual_call_type_ok(bci);
|
||||
ciVirtualCallTypeData* call = (ciVirtualCallTypeData*)data->as_VirtualCallTypeData();
|
||||
if (i >= call->number_of_arguments()) {
|
||||
return NULL;
|
||||
}
|
||||
ciKlass* type = call->valid_argument_type(i);
|
||||
if (type != NULL && !call->argument_maybe_null(i)) {
|
||||
return type;
|
||||
}
|
||||
} else if (data->is_CallTypeData()) {
|
||||
assert_call_type_ok(bci);
|
||||
ciCallTypeData* call = (ciCallTypeData*)data->as_CallTypeData();
|
||||
if (i >= call->number_of_arguments()) {
|
||||
return NULL;
|
||||
}
|
||||
ciKlass* type = call->valid_argument_type(i);
|
||||
if (type != NULL && !call->argument_maybe_null(i)) {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether profiling provides a type for the return value from
|
||||
* the call at bci bci
|
||||
*
|
||||
* @param bci bci of the call
|
||||
* @return profiled type
|
||||
*
|
||||
* If the profile reports that the argument may be null, return false
|
||||
* at least for now.
|
||||
*/
|
||||
ciKlass* ciMethod::return_profiled_type(int bci) {
|
||||
if (MethodData::profile_return() && method_data() != NULL && method_data()->is_mature()) {
|
||||
ciProfileData* data = method_data()->bci_to_data(bci);
|
||||
if (data != NULL) {
|
||||
if (data->is_VirtualCallTypeData()) {
|
||||
assert_virtual_call_type_ok(bci);
|
||||
ciVirtualCallTypeData* call = (ciVirtualCallTypeData*)data->as_VirtualCallTypeData();
|
||||
ciKlass* type = call->valid_return_type();
|
||||
if (type != NULL && !call->return_maybe_null()) {
|
||||
return type;
|
||||
}
|
||||
} else if (data->is_CallTypeData()) {
|
||||
assert_call_type_ok(bci);
|
||||
ciCallTypeData* call = (ciCallTypeData*)data->as_CallTypeData();
|
||||
ciKlass* type = call->valid_return_type();
|
||||
if (type != NULL && !call->return_maybe_null()) {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether profiling provides a type for the parameter i
|
||||
*
|
||||
* @param i parameter number
|
||||
* @return profiled type
|
||||
*
|
||||
* If the profile reports that the argument may be null, return false
|
||||
* at least for now.
|
||||
*/
|
||||
ciKlass* ciMethod::parameter_profiled_type(int i) {
|
||||
if (MethodData::profile_parameters() && method_data() != NULL && method_data()->is_mature()) {
|
||||
ciParametersTypeData* parameters = method_data()->parameters_type_data();
|
||||
if (parameters != NULL && i < parameters->number_of_parameters()) {
|
||||
ciKlass* type = parameters->valid_parameter_type(i);
|
||||
if (type != NULL && !parameters->parameter_maybe_null(i)) {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// ciMethod::find_monomorphic_target
|
||||
//
|
||||
|
@ -117,6 +117,10 @@ class ciMethod : public ciMetadata {
|
||||
*bcp = code;
|
||||
}
|
||||
|
||||
// Check bytecode and profile data collected are compatible
|
||||
void assert_virtual_call_type_ok(int bci);
|
||||
void assert_call_type_ok(int bci);
|
||||
|
||||
public:
|
||||
// Basic method information.
|
||||
ciFlags flags() const { check_is_loaded(); return _flags; }
|
||||
@ -230,6 +234,11 @@ class ciMethod : public ciMetadata {
|
||||
ciCallProfile call_profile_at_bci(int bci);
|
||||
int interpreter_call_site_count(int bci);
|
||||
|
||||
// Does type profiling provide a useful type at this point?
|
||||
ciKlass* argument_profiled_type(int bci, int i);
|
||||
ciKlass* parameter_profiled_type(int i);
|
||||
ciKlass* return_profiled_type(int bci);
|
||||
|
||||
ciField* get_field_at_bci( int bci, bool &will_link);
|
||||
ciMethod* get_method_at_bci(int bci, bool &will_link, ciSignature* *declared_signature);
|
||||
|
||||
|
@ -53,6 +53,7 @@ ciMethodData::ciMethodData(MethodData* md) : ciMetadata(md) {
|
||||
_hint_di = first_di();
|
||||
// Initialize the escape information (to "don't know.");
|
||||
_eflags = _arg_local = _arg_stack = _arg_returned = 0;
|
||||
_parameters = NULL;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
@ -74,6 +75,7 @@ ciMethodData::ciMethodData() : ciMetadata(NULL) {
|
||||
_hint_di = first_di();
|
||||
// Initialize the escape information (to "don't know.");
|
||||
_eflags = _arg_local = _arg_stack = _arg_returned = 0;
|
||||
_parameters = NULL;
|
||||
}
|
||||
|
||||
void ciMethodData::load_data() {
|
||||
@ -108,6 +110,12 @@ void ciMethodData::load_data() {
|
||||
ci_data = next_data(ci_data);
|
||||
data = mdo->next_data(data);
|
||||
}
|
||||
if (mdo->parameters_type_data() != NULL) {
|
||||
_parameters = data_layout_at(mdo->parameters_type_data_di());
|
||||
ciParametersTypeData* parameters = new ciParametersTypeData(_parameters);
|
||||
parameters->translate_from(mdo->parameters_type_data());
|
||||
}
|
||||
|
||||
// Note: Extra data are all BitData, and do not need translation.
|
||||
_current_mileage = MethodData::mileage_of(mdo->method());
|
||||
_invocation_counter = mdo->invocation_count();
|
||||
@ -182,6 +190,8 @@ ciProfileData* ciMethodData::data_at(int data_index) {
|
||||
return new ciCallTypeData(data_layout);
|
||||
case DataLayout::virtual_call_type_data_tag:
|
||||
return new ciVirtualCallTypeData(data_layout);
|
||||
case DataLayout::parameters_type_data_tag:
|
||||
return new ciParametersTypeData(data_layout);
|
||||
};
|
||||
}
|
||||
|
||||
@ -318,6 +328,14 @@ void ciMethodData::set_argument_type(int bci, int i, ciKlass* k) {
|
||||
}
|
||||
}
|
||||
|
||||
void ciMethodData::set_parameter_type(int i, ciKlass* k) {
|
||||
VM_ENTRY_MARK;
|
||||
MethodData* mdo = get_MethodData();
|
||||
if (mdo != NULL) {
|
||||
mdo->parameters_type_data()->set_type(i, k->get_Klass());
|
||||
}
|
||||
}
|
||||
|
||||
void ciMethodData::set_return_type(int bci, ciKlass* k) {
|
||||
VM_ENTRY_MARK;
|
||||
MethodData* mdo = get_MethodData();
|
||||
@ -605,4 +623,9 @@ void ciVirtualCallTypeData::print_data_on(outputStream* st) const {
|
||||
ret()->print_data_on(st);
|
||||
}
|
||||
}
|
||||
|
||||
void ciParametersTypeData::print_data_on(outputStream* st) const {
|
||||
st->print_cr("Parametertypes");
|
||||
parameters()->print_data_on(st);
|
||||
}
|
||||
#endif
|
||||
|
@ -43,6 +43,7 @@ class ciMultiBranchData;
|
||||
class ciArgInfoData;
|
||||
class ciCallTypeData;
|
||||
class ciVirtualCallTypeData;
|
||||
class ciParametersTypeData;
|
||||
|
||||
typedef ProfileData ciProfileData;
|
||||
|
||||
@ -99,6 +100,10 @@ public:
|
||||
return valid_ciklass(type(i));
|
||||
}
|
||||
|
||||
bool maybe_null(int i) const {
|
||||
return was_null_seen(type(i));
|
||||
}
|
||||
|
||||
#ifndef PRODUCT
|
||||
void print_data_on(outputStream* st) const;
|
||||
#endif
|
||||
@ -112,6 +117,10 @@ public:
|
||||
return valid_ciklass(type());
|
||||
}
|
||||
|
||||
bool maybe_null() const {
|
||||
return was_null_seen(type());
|
||||
}
|
||||
|
||||
#ifndef PRODUCT
|
||||
void print_data_on(outputStream* st) const;
|
||||
#endif
|
||||
@ -124,7 +133,7 @@ public:
|
||||
ciTypeStackSlotEntries* args() const { return (ciTypeStackSlotEntries*)CallTypeData::args(); }
|
||||
ciReturnTypeEntry* ret() const { return (ciReturnTypeEntry*)CallTypeData::ret(); }
|
||||
|
||||
void translate_type_data_from(const ProfileData* data) {
|
||||
void translate_from(const ProfileData* data) {
|
||||
if (has_arguments()) {
|
||||
args()->translate_type_data_from(data->as_CallTypeData()->args());
|
||||
}
|
||||
@ -153,6 +162,14 @@ public:
|
||||
return ret()->valid_type();
|
||||
}
|
||||
|
||||
bool argument_maybe_null(int i) const {
|
||||
return args()->maybe_null(i);
|
||||
}
|
||||
|
||||
bool return_maybe_null() const {
|
||||
return ret()->maybe_null();
|
||||
}
|
||||
|
||||
#ifndef PRODUCT
|
||||
void print_data_on(outputStream* st) const;
|
||||
#endif
|
||||
@ -259,6 +276,14 @@ public:
|
||||
return ret()->valid_type();
|
||||
}
|
||||
|
||||
bool argument_maybe_null(int i) const {
|
||||
return args()->maybe_null(i);
|
||||
}
|
||||
|
||||
bool return_maybe_null() const {
|
||||
return ret()->maybe_null();
|
||||
}
|
||||
|
||||
#ifndef PRODUCT
|
||||
void print_data_on(outputStream* st) const;
|
||||
#endif
|
||||
@ -290,6 +315,29 @@ public:
|
||||
ciArgInfoData(DataLayout* layout) : ArgInfoData(layout) {};
|
||||
};
|
||||
|
||||
class ciParametersTypeData : public ParametersTypeData {
|
||||
public:
|
||||
ciParametersTypeData(DataLayout* layout) : ParametersTypeData(layout) {}
|
||||
|
||||
virtual void translate_from(const ProfileData* data) {
|
||||
parameters()->translate_type_data_from(data->as_ParametersTypeData()->parameters());
|
||||
}
|
||||
|
||||
ciTypeStackSlotEntries* parameters() const { return (ciTypeStackSlotEntries*)ParametersTypeData::parameters(); }
|
||||
|
||||
ciKlass* valid_parameter_type(int i) const {
|
||||
return parameters()->valid_type(i);
|
||||
}
|
||||
|
||||
bool parameter_maybe_null(int i) const {
|
||||
return parameters()->maybe_null(i);
|
||||
}
|
||||
|
||||
#ifndef PRODUCT
|
||||
void print_data_on(outputStream* st) const;
|
||||
#endif
|
||||
};
|
||||
|
||||
// ciMethodData
|
||||
//
|
||||
// This class represents a MethodData* in the HotSpot virtual
|
||||
@ -335,6 +383,10 @@ private:
|
||||
// Coherent snapshot of original header.
|
||||
MethodData _orig;
|
||||
|
||||
// Dedicated area dedicated to parameters. Null if no parameter
|
||||
// profiling for this method.
|
||||
DataLayout* _parameters;
|
||||
|
||||
ciMethodData(MethodData* md);
|
||||
ciMethodData();
|
||||
|
||||
@ -403,6 +455,7 @@ public:
|
||||
// If the compiler finds a profiled type that is known statically
|
||||
// for sure, set it in the MethodData
|
||||
void set_argument_type(int bci, int i, ciKlass* k);
|
||||
void set_parameter_type(int i, ciKlass* k);
|
||||
void set_return_type(int bci, ciKlass* k);
|
||||
|
||||
void load_data();
|
||||
@ -467,6 +520,10 @@ public:
|
||||
bool is_arg_returned(int i) const;
|
||||
uint arg_modified(int arg) const;
|
||||
|
||||
ciParametersTypeData* parameters_type_data() const {
|
||||
return _parameters != NULL ? new ciParametersTypeData(_parameters) : NULL;
|
||||
}
|
||||
|
||||
// Code generation helper
|
||||
ByteSize offset_of_slot(ciProfileData* data, ByteSize slot_offset_in_data);
|
||||
int byte_offset_of_slot(ciProfileData* data, ByteSize slot_offset_in_data) { return in_bytes(offset_of_slot(data, slot_offset_in_data)); }
|
||||
|
@ -2360,6 +2360,11 @@ methodHandle SystemDictionary::find_method_handle_invoker(Symbol* name,
|
||||
objArrayHandle appendix_box = oopFactory::new_objArray(SystemDictionary::Object_klass(), 1, CHECK_(empty));
|
||||
assert(appendix_box->obj_at(0) == NULL, "");
|
||||
|
||||
// This should not happen. JDK code should take care of that.
|
||||
if (accessing_klass.is_null() || method_type.is_null()) {
|
||||
THROW_MSG_(vmSymbols::java_lang_InternalError(), "bad invokehandle", empty);
|
||||
}
|
||||
|
||||
// call java.lang.invoke.MethodHandleNatives::linkMethod(... String, MethodType) -> MemberName
|
||||
JavaCallArguments args;
|
||||
args.push_oop(accessing_klass()->java_mirror());
|
||||
@ -2485,6 +2490,9 @@ Handle SystemDictionary::link_method_handle_constant(KlassHandle caller,
|
||||
Handle type;
|
||||
if (signature->utf8_length() > 0 && signature->byte_at(0) == '(') {
|
||||
type = find_method_handle_type(signature, caller, CHECK_(empty));
|
||||
} else if (caller.is_null()) {
|
||||
// This should not happen. JDK code should take care of that.
|
||||
THROW_MSG_(vmSymbols::java_lang_InternalError(), "bad MH constant", empty);
|
||||
} else {
|
||||
ResourceMark rm(THREAD);
|
||||
SignatureStream ss(signature, false);
|
||||
@ -2548,6 +2556,11 @@ methodHandle SystemDictionary::find_dynamic_call_site_invoker(KlassHandle caller
|
||||
Handle method_name = java_lang_String::create_from_symbol(name, CHECK_(empty));
|
||||
Handle method_type = find_method_handle_type(type, caller, CHECK_(empty));
|
||||
|
||||
// This should not happen. JDK code should take care of that.
|
||||
if (caller.is_null() || method_type.is_null()) {
|
||||
THROW_MSG_(vmSymbols::java_lang_InternalError(), "bad invokedynamic", empty);
|
||||
}
|
||||
|
||||
objArrayHandle appendix_box = oopFactory::new_objArray(SystemDictionary::Object_klass(), 1, CHECK_(empty));
|
||||
assert(appendix_box->obj_at(0) == NULL, "");
|
||||
|
||||
|
@ -624,6 +624,7 @@
|
||||
do_class(java_lang_StrictMath, "java/lang/StrictMath") \
|
||||
do_signature(double2_double_signature, "(DD)D") \
|
||||
do_signature(int2_int_signature, "(II)I") \
|
||||
do_signature(long2_long_signature, "(JJ)J") \
|
||||
\
|
||||
/* here are the math names, all together: */ \
|
||||
do_name(abs_name,"abs") do_name(sin_name,"sin") do_name(cos_name,"cos") \
|
||||
@ -632,8 +633,11 @@
|
||||
do_name(exp_name,"exp") do_name(min_name,"min") do_name(max_name,"max") \
|
||||
\
|
||||
do_name(addExact_name,"addExact") \
|
||||
do_name(subtractExact_name,"subtractExact") \
|
||||
do_name(decrementExact_name,"decrementExact") \
|
||||
do_name(incrementExact_name,"incrementExact") \
|
||||
do_name(multiplyExact_name,"multiplyExact") \
|
||||
do_name(negateExact_name,"negateExact") \
|
||||
do_name(subtractExact_name,"subtractExact") \
|
||||
\
|
||||
do_intrinsic(_dabs, java_lang_Math, abs_name, double_double_signature, F_S) \
|
||||
do_intrinsic(_dsin, java_lang_Math, sin_name, double_double_signature, F_S) \
|
||||
@ -647,7 +651,18 @@
|
||||
do_intrinsic(_dexp, java_lang_Math, exp_name, double_double_signature, F_S) \
|
||||
do_intrinsic(_min, java_lang_Math, min_name, int2_int_signature, F_S) \
|
||||
do_intrinsic(_max, java_lang_Math, max_name, int2_int_signature, F_S) \
|
||||
do_intrinsic(_addExact, java_lang_Math, addExact_name, int2_int_signature, F_S) \
|
||||
do_intrinsic(_addExactI, java_lang_Math, addExact_name, int2_int_signature, F_S) \
|
||||
do_intrinsic(_addExactL, java_lang_Math, addExact_name, long2_long_signature, F_S) \
|
||||
do_intrinsic(_decrementExactI, java_lang_Math, decrementExact_name, int_int_signature, F_S) \
|
||||
do_intrinsic(_decrementExactL, java_lang_Math, decrementExact_name, long2_long_signature, F_S) \
|
||||
do_intrinsic(_incrementExactI, java_lang_Math, incrementExact_name, int_int_signature, F_S) \
|
||||
do_intrinsic(_incrementExactL, java_lang_Math, incrementExact_name, long2_long_signature, F_S) \
|
||||
do_intrinsic(_multiplyExactI, java_lang_Math, multiplyExact_name, int2_int_signature, F_S) \
|
||||
do_intrinsic(_multiplyExactL, java_lang_Math, multiplyExact_name, long2_long_signature, F_S) \
|
||||
do_intrinsic(_negateExactI, java_lang_Math, negateExact_name, int_int_signature, F_S) \
|
||||
do_intrinsic(_negateExactL, java_lang_Math, negateExact_name, long_long_signature, F_S) \
|
||||
do_intrinsic(_subtractExactI, java_lang_Math, subtractExact_name, int2_int_signature, F_S) \
|
||||
do_intrinsic(_subtractExactL, java_lang_Math, subtractExact_name, long2_long_signature, F_S) \
|
||||
\
|
||||
do_intrinsic(_floatToRawIntBits, java_lang_Float, floatToRawIntBits_name, float_int_signature, F_S) \
|
||||
do_name( floatToRawIntBits_name, "floatToRawIntBits") \
|
||||
|
@ -1297,13 +1297,6 @@ nmethod* CompileBroker::compile_method(methodHandle method, int osr_bci,
|
||||
method->jmethod_id();
|
||||
}
|
||||
|
||||
// If the compiler is shut off due to code cache getting full
|
||||
// fail out now so blocking compiles dont hang the java thread
|
||||
if (!should_compile_new_jobs()) {
|
||||
CompilationPolicy::policy()->delay_compilation(method());
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// do the compilation
|
||||
if (method->is_native()) {
|
||||
if (!PreferInterpreterNativeStubs || method->is_method_handle_intrinsic()) {
|
||||
@ -1313,11 +1306,22 @@ nmethod* CompileBroker::compile_method(methodHandle method, int osr_bci,
|
||||
MutexLocker locker(MethodCompileQueue_lock, THREAD);
|
||||
compile_id = assign_compile_id(method, standard_entry_bci);
|
||||
}
|
||||
// To properly handle the appendix argument for out-of-line calls we are using a small trampoline that
|
||||
// pops off the appendix argument and jumps to the target (see gen_special_dispatch in SharedRuntime).
|
||||
//
|
||||
// Since normal compiled-to-compiled calls are not able to handle such a thing we MUST generate an adapter
|
||||
// in this case. If we can't generate one and use it we can not execute the out-of-line method handle calls.
|
||||
(void) AdapterHandlerLibrary::create_native_wrapper(method, compile_id);
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
// If the compiler is shut off due to code cache getting full
|
||||
// fail out now so blocking compiles dont hang the java thread
|
||||
if (!should_compile_new_jobs()) {
|
||||
CompilationPolicy::policy()->delay_compilation(method());
|
||||
return NULL;
|
||||
}
|
||||
compile_method_base(method, osr_bci, comp_level, hot_method, hot_count, comment, THREAD);
|
||||
}
|
||||
|
||||
|
@ -30,11 +30,8 @@
|
||||
#include "runtime/thread.inline.hpp"
|
||||
#include "runtime/vmThread.hpp"
|
||||
#include "utilities/top.hpp"
|
||||
#ifdef TARGET_ARCH_MODEL_x86_32
|
||||
# include "interp_masm_x86_32.hpp"
|
||||
#endif
|
||||
#ifdef TARGET_ARCH_MODEL_x86_64
|
||||
# include "interp_masm_x86_64.hpp"
|
||||
#ifdef TARGET_ARCH_x86
|
||||
# include "interp_masm_x86.hpp"
|
||||
#endif
|
||||
#ifdef TARGET_ARCH_MODEL_sparc
|
||||
# include "interp_masm_sparc.hpp"
|
||||
|
@ -28,11 +28,8 @@
|
||||
#include "interpreter/bytecodes.hpp"
|
||||
#include "memory/allocation.hpp"
|
||||
#include "runtime/frame.hpp"
|
||||
#ifdef TARGET_ARCH_MODEL_x86_32
|
||||
# include "interp_masm_x86_32.hpp"
|
||||
#endif
|
||||
#ifdef TARGET_ARCH_MODEL_x86_64
|
||||
# include "interp_masm_x86_64.hpp"
|
||||
#ifdef TARGET_ARCH_x86
|
||||
# include "interp_masm_x86.hpp"
|
||||
#endif
|
||||
#ifdef TARGET_ARCH_MODEL_sparc
|
||||
# include "interp_masm_sparc.hpp"
|
||||
|
@ -41,7 +41,7 @@
|
||||
|
||||
// Some types of data layouts need a length field.
|
||||
bool DataLayout::needs_array_len(u1 tag) {
|
||||
return (tag == multi_branch_data_tag) || (tag == arg_info_data_tag);
|
||||
return (tag == multi_branch_data_tag) || (tag == arg_info_data_tag) || (tag == parameters_type_data_tag);
|
||||
}
|
||||
|
||||
// Perform generic initialization of the data. More specific
|
||||
@ -156,10 +156,13 @@ void JumpData::print_data_on(outputStream* st) const {
|
||||
}
|
||||
#endif // !PRODUCT
|
||||
|
||||
int TypeStackSlotEntries::compute_cell_count(Symbol* signature, int max) {
|
||||
int TypeStackSlotEntries::compute_cell_count(Symbol* signature, bool include_receiver, int max) {
|
||||
// Parameter profiling include the receiver
|
||||
int args_count = include_receiver ? 1 : 0;
|
||||
ResourceMark rm;
|
||||
SignatureStream ss(signature);
|
||||
int args_count = MIN2(ss.reference_parameter_count(), max);
|
||||
args_count += ss.reference_parameter_count();
|
||||
args_count = MIN2(args_count, max);
|
||||
return args_count * per_arg_cell_count;
|
||||
}
|
||||
|
||||
@ -169,7 +172,7 @@ int TypeEntriesAtCall::compute_cell_count(BytecodeStream* stream) {
|
||||
Bytecode_invoke inv(stream->method(), stream->bci());
|
||||
int args_cell = 0;
|
||||
if (arguments_profiling_enabled()) {
|
||||
args_cell = TypeStackSlotEntries::compute_cell_count(inv.signature(), TypeProfileArgsLimit);
|
||||
args_cell = TypeStackSlotEntries::compute_cell_count(inv.signature(), false, TypeProfileArgsLimit);
|
||||
}
|
||||
int ret_cell = 0;
|
||||
if (return_profiling_enabled() && (inv.result_type() == T_OBJECT || inv.result_type() == T_ARRAY)) {
|
||||
@ -212,12 +215,19 @@ public:
|
||||
int off_at(int i) const { return _offsets.at(i); }
|
||||
};
|
||||
|
||||
void TypeStackSlotEntries::post_initialize(Symbol* signature, bool has_receiver) {
|
||||
void TypeStackSlotEntries::post_initialize(Symbol* signature, bool has_receiver, bool include_receiver) {
|
||||
ResourceMark rm;
|
||||
ArgumentOffsetComputer aos(signature, _number_of_entries);
|
||||
int start = 0;
|
||||
// Parameter profiling include the receiver
|
||||
if (include_receiver && has_receiver) {
|
||||
set_stack_slot(0, 0);
|
||||
set_type(0, type_none());
|
||||
start += 1;
|
||||
}
|
||||
ArgumentOffsetComputer aos(signature, _number_of_entries-start);
|
||||
aos.total();
|
||||
for (int i = 0; i < _number_of_entries; i++) {
|
||||
set_stack_slot(i, aos.off_at(i) + (has_receiver ? 1 : 0));
|
||||
for (int i = start; i < _number_of_entries; i++) {
|
||||
set_stack_slot(i, aos.off_at(i-start) + (has_receiver ? 1 : 0));
|
||||
set_type(i, type_none());
|
||||
}
|
||||
}
|
||||
@ -234,7 +244,7 @@ void CallTypeData::post_initialize(BytecodeStream* stream, MethodData* mdo) {
|
||||
assert(count > 0, "room for args type but none found?");
|
||||
check_number_of_arguments(count);
|
||||
#endif
|
||||
_args.post_initialize(inv.signature(), inv.has_receiver());
|
||||
_args.post_initialize(inv.signature(), inv.has_receiver(), false);
|
||||
}
|
||||
|
||||
if (has_return()) {
|
||||
@ -255,7 +265,7 @@ void VirtualCallTypeData::post_initialize(BytecodeStream* stream, MethodData* md
|
||||
assert(count > 0, "room for args type but none found?");
|
||||
check_number_of_arguments(count);
|
||||
#endif
|
||||
_args.post_initialize(inv.signature(), inv.has_receiver());
|
||||
_args.post_initialize(inv.signature(), inv.has_receiver(), false);
|
||||
}
|
||||
|
||||
if (has_return()) {
|
||||
@ -579,6 +589,34 @@ void ArgInfoData::print_data_on(outputStream* st) const {
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
int ParametersTypeData::compute_cell_count(Method* m) {
|
||||
if (!MethodData::profile_parameters_for_method(m)) {
|
||||
return 0;
|
||||
}
|
||||
int max = TypeProfileParmsLimit == -1 ? INT_MAX : TypeProfileParmsLimit;
|
||||
int obj_args = TypeStackSlotEntries::compute_cell_count(m->signature(), !m->is_static(), max);
|
||||
if (obj_args > 0) {
|
||||
return obj_args + 1; // 1 cell for array len
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ParametersTypeData::post_initialize(BytecodeStream* stream, MethodData* mdo) {
|
||||
_parameters.post_initialize(mdo->method()->signature(), !mdo->method()->is_static(), true);
|
||||
}
|
||||
|
||||
bool ParametersTypeData::profiling_enabled() {
|
||||
return MethodData::profile_parameters();
|
||||
}
|
||||
|
||||
#ifndef PRODUCT
|
||||
void ParametersTypeData::print_data_on(outputStream* st) const {
|
||||
st->print("parameter types");
|
||||
_parameters.print_data_on(st);
|
||||
}
|
||||
#endif
|
||||
|
||||
// ==================================================================
|
||||
// MethodData*
|
||||
//
|
||||
@ -741,6 +779,12 @@ int MethodData::compute_allocation_size_in_bytes(methodHandle method) {
|
||||
int arg_size = method->size_of_parameters();
|
||||
object_size += DataLayout::compute_size_in_bytes(arg_size+1);
|
||||
|
||||
// Reserve room for an area of the MDO dedicated to profiling of
|
||||
// parameters
|
||||
int args_cell = ParametersTypeData::compute_cell_count(method());
|
||||
if (args_cell > 0) {
|
||||
object_size += DataLayout::compute_size_in_bytes(args_cell);
|
||||
}
|
||||
return object_size;
|
||||
}
|
||||
|
||||
@ -915,6 +959,8 @@ ProfileData* DataLayout::data_in() {
|
||||
return new CallTypeData(this);
|
||||
case DataLayout::virtual_call_type_data_tag:
|
||||
return new VirtualCallTypeData(this);
|
||||
case DataLayout::parameters_type_data_tag:
|
||||
return new ParametersTypeData(this);
|
||||
};
|
||||
}
|
||||
|
||||
@ -936,6 +982,9 @@ void MethodData::post_initialize(BytecodeStream* stream) {
|
||||
stream->next();
|
||||
data->post_initialize(stream, this);
|
||||
}
|
||||
if (_parameters_type_data_di != -1) {
|
||||
parameters_type_data()->post_initialize(NULL, this);
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize the MethodData* corresponding to a given method.
|
||||
@ -975,7 +1024,23 @@ MethodData::MethodData(methodHandle method, int size, TRAPS) {
|
||||
int arg_size = method->size_of_parameters();
|
||||
dp->initialize(DataLayout::arg_info_data_tag, 0, arg_size+1);
|
||||
|
||||
object_size += extra_size + DataLayout::compute_size_in_bytes(arg_size+1);
|
||||
int arg_data_size = DataLayout::compute_size_in_bytes(arg_size+1);
|
||||
object_size += extra_size + arg_data_size;
|
||||
|
||||
int args_cell = ParametersTypeData::compute_cell_count(method());
|
||||
// If we are profiling parameters, we reserver an area near the end
|
||||
// of the MDO after the slots for bytecodes (because there's no bci
|
||||
// for method entry so they don't fit with the framework for the
|
||||
// profiling of bytecodes). We store the offset within the MDO of
|
||||
// this area (or -1 if no parameter is profiled)
|
||||
if (args_cell > 0) {
|
||||
object_size += DataLayout::compute_size_in_bytes(args_cell);
|
||||
_parameters_type_data_di = data_size + extra_size + arg_data_size;
|
||||
DataLayout *dp = data_layout_at(data_size + extra_size + arg_data_size);
|
||||
dp->initialize(DataLayout::parameters_type_data_tag, 0, args_cell);
|
||||
} else {
|
||||
_parameters_type_data_di = -1;
|
||||
}
|
||||
|
||||
// Set an initial hint. Don't use set_hint_di() because
|
||||
// first_di() may be out of bounds if data_size is 0.
|
||||
@ -1134,6 +1199,9 @@ void MethodData::print_value_on(outputStream* st) const {
|
||||
void MethodData::print_data_on(outputStream* st) const {
|
||||
ResourceMark rm;
|
||||
ProfileData* data = first_data();
|
||||
if (_parameters_type_data_di != -1) {
|
||||
parameters_type_data()->print_data_on(st);
|
||||
}
|
||||
for ( ; is_valid(data); data = next_data(data)) {
|
||||
st->print("%d", dp_to_di(data->dp()));
|
||||
st->fill_to(6);
|
||||
@ -1222,7 +1290,7 @@ bool MethodData::profile_arguments_for_invoke(methodHandle m, int bci) {
|
||||
}
|
||||
|
||||
int MethodData::profile_return_flag() {
|
||||
return TypeProfileLevel / 10;
|
||||
return (TypeProfileLevel % 100) / 10;
|
||||
}
|
||||
|
||||
bool MethodData::profile_return() {
|
||||
@ -1249,3 +1317,32 @@ bool MethodData::profile_return_for_invoke(methodHandle m, int bci) {
|
||||
assert(profile_return_jsr292_only(), "inconsistent");
|
||||
return profile_jsr292(m, bci);
|
||||
}
|
||||
|
||||
int MethodData::profile_parameters_flag() {
|
||||
return TypeProfileLevel / 100;
|
||||
}
|
||||
|
||||
bool MethodData::profile_parameters() {
|
||||
return profile_parameters_flag() > no_type_profile && profile_parameters_flag() <= type_profile_all;
|
||||
}
|
||||
|
||||
bool MethodData::profile_parameters_jsr292_only() {
|
||||
return profile_parameters_flag() == type_profile_jsr292;
|
||||
}
|
||||
|
||||
bool MethodData::profile_all_parameters() {
|
||||
return profile_parameters_flag() == type_profile_all;
|
||||
}
|
||||
|
||||
bool MethodData::profile_parameters_for_method(methodHandle m) {
|
||||
if (!profile_parameters()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (profile_all_parameters()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
assert(profile_parameters_jsr292_only(), "inconsistent");
|
||||
return m->is_compiled_lambda_form();
|
||||
}
|
||||
|
@ -119,7 +119,8 @@ public:
|
||||
multi_branch_data_tag,
|
||||
arg_info_data_tag,
|
||||
call_type_data_tag,
|
||||
virtual_call_type_data_tag
|
||||
virtual_call_type_data_tag,
|
||||
parameters_type_data_tag
|
||||
};
|
||||
|
||||
enum {
|
||||
@ -264,6 +265,7 @@ class BranchData;
|
||||
class ArrayData;
|
||||
class MultiBranchData;
|
||||
class ArgInfoData;
|
||||
class ParametersTypeData;
|
||||
|
||||
// ProfileData
|
||||
//
|
||||
@ -397,6 +399,7 @@ public:
|
||||
virtual bool is_ArgInfoData() const { return false; }
|
||||
virtual bool is_CallTypeData() const { return false; }
|
||||
virtual bool is_VirtualCallTypeData()const { return false; }
|
||||
virtual bool is_ParametersTypeData() const { return false; }
|
||||
|
||||
|
||||
BitData* as_BitData() const {
|
||||
@ -447,6 +450,10 @@ public:
|
||||
assert(is_VirtualCallTypeData(), "wrong type");
|
||||
return is_VirtualCallTypeData() ? (VirtualCallTypeData*)this : NULL;
|
||||
}
|
||||
ParametersTypeData* as_ParametersTypeData() const {
|
||||
assert(is_ParametersTypeData(), "wrong type");
|
||||
return is_ParametersTypeData() ? (ParametersTypeData*)this : NULL;
|
||||
}
|
||||
|
||||
|
||||
// Subclass specific initialization
|
||||
@ -767,9 +774,9 @@ public:
|
||||
TypeStackSlotEntries(int base_off, int nb_entries)
|
||||
: TypeEntries(base_off), _number_of_entries(nb_entries) {}
|
||||
|
||||
static int compute_cell_count(Symbol* signature, int max);
|
||||
static int compute_cell_count(Symbol* signature, bool include_receiver, int max);
|
||||
|
||||
void post_initialize(Symbol* signature, bool has_receiver);
|
||||
void post_initialize(Symbol* signature, bool has_receiver, bool include_receiver);
|
||||
|
||||
// offset of cell for stack slot for entry i within this block of cells for a TypeStackSlotEntries
|
||||
static int stack_slot_local_offset(int i) {
|
||||
@ -946,17 +953,6 @@ private:
|
||||
assert(number_of_arguments() == total, "should be set in DataLayout::initialize");
|
||||
}
|
||||
|
||||
protected:
|
||||
// An entry for a return value takes less space than an entry for an
|
||||
// argument so if the number of cells exceeds the number of cells
|
||||
// needed for an argument, this object contains type information for
|
||||
// at least one argument.
|
||||
bool has_arguments() const {
|
||||
bool res = cell_count_no_header() >= TypeStackSlotEntries::per_arg_count();
|
||||
assert (!res || TypeEntriesAtCall::arguments_profiling_enabled(), "no profiling of arguments");
|
||||
return res;
|
||||
}
|
||||
|
||||
public:
|
||||
CallTypeData(DataLayout* layout) :
|
||||
CounterData(layout),
|
||||
@ -1017,6 +1013,16 @@ public:
|
||||
_ret.set_type(TypeEntries::with_status(k, current));
|
||||
}
|
||||
|
||||
// An entry for a return value takes less space than an entry for an
|
||||
// argument so if the number of cells exceeds the number of cells
|
||||
// needed for an argument, this object contains type information for
|
||||
// at least one argument.
|
||||
bool has_arguments() const {
|
||||
bool res = cell_count_no_header() >= TypeStackSlotEntries::per_arg_count();
|
||||
assert (!res || TypeEntriesAtCall::arguments_profiling_enabled(), "no profiling of arguments");
|
||||
return res;
|
||||
}
|
||||
|
||||
// An entry for a return value takes less space than an entry for an
|
||||
// argument, so if the remainder of the number of cells divided by
|
||||
// the number of cells for an argument is not null, a return value
|
||||
@ -1213,17 +1219,6 @@ private:
|
||||
assert(number_of_arguments() == total, "should be set in DataLayout::initialize");
|
||||
}
|
||||
|
||||
protected:
|
||||
// An entry for a return value takes less space than an entry for an
|
||||
// argument so if the number of cells exceeds the number of cells
|
||||
// needed for an argument, this object contains type information for
|
||||
// at least one argument.
|
||||
bool has_arguments() const {
|
||||
bool res = cell_count_no_header() >= TypeStackSlotEntries::per_arg_count();
|
||||
assert (!res || TypeEntriesAtCall::arguments_profiling_enabled(), "no profiling of arguments");
|
||||
return res;
|
||||
}
|
||||
|
||||
public:
|
||||
VirtualCallTypeData(DataLayout* layout) :
|
||||
VirtualCallData(layout),
|
||||
@ -1294,6 +1289,16 @@ public:
|
||||
return res;
|
||||
}
|
||||
|
||||
// An entry for a return value takes less space than an entry for an
|
||||
// argument so if the number of cells exceeds the number of cells
|
||||
// needed for an argument, this object contains type information for
|
||||
// at least one argument.
|
||||
bool has_arguments() const {
|
||||
bool res = cell_count_no_header() >= TypeStackSlotEntries::per_arg_count();
|
||||
assert (!res || TypeEntriesAtCall::arguments_profiling_enabled(), "no profiling of arguments");
|
||||
return res;
|
||||
}
|
||||
|
||||
// Code generation support
|
||||
static ByteSize args_data_offset() {
|
||||
return cell_offset(VirtualCallData::static_cell_count()) + TypeEntriesAtCall::args_data_offset();
|
||||
@ -1662,6 +1667,75 @@ public:
|
||||
#endif
|
||||
};
|
||||
|
||||
// ParametersTypeData
|
||||
//
|
||||
// A ParametersTypeData is used to access profiling information about
|
||||
// types of parameters to a method
|
||||
class ParametersTypeData : public ArrayData {
|
||||
|
||||
private:
|
||||
TypeStackSlotEntries _parameters;
|
||||
|
||||
static int stack_slot_local_offset(int i) {
|
||||
assert_profiling_enabled();
|
||||
return array_start_off_set + TypeStackSlotEntries::stack_slot_local_offset(i);
|
||||
}
|
||||
|
||||
static int type_local_offset(int i) {
|
||||
assert_profiling_enabled();
|
||||
return array_start_off_set + TypeStackSlotEntries::type_local_offset(i);
|
||||
}
|
||||
|
||||
static bool profiling_enabled();
|
||||
static void assert_profiling_enabled() {
|
||||
assert(profiling_enabled(), "method parameters profiling should be on");
|
||||
}
|
||||
|
||||
public:
|
||||
ParametersTypeData(DataLayout* layout) : ArrayData(layout), _parameters(1, number_of_parameters()) {
|
||||
assert(layout->tag() == DataLayout::parameters_type_data_tag, "wrong type");
|
||||
// Some compilers (VC++) don't want this passed in member initialization list
|
||||
_parameters.set_profile_data(this);
|
||||
}
|
||||
|
||||
static int compute_cell_count(Method* m);
|
||||
|
||||
virtual bool is_ParametersTypeData() const { return true; }
|
||||
|
||||
virtual void post_initialize(BytecodeStream* stream, MethodData* mdo);
|
||||
|
||||
int number_of_parameters() const {
|
||||
return array_len() / TypeStackSlotEntries::per_arg_count();
|
||||
}
|
||||
|
||||
const TypeStackSlotEntries* parameters() const { return &_parameters; }
|
||||
|
||||
uint stack_slot(int i) const {
|
||||
return _parameters.stack_slot(i);
|
||||
}
|
||||
|
||||
void set_type(int i, Klass* k) {
|
||||
intptr_t current = _parameters.type(i);
|
||||
_parameters.set_type(i, TypeEntries::with_status((intptr_t)k, current));
|
||||
}
|
||||
|
||||
virtual void clean_weak_klass_links(BoolObjectClosure* is_alive_closure) {
|
||||
_parameters.clean_weak_klass_links(is_alive_closure);
|
||||
}
|
||||
|
||||
#ifndef PRODUCT
|
||||
virtual void print_data_on(outputStream* st) const;
|
||||
#endif
|
||||
|
||||
static ByteSize stack_slot_offset(int i) {
|
||||
return cell_offset(stack_slot_local_offset(i));
|
||||
}
|
||||
|
||||
static ByteSize type_offset(int i) {
|
||||
return cell_offset(type_local_offset(i));
|
||||
}
|
||||
};
|
||||
|
||||
// MethodData*
|
||||
//
|
||||
// A MethodData* holds information which has been collected about
|
||||
@ -1773,6 +1847,10 @@ private:
|
||||
// Size of _data array in bytes. (Excludes header and extra_data fields.)
|
||||
int _data_size;
|
||||
|
||||
// data index for the area dedicated to parameters. -1 if no
|
||||
// parameter profiling.
|
||||
int _parameters_type_data_di;
|
||||
|
||||
// Beginning of the data entries
|
||||
intptr_t _data[1];
|
||||
|
||||
@ -1842,6 +1920,9 @@ private:
|
||||
static int profile_return_flag();
|
||||
static bool profile_all_return();
|
||||
static bool profile_return_for_invoke(methodHandle m, int bci);
|
||||
static int profile_parameters_flag();
|
||||
static bool profile_parameters_jsr292_only();
|
||||
static bool profile_all_parameters();
|
||||
|
||||
public:
|
||||
static int header_size() {
|
||||
@ -2048,6 +2129,16 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
// Return pointer to area dedicated to parameters in MDO
|
||||
ParametersTypeData* parameters_type_data() const {
|
||||
return _parameters_type_data_di != -1 ? data_layout_at(_parameters_type_data_di)->data_in()->as_ParametersTypeData() : NULL;
|
||||
}
|
||||
|
||||
int parameters_type_data_di() const {
|
||||
assert(_parameters_type_data_di != -1, "no args type data");
|
||||
return _parameters_type_data_di;
|
||||
}
|
||||
|
||||
// Support for code generation
|
||||
static ByteSize data_offset() {
|
||||
return byte_offset_of(MethodData, _data[0]);
|
||||
@ -2060,6 +2151,10 @@ public:
|
||||
return byte_offset_of(MethodData, _backedge_counter);
|
||||
}
|
||||
|
||||
static ByteSize parameters_type_data_di_offset() {
|
||||
return byte_offset_of(MethodData, _parameters_type_data_di);
|
||||
}
|
||||
|
||||
// Deallocation support - no pointer fields to deallocate
|
||||
void deallocate_contents(ClassLoaderData* loader_data) {}
|
||||
|
||||
@ -2083,8 +2178,10 @@ public:
|
||||
void verify_on(outputStream* st);
|
||||
void verify_data_on(outputStream* st);
|
||||
|
||||
static bool profile_parameters_for_method(methodHandle m);
|
||||
static bool profile_arguments();
|
||||
static bool profile_return();
|
||||
static bool profile_parameters();
|
||||
static bool profile_return_jsr292_only();
|
||||
};
|
||||
|
||||
|
@ -638,7 +638,13 @@
|
||||
"Find best control for expensive operations") \
|
||||
\
|
||||
product(bool, UseMathExactIntrinsics, true, \
|
||||
"Enables intrinsification of various java.lang.Math funcitons")
|
||||
"Enables intrinsification of various java.lang.Math functions") \
|
||||
\
|
||||
experimental(bool, ReplaceInParentMaps, false, \
|
||||
"Propagate type improvements in callers of inlinee if possible") \
|
||||
\
|
||||
experimental(bool, UseTypeSpeculation, false, \
|
||||
"Speculatively propagate types from profiles")
|
||||
|
||||
C2_FLAGS(DECLARE_DEVELOPER_FLAG, DECLARE_PD_DEVELOPER_FLAG, DECLARE_PRODUCT_FLAG, DECLARE_PD_PRODUCT_FLAG, DECLARE_DIAGNOSTIC_FLAG, DECLARE_EXPERIMENTAL_FLAG, DECLARE_NOTPRODUCT_FLAG)
|
||||
|
||||
|
@ -63,12 +63,12 @@ public:
|
||||
}
|
||||
|
||||
virtual bool is_parse() const { return true; }
|
||||
virtual JVMState* generate(JVMState* jvms);
|
||||
virtual JVMState* generate(JVMState* jvms, Parse* parent_parser);
|
||||
int is_osr() { return _is_osr; }
|
||||
|
||||
};
|
||||
|
||||
JVMState* ParseGenerator::generate(JVMState* jvms) {
|
||||
JVMState* ParseGenerator::generate(JVMState* jvms, Parse* parent_parser) {
|
||||
Compile* C = Compile::current();
|
||||
|
||||
if (is_osr()) {
|
||||
@ -80,7 +80,7 @@ JVMState* ParseGenerator::generate(JVMState* jvms) {
|
||||
return NULL; // bailing out of the compile; do not try to parse
|
||||
}
|
||||
|
||||
Parse parser(jvms, method(), _expected_uses);
|
||||
Parse parser(jvms, method(), _expected_uses, parent_parser);
|
||||
// Grab signature for matching/allocation
|
||||
#ifdef ASSERT
|
||||
if (parser.tf() != (parser.depth() == 1 ? C->tf() : tf())) {
|
||||
@ -119,12 +119,12 @@ class DirectCallGenerator : public CallGenerator {
|
||||
_separate_io_proj(separate_io_proj)
|
||||
{
|
||||
}
|
||||
virtual JVMState* generate(JVMState* jvms);
|
||||
virtual JVMState* generate(JVMState* jvms, Parse* parent_parser);
|
||||
|
||||
CallStaticJavaNode* call_node() const { return _call_node; }
|
||||
};
|
||||
|
||||
JVMState* DirectCallGenerator::generate(JVMState* jvms) {
|
||||
JVMState* DirectCallGenerator::generate(JVMState* jvms, Parse* parent_parser) {
|
||||
GraphKit kit(jvms);
|
||||
bool is_static = method()->is_static();
|
||||
address target = is_static ? SharedRuntime::get_resolve_static_call_stub()
|
||||
@ -171,10 +171,10 @@ public:
|
||||
vtable_index >= 0, "either invalid or usable");
|
||||
}
|
||||
virtual bool is_virtual() const { return true; }
|
||||
virtual JVMState* generate(JVMState* jvms);
|
||||
virtual JVMState* generate(JVMState* jvms, Parse* parent_parser);
|
||||
};
|
||||
|
||||
JVMState* VirtualCallGenerator::generate(JVMState* jvms) {
|
||||
JVMState* VirtualCallGenerator::generate(JVMState* jvms, Parse* parent_parser) {
|
||||
GraphKit kit(jvms);
|
||||
Node* receiver = kit.argument(0);
|
||||
|
||||
@ -276,7 +276,7 @@ class LateInlineCallGenerator : public DirectCallGenerator {
|
||||
// Convert the CallStaticJava into an inline
|
||||
virtual void do_late_inline();
|
||||
|
||||
virtual JVMState* generate(JVMState* jvms) {
|
||||
virtual JVMState* generate(JVMState* jvms, Parse* parent_parser) {
|
||||
Compile *C = Compile::current();
|
||||
C->print_inlining_skip(this);
|
||||
|
||||
@ -290,7 +290,7 @@ class LateInlineCallGenerator : public DirectCallGenerator {
|
||||
// that the late inlining logic can distinguish between fall
|
||||
// through and exceptional uses of the memory and io projections
|
||||
// as is done for allocations and macro expansion.
|
||||
return DirectCallGenerator::generate(jvms);
|
||||
return DirectCallGenerator::generate(jvms, parent_parser);
|
||||
}
|
||||
|
||||
virtual void print_inlining_late(const char* msg) {
|
||||
@ -389,7 +389,7 @@ void LateInlineCallGenerator::do_late_inline() {
|
||||
}
|
||||
|
||||
// Now perform the inling using the synthesized JVMState
|
||||
JVMState* new_jvms = _inline_cg->generate(jvms);
|
||||
JVMState* new_jvms = _inline_cg->generate(jvms, NULL);
|
||||
if (new_jvms == NULL) return; // no change
|
||||
if (C->failing()) return;
|
||||
|
||||
@ -429,8 +429,8 @@ class LateInlineMHCallGenerator : public LateInlineCallGenerator {
|
||||
|
||||
virtual bool is_mh_late_inline() const { return true; }
|
||||
|
||||
virtual JVMState* generate(JVMState* jvms) {
|
||||
JVMState* new_jvms = LateInlineCallGenerator::generate(jvms);
|
||||
virtual JVMState* generate(JVMState* jvms, Parse* parent_parser) {
|
||||
JVMState* new_jvms = LateInlineCallGenerator::generate(jvms, parent_parser);
|
||||
if (_input_not_const) {
|
||||
// inlining won't be possible so no need to enqueue right now.
|
||||
call_node()->set_generator(this);
|
||||
@ -477,15 +477,17 @@ class LateInlineStringCallGenerator : public LateInlineCallGenerator {
|
||||
LateInlineStringCallGenerator(ciMethod* method, CallGenerator* inline_cg) :
|
||||
LateInlineCallGenerator(method, inline_cg) {}
|
||||
|
||||
virtual JVMState* generate(JVMState* jvms) {
|
||||
virtual JVMState* generate(JVMState* jvms, Parse* parent_parser) {
|
||||
Compile *C = Compile::current();
|
||||
C->print_inlining_skip(this);
|
||||
|
||||
C->add_string_late_inline(this);
|
||||
|
||||
JVMState* new_jvms = DirectCallGenerator::generate(jvms);
|
||||
JVMState* new_jvms = DirectCallGenerator::generate(jvms, parent_parser);
|
||||
return new_jvms;
|
||||
}
|
||||
|
||||
virtual bool is_string_late_inline() const { return true; }
|
||||
};
|
||||
|
||||
CallGenerator* CallGenerator::for_string_late_inline(ciMethod* method, CallGenerator* inline_cg) {
|
||||
@ -498,13 +500,13 @@ class LateInlineBoxingCallGenerator : public LateInlineCallGenerator {
|
||||
LateInlineBoxingCallGenerator(ciMethod* method, CallGenerator* inline_cg) :
|
||||
LateInlineCallGenerator(method, inline_cg) {}
|
||||
|
||||
virtual JVMState* generate(JVMState* jvms) {
|
||||
virtual JVMState* generate(JVMState* jvms, Parse* parent_parser) {
|
||||
Compile *C = Compile::current();
|
||||
C->print_inlining_skip(this);
|
||||
|
||||
C->add_boxing_late_inline(this);
|
||||
|
||||
JVMState* new_jvms = DirectCallGenerator::generate(jvms);
|
||||
JVMState* new_jvms = DirectCallGenerator::generate(jvms, parent_parser);
|
||||
return new_jvms;
|
||||
}
|
||||
};
|
||||
@ -540,7 +542,7 @@ public:
|
||||
virtual bool is_virtual() const { return _is_virtual; }
|
||||
virtual bool is_deferred() const { return true; }
|
||||
|
||||
virtual JVMState* generate(JVMState* jvms);
|
||||
virtual JVMState* generate(JVMState* jvms, Parse* parent_parser);
|
||||
};
|
||||
|
||||
|
||||
@ -550,12 +552,12 @@ CallGenerator* CallGenerator::for_warm_call(WarmCallInfo* ci,
|
||||
return new WarmCallGenerator(ci, if_cold, if_hot);
|
||||
}
|
||||
|
||||
JVMState* WarmCallGenerator::generate(JVMState* jvms) {
|
||||
JVMState* WarmCallGenerator::generate(JVMState* jvms, Parse* parent_parser) {
|
||||
Compile* C = Compile::current();
|
||||
if (C->log() != NULL) {
|
||||
C->log()->elem("warm_call bci='%d'", jvms->bci());
|
||||
}
|
||||
jvms = _if_cold->generate(jvms);
|
||||
jvms = _if_cold->generate(jvms, parent_parser);
|
||||
if (jvms != NULL) {
|
||||
Node* m = jvms->map()->control();
|
||||
if (m->is_CatchProj()) m = m->in(0); else m = C->top();
|
||||
@ -616,7 +618,7 @@ public:
|
||||
virtual bool is_inline() const { return _if_hit->is_inline(); }
|
||||
virtual bool is_deferred() const { return _if_hit->is_deferred(); }
|
||||
|
||||
virtual JVMState* generate(JVMState* jvms);
|
||||
virtual JVMState* generate(JVMState* jvms, Parse* parent_parser);
|
||||
};
|
||||
|
||||
|
||||
@ -628,7 +630,7 @@ CallGenerator* CallGenerator::for_predicted_call(ciKlass* predicted_receiver,
|
||||
}
|
||||
|
||||
|
||||
JVMState* PredictedCallGenerator::generate(JVMState* jvms) {
|
||||
JVMState* PredictedCallGenerator::generate(JVMState* jvms, Parse* parent_parser) {
|
||||
GraphKit kit(jvms);
|
||||
PhaseGVN& gvn = kit.gvn();
|
||||
// We need an explicit receiver null_check before checking its type.
|
||||
@ -656,7 +658,7 @@ JVMState* PredictedCallGenerator::generate(JVMState* jvms) {
|
||||
{ PreserveJVMState pjvms(&kit);
|
||||
kit.set_control(slow_ctl);
|
||||
if (!kit.stopped()) {
|
||||
slow_jvms = _if_missed->generate(kit.sync_jvms());
|
||||
slow_jvms = _if_missed->generate(kit.sync_jvms(), parent_parser);
|
||||
if (kit.failing())
|
||||
return NULL; // might happen because of NodeCountInliningCutoff
|
||||
assert(slow_jvms != NULL, "must be");
|
||||
@ -677,12 +679,12 @@ JVMState* PredictedCallGenerator::generate(JVMState* jvms) {
|
||||
kit.replace_in_map(receiver, exact_receiver);
|
||||
|
||||
// Make the hot call:
|
||||
JVMState* new_jvms = _if_hit->generate(kit.sync_jvms());
|
||||
JVMState* new_jvms = _if_hit->generate(kit.sync_jvms(), parent_parser);
|
||||
if (new_jvms == NULL) {
|
||||
// Inline failed, so make a direct call.
|
||||
assert(_if_hit->is_inline(), "must have been a failed inline");
|
||||
CallGenerator* cg = CallGenerator::for_direct_call(_if_hit->method());
|
||||
new_jvms = cg->generate(kit.sync_jvms());
|
||||
new_jvms = cg->generate(kit.sync_jvms(), parent_parser);
|
||||
}
|
||||
kit.add_exception_states_from(new_jvms);
|
||||
kit.set_jvms(new_jvms);
|
||||
@ -773,7 +775,7 @@ CallGenerator* CallGenerator::for_method_handle_inline(JVMState* jvms, ciMethod*
|
||||
ciMethod* target = oop_ptr->const_oop()->as_method_handle()->get_vmtarget();
|
||||
guarantee(!target->is_method_handle_intrinsic(), "should not happen"); // XXX remove
|
||||
const int vtable_index = Method::invalid_vtable_index;
|
||||
CallGenerator* cg = C->call_generator(target, vtable_index, false, jvms, true, PROB_ALWAYS, true, true);
|
||||
CallGenerator* cg = C->call_generator(target, vtable_index, false, jvms, true, PROB_ALWAYS, NULL, true, true);
|
||||
assert(!cg->is_late_inline() || cg->is_mh_late_inline(), "no late inline here");
|
||||
if (cg != NULL && cg->is_inline())
|
||||
return cg;
|
||||
@ -829,6 +831,7 @@ CallGenerator* CallGenerator::for_method_handle_inline(JVMState* jvms, ciMethod*
|
||||
int vtable_index = Method::invalid_vtable_index;
|
||||
bool call_does_dispatch = false;
|
||||
|
||||
ciKlass* speculative_receiver_type = NULL;
|
||||
if (is_virtual_or_interface) {
|
||||
ciInstanceKlass* klass = target->holder();
|
||||
Node* receiver_node = kit.argument(0);
|
||||
@ -837,9 +840,12 @@ CallGenerator* CallGenerator::for_method_handle_inline(JVMState* jvms, ciMethod*
|
||||
target = C->optimize_virtual_call(caller, jvms->bci(), klass, target, receiver_type,
|
||||
is_virtual,
|
||||
call_does_dispatch, vtable_index); // out-parameters
|
||||
// We lack profiling at this call but type speculation may
|
||||
// provide us with a type
|
||||
speculative_receiver_type = receiver_type->speculative_type();
|
||||
}
|
||||
|
||||
CallGenerator* cg = C->call_generator(target, vtable_index, call_does_dispatch, jvms, true, PROB_ALWAYS, true, true);
|
||||
CallGenerator* cg = C->call_generator(target, vtable_index, call_does_dispatch, jvms, true, PROB_ALWAYS, speculative_receiver_type, true, true);
|
||||
assert(!cg->is_late_inline() || cg->is_mh_late_inline(), "no late inline here");
|
||||
if (cg != NULL && cg->is_inline())
|
||||
return cg;
|
||||
@ -874,7 +880,7 @@ public:
|
||||
virtual bool is_inlined() const { return true; }
|
||||
virtual bool is_intrinsic() const { return true; }
|
||||
|
||||
virtual JVMState* generate(JVMState* jvms);
|
||||
virtual JVMState* generate(JVMState* jvms, Parse* parent_parser);
|
||||
};
|
||||
|
||||
|
||||
@ -884,7 +890,7 @@ CallGenerator* CallGenerator::for_predicted_intrinsic(CallGenerator* intrinsic,
|
||||
}
|
||||
|
||||
|
||||
JVMState* PredictedIntrinsicGenerator::generate(JVMState* jvms) {
|
||||
JVMState* PredictedIntrinsicGenerator::generate(JVMState* jvms, Parse* parent_parser) {
|
||||
GraphKit kit(jvms);
|
||||
PhaseGVN& gvn = kit.gvn();
|
||||
|
||||
@ -904,7 +910,7 @@ JVMState* PredictedIntrinsicGenerator::generate(JVMState* jvms) {
|
||||
PreserveJVMState pjvms(&kit);
|
||||
kit.set_control(slow_ctl);
|
||||
if (!kit.stopped()) {
|
||||
slow_jvms = _cg->generate(kit.sync_jvms());
|
||||
slow_jvms = _cg->generate(kit.sync_jvms(), parent_parser);
|
||||
if (kit.failing())
|
||||
return NULL; // might happen because of NodeCountInliningCutoff
|
||||
assert(slow_jvms != NULL, "must be");
|
||||
@ -922,12 +928,12 @@ JVMState* PredictedIntrinsicGenerator::generate(JVMState* jvms) {
|
||||
}
|
||||
|
||||
// Generate intrinsic code:
|
||||
JVMState* new_jvms = _intrinsic->generate(kit.sync_jvms());
|
||||
JVMState* new_jvms = _intrinsic->generate(kit.sync_jvms(), parent_parser);
|
||||
if (new_jvms == NULL) {
|
||||
// Intrinsic failed, so use slow code or make a direct call.
|
||||
if (slow_map == NULL) {
|
||||
CallGenerator* cg = CallGenerator::for_direct_call(method());
|
||||
new_jvms = cg->generate(kit.sync_jvms());
|
||||
new_jvms = cg->generate(kit.sync_jvms(), parent_parser);
|
||||
} else {
|
||||
kit.set_jvms(slow_jvms);
|
||||
return kit.transfer_exceptions_into_jvms();
|
||||
@ -997,7 +1003,7 @@ public:
|
||||
virtual bool is_virtual() const { ShouldNotReachHere(); return false; }
|
||||
virtual bool is_trap() const { return true; }
|
||||
|
||||
virtual JVMState* generate(JVMState* jvms);
|
||||
virtual JVMState* generate(JVMState* jvms, Parse* parent_parser);
|
||||
};
|
||||
|
||||
|
||||
@ -1009,7 +1015,7 @@ CallGenerator::for_uncommon_trap(ciMethod* m,
|
||||
}
|
||||
|
||||
|
||||
JVMState* UncommonTrapCallGenerator::generate(JVMState* jvms) {
|
||||
JVMState* UncommonTrapCallGenerator::generate(JVMState* jvms, Parse* parent_parser) {
|
||||
GraphKit kit(jvms);
|
||||
// Take the trap with arguments pushed on the stack. (Cf. null_check_receiver).
|
||||
int nargs = method()->arg_size();
|
||||
|
@ -31,6 +31,8 @@
|
||||
#include "opto/type.hpp"
|
||||
#include "runtime/deoptimization.hpp"
|
||||
|
||||
class Parse;
|
||||
|
||||
//---------------------------CallGenerator-------------------------------------
|
||||
// The subclasses of this class handle generation of ideal nodes for
|
||||
// call sites and method entry points.
|
||||
@ -72,6 +74,7 @@ class CallGenerator : public ResourceObj {
|
||||
virtual bool is_late_inline() const { return false; }
|
||||
// same but for method handle calls
|
||||
virtual bool is_mh_late_inline() const { return false; }
|
||||
virtual bool is_string_late_inline() const{ return false; }
|
||||
|
||||
// for method handle calls: have we tried inlinining the call already?
|
||||
virtual bool already_attempted() const { ShouldNotReachHere(); return false; }
|
||||
@ -108,7 +111,7 @@ class CallGenerator : public ResourceObj {
|
||||
//
|
||||
// If the result is NULL, it means that this CallGenerator was unable
|
||||
// to handle the given call, and another CallGenerator should be consulted.
|
||||
virtual JVMState* generate(JVMState* jvms) = 0;
|
||||
virtual JVMState* generate(JVMState* jvms, Parse* parent_parser) = 0;
|
||||
|
||||
// How to generate a call site that is inlined:
|
||||
static CallGenerator* for_inline(ciMethod* m, float expected_uses = -1);
|
||||
|
@ -30,6 +30,7 @@ macro(AbsF)
|
||||
macro(AbsI)
|
||||
macro(AddD)
|
||||
macro(AddExactI)
|
||||
macro(AddExactL)
|
||||
macro(AddF)
|
||||
macro(AddI)
|
||||
macro(AddL)
|
||||
@ -170,6 +171,8 @@ macro(LoopLimit)
|
||||
macro(Mach)
|
||||
macro(MachProj)
|
||||
macro(MathExact)
|
||||
macro(MathExactI)
|
||||
macro(MathExactL)
|
||||
macro(MaxI)
|
||||
macro(MemBarAcquire)
|
||||
macro(MemBarAcquireLock)
|
||||
@ -189,12 +192,16 @@ macro(MoveF2I)
|
||||
macro(MoveL2D)
|
||||
macro(MoveD2L)
|
||||
macro(MulD)
|
||||
macro(MulExactI)
|
||||
macro(MulExactL)
|
||||
macro(MulF)
|
||||
macro(MulHiL)
|
||||
macro(MulI)
|
||||
macro(MulL)
|
||||
macro(Multi)
|
||||
macro(NegD)
|
||||
macro(NegExactI)
|
||||
macro(NegExactL)
|
||||
macro(NegF)
|
||||
macro(NeverBranch)
|
||||
macro(Opaque1)
|
||||
@ -244,6 +251,8 @@ macro(StrComp)
|
||||
macro(StrEquals)
|
||||
macro(StrIndexOf)
|
||||
macro(SubD)
|
||||
macro(SubExactI)
|
||||
macro(SubExactL)
|
||||
macro(SubF)
|
||||
macro(SubI)
|
||||
macro(SubL)
|
||||
|
@ -655,7 +655,8 @@ Compile::Compile( ciEnv* ci_env, C2Compiler* compiler, ciMethod* target, int osr
|
||||
_inlining_progress(false),
|
||||
_inlining_incrementally(false),
|
||||
_print_inlining_list(NULL),
|
||||
_print_inlining_idx(0) {
|
||||
_print_inlining_idx(0),
|
||||
_preserve_jvm_state(0) {
|
||||
C = this;
|
||||
|
||||
CompileWrapper cw(this);
|
||||
@ -763,7 +764,7 @@ Compile::Compile( ciEnv* ci_env, C2Compiler* compiler, ciMethod* target, int osr
|
||||
return;
|
||||
}
|
||||
JVMState* jvms = build_start_state(start(), tf());
|
||||
if ((jvms = cg->generate(jvms)) == NULL) {
|
||||
if ((jvms = cg->generate(jvms, NULL)) == NULL) {
|
||||
record_method_not_compilable("method parse failed");
|
||||
return;
|
||||
}
|
||||
@ -940,7 +941,8 @@ Compile::Compile( ciEnv* ci_env,
|
||||
_inlining_progress(false),
|
||||
_inlining_incrementally(false),
|
||||
_print_inlining_list(NULL),
|
||||
_print_inlining_idx(0) {
|
||||
_print_inlining_idx(0),
|
||||
_preserve_jvm_state(0) {
|
||||
C = this;
|
||||
|
||||
#ifndef PRODUCT
|
||||
@ -1358,7 +1360,7 @@ const TypePtr *Compile::flatten_alias_type( const TypePtr *tj ) const {
|
||||
// During the 2nd round of IterGVN, NotNull castings are removed.
|
||||
// Make sure the Bottom and NotNull variants alias the same.
|
||||
// Also, make sure exact and non-exact variants alias the same.
|
||||
if( ptr == TypePtr::NotNull || ta->klass_is_exact() ) {
|
||||
if (ptr == TypePtr::NotNull || ta->klass_is_exact() || ta->speculative() != NULL) {
|
||||
tj = ta = TypeAryPtr::make(TypePtr::BotPTR,ta->ary(),ta->klass(),false,offset);
|
||||
}
|
||||
}
|
||||
@ -1383,6 +1385,9 @@ const TypePtr *Compile::flatten_alias_type( const TypePtr *tj ) const {
|
||||
// Also, make sure exact and non-exact variants alias the same.
|
||||
tj = to = TypeInstPtr::make(TypePtr::BotPTR,to->klass(),false,0,offset);
|
||||
}
|
||||
if (to->speculative() != NULL) {
|
||||
tj = to = TypeInstPtr::make(to->ptr(),to->klass(),to->klass_is_exact(),to->const_oop(),to->offset(), to->instance_id());
|
||||
}
|
||||
// Canonicalize the holder of this field
|
||||
if (offset >= 0 && offset < instanceOopDesc::base_offset_in_bytes()) {
|
||||
// First handle header references such as a LoadKlassNode, even if the
|
||||
@ -2011,6 +2016,12 @@ void Compile::Optimize() {
|
||||
if (failing()) return;
|
||||
}
|
||||
|
||||
// Remove the speculative part of types and clean up the graph from
|
||||
// the extra CastPP nodes whose only purpose is to carry them. Do
|
||||
// that early so that optimizations are not disrupted by the extra
|
||||
// CastPP nodes.
|
||||
remove_speculative_types(igvn);
|
||||
|
||||
// No more new expensive nodes will be added to the list from here
|
||||
// so keep only the actual candidates for optimizations.
|
||||
cleanup_expensive_nodes(igvn);
|
||||
@ -3004,10 +3015,15 @@ void Compile::final_graph_reshaping_impl( Node *n, Final_Reshape_Counts &frc) {
|
||||
if (result != NULL) {
|
||||
for (DUIterator_Fast jmax, j = result->fast_outs(jmax); j < jmax; j++) {
|
||||
Node* out = result->fast_out(j);
|
||||
if (out->in(0) == NULL) {
|
||||
out->set_req(0, non_throwing);
|
||||
} else if (out->in(0) == ctrl) {
|
||||
out->set_req(0, non_throwing);
|
||||
// Phi nodes shouldn't be moved. They would only match below if they
|
||||
// had the same control as the MathExactNode. The only time that
|
||||
// would happen is if the Phi is also an input to the MathExact
|
||||
if (!out->is_Phi()) {
|
||||
if (out->in(0) == NULL) {
|
||||
out->set_req(0, non_throwing);
|
||||
} else if (out->in(0) == ctrl) {
|
||||
out->set_req(0, non_throwing);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3792,6 +3808,45 @@ void Compile::add_expensive_node(Node * n) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the speculative part of types and clean up the graph
|
||||
*/
|
||||
void Compile::remove_speculative_types(PhaseIterGVN &igvn) {
|
||||
if (UseTypeSpeculation) {
|
||||
Unique_Node_List worklist;
|
||||
worklist.push(root());
|
||||
int modified = 0;
|
||||
// Go over all type nodes that carry a speculative type, drop the
|
||||
// speculative part of the type and enqueue the node for an igvn
|
||||
// which may optimize it out.
|
||||
for (uint next = 0; next < worklist.size(); ++next) {
|
||||
Node *n = worklist.at(next);
|
||||
if (n->is_Type() && n->as_Type()->type()->isa_oopptr() != NULL &&
|
||||
n->as_Type()->type()->is_oopptr()->speculative() != NULL) {
|
||||
TypeNode* tn = n->as_Type();
|
||||
const TypeOopPtr* t = tn->type()->is_oopptr();
|
||||
bool in_hash = igvn.hash_delete(n);
|
||||
assert(in_hash, "node should be in igvn hash table");
|
||||
tn->set_type(t->remove_speculative());
|
||||
igvn.hash_insert(n);
|
||||
igvn._worklist.push(n); // give it a chance to go away
|
||||
modified++;
|
||||
}
|
||||
uint max = n->len();
|
||||
for( uint i = 0; i < max; ++i ) {
|
||||
Node *m = n->in(i);
|
||||
if (not_a_node(m)) continue;
|
||||
worklist.push(m);
|
||||
}
|
||||
}
|
||||
// Drop the speculative part of all types in the igvn's type table
|
||||
igvn.remove_speculative_types();
|
||||
if (modified > 0) {
|
||||
igvn.optimize();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Auxiliary method to support randomized stressing/fuzzing.
|
||||
//
|
||||
// This method can be called the arbitrary number of times, with current count
|
||||
|
@ -424,6 +424,11 @@ class Compile : public Phase {
|
||||
static int cmp_expensive_nodes(Node** n1, Node** n2);
|
||||
// Expensive nodes list already sorted?
|
||||
bool expensive_nodes_sorted() const;
|
||||
// Remove the speculative part of types and clean up the graph
|
||||
void remove_speculative_types(PhaseIterGVN &igvn);
|
||||
|
||||
// Are we within a PreserveJVMState block?
|
||||
int _preserve_jvm_state;
|
||||
|
||||
public:
|
||||
|
||||
@ -820,7 +825,9 @@ class Compile : public Phase {
|
||||
|
||||
// Decide how to build a call.
|
||||
// The profile factor is a discount to apply to this site's interp. profile.
|
||||
CallGenerator* call_generator(ciMethod* call_method, int vtable_index, bool call_does_dispatch, JVMState* jvms, bool allow_inline, float profile_factor, bool allow_intrinsics = true, bool delayed_forbidden = false);
|
||||
CallGenerator* call_generator(ciMethod* call_method, int vtable_index, bool call_does_dispatch,
|
||||
JVMState* jvms, bool allow_inline, float profile_factor, ciKlass* speculative_receiver_type = NULL,
|
||||
bool allow_intrinsics = true, bool delayed_forbidden = false);
|
||||
bool should_delay_inlining(ciMethod* call_method, JVMState* jvms) {
|
||||
return should_delay_string_inlining(call_method, jvms) ||
|
||||
should_delay_boxing_inlining(call_method, jvms);
|
||||
@ -1156,6 +1163,21 @@ class Compile : public Phase {
|
||||
|
||||
// Auxiliary method for randomized fuzzing/stressing
|
||||
static bool randomized_select(int count);
|
||||
|
||||
// enter a PreserveJVMState block
|
||||
void inc_preserve_jvm_state() {
|
||||
_preserve_jvm_state++;
|
||||
}
|
||||
|
||||
// exit a PreserveJVMState block
|
||||
void dec_preserve_jvm_state() {
|
||||
_preserve_jvm_state--;
|
||||
assert(_preserve_jvm_state >= 0, "_preserve_jvm_state shouldn't be negative");
|
||||
}
|
||||
|
||||
bool has_preserve_jvm_state() const {
|
||||
return _preserve_jvm_state > 0;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // SHARE_VM_OPTO_COMPILE_HPP
|
||||
|
@ -63,7 +63,8 @@ void trace_type_profile(Compile* C, ciMethod *method, int depth, int bci, ciMeth
|
||||
|
||||
CallGenerator* Compile::call_generator(ciMethod* callee, int vtable_index, bool call_does_dispatch,
|
||||
JVMState* jvms, bool allow_inline,
|
||||
float prof_factor, bool allow_intrinsics, bool delayed_forbidden) {
|
||||
float prof_factor, ciKlass* speculative_receiver_type,
|
||||
bool allow_intrinsics, bool delayed_forbidden) {
|
||||
ciMethod* caller = jvms->method();
|
||||
int bci = jvms->bci();
|
||||
Bytecodes::Code bytecode = caller->java_code_at_bci(bci);
|
||||
@ -117,7 +118,7 @@ CallGenerator* Compile::call_generator(ciMethod* callee, int vtable_index, bool
|
||||
if (cg->is_predicted()) {
|
||||
// Code without intrinsic but, hopefully, inlined.
|
||||
CallGenerator* inline_cg = this->call_generator(callee,
|
||||
vtable_index, call_does_dispatch, jvms, allow_inline, prof_factor, false);
|
||||
vtable_index, call_does_dispatch, jvms, allow_inline, prof_factor, speculative_receiver_type, false);
|
||||
if (inline_cg != NULL) {
|
||||
cg = CallGenerator::for_predicted_intrinsic(cg, inline_cg);
|
||||
}
|
||||
@ -212,8 +213,24 @@ CallGenerator* Compile::call_generator(ciMethod* callee, int vtable_index, bool
|
||||
// The major receiver's count >= TypeProfileMajorReceiverPercent of site_count.
|
||||
bool have_major_receiver = (100.*profile.receiver_prob(0) >= (float)TypeProfileMajorReceiverPercent);
|
||||
ciMethod* receiver_method = NULL;
|
||||
if (have_major_receiver || profile.morphism() == 1 ||
|
||||
(profile.morphism() == 2 && UseBimorphicInlining)) {
|
||||
|
||||
int morphism = profile.morphism();
|
||||
if (speculative_receiver_type != NULL) {
|
||||
// We have a speculative type, we should be able to resolve
|
||||
// the call. We do that before looking at the profiling at
|
||||
// this invoke because it may lead to bimorphic inlining which
|
||||
// a speculative type should help us avoid.
|
||||
receiver_method = callee->resolve_invoke(jvms->method()->holder(),
|
||||
speculative_receiver_type);
|
||||
if (receiver_method == NULL) {
|
||||
speculative_receiver_type = NULL;
|
||||
} else {
|
||||
morphism = 1;
|
||||
}
|
||||
}
|
||||
if (receiver_method == NULL &&
|
||||
(have_major_receiver || morphism == 1 ||
|
||||
(morphism == 2 && UseBimorphicInlining))) {
|
||||
// receiver_method = profile.method();
|
||||
// Profiles do not suggest methods now. Look it up in the major receiver.
|
||||
receiver_method = callee->resolve_invoke(jvms->method()->holder(),
|
||||
@ -227,7 +244,7 @@ CallGenerator* Compile::call_generator(ciMethod* callee, int vtable_index, bool
|
||||
// Look up second receiver.
|
||||
CallGenerator* next_hit_cg = NULL;
|
||||
ciMethod* next_receiver_method = NULL;
|
||||
if (profile.morphism() == 2 && UseBimorphicInlining) {
|
||||
if (morphism == 2 && UseBimorphicInlining) {
|
||||
next_receiver_method = callee->resolve_invoke(jvms->method()->holder(),
|
||||
profile.receiver(1));
|
||||
if (next_receiver_method != NULL) {
|
||||
@ -242,11 +259,10 @@ CallGenerator* Compile::call_generator(ciMethod* callee, int vtable_index, bool
|
||||
}
|
||||
}
|
||||
CallGenerator* miss_cg;
|
||||
Deoptimization::DeoptReason reason = (profile.morphism() == 2) ?
|
||||
Deoptimization::DeoptReason reason = morphism == 2 ?
|
||||
Deoptimization::Reason_bimorphic :
|
||||
Deoptimization::Reason_class_check;
|
||||
if (( profile.morphism() == 1 ||
|
||||
(profile.morphism() == 2 && next_hit_cg != NULL) ) &&
|
||||
if ((morphism == 1 || (morphism == 2 && next_hit_cg != NULL)) &&
|
||||
!too_many_traps(jvms->method(), jvms->bci(), reason)
|
||||
) {
|
||||
// Generate uncommon trap for class check failure path
|
||||
@ -260,6 +276,7 @@ CallGenerator* Compile::call_generator(ciMethod* callee, int vtable_index, bool
|
||||
}
|
||||
if (miss_cg != NULL) {
|
||||
if (next_hit_cg != NULL) {
|
||||
assert(speculative_receiver_type == NULL, "shouldn't end up here if we used speculation");
|
||||
trace_type_profile(C, jvms->method(), jvms->depth() - 1, jvms->bci(), next_receiver_method, profile.receiver(1), site_count, profile.receiver_count(1));
|
||||
// We don't need to record dependency on a receiver here and below.
|
||||
// Whenever we inline, the dependency is added by Parse::Parse().
|
||||
@ -267,7 +284,9 @@ CallGenerator* Compile::call_generator(ciMethod* callee, int vtable_index, bool
|
||||
}
|
||||
if (miss_cg != NULL) {
|
||||
trace_type_profile(C, jvms->method(), jvms->depth() - 1, jvms->bci(), receiver_method, profile.receiver(0), site_count, receiver_count);
|
||||
CallGenerator* cg = CallGenerator::for_predicted_call(profile.receiver(0), miss_cg, hit_cg, profile.receiver_prob(0));
|
||||
ciKlass* k = speculative_receiver_type != NULL ? speculative_receiver_type : profile.receiver(0);
|
||||
float hit_prob = speculative_receiver_type != NULL ? 1.0 : profile.receiver_prob(0);
|
||||
CallGenerator* cg = CallGenerator::for_predicted_call(k, miss_cg, hit_cg, hit_prob);
|
||||
if (cg != NULL) return cg;
|
||||
}
|
||||
}
|
||||
@ -446,13 +465,16 @@ void Parse::do_call() {
|
||||
int vtable_index = Method::invalid_vtable_index;
|
||||
bool call_does_dispatch = false;
|
||||
|
||||
// Speculative type of the receiver if any
|
||||
ciKlass* speculative_receiver_type = NULL;
|
||||
if (is_virtual_or_interface) {
|
||||
Node* receiver_node = stack(sp() - nargs);
|
||||
Node* receiver_node = stack(sp() - nargs);
|
||||
const TypeOopPtr* receiver_type = _gvn.type(receiver_node)->isa_oopptr();
|
||||
// call_does_dispatch and vtable_index are out-parameters. They might be changed.
|
||||
callee = C->optimize_virtual_call(method(), bci(), klass, orig_callee, receiver_type,
|
||||
is_virtual,
|
||||
call_does_dispatch, vtable_index); // out-parameters
|
||||
speculative_receiver_type = receiver_type != NULL ? receiver_type->speculative_type() : NULL;
|
||||
}
|
||||
|
||||
// Note: It's OK to try to inline a virtual call.
|
||||
@ -468,7 +490,7 @@ void Parse::do_call() {
|
||||
// Decide call tactic.
|
||||
// This call checks with CHA, the interpreter profile, intrinsics table, etc.
|
||||
// It decides whether inlining is desirable or not.
|
||||
CallGenerator* cg = C->call_generator(callee, vtable_index, call_does_dispatch, jvms, try_inline, prof_factor());
|
||||
CallGenerator* cg = C->call_generator(callee, vtable_index, call_does_dispatch, jvms, try_inline, prof_factor(), speculative_receiver_type);
|
||||
|
||||
// NOTE: Don't use orig_callee and callee after this point! Use cg->method() instead.
|
||||
orig_callee = callee = NULL;
|
||||
@ -477,6 +499,10 @@ void Parse::do_call() {
|
||||
// Round double arguments before call
|
||||
round_double_arguments(cg->method());
|
||||
|
||||
// Feed profiling data for arguments to the type system so it can
|
||||
// propagate it as speculative types
|
||||
record_profiled_arguments_for_speculation(cg->method(), bc());
|
||||
|
||||
#ifndef PRODUCT
|
||||
// bump global counters for calls
|
||||
count_compiled_calls(/*at_method_entry*/ false, cg->is_inline());
|
||||
@ -491,11 +517,18 @@ void Parse::do_call() {
|
||||
// save across call, for a subsequent cast_not_null.
|
||||
Node* receiver = has_receiver ? argument(0) : NULL;
|
||||
|
||||
// The extra CheckCastPP for speculative types mess with PhaseStringOpts
|
||||
if (receiver != NULL && !call_does_dispatch && !cg->is_string_late_inline()) {
|
||||
// Feed profiling data for a single receiver to the type system so
|
||||
// it can propagate it as a speculative type
|
||||
receiver = record_profiled_receiver_for_speculation(receiver);
|
||||
}
|
||||
|
||||
// Bump method data counters (We profile *before* the call is made
|
||||
// because exceptions don't return to the call site.)
|
||||
profile_call(receiver);
|
||||
|
||||
JVMState* new_jvms = cg->generate(jvms);
|
||||
JVMState* new_jvms = cg->generate(jvms, this);
|
||||
if (new_jvms == NULL) {
|
||||
// When inlining attempt fails (e.g., too many arguments),
|
||||
// it may contaminate the current compile state, making it
|
||||
@ -508,8 +541,8 @@ void Parse::do_call() {
|
||||
// the call site, perhaps because it did not match a pattern the
|
||||
// intrinsic was expecting to optimize. Should always be possible to
|
||||
// get a normal java call that may inline in that case
|
||||
cg = C->call_generator(cg->method(), vtable_index, call_does_dispatch, jvms, try_inline, prof_factor(), /* allow_intrinsics= */ false);
|
||||
if ((new_jvms = cg->generate(jvms)) == NULL) {
|
||||
cg = C->call_generator(cg->method(), vtable_index, call_does_dispatch, jvms, try_inline, prof_factor(), speculative_receiver_type, /* allow_intrinsics= */ false);
|
||||
if ((new_jvms = cg->generate(jvms, this)) == NULL) {
|
||||
guarantee(failing(), "call failed to generate: calls should work");
|
||||
return;
|
||||
}
|
||||
@ -607,6 +640,16 @@ void Parse::do_call() {
|
||||
null_assert(peek());
|
||||
set_bci(iter().cur_bci()); // put it back
|
||||
}
|
||||
BasicType ct = ctype->basic_type();
|
||||
if (ct == T_OBJECT || ct == T_ARRAY) {
|
||||
ciKlass* better_type = method()->return_profiled_type(bci());
|
||||
if (UseTypeSpeculation && better_type != NULL) {
|
||||
// If profiling reports a single type for the return value,
|
||||
// feed it to the type system so it can propagate it as a
|
||||
// speculative type
|
||||
record_profile_for_speculation(stack(sp()-1), better_type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Restart record of parsing work after possible inlining of call
|
||||
|
@ -639,6 +639,7 @@ PreserveJVMState::PreserveJVMState(GraphKit* kit, bool clone_map) {
|
||||
_map = kit->map(); // preserve the map
|
||||
_sp = kit->sp();
|
||||
kit->set_map(clone_map ? kit->clone_map() : NULL);
|
||||
Compile::current()->inc_preserve_jvm_state();
|
||||
#ifdef ASSERT
|
||||
_bci = kit->bci();
|
||||
Parse* parser = kit->is_Parse();
|
||||
@ -656,6 +657,7 @@ PreserveJVMState::~PreserveJVMState() {
|
||||
#endif
|
||||
kit->set_map(_map);
|
||||
kit->set_sp(_sp);
|
||||
Compile::current()->dec_preserve_jvm_state();
|
||||
}
|
||||
|
||||
|
||||
@ -1373,17 +1375,70 @@ Node* GraphKit::cast_not_null(Node* obj, bool do_replace_in_map) {
|
||||
|
||||
//--------------------------replace_in_map-------------------------------------
|
||||
void GraphKit::replace_in_map(Node* old, Node* neww) {
|
||||
this->map()->replace_edge(old, neww);
|
||||
if (old == neww) {
|
||||
return;
|
||||
}
|
||||
|
||||
map()->replace_edge(old, neww);
|
||||
|
||||
// Note: This operation potentially replaces any edge
|
||||
// on the map. This includes locals, stack, and monitors
|
||||
// of the current (innermost) JVM state.
|
||||
|
||||
// We can consider replacing in caller maps.
|
||||
// The idea would be that an inlined function's null checks
|
||||
// can be shared with the entire inlining tree.
|
||||
// The expense of doing this is that the PreserveJVMState class
|
||||
// would have to preserve caller states too, with a deep copy.
|
||||
if (!ReplaceInParentMaps) {
|
||||
return;
|
||||
}
|
||||
|
||||
// PreserveJVMState doesn't do a deep copy so we can't modify
|
||||
// parents
|
||||
if (Compile::current()->has_preserve_jvm_state()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Parse* parser = is_Parse();
|
||||
bool progress = true;
|
||||
Node* ctrl = map()->in(0);
|
||||
// Follow the chain of parsers and see whether the update can be
|
||||
// done in the map of callers. We can do the replace for a caller if
|
||||
// the current control post dominates the control of a caller.
|
||||
while (parser != NULL && parser->caller() != NULL && progress) {
|
||||
progress = false;
|
||||
Node* parent_map = parser->caller()->map();
|
||||
assert(parser->exits().map()->jvms()->depth() == parser->caller()->depth(), "map mismatch");
|
||||
|
||||
Node* parent_ctrl = parent_map->in(0);
|
||||
|
||||
while (parent_ctrl->is_Region()) {
|
||||
Node* n = parent_ctrl->as_Region()->is_copy();
|
||||
if (n == NULL) {
|
||||
break;
|
||||
}
|
||||
parent_ctrl = n;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
if (ctrl == parent_ctrl) {
|
||||
// update the map of the exits which is the one that will be
|
||||
// used when compilation resume after inlining
|
||||
parser->exits().map()->replace_edge(old, neww);
|
||||
progress = true;
|
||||
break;
|
||||
}
|
||||
if (ctrl->is_Proj() && ctrl->as_Proj()->is_uncommon_trap_if_pattern(Deoptimization::Reason_none)) {
|
||||
ctrl = ctrl->in(0)->in(0);
|
||||
} else if (ctrl->is_Region()) {
|
||||
Node* n = ctrl->as_Region()->is_copy();
|
||||
if (n == NULL) {
|
||||
break;
|
||||
}
|
||||
ctrl = n;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
parser = parser->parent_parser();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -2043,6 +2098,104 @@ void GraphKit::round_double_arguments(ciMethod* dest_method) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Record profiling data exact_kls for Node n with the type system so
|
||||
* that it can propagate it (speculation)
|
||||
*
|
||||
* @param n node that the type applies to
|
||||
* @param exact_kls type from profiling
|
||||
*
|
||||
* @return node with improved type
|
||||
*/
|
||||
Node* GraphKit::record_profile_for_speculation(Node* n, ciKlass* exact_kls) {
|
||||
const TypeOopPtr* current_type = _gvn.type(n)->isa_oopptr();
|
||||
assert(UseTypeSpeculation, "type speculation must be on");
|
||||
if (exact_kls != NULL &&
|
||||
// nothing to improve if type is already exact
|
||||
(current_type == NULL ||
|
||||
(!current_type->klass_is_exact() &&
|
||||
(current_type->speculative() == NULL ||
|
||||
!current_type->speculative()->klass_is_exact())))) {
|
||||
const TypeKlassPtr* tklass = TypeKlassPtr::make(exact_kls);
|
||||
const TypeOopPtr* xtype = tklass->as_instance_type();
|
||||
assert(xtype->klass_is_exact(), "Should be exact");
|
||||
|
||||
// Build a type with a speculative type (what we think we know
|
||||
// about the type but will need a guard when we use it)
|
||||
const TypeOopPtr* spec_type = TypeOopPtr::make(TypePtr::BotPTR, Type::OffsetBot, TypeOopPtr::InstanceBot, xtype);
|
||||
// We're changing the type, we need a new cast node to carry the
|
||||
// new type. The new type depends on the control: what profiling
|
||||
// tells us is only valid from here as far as we can tell.
|
||||
Node* cast = new(C) CastPPNode(n, spec_type);
|
||||
cast->init_req(0, control());
|
||||
cast = _gvn.transform(cast);
|
||||
replace_in_map(n, cast);
|
||||
n = cast;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
/**
|
||||
* Record profiling data from receiver profiling at an invoke with the
|
||||
* type system so that it can propagate it (speculation)
|
||||
*
|
||||
* @param n receiver node
|
||||
*
|
||||
* @return node with improved type
|
||||
*/
|
||||
Node* GraphKit::record_profiled_receiver_for_speculation(Node* n) {
|
||||
if (!UseTypeSpeculation) {
|
||||
return n;
|
||||
}
|
||||
ciKlass* exact_kls = profile_has_unique_klass();
|
||||
return record_profile_for_speculation(n, exact_kls);
|
||||
}
|
||||
|
||||
/**
|
||||
* Record profiling data from argument profiling at an invoke with the
|
||||
* type system so that it can propagate it (speculation)
|
||||
*
|
||||
* @param dest_method target method for the call
|
||||
* @param bc what invoke bytecode is this?
|
||||
*/
|
||||
void GraphKit::record_profiled_arguments_for_speculation(ciMethod* dest_method, Bytecodes::Code bc) {
|
||||
if (!UseTypeSpeculation) {
|
||||
return;
|
||||
}
|
||||
const TypeFunc* tf = TypeFunc::make(dest_method);
|
||||
int nargs = tf->_domain->_cnt - TypeFunc::Parms;
|
||||
int skip = Bytecodes::has_receiver(bc) ? 1 : 0;
|
||||
for (int j = skip, i = 0; j < nargs && i < TypeProfileArgsLimit; j++) {
|
||||
const Type *targ = tf->_domain->field_at(j + TypeFunc::Parms);
|
||||
if (targ->basic_type() == T_OBJECT || targ->basic_type() == T_ARRAY) {
|
||||
ciKlass* better_type = method()->argument_profiled_type(bci(), i);
|
||||
if (better_type != NULL) {
|
||||
record_profile_for_speculation(argument(j), better_type);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Record profiling data from parameter profiling at an invoke with
|
||||
* the type system so that it can propagate it (speculation)
|
||||
*/
|
||||
void GraphKit::record_profiled_parameters_for_speculation() {
|
||||
if (!UseTypeSpeculation) {
|
||||
return;
|
||||
}
|
||||
for (int i = 0, j = 0; i < method()->arg_size() ; i++) {
|
||||
if (_gvn.type(local(i))->isa_oopptr()) {
|
||||
ciKlass* better_type = method()->parameter_profiled_type(j);
|
||||
if (better_type != NULL) {
|
||||
record_profile_for_speculation(local(i), better_type);
|
||||
}
|
||||
j++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GraphKit::round_double_result(ciMethod* dest_method) {
|
||||
// A non-strict method may return a double value which has an extended
|
||||
// exponent, but this must not be visible in a caller which is 'strict'
|
||||
@ -2580,10 +2733,10 @@ bool GraphKit::seems_never_null(Node* obj, ciProfileData* data) {
|
||||
// If the profile has seen exactly one type, narrow to exactly that type.
|
||||
// Subsequent type checks will always fold up.
|
||||
Node* GraphKit::maybe_cast_profiled_receiver(Node* not_null_obj,
|
||||
ciProfileData* data,
|
||||
ciKlass* require_klass) {
|
||||
ciKlass* require_klass,
|
||||
ciKlass* spec_klass,
|
||||
bool safe_for_replace) {
|
||||
if (!UseTypeProfile || !TypeProfileCasts) return NULL;
|
||||
if (data == NULL) return NULL;
|
||||
|
||||
// Make sure we haven't already deoptimized from this tactic.
|
||||
if (too_many_traps(Deoptimization::Reason_class_check))
|
||||
@ -2591,15 +2744,15 @@ Node* GraphKit::maybe_cast_profiled_receiver(Node* not_null_obj,
|
||||
|
||||
// (No, this isn't a call, but it's enough like a virtual call
|
||||
// to use the same ciMethod accessor to get the profile info...)
|
||||
ciCallProfile profile = method()->call_profile_at_bci(bci());
|
||||
if (profile.count() >= 0 && // no cast failures here
|
||||
profile.has_receiver(0) &&
|
||||
profile.morphism() == 1) {
|
||||
ciKlass* exact_kls = profile.receiver(0);
|
||||
// If we have a speculative type use it instead of profiling (which
|
||||
// may not help us)
|
||||
ciKlass* exact_kls = spec_klass == NULL ? profile_has_unique_klass() : spec_klass;
|
||||
if (exact_kls != NULL) {// no cast failures here
|
||||
if (require_klass == NULL ||
|
||||
static_subtype_check(require_klass, exact_kls) == SSC_always_true) {
|
||||
// If we narrow the type to match what the type profile sees,
|
||||
// we can then remove the rest of the cast.
|
||||
// If we narrow the type to match what the type profile sees or
|
||||
// the speculative type, we can then remove the rest of the
|
||||
// cast.
|
||||
// This is a win, even if the exact_kls is very specific,
|
||||
// because downstream operations, such as method calls,
|
||||
// will often benefit from the sharper type.
|
||||
@ -2611,7 +2764,9 @@ Node* GraphKit::maybe_cast_profiled_receiver(Node* not_null_obj,
|
||||
uncommon_trap(Deoptimization::Reason_class_check,
|
||||
Deoptimization::Action_maybe_recompile);
|
||||
}
|
||||
replace_in_map(not_null_obj, exact_obj);
|
||||
if (safe_for_replace) {
|
||||
replace_in_map(not_null_obj, exact_obj);
|
||||
}
|
||||
return exact_obj;
|
||||
}
|
||||
// assert(ssc == SSC_always_true)... except maybe the profile lied to us.
|
||||
@ -2620,11 +2775,59 @@ Node* GraphKit::maybe_cast_profiled_receiver(Node* not_null_obj,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cast obj to type and emit guard unless we had too many traps here
|
||||
* already
|
||||
*
|
||||
* @param obj node being casted
|
||||
* @param type type to cast the node to
|
||||
* @param not_null true if we know node cannot be null
|
||||
*/
|
||||
Node* GraphKit::maybe_cast_profiled_obj(Node* obj,
|
||||
ciKlass* type,
|
||||
bool not_null) {
|
||||
// type == NULL if profiling tells us this object is always null
|
||||
if (type != NULL) {
|
||||
if (!too_many_traps(Deoptimization::Reason_null_check) &&
|
||||
!too_many_traps(Deoptimization::Reason_class_check)) {
|
||||
Node* not_null_obj = NULL;
|
||||
// not_null is true if we know the object is not null and
|
||||
// there's no need for a null check
|
||||
if (!not_null) {
|
||||
Node* null_ctl = top();
|
||||
not_null_obj = null_check_oop(obj, &null_ctl, true, true);
|
||||
assert(null_ctl->is_top(), "no null control here");
|
||||
} else {
|
||||
not_null_obj = obj;
|
||||
}
|
||||
|
||||
Node* exact_obj = not_null_obj;
|
||||
ciKlass* exact_kls = type;
|
||||
Node* slow_ctl = type_check_receiver(exact_obj, exact_kls, 1.0,
|
||||
&exact_obj);
|
||||
{
|
||||
PreserveJVMState pjvms(this);
|
||||
set_control(slow_ctl);
|
||||
uncommon_trap(Deoptimization::Reason_class_check,
|
||||
Deoptimization::Action_maybe_recompile);
|
||||
}
|
||||
replace_in_map(not_null_obj, exact_obj);
|
||||
obj = exact_obj;
|
||||
}
|
||||
} else {
|
||||
if (!too_many_traps(Deoptimization::Reason_null_assert)) {
|
||||
Node* exact_obj = null_assert(obj);
|
||||
replace_in_map(obj, exact_obj);
|
||||
obj = exact_obj;
|
||||
}
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
//-------------------------------gen_instanceof--------------------------------
|
||||
// Generate an instance-of idiom. Used by both the instance-of bytecode
|
||||
// and the reflective instance-of call.
|
||||
Node* GraphKit::gen_instanceof(Node* obj, Node* superklass) {
|
||||
Node* GraphKit::gen_instanceof(Node* obj, Node* superklass, bool safe_for_replace) {
|
||||
kill_dead_locals(); // Benefit all the uncommon traps
|
||||
assert( !stopped(), "dead parse path should be checked in callers" );
|
||||
assert(!TypePtr::NULL_PTR->higher_equal(_gvn.type(superklass)->is_klassptr()),
|
||||
@ -2637,10 +2840,8 @@ Node* GraphKit::gen_instanceof(Node* obj, Node* superklass) {
|
||||
C->set_has_split_ifs(true); // Has chance for split-if optimization
|
||||
|
||||
ciProfileData* data = NULL;
|
||||
bool safe_for_replace = false;
|
||||
if (java_bc() == Bytecodes::_instanceof) { // Only for the bytecode
|
||||
data = method()->method_data()->bci_to_data(bci());
|
||||
safe_for_replace = true;
|
||||
}
|
||||
bool never_see_null = (ProfileDynamicTypes // aggressive use of profile
|
||||
&& seems_never_null(obj, data));
|
||||
@ -2664,14 +2865,37 @@ Node* GraphKit::gen_instanceof(Node* obj, Node* superklass) {
|
||||
phi ->del_req(_null_path);
|
||||
}
|
||||
|
||||
if (ProfileDynamicTypes && data != NULL) {
|
||||
Node* cast_obj = maybe_cast_profiled_receiver(not_null_obj, data, NULL);
|
||||
if (stopped()) { // Profile disagrees with this path.
|
||||
set_control(null_ctl); // Null is the only remaining possibility.
|
||||
return intcon(0);
|
||||
// Do we know the type check always succeed?
|
||||
bool known_statically = false;
|
||||
if (_gvn.type(superklass)->singleton()) {
|
||||
ciKlass* superk = _gvn.type(superklass)->is_klassptr()->klass();
|
||||
ciKlass* subk = _gvn.type(obj)->is_oopptr()->klass();
|
||||
if (subk != NULL && subk->is_loaded()) {
|
||||
int static_res = static_subtype_check(superk, subk);
|
||||
known_statically = (static_res == SSC_always_true || static_res == SSC_always_false);
|
||||
}
|
||||
}
|
||||
|
||||
if (known_statically && UseTypeSpeculation) {
|
||||
// If we know the type check always succeed then we don't use the
|
||||
// profiling data at this bytecode. Don't lose it, feed it to the
|
||||
// type system as a speculative type.
|
||||
not_null_obj = record_profiled_receiver_for_speculation(not_null_obj);
|
||||
} else {
|
||||
const TypeOopPtr* obj_type = _gvn.type(obj)->is_oopptr();
|
||||
// We may not have profiling here or it may not help us. If we
|
||||
// have a speculative type use it to perform an exact cast.
|
||||
ciKlass* spec_obj_type = obj_type->speculative_type();
|
||||
if (spec_obj_type != NULL || (ProfileDynamicTypes && data != NULL)) {
|
||||
Node* cast_obj = maybe_cast_profiled_receiver(not_null_obj, NULL, spec_obj_type, safe_for_replace);
|
||||
if (stopped()) { // Profile disagrees with this path.
|
||||
set_control(null_ctl); // Null is the only remaining possibility.
|
||||
return intcon(0);
|
||||
}
|
||||
if (cast_obj != NULL) {
|
||||
not_null_obj = cast_obj;
|
||||
}
|
||||
}
|
||||
if (cast_obj != NULL)
|
||||
not_null_obj = cast_obj;
|
||||
}
|
||||
|
||||
// Load the object's klass
|
||||
@ -2718,7 +2942,10 @@ Node* GraphKit::gen_checkcast(Node *obj, Node* superklass,
|
||||
if (objtp != NULL && objtp->klass() != NULL) {
|
||||
switch (static_subtype_check(tk->klass(), objtp->klass())) {
|
||||
case SSC_always_true:
|
||||
return obj;
|
||||
// If we know the type check always succeed then we don't use
|
||||
// the profiling data at this bytecode. Don't lose it, feed it
|
||||
// to the type system as a speculative type.
|
||||
return record_profiled_receiver_for_speculation(obj);
|
||||
case SSC_always_false:
|
||||
// It needs a null check because a null will *pass* the cast check.
|
||||
// A non-null value will always produce an exception.
|
||||
@ -2767,12 +2994,17 @@ Node* GraphKit::gen_checkcast(Node *obj, Node* superklass,
|
||||
}
|
||||
|
||||
Node* cast_obj = NULL;
|
||||
if (data != NULL &&
|
||||
// Counter has never been decremented (due to cast failure).
|
||||
// ...This is a reasonable thing to expect. It is true of
|
||||
// all casts inserted by javac to implement generic types.
|
||||
data->as_CounterData()->count() >= 0) {
|
||||
cast_obj = maybe_cast_profiled_receiver(not_null_obj, data, tk->klass());
|
||||
const TypeOopPtr* obj_type = _gvn.type(obj)->is_oopptr();
|
||||
// We may not have profiling here or it may not help us. If we have
|
||||
// a speculative type use it to perform an exact cast.
|
||||
ciKlass* spec_obj_type = obj_type->speculative_type();
|
||||
if (spec_obj_type != NULL ||
|
||||
(data != NULL &&
|
||||
// Counter has never been decremented (due to cast failure).
|
||||
// ...This is a reasonable thing to expect. It is true of
|
||||
// all casts inserted by javac to implement generic types.
|
||||
data->as_CounterData()->count() >= 0)) {
|
||||
cast_obj = maybe_cast_profiled_receiver(not_null_obj, tk->klass(), spec_obj_type, safe_for_replace);
|
||||
if (cast_obj != NULL) {
|
||||
if (failure_control != NULL) // failure is now impossible
|
||||
(*failure_control) = top();
|
||||
|
@ -386,10 +386,33 @@ class GraphKit : public Phase {
|
||||
// Check the null_seen bit.
|
||||
bool seems_never_null(Node* obj, ciProfileData* data);
|
||||
|
||||
// Check for unique class for receiver at call
|
||||
ciKlass* profile_has_unique_klass() {
|
||||
ciCallProfile profile = method()->call_profile_at_bci(bci());
|
||||
if (profile.count() >= 0 && // no cast failures here
|
||||
profile.has_receiver(0) &&
|
||||
profile.morphism() == 1) {
|
||||
return profile.receiver(0);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// record type from profiling with the type system
|
||||
Node* record_profile_for_speculation(Node* n, ciKlass* exact_kls);
|
||||
Node* record_profiled_receiver_for_speculation(Node* n);
|
||||
void record_profiled_arguments_for_speculation(ciMethod* dest_method, Bytecodes::Code bc);
|
||||
void record_profiled_parameters_for_speculation();
|
||||
|
||||
// Use the type profile to narrow an object type.
|
||||
Node* maybe_cast_profiled_receiver(Node* not_null_obj,
|
||||
ciProfileData* data,
|
||||
ciKlass* require_klass);
|
||||
ciKlass* require_klass,
|
||||
ciKlass* spec,
|
||||
bool safe_for_replace);
|
||||
|
||||
// Cast obj to type and emit guard unless we had too many traps here already
|
||||
Node* maybe_cast_profiled_obj(Node* obj,
|
||||
ciKlass* type,
|
||||
bool not_null = false);
|
||||
|
||||
// Cast obj to not-null on this path
|
||||
Node* cast_not_null(Node* obj, bool do_replace_in_map = true);
|
||||
@ -775,7 +798,7 @@ class GraphKit : public Phase {
|
||||
|
||||
// Generate an instance-of idiom. Used by both the instance-of bytecode
|
||||
// and the reflective instance-of call.
|
||||
Node* gen_instanceof( Node *subobj, Node* superkls );
|
||||
Node* gen_instanceof(Node *subobj, Node* superkls, bool safe_for_replace = false);
|
||||
|
||||
// Generate a check-cast idiom. Used by both the check-cast bytecode
|
||||
// and the array-store bytecode
|
||||
|
@ -1019,7 +1019,7 @@ void IfNode::dominated_by( Node *prev_dom, PhaseIterGVN *igvn ) {
|
||||
// be skipped. For example, range check predicate has two checks
|
||||
// for lower and upper bounds.
|
||||
ProjNode* unc_proj = proj_out(1 - prev_dom->as_Proj()->_con)->as_Proj();
|
||||
if (PhaseIdealLoop::is_uncommon_trap_proj(unc_proj, Deoptimization::Reason_predicate))
|
||||
if (unc_proj->is_uncommon_trap_proj(Deoptimization::Reason_predicate))
|
||||
prev_dom = idom;
|
||||
|
||||
// Now walk the current IfNode's projections.
|
||||
|
@ -63,7 +63,7 @@ class LibraryIntrinsic : public InlineCallGenerator {
|
||||
virtual bool is_virtual() const { return _is_virtual; }
|
||||
virtual bool is_predicted() const { return _is_predicted; }
|
||||
virtual bool does_virtual_dispatch() const { return _does_virtual_dispatch; }
|
||||
virtual JVMState* generate(JVMState* jvms);
|
||||
virtual JVMState* generate(JVMState* jvms, Parse* parent_parser);
|
||||
virtual Node* generate_predicate(JVMState* jvms);
|
||||
vmIntrinsics::ID intrinsic_id() const { return _intrinsic_id; }
|
||||
};
|
||||
@ -203,8 +203,15 @@ class LibraryCallKit : public GraphKit {
|
||||
bool inline_math_native(vmIntrinsics::ID id);
|
||||
bool inline_trig(vmIntrinsics::ID id);
|
||||
bool inline_math(vmIntrinsics::ID id);
|
||||
bool inline_math_mathExact(Node* math);
|
||||
bool inline_math_addExact();
|
||||
void inline_math_mathExact(Node* math);
|
||||
bool inline_math_addExactI(bool is_increment);
|
||||
bool inline_math_addExactL(bool is_increment);
|
||||
bool inline_math_multiplyExactI();
|
||||
bool inline_math_multiplyExactL();
|
||||
bool inline_math_negateExactI();
|
||||
bool inline_math_negateExactL();
|
||||
bool inline_math_subtractExactI(bool is_decrement);
|
||||
bool inline_math_subtractExactL(bool is_decrement);
|
||||
bool inline_exp();
|
||||
bool inline_pow();
|
||||
void finish_pow_exp(Node* result, Node* x, Node* y, const TypeFunc* call_type, address funcAddr, const char* funcName);
|
||||
@ -507,13 +514,33 @@ CallGenerator* Compile::make_vm_intrinsic(ciMethod* m, bool is_virtual) {
|
||||
if (!UseCRC32Intrinsics) return NULL;
|
||||
break;
|
||||
|
||||
case vmIntrinsics::_addExact:
|
||||
if (!Matcher::match_rule_supported(Op_AddExactI)) {
|
||||
return NULL;
|
||||
}
|
||||
if (!UseMathExactIntrinsics) {
|
||||
return NULL;
|
||||
}
|
||||
case vmIntrinsics::_incrementExactI:
|
||||
case vmIntrinsics::_addExactI:
|
||||
if (!Matcher::match_rule_supported(Op_AddExactI) || !UseMathExactIntrinsics) return NULL;
|
||||
break;
|
||||
case vmIntrinsics::_incrementExactL:
|
||||
case vmIntrinsics::_addExactL:
|
||||
if (!Matcher::match_rule_supported(Op_AddExactL) || !UseMathExactIntrinsics) return NULL;
|
||||
break;
|
||||
case vmIntrinsics::_decrementExactI:
|
||||
case vmIntrinsics::_subtractExactI:
|
||||
if (!Matcher::match_rule_supported(Op_SubExactI) || !UseMathExactIntrinsics) return NULL;
|
||||
break;
|
||||
case vmIntrinsics::_decrementExactL:
|
||||
case vmIntrinsics::_subtractExactL:
|
||||
if (!Matcher::match_rule_supported(Op_SubExactL) || !UseMathExactIntrinsics) return NULL;
|
||||
break;
|
||||
case vmIntrinsics::_negateExactI:
|
||||
if (!Matcher::match_rule_supported(Op_NegExactI) || !UseMathExactIntrinsics) return NULL;
|
||||
break;
|
||||
case vmIntrinsics::_negateExactL:
|
||||
if (!Matcher::match_rule_supported(Op_NegExactL) || !UseMathExactIntrinsics) return NULL;
|
||||
break;
|
||||
case vmIntrinsics::_multiplyExactI:
|
||||
if (!Matcher::match_rule_supported(Op_MulExactI) || !UseMathExactIntrinsics) return NULL;
|
||||
break;
|
||||
case vmIntrinsics::_multiplyExactL:
|
||||
if (!Matcher::match_rule_supported(Op_MulExactL) || !UseMathExactIntrinsics) return NULL;
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -556,7 +583,7 @@ void Compile::register_library_intrinsics() {
|
||||
// Nothing to do here.
|
||||
}
|
||||
|
||||
JVMState* LibraryIntrinsic::generate(JVMState* jvms) {
|
||||
JVMState* LibraryIntrinsic::generate(JVMState* jvms, Parse* parent_parser) {
|
||||
LibraryCallKit kit(jvms, this);
|
||||
Compile* C = kit.C;
|
||||
int nodes = C->unique();
|
||||
@ -686,7 +713,18 @@ bool LibraryCallKit::try_to_inline() {
|
||||
case vmIntrinsics::_min:
|
||||
case vmIntrinsics::_max: return inline_min_max(intrinsic_id());
|
||||
|
||||
case vmIntrinsics::_addExact: return inline_math_addExact();
|
||||
case vmIntrinsics::_addExactI: return inline_math_addExactI(false /* add */);
|
||||
case vmIntrinsics::_addExactL: return inline_math_addExactL(false /* add */);
|
||||
case vmIntrinsics::_decrementExactI: return inline_math_subtractExactI(true /* decrement */);
|
||||
case vmIntrinsics::_decrementExactL: return inline_math_subtractExactL(true /* decrement */);
|
||||
case vmIntrinsics::_incrementExactI: return inline_math_addExactI(true /* increment */);
|
||||
case vmIntrinsics::_incrementExactL: return inline_math_addExactL(true /* increment */);
|
||||
case vmIntrinsics::_multiplyExactI: return inline_math_multiplyExactI();
|
||||
case vmIntrinsics::_multiplyExactL: return inline_math_multiplyExactL();
|
||||
case vmIntrinsics::_negateExactI: return inline_math_negateExactI();
|
||||
case vmIntrinsics::_negateExactL: return inline_math_negateExactL();
|
||||
case vmIntrinsics::_subtractExactI: return inline_math_subtractExactI(false /* subtract */);
|
||||
case vmIntrinsics::_subtractExactL: return inline_math_subtractExactL(false /* subtract */);
|
||||
|
||||
case vmIntrinsics::_arraycopy: return inline_arraycopy();
|
||||
|
||||
@ -1931,7 +1969,14 @@ bool LibraryCallKit::inline_min_max(vmIntrinsics::ID id) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LibraryCallKit::inline_math_mathExact(Node* math) {
|
||||
void LibraryCallKit::inline_math_mathExact(Node* math) {
|
||||
// If we didn't get the expected opcode it means we have optimized
|
||||
// the node to something else and don't need the exception edge.
|
||||
if (!math->is_MathExact()) {
|
||||
set_result(math);
|
||||
return;
|
||||
}
|
||||
|
||||
Node* result = _gvn.transform( new(C) ProjNode(math, MathExactNode::result_proj_node));
|
||||
Node* flags = _gvn.transform( new(C) FlagsProjNode(math, MathExactNode::flags_proj_node));
|
||||
|
||||
@ -1954,19 +1999,106 @@ bool LibraryCallKit::inline_math_mathExact(Node* math) {
|
||||
|
||||
set_control(fast_path);
|
||||
set_result(result);
|
||||
}
|
||||
|
||||
bool LibraryCallKit::inline_math_addExactI(bool is_increment) {
|
||||
Node* arg1 = argument(0);
|
||||
Node* arg2 = NULL;
|
||||
|
||||
if (is_increment) {
|
||||
arg2 = intcon(1);
|
||||
} else {
|
||||
arg2 = argument(1);
|
||||
}
|
||||
|
||||
Node* add = _gvn.transform( new(C) AddExactINode(NULL, arg1, arg2) );
|
||||
inline_math_mathExact(add);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LibraryCallKit::inline_math_addExact() {
|
||||
bool LibraryCallKit::inline_math_addExactL(bool is_increment) {
|
||||
Node* arg1 = argument(0); // type long
|
||||
// argument(1) == TOP
|
||||
Node* arg2 = NULL;
|
||||
|
||||
if (is_increment) {
|
||||
arg2 = longcon(1);
|
||||
} else {
|
||||
arg2 = argument(2); // type long
|
||||
// argument(3) == TOP
|
||||
}
|
||||
|
||||
Node* add = _gvn.transform(new(C) AddExactLNode(NULL, arg1, arg2));
|
||||
inline_math_mathExact(add);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LibraryCallKit::inline_math_subtractExactI(bool is_decrement) {
|
||||
Node* arg1 = argument(0);
|
||||
Node* arg2 = NULL;
|
||||
|
||||
if (is_decrement) {
|
||||
arg2 = intcon(1);
|
||||
} else {
|
||||
arg2 = argument(1);
|
||||
}
|
||||
|
||||
Node* sub = _gvn.transform(new(C) SubExactINode(NULL, arg1, arg2));
|
||||
inline_math_mathExact(sub);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LibraryCallKit::inline_math_subtractExactL(bool is_decrement) {
|
||||
Node* arg1 = argument(0); // type long
|
||||
// argument(1) == TOP
|
||||
Node* arg2 = NULL;
|
||||
|
||||
if (is_decrement) {
|
||||
arg2 = longcon(1);
|
||||
} else {
|
||||
Node* arg2 = argument(2); // type long
|
||||
// argument(3) == TOP
|
||||
}
|
||||
|
||||
Node* sub = _gvn.transform(new(C) SubExactLNode(NULL, arg1, arg2));
|
||||
inline_math_mathExact(sub);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LibraryCallKit::inline_math_negateExactI() {
|
||||
Node* arg1 = argument(0);
|
||||
|
||||
Node* neg = _gvn.transform(new(C) NegExactINode(NULL, arg1));
|
||||
inline_math_mathExact(neg);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LibraryCallKit::inline_math_negateExactL() {
|
||||
Node* arg1 = argument(0);
|
||||
// argument(1) == TOP
|
||||
|
||||
Node* neg = _gvn.transform(new(C) NegExactLNode(NULL, arg1));
|
||||
inline_math_mathExact(neg);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LibraryCallKit::inline_math_multiplyExactI() {
|
||||
Node* arg1 = argument(0);
|
||||
Node* arg2 = argument(1);
|
||||
|
||||
Node* add = _gvn.transform( new(C) AddExactINode(NULL, arg1, arg2) );
|
||||
if (add->Opcode() == Op_AddExactI) {
|
||||
return inline_math_mathExact(add);
|
||||
} else {
|
||||
set_result(add);
|
||||
}
|
||||
Node* mul = _gvn.transform(new(C) MulExactINode(NULL, arg1, arg2));
|
||||
inline_math_mathExact(mul);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LibraryCallKit::inline_math_multiplyExactL() {
|
||||
Node* arg1 = argument(0);
|
||||
// argument(1) == TOP
|
||||
Node* arg2 = argument(2);
|
||||
// argument(3) == TOP
|
||||
|
||||
Node* mul = _gvn.transform(new(C) MulExactLNode(NULL, arg1, arg2));
|
||||
inline_math_mathExact(mul);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -3353,6 +3485,7 @@ bool LibraryCallKit::inline_native_Class_query(vmIntrinsics::ID id) {
|
||||
// If kls is null, we have a primitive mirror.
|
||||
phi->init_req(_prim_path, prim_return_value);
|
||||
if (stopped()) { set_result(region, phi); return true; }
|
||||
bool safe_for_replace = (region->in(_prim_path) == top());
|
||||
|
||||
Node* p; // handy temp
|
||||
Node* null_ctl;
|
||||
@ -3363,7 +3496,7 @@ bool LibraryCallKit::inline_native_Class_query(vmIntrinsics::ID id) {
|
||||
switch (id) {
|
||||
case vmIntrinsics::_isInstance:
|
||||
// nothing is an instance of a primitive type
|
||||
query_value = gen_instanceof(obj, kls);
|
||||
query_value = gen_instanceof(obj, kls, safe_for_replace);
|
||||
break;
|
||||
|
||||
case vmIntrinsics::_getModifiers:
|
||||
@ -4553,8 +4686,62 @@ bool LibraryCallKit::inline_arraycopy() {
|
||||
const Type* dest_type = dest->Value(&_gvn);
|
||||
const TypeAryPtr* top_src = src_type->isa_aryptr();
|
||||
const TypeAryPtr* top_dest = dest_type->isa_aryptr();
|
||||
if (top_src == NULL || top_src->klass() == NULL ||
|
||||
top_dest == NULL || top_dest->klass() == NULL) {
|
||||
|
||||
// Do we have the type of src?
|
||||
bool has_src = (top_src != NULL && top_src->klass() != NULL);
|
||||
// Do we have the type of dest?
|
||||
bool has_dest = (top_dest != NULL && top_dest->klass() != NULL);
|
||||
// Is the type for src from speculation?
|
||||
bool src_spec = false;
|
||||
// Is the type for dest from speculation?
|
||||
bool dest_spec = false;
|
||||
|
||||
if (!has_src || !has_dest) {
|
||||
// We don't have sufficient type information, let's see if
|
||||
// speculative types can help. We need to have types for both src
|
||||
// and dest so that it pays off.
|
||||
|
||||
// Do we already have or could we have type information for src
|
||||
bool could_have_src = has_src;
|
||||
// Do we already have or could we have type information for dest
|
||||
bool could_have_dest = has_dest;
|
||||
|
||||
ciKlass* src_k = NULL;
|
||||
if (!has_src) {
|
||||
src_k = src_type->speculative_type();
|
||||
if (src_k != NULL && src_k->is_array_klass()) {
|
||||
could_have_src = true;
|
||||
}
|
||||
}
|
||||
|
||||
ciKlass* dest_k = NULL;
|
||||
if (!has_dest) {
|
||||
dest_k = dest_type->speculative_type();
|
||||
if (dest_k != NULL && dest_k->is_array_klass()) {
|
||||
could_have_dest = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (could_have_src && could_have_dest) {
|
||||
// This is going to pay off so emit the required guards
|
||||
if (!has_src) {
|
||||
src = maybe_cast_profiled_obj(src, src_k);
|
||||
src_type = _gvn.type(src);
|
||||
top_src = src_type->isa_aryptr();
|
||||
has_src = (top_src != NULL && top_src->klass() != NULL);
|
||||
src_spec = true;
|
||||
}
|
||||
if (!has_dest) {
|
||||
dest = maybe_cast_profiled_obj(dest, dest_k);
|
||||
dest_type = _gvn.type(dest);
|
||||
top_dest = dest_type->isa_aryptr();
|
||||
has_dest = (top_dest != NULL && top_dest->klass() != NULL);
|
||||
dest_spec = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!has_src || !has_dest) {
|
||||
// Conservatively insert a memory barrier on all memory slices.
|
||||
// Do not let writes into the source float below the arraycopy.
|
||||
insert_mem_bar(Op_MemBarCPUOrder);
|
||||
@ -4589,6 +4776,40 @@ bool LibraryCallKit::inline_arraycopy() {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (src_elem == T_OBJECT) {
|
||||
// If both arrays are object arrays then having the exact types
|
||||
// for both will remove the need for a subtype check at runtime
|
||||
// before the call and may make it possible to pick a faster copy
|
||||
// routine (without a subtype check on every element)
|
||||
// Do we have the exact type of src?
|
||||
bool could_have_src = src_spec;
|
||||
// Do we have the exact type of dest?
|
||||
bool could_have_dest = dest_spec;
|
||||
ciKlass* src_k = top_src->klass();
|
||||
ciKlass* dest_k = top_dest->klass();
|
||||
if (!src_spec) {
|
||||
src_k = src_type->speculative_type();
|
||||
if (src_k != NULL && src_k->is_array_klass()) {
|
||||
could_have_src = true;
|
||||
}
|
||||
}
|
||||
if (!dest_spec) {
|
||||
dest_k = dest_type->speculative_type();
|
||||
if (dest_k != NULL && dest_k->is_array_klass()) {
|
||||
could_have_dest = true;
|
||||
}
|
||||
}
|
||||
if (could_have_src && could_have_dest) {
|
||||
// If we can have both exact types, emit the missing guards
|
||||
if (could_have_src && !src_spec) {
|
||||
src = maybe_cast_profiled_obj(src, src_k);
|
||||
}
|
||||
if (could_have_dest && !dest_spec) {
|
||||
dest = maybe_cast_profiled_obj(dest, dest_k);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// We will make a fast path for this call to arraycopy.
|
||||
|
||||
|
@ -41,63 +41,6 @@
|
||||
* checks (such as null checks).
|
||||
*/
|
||||
|
||||
//-------------------------------is_uncommon_trap_proj----------------------------
|
||||
// Return true if proj is the form of "proj->[region->..]call_uct"
|
||||
bool PhaseIdealLoop::is_uncommon_trap_proj(ProjNode* proj, Deoptimization::DeoptReason reason) {
|
||||
int path_limit = 10;
|
||||
assert(proj, "invalid argument");
|
||||
Node* out = proj;
|
||||
for (int ct = 0; ct < path_limit; ct++) {
|
||||
out = out->unique_ctrl_out();
|
||||
if (out == NULL)
|
||||
return false;
|
||||
if (out->is_CallStaticJava()) {
|
||||
int req = out->as_CallStaticJava()->uncommon_trap_request();
|
||||
if (req != 0) {
|
||||
Deoptimization::DeoptReason trap_reason = Deoptimization::trap_request_reason(req);
|
||||
if (trap_reason == reason || reason == Deoptimization::Reason_none) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false; // don't do further after call
|
||||
}
|
||||
if (out->Opcode() != Op_Region)
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//-------------------------------is_uncommon_trap_if_pattern-------------------------
|
||||
// Return true for "if(test)-> proj -> ...
|
||||
// |
|
||||
// V
|
||||
// other_proj->[region->..]call_uct"
|
||||
//
|
||||
// "must_reason_predicate" means the uct reason must be Reason_predicate
|
||||
bool PhaseIdealLoop::is_uncommon_trap_if_pattern(ProjNode *proj, Deoptimization::DeoptReason reason) {
|
||||
Node *in0 = proj->in(0);
|
||||
if (!in0->is_If()) return false;
|
||||
// Variation of a dead If node.
|
||||
if (in0->outcnt() < 2) return false;
|
||||
IfNode* iff = in0->as_If();
|
||||
|
||||
// we need "If(Conv2B(Opaque1(...)))" pattern for reason_predicate
|
||||
if (reason != Deoptimization::Reason_none) {
|
||||
if (iff->in(1)->Opcode() != Op_Conv2B ||
|
||||
iff->in(1)->in(1)->Opcode() != Op_Opaque1) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
ProjNode* other_proj = iff->proj_out(1-proj->_con)->as_Proj();
|
||||
if (is_uncommon_trap_proj(other_proj, reason)) {
|
||||
assert(reason == Deoptimization::Reason_none ||
|
||||
Compile::current()->is_predicate_opaq(iff->in(1)->in(1)), "should be on the list");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//-------------------------------register_control-------------------------
|
||||
void PhaseIdealLoop::register_control(Node* n, IdealLoopTree *loop, Node* pred) {
|
||||
assert(n->is_CFG(), "must be control node");
|
||||
@ -147,7 +90,7 @@ void PhaseIdealLoop::register_control(Node* n, IdealLoopTree *loop, Node* pred)
|
||||
// This code is also used to clone predicates to clonned loops.
|
||||
ProjNode* PhaseIdealLoop::create_new_if_for_predicate(ProjNode* cont_proj, Node* new_entry,
|
||||
Deoptimization::DeoptReason reason) {
|
||||
assert(is_uncommon_trap_if_pattern(cont_proj, reason), "must be a uct if pattern!");
|
||||
assert(cont_proj->is_uncommon_trap_if_pattern(reason), "must be a uct if pattern!");
|
||||
IfNode* iff = cont_proj->in(0)->as_If();
|
||||
|
||||
ProjNode *uncommon_proj = iff->proj_out(1 - cont_proj->_con);
|
||||
@ -235,7 +178,7 @@ ProjNode* PhaseIdealLoop::create_new_if_for_predicate(ProjNode* cont_proj, Node*
|
||||
ProjNode* PhaseIterGVN::create_new_if_for_predicate(ProjNode* cont_proj, Node* new_entry,
|
||||
Deoptimization::DeoptReason reason) {
|
||||
assert(new_entry != 0, "only used for clone predicate");
|
||||
assert(PhaseIdealLoop::is_uncommon_trap_if_pattern(cont_proj, reason), "must be a uct if pattern!");
|
||||
assert(cont_proj->is_uncommon_trap_if_pattern(reason), "must be a uct if pattern!");
|
||||
IfNode* iff = cont_proj->in(0)->as_If();
|
||||
|
||||
ProjNode *uncommon_proj = iff->proj_out(1 - cont_proj->_con);
|
||||
@ -422,7 +365,7 @@ Node* PhaseIdealLoop::skip_loop_predicates(Node* entry) {
|
||||
ProjNode* PhaseIdealLoop::find_predicate_insertion_point(Node* start_c, Deoptimization::DeoptReason reason) {
|
||||
if (start_c == NULL || !start_c->is_Proj())
|
||||
return NULL;
|
||||
if (is_uncommon_trap_if_pattern(start_c->as_Proj(), reason)) {
|
||||
if (start_c->as_Proj()->is_uncommon_trap_if_pattern(reason)) {
|
||||
return start_c->as_Proj();
|
||||
}
|
||||
return NULL;
|
||||
@ -773,7 +716,7 @@ bool PhaseIdealLoop::loop_predication_impl(IdealLoopTree *loop) {
|
||||
ProjNode* proj = if_proj_list.pop()->as_Proj();
|
||||
IfNode* iff = proj->in(0)->as_If();
|
||||
|
||||
if (!is_uncommon_trap_if_pattern(proj, Deoptimization::Reason_none)) {
|
||||
if (!proj->is_uncommon_trap_if_pattern(Deoptimization::Reason_none)) {
|
||||
if (loop->is_loop_exit(iff)) {
|
||||
// stop processing the remaining projs in the list because the execution of them
|
||||
// depends on the condition of "iff" (iff->in(1)).
|
||||
|
@ -167,7 +167,7 @@ Node *PhaseIdealLoop::get_early_ctrl_for_expensive(Node *n, Node* earliest) {
|
||||
// expensive nodes will notice the loop and skip over it to try to
|
||||
// move the node further up.
|
||||
if (ctl->is_CountedLoop() && ctl->in(1) != NULL && ctl->in(1)->in(0) != NULL && ctl->in(1)->in(0)->is_If()) {
|
||||
if (!is_uncommon_trap_if_pattern(ctl->in(1)->as_Proj(), Deoptimization::Reason_none)) {
|
||||
if (!ctl->in(1)->as_Proj()->is_uncommon_trap_if_pattern(Deoptimization::Reason_none)) {
|
||||
break;
|
||||
}
|
||||
next = idom(ctl->in(1)->in(0));
|
||||
@ -181,7 +181,7 @@ Node *PhaseIdealLoop::get_early_ctrl_for_expensive(Node *n, Node* earliest) {
|
||||
} else if (parent_ctl->is_CountedLoopEnd() && parent_ctl->as_CountedLoopEnd()->loopnode() != NULL) {
|
||||
next = parent_ctl->as_CountedLoopEnd()->loopnode()->init_control();
|
||||
} else if (parent_ctl->is_If()) {
|
||||
if (!is_uncommon_trap_if_pattern(ctl->as_Proj(), Deoptimization::Reason_none)) {
|
||||
if (!ctl->as_Proj()->is_uncommon_trap_if_pattern(Deoptimization::Reason_none)) {
|
||||
break;
|
||||
}
|
||||
assert(idom(ctl) == parent_ctl, "strange");
|
||||
|
@ -876,13 +876,6 @@ public:
|
||||
// Return true if exp is a scaled induction var plus (or minus) constant
|
||||
bool is_scaled_iv_plus_offset(Node* exp, Node* iv, int* p_scale, Node** p_offset, int depth = 0);
|
||||
|
||||
// Return true if proj is for "proj->[region->..]call_uct"
|
||||
static bool is_uncommon_trap_proj(ProjNode* proj, Deoptimization::DeoptReason reason);
|
||||
// Return true for "if(test)-> proj -> ...
|
||||
// |
|
||||
// V
|
||||
// other_proj->[region->..]call_uct"
|
||||
static bool is_uncommon_trap_if_pattern(ProjNode* proj, Deoptimization::DeoptReason reason);
|
||||
// Create a new if above the uncommon_trap_if_pattern for the predicate to be promoted
|
||||
ProjNode* create_new_if_for_predicate(ProjNode* cont_proj, Node* new_entry,
|
||||
Deoptimization::DeoptReason reason);
|
||||
|
@ -238,7 +238,7 @@ void PhaseIdealLoop::dominated_by( Node *prevdom, Node *iff, bool flip, bool exc
|
||||
ProjNode* dp_proj = dp->as_Proj();
|
||||
ProjNode* unc_proj = iff->as_If()->proj_out(1 - dp_proj->_con)->as_Proj();
|
||||
if (exclude_loop_predicate &&
|
||||
is_uncommon_trap_proj(unc_proj, Deoptimization::Reason_predicate))
|
||||
unc_proj->is_uncommon_trap_proj(Deoptimization::Reason_predicate))
|
||||
return; // Let IGVN transformation change control dependence.
|
||||
|
||||
IdealLoopTree *old_loop = get_loop(dp);
|
||||
|
@ -338,6 +338,7 @@ public:
|
||||
static RegMask modL_proj_mask();
|
||||
|
||||
static const RegMask mathExactI_result_proj_mask();
|
||||
static const RegMask mathExactL_result_proj_mask();
|
||||
static const RegMask mathExactI_flags_proj_mask();
|
||||
|
||||
// Use hardware DIV instruction when it is faster than
|
||||
|
@ -31,10 +31,17 @@
|
||||
#include "opto/mathexactnode.hpp"
|
||||
#include "opto/subnode.hpp"
|
||||
|
||||
MathExactNode::MathExactNode(Node* ctrl, Node* n1, Node* n2) : MultiNode(3) {
|
||||
MathExactNode::MathExactNode(Node* ctrl, Node* in1) : MultiNode(2) {
|
||||
init_class_id(Class_MathExact);
|
||||
init_req(0, ctrl);
|
||||
init_req(1, n1);
|
||||
init_req(2, n2);
|
||||
init_req(1, in1);
|
||||
}
|
||||
|
||||
MathExactNode::MathExactNode(Node* ctrl, Node* in1, Node* in2) : MultiNode(3) {
|
||||
init_class_id(Class_MathExact);
|
||||
init_req(0, ctrl);
|
||||
init_req(1, in1);
|
||||
init_req(2, in2);
|
||||
}
|
||||
|
||||
BoolNode* MathExactNode::bool_node() const {
|
||||
@ -64,23 +71,10 @@ Node* MathExactNode::non_throwing_branch() const {
|
||||
return ifnode->proj_out(1);
|
||||
}
|
||||
|
||||
Node* AddExactINode::match(const ProjNode* proj, const Matcher* m) {
|
||||
uint ideal_reg = proj->ideal_reg();
|
||||
RegMask rm;
|
||||
if (proj->_con == result_proj_node) {
|
||||
rm = m->mathExactI_result_proj_mask();
|
||||
} else {
|
||||
assert(proj->_con == flags_proj_node, "must be result or flags");
|
||||
assert(ideal_reg == Op_RegFlags, "sanity");
|
||||
rm = m->mathExactI_flags_proj_mask();
|
||||
}
|
||||
return new (m->C) MachProjNode(this, proj->_con, rm, ideal_reg);
|
||||
}
|
||||
|
||||
// If the MathExactNode won't overflow we have to replace the
|
||||
// FlagsProjNode and ProjNode that is generated by the MathExactNode
|
||||
Node* MathExactNode::no_overflow(PhaseGVN *phase, Node* new_result) {
|
||||
PhaseIterGVN *igvn = phase->is_IterGVN();
|
||||
Node* MathExactNode::no_overflow(PhaseGVN* phase, Node* new_result) {
|
||||
PhaseIterGVN* igvn = phase->is_IterGVN();
|
||||
if (igvn) {
|
||||
ProjNode* result = result_node();
|
||||
ProjNode* flags = flags_node();
|
||||
@ -110,9 +104,35 @@ Node* MathExactNode::no_overflow(PhaseGVN *phase, Node* new_result) {
|
||||
return new_result;
|
||||
}
|
||||
|
||||
Node *AddExactINode::Ideal(PhaseGVN *phase, bool can_reshape) {
|
||||
Node *arg1 = in(1);
|
||||
Node *arg2 = in(2);
|
||||
Node* MathExactINode::match(const ProjNode* proj, const Matcher* m) {
|
||||
uint ideal_reg = proj->ideal_reg();
|
||||
RegMask rm;
|
||||
if (proj->_con == result_proj_node) {
|
||||
rm = m->mathExactI_result_proj_mask();
|
||||
} else {
|
||||
assert(proj->_con == flags_proj_node, "must be result or flags");
|
||||
assert(ideal_reg == Op_RegFlags, "sanity");
|
||||
rm = m->mathExactI_flags_proj_mask();
|
||||
}
|
||||
return new (m->C) MachProjNode(this, proj->_con, rm, ideal_reg);
|
||||
}
|
||||
|
||||
Node* MathExactLNode::match(const ProjNode* proj, const Matcher* m) {
|
||||
uint ideal_reg = proj->ideal_reg();
|
||||
RegMask rm;
|
||||
if (proj->_con == result_proj_node) {
|
||||
rm = m->mathExactL_result_proj_mask();
|
||||
} else {
|
||||
assert(proj->_con == flags_proj_node, "must be result or flags");
|
||||
assert(ideal_reg == Op_RegFlags, "sanity");
|
||||
rm = m->mathExactI_flags_proj_mask();
|
||||
}
|
||||
return new (m->C) MachProjNode(this, proj->_con, rm, ideal_reg);
|
||||
}
|
||||
|
||||
Node* AddExactINode::Ideal(PhaseGVN* phase, bool can_reshape) {
|
||||
Node* arg1 = in(1);
|
||||
Node* arg2 = in(2);
|
||||
|
||||
const Type* type1 = phase->type(arg1);
|
||||
const Type* type2 = phase->type(arg2);
|
||||
@ -130,12 +150,7 @@ Node *AddExactINode::Ideal(PhaseGVN *phase, bool can_reshape) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (type1 == TypeInt::ZERO) { // (Add 0 x) == x
|
||||
Node* add_result = new (phase->C) AddINode(arg1, arg2);
|
||||
return no_overflow(phase, add_result);
|
||||
}
|
||||
|
||||
if (type2 == TypeInt::ZERO) { // (Add x 0) == x
|
||||
if (type1 == TypeInt::ZERO || type2 == TypeInt::ZERO) { // (Add 0 x) == x
|
||||
Node* add_result = new (phase->C) AddINode(arg1, arg2);
|
||||
return no_overflow(phase, add_result);
|
||||
}
|
||||
@ -169,3 +184,247 @@ Node *AddExactINode::Ideal(PhaseGVN *phase, bool can_reshape) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Node* AddExactLNode::Ideal(PhaseGVN* phase, bool can_reshape) {
|
||||
Node* arg1 = in(1);
|
||||
Node* arg2 = in(2);
|
||||
|
||||
const Type* type1 = phase->type(arg1);
|
||||
const Type* type2 = phase->type(arg2);
|
||||
|
||||
if (type1 != Type::TOP && type1->singleton() &&
|
||||
type2 != Type::TOP && type2->singleton()) {
|
||||
jlong val1 = arg1->get_long();
|
||||
jlong val2 = arg2->get_long();
|
||||
jlong result = val1 + val2;
|
||||
// Hacker's Delight 2-12 Overflow if both arguments have the opposite sign of the result
|
||||
if ( (((val1 ^ result) & (val2 ^ result)) >= 0)) {
|
||||
Node* con_result = ConLNode::make(phase->C, result);
|
||||
return no_overflow(phase, con_result);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (type1 == TypeLong::ZERO || type2 == TypeLong::ZERO) { // (Add 0 x) == x
|
||||
Node* add_result = new (phase->C) AddLNode(arg1, arg2);
|
||||
return no_overflow(phase, add_result);
|
||||
}
|
||||
|
||||
if (type2->singleton()) {
|
||||
return NULL; // no change - keep constant on the right
|
||||
}
|
||||
|
||||
if (type1->singleton()) {
|
||||
// Make it x + Constant - move constant to the right
|
||||
swap_edges(1, 2);
|
||||
return this;
|
||||
}
|
||||
|
||||
if (arg2->is_Load()) {
|
||||
return NULL; // no change - keep load on the right
|
||||
}
|
||||
|
||||
if (arg1->is_Load()) {
|
||||
// Make it x + Load - move load to the right
|
||||
swap_edges(1, 2);
|
||||
return this;
|
||||
}
|
||||
|
||||
if (arg1->_idx > arg2->_idx) {
|
||||
// Sort the edges
|
||||
swap_edges(1, 2);
|
||||
return this;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Node* SubExactINode::Ideal(PhaseGVN* phase, bool can_reshape) {
|
||||
Node* arg1 = in(1);
|
||||
Node* arg2 = in(2);
|
||||
|
||||
const Type* type1 = phase->type(arg1);
|
||||
const Type* type2 = phase->type(arg2);
|
||||
|
||||
if (type1 != Type::TOP && type1->singleton() &&
|
||||
type2 != Type::TOP && type2->singleton()) {
|
||||
jint val1 = arg1->get_int();
|
||||
jint val2 = arg2->get_int();
|
||||
jint result = val1 - val2;
|
||||
|
||||
// Hacker's Delight 2-12 Overflow iff the arguments have different signs and
|
||||
// the sign of the result is different than the sign of arg1
|
||||
if (((val1 ^ val2) & (val1 ^ result)) >= 0) {
|
||||
Node* con_result = ConINode::make(phase->C, result);
|
||||
return no_overflow(phase, con_result);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (type1 == TypeInt::ZERO || type2 == TypeInt::ZERO) {
|
||||
// Sub with zero is the same as add with zero
|
||||
Node* add_result = new (phase->C) AddINode(arg1, arg2);
|
||||
return no_overflow(phase, add_result);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Node* SubExactLNode::Ideal(PhaseGVN* phase, bool can_reshape) {
|
||||
Node* arg1 = in(1);
|
||||
Node* arg2 = in(2);
|
||||
|
||||
const Type* type1 = phase->type(arg1);
|
||||
const Type* type2 = phase->type(arg2);
|
||||
|
||||
if (type1 != Type::TOP && type1->singleton() &&
|
||||
type2 != Type::TOP && type2->singleton()) {
|
||||
jlong val1 = arg1->get_long();
|
||||
jlong val2 = arg2->get_long();
|
||||
jlong result = val1 - val2;
|
||||
|
||||
// Hacker's Delight 2-12 Overflow iff the arguments have different signs and
|
||||
// the sign of the result is different than the sign of arg1
|
||||
if (((val1 ^ val2) & (val1 ^ result)) >= 0) {
|
||||
Node* con_result = ConLNode::make(phase->C, result);
|
||||
return no_overflow(phase, con_result);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (type1 == TypeLong::ZERO || type2 == TypeLong::ZERO) {
|
||||
// Sub with zero is the same as add with zero
|
||||
Node* add_result = new (phase->C) AddLNode(arg1, arg2);
|
||||
return no_overflow(phase, add_result);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Node* NegExactINode::Ideal(PhaseGVN* phase, bool can_reshape) {
|
||||
Node *arg = in(1);
|
||||
|
||||
const Type* type = phase->type(arg);
|
||||
if (type != Type::TOP && type->singleton()) {
|
||||
jint value = arg->get_int();
|
||||
if (value != min_jint) {
|
||||
Node* neg_result = ConINode::make(phase->C, -value);
|
||||
return no_overflow(phase, neg_result);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Node* NegExactLNode::Ideal(PhaseGVN* phase, bool can_reshape) {
|
||||
Node *arg = in(1);
|
||||
|
||||
const Type* type = phase->type(arg);
|
||||
if (type != Type::TOP && type->singleton()) {
|
||||
jlong value = arg->get_long();
|
||||
if (value != min_jlong) {
|
||||
Node* neg_result = ConLNode::make(phase->C, -value);
|
||||
return no_overflow(phase, neg_result);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Node* MulExactINode::Ideal(PhaseGVN* phase, bool can_reshape) {
|
||||
Node* arg1 = in(1);
|
||||
Node* arg2 = in(2);
|
||||
|
||||
const Type* type1 = phase->type(arg1);
|
||||
const Type* type2 = phase->type(arg2);
|
||||
|
||||
if (type1 != Type::TOP && type1->singleton() &&
|
||||
type2 != Type::TOP && type2->singleton()) {
|
||||
jint val1 = arg1->get_int();
|
||||
jint val2 = arg2->get_int();
|
||||
jlong result = (jlong) val1 * (jlong) val2;
|
||||
if ((jint) result == result) {
|
||||
// no overflow
|
||||
Node* mul_result = ConINode::make(phase->C, result);
|
||||
return no_overflow(phase, mul_result);
|
||||
}
|
||||
}
|
||||
|
||||
if (type1 == TypeInt::ZERO || type2 == TypeInt::ZERO) {
|
||||
return no_overflow(phase, ConINode::make(phase->C, 0));
|
||||
}
|
||||
|
||||
if (type1 == TypeInt::ONE) {
|
||||
Node* mul_result = new (phase->C) AddINode(arg2, phase->intcon(0));
|
||||
return no_overflow(phase, mul_result);
|
||||
}
|
||||
if (type2 == TypeInt::ONE) {
|
||||
Node* mul_result = new (phase->C) AddINode(arg1, phase->intcon(0));
|
||||
return no_overflow(phase, mul_result);
|
||||
}
|
||||
|
||||
if (type1 == TypeInt::MINUS_1) {
|
||||
return new (phase->C) NegExactINode(NULL, arg2);
|
||||
}
|
||||
|
||||
if (type2 == TypeInt::MINUS_1) {
|
||||
return new (phase->C) NegExactINode(NULL, arg1);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Node* MulExactLNode::Ideal(PhaseGVN* phase, bool can_reshape) {
|
||||
Node* arg1 = in(1);
|
||||
Node* arg2 = in(2);
|
||||
|
||||
const Type* type1 = phase->type(arg1);
|
||||
const Type* type2 = phase->type(arg2);
|
||||
|
||||
if (type1 != Type::TOP && type1->singleton() &&
|
||||
type2 != Type::TOP && type2->singleton()) {
|
||||
jlong val1 = arg1->get_long();
|
||||
jlong val2 = arg2->get_long();
|
||||
|
||||
jlong result = val1 * val2;
|
||||
jlong ax = (val1 < 0 ? -val1 : val1);
|
||||
jlong ay = (val2 < 0 ? -val2 : val2);
|
||||
|
||||
bool overflow = false;
|
||||
if ((ax | ay) & CONST64(0xFFFFFFFF00000000)) {
|
||||
// potential overflow if any bit in upper 32 bits are set
|
||||
if ((val1 == min_jlong && val2 == -1) || (val2 == min_jlong && val1 == -1)) {
|
||||
// -1 * Long.MIN_VALUE will overflow
|
||||
overflow = true;
|
||||
} else if (val2 != 0 && (result / val2 != val1)) {
|
||||
overflow = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!overflow) {
|
||||
Node* mul_result = ConLNode::make(phase->C, result);
|
||||
return no_overflow(phase, mul_result);
|
||||
}
|
||||
}
|
||||
|
||||
if (type1 == TypeLong::ZERO || type2 == TypeLong::ZERO) {
|
||||
return no_overflow(phase, ConLNode::make(phase->C, 0));
|
||||
}
|
||||
|
||||
if (type1 == TypeLong::ONE) {
|
||||
Node* mul_result = new (phase->C) AddLNode(arg2, phase->longcon(0));
|
||||
return no_overflow(phase, mul_result);
|
||||
}
|
||||
if (type2 == TypeLong::ONE) {
|
||||
Node* mul_result = new (phase->C) AddLNode(arg1, phase->longcon(0));
|
||||
return no_overflow(phase, mul_result);
|
||||
}
|
||||
|
||||
if (type1 == TypeLong::MINUS_1) {
|
||||
return new (phase->C) NegExactLNode(NULL, arg2);
|
||||
}
|
||||
|
||||
if (type2 == TypeLong::MINUS_1) {
|
||||
return new (phase->C) NegExactLNode(NULL, arg1);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -39,6 +39,7 @@ class PhaseTransform;
|
||||
|
||||
class MathExactNode : public MultiNode {
|
||||
public:
|
||||
MathExactNode(Node* ctrl, Node* in1);
|
||||
MathExactNode(Node* ctrl, Node* in1, Node* in2);
|
||||
enum {
|
||||
result_proj_node = 0,
|
||||
@ -62,15 +63,80 @@ protected:
|
||||
Node* no_overflow(PhaseGVN *phase, Node* new_result);
|
||||
};
|
||||
|
||||
class AddExactINode : public MathExactNode {
|
||||
public:
|
||||
AddExactINode(Node* ctrl, Node* in1, Node* in2) : MathExactNode(ctrl, in1, in2) {}
|
||||
class MathExactINode : public MathExactNode {
|
||||
public:
|
||||
MathExactINode(Node* ctrl, Node* in1) : MathExactNode(ctrl, in1) {}
|
||||
MathExactINode(Node* ctrl, Node* in1, Node* in2) : MathExactNode(ctrl, in1, in2) {}
|
||||
virtual int Opcode() const;
|
||||
virtual const Type* bottom_type() const { return TypeTuple::INT_CC_PAIR; }
|
||||
virtual Node* match(const ProjNode* proj, const Matcher* m);
|
||||
virtual const Type* bottom_type() const { return TypeTuple::INT_CC_PAIR; }
|
||||
};
|
||||
|
||||
class MathExactLNode : public MathExactNode {
|
||||
public:
|
||||
MathExactLNode(Node* ctrl, Node* in1) : MathExactNode(ctrl, in1) {}
|
||||
MathExactLNode(Node* ctrl, Node* in1, Node* in2) : MathExactNode(ctrl, in1, in2) {}
|
||||
virtual int Opcode() const;
|
||||
virtual Node* match(const ProjNode* proj, const Matcher* m);
|
||||
virtual const Type* bottom_type() const { return TypeTuple::LONG_CC_PAIR; }
|
||||
};
|
||||
|
||||
class AddExactINode : public MathExactINode {
|
||||
public:
|
||||
AddExactINode(Node* ctrl, Node* in1, Node* in2) : MathExactINode(ctrl, in1, in2) {}
|
||||
virtual int Opcode() const;
|
||||
virtual Node *Ideal(PhaseGVN *phase, bool can_reshape);
|
||||
};
|
||||
|
||||
class AddExactLNode : public MathExactLNode {
|
||||
public:
|
||||
AddExactLNode(Node* ctrl, Node* in1, Node* in2) : MathExactLNode(ctrl, in1, in2) {}
|
||||
virtual int Opcode() const;
|
||||
virtual Node* Ideal(PhaseGVN* phase, bool can_reshape);
|
||||
};
|
||||
|
||||
class SubExactINode : public MathExactINode {
|
||||
public:
|
||||
SubExactINode(Node* ctrl, Node* in1, Node* in2) : MathExactINode(ctrl, in1, in2) {}
|
||||
virtual int Opcode() const;
|
||||
virtual Node* Ideal(PhaseGVN* phase, bool can_reshape);
|
||||
};
|
||||
|
||||
class SubExactLNode : public MathExactLNode {
|
||||
public:
|
||||
SubExactLNode(Node* ctrl, Node* in1, Node* in2) : MathExactLNode(ctrl, in1, in2) {}
|
||||
virtual int Opcode() const;
|
||||
virtual Node* Ideal(PhaseGVN* phase, bool can_reshape);
|
||||
};
|
||||
|
||||
class NegExactINode : public MathExactINode {
|
||||
public:
|
||||
NegExactINode(Node* ctrl, Node* in1) : MathExactINode(ctrl, in1) {}
|
||||
virtual int Opcode() const;
|
||||
virtual Node* Ideal(PhaseGVN* phase, bool can_reshape);
|
||||
};
|
||||
|
||||
class NegExactLNode : public MathExactLNode {
|
||||
public:
|
||||
NegExactLNode(Node* ctrl, Node* in1) : MathExactLNode(ctrl, in1) {}
|
||||
virtual int Opcode() const;
|
||||
virtual Node* Ideal(PhaseGVN* phase, bool can_reshape);
|
||||
};
|
||||
|
||||
class MulExactINode : public MathExactINode {
|
||||
public:
|
||||
MulExactINode(Node* ctrl, Node* in1, Node* in2) : MathExactINode(ctrl, in1, in2) {}
|
||||
virtual int Opcode() const;
|
||||
virtual Node* Ideal(PhaseGVN* phase, bool can_reshape);
|
||||
};
|
||||
|
||||
class MulExactLNode : public MathExactLNode {
|
||||
public:
|
||||
MulExactLNode(Node* ctrl, Node* in1, Node* in2) : MathExactLNode(ctrl, in1, in2) {}
|
||||
virtual int Opcode() const;
|
||||
virtual Node* Ideal(PhaseGVN* phase, bool can_reshape);
|
||||
};
|
||||
|
||||
class FlagsProjNode : public ProjNode {
|
||||
public:
|
||||
FlagsProjNode(Node* src, uint con) : ProjNode(src, con) {
|
||||
|
@ -24,6 +24,7 @@
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "opto/callnode.hpp"
|
||||
#include "opto/cfgnode.hpp"
|
||||
#include "opto/matcher.hpp"
|
||||
#include "opto/mathexactnode.hpp"
|
||||
#include "opto/multnode.hpp"
|
||||
@ -150,3 +151,59 @@ const RegMask &ProjNode::out_RegMask() const {
|
||||
uint ProjNode::ideal_reg() const {
|
||||
return bottom_type()->ideal_reg();
|
||||
}
|
||||
|
||||
//-------------------------------is_uncommon_trap_proj----------------------------
|
||||
// Return true if proj is the form of "proj->[region->..]call_uct"
|
||||
bool ProjNode::is_uncommon_trap_proj(Deoptimization::DeoptReason reason) {
|
||||
int path_limit = 10;
|
||||
Node* out = this;
|
||||
for (int ct = 0; ct < path_limit; ct++) {
|
||||
out = out->unique_ctrl_out();
|
||||
if (out == NULL)
|
||||
return false;
|
||||
if (out->is_CallStaticJava()) {
|
||||
int req = out->as_CallStaticJava()->uncommon_trap_request();
|
||||
if (req != 0) {
|
||||
Deoptimization::DeoptReason trap_reason = Deoptimization::trap_request_reason(req);
|
||||
if (trap_reason == reason || reason == Deoptimization::Reason_none) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false; // don't do further after call
|
||||
}
|
||||
if (out->Opcode() != Op_Region)
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//-------------------------------is_uncommon_trap_if_pattern-------------------------
|
||||
// Return true for "if(test)-> proj -> ...
|
||||
// |
|
||||
// V
|
||||
// other_proj->[region->..]call_uct"
|
||||
//
|
||||
// "must_reason_predicate" means the uct reason must be Reason_predicate
|
||||
bool ProjNode::is_uncommon_trap_if_pattern(Deoptimization::DeoptReason reason) {
|
||||
Node *in0 = in(0);
|
||||
if (!in0->is_If()) return false;
|
||||
// Variation of a dead If node.
|
||||
if (in0->outcnt() < 2) return false;
|
||||
IfNode* iff = in0->as_If();
|
||||
|
||||
// we need "If(Conv2B(Opaque1(...)))" pattern for reason_predicate
|
||||
if (reason != Deoptimization::Reason_none) {
|
||||
if (iff->in(1)->Opcode() != Op_Conv2B ||
|
||||
iff->in(1)->in(1)->Opcode() != Op_Opaque1) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
ProjNode* other_proj = iff->proj_out(1-_con)->as_Proj();
|
||||
if (other_proj->is_uncommon_trap_proj(reason)) {
|
||||
assert(reason == Deoptimization::Reason_none ||
|
||||
Compile::current()->is_predicate_opaq(iff->in(1)->in(1)), "should be on the list");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -88,6 +88,14 @@ public:
|
||||
#ifndef PRODUCT
|
||||
virtual void dump_spec(outputStream *st) const;
|
||||
#endif
|
||||
|
||||
// Return true if proj is for "proj->[region->..]call_uct"
|
||||
bool is_uncommon_trap_proj(Deoptimization::DeoptReason reason);
|
||||
// Return true for "if(test)-> proj -> ...
|
||||
// |
|
||||
// V
|
||||
// other_proj->[region->..]call_uct"
|
||||
bool is_uncommon_trap_if_pattern(Deoptimization::DeoptReason reason);
|
||||
};
|
||||
|
||||
#endif // SHARE_VM_OPTO_MULTNODE_HPP
|
||||
|
@ -100,6 +100,7 @@ class MachSafePointNode;
|
||||
class MachSpillCopyNode;
|
||||
class MachTempNode;
|
||||
class Matcher;
|
||||
class MathExactNode;
|
||||
class MemBarNode;
|
||||
class MemBarStoreStoreNode;
|
||||
class MemNode;
|
||||
@ -568,6 +569,7 @@ public:
|
||||
DEFINE_CLASS_ID(MemBar, Multi, 3)
|
||||
DEFINE_CLASS_ID(Initialize, MemBar, 0)
|
||||
DEFINE_CLASS_ID(MemBarStoreStore, MemBar, 1)
|
||||
DEFINE_CLASS_ID(MathExact, Multi, 4)
|
||||
|
||||
DEFINE_CLASS_ID(Mach, Node, 1)
|
||||
DEFINE_CLASS_ID(MachReturn, Mach, 0)
|
||||
@ -757,6 +759,7 @@ public:
|
||||
DEFINE_CLASS_QUERY(MachSafePoint)
|
||||
DEFINE_CLASS_QUERY(MachSpillCopy)
|
||||
DEFINE_CLASS_QUERY(MachTemp)
|
||||
DEFINE_CLASS_QUERY(MathExact)
|
||||
DEFINE_CLASS_QUERY(Mem)
|
||||
DEFINE_CLASS_QUERY(MemBar)
|
||||
DEFINE_CLASS_QUERY(MemBarStoreStore)
|
||||
|
@ -349,13 +349,15 @@ class Parse : public GraphKit {
|
||||
int _est_switch_depth; // Debugging SwitchRanges.
|
||||
#endif
|
||||
|
||||
// parser for the caller of the method of this object
|
||||
Parse* const _parent;
|
||||
|
||||
public:
|
||||
// Constructor
|
||||
Parse(JVMState* caller, ciMethod* parse_method, float expected_uses);
|
||||
Parse(JVMState* caller, ciMethod* parse_method, float expected_uses, Parse* parent);
|
||||
|
||||
virtual Parse* is_Parse() const { return (Parse*)this; }
|
||||
|
||||
public:
|
||||
// Accessors.
|
||||
JVMState* caller() const { return _caller; }
|
||||
float expected_uses() const { return _expected_uses; }
|
||||
@ -407,6 +409,8 @@ class Parse : public GraphKit {
|
||||
return block()->successor_for_bci(bci);
|
||||
}
|
||||
|
||||
Parse* parent_parser() const { return _parent; }
|
||||
|
||||
private:
|
||||
// Create a JVMS & map for the initial state of this method.
|
||||
SafePointNode* create_entry_map();
|
||||
@ -603,6 +607,9 @@ class Parse : public GraphKit {
|
||||
// Assumes that there is no applicable local handler.
|
||||
void throw_to_exit(SafePointNode* ex_map);
|
||||
|
||||
// Use speculative type to optimize CmpP node
|
||||
Node* optimize_cmp_with_klass(Node* c);
|
||||
|
||||
public:
|
||||
#ifndef PRODUCT
|
||||
// Handle PrintOpto, etc.
|
||||
|
@ -381,8 +381,8 @@ void Parse::load_interpreter_state(Node* osr_buf) {
|
||||
|
||||
//------------------------------Parse------------------------------------------
|
||||
// Main parser constructor.
|
||||
Parse::Parse(JVMState* caller, ciMethod* parse_method, float expected_uses)
|
||||
: _exits(caller)
|
||||
Parse::Parse(JVMState* caller, ciMethod* parse_method, float expected_uses, Parse* parent)
|
||||
: _exits(caller), _parent(parent)
|
||||
{
|
||||
// Init some variables
|
||||
_caller = caller;
|
||||
@ -1102,6 +1102,10 @@ void Parse::do_method_entry() {
|
||||
_synch_lock = shared_lock(lock_obj);
|
||||
}
|
||||
|
||||
// Feed profiling data for parameters to the type system so it can
|
||||
// propagate it as speculative types
|
||||
record_profiled_parameters_for_speculation();
|
||||
|
||||
if (depth() == 1) {
|
||||
increment_and_test_invocation_counter(Tier2CompileThreshold);
|
||||
}
|
||||
|
@ -1366,6 +1366,56 @@ void Parse::sharpen_type_after_if(BoolTest::mask btest,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Use speculative type to optimize CmpP node: if comparison is
|
||||
* against the low level class, cast the object to the speculative
|
||||
* type if any. CmpP should then go away.
|
||||
*
|
||||
* @param c expected CmpP node
|
||||
* @return result of CmpP on object casted to speculative type
|
||||
*
|
||||
*/
|
||||
Node* Parse::optimize_cmp_with_klass(Node* c) {
|
||||
// If this is transformed by the _gvn to a comparison with the low
|
||||
// level klass then we may be able to use speculation
|
||||
if (c->Opcode() == Op_CmpP &&
|
||||
(c->in(1)->Opcode() == Op_LoadKlass || c->in(1)->Opcode() == Op_DecodeNKlass) &&
|
||||
c->in(2)->is_Con()) {
|
||||
Node* load_klass = NULL;
|
||||
Node* decode = NULL;
|
||||
if (c->in(1)->Opcode() == Op_DecodeNKlass) {
|
||||
decode = c->in(1);
|
||||
load_klass = c->in(1)->in(1);
|
||||
} else {
|
||||
load_klass = c->in(1);
|
||||
}
|
||||
if (load_klass->in(2)->is_AddP()) {
|
||||
Node* addp = load_klass->in(2);
|
||||
Node* obj = addp->in(AddPNode::Address);
|
||||
const TypeOopPtr* obj_type = _gvn.type(obj)->is_oopptr();
|
||||
if (obj_type->speculative_type() != NULL) {
|
||||
ciKlass* k = obj_type->speculative_type();
|
||||
inc_sp(2);
|
||||
obj = maybe_cast_profiled_obj(obj, k);
|
||||
dec_sp(2);
|
||||
// Make the CmpP use the casted obj
|
||||
addp = basic_plus_adr(obj, addp->in(AddPNode::Offset));
|
||||
load_klass = load_klass->clone();
|
||||
load_klass->set_req(2, addp);
|
||||
load_klass = _gvn.transform(load_klass);
|
||||
if (decode != NULL) {
|
||||
decode = decode->clone();
|
||||
decode->set_req(1, load_klass);
|
||||
load_klass = _gvn.transform(decode);
|
||||
}
|
||||
c = c->clone();
|
||||
c->set_req(1, load_klass);
|
||||
c = _gvn.transform(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
//------------------------------do_one_bytecode--------------------------------
|
||||
// Parse this bytecode, and alter the Parsers JVM->Node mapping
|
||||
@ -2239,6 +2289,7 @@ void Parse::do_one_bytecode() {
|
||||
a = pop();
|
||||
b = pop();
|
||||
c = _gvn.transform( new (C) CmpPNode(b, a) );
|
||||
c = optimize_cmp_with_klass(c);
|
||||
do_if(btest, c);
|
||||
break;
|
||||
|
||||
|
@ -128,7 +128,7 @@ void Parse::do_instanceof() {
|
||||
}
|
||||
|
||||
// Push the bool result back on stack
|
||||
Node* res = gen_instanceof(peek(), makecon(TypeKlassPtr::make(klass)));
|
||||
Node* res = gen_instanceof(peek(), makecon(TypeKlassPtr::make(klass)), true);
|
||||
|
||||
// Pop from stack AFTER gen_instanceof because it can uncommon trap.
|
||||
pop();
|
||||
|
@ -1385,6 +1385,20 @@ void PhaseIterGVN::add_users_to_worklist( Node *n ) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the speculative part of all types that we know of
|
||||
*/
|
||||
void PhaseIterGVN::remove_speculative_types() {
|
||||
assert(UseTypeSpeculation, "speculation is off");
|
||||
for (uint i = 0; i < _types.Size(); i++) {
|
||||
const Type* t = _types.fast_lookup(i);
|
||||
if (t != NULL && t->isa_oopptr()) {
|
||||
const TypeOopPtr* to = t->is_oopptr();
|
||||
_types.map(i, to->remove_speculative());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
#ifndef PRODUCT
|
||||
uint PhaseCCP::_total_invokes = 0;
|
||||
|
@ -500,6 +500,8 @@ public:
|
||||
ProjNode* create_new_if_for_predicate(ProjNode* cont_proj, Node* new_entry,
|
||||
Deoptimization::DeoptReason reason);
|
||||
|
||||
void remove_speculative_types();
|
||||
|
||||
#ifndef PRODUCT
|
||||
protected:
|
||||
// Sub-quadratic implementation of VerifyIterativeGVN.
|
||||
|
@ -51,15 +51,6 @@
|
||||
|
||||
static const char out_of_nodes[] = "out of nodes during split";
|
||||
|
||||
static bool contains_no_live_range_input(const Node* def) {
|
||||
for (uint i = 1; i < def->req(); ++i) {
|
||||
if (def->in(i) != NULL && def->in_RegMask(i).is_NotEmpty()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//------------------------------get_spillcopy_wide-----------------------------
|
||||
// Get a SpillCopy node with wide-enough masks. Use the 'wide-mask', the
|
||||
// wide ideal-register spill-mask if possible. If the 'wide-mask' does
|
||||
@ -326,12 +317,11 @@ Node *PhaseChaitin::split_Rematerialize( Node *def, Block *b, uint insidx, uint
|
||||
if( def->req() > 1 ) {
|
||||
for( uint i = 1; i < def->req(); i++ ) {
|
||||
Node *in = def->in(i);
|
||||
// Check for single-def (LRG cannot redefined)
|
||||
uint lidx = _lrg_map.live_range_id(in);
|
||||
if (lidx >= _lrg_map.max_lrg_id()) {
|
||||
continue; // Value is a recent spill-copy
|
||||
}
|
||||
if (lrgs(lidx).is_singledef()) {
|
||||
// We do not need this for live ranges that are only defined once.
|
||||
// However, this is not true for spill copies that are added in this
|
||||
// Split() pass, since they might get coalesced later on in this pass.
|
||||
if (lidx < _lrg_map.max_lrg_id() && lrgs(lidx).is_singledef()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -375,7 +365,6 @@ Node *PhaseChaitin::split_Rematerialize( Node *def, Block *b, uint insidx, uint
|
||||
}
|
||||
|
||||
if (lidx < _lrg_map.max_lrg_id() && lrgs(lidx).reg() >= LRG::SPILL_REG) {
|
||||
assert(Reachblock != NULL, "Reachblock must be non-NULL");
|
||||
Node *rdef = Reachblock[lrg2reach[lidx]];
|
||||
if (rdef) {
|
||||
spill->set_req(i, rdef);
|
||||
@ -486,7 +475,6 @@ uint PhaseChaitin::Split(uint maxlrg, ResourceArea* split_arena) {
|
||||
|
||||
uint bidx, pidx, slidx, insidx, inpidx, twoidx;
|
||||
uint non_phi = 1, spill_cnt = 0;
|
||||
Node **Reachblock;
|
||||
Node *n1, *n2, *n3;
|
||||
Node_List *defs,*phis;
|
||||
bool *UPblock;
|
||||
@ -569,7 +557,7 @@ uint PhaseChaitin::Split(uint maxlrg, ResourceArea* split_arena) {
|
||||
|
||||
b = _cfg.get_block(bidx);
|
||||
// Reaches & UP arrays for this block
|
||||
Reachblock = Reaches[b->_pre_order];
|
||||
Node** Reachblock = Reaches[b->_pre_order];
|
||||
UPblock = UP[b->_pre_order];
|
||||
// Reset counter of start of non-Phi nodes in block
|
||||
non_phi = 1;
|
||||
@ -1325,9 +1313,10 @@ uint PhaseChaitin::Split(uint maxlrg, ResourceArea* split_arena) {
|
||||
pidx = pred->_pre_order;
|
||||
// Grab reaching def
|
||||
Node *def = Reaches[pidx][slidx];
|
||||
Node** Reachblock = Reaches[pidx];
|
||||
assert( def, "must have reaching def" );
|
||||
// If input up/down sense and reg-pressure DISagree
|
||||
if (def->rematerialize() && contains_no_live_range_input(def)) {
|
||||
if (def->rematerialize()) {
|
||||
// Place the rematerialized node above any MSCs created during
|
||||
// phi node splitting. end_idx points at the insertion point
|
||||
// so look at the node before it.
|
||||
@ -1337,8 +1326,7 @@ uint PhaseChaitin::Split(uint maxlrg, ResourceArea* split_arena) {
|
||||
_lrg_map.find(pred->get_node(insert - 1)) >= lrgs_before_phi_split) {
|
||||
insert--;
|
||||
}
|
||||
// since the def cannot contain any live range input, we can pass in NULL as Reachlock parameter
|
||||
def = split_Rematerialize(def, pred, insert, maxlrg, splits, slidx, lrg2reach, NULL, false);
|
||||
def = split_Rematerialize(def, pred, insert, maxlrg, splits, slidx, lrg2reach, Reachblock, false);
|
||||
if (!def) {
|
||||
return 0; // Bail out
|
||||
}
|
||||
|
@ -358,7 +358,7 @@ void Type::Initialize_shared(Compile* current) {
|
||||
false, 0, oopDesc::mark_offset_in_bytes());
|
||||
TypeInstPtr::KLASS = TypeInstPtr::make(TypePtr::BotPTR, current->env()->Object_klass(),
|
||||
false, 0, oopDesc::klass_offset_in_bytes());
|
||||
TypeOopPtr::BOTTOM = TypeOopPtr::make(TypePtr::BotPTR, OffsetBot, TypeOopPtr::InstanceBot);
|
||||
TypeOopPtr::BOTTOM = TypeOopPtr::make(TypePtr::BotPTR, OffsetBot, TypeOopPtr::InstanceBot, NULL);
|
||||
|
||||
TypeMetadataPtr::BOTTOM = TypeMetadataPtr::make(TypePtr::BotPTR, NULL, OffsetBot);
|
||||
|
||||
@ -435,6 +435,11 @@ void Type::Initialize_shared(Compile* current) {
|
||||
intccpair[1] = TypeInt::CC;
|
||||
TypeTuple::INT_CC_PAIR = TypeTuple::make(2, intccpair);
|
||||
|
||||
const Type **longccpair = TypeTuple::fields(2);
|
||||
longccpair[0] = TypeLong::LONG;
|
||||
longccpair[1] = TypeInt::CC;
|
||||
TypeTuple::LONG_CC_PAIR = TypeTuple::make(2, longccpair);
|
||||
|
||||
_const_basic_type[T_NARROWOOP] = TypeNarrowOop::BOTTOM;
|
||||
_const_basic_type[T_NARROWKLASS] = Type::BOTTOM;
|
||||
_const_basic_type[T_BOOLEAN] = TypeInt::BOOL;
|
||||
@ -577,7 +582,7 @@ bool Type::is_nan() const {
|
||||
|
||||
//----------------------interface_vs_oop---------------------------------------
|
||||
#ifdef ASSERT
|
||||
bool Type::interface_vs_oop(const Type *t) const {
|
||||
bool Type::interface_vs_oop_helper(const Type *t) const {
|
||||
bool result = false;
|
||||
|
||||
const TypePtr* this_ptr = this->make_ptr(); // In case it is narrow_oop
|
||||
@ -595,6 +600,29 @@ bool Type::interface_vs_oop(const Type *t) const {
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool Type::interface_vs_oop(const Type *t) const {
|
||||
if (interface_vs_oop_helper(t)) {
|
||||
return true;
|
||||
}
|
||||
// Now check the speculative parts as well
|
||||
const TypeOopPtr* this_spec = isa_oopptr() != NULL ? isa_oopptr()->speculative() : NULL;
|
||||
const TypeOopPtr* t_spec = t->isa_oopptr() != NULL ? t->isa_oopptr()->speculative() : NULL;
|
||||
if (this_spec != NULL && t_spec != NULL) {
|
||||
if (this_spec->interface_vs_oop_helper(t_spec)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (this_spec != NULL && this_spec->interface_vs_oop_helper(t)) {
|
||||
return true;
|
||||
}
|
||||
if (t_spec != NULL && interface_vs_oop_helper(t_spec)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
//------------------------------meet-------------------------------------------
|
||||
@ -1652,6 +1680,7 @@ const TypeTuple *TypeTuple::START_I2C;
|
||||
const TypeTuple *TypeTuple::INT_PAIR;
|
||||
const TypeTuple *TypeTuple::LONG_PAIR;
|
||||
const TypeTuple *TypeTuple::INT_CC_PAIR;
|
||||
const TypeTuple *TypeTuple::LONG_CC_PAIR;
|
||||
|
||||
|
||||
//------------------------------make-------------------------------------------
|
||||
@ -2407,14 +2436,15 @@ void TypeRawPtr::dump2( Dict &d, uint depth, outputStream *st ) const {
|
||||
const TypeOopPtr *TypeOopPtr::BOTTOM;
|
||||
|
||||
//------------------------------TypeOopPtr-------------------------------------
|
||||
TypeOopPtr::TypeOopPtr( TYPES t, PTR ptr, ciKlass* k, bool xk, ciObject* o, int offset, int instance_id )
|
||||
TypeOopPtr::TypeOopPtr(TYPES t, PTR ptr, ciKlass* k, bool xk, ciObject* o, int offset, int instance_id, const TypeOopPtr* speculative)
|
||||
: TypePtr(t, ptr, offset),
|
||||
_const_oop(o), _klass(k),
|
||||
_klass_is_exact(xk),
|
||||
_is_ptr_to_narrowoop(false),
|
||||
_is_ptr_to_narrowklass(false),
|
||||
_is_ptr_to_boxed_value(false),
|
||||
_instance_id(instance_id) {
|
||||
_instance_id(instance_id),
|
||||
_speculative(speculative) {
|
||||
if (Compile::current()->eliminate_boxing() && (t == InstPtr) &&
|
||||
(offset > 0) && xk && (k != 0) && k->is_instance_klass()) {
|
||||
_is_ptr_to_boxed_value = k->as_instance_klass()->is_boxed_value_offset(offset);
|
||||
@ -2481,12 +2511,12 @@ TypeOopPtr::TypeOopPtr( TYPES t, PTR ptr, ciKlass* k, bool xk, ciObject* o, int
|
||||
|
||||
//------------------------------make-------------------------------------------
|
||||
const TypeOopPtr *TypeOopPtr::make(PTR ptr,
|
||||
int offset, int instance_id) {
|
||||
int offset, int instance_id, const TypeOopPtr* speculative) {
|
||||
assert(ptr != Constant, "no constant generic pointers");
|
||||
ciKlass* k = Compile::current()->env()->Object_klass();
|
||||
bool xk = false;
|
||||
ciObject* o = NULL;
|
||||
return (TypeOopPtr*)(new TypeOopPtr(OopPtr, ptr, k, xk, o, offset, instance_id))->hashcons();
|
||||
return (TypeOopPtr*)(new TypeOopPtr(OopPtr, ptr, k, xk, o, offset, instance_id, speculative))->hashcons();
|
||||
}
|
||||
|
||||
|
||||
@ -2494,7 +2524,7 @@ const TypeOopPtr *TypeOopPtr::make(PTR ptr,
|
||||
const Type *TypeOopPtr::cast_to_ptr_type(PTR ptr) const {
|
||||
assert(_base == OopPtr, "subclass must override cast_to_ptr_type");
|
||||
if( ptr == _ptr ) return this;
|
||||
return make(ptr, _offset, _instance_id);
|
||||
return make(ptr, _offset, _instance_id, _speculative);
|
||||
}
|
||||
|
||||
//-----------------------------cast_to_instance_id----------------------------
|
||||
@ -2524,10 +2554,31 @@ const TypeKlassPtr* TypeOopPtr::as_klass_type() const {
|
||||
return TypeKlassPtr::make(xk? Constant: NotNull, k, 0);
|
||||
}
|
||||
|
||||
const Type *TypeOopPtr::xmeet(const Type *t) const {
|
||||
const Type* res = xmeet_helper(t);
|
||||
if (res->isa_oopptr() == NULL) {
|
||||
return res;
|
||||
}
|
||||
|
||||
if (res->isa_oopptr() != NULL) {
|
||||
// type->speculative() == NULL means that speculation is no better
|
||||
// than type, i.e. type->speculative() == type. So there are 2
|
||||
// ways to represent the fact that we have no useful speculative
|
||||
// data and we should use a single one to be able to test for
|
||||
// equality between types. Check whether type->speculative() ==
|
||||
// type and set speculative to NULL if it is the case.
|
||||
const TypeOopPtr* res_oopptr = res->is_oopptr();
|
||||
if (res_oopptr->remove_speculative() == res_oopptr->speculative()) {
|
||||
return res_oopptr->remove_speculative();
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
//------------------------------meet-------------------------------------------
|
||||
// Compute the MEET of two types. It returns a new Type object.
|
||||
const Type *TypeOopPtr::xmeet( const Type *t ) const {
|
||||
const Type *TypeOopPtr::xmeet_helper(const Type *t) const {
|
||||
// Perform a fast test for common case; meeting the same types together.
|
||||
if( this == t ) return this; // Meeting same type-rep?
|
||||
|
||||
@ -2569,7 +2620,8 @@ const Type *TypeOopPtr::xmeet( const Type *t ) const {
|
||||
case TopPTR:
|
||||
case AnyNull: {
|
||||
int instance_id = meet_instance_id(InstanceTop);
|
||||
return make(ptr, offset, instance_id);
|
||||
const TypeOopPtr* speculative = _speculative;
|
||||
return make(ptr, offset, instance_id, speculative);
|
||||
}
|
||||
case BotPTR:
|
||||
case NotNull:
|
||||
@ -2581,7 +2633,8 @@ const Type *TypeOopPtr::xmeet( const Type *t ) const {
|
||||
case OopPtr: { // Meeting to other OopPtrs
|
||||
const TypeOopPtr *tp = t->is_oopptr();
|
||||
int instance_id = meet_instance_id(tp->instance_id());
|
||||
return make( meet_ptr(tp->ptr()), meet_offset(tp->offset()), instance_id );
|
||||
const TypeOopPtr* speculative = meet_speculative(tp);
|
||||
return make(meet_ptr(tp->ptr()), meet_offset(tp->offset()), instance_id, speculative);
|
||||
}
|
||||
|
||||
case InstPtr: // For these, flip the call around to cut down
|
||||
@ -2598,7 +2651,7 @@ const Type *TypeOopPtr::xmeet( const Type *t ) const {
|
||||
const Type *TypeOopPtr::xdual() const {
|
||||
assert(klass() == Compile::current()->env()->Object_klass(), "no klasses here");
|
||||
assert(const_oop() == NULL, "no constants here");
|
||||
return new TypeOopPtr(_base, dual_ptr(), klass(), klass_is_exact(), const_oop(), dual_offset(), dual_instance_id() );
|
||||
return new TypeOopPtr(_base, dual_ptr(), klass(), klass_is_exact(), const_oop(), dual_offset(), dual_instance_id(), dual_speculative());
|
||||
}
|
||||
|
||||
//--------------------------make_from_klass_common-----------------------------
|
||||
@ -2689,7 +2742,7 @@ const TypeOopPtr* TypeOopPtr::make_from_constant(ciObject* o,
|
||||
} else if (!o->should_be_constant()) {
|
||||
return TypeAryPtr::make(TypePtr::NotNull, arr0, klass, true, 0);
|
||||
}
|
||||
const TypeAryPtr* arr = TypeAryPtr::make(TypePtr::Constant, o, arr0, klass, true, 0, InstanceBot, is_autobox_cache);
|
||||
const TypeAryPtr* arr = TypeAryPtr::make(TypePtr::Constant, o, arr0, klass, true, 0, InstanceBot, NULL, is_autobox_cache);
|
||||
return arr;
|
||||
} else if (klass->is_type_array_klass()) {
|
||||
// Element is an typeArray
|
||||
@ -2789,7 +2842,8 @@ const Type *TypeOopPtr::filter( const Type *kills ) const {
|
||||
bool TypeOopPtr::eq( const Type *t ) const {
|
||||
const TypeOopPtr *a = (const TypeOopPtr*)t;
|
||||
if (_klass_is_exact != a->_klass_is_exact ||
|
||||
_instance_id != a->_instance_id) return false;
|
||||
_instance_id != a->_instance_id ||
|
||||
!eq_speculative(a)) return false;
|
||||
ciObject* one = const_oop();
|
||||
ciObject* two = a->const_oop();
|
||||
if (one == NULL || two == NULL) {
|
||||
@ -2806,6 +2860,7 @@ int TypeOopPtr::hash(void) const {
|
||||
(const_oop() ? const_oop()->hash() : 0) +
|
||||
_klass_is_exact +
|
||||
_instance_id +
|
||||
hash_speculative() +
|
||||
TypePtr::hash();
|
||||
}
|
||||
|
||||
@ -2825,6 +2880,19 @@ void TypeOopPtr::dump2( Dict &d, uint depth, outputStream *st ) const {
|
||||
st->print(",iid=top");
|
||||
else if (_instance_id != InstanceBot)
|
||||
st->print(",iid=%d",_instance_id);
|
||||
|
||||
dump_speculative(st);
|
||||
}
|
||||
|
||||
/**
|
||||
*dump the speculative part of the type
|
||||
*/
|
||||
void TypeOopPtr::dump_speculative(outputStream *st) const {
|
||||
if (_speculative != NULL) {
|
||||
st->print(" (speculative=");
|
||||
_speculative->dump_on(st);
|
||||
st->print(")");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -2838,8 +2906,15 @@ bool TypeOopPtr::singleton(void) const {
|
||||
}
|
||||
|
||||
//------------------------------add_offset-------------------------------------
|
||||
const TypePtr *TypeOopPtr::add_offset( intptr_t offset ) const {
|
||||
return make( _ptr, xadd_offset(offset), _instance_id);
|
||||
const TypePtr *TypeOopPtr::add_offset(intptr_t offset) const {
|
||||
return make(_ptr, xadd_offset(offset), _instance_id, add_offset_speculative(offset));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return same type without a speculative part
|
||||
*/
|
||||
const TypeOopPtr* TypeOopPtr::remove_speculative() const {
|
||||
return make(_ptr, _offset, _instance_id, NULL);
|
||||
}
|
||||
|
||||
//------------------------------meet_instance_id--------------------------------
|
||||
@ -2859,6 +2934,89 @@ int TypeOopPtr::dual_instance_id( ) const {
|
||||
return _instance_id; // Map everything else into self
|
||||
}
|
||||
|
||||
/**
|
||||
* meet of the speculative parts of 2 types
|
||||
*
|
||||
* @param other type to meet with
|
||||
*/
|
||||
const TypeOopPtr* TypeOopPtr::meet_speculative(const TypeOopPtr* other) const {
|
||||
bool this_has_spec = (_speculative != NULL);
|
||||
bool other_has_spec = (other->speculative() != NULL);
|
||||
|
||||
if (!this_has_spec && !other_has_spec) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// If we are at a point where control flow meets and one branch has
|
||||
// a speculative type and the other has not, we meet the speculative
|
||||
// type of one branch with the actual type of the other. If the
|
||||
// actual type is exact and the speculative is as well, then the
|
||||
// result is a speculative type which is exact and we can continue
|
||||
// speculation further.
|
||||
const TypeOopPtr* this_spec = _speculative;
|
||||
const TypeOopPtr* other_spec = other->speculative();
|
||||
|
||||
if (!this_has_spec) {
|
||||
this_spec = this;
|
||||
}
|
||||
|
||||
if (!other_has_spec) {
|
||||
other_spec = other;
|
||||
}
|
||||
|
||||
return this_spec->meet(other_spec)->is_oopptr();
|
||||
}
|
||||
|
||||
/**
|
||||
* dual of the speculative part of the type
|
||||
*/
|
||||
const TypeOopPtr* TypeOopPtr::dual_speculative() const {
|
||||
if (_speculative == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
return _speculative->dual()->is_oopptr();
|
||||
}
|
||||
|
||||
/**
|
||||
* add offset to the speculative part of the type
|
||||
*
|
||||
* @param offset offset to add
|
||||
*/
|
||||
const TypeOopPtr* TypeOopPtr::add_offset_speculative(intptr_t offset) const {
|
||||
if (_speculative == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
return _speculative->add_offset(offset)->is_oopptr();
|
||||
}
|
||||
|
||||
/**
|
||||
* Are the speculative parts of 2 types equal?
|
||||
*
|
||||
* @param other type to compare this one to
|
||||
*/
|
||||
bool TypeOopPtr::eq_speculative(const TypeOopPtr* other) const {
|
||||
if (_speculative == NULL || other->speculative() == NULL) {
|
||||
return _speculative == other->speculative();
|
||||
}
|
||||
|
||||
if (_speculative->base() != other->speculative()->base()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return _speculative->eq(other->speculative());
|
||||
}
|
||||
|
||||
/**
|
||||
* Hash of the speculative part of the type
|
||||
*/
|
||||
int TypeOopPtr::hash_speculative() const {
|
||||
if (_speculative == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return _speculative->hash();
|
||||
}
|
||||
|
||||
|
||||
//=============================================================================
|
||||
// Convenience common pre-built types.
|
||||
@ -2869,8 +3027,8 @@ const TypeInstPtr *TypeInstPtr::MARK;
|
||||
const TypeInstPtr *TypeInstPtr::KLASS;
|
||||
|
||||
//------------------------------TypeInstPtr-------------------------------------
|
||||
TypeInstPtr::TypeInstPtr(PTR ptr, ciKlass* k, bool xk, ciObject* o, int off, int instance_id)
|
||||
: TypeOopPtr(InstPtr, ptr, k, xk, o, off, instance_id), _name(k->name()) {
|
||||
TypeInstPtr::TypeInstPtr(PTR ptr, ciKlass* k, bool xk, ciObject* o, int off, int instance_id, const TypeOopPtr* speculative)
|
||||
: TypeOopPtr(InstPtr, ptr, k, xk, o, off, instance_id, speculative), _name(k->name()) {
|
||||
assert(k != NULL &&
|
||||
(k->is_loaded() || o == NULL),
|
||||
"cannot have constants with non-loaded klass");
|
||||
@ -2882,7 +3040,8 @@ const TypeInstPtr *TypeInstPtr::make(PTR ptr,
|
||||
bool xk,
|
||||
ciObject* o,
|
||||
int offset,
|
||||
int instance_id) {
|
||||
int instance_id,
|
||||
const TypeOopPtr* speculative) {
|
||||
assert( !k->is_loaded() || k->is_instance_klass(), "Must be for instance");
|
||||
// Either const_oop() is NULL or else ptr is Constant
|
||||
assert( (!o && ptr != Constant) || (o && ptr == Constant),
|
||||
@ -2903,7 +3062,7 @@ const TypeInstPtr *TypeInstPtr::make(PTR ptr,
|
||||
|
||||
// Now hash this baby
|
||||
TypeInstPtr *result =
|
||||
(TypeInstPtr*)(new TypeInstPtr(ptr, k, xk, o ,offset, instance_id))->hashcons();
|
||||
(TypeInstPtr*)(new TypeInstPtr(ptr, k, xk, o ,offset, instance_id, speculative))->hashcons();
|
||||
|
||||
return result;
|
||||
}
|
||||
@ -2936,7 +3095,7 @@ const Type *TypeInstPtr::cast_to_ptr_type(PTR ptr) const {
|
||||
if( ptr == _ptr ) return this;
|
||||
// Reconstruct _sig info here since not a problem with later lazy
|
||||
// construction, _sig will show up on demand.
|
||||
return make(ptr, klass(), klass_is_exact(), const_oop(), _offset, _instance_id);
|
||||
return make(ptr, klass(), klass_is_exact(), const_oop(), _offset, _instance_id, _speculative);
|
||||
}
|
||||
|
||||
|
||||
@ -2948,13 +3107,13 @@ const Type *TypeInstPtr::cast_to_exactness(bool klass_is_exact) const {
|
||||
ciInstanceKlass* ik = _klass->as_instance_klass();
|
||||
if( (ik->is_final() || _const_oop) ) return this; // cannot clear xk
|
||||
if( ik->is_interface() ) return this; // cannot set xk
|
||||
return make(ptr(), klass(), klass_is_exact, const_oop(), _offset, _instance_id);
|
||||
return make(ptr(), klass(), klass_is_exact, const_oop(), _offset, _instance_id, _speculative);
|
||||
}
|
||||
|
||||
//-----------------------------cast_to_instance_id----------------------------
|
||||
const TypeOopPtr *TypeInstPtr::cast_to_instance_id(int instance_id) const {
|
||||
if( instance_id == _instance_id ) return this;
|
||||
return make(_ptr, klass(), _klass_is_exact, const_oop(), _offset, instance_id);
|
||||
return make(_ptr, klass(), _klass_is_exact, const_oop(), _offset, instance_id, _speculative);
|
||||
}
|
||||
|
||||
//------------------------------xmeet_unloaded---------------------------------
|
||||
@ -2964,6 +3123,7 @@ const TypeInstPtr *TypeInstPtr::xmeet_unloaded(const TypeInstPtr *tinst) const {
|
||||
int off = meet_offset(tinst->offset());
|
||||
PTR ptr = meet_ptr(tinst->ptr());
|
||||
int instance_id = meet_instance_id(tinst->instance_id());
|
||||
const TypeOopPtr* speculative = meet_speculative(tinst);
|
||||
|
||||
const TypeInstPtr *loaded = is_loaded() ? this : tinst;
|
||||
const TypeInstPtr *unloaded = is_loaded() ? tinst : this;
|
||||
@ -2984,7 +3144,7 @@ const TypeInstPtr *TypeInstPtr::xmeet_unloaded(const TypeInstPtr *tinst) const {
|
||||
assert(loaded->ptr() != TypePtr::Null, "insanity check");
|
||||
//
|
||||
if( loaded->ptr() == TypePtr::TopPTR ) { return unloaded; }
|
||||
else if (loaded->ptr() == TypePtr::AnyNull) { return TypeInstPtr::make( ptr, unloaded->klass(), false, NULL, off, instance_id ); }
|
||||
else if (loaded->ptr() == TypePtr::AnyNull) { return TypeInstPtr::make(ptr, unloaded->klass(), false, NULL, off, instance_id, speculative); }
|
||||
else if (loaded->ptr() == TypePtr::BotPTR ) { return TypeInstPtr::BOTTOM; }
|
||||
else if (loaded->ptr() == TypePtr::Constant || loaded->ptr() == TypePtr::NotNull) {
|
||||
if (unloaded->ptr() == TypePtr::BotPTR ) { return TypeInstPtr::BOTTOM; }
|
||||
@ -3006,7 +3166,7 @@ const TypeInstPtr *TypeInstPtr::xmeet_unloaded(const TypeInstPtr *tinst) const {
|
||||
|
||||
//------------------------------meet-------------------------------------------
|
||||
// Compute the MEET of two types. It returns a new Type object.
|
||||
const Type *TypeInstPtr::xmeet( const Type *t ) const {
|
||||
const Type *TypeInstPtr::xmeet_helper(const Type *t) const {
|
||||
// Perform a fast test for common case; meeting the same types together.
|
||||
if( this == t ) return this; // Meeting same type-rep?
|
||||
|
||||
@ -3040,16 +3200,20 @@ const Type *TypeInstPtr::xmeet( const Type *t ) const {
|
||||
int offset = meet_offset(tp->offset());
|
||||
PTR ptr = meet_ptr(tp->ptr());
|
||||
int instance_id = meet_instance_id(tp->instance_id());
|
||||
const TypeOopPtr* speculative = meet_speculative(tp);
|
||||
switch (ptr) {
|
||||
case TopPTR:
|
||||
case AnyNull: // Fall 'down' to dual of object klass
|
||||
if (klass()->equals(ciEnv::current()->Object_klass())) {
|
||||
return TypeAryPtr::make(ptr, tp->ary(), tp->klass(), tp->klass_is_exact(), offset, instance_id);
|
||||
// For instances when a subclass meets a superclass we fall
|
||||
// below the centerline when the superclass is exact. We need to
|
||||
// do the same here.
|
||||
if (klass()->equals(ciEnv::current()->Object_klass()) && !klass_is_exact()) {
|
||||
return TypeAryPtr::make(ptr, tp->ary(), tp->klass(), tp->klass_is_exact(), offset, instance_id, speculative);
|
||||
} else {
|
||||
// cannot subclass, so the meet has to fall badly below the centerline
|
||||
ptr = NotNull;
|
||||
instance_id = InstanceBot;
|
||||
return TypeInstPtr::make( ptr, ciEnv::current()->Object_klass(), false, NULL, offset, instance_id);
|
||||
return TypeInstPtr::make( ptr, ciEnv::current()->Object_klass(), false, NULL, offset, instance_id, speculative);
|
||||
}
|
||||
case Constant:
|
||||
case NotNull:
|
||||
@ -3058,10 +3222,13 @@ const Type *TypeInstPtr::xmeet( const Type *t ) const {
|
||||
if( above_centerline(_ptr) ) { // if( _ptr == TopPTR || _ptr == AnyNull )
|
||||
// If 'this' (InstPtr) is above the centerline and it is Object class
|
||||
// then we can subclass in the Java class hierarchy.
|
||||
if (klass()->equals(ciEnv::current()->Object_klass())) {
|
||||
// For instances when a subclass meets a superclass we fall
|
||||
// below the centerline when the superclass is exact. We need
|
||||
// to do the same here.
|
||||
if (klass()->equals(ciEnv::current()->Object_klass()) && !klass_is_exact()) {
|
||||
// that is, tp's array type is a subtype of my klass
|
||||
return TypeAryPtr::make(ptr, (ptr == Constant ? tp->const_oop() : NULL),
|
||||
tp->ary(), tp->klass(), tp->klass_is_exact(), offset, instance_id);
|
||||
tp->ary(), tp->klass(), tp->klass_is_exact(), offset, instance_id, speculative);
|
||||
}
|
||||
}
|
||||
// The other case cannot happen, since I cannot be a subtype of an array.
|
||||
@ -3069,7 +3236,7 @@ const Type *TypeInstPtr::xmeet( const Type *t ) const {
|
||||
if( ptr == Constant )
|
||||
ptr = NotNull;
|
||||
instance_id = InstanceBot;
|
||||
return make( ptr, ciEnv::current()->Object_klass(), false, NULL, offset, instance_id );
|
||||
return make(ptr, ciEnv::current()->Object_klass(), false, NULL, offset, instance_id, speculative);
|
||||
default: typerr(t);
|
||||
}
|
||||
}
|
||||
@ -3083,13 +3250,15 @@ const Type *TypeInstPtr::xmeet( const Type *t ) const {
|
||||
case TopPTR:
|
||||
case AnyNull: {
|
||||
int instance_id = meet_instance_id(InstanceTop);
|
||||
const TypeOopPtr* speculative = meet_speculative(tp);
|
||||
return make(ptr, klass(), klass_is_exact(),
|
||||
(ptr == Constant ? const_oop() : NULL), offset, instance_id);
|
||||
(ptr == Constant ? const_oop() : NULL), offset, instance_id, speculative);
|
||||
}
|
||||
case NotNull:
|
||||
case BotPTR: {
|
||||
int instance_id = meet_instance_id(tp->instance_id());
|
||||
return TypeOopPtr::make(ptr, offset, instance_id);
|
||||
const TypeOopPtr* speculative = meet_speculative(tp);
|
||||
return TypeOopPtr::make(ptr, offset, instance_id, speculative);
|
||||
}
|
||||
default: typerr(t);
|
||||
}
|
||||
@ -3102,17 +3271,18 @@ const Type *TypeInstPtr::xmeet( const Type *t ) const {
|
||||
PTR ptr = meet_ptr(tp->ptr());
|
||||
switch (tp->ptr()) {
|
||||
case Null:
|
||||
if( ptr == Null ) return TypePtr::make( AnyPtr, ptr, offset );
|
||||
if( ptr == Null ) return TypePtr::make(AnyPtr, ptr, offset);
|
||||
// else fall through to AnyNull
|
||||
case TopPTR:
|
||||
case AnyNull: {
|
||||
int instance_id = meet_instance_id(InstanceTop);
|
||||
return make( ptr, klass(), klass_is_exact(),
|
||||
(ptr == Constant ? const_oop() : NULL), offset, instance_id);
|
||||
const TypeOopPtr* speculative = _speculative;
|
||||
return make(ptr, klass(), klass_is_exact(),
|
||||
(ptr == Constant ? const_oop() : NULL), offset, instance_id, speculative);
|
||||
}
|
||||
case NotNull:
|
||||
case BotPTR:
|
||||
return TypePtr::make( AnyPtr, ptr, offset );
|
||||
return TypePtr::make(AnyPtr, ptr, offset);
|
||||
default: typerr(t);
|
||||
}
|
||||
}
|
||||
@ -3139,13 +3309,14 @@ const Type *TypeInstPtr::xmeet( const Type *t ) const {
|
||||
int off = meet_offset( tinst->offset() );
|
||||
PTR ptr = meet_ptr( tinst->ptr() );
|
||||
int instance_id = meet_instance_id(tinst->instance_id());
|
||||
const TypeOopPtr* speculative = meet_speculative(tinst);
|
||||
|
||||
// Check for easy case; klasses are equal (and perhaps not loaded!)
|
||||
// If we have constants, then we created oops so classes are loaded
|
||||
// and we can handle the constants further down. This case handles
|
||||
// both-not-loaded or both-loaded classes
|
||||
if (ptr != Constant && klass()->equals(tinst->klass()) && klass_is_exact() == tinst->klass_is_exact()) {
|
||||
return make( ptr, klass(), klass_is_exact(), NULL, off, instance_id );
|
||||
return make(ptr, klass(), klass_is_exact(), NULL, off, instance_id, speculative);
|
||||
}
|
||||
|
||||
// Classes require inspection in the Java klass hierarchy. Must be loaded.
|
||||
@ -3167,7 +3338,8 @@ const Type *TypeInstPtr::xmeet( const Type *t ) const {
|
||||
}
|
||||
|
||||
// Handle mixing oops and interfaces first.
|
||||
if( this_klass->is_interface() && !tinst_klass->is_interface() ) {
|
||||
if( this_klass->is_interface() && !(tinst_klass->is_interface() ||
|
||||
tinst_klass == ciEnv::current()->Object_klass())) {
|
||||
ciKlass *tmp = tinst_klass; // Swap interface around
|
||||
tinst_klass = this_klass;
|
||||
this_klass = tmp;
|
||||
@ -3208,7 +3380,7 @@ const Type *TypeInstPtr::xmeet( const Type *t ) const {
|
||||
// Find out which constant.
|
||||
o = (this_klass == klass()) ? const_oop() : tinst->const_oop();
|
||||
}
|
||||
return make( ptr, k, xk, o, off, instance_id );
|
||||
return make(ptr, k, xk, o, off, instance_id, speculative);
|
||||
}
|
||||
|
||||
// Either oop vs oop or interface vs interface or interface vs Object
|
||||
@ -3285,7 +3457,7 @@ const Type *TypeInstPtr::xmeet( const Type *t ) const {
|
||||
else
|
||||
ptr = NotNull;
|
||||
}
|
||||
return make( ptr, this_klass, this_xk, o, off, instance_id );
|
||||
return make(ptr, this_klass, this_xk, o, off, instance_id, speculative);
|
||||
} // Else classes are not equal
|
||||
|
||||
// Since klasses are different, we require a LCA in the Java
|
||||
@ -3296,7 +3468,7 @@ const Type *TypeInstPtr::xmeet( const Type *t ) const {
|
||||
|
||||
// Now we find the LCA of Java classes
|
||||
ciKlass* k = this_klass->least_common_ancestor(tinst_klass);
|
||||
return make( ptr, k, false, NULL, off, instance_id );
|
||||
return make(ptr, k, false, NULL, off, instance_id, speculative);
|
||||
} // End of case InstPtr
|
||||
|
||||
} // End of switch
|
||||
@ -3320,7 +3492,7 @@ ciType* TypeInstPtr::java_mirror_type() const {
|
||||
// Dual: do NOT dual on klasses. This means I do NOT understand the Java
|
||||
// inheritance mechanism.
|
||||
const Type *TypeInstPtr::xdual() const {
|
||||
return new TypeInstPtr( dual_ptr(), klass(), klass_is_exact(), const_oop(), dual_offset(), dual_instance_id() );
|
||||
return new TypeInstPtr(dual_ptr(), klass(), klass_is_exact(), const_oop(), dual_offset(), dual_instance_id(), dual_speculative());
|
||||
}
|
||||
|
||||
//------------------------------eq---------------------------------------------
|
||||
@ -3376,12 +3548,18 @@ void TypeInstPtr::dump2( Dict &d, uint depth, outputStream *st ) const {
|
||||
st->print(",iid=top");
|
||||
else if (_instance_id != InstanceBot)
|
||||
st->print(",iid=%d",_instance_id);
|
||||
|
||||
dump_speculative(st);
|
||||
}
|
||||
#endif
|
||||
|
||||
//------------------------------add_offset-------------------------------------
|
||||
const TypePtr *TypeInstPtr::add_offset( intptr_t offset ) const {
|
||||
return make( _ptr, klass(), klass_is_exact(), const_oop(), xadd_offset(offset), _instance_id );
|
||||
const TypePtr *TypeInstPtr::add_offset(intptr_t offset) const {
|
||||
return make(_ptr, klass(), klass_is_exact(), const_oop(), xadd_offset(offset), _instance_id, add_offset_speculative(offset));
|
||||
}
|
||||
|
||||
const TypeOopPtr *TypeInstPtr::remove_speculative() const {
|
||||
return make(_ptr, klass(), klass_is_exact(), const_oop(), _offset, _instance_id, NULL);
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
@ -3398,30 +3576,30 @@ const TypeAryPtr *TypeAryPtr::FLOATS;
|
||||
const TypeAryPtr *TypeAryPtr::DOUBLES;
|
||||
|
||||
//------------------------------make-------------------------------------------
|
||||
const TypeAryPtr *TypeAryPtr::make( PTR ptr, const TypeAry *ary, ciKlass* k, bool xk, int offset, int instance_id ) {
|
||||
const TypeAryPtr *TypeAryPtr::make(PTR ptr, const TypeAry *ary, ciKlass* k, bool xk, int offset, int instance_id, const TypeOopPtr* speculative) {
|
||||
assert(!(k == NULL && ary->_elem->isa_int()),
|
||||
"integral arrays must be pre-equipped with a class");
|
||||
if (!xk) xk = ary->ary_must_be_exact();
|
||||
assert(instance_id <= 0 || xk || !UseExactTypes, "instances are always exactly typed");
|
||||
if (!UseExactTypes) xk = (ptr == Constant);
|
||||
return (TypeAryPtr*)(new TypeAryPtr(ptr, NULL, ary, k, xk, offset, instance_id, false))->hashcons();
|
||||
return (TypeAryPtr*)(new TypeAryPtr(ptr, NULL, ary, k, xk, offset, instance_id, false, speculative))->hashcons();
|
||||
}
|
||||
|
||||
//------------------------------make-------------------------------------------
|
||||
const TypeAryPtr *TypeAryPtr::make( PTR ptr, ciObject* o, const TypeAry *ary, ciKlass* k, bool xk, int offset, int instance_id, bool is_autobox_cache) {
|
||||
const TypeAryPtr *TypeAryPtr::make(PTR ptr, ciObject* o, const TypeAry *ary, ciKlass* k, bool xk, int offset, int instance_id, const TypeOopPtr* speculative, bool is_autobox_cache) {
|
||||
assert(!(k == NULL && ary->_elem->isa_int()),
|
||||
"integral arrays must be pre-equipped with a class");
|
||||
assert( (ptr==Constant && o) || (ptr!=Constant && !o), "" );
|
||||
if (!xk) xk = (o != NULL) || ary->ary_must_be_exact();
|
||||
assert(instance_id <= 0 || xk || !UseExactTypes, "instances are always exactly typed");
|
||||
if (!UseExactTypes) xk = (ptr == Constant);
|
||||
return (TypeAryPtr*)(new TypeAryPtr(ptr, o, ary, k, xk, offset, instance_id, is_autobox_cache))->hashcons();
|
||||
return (TypeAryPtr*)(new TypeAryPtr(ptr, o, ary, k, xk, offset, instance_id, is_autobox_cache, speculative))->hashcons();
|
||||
}
|
||||
|
||||
//------------------------------cast_to_ptr_type-------------------------------
|
||||
const Type *TypeAryPtr::cast_to_ptr_type(PTR ptr) const {
|
||||
if( ptr == _ptr ) return this;
|
||||
return make(ptr, const_oop(), _ary, klass(), klass_is_exact(), _offset, _instance_id);
|
||||
return make(ptr, const_oop(), _ary, klass(), klass_is_exact(), _offset, _instance_id, _speculative);
|
||||
}
|
||||
|
||||
|
||||
@ -3430,13 +3608,13 @@ const Type *TypeAryPtr::cast_to_exactness(bool klass_is_exact) const {
|
||||
if( klass_is_exact == _klass_is_exact ) return this;
|
||||
if (!UseExactTypes) return this;
|
||||
if (_ary->ary_must_be_exact()) return this; // cannot clear xk
|
||||
return make(ptr(), const_oop(), _ary, klass(), klass_is_exact, _offset, _instance_id);
|
||||
return make(ptr(), const_oop(), _ary, klass(), klass_is_exact, _offset, _instance_id, _speculative);
|
||||
}
|
||||
|
||||
//-----------------------------cast_to_instance_id----------------------------
|
||||
const TypeOopPtr *TypeAryPtr::cast_to_instance_id(int instance_id) const {
|
||||
if( instance_id == _instance_id ) return this;
|
||||
return make(_ptr, const_oop(), _ary, klass(), _klass_is_exact, _offset, instance_id);
|
||||
return make(_ptr, const_oop(), _ary, klass(), _klass_is_exact, _offset, instance_id, _speculative);
|
||||
}
|
||||
|
||||
//-----------------------------narrow_size_type-------------------------------
|
||||
@ -3499,7 +3677,7 @@ const TypeAryPtr* TypeAryPtr::cast_to_size(const TypeInt* new_size) const {
|
||||
new_size = narrow_size_type(new_size);
|
||||
if (new_size == size()) return this;
|
||||
const TypeAry* new_ary = TypeAry::make(elem(), new_size, is_stable());
|
||||
return make(ptr(), const_oop(), new_ary, klass(), klass_is_exact(), _offset, _instance_id);
|
||||
return make(ptr(), const_oop(), new_ary, klass(), klass_is_exact(), _offset, _instance_id, _speculative);
|
||||
}
|
||||
|
||||
|
||||
@ -3548,7 +3726,7 @@ int TypeAryPtr::hash(void) const {
|
||||
|
||||
//------------------------------meet-------------------------------------------
|
||||
// Compute the MEET of two types. It returns a new Type object.
|
||||
const Type *TypeAryPtr::xmeet( const Type *t ) const {
|
||||
const Type *TypeAryPtr::xmeet_helper(const Type *t) const {
|
||||
// Perform a fast test for common case; meeting the same types together.
|
||||
if( this == t ) return this; // Meeting same type-rep?
|
||||
// Current "this->_base" is Pointer
|
||||
@ -3582,13 +3760,15 @@ const Type *TypeAryPtr::xmeet( const Type *t ) const {
|
||||
case TopPTR:
|
||||
case AnyNull: {
|
||||
int instance_id = meet_instance_id(InstanceTop);
|
||||
const TypeOopPtr* speculative = meet_speculative(tp);
|
||||
return make(ptr, (ptr == Constant ? const_oop() : NULL),
|
||||
_ary, _klass, _klass_is_exact, offset, instance_id);
|
||||
_ary, _klass, _klass_is_exact, offset, instance_id, speculative);
|
||||
}
|
||||
case BotPTR:
|
||||
case NotNull: {
|
||||
int instance_id = meet_instance_id(tp->instance_id());
|
||||
return TypeOopPtr::make(ptr, offset, instance_id);
|
||||
const TypeOopPtr* speculative = meet_speculative(tp);
|
||||
return TypeOopPtr::make(ptr, offset, instance_id, speculative);
|
||||
}
|
||||
default: ShouldNotReachHere();
|
||||
}
|
||||
@ -3610,8 +3790,9 @@ const Type *TypeAryPtr::xmeet( const Type *t ) const {
|
||||
// else fall through to AnyNull
|
||||
case AnyNull: {
|
||||
int instance_id = meet_instance_id(InstanceTop);
|
||||
return make( ptr, (ptr == Constant ? const_oop() : NULL),
|
||||
_ary, _klass, _klass_is_exact, offset, instance_id);
|
||||
const TypeOopPtr* speculative = _speculative;
|
||||
return make(ptr, (ptr == Constant ? const_oop() : NULL),
|
||||
_ary, _klass, _klass_is_exact, offset, instance_id, speculative);
|
||||
}
|
||||
default: ShouldNotReachHere();
|
||||
}
|
||||
@ -3627,6 +3808,7 @@ const Type *TypeAryPtr::xmeet( const Type *t ) const {
|
||||
const TypeAry *tary = _ary->meet(tap->_ary)->is_ary();
|
||||
PTR ptr = meet_ptr(tap->ptr());
|
||||
int instance_id = meet_instance_id(tap->instance_id());
|
||||
const TypeOopPtr* speculative = meet_speculative(tap);
|
||||
ciKlass* lazy_klass = NULL;
|
||||
if (tary->_elem->isa_int()) {
|
||||
// Integral array element types have irrelevant lattice relations.
|
||||
@ -3654,7 +3836,7 @@ const Type *TypeAryPtr::xmeet( const Type *t ) const {
|
||||
// 'this' is exact and super or unrelated:
|
||||
(this->_klass_is_exact && !klass()->is_subtype_of(tap->klass())))) {
|
||||
tary = TypeAry::make(Type::BOTTOM, tary->_size, tary->_stable);
|
||||
return make( NotNull, NULL, tary, lazy_klass, false, off, InstanceBot );
|
||||
return make(NotNull, NULL, tary, lazy_klass, false, off, InstanceBot);
|
||||
}
|
||||
|
||||
bool xk = false;
|
||||
@ -3662,8 +3844,12 @@ const Type *TypeAryPtr::xmeet( const Type *t ) const {
|
||||
case AnyNull:
|
||||
case TopPTR:
|
||||
// Compute new klass on demand, do not use tap->_klass
|
||||
xk = (tap->_klass_is_exact | this->_klass_is_exact);
|
||||
return make( ptr, const_oop(), tary, lazy_klass, xk, off, instance_id );
|
||||
if (below_centerline(this->_ptr)) {
|
||||
xk = this->_klass_is_exact;
|
||||
} else {
|
||||
xk = (tap->_klass_is_exact | this->_klass_is_exact);
|
||||
}
|
||||
return make(ptr, const_oop(), tary, lazy_klass, xk, off, instance_id, speculative);
|
||||
case Constant: {
|
||||
ciObject* o = const_oop();
|
||||
if( _ptr == Constant ) {
|
||||
@ -3675,25 +3861,23 @@ const Type *TypeAryPtr::xmeet( const Type *t ) const {
|
||||
} else {
|
||||
xk = true;
|
||||
}
|
||||
} else if( above_centerline(_ptr) ) {
|
||||
} else if(above_centerline(_ptr)) {
|
||||
o = tap->const_oop();
|
||||
xk = true;
|
||||
} else {
|
||||
// Only precise for identical arrays
|
||||
xk = this->_klass_is_exact && (klass() == tap->klass());
|
||||
}
|
||||
return TypeAryPtr::make( ptr, o, tary, lazy_klass, xk, off, instance_id );
|
||||
return TypeAryPtr::make(ptr, o, tary, lazy_klass, xk, off, instance_id, speculative);
|
||||
}
|
||||
case NotNull:
|
||||
case BotPTR:
|
||||
// Compute new klass on demand, do not use tap->_klass
|
||||
if (above_centerline(this->_ptr))
|
||||
xk = tap->_klass_is_exact;
|
||||
else if (above_centerline(tap->_ptr))
|
||||
xk = this->_klass_is_exact;
|
||||
else xk = (tap->_klass_is_exact & this->_klass_is_exact) &&
|
||||
(klass() == tap->klass()); // Only precise for identical arrays
|
||||
return TypeAryPtr::make( ptr, NULL, tary, lazy_klass, xk, off, instance_id );
|
||||
return TypeAryPtr::make(ptr, NULL, tary, lazy_klass, xk, off, instance_id, speculative);
|
||||
default: ShouldNotReachHere();
|
||||
}
|
||||
}
|
||||
@ -3704,16 +3888,20 @@ const Type *TypeAryPtr::xmeet( const Type *t ) const {
|
||||
int offset = meet_offset(tp->offset());
|
||||
PTR ptr = meet_ptr(tp->ptr());
|
||||
int instance_id = meet_instance_id(tp->instance_id());
|
||||
const TypeOopPtr* speculative = meet_speculative(tp);
|
||||
switch (ptr) {
|
||||
case TopPTR:
|
||||
case AnyNull: // Fall 'down' to dual of object klass
|
||||
if( tp->klass()->equals(ciEnv::current()->Object_klass()) ) {
|
||||
return TypeAryPtr::make( ptr, _ary, _klass, _klass_is_exact, offset, instance_id );
|
||||
// For instances when a subclass meets a superclass we fall
|
||||
// below the centerline when the superclass is exact. We need to
|
||||
// do the same here.
|
||||
if (tp->klass()->equals(ciEnv::current()->Object_klass()) && !tp->klass_is_exact()) {
|
||||
return TypeAryPtr::make(ptr, _ary, _klass, _klass_is_exact, offset, instance_id, speculative);
|
||||
} else {
|
||||
// cannot subclass, so the meet has to fall badly below the centerline
|
||||
ptr = NotNull;
|
||||
instance_id = InstanceBot;
|
||||
return TypeInstPtr::make( ptr, ciEnv::current()->Object_klass(), false, NULL,offset, instance_id);
|
||||
return TypeInstPtr::make(ptr, ciEnv::current()->Object_klass(), false, NULL,offset, instance_id, speculative);
|
||||
}
|
||||
case Constant:
|
||||
case NotNull:
|
||||
@ -3722,10 +3910,13 @@ const Type *TypeAryPtr::xmeet( const Type *t ) const {
|
||||
if (above_centerline(tp->ptr())) {
|
||||
// If 'tp' is above the centerline and it is Object class
|
||||
// then we can subclass in the Java class hierarchy.
|
||||
if( tp->klass()->equals(ciEnv::current()->Object_klass()) ) {
|
||||
// For instances when a subclass meets a superclass we fall
|
||||
// below the centerline when the superclass is exact. We need
|
||||
// to do the same here.
|
||||
if (tp->klass()->equals(ciEnv::current()->Object_klass()) && !tp->klass_is_exact()) {
|
||||
// that is, my array type is a subtype of 'tp' klass
|
||||
return make( ptr, (ptr == Constant ? const_oop() : NULL),
|
||||
_ary, _klass, _klass_is_exact, offset, instance_id );
|
||||
return make(ptr, (ptr == Constant ? const_oop() : NULL),
|
||||
_ary, _klass, _klass_is_exact, offset, instance_id, speculative);
|
||||
}
|
||||
}
|
||||
// The other case cannot happen, since t cannot be a subtype of an array.
|
||||
@ -3733,7 +3924,7 @@ const Type *TypeAryPtr::xmeet( const Type *t ) const {
|
||||
if( ptr == Constant )
|
||||
ptr = NotNull;
|
||||
instance_id = InstanceBot;
|
||||
return TypeInstPtr::make( ptr, ciEnv::current()->Object_klass(), false, NULL,offset, instance_id);
|
||||
return TypeInstPtr::make(ptr, ciEnv::current()->Object_klass(), false, NULL,offset, instance_id, speculative);
|
||||
default: typerr(t);
|
||||
}
|
||||
}
|
||||
@ -3744,7 +3935,7 @@ const Type *TypeAryPtr::xmeet( const Type *t ) const {
|
||||
//------------------------------xdual------------------------------------------
|
||||
// Dual: compute field-by-field dual
|
||||
const Type *TypeAryPtr::xdual() const {
|
||||
return new TypeAryPtr( dual_ptr(), _const_oop, _ary->dual()->is_ary(),_klass, _klass_is_exact, dual_offset(), dual_instance_id(), is_autobox_cache() );
|
||||
return new TypeAryPtr(dual_ptr(), _const_oop, _ary->dual()->is_ary(),_klass, _klass_is_exact, dual_offset(), dual_instance_id(), is_autobox_cache(), dual_speculative());
|
||||
}
|
||||
|
||||
//----------------------interface_vs_oop---------------------------------------
|
||||
@ -3796,6 +3987,8 @@ void TypeAryPtr::dump2( Dict &d, uint depth, outputStream *st ) const {
|
||||
st->print(",iid=top");
|
||||
else if (_instance_id != InstanceBot)
|
||||
st->print(",iid=%d",_instance_id);
|
||||
|
||||
dump_speculative(st);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -3805,10 +3998,13 @@ bool TypeAryPtr::empty(void) const {
|
||||
}
|
||||
|
||||
//------------------------------add_offset-------------------------------------
|
||||
const TypePtr *TypeAryPtr::add_offset( intptr_t offset ) const {
|
||||
return make( _ptr, _const_oop, _ary, _klass, _klass_is_exact, xadd_offset(offset), _instance_id );
|
||||
const TypePtr *TypeAryPtr::add_offset(intptr_t offset) const {
|
||||
return make(_ptr, _const_oop, _ary, _klass, _klass_is_exact, xadd_offset(offset), _instance_id, add_offset_speculative(offset));
|
||||
}
|
||||
|
||||
const TypeOopPtr *TypeAryPtr::remove_speculative() const {
|
||||
return make(_ptr, _const_oop, _ary, _klass, _klass_is_exact, _offset, _instance_id, NULL);
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
||||
|
@ -159,6 +159,11 @@ private:
|
||||
// Table for efficient dualing of base types
|
||||
static const TYPES dual_type[lastype];
|
||||
|
||||
#ifdef ASSERT
|
||||
// One type is interface, the other is oop
|
||||
virtual bool interface_vs_oop_helper(const Type *t) const;
|
||||
#endif
|
||||
|
||||
protected:
|
||||
// Each class of type is also identified by its base.
|
||||
const TYPES _base; // Enum of Types type
|
||||
@ -376,6 +381,9 @@ public:
|
||||
bool require_constant = false,
|
||||
bool is_autobox_cache = false);
|
||||
|
||||
// Speculative type. See TypeInstPtr
|
||||
virtual ciKlass* speculative_type() const { return NULL; }
|
||||
|
||||
private:
|
||||
// support arrays
|
||||
static const BasicType _basic_type[];
|
||||
@ -585,6 +593,7 @@ public:
|
||||
static const TypeTuple *INT_PAIR;
|
||||
static const TypeTuple *LONG_PAIR;
|
||||
static const TypeTuple *INT_CC_PAIR;
|
||||
static const TypeTuple *LONG_CC_PAIR;
|
||||
#ifndef PRODUCT
|
||||
virtual void dump2( Dict &d, uint, outputStream *st ) const; // Specialized per-Type dumping
|
||||
#endif
|
||||
@ -784,7 +793,7 @@ public:
|
||||
// Some kind of oop (Java pointer), either klass or instance or array.
|
||||
class TypeOopPtr : public TypePtr {
|
||||
protected:
|
||||
TypeOopPtr( TYPES t, PTR ptr, ciKlass* k, bool xk, ciObject* o, int offset, int instance_id );
|
||||
TypeOopPtr(TYPES t, PTR ptr, ciKlass* k, bool xk, ciObject* o, int offset, int instance_id, const TypeOopPtr* speculative);
|
||||
public:
|
||||
virtual bool eq( const Type *t ) const;
|
||||
virtual int hash() const; // Type specific hashing
|
||||
@ -810,11 +819,27 @@ protected:
|
||||
// This is the the node index of the allocation node creating this instance.
|
||||
int _instance_id;
|
||||
|
||||
// Extra type information profiling gave us. We propagate it the
|
||||
// same way the rest of the type info is propagated. If we want to
|
||||
// use it, then we have to emit a guard: this part of the type is
|
||||
// not something we know but something we speculate about the type.
|
||||
const TypeOopPtr* _speculative;
|
||||
|
||||
static const TypeOopPtr* make_from_klass_common(ciKlass* klass, bool klass_change, bool try_for_exact);
|
||||
|
||||
int dual_instance_id() const;
|
||||
int meet_instance_id(int uid) const;
|
||||
|
||||
// utility methods to work on the speculative part of the type
|
||||
const TypeOopPtr* dual_speculative() const;
|
||||
const TypeOopPtr* meet_speculative(const TypeOopPtr* other) const;
|
||||
bool eq_speculative(const TypeOopPtr* other) const;
|
||||
int hash_speculative() const;
|
||||
const TypeOopPtr* add_offset_speculative(intptr_t offset) const;
|
||||
#ifndef PRODUCT
|
||||
void dump_speculative(outputStream *st) const;
|
||||
#endif
|
||||
|
||||
public:
|
||||
// Creates a type given a klass. Correctly handles multi-dimensional arrays
|
||||
// Respects UseUniqueSubclasses.
|
||||
@ -841,7 +866,7 @@ public:
|
||||
bool not_null_elements = false);
|
||||
|
||||
// Make a generic (unclassed) pointer to an oop.
|
||||
static const TypeOopPtr* make(PTR ptr, int offset, int instance_id);
|
||||
static const TypeOopPtr* make(PTR ptr, int offset, int instance_id, const TypeOopPtr* speculative);
|
||||
|
||||
ciObject* const_oop() const { return _const_oop; }
|
||||
virtual ciKlass* klass() const { return _klass; }
|
||||
@ -855,6 +880,7 @@ public:
|
||||
bool is_known_instance() const { return _instance_id > 0; }
|
||||
int instance_id() const { return _instance_id; }
|
||||
bool is_known_instance_field() const { return is_known_instance() && _offset >= 0; }
|
||||
const TypeOopPtr* speculative() const { return _speculative; }
|
||||
|
||||
virtual intptr_t get_con() const;
|
||||
|
||||
@ -868,9 +894,13 @@ public:
|
||||
const TypeKlassPtr* as_klass_type() const;
|
||||
|
||||
virtual const TypePtr *add_offset( intptr_t offset ) const;
|
||||
// Return same type without a speculative part
|
||||
virtual const TypeOopPtr* remove_speculative() const;
|
||||
|
||||
virtual const Type *xmeet( const Type *t ) const;
|
||||
virtual const Type *xmeet(const Type *t) const;
|
||||
virtual const Type *xdual() const; // Compute dual right now.
|
||||
// the core of the computation of the meet for TypeOopPtr and for its subclasses
|
||||
virtual const Type *xmeet_helper(const Type *t) const;
|
||||
|
||||
// Do not allow interface-vs.-noninterface joins to collapse to top.
|
||||
virtual const Type *filter( const Type *kills ) const;
|
||||
@ -880,13 +910,24 @@ public:
|
||||
#ifndef PRODUCT
|
||||
virtual void dump2( Dict &d, uint depth, outputStream *st ) const;
|
||||
#endif
|
||||
|
||||
// Return the speculative type if any
|
||||
ciKlass* speculative_type() const {
|
||||
if (_speculative != NULL) {
|
||||
const TypeOopPtr* speculative = _speculative->join(this)->is_oopptr();
|
||||
if (speculative->klass_is_exact()) {
|
||||
return speculative->klass();
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
};
|
||||
|
||||
//------------------------------TypeInstPtr------------------------------------
|
||||
// Class of Java object pointers, pointing either to non-array Java instances
|
||||
// or to a Klass* (including array klasses).
|
||||
class TypeInstPtr : public TypeOopPtr {
|
||||
TypeInstPtr( PTR ptr, ciKlass* k, bool xk, ciObject* o, int offset, int instance_id );
|
||||
TypeInstPtr(PTR ptr, ciKlass* k, bool xk, ciObject* o, int offset, int instance_id, const TypeOopPtr* speculative);
|
||||
virtual bool eq( const Type *t ) const;
|
||||
virtual int hash() const; // Type specific hashing
|
||||
|
||||
@ -899,30 +940,30 @@ class TypeInstPtr : public TypeOopPtr {
|
||||
|
||||
// Make a pointer to a constant oop.
|
||||
static const TypeInstPtr *make(ciObject* o) {
|
||||
return make(TypePtr::Constant, o->klass(), true, o, 0);
|
||||
return make(TypePtr::Constant, o->klass(), true, o, 0, InstanceBot);
|
||||
}
|
||||
// Make a pointer to a constant oop with offset.
|
||||
static const TypeInstPtr *make(ciObject* o, int offset) {
|
||||
return make(TypePtr::Constant, o->klass(), true, o, offset);
|
||||
return make(TypePtr::Constant, o->klass(), true, o, offset, InstanceBot);
|
||||
}
|
||||
|
||||
// Make a pointer to some value of type klass.
|
||||
static const TypeInstPtr *make(PTR ptr, ciKlass* klass) {
|
||||
return make(ptr, klass, false, NULL, 0);
|
||||
return make(ptr, klass, false, NULL, 0, InstanceBot);
|
||||
}
|
||||
|
||||
// Make a pointer to some non-polymorphic value of exactly type klass.
|
||||
static const TypeInstPtr *make_exact(PTR ptr, ciKlass* klass) {
|
||||
return make(ptr, klass, true, NULL, 0);
|
||||
return make(ptr, klass, true, NULL, 0, InstanceBot);
|
||||
}
|
||||
|
||||
// Make a pointer to some value of type klass with offset.
|
||||
static const TypeInstPtr *make(PTR ptr, ciKlass* klass, int offset) {
|
||||
return make(ptr, klass, false, NULL, offset);
|
||||
return make(ptr, klass, false, NULL, offset, InstanceBot);
|
||||
}
|
||||
|
||||
// Make a pointer to an oop.
|
||||
static const TypeInstPtr *make(PTR ptr, ciKlass* k, bool xk, ciObject* o, int offset, int instance_id = InstanceBot );
|
||||
static const TypeInstPtr *make(PTR ptr, ciKlass* k, bool xk, ciObject* o, int offset, int instance_id = InstanceBot, const TypeOopPtr* speculative = NULL);
|
||||
|
||||
/** Create constant type for a constant boxed value */
|
||||
const Type* get_const_boxed_value() const;
|
||||
@ -939,8 +980,11 @@ class TypeInstPtr : public TypeOopPtr {
|
||||
virtual const TypeOopPtr *cast_to_instance_id(int instance_id) const;
|
||||
|
||||
virtual const TypePtr *add_offset( intptr_t offset ) const;
|
||||
// Return same type without a speculative part
|
||||
virtual const TypeOopPtr* remove_speculative() const;
|
||||
|
||||
virtual const Type *xmeet( const Type *t ) const;
|
||||
// the core of the computation of the meet of 2 types
|
||||
virtual const Type *xmeet_helper(const Type *t) const;
|
||||
virtual const TypeInstPtr *xmeet_unloaded( const TypeInstPtr *t ) const;
|
||||
virtual const Type *xdual() const; // Compute dual right now.
|
||||
|
||||
@ -959,8 +1003,8 @@ class TypeInstPtr : public TypeOopPtr {
|
||||
// Class of Java array pointers
|
||||
class TypeAryPtr : public TypeOopPtr {
|
||||
TypeAryPtr( PTR ptr, ciObject* o, const TypeAry *ary, ciKlass* k, bool xk,
|
||||
int offset, int instance_id, bool is_autobox_cache )
|
||||
: TypeOopPtr(AryPtr,ptr,k,xk,o,offset, instance_id),
|
||||
int offset, int instance_id, bool is_autobox_cache, const TypeOopPtr* speculative)
|
||||
: TypeOopPtr(AryPtr,ptr,k,xk,o,offset, instance_id, speculative),
|
||||
_ary(ary),
|
||||
_is_autobox_cache(is_autobox_cache)
|
||||
{
|
||||
@ -998,9 +1042,9 @@ public:
|
||||
|
||||
bool is_autobox_cache() const { return _is_autobox_cache; }
|
||||
|
||||
static const TypeAryPtr *make( PTR ptr, const TypeAry *ary, ciKlass* k, bool xk, int offset, int instance_id = InstanceBot);
|
||||
static const TypeAryPtr *make( PTR ptr, const TypeAry *ary, ciKlass* k, bool xk, int offset, int instance_id = InstanceBot, const TypeOopPtr* speculative = NULL);
|
||||
// Constant pointer to array
|
||||
static const TypeAryPtr *make( PTR ptr, ciObject* o, const TypeAry *ary, ciKlass* k, bool xk, int offset, int instance_id = InstanceBot, bool is_autobox_cache = false);
|
||||
static const TypeAryPtr *make( PTR ptr, ciObject* o, const TypeAry *ary, ciKlass* k, bool xk, int offset, int instance_id = InstanceBot, const TypeOopPtr* speculative = NULL, bool is_autobox_cache = false);
|
||||
|
||||
// Return a 'ptr' version of this type
|
||||
virtual const Type *cast_to_ptr_type(PTR ptr) const;
|
||||
@ -1014,8 +1058,11 @@ public:
|
||||
|
||||
virtual bool empty(void) const; // TRUE if type is vacuous
|
||||
virtual const TypePtr *add_offset( intptr_t offset ) const;
|
||||
// Return same type without a speculative part
|
||||
virtual const TypeOopPtr* remove_speculative() const;
|
||||
|
||||
virtual const Type *xmeet( const Type *t ) const;
|
||||
// the core of the computation of the meet of 2 types
|
||||
virtual const Type *xmeet_helper(const Type *t) const;
|
||||
virtual const Type *xdual() const; // Compute dual right now.
|
||||
|
||||
const TypeAryPtr* cast_to_stable(bool stable, int stable_dimension = 1) const;
|
||||
|
@ -1194,9 +1194,7 @@ JVM_ENTRY(jobject, MHN_getMemberVMInfo(JNIEnv *env, jobject igcls, jobject mname
|
||||
} else if (vmtarget->is_klass()) {
|
||||
x = ((Klass*) vmtarget)->java_mirror();
|
||||
} else if (vmtarget->is_method()) {
|
||||
Handle mname2 = MethodHandles::new_MemberName(CHECK_NULL);
|
||||
CallInfo info((Method*)vmtarget);
|
||||
x = MethodHandles::init_method_MemberName(mname2, info);
|
||||
x = mname();
|
||||
}
|
||||
result->obj_at_put(1, x);
|
||||
return JNIHandles::make_local(env, result());
|
||||
|
@ -1957,12 +1957,6 @@ bool Arguments::check_gc_consistency() {
|
||||
"please refer to the release notes for the combinations "
|
||||
"allowed\n");
|
||||
status = false;
|
||||
} else if (ReservedCodeCacheSize > 2*G) {
|
||||
// Code cache size larger than MAXINT is not supported.
|
||||
jio_fprintf(defaultStream::error_stream(),
|
||||
"Invalid ReservedCodeCacheSize=%dM. Must be at most %uM.\n", ReservedCodeCacheSize/M,
|
||||
(2*G)/M);
|
||||
status = false;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
@ -3721,6 +3715,18 @@ jint Arguments::apply_ergo() {
|
||||
// incremental inlining: bump MaxNodeLimit
|
||||
FLAG_SET_DEFAULT(MaxNodeLimit, (intx)75000);
|
||||
}
|
||||
if (!UseTypeSpeculation && FLAG_IS_DEFAULT(TypeProfileLevel)) {
|
||||
// nothing to use the profiling, turn if off
|
||||
FLAG_SET_DEFAULT(TypeProfileLevel, 0);
|
||||
}
|
||||
if (UseTypeSpeculation && FLAG_IS_DEFAULT(ReplaceInParentMaps)) {
|
||||
// Doing the replace in parent maps helps speculation
|
||||
FLAG_SET_DEFAULT(ReplaceInParentMaps, true);
|
||||
}
|
||||
#ifndef X86
|
||||
// Only on x86 for now
|
||||
FLAG_SET_DEFAULT(TypeProfileLevel, 0);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (PrintAssembly && FLAG_IS_DEFAULT(DebugNonSafepoints)) {
|
||||
|
@ -2671,13 +2671,18 @@ class CommandLineFlags {
|
||||
"Enable aggressive optimizations - see arguments.cpp") \
|
||||
\
|
||||
product_pd(uintx, TypeProfileLevel, \
|
||||
"=XY, with Y, Type profiling of arguments at call" \
|
||||
" X, Type profiling of return value at call" \
|
||||
"X and Y in 0->off ; 1->js292 only; 2->all methods") \
|
||||
"=XYZ, with Z: Type profiling of arguments at call; " \
|
||||
"Y: Type profiling of return value at call; " \
|
||||
"X: Type profiling of parameters to methods; " \
|
||||
"X, Y and Z in 0=off ; 1=jsr292 only; 2=all methods") \
|
||||
\
|
||||
product(intx, TypeProfileArgsLimit, 2, \
|
||||
"max number of call arguments to consider for type profiling") \
|
||||
\
|
||||
product(intx, TypeProfileParmsLimit, 2, \
|
||||
"max number of incoming parameters to consider for type profiling"\
|
||||
", -1 for all") \
|
||||
\
|
||||
/* statistics */ \
|
||||
develop(bool, CountCompiledCalls, false, \
|
||||
"Count method invocations") \
|
||||
|
@ -193,6 +193,11 @@ void print_method_profiling_data() {
|
||||
m->print_invocation_count();
|
||||
tty->print_cr(" mdo size: %d bytes", m->method_data()->size_in_bytes());
|
||||
tty->cr();
|
||||
// Dump data on parameters if any
|
||||
if (m->method_data() != NULL && m->method_data()->parameters_type_data() != NULL) {
|
||||
tty->fill_to(2);
|
||||
m->method_data()->parameters_type_data()->print_data_on(tty);
|
||||
}
|
||||
m->print_codes();
|
||||
total_size += m->method_data()->size_in_bytes();
|
||||
}
|
||||
|
@ -1938,7 +1938,13 @@ typedef BinaryTreeDictionary<Metablock, FreeList> MetablockTreeDictionary;
|
||||
declare_c2_type(CmpDNode, CmpNode) \
|
||||
declare_c2_type(CmpD3Node, CmpDNode) \
|
||||
declare_c2_type(MathExactNode, MultiNode) \
|
||||
declare_c2_type(AddExactINode, MathExactNode) \
|
||||
declare_c2_type(MathExactINode, MathExactNode) \
|
||||
declare_c2_type(AddExactINode, MathExactINode) \
|
||||
declare_c2_type(AddExactLNode, MathExactLNode) \
|
||||
declare_c2_type(SubExactINode, MathExactINode) \
|
||||
declare_c2_type(SubExactLNode, MathExactLNode) \
|
||||
declare_c2_type(NegExactINode, MathExactINode) \
|
||||
declare_c2_type(MulExactINode, MathExactINode) \
|
||||
declare_c2_type(FlagsProjNode, ProjNode) \
|
||||
declare_c2_type(BoolNode, Node) \
|
||||
declare_c2_type(AbsNode, Node) \
|
||||
|
@ -25,14 +25,12 @@
|
||||
* @test
|
||||
* @bug 8024924
|
||||
* @summary Test non constant addExact
|
||||
* @compile CondTest.java Verify.java
|
||||
* @run main CondTest
|
||||
* @compile AddExactICondTest.java
|
||||
* @run main AddExactICondTest
|
||||
*
|
||||
*/
|
||||
|
||||
import java.lang.ArithmeticException;
|
||||
|
||||
public class CondTest {
|
||||
public class AddExactICondTest {
|
||||
public static int result = 0;
|
||||
|
||||
public static void main(String[] args) {
|
@ -25,23 +25,13 @@
|
||||
* @test
|
||||
* @bug 8024924
|
||||
* @summary Test constant addExact
|
||||
* @compile ConstantTest.java Verify.java
|
||||
* @run main ConstantTest
|
||||
* @compile AddExactIConstantTest.java Verify.java
|
||||
* @run main AddExactIConstantTest
|
||||
*
|
||||
*/
|
||||
|
||||
import java.lang.ArithmeticException;
|
||||
|
||||
public class ConstantTest {
|
||||
public class AddExactIConstantTest {
|
||||
public static void main(String[] args) {
|
||||
for (int i = 0; i < 50000; ++i) {
|
||||
Verify.verify(5, 7);
|
||||
Verify.verify(Integer.MAX_VALUE, 1);
|
||||
Verify.verify(Integer.MIN_VALUE, -1);
|
||||
Verify.verify(Integer.MAX_VALUE, -1);
|
||||
Verify.verify(Integer.MIN_VALUE, 1);
|
||||
Verify.verify(Integer.MAX_VALUE / 2, Integer.MAX_VALUE / 2);
|
||||
Verify.verify(Integer.MAX_VALUE / 2, (Integer.MAX_VALUE / 2) + 3);
|
||||
}
|
||||
Verify.ConstantTest.verify(new Verify.AddExactI());
|
||||
}
|
||||
}
|
@ -25,24 +25,14 @@
|
||||
* @test
|
||||
* @bug 8024924
|
||||
* @summary Test non constant addExact
|
||||
* @compile NonConstantTest.java Verify.java
|
||||
* @run main NonConstantTest
|
||||
* @compile AddExactILoadTest.java Verify.java
|
||||
* @run main AddExactILoadTest
|
||||
*
|
||||
*/
|
||||
|
||||
import java.lang.ArithmeticException;
|
||||
|
||||
public class NonConstantTest {
|
||||
public static java.util.Random rnd = new java.util.Random();
|
||||
|
||||
public class AddExactILoadTest {
|
||||
public static void main(String[] args) {
|
||||
for (int i = 0; i < 50000; ++i) {
|
||||
int rnd1 = rnd.nextInt(), rnd2 = rnd.nextInt();
|
||||
Verify.verify(rnd1, rnd2);
|
||||
Verify.verify(rnd1, rnd2 + 1);
|
||||
Verify.verify(rnd1 + 1, rnd2);
|
||||
Verify.verify(rnd1 - 1, rnd2);
|
||||
Verify.verify(rnd1, rnd2 - 1);
|
||||
}
|
||||
Verify.LoadTest.init();
|
||||
Verify.LoadTest.verify(new Verify.AddExactI());
|
||||
}
|
||||
}
|
@ -25,24 +25,13 @@
|
||||
* @test
|
||||
* @bug 8024924
|
||||
* @summary Test non constant addExact
|
||||
* @compile LoopDependentTest.java Verify.java
|
||||
* @run main LoopDependentTest
|
||||
* @compile AddExactILoopDependentTest.java Verify.java
|
||||
* @run main AddExactILoopDependentTest
|
||||
*
|
||||
*/
|
||||
|
||||
import java.lang.ArithmeticException;
|
||||
|
||||
public class LoopDependentTest {
|
||||
public static java.util.Random rnd = new java.util.Random();
|
||||
|
||||
public class AddExactILoopDependentTest {
|
||||
public static void main(String[] args) {
|
||||
int rnd1 = rnd.nextInt(), rnd2 = rnd.nextInt();
|
||||
for (int i = 0; i < 50000; ++i) {
|
||||
Verify.verify(rnd1 + i, rnd2 + i);
|
||||
Verify.verify(rnd1 + i, rnd2 + (i & 0xff));
|
||||
Verify.verify(rnd1 - i, rnd2 - (i & 0xff));
|
||||
Verify.verify(rnd1 + i + 1, rnd2 + i + 2);
|
||||
Verify.verify(rnd1 + i * 2, rnd2 + i);
|
||||
}
|
||||
Verify.LoopDependentTest.verify(new Verify.AddExactI());
|
||||
}
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8024924
|
||||
* @summary Test non constant addExact
|
||||
* @compile AddExactINonConstantTest.java Verify.java
|
||||
* @run main AddExactINonConstantTest
|
||||
*
|
||||
*/
|
||||
|
||||
public class AddExactINonConstantTest {
|
||||
public static void main(String[] args) {
|
||||
Verify.NonConstantTest.verify(new Verify.AddExactI());
|
||||
}
|
||||
}
|
@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8025657
|
||||
* @summary Test repeating addExact
|
||||
* @compile AddExactIRepeatTest.java Verify.java
|
||||
* @run main AddExactIRepeatTest
|
||||
*
|
||||
*/
|
||||
|
||||
public class AddExactIRepeatTest {
|
||||
public static void main(String[] args) {
|
||||
runTest(new Verify.AddExactI());
|
||||
}
|
||||
|
||||
public static int nonExact(int x, int y, Verify.BinaryMethod method) {
|
||||
int result = method.unchecked(x, y);
|
||||
result += method.unchecked(x, y);
|
||||
result += method.unchecked(x, y);
|
||||
result += method.unchecked(x, y);
|
||||
return result;
|
||||
}
|
||||
|
||||
public static void runTest(Verify.BinaryMethod method) {
|
||||
java.util.Random rnd = new java.util.Random();
|
||||
for (int i = 0; i < 50000; ++i) {
|
||||
int x = Integer.MAX_VALUE - 10;
|
||||
int y = Integer.MAX_VALUE - 10 + rnd.nextInt(5);
|
||||
|
||||
int c = rnd.nextInt() / 2;
|
||||
int d = rnd.nextInt() / 2;
|
||||
|
||||
int a = catchingExact(x, y, method);
|
||||
|
||||
if (a != 36) {
|
||||
throw new RuntimeException("a != 36 : " + a);
|
||||
}
|
||||
|
||||
int b = nonExact(c, d, method);
|
||||
int n = exact(c, d, method);
|
||||
|
||||
|
||||
if (n != b) {
|
||||
throw new RuntimeException("n != b : " + n + " != " + b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static int exact(int x, int y, Verify.BinaryMethod method) {
|
||||
int result = 0;
|
||||
result += method.checkMethod(x, y);
|
||||
result += method.checkMethod(x, y);
|
||||
result += method.checkMethod(x, y);
|
||||
result += method.checkMethod(x, y);
|
||||
return result;
|
||||
}
|
||||
|
||||
public static int catchingExact(int x, int y, Verify.BinaryMethod method) {
|
||||
int result = 0;
|
||||
try {
|
||||
result += 5;
|
||||
result = method.checkMethod(x, y);
|
||||
} catch (ArithmeticException e) {
|
||||
result += 1;
|
||||
}
|
||||
try {
|
||||
result += 6;
|
||||
|
||||
result += method.checkMethod(x, y);
|
||||
} catch (ArithmeticException e) {
|
||||
result += 2;
|
||||
}
|
||||
try {
|
||||
result += 7;
|
||||
result += method.checkMethod(x, y);
|
||||
} catch (ArithmeticException e) {
|
||||
result += 3;
|
||||
}
|
||||
try {
|
||||
result += 8;
|
||||
result += method.checkMethod(x, y);
|
||||
} catch (ArithmeticException e) {
|
||||
result += 4;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8026844
|
||||
* @summary Test constant addExact
|
||||
* @compile AddExactLConstantTest.java Verify.java
|
||||
* @run main AddExactLConstantTest
|
||||
*
|
||||
*/
|
||||
|
||||
public class AddExactLConstantTest {
|
||||
public static void main(String[] args) {
|
||||
Verify.ConstantLongTest.verify(new Verify.AddExactL());
|
||||
}
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8026844
|
||||
* @summary Test non constant addExact
|
||||
* @compile AddExactLNonConstantTest.java Verify.java
|
||||
* @run main AddExactLNonConstantTest
|
||||
*
|
||||
*/
|
||||
|
||||
public class AddExactLNonConstantTest {
|
||||
public static void main(String[] args) {
|
||||
Verify.NonConstantLongTest.verify(new Verify.AddExactL());
|
||||
}
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8026844
|
||||
* @summary Test decrementExact
|
||||
* @compile DecExactITest.java Verify.java
|
||||
* @run main DecExactITest
|
||||
*
|
||||
*/
|
||||
|
||||
public class DecExactITest {
|
||||
public static int[] values = {1, 1, 1, 1};
|
||||
public static int[] minvalues = {Integer.MIN_VALUE, Integer.MIN_VALUE};
|
||||
|
||||
public static void main(String[] args) {
|
||||
runTest(new Verify.DecExactI());
|
||||
}
|
||||
|
||||
public static void runTest(Verify.UnaryMethod method) {
|
||||
for (int i = 0; i < 20000; ++i) {
|
||||
Verify.verifyUnary(Integer.MIN_VALUE, method);
|
||||
Verify.verifyUnary(minvalues[0], method);
|
||||
Verify.verifyUnary(Integer.MIN_VALUE - values[2], method);
|
||||
Verify.verifyUnary(0, method);
|
||||
Verify.verifyUnary(values[2], method);
|
||||
Verify.verifyUnary(Integer.MAX_VALUE, method);
|
||||
Verify.verifyUnary(Integer.MIN_VALUE - values[0] + values[3], method);
|
||||
Verify.verifyUnary(Integer.MIN_VALUE + 1 - values[0], method);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8026844
|
||||
* @summary Test decrementExact
|
||||
* @compile DecExactITest.java Verify.java
|
||||
* @run main DecExactITest
|
||||
*
|
||||
*/
|
||||
|
||||
public class DecExactLTest {
|
||||
public static long[] values = {1, 1, 1, 1};
|
||||
public static long[] minvalues = {Long.MIN_VALUE, Long.MIN_VALUE};
|
||||
|
||||
public static void main(String[] args) {
|
||||
runTest(new Verify.DecExactL());
|
||||
}
|
||||
|
||||
public static void runTest(Verify.UnaryLongMethod method) {
|
||||
for (int i = 0; i < 20000; ++i) {
|
||||
Verify.verifyUnary(Long.MIN_VALUE, method);
|
||||
Verify.verifyUnary(minvalues[0], method);
|
||||
Verify.verifyUnary(Long.MIN_VALUE - values[2], method);
|
||||
Verify.verifyUnary(0, method);
|
||||
Verify.verifyUnary(values[2], method);
|
||||
Verify.verifyUnary(Long.MAX_VALUE, method);
|
||||
Verify.verifyUnary(Long.MIN_VALUE - values[0] + values[3], method);
|
||||
Verify.verifyUnary(Long.MIN_VALUE + 1 - values[0], method);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8026844
|
||||
* @summary Test incrementExact
|
||||
* @compile IncExactITest.java Verify.java
|
||||
* @run main IncExactITest
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
public class IncExactITest {
|
||||
public static int[] values = {1, 1, 1, 1};
|
||||
public static void main(String[] args) {
|
||||
runTest(new Verify.IncExactI());
|
||||
}
|
||||
|
||||
public static void runTest(Verify.UnaryMethod method) {
|
||||
for (int i = 0; i < 20000; ++i) {
|
||||
Verify.verifyUnary(Integer.MIN_VALUE, method);
|
||||
Verify.verifyUnary(Integer.MAX_VALUE - 1, method);
|
||||
Verify.verifyUnary(0, method);
|
||||
Verify.verifyUnary(values[1], method);
|
||||
Verify.verifyUnary(Integer.MAX_VALUE, method);
|
||||
Verify.verifyUnary(Integer.MAX_VALUE - values[0] + values[3], method);
|
||||
Verify.verifyUnary(Integer.MAX_VALUE - 1 + values[0], method);
|
||||
}
|
||||
}
|
||||
}
|
@ -23,33 +23,28 @@
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8024924
|
||||
* @summary Test non constant addExact
|
||||
* @compile LoadTest.java Verify.java
|
||||
* @run main LoadTest
|
||||
* @bug 8026844
|
||||
* @summary Test incrementExact
|
||||
* @compile IncExactLTest.java Verify.java
|
||||
* @run main IncExactLTest
|
||||
*
|
||||
*/
|
||||
|
||||
import java.lang.ArithmeticException;
|
||||
|
||||
public class LoadTest {
|
||||
public static java.util.Random rnd = new java.util.Random();
|
||||
public static int[] values = new int[256];
|
||||
|
||||
public static void main(String[] args) {
|
||||
for (int i = 0; i < values.length; ++i) {
|
||||
values[i] = rnd.nextInt();
|
||||
public class IncExactLTest {
|
||||
public static long[] values = {1, 1, 1, 1};
|
||||
public static void main(String[] args) {
|
||||
runTest(new Verify.IncExactL());
|
||||
}
|
||||
|
||||
for (int i = 0; i < 50000; ++i) {
|
||||
Verify.verify(values[i & 255], values[i & 255] - i);
|
||||
Verify.verify(values[i & 255] + i, values[i & 255] - i);
|
||||
Verify.verify(values[i & 255], values[i & 255]);
|
||||
if ((i & 1) == 1 && i > 5) {
|
||||
Verify.verify(values[i & 255] + i, values[i & 255] - i);
|
||||
} else {
|
||||
Verify.verify(values[i & 255] - i, values[i & 255] + i);
|
||||
}
|
||||
public static void runTest(Verify.UnaryLongMethod method) {
|
||||
for (int i = 0; i < 20000; ++i) {
|
||||
Verify.verifyUnary(Long.MIN_VALUE, method);
|
||||
Verify.verifyUnary(Long.MAX_VALUE - 1, method);
|
||||
Verify.verifyUnary(0, method);
|
||||
Verify.verifyUnary(values[1], method);
|
||||
Verify.verifyUnary(Long.MAX_VALUE, method);
|
||||
Verify.verifyUnary(Long.MAX_VALUE - values[0] + values[3], method);
|
||||
Verify.verifyUnary(Long.MAX_VALUE - 1 + values[0], method);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8026844
|
||||
* @summary Test multiplyExact as condition
|
||||
* @compile MulExactICondTest.java
|
||||
* @run main MulExactICondTest
|
||||
*
|
||||
*/
|
||||
|
||||
public class MulExactICondTest {
|
||||
public static int result = 0;
|
||||
|
||||
public static void main(String[] args) {
|
||||
for (int i = 0; i < 50000; ++i) {
|
||||
runTest();
|
||||
}
|
||||
}
|
||||
|
||||
public static void runTest() {
|
||||
int i = 7;
|
||||
while (java.lang.Math.multiplyExact(i, result) < 89361) {
|
||||
if ((java.lang.Math.multiplyExact(i, i) & 1) == 1) {
|
||||
i += 3;
|
||||
} else if ((i & 5) == 4) {
|
||||
i += 7;
|
||||
} else if ((i & 0xf) == 6) {
|
||||
i += 2;
|
||||
} else {
|
||||
i += 1;
|
||||
}
|
||||
result += 2;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8026844
|
||||
* @summary Test constant multiplyExact
|
||||
* @compile MulExactIConstantTest.java Verify.java
|
||||
* @run main MulExactIConstantTest
|
||||
*
|
||||
*/
|
||||
|
||||
public class MulExactIConstantTest {
|
||||
public static void main(String[] args) {
|
||||
Verify.ConstantTest.verify(new Verify.MulExactI());
|
||||
}
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8026844
|
||||
* @summary Test multiplyExact
|
||||
* @compile MulExactILoadTest.java Verify.java
|
||||
* @run main MulExactILoadTest
|
||||
*
|
||||
*/
|
||||
|
||||
public class MulExactILoadTest {
|
||||
public static void main(String[] args) {
|
||||
Verify.LoadTest.init();
|
||||
Verify.LoadTest.verify(new Verify.MulExactI());
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8026844
|
||||
* @summary Test loop dependent multiplyExact
|
||||
* @compile MulExactILoopDependentTest.java Verify.java
|
||||
* @run main MulExactILoopDependentTest
|
||||
*
|
||||
*/
|
||||
public class MulExactILoopDependentTest {
|
||||
public static void main(String[] args) {
|
||||
Verify.LoopDependentTest.verify(new Verify.MulExactI());
|
||||
}
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8026844
|
||||
* @summary Test non constant multiplyExact
|
||||
* @compile MulExactINonConstantTest.java Verify.java
|
||||
* @run main MulExactINonConstantTest
|
||||
*
|
||||
*/
|
||||
|
||||
public class MulExactINonConstantTest {
|
||||
public static void main(String[] args) {
|
||||
Verify.NonConstantTest.verify(new Verify.MulExactI());
|
||||
Verify.LoadTest.verify(new Verify.MulExactI());
|
||||
}
|
||||
}
|
@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8026844
|
||||
* @summary Test repeating multiplyExact
|
||||
* @compile MulExactIRepeatTest.java Verify.java
|
||||
* @run main MulExactIRepeatTest
|
||||
*
|
||||
*/
|
||||
|
||||
public class MulExactIRepeatTest {
|
||||
public static void main(String[] args) {
|
||||
runTest(new Verify.MulExactI());
|
||||
}
|
||||
|
||||
public static int nonExact(int x, int y, Verify.BinaryMethod method) {
|
||||
int result = method.unchecked(x, y);
|
||||
result += method.unchecked(x, y);
|
||||
result += method.unchecked(x, y);
|
||||
result += method.unchecked(x, y);
|
||||
return result;
|
||||
}
|
||||
|
||||
public static void runTest(Verify.BinaryMethod method) {
|
||||
java.util.Random rnd = new java.util.Random();
|
||||
for (int i = 0; i < 50000; ++i) {
|
||||
int x = Integer.MAX_VALUE - 10;
|
||||
int y = Integer.MAX_VALUE - 10 + rnd.nextInt(5);
|
||||
|
||||
int c = rnd.nextInt() / 10;
|
||||
int d = rnd.nextInt(9);
|
||||
|
||||
int a = catchingExact(x, y, method);
|
||||
|
||||
if (a != 36) {
|
||||
throw new RuntimeException("a != 36 : " + a);
|
||||
}
|
||||
|
||||
int b = nonExact(c, d, method);
|
||||
int n = exact(c, d, method);
|
||||
|
||||
|
||||
if (n != b) {
|
||||
throw new RuntimeException("n != b : " + n + " != " + b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static int exact(int x, int y, Verify.BinaryMethod method) {
|
||||
int result = 0;
|
||||
result += method.checkMethod(x, y);
|
||||
result += method.checkMethod(x, y);
|
||||
result += method.checkMethod(x, y);
|
||||
result += method.checkMethod(x, y);
|
||||
return result;
|
||||
}
|
||||
|
||||
public static int catchingExact(int x, int y, Verify.BinaryMethod method) {
|
||||
int result = 0;
|
||||
try {
|
||||
result += 5;
|
||||
result = method.checkMethod(x, y);
|
||||
} catch (ArithmeticException e) {
|
||||
result += 1;
|
||||
}
|
||||
try {
|
||||
result += 6;
|
||||
|
||||
result += method.checkMethod(x, y);
|
||||
} catch (ArithmeticException e) {
|
||||
result += 2;
|
||||
}
|
||||
try {
|
||||
result += 7;
|
||||
result += method.checkMethod(x, y);
|
||||
} catch (ArithmeticException e) {
|
||||
result += 3;
|
||||
}
|
||||
try {
|
||||
result += 8;
|
||||
result += method.checkMethod(x, y);
|
||||
} catch (ArithmeticException e) {
|
||||
result += 4;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8026844
|
||||
* @summary Test constant mulExact
|
||||
* @compile MulExactLConstantTest.java Verify.java
|
||||
* @run main MulExactLConstantTest
|
||||
*
|
||||
*/
|
||||
|
||||
public class MulExactLConstantTest {
|
||||
public static void main(String[] args) {
|
||||
Verify.ConstantLongTest.verify(new Verify.MulExactL());
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user