< prev index next >

src/hotspot/share/opto/parseHelper.cpp

Print this page

        

*** 21,39 **** --- 21,42 ---- * questions. * */ #include "precompiled.hpp" + #include "ci/ciValueKlass.hpp" #include "classfile/systemDictionary.hpp" #include "compiler/compileLog.hpp" #include "oops/objArrayKlass.hpp" + #include "oops/valueArrayKlass.hpp" #include "opto/addnode.hpp" #include "opto/memnode.hpp" #include "opto/mulnode.hpp" #include "opto/parse.hpp" #include "opto/rootnode.hpp" #include "opto/runtime.hpp" + #include "opto/valuetypenode.hpp" #include "runtime/sharedRuntime.hpp" //------------------------------make_dtrace_method_entry_exit ---------------- // Dtrace -- record entry or exit of a method if compiled with dtrace support void GraphKit::make_dtrace_method_entry_exit(ciMethod* method, bool is_entry) {
*** 63,72 **** --- 66,76 ---- //============================================================================= //------------------------------do_checkcast----------------------------------- void Parse::do_checkcast() { bool will_link; ciKlass* klass = iter().get_klass(will_link); + bool never_null = iter().is_klass_never_null(); Node *obj = peek(); // Throw uncommon trap if class is not loaded or the value we are casting // _from_ is not loaded, and value is not null. If the value _is_ NULL,
*** 90,100 **** profile_null_checkcast(); } return; } ! Node *res = gen_checkcast(obj, makecon(TypeKlassPtr::make(klass)) ); // Pop from stack AFTER gen_checkcast because it can uncommon trap and // the debug info has to be correct. pop(); push(res); --- 94,107 ---- profile_null_checkcast(); } return; } ! Node* res = gen_checkcast(obj, makecon(TypeKlassPtr::make(klass)), NULL, never_null); ! if (stopped()) { ! return; ! } // Pop from stack AFTER gen_checkcast because it can uncommon trap and // the debug info has to be correct. pop(); push(res);
*** 135,164 **** push(res); } //------------------------------array_store_check------------------------------ // pull array from stack and check that the store is valid ! void Parse::array_store_check() { ! // Shorthand access to array store elements without popping them. Node *obj = peek(0); Node *idx = peek(1); Node *ary = peek(2); if (_gvn.type(obj) == TypePtr::NULL_PTR) { // There's never a type check on null values. // This cutout lets us avoid the uncommon_trap(Reason_array_check) // below, which turns into a performance liability if the // gen_checkcast folds up completely. ! return; } // Extract the array klass type ! int klass_offset = oopDesc::klass_offset_in_bytes(); ! Node* p = basic_plus_adr( ary, ary, klass_offset ); ! // p's type is array-of-OOPS plus klass_offset ! Node* array_klass = _gvn.transform(LoadKlassNode::make(_gvn, NULL, immutable_memory(), p, TypeInstPtr::KLASS)); // Get the array klass const TypeKlassPtr *tak = _gvn.type(array_klass)->is_klassptr(); // The type of array_klass is usually INexact array-of-oop. Heroically // cast array_klass to EXACT array and uncommon-trap if the cast fails. --- 142,172 ---- push(res); } //------------------------------array_store_check------------------------------ // pull array from stack and check that the store is valid ! Node* Parse::array_store_check() { // Shorthand access to array store elements without popping them. Node *obj = peek(0); Node *idx = peek(1); Node *ary = peek(2); + const TypeAryPtr* ary_t = _gvn.type(ary)->is_aryptr(); + const Type* elemtype = ary_t->elem(); + const TypeOopPtr* elemptr = elemtype->make_oopptr(); + bool is_value_array = elemtype->isa_valuetype() != NULL || (elemptr != NULL && elemptr->is_valuetypeptr()); + if (_gvn.type(obj) == TypePtr::NULL_PTR) { // There's never a type check on null values. // This cutout lets us avoid the uncommon_trap(Reason_array_check) // below, which turns into a performance liability if the // gen_checkcast folds up completely. ! return obj; } // Extract the array klass type ! Node* array_klass = load_object_klass(ary); // Get the array klass const TypeKlassPtr *tak = _gvn.type(array_klass)->is_klassptr(); // The type of array_klass is usually INexact array-of-oop. Heroically // cast array_klass to EXACT array and uncommon-trap if the cast fails.
*** 219,243 **** } // Come here for polymorphic array klasses // Extract the array element class ! int element_klass_offset = in_bytes(ObjArrayKlass::element_klass_offset()); Node *p2 = basic_plus_adr(array_klass, array_klass, element_klass_offset); // We are allowed to use the constant type only if cast succeeded. If always_see_exact_class is true, // we must set a control edge from the IfTrue node created by the uncommon_trap above to the // LoadKlassNode. Node* a_e_klass = _gvn.transform(LoadKlassNode::make(_gvn, always_see_exact_class ? control() : NULL, immutable_memory(), p2, tak)); // Check (the hard way) and throw if not a subklass. ! // Result is ignored, we just need the CFG effects. ! gen_checkcast(obj, a_e_klass); } void Parse::emit_guard_for_new(ciInstanceKlass* klass) { // Emit guarded new // if (klass->_init_thread != current_thread || // klass->_init_state != being_initialized) // uncommon_trap Node* cur_thread = _gvn.transform( new ThreadLocalNode() ); --- 227,267 ---- } // Come here for polymorphic array klasses // Extract the array element class ! int element_klass_offset = in_bytes(ArrayKlass::element_klass_offset()); ! Node *p2 = basic_plus_adr(array_klass, array_klass, element_klass_offset); // We are allowed to use the constant type only if cast succeeded. If always_see_exact_class is true, // we must set a control edge from the IfTrue node created by the uncommon_trap above to the // LoadKlassNode. Node* a_e_klass = _gvn.transform(LoadKlassNode::make(_gvn, always_see_exact_class ? control() : NULL, immutable_memory(), p2, tak)); + // Handle value type arrays + if (is_value_array) { + // We statically know that this is a value type array, use precise klass ptr + ciValueKlass* vk = elemtype->isa_valuetype() ? elemtype->is_valuetype()->value_klass() : + elemptr->value_klass(); + a_e_klass = makecon(TypeKlassPtr::make(vk)); + } + // Check (the hard way) and throw if not a subklass. ! return gen_checkcast(obj, a_e_klass); } void Parse::emit_guard_for_new(ciInstanceKlass* klass) { + if ((!klass->is_initialized() && !klass->is_being_initialized()) || + klass->is_abstract() || klass->is_interface() || + klass->name() == ciSymbol::java_lang_Class() || + iter().is_unresolved_klass()) { + uncommon_trap(Deoptimization::Reason_uninitialized, + Deoptimization::Action_reinterpret, + klass); + } if (klass->is_being_initialized()) { // Emit guarded new // if (klass->_init_thread != current_thread || // klass->_init_state != being_initialized) // uncommon_trap Node* cur_thread = _gvn.transform( new ThreadLocalNode() );
*** 269,278 **** --- 293,303 ---- set_control(merge); uncommon_trap(Deoptimization::Reason_uninitialized, Deoptimization::Action_reinterpret, klass); + } } //------------------------------do_new----------------------------------------- void Parse::do_new() {
*** 281,302 **** bool will_link; ciInstanceKlass* klass = iter().get_klass(will_link)->as_instance_klass(); assert(will_link, "_new: typeflow responsibility"); // Should initialize, or throw an InstantiationError? - if ((!klass->is_initialized() && !klass->is_being_initialized()) || - klass->is_abstract() || klass->is_interface() || - klass->name() == ciSymbol::java_lang_Class() || - iter().is_unresolved_klass()) { - uncommon_trap(Deoptimization::Reason_uninitialized, - Deoptimization::Action_reinterpret, - klass); - return; - } - if (klass->is_being_initialized()) { emit_guard_for_new(klass); ! } Node* kls = makecon(TypeKlassPtr::make(klass)); Node* obj = new_instance(kls); // Push resultant oop onto stack --- 306,317 ---- bool will_link; ciInstanceKlass* klass = iter().get_klass(will_link)->as_instance_klass(); assert(will_link, "_new: typeflow responsibility"); // Should initialize, or throw an InstantiationError? emit_guard_for_new(klass); ! if (stopped()) return; Node* kls = makecon(TypeKlassPtr::make(klass)); Node* obj = new_instance(kls); // Push resultant oop onto stack
*** 314,323 **** --- 329,395 ---- if (C->eliminate_boxing() && klass->is_box_klass()) { C->set_has_boxed_value(true); } } + //------------------------------do_defaultvalue--------------------------------- + void Parse::do_defaultvalue() { + bool will_link; + ciValueKlass* vk = iter().get_klass(will_link)->as_value_klass(); + assert(will_link, "defaultvalue: typeflow responsibility"); + + // Should initialize, or throw an InstantiationError? + emit_guard_for_new(vk); + if (stopped()) return; + + // Always scalarize default value because it's not NULL by definition + push(ValueTypeNode::make_default(_gvn, vk)); + } + + //------------------------------do_withfield------------------------------------ + void Parse::do_withfield() { + bool will_link; + ciField* field = iter().get_field(will_link); + assert(will_link, "withfield: typeflow responsibility"); + BasicType bt = field->layout_type(); + Node* val = type2size[bt] == 1 ? pop() : pop_pair(); + ciValueKlass* holder_klass = field->holder()->as_value_klass(); + Node* holder = pop(); + + if (!holder->is_ValueType()) { + // Null check and scalarize value type holder + inc_sp(2); + holder = null_check(holder); + dec_sp(2); + if (stopped()) return; + holder = ValueTypeNode::make_from_oop(this, holder, holder_klass); + } + if (!val->is_ValueType() && field->is_flattenable()) { + // Null check and scalarize value type field value + inc_sp(2); + val = null_check(val); + dec_sp(2); + if (stopped()) return; + val = ValueTypeNode::make_from_oop(this, val, gvn().type(val)->value_klass()); + } else if (val->is_ValueType() && !field->is_flattenable()) { + // Non-flattenable field should not be scalarized + val = ValueTypePtrNode::make_from_value_type(this, val->as_ValueType()); + } + + // Clone the value type node and set the new field value + ValueTypeNode* new_vt = holder->clone()->as_ValueType(); + new_vt->set_oop(_gvn.zerocon(T_VALUETYPE)); + gvn().set_type(new_vt, new_vt->bottom_type()); + new_vt->set_field_value_by_offset(field->offset(), val); + + if (holder_klass->is_scalarizable()) { + push(_gvn.transform(new_vt)); + } else { + push(new_vt->allocate(this)->get_oop()); + } + } + #ifndef PRODUCT //------------------------------dump_map_adr_mem------------------------------- // Debug dump of the mapping from address types to MergeMemNode indices. void Parse::dump_map_adr_mem() const { tty->print_cr("--- Mapping from address types to memory Nodes ---");
< prev index next >