# HG changeset patch # User trims # Date 1276844962 25200 # Node ID e848dd13e1b6bf51ed70e6a30c7b18f8e02acdf4 # Parent c6984693635278851458ebf69b71bbb1d1e76722# Parent b9bc732be7c06a8677746ce5841719ef9a8fb9a3 Merge diff -r c69846936352 -r e848dd13e1b6 src/cpu/sparc/vm/c1_FrameMap_sparc.cpp --- a/src/cpu/sparc/vm/c1_FrameMap_sparc.cpp Thu Jun 17 23:59:24 2010 -0700 +++ b/src/cpu/sparc/vm/c1_FrameMap_sparc.cpp Fri Jun 18 00:09:22 2010 -0700 @@ -181,8 +181,8 @@ } -void FrameMap::init () { - if (_init_done) return; +void FrameMap::initialize() { + assert(!_init_done, "once"); int i=0; // Register usage: diff -r c69846936352 -r e848dd13e1b6 src/cpu/x86/vm/assembler_x86.cpp --- a/src/cpu/x86/vm/assembler_x86.cpp Thu Jun 17 23:59:24 2010 -0700 +++ b/src/cpu/x86/vm/assembler_x86.cpp Fri Jun 18 00:09:22 2010 -0700 @@ -7643,6 +7643,9 @@ // Pass register number to verify_oop_subroutine char* b = new char[strlen(s) + 50]; sprintf(b, "verify_oop: %s: %s", reg->name(), s); +#ifdef _LP64 + push(rscratch1); // save r10, trashed by movptr() +#endif push(rax); // save rax, push(reg); // pass register argument ExternalAddress buffer((address) b); @@ -7653,6 +7656,7 @@ // call indirectly to solve generation ordering problem movptr(rax, ExternalAddress(StubRoutines::verify_oop_subroutine_entry_address())); call(rax); + // Caller pops the arguments (oop, message) and restores rax, r10 } @@ -7767,6 +7771,9 @@ char* b = new char[strlen(s) + 50]; sprintf(b, "verify_oop_addr: %s", s); +#ifdef _LP64 + push(rscratch1); // save r10, trashed by movptr() +#endif push(rax); // save rax, // addr may contain rsp so we will have to adjust it based on the push // we just did @@ -7789,7 +7796,7 @@ // call indirectly to solve generation ordering problem movptr(rax, ExternalAddress(StubRoutines::verify_oop_subroutine_entry_address())); call(rax); - // Caller pops the arguments and restores rax, from the stack + // Caller pops the arguments (addr, message) and restores rax, r10. } void MacroAssembler::verify_tlab() { diff -r c69846936352 -r e848dd13e1b6 src/cpu/x86/vm/c1_FrameMap_x86.cpp --- a/src/cpu/x86/vm/c1_FrameMap_x86.cpp Thu Jun 17 23:59:24 2010 -0700 +++ b/src/cpu/x86/vm/c1_FrameMap_x86.cpp Fri Jun 18 00:09:22 2010 -0700 @@ -136,8 +136,8 @@ // FrameMap //-------------------------------------------------------- -void FrameMap::init() { - if (_init_done) return; +void FrameMap::initialize() { + assert(!_init_done, "once"); assert(nof_cpu_regs == LP64_ONLY(16) NOT_LP64(8), "wrong number of CPU registers"); map_register(0, rsi); rsi_opr = LIR_OprFact::single_cpu(0); diff -r c69846936352 -r e848dd13e1b6 src/cpu/x86/vm/stubGenerator_x86_64.cpp --- a/src/cpu/x86/vm/stubGenerator_x86_64.cpp Thu Jun 17 23:59:24 2010 -0700 +++ b/src/cpu/x86/vm/stubGenerator_x86_64.cpp Fri Jun 18 00:09:22 2010 -0700 @@ -914,6 +914,7 @@ // * [tos + 5]: error message (char*) // * [tos + 6]: object to verify (oop) // * [tos + 7]: saved rax - saved by caller and bashed + // * [tos + 8]: saved r10 (rscratch1) - saved by caller // * = popped on exit address generate_verify_oop() { StubCodeMark mark(this, "StubRoutines", "verify_oop"); @@ -934,6 +935,7 @@ // After previous pushes. oop_to_verify = 6 * wordSize, saved_rax = 7 * wordSize, + saved_r10 = 8 * wordSize, // Before the call to MacroAssembler::debug(), see below. return_addr = 16 * wordSize, @@ -983,15 +985,17 @@ // return if everything seems ok __ bind(exit); __ movptr(rax, Address(rsp, saved_rax)); // get saved rax back + __ movptr(rscratch1, Address(rsp, saved_r10)); // get saved r10 back __ pop(c_rarg3); // restore c_rarg3 __ pop(c_rarg2); // restore c_rarg2 __ pop(r12); // restore r12 __ popf(); // restore flags - __ ret(3 * wordSize); // pop caller saved stuff + __ ret(4 * wordSize); // pop caller saved stuff // handle errors __ bind(error); __ movptr(rax, Address(rsp, saved_rax)); // get saved rax back + __ movptr(rscratch1, Address(rsp, saved_r10)); // get saved r10 back __ pop(c_rarg3); // get saved c_rarg3 back __ pop(c_rarg2); // get saved c_rarg2 back __ pop(r12); // get saved r12 back @@ -1009,6 +1013,7 @@ // * [tos + 17] error message (char*) // * [tos + 18] object to verify (oop) // * [tos + 19] saved rax - saved by caller and bashed + // * [tos + 20] saved r10 (rscratch1) - saved by caller // * = popped on exit __ movptr(c_rarg0, Address(rsp, error_msg)); // pass address of error message @@ -1021,7 +1026,7 @@ __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, MacroAssembler::debug64))); __ mov(rsp, r12); // restore rsp __ popa(); // pop registers (includes r12) - __ ret(3 * wordSize); // pop caller saved stuff + __ ret(4 * wordSize); // pop caller saved stuff return start; } diff -r c69846936352 -r e848dd13e1b6 src/share/vm/c1/c1_Canonicalizer.cpp --- a/src/share/vm/c1/c1_Canonicalizer.cpp Thu Jun 17 23:59:24 2010 -0700 +++ b/src/share/vm/c1/c1_Canonicalizer.cpp Fri Jun 18 00:09:22 2010 -0700 @@ -26,9 +26,11 @@ #include "incls/_c1_Canonicalizer.cpp.incl" -static void do_print_value(Value* vp) { - (*vp)->print_line(); -} +class PrintValueVisitor: public ValueVisitor { + void visit(Value* vp) { + (*vp)->print_line(); + } +}; void Canonicalizer::set_canonical(Value x) { assert(x != NULL, "value must exist"); @@ -37,10 +39,11 @@ // in the instructions). if (canonical() != x) { if (PrintCanonicalization) { - canonical()->input_values_do(do_print_value); + PrintValueVisitor do_print_value; + canonical()->input_values_do(&do_print_value); canonical()->print_line(); tty->print_cr("canonicalized to:"); - x->input_values_do(do_print_value); + x->input_values_do(&do_print_value); x->print_line(); tty->cr(); } @@ -202,7 +205,7 @@ // limit this optimization to current block if (value != NULL && in_current_block(conv)) { set_canonical(new StoreField(x->obj(), x->offset(), x->field(), value, x->is_static(), - x->lock_stack(), x->state_before(), x->is_loaded(), x->is_initialized())); + x->lock_stack(), x->state_before(), x->is_loaded(), x->is_initialized())); return; } } diff -r c69846936352 -r e848dd13e1b6 src/share/vm/c1/c1_Compilation.cpp --- a/src/share/vm/c1/c1_Compilation.cpp Thu Jun 17 23:59:24 2010 -0700 +++ b/src/share/vm/c1/c1_Compilation.cpp Fri Jun 18 00:09:22 2010 -0700 @@ -66,9 +66,6 @@ } }; -Arena* Compilation::_arena = NULL; -Compilation* Compilation::_compilation = NULL; - // Implementation of Compilation @@ -238,9 +235,23 @@ } +void Compilation::setup_code_buffer(CodeBuffer* code, int call_stub_estimate) { + // Preinitialize the consts section to some large size: + int locs_buffer_size = 20 * (relocInfo::length_limit + sizeof(relocInfo)); + char* locs_buffer = NEW_RESOURCE_ARRAY(char, locs_buffer_size); + code->insts()->initialize_shared_locs((relocInfo*)locs_buffer, + locs_buffer_size / sizeof(relocInfo)); + code->initialize_consts_size(Compilation::desired_max_constant_size()); + // Call stubs + deopt/exception handler + code->initialize_stubs_size((call_stub_estimate * LIR_Assembler::call_stub_size) + + LIR_Assembler::exception_handler_size + + LIR_Assembler::deopt_handler_size); +} + + int Compilation::emit_code_body() { // emit code - Runtime1::setup_code_buffer(code(), allocator()->num_calls()); + setup_code_buffer(code(), allocator()->num_calls()); code()->initialize_oop_recorder(env()->oop_recorder()); _masm = new C1_MacroAssembler(code()); @@ -422,7 +433,8 @@ } -Compilation::Compilation(AbstractCompiler* compiler, ciEnv* env, ciMethod* method, int osr_bci) +Compilation::Compilation(AbstractCompiler* compiler, ciEnv* env, ciMethod* method, + int osr_bci, BufferBlob* buffer_blob) : _compiler(compiler) , _env(env) , _method(method) @@ -437,8 +449,10 @@ , _bailout_msg(NULL) , _exception_info_list(NULL) , _allocator(NULL) -, _code(Runtime1::get_buffer_blob()->instructions_begin(), - Runtime1::get_buffer_blob()->instructions_size()) +, _next_id(0) +, _next_block_id(0) +, _code(buffer_blob->instructions_begin(), + buffer_blob->instructions_size()) , _current_instruction(NULL) #ifndef PRODUCT , _last_instruction_printed(NULL) @@ -446,17 +460,15 @@ { PhaseTraceTime timeit(_t_compile); - assert(_arena == NULL, "shouldn't only one instance of Compilation in existence at a time"); _arena = Thread::current()->resource_area(); - _compilation = this; + _env->set_compiler_data(this); _exception_info_list = new ExceptionInfoList(); _implicit_exception_table.set_size(0); compile_method(); } Compilation::~Compilation() { - _arena = NULL; - _compilation = NULL; + _env->set_compiler_data(NULL); } diff -r c69846936352 -r e848dd13e1b6 src/share/vm/c1/c1_Compilation.hpp --- a/src/share/vm/c1/c1_Compilation.hpp Thu Jun 17 23:59:24 2010 -0700 +++ b/src/share/vm/c1/c1_Compilation.hpp Fri Jun 18 00:09:22 2010 -0700 @@ -54,14 +54,10 @@ class Compilation: public StackObj { friend class CompilationResourceObj; private: - - static Arena* _arena; - static Arena* arena() { return _arena; } - - static Compilation* _compilation; - - private: // compilation specifics + Arena* _arena; + int _next_id; + int _next_block_id; AbstractCompiler* _compiler; ciEnv* _env; ciMethod* _method; @@ -108,10 +104,14 @@ public: // creation - Compilation(AbstractCompiler* compiler, ciEnv* env, ciMethod* method, int osr_bci); + Compilation(AbstractCompiler* compiler, ciEnv* env, ciMethod* method, + int osr_bci, BufferBlob* buffer_blob); ~Compilation(); - static Compilation* current_compilation() { return _compilation; } + + static Compilation* current() { + return (Compilation*) ciEnv::current()->compiler_data(); + } // accessors ciEnv* env() const { return _env; } @@ -128,6 +128,15 @@ CodeBuffer* code() { return &_code; } C1_MacroAssembler* masm() const { return _masm; } CodeOffsets* offsets() { return &_offsets; } + Arena* arena() { return _arena; } + + // Instruction ids + int get_next_id() { return _next_id++; } + int number_of_instructions() const { return _next_id; } + + // BlockBegin ids + int get_next_block_id() { return _next_block_id++; } + int number_of_blocks() const { return _next_block_id; } // setters void set_has_exception_handlers(bool f) { _has_exception_handlers = f; } @@ -158,6 +167,15 @@ bool bailed_out() const { return _bailout_msg != NULL; } const char* bailout_msg() const { return _bailout_msg; } + static int desired_max_code_buffer_size() { + return (int) NMethodSizeLimit; // default 256K or 512K + } + static int desired_max_constant_size() { + return (int) NMethodSizeLimit / 10; // about 25K + } + + static void setup_code_buffer(CodeBuffer* cb, int call_stub_estimate); + // timers static void print_timers(); @@ -203,7 +221,10 @@ // Base class for objects allocated by the compiler in the compilation arena class CompilationResourceObj ALLOCATION_SUPER_CLASS_SPEC { public: - void* operator new(size_t size) { return Compilation::arena()->Amalloc(size); } + void* operator new(size_t size) { return Compilation::current()->arena()->Amalloc(size); } + void* operator new(size_t size, Arena* arena) { + return arena->Amalloc(size); + } void operator delete(void* p) {} // nothing to do }; diff -r c69846936352 -r e848dd13e1b6 src/share/vm/c1/c1_Compiler.cpp --- a/src/share/vm/c1/c1_Compiler.cpp Thu Jun 17 23:59:24 2010 -0700 +++ b/src/share/vm/c1/c1_Compiler.cpp Fri Jun 18 00:09:22 2010 -0700 @@ -27,9 +27,6 @@ volatile int Compiler::_runtimes = uninitialized; -volatile bool Compiler::_compiling = false; - - Compiler::Compiler() { } @@ -39,47 +36,62 @@ } +void Compiler::initialize_all() { + BufferBlob* buffer_blob = CompilerThread::current()->get_buffer_blob(); + Arena* arena = new Arena(); + Runtime1::initialize(buffer_blob); + FrameMap::initialize(); + // initialize data structures + ValueType::initialize(arena); + // Instruction::initialize(); + // BlockBegin::initialize(); + GraphBuilder::initialize(); + // note: to use more than one instance of LinearScan at a time this function call has to + // be moved somewhere outside of this constructor: + Interval::initialize(arena); +} + + void Compiler::initialize() { if (_runtimes != initialized) { - initialize_runtimes( Runtime1::initialize, &_runtimes); + initialize_runtimes( initialize_all, &_runtimes); } mark_initialized(); } +BufferBlob* Compiler::build_buffer_blob() { + // setup CodeBuffer. Preallocate a BufferBlob of size + // NMethodSizeLimit plus some extra space for constants. + int code_buffer_size = Compilation::desired_max_code_buffer_size() + + Compilation::desired_max_constant_size(); + BufferBlob* blob = BufferBlob::create("Compiler1 temporary CodeBuffer", + code_buffer_size); + guarantee(blob != NULL, "must create initial code buffer"); + return blob; +} + + void Compiler::compile_method(ciEnv* env, ciMethod* method, int entry_bci) { + // Allocate buffer blob once at startup since allocation for each + // compilation seems to be too expensive (at least on Intel win32). + BufferBlob* buffer_blob = CompilerThread::current()->get_buffer_blob(); + if (buffer_blob == NULL) { + buffer_blob = build_buffer_blob(); + CompilerThread::current()->set_buffer_blob(buffer_blob); + } if (!is_initialized()) { initialize(); } // invoke compilation -#ifdef TIERED - // We are thread in native here... - CompilerThread* thread = CompilerThread::current(); - { - ThreadInVMfromNative tv(thread); - MutexLocker only_one (C1_lock, thread); - while ( _compiling) { - C1_lock->wait(); - } - _compiling = true; - } -#endif // TIERED { // We are nested here because we need for the destructor // of Compilation to occur before we release the any // competing compiler thread ResourceMark rm; - Compilation c(this, env, method, entry_bci); + Compilation c(this, env, method, entry_bci, buffer_blob); } -#ifdef TIERED - { - ThreadInVMfromNative tv(thread); - MutexLocker only_one (C1_lock, thread); - _compiling = false; - C1_lock->notify(); - } -#endif // TIERED } diff -r c69846936352 -r e848dd13e1b6 src/share/vm/c1/c1_Compiler.hpp --- a/src/share/vm/c1/c1_Compiler.hpp Thu Jun 17 23:59:24 2010 -0700 +++ b/src/share/vm/c1/c1_Compiler.hpp Fri Jun 18 00:09:22 2010 -0700 @@ -31,10 +31,6 @@ // Tracks whether runtime has been initialized static volatile int _runtimes; - // In tiered it is possible for multiple threads to want to do compilation - // only one can enter c1 at a time - static volatile bool _compiling; - public: // Creation Compiler(); @@ -47,6 +43,7 @@ virtual bool is_c1() { return true; }; #endif // TIERED + BufferBlob* build_buffer_blob(); // Missing feature tests virtual bool supports_native() { return true; } @@ -58,6 +55,7 @@ // Initialization virtual void initialize(); + static void initialize_all(); // Compilation entry point for methods virtual void compile_method(ciEnv* env, ciMethod* target, int entry_bci); diff -r c69846936352 -r e848dd13e1b6 src/share/vm/c1/c1_FrameMap.cpp --- a/src/share/vm/c1/c1_FrameMap.cpp Thu Jun 17 23:59:24 2010 -0700 +++ b/src/share/vm/c1/c1_FrameMap.cpp Fri Jun 18 00:09:22 2010 -0700 @@ -153,7 +153,7 @@ FrameMap::FrameMap(ciMethod* method, int monitors, int reserved_argument_area_size) { - if (!_init_done) init(); + assert(_init_done, "should already be completed"); _framesize = -1; _num_spills = -1; diff -r c69846936352 -r e848dd13e1b6 src/share/vm/c1/c1_FrameMap.hpp --- a/src/share/vm/c1/c1_FrameMap.hpp Thu Jun 17 23:59:24 2010 -0700 +++ b/src/share/vm/c1/c1_FrameMap.hpp Fri Jun 18 00:09:22 2010 -0700 @@ -235,7 +235,7 @@ return _caller_save_fpu_regs[i]; } - static void init(); + static void initialize(); }; // CallingConvention diff -r c69846936352 -r e848dd13e1b6 src/share/vm/c1/c1_GraphBuilder.cpp --- a/src/share/vm/c1/c1_GraphBuilder.cpp Thu Jun 17 23:59:24 2010 -0700 +++ b/src/share/vm/c1/c1_GraphBuilder.cpp Fri Jun 18 00:09:22 2010 -0700 @@ -2530,16 +2530,10 @@ } -bool GraphBuilder::_is_initialized = false; bool GraphBuilder::_can_trap [Bytecodes::number_of_java_codes]; bool GraphBuilder::_is_async[Bytecodes::number_of_java_codes]; void GraphBuilder::initialize() { - // make sure initialization happens only once (need a - // lock here, if we allow the compiler to be re-entrant) - if (is_initialized()) return; - _is_initialized = true; - // the following bytecodes are assumed to potentially // throw exceptions in compiled code - note that e.g. // monitorexit & the return bytecodes do not throw @@ -2855,7 +2849,6 @@ BlockList* bci2block = blm.bci2block(); BlockBegin* start_block = bci2block->at(0); - assert(is_initialized(), "GraphBuilder must have been initialized"); push_root_scope(scope, bci2block, start_block); // setup state for std entry diff -r c69846936352 -r e848dd13e1b6 src/share/vm/c1/c1_GraphBuilder.hpp --- a/src/share/vm/c1/c1_GraphBuilder.hpp Thu Jun 17 23:59:24 2010 -0700 +++ b/src/share/vm/c1/c1_GraphBuilder.hpp Fri Jun 18 00:09:22 2010 -0700 @@ -162,7 +162,6 @@ }; // for all GraphBuilders - static bool _is_initialized; // true if trap tables were initialized, false otherwise static bool _can_trap[Bytecodes::number_of_java_codes]; static bool _is_async[Bytecodes::number_of_java_codes]; @@ -268,7 +267,6 @@ Instruction* append_split(StateSplit* instr); // other helpers - static bool is_initialized() { return _is_initialized; } static bool is_async(Bytecodes::Code code) { assert(0 <= code && code < Bytecodes::number_of_java_codes, "illegal bytecode"); return _is_async[code]; diff -r c69846936352 -r e848dd13e1b6 src/share/vm/c1/c1_IR.cpp --- a/src/share/vm/c1/c1_IR.cpp Thu Jun 17 23:59:24 2010 -0700 +++ b/src/share/vm/c1/c1_IR.cpp Fri Jun 18 00:09:22 2010 -0700 @@ -287,11 +287,6 @@ IR::IR(Compilation* compilation, ciMethod* method, int osr_bci) : _locals_size(in_WordSize(-1)) , _num_loops(0) { - // initialize data structures - ValueType::initialize(); - Instruction::initialize(); - BlockBegin::initialize(); - GraphBuilder::initialize(); // setup IR fields _compilation = compilation; _top_scope = new IRScope(compilation, NULL, -1, method, osr_bci, true); @@ -381,15 +376,15 @@ } -class UseCountComputer: public AllStatic { +class UseCountComputer: public ValueVisitor, BlockClosure { private: - static void update_use_count(Value* n) { + void visit(Value* n) { // Local instructions and Phis for expression stack values at the // start of basic blocks are not added to the instruction list if ((*n)->bci() == -99 && (*n)->as_Local() == NULL && (*n)->as_Phi() == NULL) { assert(false, "a node was not appended to the graph"); - Compilation::current_compilation()->bailout("a node was not appended to the graph"); + Compilation::current()->bailout("a node was not appended to the graph"); } // use n's input if not visited before if (!(*n)->is_pinned() && !(*n)->has_uses()) { @@ -402,31 +397,31 @@ (*n)->_use_count++; } - static Values* worklist; - static int depth; + Values* worklist; + int depth; enum { max_recurse_depth = 20 }; - static void uses_do(Value* n) { + void uses_do(Value* n) { depth++; if (depth > max_recurse_depth) { // don't allow the traversal to recurse too deeply worklist->push(*n); } else { - (*n)->input_values_do(update_use_count); + (*n)->input_values_do(this); // special handling for some instructions if ((*n)->as_BlockEnd() != NULL) { // note on BlockEnd: // must 'use' the stack only if the method doesn't // terminate, however, in those cases stack is empty - (*n)->state_values_do(update_use_count); + (*n)->state_values_do(this); } } depth--; } - static void basic_compute_use_count(BlockBegin* b) { + void block_do(BlockBegin* b) { depth = 0; // process all pinned nodes as the roots of expression trees for (Instruction* n = b; n != NULL; n = n->next()) { @@ -449,18 +444,19 @@ assert(depth == 0, "should have counted back down"); } + UseCountComputer() { + worklist = new Values(); + depth = 0; + } + public: static void compute(BlockList* blocks) { - worklist = new Values(); - blocks->blocks_do(basic_compute_use_count); - worklist = NULL; + UseCountComputer ucc; + blocks->iterate_backward(&ucc); } }; -Values* UseCountComputer::worklist = NULL; -int UseCountComputer::depth = 0; - // helper macro for short definition of trace-output inside code #ifndef PRODUCT #define TRACE_LINEAR_SCAN(level, code) \ @@ -1302,7 +1298,7 @@ #endif // PRODUCT -void SubstitutionResolver::substitute(Value* v) { +void SubstitutionResolver::visit(Value* v) { Value v0 = *v; if (v0) { Value vs = v0->subst(); @@ -1313,20 +1309,22 @@ } #ifdef ASSERT -void check_substitute(Value* v) { - Value v0 = *v; - if (v0) { - Value vs = v0->subst(); - assert(vs == v0, "missed substitution"); +class SubstitutionChecker: public ValueVisitor { + void visit(Value* v) { + Value v0 = *v; + if (v0) { + Value vs = v0->subst(); + assert(vs == v0, "missed substitution"); + } } -} +}; #endif void SubstitutionResolver::block_do(BlockBegin* block) { Instruction* last = NULL; for (Instruction* n = block; n != NULL;) { - n->values_do(substitute); + n->values_do(this); // need to remove this instruction from the instruction stream if (n->subst() != n) { assert(last != NULL, "must have last"); @@ -1338,8 +1336,9 @@ } #ifdef ASSERT - if (block->state()) block->state()->values_do(check_substitute); - block->block_values_do(check_substitute); - if (block->end() && block->end()->state()) block->end()->state()->values_do(check_substitute); + SubstitutionChecker check_substitute; + if (block->state()) block->state()->values_do(&check_substitute); + block->block_values_do(&check_substitute); + if (block->end() && block->end()->state()) block->end()->state()->values_do(&check_substitute); #endif } diff -r c69846936352 -r e848dd13e1b6 src/share/vm/c1/c1_IR.hpp --- a/src/share/vm/c1/c1_IR.hpp Thu Jun 17 23:59:24 2010 -0700 +++ b/src/share/vm/c1/c1_IR.hpp Fri Jun 18 00:09:22 2010 -0700 @@ -371,8 +371,8 @@ // instructions from the instruction list. // -class SubstitutionResolver: public BlockClosure { - static void substitute(Value* v); +class SubstitutionResolver: public BlockClosure, ValueVisitor { + virtual void visit(Value* v); public: SubstitutionResolver(IR* hir) { diff -r c69846936352 -r e848dd13e1b6 src/share/vm/c1/c1_Instruction.cpp --- a/src/share/vm/c1/c1_Instruction.cpp Thu Jun 17 23:59:24 2010 -0700 +++ b/src/share/vm/c1/c1_Instruction.cpp Fri Jun 18 00:09:22 2010 -0700 @@ -29,8 +29,6 @@ // Implementation of Instruction -int Instruction::_next_id = 0; - #ifdef ASSERT void Instruction::create_hi_word() { assert(type()->is_double_word() && _hi_word == NULL, "only double word has high word"); @@ -193,22 +191,22 @@ } -void ArithmeticOp::other_values_do(void f(Value*)) { +void ArithmeticOp::other_values_do(ValueVisitor* f) { if (lock_stack() != NULL) lock_stack()->values_do(f); } -void NullCheck::other_values_do(void f(Value*)) { +void NullCheck::other_values_do(ValueVisitor* f) { lock_stack()->values_do(f); } -void AccessArray::other_values_do(void f(Value*)) { +void AccessArray::other_values_do(ValueVisitor* f) { if (lock_stack() != NULL) lock_stack()->values_do(f); } // Implementation of AccessField -void AccessField::other_values_do(void f(Value*)) { +void AccessField::other_values_do(ValueVisitor* f) { if (state_before() != NULL) state_before()->values_do(f); if (lock_stack() != NULL) lock_stack()->values_do(f); } @@ -270,7 +268,7 @@ // Implementation of CompareOp -void CompareOp::other_values_do(void f(Value*)) { +void CompareOp::other_values_do(ValueVisitor* f) { if (state_before() != NULL) state_before()->values_do(f); } @@ -302,12 +300,12 @@ } -void StateSplit::state_values_do(void f(Value*)) { +void StateSplit::state_values_do(ValueVisitor* f) { if (state() != NULL) state()->values_do(f); } -void BlockBegin::state_values_do(void f(Value*)) { +void BlockBegin::state_values_do(ValueVisitor* f) { StateSplit::state_values_do(f); if (is_set(BlockBegin::exception_entry_flag)) { @@ -318,13 +316,13 @@ } -void MonitorEnter::state_values_do(void f(Value*)) { +void MonitorEnter::state_values_do(ValueVisitor* f) { StateSplit::state_values_do(f); _lock_stack_before->values_do(f); } -void Intrinsic::state_values_do(void f(Value*)) { +void Intrinsic::state_values_do(ValueVisitor* f) { StateSplit::state_values_do(f); if (lock_stack() != NULL) lock_stack()->values_do(f); } @@ -349,8 +347,9 @@ assert(args != NULL, "args must exist"); #ifdef ASSERT - values_do(assert_value); -#endif // ASSERT + AssertValues assert_value; + values_do(&assert_value); +#endif // provide an initial guess of signature size. _signature = new BasicTypeList(number_of_arguments() + (has_receiver() ? 1 : 0)); @@ -368,7 +367,7 @@ } -void Invoke::state_values_do(void f(Value*)) { +void Invoke::state_values_do(ValueVisitor* f) { StateSplit::state_values_do(f); if (state_before() != NULL) state_before()->values_do(f); if (state() != NULL) state()->values_do(f); @@ -500,30 +499,27 @@ } -void Constant::other_values_do(void f(Value*)) { +void Constant::other_values_do(ValueVisitor* f) { if (state() != NULL) state()->values_do(f); } // Implementation of NewArray -void NewArray::other_values_do(void f(Value*)) { +void NewArray::other_values_do(ValueVisitor* f) { if (state_before() != NULL) state_before()->values_do(f); } // Implementation of TypeCheck -void TypeCheck::other_values_do(void f(Value*)) { +void TypeCheck::other_values_do(ValueVisitor* f) { if (state_before() != NULL) state_before()->values_do(f); } // Implementation of BlockBegin -int BlockBegin::_next_block_id = 0; - - void BlockBegin::set_end(BlockEnd* end) { assert(end != NULL, "should not reset block end to NULL"); BlockEnd* old_end = _end; @@ -738,7 +734,7 @@ } -void BlockBegin::block_values_do(void f(Value*)) { +void BlockBegin::block_values_do(ValueVisitor* f) { for (Instruction* n = this; n != NULL; n = n->next()) n->values_do(f); } @@ -930,7 +926,7 @@ } -void BlockList::values_do(void f(Value*)) { +void BlockList::values_do(ValueVisitor* f) { for (int i = length() - 1; i >= 0; i--) at(i)->block_values_do(f); } @@ -973,7 +969,7 @@ } -void BlockEnd::other_values_do(void f(Value*)) { +void BlockEnd::other_values_do(ValueVisitor* f) { if (state_before() != NULL) state_before()->values_do(f); } @@ -1012,6 +1008,6 @@ // Implementation of Throw -void Throw::state_values_do(void f(Value*)) { +void Throw::state_values_do(ValueVisitor* f) { BlockEnd::state_values_do(f); } diff -r c69846936352 -r e848dd13e1b6 src/share/vm/c1/c1_Instruction.hpp --- a/src/share/vm/c1/c1_Instruction.hpp Thu Jun 17 23:59:24 2010 -0700 +++ b/src/share/vm/c1/c1_Instruction.hpp Fri Jun 18 00:09:22 2010 -0700 @@ -116,6 +116,13 @@ }; +// A simple closure class for visiting the values of an Instruction +class ValueVisitor: public StackObj { + public: + virtual void visit(Value* v) = 0; +}; + + // Some array and list classes define_array(BlockBeginArray, BlockBegin*) define_stack(_BlockList, BlockBeginArray) @@ -129,7 +136,7 @@ void iterate_forward(BlockClosure* closure); void iterate_backward(BlockClosure* closure); void blocks_do(void f(BlockBegin*)); - void values_do(void f(Value*)); + void values_do(ValueVisitor* f); void print(bool cfg_only = false, bool live_only = false) PRODUCT_RETURN; }; @@ -264,8 +271,6 @@ class Instruction: public CompilationResourceObj { private: - static int _next_id; // the node counter - int _id; // the unique instruction id int _bci; // the instruction bci int _use_count; // the number of instructions refering to this value (w/o prev/next); only roots can have use count = 0 or > 1 @@ -283,6 +288,7 @@ #endif friend class UseCountComputer; + friend class BlockBegin; protected: void set_bci(int bci) { assert(bci == SynchronizationEntryBCI || bci >= 0, "illegal bci"); _bci = bci; } @@ -292,6 +298,13 @@ } public: + void* operator new(size_t size) { + Compilation* c = Compilation::current(); + void* res = c->arena()->Amalloc(size); + ((Instruction*)res)->_id = c->get_next_id(); + return res; + } + enum InstructionFlag { NeedsNullCheckFlag = 0, CanTrapFlag, @@ -338,13 +351,13 @@ static Condition negate(Condition cond); // initialization - static void initialize() { _next_id = 0; } - static int number_of_instructions() { return _next_id; } + static int number_of_instructions() { + return Compilation::current()->number_of_instructions(); + } // creation Instruction(ValueType* type, bool type_is_constant = false, bool create_hi = true) - : _id(_next_id++) - , _bci(-99) + : _bci(-99) , _use_count(0) , _pin_state(0) , _type(type) @@ -479,10 +492,10 @@ virtual bool can_trap() const { return false; } - virtual void input_values_do(void f(Value*)) = 0; - virtual void state_values_do(void f(Value*)) { /* usually no state - override on demand */ } - virtual void other_values_do(void f(Value*)) { /* usually no other - override on demand */ } - void values_do(void f(Value*)) { input_values_do(f); state_values_do(f); other_values_do(f); } + virtual void input_values_do(ValueVisitor* f) = 0; + virtual void state_values_do(ValueVisitor* f) { /* usually no state - override on demand */ } + virtual void other_values_do(ValueVisitor* f) { /* usually no other - override on demand */ } + void values_do(ValueVisitor* f) { input_values_do(f); state_values_do(f); other_values_do(f); } virtual ciType* exact_type() const { return NULL; } virtual ciType* declared_type() const { return NULL; } @@ -517,9 +530,12 @@ // Debugging support + #ifdef ASSERT - static void assert_value(Value* x) { assert((*x) != NULL, "value must exist"); } - #define ASSERT_VALUES values_do(assert_value); +class AssertValues: public ValueVisitor { + void visit(Value* x) { assert((*x) != NULL, "value must exist"); } +}; + #define ASSERT_VALUES { AssertValues assert_value; values_do(&assert_value); } #else #define ASSERT_VALUES #endif // ASSERT @@ -555,7 +571,7 @@ void make_illegal() { set_type(illegalType); } // generic - virtual void input_values_do(void f(Value*)) { ShouldNotReachHere(); } + virtual void input_values_do(ValueVisitor* f) { ShouldNotReachHere(); } }; @@ -615,7 +631,7 @@ } // generic - virtual void input_values_do(void f(Value*)) { + virtual void input_values_do(ValueVisitor* f) { } }; @@ -635,7 +651,7 @@ int java_index() const { return _java_index; } // generic - virtual void input_values_do(void f(Value*)) { /* no values */ } + virtual void input_values_do(ValueVisitor* f) { /* no values */ } }; @@ -663,8 +679,8 @@ // generic virtual bool can_trap() const { return state() != NULL; } - virtual void input_values_do(void f(Value*)) { /* no values */ } - virtual void other_values_do(void f(Value*)); + virtual void input_values_do(ValueVisitor* f) { /* no values */ } + virtual void other_values_do(ValueVisitor* f); virtual intx hash() const; virtual bool is_equal(Value v) const; @@ -734,8 +750,8 @@ // generic virtual bool can_trap() const { return needs_null_check() || needs_patching(); } - virtual void input_values_do(void f(Value*)) { f(&_obj); } - virtual void other_values_do(void f(Value*)); + virtual void input_values_do(ValueVisitor* f) { f->visit(&_obj); } + virtual void other_values_do(ValueVisitor* f); }; @@ -776,7 +792,7 @@ bool needs_write_barrier() const { return check_flag(NeedsWriteBarrierFlag); } // generic - virtual void input_values_do(void f(Value*)) { AccessField::input_values_do(f); f(&_value); } + virtual void input_values_do(ValueVisitor* f) { AccessField::input_values_do(f); f->visit(&_value); } }; @@ -804,8 +820,8 @@ // generic virtual bool can_trap() const { return needs_null_check(); } - virtual void input_values_do(void f(Value*)) { f(&_array); } - virtual void other_values_do(void f(Value*)); + virtual void input_values_do(ValueVisitor* f) { f->visit(&_array); } + virtual void other_values_do(ValueVisitor* f); }; @@ -857,7 +873,7 @@ bool compute_needs_range_check(); // generic - virtual void input_values_do(void f(Value*)) { AccessArray::input_values_do(f); f(&_index); if (_length != NULL) f(&_length); } + virtual void input_values_do(ValueVisitor* f) { AccessArray::input_values_do(f); f->visit(&_index); if (_length != NULL) f->visit(&_length); } }; @@ -909,7 +925,7 @@ bool needs_store_check() const { return check_flag(NeedsStoreCheckFlag); } // generic - virtual void input_values_do(void f(Value*)) { AccessIndexed::input_values_do(f); f(&_value); } + virtual void input_values_do(ValueVisitor* f) { AccessIndexed::input_values_do(f); f->visit(&_value); } }; @@ -927,7 +943,7 @@ Value x() const { return _x; } // generic - virtual void input_values_do(void f(Value*)) { f(&_x); } + virtual void input_values_do(ValueVisitor* f) { f->visit(&_x); } }; @@ -956,7 +972,7 @@ // generic virtual bool is_commutative() const { return false; } - virtual void input_values_do(void f(Value*)) { f(&_x); f(&_y); } + virtual void input_values_do(ValueVisitor* f) { f->visit(&_x); f->visit(&_y); } }; @@ -982,7 +998,7 @@ // generic virtual bool is_commutative() const; virtual bool can_trap() const; - virtual void other_values_do(void f(Value*)); + virtual void other_values_do(ValueVisitor* f); HASHING3(Op2, true, op(), x()->subst(), y()->subst()) }; @@ -1023,7 +1039,7 @@ // generic HASHING3(Op2, true, op(), x()->subst(), y()->subst()) - virtual void other_values_do(void f(Value*)); + virtual void other_values_do(ValueVisitor* f); }; @@ -1051,7 +1067,7 @@ Value fval() const { return _fval; } // generic - virtual void input_values_do(void f(Value*)) { Op2::input_values_do(f); f(&_tval); f(&_fval); } + virtual void input_values_do(ValueVisitor* f) { Op2::input_values_do(f); f->visit(&_tval); f->visit(&_fval); } }; @@ -1071,7 +1087,7 @@ Value value() const { return _value; } // generic - virtual void input_values_do(void f(Value*)) { f(&_value); } + virtual void input_values_do(ValueVisitor* f) { f->visit(&_value); } HASHING2(Convert, true, op(), value()->subst()) }; @@ -1100,8 +1116,8 @@ // generic virtual bool can_trap() const { return check_flag(CanTrapFlag); /* null-check elimination sets to false */ } - virtual void input_values_do(void f(Value*)) { f(&_obj); } - virtual void other_values_do(void f(Value*)); + virtual void input_values_do(ValueVisitor* f) { f->visit(&_obj); } + virtual void other_values_do(ValueVisitor* f); HASHING1(NullCheck, true, obj()->subst()) }; @@ -1127,8 +1143,8 @@ void set_state(ValueStack* state) { _state = state; } // generic - virtual void input_values_do(void f(Value*)) { /* no values */ } - virtual void state_values_do(void f(Value*)); + virtual void input_values_do(ValueVisitor* f) { /* no values */ } + virtual void state_values_do(ValueVisitor* f); }; @@ -1169,12 +1185,12 @@ // generic virtual bool can_trap() const { return true; } - virtual void input_values_do(void f(Value*)) { + virtual void input_values_do(ValueVisitor* f) { StateSplit::input_values_do(f); - if (has_receiver()) f(&_recv); - for (int i = 0; i < _args->length(); i++) f(_args->adr_at(i)); + if (has_receiver()) f->visit(&_recv); + for (int i = 0; i < _args->length(); i++) f->visit(_args->adr_at(i)); } - virtual void state_values_do(void f(Value*)); + virtual void state_values_do(ValueVisitor *f); }; @@ -1212,8 +1228,8 @@ // generic virtual bool can_trap() const { return true; } - virtual void input_values_do(void f(Value*)) { StateSplit::input_values_do(f); f(&_length); } - virtual void other_values_do(void f(Value*)); + virtual void input_values_do(ValueVisitor* f) { StateSplit::input_values_do(f); f->visit(&_length); } + virtual void other_values_do(ValueVisitor* f); }; @@ -1262,7 +1278,7 @@ int rank() const { return dims()->length(); } // generic - virtual void input_values_do(void f(Value*)) { + virtual void input_values_do(ValueVisitor* f) { // NOTE: we do not call NewArray::input_values_do since "length" // is meaningless for a multi-dimensional array; passing the // zeroth element down to NewArray as its length is a bad idea @@ -1270,7 +1286,7 @@ // get updated, and the value must not be traversed twice. Was bug // - kbr 4/10/2001 StateSplit::input_values_do(f); - for (int i = 0; i < _dims->length(); i++) f(_dims->adr_at(i)); + for (int i = 0; i < _dims->length(); i++) f->visit(_dims->adr_at(i)); } }; @@ -1300,8 +1316,8 @@ // generic virtual bool can_trap() const { return true; } - virtual void input_values_do(void f(Value*)) { StateSplit::input_values_do(f); f(&_obj); } - virtual void other_values_do(void f(Value*)); + virtual void input_values_do(ValueVisitor* f) { StateSplit::input_values_do(f); f->visit(&_obj); } + virtual void other_values_do(ValueVisitor* f); }; @@ -1366,7 +1382,7 @@ int monitor_no() const { return _monitor_no; } // generic - virtual void input_values_do(void f(Value*)) { StateSplit::input_values_do(f); f(&_obj); } + virtual void input_values_do(ValueVisitor* f) { StateSplit::input_values_do(f); f->visit(&_obj); } }; @@ -1385,7 +1401,7 @@ // accessors ValueStack* lock_stack_before() const { return _lock_stack_before; } - virtual void state_values_do(void f(Value*)); + virtual void state_values_do(ValueVisitor* f); // generic virtual bool can_trap() const { return true; } @@ -1454,11 +1470,11 @@ // generic virtual bool can_trap() const { return check_flag(CanTrapFlag); } - virtual void input_values_do(void f(Value*)) { + virtual void input_values_do(ValueVisitor* f) { StateSplit::input_values_do(f); - for (int i = 0; i < _args->length(); i++) f(_args->adr_at(i)); + for (int i = 0; i < _args->length(); i++) f->visit(_args->adr_at(i)); } - virtual void state_values_do(void f(Value*)); + virtual void state_values_do(ValueVisitor* f); }; @@ -1467,8 +1483,6 @@ LEAF(BlockBegin, StateSplit) private: - static int _next_block_id; // the block counter - int _block_id; // the unique block id int _depth_first_number; // number of this block in a depth-first ordering int _linear_scan_number; // number of this block in linear-scan ordering @@ -1510,14 +1524,22 @@ friend class SuxAndWeightAdjuster; public: + void* operator new(size_t size) { + Compilation* c = Compilation::current(); + void* res = c->arena()->Amalloc(size); + ((BlockBegin*)res)->_id = c->get_next_id(); + ((BlockBegin*)res)->_block_id = c->get_next_block_id(); + return res; + } + // initialization/counting - static void initialize() { _next_block_id = 0; } - static int number_of_blocks() { return _next_block_id; } + static int number_of_blocks() { + return Compilation::current()->number_of_blocks(); + } // creation BlockBegin(int bci) : StateSplit(illegalType) - , _block_id(_next_block_id++) , _depth_first_number(-1) , _linear_scan_number(-1) , _loop_depth(0) @@ -1592,7 +1614,7 @@ void init_stores_to_locals(int locals_count) { _stores_to_locals = BitMap(locals_count); _stores_to_locals.clear(); } // generic - virtual void state_values_do(void f(Value*)); + virtual void state_values_do(ValueVisitor* f); // successors and predecessors int number_of_sux() const; @@ -1646,7 +1668,7 @@ void iterate_preorder (BlockClosure* closure); void iterate_postorder (BlockClosure* closure); - void block_values_do(void f(Value*)); + void block_values_do(ValueVisitor* f); // loops void set_loop_index(int ix) { _loop_index = ix; } @@ -1698,7 +1720,7 @@ void set_begin(BlockBegin* begin); // generic - virtual void other_values_do(void f(Value*)); + virtual void other_values_do(ValueVisitor* f); // successors int number_of_sux() const { return _sux != NULL ? _sux->length() : 0; } @@ -1787,7 +1809,7 @@ void set_profiled_bci(int bci) { _profiled_bci = bci; } // generic - virtual void input_values_do(void f(Value*)) { BlockEnd::input_values_do(f); f(&_x); f(&_y); } + virtual void input_values_do(ValueVisitor* f) { BlockEnd::input_values_do(f); f->visit(&_x); f->visit(&_y); } }; @@ -1841,7 +1863,7 @@ } // generic - virtual void input_values_do(void f(Value*)) { BlockEnd::input_values_do(f); f(&_obj); } + virtual void input_values_do(ValueVisitor* f) { BlockEnd::input_values_do(f); f->visit(&_obj); } }; @@ -1863,7 +1885,7 @@ int length() const { return number_of_sux() - 1; } // generic - virtual void input_values_do(void f(Value*)) { BlockEnd::input_values_do(f); f(&_tag); } + virtual void input_values_do(ValueVisitor* f) { BlockEnd::input_values_do(f); f->visit(&_tag); } }; @@ -1916,9 +1938,9 @@ bool has_result() const { return result() != NULL; } // generic - virtual void input_values_do(void f(Value*)) { + virtual void input_values_do(ValueVisitor* f) { BlockEnd::input_values_do(f); - if (has_result()) f(&_result); + if (has_result()) f->visit(&_result); } }; @@ -1938,8 +1960,8 @@ // generic virtual bool can_trap() const { return true; } - virtual void input_values_do(void f(Value*)) { BlockEnd::input_values_do(f); f(&_exception); } - virtual void state_values_do(void f(Value*)); + virtual void input_values_do(ValueVisitor* f) { BlockEnd::input_values_do(f); f->visit(&_exception); } + virtual void state_values_do(ValueVisitor* f); }; @@ -1971,7 +1993,7 @@ #endif // generic - virtual void input_values_do(void f(Value*)) { } + virtual void input_values_do(ValueVisitor* f) { } }; @@ -1984,7 +2006,7 @@ } // generic - virtual void input_values_do(void f(Value*)) { } + virtual void input_values_do(ValueVisitor* f) { } }; @@ -2008,7 +2030,7 @@ Value input() const { return _input; } // generic - virtual void input_values_do(void f(Value*)) { f(&_input); } + virtual void input_values_do(ValueVisitor* f) { f->visit(&_input); } }; @@ -2033,8 +2055,8 @@ BasicType basic_type() { return _basic_type; } // generic - virtual void input_values_do(void f(Value*)) { } - virtual void other_values_do(void f(Value*)) { } + virtual void input_values_do(ValueVisitor* f) { } + virtual void other_values_do(ValueVisitor* f) { } }; @@ -2078,9 +2100,9 @@ void set_log2_scale(int log2_scale) { _log2_scale = log2_scale; } // generic - virtual void input_values_do(void f(Value*)) { UnsafeOp::input_values_do(f); - f(&_base); - if (has_index()) f(&_index); } + virtual void input_values_do(ValueVisitor* f) { UnsafeOp::input_values_do(f); + f->visit(&_base); + if (has_index()) f->visit(&_index); } }; @@ -2128,8 +2150,8 @@ Value value() { return _value; } // generic - virtual void input_values_do(void f(Value*)) { UnsafeRawOp::input_values_do(f); - f(&_value); } + virtual void input_values_do(ValueVisitor* f) { UnsafeRawOp::input_values_do(f); + f->visit(&_value); } }; @@ -2149,9 +2171,9 @@ Value offset() { return _offset; } bool is_volatile() { return _is_volatile; } // generic - virtual void input_values_do(void f(Value*)) { UnsafeOp::input_values_do(f); - f(&_object); - f(&_offset); } + virtual void input_values_do(ValueVisitor* f) { UnsafeOp::input_values_do(f); + f->visit(&_object); + f->visit(&_offset); } }; @@ -2180,8 +2202,8 @@ Value value() { return _value; } // generic - virtual void input_values_do(void f(Value*)) { UnsafeObjectOp::input_values_do(f); - f(&_value); } + virtual void input_values_do(ValueVisitor* f) { UnsafeObjectOp::input_values_do(f); + f->visit(&_value); } }; @@ -2238,7 +2260,7 @@ Value recv() { return _recv; } ciKlass* known_holder() { return _known_holder; } - virtual void input_values_do(void f(Value*)) { if (_recv != NULL) f(&_recv); } + virtual void input_values_do(ValueVisitor* f) { if (_recv != NULL) f->visit(&_recv); } }; @@ -2266,7 +2288,7 @@ int offset() { return _offset; } int increment() { return _increment; } - virtual void input_values_do(void f(Value*)) { f(&_mdo); } + virtual void input_values_do(ValueVisitor* f) { f->visit(&_mdo); } }; diff -r c69846936352 -r e848dd13e1b6 src/share/vm/c1/c1_LIRGenerator.cpp --- a/src/share/vm/c1/c1_LIRGenerator.cpp Thu Jun 17 23:59:24 2010 -0700 +++ b/src/share/vm/c1/c1_LIRGenerator.cpp Fri Jun 18 00:09:22 2010 -0700 @@ -304,7 +304,7 @@ __ branch_destination(block->label()); if (LIRTraceExecution && - Compilation::current_compilation()->hir()->start()->block_id() != block->block_id() && + Compilation::current()->hir()->start()->block_id() != block->block_id() && !block->is_set(BlockBegin::exception_entry_flag)) { assert(block->lir()->instructions_list()->length() == 1, "should come right after br_dst"); trace_block_entry(block); diff -r c69846936352 -r e848dd13e1b6 src/share/vm/c1/c1_LinearScan.cpp --- a/src/share/vm/c1/c1_LinearScan.cpp Thu Jun 17 23:59:24 2010 -0700 +++ b/src/share/vm/c1/c1_LinearScan.cpp Fri Jun 18 00:09:22 2010 -0700 @@ -84,10 +84,6 @@ , _fpu_stack_allocator(NULL) #endif { - // note: to use more than on instance of LinearScan at a time this function call has to - // be moved somewhere outside of this constructor: - Interval::initialize(); - assert(this->ir() != NULL, "check if valid"); assert(this->compilation() != NULL, "check if valid"); assert(this->gen() != NULL, "check if valid"); @@ -3929,8 +3925,8 @@ // initialize sentinel Range* Range::_end = NULL; -void Range::initialize() { - _end = new Range(max_jint, max_jint, NULL); +void Range::initialize(Arena* arena) { + _end = new (arena) Range(max_jint, max_jint, NULL); } int Range::intersects_at(Range* r2) const { @@ -3976,9 +3972,9 @@ // initialize sentinel Interval* Interval::_end = NULL; -void Interval::initialize() { - Range::initialize(); - _end = new Interval(-1); +void Interval::initialize(Arena* arena) { + Range::initialize(arena); + _end = new (arena) Interval(-1); } Interval::Interval(int reg_num) : diff -r c69846936352 -r e848dd13e1b6 src/share/vm/c1/c1_LinearScan.hpp --- a/src/share/vm/c1/c1_LinearScan.hpp Thu Jun 17 23:59:24 2010 -0700 +++ b/src/share/vm/c1/c1_LinearScan.hpp Fri Jun 18 00:09:22 2010 -0700 @@ -462,7 +462,7 @@ public: Range(int from, int to, Range* next); - static void initialize(); + static void initialize(Arena* arena); static Range* end() { return _end; } int from() const { return _from; } @@ -529,7 +529,7 @@ public: Interval(int reg_num); - static void initialize(); + static void initialize(Arena* arena); static Interval* end() { return _end; } // accessors diff -r c69846936352 -r e848dd13e1b6 src/share/vm/c1/c1_Optimizer.cpp --- a/src/share/vm/c1/c1_Optimizer.cpp Thu Jun 17 23:59:24 2010 -0700 +++ b/src/share/vm/c1/c1_Optimizer.cpp Fri Jun 18 00:09:22 2010 -0700 @@ -437,11 +437,8 @@ // Because of a static contained within (for the purpose of iteration // over instructions), it is only valid to have one of these active at // a time -class NullCheckEliminator { +class NullCheckEliminator: public ValueVisitor { private: - static NullCheckEliminator* _static_nce; - static void do_value(Value* vp); - Optimizer* _opt; ValueSet* _visitable_instructions; // Visit each instruction only once per basic block @@ -504,6 +501,8 @@ // Process a graph void iterate(BlockBegin* root); + void visit(Value* f); + // In some situations (like NullCheck(x); getfield(x)) the debug // information from the explicit NullCheck can be used to populate // the getfield, even if the two instructions are in different @@ -602,14 +601,11 @@ void NullCheckVisitor::do_ProfileCounter (ProfileCounter* x) {} -NullCheckEliminator* NullCheckEliminator::_static_nce = NULL; - - -void NullCheckEliminator::do_value(Value* p) { +void NullCheckEliminator::visit(Value* p) { assert(*p != NULL, "should not find NULL instructions"); - if (_static_nce->visitable(*p)) { - _static_nce->mark_visited(*p); - (*p)->visit(&_static_nce->_visitor); + if (visitable(*p)) { + mark_visited(*p); + (*p)->visit(&_visitor); } } @@ -637,7 +633,6 @@ void NullCheckEliminator::iterate_one(BlockBegin* block) { - _static_nce = this; clear_visitable_state(); // clear out an old explicit null checks set_last_explicit_null_check(NULL); @@ -712,7 +707,7 @@ mark_visitable(instr); if (instr->is_root() || instr->can_trap() || (instr->as_NullCheck() != NULL)) { mark_visited(instr); - instr->input_values_do(&NullCheckEliminator::do_value); + instr->input_values_do(this); instr->visit(&_visitor); } } diff -r c69846936352 -r e848dd13e1b6 src/share/vm/c1/c1_Runtime1.cpp --- a/src/share/vm/c1/c1_Runtime1.cpp Thu Jun 17 23:59:24 2010 -0700 +++ b/src/share/vm/c1/c1_Runtime1.cpp Fri Jun 18 00:09:22 2010 -0700 @@ -60,7 +60,6 @@ // Implementation of Runtime1 -bool Runtime1::_is_initialized = false; CodeBlob* Runtime1::_blobs[Runtime1::number_of_ids]; const char *Runtime1::_blob_names[] = { RUNTIME1_STUBS(STUB_NAME, LAST_STUB_NAME) @@ -89,8 +88,6 @@ int Runtime1::_throw_count = 0; #endif -BufferBlob* Runtime1::_buffer_blob = NULL; - // Simple helper to see if the caller of a runtime stub which // entered the VM has been deoptimized @@ -117,43 +114,14 @@ } -BufferBlob* Runtime1::get_buffer_blob() { - // Allocate code buffer space only once - BufferBlob* blob = _buffer_blob; - if (blob == NULL) { - // setup CodeBuffer. Preallocate a BufferBlob of size - // NMethodSizeLimit plus some extra space for constants. - int code_buffer_size = desired_max_code_buffer_size() + desired_max_constant_size(); - blob = BufferBlob::create("Compiler1 temporary CodeBuffer", - code_buffer_size); - guarantee(blob != NULL, "must create initial code buffer"); - _buffer_blob = blob; - } - return _buffer_blob; -} - -void Runtime1::setup_code_buffer(CodeBuffer* code, int call_stub_estimate) { - // Preinitialize the consts section to some large size: - int locs_buffer_size = 20 * (relocInfo::length_limit + sizeof(relocInfo)); - char* locs_buffer = NEW_RESOURCE_ARRAY(char, locs_buffer_size); - code->insts()->initialize_shared_locs((relocInfo*)locs_buffer, - locs_buffer_size / sizeof(relocInfo)); - code->initialize_consts_size(desired_max_constant_size()); - // Call stubs + deopt/exception handler - code->initialize_stubs_size((call_stub_estimate * LIR_Assembler::call_stub_size) + - LIR_Assembler::exception_handler_size + - LIR_Assembler::deopt_handler_size); -} - - -void Runtime1::generate_blob_for(StubID id) { +void Runtime1::generate_blob_for(BufferBlob* buffer_blob, StubID id) { assert(0 <= id && id < number_of_ids, "illegal stub id"); ResourceMark rm; // create code buffer for code storage - CodeBuffer code(get_buffer_blob()->instructions_begin(), - get_buffer_blob()->instructions_size()); + CodeBuffer code(buffer_blob->instructions_begin(), + buffer_blob->instructions_size()); - setup_code_buffer(&code, 0); + Compilation::setup_code_buffer(&code, 0); // create assembler for code generation StubAssembler* sasm = new StubAssembler(&code, name_for(id), id); @@ -204,35 +172,28 @@ } -void Runtime1::initialize() { - // Warning: If we have more than one compilation running in parallel, we - // need a lock here with the current setup (lazy initialization). - if (!is_initialized()) { - _is_initialized = true; - - // platform-dependent initialization - initialize_pd(); - // generate stubs - for (int id = 0; id < number_of_ids; id++) generate_blob_for((StubID)id); - // printing +void Runtime1::initialize(BufferBlob* blob) { + // platform-dependent initialization + initialize_pd(); + // generate stubs + for (int id = 0; id < number_of_ids; id++) generate_blob_for(blob, (StubID)id); + // printing #ifndef PRODUCT - if (PrintSimpleStubs) { - ResourceMark rm; - for (int id = 0; id < number_of_ids; id++) { - _blobs[id]->print(); - if (_blobs[id]->oop_maps() != NULL) { - _blobs[id]->oop_maps()->print(); - } + if (PrintSimpleStubs) { + ResourceMark rm; + for (int id = 0; id < number_of_ids; id++) { + _blobs[id]->print(); + if (_blobs[id]->oop_maps() != NULL) { + _blobs[id]->oop_maps()->print(); } } + } #endif - } } CodeBlob* Runtime1::blob_for(StubID id) { assert(0 <= id && id < number_of_ids, "illegal stub id"); - if (!is_initialized()) initialize(); return _blobs[id]; } diff -r c69846936352 -r e848dd13e1b6 src/share/vm/c1/c1_Runtime1.hpp --- a/src/share/vm/c1/c1_Runtime1.hpp Thu Jun 17 23:59:24 2010 -0700 +++ b/src/share/vm/c1/c1_Runtime1.hpp Fri Jun 18 00:09:22 2010 -0700 @@ -70,18 +70,6 @@ class Runtime1: public AllStatic { friend class VMStructs; friend class ArrayCopyStub; - private: - static int desired_max_code_buffer_size() { - return (int) NMethodSizeLimit; // default 256K or 512K - } - static int desired_max_constant_size() { - return (int) NMethodSizeLimit / 10; // about 25K - } - - // Note: This buffers is allocated once at startup since allocation - // for each compilation seems to be too expensive (at least on Intel - // win32). - static BufferBlob* _buffer_blob; public: enum StubID { @@ -115,12 +103,11 @@ #endif private: - static bool _is_initialized; static CodeBlob* _blobs[number_of_ids]; static const char* _blob_names[]; // stub generation - static void generate_blob_for(StubID id); + static void generate_blob_for(BufferBlob* blob, StubID id); static OopMapSet* generate_code_for(StubID id, StubAssembler* masm); static OopMapSet* generate_exception_throw(StubAssembler* sasm, address target, bool has_argument); static void generate_handle_exception(StubAssembler *sasm, OopMapSet* oop_maps, OopMap* oop_map, bool ignore_fpu_registers = false); @@ -162,12 +149,8 @@ static void patch_code(JavaThread* thread, StubID stub_id); public: - static BufferBlob* get_buffer_blob(); - static void setup_code_buffer(CodeBuffer* cb, int call_stub_estimate); - // initialization - static bool is_initialized() { return _is_initialized; } - static void initialize(); + static void initialize(BufferBlob* blob); static void initialize_pd(); // stubs diff -r c69846936352 -r e848dd13e1b6 src/share/vm/c1/c1_ValueStack.cpp --- a/src/share/vm/c1/c1_ValueStack.cpp Thu Jun 17 23:59:24 2010 -0700 +++ b/src/share/vm/c1/c1_ValueStack.cpp Fri Jun 18 00:09:22 2010 -0700 @@ -119,14 +119,14 @@ // apply function to all values of a list; factored out from values_do(f) -void ValueStack::apply(Values list, void f(Value*)) { +void ValueStack::apply(Values list, ValueVisitor* f) { for (int i = 0; i < list.length(); i++) { Value* va = list.adr_at(i); Value v0 = *va; if (v0 != NULL) { if (!v0->type()->is_illegal()) { assert(v0->as_HiWord() == NULL, "should never see HiWord during traversal"); - f(va); + f->visit(va); #ifdef ASSERT Value v1 = *va; if (v0 != v1) { @@ -143,7 +143,7 @@ } -void ValueStack::values_do(void f(Value*)) { +void ValueStack::values_do(ValueVisitor* f) { apply(_stack, f); apply(_locks, f); diff -r c69846936352 -r e848dd13e1b6 src/share/vm/c1/c1_ValueStack.hpp --- a/src/share/vm/c1/c1_ValueStack.hpp Thu Jun 17 23:59:24 2010 -0700 +++ b/src/share/vm/c1/c1_ValueStack.hpp Fri Jun 18 00:09:22 2010 -0700 @@ -41,7 +41,7 @@ } // helper routine - static void apply(Values list, void f(Value*)); + static void apply(Values list, ValueVisitor* f); public: // creation @@ -143,7 +143,7 @@ void pin_stack_for_linear_scan(); // iteration - void values_do(void f(Value*)); + void values_do(ValueVisitor* f); // untyped manipulation (for dup_x1, etc.) void clear_stack() { _stack.clear(); } diff -r c69846936352 -r e848dd13e1b6 src/share/vm/c1/c1_ValueType.cpp --- a/src/share/vm/c1/c1_ValueType.cpp Thu Jun 17 23:59:24 2010 -0700 +++ b/src/share/vm/c1/c1_ValueType.cpp Fri Jun 18 00:09:22 2010 -0700 @@ -46,27 +46,26 @@ ObjectConstant* objectNull = NULL; -void ValueType::initialize() { +void ValueType::initialize(Arena* arena) { // Note: Must initialize all types for each compilation // as they are allocated within a ResourceMark! // types - voidType = new VoidType(); - intType = new IntType(); - longType = new LongType(); - floatType = new FloatType(); - doubleType = new DoubleType(); - objectType = new ObjectType(); - arrayType = new ArrayType(); - instanceType = new InstanceType(); - classType = new ClassType(); - addressType = new AddressType(); - illegalType = new IllegalType(); + voidType = new (arena) VoidType(); + intType = new (arena) IntType(); + longType = new (arena) LongType(); + floatType = new (arena) FloatType(); + doubleType = new (arena) DoubleType(); + objectType = new (arena) ObjectType(); + arrayType = new (arena) ArrayType(); + instanceType = new (arena) InstanceType(); + classType = new (arena) ClassType(); + addressType = new (arena) AddressType(); + illegalType = new (arena) IllegalType(); - // constants - intZero = new IntConstant(0); - intOne = new IntConstant(1); - objectNull = new ObjectConstant(ciNullObject::make()); + intZero = new (arena) IntConstant(0); + intOne = new (arena) IntConstant(1); + objectNull = new (arena) ObjectConstant(ciNullObject::make()); }; diff -r c69846936352 -r e848dd13e1b6 src/share/vm/c1/c1_ValueType.hpp --- a/src/share/vm/c1/c1_ValueType.hpp Thu Jun 17 23:59:24 2010 -0700 +++ b/src/share/vm/c1/c1_ValueType.hpp Fri Jun 18 00:09:22 2010 -0700 @@ -94,7 +94,7 @@ public: // initialization - static void initialize(); + static void initialize(Arena* arena); // accessors virtual ValueType* base() const = 0; // the 'canonical' type (e.g., intType for an IntConstant) diff -r c69846936352 -r e848dd13e1b6 src/share/vm/classfile/classFileParser.cpp --- a/src/share/vm/classfile/classFileParser.cpp Thu Jun 17 23:59:24 2010 -0700 +++ b/src/share/vm/classfile/classFileParser.cpp Fri Jun 18 00:09:22 2010 -0700 @@ -25,10 +25,10 @@ #include "incls/_precompiled.incl" #include "incls/_classFileParser.cpp.incl" -// We generally try to create the oops directly when parsing, rather than allocating -// temporary data structures and copying the bytes twice. A temporary area is only -// needed when parsing utf8 entries in the constant pool and when parsing line number -// tables. +// We generally try to create the oops directly when parsing, rather than +// allocating temporary data structures and copying the bytes twice. A +// temporary area is only needed when parsing utf8 entries in the constant +// pool and when parsing line number tables. // We add assert in debug mode when class format is not checked. @@ -47,6 +47,10 @@ // - also used as the max version when running in jdk6 #define JAVA_6_VERSION 50 +// Used for backward compatibility reasons: +// - to check NameAndType_info signatures more aggressively +#define JAVA_7_VERSION 51 + void ClassFileParser::parse_constant_pool_entries(constantPoolHandle cp, int length, TRAPS) { // Use a local copy of ClassFileStream. It helps the C++ compiler to optimize @@ -384,6 +388,20 @@ verify_legal_class_name(class_name, CHECK_(nullHandle)); break; } + case JVM_CONSTANT_NameAndType: { + if (_need_verify && _major_version >= JAVA_7_VERSION) { + int sig_index = cp->signature_ref_index_at(index); + int name_index = cp->name_ref_index_at(index); + symbolHandle name(THREAD, cp->symbol_at(name_index)); + symbolHandle sig(THREAD, cp->symbol_at(sig_index)); + if (sig->byte_at(0) == JVM_SIGNATURE_FUNC) { + verify_legal_method_signature(name, sig, CHECK_(nullHandle)); + } else { + verify_legal_field_signature(name, sig, CHECK_(nullHandle)); + } + } + break; + } case JVM_CONSTANT_Fieldref: case JVM_CONSTANT_Methodref: case JVM_CONSTANT_InterfaceMethodref: { @@ -396,10 +414,28 @@ symbolHandle signature(THREAD, cp->symbol_at(signature_ref_index)); if (tag == JVM_CONSTANT_Fieldref) { verify_legal_field_name(name, CHECK_(nullHandle)); - verify_legal_field_signature(name, signature, CHECK_(nullHandle)); + if (_need_verify && _major_version >= JAVA_7_VERSION) { + // Signature is verified above, when iterating NameAndType_info. + // Need only to be sure it's the right type. + if (signature->byte_at(0) == JVM_SIGNATURE_FUNC) { + throwIllegalSignature( + "Field", name, signature, CHECK_(nullHandle)); + } + } else { + verify_legal_field_signature(name, signature, CHECK_(nullHandle)); + } } else { verify_legal_method_name(name, CHECK_(nullHandle)); - verify_legal_method_signature(name, signature, CHECK_(nullHandle)); + if (_need_verify && _major_version >= JAVA_7_VERSION) { + // Signature is verified above, when iterating NameAndType_info. + // Need only to be sure it's the right type. + if (signature->byte_at(0) != JVM_SIGNATURE_FUNC) { + throwIllegalSignature( + "Method", name, signature, CHECK_(nullHandle)); + } + } else { + verify_legal_method_signature(name, signature, CHECK_(nullHandle)); + } if (tag == JVM_CONSTANT_Methodref) { // 4509014: If a class method name begins with '<', it must be "". assert(!name.is_null(), "method name in constant pool is null"); @@ -1313,6 +1349,14 @@ return checked_exceptions_start; } +void ClassFileParser::throwIllegalSignature( + const char* type, symbolHandle name, symbolHandle sig, TRAPS) { + ResourceMark rm(THREAD); + Exceptions::fthrow(THREAD_AND_LOCATION, + vmSymbols::java_lang_ClassFormatError(), + "%s \"%s\" in class %s has illegal signature \"%s\"", type, + name->as_C_string(), _class_name->as_C_string(), sig->as_C_string()); +} #define MAX_ARGS_SIZE 255 #define MAX_CODE_SIZE 65535 @@ -4058,14 +4102,7 @@ char* p = skip_over_field_signature(bytes, false, length, CHECK); if (p == NULL || (p - bytes) != (int)length) { - ResourceMark rm(THREAD); - Exceptions::fthrow( - THREAD_AND_LOCATION, - vmSymbolHandles::java_lang_ClassFormatError(), - "Field \"%s\" in class %s has illegal signature \"%s\"", - name->as_C_string(), _class_name->as_C_string(), bytes - ); - return; + throwIllegalSignature("Field", name, signature, CHECK); } } @@ -4116,13 +4153,7 @@ } } // Report error - ResourceMark rm(THREAD); - Exceptions::fthrow( - THREAD_AND_LOCATION, - vmSymbolHandles::java_lang_ClassFormatError(), - "Method \"%s\" in class %s has illegal signature \"%s\"", - name->as_C_string(), _class_name->as_C_string(), p - ); + throwIllegalSignature("Method", name, signature, CHECK_0); return 0; } diff -r c69846936352 -r e848dd13e1b6 src/share/vm/classfile/classFileParser.hpp --- a/src/share/vm/classfile/classFileParser.hpp Thu Jun 17 23:59:24 2010 -0700 +++ b/src/share/vm/classfile/classFileParser.hpp Fri Jun 18 00:09:22 2010 -0700 @@ -195,6 +195,9 @@ if (!b) { classfile_parse_error(msg, index, name, CHECK); } } + void throwIllegalSignature( + const char* type, symbolHandle name, symbolHandle sig, TRAPS); + bool is_supported_version(u2 major, u2 minor); bool has_illegal_visibility(jint flags); diff -r c69846936352 -r e848dd13e1b6 src/share/vm/gc_implementation/g1/g1MMUTracker.cpp --- a/src/share/vm/gc_implementation/g1/g1MMUTracker.cpp Thu Jun 17 23:59:24 2010 -0700 +++ b/src/share/vm/gc_implementation/g1/g1MMUTracker.cpp Fri Jun 18 00:09:22 2010 -0700 @@ -81,20 +81,24 @@ remove_expired_entries(end); if (_no_entries == QueueLength) { - // OK, right now when we fill up we bomb out - // there are a few ways of dealing with this "gracefully" + // OK, we've filled up the queue. There are a few ways + // of dealing with this "gracefully" // increase the array size (:-) // remove the oldest entry (this might allow more GC time for - // the time slice than what's allowed) + // the time slice than what's allowed) - this is what we + // currently do // consolidate the two entries with the minimum gap between them // (this might allow less GC time than what's allowed) - guarantee(NOT_PRODUCT(ScavengeALot ||) G1UseFixedWindowMMUTracker, - "array full, currently we can't recover unless +G1UseFixedWindowMMUTracker"); + // In the case where ScavengeALot is true, such overflow is not // uncommon; in such cases, we can, without much loss of precision // or performance (we are GC'ing most of the time anyway!), - // simply overwrite the oldest entry in the tracker: this - // is also the behaviour when G1UseFixedWindowMMUTracker is enabled. + // simply overwrite the oldest entry in the tracker. + + if (G1PolicyVerbose > 1) { + warning("MMU Tracker Queue overflow. Replacing earliest entry."); + } + _head_index = trim_index(_head_index + 1); assert(_head_index == _tail_index, "Because we have a full circular buffer"); _tail_index = trim_index(_tail_index + 1); diff -r c69846936352 -r e848dd13e1b6 src/share/vm/gc_implementation/g1/g1_globals.hpp --- a/src/share/vm/gc_implementation/g1/g1_globals.hpp Thu Jun 17 23:59:24 2010 -0700 +++ b/src/share/vm/gc_implementation/g1/g1_globals.hpp Fri Jun 18 00:09:22 2010 -0700 @@ -254,9 +254,6 @@ "If non-0 is the size of the G1 survivor space, " \ "otherwise SurvivorRatio is used to determine the size") \ \ - product(bool, G1UseFixedWindowMMUTracker, false, \ - "If the MMU tracker's memory is full, forget the oldest entry") \ - \ product(uintx, G1HeapRegionSize, 0, \ "Size of the G1 regions.") \ \ diff -r c69846936352 -r e848dd13e1b6 src/share/vm/includeDB_compiler1 --- a/src/share/vm/includeDB_compiler1 Thu Jun 17 23:59:24 2010 -0700 +++ b/src/share/vm/includeDB_compiler1 Fri Jun 18 00:09:22 2010 -0700 @@ -71,8 +71,8 @@ c1_Compilation.cpp c1_MacroAssembler.hpp c1_Compilation.cpp c1_ValueMap.hpp c1_Compilation.cpp c1_ValueStack.hpp -c1_Compilation.cpp ciEnv.hpp c1_Compilation.cpp debugInfoRec.hpp +c1_Compilation.hpp ciEnv.hpp c1_Compilation.hpp exceptionHandlerTable.hpp c1_Compilation.hpp resourceArea.hpp @@ -82,6 +82,8 @@ c1_Compiler.cpp c1_Compilation.hpp c1_Compiler.cpp c1_Compiler.hpp c1_Compiler.cpp c1_FrameMap.hpp +c1_Compiler.cpp c1_GraphBuilder.hpp +c1_Compiler.cpp c1_LinearScan.hpp c1_Compiler.cpp c1_MacroAssembler.hpp c1_Compiler.cpp c1_Runtime1.hpp c1_Compiler.cpp c1_ValueType.hpp diff -r c69846936352 -r e848dd13e1b6 src/share/vm/opto/graphKit.cpp --- a/src/share/vm/opto/graphKit.cpp Thu Jun 17 23:59:24 2010 -0700 +++ b/src/share/vm/opto/graphKit.cpp Fri Jun 18 00:09:22 2010 -0700 @@ -3487,7 +3487,6 @@ Node* tls = __ thread(); // ThreadLocalStorage - Node* no_ctrl = NULL; Node* no_base = __ top(); float likely = PROB_LIKELY(0.999); float unlikely = PROB_UNLIKELY(0.999); @@ -3511,10 +3510,10 @@ Node* index_adr = __ AddP(no_base, tls, __ ConX(index_offset)); // Now some values - - Node* index = __ load(no_ctrl, index_adr, TypeInt::INT, T_INT, Compile::AliasIdxRaw); - Node* buffer = __ load(no_ctrl, buffer_adr, TypeRawPtr::NOTNULL, T_ADDRESS, Compile::AliasIdxRaw); - + // Use ctrl to avoid hoisting these values past a safepoint, which could + // potentially reset these fields in the JavaThread. + Node* index = __ load(__ ctrl(), index_adr, TypeInt::INT, T_INT, Compile::AliasIdxRaw); + Node* buffer = __ load(__ ctrl(), buffer_adr, TypeRawPtr::NOTNULL, T_ADDRESS, Compile::AliasIdxRaw); // Convert the store obj pointer to an int prior to doing math on it // Must use ctrl to prevent "integerized oop" existing across safepoint diff -r c69846936352 -r e848dd13e1b6 src/share/vm/opto/superword.cpp --- a/src/share/vm/opto/superword.cpp Thu Jun 17 23:59:24 2010 -0700 +++ b/src/share/vm/opto/superword.cpp Fri Jun 18 00:09:22 2010 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 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 @@ -514,6 +514,13 @@ bool SuperWord::are_adjacent_refs(Node* s1, Node* s2) { if (!s1->is_Mem() || !s2->is_Mem()) return false; if (!in_bb(s1) || !in_bb(s2)) return false; + + // Do not use superword for non-primitives + if (!is_java_primitive(s1->as_Mem()->memory_type()) || + !is_java_primitive(s2->as_Mem()->memory_type())) { + return false; + } + // FIXME - co_locate_pack fails on Stores in different mem-slices, so // only pack memops that are in the same alias set until that's fixed. if (_phase->C->get_alias_index(s1->as_Mem()->adr_type()) != diff -r c69846936352 -r e848dd13e1b6 src/share/vm/runtime/globals.hpp --- a/src/share/vm/runtime/globals.hpp Thu Jun 17 23:59:24 2010 -0700 +++ b/src/share/vm/runtime/globals.hpp Fri Jun 18 00:09:22 2010 -0700 @@ -923,6 +923,10 @@ \ product(intx, AlwaysInflate, 0, "(Unstable) Force inflation") \ \ + product(intx, MonitorBound, 0, "Bound Monitor population") \ + \ + product(bool, MonitorInUseLists, false, "Track Monitors for Deflation") \ + \ product(intx, Atomics, 0, \ "(Unsafe,Unstable) Diagnostic - Controls emission of atomics") \ \ diff -r c69846936352 -r e848dd13e1b6 src/share/vm/runtime/mutexLocker.cpp --- a/src/share/vm/runtime/mutexLocker.cpp Thu Jun 17 23:59:24 2010 -0700 +++ b/src/share/vm/runtime/mutexLocker.cpp Fri Jun 18 00:09:22 2010 -0700 @@ -82,9 +82,6 @@ Mutex* DerivedPointerTableGC_lock = NULL; Mutex* Compile_lock = NULL; Monitor* MethodCompileQueue_lock = NULL; -#ifdef TIERED -Monitor* C1_lock = NULL; -#endif // TIERED Monitor* CompileThread_lock = NULL; Mutex* CompileTaskAlloc_lock = NULL; Mutex* CompileStatistics_lock = NULL; @@ -255,11 +252,6 @@ def(Debug3_lock , Mutex , nonleaf+4, true ); def(ProfileVM_lock , Monitor, nonleaf+4, false); // used for profiling of the VMThread def(CompileThread_lock , Monitor, nonleaf+5, false ); -#ifdef TIERED - def(C1_lock , Monitor, nonleaf+5, false ); -#endif // TIERED - - } GCMutexLocker::GCMutexLocker(Monitor * mutex) { diff -r c69846936352 -r e848dd13e1b6 src/share/vm/runtime/mutexLocker.hpp --- a/src/share/vm/runtime/mutexLocker.hpp Thu Jun 17 23:59:24 2010 -0700 +++ b/src/share/vm/runtime/mutexLocker.hpp Fri Jun 18 00:09:22 2010 -0700 @@ -84,9 +84,6 @@ extern Mutex* EvacFailureStack_lock; // guards the evac failure scan stack extern Mutex* Compile_lock; // a lock held when Compilation is updating code (used to block CodeCache traversal, CHA updates, etc) extern Monitor* MethodCompileQueue_lock; // a lock held when method compilations are enqueued, dequeued -#ifdef TIERED -extern Monitor* C1_lock; // a lock to ensure on single c1 compile is ever active -#endif // TIERED extern Monitor* CompileThread_lock; // a lock held by compile threads during compilation system initialization extern Mutex* CompileTaskAlloc_lock; // a lock held when CompileTasks are allocated extern Mutex* CompileStatistics_lock; // a lock held when updating compilation statistics diff -r c69846936352 -r e848dd13e1b6 src/share/vm/runtime/synchronizer.cpp --- a/src/share/vm/runtime/synchronizer.cpp Thu Jun 17 23:59:24 2010 -0700 +++ b/src/share/vm/runtime/synchronizer.cpp Fri Jun 18 00:09:22 2010 -0700 @@ -185,6 +185,8 @@ } ; static SharedGlobals GVars ; +static int MonitorScavengeThreshold = 1000000 ; +static volatile int ForceMonitorScavenge = 0 ; // Scavenge required and pending // Tunables ... @@ -746,8 +748,85 @@ ObjectMonitor * ObjectSynchronizer::gBlockList = NULL ; ObjectMonitor * volatile ObjectSynchronizer::gFreeList = NULL ; static volatile intptr_t ListLock = 0 ; // protects global monitor free-list cache +static volatile int MonitorFreeCount = 0 ; // # on gFreeList +static volatile int MonitorPopulation = 0 ; // # Extant -- in circulation #define CHAINMARKER ((oop)-1) +// Constraining monitor pool growth via MonitorBound ... +// +// The monitor pool is grow-only. We scavenge at STW safepoint-time, but the +// the rate of scavenging is driven primarily by GC. As such, we can find +// an inordinate number of monitors in circulation. +// To avoid that scenario we can artificially induce a STW safepoint +// if the pool appears to be growing past some reasonable bound. +// Generally we favor time in space-time tradeoffs, but as there's no +// natural back-pressure on the # of extant monitors we need to impose some +// type of limit. Beware that if MonitorBound is set to too low a value +// we could just loop. In addition, if MonitorBound is set to a low value +// we'll incur more safepoints, which are harmful to performance. +// See also: GuaranteedSafepointInterval +// +// As noted elsewhere, the correct long-term solution is to deflate at +// monitorexit-time, in which case the number of inflated objects is bounded +// by the number of threads. That policy obviates the need for scavenging at +// STW safepoint time. As an aside, scavenging can be time-consuming when the +// # of extant monitors is large. Unfortunately there's a day-1 assumption baked +// into much HotSpot code that the object::monitor relationship, once established +// or observed, will remain stable except over potential safepoints. +// +// We can use either a blocking synchronous VM operation or an async VM operation. +// -- If we use a blocking VM operation : +// Calls to ScavengeCheck() should be inserted only into 'safe' locations in paths +// that lead to ::inflate() or ::omAlloc(). +// Even though the safepoint will not directly induce GC, a GC might +// piggyback on the safepoint operation, so the caller should hold no naked oops. +// Furthermore, monitor::object relationships are NOT necessarily stable over this call +// unless the caller has made provisions to "pin" the object to the monitor, say +// by incrementing the monitor's _count field. +// -- If we use a non-blocking asynchronous VM operation : +// the constraints above don't apply. The safepoint will fire in the future +// at a more convenient time. On the other hand the latency between posting and +// running the safepoint introduces or admits "slop" or laxity during which the +// monitor population can climb further above the threshold. The monitor population, +// however, tends to converge asymptotically over time to a count that's slightly +// above the target value specified by MonitorBound. That is, we avoid unbounded +// growth, albeit with some imprecision. +// +// The current implementation uses asynchronous VM operations. +// +// Ideally we'd check if (MonitorPopulation > MonitorBound) in omAlloc() +// immediately before trying to grow the global list via allocation. +// If the predicate was true then we'd induce a synchronous safepoint, wait +// for the safepoint to complete, and then again to allocate from the global +// free list. This approach is much simpler and precise, admitting no "slop". +// Unfortunately we can't safely safepoint in the midst of omAlloc(), so +// instead we use asynchronous safepoints. + +static void InduceScavenge (Thread * Self, const char * Whence) { + // Induce STW safepoint to trim monitors + // Ultimately, this results in a call to deflate_idle_monitors() in the near future. + // More precisely, trigger an asynchronous STW safepoint as the number + // of active monitors passes the specified threshold. + // TODO: assert thread state is reasonable + + if (ForceMonitorScavenge == 0 && Atomic::xchg (1, &ForceMonitorScavenge) == 0) { + if (Knob_Verbose) { + ::printf ("Monitor scavenge - Induced STW @%s (%d)\n", Whence, ForceMonitorScavenge) ; + ::fflush(stdout) ; + } + // Induce a 'null' safepoint to scavenge monitors + // Must VM_Operation instance be heap allocated as the op will be enqueue and posted + // to the VMthread and have a lifespan longer than that of this activation record. + // The VMThread will delete the op when completed. + VMThread::execute (new VM_ForceAsyncSafepoint()) ; + + if (Knob_Verbose) { + ::printf ("Monitor scavenge - STW posted @%s (%d)\n", Whence, ForceMonitorScavenge) ; + ::fflush(stdout) ; + } + } +} + ObjectMonitor * ATTR ObjectSynchronizer::omAlloc (Thread * Self) { // A large MAXPRIVATE value reduces both list lock contention // and list coherency traffic, but also tends to increase the @@ -770,6 +849,11 @@ Self->omFreeCount -- ; // CONSIDER: set m->FreeNext = BAD -- diagnostic hygiene guarantee (m->object() == NULL, "invariant") ; + if (MonitorInUseLists) { + m->FreeNext = Self->omInUseList; + Self->omInUseList = m; + Self->omInUseCount ++; + } return m ; } @@ -784,6 +868,7 @@ // on various locks. Thread::muxAcquire (&ListLock, "omAlloc") ; for (int i = Self->omFreeProvision; --i >= 0 && gFreeList != NULL; ) { + MonitorFreeCount --; ObjectMonitor * take = gFreeList ; gFreeList = take->FreeNext ; guarantee (take->object() == NULL, "invariant") ; @@ -796,6 +881,15 @@ if (Self->omFreeProvision > MAXPRIVATE ) Self->omFreeProvision = MAXPRIVATE ; TEVENT (omFirst - reprovision) ; continue ; + + const int mx = MonitorBound ; + if (mx > 0 && (MonitorPopulation-MonitorFreeCount) > mx) { + // We can't safely induce a STW safepoint from omAlloc() as our thread + // state may not be appropriate for such activities and callers may hold + // naked oops, so instead we defer the action. + InduceScavenge (Self, "omAlloc") ; + } + continue; } // 3: allocate a block of new ObjectMonitors @@ -836,6 +930,8 @@ // Acquire the ListLock to manipulate BlockList and FreeList. // An Oyama-Taura-Yonezawa scheme might be more efficient. Thread::muxAcquire (&ListLock, "omAlloc [2]") ; + MonitorPopulation += _BLOCKSIZE-1; + MonitorFreeCount += _BLOCKSIZE-1; // Add the new block to the list of extant blocks (gBlockList). // The very first objectMonitor in a block is reserved and dedicated. @@ -894,7 +990,9 @@ if (List == NULL) return ; ObjectMonitor * Tail = NULL ; ObjectMonitor * s ; + int Tally = 0; for (s = List ; s != NULL ; s = s->FreeNext) { + Tally ++ ; Tail = s ; guarantee (s->object() == NULL, "invariant") ; guarantee (!s->is_busy(), "invariant") ; @@ -906,6 +1004,7 @@ Thread::muxAcquire (&ListLock, "omFlush") ; Tail->FreeNext = gFreeList ; gFreeList = List ; + MonitorFreeCount += Tally; Thread::muxRelease (&ListLock) ; TEVENT (omFlush) ; } @@ -1747,16 +1846,15 @@ // Having a large number of monitors in-circulation negatively // impacts the performance of some applications (e.g., PointBase). // Broadly, we want to minimize the # of monitors in circulation. -// Alternately, we could partition the active monitors into sub-lists -// of those that need scanning and those that do not. -// Specifically, we would add a new sub-list of objectmonitors -// that are in-circulation and potentially active. deflate_idle_monitors() -// would scan only that list. Other monitors could reside on a quiescent -// list. Such sequestered monitors wouldn't need to be scanned by -// deflate_idle_monitors(). omAlloc() would first check the global free list, -// then the quiescent list, and, failing those, would allocate a new block. -// Deflate_idle_monitors() would scavenge and move monitors to the -// quiescent list. +// +// We have added a flag, MonitorInUseLists, which creates a list +// of active monitors for each thread. deflate_idle_monitors() +// only scans the per-thread inuse lists. omAlloc() puts all +// assigned monitors on the per-thread list. deflate_idle_monitors() +// returns the non-busy monitors to the global free list. +// An alternative could have used a single global inuse list. The +// downside would have been the additional cost of acquiring the global list lock +// for every omAlloc(). // // Perversely, the heap size -- and thus the STW safepoint rate -- // typically drives the scavenge rate. Large heaps can mean infrequent GC, @@ -1769,18 +1867,100 @@ // An even better solution would be to deflate on-the-fly, aggressively, // at monitorexit-time as is done in EVM's metalock or Relaxed Locks. + +// Deflate a single monitor if not in use +// Return true if deflated, false if in use +bool ObjectSynchronizer::deflate_monitor(ObjectMonitor* mid, oop obj, + ObjectMonitor** FreeHeadp, ObjectMonitor** FreeTailp) { + bool deflated; + // Normal case ... The monitor is associated with obj. + guarantee (obj->mark() == markOopDesc::encode(mid), "invariant") ; + guarantee (mid == obj->mark()->monitor(), "invariant"); + guarantee (mid->header()->is_neutral(), "invariant"); + + if (mid->is_busy()) { + if (ClearResponsibleAtSTW) mid->_Responsible = NULL ; + deflated = false; + } else { + // Deflate the monitor if it is no longer being used + // It's idle - scavenge and return to the global free list + // plain old deflation ... + TEVENT (deflate_idle_monitors - scavenge1) ; + if (TraceMonitorInflation) { + if (obj->is_instance()) { + ResourceMark rm; + tty->print_cr("Deflating object " INTPTR_FORMAT " , mark " INTPTR_FORMAT " , type %s", + (intptr_t) obj, (intptr_t) obj->mark(), Klass::cast(obj->klass())->external_name()); + } + } + + // Restore the header back to obj + obj->release_set_mark(mid->header()); + mid->clear(); + + assert (mid->object() == NULL, "invariant") ; + + // Move the object to the working free list defined by FreeHead,FreeTail. + if (*FreeHeadp == NULL) *FreeHeadp = mid; + if (*FreeTailp != NULL) { + ObjectMonitor * prevtail = *FreeTailp; + prevtail->FreeNext = mid; + } + *FreeTailp = mid; + deflated = true; + } + return deflated; +} + void ObjectSynchronizer::deflate_idle_monitors() { assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint"); int nInuse = 0 ; // currently associated with objects int nInCirculation = 0 ; // extant int nScavenged = 0 ; // reclaimed + bool deflated = false; ObjectMonitor * FreeHead = NULL ; // Local SLL of scavenged monitors ObjectMonitor * FreeTail = NULL ; + TEVENT (deflate_idle_monitors) ; + // Prevent omFlush from changing mids in Thread dtor's during deflation + // And in case the vm thread is acquiring a lock during a safepoint + // See e.g. 6320749 + Thread::muxAcquire (&ListLock, "scavenge - return") ; + + if (MonitorInUseLists) { + ObjectMonitor* mid; + ObjectMonitor* next; + ObjectMonitor* curmidinuse; + for (JavaThread* cur = Threads::first(); cur != NULL; cur = cur->next()) { + curmidinuse = NULL; + for (mid = cur->omInUseList; mid != NULL; ) { + oop obj = (oop) mid->object(); + deflated = false; + if (obj != NULL) { + deflated = deflate_monitor(mid, obj, &FreeHead, &FreeTail); + } + if (deflated) { + // extract from per-thread in-use-list + if (mid == cur->omInUseList) { + cur->omInUseList = mid->FreeNext; + } else if (curmidinuse != NULL) { + curmidinuse->FreeNext = mid->FreeNext; // maintain the current thread inuselist + } + next = mid->FreeNext; + mid->FreeNext = NULL; // This mid is current tail in the FreeHead list + mid = next; + cur->omInUseCount--; + nScavenged ++ ; + } else { + curmidinuse = mid; + mid = mid->FreeNext; + nInuse ++; + } + } + } + } else for (ObjectMonitor* block = gBlockList; block != NULL; block = next(block)) { // Iterate over all extant monitors - Scavenge all idle monitors. - TEVENT (deflate_idle_monitors) ; - for (ObjectMonitor* block = gBlockList; block != NULL; block = next(block)) { assert(block->object() == CHAINMARKER, "must be a block header"); nInCirculation += _BLOCKSIZE ; for (int i = 1 ; i < _BLOCKSIZE; i++) { @@ -1795,61 +1975,39 @@ guarantee (!mid->is_busy(), "invariant") ; continue ; } - - // Normal case ... The monitor is associated with obj. - guarantee (obj->mark() == markOopDesc::encode(mid), "invariant") ; - guarantee (mid == obj->mark()->monitor(), "invariant"); - guarantee (mid->header()->is_neutral(), "invariant"); - - if (mid->is_busy()) { - if (ClearResponsibleAtSTW) mid->_Responsible = NULL ; - nInuse ++ ; + deflated = deflate_monitor(mid, obj, &FreeHead, &FreeTail); + + if (deflated) { + mid->FreeNext = NULL ; + nScavenged ++ ; } else { - // Deflate the monitor if it is no longer being used - // It's idle - scavenge and return to the global free list - // plain old deflation ... - TEVENT (deflate_idle_monitors - scavenge1) ; - if (TraceMonitorInflation) { - if (obj->is_instance()) { - ResourceMark rm; - tty->print_cr("Deflating object " INTPTR_FORMAT " , mark " INTPTR_FORMAT " , type %s", - (intptr_t) obj, (intptr_t) obj->mark(), Klass::cast(obj->klass())->external_name()); - } - } - - // Restore the header back to obj - obj->release_set_mark(mid->header()); - mid->clear(); - - assert (mid->object() == NULL, "invariant") ; - - // Move the object to the working free list defined by FreeHead,FreeTail. - mid->FreeNext = NULL ; - if (FreeHead == NULL) FreeHead = mid ; - if (FreeTail != NULL) FreeTail->FreeNext = mid ; - FreeTail = mid ; - nScavenged ++ ; + nInuse ++; } } } + MonitorFreeCount += nScavenged; + + // Consider: audit gFreeList to ensure that MonitorFreeCount and list agree. + + if (Knob_Verbose) { + ::printf ("Deflate: InCirc=%d InUse=%d Scavenged=%d ForceMonitorScavenge=%d : pop=%d free=%d\n", + nInCirculation, nInuse, nScavenged, ForceMonitorScavenge, + MonitorPopulation, MonitorFreeCount) ; + ::fflush(stdout) ; + } + + ForceMonitorScavenge = 0; // Reset + // Move the scavenged monitors back to the global free list. - // In theory we don't need the freelist lock as we're at a STW safepoint. - // omAlloc() and omFree() can only be called while a thread is _not in safepoint state. - // But it's remotely possible that omFlush() or release_monitors_owned_by_thread() - // might be called while not at a global STW safepoint. In the interest of - // safety we protect the following access with ListLock. - // An even more conservative and prudent approach would be to guard - // the main loop in scavenge_idle_monitors() with ListLock. if (FreeHead != NULL) { guarantee (FreeTail != NULL && nScavenged > 0, "invariant") ; assert (FreeTail->FreeNext == NULL, "invariant") ; // constant-time list splice - prepend scavenged segment to gFreeList - Thread::muxAcquire (&ListLock, "scavenge - return") ; FreeTail->FreeNext = gFreeList ; gFreeList = FreeHead ; - Thread::muxRelease (&ListLock) ; } + Thread::muxRelease (&ListLock) ; if (_sync_Deflations != NULL) _sync_Deflations->inc(nScavenged) ; if (_sync_MonExtant != NULL) _sync_MonExtant ->set_value(nInCirculation); diff -r c69846936352 -r e848dd13e1b6 src/share/vm/runtime/synchronizer.hpp --- a/src/share/vm/runtime/synchronizer.hpp Thu Jun 17 23:59:24 2010 -0700 +++ b/src/share/vm/runtime/synchronizer.hpp Fri Jun 18 00:09:22 2010 -0700 @@ -150,6 +150,8 @@ // Basically we deflate all monitors that are not busy. // An adaptive profile-based deflation policy could be used if needed static void deflate_idle_monitors(); + static bool deflate_monitor(ObjectMonitor* mid, oop obj, ObjectMonitor** FreeHeadp, + ObjectMonitor** FreeTailp); static void oops_do(OopClosure* f); // debugging diff -r c69846936352 -r e848dd13e1b6 src/share/vm/runtime/thread.cpp --- a/src/share/vm/runtime/thread.cpp Thu Jun 17 23:59:24 2010 -0700 +++ b/src/share/vm/runtime/thread.cpp Fri Jun 18 00:09:22 2010 -0700 @@ -139,6 +139,8 @@ omFreeList = NULL ; omFreeCount = 0 ; omFreeProvision = 32 ; + omInUseList = NULL ; + omInUseCount = 0 ; _SR_lock = new Monitor(Mutex::suspend_resume, "SR_lock", true); _suspend_flags = 0; @@ -2797,6 +2799,7 @@ _task = NULL; _queue = queue; _counters = counters; + _buffer_blob = NULL; #ifndef PRODUCT _ideal_graph_printer = NULL; diff -r c69846936352 -r e848dd13e1b6 src/share/vm/runtime/thread.hpp --- a/src/share/vm/runtime/thread.hpp Thu Jun 17 23:59:24 2010 -0700 +++ b/src/share/vm/runtime/thread.hpp Fri Jun 18 00:09:22 2010 -0700 @@ -225,6 +225,8 @@ ObjectMonitor * omFreeList ; int omFreeCount ; // length of omFreeList int omFreeProvision ; // reload chunk size + ObjectMonitor * omInUseList; // SLL to track monitors in circulation + int omInUseCount; // length of omInUseList public: enum { @@ -493,7 +495,6 @@ static ByteSize stack_base_offset() { return byte_offset_of(Thread, _stack_base ); } static ByteSize stack_size_offset() { return byte_offset_of(Thread, _stack_size ); } - static ByteSize omFreeList_offset() { return byte_offset_of(Thread, omFreeList); } #define TLAB_FIELD_OFFSET(name) \ static ByteSize tlab_##name##_offset() { return byte_offset_of(Thread, _tlab) + ThreadLocalAllocBuffer::name##_offset(); } @@ -1576,6 +1577,7 @@ CompileLog* _log; CompileTask* _task; CompileQueue* _queue; + BufferBlob* _buffer_blob; public: @@ -1594,6 +1596,9 @@ ciEnv* env() { return _env; } void set_env(ciEnv* env) { _env = env; } + BufferBlob* get_buffer_blob() { return _buffer_blob; } + void set_buffer_blob(BufferBlob* b) { _buffer_blob = b; }; + // Get/set the thread's logging information CompileLog* log() { return _log; } void init_log(CompileLog* log) { diff -r c69846936352 -r e848dd13e1b6 test/compiler/6958485/Test.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/6958485/Test.java Fri Jun 18 00:09:22 2010 -0700 @@ -0,0 +1,53 @@ +/* + * Copyright (c) 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. + */ + +/** + * @test + * @bug 6958485 + * @summary fix for 6879921 was insufficient + * + * @run main/othervm -Xbatch -XX:CompileOnly=Test.init Test + */ + +public class Test { + + public static void init(Object src[], boolean[] dst) { + // initialize the arrays + for (int i =0; i