< 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 >