This commit is contained in:
Igor Ignatyev 2016-05-09 23:53:11 +02:00
commit b298fb9be2
24 changed files with 1771 additions and 73 deletions

View File

@ -0,0 +1,116 @@
#
# Copyright (c) 2016, 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. Oracle designates this
# particular file as subject to the "Classpath" exception as provided
# by Oracle in the LICENSE file that accompanied this code.
#
# 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.
#
GTEST_TEST_SRC := $(HOTSPOT_TOPDIR)/test/native
GTEST_FRAMEWORK_SRC := $(SRC_ROOT)/test/fmw/gtest
# On Windows, there are no internal debug symbols so must set copying to true
# to get any at all.
ifeq ($(OPENJDK_TARGET_OS), windows)
GTEST_COPY_DEBUG_SYMBOLS := true
else
GTEST_COPY_DEBUG_SYMBOLS := false
endif
################################################################################
GTEST_TEST_SRC_FILES := $(shell $(FIND) $(HOTSPOT_TOPDIR)/test/native -name \
"test*.cpp" -type f)
ifeq ($(OPENJDK_TARGET_OS), windows)
GTEST_JVM_MAPFILE := $(JVM_MAPFILE)
else
GTEST_JVM_MAPFILE := $(JVM_OUTPUTDIR)/gtest/mapfile
$(JVM_OUTPUTDIR)/gtest/symbols: $(JVM_OUTPUTDIR)/symbols
$(call MakeDir, $(@D))
( $(CAT) $< ; echo "runUnitTests" ) > $@
$(GTEST_JVM_MAPFILE): $(JVM_OUTPUTDIR)/gtest/symbols
$(call create-mapfile)
endif
# Disabling switch warning for clang because of test source.
$(eval $(call SetupNativeCompilation, BUILD_GTEST_LIBJVM, \
TOOLCHAIN := $(JVM_TOOLCHAIN), \
LIBRARY := jvm, \
OUTPUT_DIR := $(JVM_OUTPUTDIR)/gtest, \
EXTRA_FILES := $(GTEST_TEST_SRC_FILES) \
$(GTEST_FRAMEWORK_SRC)/src/gtest-all.cc \
$(GTEST_TEST_SRC)/gtestMain.cpp, \
OBJECT_DIR := $(JVM_OUTPUTDIR)/gtest/objs, \
EXTRA_OBJECT_FILES := $(filter-out %/operator_new$(OBJ_SUFFIX), \
$(BUILD_LIBJVM_ALL_OBJS)), \
CFLAGS := $(JVM_CFLAGS) -I$(GTEST_FRAMEWORK_SRC) \
-I$(GTEST_FRAMEWORK_SRC)/include \
-I$(GTEST_TEST_SRC), \
CFLAGS_windows := /EHsc, \
CFLAGS_solaris := -DGTEST_HAS_EXCEPTIONS=0 -library=stlport4, \
CFLAGS_macosx := -DGTEST_OS_MAC=1, \
CFLAGS_DEBUG_SYMBOLS := $(JVM_CFLAGS_SYMBOLS), \
CXXFLAGS_DEBUG_SYMBOLS := $(JVM_CFLAGS_SYMBOLS), \
DISABLED_WARNINGS_gcc := undef, \
DISABLED_WARNINGS_clang := undef switch format-nonliteral \
tautological-undefined-compare, \
DISABLED_WARNINGS_solstudio := identexpected, \
LDFLAGS := $(JVM_LDFLAGS), \
LDFLAGS_solaris := -library=stlport4 $(call SET_SHARED_LIBRARY_ORIGIN), \
LIBS := $(JVM_LIBS), \
OPTIMIZATION := $(JVM_OPTIMIZATION), \
MAPFILE := $(GTEST_JVM_MAPFILE), \
USE_MAPFILE_FOR_SYMBOLS := true, \
COPY_DEBUG_SYMBOLS := $(GTEST_COPY_DEBUG_SYMBOLS), \
ZIP_EXTERNAL_DEBUG_SYMBOLS := false, \
))
TARGETS += $(BUILD_GTEST_LIBJVM)
################################################################################
$(eval $(call SetupNativeCompilation, BUILD_GTEST_LAUNCHER, \
TOOLCHAIN := $(JVM_TOOLCHAIN), \
PROGRAM := gtestLauncher, \
OUTPUT_DIR := $(JVM_OUTPUTDIR)/gtest, \
EXTRA_FILES := $(GTEST_TEST_SRC)/gtestLauncher.cpp, \
OBJECT_DIR := $(JVM_OUTPUTDIR)/gtest/launcher-objs, \
CFLAGS := $(JVM_CFLAGS) -I$(GTEST_FRAMEWORK_SRC) \
-I$(GTEST_FRAMEWORK_SRC)/include, \
CFLAGS_DEBUG_SYMBOLS := $(JVM_CFLAGS_SYMBOLS), \
CXXFLAGS_DEBUG_SYMBOLS := $(JVM_CFLAGS_SYMBOLS), \
LDFLAGS := $(LDFLAGS_TESTEXE), \
LDFLAGS_unix := -L$(JVM_OUTPUTDIR)/gtest $(call SET_SHARED_LIBRARY_ORIGIN), \
LDFLAGS_solaris := -library=stlport4, \
LIBS_unix := -ljvm, \
LIBS_windows := $(JVM_OUTPUTDIR)/gtest/objs/jvm.lib, \
COPY_DEBUG_SYMBOLS := $(GTEST_COPY_DEBUG_SYMBOLS), \
ZIP_EXTERNAL_DEBUG_SYMBOLS := false, \
))
$(BUILD_GTEST_LAUNCHER): $(BUILD_GTEST_LIBJVM)
TARGETS += $(BUILD_GTEST_LAUNCHER)
################################################################################

View File

@ -37,6 +37,10 @@ include lib/CompileDtracePreJvm.gmk
include lib/CompileJvm.gmk
include lib/CompileDtracePostJvm.gmk
ifeq ($(BUILD_GTEST), true)
include lib/CompileGtest.gmk
endif
all: $(TARGETS)
.PHONY: all

View File

@ -153,20 +153,33 @@ $(JVM_OUTPUTDIR)/symbols: $(SYMBOLS_SRC)
################################################################################
# Finally convert the symbol list into a platform-specific mapfile
$(JVM_MAPFILE): $(JVM_OUTPUTDIR)/symbols
$(call LogInfo, Creating mapfile)
$(RM) $@
ifeq ($(OPENJDK_TARGET_OS), macosx)
# On macosx, we need to add a leading underscore
ifeq ($(OPENJDK_TARGET_OS), macosx)
# On macosx, we need to add a leading underscore
define create-mapfile-work
$(AWK) '{ if ($$0 ~ ".") { print " _" $$0 } }' < $^ > $@.tmp
else ifeq ($(OPENJDK_TARGET_OS), windows)
# On windows, add an 'EXPORTS' header
endef
else ifeq ($(OPENJDK_TARGET_OS), windows)
# On windows, add an 'EXPORTS' header
define create-mapfile-work
$(ECHO) "EXPORTS" > $@.tmp
$(AWK) '{ if ($$0 ~ ".") { print " " $$0 } }' < $^ >> $@.tmp
else
# Assume standard linker script
endef
else
# Assume standard linker script
define create-mapfile-work
$(PRINTF) "SUNWprivate_1.1 { \n global: \n" > $@.tmp
$(AWK) '{ if ($$0 ~ ".") { print " " $$0 ";" } }' < $^ >> $@.tmp
$(PRINTF) " local: \n *; \n }; \n" >> $@.tmp
endif
endef
endif
define create-mapfile
$(call LogInfo, Creating mapfile)
$(call MakeDir, $(@D))
$(call create-mapfile-work)
$(RM) $@
$(MV) $@.tmp $@
endef
$(JVM_MAPFILE): $(JVM_OUTPUTDIR)/symbols
$(call create-mapfile)

View File

@ -0,0 +1,67 @@
#
# Copyright (c) 2016, 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. Oracle designates this
# particular file as subject to the "Classpath" exception as provided
# by Oracle in the LICENSE file that accompanied this code.
#
# 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.
#
default: all
include $(SPEC)
include MakeBase.gmk
$(foreach v, $(JVM_VARIANTS), \
$(eval $(call SetupCopyFiles, COPY_GTEST_$v, \
SRC := $(HOTSPOT_OUTPUTDIR)/variant-$v/libjvm/gtest, \
DEST := $(TEST_IMAGE_DIR)/hotspot/gtest/$v, \
FILES := $(call SHARED_LIBRARY,jvm) gtestLauncher$(EXE_SUFFIX), \
)) \
$(eval TARGETS += $$(COPY_GTEST_$v)) \
)
ifeq ($(OPENJDK_TARGET_OS), windows)
$(foreach v, $(JVM_VARIANTS), \
$(eval $(call SetupCopyFiles, COPY_GTEST_MSVCR_$v, \
DEST := $(TEST_IMAGE_DIR)/hotspot/gtest/$v, \
FILES := $(MSVCR_DLL) $(MSVCP_DLL), \
FLATTEN := true, \
)) \
$(eval TARGETS += $$(COPY_GTEST_MSVCR_$v)) \
$(eval $(call SetupCopyFiles, COPY_GTEST_PDB_$v, \
SRC := $(HOTSPOT_OUTPUTDIR)/variant-$v/libjvm/gtest, \
DEST := $(TEST_IMAGE_DIR)/hotspot/gtest/$v, \
FILES := jvm.pdb gtestLauncher.pdb, \
)) \
$(eval TARGETS += $$(COPY_GTEST_PDB_$v)) \
)
endif
ifeq ($(OPENJDK_TARGET_OS), solaris)
$(foreach v, $(JVM_VARIANTS), \
$(eval $(call SetupCopyFiles, COPY_GTEST_STLPORT_$v, \
DEST := $(TEST_IMAGE_DIR)/hotspot/gtest/$v, \
FILES := $(STLPORT_LIB), \
)) \
$(eval TARGETS += $$(COPY_GTEST_STLPORT_$v)) \
)
endif
all: $(TARGETS)

View File

@ -47,6 +47,12 @@
// Check core dump limit and report possible place where core can be found
void os::check_dump_limit(char* buffer, size_t bufferSize) {
if (!FLAG_IS_DEFAULT(CreateCoredumpOnCrash) && !CreateCoredumpOnCrash) {
jio_snprintf(buffer, bufferSize, "CreateCoredumpOnCrash is disabled from command line");
VMError::record_coredump_status(buffer, false);
return;
}
int n;
struct rlimit rlim;
bool success;

View File

@ -664,64 +664,6 @@ void* Arena::internal_malloc_4(size_t x) {
// Non-product code
#ifndef PRODUCT
// The global operator new should never be called since it will usually indicate
// a memory leak. Use CHeapObj as the base class of such objects to make it explicit
// that they're allocated on the C heap.
// Commented out in product version to avoid conflicts with third-party C++ native code.
//
// In C++98/03 the throwing new operators are defined with the following signature:
//
// void* operator new(std::size_tsize) throw(std::bad_alloc);
// void* operator new[](std::size_tsize) throw(std::bad_alloc);
//
// while all the other (non-throwing) new and delete operators are defined with an empty
// throw clause (i.e. "operator delete(void* p) throw()") which means that they do not
// throw any exceptions (see section 18.4 of the C++ standard).
//
// In the new C++11/14 standard, the signature of the throwing new operators was changed
// by completely omitting the throw clause (which effectively means they could throw any
// exception) while all the other new/delete operators where changed to have a 'nothrow'
// clause instead of an empty throw clause.
//
// Unfortunately, the support for exception specifications among C++ compilers is still
// very fragile. While some more strict compilers like AIX xlC or HP aCC reject to
// override the default throwing new operator with a user operator with an empty throw()
// clause, the MS Visual C++ compiler warns for every non-empty throw clause like
// throw(std::bad_alloc) that it will ignore the exception specification. The following
// operator definitions have been checked to correctly work with all currently supported
// compilers and they should be upwards compatible with C++11/14. Therefore
// PLEASE BE CAREFUL if you change the signature of the following operators!
static void * zero = (void *) 0;
void* operator new(size_t size) /* throw(std::bad_alloc) */ {
fatal("Should not call global operator new");
return zero;
}
void* operator new [](size_t size) /* throw(std::bad_alloc) */ {
fatal("Should not call global operator new[]");
return zero;
}
void* operator new(size_t size, const std::nothrow_t& nothrow_constant) throw() {
fatal("Should not call global operator new");
return 0;
}
void* operator new [](size_t size, std::nothrow_t& nothrow_constant) throw() {
fatal("Should not call global operator new[]");
return 0;
}
void operator delete(void* p) throw() {
fatal("Should not call global delete");
}
void operator delete [](void* p) throw() {
fatal("Should not call global delete []");
}
void AllocatedObj::print() const { print_on(tty); }
void AllocatedObj::print_value() const { print_value_on(tty); }

View File

@ -0,0 +1,92 @@
/*
* Copyright (c) 1997, 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.
*
*/
#include "precompiled.hpp"
#include "utilities/debug.hpp"
#include <new>
//--------------------------------------------------------------------------------------
// Non-product code
#ifndef PRODUCT
// The global operator new should never be called since it will usually indicate
// a memory leak. Use CHeapObj as the base class of such objects to make it explicit
// that they're allocated on the C heap.
// Commented out in product version to avoid conflicts with third-party C++ native code.
//
// In C++98/03 the throwing new operators are defined with the following signature:
//
// void* operator new(std::size_tsize) throw(std::bad_alloc);
// void* operator new[](std::size_tsize) throw(std::bad_alloc);
//
// while all the other (non-throwing) new and delete operators are defined with an empty
// throw clause (i.e. "operator delete(void* p) throw()") which means that they do not
// throw any exceptions (see section 18.4 of the C++ standard).
//
// In the new C++11/14 standard, the signature of the throwing new operators was changed
// by completely omitting the throw clause (which effectively means they could throw any
// exception) while all the other new/delete operators where changed to have a 'nothrow'
// clause instead of an empty throw clause.
//
// Unfortunately, the support for exception specifications among C++ compilers is still
// very fragile. While some more strict compilers like AIX xlC or HP aCC reject to
// override the default throwing new operator with a user operator with an empty throw()
// clause, the MS Visual C++ compiler warns for every non-empty throw clause like
// throw(std::bad_alloc) that it will ignore the exception specification. The following
// operator definitions have been checked to correctly work with all currently supported
// compilers and they should be upwards compatible with C++11/14. Therefore
// PLEASE BE CAREFUL if you change the signature of the following operators!
static void * zero = (void *) 0;
void* operator new(size_t size) /* throw(std::bad_alloc) */ {
fatal("Should not call global operator new");
return zero;
}
void* operator new [](size_t size) /* throw(std::bad_alloc) */ {
fatal("Should not call global operator new[]");
return zero;
}
void* operator new(size_t size, const std::nothrow_t& nothrow_constant) throw() {
fatal("Should not call global operator new");
return 0;
}
void* operator new [](size_t size, std::nothrow_t& nothrow_constant) throw() {
fatal("Should not call global operator new[]");
return 0;
}
void operator delete(void* p) throw() {
fatal("Should not call global delete");
}
void operator delete [](void* p) throw() {
fatal("Should not call global delete []");
}
#endif // Non-product

View File

@ -2070,6 +2070,9 @@ public:
notproduct(bool, VerboseInternalVMTests, false, \
"Turn on logging for internal VM tests.") \
\
product(bool, ExecutingUnitTests, false, \
"Whether the JVM is running unit tests or not") \
\
product_pd(bool, UseTLAB, "Use thread-local object allocation") \
\
product_pd(bool, ResizeTLAB, \

View File

@ -1609,8 +1609,8 @@ JVM_ENTRY(void, jmm_SetVMGlobal(JNIEnv *env, jstring flag_name, jvalue new_value
}
char* name = java_lang_String::as_utf8_string(fn);
FormatBuffer<80> err_msg("%s", "");
int succeed = WriteableFlags::set_flag(name, new_value, Flag::MANAGEMENT, err_msg);
FormatBuffer<80> error_msg("%s", "");
int succeed = WriteableFlags::set_flag(name, new_value, Flag::MANAGEMENT, error_msg);
if (succeed != Flag::SUCCESS) {
if (succeed == Flag::MISSING_VALUE) {
@ -1619,7 +1619,7 @@ JVM_ENTRY(void, jmm_SetVMGlobal(JNIEnv *env, jstring flag_name, jvalue new_value
} else {
// all the other errors are reported as IAE with the appropriate error message
THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
err_msg.buffer());
error_msg.buffer());
}
}
assert(succeed == Flag::SUCCESS, "Setting flag should succeed");

View File

@ -58,6 +58,8 @@
#include "trace/tracing.hpp"
#endif
#include <stdio.h>
#ifndef ASSERT
# ifdef _DEBUG
// NOTE: don't turn the lines below into a comment -- if you're getting
@ -187,7 +189,7 @@ bool error_is_suppressed(const char* file_name, int line_no) {
return true;
}
if (!is_error_reported()) {
if (!is_error_reported() && !SuppressFatalErrorMessage) {
// print a friendly hint:
fdStream out(defaultStream::output_fd());
out.print_raw_cr("# To suppress the following error report, specify this argument");
@ -262,6 +264,21 @@ void report_unimplemented(const char* file, int line) {
report_vm_error(file, line, "Unimplemented()");
}
#ifdef ASSERT
bool is_executing_unit_tests() {
return ExecutingUnitTests;
}
void report_assert_msg(const char* msg, ...) {
va_list ap;
va_start(ap, msg);
fprintf(stderr, "assert failed: %s\n", err_msg(FormatBufferDummy(), msg, ap).buffer());
va_end(ap);
}
#endif // ASSERT
void report_untested(const char* file, int line, const char* message) {
#ifndef PRODUCT
warning("Untested: %s in %s: %d\n", message, file, line);

View File

@ -46,11 +46,15 @@ class FormatBufferResource : public FormatBufferBase {
FormatBufferResource(const char * format, ...) ATTRIBUTE_PRINTF(2, 3);
};
class FormatBufferDummy {};
// Use stack for buffer
template <size_t bufsz = FormatBufferBase::BufferSize>
class FormatBuffer : public FormatBufferBase {
public:
inline FormatBuffer(const char* format, ...) ATTRIBUTE_PRINTF(2, 3);
// since va_list is unspecified type (can be char*), we use FormatBufferDummy to disambiguate these constructors
inline FormatBuffer(FormatBufferDummy dummy, const char* format, va_list ap) ATTRIBUTE_PRINTF(3, 0);
inline void append(const char* format, ...) ATTRIBUTE_PRINTF(2, 3);
inline void print(const char* format, ...) ATTRIBUTE_PRINTF(2, 3);
inline void printv(const char* format, va_list ap) ATTRIBUTE_PRINTF(2, 0);
@ -74,6 +78,11 @@ FormatBuffer<bufsz>::FormatBuffer(const char * format, ...) : FormatBufferBase(_
va_end(argp);
}
template <size_t bufsz>
FormatBuffer<bufsz>::FormatBuffer(FormatBufferDummy dummy, const char * format, va_list ap) : FormatBufferBase(_buffer) {
jio_vsnprintf(_buf, bufsz, format, ap);
}
template <size_t bufsz>
FormatBuffer<bufsz>::FormatBuffer() : FormatBufferBase(_buffer) {
_buf[0] = '\0';
@ -119,11 +128,13 @@ typedef FormatBuffer<> err_msg;
#define vmassert(p, ...) \
do { \
if (!(p)) { \
if (is_executing_unit_tests()) { \
report_assert_msg(__VA_ARGS__); \
} \
report_vm_error(__FILE__, __LINE__, "assert(" #p ") failed", __VA_ARGS__); \
BREAKPOINT; \
} \
} while (0)
#endif
// For backward compatibility.
@ -210,10 +221,16 @@ void report_vm_error(const char* file, int line, const char* error_msg);
// ATTRIBUTE_PRINTF works with gcc >= 4.8 and any other compiler.
void report_vm_error(const char* file, int line, const char* error_msg,
const char* detail_fmt, ...) ATTRIBUTE_PRINTF(4, 5);
#ifdef ASSERT
void report_assert_msg(const char* msg, ...) ATTRIBUTE_PRINTF(1, 2);
#endif // ASSERT
#else
// GCC < 4.8 warns because of empty format string. Warning can not be switched off selectively.
void report_vm_error(const char* file, int line, const char* error_msg,
const char* detail_fmt, ...);
#ifdef ASSERT
void report_assert_msg(const char* msg, ...);
#endif // ASSERT
#endif
void report_vm_status_error(const char* file, int line, const char* error_msg,
int status, const char* detail);
@ -225,6 +242,11 @@ void report_should_not_reach_here(const char* file, int line);
void report_unimplemented(const char* file, int line);
void report_untested(const char* file, int line, const char* message);
#ifdef ASSERT
// unit test support
bool is_executing_unit_tests();
#endif // ASSERT
void warning(const char* format, ...) ATTRIBUTE_PRINTF(1, 2);
// Compile-time asserts. Cond must be a compile-time constant expression that

View File

@ -52,6 +52,11 @@ UNIQ = uniq
WC = wc
ZIP = zip
define NEWLINE
endef
# Get OS name from uname (Cygwin inexplicably adds _NT-5.1)
UNAME_S := $(shell $(UNAME) -s | $(CUT) -f1 -d_)
ifeq ($(UNAME_S), SunOS)
@ -427,6 +432,20 @@ PHONY_LIST += hotspot_servertest servertest
################################################################
# Run the native gtest tests from the test image
hotspot_gtest:
$(foreach v, $(JVM_VARIANTS), \
$(MAKE) hotspot_gtest$v $(NEWLINE) )
hotspot_gtestserver hotspot_gtestclient hotspot_gtestminimal: hotspot_gtest%:
$(TESTNATIVE_DIR)/hotspot/gtest/$*/gtestLauncher \
-jdk $(shell $(GETMIXEDPATH) "$(PRODUCT_HOME)")
PHONY_LIST += hotspot_gtest hotspot_gtestserver hotspot_gtestclient \
hotspot_gtestminimal
################################################################
# Phony targets (e.g. these are not filenames)
.PHONY: all clean prep $(PHONY_LIST)

View File

@ -0,0 +1,199 @@
/*
* Copyright (c) 2016, 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.
*
*/
package gc.g1.humongousObjects.objectGraphTest;
import gc.testlibrary.Helpers;
import jdk.test.lib.Asserts;
import sun.hotspot.WhiteBox;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;
/**
* Provides methods to initiate GC of requested type and
* checks for states of humongous and non-humongous soft/weak externally
* referenced objects after GCs
*/
public enum GC {
YOUNG_GC {
@Override
public Runnable get() {
return WHITE_BOX::youngGC;
}
public Consumer<ReferenceInfo<Object[]>> getChecker() {
return getCheckerImpl(false, false, true, false);
}
@Override
public List<String> shouldContain() {
return Arrays.asList(GCTokens.WB_INITIATED_YOUNG_GC);
}
@Override
public List<String> shouldNotContain() {
return Arrays.asList(GCTokens.WB_INITIATED_MIXED_GC, GCTokens.FULL_GC, GCTokens.WB_INITIATED_CMC,
GCTokens.CMC, GCTokens.YOUNG_GC);
}
},
FULL_GC {
@Override
public Runnable get() {
return System::gc;
}
public Consumer<ReferenceInfo<Object[]>> getChecker() {
return getCheckerImpl(true, false, true, false);
}
@Override
public List<String> shouldContain() {
return Arrays.asList(GCTokens.FULL_GC);
}
@Override
public List<String> shouldNotContain() {
return Arrays.asList(GCTokens.WB_INITIATED_YOUNG_GC, GCTokens.WB_INITIATED_MIXED_GC,
GCTokens.WB_INITIATED_CMC, GCTokens.CMC, GCTokens.YOUNG_GC);
}
},
FULL_GC_MEMORY_PRESSURE {
@Override
public Runnable get() {
return WHITE_BOX::fullGC;
}
public Consumer<ReferenceInfo<Object[]>> getChecker() {
return getCheckerImpl(true, true, true, true);
}
@Override
public List<String> shouldContain() {
return Arrays.asList(GCTokens.FULL_GC_MEMORY_PRESSURE);
}
@Override
public List<String> shouldNotContain() {
return Arrays.asList(GCTokens.WB_INITIATED_YOUNG_GC, GCTokens.WB_INITIATED_MIXED_GC,
GCTokens.WB_INITIATED_CMC, GCTokens.CMC, GCTokens.YOUNG_GC, GCTokens.FULL_GC);
}
};
protected String getErrorMessage(ReferenceInfo<Object[]> ref, boolean expectedNull, String gcType) {
return String.format("Externally effectively %s referenced %shumongous object was%s deleted after %s",
(ref.softlyReachable ? "soft" : "weak"), (ref.effectiveHumongous ? "" : "non-"),
(expectedNull ? " not" : ""), gcType);
}
protected Consumer<ReferenceInfo<Object[]>> getCaseCheck(boolean expectedNull) {
return expectedNull
? r -> Asserts.assertNull(r.reference.get(), getErrorMessage(r, true, name()))
: r -> Asserts.assertNotNull(r.reference.get(), getErrorMessage(r, false, name()));
}
protected Consumer<ReferenceInfo<Object[]>> getCheckerImpl(boolean weakH, boolean softH,
boolean weakS, boolean softS) {
return new Checker(getCaseCheck(weakH), getCaseCheck(softH), getCaseCheck(weakS), getCaseCheck(softS));
}
protected String getGcLogName(String prefix) {
return prefix + "_" + name() + ".gc.log";
}
private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox();
/**
* @return method to initiate GC
*/
public abstract Runnable get();
/**
* @return checker for objects' states after GC
*/
public abstract Consumer<ReferenceInfo<Object[]>> getChecker();
/**
* @return list of tokens that should be contained in gc log after gc of specified type
*/
public abstract List<String> shouldContain();
/**
* @return list of tokens that should not be contained in gc log after gc of specified type
*/
public abstract List<String> shouldNotContain();
/**
* Checks object' state after gc
* Contains 4 Consumers which are called depending on humongous/non-humongous and
* external weak/soft referenced objects
*/
private static class Checker implements Consumer<ReferenceInfo<Object[]>> {
// 4 consumers with checks for (humongous /simple objects)*(weak/soft referenced)
final Consumer<ReferenceInfo<Object[]>> weakHumongousCheck;
final Consumer<ReferenceInfo<Object[]>> softHumongousCheck;
final Consumer<ReferenceInfo<Object[]>> weakSimpleCheck;
final Consumer<ReferenceInfo<Object[]>> softSimpleCheck;
public Checker(Consumer<ReferenceInfo<Object[]>> weakHumongousCheck,
Consumer<ReferenceInfo<Object[]>> softHumongousCheck,
Consumer<ReferenceInfo<Object[]>> weakSimpleCheck,
Consumer<ReferenceInfo<Object[]>> softSimpleCheck) {
this.weakHumongousCheck = weakHumongousCheck;
this.softHumongousCheck = softHumongousCheck;
this.weakSimpleCheck = weakSimpleCheck;
this.softSimpleCheck = softSimpleCheck;
}
public void accept(ReferenceInfo<Object[]> ref) {
System.out.println("reference.get() returned " + ref.reference.get());
if (ref.effectiveHumongous && ref.softlyReachable) {
System.out.println("soft and humongous");
softHumongousCheck.accept(ref);
}
if (ref.effectiveHumongous && !ref.softlyReachable) {
System.out.println("weak and humongous");
weakHumongousCheck.accept(ref);
}
if (!ref.effectiveHumongous && ref.softlyReachable) {
System.out.println("soft and non-humongous");
softSimpleCheck.accept(ref);
}
if (!ref.effectiveHumongous && !ref.softlyReachable) {
System.out.println("weak and non-humongous");
weakSimpleCheck.accept(ref);
}
}
}
}

View File

@ -0,0 +1,42 @@
/*
* Copyright (c) 2016, 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.
*
*/
package gc.g1.humongousObjects.objectGraphTest;
/**
* Contains tokens that could appear in gc log
*/
public final class GCTokens {
// Private c-tor to prevent instantiating
private GCTokens() {
}
public static final String WB_INITIATED_YOUNG_GC = "Young (WhiteBox Initiated Young GC)";
public static final String WB_INITIATED_MIXED_GC = "Pause Mixed (WhiteBox Initiated Young GC)";
public static final String WB_INITIATED_CMC = "WhiteBox Initiated Concurrent Mark";
public static final String FULL_GC = "Full (System.gc())";
public static final String FULL_GC_MEMORY_PRESSURE = "WhiteBox Initiated Full GC";
public static final String CMC = "Concurrent Mark)";
public static final String YOUNG_GC = "GC pause (young)";
}

View File

@ -0,0 +1,150 @@
/*
* Copyright (c) 2016, 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.
*
*/
package gc.g1.humongousObjects.objectGraphTest;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Predicate;
public class ObjectGraph {
private ObjectGraph() {
}
public enum ReferenceType {
NONE,
WEAK,
SOFT,
STRONG;
}
/**
* Performs operation on all nodes that are reachable from initial ones
*
* @param nodes initial nodes
* @param operation operation
*/
public static void propagateTransitiveProperty(Set<Object[]> nodes, Consumer<Object[]> operation) {
Deque<Object[]> roots = new ArrayDeque<>();
nodes.stream().forEach(roots::push);
ObjectGraph.enumerateAndMark(roots, operation);
}
/**
* Connects graph's vertexes with single-directed (vertex -> neighbour) link
*
* @param vertex who is connected
* @param neighbour connected to whom
*/
private static void connectVertexes(Object[] vertex, Object[] neighbour) {
// check if vertex array is full
if (vertex[vertex.length - 1] != null) {
throw new Error("Array is full and no connections could be added");
}
int i = 0;
while (vertex[i] != null) {
++i;
}
vertex[i] = neighbour;
}
/**
* Builds object graph using description from list of parsed nodes. Graph uses Object[] as nodes, first n elements
* of array are links to connected nodes, others are null. Then runs visitors on generated graph
*
* @param parsedNodes list of nodes' description
* @param visitors visitors that will visit each node of generated graph
* @param humongousAllocationSize size of humongous node
* @param simpleAllocationSize size of simple (non-humongous) node
* @return root reference to generated graph
*/
public static Object[] generateObjectNodes(List<TestcaseData.FinalParsedNode> parsedNodes,
Map<Predicate<TestcaseData.FinalParsedNode>,
BiConsumer<TestcaseData.FinalParsedNode, Object[][]>> visitors,
int humongousAllocationSize, int simpleAllocationSize) {
Object[][] objectNodes = new Object[parsedNodes.size()][];
// Allocating nodes on Object[]
for (int i = 0; i < parsedNodes.size(); ++i) {
objectNodes[i] = new Object[(parsedNodes.get(i).isHumongous ?
humongousAllocationSize : simpleAllocationSize)];
}
// Connecting nodes on allocated on Object[]
for (int i = 0; i < parsedNodes.size(); ++i) {
for (int j = 0; j < parsedNodes.get(i).getConnectedTo().size(); ++j) {
connectVertexes(objectNodes[i], objectNodes[parsedNodes.get(i).getConnectedTo().get(j)]);
}
}
// Calling visitors
visitors.entrySet()
.stream()
.forEach(
entry -> parsedNodes.stream()
.filter(parsedNode -> entry.getKey().test(parsedNode))
.forEach(node -> entry.getValue().accept(node, objectNodes))
);
return objectNodes[0];
}
/**
* Enumerates graph starting with provided vertexes. All vertexes that are reachable from the provided ones are
* marked
*
* @param markedParents provided vertexes
* @param markVertex lambda which marks vertexes
*/
public static void enumerateAndMark(Deque<Object[]> markedParents,
Consumer<Object[]> markVertex) {
Map<Object[], Boolean> isVisited = new HashMap<>();
while (!markedParents.isEmpty()) {
Object[] vertex = markedParents.pop();
if (vertex == null || isVisited.containsKey(vertex)) {
continue;
}
isVisited.put(vertex, true);
markVertex.accept(vertex);
for (int i = 0; i < vertex.length; ++i) {
if (vertex[i] == null) {
break;
}
markedParents.add((Object[]) vertex[i]);
}
}
}
}

View File

@ -0,0 +1,56 @@
/*
* Copyright (c) 2016, 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.
*
*/
The test checks that after different type of GC unreachable objects behave as expected:
1. Young GC - weakly referenced non-humongous objects are collected, other objects are not collected.
2. Full GC - weakly referenced non-humongous and humongous objects are collected, softly referenced non-humongous and
humongous objects are not collected.
3. Full GC with memory pressure - weakly and softly referenced non-humongous and humongous objects are collected.
The test gets gc type as a command line argument.
Then the test allocates object graph in heap (currently testing scenarios are pre-generated and stored in
TestcaseData.getPregeneratedTestcases()) with TestObjectGraphAfterGC::allocateObjectGraph.
Since we are testing humongous objects we need pretty unusual nodes - arrays of Object.
We need this since only large enough array could be Humongous object (in fact class with huge amount of fields is
humongous too but it's for other tests).
ObjectGraph class generates object graph with Object[] nodes. It also provides a way to collect
information about each node using "visitor" pattern.
Using visitors we build Set of ReferenceInfo instances which contains the following information:
reference - external weak/soft reference to graph's node
graphId and nodeId - graph's and node's ids - we need this for error handling
softlyReachable - is node effectively referenced by external soft reference. It could be when external
soft reference or when this node is reachable from node that exteranally referenced by soft reference
effectiveHumongous - if node behaves effectively humongous. It could be when node is humongous
or when this node is reachable from humongous node.
When we leave TestObjectGraphAfterGC::allocateObjectGraph we make graph reachable only with references from Set of
ReferenceInfo instances.
We run specified gc and check that each instance of ReferenceInfo set behaves as expected.
Then we check that gc log file contains expected tokens and doesn't contain tokens that it should not contain.

View File

@ -0,0 +1,63 @@
/*
* Copyright (c) 2016, 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.
*
*/
package gc.g1.humongousObjects.objectGraphTest;
import java.lang.ref.Reference;
/**
* Immutable structure that holds the following information about graph's node
* reference - weak/soft reference to graph's node
* graphId and nodeId - graph's and node's ids - we need this for error handling
* softlyReachable - is node effectively referenced by external soft reference. It could be when external
* soft reference or when this node is reachable from node that externally referenced by soft reference
* effectiveHumongous - if node behaves effectively humongous. It could be when node is humongous
* or when this node is reachable from humongous node.
*
* @param <T> - actual type of node
*/
public class ReferenceInfo<T> {
public final Reference<T> reference;
public final String graphId;
public final String nodeId;
public final boolean softlyReachable;
public final boolean effectiveHumongous;
public ReferenceInfo(Reference<T> reference, String graphId, String nodeId, boolean softlyReachable,
boolean effectiveHumongous) {
this.reference = reference;
this.graphId = graphId;
this.nodeId = nodeId;
this.softlyReachable = softlyReachable;
this.effectiveHumongous = effectiveHumongous;
}
@Override
public String toString() {
return String.format("Node %s is effectively %shumongous and effectively %ssoft referenced\n"
+ "\tReference type is %s and it points to %s", nodeId,
(effectiveHumongous ? "" : "non-"), (softlyReachable ? "" : "non-"),
reference.getClass().getSimpleName(), reference.get());
}
}

View File

@ -0,0 +1,247 @@
/*
* Copyright (c) 2016, 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.
*
*/
package gc.g1.humongousObjects.objectGraphTest;
import jdk.test.lib.OutputAnalyzer;
import sun.hotspot.WhiteBox;
import java.io.File;
import java.io.IOException;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
import java.lang.ref.WeakReference;
import java.nio.file.Files;
import java.util.Map;
import java.util.HashMap;
import java.util.List;
import java.util.HashSet;
import java.util.Set;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.stream.Collectors;
/**
* @test TestObjectGraphAfterGC
* @summary Checks that objects' graph behave as expected after gc
* @requires vm.gc=="G1" | vm.gc=="null"
* @requires vm.opt.ExplicitGCInvokesConcurrent != true
* @library /testlibrary /test/lib /
* @modules java.management java.base/jdk.internal.misc
* @build sun.hotspot.WhiteBox
* gc.testlibrary.Helpers
* gc.g1.humongousObjects.objectGraphTest.GCTokens
* gc.g1.humongousObjects.objectGraphTest.ReferenceInfo
* gc.g1.humongousObjects.objectGraphTest.GC
* gc.g1.humongousObjects.objectGraphTest.ObjectGraph
* gc.g1.humongousObjects.objectGraphTest.TestObjectGraphAfterGC
* @run driver ClassFileInstaller sun.hotspot.WhiteBox
* sun.hotspot.WhiteBox$WhiteBoxPermission
*
* @run main/othervm -Xms200M -XX:+UseG1GC -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
* -XX:G1HeapRegionSize=1M -Xlog:gc*=debug:file=TestObjectGraphAfterGC_YOUNG_GC.gc.log
* gc.g1.humongousObjects.objectGraphTest.TestObjectGraphAfterGC YOUNG_GC
*
* @run main/othervm -Xms200M -XX:+UseG1GC -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
* -XX:G1HeapRegionSize=1M -Xlog:gc=info:file=TestObjectGraphAfterGC_FULL_GC.gc.log
* gc.g1.humongousObjects.objectGraphTest.TestObjectGraphAfterGC FULL_GC
*
* @run main/othervm -Xms200M -XX:+UseG1GC -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
* -XX:G1HeapRegionSize=1M -Xlog:gc=info:file=TestObjectGraphAfterGC_FULL_GC_MEMORY_PRESSURE.gc.log
* gc.g1.humongousObjects.objectGraphTest.TestObjectGraphAfterGC FULL_GC_MEMORY_PRESSURE
*
*/
/**
* Checks that objects' graph behave as expected after gc
* See README file for detailed info on test's logic
*/
public class TestObjectGraphAfterGC {
private static final int simpleAllocationSize = 1024;
/**
* Entry point
*
* @param args - first argument - gc name
*/
public static void main(String[] args) {
if (args.length < 1) {
throw new Error("Expected gc name wasn't provided as command line argument");
}
GC gcType = GC.valueOf(args[0].toUpperCase());
System.out.println("Testing " + gcType.name());
TestcaseData.getPregeneratedTestcases().stream().forEach(testcase -> {
System.out.println("Testcase: " + testcase);
try {
TestObjectGraphAfterGC.doTesting(testcase, gcType.get(), gcType.getChecker(),
gcType.getGcLogName(TestObjectGraphAfterGC.class.getSimpleName()), gcType.shouldContain(),
gcType.shouldNotContain());
} catch (IOException e) {
throw new Error("Problems trying to find or open " + TestObjectGraphAfterGC.class.getSimpleName()
+ ".gc.log", e);
}
System.out.println(" Passed");
});
}
/**
* Implements testing with 3 methods - allocateObjectGraph, checkResults and checkGCLog
*
* @param testcaseData testcase in the following notation:
* H - humongous node
* S - non-humongous node
* s - external soft reference
* w - external weak reference
* Hs->Sw - 1st node is humongous, externally soft referenced and strong references to
* non-humongous node 2 which is externally weak referenced
* H->1 - humongous node connects to the first node of chain
* @param doGC method that initiates gc
* @param checker consumer that checks node's state after gc and throws Error if it's wrong
* @param gcLogName name of gc log
* @param shouldContain list of tokens that should be contained in gc log
* @param shouldNotContain list of tokens that should not be contained in gc log
* @throws IOException if there are some issues with gc log
*/
private static void doTesting(String testcaseData, Runnable doGC, Consumer<ReferenceInfo<Object[]>> checker,
String gcLogName, List<String> shouldContain, List<String> shouldNotContain)
throws IOException {
Set<ReferenceInfo<Object[]>> nodeData = allocateObjectGraph(testcaseData);
doGC.run();
checkResults(nodeData, checker);
checkGCLog(gcLogName, shouldContain, shouldNotContain);
}
/**
* Allocates a number of objects of humongous and regular size and links then with strong references.
* How many objects to create, their size and links between them is encoded in the given parameters.
* As the result an object graph will be created.
* For the testing purpose for each created object (a graph node) an extra ReferenceInfo object will be created.
* The ReferenceInfo instances will contain either weak or soft reference to the graph node.
*
* @param testcaseData testcase in the
* <p>
* H - humongous node
* S - non-humongous node
* s - external soft reference
* w - external weak reference
* Hs->Sw - 1st node is humongous, externally soft referenced and strong references to
* non-humongous node 2 which is externally weak referenced
* H->1 - humongous node connects to the first node of chain
* @return set of ReferenceInfo objects containing weak/soft reference to the graph node and other data on how
* objects should behave after gc
*/
private static Set<ReferenceInfo<Object[]>> allocateObjectGraph(String testcaseData) {
Map<Object[], String> nodeIds = new HashMap<>();
Set<Object[]> humongousNodes = new HashSet<>();
Set<Object[]> externalSoftReferenced = new HashSet<>();
Set<Object[]> externalWeakReferenced = new HashSet<>();
Map<Predicate<TestcaseData.FinalParsedNode>, BiConsumer<TestcaseData.FinalParsedNode, Object[][]>> visitors
= new HashMap<>();
visitors.put((parsedNode -> true),
(parsedNode, objects) -> nodeIds.put(objects[Integer.valueOf(parsedNode.id)], parsedNode.id)
);
visitors.put((parsedNode -> parsedNode.isHumongous),
(parsedNode, objects) -> humongousNodes.add(objects[Integer.valueOf(parsedNode.id)])
);
visitors.put(parsedNode -> parsedNode.getReferencesTypes().stream().
anyMatch(referenceType -> referenceType == ObjectGraph.ReferenceType.SOFT),
(parsedNode, objects) -> externalSoftReferenced.add(objects[Integer.valueOf(parsedNode.id)])
);
visitors.put(parsedNode -> parsedNode.getReferencesTypes().stream().
anyMatch(referenceType -> referenceType == ObjectGraph.ReferenceType.WEAK),
(parsedNode, objects) -> externalWeakReferenced.add(objects[Integer.valueOf(parsedNode.id)])
);
List<TestcaseData.FinalParsedNode> internalParsedNodes = TestcaseData.parse(testcaseData);
Object[] root = ObjectGraph.generateObjectNodes(internalParsedNodes, visitors,
WhiteBox.getWhiteBox().g1RegionSize(), simpleAllocationSize);
ObjectGraph.propagateTransitiveProperty(humongousNodes, humongousNodes::add);
Set<Object[]> effectiveSoftReferenced = new HashSet<>();
ObjectGraph.propagateTransitiveProperty(externalSoftReferenced, effectiveSoftReferenced::add);
// Create external references
ReferenceQueue<Object[]> referenceQueue = new ReferenceQueue<>();
Set<Reference<Object[]>> externalRefs = new HashSet<>();
externalWeakReferenced.stream()
.forEach(objects -> externalRefs.add(new WeakReference<>(objects, referenceQueue)));
externalSoftReferenced.stream()
.forEach(objects -> externalRefs.add(new SoftReference<>(objects, referenceQueue)));
return externalRefs.stream()
.map(ref -> new ReferenceInfo<>(ref, testcaseData, nodeIds.get(ref.get()),
effectiveSoftReferenced.contains(ref.get()), humongousNodes.contains(ref.get())))
.collect(Collectors.toSet());
}
/**
* Checks that object' state after gc is as expected
*
* @param nodeData array with information about nodes
* @param checker consumer that checks node's state after gc and throws Error if it's wrong
*/
private static void checkResults(Set<ReferenceInfo<Object[]>> nodeData, Consumer<ReferenceInfo<Object[]>> checker) {
nodeData.stream().forEach(checker::accept);
}
/**
* Checks that gc log contains what we expected and does not contain what we didn't expect
*
* @param gcLogName gc log name
* @param shouldContain list of tokens that should be contained in gc log
* @param shouldNotContain list of tokens that should not be contained in gc log
* @throws IOException if there are some issues with gc log
*/
private static void checkGCLog(String gcLogName, List<String> shouldContain, List<String> shouldNotContain)
throws IOException {
if (gcLogName == null) {
return;
}
String gcLog = new String(Files.readAllBytes(new File(gcLogName).toPath()));
OutputAnalyzer outputAnalyzer = new OutputAnalyzer(gcLog, "");
shouldContain.stream().forEach(outputAnalyzer::shouldContain);
shouldNotContain.stream().forEach(outputAnalyzer::shouldNotContain);
}
}

View File

@ -0,0 +1,207 @@
/*
* Copyright (c) 2016, 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.
*
*/
package gc.g1.humongousObjects.objectGraphTest;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
public final class TestcaseData {
/**
* Temporary node description used during parsing
*/
private static class InternalParsedNode {
public String id;
public final ArrayList<Integer> connectedTo = new ArrayList<>();
public final ArrayList<Integer> connectedFrom = new ArrayList<>();
public final List<ObjectGraph.ReferenceType> referencesTypes = new ArrayList<>();
public boolean isHumongous;
}
/**
* Immutable node description.
* Contains:
* Node id
* Humongous flag
* List of external references' types
* List of nodes connected to
*/
public static class FinalParsedNode {
public final String id;
public final boolean isHumongous;
private final List<ObjectGraph.ReferenceType> referencesTypes;
private final ArrayList<Integer> connectedTo;
public FinalParsedNode(InternalParsedNode internalParsedNode) {
referencesTypes = internalParsedNode.referencesTypes;
connectedTo = internalParsedNode.connectedTo;
id = internalParsedNode.id;
isHumongous = internalParsedNode.isHumongous;
}
public List<ObjectGraph.ReferenceType> getReferencesTypes() {
return Collections.unmodifiableList(referencesTypes);
}
public List<Integer> getConnectedTo() {
return Collections.unmodifiableList(connectedTo);
}
}
/**
* @param testcaseDesc testcase in the following notation:
* H - humongous node
* S - non-humongous node
* s - external soft reference
* w - external weak reference
* Hs->Sw - 1st node is humongous, externally soft referenced and strong references to non-humongous node 2 which is
* externally weak referenced
* H->1 - humongous node connects to the first node of chain
* @return list of nodes description in FinalParsedNode structure
*/
public static List<FinalParsedNode> parse(String testcaseDesc) {
String[] nodes = testcaseDesc.split("-");
List<InternalParsedNode> internalParsedNodeList = new ArrayList<>();
for (int i = 0; i < nodes.length; ++i) {
String node = nodes[i];
InternalParsedNode nd;
if (node.contains("1")) {
nd = internalParsedNodeList.get(0);
} else {
nd = new InternalParsedNode();
internalParsedNodeList.add(nd);
nd.id = String.valueOf(i);
}
if (node.startsWith(">")) {
nd.connectedFrom.add(i - 1);
}
if (node.endsWith("<")) {
nd.connectedFrom.add(i + 1);
}
if (node.contains("w")) {
nd.referencesTypes.add(ObjectGraph.ReferenceType.WEAK);
}
if (node.contains("s")) {
nd.referencesTypes.add(ObjectGraph.ReferenceType.SOFT);
}
if (node.contains("H")) {
nd.isHumongous = true;
}
if (node.contains("S")) {
nd.isHumongous = false;
}
}
// we have connectedFrom but we need to get connectedTo
for (int i = 0; i < internalParsedNodeList.size(); ++i) {
for (Integer reference : internalParsedNodeList.get(i).connectedFrom) {
internalParsedNodeList.get(reference).connectedTo.add(i);
}
}
List<FinalParsedNode> finalParsedNodes = internalParsedNodeList.stream().map(FinalParsedNode::new)
.collect(Collectors.toList());
return finalParsedNodes;
}
/**
* @return List of pregenerated testing cases
*/
public static List<String> getPregeneratedTestcases() {
return Arrays.asList(
"Hw",
"Sw",
"Sw->Hw",
"Hw->Sw",
"Sw<->Hw",
"Sw<->Sw",
"Hw->Sw->Sw",
"Hw->Sw->Sw",
"Sw->Hw->Sw",
"Hw->Sw->Sw->1",
"Sw->Hw->Sw->1",
"Sw->Hw->Hw->1",
"Sw<->Hw<->Hw->1",
"Sw<->Hw<->Sw->1",
"Sw->Hw<->Sw",
"Hs",
"Ss",
"Ss->Hs",
"Hs->Ss",
"Ss<->Hs",
"Ss<->Ss",
"Hs->Ss->Ss",
"Hs->Ss->Ss",
"Ss->Hs->Ss",
"Hs->Ss->Ss->1",
"Ss->Hs->Ss->1",
"Ss->Hs->Hs->1",
"Ss<->Hs<->Hs->1",
"Ss<->Hs<->Ss->1",
"Ss->Hs<->Ss",
"Ss->Hw",
"Sw->Hs",
"Hs->Sw",
"Hw->Ss",
"Ss<->Hw",
"Sw<->Hs",
"Ss<->Sw",
"Sw<->Ss",
"Hs->Sw->Sw",
"Hw->Ss->Sw",
"Hw->Sw->Ss",
"Ss->Hw->Sw",
"Sw->Hs->Sw",
"Sw->Hw->Ss",
"Hs->Sw->Sw->1",
"Hw->Ss->Sw->1",
"Hw->Sw->Ss->1",
"Ss->Hw->Sw->1",
"Ss->Hs->Sw->1",
"Sw->Hw->Ss->1",
"Ss->Hw->Hw->1",
"Sw->Hs->Hw->1",
"Sw->Hw->Hs->1",
"Ss<->Hw<->Hw->1",
"Sw<->Hs<->Hw->1",
"Sw<->Hw<->Hs->1",
"Ss<->Hw<->Sw->1",
"Sw<->Hs<->Sw->1",
"Sw<->Hw<->Ss->1",
"Ss->Hw<->Sw",
"Sw->Hs<->Sw",
"Sw->Hw<->Ss"
);
}
}

View File

@ -0,0 +1,34 @@
/*
* Copyright (c) 2016, 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 "prims/jni.h"
extern "C" {
JNIIMPORT void JNICALL runUnitTests(int argv, char** argc);
}
int main(int argc, char** argv) {
runUnitTests(argc, argv);
return 0;
}

View File

@ -0,0 +1,203 @@
/*
* Copyright (c) 2016, 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 <stdio.h>
#include <string.h>
#include <stdlib.h>
#ifdef __APPLE__
# include <dlfcn.h>
#endif
#include "prims/jni.h"
#include "unittest.hpp"
extern "C" {
static int init_jvm(int argc, char **argv, bool is_executing_death_test) {
// don't care about the program name
argc--;
argv++;
int extra_jvm_args = is_executing_death_test ? 4 : 2;
int num_jvm_options = argc + extra_jvm_args;
JavaVMOption* options = new JavaVMOption[num_jvm_options];
options[0].optionString = (char*) "-Dsun.java.launcher.is_altjvm=true";
options[1].optionString = (char*) "-XX:+ExecutingUnitTests";
if (is_executing_death_test) {
// don't create core files or hs_err files when executing death tests
options[2].optionString = (char*) "-XX:+SuppressFatalErrorMessage";
options[3].optionString = (char*) "-XX:-CreateCoredumpOnCrash";
}
for (int i = 0; i < argc; i++) {
options[extra_jvm_args + i].optionString = argv[i];
}
JavaVMInitArgs args;
args.version = JNI_VERSION_1_8;
args.nOptions = num_jvm_options;
args.options = options;
JavaVM* jvm;
JNIEnv* env;
return JNI_CreateJavaVM(&jvm, (void**)&env, &args);
}
class JVMInitializerListener : public ::testing::EmptyTestEventListener {
private:
int _argc;
char** _argv;
bool _is_initialized;
void initialize_jvm() {
}
public:
JVMInitializerListener(int argc, char** argv) :
_argc(argc), _argv(argv), _is_initialized(false) {
}
virtual void OnTestStart(const ::testing::TestInfo& test_info) {
const char* name = test_info.name();
if (strstr(name, "_test_vm") != NULL && !_is_initialized) {
ASSERT_EQ(init_jvm(_argc, _argv, false), 0) << "Could not initialize the JVM";
_is_initialized = true;
}
}
};
static bool is_prefix(const char* prefix, const char* str) {
return strncmp(str, prefix, strlen(prefix)) == 0;
}
static char* get_java_home_arg(int argc, char** argv) {
for (int i = 0; i < argc; i++) {
if (strncmp(argv[i], "-jdk", strlen(argv[i])) == 0) {
return argv[i+1];
}
if (is_prefix("--jdk=", argv[i])) {
return argv[i] + strlen("--jdk=");
}
if (is_prefix("-jdk:", argv[i])) {
return argv[i] + strlen("-jdk:");
}
}
return NULL;
}
static int num_args_to_skip(char* arg) {
if (strcmp(arg, "-jdk") == 0) {
return 2; // skip the argument after -jdk as well
}
if (is_prefix("--jdk=", arg)) {
return 1;
}
if (is_prefix("-jdk:", arg)) {
return 1;
}
return 0;
}
static char** remove_test_runner_arguments(int* argcp, char **argv) {
int argc = *argcp;
char** new_argv = (char**) malloc(sizeof(char*) * argc);
int new_argc = 0;
int i = 0;
while (i < argc) {
int args_to_skip = num_args_to_skip(argv[i]);
if (args_to_skip == 0) {
new_argv[new_argc] = argv[i];
i++;
new_argc++;
} else {
i += num_args_to_skip(argv[i]);
}
}
*argcp = new_argc;
return new_argv;
}
JNIEXPORT void JNICALL runUnitTests(int argc, char** argv) {
// Must look at googletest options before initializing googletest, since
// InitGoogleTest removes googletest options from argv.
bool is_executing_death_test = true;
for (int i = 0; i < argc; i++) {
const char* death_test_flag = "--gtest_internal_run_death_test";
if (is_prefix(death_test_flag, argv[i])) {
is_executing_death_test = true;
}
}
::testing::InitGoogleTest(&argc, argv);
::testing::GTEST_FLAG(death_test_style) = "threadsafe";
// ::testing::GTEST_FLAG(death_test_output_prefix) = "Other VM";
char* java_home = get_java_home_arg(argc, argv);
if (java_home == NULL) {
fprintf(stderr, "ERROR: You must specify a JDK to use for running the unit tests.\n");
exit(1);
}
#ifndef _WIN32
int overwrite = 1; // overwrite an eventual existing value for JAVA_HOME
setenv("JAVA_HOME", java_home, overwrite);
// workaround for JDK-7131356
#ifdef __APPLE__
size_t len = strlen(java_home) + strlen("/lib/jli/libjli.dylib") + 1;
char* path = new char[len];
snprintf(path, len, "%s/lib/jli/libjli.dylib", java_home);
dlopen(path, RTLD_NOW | RTLD_GLOBAL);
#endif // __APPLE__
#else // _WIN32
char* java_home_var = "_ALT_JAVA_HOME_DIR";
size_t len = strlen(java_home) + strlen(java_home_var) + 2;
char * envString = new char[len];
sprintf_s(envString, len, "%s=%s", java_home_var, java_home);
_putenv(envString);
#endif // _WIN32
argv = remove_test_runner_arguments(&argc, argv);
if (is_executing_death_test) {
if (init_jvm(argc, argv, true) != 0) {
abort();
}
} else {
::testing::TestEventListeners& listeners = ::testing::UnitTest::GetInstance()->listeners();
listeners.Append(new JVMInitializerListener(argc, argv));
}
int result = RUN_ALL_TESTS();
if (result != 0) {
fprintf(stderr, "ERROR: RUN_ALL_TESTS() failed. Error %d\n", result);
exit(2);
}
}
} // extern "C"

View File

@ -0,0 +1,45 @@
/*
* Copyright (c) 2016, 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 "runtime/os.hpp"
#include "unittest.hpp"
TEST_VM(os, page_size_for_region) {
size_t large_page_example = 4 * M;
size_t large_page = os::page_size_for_region_aligned(large_page_example, 1);
size_t small_page = os::vm_page_size();
if (large_page > small_page) {
size_t num_small_in_large = large_page / small_page;
size_t page = os::page_size_for_region_aligned(large_page, num_small_in_large);
ASSERT_EQ(page, small_page) << "Did not get a small page";
}
}
#ifdef ASSERT
TEST_VM_ASSERT_MSG(os, page_size_for_region_with_zero_min_pages, "sanity") {
size_t region_size = 16 * os::vm_page_size();
os::page_size_for_region_aligned(region_size, 0); // should assert
}
#endif

View File

@ -0,0 +1,104 @@
/*
* Copyright (c) 2016, 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 <stdlib.h>
#include <stdio.h>
#define GTEST_DONT_DEFINE_TEST 1
#include "gtest/gtest.h"
#ifdef assert
#undef assert
#endif
#define CONCAT(a, b) a ## b
#define TEST(category, name) GTEST_TEST(category, CONCAT(name, _test))
#define TEST_VM(category, name) GTEST_TEST(category, CONCAT(name, _test_vm))
#define TEST_VM_F(test_fixture, name) \
GTEST_TEST_(test_fixture, name ## _test_vm, test_fixture, \
::testing::internal::GetTypeId<test_fixture>())
#define TEST_OTHER_VM(category, name) \
static void test_ ## category ## _ ## name ## _(); \
\
static void child_ ## category ## _ ## name ## _() { \
::testing::GTEST_FLAG(throw_on_failure) = true; \
test_ ## category ## _ ## name ## _(); \
fprintf(stderr, "OKIDOKI"); \
exit(0); \
} \
\
TEST(category, CONCAT(name, _other_vm)) { \
ASSERT_EXIT(child_ ## category ## _ ## name ## _(), \
::testing::ExitedWithCode(0), \
".*OKIDOKI.*"); \
} \
\
void test_ ## category ## _ ## name ## _()
#ifdef ASSERT
#define TEST_VM_ASSERT(category, name) \
static void test_ ## category ## _ ## name ## _(); \
\
static void child_ ## category ## _ ## name ## _() { \
::testing::GTEST_FLAG(throw_on_failure) = true; \
test_ ## category ## _ ## name ## _(); \
exit(0); \
} \
\
TEST(category, CONCAT(name, _vm_assert)) { \
ASSERT_EXIT(child_ ## category ## _ ## name ## _(), \
::testing::ExitedWithCode(1), \
"assert failed"); \
} \
\
void test_ ## category ## _ ## name ## _()
#else
#define TEST_VM_ASSERT(...) \
TEST_VM_ASSERT is only available in debug builds
#endif
#ifdef ASSERT
#define TEST_VM_ASSERT_MSG(category, name, msg) \
static void test_ ## category ## _ ## name ## _(); \
\
static void child_ ## category ## _ ## name ## _() { \
::testing::GTEST_FLAG(throw_on_failure) = true; \
test_ ## category ## _ ## name ## _(); \
exit(0); \
} \
\
TEST(category, CONCAT(name, _vm_assert)) { \
ASSERT_EXIT(child_ ## category ## _ ## name ## _(), \
::testing::ExitedWithCode(1), \
"assert failed: " msg); \
} \
\
void test_ ## category ## _ ## name ## _()
#else
#define TEST_VM_ASSERT_MSG(...) \
TEST_VM_ASSERT_MSG is only available in debug builds
#endif

View File

@ -0,0 +1,47 @@
/*
* Copyright (c) 2016, 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 "prims/jvm.h"
#include "utilities/quickSort.hpp"
#include "unittest.hpp"
static int int_comparator(int a, int b) {
if (a == b) {
return 0;
} else if (a < b) {
return -1;
}
// a > b
return 1;
}
TEST(utilities, quicksort) {
int test_array[] = {3,2,1};
QuickSort::sort(test_array, 3, int_comparator, false);
ASSERT_EQ(1, test_array[0]);
ASSERT_EQ(2, test_array[1]);
ASSERT_EQ(3, test_array[2]);
}