This commit is contained in:
Jesper Wilhelmsson 2021-06-21 23:09:01 +00:00
commit 0458113c6b
25 changed files with 591 additions and 30 deletions

View File

@ -53,6 +53,8 @@ BUILD_JDK_JTREG_EXECUTABLES_CFLAGS_exeJliLaunchTest := \
-I$(TOPDIR)/src/java.base/$(OPENJDK_TARGET_OS_TYPE)/native/libjli \
-I$(TOPDIR)/src/java.base/$(OPENJDK_TARGET_OS)/native/libjli
BUILD_JDK_JTREG_LIBRARIES_LDFLAGS_libAsyncStackWalk := $(LIBCXX)
# Platform specific setup
ifeq ($(call isTargetOs, windows), true)
BUILD_JDK_JTREG_EXCLUDE += libDirectIO.c libInheritedChannel.c exelauncher.c
@ -63,6 +65,7 @@ ifeq ($(call isTargetOs, windows), true)
BUILD_JDK_JTREG_EXECUTABLES_LIBS_exeJliLaunchTest := $(WIN_LIB_JLI)
BUILD_JDK_JTREG_EXECUTABLES_LIBS_exeCallerAccessTest := jvm.lib
BUILD_JDK_JTREG_EXECUTABLES_LIBS_exerevokeall := advapi32.lib
BUILD_JDK_JTREG_LIBRARIES_CFLAGS_libAsyncStackWalk := /EHsc
else
BUILD_JDK_JTREG_LIBRARIES_LIBS_libstringPlatformChars := -ljava
BUILD_JDK_JTREG_LIBRARIES_LIBS_libDirectIO := -ljava

View File

@ -367,6 +367,11 @@ JavaFrameAnchor* OptimizedEntryBlob::jfa_for_frame(const frame& frame) const {
return nullptr;
}
bool frame::optimized_entry_frame_is_first() const {
ShouldNotCallThis();
return false;
}
frame frame::sender_for_optimized_entry_frame(RegisterMap* map) const {
ShouldNotCallThis();
return {};

View File

@ -313,6 +313,11 @@ frame frame::sender_for_entry_frame(RegisterMap* map) const {
return fr;
}
bool frame::optimized_entry_frame_is_first() const {
ShouldNotCallThis();
return false;
}
//------------------------------------------------------------------------------
// frame::verify_deopt_original_pc
//

View File

@ -197,6 +197,11 @@ frame frame::sender_for_entry_frame(RegisterMap *map) const {
return fr;
}
bool frame::optimized_entry_frame_is_first() const {
ShouldNotCallThis();
return false;
}
frame frame::sender_for_interpreter_frame(RegisterMap *map) const {
// Pass callers initial_caller_sp as unextended_sp.
return frame(sender_sp(), sender_pc(), (intptr_t*)get_ijava_state()->sender_sp);

View File

@ -208,6 +208,11 @@ frame frame::sender_for_entry_frame(RegisterMap *map) const {
return fr;
}
bool frame::optimized_entry_frame_is_first() const {
ShouldNotCallThis();
return false;
}
frame frame::sender_for_interpreter_frame(RegisterMap *map) const {
// Pass callers sender_sp as unextended_sp.
return frame(sender_sp(), sender_pc(), (intptr_t*)(ijava_state()->sender_sp));

View File

@ -358,12 +358,20 @@ JavaFrameAnchor* OptimizedEntryBlob::jfa_for_frame(const frame& frame) const {
return reinterpret_cast<JavaFrameAnchor*>(reinterpret_cast<char*>(frame.unextended_sp()) + in_bytes(jfa_sp_offset()));
}
bool frame::optimized_entry_frame_is_first() const {
assert(is_optimized_entry_frame(), "must be optimzed entry frame");
OptimizedEntryBlob* blob = _cb->as_optimized_entry_blob();
JavaFrameAnchor* jfa = blob->jfa_for_frame(*this);
return jfa->last_Java_sp() == NULL;
}
frame frame::sender_for_optimized_entry_frame(RegisterMap* map) const {
assert(map != NULL, "map must be set");
OptimizedEntryBlob* blob = _cb->as_optimized_entry_blob();
// Java frame called from C; skip all C frames and return top C
// frame of that chunk as the sender
JavaFrameAnchor* jfa = blob->jfa_for_frame(*this);
assert(!optimized_entry_frame_is_first(), "must have a frame anchor to go back to");
assert(jfa->last_Java_sp() > sp(), "must be above this frame on stack");
// Since we are walking the stack now this nested anchor is obviously walkable
// even if it wasn't when it was stacked.

View File

@ -61,6 +61,11 @@ frame frame::sender_for_entry_frame(RegisterMap *map) const {
return frame(zeroframe()->next(), sender_sp());
}
bool frame::optimized_entry_frame_is_first() const {
ShouldNotCallThis();
return false;
}
frame frame::sender_for_nonentry_frame(RegisterMap *map) const {
assert(zeroframe()->is_interpreter_frame() ||
zeroframe()->is_fake_stub_frame(), "wrong type of frame");

View File

@ -23,7 +23,7 @@
*/
#include "precompiled.hpp"
#include "classfile/javaClasses.hpp"
#include "classfile/javaClasses.inline.hpp"
#include "classfile/vmSymbols.hpp"
#include "jfr/jfr.hpp"
#include "jfr/dcmd/jfrDcmds.hpp"
@ -33,6 +33,7 @@
#include "logging/log.hpp"
#include "logging/logConfiguration.hpp"
#include "logging/logMessage.hpp"
#include "memory/arena.hpp"
#include "memory/resourceArea.hpp"
#include "oops/objArrayOop.inline.hpp"
#include "oops/oop.inline.hpp"
@ -219,7 +220,6 @@ void JfrDCmd::invoke(JfrJavaArguments& method, TRAPS) const {
JfrJavaArguments constructor_args(&constructor_result);
constructor_args.set_klass(javaClass(), CHECK);
ResourceMark rm(THREAD);
HandleMark hm(THREAD);
JNIHandleBlockManager jni_handle_management(THREAD);
@ -241,12 +241,10 @@ void JfrDCmd::parse(CmdLine* line, char delim, TRAPS) {
}
void JfrDCmd::execute(DCmdSource source, TRAPS) {
static const char signature[] = "(Ljava/lang/String;Ljava/lang/String;C)[Ljava/lang/String;";
if (invalid_state(output(), THREAD)) {
return;
}
static const char signature[] = "(Ljava/lang/String;Ljava/lang/String;C)[Ljava/lang/String;";
JavaValue result(T_OBJECT);
JfrJavaArguments execute(&result, javaClass(), "execute", signature, CHECK);
jstring argument = JfrJavaSupport::new_string(_args, CHECK);
@ -271,13 +269,92 @@ void JfrDCmd::print_help(const char* name) const {
static const char signature[] = "()[Ljava/lang/String;";
JavaThread* thread = JavaThread::current();
JavaValue result(T_OBJECT);
JfrJavaArguments print_help(&result, javaClass(), "printHelp", signature, thread);
invoke(print_help, thread);
JfrJavaArguments printHelp(&result, javaClass(), "printHelp", signature, thread);
invoke(printHelp, thread);
handle_dcmd_result(output(), result.get_oop(), DCmd_Source_MBean, thread);
}
// Since the DcmdFramework does not support dynamically allocated strings,
// we keep them in a thread local arena. The arena is reset between invocations.
static THREAD_LOCAL Arena* dcmd_arena = NULL;
static void prepare_dcmd_string_arena() {
if (dcmd_arena == NULL) {
dcmd_arena = new (mtTracing) Arena(mtTracing);
} else {
dcmd_arena->destruct_contents(); // will grow on next allocation
}
}
static char* dcmd_arena_allocate(size_t size) {
assert(dcmd_arena != NULL, "invariant");
return (char*)dcmd_arena->Amalloc(size);
}
static const char* get_as_dcmd_arena_string(oop string, JavaThread* t) {
char* str = NULL;
const typeArrayOop value = java_lang_String::value(string);
if (value != NULL) {
const size_t length = static_cast<size_t>(java_lang_String::utf8_length(string, value)) + 1;
str = dcmd_arena_allocate(length);
assert(str != NULL, "invariant");
java_lang_String::as_utf8_string(string, value, str, static_cast<int>(length));
}
return str;
}
static const char* read_string_field(oop argument, const char* field_name, TRAPS) {
JavaValue result(T_OBJECT);
JfrJavaArguments args(&result);
args.set_klass(argument->klass());
args.set_name(field_name);
args.set_signature("Ljava/lang/String;");
args.set_receiver(argument);
JfrJavaSupport::get_field(&args, THREAD);
const oop string_oop = result.get_oop();
return string_oop != NULL ? get_as_dcmd_arena_string(string_oop, (JavaThread*)THREAD) : NULL;
}
static bool read_boolean_field(oop argument, const char* field_name, TRAPS) {
JavaValue result(T_BOOLEAN);
JfrJavaArguments args(&result);
args.set_klass(argument->klass());
args.set_name(field_name);
args.set_signature("Z");
args.set_receiver(argument);
JfrJavaSupport::get_field(&args, THREAD);
return (result.get_jint() & 1) == 1;
}
static DCmdArgumentInfo* create_info(oop argument, TRAPS) {
return new DCmdArgumentInfo(
read_string_field(argument, "name", THREAD),
read_string_field(argument, "description", THREAD),
read_string_field(argument, "type", THREAD),
read_string_field(argument, "defaultValue", THREAD),
read_boolean_field(argument, "mandatory", THREAD),
true, // a DcmdFramework "option"
read_boolean_field(argument, "allowMultiple", THREAD));
}
GrowableArray<DCmdArgumentInfo*>* JfrDCmd::argument_info_array() const {
return new GrowableArray<DCmdArgumentInfo*>();
static const char signature[] = "()[Ljdk/jfr/internal/dcmd/Argument;";
JavaThread* thread = JavaThread::current();
JavaValue result(T_OBJECT);
JfrJavaArguments getArgumentInfos(&result, javaClass(), "getArgumentInfos", signature, thread);
invoke(getArgumentInfos, thread);
objArrayOop arguments = objArrayOop(result.get_oop());
assert(arguments != NULL, "invariant");
assert(arguments->is_array(), "must be array");
GrowableArray<DCmdArgumentInfo*>* const array = new GrowableArray<DCmdArgumentInfo*>();
const int length = arguments->length();
prepare_dcmd_string_arena();
for (int i = 0; i < length; ++i) {
DCmdArgumentInfo* const dai = create_info(arguments->obj_at(i), thread);
assert(dai != NULL, "invariant");
array->append(dai);
}
return array;
}
GrowableArray<const char*>* JfrDCmd::argument_name_array() const {
@ -387,7 +464,6 @@ void JfrConfigureFlightRecorderDCmd::execute(DCmdSource source, TRAPS) {
return;
}
ResourceMark rm(THREAD);
HandleMark hm(THREAD);
JNIHandleBlockManager jni_handle_management(THREAD);

View File

@ -65,6 +65,9 @@ class JfrStartFlightRecordingDCmd : public JfrDCmd {
virtual const char* javaClass() const {
return "jdk/jfr/internal/dcmd/DCmdStart";
}
static int num_arguments() {
return 11;
}
};
class JfrDumpFlightRecordingDCmd : public JfrDCmd {
@ -87,6 +90,9 @@ class JfrDumpFlightRecordingDCmd : public JfrDCmd {
virtual const char* javaClass() const {
return "jdk/jfr/internal/dcmd/DCmdDump";
}
static int num_arguments() {
return 7;
}
};
class JfrCheckFlightRecordingDCmd : public JfrDCmd {
@ -109,6 +115,9 @@ class JfrCheckFlightRecordingDCmd : public JfrDCmd {
virtual const char* javaClass() const {
return "jdk/jfr/internal/dcmd/DCmdCheck";
}
static int num_arguments() {
return 2;
}
};
class JfrStopFlightRecordingDCmd : public JfrDCmd {
@ -131,6 +140,9 @@ class JfrStopFlightRecordingDCmd : public JfrDCmd {
virtual const char* javaClass() const {
return "jdk/jfr/internal/dcmd/DCmdStop";
}
static int num_arguments() {
return 2;
}
};
class JfrConfigureFlightRecorderDCmd : public DCmdWithParser {

View File

@ -1758,7 +1758,7 @@ Node *AllocateArrayNode::make_ideal_length(const TypeOopPtr* oop_type, PhaseTran
InitializeNode* init = initialization();
assert(init != NULL, "initialization not found");
length = new CastIINode(length, narrow_length_type);
length->set_req(0, init->proj_out_or_null(0));
length->set_req(TypeFunc::Control, init->proj_out_or_null(TypeFunc::Control));
}
}

View File

@ -1184,15 +1184,31 @@ Node* GraphKit::load_array_length(Node* array) {
Node *r_adr = basic_plus_adr(array, arrayOopDesc::length_offset_in_bytes());
alen = _gvn.transform( new LoadRangeNode(0, immutable_memory(), r_adr, TypeInt::POS));
} else {
alen = alloc->Ideal_length();
Node* ccast = alloc->make_ideal_length(_gvn.type(array)->is_oopptr(), &_gvn);
if (ccast != alen) {
alen = _gvn.transform(ccast);
}
alen = array_ideal_length(alloc, _gvn.type(array)->is_oopptr(), false);
}
return alen;
}
Node* GraphKit::array_ideal_length(AllocateArrayNode* alloc,
const TypeOopPtr* oop_type,
bool replace_length_in_map) {
Node* length = alloc->Ideal_length();
if (replace_length_in_map == false || map()->find_edge(length) >= 0) {
Node* ccast = alloc->make_ideal_length(oop_type, &_gvn);
if (ccast != length) {
// do not transfrom ccast here, it might convert to top node for
// negative array length and break assumptions in parsing stage.
_gvn.set_type_bottom(ccast);
record_for_igvn(ccast);
if (replace_length_in_map) {
replace_in_map(length, ccast);
}
return ccast;
}
}
return length;
}
//------------------------------do_null_check----------------------------------
// Helper function to do a NULL pointer check. Returned value is
// the incoming address with NULL casted away. You are allowed to use the
@ -3980,16 +3996,7 @@ Node* GraphKit::new_array(Node* klass_node, // array klass (maybe variable)
Node* javaoop = set_output_for_allocation(alloc, ary_type, deoptimize_on_exception);
// Cast length on remaining path to be as narrow as possible
if (map()->find_edge(length) >= 0) {
Node* ccast = alloc->make_ideal_length(ary_type, &_gvn);
if (ccast != length) {
_gvn.set_type_bottom(ccast);
record_for_igvn(ccast);
replace_in_map(length, ccast);
}
}
array_ideal_length(alloc, ary_type, true);
return javaoop;
}

View File

@ -343,6 +343,12 @@ class GraphKit : public Phase {
Node* load_object_klass(Node* object);
// Find out the length of an array.
Node* load_array_length(Node* array);
// Cast array allocation's length as narrow as possible.
// If replace_length_in_map is true, replace length with CastIINode in map.
// This method is invoked after creating/moving ArrayAllocationNode or in load_array_length
Node* array_ideal_length(AllocateArrayNode* alloc,
const TypeOopPtr* oop_type,
bool replace_length_in_map);
// Helper function to do a NULL pointer check or ZERO check based on type.

View File

@ -4445,6 +4445,36 @@ void LibraryCallKit::arraycopy_move_allocation_here(AllocateArrayNode* alloc, No
Node* alloc_mem = alloc->in(TypeFunc::Memory);
C->gvn_replace_by(callprojs.fallthrough_ioproj, alloc->in(TypeFunc::I_O));
C->gvn_replace_by(init->proj_out(TypeFunc::Memory), alloc_mem);
// The CastIINode created in GraphKit::new_array (in AllocateArrayNode::make_ideal_length) must stay below
// the allocation (i.e. is only valid if the allocation succeeds):
// 1) replace CastIINode with AllocateArrayNode's length here
// 2) Create CastIINode again once allocation has moved (see below) at the end of this method
//
// Multiple identical CastIINodes might exist here. Each GraphKit::load_array_length() call will generate
// new separate CastIINode (arraycopy guard checks or any array length use between array allocation and ararycopy)
Node* init_control = init->proj_out(TypeFunc::Control);
Node* alloc_length = alloc->Ideal_length();
#ifdef ASSERT
Node* prev_cast = NULL;
#endif
for (uint i = 0; i < init_control->outcnt(); i++) {
Node* init_out = init_control->raw_out(i);
if (init_out->is_CastII() && init_out->in(TypeFunc::Control) == init_control && init_out->in(1) == alloc_length) {
#ifdef ASSERT
if (prev_cast == NULL) {
prev_cast = init_out;
} else {
if (prev_cast->cmp(*init_out) == false) {
prev_cast->dump();
init_out->dump();
assert(false, "not equal CastIINode");
}
}
#endif
C->gvn_replace_by(init_out, alloc_length);
}
}
C->gvn_replace_by(init->proj_out(TypeFunc::Control), alloc->in(0));
// move the allocation here (after the guards)
@ -4476,6 +4506,8 @@ void LibraryCallKit::arraycopy_move_allocation_here(AllocateArrayNode* alloc, No
dest->set_req(0, control());
Node* destx = _gvn.transform(dest);
assert(destx == dest, "where has the allocation result gone?");
array_ideal_length(alloc, ary_type, true);
}
}

View File

@ -1996,10 +1996,13 @@ static void clone_outer_loop_helper(Node* n, const IdealLoopTree *loop, const Id
Node* u = n->fast_out(j);
assert(check_old_new || old_new[u->_idx] == NULL, "shouldn't have been cloned");
if (!u->is_CFG() && (!check_old_new || old_new[u->_idx] == NULL)) {
Node* c = u->in(0) != NULL ? u->in(0) : phase->get_ctrl(u);
Node* c = phase->get_ctrl(u);
IdealLoopTree* u_loop = phase->get_loop(c);
assert(!loop->is_member(u_loop), "can be in outer loop or out of both loops only");
if (outer_loop->is_member(u_loop)) {
if (outer_loop->is_member(u_loop) ||
// nodes pinned with control in the outer loop but not referenced from the safepoint must be moved out of
// the outer loop too
(u->in(0) != NULL && outer_loop->is_member(phase->get_loop(u->in(0))))) {
wq.push(u);
}
}

View File

@ -2306,6 +2306,7 @@ WB_ENTRY(void, WB_VerifyFrames(JNIEnv* env, jobject wb, jboolean log, jboolean u
tty_token = ttyLocker::hold_tty();
tty->print_cr("[WhiteBox::VerifyFrames] Walking Frames");
}
ResourceMark rm; // for verify
for (StackFrameStream fst(JavaThread::current(), update_map, true); !fst.is_done(); fst.next()) {
frame* current_frame = fst.current();
if (log) {

View File

@ -1957,7 +1957,7 @@ JRT_ENTRY(void, Deoptimization::uncommon_trap_inner(JavaThread* current, jint tr
ScopeDesc* trap_scope = cvf->scope();
bool is_receiver_constraint_failure = VerifyReceiverTypes && (reason == Deoptimization::Reason_receiver_constraint);
bool is_receiver_constraint_failure = COMPILER2_PRESENT(VerifyReceiverTypes &&) (reason == Deoptimization::Reason_receiver_constraint);
if (TraceDeoptimization || is_receiver_constraint_failure) {
ttyLocker ttyl;

View File

@ -342,6 +342,7 @@ class frame {
// tells whether there is another chunk of Delta stack above
bool entry_frame_is_first() const;
bool optimized_entry_frame_is_first() const;
// Safepoints

View File

@ -50,7 +50,9 @@ inline bool frame::is_stub_frame() const {
}
inline bool frame::is_first_frame() const {
return is_entry_frame() && entry_frame_is_first();
return (is_entry_frame() && entry_frame_is_first())
// Optimized entry frames are only present on certain platforms
|| (is_optimized_entry_frame() && optimized_entry_frame_is_first());
}
inline bool frame::is_optimized_entry_frame() const {

View File

@ -58,7 +58,10 @@ abstract class AbstractDCmd {
// Called by native
public abstract String[] printHelp();
// Called by native
// Called by native. The number of arguments for each command is
// reported to the DCmdFramework as a hardcoded number in native.
// This is to avoid an upcall as part of DcmdFramework enumerating existing commands.
// Remember to keep the two sides in synch.
public abstract Argument[] getArgumentInfos();
// Called by native

View File

@ -0,0 +1,54 @@
/*
* Copyright (C) 2021 THL A29 Limited, a Tencent company. 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 8268362
* @requires vm.compiler2.enabled & vm.debug
* @summary C2 using negative array length as index, using a.length.
* AllocateArrayNode::make_ideal_length create CastIINode to not negative range.
* Apply transform in GraphKit::load_array_length will covert array load index type to top.
* This cause assert in Parse::array_addressing, it expect index type is int.
* @run main/othervm -XX:-PrintCompilation compiler.arraycopy.TestNegArrayLengthAsIndex1
*/
package compiler.arraycopy;
public class TestNegArrayLengthAsIndex1 {
public static void main(String[] args) throws Exception {
for (int i = 0; i < 10000; i++) {
foo();
}
}
static int foo() {
int minusOne = -1;
int[] a = null;
try {
a = new int[minusOne];
} catch (NegativeArraySizeException e) {
return 0;
}
return a[a.length - 1];
}
}

View File

@ -0,0 +1,52 @@
/*
* Copyright (C) 2021 THL A29 Limited, a Tencent company. 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 8268362
* @requires vm.compiler2.enabled & vm.debug
* @summary C2 using negative array length as index, using array allocation length.
* This assertion is triggered by 8267904.
* @run main/othervm compiler.arraycopy.TestNegArrayLengthAsIndex2
*/
package compiler.arraycopy;
public class TestNegArrayLengthAsIndex2 {
public static void main(String[] args) throws Exception {
for (int i = 0; i < 10000; i++) {
foo();
}
}
static int foo() {
int minusOne = -1;
int[] a = null;
try {
a = new int[minusOne];
} catch (NegativeArraySizeException e) {
return 0;
}
return a[minusOne - 1];
}
}

View File

@ -0,0 +1,60 @@
/*
* Copyright (C) 2021 THL A29 Limited, a Tencent company. 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 8267904
* @requires vm.compiler2.enabled
* @summary C2 inline array_copy move CastIINode(Array Length) before allocation cause crash.
* @run main/othervm compiler.arraycopy.TestNegativeArrayCopyAfterLoop
*/
package compiler.arraycopy;
import java.util.Arrays;
class test {
public static int exp_count = 0;
public int in1 = -4096;
test (){
try {
short sha4[] = new short[1012];
for (int i = 0; i < sha4.length; i++) {
sha4[i] = 9;
}
Arrays.copyOf(sha4, in1);
} catch (Exception ex) {
exp_count++;
}
}
}
public class TestNegativeArrayCopyAfterLoop {
public static void main(String[] args) {
for (int i = 0; i < 20000; i++) {
new test();
}
if (test.exp_count == 20000) {
System.out.println("TEST PASSED");
}
}
}

View File

@ -0,0 +1,59 @@
/*
* Copyright (c) 2021, Red Hat, Inc. 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 8268672
* @summary C2: assert(!loop->is_member(u_loop)) failed: can be in outer loop or out of both loops only
*
* @run main/othervm -Xcomp -XX:-TieredCompilation -XX:CompileOnly=TestPinnedNodeInInnerLoop TestPinnedNodeInInnerLoop
*
*/
public class TestPinnedNodeInInnerLoop {
boolean b;
double d;
int iArr[];
public static void main(String[] args) {
TestPinnedNodeInInnerLoop t = new TestPinnedNodeInInnerLoop();
for (int i = 0; i < 10; i++) {
t.test();
}
}
void test() {
int e = 4, f = -51874, g = 7, h = 0;
for (; f < 3; ++f) {
}
while (++g < 2) {
if (b) {
d = h;
} else {
iArr[g] = e;
}
}
System.out.println(g);
}
}

View File

@ -0,0 +1,113 @@
/*
* Copyright (c) 2021, 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
* @requires ((os.arch == "amd64" | os.arch == "x86_64") & sun.arch.data.model == "64") | os.arch == "aarch64"
* @library /test/lib
* @build sun.hotspot.WhiteBox
* @run driver jdk.test.lib.helpers.ClassFileInstaller sun.hotspot.WhiteBox
*
* @run main/othervm
* -Xbootclasspath/a:.
* -XX:+UnlockDiagnosticVMOptions
* -XX:+WhiteBoxAPI
* -Djdk.internal.foreign.ProgrammableInvoker.USE_INTRINSICS=true
* --enable-native-access=ALL-UNNAMED
* -Xbatch
* TestAsyncStackWalk
*
* @run main/othervm
* -Xbootclasspath/a:.
* -XX:+UnlockDiagnosticVMOptions
* -XX:+WhiteBoxAPI
* -Djdk.internal.foreign.ProgrammableInvoker.USE_INTRINSICS=false
* --enable-native-access=ALL-UNNAMED
* -Xbatch
* TestAsyncStackWalk
*/
import jdk.incubator.foreign.CLinker;
import jdk.incubator.foreign.FunctionDescriptor;
import jdk.incubator.foreign.SymbolLookup;
import jdk.incubator.foreign.MemoryAddress;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodType;
import jdk.incubator.foreign.ResourceScope;
import sun.hotspot.WhiteBox;
import static java.lang.invoke.MethodHandles.lookup;
import static jdk.incubator.foreign.CLinker.C_POINTER;
import static jdk.test.lib.Asserts.assertTrue;
public class TestAsyncStackWalk {
static final WhiteBox WB = WhiteBox.getWhiteBox();
static final CLinker linker = CLinker.getInstance();
static final MethodHandle MH_asyncStackWalk;
static final MethodHandle MH_m;
static {
try {
System.loadLibrary("AsyncStackWalk");
SymbolLookup lookup = SymbolLookup.loaderLookup();
MH_asyncStackWalk = linker.downcallHandle(
lookup.lookup("asyncStackWalk").get(),
MethodType.methodType(void.class, MemoryAddress.class),
FunctionDescriptor.ofVoid(C_POINTER));
MH_m = lookup().findStatic(TestAsyncStackWalk.class, "m", MethodType.methodType(void.class));
} catch (ReflectiveOperationException e) {
throw new RuntimeException(e);
}
}
static int invocations;
static boolean didStackWalk;
public static void main(String[] args) throws Throwable {
try (ResourceScope scope = ResourceScope.newConfinedScope()) {
MemoryAddress stub = linker.upcallStub(MH_m, FunctionDescriptor.ofVoid(), scope);
MemoryAddress stubAddress = stub.address();
invocations = 0;
didStackWalk = false;
payload(stubAddress);
assertTrue(didStackWalk);
}
}
static void payload(MemoryAddress cb) throws Throwable {
MH_asyncStackWalk.invokeExact(cb);
}
static void m() {
if (invocations++ >= 20000) { // warmup
didStackWalk = true;
WB.verifyFrames(/*log=*/true, /*updateRegisterMap=*/true);
WB.verifyFrames(/*log=*/true, /*updateRegisterMap=*/false); // triggers different code paths
}
}
}

View File

@ -0,0 +1,44 @@
/*
* Copyright (c) 2021, 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.
*
*/
#include <thread>
#ifdef _WIN64
#define EXPORT __declspec(dllexport)
#else
#define EXPORT
#endif
static void start(void (*cb)(void)) {
for (int i = 0; i < 25000; i++) {
cb();
}
}
extern "C" {
EXPORT void asyncStackWalk(void (*cb)(void)) {
std::thread thrd(start, cb);
thrd.join();
}
}