8302670: use-after-free related to PhaseIterGVN interaction with Unique_Node_List and Node_Stack
Co-authored-by: Justin King <jcking@openjdk.org> Reviewed-by: thartmann, chagedorn, jcking
This commit is contained in:
parent
d35a550f6d
commit
1f1f604071
@ -88,7 +88,7 @@ const TypeFunc *G1BarrierSetC2::write_ref_field_post_entry_Type() {
|
||||
* Returns true if the pre-barrier can be removed
|
||||
*/
|
||||
bool G1BarrierSetC2::g1_can_remove_pre_barrier(GraphKit* kit,
|
||||
PhaseTransform* phase,
|
||||
PhaseValues* phase,
|
||||
Node* adr,
|
||||
BasicType bt,
|
||||
uint adr_idx) const {
|
||||
@ -303,7 +303,7 @@ void G1BarrierSetC2::pre_barrier(GraphKit* kit,
|
||||
* Returns true if the post barrier can be removed
|
||||
*/
|
||||
bool G1BarrierSetC2::g1_can_remove_post_barrier(GraphKit* kit,
|
||||
PhaseTransform* phase, Node* store,
|
||||
PhaseValues* phase, Node* store,
|
||||
Node* adr) const {
|
||||
intptr_t offset = 0;
|
||||
Node* base = AddPNode::Ideal_base_and_offset(adr, phase, offset);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2018, 2023, 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
|
||||
@ -55,13 +55,13 @@ protected:
|
||||
bool use_precise) const;
|
||||
|
||||
bool g1_can_remove_pre_barrier(GraphKit* kit,
|
||||
PhaseTransform* phase,
|
||||
PhaseValues* phase,
|
||||
Node* adr,
|
||||
BasicType bt,
|
||||
uint adr_idx) const;
|
||||
|
||||
bool g1_can_remove_post_barrier(GraphKit* kit,
|
||||
PhaseTransform* phase, Node* store,
|
||||
PhaseValues* phase, Node* store,
|
||||
Node* adr) const;
|
||||
|
||||
void g1_mark_card(GraphKit* kit,
|
||||
|
@ -97,7 +97,7 @@ Node* ShenandoahBarrierSetC2::shenandoah_iu_barrier(GraphKit* kit, Node* obj) co
|
||||
|
||||
#define __ kit->
|
||||
|
||||
bool ShenandoahBarrierSetC2::satb_can_remove_pre_barrier(GraphKit* kit, PhaseTransform* phase, Node* adr,
|
||||
bool ShenandoahBarrierSetC2::satb_can_remove_pre_barrier(GraphKit* kit, PhaseValues* phase, Node* adr,
|
||||
BasicType bt, uint adr_idx) const {
|
||||
intptr_t offset = 0;
|
||||
Node* base = AddPNode::Ideal_base_and_offset(adr, phase, offset);
|
||||
@ -309,7 +309,7 @@ bool ShenandoahBarrierSetC2::is_shenandoah_lrb_call(Node* call) {
|
||||
(entry_point == CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_phantom));
|
||||
}
|
||||
|
||||
bool ShenandoahBarrierSetC2::is_shenandoah_marking_if(PhaseTransform *phase, Node* n) {
|
||||
bool ShenandoahBarrierSetC2::is_shenandoah_marking_if(PhaseValues* phase, Node* n) {
|
||||
if (n->Opcode() != Op_If) {
|
||||
return false;
|
||||
}
|
||||
|
@ -52,7 +52,7 @@ class ShenandoahBarrierSetC2 : public BarrierSetC2 {
|
||||
private:
|
||||
void shenandoah_eliminate_wb_pre(Node* call, PhaseIterGVN* igvn) const;
|
||||
|
||||
bool satb_can_remove_pre_barrier(GraphKit* kit, PhaseTransform* phase, Node* adr,
|
||||
bool satb_can_remove_pre_barrier(GraphKit* kit, PhaseValues* phase, Node* adr,
|
||||
BasicType bt, uint adr_idx) const;
|
||||
void satb_write_barrier_pre(GraphKit* kit, bool do_load,
|
||||
Node* obj,
|
||||
@ -94,7 +94,7 @@ public:
|
||||
|
||||
static bool is_shenandoah_wb_pre_call(Node* call);
|
||||
static bool is_shenandoah_lrb_call(Node* call);
|
||||
static bool is_shenandoah_marking_if(PhaseTransform *phase, Node* n);
|
||||
static bool is_shenandoah_marking_if(PhaseValues* phase, Node* n);
|
||||
static bool is_shenandoah_state_load(Node* n);
|
||||
static bool has_only_shenandoah_wb_pre_uses(Node* n);
|
||||
|
||||
|
@ -61,6 +61,11 @@ class Dict : public AnyObj { // Dictionary structure
|
||||
Dict(const Dict &base, Arena* arena); // Deep-copy
|
||||
~Dict();
|
||||
|
||||
NONCOPYABLE(Dict);
|
||||
Dict& operator=(Dict&&) = delete;
|
||||
// Allow move constructor for && (eg. capture return of function)
|
||||
Dict(Dict&&) = default;
|
||||
|
||||
// Return # of key-value pairs in dict
|
||||
uint32_t Size(void) const { return _cnt; }
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2023, 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
|
||||
@ -55,6 +55,11 @@ public:
|
||||
VectorSet(Arena* arena);
|
||||
~VectorSet() {}
|
||||
|
||||
NONCOPYABLE(VectorSet);
|
||||
VectorSet& operator=(VectorSet&&) = delete;
|
||||
// Allow move constructor for && (eg. capture return of function)
|
||||
VectorSet(VectorSet&&) = default;
|
||||
|
||||
void insert(uint elem);
|
||||
bool is_empty() const;
|
||||
void reset() {
|
||||
|
@ -668,7 +668,7 @@ const Type* AddPNode::Value(PhaseGVN* phase) const {
|
||||
// Split an oop pointer into a base and offset.
|
||||
// (The offset might be Type::OffsetBot in the case of an array.)
|
||||
// Return the base, or null if failure.
|
||||
Node* AddPNode::Ideal_base_and_offset(Node* ptr, PhaseTransform* phase,
|
||||
Node* AddPNode::Ideal_base_and_offset(Node* ptr, PhaseValues* phase,
|
||||
// second return value:
|
||||
intptr_t& offset) {
|
||||
if (ptr->is_AddP()) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2023, 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
|
||||
@ -166,7 +166,7 @@ public:
|
||||
virtual const Type *bottom_type() const;
|
||||
virtual uint ideal_reg() const { return Op_RegP; }
|
||||
Node *base_node() { assert( req() > Base, "Missing base"); return in(Base); }
|
||||
static Node* Ideal_base_and_offset(Node* ptr, PhaseTransform* phase,
|
||||
static Node* Ideal_base_and_offset(Node* ptr, PhaseValues* phase,
|
||||
// second return value:
|
||||
intptr_t& offset);
|
||||
|
||||
|
@ -654,7 +654,7 @@ Node *ArrayCopyNode::Ideal(PhaseGVN *phase, bool can_reshape) {
|
||||
return mem;
|
||||
}
|
||||
|
||||
bool ArrayCopyNode::may_modify(const TypeOopPtr *t_oop, PhaseTransform *phase) {
|
||||
bool ArrayCopyNode::may_modify(const TypeOopPtr* t_oop, PhaseValues* phase) {
|
||||
Node* dest = in(ArrayCopyNode::Dest);
|
||||
if (dest->is_top()) {
|
||||
return false;
|
||||
@ -672,7 +672,7 @@ bool ArrayCopyNode::may_modify(const TypeOopPtr *t_oop, PhaseTransform *phase) {
|
||||
return CallNode::may_modify_arraycopy_helper(dest_t, t_oop, phase);
|
||||
}
|
||||
|
||||
bool ArrayCopyNode::may_modify_helper(const TypeOopPtr *t_oop, Node* n, PhaseTransform *phase, CallNode*& call) {
|
||||
bool ArrayCopyNode::may_modify_helper(const TypeOopPtr* t_oop, Node* n, PhaseValues* phase, CallNode*& call) {
|
||||
if (n != nullptr &&
|
||||
n->is_Call() &&
|
||||
n->as_Call()->may_modify(t_oop, phase) &&
|
||||
@ -683,8 +683,7 @@ bool ArrayCopyNode::may_modify_helper(const TypeOopPtr *t_oop, Node* n, PhaseTra
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ArrayCopyNode::may_modify(const TypeOopPtr *t_oop, MemBarNode* mb, PhaseTransform *phase, ArrayCopyNode*& ac) {
|
||||
|
||||
bool ArrayCopyNode::may_modify(const TypeOopPtr* t_oop, MemBarNode* mb, PhaseValues* phase, ArrayCopyNode*& ac) {
|
||||
Node* c = mb->in(0);
|
||||
|
||||
BarrierSetC2* bs = BarrierSet::barrier_set()->barrier_set_c2();
|
||||
@ -725,7 +724,7 @@ bool ArrayCopyNode::may_modify(const TypeOopPtr *t_oop, MemBarNode* mb, PhaseTra
|
||||
// between offset_lo and offset_hi
|
||||
// if must_modify is true, return true if the copy is guaranteed to
|
||||
// write between offset_lo and offset_hi
|
||||
bool ArrayCopyNode::modifies(intptr_t offset_lo, intptr_t offset_hi, PhaseTransform* phase, bool must_modify) const {
|
||||
bool ArrayCopyNode::modifies(intptr_t offset_lo, intptr_t offset_hi, PhaseValues* phase, bool must_modify) const {
|
||||
assert(_kind == ArrayCopy || _kind == CopyOf || _kind == CopyOfRange, "only for real array copies");
|
||||
|
||||
Node* dest = in(Dest);
|
||||
|
@ -111,7 +111,7 @@ private:
|
||||
BasicType copy_type, const Type* value_type, int count);
|
||||
bool finish_transform(PhaseGVN *phase, bool can_reshape,
|
||||
Node* ctl, Node *mem);
|
||||
static bool may_modify_helper(const TypeOopPtr *t_oop, Node* n, PhaseTransform *phase, CallNode*& call);
|
||||
static bool may_modify_helper(const TypeOopPtr* t_oop, Node* n, PhaseValues* phase, CallNode*& call);
|
||||
public:
|
||||
static Node* load(BarrierSetC2* bs, PhaseGVN *phase, Node*& ctl, MergeMemNode* mem, Node* addr, const TypePtr* adr_type, const Type *type, BasicType bt);
|
||||
private:
|
||||
@ -173,17 +173,17 @@ public:
|
||||
virtual bool guaranteed_safepoint() { return false; }
|
||||
virtual Node *Ideal(PhaseGVN *phase, bool can_reshape);
|
||||
|
||||
virtual bool may_modify(const TypeOopPtr *t_oop, PhaseTransform *phase);
|
||||
virtual bool may_modify(const TypeOopPtr* t_oop, PhaseValues* phase);
|
||||
|
||||
bool is_alloc_tightly_coupled() const { return _alloc_tightly_coupled; }
|
||||
|
||||
bool has_negative_length_guard() const { return _has_negative_length_guard; }
|
||||
|
||||
static bool may_modify(const TypeOopPtr *t_oop, MemBarNode* mb, PhaseTransform *phase, ArrayCopyNode*& ac);
|
||||
static bool may_modify(const TypeOopPtr* t_oop, MemBarNode* mb, PhaseValues* phase, ArrayCopyNode*& ac);
|
||||
|
||||
static int get_partial_inline_vector_lane_count(BasicType type, int const_len);
|
||||
|
||||
bool modifies(intptr_t offset_lo, intptr_t offset_hi, PhaseTransform* phase, bool must_modify) const;
|
||||
bool modifies(intptr_t offset_lo, intptr_t offset_hi, PhaseValues* phase, bool must_modify) const;
|
||||
|
||||
#ifndef PRODUCT
|
||||
virtual void dump_spec(outputStream *st) const;
|
||||
|
@ -786,7 +786,7 @@ uint CallNode::match_edge(uint idx) const {
|
||||
// Determine whether the call could modify the field of the specified
|
||||
// instance at the specified offset.
|
||||
//
|
||||
bool CallNode::may_modify(const TypeOopPtr *t_oop, PhaseTransform *phase) {
|
||||
bool CallNode::may_modify(const TypeOopPtr* t_oop, PhaseValues* phase) {
|
||||
assert((t_oop != nullptr), "sanity");
|
||||
if (is_call_to_arraycopystub() && strcmp(_name, "unsafe_arraycopy") != 0) {
|
||||
const TypeTuple* args = _tf->domain();
|
||||
@ -1581,7 +1581,7 @@ Node *AllocateNode::make_ideal_mark(PhaseGVN *phase, Node* obj, Node* control, N
|
||||
// Retrieve the length from the AllocateArrayNode. Narrow the type with a
|
||||
// CastII, if appropriate. If we are not allowed to create new nodes, and
|
||||
// a CastII is appropriate, return null.
|
||||
Node *AllocateArrayNode::make_ideal_length(const TypeOopPtr* oop_type, PhaseTransform *phase, bool allow_new_nodes) {
|
||||
Node *AllocateArrayNode::make_ideal_length(const TypeOopPtr* oop_type, PhaseValues* phase, bool allow_new_nodes) {
|
||||
Node *length = in(AllocateNode::ALength);
|
||||
assert(length != nullptr, "length is not null");
|
||||
|
||||
@ -2195,7 +2195,7 @@ void AbstractLockNode::log_lock_optimization(Compile *C, const char * tag, Node*
|
||||
}
|
||||
}
|
||||
|
||||
bool CallNode::may_modify_arraycopy_helper(const TypeOopPtr* dest_t, const TypeOopPtr *t_oop, PhaseTransform *phase) {
|
||||
bool CallNode::may_modify_arraycopy_helper(const TypeOopPtr* dest_t, const TypeOopPtr* t_oop, PhaseValues* phase) {
|
||||
if (dest_t->is_known_instance() && t_oop->is_known_instance()) {
|
||||
return dest_t->instance_id() == t_oop->instance_id();
|
||||
}
|
||||
|
@ -581,7 +581,7 @@ class CallNode : public SafePointNode {
|
||||
friend class VMStructs;
|
||||
|
||||
protected:
|
||||
bool may_modify_arraycopy_helper(const TypeOopPtr* dest_t, const TypeOopPtr* t_oop, PhaseTransform* phase);
|
||||
bool may_modify_arraycopy_helper(const TypeOopPtr* dest_t, const TypeOopPtr* t_oop, PhaseValues* phase);
|
||||
|
||||
public:
|
||||
const TypeFunc* _tf; // Function type
|
||||
@ -629,7 +629,7 @@ public:
|
||||
virtual bool needs_deep_clone_jvms(Compile* C) { return C->needs_deep_clone_jvms(); }
|
||||
|
||||
// Returns true if the call may modify n
|
||||
virtual bool may_modify(const TypeOopPtr* t_oop, PhaseTransform* phase);
|
||||
virtual bool may_modify(const TypeOopPtr* t_oop, PhaseValues* phase);
|
||||
// Does this node have a use of n other than in debug information?
|
||||
bool has_non_debug_use(Node* n);
|
||||
// Returns the unique CheckCastPP of a call
|
||||
@ -913,7 +913,7 @@ public:
|
||||
virtual bool guaranteed_safepoint() { return false; }
|
||||
|
||||
// allocations do not modify their arguments
|
||||
virtual bool may_modify(const TypeOopPtr *t_oop, PhaseTransform *phase) { return false;}
|
||||
virtual bool may_modify(const TypeOopPtr* t_oop, PhaseValues* phase) { return false;}
|
||||
|
||||
// Pattern-match a possible usage of AllocateNode.
|
||||
// Return null if no allocation is recognized.
|
||||
@ -922,16 +922,16 @@ public:
|
||||
// (Note: This function is defined in file graphKit.cpp, near
|
||||
// GraphKit::new_instance/new_array, whose output it recognizes.)
|
||||
// The 'ptr' may not have an offset unless the 'offset' argument is given.
|
||||
static AllocateNode* Ideal_allocation(Node* ptr, PhaseTransform* phase);
|
||||
static AllocateNode* Ideal_allocation(Node* ptr, PhaseValues* phase);
|
||||
|
||||
// Fancy version which uses AddPNode::Ideal_base_and_offset to strip
|
||||
// an offset, which is reported back to the caller.
|
||||
// (Note: AllocateNode::Ideal_allocation is defined in graphKit.cpp.)
|
||||
static AllocateNode* Ideal_allocation(Node* ptr, PhaseTransform* phase,
|
||||
static AllocateNode* Ideal_allocation(Node* ptr, PhaseValues* phase,
|
||||
intptr_t& offset);
|
||||
|
||||
// Dig the klass operand out of a (possible) allocation site.
|
||||
static Node* Ideal_klass(Node* ptr, PhaseTransform* phase) {
|
||||
static Node* Ideal_klass(Node* ptr, PhaseValues* phase) {
|
||||
AllocateNode* allo = Ideal_allocation(ptr, phase);
|
||||
return (allo == nullptr) ? nullptr : allo->in(KlassNode);
|
||||
}
|
||||
@ -997,11 +997,11 @@ public:
|
||||
|
||||
// Dig the length operand out of a array allocation site and narrow the
|
||||
// type with a CastII, if necesssary
|
||||
Node* make_ideal_length(const TypeOopPtr* ary_type, PhaseTransform *phase, bool can_create = true);
|
||||
Node* make_ideal_length(const TypeOopPtr* ary_type, PhaseValues* phase, bool can_create = true);
|
||||
|
||||
// Pattern-match a possible usage of AllocateArrayNode.
|
||||
// Return null if no allocation is recognized.
|
||||
static AllocateArrayNode* Ideal_array_allocation(Node* ptr, PhaseTransform* phase) {
|
||||
static AllocateArrayNode* Ideal_array_allocation(Node* ptr, PhaseValues* phase) {
|
||||
AllocateNode* allo = Ideal_allocation(ptr, phase);
|
||||
return (allo == nullptr || !allo->is_AllocateArray())
|
||||
? nullptr : allo->as_AllocateArray();
|
||||
@ -1071,7 +1071,7 @@ public:
|
||||
void set_nested() { _kind = Nested; set_eliminated_lock_counter(); }
|
||||
|
||||
// locking does not modify its arguments
|
||||
virtual bool may_modify(const TypeOopPtr *t_oop, PhaseTransform *phase){ return false;}
|
||||
virtual bool may_modify(const TypeOopPtr* t_oop, PhaseValues* phase){ return false; }
|
||||
|
||||
#ifndef PRODUCT
|
||||
void create_lock_counter(JVMState* s);
|
||||
|
@ -1089,9 +1089,8 @@ PhiNode* PhiNode::split_out_instance(const TypePtr* at, PhaseIterGVN *igvn) cons
|
||||
}
|
||||
}
|
||||
Compile *C = igvn->C;
|
||||
Arena *a = Thread::current()->resource_area();
|
||||
Node_Array node_map = new Node_Array(a);
|
||||
Node_Stack stack(a, C->live_nodes() >> 4);
|
||||
Node_Array node_map;
|
||||
Node_Stack stack(C->live_nodes() >> 4);
|
||||
PhiNode *nphi = slice_memory(at);
|
||||
igvn->register_new_node_with_optimizer( nphi );
|
||||
node_map.map(_idx, nphi);
|
||||
@ -1458,7 +1457,7 @@ Node* PhiNode::Identity(PhaseGVN* phase) {
|
||||
//-----------------------------unique_input------------------------------------
|
||||
// Find the unique value, discounting top, self-loops, and casts.
|
||||
// Return top if there are no inputs, and self if there are multiple.
|
||||
Node* PhiNode::unique_input(PhaseTransform* phase, bool uncast) {
|
||||
Node* PhiNode::unique_input(PhaseValues* phase, bool uncast) {
|
||||
// 1) One unique direct input,
|
||||
// or if uncast is true:
|
||||
// 2) some of the inputs have an intervening ConstraintCast
|
||||
|
@ -219,8 +219,8 @@ public:
|
||||
|
||||
// Determine a unique non-trivial input, if any.
|
||||
// Ignore casts if it helps. Return null on failure.
|
||||
Node* unique_input(PhaseTransform *phase, bool uncast);
|
||||
Node* unique_input(PhaseTransform *phase) {
|
||||
Node* unique_input(PhaseValues* phase, bool uncast);
|
||||
Node* unique_input(PhaseValues* phase) {
|
||||
Node* uin = unique_input(phase, false);
|
||||
if (uin == nullptr) {
|
||||
uin = unique_input(phase, true);
|
||||
|
@ -407,7 +407,7 @@ void Compile::remove_useless_node(Node* dead) {
|
||||
}
|
||||
|
||||
// Disconnect all useless nodes by disconnecting those at the boundary.
|
||||
void Compile::disconnect_useless_nodes(Unique_Node_List &useful, Unique_Node_List* worklist) {
|
||||
void Compile::disconnect_useless_nodes(Unique_Node_List& useful, Unique_Node_List& worklist) {
|
||||
uint next = 0;
|
||||
while (next < useful.size()) {
|
||||
Node *n = useful.at(next++);
|
||||
@ -430,7 +430,8 @@ void Compile::disconnect_useless_nodes(Unique_Node_List &useful, Unique_Node_Lis
|
||||
}
|
||||
}
|
||||
if (n->outcnt() == 1 && n->has_special_unique_user()) {
|
||||
worklist->push(n->unique_out());
|
||||
assert(useful.member(n->unique_out()), "do not push a useless node");
|
||||
worklist.push(n->unique_out());
|
||||
}
|
||||
}
|
||||
|
||||
@ -630,7 +631,9 @@ Compile::Compile( ciEnv* ci_env, ciMethod* target, int osr_bci,
|
||||
_mach_constant_base_node(nullptr),
|
||||
_Compile_types(mtCompiler),
|
||||
_initial_gvn(nullptr),
|
||||
_for_igvn(nullptr),
|
||||
_igvn_worklist(nullptr),
|
||||
_types(nullptr),
|
||||
_node_hash(nullptr),
|
||||
_late_inlines(comp_arena(), 2, 0, nullptr),
|
||||
_string_late_inlines(comp_arena(), 2, 0, nullptr),
|
||||
_boxing_late_inlines(comp_arena(), 2, 0, nullptr),
|
||||
@ -703,14 +706,14 @@ Compile::Compile( ciEnv* ci_env, ciMethod* target, int osr_bci,
|
||||
assert(num_alias_types() >= AliasIdxRaw, "");
|
||||
|
||||
#define MINIMUM_NODE_HASH 1023
|
||||
// Node list that Iterative GVN will start with
|
||||
Unique_Node_List for_igvn(comp_arena());
|
||||
set_for_igvn(&for_igvn);
|
||||
|
||||
// GVN that will be run immediately on new nodes
|
||||
uint estimated_size = method()->code_size()*4+64;
|
||||
estimated_size = (estimated_size < MINIMUM_NODE_HASH ? MINIMUM_NODE_HASH : estimated_size);
|
||||
PhaseGVN gvn(node_arena(), estimated_size);
|
||||
_igvn_worklist = new (comp_arena()) Unique_Node_List(comp_arena());
|
||||
_types = new (comp_arena()) Type_Array(comp_arena());
|
||||
_node_hash = new (comp_arena()) NodeHash(comp_arena(), estimated_size);
|
||||
PhaseGVN gvn;
|
||||
set_initial_gvn(&gvn);
|
||||
|
||||
print_inlining_init();
|
||||
@ -800,7 +803,7 @@ Compile::Compile( ciEnv* ci_env, ciMethod* target, int osr_bci,
|
||||
// Remove clutter produced by parsing.
|
||||
if (!failing()) {
|
||||
ResourceMark rm;
|
||||
PhaseRemoveUseless pru(initial_gvn(), &for_igvn);
|
||||
PhaseRemoveUseless pru(initial_gvn(), *igvn_worklist());
|
||||
}
|
||||
}
|
||||
|
||||
@ -917,7 +920,9 @@ Compile::Compile( ciEnv* ci_env,
|
||||
_mach_constant_base_node(nullptr),
|
||||
_Compile_types(mtCompiler),
|
||||
_initial_gvn(nullptr),
|
||||
_for_igvn(nullptr),
|
||||
_igvn_worklist(nullptr),
|
||||
_types(nullptr),
|
||||
_node_hash(nullptr),
|
||||
_number_of_mh_late_inlines(0),
|
||||
_print_inlining_stream(new (mtCompiler) stringStream()),
|
||||
_print_inlining_list(nullptr),
|
||||
@ -949,11 +954,11 @@ Compile::Compile( ciEnv* ci_env,
|
||||
Init(/*do_aliasing=*/ false);
|
||||
init_tf((*generator)());
|
||||
|
||||
_igvn_worklist = new (comp_arena()) Unique_Node_List(comp_arena());
|
||||
_types = new (comp_arena()) Type_Array(comp_arena());
|
||||
_node_hash = new (comp_arena()) NodeHash(comp_arena(), 255);
|
||||
{
|
||||
// The following is a dummy for the sake of GraphKit::gen_stub
|
||||
Unique_Node_List for_igvn(comp_arena());
|
||||
set_for_igvn(&for_igvn); // not used, but some GraphKit guys push on this
|
||||
PhaseGVN gvn(Thread::current()->resource_area(),255);
|
||||
PhaseGVN gvn;
|
||||
set_initial_gvn(&gvn); // not significant, but GraphKit guys use it pervasively
|
||||
gvn.transform_no_reclaim(top());
|
||||
|
||||
@ -1949,7 +1954,7 @@ void Compile::inline_string_calls(bool parse_time) {
|
||||
{
|
||||
// remove useless nodes to make the usage analysis simpler
|
||||
ResourceMark rm;
|
||||
PhaseRemoveUseless pru(initial_gvn(), for_igvn());
|
||||
PhaseRemoveUseless pru(initial_gvn(), *igvn_worklist());
|
||||
}
|
||||
|
||||
{
|
||||
@ -1980,9 +1985,7 @@ void Compile::inline_boxing_calls(PhaseIterGVN& igvn) {
|
||||
PhaseGVN* gvn = initial_gvn();
|
||||
set_inlining_incrementally(true);
|
||||
|
||||
assert( igvn._worklist.size() == 0, "should be done with igvn" );
|
||||
for_igvn()->clear();
|
||||
gvn->replace_with(&igvn);
|
||||
igvn_worklist()->ensure_empty(); // should be done with igvn
|
||||
|
||||
_late_inlines_pos = _late_inlines.length();
|
||||
|
||||
@ -2045,11 +2048,11 @@ void Compile::inline_incrementally_cleanup(PhaseIterGVN& igvn) {
|
||||
{
|
||||
TracePhase tp("incrementalInline_pru", &timers[_t_incrInline_pru]);
|
||||
ResourceMark rm;
|
||||
PhaseRemoveUseless pru(initial_gvn(), for_igvn());
|
||||
PhaseRemoveUseless pru(initial_gvn(), *igvn_worklist());
|
||||
}
|
||||
{
|
||||
TracePhase tp("incrementalInline_igvn", &timers[_t_incrInline_igvn]);
|
||||
igvn = PhaseIterGVN(initial_gvn());
|
||||
igvn.reset_from_gvn(initial_gvn());
|
||||
igvn.optimize();
|
||||
}
|
||||
print_method(PHASE_INCREMENTAL_INLINE_CLEANUP, 3);
|
||||
@ -2092,8 +2095,7 @@ void Compile::inline_incrementally(PhaseIterGVN& igvn) {
|
||||
}
|
||||
}
|
||||
|
||||
for_igvn()->clear();
|
||||
initial_gvn()->replace_with(&igvn);
|
||||
igvn_worklist()->ensure_empty(); // should be done with igvn
|
||||
|
||||
while (inline_incrementally_one()) {
|
||||
assert(!failing(), "inconsistent");
|
||||
@ -2110,12 +2112,11 @@ void Compile::inline_incrementally(PhaseIterGVN& igvn) {
|
||||
break; // no more progress
|
||||
}
|
||||
}
|
||||
assert( igvn._worklist.size() == 0, "should be done with igvn" );
|
||||
|
||||
igvn_worklist()->ensure_empty(); // should be done with igvn
|
||||
|
||||
if (_string_late_inlines.length() > 0) {
|
||||
assert(has_stringbuilder(), "inconsistent");
|
||||
for_igvn()->clear();
|
||||
initial_gvn()->replace_with(&igvn);
|
||||
|
||||
inline_string_calls(false);
|
||||
|
||||
@ -2137,8 +2138,7 @@ void Compile::process_late_inline_calls_no_inline(PhaseIterGVN& igvn) {
|
||||
assert(_late_inlines.length() > 0, "sanity");
|
||||
|
||||
while (_late_inlines.length() > 0) {
|
||||
for_igvn()->clear();
|
||||
initial_gvn()->replace_with(&igvn);
|
||||
igvn_worklist()->ensure_empty(); // should be done with igvn
|
||||
|
||||
while (inline_incrementally_one()) {
|
||||
assert(!failing(), "inconsistent");
|
||||
@ -2271,19 +2271,13 @@ void Compile::Optimize() {
|
||||
|
||||
if (!failing() && RenumberLiveNodes && live_nodes() + NodeLimitFudgeFactor < unique()) {
|
||||
Compile::TracePhase tp("", &timers[_t_renumberLive]);
|
||||
initial_gvn()->replace_with(&igvn);
|
||||
Unique_Node_List* old_worklist = for_igvn();
|
||||
old_worklist->clear();
|
||||
Unique_Node_List new_worklist(C->comp_arena());
|
||||
igvn_worklist()->ensure_empty(); // should be done with igvn
|
||||
{
|
||||
ResourceMark rm;
|
||||
PhaseRenumberLive prl = PhaseRenumberLive(initial_gvn(), for_igvn(), &new_worklist);
|
||||
PhaseRenumberLive prl(initial_gvn(), *igvn_worklist());
|
||||
}
|
||||
Unique_Node_List* save_for_igvn = for_igvn();
|
||||
set_for_igvn(&new_worklist);
|
||||
igvn = PhaseIterGVN(initial_gvn());
|
||||
igvn.reset_from_gvn(initial_gvn());
|
||||
igvn.optimize();
|
||||
set_for_igvn(old_worklist); // new_worklist is dead beyond this point
|
||||
}
|
||||
|
||||
// Now that all inlining is over and no PhaseRemoveUseless will run, cut edge from root to loop
|
||||
@ -2380,7 +2374,7 @@ void Compile::Optimize() {
|
||||
// Iterative Global Value Numbering, including ideal transforms
|
||||
{
|
||||
TracePhase tp("iterGVN2", &timers[_t_iterGVN2]);
|
||||
igvn = ccp;
|
||||
igvn.reset_from_igvn(&ccp);
|
||||
igvn.optimize();
|
||||
}
|
||||
print_method(PHASE_ITER_GVN2, 2);
|
||||
@ -2444,6 +2438,10 @@ void Compile::Optimize() {
|
||||
|
||||
process_print_inlining();
|
||||
|
||||
// We will never use the NodeHash table any more. Clear it so that final_graph_reshaping does not have
|
||||
// to remove hashes to unlock nodes for modifications.
|
||||
C->node_hash()->clear();
|
||||
|
||||
// A method with only infinite loops has no edges entering loops from root
|
||||
{
|
||||
TracePhase tp("graphReshape", &timers[_t_graphReshaping]);
|
||||
|
@ -66,6 +66,7 @@ class Node;
|
||||
class Node_Array;
|
||||
class Node_List;
|
||||
class Node_Notes;
|
||||
class NodeHash;
|
||||
class NodeCloneInfo;
|
||||
class OptoReg;
|
||||
class PhaseCFG;
|
||||
@ -87,6 +88,7 @@ class TypePtr;
|
||||
class TypeOopPtr;
|
||||
class TypeFunc;
|
||||
class TypeVect;
|
||||
class Type_Array;
|
||||
class Unique_Node_List;
|
||||
class UnstableIfTrap;
|
||||
class nmethod;
|
||||
@ -414,7 +416,16 @@ class Compile : public Phase {
|
||||
|
||||
// Parsing, optimization
|
||||
PhaseGVN* _initial_gvn; // Results of parse-time PhaseGVN
|
||||
Unique_Node_List* _for_igvn; // Initial work-list for next round of Iterative GVN
|
||||
|
||||
// Shared worklist for all IGVN rounds. Nodes can be pushed to it at any time.
|
||||
// If pushed outside IGVN, the Node is processed in the next IGVN round.
|
||||
Unique_Node_List* _igvn_worklist;
|
||||
|
||||
// Shared type array for GVN, IGVN and CCP. It maps node idx -> Type*.
|
||||
Type_Array* _types;
|
||||
|
||||
// Shared node hash table for GVN, IGVN and CCP.
|
||||
NodeHash* _node_hash;
|
||||
|
||||
GrowableArray<CallGenerator*> _late_inlines; // List of CallGenerators to be revisited after main parsing has finished.
|
||||
GrowableArray<CallGenerator*> _string_late_inlines; // same but for string operations
|
||||
@ -937,11 +948,21 @@ class Compile : public Phase {
|
||||
|
||||
// Parsing, optimization
|
||||
PhaseGVN* initial_gvn() { return _initial_gvn; }
|
||||
Unique_Node_List* for_igvn() { return _for_igvn; }
|
||||
Unique_Node_List* igvn_worklist() {
|
||||
assert(_igvn_worklist != nullptr, "must be created in Compile::Compile");
|
||||
return _igvn_worklist;
|
||||
}
|
||||
Type_Array* types() {
|
||||
assert(_types != nullptr, "must be created in Compile::Compile");
|
||||
return _types;
|
||||
}
|
||||
NodeHash* node_hash() {
|
||||
assert(_node_hash != nullptr, "must be created in Compile::Compile");
|
||||
return _node_hash;
|
||||
}
|
||||
inline void record_for_igvn(Node* n); // Body is after class Unique_Node_List in node.hpp.
|
||||
inline void remove_for_igvn(Node* n); // Body is after class Unique_Node_List in node.hpp.
|
||||
void set_initial_gvn(PhaseGVN *gvn) { _initial_gvn = gvn; }
|
||||
void set_for_igvn(Unique_Node_List *for_igvn) { _for_igvn = for_igvn; }
|
||||
|
||||
// Replace n by nn using initial_gvn, calling hash_delete and
|
||||
// record_for_igvn as needed.
|
||||
@ -950,7 +971,7 @@ class Compile : public Phase {
|
||||
|
||||
void identify_useful_nodes(Unique_Node_List &useful);
|
||||
void update_dead_node_list(Unique_Node_List &useful);
|
||||
void disconnect_useless_nodes(Unique_Node_List &useful, Unique_Node_List* worklist);
|
||||
void disconnect_useless_nodes(Unique_Node_List& useful, Unique_Node_List& worklist);
|
||||
|
||||
void remove_useless_node(Node* dead);
|
||||
|
||||
|
@ -1736,7 +1736,7 @@ int ConnectionGraph::find_init_values_phantom(JavaObjectNode* pta) {
|
||||
}
|
||||
|
||||
// Find fields initializing values for allocations.
|
||||
int ConnectionGraph::find_init_values_null(JavaObjectNode* pta, PhaseTransform* phase) {
|
||||
int ConnectionGraph::find_init_values_null(JavaObjectNode* pta, PhaseValues* phase) {
|
||||
assert(pta->escape_state() == PointsToNode::NoEscape, "Not escaped Allocate nodes only");
|
||||
Node* alloc = pta->ideal_node();
|
||||
// Do nothing for Call nodes since its fields values are unknown.
|
||||
@ -2498,7 +2498,7 @@ bool ConnectionGraph::is_captured_store_address(Node* addp) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int ConnectionGraph::address_offset(Node* adr, PhaseTransform *phase) {
|
||||
int ConnectionGraph::address_offset(Node* adr, PhaseValues* phase) {
|
||||
const Type *adr_type = phase->type(adr);
|
||||
if (adr->is_AddP() && adr_type->isa_oopptr() == nullptr && is_captured_store_address(adr)) {
|
||||
// We are computing a raw address for a store captured by an Initialize
|
||||
|
@ -426,7 +426,7 @@ private:
|
||||
int find_field_value(FieldNode* field);
|
||||
|
||||
// Find fields initializing values for allocations.
|
||||
int find_init_values_null (JavaObjectNode* ptn, PhaseTransform* phase);
|
||||
int find_init_values_null (JavaObjectNode* ptn, PhaseValues* phase);
|
||||
int find_init_values_phantom(JavaObjectNode* ptn);
|
||||
|
||||
// Set the escape state of an object and its fields.
|
||||
@ -526,7 +526,7 @@ private:
|
||||
bool is_oop_field(Node* n, int offset, bool* unsafe);
|
||||
static Node* find_second_addp(Node* addp, Node* n);
|
||||
// offset of a field reference
|
||||
int address_offset(Node* adr, PhaseTransform *phase);
|
||||
int address_offset(Node* adr, PhaseValues* phase);
|
||||
|
||||
bool is_captured_store_address(Node* addp);
|
||||
|
||||
|
@ -3918,7 +3918,7 @@ Node* GraphKit::new_array(Node* klass_node, // array klass (maybe variable)
|
||||
|
||||
//---------------------------Ideal_allocation----------------------------------
|
||||
// Given an oop pointer or raw pointer, see if it feeds from an AllocateNode.
|
||||
AllocateNode* AllocateNode::Ideal_allocation(Node* ptr, PhaseTransform* phase) {
|
||||
AllocateNode* AllocateNode::Ideal_allocation(Node* ptr, PhaseValues* phase) {
|
||||
if (ptr == nullptr) { // reduce dumb test in callers
|
||||
return nullptr;
|
||||
}
|
||||
@ -3945,7 +3945,7 @@ AllocateNode* AllocateNode::Ideal_allocation(Node* ptr, PhaseTransform* phase) {
|
||||
}
|
||||
|
||||
// Fancy version which also strips off an offset (and reports it to caller).
|
||||
AllocateNode* AllocateNode::Ideal_allocation(Node* ptr, PhaseTransform* phase,
|
||||
AllocateNode* AllocateNode::Ideal_allocation(Node* ptr, PhaseValues* phase,
|
||||
intptr_t& offset) {
|
||||
Node* base = AddPNode::Ideal_base_and_offset(ptr, phase, offset);
|
||||
if (base == nullptr) return nullptr;
|
||||
|
@ -1269,7 +1269,7 @@ Node* PhaseCFG::catch_cleanup_find_cloned_def(Block *use_blk, Node *def, Block *
|
||||
if( j == def_blk->_num_succs ) {
|
||||
// Block at same level in dom-tree is not a successor. It needs a
|
||||
// PhiNode, the PhiNode uses from the def and IT's uses need fixup.
|
||||
Node_Array inputs = new Node_List();
|
||||
Node_Array inputs;
|
||||
for(uint k = 1; k < use_blk->num_preds(); k++) {
|
||||
Block* block = get_block_for_node(use_blk->pred(k));
|
||||
inputs.map(k, catch_cleanup_find_cloned_def(block, def, def_blk, n_clone_idx));
|
||||
|
@ -259,8 +259,8 @@ void PhaseIdealLoop::set_early_ctrl(Node* n, bool update_body) {
|
||||
// set missing _ctrl entries on new nodes
|
||||
void PhaseIdealLoop::set_subtree_ctrl(Node* n, bool update_body) {
|
||||
// Already set? Get out.
|
||||
if (_nodes[n->_idx]) return;
|
||||
// Recursively set _nodes array to indicate where the Node goes
|
||||
if (_loop_or_ctrl[n->_idx]) return;
|
||||
// Recursively set _loop_or_ctrl array to indicate where the Node goes
|
||||
uint i;
|
||||
for (i = 0; i < n->req(); ++i) {
|
||||
Node *m = n->in(i);
|
||||
@ -4301,8 +4301,8 @@ void PhaseIdealLoop::build_and_optimize() {
|
||||
|
||||
VectorSet visited;
|
||||
// Pre-grow the mapping from Nodes to IdealLoopTrees.
|
||||
_nodes.map(C->unique(), nullptr);
|
||||
memset(_nodes.adr(), 0, wordSize * C->unique());
|
||||
_loop_or_ctrl.map(C->unique(), nullptr);
|
||||
memset(_loop_or_ctrl.adr(), 0, wordSize * C->unique());
|
||||
|
||||
// Pre-build the top-level outermost loop tree entry
|
||||
_ltree_root = new IdealLoopTree( this, C->root(), C->root() );
|
||||
@ -4368,7 +4368,7 @@ void PhaseIdealLoop::build_and_optimize() {
|
||||
if( _ltree_root->_child->beautify_loops( this ) ) {
|
||||
// Re-build loop tree!
|
||||
_ltree_root->_child = nullptr;
|
||||
_nodes.clear();
|
||||
_loop_or_ctrl.clear();
|
||||
reallocate_preorders();
|
||||
build_loop_tree();
|
||||
// Check for bailout, and return
|
||||
@ -4398,7 +4398,7 @@ void PhaseIdealLoop::build_and_optimize() {
|
||||
// into RegionNodes. It doesn't do this test against Root, so
|
||||
// we do it here.
|
||||
for( uint i = 1; i < C->root()->req(); i++ ) {
|
||||
if( !_nodes[C->root()->in(i)->_idx] ) { // Dead path into Root?
|
||||
if (!_loop_or_ctrl[C->root()->in(i)->_idx]) { // Dead path into Root?
|
||||
_igvn.delete_input_of(C->root(), i);
|
||||
i--; // Rerun same iteration on compressed edges
|
||||
}
|
||||
@ -4412,9 +4412,9 @@ void PhaseIdealLoop::build_and_optimize() {
|
||||
}
|
||||
|
||||
// Walk the DATA nodes and place into loops. Find earliest control
|
||||
// node. For CFG nodes, the _nodes array starts out and remains
|
||||
// node. For CFG nodes, the _loop_or_ctrl array starts out and remains
|
||||
// holding the associated IdealLoopTree pointer. For DATA nodes, the
|
||||
// _nodes array holds the earliest legal controlling CFG node.
|
||||
// _loop_or_ctrl array holds the earliest legal controlling CFG node.
|
||||
|
||||
// Allocate stack with enough space to avoid frequent realloc
|
||||
int stack_size = (C->live_nodes() >> 1) + 16; // (live_nodes>>1)+16 from Java2D stats
|
||||
@ -4719,7 +4719,7 @@ bool PhaseIdealLoop::verify_idom_and_nodes(Node* root, const PhaseIdealLoop* pha
|
||||
Node* n = worklist.at(i);
|
||||
// process node
|
||||
success &= verify_idom(n, phase_verify);
|
||||
success &= verify_nodes(n, phase_verify);
|
||||
success &= verify_loop_ctrl(n, phase_verify);
|
||||
// visit inputs
|
||||
for (uint j = 0; j < n->req(); j++) {
|
||||
if (n->in(j) != nullptr) {
|
||||
@ -4758,20 +4758,20 @@ bool PhaseIdealLoop::verify_idom(Node* n, const PhaseIdealLoop* phase_verify) co
|
||||
return true; // pass
|
||||
}
|
||||
|
||||
// Verify "_nodes": control and loop membership.
|
||||
// (0) _nodes[i] == nullptr -> node not reachable.
|
||||
// Verify "_loop_or_ctrl": control and loop membership.
|
||||
// (0) _loop_or_ctrl[i] == nullptr -> node not reachable.
|
||||
// (1) has_ctrl -> check lowest bit. 1 -> data node. 0 -> ctrl node.
|
||||
// (2) has_ctrl true: get_ctrl_no_update returns ctrl of data node.
|
||||
// (3) has_ctrl false: get_loop_idx returns IdealLoopTree for ctrl node.
|
||||
bool PhaseIdealLoop::verify_nodes(Node* n, const PhaseIdealLoop* phase_verify) const {
|
||||
bool PhaseIdealLoop::verify_loop_ctrl(Node* n, const PhaseIdealLoop* phase_verify) const {
|
||||
const uint i = n->_idx;
|
||||
// The loop-tree was built from def to use (top-down).
|
||||
// The verification happens from use to def (bottom-up).
|
||||
// We may thus find nodes during verification that are not in the loop-tree.
|
||||
if (_nodes[i] == nullptr || phase_verify->_nodes[i] == nullptr) {
|
||||
if (_nodes[i] != nullptr || phase_verify->_nodes[i] != nullptr) {
|
||||
if (_loop_or_ctrl[i] == nullptr || phase_verify->_loop_or_ctrl[i] == nullptr) {
|
||||
if (_loop_or_ctrl[i] != nullptr || phase_verify->_loop_or_ctrl[i] != nullptr) {
|
||||
tty->print_cr("Was reachable in only one. this %d, verify %d.",
|
||||
_nodes[i] != nullptr, phase_verify->_nodes[i] != nullptr);
|
||||
_loop_or_ctrl[i] != nullptr, phase_verify->_loop_or_ctrl[i] != nullptr);
|
||||
n->dump();
|
||||
return false; // fail
|
||||
}
|
||||
@ -4800,7 +4800,7 @@ bool PhaseIdealLoop::verify_nodes(Node* n, const PhaseIdealLoop* phase_verify) c
|
||||
// PhaseIdealLoop::split_if_with_blocks
|
||||
// at "set_ctrl(x, new_ctrl);"
|
||||
/*
|
||||
if( _nodes[i] != loop_verify->_nodes[i] &&
|
||||
if( _loop_or_ctrl[i] != loop_verify->_loop_or_ctrl[i] &&
|
||||
get_ctrl_no_update(n) != loop_verify->get_ctrl_no_update(n) ) {
|
||||
tty->print("Mismatched control setting for: ");
|
||||
n->dump();
|
||||
@ -5034,7 +5034,7 @@ void PhaseIdealLoop::recompute_dom_depth() {
|
||||
if (_dom_depth[i] > 0 && _idom[i] != nullptr) {
|
||||
_dom_depth[i] = no_depth_marker;
|
||||
|
||||
// heal _idom if it has a fwd mapping in _nodes
|
||||
// heal _idom if it has a fwd mapping in _loop_or_ctrl
|
||||
if (_idom[i]->in(0) == nullptr) {
|
||||
idom(i);
|
||||
}
|
||||
@ -5105,7 +5105,7 @@ IdealLoopTree *PhaseIdealLoop::sort( IdealLoopTree *loop, IdealLoopTree *innermo
|
||||
|
||||
//------------------------------build_loop_tree--------------------------------
|
||||
// I use a modified Vick/Tarjan algorithm. I need pre- and a post- visit
|
||||
// bits. The _nodes[] array is mapped by Node index and holds a null for
|
||||
// bits. The _loop_or_ctrl[] array is mapped by Node index and holds a null for
|
||||
// not-yet-pre-walked, pre-order # for pre-but-not-post-walked and holds the
|
||||
// tightest enclosing IdealLoopTree for post-walked.
|
||||
//
|
||||
@ -5231,7 +5231,7 @@ int PhaseIdealLoop::build_loop_tree_impl( Node *n, int pre_order ) {
|
||||
set_loop(m, l); // Set loop header to loop now
|
||||
|
||||
} else { // Else not a nested loop
|
||||
if( !_nodes[m->_idx] ) continue; // Dead code has no loop
|
||||
if (!_loop_or_ctrl[m->_idx]) continue; // Dead code has no loop
|
||||
l = get_loop(m); // Get previously determined loop
|
||||
// If successor is header of a loop (nest), move up-loop till it
|
||||
// is a member of some outer enclosing loop. Since there are no
|
||||
@ -5458,7 +5458,7 @@ bool PhaseIdealLoop::is_in_irreducible_loop(RegionNode* region) {
|
||||
#endif
|
||||
|
||||
//------------------------------build_loop_early-------------------------------
|
||||
// Put Data nodes into some loop nest, by setting the _nodes[]->loop mapping.
|
||||
// Put Data nodes into some loop nest, by setting the _loop_or_ctrl[]->loop mapping.
|
||||
// First pass computes the earliest controlling node possible. This is the
|
||||
// controlling input with the deepest dominating depth.
|
||||
void PhaseIdealLoop::build_loop_early( VectorSet &visited, Node_List &worklist, Node_Stack &nstack ) {
|
||||
@ -5487,7 +5487,7 @@ void PhaseIdealLoop::build_loop_early( VectorSet &visited, Node_List &worklist,
|
||||
// Normally I would use a set_loop here. But in this one special
|
||||
// case, it is legal (and expected) to change what loop a Node
|
||||
// belongs to.
|
||||
_nodes.map(n->_idx, (Node*)(ilt->_parent) );
|
||||
_loop_or_ctrl.map(n->_idx, (Node*)(ilt->_parent));
|
||||
}
|
||||
// Remove safepoints ONLY if I've already seen I don't need one.
|
||||
// (the old code here would yank a 2nd safepoint after seeing a
|
||||
@ -5646,7 +5646,7 @@ Node* PhaseIdealLoop::compute_lca_of_uses(Node* n, Node* early, bool verify) {
|
||||
Node *LCA = nullptr;
|
||||
for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax && LCA != early; i++) {
|
||||
Node* c = n->fast_out(i);
|
||||
if (_nodes[c->_idx] == nullptr)
|
||||
if (_loop_or_ctrl[c->_idx] == nullptr)
|
||||
continue; // Skip the occasional dead node
|
||||
if( c->is_Phi() ) { // For Phis, we must land above on the path
|
||||
for( uint j=1; j<c->req(); j++ ) {// For all inputs
|
||||
@ -5909,7 +5909,7 @@ void PhaseIdealLoop::init_dom_lca_tags() {
|
||||
}
|
||||
|
||||
//------------------------------build_loop_late--------------------------------
|
||||
// Put Data nodes into some loop nest, by setting the _nodes[]->loop mapping.
|
||||
// Put Data nodes into some loop nest, by setting the _loop_or_ctrl[]->loop mapping.
|
||||
// Second pass finds latest legal placement, and ideal loop placement.
|
||||
void PhaseIdealLoop::build_loop_late( VectorSet &visited, Node_List &worklist, Node_Stack &nstack ) {
|
||||
while (worklist.size() != 0) {
|
||||
@ -5919,7 +5919,7 @@ void PhaseIdealLoop::build_loop_late( VectorSet &visited, Node_List &worklist, N
|
||||
uint cnt = n->outcnt();
|
||||
uint i = 0;
|
||||
while (true) {
|
||||
assert( _nodes[n->_idx], "no dead nodes" );
|
||||
assert(_loop_or_ctrl[n->_idx], "no dead nodes");
|
||||
// Visit all children
|
||||
if (i < cnt) {
|
||||
Node* use = n->raw_out(i);
|
||||
@ -5927,7 +5927,7 @@ void PhaseIdealLoop::build_loop_late( VectorSet &visited, Node_List &worklist, N
|
||||
// Check for dead uses. Aggressively prune such junk. It might be
|
||||
// dead in the global sense, but still have local uses so I cannot
|
||||
// easily call 'remove_dead_node'.
|
||||
if( _nodes[use->_idx] != nullptr || use->is_top() ) { // Not dead?
|
||||
if (_loop_or_ctrl[use->_idx] != nullptr || use->is_top()) { // Not dead?
|
||||
// Due to cycles, we might not hit the same fixed point in the verify
|
||||
// pass as we do in the regular pass. Instead, visit such phis as
|
||||
// simple uses of the loop head.
|
||||
@ -5998,7 +5998,7 @@ void PhaseIdealLoop::verify_strip_mined_scheduling(Node *n, Node* least) {
|
||||
|
||||
|
||||
//------------------------------build_loop_late_post---------------------------
|
||||
// Put Data nodes into some loop nest, by setting the _nodes[]->loop mapping.
|
||||
// Put Data nodes into some loop nest, by setting the _loop_or_ctrl[]->loop mapping.
|
||||
// Second pass finds latest legal placement, and ideal loop placement.
|
||||
void PhaseIdealLoop::build_loop_late_post(Node *n) {
|
||||
build_loop_late_post_work(n, true);
|
||||
@ -6067,7 +6067,7 @@ void PhaseIdealLoop::build_loop_late_post_work(Node *n, bool pinned) {
|
||||
}
|
||||
} else { // No slot zero
|
||||
if( n->is_CFG() ) { // CFG with no slot 0 is dead
|
||||
_nodes.map(n->_idx,0); // No block setting, it's globally dead
|
||||
_loop_or_ctrl.map(n->_idx,0); // No block setting, it's globally dead
|
||||
return;
|
||||
}
|
||||
assert(!n->is_CFG() || n->outcnt() == 0, "");
|
||||
@ -6082,10 +6082,10 @@ void PhaseIdealLoop::build_loop_late_post_work(Node *n, bool pinned) {
|
||||
if( LCA == nullptr ) {
|
||||
#ifdef ASSERT
|
||||
for (DUIterator i1 = n->outs(); n->has_out(i1); i1++) {
|
||||
assert( _nodes[n->out(i1)->_idx] == nullptr, "all uses must also be dead");
|
||||
assert(_loop_or_ctrl[n->out(i1)->_idx] == nullptr, "all uses must also be dead");
|
||||
}
|
||||
#endif
|
||||
_nodes.map(n->_idx, 0); // This node is useless
|
||||
_loop_or_ctrl.map(n->_idx, 0); // This node is useless
|
||||
_deadlist.push(n);
|
||||
return;
|
||||
}
|
||||
@ -6366,7 +6366,7 @@ void PhaseIdealLoop::dump(IdealLoopTree* loop, uint idx, Node_List &rpo_list) co
|
||||
// Now scan for CFG nodes in the same loop
|
||||
for (uint j = idx; j > 0; j--) {
|
||||
Node* n = rpo_list[j-1];
|
||||
if (!_nodes[n->_idx]) // Skip dead nodes
|
||||
if (!_loop_or_ctrl[n->_idx]) // Skip dead nodes
|
||||
continue;
|
||||
|
||||
if (get_loop(n) != loop) { // Wrong loop nest
|
||||
@ -6399,14 +6399,14 @@ void PhaseIdealLoop::dump(IdealLoopTree* loop, uint idx, Node_List &rpo_list) co
|
||||
}
|
||||
}
|
||||
// Dump nodes it controls
|
||||
for (uint k = 0; k < _nodes.max(); k++) {
|
||||
for (uint k = 0; k < _loop_or_ctrl.max(); k++) {
|
||||
// (k < C->unique() && get_ctrl(find(k)) == n)
|
||||
if (k < C->unique() && _nodes[k] == (Node*)((intptr_t)n + 1)) {
|
||||
if (k < C->unique() && _loop_or_ctrl[k] == (Node*)((intptr_t)n + 1)) {
|
||||
Node* m = C->root()->find(k);
|
||||
if (m && m->outcnt() > 0) {
|
||||
if (!(has_ctrl(m) && get_ctrl_no_update(m) == n)) {
|
||||
tty->print_cr("*** BROKEN CTRL ACCESSOR! _nodes[k] is %p, ctrl is %p",
|
||||
_nodes[k], has_ctrl(m) ? get_ctrl_no_update(m) : nullptr);
|
||||
tty->print_cr("*** BROKEN CTRL ACCESSOR! _loop_or_ctrl[k] is %p, ctrl is %p",
|
||||
_loop_or_ctrl[k], has_ctrl(m) ? get_ctrl_no_update(m) : nullptr);
|
||||
}
|
||||
tty->sp(2 * loop->_nest + 1);
|
||||
m->dump();
|
||||
|
@ -142,7 +142,7 @@ public:
|
||||
|
||||
virtual Node *Ideal(PhaseGVN *phase, bool can_reshape);
|
||||
virtual int Opcode() const;
|
||||
bool can_be_counted_loop(PhaseTransform* phase) const {
|
||||
bool can_be_counted_loop(PhaseValues* phase) const {
|
||||
return req() == 3 && in(0) != nullptr &&
|
||||
in(1) != nullptr && phase->type(in(1)) != Type::TOP &&
|
||||
in(2) != nullptr && phase->type(in(2)) != Type::TOP;
|
||||
@ -832,6 +832,9 @@ class PhaseIdealLoop : public PhaseTransform {
|
||||
friend class ShenandoahBarrierC2Support;
|
||||
friend class AutoNodeBudget;
|
||||
|
||||
// Map loop membership for CFG nodes, and ctrl for non-CFG nodes.
|
||||
Node_List _loop_or_ctrl;
|
||||
|
||||
// Pre-computed def-use info
|
||||
PhaseIterGVN &_igvn;
|
||||
|
||||
@ -893,7 +896,7 @@ class PhaseIdealLoop : public PhaseTransform {
|
||||
public:
|
||||
// Set/get control node out. Set lower bit to distinguish from IdealLoopTree
|
||||
// Returns true if "n" is a data node, false if it's a control node.
|
||||
bool has_ctrl(const Node* n) const { return ((intptr_t)_nodes[n->_idx]) & 1; }
|
||||
bool has_ctrl(const Node* n) const { return ((intptr_t)_loop_or_ctrl[n->_idx]) & 1; }
|
||||
|
||||
private:
|
||||
// clear out dead code after build_loop_late
|
||||
@ -981,7 +984,7 @@ public:
|
||||
|
||||
bool has_node(const Node* n) const {
|
||||
guarantee(n != nullptr, "No Node.");
|
||||
return _nodes[n->_idx] != nullptr;
|
||||
return _loop_or_ctrl[n->_idx] != nullptr;
|
||||
}
|
||||
// check if transform created new nodes that need _ctrl recorded
|
||||
Node *get_late_ctrl( Node *n, Node *early );
|
||||
@ -993,7 +996,7 @@ public:
|
||||
assert( !has_node(n) || has_ctrl(n), "" );
|
||||
assert( ctrl->in(0), "cannot set dead control node" );
|
||||
assert( ctrl == find_non_split_ctrl(ctrl), "must set legal crtl" );
|
||||
_nodes.map( n->_idx, (Node*)((intptr_t)ctrl + 1) );
|
||||
_loop_or_ctrl.map(n->_idx, (Node*)((intptr_t)ctrl + 1));
|
||||
}
|
||||
// Set control and update loop membership
|
||||
void set_ctrl_and_loop(Node* n, Node* ctrl) {
|
||||
@ -1013,7 +1016,7 @@ public:
|
||||
Node* get_ctrl(const Node* i) {
|
||||
assert(has_node(i), "");
|
||||
Node *n = get_ctrl_no_update(i);
|
||||
_nodes.map( i->_idx, (Node*)((intptr_t)n + 1) );
|
||||
_loop_or_ctrl.map(i->_idx, (Node*)((intptr_t)n + 1));
|
||||
assert(has_node(i) && has_ctrl(i), "");
|
||||
assert(n == find_non_split_ctrl(n), "must return legal ctrl" );
|
||||
return n;
|
||||
@ -1032,7 +1035,7 @@ public:
|
||||
|
||||
Node* get_ctrl_no_update_helper(const Node* i) const {
|
||||
assert(has_ctrl(i), "should be control, not loop");
|
||||
return (Node*)(((intptr_t)_nodes[i->_idx]) & ~1);
|
||||
return (Node*)(((intptr_t)_loop_or_ctrl[i->_idx]) & ~1);
|
||||
}
|
||||
|
||||
Node* get_ctrl_no_update(const Node* i) const {
|
||||
@ -1056,7 +1059,7 @@ public:
|
||||
}
|
||||
// Set loop
|
||||
void set_loop( Node *n, IdealLoopTree *loop ) {
|
||||
_nodes.map(n->_idx, (Node*)loop);
|
||||
_loop_or_ctrl.map(n->_idx, (Node*)loop);
|
||||
}
|
||||
// Lazy-dazy update of 'get_ctrl' and 'idom_at' mechanisms. Replace
|
||||
// the 'old_node' with 'new_node'. Kill old-node. Add a reference
|
||||
@ -1066,7 +1069,7 @@ public:
|
||||
assert(old_node != new_node, "no cycles please");
|
||||
// Re-use the side array slot for this node to provide the
|
||||
// forwarding pointer.
|
||||
_nodes.map(old_node->_idx, (Node*)((intptr_t)new_node + 1));
|
||||
_loop_or_ctrl.map(old_node->_idx, (Node*)((intptr_t)new_node + 1));
|
||||
}
|
||||
void lazy_replace(Node *old_node, Node *new_node) {
|
||||
_igvn.replace_node(old_node, new_node);
|
||||
@ -1145,7 +1148,7 @@ public:
|
||||
Node* n = _idom[didx];
|
||||
assert(n != nullptr,"Bad immediate dominator info.");
|
||||
while (n->in(0) == nullptr) { // Skip dead CFG nodes
|
||||
n = (Node*)(((intptr_t)_nodes[n->_idx]) & ~1);
|
||||
n = (Node*)(((intptr_t)_loop_or_ctrl[n->_idx]) & ~1);
|
||||
assert(n != nullptr,"Bad immediate dominator info.");
|
||||
}
|
||||
return n;
|
||||
@ -1241,7 +1244,7 @@ public:
|
||||
// Dead nodes have no loop, so return the top level loop instead
|
||||
if (!has_node(n)) return _ltree_root;
|
||||
assert(!has_ctrl(n), "");
|
||||
return (IdealLoopTree*)_nodes[n->_idx];
|
||||
return (IdealLoopTree*)_loop_or_ctrl[n->_idx];
|
||||
}
|
||||
|
||||
IdealLoopTree* ltree_root() const { return _ltree_root; }
|
||||
@ -1666,7 +1669,7 @@ public:
|
||||
void dump(IdealLoopTree* loop, uint rpo_idx, Node_List &rpo_list) const;
|
||||
IdealLoopTree* get_loop_idx(Node* n) const {
|
||||
// Dead nodes have no loop, so return the top level loop instead
|
||||
return _nodes[n->_idx] ? (IdealLoopTree*)_nodes[n->_idx] : _ltree_root;
|
||||
return _loop_or_ctrl[n->_idx] ? (IdealLoopTree*)_loop_or_ctrl[n->_idx] : _ltree_root;
|
||||
}
|
||||
// Print some stats
|
||||
static void print_statistics();
|
||||
@ -1681,7 +1684,7 @@ public:
|
||||
void verify() const;
|
||||
bool verify_idom_and_nodes(Node* root, const PhaseIdealLoop* phase_verify) const;
|
||||
bool verify_idom(Node* n, const PhaseIdealLoop* phase_verify) const;
|
||||
bool verify_nodes(Node* n, const PhaseIdealLoop* phase_verify) const;
|
||||
bool verify_loop_ctrl(Node* n, const PhaseIdealLoop* phase_verify) const;
|
||||
#endif
|
||||
|
||||
void rpo(Node* start, Node_Stack &stk, VectorSet &visited, Node_List &rpo_list) const;
|
||||
|
@ -62,6 +62,7 @@ const uint Matcher::_end_rematerialize = _END_REMATERIALIZE;
|
||||
Matcher::Matcher()
|
||||
: PhaseTransform( Phase::Ins_Select ),
|
||||
_states_arena(Chunk::medium_size, mtCompiler),
|
||||
_new_nodes(C->comp_arena()),
|
||||
_visited(&_states_arena),
|
||||
_shared(&_states_arena),
|
||||
_dontcare(&_states_arena),
|
||||
|
@ -88,6 +88,9 @@ private:
|
||||
// Private arena of State objects
|
||||
ResourceArea _states_arena;
|
||||
|
||||
// Map old nodes to new nodes
|
||||
Node_List _new_nodes;
|
||||
|
||||
VectorSet _visited; // Visit bits
|
||||
|
||||
// Used to control the Label pass
|
||||
@ -147,20 +150,19 @@ private:
|
||||
VectorSet _reused; // Ideal IGV identifiers reused by machine nodes
|
||||
#endif // !PRODUCT
|
||||
|
||||
// Accessors for the inherited field PhaseTransform::_nodes:
|
||||
void grow_new_node_array(uint idx_limit) {
|
||||
_nodes.map(idx_limit-1, nullptr);
|
||||
_new_nodes.map(idx_limit-1, nullptr);
|
||||
}
|
||||
bool has_new_node(const Node* n) const {
|
||||
return _nodes.at(n->_idx) != nullptr;
|
||||
return _new_nodes.at(n->_idx) != nullptr;
|
||||
}
|
||||
Node* new_node(const Node* n) const {
|
||||
assert(has_new_node(n), "set before get");
|
||||
return _nodes.at(n->_idx);
|
||||
return _new_nodes.at(n->_idx);
|
||||
}
|
||||
void set_new_node(const Node* n, Node *nn) {
|
||||
assert(!has_new_node(n), "set only once");
|
||||
_nodes.map(n->_idx, nn);
|
||||
_new_nodes.map(n->_idx, nn);
|
||||
}
|
||||
|
||||
#ifdef ASSERT
|
||||
|
@ -209,7 +209,7 @@ struct IdealHelper {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static const Type* Value(const OverflowOp* node, PhaseTransform* phase) {
|
||||
static const Type* Value(const OverflowOp* node, PhaseValues* phase) {
|
||||
const Type *t1 = phase->type( node->in(1) );
|
||||
const Type *t2 = phase->type( node->in(2) );
|
||||
if( t1 == Type::TOP ) return Type::TOP;
|
||||
|
@ -32,7 +32,6 @@
|
||||
#include "opto/type.hpp"
|
||||
|
||||
class PhaseGVN;
|
||||
class PhaseTransform;
|
||||
|
||||
class OverflowNode : public CmpNode {
|
||||
public:
|
||||
|
@ -552,7 +552,7 @@ bool MemNode::detect_ptr_independence(Node* p1, AllocateNode* a1,
|
||||
// In case (c) change the parameter mem to the memory input of ac to skip it
|
||||
// when searching stored value.
|
||||
// Otherwise return null.
|
||||
Node* LoadNode::find_previous_arraycopy(PhaseTransform* phase, Node* ld_alloc, Node*& mem, bool can_see_stored_value) const {
|
||||
Node* LoadNode::find_previous_arraycopy(PhaseValues* phase, Node* ld_alloc, Node*& mem, bool can_see_stored_value) const {
|
||||
ArrayCopyNode* ac = find_array_copy_clone(phase, ld_alloc, mem);
|
||||
if (ac != nullptr) {
|
||||
Node* ld_addp = in(MemNode::Address);
|
||||
@ -608,7 +608,7 @@ Node* LoadNode::find_previous_arraycopy(PhaseTransform* phase, Node* ld_alloc, N
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ArrayCopyNode* MemNode::find_array_copy_clone(PhaseTransform* phase, Node* ld_alloc, Node* mem) const {
|
||||
ArrayCopyNode* MemNode::find_array_copy_clone(PhaseValues* phase, Node* ld_alloc, Node* mem) const {
|
||||
if (mem->is_Proj() && mem->in(0) != nullptr && (mem->in(0)->Opcode() == Op_MemBarStoreStore ||
|
||||
mem->in(0)->Opcode() == Op_MemBarCPUOrder)) {
|
||||
if (ld_alloc != nullptr) {
|
||||
@ -652,7 +652,7 @@ ArrayCopyNode* MemNode::find_array_copy_clone(PhaseTransform* phase, Node* ld_al
|
||||
// specific to loads and stores, so they are handled by the callers.
|
||||
// (Currently, only LoadNode::Ideal has steps (c), (d). More later.)
|
||||
//
|
||||
Node* MemNode::find_previous_store(PhaseTransform* phase) {
|
||||
Node* MemNode::find_previous_store(PhaseValues* phase) {
|
||||
Node* ctrl = in(MemNode::Control);
|
||||
Node* adr = in(MemNode::Address);
|
||||
intptr_t offset = 0;
|
||||
@ -1054,7 +1054,7 @@ Node* LoadNode::can_see_arraycopy_value(Node* st, PhaseGVN* phase) const {
|
||||
// same time (uses the Oracle model of aliasing), then some
|
||||
// LoadXNode::Identity will fold things back to the equivalence-class model
|
||||
// of aliasing.
|
||||
Node* MemNode::can_see_stored_value(Node* st, PhaseTransform* phase) const {
|
||||
Node* MemNode::can_see_stored_value(Node* st, PhaseValues* phase) const {
|
||||
Node* ld_adr = in(MemNode::Address);
|
||||
intptr_t ld_off = 0;
|
||||
Node* ld_base = AddPNode::Ideal_base_and_offset(ld_adr, phase, ld_off);
|
||||
@ -2847,7 +2847,7 @@ Node *StoreNode::Ideal_sign_extended_input(PhaseGVN *phase, int num_bits) {
|
||||
// For simplicity, we actually check if there are any loads from the
|
||||
// address stored to, not just for loads of the value stored by this node.
|
||||
//
|
||||
bool StoreNode::value_never_loaded( PhaseTransform *phase) const {
|
||||
bool StoreNode::value_never_loaded(PhaseValues* phase) const {
|
||||
Node *adr = in(Address);
|
||||
const TypeOopPtr *adr_oop = phase->type(adr)->isa_oopptr();
|
||||
if (adr_oop == nullptr)
|
||||
@ -3137,7 +3137,7 @@ Node *ClearArrayNode::Ideal(PhaseGVN *phase, bool can_reshape) {
|
||||
//----------------------------step_through----------------------------------
|
||||
// Return allocation input memory edge if it is different instance
|
||||
// or itself if it is the one we are looking for.
|
||||
bool ClearArrayNode::step_through(Node** np, uint instance_id, PhaseTransform* phase) {
|
||||
bool ClearArrayNode::step_through(Node** np, uint instance_id, PhaseValues* phase) {
|
||||
Node* n = *np;
|
||||
assert(n->is_ClearArray(), "sanity");
|
||||
intptr_t offset;
|
||||
@ -3689,7 +3689,7 @@ void InitializeNode::remove_extra_zeroes() {
|
||||
}
|
||||
|
||||
// Helper for remembering which stores go with which offsets.
|
||||
intptr_t InitializeNode::get_store_offset(Node* st, PhaseTransform* phase) {
|
||||
intptr_t InitializeNode::get_store_offset(Node* st, PhaseValues* phase) {
|
||||
if (!st->is_Store()) return -1; // can happen to dead code via subsume_node
|
||||
intptr_t offset = -1;
|
||||
Node* base = AddPNode::Ideal_base_and_offset(st->in(MemNode::Address),
|
||||
@ -3883,7 +3883,7 @@ intptr_t InitializeNode::can_capture_store(StoreNode* st, PhaseGVN* phase, bool
|
||||
// If size_in_bytes is zero, do not bother with overlap checks.
|
||||
int InitializeNode::captured_store_insertion_point(intptr_t start,
|
||||
int size_in_bytes,
|
||||
PhaseTransform* phase) {
|
||||
PhaseValues* phase) {
|
||||
const int FAIL = 0, MAX_STORE = MAX2(BytesPerLong, (int)MaxVectorSize);
|
||||
|
||||
if (is_complete())
|
||||
@ -3937,7 +3937,7 @@ int InitializeNode::captured_store_insertion_point(intptr_t start,
|
||||
// initialization interferes, then return zero_memory (the memory
|
||||
// projection of the AllocateNode).
|
||||
Node* InitializeNode::find_captured_store(intptr_t start, int size_in_bytes,
|
||||
PhaseTransform* phase) {
|
||||
PhaseValues* phase) {
|
||||
assert(stores_are_sane(phase), "");
|
||||
int i = captured_store_insertion_point(start, size_in_bytes, phase);
|
||||
if (i == 0) {
|
||||
@ -3953,7 +3953,7 @@ Node* InitializeNode::find_captured_store(intptr_t start, int size_in_bytes,
|
||||
|
||||
// Create, as a raw pointer, an address within my new object at 'offset'.
|
||||
Node* InitializeNode::make_raw_address(intptr_t offset,
|
||||
PhaseTransform* phase) {
|
||||
PhaseGVN* phase) {
|
||||
Node* addr = in(RawAddress);
|
||||
if (offset != 0) {
|
||||
Compile* C = phase->C;
|
||||
@ -4497,7 +4497,7 @@ Node* InitializeNode::complete_stores(Node* rawctl, Node* rawmem, Node* rawptr,
|
||||
|
||||
|
||||
#ifdef ASSERT
|
||||
bool InitializeNode::stores_are_sane(PhaseTransform* phase) {
|
||||
bool InitializeNode::stores_are_sane(PhaseValues* phase) {
|
||||
if (is_complete())
|
||||
return true; // stores could be anything at this point
|
||||
assert(allocation() != nullptr, "must be present");
|
||||
|
@ -92,8 +92,8 @@ protected:
|
||||
debug_only(_adr_type=at; adr_type();)
|
||||
}
|
||||
|
||||
virtual Node* find_previous_arraycopy(PhaseTransform* phase, Node* ld_alloc, Node*& mem, bool can_see_stored_value) const { return nullptr; }
|
||||
ArrayCopyNode* find_array_copy_clone(PhaseTransform* phase, Node* ld_alloc, Node* mem) const;
|
||||
virtual Node* find_previous_arraycopy(PhaseValues* phase, Node* ld_alloc, Node*& mem, bool can_see_stored_value) const { return nullptr; }
|
||||
ArrayCopyNode* find_array_copy_clone(PhaseValues* phase, Node* ld_alloc, Node* mem) const;
|
||||
static bool check_if_adr_maybe_raw(Node* adr);
|
||||
|
||||
public:
|
||||
@ -146,11 +146,11 @@ public:
|
||||
// Search through memory states which precede this node (load or store).
|
||||
// Look for an exact match for the address, with no intervening
|
||||
// aliased stores.
|
||||
Node* find_previous_store(PhaseTransform* phase);
|
||||
Node* find_previous_store(PhaseValues* phase);
|
||||
|
||||
// Can this node (load or store) accurately see a stored value in
|
||||
// the given memory state? (The state may or may not be in(Memory).)
|
||||
Node* can_see_stored_value(Node* st, PhaseTransform* phase) const;
|
||||
Node* can_see_stored_value(Node* st, PhaseValues* phase) const;
|
||||
|
||||
void set_unaligned_access() { _unaligned_access = true; }
|
||||
bool is_unaligned_access() const { return _unaligned_access; }
|
||||
@ -208,7 +208,7 @@ protected:
|
||||
virtual bool can_remove_control() const;
|
||||
const Type* const _type; // What kind of value is loaded?
|
||||
|
||||
virtual Node* find_previous_arraycopy(PhaseTransform* phase, Node* ld_alloc, Node*& mem, bool can_see_stored_value) const;
|
||||
virtual Node* find_previous_arraycopy(PhaseValues* phase, Node* ld_alloc, Node*& mem, bool can_see_stored_value) const;
|
||||
public:
|
||||
|
||||
LoadNode(Node *c, Node *mem, Node *adr, const TypePtr* at, const Type *rt, MemOrd mo, ControlDependency control_dependency)
|
||||
@ -633,7 +633,7 @@ public:
|
||||
virtual int store_Opcode() const { return Opcode(); }
|
||||
|
||||
// have all possible loads of the value stored been optimized away?
|
||||
bool value_never_loaded(PhaseTransform *phase) const;
|
||||
bool value_never_loaded(PhaseValues* phase) const;
|
||||
|
||||
bool has_reinterpret_variant(const Type* vt);
|
||||
Node* convert_to_reinterpret_store(PhaseGVN& gvn, Node* val, const Type* vt);
|
||||
@ -1117,7 +1117,7 @@ public:
|
||||
PhaseGVN* phase);
|
||||
// Return allocation input memory edge if it is different instance
|
||||
// or itself if it is the one we are looking for.
|
||||
static bool step_through(Node** np, uint instance_id, PhaseTransform* phase);
|
||||
static bool step_through(Node** np, uint instance_id, PhaseValues* phase);
|
||||
};
|
||||
|
||||
//------------------------------MemBar-----------------------------------------
|
||||
@ -1354,7 +1354,7 @@ public:
|
||||
|
||||
#ifdef ASSERT
|
||||
// ensure all non-degenerate stores are ordered and non-overlapping
|
||||
bool stores_are_sane(PhaseTransform* phase);
|
||||
bool stores_are_sane(PhaseValues* phase);
|
||||
#endif //ASSERT
|
||||
|
||||
// See if this store can be captured; return offset where it initializes.
|
||||
@ -1368,7 +1368,7 @@ public:
|
||||
// Find captured store which corresponds to the range [start..start+size).
|
||||
// Return my own memory projection (meaning the initial zero bits)
|
||||
// if there is no such store. Return null if there is a problem.
|
||||
Node* find_captured_store(intptr_t start, int size_in_bytes, PhaseTransform* phase);
|
||||
Node* find_captured_store(intptr_t start, int size_in_bytes, PhaseValues* phase);
|
||||
|
||||
// Called when the associated AllocateNode is expanded into CFG.
|
||||
Node* complete_stores(Node* rawctl, Node* rawmem, Node* rawptr,
|
||||
@ -1380,11 +1380,11 @@ public:
|
||||
|
||||
// Find out where a captured store should be placed (or already is placed).
|
||||
int captured_store_insertion_point(intptr_t start, int size_in_bytes,
|
||||
PhaseTransform* phase);
|
||||
PhaseValues* phase);
|
||||
|
||||
static intptr_t get_store_offset(Node* st, PhaseTransform* phase);
|
||||
static intptr_t get_store_offset(Node* st, PhaseValues* phase);
|
||||
|
||||
Node* make_raw_address(intptr_t offset, PhaseTransform* phase);
|
||||
Node* make_raw_address(intptr_t offset, PhaseGVN* phase);
|
||||
|
||||
bool detect_init_independence(Node* value, PhaseGVN* phase);
|
||||
|
||||
|
@ -1551,8 +1551,13 @@ public:
|
||||
_nodes = NEW_ARENA_ARRAY(a, Node*, max);
|
||||
clear();
|
||||
}
|
||||
Node_Array() : Node_Array(Thread::current()->resource_area()) {}
|
||||
|
||||
NONCOPYABLE(Node_Array);
|
||||
Node_Array& operator=(Node_Array&&) = delete;
|
||||
// Allow move constructor for && (eg. capture return of function)
|
||||
Node_Array(Node_Array&&) = default;
|
||||
|
||||
Node_Array(Node_Array* na) : _a(na->_a), _max(na->_max), _nodes(na->_nodes) {}
|
||||
Node *operator[] ( uint i ) const // Lookup, or null for not mapped
|
||||
{ return (i<_max) ? _nodes[i] : (Node*)nullptr; }
|
||||
Node* at(uint i) const { assert(i<_max,"oob"); return _nodes[i]; }
|
||||
@ -1576,6 +1581,12 @@ class Node_List : public Node_Array {
|
||||
public:
|
||||
Node_List(uint max = OptoNodeListSize) : Node_Array(Thread::current()->resource_area(), max), _cnt(0) {}
|
||||
Node_List(Arena *a, uint max = OptoNodeListSize) : Node_Array(a, max), _cnt(0) {}
|
||||
|
||||
NONCOPYABLE(Node_List);
|
||||
Node_List& operator=(Node_List&&) = delete;
|
||||
// Allow move constructor for && (eg. capture return of function)
|
||||
Node_List(Node_List&&) = default;
|
||||
|
||||
bool contains(const Node* n) const {
|
||||
for (uint e = 0; e < size(); e++) {
|
||||
if (at(e) == n) return true;
|
||||
@ -1610,6 +1621,11 @@ public:
|
||||
Unique_Node_List() : Node_List(), _clock_index(0) {}
|
||||
Unique_Node_List(Arena *a) : Node_List(a), _in_worklist(a), _clock_index(0) {}
|
||||
|
||||
NONCOPYABLE(Unique_Node_List);
|
||||
Unique_Node_List& operator=(Unique_Node_List&&) = delete;
|
||||
// Allow move constructor for && (eg. capture return of function)
|
||||
Unique_Node_List(Unique_Node_List&&) = default;
|
||||
|
||||
void remove( Node *n );
|
||||
bool member( Node *n ) { return _in_worklist.test(n->_idx) != 0; }
|
||||
VectorSet& member_set(){ return _in_worklist; }
|
||||
@ -1641,10 +1657,35 @@ public:
|
||||
Node_List::clear();
|
||||
_clock_index = 0;
|
||||
}
|
||||
void ensure_empty() {
|
||||
assert(size() == 0, "must be empty");
|
||||
clear(); // just in case
|
||||
}
|
||||
|
||||
// Used after parsing to remove useless nodes before Iterative GVN
|
||||
void remove_useless_nodes(VectorSet& useful);
|
||||
|
||||
// If the idx of the Nodes change, we must recompute the VectorSet
|
||||
void recompute_idx_set() {
|
||||
_in_worklist.clear();
|
||||
for (uint i = 0; i < size(); i++) {
|
||||
Node* n = at(i);
|
||||
_in_worklist.set(n->_idx);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef ASSERT
|
||||
bool is_subset_of(Unique_Node_List& other) {
|
||||
for (uint i = 0; i < size(); i++) {
|
||||
Node* n = at(i);
|
||||
if (!other.member(n)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool contains(const Node* n) const {
|
||||
fatal("use faster member() instead");
|
||||
return false;
|
||||
@ -1687,12 +1728,12 @@ private:
|
||||
|
||||
// Inline definition of Compile::record_for_igvn must be deferred to this point.
|
||||
inline void Compile::record_for_igvn(Node* n) {
|
||||
_for_igvn->push(n);
|
||||
_igvn_worklist->push(n);
|
||||
}
|
||||
|
||||
// Inline definition of Compile::remove_for_igvn must be deferred to this point.
|
||||
inline void Compile::remove_for_igvn(Node* n) {
|
||||
_for_igvn->remove(n);
|
||||
_igvn_worklist->remove(n);
|
||||
}
|
||||
|
||||
//------------------------------Node_Stack-------------------------------------
|
||||
@ -1763,6 +1804,8 @@ public:
|
||||
|
||||
// Node_Stack is used to map nodes.
|
||||
Node* find(uint idx) const;
|
||||
|
||||
NONCOPYABLE(Node_Stack);
|
||||
};
|
||||
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2023, 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
|
||||
@ -145,6 +145,7 @@ protected:
|
||||
public:
|
||||
Compile * C;
|
||||
Phase( PhaseNumber pnum );
|
||||
NONCOPYABLE(Phase);
|
||||
|
||||
static void print_timers();
|
||||
};
|
||||
|
@ -43,22 +43,6 @@
|
||||
|
||||
//=============================================================================
|
||||
#define NODE_HASH_MINIMUM_SIZE 255
|
||||
//------------------------------NodeHash---------------------------------------
|
||||
NodeHash::NodeHash(uint est_max_size) :
|
||||
_a(Thread::current()->resource_area()),
|
||||
_max( round_up(est_max_size < NODE_HASH_MINIMUM_SIZE ? NODE_HASH_MINIMUM_SIZE : est_max_size) ),
|
||||
_inserts(0), _insert_limit( insert_limit() ),
|
||||
_table( NEW_ARENA_ARRAY( _a , Node* , _max ) ) // (Node**)_a->Amalloc(_max * sizeof(Node*)) ),
|
||||
#ifndef PRODUCT
|
||||
, _grows(0),_look_probes(0), _lookup_hits(0), _lookup_misses(0),
|
||||
_insert_probes(0), _delete_probes(0), _delete_hits(0), _delete_misses(0),
|
||||
_total_inserts(0), _total_insert_probes(0)
|
||||
#endif
|
||||
{
|
||||
// _sentinel must be in the current node space
|
||||
_sentinel = new ProjNode(nullptr, TypeFunc::Control);
|
||||
memset(_table,0,sizeof(Node*)*_max);
|
||||
}
|
||||
|
||||
//------------------------------NodeHash---------------------------------------
|
||||
NodeHash::NodeHash(Arena *arena, uint est_max_size) :
|
||||
@ -77,21 +61,6 @@ NodeHash::NodeHash(Arena *arena, uint est_max_size) :
|
||||
memset(_table,0,sizeof(Node*)*_max);
|
||||
}
|
||||
|
||||
//------------------------------NodeHash---------------------------------------
|
||||
NodeHash::NodeHash(NodeHash *nh) {
|
||||
debug_only(_table = (Node**)badAddress); // interact correctly w/ operator=
|
||||
// just copy in all the fields
|
||||
*this = *nh;
|
||||
// nh->_sentinel must be in the current node space
|
||||
}
|
||||
|
||||
void NodeHash::replace_with(NodeHash *nh) {
|
||||
debug_only(_table = (Node**)badAddress); // interact correctly w/ operator=
|
||||
// just copy in all the fields
|
||||
*this = *nh;
|
||||
// nh->_sentinel must be in the current node space
|
||||
}
|
||||
|
||||
//------------------------------hash_find--------------------------------------
|
||||
// Find in hash table
|
||||
Node *NodeHash::hash_find( const Node *n ) {
|
||||
@ -388,25 +357,13 @@ NodeHash::~NodeHash() {
|
||||
// Unlock all nodes upon destruction of table.
|
||||
if (_table != (Node**)badAddress) clear();
|
||||
}
|
||||
|
||||
void NodeHash::operator=(const NodeHash& nh) {
|
||||
// Unlock all nodes upon replacement of table.
|
||||
if (&nh == this) return;
|
||||
if (_table != (Node**)badAddress) clear();
|
||||
memcpy((void*)this, (void*)&nh, sizeof(*this));
|
||||
// Do not increment hash_lock counts again.
|
||||
// Instead, be sure we never again use the source table.
|
||||
((NodeHash*)&nh)->_table = (Node**)badAddress;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
//=============================================================================
|
||||
//------------------------------PhaseRemoveUseless-----------------------------
|
||||
// 1) Use a breadthfirst walk to collect useful nodes reachable from root.
|
||||
PhaseRemoveUseless::PhaseRemoveUseless(PhaseGVN* gvn, Unique_Node_List* worklist, PhaseNumber phase_num) : Phase(phase_num) {
|
||||
PhaseRemoveUseless::PhaseRemoveUseless(PhaseGVN* gvn, Unique_Node_List& worklist, PhaseNumber phase_num) : Phase(phase_num) {
|
||||
// Implementation requires an edge from root to each SafePointNode
|
||||
// at a backward branch. Inserted in add_safepoint().
|
||||
|
||||
@ -420,7 +377,7 @@ PhaseRemoveUseless::PhaseRemoveUseless(PhaseGVN* gvn, Unique_Node_List* worklist
|
||||
gvn->remove_useless_nodes(_useful.member_set());
|
||||
|
||||
// Remove all useless nodes from future worklist
|
||||
worklist->remove_useless_nodes(_useful.member_set());
|
||||
worklist.remove_useless_nodes(_useful.member_set());
|
||||
|
||||
// Disconnect 'useless' nodes that are adjacent to useful nodes
|
||||
C->disconnect_useless_nodes(_useful, worklist);
|
||||
@ -440,21 +397,17 @@ PhaseRemoveUseless::PhaseRemoveUseless(PhaseGVN* gvn, Unique_Node_List* worklist
|
||||
// updated to 'x' and the list of dead nodes is reset (as there are no dead nodes).
|
||||
//
|
||||
// The PhaseRenumberLive phase updates two data structures with the new node IDs.
|
||||
// (1) The worklist is used by the PhaseIterGVN phase to identify nodes that must be
|
||||
// processed. A new worklist (with the updated node IDs) is returned in 'new_worklist'.
|
||||
// 'worklist' is cleared upon returning.
|
||||
// (2) Type information (the field PhaseGVN::_types) maps type information to each
|
||||
// node ID. The mapping is updated to use the new node IDs as well. Updated type
|
||||
// information is returned in PhaseGVN::_types.
|
||||
//
|
||||
// The PhaseRenumberLive phase does not preserve the order of elements in the worklist.
|
||||
// (1) The "worklist" is "C->igvn_worklist()", which is to collect which nodes need to
|
||||
// be processed by IGVN after removal of the useless nodes.
|
||||
// (2) Type information "gvn->types()" (same as "C->types()") maps every node ID to
|
||||
// the node's type. The mapping is updated to use the new node IDs as well. We
|
||||
// create a new map, and swap it with the old one.
|
||||
//
|
||||
// Other data structures used by the compiler are not updated. The hash table for value
|
||||
// numbering (the field PhaseGVN::_table) is not updated because computing the hash
|
||||
// values is not based on node IDs. The field PhaseGVN::_nodes is not updated either
|
||||
// because it is empty wherever PhaseRenumberLive is used.
|
||||
// numbering ("C->node_hash()", referenced by PhaseValue::_table) is not updated because
|
||||
// computing the hash values is not based on node IDs.
|
||||
PhaseRenumberLive::PhaseRenumberLive(PhaseGVN* gvn,
|
||||
Unique_Node_List* worklist, Unique_Node_List* new_worklist,
|
||||
Unique_Node_List& worklist,
|
||||
PhaseNumber phase_num) :
|
||||
PhaseRemoveUseless(gvn, worklist, Remove_Useless_And_Renumber_Live),
|
||||
_new_type_array(C->comp_arena()),
|
||||
@ -464,10 +417,9 @@ PhaseRenumberLive::PhaseRenumberLive(PhaseGVN* gvn,
|
||||
{
|
||||
assert(RenumberLiveNodes, "RenumberLiveNodes must be set to true for node renumbering to take place");
|
||||
assert(C->live_nodes() == _useful.size(), "the number of live nodes must match the number of useful nodes");
|
||||
assert(gvn->nodes_size() == 0, "GVN must not contain any nodes at this point");
|
||||
assert(_delayed.size() == 0, "should be empty");
|
||||
|
||||
uint worklist_size = worklist->size();
|
||||
assert(&worklist == C->igvn_worklist(), "reference still same as the one from Compile");
|
||||
assert(&gvn->types() == C->types(), "reference still same as that from Compile");
|
||||
|
||||
GrowableArray<Node_Notes*>* old_node_note_array = C->node_note_array();
|
||||
if (old_node_note_array != nullptr) {
|
||||
@ -477,15 +429,12 @@ PhaseRenumberLive::PhaseRenumberLive(PhaseGVN* gvn,
|
||||
C->grow_node_notes(C->node_note_array(), new_size);
|
||||
}
|
||||
|
||||
assert(worklist.is_subset_of(_useful), "only useful nodes should still be in the worklist");
|
||||
|
||||
// Iterate over the set of live nodes.
|
||||
for (uint current_idx = 0; current_idx < _useful.size(); current_idx++) {
|
||||
Node* n = _useful.at(current_idx);
|
||||
|
||||
bool in_worklist = false;
|
||||
if (worklist->member(n)) {
|
||||
in_worklist = true;
|
||||
}
|
||||
|
||||
const Type* type = gvn->type_or_null(n);
|
||||
_new_type_array.map(current_idx, type);
|
||||
|
||||
@ -499,16 +448,14 @@ PhaseRenumberLive::PhaseRenumberLive(PhaseGVN* gvn,
|
||||
|
||||
n->set_idx(current_idx); // Update node ID.
|
||||
|
||||
if (in_worklist) {
|
||||
new_worklist->push(n);
|
||||
}
|
||||
|
||||
if (update_embedded_ids(n) < 0) {
|
||||
_delayed.push(n); // has embedded IDs; handle later
|
||||
}
|
||||
}
|
||||
|
||||
assert(worklist_size == new_worklist->size(), "the new worklist must have the same size as the original worklist");
|
||||
// VectorSet in Unique_Node_Set must be recomputed, since IDs have changed.
|
||||
worklist.recompute_idx_set();
|
||||
|
||||
assert(_live_node_count == _useful.size(), "all live nodes must be processed");
|
||||
|
||||
_is_pass_finished = true; // pass finished; safe to process delayed updates
|
||||
@ -520,16 +467,13 @@ PhaseRenumberLive::PhaseRenumberLive(PhaseGVN* gvn,
|
||||
}
|
||||
|
||||
// Replace the compiler's type information with the updated type information.
|
||||
gvn->replace_types(_new_type_array);
|
||||
gvn->types().swap(_new_type_array);
|
||||
|
||||
// Update the unique node count of the compilation to the number of currently live nodes.
|
||||
C->set_unique(_live_node_count);
|
||||
|
||||
// Set the dead node count to 0 and reset dead node list.
|
||||
C->reset_dead_node_list();
|
||||
|
||||
// Clear the original worklist
|
||||
worklist->clear();
|
||||
}
|
||||
|
||||
int PhaseRenumberLive::new_index(int old_idx) {
|
||||
@ -581,63 +525,14 @@ int PhaseRenumberLive::update_embedded_ids(Node* n) {
|
||||
return no_of_updates;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//------------------------------PhaseTransform---------------------------------
|
||||
PhaseTransform::PhaseTransform( PhaseNumber pnum ) : Phase(pnum),
|
||||
_arena(Thread::current()->resource_area()),
|
||||
_nodes(_arena),
|
||||
_types(_arena)
|
||||
{
|
||||
init_con_caches();
|
||||
#ifndef PRODUCT
|
||||
clear_progress();
|
||||
clear_transforms();
|
||||
set_allow_progress(true);
|
||||
#endif
|
||||
// Force allocation for currently existing nodes
|
||||
_types.map(C->unique(), nullptr);
|
||||
}
|
||||
|
||||
//------------------------------PhaseTransform---------------------------------
|
||||
PhaseTransform::PhaseTransform( Arena *arena, PhaseNumber pnum ) : Phase(pnum),
|
||||
_arena(arena),
|
||||
_nodes(arena),
|
||||
_types(arena)
|
||||
{
|
||||
init_con_caches();
|
||||
#ifndef PRODUCT
|
||||
clear_progress();
|
||||
clear_transforms();
|
||||
set_allow_progress(true);
|
||||
#endif
|
||||
// Force allocation for currently existing nodes
|
||||
_types.map(C->unique(), nullptr);
|
||||
}
|
||||
|
||||
//------------------------------PhaseTransform---------------------------------
|
||||
// Initialize with previously generated type information
|
||||
PhaseTransform::PhaseTransform( PhaseTransform *pt, PhaseNumber pnum ) : Phase(pnum),
|
||||
_arena(pt->_arena),
|
||||
_nodes(pt->_nodes),
|
||||
_types(pt->_types)
|
||||
{
|
||||
init_con_caches();
|
||||
#ifndef PRODUCT
|
||||
clear_progress();
|
||||
clear_transforms();
|
||||
set_allow_progress(true);
|
||||
#endif
|
||||
}
|
||||
|
||||
void PhaseTransform::init_con_caches() {
|
||||
void PhaseValues::init_con_caches() {
|
||||
memset(_icons,0,sizeof(_icons));
|
||||
memset(_lcons,0,sizeof(_lcons));
|
||||
memset(_zcons,0,sizeof(_zcons));
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------find_int_type--------------------------------
|
||||
const TypeInt* PhaseTransform::find_int_type(Node* n) {
|
||||
const TypeInt* PhaseValues::find_int_type(Node* n) {
|
||||
if (n == nullptr) return nullptr;
|
||||
// Call type_or_null(n) to determine node's type since we might be in
|
||||
// parse phase and call n->Value() may return wrong type.
|
||||
@ -649,7 +544,7 @@ const TypeInt* PhaseTransform::find_int_type(Node* n) {
|
||||
|
||||
|
||||
//-------------------------------find_long_type--------------------------------
|
||||
const TypeLong* PhaseTransform::find_long_type(Node* n) {
|
||||
const TypeLong* PhaseValues::find_long_type(Node* n) {
|
||||
if (n == nullptr) return nullptr;
|
||||
// (See comment above on type_or_null.)
|
||||
const Type* t = type_or_null(n);
|
||||
@ -657,72 +552,11 @@ const TypeLong* PhaseTransform::find_long_type(Node* n) {
|
||||
return t->isa_long();
|
||||
}
|
||||
|
||||
|
||||
#ifndef PRODUCT
|
||||
void PhaseTransform::dump_old2new_map() const {
|
||||
_nodes.dump();
|
||||
}
|
||||
|
||||
void PhaseTransform::dump_new( uint nidx ) const {
|
||||
for( uint i=0; i<_nodes.max(); i++ )
|
||||
if( _nodes[i] && _nodes[i]->_idx == nidx ) {
|
||||
_nodes[i]->dump();
|
||||
tty->cr();
|
||||
tty->print_cr("Old index= %d",i);
|
||||
return;
|
||||
}
|
||||
tty->print_cr("Node %d not found in the new indices", nidx);
|
||||
}
|
||||
|
||||
//------------------------------dump_types-------------------------------------
|
||||
void PhaseTransform::dump_types( ) const {
|
||||
_types.dump();
|
||||
}
|
||||
|
||||
//------------------------------dump_nodes_and_types---------------------------
|
||||
void PhaseTransform::dump_nodes_and_types(const Node* root, uint depth, bool only_ctrl) {
|
||||
VectorSet visited;
|
||||
dump_nodes_and_types_recur(root, depth, only_ctrl, visited);
|
||||
}
|
||||
|
||||
//------------------------------dump_nodes_and_types_recur---------------------
|
||||
void PhaseTransform::dump_nodes_and_types_recur( const Node *n, uint depth, bool only_ctrl, VectorSet &visited) {
|
||||
if( !n ) return;
|
||||
if( depth == 0 ) return;
|
||||
if( visited.test_set(n->_idx) ) return;
|
||||
for( uint i=0; i<n->len(); i++ ) {
|
||||
if( only_ctrl && !(n->is_Region()) && i != TypeFunc::Control ) continue;
|
||||
dump_nodes_and_types_recur( n->in(i), depth-1, only_ctrl, visited );
|
||||
}
|
||||
n->dump();
|
||||
if (type_or_null(n) != nullptr) {
|
||||
tty->print(" "); type(n)->dump(); tty->cr();
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
//=============================================================================
|
||||
//------------------------------PhaseValues------------------------------------
|
||||
// Set minimum table size to "255"
|
||||
PhaseValues::PhaseValues( Arena *arena, uint est_max_size )
|
||||
: PhaseTransform(arena, GVN), _table(arena, est_max_size), _iterGVN(false) {
|
||||
NOT_PRODUCT( clear_new_values(); )
|
||||
}
|
||||
|
||||
//------------------------------PhaseValues------------------------------------
|
||||
// Set minimum table size to "255"
|
||||
PhaseValues::PhaseValues(PhaseValues* ptv)
|
||||
: PhaseTransform(ptv, GVN), _table(&ptv->_table), _iterGVN(false) {
|
||||
NOT_PRODUCT( clear_new_values(); )
|
||||
}
|
||||
|
||||
//------------------------------~PhaseValues-----------------------------------
|
||||
#ifndef PRODUCT
|
||||
PhaseValues::~PhaseValues() {
|
||||
// Statistics for NodeHash
|
||||
_table.dump();
|
||||
|
||||
// Statistics for value progress and efficiency
|
||||
if( PrintCompilation && Verbose && WizardMode ) {
|
||||
tty->print("\n%sValues: %d nodes ---> %d/%d (%d)",
|
||||
@ -737,7 +571,7 @@ PhaseValues::~PhaseValues() {
|
||||
#endif
|
||||
|
||||
//------------------------------makecon----------------------------------------
|
||||
ConNode* PhaseTransform::makecon(const Type *t) {
|
||||
ConNode* PhaseValues::makecon(const Type* t) {
|
||||
assert(t->singleton(), "must be a constant");
|
||||
assert(!t->empty() || t == Type::TOP, "must not be vacuous range");
|
||||
switch (t->base()) { // fast paths
|
||||
@ -774,7 +608,7 @@ ConNode* PhaseValues::uncached_makecon(const Type *t) {
|
||||
|
||||
//------------------------------intcon-----------------------------------------
|
||||
// Fast integer constant. Same as "transform(new ConINode(TypeInt::make(i)))"
|
||||
ConINode* PhaseTransform::intcon(jint i) {
|
||||
ConINode* PhaseValues::intcon(jint i) {
|
||||
// Small integer? Check cache! Check that cached node is not dead
|
||||
if (i >= _icon_min && i <= _icon_max) {
|
||||
ConINode* icon = _icons[i-_icon_min];
|
||||
@ -790,7 +624,7 @@ ConINode* PhaseTransform::intcon(jint i) {
|
||||
|
||||
//------------------------------longcon----------------------------------------
|
||||
// Fast long constant.
|
||||
ConLNode* PhaseTransform::longcon(jlong l) {
|
||||
ConLNode* PhaseValues::longcon(jlong l) {
|
||||
// Small integer? Check cache! Check that cached node is not dead
|
||||
if (l >= _lcon_min && l <= _lcon_max) {
|
||||
ConLNode* lcon = _lcons[l-_lcon_min];
|
||||
@ -803,7 +637,7 @@ ConLNode* PhaseTransform::longcon(jlong l) {
|
||||
_lcons[l-_lcon_min] = lcon; // Cache small integers
|
||||
return lcon;
|
||||
}
|
||||
ConNode* PhaseTransform::integercon(jlong l, BasicType bt) {
|
||||
ConNode* PhaseValues::integercon(jlong l, BasicType bt) {
|
||||
if (bt == T_INT) {
|
||||
return intcon(checked_cast<jint>(l));
|
||||
}
|
||||
@ -814,7 +648,7 @@ ConNode* PhaseTransform::integercon(jlong l, BasicType bt) {
|
||||
|
||||
//------------------------------zerocon-----------------------------------------
|
||||
// Fast zero or null constant. Same as "transform(ConNode::make(Type::get_zero_type(bt)))"
|
||||
ConNode* PhaseTransform::zerocon(BasicType bt) {
|
||||
ConNode* PhaseValues::zerocon(BasicType bt) {
|
||||
assert((uint)bt <= _zcon_max, "domain check");
|
||||
ConNode* zcon = _zcons[bt];
|
||||
if (zcon != nullptr && zcon->in(TypeFunc::Control) != nullptr)
|
||||
@ -971,24 +805,17 @@ void PhaseGVN::dump_infinite_loop_info(Node* n, const char* where) {
|
||||
//=============================================================================
|
||||
//------------------------------PhaseIterGVN-----------------------------------
|
||||
// Initialize with previous PhaseIterGVN info; used by PhaseCCP
|
||||
PhaseIterGVN::PhaseIterGVN(PhaseIterGVN* igvn) : PhaseGVN(igvn),
|
||||
_delay_transform(igvn->_delay_transform),
|
||||
_stack(igvn->_stack ),
|
||||
_worklist(igvn->_worklist)
|
||||
PhaseIterGVN::PhaseIterGVN(PhaseIterGVN* igvn) : _delay_transform(igvn->_delay_transform),
|
||||
_worklist(*C->igvn_worklist())
|
||||
{
|
||||
_iterGVN = true;
|
||||
assert(&_worklist == &igvn->_worklist, "sanity");
|
||||
}
|
||||
|
||||
//------------------------------PhaseIterGVN-----------------------------------
|
||||
// Initialize with previous PhaseGVN info from Parser
|
||||
PhaseIterGVN::PhaseIterGVN(PhaseGVN* gvn) : PhaseGVN(gvn),
|
||||
_delay_transform(false),
|
||||
// TODO: Before incremental inlining it was allocated only once and it was fine. Now that
|
||||
// the constructor is used in incremental inlining, this consumes too much memory:
|
||||
// _stack(C->live_nodes() >> 1),
|
||||
// So, as a band-aid, we replace this by:
|
||||
_stack(C->comp_arena(), 32),
|
||||
_worklist(*C->for_igvn())
|
||||
PhaseIterGVN::PhaseIterGVN(PhaseGVN* gvn) : _delay_transform(false),
|
||||
_worklist(*C->igvn_worklist())
|
||||
{
|
||||
_iterGVN = true;
|
||||
uint max;
|
||||
@ -1468,21 +1295,22 @@ void PhaseIterGVN::remove_globally_dead_node( Node *dead ) {
|
||||
PROCESS_INPUTS,
|
||||
PROCESS_OUTPUTS
|
||||
};
|
||||
assert(_stack.is_empty(), "not empty");
|
||||
_stack.push(dead, PROCESS_INPUTS);
|
||||
ResourceMark rm;
|
||||
Node_Stack stack(32);
|
||||
stack.push(dead, PROCESS_INPUTS);
|
||||
|
||||
while (_stack.is_nonempty()) {
|
||||
dead = _stack.node();
|
||||
while (stack.is_nonempty()) {
|
||||
dead = stack.node();
|
||||
if (dead->Opcode() == Op_SafePoint) {
|
||||
dead->as_SafePoint()->disconnect_from_root(this);
|
||||
}
|
||||
uint progress_state = _stack.index();
|
||||
uint progress_state = stack.index();
|
||||
assert(dead != C->root(), "killing root, eh?");
|
||||
assert(!dead->is_top(), "add check for top when pushing");
|
||||
NOT_PRODUCT( set_progress(); )
|
||||
if (progress_state == PROCESS_INPUTS) {
|
||||
// After following inputs, continue to outputs
|
||||
_stack.set_index(PROCESS_OUTPUTS);
|
||||
stack.set_index(PROCESS_OUTPUTS);
|
||||
if (!dead->is_Con()) { // Don't kill cons but uses
|
||||
bool recurse = false;
|
||||
// Remove from hash table
|
||||
@ -1494,7 +1322,7 @@ void PhaseIterGVN::remove_globally_dead_node( Node *dead ) {
|
||||
int nrep = dead->replace_edge(in, nullptr, this); // Kill edges
|
||||
assert((nrep > 0), "sanity");
|
||||
if (in->outcnt() == 0) { // Made input go dead?
|
||||
_stack.push(in, PROCESS_INPUTS); // Recursively remove
|
||||
stack.push(in, PROCESS_INPUTS); // Recursively remove
|
||||
recurse = true;
|
||||
} else if (in->outcnt() == 1 &&
|
||||
in->has_special_unique_user()) {
|
||||
@ -1541,15 +1369,15 @@ void PhaseIterGVN::remove_globally_dead_node( Node *dead ) {
|
||||
// of edge deletions per loop trip.)
|
||||
if (dead->outcnt() > 0) {
|
||||
// Recursively remove output edges
|
||||
_stack.push(dead->raw_out(0), PROCESS_INPUTS);
|
||||
stack.push(dead->raw_out(0), PROCESS_INPUTS);
|
||||
} else {
|
||||
// Finished disconnecting all input and output edges.
|
||||
_stack.pop();
|
||||
stack.pop();
|
||||
// Remove dead node from iterative worklist
|
||||
_worklist.remove(dead);
|
||||
C->remove_useless_node(dead);
|
||||
}
|
||||
} // while (_stack.is_nonempty())
|
||||
} // while (stack.is_nonempty())
|
||||
}
|
||||
|
||||
//------------------------------subsume_node-----------------------------------
|
||||
@ -1912,8 +1740,6 @@ uint PhaseCCP::_total_constants = 0;
|
||||
PhaseCCP::PhaseCCP( PhaseIterGVN *igvn ) : PhaseIterGVN(igvn) {
|
||||
NOT_PRODUCT( clear_constants(); )
|
||||
assert( _worklist.size() == 0, "" );
|
||||
// Clear out _nodes from IterGVN. Must be clear to transform call.
|
||||
_nodes.clear(); // Clear out from IterGVN
|
||||
analyze();
|
||||
}
|
||||
|
||||
@ -2190,16 +2016,16 @@ void PhaseCCP::do_transform() {
|
||||
// Given a Node in old-space, clone him into new-space.
|
||||
// Convert any of his old-space children into new-space children.
|
||||
Node *PhaseCCP::transform( Node *n ) {
|
||||
Node *new_node = _nodes[n->_idx]; // Check for transformed node
|
||||
if( new_node != nullptr )
|
||||
return new_node; // Been there, done that, return old answer
|
||||
|
||||
assert(n->is_Root(), "traversal must start at root");
|
||||
assert(_root_and_safepoints.member(n), "root (n) must be in list");
|
||||
|
||||
// Allocate stack of size _nodes.Size()/2 to avoid frequent realloc
|
||||
ResourceMark rm;
|
||||
// Map: old node idx -> node after CCP (or nullptr if not yet transformed or useless).
|
||||
Node_List node_map;
|
||||
// Pre-allocate to avoid frequent realloc
|
||||
GrowableArray <Node *> transform_stack(C->live_nodes() >> 1);
|
||||
Unique_Node_List useful; // track all visited nodes, so that we can remove the complement
|
||||
// track all visited nodes, so that we can remove the complement
|
||||
Unique_Node_List useful;
|
||||
|
||||
// Initialize the traversal.
|
||||
// This CCP pass may prove that no exit test for a loop ever succeeds (i.e. the loop is infinite). In that case,
|
||||
@ -2211,10 +2037,10 @@ Node *PhaseCCP::transform( Node *n ) {
|
||||
// and all safepoints.
|
||||
for (uint i = 0; i < _root_and_safepoints.size(); ++i) {
|
||||
Node* nn = _root_and_safepoints.at(i);
|
||||
Node* new_node = _nodes[nn->_idx];
|
||||
Node* new_node = node_map[nn->_idx];
|
||||
assert(new_node == nullptr, "");
|
||||
new_node = transform_once(nn); // Check for constant
|
||||
_nodes.map(nn->_idx, new_node); // Flag as having been cloned
|
||||
node_map.map(nn->_idx, new_node); // Flag as having been cloned
|
||||
transform_stack.push(new_node); // Process children of cloned node
|
||||
useful.push(new_node);
|
||||
}
|
||||
@ -2225,10 +2051,10 @@ Node *PhaseCCP::transform( Node *n ) {
|
||||
for( uint i = 0; i < cnt; i++ ) { // For all inputs do
|
||||
Node *input = clone->in(i);
|
||||
if( input != nullptr ) { // Ignore nulls
|
||||
Node *new_input = _nodes[input->_idx]; // Check for cloned input node
|
||||
Node *new_input = node_map[input->_idx]; // Check for cloned input node
|
||||
if( new_input == nullptr ) {
|
||||
new_input = transform_once(input); // Check for constant
|
||||
_nodes.map( input->_idx, new_input );// Flag as having been cloned
|
||||
node_map.map( input->_idx, new_input );// Flag as having been cloned
|
||||
transform_stack.push(new_input); // Process children of cloned node
|
||||
useful.push(new_input);
|
||||
}
|
||||
@ -2251,14 +2077,13 @@ Node *PhaseCCP::transform( Node *n ) {
|
||||
C->update_dead_node_list(useful);
|
||||
remove_useless_nodes(useful.member_set());
|
||||
_worklist.remove_useless_nodes(useful.member_set());
|
||||
C->disconnect_useless_nodes(useful, &_worklist);
|
||||
C->disconnect_useless_nodes(useful, _worklist);
|
||||
|
||||
Node* new_root = _nodes[n->_idx];
|
||||
Node* new_root = node_map[n->_idx];
|
||||
assert(new_root->is_Root(), "transformed root node must be a root node");
|
||||
return new_root;
|
||||
}
|
||||
|
||||
|
||||
//------------------------------transform_once---------------------------------
|
||||
// For PhaseCCP, transformation is IDENTITY unless Node computed a constant.
|
||||
Node *PhaseCCP::transform_once( Node *n ) {
|
||||
|
@ -32,6 +32,7 @@
|
||||
#include "opto/node.hpp"
|
||||
#include "opto/phase.hpp"
|
||||
#include "opto/type.hpp"
|
||||
#include "utilities/globalDefinitions.hpp"
|
||||
|
||||
class BarrierSetC2;
|
||||
class Compile;
|
||||
@ -51,7 +52,7 @@ class PhaseRegAlloc;
|
||||
// Expandable closed hash-table of nodes, initialized to null.
|
||||
// Note that the constructor just zeros things
|
||||
// Storage is reclaimed when the Arena's lifetime is over.
|
||||
class NodeHash : public StackObj {
|
||||
class NodeHash : public AnyObj {
|
||||
protected:
|
||||
Arena *_a; // Arena to allocate in
|
||||
uint _max; // Size of table (power of 2)
|
||||
@ -61,12 +62,9 @@ protected:
|
||||
Node *_sentinel; // Replaces deleted entries in hash table
|
||||
|
||||
public:
|
||||
NodeHash(uint est_max_size);
|
||||
NodeHash(Arena *arena, uint est_max_size);
|
||||
NodeHash(NodeHash *use_this_state);
|
||||
#ifdef ASSERT
|
||||
~NodeHash(); // Unlock all nodes upon destruction of table.
|
||||
void operator=(const NodeHash&); // Unlock all nodes upon replacement of table.
|
||||
#endif
|
||||
Node *hash_find(const Node*);// Find an equivalent version in hash table
|
||||
Node *hash_find_insert(Node*);// If not in table insert else return found node
|
||||
@ -93,7 +91,6 @@ public:
|
||||
}
|
||||
|
||||
void remove_useless_nodes(VectorSet& useful); // replace with sentinel
|
||||
void replace_with(NodeHash* nh);
|
||||
void check_no_speculative_types(); // Check no speculative part for type nodes in table
|
||||
|
||||
Node *sentinel() { return _sentinel; }
|
||||
@ -112,6 +109,7 @@ public:
|
||||
uint _total_inserts; // For debugging, total inserts into hash table
|
||||
uint _total_insert_probes; // For debugging, total probes while inserting
|
||||
#endif
|
||||
NONCOPYABLE(NodeHash);
|
||||
};
|
||||
|
||||
|
||||
@ -120,18 +118,17 @@ public:
|
||||
// Abstractly provides an infinite array of Type*'s, initialized to null.
|
||||
// Note that the constructor just zeros things, and since I use Arena
|
||||
// allocation I do not need a destructor to reclaim storage.
|
||||
// Despite the general name, this class is customized for use by PhaseTransform.
|
||||
class Type_Array : public StackObj {
|
||||
// Despite the general name, this class is customized for use by PhaseValues.
|
||||
class Type_Array : public AnyObj {
|
||||
Arena *_a; // Arena to allocate in
|
||||
uint _max;
|
||||
const Type **_types;
|
||||
void grow( uint i ); // Grow array node to fit
|
||||
const Type *operator[] ( uint i ) const // Lookup, or null for not mapped
|
||||
{ return (i<_max) ? _types[i] : (Type*)nullptr; }
|
||||
friend class PhaseTransform;
|
||||
friend class PhaseValues;
|
||||
public:
|
||||
Type_Array(Arena *a) : _a(a), _max(0), _types(0) {}
|
||||
Type_Array(Type_Array *ta) : _a(ta->_a), _max(ta->_max), _types(ta->_types) { }
|
||||
const Type *fast_lookup(uint i) const{assert(i<_max,"oob");return _types[i];}
|
||||
// Extend the mapping: index i maps to Type *n.
|
||||
void map( uint i, const Type *n ) { if( i>=_max ) grow(i); _types[i] = n; }
|
||||
@ -139,6 +136,14 @@ public:
|
||||
#ifndef PRODUCT
|
||||
void dump() const;
|
||||
#endif
|
||||
void swap(Type_Array &other) {
|
||||
if (this != &other) {
|
||||
assert(_a == other._a, "swapping for differing arenas is probably a bad idea");
|
||||
::swap(_max, other._max);
|
||||
::swap(_types, other._types);
|
||||
}
|
||||
}
|
||||
NONCOPYABLE(Type_Array);
|
||||
};
|
||||
|
||||
|
||||
@ -149,7 +154,7 @@ protected:
|
||||
Unique_Node_List _useful; // Nodes reachable from root
|
||||
// list is allocated from current resource area
|
||||
public:
|
||||
PhaseRemoveUseless(PhaseGVN *gvn, Unique_Node_List *worklist, PhaseNumber phase_num = Remove_Useless);
|
||||
PhaseRemoveUseless(PhaseGVN* gvn, Unique_Node_List& worklist, PhaseNumber phase_num = Remove_Useless);
|
||||
|
||||
Unique_Node_List *get_useful() { return &_useful; }
|
||||
};
|
||||
@ -170,7 +175,7 @@ protected:
|
||||
|
||||
public:
|
||||
PhaseRenumberLive(PhaseGVN* gvn,
|
||||
Unique_Node_List* worklist, Unique_Node_List* new_worklist,
|
||||
Unique_Node_List& worklist,
|
||||
PhaseNumber phase_num = Remove_Useless_And_Renumber_Live);
|
||||
};
|
||||
|
||||
@ -181,12 +186,56 @@ public:
|
||||
// transformation pass. When the Phase object is deleted the cached analysis
|
||||
// results are deleted.
|
||||
class PhaseTransform : public Phase {
|
||||
public:
|
||||
PhaseTransform(PhaseNumber pnum) : Phase(pnum) {
|
||||
#ifndef PRODUCT
|
||||
clear_progress();
|
||||
clear_transforms();
|
||||
set_allow_progress(true);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Return a node which computes the same function as this node, but
|
||||
// in a faster or cheaper fashion.
|
||||
virtual Node *transform( Node *n ) = 0;
|
||||
|
||||
// true if CFG node d dominates CFG node n
|
||||
virtual bool is_dominator(Node *d, Node *n) { fatal("unimplemented for this pass"); return false; };
|
||||
|
||||
#ifndef PRODUCT
|
||||
uint _count_progress; // For profiling, count transforms that make progress
|
||||
void set_progress() { ++_count_progress; assert( allow_progress(),"No progress allowed during verification"); }
|
||||
void clear_progress() { _count_progress = 0; }
|
||||
uint made_progress() const { return _count_progress; }
|
||||
|
||||
uint _count_transforms; // For profiling, count transforms performed
|
||||
void set_transforms() { ++_count_transforms; }
|
||||
void clear_transforms() { _count_transforms = 0; }
|
||||
uint made_transforms() const{ return _count_transforms; }
|
||||
|
||||
bool _allow_progress; // progress not allowed during verification pass
|
||||
void set_allow_progress(bool allow) { _allow_progress = allow; }
|
||||
bool allow_progress() { return _allow_progress; }
|
||||
#endif
|
||||
};
|
||||
|
||||
// Phase infrastructure required for Node::Value computations.
|
||||
// 1) Type array, and accessor methods.
|
||||
// 2) Constants cache, which requires access to the types.
|
||||
// 3) NodeHash table, to find identical nodes (and remove/update the hash of a node on modification).
|
||||
class PhaseValues : public PhaseTransform {
|
||||
protected:
|
||||
Arena* _arena;
|
||||
Node_List _nodes; // Map old node indices to new nodes.
|
||||
Type_Array _types; // Map old node indices to Types.
|
||||
bool _iterGVN;
|
||||
|
||||
// Hash table for value-numbering. Reference to "C->node_hash()",
|
||||
NodeHash &_table;
|
||||
|
||||
// Type array mapping node idx to Type*. Reference to "C->types()".
|
||||
Type_Array &_types;
|
||||
|
||||
// ConNode caches:
|
||||
// Support both int and long caches because either might be an intptr_t,
|
||||
// so they show up frequently in address computations.
|
||||
enum { _icon_min = -1 * HeapWordSize,
|
||||
_icon_max = 16 * HeapWordSize,
|
||||
_lcon_min = _icon_min,
|
||||
@ -198,31 +247,40 @@ protected:
|
||||
ConNode* _zcons[_zcon_max + 1]; // cached is_zero_type nodes
|
||||
void init_con_caches();
|
||||
|
||||
// Support both int and long caches because either might be an intptr_t,
|
||||
// so they show up frequently in address computations.
|
||||
|
||||
public:
|
||||
PhaseTransform( PhaseNumber pnum );
|
||||
PhaseTransform( Arena *arena, PhaseNumber pnum );
|
||||
PhaseTransform( PhaseTransform *phase, PhaseNumber pnum );
|
||||
|
||||
Arena* arena() { return _arena; }
|
||||
Type_Array& types() { return _types; }
|
||||
void replace_types(Type_Array new_types) {
|
||||
_types = new_types;
|
||||
PhaseValues() : PhaseTransform(GVN), _iterGVN(false),
|
||||
_table(*C->node_hash()), _types(*C->types())
|
||||
{
|
||||
NOT_PRODUCT( clear_new_values(); )
|
||||
// Force allocation for currently existing nodes
|
||||
_types.map(C->unique(), nullptr);
|
||||
init_con_caches();
|
||||
}
|
||||
// _nodes is used in varying ways by subclasses, which define local accessors
|
||||
uint nodes_size() {
|
||||
return _nodes.size();
|
||||
NOT_PRODUCT(~PhaseValues();)
|
||||
PhaseIterGVN* is_IterGVN() { return (_iterGVN) ? (PhaseIterGVN*)this : nullptr; }
|
||||
|
||||
// Some Ideal and other transforms delete --> modify --> insert values
|
||||
bool hash_delete(Node* n) { return _table.hash_delete(n); }
|
||||
void hash_insert(Node* n) { _table.hash_insert(n); }
|
||||
Node* hash_find_insert(Node* n){ return _table.hash_find_insert(n); }
|
||||
Node* hash_find(const Node* n) { return _table.hash_find(n); }
|
||||
|
||||
// Used after parsing to eliminate values that are no longer in program
|
||||
void remove_useless_nodes(VectorSet &useful) {
|
||||
_table.remove_useless_nodes(useful);
|
||||
// this may invalidate cached cons so reset the cache
|
||||
init_con_caches();
|
||||
}
|
||||
|
||||
Type_Array& types() {
|
||||
return _types;
|
||||
}
|
||||
|
||||
public:
|
||||
// Get a previously recorded type for the node n.
|
||||
// This type must already have been recorded.
|
||||
// If you want the type of a very new (untransformed) node,
|
||||
// you must use type_or_null, and test the result for null.
|
||||
const Type* type(const Node* n) const {
|
||||
assert(_pnum != Ideal_Loop, "should not be used from PhaseIdealLoop");
|
||||
assert(n != nullptr, "must not be null");
|
||||
const Type* t = _types.fast_lookup(n->_idx);
|
||||
assert(t != nullptr, "must set before get");
|
||||
@ -231,7 +289,6 @@ public:
|
||||
// Get a previously recorded type for the node n,
|
||||
// or else return null if there is none.
|
||||
const Type* type_or_null(const Node* n) const {
|
||||
assert(_pnum != Ideal_Loop, "should not be used from PhaseIdealLoop");
|
||||
return _types.fast_lookup(n->_idx);
|
||||
}
|
||||
// Record a type for a node.
|
||||
@ -274,8 +331,7 @@ public:
|
||||
// Make an idealized constant, i.e., one of ConINode, ConPNode, ConFNode, etc.
|
||||
// Same as transform(ConNode::make(t)).
|
||||
ConNode* makecon(const Type* t);
|
||||
virtual ConNode* uncached_makecon(const Type* t) // override in PhaseValues
|
||||
{ ShouldNotCallThis(); return nullptr; }
|
||||
ConNode* uncached_makecon(const Type* t);
|
||||
|
||||
// Fast int or long constant. Same as TypeInt::make(i) or TypeLong::make(l).
|
||||
ConINode* intcon(jint i);
|
||||
@ -285,10 +341,6 @@ public:
|
||||
// Fast zero or null constant. Same as makecon(Type::get_zero_type(bt)).
|
||||
ConNode* zerocon(BasicType bt);
|
||||
|
||||
// Return a node which computes the same function as this node, but
|
||||
// in a faster or cheaper fashion.
|
||||
virtual Node *transform( Node *n ) = 0;
|
||||
|
||||
// For pessimistic passes, the return type must monotonically narrow.
|
||||
// For optimistic passes, the return type must monotonically widen.
|
||||
// It is possible to get into a "death march" in either type of pass,
|
||||
@ -337,70 +389,15 @@ public:
|
||||
// if the phase wishes to widen the new_type.
|
||||
// If the phase is narrowing, the old type provides a lower limit.
|
||||
// Caller guarantees that old_type and new_type are no higher than limit_type.
|
||||
virtual const Type* saturate(const Type* new_type, const Type* old_type,
|
||||
const Type* limit_type) const
|
||||
{ ShouldNotCallThis(); return nullptr; }
|
||||
virtual const Type* saturate(const Type* new_type,
|
||||
const Type* old_type,
|
||||
const Type* limit_type) const {
|
||||
return new_type;
|
||||
}
|
||||
virtual const Type* saturate_and_maybe_push_to_igvn_worklist(const TypeNode* n, const Type* new_type) {
|
||||
return saturate(new_type, type_or_null(n), n->type());
|
||||
}
|
||||
|
||||
// true if CFG node d dominates CFG node n
|
||||
virtual bool is_dominator(Node *d, Node *n) { fatal("unimplemented for this pass"); return false; };
|
||||
|
||||
#ifndef PRODUCT
|
||||
void dump_old2new_map() const;
|
||||
void dump_new( uint new_lidx ) const;
|
||||
void dump_types() const;
|
||||
void dump_nodes_and_types(const Node *root, uint depth, bool only_ctrl = true);
|
||||
void dump_nodes_and_types_recur( const Node *n, uint depth, bool only_ctrl, VectorSet &visited);
|
||||
|
||||
uint _count_progress; // For profiling, count transforms that make progress
|
||||
void set_progress() { ++_count_progress; assert( allow_progress(),"No progress allowed during verification"); }
|
||||
void clear_progress() { _count_progress = 0; }
|
||||
uint made_progress() const { return _count_progress; }
|
||||
|
||||
uint _count_transforms; // For profiling, count transforms performed
|
||||
void set_transforms() { ++_count_transforms; }
|
||||
void clear_transforms() { _count_transforms = 0; }
|
||||
uint made_transforms() const{ return _count_transforms; }
|
||||
|
||||
bool _allow_progress; // progress not allowed during verification pass
|
||||
void set_allow_progress(bool allow) { _allow_progress = allow; }
|
||||
bool allow_progress() { return _allow_progress; }
|
||||
#endif
|
||||
};
|
||||
|
||||
//------------------------------PhaseValues------------------------------------
|
||||
// Phase infrastructure to support values
|
||||
class PhaseValues : public PhaseTransform {
|
||||
protected:
|
||||
NodeHash _table; // Hash table for value-numbering
|
||||
bool _iterGVN;
|
||||
public:
|
||||
PhaseValues(Arena* arena, uint est_max_size);
|
||||
PhaseValues(PhaseValues* pt);
|
||||
NOT_PRODUCT(~PhaseValues();)
|
||||
PhaseIterGVN* is_IterGVN() { return (_iterGVN) ? (PhaseIterGVN*)this : nullptr; }
|
||||
|
||||
// Some Ideal and other transforms delete --> modify --> insert values
|
||||
bool hash_delete(Node* n) { return _table.hash_delete(n); }
|
||||
void hash_insert(Node* n) { _table.hash_insert(n); }
|
||||
Node* hash_find_insert(Node* n){ return _table.hash_find_insert(n); }
|
||||
Node* hash_find(const Node* n) { return _table.hash_find(n); }
|
||||
|
||||
// Used after parsing to eliminate values that are no longer in program
|
||||
void remove_useless_nodes(VectorSet &useful) {
|
||||
_table.remove_useless_nodes(useful);
|
||||
// this may invalidate cached cons so reset the cache
|
||||
init_con_caches();
|
||||
}
|
||||
|
||||
virtual ConNode* uncached_makecon(const Type* t); // override from PhaseTransform
|
||||
|
||||
const Type* saturate(const Type* new_type, const Type* old_type,
|
||||
const Type* limit_type) const
|
||||
{ return new_type; }
|
||||
|
||||
#ifndef PRODUCT
|
||||
uint _count_new_values; // For profiling, count new values produced
|
||||
void inc_new_values() { ++_count_new_values; }
|
||||
@ -417,9 +414,6 @@ protected:
|
||||
bool is_dominator_helper(Node *d, Node *n, bool linear_only);
|
||||
|
||||
public:
|
||||
PhaseGVN( Arena *arena, uint est_max_size ) : PhaseValues( arena, est_max_size ) {}
|
||||
PhaseGVN( PhaseGVN *gvn ) : PhaseValues( gvn ) {}
|
||||
|
||||
// Return a node which computes the same function as this node, but
|
||||
// in a faster or cheaper fashion.
|
||||
Node *transform( Node *n );
|
||||
@ -428,11 +422,6 @@ public:
|
||||
C->record_for_igvn(n);
|
||||
}
|
||||
|
||||
void replace_with(PhaseGVN* gvn) {
|
||||
_table.replace_with(&gvn->_table);
|
||||
_types = gvn->_types;
|
||||
}
|
||||
|
||||
bool is_dominator(Node *d, Node *n) { return is_dominator_helper(d, n, true); }
|
||||
|
||||
// Helper to call Node::Ideal() and BarrierSetC2::ideal_node().
|
||||
@ -459,9 +448,7 @@ private:
|
||||
// Subsume users of node 'old' into node 'nn'
|
||||
void subsume_node( Node *old, Node *nn );
|
||||
|
||||
Node_Stack _stack; // Stack used to avoid recursion
|
||||
protected:
|
||||
|
||||
// Shuffle worklist, for stress testing
|
||||
void shuffle_worklist();
|
||||
|
||||
@ -471,14 +458,36 @@ protected:
|
||||
// improvement, such that it would take many (>>10) steps to reach 2**32.
|
||||
|
||||
public:
|
||||
|
||||
PhaseIterGVN(PhaseIterGVN* igvn); // Used by CCP constructor
|
||||
PhaseIterGVN(PhaseGVN* gvn); // Used after Parser
|
||||
|
||||
// Reset IGVN from GVN: call deconstructor, and placement new.
|
||||
// Achieves the same as the following (but without move constructors):
|
||||
// igvn = PhaseIterGVN(gvn);
|
||||
void reset_from_gvn(PhaseGVN* gvn) {
|
||||
if (this != gvn) {
|
||||
this->~PhaseIterGVN();
|
||||
::new (static_cast<void*>(this)) PhaseIterGVN(gvn);
|
||||
}
|
||||
}
|
||||
|
||||
// Reset IGVN with another: call deconstructor, and placement new.
|
||||
// Achieves the same as the following (but without move constructors):
|
||||
// igvn = PhaseIterGVN(other);
|
||||
void reset_from_igvn(PhaseIterGVN* other) {
|
||||
if (this != other) {
|
||||
this->~PhaseIterGVN();
|
||||
::new (static_cast<void*>(this)) PhaseIterGVN(other);
|
||||
}
|
||||
}
|
||||
|
||||
// Idealize new Node 'n' with respect to its inputs and its value
|
||||
virtual Node *transform( Node *a_node );
|
||||
virtual void record_for_igvn(Node *n) { }
|
||||
|
||||
Unique_Node_List _worklist; // Iterative worklist
|
||||
// Iterative worklist. Reference to "C->igvn_worklist()".
|
||||
Unique_Node_List &_worklist;
|
||||
|
||||
// Given def-use info and an initial worklist, apply Node::Ideal,
|
||||
// Node::Value, Node::Identity, hash-based value numbering, Node::Ideal_DU
|
||||
|
@ -628,7 +628,7 @@ void PhaseIdealLoop::do_split_if(Node* iff, RegionNode** new_false_region, Regio
|
||||
for (j = n->outs(); n->has_out(j); j++) {
|
||||
Node* m = n->out(j);
|
||||
// If m is dead, throw it away, and declare progress
|
||||
if (_nodes[m->_idx] == nullptr) {
|
||||
if (_loop_or_ctrl[m->_idx] == nullptr) {
|
||||
_igvn.remove_dead_node(m);
|
||||
// fall through
|
||||
}
|
||||
|
@ -77,7 +77,7 @@ Node* SubNode::Identity(PhaseGVN* phase) {
|
||||
|
||||
//------------------------------Value------------------------------------------
|
||||
// A subtract node differences it's two inputs.
|
||||
const Type* SubNode::Value_common(PhaseTransform *phase) const {
|
||||
const Type* SubNode::Value_common(PhaseValues* phase) const {
|
||||
const Node* in1 = in(1);
|
||||
const Node* in2 = in(2);
|
||||
// Either input is TOP ==> the result is TOP
|
||||
|
@ -50,7 +50,7 @@ public:
|
||||
// Compute a new Type for this node. Basically we just do the pre-check,
|
||||
// then call the virtual add() to set the type.
|
||||
virtual const Type* Value(PhaseGVN* phase) const;
|
||||
const Type* Value_common( PhaseTransform *phase ) const;
|
||||
const Type* Value_common(PhaseValues* phase) const;
|
||||
|
||||
// Supplied function returns the subtractend of the inputs.
|
||||
// This also type-checks the inputs for sanity. Guaranteed never to
|
||||
|
@ -43,8 +43,7 @@ void PhaseVector::optimize_vector_boxes() {
|
||||
assert(C->inlining_incrementally() == false, "sanity");
|
||||
C->set_inlining_incrementally(true);
|
||||
|
||||
C->for_igvn()->clear();
|
||||
C->initial_gvn()->replace_with(&_igvn);
|
||||
C->igvn_worklist()->ensure_empty(); // should be done with igvn
|
||||
|
||||
expand_vunbox_nodes();
|
||||
scalarize_vbox_nodes();
|
||||
@ -64,12 +63,12 @@ void PhaseVector::do_cleanup() {
|
||||
{
|
||||
Compile::TracePhase tp("vector_pru", &timers[_t_vector_pru]);
|
||||
ResourceMark rm;
|
||||
PhaseRemoveUseless pru(C->initial_gvn(), C->for_igvn());
|
||||
PhaseRemoveUseless pru(C->initial_gvn(), *C->igvn_worklist());
|
||||
if (C->failing()) return;
|
||||
}
|
||||
{
|
||||
Compile::TracePhase tp("incrementalInline_igvn", &timers[_t_vector_igvn]);
|
||||
_igvn = PhaseIterGVN(C->initial_gvn());
|
||||
_igvn.reset_from_gvn(C->initial_gvn());
|
||||
_igvn.optimize();
|
||||
if (C->failing()) return;
|
||||
}
|
||||
|
@ -1689,7 +1689,6 @@
|
||||
declare_c2_type(MultiNode, Node) \
|
||||
declare_c2_type(ProjNode, Node) \
|
||||
declare_c2_type(TypeNode, Node) \
|
||||
declare_c2_type(NodeHash, StackObj) \
|
||||
declare_c2_type(RootNode, LoopNode) \
|
||||
declare_c2_type(HaltNode, Node) \
|
||||
declare_c2_type(SubNode, Node) \
|
||||
|
Loading…
x
Reference in New Issue
Block a user