Merge
This commit is contained in:
commit
f5da332e66
3
.hgtags
3
.hgtags
@ -219,3 +219,6 @@ b72ae39e1329fefae50d4690db4fde43f3841a95 jdk8-b93
|
||||
49fe9c8049132647ad38837a877dd473e6c9b0e5 jdk8-b95
|
||||
ea73f01b9053e7165e7ba80f242bafecbc6af712 jdk8-b96
|
||||
0a85476a0b9cb876d5666d45097dac68bef3fce1 jdk8-b97
|
||||
711eb4aa87de68de78250e0549980936bab53d54 jdk8-b98
|
||||
2d3875b0d18b3ad1c2bebf385a697e309e4005a4 jdk8-b99
|
||||
3d34036aae4ea90b2ca59712d5a69db3221f0875 jdk8-b100
|
||||
|
@ -219,3 +219,6 @@ cb51fb4789ac0b8be4056482077ddfb8f3bd3805 jdk8-b91
|
||||
785d07fe38901ecc1b7e0145e53e1c3da9361fee jdk8-b95
|
||||
c156084add486f941c12d886a0b1b2854795d557 jdk8-b96
|
||||
a1c1e8bf71f354f3aec0214cf13d6668811e021d jdk8-b97
|
||||
0d0c983a817bbe8518a5ff201306334a8de267f2 jdk8-b98
|
||||
59dc9da813794c924a0383c2a6241af94defdfed jdk8-b99
|
||||
d2dcb110e9dbaf9903c05b211df800e78e4b394e jdk8-b100
|
||||
|
@ -219,3 +219,6 @@ c8286839d0df04aba819ec4bef12b86babccf30e jdk8-b90
|
||||
2cf36f43df36137980d9828cec27003ec10daeee jdk8-b95
|
||||
3357c2776431d51a8de326a85e0f41420e40774f jdk8-b96
|
||||
469995a8e97424f450c880606d689bf345277b19 jdk8-b97
|
||||
3370fb6146e47a6cc05a213fc213e12fc0a38d07 jdk8-b98
|
||||
3f67804ab61303782df57e54989ef5e0e4629beb jdk8-b99
|
||||
8d492f1dfd1b131a4c7886ee6b59528609f7e4fe jdk8-b100
|
||||
|
@ -357,3 +357,9 @@ e6a4b8c71fa6f225bd989a34de2d0d0a656a8be8 jdk8-b96
|
||||
2b9380b0bf0b649f40704735773e8956c2d88ba0 hs25-b39
|
||||
d197d377ab2e016d024e8c86cb06a57bd7eae590 jdk8-b97
|
||||
c9dd82da51ed34a28f7c6b3245163ee962e94572 hs25-b40
|
||||
30b5b75c42ac5174b640fbef8aa87527668e8400 jdk8-b98
|
||||
2b9946e10587f74ef75ae8145bea484df4a2738b hs25-b41
|
||||
81b6cb70717c66375846b78bb174594ec3aa998e jdk8-b99
|
||||
9f71e36a471ae4a668e08827d33035963ed10c08 hs25-b42
|
||||
5787fac72e760c6a5fd9efa113b0c75caf554136 jdk8-b100
|
||||
46487ba40ff225654d0c51787ed3839bafcbd9f3 hs25-b43
|
||||
|
@ -49,7 +49,6 @@ public class ArrayKlass extends Klass {
|
||||
higherDimension = new MetadataField(type.getAddressField("_higher_dimension"), 0);
|
||||
lowerDimension = new MetadataField(type.getAddressField("_lower_dimension"), 0);
|
||||
vtableLen = new CIntField(type.getCIntegerField("_vtable_len"), 0);
|
||||
allocSize = new CIntField(type.getCIntegerField("_alloc_size"), 0);
|
||||
componentMirror = new OopField(type.getOopField("_component_mirror"), 0);
|
||||
javaLangCloneableName = null;
|
||||
javaLangObjectName = null;
|
||||
@ -64,7 +63,6 @@ public class ArrayKlass extends Klass {
|
||||
private static MetadataField higherDimension;
|
||||
private static MetadataField lowerDimension;
|
||||
private static CIntField vtableLen;
|
||||
private static CIntField allocSize;
|
||||
private static OopField componentMirror;
|
||||
|
||||
public Klass getJavaSuper() {
|
||||
@ -76,7 +74,6 @@ public class ArrayKlass extends Klass {
|
||||
public Klass getHigherDimension() { return (Klass) higherDimension.getValue(this); }
|
||||
public Klass getLowerDimension() { return (Klass) lowerDimension.getValue(this); }
|
||||
public long getVtableLen() { return vtableLen.getValue(this); }
|
||||
public long getAllocSize() { return allocSize.getValue(this); }
|
||||
public Oop getComponentMirror() { return componentMirror.getValue(this); }
|
||||
|
||||
// constant class names - javaLangCloneable, javaIoSerializable, javaLangObject
|
||||
@ -147,7 +144,6 @@ public class ArrayKlass extends Klass {
|
||||
visitor.doMetadata(higherDimension, true);
|
||||
visitor.doMetadata(lowerDimension, true);
|
||||
visitor.doCInt(vtableLen, true);
|
||||
visitor.doCInt(allocSize, true);
|
||||
visitor.doOop(componentMirror, true);
|
||||
}
|
||||
}
|
||||
|
@ -57,7 +57,6 @@ public class Klass extends Metadata implements ClassConstants {
|
||||
accessFlags = new CIntField(type.getCIntegerField("_access_flags"), 0);
|
||||
subklass = new MetadataField(type.getAddressField("_subklass"), 0);
|
||||
nextSibling = new MetadataField(type.getAddressField("_next_sibling"), 0);
|
||||
allocCount = new CIntField(type.getCIntegerField("_alloc_count"), 0);
|
||||
|
||||
LH_INSTANCE_SLOW_PATH_BIT = db.lookupIntConstant("Klass::_lh_instance_slow_path_bit").intValue();
|
||||
LH_LOG2_ELEMENT_SIZE_SHIFT = db.lookupIntConstant("Klass::_lh_log2_element_size_shift").intValue();
|
||||
@ -87,7 +86,6 @@ public class Klass extends Metadata implements ClassConstants {
|
||||
private static CIntField accessFlags;
|
||||
private static MetadataField subklass;
|
||||
private static MetadataField nextSibling;
|
||||
private static CIntField allocCount;
|
||||
|
||||
private Address getValue(AddressField field) {
|
||||
return addr.getAddressAt(field.getOffset());
|
||||
@ -108,7 +106,6 @@ public class Klass extends Metadata implements ClassConstants {
|
||||
public AccessFlags getAccessFlagsObj(){ return new AccessFlags(getAccessFlags()); }
|
||||
public Klass getSubklassKlass() { return (Klass) subklass.getValue(this); }
|
||||
public Klass getNextSiblingKlass() { return (Klass) nextSibling.getValue(this); }
|
||||
public long getAllocCount() { return allocCount.getValue(this); }
|
||||
|
||||
// computed access flags - takes care of inner classes etc.
|
||||
// This is closer to actual source level than getAccessFlags() etc.
|
||||
@ -172,7 +169,6 @@ public class Klass extends Metadata implements ClassConstants {
|
||||
visitor.doCInt(accessFlags, true);
|
||||
visitor.doMetadata(subklass, true);
|
||||
visitor.doMetadata(nextSibling, true);
|
||||
visitor.doCInt(allocCount, true);
|
||||
}
|
||||
|
||||
public long getObjectSize() {
|
||||
|
@ -221,7 +221,6 @@
|
||||
_JVM_SetLength
|
||||
_JVM_SetNativeThreadName
|
||||
_JVM_SetPrimitiveArrayElement
|
||||
_JVM_SetProtectionDomain
|
||||
_JVM_SetSockOpt
|
||||
_JVM_SetThreadPriority
|
||||
_JVM_Sleep
|
||||
|
@ -221,7 +221,6 @@
|
||||
_JVM_SetLength
|
||||
_JVM_SetNativeThreadName
|
||||
_JVM_SetPrimitiveArrayElement
|
||||
_JVM_SetProtectionDomain
|
||||
_JVM_SetSockOpt
|
||||
_JVM_SetThreadPriority
|
||||
_JVM_Sleep
|
||||
|
@ -35,7 +35,7 @@ HOTSPOT_VM_COPYRIGHT=Copyright 2013
|
||||
|
||||
HS_MAJOR_VER=25
|
||||
HS_MINOR_VER=0
|
||||
HS_BUILD_NUMBER=40
|
||||
HS_BUILD_NUMBER=43
|
||||
|
||||
JDK_MAJOR_VER=1
|
||||
JDK_MINOR_VER=8
|
||||
|
@ -223,7 +223,6 @@ SUNWprivate_1.1 {
|
||||
JVM_SetLength;
|
||||
JVM_SetNativeThreadName;
|
||||
JVM_SetPrimitiveArrayElement;
|
||||
JVM_SetProtectionDomain;
|
||||
JVM_SetSockOpt;
|
||||
JVM_SetThreadPriority;
|
||||
JVM_Sleep;
|
||||
|
@ -223,7 +223,6 @@ SUNWprivate_1.1 {
|
||||
JVM_SetLength;
|
||||
JVM_SetNativeThreadName;
|
||||
JVM_SetPrimitiveArrayElement;
|
||||
JVM_SetProtectionDomain;
|
||||
JVM_SetSockOpt;
|
||||
JVM_SetThreadPriority;
|
||||
JVM_Sleep;
|
||||
|
@ -46,6 +46,7 @@ ifeq ($(findstring true, $(JVM_VARIANT_ZERO) $(JVM_VARIANT_ZEROSHARK)), true)
|
||||
include $(MAKEFILES_DIR)/zeroshark.make
|
||||
else
|
||||
include $(MAKEFILES_DIR)/$(BUILDARCH).make
|
||||
-include $(HS_ALT_MAKE)/$(Platform_os_family)/makefiles/$(BUILDARCH).make
|
||||
endif
|
||||
|
||||
# set VPATH so make knows where to look for source files
|
||||
@ -211,6 +212,12 @@ ifeq ($(Platform_arch_model), x86_64)
|
||||
Src_Files_EXCLUDE += \*x86_32\*
|
||||
endif
|
||||
|
||||
# Alternate vm.make
|
||||
# This has to be included here to allow changes to the source
|
||||
# directories and excluded files before they are expanded
|
||||
# by the definition of Src_Files.
|
||||
-include $(HS_ALT_MAKE)/$(Platform_os_family)/makefiles/vm.make
|
||||
|
||||
# Locate all source files in the given directory, excluding files in Src_Files_EXCLUDE.
|
||||
define findsrc
|
||||
$(notdir $(shell find $(1)/. ! -name . -prune \
|
||||
@ -380,4 +387,4 @@ build: $(LIBJVM) $(LAUNCHER) $(LIBJSIG) $(LIBJVM_DB) $(BUILDLIBSAPROC) dtraceChe
|
||||
|
||||
install: install_jvm install_jsig install_saproc
|
||||
|
||||
.PHONY: default build install install_jvm
|
||||
.PHONY: default build install install_jvm $(HS_ALT_MAKE)/$(Platform_os_family)/makefiles/$(BUILDARCH).make $(HS_ALT_MAKE)/$(Platform_os_family)/makefiles/vm.make
|
||||
|
@ -223,7 +223,6 @@ SUNWprivate_1.1 {
|
||||
JVM_SetLength;
|
||||
JVM_SetNativeThreadName;
|
||||
JVM_SetPrimitiveArrayElement;
|
||||
JVM_SetProtectionDomain;
|
||||
JVM_SetSockOpt;
|
||||
JVM_SetThreadPriority;
|
||||
JVM_Sleep;
|
||||
|
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
# Copyright (c) 1997, 2013, 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
|
||||
@ -110,6 +110,7 @@ CXX_FLAGS=$(CXX_FLAGS) /D TARGET_COMPILER_visCPP
|
||||
# 1400 is for VS2005
|
||||
# 1500 is for VS2008
|
||||
# 1600 is for VS2010
|
||||
# 1700 is for VS2012
|
||||
# Do not confuse this MSC_VER with the predefined macro _MSC_VER that the
|
||||
# compiler provides, when MSC_VER==1399, _MSC_VER will be 1400.
|
||||
# Normally they are the same, but a pre-release of the VS2005 compilers
|
||||
@ -142,6 +143,9 @@ COMPILER_NAME=VS2008
|
||||
!if "$(MSC_VER)" == "1600"
|
||||
COMPILER_NAME=VS2010
|
||||
!endif
|
||||
!if "$(MSC_VER)" == "1700"
|
||||
COMPILER_NAME=VS2012
|
||||
!endif
|
||||
!endif
|
||||
|
||||
# By default, we do not want to use the debug version of the msvcrt.dll file
|
||||
@ -151,9 +155,13 @@ MS_RUNTIME_OPTION = /MD
|
||||
MS_RUNTIME_OPTION = /MTd /D "_DEBUG"
|
||||
!endif
|
||||
|
||||
# VS2012 and later won't work with:
|
||||
# /D _STATIC_CPPLIB /D _DISABLE_DEPRECATE_STATIC_CPPLIB
|
||||
!if "$(MSC_VER)" < "1700"
|
||||
# Always add the _STATIC_CPPLIB flag
|
||||
STATIC_CPPLIB_OPTION = /D _STATIC_CPPLIB /D _DISABLE_DEPRECATE_STATIC_CPPLIB
|
||||
MS_RUNTIME_OPTION = $(MS_RUNTIME_OPTION) $(STATIC_CPPLIB_OPTION)
|
||||
!endif
|
||||
CXX_FLAGS=$(CXX_FLAGS) $(MS_RUNTIME_OPTION)
|
||||
|
||||
# How /GX option is spelled
|
||||
@ -221,6 +229,22 @@ LD_FLAGS = /SAFESEH $(LD_FLAGS)
|
||||
!endif
|
||||
!endif
|
||||
|
||||
!if "$(COMPILER_NAME)" == "VS2012"
|
||||
PRODUCT_OPT_OPTION = /O2 /Oy-
|
||||
FASTDEBUG_OPT_OPTION = /O2 /Oy-
|
||||
DEBUG_OPT_OPTION = /Od
|
||||
GX_OPTION = /EHsc
|
||||
LD_FLAGS = /manifest $(LD_FLAGS)
|
||||
# Manifest Tool - used in VS2005 and later to adjust manifests stored
|
||||
# as resources inside build artifacts.
|
||||
!if "x$(MT)" == "x"
|
||||
MT=mt.exe
|
||||
!endif
|
||||
!if "$(BUILDARCH)" == "i486"
|
||||
LD_FLAGS = /SAFESEH $(LD_FLAGS)
|
||||
!endif
|
||||
!endif
|
||||
|
||||
# If NO_OPTIMIZATIONS is defined in the environment, turn everything off
|
||||
!ifdef NO_OPTIMIZATIONS
|
||||
PRODUCT_OPT_OPTION = $(DEBUG_OPT_OPTION)
|
||||
|
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2006, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
# Copyright (c) 2006, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
#
|
||||
# This code is free software; you can redistribute it and/or modify it
|
||||
@ -27,9 +27,9 @@
|
||||
all: checkCL checkLink
|
||||
|
||||
checkCL:
|
||||
@ if "$(MSC_VER)" NEQ "1310" if "$(MSC_VER)" NEQ "1399" if "$(MSC_VER)" NEQ "1400" if "$(MSC_VER)" NEQ "1500" if "$(MSC_VER)" NEQ "1600" \
|
||||
@ if "$(MSC_VER)" NEQ "1310" if "$(MSC_VER)" NEQ "1399" if "$(MSC_VER)" NEQ "1400" if "$(MSC_VER)" NEQ "1500" if "$(MSC_VER)" NEQ "1600" if "$(MSC_VER)" NEQ "1700" \
|
||||
echo *** WARNING *** unrecognized cl.exe version $(MSC_VER) ($(RAW_MSC_VER)). Use FORCE_MSC_VER to override automatic detection.
|
||||
|
||||
checkLink:
|
||||
@ if "$(LD_VER)" NEQ "710" if "$(LD_VER)" NEQ "800" if "$(LD_VER)" NEQ "900" if "$(LD_VER)" NEQ "1000" \
|
||||
@ if "$(LD_VER)" NEQ "710" if "$(LD_VER)" NEQ "800" if "$(LD_VER)" NEQ "900" if "$(LD_VER)" NEQ "1000" if "$(LD_VER)" NEQ "1100" \
|
||||
echo *** WARNING *** unrecognized link.exe version $(LD_VER) ($(RAW_LD_VER)). Use FORCE_LD_VER to override automatic detection.
|
||||
|
@ -132,6 +132,10 @@ CXX_DONT_USE_PCH=/D DONT_USE_PRECOMPILED_HEADER
|
||||
|
||||
!if "$(USE_PRECOMPILED_HEADER)" != "0"
|
||||
CXX_USE_PCH=/Fp"vm.pch" /Yu"precompiled.hpp"
|
||||
!if "$(COMPILER_NAME)" == "VS2012"
|
||||
# VS2012 requires this object file to be listed:
|
||||
LD_FLAGS=$(LD_FLAGS) _build_pch_file.obj
|
||||
!endif
|
||||
!else
|
||||
CXX_USE_PCH=$(CXX_DONT_USE_PCH)
|
||||
!endif
|
||||
|
@ -240,10 +240,10 @@ inline ConstantPoolCache** frame::interpreter_frame_cache_addr() const {
|
||||
#endif // CC_INTERP
|
||||
|
||||
|
||||
inline JavaCallWrapper* frame::entry_frame_call_wrapper() const {
|
||||
inline JavaCallWrapper** frame::entry_frame_call_wrapper_addr() const {
|
||||
// note: adjust this code if the link argument in StubGenerator::call_stub() changes!
|
||||
const Argument link = Argument(0, false);
|
||||
return (JavaCallWrapper*)sp()[link.as_in().as_register()->sp_offset_in_saved_window()];
|
||||
return (JavaCallWrapper**)&sp()[link.as_in().as_register()->sp_offset_in_saved_window()];
|
||||
}
|
||||
|
||||
|
||||
|
@ -410,6 +410,51 @@ class StubGenerator: public StubCodeGenerator {
|
||||
return start;
|
||||
}
|
||||
|
||||
// Safefetch stubs.
|
||||
void generate_safefetch(const char* name, int size, address* entry,
|
||||
address* fault_pc, address* continuation_pc) {
|
||||
// safefetch signatures:
|
||||
// int SafeFetch32(int* adr, int errValue);
|
||||
// intptr_t SafeFetchN (intptr_t* adr, intptr_t errValue);
|
||||
//
|
||||
// arguments:
|
||||
// o0 = adr
|
||||
// o1 = errValue
|
||||
//
|
||||
// result:
|
||||
// o0 = *adr or errValue
|
||||
|
||||
StubCodeMark mark(this, "StubRoutines", name);
|
||||
|
||||
// Entry point, pc or function descriptor.
|
||||
__ align(CodeEntryAlignment);
|
||||
*entry = __ pc();
|
||||
|
||||
__ mov(O0, G1); // g1 = o0
|
||||
__ mov(O1, O0); // o0 = o1
|
||||
// Load *adr into c_rarg1, may fault.
|
||||
*fault_pc = __ pc();
|
||||
switch (size) {
|
||||
case 4:
|
||||
// int32_t
|
||||
__ ldsw(G1, 0, O0); // o0 = [g1]
|
||||
break;
|
||||
case 8:
|
||||
// int64_t
|
||||
__ ldx(G1, 0, O0); // o0 = [g1]
|
||||
break;
|
||||
default:
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
|
||||
// return errValue or *adr
|
||||
*continuation_pc = __ pc();
|
||||
// By convention with the trap handler we ensure there is a non-CTI
|
||||
// instruction in the trap shadow.
|
||||
__ nop();
|
||||
__ retl();
|
||||
__ delayed()->nop();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------------------------------------------
|
||||
// Continuation point for throwing of implicit exceptions that are not handled in
|
||||
@ -3315,6 +3360,14 @@ class StubGenerator: public StubCodeGenerator {
|
||||
|
||||
// Don't initialize the platform math functions since sparc
|
||||
// doesn't have intrinsics for these operations.
|
||||
|
||||
// Safefetch stubs.
|
||||
generate_safefetch("SafeFetch32", sizeof(int), &StubRoutines::_safefetch32_entry,
|
||||
&StubRoutines::_safefetch32_fault_pc,
|
||||
&StubRoutines::_safefetch32_continuation_pc);
|
||||
generate_safefetch("SafeFetchN", sizeof(intptr_t), &StubRoutines::_safefetchN_entry,
|
||||
&StubRoutines::_safefetchN_fault_pc,
|
||||
&StubRoutines::_safefetchN_continuation_pc);
|
||||
}
|
||||
|
||||
|
||||
|
@ -272,11 +272,10 @@ inline jint frame::interpreter_frame_expression_stack_direction() { return -1; }
|
||||
|
||||
// Entry frames
|
||||
|
||||
inline JavaCallWrapper* frame::entry_frame_call_wrapper() const {
|
||||
return (JavaCallWrapper*)at(entry_frame_call_wrapper_offset);
|
||||
inline JavaCallWrapper** frame::entry_frame_call_wrapper_addr() const {
|
||||
return (JavaCallWrapper**)addr_at(entry_frame_call_wrapper_offset);
|
||||
}
|
||||
|
||||
|
||||
// Compiled frames
|
||||
|
||||
inline int frame::local_offset_for_compiler(int local_index, int nof_args, int max_nof_locals, int max_nof_monitors) {
|
||||
|
@ -2766,6 +2766,39 @@ class StubGenerator: public StubCodeGenerator {
|
||||
return start;
|
||||
}
|
||||
|
||||
// Safefetch stubs.
|
||||
void generate_safefetch(const char* name, int size, address* entry,
|
||||
address* fault_pc, address* continuation_pc) {
|
||||
// safefetch signatures:
|
||||
// int SafeFetch32(int* adr, int errValue);
|
||||
// intptr_t SafeFetchN (intptr_t* adr, intptr_t errValue);
|
||||
|
||||
StubCodeMark mark(this, "StubRoutines", name);
|
||||
|
||||
// Entry point, pc or function descriptor.
|
||||
*entry = __ pc();
|
||||
|
||||
__ movl(rax, Address(rsp, 0x8));
|
||||
__ movl(rcx, Address(rsp, 0x4));
|
||||
// Load *adr into eax, may fault.
|
||||
*fault_pc = __ pc();
|
||||
switch (size) {
|
||||
case 4:
|
||||
// int32_t
|
||||
__ movl(rax, Address(rcx, 0));
|
||||
break;
|
||||
case 8:
|
||||
// int64_t
|
||||
Unimplemented();
|
||||
break;
|
||||
default:
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
|
||||
// Return errValue or *adr.
|
||||
*continuation_pc = __ pc();
|
||||
__ ret(0);
|
||||
}
|
||||
|
||||
public:
|
||||
// Information about frame layout at time of blocking runtime call.
|
||||
@ -2978,6 +3011,14 @@ class StubGenerator: public StubCodeGenerator {
|
||||
StubRoutines::_cipherBlockChaining_encryptAESCrypt = generate_cipherBlockChaining_encryptAESCrypt();
|
||||
StubRoutines::_cipherBlockChaining_decryptAESCrypt = generate_cipherBlockChaining_decryptAESCrypt();
|
||||
}
|
||||
|
||||
// Safefetch stubs.
|
||||
generate_safefetch("SafeFetch32", sizeof(int), &StubRoutines::_safefetch32_entry,
|
||||
&StubRoutines::_safefetch32_fault_pc,
|
||||
&StubRoutines::_safefetch32_continuation_pc);
|
||||
StubRoutines::_safefetchN_entry = StubRoutines::_safefetch32_entry;
|
||||
StubRoutines::_safefetchN_fault_pc = StubRoutines::_safefetch32_fault_pc;
|
||||
StubRoutines::_safefetchN_continuation_pc = StubRoutines::_safefetch32_continuation_pc;
|
||||
}
|
||||
|
||||
|
||||
|
@ -279,7 +279,7 @@ class StubGenerator: public StubCodeGenerator {
|
||||
__ stmxcsr(mxcsr_save);
|
||||
__ movl(rax, mxcsr_save);
|
||||
__ andl(rax, MXCSR_MASK); // Only check control and mask bits
|
||||
ExternalAddress mxcsr_std(StubRoutines::x86::mxcsr_std());
|
||||
ExternalAddress mxcsr_std(StubRoutines::addr_mxcsr_std());
|
||||
__ cmp32(rax, mxcsr_std);
|
||||
__ jcc(Assembler::equal, skip_ldmx);
|
||||
__ ldmxcsr(mxcsr_std);
|
||||
@ -729,17 +729,18 @@ class StubGenerator: public StubCodeGenerator {
|
||||
|
||||
if (CheckJNICalls) {
|
||||
Label ok_ret;
|
||||
ExternalAddress mxcsr_std(StubRoutines::addr_mxcsr_std());
|
||||
__ push(rax);
|
||||
__ subptr(rsp, wordSize); // allocate a temp location
|
||||
__ stmxcsr(mxcsr_save);
|
||||
__ movl(rax, mxcsr_save);
|
||||
__ andl(rax, MXCSR_MASK); // Only check control and mask bits
|
||||
__ cmpl(rax, *(int *)(StubRoutines::x86::mxcsr_std()));
|
||||
__ cmp32(rax, mxcsr_std);
|
||||
__ jcc(Assembler::equal, ok_ret);
|
||||
|
||||
__ warn("MXCSR changed by native JNI code, use -XX:+RestoreMXCSROnJNICall");
|
||||
|
||||
__ ldmxcsr(ExternalAddress(StubRoutines::x86::mxcsr_std()));
|
||||
__ ldmxcsr(mxcsr_std);
|
||||
|
||||
__ bind(ok_ret);
|
||||
__ addptr(rsp, wordSize);
|
||||
@ -3357,7 +3358,45 @@ class StubGenerator: public StubCodeGenerator {
|
||||
return start;
|
||||
}
|
||||
|
||||
// Safefetch stubs.
|
||||
void generate_safefetch(const char* name, int size, address* entry,
|
||||
address* fault_pc, address* continuation_pc) {
|
||||
// safefetch signatures:
|
||||
// int SafeFetch32(int* adr, int errValue);
|
||||
// intptr_t SafeFetchN (intptr_t* adr, intptr_t errValue);
|
||||
//
|
||||
// arguments:
|
||||
// c_rarg0 = adr
|
||||
// c_rarg1 = errValue
|
||||
//
|
||||
// result:
|
||||
// PPC_RET = *adr or errValue
|
||||
|
||||
StubCodeMark mark(this, "StubRoutines", name);
|
||||
|
||||
// Entry point, pc or function descriptor.
|
||||
*entry = __ pc();
|
||||
|
||||
// Load *adr into c_rarg1, may fault.
|
||||
*fault_pc = __ pc();
|
||||
switch (size) {
|
||||
case 4:
|
||||
// int32_t
|
||||
__ movl(c_rarg1, Address(c_rarg0, 0));
|
||||
break;
|
||||
case 8:
|
||||
// int64_t
|
||||
__ movq(c_rarg1, Address(c_rarg0, 0));
|
||||
break;
|
||||
default:
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
|
||||
// return errValue or *adr
|
||||
*continuation_pc = __ pc();
|
||||
__ movq(rax, c_rarg1);
|
||||
__ ret(0);
|
||||
}
|
||||
|
||||
// This is a version of CBC/AES Decrypt which does 4 blocks in a loop at a time
|
||||
// to hide instruction latency
|
||||
@ -3729,12 +3768,35 @@ class StubGenerator: public StubCodeGenerator {
|
||||
return stub->entry_point();
|
||||
}
|
||||
|
||||
void create_control_words() {
|
||||
// Round to nearest, 53-bit mode, exceptions masked
|
||||
StubRoutines::_fpu_cntrl_wrd_std = 0x027F;
|
||||
// Round to zero, 53-bit mode, exception mased
|
||||
StubRoutines::_fpu_cntrl_wrd_trunc = 0x0D7F;
|
||||
// Round to nearest, 24-bit mode, exceptions masked
|
||||
StubRoutines::_fpu_cntrl_wrd_24 = 0x007F;
|
||||
// Round to nearest, 64-bit mode, exceptions masked
|
||||
StubRoutines::_fpu_cntrl_wrd_64 = 0x037F;
|
||||
// Round to nearest, 64-bit mode, exceptions masked
|
||||
StubRoutines::_mxcsr_std = 0x1F80;
|
||||
// Note: the following two constants are 80-bit values
|
||||
// layout is critical for correct loading by FPU.
|
||||
// Bias for strict fp multiply/divide
|
||||
StubRoutines::_fpu_subnormal_bias1[0]= 0x00000000; // 2^(-15360) == 0x03ff 8000 0000 0000 0000
|
||||
StubRoutines::_fpu_subnormal_bias1[1]= 0x80000000;
|
||||
StubRoutines::_fpu_subnormal_bias1[2]= 0x03ff;
|
||||
// Un-Bias for strict fp multiply/divide
|
||||
StubRoutines::_fpu_subnormal_bias2[0]= 0x00000000; // 2^(+15360) == 0x7bff 8000 0000 0000 0000
|
||||
StubRoutines::_fpu_subnormal_bias2[1]= 0x80000000;
|
||||
StubRoutines::_fpu_subnormal_bias2[2]= 0x7bff;
|
||||
}
|
||||
|
||||
// Initialization
|
||||
void generate_initial() {
|
||||
// Generates all stubs and initializes the entry points
|
||||
|
||||
// This platform-specific stub is needed by generate_call_stub()
|
||||
StubRoutines::x86::_mxcsr_std = generate_fp_mask("mxcsr_std", 0x0000000000001F80);
|
||||
// This platform-specific settings are needed by generate_call_stub()
|
||||
create_control_words();
|
||||
|
||||
// entry points that exist in all platforms Note: This is code
|
||||
// that could be shared among different platforms - however the
|
||||
@ -3833,6 +3895,14 @@ class StubGenerator: public StubCodeGenerator {
|
||||
StubRoutines::_cipherBlockChaining_encryptAESCrypt = generate_cipherBlockChaining_encryptAESCrypt();
|
||||
StubRoutines::_cipherBlockChaining_decryptAESCrypt = generate_cipherBlockChaining_decryptAESCrypt_Parallel();
|
||||
}
|
||||
|
||||
// Safefetch stubs.
|
||||
generate_safefetch("SafeFetch32", sizeof(int), &StubRoutines::_safefetch32_entry,
|
||||
&StubRoutines::_safefetch32_fault_pc,
|
||||
&StubRoutines::_safefetch32_continuation_pc);
|
||||
generate_safefetch("SafeFetchN", sizeof(intptr_t), &StubRoutines::_safefetchN_entry,
|
||||
&StubRoutines::_safefetchN_fault_pc,
|
||||
&StubRoutines::_safefetchN_continuation_pc);
|
||||
}
|
||||
|
||||
public:
|
||||
|
@ -42,4 +42,3 @@ address StubRoutines::x86::_float_sign_mask = NULL;
|
||||
address StubRoutines::x86::_float_sign_flip = NULL;
|
||||
address StubRoutines::x86::_double_sign_mask = NULL;
|
||||
address StubRoutines::x86::_double_sign_flip = NULL;
|
||||
address StubRoutines::x86::_mxcsr_std = NULL;
|
||||
|
@ -52,7 +52,6 @@ class x86 {
|
||||
static address _float_sign_flip;
|
||||
static address _double_sign_mask;
|
||||
static address _double_sign_flip;
|
||||
static address _mxcsr_std;
|
||||
|
||||
public:
|
||||
|
||||
@ -106,11 +105,6 @@ class x86 {
|
||||
return _double_sign_flip;
|
||||
}
|
||||
|
||||
static address mxcsr_std()
|
||||
{
|
||||
return _mxcsr_std;
|
||||
}
|
||||
|
||||
# include "stubRoutines_x86.hpp"
|
||||
|
||||
};
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2005, 2013, 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
|
||||
@ -437,6 +437,30 @@ AttachOperation* AttachListener::dequeue() {
|
||||
return op;
|
||||
}
|
||||
|
||||
|
||||
// Performs initialization at vm startup
|
||||
// For BSD we remove any stale .java_pid file which could cause
|
||||
// an attaching process to think we are ready to receive on the
|
||||
// domain socket before we are properly initialized
|
||||
|
||||
void AttachListener::vm_start() {
|
||||
char fn[UNIX_PATH_MAX];
|
||||
struct stat64 st;
|
||||
int ret;
|
||||
|
||||
int n = snprintf(fn, UNIX_PATH_MAX, "%s/.java_pid%d",
|
||||
os::get_temp_directory(), os::current_process_id());
|
||||
assert(n < (int)UNIX_PATH_MAX, "java_pid file name buffer overflow");
|
||||
|
||||
RESTARTABLE(::stat64(fn, &st), ret);
|
||||
if (ret == 0) {
|
||||
ret = ::unlink(fn);
|
||||
if (ret == -1) {
|
||||
debug_only(warning("failed to remove stale attach pid file at %s", fn));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int AttachListener::pd_init() {
|
||||
JavaThread* thread = JavaThread::current();
|
||||
ThreadBlockInVM tbivm(thread);
|
||||
|
@ -1234,12 +1234,13 @@ bool os::address_is_in_vm(address addr) {
|
||||
Dl_info dlinfo;
|
||||
|
||||
if (libjvm_base_addr == NULL) {
|
||||
dladdr(CAST_FROM_FN_PTR(void *, os::address_is_in_vm), &dlinfo);
|
||||
libjvm_base_addr = (address)dlinfo.dli_fbase;
|
||||
if (dladdr(CAST_FROM_FN_PTR(void *, os::address_is_in_vm), &dlinfo) != 0) {
|
||||
libjvm_base_addr = (address)dlinfo.dli_fbase;
|
||||
}
|
||||
assert(libjvm_base_addr !=NULL, "Cannot obtain base address for libjvm");
|
||||
}
|
||||
|
||||
if (dladdr((void *)addr, &dlinfo)) {
|
||||
if (dladdr((void *)addr, &dlinfo) != 0) {
|
||||
if (libjvm_base_addr == (address)dlinfo.dli_fbase) return true;
|
||||
}
|
||||
|
||||
@ -1251,35 +1252,40 @@ bool os::address_is_in_vm(address addr) {
|
||||
|
||||
bool os::dll_address_to_function_name(address addr, char *buf,
|
||||
int buflen, int *offset) {
|
||||
// buf is not optional, but offset is optional
|
||||
assert(buf != NULL, "sanity check");
|
||||
|
||||
Dl_info dlinfo;
|
||||
char localbuf[MACH_MAXSYMLEN];
|
||||
|
||||
// dladdr will find names of dynamic functions only, but does
|
||||
// it set dli_fbase with mach_header address when it "fails" ?
|
||||
if (dladdr((void*)addr, &dlinfo) && dlinfo.dli_sname != NULL) {
|
||||
if (buf != NULL) {
|
||||
if(!Decoder::demangle(dlinfo.dli_sname, buf, buflen)) {
|
||||
if (dladdr((void*)addr, &dlinfo) != 0) {
|
||||
// see if we have a matching symbol
|
||||
if (dlinfo.dli_saddr != NULL && dlinfo.dli_sname != NULL) {
|
||||
if (!Decoder::demangle(dlinfo.dli_sname, buf, buflen)) {
|
||||
jio_snprintf(buf, buflen, "%s", dlinfo.dli_sname);
|
||||
}
|
||||
if (offset != NULL) *offset = addr - (address)dlinfo.dli_saddr;
|
||||
return true;
|
||||
}
|
||||
if (offset != NULL) *offset = addr - (address)dlinfo.dli_saddr;
|
||||
return true;
|
||||
} else if (dlinfo.dli_fname != NULL && dlinfo.dli_fbase != 0) {
|
||||
if (Decoder::decode((address)(addr - (address)dlinfo.dli_fbase),
|
||||
buf, buflen, offset, dlinfo.dli_fname)) {
|
||||
return true;
|
||||
// no matching symbol so try for just file info
|
||||
if (dlinfo.dli_fname != NULL && dlinfo.dli_fbase != NULL) {
|
||||
if (Decoder::decode((address)(addr - (address)dlinfo.dli_fbase),
|
||||
buf, buflen, offset, dlinfo.dli_fname)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handle non-dymanic manually:
|
||||
if (dlinfo.dli_fbase != NULL &&
|
||||
Decoder::decode(addr, localbuf, MACH_MAXSYMLEN, offset, dlinfo.dli_fbase)) {
|
||||
if(!Decoder::demangle(localbuf, buf, buflen)) {
|
||||
jio_snprintf(buf, buflen, "%s", localbuf);
|
||||
// Handle non-dynamic manually:
|
||||
if (dlinfo.dli_fbase != NULL &&
|
||||
Decoder::decode(addr, localbuf, MACH_MAXSYMLEN, offset,
|
||||
dlinfo.dli_fbase)) {
|
||||
if (!Decoder::demangle(localbuf, buf, buflen)) {
|
||||
jio_snprintf(buf, buflen, "%s", localbuf);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (buf != NULL) buf[0] = '\0';
|
||||
buf[0] = '\0';
|
||||
if (offset != NULL) *offset = -1;
|
||||
return false;
|
||||
}
|
||||
@ -1287,17 +1293,24 @@ bool os::dll_address_to_function_name(address addr, char *buf,
|
||||
// ported from solaris version
|
||||
bool os::dll_address_to_library_name(address addr, char* buf,
|
||||
int buflen, int* offset) {
|
||||
// buf is not optional, but offset is optional
|
||||
assert(buf != NULL, "sanity check");
|
||||
|
||||
Dl_info dlinfo;
|
||||
|
||||
if (dladdr((void*)addr, &dlinfo)){
|
||||
if (buf) jio_snprintf(buf, buflen, "%s", dlinfo.dli_fname);
|
||||
if (offset) *offset = addr - (address)dlinfo.dli_fbase;
|
||||
return true;
|
||||
} else {
|
||||
if (buf) buf[0] = '\0';
|
||||
if (offset) *offset = -1;
|
||||
return false;
|
||||
if (dladdr((void*)addr, &dlinfo) != 0) {
|
||||
if (dlinfo.dli_fname != NULL) {
|
||||
jio_snprintf(buf, buflen, "%s", dlinfo.dli_fname);
|
||||
}
|
||||
if (dlinfo.dli_fbase != NULL && offset != NULL) {
|
||||
*offset = addr - (address)dlinfo.dli_fbase;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
buf[0] = '\0';
|
||||
if (offset) *offset = -1;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Loads .dll/.so and
|
||||
@ -1520,49 +1533,50 @@ static bool _print_ascii_file(const char* filename, outputStream* st) {
|
||||
}
|
||||
|
||||
void os::print_dll_info(outputStream *st) {
|
||||
st->print_cr("Dynamic libraries:");
|
||||
st->print_cr("Dynamic libraries:");
|
||||
#ifdef RTLD_DI_LINKMAP
|
||||
Dl_info dli;
|
||||
void *handle;
|
||||
Link_map *map;
|
||||
Link_map *p;
|
||||
Dl_info dli;
|
||||
void *handle;
|
||||
Link_map *map;
|
||||
Link_map *p;
|
||||
|
||||
if (!dladdr(CAST_FROM_FN_PTR(void *, os::print_dll_info), &dli)) {
|
||||
st->print_cr("Error: Cannot print dynamic libraries.");
|
||||
return;
|
||||
}
|
||||
handle = dlopen(dli.dli_fname, RTLD_LAZY);
|
||||
if (handle == NULL) {
|
||||
st->print_cr("Error: Cannot print dynamic libraries.");
|
||||
return;
|
||||
}
|
||||
dlinfo(handle, RTLD_DI_LINKMAP, &map);
|
||||
if (map == NULL) {
|
||||
st->print_cr("Error: Cannot print dynamic libraries.");
|
||||
return;
|
||||
}
|
||||
if (dladdr(CAST_FROM_FN_PTR(void *, os::print_dll_info), &dli) == 0 ||
|
||||
dli.dli_fname == NULL) {
|
||||
st->print_cr("Error: Cannot print dynamic libraries.");
|
||||
return;
|
||||
}
|
||||
handle = dlopen(dli.dli_fname, RTLD_LAZY);
|
||||
if (handle == NULL) {
|
||||
st->print_cr("Error: Cannot print dynamic libraries.");
|
||||
return;
|
||||
}
|
||||
dlinfo(handle, RTLD_DI_LINKMAP, &map);
|
||||
if (map == NULL) {
|
||||
st->print_cr("Error: Cannot print dynamic libraries.");
|
||||
return;
|
||||
}
|
||||
|
||||
while (map->l_prev != NULL)
|
||||
map = map->l_prev;
|
||||
while (map->l_prev != NULL)
|
||||
map = map->l_prev;
|
||||
|
||||
while (map != NULL) {
|
||||
st->print_cr(PTR_FORMAT " \t%s", map->l_addr, map->l_name);
|
||||
map = map->l_next;
|
||||
}
|
||||
while (map != NULL) {
|
||||
st->print_cr(PTR_FORMAT " \t%s", map->l_addr, map->l_name);
|
||||
map = map->l_next;
|
||||
}
|
||||
|
||||
dlclose(handle);
|
||||
dlclose(handle);
|
||||
#elif defined(__APPLE__)
|
||||
uint32_t count;
|
||||
uint32_t i;
|
||||
uint32_t count;
|
||||
uint32_t i;
|
||||
|
||||
count = _dyld_image_count();
|
||||
for (i = 1; i < count; i++) {
|
||||
const char *name = _dyld_get_image_name(i);
|
||||
intptr_t slide = _dyld_get_image_vmaddr_slide(i);
|
||||
st->print_cr(PTR_FORMAT " \t%s", slide, name);
|
||||
}
|
||||
count = _dyld_image_count();
|
||||
for (i = 1; i < count; i++) {
|
||||
const char *name = _dyld_get_image_name(i);
|
||||
intptr_t slide = _dyld_get_image_vmaddr_slide(i);
|
||||
st->print_cr(PTR_FORMAT " \t%s", slide, name);
|
||||
}
|
||||
#else
|
||||
st->print_cr("Error: Cannot print dynamic libraries.");
|
||||
st->print_cr("Error: Cannot print dynamic libraries.");
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -1707,8 +1721,11 @@ void os::jvm_path(char *buf, jint buflen) {
|
||||
bool ret = dll_address_to_library_name(
|
||||
CAST_FROM_FN_PTR(address, os::jvm_path),
|
||||
dli_fname, sizeof(dli_fname), NULL);
|
||||
assert(ret != 0, "cannot locate libjvm");
|
||||
char *rp = realpath(dli_fname, buf);
|
||||
assert(ret, "cannot locate libjvm");
|
||||
char *rp = NULL;
|
||||
if (ret && dli_fname[0] != '\0') {
|
||||
rp = realpath(dli_fname, buf);
|
||||
}
|
||||
if (rp == NULL)
|
||||
return;
|
||||
|
||||
@ -3747,20 +3764,20 @@ int os::Bsd::safe_cond_timedwait(pthread_cond_t *_cond, pthread_mutex_t *_mutex,
|
||||
bool os::find(address addr, outputStream* st) {
|
||||
Dl_info dlinfo;
|
||||
memset(&dlinfo, 0, sizeof(dlinfo));
|
||||
if (dladdr(addr, &dlinfo)) {
|
||||
if (dladdr(addr, &dlinfo) != 0) {
|
||||
st->print(PTR_FORMAT ": ", addr);
|
||||
if (dlinfo.dli_sname != NULL) {
|
||||
if (dlinfo.dli_sname != NULL && dlinfo.dli_saddr != NULL) {
|
||||
st->print("%s+%#x", dlinfo.dli_sname,
|
||||
addr - (intptr_t)dlinfo.dli_saddr);
|
||||
} else if (dlinfo.dli_fname) {
|
||||
} else if (dlinfo.dli_fbase != NULL) {
|
||||
st->print("<offset %#x>", addr - (intptr_t)dlinfo.dli_fbase);
|
||||
} else {
|
||||
st->print("<absolute address>");
|
||||
}
|
||||
if (dlinfo.dli_fname) {
|
||||
if (dlinfo.dli_fname != NULL) {
|
||||
st->print(" in %s", dlinfo.dli_fname);
|
||||
}
|
||||
if (dlinfo.dli_fbase) {
|
||||
if (dlinfo.dli_fbase != NULL) {
|
||||
st->print(" at " PTR_FORMAT, dlinfo.dli_fbase);
|
||||
}
|
||||
st->cr();
|
||||
@ -3773,7 +3790,7 @@ bool os::find(address addr, outputStream* st) {
|
||||
if (!lowest) lowest = (address) dlinfo.dli_fbase;
|
||||
if (begin < lowest) begin = lowest;
|
||||
Dl_info dlinfo2;
|
||||
if (dladdr(end, &dlinfo2) && dlinfo2.dli_saddr != dlinfo.dli_saddr
|
||||
if (dladdr(end, &dlinfo2) != 0 && dlinfo2.dli_saddr != dlinfo.dli_saddr
|
||||
&& end > dlinfo2.dli_saddr && dlinfo2.dli_saddr > begin)
|
||||
end = (address) dlinfo2.dli_saddr;
|
||||
Disassembler::decode(begin, end, st);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2005, 2013, 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
|
||||
@ -432,6 +432,30 @@ AttachOperation* AttachListener::dequeue() {
|
||||
return op;
|
||||
}
|
||||
|
||||
|
||||
// Performs initialization at vm startup
|
||||
// For Linux we remove any stale .java_pid file which could cause
|
||||
// an attaching process to think we are ready to receive on the
|
||||
// domain socket before we are properly initialized
|
||||
|
||||
void AttachListener::vm_start() {
|
||||
char fn[UNIX_PATH_MAX];
|
||||
struct stat64 st;
|
||||
int ret;
|
||||
|
||||
int n = snprintf(fn, UNIX_PATH_MAX, "%s/.java_pid%d",
|
||||
os::get_temp_directory(), os::current_process_id());
|
||||
assert(n < (int)UNIX_PATH_MAX, "java_pid file name buffer overflow");
|
||||
|
||||
RESTARTABLE(::stat64(fn, &st), ret);
|
||||
if (ret == 0) {
|
||||
ret = ::unlink(fn);
|
||||
if (ret == -1) {
|
||||
debug_only(warning("failed to remove stale attach pid file at %s", fn));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int AttachListener::pd_init() {
|
||||
JavaThread* thread = JavaThread::current();
|
||||
ThreadBlockInVM tbivm(thread);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2001, 2013, 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
|
||||
@ -107,7 +107,7 @@ static sa_handler_t set_signal(int sig, sa_handler_t disp, bool is_sigset) {
|
||||
|
||||
signal_lock();
|
||||
|
||||
sigused = (MASK(sig) & jvmsigs) != 0;
|
||||
sigused = (sig < MAXSIGNUM) && ((MASK(sig) & jvmsigs) != 0);
|
||||
if (jvm_signal_installed && sigused) {
|
||||
/* jvm has installed its signal handler for this signal. */
|
||||
/* Save the handler. Don't really install it. */
|
||||
@ -116,7 +116,7 @@ static sa_handler_t set_signal(int sig, sa_handler_t disp, bool is_sigset) {
|
||||
|
||||
signal_unlock();
|
||||
return oldhandler;
|
||||
} else if (jvm_signal_installing) {
|
||||
} else if (sig < MAXSIGNUM && jvm_signal_installing) {
|
||||
/* jvm is installing its signal handlers. Install the new
|
||||
* handlers and save the old ones. jvm uses sigaction().
|
||||
* Leave the piece here just in case. */
|
||||
@ -165,7 +165,7 @@ int sigaction(int sig, const struct sigaction *act, struct sigaction *oact) {
|
||||
|
||||
signal_lock();
|
||||
|
||||
sigused = (MASK(sig) & jvmsigs) != 0;
|
||||
sigused = (sig < MAXSIGNUM) && ((MASK(sig) & jvmsigs) != 0);
|
||||
if (jvm_signal_installed && sigused) {
|
||||
/* jvm has installed its signal handler for this signal. */
|
||||
/* Save the handler. Don't really install it. */
|
||||
@ -178,7 +178,7 @@ int sigaction(int sig, const struct sigaction *act, struct sigaction *oact) {
|
||||
|
||||
signal_unlock();
|
||||
return 0;
|
||||
} else if (jvm_signal_installing) {
|
||||
} else if (sig < MAXSIGNUM && jvm_signal_installing) {
|
||||
/* jvm is installing its signal handlers. Install the new
|
||||
* handlers and save the old ones. */
|
||||
res = call_os_sigaction(sig, act, &oldAct);
|
||||
|
@ -1682,12 +1682,13 @@ bool os::address_is_in_vm(address addr) {
|
||||
Dl_info dlinfo;
|
||||
|
||||
if (libjvm_base_addr == NULL) {
|
||||
dladdr(CAST_FROM_FN_PTR(void *, os::address_is_in_vm), &dlinfo);
|
||||
libjvm_base_addr = (address)dlinfo.dli_fbase;
|
||||
if (dladdr(CAST_FROM_FN_PTR(void *, os::address_is_in_vm), &dlinfo) != 0) {
|
||||
libjvm_base_addr = (address)dlinfo.dli_fbase;
|
||||
}
|
||||
assert(libjvm_base_addr !=NULL, "Cannot obtain base address for libjvm");
|
||||
}
|
||||
|
||||
if (dladdr((void *)addr, &dlinfo)) {
|
||||
if (dladdr((void *)addr, &dlinfo) != 0) {
|
||||
if (libjvm_base_addr == (address)dlinfo.dli_fbase) return true;
|
||||
}
|
||||
|
||||
@ -1696,24 +1697,30 @@ bool os::address_is_in_vm(address addr) {
|
||||
|
||||
bool os::dll_address_to_function_name(address addr, char *buf,
|
||||
int buflen, int *offset) {
|
||||
// buf is not optional, but offset is optional
|
||||
assert(buf != NULL, "sanity check");
|
||||
|
||||
Dl_info dlinfo;
|
||||
|
||||
if (dladdr((void*)addr, &dlinfo) && dlinfo.dli_sname != NULL) {
|
||||
if (buf != NULL) {
|
||||
if(!Decoder::demangle(dlinfo.dli_sname, buf, buflen)) {
|
||||
if (dladdr((void*)addr, &dlinfo) != 0) {
|
||||
// see if we have a matching symbol
|
||||
if (dlinfo.dli_saddr != NULL && dlinfo.dli_sname != NULL) {
|
||||
if (!Decoder::demangle(dlinfo.dli_sname, buf, buflen)) {
|
||||
jio_snprintf(buf, buflen, "%s", dlinfo.dli_sname);
|
||||
}
|
||||
if (offset != NULL) *offset = addr - (address)dlinfo.dli_saddr;
|
||||
return true;
|
||||
}
|
||||
if (offset != NULL) *offset = addr - (address)dlinfo.dli_saddr;
|
||||
return true;
|
||||
} else if (dlinfo.dli_fname != NULL && dlinfo.dli_fbase != 0) {
|
||||
if (Decoder::decode((address)(addr - (address)dlinfo.dli_fbase),
|
||||
buf, buflen, offset, dlinfo.dli_fname)) {
|
||||
return true;
|
||||
// no matching symbol so try for just file info
|
||||
if (dlinfo.dli_fname != NULL && dlinfo.dli_fbase != NULL) {
|
||||
if (Decoder::decode((address)(addr - (address)dlinfo.dli_fbase),
|
||||
buf, buflen, offset, dlinfo.dli_fname)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (buf != NULL) buf[0] = '\0';
|
||||
buf[0] = '\0';
|
||||
if (offset != NULL) *offset = -1;
|
||||
return false;
|
||||
}
|
||||
@ -1764,6 +1771,9 @@ static int address_to_library_name_callback(struct dl_phdr_info *info,
|
||||
|
||||
bool os::dll_address_to_library_name(address addr, char* buf,
|
||||
int buflen, int* offset) {
|
||||
// buf is not optional, but offset is optional
|
||||
assert(buf != NULL, "sanity check");
|
||||
|
||||
Dl_info dlinfo;
|
||||
struct _address_to_library_name data;
|
||||
|
||||
@ -1782,15 +1792,20 @@ bool os::dll_address_to_library_name(address addr, char* buf,
|
||||
// buf already contains library name
|
||||
if (offset) *offset = addr - data.base;
|
||||
return true;
|
||||
} else if (dladdr((void*)addr, &dlinfo)){
|
||||
if (buf) jio_snprintf(buf, buflen, "%s", dlinfo.dli_fname);
|
||||
if (offset) *offset = addr - (address)dlinfo.dli_fbase;
|
||||
return true;
|
||||
} else {
|
||||
if (buf) buf[0] = '\0';
|
||||
if (offset) *offset = -1;
|
||||
return false;
|
||||
}
|
||||
if (dladdr((void*)addr, &dlinfo) != 0) {
|
||||
if (dlinfo.dli_fname != NULL) {
|
||||
jio_snprintf(buf, buflen, "%s", dlinfo.dli_fname);
|
||||
}
|
||||
if (dlinfo.dli_fbase != NULL && offset != NULL) {
|
||||
*offset = addr - (address)dlinfo.dli_fbase;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
buf[0] = '\0';
|
||||
if (offset) *offset = -1;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Loads .dll/.so and
|
||||
@ -2317,8 +2332,11 @@ void os::jvm_path(char *buf, jint buflen) {
|
||||
bool ret = dll_address_to_library_name(
|
||||
CAST_FROM_FN_PTR(address, os::jvm_path),
|
||||
dli_fname, sizeof(dli_fname), NULL);
|
||||
assert(ret != 0, "cannot locate libjvm");
|
||||
char *rp = realpath(dli_fname, buf);
|
||||
assert(ret, "cannot locate libjvm");
|
||||
char *rp = NULL;
|
||||
if (ret && dli_fname[0] != '\0') {
|
||||
rp = realpath(dli_fname, buf);
|
||||
}
|
||||
if (rp == NULL)
|
||||
return;
|
||||
|
||||
@ -4730,20 +4748,20 @@ int os::Linux::safe_cond_timedwait(pthread_cond_t *_cond, pthread_mutex_t *_mute
|
||||
bool os::find(address addr, outputStream* st) {
|
||||
Dl_info dlinfo;
|
||||
memset(&dlinfo, 0, sizeof(dlinfo));
|
||||
if (dladdr(addr, &dlinfo)) {
|
||||
if (dladdr(addr, &dlinfo) != 0) {
|
||||
st->print(PTR_FORMAT ": ", addr);
|
||||
if (dlinfo.dli_sname != NULL) {
|
||||
if (dlinfo.dli_sname != NULL && dlinfo.dli_saddr != NULL) {
|
||||
st->print("%s+%#x", dlinfo.dli_sname,
|
||||
addr - (intptr_t)dlinfo.dli_saddr);
|
||||
} else if (dlinfo.dli_fname) {
|
||||
} else if (dlinfo.dli_fbase != NULL) {
|
||||
st->print("<offset %#x>", addr - (intptr_t)dlinfo.dli_fbase);
|
||||
} else {
|
||||
st->print("<absolute address>");
|
||||
}
|
||||
if (dlinfo.dli_fname) {
|
||||
if (dlinfo.dli_fname != NULL) {
|
||||
st->print(" in %s", dlinfo.dli_fname);
|
||||
}
|
||||
if (dlinfo.dli_fbase) {
|
||||
if (dlinfo.dli_fbase != NULL) {
|
||||
st->print(" at " PTR_FORMAT, dlinfo.dli_fbase);
|
||||
}
|
||||
st->cr();
|
||||
@ -4756,7 +4774,7 @@ bool os::find(address addr, outputStream* st) {
|
||||
if (!lowest) lowest = (address) dlinfo.dli_fbase;
|
||||
if (begin < lowest) begin = lowest;
|
||||
Dl_info dlinfo2;
|
||||
if (dladdr(end, &dlinfo2) && dlinfo2.dli_saddr != dlinfo.dli_saddr
|
||||
if (dladdr(end, &dlinfo2) != 0 && dlinfo2.dli_saddr != dlinfo.dli_saddr
|
||||
&& end > dlinfo2.dli_saddr && dlinfo2.dli_saddr > begin)
|
||||
end = (address) dlinfo2.dli_saddr;
|
||||
Disassembler::decode(begin, end, st);
|
||||
|
@ -259,3 +259,52 @@ const char* os::get_current_directory(char *buf, size_t buflen) {
|
||||
FILE* os::open(int fd, const char* mode) {
|
||||
return ::fdopen(fd, mode);
|
||||
}
|
||||
|
||||
os::WatcherThreadCrashProtection::WatcherThreadCrashProtection() {
|
||||
assert(Thread::current()->is_Watcher_thread(), "Must be WatcherThread");
|
||||
}
|
||||
|
||||
/*
|
||||
* See the caveats for this class in os_posix.hpp
|
||||
* Protects the callback call so that SIGSEGV / SIGBUS jumps back into this
|
||||
* method and returns false. If none of the signals are raised, returns true.
|
||||
* The callback is supposed to provide the method that should be protected.
|
||||
*/
|
||||
bool os::WatcherThreadCrashProtection::call(os::CrashProtectionCallback& cb) {
|
||||
assert(Thread::current()->is_Watcher_thread(), "Only for WatcherThread");
|
||||
assert(!WatcherThread::watcher_thread()->has_crash_protection(),
|
||||
"crash_protection already set?");
|
||||
|
||||
if (sigsetjmp(_jmpbuf, 1) == 0) {
|
||||
// make sure we can see in the signal handler that we have crash protection
|
||||
// installed
|
||||
WatcherThread::watcher_thread()->set_crash_protection(this);
|
||||
cb.call();
|
||||
// and clear the crash protection
|
||||
WatcherThread::watcher_thread()->set_crash_protection(NULL);
|
||||
return true;
|
||||
}
|
||||
// this happens when we siglongjmp() back
|
||||
WatcherThread::watcher_thread()->set_crash_protection(NULL);
|
||||
return false;
|
||||
}
|
||||
|
||||
void os::WatcherThreadCrashProtection::restore() {
|
||||
assert(WatcherThread::watcher_thread()->has_crash_protection(),
|
||||
"must have crash protection");
|
||||
|
||||
siglongjmp(_jmpbuf, 1);
|
||||
}
|
||||
|
||||
void os::WatcherThreadCrashProtection::check_crash_protection(int sig,
|
||||
Thread* thread) {
|
||||
|
||||
if (thread != NULL &&
|
||||
thread->is_Watcher_thread() &&
|
||||
WatcherThread::watcher_thread()->has_crash_protection()) {
|
||||
|
||||
if (sig == SIGSEGV || sig == SIGBUS) {
|
||||
WatcherThread::watcher_thread()->crash_protection()->restore();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -37,5 +37,24 @@ protected:
|
||||
|
||||
};
|
||||
|
||||
/*
|
||||
* Crash protection for the watcher thread. Wrap the callback
|
||||
* with a sigsetjmp and in case of a SIGSEGV/SIGBUS we siglongjmp
|
||||
* back.
|
||||
* To be able to use this - don't take locks, don't rely on destructors,
|
||||
* don't make OS library calls, don't allocate memory, don't print,
|
||||
* don't call code that could leave the heap / memory in an inconsistent state,
|
||||
* or anything else where we are not in control if we suddenly jump out.
|
||||
*/
|
||||
class WatcherThreadCrashProtection : public StackObj {
|
||||
public:
|
||||
WatcherThreadCrashProtection();
|
||||
bool call(os::CrashProtectionCallback& cb);
|
||||
|
||||
static void check_crash_protection(int signal, Thread* thread);
|
||||
private:
|
||||
void restore();
|
||||
sigjmp_buf _jmpbuf;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2005, 2013, 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
|
||||
@ -576,6 +576,30 @@ AttachOperation* AttachListener::dequeue() {
|
||||
return op;
|
||||
}
|
||||
|
||||
|
||||
// Performs initialization at vm startup
|
||||
// For Solaris we remove any stale .java_pid file which could cause
|
||||
// an attaching process to think we are ready to receive a door_call
|
||||
// before we are properly initialized
|
||||
|
||||
void AttachListener::vm_start() {
|
||||
char fn[PATH_MAX+1];
|
||||
struct stat64 st;
|
||||
int ret;
|
||||
|
||||
int n = snprintf(fn, sizeof(fn), "%s/.java_pid%d",
|
||||
os::get_temp_directory(), os::current_process_id());
|
||||
assert(n < sizeof(fn), "java_pid file name buffer overflow");
|
||||
|
||||
RESTARTABLE(::stat64(fn, &st), ret);
|
||||
if (ret == 0) {
|
||||
ret = ::unlink(fn);
|
||||
if (ret == -1) {
|
||||
debug_only(warning("failed to remove stale attach pid file at %s", fn));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int AttachListener::pd_init() {
|
||||
JavaThread* thread = JavaThread::current();
|
||||
ThreadBlockInVM tbivm(thread);
|
||||
|
@ -30,15 +30,6 @@
|
||||
//
|
||||
#define RUNTIME_OS_FLAGS(develop, develop_pd, product, product_pd, diagnostic, notproduct) \
|
||||
\
|
||||
product(bool, UseISM, false, \
|
||||
"Use Intimate Shared Memory (Solaris Only)") \
|
||||
\
|
||||
product(bool, UsePermISM, false, \
|
||||
"Obsolete flag for compatibility (same as UseISM)") \
|
||||
\
|
||||
product(bool, UseMPSS, true, \
|
||||
"Use Multiple Page Size Support (Solaris 9 Only)") \
|
||||
\
|
||||
product(bool, UseExtendedFileIO, true, \
|
||||
"Enable workaround for limitations of stdio FILE structure")
|
||||
|
||||
|
@ -115,45 +115,6 @@
|
||||
// for timer info max values which include all bits
|
||||
#define ALL_64_BITS CONST64(0xFFFFFFFFFFFFFFFF)
|
||||
|
||||
#ifdef _GNU_SOURCE
|
||||
// See bug #6514594
|
||||
extern "C" int madvise(caddr_t, size_t, int);
|
||||
extern "C" int memcntl(caddr_t addr, size_t len, int cmd, caddr_t arg,
|
||||
int attr, int mask);
|
||||
#endif //_GNU_SOURCE
|
||||
|
||||
/*
|
||||
MPSS Changes Start.
|
||||
The JVM binary needs to be built and run on pre-Solaris 9
|
||||
systems, but the constants needed by MPSS are only in Solaris 9
|
||||
header files. They are textually replicated here to allow
|
||||
building on earlier systems. Once building on Solaris 8 is
|
||||
no longer a requirement, these #defines can be replaced by ordinary
|
||||
system .h inclusion.
|
||||
|
||||
In earlier versions of the JDK and Solaris, we used ISM for large pages.
|
||||
But ISM requires shared memory to achieve this and thus has many caveats.
|
||||
MPSS is a fully transparent and is a cleaner way to get large pages.
|
||||
Although we still require keeping ISM for backward compatiblitiy as well as
|
||||
giving the opportunity to use large pages on older systems it is
|
||||
recommended that MPSS be used for Solaris 9 and above.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef MC_HAT_ADVISE
|
||||
|
||||
struct memcntl_mha {
|
||||
uint_t mha_cmd; /* command(s) */
|
||||
uint_t mha_flags;
|
||||
size_t mha_pagesize;
|
||||
};
|
||||
#define MC_HAT_ADVISE 7 /* advise hat map size */
|
||||
#define MHA_MAPSIZE_VA 0x1 /* set preferred page size */
|
||||
#define MAP_ALIGN 0x200 /* addr specifies alignment */
|
||||
|
||||
#endif
|
||||
// MPSS Changes End.
|
||||
|
||||
|
||||
// Here are some liblgrp types from sys/lgrp_user.h to be able to
|
||||
// compile on older systems without this header file.
|
||||
@ -172,32 +133,6 @@ struct memcntl_mha {
|
||||
# define LGRP_RSRC_MEM 1 /* memory resources */
|
||||
#endif
|
||||
|
||||
// Some more macros from sys/mman.h that are not present in Solaris 8.
|
||||
|
||||
#ifndef MAX_MEMINFO_CNT
|
||||
/*
|
||||
* info_req request type definitions for meminfo
|
||||
* request types starting with MEMINFO_V are used for Virtual addresses
|
||||
* and should not be mixed with MEMINFO_PLGRP which is targeted for Physical
|
||||
* addresses
|
||||
*/
|
||||
# define MEMINFO_SHIFT 16
|
||||
# define MEMINFO_MASK (0xFF << MEMINFO_SHIFT)
|
||||
# define MEMINFO_VPHYSICAL (0x01 << MEMINFO_SHIFT) /* get physical addr */
|
||||
# define MEMINFO_VLGRP (0x02 << MEMINFO_SHIFT) /* get lgroup */
|
||||
# define MEMINFO_VPAGESIZE (0x03 << MEMINFO_SHIFT) /* size of phys page */
|
||||
# define MEMINFO_VREPLCNT (0x04 << MEMINFO_SHIFT) /* no. of replica */
|
||||
# define MEMINFO_VREPL (0x05 << MEMINFO_SHIFT) /* physical replica */
|
||||
# define MEMINFO_VREPL_LGRP (0x06 << MEMINFO_SHIFT) /* lgrp of replica */
|
||||
# define MEMINFO_PLGRP (0x07 << MEMINFO_SHIFT) /* lgroup for paddr */
|
||||
|
||||
/* maximum number of addresses meminfo() can process at a time */
|
||||
# define MAX_MEMINFO_CNT 256
|
||||
|
||||
/* maximum number of request types */
|
||||
# define MAX_MEMINFO_REQ 31
|
||||
#endif
|
||||
|
||||
// see thr_setprio(3T) for the basis of these numbers
|
||||
#define MinimumPriority 0
|
||||
#define NormalPriority 64
|
||||
@ -1924,12 +1859,13 @@ bool os::address_is_in_vm(address addr) {
|
||||
Dl_info dlinfo;
|
||||
|
||||
if (libjvm_base_addr == NULL) {
|
||||
dladdr(CAST_FROM_FN_PTR(void *, os::address_is_in_vm), &dlinfo);
|
||||
libjvm_base_addr = (address)dlinfo.dli_fbase;
|
||||
if (dladdr(CAST_FROM_FN_PTR(void *, os::address_is_in_vm), &dlinfo) != 0) {
|
||||
libjvm_base_addr = (address)dlinfo.dli_fbase;
|
||||
}
|
||||
assert(libjvm_base_addr !=NULL, "Cannot obtain base address for libjvm");
|
||||
}
|
||||
|
||||
if (dladdr((void *)addr, &dlinfo)) {
|
||||
if (dladdr((void *)addr, &dlinfo) != 0) {
|
||||
if (libjvm_base_addr == (address)dlinfo.dli_fbase) return true;
|
||||
}
|
||||
|
||||
@ -1941,114 +1877,133 @@ static dladdr1_func_type dladdr1_func = NULL;
|
||||
|
||||
bool os::dll_address_to_function_name(address addr, char *buf,
|
||||
int buflen, int * offset) {
|
||||
// buf is not optional, but offset is optional
|
||||
assert(buf != NULL, "sanity check");
|
||||
|
||||
Dl_info dlinfo;
|
||||
|
||||
// dladdr1_func was initialized in os::init()
|
||||
if (dladdr1_func){
|
||||
// yes, we have dladdr1
|
||||
if (dladdr1_func != NULL) {
|
||||
// yes, we have dladdr1
|
||||
|
||||
// Support for dladdr1 is checked at runtime; it may be
|
||||
// available even if the vm is built on a machine that does
|
||||
// not have dladdr1 support. Make sure there is a value for
|
||||
// RTLD_DL_SYMENT.
|
||||
#ifndef RTLD_DL_SYMENT
|
||||
#define RTLD_DL_SYMENT 1
|
||||
#endif
|
||||
// Support for dladdr1 is checked at runtime; it may be
|
||||
// available even if the vm is built on a machine that does
|
||||
// not have dladdr1 support. Make sure there is a value for
|
||||
// RTLD_DL_SYMENT.
|
||||
#ifndef RTLD_DL_SYMENT
|
||||
#define RTLD_DL_SYMENT 1
|
||||
#endif
|
||||
#ifdef _LP64
|
||||
Elf64_Sym * info;
|
||||
Elf64_Sym * info;
|
||||
#else
|
||||
Elf32_Sym * info;
|
||||
Elf32_Sym * info;
|
||||
#endif
|
||||
if (dladdr1_func((void *)addr, &dlinfo, (void **)&info,
|
||||
RTLD_DL_SYMENT)) {
|
||||
if ((char *)dlinfo.dli_saddr + info->st_size > (char *)addr) {
|
||||
if (buf != NULL) {
|
||||
if (!Decoder::demangle(dlinfo.dli_sname, buf, buflen))
|
||||
jio_snprintf(buf, buflen, "%s", dlinfo.dli_sname);
|
||||
}
|
||||
if (offset != NULL) *offset = addr - (address)dlinfo.dli_saddr;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (dlinfo.dli_fname != NULL && dlinfo.dli_fbase != 0) {
|
||||
if (Decoder::decode((address)(addr - (address)dlinfo.dli_fbase),
|
||||
buf, buflen, offset, dlinfo.dli_fname)) {
|
||||
if (dladdr1_func((void *)addr, &dlinfo, (void **)&info,
|
||||
RTLD_DL_SYMENT) != 0) {
|
||||
// see if we have a matching symbol that covers our address
|
||||
if (dlinfo.dli_saddr != NULL &&
|
||||
(char *)dlinfo.dli_saddr + info->st_size > (char *)addr) {
|
||||
if (dlinfo.dli_sname != NULL) {
|
||||
if (!Decoder::demangle(dlinfo.dli_sname, buf, buflen)) {
|
||||
jio_snprintf(buf, buflen, "%s", dlinfo.dli_sname);
|
||||
}
|
||||
if (offset != NULL) *offset = addr - (address)dlinfo.dli_saddr;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (buf != NULL) buf[0] = '\0';
|
||||
if (offset != NULL) *offset = -1;
|
||||
return false;
|
||||
} else {
|
||||
// no, only dladdr is available
|
||||
if (dladdr((void *)addr, &dlinfo)) {
|
||||
if (buf != NULL) {
|
||||
if (!Decoder::demangle(dlinfo.dli_sname, buf, buflen))
|
||||
jio_snprintf(buf, buflen, dlinfo.dli_sname);
|
||||
}
|
||||
if (offset != NULL) *offset = addr - (address)dlinfo.dli_saddr;
|
||||
return true;
|
||||
} else if (dlinfo.dli_fname != NULL && dlinfo.dli_fbase != 0) {
|
||||
// no matching symbol so try for just file info
|
||||
if (dlinfo.dli_fname != NULL && dlinfo.dli_fbase != NULL) {
|
||||
if (Decoder::decode((address)(addr - (address)dlinfo.dli_fbase),
|
||||
buf, buflen, offset, dlinfo.dli_fname)) {
|
||||
buf, buflen, offset, dlinfo.dli_fname)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (buf != NULL) buf[0] = '\0';
|
||||
if (offset != NULL) *offset = -1;
|
||||
return false;
|
||||
}
|
||||
buf[0] = '\0';
|
||||
if (offset != NULL) *offset = -1;
|
||||
return false;
|
||||
}
|
||||
|
||||
// no, only dladdr is available
|
||||
if (dladdr((void *)addr, &dlinfo) != 0) {
|
||||
// see if we have a matching symbol
|
||||
if (dlinfo.dli_saddr != NULL && dlinfo.dli_sname != NULL) {
|
||||
if (!Decoder::demangle(dlinfo.dli_sname, buf, buflen)) {
|
||||
jio_snprintf(buf, buflen, dlinfo.dli_sname);
|
||||
}
|
||||
if (offset != NULL) *offset = addr - (address)dlinfo.dli_saddr;
|
||||
return true;
|
||||
}
|
||||
// no matching symbol so try for just file info
|
||||
if (dlinfo.dli_fname != NULL && dlinfo.dli_fbase != NULL) {
|
||||
if (Decoder::decode((address)(addr - (address)dlinfo.dli_fbase),
|
||||
buf, buflen, offset, dlinfo.dli_fname)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
buf[0] = '\0';
|
||||
if (offset != NULL) *offset = -1;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool os::dll_address_to_library_name(address addr, char* buf,
|
||||
int buflen, int* offset) {
|
||||
// buf is not optional, but offset is optional
|
||||
assert(buf != NULL, "sanity check");
|
||||
|
||||
Dl_info dlinfo;
|
||||
|
||||
if (dladdr((void*)addr, &dlinfo)){
|
||||
if (buf) jio_snprintf(buf, buflen, "%s", dlinfo.dli_fname);
|
||||
if (offset) *offset = addr - (address)dlinfo.dli_fbase;
|
||||
return true;
|
||||
} else {
|
||||
if (buf) buf[0] = '\0';
|
||||
if (offset) *offset = -1;
|
||||
return false;
|
||||
if (dladdr((void*)addr, &dlinfo) != 0) {
|
||||
if (dlinfo.dli_fname != NULL) {
|
||||
jio_snprintf(buf, buflen, "%s", dlinfo.dli_fname);
|
||||
}
|
||||
if (dlinfo.dli_fbase != NULL && offset != NULL) {
|
||||
*offset = addr - (address)dlinfo.dli_fbase;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
buf[0] = '\0';
|
||||
if (offset) *offset = -1;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Prints the names and full paths of all opened dynamic libraries
|
||||
// for current process
|
||||
void os::print_dll_info(outputStream * st) {
|
||||
Dl_info dli;
|
||||
void *handle;
|
||||
Link_map *map;
|
||||
Link_map *p;
|
||||
Dl_info dli;
|
||||
void *handle;
|
||||
Link_map *map;
|
||||
Link_map *p;
|
||||
|
||||
st->print_cr("Dynamic libraries:"); st->flush();
|
||||
st->print_cr("Dynamic libraries:"); st->flush();
|
||||
|
||||
if (!dladdr(CAST_FROM_FN_PTR(void *, os::print_dll_info), &dli)) {
|
||||
st->print_cr("Error: Cannot print dynamic libraries.");
|
||||
return;
|
||||
}
|
||||
handle = dlopen(dli.dli_fname, RTLD_LAZY);
|
||||
if (handle == NULL) {
|
||||
st->print_cr("Error: Cannot print dynamic libraries.");
|
||||
return;
|
||||
}
|
||||
dlinfo(handle, RTLD_DI_LINKMAP, &map);
|
||||
if (map == NULL) {
|
||||
st->print_cr("Error: Cannot print dynamic libraries.");
|
||||
return;
|
||||
}
|
||||
if (dladdr(CAST_FROM_FN_PTR(void *, os::print_dll_info), &dli) == 0 ||
|
||||
dli.dli_fname == NULL) {
|
||||
st->print_cr("Error: Cannot print dynamic libraries.");
|
||||
return;
|
||||
}
|
||||
handle = dlopen(dli.dli_fname, RTLD_LAZY);
|
||||
if (handle == NULL) {
|
||||
st->print_cr("Error: Cannot print dynamic libraries.");
|
||||
return;
|
||||
}
|
||||
dlinfo(handle, RTLD_DI_LINKMAP, &map);
|
||||
if (map == NULL) {
|
||||
st->print_cr("Error: Cannot print dynamic libraries.");
|
||||
return;
|
||||
}
|
||||
|
||||
while (map->l_prev != NULL)
|
||||
map = map->l_prev;
|
||||
while (map->l_prev != NULL)
|
||||
map = map->l_prev;
|
||||
|
||||
while (map != NULL) {
|
||||
st->print_cr(PTR_FORMAT " \t%s", map->l_addr, map->l_name);
|
||||
map = map->l_next;
|
||||
}
|
||||
while (map != NULL) {
|
||||
st->print_cr(PTR_FORMAT " \t%s", map->l_addr, map->l_name);
|
||||
map = map->l_next;
|
||||
}
|
||||
|
||||
dlclose(handle);
|
||||
dlclose(handle);
|
||||
}
|
||||
|
||||
// Loads .dll/.so and
|
||||
@ -2475,7 +2430,12 @@ void os::jvm_path(char *buf, jint buflen) {
|
||||
Dl_info dlinfo;
|
||||
int ret = dladdr(CAST_FROM_FN_PTR(void *, os::jvm_path), &dlinfo);
|
||||
assert(ret != 0, "cannot locate libjvm");
|
||||
realpath((char *)dlinfo.dli_fname, buf);
|
||||
if (ret != 0 && dlinfo.dli_fname != NULL) {
|
||||
realpath((char *)dlinfo.dli_fname, buf);
|
||||
} else {
|
||||
buf[0] = '\0';
|
||||
return;
|
||||
}
|
||||
|
||||
if (Arguments::created_by_gamma_launcher()) {
|
||||
// Support for the gamma launcher. Typical value for buf is
|
||||
@ -2859,7 +2819,7 @@ int os::Solaris::commit_memory_impl(char* addr, size_t bytes,
|
||||
size_t alignment_hint, bool exec) {
|
||||
int err = Solaris::commit_memory_impl(addr, bytes, exec);
|
||||
if (err == 0) {
|
||||
if (UseMPSS && alignment_hint > (size_t)vm_page_size()) {
|
||||
if (UseLargePages && (alignment_hint > (size_t)vm_page_size())) {
|
||||
// If the large page size has been set and the VM
|
||||
// is using large pages, use the large page size
|
||||
// if it is smaller than the alignment hint. This is
|
||||
@ -2878,7 +2838,7 @@ int os::Solaris::commit_memory_impl(char* addr, size_t bytes,
|
||||
page_size = alignment_hint;
|
||||
}
|
||||
// Since this is a hint, ignore any failures.
|
||||
(void)Solaris::set_mpss_range(addr, bytes, page_size);
|
||||
(void)Solaris::setup_large_pages(addr, bytes, page_size);
|
||||
}
|
||||
}
|
||||
return err;
|
||||
@ -2921,8 +2881,8 @@ bool os::remove_stack_guard_pages(char* addr, size_t size) {
|
||||
void os::pd_realign_memory(char *addr, size_t bytes, size_t alignment_hint) {
|
||||
assert((intptr_t)addr % alignment_hint == 0, "Address should be aligned.");
|
||||
assert((intptr_t)(addr + bytes) % alignment_hint == 0, "End should be aligned.");
|
||||
if (UseLargePages && UseMPSS) {
|
||||
Solaris::set_mpss_range(addr, bytes, alignment_hint);
|
||||
if (UseLargePages) {
|
||||
Solaris::setup_large_pages(addr, bytes, alignment_hint);
|
||||
}
|
||||
}
|
||||
|
||||
@ -3321,47 +3281,8 @@ bool os::unguard_memory(char* addr, size_t bytes) {
|
||||
}
|
||||
|
||||
// Large page support
|
||||
|
||||
// UseLargePages is the master flag to enable/disable large page memory.
|
||||
// UseMPSS and UseISM are supported for compatibility reasons. Their combined
|
||||
// effects can be described in the following table:
|
||||
//
|
||||
// UseLargePages UseMPSS UseISM
|
||||
// false * * => UseLargePages is the master switch, turning
|
||||
// it off will turn off both UseMPSS and
|
||||
// UseISM. VM will not use large page memory
|
||||
// regardless the settings of UseMPSS/UseISM.
|
||||
// true false false => Unless future Solaris provides other
|
||||
// mechanism to use large page memory, this
|
||||
// combination is equivalent to -UseLargePages,
|
||||
// VM will not use large page memory
|
||||
// true true false => JVM will use MPSS for large page memory.
|
||||
// This is the default behavior.
|
||||
// true false true => JVM will use ISM for large page memory.
|
||||
// true true true => JVM will use ISM if it is available.
|
||||
// Otherwise, JVM will fall back to MPSS.
|
||||
// Becaues ISM is now available on all
|
||||
// supported Solaris versions, this combination
|
||||
// is equivalent to +UseISM -UseMPSS.
|
||||
|
||||
static size_t _large_page_size = 0;
|
||||
|
||||
bool os::Solaris::ism_sanity_check(bool warn, size_t * page_size) {
|
||||
// x86 uses either 2M or 4M page, depending on whether PAE (Physical Address
|
||||
// Extensions) mode is enabled. AMD64/EM64T uses 2M page in 64bit mode. Sparc
|
||||
// can support multiple page sizes.
|
||||
|
||||
// Don't bother to probe page size because getpagesizes() comes with MPSS.
|
||||
// ISM is only recommended on old Solaris where there is no MPSS support.
|
||||
// Simply choose a conservative value as default.
|
||||
*page_size = LargePageSizeInBytes ? LargePageSizeInBytes :
|
||||
SPARC_ONLY(4 * M) IA32_ONLY(4 * M) AMD64_ONLY(2 * M)
|
||||
ARM_ONLY(2 * M);
|
||||
|
||||
// ISM is available on all supported Solaris versions
|
||||
return true;
|
||||
}
|
||||
|
||||
// Insertion sort for small arrays (descending order).
|
||||
static void insertion_sort_descending(size_t* array, int len) {
|
||||
for (int i = 0; i < len; i++) {
|
||||
@ -3374,7 +3295,7 @@ static void insertion_sort_descending(size_t* array, int len) {
|
||||
}
|
||||
}
|
||||
|
||||
bool os::Solaris::mpss_sanity_check(bool warn, size_t * page_size) {
|
||||
bool os::Solaris::mpss_sanity_check(bool warn, size_t* page_size) {
|
||||
const unsigned int usable_count = VM_Version::page_size_count();
|
||||
if (usable_count == 1) {
|
||||
return false;
|
||||
@ -3440,41 +3361,24 @@ bool os::Solaris::mpss_sanity_check(bool warn, size_t * page_size) {
|
||||
}
|
||||
|
||||
void os::large_page_init() {
|
||||
if (!UseLargePages) {
|
||||
UseISM = false;
|
||||
UseMPSS = false;
|
||||
return;
|
||||
if (UseLargePages) {
|
||||
// print a warning if any large page related flag is specified on command line
|
||||
bool warn_on_failure = !FLAG_IS_DEFAULT(UseLargePages) ||
|
||||
!FLAG_IS_DEFAULT(LargePageSizeInBytes);
|
||||
|
||||
UseLargePages = Solaris::mpss_sanity_check(warn_on_failure, &_large_page_size);
|
||||
}
|
||||
|
||||
// print a warning if any large page related flag is specified on command line
|
||||
bool warn_on_failure = !FLAG_IS_DEFAULT(UseLargePages) ||
|
||||
!FLAG_IS_DEFAULT(UseISM) ||
|
||||
!FLAG_IS_DEFAULT(UseMPSS) ||
|
||||
!FLAG_IS_DEFAULT(LargePageSizeInBytes);
|
||||
UseISM = UseISM &&
|
||||
Solaris::ism_sanity_check(warn_on_failure, &_large_page_size);
|
||||
if (UseISM) {
|
||||
// ISM disables MPSS to be compatible with old JDK behavior
|
||||
UseMPSS = false;
|
||||
_page_sizes[0] = _large_page_size;
|
||||
_page_sizes[1] = vm_page_size();
|
||||
}
|
||||
|
||||
UseMPSS = UseMPSS &&
|
||||
Solaris::mpss_sanity_check(warn_on_failure, &_large_page_size);
|
||||
|
||||
UseLargePages = UseISM || UseMPSS;
|
||||
}
|
||||
|
||||
bool os::Solaris::set_mpss_range(caddr_t start, size_t bytes, size_t align) {
|
||||
bool os::Solaris::setup_large_pages(caddr_t start, size_t bytes, size_t align) {
|
||||
// Signal to OS that we want large pages for addresses
|
||||
// from addr, addr + bytes
|
||||
struct memcntl_mha mpss_struct;
|
||||
mpss_struct.mha_cmd = MHA_MAPSIZE_VA;
|
||||
mpss_struct.mha_pagesize = align;
|
||||
mpss_struct.mha_flags = 0;
|
||||
if (memcntl(start, bytes, MC_HAT_ADVISE,
|
||||
(caddr_t) &mpss_struct, 0, 0) < 0) {
|
||||
// Upon successful completion, memcntl() returns 0
|
||||
if (memcntl(start, bytes, MC_HAT_ADVISE, (caddr_t) &mpss_struct, 0, 0)) {
|
||||
debug_only(warning("Attempt to use MPSS failed."));
|
||||
return false;
|
||||
}
|
||||
@ -3482,72 +3386,13 @@ bool os::Solaris::set_mpss_range(caddr_t start, size_t bytes, size_t align) {
|
||||
}
|
||||
|
||||
char* os::reserve_memory_special(size_t size, char* addr, bool exec) {
|
||||
// "exec" is passed in but not used. Creating the shared image for
|
||||
// the code cache doesn't have an SHM_X executable permission to check.
|
||||
assert(UseLargePages && UseISM, "only for ISM large pages");
|
||||
|
||||
char* retAddr = NULL;
|
||||
int shmid;
|
||||
key_t ismKey;
|
||||
|
||||
bool warn_on_failure = UseISM &&
|
||||
(!FLAG_IS_DEFAULT(UseLargePages) ||
|
||||
!FLAG_IS_DEFAULT(UseISM) ||
|
||||
!FLAG_IS_DEFAULT(LargePageSizeInBytes)
|
||||
);
|
||||
char msg[128];
|
||||
|
||||
ismKey = IPC_PRIVATE;
|
||||
|
||||
// Create a large shared memory region to attach to based on size.
|
||||
// Currently, size is the total size of the heap
|
||||
shmid = shmget(ismKey, size, SHM_R | SHM_W | IPC_CREAT);
|
||||
if (shmid == -1){
|
||||
if (warn_on_failure) {
|
||||
jio_snprintf(msg, sizeof(msg), "Failed to reserve shared memory (errno = %d).", errno);
|
||||
warning(msg);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Attach to the region
|
||||
retAddr = (char *) shmat(shmid, 0, SHM_SHARE_MMU | SHM_R | SHM_W);
|
||||
int err = errno;
|
||||
|
||||
// Remove shmid. If shmat() is successful, the actual shared memory segment
|
||||
// will be deleted when it's detached by shmdt() or when the process
|
||||
// terminates. If shmat() is not successful this will remove the shared
|
||||
// segment immediately.
|
||||
shmctl(shmid, IPC_RMID, NULL);
|
||||
|
||||
if (retAddr == (char *) -1) {
|
||||
if (warn_on_failure) {
|
||||
jio_snprintf(msg, sizeof(msg), "Failed to attach shared memory (errno = %d).", err);
|
||||
warning(msg);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
if ((retAddr != NULL) && UseNUMAInterleaving) {
|
||||
numa_make_global(retAddr, size);
|
||||
}
|
||||
|
||||
// The memory is committed
|
||||
MemTracker::record_virtual_memory_reserve_and_commit((address)retAddr, size, mtNone, CURRENT_PC);
|
||||
|
||||
return retAddr;
|
||||
fatal("os::reserve_memory_special should not be called on Solaris.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool os::release_memory_special(char* base, size_t bytes) {
|
||||
MemTracker::Tracker tkr = MemTracker::get_virtual_memory_release_tracker();
|
||||
// detaching the SHM segment will also delete it, see reserve_memory_special()
|
||||
int rslt = shmdt(base);
|
||||
if (rslt == 0) {
|
||||
tkr.record((address)base, bytes);
|
||||
return true;
|
||||
} else {
|
||||
tkr.discard();
|
||||
return false;
|
||||
}
|
||||
fatal("os::release_memory_special should not be called on Solaris.");
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t os::large_page_size() {
|
||||
@ -3557,11 +3402,11 @@ size_t os::large_page_size() {
|
||||
// MPSS allows application to commit large page memory on demand; with ISM
|
||||
// the entire memory region must be allocated as shared memory.
|
||||
bool os::can_commit_large_page_memory() {
|
||||
return UseISM ? false : true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool os::can_execute_large_page_memory() {
|
||||
return UseISM ? false : true;
|
||||
return true;
|
||||
}
|
||||
|
||||
static int os_sleep(jlong millis, bool interruptible) {
|
||||
@ -3835,28 +3680,6 @@ static bool priocntl_enable = false;
|
||||
static const int criticalPrio = 60; // FX/60 is critical thread class/priority on T4
|
||||
static int java_MaxPriority_to_os_priority = 0; // Saved mapping
|
||||
|
||||
// Call the version of priocntl suitable for all supported versions
|
||||
// of Solaris. We need to call through this wrapper so that we can
|
||||
// build on Solaris 9 and run on Solaris 8, 9 and 10.
|
||||
//
|
||||
// This code should be removed if we ever stop supporting Solaris 8
|
||||
// and earlier releases.
|
||||
|
||||
static long priocntl_stub(int pcver, idtype_t idtype, id_t id, int cmd, caddr_t arg);
|
||||
typedef long (*priocntl_type)(int pcver, idtype_t idtype, id_t id, int cmd, caddr_t arg);
|
||||
static priocntl_type priocntl_ptr = priocntl_stub;
|
||||
|
||||
// Stub to set the value of the real pointer, and then call the real
|
||||
// function.
|
||||
|
||||
static long priocntl_stub(int pcver, idtype_t idtype, id_t id, int cmd, caddr_t arg) {
|
||||
// Try Solaris 8- name only.
|
||||
priocntl_type tmp = (priocntl_type)dlsym(RTLD_DEFAULT, "__priocntl");
|
||||
guarantee(tmp != NULL, "priocntl function not found.");
|
||||
priocntl_ptr = tmp;
|
||||
return (*priocntl_ptr)(PC_VERSION, idtype, id, cmd, arg);
|
||||
}
|
||||
|
||||
|
||||
// lwp_priocntl_init
|
||||
//
|
||||
@ -3864,9 +3687,7 @@ static long priocntl_stub(int pcver, idtype_t idtype, id_t id, int cmd, caddr_t
|
||||
//
|
||||
// Return errno or 0 if OK.
|
||||
//
|
||||
static
|
||||
int lwp_priocntl_init ()
|
||||
{
|
||||
static int lwp_priocntl_init () {
|
||||
int rslt;
|
||||
pcinfo_t ClassInfo;
|
||||
pcparms_t ParmInfo;
|
||||
@ -3906,7 +3727,7 @@ int lwp_priocntl_init ()
|
||||
|
||||
strcpy(ClassInfo.pc_clname, "TS");
|
||||
ClassInfo.pc_cid = -1;
|
||||
rslt = (*priocntl_ptr)(PC_VERSION, P_ALL, 0, PC_GETCID, (caddr_t)&ClassInfo);
|
||||
rslt = priocntl(P_ALL, 0, PC_GETCID, (caddr_t)&ClassInfo);
|
||||
if (rslt < 0) return errno;
|
||||
assert(ClassInfo.pc_cid != -1, "cid for TS class is -1");
|
||||
tsLimits.schedPolicy = ClassInfo.pc_cid;
|
||||
@ -3915,7 +3736,7 @@ int lwp_priocntl_init ()
|
||||
|
||||
strcpy(ClassInfo.pc_clname, "IA");
|
||||
ClassInfo.pc_cid = -1;
|
||||
rslt = (*priocntl_ptr)(PC_VERSION, P_ALL, 0, PC_GETCID, (caddr_t)&ClassInfo);
|
||||
rslt = priocntl(P_ALL, 0, PC_GETCID, (caddr_t)&ClassInfo);
|
||||
if (rslt < 0) return errno;
|
||||
assert(ClassInfo.pc_cid != -1, "cid for IA class is -1");
|
||||
iaLimits.schedPolicy = ClassInfo.pc_cid;
|
||||
@ -3924,7 +3745,7 @@ int lwp_priocntl_init ()
|
||||
|
||||
strcpy(ClassInfo.pc_clname, "RT");
|
||||
ClassInfo.pc_cid = -1;
|
||||
rslt = (*priocntl_ptr)(PC_VERSION, P_ALL, 0, PC_GETCID, (caddr_t)&ClassInfo);
|
||||
rslt = priocntl(P_ALL, 0, PC_GETCID, (caddr_t)&ClassInfo);
|
||||
if (rslt < 0) return errno;
|
||||
assert(ClassInfo.pc_cid != -1, "cid for RT class is -1");
|
||||
rtLimits.schedPolicy = ClassInfo.pc_cid;
|
||||
@ -3933,7 +3754,7 @@ int lwp_priocntl_init ()
|
||||
|
||||
strcpy(ClassInfo.pc_clname, "FX");
|
||||
ClassInfo.pc_cid = -1;
|
||||
rslt = (*priocntl_ptr)(PC_VERSION, P_ALL, 0, PC_GETCID, (caddr_t)&ClassInfo);
|
||||
rslt = priocntl(P_ALL, 0, PC_GETCID, (caddr_t)&ClassInfo);
|
||||
if (rslt < 0) return errno;
|
||||
assert(ClassInfo.pc_cid != -1, "cid for FX class is -1");
|
||||
fxLimits.schedPolicy = ClassInfo.pc_cid;
|
||||
@ -3944,7 +3765,7 @@ int lwp_priocntl_init ()
|
||||
// This will normally be IA, TS or, rarely, FX or RT.
|
||||
memset(&ParmInfo, 0, sizeof(ParmInfo));
|
||||
ParmInfo.pc_cid = PC_CLNULL;
|
||||
rslt = (*priocntl_ptr) (PC_VERSION, P_PID, P_MYID, PC_GETPARMS, (caddr_t)&ParmInfo);
|
||||
rslt = priocntl(P_PID, P_MYID, PC_GETPARMS, (caddr_t)&ParmInfo);
|
||||
if (rslt < 0) return errno;
|
||||
myClass = ParmInfo.pc_cid;
|
||||
|
||||
@ -3952,7 +3773,7 @@ int lwp_priocntl_init ()
|
||||
// about the class.
|
||||
ClassInfo.pc_cid = myClass;
|
||||
ClassInfo.pc_clname[0] = 0;
|
||||
rslt = (*priocntl_ptr) (PC_VERSION, (idtype)0, 0, PC_GETCLINFO, (caddr_t)&ClassInfo);
|
||||
rslt = priocntl((idtype)0, 0, PC_GETCLINFO, (caddr_t)&ClassInfo);
|
||||
if (rslt < 0) return errno;
|
||||
|
||||
if (ThreadPriorityVerbose) {
|
||||
@ -3961,7 +3782,7 @@ int lwp_priocntl_init ()
|
||||
|
||||
memset(&ParmInfo, 0, sizeof(pcparms_t));
|
||||
ParmInfo.pc_cid = PC_CLNULL;
|
||||
rslt = (*priocntl_ptr)(PC_VERSION, P_PID, P_MYID, PC_GETPARMS, (caddr_t)&ParmInfo);
|
||||
rslt = priocntl(P_PID, P_MYID, PC_GETPARMS, (caddr_t)&ParmInfo);
|
||||
if (rslt < 0) return errno;
|
||||
|
||||
if (ParmInfo.pc_cid == rtLimits.schedPolicy) {
|
||||
@ -4065,7 +3886,7 @@ int set_lwp_class_and_priority(int ThreadID, int lwpid,
|
||||
|
||||
memset(&ParmInfo, 0, sizeof(pcparms_t));
|
||||
ParmInfo.pc_cid = PC_CLNULL;
|
||||
rslt = (*priocntl_ptr)(PC_VERSION, P_LWPID, lwpid, PC_GETPARMS, (caddr_t)&ParmInfo);
|
||||
rslt = priocntl(P_LWPID, lwpid, PC_GETPARMS, (caddr_t)&ParmInfo);
|
||||
if (rslt < 0) return errno;
|
||||
|
||||
int cur_class = ParmInfo.pc_cid;
|
||||
@ -4133,7 +3954,7 @@ int set_lwp_class_and_priority(int ThreadID, int lwpid,
|
||||
return EINVAL; // no clue, punt
|
||||
}
|
||||
|
||||
rslt = (*priocntl_ptr)(PC_VERSION, P_LWPID, lwpid, PC_SETPARMS, (caddr_t)&ParmInfo);
|
||||
rslt = priocntl(P_LWPID, lwpid, PC_SETPARMS, (caddr_t)&ParmInfo);
|
||||
if (ThreadPriorityVerbose && rslt) {
|
||||
tty->print_cr ("PC_SETPARMS ->%d %d\n", rslt, errno);
|
||||
}
|
||||
@ -4152,7 +3973,7 @@ int set_lwp_class_and_priority(int ThreadID, int lwpid,
|
||||
|
||||
memset(&ReadBack, 0, sizeof(pcparms_t));
|
||||
ReadBack.pc_cid = PC_CLNULL;
|
||||
rslt = (*priocntl_ptr)(PC_VERSION, P_LWPID, lwpid, PC_GETPARMS, (caddr_t)&ReadBack);
|
||||
rslt = priocntl(P_LWPID, lwpid, PC_GETPARMS, (caddr_t)&ReadBack);
|
||||
assert(rslt >= 0, "priocntl failed");
|
||||
Actual = Expected = 0xBAD;
|
||||
assert(ParmInfo.pc_cid == ReadBack.pc_cid, "cid's don't match");
|
||||
@ -5244,11 +5065,6 @@ uint_t os::Solaris::getisax(uint32_t* array, uint_t n) {
|
||||
return _getisax(array, n);
|
||||
}
|
||||
|
||||
// Symbol doesn't exist in Solaris 8 pset.h
|
||||
#ifndef PS_MYID
|
||||
#define PS_MYID -3
|
||||
#endif
|
||||
|
||||
// int pset_getloadavg(psetid_t pset, double loadavg[], int nelem);
|
||||
typedef long (*pset_getloadavg_type)(psetid_t pset, double loadavg[], int nelem);
|
||||
static pset_getloadavg_type pset_getloadavg_ptr = NULL;
|
||||
@ -5418,20 +5234,6 @@ jint os::init_2(void) {
|
||||
UseNUMA = false;
|
||||
}
|
||||
}
|
||||
// ISM is not compatible with the NUMA allocator - it always allocates
|
||||
// pages round-robin across the lgroups.
|
||||
if (UseNUMA && UseLargePages && UseISM) {
|
||||
if (!FLAG_IS_DEFAULT(UseNUMA)) {
|
||||
if (FLAG_IS_DEFAULT(UseLargePages) && FLAG_IS_DEFAULT(UseISM)) {
|
||||
UseLargePages = false;
|
||||
} else {
|
||||
warning("UseNUMA is not compatible with ISM large pages, disabling NUMA allocator");
|
||||
UseNUMA = false;
|
||||
}
|
||||
} else {
|
||||
UseNUMA = false;
|
||||
}
|
||||
}
|
||||
if (!UseNUMA && ForceNUMA) {
|
||||
UseNUMA = true;
|
||||
}
|
||||
@ -6077,24 +5879,20 @@ int os::loadavg(double loadavg[], int nelem) {
|
||||
bool os::find(address addr, outputStream* st) {
|
||||
Dl_info dlinfo;
|
||||
memset(&dlinfo, 0, sizeof(dlinfo));
|
||||
if (dladdr(addr, &dlinfo)) {
|
||||
#ifdef _LP64
|
||||
st->print("0x%016lx: ", addr);
|
||||
#else
|
||||
st->print("0x%08x: ", addr);
|
||||
#endif
|
||||
if (dlinfo.dli_sname != NULL)
|
||||
if (dladdr(addr, &dlinfo) != 0) {
|
||||
st->print(PTR_FORMAT ": ", addr);
|
||||
if (dlinfo.dli_sname != NULL && dlinfo.dli_saddr != NULL) {
|
||||
st->print("%s+%#lx", dlinfo.dli_sname, addr-(intptr_t)dlinfo.dli_saddr);
|
||||
else if (dlinfo.dli_fname)
|
||||
} else if (dlinfo.dli_fbase != NULL)
|
||||
st->print("<offset %#lx>", addr-(intptr_t)dlinfo.dli_fbase);
|
||||
else
|
||||
st->print("<absolute address>");
|
||||
if (dlinfo.dli_fname) st->print(" in %s", dlinfo.dli_fname);
|
||||
#ifdef _LP64
|
||||
if (dlinfo.dli_fbase) st->print(" at 0x%016lx", dlinfo.dli_fbase);
|
||||
#else
|
||||
if (dlinfo.dli_fbase) st->print(" at 0x%08x", dlinfo.dli_fbase);
|
||||
#endif
|
||||
if (dlinfo.dli_fname != NULL) {
|
||||
st->print(" in %s", dlinfo.dli_fname);
|
||||
}
|
||||
if (dlinfo.dli_fbase != NULL) {
|
||||
st->print(" at " PTR_FORMAT, dlinfo.dli_fbase);
|
||||
}
|
||||
st->cr();
|
||||
|
||||
if (Verbose) {
|
||||
@ -6105,7 +5903,7 @@ bool os::find(address addr, outputStream* st) {
|
||||
if (!lowest) lowest = (address) dlinfo.dli_fbase;
|
||||
if (begin < lowest) begin = lowest;
|
||||
Dl_info dlinfo2;
|
||||
if (dladdr(end, &dlinfo2) && dlinfo2.dli_saddr != dlinfo.dli_saddr
|
||||
if (dladdr(end, &dlinfo2) != 0 && dlinfo2.dli_saddr != dlinfo.dli_saddr
|
||||
&& end > dlinfo2.dli_saddr && dlinfo2.dli_saddr > begin)
|
||||
end = (address) dlinfo2.dli_saddr;
|
||||
Disassembler::decode(begin, end, st);
|
||||
|
@ -106,8 +106,8 @@ class Solaris {
|
||||
|
||||
static meminfo_func_t _meminfo;
|
||||
|
||||
// Large Page Support--mpss.
|
||||
static bool set_mpss_range(caddr_t start, size_t bytes, size_t align);
|
||||
// Large Page Support
|
||||
static bool setup_large_pages(caddr_t start, size_t bytes, size_t align);
|
||||
|
||||
static void init_thread_fpu_state(void);
|
||||
|
||||
@ -174,7 +174,6 @@ class Solaris {
|
||||
static char* mmap_chunk(char *addr, size_t size, int flags, int prot);
|
||||
static char* anon_mmap(char* requested_addr, size_t bytes, size_t alignment_hint, bool fixed);
|
||||
static bool mpss_sanity_check(bool warn, size_t * page_size);
|
||||
static bool ism_sanity_check (bool warn, size_t * page_size);
|
||||
|
||||
// Workaround for 4352906. thr_stksegment sometimes returns
|
||||
// a bad value for the primordial thread's stack base when
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2005, 2013, 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
|
||||
@ -358,6 +358,10 @@ AttachOperation* AttachListener::dequeue() {
|
||||
return op;
|
||||
}
|
||||
|
||||
void AttachListener::vm_start() {
|
||||
// nothing to do
|
||||
}
|
||||
|
||||
int AttachListener::pd_init() {
|
||||
return Win32AttachListener::init();
|
||||
}
|
||||
|
@ -1420,34 +1420,40 @@ static int _locate_module_by_addr(int pid, char * mod_fname, address base_addr,
|
||||
|
||||
bool os::dll_address_to_library_name(address addr, char* buf,
|
||||
int buflen, int* offset) {
|
||||
// buf is not optional, but offset is optional
|
||||
assert(buf != NULL, "sanity check");
|
||||
|
||||
// NOTE: the reason we don't use SymGetModuleInfo() is it doesn't always
|
||||
// return the full path to the DLL file, sometimes it returns path
|
||||
// to the corresponding PDB file (debug info); sometimes it only
|
||||
// returns partial path, which makes life painful.
|
||||
|
||||
struct _modinfo mi;
|
||||
mi.addr = addr;
|
||||
mi.full_path = buf;
|
||||
mi.buflen = buflen;
|
||||
int pid = os::current_process_id();
|
||||
if (enumerate_modules(pid, _locate_module_by_addr, (void *)&mi)) {
|
||||
// buf already contains path name
|
||||
if (offset) *offset = addr - mi.base_addr;
|
||||
return true;
|
||||
} else {
|
||||
if (buf) buf[0] = '\0';
|
||||
if (offset) *offset = -1;
|
||||
return false;
|
||||
}
|
||||
struct _modinfo mi;
|
||||
mi.addr = addr;
|
||||
mi.full_path = buf;
|
||||
mi.buflen = buflen;
|
||||
int pid = os::current_process_id();
|
||||
if (enumerate_modules(pid, _locate_module_by_addr, (void *)&mi)) {
|
||||
// buf already contains path name
|
||||
if (offset) *offset = addr - mi.base_addr;
|
||||
return true;
|
||||
}
|
||||
|
||||
buf[0] = '\0';
|
||||
if (offset) *offset = -1;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool os::dll_address_to_function_name(address addr, char *buf,
|
||||
int buflen, int *offset) {
|
||||
// buf is not optional, but offset is optional
|
||||
assert(buf != NULL, "sanity check");
|
||||
|
||||
if (Decoder::decode(addr, buf, buflen, offset)) {
|
||||
return true;
|
||||
}
|
||||
if (offset != NULL) *offset = -1;
|
||||
if (buf != NULL) buf[0] = '\0';
|
||||
buf[0] = '\0';
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -2317,6 +2323,11 @@ LONG WINAPI topLevelExceptionFilter(struct _EXCEPTION_POINTERS* exceptionInfo) {
|
||||
#endif
|
||||
Thread* t = ThreadLocalStorage::get_thread_slow(); // slow & steady
|
||||
|
||||
// Handle SafeFetch32 and SafeFetchN exceptions.
|
||||
if (StubRoutines::is_safefetch_fault(pc)) {
|
||||
return Handle_Exception(exceptionInfo, StubRoutines::continuation_for_safefetch_fault(pc));
|
||||
}
|
||||
|
||||
#ifndef _WIN64
|
||||
// Execution protection violation - win32 running on AMD64 only
|
||||
// Handled first to avoid misdiagnosis as a "normal" access violation;
|
||||
@ -2689,6 +2700,19 @@ address os::win32::fast_jni_accessor_wrapper(BasicType type) {
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef PRODUCT
|
||||
void os::win32::call_test_func_with_wrapper(void (*funcPtr)(void)) {
|
||||
// Install a win32 structured exception handler around the test
|
||||
// function call so the VM can generate an error dump if needed.
|
||||
__try {
|
||||
(*funcPtr)();
|
||||
} __except(topLevelExceptionFilter(
|
||||
(_EXCEPTION_POINTERS*)_exception_info())) {
|
||||
// Nothing to do.
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Virtual Memory
|
||||
|
||||
int os::vm_page_size() { return os::win32::vm_page_size(); }
|
||||
@ -4665,6 +4689,34 @@ void os::pause() {
|
||||
}
|
||||
}
|
||||
|
||||
os::WatcherThreadCrashProtection::WatcherThreadCrashProtection() {
|
||||
assert(Thread::current()->is_Watcher_thread(), "Must be WatcherThread");
|
||||
}
|
||||
|
||||
/*
|
||||
* See the caveats for this class in os_windows.hpp
|
||||
* Protects the callback call so that raised OS EXCEPTIONS causes a jump back
|
||||
* into this method and returns false. If no OS EXCEPTION was raised, returns
|
||||
* true.
|
||||
* The callback is supposed to provide the method that should be protected.
|
||||
*/
|
||||
bool os::WatcherThreadCrashProtection::call(os::CrashProtectionCallback& cb) {
|
||||
assert(Thread::current()->is_Watcher_thread(), "Only for WatcherThread");
|
||||
assert(!WatcherThread::watcher_thread()->has_crash_protection(),
|
||||
"crash_protection already set?");
|
||||
|
||||
bool success = true;
|
||||
__try {
|
||||
WatcherThread::watcher_thread()->set_crash_protection(this);
|
||||
cb.call();
|
||||
} __except(EXCEPTION_EXECUTE_HANDLER) {
|
||||
// only for protection, nothing to do
|
||||
success = false;
|
||||
}
|
||||
WatcherThread::watcher_thread()->set_crash_protection(NULL);
|
||||
return success;
|
||||
}
|
||||
|
||||
// An Event wraps a win32 "CreateEvent" kernel handle.
|
||||
//
|
||||
// We have a number of choices regarding "CreateEvent" win32 handle leakage:
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -94,10 +94,28 @@ class win32 {
|
||||
static address fast_jni_accessor_wrapper(BasicType);
|
||||
#endif
|
||||
|
||||
#ifndef PRODUCT
|
||||
static void call_test_func_with_wrapper(void (*funcPtr)(void));
|
||||
#endif
|
||||
|
||||
// filter function to ignore faults on serializations page
|
||||
static LONG WINAPI serialize_fault_filter(struct _EXCEPTION_POINTERS* e);
|
||||
};
|
||||
|
||||
/*
|
||||
* Crash protection for the watcher thread. Wrap the callback
|
||||
* with a __try { call() }
|
||||
* To be able to use this - don't take locks, don't rely on destructors,
|
||||
* don't make OS library calls, don't allocate memory, don't print,
|
||||
* don't call code that could leave the heap / memory in an inconsistent state,
|
||||
* or anything else where we are not in control if we suddenly jump out.
|
||||
*/
|
||||
class WatcherThreadCrashProtection : public StackObj {
|
||||
public:
|
||||
WatcherThreadCrashProtection();
|
||||
bool call(os::CrashProtectionCallback& cb);
|
||||
};
|
||||
|
||||
class PlatformEvent : public CHeapObj<mtInternal> {
|
||||
private:
|
||||
double CachePad [4] ; // increase odds that _Event is sole occupant of cache line
|
||||
|
@ -106,4 +106,10 @@ inline size_t os::write(int fd, const void *buf, unsigned int nBytes) {
|
||||
inline int os::close(int fd) {
|
||||
return ::close(fd);
|
||||
}
|
||||
|
||||
#ifndef PRODUCT
|
||||
#define CALL_TEST_FUNC_WITH_WRAPPER_IF_NEEDED(f) \
|
||||
os::win32::call_test_func_with_wrapper(f)
|
||||
#endif
|
||||
|
||||
#endif // OS_WINDOWS_VM_OS_WINDOWS_INLINE_HPP
|
||||
|
@ -63,24 +63,6 @@ SYMBOL(fixcw):
|
||||
popl %eax
|
||||
ret
|
||||
|
||||
.globl SYMBOL(SafeFetch32), SYMBOL(Fetch32PFI), SYMBOL(Fetch32Resume)
|
||||
.globl SYMBOL(SafeFetchN)
|
||||
## TODO: avoid exposing Fetch32PFI and Fetch32Resume.
|
||||
## Instead, the signal handler would call a new SafeFetchTriage(FaultingEIP)
|
||||
## routine to vet the address. If the address is the faulting LD then
|
||||
## SafeFetchTriage() would return the resume-at EIP, otherwise null.
|
||||
ELF_TYPE(SafeFetch32,@function)
|
||||
.p2align 4,,15
|
||||
SYMBOL(SafeFetch32):
|
||||
SYMBOL(SafeFetchN):
|
||||
movl 0x8(%esp), %eax
|
||||
movl 0x4(%esp), %ecx
|
||||
SYMBOL(Fetch32PFI):
|
||||
movl (%ecx), %eax
|
||||
SYMBOL(Fetch32Resume):
|
||||
ret
|
||||
|
||||
|
||||
.globl SYMBOL(SpinPause)
|
||||
ELF_TYPE(SpinPause,@function)
|
||||
.p2align 4,,15
|
||||
|
@ -46,28 +46,6 @@
|
||||
|
||||
.text
|
||||
|
||||
.globl SYMBOL(SafeFetch32), SYMBOL(Fetch32PFI), SYMBOL(Fetch32Resume)
|
||||
.p2align 4,,15
|
||||
ELF_TYPE(SafeFetch32,@function)
|
||||
// Prototype: int SafeFetch32 (int * Adr, int ErrValue)
|
||||
SYMBOL(SafeFetch32):
|
||||
movl %esi, %eax
|
||||
SYMBOL(Fetch32PFI):
|
||||
movl (%rdi), %eax
|
||||
SYMBOL(Fetch32Resume):
|
||||
ret
|
||||
|
||||
.globl SYMBOL(SafeFetchN), SYMBOL(FetchNPFI), SYMBOL(FetchNResume)
|
||||
.p2align 4,,15
|
||||
ELF_TYPE(SafeFetchN,@function)
|
||||
// Prototype: intptr_t SafeFetchN (intptr_t * Adr, intptr_t ErrValue)
|
||||
SYMBOL(SafeFetchN):
|
||||
movq %rsi, %rax
|
||||
SYMBOL(FetchNPFI):
|
||||
movq (%rdi), %rax
|
||||
SYMBOL(FetchNResume):
|
||||
ret
|
||||
|
||||
.globl SYMBOL(SpinPause)
|
||||
.p2align 4,,15
|
||||
ELF_TYPE(SpinPause,@function)
|
||||
|
@ -72,7 +72,7 @@ inline jushort OrderAccess::load_acquire(volatile jushort* p) { return *p; }
|
||||
inline juint OrderAccess::load_acquire(volatile juint* p) { return *p; }
|
||||
inline julong OrderAccess::load_acquire(volatile julong* p) { return Atomic::load((volatile jlong*)p); }
|
||||
inline jfloat OrderAccess::load_acquire(volatile jfloat* p) { return *p; }
|
||||
inline jdouble OrderAccess::load_acquire(volatile jdouble* p) { return *p; }
|
||||
inline jdouble OrderAccess::load_acquire(volatile jdouble* p) { return jdouble_cast(Atomic::load((volatile jlong*)p)); }
|
||||
|
||||
inline intptr_t OrderAccess::load_ptr_acquire(volatile intptr_t* p) { return *p; }
|
||||
inline void* OrderAccess::load_ptr_acquire(volatile void* p) { return *(void* volatile *)p; }
|
||||
@ -87,7 +87,7 @@ inline void OrderAccess::release_store(volatile jushort* p, jushort v) { *p
|
||||
inline void OrderAccess::release_store(volatile juint* p, juint v) { *p = v; }
|
||||
inline void OrderAccess::release_store(volatile julong* p, julong v) { Atomic::store((jlong)v, (volatile jlong*)p); }
|
||||
inline void OrderAccess::release_store(volatile jfloat* p, jfloat v) { *p = v; }
|
||||
inline void OrderAccess::release_store(volatile jdouble* p, jdouble v) { *p = v; }
|
||||
inline void OrderAccess::release_store(volatile jdouble* p, jdouble v) { release_store((volatile jlong*)p, jlong_cast(v)); }
|
||||
|
||||
inline void OrderAccess::release_store_ptr(volatile intptr_t* p, intptr_t v) { *p = v; }
|
||||
inline void OrderAccess::release_store_ptr(volatile void* p, void* v) { *(void* volatile *)p = v; }
|
||||
@ -190,7 +190,7 @@ inline void OrderAccess::release_store_fence(volatile juint* p, juint v)
|
||||
inline void OrderAccess::release_store_fence(volatile julong* p, julong v) { release_store_fence((volatile jlong*)p, (jlong)v); }
|
||||
|
||||
inline void OrderAccess::release_store_fence(volatile jfloat* p, jfloat v) { *p = v; fence(); }
|
||||
inline void OrderAccess::release_store_fence(volatile jdouble* p, jdouble v) { *p = v; fence(); }
|
||||
inline void OrderAccess::release_store_fence(volatile jdouble* p, jdouble v) { release_store_fence((volatile jlong*)p, jdouble_cast(v)); }
|
||||
|
||||
inline void OrderAccess::release_store_ptr_fence(volatile intptr_t* p, intptr_t v) {
|
||||
#ifdef AMD64
|
||||
|
@ -385,13 +385,6 @@ enum {
|
||||
trap_page_fault = 0xE
|
||||
};
|
||||
|
||||
extern "C" void Fetch32PFI () ;
|
||||
extern "C" void Fetch32Resume () ;
|
||||
#ifdef AMD64
|
||||
extern "C" void FetchNPFI () ;
|
||||
extern "C" void FetchNResume () ;
|
||||
#endif // AMD64
|
||||
|
||||
extern "C" JNIEXPORT int
|
||||
JVM_handle_bsd_signal(int sig,
|
||||
siginfo_t* info,
|
||||
@ -401,6 +394,10 @@ JVM_handle_bsd_signal(int sig,
|
||||
|
||||
Thread* t = ThreadLocalStorage::get_thread_slow();
|
||||
|
||||
// Must do this before SignalHandlerMark, if crash protection installed we will longjmp away
|
||||
// (no destructors can be run)
|
||||
os::WatcherThreadCrashProtection::check_crash_protection(sig, t);
|
||||
|
||||
SignalHandlerMark shm(t);
|
||||
|
||||
// Note: it's not uncommon that JNI code uses signal/sigset to install
|
||||
@ -454,16 +451,10 @@ JVM_handle_bsd_signal(int sig,
|
||||
if (info != NULL && uc != NULL && thread != NULL) {
|
||||
pc = (address) os::Bsd::ucontext_get_pc(uc);
|
||||
|
||||
if (pc == (address) Fetch32PFI) {
|
||||
uc->context_pc = intptr_t(Fetch32Resume) ;
|
||||
return 1 ;
|
||||
if (StubRoutines::is_safefetch_fault(pc)) {
|
||||
uc->context_pc = intptr_t(StubRoutines::continuation_for_safefetch_fault(pc));
|
||||
return 1;
|
||||
}
|
||||
#ifdef AMD64
|
||||
if (pc == (address) FetchNPFI) {
|
||||
uc->context_pc = intptr_t (FetchNResume) ;
|
||||
return 1 ;
|
||||
}
|
||||
#endif // AMD64
|
||||
|
||||
// Handle ALL stack overflow variations here
|
||||
if (sig == SIGSEGV || sig == SIGBUS) {
|
||||
|
@ -21,42 +21,6 @@
|
||||
# questions.
|
||||
#
|
||||
|
||||
# Prototype: int SafeFetch32 (int * adr, int ErrValue)
|
||||
# The "ld" at Fetch32 is potentially faulting instruction.
|
||||
# If the instruction traps the trap handler will arrange
|
||||
# for control to resume at Fetch32Resume.
|
||||
# By convention with the trap handler we ensure there is a non-CTI
|
||||
# instruction in the trap shadow.
|
||||
|
||||
|
||||
.globl SafeFetch32, Fetch32PFI, Fetch32Resume
|
||||
.globl SafeFetchN
|
||||
.align 32
|
||||
.type SafeFetch32,@function
|
||||
SafeFetch32:
|
||||
mov %o0, %g1
|
||||
mov %o1, %o0
|
||||
Fetch32PFI:
|
||||
# <-- Potentially faulting instruction
|
||||
ld [%g1], %o0
|
||||
Fetch32Resume:
|
||||
nop
|
||||
retl
|
||||
nop
|
||||
|
||||
.globl SafeFetchN, FetchNPFI, FetchNResume
|
||||
.type SafeFetchN,@function
|
||||
.align 32
|
||||
SafeFetchN:
|
||||
mov %o0, %g1
|
||||
mov %o1, %o0
|
||||
FetchNPFI:
|
||||
ldn [%g1], %o0
|
||||
FetchNResume:
|
||||
nop
|
||||
retl
|
||||
nop
|
||||
|
||||
# Possibilities:
|
||||
# -- membar
|
||||
# -- CAS (SP + BIAS, G0, G0)
|
||||
|
@ -366,18 +366,9 @@ intptr_t* os::Linux::ucontext_get_fp(ucontext_t *uc) {
|
||||
|
||||
// Utility functions
|
||||
|
||||
extern "C" void Fetch32PFI();
|
||||
extern "C" void Fetch32Resume();
|
||||
extern "C" void FetchNPFI();
|
||||
extern "C" void FetchNResume();
|
||||
|
||||
inline static bool checkPrefetch(sigcontext* uc, address pc) {
|
||||
if (pc == (address) Fetch32PFI) {
|
||||
set_cont_address(uc, address(Fetch32Resume));
|
||||
return true;
|
||||
}
|
||||
if (pc == (address) FetchNPFI) {
|
||||
set_cont_address(uc, address(FetchNResume));
|
||||
if (StubRoutines::is_safefetch_fault(pc)) {
|
||||
set_cont_address(uc, address(StubRoutines::continuation_for_safefetch_fault(pc)));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@ -553,6 +544,10 @@ JVM_handle_linux_signal(int sig,
|
||||
|
||||
Thread* t = ThreadLocalStorage::get_thread_slow();
|
||||
|
||||
// Must do this before SignalHandlerMark, if crash protection installed we will longjmp away
|
||||
// (no destructors can be run)
|
||||
os::WatcherThreadCrashProtection::check_crash_protection(sig, t);
|
||||
|
||||
SignalHandlerMark shm(t);
|
||||
|
||||
// Note: it's not uncommon that JNI code uses signal/sigset to install
|
||||
|
@ -42,24 +42,6 @@
|
||||
|
||||
.text
|
||||
|
||||
.globl SafeFetch32, Fetch32PFI, Fetch32Resume
|
||||
.globl SafeFetchN
|
||||
## TODO: avoid exposing Fetch32PFI and Fetch32Resume.
|
||||
## Instead, the signal handler would call a new SafeFetchTriage(FaultingEIP)
|
||||
## routine to vet the address. If the address is the faulting LD then
|
||||
## SafeFetchTriage() would return the resume-at EIP, otherwise null.
|
||||
.type SafeFetch32,@function
|
||||
.p2align 4,,15
|
||||
SafeFetch32:
|
||||
SafeFetchN:
|
||||
movl 0x8(%esp), %eax
|
||||
movl 0x4(%esp), %ecx
|
||||
Fetch32PFI:
|
||||
movl (%ecx), %eax
|
||||
Fetch32Resume:
|
||||
ret
|
||||
|
||||
|
||||
.globl SpinPause
|
||||
.type SpinPause,@function
|
||||
.p2align 4,,15
|
||||
|
@ -38,28 +38,6 @@
|
||||
|
||||
.text
|
||||
|
||||
.globl SafeFetch32, Fetch32PFI, Fetch32Resume
|
||||
.align 16
|
||||
.type SafeFetch32,@function
|
||||
// Prototype: int SafeFetch32 (int * Adr, int ErrValue)
|
||||
SafeFetch32:
|
||||
movl %esi, %eax
|
||||
Fetch32PFI:
|
||||
movl (%rdi), %eax
|
||||
Fetch32Resume:
|
||||
ret
|
||||
|
||||
.globl SafeFetchN, FetchNPFI, FetchNResume
|
||||
.align 16
|
||||
.type SafeFetchN,@function
|
||||
// Prototype: intptr_t SafeFetchN (intptr_t * Adr, intptr_t ErrValue)
|
||||
SafeFetchN:
|
||||
movq %rsi, %rax
|
||||
FetchNPFI:
|
||||
movq (%rdi), %rax
|
||||
FetchNResume:
|
||||
ret
|
||||
|
||||
.globl SpinPause
|
||||
.align 16
|
||||
.type SpinPause,@function
|
||||
|
@ -72,7 +72,7 @@ inline jushort OrderAccess::load_acquire(volatile jushort* p) { return *p; }
|
||||
inline juint OrderAccess::load_acquire(volatile juint* p) { return *p; }
|
||||
inline julong OrderAccess::load_acquire(volatile julong* p) { return Atomic::load((volatile jlong*)p); }
|
||||
inline jfloat OrderAccess::load_acquire(volatile jfloat* p) { return *p; }
|
||||
inline jdouble OrderAccess::load_acquire(volatile jdouble* p) { return *p; }
|
||||
inline jdouble OrderAccess::load_acquire(volatile jdouble* p) { return jdouble_cast(Atomic::load((volatile jlong*)p)); }
|
||||
|
||||
inline intptr_t OrderAccess::load_ptr_acquire(volatile intptr_t* p) { return *p; }
|
||||
inline void* OrderAccess::load_ptr_acquire(volatile void* p) { return *(void* volatile *)p; }
|
||||
@ -87,7 +87,7 @@ inline void OrderAccess::release_store(volatile jushort* p, jushort v) { *p
|
||||
inline void OrderAccess::release_store(volatile juint* p, juint v) { *p = v; }
|
||||
inline void OrderAccess::release_store(volatile julong* p, julong v) { Atomic::store((jlong)v, (volatile jlong*)p); }
|
||||
inline void OrderAccess::release_store(volatile jfloat* p, jfloat v) { *p = v; }
|
||||
inline void OrderAccess::release_store(volatile jdouble* p, jdouble v) { *p = v; }
|
||||
inline void OrderAccess::release_store(volatile jdouble* p, jdouble v) { release_store((volatile jlong *)p, jlong_cast(v)); }
|
||||
|
||||
inline void OrderAccess::release_store_ptr(volatile intptr_t* p, intptr_t v) { *p = v; }
|
||||
inline void OrderAccess::release_store_ptr(volatile void* p, void* v) { *(void* volatile *)p = v; }
|
||||
@ -129,7 +129,7 @@ inline void OrderAccess::store_fence(jushort* p, jushort v) { store_fence((j
|
||||
inline void OrderAccess::store_fence(juint* p, juint v) { store_fence((jint*)p, (jint)v); }
|
||||
inline void OrderAccess::store_fence(julong* p, julong v) { store_fence((jlong*)p, (jlong)v); }
|
||||
inline void OrderAccess::store_fence(jfloat* p, jfloat v) { *p = v; fence(); }
|
||||
inline void OrderAccess::store_fence(jdouble* p, jdouble v) { *p = v; fence(); }
|
||||
inline void OrderAccess::store_fence(jdouble* p, jdouble v) { store_fence((jlong*)p, jlong_cast(v)); }
|
||||
|
||||
inline void OrderAccess::store_ptr_fence(intptr_t* p, intptr_t v) {
|
||||
#ifdef AMD64
|
||||
@ -190,7 +190,7 @@ inline void OrderAccess::release_store_fence(volatile juint* p, juint v)
|
||||
inline void OrderAccess::release_store_fence(volatile julong* p, julong v) { release_store_fence((volatile jlong*)p, (jlong)v); }
|
||||
|
||||
inline void OrderAccess::release_store_fence(volatile jfloat* p, jfloat v) { *p = v; fence(); }
|
||||
inline void OrderAccess::release_store_fence(volatile jdouble* p, jdouble v) { *p = v; fence(); }
|
||||
inline void OrderAccess::release_store_fence(volatile jdouble* p, jdouble v) { release_store_fence((volatile jlong*)p, jlong_cast(v)); }
|
||||
|
||||
inline void OrderAccess::release_store_ptr_fence(volatile intptr_t* p, intptr_t v) {
|
||||
#ifdef AMD64
|
||||
|
@ -209,13 +209,6 @@ enum {
|
||||
trap_page_fault = 0xE
|
||||
};
|
||||
|
||||
extern "C" void Fetch32PFI () ;
|
||||
extern "C" void Fetch32Resume () ;
|
||||
#ifdef AMD64
|
||||
extern "C" void FetchNPFI () ;
|
||||
extern "C" void FetchNResume () ;
|
||||
#endif // AMD64
|
||||
|
||||
extern "C" JNIEXPORT int
|
||||
JVM_handle_linux_signal(int sig,
|
||||
siginfo_t* info,
|
||||
@ -225,6 +218,10 @@ JVM_handle_linux_signal(int sig,
|
||||
|
||||
Thread* t = ThreadLocalStorage::get_thread_slow();
|
||||
|
||||
// Must do this before SignalHandlerMark, if crash protection installed we will longjmp away
|
||||
// (no destructors can be run)
|
||||
os::WatcherThreadCrashProtection::check_crash_protection(sig, t);
|
||||
|
||||
SignalHandlerMark shm(t);
|
||||
|
||||
// Note: it's not uncommon that JNI code uses signal/sigset to install
|
||||
@ -278,16 +275,10 @@ JVM_handle_linux_signal(int sig,
|
||||
if (info != NULL && uc != NULL && thread != NULL) {
|
||||
pc = (address) os::Linux::ucontext_get_pc(uc);
|
||||
|
||||
if (pc == (address) Fetch32PFI) {
|
||||
uc->uc_mcontext.gregs[REG_PC] = intptr_t(Fetch32Resume) ;
|
||||
return 1 ;
|
||||
if (StubRoutines::is_safefetch_fault(pc)) {
|
||||
uc->uc_mcontext.gregs[REG_PC] = intptr_t(StubRoutines::continuation_for_safefetch_fault(pc));
|
||||
return 1;
|
||||
}
|
||||
#ifdef AMD64
|
||||
if (pc == (address) FetchNPFI) {
|
||||
uc->uc_mcontext.gregs[REG_PC] = intptr_t (FetchNResume) ;
|
||||
return 1 ;
|
||||
}
|
||||
#endif // AMD64
|
||||
|
||||
#ifndef AMD64
|
||||
// Halt if SI_KERNEL before more crashes get misdiagnosed as Java bugs
|
||||
|
@ -303,11 +303,6 @@ bool os::is_allocatable(size_t bytes) {
|
||||
#endif
|
||||
}
|
||||
|
||||
extern "C" void Fetch32PFI () ;
|
||||
extern "C" void Fetch32Resume () ;
|
||||
extern "C" void FetchNPFI () ;
|
||||
extern "C" void FetchNResume () ;
|
||||
|
||||
extern "C" JNIEXPORT int
|
||||
JVM_handle_solaris_signal(int sig, siginfo_t* info, void* ucVoid,
|
||||
int abort_if_unrecognized) {
|
||||
@ -315,6 +310,10 @@ JVM_handle_solaris_signal(int sig, siginfo_t* info, void* ucVoid,
|
||||
|
||||
Thread* t = ThreadLocalStorage::get_thread_slow();
|
||||
|
||||
// Must do this before SignalHandlerMark, if crash protection installed we will longjmp away
|
||||
// (no destructors can be run)
|
||||
os::WatcherThreadCrashProtection::check_crash_protection(sig, t);
|
||||
|
||||
SignalHandlerMark shm(t);
|
||||
|
||||
if(sig == SIGPIPE || sig == SIGXFSZ) {
|
||||
@ -379,17 +378,10 @@ JVM_handle_solaris_signal(int sig, siginfo_t* info, void* ucVoid,
|
||||
npc = (address) uc->uc_mcontext.gregs[REG_nPC];
|
||||
|
||||
// SafeFetch() support
|
||||
// Implemented with either a fixed set of addresses such
|
||||
// as Fetch32*, or with Thread._OnTrap.
|
||||
if (uc->uc_mcontext.gregs[REG_PC] == intptr_t(Fetch32PFI)) {
|
||||
uc->uc_mcontext.gregs [REG_PC] = intptr_t(Fetch32Resume) ;
|
||||
uc->uc_mcontext.gregs [REG_nPC] = intptr_t(Fetch32Resume) + 4 ;
|
||||
return true ;
|
||||
}
|
||||
if (uc->uc_mcontext.gregs[REG_PC] == intptr_t(FetchNPFI)) {
|
||||
uc->uc_mcontext.gregs [REG_PC] = intptr_t(FetchNResume) ;
|
||||
uc->uc_mcontext.gregs [REG_nPC] = intptr_t(FetchNResume) + 4 ;
|
||||
return true ;
|
||||
if (StubRoutines::is_safefetch_fault(pc)) {
|
||||
uc->uc_mcontext.gregs[REG_PC] = intptr_t(StubRoutines::continuation_for_safefetch_fault(pc));
|
||||
uc->uc_mcontext.gregs[REG_nPC] = uc->uc_mcontext.gregs[REG_PC] + 4;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Handle ALL stack overflow variations here
|
||||
|
@ -21,47 +21,6 @@
|
||||
!! questions.
|
||||
!!
|
||||
|
||||
!! Prototype: int SafeFetch32 (int * adr, int ErrValue)
|
||||
!! The "ld" at Fetch32 is potentially faulting instruction.
|
||||
!! If the instruction traps the trap handler will arrange
|
||||
!! for control to resume at Fetch32Resume.
|
||||
!! By convention with the trap handler we ensure there is a non-CTI
|
||||
!! instruction in the trap shadow.
|
||||
!!
|
||||
!! The reader might be tempted to move this service to .il.
|
||||
!! Don't. Sun's CC back-end reads and optimize code emitted
|
||||
!! by the .il "call", in some cases optimizing the code, completely eliding it,
|
||||
!! or by moving the code from the "call site".
|
||||
|
||||
!! ASM better know we may use G6 for our own purposes
|
||||
.register %g6, #ignore
|
||||
|
||||
.globl SafeFetch32
|
||||
.align 32
|
||||
.global Fetch32PFI, Fetch32Resume
|
||||
SafeFetch32:
|
||||
mov %o0, %g1
|
||||
mov %o1, %o0
|
||||
Fetch32PFI:
|
||||
ld [%g1], %o0 !! <-- Potentially faulting instruction
|
||||
Fetch32Resume:
|
||||
nop
|
||||
retl
|
||||
nop
|
||||
|
||||
.globl SafeFetchN
|
||||
.align 32
|
||||
.globl FetchNPFI, FetchNResume
|
||||
SafeFetchN:
|
||||
mov %o0, %g1
|
||||
mov %o1, %o0
|
||||
FetchNPFI:
|
||||
ldn [%g1], %o0
|
||||
FetchNResume:
|
||||
nop
|
||||
retl
|
||||
nop
|
||||
|
||||
!! Possibilities:
|
||||
!! -- membar
|
||||
!! -- CAS (SP + BIAS, G0, G0)
|
||||
|
@ -88,7 +88,7 @@ inline jushort OrderAccess::load_acquire(volatile jushort* p) { return *p; }
|
||||
inline juint OrderAccess::load_acquire(volatile juint* p) { return *p; }
|
||||
inline julong OrderAccess::load_acquire(volatile julong* p) { return Atomic::load((volatile jlong*)p); }
|
||||
inline jfloat OrderAccess::load_acquire(volatile jfloat* p) { return *p; }
|
||||
inline jdouble OrderAccess::load_acquire(volatile jdouble* p) { return *p; }
|
||||
inline jdouble OrderAccess::load_acquire(volatile jdouble* p) { return jdouble_cast(Atomic::load((volatile jlong*)p)); }
|
||||
|
||||
inline intptr_t OrderAccess::load_ptr_acquire(volatile intptr_t* p) { return *p; }
|
||||
inline void* OrderAccess::load_ptr_acquire(volatile void* p) { return *(void* volatile *)p; }
|
||||
@ -103,7 +103,7 @@ inline void OrderAccess::release_store(volatile jushort* p, jushort v) { *p
|
||||
inline void OrderAccess::release_store(volatile juint* p, juint v) { *p = v; }
|
||||
inline void OrderAccess::release_store(volatile julong* p, julong v) { Atomic::store((jlong)v, (volatile jlong*)p); }
|
||||
inline void OrderAccess::release_store(volatile jfloat* p, jfloat v) { *p = v; }
|
||||
inline void OrderAccess::release_store(volatile jdouble* p, jdouble v) { *p = v; }
|
||||
inline void OrderAccess::release_store(volatile jdouble* p, jdouble v) { release_store((volatile jlong*)p, jlong_cast(v)); }
|
||||
|
||||
inline void OrderAccess::release_store_ptr(volatile intptr_t* p, intptr_t v) { *p = v; }
|
||||
inline void OrderAccess::release_store_ptr(volatile void* p, void* v) { *(void* volatile *)p = v; }
|
||||
@ -129,9 +129,9 @@ inline void OrderAccess::release_store_fence(volatile jlong* p, jlong v)
|
||||
inline void OrderAccess::release_store_fence(volatile jubyte* p, jubyte v) { *p = v; fence(); }
|
||||
inline void OrderAccess::release_store_fence(volatile jushort* p, jushort v) { *p = v; fence(); }
|
||||
inline void OrderAccess::release_store_fence(volatile juint* p, juint v) { *p = v; fence(); }
|
||||
inline void OrderAccess::release_store_fence(volatile julong* p, julong v) { release_store(p, v); fence(); }
|
||||
inline void OrderAccess::release_store_fence(volatile julong* p, julong v) { release_store((jlong *)p, (jlong)v); fence(); }
|
||||
inline void OrderAccess::release_store_fence(volatile jfloat* p, jfloat v) { *p = v; fence(); }
|
||||
inline void OrderAccess::release_store_fence(volatile jdouble* p, jdouble v) { *p = v; fence(); }
|
||||
inline void OrderAccess::release_store_fence(volatile jdouble* p, jdouble v) { release_store_fence((volatile jlong*)p, jlong_cast(v)); }
|
||||
|
||||
inline void OrderAccess::release_store_ptr_fence(volatile intptr_t* p, intptr_t v) { *p = v; fence(); }
|
||||
inline void OrderAccess::release_store_ptr_fence(volatile void* p, void* v) { *(void* volatile *)p = v; fence(); }
|
||||
|
@ -352,13 +352,6 @@ bool os::is_allocatable(size_t bytes) {
|
||||
|
||||
}
|
||||
|
||||
extern "C" void Fetch32PFI () ;
|
||||
extern "C" void Fetch32Resume () ;
|
||||
#ifdef AMD64
|
||||
extern "C" void FetchNPFI () ;
|
||||
extern "C" void FetchNResume () ;
|
||||
#endif // AMD64
|
||||
|
||||
extern "C" JNIEXPORT int
|
||||
JVM_handle_solaris_signal(int sig, siginfo_t* info, void* ucVoid,
|
||||
int abort_if_unrecognized) {
|
||||
@ -374,6 +367,10 @@ JVM_handle_solaris_signal(int sig, siginfo_t* info, void* ucVoid,
|
||||
|
||||
Thread* t = ThreadLocalStorage::get_thread_slow(); // slow & steady
|
||||
|
||||
// Must do this before SignalHandlerMark, if crash protection installed we will longjmp away
|
||||
// (no destructors can be run)
|
||||
os::WatcherThreadCrashProtection::check_crash_protection(sig, t);
|
||||
|
||||
SignalHandlerMark shm(t);
|
||||
|
||||
if(sig == SIGPIPE || sig == SIGXFSZ) {
|
||||
@ -436,17 +433,10 @@ JVM_handle_solaris_signal(int sig, siginfo_t* info, void* ucVoid,
|
||||
// factor me: getPCfromContext
|
||||
pc = (address) uc->uc_mcontext.gregs[REG_PC];
|
||||
|
||||
// SafeFetch32() support
|
||||
if (pc == (address) Fetch32PFI) {
|
||||
uc->uc_mcontext.gregs[REG_PC] = intptr_t(Fetch32Resume) ;
|
||||
return true ;
|
||||
if (StubRoutines::is_safefetch_fault(pc)) {
|
||||
uc->uc_mcontext.gregs[REG_PC] = intptr_t(StubRoutines::continuation_for_safefetch_fault(pc));
|
||||
return true;
|
||||
}
|
||||
#ifdef AMD64
|
||||
if (pc == (address) FetchNPFI) {
|
||||
uc->uc_mcontext.gregs [REG_PC] = intptr_t(FetchNResume) ;
|
||||
return true ;
|
||||
}
|
||||
#endif // AMD64
|
||||
|
||||
// Handle ALL stack overflow variations here
|
||||
if (sig == SIGSEGV && info->si_code == SEGV_ACCERR) {
|
||||
|
@ -54,20 +54,6 @@ fixcw:
|
||||
popl %eax
|
||||
ret
|
||||
|
||||
.align 16
|
||||
.globl SafeFetch32
|
||||
.globl SafeFetchN
|
||||
.globl Fetch32PFI, Fetch32Resume
|
||||
SafeFetch32:
|
||||
SafeFetchN:
|
||||
movl 0x8(%esp), %eax
|
||||
movl 0x4(%esp), %ecx
|
||||
Fetch32PFI:
|
||||
movl (%ecx), %eax
|
||||
Fetch32Resume:
|
||||
ret
|
||||
|
||||
|
||||
.align 16
|
||||
.globl SpinPause
|
||||
SpinPause:
|
||||
|
@ -21,54 +21,34 @@
|
||||
/ questions.
|
||||
/
|
||||
|
||||
.globl fs_load
|
||||
.globl fs_thread
|
||||
.globl fs_load
|
||||
.globl fs_thread
|
||||
|
||||
// NOTE WELL! The _Copy functions are called directly
|
||||
// from server-compiler-generated code via CallLeafNoFP,
|
||||
// which means that they *must* either not use floating
|
||||
// point or use it in the same manner as does the server
|
||||
// compiler.
|
||||
// from server-compiler-generated code via CallLeafNoFP,
|
||||
// which means that they *must* either not use floating
|
||||
// point or use it in the same manner as does the server
|
||||
// compiler.
|
||||
|
||||
.globl _Copy_arrayof_conjoint_bytes
|
||||
.globl _Copy_conjoint_jshorts_atomic
|
||||
.globl _Copy_arrayof_conjoint_jshorts
|
||||
.globl _Copy_arrayof_conjoint_jshorts
|
||||
.globl _Copy_conjoint_jints_atomic
|
||||
.globl _Copy_arrayof_conjoint_jints
|
||||
.globl _Copy_conjoint_jlongs_atomic
|
||||
.globl _Copy_conjoint_jlongs_atomic
|
||||
.globl _Copy_arrayof_conjoint_jlongs
|
||||
|
||||
.section .text,"ax"
|
||||
.section .text,"ax"
|
||||
|
||||
/ Fast thread accessors, used by threadLS_solaris_amd64.cpp
|
||||
.align 16
|
||||
.align 16
|
||||
fs_load:
|
||||
movq %fs:(%rdi),%rax
|
||||
ret
|
||||
|
||||
.align 16
|
||||
fs_thread:
|
||||
movq %fs:0x0,%rax
|
||||
ret
|
||||
|
||||
.globl SafeFetch32, Fetch32PFI, Fetch32Resume
|
||||
.align 16
|
||||
// Prototype: int SafeFetch32 (int * Adr, int ErrValue)
|
||||
SafeFetch32:
|
||||
movl %esi, %eax
|
||||
Fetch32PFI:
|
||||
movl (%rdi), %eax
|
||||
Fetch32Resume:
|
||||
movq %fs:(%rdi),%rax
|
||||
ret
|
||||
|
||||
.globl SafeFetchN, FetchNPFI, FetchNResume
|
||||
.align 16
|
||||
// Prototype: intptr_t SafeFetchN (intptr_t * Adr, intptr_t ErrValue)
|
||||
SafeFetchN:
|
||||
movq %rsi, %rax
|
||||
FetchNPFI:
|
||||
movq (%rdi), %rax
|
||||
FetchNResume:
|
||||
.align 16
|
||||
fs_thread:
|
||||
movq %fs:0x0,%rax
|
||||
ret
|
||||
|
||||
.globl SpinPause
|
||||
@ -78,7 +58,7 @@ SpinPause:
|
||||
nop
|
||||
movq $1, %rax
|
||||
ret
|
||||
|
||||
|
||||
|
||||
/ Support for void Copy::arrayof_conjoint_bytes(void* from,
|
||||
/ void* to,
|
||||
@ -340,7 +320,7 @@ aci_CopyLeft:
|
||||
addq $4,%rdx
|
||||
jg 1b
|
||||
ret
|
||||
|
||||
|
||||
/ Support for void Copy::arrayof_conjoint_jlongs(jlong* from,
|
||||
/ jlong* to,
|
||||
/ size_t count)
|
||||
|
@ -71,7 +71,7 @@ inline jushort OrderAccess::load_acquire(volatile jushort* p) { return *p; }
|
||||
inline juint OrderAccess::load_acquire(volatile juint* p) { return *p; }
|
||||
inline julong OrderAccess::load_acquire(volatile julong* p) { return Atomic::load((volatile jlong*)p); }
|
||||
inline jfloat OrderAccess::load_acquire(volatile jfloat* p) { return *p; }
|
||||
inline jdouble OrderAccess::load_acquire(volatile jdouble* p) { return *p; }
|
||||
inline jdouble OrderAccess::load_acquire(volatile jdouble* p) { return jdouble_cast(Atomic::load((volatile jlong*)p)); }
|
||||
|
||||
inline intptr_t OrderAccess::load_ptr_acquire(volatile intptr_t* p) { return *p; }
|
||||
inline void* OrderAccess::load_ptr_acquire(volatile void* p) { return *(void* volatile *)p; }
|
||||
@ -86,7 +86,7 @@ inline void OrderAccess::release_store(volatile jushort* p, jushort v) { *p
|
||||
inline void OrderAccess::release_store(volatile juint* p, juint v) { *p = v; }
|
||||
inline void OrderAccess::release_store(volatile julong* p, julong v) { Atomic::store((jlong)v, (volatile jlong*)p); }
|
||||
inline void OrderAccess::release_store(volatile jfloat* p, jfloat v) { *p = v; }
|
||||
inline void OrderAccess::release_store(volatile jdouble* p, jdouble v) { *p = v; }
|
||||
inline void OrderAccess::release_store(volatile jdouble* p, jdouble v) { release_store((volatile jlong*)p, jlong_cast(v)); }
|
||||
|
||||
inline void OrderAccess::release_store_ptr(volatile intptr_t* p, intptr_t v) { *p = v; }
|
||||
inline void OrderAccess::release_store_ptr(volatile void* p, void* v) { *(void* volatile *)p = v; }
|
||||
@ -195,7 +195,7 @@ inline void OrderAccess::release_store_fence(volatile jushort* p, jushort v)
|
||||
inline void OrderAccess::release_store_fence(volatile juint* p, juint v) { release_store_fence((volatile jint*)p, (jint)v); }
|
||||
inline void OrderAccess::release_store_fence(volatile julong* p, julong v) { release_store_fence((volatile jlong*)p, (jlong)v); }
|
||||
inline void OrderAccess::release_store_fence(volatile jfloat* p, jfloat v) { *p = v; fence(); }
|
||||
inline void OrderAccess::release_store_fence(volatile jdouble* p, jdouble v) { *p = v; fence(); }
|
||||
inline void OrderAccess::release_store_fence(volatile jdouble* p, jdouble v) { release_store_fence((volatile jlong*)p, jlong_cast(v)); }
|
||||
|
||||
inline void OrderAccess::release_store_ptr_fence(volatile intptr_t* p, intptr_t v) {
|
||||
#ifdef AMD64
|
||||
|
@ -518,24 +518,6 @@ void os::print_register_info(outputStream *st, void *context) {
|
||||
st->cr();
|
||||
}
|
||||
|
||||
extern "C" int SafeFetch32 (int * adr, int Err) {
|
||||
int rv = Err ;
|
||||
_try {
|
||||
rv = *((volatile int *) adr) ;
|
||||
} __except(EXCEPTION_EXECUTE_HANDLER) {
|
||||
}
|
||||
return rv ;
|
||||
}
|
||||
|
||||
extern "C" intptr_t SafeFetchN (intptr_t * adr, intptr_t Err) {
|
||||
intptr_t rv = Err ;
|
||||
_try {
|
||||
rv = *((volatile intptr_t *) adr) ;
|
||||
} __except(EXCEPTION_EXECUTE_HANDLER) {
|
||||
}
|
||||
return rv ;
|
||||
}
|
||||
|
||||
extern "C" int SpinPause () {
|
||||
#ifdef AMD64
|
||||
return 0 ;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2004, 2013, 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
|
||||
@ -29,10 +29,15 @@
|
||||
#ifdef AMD64
|
||||
typedef unsigned char UBYTE;
|
||||
|
||||
#if _MSC_VER < 1700
|
||||
|
||||
/* Not needed for VS2012 compiler, comes from winnt.h. */
|
||||
#define UNW_FLAG_EHANDLER 0x01
|
||||
#define UNW_FLAG_UHANDLER 0x02
|
||||
#define UNW_FLAG_CHAININFO 0x04
|
||||
|
||||
#endif
|
||||
|
||||
// This structure is used to define an UNWIND_INFO that
|
||||
// only has an ExceptionHandler. There are no UnwindCodes
|
||||
// declared.
|
||||
@ -59,6 +64,9 @@ typedef struct _RUNTIME_FUNCTION {
|
||||
} RUNTIME_FUNCTION, *PRUNTIME_FUNCTION;
|
||||
*/
|
||||
|
||||
#if _MSC_VER < 1700
|
||||
|
||||
/* Not needed for VS2012 compiler, comes from winnt.h. */
|
||||
typedef struct _DISPATCHER_CONTEXT {
|
||||
ULONG64 ControlPc;
|
||||
ULONG64 ImageBase;
|
||||
@ -71,6 +79,8 @@ typedef struct _DISPATCHER_CONTEXT {
|
||||
PVOID HandlerData;
|
||||
} DISPATCHER_CONTEXT, *PDISPATCHER_CONTEXT;
|
||||
|
||||
#endif
|
||||
|
||||
#if _MSC_VER < 1500
|
||||
|
||||
/* Not needed for VS2008 compiler, comes from winnt.h. */
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2013, 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
|
||||
@ -146,7 +146,7 @@ public:
|
||||
// Public Methods
|
||||
Form(int formType=0, int line=0)
|
||||
: _next(NULL), _linenum(line), _ftype(formType) { };
|
||||
~Form() {};
|
||||
virtual ~Form() {};
|
||||
|
||||
virtual bool ideal_only() const {
|
||||
assert(0,"Check of ideal status on non-instruction/operand form.\n");
|
||||
|
@ -138,6 +138,16 @@ bool BCEscapeAnalyzer::is_arg_stack(ArgumentMap vars){
|
||||
return false;
|
||||
}
|
||||
|
||||
// return true if all argument elements of vars are returned
|
||||
bool BCEscapeAnalyzer::returns_all(ArgumentMap vars) {
|
||||
for (int i = 0; i < _arg_size; i++) {
|
||||
if (vars.contains(i) && !_arg_returned.test(i)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void BCEscapeAnalyzer::clear_bits(ArgumentMap vars, VectorSet &bm) {
|
||||
for (int i = 0; i < _arg_size; i++) {
|
||||
if (vars.contains(i)) {
|
||||
@ -166,6 +176,11 @@ void BCEscapeAnalyzer::set_global_escape(ArgumentMap vars, bool merge) {
|
||||
if (vars.contains_unknown() || vars.contains_vars()) {
|
||||
_return_allocated = false;
|
||||
}
|
||||
if (_return_local && vars.contains_vars() && !returns_all(vars)) {
|
||||
// Return result should be invalidated if args in new
|
||||
// state are not recorded in return state.
|
||||
_return_local = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -80,6 +80,7 @@ class BCEscapeAnalyzer : public ResourceObj {
|
||||
void set_returned(ArgumentMap vars);
|
||||
bool is_argument(ArgumentMap vars);
|
||||
bool is_arg_stack(ArgumentMap vars);
|
||||
bool returns_all(ArgumentMap vars);
|
||||
void clear_bits(ArgumentMap vars, VectorSet &bs);
|
||||
void set_method_escape(ArgumentMap vars);
|
||||
void set_global_escape(ArgumentMap vars, bool merge = false);
|
||||
|
@ -3647,8 +3647,7 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name,
|
||||
// If RedefineClasses() was used before the retransformable
|
||||
// agent attached, then the cached class bytes may not be the
|
||||
// original class bytes.
|
||||
unsigned char *cached_class_file_bytes = NULL;
|
||||
jint cached_class_file_length;
|
||||
JvmtiCachedClassFileData *cached_class_file = NULL;
|
||||
Handle class_loader(THREAD, loader_data->class_loader());
|
||||
bool has_default_methods = false;
|
||||
ResourceMark rm(THREAD);
|
||||
@ -3680,10 +3679,7 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name,
|
||||
if (h_class_being_redefined != NULL) {
|
||||
instanceKlassHandle ikh_class_being_redefined =
|
||||
instanceKlassHandle(THREAD, (*h_class_being_redefined)());
|
||||
cached_class_file_bytes =
|
||||
ikh_class_being_redefined->get_cached_class_file_bytes();
|
||||
cached_class_file_length =
|
||||
ikh_class_being_redefined->get_cached_class_file_len();
|
||||
cached_class_file = ikh_class_being_redefined->get_cached_class_file();
|
||||
}
|
||||
}
|
||||
|
||||
@ -3691,9 +3687,7 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name,
|
||||
unsigned char* end_ptr = cfs->buffer() + cfs->length();
|
||||
|
||||
JvmtiExport::post_class_file_load_hook(name, class_loader(), protection_domain,
|
||||
&ptr, &end_ptr,
|
||||
&cached_class_file_bytes,
|
||||
&cached_class_file_length);
|
||||
&ptr, &end_ptr, &cached_class_file);
|
||||
|
||||
if (ptr != cfs->buffer()) {
|
||||
// JVMTI agent has modified class file data.
|
||||
@ -4011,10 +4005,9 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name,
|
||||
}
|
||||
}
|
||||
|
||||
if (cached_class_file_bytes != NULL) {
|
||||
if (cached_class_file != NULL) {
|
||||
// JVMTI: we have an InstanceKlass now, tell it about the cached bytes
|
||||
this_klass->set_cached_class_file(cached_class_file_bytes,
|
||||
cached_class_file_length);
|
||||
this_klass->set_cached_class_file(cached_class_file);
|
||||
}
|
||||
|
||||
// Fill in field values obtained by parse_classfile_attributes
|
||||
|
@ -318,17 +318,17 @@ class KeepAliveVisitor : public HierarchyVisitor<KeepAliveVisitor> {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// A method family contains a set of all methods that implement a single
|
||||
// language-level method. Because of erasure, these methods may have different
|
||||
// signatures. As members of the set are collected while walking over the
|
||||
// erased method. As members of the set are collected while walking over the
|
||||
// hierarchy, they are tagged with a qualification state. The qualification
|
||||
// state for an erased method is set to disqualified if there exists a path
|
||||
// from the root of hierarchy to the method that contains an interleaving
|
||||
// language-equivalent method defined in an interface.
|
||||
// erased method defined in an interface.
|
||||
|
||||
class MethodFamily : public ResourceObj {
|
||||
private:
|
||||
|
||||
generic::MethodDescriptor* _descriptor; // language-level description
|
||||
GrowableArray<Pair<Method*,QualifiedState> > _members;
|
||||
ResourceHashtable<Method*, int> _member_index;
|
||||
|
||||
@ -358,15 +358,8 @@ class MethodFamily : public ResourceObj {
|
||||
|
||||
public:
|
||||
|
||||
MethodFamily(generic::MethodDescriptor* canonical_desc)
|
||||
: _descriptor(canonical_desc), _selected_target(NULL),
|
||||
_exception_message(NULL) {}
|
||||
|
||||
generic::MethodDescriptor* descriptor() const { return _descriptor; }
|
||||
|
||||
bool descriptor_matches(generic::MethodDescriptor* md, generic::Context* ctx) {
|
||||
return descriptor()->covariant_match(md, ctx);
|
||||
}
|
||||
MethodFamily()
|
||||
: _selected_target(NULL), _exception_message(NULL) {}
|
||||
|
||||
void set_target_if_empty(Method* m) {
|
||||
if (_selected_target == NULL && !m->is_overpass()) {
|
||||
@ -441,16 +434,10 @@ class MethodFamily : public ResourceObj {
|
||||
}
|
||||
|
||||
#ifndef PRODUCT
|
||||
void print_on(outputStream* str) const {
|
||||
print_on(str, 0);
|
||||
}
|
||||
|
||||
void print_on(outputStream* str, int indent) const {
|
||||
void print_sig_on(outputStream* str, Symbol* signature, int indent) const {
|
||||
streamIndentor si(str, indent * 2);
|
||||
|
||||
generic::Context ctx(NULL); // empty, as _descriptor already canonicalized
|
||||
TempNewSymbol family = descriptor()->reify_signature(&ctx, Thread::current());
|
||||
str->indent().print_cr("Logical Method %s:", family->as_C_string());
|
||||
str->indent().print_cr("Logical Method %s:", signature->as_C_string());
|
||||
|
||||
streamIndentor si2(str);
|
||||
for (int i = 0; i < _members.length(); ++i) {
|
||||
@ -516,38 +503,94 @@ Symbol* MethodFamily::generate_conflicts_message(GrowableArray<Method*>* methods
|
||||
return SymbolTable::new_symbol(ss.base(), (int)ss.size(), CHECK_NULL);
|
||||
}
|
||||
|
||||
// A generic method family contains a set of all methods that implement a single
|
||||
// language-level method. Because of erasure, these methods may have different
|
||||
// signatures. As members of the set are collected while walking over the
|
||||
// hierarchy, they are tagged with a qualification state. The qualification
|
||||
// state for an erased method is set to disqualified if there exists a path
|
||||
// from the root of hierarchy to the method that contains an interleaving
|
||||
// language-equivalent method defined in an interface.
|
||||
class GenericMethodFamily : public MethodFamily {
|
||||
private:
|
||||
|
||||
generic::MethodDescriptor* _descriptor; // language-level description
|
||||
|
||||
public:
|
||||
|
||||
GenericMethodFamily(generic::MethodDescriptor* canonical_desc)
|
||||
: _descriptor(canonical_desc) {}
|
||||
|
||||
generic::MethodDescriptor* descriptor() const { return _descriptor; }
|
||||
|
||||
bool descriptor_matches(generic::MethodDescriptor* md, generic::Context* ctx) {
|
||||
return descriptor()->covariant_match(md, ctx);
|
||||
}
|
||||
|
||||
#ifndef PRODUCT
|
||||
Symbol* get_generic_sig() const {
|
||||
|
||||
generic::Context ctx(NULL); // empty, as _descriptor already canonicalized
|
||||
TempNewSymbol sig = descriptor()->reify_signature(&ctx, Thread::current());
|
||||
return sig;
|
||||
}
|
||||
#endif // ndef PRODUCT
|
||||
};
|
||||
|
||||
class StateRestorer;
|
||||
|
||||
// StatefulMethodFamily is a wrapper around MethodFamily that maintains the
|
||||
// StatefulMethodFamily is a wrapper around a MethodFamily that maintains the
|
||||
// qualification state during hierarchy visitation, and applies that state
|
||||
// when adding members to the MethodFamily.
|
||||
// when adding members to the MethodFamily
|
||||
class StatefulMethodFamily : public ResourceObj {
|
||||
friend class StateRestorer;
|
||||
private:
|
||||
MethodFamily* _method;
|
||||
QualifiedState _qualification_state;
|
||||
|
||||
void set_qualification_state(QualifiedState state) {
|
||||
_qualification_state = state;
|
||||
}
|
||||
|
||||
protected:
|
||||
MethodFamily* _method_family;
|
||||
|
||||
public:
|
||||
StatefulMethodFamily(generic::MethodDescriptor* md, generic::Context* ctx) {
|
||||
_method = new MethodFamily(md->canonicalize(ctx));
|
||||
_qualification_state = QUALIFIED;
|
||||
StatefulMethodFamily() {
|
||||
_method_family = new MethodFamily();
|
||||
_qualification_state = QUALIFIED;
|
||||
}
|
||||
|
||||
void set_target_if_empty(Method* m) { _method->set_target_if_empty(m); }
|
||||
|
||||
MethodFamily* get_method_family() { return _method; }
|
||||
|
||||
bool descriptor_matches(generic::MethodDescriptor* md, generic::Context* ctx) {
|
||||
return _method->descriptor_matches(md, ctx);
|
||||
StatefulMethodFamily(MethodFamily* mf) {
|
||||
_method_family = mf;
|
||||
_qualification_state = QUALIFIED;
|
||||
}
|
||||
|
||||
void set_target_if_empty(Method* m) { _method_family->set_target_if_empty(m); }
|
||||
|
||||
MethodFamily* get_method_family() { return _method_family; }
|
||||
|
||||
StateRestorer* record_method_and_dq_further(Method* mo);
|
||||
};
|
||||
|
||||
|
||||
// StatefulGenericMethodFamily is a wrapper around GenericMethodFamily that maintains the
|
||||
// qualification state during hierarchy visitation, and applies that state
|
||||
// when adding members to the GenericMethodFamily.
|
||||
class StatefulGenericMethodFamily : public StatefulMethodFamily {
|
||||
|
||||
public:
|
||||
StatefulGenericMethodFamily(generic::MethodDescriptor* md, generic::Context* ctx)
|
||||
: StatefulMethodFamily(new GenericMethodFamily(md->canonicalize(ctx))) {
|
||||
|
||||
}
|
||||
GenericMethodFamily* get_method_family() {
|
||||
return (GenericMethodFamily*)_method_family;
|
||||
}
|
||||
|
||||
bool descriptor_matches(generic::MethodDescriptor* md, generic::Context* ctx) {
|
||||
return get_method_family()->descriptor_matches(md, ctx);
|
||||
}
|
||||
};
|
||||
|
||||
class StateRestorer : public PseudoScopeMark {
|
||||
private:
|
||||
StatefulMethodFamily* _method;
|
||||
@ -563,9 +606,9 @@ class StateRestorer : public PseudoScopeMark {
|
||||
StateRestorer* StatefulMethodFamily::record_method_and_dq_further(Method* mo) {
|
||||
StateRestorer* mark = new StateRestorer(this, _qualification_state);
|
||||
if (_qualification_state == QUALIFIED) {
|
||||
_method->record_qualified_method(mo);
|
||||
_method_family->record_qualified_method(mo);
|
||||
} else {
|
||||
_method->record_disqualified_method(mo);
|
||||
_method_family->record_disqualified_method(mo);
|
||||
}
|
||||
// Everything found "above"??? this method in the hierarchy walk is set to
|
||||
// disqualified
|
||||
@ -573,15 +616,15 @@ StateRestorer* StatefulMethodFamily::record_method_and_dq_further(Method* mo) {
|
||||
return mark;
|
||||
}
|
||||
|
||||
class StatefulMethodFamilies : public ResourceObj {
|
||||
class StatefulGenericMethodFamilies : public ResourceObj {
|
||||
private:
|
||||
GrowableArray<StatefulMethodFamily*> _methods;
|
||||
GrowableArray<StatefulGenericMethodFamily*> _methods;
|
||||
|
||||
public:
|
||||
StatefulMethodFamily* find_matching(
|
||||
StatefulGenericMethodFamily* find_matching(
|
||||
generic::MethodDescriptor* md, generic::Context* ctx) {
|
||||
for (int i = 0; i < _methods.length(); ++i) {
|
||||
StatefulMethodFamily* existing = _methods.at(i);
|
||||
StatefulGenericMethodFamily* existing = _methods.at(i);
|
||||
if (existing->descriptor_matches(md, ctx)) {
|
||||
return existing;
|
||||
}
|
||||
@ -589,17 +632,17 @@ class StatefulMethodFamilies : public ResourceObj {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
StatefulMethodFamily* find_matching_or_create(
|
||||
StatefulGenericMethodFamily* find_matching_or_create(
|
||||
generic::MethodDescriptor* md, generic::Context* ctx) {
|
||||
StatefulMethodFamily* method = find_matching(md, ctx);
|
||||
StatefulGenericMethodFamily* method = find_matching(md, ctx);
|
||||
if (method == NULL) {
|
||||
method = new StatefulMethodFamily(md, ctx);
|
||||
method = new StatefulGenericMethodFamily(md, ctx);
|
||||
_methods.append(method);
|
||||
}
|
||||
return method;
|
||||
}
|
||||
|
||||
void extract_families_into(GrowableArray<MethodFamily*>* array) {
|
||||
void extract_families_into(GrowableArray<GenericMethodFamily*>* array) {
|
||||
for (int i = 0; i < _methods.length(); ++i) {
|
||||
array->append(_methods.at(i)->get_method_family());
|
||||
}
|
||||
@ -683,26 +726,79 @@ static GrowableArray<EmptyVtableSlot*>* find_empty_vtable_slots(
|
||||
return slots;
|
||||
}
|
||||
|
||||
// Iterates over the superinterface type hierarchy looking for all methods
|
||||
// with a specific erased signature.
|
||||
class FindMethodsByErasedSig : public HierarchyVisitor<FindMethodsByErasedSig> {
|
||||
private:
|
||||
// Context data
|
||||
Symbol* _method_name;
|
||||
Symbol* _method_signature;
|
||||
StatefulMethodFamily* _family;
|
||||
|
||||
public:
|
||||
FindMethodsByErasedSig(Symbol* name, Symbol* signature) :
|
||||
_method_name(name), _method_signature(signature),
|
||||
_family(NULL) {}
|
||||
|
||||
void get_discovered_family(MethodFamily** family) {
|
||||
if (_family != NULL) {
|
||||
*family = _family->get_method_family();
|
||||
} else {
|
||||
*family = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void* new_node_data(InstanceKlass* cls) { return new PseudoScope(); }
|
||||
void free_node_data(void* node_data) {
|
||||
PseudoScope::cast(node_data)->destroy();
|
||||
}
|
||||
|
||||
// Find all methods on this hierarchy that match this
|
||||
// method's erased (name, signature)
|
||||
bool visit() {
|
||||
PseudoScope* scope = PseudoScope::cast(current_data());
|
||||
InstanceKlass* iklass = current_class();
|
||||
|
||||
Method* m = iklass->find_method(_method_name, _method_signature);
|
||||
if (m != NULL) {
|
||||
if (_family == NULL) {
|
||||
_family = new StatefulMethodFamily();
|
||||
}
|
||||
|
||||
if (iklass->is_interface()) {
|
||||
StateRestorer* restorer = _family->record_method_and_dq_further(m);
|
||||
scope->add_mark(restorer);
|
||||
} else {
|
||||
// This is the rule that methods in classes "win" (bad word) over
|
||||
// methods in interfaces. This works because of single inheritance
|
||||
_family->set_target_if_empty(m);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// Iterates over the type hierarchy looking for all methods with a specific
|
||||
// method name. The result of this is a set of method families each of
|
||||
// which is populated with a set of methods that implement the same
|
||||
// language-level signature.
|
||||
class FindMethodsByName : public HierarchyVisitor<FindMethodsByName> {
|
||||
class FindMethodsByGenericSig : public HierarchyVisitor<FindMethodsByGenericSig> {
|
||||
private:
|
||||
// Context data
|
||||
Thread* THREAD;
|
||||
generic::DescriptorCache* _cache;
|
||||
Symbol* _method_name;
|
||||
generic::Context* _ctx;
|
||||
StatefulMethodFamilies _families;
|
||||
StatefulGenericMethodFamilies _families;
|
||||
|
||||
public:
|
||||
|
||||
FindMethodsByName(generic::DescriptorCache* cache, Symbol* name,
|
||||
FindMethodsByGenericSig(generic::DescriptorCache* cache, Symbol* name,
|
||||
generic::Context* ctx, Thread* thread) :
|
||||
_cache(cache), _method_name(name), _ctx(ctx), THREAD(thread) {}
|
||||
|
||||
void get_discovered_families(GrowableArray<MethodFamily*>* methods) {
|
||||
void get_discovered_families(GrowableArray<GenericMethodFamily*>* methods) {
|
||||
_families.extract_families_into(methods);
|
||||
}
|
||||
|
||||
@ -733,7 +829,7 @@ class FindMethodsByName : public HierarchyVisitor<FindMethodsByName> {
|
||||
// Find all methods on this hierarchy that match this method
|
||||
// (name, signature). This class collects other families of this
|
||||
// method name.
|
||||
StatefulMethodFamily* family =
|
||||
StatefulGenericMethodFamily* family =
|
||||
_families.find_matching_or_create(md, _ctx);
|
||||
|
||||
if (klass->is_interface()) {
|
||||
@ -752,8 +848,8 @@ class FindMethodsByName : public HierarchyVisitor<FindMethodsByName> {
|
||||
};
|
||||
|
||||
#ifndef PRODUCT
|
||||
static void print_families(
|
||||
GrowableArray<MethodFamily*>* methods, Symbol* match) {
|
||||
static void print_generic_families(
|
||||
GrowableArray<GenericMethodFamily*>* methods, Symbol* match) {
|
||||
streamIndentor si(tty, 4);
|
||||
if (methods->length() == 0) {
|
||||
tty->indent();
|
||||
@ -761,22 +857,87 @@ static void print_families(
|
||||
}
|
||||
for (int i = 0; i < methods->length(); ++i) {
|
||||
tty->indent();
|
||||
MethodFamily* lm = methods->at(i);
|
||||
GenericMethodFamily* lm = methods->at(i);
|
||||
if (lm->contains_signature(match)) {
|
||||
tty->print_cr("<Matching>");
|
||||
} else {
|
||||
tty->print_cr("<Non-Matching>");
|
||||
}
|
||||
lm->print_on(tty, 1);
|
||||
lm->print_sig_on(tty, lm->get_generic_sig(), 1);
|
||||
}
|
||||
}
|
||||
#endif // ndef PRODUCT
|
||||
|
||||
static void merge_in_new_methods(InstanceKlass* klass,
|
||||
GrowableArray<Method*>* new_methods, TRAPS);
|
||||
static void create_overpasses(
|
||||
GrowableArray<EmptyVtableSlot*>* slots, InstanceKlass* klass, TRAPS);
|
||||
|
||||
static void generate_generic_defaults(
|
||||
InstanceKlass* klass, GrowableArray<EmptyVtableSlot*>* empty_slots,
|
||||
EmptyVtableSlot* slot, int current_slot_index, TRAPS) {
|
||||
|
||||
if (slot->is_bound()) {
|
||||
#ifndef PRODUCT
|
||||
if (TraceDefaultMethods) {
|
||||
streamIndentor si(tty, 4);
|
||||
tty->indent().print_cr("Already bound to logical method:");
|
||||
GenericMethodFamily* lm = (GenericMethodFamily*)(slot->get_binding());
|
||||
lm->print_sig_on(tty, lm->get_generic_sig(), 1);
|
||||
}
|
||||
#endif // ndef PRODUCT
|
||||
return; // covered by previous processing
|
||||
}
|
||||
|
||||
generic::DescriptorCache cache;
|
||||
|
||||
generic::Context ctx(&cache);
|
||||
FindMethodsByGenericSig visitor(&cache, slot->name(), &ctx, CHECK);
|
||||
visitor.run(klass);
|
||||
|
||||
GrowableArray<GenericMethodFamily*> discovered_families;
|
||||
visitor.get_discovered_families(&discovered_families);
|
||||
|
||||
#ifndef PRODUCT
|
||||
if (TraceDefaultMethods) {
|
||||
print_generic_families(&discovered_families, slot->signature());
|
||||
}
|
||||
#endif // ndef PRODUCT
|
||||
|
||||
// Find and populate any other slots that match the discovered families
|
||||
for (int j = current_slot_index; j < empty_slots->length(); ++j) {
|
||||
EmptyVtableSlot* open_slot = empty_slots->at(j);
|
||||
|
||||
if (slot->name() == open_slot->name()) {
|
||||
for (int k = 0; k < discovered_families.length(); ++k) {
|
||||
GenericMethodFamily* lm = discovered_families.at(k);
|
||||
|
||||
if (lm->contains_signature(open_slot->signature())) {
|
||||
lm->determine_target(klass, CHECK);
|
||||
open_slot->bind_family(lm);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void generate_erased_defaults(
|
||||
InstanceKlass* klass, GrowableArray<EmptyVtableSlot*>* empty_slots,
|
||||
EmptyVtableSlot* slot, TRAPS) {
|
||||
|
||||
// sets up a set of methods with the same exact erased signature
|
||||
FindMethodsByErasedSig visitor(slot->name(), slot->signature());
|
||||
visitor.run(klass);
|
||||
|
||||
MethodFamily* family;
|
||||
visitor.get_discovered_family(&family);
|
||||
if (family != NULL) {
|
||||
family->determine_target(klass, CHECK);
|
||||
slot->bind_family(family);
|
||||
}
|
||||
}
|
||||
|
||||
static void merge_in_new_methods(InstanceKlass* klass,
|
||||
GrowableArray<Method*>* new_methods, TRAPS);
|
||||
|
||||
// This is the guts of the default methods implementation. This is called just
|
||||
// after the classfile has been parsed if some ancestor has default methods.
|
||||
//
|
||||
@ -807,8 +968,6 @@ void DefaultMethods::generate_default_methods(
|
||||
// whatever scope it's in.
|
||||
ResourceMark rm(THREAD);
|
||||
|
||||
generic::DescriptorCache cache;
|
||||
|
||||
// Keep entire hierarchy alive for the duration of the computation
|
||||
KeepAliveRegistrar keepAlive(THREAD);
|
||||
KeepAliveVisitor loadKeepAlive(&keepAlive);
|
||||
@ -837,47 +996,13 @@ void DefaultMethods::generate_default_methods(
|
||||
tty->print_cr("");
|
||||
}
|
||||
#endif // ndef PRODUCT
|
||||
if (slot->is_bound()) {
|
||||
#ifndef PRODUCT
|
||||
if (TraceDefaultMethods) {
|
||||
streamIndentor si(tty, 4);
|
||||
tty->indent().print_cr("Already bound to logical method:");
|
||||
slot->get_binding()->print_on(tty, 1);
|
||||
}
|
||||
#endif // ndef PRODUCT
|
||||
continue; // covered by previous processing
|
||||
|
||||
if (ParseGenericDefaults) {
|
||||
generate_generic_defaults(klass, empty_slots, slot, i, CHECK);
|
||||
} else {
|
||||
generate_erased_defaults(klass, empty_slots, slot, CHECK);
|
||||
}
|
||||
|
||||
generic::Context ctx(&cache);
|
||||
FindMethodsByName visitor(&cache, slot->name(), &ctx, CHECK);
|
||||
visitor.run(klass);
|
||||
|
||||
GrowableArray<MethodFamily*> discovered_families;
|
||||
visitor.get_discovered_families(&discovered_families);
|
||||
|
||||
#ifndef PRODUCT
|
||||
if (TraceDefaultMethods) {
|
||||
print_families(&discovered_families, slot->signature());
|
||||
}
|
||||
#endif // ndef PRODUCT
|
||||
|
||||
// Find and populate any other slots that match the discovered families
|
||||
for (int j = i; j < empty_slots->length(); ++j) {
|
||||
EmptyVtableSlot* open_slot = empty_slots->at(j);
|
||||
|
||||
if (slot->name() == open_slot->name()) {
|
||||
for (int k = 0; k < discovered_families.length(); ++k) {
|
||||
MethodFamily* lm = discovered_families.at(k);
|
||||
|
||||
if (lm->contains_signature(open_slot->signature())) {
|
||||
lm->determine_target(klass, CHECK);
|
||||
open_slot->bind_family(lm);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
#ifndef PRODUCT
|
||||
if (TraceDefaultMethods) {
|
||||
tty->print_cr("Creating overpasses...");
|
||||
@ -893,7 +1018,6 @@ void DefaultMethods::generate_default_methods(
|
||||
#endif // ndef PRODUCT
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Generic analysis was used upon interface '_target' and found a unique
|
||||
* default method candidate with generic signature '_method_desc'. This
|
||||
@ -912,17 +1036,85 @@ void DefaultMethods::generate_default_methods(
|
||||
* the selected method along that path.
|
||||
*/
|
||||
class ShadowChecker : public HierarchyVisitor<ShadowChecker> {
|
||||
private:
|
||||
generic::DescriptorCache* _cache;
|
||||
protected:
|
||||
Thread* THREAD;
|
||||
|
||||
InstanceKlass* _target;
|
||||
|
||||
Symbol* _method_name;
|
||||
InstanceKlass* _method_holder;
|
||||
generic::MethodDescriptor* _method_desc;
|
||||
bool _found_shadow;
|
||||
|
||||
|
||||
public:
|
||||
|
||||
ShadowChecker(Thread* thread, Symbol* name, InstanceKlass* holder,
|
||||
InstanceKlass* target)
|
||||
: THREAD(thread), _method_name(name), _method_holder(holder),
|
||||
_target(target), _found_shadow(false) {}
|
||||
|
||||
void* new_node_data(InstanceKlass* cls) { return NULL; }
|
||||
void free_node_data(void* data) { return; }
|
||||
|
||||
bool visit() {
|
||||
InstanceKlass* ik = current_class();
|
||||
if (ik == _target && current_depth() == 1) {
|
||||
return false; // This was the specified super -- no need to search it
|
||||
}
|
||||
if (ik == _method_holder || ik == _target) {
|
||||
// We found a path that should be examined to see if it shadows _method
|
||||
if (path_has_shadow()) {
|
||||
_found_shadow = true;
|
||||
cancel_iteration();
|
||||
}
|
||||
return false; // no need to continue up hierarchy
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool path_has_shadow() = 0;
|
||||
bool found_shadow() { return _found_shadow; }
|
||||
};
|
||||
|
||||
// Used for Invokespecial.
|
||||
// Invokespecial is allowed to invoke a concrete interface method
|
||||
// and can be used to disambuiguate among qualified candidates,
|
||||
// which are methods in immediate superinterfaces,
|
||||
// but may not be used to invoke a candidate that would be shadowed
|
||||
// from the perspective of the caller.
|
||||
// Invokespecial is also used in the overpass generation today
|
||||
// We re-run the shadowchecker because we can't distinguish this case,
|
||||
// but it should return the same answer, since the overpass target
|
||||
// is now the invokespecial caller.
|
||||
class ErasedShadowChecker : public ShadowChecker {
|
||||
private:
|
||||
bool path_has_shadow() {
|
||||
|
||||
for (int i = current_depth() - 1; i > 0; --i) {
|
||||
InstanceKlass* ik = class_at_depth(i);
|
||||
|
||||
if (ik->is_interface()) {
|
||||
int end;
|
||||
int start = ik->find_method_by_name(_method_name, &end);
|
||||
if (start != -1) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
public:
|
||||
|
||||
ErasedShadowChecker(Thread* thread, Symbol* name, InstanceKlass* holder,
|
||||
InstanceKlass* target)
|
||||
: ShadowChecker(thread, name, holder, target) {}
|
||||
};
|
||||
|
||||
class GenericShadowChecker : public ShadowChecker {
|
||||
private:
|
||||
generic::DescriptorCache* _cache;
|
||||
generic::MethodDescriptor* _method_desc;
|
||||
|
||||
bool path_has_shadow() {
|
||||
generic::Context ctx(_cache);
|
||||
|
||||
@ -950,104 +1142,42 @@ class ShadowChecker : public HierarchyVisitor<ShadowChecker> {
|
||||
|
||||
public:
|
||||
|
||||
ShadowChecker(generic::DescriptorCache* cache, Thread* thread,
|
||||
GenericShadowChecker(generic::DescriptorCache* cache, Thread* thread,
|
||||
Symbol* name, InstanceKlass* holder, generic::MethodDescriptor* desc,
|
||||
InstanceKlass* target)
|
||||
: _cache(cache), THREAD(thread), _method_name(name), _method_holder(holder),
|
||||
_method_desc(desc), _target(target), _found_shadow(false) {}
|
||||
|
||||
void* new_node_data(InstanceKlass* cls) { return NULL; }
|
||||
void free_node_data(void* data) { return; }
|
||||
|
||||
bool visit() {
|
||||
InstanceKlass* ik = current_class();
|
||||
if (ik == _target && current_depth() == 1) {
|
||||
return false; // This was the specified super -- no need to search it
|
||||
}
|
||||
if (ik == _method_holder || ik == _target) {
|
||||
// We found a path that should be examined to see if it shadows _method
|
||||
if (path_has_shadow()) {
|
||||
_found_shadow = true;
|
||||
cancel_iteration();
|
||||
}
|
||||
return false; // no need to continue up hierarchy
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool found_shadow() { return _found_shadow; }
|
||||
: ShadowChecker(thread, name, holder, target) {
|
||||
_cache = cache;
|
||||
_method_desc = desc;
|
||||
}
|
||||
};
|
||||
|
||||
// This is called during linktime when we find an invokespecial call that
|
||||
// refers to a direct superinterface. It indicates that we should find the
|
||||
// default method in the hierarchy of that superinterface, and if that method
|
||||
// would have been a candidate from the point of view of 'this' class, then we
|
||||
// return that method.
|
||||
Method* DefaultMethods::find_super_default(
|
||||
Klass* cls, Klass* super, Symbol* method_name, Symbol* sig, TRAPS) {
|
||||
|
||||
ResourceMark rm(THREAD);
|
||||
|
||||
assert(cls != NULL && super != NULL, "Need real classes");
|
||||
// Find the unique qualified candidate from the perspective of the super_class
|
||||
// which is the resolved_klass, which must be an immediate superinterface
|
||||
// of klass
|
||||
Method* find_erased_super_default(InstanceKlass* current_class, InstanceKlass* super_class, Symbol* method_name, Symbol* sig, TRAPS) {
|
||||
|
||||
InstanceKlass* current_class = InstanceKlass::cast(cls);
|
||||
InstanceKlass* direction = InstanceKlass::cast(super);
|
||||
FindMethodsByErasedSig visitor(method_name, sig);
|
||||
visitor.run(super_class); // find candidates from resolved_klass
|
||||
|
||||
// Keep entire hierarchy alive for the duration of the computation
|
||||
KeepAliveRegistrar keepAlive(THREAD);
|
||||
KeepAliveVisitor loadKeepAlive(&keepAlive);
|
||||
loadKeepAlive.run(current_class);
|
||||
MethodFamily* family;
|
||||
visitor.get_discovered_family(&family);
|
||||
|
||||
#ifndef PRODUCT
|
||||
if (TraceDefaultMethods) {
|
||||
tty->print_cr("Finding super default method %s.%s%s from %s",
|
||||
direction->name()->as_C_string(),
|
||||
method_name->as_C_string(), sig->as_C_string(),
|
||||
current_class->name()->as_C_string());
|
||||
}
|
||||
#endif // ndef PRODUCT
|
||||
|
||||
if (!direction->is_interface()) {
|
||||
// We should not be here
|
||||
return NULL;
|
||||
if (family != NULL) {
|
||||
family->determine_target(current_class, CHECK_NULL); // get target from current_class
|
||||
}
|
||||
|
||||
generic::DescriptorCache cache;
|
||||
generic::Context ctx(&cache);
|
||||
|
||||
// Prime the initial generic context for current -> direction
|
||||
ctx.apply_type_arguments(current_class, direction, CHECK_NULL);
|
||||
|
||||
FindMethodsByName visitor(&cache, method_name, &ctx, CHECK_NULL);
|
||||
visitor.run(direction);
|
||||
|
||||
GrowableArray<MethodFamily*> families;
|
||||
visitor.get_discovered_families(&families);
|
||||
|
||||
#ifndef PRODUCT
|
||||
if (TraceDefaultMethods) {
|
||||
print_families(&families, sig);
|
||||
}
|
||||
#endif // ndef PRODUCT
|
||||
|
||||
MethodFamily* selected_family = NULL;
|
||||
|
||||
for (int i = 0; i < families.length(); ++i) {
|
||||
MethodFamily* lm = families.at(i);
|
||||
if (lm->contains_signature(sig)) {
|
||||
lm->determine_target(current_class, CHECK_NULL);
|
||||
selected_family = lm;
|
||||
}
|
||||
}
|
||||
|
||||
if (selected_family->has_target()) {
|
||||
Method* target = selected_family->get_selected_target();
|
||||
if (family->has_target()) {
|
||||
Method* target = family->get_selected_target();
|
||||
InstanceKlass* holder = InstanceKlass::cast(target->method_holder());
|
||||
|
||||
// Verify that the identified method is valid from the context of
|
||||
// the current class
|
||||
ShadowChecker checker(&cache, THREAD, target->name(),
|
||||
holder, selected_family->descriptor(), direction);
|
||||
// the current class, which is the caller class for invokespecial
|
||||
// link resolution, i.e. ensure there it is not shadowed.
|
||||
// You can use invokespecial to disambiguate interface methods, but
|
||||
// you can not use it to skip over an interface method that would shadow it.
|
||||
ErasedShadowChecker checker(THREAD, target->name(), holder, super_class);
|
||||
checker.run(current_class);
|
||||
|
||||
if (checker.found_shadow()) {
|
||||
@ -1061,13 +1191,71 @@ Method* DefaultMethods::find_super_default(
|
||||
} else {
|
||||
#ifndef PRODUCT
|
||||
if (TraceDefaultMethods) {
|
||||
tty->print(" Returning ");
|
||||
print_method(tty, target, true);
|
||||
tty->print_cr("");
|
||||
family->print_sig_on(tty, target->signature(), 1);
|
||||
}
|
||||
#endif // ndef PRODUCT
|
||||
return target;
|
||||
}
|
||||
} else {
|
||||
assert(family->throws_exception(), "must have target or throw");
|
||||
THROW_MSG_(vmSymbols::java_lang_AbstractMethodError(),
|
||||
family->get_exception_message()->as_C_string(), NULL);
|
||||
}
|
||||
}
|
||||
|
||||
// super_class is assumed to be the direct super of current_class
|
||||
Method* find_generic_super_default( InstanceKlass* current_class,
|
||||
InstanceKlass* super_class,
|
||||
Symbol* method_name, Symbol* sig, TRAPS) {
|
||||
generic::DescriptorCache cache;
|
||||
generic::Context ctx(&cache);
|
||||
|
||||
// Prime the initial generic context for current -> super_class
|
||||
ctx.apply_type_arguments(current_class, super_class, CHECK_NULL);
|
||||
|
||||
FindMethodsByGenericSig visitor(&cache, method_name, &ctx, CHECK_NULL);
|
||||
visitor.run(super_class);
|
||||
|
||||
GrowableArray<GenericMethodFamily*> families;
|
||||
visitor.get_discovered_families(&families);
|
||||
|
||||
#ifndef PRODUCT
|
||||
if (TraceDefaultMethods) {
|
||||
print_generic_families(&families, sig);
|
||||
}
|
||||
#endif // ndef PRODUCT
|
||||
|
||||
GenericMethodFamily* selected_family = NULL;
|
||||
|
||||
for (int i = 0; i < families.length(); ++i) {
|
||||
GenericMethodFamily* lm = families.at(i);
|
||||
if (lm->contains_signature(sig)) {
|
||||
lm->determine_target(current_class, CHECK_NULL);
|
||||
selected_family = lm;
|
||||
}
|
||||
}
|
||||
|
||||
if (selected_family->has_target()) {
|
||||
Method* target = selected_family->get_selected_target();
|
||||
InstanceKlass* holder = InstanceKlass::cast(target->method_holder());
|
||||
|
||||
// Verify that the identified method is valid from the context of
|
||||
// the current class
|
||||
GenericShadowChecker checker(&cache, THREAD, target->name(),
|
||||
holder, selected_family->descriptor(), super_class);
|
||||
checker.run(current_class);
|
||||
|
||||
if (checker.found_shadow()) {
|
||||
#ifndef PRODUCT
|
||||
if (TraceDefaultMethods) {
|
||||
tty->print_cr(" Only candidate found was shadowed.");
|
||||
}
|
||||
#endif // ndef PRODUCT
|
||||
THROW_MSG_(vmSymbols::java_lang_AbstractMethodError(),
|
||||
"Accessible default method not found", NULL);
|
||||
} else {
|
||||
return target;
|
||||
}
|
||||
} else {
|
||||
assert(selected_family->throws_exception(), "must have target or throw");
|
||||
THROW_MSG_(vmSymbols::java_lang_AbstractMethodError(),
|
||||
@ -1075,6 +1263,71 @@ Method* DefaultMethods::find_super_default(
|
||||
}
|
||||
}
|
||||
|
||||
// This is called during linktime when we find an invokespecial call that
|
||||
// refers to a direct superinterface. It indicates that we should find the
|
||||
// default method in the hierarchy of that superinterface, and if that method
|
||||
// would have been a candidate from the point of view of 'this' class, then we
|
||||
// return that method.
|
||||
// This logic assumes that the super is a direct superclass of the caller
|
||||
Method* DefaultMethods::find_super_default(
|
||||
Klass* cls, Klass* super, Symbol* method_name, Symbol* sig, TRAPS) {
|
||||
|
||||
ResourceMark rm(THREAD);
|
||||
|
||||
assert(cls != NULL && super != NULL, "Need real classes");
|
||||
|
||||
InstanceKlass* current_class = InstanceKlass::cast(cls);
|
||||
InstanceKlass* super_class = InstanceKlass::cast(super);
|
||||
|
||||
// Keep entire hierarchy alive for the duration of the computation
|
||||
KeepAliveRegistrar keepAlive(THREAD);
|
||||
KeepAliveVisitor loadKeepAlive(&keepAlive);
|
||||
loadKeepAlive.run(current_class); // get hierarchy from current class
|
||||
|
||||
#ifndef PRODUCT
|
||||
if (TraceDefaultMethods) {
|
||||
tty->print_cr("Finding super default method %s.%s%s from %s",
|
||||
super_class->name()->as_C_string(),
|
||||
method_name->as_C_string(), sig->as_C_string(),
|
||||
current_class->name()->as_C_string());
|
||||
}
|
||||
#endif // ndef PRODUCT
|
||||
|
||||
assert(super_class->is_interface(), "only call for default methods");
|
||||
|
||||
Method* target = NULL;
|
||||
if (ParseGenericDefaults) {
|
||||
target = find_generic_super_default(current_class, super_class,
|
||||
method_name, sig, CHECK_NULL);
|
||||
} else {
|
||||
target = find_erased_super_default(current_class, super_class,
|
||||
method_name, sig, CHECK_NULL);
|
||||
}
|
||||
|
||||
#ifndef PRODUCT
|
||||
if (target != NULL) {
|
||||
if (TraceDefaultMethods) {
|
||||
tty->print(" Returning ");
|
||||
print_method(tty, target, true);
|
||||
tty->print_cr("");
|
||||
}
|
||||
}
|
||||
#endif // ndef PRODUCT
|
||||
return target;
|
||||
}
|
||||
|
||||
#ifndef PRODUCT
|
||||
// Return true is broad type is a covariant return of narrow type
|
||||
static bool covariant_return_type(BasicType narrow, BasicType broad) {
|
||||
if (narrow == broad) {
|
||||
return true;
|
||||
}
|
||||
if (broad == T_OBJECT) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
#endif // ndef PRODUCT
|
||||
|
||||
static int assemble_redirect(
|
||||
BytecodeConstantPool* cp, BytecodeBuffer* buffer,
|
||||
@ -1103,7 +1356,7 @@ static int assemble_redirect(
|
||||
out.next();
|
||||
}
|
||||
assert(out.at_return_type(), "Parameter counts do not match");
|
||||
assert(in.type() == out.type(), "Return types are not compatible");
|
||||
assert(covariant_return_type(out.type(), in.type()), "Return types are not compatible");
|
||||
|
||||
if (parameter_count == 1 && (in.type() == T_LONG || in.type() == T_DOUBLE)) {
|
||||
++parameter_count; // need room for return value
|
||||
@ -1144,10 +1397,15 @@ static Method* new_method(
|
||||
Symbol* sig, AccessFlags flags, int max_stack, int params,
|
||||
ConstMethod::MethodType mt, TRAPS) {
|
||||
|
||||
address code_start = static_cast<address>(bytecodes->adr_at(0));
|
||||
int code_length = bytecodes->length();
|
||||
address code_start = 0;
|
||||
int code_length = 0;
|
||||
InlineTableSizes sizes;
|
||||
|
||||
if (bytecodes != NULL && bytecodes->length() > 0) {
|
||||
code_start = static_cast<address>(bytecodes->adr_at(0));
|
||||
code_length = bytecodes->length();
|
||||
}
|
||||
|
||||
Method* m = Method::allocate(cp->pool_holder()->class_loader_data(),
|
||||
code_length, flags, &sizes,
|
||||
mt, CHECK_NULL);
|
||||
|
@ -234,6 +234,7 @@ class java_lang_Class : AllStatic {
|
||||
static GrowableArray<Klass*>* _fixup_mirror_list;
|
||||
|
||||
static void set_init_lock(oop java_class, oop init_lock);
|
||||
static void set_protection_domain(oop java_class, oop protection_domain);
|
||||
public:
|
||||
static void compute_offsets();
|
||||
|
||||
@ -272,7 +273,6 @@ class java_lang_Class : AllStatic {
|
||||
|
||||
// Support for embedded per-class oops
|
||||
static oop protection_domain(oop java_class);
|
||||
static void set_protection_domain(oop java_class, oop protection_domain);
|
||||
static oop init_lock(oop java_class);
|
||||
static objArrayOop signers(oop java_class);
|
||||
static void set_signers(oop java_class, objArrayOop signers);
|
||||
|
@ -53,8 +53,6 @@
|
||||
template(java_lang_Object, "java/lang/Object") \
|
||||
template(java_lang_Class, "java/lang/Class") \
|
||||
template(java_lang_String, "java/lang/String") \
|
||||
template(java_lang_StringValue, "java/lang/StringValue") \
|
||||
template(java_lang_StringCache, "java/lang/StringValue$StringCache") \
|
||||
template(java_lang_Thread, "java/lang/Thread") \
|
||||
template(java_lang_ThreadGroup, "java/lang/ThreadGroup") \
|
||||
template(java_lang_Cloneable, "java/lang/Cloneable") \
|
||||
@ -106,7 +104,6 @@
|
||||
template(java_util_Vector, "java/util/Vector") \
|
||||
template(java_util_AbstractList, "java/util/AbstractList") \
|
||||
template(java_util_Hashtable, "java/util/Hashtable") \
|
||||
template(java_util_HashMap, "java/util/HashMap") \
|
||||
template(java_lang_Compiler, "java/lang/Compiler") \
|
||||
template(sun_misc_Signal, "sun/misc/Signal") \
|
||||
template(java_lang_AssertionStatusDirectives, "java/lang/AssertionStatusDirectives") \
|
||||
@ -367,8 +364,6 @@
|
||||
template(offset_name, "offset") \
|
||||
template(count_name, "count") \
|
||||
template(hash_name, "hash") \
|
||||
template(frontCacheEnabled_name, "frontCacheEnabled") \
|
||||
template(stringCacheEnabled_name, "stringCacheEnabled") \
|
||||
template(numberOfLeadingZeros_name, "numberOfLeadingZeros") \
|
||||
template(numberOfTrailingZeros_name, "numberOfTrailingZeros") \
|
||||
template(bitCount_name, "bitCount") \
|
||||
|
@ -2017,12 +2017,6 @@ oop_since_save_marks_iterate##nv_suffix(OopClosureType* blk) { \
|
||||
|
||||
ALL_SINCE_SAVE_MARKS_CLOSURES(CFLS_OOP_SINCE_SAVE_MARKS_DEFN)
|
||||
|
||||
|
||||
void CompactibleFreeListSpace::object_iterate_since_last_GC(ObjectClosure* cl) {
|
||||
// ugghh... how would one do this efficiently for a non-contiguous space?
|
||||
guarantee(false, "NYI");
|
||||
}
|
||||
|
||||
bool CompactibleFreeListSpace::linearAllocationWouldFail() const {
|
||||
return _smallLinearAllocBlock._word_size == 0;
|
||||
}
|
||||
|
@ -396,7 +396,6 @@ class CompactibleFreeListSpace: public CompactibleSpace {
|
||||
// iteration support for promotion
|
||||
void save_marks();
|
||||
bool no_allocs_since_save_marks();
|
||||
void object_iterate_since_last_GC(ObjectClosure* cl);
|
||||
|
||||
// iteration support for sweeping
|
||||
void save_sweep_limit() {
|
||||
|
@ -3129,26 +3129,6 @@ oop_since_save_marks_iterate##nv_suffix(OopClosureType* cl) { \
|
||||
|
||||
ALL_SINCE_SAVE_MARKS_CLOSURES(CMS_SINCE_SAVE_MARKS_DEFN)
|
||||
|
||||
void
|
||||
ConcurrentMarkSweepGeneration::object_iterate_since_last_GC(ObjectClosure* blk)
|
||||
{
|
||||
// Not currently implemented; need to do the following. -- ysr.
|
||||
// dld -- I think that is used for some sort of allocation profiler. So it
|
||||
// really means the objects allocated by the mutator since the last
|
||||
// GC. We could potentially implement this cheaply by recording only
|
||||
// the direct allocations in a side data structure.
|
||||
//
|
||||
// I think we probably ought not to be required to support these
|
||||
// iterations at any arbitrary point; I think there ought to be some
|
||||
// call to enable/disable allocation profiling in a generation/space,
|
||||
// and the iterator ought to return the objects allocated in the
|
||||
// gen/space since the enable call, or the last iterator call (which
|
||||
// will probably be at a GC.) That way, for gens like CM&S that would
|
||||
// require some extra data structure to support this, we only pay the
|
||||
// cost when it's in use...
|
||||
cmsSpace()->object_iterate_since_last_GC(blk);
|
||||
}
|
||||
|
||||
void
|
||||
ConcurrentMarkSweepGeneration::younger_refs_iterate(OopsInGenClosure* cl) {
|
||||
cl->set_generation(this);
|
||||
|
@ -1273,7 +1273,6 @@ class ConcurrentMarkSweepGeneration: public CardGeneration {
|
||||
// Iteration support and related enquiries
|
||||
void save_marks();
|
||||
bool no_allocs_since_save_marks();
|
||||
void object_iterate_since_last_GC(ObjectClosure* cl);
|
||||
void younger_refs_iterate(OopsInGenClosure* cl);
|
||||
|
||||
// Iteration support specific to CMS generations
|
||||
|
@ -54,7 +54,6 @@
|
||||
#include "memory/referenceProcessor.hpp"
|
||||
#include "oops/oop.inline.hpp"
|
||||
#include "oops/oop.pcgc.inline.hpp"
|
||||
#include "runtime/aprofiler.hpp"
|
||||
#include "runtime/vmThread.hpp"
|
||||
|
||||
size_t G1CollectedHeap::_humongous_object_threshold_in_words = 0;
|
||||
@ -2665,11 +2664,6 @@ void G1CollectedHeap::object_iterate(ObjectClosure* cl) {
|
||||
heap_region_iterate(&blk);
|
||||
}
|
||||
|
||||
void G1CollectedHeap::object_iterate_since_last_GC(ObjectClosure* cl) {
|
||||
// FIXME: is this right?
|
||||
guarantee(false, "object_iterate_since_last_GC not supported by G1 heap");
|
||||
}
|
||||
|
||||
// Calls a SpaceClosure on a HeapRegion.
|
||||
|
||||
class SpaceClosureRegionClosure: public HeapRegionClosure {
|
||||
@ -3598,8 +3592,6 @@ G1CollectedHeap* G1CollectedHeap::heap() {
|
||||
void G1CollectedHeap::gc_prologue(bool full /* Ignored */) {
|
||||
// always_do_update_barrier = false;
|
||||
assert(InlineCacheBuffer::is_empty(), "should have cleaned up ICBuffer");
|
||||
// Call allocation profiler
|
||||
AllocationProfiler::iterate_since_last_gc();
|
||||
// Fill TLAB's and such
|
||||
ensure_parsability(true);
|
||||
}
|
||||
|
@ -1360,11 +1360,6 @@ public:
|
||||
object_iterate(cl);
|
||||
}
|
||||
|
||||
// Iterate over all objects allocated since the last collection, calling
|
||||
// "cl.do_object" on each. The heap must have been initialized properly
|
||||
// to support this function, or else this call will fail.
|
||||
virtual void object_iterate_since_last_GC(ObjectClosure* cl);
|
||||
|
||||
// Iterate over all spaces in use in the heap, in ascending address order.
|
||||
virtual void space_iterate(SpaceClosure* cl);
|
||||
|
||||
|
@ -873,7 +873,7 @@ bool G1CollectorPolicy::need_to_start_conc_mark(const char* source, size_t alloc
|
||||
size_t alloc_byte_size = alloc_word_size * HeapWordSize;
|
||||
|
||||
if ((cur_used_bytes + alloc_byte_size) > marking_initiating_used_threshold) {
|
||||
if (gcs_are_young()) {
|
||||
if (gcs_are_young() && !_last_young_gc) {
|
||||
ergo_verbose5(ErgoConcCycles,
|
||||
"request concurrent cycle initiation",
|
||||
ergo_format_reason("occupancy higher than threshold")
|
||||
@ -931,7 +931,7 @@ void G1CollectorPolicy::record_collection_pause_end(double pause_time_ms, Evacua
|
||||
last_pause_included_initial_mark = during_initial_mark_pause();
|
||||
if (last_pause_included_initial_mark) {
|
||||
record_concurrent_mark_init_end(0.0);
|
||||
} else if (!_last_young_gc && need_to_start_conc_mark("end of GC")) {
|
||||
} else if (need_to_start_conc_mark("end of GC")) {
|
||||
// Note: this might have already been set, if during the last
|
||||
// pause we decided to start a cycle but at the beginning of
|
||||
// this pause we decided to postpone it. That's OK.
|
||||
|
@ -43,7 +43,6 @@
|
||||
#include "oops/instanceRefKlass.hpp"
|
||||
#include "oops/oop.inline.hpp"
|
||||
#include "prims/jvmtiExport.hpp"
|
||||
#include "runtime/aprofiler.hpp"
|
||||
#include "runtime/biasedLocking.hpp"
|
||||
#include "runtime/fprofiler.hpp"
|
||||
#include "runtime/synchronizer.hpp"
|
||||
|
@ -23,12 +23,14 @@
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "gc_implementation/shared/copyFailedInfo.hpp"
|
||||
#include "gc_implementation/shared/gcHeapSummary.hpp"
|
||||
#include "gc_implementation/shared/gcTimer.hpp"
|
||||
#include "gc_implementation/shared/gcTrace.hpp"
|
||||
#include "gc_implementation/shared/copyFailedInfo.hpp"
|
||||
#include "gc_implementation/shared/objectCountEventSender.hpp"
|
||||
#include "memory/heapInspection.hpp"
|
||||
#include "memory/referenceProcessorStats.hpp"
|
||||
#include "runtime/os.hpp"
|
||||
#include "utilities/globalDefinitions.hpp"
|
||||
|
||||
#if INCLUDE_ALL_GCS
|
||||
@ -38,7 +40,7 @@
|
||||
#define assert_unset_gc_id() assert(_shared_gc_info.id() == SharedGCInfo::UNSET_GCID, "GC already started?")
|
||||
#define assert_set_gc_id() assert(_shared_gc_info.id() != SharedGCInfo::UNSET_GCID, "GC not started?")
|
||||
|
||||
static jlong GCTracer_next_gc_id = 0;
|
||||
static GCId GCTracer_next_gc_id = 0;
|
||||
static GCId create_new_gc_id() {
|
||||
return GCTracer_next_gc_id++;
|
||||
}
|
||||
@ -91,26 +93,38 @@ void GCTracer::report_gc_reference_stats(const ReferenceProcessorStats& rps) con
|
||||
}
|
||||
|
||||
#if INCLUDE_SERVICES
|
||||
void ObjectCountEventSenderClosure::do_cinfo(KlassInfoEntry* entry) {
|
||||
if (should_send_event(entry)) {
|
||||
send_event(entry);
|
||||
class ObjectCountEventSenderClosure : public KlassInfoClosure {
|
||||
const GCId _gc_id;
|
||||
const double _size_threshold_percentage;
|
||||
const size_t _total_size_in_words;
|
||||
const jlong _timestamp;
|
||||
|
||||
public:
|
||||
ObjectCountEventSenderClosure(GCId gc_id, size_t total_size_in_words, jlong timestamp) :
|
||||
_gc_id(gc_id),
|
||||
_size_threshold_percentage(ObjectCountCutOffPercent / 100),
|
||||
_total_size_in_words(total_size_in_words),
|
||||
_timestamp(timestamp)
|
||||
{}
|
||||
|
||||
virtual void do_cinfo(KlassInfoEntry* entry) {
|
||||
if (should_send_event(entry)) {
|
||||
ObjectCountEventSender::send(entry, _gc_id, _timestamp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ObjectCountEventSenderClosure::send_event(KlassInfoEntry* entry) {
|
||||
_gc_tracer->send_object_count_after_gc_event(entry->klass(), entry->count(),
|
||||
entry->words() * BytesPerWord);
|
||||
}
|
||||
|
||||
bool ObjectCountEventSenderClosure::should_send_event(KlassInfoEntry* entry) const {
|
||||
double percentage_of_heap = ((double) entry->words()) / _total_size_in_words;
|
||||
return percentage_of_heap > _size_threshold_percentage;
|
||||
}
|
||||
private:
|
||||
bool should_send_event(const KlassInfoEntry* entry) const {
|
||||
double percentage_of_heap = ((double) entry->words()) / _total_size_in_words;
|
||||
return percentage_of_heap >= _size_threshold_percentage;
|
||||
}
|
||||
};
|
||||
|
||||
void GCTracer::report_object_count_after_gc(BoolObjectClosure* is_alive_cl) {
|
||||
assert_set_gc_id();
|
||||
assert(is_alive_cl != NULL, "Must supply function to check liveness");
|
||||
|
||||
if (should_send_object_count_after_gc_event()) {
|
||||
if (ObjectCountEventSender::should_send_event()) {
|
||||
ResourceMark rm;
|
||||
|
||||
KlassInfoTable cit(false);
|
||||
@ -118,12 +132,13 @@ void GCTracer::report_object_count_after_gc(BoolObjectClosure* is_alive_cl) {
|
||||
HeapInspection hi(false, false, false, NULL);
|
||||
hi.populate_table(&cit, is_alive_cl);
|
||||
|
||||
ObjectCountEventSenderClosure event_sender(this, cit.size_of_instances_in_words());
|
||||
jlong timestamp = os::elapsed_counter();
|
||||
ObjectCountEventSenderClosure event_sender(_shared_gc_info.id(), cit.size_of_instances_in_words(), timestamp);
|
||||
cit.iterate(&event_sender);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif // INCLUDE_SERVICES
|
||||
|
||||
void GCTracer::report_gc_heap_summary(GCWhen::Type when, const GCHeapSummary& heap_summary, const MetaspaceSummary& meta_space_summary) const {
|
||||
assert_set_gc_id();
|
||||
|
@ -30,7 +30,6 @@
|
||||
#include "gc_implementation/shared/gcWhen.hpp"
|
||||
#include "gc_implementation/shared/copyFailedInfo.hpp"
|
||||
#include "memory/allocation.hpp"
|
||||
#include "memory/klassInfoClosure.hpp"
|
||||
#include "memory/referenceType.hpp"
|
||||
#if INCLUDE_ALL_GCS
|
||||
#include "gc_implementation/g1/g1YCTypes.hpp"
|
||||
@ -113,7 +112,6 @@ class G1YoungGCInfo VALUE_OBJ_CLASS_SPEC {
|
||||
#endif // INCLUDE_ALL_GCS
|
||||
|
||||
class GCTracer : public ResourceObj {
|
||||
friend class ObjectCountEventSenderClosure;
|
||||
protected:
|
||||
SharedGCInfo _shared_gc_info;
|
||||
|
||||
@ -123,7 +121,6 @@ class GCTracer : public ResourceObj {
|
||||
void report_gc_heap_summary(GCWhen::Type when, const GCHeapSummary& heap_summary, const MetaspaceSummary& meta_space_summary) const;
|
||||
void report_gc_reference_stats(const ReferenceProcessorStats& rp) const;
|
||||
void report_object_count_after_gc(BoolObjectClosure* object_filter) NOT_SERVICES_RETURN;
|
||||
|
||||
bool has_reported_gc_start() const;
|
||||
|
||||
protected:
|
||||
@ -137,25 +134,6 @@ class GCTracer : public ResourceObj {
|
||||
void send_meta_space_summary_event(GCWhen::Type when, const MetaspaceSummary& meta_space_summary) const;
|
||||
void send_reference_stats_event(ReferenceType type, size_t count) const;
|
||||
void send_phase_events(TimePartitions* time_partitions) const;
|
||||
void send_object_count_after_gc_event(Klass* klass, jlong count, julong total_size) const NOT_SERVICES_RETURN;
|
||||
bool should_send_object_count_after_gc_event() const;
|
||||
};
|
||||
|
||||
class ObjectCountEventSenderClosure : public KlassInfoClosure {
|
||||
GCTracer* _gc_tracer;
|
||||
const double _size_threshold_percentage;
|
||||
const size_t _total_size_in_words;
|
||||
public:
|
||||
ObjectCountEventSenderClosure(GCTracer* gc_tracer, size_t total_size_in_words) :
|
||||
_gc_tracer(gc_tracer),
|
||||
_size_threshold_percentage(ObjectCountCutOffPercent / 100),
|
||||
_total_size_in_words(total_size_in_words)
|
||||
{}
|
||||
virtual void do_cinfo(KlassInfoEntry* entry);
|
||||
protected:
|
||||
virtual void send_event(KlassInfoEntry* entry);
|
||||
private:
|
||||
bool should_send_event(KlassInfoEntry* entry) const;
|
||||
};
|
||||
|
||||
class YoungGCTracer : public GCTracer {
|
||||
|
@ -123,27 +123,6 @@ void OldGCTracer::send_concurrent_mode_failure_event() {
|
||||
}
|
||||
}
|
||||
|
||||
#if INCLUDE_SERVICES
|
||||
void GCTracer::send_object_count_after_gc_event(Klass* klass, jlong count, julong total_size) const {
|
||||
EventObjectCountAfterGC e;
|
||||
if (e.should_commit()) {
|
||||
e.set_gcId(_shared_gc_info.id());
|
||||
e.set_class(klass);
|
||||
e.set_count(count);
|
||||
e.set_totalSize(total_size);
|
||||
e.commit();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
bool GCTracer::should_send_object_count_after_gc_event() const {
|
||||
#if INCLUDE_TRACE
|
||||
return Tracing::is_event_enabled(EventObjectCountAfterGC::eventId);
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if INCLUDE_ALL_GCS
|
||||
void G1NewTracer::send_g1_young_gc_event() {
|
||||
EventGCG1GarbageCollection e(UNTIMED);
|
||||
|
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 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_implementation/shared/objectCountEventSender.hpp"
|
||||
#include "memory/heapInspection.hpp"
|
||||
#include "trace/tracing.hpp"
|
||||
#include "utilities/globalDefinitions.hpp"
|
||||
|
||||
#if INCLUDE_SERVICES
|
||||
|
||||
void ObjectCountEventSender::send(const KlassInfoEntry* entry, GCId gc_id, jlong timestamp) {
|
||||
assert(Tracing::is_event_enabled(EventObjectCountAfterGC::eventId),
|
||||
"Only call this method if the event is enabled");
|
||||
|
||||
EventObjectCountAfterGC event(UNTIMED);
|
||||
event.set_gcId(gc_id);
|
||||
event.set_class(entry->klass());
|
||||
event.set_count(entry->count());
|
||||
event.set_totalSize(entry->words() * BytesPerWord);
|
||||
event.set_endtime(timestamp);
|
||||
event.commit();
|
||||
}
|
||||
|
||||
bool ObjectCountEventSender::should_send_event() {
|
||||
#if INCLUDE_TRACE
|
||||
return Tracing::is_event_enabled(EventObjectCountAfterGC::eventId);
|
||||
#else
|
||||
return false;
|
||||
#endif // INCLUDE_TRACE
|
||||
}
|
||||
|
||||
#endif // INCLUDE_SERVICES
|
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 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_OBJECT_COUNT_EVENT_SENDER_HPP
|
||||
#define SHARE_VM_OBJECT_COUNT_EVENT_SENDER_HPP
|
||||
|
||||
#include "gc_implementation/shared/gcTrace.hpp"
|
||||
#include "memory/allocation.hpp"
|
||||
#include "utilities/macros.hpp"
|
||||
|
||||
#if INCLUDE_SERVICES
|
||||
|
||||
class KlassInfoEntry;
|
||||
|
||||
class ObjectCountEventSender : public AllStatic {
|
||||
public:
|
||||
static void send(const KlassInfoEntry* entry, GCId gc_id, jlong timestamp);
|
||||
static bool should_send_event();
|
||||
};
|
||||
|
||||
#endif // INCLUDE_SERVICES
|
||||
|
||||
#endif // SHARE_VM_OBJECT_COUNT_EVENT_SENDER
|
@ -85,16 +85,16 @@ GCHeapSummary CollectedHeap::create_heap_summary() {
|
||||
|
||||
MetaspaceSummary CollectedHeap::create_metaspace_summary() {
|
||||
const MetaspaceSizes meta_space(
|
||||
0, /*MetaspaceAux::capacity_in_bytes(),*/
|
||||
0, /*MetaspaceAux::used_in_bytes(),*/
|
||||
MetaspaceAux::allocated_capacity_bytes(),
|
||||
MetaspaceAux::allocated_used_bytes(),
|
||||
MetaspaceAux::reserved_in_bytes());
|
||||
const MetaspaceSizes data_space(
|
||||
0, /*MetaspaceAux::capacity_in_bytes(Metaspace::NonClassType),*/
|
||||
0, /*MetaspaceAux::used_in_bytes(Metaspace::NonClassType),*/
|
||||
MetaspaceAux::allocated_capacity_bytes(Metaspace::NonClassType),
|
||||
MetaspaceAux::allocated_used_bytes(Metaspace::NonClassType),
|
||||
MetaspaceAux::reserved_in_bytes(Metaspace::NonClassType));
|
||||
const MetaspaceSizes class_space(
|
||||
0, /*MetaspaceAux::capacity_in_bytes(Metaspace::ClassType),*/
|
||||
0, /*MetaspaceAux::used_in_bytes(Metaspace::ClassType),*/
|
||||
MetaspaceAux::allocated_capacity_bytes(Metaspace::ClassType),
|
||||
MetaspaceAux::allocated_used_bytes(Metaspace::ClassType),
|
||||
MetaspaceAux::reserved_in_bytes(Metaspace::ClassType));
|
||||
|
||||
return MetaspaceSummary(meta_space, data_space, class_space);
|
||||
|
@ -236,10 +236,11 @@ class ChunkPool: public CHeapObj<mtInternal> {
|
||||
size_t _num_used; // number of chunks currently checked out
|
||||
const size_t _size; // size of each chunk (must be uniform)
|
||||
|
||||
// Our three static pools
|
||||
// Our four static pools
|
||||
static ChunkPool* _large_pool;
|
||||
static ChunkPool* _medium_pool;
|
||||
static ChunkPool* _small_pool;
|
||||
static ChunkPool* _tiny_pool;
|
||||
|
||||
// return first element or null
|
||||
void* get_first() {
|
||||
@ -319,15 +320,18 @@ class ChunkPool: public CHeapObj<mtInternal> {
|
||||
static ChunkPool* large_pool() { assert(_large_pool != NULL, "must be initialized"); return _large_pool; }
|
||||
static ChunkPool* medium_pool() { assert(_medium_pool != NULL, "must be initialized"); return _medium_pool; }
|
||||
static ChunkPool* small_pool() { assert(_small_pool != NULL, "must be initialized"); return _small_pool; }
|
||||
static ChunkPool* tiny_pool() { assert(_tiny_pool != NULL, "must be initialized"); return _tiny_pool; }
|
||||
|
||||
static void initialize() {
|
||||
_large_pool = new ChunkPool(Chunk::size + Chunk::aligned_overhead_size());
|
||||
_medium_pool = new ChunkPool(Chunk::medium_size + Chunk::aligned_overhead_size());
|
||||
_small_pool = new ChunkPool(Chunk::init_size + Chunk::aligned_overhead_size());
|
||||
_tiny_pool = new ChunkPool(Chunk::tiny_size + Chunk::aligned_overhead_size());
|
||||
}
|
||||
|
||||
static void clean() {
|
||||
enum { BlocksToKeep = 5 };
|
||||
_tiny_pool->free_all_but(BlocksToKeep);
|
||||
_small_pool->free_all_but(BlocksToKeep);
|
||||
_medium_pool->free_all_but(BlocksToKeep);
|
||||
_large_pool->free_all_but(BlocksToKeep);
|
||||
@ -337,6 +341,7 @@ class ChunkPool: public CHeapObj<mtInternal> {
|
||||
ChunkPool* ChunkPool::_large_pool = NULL;
|
||||
ChunkPool* ChunkPool::_medium_pool = NULL;
|
||||
ChunkPool* ChunkPool::_small_pool = NULL;
|
||||
ChunkPool* ChunkPool::_tiny_pool = NULL;
|
||||
|
||||
void chunkpool_init() {
|
||||
ChunkPool::initialize();
|
||||
@ -376,6 +381,7 @@ void* Chunk::operator new (size_t requested_size, AllocFailType alloc_failmode,
|
||||
case Chunk::size: return ChunkPool::large_pool()->allocate(bytes, alloc_failmode);
|
||||
case Chunk::medium_size: return ChunkPool::medium_pool()->allocate(bytes, alloc_failmode);
|
||||
case Chunk::init_size: return ChunkPool::small_pool()->allocate(bytes, alloc_failmode);
|
||||
case Chunk::tiny_size: return ChunkPool::tiny_pool()->allocate(bytes, alloc_failmode);
|
||||
default: {
|
||||
void* p = os::malloc(bytes, mtChunk, CALLER_PC);
|
||||
if (p == NULL && alloc_failmode == AllocFailStrategy::EXIT_OOM) {
|
||||
@ -392,6 +398,7 @@ void Chunk::operator delete(void* p) {
|
||||
case Chunk::size: ChunkPool::large_pool()->free(c); break;
|
||||
case Chunk::medium_size: ChunkPool::medium_pool()->free(c); break;
|
||||
case Chunk::init_size: ChunkPool::small_pool()->free(c); break;
|
||||
case Chunk::tiny_size: ChunkPool::tiny_pool()->free(c); break;
|
||||
default: os::free(c, mtChunk);
|
||||
}
|
||||
}
|
||||
|
@ -353,7 +353,8 @@ class Chunk: CHeapObj<mtChunk> {
|
||||
slack = 20, // suspected sizeof(Chunk) + internal malloc headers
|
||||
#endif
|
||||
|
||||
init_size = 1*K - slack, // Size of first chunk
|
||||
tiny_size = 256 - slack, // Size of first chunk (tiny)
|
||||
init_size = 1*K - slack, // Size of first chunk (normal aka small)
|
||||
medium_size= 10*K - slack, // Size of medium-sized chunk
|
||||
size = 32*K - slack, // Default size of an Arena chunk (following the first)
|
||||
non_pool_size = init_size + 32 // An initial size which is not one of above
|
||||
|
@ -450,11 +450,6 @@ void DefNewGeneration::compute_new_size() {
|
||||
}
|
||||
}
|
||||
|
||||
void DefNewGeneration::object_iterate_since_last_GC(ObjectClosure* cl) {
|
||||
// $$$ This may be wrong in case of "scavenge failure"?
|
||||
eden()->object_iterate(cl);
|
||||
}
|
||||
|
||||
void DefNewGeneration::younger_refs_iterate(OopsInGenClosure* cl) {
|
||||
assert(false, "NYI -- are you sure you want to call this?");
|
||||
}
|
||||
|
@ -252,7 +252,6 @@ protected:
|
||||
|
||||
// Iteration
|
||||
void object_iterate(ObjectClosure* blk);
|
||||
void object_iterate_since_last_GC(ObjectClosure* cl);
|
||||
|
||||
void younger_refs_iterate(OopsInGenClosure* cl);
|
||||
|
||||
|
@ -42,7 +42,6 @@
|
||||
#include "memory/space.hpp"
|
||||
#include "oops/oop.inline.hpp"
|
||||
#include "oops/oop.inline2.hpp"
|
||||
#include "runtime/aprofiler.hpp"
|
||||
#include "runtime/biasedLocking.hpp"
|
||||
#include "runtime/fprofiler.hpp"
|
||||
#include "runtime/handles.hpp"
|
||||
@ -873,12 +872,6 @@ void GenCollectedHeap::safe_object_iterate(ObjectClosure* cl) {
|
||||
}
|
||||
}
|
||||
|
||||
void GenCollectedHeap::object_iterate_since_last_GC(ObjectClosure* cl) {
|
||||
for (int i = 0; i < _n_gens; i++) {
|
||||
_gens[i]->object_iterate_since_last_GC(cl);
|
||||
}
|
||||
}
|
||||
|
||||
Space* GenCollectedHeap::space_containing(const void* addr) const {
|
||||
for (int i = 0; i < _n_gens; i++) {
|
||||
Space* res = _gens[i]->space_containing(addr);
|
||||
@ -1186,8 +1179,6 @@ void GenCollectedHeap::gc_prologue(bool full) {
|
||||
CollectedHeap::accumulate_statistics_all_tlabs();
|
||||
ensure_parsability(true); // retire TLABs
|
||||
|
||||
// Call allocation profiler
|
||||
AllocationProfiler::iterate_since_last_gc();
|
||||
// Walk generations
|
||||
GenGCPrologueClosure blk(full);
|
||||
generation_iterate(&blk, false); // not old-to-young.
|
||||
|
@ -222,7 +222,6 @@ public:
|
||||
void oop_iterate(MemRegion mr, ExtendedOopClosure* cl);
|
||||
void object_iterate(ObjectClosure* cl);
|
||||
void safe_object_iterate(ObjectClosure* cl);
|
||||
void object_iterate_since_last_GC(ObjectClosure* cl);
|
||||
Space* space_containing(const void* addr) const;
|
||||
|
||||
// A CollectedHeap is divided into a dense sequence of "blocks"; that is,
|
||||
|
@ -811,16 +811,6 @@ void OneContigSpaceCardGeneration::space_iterate(SpaceClosure* blk,
|
||||
blk->do_space(_the_space);
|
||||
}
|
||||
|
||||
void OneContigSpaceCardGeneration::object_iterate_since_last_GC(ObjectClosure* blk) {
|
||||
// Deal with delayed initialization of _the_space,
|
||||
// and lack of initialization of _last_gc.
|
||||
if (_last_gc.space() == NULL) {
|
||||
assert(the_space() != NULL, "shouldn't be NULL");
|
||||
_last_gc = the_space()->bottom_mark();
|
||||
}
|
||||
the_space()->object_iterate_from(_last_gc, blk);
|
||||
}
|
||||
|
||||
void OneContigSpaceCardGeneration::younger_refs_iterate(OopsInGenClosure* blk) {
|
||||
blk->set_generation(this);
|
||||
younger_refs_in_space_iterate(_the_space, blk);
|
||||
|
@ -551,12 +551,6 @@ class Generation: public CHeapObj<mtGC> {
|
||||
// the heap. This defaults to object_iterate() unless overridden.
|
||||
virtual void safe_object_iterate(ObjectClosure* cl);
|
||||
|
||||
// Iterate over all objects allocated in the generation since the last
|
||||
// collection, calling "cl.do_object" on each. The generation must have
|
||||
// been initialized properly to support this function, or else this call
|
||||
// will fail.
|
||||
virtual void object_iterate_since_last_GC(ObjectClosure* cl) = 0;
|
||||
|
||||
// Apply "cl->do_oop" to (the address of) all and only all the ref fields
|
||||
// in the current generation that contain pointers to objects in younger
|
||||
// generations. Objects allocated since the last "save_marks" call are
|
||||
@ -724,7 +718,6 @@ class OneContigSpaceCardGeneration: public CardGeneration {
|
||||
// Iteration
|
||||
void object_iterate(ObjectClosure* blk);
|
||||
void space_iterate(SpaceClosure* blk, bool usedOnly = false);
|
||||
void object_iterate_since_last_GC(ObjectClosure* cl);
|
||||
|
||||
void younger_refs_iterate(OopsInGenClosure* blk);
|
||||
|
||||
|
@ -26,7 +26,6 @@
|
||||
#define SHARE_VM_MEMORY_HEAPINSPECTION_HPP
|
||||
|
||||
#include "memory/allocation.inline.hpp"
|
||||
#include "memory/klassInfoClosure.hpp"
|
||||
#include "oops/oop.inline.hpp"
|
||||
#include "oops/annotations.hpp"
|
||||
#include "utilities/macros.hpp"
|
||||
@ -204,6 +203,12 @@ class KlassInfoEntry: public CHeapObj<mtInternal> {
|
||||
const char* name() const;
|
||||
};
|
||||
|
||||
class KlassInfoClosure : public StackObj {
|
||||
public:
|
||||
// Called for each KlassInfoEntry.
|
||||
virtual void do_cinfo(KlassInfoEntry* cie) = 0;
|
||||
};
|
||||
|
||||
class KlassInfoBucket: public CHeapObj<mtInternal> {
|
||||
private:
|
||||
KlassInfoEntry* _list;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2013, 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
|
||||
@ -83,6 +83,10 @@ protected:
|
||||
Chunk *_chunk; // saved arena chunk
|
||||
char *_hwm, *_max;
|
||||
size_t _size_in_bytes;
|
||||
#ifdef ASSERT
|
||||
Thread* _thread;
|
||||
ResourceMark* _previous_resource_mark;
|
||||
#endif //ASSERT
|
||||
|
||||
void initialize(Thread *thread) {
|
||||
_area = thread->resource_area();
|
||||
@ -92,6 +96,11 @@ protected:
|
||||
_size_in_bytes = _area->size_in_bytes();
|
||||
debug_only(_area->_nesting++;)
|
||||
assert( _area->_nesting > 0, "must stack allocate RMs" );
|
||||
#ifdef ASSERT
|
||||
_thread = thread;
|
||||
_previous_resource_mark = thread->current_resource_mark();
|
||||
thread->set_current_resource_mark(this);
|
||||
#endif // ASSERT
|
||||
}
|
||||
public:
|
||||
|
||||
@ -111,6 +120,17 @@ protected:
|
||||
_size_in_bytes = r->_size_in_bytes;
|
||||
debug_only(_area->_nesting++;)
|
||||
assert( _area->_nesting > 0, "must stack allocate RMs" );
|
||||
#ifdef ASSERT
|
||||
Thread* thread = ThreadLocalStorage::thread();
|
||||
if (thread != NULL) {
|
||||
_thread = thread;
|
||||
_previous_resource_mark = thread->current_resource_mark();
|
||||
thread->set_current_resource_mark(this);
|
||||
} else {
|
||||
_thread = NULL;
|
||||
_previous_resource_mark = NULL;
|
||||
}
|
||||
#endif // ASSERT
|
||||
}
|
||||
|
||||
void reset_to_mark() {
|
||||
@ -137,6 +157,11 @@ protected:
|
||||
assert( _area->_nesting > 0, "must stack allocate RMs" );
|
||||
debug_only(_area->_nesting--;)
|
||||
reset_to_mark();
|
||||
#ifdef ASSERT
|
||||
if (_thread != NULL) {
|
||||
_thread->set_current_resource_mark(_previous_resource_mark);
|
||||
}
|
||||
#endif // ASSERT
|
||||
}
|
||||
|
||||
|
||||
|
@ -166,11 +166,6 @@ public:
|
||||
// Same as above, restricted to a memory region.
|
||||
virtual void oop_iterate(MemRegion mr, ExtendedOopClosure* cl) = 0;
|
||||
|
||||
// Iterate over all objects allocated since the last collection, calling
|
||||
// "cl->do_object" on each. The heap must have been initialized properly
|
||||
// to support this function, or else this call will fail.
|
||||
virtual void object_iterate_since_last_GC(ObjectClosure* cl) = 0;
|
||||
|
||||
// Iterate over all spaces in use in the heap, in an undefined order.
|
||||
virtual void space_iterate(SpaceClosure* cl) = 0;
|
||||
|
||||
|
@ -52,7 +52,6 @@
|
||||
#include "oops/oop.inline.hpp"
|
||||
#include "oops/typeArrayKlass.hpp"
|
||||
#include "prims/jvmtiRedefineClassesTrace.hpp"
|
||||
#include "runtime/aprofiler.hpp"
|
||||
#include "runtime/arguments.hpp"
|
||||
#include "runtime/deoptimization.hpp"
|
||||
#include "runtime/fprofiler.hpp"
|
||||
|
@ -71,7 +71,6 @@ Method* ArrayKlass::uncached_lookup_method(Symbol* name, Symbol* signature) cons
|
||||
}
|
||||
|
||||
ArrayKlass::ArrayKlass(Symbol* name) {
|
||||
set_alloc_size(0);
|
||||
set_name(name);
|
||||
|
||||
set_super(Universe::is_bootstrapping() ? (Klass*)NULL : SystemDictionary::Object_klass());
|
||||
@ -161,12 +160,6 @@ void ArrayKlass::array_klasses_do(void f(Klass* k)) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ArrayKlass::with_array_klasses_do(void f(Klass* k)) {
|
||||
array_klasses_do(f);
|
||||
}
|
||||
|
||||
|
||||
// GC support
|
||||
|
||||
void ArrayKlass::oops_do(OopClosure* cl) {
|
||||
|
@ -39,7 +39,6 @@ class ArrayKlass: public Klass {
|
||||
Klass* volatile _higher_dimension; // Refers the (n+1)'th-dimensional array (if present).
|
||||
Klass* volatile _lower_dimension; // Refers the (n-1)'th-dimensional array (if present).
|
||||
int _vtable_len; // size of vtable for this klass
|
||||
juint _alloc_size; // allocation profiling support
|
||||
oop _component_mirror; // component type, as a java/lang/Class
|
||||
|
||||
protected:
|
||||
@ -65,10 +64,6 @@ class ArrayKlass: public Klass {
|
||||
void set_lower_dimension(Klass* k) { _lower_dimension = k; }
|
||||
Klass** adr_lower_dimension() { return (Klass**)&this->_lower_dimension;}
|
||||
|
||||
// Allocation profiling support
|
||||
juint alloc_size() const { return _alloc_size; }
|
||||
void set_alloc_size(juint n) { _alloc_size = n; }
|
||||
|
||||
// offset of first element, including any padding for the sake of alignment
|
||||
int array_header_in_bytes() const { return layout_helper_header_size(layout_helper()); }
|
||||
int log2_element_size() const { return layout_helper_log2_element_size(layout_helper()); }
|
||||
@ -126,7 +121,6 @@ class ArrayKlass: public Klass {
|
||||
// Iterators
|
||||
void array_klasses_do(void f(Klass* k));
|
||||
void array_klasses_do(void f(Klass* k, TRAPS), TRAPS);
|
||||
void with_array_klasses_do(void f(Klass* k));
|
||||
|
||||
// GC support
|
||||
virtual void oops_do(OopClosure* cl);
|
||||
|
@ -140,8 +140,15 @@ class ConstantPoolCacheEntry VALUE_OBJ_CLASS_SPEC {
|
||||
_f1 = f1;
|
||||
}
|
||||
void release_set_f1(Metadata* f1);
|
||||
void set_f2(intx f2) { assert(_f2 == 0 || _f2 == f2, "illegal field change"); _f2 = f2; }
|
||||
void set_f2_as_vfinal_method(Method* f2) { assert(_f2 == 0 || _f2 == (intptr_t) f2, "illegal field change"); assert(is_vfinal(), "flags must be set"); _f2 = (intptr_t) f2; }
|
||||
void set_f2(intx f2) {
|
||||
intx existing_f2 = _f2; // read once
|
||||
assert(existing_f2 == 0 || existing_f2 == f2, "illegal field change");
|
||||
_f2 = f2;
|
||||
}
|
||||
void set_f2_as_vfinal_method(Method* f2) {
|
||||
assert(is_vfinal(), "flags must be set");
|
||||
set_f2((intx)f2);
|
||||
}
|
||||
int make_flags(TosState state, int option_bits, int field_index_or_method_params);
|
||||
void set_flags(intx flags) { _flags = flags; }
|
||||
bool init_flags_atomic(intx flags);
|
||||
|
@ -48,6 +48,7 @@
|
||||
#include "oops/symbol.hpp"
|
||||
#include "prims/jvmtiExport.hpp"
|
||||
#include "prims/jvmtiRedefineClassesTrace.hpp"
|
||||
#include "prims/jvmtiRedefineClasses.hpp"
|
||||
#include "prims/methodComparator.hpp"
|
||||
#include "runtime/fieldDescriptor.hpp"
|
||||
#include "runtime/handles.inline.hpp"
|
||||
@ -291,7 +292,7 @@ InstanceKlass::InstanceKlass(int vtable_len,
|
||||
set_initial_method_idnum(0);
|
||||
_dependencies = NULL;
|
||||
set_jvmti_cached_class_field_map(NULL);
|
||||
set_cached_class_file(NULL, 0);
|
||||
set_cached_class_file(NULL);
|
||||
set_initial_method_idnum(0);
|
||||
set_minor_version(0);
|
||||
set_major_version(0);
|
||||
@ -1321,12 +1322,6 @@ void InstanceKlass::array_klasses_do(void f(Klass* k)) {
|
||||
ArrayKlass::cast(array_klasses())->array_klasses_do(f);
|
||||
}
|
||||
|
||||
|
||||
void InstanceKlass::with_array_klasses_do(void f(Klass* k)) {
|
||||
f(this);
|
||||
array_klasses_do(f);
|
||||
}
|
||||
|
||||
#ifdef ASSERT
|
||||
static int linear_search(Array<Method*>* methods, Symbol* name, Symbol* signature) {
|
||||
int len = methods->length();
|
||||
@ -2363,10 +2358,9 @@ void InstanceKlass::release_C_heap_structures() {
|
||||
}
|
||||
|
||||
// deallocate the cached class file
|
||||
if (_cached_class_file_bytes != NULL) {
|
||||
os::free(_cached_class_file_bytes, mtClass);
|
||||
_cached_class_file_bytes = NULL;
|
||||
_cached_class_file_len = 0;
|
||||
if (_cached_class_file != NULL) {
|
||||
os::free(_cached_class_file, mtClass);
|
||||
_cached_class_file = NULL;
|
||||
}
|
||||
|
||||
// Decrement symbol reference counts associated with the unloaded class.
|
||||
@ -3536,6 +3530,14 @@ Method* InstanceKlass::method_with_idnum(int idnum) {
|
||||
return m;
|
||||
}
|
||||
|
||||
jint InstanceKlass::get_cached_class_file_len() {
|
||||
return VM_RedefineClasses::get_cached_class_file_len(_cached_class_file);
|
||||
}
|
||||
|
||||
unsigned char * InstanceKlass::get_cached_class_file_bytes() {
|
||||
return VM_RedefineClasses::get_cached_class_file_bytes(_cached_class_file);
|
||||
}
|
||||
|
||||
|
||||
// Construct a PreviousVersionNode entry for the array hung off
|
||||
// the InstanceKlass.
|
||||
|
@ -133,6 +133,8 @@ class OopMapBlock VALUE_OBJ_CLASS_SPEC {
|
||||
uint _count;
|
||||
};
|
||||
|
||||
struct JvmtiCachedClassFileData;
|
||||
|
||||
class InstanceKlass: public Klass {
|
||||
friend class VMStructs;
|
||||
friend class ClassFileParser;
|
||||
@ -249,8 +251,8 @@ class InstanceKlass: public Klass {
|
||||
// InstanceKlass. See PreviousVersionWalker below.
|
||||
GrowableArray<PreviousVersionNode *>* _previous_versions;
|
||||
// JVMTI fields can be moved to their own structure - see 6315920
|
||||
unsigned char * _cached_class_file_bytes; // JVMTI: cached class file, before retransformable agent modified it in CFLH
|
||||
jint _cached_class_file_len; // JVMTI: length of above
|
||||
// JVMTI: cached class file, before retransformable agent modified it in CFLH
|
||||
JvmtiCachedClassFileData* _cached_class_file;
|
||||
|
||||
volatile u2 _idnum_allocated_count; // JNI/JVMTI: increments with the addition of methods, old ids don't change
|
||||
|
||||
@ -615,11 +617,12 @@ class InstanceKlass: public Klass {
|
||||
static void purge_previous_versions(InstanceKlass* ik);
|
||||
|
||||
// JVMTI: Support for caching a class file before it is modified by an agent that can do retransformation
|
||||
void set_cached_class_file(unsigned char *class_file_bytes,
|
||||
jint class_file_len) { _cached_class_file_len = class_file_len;
|
||||
_cached_class_file_bytes = class_file_bytes; }
|
||||
jint get_cached_class_file_len() { return _cached_class_file_len; }
|
||||
unsigned char * get_cached_class_file_bytes() { return _cached_class_file_bytes; }
|
||||
void set_cached_class_file(JvmtiCachedClassFileData *data) {
|
||||
_cached_class_file = data;
|
||||
}
|
||||
JvmtiCachedClassFileData * get_cached_class_file() { return _cached_class_file; }
|
||||
jint get_cached_class_file_len();
|
||||
unsigned char * get_cached_class_file_bytes();
|
||||
|
||||
// JVMTI: Support for caching of field indices, types, and offsets
|
||||
void set_jvmti_cached_class_field_map(JvmtiCachedClassFieldMap* descriptor) {
|
||||
@ -794,7 +797,6 @@ class InstanceKlass: public Klass {
|
||||
void methods_do(void f(Method* method));
|
||||
void array_klasses_do(void f(Klass* k));
|
||||
void array_klasses_do(void f(Klass* k, TRAPS), TRAPS);
|
||||
void with_array_klasses_do(void f(Klass* k));
|
||||
bool super_types_do(SuperTypeClosure* blk);
|
||||
|
||||
// Casting from Klass*
|
||||
@ -874,10 +876,6 @@ class InstanceKlass: public Klass {
|
||||
}
|
||||
}
|
||||
|
||||
// Allocation profiling support
|
||||
juint alloc_size() const { return _alloc_count * size_helper(); }
|
||||
void set_alloc_size(juint n) {}
|
||||
|
||||
// Use this to return the size of an instance in heap words:
|
||||
int size_helper() const {
|
||||
return layout_helper_to_size_helper(layout_helper());
|
||||
|
@ -168,7 +168,6 @@ Klass::Klass() {
|
||||
set_subklass(NULL);
|
||||
set_next_sibling(NULL);
|
||||
set_next_link(NULL);
|
||||
set_alloc_count(0);
|
||||
TRACE_INIT_ID(this);
|
||||
|
||||
set_prototype_header(markOopDesc::prototype());
|
||||
@ -543,12 +542,6 @@ Klass* Klass::array_klass_impl(bool or_null, TRAPS) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
void Klass::with_array_klasses_do(void f(Klass* k)) {
|
||||
f(this);
|
||||
}
|
||||
|
||||
|
||||
oop Klass::class_loader() const { return class_loader_data()->class_loader(); }
|
||||
|
||||
const char* Klass::external_name() const {
|
||||
|
@ -79,7 +79,6 @@
|
||||
// [last_biased_lock_bulk_revocation_time] (64 bits)
|
||||
// [prototype_header]
|
||||
// [biased_lock_revocation_count]
|
||||
// [alloc_count ]
|
||||
// [_modified_oops]
|
||||
// [_accumulated_modified_oops]
|
||||
// [trace_id]
|
||||
@ -171,8 +170,6 @@ class Klass : public Metadata {
|
||||
markOop _prototype_header; // Used when biased locking is both enabled and disabled for this type
|
||||
jint _biased_lock_revocation_count;
|
||||
|
||||
juint _alloc_count; // allocation profiling support
|
||||
|
||||
TRACE_DEFINE_KLASS_TRACE_ID;
|
||||
|
||||
// Remembered sets support for the oops in the klasses.
|
||||
@ -290,11 +287,6 @@ class Klass : public Metadata {
|
||||
void set_next_sibling(Klass* s);
|
||||
|
||||
public:
|
||||
// Allocation profiling support
|
||||
juint alloc_count() const { return _alloc_count; }
|
||||
void set_alloc_count(juint n) { _alloc_count = n; }
|
||||
virtual juint alloc_size() const = 0;
|
||||
virtual void set_alloc_size(juint n) = 0;
|
||||
|
||||
// Compiler support
|
||||
static ByteSize super_offset() { return in_ByteSize(offset_of(Klass, _super)); }
|
||||
@ -677,7 +669,6 @@ class Klass : public Metadata {
|
||||
#endif // INCLUDE_ALL_GCS
|
||||
|
||||
virtual void array_klasses_do(void f(Klass* k)) {}
|
||||
virtual void with_array_klasses_do(void f(Klass* k));
|
||||
|
||||
// Return self, except for abstract classes with exactly 1
|
||||
// implementor. Then return the 1 concrete implementation.
|
||||
|
@ -1163,6 +1163,7 @@ methodHandle Method::clone_with_new_data(methodHandle m, u_char* new_code, int n
|
||||
newm->constMethod()->set_constMethod_size(new_const_method_size);
|
||||
newm->set_method_size(new_method_size);
|
||||
assert(newm->code_size() == new_code_length, "check");
|
||||
assert(newm->method_parameters_length() == method_parameters_len, "check");
|
||||
assert(newm->checked_exceptions_length() == checked_exceptions_len, "check");
|
||||
assert(newm->exception_table_length() == exception_table_len, "check");
|
||||
assert(newm->localvariable_table_length() == localvariable_len, "check");
|
||||
@ -1174,6 +1175,12 @@ methodHandle Method::clone_with_new_data(methodHandle m, u_char* new_code, int n
|
||||
new_compressed_linenumber_table,
|
||||
new_compressed_linenumber_size);
|
||||
}
|
||||
// Copy method_parameters
|
||||
if (method_parameters_len > 0) {
|
||||
memcpy(newm->method_parameters_start(),
|
||||
m->method_parameters_start(),
|
||||
method_parameters_len * sizeof(MethodParametersElement));
|
||||
}
|
||||
// Copy checked_exceptions
|
||||
if (checked_exceptions_len > 0) {
|
||||
memcpy(newm->checked_exceptions_start(),
|
||||
|
@ -297,15 +297,6 @@ bool InlineTree::should_not_inline(ciMethod *callee_method,
|
||||
}
|
||||
}
|
||||
|
||||
if (UseStringCache) {
|
||||
// Do not inline StringCache::profile() method used only at the beginning.
|
||||
if (callee_method->name() == ciSymbol::profile_name() &&
|
||||
callee_method->holder()->name() == ciSymbol::java_lang_StringCache()) {
|
||||
set_msg("profiling method");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// use frequency-based objections only for non-trivial methods
|
||||
if (callee_method->code_size() <= MaxTrivialSize) {
|
||||
return false;
|
||||
|
@ -2305,26 +2305,26 @@ void Matcher::validate_null_checks( ) {
|
||||
// atomic instruction acting as a store_load barrier without any
|
||||
// intervening volatile load, and thus we don't need a barrier here.
|
||||
// We retain the Node to act as a compiler ordering barrier.
|
||||
bool Matcher::post_store_load_barrier(const Node *vmb) {
|
||||
Compile *C = Compile::current();
|
||||
assert( vmb->is_MemBar(), "" );
|
||||
assert( vmb->Opcode() != Op_MemBarAcquire, "" );
|
||||
const MemBarNode *mem = (const MemBarNode*)vmb;
|
||||
bool Matcher::post_store_load_barrier(const Node* vmb) {
|
||||
Compile* C = Compile::current();
|
||||
assert(vmb->is_MemBar(), "");
|
||||
assert(vmb->Opcode() != Op_MemBarAcquire, "");
|
||||
const MemBarNode* membar = vmb->as_MemBar();
|
||||
|
||||
// Get the Proj node, ctrl, that can be used to iterate forward
|
||||
Node *ctrl = NULL;
|
||||
DUIterator_Fast imax, i = mem->fast_outs(imax);
|
||||
while( true ) {
|
||||
ctrl = mem->fast_out(i); // Throw out-of-bounds if proj not found
|
||||
assert( ctrl->is_Proj(), "only projections here" );
|
||||
ProjNode *proj = (ProjNode*)ctrl;
|
||||
if( proj->_con == TypeFunc::Control &&
|
||||
!C->node_arena()->contains(ctrl) ) // Unmatched old-space only
|
||||
// Get the Ideal Proj node, ctrl, that can be used to iterate forward
|
||||
Node* ctrl = NULL;
|
||||
for (DUIterator_Fast imax, i = membar->fast_outs(imax); i < imax; i++) {
|
||||
Node* p = membar->fast_out(i);
|
||||
assert(p->is_Proj(), "only projections here");
|
||||
if ((p->as_Proj()->_con == TypeFunc::Control) &&
|
||||
!C->node_arena()->contains(p)) { // Unmatched old-space only
|
||||
ctrl = p;
|
||||
break;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
assert((ctrl != NULL), "missing control projection");
|
||||
|
||||
for( DUIterator_Fast jmax, j = ctrl->fast_outs(jmax); j < jmax; j++ ) {
|
||||
for (DUIterator_Fast jmax, j = ctrl->fast_outs(jmax); j < jmax; j++) {
|
||||
Node *x = ctrl->fast_out(j);
|
||||
int xop = x->Opcode();
|
||||
|
||||
@ -2336,37 +2336,36 @@ bool Matcher::post_store_load_barrier(const Node *vmb) {
|
||||
// that a monitor exit operation contains a serializing instruction.
|
||||
|
||||
if (xop == Op_MemBarVolatile ||
|
||||
xop == Op_FastLock ||
|
||||
xop == Op_CompareAndSwapL ||
|
||||
xop == Op_CompareAndSwapP ||
|
||||
xop == Op_CompareAndSwapN ||
|
||||
xop == Op_CompareAndSwapI)
|
||||
xop == Op_CompareAndSwapI) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Op_FastLock previously appeared in the Op_* list above.
|
||||
// With biased locking we're no longer guaranteed that a monitor
|
||||
// enter operation contains a serializing instruction.
|
||||
if ((xop == Op_FastLock) && !UseBiasedLocking) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (x->is_MemBar()) {
|
||||
// We must retain this membar if there is an upcoming volatile
|
||||
// load, which will be preceded by acquire membar.
|
||||
if (xop == Op_MemBarAcquire)
|
||||
// load, which will be followed by acquire membar.
|
||||
if (xop == Op_MemBarAcquire) {
|
||||
return false;
|
||||
// For other kinds of barriers, check by pretending we
|
||||
// are them, and seeing if we can be removed.
|
||||
else
|
||||
return post_store_load_barrier((const MemBarNode*)x);
|
||||
} else {
|
||||
// For other kinds of barriers, check by pretending we
|
||||
// are them, and seeing if we can be removed.
|
||||
return post_store_load_barrier(x->as_MemBar());
|
||||
}
|
||||
}
|
||||
|
||||
// Delicate code to detect case of an upcoming fastlock block
|
||||
if( x->is_If() && x->req() > 1 &&
|
||||
!C->node_arena()->contains(x) ) { // Unmatched old-space only
|
||||
Node *iff = x;
|
||||
Node *bol = iff->in(1);
|
||||
// The iff might be some random subclass of If or bol might be Con-Top
|
||||
if (!bol->is_Bool()) return false;
|
||||
assert( bol->req() > 1, "" );
|
||||
return (bol->in(1)->Opcode() == Op_FastUnlock);
|
||||
}
|
||||
// probably not necessary to check for these
|
||||
if (x->is_Call() || x->is_SafePoint() || x->is_block_proj())
|
||||
if (x->is_Call() || x->is_SafePoint() || x->is_block_proj()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user