Merge
This commit is contained in:
commit
e1b2c1c442
1
.hgtags
1
.hgtags
@ -25,3 +25,4 @@ caf58ffa084568990cbb3441f9ae188e36b31770 jdk7-b42
|
||||
1bf51a4c2627c2f0e0cbcc2cf0421bdb37f1f2b2 jdk7-b48
|
||||
6b84b04a80afe23262377c60913eebfc898f14c4 jdk7-b49
|
||||
5da0e6b9f4f18ef483c977337214b12ee0e1fc8f jdk7-b50
|
||||
a25c5ec5e40e07733d1ff9898a0abe36159288ff jdk7-b51
|
||||
|
@ -25,3 +25,4 @@ d7744e86dedc21a8ecf6bdb73eb191b8eaf5b0da jdk7-b47
|
||||
4ae9f4bfdb98f65bd957e3fe72471b320150b38e jdk7-b48
|
||||
aee93a8992d2389121eb610c00a86196f3e2b9b0 jdk7-b49
|
||||
5111e13e44e542fe945b47ab154546daec36737d jdk7-b50
|
||||
0f0189d55ce4a1f7840da7582ac7d970b3b7ab15 jdk7-b51
|
||||
|
@ -25,3 +25,4 @@ ccd6a16502e0650d91d85c4b86be05cbcd461a87 jdk7-b42
|
||||
0be222241fd405e48915647facfaa176621b39b9 jdk7-b48
|
||||
d70978bc64bc7a04be7797ab0dcd9b7b1b3a6bff jdk7-b49
|
||||
0edbd0074b02b42b2b83cc47cb391d4869b7a8ec jdk7-b50
|
||||
3eb8f1047a7402a9a79937d1c39560e931e91da2 jdk7-b51
|
||||
|
@ -25,3 +25,4 @@ fcb923bad68e2b10380a030ea83a723f4dc3d4d6 jdk7-b47
|
||||
bcb33806d186561c781992e5f4d8a90bb033f9f0 jdk7-b48
|
||||
8b22ccb5aba2c6c11bddf6488a7bb7ef5b4bf2be jdk7-b49
|
||||
dae503d9f04c1a11e182dbf7f770509c28dc0609 jdk7-b50
|
||||
2581d90c6c9b2012da930eb4742add94a03069a0 jdk7-b51
|
||||
|
@ -46,12 +46,18 @@ public class StubRoutines {
|
||||
Type type = db.lookupType("StubRoutines");
|
||||
|
||||
callStubReturnAddressField = type.getAddressField("_call_stub_return_address");
|
||||
// Only some platforms have specif return from compiled to call_stub
|
||||
// Only some platforms have specific return from compiled to call_stub
|
||||
try {
|
||||
callStubCompiledReturnAddressField = type.getAddressField("_call_stub_compiled_return");
|
||||
type = db.lookupType("StubRoutines::x86");
|
||||
if (type != null) {
|
||||
callStubCompiledReturnAddressField = type.getAddressField("_call_stub_compiled_return");
|
||||
}
|
||||
} catch (RuntimeException re) {
|
||||
callStubCompiledReturnAddressField = null;
|
||||
}
|
||||
if (callStubCompiledReturnAddressField == null && VM.getVM().getCPU().equals("x86")) {
|
||||
throw new InternalError("Missing definition for _call_stub_compiled_return");
|
||||
}
|
||||
}
|
||||
|
||||
public StubRoutines() {
|
||||
|
@ -342,11 +342,14 @@ public class VM {
|
||||
throw new RuntimeException("Attempt to initialize VM twice");
|
||||
}
|
||||
soleInstance = new VM(db, debugger, debugger.getMachineDescription().isBigEndian());
|
||||
|
||||
debugger.putHeapConst(soleInstance.getHeapOopSize(), Universe.getNarrowOopBase(),
|
||||
Universe.getNarrowOopShift());
|
||||
|
||||
for (Iterator iter = vmInitializedObservers.iterator(); iter.hasNext(); ) {
|
||||
((Observer) iter.next()).update(null, null);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** This is used by the debugging system */
|
||||
|
@ -35,7 +35,7 @@ HOTSPOT_VM_COPYRIGHT=Copyright 2008
|
||||
|
||||
HS_MAJOR_VER=15
|
||||
HS_MINOR_VER=0
|
||||
HS_BUILD_NUMBER=03
|
||||
HS_BUILD_NUMBER=04
|
||||
|
||||
JDK_MAJOR_VER=1
|
||||
JDK_MINOR_VER=7
|
||||
|
@ -52,6 +52,19 @@ CAT="$MKS_HOME/cat.exe"
|
||||
RM="$MKS_HOME/rm.exe"
|
||||
DUMPBIN="link.exe /dump"
|
||||
|
||||
# When called from IDE the first param should contain the link version, otherwise may be nill
|
||||
if [ "x$1" != "x" ]; then
|
||||
LINK_VER="$1"
|
||||
fi
|
||||
|
||||
if [ "x$LINK_VER" != "x800" -a "x$LINK_VER" != "x900" ]; then
|
||||
$DUMPBIN /symbols *.obj | "$GREP" "??_7.*@@6B@" | "$AWK" '{print $7}' | "$SORT" | "$UNIQ" > vm2.def
|
||||
else
|
||||
# Can't use pipes when calling cl.exe or link.exe from IDE. Using transit file vm3.def
|
||||
$DUMPBIN /OUT:vm3.def /symbols *.obj
|
||||
"$CAT" vm3.def | "$GREP" "??_7.*@@6B@" | "$AWK" '{print $7}' | "$SORT" | "$UNIQ" > vm2.def
|
||||
"$RM" -f vm3.def
|
||||
fi
|
||||
|
||||
"$CAT" vm1.def vm2.def > vm.def
|
||||
"$RM" -f vm1.def vm2.def
|
||||
|
@ -72,12 +72,20 @@ REM figure out MSC version
|
||||
for /F %%i in ('sh %HotSpotWorkSpace%/make/windows/get_msc_ver.sh') do set %%i
|
||||
|
||||
echo **************************************************************
|
||||
set ProjectFile=vm.vcproj
|
||||
if "%MSC_VER%" == "1200" (
|
||||
set ProjectFile=vm.dsp
|
||||
echo Will generate VC6 project {unsupported}
|
||||
) else (
|
||||
set ProjectFile=vm.vcproj
|
||||
echo Will generate VC7 project
|
||||
if "%MSC_VER%" == "1400" (
|
||||
echo Will generate VC8 {Visual Studio 2005}
|
||||
) else (
|
||||
if "%MSC_VER%" == "1500" (
|
||||
echo Will generate VC9 {Visual Studio 2008}
|
||||
) else (
|
||||
echo Will generate VC7 project {Visual Studio 2003 .NET}
|
||||
)
|
||||
)
|
||||
)
|
||||
echo %ProjectFile%
|
||||
echo **************************************************************
|
||||
|
@ -46,6 +46,7 @@ ADLCFLAGS=-q -T -D_LP64
|
||||
ADLCFLAGS=-q -T -U_LP64
|
||||
!endif
|
||||
|
||||
CPP_FLAGS=$(CPP_FLAGS) /D _CRT_SECURE_NO_WARNINGS /D _CRT_SECURE_NO_DEPRECATE
|
||||
|
||||
CPP_INCLUDE_DIRS=\
|
||||
/I "..\generated" \
|
||||
|
@ -170,8 +170,6 @@ LINK_FLAGS = /manifest $(LINK_FLAGS) $(BUFFEROVERFLOWLIB)
|
||||
# Manifest Tool - used in VS2005 and later to adjust manifests stored
|
||||
# as resources inside build artifacts.
|
||||
MT=mt.exe
|
||||
# VS2005 and later restricts the use of certain libc functions without this
|
||||
CPP_FLAGS=$(CPP_FLAGS) /D _CRT_SECURE_NO_DEPRECATE
|
||||
!endif
|
||||
|
||||
!if "$(COMPILER_NAME)" == "VS2008"
|
||||
@ -183,8 +181,6 @@ LINK_FLAGS = /manifest $(LINK_FLAGS)
|
||||
# Manifest Tool - used in VS2005 and later to adjust manifests stored
|
||||
# as resources inside build artifacts.
|
||||
MT=mt.exe
|
||||
# VS2005 and later restricts the use of certain libc functions without this
|
||||
CPP_FLAGS=$(CPP_FLAGS) /D _CRT_SECURE_NO_DEPRECATE
|
||||
!endif
|
||||
|
||||
# Compile for space above time.
|
||||
|
@ -48,6 +48,8 @@ MakeDepsSources=\
|
||||
$(WorkSpace)\src\share\tools\MakeDeps\WinGammaPlatform.java \
|
||||
$(WorkSpace)\src\share\tools\MakeDeps\WinGammaPlatformVC6.java \
|
||||
$(WorkSpace)\src\share\tools\MakeDeps\WinGammaPlatformVC7.java \
|
||||
$(WorkSpace)\src\share\tools\MakeDeps\WinGammaPlatformVC8.java \
|
||||
$(WorkSpace)\src\share\tools\MakeDeps\WinGammaPlatformVC9.java \
|
||||
$(WorkSpace)\src\share\tools\MakeDeps\Util.java \
|
||||
$(WorkSpace)\src\share\tools\MakeDeps\BuildConfig.java \
|
||||
$(WorkSpace)\src\share\tools\MakeDeps\ArgsParser.java
|
||||
@ -121,7 +123,7 @@ MakeDepsIDEOptions=\
|
||||
-additionalFile includeDB_gc_shared \
|
||||
-additionalFile includeDB_gc_serial \
|
||||
-additionalGeneratedFile $(HOTSPOTBUILDSPACE)\%f\%b vm.def \
|
||||
-prelink "" "Generating vm.def..." "cd $(HOTSPOTBUILDSPACE)\%f\%b $(HOTSPOTMKSHOME)\sh $(HOTSPOTWORKSPACE)\make\windows\build_vm_def.sh" \
|
||||
-prelink "" "Generating vm.def..." "cd $(HOTSPOTBUILDSPACE)\%f\%b set HOTSPOTMKSHOME=$(HOTSPOTMKSHOME) $(HOTSPOTMKSHOME)\sh $(HOTSPOTWORKSPACE)\make\windows\build_vm_def.sh $(LINK_VER)" \
|
||||
$(MakeDepsIncludesPRIVATE)
|
||||
|
||||
# Add in build-specific options
|
||||
|
@ -42,10 +42,23 @@ COMPILE_RMIC=rmic
|
||||
BOOT_JAVA_HOME=
|
||||
!endif
|
||||
|
||||
ProjectFile=vm.vcproj
|
||||
|
||||
!if "$(MSC_VER)" == "1200"
|
||||
|
||||
VcVersion=VC6
|
||||
ProjectFile=vm.dsp
|
||||
|
||||
!elseif "$(MSC_VER)" == "1400"
|
||||
|
||||
VcVersion=VC8
|
||||
|
||||
!elseif "$(MSC_VER)" == "1500"
|
||||
|
||||
VcVersion=VC9
|
||||
|
||||
!else
|
||||
|
||||
VcVersion=VC7
|
||||
ProjectFile=vm.vcproj
|
||||
|
||||
!endif
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -2615,12 +2615,12 @@ void MacroAssembler::cas_under_lock(Register top_ptr_reg, Register top_reg, Regi
|
||||
}
|
||||
}
|
||||
|
||||
RegisterConstant MacroAssembler::delayed_value(intptr_t* delayed_value_addr,
|
||||
Register tmp,
|
||||
int offset) {
|
||||
RegisterOrConstant MacroAssembler::delayed_value_impl(intptr_t* delayed_value_addr,
|
||||
Register tmp,
|
||||
int offset) {
|
||||
intptr_t value = *delayed_value_addr;
|
||||
if (value != 0)
|
||||
return RegisterConstant(value + offset);
|
||||
return RegisterOrConstant(value + offset);
|
||||
|
||||
// load indirectly to solve generation ordering problem
|
||||
Address a(tmp, (address) delayed_value_addr);
|
||||
@ -2634,11 +2634,11 @@ RegisterConstant MacroAssembler::delayed_value(intptr_t* delayed_value_addr,
|
||||
if (offset != 0)
|
||||
add(tmp, offset, tmp);
|
||||
|
||||
return RegisterConstant(tmp);
|
||||
return RegisterOrConstant(tmp);
|
||||
}
|
||||
|
||||
|
||||
void MacroAssembler::regcon_inc_ptr( RegisterConstant& dest, RegisterConstant src, Register temp ) {
|
||||
void MacroAssembler::regcon_inc_ptr( RegisterOrConstant& dest, RegisterOrConstant src, Register temp ) {
|
||||
assert(dest.register_or_noreg() != G0, "lost side effect");
|
||||
if ((src.is_constant() && src.as_constant() == 0) ||
|
||||
(src.is_register() && src.as_register() == G0)) {
|
||||
@ -2647,15 +2647,15 @@ void MacroAssembler::regcon_inc_ptr( RegisterConstant& dest, RegisterConstant sr
|
||||
add(dest.as_register(), ensure_rs2(src, temp), dest.as_register());
|
||||
} else if (src.is_constant()) {
|
||||
intptr_t res = dest.as_constant() + src.as_constant();
|
||||
dest = RegisterConstant(res); // side effect seen by caller
|
||||
dest = RegisterOrConstant(res); // side effect seen by caller
|
||||
} else {
|
||||
assert(temp != noreg, "cannot handle constant += register");
|
||||
add(src.as_register(), ensure_rs2(dest, temp), temp);
|
||||
dest = RegisterConstant(temp); // side effect seen by caller
|
||||
dest = RegisterOrConstant(temp); // side effect seen by caller
|
||||
}
|
||||
}
|
||||
|
||||
void MacroAssembler::regcon_sll_ptr( RegisterConstant& dest, RegisterConstant src, Register temp ) {
|
||||
void MacroAssembler::regcon_sll_ptr( RegisterOrConstant& dest, RegisterOrConstant src, Register temp ) {
|
||||
assert(dest.register_or_noreg() != G0, "lost side effect");
|
||||
if (!is_simm13(src.constant_or_zero()))
|
||||
src = (src.as_constant() & 0xFF);
|
||||
@ -2666,12 +2666,12 @@ void MacroAssembler::regcon_sll_ptr( RegisterConstant& dest, RegisterConstant sr
|
||||
sll_ptr(dest.as_register(), src, dest.as_register());
|
||||
} else if (src.is_constant()) {
|
||||
intptr_t res = dest.as_constant() << src.as_constant();
|
||||
dest = RegisterConstant(res); // side effect seen by caller
|
||||
dest = RegisterOrConstant(res); // side effect seen by caller
|
||||
} else {
|
||||
assert(temp != noreg, "cannot handle constant <<= register");
|
||||
set(dest.as_constant(), temp);
|
||||
sll_ptr(temp, src, temp);
|
||||
dest = RegisterConstant(temp); // side effect seen by caller
|
||||
dest = RegisterOrConstant(temp); // side effect seen by caller
|
||||
}
|
||||
}
|
||||
|
||||
@ -2683,7 +2683,7 @@ void MacroAssembler::regcon_sll_ptr( RegisterConstant& dest, RegisterConstant sr
|
||||
// On failure, execution transfers to the given label.
|
||||
void MacroAssembler::lookup_interface_method(Register recv_klass,
|
||||
Register intf_klass,
|
||||
RegisterConstant itable_index,
|
||||
RegisterOrConstant itable_index,
|
||||
Register method_result,
|
||||
Register scan_temp,
|
||||
Register sethi_temp,
|
||||
@ -2720,7 +2720,7 @@ void MacroAssembler::lookup_interface_method(Register recv_klass,
|
||||
add(recv_klass, scan_temp, scan_temp);
|
||||
|
||||
// Adjust recv_klass by scaled itable_index, so we can free itable_index.
|
||||
RegisterConstant itable_offset = itable_index;
|
||||
RegisterOrConstant itable_offset = itable_index;
|
||||
regcon_sll_ptr(itable_offset, exact_log2(itableMethodEntry::size() * wordSize));
|
||||
regcon_inc_ptr(itable_offset, itableMethodEntry::method_offset_in_bytes());
|
||||
add(recv_klass, ensure_rs2(itable_offset, sethi_temp), recv_klass);
|
||||
@ -2805,7 +2805,7 @@ void MacroAssembler::check_klass_subtype_fast_path(Register sub_klass,
|
||||
Label* L_success,
|
||||
Label* L_failure,
|
||||
Label* L_slow_path,
|
||||
RegisterConstant super_check_offset,
|
||||
RegisterOrConstant super_check_offset,
|
||||
Register instanceof_hack) {
|
||||
int sc_offset = (klassOopDesc::header_size() * HeapWordSize +
|
||||
Klass::secondary_super_cache_offset_in_bytes());
|
||||
@ -2867,7 +2867,7 @@ void MacroAssembler::check_klass_subtype_fast_path(Register sub_klass,
|
||||
if (must_load_sco) {
|
||||
// The super check offset is always positive...
|
||||
lduw(super_klass, sco_offset, temp2_reg);
|
||||
super_check_offset = RegisterConstant(temp2_reg);
|
||||
super_check_offset = RegisterOrConstant(temp2_reg);
|
||||
}
|
||||
ld_ptr(sub_klass, super_check_offset, temp_reg);
|
||||
cmp(super_klass, temp_reg);
|
||||
@ -4465,7 +4465,7 @@ void MacroAssembler::card_write_barrier_post(Register store_addr, Register new_v
|
||||
}
|
||||
|
||||
// Loading values by size and signed-ness
|
||||
void MacroAssembler::load_sized_value(Register s1, RegisterConstant s2, Register d,
|
||||
void MacroAssembler::load_sized_value(Register s1, RegisterOrConstant s2, Register d,
|
||||
int size_in_bytes, bool is_signed) {
|
||||
switch (size_in_bytes ^ (is_signed ? -1 : 0)) {
|
||||
case ~8: // fall through:
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -1088,8 +1088,8 @@ public:
|
||||
inline void add( Register s1, Register s2, Register d );
|
||||
inline void add( Register s1, int simm13a, Register d, relocInfo::relocType rtype = relocInfo::none);
|
||||
inline void add( Register s1, int simm13a, Register d, RelocationHolder const& rspec);
|
||||
inline void add( Register s1, RegisterConstant s2, Register d, int offset = 0);
|
||||
inline void add( const Address& a, Register d, int offset = 0);
|
||||
inline void add( Register s1, RegisterOrConstant s2, Register d, int offset = 0);
|
||||
inline void add( const Address& a, Register d, int offset = 0);
|
||||
|
||||
void addcc( Register s1, Register s2, Register d ) { emit_long( op(arith_op) | rd(d) | op3(add_op3 | cc_bit_op3) | rs1(s1) | rs2(s2) ); }
|
||||
void addcc( Register s1, int simm13a, Register d ) { emit_long( op(arith_op) | rd(d) | op3(add_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
|
||||
@ -1305,15 +1305,15 @@ public:
|
||||
inline void ld( const Address& a, Register d, int offset = 0 );
|
||||
inline void ldd( const Address& a, Register d, int offset = 0 );
|
||||
|
||||
inline void ldub( Register s1, RegisterConstant s2, Register d );
|
||||
inline void ldsb( Register s1, RegisterConstant s2, Register d );
|
||||
inline void lduh( Register s1, RegisterConstant s2, Register d );
|
||||
inline void ldsh( Register s1, RegisterConstant s2, Register d );
|
||||
inline void lduw( Register s1, RegisterConstant s2, Register d );
|
||||
inline void ldsw( Register s1, RegisterConstant s2, Register d );
|
||||
inline void ldx( Register s1, RegisterConstant s2, Register d );
|
||||
inline void ld( Register s1, RegisterConstant s2, Register d );
|
||||
inline void ldd( Register s1, RegisterConstant s2, Register d );
|
||||
inline void ldub( Register s1, RegisterOrConstant s2, Register d );
|
||||
inline void ldsb( Register s1, RegisterOrConstant s2, Register d );
|
||||
inline void lduh( Register s1, RegisterOrConstant s2, Register d );
|
||||
inline void ldsh( Register s1, RegisterOrConstant s2, Register d );
|
||||
inline void lduw( Register s1, RegisterOrConstant s2, Register d );
|
||||
inline void ldsw( Register s1, RegisterOrConstant s2, Register d );
|
||||
inline void ldx( Register s1, RegisterOrConstant s2, Register d );
|
||||
inline void ld( Register s1, RegisterOrConstant s2, Register d );
|
||||
inline void ldd( Register s1, RegisterOrConstant s2, Register d );
|
||||
|
||||
// pp 177
|
||||
|
||||
@ -1535,12 +1535,12 @@ public:
|
||||
inline void st( Register d, const Address& a, int offset = 0 );
|
||||
inline void std( Register d, const Address& a, int offset = 0 );
|
||||
|
||||
inline void stb( Register d, Register s1, RegisterConstant s2 );
|
||||
inline void sth( Register d, Register s1, RegisterConstant s2 );
|
||||
inline void stw( Register d, Register s1, RegisterConstant s2 );
|
||||
inline void stx( Register d, Register s1, RegisterConstant s2 );
|
||||
inline void std( Register d, Register s1, RegisterConstant s2 );
|
||||
inline void st( Register d, Register s1, RegisterConstant s2 );
|
||||
inline void stb( Register d, Register s1, RegisterOrConstant s2 );
|
||||
inline void sth( Register d, Register s1, RegisterOrConstant s2 );
|
||||
inline void stw( Register d, Register s1, RegisterOrConstant s2 );
|
||||
inline void stx( Register d, Register s1, RegisterOrConstant s2 );
|
||||
inline void std( Register d, Register s1, RegisterOrConstant s2 );
|
||||
inline void st( Register d, Register s1, RegisterOrConstant s2 );
|
||||
|
||||
// pp 177
|
||||
|
||||
@ -1859,7 +1859,7 @@ class MacroAssembler: public Assembler {
|
||||
// Functions for isolating 64 bit shifts for LP64
|
||||
inline void sll_ptr( Register s1, Register s2, Register d );
|
||||
inline void sll_ptr( Register s1, int imm6a, Register d );
|
||||
inline void sll_ptr( Register s1, RegisterConstant s2, Register d );
|
||||
inline void sll_ptr( Register s1, RegisterOrConstant s2, Register d );
|
||||
inline void srl_ptr( Register s1, Register s2, Register d );
|
||||
inline void srl_ptr( Register s1, int imm6a, Register d );
|
||||
|
||||
@ -1965,26 +1965,26 @@ class MacroAssembler: public Assembler {
|
||||
// st_ptr will perform st for 32 bit VM's and stx for 64 bit VM's
|
||||
inline void ld_ptr( Register s1, Register s2, Register d );
|
||||
inline void ld_ptr( Register s1, int simm13a, Register d);
|
||||
inline void ld_ptr( Register s1, RegisterConstant s2, Register d );
|
||||
inline void ld_ptr( Register s1, RegisterOrConstant s2, Register d );
|
||||
inline void ld_ptr( const Address& a, Register d, int offset = 0 );
|
||||
inline void st_ptr( Register d, Register s1, Register s2 );
|
||||
inline void st_ptr( Register d, Register s1, int simm13a);
|
||||
inline void st_ptr( Register d, Register s1, RegisterConstant s2 );
|
||||
inline void st_ptr( Register d, Register s1, RegisterOrConstant s2 );
|
||||
inline void st_ptr( Register d, const Address& a, int offset = 0 );
|
||||
|
||||
// ld_long will perform ld for 32 bit VM's and ldx for 64 bit VM's
|
||||
// st_long will perform st for 32 bit VM's and stx for 64 bit VM's
|
||||
inline void ld_long( Register s1, Register s2, Register d );
|
||||
inline void ld_long( Register s1, int simm13a, Register d );
|
||||
inline void ld_long( Register s1, RegisterConstant s2, Register d );
|
||||
inline void ld_long( Register s1, RegisterOrConstant s2, Register d );
|
||||
inline void ld_long( const Address& a, Register d, int offset = 0 );
|
||||
inline void st_long( Register d, Register s1, Register s2 );
|
||||
inline void st_long( Register d, Register s1, int simm13a );
|
||||
inline void st_long( Register d, Register s1, RegisterConstant s2 );
|
||||
inline void st_long( Register d, Register s1, RegisterOrConstant s2 );
|
||||
inline void st_long( Register d, const Address& a, int offset = 0 );
|
||||
|
||||
// Loading values by size and signed-ness
|
||||
void load_sized_value(Register s1, RegisterConstant s2, Register d,
|
||||
void load_sized_value(Register s1, RegisterOrConstant s2, Register d,
|
||||
int size_in_bytes, bool is_signed);
|
||||
|
||||
// Helpers for address formation.
|
||||
@ -1994,11 +1994,11 @@ class MacroAssembler: public Assembler {
|
||||
// is required, and becomes the result.
|
||||
// If dest is a register and src is a non-simm13 constant,
|
||||
// the temp argument is required, and is used to materialize the constant.
|
||||
void regcon_inc_ptr( RegisterConstant& dest, RegisterConstant src,
|
||||
void regcon_inc_ptr( RegisterOrConstant& dest, RegisterOrConstant src,
|
||||
Register temp = noreg );
|
||||
void regcon_sll_ptr( RegisterConstant& dest, RegisterConstant src,
|
||||
void regcon_sll_ptr( RegisterOrConstant& dest, RegisterOrConstant src,
|
||||
Register temp = noreg );
|
||||
RegisterConstant ensure_rs2(RegisterConstant rs2, Register sethi_temp) {
|
||||
RegisterOrConstant ensure_rs2(RegisterOrConstant rs2, Register sethi_temp) {
|
||||
guarantee(sethi_temp != noreg, "constant offset overflow");
|
||||
if (is_simm13(rs2.constant_or_zero()))
|
||||
return rs2; // register or short constant
|
||||
@ -2322,7 +2322,7 @@ class MacroAssembler: public Assembler {
|
||||
// interface method calling
|
||||
void lookup_interface_method(Register recv_klass,
|
||||
Register intf_klass,
|
||||
RegisterConstant itable_index,
|
||||
RegisterOrConstant itable_index,
|
||||
Register method_result,
|
||||
Register temp_reg, Register temp2_reg,
|
||||
Label& no_such_interface);
|
||||
@ -2341,7 +2341,7 @@ class MacroAssembler: public Assembler {
|
||||
Label* L_success,
|
||||
Label* L_failure,
|
||||
Label* L_slow_path,
|
||||
RegisterConstant super_check_offset = RegisterConstant(-1),
|
||||
RegisterOrConstant super_check_offset = RegisterOrConstant(-1),
|
||||
Register instanceof_hack = noreg);
|
||||
|
||||
// The rest of the type check; must be wired to a corresponding fast path.
|
||||
@ -2381,7 +2381,7 @@ class MacroAssembler: public Assembler {
|
||||
// stack overflow + shadow pages. Clobbers tsp and scratch registers.
|
||||
void bang_stack_size(Register Rsize, Register Rtsp, Register Rscratch);
|
||||
|
||||
virtual RegisterConstant delayed_value(intptr_t* delayed_value_addr, Register tmp, int offset);
|
||||
virtual RegisterOrConstant delayed_value_impl(intptr_t* delayed_value_addr, Register tmp, int offset);
|
||||
|
||||
void verify_tlab();
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 1997-2006 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -143,45 +143,45 @@ inline void Assembler::ld( Register s1, Register s2, Register d) { lduw( s1, s2
|
||||
inline void Assembler::ld( Register s1, int simm13a, Register d) { lduw( s1, simm13a, d); }
|
||||
#endif
|
||||
|
||||
inline void Assembler::ldub( Register s1, RegisterConstant s2, Register d) {
|
||||
inline void Assembler::ldub( Register s1, RegisterOrConstant s2, Register d) {
|
||||
if (s2.is_register()) ldsb(s1, s2.as_register(), d);
|
||||
else ldsb(s1, s2.as_constant(), d);
|
||||
}
|
||||
inline void Assembler::ldsb( Register s1, RegisterConstant s2, Register d) {
|
||||
inline void Assembler::ldsb( Register s1, RegisterOrConstant s2, Register d) {
|
||||
if (s2.is_register()) ldsb(s1, s2.as_register(), d);
|
||||
else ldsb(s1, s2.as_constant(), d);
|
||||
}
|
||||
inline void Assembler::lduh( Register s1, RegisterConstant s2, Register d) {
|
||||
inline void Assembler::lduh( Register s1, RegisterOrConstant s2, Register d) {
|
||||
if (s2.is_register()) ldsh(s1, s2.as_register(), d);
|
||||
else ldsh(s1, s2.as_constant(), d);
|
||||
}
|
||||
inline void Assembler::ldsh( Register s1, RegisterConstant s2, Register d) {
|
||||
inline void Assembler::ldsh( Register s1, RegisterOrConstant s2, Register d) {
|
||||
if (s2.is_register()) ldsh(s1, s2.as_register(), d);
|
||||
else ldsh(s1, s2.as_constant(), d);
|
||||
}
|
||||
inline void Assembler::lduw( Register s1, RegisterConstant s2, Register d) {
|
||||
inline void Assembler::lduw( Register s1, RegisterOrConstant s2, Register d) {
|
||||
if (s2.is_register()) ldsw(s1, s2.as_register(), d);
|
||||
else ldsw(s1, s2.as_constant(), d);
|
||||
}
|
||||
inline void Assembler::ldsw( Register s1, RegisterConstant s2, Register d) {
|
||||
inline void Assembler::ldsw( Register s1, RegisterOrConstant s2, Register d) {
|
||||
if (s2.is_register()) ldsw(s1, s2.as_register(), d);
|
||||
else ldsw(s1, s2.as_constant(), d);
|
||||
}
|
||||
inline void Assembler::ldx( Register s1, RegisterConstant s2, Register d) {
|
||||
inline void Assembler::ldx( Register s1, RegisterOrConstant s2, Register d) {
|
||||
if (s2.is_register()) ldx(s1, s2.as_register(), d);
|
||||
else ldx(s1, s2.as_constant(), d);
|
||||
}
|
||||
inline void Assembler::ld( Register s1, RegisterConstant s2, Register d) {
|
||||
inline void Assembler::ld( Register s1, RegisterOrConstant s2, Register d) {
|
||||
if (s2.is_register()) ld(s1, s2.as_register(), d);
|
||||
else ld(s1, s2.as_constant(), d);
|
||||
}
|
||||
inline void Assembler::ldd( Register s1, RegisterConstant s2, Register d) {
|
||||
inline void Assembler::ldd( Register s1, RegisterOrConstant s2, Register d) {
|
||||
if (s2.is_register()) ldd(s1, s2.as_register(), d);
|
||||
else ldd(s1, s2.as_constant(), d);
|
||||
}
|
||||
|
||||
// form effective addresses this way:
|
||||
inline void Assembler::add( Register s1, RegisterConstant s2, Register d, int offset) {
|
||||
inline void Assembler::add( Register s1, RegisterOrConstant s2, Register d, int offset) {
|
||||
if (s2.is_register()) add(s1, s2.as_register(), d);
|
||||
else { add(s1, s2.as_constant() + offset, d); offset = 0; }
|
||||
if (offset != 0) add(d, offset, d);
|
||||
@ -243,23 +243,23 @@ inline void Assembler::std( Register d, Register s1, int simm13a) { v9_dep(); a
|
||||
inline void Assembler::st( Register d, Register s1, Register s2) { stw(d, s1, s2); }
|
||||
inline void Assembler::st( Register d, Register s1, int simm13a) { stw(d, s1, simm13a); }
|
||||
|
||||
inline void Assembler::stb( Register d, Register s1, RegisterConstant s2) {
|
||||
inline void Assembler::stb( Register d, Register s1, RegisterOrConstant s2) {
|
||||
if (s2.is_register()) stb(d, s1, s2.as_register());
|
||||
else stb(d, s1, s2.as_constant());
|
||||
}
|
||||
inline void Assembler::sth( Register d, Register s1, RegisterConstant s2) {
|
||||
inline void Assembler::sth( Register d, Register s1, RegisterOrConstant s2) {
|
||||
if (s2.is_register()) sth(d, s1, s2.as_register());
|
||||
else sth(d, s1, s2.as_constant());
|
||||
}
|
||||
inline void Assembler::stx( Register d, Register s1, RegisterConstant s2) {
|
||||
inline void Assembler::stx( Register d, Register s1, RegisterOrConstant s2) {
|
||||
if (s2.is_register()) stx(d, s1, s2.as_register());
|
||||
else stx(d, s1, s2.as_constant());
|
||||
}
|
||||
inline void Assembler::std( Register d, Register s1, RegisterConstant s2) {
|
||||
inline void Assembler::std( Register d, Register s1, RegisterOrConstant s2) {
|
||||
if (s2.is_register()) std(d, s1, s2.as_register());
|
||||
else std(d, s1, s2.as_constant());
|
||||
}
|
||||
inline void Assembler::st( Register d, Register s1, RegisterConstant s2) {
|
||||
inline void Assembler::st( Register d, Register s1, RegisterOrConstant s2) {
|
||||
if (s2.is_register()) st(d, s1, s2.as_register());
|
||||
else st(d, s1, s2.as_constant());
|
||||
}
|
||||
@ -308,7 +308,7 @@ inline void MacroAssembler::ld_ptr( Register s1, int simm13a, Register d ) {
|
||||
#endif
|
||||
}
|
||||
|
||||
inline void MacroAssembler::ld_ptr( Register s1, RegisterConstant s2, Register d ) {
|
||||
inline void MacroAssembler::ld_ptr( Register s1, RegisterOrConstant s2, Register d ) {
|
||||
#ifdef _LP64
|
||||
Assembler::ldx( s1, s2, d);
|
||||
#else
|
||||
@ -340,7 +340,7 @@ inline void MacroAssembler::st_ptr( Register d, Register s1, int simm13a ) {
|
||||
#endif
|
||||
}
|
||||
|
||||
inline void MacroAssembler::st_ptr( Register d, Register s1, RegisterConstant s2 ) {
|
||||
inline void MacroAssembler::st_ptr( Register d, Register s1, RegisterOrConstant s2 ) {
|
||||
#ifdef _LP64
|
||||
Assembler::stx( d, s1, s2);
|
||||
#else
|
||||
@ -373,7 +373,7 @@ inline void MacroAssembler::ld_long( Register s1, int simm13a, Register d ) {
|
||||
#endif
|
||||
}
|
||||
|
||||
inline void MacroAssembler::ld_long( Register s1, RegisterConstant s2, Register d ) {
|
||||
inline void MacroAssembler::ld_long( Register s1, RegisterOrConstant s2, Register d ) {
|
||||
#ifdef _LP64
|
||||
Assembler::ldx(s1, s2, d);
|
||||
#else
|
||||
@ -405,7 +405,7 @@ inline void MacroAssembler::st_long( Register d, Register s1, int simm13a ) {
|
||||
#endif
|
||||
}
|
||||
|
||||
inline void MacroAssembler::st_long( Register d, Register s1, RegisterConstant s2 ) {
|
||||
inline void MacroAssembler::st_long( Register d, Register s1, RegisterOrConstant s2 ) {
|
||||
#ifdef _LP64
|
||||
Assembler::stx(d, s1, s2);
|
||||
#else
|
||||
@ -455,7 +455,7 @@ inline void MacroAssembler::srl_ptr( Register s1, int imm6a, Register d ) {
|
||||
#endif
|
||||
}
|
||||
|
||||
inline void MacroAssembler::sll_ptr( Register s1, RegisterConstant s2, Register d ) {
|
||||
inline void MacroAssembler::sll_ptr( Register s1, RegisterOrConstant s2, Register d ) {
|
||||
if (s2.is_register()) sll_ptr(s1, s2.as_register(), d);
|
||||
else sll_ptr(s1, s2.as_constant(), d);
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* Copyright 2000-2009 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -2489,7 +2489,7 @@ void LIR_Assembler::emit_opTypeCheck(LIR_OpTypeCheck* op) {
|
||||
__ check_klass_subtype_fast_path(klass_RInfo, k_RInfo, Rtmp1, noreg,
|
||||
(need_slow_path ? &done : NULL),
|
||||
stub->entry(), NULL,
|
||||
RegisterConstant(k->super_check_offset()));
|
||||
RegisterOrConstant(k->super_check_offset()));
|
||||
} else {
|
||||
// perform the fast part of the checking logic
|
||||
__ check_klass_subtype_fast_path(klass_RInfo, k_RInfo, Rtmp1, O7,
|
||||
@ -2550,14 +2550,14 @@ void LIR_Assembler::emit_opTypeCheck(LIR_OpTypeCheck* op) {
|
||||
__ check_klass_subtype_fast_path(klass_RInfo, k_RInfo, O7, noreg,
|
||||
(need_slow_path ? &done : NULL),
|
||||
(need_slow_path ? &done : NULL), NULL,
|
||||
RegisterConstant(k->super_check_offset()),
|
||||
RegisterOrConstant(k->super_check_offset()),
|
||||
dst);
|
||||
} else {
|
||||
assert(dst != klass_RInfo && dst != k_RInfo, "need 3 registers");
|
||||
// perform the fast part of the checking logic
|
||||
__ check_klass_subtype_fast_path(klass_RInfo, k_RInfo, O7, dst,
|
||||
&done, &done, NULL,
|
||||
RegisterConstant(-1),
|
||||
RegisterOrConstant(-1),
|
||||
dst);
|
||||
}
|
||||
if (need_slow_path) {
|
||||
|
@ -46,6 +46,7 @@ define_pd_global(uintx, TLABSize, 0);
|
||||
define_pd_global(uintx, NewSize, ScaleForWordSize((2048 * K) + (2 * (64 * K))));
|
||||
define_pd_global(intx, SurvivorRatio, 8);
|
||||
define_pd_global(intx, InlineFrequencyCount, 50); // we can use more inlining on the SPARC
|
||||
define_pd_global(intx, InlineSmallCode, 1500);
|
||||
#ifdef _LP64
|
||||
// Stack slots are 2X larger in LP64 than in the 32 bit VM.
|
||||
define_pd_global(intx, ThreadStackSize, 1024);
|
||||
|
@ -3003,6 +3003,202 @@ enc_class Fast_Unlock(iRegP oop, iRegP box, o7RegP scratch, iRegP scratch2) %{
|
||||
__ bind(Ldone);
|
||||
%}
|
||||
|
||||
enc_class enc_String_Equals(o0RegP str1, o1RegP str2, g3RegP tmp1, g4RegP tmp2, notemp_iRegI result) %{
|
||||
Label Lword, Lword_loop, Lpost_word, Lchar, Lchar_loop, Ldone;
|
||||
MacroAssembler _masm(&cbuf);
|
||||
|
||||
Register str1_reg = reg_to_register_object($str1$$reg);
|
||||
Register str2_reg = reg_to_register_object($str2$$reg);
|
||||
Register tmp1_reg = reg_to_register_object($tmp1$$reg);
|
||||
Register tmp2_reg = reg_to_register_object($tmp2$$reg);
|
||||
Register result_reg = reg_to_register_object($result$$reg);
|
||||
|
||||
// Get the first character position in both strings
|
||||
// [8] char array, [12] offset, [16] count
|
||||
int value_offset = java_lang_String:: value_offset_in_bytes();
|
||||
int offset_offset = java_lang_String::offset_offset_in_bytes();
|
||||
int count_offset = java_lang_String:: count_offset_in_bytes();
|
||||
|
||||
// load str1 (jchar*) base address into tmp1_reg
|
||||
__ load_heap_oop(Address(str1_reg, 0, value_offset), tmp1_reg);
|
||||
__ ld(Address(str1_reg, 0, offset_offset), result_reg);
|
||||
__ add(tmp1_reg, arrayOopDesc::base_offset_in_bytes(T_CHAR), tmp1_reg);
|
||||
__ ld(Address(str1_reg, 0, count_offset), str1_reg); // hoisted
|
||||
__ sll(result_reg, exact_log2(sizeof(jchar)), result_reg);
|
||||
__ load_heap_oop(Address(str2_reg, 0, value_offset), tmp2_reg); // hoisted
|
||||
__ add(result_reg, tmp1_reg, tmp1_reg);
|
||||
|
||||
// load str2 (jchar*) base address into tmp2_reg
|
||||
// __ ld_ptr(Address(str2_reg, 0, value_offset), tmp2_reg); // hoisted
|
||||
__ ld(Address(str2_reg, 0, offset_offset), result_reg);
|
||||
__ add(tmp2_reg, arrayOopDesc::base_offset_in_bytes(T_CHAR), tmp2_reg);
|
||||
__ ld(Address(str2_reg, 0, count_offset), str2_reg); // hoisted
|
||||
__ sll(result_reg, exact_log2(sizeof(jchar)), result_reg);
|
||||
__ cmp(str1_reg, str2_reg); // hoisted
|
||||
__ add(result_reg, tmp2_reg, tmp2_reg);
|
||||
|
||||
__ sll(str1_reg, exact_log2(sizeof(jchar)), str1_reg);
|
||||
__ br(Assembler::notEqual, true, Assembler::pt, Ldone);
|
||||
__ delayed()->mov(G0, result_reg); // not equal
|
||||
|
||||
__ br_zero(Assembler::equal, true, Assembler::pn, str1_reg, Ldone);
|
||||
__ delayed()->add(G0, 1, result_reg); //equals
|
||||
|
||||
__ cmp(tmp1_reg, tmp2_reg); //same string ?
|
||||
__ brx(Assembler::equal, true, Assembler::pn, Ldone);
|
||||
__ delayed()->add(G0, 1, result_reg);
|
||||
|
||||
//rename registers
|
||||
Register limit_reg = str1_reg;
|
||||
Register chr2_reg = str2_reg;
|
||||
Register chr1_reg = result_reg;
|
||||
// tmp{12} are the base pointers
|
||||
|
||||
//check for alignment and position the pointers to the ends
|
||||
__ or3(tmp1_reg, tmp2_reg, chr1_reg);
|
||||
__ andcc(chr1_reg, 0x3, chr1_reg); // notZero means at least one not 4-byte aligned
|
||||
__ br(Assembler::notZero, false, Assembler::pn, Lchar);
|
||||
__ delayed()->nop();
|
||||
|
||||
__ bind(Lword);
|
||||
__ and3(limit_reg, 0x2, O7); //remember the remainder (either 0 or 2)
|
||||
__ andn(limit_reg, 0x3, limit_reg);
|
||||
__ br_zero(Assembler::zero, false, Assembler::pn, limit_reg, Lpost_word);
|
||||
__ delayed()->nop();
|
||||
|
||||
__ add(tmp1_reg, limit_reg, tmp1_reg);
|
||||
__ add(tmp2_reg, limit_reg, tmp2_reg);
|
||||
__ neg(limit_reg);
|
||||
|
||||
__ lduw(tmp1_reg, limit_reg, chr1_reg);
|
||||
__ bind(Lword_loop);
|
||||
__ lduw(tmp2_reg, limit_reg, chr2_reg);
|
||||
__ cmp(chr1_reg, chr2_reg);
|
||||
__ br(Assembler::notEqual, true, Assembler::pt, Ldone);
|
||||
__ delayed()->mov(G0, result_reg);
|
||||
__ inccc(limit_reg, 2*sizeof(jchar));
|
||||
// annul LDUW if branch i s not taken to prevent access past end of string
|
||||
__ br(Assembler::notZero, true, Assembler::pt, Lword_loop); //annul on taken
|
||||
__ delayed()->lduw(tmp1_reg, limit_reg, chr1_reg); // hoisted
|
||||
|
||||
__ bind(Lpost_word);
|
||||
__ br_zero(Assembler::zero, true, Assembler::pt, O7, Ldone);
|
||||
__ delayed()->add(G0, 1, result_reg);
|
||||
|
||||
__ lduh(tmp1_reg, 0, chr1_reg);
|
||||
__ lduh(tmp2_reg, 0, chr2_reg);
|
||||
__ cmp (chr1_reg, chr2_reg);
|
||||
__ br(Assembler::notEqual, true, Assembler::pt, Ldone);
|
||||
__ delayed()->mov(G0, result_reg);
|
||||
__ ba(false,Ldone);
|
||||
__ delayed()->add(G0, 1, result_reg);
|
||||
|
||||
__ bind(Lchar);
|
||||
__ add(tmp1_reg, limit_reg, tmp1_reg);
|
||||
__ add(tmp2_reg, limit_reg, tmp2_reg);
|
||||
__ neg(limit_reg); //negate count
|
||||
|
||||
__ lduh(tmp1_reg, limit_reg, chr1_reg);
|
||||
__ bind(Lchar_loop);
|
||||
__ lduh(tmp2_reg, limit_reg, chr2_reg);
|
||||
__ cmp(chr1_reg, chr2_reg);
|
||||
__ br(Assembler::notEqual, true, Assembler::pt, Ldone);
|
||||
__ delayed()->mov(G0, result_reg); //not equal
|
||||
__ inccc(limit_reg, sizeof(jchar));
|
||||
// annul LDUH if branch is not taken to prevent access past end of string
|
||||
__ br(Assembler::notZero, true, Assembler::pt, Lchar_loop); //annul on taken
|
||||
__ delayed()->lduh(tmp1_reg, limit_reg, chr1_reg); // hoisted
|
||||
|
||||
__ add(G0, 1, result_reg); //equal
|
||||
|
||||
__ bind(Ldone);
|
||||
%}
|
||||
|
||||
enc_class enc_Array_Equals(o0RegP ary1, o1RegP ary2, g3RegP tmp1, g4RegP tmp2, notemp_iRegI result) %{
|
||||
Label Lvector, Ldone, Lloop;
|
||||
MacroAssembler _masm(&cbuf);
|
||||
|
||||
Register ary1_reg = reg_to_register_object($ary1$$reg);
|
||||
Register ary2_reg = reg_to_register_object($ary2$$reg);
|
||||
Register tmp1_reg = reg_to_register_object($tmp1$$reg);
|
||||
Register tmp2_reg = reg_to_register_object($tmp2$$reg);
|
||||
Register result_reg = reg_to_register_object($result$$reg);
|
||||
|
||||
int length_offset = arrayOopDesc::length_offset_in_bytes();
|
||||
int base_offset = arrayOopDesc::base_offset_in_bytes(T_CHAR);
|
||||
|
||||
// return true if the same array
|
||||
__ cmp(ary1_reg, ary2_reg);
|
||||
__ br(Assembler::equal, true, Assembler::pn, Ldone);
|
||||
__ delayed()->add(G0, 1, result_reg); // equal
|
||||
|
||||
__ br_null(ary1_reg, true, Assembler::pn, Ldone);
|
||||
__ delayed()->mov(G0, result_reg); // not equal
|
||||
|
||||
__ br_null(ary2_reg, true, Assembler::pn, Ldone);
|
||||
__ delayed()->mov(G0, result_reg); // not equal
|
||||
|
||||
//load the lengths of arrays
|
||||
__ ld(Address(ary1_reg, 0, length_offset), tmp1_reg);
|
||||
__ ld(Address(ary2_reg, 0, length_offset), tmp2_reg);
|
||||
|
||||
// return false if the two arrays are not equal length
|
||||
__ cmp(tmp1_reg, tmp2_reg);
|
||||
__ br(Assembler::notEqual, true, Assembler::pn, Ldone);
|
||||
__ delayed()->mov(G0, result_reg); // not equal
|
||||
|
||||
__ br_zero(Assembler::zero, true, Assembler::pn, tmp1_reg, Ldone);
|
||||
__ delayed()->add(G0, 1, result_reg); // zero-length arrays are equal
|
||||
|
||||
// load array addresses
|
||||
__ add(ary1_reg, base_offset, ary1_reg);
|
||||
__ add(ary2_reg, base_offset, ary2_reg);
|
||||
|
||||
// renaming registers
|
||||
Register chr1_reg = tmp2_reg; // for characters in ary1
|
||||
Register chr2_reg = result_reg; // for characters in ary2
|
||||
Register limit_reg = tmp1_reg; // length
|
||||
|
||||
// set byte count
|
||||
__ sll(limit_reg, exact_log2(sizeof(jchar)), limit_reg);
|
||||
__ andcc(limit_reg, 0x2, chr1_reg); //trailing character ?
|
||||
__ br(Assembler::zero, false, Assembler::pt, Lvector);
|
||||
__ delayed()->nop();
|
||||
|
||||
//compare the trailing char
|
||||
__ sub(limit_reg, sizeof(jchar), limit_reg);
|
||||
__ lduh(ary1_reg, limit_reg, chr1_reg);
|
||||
__ lduh(ary2_reg, limit_reg, chr2_reg);
|
||||
__ cmp(chr1_reg, chr2_reg);
|
||||
__ br(Assembler::notEqual, true, Assembler::pt, Ldone);
|
||||
__ delayed()->mov(G0, result_reg); // not equal
|
||||
|
||||
// only one char ?
|
||||
__ br_zero(Assembler::zero, true, Assembler::pn, limit_reg, Ldone);
|
||||
__ delayed()->add(G0, 1, result_reg); // zero-length arrays are equal
|
||||
|
||||
__ bind(Lvector);
|
||||
// Shift ary1_reg and ary2_reg to the end of the arrays, negate limit
|
||||
__ add(ary1_reg, limit_reg, ary1_reg);
|
||||
__ add(ary2_reg, limit_reg, ary2_reg);
|
||||
__ neg(limit_reg, limit_reg);
|
||||
|
||||
__ lduw(ary1_reg, limit_reg, chr1_reg);
|
||||
__ bind(Lloop);
|
||||
__ lduw(ary2_reg, limit_reg, chr2_reg);
|
||||
__ cmp(chr1_reg, chr2_reg);
|
||||
__ br(Assembler::notEqual, false, Assembler::pt, Ldone);
|
||||
__ delayed()->mov(G0, result_reg); // not equal
|
||||
__ inccc(limit_reg, 2*sizeof(jchar));
|
||||
// annul LDUW if branch is not taken to prevent access past end of string
|
||||
__ br(Assembler::notZero, true, Assembler::pt, Lloop); //annul on taken
|
||||
__ delayed()->lduw(ary1_reg, limit_reg, chr1_reg); // hoisted
|
||||
|
||||
__ add(G0, 1, result_reg); // equals
|
||||
|
||||
__ bind(Ldone);
|
||||
%}
|
||||
|
||||
enc_class enc_rethrow() %{
|
||||
cbuf.set_inst_mark();
|
||||
Register temp_reg = G3;
|
||||
@ -9015,6 +9211,25 @@ instruct string_compare(o0RegP str1, o1RegP str2, g3RegP tmp1, g4RegP tmp2, note
|
||||
ins_pipe(long_memory_op);
|
||||
%}
|
||||
|
||||
instruct string_equals(o0RegP str1, o1RegP str2, g3RegP tmp1, g4RegP tmp2, notemp_iRegI result,
|
||||
o7RegI tmp3, flagsReg ccr) %{
|
||||
match(Set result (StrEquals str1 str2));
|
||||
effect(USE_KILL str1, USE_KILL str2, KILL tmp1, KILL tmp2, KILL ccr, KILL tmp3);
|
||||
ins_cost(300);
|
||||
format %{ "String Equals $str1,$str2 -> $result" %}
|
||||
ins_encode( enc_String_Equals(str1, str2, tmp1, tmp2, result) );
|
||||
ins_pipe(long_memory_op);
|
||||
%}
|
||||
|
||||
instruct array_equals(o0RegP ary1, o1RegP ary2, g3RegP tmp1, g4RegP tmp2, notemp_iRegI result,
|
||||
flagsReg ccr) %{
|
||||
match(Set result (AryEq ary1 ary2));
|
||||
effect(USE_KILL ary1, USE_KILL ary2, KILL tmp1, KILL tmp2, KILL ccr);
|
||||
ins_cost(300);
|
||||
format %{ "Array Equals $ary1,$ary2 -> $result" %}
|
||||
ins_encode( enc_Array_Equals(ary1, ary2, tmp1, tmp2, result));
|
||||
ins_pipe(long_memory_op);
|
||||
%}
|
||||
|
||||
//---------- Population Count Instructions -------------------------------------
|
||||
|
||||
|
@ -817,21 +817,6 @@ class StubGenerator: public StubCodeGenerator {
|
||||
Label _atomic_add_stub; // called from other stubs
|
||||
|
||||
|
||||
// Support for void OrderAccess::fence().
|
||||
//
|
||||
address generate_fence() {
|
||||
StubCodeMark mark(this, "StubRoutines", "fence");
|
||||
address start = __ pc();
|
||||
|
||||
__ membar(Assembler::Membar_mask_bits(Assembler::LoadLoad | Assembler::LoadStore |
|
||||
Assembler::StoreLoad | Assembler::StoreStore));
|
||||
__ retl(false);
|
||||
__ delayed()->nop();
|
||||
|
||||
return start;
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------------------------------------------------
|
||||
// The following routine generates a subroutine to throw an asynchronous
|
||||
// UnknownError when an unsafe access gets a fault that could not be
|
||||
@ -2861,7 +2846,6 @@ class StubGenerator: public StubCodeGenerator {
|
||||
StubRoutines::_atomic_cmpxchg_ptr_entry = StubRoutines::_atomic_cmpxchg_entry;
|
||||
StubRoutines::_atomic_cmpxchg_long_entry = generate_atomic_cmpxchg_long();
|
||||
StubRoutines::_atomic_add_ptr_entry = StubRoutines::_atomic_add_entry;
|
||||
StubRoutines::_fence_entry = generate_fence();
|
||||
#endif // COMPILER2 !=> _LP64
|
||||
}
|
||||
|
||||
|
@ -62,7 +62,7 @@ void VM_Version::initialize() {
|
||||
if (is_niagara1()) {
|
||||
// Indirect branch is the same cost as direct
|
||||
if (FLAG_IS_DEFAULT(UseInlineCaches)) {
|
||||
UseInlineCaches = false;
|
||||
FLAG_SET_DEFAULT(UseInlineCaches, false);
|
||||
}
|
||||
#ifdef _LP64
|
||||
// Single issue niagara1 is slower for CompressedOops
|
||||
@ -79,15 +79,19 @@ void VM_Version::initialize() {
|
||||
#ifdef COMPILER2
|
||||
// Indirect branch is the same cost as direct
|
||||
if (FLAG_IS_DEFAULT(UseJumpTables)) {
|
||||
UseJumpTables = true;
|
||||
FLAG_SET_DEFAULT(UseJumpTables, true);
|
||||
}
|
||||
// Single-issue, so entry and loop tops are
|
||||
// aligned on a single instruction boundary
|
||||
if (FLAG_IS_DEFAULT(InteriorEntryAlignment)) {
|
||||
InteriorEntryAlignment = 4;
|
||||
FLAG_SET_DEFAULT(InteriorEntryAlignment, 4);
|
||||
}
|
||||
if (FLAG_IS_DEFAULT(OptoLoopAlignment)) {
|
||||
OptoLoopAlignment = 4;
|
||||
FLAG_SET_DEFAULT(OptoLoopAlignment, 4);
|
||||
}
|
||||
if (is_niagara1_plus() && FLAG_IS_DEFAULT(AllocatePrefetchDistance)) {
|
||||
// Use smaller prefetch distance on N2
|
||||
FLAG_SET_DEFAULT(AllocatePrefetchDistance, 256);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@ -95,7 +99,7 @@ void VM_Version::initialize() {
|
||||
// Use hardware population count instruction if available.
|
||||
if (has_hardware_popc()) {
|
||||
if (FLAG_IS_DEFAULT(UsePopCountInstruction)) {
|
||||
UsePopCountInstruction = true;
|
||||
FLAG_SET_DEFAULT(UsePopCountInstruction, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1438,26 +1438,12 @@ void Assembler::lock() {
|
||||
}
|
||||
}
|
||||
|
||||
// Serializes memory.
|
||||
// Emit mfence instruction
|
||||
void Assembler::mfence() {
|
||||
// Memory barriers are only needed on multiprocessors
|
||||
if (os::is_MP()) {
|
||||
if( LP64_ONLY(true ||) VM_Version::supports_sse2() ) {
|
||||
emit_byte( 0x0F ); // MFENCE; faster blows no regs
|
||||
emit_byte( 0xAE );
|
||||
emit_byte( 0xF0 );
|
||||
} else {
|
||||
// All usable chips support "locked" instructions which suffice
|
||||
// as barriers, and are much faster than the alternative of
|
||||
// using cpuid instruction. We use here a locked add [esp],0.
|
||||
// This is conveniently otherwise a no-op except for blowing
|
||||
// flags (which we save and restore.)
|
||||
pushf(); // Save eflags register
|
||||
lock();
|
||||
addl(Address(rsp, 0), 0);// Assert the lock# signal here
|
||||
popf(); // Restore eflags register
|
||||
}
|
||||
}
|
||||
NOT_LP64(assert(VM_Version::supports_sse2(), "unsupported");)
|
||||
emit_byte( 0x0F );
|
||||
emit_byte( 0xAE );
|
||||
emit_byte( 0xF0 );
|
||||
}
|
||||
|
||||
void Assembler::mov(Register dst, Register src) {
|
||||
@ -2187,6 +2173,31 @@ void Assembler::orl(Register dst, Register src) {
|
||||
emit_arith(0x0B, 0xC0, dst, src);
|
||||
}
|
||||
|
||||
void Assembler::pcmpestri(XMMRegister dst, Address src, int imm8) {
|
||||
assert(VM_Version::supports_sse4_2(), "");
|
||||
|
||||
InstructionMark im(this);
|
||||
emit_byte(0x66);
|
||||
prefix(src, dst);
|
||||
emit_byte(0x0F);
|
||||
emit_byte(0x3A);
|
||||
emit_byte(0x61);
|
||||
emit_operand(dst, src);
|
||||
emit_byte(imm8);
|
||||
}
|
||||
|
||||
void Assembler::pcmpestri(XMMRegister dst, XMMRegister src, int imm8) {
|
||||
assert(VM_Version::supports_sse4_2(), "");
|
||||
|
||||
emit_byte(0x66);
|
||||
int encode = prefixq_and_encode(dst->encoding(), src->encoding());
|
||||
emit_byte(0x0F);
|
||||
emit_byte(0x3A);
|
||||
emit_byte(0x61);
|
||||
emit_byte(0xC0 | encode);
|
||||
emit_byte(imm8);
|
||||
}
|
||||
|
||||
// generic
|
||||
void Assembler::pop(Register dst) {
|
||||
int encode = prefix_and_encode(dst->encoding());
|
||||
@ -2344,6 +2355,29 @@ void Assembler::psrlq(XMMRegister dst, int shift) {
|
||||
emit_byte(shift);
|
||||
}
|
||||
|
||||
void Assembler::ptest(XMMRegister dst, Address src) {
|
||||
assert(VM_Version::supports_sse4_1(), "");
|
||||
|
||||
InstructionMark im(this);
|
||||
emit_byte(0x66);
|
||||
prefix(src, dst);
|
||||
emit_byte(0x0F);
|
||||
emit_byte(0x38);
|
||||
emit_byte(0x17);
|
||||
emit_operand(dst, src);
|
||||
}
|
||||
|
||||
void Assembler::ptest(XMMRegister dst, XMMRegister src) {
|
||||
assert(VM_Version::supports_sse4_1(), "");
|
||||
|
||||
emit_byte(0x66);
|
||||
int encode = prefixq_and_encode(dst->encoding(), src->encoding());
|
||||
emit_byte(0x0F);
|
||||
emit_byte(0x38);
|
||||
emit_byte(0x17);
|
||||
emit_byte(0xC0 | encode);
|
||||
}
|
||||
|
||||
void Assembler::punpcklbw(XMMRegister dst, XMMRegister src) {
|
||||
NOT_LP64(assert(VM_Version::supports_sse2(), ""));
|
||||
emit_byte(0x66);
|
||||
@ -7218,7 +7252,7 @@ void MacroAssembler::trigfunc(char trig, int num_fpu_regs_in_use) {
|
||||
// On failure, execution transfers to the given label.
|
||||
void MacroAssembler::lookup_interface_method(Register recv_klass,
|
||||
Register intf_klass,
|
||||
RegisterConstant itable_index,
|
||||
RegisterOrConstant itable_index,
|
||||
Register method_result,
|
||||
Register scan_temp,
|
||||
Label& L_no_such_interface) {
|
||||
@ -7303,7 +7337,7 @@ void MacroAssembler::check_klass_subtype_fast_path(Register sub_klass,
|
||||
Label* L_success,
|
||||
Label* L_failure,
|
||||
Label* L_slow_path,
|
||||
RegisterConstant super_check_offset) {
|
||||
RegisterOrConstant super_check_offset) {
|
||||
assert_different_registers(sub_klass, super_klass, temp_reg);
|
||||
bool must_load_sco = (super_check_offset.constant_or_zero() == -1);
|
||||
if (super_check_offset.is_register()) {
|
||||
@ -7352,7 +7386,7 @@ void MacroAssembler::check_klass_subtype_fast_path(Register sub_klass,
|
||||
if (must_load_sco) {
|
||||
// Positive movl does right thing on LP64.
|
||||
movl(temp_reg, super_check_offset_addr);
|
||||
super_check_offset = RegisterConstant(temp_reg);
|
||||
super_check_offset = RegisterOrConstant(temp_reg);
|
||||
}
|
||||
Address super_check_addr(sub_klass, super_check_offset, Address::times_1, 0);
|
||||
cmpptr(super_klass, super_check_addr); // load displayed supertype
|
||||
@ -7550,12 +7584,12 @@ void MacroAssembler::verify_oop(Register reg, const char* s) {
|
||||
}
|
||||
|
||||
|
||||
RegisterConstant MacroAssembler::delayed_value(intptr_t* delayed_value_addr,
|
||||
Register tmp,
|
||||
int offset) {
|
||||
RegisterOrConstant MacroAssembler::delayed_value_impl(intptr_t* delayed_value_addr,
|
||||
Register tmp,
|
||||
int offset) {
|
||||
intptr_t value = *delayed_value_addr;
|
||||
if (value != 0)
|
||||
return RegisterConstant(value + offset);
|
||||
return RegisterOrConstant(value + offset);
|
||||
|
||||
// load indirectly to solve generation ordering problem
|
||||
movptr(tmp, ExternalAddress((address) delayed_value_addr));
|
||||
@ -7571,7 +7605,7 @@ RegisterConstant MacroAssembler::delayed_value(intptr_t* delayed_value_addr,
|
||||
if (offset != 0)
|
||||
addptr(tmp, offset);
|
||||
|
||||
return RegisterConstant(tmp);
|
||||
return RegisterOrConstant(tmp);
|
||||
}
|
||||
|
||||
|
||||
|
@ -212,7 +212,7 @@ class Address VALUE_OBJ_CLASS_SPEC {
|
||||
"inconsistent address");
|
||||
}
|
||||
|
||||
Address(Register base, RegisterConstant index, ScaleFactor scale = times_1, int disp = 0)
|
||||
Address(Register base, RegisterOrConstant index, ScaleFactor scale = times_1, int disp = 0)
|
||||
: _base (base),
|
||||
_index(index.register_or_noreg()),
|
||||
_scale(scale),
|
||||
@ -256,7 +256,7 @@ class Address VALUE_OBJ_CLASS_SPEC {
|
||||
"inconsistent address");
|
||||
}
|
||||
|
||||
Address(Register base, RegisterConstant index, ScaleFactor scale, ByteSize disp)
|
||||
Address(Register base, RegisterOrConstant index, ScaleFactor scale, ByteSize disp)
|
||||
: _base (base),
|
||||
_index(index.register_or_noreg()),
|
||||
_scale(scale),
|
||||
@ -1068,15 +1068,23 @@ private:
|
||||
LoadLoad = 1 << 0
|
||||
};
|
||||
|
||||
// Serializes memory.
|
||||
// Serializes memory and blows flags
|
||||
void membar(Membar_mask_bits order_constraint) {
|
||||
// We only have to handle StoreLoad and LoadLoad
|
||||
if (order_constraint & StoreLoad) {
|
||||
// MFENCE subsumes LFENCE
|
||||
mfence();
|
||||
} /* [jk] not needed currently: else if (order_constraint & LoadLoad) {
|
||||
lfence();
|
||||
} */
|
||||
if (os::is_MP()) {
|
||||
// We only have to handle StoreLoad
|
||||
if (order_constraint & StoreLoad) {
|
||||
// All usable chips support "locked" instructions which suffice
|
||||
// as barriers, and are much faster than the alternative of
|
||||
// using cpuid instruction. We use here a locked add [esp],0.
|
||||
// This is conveniently otherwise a no-op except for blowing
|
||||
// flags.
|
||||
// Any change to this code may need to revisit other places in
|
||||
// the code where this idiom is used, in particular the
|
||||
// orderAccess code.
|
||||
lock();
|
||||
addl(Address(rsp, 0), 0);// Assert the lock# signal here
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void mfence();
|
||||
@ -1218,6 +1226,10 @@ private:
|
||||
void orq(Register dst, Address src);
|
||||
void orq(Register dst, Register src);
|
||||
|
||||
// SSE4.2 string instructions
|
||||
void pcmpestri(XMMRegister xmm1, XMMRegister xmm2, int imm8);
|
||||
void pcmpestri(XMMRegister xmm1, Address src, int imm8);
|
||||
|
||||
void popl(Address dst);
|
||||
|
||||
#ifdef _LP64
|
||||
@ -1252,6 +1264,10 @@ private:
|
||||
// Shift Right Logical Quadword Immediate
|
||||
void psrlq(XMMRegister dst, int shift);
|
||||
|
||||
// Logical Compare Double Quadword
|
||||
void ptest(XMMRegister dst, XMMRegister src);
|
||||
void ptest(XMMRegister dst, Address src);
|
||||
|
||||
// Interleave Low Bytes
|
||||
void punpcklbw(XMMRegister dst, XMMRegister src);
|
||||
|
||||
@ -1802,7 +1818,7 @@ class MacroAssembler: public Assembler {
|
||||
// interface method calling
|
||||
void lookup_interface_method(Register recv_klass,
|
||||
Register intf_klass,
|
||||
RegisterConstant itable_index,
|
||||
RegisterOrConstant itable_index,
|
||||
Register method_result,
|
||||
Register scan_temp,
|
||||
Label& no_such_interface);
|
||||
@ -1819,7 +1835,7 @@ class MacroAssembler: public Assembler {
|
||||
Label* L_success,
|
||||
Label* L_failure,
|
||||
Label* L_slow_path,
|
||||
RegisterConstant super_check_offset = RegisterConstant(-1));
|
||||
RegisterOrConstant super_check_offset = RegisterOrConstant(-1));
|
||||
|
||||
// The rest of the type check; must be wired to a corresponding fast path.
|
||||
// It does not repeat the fast path logic, so don't use it standalone.
|
||||
@ -1883,9 +1899,9 @@ class MacroAssembler: public Assembler {
|
||||
// stack overflow + shadow pages. Also, clobbers tmp
|
||||
void bang_stack_size(Register size, Register tmp);
|
||||
|
||||
virtual RegisterConstant delayed_value(intptr_t* delayed_value_addr,
|
||||
Register tmp,
|
||||
int offset);
|
||||
virtual RegisterOrConstant delayed_value_impl(intptr_t* delayed_value_addr,
|
||||
Register tmp,
|
||||
int offset);
|
||||
|
||||
// Support for serializing memory accesses between threads
|
||||
void serialize_memory(Register thread, Register tmp);
|
||||
|
@ -60,6 +60,7 @@ define_pd_global(uintx, NewSize, 1024 * K);
|
||||
define_pd_global(intx, StackShadowPages, 3 DEBUG_ONLY(+1));
|
||||
#endif // AMD64
|
||||
define_pd_global(intx, InlineFrequencyCount, 100);
|
||||
define_pd_global(intx, InlineSmallCode, 1000);
|
||||
define_pd_global(intx, PreInflateSpin, 10);
|
||||
|
||||
define_pd_global(intx, StackYellowPages, 2);
|
||||
|
@ -2691,7 +2691,7 @@ void SharedRuntime::generate_deopt_blob() {
|
||||
__ mov(rdi, rax);
|
||||
|
||||
Label noException;
|
||||
__ cmpl(r12, Deoptimization::Unpack_exception); // Was exception pending?
|
||||
__ cmpl(r14, Deoptimization::Unpack_exception); // Was exception pending?
|
||||
__ jcc(Assembler::notEqual, noException);
|
||||
__ movptr(rax, Address(r15_thread, JavaThread::exception_oop_offset()));
|
||||
// QQQ this is useless it was NULL above
|
||||
|
@ -637,7 +637,7 @@ class StubGenerator: public StubCodeGenerator {
|
||||
address generate_orderaccess_fence() {
|
||||
StubCodeMark mark(this, "StubRoutines", "orderaccess_fence");
|
||||
address start = __ pc();
|
||||
__ mfence();
|
||||
__ membar(Assembler::StoreLoad);
|
||||
__ ret(0);
|
||||
|
||||
return start;
|
||||
|
@ -408,6 +408,11 @@ void VM_Version::get_processor_features() {
|
||||
UseUnalignedLoadStores = true; // use movdqu on newest Intel cpus
|
||||
}
|
||||
}
|
||||
if( supports_sse4_2() && UseSSE >= 4 ) {
|
||||
if( FLAG_IS_DEFAULT(UseSSE42Intrinsics)) {
|
||||
UseSSE42Intrinsics = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3694,12 +3694,16 @@ encode %{
|
||||
}
|
||||
%}
|
||||
|
||||
enc_class enc_String_Compare() %{
|
||||
enc_class enc_String_Compare(eDIRegP str1, eSIRegP str2, regXD tmp1, regXD tmp2,
|
||||
eAXRegI tmp3, eBXRegI tmp4, eCXRegI result) %{
|
||||
Label ECX_GOOD_LABEL, LENGTH_DIFF_LABEL,
|
||||
POP_LABEL, DONE_LABEL, CONT_LABEL,
|
||||
WHILE_HEAD_LABEL;
|
||||
MacroAssembler masm(&cbuf);
|
||||
|
||||
XMMRegister tmp1Reg = as_XMMRegister($tmp1$$reg);
|
||||
XMMRegister tmp2Reg = as_XMMRegister($tmp2$$reg);
|
||||
|
||||
// Get the first character position in both strings
|
||||
// [8] char array, [12] offset, [16] count
|
||||
int value_offset = java_lang_String::value_offset_in_bytes();
|
||||
@ -3717,7 +3721,6 @@ encode %{
|
||||
// Compute the minimum of the string lengths(rsi) and the
|
||||
// difference of the string lengths (stack)
|
||||
|
||||
|
||||
if (VM_Version::supports_cmov()) {
|
||||
masm.movl(rdi, Address(rdi, count_offset));
|
||||
masm.movl(rsi, Address(rsi, count_offset));
|
||||
@ -3731,7 +3734,7 @@ encode %{
|
||||
masm.movl(rsi, rdi);
|
||||
masm.subl(rdi, rcx);
|
||||
masm.push(rdi);
|
||||
masm.jcc(Assembler::lessEqual, ECX_GOOD_LABEL);
|
||||
masm.jccb(Assembler::lessEqual, ECX_GOOD_LABEL);
|
||||
masm.movl(rsi, rcx);
|
||||
// rsi holds min, rcx is unused
|
||||
}
|
||||
@ -3756,7 +3759,7 @@ encode %{
|
||||
Label LSkip2;
|
||||
// Check if the strings start at same location
|
||||
masm.cmpptr(rbx,rax);
|
||||
masm.jcc(Assembler::notEqual, LSkip2);
|
||||
masm.jccb(Assembler::notEqual, LSkip2);
|
||||
|
||||
// Check if the length difference is zero (from stack)
|
||||
masm.cmpl(Address(rsp, 0), 0x0);
|
||||
@ -3766,9 +3769,52 @@ encode %{
|
||||
masm.bind(LSkip2);
|
||||
}
|
||||
|
||||
// Shift rax, and rbx, to the end of the arrays, negate min
|
||||
masm.lea(rax, Address(rax, rsi, Address::times_2, 2));
|
||||
masm.lea(rbx, Address(rbx, rsi, Address::times_2, 2));
|
||||
// Advance to next character
|
||||
masm.addptr(rax, 2);
|
||||
masm.addptr(rbx, 2);
|
||||
|
||||
if (UseSSE42Intrinsics) {
|
||||
// With SSE4.2, use double quad vector compare
|
||||
Label COMPARE_VECTORS, VECTOR_NOT_EQUAL, COMPARE_TAIL;
|
||||
// Setup to compare 16-byte vectors
|
||||
masm.movl(rdi, rsi);
|
||||
masm.andl(rsi, 0xfffffff8); // rsi holds the vector count
|
||||
masm.andl(rdi, 0x00000007); // rdi holds the tail count
|
||||
masm.testl(rsi, rsi);
|
||||
masm.jccb(Assembler::zero, COMPARE_TAIL);
|
||||
|
||||
masm.lea(rax, Address(rax, rsi, Address::times_2));
|
||||
masm.lea(rbx, Address(rbx, rsi, Address::times_2));
|
||||
masm.negl(rsi);
|
||||
|
||||
masm.bind(COMPARE_VECTORS);
|
||||
masm.movdqu(tmp1Reg, Address(rax, rsi, Address::times_2));
|
||||
masm.movdqu(tmp2Reg, Address(rbx, rsi, Address::times_2));
|
||||
masm.pxor(tmp1Reg, tmp2Reg);
|
||||
masm.ptest(tmp1Reg, tmp1Reg);
|
||||
masm.jccb(Assembler::notZero, VECTOR_NOT_EQUAL);
|
||||
masm.addl(rsi, 8);
|
||||
masm.jcc(Assembler::notZero, COMPARE_VECTORS);
|
||||
masm.jmpb(COMPARE_TAIL);
|
||||
|
||||
// Mismatched characters in the vectors
|
||||
masm.bind(VECTOR_NOT_EQUAL);
|
||||
masm.lea(rax, Address(rax, rsi, Address::times_2));
|
||||
masm.lea(rbx, Address(rbx, rsi, Address::times_2));
|
||||
masm.movl(rdi, 8);
|
||||
|
||||
// Compare tail (< 8 chars), or rescan last vectors to
|
||||
// find 1st mismatched characters
|
||||
masm.bind(COMPARE_TAIL);
|
||||
masm.testl(rdi, rdi);
|
||||
masm.jccb(Assembler::zero, LENGTH_DIFF_LABEL);
|
||||
masm.movl(rsi, rdi);
|
||||
// Fallthru to tail compare
|
||||
}
|
||||
|
||||
//Shift rax, and rbx, to the end of the arrays, negate min
|
||||
masm.lea(rax, Address(rax, rsi, Address::times_2, 0));
|
||||
masm.lea(rbx, Address(rbx, rsi, Address::times_2, 0));
|
||||
masm.negl(rsi);
|
||||
|
||||
// Compare the rest of the characters
|
||||
@ -3776,93 +3822,329 @@ encode %{
|
||||
masm.load_unsigned_short(rcx, Address(rbx, rsi, Address::times_2, 0));
|
||||
masm.load_unsigned_short(rdi, Address(rax, rsi, Address::times_2, 0));
|
||||
masm.subl(rcx, rdi);
|
||||
masm.jcc(Assembler::notZero, POP_LABEL);
|
||||
masm.jccb(Assembler::notZero, POP_LABEL);
|
||||
masm.incrementl(rsi);
|
||||
masm.jcc(Assembler::notZero, WHILE_HEAD_LABEL);
|
||||
|
||||
// Strings are equal up to min length. Return the length difference.
|
||||
masm.bind(LENGTH_DIFF_LABEL);
|
||||
masm.pop(rcx);
|
||||
masm.jmp(DONE_LABEL);
|
||||
masm.jmpb(DONE_LABEL);
|
||||
|
||||
// Discard the stored length difference
|
||||
masm.bind(POP_LABEL);
|
||||
masm.addptr(rsp, 4);
|
||||
|
||||
|
||||
// That's it
|
||||
masm.bind(DONE_LABEL);
|
||||
%}
|
||||
|
||||
enc_class enc_Array_Equals(eDIRegP ary1, eSIRegP ary2, eAXRegI tmp1, eBXRegI tmp2, eCXRegI result) %{
|
||||
Label TRUE_LABEL, FALSE_LABEL, DONE_LABEL, COMPARE_LOOP_HDR, COMPARE_LOOP;
|
||||
enc_class enc_String_Equals(eDIRegP str1, eSIRegP str2, regXD tmp1, regXD tmp2,
|
||||
eBXRegI tmp3, eCXRegI tmp4, eAXRegI result) %{
|
||||
Label RET_TRUE, RET_FALSE, DONE, COMPARE_VECTORS, COMPARE_CHAR;
|
||||
MacroAssembler masm(&cbuf);
|
||||
|
||||
Register ary1Reg = as_Register($ary1$$reg);
|
||||
Register ary2Reg = as_Register($ary2$$reg);
|
||||
Register tmp1Reg = as_Register($tmp1$$reg);
|
||||
Register tmp2Reg = as_Register($tmp2$$reg);
|
||||
Register resultReg = as_Register($result$$reg);
|
||||
XMMRegister tmp1Reg = as_XMMRegister($tmp1$$reg);
|
||||
XMMRegister tmp2Reg = as_XMMRegister($tmp2$$reg);
|
||||
|
||||
int value_offset = java_lang_String::value_offset_in_bytes();
|
||||
int offset_offset = java_lang_String::offset_offset_in_bytes();
|
||||
int count_offset = java_lang_String::count_offset_in_bytes();
|
||||
int base_offset = arrayOopDesc::base_offset_in_bytes(T_CHAR);
|
||||
|
||||
// does source == target string?
|
||||
masm.cmpptr(rdi, rsi);
|
||||
masm.jcc(Assembler::equal, RET_TRUE);
|
||||
|
||||
// get and compare counts
|
||||
masm.movl(rcx, Address(rdi, count_offset));
|
||||
masm.movl(rax, Address(rsi, count_offset));
|
||||
masm.cmpl(rcx, rax);
|
||||
masm.jcc(Assembler::notEqual, RET_FALSE);
|
||||
masm.testl(rax, rax);
|
||||
masm.jcc(Assembler::zero, RET_TRUE);
|
||||
|
||||
// get source string offset and value
|
||||
masm.movptr(rbx, Address(rsi, value_offset));
|
||||
masm.movl(rax, Address(rsi, offset_offset));
|
||||
masm.leal(rsi, Address(rbx, rax, Address::times_2, base_offset));
|
||||
|
||||
// get compare string offset and value
|
||||
masm.movptr(rbx, Address(rdi, value_offset));
|
||||
masm.movl(rax, Address(rdi, offset_offset));
|
||||
masm.leal(rdi, Address(rbx, rax, Address::times_2, base_offset));
|
||||
|
||||
// Set byte count
|
||||
masm.shll(rcx, 1);
|
||||
masm.movl(rax, rcx);
|
||||
|
||||
if (UseSSE42Intrinsics) {
|
||||
// With SSE4.2, use double quad vector compare
|
||||
Label COMPARE_WIDE_VECTORS, COMPARE_TAIL;
|
||||
// Compare 16-byte vectors
|
||||
masm.andl(rcx, 0xfffffff0); // vector count (in bytes)
|
||||
masm.andl(rax, 0x0000000e); // tail count (in bytes)
|
||||
masm.testl(rcx, rcx);
|
||||
masm.jccb(Assembler::zero, COMPARE_TAIL);
|
||||
masm.lea(rdi, Address(rdi, rcx, Address::times_1));
|
||||
masm.lea(rsi, Address(rsi, rcx, Address::times_1));
|
||||
masm.negl(rcx);
|
||||
|
||||
masm.bind(COMPARE_WIDE_VECTORS);
|
||||
masm.movdqu(tmp1Reg, Address(rdi, rcx, Address::times_1));
|
||||
masm.movdqu(tmp2Reg, Address(rsi, rcx, Address::times_1));
|
||||
masm.pxor(tmp1Reg, tmp2Reg);
|
||||
masm.ptest(tmp1Reg, tmp1Reg);
|
||||
masm.jccb(Assembler::notZero, RET_FALSE);
|
||||
masm.addl(rcx, 16);
|
||||
masm.jcc(Assembler::notZero, COMPARE_WIDE_VECTORS);
|
||||
masm.bind(COMPARE_TAIL);
|
||||
masm.movl(rcx, rax);
|
||||
// Fallthru to tail compare
|
||||
}
|
||||
|
||||
// Compare 4-byte vectors
|
||||
masm.andl(rcx, 0xfffffffc); // vector count (in bytes)
|
||||
masm.andl(rax, 0x00000002); // tail char (in bytes)
|
||||
masm.testl(rcx, rcx);
|
||||
masm.jccb(Assembler::zero, COMPARE_CHAR);
|
||||
masm.lea(rdi, Address(rdi, rcx, Address::times_1));
|
||||
masm.lea(rsi, Address(rsi, rcx, Address::times_1));
|
||||
masm.negl(rcx);
|
||||
|
||||
masm.bind(COMPARE_VECTORS);
|
||||
masm.movl(rbx, Address(rdi, rcx, Address::times_1));
|
||||
masm.cmpl(rbx, Address(rsi, rcx, Address::times_1));
|
||||
masm.jccb(Assembler::notEqual, RET_FALSE);
|
||||
masm.addl(rcx, 4);
|
||||
masm.jcc(Assembler::notZero, COMPARE_VECTORS);
|
||||
|
||||
// Compare trailing char (final 2 bytes), if any
|
||||
masm.bind(COMPARE_CHAR);
|
||||
masm.testl(rax, rax);
|
||||
masm.jccb(Assembler::zero, RET_TRUE);
|
||||
masm.load_unsigned_short(rbx, Address(rdi, 0));
|
||||
masm.load_unsigned_short(rcx, Address(rsi, 0));
|
||||
masm.cmpl(rbx, rcx);
|
||||
masm.jccb(Assembler::notEqual, RET_FALSE);
|
||||
|
||||
masm.bind(RET_TRUE);
|
||||
masm.movl(rax, 1); // return true
|
||||
masm.jmpb(DONE);
|
||||
|
||||
masm.bind(RET_FALSE);
|
||||
masm.xorl(rax, rax); // return false
|
||||
|
||||
masm.bind(DONE);
|
||||
%}
|
||||
|
||||
enc_class enc_String_IndexOf(eSIRegP str1, eDIRegP str2, regXD tmp1, eAXRegI tmp2,
|
||||
eCXRegI tmp3, eDXRegI tmp4, eBXRegI result) %{
|
||||
// SSE4.2 version
|
||||
Label LOAD_SUBSTR, PREP_FOR_SCAN, SCAN_TO_SUBSTR,
|
||||
SCAN_SUBSTR, RET_NEG_ONE, RET_NOT_FOUND, CLEANUP, DONE;
|
||||
MacroAssembler masm(&cbuf);
|
||||
|
||||
XMMRegister tmp1Reg = as_XMMRegister($tmp1$$reg);
|
||||
|
||||
// Get the first character position in both strings
|
||||
// [8] char array, [12] offset, [16] count
|
||||
int value_offset = java_lang_String::value_offset_in_bytes();
|
||||
int offset_offset = java_lang_String::offset_offset_in_bytes();
|
||||
int count_offset = java_lang_String::count_offset_in_bytes();
|
||||
int base_offset = arrayOopDesc::base_offset_in_bytes(T_CHAR);
|
||||
|
||||
// Get counts for string and substr
|
||||
masm.movl(rdx, Address(rsi, count_offset));
|
||||
masm.movl(rax, Address(rdi, count_offset));
|
||||
// Check for substr count > string count
|
||||
masm.cmpl(rax, rdx);
|
||||
masm.jcc(Assembler::greater, RET_NEG_ONE);
|
||||
|
||||
// Start the indexOf operation
|
||||
// Get start addr of string
|
||||
masm.movptr(rbx, Address(rsi, value_offset));
|
||||
masm.movl(rcx, Address(rsi, offset_offset));
|
||||
masm.lea(rsi, Address(rbx, rcx, Address::times_2, base_offset));
|
||||
masm.push(rsi);
|
||||
|
||||
// Get start addr of substr
|
||||
masm.movptr(rbx, Address(rdi, value_offset));
|
||||
masm.movl(rcx, Address(rdi, offset_offset));
|
||||
masm.lea(rdi, Address(rbx, rcx, Address::times_2, base_offset));
|
||||
masm.push(rdi);
|
||||
masm.push(rax);
|
||||
masm.jmpb(PREP_FOR_SCAN);
|
||||
|
||||
// Substr count saved at sp
|
||||
// Substr saved at sp+4
|
||||
// String saved at sp+8
|
||||
|
||||
// Prep to load substr for scan
|
||||
masm.bind(LOAD_SUBSTR);
|
||||
masm.movptr(rdi, Address(rsp, 4));
|
||||
masm.movl(rax, Address(rsp, 0));
|
||||
|
||||
// Load substr
|
||||
masm.bind(PREP_FOR_SCAN);
|
||||
masm.movdqu(tmp1Reg, Address(rdi, 0));
|
||||
masm.addl(rdx, 8); // prime the loop
|
||||
masm.subptr(rsi, 16);
|
||||
|
||||
// Scan string for substr in 16-byte vectors
|
||||
masm.bind(SCAN_TO_SUBSTR);
|
||||
masm.subl(rdx, 8);
|
||||
masm.addptr(rsi, 16);
|
||||
masm.pcmpestri(tmp1Reg, Address(rsi, 0), 0x0d);
|
||||
masm.jcc(Assembler::above, SCAN_TO_SUBSTR); // CF == 0 && ZF == 0
|
||||
masm.jccb(Assembler::aboveEqual, RET_NOT_FOUND); // CF == 0
|
||||
|
||||
// Fallthru: found a potential substr
|
||||
|
||||
// Make sure string is still long enough
|
||||
masm.subl(rdx, rcx);
|
||||
masm.cmpl(rdx, rax);
|
||||
masm.jccb(Assembler::negative, RET_NOT_FOUND);
|
||||
// Compute start addr of substr
|
||||
masm.lea(rsi, Address(rsi, rcx, Address::times_2));
|
||||
masm.movptr(rbx, rsi);
|
||||
|
||||
// Compare potential substr
|
||||
masm.addl(rdx, 8); // prime the loop
|
||||
masm.addl(rax, 8);
|
||||
masm.subptr(rsi, 16);
|
||||
masm.subptr(rdi, 16);
|
||||
|
||||
// Scan 16-byte vectors of string and substr
|
||||
masm.bind(SCAN_SUBSTR);
|
||||
masm.subl(rax, 8);
|
||||
masm.subl(rdx, 8);
|
||||
masm.addptr(rsi, 16);
|
||||
masm.addptr(rdi, 16);
|
||||
masm.movdqu(tmp1Reg, Address(rdi, 0));
|
||||
masm.pcmpestri(tmp1Reg, Address(rsi, 0), 0x0d);
|
||||
masm.jcc(Assembler::noOverflow, LOAD_SUBSTR); // OF == 0
|
||||
masm.jcc(Assembler::positive, SCAN_SUBSTR); // SF == 0
|
||||
|
||||
// Compute substr offset
|
||||
masm.movptr(rsi, Address(rsp, 8));
|
||||
masm.subptr(rbx, rsi);
|
||||
masm.shrl(rbx, 1);
|
||||
masm.jmpb(CLEANUP);
|
||||
|
||||
masm.bind(RET_NEG_ONE);
|
||||
masm.movl(rbx, -1);
|
||||
masm.jmpb(DONE);
|
||||
|
||||
masm.bind(RET_NOT_FOUND);
|
||||
masm.movl(rbx, -1);
|
||||
|
||||
masm.bind(CLEANUP);
|
||||
masm.addptr(rsp, 12);
|
||||
|
||||
masm.bind(DONE);
|
||||
%}
|
||||
|
||||
enc_class enc_Array_Equals(eDIRegP ary1, eSIRegP ary2, regXD tmp1, regXD tmp2,
|
||||
eBXRegI tmp3, eDXRegI tmp4, eAXRegI result) %{
|
||||
Label TRUE_LABEL, FALSE_LABEL, DONE, COMPARE_VECTORS, COMPARE_CHAR;
|
||||
MacroAssembler masm(&cbuf);
|
||||
|
||||
XMMRegister tmp1Reg = as_XMMRegister($tmp1$$reg);
|
||||
XMMRegister tmp2Reg = as_XMMRegister($tmp2$$reg);
|
||||
Register ary1Reg = as_Register($ary1$$reg);
|
||||
Register ary2Reg = as_Register($ary2$$reg);
|
||||
Register tmp3Reg = as_Register($tmp3$$reg);
|
||||
Register tmp4Reg = as_Register($tmp4$$reg);
|
||||
Register resultReg = as_Register($result$$reg);
|
||||
|
||||
int length_offset = arrayOopDesc::length_offset_in_bytes();
|
||||
int base_offset = arrayOopDesc::base_offset_in_bytes(T_CHAR);
|
||||
|
||||
// Check the input args
|
||||
masm.cmpl(ary1Reg, ary2Reg);
|
||||
masm.cmpptr(ary1Reg, ary2Reg);
|
||||
masm.jcc(Assembler::equal, TRUE_LABEL);
|
||||
masm.testl(ary1Reg, ary1Reg);
|
||||
masm.testptr(ary1Reg, ary1Reg);
|
||||
masm.jcc(Assembler::zero, FALSE_LABEL);
|
||||
masm.testl(ary2Reg, ary2Reg);
|
||||
masm.testptr(ary2Reg, ary2Reg);
|
||||
masm.jcc(Assembler::zero, FALSE_LABEL);
|
||||
|
||||
// Check the lengths
|
||||
masm.movl(tmp2Reg, Address(ary1Reg, length_offset));
|
||||
masm.movl(tmp4Reg, Address(ary1Reg, length_offset));
|
||||
masm.movl(resultReg, Address(ary2Reg, length_offset));
|
||||
masm.cmpl(tmp2Reg, resultReg);
|
||||
masm.cmpl(tmp4Reg, resultReg);
|
||||
masm.jcc(Assembler::notEqual, FALSE_LABEL);
|
||||
masm.testl(resultReg, resultReg);
|
||||
masm.jcc(Assembler::zero, TRUE_LABEL);
|
||||
|
||||
// Get the number of 4 byte vectors to compare
|
||||
masm.shrl(resultReg, 1);
|
||||
// Load array addrs
|
||||
masm.lea(ary1Reg, Address(ary1Reg, base_offset));
|
||||
masm.lea(ary2Reg, Address(ary2Reg, base_offset));
|
||||
|
||||
// Check for odd-length arrays
|
||||
masm.andl(tmp2Reg, 1);
|
||||
masm.testl(tmp2Reg, tmp2Reg);
|
||||
masm.jcc(Assembler::zero, COMPARE_LOOP_HDR);
|
||||
// Set byte count
|
||||
masm.shll(tmp4Reg, 1);
|
||||
masm.movl(resultReg, tmp4Reg);
|
||||
|
||||
// Compare 2-byte "tail" at end of arrays
|
||||
masm.load_unsigned_short(tmp1Reg, Address(ary1Reg, resultReg, Address::times_4, base_offset));
|
||||
masm.load_unsigned_short(tmp2Reg, Address(ary2Reg, resultReg, Address::times_4, base_offset));
|
||||
masm.cmpl(tmp1Reg, tmp2Reg);
|
||||
masm.jcc(Assembler::notEqual, FALSE_LABEL);
|
||||
if (UseSSE42Intrinsics) {
|
||||
// With SSE4.2, use double quad vector compare
|
||||
Label COMPARE_WIDE_VECTORS, COMPARE_TAIL;
|
||||
// Compare 16-byte vectors
|
||||
masm.andl(tmp4Reg, 0xfffffff0); // vector count (in bytes)
|
||||
masm.andl(resultReg, 0x0000000e); // tail count (in bytes)
|
||||
masm.testl(tmp4Reg, tmp4Reg);
|
||||
masm.jccb(Assembler::zero, COMPARE_TAIL);
|
||||
masm.lea(ary1Reg, Address(ary1Reg, tmp4Reg, Address::times_1));
|
||||
masm.lea(ary2Reg, Address(ary2Reg, tmp4Reg, Address::times_1));
|
||||
masm.negl(tmp4Reg);
|
||||
|
||||
masm.bind(COMPARE_WIDE_VECTORS);
|
||||
masm.movdqu(tmp1Reg, Address(ary1Reg, tmp4Reg, Address::times_1));
|
||||
masm.movdqu(tmp2Reg, Address(ary2Reg, tmp4Reg, Address::times_1));
|
||||
masm.pxor(tmp1Reg, tmp2Reg);
|
||||
masm.ptest(tmp1Reg, tmp1Reg);
|
||||
|
||||
masm.jccb(Assembler::notZero, FALSE_LABEL);
|
||||
masm.addl(tmp4Reg, 16);
|
||||
masm.jcc(Assembler::notZero, COMPARE_WIDE_VECTORS);
|
||||
masm.bind(COMPARE_TAIL);
|
||||
masm.movl(tmp4Reg, resultReg);
|
||||
// Fallthru to tail compare
|
||||
}
|
||||
|
||||
// Compare 4-byte vectors
|
||||
masm.andl(tmp4Reg, 0xfffffffc); // vector count (in bytes)
|
||||
masm.andl(resultReg, 0x00000002); // tail char (in bytes)
|
||||
masm.testl(tmp4Reg, tmp4Reg);
|
||||
masm.jccb(Assembler::zero, COMPARE_CHAR);
|
||||
masm.lea(ary1Reg, Address(ary1Reg, tmp4Reg, Address::times_1));
|
||||
masm.lea(ary2Reg, Address(ary2Reg, tmp4Reg, Address::times_1));
|
||||
masm.negl(tmp4Reg);
|
||||
|
||||
masm.bind(COMPARE_VECTORS);
|
||||
masm.movl(tmp3Reg, Address(ary1Reg, tmp4Reg, Address::times_1));
|
||||
masm.cmpl(tmp3Reg, Address(ary2Reg, tmp4Reg, Address::times_1));
|
||||
masm.jccb(Assembler::notEqual, FALSE_LABEL);
|
||||
masm.addl(tmp4Reg, 4);
|
||||
masm.jcc(Assembler::notZero, COMPARE_VECTORS);
|
||||
|
||||
// Compare trailing char (final 2 bytes), if any
|
||||
masm.bind(COMPARE_CHAR);
|
||||
masm.testl(resultReg, resultReg);
|
||||
masm.jcc(Assembler::zero, TRUE_LABEL);
|
||||
|
||||
// Setup compare loop
|
||||
masm.bind(COMPARE_LOOP_HDR);
|
||||
// Shift tmp1Reg and tmp2Reg to the last 4-byte boundary of the arrays
|
||||
masm.leal(tmp1Reg, Address(ary1Reg, resultReg, Address::times_4, base_offset));
|
||||
masm.leal(tmp2Reg, Address(ary2Reg, resultReg, Address::times_4, base_offset));
|
||||
masm.negl(resultReg);
|
||||
|
||||
// 4-byte-wide compare loop
|
||||
masm.bind(COMPARE_LOOP);
|
||||
masm.movl(ary1Reg, Address(tmp1Reg, resultReg, Address::times_4, 0));
|
||||
masm.movl(ary2Reg, Address(tmp2Reg, resultReg, Address::times_4, 0));
|
||||
masm.cmpl(ary1Reg, ary2Reg);
|
||||
masm.jcc(Assembler::notEqual, FALSE_LABEL);
|
||||
masm.increment(resultReg);
|
||||
masm.jcc(Assembler::notZero, COMPARE_LOOP);
|
||||
masm.jccb(Assembler::zero, TRUE_LABEL);
|
||||
masm.load_unsigned_short(tmp3Reg, Address(ary1Reg, 0));
|
||||
masm.load_unsigned_short(tmp4Reg, Address(ary2Reg, 0));
|
||||
masm.cmpl(tmp3Reg, tmp4Reg);
|
||||
masm.jccb(Assembler::notEqual, FALSE_LABEL);
|
||||
|
||||
masm.bind(TRUE_LABEL);
|
||||
masm.movl(resultReg, 1); // return true
|
||||
masm.jmp(DONE_LABEL);
|
||||
masm.jmpb(DONE);
|
||||
|
||||
masm.bind(FALSE_LABEL);
|
||||
masm.xorl(resultReg, resultReg); // return false
|
||||
|
||||
// That's it
|
||||
masm.bind(DONE_LABEL);
|
||||
masm.bind(DONE);
|
||||
%}
|
||||
|
||||
enc_class enc_pop_rdx() %{
|
||||
@ -4288,24 +4570,6 @@ encode %{
|
||||
emit_opcode(cbuf, 0xC8 + $src2$$reg);
|
||||
%}
|
||||
|
||||
enc_class enc_membar_acquire %{
|
||||
// Doug Lea believes this is not needed with current Sparcs and TSO.
|
||||
// MacroAssembler masm(&cbuf);
|
||||
// masm.membar();
|
||||
%}
|
||||
|
||||
enc_class enc_membar_release %{
|
||||
// Doug Lea believes this is not needed with current Sparcs and TSO.
|
||||
// MacroAssembler masm(&cbuf);
|
||||
// masm.membar();
|
||||
%}
|
||||
|
||||
enc_class enc_membar_volatile %{
|
||||
MacroAssembler masm(&cbuf);
|
||||
masm.membar(Assembler::Membar_mask_bits(Assembler::StoreLoad |
|
||||
Assembler::StoreStore));
|
||||
%}
|
||||
|
||||
// Atomically load the volatile long
|
||||
enc_class enc_loadL_volatile( memory mem, stackSlotL dst ) %{
|
||||
emit_opcode(cbuf,0xDF);
|
||||
@ -7498,9 +7762,9 @@ instruct membar_acquire() %{
|
||||
ins_cost(400);
|
||||
|
||||
size(0);
|
||||
format %{ "MEMBAR-acquire" %}
|
||||
ins_encode( enc_membar_acquire );
|
||||
ins_pipe(pipe_slow);
|
||||
format %{ "MEMBAR-acquire ! (empty encoding)" %}
|
||||
ins_encode();
|
||||
ins_pipe(empty);
|
||||
%}
|
||||
|
||||
instruct membar_acquire_lock() %{
|
||||
@ -7519,9 +7783,9 @@ instruct membar_release() %{
|
||||
ins_cost(400);
|
||||
|
||||
size(0);
|
||||
format %{ "MEMBAR-release" %}
|
||||
ins_encode( enc_membar_release );
|
||||
ins_pipe(pipe_slow);
|
||||
format %{ "MEMBAR-release ! (empty encoding)" %}
|
||||
ins_encode( );
|
||||
ins_pipe(empty);
|
||||
%}
|
||||
|
||||
instruct membar_release_lock() %{
|
||||
@ -7535,12 +7799,22 @@ instruct membar_release_lock() %{
|
||||
ins_pipe(empty);
|
||||
%}
|
||||
|
||||
instruct membar_volatile() %{
|
||||
instruct membar_volatile(eFlagsReg cr) %{
|
||||
match(MemBarVolatile);
|
||||
effect(KILL cr);
|
||||
ins_cost(400);
|
||||
|
||||
format %{ "MEMBAR-volatile" %}
|
||||
ins_encode( enc_membar_volatile );
|
||||
format %{
|
||||
$$template
|
||||
if (os::is_MP()) {
|
||||
$$emit$$"LOCK ADDL [ESP + #0], 0\t! membar_volatile"
|
||||
} else {
|
||||
$$emit$$"MEMBAR-volatile ! (empty encoding)"
|
||||
}
|
||||
%}
|
||||
ins_encode %{
|
||||
__ membar(Assembler::StoreLoad);
|
||||
%}
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
@ -12082,11 +12356,8 @@ instruct Repl2F_immXF0(regXD dst, immXF0 zero) %{
|
||||
ins_pipe( fpu_reg_reg );
|
||||
%}
|
||||
|
||||
|
||||
|
||||
// =======================================================================
|
||||
// fast clearing of an array
|
||||
|
||||
instruct rep_stos(eCXRegI cnt, eDIRegP base, eAXRegI zero, Universe dummy, eFlagsReg cr) %{
|
||||
match(Set dummy (ClearArray cnt base));
|
||||
effect(USE_KILL cnt, USE_KILL base, KILL zero, KILL cr);
|
||||
@ -12100,24 +12371,48 @@ instruct rep_stos(eCXRegI cnt, eDIRegP base, eAXRegI zero, Universe dummy, eFlag
|
||||
ins_pipe( pipe_slow );
|
||||
%}
|
||||
|
||||
instruct string_compare(eDIRegP str1, eSIRegP str2, eAXRegI tmp1, eBXRegI tmp2, eCXRegI result, eFlagsReg cr) %{
|
||||
instruct string_compare(eDIRegP str1, eSIRegP str2, regXD tmp1, regXD tmp2,
|
||||
eAXRegI tmp3, eBXRegI tmp4, eCXRegI result, eFlagsReg cr) %{
|
||||
match(Set result (StrComp str1 str2));
|
||||
effect(USE_KILL str1, USE_KILL str2, KILL tmp1, KILL tmp2, KILL cr);
|
||||
effect(TEMP tmp1, TEMP tmp2, USE_KILL str1, USE_KILL str2, KILL tmp3, KILL tmp4, KILL cr);
|
||||
//ins_cost(300);
|
||||
|
||||
format %{ "String Compare $str1,$str2 -> $result // KILL EAX, EBX" %}
|
||||
ins_encode( enc_String_Compare() );
|
||||
ins_encode( enc_String_Compare(str1, str2, tmp1, tmp2, tmp3, tmp4, result) );
|
||||
ins_pipe( pipe_slow );
|
||||
%}
|
||||
|
||||
// fast string equals
|
||||
instruct string_equals(eDIRegP str1, eSIRegP str2, regXD tmp1, regXD tmp2,
|
||||
eBXRegI tmp3, eCXRegI tmp4, eAXRegI result, eFlagsReg cr) %{
|
||||
match(Set result (StrEquals str1 str2));
|
||||
effect(TEMP tmp1, TEMP tmp2, USE_KILL str1, USE_KILL str2, KILL tmp3, KILL tmp4, KILL cr);
|
||||
|
||||
format %{ "String Equals $str1,$str2 -> $result // KILL EBX, ECX" %}
|
||||
ins_encode( enc_String_Equals(tmp1, tmp2, str1, str2, tmp3, tmp4, result) );
|
||||
ins_pipe( pipe_slow );
|
||||
%}
|
||||
|
||||
instruct string_indexof(eSIRegP str1, eDIRegP str2, regXD tmp1, eAXRegI tmp2,
|
||||
eCXRegI tmp3, eDXRegI tmp4, eBXRegI result, eFlagsReg cr) %{
|
||||
predicate(UseSSE42Intrinsics);
|
||||
match(Set result (StrIndexOf str1 str2));
|
||||
effect(TEMP tmp1, USE_KILL str1, USE_KILL str2, KILL tmp2, KILL tmp3, KILL tmp4, KILL cr);
|
||||
|
||||
format %{ "String IndexOf $str1,$str2 -> $result // KILL EAX, ECX, EDX" %}
|
||||
ins_encode( enc_String_IndexOf(str1, str2, tmp1, tmp2, tmp3, tmp4, result) );
|
||||
ins_pipe( pipe_slow );
|
||||
%}
|
||||
|
||||
// fast array equals
|
||||
instruct array_equals(eDIRegP ary1, eSIRegP ary2, eAXRegI tmp1, eBXRegI tmp2, eCXRegI result, eFlagsReg cr) %{
|
||||
instruct array_equals(eDIRegP ary1, eSIRegP ary2, regXD tmp1, regXD tmp2, eBXRegI tmp3,
|
||||
eDXRegI tmp4, eAXRegI result, eFlagsReg cr) %{
|
||||
match(Set result (AryEq ary1 ary2));
|
||||
effect(USE_KILL ary1, USE_KILL ary2, KILL tmp1, KILL tmp2, KILL cr);
|
||||
effect(TEMP tmp1, TEMP tmp2, USE_KILL ary1, USE_KILL ary2, KILL tmp3, KILL tmp4, KILL cr);
|
||||
//ins_cost(300);
|
||||
|
||||
format %{ "Array Equals $ary1,$ary2 -> $result // KILL EAX, EBX" %}
|
||||
ins_encode( enc_Array_Equals(ary1, ary2, tmp1, tmp2, result) );
|
||||
format %{ "Array Equals $ary1,$ary2 -> $result // KILL EBX, EDX" %}
|
||||
ins_encode( enc_Array_Equals(ary1, ary2, tmp1, tmp2, tmp3, tmp4, result) );
|
||||
ins_pipe( pipe_slow );
|
||||
%}
|
||||
|
||||
|
@ -3694,13 +3694,16 @@ encode %{
|
||||
}
|
||||
%}
|
||||
|
||||
enc_class enc_String_Compare()
|
||||
%{
|
||||
enc_class enc_String_Compare(rdi_RegP str1, rsi_RegP str2, regD tmp1, regD tmp2,
|
||||
rax_RegI tmp3, rbx_RegI tmp4, rcx_RegI result) %{
|
||||
Label RCX_GOOD_LABEL, LENGTH_DIFF_LABEL,
|
||||
POP_LABEL, DONE_LABEL, CONT_LABEL,
|
||||
WHILE_HEAD_LABEL;
|
||||
MacroAssembler masm(&cbuf);
|
||||
|
||||
XMMRegister tmp1Reg = as_XMMRegister($tmp1$$reg);
|
||||
XMMRegister tmp2Reg = as_XMMRegister($tmp2$$reg);
|
||||
|
||||
// Get the first character position in both strings
|
||||
// [8] char array, [12] offset, [16] count
|
||||
int value_offset = java_lang_String::value_offset_in_bytes();
|
||||
@ -3718,6 +3721,7 @@ encode %{
|
||||
// Compute the minimum of the string lengths(rsi) and the
|
||||
// difference of the string lengths (stack)
|
||||
|
||||
// do the conditional move stuff
|
||||
masm.movl(rdi, Address(rdi, count_offset));
|
||||
masm.movl(rsi, Address(rsi, count_offset));
|
||||
masm.movl(rcx, rdi);
|
||||
@ -3745,7 +3749,7 @@ encode %{
|
||||
Label LSkip2;
|
||||
// Check if the strings start at same location
|
||||
masm.cmpptr(rbx, rax);
|
||||
masm.jcc(Assembler::notEqual, LSkip2);
|
||||
masm.jccb(Assembler::notEqual, LSkip2);
|
||||
|
||||
// Check if the length difference is zero (from stack)
|
||||
masm.cmpl(Address(rsp, 0), 0x0);
|
||||
@ -3755,9 +3759,52 @@ encode %{
|
||||
masm.bind(LSkip2);
|
||||
}
|
||||
|
||||
// Advance to next character
|
||||
masm.addptr(rax, 2);
|
||||
masm.addptr(rbx, 2);
|
||||
|
||||
if (UseSSE42Intrinsics) {
|
||||
// With SSE4.2, use double quad vector compare
|
||||
Label COMPARE_VECTORS, VECTOR_NOT_EQUAL, COMPARE_TAIL;
|
||||
// Setup to compare 16-byte vectors
|
||||
masm.movl(rdi, rsi);
|
||||
masm.andl(rsi, 0xfffffff8); // rsi holds the vector count
|
||||
masm.andl(rdi, 0x00000007); // rdi holds the tail count
|
||||
masm.testl(rsi, rsi);
|
||||
masm.jccb(Assembler::zero, COMPARE_TAIL);
|
||||
|
||||
masm.lea(rax, Address(rax, rsi, Address::times_2));
|
||||
masm.lea(rbx, Address(rbx, rsi, Address::times_2));
|
||||
masm.negptr(rsi);
|
||||
|
||||
masm.bind(COMPARE_VECTORS);
|
||||
masm.movdqu(tmp1Reg, Address(rax, rsi, Address::times_2));
|
||||
masm.movdqu(tmp2Reg, Address(rbx, rsi, Address::times_2));
|
||||
masm.pxor(tmp1Reg, tmp2Reg);
|
||||
masm.ptest(tmp1Reg, tmp1Reg);
|
||||
masm.jccb(Assembler::notZero, VECTOR_NOT_EQUAL);
|
||||
masm.addptr(rsi, 8);
|
||||
masm.jcc(Assembler::notZero, COMPARE_VECTORS);
|
||||
masm.jmpb(COMPARE_TAIL);
|
||||
|
||||
// Mismatched characters in the vectors
|
||||
masm.bind(VECTOR_NOT_EQUAL);
|
||||
masm.lea(rax, Address(rax, rsi, Address::times_2));
|
||||
masm.lea(rbx, Address(rbx, rsi, Address::times_2));
|
||||
masm.movl(rdi, 8);
|
||||
|
||||
// Compare tail (< 8 chars), or rescan last vectors to
|
||||
// find 1st mismatched characters
|
||||
masm.bind(COMPARE_TAIL);
|
||||
masm.testl(rdi, rdi);
|
||||
masm.jccb(Assembler::zero, LENGTH_DIFF_LABEL);
|
||||
masm.movl(rsi, rdi);
|
||||
// Fallthru to tail compare
|
||||
}
|
||||
|
||||
// Shift RAX and RBX to the end of the arrays, negate min
|
||||
masm.lea(rax, Address(rax, rsi, Address::times_2, 2));
|
||||
masm.lea(rbx, Address(rbx, rsi, Address::times_2, 2));
|
||||
masm.lea(rax, Address(rax, rsi, Address::times_2, 0));
|
||||
masm.lea(rbx, Address(rbx, rsi, Address::times_2, 0));
|
||||
masm.negptr(rsi);
|
||||
|
||||
// Compare the rest of the characters
|
||||
@ -3765,93 +3812,329 @@ encode %{
|
||||
masm.load_unsigned_short(rcx, Address(rbx, rsi, Address::times_2, 0));
|
||||
masm.load_unsigned_short(rdi, Address(rax, rsi, Address::times_2, 0));
|
||||
masm.subl(rcx, rdi);
|
||||
masm.jcc(Assembler::notZero, POP_LABEL);
|
||||
masm.jccb(Assembler::notZero, POP_LABEL);
|
||||
masm.increment(rsi);
|
||||
masm.jcc(Assembler::notZero, WHILE_HEAD_LABEL);
|
||||
|
||||
// Strings are equal up to min length. Return the length difference.
|
||||
masm.bind(LENGTH_DIFF_LABEL);
|
||||
masm.pop(rcx);
|
||||
masm.jmp(DONE_LABEL);
|
||||
masm.jmpb(DONE_LABEL);
|
||||
|
||||
// Discard the stored length difference
|
||||
masm.bind(POP_LABEL);
|
||||
masm.addptr(rsp, 8);
|
||||
|
||||
|
||||
// That's it
|
||||
masm.bind(DONE_LABEL);
|
||||
%}
|
||||
|
||||
enc_class enc_Array_Equals(rdi_RegP ary1, rsi_RegP ary2, rax_RegI tmp1, rbx_RegI tmp2, rcx_RegI result) %{
|
||||
Label TRUE_LABEL, FALSE_LABEL, DONE_LABEL, COMPARE_LOOP_HDR, COMPARE_LOOP;
|
||||
enc_class enc_String_IndexOf(rsi_RegP str1, rdi_RegP str2, regD tmp1, rax_RegI tmp2,
|
||||
rcx_RegI tmp3, rdx_RegI tmp4, rbx_RegI result) %{
|
||||
// SSE4.2 version
|
||||
Label LOAD_SUBSTR, PREP_FOR_SCAN, SCAN_TO_SUBSTR,
|
||||
SCAN_SUBSTR, RET_NEG_ONE, RET_NOT_FOUND, CLEANUP, DONE;
|
||||
MacroAssembler masm(&cbuf);
|
||||
|
||||
Register ary1Reg = as_Register($ary1$$reg);
|
||||
Register ary2Reg = as_Register($ary2$$reg);
|
||||
Register tmp1Reg = as_Register($tmp1$$reg);
|
||||
Register tmp2Reg = as_Register($tmp2$$reg);
|
||||
Register resultReg = as_Register($result$$reg);
|
||||
XMMRegister tmp1Reg = as_XMMRegister($tmp1$$reg);
|
||||
|
||||
// Get the first character position in both strings
|
||||
// [8] char array, [12] offset, [16] count
|
||||
int value_offset = java_lang_String::value_offset_in_bytes();
|
||||
int offset_offset = java_lang_String::offset_offset_in_bytes();
|
||||
int count_offset = java_lang_String::count_offset_in_bytes();
|
||||
int base_offset = arrayOopDesc::base_offset_in_bytes(T_CHAR);
|
||||
|
||||
// Get counts for string and substr
|
||||
masm.movl(rdx, Address(rsi, count_offset));
|
||||
masm.movl(rax, Address(rdi, count_offset));
|
||||
// Check for substr count > string count
|
||||
masm.cmpl(rax, rdx);
|
||||
masm.jcc(Assembler::greater, RET_NEG_ONE);
|
||||
|
||||
// Start the indexOf operation
|
||||
// Get start addr of string
|
||||
masm.load_heap_oop(rbx, Address(rsi, value_offset));
|
||||
masm.movl(rcx, Address(rsi, offset_offset));
|
||||
masm.lea(rsi, Address(rbx, rcx, Address::times_2, base_offset));
|
||||
masm.push(rsi);
|
||||
|
||||
// Get start addr of substr
|
||||
masm.load_heap_oop(rbx, Address(rdi, value_offset));
|
||||
masm.movl(rcx, Address(rdi, offset_offset));
|
||||
masm.lea(rdi, Address(rbx, rcx, Address::times_2, base_offset));
|
||||
masm.push(rdi);
|
||||
masm.push(rax);
|
||||
masm.jmpb(PREP_FOR_SCAN);
|
||||
|
||||
// Substr count saved at sp
|
||||
// Substr saved at sp+8
|
||||
// String saved at sp+16
|
||||
|
||||
// Prep to load substr for scan
|
||||
masm.bind(LOAD_SUBSTR);
|
||||
masm.movptr(rdi, Address(rsp, 8));
|
||||
masm.movl(rax, Address(rsp, 0));
|
||||
|
||||
// Load substr
|
||||
masm.bind(PREP_FOR_SCAN);
|
||||
masm.movdqu(tmp1Reg, Address(rdi, 0));
|
||||
masm.addq(rdx, 8); // prime the loop
|
||||
masm.subptr(rsi, 16);
|
||||
|
||||
// Scan string for substr in 16-byte vectors
|
||||
masm.bind(SCAN_TO_SUBSTR);
|
||||
masm.subq(rdx, 8);
|
||||
masm.addptr(rsi, 16);
|
||||
masm.pcmpestri(tmp1Reg, Address(rsi, 0), 0x0d);
|
||||
masm.jcc(Assembler::above, SCAN_TO_SUBSTR);
|
||||
masm.jccb(Assembler::aboveEqual, RET_NOT_FOUND);
|
||||
|
||||
// Fallthru: found a potential substr
|
||||
|
||||
//Make sure string is still long enough
|
||||
masm.subl(rdx, rcx);
|
||||
masm.cmpl(rdx, rax);
|
||||
masm.jccb(Assembler::negative, RET_NOT_FOUND);
|
||||
// Compute start addr of substr
|
||||
masm.lea(rsi, Address(rsi, rcx, Address::times_2));
|
||||
masm.movptr(rbx, rsi);
|
||||
|
||||
// Compare potential substr
|
||||
masm.addq(rdx, 8); // prime the loop
|
||||
masm.addq(rax, 8);
|
||||
masm.subptr(rsi, 16);
|
||||
masm.subptr(rdi, 16);
|
||||
|
||||
// Scan 16-byte vectors of string and substr
|
||||
masm.bind(SCAN_SUBSTR);
|
||||
masm.subq(rax, 8);
|
||||
masm.subq(rdx, 8);
|
||||
masm.addptr(rsi, 16);
|
||||
masm.addptr(rdi, 16);
|
||||
masm.movdqu(tmp1Reg, Address(rdi, 0));
|
||||
masm.pcmpestri(tmp1Reg, Address(rsi, 0), 0x0d);
|
||||
masm.jcc(Assembler::noOverflow, LOAD_SUBSTR); // OF == 0
|
||||
masm.jcc(Assembler::positive, SCAN_SUBSTR); // SF == 0
|
||||
|
||||
// Compute substr offset
|
||||
masm.movptr(rsi, Address(rsp, 16));
|
||||
masm.subptr(rbx, rsi);
|
||||
masm.shrl(rbx, 1);
|
||||
masm.jmpb(CLEANUP);
|
||||
|
||||
masm.bind(RET_NEG_ONE);
|
||||
masm.movl(rbx, -1);
|
||||
masm.jmpb(DONE);
|
||||
|
||||
masm.bind(RET_NOT_FOUND);
|
||||
masm.movl(rbx, -1);
|
||||
|
||||
masm.bind(CLEANUP);
|
||||
masm.addptr(rsp, 24);
|
||||
|
||||
masm.bind(DONE);
|
||||
%}
|
||||
|
||||
enc_class enc_String_Equals(rdi_RegP str1, rsi_RegP str2, regD tmp1, regD tmp2,
|
||||
rbx_RegI tmp3, rcx_RegI tmp2, rax_RegI result) %{
|
||||
Label RET_TRUE, RET_FALSE, DONE, COMPARE_VECTORS, COMPARE_CHAR;
|
||||
MacroAssembler masm(&cbuf);
|
||||
|
||||
XMMRegister tmp1Reg = as_XMMRegister($tmp1$$reg);
|
||||
XMMRegister tmp2Reg = as_XMMRegister($tmp2$$reg);
|
||||
|
||||
int value_offset = java_lang_String::value_offset_in_bytes();
|
||||
int offset_offset = java_lang_String::offset_offset_in_bytes();
|
||||
int count_offset = java_lang_String::count_offset_in_bytes();
|
||||
int base_offset = arrayOopDesc::base_offset_in_bytes(T_CHAR);
|
||||
|
||||
// does source == target string?
|
||||
masm.cmpptr(rdi, rsi);
|
||||
masm.jcc(Assembler::equal, RET_TRUE);
|
||||
|
||||
// get and compare counts
|
||||
masm.movl(rcx, Address(rdi, count_offset));
|
||||
masm.movl(rax, Address(rsi, count_offset));
|
||||
masm.cmpl(rcx, rax);
|
||||
masm.jcc(Assembler::notEqual, RET_FALSE);
|
||||
masm.testl(rax, rax);
|
||||
masm.jcc(Assembler::zero, RET_TRUE);
|
||||
|
||||
// get source string offset and value
|
||||
masm.load_heap_oop(rbx, Address(rsi, value_offset));
|
||||
masm.movl(rax, Address(rsi, offset_offset));
|
||||
masm.lea(rsi, Address(rbx, rax, Address::times_2, base_offset));
|
||||
|
||||
// get compare string offset and value
|
||||
masm.load_heap_oop(rbx, Address(rdi, value_offset));
|
||||
masm.movl(rax, Address(rdi, offset_offset));
|
||||
masm.lea(rdi, Address(rbx, rax, Address::times_2, base_offset));
|
||||
|
||||
// Set byte count
|
||||
masm.shll(rcx, 1);
|
||||
masm.movl(rax, rcx);
|
||||
|
||||
if (UseSSE42Intrinsics) {
|
||||
// With SSE4.2, use double quad vector compare
|
||||
Label COMPARE_WIDE_VECTORS, COMPARE_TAIL;
|
||||
// Compare 16-byte vectors
|
||||
masm.andl(rcx, 0xfffffff0); // vector count (in bytes)
|
||||
masm.andl(rax, 0x0000000e); // tail count (in bytes)
|
||||
masm.testl(rcx, rcx);
|
||||
masm.jccb(Assembler::zero, COMPARE_TAIL);
|
||||
masm.lea(rdi, Address(rdi, rcx, Address::times_1));
|
||||
masm.lea(rsi, Address(rsi, rcx, Address::times_1));
|
||||
masm.negptr(rcx);
|
||||
|
||||
masm.bind(COMPARE_WIDE_VECTORS);
|
||||
masm.movdqu(tmp1Reg, Address(rdi, rcx, Address::times_1));
|
||||
masm.movdqu(tmp2Reg, Address(rsi, rcx, Address::times_1));
|
||||
masm.pxor(tmp1Reg, tmp2Reg);
|
||||
masm.ptest(tmp1Reg, tmp1Reg);
|
||||
masm.jccb(Assembler::notZero, RET_FALSE);
|
||||
masm.addptr(rcx, 16);
|
||||
masm.jcc(Assembler::notZero, COMPARE_WIDE_VECTORS);
|
||||
masm.bind(COMPARE_TAIL);
|
||||
masm.movl(rcx, rax);
|
||||
// Fallthru to tail compare
|
||||
}
|
||||
|
||||
// Compare 4-byte vectors
|
||||
masm.andl(rcx, 0xfffffffc); // vector count (in bytes)
|
||||
masm.andl(rax, 0x00000002); // tail char (in bytes)
|
||||
masm.testl(rcx, rcx);
|
||||
masm.jccb(Assembler::zero, COMPARE_CHAR);
|
||||
masm.lea(rdi, Address(rdi, rcx, Address::times_1));
|
||||
masm.lea(rsi, Address(rsi, rcx, Address::times_1));
|
||||
masm.negptr(rcx);
|
||||
|
||||
masm.bind(COMPARE_VECTORS);
|
||||
masm.movl(rbx, Address(rdi, rcx, Address::times_1));
|
||||
masm.cmpl(rbx, Address(rsi, rcx, Address::times_1));
|
||||
masm.jccb(Assembler::notEqual, RET_FALSE);
|
||||
masm.addptr(rcx, 4);
|
||||
masm.jcc(Assembler::notZero, COMPARE_VECTORS);
|
||||
|
||||
// Compare trailing char (final 2 bytes), if any
|
||||
masm.bind(COMPARE_CHAR);
|
||||
masm.testl(rax, rax);
|
||||
masm.jccb(Assembler::zero, RET_TRUE);
|
||||
masm.load_unsigned_short(rbx, Address(rdi, 0));
|
||||
masm.load_unsigned_short(rcx, Address(rsi, 0));
|
||||
masm.cmpl(rbx, rcx);
|
||||
masm.jccb(Assembler::notEqual, RET_FALSE);
|
||||
|
||||
masm.bind(RET_TRUE);
|
||||
masm.movl(rax, 1); // return true
|
||||
masm.jmpb(DONE);
|
||||
|
||||
masm.bind(RET_FALSE);
|
||||
masm.xorl(rax, rax); // return false
|
||||
|
||||
masm.bind(DONE);
|
||||
%}
|
||||
|
||||
enc_class enc_Array_Equals(rdi_RegP ary1, rsi_RegP ary2, regD tmp1, regD tmp2,
|
||||
rax_RegI tmp3, rbx_RegI tmp4, rcx_RegI result) %{
|
||||
Label TRUE_LABEL, FALSE_LABEL, DONE, COMPARE_VECTORS, COMPARE_CHAR;
|
||||
MacroAssembler masm(&cbuf);
|
||||
|
||||
XMMRegister tmp1Reg = as_XMMRegister($tmp1$$reg);
|
||||
XMMRegister tmp2Reg = as_XMMRegister($tmp2$$reg);
|
||||
Register ary1Reg = as_Register($ary1$$reg);
|
||||
Register ary2Reg = as_Register($ary2$$reg);
|
||||
Register tmp3Reg = as_Register($tmp3$$reg);
|
||||
Register tmp4Reg = as_Register($tmp4$$reg);
|
||||
Register resultReg = as_Register($result$$reg);
|
||||
|
||||
int length_offset = arrayOopDesc::length_offset_in_bytes();
|
||||
int base_offset = arrayOopDesc::base_offset_in_bytes(T_CHAR);
|
||||
|
||||
// Check the input args
|
||||
masm.cmpq(ary1Reg, ary2Reg);
|
||||
masm.cmpq(ary1Reg, ary2Reg);
|
||||
masm.jcc(Assembler::equal, TRUE_LABEL);
|
||||
masm.testq(ary1Reg, ary1Reg);
|
||||
masm.testq(ary1Reg, ary1Reg);
|
||||
masm.jcc(Assembler::zero, FALSE_LABEL);
|
||||
masm.testq(ary2Reg, ary2Reg);
|
||||
masm.testq(ary2Reg, ary2Reg);
|
||||
masm.jcc(Assembler::zero, FALSE_LABEL);
|
||||
|
||||
// Check the lengths
|
||||
masm.movl(tmp2Reg, Address(ary1Reg, length_offset));
|
||||
masm.movl(tmp4Reg, Address(ary1Reg, length_offset));
|
||||
masm.movl(resultReg, Address(ary2Reg, length_offset));
|
||||
masm.cmpl(tmp2Reg, resultReg);
|
||||
masm.cmpl(tmp4Reg, resultReg);
|
||||
masm.jcc(Assembler::notEqual, FALSE_LABEL);
|
||||
masm.testl(resultReg, resultReg);
|
||||
masm.jcc(Assembler::zero, TRUE_LABEL);
|
||||
|
||||
// Get the number of 4 byte vectors to compare
|
||||
masm.shrl(resultReg, 1);
|
||||
//load array address
|
||||
masm.lea(ary1Reg, Address(ary1Reg, base_offset));
|
||||
masm.lea(ary2Reg, Address(ary2Reg, base_offset));
|
||||
|
||||
// Check for odd-length arrays
|
||||
masm.andl(tmp2Reg, 1);
|
||||
masm.testl(tmp2Reg, tmp2Reg);
|
||||
masm.jcc(Assembler::zero, COMPARE_LOOP_HDR);
|
||||
//set byte count
|
||||
masm.shll(tmp4Reg, 1);
|
||||
masm.movl(resultReg,tmp4Reg);
|
||||
|
||||
// Compare 2-byte "tail" at end of arrays
|
||||
masm.load_unsigned_short(tmp1Reg, Address(ary1Reg, resultReg, Address::times_4, base_offset));
|
||||
masm.load_unsigned_short(tmp2Reg, Address(ary2Reg, resultReg, Address::times_4, base_offset));
|
||||
masm.cmpl(tmp1Reg, tmp2Reg);
|
||||
masm.jcc(Assembler::notEqual, FALSE_LABEL);
|
||||
if (UseSSE42Intrinsics){
|
||||
// With SSE4.2, use double quad vector compare
|
||||
Label COMPARE_WIDE_VECTORS, COMPARE_TAIL;
|
||||
// Compare 16-byte vectors
|
||||
masm.andl(tmp4Reg, 0xfffffff0); // vector count (in bytes)
|
||||
masm.andl(resultReg, 0x0000000e); // tail count (in bytes)
|
||||
masm.testl(tmp4Reg, tmp4Reg);
|
||||
masm.jccb(Assembler::zero, COMPARE_TAIL);
|
||||
masm.lea(ary1Reg, Address(ary1Reg, tmp4Reg, Address::times_1));
|
||||
masm.lea(ary2Reg, Address(ary2Reg, tmp4Reg, Address::times_1));
|
||||
masm.negptr(tmp4Reg);
|
||||
|
||||
masm.bind(COMPARE_WIDE_VECTORS);
|
||||
masm.movdqu(tmp1Reg, Address(ary1Reg, tmp4Reg, Address::times_1));
|
||||
masm.movdqu(tmp2Reg, Address(ary2Reg, tmp4Reg, Address::times_1));
|
||||
masm.pxor(tmp1Reg, tmp2Reg);
|
||||
masm.ptest(tmp1Reg, tmp1Reg);
|
||||
|
||||
masm.jccb(Assembler::notZero, FALSE_LABEL);
|
||||
masm.addptr(tmp4Reg, 16);
|
||||
masm.jcc(Assembler::notZero, COMPARE_WIDE_VECTORS);
|
||||
masm.bind(COMPARE_TAIL);
|
||||
masm.movl(tmp4Reg, resultReg);
|
||||
// Fallthru to tail compare
|
||||
}
|
||||
|
||||
// Compare 4-byte vectors
|
||||
masm.andl(tmp4Reg, 0xfffffffc); // vector count (in bytes)
|
||||
masm.andl(resultReg, 0x00000002); // tail char (in bytes)
|
||||
masm.testl(tmp4Reg, tmp4Reg); //if tmp2 == 0, only compare char
|
||||
masm.jccb(Assembler::zero, COMPARE_CHAR);
|
||||
masm.lea(ary1Reg, Address(ary1Reg, tmp4Reg, Address::times_1));
|
||||
masm.lea(ary2Reg, Address(ary2Reg, tmp4Reg, Address::times_1));
|
||||
masm.negptr(tmp4Reg);
|
||||
|
||||
masm.bind(COMPARE_VECTORS);
|
||||
masm.movl(tmp3Reg, Address(ary1Reg, tmp4Reg, Address::times_1));
|
||||
masm.cmpl(tmp3Reg, Address(ary2Reg, tmp4Reg, Address::times_1));
|
||||
masm.jccb(Assembler::notEqual, FALSE_LABEL);
|
||||
masm.addptr(tmp4Reg, 4);
|
||||
masm.jcc(Assembler::notZero, COMPARE_VECTORS);
|
||||
|
||||
// Compare trailing char (final 2 bytes), if any
|
||||
masm.bind(COMPARE_CHAR);
|
||||
masm.testl(resultReg, resultReg);
|
||||
masm.jcc(Assembler::zero, TRUE_LABEL);
|
||||
|
||||
// Setup compare loop
|
||||
masm.bind(COMPARE_LOOP_HDR);
|
||||
// Shift tmp1Reg and tmp2Reg to the last 4-byte boundary of the arrays
|
||||
masm.leaq(tmp1Reg, Address(ary1Reg, resultReg, Address::times_4, base_offset));
|
||||
masm.leaq(tmp2Reg, Address(ary2Reg, resultReg, Address::times_4, base_offset));
|
||||
masm.negq(resultReg);
|
||||
|
||||
// 4-byte-wide compare loop
|
||||
masm.bind(COMPARE_LOOP);
|
||||
masm.movl(ary1Reg, Address(tmp1Reg, resultReg, Address::times_4, 0));
|
||||
masm.movl(ary2Reg, Address(tmp2Reg, resultReg, Address::times_4, 0));
|
||||
masm.cmpl(ary1Reg, ary2Reg);
|
||||
masm.jcc(Assembler::notEqual, FALSE_LABEL);
|
||||
masm.incrementq(resultReg);
|
||||
masm.jcc(Assembler::notZero, COMPARE_LOOP);
|
||||
masm.jccb(Assembler::zero, TRUE_LABEL);
|
||||
masm.load_unsigned_short(tmp3Reg, Address(ary1Reg, 0));
|
||||
masm.load_unsigned_short(tmp4Reg, Address(ary2Reg, 0));
|
||||
masm.cmpl(tmp3Reg, tmp4Reg);
|
||||
masm.jccb(Assembler::notEqual, FALSE_LABEL);
|
||||
|
||||
masm.bind(TRUE_LABEL);
|
||||
masm.movl(resultReg, 1); // return true
|
||||
masm.jmp(DONE_LABEL);
|
||||
masm.jmpb(DONE);
|
||||
|
||||
masm.bind(FALSE_LABEL);
|
||||
masm.xorl(resultReg, resultReg); // return false
|
||||
|
||||
// That's it
|
||||
masm.bind(DONE_LABEL);
|
||||
masm.bind(DONE);
|
||||
%}
|
||||
|
||||
enc_class enc_rethrow()
|
||||
@ -4162,33 +4445,6 @@ encode %{
|
||||
// done:
|
||||
%}
|
||||
|
||||
enc_class enc_membar_acquire
|
||||
%{
|
||||
// [jk] not needed currently, if you enable this and it really
|
||||
// emits code don't forget to the remove the "size(0)" line in
|
||||
// membar_acquire()
|
||||
// MacroAssembler masm(&cbuf);
|
||||
// masm.membar(Assembler::Membar_mask_bits(Assembler::LoadStore |
|
||||
// Assembler::LoadLoad));
|
||||
%}
|
||||
|
||||
enc_class enc_membar_release
|
||||
%{
|
||||
// [jk] not needed currently, if you enable this and it really
|
||||
// emits code don't forget to the remove the "size(0)" line in
|
||||
// membar_release()
|
||||
// MacroAssembler masm(&cbuf);
|
||||
// masm.membar(Assembler::Membar_mask_bits(Assembler::LoadStore |
|
||||
// Assembler::StoreStore));
|
||||
%}
|
||||
|
||||
enc_class enc_membar_volatile
|
||||
%{
|
||||
MacroAssembler masm(&cbuf);
|
||||
masm.membar(Assembler::Membar_mask_bits(Assembler::StoreLoad |
|
||||
Assembler::StoreStore));
|
||||
%}
|
||||
|
||||
// Safepoint Poll. This polls the safepoint page, and causes an
|
||||
// exception if it is not readable. Unfortunately, it kills
|
||||
// RFLAGS in the process.
|
||||
@ -5114,7 +5370,7 @@ operand regF()
|
||||
%}
|
||||
|
||||
// Double register operands
|
||||
operand regD()
|
||||
operand regD()
|
||||
%{
|
||||
constraint(ALLOC_IN_RC(double_reg));
|
||||
match(RegD);
|
||||
@ -7458,7 +7714,7 @@ instruct membar_acquire()
|
||||
ins_cost(0);
|
||||
|
||||
size(0);
|
||||
format %{ "MEMBAR-acquire" %}
|
||||
format %{ "MEMBAR-acquire ! (empty encoding)" %}
|
||||
ins_encode();
|
||||
ins_pipe(empty);
|
||||
%}
|
||||
@ -7481,7 +7737,7 @@ instruct membar_release()
|
||||
ins_cost(0);
|
||||
|
||||
size(0);
|
||||
format %{ "MEMBAR-release" %}
|
||||
format %{ "MEMBAR-release ! (empty encoding)" %}
|
||||
ins_encode();
|
||||
ins_pipe(empty);
|
||||
%}
|
||||
@ -7498,13 +7754,22 @@ instruct membar_release_lock()
|
||||
ins_pipe(empty);
|
||||
%}
|
||||
|
||||
instruct membar_volatile()
|
||||
%{
|
||||
instruct membar_volatile(rFlagsReg cr) %{
|
||||
match(MemBarVolatile);
|
||||
effect(KILL cr);
|
||||
ins_cost(400);
|
||||
|
||||
format %{ "MEMBAR-volatile" %}
|
||||
ins_encode(enc_membar_volatile);
|
||||
format %{
|
||||
$$template
|
||||
if (os::is_MP()) {
|
||||
$$emit$$"lock addl [rsp + #0], 0\t! membar_volatile"
|
||||
} else {
|
||||
$$emit$$"MEMBAR-volatile ! (empty encoding)"
|
||||
}
|
||||
%}
|
||||
ins_encode %{
|
||||
__ membar(Assembler::StoreLoad);
|
||||
%}
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
@ -11558,27 +11823,52 @@ instruct rep_stos(rcx_RegL cnt, rdi_RegP base, rax_RegI zero, Universe dummy,
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
instruct string_compare(rdi_RegP str1, rsi_RegP str2, rax_RegI tmp1,
|
||||
rbx_RegI tmp2, rcx_RegI result, rFlagsReg cr)
|
||||
instruct string_compare(rdi_RegP str1, rsi_RegP str2, regD tmp1, regD tmp2,
|
||||
rax_RegI tmp3, rbx_RegI tmp4, rcx_RegI result, rFlagsReg cr)
|
||||
%{
|
||||
match(Set result (StrComp str1 str2));
|
||||
effect(USE_KILL str1, USE_KILL str2, KILL tmp1, KILL tmp2, KILL cr);
|
||||
effect(TEMP tmp1, TEMP tmp2, USE_KILL str1, USE_KILL str2, KILL tmp3, KILL tmp4, KILL cr);
|
||||
//ins_cost(300);
|
||||
|
||||
format %{ "String Compare $str1, $str2 -> $result // XXX KILL RAX, RBX" %}
|
||||
ins_encode( enc_String_Compare() );
|
||||
ins_encode( enc_String_Compare(str1, str2, tmp1, tmp2, tmp3, tmp4, result) );
|
||||
ins_pipe( pipe_slow );
|
||||
%}
|
||||
|
||||
instruct string_indexof(rsi_RegP str1, rdi_RegP str2, regD tmp1, rax_RegI tmp2,
|
||||
rcx_RegI tmp3, rdx_RegI tmp4, rbx_RegI result, rFlagsReg cr)
|
||||
%{
|
||||
predicate(UseSSE42Intrinsics);
|
||||
match(Set result (StrIndexOf str1 str2));
|
||||
effect(TEMP tmp1, USE_KILL str1, USE_KILL str2, KILL tmp2, KILL tmp3, KILL tmp4, KILL cr);
|
||||
|
||||
format %{ "String IndexOf $str1,$str2 -> $result // KILL RAX, RCX, RDX" %}
|
||||
ins_encode( enc_String_IndexOf(str1, str2, tmp1, tmp2, tmp3, tmp4, result) );
|
||||
ins_pipe( pipe_slow );
|
||||
%}
|
||||
|
||||
// fast string equals
|
||||
instruct string_equals(rdi_RegP str1, rsi_RegP str2, regD tmp1, regD tmp2, rbx_RegI tmp3,
|
||||
rcx_RegI tmp4, rax_RegI result, rFlagsReg cr)
|
||||
%{
|
||||
match(Set result (StrEquals str1 str2));
|
||||
effect(TEMP tmp1, TEMP tmp2, USE_KILL str1, USE_KILL str2, KILL tmp3, KILL tmp4, KILL cr);
|
||||
|
||||
format %{ "String Equals $str1,$str2 -> $result // KILL RBX, RCX" %}
|
||||
ins_encode( enc_String_Equals(str1, str2, tmp1, tmp2, tmp3, tmp4, result) );
|
||||
ins_pipe( pipe_slow );
|
||||
%}
|
||||
|
||||
// fast array equals
|
||||
instruct array_equals(rdi_RegP ary1, rsi_RegP ary2, rax_RegI tmp1,
|
||||
rbx_RegI tmp2, rcx_RegI result, rFlagsReg cr) %{
|
||||
instruct array_equals(rdi_RegP ary1, rsi_RegP ary2, regD tmp1, regD tmp2, rax_RegI tmp3,
|
||||
rbx_RegI tmp4, rcx_RegI result, rFlagsReg cr)
|
||||
%{
|
||||
match(Set result (AryEq ary1 ary2));
|
||||
effect(USE_KILL ary1, USE_KILL ary2, KILL tmp1, KILL tmp2, KILL cr);
|
||||
effect(TEMP tmp1, TEMP tmp2, USE_KILL ary1, USE_KILL ary2, KILL tmp3, KILL tmp4, KILL cr);
|
||||
//ins_cost(300);
|
||||
|
||||
format %{ "Array Equals $ary1,$ary2 -> $result // KILL RAX, RBX" %}
|
||||
ins_encode( enc_Array_Equals(ary1, ary2, tmp1, tmp2, result) );
|
||||
format %{ "Array Equals $ary1,$ary2 -> $result // KILL RAX, RBX" %}
|
||||
ins_encode( enc_Array_Equals(ary1, ary2, tmp1, tmp2, tmp3, tmp4, result) );
|
||||
ins_pipe( pipe_slow );
|
||||
%}
|
||||
|
||||
|
@ -1518,21 +1518,51 @@ const char* os::dll_file_extension() { return ".so"; }
|
||||
|
||||
const char* os::get_temp_directory() { return "/tmp/"; }
|
||||
|
||||
void os::dll_build_name(
|
||||
char* buffer, size_t buflen, const char* pname, const char* fname) {
|
||||
// copied from libhpi
|
||||
static bool file_exists(const char* filename) {
|
||||
struct stat statbuf;
|
||||
if (filename == NULL || strlen(filename) == 0) {
|
||||
return false;
|
||||
}
|
||||
return os::stat(filename, &statbuf) == 0;
|
||||
}
|
||||
|
||||
void os::dll_build_name(char* buffer, size_t buflen,
|
||||
const char* pname, const char* fname) {
|
||||
// Copied from libhpi
|
||||
const size_t pnamelen = pname ? strlen(pname) : 0;
|
||||
|
||||
/* Quietly truncate on buffer overflow. Should be an error. */
|
||||
// Quietly truncate on buffer overflow. Should be an error.
|
||||
if (pnamelen + strlen(fname) + 10 > (size_t) buflen) {
|
||||
*buffer = '\0';
|
||||
return;
|
||||
}
|
||||
|
||||
if (pnamelen == 0) {
|
||||
sprintf(buffer, "lib%s.so", fname);
|
||||
snprintf(buffer, buflen, "lib%s.so", fname);
|
||||
} else if (strchr(pname, *os::path_separator()) != NULL) {
|
||||
int n;
|
||||
char** pelements = split_path(pname, &n);
|
||||
for (int i = 0 ; i < n ; i++) {
|
||||
// Really shouldn't be NULL, but check can't hurt
|
||||
if (pelements[i] == NULL || strlen(pelements[i]) == 0) {
|
||||
continue; // skip the empty path values
|
||||
}
|
||||
snprintf(buffer, buflen, "%s/lib%s.so", pelements[i], fname);
|
||||
if (file_exists(buffer)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// release the storage
|
||||
for (int i = 0 ; i < n ; i++) {
|
||||
if (pelements[i] != NULL) {
|
||||
FREE_C_HEAP_ARRAY(char, pelements[i]);
|
||||
}
|
||||
}
|
||||
if (pelements != NULL) {
|
||||
FREE_C_HEAP_ARRAY(char*, pelements);
|
||||
}
|
||||
} else {
|
||||
sprintf(buffer, "%s/lib%s.so", pname, fname);
|
||||
snprintf(buffer, buflen, "%s/lib%s.so", pname, fname);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2269,15 +2299,16 @@ void linux_wrap_code(char* base, size_t size) {
|
||||
// All it does is to check if there are enough free pages
|
||||
// left at the time of mmap(). This could be a potential
|
||||
// problem.
|
||||
bool os::commit_memory(char* addr, size_t size) {
|
||||
uintptr_t res = (uintptr_t) ::mmap(addr, size,
|
||||
PROT_READ|PROT_WRITE|PROT_EXEC,
|
||||
bool os::commit_memory(char* addr, size_t size, bool exec) {
|
||||
int prot = exec ? PROT_READ|PROT_WRITE|PROT_EXEC : PROT_READ|PROT_WRITE;
|
||||
uintptr_t res = (uintptr_t) ::mmap(addr, size, prot,
|
||||
MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0);
|
||||
return res != (uintptr_t) MAP_FAILED;
|
||||
}
|
||||
|
||||
bool os::commit_memory(char* addr, size_t size, size_t alignment_hint) {
|
||||
return commit_memory(addr, size);
|
||||
bool os::commit_memory(char* addr, size_t size, size_t alignment_hint,
|
||||
bool exec) {
|
||||
return commit_memory(addr, size, exec);
|
||||
}
|
||||
|
||||
void os::realign_memory(char *addr, size_t bytes, size_t alignment_hint) { }
|
||||
@ -2417,8 +2448,7 @@ os::Linux::numa_interleave_memory_func_t os::Linux::_numa_interleave_memory;
|
||||
unsigned long* os::Linux::_numa_all_nodes;
|
||||
|
||||
bool os::uncommit_memory(char* addr, size_t size) {
|
||||
return ::mmap(addr, size,
|
||||
PROT_READ|PROT_WRITE|PROT_EXEC,
|
||||
return ::mmap(addr, size, PROT_NONE,
|
||||
MAP_PRIVATE|MAP_FIXED|MAP_NORESERVE|MAP_ANONYMOUS, -1, 0)
|
||||
!= MAP_FAILED;
|
||||
}
|
||||
@ -2441,7 +2471,9 @@ static char* anon_mmap(char* requested_addr, size_t bytes, bool fixed) {
|
||||
flags |= MAP_FIXED;
|
||||
}
|
||||
|
||||
addr = (char*)::mmap(requested_addr, bytes, PROT_READ|PROT_WRITE|PROT_EXEC,
|
||||
// Map uncommitted pages PROT_READ and PROT_WRITE, change access
|
||||
// to PROT_EXEC if executable when we commit the page.
|
||||
addr = (char*)::mmap(requested_addr, bytes, PROT_READ|PROT_WRITE,
|
||||
flags, -1, 0);
|
||||
|
||||
if (addr != MAP_FAILED) {
|
||||
@ -2582,7 +2614,9 @@ bool os::large_page_init() {
|
||||
#define SHM_HUGETLB 04000
|
||||
#endif
|
||||
|
||||
char* os::reserve_memory_special(size_t bytes, char* req_addr) {
|
||||
char* os::reserve_memory_special(size_t bytes, char* req_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, "only for large pages");
|
||||
|
||||
key_t key = IPC_PRIVATE;
|
||||
|
@ -1827,21 +1827,51 @@ const char* os::dll_file_extension() { return ".so"; }
|
||||
|
||||
const char* os::get_temp_directory() { return "/tmp/"; }
|
||||
|
||||
void os::dll_build_name(
|
||||
char* buffer, size_t buflen, const char* pname, const char* fname) {
|
||||
// copied from libhpi
|
||||
static bool file_exists(const char* filename) {
|
||||
struct stat statbuf;
|
||||
if (filename == NULL || strlen(filename) == 0) {
|
||||
return false;
|
||||
}
|
||||
return os::stat(filename, &statbuf) == 0;
|
||||
}
|
||||
|
||||
void os::dll_build_name(char* buffer, size_t buflen,
|
||||
const char* pname, const char* fname) {
|
||||
// Copied from libhpi
|
||||
const size_t pnamelen = pname ? strlen(pname) : 0;
|
||||
|
||||
/* Quietly truncate on buffer overflow. Should be an error. */
|
||||
// Quietly truncate on buffer overflow. Should be an error.
|
||||
if (pnamelen + strlen(fname) + 10 > (size_t) buflen) {
|
||||
*buffer = '\0';
|
||||
return;
|
||||
}
|
||||
|
||||
if (pnamelen == 0) {
|
||||
sprintf(buffer, "lib%s.so", fname);
|
||||
snprintf(buffer, buflen, "lib%s.so", fname);
|
||||
} else if (strchr(pname, *os::path_separator()) != NULL) {
|
||||
int n;
|
||||
char** pelements = split_path(pname, &n);
|
||||
for (int i = 0 ; i < n ; i++) {
|
||||
// really shouldn't be NULL but what the heck, check can't hurt
|
||||
if (pelements[i] == NULL || strlen(pelements[i]) == 0) {
|
||||
continue; // skip the empty path values
|
||||
}
|
||||
snprintf(buffer, buflen, "%s/lib%s.so", pelements[i], fname);
|
||||
if (file_exists(buffer)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// release the storage
|
||||
for (int i = 0 ; i < n ; i++) {
|
||||
if (pelements[i] != NULL) {
|
||||
FREE_C_HEAP_ARRAY(char, pelements[i]);
|
||||
}
|
||||
}
|
||||
if (pelements != NULL) {
|
||||
FREE_C_HEAP_ARRAY(char*, pelements);
|
||||
}
|
||||
} else {
|
||||
sprintf(buffer, "%s/lib%s.so", pname, fname);
|
||||
snprintf(buffer, buflen, "%s/lib%s.so", pname, fname);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2623,15 +2653,16 @@ int os::vm_allocation_granularity() {
|
||||
return page_size;
|
||||
}
|
||||
|
||||
bool os::commit_memory(char* addr, size_t bytes) {
|
||||
bool os::commit_memory(char* addr, size_t bytes, bool exec) {
|
||||
int prot = exec ? PROT_READ|PROT_WRITE|PROT_EXEC : PROT_READ|PROT_WRITE;
|
||||
size_t size = bytes;
|
||||
return
|
||||
NULL != Solaris::mmap_chunk(addr, size, MAP_PRIVATE|MAP_FIXED,
|
||||
PROT_READ | PROT_WRITE | PROT_EXEC);
|
||||
NULL != Solaris::mmap_chunk(addr, size, MAP_PRIVATE|MAP_FIXED, prot);
|
||||
}
|
||||
|
||||
bool os::commit_memory(char* addr, size_t bytes, size_t alignment_hint) {
|
||||
if (commit_memory(addr, bytes)) {
|
||||
bool os::commit_memory(char* addr, size_t bytes, size_t alignment_hint,
|
||||
bool exec) {
|
||||
if (commit_memory(addr, bytes, exec)) {
|
||||
if (UseMPSS && 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
|
||||
@ -3220,7 +3251,9 @@ bool os::Solaris::set_mpss_range(caddr_t start, size_t bytes, size_t align) {
|
||||
return true;
|
||||
}
|
||||
|
||||
char* os::reserve_memory_special(size_t bytes, char* addr) {
|
||||
char* os::reserve_memory_special(size_t bytes, 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");
|
||||
|
||||
size_t size = bytes;
|
||||
|
@ -1004,26 +1004,61 @@ const char * os::get_temp_directory()
|
||||
}
|
||||
}
|
||||
|
||||
void os::dll_build_name(char *holder, size_t holderlen,
|
||||
const char* pname, const char* fname)
|
||||
{
|
||||
// copied from libhpi
|
||||
const size_t pnamelen = pname ? strlen(pname) : 0;
|
||||
const char c = (pnamelen > 0) ? pname[pnamelen-1] : 0;
|
||||
static bool file_exists(const char* filename) {
|
||||
if (filename == NULL || strlen(filename) == 0) {
|
||||
return false;
|
||||
}
|
||||
return GetFileAttributes(filename) != INVALID_FILE_ATTRIBUTES;
|
||||
}
|
||||
|
||||
/* Quietly truncates on buffer overflow. Should be an error. */
|
||||
if (pnamelen + strlen(fname) + 10 > holderlen) {
|
||||
*holder = '\0';
|
||||
return;
|
||||
}
|
||||
void os::dll_build_name(char *buffer, size_t buflen,
|
||||
const char* pname, const char* fname) {
|
||||
// Copied from libhpi
|
||||
const size_t pnamelen = pname ? strlen(pname) : 0;
|
||||
const char c = (pnamelen > 0) ? pname[pnamelen-1] : 0;
|
||||
|
||||
if (pnamelen == 0) {
|
||||
sprintf(holder, "%s.dll", fname);
|
||||
} else if (c == ':' || c == '\\') {
|
||||
sprintf(holder, "%s%s.dll", pname, fname);
|
||||
} else {
|
||||
sprintf(holder, "%s\\%s.dll", pname, fname);
|
||||
// Quietly truncates on buffer overflow. Should be an error.
|
||||
if (pnamelen + strlen(fname) + 10 > buflen) {
|
||||
*buffer = '\0';
|
||||
return;
|
||||
}
|
||||
|
||||
if (pnamelen == 0) {
|
||||
jio_snprintf(buffer, buflen, "%s.dll", fname);
|
||||
} else if (c == ':' || c == '\\') {
|
||||
jio_snprintf(buffer, buflen, "%s%s.dll", pname, fname);
|
||||
} else if (strchr(pname, *os::path_separator()) != NULL) {
|
||||
int n;
|
||||
char** pelements = split_path(pname, &n);
|
||||
for (int i = 0 ; i < n ; i++) {
|
||||
char* path = pelements[i];
|
||||
// Really shouldn't be NULL, but check can't hurt
|
||||
size_t plen = (path == NULL) ? 0 : strlen(path);
|
||||
if (plen == 0) {
|
||||
continue; // skip the empty path values
|
||||
}
|
||||
const char lastchar = path[plen - 1];
|
||||
if (lastchar == ':' || lastchar == '\\') {
|
||||
jio_snprintf(buffer, buflen, "%s%s.dll", path, fname);
|
||||
} else {
|
||||
jio_snprintf(buffer, buflen, "%s\\%s.dll", path, fname);
|
||||
}
|
||||
if (file_exists(buffer)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// release the storage
|
||||
for (int i = 0 ; i < n ; i++) {
|
||||
if (pelements[i] != NULL) {
|
||||
FREE_C_HEAP_ARRAY(char, pelements[i]);
|
||||
}
|
||||
}
|
||||
if (pelements != NULL) {
|
||||
FREE_C_HEAP_ARRAY(char*, pelements);
|
||||
}
|
||||
} else {
|
||||
jio_snprintf(buffer, buflen, "%s\\%s.dll", pname, fname);
|
||||
}
|
||||
}
|
||||
|
||||
// Needs to be in os specific directory because windows requires another
|
||||
@ -2189,7 +2224,8 @@ LONG WINAPI topLevelExceptionFilter(struct _EXCEPTION_POINTERS* exceptionInfo) {
|
||||
if (addr > thread->stack_yellow_zone_base() && addr < thread->stack_base() ) {
|
||||
addr = (address)((uintptr_t)addr &
|
||||
(~((uintptr_t)os::vm_page_size() - (uintptr_t)1)));
|
||||
os::commit_memory( (char *)addr, thread->stack_base() - addr );
|
||||
os::commit_memory((char *)addr, thread->stack_base() - addr,
|
||||
false );
|
||||
return EXCEPTION_CONTINUE_EXECUTION;
|
||||
}
|
||||
else
|
||||
@ -2565,8 +2601,7 @@ char* os::reserve_memory(size_t bytes, char* addr, size_t alignment_hint) {
|
||||
assert((size_t)addr % os::vm_allocation_granularity() == 0,
|
||||
"reserve alignment");
|
||||
assert(bytes % os::vm_allocation_granularity() == 0, "reserve block size");
|
||||
char* res = (char*)VirtualAlloc(addr, bytes, MEM_RESERVE,
|
||||
PAGE_EXECUTE_READWRITE);
|
||||
char* res = (char*)VirtualAlloc(addr, bytes, MEM_RESERVE, PAGE_READWRITE);
|
||||
assert(res == NULL || addr == NULL || addr == res,
|
||||
"Unexpected address from reserve.");
|
||||
return res;
|
||||
@ -2595,7 +2630,7 @@ bool os::can_execute_large_page_memory() {
|
||||
return true;
|
||||
}
|
||||
|
||||
char* os::reserve_memory_special(size_t bytes, char* addr) {
|
||||
char* os::reserve_memory_special(size_t bytes, char* addr, bool exec) {
|
||||
|
||||
if (UseLargePagesIndividualAllocation) {
|
||||
if (TracePageSizes && Verbose) {
|
||||
@ -2618,7 +2653,7 @@ char* os::reserve_memory_special(size_t bytes, char* addr) {
|
||||
p_buf = (char *) VirtualAlloc(addr,
|
||||
size_of_reserve, // size of Reserve
|
||||
MEM_RESERVE,
|
||||
PAGE_EXECUTE_READWRITE);
|
||||
PAGE_READWRITE);
|
||||
// If reservation failed, return NULL
|
||||
if (p_buf == NULL) return NULL;
|
||||
|
||||
@ -2659,7 +2694,13 @@ char* os::reserve_memory_special(size_t bytes, char* addr) {
|
||||
p_new = (char *) VirtualAlloc(next_alloc_addr,
|
||||
bytes_to_rq,
|
||||
MEM_RESERVE | MEM_COMMIT | MEM_LARGE_PAGES,
|
||||
PAGE_EXECUTE_READWRITE);
|
||||
PAGE_READWRITE);
|
||||
if (p_new != NULL && exec) {
|
||||
DWORD oldprot;
|
||||
// Windows doc says to use VirtualProtect to get execute permissions
|
||||
VirtualProtect(next_alloc_addr, bytes_to_rq,
|
||||
PAGE_EXECUTE_READWRITE, &oldprot);
|
||||
}
|
||||
}
|
||||
|
||||
if (p_new == NULL) {
|
||||
@ -2688,10 +2729,12 @@ char* os::reserve_memory_special(size_t bytes, char* addr) {
|
||||
} else {
|
||||
// normal policy just allocate it all at once
|
||||
DWORD flag = MEM_RESERVE | MEM_COMMIT | MEM_LARGE_PAGES;
|
||||
char * res = (char *)VirtualAlloc(NULL,
|
||||
bytes,
|
||||
flag,
|
||||
PAGE_EXECUTE_READWRITE);
|
||||
char * res = (char *)VirtualAlloc(NULL, bytes, flag, PAGE_READWRITE);
|
||||
if (res != NULL && exec) {
|
||||
DWORD oldprot;
|
||||
// Windows doc says to use VirtualProtect to get execute permissions
|
||||
VirtualProtect(res, bytes, PAGE_EXECUTE_READWRITE, &oldprot);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
@ -2703,7 +2746,7 @@ bool os::release_memory_special(char* base, size_t bytes) {
|
||||
void os::print_statistics() {
|
||||
}
|
||||
|
||||
bool os::commit_memory(char* addr, size_t bytes) {
|
||||
bool os::commit_memory(char* addr, size_t bytes, bool exec) {
|
||||
if (bytes == 0) {
|
||||
// Don't bother the OS with noops.
|
||||
return true;
|
||||
@ -2712,11 +2755,19 @@ bool os::commit_memory(char* addr, size_t bytes) {
|
||||
assert(bytes % os::vm_page_size() == 0, "commit in page-sized chunks");
|
||||
// Don't attempt to print anything if the OS call fails. We're
|
||||
// probably low on resources, so the print itself may cause crashes.
|
||||
return VirtualAlloc(addr, bytes, MEM_COMMIT, PAGE_EXECUTE_READWRITE) != NULL;
|
||||
bool result = VirtualAlloc(addr, bytes, MEM_COMMIT, PAGE_READWRITE) != 0;
|
||||
if (result != NULL && exec) {
|
||||
DWORD oldprot;
|
||||
// Windows doc says to use VirtualProtect to get execute permissions
|
||||
return VirtualProtect(addr, bytes, PAGE_EXECUTE_READWRITE, &oldprot) != 0;
|
||||
} else {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
bool os::commit_memory(char* addr, size_t size, size_t alignment_hint) {
|
||||
return commit_memory(addr, size);
|
||||
bool os::commit_memory(char* addr, size_t size, size_t alignment_hint,
|
||||
bool exec) {
|
||||
return commit_memory(addr, size, exec);
|
||||
}
|
||||
|
||||
bool os::uncommit_memory(char* addr, size_t bytes) {
|
||||
@ -2750,7 +2801,7 @@ bool os::protect_memory(char* addr, size_t bytes, ProtType prot,
|
||||
|
||||
// Strange enough, but on Win32 one can change protection only for committed
|
||||
// memory, not a big deal anyway, as bytes less or equal than 64K
|
||||
if (!is_committed && !commit_memory(addr, bytes)) {
|
||||
if (!is_committed && !commit_memory(addr, bytes, prot == MEM_PROT_RWX)) {
|
||||
fatal("cannot commit protection page");
|
||||
}
|
||||
// One cannot use os::guard_memory() here, as on Win32 guard page
|
||||
@ -3248,10 +3299,10 @@ jint os::init_2(void) {
|
||||
#endif
|
||||
|
||||
if (!UseMembar) {
|
||||
address mem_serialize_page = (address)VirtualAlloc(NULL, os::vm_page_size(), MEM_RESERVE, PAGE_EXECUTE_READWRITE);
|
||||
address mem_serialize_page = (address)VirtualAlloc(NULL, os::vm_page_size(), MEM_RESERVE, PAGE_READWRITE);
|
||||
guarantee( mem_serialize_page != NULL, "Reserve Failed for memory serialize page");
|
||||
|
||||
return_page = (address)VirtualAlloc(mem_serialize_page, os::vm_page_size(), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
|
||||
return_page = (address)VirtualAlloc(mem_serialize_page, os::vm_page_size(), MEM_COMMIT, PAGE_READWRITE);
|
||||
guarantee( return_page != NULL, "Commit Failed for memory serialize page");
|
||||
|
||||
os::set_memory_serialize_page( mem_serialize_page );
|
||||
|
@ -29,13 +29,11 @@
|
||||
static jint (*atomic_cmpxchg_func) (jint, volatile jint*, jint);
|
||||
static jlong (*atomic_cmpxchg_long_func)(jlong, volatile jlong*, jlong);
|
||||
static jint (*atomic_add_func) (jint, volatile jint*);
|
||||
static void (*fence_func) ();
|
||||
|
||||
static jint atomic_xchg_bootstrap (jint, volatile jint*);
|
||||
static jint atomic_cmpxchg_bootstrap (jint, volatile jint*, jint);
|
||||
static jlong atomic_cmpxchg_long_bootstrap(jlong, volatile jlong*, jlong);
|
||||
static jint atomic_add_bootstrap (jint, volatile jint*);
|
||||
static void fence_bootstrap ();
|
||||
|
||||
static void setup_fpu() {}
|
||||
|
||||
|
@ -44,11 +44,12 @@ inline void OrderAccess::release() {
|
||||
|
||||
inline void OrderAccess::fence() {
|
||||
if (os::is_MP()) {
|
||||
// always use locked addl since mfence is sometimes expensive
|
||||
#ifdef AMD64
|
||||
__asm__ __volatile__ ("mfence":::"memory");
|
||||
__asm__ volatile ("lock; addl $0,0(%%rsp)" : : : "cc", "memory");
|
||||
#else
|
||||
__asm__ volatile ("lock; addl $0,0(%%esp)" : : : "cc", "memory");
|
||||
#endif // AMD64
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -60,22 +60,10 @@ inline void OrderAccess::release() {
|
||||
dummy = 0;
|
||||
}
|
||||
|
||||
#if defined(COMPILER2) || defined(_LP64)
|
||||
|
||||
inline void OrderAccess::fence() {
|
||||
_OrderAccess_fence();
|
||||
}
|
||||
|
||||
#else // defined(COMPILER2) || defined(_LP64)
|
||||
|
||||
inline void OrderAccess::fence() {
|
||||
if (os::is_MP()) {
|
||||
(*os::fence_func)();
|
||||
}
|
||||
}
|
||||
|
||||
#endif // defined(COMPILER2) || defined(_LP64)
|
||||
|
||||
#endif // _GNU_SOURCE
|
||||
|
||||
inline jbyte OrderAccess::load_acquire(volatile jbyte* p) { return *p; }
|
||||
|
@ -619,7 +619,6 @@ typedef jint xchg_func_t (jint, volatile jint*);
|
||||
typedef jint cmpxchg_func_t (jint, volatile jint*, jint);
|
||||
typedef jlong cmpxchg_long_func_t(jlong, volatile jlong*, jlong);
|
||||
typedef jint add_func_t (jint, volatile jint*);
|
||||
typedef void fence_func_t ();
|
||||
|
||||
jint os::atomic_xchg_bootstrap(jint exchange_value, volatile jint* dest) {
|
||||
// try to use the stub:
|
||||
@ -681,25 +680,10 @@ jint os::atomic_add_bootstrap(jint add_value, volatile jint* dest) {
|
||||
return (*dest) += add_value;
|
||||
}
|
||||
|
||||
void os::fence_bootstrap() {
|
||||
// try to use the stub:
|
||||
fence_func_t* func = CAST_TO_FN_PTR(fence_func_t*, StubRoutines::fence_entry());
|
||||
|
||||
if (func != NULL) {
|
||||
os::fence_func = func;
|
||||
(*func)();
|
||||
return;
|
||||
}
|
||||
assert(Threads::number_of_threads() == 0, "for bootstrap only");
|
||||
|
||||
// don't have to do anything for a single thread
|
||||
}
|
||||
|
||||
xchg_func_t* os::atomic_xchg_func = os::atomic_xchg_bootstrap;
|
||||
cmpxchg_func_t* os::atomic_cmpxchg_func = os::atomic_cmpxchg_bootstrap;
|
||||
cmpxchg_long_func_t* os::atomic_cmpxchg_long_func = os::atomic_cmpxchg_long_bootstrap;
|
||||
add_func_t* os::atomic_add_func = os::atomic_add_bootstrap;
|
||||
fence_func_t* os::fence_func = os::fence_bootstrap;
|
||||
|
||||
#endif // !_LP64 && !COMPILER2
|
||||
|
||||
|
@ -29,13 +29,11 @@
|
||||
static jint (*atomic_cmpxchg_func) (jint, volatile jint*, jint);
|
||||
static jlong (*atomic_cmpxchg_long_func)(jlong, volatile jlong*, jlong);
|
||||
static jint (*atomic_add_func) (jint, volatile jint*);
|
||||
static void (*fence_func) ();
|
||||
|
||||
static jint atomic_xchg_bootstrap (jint, volatile jint*);
|
||||
static jint atomic_cmpxchg_bootstrap (jint, volatile jint*, jint);
|
||||
static jlong atomic_cmpxchg_long_bootstrap(jlong, volatile jlong*, jlong);
|
||||
static jint atomic_add_bootstrap (jint, volatile jint*);
|
||||
static void fence_bootstrap ();
|
||||
|
||||
static void setup_fpu() {}
|
||||
|
||||
|
@ -61,11 +61,8 @@ extern "C" {
|
||||
#endif // AMD64
|
||||
}
|
||||
inline void _OrderAccess_fence() {
|
||||
#ifdef AMD64
|
||||
__asm__ __volatile__ ("mfence":::"memory");
|
||||
#else
|
||||
// Always use locked addl since mfence is sometimes expensive
|
||||
__asm__ volatile ("lock; addl $0,0(%%esp)" : : : "cc", "memory");
|
||||
#endif // AMD64
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -794,7 +794,6 @@ typedef jint xchg_func_t (jint, volatile jint*);
|
||||
typedef jint cmpxchg_func_t (jint, volatile jint*, jint);
|
||||
typedef jlong cmpxchg_long_func_t(jlong, volatile jlong*, jlong);
|
||||
typedef jint add_func_t (jint, volatile jint*);
|
||||
typedef void fence_func_t ();
|
||||
|
||||
jint os::atomic_xchg_bootstrap(jint exchange_value, volatile jint* dest) {
|
||||
// try to use the stub:
|
||||
@ -856,25 +855,10 @@ jint os::atomic_add_bootstrap(jint add_value, volatile jint* dest) {
|
||||
return (*dest) += add_value;
|
||||
}
|
||||
|
||||
void os::fence_bootstrap() {
|
||||
// try to use the stub:
|
||||
fence_func_t* func = CAST_TO_FN_PTR(fence_func_t*, StubRoutines::fence_entry());
|
||||
|
||||
if (func != NULL) {
|
||||
os::fence_func = func;
|
||||
(*func)();
|
||||
return;
|
||||
}
|
||||
assert(Threads::number_of_threads() == 0, "for bootstrap only");
|
||||
|
||||
// don't have to do anything for a single thread
|
||||
}
|
||||
|
||||
xchg_func_t* os::atomic_xchg_func = os::atomic_xchg_bootstrap;
|
||||
cmpxchg_func_t* os::atomic_cmpxchg_func = os::atomic_cmpxchg_bootstrap;
|
||||
cmpxchg_long_func_t* os::atomic_cmpxchg_long_func = os::atomic_cmpxchg_long_bootstrap;
|
||||
add_func_t* os::atomic_add_func = os::atomic_add_bootstrap;
|
||||
fence_func_t* os::fence_func = os::fence_bootstrap;
|
||||
|
||||
extern "C" _solaris_raw_setup_fpu(address ptr);
|
||||
void os::setup_fpu() {
|
||||
|
@ -32,13 +32,11 @@
|
||||
static jint (*atomic_cmpxchg_func) (jint, volatile jint*, jint);
|
||||
static jlong (*atomic_cmpxchg_long_func)(jlong, volatile jlong*, jlong);
|
||||
static jint (*atomic_add_func) (jint, volatile jint*);
|
||||
static void (*fence_func) ();
|
||||
|
||||
static jint atomic_xchg_bootstrap (jint, volatile jint*);
|
||||
static jint atomic_cmpxchg_bootstrap (jint, volatile jint*, jint);
|
||||
static jlong atomic_cmpxchg_long_bootstrap(jlong, volatile jlong*, jlong);
|
||||
static jint atomic_add_bootstrap (jint, volatile jint*);
|
||||
static void fence_bootstrap ();
|
||||
|
||||
static void setup_fpu();
|
||||
#endif // AMD64
|
||||
|
@ -46,7 +46,7 @@ inline void OrderAccess::release() {
|
||||
|
||||
inline void OrderAccess::fence() {
|
||||
#ifdef AMD64
|
||||
(*os::fence_func)();
|
||||
StubRoutines_fence();
|
||||
#else
|
||||
if (os::is_MP()) {
|
||||
__asm {
|
||||
|
@ -196,7 +196,6 @@ typedef jint cmpxchg_func_t (jint, volatile jint*, jint);
|
||||
typedef jlong cmpxchg_long_func_t (jlong, volatile jlong*, jlong);
|
||||
typedef jint add_func_t (jint, volatile jint*);
|
||||
typedef intptr_t add_ptr_func_t (intptr_t, volatile intptr_t*);
|
||||
typedef void fence_func_t ();
|
||||
|
||||
#ifdef AMD64
|
||||
|
||||
@ -292,27 +291,11 @@ intptr_t os::atomic_add_ptr_bootstrap(intptr_t add_value, volatile intptr_t* des
|
||||
return (*dest) += add_value;
|
||||
}
|
||||
|
||||
void os::fence_bootstrap() {
|
||||
// try to use the stub:
|
||||
fence_func_t* func = CAST_TO_FN_PTR(fence_func_t*, StubRoutines::fence_entry());
|
||||
|
||||
if (func != NULL) {
|
||||
os::fence_func = func;
|
||||
(*func)();
|
||||
return;
|
||||
}
|
||||
assert(Threads::number_of_threads() == 0, "for bootstrap only");
|
||||
|
||||
// don't have to do anything for a single thread
|
||||
}
|
||||
|
||||
|
||||
xchg_func_t* os::atomic_xchg_func = os::atomic_xchg_bootstrap;
|
||||
xchg_ptr_func_t* os::atomic_xchg_ptr_func = os::atomic_xchg_ptr_bootstrap;
|
||||
cmpxchg_func_t* os::atomic_cmpxchg_func = os::atomic_cmpxchg_bootstrap;
|
||||
add_func_t* os::atomic_add_func = os::atomic_add_bootstrap;
|
||||
add_ptr_func_t* os::atomic_add_ptr_func = os::atomic_add_ptr_bootstrap;
|
||||
fence_func_t* os::fence_func = os::fence_bootstrap;
|
||||
|
||||
#endif // AMD64
|
||||
|
||||
|
@ -35,9 +35,6 @@
|
||||
static jint (*atomic_add_func) (jint, volatile jint*);
|
||||
static intptr_t (*atomic_add_ptr_func) (intptr_t, volatile intptr_t*);
|
||||
|
||||
static void (*fence_func) ();
|
||||
|
||||
|
||||
static jint atomic_xchg_bootstrap (jint, volatile jint*);
|
||||
static intptr_t atomic_xchg_ptr_bootstrap (intptr_t, volatile intptr_t*);
|
||||
|
||||
@ -53,8 +50,6 @@
|
||||
#ifdef AMD64
|
||||
static jint atomic_add_bootstrap (jint, volatile jint*);
|
||||
static intptr_t atomic_add_ptr_bootstrap (intptr_t, volatile intptr_t*);
|
||||
|
||||
static void fence_bootstrap ();
|
||||
#endif // AMD64
|
||||
|
||||
static void setup_fpu();
|
||||
|
@ -27,6 +27,8 @@ import java.util.*;
|
||||
|
||||
public class WinGammaPlatformVC7 extends WinGammaPlatform {
|
||||
|
||||
String projectVersion() {return "7.10";};
|
||||
|
||||
public void writeProjectFile(String projectFileName, String projectName,
|
||||
Vector allConfigs) throws IOException {
|
||||
System.out.println();
|
||||
@ -40,7 +42,7 @@ public class WinGammaPlatformVC7 extends WinGammaPlatform {
|
||||
"VisualStudioProject",
|
||||
new String[] {
|
||||
"ProjectType", "Visual C++",
|
||||
"Version", "7.10",
|
||||
"Version", projectVersion(),
|
||||
"Name", projectName,
|
||||
"ProjectGUID", "{8822CB5C-1C41-41C2-8493-9F6E1994338B}",
|
||||
"SccProjectName", "",
|
||||
@ -417,7 +419,9 @@ public class WinGammaPlatformVC7 extends WinGammaPlatform {
|
||||
new String[] {
|
||||
"Name", "VCPreLinkEventTool",
|
||||
"Description", BuildConfig.getFieldString(null, "PrelinkDescription"),
|
||||
"CommandLine", cfg.expandFormat(BuildConfig.getFieldString(null, "PrelinkCommand").replace('\t', '\n'))
|
||||
//Caution: String.replace(String,String) is available from JDK5 onwards only
|
||||
"CommandLine", cfg.expandFormat(BuildConfig.getFieldString(null, "PrelinkCommand").replace
|
||||
("\t", "
"))
|
||||
}
|
||||
);
|
||||
|
||||
@ -542,25 +546,41 @@ public class WinGammaPlatformVC7 extends WinGammaPlatform {
|
||||
}
|
||||
|
||||
class CompilerInterfaceVC7 extends CompilerInterface {
|
||||
Vector getBaseCompilerFlags(Vector defines, Vector includes, String outDir) {
|
||||
Vector rv = new Vector();
|
||||
void getBaseCompilerFlags_common(Vector defines, Vector includes, String outDir,Vector rv) {
|
||||
|
||||
// advanced M$ IDE (2003) can only recognize name if it's first or
|
||||
// second attribute in the tag - go guess
|
||||
addAttr(rv, "Name", "VCCLCompilerTool");
|
||||
addAttr(rv, "AdditionalIncludeDirectories", Util.join(",", includes));
|
||||
addAttr(rv, "PreprocessorDefinitions", Util.join(";", defines).replace("\"","""));
|
||||
addAttr(rv, "UsePrecompiledHeader", "3");
|
||||
addAttr(rv, "PrecompiledHeaderThrough", "incls"+Util.sep+"_precompiled.incl");
|
||||
addAttr(rv, "PreprocessorDefinitions",
|
||||
Util.join(";", defines).replace("\"","""));
|
||||
addAttr(rv, "PrecompiledHeaderThrough",
|
||||
"incls"+Util.sep+"_precompiled.incl");
|
||||
addAttr(rv, "PrecompiledHeaderFile", outDir+Util.sep+"vm.pch");
|
||||
addAttr(rv, "AssemblerListingLocation", outDir);
|
||||
addAttr(rv, "ObjectFile", outDir+Util.sep);
|
||||
addAttr(rv, "ProgramDataBaseFileName", outDir+Util.sep+"vm.pdb");
|
||||
// Set /nologo optin
|
||||
addAttr(rv, "SuppressStartupBanner", "TRUE");
|
||||
// Surpass the default /Tc or /Tp. 0 is compileAsDefault
|
||||
addAttr(rv, "CompileAs", "0");
|
||||
// Set /W3 option. 3 is warningLevel_3
|
||||
addAttr(rv, "WarningLevel", "3");
|
||||
// Set /WX option,
|
||||
addAttr(rv, "WarnAsError", "TRUE");
|
||||
// Set /GS option
|
||||
addAttr(rv, "BufferSecurityCheck", "FALSE");
|
||||
// Set /Zi option. 3 is debugEnabled
|
||||
addAttr(rv, "DebugInformationFormat", "3");
|
||||
}
|
||||
Vector getBaseCompilerFlags(Vector defines, Vector includes, String outDir) {
|
||||
Vector rv = new Vector();
|
||||
|
||||
getBaseCompilerFlags_common(defines,includes, outDir, rv);
|
||||
// Set /Yu option. 3 is pchUseUsingSpecific
|
||||
// Note: Starting VC8 pchUseUsingSpecific is 2 !!!
|
||||
addAttr(rv, "UsePrecompiledHeader", "3");
|
||||
// Set /EHsc- option
|
||||
addAttr(rv, "ExceptionHandling", "FALSE");
|
||||
|
||||
return rv;
|
||||
@ -579,27 +599,39 @@ class CompilerInterfaceVC7 extends CompilerInterface {
|
||||
"/export:jio_vsnprintf ");
|
||||
addAttr(rv, "AdditionalDependencies", "Wsock32.lib winmm.lib");
|
||||
addAttr(rv, "OutputFile", outDll);
|
||||
// Set /INCREMENTAL option. 1 is linkIncrementalNo
|
||||
addAttr(rv, "LinkIncremental", "1");
|
||||
addAttr(rv, "SuppressStartupBanner", "TRUE");
|
||||
addAttr(rv, "ModuleDefinitionFile", outDir+Util.sep+"vm.def");
|
||||
addAttr(rv, "ProgramDatabaseFile", outDir+Util.sep+"vm.pdb");
|
||||
// Set /SUBSYSTEM option. 2 is subSystemWindows
|
||||
addAttr(rv, "SubSystem", "2");
|
||||
addAttr(rv, "BaseAddress", "0x8000000");
|
||||
addAttr(rv, "ImportLibrary", outDir+Util.sep+"jvm.lib");
|
||||
// Set /MACHINE option. 1 is machineX86
|
||||
addAttr(rv, "TargetMachine", "1");
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
void getDebugCompilerFlags_common(String opt,Vector rv) {
|
||||
|
||||
// Set /On option
|
||||
addAttr(rv, "Optimization", opt);
|
||||
// Set /FR option. 1 is brAllInfo
|
||||
addAttr(rv, "BrowseInformation", "1");
|
||||
addAttr(rv, "BrowseInformationFile", "$(IntDir)" + Util.sep);
|
||||
// Set /MD option. 2 is rtMultiThreadedDLL
|
||||
addAttr(rv, "RuntimeLibrary", "2");
|
||||
// Set /Oy- option
|
||||
addAttr(rv, "OmitFramePointers", "FALSE");
|
||||
|
||||
}
|
||||
|
||||
Vector getDebugCompilerFlags(String opt) {
|
||||
Vector rv = new Vector();
|
||||
|
||||
addAttr(rv, "Optimization", opt);
|
||||
addAttr(rv, "OptimizeForProcessor", "1");
|
||||
addAttr(rv, "DebugInformationFormat", "3");
|
||||
addAttr(rv, "RuntimeLibrary", "2");
|
||||
addAttr(rv, "BrowseInformation", "1");
|
||||
addAttr(rv, "BrowseInformationFile", "$(IntDir)" + Util.sep);
|
||||
getDebugCompilerFlags_common(opt,rv);
|
||||
|
||||
return rv;
|
||||
}
|
||||
@ -607,18 +639,29 @@ class CompilerInterfaceVC7 extends CompilerInterface {
|
||||
Vector getDebugLinkerFlags() {
|
||||
Vector rv = new Vector();
|
||||
|
||||
addAttr(rv, "GenerateDebugInformation", "TRUE");
|
||||
addAttr(rv, "GenerateDebugInformation", "TRUE"); // == /DEBUG option
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
void getProductCompilerFlags_common(Vector rv) {
|
||||
// Set /O2 option. 2 is optimizeMaxSpeed
|
||||
addAttr(rv, "Optimization", "2");
|
||||
// Set /Oy- option
|
||||
addAttr(rv, "OmitFramePointers", "FALSE");
|
||||
}
|
||||
|
||||
Vector getProductCompilerFlags() {
|
||||
Vector rv = new Vector();
|
||||
|
||||
addAttr(rv, "Optimization", "2");
|
||||
getProductCompilerFlags_common(rv);
|
||||
// Set /Ob option. 1 is expandOnlyInline
|
||||
addAttr(rv, "InlineFunctionExpansion", "1");
|
||||
// Set /GF option.
|
||||
addAttr(rv, "StringPooling", "TRUE");
|
||||
// Set /MD option. 2 is rtMultiThreadedDLL
|
||||
addAttr(rv, "RuntimeLibrary", "2");
|
||||
// Set /Gy option
|
||||
addAttr(rv, "EnableFunctionLevelLinking", "TRUE");
|
||||
|
||||
return rv;
|
||||
@ -627,7 +670,9 @@ class CompilerInterfaceVC7 extends CompilerInterface {
|
||||
Vector getProductLinkerFlags() {
|
||||
Vector rv = new Vector();
|
||||
|
||||
// Set /OPT:REF option. 2 is optReferences
|
||||
addAttr(rv, "OptimizeReferences", "2");
|
||||
// Set /OPT:optFolding option. 2 is optFolding
|
||||
addAttr(rv, "EnableCOMDATFolding", "2");
|
||||
|
||||
return rv;
|
||||
|
66
hotspot/src/share/tools/MakeDeps/WinGammaPlatformVC8.java
Normal file
66
hotspot/src/share/tools/MakeDeps/WinGammaPlatformVC8.java
Normal file
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright 2005-2007 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
*
|
||||
*/
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
public class WinGammaPlatformVC8 extends WinGammaPlatformVC7 {
|
||||
|
||||
String projectVersion() {return "8.00";};
|
||||
|
||||
}
|
||||
|
||||
class CompilerInterfaceVC8 extends CompilerInterfaceVC7 {
|
||||
|
||||
Vector getBaseCompilerFlags(Vector defines, Vector includes, String outDir) {
|
||||
Vector rv = new Vector();
|
||||
|
||||
getBaseCompilerFlags_common(defines,includes, outDir, rv);
|
||||
// Set /Yu option. 2 is pchUseUsingSpecific
|
||||
addAttr(rv, "UsePrecompiledHeader", "2");
|
||||
// Set /EHsc- option. 0 is cppExceptionHandlingNo
|
||||
addAttr(rv, "ExceptionHandling", "0");
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
Vector getDebugCompilerFlags(String opt) {
|
||||
Vector rv = new Vector();
|
||||
|
||||
getDebugCompilerFlags_common(opt,rv);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
Vector getProductCompilerFlags() {
|
||||
Vector rv = new Vector();
|
||||
|
||||
getProductCompilerFlags_common(rv);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
}
|
35
hotspot/src/share/tools/MakeDeps/WinGammaPlatformVC9.java
Normal file
35
hotspot/src/share/tools/MakeDeps/WinGammaPlatformVC9.java
Normal file
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright 2005-2007 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
*
|
||||
*/
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
public class WinGammaPlatformVC9 extends WinGammaPlatformVC8 {
|
||||
|
||||
String projectVersion() {return "9.00";};
|
||||
|
||||
}
|
||||
|
||||
class CompilerInterfaceVC9 extends CompilerInterfaceVC8 {
|
||||
}
|
@ -574,9 +574,13 @@ bool InstructForm::needs_anti_dependence_check(FormDict &globals) const {
|
||||
// TEMPORARY
|
||||
// if( is_simple_chain_rule(globals) ) return false;
|
||||
|
||||
// String-compare uses many memorys edges, but writes none
|
||||
// String.(compareTo/equals/indexOf) and Arrays.equals use many memorys edges,
|
||||
// but writes none
|
||||
if( _matrule && _matrule->_rChild &&
|
||||
strcmp(_matrule->_rChild->_opType,"StrComp")==0 )
|
||||
( strcmp(_matrule->_rChild->_opType,"StrComp" )==0 ||
|
||||
strcmp(_matrule->_rChild->_opType,"StrEquals" )==0 ||
|
||||
strcmp(_matrule->_rChild->_opType,"StrIndexOf" )==0 ||
|
||||
strcmp(_matrule->_rChild->_opType,"AryEq" )==0 ))
|
||||
return true;
|
||||
|
||||
// Check if instruction has a USE of a memory operand class, but no defs
|
||||
@ -815,8 +819,10 @@ uint InstructForm::oper_input_base(FormDict &globals) {
|
||||
return AdlcVMDeps::Parms; // Skip the machine-state edges
|
||||
|
||||
if( _matrule->_rChild &&
|
||||
strcmp(_matrule->_rChild->_opType,"StrComp")==0 ) {
|
||||
// String compare takes 1 control and 4 memory edges.
|
||||
( strcmp(_matrule->_rChild->_opType,"StrComp" )==0 ||
|
||||
strcmp(_matrule->_rChild->_opType,"StrEquals" )==0 ||
|
||||
strcmp(_matrule->_rChild->_opType,"StrIndexOf")==0 )) {
|
||||
// String.(compareTo/equals/indexOf) take 1 control and 4 memory edges.
|
||||
return 5;
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 1997-2006 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -143,15 +143,15 @@ class Label VALUE_OBJ_CLASS_SPEC {
|
||||
// A union type for code which has to assemble both constant and
|
||||
// non-constant operands, when the distinction cannot be made
|
||||
// statically.
|
||||
class RegisterConstant VALUE_OBJ_CLASS_SPEC {
|
||||
class RegisterOrConstant VALUE_OBJ_CLASS_SPEC {
|
||||
private:
|
||||
Register _r;
|
||||
intptr_t _c;
|
||||
|
||||
public:
|
||||
RegisterConstant(): _r(noreg), _c(0) {}
|
||||
RegisterConstant(Register r): _r(r), _c(0) {}
|
||||
RegisterConstant(intptr_t c): _r(noreg), _c(c) {}
|
||||
RegisterOrConstant(): _r(noreg), _c(0) {}
|
||||
RegisterOrConstant(Register r): _r(r), _c(0) {}
|
||||
RegisterOrConstant(intptr_t c): _r(noreg), _c(c) {}
|
||||
|
||||
Register as_register() const { assert(is_register(),""); return _r; }
|
||||
intptr_t as_constant() const { assert(is_constant(),""); return _c; }
|
||||
@ -310,13 +310,13 @@ class AbstractAssembler : public ResourceObj {
|
||||
// offsets in code which must be generated before the object class is loaded.
|
||||
// Field offsets are never zero, since an object's header (mark word)
|
||||
// is located at offset zero.
|
||||
RegisterConstant delayed_value(int(*value_fn)(), Register tmp, int offset = 0) {
|
||||
return delayed_value(delayed_value_addr(value_fn), tmp, offset);
|
||||
RegisterOrConstant delayed_value(int(*value_fn)(), Register tmp, int offset = 0) {
|
||||
return delayed_value_impl(delayed_value_addr(value_fn), tmp, offset);
|
||||
}
|
||||
RegisterConstant delayed_value(address(*value_fn)(), Register tmp, int offset = 0) {
|
||||
return delayed_value(delayed_value_addr(value_fn), tmp, offset);
|
||||
RegisterOrConstant delayed_value(address(*value_fn)(), Register tmp, int offset = 0) {
|
||||
return delayed_value_impl(delayed_value_addr(value_fn), tmp, offset);
|
||||
}
|
||||
virtual RegisterConstant delayed_value(intptr_t* delayed_value_addr, Register tmp, int offset) = 0;
|
||||
virtual RegisterOrConstant delayed_value_impl(intptr_t* delayed_value_addr, Register tmp, int offset) = 0;
|
||||
// Last overloading is platform-dependent; look in assembler_<arch>.cpp.
|
||||
static intptr_t* delayed_value_addr(int(*constant_fn)());
|
||||
static intptr_t* delayed_value_addr(address(*constant_fn)());
|
||||
|
@ -2237,7 +2237,6 @@ ciTypeFlow::Block* ciTypeFlow::clone_loop_head(Loop* lp, StateVector* temp_vecto
|
||||
for (SuccIter iter(tail); !iter.done(); iter.next()) {
|
||||
if (iter.succ() == head) {
|
||||
iter.set_succ(clone);
|
||||
break;
|
||||
}
|
||||
}
|
||||
flow_block(tail, temp_vector, temp_set);
|
||||
|
@ -2747,9 +2747,10 @@ instanceKlassHandle ClassFileParser::parseClassFile(symbolHandle name,
|
||||
super_klass(),
|
||||
methods(),
|
||||
access_flags,
|
||||
class_loader(),
|
||||
class_name(),
|
||||
local_interfaces());
|
||||
class_loader,
|
||||
class_name,
|
||||
local_interfaces(),
|
||||
CHECK_(nullHandle));
|
||||
|
||||
// Size of Java itable (in words)
|
||||
itable_size = access_flags.is_interface() ? 0 : klassItable::compute_itable_size(transitive_interfaces);
|
||||
@ -3229,7 +3230,7 @@ instanceKlassHandle ClassFileParser::parseClassFile(symbolHandle name,
|
||||
// print out the superclass.
|
||||
const char * from = Klass::cast(this_klass())->external_name();
|
||||
if (this_klass->java_super() != NULL) {
|
||||
tty->print("RESOLVE %s %s\n", from, instanceKlass::cast(this_klass->java_super())->external_name());
|
||||
tty->print("RESOLVE %s %s (super)\n", from, instanceKlass::cast(this_klass->java_super())->external_name());
|
||||
}
|
||||
// print out each of the interface classes referred to by this class.
|
||||
objArrayHandle local_interfaces(THREAD, this_klass->local_interfaces());
|
||||
@ -3239,7 +3240,7 @@ instanceKlassHandle ClassFileParser::parseClassFile(symbolHandle name,
|
||||
klassOop k = klassOop(local_interfaces->obj_at(i));
|
||||
instanceKlass* to_class = instanceKlass::cast(k);
|
||||
const char * to = to_class->external_name();
|
||||
tty->print("RESOLVE %s %s\n", from, to);
|
||||
tty->print("RESOLVE %s %s (interface)\n", from, to);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -239,22 +239,20 @@ symbolHandle java_lang_String::as_symbol(Handle java_string, TRAPS) {
|
||||
typeArrayOop value = java_lang_String::value(obj);
|
||||
int offset = java_lang_String::offset(obj);
|
||||
int length = java_lang_String::length(obj);
|
||||
|
||||
ResourceMark rm(THREAD);
|
||||
symbolHandle result;
|
||||
|
||||
if (length > 0) {
|
||||
int utf8_length = UNICODE::utf8_length(value->char_at_addr(offset), length);
|
||||
char* chars = NEW_RESOURCE_ARRAY(char, utf8_length + 1);
|
||||
UNICODE::convert_to_utf8(value->char_at_addr(offset), length, chars);
|
||||
// Allocate the symbol
|
||||
result = oopFactory::new_symbol_handle(chars, utf8_length, CHECK_(symbolHandle()));
|
||||
} else {
|
||||
result = oopFactory::new_symbol_handle("", 0, CHECK_(symbolHandle()));
|
||||
}
|
||||
return result;
|
||||
jchar* base = value->char_at_addr(offset);
|
||||
symbolOop sym = SymbolTable::lookup_unicode(base, length, THREAD);
|
||||
return symbolHandle(THREAD, sym);
|
||||
}
|
||||
|
||||
symbolOop java_lang_String::as_symbol_or_null(oop java_string) {
|
||||
typeArrayOop value = java_lang_String::value(java_string);
|
||||
int offset = java_lang_String::offset(java_string);
|
||||
int length = java_lang_String::length(java_string);
|
||||
jchar* base = value->char_at_addr(offset);
|
||||
return SymbolTable::probe_unicode(base, length);
|
||||
}
|
||||
|
||||
|
||||
int java_lang_String::utf8_length(oop java_string) {
|
||||
typeArrayOop value = java_lang_String::value(java_string);
|
||||
int offset = java_lang_String::offset(java_string);
|
||||
@ -385,6 +383,48 @@ klassOop java_lang_Class::as_klassOop(oop java_class) {
|
||||
}
|
||||
|
||||
|
||||
void java_lang_Class::print_signature(oop java_class, outputStream* st) {
|
||||
assert(java_lang_Class::is_instance(java_class), "must be a Class object");
|
||||
symbolOop name = NULL;
|
||||
bool is_instance = false;
|
||||
if (is_primitive(java_class)) {
|
||||
name = vmSymbols::type_signature(primitive_type(java_class));
|
||||
} else {
|
||||
klassOop k = as_klassOop(java_class);
|
||||
is_instance = Klass::cast(k)->oop_is_instance();
|
||||
name = Klass::cast(k)->name();
|
||||
}
|
||||
if (name == NULL) {
|
||||
st->print("<null>");
|
||||
return;
|
||||
}
|
||||
if (is_instance) st->print("L");
|
||||
st->write((char*) name->base(), (int) name->utf8_length());
|
||||
if (is_instance) st->print(";");
|
||||
}
|
||||
|
||||
symbolOop java_lang_Class::as_signature(oop java_class, bool intern_if_not_found, TRAPS) {
|
||||
assert(java_lang_Class::is_instance(java_class), "must be a Class object");
|
||||
symbolOop name = NULL;
|
||||
if (is_primitive(java_class)) {
|
||||
return vmSymbols::type_signature(primitive_type(java_class));
|
||||
} else {
|
||||
klassOop k = as_klassOop(java_class);
|
||||
if (!Klass::cast(k)->oop_is_instance()) {
|
||||
return Klass::cast(k)->name();
|
||||
} else {
|
||||
ResourceMark rm;
|
||||
const char* sigstr = Klass::cast(k)->signature_name();
|
||||
int siglen = (int) strlen(sigstr);
|
||||
if (!intern_if_not_found)
|
||||
return SymbolTable::probe(sigstr, siglen);
|
||||
else
|
||||
return oopFactory::new_symbol(sigstr, siglen, THREAD);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
klassOop java_lang_Class::array_klass(oop java_class) {
|
||||
klassOop k = klassOop(java_class->obj_field(array_klass_offset));
|
||||
assert(k == NULL || k->is_klass() && Klass::cast(k)->oop_is_javaArray(), "should be array klass");
|
||||
@ -412,6 +452,8 @@ void java_lang_Class::set_resolved_constructor(oop java_class, methodOop constru
|
||||
|
||||
|
||||
bool java_lang_Class::is_primitive(oop java_class) {
|
||||
// should assert:
|
||||
//assert(java_lang_Class::is_instance(java_class), "must be a Class object");
|
||||
klassOop k = klassOop(java_class->obj_field(klass_offset));
|
||||
return k == NULL;
|
||||
}
|
||||
@ -431,6 +473,19 @@ BasicType java_lang_Class::primitive_type(oop java_class) {
|
||||
return type;
|
||||
}
|
||||
|
||||
BasicType java_lang_Class::as_BasicType(oop java_class, klassOop* reference_klass) {
|
||||
assert(java_lang_Class::is_instance(java_class), "must be a Class object");
|
||||
if (is_primitive(java_class)) {
|
||||
if (reference_klass != NULL)
|
||||
(*reference_klass) = NULL;
|
||||
return primitive_type(java_class);
|
||||
} else {
|
||||
if (reference_klass != NULL)
|
||||
(*reference_klass) = as_klassOop(java_class);
|
||||
return T_OBJECT;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
oop java_lang_Class::primitive_mirror(BasicType t) {
|
||||
oop mirror = Universe::java_mirror(t);
|
||||
@ -1988,6 +2043,21 @@ BasicType java_lang_boxing_object::set_value(oop box, jvalue* value) {
|
||||
}
|
||||
|
||||
|
||||
void java_lang_boxing_object::print(BasicType type, jvalue* value, outputStream* st) {
|
||||
switch (type) {
|
||||
case T_BOOLEAN: st->print("%s", value->z ? "true" : "false"); break;
|
||||
case T_CHAR: st->print("%d", value->c); break;
|
||||
case T_BYTE: st->print("%d", value->b); break;
|
||||
case T_SHORT: st->print("%d", value->s); break;
|
||||
case T_INT: st->print("%d", value->i); break;
|
||||
case T_LONG: st->print(INT64_FORMAT, value->j); break;
|
||||
case T_FLOAT: st->print("%f", value->f); break;
|
||||
case T_DOUBLE: st->print("%lf", value->d); break;
|
||||
default: st->print("type %d?", type); break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Support for java_lang_ref_Reference
|
||||
oop java_lang_ref_Reference::pending_list_lock() {
|
||||
instanceKlass* ik = instanceKlass::cast(SystemDictionary::reference_klass());
|
||||
|
@ -107,6 +107,7 @@ class java_lang_String : AllStatic {
|
||||
|
||||
// Conversion
|
||||
static symbolHandle as_symbol(Handle java_string, TRAPS);
|
||||
static symbolOop as_symbol_or_null(oop java_string);
|
||||
|
||||
// Testers
|
||||
static bool is_instance(oop obj) {
|
||||
@ -149,6 +150,9 @@ class java_lang_Class : AllStatic {
|
||||
static oop create_basic_type_mirror(const char* basic_type_name, BasicType type, TRAPS);
|
||||
// Conversion
|
||||
static klassOop as_klassOop(oop java_class);
|
||||
static BasicType as_BasicType(oop java_class, klassOop* reference_klass = NULL);
|
||||
static symbolOop as_signature(oop java_class, bool intern_if_not_found, TRAPS);
|
||||
static void print_signature(oop java_class, outputStream *st);
|
||||
// Testing
|
||||
static bool is_instance(oop obj) {
|
||||
return obj != NULL && obj->klass() == SystemDictionary::class_klass();
|
||||
@ -668,6 +672,8 @@ class java_lang_boxing_object: AllStatic {
|
||||
static BasicType basic_type(oop box);
|
||||
static bool is_instance(oop box) { return basic_type(box) != T_ILLEGAL; }
|
||||
static bool is_instance(oop box, BasicType type) { return basic_type(box) == type; }
|
||||
static void print(oop box, outputStream* st) { jvalue value; print(get_value(box, &value), &value, st); }
|
||||
static void print(BasicType type, jvalue* value, outputStream* st);
|
||||
|
||||
static int value_offset_in_bytes(BasicType type) {
|
||||
return ( type == T_LONG || type == T_DOUBLE ) ? long_value_offset :
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2003-2006 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* Copyright 2003-2009 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -60,8 +60,10 @@ public:
|
||||
bool add_entry(symbolHandle name, klassOop klass1, Handle loader1,
|
||||
klassOop klass2, Handle loader2);
|
||||
|
||||
void check_signature_loaders(symbolHandle signature, Handle loader1,
|
||||
Handle loader2, bool is_method, TRAPS);
|
||||
// Note: The main entry point for this module is via SystemDictionary.
|
||||
// SystemDictionary::check_signature_loaders(symbolHandle signature,
|
||||
// Handle loader1, Handle loader2,
|
||||
// bool is_method, TRAPS)
|
||||
|
||||
klassOop find_constrained_klass(symbolHandle name, Handle loader);
|
||||
klassOop find_constrained_elem_klass(symbolHandle name, symbolHandle elem_name,
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 1997-2006 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -109,6 +109,40 @@ symbolOop SymbolTable::lookup_only(const char* name, int len,
|
||||
return the_table()->lookup(index, name, len, hash);
|
||||
}
|
||||
|
||||
// Suggestion: Push unicode-based lookup all the way into the hashing
|
||||
// and probing logic, so there is no need for convert_to_utf8 until
|
||||
// an actual new symbolOop is created.
|
||||
symbolOop SymbolTable::lookup_unicode(const jchar* name, int utf16_length, TRAPS) {
|
||||
int utf8_length = UNICODE::utf8_length((jchar*) name, utf16_length);
|
||||
char stack_buf[128];
|
||||
if (utf8_length < (int) sizeof(stack_buf)) {
|
||||
char* chars = stack_buf;
|
||||
UNICODE::convert_to_utf8(name, utf16_length, chars);
|
||||
return lookup(chars, utf8_length, THREAD);
|
||||
} else {
|
||||
ResourceMark rm(THREAD);
|
||||
char* chars = NEW_RESOURCE_ARRAY(char, utf8_length + 1);;
|
||||
UNICODE::convert_to_utf8(name, utf16_length, chars);
|
||||
return lookup(chars, utf8_length, THREAD);
|
||||
}
|
||||
}
|
||||
|
||||
symbolOop SymbolTable::lookup_only_unicode(const jchar* name, int utf16_length,
|
||||
unsigned int& hash) {
|
||||
int utf8_length = UNICODE::utf8_length((jchar*) name, utf16_length);
|
||||
char stack_buf[128];
|
||||
if (utf8_length < (int) sizeof(stack_buf)) {
|
||||
char* chars = stack_buf;
|
||||
UNICODE::convert_to_utf8(name, utf16_length, chars);
|
||||
return lookup_only(chars, utf8_length, hash);
|
||||
} else {
|
||||
ResourceMark rm;
|
||||
char* chars = NEW_RESOURCE_ARRAY(char, utf8_length + 1);;
|
||||
UNICODE::convert_to_utf8(name, utf16_length, chars);
|
||||
return lookup_only(chars, utf8_length, hash);
|
||||
}
|
||||
}
|
||||
|
||||
void SymbolTable::add(constantPoolHandle cp, int names_count,
|
||||
const char** names, int* lengths, int* cp_indices,
|
||||
unsigned int* hashValues, TRAPS) {
|
||||
@ -126,15 +160,6 @@ void SymbolTable::add(constantPoolHandle cp, int names_count,
|
||||
}
|
||||
}
|
||||
|
||||
// Needed for preloading classes in signatures when compiling.
|
||||
|
||||
symbolOop SymbolTable::probe(const char* name, int len) {
|
||||
unsigned int hashValue = hash_symbol(name, len);
|
||||
int index = the_table()->hash_to_index(hashValue);
|
||||
return the_table()->lookup(index, name, len, hashValue);
|
||||
}
|
||||
|
||||
|
||||
symbolOop SymbolTable::basic_add(int index, u1 *name, int len,
|
||||
unsigned int hashValue, TRAPS) {
|
||||
assert(!Universe::heap()->is_in_reserved(name) || GC_locker::is_active(),
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 1997-2006 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -91,6 +91,10 @@ public:
|
||||
// Only copy to C string to be added if lookup failed.
|
||||
static symbolOop lookup(symbolHandle sym, int begin, int end, TRAPS);
|
||||
|
||||
// jchar (utf16) version of lookups
|
||||
static symbolOop lookup_unicode(const jchar* name, int len, TRAPS);
|
||||
static symbolOop lookup_only_unicode(const jchar* name, int len, unsigned int& hash);
|
||||
|
||||
static void add(constantPoolHandle cp, int names_count,
|
||||
const char** names, int* lengths, int* cp_indices,
|
||||
unsigned int* hashValues, TRAPS);
|
||||
@ -112,7 +116,14 @@ public:
|
||||
// Needed for preloading classes in signatures when compiling.
|
||||
// Returns the symbol is already present in symbol table, otherwise
|
||||
// NULL. NO ALLOCATION IS GUARANTEED!
|
||||
static symbolOop probe(const char* name, int len);
|
||||
static symbolOop probe(const char* name, int len) {
|
||||
unsigned int ignore_hash;
|
||||
return lookup_only(name, len, ignore_hash);
|
||||
}
|
||||
static symbolOop probe_unicode(const jchar* name, int len) {
|
||||
unsigned int ignore_hash;
|
||||
return lookup_only_unicode(name, len, ignore_hash);
|
||||
}
|
||||
|
||||
// Histogram
|
||||
static void print_histogram() PRODUCT_RETURN;
|
||||
|
@ -1964,6 +1964,13 @@ BasicType SystemDictionary::box_klass_type(klassOop k) {
|
||||
return T_OBJECT;
|
||||
}
|
||||
|
||||
KlassHandle SystemDictionaryHandles::box_klass(BasicType t) {
|
||||
if (t >= T_BOOLEAN && t <= T_VOID)
|
||||
return KlassHandle(&SystemDictionary::_box_klasses[t], true);
|
||||
else
|
||||
return KlassHandle();
|
||||
}
|
||||
|
||||
// Constraints on class loaders. The details of the algorithm can be
|
||||
// found in the OOPSLA'98 paper "Dynamic Class Loading in the Java
|
||||
// Virtual Machine" by Sheng Liang and Gilad Bracha. The basic idea is
|
||||
@ -2174,11 +2181,56 @@ symbolOop SystemDictionary::find_resolution_error(constantPoolHandle pool, int w
|
||||
}
|
||||
|
||||
|
||||
// Signature constraints ensure that callers and callees agree about
|
||||
// the meaning of type names in their signatures. This routine is the
|
||||
// intake for constraints. It collects them from several places:
|
||||
//
|
||||
// * LinkResolver::resolve_method (if check_access is true) requires
|
||||
// that the resolving class (the caller) and the defining class of
|
||||
// the resolved method (the callee) agree on each type in the
|
||||
// method's signature.
|
||||
//
|
||||
// * LinkResolver::resolve_interface_method performs exactly the same
|
||||
// checks.
|
||||
//
|
||||
// * LinkResolver::resolve_field requires that the constant pool
|
||||
// attempting to link to a field agree with the field's defining
|
||||
// class about the type of the field signature.
|
||||
//
|
||||
// * klassVtable::initialize_vtable requires that, when a class
|
||||
// overrides a vtable entry allocated by a superclass, that the
|
||||
// overriding method (i.e., the callee) agree with the superclass
|
||||
// on each type in the method's signature.
|
||||
//
|
||||
// * klassItable::initialize_itable requires that, when a class fills
|
||||
// in its itables, for each non-abstract method installed in an
|
||||
// itable, the method (i.e., the callee) agree with the interface
|
||||
// on each type in the method's signature.
|
||||
//
|
||||
// All those methods have a boolean (check_access, checkconstraints)
|
||||
// which turns off the checks. This is used from specialized contexts
|
||||
// such as bootstrapping, dumping, and debugging.
|
||||
//
|
||||
// No direct constraint is placed between the class and its
|
||||
// supertypes. Constraints are only placed along linked relations
|
||||
// between callers and callees. When a method overrides or implements
|
||||
// an abstract method in a supertype (superclass or interface), the
|
||||
// constraints are placed as if the supertype were the caller to the
|
||||
// overriding method. (This works well, since callers to the
|
||||
// supertype have already established agreement between themselves and
|
||||
// the supertype.) As a result of all this, a class can disagree with
|
||||
// its supertype about the meaning of a type name, as long as that
|
||||
// class neither calls a relevant method of the supertype, nor is
|
||||
// called (perhaps via an override) from the supertype.
|
||||
//
|
||||
//
|
||||
// SystemDictionary::check_signature_loaders(sig, l1, l2)
|
||||
//
|
||||
// Make sure all class components (including arrays) in the given
|
||||
// signature will be resolved to the same class in both loaders.
|
||||
// Returns the name of the type that failed a loader constraint check, or
|
||||
// NULL if no constraint failed. The returned C string needs cleaning up
|
||||
// with a ResourceMark in the caller
|
||||
// with a ResourceMark in the caller. No exception except OOME is thrown.
|
||||
char* SystemDictionary::check_signature_loaders(symbolHandle signature,
|
||||
Handle loader1, Handle loader2,
|
||||
bool is_method, TRAPS) {
|
||||
|
@ -161,6 +161,7 @@ class ResolutionErrorTable;
|
||||
class SystemDictionary : AllStatic {
|
||||
friend class VMStructs;
|
||||
friend class CompactingPermGenGen;
|
||||
friend class SystemDictionaryHandles;
|
||||
NOT_PRODUCT(friend class instanceKlassKlass;)
|
||||
|
||||
public:
|
||||
@ -595,3 +596,18 @@ private:
|
||||
static bool _has_loadClassInternal;
|
||||
static bool _has_checkPackageAccess;
|
||||
};
|
||||
|
||||
// Cf. vmSymbols vs. vmSymbolHandles
|
||||
class SystemDictionaryHandles : AllStatic {
|
||||
public:
|
||||
#define WK_KLASS_HANDLE_DECLARE(name, ignore_symbol, option) \
|
||||
static KlassHandle name() { \
|
||||
SystemDictionary::name(); \
|
||||
klassOop* loc = &SystemDictionary::_well_known_klasses[SystemDictionary::WK_KLASS_ENUM_NAME(name)]; \
|
||||
return KlassHandle(loc, true); \
|
||||
}
|
||||
WK_KLASSES_DO(WK_KLASS_HANDLE_DECLARE);
|
||||
#undef WK_KLASS_HANDLE_DECLARE
|
||||
|
||||
static KlassHandle box_klass(BasicType t);
|
||||
};
|
||||
|
@ -49,6 +49,8 @@
|
||||
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") \
|
||||
@ -285,6 +287,8 @@
|
||||
template(frontCacheEnabled_name, "frontCacheEnabled") \
|
||||
template(stringCacheEnabled_name, "stringCacheEnabled") \
|
||||
template(bitCount_name, "bitCount") \
|
||||
template(profile_name, "profile") \
|
||||
template(equals_name, "equals") \
|
||||
\
|
||||
/* non-intrinsic name/signature pairs: */ \
|
||||
template(register_method_name, "register") \
|
||||
@ -378,7 +382,7 @@
|
||||
template(unknown_class_name, "<Unknown>") \
|
||||
\
|
||||
/* used to identify class loaders handling parallel class loading */ \
|
||||
template(parallelCapable_name, "parallelLockMap;") \
|
||||
template(parallelCapable_name, "parallelLockMap") \
|
||||
\
|
||||
/* JVM monitoring and management support */ \
|
||||
template(java_lang_StackTraceElement_array, "[Ljava/lang/StackTraceElement;") \
|
||||
@ -576,7 +580,6 @@
|
||||
do_signature(copyOfRange_signature, "([Ljava/lang/Object;IILjava/lang/Class;)[Ljava/lang/Object;") \
|
||||
\
|
||||
do_intrinsic(_equalsC, java_util_Arrays, equals_name, equalsC_signature, F_S) \
|
||||
do_name( equals_name, "equals") \
|
||||
do_signature(equalsC_signature, "([C[C)Z") \
|
||||
\
|
||||
do_intrinsic(_invoke, java_lang_reflect_Method, invoke_name, object_array_object_object_signature, F_R) \
|
||||
@ -586,6 +589,7 @@
|
||||
do_name( compareTo_name, "compareTo") \
|
||||
do_intrinsic(_indexOf, java_lang_String, indexOf_name, string_int_signature, F_R) \
|
||||
do_name( indexOf_name, "indexOf") \
|
||||
do_intrinsic(_equals, java_lang_String, equals_name, object_boolean_signature, F_R) \
|
||||
\
|
||||
do_class(java_nio_Buffer, "java/nio/Buffer") \
|
||||
do_intrinsic(_checkIndex, java_nio_Buffer, checkIndex_name, int_int_signature, F_R) \
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2001-2008 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* Copyright 2001-2009 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -825,6 +825,7 @@ HeapWord* ParallelScavengeHeap::block_start(const void* addr) const {
|
||||
if (young_gen()->is_in_reserved(addr)) {
|
||||
assert(young_gen()->is_in(addr),
|
||||
"addr should be in allocated part of young gen");
|
||||
if (Debugging) return NULL; // called from find() in debug.cpp
|
||||
Unimplemented();
|
||||
} else if (old_gen()->is_in_reserved(addr)) {
|
||||
assert(old_gen()->is_in(addr),
|
||||
|
@ -3154,6 +3154,8 @@ oopsHierarchy.cpp thread.hpp
|
||||
oopsHierarchy.cpp thread_<os_family>.inline.hpp
|
||||
|
||||
orderAccess.cpp orderAccess.hpp
|
||||
orderAccess.cpp stubRoutines.hpp
|
||||
orderAccess.cpp thread.hpp
|
||||
|
||||
orderAccess.hpp allocation.hpp
|
||||
orderAccess.hpp os.hpp
|
||||
|
@ -47,6 +47,8 @@ void InvocationCounter::set_carry() {
|
||||
// executed many more times before re-entering the VM.
|
||||
int old_count = count();
|
||||
int new_count = MIN2(old_count, (int) (CompileThreshold / 2));
|
||||
// prevent from going to zero, to distinguish from never-executed methods
|
||||
if (new_count == 0) new_count = 1;
|
||||
if (old_count != new_count) set(state(), new_count);
|
||||
}
|
||||
|
||||
|
@ -112,7 +112,7 @@ bool CodeHeap::reserve(size_t reserved_size, size_t committed_size,
|
||||
|
||||
const size_t rs_align = page_size == (size_t) os::vm_page_size() ? 0 :
|
||||
MAX2(page_size, granularity);
|
||||
ReservedSpace rs(r_size, rs_align, rs_align > 0);
|
||||
ReservedCodeSpace rs(r_size, rs_align, rs_align > 0);
|
||||
os::trace_page_sizes("code heap", committed_size, reserved_size, page_size,
|
||||
rs.base(), rs.size());
|
||||
if (!_memory.initialize(rs, c_size)) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -1813,6 +1813,8 @@ bool instanceKlass::is_same_class_package(oop class_loader1, symbolOop class_nam
|
||||
oop class_loader2, symbolOop class_name2) {
|
||||
if (class_loader1 != class_loader2) {
|
||||
return false;
|
||||
} else if (class_name1 == class_name2) {
|
||||
return true; // skip painful bytewise comparison
|
||||
} else {
|
||||
ResourceMark rm;
|
||||
|
||||
@ -1859,6 +1861,75 @@ bool instanceKlass::is_same_class_package(oop class_loader1, symbolOop class_nam
|
||||
}
|
||||
}
|
||||
|
||||
// Returns true iff super_method can be overridden by a method in targetclassname
|
||||
// See JSL 3rd edition 8.4.6.1
|
||||
// Assumes name-signature match
|
||||
// "this" is instanceKlass of super_method which must exist
|
||||
// note that the instanceKlass of the method in the targetclassname has not always been created yet
|
||||
bool instanceKlass::is_override(methodHandle super_method, Handle targetclassloader, symbolHandle targetclassname, TRAPS) {
|
||||
// Private methods can not be overridden
|
||||
if (super_method->is_private()) {
|
||||
return false;
|
||||
}
|
||||
// If super method is accessible, then override
|
||||
if ((super_method->is_protected()) ||
|
||||
(super_method->is_public())) {
|
||||
return true;
|
||||
}
|
||||
// Package-private methods are not inherited outside of package
|
||||
assert(super_method->is_package_private(), "must be package private");
|
||||
return(is_same_class_package(targetclassloader(), targetclassname()));
|
||||
}
|
||||
|
||||
/* defined for now in jvm.cpp, for historical reasons *--
|
||||
klassOop instanceKlass::compute_enclosing_class_impl(instanceKlassHandle self,
|
||||
symbolOop& simple_name_result, TRAPS) {
|
||||
...
|
||||
}
|
||||
*/
|
||||
|
||||
// tell if two classes have the same enclosing class (at package level)
|
||||
bool instanceKlass::is_same_package_member_impl(instanceKlassHandle class1,
|
||||
klassOop class2_oop, TRAPS) {
|
||||
if (class2_oop == class1->as_klassOop()) return true;
|
||||
if (!Klass::cast(class2_oop)->oop_is_instance()) return false;
|
||||
instanceKlassHandle class2(THREAD, class2_oop);
|
||||
|
||||
// must be in same package before we try anything else
|
||||
if (!class1->is_same_class_package(class2->class_loader(), class2->name()))
|
||||
return false;
|
||||
|
||||
// As long as there is an outer1.getEnclosingClass,
|
||||
// shift the search outward.
|
||||
instanceKlassHandle outer1 = class1;
|
||||
for (;;) {
|
||||
// As we walk along, look for equalities between outer1 and class2.
|
||||
// Eventually, the walks will terminate as outer1 stops
|
||||
// at the top-level class around the original class.
|
||||
symbolOop ignore_name;
|
||||
klassOop next = outer1->compute_enclosing_class(ignore_name, CHECK_false);
|
||||
if (next == NULL) break;
|
||||
if (next == class2()) return true;
|
||||
outer1 = instanceKlassHandle(THREAD, next);
|
||||
}
|
||||
|
||||
// Now do the same for class2.
|
||||
instanceKlassHandle outer2 = class2;
|
||||
for (;;) {
|
||||
symbolOop ignore_name;
|
||||
klassOop next = outer2->compute_enclosing_class(ignore_name, CHECK_false);
|
||||
if (next == NULL) break;
|
||||
// Might as well check the new outer against all available values.
|
||||
if (next == class1()) return true;
|
||||
if (next == outer1()) return true;
|
||||
outer2 = instanceKlassHandle(THREAD, next);
|
||||
}
|
||||
|
||||
// If by this point we have not found an equality between the
|
||||
// two classes, we know they are in separate package members.
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
jint instanceKlass::compute_modifier_flags(TRAPS) const {
|
||||
klassOop k = as_klassOop();
|
||||
@ -1996,9 +2067,11 @@ nmethod* instanceKlass::lookup_osr_nmethod(const methodOop m, int bci) const {
|
||||
|
||||
// Printing
|
||||
|
||||
#define BULLET " - "
|
||||
|
||||
void FieldPrinter::do_field(fieldDescriptor* fd) {
|
||||
if (fd->is_static() == (_obj == NULL)) {
|
||||
_st->print(" - ");
|
||||
_st->print(BULLET);
|
||||
if (fd->is_static() || (_obj == NULL)) {
|
||||
fd->print_on(_st);
|
||||
_st->cr();
|
||||
} else {
|
||||
@ -2019,7 +2092,7 @@ void instanceKlass::oop_print_on(oop obj, outputStream* st) {
|
||||
value->is_typeArray() &&
|
||||
offset <= (juint) value->length() &&
|
||||
offset + length <= (juint) value->length()) {
|
||||
st->print("string: ");
|
||||
st->print(BULLET"string: ");
|
||||
Handle h_obj(obj);
|
||||
java_lang_String::print(h_obj, st);
|
||||
st->cr();
|
||||
@ -2027,22 +2100,25 @@ void instanceKlass::oop_print_on(oop obj, outputStream* st) {
|
||||
}
|
||||
}
|
||||
|
||||
st->print_cr("fields:");
|
||||
st->print_cr(BULLET"---- fields (total size %d words):", oop_size(obj));
|
||||
FieldPrinter print_nonstatic_field(st, obj);
|
||||
do_nonstatic_fields(&print_nonstatic_field);
|
||||
|
||||
if (as_klassOop() == SystemDictionary::class_klass()) {
|
||||
st->print(BULLET"signature: ");
|
||||
java_lang_Class::print_signature(obj, st);
|
||||
st->cr();
|
||||
klassOop mirrored_klass = java_lang_Class::as_klassOop(obj);
|
||||
st->print(" - fake entry for mirror: ");
|
||||
st->print(BULLET"fake entry for mirror: ");
|
||||
mirrored_klass->print_value_on(st);
|
||||
st->cr();
|
||||
st->print(" - fake entry resolved_constructor: ");
|
||||
st->print(BULLET"fake entry resolved_constructor: ");
|
||||
methodOop ctor = java_lang_Class::resolved_constructor(obj);
|
||||
ctor->print_value_on(st);
|
||||
klassOop array_klass = java_lang_Class::array_klass(obj);
|
||||
st->print(" - fake entry for array: ");
|
||||
array_klass->print_value_on(st);
|
||||
st->cr();
|
||||
st->print(BULLET"fake entry for array: ");
|
||||
array_klass->print_value_on(st);
|
||||
st->cr();
|
||||
}
|
||||
}
|
||||
@ -2051,6 +2127,28 @@ void instanceKlass::oop_print_value_on(oop obj, outputStream* st) {
|
||||
st->print("a ");
|
||||
name()->print_value_on(st);
|
||||
obj->print_address_on(st);
|
||||
if (as_klassOop() == SystemDictionary::string_klass()
|
||||
&& java_lang_String::value(obj) != NULL) {
|
||||
ResourceMark rm;
|
||||
int len = java_lang_String::length(obj);
|
||||
int plen = (len < 24 ? len : 12);
|
||||
char* str = java_lang_String::as_utf8_string(obj, 0, plen);
|
||||
st->print(" = \"%s\"", str);
|
||||
if (len > plen)
|
||||
st->print("...[%d]", len);
|
||||
} else if (as_klassOop() == SystemDictionary::class_klass()) {
|
||||
klassOop k = java_lang_Class::as_klassOop(obj);
|
||||
st->print(" = ");
|
||||
if (k != NULL) {
|
||||
k->print_value_on(st);
|
||||
} else {
|
||||
const char* tname = type2name(java_lang_Class::primitive_type(obj));
|
||||
st->print("%s", tname ? tname : "type?");
|
||||
}
|
||||
} else if (java_lang_boxing_object::is_instance(obj)) {
|
||||
st->print(" = ");
|
||||
java_lang_boxing_object::print(obj, st);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // ndef PRODUCT
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -303,11 +303,30 @@ class instanceKlass: public Klass {
|
||||
inner_class_next_offset = 4
|
||||
};
|
||||
|
||||
// method override check
|
||||
bool is_override(methodHandle super_method, Handle targetclassloader, symbolHandle targetclassname, TRAPS);
|
||||
|
||||
// package
|
||||
bool is_same_class_package(klassOop class2);
|
||||
bool is_same_class_package(oop classloader2, symbolOop classname2);
|
||||
static bool is_same_class_package(oop class_loader1, symbolOop class_name1, oop class_loader2, symbolOop class_name2);
|
||||
|
||||
// find an enclosing class (defined where original code was, in jvm.cpp!)
|
||||
klassOop compute_enclosing_class(symbolOop& simple_name_result, TRAPS) {
|
||||
instanceKlassHandle self(THREAD, this->as_klassOop());
|
||||
return compute_enclosing_class_impl(self, simple_name_result, THREAD);
|
||||
}
|
||||
static klassOop compute_enclosing_class_impl(instanceKlassHandle self,
|
||||
symbolOop& simple_name_result, TRAPS);
|
||||
|
||||
// tell if two classes have the same enclosing class (at package level)
|
||||
bool is_same_package_member(klassOop class2, TRAPS) {
|
||||
instanceKlassHandle self(THREAD, this->as_klassOop());
|
||||
return is_same_package_member_impl(self, class2, THREAD);
|
||||
}
|
||||
static bool is_same_package_member_impl(instanceKlassHandle self,
|
||||
klassOop class2, TRAPS);
|
||||
|
||||
// initialization state
|
||||
bool is_loaded() const { return _init_state >= loaded; }
|
||||
bool is_linked() const { return _init_state >= linked; }
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -487,6 +487,8 @@ klassOop instanceKlassKlass::allocate_instance_klass(int vtable_len, int itable_
|
||||
|
||||
// Printing
|
||||
|
||||
#define BULLET " - "
|
||||
|
||||
static const char* state_names[] = {
|
||||
"unparseable_by_gc", "allocated", "loaded", "linked", "being_initialized", "fully_initialized", "initialization_error"
|
||||
};
|
||||
@ -497,13 +499,13 @@ void instanceKlassKlass::oop_print_on(oop obj, outputStream* st) {
|
||||
instanceKlass* ik = instanceKlass::cast(klassOop(obj));
|
||||
klassKlass::oop_print_on(obj, st);
|
||||
|
||||
st->print(" - instance size: %d", ik->size_helper()); st->cr();
|
||||
st->print(" - klass size: %d", ik->object_size()); st->cr();
|
||||
st->print(" - access: "); ik->access_flags().print_on(st); st->cr();
|
||||
st->print(" - state: "); st->print_cr(state_names[ik->_init_state]);
|
||||
st->print(" - name: "); ik->name()->print_value_on(st); st->cr();
|
||||
st->print(" - super: "); ik->super()->print_value_on(st); st->cr();
|
||||
st->print(" - sub: ");
|
||||
st->print(BULLET"instance size: %d", ik->size_helper()); st->cr();
|
||||
st->print(BULLET"klass size: %d", ik->object_size()); st->cr();
|
||||
st->print(BULLET"access: "); ik->access_flags().print_on(st); st->cr();
|
||||
st->print(BULLET"state: "); st->print_cr(state_names[ik->_init_state]);
|
||||
st->print(BULLET"name: "); ik->name()->print_value_on(st); st->cr();
|
||||
st->print(BULLET"super: "); ik->super()->print_value_on(st); st->cr();
|
||||
st->print(BULLET"sub: ");
|
||||
Klass* sub = ik->subklass();
|
||||
int n;
|
||||
for (n = 0; sub != NULL; n++, sub = sub->next_sibling()) {
|
||||
@ -516,12 +518,12 @@ void instanceKlassKlass::oop_print_on(oop obj, outputStream* st) {
|
||||
st->cr();
|
||||
|
||||
if (ik->is_interface()) {
|
||||
st->print_cr(" - nof implementors: %d", ik->nof_implementors());
|
||||
st->print_cr(BULLET"nof implementors: %d", ik->nof_implementors());
|
||||
int print_impl = 0;
|
||||
for (int i = 0; i < instanceKlass::implementors_limit; i++) {
|
||||
if (ik->implementor(i) != NULL) {
|
||||
if (++print_impl == 1)
|
||||
st->print_cr(" - implementor: ");
|
||||
st->print_cr(BULLET"implementor: ");
|
||||
st->print(" ");
|
||||
ik->implementor(i)->print_value_on(st);
|
||||
}
|
||||
@ -529,34 +531,33 @@ void instanceKlassKlass::oop_print_on(oop obj, outputStream* st) {
|
||||
if (print_impl > 0) st->cr();
|
||||
}
|
||||
|
||||
st->print(" - arrays: "); ik->array_klasses()->print_value_on(st); st->cr();
|
||||
st->print(" - methods: "); ik->methods()->print_value_on(st); st->cr();
|
||||
st->print(BULLET"arrays: "); ik->array_klasses()->print_value_on(st); st->cr();
|
||||
st->print(BULLET"methods: "); ik->methods()->print_value_on(st); st->cr();
|
||||
if (Verbose) {
|
||||
objArrayOop methods = ik->methods();
|
||||
for(int i = 0; i < methods->length(); i++) {
|
||||
tty->print("%d : ", i); methods->obj_at(i)->print_value(); tty->cr();
|
||||
}
|
||||
}
|
||||
st->print(" - method ordering: "); ik->method_ordering()->print_value_on(st); st->cr();
|
||||
st->print(" - local interfaces: "); ik->local_interfaces()->print_value_on(st); st->cr();
|
||||
st->print(" - trans. interfaces: "); ik->transitive_interfaces()->print_value_on(st); st->cr();
|
||||
st->print(" - constants: "); ik->constants()->print_value_on(st); st->cr();
|
||||
st->print(" - class loader: "); ik->class_loader()->print_value_on(st); st->cr();
|
||||
st->print(" - protection domain: "); ik->protection_domain()->print_value_on(st); st->cr();
|
||||
st->print(" - host class: "); ik->host_klass()->print_value_on(st); st->cr();
|
||||
st->print(" - signers: "); ik->signers()->print_value_on(st); st->cr();
|
||||
st->print(BULLET"method ordering: "); ik->method_ordering()->print_value_on(st); st->cr();
|
||||
st->print(BULLET"local interfaces: "); ik->local_interfaces()->print_value_on(st); st->cr();
|
||||
st->print(BULLET"trans. interfaces: "); ik->transitive_interfaces()->print_value_on(st); st->cr();
|
||||
st->print(BULLET"constants: "); ik->constants()->print_value_on(st); st->cr();
|
||||
st->print(BULLET"class loader: "); ik->class_loader()->print_value_on(st); st->cr();
|
||||
st->print(BULLET"protection domain: "); ik->protection_domain()->print_value_on(st); st->cr();
|
||||
st->print(BULLET"host class: "); ik->host_klass()->print_value_on(st); st->cr();
|
||||
st->print(BULLET"signers: "); ik->signers()->print_value_on(st); st->cr();
|
||||
if (ik->source_file_name() != NULL) {
|
||||
st->print(" - source file: ");
|
||||
st->print(BULLET"source file: ");
|
||||
ik->source_file_name()->print_value_on(st);
|
||||
st->cr();
|
||||
}
|
||||
if (ik->source_debug_extension() != NULL) {
|
||||
st->print(" - source debug extension: ");
|
||||
st->print(BULLET"source debug extension: ");
|
||||
ik->source_debug_extension()->print_value_on(st);
|
||||
st->cr();
|
||||
}
|
||||
|
||||
st->print_cr(" - previous version: ");
|
||||
{
|
||||
ResourceMark rm;
|
||||
// PreviousVersionInfo objects returned via PreviousVersionWalker
|
||||
@ -564,38 +565,43 @@ void instanceKlassKlass::oop_print_on(oop obj, outputStream* st) {
|
||||
// GrowableArray _after_ the PreviousVersionWalker destructor
|
||||
// has destroyed the handles.
|
||||
{
|
||||
bool have_pv = false;
|
||||
PreviousVersionWalker pvw(ik);
|
||||
for (PreviousVersionInfo * pv_info = pvw.next_previous_version();
|
||||
pv_info != NULL; pv_info = pvw.next_previous_version()) {
|
||||
if (!have_pv)
|
||||
st->print(BULLET"previous version: ");
|
||||
have_pv = true;
|
||||
pv_info->prev_constant_pool_handle()()->print_value_on(st);
|
||||
}
|
||||
st->cr();
|
||||
if (have_pv) st->cr();
|
||||
} // pvw is cleaned up
|
||||
} // rm is cleaned up
|
||||
|
||||
if (ik->generic_signature() != NULL) {
|
||||
st->print(" - generic signature: ");
|
||||
st->print(BULLET"generic signature: ");
|
||||
ik->generic_signature()->print_value_on(st);
|
||||
st->cr();
|
||||
}
|
||||
st->print(" - inner classes: "); ik->inner_classes()->print_value_on(st); st->cr();
|
||||
st->print(" - java mirror: "); ik->java_mirror()->print_value_on(st); st->cr();
|
||||
st->print(" - vtable length %d (start addr: " INTPTR_FORMAT ")", ik->vtable_length(), ik->start_of_vtable()); st->cr();
|
||||
st->print(" - itable length %d (start addr: " INTPTR_FORMAT ")", ik->itable_length(), ik->start_of_itable()); st->cr();
|
||||
st->print_cr(" - static fields:");
|
||||
st->print(BULLET"inner classes: "); ik->inner_classes()->print_value_on(st); st->cr();
|
||||
st->print(BULLET"java mirror: "); ik->java_mirror()->print_value_on(st); st->cr();
|
||||
st->print(BULLET"vtable length %d (start addr: " INTPTR_FORMAT ")", ik->vtable_length(), ik->start_of_vtable()); st->cr();
|
||||
st->print(BULLET"itable length %d (start addr: " INTPTR_FORMAT ")", ik->itable_length(), ik->start_of_itable()); st->cr();
|
||||
st->print_cr(BULLET"---- static fields (%d words):", ik->static_field_size());
|
||||
FieldPrinter print_static_field(st);
|
||||
ik->do_local_static_fields(&print_static_field);
|
||||
st->print_cr(" - non-static fields:");
|
||||
FieldPrinter print_nonstatic_field(st, obj);
|
||||
st->print_cr(BULLET"---- non-static fields (%d words):", ik->nonstatic_field_size());
|
||||
FieldPrinter print_nonstatic_field(st);
|
||||
ik->do_nonstatic_fields(&print_nonstatic_field);
|
||||
|
||||
st->print(" - static oop maps: ");
|
||||
st->print(BULLET"static oop maps: ");
|
||||
if (ik->static_oop_field_size() > 0) {
|
||||
int first_offset = ik->offset_of_static_fields();
|
||||
st->print("%d-%d", first_offset, first_offset + ik->static_oop_field_size() - 1);
|
||||
}
|
||||
st->cr();
|
||||
|
||||
st->print(" - non-static oop maps: ");
|
||||
st->print(BULLET"non-static oop maps: ");
|
||||
OopMapBlock* map = ik->start_of_nonstatic_oop_maps();
|
||||
OopMapBlock* end_map = map + ik->nonstatic_oop_map_size();
|
||||
while (map < end_map) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -45,9 +45,10 @@ void klassVtable::compute_vtable_size_and_num_mirandas(int &vtable_length,
|
||||
klassOop super,
|
||||
objArrayOop methods,
|
||||
AccessFlags class_flags,
|
||||
oop classloader,
|
||||
symbolOop classname,
|
||||
objArrayOop local_interfaces
|
||||
Handle classloader,
|
||||
symbolHandle classname,
|
||||
objArrayOop local_interfaces,
|
||||
TRAPS
|
||||
) {
|
||||
|
||||
No_Safepoint_Verifier nsv;
|
||||
@ -64,9 +65,9 @@ void klassVtable::compute_vtable_size_and_num_mirandas(int &vtable_length,
|
||||
int len = methods->length();
|
||||
for (int i = 0; i < len; i++) {
|
||||
assert(methods->obj_at(i)->is_method(), "must be a methodOop");
|
||||
methodOop m = methodOop(methods->obj_at(i));
|
||||
methodHandle mh(THREAD, methodOop(methods->obj_at(i)));
|
||||
|
||||
if (needs_new_vtable_entry(m, super, classloader, classname, class_flags)) {
|
||||
if (needs_new_vtable_entry(mh, super, classloader, classname, class_flags, THREAD)) {
|
||||
vtable_length += vtableEntry::size(); // we need a new entry
|
||||
}
|
||||
}
|
||||
@ -117,6 +118,7 @@ int klassVtable::initialize_from_super(KlassHandle super) {
|
||||
superVtable->copy_vtable_to(table());
|
||||
#ifndef PRODUCT
|
||||
if (PrintVtables && Verbose) {
|
||||
ResourceMark rm;
|
||||
tty->print_cr("copy vtable from %s to %s size %d", sk->internal_name(), klass()->internal_name(), _length);
|
||||
}
|
||||
#endif
|
||||
@ -159,13 +161,13 @@ void klassVtable::initialize_vtable(bool checkconstraints, TRAPS) {
|
||||
int len = methods()->length();
|
||||
int initialized = super_vtable_len;
|
||||
|
||||
// update_super_vtable can stop for gc - ensure using handles
|
||||
// update_inherited_vtable can stop for gc - ensure using handles
|
||||
for (int i = 0; i < len; i++) {
|
||||
HandleMark hm(THREAD);
|
||||
assert(methods()->obj_at(i)->is_method(), "must be a methodOop");
|
||||
methodHandle mh(THREAD, (methodOop)methods()->obj_at(i));
|
||||
|
||||
bool needs_new_entry = update_super_vtable(ik(), mh, super_vtable_len, checkconstraints, CHECK);
|
||||
bool needs_new_entry = update_inherited_vtable(ik(), mh, super_vtable_len, checkconstraints, CHECK);
|
||||
|
||||
if (needs_new_entry) {
|
||||
put_method_at(mh(), initialized);
|
||||
@ -177,7 +179,7 @@ void klassVtable::initialize_vtable(bool checkconstraints, TRAPS) {
|
||||
// add miranda methods; it will also update the value of initialized
|
||||
fill_in_mirandas(initialized);
|
||||
|
||||
// In class hierachieswhere the accesibility is not increasing (i.e., going from private ->
|
||||
// In class hierarchies where the accessibility is not increasing (i.e., going from private ->
|
||||
// package_private -> publicprotected), the vtable might actually be smaller than our initial
|
||||
// calculation.
|
||||
assert(initialized <= _length, "vtable initialization failed");
|
||||
@ -188,26 +190,49 @@ void klassVtable::initialize_vtable(bool checkconstraints, TRAPS) {
|
||||
}
|
||||
}
|
||||
|
||||
// Interates through the vtables to find the broadest access level. This
|
||||
// will always be monotomic for valid Java programs - but not neccesarily
|
||||
// for incompatible class files.
|
||||
klassVtable::AccessType klassVtable::vtable_accessibility_at(int i) {
|
||||
// This vtable is not implementing the specific method
|
||||
if (i >= length()) return acc_private;
|
||||
// Called for cases where a method does not override its superclass' vtable entry
|
||||
// For bytecodes not produced by javac together it is possible that a method does not override
|
||||
// the superclass's method, but might indirectly override a super-super class's vtable entry
|
||||
// If none found, return a null superk, else return the superk of the method this does override
|
||||
instanceKlass* klassVtable::find_transitive_override(instanceKlass* initialsuper, methodHandle target_method,
|
||||
int vtable_index, Handle target_loader, symbolHandle target_classname, Thread * THREAD) {
|
||||
instanceKlass* superk = initialsuper;
|
||||
while (superk != NULL && superk->super() != NULL) {
|
||||
instanceKlass* supersuperklass = instanceKlass::cast(superk->super());
|
||||
klassVtable* ssVtable = supersuperklass->vtable();
|
||||
if (vtable_index < ssVtable->length()) {
|
||||
methodOop super_method = ssVtable->method_at(vtable_index);
|
||||
#ifndef PRODUCT
|
||||
symbolHandle name(THREAD,target_method()->name());
|
||||
symbolHandle signature(THREAD,target_method()->signature());
|
||||
assert(super_method->name() == name() && super_method->signature() == signature(), "vtable entry name/sig mismatch");
|
||||
#endif
|
||||
if (supersuperklass->is_override(super_method, target_loader, target_classname, THREAD)) {
|
||||
#ifndef PRODUCT
|
||||
if (PrintVtables && Verbose) {
|
||||
ResourceMark rm(THREAD);
|
||||
tty->print("transitive overriding superclass %s with %s::%s index %d, original flags: ",
|
||||
supersuperklass->internal_name(),
|
||||
_klass->internal_name(), (target_method() != NULL) ?
|
||||
target_method()->name()->as_C_string() : "<NULL>", vtable_index);
|
||||
super_method->access_flags().print_on(tty);
|
||||
tty->print("overriders flags: ");
|
||||
target_method->access_flags().print_on(tty);
|
||||
tty->cr();
|
||||
}
|
||||
#endif /*PRODUCT*/
|
||||
break; // return found superk
|
||||
}
|
||||
} else {
|
||||
// super class has no vtable entry here, stop transitive search
|
||||
superk = (instanceKlass*)NULL;
|
||||
break;
|
||||
}
|
||||
// if no override found yet, continue to search up
|
||||
superk = instanceKlass::cast(superk->super());
|
||||
}
|
||||
|
||||
// Compute AccessType for current method. public or protected we are done.
|
||||
methodOop m = method_at(i);
|
||||
if (m->is_protected() || m->is_public()) return acc_publicprotected;
|
||||
|
||||
AccessType acc = m->is_package_private() ? acc_package_private : acc_private;
|
||||
|
||||
// Compute AccessType for method in super classes
|
||||
klassOop super = klass()->super();
|
||||
AccessType super_acc = (super != NULL) ? instanceKlass::cast(klass()->super())->vtable()->vtable_accessibility_at(i)
|
||||
: acc_private;
|
||||
|
||||
// Merge
|
||||
return (AccessType)MAX2((int)acc, (int)super_acc);
|
||||
return superk;
|
||||
}
|
||||
|
||||
|
||||
@ -215,7 +240,8 @@ klassVtable::AccessType klassVtable::vtable_accessibility_at(int i) {
|
||||
// OR return true if a new vtable entry is required
|
||||
// Only called for instanceKlass's, i.e. not for arrays
|
||||
// If that changed, could not use _klass as handle for klass
|
||||
bool klassVtable::update_super_vtable(instanceKlass* klass, methodHandle target_method, int super_vtable_len, bool checkconstraints, TRAPS) {
|
||||
bool klassVtable::update_inherited_vtable(instanceKlass* klass, methodHandle target_method, int super_vtable_len,
|
||||
bool checkconstraints, TRAPS) {
|
||||
ResourceMark rm;
|
||||
bool allocate_new = true;
|
||||
assert(klass->oop_is_instance(), "must be instanceKlass");
|
||||
@ -242,58 +268,35 @@ bool klassVtable::update_super_vtable(instanceKlass* klass, methodHandle target_
|
||||
}
|
||||
|
||||
// private methods always have a new entry in the vtable
|
||||
// specification interpretation since classic has
|
||||
// private methods not overriding
|
||||
if (target_method()->is_private()) {
|
||||
return allocate_new;
|
||||
}
|
||||
|
||||
// search through the vtable and update overridden entries
|
||||
// Since check_signature_loaders acquires SystemDictionary_lock
|
||||
// which can block for gc, once we are in this loop, use handles, not
|
||||
// unhandled oops unless they are reinitialized for each loop
|
||||
// handles for name, signature, klass, target_method
|
||||
// not for match_method, holder
|
||||
// which can block for gc, once we are in this loop, use handles
|
||||
// For classfiles built with >= jdk7, we now look for transitive overrides
|
||||
|
||||
symbolHandle name(THREAD,target_method()->name());
|
||||
symbolHandle signature(THREAD,target_method()->signature());
|
||||
Handle target_loader(THREAD, _klass->class_loader());
|
||||
symbolHandle target_classname(THREAD, _klass->name());
|
||||
for(int i = 0; i < super_vtable_len; i++) {
|
||||
methodOop match_method = method_at(i);
|
||||
methodOop super_method = method_at(i);
|
||||
// Check if method name matches
|
||||
if (match_method->name() == name() && match_method->signature() == signature()) {
|
||||
if (super_method->name() == name() && super_method->signature() == signature()) {
|
||||
|
||||
instanceKlass* holder = (THREAD, instanceKlass::cast(match_method->method_holder()));
|
||||
// get super_klass for method_holder for the found method
|
||||
instanceKlass* super_klass = instanceKlass::cast(super_method->method_holder());
|
||||
|
||||
// Check if the match_method is accessable from current class
|
||||
|
||||
bool same_package_init = false;
|
||||
bool same_package_flag = false;
|
||||
bool simple_match = match_method->is_public() || match_method->is_protected();
|
||||
if (!simple_match) {
|
||||
same_package_init = true;
|
||||
same_package_flag = holder->is_same_class_package(_klass->class_loader(), _klass->name());
|
||||
|
||||
simple_match = match_method->is_package_private() && same_package_flag;
|
||||
}
|
||||
// match_method is the superclass' method. Note we can't override
|
||||
// and shouldn't access superclass' ACC_PRIVATE methods
|
||||
// (although they have been copied into our vtable)
|
||||
// A simple form of this statement is:
|
||||
// if ( (match_method->is_public() || match_method->is_protected()) ||
|
||||
// (match_method->is_package_private() && holder->is_same_class_package(klass->class_loader(), klass->name()))) {
|
||||
//
|
||||
// The complexity is introduced it avoid recomputing 'is_same_class_package' which is expensive.
|
||||
if (simple_match) {
|
||||
// Check if target_method and match_method has same level of accessibility. The accesibility of the
|
||||
// match method is the "most-general" visibility of all entries at it's particular vtable index for
|
||||
// all superclasses. This check must be done before we override the current entry in the vtable.
|
||||
AccessType at = vtable_accessibility_at(i);
|
||||
bool same_access = false;
|
||||
|
||||
if ( (at == acc_publicprotected && (target_method()->is_public() || target_method()->is_protected())
|
||||
|| (at == acc_package_private && (target_method()->is_package_private() &&
|
||||
(( same_package_init && same_package_flag) ||
|
||||
(!same_package_init && holder->is_same_class_package(_klass->class_loader(), _klass->name()))))))) {
|
||||
same_access = true;
|
||||
}
|
||||
if ((super_klass->is_override(super_method, target_loader, target_classname, THREAD)) ||
|
||||
((klass->major_version() >= VTABLE_TRANSITIVE_OVERRIDE_VERSION)
|
||||
&& ((super_klass = find_transitive_override(super_klass, target_method, i, target_loader,
|
||||
target_classname, THREAD)) != (instanceKlass*)NULL))) {
|
||||
// overriding, so no new entry
|
||||
allocate_new = false;
|
||||
|
||||
if (checkconstraints) {
|
||||
// Override vtable entry if passes loader constraint check
|
||||
@ -302,15 +305,12 @@ bool klassVtable::update_super_vtable(instanceKlass* klass, methodHandle target_
|
||||
// have already made any needed loader constraints.
|
||||
// Since loader constraints are transitive, it is enough
|
||||
// to link to the first super, and we get all the others.
|
||||
symbolHandle signature(THREAD, target_method()->signature());
|
||||
Handle this_loader(THREAD, _klass->class_loader());
|
||||
instanceKlassHandle super_klass(THREAD, _klass->super());
|
||||
Handle super_loader(THREAD, super_klass->class_loader());
|
||||
|
||||
if (this_loader() != super_loader()) {
|
||||
if (target_loader() != super_loader()) {
|
||||
ResourceMark rm(THREAD);
|
||||
char* failed_type_name =
|
||||
SystemDictionary::check_signature_loaders(signature, this_loader,
|
||||
SystemDictionary::check_signature_loaders(signature, target_loader,
|
||||
super_loader, true,
|
||||
CHECK_(false));
|
||||
if (failed_type_name != NULL) {
|
||||
@ -320,7 +320,7 @@ bool klassVtable::update_super_vtable(instanceKlass* klass, methodHandle target_
|
||||
"(instance of %s), have different Class objects for the type "
|
||||
"%s used in the signature";
|
||||
char* sig = target_method()->name_and_sig_as_C_string();
|
||||
const char* loader1 = SystemDictionary::loader_name(this_loader());
|
||||
const char* loader1 = SystemDictionary::loader_name(target_loader());
|
||||
char* current = _klass->name()->as_C_string();
|
||||
const char* loader2 = SystemDictionary::loader_name(super_loader());
|
||||
size_t buflen = strlen(msg) + strlen(sig) + strlen(loader1) +
|
||||
@ -331,59 +331,46 @@ bool klassVtable::update_super_vtable(instanceKlass* klass, methodHandle target_
|
||||
THROW_MSG_(vmSymbols::java_lang_LinkageError(), buf, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
put_method_at(target_method(), i);
|
||||
|
||||
|
||||
if (same_access) {
|
||||
// target and match has same accessiblity - share entry
|
||||
allocate_new = false;
|
||||
target_method()->set_vtable_index(i);
|
||||
target_method()->set_vtable_index(i);
|
||||
#ifndef PRODUCT
|
||||
if (PrintVtables && Verbose) {
|
||||
AccessType targetacc;
|
||||
if (target_method()->is_protected() ||
|
||||
target_method()->is_public()) {
|
||||
targetacc = acc_publicprotected;
|
||||
} else {
|
||||
targetacc = target_method()->is_package_private() ? acc_package_private : acc_private;
|
||||
}
|
||||
tty->print_cr("overriding with %s::%s index %d, original flags: %x overriders flags: %x",
|
||||
_klass->internal_name(), (target_method() != NULL) ?
|
||||
target_method()->name()->as_C_string() : "<NULL>", i,
|
||||
at, targetacc);
|
||||
}
|
||||
#endif /*PRODUCT*/
|
||||
} else {
|
||||
#ifndef PRODUCT
|
||||
if (PrintVtables && Verbose) {
|
||||
AccessType targetacc;
|
||||
if (target_method()->is_protected() ||
|
||||
target_method()->is_public()) {
|
||||
targetacc = acc_publicprotected;
|
||||
} else {
|
||||
targetacc = target_method()->is_package_private() ? acc_package_private : acc_private;
|
||||
}
|
||||
tty->print_cr("override %s %s::%s at index %d, original flags: %x overriders flags: %x",
|
||||
allocate_new ? "+ new" : "only",
|
||||
_klass->internal_name(), (target_method() != NULL) ?
|
||||
target_method()->name()->as_C_string() : "<NULL>", i,
|
||||
at, targetacc);
|
||||
}
|
||||
#endif /*PRODUCT*/
|
||||
if (PrintVtables && Verbose) {
|
||||
tty->print("overriding with %s::%s index %d, original flags: ",
|
||||
_klass->internal_name(), (target_method() != NULL) ?
|
||||
target_method()->name()->as_C_string() : "<NULL>", i);
|
||||
super_method->access_flags().print_on(tty);
|
||||
tty->print("overriders flags: ");
|
||||
target_method->access_flags().print_on(tty);
|
||||
tty->cr();
|
||||
}
|
||||
#endif /*PRODUCT*/
|
||||
} else {
|
||||
// allocate_new = true; default. We might override one entry,
|
||||
// but not override another. Once we override one, not need new
|
||||
#ifndef PRODUCT
|
||||
if (PrintVtables && Verbose) {
|
||||
tty->print("NOT overriding with %s::%s index %d, original flags: ",
|
||||
_klass->internal_name(), (target_method() != NULL) ?
|
||||
target_method()->name()->as_C_string() : "<NULL>", i);
|
||||
super_method->access_flags().print_on(tty);
|
||||
tty->print("overriders flags: ");
|
||||
target_method->access_flags().print_on(tty);
|
||||
tty->cr();
|
||||
}
|
||||
#endif /*PRODUCT*/
|
||||
}
|
||||
}
|
||||
}
|
||||
return allocate_new;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void klassVtable::put_method_at(methodOop m, int index) {
|
||||
assert(m->is_oop_or_null(), "Not an oop or null");
|
||||
#ifndef PRODUCT
|
||||
if (PrintVtables && Verbose) {
|
||||
ResourceMark rm;
|
||||
tty->print_cr("adding %s::%s at index %d", _klass->internal_name(),
|
||||
(m != NULL) ? m->name()->as_C_string() : "<NULL>", index);
|
||||
}
|
||||
@ -397,19 +384,23 @@ void klassVtable::put_method_at(methodOop m, int index) {
|
||||
// by "classloader" and "classname".
|
||||
// NOTE: The logic used here is very similar to the one used for computing
|
||||
// the vtables indices for a method. We cannot directly use that function because,
|
||||
// when the Universe is boostrapping, a super's vtable might not be initialized.
|
||||
bool klassVtable::needs_new_vtable_entry(methodOop target_method,
|
||||
// we allocate the instanceKlass at load time, and that requires that the
|
||||
// superclass has been loaded.
|
||||
// However, the vtable entries are filled in at link time, and therefore
|
||||
// the superclass' vtable may not yet have been filled in.
|
||||
bool klassVtable::needs_new_vtable_entry(methodHandle target_method,
|
||||
klassOop super,
|
||||
oop classloader,
|
||||
symbolOop classname,
|
||||
AccessFlags class_flags) {
|
||||
if ((class_flags.is_final() || target_method->is_final()) ||
|
||||
Handle classloader,
|
||||
symbolHandle classname,
|
||||
AccessFlags class_flags,
|
||||
TRAPS) {
|
||||
if ((class_flags.is_final() || target_method()->is_final()) ||
|
||||
// a final method never needs a new entry; final methods can be statically
|
||||
// resolved and they have to be present in the vtable only if they override
|
||||
// a super's method, in which case they re-use its entry
|
||||
(target_method->is_static()) ||
|
||||
(target_method()->is_static()) ||
|
||||
// static methods don't need to be in vtable
|
||||
(target_method->name() == vmSymbols::object_initializer_name())
|
||||
(target_method()->name() == vmSymbols::object_initializer_name())
|
||||
// <init> is never called dynamically-bound
|
||||
) {
|
||||
return false;
|
||||
@ -421,55 +412,58 @@ bool klassVtable::needs_new_vtable_entry(methodOop target_method,
|
||||
}
|
||||
|
||||
// private methods always have a new entry in the vtable
|
||||
if (target_method->is_private()) {
|
||||
// specification interpretation since classic has
|
||||
// private methods not overriding
|
||||
if (target_method()->is_private()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// search through the super class hierarchy to see if we need
|
||||
// a new entry
|
||||
symbolOop name = target_method->name();
|
||||
symbolOop signature = target_method->signature();
|
||||
ResourceMark rm;
|
||||
symbolOop name = target_method()->name();
|
||||
symbolOop signature = target_method()->signature();
|
||||
klassOop k = super;
|
||||
methodOop match_method = NULL;
|
||||
methodOop super_method = NULL;
|
||||
instanceKlass *holder = NULL;
|
||||
methodOop recheck_method = NULL;
|
||||
while (k != NULL) {
|
||||
// lookup through the hierarchy for a method with matching name and sign.
|
||||
match_method = instanceKlass::cast(k)->lookup_method(name, signature);
|
||||
if (match_method == NULL) {
|
||||
super_method = instanceKlass::cast(k)->lookup_method(name, signature);
|
||||
if (super_method == NULL) {
|
||||
break; // we still have to search for a matching miranda method
|
||||
}
|
||||
// get the class holding the matching method
|
||||
holder = instanceKlass::cast(match_method->method_holder());
|
||||
|
||||
if (!match_method->is_static()) { // we want only instance method matches
|
||||
if ((target_method->is_public() || target_method->is_protected()) &&
|
||||
(match_method->is_public() || match_method->is_protected())) {
|
||||
// target and match are public/protected; we do not need a new entry
|
||||
return false;
|
||||
}
|
||||
|
||||
if (target_method->is_package_private() &&
|
||||
match_method->is_package_private() &&
|
||||
holder->is_same_class_package(classloader, classname)) {
|
||||
// target and match are P private; we do not need a new entry
|
||||
// make sure you use that class for is_override
|
||||
instanceKlass* superk = instanceKlass::cast(super_method->method_holder());
|
||||
// we want only instance method matches
|
||||
// pretend private methods are not in the super vtable
|
||||
// since we do override around them: e.g. a.m pub/b.m private/c.m pub,
|
||||
// ignore private, c.m pub does override a.m pub
|
||||
// For classes that were not javac'd together, we also do transitive overriding around
|
||||
// methods that have less accessibility
|
||||
if ((!super_method->is_static()) &&
|
||||
(!super_method->is_private())) {
|
||||
if (superk->is_override(super_method, classloader, classname, THREAD)) {
|
||||
return false;
|
||||
// else keep looking for transitive overrides
|
||||
}
|
||||
}
|
||||
|
||||
k = holder->super(); // haven't found a match yet; continue to look
|
||||
// Start with lookup result and continue to search up
|
||||
k = superk->super(); // haven't found an override match yet; continue to look
|
||||
}
|
||||
|
||||
// if the target method is public or protected it may have a matching
|
||||
// miranda method in the super, whose entry it should re-use.
|
||||
if (target_method->is_public() || target_method->is_protected()) {
|
||||
instanceKlass *sk = instanceKlass::cast(super);
|
||||
if (sk->has_miranda_methods()) {
|
||||
if (sk->lookup_method_in_all_interfaces(name, signature) != NULL) {
|
||||
return false; // found a matching miranda; we do not need a new entry
|
||||
}
|
||||
// Actually, to handle cases that javac would not generate, we need
|
||||
// this check for all access permissions.
|
||||
instanceKlass *sk = instanceKlass::cast(super);
|
||||
if (sk->has_miranda_methods()) {
|
||||
if (sk->lookup_method_in_all_interfaces(name, signature) != NULL) {
|
||||
return false; // found a matching miranda; we do not need a new entry
|
||||
}
|
||||
}
|
||||
|
||||
return true; // found no match; we need a new entry
|
||||
}
|
||||
|
||||
@ -884,7 +878,7 @@ void klassItable::initialize_itable(bool checkconstraints, TRAPS) {
|
||||
_klass->name()->as_C_string());
|
||||
|
||||
|
||||
// Interate through all interfaces
|
||||
// Iterate through all interfaces
|
||||
int i;
|
||||
for(i = 0; i < num_interfaces; i++) {
|
||||
itableOffsetEntry* ioe = offset_entry(i);
|
||||
@ -1012,6 +1006,7 @@ void klassItable::adjust_method_entries(methodOop* old_methods, methodOop* new_m
|
||||
new_method->name()->as_C_string(),
|
||||
new_method->signature()->as_C_string()));
|
||||
}
|
||||
break;
|
||||
}
|
||||
ime++;
|
||||
}
|
||||
@ -1153,6 +1148,27 @@ int klassItable::compute_itable_index(methodOop m) {
|
||||
return index;
|
||||
}
|
||||
|
||||
|
||||
// inverse to compute_itable_index
|
||||
methodOop klassItable::method_for_itable_index(klassOop intf, int itable_index) {
|
||||
assert(instanceKlass::cast(intf)->is_interface(), "sanity check");
|
||||
objArrayOop methods = instanceKlass::cast(intf)->methods();
|
||||
|
||||
int index = itable_index;
|
||||
// Adjust for <clinit>, which is left out of table if first method
|
||||
if (methods->length() > 0 && ((methodOop)methods->obj_at(0))->name() == vmSymbols::class_initializer_name()) {
|
||||
index++;
|
||||
}
|
||||
|
||||
if (itable_index < 0 || index >= methods->length())
|
||||
return NULL; // help caller defend against bad indexes
|
||||
|
||||
methodOop m = (methodOop)methods->obj_at(index);
|
||||
assert(compute_itable_index(m) == itable_index, "correct inverse");
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
void klassVtable::verify(outputStream* st, bool forced) {
|
||||
// make sure table is initialized
|
||||
if (!Universe::is_fully_initialized()) return;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 1997-2006 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -70,8 +70,9 @@ class klassVtable : public ResourceObj {
|
||||
// conputes vtable length (in words) and the number of miranda methods
|
||||
static void compute_vtable_size_and_num_mirandas(int &vtable_length, int &num_miranda_methods,
|
||||
klassOop super, objArrayOop methods,
|
||||
AccessFlags class_flags, oop classloader,
|
||||
symbolOop classname, objArrayOop local_interfaces);
|
||||
AccessFlags class_flags, Handle classloader,
|
||||
symbolHandle classname, objArrayOop local_interfaces,
|
||||
TRAPS);
|
||||
|
||||
// RedefineClasses() API support:
|
||||
// If any entry of this vtable points to any of old_methods,
|
||||
@ -111,14 +112,16 @@ class klassVtable : public ResourceObj {
|
||||
protected:
|
||||
friend class vtableEntry;
|
||||
private:
|
||||
enum { VTABLE_TRANSITIVE_OVERRIDE_VERSION = 51 } ;
|
||||
void copy_vtable_to(vtableEntry* start);
|
||||
int initialize_from_super(KlassHandle super);
|
||||
int index_of(methodOop m, int len) const; // same as index_of, but search only up to len
|
||||
void put_method_at(methodOop m, int index);
|
||||
static bool needs_new_vtable_entry(methodOop m, klassOop super, oop classloader, symbolOop classname, AccessFlags access_flags);
|
||||
AccessType vtable_accessibility_at(int i);
|
||||
static bool needs_new_vtable_entry(methodHandle m, klassOop super, Handle classloader, symbolHandle classname, AccessFlags access_flags, TRAPS);
|
||||
|
||||
bool update_super_vtable(instanceKlass* klass, methodHandle target_method, int super_vtable_len, bool checkconstraints, TRAPS);
|
||||
bool update_inherited_vtable(instanceKlass* klass, methodHandle target_method, int super_vtable_len, bool checkconstraints, TRAPS);
|
||||
instanceKlass* find_transitive_override(instanceKlass* initialsuper, methodHandle target_method, int vtable_index,
|
||||
Handle target_loader, symbolHandle target_classname, Thread* THREAD);
|
||||
|
||||
// support for miranda methods
|
||||
bool is_miranda_entry_at(int i);
|
||||
@ -298,6 +301,8 @@ class klassItable : public ResourceObj {
|
||||
|
||||
// Resolving of method to index
|
||||
static int compute_itable_index(methodOop m);
|
||||
// ...and back again:
|
||||
static methodOop method_for_itable_index(klassOop klass, int itable_index);
|
||||
|
||||
// Debugging/Statistics
|
||||
static void print_statistics() PRODUCT_RETURN;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -247,9 +247,14 @@ void methodKlass::oop_print_on(oop obj, outputStream* st) {
|
||||
st->print_cr(" - size of params: %d", m->size_of_parameters());
|
||||
st->print_cr(" - method size: %d", m->method_size());
|
||||
st->print_cr(" - vtable index: %d", m->_vtable_index);
|
||||
st->print_cr(" - i2i entry: " INTPTR_FORMAT, m->interpreter_entry());
|
||||
st->print_cr(" - adapter: " INTPTR_FORMAT, m->adapter());
|
||||
st->print_cr(" - compiled entry " INTPTR_FORMAT, m->from_compiled_entry());
|
||||
st->print_cr(" - code size: %d", m->code_size());
|
||||
st->print_cr(" - code start: " INTPTR_FORMAT, m->code_base());
|
||||
st->print_cr(" - code end (excl): " INTPTR_FORMAT, m->code_base() + m->code_size());
|
||||
if (m->code_size() != 0) {
|
||||
st->print_cr(" - code start: " INTPTR_FORMAT, m->code_base());
|
||||
st->print_cr(" - code end (excl): " INTPTR_FORMAT, m->code_base() + m->code_size());
|
||||
}
|
||||
if (m->method_data() != NULL) {
|
||||
st->print_cr(" - method data: " INTPTR_FORMAT, (address)m->method_data());
|
||||
}
|
||||
@ -293,6 +298,10 @@ void methodKlass::oop_print_on(oop obj, outputStream* st) {
|
||||
m->code()->print_value_on(st);
|
||||
st->cr();
|
||||
}
|
||||
if (m->is_native()) {
|
||||
st->print_cr(" - native function: " INTPTR_FORMAT, m->native_function());
|
||||
st->print_cr(" - signature handler: " INTPTR_FORMAT, m->signature_handler());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -502,12 +502,25 @@ void objArrayKlass::oop_print_on(oop obj, outputStream* st) {
|
||||
}
|
||||
}
|
||||
|
||||
static int max_objArray_print_length = 4;
|
||||
|
||||
void objArrayKlass::oop_print_value_on(oop obj, outputStream* st) {
|
||||
assert(obj->is_objArray(), "must be objArray");
|
||||
st->print("a ");
|
||||
element_klass()->print_value_on(st);
|
||||
st->print("a [%d] ", objArrayOop(obj)->length());
|
||||
as_klassOop()->klass()->print_value_on(st);
|
||||
int len = objArrayOop(obj)->length();
|
||||
st->print("[%d] ", len);
|
||||
obj->print_address_on(st);
|
||||
if (PrintOopAddress || PrintMiscellaneous && (WizardMode || Verbose)) {
|
||||
st->print("{");
|
||||
for (int i = 0; i < len; i++) {
|
||||
if (i > max_objArray_print_length) {
|
||||
st->print("..."); break;
|
||||
}
|
||||
st->print(" "INTPTR_FORMAT, (intptr_t)(void*)objArrayOop(obj)->obj_at(i));
|
||||
}
|
||||
st->print(" }");
|
||||
}
|
||||
}
|
||||
|
||||
#endif // PRODUCT
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -65,11 +65,7 @@ void oopDesc::print_value_on(outputStream* st) const {
|
||||
|
||||
void oopDesc::print_address_on(outputStream* st) const {
|
||||
if (PrintOopAddress) {
|
||||
st->print("{");
|
||||
if (PrintOopAddress) {
|
||||
st->print(INTPTR_FORMAT, this);
|
||||
}
|
||||
st->print("}");
|
||||
st->print("{"INTPTR_FORMAT"}", this);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -371,6 +371,7 @@ class PhaseCFG : public Phase {
|
||||
Block *_broot; // Basic block of root
|
||||
uint _rpo_ctr;
|
||||
CFGLoop* _root_loop;
|
||||
float _outer_loop_freq; // Outmost loop frequency
|
||||
|
||||
// Per node latency estimation, valid only during GCM
|
||||
GrowableArray<uint> _node_latency;
|
||||
@ -537,6 +538,7 @@ class CFGLoop : public CFGElement {
|
||||
void compute_loop_depth(int depth);
|
||||
void compute_freq(); // compute frequency with loop assuming head freq 1.0f
|
||||
void scale_freq(); // scale frequency by loop trip count (including outer loops)
|
||||
float outer_loop_freq() const; // frequency of outer loop
|
||||
bool in_loop_nest(Block* b);
|
||||
float trip_count() const { return 1.0f / _exit_prob; }
|
||||
virtual bool is_loop() { return true; }
|
||||
|
@ -232,6 +232,14 @@ const char* InlineTree::shouldNotInline(ciMethod *callee_method, ciMethod* calle
|
||||
return "disallowed by CompilerOracle";
|
||||
}
|
||||
|
||||
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()) {
|
||||
return "profiling method";
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -391,7 +391,7 @@
|
||||
product(intx, EliminateAllocationArraySizeLimit, 64, \
|
||||
"Array size (number of elements) limit for scalar replacement") \
|
||||
\
|
||||
product(bool, UseOptoBiasInlining, true, \
|
||||
product(bool, UseOptoBiasInlining, true, \
|
||||
"Generate biased locking code in C2 ideal graph") \
|
||||
\
|
||||
product(intx, ValueSearchLimit, 1000, \
|
||||
@ -410,7 +410,7 @@
|
||||
"Miniumum %% of a successor (predecessor) for which block layout "\
|
||||
"a will allow a fork (join) in a single chain") \
|
||||
\
|
||||
product(bool, BlockLayoutRotateLoops, false, \
|
||||
product(bool, BlockLayoutRotateLoops, true, \
|
||||
"Allow back branches to be fall throughs in the block layour") \
|
||||
|
||||
C2_FLAGS(DECLARE_DEVELOPER_FLAG, DECLARE_PD_DEVELOPER_FLAG, DECLARE_PRODUCT_FLAG, DECLARE_PD_PRODUCT_FLAG, DECLARE_DIAGNOSTIC_FLAG, DECLARE_NOTPRODUCT_FLAG)
|
||||
|
@ -149,6 +149,9 @@ PhaseChaitin::PhaseChaitin(uint unique, PhaseCFG &cfg, Matcher &matcher)
|
||||
#endif
|
||||
{
|
||||
NOT_PRODUCT( Compile::TracePhase t3("ctorChaitin", &_t_ctorChaitin, TimeCompiler); )
|
||||
|
||||
_high_frequency_lrg = MIN2(float(OPTO_LRG_HIGH_FREQ), _cfg._outer_loop_freq);
|
||||
|
||||
uint i,j;
|
||||
// Build a list of basic blocks, sorted by frequency
|
||||
_blks = NEW_RESOURCE_ARRAY( Block *, _cfg._num_blocks );
|
||||
|
@ -338,6 +338,8 @@ class PhaseChaitin : public PhaseRegAlloc {
|
||||
|
||||
Block **_blks; // Array of blocks sorted by frequency for coalescing
|
||||
|
||||
float _high_frequency_lrg; // Frequency at which LRG will be spilled for debug info
|
||||
|
||||
#ifndef PRODUCT
|
||||
bool _trace_spilling;
|
||||
#endif
|
||||
@ -360,6 +362,8 @@ public:
|
||||
|
||||
uint n2lidx( const Node *n ) const { return _names[n->_idx]; }
|
||||
|
||||
float high_frequency_lrg() const { return _high_frequency_lrg; }
|
||||
|
||||
#ifndef PRODUCT
|
||||
bool trace_spilling() const { return _trace_spilling; }
|
||||
#endif
|
||||
|
@ -218,6 +218,8 @@ macro(StoreL)
|
||||
macro(StoreP)
|
||||
macro(StoreN)
|
||||
macro(StrComp)
|
||||
macro(StrEquals)
|
||||
macro(StrIndexOf)
|
||||
macro(SubD)
|
||||
macro(SubF)
|
||||
macro(SubI)
|
||||
|
@ -473,7 +473,7 @@ void PhaseAggressiveCoalesce::insert_copies( Matcher &matcher ) {
|
||||
} // End of is two-adr
|
||||
|
||||
// Insert a copy at a debug use for a lrg which has high frequency
|
||||
if( (b->_freq < OPTO_DEBUG_SPLIT_FREQ) && n->is_MachSafePoint() ) {
|
||||
if( b->_freq < OPTO_DEBUG_SPLIT_FREQ || b->is_uncommon(_phc._cfg._bbs) ) {
|
||||
// Walk the debug inputs to the node and check for lrg freq
|
||||
JVMState* jvms = n->jvms();
|
||||
uint debug_start = jvms ? jvms->debug_start() : 999999;
|
||||
@ -487,7 +487,7 @@ void PhaseAggressiveCoalesce::insert_copies( Matcher &matcher ) {
|
||||
LRG &lrg = lrgs(nidx);
|
||||
|
||||
// If this lrg has a high frequency use/def
|
||||
if( lrg._maxfreq >= OPTO_LRG_HIGH_FREQ ) {
|
||||
if( lrg._maxfreq >= _phc.high_frequency_lrg() ) {
|
||||
// If the live range is also live out of this block (like it
|
||||
// would be for a fast/slow idiom), the normal spill mechanism
|
||||
// does an excellent job. If it is not live out of this block
|
||||
|
@ -438,6 +438,12 @@ Block* PhaseCFG::insert_anti_dependences(Block* LCA, Node* load, bool verify) {
|
||||
#endif
|
||||
assert(load_alias_idx || (load->is_Mach() && load->as_Mach()->ideal_Opcode() == Op_StrComp),
|
||||
"String compare is only known 'load' that does not conflict with any stores");
|
||||
assert(load_alias_idx || (load->is_Mach() && load->as_Mach()->ideal_Opcode() == Op_StrEquals),
|
||||
"String equals is a 'load' that does not conflict with any stores");
|
||||
assert(load_alias_idx || (load->is_Mach() && load->as_Mach()->ideal_Opcode() == Op_StrIndexOf),
|
||||
"String indexOf is a 'load' that does not conflict with any stores");
|
||||
assert(load_alias_idx || (load->is_Mach() && load->as_Mach()->ideal_Opcode() == Op_AryEq),
|
||||
"Arrays equals is a 'load' that do not conflict with any stores");
|
||||
|
||||
if (!C->alias_type(load_alias_idx)->is_rewritable()) {
|
||||
// It is impossible to spoil this load by putting stores before it,
|
||||
@ -1374,6 +1380,9 @@ void PhaseCFG::Estimate_Block_Frequency() {
|
||||
_root_loop->_freq = 1.0;
|
||||
_root_loop->scale_freq();
|
||||
|
||||
// Save outmost loop frequency for LRG frequency threshold
|
||||
_outer_loop_freq = _root_loop->outer_loop_freq();
|
||||
|
||||
// force paths ending at uncommon traps to be infrequent
|
||||
if (!C->do_freq_based_layout()) {
|
||||
Block_List worklist;
|
||||
@ -1898,6 +1907,7 @@ bool CFGLoop::in_loop_nest(Block* b) {
|
||||
// Do a top down traversal of loop tree (visit outer loops first.)
|
||||
void CFGLoop::scale_freq() {
|
||||
float loop_freq = _freq * trip_count();
|
||||
_freq = loop_freq;
|
||||
for (int i = 0; i < _members.length(); i++) {
|
||||
CFGElement* s = _members.at(i);
|
||||
float block_freq = s->_freq * loop_freq;
|
||||
@ -1912,6 +1922,14 @@ void CFGLoop::scale_freq() {
|
||||
}
|
||||
}
|
||||
|
||||
// Frequency of outer loop
|
||||
float CFGLoop::outer_loop_freq() const {
|
||||
if (_child != NULL) {
|
||||
return _child->_freq;
|
||||
}
|
||||
return _freq;
|
||||
}
|
||||
|
||||
#ifndef PRODUCT
|
||||
//------------------------------dump_tree--------------------------------------
|
||||
void CFGLoop::dump_tree() const {
|
||||
|
@ -137,6 +137,8 @@ void Block::implicit_null_check(PhaseCFG *cfg, Node *proj, Node *val, int allowe
|
||||
if( mach->in(2) != val ) continue;
|
||||
break; // Found a memory op?
|
||||
case Op_StrComp:
|
||||
case Op_StrEquals:
|
||||
case Op_StrIndexOf:
|
||||
case Op_AryEq:
|
||||
// Not a legit memory op for implicit null check regardless of
|
||||
// embedded loads
|
||||
|
@ -136,6 +136,7 @@ class LibraryCallKit : public GraphKit {
|
||||
bool inline_string_compareTo();
|
||||
bool inline_string_indexOf();
|
||||
Node* string_indexOf(Node* string_object, ciTypeArray* target_array, jint offset, jint cache_i, jint md2_i);
|
||||
bool inline_string_equals();
|
||||
Node* pop_math_arg();
|
||||
bool runtime_math(const TypeFunc* call_type, address funcAddr, const char* funcName);
|
||||
bool inline_math_native(vmIntrinsics::ID id);
|
||||
@ -261,6 +262,7 @@ CallGenerator* Compile::make_vm_intrinsic(ciMethod* m, bool is_virtual) {
|
||||
switch (id) {
|
||||
case vmIntrinsics::_indexOf:
|
||||
case vmIntrinsics::_compareTo:
|
||||
case vmIntrinsics::_equals:
|
||||
case vmIntrinsics::_equalsC:
|
||||
break; // InlineNatives does not control String.compareTo
|
||||
default:
|
||||
@ -275,6 +277,9 @@ CallGenerator* Compile::make_vm_intrinsic(ciMethod* m, bool is_virtual) {
|
||||
case vmIntrinsics::_indexOf:
|
||||
if (!SpecialStringIndexOf) return NULL;
|
||||
break;
|
||||
case vmIntrinsics::_equals:
|
||||
if (!SpecialStringEquals) return NULL;
|
||||
break;
|
||||
case vmIntrinsics::_equalsC:
|
||||
if (!SpecialArraysEquals) return NULL;
|
||||
break;
|
||||
@ -442,6 +447,8 @@ bool LibraryCallKit::try_to_inline() {
|
||||
return inline_string_compareTo();
|
||||
case vmIntrinsics::_indexOf:
|
||||
return inline_string_indexOf();
|
||||
case vmIntrinsics::_equals:
|
||||
return inline_string_equals();
|
||||
|
||||
case vmIntrinsics::_getObject:
|
||||
return inline_unsafe_access(!is_native_ptr, !is_store, T_OBJECT, false);
|
||||
@ -793,6 +800,8 @@ Node* LibraryCallKit::generate_current_thread(Node* &tls_output) {
|
||||
//------------------------------inline_string_compareTo------------------------
|
||||
bool LibraryCallKit::inline_string_compareTo() {
|
||||
|
||||
if (!Matcher::has_match_rule(Op_StrComp)) return false;
|
||||
|
||||
const int value_offset = java_lang_String::value_offset_in_bytes();
|
||||
const int count_offset = java_lang_String::count_offset_in_bytes();
|
||||
const int offset_offset = java_lang_String::offset_offset_in_bytes();
|
||||
@ -830,6 +839,82 @@ bool LibraryCallKit::inline_string_compareTo() {
|
||||
return true;
|
||||
}
|
||||
|
||||
//------------------------------inline_string_equals------------------------
|
||||
bool LibraryCallKit::inline_string_equals() {
|
||||
|
||||
if (!Matcher::has_match_rule(Op_StrEquals)) return false;
|
||||
|
||||
const int value_offset = java_lang_String::value_offset_in_bytes();
|
||||
const int count_offset = java_lang_String::count_offset_in_bytes();
|
||||
const int offset_offset = java_lang_String::offset_offset_in_bytes();
|
||||
|
||||
_sp += 2;
|
||||
Node* argument = pop(); // pop non-receiver first: it was pushed second
|
||||
Node* receiver = pop();
|
||||
|
||||
// Null check on self without removing any arguments. The argument
|
||||
// null check technically happens in the wrong place, which can lead to
|
||||
// invalid stack traces when string compare is inlined into a method
|
||||
// which handles NullPointerExceptions.
|
||||
_sp += 2;
|
||||
receiver = do_null_check(receiver, T_OBJECT);
|
||||
//should not do null check for argument for String.equals(), because spec
|
||||
//allows to specify NULL as argument.
|
||||
_sp -= 2;
|
||||
|
||||
if (stopped()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// get String klass for instanceOf
|
||||
ciInstanceKlass* klass = env()->String_klass();
|
||||
|
||||
// two paths (plus control) merge
|
||||
RegionNode* region = new (C, 3) RegionNode(3);
|
||||
Node* phi = new (C, 3) PhiNode(region, TypeInt::BOOL);
|
||||
|
||||
Node* inst = gen_instanceof(argument, makecon(TypeKlassPtr::make(klass)));
|
||||
Node* cmp = _gvn.transform(new (C, 3) CmpINode(inst, intcon(1)));
|
||||
Node* bol = _gvn.transform(new (C, 2) BoolNode(cmp, BoolTest::eq));
|
||||
|
||||
IfNode* iff = create_and_map_if(control(), bol, PROB_MAX, COUNT_UNKNOWN);
|
||||
|
||||
Node* if_true = _gvn.transform(new (C, 1) IfTrueNode(iff));
|
||||
set_control(if_true);
|
||||
|
||||
const TypeInstPtr* string_type =
|
||||
TypeInstPtr::make(TypePtr::BotPTR, klass, false, NULL, 0);
|
||||
|
||||
// instanceOf == true
|
||||
Node* equals =
|
||||
_gvn.transform(new (C, 7) StrEqualsNode(
|
||||
control(),
|
||||
memory(TypeAryPtr::CHARS),
|
||||
memory(string_type->add_offset(value_offset)),
|
||||
memory(string_type->add_offset(count_offset)),
|
||||
memory(string_type->add_offset(offset_offset)),
|
||||
receiver,
|
||||
argument));
|
||||
|
||||
phi->init_req(1, _gvn.transform(equals));
|
||||
region->init_req(1, if_true);
|
||||
|
||||
//instanceOf == false, fallthrough
|
||||
Node* if_false = _gvn.transform(new (C, 1) IfFalseNode(iff));
|
||||
set_control(if_false);
|
||||
|
||||
phi->init_req(2, _gvn.transform(intcon(0)));
|
||||
region->init_req(2, if_false);
|
||||
|
||||
// post merge
|
||||
set_control(_gvn.transform(region));
|
||||
record_for_igvn(region);
|
||||
|
||||
push(_gvn.transform(phi));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//------------------------------inline_array_equals----------------------------
|
||||
bool LibraryCallKit::inline_array_equals() {
|
||||
|
||||
@ -994,80 +1079,115 @@ Node* LibraryCallKit::string_indexOf(Node* string_object, ciTypeArray* target_ar
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
//------------------------------inline_string_indexOf------------------------
|
||||
bool LibraryCallKit::inline_string_indexOf() {
|
||||
|
||||
_sp += 2;
|
||||
Node *argument = pop(); // pop non-receiver first: it was pushed second
|
||||
Node *receiver = pop();
|
||||
|
||||
// don't intrinsify if argument isn't a constant string.
|
||||
if (!argument->is_Con()) {
|
||||
return false;
|
||||
}
|
||||
const TypeOopPtr* str_type = _gvn.type(argument)->isa_oopptr();
|
||||
if (str_type == NULL) {
|
||||
return false;
|
||||
}
|
||||
ciInstanceKlass* klass = env()->String_klass();
|
||||
ciObject* str_const = str_type->const_oop();
|
||||
if (str_const == NULL || str_const->klass() != klass) {
|
||||
return false;
|
||||
}
|
||||
ciInstance* str = str_const->as_instance();
|
||||
assert(str != NULL, "must be instance");
|
||||
|
||||
const int value_offset = java_lang_String::value_offset_in_bytes();
|
||||
const int count_offset = java_lang_String::count_offset_in_bytes();
|
||||
const int offset_offset = java_lang_String::offset_offset_in_bytes();
|
||||
|
||||
ciObject* v = str->field_value_by_offset(value_offset).as_object();
|
||||
int o = str->field_value_by_offset(offset_offset).as_int();
|
||||
int c = str->field_value_by_offset(count_offset).as_int();
|
||||
ciTypeArray* pat = v->as_type_array(); // pattern (argument) character array
|
||||
|
||||
// constant strings have no offset and count == length which
|
||||
// simplifies the resulting code somewhat so lets optimize for that.
|
||||
if (o != 0 || c != pat->length()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Null check on self without removing any arguments. The argument
|
||||
// null check technically happens in the wrong place, which can lead to
|
||||
// invalid stack traces when string compare is inlined into a method
|
||||
// which handles NullPointerExceptions.
|
||||
_sp += 2;
|
||||
receiver = do_null_check(receiver, T_OBJECT);
|
||||
// No null check on the argument is needed since it's a constant String oop.
|
||||
_sp -= 2;
|
||||
if (stopped()) {
|
||||
return true;
|
||||
}
|
||||
Node *argument = pop(); // pop non-receiver first: it was pushed second
|
||||
Node *receiver = pop();
|
||||
|
||||
// The null string as a pattern always returns 0 (match at beginning of string)
|
||||
if (c == 0) {
|
||||
push(intcon(0));
|
||||
return true;
|
||||
}
|
||||
Node* result;
|
||||
if (Matcher::has_match_rule(Op_StrIndexOf) &&
|
||||
UseSSE42Intrinsics) {
|
||||
// Generate SSE4.2 version of indexOf
|
||||
// We currently only have match rules that use SSE4.2
|
||||
|
||||
jchar lastChar = pat->char_at(o + (c - 1));
|
||||
int cache = 0;
|
||||
int i;
|
||||
for (i = 0; i < c - 1; i++) {
|
||||
assert(i < pat->length(), "out of range");
|
||||
cache |= (1 << (pat->char_at(o + i) & (sizeof(cache) * BitsPerByte - 1)));
|
||||
}
|
||||
// Null check on self without removing any arguments. The argument
|
||||
// null check technically happens in the wrong place, which can lead to
|
||||
// invalid stack traces when string compare is inlined into a method
|
||||
// which handles NullPointerExceptions.
|
||||
_sp += 2;
|
||||
receiver = do_null_check(receiver, T_OBJECT);
|
||||
argument = do_null_check(argument, T_OBJECT);
|
||||
_sp -= 2;
|
||||
|
||||
int md2 = c;
|
||||
for (i = 0; i < c - 1; i++) {
|
||||
assert(i < pat->length(), "out of range");
|
||||
if (pat->char_at(o + i) == lastChar) {
|
||||
md2 = (c - 1) - i;
|
||||
if (stopped()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
ciInstanceKlass* klass = env()->String_klass();
|
||||
const TypeInstPtr* string_type =
|
||||
TypeInstPtr::make(TypePtr::BotPTR, klass, false, NULL, 0);
|
||||
|
||||
result =
|
||||
_gvn.transform(new (C, 7)
|
||||
StrIndexOfNode(control(),
|
||||
memory(TypeAryPtr::CHARS),
|
||||
memory(string_type->add_offset(value_offset)),
|
||||
memory(string_type->add_offset(count_offset)),
|
||||
memory(string_type->add_offset(offset_offset)),
|
||||
receiver,
|
||||
argument));
|
||||
} else { //Use LibraryCallKit::string_indexOf
|
||||
// don't intrinsify is argument isn't a constant string.
|
||||
if (!argument->is_Con()) {
|
||||
return false;
|
||||
}
|
||||
const TypeOopPtr* str_type = _gvn.type(argument)->isa_oopptr();
|
||||
if (str_type == NULL) {
|
||||
return false;
|
||||
}
|
||||
ciInstanceKlass* klass = env()->String_klass();
|
||||
ciObject* str_const = str_type->const_oop();
|
||||
if (str_const == NULL || str_const->klass() != klass) {
|
||||
return false;
|
||||
}
|
||||
ciInstance* str = str_const->as_instance();
|
||||
assert(str != NULL, "must be instance");
|
||||
|
||||
ciObject* v = str->field_value_by_offset(value_offset).as_object();
|
||||
int o = str->field_value_by_offset(offset_offset).as_int();
|
||||
int c = str->field_value_by_offset(count_offset).as_int();
|
||||
ciTypeArray* pat = v->as_type_array(); // pattern (argument) character array
|
||||
|
||||
// constant strings have no offset and count == length which
|
||||
// simplifies the resulting code somewhat so lets optimize for that.
|
||||
if (o != 0 || c != pat->length()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Null check on self without removing any arguments. The argument
|
||||
// null check technically happens in the wrong place, which can lead to
|
||||
// invalid stack traces when string compare is inlined into a method
|
||||
// which handles NullPointerExceptions.
|
||||
_sp += 2;
|
||||
receiver = do_null_check(receiver, T_OBJECT);
|
||||
// No null check on the argument is needed since it's a constant String oop.
|
||||
_sp -= 2;
|
||||
if (stopped()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// The null string as a pattern always returns 0 (match at beginning of string)
|
||||
if (c == 0) {
|
||||
push(intcon(0));
|
||||
return true;
|
||||
}
|
||||
|
||||
// Generate default indexOf
|
||||
jchar lastChar = pat->char_at(o + (c - 1));
|
||||
int cache = 0;
|
||||
int i;
|
||||
for (i = 0; i < c - 1; i++) {
|
||||
assert(i < pat->length(), "out of range");
|
||||
cache |= (1 << (pat->char_at(o + i) & (sizeof(cache) * BitsPerByte - 1)));
|
||||
}
|
||||
|
||||
int md2 = c;
|
||||
for (i = 0; i < c - 1; i++) {
|
||||
assert(i < pat->length(), "out of range");
|
||||
if (pat->char_at(o + i) == lastChar) {
|
||||
md2 = (c - 1) - i;
|
||||
}
|
||||
}
|
||||
|
||||
result = string_indexOf(receiver, pat, o, cache, md2);
|
||||
}
|
||||
|
||||
Node* result = string_indexOf(receiver, pat, o, cache, md2);
|
||||
push(result);
|
||||
return true;
|
||||
}
|
||||
|
@ -2668,6 +2668,8 @@ void PhaseIdealLoop::build_loop_late_post( Node *n, const PhaseIdealLoop *verify
|
||||
case Op_LoadD_unaligned:
|
||||
case Op_LoadL_unaligned:
|
||||
case Op_StrComp: // Does a bunch of load-like effects
|
||||
case Op_StrEquals:
|
||||
case Op_StrIndexOf:
|
||||
case Op_AryEq:
|
||||
pinned = false;
|
||||
}
|
||||
|
@ -340,6 +340,10 @@ const class TypePtr *MachNode::adr_type() const {
|
||||
if (base == NodeSentinel) return TypePtr::BOTTOM;
|
||||
|
||||
const Type* t = base->bottom_type();
|
||||
if (UseCompressedOops && Universe::narrow_oop_shift() == 0) {
|
||||
// 32-bit unscaled narrow oop can be the base of any address expression
|
||||
t = t->make_ptr();
|
||||
}
|
||||
if (t->isa_intptr_t() && offset != 0 && offset != Type::OffsetBot) {
|
||||
// We cannot assert that the offset does not look oop-ish here.
|
||||
// Depending on the heap layout the cardmark base could land
|
||||
@ -353,6 +357,7 @@ const class TypePtr *MachNode::adr_type() const {
|
||||
|
||||
// be conservative if we do not recognize the type
|
||||
if (tp == NULL) {
|
||||
assert(false, "this path may produce not optimal code");
|
||||
return TypePtr::BOTTOM;
|
||||
}
|
||||
assert(tp->base() != Type::AnyPtr, "not a bare pointer");
|
||||
|
@ -746,6 +746,8 @@ static void match_alias_type(Compile* C, Node* n, Node* m) {
|
||||
if (nidx == Compile::AliasIdxBot && midx == Compile::AliasIdxTop) {
|
||||
switch (n->Opcode()) {
|
||||
case Op_StrComp:
|
||||
case Op_StrEquals:
|
||||
case Op_StrIndexOf:
|
||||
case Op_AryEq:
|
||||
case Op_MemBarVolatile:
|
||||
case Op_MemBarCPUOrder: // %%% these ideals should have narrower adr_type?
|
||||
@ -1788,6 +1790,8 @@ void Matcher::find_shared( Node *n ) {
|
||||
mstack.push(n->in(0), Pre_Visit); // Visit Control input
|
||||
continue; // while (mstack.is_nonempty())
|
||||
case Op_StrComp:
|
||||
case Op_StrEquals:
|
||||
case Op_StrIndexOf:
|
||||
case Op_AryEq:
|
||||
set_shared(n); // Force result into register (it will be anyways)
|
||||
break;
|
||||
|
@ -2481,6 +2481,31 @@ Node *StrCompNode::Ideal(PhaseGVN *phase, bool can_reshape){
|
||||
return remove_dead_region(phase, can_reshape) ? this : NULL;
|
||||
}
|
||||
|
||||
// Do we match on this edge? No memory edges
|
||||
uint StrEqualsNode::match_edge(uint idx) const {
|
||||
return idx == 5 || idx == 6;
|
||||
}
|
||||
|
||||
//------------------------------Ideal------------------------------------------
|
||||
// Return a node which is more "ideal" than the current node. Strip out
|
||||
// control copies
|
||||
Node *StrEqualsNode::Ideal(PhaseGVN *phase, bool can_reshape){
|
||||
return remove_dead_region(phase, can_reshape) ? this : NULL;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// Do we match on this edge? No memory edges
|
||||
uint StrIndexOfNode::match_edge(uint idx) const {
|
||||
return idx == 5 || idx == 6;
|
||||
}
|
||||
|
||||
//------------------------------Ideal------------------------------------------
|
||||
// Return a node which is more "ideal" than the current node. Strip out
|
||||
// control copies
|
||||
Node *StrIndexOfNode::Ideal(PhaseGVN *phase, bool can_reshape){
|
||||
return remove_dead_region(phase, can_reshape) ? this : NULL;
|
||||
}
|
||||
|
||||
//------------------------------Ideal------------------------------------------
|
||||
// Return a node which is more "ideal" than the current node. Strip out
|
||||
// control copies
|
||||
@ -2488,7 +2513,6 @@ Node *AryEqNode::Ideal(PhaseGVN *phase, bool can_reshape){
|
||||
return remove_dead_region(phase, can_reshape) ? this : NULL;
|
||||
}
|
||||
|
||||
|
||||
//=============================================================================
|
||||
MemBarNode::MemBarNode(Compile* C, int alias_idx, Node* precedent)
|
||||
: MultiNode(TypeFunc::Parms + (precedent == NULL? 0: 1)),
|
||||
|
@ -765,6 +765,54 @@ public:
|
||||
virtual Node *Ideal(PhaseGVN *phase, bool can_reshape);
|
||||
};
|
||||
|
||||
//------------------------------StrEquals-------------------------------------
|
||||
class StrEqualsNode: public Node {
|
||||
public:
|
||||
StrEqualsNode(Node *control,
|
||||
Node* char_array_mem,
|
||||
Node* value_mem,
|
||||
Node* count_mem,
|
||||
Node* offset_mem,
|
||||
Node* s1, Node* s2): Node(control,
|
||||
char_array_mem,
|
||||
value_mem,
|
||||
count_mem,
|
||||
offset_mem,
|
||||
s1, s2) {};
|
||||
virtual int Opcode() const;
|
||||
virtual bool depends_only_on_test() const { return false; }
|
||||
virtual const Type* bottom_type() const { return TypeInt::BOOL; }
|
||||
// a StrEqualsNode (conservatively) aliases with everything:
|
||||
virtual const TypePtr* adr_type() const { return TypePtr::BOTTOM; }
|
||||
virtual uint match_edge(uint idx) const;
|
||||
virtual uint ideal_reg() const { return Op_RegI; }
|
||||
virtual Node *Ideal(PhaseGVN *phase, bool can_reshape);
|
||||
};
|
||||
|
||||
//------------------------------StrIndexOf-------------------------------------
|
||||
class StrIndexOfNode: public Node {
|
||||
public:
|
||||
StrIndexOfNode(Node *control,
|
||||
Node* char_array_mem,
|
||||
Node* value_mem,
|
||||
Node* count_mem,
|
||||
Node* offset_mem,
|
||||
Node* s1, Node* s2): Node(control,
|
||||
char_array_mem,
|
||||
value_mem,
|
||||
count_mem,
|
||||
offset_mem,
|
||||
s1, s2) {};
|
||||
virtual int Opcode() const;
|
||||
virtual bool depends_only_on_test() const { return false; }
|
||||
virtual const Type* bottom_type() const { return TypeInt::INT; }
|
||||
// a StrIndexOfNode (conservatively) aliases with everything:
|
||||
virtual const TypePtr* adr_type() const { return TypePtr::BOTTOM; }
|
||||
virtual uint match_edge(uint idx) const;
|
||||
virtual uint ideal_reg() const { return Op_RegI; }
|
||||
virtual Node *Ideal(PhaseGVN *phase, bool can_reshape);
|
||||
};
|
||||
|
||||
//------------------------------AryEq---------------------------------------
|
||||
class AryEqNode: public Node {
|
||||
public:
|
||||
|
@ -95,7 +95,7 @@ Node *Parse::fetch_interpreter_state(int index,
|
||||
switch( bt ) { // Signature is flattened
|
||||
case T_INT: l = new (C, 3) LoadINode( 0, mem, adr, TypeRawPtr::BOTTOM ); break;
|
||||
case T_FLOAT: l = new (C, 3) LoadFNode( 0, mem, adr, TypeRawPtr::BOTTOM ); break;
|
||||
case T_ADDRESS:
|
||||
case T_ADDRESS: l = new (C, 3) LoadPNode( 0, mem, adr, TypeRawPtr::BOTTOM, TypeRawPtr::BOTTOM ); break;
|
||||
case T_OBJECT: l = new (C, 3) LoadPNode( 0, mem, adr, TypeRawPtr::BOTTOM, TypeInstPtr::BOTTOM ); break;
|
||||
case T_LONG:
|
||||
case T_DOUBLE: {
|
||||
|
@ -639,8 +639,8 @@ const Type *CmpPNode::sub( const Type *t1, const Type *t2 ) const {
|
||||
int kps = (p0->isa_klassptr()?1:0) + (p1->isa_klassptr()?1:0);
|
||||
if (klass0 && klass1 &&
|
||||
kps != 1 && // both or neither are klass pointers
|
||||
!klass0->is_interface() && // do not trust interfaces
|
||||
!klass1->is_interface()) {
|
||||
klass0->is_loaded() && !klass0->is_interface() && // do not trust interfaces
|
||||
klass1->is_loaded() && !klass1->is_interface()) {
|
||||
bool unrelated_classes = false;
|
||||
// See if neither subclasses the other, or if the class on top
|
||||
// is precise. In either of these cases, the compare is known
|
||||
|
@ -454,9 +454,13 @@ void SuperWord::mem_slice_preds(Node* start, Node* stop, GrowableArray<Node*> &p
|
||||
// or need to run igvn.optimize() again before SLP
|
||||
} else if (out->is_Phi() && out->bottom_type() == Type::MEMORY && !in_bb(out)) {
|
||||
// Ditto. Not sure what else to check further.
|
||||
} else if (out->Opcode() == Op_StoreCM && out->in(4) == n) {
|
||||
} else if (out->Opcode() == Op_StoreCM && out->in(MemNode::OopStore) == n) {
|
||||
// StoreCM has an input edge used as a precedence edge.
|
||||
// Maybe an issue when oop stores are vectorized.
|
||||
} else if( out->is_MergeMem() && prev &&
|
||||
prev->Opcode() == Op_StoreCM && out == prev->in(MemNode::OopStore)) {
|
||||
// Oop store is a MergeMem! This should not happen. Temporarily remove the assertion
|
||||
// for this case because it could not be superwordized anyway.
|
||||
} else {
|
||||
assert(out == prev || prev == NULL, "no branches off of store slice");
|
||||
}
|
||||
@ -912,54 +916,175 @@ void SuperWord::schedule() {
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------co_locate_pack---------------------------
|
||||
// Within a pack, move stores down to the last executed store,
|
||||
// and move loads up to the first executed load.
|
||||
//-------------------------------remove_and_insert-------------------
|
||||
//remove "current" from its current position in the memory graph and insert
|
||||
//it after the appropriate insertion point (lip or uip)
|
||||
void SuperWord::remove_and_insert(MemNode *current, MemNode *prev, MemNode *lip,
|
||||
Node *uip, Unique_Node_List &sched_before) {
|
||||
Node* my_mem = current->in(MemNode::Memory);
|
||||
_igvn.hash_delete(current);
|
||||
_igvn.hash_delete(my_mem);
|
||||
|
||||
//remove current_store from its current position in the memmory graph
|
||||
for (DUIterator i = current->outs(); current->has_out(i); i++) {
|
||||
Node* use = current->out(i);
|
||||
if (use->is_Mem()) {
|
||||
assert(use->in(MemNode::Memory) == current, "must be");
|
||||
_igvn.hash_delete(use);
|
||||
if (use == prev) { // connect prev to my_mem
|
||||
use->set_req(MemNode::Memory, my_mem);
|
||||
} else if (sched_before.member(use)) {
|
||||
_igvn.hash_delete(uip);
|
||||
use->set_req(MemNode::Memory, uip);
|
||||
} else {
|
||||
_igvn.hash_delete(lip);
|
||||
use->set_req(MemNode::Memory, lip);
|
||||
}
|
||||
_igvn._worklist.push(use);
|
||||
--i; //deleted this edge; rescan position
|
||||
}
|
||||
}
|
||||
|
||||
bool sched_up = sched_before.member(current);
|
||||
Node *insert_pt = sched_up ? uip : lip;
|
||||
_igvn.hash_delete(insert_pt);
|
||||
|
||||
// all uses of insert_pt's memory state should use current's instead
|
||||
for (DUIterator i = insert_pt->outs(); insert_pt->has_out(i); i++) {
|
||||
Node* use = insert_pt->out(i);
|
||||
if (use->is_Mem()) {
|
||||
assert(use->in(MemNode::Memory) == insert_pt, "must be");
|
||||
_igvn.hash_delete(use);
|
||||
use->set_req(MemNode::Memory, current);
|
||||
_igvn._worklist.push(use);
|
||||
--i; //deleted this edge; rescan position
|
||||
} else if (!sched_up && use->is_Phi() && use->bottom_type() == Type::MEMORY) {
|
||||
uint pos; //lip (lower insert point) must be the last one in the memory slice
|
||||
_igvn.hash_delete(use);
|
||||
for (pos=1; pos < use->req(); pos++) {
|
||||
if (use->in(pos) == insert_pt) break;
|
||||
}
|
||||
use->set_req(pos, current);
|
||||
_igvn._worklist.push(use);
|
||||
--i;
|
||||
}
|
||||
}
|
||||
|
||||
//connect current to insert_pt
|
||||
current->set_req(MemNode::Memory, insert_pt);
|
||||
_igvn._worklist.push(current);
|
||||
}
|
||||
|
||||
//------------------------------co_locate_pack----------------------------------
|
||||
// To schedule a store pack, we need to move any sandwiched memory ops either before
|
||||
// or after the pack, based upon dependence information:
|
||||
// (1) If any store in the pack depends on the sandwiched memory op, the
|
||||
// sandwiched memory op must be scheduled BEFORE the pack;
|
||||
// (2) If a sandwiched memory op depends on any store in the pack, the
|
||||
// sandwiched memory op must be scheduled AFTER the pack;
|
||||
// (3) If a sandwiched memory op (say, memA) depends on another sandwiched
|
||||
// memory op (say memB), memB must be scheduled before memA. So, if memA is
|
||||
// scheduled before the pack, memB must also be scheduled before the pack;
|
||||
// (4) If there is no dependence restriction for a sandwiched memory op, we simply
|
||||
// schedule this store AFTER the pack
|
||||
// (5) We know there is no dependence cycle, so there in no other case;
|
||||
// (6) Finally, all memory ops in another single pack should be moved in the same direction.
|
||||
//
|
||||
// To schedule a load pack: the memory edge of every loads in the pack must be
|
||||
// the same as the memory edge of the last executed load in the pack
|
||||
void SuperWord::co_locate_pack(Node_List* pk) {
|
||||
if (pk->at(0)->is_Store()) {
|
||||
// Push Stores down towards last executed pack member
|
||||
MemNode* first = executed_first(pk)->as_Mem();
|
||||
MemNode* last = executed_last(pk)->as_Mem();
|
||||
MemNode* insert_pt = last;
|
||||
Unique_Node_List schedule_before_pack;
|
||||
Unique_Node_List memops;
|
||||
|
||||
MemNode* current = last->in(MemNode::Memory)->as_Mem();
|
||||
MemNode* previous = last;
|
||||
while (true) {
|
||||
assert(in_bb(current), "stay in block");
|
||||
memops.push(previous);
|
||||
for (DUIterator i = current->outs(); current->has_out(i); i++) {
|
||||
Node* use = current->out(i);
|
||||
if (use->is_Mem() && use != previous)
|
||||
memops.push(use);
|
||||
}
|
||||
if(current == first) break;
|
||||
previous = current;
|
||||
current = current->in(MemNode::Memory)->as_Mem();
|
||||
}
|
||||
|
||||
// determine which memory operations should be scheduled before the pack
|
||||
for (uint i = 1; i < memops.size(); i++) {
|
||||
Node *s1 = memops.at(i);
|
||||
if (!in_pack(s1, pk) && !schedule_before_pack.member(s1)) {
|
||||
for (uint j = 0; j< i; j++) {
|
||||
Node *s2 = memops.at(j);
|
||||
if (!independent(s1, s2)) {
|
||||
if (in_pack(s2, pk) || schedule_before_pack.member(s2)) {
|
||||
schedule_before_pack.push(s1); //s1 must be scheduled before
|
||||
Node_List* mem_pk = my_pack(s1);
|
||||
if (mem_pk != NULL) {
|
||||
for (uint ii = 0; ii < mem_pk->size(); ii++) {
|
||||
Node* s = mem_pk->at(ii); // follow partner
|
||||
if (memops.member(s) && !schedule_before_pack.member(s))
|
||||
schedule_before_pack.push(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MemNode* lower_insert_pt = last;
|
||||
Node* upper_insert_pt = first->in(MemNode::Memory);
|
||||
previous = last; //previous store in pk
|
||||
current = last->in(MemNode::Memory)->as_Mem();
|
||||
|
||||
//start scheduling from "last" to "first"
|
||||
while (true) {
|
||||
assert(in_bb(current), "stay in block");
|
||||
assert(in_pack(previous, pk), "previous stays in pack");
|
||||
Node* my_mem = current->in(MemNode::Memory);
|
||||
|
||||
if (in_pack(current, pk)) {
|
||||
// Forward users of my memory state to my input memory state
|
||||
// Forward users of my memory state (except "previous) to my input memory state
|
||||
_igvn.hash_delete(current);
|
||||
_igvn.hash_delete(my_mem);
|
||||
for (DUIterator i = current->outs(); current->has_out(i); i++) {
|
||||
Node* use = current->out(i);
|
||||
if (use->is_Mem()) {
|
||||
if (use->is_Mem() && use != previous) {
|
||||
assert(use->in(MemNode::Memory) == current, "must be");
|
||||
_igvn.hash_delete(use);
|
||||
use->set_req(MemNode::Memory, my_mem);
|
||||
if (schedule_before_pack.member(use)) {
|
||||
_igvn.hash_delete(upper_insert_pt);
|
||||
use->set_req(MemNode::Memory, upper_insert_pt);
|
||||
} else {
|
||||
_igvn.hash_delete(lower_insert_pt);
|
||||
use->set_req(MemNode::Memory, lower_insert_pt);
|
||||
}
|
||||
_igvn._worklist.push(use);
|
||||
--i; // deleted this edge; rescan position
|
||||
}
|
||||
}
|
||||
// put current immediately before insert_pt
|
||||
current->set_req(MemNode::Memory, insert_pt->in(MemNode::Memory));
|
||||
_igvn.hash_delete(insert_pt);
|
||||
insert_pt->set_req(MemNode::Memory, current);
|
||||
_igvn._worklist.push(insert_pt);
|
||||
_igvn._worklist.push(current);
|
||||
insert_pt = current;
|
||||
previous = current;
|
||||
} else { // !in_pack(current, pk) ==> a sandwiched store
|
||||
remove_and_insert(current, previous, lower_insert_pt, upper_insert_pt, schedule_before_pack);
|
||||
}
|
||||
|
||||
if (current == first) break;
|
||||
current = my_mem->as_Mem();
|
||||
}
|
||||
} else if (pk->at(0)->is_Load()) {
|
||||
// Pull Loads up towards first executed pack member
|
||||
LoadNode* first = executed_first(pk)->as_Load();
|
||||
Node* first_mem = first->in(MemNode::Memory);
|
||||
_igvn.hash_delete(first_mem);
|
||||
// Give each load same memory state as first
|
||||
} // end while
|
||||
} else if (pk->at(0)->is_Load()) { //load
|
||||
// all use the memory state that the last executed load uses
|
||||
LoadNode* last_load = executed_last(pk)->as_Load();
|
||||
Node* last_mem = last_load->in(MemNode::Memory);
|
||||
_igvn.hash_delete(last_mem);
|
||||
// Give each load same memory state as last
|
||||
for (uint i = 0; i < pk->size(); i++) {
|
||||
LoadNode* ld = pk->at(i)->as_Load();
|
||||
_igvn.hash_delete(ld);
|
||||
ld->set_req(MemNode::Memory, first_mem);
|
||||
ld->set_req(MemNode::Memory, last_mem);
|
||||
_igvn._worklist.push(ld);
|
||||
}
|
||||
}
|
||||
|
@ -341,8 +341,11 @@ class SuperWord : public ResourceObj {
|
||||
void filter_packs();
|
||||
// Adjust the memory graph for the packed operations
|
||||
void schedule();
|
||||
// Within a pack, move stores down to the last executed store,
|
||||
// and move loads up to the first executed load.
|
||||
// Remove "current" from its current position in the memory graph and insert
|
||||
// it after the appropriate insert points (lip or uip);
|
||||
void remove_and_insert(MemNode *current, MemNode *prev, MemNode *lip, Node *uip, Unique_Node_List &schd_before);
|
||||
// Within a store pack, schedule stores together by moving out the sandwiched memory ops according
|
||||
// to dependence info; and within a load pack, move loads down to the last executed load.
|
||||
void co_locate_pack(Node_List* p);
|
||||
// Convert packs into vector node operations
|
||||
void output();
|
||||
|
@ -301,6 +301,10 @@ JNI_ENTRY(jclass, jni_DefineClass(JNIEnv *env, const char *name, jobject loaderR
|
||||
klassOop k = SystemDictionary::resolve_from_stream(class_name, class_loader,
|
||||
Handle(), &st, CHECK_NULL);
|
||||
|
||||
if (TraceClassResolution && k != NULL) {
|
||||
trace_class_resolution(k);
|
||||
}
|
||||
|
||||
cls = (jclass)JNIHandles::make_local(
|
||||
env, Klass::cast(k)->java_mirror());
|
||||
return cls;
|
||||
@ -365,6 +369,10 @@ JNI_ENTRY(jclass, jni_FindClass(JNIEnv *env, const char *name))
|
||||
result = find_class_from_class_loader(env, sym, true, loader,
|
||||
protection_domain, true, thread);
|
||||
|
||||
if (TraceClassResolution && result != NULL) {
|
||||
trace_class_resolution(java_lang_Class::as_klassOop(JNIHandles::resolve_non_null(result)));
|
||||
}
|
||||
|
||||
// If we were the first invocation of jni_FindClass, we enable compilation again
|
||||
// rather than just allowing invocation counter to overflow and decay.
|
||||
// Controlled by flag DelayCompilationDuringStartup.
|
||||
@ -2646,7 +2654,12 @@ static jclass lookupOne(JNIEnv* env, const char* name, TRAPS) {
|
||||
Handle protection_domain; // null protection domain
|
||||
|
||||
symbolHandle sym = oopFactory::new_symbol_handle(name, CHECK_NULL);
|
||||
return find_class_from_class_loader(env, sym, true, loader, protection_domain, true, CHECK_NULL);
|
||||
jclass result = find_class_from_class_loader(env, sym, true, loader, protection_domain, true, CHECK_NULL);
|
||||
|
||||
if (TraceClassResolution && result != NULL) {
|
||||
trace_class_resolution(java_lang_Class::as_klassOop(JNIHandles::resolve_non_null(result)));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// These lookups are done with the NULL (bootstrap) ClassLoader to
|
||||
|
@ -64,6 +64,7 @@ static void trace_class_resolution_impl(klassOop to_class, TRAPS) {
|
||||
ResourceMark rm;
|
||||
int line_number = -1;
|
||||
const char * source_file = NULL;
|
||||
const char * trace = "explicit";
|
||||
klassOop caller = NULL;
|
||||
JavaThread* jthread = JavaThread::current();
|
||||
if (jthread->has_last_Java_frame()) {
|
||||
@ -107,12 +108,21 @@ static void trace_class_resolution_impl(klassOop to_class, TRAPS) {
|
||||
(last_caller->name() == vmSymbols::loadClassInternal_name() ||
|
||||
last_caller->name() == vmSymbols::loadClass_name())) {
|
||||
found_it = true;
|
||||
} else if (!vfst.at_end()) {
|
||||
if (vfst.method()->is_native()) {
|
||||
// JNI call
|
||||
found_it = true;
|
||||
}
|
||||
}
|
||||
if (found_it && !vfst.at_end()) {
|
||||
// found the caller
|
||||
caller = vfst.method()->method_holder();
|
||||
line_number = vfst.method()->line_number_from_bci(vfst.bci());
|
||||
symbolOop s = instanceKlass::cast(vfst.method()->method_holder())->source_file_name();
|
||||
if (line_number == -1) {
|
||||
// show method name if it's a native method
|
||||
trace = vfst.method()->name_and_sig_as_C_string();
|
||||
}
|
||||
symbolOop s = instanceKlass::cast(caller)->source_file_name();
|
||||
if (s != NULL) {
|
||||
source_file = s->as_C_string();
|
||||
}
|
||||
@ -124,15 +134,15 @@ static void trace_class_resolution_impl(klassOop to_class, TRAPS) {
|
||||
const char * to = Klass::cast(to_class)->external_name();
|
||||
// print in a single call to reduce interleaving between threads
|
||||
if (source_file != NULL) {
|
||||
tty->print("RESOLVE %s %s %s:%d (explicit)\n", from, to, source_file, line_number);
|
||||
tty->print("RESOLVE %s %s %s:%d (%s)\n", from, to, source_file, line_number, trace);
|
||||
} else {
|
||||
tty->print("RESOLVE %s %s (explicit)\n", from, to);
|
||||
tty->print("RESOLVE %s %s (%s)\n", from, to, trace);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void trace_class_resolution(klassOop to_class) {
|
||||
void trace_class_resolution(klassOop to_class) {
|
||||
EXCEPTION_MARK;
|
||||
trace_class_resolution_impl(to_class, THREAD);
|
||||
if (HAS_PENDING_EXCEPTION) {
|
||||
@ -1242,7 +1252,7 @@ JVM_ENTRY(jobjectArray, JVM_GetDeclaredClasses(JNIEnv *env, jclass ofClass))
|
||||
|
||||
// Throws an exception if outer klass has not declared k as
|
||||
// an inner klass
|
||||
Reflection::check_for_inner_class(k, inner_klass, CHECK_NULL);
|
||||
Reflection::check_for_inner_class(k, inner_klass, true, CHECK_NULL);
|
||||
|
||||
result->obj_at_put(members, inner_klass->java_mirror());
|
||||
members++;
|
||||
@ -1265,16 +1275,29 @@ JVM_END
|
||||
|
||||
|
||||
JVM_ENTRY(jclass, JVM_GetDeclaringClass(JNIEnv *env, jclass ofClass))
|
||||
const int inner_class_info_index = 0;
|
||||
const int outer_class_info_index = 1;
|
||||
|
||||
{
|
||||
// ofClass is a reference to a java_lang_Class object.
|
||||
if (java_lang_Class::is_primitive(JNIHandles::resolve_non_null(ofClass)) ||
|
||||
! Klass::cast(java_lang_Class::as_klassOop(JNIHandles::resolve_non_null(ofClass)))->oop_is_instance()) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
instanceKlassHandle k(thread, java_lang_Class::as_klassOop(JNIHandles::resolve_non_null(ofClass)));
|
||||
symbolOop simple_name = NULL;
|
||||
klassOop outer_klass
|
||||
= instanceKlass::cast(java_lang_Class::as_klassOop(JNIHandles::resolve_non_null(ofClass))
|
||||
)->compute_enclosing_class(simple_name, CHECK_NULL);
|
||||
if (outer_klass == NULL) return NULL; // already a top-level class
|
||||
if (simple_name == NULL) return NULL; // an anonymous class (inside a method)
|
||||
return (jclass) JNIHandles::make_local(env, Klass::cast(outer_klass)->java_mirror());
|
||||
}
|
||||
JVM_END
|
||||
|
||||
// should be in instanceKlass.cpp, but is here for historical reasons
|
||||
klassOop instanceKlass::compute_enclosing_class_impl(instanceKlassHandle k,
|
||||
symbolOop& simple_name_result, TRAPS) {
|
||||
Thread* thread = THREAD;
|
||||
const int inner_class_info_index = inner_class_inner_class_info_offset;
|
||||
const int outer_class_info_index = inner_class_outer_class_info_offset;
|
||||
|
||||
if (k->inner_classes()->length() == 0) {
|
||||
// No inner class info => no declaring class
|
||||
@ -1288,35 +1311,51 @@ JVM_ENTRY(jclass, JVM_GetDeclaringClass(JNIEnv *env, jclass ofClass))
|
||||
bool found = false;
|
||||
klassOop ok;
|
||||
instanceKlassHandle outer_klass;
|
||||
bool inner_is_member = false;
|
||||
int simple_name_index = 0;
|
||||
|
||||
// Find inner_klass attribute
|
||||
for(int i = 0; i < i_length && !found; i+= 4) {
|
||||
for (int i = 0; i < i_length && !found; i += inner_class_next_offset) {
|
||||
int ioff = i_icls->ushort_at(i + inner_class_info_index);
|
||||
int ooff = i_icls->ushort_at(i + outer_class_info_index);
|
||||
|
||||
if (ioff != 0 && ooff != 0) {
|
||||
int noff = i_icls->ushort_at(i + inner_class_inner_name_offset);
|
||||
if (ioff != 0) {
|
||||
// Check to see if the name matches the class we're looking for
|
||||
// before attempting to find the class.
|
||||
if (i_cp->klass_name_at_matches(k, ioff)) {
|
||||
klassOop inner_klass = i_cp->klass_at(ioff, CHECK_NULL);
|
||||
if (k() == inner_klass) {
|
||||
found = true;
|
||||
found = (k() == inner_klass);
|
||||
if (found && ooff != 0) {
|
||||
ok = i_cp->klass_at(ooff, CHECK_NULL);
|
||||
outer_klass = instanceKlassHandle(thread, ok);
|
||||
simple_name_index = noff;
|
||||
inner_is_member = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (found && outer_klass.is_null()) {
|
||||
// It may be anonymous; try for that.
|
||||
int encl_method_class_idx = k->enclosing_method_class_index();
|
||||
if (encl_method_class_idx != 0) {
|
||||
ok = i_cp->klass_at(encl_method_class_idx, CHECK_NULL);
|
||||
outer_klass = instanceKlassHandle(thread, ok);
|
||||
inner_is_member = false;
|
||||
}
|
||||
}
|
||||
|
||||
// If no inner class attribute found for this class.
|
||||
if (!found) return NULL;
|
||||
if (outer_klass.is_null()) return NULL;
|
||||
|
||||
// Throws an exception if outer klass has not declared k as an inner klass
|
||||
Reflection::check_for_inner_class(outer_klass, k, CHECK_NULL);
|
||||
|
||||
return (jclass)JNIHandles::make_local(env, outer_klass->java_mirror());
|
||||
JVM_END
|
||||
// We need evidence that each klass knows about the other, or else
|
||||
// the system could allow a spoof of an inner class to gain access rights.
|
||||
Reflection::check_for_inner_class(outer_klass, k, inner_is_member, CHECK_NULL);
|
||||
|
||||
simple_name_result = (inner_is_member ? i_cp->symbol_at(simple_name_index) : symbolOop(NULL));
|
||||
return outer_klass();
|
||||
}
|
||||
|
||||
JVM_ENTRY(jstring, JVM_GetClassSignature(JNIEnv *env, jclass cls))
|
||||
assert (cls != NULL, "illegal class");
|
||||
@ -3213,8 +3252,12 @@ JVM_ENTRY(jclass, JVM_LoadClass0(JNIEnv *env, jobject receiver,
|
||||
}
|
||||
Handle h_loader(THREAD, loader);
|
||||
Handle h_prot (THREAD, protection_domain);
|
||||
return find_class_from_class_loader(env, name, true, h_loader, h_prot,
|
||||
false, thread);
|
||||
jclass result = find_class_from_class_loader(env, name, true, h_loader, h_prot,
|
||||
false, thread);
|
||||
if (TraceClassResolution && result != NULL) {
|
||||
trace_class_resolution(java_lang_Class::as_klassOop(JNIHandles::resolve_non_null(result)));
|
||||
}
|
||||
return result;
|
||||
JVM_END
|
||||
|
||||
|
||||
|
@ -27,6 +27,7 @@
|
||||
|
||||
jclass find_class_from_class_loader(JNIEnv* env, symbolHandle name, jboolean init, Handle loader, Handle protection_domain, jboolean throwError, TRAPS);
|
||||
|
||||
void trace_class_resolution(klassOop to_class);
|
||||
|
||||
/*
|
||||
* Support for Serialization and RMI. Currently used by HotSpot only.
|
||||
|
@ -852,16 +852,13 @@ bool Arguments::add_property(const char* prop) {
|
||||
FreeHeap(value);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else if (strcmp(key, "sun.java.command") == 0) {
|
||||
|
||||
} else if (strcmp(key, "sun.java.command") == 0) {
|
||||
_java_command = value;
|
||||
|
||||
// don't add this property to the properties exposed to the java application
|
||||
FreeHeap(key);
|
||||
return true;
|
||||
}
|
||||
else if (strcmp(key, "sun.java.launcher.pid") == 0) {
|
||||
} else if (strcmp(key, "sun.java.launcher.pid") == 0) {
|
||||
// launcher.pid property is private and is processed
|
||||
// in process_sun_java_launcher_properties();
|
||||
// the sun.java.launcher property is passed on to the java application
|
||||
@ -870,13 +867,14 @@ bool Arguments::add_property(const char* prop) {
|
||||
FreeHeap(value);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else if (strcmp(key, "java.vendor.url.bug") == 0) {
|
||||
} else if (strcmp(key, "java.vendor.url.bug") == 0) {
|
||||
// save it in _java_vendor_url_bug, so JVM fatal error handler can access
|
||||
// its value without going through the property list or making a Java call.
|
||||
_java_vendor_url_bug = value;
|
||||
} else if (strcmp(key, "sun.boot.library.path") == 0) {
|
||||
PropertyList_unique_add(&_system_properties, key, value, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Create new property and add at the end of the list
|
||||
PropertyList_unique_add(&_system_properties, key, value);
|
||||
return true;
|
||||
@ -895,7 +893,7 @@ void Arguments::set_mode_flags(Mode mode) {
|
||||
// Ensure Agent_OnLoad has the correct initial values.
|
||||
// This may not be the final mode; mode may change later in onload phase.
|
||||
PropertyList_unique_add(&_system_properties, "java.vm.info",
|
||||
(char*)Abstract_VM_Version::vm_info_string());
|
||||
(char*)Abstract_VM_Version::vm_info_string(), false);
|
||||
|
||||
UseInterpreter = true;
|
||||
UseCompiler = true;
|
||||
@ -1376,9 +1374,6 @@ void Arguments::set_aggressive_opts_flags() {
|
||||
if (AggressiveOpts && FLAG_IS_DEFAULT(DoEscapeAnalysis)) {
|
||||
FLAG_SET_DEFAULT(DoEscapeAnalysis, true);
|
||||
}
|
||||
if (AggressiveOpts && FLAG_IS_DEFAULT(SpecialArraysEquals)) {
|
||||
FLAG_SET_DEFAULT(SpecialArraysEquals, true);
|
||||
}
|
||||
if (AggressiveOpts && FLAG_IS_DEFAULT(BiasedLockingStartupDelay)) {
|
||||
FLAG_SET_DEFAULT(BiasedLockingStartupDelay, 500);
|
||||
}
|
||||
@ -2777,7 +2772,7 @@ void Arguments::PropertyList_add(SystemProperty** plist, const char* k, char* v)
|
||||
}
|
||||
|
||||
// This add maintains unique property key in the list.
|
||||
void Arguments::PropertyList_unique_add(SystemProperty** plist, const char* k, char* v) {
|
||||
void Arguments::PropertyList_unique_add(SystemProperty** plist, const char* k, char* v, jboolean append) {
|
||||
if (plist == NULL)
|
||||
return;
|
||||
|
||||
@ -2785,7 +2780,11 @@ void Arguments::PropertyList_unique_add(SystemProperty** plist, const char* k, c
|
||||
SystemProperty* prop;
|
||||
for (prop = *plist; prop != NULL; prop = prop->next()) {
|
||||
if (strcmp(k, prop->key()) == 0) {
|
||||
prop->set_value(v);
|
||||
if (append) {
|
||||
prop->append_value(v);
|
||||
} else {
|
||||
prop->set_value(v);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -475,10 +475,13 @@ class Arguments : AllStatic {
|
||||
// System properties
|
||||
static void init_system_properties();
|
||||
|
||||
// Proptery List manipulation
|
||||
// Property List manipulation
|
||||
static void PropertyList_add(SystemProperty** plist, SystemProperty *element);
|
||||
static void PropertyList_add(SystemProperty** plist, const char* k, char* v);
|
||||
static void PropertyList_unique_add(SystemProperty** plist, const char* k, char* v);
|
||||
static void PropertyList_unique_add(SystemProperty** plist, const char* k, char* v) {
|
||||
PropertyList_unique_add(plist, k, v, false);
|
||||
}
|
||||
static void PropertyList_unique_add(SystemProperty** plist, const char* k, char* v, jboolean append);
|
||||
static const char* PropertyList_get_value(SystemProperty* plist, const char* key);
|
||||
static int PropertyList_count(SystemProperty* pl);
|
||||
static const char* PropertyList_get_key_at(SystemProperty* pl,int index);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 1997-2005 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -107,13 +107,14 @@ void fieldDescriptor::print_on(outputStream* st) const {
|
||||
void fieldDescriptor::print_on_for(outputStream* st, oop obj) {
|
||||
print_on(st);
|
||||
BasicType ft = field_type();
|
||||
jint as_int;
|
||||
jint as_int = 0;
|
||||
switch (ft) {
|
||||
case T_BYTE:
|
||||
as_int = (jint)obj->byte_field(offset());
|
||||
st->print(" %d", obj->byte_field(offset()));
|
||||
break;
|
||||
case T_CHAR:
|
||||
as_int = (jint)obj->char_field(offset());
|
||||
{
|
||||
jchar c = obj->char_field(offset());
|
||||
as_int = c;
|
||||
@ -128,6 +129,7 @@ void fieldDescriptor::print_on_for(outputStream* st, oop obj) {
|
||||
st->print(" %f", obj->float_field(offset()));
|
||||
break;
|
||||
case T_INT:
|
||||
as_int = obj->int_field(offset());
|
||||
st->print(" %d", obj->int_field(offset()));
|
||||
break;
|
||||
case T_LONG:
|
||||
@ -144,12 +146,12 @@ void fieldDescriptor::print_on_for(outputStream* st, oop obj) {
|
||||
break;
|
||||
case T_ARRAY:
|
||||
st->print(" ");
|
||||
as_int = obj->int_field(offset());
|
||||
NOT_LP64(as_int = obj->int_field(offset()));
|
||||
obj->obj_field(offset())->print_value_on(st);
|
||||
break;
|
||||
case T_OBJECT:
|
||||
st->print(" ");
|
||||
as_int = obj->int_field(offset());
|
||||
NOT_LP64(as_int = obj->int_field(offset()));
|
||||
obj->obj_field(offset())->print_value_on(st);
|
||||
break;
|
||||
default:
|
||||
@ -158,9 +160,9 @@ void fieldDescriptor::print_on_for(outputStream* st, oop obj) {
|
||||
}
|
||||
// Print a hint as to the underlying integer representation. This can be wrong for
|
||||
// pointers on an LP64 machine
|
||||
if (ft == T_LONG || ft == T_DOUBLE) {
|
||||
if (ft == T_LONG || ft == T_DOUBLE LP64_ONLY(|| !is_java_primitive(ft)) ) {
|
||||
st->print(" (%x %x)", obj->int_field(offset()), obj->int_field(offset()+sizeof(jint)));
|
||||
} else {
|
||||
} else if (as_int < 0 || as_int > 9) {
|
||||
st->print(" (%x)", as_int);
|
||||
}
|
||||
}
|
||||
|
@ -47,6 +47,7 @@ define_pd_global(intx, Tier4BackEdgeThreshold, 0);
|
||||
define_pd_global(intx, OnStackReplacePercentage, 0);
|
||||
define_pd_global(bool, ResizeTLAB, false);
|
||||
define_pd_global(intx, FreqInlineSize, 0);
|
||||
define_pd_global(intx, InlineSmallCode, 0);
|
||||
define_pd_global(intx, NewSizeThreadIncrease, 4*K);
|
||||
define_pd_global(intx, NewRatio, 4);
|
||||
define_pd_global(intx, InlineClassNatives, true);
|
||||
@ -490,9 +491,15 @@ class CommandLineFlags {
|
||||
develop(bool, SpecialStringIndexOf, true, \
|
||||
"special version of string indexOf") \
|
||||
\
|
||||
product(bool, SpecialArraysEquals, false, \
|
||||
develop(bool, SpecialStringEquals, true, \
|
||||
"special version of string equals") \
|
||||
\
|
||||
develop(bool, SpecialArraysEquals, true, \
|
||||
"special version of Arrays.equals(char[],char[])") \
|
||||
\
|
||||
product(bool, UseSSE42Intrinsics, false, \
|
||||
"SSE4.2 versions of intrinsics") \
|
||||
\
|
||||
develop(bool, TraceCallFixup, false, \
|
||||
"traces all call fixups") \
|
||||
\
|
||||
@ -2622,7 +2629,7 @@ class CommandLineFlags {
|
||||
develop(intx, MaxRecursiveInlineLevel, 1, \
|
||||
"maximum number of nested recursive calls that are inlined") \
|
||||
\
|
||||
product(intx, InlineSmallCode, 1000, \
|
||||
product_pd(intx, InlineSmallCode, \
|
||||
"Only inline already compiled methods if their code size is " \
|
||||
"less than this") \
|
||||
\
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -137,6 +137,14 @@ class KlassHandle: public Handle {
|
||||
assert(is_null() || obj()->is_klass(), "not a klassOop");
|
||||
}
|
||||
|
||||
// Direct interface, use very sparingly.
|
||||
// Used by SystemDictionaryHandles to create handles on existing WKKs.
|
||||
// The obj of such a klass handle may be null, because the handle is formed
|
||||
// during system bootstrapping.
|
||||
KlassHandle(klassOop *handle, bool dummy) : Handle((oop*)handle, dummy) {
|
||||
assert(SharedSkipVerify || is_null() || obj() == NULL || obj()->is_klass(), "not a klassOop");
|
||||
}
|
||||
|
||||
// General access
|
||||
klassOop operator () () const { return obj(); }
|
||||
Klass* operator -> () const { return as_klass(); }
|
||||
|
@ -90,7 +90,7 @@ public:
|
||||
static inline struct protoent* get_proto_by_name(char* name);
|
||||
|
||||
// HPI_LibraryInterface
|
||||
static inline void dll_build_name(char *buf, int buf_len, char* path,
|
||||
static inline void dll_build_name(char *buf, int buf_len, const char* path,
|
||||
const char *name);
|
||||
static inline void* dll_load(const char *name, char *ebuf, int ebuflen);
|
||||
static inline void dll_unload(void *lib);
|
||||
@ -137,7 +137,15 @@ public:
|
||||
return result; \
|
||||
}
|
||||
|
||||
|
||||
#define VM_HPIDECL_VOID(name, names, func, arg_type, arg_print, arg) \
|
||||
inline void hpi::name arg_type { \
|
||||
if (TraceHPI) { \
|
||||
tty->print("hpi::" names "("); \
|
||||
tty->print arg_print; \
|
||||
tty->print(") = "); \
|
||||
} \
|
||||
func arg; \
|
||||
}
|
||||
|
||||
#define HPIDECL_VOID(name, names, intf, func, arg_type, arg_print, arg) \
|
||||
inline void hpi::name arg_type { \
|
||||
@ -197,11 +205,11 @@ HPIDECL(fsize, "fsize", _file, FileSizeFD, int, "%d",
|
||||
(fd, size));
|
||||
|
||||
// HPI_LibraryInterface
|
||||
HPIDECL_VOID(dll_build_name, "dll_build_name", _library, BuildLibName,
|
||||
(char *buf, int buf_len, char *path, const char *name),
|
||||
("buf = %p, buflen = %d, path = %s, name = %s",
|
||||
buf, buf_len, path, name),
|
||||
(buf, buf_len, path, name));
|
||||
VM_HPIDECL_VOID(dll_build_name, "dll_build_name", os::dll_build_name,
|
||||
(char *buf, int buf_len, const char *path, const char *name),
|
||||
("buf = %p, buflen = %d, path = %s, name = %s",
|
||||
buf, buf_len, path, name),
|
||||
(buf, buf_len, path, name));
|
||||
|
||||
VM_HPIDECL(dll_load, "dll_load", os::dll_load,
|
||||
void *, "(void *)%p",
|
||||
|
@ -26,3 +26,15 @@
|
||||
# include "incls/_orderAccess.cpp.incl"
|
||||
|
||||
volatile intptr_t OrderAccess::dummy = 0;
|
||||
|
||||
void OrderAccess::StubRoutines_fence() {
|
||||
// Use a stub if it exists. It may not exist during bootstrap so do
|
||||
// nothing in that case but assert if no fence code exists after threads have been created
|
||||
void (*func)() = CAST_TO_FN_PTR(void (*)(), StubRoutines::fence_entry());
|
||||
|
||||
if (func != NULL) {
|
||||
(*func)();
|
||||
return;
|
||||
}
|
||||
assert(Threads::number_of_threads() == 0, "for bootstrap only");
|
||||
}
|
||||
|
@ -300,4 +300,10 @@ class OrderAccess : AllStatic {
|
||||
// In order to force a memory access, implementations may
|
||||
// need a volatile externally visible dummy variable.
|
||||
static volatile intptr_t dummy;
|
||||
|
||||
private:
|
||||
// This is a helper that invokes the StubRoutines::fence_entry()
|
||||
// routine if it exists, It should only be used by platforms that
|
||||
// don't another way to do the inline eassembly.
|
||||
static void StubRoutines_fence();
|
||||
};
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user