mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-24 04:54:40 +02:00
8033626: assert(ex_map->jvms()->same_calls_as(_exceptions->jvms())) failed: all collected exceptions must come from the same place
Reviewed-by: kvn, roland
This commit is contained in:
parent
5067eae483
commit
ea0470002e
4 changed files with 113 additions and 17 deletions
|
@ -2513,7 +2513,7 @@ void GraphKit::merge_memory(Node* new_mem, Node* region, int new_path) {
|
||||||
|
|
||||||
//------------------------------make_slow_call_ex------------------------------
|
//------------------------------make_slow_call_ex------------------------------
|
||||||
// Make the exception handler hookups for the slow call
|
// Make the exception handler hookups for the slow call
|
||||||
void GraphKit::make_slow_call_ex(Node* call, ciInstanceKlass* ex_klass, bool separate_io_proj) {
|
void GraphKit::make_slow_call_ex(Node* call, ciInstanceKlass* ex_klass, bool separate_io_proj, bool deoptimize) {
|
||||||
if (stopped()) return;
|
if (stopped()) return;
|
||||||
|
|
||||||
// Make a catch node with just two handlers: fall-through and catch-all
|
// Make a catch node with just two handlers: fall-through and catch-all
|
||||||
|
@ -2527,6 +2527,11 @@ void GraphKit::make_slow_call_ex(Node* call, ciInstanceKlass* ex_klass, bool sep
|
||||||
set_i_o(i_o);
|
set_i_o(i_o);
|
||||||
|
|
||||||
if (excp != top()) {
|
if (excp != top()) {
|
||||||
|
if (deoptimize) {
|
||||||
|
// Deoptimize if an exception is caught. Don't construct exception state in this case.
|
||||||
|
uncommon_trap(Deoptimization::Reason_unhandled,
|
||||||
|
Deoptimization::Action_none);
|
||||||
|
} else {
|
||||||
// Create an exception state also.
|
// Create an exception state also.
|
||||||
// Use an exact type if the caller has specified a specific exception.
|
// Use an exact type if the caller has specified a specific exception.
|
||||||
const Type* ex_type = TypeOopPtr::make_from_klass_unique(ex_klass)->cast_to_ptr_type(TypePtr::NotNull);
|
const Type* ex_type = TypeOopPtr::make_from_klass_unique(ex_klass)->cast_to_ptr_type(TypePtr::NotNull);
|
||||||
|
@ -2534,6 +2539,7 @@ void GraphKit::make_slow_call_ex(Node* call, ciInstanceKlass* ex_klass, bool sep
|
||||||
add_exception_state(make_exception_state(_gvn.transform(ex_oop)));
|
add_exception_state(make_exception_state(_gvn.transform(ex_oop)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Get the no-exception control from the CatchNode.
|
// Get the no-exception control from the CatchNode.
|
||||||
set_control(norm);
|
set_control(norm);
|
||||||
|
@ -3352,7 +3358,8 @@ static void hook_memory_on_init(GraphKit& kit, int alias_idx,
|
||||||
|
|
||||||
//---------------------------set_output_for_allocation-------------------------
|
//---------------------------set_output_for_allocation-------------------------
|
||||||
Node* GraphKit::set_output_for_allocation(AllocateNode* alloc,
|
Node* GraphKit::set_output_for_allocation(AllocateNode* alloc,
|
||||||
const TypeOopPtr* oop_type) {
|
const TypeOopPtr* oop_type,
|
||||||
|
bool deoptimize_on_exception) {
|
||||||
int rawidx = Compile::AliasIdxRaw;
|
int rawidx = Compile::AliasIdxRaw;
|
||||||
alloc->set_req( TypeFunc::FramePtr, frameptr() );
|
alloc->set_req( TypeFunc::FramePtr, frameptr() );
|
||||||
add_safepoint_edges(alloc);
|
add_safepoint_edges(alloc);
|
||||||
|
@ -3360,7 +3367,7 @@ Node* GraphKit::set_output_for_allocation(AllocateNode* alloc,
|
||||||
set_control( _gvn.transform(new ProjNode(allocx, TypeFunc::Control) ) );
|
set_control( _gvn.transform(new ProjNode(allocx, TypeFunc::Control) ) );
|
||||||
// create memory projection for i_o
|
// create memory projection for i_o
|
||||||
set_memory ( _gvn.transform( new ProjNode(allocx, TypeFunc::Memory, true) ), rawidx );
|
set_memory ( _gvn.transform( new ProjNode(allocx, TypeFunc::Memory, true) ), rawidx );
|
||||||
make_slow_call_ex(allocx, env()->Throwable_klass(), true);
|
make_slow_call_ex(allocx, env()->Throwable_klass(), true, deoptimize_on_exception);
|
||||||
|
|
||||||
// create a memory projection as for the normal control path
|
// create a memory projection as for the normal control path
|
||||||
Node* malloc = _gvn.transform(new ProjNode(allocx, TypeFunc::Memory));
|
Node* malloc = _gvn.transform(new ProjNode(allocx, TypeFunc::Memory));
|
||||||
|
@ -3438,9 +3445,11 @@ Node* GraphKit::set_output_for_allocation(AllocateNode* alloc,
|
||||||
// The optional arguments are for specialized use by intrinsics:
|
// The optional arguments are for specialized use by intrinsics:
|
||||||
// - If 'extra_slow_test' if not null is an extra condition for the slow-path.
|
// - If 'extra_slow_test' if not null is an extra condition for the slow-path.
|
||||||
// - If 'return_size_val', report the the total object size to the caller.
|
// - If 'return_size_val', report the the total object size to the caller.
|
||||||
|
// - deoptimize_on_exception controls how Java exceptions are handled (rethrow vs deoptimize)
|
||||||
Node* GraphKit::new_instance(Node* klass_node,
|
Node* GraphKit::new_instance(Node* klass_node,
|
||||||
Node* extra_slow_test,
|
Node* extra_slow_test,
|
||||||
Node* *return_size_val) {
|
Node* *return_size_val,
|
||||||
|
bool deoptimize_on_exception) {
|
||||||
// Compute size in doublewords
|
// Compute size in doublewords
|
||||||
// The size is always an integral number of doublewords, represented
|
// The size is always an integral number of doublewords, represented
|
||||||
// as a positive bytewise size stored in the klass's layout_helper.
|
// as a positive bytewise size stored in the klass's layout_helper.
|
||||||
|
@ -3508,7 +3517,7 @@ Node* GraphKit::new_instance(Node* klass_node,
|
||||||
size, klass_node,
|
size, klass_node,
|
||||||
initial_slow_test);
|
initial_slow_test);
|
||||||
|
|
||||||
return set_output_for_allocation(alloc, oop_type);
|
return set_output_for_allocation(alloc, oop_type, deoptimize_on_exception);
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------new_array-------------------------------------
|
//-------------------------------new_array-------------------------------------
|
||||||
|
@ -3518,7 +3527,8 @@ Node* GraphKit::new_instance(Node* klass_node,
|
||||||
Node* GraphKit::new_array(Node* klass_node, // array klass (maybe variable)
|
Node* GraphKit::new_array(Node* klass_node, // array klass (maybe variable)
|
||||||
Node* length, // number of array elements
|
Node* length, // number of array elements
|
||||||
int nargs, // number of arguments to push back for uncommon trap
|
int nargs, // number of arguments to push back for uncommon trap
|
||||||
Node* *return_size_val) {
|
Node* *return_size_val,
|
||||||
|
bool deoptimize_on_exception) {
|
||||||
jint layout_con = Klass::_lh_neutral_value;
|
jint layout_con = Klass::_lh_neutral_value;
|
||||||
Node* layout_val = get_layout_helper(klass_node, layout_con);
|
Node* layout_val = get_layout_helper(klass_node, layout_con);
|
||||||
int layout_is_con = (layout_val == NULL);
|
int layout_is_con = (layout_val == NULL);
|
||||||
|
@ -3661,7 +3671,7 @@ Node* GraphKit::new_array(Node* klass_node, // array klass (maybe variable)
|
||||||
ary_type = ary_type->is_aryptr()->cast_to_size(length_type);
|
ary_type = ary_type->is_aryptr()->cast_to_size(length_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
Node* javaoop = set_output_for_allocation(alloc, ary_type);
|
Node* javaoop = set_output_for_allocation(alloc, ary_type, deoptimize_on_exception);
|
||||||
|
|
||||||
// Cast length on remaining path to be as narrow as possible
|
// Cast length on remaining path to be as narrow as possible
|
||||||
if (map()->find_edge(length) >= 0) {
|
if (map()->find_edge(length) >= 0) {
|
||||||
|
|
|
@ -807,7 +807,7 @@ class GraphKit : public Phase {
|
||||||
|
|
||||||
// merge in all memory slices from new_mem, along the given path
|
// merge in all memory slices from new_mem, along the given path
|
||||||
void merge_memory(Node* new_mem, Node* region, int new_path);
|
void merge_memory(Node* new_mem, Node* region, int new_path);
|
||||||
void make_slow_call_ex(Node* call, ciInstanceKlass* ex_klass, bool separate_io_proj);
|
void make_slow_call_ex(Node* call, ciInstanceKlass* ex_klass, bool separate_io_proj, bool deoptimize = false);
|
||||||
|
|
||||||
// Helper functions to build synchronizations
|
// Helper functions to build synchronizations
|
||||||
int next_monitor();
|
int next_monitor();
|
||||||
|
@ -849,13 +849,16 @@ class GraphKit : public Phase {
|
||||||
|
|
||||||
// implementation of object creation
|
// implementation of object creation
|
||||||
Node* set_output_for_allocation(AllocateNode* alloc,
|
Node* set_output_for_allocation(AllocateNode* alloc,
|
||||||
const TypeOopPtr* oop_type);
|
const TypeOopPtr* oop_type,
|
||||||
|
bool deoptimize_on_exception=false);
|
||||||
Node* get_layout_helper(Node* klass_node, jint& constant_value);
|
Node* get_layout_helper(Node* klass_node, jint& constant_value);
|
||||||
Node* new_instance(Node* klass_node,
|
Node* new_instance(Node* klass_node,
|
||||||
Node* slow_test = NULL,
|
Node* slow_test = NULL,
|
||||||
Node* *return_size_val = NULL);
|
Node* *return_size_val = NULL,
|
||||||
|
bool deoptimize_on_exception = false);
|
||||||
Node* new_array(Node* klass_node, Node* count_val, int nargs,
|
Node* new_array(Node* klass_node, Node* count_val, int nargs,
|
||||||
Node* *return_size_val = NULL);
|
Node* *return_size_val = NULL,
|
||||||
|
bool deoptimize_on_exception = false);
|
||||||
|
|
||||||
// java.lang.String helpers
|
// java.lang.String helpers
|
||||||
Node* load_String_offset(Node* ctrl, Node* str);
|
Node* load_String_offset(Node* ctrl, Node* str);
|
||||||
|
|
|
@ -4579,7 +4579,10 @@ bool LibraryCallKit::inline_native_clone(bool is_virtual) {
|
||||||
// It's an instance, and it passed the slow-path tests.
|
// It's an instance, and it passed the slow-path tests.
|
||||||
PreserveJVMState pjvms(this);
|
PreserveJVMState pjvms(this);
|
||||||
Node* obj_size = NULL;
|
Node* obj_size = NULL;
|
||||||
Node* alloc_obj = new_instance(obj_klass, NULL, &obj_size);
|
// Need to deoptimize on exception from allocation since Object.clone intrinsic
|
||||||
|
// is reexecuted if deoptimization occurs and there could be problems when merging
|
||||||
|
// exception state between multiple Object.clone versions (reexecute=true vs reexecute=false).
|
||||||
|
Node* alloc_obj = new_instance(obj_klass, NULL, &obj_size, /*deoptimize_on_exception=*/true);
|
||||||
|
|
||||||
copy_to_clone(obj, alloc_obj, obj_size, false, !use_ReduceInitialCardMarks());
|
copy_to_clone(obj, alloc_obj, obj_size, false, !use_ReduceInitialCardMarks());
|
||||||
|
|
||||||
|
|
80
hotspot/test/compiler/intrinsics/clone/TestObjectClone.java
Normal file
80
hotspot/test/compiler/intrinsics/clone/TestObjectClone.java
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2014, 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 8033626
|
||||||
|
* @summary assert(ex_map->jvms()->same_calls_as(_exceptions->jvms())) failed: all collected exceptions must come from the same place
|
||||||
|
* @library /testlibrary
|
||||||
|
* @run main/othervm -XX:-TieredCompilation -Xbatch -XX:CompileOnly=TestObjectClone::f TestObjectClone
|
||||||
|
*/
|
||||||
|
import com.oracle.java.testlibrary.Asserts;
|
||||||
|
|
||||||
|
public class TestObjectClone implements Cloneable {
|
||||||
|
static class A extends TestObjectClone {}
|
||||||
|
static class B extends TestObjectClone {
|
||||||
|
public B clone() {
|
||||||
|
return (B)TestObjectClone.b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static class C extends TestObjectClone {
|
||||||
|
public C clone() {
|
||||||
|
return (C)TestObjectClone.c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static class D extends TestObjectClone {
|
||||||
|
public D clone() {
|
||||||
|
return (D)TestObjectClone.d;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static TestObjectClone a = new A(), b = new B(), c = new C(), d = new D();
|
||||||
|
|
||||||
|
public static Object f(TestObjectClone o) throws CloneNotSupportedException {
|
||||||
|
// Polymorphic call site: >90% Object::clone / <10% other methods
|
||||||
|
return o.clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
TestObjectClone[] params1 = {a, a, a, a, a, a, a, a, a, a, a,
|
||||||
|
a, a, a, a, a, a, a, a, a, a, a,
|
||||||
|
a, a, a, a, a, a, a, a, a, a, a,
|
||||||
|
b, c, d};
|
||||||
|
|
||||||
|
for (int i = 0; i < 15000; i++) {
|
||||||
|
f(params1[i % params1.length]);
|
||||||
|
}
|
||||||
|
|
||||||
|
Asserts.assertTrue(f(a) != a);
|
||||||
|
Asserts.assertTrue(f(b) == b);
|
||||||
|
Asserts.assertTrue(f(c) == c);
|
||||||
|
Asserts.assertTrue(f(d) == d);
|
||||||
|
|
||||||
|
try {
|
||||||
|
f(null);
|
||||||
|
throw new AssertionError("");
|
||||||
|
} catch (NullPointerException e) { /* expected */ }
|
||||||
|
|
||||||
|
System.out.println("TEST PASSED");
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue