/* * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. *
*/
class AbstractLockNode; class AddPNode; class Block; class Bundle; class CallGenerator; class CallStaticJavaNode; class CloneMap; class ConnectionGraph; class IdealGraphPrinter; class InlineTree; class Int_Array; class Matcher; class MachConstantNode; class MachConstantBaseNode; class MachNode; class MachOper; class MachSafePointNode; class Node; class Node_Array; class Node_List; class Node_Notes; class NodeCloneInfo; class OptoReg; class PhaseCFG; class PhaseGVN; class PhaseIterGVN; class PhaseRegAlloc; class PhaseCCP; class PhaseOutput; class RootNode; class relocInfo; class Scope; class StartNode; class SafePointNode; class JVMState; class Type; class TypeData; class TypeInt; class TypeInteger; class TypeKlassPtr; class TypePtr; class TypeOopPtr; class TypeFunc; class TypeVect; class Unique_Node_List; class UnstableIfTrap; class nmethod; class Node_Stack; struct Final_Reshape_Counts;
// The type of all node counts and indexes. // It must hold at least 16 bits, but must also be fast to load and store. // This type, if less than 32 bits, could limit the number of possible nodes. // (To make this type platform-specific, move to globalDefinitions_xxx.hpp.) typedefunsignedint node_idx_t;
class NodeCloneInfo { private:
uint64_t _idx_clone_orig; public:
//------------------------------Compile---------------------------------------- // This class defines a top-level Compiler invocation.
class Compile : public Phase { friendclass VMStructs;
public: // Fixed alias indexes. (See also MergeMemNode.) enum {
AliasIdxTop = 1, // pseudo-index, aliases to nothing (used as sentinel value)
AliasIdxBot = 2, // pseudo-index, aliases to everything
AliasIdxRaw = 3 // hard-wired index for TypeRawPtr::BOTTOM
};
// Variant of TraceTime(NULL, &_t_accumulator, CITime); // Integrated with logging. If logging is turned on, and CITimeVerbose is true, // then brackets are put into the log, with time stamps and node counts. // (The time collection itself is always conditionalized on CITime.) class TracePhase : public TraceTime { private:
Compile* C;
CompileLog* _log; constchar* _phase_name; bool _dolog; public:
TracePhase(constchar* name, elapsedTimer* accumulator);
~TracePhase();
};
// Information per category of alias (memory slice) class AliasType { private: friendclass Compile;
int _index; // unique index, used with MergeMemNode const TypePtr* _adr_type; // normalized address type
ciField* _field; // relevant instance field, or null if none const Type* _element; // relevant array element type, or null if none bool _is_rewritable; // false if the memory is write-once only int _general_index; // if this is type is an instance, the general // type that this is an instance of
void set_rewritable(bool z) { _is_rewritable = z; } void set_field(ciField* f) {
assert(!_field,"");
_field = f; if (f->is_final() || f->is_stable()) { // In the case of @Stable, multiple writes are possible but may be assumed to be no-ops.
_is_rewritable = false;
}
} void set_element(const Type* e) {
assert(_element == NULL, "");
_element = e;
}
private: // Fixed parameters to this compilation. constint _compile_id; const Options _options; // Compilation options
ciMethod* _method; // The method being compiled. int _entry_bci; // entry bci for osr methods. const TypeFunc* _tf; // My kind of signature
InlineTree* _ilt; // Ditto (temporary).
address _stub_function; // VM entry for stub being compiled, or NULL constchar* _stub_name; // Name of stub or adapter being compiled, or NULL
address _stub_entry_point; // Compile code entry for generated stub, or NULL
// Control of this compilation. int _max_inline_size; // Max inline size for this compilation int _freq_inline_size; // Max hot method inline size for this compilation int _fixed_slots; // count of frame slots not allocated by the register // allocator i.e. locks, original deopt pc, etc.
uintx _max_node_limit; // Max unique node count during a single compilation.
bool _post_loop_opts_phase; // Loop opts are finished.
int _major_progress; // Count of something big happening bool _inlining_progress; // progress doing incremental inlining? bool _inlining_incrementally;// Are we doing incremental inlining (post parse) bool _do_cleanup; // Cleanup is needed before proceeding with incremental inlining bool _has_loops; // True if the method _may_ have some loops bool _has_split_ifs; // True if the method _may_ have some split-if bool _has_unsafe_access; // True if the method _may_ produce faults in unsafe loads or stores. bool _has_stringbuilder; // True StringBuffers or StringBuilders are allocated bool _has_boxed_value; // True if a boxed object is allocated bool _has_reserved_stack_access; // True if the method or an inlined method is annotated with ReservedStackAccess
uint _max_vector_size; // Maximum size of generated vectors bool _clear_upper_avx; // Clear upper bits of ymm registers using vzeroupper
uint _trap_hist[trapHistLength]; // Cumulative traps bool _trap_can_recompile; // Have we emitted a recompiling trap?
uint _decompile_count; // Cumulative decompilation counts. bool _do_inlining; // True if we intend to do inlining bool _do_scheduling; // True if we intend to do scheduling bool _do_freq_based_layout; // True if we intend to do frequency based block layout bool _do_vector_loop; // True if allowed to execute loop in parallel iterations bool _use_cmove; // True if CMove should be used without profitability analysis bool _do_aliasing; // True if we intend to do aliasing bool _print_assembly; // True if we should dump assembly code for this compilation bool _print_inlining; // True if we should print inlining for this compilation bool _print_intrinsics; // True if we should print intrinsics for this compilation #ifndef PRODUCT
uint _igv_idx; // Counter for IGV node identifiers bool _trace_opto_output; bool _parsed_irreducible_loop; // True if ciTypeFlow detected irreducible loops during parsing #endif bool _has_irreducible_loop; // Found irreducible loops // JSR 292 bool _has_method_handle_invokes; // True if this method has MethodHandle invokes. bool _has_monitors; // Metadata transfered to nmethod to enable Continuations lock-detection fastpath
RTMState _rtm_state; // State of Restricted Transactional Memory usage int _loop_opts_cnt; // loop opts round bool _clinit_barrier_on_entry; // True if clinit barrier is needed on nmethod entry
uint _stress_seed; // Seed for stress testing
// Compilation environment.
Arena _comp_arena; // Arena with lifetime equivalent to Compile void* _barrier_set_state; // Potential GC barrier state for Compile
ciEnv* _env; // CI interface
DirectiveSet* _directive; // Compiler directive
CompileLog* _log; // from CompilerThread constchar* _failure_reason; // for record_failure/failing pattern
GrowableArray<CallGenerator*> _intrinsics; // List of intrinsics.
GrowableArray<Node*> _macro_nodes; // List of nodes which need to be expanded before matching.
GrowableArray<Node*> _predicate_opaqs; // List of Opaque1 nodes for the loop predicates.
GrowableArray<Node*> _skeleton_predicate_opaqs; // List of Opaque4 nodes for the loop skeleton predicates.
GrowableArray<Node*> _expensive_nodes; // List of nodes that are expensive to compute and that we'd better not let the GVN freely common
GrowableArray<Node*> _for_post_loop_igvn; // List of nodes for IGVN after loop opts are over
GrowableArray<UnstableIfTrap*> _unstable_if_traps; // List of ifnodes after IGVN
GrowableArray<Node_List*> _coarsened_locks; // List of coarsened Lock and Unlock nodes
ConnectionGraph* _congraph; #ifndef PRODUCT
IdealGraphPrinter* _igv_printer; static IdealGraphPrinter* _debug_file_printer; static IdealGraphPrinter* _debug_network_printer; #endif
// Node management
uint _unique; // Counter for unique Node indices
VectorSet _dead_node_list; // Set of dead nodes
uint _dead_node_count; // Number of dead nodes; VectorSet::Size() is O(N). // So use this to keep count and make the call O(1).
DEBUG_ONLY(Unique_Node_List* _modified_nodes;) // List of nodes which inputs were modified
DEBUG_ONLY(bool _phase_optimize_finished;) // Used for live node verification while creating new nodes
debug_only(staticint _debug_idx;) // Monotonic counter (not reset), use -XX:BreakAtNode=<idx>
Arena _node_arena; // Arena for new-space Nodes
Arena _old_arena; // Arena for old-space Nodes, lifetime during xform
RootNode* _root; // Unique root of compilation, or NULL after bail-out.
Node* _top; // Unique top node. (Reset by various phases.)
// Blocked array of debugging and profiling information, // tracked per node. enum { _log2_node_notes_block_size = 8,
_node_notes_block_size = (1<<_log2_node_notes_block_size)
};
GrowableArray<Node_Notes*>* _node_note_array;
Node_Notes* _default_node_notes; // default notes for new nodes
// After parsing and every bulk phase we hang onto the Root instruction. // The RootNode instruction is where the whole program begins. It produces // the initial Control and BOTTOM for everybody else.
// Type management
Arena _Compile_types; // Arena for all types
Arena* _type_arena; // Alias for _Compile_types except in Initialize_shared()
Dict* _type_dict; // Intern table
CloneMap _clone_map; // used for recording history of cloned nodes
size_t _type_last_size; // Last allocation size (see Type::operator new/delete)
ciMethod* _last_tf_m; // Cache for const TypeFunc* _last_tf; // TypeFunc::make
AliasType** _alias_types; // List of alias types seen so far. int _num_alias_types; // Logical length of _alias_types int _max_alias_types; // Physical length of _alias_types
AliasCacheEntry _alias_cache[AliasCacheSize]; // Gets aliases w/o data structure walking
// Parsing, optimization
PhaseGVN* _initial_gvn; // Results of parse-time PhaseGVN
Unique_Node_List* _for_igvn; // Initial work-list for next round of Iterative GVN
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
GrowableArray<CallGenerator*> _boxing_late_inlines; // same but for boxing operations
GrowableArray<CallGenerator*> _vector_reboxing_late_inlines; // same but for vector reboxing operations
int _late_inlines_pos; // Where in the queue should the next late inlining candidate go (emulate depth first inlining)
uint _number_of_mh_late_inlines; // number of method handle late inlining still pending
// Inlining may not happen in parse order which would make // PrintInlining output confusing. Keep track of PrintInlining // pieces in order. class PrintInliningBuffer : public CHeapObj<mtCompiler> { private:
CallGenerator* _cg;
stringStream _ss; staticconst size_t default_stream_buffer_size = 128;
stringStream* _print_inlining_stream;
GrowableArray<PrintInliningBuffer*>* _print_inlining_list; int _print_inlining_idx; char* _print_inlining_output;
// Only keep nodes in the expensive node list that need to be optimized void cleanup_expensive_nodes(PhaseIterGVN &igvn); // Use for sorting expensive nodes to bring similar nodes together staticint cmp_expensive_nodes(Node** n1, Node** n2); // Expensive nodes list already sorted? bool expensive_nodes_sorted() const; // Remove the speculative part of types and clean up the graph void remove_speculative_types(PhaseIterGVN &igvn);
void* _replay_inline_data; // Pointer to data loaded from file
// Dump inlining replay data to the stream. void dump_inline_data(outputStream* out); void dump_inline_data_reduced(outputStream* out);
private: // Matching, CFG layout, allocation, code generation
PhaseCFG* _cfg; // Results of CFG finding int _java_calls; // Number of java calls in the method int _inner_loops; // Number of inner loops in the method
Matcher* _matcher; // Engine to map ideal to machine instructions
PhaseRegAlloc* _regalloc; // Results of register allocation.
RegMask _FIRST_STACK_mask; // All stack slots usable for spills (depends on frame layout)
Arena* _indexSet_arena; // control IndexSet allocation within PhaseChaitin void* _indexSet_free_block_list; // free list of IndexSet bit blocks int _interpreter_frame_size;
PhaseOutput* _output;
public: // Accessors
// The Compile instance currently active in this (compiler) thread. static Compile* current() { return (Compile*) ciEnv::current()->compiler_data();
}
int interpreter_frame_size() const { return _interpreter_frame_size; }
// ID for this compilation. Useful for setting breakpoints in the debugger. int compile_id() const { return _compile_id; }
DirectiveSet* directive() const { return _directive; }
// Does this compilation allow instructions to subsume loads? User // instructions that subsume a load may result in an unschedulable // instruction sequence. bool subsume_loads() const { return _options._subsume_loads; } /** Do escape analysis. */ bool do_escape_analysis() const { return _options._do_escape_analysis; } bool do_iterative_escape_analysis() const { return _options._do_iterative_escape_analysis; } /** Do boxing elimination. */ bool eliminate_boxing() const { return _options._eliminate_boxing; } /** Do aggressive boxing elimination. */ bool aggressive_unboxing() const { return _options._eliminate_boxing && AggressiveUnboxing; } bool should_install_code() const { return _options._install_code; } /** Do locks coarsening. */ bool do_locks_coarsening() const { return _options._do_locks_coarsening; }
// check the CompilerOracle for special behaviours for this compile bool method_has_option(enum CompileCommand option) { return method() != NULL && method()->has_option(option);
}
ConnectionGraph* congraph() { return _congraph;} void set_congraph(ConnectionGraph* congraph) { _congraph = congraph;} void add_macro_node(Node * n) { //assert(n->is_macro(), "must be a macro node");
assert(!_macro_nodes.contains(n), "duplicate entry in expand list");
_macro_nodes.append(n);
} void remove_macro_node(Node* n) { // this function may be called twice for a node so we can only remove it // if it's still existing.
_macro_nodes.remove_if_existing(n); // remove from _predicate_opaqs list also if it is there if (predicate_count() > 0) {
_predicate_opaqs.remove_if_existing(n);
} // Remove from coarsened locks list if present if (coarsened_count() > 0) {
remove_coarsened_lock(n);
}
} void add_expensive_node(Node* n); void remove_expensive_node(Node* n) {
_expensive_nodes.remove_if_existing(n);
} void add_predicate_opaq(Node* n) {
assert(!_predicate_opaqs.contains(n), "duplicate entry in predicate opaque1");
assert(_macro_nodes.contains(n), "should have already been in macro list");
_predicate_opaqs.append(n);
} void add_skeleton_predicate_opaq(Node* n) {
assert(!_skeleton_predicate_opaqs.contains(n), "duplicate entry in skeleton predicate opaque4 list");
_skeleton_predicate_opaqs.append(n);
} void remove_skeleton_predicate_opaq(Node* n) { if (skeleton_predicate_count() > 0) {
_skeleton_predicate_opaqs.remove_if_existing(n);
}
} void add_coarsened_locks(GrowableArray<AbstractLockNode*>& locks); void remove_coarsened_lock(Node* n); bool coarsened_locks_consistent();
// remove the opaque nodes that protect the predicates so that the unused checks and // uncommon traps will be eliminated from the graph. void cleanup_loop_predicates(PhaseIterGVN &igvn); bool is_predicate_opaq(Node* n) { return _predicate_opaqs.contains(n);
}
// Are there candidate expensive nodes for optimization? bool should_optimize_expensive_nodes(PhaseIterGVN &igvn); // Check whether n1 and n2 are similar staticint cmp_expensive_nodes(Node* n1, Node* n2); // Sort expensive nodes to locate similar expensive nodes void sort_expensive_nodes();
// Record modified nodes to check that they are put on IGVN worklist void record_modified_node(Node* n) NOT_DEBUG_RETURN; void remove_modified_node(Node* n) NOT_DEBUG_RETURN;
DEBUG_ONLY( Unique_Node_List* modified_nodes() const { return _modified_nodes; } )
// these are used by guys who need to know about creation and transformation of top:
Node* cached_top_node() { return _top; } void set_cached_top_node(Node* tn);
// Copy notes from source to dest, if they exist. // Overwrite dest only if source provides something. // Return true if information was moved. bool copy_node_notes_to(Node* dest, Node* source);
// Workhorse function to sort out the blocked Node_Notes array: inline Node_Notes* locate_node_notes(GrowableArray<Node_Notes*>* arr, int idx, bool can_grow = false);
void grow_node_notes(GrowableArray<Node_Notes*>* arr, int grow_by);
// Report if there were too many traps at a current method and bci. // Report if a trap was recorded, and/or PerMethodTrapLimit was exceeded. // If there is no MDO at all, report no trap unless told to assume it. bool too_many_traps(ciMethod* method, int bci, Deoptimization::DeoptReason reason); // This version, unspecific to a particular bci, asks if // PerMethodTrapLimit was exceeded for all inlined methods seen so far. bool too_many_traps(Deoptimization::DeoptReason reason, // Privately used parameter for logging:
ciMethodData* logmd = NULL); // Report if there were too many recompiles at a method and bci. bool too_many_recompiles(ciMethod* method, int bci, Deoptimization::DeoptReason reason); // Report if there were too many traps or recompiles at a method and bci. bool too_many_traps_or_recompiles(ciMethod* method, int bci, Deoptimization::DeoptReason reason) { return too_many_traps(method, bci, reason) ||
too_many_recompiles(method, bci, reason);
} // Return a bitset with the reasons where deoptimization is allowed, // i.e., where there were not too many uncommon traps. int _allowed_reasons; int allowed_deopt_reasons() { return _allowed_reasons; } void set_allowed_deopt_reasons();
// Parsing, optimization
PhaseGVN* initial_gvn() { return _initial_gvn; }
Unique_Node_List* for_igvn() { return _for_igvn; } inlinevoid record_for_igvn(Node* n); // Body is after class Unique_Node_List. 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. void gvn_replace_by(Node* n, Node* nn);
// Record this CallGenerator for inlining at the end of parsing. void add_late_inline(CallGenerator* cg) {
_late_inlines.insert_before(_late_inlines_pos, cg);
_late_inlines_pos++;
}
bool over_inlining_cutoff() const { if (!inlining_incrementally()) { return unique() > (uint)NodeCountInliningCutoff;
} else { // Give some room for incremental inlining algorithm to "breathe" // and avoid thrashing when live node count is close to the limit. // Keep in mind that live_nodes() isn't accurate during inlining until // dead node elimination step happens (see Compile::inline_incrementally). return live_nodes() > (uint)LiveNodeCountInliningCutoff * 11 / 10;
}
}
// Major entry point. Given a Scope, compile the associated method. // For normal compilations, entry_bci is InvocationEntryBci. For on stack // replacement, entry_bci indicates the bytecode for which to compile a // continuation.
Compile(ciEnv* ci_env, ciMethod* target, int entry_bci, Options options, DirectiveSet* directive);
// Second major entry point. From the TypeFunc signature, generate code // to pass arguments from the Java calling convention to the C calling // convention.
Compile(ciEnv* ci_env, const TypeFunc *(*gen)(),
address stub_function, constchar *stub_name, int is_fancy_jump, bool pass_tls, bool return_pc, DirectiveSet* directive);
~Compile() { delete _print_inlining_stream;
};
// Are we compiling a method? bool has_method() { return method() != NULL; }
// Maybe print some information about this compile. void print_compile_messages();
// Final graph reshaping, a post-pass after the regular optimizer is done. bool final_graph_reshaping();
// returns true if adr is completely contained in the given alias category bool must_alias(const TypePtr* adr, int alias_idx);
// returns true if adr overlaps with the given alias category bool can_alias(const TypePtr* adr, int alias_idx);
// Stack slots that may be unused by the calling convention but must // otherwise be preserved. On Intel this includes the return address. // On PowerPC it includes the 4 words holding the old TOC & LR glue.
uint in_preserve_stack_slots() { return SharedRuntime::in_preserve_stack_slots();
}
// "Top of Stack" slots that may be unused by the calling convention but must // otherwise be preserved. // On Intel these are not necessary and the value can be zero. static uint out_preserve_stack_slots() { return SharedRuntime::out_preserve_stack_slots();
}
// Number of outgoing stack slots killed above the out_preserve_stack_slots // for calls to C. Supports the var-args backing area for register parms.
uint varargs_C_out_slots_killed() const;
// Number of Stack Slots consumed by a synchronization entry int sync_stack_slots() const;
// Compute the name of old_SP. See <arch>.ad for frame layout.
OptoReg::Name compute_old_SP();
private: // Phase control: void Init(bool aliasing); // Prepare for a single compilation void Optimize(); // Given a graph, optimize it void Code_Gen(); // Generate code from a graph
// Intrinsic setup.
CallGenerator* make_vm_intrinsic(ciMethod* m, bool is_virtual); // constructor int intrinsic_insertion_index(ciMethod* m, bool is_virtual, bool& found); // helper
CallGenerator* find_intrinsic(ciMethod* m, bool is_virtual); // query fn void register_intrinsic(CallGenerator* cg); // update fn
#ifndef PRODUCT static juint _intrinsic_hist_count[]; static jubyte _intrinsic_hist_flags[]; #endif // Function calls made by the public function final_graph_reshaping. // No need to be made public as they are not called elsewhere. void final_graph_reshaping_impl(Node *n, Final_Reshape_Counts& frc, Unique_Node_List& dead_nodes); void final_graph_reshaping_main_switch(Node* n, Final_Reshape_Counts& frc, uint nop, Unique_Node_List& dead_nodes); void final_graph_reshaping_walk(Node_Stack& nstack, Node* root, Final_Reshape_Counts& frc, Unique_Node_List& dead_nodes); void eliminate_redundant_card_marks(Node* n);
// Note: Histogram array size is about 1 Kb. enum { // flag bits:
_intrinsic_worked = 1, // succeeded at least once
_intrinsic_failed = 2, // tried it but it failed
_intrinsic_disabled = 4, // was requested but disabled (e.g., -XX:-InlineUnsafeOps)
_intrinsic_virtual = 8, // was seen in the virtual form (rare)
_intrinsic_both = 16 // was seen in the non-virtual form (usual)
}; // Update histogram. Return boolean if this is a first-time occurrence. staticbool gather_intrinsic_statistics(vmIntrinsics::ID id, bool is_virtual, int flags) PRODUCT_RETURN0; staticvoid print_intrinsic_statistics() PRODUCT_RETURN;
// Graph verification code // Walk the node list, verifying that there is a one-to-one // correspondence between Use-Def edges and Def-Use edges // The option no_dead_code enables stronger checks that the // graph is strongly connected from root in both directions. void verify_graph_edges(bool no_dead_code = false) PRODUCT_RETURN;
// Verify bi-directional correspondence of edges void verify_bidirectional_edges(Unique_Node_List &visited);
static Node* conv_I2X_index(PhaseGVN* phase, Node* offset, const TypeInt* sizetype, // Optional control dependency (for example, on range check)
Node* ctrl = NULL);
// Convert integer value to a narrowed long type dependent on ctrl (for example, a range check) static Node* constrained_convI2L(PhaseGVN* phase, Node* value, const TypeInt* itype, Node* ctrl, bool carry_dependency = false);
// Auxiliary methods for randomized fuzzing/stressing int random(); bool randomized_select(int count);
#ifdef IA32 private: bool _select_24_bit_instr; // We selected an instruction with a 24-bit result bool _in_24_bit_fp_mode; // We are emitting instructions with 24-bit results
// Remember if this compilation changes hardware mode to 24-bit precision. void set_24_bit_selection_and_mode(bool selection, bool mode) {
_select_24_bit_instr = selection;
_in_24_bit_fp_mode = mode;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.