Merge
This commit is contained in:
commit
354e0fd809
@ -446,3 +446,4 @@ d2982a786f53814367698e63efe6349c9128e1db jdk-9+180
|
||||
b656dea9398ef601f7fc08d1a5157a560e0ccbe0 jdk-9+181
|
||||
682e2a6df836f4731f92eb2ddcd467075047f6ea jdk-10+20
|
||||
90cdfe56f1543267a8005e638bd1b44551fda189 jdk-10+21
|
||||
8625e8491887bfd4310b2cfc2b84bac26312ba20 jdk-10+22
|
||||
|
@ -209,6 +209,7 @@ JDKOPT_SETUP_CODE_COVERAGE
|
||||
# Need toolchain to setup dtrace
|
||||
HOTSPOT_SETUP_DTRACE
|
||||
HOTSPOT_ENABLE_DISABLE_AOT
|
||||
HOTSPOT_ENABLE_DISABLE_CDS
|
||||
HOTSPOT_ENABLE_DISABLE_GTEST
|
||||
|
||||
###############################################################################
|
||||
|
@ -702,6 +702,7 @@ LIBCXX
|
||||
FIXPATH_DETACH_FLAG
|
||||
FIXPATH
|
||||
BUILD_GTEST
|
||||
ENABLE_CDS
|
||||
ENABLE_AOT
|
||||
GCOV_ENABLED
|
||||
ZIP_EXTERNAL_DEBUG_SYMBOLS
|
||||
@ -1191,6 +1192,7 @@ enable_zip_debug_info
|
||||
enable_native_coverage
|
||||
enable_dtrace
|
||||
enable_aot
|
||||
enable_cds
|
||||
enable_hotspot_gtest
|
||||
with_stdc__lib
|
||||
with_msvcr_dll
|
||||
@ -1999,6 +2001,8 @@ Optional Features:
|
||||
enable ahead of time compilation feature. Default is
|
||||
auto, where aot is enabled if all dependencies are
|
||||
present.
|
||||
--enable-cds[=yes/no] enable class data sharing feature in non-minimal VM.
|
||||
Default is yes.
|
||||
--disable-hotspot-gtest Disables building of the Hotspot unit tests
|
||||
--disable-freetype-bundling
|
||||
disable bundling of the freetype library with the
|
||||
@ -2016,7 +2020,8 @@ Optional Features:
|
||||
--disable-generate-classlist
|
||||
forces enabling or disabling of the generation of a
|
||||
CDS classlist at build time. Default is to generate
|
||||
it when either the server or client JVMs are built.
|
||||
it when either the server or client JVMs are built
|
||||
and enable-cds is true.
|
||||
--enable-sjavac use sjavac to do fast incremental compiles
|
||||
[disabled]
|
||||
--disable-javac-server disable javac server [enabled]
|
||||
@ -4295,7 +4300,7 @@ pkgadd_help() {
|
||||
|
||||
# All valid JVM features, regardless of platform
|
||||
VALID_JVM_FEATURES="compiler1 compiler2 zero shark minimal dtrace jvmti jvmci \
|
||||
graal fprof vm-structs jni-check services management all-gcs nmt cds \
|
||||
graal vm-structs jni-check services management all-gcs nmt cds \
|
||||
static-build link-time-opt aot"
|
||||
|
||||
# All valid JVM variants
|
||||
@ -4345,6 +4350,11 @@ VALID_JVM_VARIANTS="server client minimal core zero zeroshark custom"
|
||||
#
|
||||
|
||||
|
||||
################################################################################
|
||||
# Allow to disable CDS
|
||||
#
|
||||
|
||||
|
||||
###############################################################################
|
||||
# Set up all JVM features for each JVM variant.
|
||||
#
|
||||
@ -5151,7 +5161,7 @@ VS_SDK_PLATFORM_NAME_2013=
|
||||
#CUSTOM_AUTOCONF_INCLUDE
|
||||
|
||||
# Do not change or remove the following line, it is needed for consistency checks:
|
||||
DATE_WHEN_GENERATED=1504187184
|
||||
DATE_WHEN_GENERATED=1504441177
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
@ -54216,6 +54226,23 @@ $as_echo "no, forced" >&6; }
|
||||
|
||||
|
||||
|
||||
# Check whether --enable-cds was given.
|
||||
if test "${enable_cds+set}" = set; then :
|
||||
enableval=$enable_cds;
|
||||
fi
|
||||
|
||||
|
||||
if test "x$enable_cds" = "x" || test "x$enable_cds" = "xyes"; then
|
||||
ENABLE_CDS="true"
|
||||
elif test "x$enable_cds" = "xno"; then
|
||||
ENABLE_CDS="false"
|
||||
else
|
||||
as_fn_error $? "Invalid value for --enable-cds: $enable_cds" "$LINENO" 5
|
||||
fi
|
||||
|
||||
|
||||
|
||||
|
||||
# Check whether --enable-hotspot-gtest was given.
|
||||
if test "${enable_hotspot_gtest+set}" = set; then :
|
||||
enableval=$enable_hotspot_gtest;
|
||||
@ -65810,8 +65837,12 @@ $as_echo "yes, forced" >&6; }
|
||||
fi
|
||||
INCLUDE_GRAAL="true"
|
||||
else
|
||||
# By default enable graal build where AOT is available
|
||||
if test "x$ENABLE_AOT" = "xtrue"; then
|
||||
# By default enable graal build on linux-x64 or where AOT is available.
|
||||
# graal build requires jvmci.
|
||||
if test "x$JVM_FEATURES_jvmci" = "xjvmci" && \
|
||||
(test "x$OPENJDK_TARGET_CPU" = "xx86_64" && \
|
||||
test "x$OPENJDK_TARGET_OS" = "xlinux" || \
|
||||
test "x$ENABLE_AOT" = "xtrue") ; then
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
|
||||
$as_echo "yes" >&6; }
|
||||
JVM_FEATURES_graal="graal"
|
||||
@ -65856,7 +65887,10 @@ $as_echo "no" >&6; }
|
||||
fi
|
||||
|
||||
# All variants but minimal (and custom) get these features
|
||||
NON_MINIMAL_FEATURES="$NON_MINIMAL_FEATURES jvmti fprof vm-structs jni-check services management all-gcs nmt cds"
|
||||
NON_MINIMAL_FEATURES="$NON_MINIMAL_FEATURES jvmti vm-structs jni-check services management all-gcs nmt"
|
||||
if test "x$ENABLE_CDS" = "xtrue"; then
|
||||
NON_MINIMAL_FEATURES="$NON_MINIMAL_FEATURES cds"
|
||||
fi
|
||||
|
||||
# Enable features depending on variant.
|
||||
JVM_FEATURES_server="compiler1 compiler2 $NON_MINIMAL_FEATURES $JVM_FEATURES $JVM_FEATURES_jvmci $JVM_FEATURES_aot $JVM_FEATURES_graal"
|
||||
@ -65960,7 +65994,7 @@ fi
|
||||
|
||||
# Check if it's likely that it's possible to generate the classlist. Depending
|
||||
# on exact jvm configuration it could be possible anyway.
|
||||
if [[ " $JVM_VARIANTS " =~ " server " ]] || [[ " $JVM_VARIANTS " =~ " client " ]] ; then
|
||||
if test "x$ENABLE_CDS" = "xtrue" && ( [[ " $JVM_VARIANTS " =~ " server " ]] || [[ " $JVM_VARIANTS " =~ " client " ]] ); then
|
||||
ENABLE_GENERATE_CLASSLIST_POSSIBLE="true"
|
||||
else
|
||||
ENABLE_GENERATE_CLASSLIST_POSSIBLE="false"
|
||||
@ -65973,8 +66007,8 @@ $as_echo_n "checking if the CDS classlist generation should be enabled... " >&6;
|
||||
$as_echo "yes, forced" >&6; }
|
||||
ENABLE_GENERATE_CLASSLIST="true"
|
||||
if test "x$ENABLE_GENERATE_CLASSLIST_POSSIBLE" = "xfalse"; then
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Generation of classlist might not be possible with JVM Variants $JVM_VARIANTS" >&5
|
||||
$as_echo "$as_me: WARNING: Generation of classlist might not be possible with JVM Variants $JVM_VARIANTS" >&2;}
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Generation of classlist might not be possible with JVM Variants $JVM_VARIANTS and enable-cds=$ENABLE_CDS" >&5
|
||||
$as_echo "$as_me: WARNING: Generation of classlist might not be possible with JVM Variants $JVM_VARIANTS and enable-cds=$ENABLE_CDS" >&2;}
|
||||
fi
|
||||
elif test "x$enable_generate_classlist" = "xno"; then
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no, forced" >&5
|
||||
|
@ -25,7 +25,7 @@
|
||||
|
||||
# All valid JVM features, regardless of platform
|
||||
VALID_JVM_FEATURES="compiler1 compiler2 zero shark minimal dtrace jvmti jvmci \
|
||||
graal fprof vm-structs jni-check services management all-gcs nmt cds \
|
||||
graal vm-structs jni-check services management all-gcs nmt cds \
|
||||
static-build link-time-opt aot"
|
||||
|
||||
# All valid JVM variants
|
||||
@ -240,6 +240,25 @@ AC_DEFUN_ONCE([HOTSPOT_ENABLE_DISABLE_AOT],
|
||||
AC_SUBST(ENABLE_AOT)
|
||||
])
|
||||
|
||||
################################################################################
|
||||
# Allow to disable CDS
|
||||
#
|
||||
AC_DEFUN_ONCE([HOTSPOT_ENABLE_DISABLE_CDS],
|
||||
[
|
||||
AC_ARG_ENABLE([cds], [AS_HELP_STRING([--enable-cds@<:@=yes/no@:>@],
|
||||
[enable class data sharing feature in non-minimal VM. Default is yes.])])
|
||||
|
||||
if test "x$enable_cds" = "x" || test "x$enable_cds" = "xyes"; then
|
||||
ENABLE_CDS="true"
|
||||
elif test "x$enable_cds" = "xno"; then
|
||||
ENABLE_CDS="false"
|
||||
else
|
||||
AC_MSG_ERROR([Invalid value for --enable-cds: $enable_cds])
|
||||
fi
|
||||
|
||||
AC_SUBST(ENABLE_CDS)
|
||||
])
|
||||
|
||||
###############################################################################
|
||||
# Set up all JVM features for each JVM variant.
|
||||
#
|
||||
@ -335,8 +354,12 @@ AC_DEFUN_ONCE([HOTSPOT_SETUP_JVM_FEATURES],
|
||||
fi
|
||||
INCLUDE_GRAAL="true"
|
||||
else
|
||||
# By default enable graal build where AOT is available
|
||||
if test "x$ENABLE_AOT" = "xtrue"; then
|
||||
# By default enable graal build on linux-x64 or where AOT is available.
|
||||
# graal build requires jvmci.
|
||||
if test "x$JVM_FEATURES_jvmci" = "xjvmci" && \
|
||||
(test "x$OPENJDK_TARGET_CPU" = "xx86_64" && \
|
||||
test "x$OPENJDK_TARGET_OS" = "xlinux" || \
|
||||
test "x$ENABLE_AOT" = "xtrue") ; then
|
||||
AC_MSG_RESULT([yes])
|
||||
JVM_FEATURES_graal="graal"
|
||||
INCLUDE_GRAAL="true"
|
||||
@ -374,7 +397,10 @@ AC_DEFUN_ONCE([HOTSPOT_SETUP_JVM_FEATURES],
|
||||
fi
|
||||
|
||||
# All variants but minimal (and custom) get these features
|
||||
NON_MINIMAL_FEATURES="$NON_MINIMAL_FEATURES jvmti fprof vm-structs jni-check services management all-gcs nmt cds"
|
||||
NON_MINIMAL_FEATURES="$NON_MINIMAL_FEATURES jvmti vm-structs jni-check services management all-gcs nmt"
|
||||
if test "x$ENABLE_CDS" = "xtrue"; then
|
||||
NON_MINIMAL_FEATURES="$NON_MINIMAL_FEATURES cds"
|
||||
fi
|
||||
|
||||
# Enable features depending on variant.
|
||||
JVM_FEATURES_server="compiler1 compiler2 $NON_MINIMAL_FEATURES $JVM_FEATURES $JVM_FEATURES_jvmci $JVM_FEATURES_aot $JVM_FEATURES_graal"
|
||||
|
@ -496,11 +496,12 @@ AC_DEFUN_ONCE([JDKOPT_ENABLE_DISABLE_GENERATE_CLASSLIST],
|
||||
[
|
||||
AC_ARG_ENABLE([generate-classlist], [AS_HELP_STRING([--disable-generate-classlist],
|
||||
[forces enabling or disabling of the generation of a CDS classlist at build time.
|
||||
Default is to generate it when either the server or client JVMs are built.])])
|
||||
Default is to generate it when either the server or client JVMs are built and
|
||||
enable-cds is true.])])
|
||||
|
||||
# Check if it's likely that it's possible to generate the classlist. Depending
|
||||
# on exact jvm configuration it could be possible anyway.
|
||||
if HOTSPOT_CHECK_JVM_VARIANT(server) || HOTSPOT_CHECK_JVM_VARIANT(client); then
|
||||
if test "x$ENABLE_CDS" = "xtrue" && (HOTSPOT_CHECK_JVM_VARIANT(server) || HOTSPOT_CHECK_JVM_VARIANT(client)); then
|
||||
ENABLE_GENERATE_CLASSLIST_POSSIBLE="true"
|
||||
else
|
||||
ENABLE_GENERATE_CLASSLIST_POSSIBLE="false"
|
||||
@ -511,7 +512,7 @@ AC_DEFUN_ONCE([JDKOPT_ENABLE_DISABLE_GENERATE_CLASSLIST],
|
||||
AC_MSG_RESULT([yes, forced])
|
||||
ENABLE_GENERATE_CLASSLIST="true"
|
||||
if test "x$ENABLE_GENERATE_CLASSLIST_POSSIBLE" = "xfalse"; then
|
||||
AC_MSG_WARN([Generation of classlist might not be possible with JVM Variants $JVM_VARIANTS])
|
||||
AC_MSG_WARN([Generation of classlist might not be possible with JVM Variants $JVM_VARIANTS and enable-cds=$ENABLE_CDS])
|
||||
fi
|
||||
elif test "x$enable_generate_classlist" = "xno"; then
|
||||
AC_MSG_RESULT([no, forced])
|
||||
|
@ -818,6 +818,49 @@ var getJibProfilesProfiles = function (input, common, data) {
|
||||
}
|
||||
},
|
||||
|
||||
"macosx-x64-open": {
|
||||
artifacts: {
|
||||
jdk: {
|
||||
local: "bundles/\\(jdk.*bin.tar.gz\\)",
|
||||
remote: [
|
||||
"bundles/openjdk/GPL/osx-x64/jdk-" + data.version
|
||||
+ "_osx-x64_bin.tar.gz",
|
||||
"bundles/openjdk/GPL/osx-x64/\\1"
|
||||
],
|
||||
subdir: "jdk-" + data.version
|
||||
},
|
||||
jre: {
|
||||
local: "bundles/\\(jre.*bin.tar.gz\\)",
|
||||
remote: "bundles/openjdk/GPL/osx-x64/\\1",
|
||||
},
|
||||
test: {
|
||||
local: "bundles/\\(jdk.*bin-tests.tar.gz\\)",
|
||||
remote: [
|
||||
"bundles/openjdk/GPL/osx-x64/jdk-" + data.version
|
||||
+ "_osx-x64_bin-tests.tar.gz",
|
||||
"bundles/openjdk/GPL/osx-x64/\\1"
|
||||
]
|
||||
},
|
||||
jdk_symbols: {
|
||||
local: "bundles/\\(jdk.*bin-symbols.tar.gz\\)",
|
||||
remote: [
|
||||
"bundles/openjdk/GPL/osx-x64/jdk-" + data.version
|
||||
+ "_osx-x64_bin-symbols.tar.gz",
|
||||
"bundles/openjdk/GPL/osx-x64/\\1"
|
||||
],
|
||||
subdir: "jdk-" + data.version
|
||||
},
|
||||
jre_symbols: {
|
||||
local: "bundles/\\(jre.*bin-symbols.tar.gz\\)",
|
||||
remote: "bundles/openjdk/GPL/osx-x64/\\1",
|
||||
},
|
||||
doc_api_spec: {
|
||||
local: "bundles/\\(jdk.*doc-api-spec.tar.gz\\)",
|
||||
remote: "bundles/openjdk/GPL/osx-x64/\\1",
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
"windows-x86-open": {
|
||||
artifacts: {
|
||||
jdk: {
|
||||
@ -884,10 +927,11 @@ var getJibProfilesProfiles = function (input, common, data) {
|
||||
profiles["linux-x64-ri"] = clone(profiles["linux-x64-open"]);
|
||||
profiles["linux-x86-ri"] = clone(profiles["linux-x86-open"]);
|
||||
profiles["linux-x86-ri-debug"] = clone(profiles["linux-x86-open-debug"]);
|
||||
profiles["macosx-x64-ri"] = clone(profiles["macosx-x64-open"]);
|
||||
profiles["windows-x86-ri"] = clone(profiles["windows-x86-open"]);
|
||||
|
||||
// Generate artifacts for ri profiles
|
||||
[ "linux-x64-ri", "linux-x86-ri", "linux-x86-ri-debug", "windows-x86-ri" ]
|
||||
[ "linux-x64-ri", "linux-x86-ri", "linux-x86-ri-debug", "macosx-x64-ri", "windows-x86-ri" ]
|
||||
.forEach(function (name) {
|
||||
// Rewrite all remote dirs to "bundles/openjdk/BCL/..."
|
||||
for (artifactName in profiles[name].artifacts) {
|
||||
|
@ -606,3 +606,4 @@ d7baadc223e790c08bc69bf7e553bce65b4e7e40 jdk-9+180
|
||||
4a443796f6f57842d6a0434ac27ca3d1033ccc20 jdk-9+181
|
||||
e93ed1a092409351c90b3a76d80b9aa8b44d5e6a jdk-10+20
|
||||
bdb2dbc43ff065b74c2121bdfb0d6e1fa8684b73 jdk-10+21
|
||||
71337910df60ff2b62daf10357f553def25e2d0b jdk-10+22
|
||||
|
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
# Copyright (c) 2013, 2017, 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
|
||||
@ -88,11 +88,6 @@ ifneq ($(call check-jvm-feature, jvmci), true)
|
||||
JVM_EXCLUDE_FILES += jvmciCodeInstaller_$(HOTSPOT_TARGET_CPU_ARCH).cpp
|
||||
endif
|
||||
|
||||
ifneq ($(call check-jvm-feature, fprof), true)
|
||||
JVM_CFLAGS_FEATURES += -DINCLUDE_FPROF=0
|
||||
JVM_EXCLUDE_FILES += fprofiler.cpp
|
||||
endif
|
||||
|
||||
ifneq ($(call check-jvm-feature, vm-structs), true)
|
||||
JVM_CFLAGS_FEATURES += -DINCLUDE_VM_STRUCTS=0
|
||||
JVM_EXCLUDE_FILES += vmStructs.cpp
|
||||
|
@ -12614,7 +12614,7 @@ instruct ubfxwI(iRegINoSp dst, iRegIorL2I src, immI rshift, immI_bitmask mask)
|
||||
match(Set dst (AndI (URShiftI src rshift) mask));
|
||||
|
||||
ins_cost(INSN_COST);
|
||||
format %{ "ubfxw $dst, $src, $mask" %}
|
||||
format %{ "ubfxw $dst, $src, $rshift, $mask" %}
|
||||
ins_encode %{
|
||||
int rshift = $rshift$$constant;
|
||||
long mask = $mask$$constant;
|
||||
@ -12629,7 +12629,7 @@ instruct ubfxL(iRegLNoSp dst, iRegL src, immI rshift, immL_bitmask mask)
|
||||
match(Set dst (AndL (URShiftL src rshift) mask));
|
||||
|
||||
ins_cost(INSN_COST);
|
||||
format %{ "ubfx $dst, $src, $mask" %}
|
||||
format %{ "ubfx $dst, $src, $rshift, $mask" %}
|
||||
ins_encode %{
|
||||
int rshift = $rshift$$constant;
|
||||
long mask = $mask$$constant;
|
||||
@ -12647,7 +12647,7 @@ instruct ubfxIConvI2L(iRegLNoSp dst, iRegIorL2I src, immI rshift, immI_bitmask m
|
||||
match(Set dst (ConvI2L (AndI (URShiftI src rshift) mask)));
|
||||
|
||||
ins_cost(INSN_COST * 2);
|
||||
format %{ "ubfx $dst, $src, $mask" %}
|
||||
format %{ "ubfx $dst, $src, $rshift, $mask" %}
|
||||
ins_encode %{
|
||||
int rshift = $rshift$$constant;
|
||||
long mask = $mask$$constant;
|
||||
|
@ -183,7 +183,7 @@ define(`BFX_INSN',
|
||||
match(Set dst (And$1 ($2$1 src rshift) mask));
|
||||
|
||||
ins_cost(INSN_COST);
|
||||
format %{ "$3 $dst, $src, $mask" %}
|
||||
format %{ "$3 $dst, $src, $rshift, $mask" %}
|
||||
ins_encode %{
|
||||
int rshift = $rshift$$constant;
|
||||
long mask = $mask$$constant;
|
||||
@ -203,7 +203,7 @@ instruct ubfxIConvI2L(iRegLNoSp dst, iRegIorL2I src, immI rshift, immI_bitmask m
|
||||
match(Set dst (ConvI2L (AndI (URShiftI src rshift) mask)));
|
||||
|
||||
ins_cost(INSN_COST * 2);
|
||||
format %{ "ubfx $dst, $src, $mask" %}
|
||||
format %{ "ubfx $dst, $src, $rshift, $mask" %}
|
||||
ins_encode %{
|
||||
int rshift = $rshift$$constant;
|
||||
long mask = $mask$$constant;
|
||||
|
@ -3630,6 +3630,12 @@ void MacroAssembler::store_heap_oop_null(Address dst) {
|
||||
}
|
||||
|
||||
#if INCLUDE_ALL_GCS
|
||||
/*
|
||||
* g1_write_barrier_pre -- G1GC pre-write barrier for store of new_val at
|
||||
* store_addr.
|
||||
*
|
||||
* Allocates rscratch1
|
||||
*/
|
||||
void MacroAssembler::g1_write_barrier_pre(Register obj,
|
||||
Register pre_val,
|
||||
Register thread,
|
||||
@ -3645,10 +3651,8 @@ void MacroAssembler::g1_write_barrier_pre(Register obj,
|
||||
Label done;
|
||||
Label runtime;
|
||||
|
||||
assert(pre_val != noreg, "check this code");
|
||||
|
||||
if (obj != noreg)
|
||||
assert_different_registers(obj, pre_val, tmp);
|
||||
assert_different_registers(obj, pre_val, tmp, rscratch1);
|
||||
assert(pre_val != noreg && tmp != noreg, "expecting a register");
|
||||
|
||||
Address in_progress(thread, in_bytes(JavaThread::satb_mark_queue_offset() +
|
||||
SATBMarkQueue::byte_offset_of_active()));
|
||||
@ -3722,12 +3726,22 @@ void MacroAssembler::g1_write_barrier_pre(Register obj,
|
||||
bind(done);
|
||||
}
|
||||
|
||||
/*
|
||||
* g1_write_barrier_post -- G1GC post-write barrier for store of new_val at
|
||||
* store_addr
|
||||
*
|
||||
* Allocates rscratch1
|
||||
*/
|
||||
void MacroAssembler::g1_write_barrier_post(Register store_addr,
|
||||
Register new_val,
|
||||
Register thread,
|
||||
Register tmp,
|
||||
Register tmp2) {
|
||||
assert(thread == rthread, "must be");
|
||||
assert_different_registers(store_addr, new_val, thread, tmp, tmp2,
|
||||
rscratch1);
|
||||
assert(store_addr != noreg && new_val != noreg && tmp != noreg
|
||||
&& tmp2 != noreg, "expecting a register");
|
||||
|
||||
Address queue_index(thread, in_bytes(JavaThread::dirty_card_queue_offset() +
|
||||
DirtyCardQueue::byte_offset_of_index()));
|
||||
|
@ -2067,7 +2067,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm,
|
||||
__ g1_write_barrier_pre(noreg /* obj */,
|
||||
r0 /* pre_val */,
|
||||
rthread /* thread */,
|
||||
rscratch1 /* tmp */,
|
||||
rscratch2 /* tmp */,
|
||||
true /* tosca_live */,
|
||||
true /* expand_call */);
|
||||
}
|
||||
|
@ -170,7 +170,7 @@ static void do_oop_store(InterpreterMacroAssembler* _masm,
|
||||
// G1 barrier needs uncompressed oop for region cross check.
|
||||
Register new_val = val;
|
||||
if (UseCompressedOops) {
|
||||
new_val = rscratch1;
|
||||
new_val = rscratch2;
|
||||
__ mov(new_val, val);
|
||||
}
|
||||
__ store_heap_oop(Address(r3, 0), val);
|
||||
|
@ -292,7 +292,7 @@ void MacroAssembler::verify_thread() {
|
||||
if (VerifyThread) {
|
||||
// NOTE: this chops off the heads of the 64-bit O registers.
|
||||
// make sure G2_thread contains the right value
|
||||
save_frame_and_mov(0, Lmethod, Lmethod); // to avoid clobbering O0 (and propagate Lmethod for -Xprof)
|
||||
save_frame_and_mov(0, Lmethod, Lmethod); // to avoid clobbering O0 (and propagate Lmethod)
|
||||
mov(G1, L1); // avoid clobbering G1
|
||||
// G2 saved below
|
||||
mov(G3, L3); // avoid clobbering G3
|
||||
@ -398,7 +398,7 @@ void MacroAssembler::reset_last_Java_frame(void) {
|
||||
|
||||
#ifdef ASSERT
|
||||
// check that it WAS previously set
|
||||
save_frame_and_mov(0, Lmethod, Lmethod); // Propagate Lmethod to helper frame for -Xprof
|
||||
save_frame_and_mov(0, Lmethod, Lmethod); // Propagate Lmethod to helper frame
|
||||
ld_ptr(sp_addr, L0);
|
||||
tst(L0);
|
||||
breakpoint_trap(Assembler::zero, Assembler::ptr_cc);
|
||||
@ -618,7 +618,7 @@ void MacroAssembler::set_vm_result(Register oop_result) {
|
||||
|
||||
# ifdef ASSERT
|
||||
// Check that we are not overwriting any other oop.
|
||||
save_frame_and_mov(0, Lmethod, Lmethod); // Propagate Lmethod for -Xprof
|
||||
save_frame_and_mov(0, Lmethod, Lmethod); // Propagate Lmethod
|
||||
ld_ptr(vm_result_addr, L0);
|
||||
tst(L0);
|
||||
restore();
|
||||
|
@ -2928,7 +2928,7 @@ void TemplateTable::invokevirtual(int byte_no) {
|
||||
__ br(Assembler::zero, false, Assembler::pt, notFinal);
|
||||
__ delayed()->and3(Rret, 0xFF, G4_scratch); // gets number of parameters
|
||||
|
||||
if (RewriteBytecodes && !UseSharedSpaces) {
|
||||
if (RewriteBytecodes && !UseSharedSpaces && !DumpSharedSpaces) {
|
||||
patch_bytecode(Bytecodes::_fast_invokevfinal, Rscratch, Rtemp);
|
||||
}
|
||||
|
||||
|
@ -187,11 +187,10 @@ public final class BinaryContainer implements SymbolTable {
|
||||
{"StubRoutines::_arrayof_oop_disjoint_arraycopy", "_aot_stub_routines_arrayof_oop_disjoint_arraycopy"},
|
||||
{"StubRoutines::_arrayof_oop_disjoint_arraycopy_uninit", "_aot_stub_routines_arrayof_oop_disjoint_arraycopy_uninit"},
|
||||
|
||||
{"StubRoutines::_unsafe_arraycopy", "_aot_stub_routines_unsafe_arraycopy"},
|
||||
|
||||
{"StubRoutines::_checkcast_arraycopy", "_aot_stub_routines_checkcast_arraycopy"},
|
||||
|
||||
|
||||
|
||||
|
||||
{"StubRoutines::_aescrypt_encryptBlock", "_aot_stub_routines_aescrypt_encryptBlock"},
|
||||
{"StubRoutines::_aescrypt_decryptBlock", "_aot_stub_routines_aescrypt_decryptBlock"},
|
||||
{"StubRoutines::_cipherBlockChaining_encryptAESCrypt", "_aot_stub_routines_cipherBlockChaining_encryptAESCrypt"},
|
||||
@ -478,8 +477,8 @@ public final class BinaryContainer implements SymbolTable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a global symbol of the form {@code "A" + container name}.
|
||||
* Note, linker on Windows does not allow names which start with '.'
|
||||
* Creates a global symbol of the form {@code "A" + container name}. Note, linker on Windows
|
||||
* does not allow names which start with '.'
|
||||
*
|
||||
* @param container container to create a symbol for
|
||||
*/
|
||||
@ -685,7 +684,8 @@ public final class BinaryContainer implements SymbolTable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Add oop symbol by as follows. Extend the oop.got section with another slot for the VM to patch.
|
||||
* Add oop symbol by as follows. Extend the oop.got section with another slot for the VM to
|
||||
* patch.
|
||||
*
|
||||
* @param oopName name of the oop symbol
|
||||
*/
|
||||
@ -728,10 +728,9 @@ public final class BinaryContainer implements SymbolTable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Add klass symbol by as follows.
|
||||
* - Adding the symbol name to the metaspace.names section
|
||||
* - Add the offset of the name in metaspace.names to metaspace.offsets
|
||||
* - Extend the klasses.got section with another slot for the VM to patch
|
||||
* Add klass symbol by as follows. - Adding the symbol name to the metaspace.names section - Add
|
||||
* the offset of the name in metaspace.names to metaspace.offsets - Extend the klasses.got
|
||||
* section with another slot for the VM to patch
|
||||
*
|
||||
* @param klassName name of the metaspace symbol
|
||||
* @return the got offset in the klasses.got of the metaspace symbol
|
||||
|
@ -27,6 +27,8 @@ import java.util.ListIterator;
|
||||
|
||||
import org.graalvm.compiler.code.CompilationResult;
|
||||
import org.graalvm.compiler.core.GraalCompiler;
|
||||
import org.graalvm.compiler.core.common.CompilationIdentifier;
|
||||
import org.graalvm.compiler.core.common.CompilationIdentifier.Verbosity;
|
||||
import org.graalvm.compiler.debug.DebugContext;
|
||||
import org.graalvm.compiler.hotspot.HotSpotBackend;
|
||||
import org.graalvm.compiler.hotspot.HotSpotCompiledCodeBuilder;
|
||||
@ -127,7 +129,13 @@ final class AOTBackend {
|
||||
ProfilingInfo profilingInfo = DefaultProfilingInfo.get(TriState.FALSE);
|
||||
|
||||
final boolean isImmutablePIC = true;
|
||||
CompilationResult compilationResult = new CompilationResult(resolvedMethod.getName(), isImmutablePIC);
|
||||
CompilationIdentifier id = new CompilationIdentifier() {
|
||||
@Override
|
||||
public String toString(Verbosity verbosity) {
|
||||
return resolvedMethod.getName();
|
||||
}
|
||||
};
|
||||
CompilationResult compilationResult = new CompilationResult(id, isImmutablePIC);
|
||||
|
||||
return GraalCompiler.compileGraph(graph, resolvedMethod, providers, backend, graphBuilderSuite, OptimisticOptimizations.ALL, profilingInfo, getSuites(), getLirSuites(),
|
||||
compilationResult, CompilationResultBuilderFactory.Default);
|
||||
|
@ -57,7 +57,9 @@ public @interface ClassSubstitution {
|
||||
|
||||
/**
|
||||
* Determines if the substitutions are for classes that may not be part of the runtime.
|
||||
* Substitutions for such classes are omitted if the original classes cannot be found.
|
||||
* Substitutions for such classes are omitted if the original classes cannot be found. If
|
||||
* multiple classes are specified using {@link #className()} and {@link #optional()} is false,
|
||||
* then at least one of the classes is required to be reachable.
|
||||
*/
|
||||
boolean optional() default false;
|
||||
}
|
||||
|
@ -90,7 +90,7 @@ public abstract class AssemblerTest extends GraalTest {
|
||||
StructuredGraph graph = new StructuredGraph.Builder(options, debug).method(method).compilationId(compilationId).build();
|
||||
CallingConvention cc = backend.newLIRGenerationResult(compilationId, null, null, graph, null).getCallingConvention();
|
||||
|
||||
CompilationResult compResult = new CompilationResult();
|
||||
CompilationResult compResult = new CompilationResult(graph.compilationId());
|
||||
byte[] targetCode = test.generateCode(compResult, codeCache.getTarget(), registerConfig, cc);
|
||||
compResult.setTargetCode(targetCode, targetCode.length);
|
||||
compResult.setTotalFrameSize(0);
|
||||
|
@ -33,6 +33,7 @@ import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import org.graalvm.compiler.core.common.CompilationIdentifier;
|
||||
import org.graalvm.compiler.graph.NodeSourcePosition;
|
||||
import org.graalvm.util.EconomicSet;
|
||||
|
||||
@ -190,6 +191,8 @@ public class CompilationResult {
|
||||
|
||||
private final String name;
|
||||
|
||||
private final CompilationIdentifier compilationId;
|
||||
|
||||
/**
|
||||
* The buffer containing the emitted machine code.
|
||||
*/
|
||||
@ -222,21 +225,26 @@ public class CompilationResult {
|
||||
|
||||
private boolean isImmutablePIC;
|
||||
|
||||
public CompilationResult() {
|
||||
this(null, false);
|
||||
public CompilationResult(CompilationIdentifier compilationId) {
|
||||
this(compilationId, compilationId.toString(CompilationIdentifier.Verbosity.NAME), false);
|
||||
}
|
||||
|
||||
public CompilationResult(CompilationIdentifier compilationId, String name) {
|
||||
this(compilationId, name, false);
|
||||
}
|
||||
|
||||
public CompilationResult(CompilationIdentifier compilationId, boolean isImmutablePIC) {
|
||||
this(compilationId, null, isImmutablePIC);
|
||||
}
|
||||
|
||||
public CompilationResult(CompilationIdentifier compilationId, String name, boolean isImmutablePIC) {
|
||||
this.compilationId = compilationId;
|
||||
this.name = name;
|
||||
this.isImmutablePIC = isImmutablePIC;
|
||||
}
|
||||
|
||||
public CompilationResult(String name) {
|
||||
this(name, false);
|
||||
}
|
||||
|
||||
public CompilationResult(boolean isImmutablePIC) {
|
||||
this(null, isImmutablePIC);
|
||||
}
|
||||
|
||||
public CompilationResult(String name, boolean isImmutablePIC) {
|
||||
this.name = name;
|
||||
this.isImmutablePIC = isImmutablePIC;
|
||||
this(null, name);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -266,6 +274,7 @@ public class CompilationResult {
|
||||
this.totalFrameSize == that.totalFrameSize &&
|
||||
this.targetCodeSize == that.targetCodeSize &&
|
||||
Objects.equals(this.name, that.name) &&
|
||||
Objects.equals(this.compilationId, that.compilationId) &&
|
||||
Objects.equals(this.annotations, that.annotations) &&
|
||||
Objects.equals(this.dataSection, that.dataSection) &&
|
||||
Objects.equals(this.exceptionHandlers, that.exceptionHandlers) &&
|
||||
@ -670,6 +679,10 @@ public class CompilationResult {
|
||||
return name;
|
||||
}
|
||||
|
||||
public CompilationIdentifier getCompilationId() {
|
||||
return compilationId;
|
||||
}
|
||||
|
||||
public void setHasUnsafeAccess(boolean hasUnsafeAccess) {
|
||||
checkOpen();
|
||||
this.hasUnsafeAccess = hasUnsafeAccess;
|
||||
|
@ -949,7 +949,7 @@ public abstract class GraalCompilerTest extends GraalTest {
|
||||
|
||||
try (AllocSpy spy = AllocSpy.open(installedCodeOwner); DebugContext.Scope ds = debug.scope("Compiling", new DebugDumpScope(id.toString(CompilationIdentifier.Verbosity.ID), true))) {
|
||||
CompilationPrinter printer = CompilationPrinter.begin(options, id, installedCodeOwner, INVOCATION_ENTRY_BCI);
|
||||
CompilationResult compResult = compile(installedCodeOwner, graphToCompile, new CompilationResult(), id, options);
|
||||
CompilationResult compResult = compile(installedCodeOwner, graphToCompile, new CompilationResult(graphToCompile.compilationId()), id, options);
|
||||
printer.finish(compResult);
|
||||
|
||||
try (DebugContext.Scope s = debug.scope("CodeInstall", getCodeCache(), installedCodeOwner, compResult);
|
||||
@ -1019,17 +1019,19 @@ public abstract class GraalCompilerTest extends GraalTest {
|
||||
*/
|
||||
protected final CompilationResult compile(ResolvedJavaMethod installedCodeOwner, StructuredGraph graph) {
|
||||
OptionValues options = graph == null ? getInitialOptions() : graph.getOptions();
|
||||
return compile(installedCodeOwner, graph, new CompilationResult(), getOrCreateCompilationId(installedCodeOwner, graph), options);
|
||||
CompilationIdentifier compilationId = getOrCreateCompilationId(installedCodeOwner, graph);
|
||||
return compile(installedCodeOwner, graph, new CompilationResult(compilationId), compilationId, options);
|
||||
}
|
||||
|
||||
protected final CompilationResult compile(ResolvedJavaMethod installedCodeOwner, StructuredGraph graph, CompilationIdentifier compilationId) {
|
||||
OptionValues options = graph == null ? getInitialOptions() : graph.getOptions();
|
||||
return compile(installedCodeOwner, graph, new CompilationResult(), compilationId, options);
|
||||
return compile(installedCodeOwner, graph, new CompilationResult(compilationId), compilationId, options);
|
||||
}
|
||||
|
||||
protected final CompilationResult compile(ResolvedJavaMethod installedCodeOwner, StructuredGraph graph, OptionValues options) {
|
||||
assert graph == null || graph.getOptions() == options;
|
||||
return compile(installedCodeOwner, graph, new CompilationResult(), getOrCreateCompilationId(installedCodeOwner, graph), options);
|
||||
CompilationIdentifier compilationId = getOrCreateCompilationId(installedCodeOwner, graph);
|
||||
return compile(installedCodeOwner, graph, new CompilationResult(compilationId), compilationId, options);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -64,7 +64,7 @@ public class InfopointReasonTest extends GraalCompilerTest {
|
||||
final ResolvedJavaMethod method = getResolvedJavaMethod("testMethod");
|
||||
final StructuredGraph graph = parseEager(method, AllowAssumptions.YES);
|
||||
final CompilationResult cr = compileGraph(graph, graph.method(), getProviders(), getBackend(), getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL, graph.getProfilingInfo(),
|
||||
createSuites(graph.getOptions()), createLIRSuites(graph.getOptions()), new CompilationResult(), CompilationResultBuilderFactory.Default);
|
||||
createSuites(graph.getOptions()), createLIRSuites(graph.getOptions()), new CompilationResult(graph.compilationId()), CompilationResultBuilderFactory.Default);
|
||||
for (Infopoint sp : cr.getInfopoints()) {
|
||||
assertNotNull(sp.reason);
|
||||
if (sp instanceof Call) {
|
||||
@ -86,7 +86,7 @@ public class InfopointReasonTest extends GraalCompilerTest {
|
||||
assertTrue(graphLineSPs > 0);
|
||||
PhaseSuite<HighTierContext> graphBuilderSuite = getCustomGraphBuilderSuite(GraphBuilderConfiguration.getDefault(getDefaultGraphBuilderPlugins()).withFullInfopoints(true));
|
||||
final CompilationResult cr = compileGraph(graph, graph.method(), getProviders(), getBackend(), graphBuilderSuite, OptimisticOptimizations.ALL, graph.getProfilingInfo(),
|
||||
createSuites(graph.getOptions()), createLIRSuites(graph.getOptions()), new CompilationResult(), CompilationResultBuilderFactory.Default);
|
||||
createSuites(graph.getOptions()), createLIRSuites(graph.getOptions()), new CompilationResult(graph.compilationId()), CompilationResultBuilderFactory.Default);
|
||||
int lineSPs = 0;
|
||||
for (Infopoint sp : cr.getInfopoints()) {
|
||||
assertNotNull(sp.reason);
|
||||
|
@ -123,7 +123,7 @@ public class InvokeGraal {
|
||||
ProfilingInfo profilingInfo = graph.getProfilingInfo(method);
|
||||
|
||||
/* The default class and configuration for compilation results. */
|
||||
CompilationResult compilationResult = new CompilationResult();
|
||||
CompilationResult compilationResult = new CompilationResult(graph.compilationId());
|
||||
CompilationResultBuilderFactory factory = CompilationResultBuilderFactory.Default;
|
||||
|
||||
/* Invoke the whole Graal compilation pipeline. */
|
||||
|
@ -0,0 +1,203 @@
|
||||
/*
|
||||
* Copyright (c) 2017, 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 org.graalvm.compiler.graph.test;
|
||||
|
||||
import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_IGNORED;
|
||||
import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_IGNORED;
|
||||
|
||||
import java.util.ConcurrentModificationException;
|
||||
import java.util.Iterator;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
import org.graalvm.compiler.api.test.Graal;
|
||||
import org.graalvm.compiler.graph.Graph;
|
||||
import org.graalvm.compiler.graph.Node;
|
||||
import org.graalvm.compiler.graph.NodeBitMap;
|
||||
import org.graalvm.compiler.graph.NodeClass;
|
||||
import org.graalvm.compiler.nodeinfo.NodeInfo;
|
||||
import org.graalvm.compiler.options.OptionValues;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
public class NodeBitMapTest extends GraphTest {
|
||||
|
||||
@NodeInfo(cycles = CYCLES_IGNORED, size = SIZE_IGNORED)
|
||||
static final class TestNode extends Node {
|
||||
public static final NodeClass<TestNode> TYPE = NodeClass.create(TestNode.class);
|
||||
|
||||
protected TestNode() {
|
||||
super(TYPE);
|
||||
}
|
||||
}
|
||||
|
||||
private Graph graph;
|
||||
private TestNode[] nodes = new TestNode[100];
|
||||
private NodeBitMap map;
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
// Need to initialize HotSpotGraalRuntime before any Node class is initialized.
|
||||
Graal.getRuntime();
|
||||
|
||||
OptionValues options = getOptions();
|
||||
graph = new Graph(options, getDebug(options));
|
||||
for (int i = 0; i < nodes.length; i++) {
|
||||
nodes[i] = graph.add(new TestNode());
|
||||
}
|
||||
map = graph.createNodeBitMap();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void iterateEmpty() {
|
||||
for (Node n : map) {
|
||||
Assert.fail("no elements expected: " + n);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void iterateMarkedNodes() {
|
||||
map.mark(nodes[99]);
|
||||
map.mark(nodes[0]);
|
||||
map.mark(nodes[7]);
|
||||
map.mark(nodes[1]);
|
||||
map.mark(nodes[53]);
|
||||
|
||||
Iterator<Node> iter = map.iterator();
|
||||
Assert.assertTrue(iter.hasNext());
|
||||
Assert.assertEquals(nodes[0], iter.next());
|
||||
Assert.assertTrue(iter.hasNext());
|
||||
Assert.assertEquals(nodes[1], iter.next());
|
||||
Assert.assertTrue(iter.hasNext());
|
||||
Assert.assertEquals(nodes[7], iter.next());
|
||||
Assert.assertTrue(iter.hasNext());
|
||||
Assert.assertEquals(nodes[53], iter.next());
|
||||
Assert.assertTrue(iter.hasNext());
|
||||
Assert.assertEquals(nodes[99], iter.next());
|
||||
Assert.assertFalse(iter.hasNext());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void deleteNodeWhileIterating() {
|
||||
map.mark(nodes[99]);
|
||||
map.mark(nodes[0]);
|
||||
map.mark(nodes[7]);
|
||||
map.mark(nodes[1]);
|
||||
map.mark(nodes[53]);
|
||||
|
||||
Iterator<Node> iter = map.iterator();
|
||||
Assert.assertTrue(iter.hasNext());
|
||||
Assert.assertEquals(nodes[0], iter.next());
|
||||
Assert.assertTrue(iter.hasNext());
|
||||
Assert.assertEquals(nodes[1], iter.next());
|
||||
nodes[7].markDeleted();
|
||||
nodes[53].markDeleted();
|
||||
Assert.assertTrue(iter.hasNext());
|
||||
Assert.assertEquals(nodes[99], iter.next());
|
||||
Assert.assertFalse(iter.hasNext());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void deleteAllNodesBeforeIterating() {
|
||||
for (int i = 0; i < nodes.length; i++) {
|
||||
map.mark(nodes[i]);
|
||||
nodes[i].markDeleted();
|
||||
}
|
||||
|
||||
Iterator<Node> iter = map.iterator();
|
||||
Assert.assertFalse(iter.hasNext());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void multipleHasNextInvocations() {
|
||||
map.mark(nodes[7]);
|
||||
|
||||
Iterator<Node> iter = map.iterator();
|
||||
Assert.assertTrue(iter.hasNext());
|
||||
Assert.assertTrue(iter.hasNext());
|
||||
Assert.assertEquals(nodes[7], iter.next());
|
||||
Assert.assertFalse(iter.hasNext());
|
||||
}
|
||||
|
||||
@Test(expected = NoSuchElementException.class)
|
||||
public void noSuchElement() {
|
||||
map.iterator().next();
|
||||
}
|
||||
|
||||
@Test(expected = ConcurrentModificationException.class)
|
||||
public void concurrentModification() {
|
||||
map.mark(nodes[7]);
|
||||
|
||||
map.mark(nodes[99]);
|
||||
map.mark(nodes[0]);
|
||||
map.mark(nodes[7]);
|
||||
map.mark(nodes[1]);
|
||||
map.mark(nodes[53]);
|
||||
|
||||
Iterator<Node> iter = map.iterator();
|
||||
Assert.assertTrue(iter.hasNext());
|
||||
Assert.assertEquals(nodes[0], iter.next());
|
||||
Assert.assertTrue(iter.hasNext());
|
||||
Assert.assertEquals(nodes[1], iter.next());
|
||||
Assert.assertTrue(iter.hasNext());
|
||||
nodes[7].markDeleted();
|
||||
iter.next();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nextWithoutHasNext() {
|
||||
map.mark(nodes[99]);
|
||||
map.mark(nodes[0]);
|
||||
map.mark(nodes[7]);
|
||||
map.mark(nodes[1]);
|
||||
map.mark(nodes[53]);
|
||||
|
||||
Iterator<Node> iter = map.iterator();
|
||||
Assert.assertEquals(nodes[0], iter.next());
|
||||
Assert.assertEquals(nodes[1], iter.next());
|
||||
Assert.assertEquals(nodes[7], iter.next());
|
||||
Assert.assertEquals(nodes[53], iter.next());
|
||||
Assert.assertEquals(nodes[99], iter.next());
|
||||
Assert.assertFalse(iter.hasNext());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void markWhileIterating() {
|
||||
map.mark(nodes[0]);
|
||||
|
||||
Iterator<Node> iter = map.iterator();
|
||||
Assert.assertTrue(iter.hasNext());
|
||||
Assert.assertEquals(nodes[0], iter.next());
|
||||
map.mark(nodes[7]);
|
||||
Assert.assertTrue(iter.hasNext());
|
||||
map.mark(nodes[1]);
|
||||
Assert.assertEquals(nodes[7], iter.next());
|
||||
map.mark(nodes[99]);
|
||||
map.mark(nodes[53]);
|
||||
Assert.assertTrue(iter.hasNext());
|
||||
Assert.assertEquals(nodes[53], iter.next());
|
||||
Assert.assertTrue(iter.hasNext());
|
||||
Assert.assertEquals(nodes[99], iter.next());
|
||||
Assert.assertFalse(iter.hasNext());
|
||||
}
|
||||
}
|
@ -23,22 +23,23 @@
|
||||
package org.graalvm.compiler.graph;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.ConcurrentModificationException;
|
||||
import java.util.Iterator;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
import org.graalvm.compiler.graph.iterators.NodeIterable;
|
||||
|
||||
public final class NodeBitMap implements NodeIterable<Node> {
|
||||
public final class NodeBitMap extends NodeIdAccessor implements NodeIterable<Node> {
|
||||
private static final int SHIFT = 6;
|
||||
|
||||
private long[] bits;
|
||||
private int nodeCount;
|
||||
private int counter;
|
||||
private final Graph graph;
|
||||
|
||||
public NodeBitMap(Graph graph) {
|
||||
super(graph);
|
||||
this.nodeCount = graph.nodeIdCount();
|
||||
this.bits = new long[sizeForNodeCount(nodeCount)];
|
||||
this.graph = graph;
|
||||
}
|
||||
|
||||
private static int sizeForNodeCount(int nodeCount) {
|
||||
@ -50,9 +51,9 @@ public final class NodeBitMap implements NodeIterable<Node> {
|
||||
}
|
||||
|
||||
private NodeBitMap(NodeBitMap other) {
|
||||
super(other.graph);
|
||||
this.bits = other.bits.clone();
|
||||
this.nodeCount = other.nodeCount;
|
||||
this.graph = other.graph;
|
||||
}
|
||||
|
||||
public Graph graph() {
|
||||
@ -60,12 +61,12 @@ public final class NodeBitMap implements NodeIterable<Node> {
|
||||
}
|
||||
|
||||
public boolean isNew(Node node) {
|
||||
return node.id() >= nodeCount;
|
||||
return getNodeId(node) >= nodeCount;
|
||||
}
|
||||
|
||||
public boolean isMarked(Node node) {
|
||||
assert check(node, false);
|
||||
return isMarked(node.id());
|
||||
return isMarked(getNodeId(node));
|
||||
}
|
||||
|
||||
public boolean checkAndMarkInc(Node node) {
|
||||
@ -84,33 +85,33 @@ public final class NodeBitMap implements NodeIterable<Node> {
|
||||
|
||||
public boolean isMarkedAndGrow(Node node) {
|
||||
assert check(node, true);
|
||||
int id = node.id();
|
||||
int id = getNodeId(node);
|
||||
checkGrow(id);
|
||||
return isMarked(id);
|
||||
}
|
||||
|
||||
public void mark(Node node) {
|
||||
assert check(node, false);
|
||||
int id = node.id();
|
||||
int id = getNodeId(node);
|
||||
bits[id >> SHIFT] |= (1L << id);
|
||||
}
|
||||
|
||||
public void markAndGrow(Node node) {
|
||||
assert check(node, true);
|
||||
int id = node.id();
|
||||
int id = getNodeId(node);
|
||||
checkGrow(id);
|
||||
bits[id >> SHIFT] |= (1L << id);
|
||||
}
|
||||
|
||||
public void clear(Node node) {
|
||||
assert check(node, false);
|
||||
int id = node.id();
|
||||
int id = getNodeId(node);
|
||||
bits[id >> SHIFT] &= ~(1L << id);
|
||||
}
|
||||
|
||||
public void clearAndGrow(Node node) {
|
||||
assert check(node, true);
|
||||
int id = node.id();
|
||||
int id = getNodeId(node);
|
||||
checkGrow(id);
|
||||
bits[id >> SHIFT] &= ~(1L << id);
|
||||
}
|
||||
@ -181,15 +182,30 @@ public final class NodeBitMap implements NodeIterable<Node> {
|
||||
}
|
||||
}
|
||||
|
||||
protected int nextMarkedNodeId(int fromNodeId) {
|
||||
protected Node nextMarkedNode(int fromNodeId) {
|
||||
assert fromNodeId >= 0;
|
||||
int wordIndex = fromNodeId >> SHIFT;
|
||||
int wordsInUse = bits.length;
|
||||
if (wordIndex < wordsInUse) {
|
||||
long word = bits[wordIndex] & (0xFFFFFFFFFFFFFFFFL << fromNodeId);
|
||||
long word = getPartOfWord(bits[wordIndex], fromNodeId);
|
||||
while (true) {
|
||||
if (word != 0) {
|
||||
return wordIndex * Long.SIZE + Long.numberOfTrailingZeros(word);
|
||||
while (word != 0) {
|
||||
int bitIndex = Long.numberOfTrailingZeros(word);
|
||||
int nodeId = wordIndex * Long.SIZE + bitIndex;
|
||||
Node result = graph.getNode(nodeId);
|
||||
if (result == null) {
|
||||
// node was deleted -> clear the bit and continue searching
|
||||
bits[wordIndex] = bits[wordIndex] & ~(1 << bitIndex);
|
||||
int nextNodeId = nodeId + 1;
|
||||
if ((nextNodeId & (Long.SIZE - 1)) == 0) {
|
||||
// we reached the end of this word
|
||||
break;
|
||||
} else {
|
||||
word = getPartOfWord(word, nextNodeId);
|
||||
}
|
||||
} else {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
if (++wordIndex == wordsInUse) {
|
||||
break;
|
||||
@ -197,30 +213,56 @@ public final class NodeBitMap implements NodeIterable<Node> {
|
||||
word = bits[wordIndex];
|
||||
}
|
||||
}
|
||||
return -2;
|
||||
return null;
|
||||
}
|
||||
|
||||
private static long getPartOfWord(long word, int firstNodeIdToInclude) {
|
||||
return word & (0xFFFFFFFFFFFFFFFFL << firstNodeIdToInclude);
|
||||
}
|
||||
|
||||
/**
|
||||
* This iterator only returns nodes that are marked in the {@link NodeBitMap} and are alive in
|
||||
* the corresponding {@link Graph}.
|
||||
*/
|
||||
private class MarkedNodeIterator implements Iterator<Node> {
|
||||
private int nextNodeId;
|
||||
private int currentNodeId;
|
||||
private Node currentNode;
|
||||
|
||||
MarkedNodeIterator() {
|
||||
nextNodeId = -1;
|
||||
currentNodeId = -1;
|
||||
forward();
|
||||
}
|
||||
|
||||
private void forward() {
|
||||
nextNodeId = NodeBitMap.this.nextMarkedNodeId(nextNodeId + 1);
|
||||
assert currentNode == null;
|
||||
currentNode = NodeBitMap.this.nextMarkedNode(currentNodeId + 1);
|
||||
if (currentNode != null) {
|
||||
assert currentNode.isAlive();
|
||||
currentNodeId = getNodeId(currentNode);
|
||||
} else {
|
||||
currentNodeId = -1;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return nextNodeId >= 0;
|
||||
if (currentNode == null && currentNodeId >= 0) {
|
||||
forward();
|
||||
}
|
||||
return currentNodeId >= 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node next() {
|
||||
Node result = graph.getNode(nextNodeId);
|
||||
forward();
|
||||
if (!hasNext()) {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
if (!currentNode.isAlive()) {
|
||||
throw new ConcurrentModificationException("NodeBitMap was modified between the calls to hasNext() and next()");
|
||||
}
|
||||
|
||||
Node result = currentNode;
|
||||
currentNode = null;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -1,117 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 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 org.graalvm.compiler.hotspot.aarch64;
|
||||
|
||||
import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN;
|
||||
import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_UNKNOWN;
|
||||
|
||||
import org.graalvm.compiler.core.aarch64.AArch64NodeLIRBuilder;
|
||||
import org.graalvm.compiler.core.common.type.RawPointerStamp;
|
||||
import org.graalvm.compiler.core.common.type.Stamp;
|
||||
import org.graalvm.compiler.core.common.type.StampFactory;
|
||||
import org.graalvm.compiler.graph.NodeClass;
|
||||
import org.graalvm.compiler.graph.NodeInputList;
|
||||
import org.graalvm.compiler.nodeinfo.NodeInfo;
|
||||
import org.graalvm.compiler.nodes.FixedWithNextNode;
|
||||
import org.graalvm.compiler.nodes.ValueNode;
|
||||
import org.graalvm.compiler.nodes.spi.LIRLowerable;
|
||||
import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
|
||||
|
||||
import jdk.vm.ci.code.CallingConvention;
|
||||
import jdk.vm.ci.hotspot.HotSpotCallingConventionType;
|
||||
import jdk.vm.ci.meta.JavaConstant;
|
||||
import jdk.vm.ci.meta.JavaKind;
|
||||
import jdk.vm.ci.meta.JavaType;
|
||||
import jdk.vm.ci.meta.MetaAccessProvider;
|
||||
import jdk.vm.ci.meta.ResolvedJavaType;
|
||||
import jdk.vm.ci.meta.Value;
|
||||
|
||||
@NodeInfo(cycles = CYCLES_UNKNOWN, cyclesRationale = "Native call is a block hole", size = SIZE_UNKNOWN)
|
||||
public final class AArch64RawNativeCallNode extends FixedWithNextNode implements LIRLowerable {
|
||||
public static final NodeClass<AArch64RawNativeCallNode> TYPE = NodeClass.create(AArch64RawNativeCallNode.class);
|
||||
|
||||
protected final JavaConstant functionPointer;
|
||||
@Input NodeInputList<ValueNode> args;
|
||||
|
||||
public AArch64RawNativeCallNode(JavaKind returnType, JavaConstant functionPointer, ValueNode[] args) {
|
||||
super(TYPE, StampFactory.forKind(returnType));
|
||||
this.functionPointer = functionPointer;
|
||||
this.args = new NodeInputList<>(this, args);
|
||||
}
|
||||
|
||||
private static class PointerType implements JavaType {
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "void*";
|
||||
}
|
||||
|
||||
@Override
|
||||
public JavaType getComponentType() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JavaType getArrayClass() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JavaKind getJavaKind() {
|
||||
// native pointers and java objects use the same registers in the calling convention
|
||||
return JavaKind.Object;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResolvedJavaType resolve(ResolvedJavaType accessingClass) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static JavaType toJavaType(Stamp stamp, MetaAccessProvider metaAccess) {
|
||||
if (stamp instanceof RawPointerStamp) {
|
||||
return new PointerType();
|
||||
} else {
|
||||
return stamp.javaType(metaAccess);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generate(NodeLIRBuilderTool generator) {
|
||||
AArch64NodeLIRBuilder gen = (AArch64NodeLIRBuilder) generator;
|
||||
Value[] parameter = new Value[args.count()];
|
||||
JavaType[] parameterTypes = new JavaType[args.count()];
|
||||
for (int i = 0; i < args.count(); i++) {
|
||||
parameter[i] = generator.operand(args.get(i));
|
||||
parameterTypes[i] = toJavaType(args.get(i).stamp(), gen.getLIRGeneratorTool().getMetaAccess());
|
||||
}
|
||||
JavaType returnType = toJavaType(stamp(), gen.getLIRGeneratorTool().getMetaAccess());
|
||||
CallingConvention cc = generator.getLIRGeneratorTool().getCodeCache().getRegisterConfig().getCallingConvention(HotSpotCallingConventionType.NativeCall, returnType, parameterTypes,
|
||||
generator.getLIRGeneratorTool());
|
||||
gen.getLIRGeneratorTool().emitCCall(functionPointer.asLong(), cc, parameter);
|
||||
if (this.getStackKind() != JavaKind.Void) {
|
||||
generator.setResult(this, gen.getLIRGeneratorTool().emitMove(cc.getReturn()));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,130 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 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 org.graalvm.compiler.hotspot.amd64;
|
||||
|
||||
import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN;
|
||||
|
||||
import org.graalvm.compiler.core.amd64.AMD64NodeLIRBuilder;
|
||||
import org.graalvm.compiler.core.common.type.RawPointerStamp;
|
||||
import org.graalvm.compiler.core.common.type.Stamp;
|
||||
import org.graalvm.compiler.core.common.type.StampFactory;
|
||||
import org.graalvm.compiler.graph.NodeClass;
|
||||
import org.graalvm.compiler.graph.NodeInputList;
|
||||
import org.graalvm.compiler.nodeinfo.NodeInfo;
|
||||
import org.graalvm.compiler.nodeinfo.NodeSize;
|
||||
import org.graalvm.compiler.nodes.FixedWithNextNode;
|
||||
import org.graalvm.compiler.nodes.ValueNode;
|
||||
import org.graalvm.compiler.nodes.spi.LIRLowerable;
|
||||
import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
|
||||
|
||||
import jdk.vm.ci.code.CallingConvention;
|
||||
import jdk.vm.ci.hotspot.HotSpotCallingConventionType;
|
||||
import jdk.vm.ci.meta.JavaConstant;
|
||||
import jdk.vm.ci.meta.JavaKind;
|
||||
import jdk.vm.ci.meta.JavaType;
|
||||
import jdk.vm.ci.meta.MetaAccessProvider;
|
||||
import jdk.vm.ci.meta.ResolvedJavaType;
|
||||
import jdk.vm.ci.meta.Value;
|
||||
|
||||
@NodeInfo(cycles = CYCLES_UNKNOWN, cyclesRationale = "Native call is a block hole", size = NodeSize.SIZE_UNKNOWN)
|
||||
public final class AMD64RawNativeCallNode extends FixedWithNextNode implements LIRLowerable {
|
||||
public static final NodeClass<AMD64RawNativeCallNode> TYPE = NodeClass.create(AMD64RawNativeCallNode.class);
|
||||
|
||||
protected final JavaConstant functionPointer;
|
||||
@Input NodeInputList<ValueNode> args;
|
||||
|
||||
public AMD64RawNativeCallNode(JavaKind returnType, JavaConstant functionPointer, ValueNode[] args) {
|
||||
super(TYPE, StampFactory.forKind(returnType));
|
||||
this.functionPointer = functionPointer;
|
||||
this.args = new NodeInputList<>(this, args);
|
||||
}
|
||||
|
||||
private static class PointerType implements JavaType {
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "void*";
|
||||
}
|
||||
|
||||
@Override
|
||||
public JavaType getComponentType() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JavaType getArrayClass() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JavaKind getJavaKind() {
|
||||
// native pointers and java objects use the same registers in the calling convention
|
||||
return JavaKind.Object;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResolvedJavaType resolve(ResolvedJavaType accessingClass) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static JavaType toJavaType(Stamp stamp, MetaAccessProvider metaAccess) {
|
||||
if (stamp instanceof RawPointerStamp) {
|
||||
return new PointerType();
|
||||
} else {
|
||||
return stamp.javaType(metaAccess);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generate(NodeLIRBuilderTool generator) {
|
||||
AMD64NodeLIRBuilder gen = (AMD64NodeLIRBuilder) generator;
|
||||
Value[] parameter = new Value[args.count()];
|
||||
JavaType[] parameterTypes = new JavaType[args.count()];
|
||||
for (int i = 0; i < args.count(); i++) {
|
||||
parameter[i] = generator.operand(args.get(i));
|
||||
parameterTypes[i] = toJavaType(args.get(i).stamp(), gen.getLIRGeneratorTool().getMetaAccess());
|
||||
}
|
||||
JavaType returnType = toJavaType(stamp(), gen.getLIRGeneratorTool().getMetaAccess());
|
||||
CallingConvention cc = generator.getLIRGeneratorTool().getCodeCache().getRegisterConfig().getCallingConvention(HotSpotCallingConventionType.NativeCall, returnType, parameterTypes,
|
||||
generator.getLIRGeneratorTool());
|
||||
gen.getLIRGeneratorTool().emitCCall(functionPointer.asLong(), cc, parameter, countFloatingTypeArguments(args));
|
||||
if (this.getStackKind() != JavaKind.Void) {
|
||||
generator.setResult(this, gen.getLIRGeneratorTool().emitMove(cc.getReturn()));
|
||||
}
|
||||
}
|
||||
|
||||
private static int countFloatingTypeArguments(NodeInputList<ValueNode> args) {
|
||||
int count = 0;
|
||||
for (ValueNode n : args) {
|
||||
if (n.getStackKind() == JavaKind.Double || n.getStackKind() == JavaKind.Float) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
if (count > 8) {
|
||||
return 8;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
}
|
@ -207,7 +207,6 @@ public class CheckGraalIntrinsics extends GraalTest {
|
||||
"oracle/jrockit/jfr/Timing.counterTime()J",
|
||||
"oracle/jrockit/jfr/VMJFR.classID0(Ljava/lang/Class;)J",
|
||||
"oracle/jrockit/jfr/VMJFR.threadID()I",
|
||||
"sun/misc/Unsafe.copyMemory(Ljava/lang/Object;JLjava/lang/Object;JJ)V",
|
||||
"sun/nio/cs/ISO_8859_1$Encoder.encodeISOArray([CI[BII)I",
|
||||
"sun/security/provider/DigestBase.implCompressMultiBlock([BII)I",
|
||||
"sun/security/provider/SHA.implCompress([BI)V",
|
||||
@ -273,7 +272,6 @@ public class CheckGraalIntrinsics extends GraalTest {
|
||||
"jdk/internal/misc/Unsafe.compareAndExchangeShortRelease(Ljava/lang/Object;JSS)S",
|
||||
"jdk/internal/misc/Unsafe.compareAndSetByte(Ljava/lang/Object;JBB)Z",
|
||||
"jdk/internal/misc/Unsafe.compareAndSetShort(Ljava/lang/Object;JSS)Z",
|
||||
"jdk/internal/misc/Unsafe.copyMemory0(Ljava/lang/Object;JLjava/lang/Object;JJ)V",
|
||||
"jdk/internal/misc/Unsafe.getAndAddByte(Ljava/lang/Object;JB)B",
|
||||
"jdk/internal/misc/Unsafe.getAndAddShort(Ljava/lang/Object;JS)S",
|
||||
"jdk/internal/misc/Unsafe.getAndSetByte(Ljava/lang/Object;JB)B",
|
||||
|
@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright (c) 2017, 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 org.graalvm.compiler.hotspot.test;
|
||||
|
||||
import org.graalvm.compiler.replacements.test.MethodSubstitutionTest;
|
||||
import org.junit.Test;
|
||||
|
||||
import jdk.vm.ci.code.InstalledCode;
|
||||
import jdk.vm.ci.meta.ResolvedJavaMethod;
|
||||
import sun.misc.Unsafe;
|
||||
|
||||
/**
|
||||
* Tests the VM independent intrinsification of {@link Unsafe} methods.
|
||||
*/
|
||||
public class HotSpotUnsafeSubstitutionTest extends MethodSubstitutionTest {
|
||||
|
||||
public void testSubstitution(String testMethodName, Class<?> holder, String methodName, Class<?>[] parameterTypes, Object receiver, Object[] args1, Object[] args2) {
|
||||
ResolvedJavaMethod testMethod = getResolvedJavaMethod(testMethodName);
|
||||
ResolvedJavaMethod originalMethod = getResolvedJavaMethod(holder, methodName, parameterTypes);
|
||||
|
||||
// Force compilation
|
||||
InstalledCode code = getCode(testMethod);
|
||||
assert code != null;
|
||||
|
||||
// Verify that the original method and the substitution produce the same value
|
||||
Object expected = invokeSafe(originalMethod, receiver, args1);
|
||||
Object actual = invokeSafe(testMethod, null, args2);
|
||||
assertDeepEquals(expected, actual);
|
||||
|
||||
// Verify that the generated code and the original produce the same value
|
||||
expected = invokeSafe(originalMethod, receiver, args1);
|
||||
actual = executeVarargsSafe(code, args2);
|
||||
assertDeepEquals(expected, actual);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnsafeSubstitutions() throws Exception {
|
||||
testGraph("unsafeCopyMemory");
|
||||
}
|
||||
|
||||
public void unsafeCopyMemory(Object srcBase, long srcOffset, Object dstBase, long dstOffset, long bytes) {
|
||||
UNSAFE.copyMemory(srcBase, srcOffset, dstBase, dstOffset, bytes);
|
||||
}
|
||||
|
||||
public byte[] testCopyMemorySnippet(long src, int bytes) {
|
||||
byte[] result = new byte[bytes];
|
||||
UNSAFE.copyMemory(null, src, result, Unsafe.ARRAY_BYTE_BASE_OFFSET, bytes);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCopyMemory() {
|
||||
int size = 128;
|
||||
long src = UNSAFE.allocateMemory(size);
|
||||
for (int i = 0; i < size; i++) {
|
||||
UNSAFE.putByte(null, src + i, (byte) i);
|
||||
}
|
||||
test("testCopyMemorySnippet", src, size);
|
||||
}
|
||||
}
|
@ -64,9 +64,9 @@ import org.graalvm.compiler.options.OptionType;
|
||||
import org.graalvm.compiler.options.OptionValues;
|
||||
import org.graalvm.compiler.phases.tiers.SuitesProvider;
|
||||
import org.graalvm.compiler.word.Word;
|
||||
import org.graalvm.util.Equivalence;
|
||||
import org.graalvm.util.EconomicMap;
|
||||
import org.graalvm.util.EconomicSet;
|
||||
import org.graalvm.util.Equivalence;
|
||||
import org.graalvm.util.MapCursor;
|
||||
import org.graalvm.word.Pointer;
|
||||
|
||||
@ -257,6 +257,18 @@ public abstract class HotSpotBackend extends Backend implements FrameMap.Referen
|
||||
@NodeIntrinsic(ForeignCallNode.class)
|
||||
private static native void sha5ImplCompressStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word bufAddr, Object state);
|
||||
|
||||
/**
|
||||
* @see org.graalvm.compiler.hotspot.meta.HotSpotUnsafeSubstitutions#copyMemory
|
||||
*/
|
||||
public static final ForeignCallDescriptor UNSAFE_ARRAYCOPY = new ForeignCallDescriptor("unsafe_arraycopy", void.class, Word.class, Word.class, Word.class);
|
||||
|
||||
public static void unsafeArraycopy(Word srcAddr, Word dstAddr, Word size) {
|
||||
unsafeArraycopyStub(HotSpotBackend.UNSAFE_ARRAYCOPY, srcAddr, dstAddr, size);
|
||||
}
|
||||
|
||||
@NodeIntrinsic(ForeignCallNode.class)
|
||||
private static native void unsafeArraycopyStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word srcAddr, Word dstAddr, Word size);
|
||||
|
||||
/**
|
||||
* @see VMErrorNode
|
||||
*/
|
||||
|
@ -198,7 +198,7 @@ public class HotSpotGraalCompiler implements GraalJVMCICompiler {
|
||||
|
||||
public CompilationResult compile(ResolvedJavaMethod method, int entryBCI, boolean useProfilingInfo, CompilationIdentifier compilationId, OptionValues options, DebugContext debug) {
|
||||
StructuredGraph graph = createGraph(method, entryBCI, useProfilingInfo, compilationId, options, debug);
|
||||
CompilationResult result = new CompilationResult();
|
||||
CompilationResult result = new CompilationResult(compilationId);
|
||||
return compileHelper(CompilationResultBuilderFactory.Default, result, graph, method, entryBCI, useProfilingInfo, options);
|
||||
}
|
||||
|
||||
|
@ -111,6 +111,7 @@ import jdk.vm.ci.meta.JavaConstant;
|
||||
import jdk.vm.ci.meta.JavaKind;
|
||||
import jdk.vm.ci.meta.MetaAccessProvider;
|
||||
import jdk.vm.ci.meta.ResolvedJavaMethod;
|
||||
import sun.misc.Unsafe;
|
||||
|
||||
/**
|
||||
* Defines the {@link Plugins} used when running on HotSpot.
|
||||
@ -202,6 +203,7 @@ public class HotSpotGraphBuilderPlugins {
|
||||
registerCRC32Plugins(invocationPlugins, config, replacementBytecodeProvider);
|
||||
registerBigIntegerPlugins(invocationPlugins, config, replacementBytecodeProvider);
|
||||
registerSHAPlugins(invocationPlugins, config, replacementBytecodeProvider);
|
||||
registerUnsafePlugins(invocationPlugins, replacementBytecodeProvider);
|
||||
StandardGraphBuilderPlugins.registerInvocationPlugins(metaAccess, snippetReflection, invocationPlugins, replacementBytecodeProvider, true);
|
||||
|
||||
for (NodeIntrinsicPluginFactory factory : GraalServices.load(NodeIntrinsicPluginFactory.class)) {
|
||||
@ -313,6 +315,17 @@ public class HotSpotGraphBuilderPlugins {
|
||||
r.registerMethodSubstitution(ReflectionSubstitutions.class, "getClassAccessFlags", Class.class);
|
||||
}
|
||||
|
||||
private static void registerUnsafePlugins(InvocationPlugins plugins, BytecodeProvider replacementBytecodeProvider) {
|
||||
Registration r;
|
||||
if (Java8OrEarlier) {
|
||||
r = new Registration(plugins, Unsafe.class, replacementBytecodeProvider);
|
||||
} else {
|
||||
r = new Registration(plugins, "jdk.internal.misc.Unsafe", replacementBytecodeProvider);
|
||||
}
|
||||
r.registerMethodSubstitution(HotSpotUnsafeSubstitutions.class, HotSpotUnsafeSubstitutions.copyMemoryName, "copyMemory", Receiver.class, Object.class, long.class, Object.class, long.class,
|
||||
long.class);
|
||||
}
|
||||
|
||||
private static final LocationIdentity INSTANCE_KLASS_CONSTANTS = NamedLocationIdentity.immutable("InstanceKlass::_constants");
|
||||
private static final LocationIdentity CONSTANT_POOL_LENGTH = NamedLocationIdentity.immutable("ConstantPool::_length");
|
||||
|
||||
|
@ -51,6 +51,7 @@ import static org.graalvm.compiler.hotspot.HotSpotBackend.SHA2_IMPL_COMPRESS;
|
||||
import static org.graalvm.compiler.hotspot.HotSpotBackend.SHA5_IMPL_COMPRESS;
|
||||
import static org.graalvm.compiler.hotspot.HotSpotBackend.SHA_IMPL_COMPRESS;
|
||||
import static org.graalvm.compiler.hotspot.HotSpotBackend.SQUARE_TO_LEN;
|
||||
import static org.graalvm.compiler.hotspot.HotSpotBackend.UNSAFE_ARRAYCOPY;
|
||||
import static org.graalvm.compiler.hotspot.HotSpotBackend.UNWIND_EXCEPTION_TO_CALLER;
|
||||
import static org.graalvm.compiler.hotspot.HotSpotBackend.VM_ERROR;
|
||||
import static org.graalvm.compiler.hotspot.HotSpotBackend.WRONG_METHOD_HANDLER;
|
||||
@ -330,6 +331,8 @@ public abstract class HotSpotHostForeignCallsProvider extends HotSpotForeignCall
|
||||
registerCheckcastArraycopyDescriptor(true, c.checkcastArraycopyUninit);
|
||||
registerCheckcastArraycopyDescriptor(false, c.checkcastArraycopy);
|
||||
|
||||
registerForeignCall(UNSAFE_ARRAYCOPY, c.unsafeArraycopy, NativeCall, DESTROYS_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, NamedLocationIdentity.any());
|
||||
|
||||
if (c.useMultiplyToLenIntrinsic()) {
|
||||
registerForeignCall(MULTIPLY_TO_LEN, c.multiplyToLen, NativeCall, DESTROYS_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, NamedLocationIdentity.getArrayLocation(JavaKind.Int));
|
||||
}
|
||||
|
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (c) 2017, 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 org.graalvm.compiler.hotspot.meta;
|
||||
|
||||
import static org.graalvm.compiler.serviceprovider.JDK9Method.Java8OrEarlier;
|
||||
|
||||
import org.graalvm.compiler.api.replacements.ClassSubstitution;
|
||||
import org.graalvm.compiler.api.replacements.MethodSubstitution;
|
||||
import org.graalvm.compiler.hotspot.HotSpotBackend;
|
||||
import org.graalvm.compiler.hotspot.nodes.ComputeObjectAddressNode;
|
||||
import org.graalvm.compiler.word.Word;
|
||||
import org.graalvm.word.WordFactory;
|
||||
|
||||
@ClassSubstitution(className = {"jdk.internal.misc.Unsafe", "sun.misc.Unsafe"})
|
||||
public class HotSpotUnsafeSubstitutions {
|
||||
|
||||
public static final String copyMemoryName = Java8OrEarlier ? "copyMemory" : "copyMemory0";
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@MethodSubstitution(isStatic = false)
|
||||
static void copyMemory(Object receiver, Object srcBase, long srcOffset, Object destBase, long destOffset, long bytes) {
|
||||
Word srcAddr = WordFactory.unsigned(ComputeObjectAddressNode.get(srcBase, srcOffset));
|
||||
Word dstAddr = WordFactory.unsigned(ComputeObjectAddressNode.get(destBase, destOffset));
|
||||
Word size = Word.signed(bytes);
|
||||
HotSpotBackend.unsafeArraycopy(srcAddr, dstAddr, size);
|
||||
}
|
||||
}
|
@ -216,8 +216,9 @@ public abstract class Stub {
|
||||
|
||||
@SuppressWarnings("try")
|
||||
private CompilationResult buildCompilationResult(DebugContext debug, final Backend backend) {
|
||||
CompilationResult compResult = new CompilationResult(toString(), GeneratePIC.getValue(options));
|
||||
final StructuredGraph graph = getGraph(debug, getStubCompilationId());
|
||||
CompilationIdentifier compilationId = getStubCompilationId();
|
||||
final StructuredGraph graph = getGraph(debug, compilationId);
|
||||
CompilationResult compResult = new CompilationResult(compilationId, toString(), GeneratePIC.getValue(options));
|
||||
|
||||
// Stubs cannot be recompiled so they cannot be compiled with assumptions
|
||||
assert graph.getAssumptions() == null;
|
||||
|
@ -365,10 +365,6 @@ final class TraceInterval extends IntervalHint {
|
||||
return intTo;
|
||||
}
|
||||
|
||||
int numUsePositions() {
|
||||
return numUsePos();
|
||||
}
|
||||
|
||||
public void setLocationHint(IntervalHint interval) {
|
||||
locationHint = interval;
|
||||
}
|
||||
@ -452,6 +448,10 @@ final class TraceInterval extends IntervalHint {
|
||||
return spillSt == SpillState.StartInMemory || (spillSt == SpillState.SpillStore && opId > spillDefinitionPos() && !canMaterialize());
|
||||
}
|
||||
|
||||
public boolean preSpilledAllocated() {
|
||||
return spillState() == SpillState.StartInMemory && numUsePos() == 0 && !hasHint();
|
||||
}
|
||||
|
||||
// test intersection
|
||||
boolean intersects(TraceInterval i) {
|
||||
return intersectsAt(i) != -1;
|
||||
|
@ -541,16 +541,23 @@ public final class TraceLinearScanLifetimeAnalysisPhase extends TraceLinearScanA
|
||||
assert instructionIndex == 0 : "not at start?" + instructionIndex;
|
||||
handleTraceBegin(blocks[0]);
|
||||
|
||||
// fix spill state for phi/incoming intervals
|
||||
for (TraceInterval interval : allocator.intervals()) {
|
||||
if (interval != null && interval.spillState().equals(SpillState.NoDefinitionFound) && interval.spillDefinitionPos() != -1) {
|
||||
// there was a definition in a phi/incoming
|
||||
interval.setSpillState(SpillState.NoSpillStore);
|
||||
}
|
||||
}
|
||||
if (TraceRAuseInterTraceHints.getValue(allocator.getLIR().getOptions())) {
|
||||
addInterTraceHints();
|
||||
}
|
||||
// fix spill state for phi/incoming intervals
|
||||
for (TraceInterval interval : allocator.intervals()) {
|
||||
if (interval != null) {
|
||||
if (interval.spillState().equals(SpillState.NoDefinitionFound) && interval.spillDefinitionPos() != -1) {
|
||||
// there was a definition in a phi/incoming
|
||||
interval.setSpillState(SpillState.NoSpillStore);
|
||||
}
|
||||
if (interval.preSpilledAllocated()) {
|
||||
// pre-spill unused, start in memory intervals
|
||||
allocator.assignSpillSlot(interval);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (FixedInterval interval1 : allocator.fixedIntervals()) {
|
||||
if (interval1 != null) {
|
||||
/* We use [-1, 0] to avoid intersection with incoming values. */
|
||||
|
@ -153,7 +153,7 @@ public final class TraceLinearScanPhase extends TraceAllocationPhase<TraceAlloca
|
||||
@Override
|
||||
public boolean apply(TraceInterval i) {
|
||||
// all TraceIntervals are variable intervals
|
||||
return true;
|
||||
return !i.preSpilledAllocated();
|
||||
}
|
||||
};
|
||||
private static final Comparator<TraceInterval> SORT_BY_FROM_COMP = new Comparator<TraceInterval>() {
|
||||
|
@ -319,7 +319,7 @@ public abstract class GraalCompilerState {
|
||||
assert !graph.isFrozen();
|
||||
ResolvedJavaMethod installedCodeOwner = graph.method();
|
||||
request = new Request<>(graph, installedCodeOwner, getProviders(), getBackend(), getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL,
|
||||
graph.getProfilingInfo(), createSuites(getOptions()), createLIRSuites(getOptions()), new CompilationResult(), CompilationResultBuilderFactory.Default);
|
||||
graph.getProfilingInfo(), createSuites(getOptions()), createLIRSuites(getOptions()), new CompilationResult(graph.compilationId()), CompilationResultBuilderFactory.Default);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -209,7 +209,6 @@ public class GraphEncoder {
|
||||
int nodeCount = nodeOrder.nextOrderId;
|
||||
assert nodeOrder.orderIds.get(graph.start()) == START_NODE_ORDER_ID;
|
||||
assert nodeOrder.orderIds.get(graph.start().next()) == FIRST_NODE_ORDER_ID;
|
||||
assert nodeCount == graph.getNodeCount() + 1;
|
||||
|
||||
long[] nodeStartOffsets = new long[nodeCount];
|
||||
UnmodifiableMapCursor<Node, Integer> cursor = nodeOrder.orderIds.getEntries();
|
||||
@ -218,6 +217,7 @@ public class GraphEncoder {
|
||||
Integer orderId = cursor.getValue();
|
||||
|
||||
assert !(node instanceof AbstractBeginNode) || nodeOrder.orderIds.get(((AbstractBeginNode) node).next()) == orderId + BEGIN_NEXT_ORDER_ID_OFFSET;
|
||||
assert nodeStartOffsets[orderId] == 0;
|
||||
nodeStartOffsets[orderId] = writer.getBytesWritten();
|
||||
|
||||
/* Write out the type, properties, and edges. */
|
||||
@ -284,7 +284,6 @@ public class GraphEncoder {
|
||||
writer.putUV(nodeOrder.maxFixedNodeOrderId);
|
||||
writer.putUV(nodeCount);
|
||||
for (int i = 0; i < nodeCount; i++) {
|
||||
assert i == NULL_ORDER_ID || i == START_NODE_ORDER_ID || nodeStartOffsets[i] > 0;
|
||||
writer.putUV(metadataStart - nodeStartOffsets[i]);
|
||||
}
|
||||
|
||||
@ -344,8 +343,25 @@ public class GraphEncoder {
|
||||
} while (current != null);
|
||||
|
||||
maxFixedNodeOrderId = nextOrderId - 1;
|
||||
|
||||
/*
|
||||
* Emit all parameters consecutively at a known location (after all fixed nodes). This
|
||||
* allows substituting parameters when inlining during decoding by pre-initializing the
|
||||
* decoded node list.
|
||||
*
|
||||
* Note that not all parameters must be present (unused parameters are deleted after
|
||||
* parsing). This leads to holes in the orderId, i.e., unused orderIds.
|
||||
*/
|
||||
int parameterCount = graph.method().getSignature().getParameterCount(!graph.method().isStatic());
|
||||
for (ParameterNode node : graph.getNodes(ParameterNode.TYPE)) {
|
||||
assert orderIds.get(node) == null : "Parameter node must not be ordered yet";
|
||||
assert node.index() < parameterCount : "Parameter index out of range";
|
||||
orderIds.set(node, nextOrderId + node.index());
|
||||
}
|
||||
nextOrderId += parameterCount;
|
||||
|
||||
for (Node node : graph.getNodes()) {
|
||||
assert (node instanceof FixedNode) == (orderIds.get(node) != null) : "all fixed nodes must be ordered: " + node;
|
||||
assert (node instanceof FixedNode || node instanceof ParameterNode) == (orderIds.get(node) != null) : "all fixed nodes and ParameterNodes must be ordered: " + node;
|
||||
add(node);
|
||||
}
|
||||
}
|
||||
|
@ -37,6 +37,7 @@ import java.util.List;
|
||||
import org.graalvm.compiler.bytecode.BytecodeDisassembler;
|
||||
import org.graalvm.compiler.code.CompilationResult;
|
||||
import org.graalvm.compiler.code.DisassemblerProvider;
|
||||
import org.graalvm.compiler.core.common.CompilationIdentifier;
|
||||
import org.graalvm.compiler.core.common.alloc.Trace;
|
||||
import org.graalvm.compiler.core.common.alloc.TraceBuilderResult;
|
||||
import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
|
||||
@ -72,6 +73,7 @@ public class CFGPrinterObserver implements DebugDumpHandler {
|
||||
private CFGPrinter cfgPrinter;
|
||||
private File cfgFile;
|
||||
private JavaMethod curMethod;
|
||||
private CompilationIdentifier curCompilation;
|
||||
private List<String> curDecorators = Collections.emptyList();
|
||||
|
||||
@Override
|
||||
@ -92,6 +94,7 @@ public class CFGPrinterObserver implements DebugDumpHandler {
|
||||
*/
|
||||
private boolean checkMethodScope(DebugContext debug) {
|
||||
JavaMethod method = null;
|
||||
CompilationIdentifier compilation = null;
|
||||
ArrayList<String> decorators = new ArrayList<>();
|
||||
for (Object o : debug.context()) {
|
||||
if (o instanceof JavaMethod) {
|
||||
@ -102,22 +105,33 @@ public class CFGPrinterObserver implements DebugDumpHandler {
|
||||
if (graph.method() != null) {
|
||||
method = graph.method();
|
||||
decorators.clear();
|
||||
compilation = graph.compilationId();
|
||||
}
|
||||
} else if (o instanceof DebugDumpScope) {
|
||||
DebugDumpScope debugDumpScope = (DebugDumpScope) o;
|
||||
if (debugDumpScope.decorator) {
|
||||
decorators.add(debugDumpScope.name);
|
||||
}
|
||||
} else if (o instanceof CompilationResult) {
|
||||
CompilationResult compilationResult = (CompilationResult) o;
|
||||
compilation = compilationResult.getCompilationId();
|
||||
}
|
||||
}
|
||||
|
||||
if (method == null) {
|
||||
if (method == null && compilation == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!method.equals(curMethod) || !curDecorators.equals(decorators)) {
|
||||
cfgPrinter.printCompilation(method);
|
||||
if (compilation != null) {
|
||||
if (!compilation.equals(curCompilation) || !curDecorators.equals(decorators)) {
|
||||
cfgPrinter.printCompilation(compilation);
|
||||
}
|
||||
} else {
|
||||
if (!method.equals(curMethod) || !curDecorators.equals(decorators)) {
|
||||
cfgPrinter.printCompilation(method);
|
||||
}
|
||||
}
|
||||
curCompilation = compilation;
|
||||
curMethod = method;
|
||||
curDecorators = decorators;
|
||||
return true;
|
||||
@ -277,6 +291,7 @@ public class CFGPrinterObserver implements DebugDumpHandler {
|
||||
cfgPrinter = null;
|
||||
curDecorators = Collections.emptyList();
|
||||
curMethod = null;
|
||||
curCompilation = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -31,6 +31,7 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.graalvm.compiler.core.common.CompilationIdentifier;
|
||||
import org.graalvm.compiler.debug.LogStream;
|
||||
import org.graalvm.compiler.debug.TTY;
|
||||
import org.graalvm.compiler.lir.util.IndexedValueMap;
|
||||
@ -115,12 +116,25 @@ public class CompilationPrinter implements Closeable {
|
||||
/**
|
||||
* Prints a compilation timestamp for a given method.
|
||||
*
|
||||
* @param method the method for which a timestamp will be printed
|
||||
* @param javaMethod the method for which a timestamp will be printed
|
||||
*/
|
||||
public void printCompilation(JavaMethod method) {
|
||||
public void printCompilation(JavaMethod javaMethod) {
|
||||
printCompilation(javaMethod.format("%H::%n"), javaMethod.format("%f %r %H.%n(%p)"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints a compilation id.
|
||||
*
|
||||
* @param compilationId the compilation method for which an id will be printed
|
||||
*/
|
||||
public void printCompilation(CompilationIdentifier compilationId) {
|
||||
printCompilation(compilationId.toString(CompilationIdentifier.Verbosity.DETAILED), compilationId.toString(CompilationIdentifier.Verbosity.DETAILED));
|
||||
}
|
||||
|
||||
private void printCompilation(final String name, String method) {
|
||||
begin("compilation");
|
||||
out.print("name \" ").print(method.format("%H::%n")).println('"');
|
||||
out.print("method \"").print(method.format("%f %r %H.%n(%p)")).println('"');
|
||||
out.print("name \" ").print(name).println('"');
|
||||
out.print("method \"").print(method).println('"');
|
||||
out.print("date ").println(System.currentTimeMillis());
|
||||
end("compilation");
|
||||
}
|
||||
|
@ -95,10 +95,13 @@ public final class ClassSubstitutionVerifier extends AbstractVerifier {
|
||||
TypeElement typeElement = null;
|
||||
for (String className : classNames) {
|
||||
typeElement = env.getElementUtils().getTypeElement(className);
|
||||
if (typeElement == null && !optional) {
|
||||
env.getMessager().printMessage(Kind.ERROR, String.format("The class '%s' was not found on the classpath.", stringValue), sourceElement, classSubstition, stringValue);
|
||||
if (typeElement != null) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (typeElement == null && !optional) {
|
||||
env.getMessager().printMessage(Kind.ERROR, String.format("The class '%s' was not found on the classpath.", stringValue), sourceElement, classSubstition, stringValue);
|
||||
}
|
||||
|
||||
return typeElement;
|
||||
}
|
||||
|
@ -707,10 +707,22 @@ public abstract class PEGraphDecoder extends SimplifyingGraphDecoder {
|
||||
}
|
||||
}
|
||||
|
||||
LoopScope inlineLoopScope = createInitialLoopScope(inlineScope, predecessor);
|
||||
|
||||
/*
|
||||
* The GraphEncoder assigns parameters a nodeId immediately after the fixed nodes.
|
||||
* Initializing createdNodes here avoid decoding and immediately replacing the
|
||||
* ParameterNodes.
|
||||
*/
|
||||
int firstArgumentNodeId = inlineScope.maxFixedNodeOrderId + 1;
|
||||
for (int i = 0; i < arguments.length; i++) {
|
||||
inlineLoopScope.createdNodes[firstArgumentNodeId + i] = arguments[i];
|
||||
}
|
||||
|
||||
/*
|
||||
* Do the actual inlining by returning the initial loop scope for the inlined method scope.
|
||||
*/
|
||||
return createInitialLoopScope(inlineScope, predecessor);
|
||||
return inlineLoopScope;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -1028,9 +1040,7 @@ public abstract class PEGraphDecoder extends SimplifyingGraphDecoder {
|
||||
if (node instanceof ParameterNode) {
|
||||
ParameterNode param = (ParameterNode) node;
|
||||
if (methodScope.isInlinedMethod()) {
|
||||
Node result = methodScope.arguments[param.index()];
|
||||
assert result != null;
|
||||
return result;
|
||||
throw GraalError.shouldNotReachHere("Parameter nodes are already registered when the inlined scope is created");
|
||||
|
||||
} else if (parameterPlugin != null) {
|
||||
assert !methodScope.isInlinedMethod();
|
||||
|
@ -1185,62 +1185,6 @@ const char* os::dll_file_extension() { return ".so"; }
|
||||
// directory not the java application's temp directory, ala java.io.tmpdir.
|
||||
const char* os::get_temp_directory() { return "/tmp"; }
|
||||
|
||||
static bool file_exists(const char* filename) {
|
||||
struct stat statbuf;
|
||||
if (filename == NULL || strlen(filename) == 0) {
|
||||
return false;
|
||||
}
|
||||
return os::stat(filename, &statbuf) == 0;
|
||||
}
|
||||
|
||||
bool os::dll_build_name(char* buffer, size_t buflen,
|
||||
const char* pname, const char* fname) {
|
||||
bool retval = false;
|
||||
// Copied from libhpi
|
||||
const size_t pnamelen = pname ? strlen(pname) : 0;
|
||||
|
||||
// Return error on buffer overflow.
|
||||
if (pnamelen + strlen(fname) + 10 > (size_t) buflen) {
|
||||
*buffer = '\0';
|
||||
return retval;
|
||||
}
|
||||
|
||||
if (pnamelen == 0) {
|
||||
snprintf(buffer, buflen, "lib%s.so", fname);
|
||||
retval = true;
|
||||
} else if (strchr(pname, *os::path_separator()) != NULL) {
|
||||
int n;
|
||||
char** pelements = split_path(pname, &n);
|
||||
if (pelements == NULL) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < n; i++) {
|
||||
// Really shouldn't be NULL, but check can't hurt
|
||||
if (pelements[i] == NULL || strlen(pelements[i]) == 0) {
|
||||
continue; // skip the empty path values
|
||||
}
|
||||
snprintf(buffer, buflen, "%s/lib%s.so", pelements[i], fname);
|
||||
if (file_exists(buffer)) {
|
||||
retval = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// release the storage
|
||||
for (int i = 0; i < n; i++) {
|
||||
if (pelements[i] != NULL) {
|
||||
FREE_C_HEAP_ARRAY(char, pelements[i]);
|
||||
}
|
||||
}
|
||||
if (pelements != NULL) {
|
||||
FREE_C_HEAP_ARRAY(char*, pelements);
|
||||
}
|
||||
} else {
|
||||
snprintf(buffer, buflen, "%s/lib%s.so", pname, fname);
|
||||
retval = true;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
// Check if addr is inside libjvm.so.
|
||||
bool os::address_is_in_vm(address addr) {
|
||||
|
||||
@ -1493,12 +1437,7 @@ void os::get_summary_cpu_info(char* buf, size_t buflen) {
|
||||
}
|
||||
|
||||
void os::pd_print_cpu_info(outputStream* st, char* buf, size_t buflen) {
|
||||
st->print("CPU:");
|
||||
st->print("total %d", os::processor_count());
|
||||
// It's not safe to query number of active processors after crash.
|
||||
// st->print("(active %d)", os::active_processor_count());
|
||||
st->print(" %s", VM_Version::features());
|
||||
st->cr();
|
||||
// Nothing to do beyond what os::print_cpu_info() does.
|
||||
}
|
||||
|
||||
static void print_signal_handler(outputStream* st, int sig,
|
||||
@ -2668,11 +2607,10 @@ void os::hint_no_preempt() {}
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// suspend/resume support
|
||||
|
||||
// the low-level signal-based suspend/resume support is a remnant from the
|
||||
// The low-level signal-based suspend/resume support is a remnant from the
|
||||
// old VM-suspension that used to be for java-suspension, safepoints etc,
|
||||
// within hotspot. Now there is a single use-case for this:
|
||||
// - calling get_thread_pc() on the VMThread by the flat-profiler task
|
||||
// that runs in the watcher thread.
|
||||
// within hotspot. Currently used by JFR's OSThreadSampler
|
||||
//
|
||||
// The remaining code is greatly simplified from the more general suspension
|
||||
// code that used to be used.
|
||||
//
|
||||
@ -2688,7 +2626,13 @@ void os::hint_no_preempt() {}
|
||||
//
|
||||
// Note that the SR_lock plays no role in this suspend/resume protocol,
|
||||
// but is checked for NULL in SR_handler as a thread termination indicator.
|
||||
// The SR_lock is, however, used by JavaThread::java_suspend()/java_resume() APIs.
|
||||
//
|
||||
// Note that resume_clear_context() and suspend_save_context() are needed
|
||||
// by SR_handler(), so that fetch_frame_from_ucontext() works,
|
||||
// which in part is used by:
|
||||
// - Forte Analyzer: AsyncGetCallTrace()
|
||||
// - StackBanging: get_frame_at_stack_banging_point()
|
||||
|
||||
static void resume_clear_context(OSThread *osthread) {
|
||||
osthread->set_ucontext(NULL);
|
||||
@ -3695,44 +3639,6 @@ void os::SuspendedThreadTask::internal_do_task() {
|
||||
}
|
||||
}
|
||||
|
||||
class PcFetcher : public os::SuspendedThreadTask {
|
||||
public:
|
||||
PcFetcher(Thread* thread) : os::SuspendedThreadTask(thread) {}
|
||||
ExtendedPC result();
|
||||
protected:
|
||||
void do_task(const os::SuspendedThreadTaskContext& context);
|
||||
private:
|
||||
ExtendedPC _epc;
|
||||
};
|
||||
|
||||
ExtendedPC PcFetcher::result() {
|
||||
guarantee(is_done(), "task is not done yet.");
|
||||
return _epc;
|
||||
}
|
||||
|
||||
void PcFetcher::do_task(const os::SuspendedThreadTaskContext& context) {
|
||||
Thread* thread = context.thread();
|
||||
OSThread* osthread = thread->osthread();
|
||||
if (osthread->ucontext() != NULL) {
|
||||
_epc = os::Aix::ucontext_get_pc((const ucontext_t *) context.ucontext());
|
||||
} else {
|
||||
// NULL context is unexpected, double-check this is the VMThread.
|
||||
guarantee(thread->is_VM_thread(), "can only be called for VMThread");
|
||||
}
|
||||
}
|
||||
|
||||
// Suspends the target using the signal mechanism and then grabs the PC before
|
||||
// resuming the target. Used by the flat-profiler only
|
||||
ExtendedPC os::get_thread_pc(Thread* thread) {
|
||||
// Make sure that it is called by the watcher for the VMThread.
|
||||
assert(Thread::current()->is_Watcher_thread(), "Must be watcher");
|
||||
assert(thread->is_VM_thread(), "Can only be called for VMThread");
|
||||
|
||||
PcFetcher fetcher(thread);
|
||||
fetcher.run();
|
||||
return fetcher.result();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// debug support
|
||||
|
||||
|
@ -1172,13 +1172,6 @@ int os::current_process_id() {
|
||||
|
||||
// DLL functions
|
||||
|
||||
#define JNI_LIB_PREFIX "lib"
|
||||
#ifdef __APPLE__
|
||||
#define JNI_LIB_SUFFIX ".dylib"
|
||||
#else
|
||||
#define JNI_LIB_SUFFIX ".so"
|
||||
#endif
|
||||
|
||||
const char* os::dll_file_extension() { return JNI_LIB_SUFFIX; }
|
||||
|
||||
// This must be hard coded because it's the system's temporary
|
||||
@ -1201,62 +1194,6 @@ const char* os::get_temp_directory() {
|
||||
const char* os::get_temp_directory() { return "/tmp"; }
|
||||
#endif // __APPLE__
|
||||
|
||||
static bool file_exists(const char* filename) {
|
||||
struct stat statbuf;
|
||||
if (filename == NULL || strlen(filename) == 0) {
|
||||
return false;
|
||||
}
|
||||
return os::stat(filename, &statbuf) == 0;
|
||||
}
|
||||
|
||||
bool os::dll_build_name(char* buffer, size_t buflen,
|
||||
const char* pname, const char* fname) {
|
||||
bool retval = false;
|
||||
// Copied from libhpi
|
||||
const size_t pnamelen = pname ? strlen(pname) : 0;
|
||||
|
||||
// Return error on buffer overflow.
|
||||
if (pnamelen + strlen(fname) + strlen(JNI_LIB_PREFIX) + strlen(JNI_LIB_SUFFIX) + 2 > buflen) {
|
||||
return retval;
|
||||
}
|
||||
|
||||
if (pnamelen == 0) {
|
||||
snprintf(buffer, buflen, JNI_LIB_PREFIX "%s" JNI_LIB_SUFFIX, fname);
|
||||
retval = true;
|
||||
} else if (strchr(pname, *os::path_separator()) != NULL) {
|
||||
int n;
|
||||
char** pelements = split_path(pname, &n);
|
||||
if (pelements == NULL) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < n; i++) {
|
||||
// Really shouldn't be NULL, but check can't hurt
|
||||
if (pelements[i] == NULL || strlen(pelements[i]) == 0) {
|
||||
continue; // skip the empty path values
|
||||
}
|
||||
snprintf(buffer, buflen, "%s/" JNI_LIB_PREFIX "%s" JNI_LIB_SUFFIX,
|
||||
pelements[i], fname);
|
||||
if (file_exists(buffer)) {
|
||||
retval = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// release the storage
|
||||
for (int i = 0; i < n; i++) {
|
||||
if (pelements[i] != NULL) {
|
||||
FREE_C_HEAP_ARRAY(char, pelements[i]);
|
||||
}
|
||||
}
|
||||
if (pelements != NULL) {
|
||||
FREE_C_HEAP_ARRAY(char*, pelements);
|
||||
}
|
||||
} else {
|
||||
snprintf(buffer, buflen, "%s/" JNI_LIB_PREFIX "%s" JNI_LIB_SUFFIX, pname, fname);
|
||||
retval = true;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
// check if addr is inside libjvm.so
|
||||
bool os::address_is_in_vm(address addr) {
|
||||
static address libjvm_base_addr;
|
||||
@ -2666,11 +2603,10 @@ void os::hint_no_preempt() {}
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// suspend/resume support
|
||||
|
||||
// the low-level signal-based suspend/resume support is a remnant from the
|
||||
// The low-level signal-based suspend/resume support is a remnant from the
|
||||
// old VM-suspension that used to be for java-suspension, safepoints etc,
|
||||
// within hotspot. Now there is a single use-case for this:
|
||||
// - calling get_thread_pc() on the VMThread by the flat-profiler task
|
||||
// that runs in the watcher thread.
|
||||
// within hotspot. Currently used by JFR's OSThreadSampler
|
||||
//
|
||||
// The remaining code is greatly simplified from the more general suspension
|
||||
// code that used to be used.
|
||||
//
|
||||
@ -2686,6 +2622,13 @@ void os::hint_no_preempt() {}
|
||||
//
|
||||
// Note that the SR_lock plays no role in this suspend/resume protocol,
|
||||
// but is checked for NULL in SR_handler as a thread termination indicator.
|
||||
// The SR_lock is, however, used by JavaThread::java_suspend()/java_resume() APIs.
|
||||
//
|
||||
// Note that resume_clear_context() and suspend_save_context() are needed
|
||||
// by SR_handler(), so that fetch_frame_from_ucontext() works,
|
||||
// which in part is used by:
|
||||
// - Forte Analyzer: AsyncGetCallTrace()
|
||||
// - StackBanging: get_frame_at_stack_banging_point()
|
||||
|
||||
static void resume_clear_context(OSThread *osthread) {
|
||||
osthread->set_ucontext(NULL);
|
||||
@ -3584,45 +3527,6 @@ void os::SuspendedThreadTask::internal_do_task() {
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
class PcFetcher : public os::SuspendedThreadTask {
|
||||
public:
|
||||
PcFetcher(Thread* thread) : os::SuspendedThreadTask(thread) {}
|
||||
ExtendedPC result();
|
||||
protected:
|
||||
void do_task(const os::SuspendedThreadTaskContext& context);
|
||||
private:
|
||||
ExtendedPC _epc;
|
||||
};
|
||||
|
||||
ExtendedPC PcFetcher::result() {
|
||||
guarantee(is_done(), "task is not done yet.");
|
||||
return _epc;
|
||||
}
|
||||
|
||||
void PcFetcher::do_task(const os::SuspendedThreadTaskContext& context) {
|
||||
Thread* thread = context.thread();
|
||||
OSThread* osthread = thread->osthread();
|
||||
if (osthread->ucontext() != NULL) {
|
||||
_epc = os::Bsd::ucontext_get_pc((const ucontext_t *) context.ucontext());
|
||||
} else {
|
||||
// NULL context is unexpected, double-check this is the VMThread
|
||||
guarantee(thread->is_VM_thread(), "can only be called for VMThread");
|
||||
}
|
||||
}
|
||||
|
||||
// Suspends the target using the signal mechanism and then grabs the PC before
|
||||
// resuming the target. Used by the flat-profiler only
|
||||
ExtendedPC os::get_thread_pc(Thread* thread) {
|
||||
// Make sure that it is called by the watcher for the VMThread
|
||||
assert(Thread::current()->is_Watcher_thread(), "Must be watcher");
|
||||
assert(thread->is_VM_thread(), "Can only be called for VMThread");
|
||||
|
||||
PcFetcher fetcher(thread);
|
||||
fetcher.run();
|
||||
return fetcher.result();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// debug support
|
||||
|
||||
|
@ -1419,53 +1419,6 @@ static bool file_exists(const char* filename) {
|
||||
return os::stat(filename, &statbuf) == 0;
|
||||
}
|
||||
|
||||
bool os::dll_build_name(char* buffer, size_t buflen,
|
||||
const char* pname, const char* fname) {
|
||||
bool retval = false;
|
||||
// Copied from libhpi
|
||||
const size_t pnamelen = pname ? strlen(pname) : 0;
|
||||
|
||||
// Return error on buffer overflow.
|
||||
if (pnamelen + strlen(fname) + 10 > (size_t) buflen) {
|
||||
return retval;
|
||||
}
|
||||
|
||||
if (pnamelen == 0) {
|
||||
snprintf(buffer, buflen, "lib%s.so", fname);
|
||||
retval = true;
|
||||
} else if (strchr(pname, *os::path_separator()) != NULL) {
|
||||
int n;
|
||||
char** pelements = split_path(pname, &n);
|
||||
if (pelements == NULL) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < n; i++) {
|
||||
// Really shouldn't be NULL, but check can't hurt
|
||||
if (pelements[i] == NULL || strlen(pelements[i]) == 0) {
|
||||
continue; // skip the empty path values
|
||||
}
|
||||
snprintf(buffer, buflen, "%s/lib%s.so", pelements[i], fname);
|
||||
if (file_exists(buffer)) {
|
||||
retval = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// release the storage
|
||||
for (int i = 0; i < n; i++) {
|
||||
if (pelements[i] != NULL) {
|
||||
FREE_C_HEAP_ARRAY(char, pelements[i]);
|
||||
}
|
||||
}
|
||||
if (pelements != NULL) {
|
||||
FREE_C_HEAP_ARRAY(char*, pelements);
|
||||
}
|
||||
} else {
|
||||
snprintf(buffer, buflen, "%s/lib%s.so", pname, fname);
|
||||
retval = true;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
// check if addr is inside libjvm.so
|
||||
bool os::address_is_in_vm(address addr) {
|
||||
static address libjvm_base_addr;
|
||||
@ -4047,11 +4000,10 @@ void os::hint_no_preempt() {}
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// suspend/resume support
|
||||
|
||||
// the low-level signal-based suspend/resume support is a remnant from the
|
||||
// The low-level signal-based suspend/resume support is a remnant from the
|
||||
// old VM-suspension that used to be for java-suspension, safepoints etc,
|
||||
// within hotspot. Now there is a single use-case for this:
|
||||
// - calling get_thread_pc() on the VMThread by the flat-profiler task
|
||||
// that runs in the watcher thread.
|
||||
// within hotspot. Currently used by JFR's OSThreadSampler
|
||||
//
|
||||
// The remaining code is greatly simplified from the more general suspension
|
||||
// code that used to be used.
|
||||
//
|
||||
@ -4067,6 +4019,13 @@ void os::hint_no_preempt() {}
|
||||
//
|
||||
// Note that the SR_lock plays no role in this suspend/resume protocol,
|
||||
// but is checked for NULL in SR_handler as a thread termination indicator.
|
||||
// The SR_lock is, however, used by JavaThread::java_suspend()/java_resume() APIs.
|
||||
//
|
||||
// Note that resume_clear_context() and suspend_save_context() are needed
|
||||
// by SR_handler(), so that fetch_frame_from_ucontext() works,
|
||||
// which in part is used by:
|
||||
// - Forte Analyzer: AsyncGetCallTrace()
|
||||
// - StackBanging: get_frame_at_stack_banging_point()
|
||||
|
||||
static void resume_clear_context(OSThread *osthread) {
|
||||
osthread->set_ucontext(NULL);
|
||||
@ -5107,44 +5066,6 @@ void os::SuspendedThreadTask::internal_do_task() {
|
||||
}
|
||||
}
|
||||
|
||||
class PcFetcher : public os::SuspendedThreadTask {
|
||||
public:
|
||||
PcFetcher(Thread* thread) : os::SuspendedThreadTask(thread) {}
|
||||
ExtendedPC result();
|
||||
protected:
|
||||
void do_task(const os::SuspendedThreadTaskContext& context);
|
||||
private:
|
||||
ExtendedPC _epc;
|
||||
};
|
||||
|
||||
ExtendedPC PcFetcher::result() {
|
||||
guarantee(is_done(), "task is not done yet.");
|
||||
return _epc;
|
||||
}
|
||||
|
||||
void PcFetcher::do_task(const os::SuspendedThreadTaskContext& context) {
|
||||
Thread* thread = context.thread();
|
||||
OSThread* osthread = thread->osthread();
|
||||
if (osthread->ucontext() != NULL) {
|
||||
_epc = os::Linux::ucontext_get_pc((const ucontext_t *) context.ucontext());
|
||||
} else {
|
||||
// NULL context is unexpected, double-check this is the VMThread
|
||||
guarantee(thread->is_VM_thread(), "can only be called for VMThread");
|
||||
}
|
||||
}
|
||||
|
||||
// Suspends the target using the signal mechanism and then grabs the PC before
|
||||
// resuming the target. Used by the flat-profiler only
|
||||
ExtendedPC os::get_thread_pc(Thread* thread) {
|
||||
// Make sure that it is called by the watcher for the VMThread
|
||||
assert(Thread::current()->is_Watcher_thread(), "Must be watcher");
|
||||
assert(thread->is_VM_thread(), "Can only be called for VMThread");
|
||||
|
||||
PcFetcher fetcher(thread);
|
||||
fetcher.run();
|
||||
return fetcher.result();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// debug support
|
||||
|
||||
|
@ -24,7 +24,6 @@
|
||||
|
||||
#include "utilities/globalDefinitions.hpp"
|
||||
#include "prims/jvm.h"
|
||||
#include "semaphore_posix.hpp"
|
||||
#include "runtime/frame.inline.hpp"
|
||||
#include "runtime/interfaceSupport.hpp"
|
||||
#include "runtime/os.hpp"
|
||||
@ -32,6 +31,11 @@
|
||||
#include "utilities/macros.hpp"
|
||||
#include "utilities/vmError.hpp"
|
||||
|
||||
#ifndef __APPLE__
|
||||
// POSIX unamed semaphores are not supported on OS X.
|
||||
#include "semaphore_posix.hpp"
|
||||
#endif
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <pthread.h>
|
||||
#include <semaphore.h>
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2017, 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
|
||||
@ -65,12 +65,6 @@
|
||||
void set_lwp_id(uint id) { _lwp_id = id; }
|
||||
void set_native_priority(int prio) { _native_priority = prio; }
|
||||
|
||||
// ***************************************************************
|
||||
// interrupt support. interrupts (using signals) are used to get
|
||||
// the thread context (get_thread_pc), to set the thread context
|
||||
// (set_thread_pc), and to implement java.lang.Thread.interrupt.
|
||||
// ***************************************************************
|
||||
|
||||
public:
|
||||
os::SuspendResume sr;
|
||||
|
||||
|
@ -1356,60 +1356,6 @@ const char* os::dll_file_extension() { return ".so"; }
|
||||
// directory not the java application's temp directory, ala java.io.tmpdir.
|
||||
const char* os::get_temp_directory() { return "/tmp"; }
|
||||
|
||||
static bool file_exists(const char* filename) {
|
||||
struct stat statbuf;
|
||||
if (filename == NULL || strlen(filename) == 0) {
|
||||
return false;
|
||||
}
|
||||
return os::stat(filename, &statbuf) == 0;
|
||||
}
|
||||
|
||||
bool os::dll_build_name(char* buffer, size_t buflen,
|
||||
const char* pname, const char* fname) {
|
||||
bool retval = false;
|
||||
const size_t pnamelen = pname ? strlen(pname) : 0;
|
||||
|
||||
// Return error on buffer overflow.
|
||||
if (pnamelen + strlen(fname) + 10 > (size_t) buflen) {
|
||||
return retval;
|
||||
}
|
||||
|
||||
if (pnamelen == 0) {
|
||||
snprintf(buffer, buflen, "lib%s.so", fname);
|
||||
retval = true;
|
||||
} else if (strchr(pname, *os::path_separator()) != NULL) {
|
||||
int n;
|
||||
char** pelements = split_path(pname, &n);
|
||||
if (pelements == NULL) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < n; i++) {
|
||||
// really shouldn't be NULL but what the heck, check can't hurt
|
||||
if (pelements[i] == NULL || strlen(pelements[i]) == 0) {
|
||||
continue; // skip the empty path values
|
||||
}
|
||||
snprintf(buffer, buflen, "%s/lib%s.so", pelements[i], fname);
|
||||
if (file_exists(buffer)) {
|
||||
retval = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// release the storage
|
||||
for (int i = 0; i < n; i++) {
|
||||
if (pelements[i] != NULL) {
|
||||
FREE_C_HEAP_ARRAY(char, pelements[i]);
|
||||
}
|
||||
}
|
||||
if (pelements != NULL) {
|
||||
FREE_C_HEAP_ARRAY(char*, pelements);
|
||||
}
|
||||
} else {
|
||||
snprintf(buffer, buflen, "%s/lib%s.so", pname, fname);
|
||||
retval = true;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
// check if addr is inside libjvm.so
|
||||
bool os::address_is_in_vm(address addr) {
|
||||
static address libjvm_base_addr;
|
||||
@ -3496,6 +3442,37 @@ void os::hint_no_preempt() {
|
||||
schedctl_start(schedctl_init());
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// suspend/resume support
|
||||
|
||||
// The low-level signal-based suspend/resume support is a remnant from the
|
||||
// old VM-suspension that used to be for java-suspension, safepoints etc,
|
||||
// within hotspot. Currently used by JFR's OSThreadSampler
|
||||
//
|
||||
// The remaining code is greatly simplified from the more general suspension
|
||||
// code that used to be used.
|
||||
//
|
||||
// The protocol is quite simple:
|
||||
// - suspend:
|
||||
// - sends a signal to the target thread
|
||||
// - polls the suspend state of the osthread using a yield loop
|
||||
// - target thread signal handler (SR_handler) sets suspend state
|
||||
// and blocks in sigsuspend until continued
|
||||
// - resume:
|
||||
// - sets target osthread state to continue
|
||||
// - sends signal to end the sigsuspend loop in the SR_handler
|
||||
//
|
||||
// Note that the SR_lock plays no role in this suspend/resume protocol,
|
||||
// but is checked for NULL in SR_handler as a thread termination indicator.
|
||||
// The SR_lock is, however, used by JavaThread::java_suspend()/java_resume() APIs.
|
||||
//
|
||||
// Note that resume_clear_context() and suspend_save_context() are needed
|
||||
// by SR_handler(), so that fetch_frame_from_ucontext() works,
|
||||
// which in part is used by:
|
||||
// - Forte Analyzer: AsyncGetCallTrace()
|
||||
// - StackBanging: get_frame_at_stack_banging_point()
|
||||
// - JFR: get_topframe()-->....-->get_valid_uc_in_signal_handler()
|
||||
|
||||
static void resume_clear_context(OSThread *osthread) {
|
||||
osthread->set_ucontext(NULL);
|
||||
}
|
||||
@ -3506,7 +3483,7 @@ static void suspend_save_context(OSThread *osthread, ucontext_t* context) {
|
||||
|
||||
static PosixSemaphore sr_semaphore;
|
||||
|
||||
void os::Solaris::SR_handler(Thread* thread, ucontext_t* uc) {
|
||||
void os::Solaris::SR_handler(Thread* thread, ucontext_t* context) {
|
||||
// Save and restore errno to avoid confusing native code with EINTR
|
||||
// after sigsuspend.
|
||||
int old_errno = errno;
|
||||
@ -3516,7 +3493,7 @@ void os::Solaris::SR_handler(Thread* thread, ucontext_t* uc) {
|
||||
|
||||
os::SuspendResume::State current = osthread->sr.state();
|
||||
if (current == os::SuspendResume::SR_SUSPEND_REQUEST) {
|
||||
suspend_save_context(osthread, uc);
|
||||
suspend_save_context(osthread, context);
|
||||
|
||||
// attempt to switch the state, we assume we had a SUSPEND_REQUEST
|
||||
os::SuspendResume::State state = osthread->sr.suspended();
|
||||
@ -3663,45 +3640,6 @@ void os::SuspendedThreadTask::internal_do_task() {
|
||||
}
|
||||
}
|
||||
|
||||
class PcFetcher : public os::SuspendedThreadTask {
|
||||
public:
|
||||
PcFetcher(Thread* thread) : os::SuspendedThreadTask(thread) {}
|
||||
ExtendedPC result();
|
||||
protected:
|
||||
void do_task(const os::SuspendedThreadTaskContext& context);
|
||||
private:
|
||||
ExtendedPC _epc;
|
||||
};
|
||||
|
||||
ExtendedPC PcFetcher::result() {
|
||||
guarantee(is_done(), "task is not done yet.");
|
||||
return _epc;
|
||||
}
|
||||
|
||||
void PcFetcher::do_task(const os::SuspendedThreadTaskContext& context) {
|
||||
Thread* thread = context.thread();
|
||||
OSThread* osthread = thread->osthread();
|
||||
if (osthread->ucontext() != NULL) {
|
||||
_epc = os::Solaris::ucontext_get_pc((const ucontext_t *) context.ucontext());
|
||||
} else {
|
||||
// NULL context is unexpected, double-check this is the VMThread
|
||||
guarantee(thread->is_VM_thread(), "can only be called for VMThread");
|
||||
}
|
||||
}
|
||||
|
||||
// A lightweight implementation that does not suspend the target thread and
|
||||
// thus returns only a hint. Used for profiling only!
|
||||
ExtendedPC os::get_thread_pc(Thread* thread) {
|
||||
// Make sure that it is called by the watcher and the Threads lock is owned.
|
||||
assert(Thread::current()->is_Watcher_thread(), "Must be watcher and own Threads_lock");
|
||||
// For now, is only used to profile the VM Thread
|
||||
assert(thread->is_VM_thread(), "Can only be called for VMThread");
|
||||
PcFetcher fetcher(thread);
|
||||
fetcher.run();
|
||||
return fetcher.result();
|
||||
}
|
||||
|
||||
|
||||
// This does not do anything on Solaris. This is basically a hook for being
|
||||
// able to use structured exception handling (thread-local exception filters) on, e.g., Win32.
|
||||
void os::os_exception_wrapper(java_call_t f, JavaValue* value,
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2017, 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
|
||||
@ -27,160 +27,99 @@
|
||||
#include "runtime/arguments.hpp"
|
||||
#include "runtime/os.hpp"
|
||||
#include "decoder_windows.hpp"
|
||||
#include "windbghelp.hpp"
|
||||
|
||||
WindowsDecoder::WindowsDecoder() {
|
||||
_dbghelp_handle = NULL;
|
||||
_can_decode_in_vm = false;
|
||||
_pfnSymGetSymFromAddr64 = NULL;
|
||||
_pfnUndecorateSymbolName = NULL;
|
||||
#ifdef AMD64
|
||||
_pfnStackWalk64 = NULL;
|
||||
_pfnSymFunctionTableAccess64 = NULL;
|
||||
_pfnSymGetModuleBase64 = NULL;
|
||||
#endif
|
||||
_can_decode_in_vm = true;
|
||||
_decoder_status = no_error;
|
||||
initialize();
|
||||
}
|
||||
|
||||
void WindowsDecoder::initialize() {
|
||||
if (!has_error() && _dbghelp_handle == NULL) {
|
||||
HMODULE handle = ::LoadLibrary("dbghelp.dll");
|
||||
if (!handle) {
|
||||
_decoder_status = helper_not_found;
|
||||
return;
|
||||
}
|
||||
|
||||
_dbghelp_handle = handle;
|
||||
|
||||
pfn_SymSetOptions _pfnSymSetOptions = (pfn_SymSetOptions)::GetProcAddress(handle, "SymSetOptions");
|
||||
pfn_SymInitialize _pfnSymInitialize = (pfn_SymInitialize)::GetProcAddress(handle, "SymInitialize");
|
||||
_pfnSymGetSymFromAddr64 = (pfn_SymGetSymFromAddr64)::GetProcAddress(handle, "SymGetSymFromAddr64");
|
||||
_pfnUndecorateSymbolName = (pfn_UndecorateSymbolName)::GetProcAddress(handle, "UnDecorateSymbolName");
|
||||
|
||||
if (_pfnSymSetOptions == NULL || _pfnSymInitialize == NULL || _pfnSymGetSymFromAddr64 == NULL) {
|
||||
uninitialize();
|
||||
_decoder_status = helper_func_error;
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef AMD64
|
||||
_pfnStackWalk64 = (pfn_StackWalk64)::GetProcAddress(handle, "StackWalk64");
|
||||
_pfnSymFunctionTableAccess64 = (pfn_SymFunctionTableAccess64)::GetProcAddress(handle, "SymFunctionTableAccess64");
|
||||
_pfnSymGetModuleBase64 = (pfn_SymGetModuleBase64)::GetProcAddress(handle, "SymGetModuleBase64");
|
||||
if (_pfnStackWalk64 == NULL || _pfnSymFunctionTableAccess64 == NULL || _pfnSymGetModuleBase64 == NULL) {
|
||||
// We can't call StackWalk64 to walk the stack, but we are still
|
||||
// able to decode the symbols. Let's limp on.
|
||||
_pfnStackWalk64 = NULL;
|
||||
_pfnSymFunctionTableAccess64 = NULL;
|
||||
_pfnSymGetModuleBase64 = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!has_error()) {
|
||||
HANDLE hProcess = ::GetCurrentProcess();
|
||||
_pfnSymSetOptions(SYMOPT_UNDNAME | SYMOPT_DEFERRED_LOADS | SYMOPT_EXACT_SYMBOLS);
|
||||
if (!_pfnSymInitialize(hProcess, NULL, TRUE)) {
|
||||
_pfnSymGetSymFromAddr64 = NULL;
|
||||
_pfnUndecorateSymbolName = NULL;
|
||||
::FreeLibrary(handle);
|
||||
_dbghelp_handle = NULL;
|
||||
WindowsDbgHelp::symSetOptions(SYMOPT_UNDNAME | SYMOPT_DEFERRED_LOADS | SYMOPT_EXACT_SYMBOLS);
|
||||
if (!WindowsDbgHelp::symInitialize(hProcess, NULL, TRUE)) {
|
||||
_decoder_status = helper_init_error;
|
||||
return;
|
||||
}
|
||||
|
||||
// set pdb search paths
|
||||
pfn_SymSetSearchPath _pfn_SymSetSearchPath =
|
||||
(pfn_SymSetSearchPath)::GetProcAddress(handle, "SymSetSearchPath");
|
||||
pfn_SymGetSearchPath _pfn_SymGetSearchPath =
|
||||
(pfn_SymGetSearchPath)::GetProcAddress(handle, "SymGetSearchPath");
|
||||
if (_pfn_SymSetSearchPath != NULL && _pfn_SymGetSearchPath != NULL) {
|
||||
char paths[MAX_PATH];
|
||||
int len = sizeof(paths);
|
||||
if (!_pfn_SymGetSearchPath(hProcess, paths, len)) {
|
||||
paths[0] = '\0';
|
||||
} else {
|
||||
// available spaces in path buffer
|
||||
len -= (int)strlen(paths);
|
||||
}
|
||||
|
||||
char tmp_path[MAX_PATH];
|
||||
DWORD dwSize;
|
||||
HMODULE hJVM = ::GetModuleHandle("jvm.dll");
|
||||
tmp_path[0] = '\0';
|
||||
// append the path where jvm.dll is located
|
||||
if (hJVM != NULL && (dwSize = ::GetModuleFileName(hJVM, tmp_path, sizeof(tmp_path))) > 0) {
|
||||
while (dwSize > 0 && tmp_path[dwSize] != '\\') {
|
||||
dwSize --;
|
||||
}
|
||||
|
||||
tmp_path[dwSize] = '\0';
|
||||
|
||||
if (dwSize > 0 && len > (int)dwSize + 1) {
|
||||
strncat(paths, os::path_separator(), 1);
|
||||
strncat(paths, tmp_path, dwSize);
|
||||
len -= dwSize + 1;
|
||||
}
|
||||
}
|
||||
|
||||
// append $JRE/bin. Arguments::get_java_home actually returns $JRE
|
||||
// path
|
||||
char *p = Arguments::get_java_home();
|
||||
assert(p != NULL, "empty java home");
|
||||
size_t java_home_len = strlen(p);
|
||||
if (len > (int)java_home_len + 5) {
|
||||
strncat(paths, os::path_separator(), 1);
|
||||
strncat(paths, p, java_home_len);
|
||||
strncat(paths, "\\bin", 4);
|
||||
len -= (int)(java_home_len + 5);
|
||||
}
|
||||
|
||||
// append $JDK/bin path if it exists
|
||||
assert(java_home_len < MAX_PATH, "Invalid path length");
|
||||
// assume $JRE is under $JDK, construct $JDK/bin path and
|
||||
// see if it exists or not
|
||||
if (strncmp(&p[java_home_len - 3], "jre", 3) == 0) {
|
||||
strncpy(tmp_path, p, java_home_len - 3);
|
||||
tmp_path[java_home_len - 3] = '\0';
|
||||
strncat(tmp_path, "bin", 3);
|
||||
|
||||
// if the directory exists
|
||||
DWORD dwAttrib = GetFileAttributes(tmp_path);
|
||||
if (dwAttrib != INVALID_FILE_ATTRIBUTES &&
|
||||
(dwAttrib & FILE_ATTRIBUTE_DIRECTORY)) {
|
||||
// tmp_path should have the same length as java_home_len, since we only
|
||||
// replaced 'jre' with 'bin'
|
||||
if (len > (int)java_home_len + 1) {
|
||||
strncat(paths, os::path_separator(), 1);
|
||||
strncat(paths, tmp_path, java_home_len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_pfn_SymSetSearchPath(hProcess, paths);
|
||||
char paths[MAX_PATH];
|
||||
int len = sizeof(paths);
|
||||
if (!WindowsDbgHelp::symGetSearchPath(hProcess, paths, len)) {
|
||||
paths[0] = '\0';
|
||||
} else {
|
||||
// available spaces in path buffer
|
||||
len -= (int)strlen(paths);
|
||||
}
|
||||
|
||||
// find out if jvm.dll contains private symbols, by decoding
|
||||
// current function and comparing the result
|
||||
address addr = (address)Decoder::demangle;
|
||||
char buf[MAX_PATH];
|
||||
if (decode(addr, buf, sizeof(buf), NULL, NULL, true /* demangle */)) {
|
||||
_can_decode_in_vm = !strcmp(buf, "Decoder::demangle");
|
||||
}
|
||||
char tmp_path[MAX_PATH];
|
||||
DWORD dwSize;
|
||||
HMODULE hJVM = ::GetModuleHandle("jvm.dll");
|
||||
tmp_path[0] = '\0';
|
||||
// append the path where jvm.dll is located
|
||||
if (hJVM != NULL && (dwSize = ::GetModuleFileName(hJVM, tmp_path, sizeof(tmp_path))) > 0) {
|
||||
while (dwSize > 0 && tmp_path[dwSize] != '\\') {
|
||||
dwSize --;
|
||||
}
|
||||
|
||||
tmp_path[dwSize] = '\0';
|
||||
|
||||
if (dwSize > 0 && len > (int)dwSize + 1) {
|
||||
strncat(paths, os::path_separator(), 1);
|
||||
strncat(paths, tmp_path, dwSize);
|
||||
len -= dwSize + 1;
|
||||
}
|
||||
}
|
||||
|
||||
// append $JRE/bin. Arguments::get_java_home actually returns $JRE
|
||||
// path
|
||||
char *p = Arguments::get_java_home();
|
||||
assert(p != NULL, "empty java home");
|
||||
size_t java_home_len = strlen(p);
|
||||
if (len > (int)java_home_len + 5) {
|
||||
strncat(paths, os::path_separator(), 1);
|
||||
strncat(paths, p, java_home_len);
|
||||
strncat(paths, "\\bin", 4);
|
||||
len -= (int)(java_home_len + 5);
|
||||
}
|
||||
|
||||
// append $JDK/bin path if it exists
|
||||
assert(java_home_len < MAX_PATH, "Invalid path length");
|
||||
// assume $JRE is under $JDK, construct $JDK/bin path and
|
||||
// see if it exists or not
|
||||
if (strncmp(&p[java_home_len - 3], "jre", 3) == 0) {
|
||||
strncpy(tmp_path, p, java_home_len - 3);
|
||||
tmp_path[java_home_len - 3] = '\0';
|
||||
strncat(tmp_path, "bin", 3);
|
||||
|
||||
// if the directory exists
|
||||
DWORD dwAttrib = GetFileAttributes(tmp_path);
|
||||
if (dwAttrib != INVALID_FILE_ATTRIBUTES &&
|
||||
(dwAttrib & FILE_ATTRIBUTE_DIRECTORY)) {
|
||||
// tmp_path should have the same length as java_home_len, since we only
|
||||
// replaced 'jre' with 'bin'
|
||||
if (len > (int)java_home_len + 1) {
|
||||
strncat(paths, os::path_separator(), 1);
|
||||
strncat(paths, tmp_path, java_home_len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
WindowsDbgHelp::symSetSearchPath(hProcess, paths);
|
||||
|
||||
// find out if jvm.dll contains private symbols, by decoding
|
||||
// current function and comparing the result
|
||||
address addr = (address)Decoder::demangle;
|
||||
char buf[MAX_PATH];
|
||||
if (decode(addr, buf, sizeof(buf), NULL, NULL, true /* demangle */)) {
|
||||
_can_decode_in_vm = !strcmp(buf, "Decoder::demangle");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WindowsDecoder::uninitialize() {
|
||||
_pfnSymGetSymFromAddr64 = NULL;
|
||||
_pfnUndecorateSymbolName = NULL;
|
||||
#ifdef AMD64
|
||||
_pfnStackWalk64 = NULL;
|
||||
_pfnSymFunctionTableAccess64 = NULL;
|
||||
_pfnSymGetModuleBase64 = NULL;
|
||||
#endif
|
||||
if (_dbghelp_handle != NULL) {
|
||||
::FreeLibrary(_dbghelp_handle);
|
||||
}
|
||||
_dbghelp_handle = NULL;
|
||||
}
|
||||
void WindowsDecoder::uninitialize() {}
|
||||
|
||||
bool WindowsDecoder::can_decode_C_frame_in_vm() const {
|
||||
return (!has_error() && _can_decode_in_vm);
|
||||
@ -188,14 +127,14 @@ bool WindowsDecoder::can_decode_C_frame_in_vm() const {
|
||||
|
||||
|
||||
bool WindowsDecoder::decode(address addr, char *buf, int buflen, int* offset, const char* modulepath, bool demangle_name) {
|
||||
if (_pfnSymGetSymFromAddr64 != NULL) {
|
||||
if (!has_error()) {
|
||||
PIMAGEHLP_SYMBOL64 pSymbol;
|
||||
char symbolInfo[MAX_PATH + sizeof(IMAGEHLP_SYMBOL64)];
|
||||
pSymbol = (PIMAGEHLP_SYMBOL64)symbolInfo;
|
||||
pSymbol->MaxNameLength = MAX_PATH;
|
||||
pSymbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);
|
||||
DWORD64 displacement;
|
||||
if (_pfnSymGetSymFromAddr64(::GetCurrentProcess(), (DWORD64)addr, &displacement, pSymbol)) {
|
||||
if (WindowsDbgHelp::symGetSymFromAddr64(::GetCurrentProcess(), (DWORD64)addr, &displacement, pSymbol)) {
|
||||
if (buf != NULL) {
|
||||
if (!(demangle_name && demangle(pSymbol->Name, buf, buflen))) {
|
||||
jio_snprintf(buf, buflen, "%s", pSymbol->Name);
|
||||
@ -211,69 +150,9 @@ bool WindowsDecoder::decode(address addr, char *buf, int buflen, int* offset, co
|
||||
}
|
||||
|
||||
bool WindowsDecoder::demangle(const char* symbol, char *buf, int buflen) {
|
||||
return _pfnUndecorateSymbolName != NULL &&
|
||||
_pfnUndecorateSymbolName(symbol, buf, buflen, UNDNAME_COMPLETE);
|
||||
}
|
||||
|
||||
#ifdef AMD64
|
||||
BOOL WindowsDbgHelp::StackWalk64(DWORD MachineType,
|
||||
HANDLE hProcess,
|
||||
HANDLE hThread,
|
||||
LPSTACKFRAME64 StackFrame,
|
||||
PVOID ContextRecord,
|
||||
PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine,
|
||||
PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine,
|
||||
PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine,
|
||||
PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress) {
|
||||
DecoderLocker locker;
|
||||
WindowsDecoder* wd = (WindowsDecoder*)locker.decoder();
|
||||
|
||||
if (!wd->has_error() && wd->_pfnStackWalk64) {
|
||||
return wd->_pfnStackWalk64(MachineType,
|
||||
hProcess,
|
||||
hThread,
|
||||
StackFrame,
|
||||
ContextRecord,
|
||||
ReadMemoryRoutine,
|
||||
FunctionTableAccessRoutine,
|
||||
GetModuleBaseRoutine,
|
||||
TranslateAddress);
|
||||
} else {
|
||||
return false;
|
||||
if (!has_error()) {
|
||||
return WindowsDbgHelp::unDecorateSymbolName(symbol, buf, buflen, UNDNAME_COMPLETE) > 0;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
PVOID WindowsDbgHelp::SymFunctionTableAccess64(HANDLE hProcess, DWORD64 AddrBase) {
|
||||
DecoderLocker locker;
|
||||
WindowsDecoder* wd = (WindowsDecoder*)locker.decoder();
|
||||
|
||||
if (!wd->has_error() && wd->_pfnSymFunctionTableAccess64) {
|
||||
return wd->_pfnSymFunctionTableAccess64(hProcess, AddrBase);
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
pfn_SymFunctionTableAccess64 WindowsDbgHelp::pfnSymFunctionTableAccess64() {
|
||||
DecoderLocker locker;
|
||||
WindowsDecoder* wd = (WindowsDecoder*)locker.decoder();
|
||||
|
||||
if (!wd->has_error()) {
|
||||
return wd->_pfnSymFunctionTableAccess64;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
pfn_SymGetModuleBase64 WindowsDbgHelp::pfnSymGetModuleBase64() {
|
||||
DecoderLocker locker;
|
||||
WindowsDecoder* wd = (WindowsDecoder*)locker.decoder();
|
||||
|
||||
if (!wd->has_error()) {
|
||||
return wd->_pfnSymGetModuleBase64;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // AMD64
|
||||
|
@ -25,33 +25,8 @@
|
||||
#ifndef OS_WINDOWS_VM_DECODER_WINDOWS_HPP
|
||||
#define OS_WINDOWS_VM_DECIDER_WINDOWS_HPP
|
||||
|
||||
#include <windows.h>
|
||||
#include <imagehlp.h>
|
||||
|
||||
#include "utilities/decoder.hpp"
|
||||
|
||||
// functions needed for decoding symbols
|
||||
typedef DWORD (WINAPI *pfn_SymSetOptions)(DWORD);
|
||||
typedef BOOL (WINAPI *pfn_SymInitialize)(HANDLE, PCTSTR, BOOL);
|
||||
typedef BOOL (WINAPI *pfn_SymGetSymFromAddr64)(HANDLE, DWORD64, PDWORD64, PIMAGEHLP_SYMBOL64);
|
||||
typedef DWORD (WINAPI *pfn_UndecorateSymbolName)(const char*, char*, DWORD, DWORD);
|
||||
typedef BOOL (WINAPI *pfn_SymSetSearchPath)(HANDLE, PCTSTR);
|
||||
typedef BOOL (WINAPI *pfn_SymGetSearchPath)(HANDLE, PTSTR, int);
|
||||
|
||||
#ifdef AMD64
|
||||
typedef BOOL (WINAPI *pfn_StackWalk64)(DWORD MachineType,
|
||||
HANDLE hProcess,
|
||||
HANDLE hThread,
|
||||
LPSTACKFRAME64 StackFrame,
|
||||
PVOID ContextRecord,
|
||||
PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine,
|
||||
PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine,
|
||||
PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine,
|
||||
PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress);
|
||||
typedef PVOID (WINAPI *pfn_SymFunctionTableAccess64)(HANDLE hProcess, DWORD64 AddrBase);
|
||||
typedef DWORD64 (WINAPI *pfn_SymGetModuleBase64)(HANDLE hProcess, DWORD64 dwAddr);
|
||||
#endif
|
||||
|
||||
class WindowsDecoder : public AbstractDecoder {
|
||||
|
||||
public:
|
||||
@ -70,38 +45,8 @@ private:
|
||||
void initialize();
|
||||
void uninitialize();
|
||||
|
||||
private:
|
||||
HMODULE _dbghelp_handle;
|
||||
bool _can_decode_in_vm;
|
||||
pfn_SymGetSymFromAddr64 _pfnSymGetSymFromAddr64;
|
||||
pfn_UndecorateSymbolName _pfnUndecorateSymbolName;
|
||||
#ifdef AMD64
|
||||
pfn_StackWalk64 _pfnStackWalk64;
|
||||
pfn_SymFunctionTableAccess64 _pfnSymFunctionTableAccess64;
|
||||
pfn_SymGetModuleBase64 _pfnSymGetModuleBase64;
|
||||
|
||||
friend class WindowsDbgHelp;
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef AMD64
|
||||
// TODO: refactor and move the handling of dbghelp.dll outside of Decoder
|
||||
class WindowsDbgHelp : public Decoder {
|
||||
public:
|
||||
static BOOL StackWalk64(DWORD MachineType,
|
||||
HANDLE hProcess,
|
||||
HANDLE hThread,
|
||||
LPSTACKFRAME64 StackFrame,
|
||||
PVOID ContextRecord,
|
||||
PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine,
|
||||
PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine,
|
||||
PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine,
|
||||
PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress);
|
||||
static PVOID SymFunctionTableAccess64(HANDLE hProcess, DWORD64 AddrBase);
|
||||
|
||||
static pfn_SymFunctionTableAccess64 pfnSymFunctionTableAccess64();
|
||||
static pfn_SymGetModuleBase64 pfnSymGetModuleBase64();
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif // OS_WINDOWS_VM_DECODER_WINDOWS_HPP
|
||||
|
@ -74,6 +74,8 @@
|
||||
#include "utilities/growableArray.hpp"
|
||||
#include "utilities/macros.hpp"
|
||||
#include "utilities/vmError.hpp"
|
||||
#include "windbghelp.hpp"
|
||||
|
||||
|
||||
#ifdef _DEBUG
|
||||
#include <crtdbg.h>
|
||||
@ -1009,7 +1011,6 @@ void os::check_dump_limit(char* buffer, size_t buffsz) {
|
||||
}
|
||||
|
||||
void os::abort(bool dump_core, void* siginfo, const void* context) {
|
||||
HINSTANCE dbghelp;
|
||||
EXCEPTION_POINTERS ep;
|
||||
MINIDUMP_EXCEPTION_INFORMATION mei;
|
||||
MINIDUMP_EXCEPTION_INFORMATION* pmei;
|
||||
@ -1026,28 +1027,6 @@ void os::abort(bool dump_core, void* siginfo, const void* context) {
|
||||
win32::exit_process_or_thread(win32::EPT_PROCESS, 1);
|
||||
}
|
||||
|
||||
dbghelp = os::win32::load_Windows_dll("DBGHELP.DLL", NULL, 0);
|
||||
|
||||
if (dbghelp == NULL) {
|
||||
jio_fprintf(stderr, "Failed to load dbghelp.dll\n");
|
||||
CloseHandle(dumpFile);
|
||||
win32::exit_process_or_thread(win32::EPT_PROCESS, 1);
|
||||
}
|
||||
|
||||
_MiniDumpWriteDump =
|
||||
CAST_TO_FN_PTR(BOOL(WINAPI *)(HANDLE, DWORD, HANDLE, MINIDUMP_TYPE,
|
||||
PMINIDUMP_EXCEPTION_INFORMATION,
|
||||
PMINIDUMP_USER_STREAM_INFORMATION,
|
||||
PMINIDUMP_CALLBACK_INFORMATION),
|
||||
GetProcAddress(dbghelp,
|
||||
"MiniDumpWriteDump"));
|
||||
|
||||
if (_MiniDumpWriteDump == NULL) {
|
||||
jio_fprintf(stderr, "Failed to find MiniDumpWriteDump() in module dbghelp.dll.\n");
|
||||
CloseHandle(dumpFile);
|
||||
win32::exit_process_or_thread(win32::EPT_PROCESS, 1);
|
||||
}
|
||||
|
||||
dumpType = (MINIDUMP_TYPE)(MiniDumpWithFullMemory | MiniDumpWithHandleData |
|
||||
MiniDumpWithFullMemoryInfo | MiniDumpWithThreadInfo | MiniDumpWithUnloadedModules);
|
||||
|
||||
@ -1064,8 +1043,8 @@ void os::abort(bool dump_core, void* siginfo, const void* context) {
|
||||
|
||||
// Older versions of dbghelp.dll (the one shipped with Win2003 for example) may not support all
|
||||
// the dump types we really want. If first call fails, lets fall back to just use MiniDumpWithFullMemory then.
|
||||
if (_MiniDumpWriteDump(hProcess, processId, dumpFile, dumpType, pmei, NULL, NULL) == false &&
|
||||
_MiniDumpWriteDump(hProcess, processId, dumpFile, (MINIDUMP_TYPE)MiniDumpWithFullMemory, pmei, NULL, NULL) == false) {
|
||||
if (!WindowsDbgHelp::miniDumpWriteDump(hProcess, processId, dumpFile, dumpType, pmei, NULL, NULL) &&
|
||||
!WindowsDbgHelp::miniDumpWriteDump(hProcess, processId, dumpFile, (MINIDUMP_TYPE)MiniDumpWithFullMemory, pmei, NULL, NULL)) {
|
||||
jio_fprintf(stderr, "Call to MiniDumpWriteDump() failed (Error 0x%x)\n", GetLastError());
|
||||
}
|
||||
CloseHandle(dumpFile);
|
||||
@ -1198,70 +1177,6 @@ const char* os::get_temp_directory() {
|
||||
}
|
||||
}
|
||||
|
||||
static bool file_exists(const char* filename) {
|
||||
if (filename == NULL || strlen(filename) == 0) {
|
||||
return false;
|
||||
}
|
||||
return GetFileAttributes(filename) != INVALID_FILE_ATTRIBUTES;
|
||||
}
|
||||
|
||||
bool os::dll_build_name(char *buffer, size_t buflen,
|
||||
const char* pname, const char* fname) {
|
||||
bool retval = false;
|
||||
const size_t pnamelen = pname ? strlen(pname) : 0;
|
||||
const char c = (pnamelen > 0) ? pname[pnamelen-1] : 0;
|
||||
|
||||
// Return error on buffer overflow.
|
||||
if (pnamelen + strlen(fname) + 10 > buflen) {
|
||||
return retval;
|
||||
}
|
||||
|
||||
if (pnamelen == 0) {
|
||||
jio_snprintf(buffer, buflen, "%s.dll", fname);
|
||||
retval = true;
|
||||
} else if (c == ':' || c == '\\') {
|
||||
jio_snprintf(buffer, buflen, "%s%s.dll", pname, fname);
|
||||
retval = true;
|
||||
} else if (strchr(pname, *os::path_separator()) != NULL) {
|
||||
int n;
|
||||
char** pelements = split_path(pname, &n);
|
||||
if (pelements == NULL) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < n; i++) {
|
||||
char* path = pelements[i];
|
||||
// Really shouldn't be NULL, but check can't hurt
|
||||
size_t plen = (path == NULL) ? 0 : strlen(path);
|
||||
if (plen == 0) {
|
||||
continue; // skip the empty path values
|
||||
}
|
||||
const char lastchar = path[plen - 1];
|
||||
if (lastchar == ':' || lastchar == '\\') {
|
||||
jio_snprintf(buffer, buflen, "%s%s.dll", path, fname);
|
||||
} else {
|
||||
jio_snprintf(buffer, buflen, "%s\\%s.dll", path, fname);
|
||||
}
|
||||
if (file_exists(buffer)) {
|
||||
retval = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// release the storage
|
||||
for (int i = 0; i < n; i++) {
|
||||
if (pelements[i] != NULL) {
|
||||
FREE_C_HEAP_ARRAY(char, pelements[i]);
|
||||
}
|
||||
}
|
||||
if (pelements != NULL) {
|
||||
FREE_C_HEAP_ARRAY(char*, pelements);
|
||||
}
|
||||
} else {
|
||||
jio_snprintf(buffer, buflen, "%s\\%s.dll", pname, fname);
|
||||
retval = true;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
// Needs to be in os specific directory because windows requires another
|
||||
// header file <direct.h>
|
||||
const char* os::get_current_directory(char *buf, size_t buflen) {
|
||||
@ -3591,22 +3506,6 @@ bool os::is_interrupted(Thread* thread, bool clear_interrupted) {
|
||||
return interrupted;
|
||||
}
|
||||
|
||||
// Get's a pc (hint) for a running thread. Currently used only for profiling.
|
||||
ExtendedPC os::get_thread_pc(Thread* thread) {
|
||||
CONTEXT context;
|
||||
context.ContextFlags = CONTEXT_CONTROL;
|
||||
HANDLE handle = thread->osthread()->thread_handle();
|
||||
if (GetThreadContext(handle, &context)) {
|
||||
#ifdef _M_AMD64
|
||||
return ExtendedPC((address) context.Rip);
|
||||
#else
|
||||
return ExtendedPC((address) context.Eip);
|
||||
#endif
|
||||
} else {
|
||||
return ExtendedPC(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
// GetCurrentThreadId() returns DWORD
|
||||
intx os::current_thread_id() { return GetCurrentThreadId(); }
|
||||
|
||||
|
306
hotspot/src/os/windows/vm/windbghelp.cpp
Normal file
306
hotspot/src/os/windows/vm/windbghelp.cpp
Normal file
@ -0,0 +1,306 @@
|
||||
/*
|
||||
* Copyright (c) 2017, 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/ostream.hpp"
|
||||
#include "windbghelp.hpp"
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
typedef DWORD (WINAPI *pfn_SymSetOptions)(DWORD);
|
||||
typedef DWORD (WINAPI *pfn_SymGetOptions)(void);
|
||||
typedef BOOL (WINAPI *pfn_SymInitialize)(HANDLE, PCTSTR, BOOL);
|
||||
typedef BOOL (WINAPI *pfn_SymGetSymFromAddr64)(HANDLE, DWORD64, PDWORD64, PIMAGEHLP_SYMBOL64);
|
||||
typedef DWORD (WINAPI *pfn_UnDecorateSymbolName)(const char*, char*, DWORD, DWORD);
|
||||
typedef BOOL (WINAPI *pfn_SymSetSearchPath)(HANDLE, PCTSTR);
|
||||
typedef BOOL (WINAPI *pfn_SymGetSearchPath)(HANDLE, PTSTR, int);
|
||||
typedef BOOL (WINAPI *pfn_StackWalk64)(DWORD MachineType,
|
||||
HANDLE hProcess,
|
||||
HANDLE hThread,
|
||||
LPSTACKFRAME64 StackFrame,
|
||||
PVOID ContextRecord,
|
||||
PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine,
|
||||
PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine,
|
||||
PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine,
|
||||
PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress);
|
||||
typedef PVOID (WINAPI *pfn_SymFunctionTableAccess64)(HANDLE hProcess, DWORD64 AddrBase);
|
||||
typedef DWORD64 (WINAPI *pfn_SymGetModuleBase64)(HANDLE hProcess, DWORD64 dwAddr);
|
||||
typedef BOOL (WINAPI *pfn_MiniDumpWriteDump) (HANDLE hProcess, DWORD ProcessId, HANDLE hFile,
|
||||
MINIDUMP_TYPE DumpType, PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
|
||||
PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
|
||||
PMINIDUMP_CALLBACK_INFORMATION CallbackParam);
|
||||
typedef BOOL (WINAPI *pfn_SymGetLineFromAddr64) (HANDLE hProcess, DWORD64 dwAddr,
|
||||
PDWORD pdwDisplacement, PIMAGEHLP_LINE64 Line);
|
||||
typedef LPAPI_VERSION (WINAPI *pfn_ImagehlpApiVersion)(void);
|
||||
|
||||
// Add functions as needed.
|
||||
#define FOR_ALL_FUNCTIONS(DO) \
|
||||
DO(ImagehlpApiVersion) \
|
||||
DO(SymGetOptions) \
|
||||
DO(SymSetOptions) \
|
||||
DO(SymInitialize) \
|
||||
DO(SymGetSymFromAddr64) \
|
||||
DO(UnDecorateSymbolName) \
|
||||
DO(SymSetSearchPath) \
|
||||
DO(SymGetSearchPath) \
|
||||
DO(StackWalk64) \
|
||||
DO(SymFunctionTableAccess64) \
|
||||
DO(SymGetModuleBase64) \
|
||||
DO(MiniDumpWriteDump) \
|
||||
DO(SymGetLineFromAddr64)
|
||||
|
||||
|
||||
#define DECLARE_FUNCTION_POINTER(functionname) \
|
||||
static pfn_##functionname g_pfn_##functionname;
|
||||
|
||||
FOR_ALL_FUNCTIONS(DECLARE_FUNCTION_POINTER)
|
||||
|
||||
|
||||
static HMODULE g_dll_handle = NULL;
|
||||
static DWORD g_dll_load_error = 0;
|
||||
static API_VERSION g_version = { 0, 0, 0, 0 };
|
||||
|
||||
static enum {
|
||||
state_uninitialized = 0,
|
||||
state_ready = 1,
|
||||
state_error = 2
|
||||
} g_state = state_uninitialized;
|
||||
|
||||
static void initialize() {
|
||||
|
||||
assert(g_state == state_uninitialized, "wrong sequence");
|
||||
g_state = state_error;
|
||||
|
||||
g_dll_handle = ::LoadLibrary("DBGHELP.DLL");
|
||||
if (g_dll_handle == NULL) {
|
||||
g_dll_load_error = ::GetLastError();
|
||||
} else {
|
||||
// Note: We loaded the DLL successfully. From here on we count
|
||||
// initialization as success. We still may fail to load all of the
|
||||
// desired function pointers successfully, but DLL may still be usable
|
||||
// enough for our purposes.
|
||||
g_state = state_ready;
|
||||
|
||||
#define DO_RESOLVE(functionname) \
|
||||
g_pfn_##functionname = (pfn_##functionname) ::GetProcAddress(g_dll_handle, #functionname);
|
||||
|
||||
FOR_ALL_FUNCTIONS(DO_RESOLVE)
|
||||
|
||||
// Retrieve version information.
|
||||
if (g_pfn_ImagehlpApiVersion) {
|
||||
const API_VERSION* p = g_pfn_ImagehlpApiVersion();
|
||||
memcpy(&g_version, p, sizeof(API_VERSION));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
///////////////////// External functions //////////////////////////
|
||||
|
||||
// All outside facing functions are synchronized. Also, we run
|
||||
// initialization on first touch.
|
||||
|
||||
|
||||
// Call InitializeCriticalSection as early as possible.
|
||||
class CritSect {
|
||||
CRITICAL_SECTION cs;
|
||||
public:
|
||||
CritSect() { ::InitializeCriticalSection(&cs); }
|
||||
void enter() { ::EnterCriticalSection(&cs); }
|
||||
void leave() { ::LeaveCriticalSection(&cs); }
|
||||
};
|
||||
|
||||
static CritSect g_cs;
|
||||
|
||||
class EntryGuard {
|
||||
public:
|
||||
EntryGuard() {
|
||||
g_cs.enter();
|
||||
if (g_state == state_uninitialized) {
|
||||
initialize();
|
||||
}
|
||||
}
|
||||
~EntryGuard() {
|
||||
g_cs.leave();
|
||||
}
|
||||
};
|
||||
|
||||
DWORD WindowsDbgHelp::symSetOptions(DWORD arg) {
|
||||
EntryGuard entry_guard;
|
||||
if (g_pfn_SymSetOptions != NULL) {
|
||||
return g_pfn_SymSetOptions(arg);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
DWORD WindowsDbgHelp::symGetOptions(void) {
|
||||
EntryGuard entry_guard;
|
||||
if (g_pfn_SymGetOptions != NULL) {
|
||||
return g_pfn_SymGetOptions();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
BOOL WindowsDbgHelp::symInitialize(HANDLE hProcess, PCTSTR UserSearchPath, BOOL fInvadeProcess) {
|
||||
EntryGuard entry_guard;
|
||||
if (g_pfn_SymInitialize != NULL) {
|
||||
return g_pfn_SymInitialize(hProcess, UserSearchPath, fInvadeProcess);
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL WindowsDbgHelp::symGetSymFromAddr64(HANDLE hProcess, DWORD64 the_address,
|
||||
PDWORD64 Displacement, PIMAGEHLP_SYMBOL64 Symbol) {
|
||||
EntryGuard entry_guard;
|
||||
if (g_pfn_SymGetSymFromAddr64 != NULL) {
|
||||
return g_pfn_SymGetSymFromAddr64(hProcess, the_address, Displacement, Symbol);
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
DWORD WindowsDbgHelp::unDecorateSymbolName(const char* DecoratedName, char* UnDecoratedName,
|
||||
DWORD UndecoratedLength, DWORD Flags) {
|
||||
EntryGuard entry_guard;
|
||||
if (g_pfn_UnDecorateSymbolName != NULL) {
|
||||
return g_pfn_UnDecorateSymbolName(DecoratedName, UnDecoratedName, UndecoratedLength, Flags);
|
||||
}
|
||||
if (UnDecoratedName != NULL && UndecoratedLength > 0) {
|
||||
UnDecoratedName[0] = '\0';
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
BOOL WindowsDbgHelp::symSetSearchPath(HANDLE hProcess, PCTSTR SearchPath) {
|
||||
EntryGuard entry_guard;
|
||||
if (g_pfn_SymSetSearchPath != NULL) {
|
||||
return g_pfn_SymSetSearchPath(hProcess, SearchPath);
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL WindowsDbgHelp::symGetSearchPath(HANDLE hProcess, PTSTR SearchPath, int SearchPathLength) {
|
||||
EntryGuard entry_guard;
|
||||
if (g_pfn_SymGetSearchPath != NULL) {
|
||||
return g_pfn_SymGetSearchPath(hProcess, SearchPath, SearchPathLength);
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL WindowsDbgHelp::stackWalk64(DWORD MachineType,
|
||||
HANDLE hProcess,
|
||||
HANDLE hThread,
|
||||
LPSTACKFRAME64 StackFrame,
|
||||
PVOID ContextRecord) {
|
||||
EntryGuard entry_guard;
|
||||
if (g_pfn_StackWalk64 != NULL) {
|
||||
return g_pfn_StackWalk64(MachineType, hProcess, hThread, StackFrame,
|
||||
ContextRecord,
|
||||
NULL, // ReadMemoryRoutine
|
||||
g_pfn_SymFunctionTableAccess64, // FunctionTableAccessRoutine,
|
||||
g_pfn_SymGetModuleBase64, // GetModuleBaseRoutine
|
||||
NULL // TranslateAddressRoutine
|
||||
);
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
PVOID WindowsDbgHelp::symFunctionTableAccess64(HANDLE hProcess, DWORD64 AddrBase) {
|
||||
EntryGuard entry_guard;
|
||||
if (g_pfn_SymFunctionTableAccess64 != NULL) {
|
||||
return g_pfn_SymFunctionTableAccess64(hProcess, AddrBase);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DWORD64 WindowsDbgHelp::symGetModuleBase64(HANDLE hProcess, DWORD64 dwAddr) {
|
||||
EntryGuard entry_guard;
|
||||
if (g_pfn_SymGetModuleBase64 != NULL) {
|
||||
return g_pfn_SymGetModuleBase64(hProcess, dwAddr);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
BOOL WindowsDbgHelp::miniDumpWriteDump(HANDLE hProcess, DWORD ProcessId, HANDLE hFile,
|
||||
MINIDUMP_TYPE DumpType, PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
|
||||
PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
|
||||
PMINIDUMP_CALLBACK_INFORMATION CallbackParam) {
|
||||
EntryGuard entry_guard;
|
||||
if (g_pfn_MiniDumpWriteDump != NULL) {
|
||||
return g_pfn_MiniDumpWriteDump(hProcess, ProcessId, hFile, DumpType,
|
||||
ExceptionParam, UserStreamParam, CallbackParam);
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL WindowsDbgHelp::symGetLineFromAddr64(HANDLE hProcess, DWORD64 dwAddr,
|
||||
PDWORD pdwDisplacement, PIMAGEHLP_LINE64 Line) {
|
||||
EntryGuard entry_guard;
|
||||
if (g_pfn_SymGetLineFromAddr64 != NULL) {
|
||||
return g_pfn_SymGetLineFromAddr64(hProcess, dwAddr, pdwDisplacement, Line);
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Print one liner describing state (if library loaded, which functions are
|
||||
// missing - if any, and the dbhelp API version)
|
||||
void WindowsDbgHelp::print_state_on(outputStream* st) {
|
||||
// Note: We should not lock while printing, but this should be
|
||||
// safe to do without lock anyway.
|
||||
st->print("dbghelp: ");
|
||||
|
||||
if (g_state == state_uninitialized) {
|
||||
st->print("uninitialized.");
|
||||
} else if (g_state == state_error) {
|
||||
st->print("loading error: %u", g_dll_load_error);
|
||||
} else {
|
||||
st->print("loaded successfully ");
|
||||
|
||||
// We may want to print dll file name here - which may be interesting for
|
||||
// cases where more than one version exists on the system, e.g. with a
|
||||
// debugging sdk separately installed. But we get the file name in the DLL
|
||||
// section of the hs-err file too, so this may be redundant.
|
||||
|
||||
// Print version.
|
||||
st->print("- version: %u.%u.%u",
|
||||
g_version.MajorVersion, g_version.MinorVersion, g_version.Revision);
|
||||
|
||||
// Print any functions which failed to load.
|
||||
int num_missing = 0;
|
||||
st->print(" - missing functions: ");
|
||||
|
||||
#define CHECK_AND_PRINT_IF_NULL(functionname) \
|
||||
if (g_pfn_##functionname == NULL) { \
|
||||
st->print("%s" #functionname, ((num_missing > 0) ? ", " : "")); \
|
||||
num_missing ++; \
|
||||
}
|
||||
|
||||
FOR_ALL_FUNCTIONS(CHECK_AND_PRINT_IF_NULL)
|
||||
|
||||
if (num_missing == 0) {
|
||||
st->print("none");
|
||||
}
|
||||
}
|
||||
st->cr();
|
||||
}
|
||||
|
73
hotspot/src/os/windows/vm/windbghelp.hpp
Normal file
73
hotspot/src/os/windows/vm/windbghelp.hpp
Normal file
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright (c) 2017, 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef OS_WINDOWS_VM_DBGHELPLOADER_HPP
|
||||
#define OS_WINDOWS_VM_DBGHELPLOADER_HPP
|
||||
|
||||
#include <windows.h>
|
||||
#include <imagehlp.h>
|
||||
|
||||
// This is a very plain wrapper for loading dbghelp.dll. It does not offer
|
||||
// any additional functionality. It takes care of locking.
|
||||
|
||||
class outputStream;
|
||||
|
||||
// Please note: dbghelp.dll may not have been loaded, or it may have been loaded but not
|
||||
// all functions may be available (because on the target system dbghelp.dll is of an
|
||||
// older version).
|
||||
// In all these cases we return an error from the WindowsDbgHelp::symXXXX() wrapper. We never
|
||||
// assert. It should always be safe to call these functions, but caller has to process the
|
||||
// return code (which he would have to do anyway).
|
||||
namespace WindowsDbgHelp {
|
||||
|
||||
DWORD symSetOptions(DWORD);
|
||||
DWORD symGetOptions(void);
|
||||
BOOL symInitialize(HANDLE, PCTSTR, BOOL);
|
||||
BOOL symGetSymFromAddr64(HANDLE, DWORD64, PDWORD64, PIMAGEHLP_SYMBOL64);
|
||||
DWORD unDecorateSymbolName(const char*, char*, DWORD, DWORD);
|
||||
BOOL symSetSearchPath(HANDLE, PCTSTR);
|
||||
BOOL symGetSearchPath(HANDLE, PTSTR, int);
|
||||
BOOL stackWalk64(DWORD MachineType,
|
||||
HANDLE hProcess,
|
||||
HANDLE hThread,
|
||||
LPSTACKFRAME64 StackFrame,
|
||||
PVOID ContextRecord);
|
||||
PVOID symFunctionTableAccess64(HANDLE hProcess, DWORD64 AddrBase);
|
||||
DWORD64 symGetModuleBase64(HANDLE hProcess, DWORD64 dwAddr);
|
||||
BOOL miniDumpWriteDump(HANDLE hProcess, DWORD ProcessId, HANDLE hFile,
|
||||
MINIDUMP_TYPE DumpType, PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
|
||||
PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
|
||||
PMINIDUMP_CALLBACK_INFORMATION CallbackParam);
|
||||
BOOL symGetLineFromAddr64 (HANDLE hProcess, DWORD64 dwAddr,
|
||||
PDWORD pdwDisplacement, PIMAGEHLP_LINE64 Line);
|
||||
|
||||
// Print one liner describing state (if library loaded, which functions are
|
||||
// missing - if any, and the dbhelp API version)
|
||||
void print_state_on(outputStream* st);
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif // OS_WINDOWS_VM_DBGHELPLOADER_HPP
|
||||
|
@ -106,8 +106,8 @@ struct Atomic::PlatformAdd
|
||||
template<>
|
||||
template<typename I, typename D>
|
||||
inline D Atomic::PlatformAdd<4>::add_and_fetch(I add_value, D volatile* dest) const {
|
||||
STATIC_CAST(4 == sizeof(I));
|
||||
STATIC_CAST(4 == sizeof(D));
|
||||
STATIC_ASSERT(4 == sizeof(I));
|
||||
STATIC_ASSERT(4 == sizeof(D));
|
||||
|
||||
D result;
|
||||
|
||||
@ -129,8 +129,8 @@ inline D Atomic::PlatformAdd<4>::add_and_fetch(I add_value, D volatile* dest) co
|
||||
template<>
|
||||
template<typename I, typename D>
|
||||
inline D Atomic::PlatformAdd<8>::add_and_fetch(I add_value, D volatile* dest) const {
|
||||
STATIC_CAST(8 == sizeof(I));
|
||||
STATIC_CAST(8 == sizeof(D));
|
||||
STATIC_ASSERT(8 == sizeof(I));
|
||||
STATIC_ASSERT(8 == sizeof(D));
|
||||
|
||||
D result;
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2013 SAP SE. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
@ -29,7 +29,6 @@
|
||||
private:
|
||||
void pd_initialize() {
|
||||
_anchor.clear();
|
||||
_last_interpreter_fp = NULL;
|
||||
}
|
||||
|
||||
// The `last' frame is the youngest Java frame on the thread's stack.
|
||||
@ -60,20 +59,4 @@
|
||||
bool pd_get_top_frame_for_signal_handler(frame* fr_addr, void* ucontext,
|
||||
bool isInJava);
|
||||
|
||||
// -Xprof support
|
||||
//
|
||||
// In order to find the last Java fp from an async profile
|
||||
// tick, we store the current interpreter fp in the thread.
|
||||
// This value is only valid while we are in the C++ interpreter
|
||||
// and profiling.
|
||||
protected:
|
||||
intptr_t *_last_interpreter_fp;
|
||||
|
||||
public:
|
||||
static ByteSize last_interpreter_fp_offset() {
|
||||
return byte_offset_of(JavaThread, _last_interpreter_fp);
|
||||
}
|
||||
|
||||
intptr_t* last_interpreter_fp() { return _last_interpreter_fp; }
|
||||
|
||||
#endif // OS_CPU_AIX_PPC_VM_THREAD_AIX_PPC_HPP
|
||||
|
@ -184,8 +184,8 @@ struct Atomic::PlatformAdd
|
||||
template<>
|
||||
template<typename I, typename D>
|
||||
inline D Atomic::PlatformAdd<4>::add_and_fetch(I add_value, D volatile* dest) const {
|
||||
STATIC_CAST(4 == sizeof(I));
|
||||
STATIC_CAST(4 == sizeof(D));
|
||||
STATIC_ASSERT(4 == sizeof(I));
|
||||
STATIC_ASSERT(4 == sizeof(D));
|
||||
|
||||
#ifdef ARM
|
||||
return add_using_helper<int>(arm_add_and_fetch, add_value, dest);
|
||||
@ -201,8 +201,8 @@ inline D Atomic::PlatformAdd<4>::add_and_fetch(I add_value, D volatile* dest) co
|
||||
template<>
|
||||
template<typename I, typename D>
|
||||
inline D Atomic::PlatformAdd<8>::add_and_fetch(I add_value, D volatile* dest) const {
|
||||
STATIC_CAST(8 == sizeof(I));
|
||||
STATIC_CAST(8 == sizeof(D));
|
||||
STATIC_ASSERT(8 == sizeof(I));
|
||||
STATIC_ASSERT(8 == sizeof(D));
|
||||
|
||||
return __sync_add_and_fetch(dest, add_value);
|
||||
}
|
||||
@ -283,7 +283,7 @@ inline T Atomic::PlatformCmpxchg<4>::operator()(T exchange_value,
|
||||
T volatile* dest,
|
||||
T compare_value,
|
||||
cmpxchg_memory_order order) const {
|
||||
STATIC_CAST(4 == sizeof(T));
|
||||
STATIC_ASSERT(4 == sizeof(T));
|
||||
#ifdef ARM
|
||||
return cmpxchg_using_helper<int>(arm_compare_and_swap, exchange_value, dest, compare_value);
|
||||
#else
|
||||
@ -301,7 +301,7 @@ inline T Atomic::PlatformCmpxchg<8>::operator()(T exchange_value,
|
||||
T volatile* dest,
|
||||
T compare_value,
|
||||
cmpxchg_memory_order order) const {
|
||||
STATIC_CAST(8 == sizeof(T));
|
||||
STATIC_ASSERT(8 == sizeof(T));
|
||||
return __sync_val_compare_and_swap(dest, compare_value, exchange_value);
|
||||
}
|
||||
|
||||
|
@ -104,8 +104,8 @@ struct Atomic::PlatformAdd
|
||||
template<>
|
||||
template<typename I, typename D>
|
||||
inline D Atomic::PlatformAdd<4>::add_and_fetch(I add_value, D volatile* dest) const {
|
||||
STATIC_CAST(4 == sizeof(I));
|
||||
STATIC_CAST(4 == sizeof(D));
|
||||
STATIC_ASSERT(4 == sizeof(I));
|
||||
STATIC_ASSERT(4 == sizeof(D));
|
||||
|
||||
D result;
|
||||
|
||||
@ -127,8 +127,8 @@ inline D Atomic::PlatformAdd<4>::add_and_fetch(I add_value, D volatile* dest) co
|
||||
template<>
|
||||
template<typename I, typename D>
|
||||
inline D Atomic::PlatformAdd<8>::add_and_fetch(I add_value, D volatile* dest) const {
|
||||
STATIC_CAST(8 == sizeof(I));
|
||||
STATIC_CAST(8 == sizeof(D));
|
||||
STATIC_ASSERT(8 == sizeof(I));
|
||||
STATIC_ASSERT(8 == sizeof(D));
|
||||
|
||||
D result;
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2013 SAP SE. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
@ -30,7 +30,6 @@
|
||||
|
||||
void pd_initialize() {
|
||||
_anchor.clear();
|
||||
_last_interpreter_fp = NULL;
|
||||
}
|
||||
|
||||
// The `last' frame is the youngest Java frame on the thread's stack.
|
||||
@ -62,22 +61,4 @@
|
||||
|
||||
bool pd_get_top_frame_for_signal_handler(frame* fr_addr, void* ucontext, bool isInJava);
|
||||
|
||||
protected:
|
||||
|
||||
// -Xprof support
|
||||
//
|
||||
// In order to find the last Java fp from an async profile
|
||||
// tick, we store the current interpreter fp in the thread.
|
||||
// This value is only valid while we are in the C++ interpreter
|
||||
// and profiling.
|
||||
intptr_t *_last_interpreter_fp;
|
||||
|
||||
public:
|
||||
|
||||
static ByteSize last_interpreter_fp_offset() {
|
||||
return byte_offset_of(JavaThread, _last_interpreter_fp);
|
||||
}
|
||||
|
||||
intptr_t* last_interpreter_fp() { return _last_interpreter_fp; }
|
||||
|
||||
#endif // OS_CPU_LINUX_PPC_VM_THREAD_LINUX_PPC_HPP
|
||||
|
@ -92,9 +92,9 @@ struct Atomic::PlatformAdd
|
||||
|
||||
template<>
|
||||
template<typename I, typename D>
|
||||
inline D Atomic::PlatformAdd<4>::add_and_fetch(I add_value, D volatile* dest) const {
|
||||
STATIC_CAST(4 == sizeof(I));
|
||||
STATIC_CAST(4 == sizeof(D));
|
||||
inline D Atomic::PlatformAdd<4>::add_and_fetch(I inc, D volatile* dest) const {
|
||||
STATIC_ASSERT(4 == sizeof(I));
|
||||
STATIC_ASSERT(4 == sizeof(D));
|
||||
|
||||
D old, upd;
|
||||
|
||||
@ -143,9 +143,9 @@ inline D Atomic::PlatformAdd<4>::add_and_fetch(I add_value, D volatile* dest) co
|
||||
|
||||
template<>
|
||||
template<typename I, typename D>
|
||||
inline D Atomic::PlatformAdd<8>::add_and_fetch(I add_value, D volatile* dest) const {
|
||||
STATIC_CAST(8 == sizeof(I));
|
||||
STATIC_CAST(8 == sizeof(D));
|
||||
inline D Atomic::PlatformAdd<8>::add_and_fetch(I inc, D volatile* dest) const {
|
||||
STATIC_ASSERT(8 == sizeof(I));
|
||||
STATIC_ASSERT(8 == sizeof(D));
|
||||
|
||||
D old, upd;
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2016 SAP SE. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
@ -30,7 +30,6 @@
|
||||
|
||||
void pd_initialize() {
|
||||
_anchor.clear();
|
||||
_last_interpreter_fp = NULL;
|
||||
}
|
||||
|
||||
// The `last' frame is the youngest Java frame on the thread's stack.
|
||||
@ -61,22 +60,4 @@
|
||||
|
||||
bool pd_get_top_frame_for_signal_handler(frame* fr_addr, void* ucontext, bool isInJava);
|
||||
|
||||
protected:
|
||||
|
||||
// -Xprof support
|
||||
//
|
||||
// In order to find the last Java fp from an async profile
|
||||
// tick, we store the current interpreter fp in the thread.
|
||||
// This value is only valid while we are in the C++ interpreter
|
||||
// and profiling.
|
||||
intptr_t *_last_interpreter_fp;
|
||||
|
||||
public:
|
||||
|
||||
static ByteSize last_interpreter_fp_offset() {
|
||||
return byte_offset_of(JavaThread, _last_interpreter_fp);
|
||||
}
|
||||
|
||||
intptr_t* last_interpreter_fp() { return _last_interpreter_fp; }
|
||||
|
||||
#endif // OS_CPU_LINUX_S390_VM_THREAD_LINUX_S390_HPP
|
||||
|
@ -62,8 +62,8 @@ struct Atomic::PlatformAdd
|
||||
template<>
|
||||
template<typename I, typename D>
|
||||
inline D Atomic::PlatformAdd<4>::add_and_fetch(I add_value, D volatile* dest) const {
|
||||
STATIC_CAST(4 == sizeof(I));
|
||||
STATIC_CAST(4 == sizeof(D));
|
||||
STATIC_ASSERT(4 == sizeof(I));
|
||||
STATIC_ASSERT(4 == sizeof(D));
|
||||
|
||||
D rv;
|
||||
__asm__ volatile(
|
||||
@ -81,10 +81,11 @@ inline D Atomic::PlatformAdd<4>::add_and_fetch(I add_value, D volatile* dest) co
|
||||
return rv;
|
||||
}
|
||||
|
||||
template<>
|
||||
template<typename I, typename D>
|
||||
inline D Atomic::PlatformAdd<8>::add_and_fetch(I add_value, D volatile* dest) const {
|
||||
STATIC_CAST(8 == sizeof(I));
|
||||
STATIC_CAST(8 == sizeof(D));
|
||||
STATIC_ASSERT(8 == sizeof(I));
|
||||
STATIC_ASSERT(8 == sizeof(D));
|
||||
|
||||
D rv;
|
||||
__asm__ volatile(
|
||||
|
@ -178,8 +178,8 @@ struct Atomic::PlatformAdd
|
||||
template<>
|
||||
template<typename I, typename D>
|
||||
inline D Atomic::PlatformAdd<4>::add_and_fetch(I add_value, D volatile* dest) const {
|
||||
STATIC_CAST(4 == sizeof(I));
|
||||
STATIC_CAST(4 == sizeof(D));
|
||||
STATIC_ASSERT(4 == sizeof(I));
|
||||
STATIC_ASSERT(4 == sizeof(D));
|
||||
|
||||
#ifdef ARM
|
||||
return add_using_helper<int>(arm_add_and_fetch, add_value, dest);
|
||||
@ -195,8 +195,8 @@ inline D Atomic::PlatformAdd<4>::add_and_fetch(I add_value, D volatile* dest) co
|
||||
template<>
|
||||
template<typename I, typename D>
|
||||
inline D Atomic::PlatformAdd<8>::add_and_fetch(I add_value, D volatile* dest) const {
|
||||
STATIC_CAST(8 == sizeof(I));
|
||||
STATIC_CAST(8 == sizeof(D));
|
||||
STATIC_ASSERT(8 == sizeof(I));
|
||||
STATIC_ASSERT(8 == sizeof(D));
|
||||
|
||||
return __sync_add_and_fetch(dest, add_value);
|
||||
}
|
||||
|
@ -29,7 +29,6 @@
|
||||
#include "classfile/vmSymbols.hpp"
|
||||
#include "code/icBuffer.hpp"
|
||||
#include "code/vtableStubs.hpp"
|
||||
#include "decoder_windows.hpp"
|
||||
#include "interpreter/interpreter.hpp"
|
||||
#include "jvm_windows.h"
|
||||
#include "memory/allocation.inline.hpp"
|
||||
@ -51,10 +50,12 @@
|
||||
#include "runtime/stubRoutines.hpp"
|
||||
#include "runtime/thread.inline.hpp"
|
||||
#include "runtime/timer.hpp"
|
||||
#include "unwind_windows_x86.hpp"
|
||||
#include "utilities/events.hpp"
|
||||
#include "utilities/vmError.hpp"
|
||||
#include "windbghelp.hpp"
|
||||
|
||||
|
||||
# include "unwind_windows_x86.hpp"
|
||||
#undef REG_SP
|
||||
#undef REG_FP
|
||||
#undef REG_PC
|
||||
@ -401,24 +402,18 @@ bool os::platform_print_native_stack(outputStream* st, const void* context,
|
||||
lastpc = pc;
|
||||
}
|
||||
|
||||
PVOID p = WindowsDbgHelp::SymFunctionTableAccess64(GetCurrentProcess(), stk.AddrPC.Offset);
|
||||
PVOID p = WindowsDbgHelp::symFunctionTableAccess64(GetCurrentProcess(), stk.AddrPC.Offset);
|
||||
if (!p) {
|
||||
// StackWalk64() can't handle this PC. Calling StackWalk64 again may cause crash.
|
||||
break;
|
||||
}
|
||||
|
||||
BOOL result = WindowsDbgHelp::StackWalk64(
|
||||
BOOL result = WindowsDbgHelp::stackWalk64(
|
||||
IMAGE_FILE_MACHINE_AMD64, // __in DWORD MachineType,
|
||||
GetCurrentProcess(), // __in HANDLE hProcess,
|
||||
GetCurrentThread(), // __in HANDLE hThread,
|
||||
&stk, // __inout LP STACKFRAME64 StackFrame,
|
||||
&ctx, // __inout PVOID ContextRecord,
|
||||
NULL, // __in_opt PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine,
|
||||
WindowsDbgHelp::pfnSymFunctionTableAccess64(),
|
||||
// __in_opt PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine,
|
||||
WindowsDbgHelp::pfnSymGetModuleBase64(),
|
||||
// __in_opt PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine,
|
||||
NULL); // __in_opt PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress
|
||||
&ctx); // __inout PVOID ContextRecord,
|
||||
|
||||
if (!result) {
|
||||
break;
|
||||
|
@ -12,7 +12,6 @@
|
||||
-Xms<size> set initial Java heap size
|
||||
-Xmx<size> set maximum Java heap size
|
||||
-Xss<size> set java thread stack size
|
||||
-Xprof output cpu profiling data (deprecated)
|
||||
-Xfuture enable strictest checks, anticipating future default
|
||||
-Xrs reduce use of OS signals by Java/VM (see documentation)
|
||||
-Xcheck:jni perform additional checks for JNI functions
|
||||
|
@ -478,6 +478,8 @@ void AOTCodeHeap::link_stub_routines_symbols() {
|
||||
SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_arrayof_oop_disjoint_arraycopy", address, StubRoutines::_arrayof_oop_disjoint_arraycopy);
|
||||
SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_arrayof_oop_disjoint_arraycopy_uninit", address, StubRoutines::_arrayof_oop_disjoint_arraycopy_uninit);
|
||||
|
||||
SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_unsafe_arraycopy", address, StubRoutines::_unsafe_arraycopy);
|
||||
|
||||
SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_checkcast_arraycopy", address, StubRoutines::_checkcast_arraycopy);
|
||||
|
||||
SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_aescrypt_encryptBlock", address, StubRoutines::_aescrypt_encryptBlock);
|
||||
|
@ -57,7 +57,6 @@
|
||||
#include "prims/jvm_misc.hpp"
|
||||
#include "runtime/arguments.hpp"
|
||||
#include "runtime/compilationPolicy.hpp"
|
||||
#include "runtime/fprofiler.hpp"
|
||||
#include "runtime/handles.hpp"
|
||||
#include "runtime/handles.inline.hpp"
|
||||
#include "runtime/init.hpp"
|
||||
@ -147,6 +146,7 @@ ClassPathEntry* ClassLoader::_jrt_entry = NULL;
|
||||
ClassPathEntry* ClassLoader::_first_append_entry = NULL;
|
||||
ClassPathEntry* ClassLoader::_last_append_entry = NULL;
|
||||
int ClassLoader::_num_entries = 0;
|
||||
int ClassLoader::_num_boot_entries = -1;
|
||||
#if INCLUDE_CDS
|
||||
GrowableArray<char*>* ClassLoader::_boot_modules_array = NULL;
|
||||
GrowableArray<char*>* ClassLoader::_platform_modules_array = NULL;
|
||||
@ -242,7 +242,7 @@ const char* ClassLoader::package_from_name(const char* const class_name, bool* b
|
||||
|
||||
// Given a fully qualified class name, find its defining package in the class loader's
|
||||
// package entry table.
|
||||
static PackageEntry* get_package_entry(const char* class_name, ClassLoaderData* loader_data, TRAPS) {
|
||||
PackageEntry* ClassLoader::get_package_entry(const char* class_name, ClassLoaderData* loader_data, TRAPS) {
|
||||
ResourceMark rm(THREAD);
|
||||
const char *pkg_name = ClassLoader::package_from_name(class_name);
|
||||
if (pkg_name == NULL) {
|
||||
@ -509,7 +509,7 @@ ClassFileStream* ClassPathImageEntry::open_stream(const char* name, TRAPS) {
|
||||
#endif
|
||||
|
||||
} else {
|
||||
PackageEntry* package_entry = get_package_entry(name, ClassLoaderData::the_null_class_loader_data(), CHECK_NULL);
|
||||
PackageEntry* package_entry = ClassLoader::get_package_entry(name, ClassLoaderData::the_null_class_loader_data(), CHECK_NULL);
|
||||
if (package_entry != NULL) {
|
||||
ResourceMark rm;
|
||||
// Get the module name
|
||||
@ -540,6 +540,13 @@ ClassFileStream* ClassPathImageEntry::open_stream(const char* name, TRAPS) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
JImageLocationRef ClassLoader::jimage_find_resource(JImageFile* jf,
|
||||
const char* module_name,
|
||||
const char* file_name,
|
||||
jlong &size) {
|
||||
return ((*JImageFindResource)(jf, module_name, get_jimage_version_string(), file_name, &size));
|
||||
}
|
||||
|
||||
#ifndef PRODUCT
|
||||
bool ctw_visitor(JImageFile* jimage,
|
||||
const char* module_name, const char* version, const char* package,
|
||||
@ -1066,7 +1073,7 @@ void ClassLoader::load_zip_library() {
|
||||
char path[JVM_MAXPATHLEN];
|
||||
char ebuf[1024];
|
||||
void* handle = NULL;
|
||||
if (os::dll_build_name(path, sizeof(path), Arguments::get_dll_dir(), "zip")) {
|
||||
if (os::dll_locate_lib(path, sizeof(path), Arguments::get_dll_dir(), "zip")) {
|
||||
handle = os::dll_load(path, ebuf, sizeof ebuf);
|
||||
}
|
||||
if (handle == NULL) {
|
||||
@ -1104,7 +1111,7 @@ void ClassLoader::load_jimage_library() {
|
||||
char path[JVM_MAXPATHLEN];
|
||||
char ebuf[1024];
|
||||
void* handle = NULL;
|
||||
if (os::dll_build_name(path, sizeof(path), Arguments::get_dll_dir(), "jimage")) {
|
||||
if (os::dll_locate_lib(path, sizeof(path), Arguments::get_dll_dir(), "jimage")) {
|
||||
handle = os::dll_load(path, ebuf, sizeof ebuf);
|
||||
}
|
||||
if (handle == NULL) {
|
||||
@ -1434,7 +1441,6 @@ InstanceKlass* ClassLoader::load_class(Symbol* name, bool search_append_only, TR
|
||||
const char* const class_name = name->as_C_string();
|
||||
|
||||
EventMark m("loading class %s", class_name);
|
||||
ThreadProfilerMark tpm(ThreadProfilerMark::classLoaderRegion);
|
||||
|
||||
const char* const file_name = file_name_for_class_name(class_name,
|
||||
name->utf8_length());
|
||||
@ -1459,9 +1465,6 @@ InstanceKlass* ClassLoader::load_class(Symbol* name, bool search_append_only, TR
|
||||
// This would include:
|
||||
// [--patch-module=<module>=<file>(<pathsep><file>)*]; [jimage | exploded module build]
|
||||
//
|
||||
// DumpSharedSpaces and search_append_only are mutually exclusive and cannot
|
||||
// be true at the same time.
|
||||
assert(!(DumpSharedSpaces && search_append_only), "DumpSharedSpaces and search_append_only are both true");
|
||||
|
||||
// Load Attempt #1: --patch-module
|
||||
// Determine the class' defining module. If it appears in the _patch_mod_entries,
|
||||
@ -1507,6 +1510,11 @@ InstanceKlass* ClassLoader::load_class(Symbol* name, bool search_append_only, TR
|
||||
|
||||
e = _first_append_entry;
|
||||
while (e != NULL) {
|
||||
if (DumpSharedSpaces && classpath_index >= _num_boot_entries) {
|
||||
// Do not load any class from the app classpath using the boot loader. Let
|
||||
// the built-in app class laoder load them.
|
||||
break;
|
||||
}
|
||||
stream = e->open_stream(file_name, CHECK_NULL);
|
||||
if (!context.check(stream, classpath_index)) {
|
||||
return NULL;
|
||||
@ -1520,9 +1528,6 @@ InstanceKlass* ClassLoader::load_class(Symbol* name, bool search_append_only, TR
|
||||
}
|
||||
|
||||
if (NULL == stream) {
|
||||
if (DumpSharedSpaces) {
|
||||
tty->print_cr("Preload Warning: Cannot find %s", class_name);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -1548,6 +1553,100 @@ InstanceKlass* ClassLoader::load_class(Symbol* name, bool search_append_only, TR
|
||||
return context.record_result(name, e, classpath_index, result, THREAD);
|
||||
}
|
||||
|
||||
#if INCLUDE_CDS
|
||||
static char* skip_uri_protocol(char* source) {
|
||||
if (strncmp(source, "file:", 5) == 0) {
|
||||
// file: protocol path could start with file:/ or file:///
|
||||
// locate the char after all the forward slashes
|
||||
int offset = 5;
|
||||
while (*(source + offset) == '/') {
|
||||
offset++;
|
||||
}
|
||||
source += offset;
|
||||
// for non-windows platforms, move back one char as the path begins with a '/'
|
||||
#ifndef _WINDOWS
|
||||
source -= 1;
|
||||
#endif
|
||||
} else if (strncmp(source, "jrt:/", 5) == 0) {
|
||||
source += 5;
|
||||
}
|
||||
return source;
|
||||
}
|
||||
|
||||
void ClassLoader::record_shared_class_loader_type(InstanceKlass* ik, const ClassFileStream* stream) {
|
||||
assert(DumpSharedSpaces, "sanity");
|
||||
assert(stream != NULL, "sanity");
|
||||
|
||||
if (ik->is_anonymous()) {
|
||||
// We do not archive anonymous classes.
|
||||
return;
|
||||
}
|
||||
|
||||
if (stream->source() == NULL) {
|
||||
if (ik->class_loader() == NULL) {
|
||||
// JFR classes
|
||||
ik->set_shared_classpath_index(0);
|
||||
ik->set_class_loader_type(ClassLoader::BOOT_LOADER);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
assert(has_jrt_entry(), "CDS dumping does not support exploded JDK build");
|
||||
|
||||
ModuleEntry* module = ik->module();
|
||||
ClassPathEntry* e = NULL;
|
||||
int classpath_index = 0;
|
||||
|
||||
// Check if the class is from the runtime image
|
||||
if (module != NULL && (module->location() != NULL) &&
|
||||
(module->location()->starts_with("jrt:"))) {
|
||||
e = _jrt_entry;
|
||||
classpath_index = 0;
|
||||
} else {
|
||||
classpath_index = 1;
|
||||
ResourceMark rm;
|
||||
char* canonical_path = NEW_RESOURCE_ARRAY(char, JVM_MAXPATHLEN);
|
||||
for (e = _first_append_entry; e != NULL; e = e->next()) {
|
||||
if (get_canonical_path(e->name(), canonical_path, JVM_MAXPATHLEN)) {
|
||||
char* src = (char*)stream->source();
|
||||
// save the path from the file: protocol or the module name from the jrt: protocol
|
||||
// if no protocol prefix is found, src is the same as stream->source() after the following call
|
||||
src = skip_uri_protocol(src);
|
||||
if (strcmp(canonical_path, os::native_path((char*)src)) == 0) {
|
||||
break;
|
||||
}
|
||||
classpath_index ++;
|
||||
}
|
||||
}
|
||||
if (e == NULL) {
|
||||
assert(ik->shared_classpath_index() < 0,
|
||||
"must be a class from a custom jar which isn't in the class path or boot class path");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (classpath_index < _num_boot_entries) {
|
||||
// ik is either:
|
||||
// 1) a boot class loaded from the runtime image during vm initialization (classpath_index = 0); or
|
||||
// 2) a user's class from -Xbootclasspath/a (classpath_index > 0)
|
||||
// In the second case, the classpath_index, classloader_type will be recorded via
|
||||
// context.record_result() in ClassLoader::load_class(Symbol* name, bool search_append_only, TRAPS).
|
||||
if (classpath_index > 0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ResourceMark rm;
|
||||
const char* const class_name = ik->name()->as_C_string();
|
||||
const char* const file_name = file_name_for_class_name(class_name,
|
||||
ik->name()->utf8_length());
|
||||
assert(file_name != NULL, "invariant");
|
||||
Thread* THREAD = Thread::current();
|
||||
ClassLoaderExt::Context context(class_name, file_name, CATCH);
|
||||
context.record_result(ik->name(), e, classpath_index, ik, THREAD);
|
||||
}
|
||||
#endif // INCLUDE_CDS
|
||||
|
||||
// Initialize the class loader's access to methods in libzip. Parse and
|
||||
// process the boot classpath into a list ClassPathEntry objects. Once
|
||||
// this list has been created, it must not change order (see class PackageInfo)
|
||||
@ -1632,6 +1731,7 @@ void ClassLoader::initialize() {
|
||||
#if INCLUDE_CDS
|
||||
void ClassLoader::initialize_shared_path() {
|
||||
if (DumpSharedSpaces) {
|
||||
_num_boot_entries = _num_entries;
|
||||
ClassLoaderExt::setup_search_paths();
|
||||
_shared_paths_misc_info->write_jint(0); // see comments in SharedPathsMiscInfo::check()
|
||||
}
|
||||
|
@ -25,6 +25,7 @@
|
||||
#ifndef SHARE_VM_CLASSFILE_CLASSLOADER_HPP
|
||||
#define SHARE_VM_CLASSFILE_CLASSLOADER_HPP
|
||||
|
||||
#include "classfile/jimage.hpp"
|
||||
#include "runtime/orderAccess.hpp"
|
||||
#include "runtime/perfData.hpp"
|
||||
#include "utilities/exceptions.hpp"
|
||||
@ -47,6 +48,7 @@
|
||||
|
||||
class JImageFile;
|
||||
class ClassFileStream;
|
||||
class PackageEntry;
|
||||
|
||||
class ClassPathEntry : public CHeapObj<mtClass> {
|
||||
private:
|
||||
@ -103,7 +105,6 @@ typedef struct {
|
||||
jlong pos; /* position of LOC header (if negative) or data */
|
||||
} jzentry;
|
||||
|
||||
|
||||
class ClassPathZipEntry: public ClassPathEntry {
|
||||
enum {
|
||||
_unknown = 0,
|
||||
@ -249,6 +250,10 @@ class ClassLoader: AllStatic {
|
||||
// the entries on the _first_append_entry linked list.
|
||||
static int _num_entries;
|
||||
|
||||
// number of entries in the boot class path including the
|
||||
// java runtime image
|
||||
static int _num_boot_entries;
|
||||
|
||||
// Array of module names associated with the boot class loader
|
||||
CDS_ONLY(static GrowableArray<char*>* _boot_modules_array;)
|
||||
|
||||
@ -289,6 +294,7 @@ class ClassLoader: AllStatic {
|
||||
static bool get_canonical_path(const char* orig, char* out, int len);
|
||||
static const char* file_name_for_class_name(const char* class_name,
|
||||
int class_name_len);
|
||||
static PackageEntry* get_package_entry(const char* class_name, ClassLoaderData* loader_data, TRAPS);
|
||||
|
||||
public:
|
||||
static jboolean decompress(void *in, u8 inSize, void *out, u8 outSize, char **pmsg);
|
||||
@ -436,7 +442,10 @@ class ClassLoader: AllStatic {
|
||||
static void initialize_module_loader_map(JImageFile* jimage);
|
||||
static s2 classloader_type(Symbol* class_name, ClassPathEntry* e,
|
||||
int classpath_index, TRAPS);
|
||||
static void record_shared_class_loader_type(InstanceKlass* ik, const ClassFileStream* stream);
|
||||
#endif
|
||||
static JImageLocationRef jimage_find_resource(JImageFile* jf, const char* module_name,
|
||||
const char* file_name, jlong &size);
|
||||
|
||||
static void trace_class_path(const char* msg, const char* name = NULL);
|
||||
|
||||
|
@ -75,6 +75,9 @@
|
||||
#include "utilities/growableArray.hpp"
|
||||
#include "utilities/macros.hpp"
|
||||
#include "utilities/ostream.hpp"
|
||||
#if INCLUDE_ALL_GCS
|
||||
#include "gc/g1/g1SATBCardTableModRefBS.hpp"
|
||||
#endif // INCLUDE_ALL_GCS
|
||||
#if INCLUDE_TRACE
|
||||
#include "trace/tracing.hpp"
|
||||
#endif
|
||||
@ -764,6 +767,25 @@ OopHandle ClassLoaderData::add_handle(Handle h) {
|
||||
return OopHandle(_handles.add(h()));
|
||||
}
|
||||
|
||||
void ClassLoaderData::remove_handle(OopHandle h) {
|
||||
oop* ptr = h.ptr_raw();
|
||||
if (ptr != NULL) {
|
||||
assert(_handles.contains(ptr), "Got unexpected handle " PTR_FORMAT, p2i(ptr));
|
||||
#if INCLUDE_ALL_GCS
|
||||
// This barrier is used by G1 to remember the old oop values, so
|
||||
// that we don't forget any objects that were live at the snapshot at
|
||||
// the beginning.
|
||||
if (UseG1GC) {
|
||||
oop obj = *ptr;
|
||||
if (obj != NULL) {
|
||||
G1SATBCardTableModRefBS::enqueue(obj);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
*ptr = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void ClassLoaderData::init_handle_locked(OopHandle& dest, Handle h) {
|
||||
MutexLockerEx ml(metaspace_lock(), Mutex::_no_safepoint_check_flag);
|
||||
if (dest.resolve() != NULL) {
|
||||
|
@ -364,6 +364,7 @@ class ClassLoaderData : public CHeapObj<mtClass> {
|
||||
const char* loader_name();
|
||||
|
||||
OopHandle add_handle(Handle h);
|
||||
void remove_handle(OopHandle h);
|
||||
void init_handle_locked(OopHandle& pd, Handle h); // used for concurrent access to ModuleEntry::_pd field
|
||||
void add_class(Klass* k, bool publicize = true);
|
||||
void remove_class(Klass* k);
|
||||
|
@ -26,6 +26,7 @@
|
||||
#define SHARE_VM_CLASSFILE_CLASSLOADEREXT_HPP
|
||||
|
||||
#include "classfile/classLoader.hpp"
|
||||
#include "classfile/systemDictionary.hpp"
|
||||
#include "oops/instanceKlass.hpp"
|
||||
#include "runtime/handles.hpp"
|
||||
|
||||
@ -56,8 +57,15 @@ public:
|
||||
if (ClassLoader::add_package(_file_name, classpath_index, THREAD)) {
|
||||
#if INCLUDE_CDS
|
||||
if (DumpSharedSpaces) {
|
||||
s2 classloader_type = ClassLoader::classloader_type(
|
||||
class_name, e, classpath_index, CHECK_(result));
|
||||
oop loader = result->class_loader();
|
||||
s2 classloader_type = ClassLoader::BOOT_LOADER;
|
||||
if (SystemDictionary::is_system_class_loader(loader)) {
|
||||
classloader_type = ClassLoader::APP_LOADER;
|
||||
ClassLoaderExt::set_has_app_classes();
|
||||
} else if (SystemDictionary::is_platform_class_loader(loader)) {
|
||||
classloader_type = ClassLoader::PLATFORM_LOADER;
|
||||
ClassLoaderExt::set_has_platform_classes();
|
||||
}
|
||||
result->set_shared_classpath_index(classpath_index);
|
||||
result->set_class_loader_type(classloader_type);
|
||||
}
|
||||
@ -82,6 +90,13 @@ public:
|
||||
return true;
|
||||
}
|
||||
static Klass* load_one_class(ClassListParser* parser, TRAPS);
|
||||
#if INCLUDE_CDS
|
||||
static void set_has_app_classes() {}
|
||||
static void set_has_platform_classes() {}
|
||||
static char* read_manifest(ClassPathEntry* entry, jint *manifest_size, TRAPS) {
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif // SHARE_VM_CLASSFILE_CLASSLOADEREXT_HPP
|
||||
|
@ -85,6 +85,7 @@ DictionaryEntry* Dictionary::new_entry(unsigned int hash, InstanceKlass* klass)
|
||||
|
||||
void Dictionary::free_entry(DictionaryEntry* entry) {
|
||||
// avoid recursion when deleting linked list
|
||||
// pd_set is accessed during a safepoint.
|
||||
while (entry->pd_set() != NULL) {
|
||||
ProtectionDomainEntry* to_delete = entry->pd_set();
|
||||
entry->set_pd_set(to_delete->next());
|
||||
@ -101,7 +102,7 @@ bool DictionaryEntry::contains_protection_domain(oop protection_domain) const {
|
||||
if (protection_domain == instance_klass()->protection_domain()) {
|
||||
// Ensure this doesn't show up in the pd_set (invariant)
|
||||
bool in_pd_set = false;
|
||||
for (ProtectionDomainEntry* current = _pd_set;
|
||||
for (ProtectionDomainEntry* current = pd_set_acquire();
|
||||
current != NULL;
|
||||
current = current->next()) {
|
||||
if (current->protection_domain() == protection_domain) {
|
||||
@ -121,7 +122,7 @@ bool DictionaryEntry::contains_protection_domain(oop protection_domain) const {
|
||||
return true;
|
||||
}
|
||||
|
||||
for (ProtectionDomainEntry* current = _pd_set;
|
||||
for (ProtectionDomainEntry* current = pd_set_acquire();
|
||||
current != NULL;
|
||||
current = current->next()) {
|
||||
if (current->protection_domain() == protection_domain) return true;
|
||||
@ -135,12 +136,12 @@ void DictionaryEntry::add_protection_domain(Dictionary* dict, Handle protection_
|
||||
if (!contains_protection_domain(protection_domain())) {
|
||||
ProtectionDomainCacheEntry* entry = SystemDictionary::cache_get(protection_domain);
|
||||
ProtectionDomainEntry* new_head =
|
||||
new ProtectionDomainEntry(entry, _pd_set);
|
||||
new ProtectionDomainEntry(entry, pd_set());
|
||||
// Warning: Preserve store ordering. The SystemDictionary is read
|
||||
// without locks. The new ProtectionDomainEntry must be
|
||||
// complete before other threads can be allowed to see it
|
||||
// via a store to _pd_set.
|
||||
OrderAccess::release_store_ptr(&_pd_set, new_head);
|
||||
release_set_pd_set(new_head);
|
||||
}
|
||||
LogTarget(Trace, protectiondomain) lt;
|
||||
if (lt.is_enabled()) {
|
||||
@ -365,11 +366,21 @@ void Dictionary::reorder_dictionary_for_sharing() {
|
||||
for (int i = 0; i < table_size(); ++i) {
|
||||
DictionaryEntry* p = bucket(i);
|
||||
while (p != NULL) {
|
||||
DictionaryEntry* tmp;
|
||||
tmp = p->next();
|
||||
p->set_next(master_list);
|
||||
master_list = p;
|
||||
p = tmp;
|
||||
DictionaryEntry* next = p->next();
|
||||
InstanceKlass*ik = p->instance_klass();
|
||||
// we cannot include signed classes in the archive because the certificates
|
||||
// used during dump time may be different than those used during
|
||||
// runtime (due to expiration, etc).
|
||||
if (ik->signers() != NULL) {
|
||||
ResourceMark rm;
|
||||
tty->print_cr("Preload Warning: Skipping %s from signed JAR",
|
||||
ik->name()->as_C_string());
|
||||
free_entry(p);
|
||||
} else {
|
||||
p->set_next(master_list);
|
||||
master_list = p;
|
||||
}
|
||||
p = next;
|
||||
}
|
||||
set_entry(i, NULL);
|
||||
}
|
||||
|
@ -29,6 +29,7 @@
|
||||
#include "classfile/systemDictionary.hpp"
|
||||
#include "oops/instanceKlass.hpp"
|
||||
#include "oops/oop.hpp"
|
||||
#include "runtime/orderAccess.hpp"
|
||||
#include "utilities/hashtable.hpp"
|
||||
#include "utilities/ostream.hpp"
|
||||
|
||||
@ -48,21 +49,6 @@ class Dictionary : public Hashtable<InstanceKlass*, mtClass> {
|
||||
DictionaryEntry* get_entry(int index, unsigned int hash, Symbol* name);
|
||||
|
||||
protected:
|
||||
DictionaryEntry* bucket(int i) const {
|
||||
return (DictionaryEntry*)Hashtable<InstanceKlass*, mtClass>::bucket(i);
|
||||
}
|
||||
|
||||
// The following method is not MT-safe and must be done under lock.
|
||||
DictionaryEntry** bucket_addr(int i) {
|
||||
return (DictionaryEntry**)Hashtable<InstanceKlass*, mtClass>::bucket_addr(i);
|
||||
}
|
||||
|
||||
void add_entry(int index, DictionaryEntry* new_entry) {
|
||||
Hashtable<InstanceKlass*, mtClass>::add_entry(index, (HashtableEntry<InstanceKlass*, mtClass>*)new_entry);
|
||||
}
|
||||
|
||||
void free_entry(DictionaryEntry* entry);
|
||||
|
||||
static size_t entry_size();
|
||||
public:
|
||||
Dictionary(ClassLoaderData* loader_data, int table_size);
|
||||
@ -106,6 +92,24 @@ public:
|
||||
|
||||
void print_on(outputStream* st) const;
|
||||
void verify();
|
||||
DictionaryEntry* bucket(int i) const {
|
||||
return (DictionaryEntry*)Hashtable<InstanceKlass*, mtClass>::bucket(i);
|
||||
}
|
||||
|
||||
// The following method is not MT-safe and must be done under lock.
|
||||
DictionaryEntry** bucket_addr(int i) {
|
||||
return (DictionaryEntry**)Hashtable<InstanceKlass*, mtClass>::bucket_addr(i);
|
||||
}
|
||||
|
||||
void add_entry(int index, DictionaryEntry* new_entry) {
|
||||
Hashtable<InstanceKlass*, mtClass>::add_entry(index, (HashtableEntry<InstanceKlass*, mtClass>*)new_entry);
|
||||
}
|
||||
|
||||
void unlink_entry(DictionaryEntry* entry) {
|
||||
Hashtable<InstanceKlass*, mtClass>::unlink_entry((HashtableEntry<InstanceKlass*, mtClass>*)entry);
|
||||
}
|
||||
|
||||
void free_entry(DictionaryEntry* entry);
|
||||
};
|
||||
|
||||
// An entry in the class loader data dictionaries, this describes a class as
|
||||
@ -134,7 +138,7 @@ class DictionaryEntry : public HashtableEntry<InstanceKlass*, mtClass> {
|
||||
// It is essentially a cache to avoid repeated Java up-calls to
|
||||
// ClassLoader.checkPackageAccess().
|
||||
//
|
||||
ProtectionDomainEntry* _pd_set;
|
||||
ProtectionDomainEntry* volatile _pd_set;
|
||||
|
||||
public:
|
||||
// Tells whether a protection is in the approved set.
|
||||
@ -153,8 +157,15 @@ class DictionaryEntry : public HashtableEntry<InstanceKlass*, mtClass> {
|
||||
return (DictionaryEntry**)HashtableEntry<InstanceKlass*, mtClass>::next_addr();
|
||||
}
|
||||
|
||||
ProtectionDomainEntry* pd_set() const { return _pd_set; }
|
||||
void set_pd_set(ProtectionDomainEntry* pd_set) { _pd_set = pd_set; }
|
||||
ProtectionDomainEntry* pd_set() const { return _pd_set; }
|
||||
void set_pd_set(ProtectionDomainEntry* new_head) { _pd_set = new_head; }
|
||||
|
||||
ProtectionDomainEntry* pd_set_acquire() const {
|
||||
return (ProtectionDomainEntry*)OrderAccess::load_ptr_acquire(&_pd_set);
|
||||
}
|
||||
void release_set_pd_set(ProtectionDomainEntry* new_head) {
|
||||
OrderAccess::release_store_ptr(&_pd_set, new_head);
|
||||
}
|
||||
|
||||
// Tells whether the initiating class' protection domain can access the klass in this entry
|
||||
bool is_valid_protection_domain(Handle protection_domain) {
|
||||
@ -167,7 +178,7 @@ class DictionaryEntry : public HashtableEntry<InstanceKlass*, mtClass> {
|
||||
}
|
||||
|
||||
void verify_protection_domain_set() {
|
||||
for (ProtectionDomainEntry* current = _pd_set;
|
||||
for (ProtectionDomainEntry* current = pd_set(); // accessed at a safepoint
|
||||
current != NULL;
|
||||
current = current->_next) {
|
||||
current->_pd_cache->protection_domain()->verify();
|
||||
@ -181,7 +192,7 @@ class DictionaryEntry : public HashtableEntry<InstanceKlass*, mtClass> {
|
||||
|
||||
void print_count(outputStream *st) {
|
||||
int count = 0;
|
||||
for (ProtectionDomainEntry* current = _pd_set;
|
||||
for (ProtectionDomainEntry* current = pd_set(); // accessed inside SD lock
|
||||
current != NULL;
|
||||
current = current->_next) {
|
||||
count++;
|
||||
@ -246,10 +257,6 @@ class SymbolPropertyEntry : public HashtableEntry<Symbol*, mtSymbol> {
|
||||
class SymbolPropertyTable : public Hashtable<Symbol*, mtSymbol> {
|
||||
friend class VMStructs;
|
||||
private:
|
||||
SymbolPropertyEntry* bucket(int i) {
|
||||
return (SymbolPropertyEntry*) Hashtable<Symbol*, mtSymbol>::bucket(i);
|
||||
}
|
||||
|
||||
// The following method is not MT-safe and must be done under lock.
|
||||
SymbolPropertyEntry** bucket_addr(int i) {
|
||||
return (SymbolPropertyEntry**) Hashtable<Symbol*, mtSymbol>::bucket_addr(i);
|
||||
@ -303,5 +310,9 @@ public:
|
||||
void methods_do(void f(Method*));
|
||||
|
||||
void verify();
|
||||
|
||||
SymbolPropertyEntry* bucket(int i) {
|
||||
return (SymbolPropertyEntry*) Hashtable<Symbol*, mtSymbol>::bucket(i);
|
||||
}
|
||||
};
|
||||
#endif // SHARE_VM_CLASSFILE_DICTIONARY_HPP
|
||||
|
@ -70,11 +70,25 @@ InstanceKlass* KlassFactory::check_shared_class_file_load_hook(
|
||||
ClassLoaderData* loader_data =
|
||||
ClassLoaderData::class_loader_data(class_loader());
|
||||
int path_index = ik->shared_classpath_index();
|
||||
SharedClassPathEntry* ent =
|
||||
(SharedClassPathEntry*)FileMapInfo::shared_classpath(path_index);
|
||||
const char* pathname;
|
||||
if (path_index < 0) {
|
||||
// shared classes loaded by user defined class loader
|
||||
// do not have shared_classpath_index
|
||||
ModuleEntry* mod_entry = ik->module();
|
||||
if (mod_entry != NULL && (mod_entry->location() != NULL)) {
|
||||
ResourceMark rm;
|
||||
pathname = (const char*)(mod_entry->location()->as_C_string());
|
||||
} else {
|
||||
pathname = "";
|
||||
}
|
||||
} else {
|
||||
SharedClassPathEntry* ent =
|
||||
(SharedClassPathEntry*)FileMapInfo::shared_classpath(path_index);
|
||||
pathname = ent == NULL ? NULL : ent->name();
|
||||
}
|
||||
ClassFileStream* stream = new ClassFileStream(ptr,
|
||||
end_ptr - ptr,
|
||||
ent == NULL ? NULL : ent->name(),
|
||||
pathname,
|
||||
ClassFileStream::verify);
|
||||
ClassFileParser parser(stream,
|
||||
class_name,
|
||||
@ -215,8 +229,10 @@ InstanceKlass* KlassFactory::create_from_stream(ClassFileStream* stream,
|
||||
|
||||
TRACE_KLASS_CREATION(result, parser, THREAD);
|
||||
|
||||
#if INCLUDE_CDS && INCLUDE_JVMTI
|
||||
#if INCLUDE_CDS
|
||||
if (DumpSharedSpaces) {
|
||||
ClassLoader::record_shared_class_loader_type(result, stream);
|
||||
#if INCLUDE_JVMTI
|
||||
assert(cached_class_file == NULL, "Sanity");
|
||||
// Archive the class stream data into the optional data section
|
||||
JvmtiCachedClassFileData *p;
|
||||
@ -233,8 +249,9 @@ InstanceKlass* KlassFactory::create_from_stream(ClassFileStream* stream,
|
||||
p->length = len;
|
||||
memcpy(p->data, bytes, len);
|
||||
result->set_archived_class_data(p);
|
||||
#endif // INCLUDE_JVMTI
|
||||
}
|
||||
#endif
|
||||
#endif // INCLUDE_CDS
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -729,7 +729,6 @@ bool StringTable::copy_shared_string(GrowableArray<MemRegion> *string_space,
|
||||
}
|
||||
|
||||
G1CollectedHeap::heap()->end_archive_alloc_range(string_space, os::vm_allocation_granularity());
|
||||
assert(string_space->length() <= 2, "sanity");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -66,6 +66,7 @@
|
||||
#include "prims/resolvedMethodTable.hpp"
|
||||
#include "prims/methodHandles.hpp"
|
||||
#include "runtime/arguments.hpp"
|
||||
#include "runtime/arguments_ext.hpp"
|
||||
#include "runtime/biasedLocking.hpp"
|
||||
#include "runtime/fieldType.hpp"
|
||||
#include "runtime/handles.inline.hpp"
|
||||
@ -869,7 +870,7 @@ Klass* SystemDictionary::resolve_instance_class_or_null(Symbol* name,
|
||||
// during compilations.
|
||||
MutexLocker mu(Compile_lock, THREAD);
|
||||
update_dictionary(d_index, d_hash, p_index, p_hash,
|
||||
k, class_loader, THREAD);
|
||||
k, class_loader, THREAD);
|
||||
}
|
||||
|
||||
if (JvmtiExport::should_post_class_load()) {
|
||||
@ -910,12 +911,9 @@ Klass* SystemDictionary::resolve_instance_class_or_null(Symbol* name,
|
||||
if (protection_domain() == NULL) return k;
|
||||
|
||||
// Check the protection domain has the right access
|
||||
{
|
||||
MutexLocker mu(SystemDictionary_lock, THREAD);
|
||||
if (dictionary->is_valid_protection_domain(d_index, d_hash, name,
|
||||
protection_domain)) {
|
||||
return k;
|
||||
}
|
||||
if (dictionary->is_valid_protection_domain(d_index, d_hash, name,
|
||||
protection_domain)) {
|
||||
return k;
|
||||
}
|
||||
|
||||
// Verify protection domain. If it fails an exception is thrown
|
||||
@ -1009,7 +1007,6 @@ InstanceKlass* SystemDictionary::parse_stream(Symbol* class_name,
|
||||
// Create a new CLD for anonymous class, that uses the same class loader
|
||||
// as the host_klass
|
||||
guarantee(host_klass->class_loader() == class_loader(), "should be the same");
|
||||
guarantee(!DumpSharedSpaces, "must not create anonymous classes when dumping");
|
||||
loader_data = ClassLoaderData::anonymous_class_loader_data(class_loader(), CHECK_NULL);
|
||||
} else {
|
||||
loader_data = ClassLoaderData::class_loader_data(class_loader());
|
||||
@ -1078,6 +1075,15 @@ InstanceKlass* SystemDictionary::resolve_from_stream(Symbol* class_name,
|
||||
Handle protection_domain,
|
||||
ClassFileStream* st,
|
||||
TRAPS) {
|
||||
#if INCLUDE_CDS
|
||||
ResourceMark rm(THREAD);
|
||||
if (DumpSharedSpaces && !class_loader.is_null() &&
|
||||
!ArgumentsExt::using_AppCDS() && strcmp(class_name->as_C_string(), "Unnamed") != 0) {
|
||||
// If AppCDS is not enabled, don't define the class at dump time (except for the "Unnamed"
|
||||
// class, which is used by MethodHandles).
|
||||
THROW_MSG_NULL(vmSymbols::java_lang_ClassNotFoundException(), class_name->as_C_string());
|
||||
}
|
||||
#endif
|
||||
|
||||
HandleMark hm(THREAD);
|
||||
|
||||
@ -1104,11 +1110,13 @@ InstanceKlass* SystemDictionary::resolve_from_stream(Symbol* class_name,
|
||||
InstanceKlass* k = NULL;
|
||||
|
||||
#if INCLUDE_CDS
|
||||
k = SystemDictionaryShared::lookup_from_stream(class_name,
|
||||
class_loader,
|
||||
protection_domain,
|
||||
st,
|
||||
CHECK_NULL);
|
||||
if (!DumpSharedSpaces) {
|
||||
k = SystemDictionaryShared::lookup_from_stream(class_name,
|
||||
class_loader,
|
||||
protection_domain,
|
||||
st,
|
||||
CHECK_NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (k == NULL) {
|
||||
@ -1217,6 +1225,16 @@ bool SystemDictionary::is_shared_class_visible(Symbol* class_name,
|
||||
"Cannot use sharing if java.base is patched");
|
||||
ResourceMark rm;
|
||||
int path_index = ik->shared_classpath_index();
|
||||
ClassLoaderData* loader_data = class_loader_data(class_loader);
|
||||
if (path_index < 0) {
|
||||
// path_index < 0 indicates that the class is intended for a custom loader
|
||||
// and should not be loaded by boot/platform/app loaders
|
||||
if (loader_data->is_builtin_class_loader_data()) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
SharedClassPathEntry* ent =
|
||||
(SharedClassPathEntry*)FileMapInfo::shared_classpath(path_index);
|
||||
if (!Universe::is_module_initialized()) {
|
||||
@ -1230,7 +1248,6 @@ bool SystemDictionary::is_shared_class_visible(Symbol* class_name,
|
||||
PackageEntry* pkg_entry = NULL;
|
||||
ModuleEntry* mod_entry = NULL;
|
||||
const char* pkg_string = NULL;
|
||||
ClassLoaderData* loader_data = class_loader_data(class_loader);
|
||||
pkg_name = InstanceKlass::package_from_name(class_name, CHECK_false);
|
||||
if (pkg_name != NULL) {
|
||||
pkg_string = pkg_name->as_C_string();
|
||||
@ -1403,6 +1420,18 @@ InstanceKlass* SystemDictionary::load_shared_class(InstanceKlass* ik,
|
||||
}
|
||||
return ik;
|
||||
}
|
||||
|
||||
void SystemDictionary::clear_invoke_method_table() {
|
||||
SymbolPropertyEntry* spe = NULL;
|
||||
for (int index = 0; index < _invoke_method_table->table_size(); index++) {
|
||||
SymbolPropertyEntry* p = _invoke_method_table->bucket(index);
|
||||
while (p != NULL) {
|
||||
spe = p;
|
||||
p = p->next();
|
||||
_invoke_method_table->free_entry(spe);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // INCLUDE_CDS
|
||||
|
||||
InstanceKlass* SystemDictionary::load_instance_class(Symbol* class_name, Handle class_loader, TRAPS) {
|
||||
@ -1449,7 +1478,6 @@ InstanceKlass* SystemDictionary::load_instance_class(Symbol* class_name, Handle
|
||||
}
|
||||
}
|
||||
} else {
|
||||
assert(!DumpSharedSpaces, "Archive dumped after module system initialization");
|
||||
// After the module system has been initialized, check if the class'
|
||||
// package is in a module defined to the boot loader.
|
||||
if (pkg_name == NULL || pkg_entry == NULL || pkg_entry->in_unnamed_module()) {
|
||||
@ -1968,8 +1996,19 @@ void SystemDictionary::methods_do(void f(Method*)) {
|
||||
invoke_method_table()->methods_do(f);
|
||||
}
|
||||
|
||||
class RemoveClassesClosure : public CLDClosure {
|
||||
public:
|
||||
void do_cld(ClassLoaderData* cld) {
|
||||
if (cld->is_system_class_loader_data() || cld->is_platform_class_loader_data()) {
|
||||
cld->dictionary()->remove_classes_in_error_state();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void SystemDictionary::remove_classes_in_error_state() {
|
||||
ClassLoaderData::the_null_class_loader_data()->dictionary()->remove_classes_in_error_state();
|
||||
RemoveClassesClosure rcc;
|
||||
ClassLoaderDataGraph::cld_do(&rcc);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@ -2910,6 +2949,56 @@ int SystemDictionaryDCmd::num_arguments() {
|
||||
}
|
||||
}
|
||||
|
||||
class CombineDictionariesClosure : public CLDClosure {
|
||||
private:
|
||||
Dictionary* _master_dictionary;
|
||||
public:
|
||||
CombineDictionariesClosure(Dictionary* master_dictionary) :
|
||||
_master_dictionary(master_dictionary) {}
|
||||
void do_cld(ClassLoaderData* cld) {
|
||||
ResourceMark rm;
|
||||
if (cld->is_system_class_loader_data() || cld->is_platform_class_loader_data()) {
|
||||
for (int i = 0; i < cld->dictionary()->table_size(); ++i) {
|
||||
Dictionary* curr_dictionary = cld->dictionary();
|
||||
DictionaryEntry* p = curr_dictionary->bucket(i);
|
||||
while (p != NULL) {
|
||||
Symbol* name = p->instance_klass()->name();
|
||||
unsigned int d_hash = _master_dictionary->compute_hash(name);
|
||||
int d_index = _master_dictionary->hash_to_index(d_hash);
|
||||
DictionaryEntry* next = p->next();
|
||||
if (p->literal()->class_loader_data() != cld) {
|
||||
// This is an initiating class loader entry; don't use it
|
||||
log_trace(cds)("Skipping initiating cl entry: %s", name->as_C_string());
|
||||
curr_dictionary->free_entry(p);
|
||||
} else {
|
||||
log_trace(cds)("Moved to boot dictionary: %s", name->as_C_string());
|
||||
curr_dictionary->unlink_entry(p);
|
||||
p->set_pd_set(NULL); // pd_set is runtime only information and will be reconstructed.
|
||||
_master_dictionary->add_entry(d_index, p);
|
||||
}
|
||||
p = next;
|
||||
}
|
||||
*curr_dictionary->bucket_addr(i) = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Combining platform and system loader dictionaries into boot loader dictionaries.
|
||||
// During run time, we only have one shared dictionary.
|
||||
void SystemDictionary::combine_shared_dictionaries() {
|
||||
assert(DumpSharedSpaces, "dump time only");
|
||||
Dictionary* master_dictionary = ClassLoaderData::the_null_class_loader_data()->dictionary();
|
||||
CombineDictionariesClosure cdc(master_dictionary);
|
||||
ClassLoaderDataGraph::cld_do(&cdc);
|
||||
|
||||
// These tables are no longer valid or necessary. Keeping them around will
|
||||
// cause SystemDictionary::verify() to fail. Let's empty them.
|
||||
_placeholders = new PlaceholderTable(_placeholder_table_size);
|
||||
_loader_constraints = new LoaderConstraintTable(_loader_constraint_size);
|
||||
|
||||
NOT_PRODUCT(SystemDictionary::verify());
|
||||
}
|
||||
|
||||
// caller needs ResourceMark
|
||||
const char* SystemDictionary::loader_name(const oop loader) {
|
||||
|
@ -385,6 +385,7 @@ public:
|
||||
public:
|
||||
// Sharing support.
|
||||
static void reorder_dictionary_for_sharing();
|
||||
static void combine_shared_dictionaries();
|
||||
static size_t count_bytes_for_buckets();
|
||||
static size_t count_bytes_for_table();
|
||||
static void copy_buckets(char* top, char* end);
|
||||
@ -643,6 +644,7 @@ public:
|
||||
TRAPS);
|
||||
static bool is_system_class_loader(oop class_loader);
|
||||
static bool is_platform_class_loader(oop class_loader);
|
||||
static void clear_invoke_method_table();
|
||||
|
||||
protected:
|
||||
static InstanceKlass* find_shared_class(Symbol* class_name);
|
||||
|
@ -1220,7 +1220,7 @@ bool nmethod::make_not_entrant_or_zombie(unsigned int state) {
|
||||
// for stack scanning.
|
||||
if (state == not_entrant) {
|
||||
mark_as_seen_on_stack();
|
||||
OrderAccess::storestore();
|
||||
OrderAccess::storestore(); // _stack_traversal_mark and _state
|
||||
}
|
||||
|
||||
// Change state
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2017, 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
|
||||
@ -136,7 +136,7 @@ class nmethod : public CompiledMethod {
|
||||
// stack. An not_entrant method can be removed when there are no
|
||||
// more activations, i.e., when the _stack_traversal_mark is less than
|
||||
// current sweep traversal index.
|
||||
volatile jlong _stack_traversal_mark;
|
||||
volatile long _stack_traversal_mark;
|
||||
|
||||
// The _hotness_counter indicates the hotness of a method. The higher
|
||||
// the value the hotter the method. The hotness counter of a nmethod is
|
||||
@ -396,8 +396,8 @@ public:
|
||||
public:
|
||||
|
||||
// Sweeper support
|
||||
jlong stack_traversal_mark() { return OrderAccess::load_acquire(&_stack_traversal_mark); }
|
||||
void set_stack_traversal_mark(jlong l) { OrderAccess::release_store(&_stack_traversal_mark, l); }
|
||||
long stack_traversal_mark() { return _stack_traversal_mark; }
|
||||
void set_stack_traversal_mark(long l) { _stack_traversal_mark = l; }
|
||||
|
||||
// implicit exceptions support
|
||||
address continuation_for_implicit_exception(address pc);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2008, 2017, 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
|
||||
@ -30,7 +30,6 @@
|
||||
#include "gc/shared/collectedHeap.hpp"
|
||||
#include "memory/resourceArea.hpp"
|
||||
#include "oops/oop.inline.hpp"
|
||||
#include "runtime/fprofiler.hpp"
|
||||
#include "runtime/handles.inline.hpp"
|
||||
#include "runtime/os.hpp"
|
||||
#include "runtime/stubCodeGenerator.hpp"
|
||||
@ -163,7 +162,6 @@ class decode_env {
|
||||
bool _print_pc;
|
||||
bool _print_bytes;
|
||||
address _cur_insn;
|
||||
int _total_ticks;
|
||||
int _bytes_per_line; // arch-specific formatting option
|
||||
|
||||
static bool match(const char* event, const char* tag) {
|
||||
@ -213,18 +211,6 @@ class decode_env {
|
||||
_nm->print_code_comment_on(st, COMMENT_COLUMN, pc0, pc);
|
||||
// this calls reloc_string_for which calls oop::print_value_on
|
||||
}
|
||||
|
||||
// Output pc bucket ticks if we have any
|
||||
if (total_ticks() != 0) {
|
||||
address bucket_pc = FlatProfiler::bucket_start_for(pc);
|
||||
if (bucket_pc != NULL && bucket_pc > pc0 && bucket_pc <= pc) {
|
||||
int bucket_count = FlatProfiler::bucket_count_for(pc0);
|
||||
if (bucket_count != 0) {
|
||||
st->bol();
|
||||
st->print_cr("%3.1f%% [%d]", bucket_count*100.0/total_ticks(), bucket_count);
|
||||
}
|
||||
}
|
||||
}
|
||||
// follow each complete insn by a nice newline
|
||||
st->cr();
|
||||
}
|
||||
@ -233,8 +219,6 @@ class decode_env {
|
||||
|
||||
outputStream* output() { return _output; }
|
||||
address cur_insn() { return _cur_insn; }
|
||||
int total_ticks() { return _total_ticks; }
|
||||
void set_total_ticks(int n) { _total_ticks = n; }
|
||||
const char* options() { return _option_buf; }
|
||||
};
|
||||
|
||||
@ -561,20 +545,6 @@ void Disassembler::decode(nmethod* nm, outputStream* st) {
|
||||
#endif
|
||||
env.output()->print_cr(" [" PTR_FORMAT ", " PTR_FORMAT "] " JLONG_FORMAT " bytes", p2i(p), p2i(end), ((jlong)(end - p)));
|
||||
|
||||
// If there has been profiling, print the buckets.
|
||||
if (FlatProfiler::bucket_start_for(p) != NULL) {
|
||||
unsigned char* p1 = p;
|
||||
int total_bucket_count = 0;
|
||||
while (p1 < end) {
|
||||
unsigned char* p0 = p1;
|
||||
p1 += pd_instruction_alignment();
|
||||
address bucket_pc = FlatProfiler::bucket_start_for(p1);
|
||||
if (bucket_pc != NULL && bucket_pc > p0 && bucket_pc <= p1)
|
||||
total_bucket_count += FlatProfiler::bucket_count_for(p0);
|
||||
}
|
||||
env.set_total_ticks(total_bucket_count);
|
||||
}
|
||||
|
||||
// Print constant table.
|
||||
if (nm->consts_size() > 0) {
|
||||
nm->print_nmethod_labels(env.output(), nm->consts_begin());
|
||||
|
@ -1719,7 +1719,6 @@ jint G1CollectedHeap::initialize() {
|
||||
G1BlockOffsetTable::compute_size(g1_rs.size() / HeapWordSize),
|
||||
G1BlockOffsetTable::heap_map_factor());
|
||||
|
||||
ReservedSpace cardtable_rs(G1SATBCardTableLoggingModRefBS::compute_size(g1_rs.size() / HeapWordSize));
|
||||
G1RegionToSpaceMapper* cardtable_storage =
|
||||
create_aux_memory_mapper("Card Table",
|
||||
G1SATBCardTableLoggingModRefBS::compute_size(g1_rs.size() / HeapWordSize),
|
||||
|
@ -54,7 +54,6 @@ G1GCPhaseTimes::G1GCPhaseTimes(STWGCTimer* gc_timer, uint max_gc_threads) :
|
||||
_gc_par_phases[UniverseRoots] = new WorkerDataArray<double>(max_gc_threads, "Universe Roots (ms):");
|
||||
_gc_par_phases[JNIRoots] = new WorkerDataArray<double>(max_gc_threads, "JNI Handles Roots (ms):");
|
||||
_gc_par_phases[ObjectSynchronizerRoots] = new WorkerDataArray<double>(max_gc_threads, "ObjectSynchronizer Roots (ms):");
|
||||
_gc_par_phases[FlatProfilerRoots] = new WorkerDataArray<double>(max_gc_threads, "FlatProfiler Roots (ms):");
|
||||
_gc_par_phases[ManagementRoots] = new WorkerDataArray<double>(max_gc_threads, "Management Roots (ms):");
|
||||
_gc_par_phases[SystemDictionaryRoots] = new WorkerDataArray<double>(max_gc_threads, "SystemDictionary Roots (ms):");
|
||||
_gc_par_phases[CLDGRoots] = new WorkerDataArray<double>(max_gc_threads, "CLDG Roots (ms):");
|
||||
|
@ -49,7 +49,6 @@ class G1GCPhaseTimes : public CHeapObj<mtGC> {
|
||||
UniverseRoots,
|
||||
JNIRoots,
|
||||
ObjectSynchronizerRoots,
|
||||
FlatProfilerRoots,
|
||||
ManagementRoots,
|
||||
SystemDictionaryRoots,
|
||||
CLDGRoots,
|
||||
|
@ -62,7 +62,7 @@ public:
|
||||
oop obj = oopDesc::decode_heap_oop_not_null(heap_oop);
|
||||
if (_g1h->is_obj_dead_cond(obj, _vo)) {
|
||||
Log(gc, verify) log;
|
||||
log.info("Root location " PTR_FORMAT " points to dead obj " PTR_FORMAT, p2i(p), p2i(obj));
|
||||
log.error("Root location " PTR_FORMAT " points to dead obj " PTR_FORMAT, p2i(p), p2i(obj));
|
||||
if (_vo == VerifyOption_G1UseMarkWord) {
|
||||
log.error(" Mark word: " PTR_FORMAT, p2i(obj->mark()));
|
||||
}
|
||||
|
@ -48,7 +48,6 @@
|
||||
#include "prims/jvmtiExport.hpp"
|
||||
#include "runtime/atomic.hpp"
|
||||
#include "runtime/biasedLocking.hpp"
|
||||
#include "runtime/fprofiler.hpp"
|
||||
#include "runtime/synchronizer.hpp"
|
||||
#include "runtime/thread.hpp"
|
||||
#include "runtime/vmThread.hpp"
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, 2017, 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
|
||||
@ -38,7 +38,6 @@
|
||||
#include "gc/g1/g1RootProcessor.hpp"
|
||||
#include "gc/g1/heapRegion.inline.hpp"
|
||||
#include "memory/allocation.inline.hpp"
|
||||
#include "runtime/fprofiler.hpp"
|
||||
#include "runtime/mutex.hpp"
|
||||
#include "services/management.hpp"
|
||||
#include "utilities/macros.hpp"
|
||||
@ -271,13 +270,6 @@ void G1RootProcessor::process_vm_roots(G1RootClosures* closures,
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
G1GCParPhaseTimesTracker x(phase_times, G1GCPhaseTimes::FlatProfilerRoots, worker_i);
|
||||
if (!_process_strong_tasks.is_task_claimed(G1RP_PS_FlatProfiler_oops_do)) {
|
||||
FlatProfiler::oops_do(strong_roots);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
G1GCParPhaseTimesTracker x(phase_times, G1GCPhaseTimes::ManagementRoots, worker_i);
|
||||
if (!_process_strong_tasks.is_task_claimed(G1RP_PS_Management_oops_do)) {
|
||||
|
@ -57,7 +57,6 @@ class G1RootProcessor : public StackObj {
|
||||
G1RP_PS_Universe_oops_do,
|
||||
G1RP_PS_JNIHandles_oops_do,
|
||||
G1RP_PS_ObjectSynchronizer_oops_do,
|
||||
G1RP_PS_FlatProfiler_oops_do,
|
||||
G1RP_PS_Management_oops_do,
|
||||
G1RP_PS_SystemDictionary_oops_do,
|
||||
G1RP_PS_ClassLoaderDataGraph_oops_do,
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2005, 2017, 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
|
||||
@ -39,7 +39,6 @@
|
||||
#include "oops/objArrayKlass.inline.hpp"
|
||||
#include "oops/oop.inline.hpp"
|
||||
#include "prims/jvmtiExport.hpp"
|
||||
#include "runtime/fprofiler.hpp"
|
||||
#include "runtime/jniHandles.hpp"
|
||||
#include "runtime/thread.hpp"
|
||||
#include "runtime/vmThread.hpp"
|
||||
@ -105,10 +104,6 @@ void MarkFromRootsTask::do_it(GCTaskManager* manager, uint which) {
|
||||
ObjectSynchronizer::oops_do(&mark_and_push_closure);
|
||||
break;
|
||||
|
||||
case flat_profiler:
|
||||
FlatProfiler::oops_do(&mark_and_push_closure);
|
||||
break;
|
||||
|
||||
case management:
|
||||
Management::oops_do(&mark_and_push_closure);
|
||||
break;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2005, 2017, 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
|
||||
@ -94,12 +94,11 @@ class MarkFromRootsTask : public GCTask {
|
||||
jni_handles = 2,
|
||||
threads = 3,
|
||||
object_synchronizer = 4,
|
||||
flat_profiler = 5,
|
||||
management = 6,
|
||||
jvmti = 7,
|
||||
system_dictionary = 8,
|
||||
class_loader_data = 9,
|
||||
code_cache = 10
|
||||
management = 5,
|
||||
jvmti = 6,
|
||||
system_dictionary = 7,
|
||||
class_loader_data = 8,
|
||||
code_cache = 9
|
||||
};
|
||||
private:
|
||||
RootType _root_type;
|
||||
|
@ -50,7 +50,6 @@
|
||||
#include "logging/log.hpp"
|
||||
#include "oops/oop.inline.hpp"
|
||||
#include "runtime/biasedLocking.hpp"
|
||||
#include "runtime/fprofiler.hpp"
|
||||
#include "runtime/safepoint.hpp"
|
||||
#include "runtime/vmThread.hpp"
|
||||
#include "services/management.hpp"
|
||||
@ -514,7 +513,6 @@ void PSMarkSweep::mark_sweep_phase1(bool clear_all_softrefs) {
|
||||
MarkingCodeBlobClosure each_active_code_blob(mark_and_push_closure(), !CodeBlobToOopClosure::FixRelocations);
|
||||
Threads::oops_do(mark_and_push_closure(), &each_active_code_blob);
|
||||
ObjectSynchronizer::oops_do(mark_and_push_closure());
|
||||
FlatProfiler::oops_do(mark_and_push_closure());
|
||||
Management::oops_do(mark_and_push_closure());
|
||||
JvmtiExport::oops_do(mark_and_push_closure());
|
||||
SystemDictionary::always_strong_oops_do(mark_and_push_closure());
|
||||
@ -607,7 +605,6 @@ void PSMarkSweep::mark_sweep_phase3() {
|
||||
JNIHandles::oops_do(adjust_pointer_closure()); // Global (strong) JNI handles
|
||||
Threads::oops_do(adjust_pointer_closure(), NULL);
|
||||
ObjectSynchronizer::oops_do(adjust_pointer_closure());
|
||||
FlatProfiler::oops_do(adjust_pointer_closure());
|
||||
Management::oops_do(adjust_pointer_closure());
|
||||
JvmtiExport::oops_do(adjust_pointer_closure());
|
||||
SystemDictionary::oops_do(adjust_pointer_closure());
|
||||
|
@ -60,7 +60,6 @@
|
||||
#include "oops/objArrayKlass.inline.hpp"
|
||||
#include "oops/oop.inline.hpp"
|
||||
#include "runtime/atomic.hpp"
|
||||
#include "runtime/fprofiler.hpp"
|
||||
#include "runtime/safepoint.hpp"
|
||||
#include "runtime/vmThread.hpp"
|
||||
#include "services/management.hpp"
|
||||
@ -2086,7 +2085,6 @@ void PSParallelCompact::marking_phase(ParCompactionManager* cm,
|
||||
// We scan the thread roots in parallel
|
||||
Threads::create_thread_roots_marking_tasks(q);
|
||||
q->enqueue(new MarkFromRootsTask(MarkFromRootsTask::object_synchronizer));
|
||||
q->enqueue(new MarkFromRootsTask(MarkFromRootsTask::flat_profiler));
|
||||
q->enqueue(new MarkFromRootsTask(MarkFromRootsTask::management));
|
||||
q->enqueue(new MarkFromRootsTask(MarkFromRootsTask::system_dictionary));
|
||||
q->enqueue(new MarkFromRootsTask(MarkFromRootsTask::class_loader_data));
|
||||
@ -2169,7 +2167,6 @@ void PSParallelCompact::adjust_roots(ParCompactionManager* cm) {
|
||||
JNIHandles::oops_do(&oop_closure); // Global (strong) JNI handles
|
||||
Threads::oops_do(&oop_closure, NULL);
|
||||
ObjectSynchronizer::oops_do(&oop_closure);
|
||||
FlatProfiler::oops_do(&oop_closure);
|
||||
Management::oops_do(&oop_closure);
|
||||
JvmtiExport::oops_do(&oop_closure);
|
||||
SystemDictionary::oops_do(&oop_closure);
|
||||
|
@ -49,7 +49,6 @@
|
||||
#include "logging/log.hpp"
|
||||
#include "oops/oop.inline.hpp"
|
||||
#include "runtime/biasedLocking.hpp"
|
||||
#include "runtime/fprofiler.hpp"
|
||||
#include "runtime/handles.inline.hpp"
|
||||
#include "runtime/threadCritical.hpp"
|
||||
#include "runtime/vmThread.hpp"
|
||||
@ -381,7 +380,6 @@ bool PSScavenge::invoke_no_policy() {
|
||||
// We scan the thread roots in parallel
|
||||
Threads::create_thread_roots_tasks(q);
|
||||
q->enqueue(new ScavengeRootsTask(ScavengeRootsTask::object_synchronizer));
|
||||
q->enqueue(new ScavengeRootsTask(ScavengeRootsTask::flat_profiler));
|
||||
q->enqueue(new ScavengeRootsTask(ScavengeRootsTask::management));
|
||||
q->enqueue(new ScavengeRootsTask(ScavengeRootsTask::system_dictionary));
|
||||
q->enqueue(new ScavengeRootsTask(ScavengeRootsTask::class_loader_data));
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2002, 2017, 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
|
||||
@ -38,7 +38,6 @@
|
||||
#include "memory/resourceArea.hpp"
|
||||
#include "memory/universe.hpp"
|
||||
#include "oops/oop.inline.hpp"
|
||||
#include "runtime/fprofiler.hpp"
|
||||
#include "runtime/thread.hpp"
|
||||
#include "runtime/vmThread.hpp"
|
||||
#include "services/management.hpp"
|
||||
@ -74,10 +73,6 @@ void ScavengeRootsTask::do_it(GCTaskManager* manager, uint which) {
|
||||
ObjectSynchronizer::oops_do(&roots_closure);
|
||||
break;
|
||||
|
||||
case flat_profiler:
|
||||
FlatProfiler::oops_do(&roots_closure);
|
||||
break;
|
||||
|
||||
case system_dictionary:
|
||||
SystemDictionary::oops_do(&roots_closure);
|
||||
break;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2002, 2017, 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
|
||||
@ -57,12 +57,11 @@ class ScavengeRootsTask : public GCTask {
|
||||
jni_handles = 2,
|
||||
threads = 3,
|
||||
object_synchronizer = 4,
|
||||
flat_profiler = 5,
|
||||
system_dictionary = 6,
|
||||
class_loader_data = 7,
|
||||
management = 8,
|
||||
jvmti = 9,
|
||||
code_cache = 10
|
||||
system_dictionary = 5,
|
||||
class_loader_data = 6,
|
||||
management = 7,
|
||||
jvmti = 8,
|
||||
code_cache = 9
|
||||
};
|
||||
private:
|
||||
RootType _root_type;
|
||||
|
@ -46,7 +46,6 @@
|
||||
#include "oops/instanceRefKlass.hpp"
|
||||
#include "oops/oop.inline.hpp"
|
||||
#include "prims/jvmtiExport.hpp"
|
||||
#include "runtime/fprofiler.hpp"
|
||||
#include "runtime/handles.inline.hpp"
|
||||
#include "runtime/synchronizer.hpp"
|
||||
#include "runtime/thread.inline.hpp"
|
||||
|
@ -47,7 +47,6 @@
|
||||
#include "memory/resourceArea.hpp"
|
||||
#include "oops/oop.inline.hpp"
|
||||
#include "runtime/biasedLocking.hpp"
|
||||
#include "runtime/fprofiler.hpp"
|
||||
#include "runtime/handles.hpp"
|
||||
#include "runtime/handles.inline.hpp"
|
||||
#include "runtime/java.hpp"
|
||||
@ -71,7 +70,6 @@ enum GCH_strong_roots_tasks {
|
||||
GCH_PS_Universe_oops_do,
|
||||
GCH_PS_JNIHandles_oops_do,
|
||||
GCH_PS_ObjectSynchronizer_oops_do,
|
||||
GCH_PS_FlatProfiler_oops_do,
|
||||
GCH_PS_Management_oops_do,
|
||||
GCH_PS_SystemDictionary_oops_do,
|
||||
GCH_PS_ClassLoaderDataGraph_oops_do,
|
||||
@ -606,9 +604,6 @@ void GenCollectedHeap::process_roots(StrongRootsScope* scope,
|
||||
if (!_process_strong_tasks->is_task_claimed(GCH_PS_ObjectSynchronizer_oops_do)) {
|
||||
ObjectSynchronizer::oops_do(strong_roots);
|
||||
}
|
||||
if (!_process_strong_tasks->is_task_claimed(GCH_PS_FlatProfiler_oops_do)) {
|
||||
FlatProfiler::oops_do(strong_roots);
|
||||
}
|
||||
if (!_process_strong_tasks->is_task_claimed(GCH_PS_Management_oops_do)) {
|
||||
Management::oops_do(strong_roots);
|
||||
}
|
||||
|
@ -109,6 +109,11 @@ void Rewriter::make_constant_pool_cache(TRAPS) {
|
||||
MetadataFactory::free_metadata(loader_data, cache);
|
||||
_pool->set_cache(NULL); // so the verifier isn't confused
|
||||
}
|
||||
|
||||
DEBUG_ONLY(
|
||||
if (DumpSharedSpaces) {
|
||||
cache->verify_just_initialized();
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
|
@ -140,6 +140,7 @@
|
||||
LOG_TAG(timer) \
|
||||
LOG_TAG(update) \
|
||||
LOG_TAG(unload) /* Trace unloading of classes */ \
|
||||
LOG_TAG(unshareable) \
|
||||
LOG_TAG(verification) \
|
||||
LOG_TAG(verify) \
|
||||
LOG_TAG(vmoperation) \
|
||||
|
@ -275,7 +275,8 @@ private:
|
||||
address, bool,
|
||||
UniqueMetaspaceClosure::my_hash, // solaris compiler doesn't like: primitive_hash<address>
|
||||
UniqueMetaspaceClosure::my_equals, // solaris compiler doesn't like: primitive_equals<address>
|
||||
16384> _has_been_visited;
|
||||
15889, // prime number
|
||||
ResourceObj::C_HEAP> _has_been_visited;
|
||||
};
|
||||
|
||||
#endif // SHARE_VM_MEMORY_METASPACE_ITERATOR_HPP
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user