This commit is contained in:
Jesper Wilhelmsson 2016-12-08 15:49:29 +01:00
commit f09c55c0d8
223 changed files with 3109 additions and 1504 deletions

View File

@ -1,51 +0,0 @@
#
# Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 2 only, as
# published by the Free Software Foundation. Oracle designates this
# particular file as subject to the "Classpath" exception as provided
# by Oracle in the LICENSE file that accompanied this code.
#
# This code is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# version 2 for more details (a copy is included in the LICENSE file that
# accompanied this code).
#
# You should have received a copy of the GNU General Public License version
# 2 along with this work; if not, write to the Free Software Foundation,
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
# or visit www.oracle.com if you need additional information or have any
# questions.
#
# This must be the first rule
default: all
include $(SPEC)
include MakeBase.gmk
VARIANT_TARGETS := $(foreach v, $(JVM_VARIANTS), variant-$v)
VARIANT_GENSRC_TARGETS := $(addsuffix -gensrc, $(VARIANT_TARGETS))
VARIANT_LIBS_TARGETS := $(addsuffix -libs, $(VARIANT_TARGETS))
$(VARIANT_GENSRC_TARGETS): variant-%-gensrc:
$(call LogWarn, Building JVM variant '$*' with features '$(JVM_FEATURES_$*)')
+$(MAKE) -f gensrc/GenerateSources.gmk JVM_VARIANT=$*
$(VARIANT_LIBS_TARGETS): variant-%-libs: variant-%-gensrc
+$(MAKE) -f lib/CompileLibraries.gmk JVM_VARIANT=$*
$(VARIANT_TARGETS): variant-%: variant-%-gensrc variant-%-libs
jsig:
+$(MAKE) -f lib/CompileLibjsig.gmk
all: $(VARIANT_TARGETS) jsig
.PHONY: $(VARIANT_TARGETS) $(VARIANT_GENSRC_TARGETS) $(VARIANT_LIBS_TARGETS) \
jsig all

View File

@ -107,6 +107,7 @@ $(eval $(call SetupNativeCompilation, BUILD_GTEST_LAUNCHER, \
LDFLAGS := $(LDFLAGS_JDKEXE), \ LDFLAGS := $(LDFLAGS_JDKEXE), \
LDFLAGS_unix := -L$(JVM_OUTPUTDIR)/gtest $(call SET_SHARED_LIBRARY_ORIGIN), \ LDFLAGS_unix := -L$(JVM_OUTPUTDIR)/gtest $(call SET_SHARED_LIBRARY_ORIGIN), \
LDFLAGS_solaris := -library=stlport4, \ LDFLAGS_solaris := -library=stlport4, \
LIBS_linux := $(LIBCXX), \
LIBS_unix := -ljvm, \ LIBS_unix := -ljvm, \
LIBS_windows := $(JVM_OUTPUTDIR)/gtest/objs/jvm.lib, \ LIBS_windows := $(JVM_OUTPUTDIR)/gtest/objs/jvm.lib, \
COPY_DEBUG_SYMBOLS := $(GTEST_COPY_DEBUG_SYMBOLS), \ COPY_DEBUG_SYMBOLS := $(GTEST_COPY_DEBUG_SYMBOLS), \

View File

@ -48,6 +48,12 @@ ifneq ($(OPENJDK_TARGET_OS), windows)
LIBJSIG_CPU_FLAGS := -m64 LIBJSIG_CPU_FLAGS := -m64
else ifeq ($(OPENJDK_TARGET_CPU), x86) else ifeq ($(OPENJDK_TARGET_CPU), x86)
LIBJSIG_CPU_FLAGS := -m32 -march=i586 LIBJSIG_CPU_FLAGS := -m32 -march=i586
else ifeq ($(OPENJDK_TARGET_CPU), ppc64)
LIBJSIG_CPU_FLAGS := -mcpu=powerpc64 -mtune=power5
else ifeq ($(OPENJDK_TARGET_CPU), ppc64le)
LIBJSIG_CPU_FLAGS := -DABI_ELFv2 -mcpu=power8 -mtune=power8
else ifeq ($(OPENJDK_TARGET_CPU), s390x)
LIBJSIG_CPU_FLAGS := -mbackchain -march=z10
endif endif
else ifeq ($(OPENJDK_TARGET_OS), solaris) else ifeq ($(OPENJDK_TARGET_OS), solaris)

View File

@ -53,7 +53,6 @@ BUILD_HOTSPOT_JTREG_NATIVE_SRC := \
$(HOTSPOT_TOPDIR)/test/runtime/BoolReturn \ $(HOTSPOT_TOPDIR)/test/runtime/BoolReturn \
$(HOTSPOT_TOPDIR)/test/compiler/floatingpoint/ \ $(HOTSPOT_TOPDIR)/test/compiler/floatingpoint/ \
$(HOTSPOT_TOPDIR)/test/compiler/calls \ $(HOTSPOT_TOPDIR)/test/compiler/calls \
$(HOTSPOT_TOPDIR)/test/compiler/native \
$(HOTSPOT_TOPDIR)/test/serviceability/jvmti/GetNamedModule \ $(HOTSPOT_TOPDIR)/test/serviceability/jvmti/GetNamedModule \
$(HOTSPOT_TOPDIR)/test/serviceability/jvmti/AddModuleReads \ $(HOTSPOT_TOPDIR)/test/serviceability/jvmti/AddModuleReads \
$(HOTSPOT_TOPDIR)/test/serviceability/jvmti/AddModuleExportsAndOpens \ $(HOTSPOT_TOPDIR)/test/serviceability/jvmti/AddModuleExportsAndOpens \
@ -97,7 +96,7 @@ ifeq ($(OPENJDK_TARGET_OS), linux)
BUILD_HOTSPOT_JTREG_LIBRARIES_LDFLAGS_libtest-rwx := -z execstack BUILD_HOTSPOT_JTREG_LIBRARIES_LDFLAGS_libtest-rwx := -z execstack
BUILD_HOTSPOT_JTREG_EXECUTABLES_LIBS_exeinvoke := -ljvm -lpthread BUILD_HOTSPOT_JTREG_EXECUTABLES_LIBS_exeinvoke := -ljvm -lpthread
BUILD_TEST_invoke_exeinvoke.c_OPTIMIZATION := NONE BUILD_TEST_invoke_exeinvoke.c_OPTIMIZATION := NONE
BUILD_HOTSPOT_JTREG_EXECUTABLES_LDFLAGS_exeFPRegs := -ldl BUILD_HOTSPOT_JTREG_EXECUTABLES_LIBS_exeFPRegs := -ldl
endif endif
ifeq ($(OPENJDK_TARGET_OS), windows) ifeq ($(OPENJDK_TARGET_OS), windows)

View File

@ -9646,6 +9646,10 @@ instruct compareAndSwapNAcq(iRegINoSp res, indirect mem, iRegNNoSp oldval, iRegN
// --------------------------------------------------------------------- // ---------------------------------------------------------------------
// BEGIN This section of the file is automatically generated. Do not edit --------------
// Sundry CAS operations. Note that release is always true, // Sundry CAS operations. Note that release is always true,
// regardless of the memory ordering of the CAS. This is because we // regardless of the memory ordering of the CAS. This is because we
// need the volatile case to be sequentially consistent but there is // need the volatile case to be sequentially consistent but there is
@ -9656,10 +9660,11 @@ instruct compareAndSwapNAcq(iRegINoSp res, indirect mem, iRegNNoSp oldval, iRegN
// This section is generated from aarch64_ad_cas.m4 // This section is generated from aarch64_ad_cas.m4
instruct compareAndExchangeB(iRegI_R0 res, indirect mem, iRegI_R2 oldval, iRegI_R3 newval, rFlagsReg cr) %{
instruct compareAndExchangeB(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{
match(Set res (CompareAndExchangeB mem (Binary oldval newval))); match(Set res (CompareAndExchangeB mem (Binary oldval newval)));
ins_cost(2 * VOLATILE_REF_COST); ins_cost(2 * VOLATILE_REF_COST);
effect(KILL cr); effect(TEMP_DEF res, KILL cr);
format %{ format %{
"cmpxchg $res = $mem, $oldval, $newval\t# (byte, weak) if $mem == $oldval then $mem <-- $newval" "cmpxchg $res = $mem, $oldval, $newval\t# (byte, weak) if $mem == $oldval then $mem <-- $newval"
%} %}
@ -9673,10 +9678,10 @@ instruct compareAndExchangeB(iRegI_R0 res, indirect mem, iRegI_R2 oldval, iRegI_
ins_pipe(pipe_slow); ins_pipe(pipe_slow);
%} %}
instruct compareAndExchangeS(iRegI_R0 res, indirect mem, iRegI_R2 oldval, iRegI_R3 newval, rFlagsReg cr) %{ instruct compareAndExchangeS(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{
match(Set res (CompareAndExchangeS mem (Binary oldval newval))); match(Set res (CompareAndExchangeS mem (Binary oldval newval)));
ins_cost(2 * VOLATILE_REF_COST); ins_cost(2 * VOLATILE_REF_COST);
effect(KILL cr); effect(TEMP_DEF res, KILL cr);
format %{ format %{
"cmpxchg $res = $mem, $oldval, $newval\t# (short, weak) if $mem == $oldval then $mem <-- $newval" "cmpxchg $res = $mem, $oldval, $newval\t# (short, weak) if $mem == $oldval then $mem <-- $newval"
%} %}
@ -9690,10 +9695,10 @@ instruct compareAndExchangeS(iRegI_R0 res, indirect mem, iRegI_R2 oldval, iRegI_
ins_pipe(pipe_slow); ins_pipe(pipe_slow);
%} %}
instruct compareAndExchangeI(iRegI_R0 res, indirect mem, iRegI_R2 oldval, iRegI_R3 newval, rFlagsReg cr) %{ instruct compareAndExchangeI(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval, rFlagsReg cr) %{
match(Set res (CompareAndExchangeI mem (Binary oldval newval))); match(Set res (CompareAndExchangeI mem (Binary oldval newval)));
ins_cost(2 * VOLATILE_REF_COST); ins_cost(2 * VOLATILE_REF_COST);
effect(KILL cr); effect(TEMP_DEF res, KILL cr);
format %{ format %{
"cmpxchg $res = $mem, $oldval, $newval\t# (int, weak) if $mem == $oldval then $mem <-- $newval" "cmpxchg $res = $mem, $oldval, $newval\t# (int, weak) if $mem == $oldval then $mem <-- $newval"
%} %}
@ -9705,10 +9710,10 @@ instruct compareAndExchangeI(iRegI_R0 res, indirect mem, iRegI_R2 oldval, iRegI_
ins_pipe(pipe_slow); ins_pipe(pipe_slow);
%} %}
instruct compareAndExchangeL(iRegL_R0 res, indirect mem, iRegL_R2 oldval, iRegL_R3 newval, rFlagsReg cr) %{ instruct compareAndExchangeL(iRegLNoSp res, indirect mem, iRegL oldval, iRegL newval, rFlagsReg cr) %{
match(Set res (CompareAndExchangeL mem (Binary oldval newval))); match(Set res (CompareAndExchangeL mem (Binary oldval newval)));
ins_cost(2 * VOLATILE_REF_COST); ins_cost(2 * VOLATILE_REF_COST);
effect(KILL cr); effect(TEMP_DEF res, KILL cr);
format %{ format %{
"cmpxchg $res = $mem, $oldval, $newval\t# (long, weak) if $mem == $oldval then $mem <-- $newval" "cmpxchg $res = $mem, $oldval, $newval\t# (long, weak) if $mem == $oldval then $mem <-- $newval"
%} %}
@ -9720,10 +9725,10 @@ instruct compareAndExchangeL(iRegL_R0 res, indirect mem, iRegL_R2 oldval, iRegL_
ins_pipe(pipe_slow); ins_pipe(pipe_slow);
%} %}
instruct compareAndExchangeN(iRegN_R0 res, indirect mem, iRegN_R2 oldval, iRegN_R3 newval, rFlagsReg cr) %{ instruct compareAndExchangeN(iRegNNoSp res, indirect mem, iRegN oldval, iRegN newval, rFlagsReg cr) %{
match(Set res (CompareAndExchangeN mem (Binary oldval newval))); match(Set res (CompareAndExchangeN mem (Binary oldval newval)));
ins_cost(2 * VOLATILE_REF_COST); ins_cost(2 * VOLATILE_REF_COST);
effect(KILL cr); effect(TEMP_DEF res, KILL cr);
format %{ format %{
"cmpxchg $res = $mem, $oldval, $newval\t# (narrow oop, weak) if $mem == $oldval then $mem <-- $newval" "cmpxchg $res = $mem, $oldval, $newval\t# (narrow oop, weak) if $mem == $oldval then $mem <-- $newval"
%} %}
@ -9735,10 +9740,10 @@ instruct compareAndExchangeN(iRegN_R0 res, indirect mem, iRegN_R2 oldval, iRegN_
ins_pipe(pipe_slow); ins_pipe(pipe_slow);
%} %}
instruct compareAndExchangeP(iRegP_R0 res, indirect mem, iRegP_R2 oldval, iRegP_R3 newval, rFlagsReg cr) %{ instruct compareAndExchangeP(iRegPNoSp res, indirect mem, iRegP oldval, iRegP newval, rFlagsReg cr) %{
match(Set res (CompareAndExchangeP mem (Binary oldval newval))); match(Set res (CompareAndExchangeP mem (Binary oldval newval)));
ins_cost(2 * VOLATILE_REF_COST); ins_cost(2 * VOLATILE_REF_COST);
effect(KILL cr); effect(TEMP_DEF res, KILL cr);
format %{ format %{
"cmpxchg $res = $mem, $oldval, $newval\t# (ptr, weak) if $mem == $oldval then $mem <-- $newval" "cmpxchg $res = $mem, $oldval, $newval\t# (ptr, weak) if $mem == $oldval then $mem <-- $newval"
%} %}
@ -9853,6 +9858,8 @@ instruct weakCompareAndSwapP(iRegINoSp res, indirect mem, iRegP oldval, iRegP ne
%} %}
ins_pipe(pipe_slow); ins_pipe(pipe_slow);
%} %}
// END This section of the file is automatically generated. Do not edit --------------
// --------------------------------------------------------------------- // ---------------------------------------------------------------------
instruct get_and_setI(indirect mem, iRegINoSp newv, iRegI prev) %{ instruct get_and_setI(indirect mem, iRegINoSp newv, iRegI prev) %{

View File

@ -848,7 +848,7 @@ public:
// architecture. In debug mode we shrink it in order to test // architecture. In debug mode we shrink it in order to test
// trampolines, but not so small that branches in the interpreter // trampolines, but not so small that branches in the interpreter
// are out of range. // are out of range.
static const unsigned long branch_range = NOT_DEBUG(128 * M) DEBUG_ONLY(2 * M); static const unsigned long branch_range = INCLUDE_JVMCI ? 128 * M : NOT_DEBUG(128 * M) DEBUG_ONLY(2 * M);
static bool reachable_from_branch_at(address branch, address target) { static bool reachable_from_branch_at(address branch, address target) {
return uabs(target - branch) < branch_range; return uabs(target - branch) < branch_range;

View File

@ -2249,6 +2249,25 @@ void LIR_Assembler::emit_arraycopy(LIR_OpArrayCopy* op) {
__ cbz(dst, *stub->entry()); __ cbz(dst, *stub->entry());
} }
// If the compiler was not able to prove that exact type of the source or the destination
// of the arraycopy is an array type, check at runtime if the source or the destination is
// an instance type.
if (flags & LIR_OpArrayCopy::type_check) {
if (!(flags & LIR_OpArrayCopy::LIR_OpArrayCopy::dst_objarray)) {
__ load_klass(tmp, dst);
__ ldrw(rscratch1, Address(tmp, in_bytes(Klass::layout_helper_offset())));
__ cmpw(rscratch1, Klass::_lh_neutral_value);
__ br(Assembler::GE, *stub->entry());
}
if (!(flags & LIR_OpArrayCopy::LIR_OpArrayCopy::src_objarray)) {
__ load_klass(tmp, src);
__ ldrw(rscratch1, Address(tmp, in_bytes(Klass::layout_helper_offset())));
__ cmpw(rscratch1, Klass::_lh_neutral_value);
__ br(Assembler::GE, *stub->entry());
}
}
// check if negative // check if negative
if (flags & LIR_OpArrayCopy::src_pos_positive_check) { if (flags & LIR_OpArrayCopy::src_pos_positive_check) {
__ cmpw(src_pos, 0); __ cmpw(src_pos, 0);

View File

@ -1,3 +1,31 @@
dnl Copyright (c) 2016, Red Hat Inc. All rights reserved.
dnl DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
dnl
dnl This code is free software; you can redistribute it and/or modify it
dnl under the terms of the GNU General Public License version 2 only, as
dnl published by the Free Software Foundation.
dnl
dnl This code is distributed in the hope that it will be useful, but WITHOUT
dnl ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
dnl FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
dnl version 2 for more details (a copy is included in the LICENSE file that
dnl accompanied this code).
dnl
dnl You should have received a copy of the GNU General Public License version
dnl 2 along with this work; if not, write to the Free Software Foundation,
dnl Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
dnl
dnl Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
dnl or visit www.oracle.com if you need additional information or have any
dnl questions.
dnl
dnl
dnl Process this file with m4 cas.m4 to generate the CAE and wCAS
dnl instructions used in aarch64.ad.
dnl
// BEGIN This section of the file is automatically generated. Do not edit --------------
// Sundry CAS operations. Note that release is always true, // Sundry CAS operations. Note that release is always true,
// regardless of the memory ordering of the CAS. This is because we // regardless of the memory ordering of the CAS. This is because we
// need the volatile case to be sequentially consistent but there is // need the volatile case to be sequentially consistent but there is
@ -5,13 +33,16 @@
// can't check the type of memory ordering here, so we always emit a // can't check the type of memory ordering here, so we always emit a
// STLXR. // STLXR.
// This section is generated from aarch64_ad_cas.m4
define(`CAS_INSN', define(`CAS_INSN',
` `
instruct compareAndExchange$1$5(iReg$2_R0 res, indirect mem, iReg$2_R2 oldval, iReg$2_R3 newval, rFlagsReg cr) %{ instruct compareAndExchange$1$5(iReg$2NoSp res, indirect mem, iReg$2 oldval, iReg$2 newval, rFlagsReg cr) %{
match(Set res (CompareAndExchange$1 mem (Binary oldval newval))); match(Set res (CompareAndExchange$1 mem (Binary oldval newval)));
ifelse($5,Acq,' predicate(needs_acquiring_load_exclusive(n)); ifelse($5,Acq,' predicate(needs_acquiring_load_exclusive(n));
ins_cost(VOLATILE_REF_COST);`,' ins_cost(2 * VOLATILE_REF_COST);`) ins_cost(VOLATILE_REF_COST);`,' ins_cost(2 * VOLATILE_REF_COST);`)
effect(KILL cr); effect(TEMP_DEF res, KILL cr);
format %{ format %{
"cmpxchg $res = $mem, $oldval, $newval\t# ($3, weak) if $mem == $oldval then $mem <-- $newval" "cmpxchg $res = $mem, $oldval, $newval\t# ($3, weak) if $mem == $oldval then $mem <-- $newval"
%} %}
@ -24,11 +55,11 @@ instruct compareAndExchange$1$5(iReg$2_R0 res, indirect mem, iReg$2_R2 oldval, i
%}')dnl %}')dnl
define(`CAS_INSN4', define(`CAS_INSN4',
` `
instruct compareAndExchange$1$7(iReg$2_R0 res, indirect mem, iReg$2_R2 oldval, iReg$2_R3 newval, rFlagsReg cr) %{ instruct compareAndExchange$1$7(iReg$2NoSp res, indirect mem, iReg$2 oldval, iReg$2 newval, rFlagsReg cr) %{
match(Set res (CompareAndExchange$1 mem (Binary oldval newval))); match(Set res (CompareAndExchange$1 mem (Binary oldval newval)));
ifelse($7,Acq,' predicate(needs_acquiring_load_exclusive(n)); ifelse($7,Acq,' predicate(needs_acquiring_load_exclusive(n));
ins_cost(VOLATILE_REF_COST);`,' ins_cost(2 * VOLATILE_REF_COST);`) ins_cost(VOLATILE_REF_COST);`,' ins_cost(2 * VOLATILE_REF_COST);`)
effect(KILL cr); effect(TEMP_DEF res, KILL cr);
format %{ format %{
"cmpxchg $res = $mem, $oldval, $newval\t# ($3, weak) if $mem == $oldval then $mem <-- $newval" "cmpxchg $res = $mem, $oldval, $newval\t# ($3, weak) if $mem == $oldval then $mem <-- $newval"
%} %}
@ -107,3 +138,5 @@ dnl CAS_INSN3(L,L,long,xword,Acq)
dnl CAS_INSN3(N,N,narrow oop,word,Acq) dnl CAS_INSN3(N,N,narrow oop,word,Acq)
dnl CAS_INSN3(P,P,ptr,xword,Acq) dnl CAS_INSN3(P,P,ptr,xword,Acq)
dnl dnl
// END This section of the file is automatically generated. Do not edit --------------

View File

@ -407,10 +407,8 @@ void InterpreterMacroAssembler::jump_from_interpreted(Register method, Register
// JVMTI events, such as single-stepping, are implemented partly by avoiding running // JVMTI events, such as single-stepping, are implemented partly by avoiding running
// compiled code in threads for which the event is enabled. Check here for // compiled code in threads for which the event is enabled. Check here for
// interp_only_mode if these events CAN be enabled. // interp_only_mode if these events CAN be enabled.
// interp_only is an int, on little endian it is sufficient to test the byte only ldrw(rscratch1, Address(rthread, JavaThread::interp_only_mode_offset()));
// Is a cmpl faster? cbzw(rscratch1, run_compiled_code);
ldr(rscratch1, Address(rthread, JavaThread::interp_only_mode_offset()));
cbz(rscratch1, run_compiled_code);
ldr(rscratch1, Address(method, Method::interpreter_entry_offset())); ldr(rscratch1, Address(method, Method::interpreter_entry_offset()));
br(rscratch1); br(rscratch1);
bind(run_compiled_code); bind(run_compiled_code);

View File

@ -41,28 +41,34 @@ jint CodeInstaller::pd_next_offset(NativeInstruction* inst, jint pc_offset, Hand
void CodeInstaller::pd_patch_OopConstant(int pc_offset, Handle constant, TRAPS) { void CodeInstaller::pd_patch_OopConstant(int pc_offset, Handle constant, TRAPS) {
address pc = _instructions->start() + pc_offset; address pc = _instructions->start() + pc_offset;
#ifdef ASSERT
{
NativeInstruction *insn = nativeInstruction_at(pc);
if (HotSpotObjectConstantImpl::compressed(constant)) {
// Mov narrow constant: movz n << 16, movk
assert(Instruction_aarch64::extract(insn->encoding(), 31, 21) == 0b11010010101 &&
nativeInstruction_at(pc+4)->is_movk(), "wrong insn in patch");
} else {
// Move wide constant: movz n, movk, movk.
assert(nativeInstruction_at(pc+4)->is_movk()
&& nativeInstruction_at(pc+8)->is_movk(), "wrong insn in patch");
}
}
#endif // ASSERT
Handle obj = HotSpotObjectConstantImpl::object(constant); Handle obj = HotSpotObjectConstantImpl::object(constant);
jobject value = JNIHandles::make_local(obj()); jobject value = JNIHandles::make_local(obj());
if (HotSpotObjectConstantImpl::compressed(constant)) { MacroAssembler::patch_oop(pc, (address)obj());
int oop_index = _oop_recorder->find_index(value); int oop_index = _oop_recorder->find_index(value);
RelocationHolder rspec = oop_Relocation::spec(oop_index); RelocationHolder rspec = oop_Relocation::spec(oop_index);
_instructions->relocate(pc, rspec, 1); _instructions->relocate(pc, rspec);
Unimplemented();
} else {
NativeMovConstReg* move = nativeMovConstReg_at(pc);
move->set_data((intptr_t) value);
int oop_index = _oop_recorder->find_index(value);
RelocationHolder rspec = oop_Relocation::spec(oop_index);
_instructions->relocate(pc, rspec);
}
} }
void CodeInstaller::pd_patch_MetaspaceConstant(int pc_offset, Handle constant, TRAPS) { void CodeInstaller::pd_patch_MetaspaceConstant(int pc_offset, Handle constant, TRAPS) {
address pc = _instructions->start() + pc_offset; address pc = _instructions->start() + pc_offset;
if (HotSpotMetaspaceConstantImpl::compressed(constant)) { if (HotSpotMetaspaceConstantImpl::compressed(constant)) {
narrowKlass narrowOop = record_narrow_metadata_reference(_instructions, pc, constant, CHECK); narrowKlass narrowOop = record_narrow_metadata_reference(_instructions, pc, constant, CHECK);
MacroAssembler::patch_narrow_klass(pc, narrowOop);
TRACE_jvmci_3("relocating (narrow metaspace constant) at " PTR_FORMAT "/0x%x", p2i(pc), narrowOop); TRACE_jvmci_3("relocating (narrow metaspace constant) at " PTR_FORMAT "/0x%x", p2i(pc), narrowOop);
Unimplemented();
} else { } else {
NativeMovConstReg* move = nativeMovConstReg_at(pc); NativeMovConstReg* move = nativeMovConstReg_at(pc);
void* reference = record_metadata_reference(_instructions, pc, constant, CHECK); void* reference = record_metadata_reference(_instructions, pc, constant, CHECK);
@ -167,8 +173,8 @@ VMReg CodeInstaller::get_hotspot_reg(jint jvmci_reg, TRAPS) {
if (jvmci_reg < RegisterImpl::number_of_registers) { if (jvmci_reg < RegisterImpl::number_of_registers) {
return as_Register(jvmci_reg)->as_VMReg(); return as_Register(jvmci_reg)->as_VMReg();
} else { } else {
jint floatRegisterNumber = jvmci_reg - RegisterImpl::number_of_registers; jint floatRegisterNumber = jvmci_reg - RegisterImpl::number_of_registers_for_jvmci;
if (floatRegisterNumber < FloatRegisterImpl::number_of_registers) { if (floatRegisterNumber >= 0 && floatRegisterNumber < FloatRegisterImpl::number_of_registers) {
return as_FloatRegister(floatRegisterNumber)->as_VMReg(); return as_FloatRegister(floatRegisterNumber)->as_VMReg();
} }
JVMCI_ERROR_NULL("invalid register number: %d", jvmci_reg); JVMCI_ERROR_NULL("invalid register number: %d", jvmci_reg);

View File

@ -185,6 +185,19 @@ int MacroAssembler::patch_oop(address insn_addr, address o) {
return instructions * NativeInstruction::instruction_size; return instructions * NativeInstruction::instruction_size;
} }
int MacroAssembler::patch_narrow_klass(address insn_addr, narrowKlass n) {
// Metatdata pointers are either narrow (32 bits) or wide (48 bits).
// We encode narrow ones by setting the upper 16 bits in the first
// instruction.
NativeInstruction *insn = nativeInstruction_at(insn_addr);
assert(Instruction_aarch64::extract(insn->encoding(), 31, 21) == 0b11010010101 &&
nativeInstruction_at(insn_addr+4)->is_movk(), "wrong insns in patch");
Instruction_aarch64::patch(insn_addr, 20, 5, n >> 16);
Instruction_aarch64::patch(insn_addr+4, 20, 5, n & 0xffff);
return 2 * NativeInstruction::instruction_size;
}
address MacroAssembler::target_addr_for_insn(address insn_addr, unsigned insn) { address MacroAssembler::target_addr_for_insn(address insn_addr, unsigned insn) {
long offset = 0; long offset = 0;
if ((Instruction_aarch64::extract(insn, 29, 24) & 0b011011) == 0b00011000) { if ((Instruction_aarch64::extract(insn, 29, 24) & 0b011011) == 0b00011000) {

View File

@ -590,6 +590,7 @@ public:
#endif #endif
static int patch_oop(address insn_addr, address o); static int patch_oop(address insn_addr, address o);
static int patch_narrow_klass(address insn_addr, narrowKlass n);
address emit_trampoline_stub(int insts_call_instruction_offset, address target); address emit_trampoline_stub(int insts_call_instruction_offset, address target);

View File

@ -42,8 +42,9 @@ inline Register as_Register(int encoding) {
class RegisterImpl: public AbstractRegisterImpl { class RegisterImpl: public AbstractRegisterImpl {
public: public:
enum { enum {
number_of_registers = 32, number_of_registers = 32,
number_of_byte_registers = 32 number_of_byte_registers = 32,
number_of_registers_for_jvmci = 34 // Including SP and ZR.
}; };
// derived registers, offsets, and addresses // derived registers, offsets, and addresses
@ -103,6 +104,10 @@ CONSTANT_REGISTER_DECLARATION(Register, r28, (28));
CONSTANT_REGISTER_DECLARATION(Register, r29, (29)); CONSTANT_REGISTER_DECLARATION(Register, r29, (29));
CONSTANT_REGISTER_DECLARATION(Register, r30, (30)); CONSTANT_REGISTER_DECLARATION(Register, r30, (30));
// r31 is not a general purpose register, but represents either the
// stack pointer or the zero/discard register depending on the
// instruction.
CONSTANT_REGISTER_DECLARATION(Register, r31_sp, (31)); CONSTANT_REGISTER_DECLARATION(Register, r31_sp, (31));
CONSTANT_REGISTER_DECLARATION(Register, zr, (32)); CONSTANT_REGISTER_DECLARATION(Register, zr, (32));
CONSTANT_REGISTER_DECLARATION(Register, sp, (33)); CONSTANT_REGISTER_DECLARATION(Register, sp, (33));

View File

@ -2388,6 +2388,7 @@ void SharedRuntime::generate_deopt_blob() {
__ movw(rcpool, (int32_t)Deoptimization::Unpack_reexecute); __ movw(rcpool, (int32_t)Deoptimization::Unpack_reexecute);
__ mov(c_rarg0, rthread); __ mov(c_rarg0, rthread);
__ movw(c_rarg2, rcpool); // exec mode
__ lea(rscratch1, __ lea(rscratch1,
RuntimeAddress(CAST_FROM_FN_PTR(address, RuntimeAddress(CAST_FROM_FN_PTR(address,
Deoptimization::uncommon_trap))); Deoptimization::uncommon_trap)));

View File

@ -2743,7 +2743,7 @@ class StubGenerator: public StubCodeGenerator {
__ align(CodeEntryAlignment); __ align(CodeEntryAlignment);
StubCodeMark mark(this, "StubRoutines", "cipherBlockChaining_encryptAESCrypt"); StubCodeMark mark(this, "StubRoutines", "cipherBlockChaining_encryptAESCrypt");
Label L_loadkeys_44, L_loadkeys_52, L_aes_loop, L_rounds_44, L_rounds_52, _L_finish; Label L_loadkeys_44, L_loadkeys_52, L_aes_loop, L_rounds_44, L_rounds_52;
const Register from = c_rarg0; // source array address const Register from = c_rarg0; // source array address
const Register to = c_rarg1; // destination array address const Register to = c_rarg1; // destination array address
@ -2757,8 +2757,7 @@ class StubGenerator: public StubCodeGenerator {
__ enter(); __ enter();
__ subsw(rscratch2, len_reg, zr); __ movw(rscratch2, len_reg);
__ br(Assembler::LE, _L_finish);
__ ldrw(keylen, Address(key, arrayOopDesc::length_offset_in_bytes() - arrayOopDesc::base_offset_in_bytes(T_INT))); __ ldrw(keylen, Address(key, arrayOopDesc::length_offset_in_bytes() - arrayOopDesc::base_offset_in_bytes(T_INT)));
@ -2823,7 +2822,6 @@ class StubGenerator: public StubCodeGenerator {
__ st1(v0, __ T16B, rvec); __ st1(v0, __ T16B, rvec);
__ BIND(_L_finish);
__ mov(r0, rscratch2); __ mov(r0, rscratch2);
__ leave(); __ leave();
@ -2849,7 +2847,7 @@ class StubGenerator: public StubCodeGenerator {
__ align(CodeEntryAlignment); __ align(CodeEntryAlignment);
StubCodeMark mark(this, "StubRoutines", "cipherBlockChaining_decryptAESCrypt"); StubCodeMark mark(this, "StubRoutines", "cipherBlockChaining_decryptAESCrypt");
Label L_loadkeys_44, L_loadkeys_52, L_aes_loop, L_rounds_44, L_rounds_52, _L_finish; Label L_loadkeys_44, L_loadkeys_52, L_aes_loop, L_rounds_44, L_rounds_52;
const Register from = c_rarg0; // source array address const Register from = c_rarg0; // source array address
const Register to = c_rarg1; // destination array address const Register to = c_rarg1; // destination array address
@ -2863,8 +2861,7 @@ class StubGenerator: public StubCodeGenerator {
__ enter(); __ enter();
__ subsw(rscratch2, len_reg, zr); __ movw(rscratch2, len_reg);
__ br(Assembler::LE, _L_finish);
__ ldrw(keylen, Address(key, arrayOopDesc::length_offset_in_bytes() - arrayOopDesc::base_offset_in_bytes(T_INT))); __ ldrw(keylen, Address(key, arrayOopDesc::length_offset_in_bytes() - arrayOopDesc::base_offset_in_bytes(T_INT)));
@ -2933,7 +2930,6 @@ class StubGenerator: public StubCodeGenerator {
__ st1(v2, __ T16B, rvec); __ st1(v2, __ T16B, rvec);
__ BIND(_L_finish);
__ mov(r0, rscratch2); __ mov(r0, rscratch2);
__ leave(); __ leave();

View File

@ -203,6 +203,9 @@ address TemplateInterpreterGenerator::generate_math_entry(AbstractInterpreter::M
__ mov(sp, r13); __ mov(sp, r13);
generate_transcendental_entry(kind, 2); generate_transcendental_entry(kind, 2);
break; break;
case Interpreter::java_lang_math_fmaD :
case Interpreter::java_lang_math_fmaF :
return NULL;
default: default:
; ;
} }
@ -883,7 +886,7 @@ address TemplateInterpreterGenerator::generate_Reference_get_entry(void) {
// and so we don't need to call the G1 pre-barrier. Thus we can use the // and so we don't need to call the G1 pre-barrier. Thus we can use the
// regular method entry code to generate the NPE. // regular method entry code to generate the NPE.
// //
// This code is based on generate_accessor_enty. // This code is based on generate_accessor_entry.
// //
// rmethod: Method* // rmethod: Method*
// r13: senderSP must preserve for slow path, set SP to it on fast path // r13: senderSP must preserve for slow path, set SP to it on fast path
@ -901,11 +904,11 @@ address TemplateInterpreterGenerator::generate_Reference_get_entry(void) {
__ ldr(local_0, Address(esp, 0)); __ ldr(local_0, Address(esp, 0));
__ cbz(local_0, slow_path); __ cbz(local_0, slow_path);
// Load the value of the referent field. // Load the value of the referent field.
const Address field_address(local_0, referent_offset); const Address field_address(local_0, referent_offset);
__ load_heap_oop(local_0, field_address); __ load_heap_oop(local_0, field_address);
__ mov(r19, r13); // Move senderSP to a callee-saved register
// Generate the G1 pre-barrier code to log the value of // Generate the G1 pre-barrier code to log the value of
// the referent field in an SATB buffer. // the referent field in an SATB buffer.
__ enter(); // g1_write may call runtime __ enter(); // g1_write may call runtime
@ -917,7 +920,7 @@ address TemplateInterpreterGenerator::generate_Reference_get_entry(void) {
true /* expand_call */); true /* expand_call */);
__ leave(); __ leave();
// areturn // areturn
__ andr(sp, r13, -16); // done with stack __ andr(sp, r19, -16); // done with stack
__ ret(lr); __ ret(lr);
// generate a vanilla interpreter entry as the slow path // generate a vanilla interpreter entry as the slow path

View File

@ -9580,6 +9580,19 @@ instruct andI_reg_reg(iRegIdst dst, iRegIsrc src1, iRegIsrc src2) %{
ins_pipe(pipe_class_default); ins_pipe(pipe_class_default);
%} %}
// Left shifted Immediate And
instruct andI_reg_immIhi16(iRegIdst dst, iRegIsrc src1, immIhi16 src2, flagsRegCR0 cr0) %{
match(Set dst (AndI src1 src2));
effect(KILL cr0);
format %{ "ANDIS $dst, $src1, $src2.hi" %}
size(4);
ins_encode %{
// TODO: PPC port $archOpcode(ppc64Opcode_andis_);
__ andis_($dst$$Register, $src1$$Register, (int)((unsigned short)(($src2$$constant & 0xFFFF0000) >> 16)));
%}
ins_pipe(pipe_class_default);
%}
// Immediate And // Immediate And
instruct andI_reg_uimm16(iRegIdst dst, iRegIsrc src1, uimmI16 src2, flagsRegCR0 cr0) %{ instruct andI_reg_uimm16(iRegIdst dst, iRegIsrc src1, uimmI16 src2, flagsRegCR0 cr0) %{
match(Set dst (AndI src1 src2)); match(Set dst (AndI src1 src2));

View File

@ -1075,8 +1075,7 @@ void LIR_Assembler::reg2mem(LIR_Opr from, LIR_Opr dest_opr, BasicType type,
{ {
if (UseCompressedOops && !wide) { if (UseCompressedOops && !wide) {
Register compressed_src = Z_R14; Register compressed_src = Z_R14;
__ z_lgr(compressed_src, from->as_register()); __ oop_encoder(compressed_src, from->as_register(), true, (disp_reg != Z_R1) ? Z_R1 : Z_R0, -1, true);
__ encode_heap_oop(compressed_src);
offset = code_offset(); offset = code_offset();
if (short_disp) { if (short_disp) {
__ z_st(compressed_src, disp_value, disp_reg, dest); __ z_st(compressed_src, disp_value, disp_reg, dest);

View File

@ -156,7 +156,7 @@ void frame::patch_pc(Thread* thread, address pc) {
} }
own_abi()->return_pc = (uint64_t)pc; own_abi()->return_pc = (uint64_t)pc;
_cb = CodeCache::find_blob(pc); _cb = CodeCache::find_blob(pc);
address original_pc = nmethod::get_deopt_original_pc(this); address original_pc = CompiledMethod::get_deopt_original_pc(this);
if (original_pc != NULL) { if (original_pc != NULL) {
assert(original_pc == _pc, "expected original to be stored before patching"); assert(original_pc == _pc, "expected original to be stored before patching");
_deopt_state = is_deoptimized; _deopt_state = is_deoptimized;

View File

@ -39,7 +39,7 @@ inline void frame::find_codeblob_and_set_pc_and_deopt_state(address pc) {
_fp = (intptr_t *) own_abi()->callers_sp; _fp = (intptr_t *) own_abi()->callers_sp;
address original_pc = nmethod::get_deopt_original_pc(this); address original_pc = CompiledMethod::get_deopt_original_pc(this);
if (original_pc != NULL) { if (original_pc != NULL) {
_pc = original_pc; _pc = original_pc;
_deopt_state = is_deoptimized; _deopt_state = is_deoptimized;

View File

@ -92,9 +92,6 @@ define_pd_global(intx, InitArrayShortSize, 1*BytesPerLong);
product(bool, ReoptimizeCallSequences, true, \ product(bool, ReoptimizeCallSequences, true, \
"Reoptimize code-sequences of calls at runtime.") \ "Reoptimize code-sequences of calls at runtime.") \
\ \
product(bool, UseCountLeadingZerosInstruction, true, \
"Use count leading zeros instruction.") \
\
product(bool, UseByteReverseInstruction, true, \ product(bool, UseByteReverseInstruction, true, \
"Use byte reverse instruction.") \ "Use byte reverse instruction.") \
\ \

View File

@ -574,6 +574,7 @@ class MacroAssembler: public Assembler {
static int call_far_patchable_ret_addr_offset() { return call_far_patchable_size(); } static int call_far_patchable_ret_addr_offset() { return call_far_patchable_size(); }
static bool call_far_patchable_requires_alignment_nop(address pc) { static bool call_far_patchable_requires_alignment_nop(address pc) {
if (!os::is_MP()) return false;
int size = call_far_patchable_size(); int size = call_far_patchable_size();
return ((intptr_t)(pc + size) & 0x03L) != 0; return ((intptr_t)(pc + size) & 0x03L) != 0;
} }

View File

@ -256,11 +256,7 @@ void NativeFarCall::verify() {
address NativeFarCall::destination() { address NativeFarCall::destination() {
assert(MacroAssembler::is_call_far_patchable_at((address)this), "unexpected call type"); assert(MacroAssembler::is_call_far_patchable_at((address)this), "unexpected call type");
address ctable = NULL; address ctable = NULL;
if (MacroAssembler::call_far_patchable_requires_alignment_nop((address)this)) { return MacroAssembler::get_dest_of_call_far_patchable_at((address)this, ctable);
return MacroAssembler::get_dest_of_call_far_patchable_at(((address)this)+MacroAssembler::nop_size(), ctable);
} else {
return MacroAssembler::get_dest_of_call_far_patchable_at((address)this, ctable);
}
} }
@ -610,20 +606,20 @@ void NativeMovRegMem::verify() {
unsigned long inst1; unsigned long inst1;
Assembler::get_instruction(l2, &inst1); Assembler::get_instruction(l2, &inst1);
if (!Assembler::is_z_lb(inst1) && if (!Assembler::is_z_lb(inst1) &&
!Assembler::is_z_llgh(inst1) && !Assembler::is_z_llgh(inst1) &&
!Assembler::is_z_lh(inst1) && !Assembler::is_z_lh(inst1) &&
!Assembler::is_z_l(inst1) && !Assembler::is_z_l(inst1) &&
!Assembler::is_z_llgf(inst1) && !Assembler::is_z_llgf(inst1) &&
!Assembler::is_z_lg(inst1) && !Assembler::is_z_lg(inst1) &&
!Assembler::is_z_le(inst1) && !Assembler::is_z_le(inst1) &&
!Assembler::is_z_ld(inst1) && !Assembler::is_z_ld(inst1) &&
!Assembler::is_z_stc(inst1) && !Assembler::is_z_stc(inst1) &&
!Assembler::is_z_sth(inst1) && !Assembler::is_z_sth(inst1) &&
!Assembler::is_z_st(inst1) && !Assembler::is_z_st(inst1) &&
!(Assembler::is_z_lgr(inst1) && UseCompressedOops) && !UseCompressedOops &&
!Assembler::is_z_stg(inst1) && !Assembler::is_z_stg(inst1) &&
!Assembler::is_z_ste(inst1) && !Assembler::is_z_ste(inst1) &&
!Assembler::is_z_std(inst1)) { !Assembler::is_z_std(inst1)) {
tty->cr(); tty->cr();
tty->print_cr("NativeMovRegMem::verify(): verifying addr " PTR_FORMAT tty->print_cr("NativeMovRegMem::verify(): verifying addr " PTR_FORMAT

View File

@ -102,11 +102,8 @@ address Relocation::pd_call_destination(address orig_addr) {
if (orig_addr == NULL) { if (orig_addr == NULL) {
call = nativeFarCall_at(inst_addr); call = nativeFarCall_at(inst_addr);
} else { } else {
if (MacroAssembler::is_call_far_patchable_pcrelative_at(inst_addr)) { // must access location (in CP) where destination is stored in unmoved code, because load from CP is pc-relative
call = nativeFarCall_at(orig_addr); call = nativeFarCall_at(orig_addr);
} else {
call = nativeFarCall_at(orig_addr); // must access location (in CP) where destination is stored in unmoved code, because load from CP is pc-relative
}
} }
return call->destination(); return call->destination();
} }

View File

@ -1489,8 +1489,8 @@ const bool Matcher::match_rule_supported(int opcode) {
case Op_CountLeadingZerosL: case Op_CountLeadingZerosL:
case Op_CountTrailingZerosI: case Op_CountTrailingZerosI:
case Op_CountTrailingZerosL: case Op_CountTrailingZerosL:
// Implementation requires FLOGR instruction. // Implementation requires FLOGR instruction, which is available since z9.
return UseCountLeadingZerosInstruction; return true;
case Op_ReverseBytesI: case Op_ReverseBytesI:
case Op_ReverseBytesL: case Op_ReverseBytesL:
@ -9897,7 +9897,6 @@ instruct string_compareUL(iRegP str1, iRegP str2, rarg2RegI cnt1, rarg5RegI cnt2
// String IndexOfChar // String IndexOfChar
instruct indexOfChar_U(iRegP haystack, iRegI haycnt, iRegI ch, iRegI result, roddRegL oddReg, revenRegL evenReg, flagsReg cr) %{ instruct indexOfChar_U(iRegP haystack, iRegI haycnt, iRegI ch, iRegI result, roddRegL oddReg, revenRegL evenReg, flagsReg cr) %{
predicate(CompactStrings);
match(Set result (StrIndexOfChar (Binary haystack haycnt) ch)); match(Set result (StrIndexOfChar (Binary haystack haycnt) ch));
effect(TEMP_DEF result, TEMP evenReg, TEMP oddReg, KILL cr); // R0, R1 are killed, too. effect(TEMP_DEF result, TEMP evenReg, TEMP oddReg, KILL cr); // R0, R1 are killed, too.
ins_cost(200); ins_cost(200);
@ -10590,7 +10589,6 @@ instruct bytes_reverse_long(iRegL dst, iRegL src) %{
instruct countLeadingZerosI(revenRegI dst, iRegI src, roddRegI tmp, flagsReg cr) %{ instruct countLeadingZerosI(revenRegI dst, iRegI src, roddRegI tmp, flagsReg cr) %{
match(Set dst (CountLeadingZerosI src)); match(Set dst (CountLeadingZerosI src));
effect(KILL tmp, KILL cr); effect(KILL tmp, KILL cr);
predicate(UseCountLeadingZerosInstruction); // See Matcher::match_rule_supported
ins_cost(3 * DEFAULT_COST); ins_cost(3 * DEFAULT_COST);
size(14); size(14);
format %{ "SLLG $dst,$src,32\t# no need to always count 32 zeroes first\n\t" format %{ "SLLG $dst,$src,32\t# no need to always count 32 zeroes first\n\t"
@ -10629,7 +10627,6 @@ instruct countLeadingZerosI(revenRegI dst, iRegI src, roddRegI tmp, flagsReg cr)
instruct countLeadingZerosL(revenRegI dst, iRegL src, roddRegI tmp, flagsReg cr) %{ instruct countLeadingZerosL(revenRegI dst, iRegL src, roddRegI tmp, flagsReg cr) %{
match(Set dst (CountLeadingZerosL src)); match(Set dst (CountLeadingZerosL src));
effect(KILL tmp, KILL cr); effect(KILL tmp, KILL cr);
predicate(UseCountLeadingZerosInstruction); // See Matcher::match_rule_supported
ins_cost(DEFAULT_COST); ins_cost(DEFAULT_COST);
size(4); size(4);
format %{ "FLOGR $dst,$src \t# count leading zeros (long)\n\t" %} format %{ "FLOGR $dst,$src \t# count leading zeros (long)\n\t" %}
@ -10655,7 +10652,6 @@ instruct countLeadingZerosL(revenRegI dst, iRegL src, roddRegI tmp, flagsReg cr)
instruct countTrailingZerosI(revenRegI dst, iRegI src, roddRegI tmp, flagsReg cr) %{ instruct countTrailingZerosI(revenRegI dst, iRegI src, roddRegI tmp, flagsReg cr) %{
match(Set dst (CountTrailingZerosI src)); match(Set dst (CountTrailingZerosI src));
effect(TEMP_DEF dst, TEMP tmp, KILL cr); effect(TEMP_DEF dst, TEMP tmp, KILL cr);
predicate(UseCountLeadingZerosInstruction); // See Matcher::match_rule_supported
ins_cost(8 * DEFAULT_COST); ins_cost(8 * DEFAULT_COST);
// TODO: s390 port size(FIXED_SIZE); // Emitted code depends on PreferLAoverADD being on/off. // TODO: s390 port size(FIXED_SIZE); // Emitted code depends on PreferLAoverADD being on/off.
format %{ "LLGFR $dst,$src \t# clear upper 32 bits (we are dealing with int)\n\t" format %{ "LLGFR $dst,$src \t# clear upper 32 bits (we are dealing with int)\n\t"
@ -10709,7 +10705,6 @@ instruct countTrailingZerosI(revenRegI dst, iRegI src, roddRegI tmp, flagsReg cr
instruct countTrailingZerosL(revenRegI dst, iRegL src, roddRegL tmp, flagsReg cr) %{ instruct countTrailingZerosL(revenRegI dst, iRegL src, roddRegL tmp, flagsReg cr) %{
match(Set dst (CountTrailingZerosL src)); match(Set dst (CountTrailingZerosL src));
effect(TEMP_DEF dst, KILL tmp, KILL cr); effect(TEMP_DEF dst, KILL tmp, KILL cr);
predicate(UseCountLeadingZerosInstruction); // See Matcher::match_rule_supported
ins_cost(8 * DEFAULT_COST); ins_cost(8 * DEFAULT_COST);
// TODO: s390 port size(FIXED_SIZE); // Emitted code depends on PreferLAoverADD being on/off. // TODO: s390 port size(FIXED_SIZE); // Emitted code depends on PreferLAoverADD being on/off.
format %{ "LCGR $dst,$src \t# preserve src\n\t" format %{ "LCGR $dst,$src \t# preserve src\n\t"

View File

@ -3831,17 +3831,17 @@ void TemplateTable::newarray() {
// Call runtime. // Call runtime.
__ z_llgc(Z_ARG2, at_bcp(1)); // type __ z_llgc(Z_ARG2, at_bcp(1)); // type
// size in Z_tos __ z_lgfr(Z_ARG3, Z_tos); // size
call_VM(Z_RET, call_VM(Z_RET,
CAST_FROM_FN_PTR(address, InterpreterRuntime::newarray), CAST_FROM_FN_PTR(address, InterpreterRuntime::newarray),
Z_ARG2, Z_tos); Z_ARG2, Z_ARG3);
} }
void TemplateTable::anewarray() { void TemplateTable::anewarray() {
transition(itos, atos); transition(itos, atos);
__ get_2_byte_integer_at_bcp(Z_ARG3, 1, InterpreterMacroAssembler::Unsigned); __ get_2_byte_integer_at_bcp(Z_ARG3, 1, InterpreterMacroAssembler::Unsigned);
__ get_constant_pool(Z_ARG2); __ get_constant_pool(Z_ARG2);
__ z_llgfr(Z_ARG4, Z_tos); __ z_lgfr(Z_ARG4, Z_tos);
call_VM(Z_tos, CAST_FROM_FN_PTR(address, InterpreterRuntime::anewarray), call_VM(Z_tos, CAST_FROM_FN_PTR(address, InterpreterRuntime::anewarray),
Z_ARG2, Z_ARG3, Z_ARG4); Z_ARG2, Z_ARG3, Z_ARG4);
} }

View File

@ -271,6 +271,31 @@ void VM_Version::set_features_string() {
tty->print_cr(" oldest detected generation is %s", _features_string); tty->print_cr(" oldest detected generation is %s", _features_string);
_features_string = "z/Architecture (ambiguous detection)"; _features_string = "z/Architecture (ambiguous detection)";
} }
if (has_Crypto_AES()) {
char buf[256];
assert(strlen(_features_string) + 4 + 3*4 + 1 < sizeof(buf), "increase buffer size");
jio_snprintf(buf, sizeof(buf), "%s aes%s%s%s", // String 'aes' must be surrounded by spaces so that jtreg tests recognize it.
_features_string,
has_Crypto_AES128() ? " 128" : "",
has_Crypto_AES192() ? " 192" : "",
has_Crypto_AES256() ? " 256" : "");
_features_string = os::strdup(buf);
}
if (has_Crypto_SHA()) {
char buf[256];
assert(strlen(_features_string) + 4 + 2 + 2*4 + 6 + 1 < sizeof(buf), "increase buffer size");
// String 'sha1' etc must be surrounded by spaces so that jtreg tests recognize it.
jio_snprintf(buf, sizeof(buf), "%s %s%s%s%s",
_features_string,
has_Crypto_SHA1() ? " sha1" : "",
has_Crypto_SHA256() ? " sha256" : "",
has_Crypto_SHA512() ? " sha512" : "",
has_Crypto_GHASH() ? " ghash" : "");
if (has_Crypto_AES()) { os::free((void *)_features_string); }
_features_string = os::strdup(buf);
}
} }
// featureBuffer - bit array indicating availability of various features // featureBuffer - bit array indicating availability of various features
@ -369,7 +394,7 @@ void VM_Version::print_features_internal(const char* text, bool print_anyway) {
if (has_Crypto()) { if (has_Crypto()) {
tty->cr(); tty->cr();
tty->print_cr("detailled availability of %s capabilities:", "CryptoFacility"); tty->print_cr("detailed availability of %s capabilities:", "CryptoFacility");
if (test_feature_bit(&_cipher_features[0], -1, 2*Cipher::_featureBits)) { if (test_feature_bit(&_cipher_features[0], -1, 2*Cipher::_featureBits)) {
tty->cr(); tty->cr();
tty->print_cr(" available: %s", "Message Cipher Functions"); tty->print_cr(" available: %s", "Message Cipher Functions");
@ -479,7 +504,6 @@ void VM_Version::reset_features(bool reset) {
} }
} }
void VM_Version::set_features_z900(bool reset) { void VM_Version::set_features_z900(bool reset) {
reset_features(reset); reset_features(reset);

View File

@ -351,7 +351,7 @@ void VM_Version::initialize() {
FLAG_SET_DEFAULT(UseCRC32Intrinsics, true); FLAG_SET_DEFAULT(UseCRC32Intrinsics, true);
} }
} else if (UseCRC32Intrinsics) { } else if (UseCRC32Intrinsics) {
warning("SPARC CRC32 intrinsics require VIS3 insructions support. Intriniscs will be disabled"); warning("SPARC CRC32 intrinsics require VIS3 instructions support. Intrinsics will be disabled");
FLAG_SET_DEFAULT(UseCRC32Intrinsics, false); FLAG_SET_DEFAULT(UseCRC32Intrinsics, false);
} }

View File

@ -4285,8 +4285,7 @@ void Assembler::pblendw(XMMRegister dst, XMMRegister src, int imm8) {
void Assembler::sha1rnds4(XMMRegister dst, XMMRegister src, int imm8) { void Assembler::sha1rnds4(XMMRegister dst, XMMRegister src, int imm8) {
assert(VM_Version::supports_sha(), ""); assert(VM_Version::supports_sha(), "");
InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ false, /* uses_vl */ false); int encode = rex_prefix_and_encode(dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3A, /* rex_w */ false);
int encode = simd_prefix_and_encode(dst, xnoreg, src, VEX_SIMD_NONE, VEX_OPCODE_0F_3A, &attributes);
emit_int8((unsigned char)0xCC); emit_int8((unsigned char)0xCC);
emit_int8((unsigned char)(0xC0 | encode)); emit_int8((unsigned char)(0xC0 | encode));
emit_int8((unsigned char)imm8); emit_int8((unsigned char)imm8);
@ -4294,24 +4293,21 @@ void Assembler::sha1rnds4(XMMRegister dst, XMMRegister src, int imm8) {
void Assembler::sha1nexte(XMMRegister dst, XMMRegister src) { void Assembler::sha1nexte(XMMRegister dst, XMMRegister src) {
assert(VM_Version::supports_sha(), ""); assert(VM_Version::supports_sha(), "");
InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ false, /* uses_vl */ false); int encode = rex_prefix_and_encode(dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_38, /* rex_w */ false);
int encode = simd_prefix_and_encode(dst, xnoreg, src, VEX_SIMD_NONE, VEX_OPCODE_0F_38, &attributes);
emit_int8((unsigned char)0xC8); emit_int8((unsigned char)0xC8);
emit_int8((unsigned char)(0xC0 | encode)); emit_int8((unsigned char)(0xC0 | encode));
} }
void Assembler::sha1msg1(XMMRegister dst, XMMRegister src) { void Assembler::sha1msg1(XMMRegister dst, XMMRegister src) {
assert(VM_Version::supports_sha(), ""); assert(VM_Version::supports_sha(), "");
InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ false, /* uses_vl */ false); int encode = rex_prefix_and_encode(dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_38, /* rex_w */ false);
int encode = simd_prefix_and_encode(dst, xnoreg, src, VEX_SIMD_NONE, VEX_OPCODE_0F_38, &attributes);
emit_int8((unsigned char)0xC9); emit_int8((unsigned char)0xC9);
emit_int8((unsigned char)(0xC0 | encode)); emit_int8((unsigned char)(0xC0 | encode));
} }
void Assembler::sha1msg2(XMMRegister dst, XMMRegister src) { void Assembler::sha1msg2(XMMRegister dst, XMMRegister src) {
assert(VM_Version::supports_sha(), ""); assert(VM_Version::supports_sha(), "");
InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ false, /* uses_vl */ false); int encode = rex_prefix_and_encode(dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_38, /* rex_w */ false);
int encode = simd_prefix_and_encode(dst, xnoreg, src, VEX_SIMD_NONE, VEX_OPCODE_0F_38, &attributes);
emit_int8((unsigned char)0xCA); emit_int8((unsigned char)0xCA);
emit_int8((unsigned char)(0xC0 | encode)); emit_int8((unsigned char)(0xC0 | encode));
} }
@ -4319,24 +4315,21 @@ void Assembler::sha1msg2(XMMRegister dst, XMMRegister src) {
// xmm0 is implicit additional source to this instruction. // xmm0 is implicit additional source to this instruction.
void Assembler::sha256rnds2(XMMRegister dst, XMMRegister src) { void Assembler::sha256rnds2(XMMRegister dst, XMMRegister src) {
assert(VM_Version::supports_sha(), ""); assert(VM_Version::supports_sha(), "");
InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ false, /* uses_vl */ false); int encode = rex_prefix_and_encode(dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_38, /* rex_w */ false);
int encode = simd_prefix_and_encode(dst, xnoreg, src, VEX_SIMD_NONE, VEX_OPCODE_0F_38, &attributes);
emit_int8((unsigned char)0xCB); emit_int8((unsigned char)0xCB);
emit_int8((unsigned char)(0xC0 | encode)); emit_int8((unsigned char)(0xC0 | encode));
} }
void Assembler::sha256msg1(XMMRegister dst, XMMRegister src) { void Assembler::sha256msg1(XMMRegister dst, XMMRegister src) {
assert(VM_Version::supports_sha(), ""); assert(VM_Version::supports_sha(), "");
InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ false, /* uses_vl */ false); int encode = rex_prefix_and_encode(dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_38, /* rex_w */ false);
int encode = simd_prefix_and_encode(dst, xnoreg, src, VEX_SIMD_NONE, VEX_OPCODE_0F_38, &attributes);
emit_int8((unsigned char)0xCC); emit_int8((unsigned char)0xCC);
emit_int8((unsigned char)(0xC0 | encode)); emit_int8((unsigned char)(0xC0 | encode));
} }
void Assembler::sha256msg2(XMMRegister dst, XMMRegister src) { void Assembler::sha256msg2(XMMRegister dst, XMMRegister src) {
assert(VM_Version::supports_sha(), ""); assert(VM_Version::supports_sha(), "");
InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ false, /* uses_vl */ false); int encode = rex_prefix_and_encode(dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_38, /* rex_w */ false);
int encode = simd_prefix_and_encode(dst, xnoreg, src, VEX_SIMD_NONE, VEX_OPCODE_0F_38, &attributes);
emit_int8((unsigned char)0xCD); emit_int8((unsigned char)0xCD);
emit_int8((unsigned char)(0xC0 | encode)); emit_int8((unsigned char)(0xC0 | encode));
} }

View File

@ -10773,16 +10773,13 @@ void MacroAssembler::char_array_compress(Register src, Register dst, Register le
// save length for return // save length for return
push(len); push(len);
// 8165287: EVEX version disabled for now, needs to be refactored as
// it is returning incorrect results.
if ((UseAVX > 2) && // AVX512 if ((UseAVX > 2) && // AVX512
0 &&
VM_Version::supports_avx512vlbw() && VM_Version::supports_avx512vlbw() &&
VM_Version::supports_bmi2()) { VM_Version::supports_bmi2()) {
set_vector_masking(); // opening of the stub context for programming mask registers set_vector_masking(); // opening of the stub context for programming mask registers
Label copy_32_loop, copy_loop_tail, copy_just_portion_of_candidates; Label copy_32_loop, copy_loop_tail, restore_k1_return_zero;
// alignement // alignement
Label post_alignement; Label post_alignement;
@ -10797,16 +10794,16 @@ void MacroAssembler::char_array_compress(Register src, Register dst, Register le
movl(result, 0x00FF); movl(result, 0x00FF);
evpbroadcastw(tmp2Reg, result, Assembler::AVX_512bit); evpbroadcastw(tmp2Reg, result, Assembler::AVX_512bit);
testl(len, -64);
jcc(Assembler::zero, post_alignement);
// Save k1 // Save k1
kmovql(k3, k1); kmovql(k3, k1);
testl(len, -64);
jcc(Assembler::zero, post_alignement);
movl(tmp5, dst); movl(tmp5, dst);
andl(tmp5, (64 - 1)); andl(tmp5, (32 - 1));
negl(tmp5); negl(tmp5);
andl(tmp5, (64 - 1)); andl(tmp5, (32 - 1));
// bail out when there is nothing to be done // bail out when there is nothing to be done
testl(tmp5, 0xFFFFFFFF); testl(tmp5, 0xFFFFFFFF);
@ -10816,13 +10813,12 @@ void MacroAssembler::char_array_compress(Register src, Register dst, Register le
movl(result, 0xFFFFFFFF); movl(result, 0xFFFFFFFF);
shlxl(result, result, tmp5); shlxl(result, result, tmp5);
notl(result); notl(result);
kmovdl(k1, result); kmovdl(k1, result);
evmovdquw(tmp1Reg, k1, Address(src, 0), Assembler::AVX_512bit); evmovdquw(tmp1Reg, k1, Address(src, 0), Assembler::AVX_512bit);
evpcmpuw(k2, k1, tmp1Reg, tmp2Reg, Assembler::le, Assembler::AVX_512bit); evpcmpuw(k2, k1, tmp1Reg, tmp2Reg, Assembler::le, Assembler::AVX_512bit);
ktestd(k2, k1); ktestd(k2, k1);
jcc(Assembler::carryClear, copy_just_portion_of_candidates); jcc(Assembler::carryClear, restore_k1_return_zero);
evpmovwb(Address(dst, 0), k1, tmp1Reg, Assembler::AVX_512bit); evpmovwb(Address(dst, 0), k1, tmp1Reg, Assembler::AVX_512bit);
@ -10835,7 +10831,7 @@ void MacroAssembler::char_array_compress(Register src, Register dst, Register le
// end of alignement // end of alignement
movl(tmp5, len); movl(tmp5, len);
andl(tmp5, (32 - 1)); // tail count (in chars) andl(tmp5, (32 - 1)); // tail count (in chars)
andl(len, ~(32 - 1)); // vector count (in chars) andl(len, ~(32 - 1)); // vector count (in chars)
jcc(Assembler::zero, copy_loop_tail); jcc(Assembler::zero, copy_loop_tail);
@ -10847,7 +10843,7 @@ void MacroAssembler::char_array_compress(Register src, Register dst, Register le
evmovdquw(tmp1Reg, Address(src, len, Address::times_2), Assembler::AVX_512bit); evmovdquw(tmp1Reg, Address(src, len, Address::times_2), Assembler::AVX_512bit);
evpcmpuw(k2, tmp1Reg, tmp2Reg, Assembler::le, Assembler::AVX_512bit); evpcmpuw(k2, tmp1Reg, tmp2Reg, Assembler::le, Assembler::AVX_512bit);
kortestdl(k2, k2); kortestdl(k2, k2);
jcc(Assembler::carryClear, copy_just_portion_of_candidates); jcc(Assembler::carryClear, restore_k1_return_zero);
// All elements in current processed chunk are valid candidates for // All elements in current processed chunk are valid candidates for
// compression. Write a truncated byte elements to the memory. // compression. Write a truncated byte elements to the memory.
@ -10858,11 +10854,10 @@ void MacroAssembler::char_array_compress(Register src, Register dst, Register le
bind(copy_loop_tail); bind(copy_loop_tail);
// bail out when there is nothing to be done // bail out when there is nothing to be done
testl(tmp5, 0xFFFFFFFF); testl(tmp5, 0xFFFFFFFF);
// Restore k1
kmovql(k1, k3);
jcc(Assembler::zero, return_length); jcc(Assembler::zero, return_length);
// Save k1
kmovql(k3, k1);
movl(len, tmp5); movl(len, tmp5);
// ~(~0 << len), where len is the # of remaining elements to process // ~(~0 << len), where len is the # of remaining elements to process
@ -10875,30 +10870,16 @@ void MacroAssembler::char_array_compress(Register src, Register dst, Register le
evmovdquw(tmp1Reg, k1, Address(src, 0), Assembler::AVX_512bit); evmovdquw(tmp1Reg, k1, Address(src, 0), Assembler::AVX_512bit);
evpcmpuw(k2, k1, tmp1Reg, tmp2Reg, Assembler::le, Assembler::AVX_512bit); evpcmpuw(k2, k1, tmp1Reg, tmp2Reg, Assembler::le, Assembler::AVX_512bit);
ktestd(k2, k1); ktestd(k2, k1);
jcc(Assembler::carryClear, copy_just_portion_of_candidates); jcc(Assembler::carryClear, restore_k1_return_zero);
evpmovwb(Address(dst, 0), k1, tmp1Reg, Assembler::AVX_512bit); evpmovwb(Address(dst, 0), k1, tmp1Reg, Assembler::AVX_512bit);
// Restore k1 // Restore k1
kmovql(k1, k3); kmovql(k1, k3);
jmp(return_length); jmp(return_length);
bind(copy_just_portion_of_candidates); bind(restore_k1_return_zero);
kmovdl(tmp5, k2);
tzcntl(tmp5, tmp5);
// ~(~0 << tmp5), where tmp5 is a number of elements in an array from the
// result to the first element larger than 0xFF
movl(result, 0xFFFFFFFF);
shlxl(result, result, tmp5);
notl(result);
kmovdl(k1, result);
evpmovwb(Address(dst, 0), k1, tmp1Reg, Assembler::AVX_512bit);
// Restore k1 // Restore k1
kmovql(k1, k3); kmovql(k1, k3);
jmp(return_zero); jmp(return_zero);
clear_vector_masking(); // closing of the stub context for programming mask registers clear_vector_masking(); // closing of the stub context for programming mask registers

View File

@ -3857,7 +3857,7 @@ class StubGenerator: public StubCodeGenerator {
StubRoutines::_crc32c_table_addr = (address)StubRoutines::x86::_crc32c_table; StubRoutines::_crc32c_table_addr = (address)StubRoutines::x86::_crc32c_table;
StubRoutines::_updateBytesCRC32C = generate_updateBytesCRC32C(supports_clmul); StubRoutines::_updateBytesCRC32C = generate_updateBytesCRC32C(supports_clmul);
} }
if (VM_Version::supports_sse2() && UseLibmIntrinsic) { if (VM_Version::supports_sse2() && UseLibmIntrinsic && InlineIntrinsics) {
if (vmIntrinsics::is_intrinsic_available(vmIntrinsics::_dsin) || if (vmIntrinsics::is_intrinsic_available(vmIntrinsics::_dsin) ||
vmIntrinsics::is_intrinsic_available(vmIntrinsics::_dcos) || vmIntrinsics::is_intrinsic_available(vmIntrinsics::_dcos) ||
vmIntrinsics::is_intrinsic_available(vmIntrinsics::_dtan)) { vmIntrinsics::is_intrinsic_available(vmIntrinsics::_dtan)) {

View File

@ -5017,7 +5017,7 @@ class StubGenerator: public StubCodeGenerator {
StubRoutines::_crc32c_table_addr = (address)StubRoutines::x86::_crc32c_table; StubRoutines::_crc32c_table_addr = (address)StubRoutines::x86::_crc32c_table;
StubRoutines::_updateBytesCRC32C = generate_updateBytesCRC32C(supports_clmul); StubRoutines::_updateBytesCRC32C = generate_updateBytesCRC32C(supports_clmul);
} }
if (VM_Version::supports_sse2() && UseLibmIntrinsic) { if (VM_Version::supports_sse2() && UseLibmIntrinsic && InlineIntrinsics) {
if (vmIntrinsics::is_intrinsic_available(vmIntrinsics::_dsin) || if (vmIntrinsics::is_intrinsic_available(vmIntrinsics::_dsin) ||
vmIntrinsics::is_intrinsic_available(vmIntrinsics::_dcos) || vmIntrinsics::is_intrinsic_available(vmIntrinsics::_dcos) ||
vmIntrinsics::is_intrinsic_available(vmIntrinsics::_dtan)) { vmIntrinsics::is_intrinsic_available(vmIntrinsics::_dtan)) {

View File

@ -342,6 +342,9 @@ address TemplateInterpreterGenerator::generate_math_entry(AbstractInterpreter::M
// [ hi(arg) ] // [ hi(arg) ]
// //
if (kind == Interpreter::java_lang_math_fmaD) { if (kind == Interpreter::java_lang_math_fmaD) {
if (!UseFMA) {
return NULL; // Generate a vanilla entry
}
__ movdbl(xmm2, Address(rsp, 5 * wordSize)); __ movdbl(xmm2, Address(rsp, 5 * wordSize));
__ movdbl(xmm1, Address(rsp, 3 * wordSize)); __ movdbl(xmm1, Address(rsp, 3 * wordSize));
__ movdbl(xmm0, Address(rsp, 1 * wordSize)); __ movdbl(xmm0, Address(rsp, 1 * wordSize));
@ -352,6 +355,9 @@ address TemplateInterpreterGenerator::generate_math_entry(AbstractInterpreter::M
return entry_point; return entry_point;
} else if (kind == Interpreter::java_lang_math_fmaF) { } else if (kind == Interpreter::java_lang_math_fmaF) {
if (!UseFMA) {
return NULL; // Generate a vanilla entry
}
__ movflt(xmm2, Address(rsp, 3 * wordSize)); __ movflt(xmm2, Address(rsp, 3 * wordSize));
__ movflt(xmm1, Address(rsp, 2 * wordSize)); __ movflt(xmm1, Address(rsp, 2 * wordSize));
__ movflt(xmm0, Address(rsp, 1 * wordSize)); __ movflt(xmm0, Address(rsp, 1 * wordSize));

View File

@ -370,11 +370,17 @@ address TemplateInterpreterGenerator::generate_math_entry(AbstractInterpreter::M
// //
if (kind == Interpreter::java_lang_math_fmaD) { if (kind == Interpreter::java_lang_math_fmaD) {
if (!UseFMA) {
return NULL; // Generate a vanilla entry
}
__ movdbl(xmm0, Address(rsp, wordSize)); __ movdbl(xmm0, Address(rsp, wordSize));
__ movdbl(xmm1, Address(rsp, 3 * wordSize)); __ movdbl(xmm1, Address(rsp, 3 * wordSize));
__ movdbl(xmm2, Address(rsp, 5 * wordSize)); __ movdbl(xmm2, Address(rsp, 5 * wordSize));
__ fmad(xmm0, xmm1, xmm2, xmm0); __ fmad(xmm0, xmm1, xmm2, xmm0);
} else if (kind == Interpreter::java_lang_math_fmaF) { } else if (kind == Interpreter::java_lang_math_fmaF) {
if (!UseFMA) {
return NULL; // Generate a vanilla entry
}
__ movflt(xmm0, Address(rsp, wordSize)); __ movflt(xmm0, Address(rsp, wordSize));
__ movflt(xmm1, Address(rsp, 2 * wordSize)); __ movflt(xmm1, Address(rsp, 2 * wordSize));
__ movflt(xmm2, Address(rsp, 3 * wordSize)); __ movflt(xmm2, Address(rsp, 3 * wordSize));

View File

@ -65,6 +65,7 @@ class VM_Version_StubGenerator: public StubCodeGenerator {
const int CPU_FAMILY_SHIFT = 8; const int CPU_FAMILY_SHIFT = 8;
const uint32_t CPU_FAMILY_386 = (3 << CPU_FAMILY_SHIFT); const uint32_t CPU_FAMILY_386 = (3 << CPU_FAMILY_SHIFT);
const uint32_t CPU_FAMILY_486 = (4 << CPU_FAMILY_SHIFT); const uint32_t CPU_FAMILY_486 = (4 << CPU_FAMILY_SHIFT);
bool use_evex = FLAG_IS_DEFAULT(UseAVX) || (UseAVX > 2);
Label detect_486, cpu486, detect_586, std_cpuid1, std_cpuid4; Label detect_486, cpu486, detect_586, std_cpuid1, std_cpuid4;
Label sef_cpuid, ext_cpuid, ext_cpuid1, ext_cpuid5, ext_cpuid7, done, wrapup; Label sef_cpuid, ext_cpuid, ext_cpuid1, ext_cpuid5, ext_cpuid7, done, wrapup;
@ -358,36 +359,39 @@ class VM_Version_StubGenerator: public StubCodeGenerator {
__ cmpl(rax, 0xE0); __ cmpl(rax, 0xE0);
__ jccb(Assembler::notEqual, legacy_setup); // jump if EVEX is not supported __ jccb(Assembler::notEqual, legacy_setup); // jump if EVEX is not supported
// EVEX setup: run in lowest evex mode // If UseAVX is unitialized or is set by the user to include EVEX
VM_Version::set_evex_cpuFeatures(); // Enable temporary to pass asserts if (use_evex) {
UseAVX = 3; // EVEX setup: run in lowest evex mode
UseSSE = 2; VM_Version::set_evex_cpuFeatures(); // Enable temporary to pass asserts
UseAVX = 3;
UseSSE = 2;
#ifdef _WINDOWS #ifdef _WINDOWS
// xmm5-xmm15 are not preserved by caller on windows // xmm5-xmm15 are not preserved by caller on windows
// https://msdn.microsoft.com/en-us/library/9z1stfyw.aspx // https://msdn.microsoft.com/en-us/library/9z1stfyw.aspx
__ subptr(rsp, 64); __ subptr(rsp, 64);
__ evmovdqul(Address(rsp, 0), xmm7, Assembler::AVX_512bit); __ evmovdqul(Address(rsp, 0), xmm7, Assembler::AVX_512bit);
#ifdef _LP64 #ifdef _LP64
__ subptr(rsp, 64); __ subptr(rsp, 64);
__ evmovdqul(Address(rsp, 0), xmm8, Assembler::AVX_512bit); __ evmovdqul(Address(rsp, 0), xmm8, Assembler::AVX_512bit);
__ subptr(rsp, 64); __ subptr(rsp, 64);
__ evmovdqul(Address(rsp, 0), xmm31, Assembler::AVX_512bit); __ evmovdqul(Address(rsp, 0), xmm31, Assembler::AVX_512bit);
#endif // _LP64 #endif // _LP64
#endif // _WINDOWS #endif // _WINDOWS
// load value into all 64 bytes of zmm7 register // load value into all 64 bytes of zmm7 register
__ movl(rcx, VM_Version::ymm_test_value()); __ movl(rcx, VM_Version::ymm_test_value());
__ movdl(xmm0, rcx); __ movdl(xmm0, rcx);
__ movl(rcx, 0xffff); __ movl(rcx, 0xffff);
__ kmovwl(k1, rcx); __ kmovwl(k1, rcx);
__ evpbroadcastd(xmm0, xmm0, Assembler::AVX_512bit); __ evpbroadcastd(xmm0, xmm0, Assembler::AVX_512bit);
__ evmovdqul(xmm7, xmm0, Assembler::AVX_512bit); __ evmovdqul(xmm7, xmm0, Assembler::AVX_512bit);
#ifdef _LP64 #ifdef _LP64
__ evmovdqul(xmm8, xmm0, Assembler::AVX_512bit); __ evmovdqul(xmm8, xmm0, Assembler::AVX_512bit);
__ evmovdqul(xmm31, xmm0, Assembler::AVX_512bit); __ evmovdqul(xmm31, xmm0, Assembler::AVX_512bit);
#endif #endif
VM_Version::clean_cpuFeatures(); VM_Version::clean_cpuFeatures();
__ jmp(save_restore_except); __ jmp(save_restore_except);
}
__ bind(legacy_setup); __ bind(legacy_setup);
// AVX setup // AVX setup
@ -441,32 +445,35 @@ class VM_Version_StubGenerator: public StubCodeGenerator {
__ cmpl(rax, 0xE0); __ cmpl(rax, 0xE0);
__ jccb(Assembler::notEqual, legacy_save_restore); __ jccb(Assembler::notEqual, legacy_save_restore);
// EVEX check: run in lowest evex mode // If UseAVX is unitialized or is set by the user to include EVEX
VM_Version::set_evex_cpuFeatures(); // Enable temporary to pass asserts if (use_evex) {
UseAVX = 3; // EVEX check: run in lowest evex mode
UseSSE = 2; VM_Version::set_evex_cpuFeatures(); // Enable temporary to pass asserts
__ lea(rsi, Address(rbp, in_bytes(VM_Version::zmm_save_offset()))); UseAVX = 3;
__ evmovdqul(Address(rsi, 0), xmm0, Assembler::AVX_512bit); UseSSE = 2;
__ evmovdqul(Address(rsi, 64), xmm7, Assembler::AVX_512bit); __ lea(rsi, Address(rbp, in_bytes(VM_Version::zmm_save_offset())));
__ evmovdqul(Address(rsi, 0), xmm0, Assembler::AVX_512bit);
__ evmovdqul(Address(rsi, 64), xmm7, Assembler::AVX_512bit);
#ifdef _LP64 #ifdef _LP64
__ evmovdqul(Address(rsi, 128), xmm8, Assembler::AVX_512bit); __ evmovdqul(Address(rsi, 128), xmm8, Assembler::AVX_512bit);
__ evmovdqul(Address(rsi, 192), xmm31, Assembler::AVX_512bit); __ evmovdqul(Address(rsi, 192), xmm31, Assembler::AVX_512bit);
#endif #endif
#ifdef _WINDOWS #ifdef _WINDOWS
#ifdef _LP64 #ifdef _LP64
__ evmovdqul(xmm31, Address(rsp, 0), Assembler::AVX_512bit); __ evmovdqul(xmm31, Address(rsp, 0), Assembler::AVX_512bit);
__ addptr(rsp, 64); __ addptr(rsp, 64);
__ evmovdqul(xmm8, Address(rsp, 0), Assembler::AVX_512bit); __ evmovdqul(xmm8, Address(rsp, 0), Assembler::AVX_512bit);
__ addptr(rsp, 64); __ addptr(rsp, 64);
#endif // _LP64 #endif // _LP64
__ evmovdqul(xmm7, Address(rsp, 0), Assembler::AVX_512bit); __ evmovdqul(xmm7, Address(rsp, 0), Assembler::AVX_512bit);
__ addptr(rsp, 64); __ addptr(rsp, 64);
#endif // _WINDOWS #endif // _WINDOWS
VM_Version::clean_cpuFeatures(); VM_Version::clean_cpuFeatures();
UseAVX = saved_useavx; UseAVX = saved_useavx;
UseSSE = saved_usesse; UseSSE = saved_usesse;
__ jmp(wrapup); __ jmp(wrapup);
}
__ bind(legacy_save_restore); __ bind(legacy_save_restore);
// AVX check // AVX check

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -697,14 +697,8 @@ err:
} }
/**local function **/ /**local function **/
bool exists(const char *fname) bool exists(const char *fname) {
{ return access(fname, F_OK) == 0;
int fd;
if ((fd = open(fname, O_RDONLY)) > 0) {
close(fd);
return true;
}
return false;
} }
// we check: 1. lib // we check: 1. lib

View File

@ -1957,7 +1957,7 @@ public class CommandProcessor {
if (doit == null) { if (doit == null) {
out.println("Unrecognized command. Try help..."); out.println("Unrecognized command. Try help...");
} else if (!debugger.isAttached() && !doit.okIfDisconnected) { } else if (!debugger.isAttached() && !doit.okIfDisconnected) {
out.println("Command not valid until the attached to a VM"); out.println("Command not valid until attached to a VM");
} else { } else {
try { try {
doit.doit(args); doit.doit(args);

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -1474,7 +1474,7 @@ public class HSDB implements ObjectHistogramPanel.Listener, SAListener {
return attached; return attached;
} }
public void attach(String pid) { public void attach(String pid) {
attach(pid); HSDB.this.attach(pid);
} }
public void attach(String java, String core) { public void attach(String java, String core) {
} }

View File

@ -975,7 +975,7 @@ public class InstanceKlass extends Klass {
while (l <= h) { while (l <= h) {
int mid = (l + h) >> 1; int mid = (l + h) >> 1;
Method m = methods.at(mid); Method m = methods.at(mid);
int res = m.getName().fastCompare(name); long res = m.getName().fastCompare(name);
if (res == 0) { if (res == 0) {
// found matching name; do linear search to find matching signature // found matching name; do linear search to find matching signature
// first, quick check for common case // first, quick check for common case

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -139,8 +139,8 @@ public class Symbol extends VMObject {
time-invariant order Since Symbol* are in C_HEAP, their time-invariant order Since Symbol* are in C_HEAP, their
relative order in memory never changes, so use address relative order in memory never changes, so use address
comparison for speed. */ comparison for speed. */
public int fastCompare(Symbol other) { public long fastCompare(Symbol other) {
return (int) addr.minus(other.addr); return addr.minus(other.addr);
} }
private static String readModifiedUTF8(byte[] buf) throws IOException { private static String readModifiedUTF8(byte[] buf) throws IOException {

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -51,7 +51,7 @@ public class Bytes {
if (!swap) if (!swap)
return x; return x;
return (swapShort((short) x) << 16) | (swapShort((short) (x >> 16)) & 0xFFFF); return ((int)swapShort((short) x) << 16) | (swapShort((short) (x >> 16)) & 0xFFFF);
} }
/** Should only swap if the hardware's underlying byte order is /** Should only swap if the hardware's underlying byte order is
@ -60,6 +60,6 @@ public class Bytes {
if (!swap) if (!swap)
return x; return x;
return (swapInt((int) x) << 32) | (swapInt((int) (x >> 32)) & 0xFFFFFFFF); return ((long)swapInt((int) x) << 32) | (swapInt((int) (x >> 32)) & 0xFFFFFFFF);
} }
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2004, 2007, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2004, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -177,14 +177,14 @@ public class JSJavaHeap extends DefaultScriptObject {
JSJavaObject k = jk.getJSJavaClass(); JSJavaObject k = jk.getJSJavaClass();
JSJavaObject l = factory.newJSJavaObject(loader); JSJavaObject l = factory.newJSJavaObject(loader);
if (k != null) { if (k != null) {
if (k != null) { if (l != null) {
try { try {
finalFunc.call(new Object[] { k, l }); finalFunc.call(new Object[] { k, l });
} catch (ScriptException exp) { } catch (ScriptException exp) {
throw new RuntimeException(exp); throw new RuntimeException(exp);
}
}
} }
}
}
} }
}); });

View File

@ -84,6 +84,10 @@ public class AArch64 extends Architecture {
public static final Register lr = r30; public static final Register lr = r30;
// Used by runtime code: cannot be compiler-allocated.
public static final Register rscratch1 = r8;
public static final Register rscratch2 = r9;
// @formatter:off // @formatter:off
public static final RegisterArray cpuRegisters = new RegisterArray( public static final RegisterArray cpuRegisters = new RegisterArray(
r0, r1, r2, r3, r4, r5, r6, r7, r0, r1, r2, r3, r4, r5, r6, r7,

View File

@ -25,18 +25,19 @@ package jdk.vm.ci.hotspot.aarch64;
import static jdk.vm.ci.aarch64.AArch64.lr; import static jdk.vm.ci.aarch64.AArch64.lr;
import static jdk.vm.ci.aarch64.AArch64.r0; import static jdk.vm.ci.aarch64.AArch64.r0;
import static jdk.vm.ci.aarch64.AArch64.r1; import static jdk.vm.ci.aarch64.AArch64.r1;
import static jdk.vm.ci.aarch64.AArch64.r12;
import static jdk.vm.ci.aarch64.AArch64.r2; import static jdk.vm.ci.aarch64.AArch64.r2;
import static jdk.vm.ci.aarch64.AArch64.r27;
import static jdk.vm.ci.aarch64.AArch64.r28;
import static jdk.vm.ci.aarch64.AArch64.r29;
import static jdk.vm.ci.aarch64.AArch64.r3; import static jdk.vm.ci.aarch64.AArch64.r3;
import static jdk.vm.ci.aarch64.AArch64.r31;
import static jdk.vm.ci.aarch64.AArch64.r4; import static jdk.vm.ci.aarch64.AArch64.r4;
import static jdk.vm.ci.aarch64.AArch64.r5; import static jdk.vm.ci.aarch64.AArch64.r5;
import static jdk.vm.ci.aarch64.AArch64.r6; import static jdk.vm.ci.aarch64.AArch64.r6;
import static jdk.vm.ci.aarch64.AArch64.r7; import static jdk.vm.ci.aarch64.AArch64.r7;
import static jdk.vm.ci.aarch64.AArch64.r9; import static jdk.vm.ci.aarch64.AArch64.rscratch1;
import static jdk.vm.ci.aarch64.AArch64.rscratch2;
import static jdk.vm.ci.aarch64.AArch64.r12;
import static jdk.vm.ci.aarch64.AArch64.r27;
import static jdk.vm.ci.aarch64.AArch64.r28;
import static jdk.vm.ci.aarch64.AArch64.r29;
import static jdk.vm.ci.aarch64.AArch64.r31;
import static jdk.vm.ci.aarch64.AArch64.sp; import static jdk.vm.ci.aarch64.AArch64.sp;
import static jdk.vm.ci.aarch64.AArch64.v0; import static jdk.vm.ci.aarch64.AArch64.v0;
import static jdk.vm.ci.aarch64.AArch64.v1; import static jdk.vm.ci.aarch64.AArch64.v1;
@ -114,7 +115,7 @@ public class AArch64HotSpotRegisterConfig implements RegisterConfig {
private final RegisterArray nativeGeneralParameterRegisters = new RegisterArray(r0, r1, r2, r3, r4, r5, r6, r7); private final RegisterArray nativeGeneralParameterRegisters = new RegisterArray(r0, r1, r2, r3, r4, r5, r6, r7);
private final RegisterArray simdParameterRegisters = new RegisterArray(v0, v1, v2, v3, v4, v5, v6, v7); private final RegisterArray simdParameterRegisters = new RegisterArray(v0, v1, v2, v3, v4, v5, v6, v7);
public static final Register inlineCacheRegister = r9; public static final Register inlineCacheRegister = rscratch2;
/** /**
* Vtable stubs expect the metaspace Method in r12. * Vtable stubs expect the metaspace Method in r12.
@ -125,7 +126,8 @@ public class AArch64HotSpotRegisterConfig implements RegisterConfig {
public static final Register threadRegister = r28; public static final Register threadRegister = r28;
public static final Register fp = r29; public static final Register fp = r29;
private static final RegisterArray reservedRegisters = new RegisterArray(threadRegister, fp, lr, r31, zr, sp); private static final RegisterArray reservedRegisters
= new RegisterArray(rscratch1, rscratch2, threadRegister, fp, lr, r31, zr, sp);
private static RegisterArray initAllocatable(Architecture arch, boolean reserveForHeapBase) { private static RegisterArray initAllocatable(Architecture arch, boolean reserveForHeapBase) {
RegisterArray allRegisters = arch.getAvailableValueRegisters(); RegisterArray allRegisters = arch.getAvailableValueRegisters();

View File

@ -472,7 +472,8 @@ final class HotSpotResolvedJavaMethodImpl extends HotSpotMethod implements HotSp
Parameter[] res = new Parameter[javaParameters.length]; Parameter[] res = new Parameter[javaParameters.length];
for (int i = 0; i < res.length; i++) { for (int i = 0; i < res.length; i++) {
java.lang.reflect.Parameter src = javaParameters[i]; java.lang.reflect.Parameter src = javaParameters[i];
res[i] = new Parameter(src.getName(), src.getModifiers(), this, i); String paramName = src.isNamePresent() ? src.getName() : null;
res[i] = new Parameter(paramName, src.getModifiers(), this, i);
} }
return res; return res;
} }

View File

@ -177,7 +177,7 @@ public interface ResolvedJavaMethod extends JavaMethod, InvokeTarget, ModifiersP
/** /**
* A {@code Parameter} provides information about method parameters. * A {@code Parameter} provides information about method parameters.
*/ */
public static class Parameter implements AnnotatedElement { class Parameter implements AnnotatedElement {
private final String name; private final String name;
private final ResolvedJavaMethod method; private final ResolvedJavaMethod method;
private final int modifiers; private final int modifiers;
@ -186,7 +186,9 @@ public interface ResolvedJavaMethod extends JavaMethod, InvokeTarget, ModifiersP
/** /**
* Constructor for {@code Parameter}. * Constructor for {@code Parameter}.
* *
* @param name the name of the parameter * @param name the name of the parameter or {@code null} if there is no
* {@literal MethodParameters} class file attribute providing a non-empty name
* for the parameter
* @param modifiers the modifier flags for the parameter * @param modifiers the modifier flags for the parameter
* @param method the method which defines this parameter * @param method the method which defines this parameter
* @param index the index of the parameter * @param index the index of the parameter
@ -195,6 +197,7 @@ public interface ResolvedJavaMethod extends JavaMethod, InvokeTarget, ModifiersP
int modifiers, int modifiers,
ResolvedJavaMethod method, ResolvedJavaMethod method,
int index) { int index) {
assert name == null || !name.isEmpty();
this.name = name; this.name = name;
this.modifiers = modifiers; this.modifiers = modifiers;
this.method = method; this.method = method;
@ -202,10 +205,20 @@ public interface ResolvedJavaMethod extends JavaMethod, InvokeTarget, ModifiersP
} }
/** /**
* Gets the name of the parameter. * Gets the name of the parameter. If the parameter's name is {@linkplain #isNamePresent()
* present}, then this method returns the name provided by the class file. Otherwise, this
* method synthesizes a name of the form argN, where N is the index of the parameter in the
* descriptor of the method which declares the parameter.
*
* @return the name of the parameter, either provided by the class file or synthesized if
* the class file does not provide a name
*/ */
public String getName() { public String getName() {
return name; if (name == null) {
return "arg" + index;
} else {
return name;
}
} }
/** /**
@ -216,7 +229,7 @@ public interface ResolvedJavaMethod extends JavaMethod, InvokeTarget, ModifiersP
} }
/** /**
* Get the modifier flags for the parameter * Get the modifier flags for the parameter.
*/ */
public int getModifiers() { public int getModifiers() {
return modifiers; return modifiers;
@ -243,6 +256,16 @@ public interface ResolvedJavaMethod extends JavaMethod, InvokeTarget, ModifiersP
return method.getSignature().getParameterType(index, method.getDeclaringClass()); return method.getSignature().getParameterType(index, method.getDeclaringClass());
} }
/**
* Determines if the parameter has a name according to a {@literal MethodParameters} class
* file attribute.
*
* @return true if and only if the parameter has a name according to the class file.
*/
public boolean isNamePresent() {
return name != null;
}
/** /**
* Determines if the parameter represents a variable argument list. * Determines if the parameter represents a variable argument list.
*/ */

View File

@ -171,6 +171,8 @@ frame os::get_sender_for_C_frame(frame* fr) {
} }
frame os::current_frame() { frame os::current_frame() {
// Expected to return the stack pointer of this method.
// But if inlined, returns the stack pointer of our caller!
intptr_t* csp = (intptr_t*) *((intptr_t*) os::current_stack_pointer()); intptr_t* csp = (intptr_t*) *((intptr_t*) os::current_stack_pointer());
assert (csp != NULL, "sp should not be NULL"); assert (csp != NULL, "sp should not be NULL");
// Pass a dummy pc. This way we don't have to load it from the // Pass a dummy pc. This way we don't have to load it from the
@ -184,8 +186,13 @@ frame os::current_frame() {
assert(senderFrame.pc() != NULL, "Sender pc should not be NULL"); assert(senderFrame.pc() != NULL, "Sender pc should not be NULL");
// Return sender of sender of current topframe which hopefully // Return sender of sender of current topframe which hopefully
// both have pc != NULL. // both have pc != NULL.
#ifdef _NMT_NOINLINE_ // Is set in slowdebug builds.
// Current_stack_pointer is not inlined, we must pop one more frame.
frame tmp = os::get_sender_for_C_frame(&topframe); frame tmp = os::get_sender_for_C_frame(&topframe);
return os::get_sender_for_C_frame(&tmp); return os::get_sender_for_C_frame(&tmp);
#else
return os::get_sender_for_C_frame(&topframe);
#endif
} }
} }
@ -374,7 +381,7 @@ JVM_handle_linux_signal(int sig,
// BugId 4454115: A read from a MappedByteBuffer can fault here if the // BugId 4454115: A read from a MappedByteBuffer can fault here if the
// underlying file has been truncated. Do not crash the VM in such a case. // underlying file has been truncated. Do not crash the VM in such a case.
CodeBlob* cb = CodeCache::find_blob_unsafe(pc); CodeBlob* cb = CodeCache::find_blob_unsafe(pc);
nmethod* nm = (cb != NULL && cb->is_nmethod()) ? (nmethod*)cb : NULL; CompiledMethod* nm = (cb != NULL) ? cb->as_compiled_method_or_null() : NULL;
if (nm != NULL && nm->has_unsafe_access()) { if (nm != NULL && nm->has_unsafe_access()) {
// We don't really need a stub here! Just set the pending exeption and // We don't really need a stub here! Just set the pending exeption and
// continue at the next instruction after the faulting read. Returning // continue at the next instruction after the faulting read. Returning

View File

@ -1813,14 +1813,10 @@ void GraphBuilder::invoke(Bytecodes::Code code) {
ciKlass* holder = stream()->get_declared_method_holder(); ciKlass* holder = stream()->get_declared_method_holder();
const Bytecodes::Code bc_raw = stream()->cur_bc_raw(); const Bytecodes::Code bc_raw = stream()->cur_bc_raw();
assert(declared_signature != NULL, "cannot be null"); assert(declared_signature != NULL, "cannot be null");
assert(will_link == target->is_loaded(), "");
ciInstanceKlass* klass = target->holder(); ciInstanceKlass* klass = target->holder();
assert(!target->is_loaded() || klass->is_loaded(), "loaded target must imply loaded klass");
// Make sure there are no evident problems with linking the instruction.
bool is_resolved = true;
if (klass->is_loaded() && !target->is_loaded()) {
is_resolved = false; // method not found
}
// check if CHA possible: if so, change the code to invoke_special // check if CHA possible: if so, change the code to invoke_special
ciInstanceKlass* calling_klass = method()->holder(); ciInstanceKlass* calling_klass = method()->holder();
@ -1868,7 +1864,7 @@ void GraphBuilder::invoke(Bytecodes::Code code) {
ciMethod* cha_monomorphic_target = NULL; ciMethod* cha_monomorphic_target = NULL;
ciMethod* exact_target = NULL; ciMethod* exact_target = NULL;
Value better_receiver = NULL; Value better_receiver = NULL;
if (UseCHA && DeoptC1 && klass->is_loaded() && target->is_loaded() && if (UseCHA && DeoptC1 && target->is_loaded() &&
!(// %%% FIXME: Are both of these relevant? !(// %%% FIXME: Are both of these relevant?
target->is_method_handle_intrinsic() || target->is_method_handle_intrinsic() ||
target->is_compiled_lambda_form()) && target->is_compiled_lambda_form()) &&
@ -1988,8 +1984,7 @@ void GraphBuilder::invoke(Bytecodes::Code code) {
} }
// check if we could do inlining // check if we could do inlining
if (!PatchALot && Inline && is_resolved && if (!PatchALot && Inline && target->is_loaded() &&
klass->is_loaded() && target->is_loaded() &&
(klass->is_initialized() || klass->is_interface() && target->holder()->is_initialized()) (klass->is_initialized() || klass->is_interface() && target->holder()->is_initialized())
&& !patch_for_appendix) { && !patch_for_appendix) {
// callee is known => check if we have static binding // callee is known => check if we have static binding
@ -2032,7 +2027,6 @@ void GraphBuilder::invoke(Bytecodes::Code code) {
CHECK_BAILOUT(); CHECK_BAILOUT();
// inlining not successful => standard invoke // inlining not successful => standard invoke
bool is_loaded = target->is_loaded();
ValueType* result_type = as_ValueType(declared_signature->return_type()); ValueType* result_type = as_ValueType(declared_signature->return_type());
ValueStack* state_before = copy_state_exhandling(); ValueStack* state_before = copy_state_exhandling();
@ -2049,7 +2043,7 @@ void GraphBuilder::invoke(Bytecodes::Code code) {
// Currently only supported on Sparc. // Currently only supported on Sparc.
// The UseInlineCaches only controls dispatch to invokevirtuals for // The UseInlineCaches only controls dispatch to invokevirtuals for
// loaded classes which we weren't able to statically bind. // loaded classes which we weren't able to statically bind.
if (!UseInlineCaches && is_resolved && is_loaded && code == Bytecodes::_invokevirtual if (!UseInlineCaches && target->is_loaded() && code == Bytecodes::_invokevirtual
&& !target->can_be_statically_bound()) { && !target->can_be_statically_bound()) {
// Find a vtable index if one is available // Find a vtable index if one is available
// For arrays, callee_holder is Object. Resolving the call with // For arrays, callee_holder is Object. Resolving the call with
@ -2062,16 +2056,24 @@ void GraphBuilder::invoke(Bytecodes::Code code) {
} }
#endif #endif
if (is_resolved) { // A null check is required here (when there is a receiver) for any of the following cases
// invokespecial always needs a NULL check. invokevirtual where the target is // - invokespecial, always need a null check.
// final or where it's not known whether the target is final requires a NULL check. // - invokevirtual, when the target is final and loaded. Calls to final targets will become optimized
// Otherwise normal invokevirtual will perform the null check during the lookup // and require null checking. If the target is loaded a null check is emitted here.
// logic or the unverified entry point. Profiling of calls requires that // If the target isn't loaded the null check must happen after the call resolution. We achieve that
// the null check is performed in all cases. // by using the target methods unverified entry point (see CompiledIC::compute_monomorphic_entry).
bool do_null_check = (recv != NULL) && // (The JVM specification requires that LinkageError must be thrown before a NPE. An unloaded target may
(code == Bytecodes::_invokespecial || !is_loaded || target->is_final() || (is_profiling() && profile_calls())); // potentially fail, and can't have the null check before the resolution.)
// - A call that will be profiled. (But we can't add a null check when the target is unloaded, by the same
// reason as above, so calls with a receiver to unloaded targets can't be profiled.)
//
// Normal invokevirtual will perform the null check during lookup
if (do_null_check) { bool need_null_check = (code == Bytecodes::_invokespecial) ||
(target->is_loaded() && (target->is_final_method() || (is_profiling() && profile_calls())));
if (need_null_check) {
if (recv != NULL) {
null_check(recv); null_check(recv);
} }
@ -2090,9 +2092,6 @@ void GraphBuilder::invoke(Bytecodes::Code code) {
profile_call(target, recv, target_klass, collect_args_for_profiling(args, NULL, false), false); profile_call(target, recv, target_klass, collect_args_for_profiling(args, NULL, false), false);
} }
} }
} else {
// No need in null check or profiling: linkage error will be thrown at runtime
// during resolution.
} }
Invoke* result = new Invoke(code, result_type, recv, args, vtable_index, target, state_before); Invoke* result = new Invoke(code, result_type, recv, args, vtable_index, target, state_before);

View File

@ -2976,7 +2976,6 @@ void LIRGenerator::do_Invoke(Invoke* x) {
} }
// emit invoke code // emit invoke code
bool optimized = x->target_is_loaded() && x->target_is_final();
assert(receiver->is_illegal() || receiver->is_equal(LIR_Assembler::receiverOpr()), "must match"); assert(receiver->is_illegal() || receiver->is_equal(LIR_Assembler::receiverOpr()), "must match");
// JSR 292 // JSR 292
@ -3001,9 +3000,9 @@ void LIRGenerator::do_Invoke(Invoke* x) {
case Bytecodes::_invokespecial: case Bytecodes::_invokespecial:
case Bytecodes::_invokevirtual: case Bytecodes::_invokevirtual:
case Bytecodes::_invokeinterface: case Bytecodes::_invokeinterface:
// for final target we still produce an inline cache, in order // for loaded and final (method or class) target we still produce an inline cache,
// to be able to call mixed mode // in order to be able to call mixed mode
if (x->code() == Bytecodes::_invokespecial || optimized) { if (x->code() == Bytecodes::_invokespecial || x->target_is_final()) {
__ call_opt_virtual(target, receiver, result_register, __ call_opt_virtual(target, receiver, result_register,
SharedRuntime::get_resolve_opt_virtual_call_stub(), SharedRuntime::get_resolve_opt_virtual_call_stub(),
arg_list, info); arg_list, info);

View File

@ -4349,13 +4349,34 @@ static void check_super_class_access(const InstanceKlass* this_klass, TRAPS) {
assert(this_klass != NULL, "invariant"); assert(this_klass != NULL, "invariant");
const Klass* const super = this_klass->super(); const Klass* const super = this_klass->super();
if (super != NULL) { if (super != NULL) {
// If the loader is not the boot loader then throw an exception if its
// superclass is in package jdk.internal.reflect and its loader is not a
// special reflection class loader
if (!this_klass->class_loader_data()->is_the_null_class_loader_data()) {
assert(super->is_instance_klass(), "super is not instance klass");
PackageEntry* super_package = super->package();
if (super_package != NULL &&
super_package->name()->fast_compare(vmSymbols::jdk_internal_reflect()) == 0 &&
!java_lang_ClassLoader::is_reflection_class_loader(this_klass->class_loader())) {
ResourceMark rm(THREAD);
Exceptions::fthrow(
THREAD_AND_LOCATION,
vmSymbols::java_lang_IllegalAccessError(),
"class %s loaded by %s cannot access jdk/internal/reflect superclass %s",
this_klass->external_name(),
this_klass->class_loader_data()->loader_name(),
super->external_name());
return;
}
}
Reflection::VerifyClassAccessResults vca_result = Reflection::VerifyClassAccessResults vca_result =
Reflection::verify_class_access(this_klass, super, false); Reflection::verify_class_access(this_klass, super, false);
if (vca_result != Reflection::ACCESS_OK) { if (vca_result != Reflection::ACCESS_OK) {
ResourceMark rm(THREAD); ResourceMark rm(THREAD);
char* msg = Reflection::verify_class_access_msg(this_klass, super, vca_result); char* msg = Reflection::verify_class_access_msg(this_klass, super, vca_result);
if (msg == NULL) { if (msg == NULL) {
ResourceMark rm(THREAD);
Exceptions::fthrow( Exceptions::fthrow(
THREAD_AND_LOCATION, THREAD_AND_LOCATION,
vmSymbols::java_lang_IllegalAccessError(), vmSymbols::java_lang_IllegalAccessError(),

View File

@ -171,11 +171,11 @@ void CompactHashtableWriter::dump(SimpleCompactHashtable *cht, const char* table
void CompactSymbolTableWriter::add(unsigned int hash, Symbol *symbol) { void CompactSymbolTableWriter::add(unsigned int hash, Symbol *symbol) {
address base_address = address(MetaspaceShared::shared_rs()->base()); address base_address = address(MetaspaceShared::shared_rs()->base());
uintx max_delta = uintx(MetaspaceShared::shared_rs()->size());
assert(max_delta <= MAX_SHARED_DELTA, "range check");
uintx deltax = address(symbol) - base_address; uintx deltax = address(symbol) - base_address;
assert(deltax < max_delta, "range check"); // The symbols are in RO space, which is smaler than MAX_SHARED_DELTA.
// The assert below is just to be extra cautious.
assert(deltax <= MAX_SHARED_DELTA, "the delta is too large to encode");
u4 delta = u4(deltax); u4 delta = u4(deltax);
CompactHashtableWriter::add(hash, delta); CompactHashtableWriter::add(hash, delta);

View File

@ -3525,17 +3525,24 @@ bool java_lang_ClassLoader::is_trusted_loader(oop loader) {
return false; return false;
} }
oop java_lang_ClassLoader::non_reflection_class_loader(oop loader) { // Return true if this is one of the class loaders associated with
// the generated bytecodes for reflection.
bool java_lang_ClassLoader::is_reflection_class_loader(oop loader) {
if (loader != NULL) { if (loader != NULL) {
// See whether this is one of the class loaders associated with
// the generated bytecodes for reflection, and if so, "magically"
// delegate to its parent to prevent class loading from occurring
// in places where applications using reflection didn't expect it.
Klass* delegating_cl_class = SystemDictionary::reflect_DelegatingClassLoader_klass(); Klass* delegating_cl_class = SystemDictionary::reflect_DelegatingClassLoader_klass();
// This might be null in non-1.4 JDKs // This might be null in non-1.4 JDKs
if (delegating_cl_class != NULL && loader->is_a(delegating_cl_class)) { return (delegating_cl_class != NULL && loader->is_a(delegating_cl_class));
return parent(loader); }
} return false;
}
oop java_lang_ClassLoader::non_reflection_class_loader(oop loader) {
// See whether this is one of the class loaders associated with
// the generated bytecodes for reflection, and if so, "magically"
// delegate to its parent to prevent class loading from occurring
// in places where applications using reflection didn't expect it.
if (is_reflection_class_loader(loader)) {
return parent(loader);
} }
return loader; return loader;
} }

View File

@ -1243,6 +1243,10 @@ class java_lang_ClassLoader : AllStatic {
static bool is_trusted_loader(oop loader); static bool is_trusted_loader(oop loader);
// Return true if this is one of the class loaders associated with
// the generated bytecodes for reflection.
static bool is_reflection_class_loader(oop loader);
// Fix for 4474172 // Fix for 4474172
static oop non_reflection_class_loader(oop loader); static oop non_reflection_class_loader(oop loader);

View File

@ -94,7 +94,7 @@ typedef void (*JImageClose_t)(JImageFile* jimage);
* Ex. * Ex.
* const char* package = (*JImagePackageToModule)(image, "java/lang"); * const char* package = (*JImagePackageToModule)(image, "java/lang");
* tty->print_cr(package); * tty->print_cr(package);
* > java.base * -> java.base
*/ */
extern "C" const char * JIMAGE_PackageToModule(JImageFile* jimage, const char* package_name); extern "C" const char * JIMAGE_PackageToModule(JImageFile* jimage, const char* package_name);
@ -126,7 +126,7 @@ typedef JImageLocationRef(*JImageFindResource_t)(JImageFile* jimage,
/* /*
* JImageGetResource - Given an open image file (see JImageOpen), a resources * JImageGetResource - Given an open image file (see JImageOpen), a resource's
* location information (see JImageFindResource), a buffer of appropriate * location information (see JImageFindResource), a buffer of appropriate
* size and the size, retrieve the bytes associated with the * size and the size, retrieve the bytes associated with the
* resource. If the size is less than the resource size then the read is truncated. * resource. If the size is less than the resource size then the read is truncated.
@ -158,7 +158,7 @@ typedef jlong(*JImageGetResource_t)(JImageFile* jimage, JImageLocationRef locati
* Ex. * Ex.
* bool ctw_visitor(JImageFile* jimage, const char* module_name, const char* version, * bool ctw_visitor(JImageFile* jimage, const char* module_name, const char* version,
* const char* package, const char* name, const char* extension, void* arg) { * const char* package, const char* name, const char* extension, void* arg) {
* if (strcmp(extension, class) == 0) { * if (strcmp(extension, "class") == 0) {
* char path[JIMAGE_MAX_PATH]; * char path[JIMAGE_MAX_PATH];
* Thread* THREAD = Thread::current(); * Thread* THREAD = Thread::current();
* jio_snprintf(path, JIMAGE_MAX_PATH - 1, "/%s/%s", package, name); * jio_snprintf(path, JIMAGE_MAX_PATH - 1, "/%s/%s", package, name);

View File

@ -54,6 +54,17 @@ void ModuleEntry::set_location(Symbol* location) {
} }
} }
bool ModuleEntry::is_non_jdk_module() {
ResourceMark rm;
if (location() != NULL) {
const char* loc = location()->as_C_string();
if (strncmp(loc, "jrt:/java.", 10) != 0 && strncmp(loc, "jrt:/jdk.", 9) != 0) {
return true;
}
}
return false;
}
void ModuleEntry::set_version(Symbol* version) { void ModuleEntry::set_version(Symbol* version) {
if (_version != NULL) { if (_version != NULL) {
// _version symbol's refcounts are managed by ModuleEntry, // _version symbol's refcounts are managed by ModuleEntry,

View File

@ -38,6 +38,7 @@
#define UNNAMED_MODULE "Unnamed Module" #define UNNAMED_MODULE "Unnamed Module"
#define JAVAPKG "java/" #define JAVAPKG "java/"
#define JAVAPKG_LEN 5 #define JAVAPKG_LEN 5
#define JAVA_BASE_NAME "java.base"
class ModuleClosure; class ModuleClosure;
@ -102,6 +103,7 @@ public:
Symbol* location() const { return _location; } Symbol* location() const { return _location; }
void set_location(Symbol* location); void set_location(Symbol* location);
bool is_non_jdk_module();
bool can_read(ModuleEntry* m) const; bool can_read(ModuleEntry* m) const;
bool has_reads() const; bool has_reads() const;

View File

@ -2897,11 +2897,11 @@ void SystemDictionary::verify() {
// caller needs ResourceMark // caller needs ResourceMark
const char* SystemDictionary::loader_name(const oop loader) { const char* SystemDictionary::loader_name(const oop loader) {
return ((loader) == NULL ? "<bootloader>" : return ((loader) == NULL ? "<bootloader>" :
InstanceKlass::cast((loader)->klass())->name()->as_C_string()); InstanceKlass::cast((loader)->klass())->name()->as_C_string());
} }
// caller needs ResourceMark // caller needs ResourceMark
const char* SystemDictionary::loader_name(const ClassLoaderData* loader_data) { const char* SystemDictionary::loader_name(const ClassLoaderData* loader_data) {
return (loader_data->class_loader() == NULL ? "<bootloader>" : return (loader_data->class_loader() == NULL ? "<bootloader>" :
InstanceKlass::cast((loader_data->class_loader())->klass())->name()->as_C_string()); SystemDictionary::loader_name(loader_data->class_loader()));
} }

View File

@ -228,6 +228,7 @@
\ \
/* Support for reflection based on dynamic bytecode generation (JDK 1.4 and above) */ \ /* Support for reflection based on dynamic bytecode generation (JDK 1.4 and above) */ \
\ \
template(jdk_internal_reflect, "jdk/internal/reflect") \
template(reflect_MagicAccessorImpl, "jdk/internal/reflect/MagicAccessorImpl") \ template(reflect_MagicAccessorImpl, "jdk/internal/reflect/MagicAccessorImpl") \
template(reflect_MethodAccessorImpl, "jdk/internal/reflect/MethodAccessorImpl") \ template(reflect_MethodAccessorImpl, "jdk/internal/reflect/MethodAccessorImpl") \
template(reflect_ConstructorAccessorImpl, "jdk/internal/reflect/ConstructorAccessorImpl") \ template(reflect_ConstructorAccessorImpl, "jdk/internal/reflect/ConstructorAccessorImpl") \

View File

@ -159,7 +159,8 @@ public:
bool blob_contains(address addr) const { return header_begin() <= addr && addr < data_end(); } bool blob_contains(address addr) const { return header_begin() <= addr && addr < data_end(); }
bool code_contains(address addr) const { return code_begin() <= addr && addr < code_end(); } bool code_contains(address addr) const { return code_begin() <= addr && addr < code_end(); }
bool contains(address addr) const { return content_begin() <= addr && addr < content_end(); } bool contains(address addr) const { return content_begin() <= addr && addr < content_end(); }
bool is_frame_complete_at(address addr) const { return code_contains(addr) && addr >= code_begin() + _frame_complete_offset; } bool is_frame_complete_at(address addr) const { return _frame_complete_offset != CodeOffsets::frame_never_safe &&
code_contains(addr) && addr >= code_begin() + _frame_complete_offset; }
// CodeCache support: really only used by the nmethods, but in order to get // CodeCache support: really only used by the nmethods, but in order to get
// asserts and certain bookkeeping to work in the CodeCache they are defined // asserts and certain bookkeeping to work in the CodeCache they are defined

View File

@ -460,9 +460,11 @@ void CompiledIC::set_to_monomorphic(CompiledICInfo& info) {
} }
// is_optimized: Compiler has generated an optimized call (i.e., no inline // is_optimized: Compiler has generated an optimized call (i.e. fixed, no inline cache)
// cache) static_bound: The call can be static bound (i.e, no need to use // static_bound: The call can be static bound. If it isn't also optimized, the property
// inline cache) // wasn't provable at time of compilation. An optimized call will have any necessary
// null check, while a static_bound won't. A static_bound (but not optimized) must
// therefore use the unverified entry point.
void CompiledIC::compute_monomorphic_entry(const methodHandle& method, void CompiledIC::compute_monomorphic_entry(const methodHandle& method,
KlassHandle receiver_klass, KlassHandle receiver_klass,
bool is_optimized, bool is_optimized,
@ -475,7 +477,23 @@ void CompiledIC::compute_monomorphic_entry(const methodHandle& method,
if (method_code != NULL && method_code->is_in_use()) { if (method_code != NULL && method_code->is_in_use()) {
assert(method_code->is_compiled(), "must be compiled"); assert(method_code->is_compiled(), "must be compiled");
// Call to compiled code // Call to compiled code
if (static_bound || is_optimized) { //
// Note: the following problem exists with Compiler1:
// - at compile time we may or may not know if the destination is final
// - if we know that the destination is final (is_optimized), we will emit
// an optimized virtual call (no inline cache), and need a Method* to make
// a call to the interpreter
// - if we don't know if the destination is final, we emit a standard
// virtual call, and use CompiledICHolder to call interpreted code
// (no static call stub has been generated)
// - In the case that we here notice the call is static bound we
// convert the call into what looks to be an optimized virtual call,
// but we must use the unverified entry point (since there will be no
// null check on a call when the target isn't loaded).
// This causes problems when verifying the IC because
// it looks vanilla but is optimized. Code in is_call_to_interpreted
// is aware of this and weakens its asserts.
if (is_optimized) {
entry = method_code->verified_entry_point(); entry = method_code->verified_entry_point();
} else { } else {
entry = method_code->entry_point(); entry = method_code->entry_point();
@ -485,38 +503,6 @@ void CompiledIC::compute_monomorphic_entry(const methodHandle& method,
// Call to compiled code // Call to compiled code
info.set_compiled_entry(entry, (static_bound || is_optimized) ? NULL : receiver_klass(), is_optimized); info.set_compiled_entry(entry, (static_bound || is_optimized) ? NULL : receiver_klass(), is_optimized);
} else { } else {
// Note: the following problem exists with Compiler1:
// - at compile time we may or may not know if the destination is final
// - if we know that the destination is final, we will emit an optimized
// virtual call (no inline cache), and need a Method* to make a call
// to the interpreter
// - if we do not know if the destination is final, we emit a standard
// virtual call, and use CompiledICHolder to call interpreted code
// (no static call stub has been generated)
// However in that case we will now notice it is static_bound
// and convert the call into what looks to be an optimized
// virtual call. This causes problems in verifying the IC because
// it look vanilla but is optimized. Code in is_call_to_interpreted
// is aware of this and weakens its asserts.
// static_bound should imply is_optimized -- otherwise we have a
// performance bug (statically-bindable method is called via
// dynamically-dispatched call note: the reverse implication isn't
// necessarily true -- the call may have been optimized based on compiler
// analysis (static_bound is only based on "final" etc.)
#ifdef COMPILER2
#ifdef TIERED
#if defined(ASSERT)
// can't check the assert because we don't have the CompiledIC with which to
// find the address if the call instruction.
//
// CodeBlob* cb = find_blob_unsafe(instruction_address());
// assert(cb->is_compiled_by_c1() || !static_bound || is_optimized, "static_bound should imply is_optimized");
#endif // ASSERT
#else
assert(!static_bound || is_optimized, "static_bound should imply is_optimized");
#endif // TIERED
#endif // COMPILER2
if (is_optimized) { if (is_optimized) {
// Use stub entry // Use stub entry
info.set_interpreter_entry(method()->get_c2i_entry(), method()); info.set_interpreter_entry(method()->get_c2i_entry(), method());

View File

@ -64,7 +64,7 @@
cflags(TraceOptoOutput, bool, false, TraceOptoOutput) \ cflags(TraceOptoOutput, bool, false, TraceOptoOutput) \
cflags(TraceSpilling, bool, TraceSpilling, TraceSpilling) \ cflags(TraceSpilling, bool, TraceSpilling, TraceSpilling) \
cflags(Vectorize, bool, false, Vectorize) \ cflags(Vectorize, bool, false, Vectorize) \
cflags(VectorizeDebug, bool, false, VectorizeDebug) \ cflags(VectorizeDebug, uintx, 0, VectorizeDebug) \
cflags(CloneMapDebug, bool, false, CloneMapDebug) \ cflags(CloneMapDebug, bool, false, CloneMapDebug) \
cflags(DoReserveCopyInSuperWordDebug, bool, false, DoReserveCopyInSuperWordDebug) \ cflags(DoReserveCopyInSuperWordDebug, bool, false, DoReserveCopyInSuperWordDebug) \
cflags(IGVPrintLevel, intx, PrintIdealGraphLevel, IGVPrintLevel) \ cflags(IGVPrintLevel, intx, PrintIdealGraphLevel, IGVPrintLevel) \
@ -140,6 +140,7 @@ public:
compilerdirectives_c1_flags(set_function_definition) compilerdirectives_c1_flags(set_function_definition)
void print_intx(outputStream* st, ccstr n, intx v, bool mod) { if (mod) { st->print("%s:" INTX_FORMAT " ", n, v); } } void print_intx(outputStream* st, ccstr n, intx v, bool mod) { if (mod) { st->print("%s:" INTX_FORMAT " ", n, v); } }
void print_uintx(outputStream* st, ccstr n, intx v, bool mod) { if (mod) { st->print("%s:" UINTX_FORMAT " ", n, v); } }
void print_bool(outputStream* st, ccstr n, bool v, bool mod) { if (mod) { st->print("%s:%s ", n, v ? "true" : "false"); } } void print_bool(outputStream* st, ccstr n, bool v, bool mod) { if (mod) { st->print("%s:%s ", n, v ? "true" : "false"); } }
void print_double(outputStream* st, ccstr n, double v, bool mod) { if (mod) { st->print("%s:%f ", n, v); } } void print_double(outputStream* st, ccstr n, double v, bool mod) { if (mod) { st->print("%s:%f ", n, v); } }
void print_ccstr(outputStream* st, ccstr n, ccstr v, bool mod) { if (mod) { st->print("%s:%s ", n, v); } } void print_ccstr(outputStream* st, ccstr n, ccstr v, bool mod) { if (mod) { st->print("%s:%s ", n, v); } }

View File

@ -31,6 +31,7 @@
enum FlagType { enum FlagType {
boolFlag, boolFlag,
intxFlag, intxFlag,
uintxFlag,
doubleFlag, doubleFlag,
ccstrFlag, ccstrFlag,
ccstrlistFlag, ccstrlistFlag,
@ -40,6 +41,7 @@ enum FlagType {
static const char* flag_type_names[] = { static const char* flag_type_names[] = {
"bool", "bool",
"int", "int",
"uint",
"double", "double",
"string", "string",
"string list", "string list",

View File

@ -156,9 +156,7 @@ void ConcurrentMarkThread::run_service() {
jlong mark_start = os::elapsed_counter(); jlong mark_start = os::elapsed_counter();
log_info(gc, marking)("Concurrent Mark (%.3fs)", TimeHelper::counter_to_seconds(mark_start)); log_info(gc, marking)("Concurrent Mark (%.3fs)", TimeHelper::counter_to_seconds(mark_start));
int iter = 0; for (uint iter = 1; true; ++iter) {
do {
iter++;
if (!cm()->has_aborted()) { if (!cm()->has_aborted()) {
G1ConcPhaseTimer t(_cm, "Concurrent Mark From Roots"); G1ConcPhaseTimer t(_cm, "Concurrent Mark From Roots");
_cm->mark_from_roots(); _cm->mark_from_roots();
@ -178,11 +176,14 @@ void ConcurrentMarkThread::run_service() {
VM_CGC_Operation op(&final_cl, "Pause Remark"); VM_CGC_Operation op(&final_cl, "Pause Remark");
VMThread::execute(&op); VMThread::execute(&op);
} }
if (cm()->restart_for_overflow()) {
log_debug(gc, marking)("Restarting Concurrent Marking because of Mark Stack Overflow in Remark (Iteration #%d).", iter); if (!cm()->restart_for_overflow() || cm()->has_aborted()) {
log_info(gc, marking)("Concurrent Mark Restart due to overflow"); break;
} }
} while (cm()->restart_for_overflow());
log_info(gc, marking)("Concurrent Mark Restart due to overflow"
" (iteration #%u", iter);
}
if (!cm()->has_aborted()) { if (!cm()->has_aborted()) {
G1ConcPhaseTimer t(_cm, "Concurrent Create Live Data"); G1ConcPhaseTimer t(_cm, "Concurrent Create Live Data");

View File

@ -227,7 +227,7 @@ HeapWord* G1BlockOffsetTablePart::forward_to_block_containing_addr_slow(HeapWord
while (n <= next_boundary) { while (n <= next_boundary) {
q = n; q = n;
oop obj = oop(q); oop obj = oop(q);
if (obj->klass_or_null() == NULL) return q; if (obj->klass_or_null_acquire() == NULL) return q;
n += block_size(q); n += block_size(q);
} }
assert(q <= next_boundary && n > next_boundary, "Consequence of loop"); assert(q <= next_boundary && n > next_boundary, "Consequence of loop");

View File

@ -136,7 +136,7 @@ inline HeapWord* G1BlockOffsetTablePart::forward_to_block_containing_addr_const(
while (n <= addr) { while (n <= addr) {
q = n; q = n;
oop obj = oop(q); oop obj = oop(q);
if (obj->klass_or_null() == NULL) { if (obj->klass_or_null_acquire() == NULL) {
return q; return q;
} }
n += block_size(q); n += block_size(q);
@ -148,7 +148,7 @@ inline HeapWord* G1BlockOffsetTablePart::forward_to_block_containing_addr_const(
inline HeapWord* G1BlockOffsetTablePart::forward_to_block_containing_addr(HeapWord* q, inline HeapWord* G1BlockOffsetTablePart::forward_to_block_containing_addr(HeapWord* q,
const void* addr) { const void* addr) {
if (oop(q)->klass_or_null() == NULL) { if (oop(q)->klass_or_null_acquire() == NULL) {
return q; return q;
} }
HeapWord* n = q + block_size(q); HeapWord* n = q + block_size(q);

View File

@ -300,6 +300,8 @@ G1CollectedHeap::humongous_obj_allocate_initialize_regions(uint first,
// thread to calculate the object size incorrectly. // thread to calculate the object size incorrectly.
Copy::fill_to_words(new_obj, oopDesc::header_size(), 0); Copy::fill_to_words(new_obj, oopDesc::header_size(), 0);
// Next, pad out the unused tail of the last region with filler
// objects, for improved usage accounting.
// How many words we use for filler objects. // How many words we use for filler objects.
size_t word_fill_size = word_size_sum - word_size; size_t word_fill_size = word_size_sum - word_size;
@ -426,8 +428,7 @@ HeapWord* G1CollectedHeap::humongous_obj_allocate(size_t word_size, AllocationCo
log_debug(gc, ergo, heap)("Attempt heap expansion (humongous allocation request failed). Allocation request: " SIZE_FORMAT "B", log_debug(gc, ergo, heap)("Attempt heap expansion (humongous allocation request failed). Allocation request: " SIZE_FORMAT "B",
word_size * HeapWordSize); word_size * HeapWordSize);
_hrm.expand_at(first, obj_regions, workers());
_hrm.expand_at(first, obj_regions);
g1_policy()->record_new_heap_size(num_regions()); g1_policy()->record_new_heap_size(num_regions());
#ifdef ASSERT #ifdef ASSERT
@ -739,7 +740,7 @@ bool G1CollectedHeap::alloc_archive_regions(MemRegion* ranges, size_t count) {
// Perform the actual region allocation, exiting if it fails. // Perform the actual region allocation, exiting if it fails.
// Then note how much new space we have allocated. // Then note how much new space we have allocated.
if (!_hrm.allocate_containing_regions(curr_range, &commits)) { if (!_hrm.allocate_containing_regions(curr_range, &commits, workers())) {
return false; return false;
} }
increase_used(word_size * HeapWordSize); increase_used(word_size * HeapWordSize);

View File

@ -2009,10 +2009,10 @@ public:
{ } { }
void operator()(oop obj) const { void operator()(oop obj) const {
guarantee(obj->is_oop(), guarantee(G1CMObjArrayProcessor::is_array_slice(obj) || obj->is_oop(),
"Non-oop " PTR_FORMAT ", phase: %s, info: %d", "Non-oop " PTR_FORMAT ", phase: %s, info: %d",
p2i(obj), _phase, _info); p2i(obj), _phase, _info);
guarantee(!_g1h->obj_in_cs(obj), guarantee(G1CMObjArrayProcessor::is_array_slice(obj) || !_g1h->obj_in_cs(obj),
"obj: " PTR_FORMAT " in CSet, phase: %s, info: %d", "obj: " PTR_FORMAT " in CSet, phase: %s, info: %d",
p2i(obj), _phase, _info); p2i(obj), _phase, _info);
} }
@ -2436,6 +2436,7 @@ bool G1CMTask::get_entries_from_global_stack() {
if (elem == NULL) { if (elem == NULL) {
break; break;
} }
assert(G1CMObjArrayProcessor::is_array_slice(elem) || elem->is_oop(), "Element " PTR_FORMAT " must be an array slice or oop", p2i(elem));
bool success = _task_queue->push(elem); bool success = _task_queue->push(elem);
// We only call this when the local queue is empty or under a // We only call this when the local queue is empty or under a
// given target limit. So, we do not expect this push to fail. // given target limit. So, we do not expect this push to fail.
@ -2448,7 +2449,9 @@ bool G1CMTask::get_entries_from_global_stack() {
} }
void G1CMTask::drain_local_queue(bool partially) { void G1CMTask::drain_local_queue(bool partially) {
if (has_aborted()) return; if (has_aborted()) {
return;
}
// Decide what the target size is, depending whether we're going to // Decide what the target size is, depending whether we're going to
// drain it partially (so that other tasks can steal if they run out // drain it partially (so that other tasks can steal if they run out
@ -2464,12 +2467,7 @@ void G1CMTask::drain_local_queue(bool partially) {
oop obj; oop obj;
bool ret = _task_queue->pop_local(obj); bool ret = _task_queue->pop_local(obj);
while (ret) { while (ret) {
assert(_g1h->is_in_g1_reserved((HeapWord*) obj), "invariant" );
assert(!_g1h->is_on_master_free_list(
_g1h->heap_region_containing((HeapWord*) obj)), "invariant");
scan_object(obj); scan_object(obj);
if (_task_queue->size() <= target_size || has_aborted()) { if (_task_queue->size() <= target_size || has_aborted()) {
ret = false; ret = false;
} else { } else {
@ -2880,8 +2878,6 @@ void G1CMTask::do_marking_step(double time_target_ms,
while (!has_aborted()) { while (!has_aborted()) {
oop obj; oop obj;
if (_cm->try_stealing(_worker_id, &_hash_seed, obj)) { if (_cm->try_stealing(_worker_id, &_hash_seed, obj)) {
assert(_nextMarkBitMap->isMarked((HeapWord*) obj),
"any stolen object should be marked");
scan_object(obj); scan_object(obj);
// And since we're towards the end, let's totally drain the // And since we're towards the end, let's totally drain the
@ -3003,6 +2999,7 @@ G1CMTask::G1CMTask(uint worker_id,
G1CMTaskQueueSet* task_queues) G1CMTaskQueueSet* task_queues)
: _g1h(G1CollectedHeap::heap()), : _g1h(G1CollectedHeap::heap()),
_worker_id(worker_id), _cm(cm), _worker_id(worker_id), _cm(cm),
_objArray_processor(this),
_claimed(false), _claimed(false),
_nextMarkBitMap(NULL), _hash_seed(17), _nextMarkBitMap(NULL), _hash_seed(17),
_task_queue(task_queue), _task_queue(task_queue),

View File

@ -26,6 +26,7 @@
#define SHARE_VM_GC_G1_G1CONCURRENTMARK_HPP #define SHARE_VM_GC_G1_G1CONCURRENTMARK_HPP
#include "classfile/javaClasses.hpp" #include "classfile/javaClasses.hpp"
#include "gc/g1/g1ConcurrentMarkObjArrayProcessor.hpp"
#include "gc/g1/g1RegionToSpaceMapper.hpp" #include "gc/g1/g1RegionToSpaceMapper.hpp"
#include "gc/g1/heapRegionSet.hpp" #include "gc/g1/heapRegionSet.hpp"
#include "gc/shared/taskqueue.hpp" #include "gc/shared/taskqueue.hpp"
@ -706,11 +707,13 @@ private:
words_scanned_period = 12*1024, words_scanned_period = 12*1024,
// The regular clock call is called once the number of visited // The regular clock call is called once the number of visited
// references reaches this limit // references reaches this limit
refs_reached_period = 384, refs_reached_period = 1024,
// Initial value for the hash seed, used in the work stealing code // Initial value for the hash seed, used in the work stealing code
init_hash_seed = 17 init_hash_seed = 17
}; };
G1CMObjArrayProcessor _objArray_processor;
uint _worker_id; uint _worker_id;
G1CollectedHeap* _g1h; G1CollectedHeap* _g1h;
G1ConcurrentMark* _cm; G1ConcurrentMark* _cm;
@ -826,8 +829,10 @@ private:
bool is_below_finger(oop obj, HeapWord* global_finger) const; bool is_below_finger(oop obj, HeapWord* global_finger) const;
template<bool scan> void process_grey_object(oop obj); template<bool scan> void process_grey_object(oop obj);
public: public:
// Apply the closure on the given area of the objArray. Return the number of words
// scanned.
inline size_t scan_objArray(objArrayOop obj, MemRegion mr);
// It resets the task; it should be called right at the beginning of // It resets the task; it should be called right at the beginning of
// a marking phase. // a marking phase.
void reset(G1CMBitMap* _nextMarkBitMap); void reset(G1CMBitMap* _nextMarkBitMap);

View File

@ -27,6 +27,7 @@
#include "gc/g1/g1CollectedHeap.inline.hpp" #include "gc/g1/g1CollectedHeap.inline.hpp"
#include "gc/g1/g1ConcurrentMark.hpp" #include "gc/g1/g1ConcurrentMark.hpp"
#include "gc/g1/g1ConcurrentMarkObjArrayProcessor.inline.hpp"
#include "gc/g1/suspendibleThreadSet.hpp" #include "gc/g1/suspendibleThreadSet.hpp"
#include "gc/shared/taskqueue.inline.hpp" #include "gc/shared/taskqueue.inline.hpp"
@ -117,11 +118,11 @@ inline void G1CMTask::scan_object(oop obj) { process_grey_object<true>(obj); }
inline void G1CMTask::push(oop obj) { inline void G1CMTask::push(oop obj) {
HeapWord* objAddr = (HeapWord*) obj; HeapWord* objAddr = (HeapWord*) obj;
assert(_g1h->is_in_g1_reserved(objAddr), "invariant"); assert(G1CMObjArrayProcessor::is_array_slice(obj) || _g1h->is_in_g1_reserved(objAddr), "invariant");
assert(!_g1h->is_on_master_free_list( assert(G1CMObjArrayProcessor::is_array_slice(obj) || !_g1h->is_on_master_free_list(
_g1h->heap_region_containing((HeapWord*) objAddr)), "invariant"); _g1h->heap_region_containing((HeapWord*) objAddr)), "invariant");
assert(!_g1h->is_obj_ill(obj), "invariant"); assert(G1CMObjArrayProcessor::is_array_slice(obj) || !_g1h->is_obj_ill(obj), "invariant");
assert(_nextMarkBitMap->isMarked(objAddr), "invariant"); assert(G1CMObjArrayProcessor::is_array_slice(obj) || _nextMarkBitMap->isMarked(objAddr), "invariant");
if (!_task_queue->push(obj)) { if (!_task_queue->push(obj)) {
// The local task queue looks full. We need to push some entries // The local task queue looks full. We need to push some entries
@ -169,17 +170,26 @@ inline bool G1CMTask::is_below_finger(oop obj, HeapWord* global_finger) const {
template<bool scan> template<bool scan>
inline void G1CMTask::process_grey_object(oop obj) { inline void G1CMTask::process_grey_object(oop obj) {
assert(scan || obj->is_typeArray(), "Skipping scan of grey non-typeArray"); assert(scan || obj->is_typeArray(), "Skipping scan of grey non-typeArray");
assert(_nextMarkBitMap->isMarked((HeapWord*) obj), "invariant"); assert(G1CMObjArrayProcessor::is_array_slice(obj) || _nextMarkBitMap->isMarked((HeapWord*) obj),
"Any stolen object should be a slice or marked");
size_t obj_size = obj->size();
_words_scanned += obj_size;
if (scan) { if (scan) {
obj->oop_iterate(_cm_oop_closure); if (G1CMObjArrayProcessor::is_array_slice(obj)) {
_words_scanned += _objArray_processor.process_slice(obj);
} else if (G1CMObjArrayProcessor::should_be_sliced(obj)) {
_words_scanned += _objArray_processor.process_obj(obj);
} else {
_words_scanned += obj->oop_iterate_size(_cm_oop_closure);;
}
} }
check_limits(); check_limits();
} }
inline size_t G1CMTask::scan_objArray(objArrayOop obj, MemRegion mr) {
obj->oop_iterate(_cm_oop_closure, mr);
return mr.word_size();
}
inline void G1CMTask::make_reference_grey(oop obj) { inline void G1CMTask::make_reference_grey(oop obj) {
if (_cm->par_mark(obj)) { if (_cm->par_mark(obj)) {
// No OrderAccess:store_load() is needed. It is implicit in the // No OrderAccess:store_load() is needed. It is implicit in the

View File

@ -0,0 +1,87 @@
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#include "precompiled.hpp"
#include "gc/g1/g1ConcurrentMark.inline.hpp"
#include "gc/g1/g1ConcurrentMarkObjArrayProcessor.inline.hpp"
oop G1CMObjArrayProcessor::encode_array_slice(HeapWord* addr) {
return oop((void*)((uintptr_t)addr | ArraySliceBit));
}
HeapWord* G1CMObjArrayProcessor::decode_array_slice(oop value) {
assert(is_array_slice(value), "Given value " PTR_FORMAT " is not an array slice", p2i(value));
return (HeapWord*)((uintptr_t)(void*)value & ~ArraySliceBit);
}
void G1CMObjArrayProcessor::push_array_slice(HeapWord* what) {
oop obj = encode_array_slice(what);
_task->push(obj);
}
size_t G1CMObjArrayProcessor::process_array_slice(objArrayOop obj, HeapWord* start_from, size_t remaining) {
size_t words_to_scan = MIN2(remaining, ObjArrayMarkingStride);
if (remaining > ObjArrayMarkingStride) {
push_array_slice(start_from + ObjArrayMarkingStride);
}
// Then process current area.
MemRegion mr(start_from, words_to_scan);
return _task->scan_objArray(obj, mr);
}
size_t G1CMObjArrayProcessor::process_obj(oop obj) {
assert(should_be_sliced(obj), "Must be an array object %d and large " SIZE_FORMAT, obj->is_objArray(), (size_t)obj->size());
return process_array_slice(objArrayOop(obj), (HeapWord*)obj, (size_t)objArrayOop(obj)->size());
}
size_t G1CMObjArrayProcessor::process_slice(oop obj) {
HeapWord* const decoded_address = decode_array_slice(obj);
// Find the start address of the objArrayOop.
// Shortcut the BOT access if the given address is from a humongous object. The BOT
// slide is fast enough for "smaller" objects in non-humongous regions, but is slower
// than directly using heap region table.
G1CollectedHeap* g1h = G1CollectedHeap::heap();
HeapRegion* r = g1h->heap_region_containing(decoded_address);
HeapWord* const start_address = r->is_humongous() ?
r->humongous_start_region()->bottom() :
g1h->block_start(decoded_address);
assert(oop(start_address)->is_objArray(), "Address " PTR_FORMAT " does not refer to an object array ", p2i(start_address));
assert(start_address < decoded_address,
"Object start address " PTR_FORMAT " must be smaller than decoded address " PTR_FORMAT,
p2i(start_address),
p2i(decoded_address));
objArrayOop objArray = objArrayOop(start_address);
size_t already_scanned = decoded_address - start_address;
size_t remaining = objArray->size() - already_scanned;
return process_array_slice(objArray, decoded_address, remaining);
}

View File

@ -0,0 +1,70 @@
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#ifndef SHARE_VM_GC_G1_G1CONCURRENTMARKOBJARRAYPROCESSOR_HPP
#define SHARE_VM_GC_G1_G1CONCURRENTMARKOBJARRAYPROCESSOR_HPP
#include "oops/oopsHierarchy.hpp"
#include "memory/allocation.hpp"
class G1CMTask;
// Helper class to mark through large objArrays during marking in an efficient way.
// Instead of pushing large object arrays, we push continuations onto the
// mark stack. These continuations are identified by having their LSB set.
// This allows incremental processing of large objects.
class G1CMObjArrayProcessor VALUE_OBJ_CLASS_SPEC {
private:
// The bit mask for the continuation indicator of elements on the mark stack.
static const size_t ArraySliceBit = 1;
// Reference to the task for doing the actual work.
G1CMTask* _task;
// Encodes the given address as a continuation "oop".
oop encode_array_slice(HeapWord* addr);
// Remove the continuation marker from the given oop from the mark stack.
HeapWord* decode_array_slice(oop value);
// Push the continuation at the given address onto the mark stack.
void push_array_slice(HeapWord* addr);
// Process (apply the closure) on the given continuation of the given objArray.
size_t process_array_slice(objArrayOop const obj, HeapWord* start_from, size_t remaining);
public:
static bool is_array_slice(void* obj) { return ((uintptr_t)obj & ArraySliceBit) != 0; }
static bool should_be_sliced(oop obj);
G1CMObjArrayProcessor(G1CMTask* task) : _task(task) {
}
// Process the given continuation "oop". Returns the number of words scanned.
size_t process_slice(oop obj);
// Start processing the given objArrayOop by scanning the header and pushing its
// continuation.
size_t process_obj(oop obj);
};
#endif /* SHARE_VM_GC_G1_G1CONCURRENTMARKOBJARRAYPROCESSOR_HPP */

View File

@ -0,0 +1,36 @@
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#ifndef SHARE_VM_GC_G1_G1CONCURRENTMARKOBJARRAYPROCESSOR_INLINE_HPP
#define SHARE_VM_GC_G1_G1CONCURRENTMARKOBJARRAYPROCESSOR_INLINE_HPP
#include "oops/oop.inline.hpp"
#include "oops/oopsHierarchy.hpp"
#include "runtime/globals.hpp"
inline bool G1CMObjArrayProcessor::should_be_sliced(oop obj) {
return obj->is_objArray() && ((size_t)((objArrayOop)obj)->size()) >= 2 * ObjArrayMarkingStride;
}
#endif /* SHARE_VM_GC_G1_G1CONCURRENTMARKOBJARRAYPROCESSOR_INLINE_HPP */

View File

@ -36,7 +36,9 @@
static const char* Indents[5] = {"", " ", " ", " ", " "}; static const char* Indents[5] = {"", " ", " ", " ", " "};
G1GCPhaseTimes::G1GCPhaseTimes(uint max_gc_threads) : G1GCPhaseTimes::G1GCPhaseTimes(uint max_gc_threads) :
_max_gc_threads(max_gc_threads) _max_gc_threads(max_gc_threads),
_gc_start_counter(0),
_gc_pause_time_ms(0.0)
{ {
assert(max_gc_threads > 0, "Must have some GC threads"); assert(max_gc_threads > 0, "Must have some GC threads");
@ -95,13 +97,40 @@ G1GCPhaseTimes::G1GCPhaseTimes(uint max_gc_threads) :
_gc_par_phases[NonYoungFreeCSet] = new WorkerDataArray<double>(max_gc_threads, "Non-Young Free Collection Set (ms):"); _gc_par_phases[NonYoungFreeCSet] = new WorkerDataArray<double>(max_gc_threads, "Non-Young Free Collection Set (ms):");
_gc_par_phases[PreserveCMReferents] = new WorkerDataArray<double>(max_gc_threads, "Parallel Preserve CM Refs (ms):"); _gc_par_phases[PreserveCMReferents] = new WorkerDataArray<double>(max_gc_threads, "Parallel Preserve CM Refs (ms):");
reset();
} }
void G1GCPhaseTimes::note_gc_start() { void G1GCPhaseTimes::reset() {
_gc_start_counter = os::elapsed_counter(); _cur_collection_par_time_ms = 0.0;
_cur_collection_code_root_fixup_time_ms = 0.0;
_cur_strong_code_root_purge_time_ms = 0.0;
_cur_evac_fail_recalc_used = 0.0;
_cur_evac_fail_restore_remsets = 0.0;
_cur_evac_fail_remove_self_forwards = 0.0;
_cur_string_dedup_fixup_time_ms = 0.0;
_cur_clear_ct_time_ms = 0.0;
_cur_expand_heap_time_ms = 0.0; _cur_expand_heap_time_ms = 0.0;
_cur_ref_proc_time_ms = 0.0;
_cur_ref_enq_time_ms = 0.0;
_cur_collection_start_sec = 0.0;
_root_region_scan_wait_time_ms = 0.0;
_external_accounted_time_ms = 0.0; _external_accounted_time_ms = 0.0;
_recorded_clear_claimed_marks_time_ms = 0.0; _recorded_clear_claimed_marks_time_ms = 0.0;
_recorded_young_cset_choice_time_ms = 0.0;
_recorded_non_young_cset_choice_time_ms = 0.0;
_recorded_redirty_logged_cards_time_ms = 0.0;
_recorded_preserve_cm_referents_time_ms = 0.0;
_recorded_merge_pss_time_ms = 0.0;
_recorded_total_free_cset_time_ms = 0.0;
_recorded_serial_free_cset_time_ms = 0.0;
_cur_fast_reclaim_humongous_time_ms = 0.0;
_cur_fast_reclaim_humongous_register_time_ms = 0.0;
_cur_fast_reclaim_humongous_total = 0;
_cur_fast_reclaim_humongous_candidates = 0;
_cur_fast_reclaim_humongous_reclaimed = 0;
_cur_verify_before_time_ms = 0.0;
_cur_verify_after_time_ms = 0.0;
for (int i = 0; i < GCParPhasesSentinel; i++) { for (int i = 0; i < GCParPhasesSentinel; i++) {
if (_gc_par_phases[i] != NULL) { if (_gc_par_phases[i] != NULL) {
@ -110,6 +139,11 @@ void G1GCPhaseTimes::note_gc_start() {
} }
} }
void G1GCPhaseTimes::note_gc_start() {
_gc_start_counter = os::elapsed_counter();
reset();
}
#define ASSERT_PHASE_UNINITIALIZED(phase) \ #define ASSERT_PHASE_UNINITIALIZED(phase) \
assert(_gc_par_phases[phase]->get(i) == uninitialized, "Phase " #phase " reported for thread that was not started"); assert(_gc_par_phases[phase]->get(i) == uninitialized, "Phase " #phase " reported for thread that was not started");
@ -184,7 +218,7 @@ size_t G1GCPhaseTimes::sum_thread_work_items(GCParPhases phase) {
} }
template <class T> template <class T>
void G1GCPhaseTimes::details(T* phase, const char* indent) { void G1GCPhaseTimes::details(T* phase, const char* indent) const {
Log(gc, phases, task) log; Log(gc, phases, task) log;
if (log.is_level(LogLevel::Trace)) { if (log.is_level(LogLevel::Trace)) {
outputStream* trace_out = log.trace_stream(); outputStream* trace_out = log.trace_stream();
@ -193,7 +227,7 @@ void G1GCPhaseTimes::details(T* phase, const char* indent) {
} }
} }
void G1GCPhaseTimes::log_phase(WorkerDataArray<double>* phase, uint indent, outputStream* out, bool print_sum) { void G1GCPhaseTimes::log_phase(WorkerDataArray<double>* phase, uint indent, outputStream* out, bool print_sum) const {
out->print("%s", Indents[indent]); out->print("%s", Indents[indent]);
phase->print_summary_on(out, print_sum); phase->print_summary_on(out, print_sum);
details(phase, Indents[indent]); details(phase, Indents[indent]);
@ -206,7 +240,7 @@ void G1GCPhaseTimes::log_phase(WorkerDataArray<double>* phase, uint indent, outp
} }
} }
void G1GCPhaseTimes::debug_phase(WorkerDataArray<double>* phase) { void G1GCPhaseTimes::debug_phase(WorkerDataArray<double>* phase) const {
Log(gc, phases) log; Log(gc, phases) log;
if (log.is_level(LogLevel::Debug)) { if (log.is_level(LogLevel::Debug)) {
ResourceMark rm; ResourceMark rm;
@ -214,7 +248,7 @@ void G1GCPhaseTimes::debug_phase(WorkerDataArray<double>* phase) {
} }
} }
void G1GCPhaseTimes::trace_phase(WorkerDataArray<double>* phase, bool print_sum) { void G1GCPhaseTimes::trace_phase(WorkerDataArray<double>* phase, bool print_sum) const {
Log(gc, phases) log; Log(gc, phases) log;
if (log.is_level(LogLevel::Trace)) { if (log.is_level(LogLevel::Trace)) {
ResourceMark rm; ResourceMark rm;
@ -222,37 +256,50 @@ void G1GCPhaseTimes::trace_phase(WorkerDataArray<double>* phase, bool print_sum)
} }
} }
#define PHASE_DOUBLE_FORMAT "%s%s: %.1lfms" #define TIME_FORMAT "%.1lfms"
#define PHASE_SIZE_FORMAT "%s%s: " SIZE_FORMAT
#define info_line(str, value) \ void G1GCPhaseTimes::info_time(const char* name, double value) const {
log_info(gc, phases)(PHASE_DOUBLE_FORMAT, Indents[1], str, value); log_info(gc, phases)("%s%s: " TIME_FORMAT, Indents[1], name, value);
}
#define debug_line(str, value) \ void G1GCPhaseTimes::debug_time(const char* name, double value) const {
log_debug(gc, phases)(PHASE_DOUBLE_FORMAT, Indents[2], str, value); log_debug(gc, phases)("%s%s: " TIME_FORMAT, Indents[2], name, value);
}
#define trace_line(str, value) \ void G1GCPhaseTimes::trace_time(const char* name, double value) const {
log_trace(gc, phases)(PHASE_DOUBLE_FORMAT, Indents[3], str, value); log_trace(gc, phases)("%s%s: " TIME_FORMAT, Indents[3], name, value);
}
#define trace_line_sz(str, value) \ void G1GCPhaseTimes::trace_count(const char* name, size_t value) const {
log_trace(gc, phases)(PHASE_SIZE_FORMAT, Indents[3], str, value); log_trace(gc, phases)("%s%s: " SIZE_FORMAT, Indents[3], name, value);
}
#define trace_line_ms(str, value) \ double G1GCPhaseTimes::print_pre_evacuate_collection_set() const {
log_trace(gc, phases)(PHASE_SIZE_FORMAT, Indents[3], str, value); const double sum_ms = _root_region_scan_wait_time_ms +
_recorded_young_cset_choice_time_ms +
_recorded_non_young_cset_choice_time_ms +
_cur_fast_reclaim_humongous_register_time_ms;
#define info_line_and_account(str, value) \ info_time("Pre Evacuate Collection Set", sum_ms);
info_line(str, value); \
accounted_time_ms += value;
void G1GCPhaseTimes::print() {
note_gc_end();
double accounted_time_ms = _external_accounted_time_ms;
if (_root_region_scan_wait_time_ms > 0.0) { if (_root_region_scan_wait_time_ms > 0.0) {
info_line_and_account("Root Region Scan Waiting", _root_region_scan_wait_time_ms); debug_time("Root Region Scan Waiting", _root_region_scan_wait_time_ms);
}
debug_time("Choose Collection Set", (_recorded_young_cset_choice_time_ms + _recorded_non_young_cset_choice_time_ms));
if (G1EagerReclaimHumongousObjects) {
debug_time("Humongous Register", _cur_fast_reclaim_humongous_register_time_ms);
trace_count("Humongous Total", _cur_fast_reclaim_humongous_total);
trace_count("Humongous Candidate", _cur_fast_reclaim_humongous_candidates);
} }
info_line_and_account("Evacuate Collection Set", _cur_collection_par_time_ms); return sum_ms;
}
double G1GCPhaseTimes::print_evacuate_collection_set() const {
const double sum_ms = _cur_collection_par_time_ms;
info_time("Evacuate Collection Set", sum_ms);
trace_phase(_gc_par_phases[GCWorkerStart], false); trace_phase(_gc_par_phases[GCWorkerStart], false);
debug_phase(_gc_par_phases[ExtRootScan]); debug_phase(_gc_par_phases[ExtRootScan]);
for (int i = ThreadRoots; i <= SATBFiltering; i++) { for (int i = ThreadRoots; i <= SATBFiltering; i++) {
@ -270,57 +317,98 @@ void G1GCPhaseTimes::print() {
debug_phase(_gc_par_phases[GCWorkerTotal]); debug_phase(_gc_par_phases[GCWorkerTotal]);
trace_phase(_gc_par_phases[GCWorkerEnd], false); trace_phase(_gc_par_phases[GCWorkerEnd], false);
info_line_and_account("Code Roots", _cur_collection_code_root_fixup_time_ms + _cur_strong_code_root_purge_time_ms); return sum_ms;
debug_line("Code Roots Fixup", _cur_collection_code_root_fixup_time_ms); }
debug_line("Code Roots Purge", _cur_strong_code_root_purge_time_ms);
double G1GCPhaseTimes::print_post_evacuate_collection_set() const {
const double evac_fail_handling = _cur_evac_fail_recalc_used +
_cur_evac_fail_remove_self_forwards +
_cur_evac_fail_restore_remsets;
const double sum_ms = evac_fail_handling +
_cur_collection_code_root_fixup_time_ms +
_recorded_preserve_cm_referents_time_ms +
_cur_ref_proc_time_ms +
_cur_ref_enq_time_ms +
_cur_clear_ct_time_ms +
_recorded_merge_pss_time_ms +
_cur_strong_code_root_purge_time_ms +
_recorded_redirty_logged_cards_time_ms +
_recorded_clear_claimed_marks_time_ms +
_recorded_total_free_cset_time_ms +
_cur_fast_reclaim_humongous_time_ms +
_cur_expand_heap_time_ms +
_cur_string_dedup_fixup_time_ms;
info_time("Post Evacuate Collection Set", sum_ms);
debug_time("Code Roots Fixup", _cur_collection_code_root_fixup_time_ms);
debug_time("Preserve CM Refs", _recorded_preserve_cm_referents_time_ms);
trace_phase(_gc_par_phases[PreserveCMReferents]);
debug_time("Reference Processing", _cur_ref_proc_time_ms);
if (G1StringDedup::is_enabled()) { if (G1StringDedup::is_enabled()) {
info_line_and_account("String Dedup Fixup", _cur_string_dedup_fixup_time_ms); debug_time("String Dedup Fixup", _cur_string_dedup_fixup_time_ms);
debug_phase(_gc_par_phases[StringDedupQueueFixup]); debug_phase(_gc_par_phases[StringDedupQueueFixup]);
debug_phase(_gc_par_phases[StringDedupTableFixup]); debug_phase(_gc_par_phases[StringDedupTableFixup]);
} }
info_line_and_account("Clear Card Table", _cur_clear_ct_time_ms);
info_line_and_account("Expand Heap After Collection", _cur_expand_heap_time_ms);
info_line_and_account("Free Collection Set", _recorded_total_free_cset_time_ms); debug_time("Clear Card Table", _cur_clear_ct_time_ms);
debug_line("Free Collection Set Serial", _recorded_serial_free_cset_time_ms);
debug_phase(_gc_par_phases[YoungFreeCSet]);
debug_phase(_gc_par_phases[NonYoungFreeCSet]);
info_line_and_account("Merge Per-Thread State", _recorded_merge_pss_time_ms);
info_line("Other", _gc_pause_time_ms - accounted_time_ms);
if (_cur_verify_before_time_ms > 0.0) {
debug_line("Verify Before", _cur_verify_before_time_ms);
}
if (G1CollectedHeap::heap()->evacuation_failed()) { if (G1CollectedHeap::heap()->evacuation_failed()) {
double evac_fail_handling = _cur_evac_fail_recalc_used + _cur_evac_fail_remove_self_forwards + debug_time("Evacuation Failure", evac_fail_handling);
_cur_evac_fail_restore_remsets; trace_time("Recalculate Used", _cur_evac_fail_recalc_used);
debug_line("Evacuation Failure", evac_fail_handling); trace_time("Remove Self Forwards",_cur_evac_fail_remove_self_forwards);
trace_line("Recalculate Used", _cur_evac_fail_recalc_used); trace_time("Restore RemSet", _cur_evac_fail_restore_remsets);
trace_line("Remove Self Forwards",_cur_evac_fail_remove_self_forwards);
trace_line("Restore RemSet", _cur_evac_fail_restore_remsets);
} }
debug_line("Choose CSet", (_recorded_young_cset_choice_time_ms + _recorded_non_young_cset_choice_time_ms));
debug_line("Preserve CM Refs", _recorded_preserve_cm_referents_time_ms); debug_time("Reference Enqueuing", _cur_ref_enq_time_ms);
trace_phase(_gc_par_phases[PreserveCMReferents]);
debug_line("Reference Processing", _cur_ref_proc_time_ms); debug_time("Merge Per-Thread State", _recorded_merge_pss_time_ms);
debug_line("Reference Enqueuing", _cur_ref_enq_time_ms); debug_time("Code Roots Purge", _cur_strong_code_root_purge_time_ms);
debug_line("Redirty Cards", _recorded_redirty_logged_cards_time_ms);
debug_time("Redirty Cards", _recorded_redirty_logged_cards_time_ms);
if (_recorded_clear_claimed_marks_time_ms > 0.0) { if (_recorded_clear_claimed_marks_time_ms > 0.0) {
debug_line("Clear Claimed Marks", _recorded_clear_claimed_marks_time_ms); debug_time("Clear Claimed Marks", _recorded_clear_claimed_marks_time_ms);
} }
trace_phase(_gc_par_phases[RedirtyCards]); trace_phase(_gc_par_phases[RedirtyCards]);
debug_time("Free Collection Set", _recorded_total_free_cset_time_ms);
trace_time("Free Collection Set Serial", _recorded_serial_free_cset_time_ms);
trace_phase(_gc_par_phases[YoungFreeCSet]);
trace_phase(_gc_par_phases[NonYoungFreeCSet]);
if (G1EagerReclaimHumongousObjects) { if (G1EagerReclaimHumongousObjects) {
debug_line("Humongous Register", _cur_fast_reclaim_humongous_register_time_ms); debug_time("Humongous Reclaim", _cur_fast_reclaim_humongous_time_ms);
trace_line_sz("Humongous Total", _cur_fast_reclaim_humongous_total); trace_count("Humongous Reclaimed", _cur_fast_reclaim_humongous_reclaimed);
trace_line_sz("Humongous Candidate", _cur_fast_reclaim_humongous_candidates);
debug_line("Humongous Reclaim", _cur_fast_reclaim_humongous_time_ms);
trace_line_sz("Humongous Reclaimed", _cur_fast_reclaim_humongous_reclaimed);
} }
debug_time("Expand Heap After Collection", _cur_expand_heap_time_ms);
return sum_ms;
}
void G1GCPhaseTimes::print_other(double accounted_ms) const {
info_time("Other", _gc_pause_time_ms - accounted_ms);
}
void G1GCPhaseTimes::print() {
note_gc_end();
if (_cur_verify_before_time_ms > 0.0) {
debug_time("Verify Before", _cur_verify_before_time_ms);
}
double accounted_ms = 0.0;
accounted_ms += print_pre_evacuate_collection_set();
accounted_ms += print_evacuate_collection_set();
accounted_ms += print_post_evacuate_collection_set();
print_other(accounted_ms);
if (_cur_verify_after_time_ms > 0.0) { if (_cur_verify_after_time_ms > 0.0) {
debug_line("Verify After", _cur_verify_after_time_ms); debug_time("Verify After", _cur_verify_after_time_ms);
} }
} }

View File

@ -25,6 +25,7 @@
#ifndef SHARE_VM_GC_G1_G1GCPHASETIMES_HPP #ifndef SHARE_VM_GC_G1_G1GCPHASETIMES_HPP
#define SHARE_VM_GC_G1_G1GCPHASETIMES_HPP #define SHARE_VM_GC_G1_G1GCPHASETIMES_HPP
#include "logging/logLevel.hpp"
#include "memory/allocation.hpp" #include "memory/allocation.hpp"
class LineBuffer; class LineBuffer;
@ -129,12 +130,24 @@ class G1GCPhaseTimes : public CHeapObj<mtGC> {
double worker_time(GCParPhases phase, uint worker); double worker_time(GCParPhases phase, uint worker);
void note_gc_end(); void note_gc_end();
void reset();
template <class T> template <class T>
void details(T* phase, const char* indent); void details(T* phase, const char* indent) const;
void log_phase(WorkerDataArray<double>* phase, uint indent, outputStream* out, bool print_sum);
void debug_phase(WorkerDataArray<double>* phase); void log_phase(WorkerDataArray<double>* phase, uint indent, outputStream* out, bool print_sum) const;
void trace_phase(WorkerDataArray<double>* phase, bool print_sum = true); void debug_phase(WorkerDataArray<double>* phase) const;
void trace_phase(WorkerDataArray<double>* phase, bool print_sum = true) const;
void info_time(const char* name, double value) const;
void debug_time(const char* name, double value) const;
void trace_time(const char* name, double value) const;
void trace_count(const char* name, size_t value) const;
double print_pre_evacuate_collection_set() const;
double print_evacuate_collection_set() const;
double print_post_evacuate_collection_set() const;
void print_other(double accounted_ms) const;
public: public:
G1GCPhaseTimes(uint max_gc_threads); G1GCPhaseTimes(uint max_gc_threads);

View File

@ -235,11 +235,12 @@ private:
public: public:
G1PretouchTask(char* start_address, char* end_address, size_t page_size) : G1PretouchTask(char* start_address, char* end_address, size_t page_size) :
AbstractGangTask("G1 PreTouch", AbstractGangTask("G1 PreTouch",
Universe::is_fully_initialized() ? GCId::current_raw() : Universe::is_fully_initialized() &&
// During VM initialization there is Thread::current()->is_Named_thread() ? GCId::current_raw() :
// no GC cycle that this task can be // During VM initialization there is
// associated with. // no GC cycle that this task can be
GCId::undefined()), // associated with.
GCId::undefined()),
_cur_addr(start_address), _cur_addr(start_address),
_start_addr(start_address), _start_addr(start_address),
_end_addr(end_address), _end_addr(end_address),
@ -262,15 +263,20 @@ public:
}; };
void G1PageBasedVirtualSpace::pretouch(size_t start_page, size_t size_in_pages, WorkGang* pretouch_gang) { void G1PageBasedVirtualSpace::pretouch(size_t start_page, size_t size_in_pages, WorkGang* pretouch_gang) {
guarantee(pretouch_gang != NULL, "No pretouch gang specified.");
size_t num_chunks = MAX2((size_t)1, size_in_pages * _page_size / MAX2(G1PretouchTask::chunk_size(), _page_size));
uint num_workers = MIN2((uint)num_chunks, pretouch_gang->active_workers());
G1PretouchTask cl(page_start(start_page), bounded_end_addr(start_page + size_in_pages), _page_size); G1PretouchTask cl(page_start(start_page), bounded_end_addr(start_page + size_in_pages), _page_size);
log_debug(gc, heap)("Running %s with %u workers for " SIZE_FORMAT " work units pre-touching " SIZE_FORMAT "B.",
cl.name(), num_workers, num_chunks, size_in_pages * _page_size); if (pretouch_gang != NULL) {
pretouch_gang->run_task(&cl, num_workers); size_t num_chunks = MAX2((size_t)1, size_in_pages * _page_size / MAX2(G1PretouchTask::chunk_size(), _page_size));
uint num_workers = MIN2((uint)num_chunks, pretouch_gang->active_workers());
log_debug(gc, heap)("Running %s with %u workers for " SIZE_FORMAT " work units pre-touching " SIZE_FORMAT "B.",
cl.name(), num_workers, num_chunks, size_in_pages * _page_size);
pretouch_gang->run_task(&cl, num_workers);
} else {
log_debug(gc, heap)("Running %s pre-touching " SIZE_FORMAT "B.",
cl.name(), size_in_pages * _page_size);
cl.work(0);
}
} }
bool G1PageBasedVirtualSpace::contains(const void* p) const { bool G1PageBasedVirtualSpace::contains(const void* p) const {

View File

@ -575,18 +575,26 @@ bool G1RemSet::refine_card(jbyte* card_ptr,
// And find the region containing it. // And find the region containing it.
HeapRegion* r = _g1->heap_region_containing(start); HeapRegion* r = _g1->heap_region_containing(start);
// Why do we have to check here whether a card is on a young region, // This check is needed for some uncommon cases where we should
// given that we dirty young regions and, as a result, the // ignore the card.
// post-barrier is supposed to filter them out and never to enqueue //
// them? When we allocate a new region as the "allocation region" we // The region could be young. Cards for young regions are
// actually dirty its cards after we release the lock, since card // distinctly marked (set to g1_young_gen), so the post-barrier will
// dirtying while holding the lock was a performance bottleneck. So, // filter them out. However, that marking is performed
// as a result, it is possible for other threads to actually // concurrently. A write to a young object could occur before the
// allocate objects in the region (after the acquire the lock) // card has been marked young, slipping past the filter.
// before all the cards on the region are dirtied. This is unlikely, //
// and it doesn't happen often, but it can happen. So, the extra // The card could be stale, because the region has been freed since
// check below filters out those cards. // the card was recorded. In this case the region type could be
if (r->is_young()) { // anything. If (still) free or (reallocated) young, just ignore
// it. If (reallocated) old or humongous, the later card trimming
// and additional checks in iteration may detect staleness. At
// worst, we end up processing a stale card unnecessarily.
//
// In the normal (non-stale) case, the synchronization between the
// enqueueing of the card and processing it here will have ensured
// we see the up-to-date region type here.
if (!r->is_old_or_humongous()) {
return false; return false;
} }
@ -617,26 +625,69 @@ bool G1RemSet::refine_card(jbyte* card_ptr,
assert(!check_for_refs_into_cset, "sanity"); assert(!check_for_refs_into_cset, "sanity");
assert(!SafepointSynchronize::is_at_safepoint(), "sanity"); assert(!SafepointSynchronize::is_at_safepoint(), "sanity");
const jbyte* orig_card_ptr = card_ptr;
card_ptr = _hot_card_cache->insert(card_ptr); card_ptr = _hot_card_cache->insert(card_ptr);
if (card_ptr == NULL) { if (card_ptr == NULL) {
// There was no eviction. Nothing to do. // There was no eviction. Nothing to do.
return false; return false;
} } else if (card_ptr != orig_card_ptr) {
// Original card was inserted and an old card was evicted.
start = _ct_bs->addr_for(card_ptr);
r = _g1->heap_region_containing(start);
start = _ct_bs->addr_for(card_ptr); // Check whether the region formerly in the cache should be
r = _g1->heap_region_containing(start); // ignored, as discussed earlier for the original card. The
// region could have been freed while in the cache. The cset is
// Checking whether the region we got back from the cache // not relevant here, since we're in concurrent phase.
// is young here is inappropriate. The region could have been if (!r->is_old_or_humongous()) {
// freed, reallocated and tagged as young while in the cache. return false;
// Hence we could see its young type change at any time. }
} // Else we still have the original card.
} }
// Trim the region designated by the card to what's been allocated
// in the region. The card could be stale, or the card could cover
// (part of) an object at the end of the allocated space and extend
// beyond the end of allocation.
HeapWord* scan_limit;
if (_g1->is_gc_active()) {
// If we're in a STW GC, then a card might be in a GC alloc region
// and extend onto a GC LAB, which may not be parsable. Stop such
// at the "scan_top" of the region.
scan_limit = r->scan_top();
} else {
// Non-humongous objects are only allocated in the old-gen during
// GC, so if region is old then top is stable. Humongous object
// allocation sets top last; if top has not yet been set, this is
// a stale card and we'll end up with an empty intersection. If
// this is not a stale card, the synchronization between the
// enqueuing of the card and processing it here will have ensured
// we see the up-to-date top here.
scan_limit = r->top();
}
if (scan_limit <= start) {
// If the trimmed region is empty, the card must be stale.
return false;
}
// Okay to clean and process the card now. There are still some
// stale card cases that may be detected by iteration and dealt with
// as iteration failure.
*const_cast<volatile jbyte*>(card_ptr) = CardTableModRefBS::clean_card_val();
// This fence serves two purposes. First, the card must be cleaned
// before processing the contents. Second, we can't proceed with
// processing until after the read of top, for synchronization with
// possibly concurrent humongous object allocation. It's okay that
// reading top and reading type were racy wrto each other. We need
// both set, in any order, to proceed.
OrderAccess::fence();
// Don't use addr_for(card_ptr + 1) which can ask for // Don't use addr_for(card_ptr + 1) which can ask for
// a card beyond the heap. This is not safe without a perm // a card beyond the heap.
// gen at the upper end of the heap. HeapWord* end = start + CardTableModRefBS::card_size_in_words;
HeapWord* end = start + CardTableModRefBS::card_size_in_words; MemRegion dirty_region(start, MIN2(scan_limit, end));
MemRegion dirtyRegion(start, end); assert(!dirty_region.is_empty(), "sanity");
G1UpdateRSOrPushRefOopClosure update_rs_oop_cl(_g1, G1UpdateRSOrPushRefOopClosure update_rs_oop_cl(_g1,
_g1->g1_rem_set(), _g1->g1_rem_set(),
@ -655,29 +706,15 @@ bool G1RemSet::refine_card(jbyte* card_ptr,
(OopClosure*)&mux : (OopClosure*)&mux :
(OopClosure*)&update_rs_oop_cl)); (OopClosure*)&update_rs_oop_cl));
// The region for the current card may be a young region. The
// current card may have been a card that was evicted from the
// card cache. When the card was inserted into the cache, we had
// determined that its region was non-young. While in the cache,
// the region may have been freed during a cleanup pause, reallocated
// and tagged as young.
//
// We wish to filter out cards for such a region but the current
// thread, if we're running concurrently, may "see" the young type
// change at any time (so an earlier "is_young" check may pass or
// fail arbitrarily). We tell the iteration code to perform this
// filtering when it has been determined that there has been an actual
// allocation in this region and making it safe to check the young type.
bool card_processed = bool card_processed =
r->oops_on_card_seq_iterate_careful(dirtyRegion, r->oops_on_card_seq_iterate_careful(dirty_region,
&filter_then_update_rs_oop_cl, &filter_then_update_rs_oop_cl);
card_ptr);
// If unable to process the card then we encountered an unparsable // If unable to process the card then we encountered an unparsable
// part of the heap (e.g. a partially allocated object). Redirty // part of the heap (e.g. a partially allocated object) while
// and re-enqueue: if we put off the card until a GC pause, then the // processing a stale card. Despite the card being stale, redirty
// allocation will have completed. // and re-enqueue, because we've already cleaned the card. Without
// this we could incorrectly discard a non-stale card.
if (!card_processed) { if (!card_processed) {
assert(!_g1->is_gc_active(), "Unparsable heap during GC"); assert(!_g1->is_gc_active(), "Unparsable heap during GC");
// The card might have gotten re-dirtied and re-enqueued while we // The card might have gotten re-dirtied and re-enqueued while we

View File

@ -178,44 +178,37 @@ G1SATBCardTableLoggingModRefBS::write_ref_field_work(void* field,
} }
void void
G1SATBCardTableLoggingModRefBS::invalidate(MemRegion mr, bool whole_heap) { G1SATBCardTableLoggingModRefBS::invalidate(MemRegion mr) {
volatile jbyte* byte = byte_for(mr.start()); volatile jbyte* byte = byte_for(mr.start());
jbyte* last_byte = byte_for(mr.last()); jbyte* last_byte = byte_for(mr.last());
Thread* thr = Thread::current(); Thread* thr = Thread::current();
if (whole_heap) {
while (byte <= last_byte) {
*byte = dirty_card;
byte++;
}
} else {
// skip all consecutive young cards // skip all consecutive young cards
for (; byte <= last_byte && *byte == g1_young_gen; byte++); for (; byte <= last_byte && *byte == g1_young_gen; byte++);
if (byte <= last_byte) { if (byte <= last_byte) {
OrderAccess::storeload(); OrderAccess::storeload();
// Enqueue if necessary. // Enqueue if necessary.
if (thr->is_Java_thread()) { if (thr->is_Java_thread()) {
JavaThread* jt = (JavaThread*)thr; JavaThread* jt = (JavaThread*)thr;
for (; byte <= last_byte; byte++) { for (; byte <= last_byte; byte++) {
if (*byte == g1_young_gen) { if (*byte == g1_young_gen) {
continue; continue;
}
if (*byte != dirty_card) {
*byte = dirty_card;
jt->dirty_card_queue().enqueue(byte);
}
} }
} else { if (*byte != dirty_card) {
MutexLockerEx x(Shared_DirtyCardQ_lock, *byte = dirty_card;
Mutex::_no_safepoint_check_flag); jt->dirty_card_queue().enqueue(byte);
for (; byte <= last_byte; byte++) { }
if (*byte == g1_young_gen) { }
continue; } else {
} MutexLockerEx x(Shared_DirtyCardQ_lock,
if (*byte != dirty_card) { Mutex::_no_safepoint_check_flag);
*byte = dirty_card; for (; byte <= last_byte; byte++) {
_dcqs.shared_dirty_card_queue()->enqueue(byte); if (*byte == g1_young_gen) {
} continue;
}
if (*byte != dirty_card) {
*byte = dirty_card;
_dcqs.shared_dirty_card_queue()->enqueue(byte);
} }
} }
} }

View File

@ -152,7 +152,7 @@ class G1SATBCardTableLoggingModRefBS: public G1SATBCardTableModRefBS {
// NB: if you do a whole-heap invalidation, the "usual invariant" defined // NB: if you do a whole-heap invalidation, the "usual invariant" defined
// above no longer applies. // above no longer applies.
void invalidate(MemRegion mr, bool whole_heap = false); void invalidate(MemRegion mr);
void write_region_work(MemRegion mr) { invalidate(mr); } void write_region_work(MemRegion mr) { invalidate(mr); }
void write_ref_array_work(MemRegion mr) { invalidate(mr); } void write_ref_array_work(MemRegion mr) { invalidate(mr); }

View File

@ -352,89 +352,101 @@ void HeapRegion::note_self_forwarding_removal_end(bool during_initial_mark,
_prev_marked_bytes = marked_bytes; _prev_marked_bytes = marked_bytes;
} }
// Humongous objects are allocated directly in the old-gen. Need
// special handling for concurrent processing encountering an
// in-progress allocation.
static bool do_oops_on_card_in_humongous(MemRegion mr,
FilterOutOfRegionClosure* cl,
HeapRegion* hr,
G1CollectedHeap* g1h) {
assert(hr->is_humongous(), "precondition");
HeapRegion* sr = hr->humongous_start_region();
oop obj = oop(sr->bottom());
// If concurrent and klass_or_null is NULL, then space has been
// allocated but the object has not yet been published by setting
// the klass. That can only happen if the card is stale. However,
// we've already set the card clean, so we must return failure,
// since the allocating thread could have performed a write to the
// card that might be missed otherwise.
if (!g1h->is_gc_active() && (obj->klass_or_null_acquire() == NULL)) {
return false;
}
// We have a well-formed humongous object at the start of sr.
// Only filler objects follow a humongous object in the containing
// regions, and we can ignore those. So only process the one
// humongous object.
if (!g1h->is_obj_dead(obj, sr)) {
if (obj->is_objArray() || (sr->bottom() < mr.start())) {
// objArrays are always marked precisely, so limit processing
// with mr. Non-objArrays might be precisely marked, and since
// it's humongous it's worthwhile avoiding full processing.
// However, the card could be stale and only cover filler
// objects. That should be rare, so not worth checking for;
// instead let it fall out from the bounded iteration.
obj->oop_iterate(cl, mr);
} else {
// If obj is not an objArray and mr contains the start of the
// obj, then this could be an imprecise mark, and we need to
// process the entire object.
obj->oop_iterate(cl);
}
}
return true;
}
bool HeapRegion::oops_on_card_seq_iterate_careful(MemRegion mr, bool HeapRegion::oops_on_card_seq_iterate_careful(MemRegion mr,
FilterOutOfRegionClosure* cl, FilterOutOfRegionClosure* cl) {
jbyte* card_ptr) { assert(MemRegion(bottom(), end()).contains(mr), "Card region not in heap region");
assert(card_ptr != NULL, "pre-condition");
G1CollectedHeap* g1h = G1CollectedHeap::heap(); G1CollectedHeap* g1h = G1CollectedHeap::heap();
// If we're within a stop-world GC, then we might look at a card in a // Special handling for humongous regions.
// GC alloc region that extends onto a GC LAB, which may not be if (is_humongous()) {
// parseable. Stop such at the "scan_top" of the region. return do_oops_on_card_in_humongous(mr, cl, this, g1h);
if (g1h->is_gc_active()) {
mr = mr.intersection(MemRegion(bottom(), scan_top()));
} else {
mr = mr.intersection(used_region());
} }
if (mr.is_empty()) { assert(is_old(), "precondition");
return true;
}
// Otherwise, find the obj that extends onto mr.start().
// The intersection of the incoming mr (for the card) and the // Because mr has been trimmed to what's been allocated in this
// allocated part of the region is non-empty. This implies that // region, the parts of the heap that are examined here are always
// we have actually allocated into this region. The code in // parsable; there's no need to use klass_or_null to detect
// G1CollectedHeap.cpp that allocates a new region sets the // in-progress allocation.
// is_young tag on the region before allocating. Thus we
// safely know if this region is young.
if (is_young()) {
return true;
}
// We can only clean the card here, after we make the decision that
// the card is not young.
*card_ptr = CardTableModRefBS::clean_card_val();
// We must complete this write before we do any of the reads below.
OrderAccess::storeload();
// Cache the boundaries of the memory region in some const locals // Cache the boundaries of the memory region in some const locals
HeapWord* const start = mr.start(); HeapWord* const start = mr.start();
HeapWord* const end = mr.end(); HeapWord* const end = mr.end();
// Update BOT as needed while finding start of (potential) object. // Find the obj that extends onto mr.start().
// Update BOT as needed while finding start of (possibly dead)
// object containing the start of the region.
HeapWord* cur = block_start(start); HeapWord* cur = block_start(start);
assert(cur <= start, "Postcondition");
oop obj; #ifdef ASSERT
{
HeapWord* next = cur; assert(cur <= start,
do { "cur: " PTR_FORMAT ", start: " PTR_FORMAT, p2i(cur), p2i(start));
cur = next; HeapWord* next = cur + block_size(cur);
obj = oop(cur); assert(start < next,
if (obj->klass_or_null() == NULL) { "start: " PTR_FORMAT ", next: " PTR_FORMAT, p2i(start), p2i(next));
// Ran into an unparseable point. }
assert(!g1h->is_gc_active(), #endif
"Unparsable heap during GC at " PTR_FORMAT, p2i(cur));
return false;
}
// Otherwise...
next = cur + block_size(cur);
} while (next <= start);
// If we finish the above loop...We have a parseable object that
// begins on or before the start of the memory region, and ends
// inside or spans the entire region.
assert(cur <= start, "Loop postcondition");
assert(obj->klass_or_null() != NULL, "Loop postcondition");
do { do {
obj = oop(cur); oop obj = oop(cur);
assert((cur + block_size(cur)) > (HeapWord*)obj, "Loop invariant"); assert(obj->is_oop(true), "Not an oop at " PTR_FORMAT, p2i(cur));
if (obj->klass_or_null() == NULL) { assert(obj->klass_or_null() != NULL,
// Ran into an unparseable point. "Unparsable heap at " PTR_FORMAT, p2i(cur));
assert(!g1h->is_gc_active(),
"Unparsable heap during GC at " PTR_FORMAT, p2i(cur));
return false;
}
// Advance the current pointer. "obj" still points to the object to iterate. if (g1h->is_obj_dead(obj, this)) {
cur = cur + block_size(cur); // Carefully step over dead object.
cur += block_size(cur);
if (!g1h->is_obj_dead(obj)) { } else {
// Non-objArrays are sometimes marked imprecise at the object start. We // Step over live object, and process its references.
// always need to iterate over them in full. cur += obj->size();
// We only iterate over object arrays in full if they are completely contained // Non-objArrays are usually marked imprecise at the object
// in the memory region. // start, in which case we need to iterate over them in full.
// objArrays are precisely marked, but can still be iterated
// over in full if completely covered.
if (!obj->is_objArray() || (((HeapWord*)obj) >= start && cur <= end)) { if (!obj->is_objArray() || (((HeapWord*)obj) >= start && cur <= end)) {
obj->oop_iterate(cl); obj->oop_iterate(cl);
} else { } else {

View File

@ -51,8 +51,9 @@
// object is larger than a heap region, the following regions will // object is larger than a heap region, the following regions will
// be of type ContinuesHumongous. In this case the top() of the // be of type ContinuesHumongous. In this case the top() of the
// StartHumongous region and all ContinuesHumongous regions except // StartHumongous region and all ContinuesHumongous regions except
// the last will point to their own end. For the last ContinuesHumongous // the last will point to their own end. The last ContinuesHumongous
// region, top() will equal the object's top. // region may have top() equal the end of object if there isn't
// room for filler objects to pad out to the end of the region.
class G1CollectedHeap; class G1CollectedHeap;
class HeapRegionRemSet; class HeapRegionRemSet;
@ -433,6 +434,8 @@ class HeapRegion: public G1ContiguousSpace {
bool is_old() const { return _type.is_old(); } bool is_old() const { return _type.is_old(); }
bool is_old_or_humongous() const { return _type.is_old_or_humongous(); }
// A pinned region contains objects which are not moved by garbage collections. // A pinned region contains objects which are not moved by garbage collections.
// Humongous regions and archive regions are pinned. // Humongous regions and archive regions are pinned.
bool is_pinned() const { return _type.is_pinned(); } bool is_pinned() const { return _type.is_pinned(); }
@ -653,17 +656,18 @@ class HeapRegion: public G1ContiguousSpace {
} }
} }
// Iterate over the card in the card designated by card_ptr, // Iterate over the objects overlapping part of a card, applying cl
// applying cl to all references in the region. // to all references in the region. This is a helper for
// mr: the memory region covered by the card. // G1RemSet::refine_card, and is tightly coupled with it.
// card_ptr: if we decide that the card is not young and we iterate // mr: the memory region covered by the card, trimmed to the
// over it, we'll clean the card before we start the iteration. // allocated space for this region. Must not be empty.
// Returns true if card was successfully processed, false if an // This region must be old or humongous.
// unparsable part of the heap was encountered, which should only // Returns true if the designated objects were successfully
// happen when invoked concurrently with the mutator. // processed, false if an unparsable part of the heap was
// encountered; that only happens when invoked concurrently with the
// mutator.
bool oops_on_card_seq_iterate_careful(MemRegion mr, bool oops_on_card_seq_iterate_careful(MemRegion mr,
FilterOutOfRegionClosure* cl, FilterOutOfRegionClosure* cl);
jbyte* card_ptr);
size_t recorded_rs_length() const { return _recorded_rs_length; } size_t recorded_rs_length() const { return _recorded_rs_length; }
double predicted_elapsed_time_ms() const { return _predicted_elapsed_time_ms; } double predicted_elapsed_time_ms() const { return _predicted_elapsed_time_ms; }

View File

@ -286,7 +286,7 @@ uint HeapRegionManager::find_highest_free(bool* expanded) {
while (true) { while (true) {
HeapRegion *hr = _regions.get_by_index(curr); HeapRegion *hr = _regions.get_by_index(curr);
if (hr == NULL) { if (hr == NULL) {
uint res = expand_at(curr, 1); uint res = expand_at(curr, 1, NULL);
if (res == 1) { if (res == 1) {
*expanded = true; *expanded = true;
return curr; return curr;
@ -304,7 +304,7 @@ uint HeapRegionManager::find_highest_free(bool* expanded) {
} }
} }
bool HeapRegionManager::allocate_containing_regions(MemRegion range, size_t* commit_count) { bool HeapRegionManager::allocate_containing_regions(MemRegion range, size_t* commit_count, WorkGang* pretouch_workers) {
size_t commits = 0; size_t commits = 0;
uint start_index = (uint)_regions.get_index_by_address(range.start()); uint start_index = (uint)_regions.get_index_by_address(range.start());
uint last_index = (uint)_regions.get_index_by_address(range.last()); uint last_index = (uint)_regions.get_index_by_address(range.last());
@ -314,7 +314,7 @@ bool HeapRegionManager::allocate_containing_regions(MemRegion range, size_t* com
for (uint curr_index = start_index; curr_index <= last_index; curr_index++) { for (uint curr_index = start_index; curr_index <= last_index; curr_index++) {
if (!is_available(curr_index)) { if (!is_available(curr_index)) {
commits++; commits++;
expand_at(curr_index, 1); expand_at(curr_index, 1, pretouch_workers);
} }
HeapRegion* curr_region = _regions.get_by_index(curr_index); HeapRegion* curr_region = _regions.get_by_index(curr_index);
if (!curr_region->is_free()) { if (!curr_region->is_free()) {

View File

@ -210,12 +210,12 @@ public:
// HeapRegions, or re-use existing ones. Returns the number of regions the // HeapRegions, or re-use existing ones. Returns the number of regions the
// sequence was expanded by. If a HeapRegion allocation fails, the resulting // sequence was expanded by. If a HeapRegion allocation fails, the resulting
// number of regions might be smaller than what's desired. // number of regions might be smaller than what's desired.
uint expand_by(uint num_regions, WorkGang* pretouch_workers = NULL); uint expand_by(uint num_regions, WorkGang* pretouch_workers);
// Makes sure that the regions from start to start+num_regions-1 are available // Makes sure that the regions from start to start+num_regions-1 are available
// for allocation. Returns the number of regions that were committed to achieve // for allocation. Returns the number of regions that were committed to achieve
// this. // this.
uint expand_at(uint start, uint num_regions, WorkGang* pretouch_workers = NULL); uint expand_at(uint start, uint num_regions, WorkGang* pretouch_workers);
// Find a contiguous set of empty regions of length num. Returns the start index of // Find a contiguous set of empty regions of length num. Returns the start index of
// that set, or G1_NO_HRM_INDEX. // that set, or G1_NO_HRM_INDEX.
@ -234,7 +234,7 @@ public:
// Allocate the regions that contain the address range specified, committing the // Allocate the regions that contain the address range specified, committing the
// regions if necessary. Return false if any of the regions is already committed // regions if necessary. Return false if any of the regions is already committed
// and not free, and return the number of regions newly committed in commit_count. // and not free, and return the number of regions newly committed in commit_count.
bool allocate_containing_regions(MemRegion range, size_t* commit_count); bool allocate_containing_regions(MemRegion range, size_t* commit_count, WorkGang* pretouch_workers);
// Apply blk->doHeapRegion() on all committed regions in address order, // Apply blk->doHeapRegion() on all committed regions in address order,
// terminating the iteration early if doHeapRegion() returns true. // terminating the iteration early if doHeapRegion() returns true.

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -120,6 +120,8 @@ public:
// is_old regions may or may not also be pinned // is_old regions may or may not also be pinned
bool is_old() const { return (get() & OldMask) != 0; } bool is_old() const { return (get() & OldMask) != 0; }
bool is_old_or_humongous() const { return (get() & (OldMask | HumongousMask)) != 0; }
// is_pinned regions may be archive or humongous // is_pinned regions may be archive or humongous
bool is_pinned() const { return (get() & PinnedMask) != 0; } bool is_pinned() const { return (get() & PinnedMask) != 0; }

View File

@ -380,7 +380,7 @@ void CardTableModRefBS::dirty_MemRegion(MemRegion mr) {
} }
} }
void CardTableModRefBS::invalidate(MemRegion mr, bool whole_heap) { void CardTableModRefBS::invalidate(MemRegion mr) {
assert((HeapWord*)align_size_down((uintptr_t)mr.start(), HeapWordSize) == mr.start(), "Unaligned start"); assert((HeapWord*)align_size_down((uintptr_t)mr.start(), HeapWordSize) == mr.start(), "Unaligned start");
assert((HeapWord*)align_size_up ((uintptr_t)mr.end(), HeapWordSize) == mr.end(), "Unaligned end" ); assert((HeapWord*)align_size_up ((uintptr_t)mr.end(), HeapWordSize) == mr.end(), "Unaligned end" );
for (int i = 0; i < _cur_covered_regions; i++) { for (int i = 0; i < _cur_covered_regions; i++) {

View File

@ -260,7 +260,7 @@ public:
} }
// ModRefBS functions. // ModRefBS functions.
virtual void invalidate(MemRegion mr, bool whole_heap = false); virtual void invalidate(MemRegion mr);
void clear(MemRegion mr); void clear(MemRegion mr);
void dirty(MemRegion mr); void dirty(MemRegion mr);

View File

@ -159,8 +159,8 @@ public:
void clear(MemRegion mr) { _ct_bs->clear(mr); } void clear(MemRegion mr) { _ct_bs->clear(mr); }
void clear_into_younger(Generation* old_gen); void clear_into_younger(Generation* old_gen);
void invalidate(MemRegion mr, bool whole_heap = false) { void invalidate(MemRegion mr) {
_ct_bs->invalidate(mr, whole_heap); _ct_bs->invalidate(mr);
} }
void invalidate_or_clear(Generation* old_gen); void invalidate_or_clear(Generation* old_gen);

View File

@ -601,34 +601,3 @@ void CollectedHeap::initialize_reserved_region(HeapWord *start, HeapWord *end) {
_reserved.set_start(start); _reserved.set_start(start);
_reserved.set_end(end); _reserved.set_end(end);
} }
/////////////// Unit tests ///////////////
#ifndef PRODUCT
void CollectedHeap::test_is_in() {
CollectedHeap* heap = Universe::heap();
uintptr_t epsilon = (uintptr_t) MinObjAlignment;
uintptr_t heap_start = (uintptr_t) heap->_reserved.start();
uintptr_t heap_end = (uintptr_t) heap->_reserved.end();
// Test that NULL is not in the heap.
assert(!heap->is_in(NULL), "NULL is unexpectedly in the heap");
// Test that a pointer to before the heap start is reported as outside the heap.
assert(heap_start >= ((uintptr_t)NULL + epsilon), "sanity");
void* before_heap = (void*)(heap_start - epsilon);
assert(!heap->is_in(before_heap),
"before_heap: " PTR_FORMAT " is unexpectedly in the heap", p2i(before_heap));
// Test that a pointer to after the heap end is reported as outside the heap.
assert(heap_end <= ((uintptr_t)-1 - epsilon), "sanity");
void* after_heap = (void*)(heap_end + epsilon);
assert(!heap->is_in(after_heap),
"after_heap: " PTR_FORMAT " is unexpectedly in the heap", p2i(after_heap));
}
void CollectedHeap_test() {
CollectedHeap::test_is_in();
}
#endif

View File

@ -612,9 +612,6 @@ class CollectedHeap : public CHeapObj<mtInternal> {
return false; return false;
} }
/////////////// Unit tests ///////////////
NOT_PRODUCT(static void test_is_in();)
}; };
// Class to set and reset the GC cause for a CollectedHeap. // Class to set and reset the GC cause for a CollectedHeap.

View File

@ -86,10 +86,8 @@ public:
assert(false, "can't call"); assert(false, "can't call");
} }
// Causes all refs in "mr" to be assumed to be modified. If "whole_heap" // Causes all refs in "mr" to be assumed to be modified.
// is true, the caller asserts that the entire heap is being invalidated, virtual void invalidate(MemRegion mr) = 0;
// which may admit an optimized implementation for some barriers.
virtual void invalidate(MemRegion mr, bool whole_heap = false) = 0;
// The caller guarantees that "mr" contains no references. (Perhaps it's // The caller guarantees that "mr" contains no references. (Perhaps it's
// objects have been moved elsewhere.) // objects have been moved elsewhere.)

View File

@ -124,29 +124,19 @@ AbstractInterpreter::MethodKind AbstractInterpreter::method_kind(methodHandle m)
} }
#ifndef CC_INTERP #ifndef CC_INTERP
if (UseCRC32Intrinsics && m->is_native()) { switch (m->intrinsic_id()) {
// Use optimized stub code for CRC32 native methods. // Use optimized stub code for CRC32 native methods.
switch (m->intrinsic_id()) { case vmIntrinsics::_updateCRC32 : return java_util_zip_CRC32_update;
case vmIntrinsics::_updateCRC32 : return java_util_zip_CRC32_update; case vmIntrinsics::_updateBytesCRC32 : return java_util_zip_CRC32_updateBytes;
case vmIntrinsics::_updateBytesCRC32 : return java_util_zip_CRC32_updateBytes; case vmIntrinsics::_updateByteBufferCRC32 : return java_util_zip_CRC32_updateByteBuffer;
case vmIntrinsics::_updateByteBufferCRC32 : return java_util_zip_CRC32_updateByteBuffer;
}
}
if (UseCRC32CIntrinsics) {
// Use optimized stub code for CRC32C methods. // Use optimized stub code for CRC32C methods.
switch (m->intrinsic_id()) { case vmIntrinsics::_updateBytesCRC32C : return java_util_zip_CRC32C_updateBytes;
case vmIntrinsics::_updateBytesCRC32C : return java_util_zip_CRC32C_updateBytes; case vmIntrinsics::_updateDirectByteBufferCRC32C : return java_util_zip_CRC32C_updateDirectByteBuffer;
case vmIntrinsics::_updateDirectByteBufferCRC32C : return java_util_zip_CRC32C_updateDirectByteBuffer; case vmIntrinsics::_intBitsToFloat: return java_lang_Float_intBitsToFloat;
} case vmIntrinsics::_floatToRawIntBits: return java_lang_Float_floatToRawIntBits;
case vmIntrinsics::_longBitsToDouble: return java_lang_Double_longBitsToDouble;
case vmIntrinsics::_doubleToRawLongBits: return java_lang_Double_doubleToRawLongBits;
} }
switch(m->intrinsic_id()) {
case vmIntrinsics::_intBitsToFloat: return java_lang_Float_intBitsToFloat;
case vmIntrinsics::_floatToRawIntBits: return java_lang_Float_floatToRawIntBits;
case vmIntrinsics::_longBitsToDouble: return java_lang_Double_longBitsToDouble;
case vmIntrinsics::_doubleToRawLongBits: return java_lang_Double_doubleToRawLongBits;
}
#endif // CC_INTERP #endif // CC_INTERP
// Native method? // Native method?
@ -189,18 +179,13 @@ AbstractInterpreter::MethodKind AbstractInterpreter::method_kind(methodHandle m)
case vmIntrinsics::_dlog10: return java_lang_math_log10; case vmIntrinsics::_dlog10: return java_lang_math_log10;
case vmIntrinsics::_dpow : return java_lang_math_pow ; case vmIntrinsics::_dpow : return java_lang_math_pow ;
case vmIntrinsics::_dexp : return java_lang_math_exp ; case vmIntrinsics::_dexp : return java_lang_math_exp ;
case vmIntrinsics::_fmaD : return java_lang_math_fmaD ;
case vmIntrinsics::_fmaF : return java_lang_math_fmaF ;
case vmIntrinsics::_Reference_get: case vmIntrinsics::_Reference_get:
return java_lang_ref_reference_get; return java_lang_ref_reference_get;
} }
if (UseFMA) {
switch (m->intrinsic_id()) {
case vmIntrinsics::_fmaD: return java_lang_math_fmaD;
case vmIntrinsics::_fmaF: return java_lang_math_fmaF;
}
}
// Accessor method? // Accessor method?
if (m->is_getter()) { if (m->is_getter()) {
// TODO: We should have used ::is_accessor above, but fast accessors in Zero expect only getters. // TODO: We should have used ::is_accessor above, but fast accessors in Zero expect only getters.

View File

@ -239,10 +239,8 @@ void TemplateInterpreterGenerator::generate_all() {
method_entry(java_lang_math_log10) method_entry(java_lang_math_log10)
method_entry(java_lang_math_exp ) method_entry(java_lang_math_exp )
method_entry(java_lang_math_pow ) method_entry(java_lang_math_pow )
if (UseFMA) { method_entry(java_lang_math_fmaF )
method_entry(java_lang_math_fmaF) method_entry(java_lang_math_fmaD )
method_entry(java_lang_math_fmaD)
}
method_entry(java_lang_ref_reference_get) method_entry(java_lang_ref_reference_get)
AbstractInterpreter::initialize_method_handle_entries(); AbstractInterpreter::initialize_method_handle_entries();
@ -253,16 +251,11 @@ void TemplateInterpreterGenerator::generate_all() {
method_entry(native_synchronized) method_entry(native_synchronized)
Interpreter::_native_entry_end = Interpreter::code()->code_end(); Interpreter::_native_entry_end = Interpreter::code()->code_end();
if (UseCRC32Intrinsics) { method_entry(java_util_zip_CRC32_update)
method_entry(java_util_zip_CRC32_update) method_entry(java_util_zip_CRC32_updateBytes)
method_entry(java_util_zip_CRC32_updateBytes) method_entry(java_util_zip_CRC32_updateByteBuffer)
method_entry(java_util_zip_CRC32_updateByteBuffer) method_entry(java_util_zip_CRC32C_updateBytes)
} method_entry(java_util_zip_CRC32C_updateDirectByteBuffer)
if (UseCRC32CIntrinsics) {
method_entry(java_util_zip_CRC32C_updateBytes)
method_entry(java_util_zip_CRC32C_updateDirectByteBuffer)
}
method_entry(java_lang_Float_intBitsToFloat); method_entry(java_lang_Float_intBitsToFloat);
method_entry(java_lang_Float_floatToRawIntBits); method_entry(java_lang_Float_floatToRawIntBits);
@ -451,7 +444,7 @@ address TemplateInterpreterGenerator::generate_method_entry(
case Interpreter::java_lang_math_pow : // fall thru case Interpreter::java_lang_math_pow : // fall thru
case Interpreter::java_lang_math_exp : // fall thru case Interpreter::java_lang_math_exp : // fall thru
case Interpreter::java_lang_math_fmaD : // fall thru case Interpreter::java_lang_math_fmaD : // fall thru
case Interpreter::java_lang_math_fmaF : entry_point = generate_math_entry(kind); break; case Interpreter::java_lang_math_fmaF : entry_point = generate_math_entry(kind); break;
case Interpreter::java_lang_ref_reference_get case Interpreter::java_lang_ref_reference_get
: entry_point = generate_Reference_get_entry(); break; : entry_point = generate_Reference_get_entry(); break;
case Interpreter::java_util_zip_CRC32_update case Interpreter::java_util_zip_CRC32_update

View File

@ -280,8 +280,25 @@
static_field(StubRoutines, _aescrypt_decryptBlock, address) \ static_field(StubRoutines, _aescrypt_decryptBlock, address) \
static_field(StubRoutines, _cipherBlockChaining_encryptAESCrypt, address) \ static_field(StubRoutines, _cipherBlockChaining_encryptAESCrypt, address) \
static_field(StubRoutines, _cipherBlockChaining_decryptAESCrypt, address) \ static_field(StubRoutines, _cipherBlockChaining_decryptAESCrypt, address) \
static_field(StubRoutines, _counterMode_AESCrypt, address) \
static_field(StubRoutines, _ghash_processBlocks, address) \
static_field(StubRoutines, _sha1_implCompress, address) \
static_field(StubRoutines, _sha1_implCompressMB, address) \
static_field(StubRoutines, _sha256_implCompress, address) \
static_field(StubRoutines, _sha256_implCompressMB, address) \
static_field(StubRoutines, _sha512_implCompress, address) \
static_field(StubRoutines, _sha512_implCompressMB, address) \
static_field(StubRoutines, _updateBytesCRC32, address) \ static_field(StubRoutines, _updateBytesCRC32, address) \
static_field(StubRoutines, _crc_table_adr, address) \ static_field(StubRoutines, _crc_table_adr, address) \
static_field(StubRoutines, _crc32c_table_addr, address) \
static_field(StubRoutines, _updateBytesCRC32C, address) \
static_field(StubRoutines, _updateBytesAdler32, address) \
static_field(StubRoutines, _multiplyToLen, address) \
static_field(StubRoutines, _squareToLen, address) \
static_field(StubRoutines, _mulAdd, address) \
static_field(StubRoutines, _montgomeryMultiply, address) \
static_field(StubRoutines, _montgomerySquare, address) \
static_field(StubRoutines, _vectorizedMismatch, address) \
\ \
nonstatic_field(Thread, _tlab, ThreadLocalAllocBuffer) \ nonstatic_field(Thread, _tlab, ThreadLocalAllocBuffer) \
nonstatic_field(Thread, _allocated_bytes, jlong) \ nonstatic_field(Thread, _allocated_bytes, jlong) \

View File

@ -153,7 +153,7 @@ class ChunkManager : public CHeapObj<mtInternal> {
// Map a size to a list index assuming that there are lists // Map a size to a list index assuming that there are lists
// for special, small, medium, and humongous chunks. // for special, small, medium, and humongous chunks.
static ChunkIndex list_index(size_t size); ChunkIndex list_index(size_t size);
// Remove the chunk from its freelist. It is // Remove the chunk from its freelist. It is
// expected to be on one of the _free_chunks[] lists. // expected to be on one of the _free_chunks[] lists.
@ -489,6 +489,10 @@ VirtualSpaceNode::VirtualSpaceNode(size_t bytes) : _top(NULL), _next(NULL), _rs(
// Get a mmap region anywhere if the SharedBaseAddress fails. // Get a mmap region anywhere if the SharedBaseAddress fails.
_rs = ReservedSpace(bytes, Metaspace::reserve_alignment(), large_pages); _rs = ReservedSpace(bytes, Metaspace::reserve_alignment(), large_pages);
} }
if (!_rs.is_reserved()) {
vm_exit_during_initialization("Unable to allocate memory for shared space",
err_msg(SIZE_FORMAT " bytes.", bytes));
}
MetaspaceShared::initialize_shared_rs(&_rs); MetaspaceShared::initialize_shared_rs(&_rs);
} else } else
#endif #endif
@ -592,9 +596,8 @@ class VirtualSpaceList : public CHeapObj<mtClass> {
size_t free_bytes(); size_t free_bytes();
Metachunk* get_new_chunk(size_t word_size, Metachunk* get_new_chunk(size_t chunk_word_size,
size_t grow_chunks_by_words, size_t suggested_commit_granularity);
size_t medium_chunk_bunch);
bool expand_node_by(VirtualSpaceNode* node, bool expand_node_by(VirtualSpaceNode* node,
size_t min_words, size_t min_words,
@ -745,15 +748,22 @@ class SpaceManager : public CHeapObj<mtClass> {
MediumChunkMultiple = 4 MediumChunkMultiple = 4
}; };
bool is_class() { return _mdtype == Metaspace::ClassType; } static size_t specialized_chunk_size(bool is_class) { return is_class ? ClassSpecializedChunk : SpecializedChunk; }
static size_t small_chunk_size(bool is_class) { return is_class ? ClassSmallChunk : SmallChunk; }
static size_t medium_chunk_size(bool is_class) { return is_class ? ClassMediumChunk : MediumChunk; }
static size_t smallest_chunk_size(bool is_class) { return specialized_chunk_size(is_class); }
// Accessors // Accessors
size_t specialized_chunk_size() { return (size_t) is_class() ? ClassSpecializedChunk : SpecializedChunk; } bool is_class() const { return _mdtype == Metaspace::ClassType; }
size_t small_chunk_size() { return (size_t) is_class() ? ClassSmallChunk : SmallChunk; }
size_t medium_chunk_size() { return (size_t) is_class() ? ClassMediumChunk : MediumChunk; }
size_t medium_chunk_bunch() { return medium_chunk_size() * MediumChunkMultiple; }
size_t smallest_chunk_size() { return specialized_chunk_size(); } size_t specialized_chunk_size() const { return specialized_chunk_size(is_class()); }
size_t small_chunk_size() const { return small_chunk_size(is_class()); }
size_t medium_chunk_size() const { return medium_chunk_size(is_class()); }
size_t smallest_chunk_size() const { return smallest_chunk_size(is_class()); }
size_t medium_chunk_bunch() const { return medium_chunk_size() * MediumChunkMultiple; }
size_t allocated_blocks_words() const { return _allocated_blocks_words; } size_t allocated_blocks_words() const { return _allocated_blocks_words; }
size_t allocated_blocks_bytes() const { return _allocated_blocks_words * BytesPerWord; } size_t allocated_blocks_bytes() const { return _allocated_blocks_words * BytesPerWord; }
@ -777,10 +787,13 @@ class SpaceManager : public CHeapObj<mtClass> {
// decremented for all the Metachunks in-use by this SpaceManager. // decremented for all the Metachunks in-use by this SpaceManager.
void dec_total_from_size_metrics(); void dec_total_from_size_metrics();
// Set the sizes for the initial chunks. // Adjust the initial chunk size to match one of the fixed chunk list sizes,
void get_initial_chunk_sizes(Metaspace::MetaspaceType type, // or return the unadjusted size if the requested size is humongous.
size_t* chunk_word_size, static size_t adjust_initial_chunk_size(size_t requested, bool is_class_space);
size_t* class_chunk_word_size); size_t adjust_initial_chunk_size(size_t requested) const;
// Get the initial chunks size for this metaspace type.
size_t get_initial_chunk_size(Metaspace::MetaspaceType type) const;
size_t sum_capacity_in_chunks_in_use() const; size_t sum_capacity_in_chunks_in_use() const;
size_t sum_used_in_chunks_in_use() const; size_t sum_used_in_chunks_in_use() const;
@ -791,7 +804,7 @@ class SpaceManager : public CHeapObj<mtClass> {
size_t sum_count_in_chunks_in_use(); size_t sum_count_in_chunks_in_use();
size_t sum_count_in_chunks_in_use(ChunkIndex i); size_t sum_count_in_chunks_in_use(ChunkIndex i);
Metachunk* get_new_chunk(size_t word_size, size_t grow_chunks_by_words); Metachunk* get_new_chunk(size_t chunk_word_size);
// Block allocation and deallocation. // Block allocation and deallocation.
// Allocates a block from the current chunk // Allocates a block from the current chunk
@ -1396,12 +1409,10 @@ bool VirtualSpaceList::expand_by(size_t min_words, size_t preferred_words) {
return false; return false;
} }
Metachunk* VirtualSpaceList::get_new_chunk(size_t word_size, Metachunk* VirtualSpaceList::get_new_chunk(size_t chunk_word_size, size_t suggested_commit_granularity) {
size_t grow_chunks_by_words,
size_t medium_chunk_bunch) {
// Allocate a chunk out of the current virtual space. // Allocate a chunk out of the current virtual space.
Metachunk* next = current_virtual_space()->get_chunk_vs(grow_chunks_by_words); Metachunk* next = current_virtual_space()->get_chunk_vs(chunk_word_size);
if (next != NULL) { if (next != NULL) {
return next; return next;
@ -1410,8 +1421,8 @@ Metachunk* VirtualSpaceList::get_new_chunk(size_t word_size,
// The expand amount is currently only determined by the requested sizes // The expand amount is currently only determined by the requested sizes
// and not how much committed memory is left in the current virtual space. // and not how much committed memory is left in the current virtual space.
size_t min_word_size = align_size_up(grow_chunks_by_words, Metaspace::commit_alignment_words()); size_t min_word_size = align_size_up(chunk_word_size, Metaspace::commit_alignment_words());
size_t preferred_word_size = align_size_up(medium_chunk_bunch, Metaspace::commit_alignment_words()); size_t preferred_word_size = align_size_up(suggested_commit_granularity, Metaspace::commit_alignment_words());
if (min_word_size >= preferred_word_size) { if (min_word_size >= preferred_word_size) {
// Can happen when humongous chunks are allocated. // Can happen when humongous chunks are allocated.
preferred_word_size = min_word_size; preferred_word_size = min_word_size;
@ -1419,7 +1430,7 @@ Metachunk* VirtualSpaceList::get_new_chunk(size_t word_size,
bool expanded = expand_by(min_word_size, preferred_word_size); bool expanded = expand_by(min_word_size, preferred_word_size);
if (expanded) { if (expanded) {
next = current_virtual_space()->get_chunk_vs(grow_chunks_by_words); next = current_virtual_space()->get_chunk_vs(chunk_word_size);
assert(next != NULL, "The allocation was expected to succeed after the expansion"); assert(next != NULL, "The allocation was expected to succeed after the expansion");
} }
@ -1783,7 +1794,11 @@ void ChunkManager::locked_print_sum_free_chunks(outputStream* st) {
st->print_cr("Sum free chunk total " SIZE_FORMAT " count " SIZE_FORMAT, st->print_cr("Sum free chunk total " SIZE_FORMAT " count " SIZE_FORMAT,
sum_free_chunks(), sum_free_chunks_count()); sum_free_chunks(), sum_free_chunks_count());
} }
ChunkList* ChunkManager::free_chunks(ChunkIndex index) { ChunkList* ChunkManager::free_chunks(ChunkIndex index) {
assert(index == SpecializedIndex || index == SmallIndex || index == MediumIndex,
"Bad index: %d", (int)index);
return &_free_chunks[index]; return &_free_chunks[index];
} }
@ -1887,7 +1902,7 @@ Metachunk* ChunkManager::chunk_freelist_allocate(size_t word_size) {
} }
assert((word_size <= chunk->word_size()) || assert((word_size <= chunk->word_size()) ||
list_index(chunk->word_size() == HumongousIndex), (list_index(chunk->word_size()) == HumongousIndex),
"Non-humongous variable sized chunk"); "Non-humongous variable sized chunk");
Log(gc, metaspace, freelist) log; Log(gc, metaspace, freelist) log;
if (log.is_debug()) { if (log.is_debug()) {
@ -1913,36 +1928,58 @@ void ChunkManager::print_on(outputStream* out) const {
// SpaceManager methods // SpaceManager methods
void SpaceManager::get_initial_chunk_sizes(Metaspace::MetaspaceType type, size_t SpaceManager::adjust_initial_chunk_size(size_t requested, bool is_class_space) {
size_t* chunk_word_size, size_t chunk_sizes[] = {
size_t* class_chunk_word_size) { specialized_chunk_size(is_class_space),
switch (type) { small_chunk_size(is_class_space),
case Metaspace::BootMetaspaceType: medium_chunk_size(is_class_space)
*chunk_word_size = Metaspace::first_chunk_word_size(); };
*class_chunk_word_size = Metaspace::first_class_chunk_word_size();
break; // Adjust up to one of the fixed chunk sizes ...
case Metaspace::ROMetaspaceType: for (size_t i = 0; i < ARRAY_SIZE(chunk_sizes); i++) {
*chunk_word_size = SharedReadOnlySize / wordSize; if (requested <= chunk_sizes[i]) {
*class_chunk_word_size = ClassSpecializedChunk; return chunk_sizes[i];
break; }
case Metaspace::ReadWriteMetaspaceType:
*chunk_word_size = SharedReadWriteSize / wordSize;
*class_chunk_word_size = ClassSpecializedChunk;
break;
case Metaspace::AnonymousMetaspaceType:
case Metaspace::ReflectionMetaspaceType:
*chunk_word_size = SpecializedChunk;
*class_chunk_word_size = ClassSpecializedChunk;
break;
default:
*chunk_word_size = SmallChunk;
*class_chunk_word_size = ClassSmallChunk;
break;
} }
assert(*chunk_word_size != 0 && *class_chunk_word_size != 0,
"Initial chunks sizes bad: data " SIZE_FORMAT // ... or return the size as a humongous chunk.
" class " SIZE_FORMAT, return requested;
*chunk_word_size, *class_chunk_word_size); }
size_t SpaceManager::adjust_initial_chunk_size(size_t requested) const {
return adjust_initial_chunk_size(requested, is_class());
}
size_t SpaceManager::get_initial_chunk_size(Metaspace::MetaspaceType type) const {
size_t requested;
if (is_class()) {
switch (type) {
case Metaspace::BootMetaspaceType: requested = Metaspace::first_class_chunk_word_size(); break;
case Metaspace::ROMetaspaceType: requested = ClassSpecializedChunk; break;
case Metaspace::ReadWriteMetaspaceType: requested = ClassSpecializedChunk; break;
case Metaspace::AnonymousMetaspaceType: requested = ClassSpecializedChunk; break;
case Metaspace::ReflectionMetaspaceType: requested = ClassSpecializedChunk; break;
default: requested = ClassSmallChunk; break;
}
} else {
switch (type) {
case Metaspace::BootMetaspaceType: requested = Metaspace::first_chunk_word_size(); break;
case Metaspace::ROMetaspaceType: requested = SharedReadOnlySize / wordSize; break;
case Metaspace::ReadWriteMetaspaceType: requested = SharedReadWriteSize / wordSize; break;
case Metaspace::AnonymousMetaspaceType: requested = SpecializedChunk; break;
case Metaspace::ReflectionMetaspaceType: requested = SpecializedChunk; break;
default: requested = SmallChunk; break;
}
}
// Adjust to one of the fixed chunk sizes (unless humongous)
const size_t adjusted = adjust_initial_chunk_size(requested);
assert(adjusted != 0, "Incorrect initial chunk size. Requested: "
SIZE_FORMAT " adjusted: " SIZE_FORMAT, requested, adjusted);
return adjusted;
} }
size_t SpaceManager::sum_free_in_chunks_in_use() const { size_t SpaceManager::sum_free_in_chunks_in_use() const {
@ -2127,8 +2164,8 @@ MetaWord* SpaceManager::grow_and_allocate(size_t word_size) {
} }
// Get another chunk // Get another chunk
size_t grow_chunks_by_words = calc_chunk_size(word_size); size_t chunk_word_size = calc_chunk_size(word_size);
Metachunk* next = get_new_chunk(word_size, grow_chunks_by_words); Metachunk* next = get_new_chunk(chunk_word_size);
MetaWord* mem = NULL; MetaWord* mem = NULL;
@ -2338,22 +2375,18 @@ const char* SpaceManager::chunk_size_name(ChunkIndex index) const {
} }
ChunkIndex ChunkManager::list_index(size_t size) { ChunkIndex ChunkManager::list_index(size_t size) {
switch (size) { if (free_chunks(SpecializedIndex)->size() == size) {
case SpecializedChunk: return SpecializedIndex;
assert(SpecializedChunk == ClassSpecializedChunk,
"Need branch for ClassSpecializedChunk");
return SpecializedIndex;
case SmallChunk:
case ClassSmallChunk:
return SmallIndex;
case MediumChunk:
case ClassMediumChunk:
return MediumIndex;
default:
assert(size > MediumChunk || size > ClassMediumChunk,
"Not a humongous chunk");
return HumongousIndex;
} }
if (free_chunks(SmallIndex)->size() == size) {
return SmallIndex;
}
if (free_chunks(MediumIndex)->size() == size) {
return MediumIndex;
}
assert(size > free_chunks(MediumIndex)->size(), "Not a humongous chunk");
return HumongousIndex;
} }
void SpaceManager::deallocate(MetaWord* p, size_t word_size) { void SpaceManager::deallocate(MetaWord* p, size_t word_size) {
@ -2377,7 +2410,7 @@ void SpaceManager::add_chunk(Metachunk* new_chunk, bool make_current) {
// Find the correct list and and set the current // Find the correct list and and set the current
// chunk for that list. // chunk for that list.
ChunkIndex index = ChunkManager::list_index(new_chunk->word_size()); ChunkIndex index = chunk_manager()->list_index(new_chunk->word_size());
if (index != HumongousIndex) { if (index != HumongousIndex) {
retire_current_chunk(); retire_current_chunk();
@ -2427,14 +2460,12 @@ void SpaceManager::retire_current_chunk() {
} }
} }
Metachunk* SpaceManager::get_new_chunk(size_t word_size, Metachunk* SpaceManager::get_new_chunk(size_t chunk_word_size) {
size_t grow_chunks_by_words) {
// Get a chunk from the chunk freelist // Get a chunk from the chunk freelist
Metachunk* next = chunk_manager()->chunk_freelist_allocate(grow_chunks_by_words); Metachunk* next = chunk_manager()->chunk_freelist_allocate(chunk_word_size);
if (next == NULL) { if (next == NULL) {
next = vs_list()->get_new_chunk(word_size, next = vs_list()->get_new_chunk(chunk_word_size,
grow_chunks_by_words,
medium_chunk_bunch()); medium_chunk_bunch());
} }
@ -3172,7 +3203,7 @@ void Metaspace::initialize_class_space(ReservedSpace rs) {
SIZE_FORMAT " != " SIZE_FORMAT, rs.size(), CompressedClassSpaceSize); SIZE_FORMAT " != " SIZE_FORMAT, rs.size(), CompressedClassSpaceSize);
assert(using_class_space(), "Must be using class space"); assert(using_class_space(), "Must be using class space");
_class_space_list = new VirtualSpaceList(rs); _class_space_list = new VirtualSpaceList(rs);
_chunk_manager_class = new ChunkManager(SpecializedChunk, ClassSmallChunk, ClassMediumChunk); _chunk_manager_class = new ChunkManager(ClassSpecializedChunk, ClassSmallChunk, ClassMediumChunk);
if (!_class_space_list->initialization_succeeded()) { if (!_class_space_list->initialization_succeeded()) {
vm_exit_during_initialization("Failed to setup compressed class space virtual space list."); vm_exit_during_initialization("Failed to setup compressed class space virtual space list.");
@ -3342,75 +3373,62 @@ void Metaspace::post_initialize() {
MetaspaceGC::post_initialize(); MetaspaceGC::post_initialize();
} }
Metachunk* Metaspace::get_initialization_chunk(MetadataType mdtype, void Metaspace::initialize_first_chunk(MetaspaceType type, MetadataType mdtype) {
size_t chunk_word_size, Metachunk* chunk = get_initialization_chunk(type, mdtype);
size_t chunk_bunch) { if (chunk != NULL) {
// Add to this manager's list of chunks in use and current_chunk().
get_space_manager(mdtype)->add_chunk(chunk, true);
}
}
Metachunk* Metaspace::get_initialization_chunk(MetaspaceType type, MetadataType mdtype) {
size_t chunk_word_size = get_space_manager(mdtype)->get_initial_chunk_size(type);
// Get a chunk from the chunk freelist // Get a chunk from the chunk freelist
Metachunk* chunk = get_chunk_manager(mdtype)->chunk_freelist_allocate(chunk_word_size); Metachunk* chunk = get_chunk_manager(mdtype)->chunk_freelist_allocate(chunk_word_size);
if (chunk != NULL) {
return chunk; if (chunk == NULL) {
chunk = get_space_list(mdtype)->get_new_chunk(chunk_word_size,
get_space_manager(mdtype)->medium_chunk_bunch());
} }
return get_space_list(mdtype)->get_new_chunk(chunk_word_size, chunk_word_size, chunk_bunch); // For dumping shared archive, report error if allocation has failed.
if (DumpSharedSpaces && chunk == NULL) {
report_insufficient_metaspace(MetaspaceAux::committed_bytes() + chunk_word_size * BytesPerWord);
}
return chunk;
}
void Metaspace::verify_global_initialization() {
assert(space_list() != NULL, "Metadata VirtualSpaceList has not been initialized");
assert(chunk_manager_metadata() != NULL, "Metadata ChunkManager has not been initialized");
if (using_class_space()) {
assert(class_space_list() != NULL, "Class VirtualSpaceList has not been initialized");
assert(chunk_manager_class() != NULL, "Class ChunkManager has not been initialized");
}
} }
void Metaspace::initialize(Mutex* lock, MetaspaceType type) { void Metaspace::initialize(Mutex* lock, MetaspaceType type) {
verify_global_initialization();
assert(space_list() != NULL, // Allocate SpaceManager for metadata objects.
"Metadata VirtualSpaceList has not been initialized");
assert(chunk_manager_metadata() != NULL,
"Metadata ChunkManager has not been initialized");
_vsm = new SpaceManager(NonClassType, lock); _vsm = new SpaceManager(NonClassType, lock);
if (_vsm == NULL) {
return;
}
size_t word_size;
size_t class_word_size;
vsm()->get_initial_chunk_sizes(type, &word_size, &class_word_size);
if (using_class_space()) { if (using_class_space()) {
assert(class_space_list() != NULL,
"Class VirtualSpaceList has not been initialized");
assert(chunk_manager_class() != NULL,
"Class ChunkManager has not been initialized");
// Allocate SpaceManager for classes. // Allocate SpaceManager for classes.
_class_vsm = new SpaceManager(ClassType, lock); _class_vsm = new SpaceManager(ClassType, lock);
if (_class_vsm == NULL) {
return;
}
} }
MutexLockerEx cl(SpaceManager::expand_lock(), Mutex::_no_safepoint_check_flag); MutexLockerEx cl(SpaceManager::expand_lock(), Mutex::_no_safepoint_check_flag);
// Allocate chunk for metadata objects // Allocate chunk for metadata objects
Metachunk* new_chunk = get_initialization_chunk(NonClassType, initialize_first_chunk(type, NonClassType);
word_size,
vsm()->medium_chunk_bunch());
// For dumping shared archive, report error if allocation has failed.
if (DumpSharedSpaces && new_chunk == NULL) {
report_insufficient_metaspace(MetaspaceAux::committed_bytes() + word_size * BytesPerWord);
}
assert(!DumpSharedSpaces || new_chunk != NULL, "should have enough space for both chunks");
if (new_chunk != NULL) {
// Add to this manager's list of chunks in use and current_chunk().
vsm()->add_chunk(new_chunk, true);
}
// Allocate chunk for class metadata objects // Allocate chunk for class metadata objects
if (using_class_space()) { if (using_class_space()) {
Metachunk* class_chunk = get_initialization_chunk(ClassType, initialize_first_chunk(type, ClassType);
class_word_size,
class_vsm()->medium_chunk_bunch());
if (class_chunk != NULL) {
class_vsm()->add_chunk(class_chunk, true);
} else {
// For dumping shared archive, report error if allocation has failed.
if (DumpSharedSpaces) {
report_insufficient_metaspace(MetaspaceAux::committed_bytes() + class_word_size * BytesPerWord);
}
}
} }
_alloc_record_head = NULL; _alloc_record_head = NULL;
@ -3836,7 +3854,7 @@ class TestMetaspaceAuxTest : AllStatic {
// vm_allocation_granularity aligned on Windows. // vm_allocation_granularity aligned on Windows.
size_t large_size = (size_t)(2*256*K + (os::vm_page_size()/BytesPerWord)); size_t large_size = (size_t)(2*256*K + (os::vm_page_size()/BytesPerWord));
large_size += (os::vm_page_size()/BytesPerWord); large_size += (os::vm_page_size()/BytesPerWord);
vs_list->get_new_chunk(large_size, large_size, 0); vs_list->get_new_chunk(large_size, 0);
} }
static void test() { static void test() {
@ -4013,4 +4031,91 @@ void TestVirtualSpaceNode_test() {
TestVirtualSpaceNodeTest::test(); TestVirtualSpaceNodeTest::test();
TestVirtualSpaceNodeTest::test_is_available(); TestVirtualSpaceNodeTest::test_is_available();
} }
// The following test is placed here instead of a gtest / unittest file
// because the ChunkManager class is only available in this file.
void ChunkManager_test_list_index() {
ChunkManager manager(ClassSpecializedChunk, ClassSmallChunk, ClassMediumChunk);
// Test previous bug where a query for a humongous class metachunk,
// incorrectly matched the non-class medium metachunk size.
{
assert(MediumChunk > ClassMediumChunk, "Precondition for test");
ChunkIndex index = manager.list_index(MediumChunk);
assert(index == HumongousIndex,
"Requested size is larger than ClassMediumChunk,"
" so should return HumongousIndex. Got index: %d", (int)index);
}
// Check the specified sizes as well.
{
ChunkIndex index = manager.list_index(ClassSpecializedChunk);
assert(index == SpecializedIndex, "Wrong index returned. Got index: %d", (int)index);
}
{
ChunkIndex index = manager.list_index(ClassSmallChunk);
assert(index == SmallIndex, "Wrong index returned. Got index: %d", (int)index);
}
{
ChunkIndex index = manager.list_index(ClassMediumChunk);
assert(index == MediumIndex, "Wrong index returned. Got index: %d", (int)index);
}
{
ChunkIndex index = manager.list_index(ClassMediumChunk + 1);
assert(index == HumongousIndex, "Wrong index returned. Got index: %d", (int)index);
}
}
// The following test is placed here instead of a gtest / unittest file
// because the ChunkManager class is only available in this file.
class SpaceManagerTest : AllStatic {
friend void SpaceManager_test_adjust_initial_chunk_size();
static void test_adjust_initial_chunk_size(bool is_class) {
const size_t smallest = SpaceManager::smallest_chunk_size(is_class);
const size_t normal = SpaceManager::small_chunk_size(is_class);
const size_t medium = SpaceManager::medium_chunk_size(is_class);
#define test_adjust_initial_chunk_size(value, expected, is_class_value) \
do { \
size_t v = value; \
size_t e = expected; \
assert(SpaceManager::adjust_initial_chunk_size(v, (is_class_value)) == e, \
"Expected: " SIZE_FORMAT " got: " SIZE_FORMAT, e, v); \
} while (0)
// Smallest (specialized)
test_adjust_initial_chunk_size(1, smallest, is_class);
test_adjust_initial_chunk_size(smallest - 1, smallest, is_class);
test_adjust_initial_chunk_size(smallest, smallest, is_class);
// Small
test_adjust_initial_chunk_size(smallest + 1, normal, is_class);
test_adjust_initial_chunk_size(normal - 1, normal, is_class);
test_adjust_initial_chunk_size(normal, normal, is_class);
// Medium
test_adjust_initial_chunk_size(normal + 1, medium, is_class);
test_adjust_initial_chunk_size(medium - 1, medium, is_class);
test_adjust_initial_chunk_size(medium, medium, is_class);
// Humongous
test_adjust_initial_chunk_size(medium + 1, medium + 1, is_class);
#undef test_adjust_initial_chunk_size
}
static void test_adjust_initial_chunk_size() {
test_adjust_initial_chunk_size(false);
test_adjust_initial_chunk_size(true);
}
};
void SpaceManager_test_adjust_initial_chunk_size() {
SpaceManagerTest::test_adjust_initial_chunk_size();
}
#endif #endif

View File

@ -105,14 +105,15 @@ class Metaspace : public CHeapObj<mtClass> {
}; };
private: private:
static void verify_global_initialization();
void initialize(Mutex* lock, MetaspaceType type); void initialize(Mutex* lock, MetaspaceType type);
// Get the first chunk for a Metaspace. Used for // Initialize the first chunk for a Metaspace. Used for
// special cases such as the boot class loader, reflection // special cases such as the boot class loader, reflection
// class loader and anonymous class loader. // class loader and anonymous class loader.
Metachunk* get_initialization_chunk(MetadataType mdtype, void initialize_first_chunk(MetaspaceType type, MetadataType mdtype);
size_t chunk_word_size, Metachunk* get_initialization_chunk(MetaspaceType type, MetadataType mdtype);
size_t chunk_bunch);
// Align up the word size to the allocation word size // Align up the word size to the allocation word size
static size_t align_word_size_up(size_t); static size_t align_word_size_up(size_t);
@ -139,6 +140,10 @@ class Metaspace : public CHeapObj<mtClass> {
SpaceManager* _class_vsm; SpaceManager* _class_vsm;
SpaceManager* class_vsm() const { return _class_vsm; } SpaceManager* class_vsm() const { return _class_vsm; }
SpaceManager* get_space_manager(MetadataType mdtype) {
assert(mdtype != MetadataTypeCount, "MetadaTypeCount can't be used as mdtype");
return mdtype == ClassType ? class_vsm() : vsm();
}
// Allocate space for metadata of type mdtype. This is space // Allocate space for metadata of type mdtype. This is space
// within a Metachunk and is used by // within a Metachunk and is used by

View File

@ -205,7 +205,7 @@ private:
// Adapter blob (i2c/c2i) for this Method*. Set once when method is linked. // Adapter blob (i2c/c2i) for this Method*. Set once when method is linked.
union { union {
AdapterHandlerEntry* _adapter; AdapterHandlerEntry* _adapter;
AdapterHandlerEntry** _adapter_trampoline; AdapterHandlerEntry** _adapter_trampoline; // see comments around Method::link_method()
}; };
int _constMethod_size; int _constMethod_size;

View File

@ -953,34 +953,103 @@ void Method::unlink_method() {
} }
#endif #endif
/****************************************************************************
// The following illustrates how the entries work for CDS shared Methods:
//
// Our goal is to delay writing into a shared Method until it's compiled.
// Hence, we want to determine the initial values for _i2i_entry,
// _from_interpreted_entry and _from_compiled_entry during CDS dump time.
//
// In this example, both Methods A and B have the _i2i_entry of "zero_locals".
// They also have similar signatures so that they will share the same
// AdapterHandlerEntry.
//
// _adapter_trampoline points to a fixed location in the RW section of
// the CDS archive. This location initially contains a NULL pointer. When the
// first of method A or B is linked, an AdapterHandlerEntry is allocated
// dynamically, and its c2i/i2c entries are generated.
//
// _i2i_entry and _from_interpreted_entry initially points to the same
// (fixed) location in the CODE section of the CDS archive. This contains
// an unconditional branch to the actual entry for "zero_locals", which is
// generated at run time and may be on an arbitrary address. Thus, the
// unconditional branch is also generated at run time to jump to the correct
// address.
//
// Similarly, _from_compiled_entry points to a fixed address in the CODE
// section. This address has enough space for an unconditional branch
// instruction, and is initially zero-filled. After the AdapterHandlerEntry is
// initialized, and the address for the actual c2i_entry is known, we emit a
// branch instruction here to branch to the actual c2i_entry.
//
// The effect of the extra branch on the i2i and c2i entries is negligible.
//
// The reason for putting _adapter_trampoline in RO is many shared Methods
// share the same AdapterHandlerEntry, so we can save space in the RW section
// by having the extra indirection.
[Method A: RW]
_constMethod ----> [ConstMethod: RO]
_adapter_trampoline -----------+
|
_i2i_entry (same value as method B) |
_from_interpreted_entry (same value as method B) |
_from_compiled_entry (same value as method B) |
|
|
[Method B: RW] +--------+
_constMethod ----> [ConstMethod: RO] |
_adapter_trampoline --+--->(AdapterHandlerEntry* ptr: RW)-+
|
+-------------------------------+
|
+----> [AdapterHandlerEntry] (allocated at run time)
_fingerprint
_c2i_entry ---------------------------------+->[c2i entry..]
_i2i_entry -------------+ _i2c_entry ---------------+-> [i2c entry..] |
_from_interpreted_entry | _c2i_unverified_entry | |
| | | |
| | (_cds_entry_table: CODE) | |
| +->[0]: jmp _entry_table[0] --> (i2i_entry_for "zero_locals") | |
| | (allocated at run time) | |
| | ... [asm code ...] | |
+-[not compiled]-+ [n]: jmp _entry_table[n] | |
| | |
| | |
+-[compiled]-------------------------------------------------------------------+ |
|
_from_compiled_entry------------> (_c2i_entry_trampoline: CODE) |
[jmp c2i_entry] ------------------------------------------------------+
***/
// Called when the method_holder is getting linked. Setup entrypoints so the method // Called when the method_holder is getting linked. Setup entrypoints so the method
// is ready to be called from interpreter, compiler, and vtables. // is ready to be called from interpreter, compiler, and vtables.
void Method::link_method(const methodHandle& h_method, TRAPS) { void Method::link_method(const methodHandle& h_method, TRAPS) {
// If the code cache is full, we may reenter this function for the // If the code cache is full, we may reenter this function for the
// leftover methods that weren't linked. // leftover methods that weren't linked.
if (is_shared()) { if (is_shared()) {
if (adapter() != NULL) return; address entry = Interpreter::entry_for_cds_method(h_method);
} else { assert(entry != NULL && entry == _i2i_entry,
if (_i2i_entry != NULL) return; "should be correctly set during dump time");
if (adapter() != NULL) {
assert(adapter() == NULL, "init'd to NULL" ); return;
}
assert(entry == _from_interpreted_entry,
"should be correctly set during dump time");
} else if (_i2i_entry != NULL) {
return;
} }
assert( _code == NULL, "nothing compiled yet" ); assert( _code == NULL, "nothing compiled yet" );
// Setup interpreter entrypoint // Setup interpreter entrypoint
assert(this == h_method(), "wrong h_method()" ); assert(this == h_method(), "wrong h_method()" );
address entry;
if (this->is_shared()) { if (!is_shared()) {
entry = Interpreter::entry_for_cds_method(h_method); assert(adapter() == NULL, "init'd to NULL");
} else { address entry = Interpreter::entry_for_method(h_method);
entry = Interpreter::entry_for_method(h_method); assert(entry != NULL, "interpreter entry must be non-null");
}
assert(entry != NULL, "interpreter entry must be non-null");
if (is_shared()) {
assert(entry == _i2i_entry && entry == _from_interpreted_entry,
"should be correctly set during dump time");
} else {
// Sets both _i2i_entry and _from_interpreted_entry // Sets both _i2i_entry and _from_interpreted_entry
set_interpreter_entry(entry); set_interpreter_entry(entry);
} }
@ -1024,7 +1093,7 @@ address Method::make_adapters(methodHandle mh, TRAPS) {
if (mh->is_shared()) { if (mh->is_shared()) {
assert(mh->adapter() == adapter, "must be"); assert(mh->adapter() == adapter, "must be");
assert(mh->_from_compiled_entry != NULL, "must be"); // FIXME, the instructions also not NULL assert(mh->_from_compiled_entry != NULL, "must be");
} else { } else {
mh->set_adapter_entry(adapter); mh->set_adapter_entry(adapter);
mh->_from_compiled_entry = adapter->get_c2i_entry(); mh->_from_compiled_entry = adapter->get_c2i_entry();
@ -1034,9 +1103,9 @@ address Method::make_adapters(methodHandle mh, TRAPS) {
void Method::restore_unshareable_info(TRAPS) { void Method::restore_unshareable_info(TRAPS) {
// Since restore_unshareable_info can be called more than once for a method, don't // Since restore_unshareable_info can be called more than once for a method, don't
// redo any work. If this field is restored, there is nothing to do. // redo any work.
if (_from_compiled_entry == NULL) { if (adapter() == NULL) {
// restore method's vtable by calling a virtual function // Restore Method's C++ vtable by calling a virtual function
restore_vtable(); restore_vtable();
methodHandle mh(THREAD, this); methodHandle mh(THREAD, this);

View File

@ -5513,7 +5513,7 @@ bool LibraryCallKit::inline_montgomeryMultiply() {
} }
assert(UseMontgomeryMultiplyIntrinsic, "not implemented on this platform"); assert(UseMontgomeryMultiplyIntrinsic, "not implemented on this platform");
const char* stubName = "montgomery_square"; const char* stubName = "montgomery_multiply";
assert(callee()->signature()->size() == 7, "montgomeryMultiply has 7 parameters"); assert(callee()->signature()->size() == 7, "montgomeryMultiply has 7 parameters");

View File

@ -1742,7 +1742,7 @@ void PhaseIdealLoop::mark_reductions(IdealLoopTree *loop) {
// The result of the reduction must not be used in the loop // The result of the reduction must not be used in the loop
for (DUIterator_Fast imax, i = def_node->fast_outs(imax); i < imax && ok; i++) { for (DUIterator_Fast imax, i = def_node->fast_outs(imax); i < imax && ok; i++) {
Node* u = def_node->fast_out(i); Node* u = def_node->fast_out(i);
if (has_ctrl(u) && !loop->is_member(get_loop(get_ctrl(u)))) { if (!loop->is_member(get_loop(ctrl_or_self(u)))) {
continue; continue;
} }
if (u == phi) { if (u == phi) {

View File

@ -1117,8 +1117,8 @@ bool Node::has_special_unique_user() const {
if (this->is_Store()) { if (this->is_Store()) {
// Condition for back-to-back stores folding. // Condition for back-to-back stores folding.
return n->Opcode() == op && n->in(MemNode::Memory) == this; return n->Opcode() == op && n->in(MemNode::Memory) == this;
} else if (this->is_Load()) { } else if (this->is_Load() || this->is_DecodeN()) {
// Condition for removing an unused LoadNode from the MemBarAcquire precedence input // Condition for removing an unused LoadNode or DecodeNNode from the MemBarAcquire precedence input
return n->Opcode() == Op_MemBarAcquire; return n->Opcode() == Op_MemBarAcquire;
} else if (op == Op_AddL) { } else if (op == Op_AddL) {
// Condition for convL2I(addL(x,y)) ==> addI(convL2I(x),convL2I(y)) // Condition for convL2I(addL(x,y)) ==> addI(convL2I(x),convL2I(y))

View File

@ -378,6 +378,7 @@ static SpecialFlag const special_jvm_flags[] = {
{ "AutoGCSelectPauseMillis", JDK_Version::jdk(9), JDK_Version::undefined(), JDK_Version::jdk(10) }, { "AutoGCSelectPauseMillis", JDK_Version::jdk(9), JDK_Version::undefined(), JDK_Version::jdk(10) },
{ "UseAutoGCSelectPolicy", JDK_Version::jdk(9), JDK_Version::undefined(), JDK_Version::jdk(10) }, { "UseAutoGCSelectPolicy", JDK_Version::jdk(9), JDK_Version::undefined(), JDK_Version::jdk(10) },
{ "UseParNewGC", JDK_Version::jdk(9), JDK_Version::undefined(), JDK_Version::jdk(10) }, { "UseParNewGC", JDK_Version::jdk(9), JDK_Version::undefined(), JDK_Version::jdk(10) },
{ "ExplicitGCInvokesConcurrentAndUnloadsClasses", JDK_Version::jdk(9), JDK_Version::undefined(), JDK_Version::jdk(10) },
{ "ConvertSleepToYield", JDK_Version::jdk(9), JDK_Version::jdk(10), JDK_Version::jdk(11) }, { "ConvertSleepToYield", JDK_Version::jdk(9), JDK_Version::jdk(10), JDK_Version::jdk(11) },
{ "ConvertYieldToSleep", JDK_Version::jdk(9), JDK_Version::jdk(10), JDK_Version::jdk(11) }, { "ConvertYieldToSleep", JDK_Version::jdk(9), JDK_Version::jdk(10), JDK_Version::jdk(11) },
@ -1318,22 +1319,31 @@ bool Arguments::add_property(const char* prop, PropertyWriteable writeable, Prop
#if INCLUDE_CDS #if INCLUDE_CDS
void Arguments::check_unsupported_dumping_properties() { void Arguments::check_unsupported_dumping_properties() {
assert(DumpSharedSpaces, "this function is only used with -Xshare:dump"); assert(DumpSharedSpaces, "this function is only used with -Xshare:dump");
const char* unsupported_properties[5] = { "jdk.module.main", const char* unsupported_properties[] = { "jdk.module.main",
"jdk.module.limitmods",
"jdk.module.path", "jdk.module.path",
"jdk.module.upgrade.path", "jdk.module.upgrade.path",
"jdk.module.addmods.0", "jdk.module.addmods.0" };
"jdk.module.limitmods" }; const char* unsupported_options[] = { "-m",
const char* unsupported_options[5] = { "-m", "--limit-modules",
"--module-path", "--module-path",
"--upgrade-module-path", "--upgrade-module-path",
"--add-modules", "--add-modules" };
"--limit-modules" }; assert(ARRAY_SIZE(unsupported_properties) == ARRAY_SIZE(unsupported_options), "must be");
// If a vm option is found in the unsupported_options array with index less than the warning_idx,
// vm will exit with an error message. Otherwise, it will result in a warning message.
uint warning_idx = 2;
SystemProperty* sp = system_properties(); SystemProperty* sp = system_properties();
while (sp != NULL) { while (sp != NULL) {
for (int i = 0; i < 5; i++) { for (uint i = 0; i < ARRAY_SIZE(unsupported_properties); i++) {
if (strcmp(sp->key(), unsupported_properties[i]) == 0) { if (strcmp(sp->key(), unsupported_properties[i]) == 0) {
if (i < warning_idx) {
vm_exit_during_initialization( vm_exit_during_initialization(
"Cannot use the following option when dumping the shared archive", unsupported_options[i]); "Cannot use the following option when dumping the shared archive", unsupported_options[i]);
} else {
warning(
"the %s option is ignored when dumping the shared archive", unsupported_options[i]);
}
} }
} }
sp = sp->next(); sp = sp->next();

Some files were not shown because too many files have changed in this diff Show More