< prev index next > src/hotspot/share/opto/parseHelper.cpp
Print this page
* questions.
*
*/
#include "precompiled.hpp"
+ #include "ci/ciInlineKlass.hpp"
#include "ci/ciSymbols.hpp"
#include "compiler/compileLog.hpp"
+ #include "oops/flatArrayKlass.hpp"
#include "oops/objArrayKlass.hpp"
#include "opto/addnode.hpp"
+ #include "opto/castnode.hpp"
+ #include "opto/inlinetypenode.hpp"
#include "opto/memnode.hpp"
#include "opto/mulnode.hpp"
#include "opto/parse.hpp"
#include "opto/rootnode.hpp"
#include "opto/runtime.hpp"
//=============================================================================
//------------------------------do_checkcast-----------------------------------
void Parse::do_checkcast() {
bool will_link;
ciKlass* klass = iter().get_klass(will_link);
-
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,
// then the checkcast does nothing.
push(res);
}
//------------------------------array_store_check------------------------------
// pull array from stack and check that the store is valid
- void Parse::array_store_check() {
-
+ Node* Parse::array_store_check(Node*& adr, const Type*& elemtype) {
// 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;
+ if (_gvn.type(ary)->is_aryptr()->is_null_free()) {
+ null_check(obj);
+ }
+ return obj;
}
// 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, nullptr, immutable_memory(), p, TypeInstPtr::KLASS));
+ Node* array_klass = load_object_klass(ary);
// Get the array klass
- const TypeKlassPtr *tak = _gvn.type(array_klass)->is_klassptr();
+ 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.
// Make constant out of the inexact array klass, but use it only if the cast
// succeeds.
bool always_see_exact_class = false;
- if (MonomorphicArrayCheck
- && !too_many_traps(Deoptimization::Reason_array_check)
- && !tak->klass_is_exact()
- && tak != TypeInstKlassPtr::OBJECT) {
- // Regarding the fourth condition in the if-statement from above:
- //
+ if (MonomorphicArrayCheck && !tak->klass_is_exact()) {
+ // Make a constant out of the inexact array klass
+ const TypeKlassPtr* extak = nullptr;
+ const TypeOopPtr* ary_t = _gvn.type(ary)->is_oopptr();
+ ciKlass* ary_spec = ary_t->speculative_type();
+ Deoptimization::DeoptReason reason = Deoptimization::Reason_none;
+ // Try to cast the array to an exact type from profile data. First
+ // check the speculative type.
+ if (ary_spec != nullptr && !too_many_traps(Deoptimization::Reason_speculate_class_check)) {
+ extak = TypeKlassPtr::make(ary_spec);
+ reason = Deoptimization::Reason_speculate_class_check;
+ } else if (UseArrayLoadStoreProfile) {
+ // No speculative type: check profile data at this bci.
+ reason = Deoptimization::Reason_class_check;
+ if (!too_many_traps(reason)) {
+ ciKlass* array_type = nullptr;
+ ciKlass* element_type = nullptr;
+ ProfilePtrKind element_ptr = ProfileMaybeNull;
+ bool flat_array = true;
+ bool null_free_array = true;
+ method()->array_access_profiled_type(bci(), array_type, element_type, element_ptr, flat_array, null_free_array);
+ if (array_type != nullptr) {
+ extak = TypeKlassPtr::make(array_type);
+ }
+ }
+ } else if (!too_many_traps(Deoptimization::Reason_array_check) && tak != TypeInstKlassPtr::OBJECT) {
// If the compiler has determined that the type of array 'ary' (represented
// by 'array_klass') is java/lang/Object, the compiler must not assume that
// the array 'ary' is monomorphic.
//
// If 'ary' were of type java/lang/Object, this arraystore would have to fail,
// java/lang/Object is the superclass of all arrays, but it is represented by the VM
// as an InstanceKlass. The checks generated by gen_checkcast() (see below) expect
// 'array_klass' to be ObjArrayKlass, which can result in invalid memory accesses.
//
// See issue JDK-8057622 for details.
-
- always_see_exact_class = true;
- // (If no MDO at all, hope for the best, until a trap actually occurs.)
-
- // Make a constant out of the inexact array klass
- const TypeKlassPtr *extak = tak->cast_to_exactness(true);
-
- if (extak->exact_klass(true) != nullptr) {
+ extak = tak->cast_to_exactness(true);
+ reason = Deoptimization::Reason_array_check;
+ }
+ if (extak != nullptr && extak->exact_klass(true) != nullptr) {
Node* con = makecon(extak);
- Node* cmp = _gvn.transform(new CmpPNode( array_klass, con ));
- Node* bol = _gvn.transform(new BoolNode( cmp, BoolTest::eq ));
- Node* ctrl= control();
- { BuildCutout unless(this, bol, PROB_MAX);
- uncommon_trap(Deoptimization::Reason_array_check,
- Deoptimization::Action_maybe_recompile,
- extak->exact_klass());
- }
- if (stopped()) { // MUST uncommon-trap?
- set_control(ctrl); // Then Don't Do It, just fall into the normal checking
- } else { // Cast array klass to exactness:
- // Use the exact constant value we know it is.
- replace_in_map(array_klass,con);
+ Node* cmp = _gvn.transform(new CmpPNode(array_klass, con));
+ Node* bol = _gvn.transform(new BoolNode(cmp, BoolTest::eq));
+ // Only do it if the check does not always pass/fail
+ if (!bol->is_Con()) {
+ always_see_exact_class = true;
+ { BuildCutout unless(this, bol, PROB_MAX);
+ uncommon_trap(reason,
+ Deoptimization::Action_maybe_recompile,
+ extak->exact_klass());
+ }
+ // Cast array klass to exactness
+ replace_in_map(array_klass, con);
+ array_klass = con;
+ Node* cast = _gvn.transform(new CheckCastPPNode(control(), ary, extak->as_instance_type()));
+ replace_in_map(ary, cast);
+ ary = cast;
+
+ // Recompute element type and address
+ const TypeAryPtr* arytype = _gvn.type(ary)->is_aryptr();
+ elemtype = arytype->elem();
+ adr = array_element_address(ary, idx, T_OBJECT, arytype->size(), control());
+
CompileLog* log = C->log();
if (log != nullptr) {
log->elem("cast_up reason='monomorphic_array' from='%d' to='(exact)'",
log->identify(extak->exact_klass()));
}
- array_klass = con; // Use cast value moving forward
}
}
}
// Come here for polymorphic array klasses
// Extract the array element class
- int element_klass_offset = in_bytes(ObjArrayKlass::element_klass_offset());
+ 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() : nullptr,
immutable_memory(), p2, tak));
+ // If we statically know that this is an inline type array, use precise element klass for checkcast
+ const TypeAryPtr* arytype = _gvn.type(ary)->is_aryptr();
+ bool null_free = false;
+ if (elemtype->make_ptr()->is_inlinetypeptr()) {
+ // We statically know that this is an inline type array, use precise klass ptr
+ null_free = arytype->is_flat() || !elemtype->make_ptr()->maybe_null();
+ a_e_klass = makecon(TypeKlassPtr::make(elemtype->inline_klass()));
+ }
+
// 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);
+ return gen_checkcast(obj, a_e_klass, nullptr, null_free);
}
//------------------------------do_new-----------------------------------------
void Parse::do_new() {
if (C->needs_clinit_barrier(klass, method())) {
clinit_barrier(klass, method());
if (stopped()) return;
}
+ if (klass->is_inlinetype()) {
+ push(InlineTypeNode::make_default(_gvn, klass->as_inline_klass(), /* is_larval */ true));
+ return;
+ }
+
Node* kls = makecon(TypeKlassPtr::make(klass));
Node* obj = new_instance(kls);
// Push resultant oop onto stack
push(obj);
< prev index next >