Mercurial > hg > graal-jvmci-8
view src/share/vm/c1/c1_IR.hpp @ 3979:4dfb2df418f2
6484982: G1: process references during evacuation pauses
Summary: G1 now uses two reference processors - one is used by concurrent marking and the other is used by STW GCs (both full and incremental evacuation pauses). In an evacuation pause, the reference processor is embedded into the closures used to scan objects. Doing so causes causes reference objects to be 'discovered' by the reference processor. At the end of the evacuation pause, these discovered reference objects are processed - preserving (and copying) referent objects (and their reachable graphs) as appropriate.
Reviewed-by: ysr, jwilhelm, brutisso, stefank, tonyp
author | johnc |
---|---|
date | Thu, 22 Sep 2011 10:57:37 -0700 |
parents | f95d63e2154a |
children | 5857923e563c 701a83c86f28 |
line wrap: on
line source
/* * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. * */ #ifndef SHARE_VM_C1_C1_IR_HPP #define SHARE_VM_C1_C1_IR_HPP #include "c1/c1_Instruction.hpp" #include "ci/ciExceptionHandler.hpp" #include "ci/ciMethod.hpp" #include "ci/ciStreams.hpp" #include "memory/allocation.hpp" // An XHandler is a C1 internal description for an exception handler class XHandler: public CompilationResourceObj { private: ciExceptionHandler* _desc; BlockBegin* _entry_block; // Entry block of xhandler LIR_List* _entry_code; // LIR-operations that must be executed before jumping to entry_block int _entry_pco; // pco where entry_code (or entry_block if no entry_code) starts int _phi_operand; // For resolving of phi functions at begin of entry_block int _scope_count; // for filling ExceptionRangeEntry::scope_count #ifdef ASSERT int _lir_op_id; // op_id of the LIR-operation throwing to this handler #endif public: // creation XHandler(ciExceptionHandler* desc) : _desc(desc) , _entry_block(NULL) , _entry_code(NULL) , _entry_pco(-1) , _phi_operand(-1) , _scope_count(-1) #ifdef ASSERT , _lir_op_id(-1) #endif { } XHandler(XHandler* other) : _desc(other->_desc) , _entry_block(other->_entry_block) , _entry_code(other->_entry_code) , _entry_pco(other->_entry_pco) , _phi_operand(other->_phi_operand) , _scope_count(other->_scope_count) #ifdef ASSERT , _lir_op_id(other->_lir_op_id) #endif { } // accessors for data of ciExceptionHandler int beg_bci() const { return _desc->start(); } int end_bci() const { return _desc->limit(); } int handler_bci() const { return _desc->handler_bci(); } bool is_catch_all() const { return _desc->is_catch_all(); } int catch_type() const { return _desc->catch_klass_index(); } ciInstanceKlass* catch_klass() const { return _desc->catch_klass(); } bool covers(int bci) const { return beg_bci() <= bci && bci < end_bci(); } // accessors for additional fields BlockBegin* entry_block() const { return _entry_block; } LIR_List* entry_code() const { return _entry_code; } int entry_pco() const { return _entry_pco; } int phi_operand() const { assert(_phi_operand != -1, "not set"); return _phi_operand; } int scope_count() const { assert(_scope_count != -1, "not set"); return _scope_count; } DEBUG_ONLY(int lir_op_id() const { return _lir_op_id; }); void set_entry_block(BlockBegin* entry_block) { assert(entry_block->is_set(BlockBegin::exception_entry_flag), "must be an exception handler entry"); assert(entry_block->bci() == handler_bci(), "bci's must correspond"); _entry_block = entry_block; } void set_entry_code(LIR_List* entry_code) { _entry_code = entry_code; } void set_entry_pco(int entry_pco) { _entry_pco = entry_pco; } void set_phi_operand(int phi_operand) { _phi_operand = phi_operand; } void set_scope_count(int scope_count) { _scope_count = scope_count; } DEBUG_ONLY(void set_lir_op_id(int lir_op_id) { _lir_op_id = lir_op_id; }); bool equals(XHandler* other) const; }; define_array(_XHandlerArray, XHandler*) define_stack(_XHandlerList, _XHandlerArray) // XHandlers is the C1 internal list of exception handlers for a method class XHandlers: public CompilationResourceObj { private: _XHandlerList _list; public: // creation XHandlers() : _list() { } XHandlers(ciMethod* method); XHandlers(XHandlers* other); // accessors int length() const { return _list.length(); } XHandler* handler_at(int i) const { return _list.at(i); } bool has_handlers() const { return _list.length() > 0; } void append(XHandler* h) { _list.append(h); } XHandler* remove_last() { return _list.pop(); } bool could_catch(ciInstanceKlass* klass, bool type_is_exact) const; bool equals(XHandlers* others) const; }; class IRScope; define_array(IRScopeArray, IRScope*) define_stack(IRScopeList, IRScopeArray) class Compilation; class IRScope: public CompilationResourceObj { private: // hierarchy Compilation* _compilation; // the current compilation IRScope* _caller; // the caller scope, or NULL int _level; // the inlining level ciMethod* _method; // the corresponding method IRScopeList _callees; // the inlined method scopes // graph XHandlers* _xhandlers; // the exception handlers int _number_of_locks; // the number of monitor lock slots needed bool _monitor_pairing_ok; // the monitor pairing info BlockBegin* _start; // the start block, successsors are method entries BitMap _requires_phi_function; // bit is set if phi functions at loop headers are necessary for a local variable // helper functions BlockBegin* build_graph(Compilation* compilation, int osr_bci); public: // creation IRScope(Compilation* compilation, IRScope* caller, int caller_bci, ciMethod* method, int osr_bci, bool create_graph = false); // accessors Compilation* compilation() const { return _compilation; } IRScope* caller() const { return _caller; } int level() const { return _level; } ciMethod* method() const { return _method; } int max_stack() const; // NOTE: expensive BitMap& requires_phi_function() { return _requires_phi_function; } // hierarchy bool is_top_scope() const { return _caller == NULL; } void add_callee(IRScope* callee) { _callees.append(callee); } int number_of_callees() const { return _callees.length(); } IRScope* callee_no(int i) const { return _callees.at(i); } // accessors, graph bool is_valid() const { return start() != NULL; } XHandlers* xhandlers() const { return _xhandlers; } int number_of_locks() const { return _number_of_locks; } void set_min_number_of_locks(int n) { if (n > _number_of_locks) _number_of_locks = n; } bool monitor_pairing_ok() const { return _monitor_pairing_ok; } BlockBegin* start() const { return _start; } }; // // IRScopeDebugInfo records the debug information for a particular IRScope // in a particular CodeEmitInfo. This allows the information to be computed // once early enough for the OopMap to be available to the LIR and also to be // reemited for different pcs using the same CodeEmitInfo without recomputing // everything. // class IRScopeDebugInfo: public CompilationResourceObj { private: IRScope* _scope; int _bci; GrowableArray<ScopeValue*>* _locals; GrowableArray<ScopeValue*>* _expressions; GrowableArray<MonitorValue*>* _monitors; IRScopeDebugInfo* _caller; public: IRScopeDebugInfo(IRScope* scope, int bci, GrowableArray<ScopeValue*>* locals, GrowableArray<ScopeValue*>* expressions, GrowableArray<MonitorValue*>* monitors, IRScopeDebugInfo* caller): _scope(scope) , _locals(locals) , _bci(bci) , _expressions(expressions) , _monitors(monitors) , _caller(caller) {} IRScope* scope() { return _scope; } int bci() { return _bci; } GrowableArray<ScopeValue*>* locals() { return _locals; } GrowableArray<ScopeValue*>* expressions() { return _expressions; } GrowableArray<MonitorValue*>* monitors() { return _monitors; } IRScopeDebugInfo* caller() { return _caller; } //Whether we should reexecute this bytecode for deopt bool should_reexecute(); void record_debug_info(DebugInformationRecorder* recorder, int pc_offset, bool topmost, bool is_method_handle_invoke = false) { if (caller() != NULL) { // Order is significant: Must record caller first. caller()->record_debug_info(recorder, pc_offset, false/*topmost*/); } DebugToken* locvals = recorder->create_scope_values(locals()); DebugToken* expvals = recorder->create_scope_values(expressions()); DebugToken* monvals = recorder->create_monitor_values(monitors()); // reexecute allowed only for the topmost frame bool reexecute = topmost ? should_reexecute() : false; bool return_oop = false; // This flag will be ignored since it used only for C2 with escape analysis. recorder->describe_scope(pc_offset, scope()->method(), bci(), reexecute, is_method_handle_invoke, return_oop, locvals, expvals, monvals); } }; class CodeEmitInfo: public CompilationResourceObj { friend class LinearScan; private: IRScopeDebugInfo* _scope_debug_info; IRScope* _scope; XHandlers* _exception_handlers; OopMap* _oop_map; ValueStack* _stack; // used by deoptimization (contains also monitors bool _is_method_handle_invoke; // true if the associated call site is a MethodHandle call site. FrameMap* frame_map() const { return scope()->compilation()->frame_map(); } Compilation* compilation() const { return scope()->compilation(); } public: // use scope from ValueStack CodeEmitInfo(ValueStack* stack, XHandlers* exception_handlers); // make a copy CodeEmitInfo(CodeEmitInfo* info, ValueStack* stack = NULL); // accessors OopMap* oop_map() { return _oop_map; } ciMethod* method() const { return _scope->method(); } IRScope* scope() const { return _scope; } XHandlers* exception_handlers() const { return _exception_handlers; } ValueStack* stack() const { return _stack; } void add_register_oop(LIR_Opr opr); void record_debug_info(DebugInformationRecorder* recorder, int pc_offset); bool is_method_handle_invoke() const { return _is_method_handle_invoke; } void set_is_method_handle_invoke(bool x) { _is_method_handle_invoke = x; } }; class IR: public CompilationResourceObj { private: Compilation* _compilation; // the current compilation IRScope* _top_scope; // the root of the scope hierarchy WordSize _locals_size; // the space required for all locals int _num_loops; // Total number of loops BlockList* _code; // the blocks in code generation order w/ use counts public: // creation IR(Compilation* compilation, ciMethod* method, int osr_bci); // accessors bool is_valid() const { return top_scope()->is_valid(); } Compilation* compilation() const { return _compilation; } IRScope* top_scope() const { return _top_scope; } int number_of_locks() const { return top_scope()->number_of_locks(); } ciMethod* method() const { return top_scope()->method(); } BlockBegin* start() const { return top_scope()->start(); } BlockBegin* std_entry() const { return start()->end()->as_Base()->std_entry(); } BlockBegin* osr_entry() const { return start()->end()->as_Base()->osr_entry(); } WordSize locals_size() const { return _locals_size; } int locals_size_in_words() const { return in_words(_locals_size); } BlockList* code() const { return _code; } int num_loops() const { return _num_loops; } int max_stack() const { return top_scope()->max_stack(); } // expensive // ir manipulation void optimize(); void compute_predecessors(); void split_critical_edges(); void compute_code(); void compute_use_counts(); // The linear-scan order and the code emission order are equal, but // this may change in future BlockList* linear_scan_order() { assert(_code != NULL, "not computed"); return _code; } // iteration void iterate_preorder (BlockClosure* closure); void iterate_postorder (BlockClosure* closure); void iterate_linear_scan_order(BlockClosure* closure); // debugging static void print(BlockBegin* start, bool cfg_only, bool live_only = false) PRODUCT_RETURN; void print(bool cfg_only, bool live_only = false) PRODUCT_RETURN; void verify() PRODUCT_RETURN; }; // Globally do instruction substitution and remove substituted // instructions from the instruction list. // class SubstitutionResolver: public BlockClosure, ValueVisitor { virtual void visit(Value* v); public: SubstitutionResolver(IR* hir) { hir->iterate_preorder(this); } SubstitutionResolver(BlockBegin* block) { block->iterate_preorder(this); } virtual void block_do(BlockBegin* block); }; #endif // SHARE_VM_C1_C1_IR_HPP