Mercurial > hg > icedtea9
changeset 1672:845ca3703fa0
2009-02-26 Gary Benson <gbenson@redhat.com>
* ports/hotspot/src/share/vm/shark/sharkBlock.cpp
(SharkBlock::do_field_access): Add optional field parameter.
(SharkBlock::get_call_type): New method.
(SharkBlock::get_callee): Likewise.
(SharkBlock::maybe_inline_call): Likewise.
(SharkBlock::maybe_inline_accessor): Likewise.
(SharkBlock::do_call): Separate call type detection from
callee fetch code, and attempt to inline inbetween.
* ports/hotspot/src/share/vm/shark/sharkBlock.hpp
(SharkBlock::do_field_access): Add optional field parameter.
(SharkBlock::CallType): New enum.
(SharkBlock::get_call_type): New method.
(SharkBlock::get_callee): Likewise.
(SharkBlock::maybe_inline_call): Likewise.
(SharkBlock::maybe_inline_accessor): Likewise.
* ports/hotspot/src/share/vm/shark/sharkState.cpp
(SharkTrackingState::enter_inlined_section): New method.
(SharkTrackingState::leave_inlined_section): Likewise.
* ports/hotspot/src/share/vm/shark/sharkState.hpp
(SharkTrackingState::_has_stack_frame): New field.
(SharkTrackingState::has_stack_frame): New method.
(SharkTrackingState::set_has_stack_frame): Likewise.
(SharkTrackingState::enter_inlined_section): Likewise.
(SharkTrackingState::leave_inlined_section): Likewise.
* ports/hotspot/src/share/vm/shark/sharkState.inline.hpp
(SharkTrackingState::decache_for_Java_call): Check we have a frame.
(SharkTrackingState::cache_after_Java_call): Likewise.
(SharkTrackingState::decache_for_VM_call): Likewise.
(SharkTrackingState::cache_after_VM_call): Likewise.
(SharkTrackingState::decache_for_trap): Likewise.
(transplanted from 5737c17b493dd8d38cd72db223d6de9415837081)
author | Gary Benson <gbenson@redhat.com> |
---|---|
date | Thu, 26 Feb 2009 12:20:11 +0000 |
parents | a7448ed41188 |
children | 9743a1ba5780 |
files | ChangeLog ports/hotspot/src/share/vm/shark/sharkBlock.cpp ports/hotspot/src/share/vm/shark/sharkBlock.hpp ports/hotspot/src/share/vm/shark/sharkState.cpp ports/hotspot/src/share/vm/shark/sharkState.hpp ports/hotspot/src/share/vm/shark/sharkState.inline.hpp |
diffstat | 6 files changed, 279 insertions(+), 18 deletions(-) [+] |
line wrap: on
line diff
--- a/ChangeLog Wed Feb 25 16:38:54 2009 -0500 +++ b/ChangeLog Thu Feb 26 12:20:11 2009 +0000 @@ -69,6 +69,39 @@ * patches/hotspot/original/icedtea-includedb.patch, * patches/icedtea-libraries.patch: Recreated. +2009-02-26 Gary Benson <gbenson@redhat.com> + + * ports/hotspot/src/share/vm/shark/sharkBlock.cpp + (SharkBlock::do_field_access): Add optional field parameter. + (SharkBlock::get_call_type): New method. + (SharkBlock::get_callee): Likewise. + (SharkBlock::maybe_inline_call): Likewise. + (SharkBlock::maybe_inline_accessor): Likewise. + (SharkBlock::do_call): Separate call type detection from + callee fetch code, and attempt to inline inbetween. + * ports/hotspot/src/share/vm/shark/sharkBlock.hpp + (SharkBlock::do_field_access): Add optional field parameter. + (SharkBlock::CallType): New enum. + (SharkBlock::get_call_type): New method. + (SharkBlock::get_callee): Likewise. + (SharkBlock::maybe_inline_call): Likewise. + (SharkBlock::maybe_inline_accessor): Likewise. + * ports/hotspot/src/share/vm/shark/sharkState.cpp + (SharkTrackingState::enter_inlined_section): New method. + (SharkTrackingState::leave_inlined_section): Likewise. + * ports/hotspot/src/share/vm/shark/sharkState.hpp + (SharkTrackingState::_has_stack_frame): New field. + (SharkTrackingState::has_stack_frame): New method. + (SharkTrackingState::set_has_stack_frame): Likewise. + (SharkTrackingState::enter_inlined_section): Likewise. + (SharkTrackingState::leave_inlined_section): Likewise. + * ports/hotspot/src/share/vm/shark/sharkState.inline.hpp + (SharkTrackingState::decache_for_Java_call): Check we have a frame. + (SharkTrackingState::cache_after_Java_call): Likewise. + (SharkTrackingState::decache_for_VM_call): Likewise. + (SharkTrackingState::cache_after_VM_call): Likewise. + (SharkTrackingState::decache_for_trap): Likewise. + 2009-02-25 Deepak Bhole <dbhole@redhat.com> * IcedTeaPlugin.cc: Implement Show/Hide from IJVMConsole, remove @@ -99,7 +132,6 @@ (SharkBlock::get_interface_callee): Removed cache parameter. (SharkBlock::get_callee): Removed. (SharkBlock::do_call): Perform caller selection inline. - * ports/hotspot/src/share/vm/shark/sharkBlock.hpp (SharkBlock::get_basic_callee): Removed. (SharkBlock::get_direct_callee): New method.
--- a/ports/hotspot/src/share/vm/shark/sharkBlock.cpp Wed Feb 25 16:38:54 2009 -0500 +++ b/ports/hotspot/src/share/vm/shark/sharkBlock.cpp Thu Feb 26 12:20:11 2009 +0000 @@ -1485,15 +1485,17 @@ push(SharkValue::create_jint(result)); } -void SharkBlock::do_field_access(bool is_get, bool is_field) +void SharkBlock::do_field_access(bool is_get, bool is_field, ciField* field) { - bool will_link; - ciField *field = iter()->get_field(will_link); - assert(will_link, "typeflow responsibility"); + if (field == NULL) { + bool will_link; + field = iter()->get_field(will_link); + assert(will_link, "typeflow responsibility"); - // Check the bytecode matches the field - if (is_field == field->is_static()) - Unimplemented(); + // Check the bytecode matches the field + if (is_field == field->is_static()) + Unimplemented(); + } // Pop the value off the stack where necessary SharkValue *value = NULL; @@ -1726,6 +1728,36 @@ } } +// Figure out what type of call this is. +// - Direct calls are where the callee is fixed. +// - Interface and Virtual calls require lookup at runtime. +// NB some invokevirtuals can be resolved to direct calls. +SharkBlock::CallType SharkBlock::get_call_type(ciMethod* method) +{ + if (bc() == Bytecodes::_invokeinterface) + return CALL_INTERFACE; + else if (bc() == Bytecodes::_invokevirtual && !method->is_final_method()) + return CALL_VIRTUAL; + else + return CALL_DIRECT; +} + +Value *SharkBlock::get_callee(CallType call_type, + ciMethod* method, + SharkValue* receiver) +{ + switch (call_type) { + case CALL_DIRECT: + return get_direct_callee(method); + case CALL_VIRTUAL: + return get_virtual_callee(receiver, method); + case CALL_INTERFACE: + return get_interface_callee(receiver); + default: + ShouldNotReachHere(); + } +} + // Direct calls can be made when the callee is fixed. // invokestatic and invokespecial are always direct; // invokevirtual is direct in some circumstances. @@ -1995,33 +2027,174 @@ return callee; } +bool SharkBlock::maybe_inline_call(ciMethod *method) +{ + // Quick checks to allow us to bail out fast. We can't inline + // native methods, there's no point inlining abstract ones, and + // monitors aren't allowed because the inlined section has no + // frame to put them in. + if (method->is_native() || + method->is_abstract() || + method->is_synchronized() || + method->has_monitor_bytecodes()) + return false; + + // We need to scan the bytecode to do any more, so we bail out + // now if the method is too big + if (method->code_size() > 5) + return false; + + // Inspect the method's code to see if we can inline it. We + // don't use method->is_accessor() because that only spots + // some getfields, whereas we can inline *all* getfields, all + // putfields, and some getstatics too. + address code = method->code(); + switch (method->code_size()) { + case 4: + // getstatic and putstatic will try to look up the receiver + // from the holder's constant pool, which we can't do. Some + // getstatics, however, resolve to constants, and those we + // can do. So we try... + if (code[0] == Bytecodes::_getstatic) + return maybe_inline_accessor(method, false); + break; + + case 5: + if (code[0] == Bytecodes::_aload_0 && + (code[1] == Bytecodes::_getfield || + code[1] == Bytecodes::_putfield)) + return maybe_inline_accessor(method, true); + break; + } + return false; +} + +bool SharkBlock::maybe_inline_accessor(ciMethod *method, bool is_field) +{ + if (method->arg_size() != (is_field ? 1 : 0)) { + NOT_PRODUCT(warning("wacky accessor in %s", function()->name())); + return false; + } + + ciBytecodeStream iter(method); + Bytecodes::Code bc; + + if (is_field) { + bc = iter.next(); + assert(bc == Bytecodes::_aload_0, "eh?"); + } + + bool is_get; + bc = iter.next(); + if (is_field) { + assert(bc == Bytecodes::_getfield || bc == Bytecodes::_putfield, "eh?"); + is_get = bc == Bytecodes::_getfield; + } + else { + assert(bc == Bytecodes::_getstatic, "eh?"); + is_get = true; + } + + bool will_link; + ciField *field = iter.get_field(will_link); + if (!will_link) + return false; + + // We can only inline getstatic if the field resolves to a + // non-oop constant. + if (!is_field) { + if (!field->is_constant()) + return false; + + if (SharkValue::from_ciConstant(field->constant_value()) == NULL) + return false; + } + + // We mustn't inline if the resolved field is the wrong type, + // because the thrown exception would appear to come from the + // wrong method. + if (is_field == field->is_static()) + return false; + + bc = iter.next(); + if (is_get) { + switch (bc) { + case Bytecodes::_ireturn: + case Bytecodes::_lreturn: + case Bytecodes::_freturn: + case Bytecodes::_dreturn: + case Bytecodes::_areturn: + break; + + default: + NOT_PRODUCT(warning("wacky accessor in %s", function()->name())); + return false; + } + } + else { + if (bc != Bytecodes::_return) { + NOT_PRODUCT(warning("wacky accessor in %s", function()->name())); + return false; + } + } + + bc = iter.next(); + assert(bc == ciBytecodeStream::EOBC(), "eh?"); + + // For field accesses we need to null check the receiver before + // entering the inlined section. For the majority of accessors + // this has already been done (in do_call) but if the accessor + // was invoked by invokestatic (eg synthetic accessors) then it + // won't have been checked and do_field_access will try to do + // it and fail. So we check here, which is moderately wrong in + // that the NullPointerException will have been thrown by the + // caller rather than the callee. + if (is_field) + check_null(xstack(0)); + + current_state()->enter_inlined_section(); + do_field_access(is_get, is_field, field); + current_state()->leave_inlined_section(); + return true; +} + void SharkBlock::do_call() { bool will_link; ciMethod *method = iter()->get_method(will_link); assert(will_link, "typeflow responsibility"); - // Find the receiver in the stack + // Figure out what type of call this is + CallType call_type = get_call_type(method); + + // Find the receiver in the stack. This has to happen + // before we try to inline, because nothing in the inlined + // code can decache (which check_null needs to do for the + // VM call to throw the NullPointerException). Once we've + // checked, the repeated null check elimination stuff does + // the work for us. SharkValue *receiver = NULL; if (bc() != Bytecodes::_invokestatic) { receiver = xstack(method->arg_size() - 1); check_null(receiver); } + // Try to inline the call + if (call_type == CALL_DIRECT) { + if (maybe_inline_call(method)) + return; + } + // Find the method we are calling - Value *callee; - if (bc() == Bytecodes::_invokeinterface) - callee = get_interface_callee(receiver); - else if (bc() == Bytecodes::_invokevirtual && !method->is_final_method()) - callee = get_virtual_callee(receiver, method); - else - callee = get_direct_callee(method); + Value *callee = get_callee(call_type, method, receiver); + // Load the SharkEntry from the callee Value *base_pc = builder()->CreateValueOfStructEntry( callee, methodOopDesc::from_interpreted_offset(), SharkType::intptr_type(), "base_pc"); + // Load the entry point from the SharkEntry Value *entry_point = builder()->CreateLoad( builder()->CreateIntToPtr( builder()->CreateAdd(
--- a/ports/hotspot/src/share/vm/shark/sharkBlock.hpp Wed Feb 25 16:38:54 2009 -0500 +++ b/ports/hotspot/src/share/vm/shark/sharkBlock.hpp Thu Feb 26 12:20:11 2009 +0000 @@ -457,7 +457,7 @@ { do_field_access(false, true); } - void do_field_access(bool is_get, bool is_field); + void do_field_access(bool is_get, bool is_field, ciField* field = NULL); // lcmp and [fd]cmp[lg] private: @@ -493,12 +493,25 @@ // invoke* private: + enum CallType { + CALL_DIRECT, + CALL_VIRTUAL, + CALL_INTERFACE + }; + CallType get_call_type(ciMethod* method); + llvm::Value* get_callee(CallType call_type, + ciMethod* method, + SharkValue* receiver); + llvm::Value* get_direct_callee(ciMethod* method); llvm::Value* get_virtual_callee(SharkValue* receiver, ciMethod* method); llvm::Value* get_virtual_callee(llvm::Value* cache, SharkValue* receiver); llvm::Value* get_interface_callee(SharkValue* receiver); + bool maybe_inline_call(ciMethod* method); + bool maybe_inline_accessor(ciMethod* method, bool is_field); + void do_call(); // checkcast and instanceof
--- a/ports/hotspot/src/share/vm/shark/sharkState.cpp Wed Feb 25 16:38:54 2009 -0500 +++ b/ports/hotspot/src/share/vm/shark/sharkState.cpp Thu Feb 26 12:20:11 2009 +0000 @@ -262,3 +262,17 @@ set_stack(i, SharkValue::create_generic(this_type, phi)); } } + +#ifndef PRODUCT +void SharkTrackingState::enter_inlined_section() +{ + assert(has_stack_frame(), "should do"); + set_has_stack_frame(false); +} + +void SharkTrackingState::leave_inlined_section() +{ + assert(!has_stack_frame(), "shouldn't do"); + set_has_stack_frame(true); +} +#endif // PRODUCT
--- a/ports/hotspot/src/share/vm/shark/sharkState.hpp Wed Feb 25 16:38:54 2009 -0500 +++ b/ports/hotspot/src/share/vm/shark/sharkState.hpp Thu Feb 26 12:20:11 2009 +0000 @@ -153,7 +153,11 @@ class SharkTrackingState : public SharkState { public: SharkTrackingState(const SharkState* state) - : SharkState(state) { set_method(state->method()); } + : SharkState(state) + { + set_method(state->method()); + NOT_PRODUCT(set_has_stack_frame(true)); + } // Cache and decache public: @@ -172,4 +176,24 @@ void merge(SharkState* other, llvm::BasicBlock* other_block, llvm::BasicBlock* this_block); + + // Inlining +#ifndef PRODUCT + private: + bool _has_stack_frame; + + protected: + bool has_stack_frame() const + { + return _has_stack_frame; + } + void set_has_stack_frame(bool has_stack_frame) + { + _has_stack_frame = has_stack_frame; + } +#endif // PRODUCT + + public: + void enter_inlined_section() PRODUCT_RETURN; + void leave_inlined_section() PRODUCT_RETURN; };
--- a/ports/hotspot/src/share/vm/shark/sharkState.inline.hpp Wed Feb 25 16:38:54 2009 -0500 +++ b/ports/hotspot/src/share/vm/shark/sharkState.inline.hpp Thu Feb 26 12:20:11 2009 +0000 @@ -50,12 +50,14 @@ inline void SharkTrackingState::decache_for_Java_call(ciMethod* callee) { + assert(has_stack_frame(), "should do"); SharkJavaCallDecacher(function(), block()->bci(), callee).scan(this); pop(callee->arg_size()); } inline void SharkTrackingState::cache_after_Java_call(ciMethod* callee) { + assert(has_stack_frame(), "should do"); if (callee->return_type()->size()) { ciType *type; switch (callee->return_type()->basic_type()) { @@ -79,15 +81,18 @@ inline void SharkTrackingState::decache_for_VM_call() { + assert(has_stack_frame(), "should do"); SharkVMCallDecacher(function(), block()->bci()).scan(this); } inline void SharkTrackingState::cache_after_VM_call() { + assert(has_stack_frame(), "should do"); SharkVMCallCacher(function(), block()->bci()).scan(this); } inline void SharkTrackingState::decache_for_trap() { + assert(has_stack_frame(), "should do"); SharkTrapDecacher(function(), block()->bci()).scan(this); }