This commit is contained in:
Lana Steuck 2011-08-17 22:47:49 -07:00
commit dfb9afd36b
545 changed files with 15023 additions and 9042 deletions

View File

@ -121,3 +121,4 @@ f4298bc3f4b6baa315643be06966f09684290068 jdk7-b140
07a8728ad49ef6dfa469c3a8bf5ab1e9c80bed5c jdk7-b144
8294c99e685a1f6d1d37c45cd97854cf74be771e jdk7-b145
dca1e8a87e8f756f95b99bac8fe795750d42e1b0 jdk7-b146
a2a589fc29543ed32919c78a1810ad93a6fcf5bc jdk7-b147

View File

@ -121,3 +121,4 @@ cfbbdb77eac0397b03eb99ee2e07ea00e0a7b81e jdk7-b142
7203965666a4fe63bf82f5e4204f41ce6285e716 jdk7-b144
55e9ebf032186c333e5964ed044419830ac02693 jdk7-b145
2d38c2a79c144c30cd04d143d83ee7ec6af40771 jdk7-b146
d91364304d7c4ecd34caffdba2b840aeb0d10b51 jdk7-b147

View File

@ -1 +1 @@
project=jdk7
project=jdk8

View File

@ -121,3 +121,4 @@ a2f340a048c88d10cbedc0504f5cf03d39925a40 jdk7-b142
7033a5756ad552d88114594d8e2d2e4dc2c05963 jdk7-b144
77ec0541aa2aa4da27e9e385a118a2e51e7fca24 jdk7-b145
770227a4087e4e401fe87ccd19738440111c3948 jdk7-b146
73323cb3396260d93e0ab731fd2d431096ceed0f jdk7-b147

View File

@ -1 +1 @@
project=jdk7
project=jdk8

View File

@ -25,12 +25,23 @@
# Properties for jprt
# Use whatever release that the submitted job requests
jprt.tools.default.release=${jprt.submit.release}
# The release to build
jprt.tools.default.release=jdk8
# The different build flavors we want, we override here so we just get these 2
jprt.build.flavors=product,fastdebug
# Standard list of jprt build targets for this source tree
jprt.build.targets= \
solaris_sparc_5.10-{product|fastdebug}, \
solaris_sparcv9_5.10-{product|fastdebug}, \
solaris_i586_5.10-{product|fastdebug}, \
solaris_x64_5.10-{product|fastdebug}, \
linux_i586_2.6-{product|fastdebug}, \
linux_x64_2.6-{product|fastdebug}, \
windows_i586_5.1-{product|fastdebug}, \
windows_x64_5.2-{product|fastdebug}
# Directories to be excluded from the source bundles
jprt.bundle.exclude.src.dirs=build dist webrev

View File

@ -172,3 +172,5 @@ d283b82966712b353fa307845a1316da42a355f4 hs21-b10
3aea9e9feb073f5500e031be6186666bcae89aa2 hs21-b11
9ad1548c6b63d596c411afc35147ffd5254426d9 jdk7-b142
9ad1548c6b63d596c411afc35147ffd5254426d9 hs21-b12
c149193c768b8b7233da4c3a3fdc0756b975848e hs21-b13
c149193c768b8b7233da4c3a3fdc0756b975848e jdk7-b143

View File

@ -1 +1 @@
project=jdk7
project=jdk8

View File

@ -1028,7 +1028,12 @@ public class CommandProcessor {
if (AddressOps.equal(val, value)) {
if (!printed) {
printed = true;
blob.printOn(out);
try {
blob.printOn(out);
} catch (Exception e) {
out.println("Exception printing blob at " + base);
e.printStackTrace();
}
}
out.println("found at " + base + "\n");
}

View File

@ -0,0 +1,58 @@
/*
* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
package sun.jvm.hotspot.code;
import java.util.*;
import sun.jvm.hotspot.debugger.*;
import sun.jvm.hotspot.runtime.*;
import sun.jvm.hotspot.types.*;
public class AdapterBlob extends CodeBlob {
static {
VM.registerVMInitializedObserver(new Observer() {
public void update(Observable o, Object data) {
initialize(VM.getVM().getTypeDataBase());
}
});
}
private static void initialize(TypeDataBase db) {
// Type type = db.lookupType("AdapterBlob");
// // FIXME: add any needed fields
}
public AdapterBlob(Address addr) {
super(addr);
}
public boolean isAdapterBlob() {
return true;
}
public String getName() {
return "AdapterBlob: " + super.getName();
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -93,6 +93,8 @@ public class CodeBlob extends VMObject {
public boolean isUncommonTrapStub() { return false; }
public boolean isExceptionStub() { return false; }
public boolean isSafepointStub() { return false; }
public boolean isRicochetBlob() { return false; }
public boolean isAdapterBlob() { return false; }
// Fine grain nmethod support: isNmethod() == isJavaMethod() || isNativeMethod() || isOSRMethod()
public boolean isJavaMethod() { return false; }

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000, 2005, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -57,6 +57,8 @@ public class CodeCache {
virtualConstructor.addMapping("BufferBlob", BufferBlob.class);
virtualConstructor.addMapping("nmethod", NMethod.class);
virtualConstructor.addMapping("RuntimeStub", RuntimeStub.class);
virtualConstructor.addMapping("RicochetBlob", RicochetBlob.class);
virtualConstructor.addMapping("AdapterBlob", AdapterBlob.class);
virtualConstructor.addMapping("SafepointBlob", SafepointBlob.class);
virtualConstructor.addMapping("DeoptimizationBlob", DeoptimizationBlob.class);
if (VM.getVM().isServerCompiler()) {

View File

@ -0,0 +1,56 @@
/*
* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
package sun.jvm.hotspot.code;
import java.util.*;
import sun.jvm.hotspot.debugger.*;
import sun.jvm.hotspot.runtime.*;
import sun.jvm.hotspot.types.*;
/** RicochetBlob (currently only used by Compiler 2) */
public class RicochetBlob extends SingletonBlob {
static {
VM.registerVMInitializedObserver(new Observer() {
public void update(Observable o, Object data) {
initialize(VM.getVM().getTypeDataBase());
}
});
}
private static void initialize(TypeDataBase db) {
// Type type = db.lookupType("RicochetBlob");
// FIXME: add any needed fields
}
public RicochetBlob(Address addr) {
super(addr);
}
public boolean isRicochetBlob() {
return true;
}
}

View File

@ -33,13 +33,13 @@
# Don't put quotes (fail windows build).
HOTSPOT_VM_COPYRIGHT=Copyright 2011
HS_MAJOR_VER=21
HS_MAJOR_VER=22
HS_MINOR_VER=0
HS_BUILD_NUMBER=13
HS_BUILD_NUMBER=01
JDK_MAJOR_VER=1
JDK_MINOR_VER=7
JDK_MINOR_VER=8
JDK_MICRO_VER=0
# Previous (bootdir) JDK version
JDK_PREVIOUS_VERSION=1.6.0
JDK_PREVIOUS_VERSION=1.7.0

View File

@ -1,5 +1,5 @@
#
# Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2006, 2011, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@ -33,6 +33,24 @@ else
ZIPFLAGS=-q -y
endif
jprt_build_productEmb:
$(MAKE) JAVASE_EMBEDDED=true jprt_build_product
jprt_build_debugEmb:
$(MAKE) JAVASE_EMBEDDED=true jprt_build_debug
jprt_build_fastdebugEmb:
$(MAKE) JAVASE_EMBEDDED=true jprt_build_fastdebug
jprt_build_productOpen:
$(MAKE) OPENJDK=true jprt_build_product
jprt_build_debugOpen:
$(MAKE) OPENJDK=true jprt_build_debug
jprt_build_fastdebugOpen:
$(MAKE) OPENJDK=true jprt_build_fastdebug
jprt_build_product: all_product copy_product_jdk export_product_jdk
( $(CD) $(JDK_IMAGE_DIR) && \
$(ZIPEXE) $(ZIPFLAGS) -r $(JPRT_ARCHIVE_BUNDLE) . )

View File

@ -50,7 +50,7 @@ jprt.sync.push=false
# sparc etc.
# Define the Solaris platforms we want for the various releases
jprt.my.solaris.sparc.jdk8=solaris_sparc_5.10
jprt.my.solaris.sparc.jdk7=solaris_sparc_5.10
jprt.my.solaris.sparc.jdk7b107=solaris_sparc_5.10
jprt.my.solaris.sparc.jdk7temp=solaris_sparc_5.10
@ -64,6 +64,7 @@ jprt.my.solaris.sparc.ejdk7=${jprt.my.solaris.sparc.jdk7}
jprt.my.solaris.sparc.ejdk6=${jprt.my.solaris.sparc.jdk6}
jprt.my.solaris.sparc=${jprt.my.solaris.sparc.${jprt.tools.default.release}}
jprt.my.solaris.sparcv9.jdk8=solaris_sparcv9_5.10
jprt.my.solaris.sparcv9.jdk7=solaris_sparcv9_5.10
jprt.my.solaris.sparcv9.jdk7b107=solaris_sparcv9_5.10
jprt.my.solaris.sparcv9.jdk7temp=solaris_sparcv9_5.10
@ -77,6 +78,7 @@ jprt.my.solaris.sparcv9.ejdk7=${jprt.my.solaris.sparcv9.jdk7}
jprt.my.solaris.sparcv9.ejdk6=${jprt.my.solaris.sparcv9.jdk6}
jprt.my.solaris.sparcv9=${jprt.my.solaris.sparcv9.${jprt.tools.default.release}}
jprt.my.solaris.i586.jdk8=solaris_i586_5.10
jprt.my.solaris.i586.jdk7=solaris_i586_5.10
jprt.my.solaris.i586.jdk7b107=solaris_i586_5.10
jprt.my.solaris.i586.jdk7temp=solaris_i586_5.10
@ -90,6 +92,7 @@ jprt.my.solaris.i586.ejdk7=${jprt.my.solaris.i586.jdk7}
jprt.my.solaris.i586.ejdk6=${jprt.my.solaris.i586.jdk6}
jprt.my.solaris.i586=${jprt.my.solaris.i586.${jprt.tools.default.release}}
jprt.my.solaris.x64.jdk8=solaris_x64_5.10
jprt.my.solaris.x64.jdk7=solaris_x64_5.10
jprt.my.solaris.x64.jdk7b107=solaris_x64_5.10
jprt.my.solaris.x64.jdk7temp=solaris_x64_5.10
@ -103,6 +106,7 @@ jprt.my.solaris.x64.ejdk7=${jprt.my.solaris.x64.jdk7}
jprt.my.solaris.x64.ejdk6=${jprt.my.solaris.x64.jdk6}
jprt.my.solaris.x64=${jprt.my.solaris.x64.${jprt.tools.default.release}}
jprt.my.linux.i586.jdk8=linux_i586_2.6
jprt.my.linux.i586.jdk7=linux_i586_2.6
jprt.my.linux.i586.jdk7b107=linux_i586_2.6
jprt.my.linux.i586.jdk7temp=linux_i586_2.6
@ -116,6 +120,7 @@ jprt.my.linux.i586.ejdk7=linux_i586_2.6
jprt.my.linux.i586.ejdk6=linux_i586_2.6
jprt.my.linux.i586=${jprt.my.linux.i586.${jprt.tools.default.release}}
jprt.my.linux.x64.jdk8=linux_x64_2.6
jprt.my.linux.x64.jdk7=linux_x64_2.6
jprt.my.linux.x64.jdk7b107=linux_x64_2.6
jprt.my.linux.x64.jdk7temp=linux_x64_2.6
@ -129,6 +134,7 @@ jprt.my.linux.x64.ejdk7=${jprt.my.linux.x64.jdk7}
jprt.my.linux.x64.ejdk6=${jprt.my.linux.x64.jdk6}
jprt.my.linux.x64=${jprt.my.linux.x64.${jprt.tools.default.release}}
jprt.my.linux.ppc.jdk8=linux_ppc_2.6
jprt.my.linux.ppc.jdk7=linux_ppc_2.6
jprt.my.linux.ppc.jdk7b107=linux_ppc_2.6
jprt.my.linux.ppc.jdk7temp=linux_ppc_2.6
@ -136,6 +142,7 @@ jprt.my.linux.ppc.ejdk6=linux_ppc_2.6
jprt.my.linux.ppc.ejdk7=linux_ppc_2.6
jprt.my.linux.ppc=${jprt.my.linux.ppc.${jprt.tools.default.release}}
jprt.my.linux.ppcv2.jdk8=linux_ppcv2_2.6
jprt.my.linux.ppcv2.jdk7=linux_ppcv2_2.6
jprt.my.linux.ppcv2.jdk7b107=linux_ppcv2_2.6
jprt.my.linux.ppcv2.jdk7temp=linux_ppcv2_2.6
@ -143,6 +150,7 @@ jprt.my.linux.ppcv2.ejdk6=linux_ppcv2_2.6
jprt.my.linux.ppcv2.ejdk7=linux_ppcv2_2.6
jprt.my.linux.ppcv2=${jprt.my.linux.ppcv2.${jprt.tools.default.release}}
jprt.my.linux.ppcsflt.jdk8=linux_ppcsflt_2.6
jprt.my.linux.ppcsflt.jdk7=linux_ppcsflt_2.6
jprt.my.linux.ppcsflt.jdk7b107=linux_ppcsflt_2.6
jprt.my.linux.ppcsflt.jdk7temp=linux_ppcsflt_2.6
@ -150,6 +158,7 @@ jprt.my.linux.ppcsflt.ejdk6=linux_ppcsflt_2.6
jprt.my.linux.ppcsflt.ejdk7=linux_ppcsflt_2.6
jprt.my.linux.ppcsflt=${jprt.my.linux.ppcsflt.${jprt.tools.default.release}}
jprt.my.linux.armvfp.jdk8=linux_armvfp_2.6
jprt.my.linux.armvfp.jdk7=linux_armvfp_2.6
jprt.my.linux.armvfp.jdk7b107=linux_armvfp_2.6
jprt.my.linux.armvfp.jdk7temp=linux_armvfp_2.6
@ -157,6 +166,7 @@ jprt.my.linux.armvfp.ejdk6=linux_armvfp_2.6
jprt.my.linux.armvfp.ejdk7=linux_armvfp_2.6
jprt.my.linux.armvfp=${jprt.my.linux.armvfp.${jprt.tools.default.release}}
jprt.my.linux.armsflt.jdk8=linux_armsflt_2.6
jprt.my.linux.armsflt.jdk7=linux_armsflt_2.6
jprt.my.linux.armsflt.jdk7b107=linux_armsflt_2.6
jprt.my.linux.armsflt.jdk7temp=linux_armsflt_2.6
@ -164,6 +174,7 @@ jprt.my.linux.armsflt.ejdk6=linux_armsflt_2.6
jprt.my.linux.armsflt.ejdk7=linux_armsflt_2.6
jprt.my.linux.armsflt=${jprt.my.linux.armsflt.${jprt.tools.default.release}}
jprt.my.windows.i586.jdk8=windows_i586_5.1
jprt.my.windows.i586.jdk7=windows_i586_5.1
jprt.my.windows.i586.jdk7b107=windows_i586_5.0
jprt.my.windows.i586.jdk7temp=windows_i586_5.0
@ -177,6 +188,7 @@ jprt.my.windows.i586.ejdk7=${jprt.my.windows.i586.jdk7}
jprt.my.windows.i586.ejdk6=${jprt.my.windows.i586.jdk6}
jprt.my.windows.i586=${jprt.my.windows.i586.${jprt.tools.default.release}}
jprt.my.windows.x64.jdk8=windows_x64_5.2
jprt.my.windows.x64.jdk7=windows_x64_5.2
jprt.my.windows.x64.jdk7b107=windows_x64_5.2
jprt.my.windows.x64.jdk7temp=windows_x64_5.2
@ -202,17 +214,23 @@ jprt.build.targets.standard= \
${jprt.my.windows.i586}-{product|fastdebug|debug}, \
${jprt.my.windows.x64}-{product|fastdebug|debug}
jprt.build.targets.open= \
${jprt.my.solaris.i586}-{productOpen}, \
${jprt.my.solaris.x64}-{debugOpen}, \
${jprt.my.linux.x64}-{productOpen}
jprt.build.targets.embedded= \
${jprt.my.linux.i586}-{product|fastdebug|debug}, \
${jprt.my.linux.ppc}-{product|fastdebug}, \
${jprt.my.linux.ppcv2}-{product|fastdebug}, \
${jprt.my.linux.ppcsflt}-{product|fastdebug}, \
${jprt.my.linux.armvfp}-{product|fastdebug}, \
${jprt.my.linux.armsflt}-{product|fastdebug}
${jprt.my.linux.i586}-{productEmb|fastdebugEmb|debugEmb}, \
${jprt.my.linux.ppc}-{productEmb|fastdebugEmb}, \
${jprt.my.linux.ppcv2}-{productEmb|fastdebugEmb}, \
${jprt.my.linux.ppcsflt}-{productEmb|fastdebugEmb}, \
${jprt.my.linux.armvfp}-{productEmb|fastdebugEmb}, \
${jprt.my.linux.armsflt}-{productEmb|fastdebugEmb}
jprt.build.targets.all=${jprt.build.targets.standard}, \
${jprt.build.targets.embedded}
${jprt.build.targets.embedded}, ${jprt.build.targets.open}
jprt.build.targets.jdk8=${jprt.build.targets.all}
jprt.build.targets.jdk7=${jprt.build.targets.all}
jprt.build.targets.jdk7temp=${jprt.build.targets.all}
jprt.build.targets.jdk7b107=${jprt.build.targets.all}
@ -453,6 +471,12 @@ jprt.my.windows.x64.test.targets = \
${jprt.my.windows.x64}-product-c2-jbb_G1, \
${jprt.my.windows.x64}-product-c2-jbb_ParOldGC
# Some basic "smoke" tests for OpenJDK builds
jprt.test.targets.open = \
${jprt.my.solaris.x64}-{productOpen|debugOpen|fastdebugOpen}-c2-jvm98_tiered, \
${jprt.my.solaris.i586}-{productOpen|fastdebugOpen}-c2-jvm98_tiered, \
${jprt.my.linux.x64}-{productOpen|fastdebugOpen}-c2-jvm98_tiered
# Testing for actual embedded builds is different to standard
jprt.my.linux.i586.test.targets.embedded = \
linux_i586_2.6-product-c1-scimark
@ -461,6 +485,7 @@ jprt.my.linux.i586.test.targets.embedded = \
# Note: no PPC or ARM tests at this stage
jprt.test.targets.standard = \
${jprt.my.linux.i586.test.targets.embedded}, \
${jprt.my.solaris.sparc.test.targets}, \
${jprt.my.solaris.sparcv9.test.targets}, \
${jprt.my.solaris.i586.test.targets}, \
@ -468,7 +493,8 @@ jprt.test.targets.standard = \
${jprt.my.linux.i586.test.targets}, \
${jprt.my.linux.x64.test.targets}, \
${jprt.my.windows.i586.test.targets}, \
${jprt.my.windows.x64.test.targets}
${jprt.my.windows.x64.test.targets}, \
${jprt.test.targets.open}
jprt.test.targets.embedded= \
${jprt.my.linux.i586.test.targets.embedded}, \
@ -481,6 +507,7 @@ jprt.test.targets.embedded= \
${jprt.my.windows.x64.test.targets}
jprt.test.targets.jdk8=${jprt.test.targets.standard}
jprt.test.targets.jdk7=${jprt.test.targets.standard}
jprt.test.targets.jdk7temp=${jprt.test.targets.standard}
jprt.test.targets.jdk7b105=${jprt.test.targets.standard}
@ -521,6 +548,7 @@ jprt.make.rule.test.targets.standard = \
jprt.make.rule.test.targets.embedded = \
${jprt.make.rule.test.targets.standard.client}
jprt.make.rule.test.targets.jdk8=${jprt.make.rule.test.targets.standard}
jprt.make.rule.test.targets.jdk7=${jprt.make.rule.test.targets.standard}
jprt.make.rule.test.targets.jdk7temp=${jprt.make.rule.test.targets.standard}
jprt.make.rule.test.targets.jdk7b107=${jprt.make.rule.test.targets.standard}

View File

@ -42,6 +42,12 @@
#include "gc_implementation/g1/heapRegion.hpp"
#endif
#ifdef PRODUCT
#define BLOCK_COMMENT(str) /* nothing */
#else
#define BLOCK_COMMENT(str) block_comment(str)
#endif
// Convert the raw encoding form into the form expected by the
// constructor for Address.
Address Address::make_raw(int base, int index, int scale, int disp, bool disp_is_oop) {
@ -1072,6 +1078,12 @@ void MacroAssembler::call_VM_base(
check_and_forward_exception(Gtemp);
}
#ifdef ASSERT
set(badHeapWordVal, G3);
set(badHeapWordVal, G4);
set(badHeapWordVal, G5);
#endif
// get oop result if there is one and reset the value in the thread
if (oop_result->is_valid()) {
get_vm_result(oop_result);
@ -1177,6 +1189,11 @@ void MacroAssembler::call_VM_leaf_base(Register thread_cache, address entry_poin
call(entry_point, relocInfo::runtime_call_type);
delayed()->nop();
restore_thread(thread_cache);
#ifdef ASSERT
set(badHeapWordVal, G3);
set(badHeapWordVal, G4);
set(badHeapWordVal, G5);
#endif
}
@ -1518,7 +1535,7 @@ int MacroAssembler::total_frame_size_in_bytes(int extraWords) {
// save_frame: given number of "extra" words in frame,
// issue approp. save instruction (p 200, v8 manual)
void MacroAssembler::save_frame(int extraWords = 0) {
void MacroAssembler::save_frame(int extraWords) {
int delta = -total_frame_size_in_bytes(extraWords);
if (is_simm13(delta)) {
save(SP, delta, SP);
@ -1730,6 +1747,7 @@ void MacroAssembler::_verify_oop(Register reg, const char* msg, const char * fil
if (reg == G0) return; // always NULL, which is always an oop
BLOCK_COMMENT("verify_oop {");
char buffer[64];
#ifdef COMPILER1
if (CommentedAssembly) {
@ -1768,6 +1786,7 @@ void MacroAssembler::_verify_oop(Register reg, const char* msg, const char * fil
delayed()->nop();
// recover frame size
add(SP, 8*8,SP);
BLOCK_COMMENT("} verify_oop");
}
void MacroAssembler::_verify_oop_addr(Address addr, const char* msg, const char * file, int line) {
@ -2040,7 +2059,7 @@ void MacroAssembler::debug(char* msg, RegistersForDebugging* regs) {
}
else
::tty->print_cr("=============== DEBUG MESSAGE: %s ================\n", msg);
assert(false, "error");
assert(false, err_msg("DEBUG MESSAGE: %s", msg));
}
@ -3230,6 +3249,7 @@ void MacroAssembler::jump_to_method_handle_entry(Register mh_reg, Register temp_
RegisterOrConstant MacroAssembler::argument_offset(RegisterOrConstant arg_slot,
Register temp_reg,
int extra_slot_offset) {
// cf. TemplateTable::prepare_invoke(), if (load_receiver).
int stackElementSize = Interpreter::stackElementSize;
@ -3238,18 +3258,19 @@ RegisterOrConstant MacroAssembler::argument_offset(RegisterOrConstant arg_slot,
offset += arg_slot.as_constant() * stackElementSize;
return offset;
} else {
Register temp = arg_slot.as_register();
sll_ptr(temp, exact_log2(stackElementSize), temp);
assert(temp_reg != noreg, "must specify");
sll_ptr(arg_slot.as_register(), exact_log2(stackElementSize), temp_reg);
if (offset != 0)
add(temp, offset, temp);
return temp;
add(temp_reg, offset, temp_reg);
return temp_reg;
}
}
Address MacroAssembler::argument_address(RegisterOrConstant arg_slot,
Register temp_reg,
int extra_slot_offset) {
return Address(Gargs, argument_offset(arg_slot, extra_slot_offset));
return Address(Gargs, argument_offset(arg_slot, temp_reg, extra_slot_offset));
}
@ -4906,4 +4927,3 @@ void MacroAssembler::char_arrays_equals(Register ary1, Register ary2,
// Caller should set it:
// add(G0, 1, result); // equals
}

View File

@ -309,12 +309,14 @@ class Address VALUE_OBJ_CLASS_SPEC {
#endif
// accessors
Register base() const { return _base; }
Register index() const { return _index_or_disp.as_register(); }
int disp() const { return _index_or_disp.as_constant(); }
Register base() const { return _base; }
Register index() const { return _index_or_disp.as_register(); }
int disp() const { return _index_or_disp.as_constant(); }
bool has_index() const { return _index_or_disp.is_register(); }
bool has_disp() const { return _index_or_disp.is_constant(); }
bool has_index() const { return _index_or_disp.is_register(); }
bool has_disp() const { return _index_or_disp.is_constant(); }
bool uses(Register reg) const { return base() == reg || (has_index() && index() == reg); }
const relocInfo::relocType rtype() { return _rspec.type(); }
const RelocationHolder& rspec() { return _rspec; }
@ -330,6 +332,10 @@ class Address VALUE_OBJ_CLASS_SPEC {
Address a(base(), disp() + plusdisp);
return a;
}
bool is_same_address(Address a) const {
// disregard _rspec
return base() == a.base() && (has_index() ? index() == a.index() : disp() == a.disp());
}
Address after_save() const {
Address a = (*this);
@ -436,6 +442,10 @@ class AddressLiteral VALUE_OBJ_CLASS_SPEC {
: _address((address) addr),
_rspec(rspec_from_rtype(rtype, (address) addr)) {}
AddressLiteral(oop* addr, relocInfo::relocType rtype = relocInfo::none)
: _address((address) addr),
_rspec(rspec_from_rtype(rtype, (address) addr)) {}
AddressLiteral(float* addr, relocInfo::relocType rtype = relocInfo::none)
: _address((address) addr),
_rspec(rspec_from_rtype(rtype, (address) addr)) {}
@ -455,6 +465,21 @@ class AddressLiteral VALUE_OBJ_CLASS_SPEC {
}
};
// Convenience classes
class ExternalAddress: public AddressLiteral {
private:
static relocInfo::relocType reloc_for_target(address target) {
// Sometimes ExternalAddress is used for values which aren't
// exactly addresses, like the card table base.
// external_word_type can't be used for values in the first page
// so just skip the reloc in that case.
return external_word_Relocation::can_be_relocated(target) ? relocInfo::external_word_type : relocInfo::none;
}
public:
ExternalAddress(address target) : AddressLiteral(target, reloc_for_target( target)) {}
ExternalAddress(oop* target) : AddressLiteral(target, reloc_for_target((address) target)) {}
};
inline Address RegisterImpl::address_in_saved_window() const {
return (Address(SP, (sp_offset_in_saved_window() * wordSize) + STACK_BIAS));
@ -691,6 +716,8 @@ class Assembler : public AbstractAssembler {
casa_op3 = 0x3c,
casxa_op3 = 0x3e,
mftoi_op3 = 0x36,
alt_bit_op3 = 0x10,
cc_bit_op3 = 0x10
};
@ -725,7 +752,13 @@ class Assembler : public AbstractAssembler {
fitod_opf = 0xc8,
fstod_opf = 0xc9,
fstoi_opf = 0xd1,
fdtoi_opf = 0xd2
fdtoi_opf = 0xd2,
mdtox_opf = 0x110,
mstouw_opf = 0x111,
mstosw_opf = 0x113,
mxtod_opf = 0x118,
mwtos_opf = 0x119
};
enum RCondition { rc_z = 1, rc_lez = 2, rc_lz = 3, rc_nz = 5, rc_gz = 6, rc_gez = 7 };
@ -855,9 +888,8 @@ class Assembler : public AbstractAssembler {
// and be sign-extended. Check the range.
static void assert_signed_range(intptr_t x, int nbits) {
assert( nbits == 32
|| -(1 << nbits-1) <= x && x < ( 1 << nbits-1),
"value out of range");
assert(nbits == 32 || (-(1 << nbits-1) <= x && x < ( 1 << nbits-1)),
err_msg("value out of range: x=" INTPTR_FORMAT ", nbits=%d", x, nbits));
}
static void assert_signed_word_disp_range(intptr_t x, int nbits) {
@ -1037,6 +1069,9 @@ class Assembler : public AbstractAssembler {
return x & ((1 << 10) - 1);
}
// instruction only in VIS3
static void vis3_only() { assert( VM_Version::has_vis3(), "This instruction only works on SPARC with VIS3"); }
// instruction only in v9
static void v9_only() { assert( VM_Version::v9_instructions_work(), "This instruction only works on SPARC V9"); }
@ -1223,8 +1258,8 @@ public:
// pp 159
void ftox( FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d ) { v9_only(); emit_long( op(arith_op) | fd(d, w) | op3(fpop1_op3) | opf(0x80 + w) | fs2(s, w)); }
void ftoi( FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d ) { emit_long( op(arith_op) | fd(d, w) | op3(fpop1_op3) | opf(0xd0 + w) | fs2(s, w)); }
void ftox( FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d ) { v9_only(); emit_long( op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(fpop1_op3) | opf(0x80 + w) | fs2(s, w)); }
void ftoi( FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d ) { emit_long( op(arith_op) | fd(d, FloatRegisterImpl::S) | op3(fpop1_op3) | opf(0xd0 + w) | fs2(s, w)); }
// pp 160
@ -1232,8 +1267,8 @@ public:
// pp 161
void fxtof( FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d ) { v9_only(); emit_long( op(arith_op) | fd(d, w) | op3(fpop1_op3) | opf(0x80 + w*4) | fs2(s, w)); }
void fitof( FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d ) { emit_long( op(arith_op) | fd(d, w) | op3(fpop1_op3) | opf(0xc0 + w*4) | fs2(s, w)); }
void fxtof( FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d ) { v9_only(); emit_long( op(arith_op) | fd(d, w) | op3(fpop1_op3) | opf(0x80 + w*4) | fs2(s, FloatRegisterImpl::D)); }
void fitof( FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d ) { emit_long( op(arith_op) | fd(d, w) | op3(fpop1_op3) | opf(0xc0 + w*4) | fs2(s, FloatRegisterImpl::S)); }
// pp 162
@ -1685,6 +1720,19 @@ public:
inline void wrasi( Register d) { v9_only(); emit_long( op(arith_op) | rs1(d) | op3(wrreg_op3) | u_field(3, 29, 25)); }
inline void wrfprs( Register d) { v9_only(); emit_long( op(arith_op) | rs1(d) | op3(wrreg_op3) | u_field(6, 29, 25)); }
// VIS3 instructions
void movstosw( FloatRegister s, Register d ) { vis3_only(); emit_long( op(arith_op) | rd(d) | op3(mftoi_op3) | opf(mstosw_opf) | fs2(s, FloatRegisterImpl::S)); }
void movstouw( FloatRegister s, Register d ) { vis3_only(); emit_long( op(arith_op) | rd(d) | op3(mftoi_op3) | opf(mstouw_opf) | fs2(s, FloatRegisterImpl::S)); }
void movdtox( FloatRegister s, Register d ) { vis3_only(); emit_long( op(arith_op) | rd(d) | op3(mftoi_op3) | opf(mdtox_opf) | fs2(s, FloatRegisterImpl::D)); }
void movwtos( Register s, FloatRegister d ) { vis3_only(); emit_long( op(arith_op) | fd(d, FloatRegisterImpl::S) | op3(mftoi_op3) | opf(mwtos_opf) | rs2(s)); }
void movxtod( Register s, FloatRegister d ) { vis3_only(); emit_long( op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(mftoi_op3) | opf(mxtod_opf) | rs2(s)); }
// For a given register condition, return the appropriate condition code
// Condition (the one you would use to get the same effect after "tst" on
// the target register.)
@ -2287,7 +2335,7 @@ public:
int total_frame_size_in_bytes(int extraWords);
// used when extraWords known statically
void save_frame(int extraWords);
void save_frame(int extraWords = 0);
void save_frame_c1(int size_in_bytes);
// make a frame, and simultaneously pass up one or two register value
// into the new register window
@ -2456,9 +2504,11 @@ public:
// offset relative to Gargs of argument at tos[arg_slot].
// (arg_slot == 0 means the last argument, not the first).
RegisterOrConstant argument_offset(RegisterOrConstant arg_slot,
Register temp_reg,
int extra_slot_offset = 0);
// Address of Gargs and argument_offset.
Address argument_address(RegisterOrConstant arg_slot,
Register temp_reg,
int extra_slot_offset = 0);
// Stack overflow checking

View File

@ -255,7 +255,11 @@ inline void Assembler::stf( FloatRegisterImpl::Width w, FloatRegister d, Regi
inline void Assembler::stf( FloatRegisterImpl::Width w, FloatRegister d, Register s1, Register s2) { emit_long( op(ldst_op) | fd(d, w) | alt_op3(stf_op3, w) | rs1(s1) | rs2(s2) ); }
inline void Assembler::stf( FloatRegisterImpl::Width w, FloatRegister d, Register s1, int simm13a) { emit_data( op(ldst_op) | fd(d, w) | alt_op3(stf_op3, w) | rs1(s1) | immed(true) | simm(simm13a, 13)); }
inline void Assembler::stf( FloatRegisterImpl::Width w, FloatRegister d, const Address& a, int offset) { relocate(a.rspec(offset)); stf(w, d, a.base(), a.disp() + offset); }
inline void Assembler::stf( FloatRegisterImpl::Width w, FloatRegister d, const Address& a, int offset) {
relocate(a.rspec(offset));
if (a.has_index()) { assert(offset == 0, ""); stf(w, d, a.base(), a.index() ); }
else { stf(w, d, a.base(), a.disp() + offset); }
}
inline void Assembler::stfsr( Register s1, Register s2) { v9_dep(); emit_long( op(ldst_op) | op3(stfsr_op3) | rs1(s1) | rs2(s2) ); }
inline void Assembler::stfsr( Register s1, int simm13a) { v9_dep(); emit_data( op(ldst_op) | op3(stfsr_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); }

View File

@ -513,6 +513,8 @@ frame frame::sender(RegisterMap* map) const {
// interpreted but its pc is in the code cache (for c1 -> osr_frame_return_id stub), so it must be
// explicitly recognized.
if (is_ricochet_frame()) return sender_for_ricochet_frame(map);
bool frame_is_interpreted = is_interpreted_frame();
if (frame_is_interpreted) {
map->make_integer_regs_unsaved();

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,228 @@
/*
* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
// Platform-specific definitions for method handles.
// These definitions are inlined into class MethodHandles.
// Adapters
enum /* platform_dependent_constants */ {
adapter_code_size = NOT_LP64(22000 DEBUG_ONLY(+ 40000)) LP64_ONLY(32000 DEBUG_ONLY(+ 80000))
};
public:
class RicochetFrame : public ResourceObj {
friend class MethodHandles;
private:
/*
RF field x86 SPARC
sender_pc *(rsp+0) I7-0x8
sender_link rbp I6+BIAS
exact_sender_sp rsi/r13 I5_savedSP
conversion *(rcx+&amh_conv) L5_conv
saved_args_base rax L4_sab (cf. Gargs = G4)
saved_args_layout #NULL L3_sal
saved_target *(rcx+&mh_vmtgt) L2_stgt
continuation #STUB_CON L1_cont
*/
static const Register L1_continuation ; // what to do when control gets back here
static const Register L2_saved_target ; // target method handle to invoke on saved_args
static const Register L3_saved_args_layout; // caching point for MethodTypeForm.vmlayout cookie
static const Register L4_saved_args_base ; // base of pushed arguments (slot 0, arg N) (-3)
static const Register L5_conversion ; // misc. information from original AdapterMethodHandle (-2)
frame _fr;
RicochetFrame(const frame& fr) : _fr(fr) { }
intptr_t* register_addr(Register reg) const {
assert((_fr.sp() + reg->sp_offset_in_saved_window()) == _fr.register_addr(reg), "must agree");
return _fr.register_addr(reg);
}
intptr_t register_value(Register reg) const { return *register_addr(reg); }
public:
intptr_t* continuation() const { return (intptr_t*) register_value(L1_continuation); }
oop saved_target() const { return (oop) register_value(L2_saved_target); }
oop saved_args_layout() const { return (oop) register_value(L3_saved_args_layout); }
intptr_t* saved_args_base() const { return (intptr_t*) register_value(L4_saved_args_base); }
intptr_t conversion() const { return register_value(L5_conversion); }
intptr_t* exact_sender_sp() const { return (intptr_t*) register_value(I5_savedSP); }
intptr_t* sender_link() const { return _fr.sender_sp(); } // XXX
address sender_pc() const { return _fr.sender_pc(); }
// This value is not used for much, but it apparently must be nonzero.
static int frame_size_in_bytes() { return wordSize * 4; }
intptr_t* extended_sender_sp() const { return saved_args_base(); }
intptr_t return_value_slot_number() const {
return adapter_conversion_vminfo(conversion());
}
BasicType return_value_type() const {
return adapter_conversion_dest_type(conversion());
}
bool has_return_value_slot() const {
return return_value_type() != T_VOID;
}
intptr_t* return_value_slot_addr() const {
assert(has_return_value_slot(), "");
return saved_arg_slot_addr(return_value_slot_number());
}
intptr_t* saved_target_slot_addr() const {
return saved_arg_slot_addr(saved_args_length());
}
intptr_t* saved_arg_slot_addr(int slot) const {
assert(slot >= 0, "");
return (intptr_t*)( (address)saved_args_base() + (slot * Interpreter::stackElementSize) );
}
jint saved_args_length() const;
jint saved_arg_offset(int arg) const;
// GC interface
oop* saved_target_addr() { return (oop*)register_addr(L2_saved_target); }
oop* saved_args_layout_addr() { return (oop*)register_addr(L3_saved_args_layout); }
oop compute_saved_args_layout(bool read_cache, bool write_cache);
#ifdef ASSERT
// The magic number is supposed to help find ricochet frames within the bytes of stack dumps.
enum { MAGIC_NUMBER_1 = 0xFEED03E, MAGIC_NUMBER_2 = 0xBEEF03E };
static const Register L0_magic_number_1 ; // cookie for debugging, at start of RSA
static Address magic_number_2_addr() { return Address(L4_saved_args_base, -wordSize); }
intptr_t magic_number_1() const { return register_value(L0_magic_number_1); }
intptr_t magic_number_2() const { return saved_args_base()[-1]; }
#endif //ASSERT
public:
enum { RETURN_VALUE_PLACEHOLDER = (NOT_DEBUG(0) DEBUG_ONLY(42)) };
void verify() const NOT_DEBUG_RETURN; // check for MAGIC_NUMBER, etc.
static void generate_ricochet_blob(MacroAssembler* _masm,
// output params:
int* bounce_offset,
int* exception_offset,
int* frame_size_in_words);
static void enter_ricochet_frame(MacroAssembler* _masm,
Register recv_reg,
Register argv_reg,
address return_handler);
static void leave_ricochet_frame(MacroAssembler* _masm,
Register recv_reg,
Register new_sp_reg,
Register sender_pc_reg);
static RicochetFrame* from_frame(const frame& fr) {
RicochetFrame* rf = new RicochetFrame(fr);
rf->verify();
return rf;
}
static void verify_clean(MacroAssembler* _masm) NOT_DEBUG_RETURN;
};
// Additional helper methods for MethodHandles code generation:
public:
static void load_klass_from_Class(MacroAssembler* _masm, Register klass_reg, Register temp_reg, Register temp2_reg);
static void load_conversion_vminfo(MacroAssembler* _masm, Address conversion_field_addr, Register reg);
static void extract_conversion_vminfo(MacroAssembler* _masm, Register conversion_field_reg, Register reg);
static void extract_conversion_dest_type(MacroAssembler* _masm, Register conversion_field_reg, Register reg);
static void load_stack_move(MacroAssembler* _masm,
Address G3_amh_conversion,
Register G5_stack_move);
static void insert_arg_slots(MacroAssembler* _masm,
RegisterOrConstant arg_slots,
Register argslot_reg,
Register temp_reg, Register temp2_reg, Register temp3_reg);
static void remove_arg_slots(MacroAssembler* _masm,
RegisterOrConstant arg_slots,
Register argslot_reg,
Register temp_reg, Register temp2_reg, Register temp3_reg);
static void push_arg_slots(MacroAssembler* _masm,
Register argslot_reg,
RegisterOrConstant slot_count,
Register temp_reg, Register temp2_reg);
static void move_arg_slots_up(MacroAssembler* _masm,
Register bottom_reg, // invariant
Address top_addr, // can use temp_reg
RegisterOrConstant positive_distance_in_slots,
Register temp_reg, Register temp2_reg);
static void move_arg_slots_down(MacroAssembler* _masm,
Address bottom_addr, // can use temp_reg
Register top_reg, // invariant
RegisterOrConstant negative_distance_in_slots,
Register temp_reg, Register temp2_reg);
static void move_typed_arg(MacroAssembler* _masm,
BasicType type, bool is_element,
Address value_src, Address slot_dest,
Register temp_reg);
static void move_return_value(MacroAssembler* _masm, BasicType type,
Address return_slot);
static void verify_argslot(MacroAssembler* _masm, Register argslot_reg,
Register temp_reg,
const char* error_message) NOT_DEBUG_RETURN;
static void verify_argslots(MacroAssembler* _masm,
RegisterOrConstant argslot_count,
Register argslot_reg,
Register temp_reg,
Register temp2_reg,
bool negate_argslot,
const char* error_message) NOT_DEBUG_RETURN;
static void verify_stack_move(MacroAssembler* _masm,
RegisterOrConstant arg_slots,
int direction) NOT_DEBUG_RETURN;
static void verify_klass(MacroAssembler* _masm,
Register obj_reg, KlassHandle klass,
Register temp_reg, Register temp2_reg,
const char* error_message = "wrong klass") NOT_DEBUG_RETURN;
static void verify_method_handle(MacroAssembler* _masm, Register mh_reg,
Register temp_reg, Register temp2_reg) {
verify_klass(_masm, mh_reg, SystemDictionaryHandles::MethodHandle_klass(),
temp_reg, temp2_reg,
"reference is a MH");
}
// Similar to InterpreterMacroAssembler::jump_from_interpreted.
// Takes care of special dispatch from single stepping too.
static void jump_from_method_handle(MacroAssembler* _masm, Register method, Register temp, Register temp2);
static void trace_method_handle(MacroAssembler* _masm, const char* adaptername) PRODUCT_RETURN;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1998, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -27,6 +27,7 @@
// machine-dependent implemention for register maps
friend class frame;
friend class MethodHandles;
private:
intptr_t* _window; // register window save area (for L and I regs)

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1998, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -42,8 +42,6 @@
#define __ masm->
ExceptionBlob *OptoRuntime::_exception_blob;
//------------------------------ generate_exception_blob ---------------------------
// creates exception blob at the end
// Using exception blob, this code is jumped from a compiled method.

View File

@ -47,18 +47,6 @@
#define __ masm->
#ifdef COMPILER2
UncommonTrapBlob* SharedRuntime::_uncommon_trap_blob;
#endif // COMPILER2
DeoptimizationBlob* SharedRuntime::_deopt_blob;
SafepointBlob* SharedRuntime::_polling_page_safepoint_handler_blob;
SafepointBlob* SharedRuntime::_polling_page_return_handler_blob;
RuntimeStub* SharedRuntime::_wrong_method_blob;
RuntimeStub* SharedRuntime::_ic_miss_blob;
RuntimeStub* SharedRuntime::_resolve_opt_virtual_call_blob;
RuntimeStub* SharedRuntime::_resolve_virtual_call_blob;
RuntimeStub* SharedRuntime::_resolve_static_call_blob;
class RegisterSaver {
@ -3492,7 +3480,7 @@ void SharedRuntime::generate_uncommon_trap_blob() {
// the 64-bit %o's, then do a save, then fixup the caller's SP (our FP).
// Tricky, tricky, tricky...
static SafepointBlob* generate_handler_blob(address call_ptr, bool cause_return) {
SafepointBlob* SharedRuntime::generate_handler_blob(address call_ptr, bool cause_return) {
assert (StubRoutines::forward_exception_entry() != NULL, "must be generated before");
// allocate space for the code
@ -3587,7 +3575,7 @@ static SafepointBlob* generate_handler_blob(address call_ptr, bool cause_return)
// but since this is generic code we don't know what they are and the caller
// must do any gc of the args.
//
static RuntimeStub* generate_resolve_blob(address destination, const char* name) {
RuntimeStub* SharedRuntime::generate_resolve_blob(address destination, const char* name) {
assert (StubRoutines::forward_exception_entry() != NULL, "must be generated before");
// allocate space for the code
@ -3677,35 +3665,3 @@ static RuntimeStub* generate_resolve_blob(address destination, const char* name)
// frame_size_words or bytes??
return RuntimeStub::new_runtime_stub(name, &buffer, frame_complete, frame_size_words, oop_maps, true);
}
void SharedRuntime::generate_stubs() {
_wrong_method_blob = generate_resolve_blob(CAST_FROM_FN_PTR(address, SharedRuntime::handle_wrong_method),
"wrong_method_stub");
_ic_miss_blob = generate_resolve_blob(CAST_FROM_FN_PTR(address, SharedRuntime::handle_wrong_method_ic_miss),
"ic_miss_stub");
_resolve_opt_virtual_call_blob = generate_resolve_blob(CAST_FROM_FN_PTR(address, SharedRuntime::resolve_opt_virtual_call_C),
"resolve_opt_virtual_call");
_resolve_virtual_call_blob = generate_resolve_blob(CAST_FROM_FN_PTR(address, SharedRuntime::resolve_virtual_call_C),
"resolve_virtual_call");
_resolve_static_call_blob = generate_resolve_blob(CAST_FROM_FN_PTR(address, SharedRuntime::resolve_static_call_C),
"resolve_static_call");
_polling_page_safepoint_handler_blob =
generate_handler_blob(CAST_FROM_FN_PTR(address,
SafepointSynchronize::handle_polling_page_exception), false);
_polling_page_return_handler_blob =
generate_handler_blob(CAST_FROM_FN_PTR(address,
SafepointSynchronize::handle_polling_page_exception), true);
generate_deopt_blob();
#ifdef COMPILER2
generate_uncommon_trap_blob();
#endif // COMPILER2
}

View File

@ -425,7 +425,7 @@ reg_class dflt_reg(R_F0, R_F1, R_F2, R_F3, R_F4, R_F5, R_F6, R_F7, R_F8, R_F9, R
// but they are used with the "Op_RegD" type, and always occur in even/odd pairs.
// This class is usable for mis-aligned loads as happen in I2C adapters.
reg_class dflt_low_reg(R_F0, R_F1, R_F2, R_F3, R_F4, R_F5, R_F6, R_F7, R_F8, R_F9, R_F10,R_F11,R_F12,R_F13,R_F14,R_F15,
R_F16,R_F17,R_F18,R_F19,R_F20,R_F21,R_F22,R_F23,R_F24,R_F25,R_F26,R_F27,R_F28,R_F29,R_F30,R_F31 );
R_F16,R_F17,R_F18,R_F19,R_F20,R_F21,R_F22,R_F23,R_F24,R_F25,R_F26,R_F27,R_F28,R_F29);
%}
//----------DEFINITION BLOCK---------------------------------------------------
@ -1326,17 +1326,17 @@ uint MachSpillCopyNode::implementation( CodeBuffer *cbuf,
// --------------------------------------
// Check for float->int copy; requires a trip through memory
if( src_first_rc == rc_float && dst_first_rc == rc_int ) {
if (src_first_rc == rc_float && dst_first_rc == rc_int && UseVIS < 3) {
int offset = frame::register_save_words*wordSize;
if( cbuf ) {
if (cbuf) {
emit3_simm13( *cbuf, Assembler::arith_op, R_SP_enc, Assembler::sub_op3, R_SP_enc, 16 );
impl_helper(this,cbuf,ra_,do_size,false,offset,src_first,Assembler::stf_op3 ,"STF ",size, st);
impl_helper(this,cbuf,ra_,do_size,true ,offset,dst_first,Assembler::lduw_op3,"LDUW",size, st);
emit3_simm13( *cbuf, Assembler::arith_op, R_SP_enc, Assembler::add_op3, R_SP_enc, 16 );
}
#ifndef PRODUCT
else if( !do_size ) {
if( size != 0 ) st->print("\n\t");
else if (!do_size) {
if (size != 0) st->print("\n\t");
st->print( "SUB R_SP,16,R_SP\n");
impl_helper(this,cbuf,ra_,do_size,false,offset,src_first,Assembler::stf_op3 ,"STF ",size, st);
impl_helper(this,cbuf,ra_,do_size,true ,offset,dst_first,Assembler::lduw_op3,"LDUW",size, st);
@ -1346,6 +1346,21 @@ uint MachSpillCopyNode::implementation( CodeBuffer *cbuf,
size += 16;
}
// Check for float->int copy on T4
if (src_first_rc == rc_float && dst_first_rc == rc_int && UseVIS >= 3) {
// Further check for aligned-adjacent pair, so we can use a double move
if ((src_first&1)==0 && src_first+1 == src_second && (dst_first&1)==0 && dst_first+1 == dst_second)
return impl_mov_helper(cbuf,do_size,src_first,dst_first,Assembler::mftoi_op3,Assembler::mdtox_opf,"MOVDTOX",size, st);
size = impl_mov_helper(cbuf,do_size,src_first,dst_first,Assembler::mftoi_op3,Assembler::mstouw_opf,"MOVSTOUW",size, st);
}
// Check for int->float copy on T4
if (src_first_rc == rc_int && dst_first_rc == rc_float && UseVIS >= 3) {
// Further check for aligned-adjacent pair, so we can use a double move
if ((src_first&1)==0 && src_first+1 == src_second && (dst_first&1)==0 && dst_first+1 == dst_second)
return impl_mov_helper(cbuf,do_size,src_first,dst_first,Assembler::mftoi_op3,Assembler::mxtod_opf,"MOVXTOD",size, st);
size = impl_mov_helper(cbuf,do_size,src_first,dst_first,Assembler::mftoi_op3,Assembler::mwtos_opf,"MOVWTOS",size, st);
}
// --------------------------------------
// In the 32-bit 1-reg-longs build ONLY, I see mis-aligned long destinations.
// In such cases, I have to do the big-endian swap. For aligned targets, the
@ -8164,215 +8179,58 @@ instruct cadd_cmpLTMask( iRegI p, iRegI q, iRegI y, iRegI tmp, flagsReg ccr ) %{
ins_pipe( cadd_cmpltmask );
%}
//----------Arithmetic Conversion Instructions---------------------------------
// The conversions operations are all Alpha sorted. Please keep it that way!
instruct convD2F_reg(regF dst, regD src) %{
match(Set dst (ConvD2F src));
size(4);
format %{ "FDTOS $src,$dst" %}
opcode(Assembler::fpop1_op3, Assembler::arith_op, Assembler::fdtos_opf);
ins_encode(form3_opf_rs2D_rdF(src, dst));
ins_pipe(fcvtD2F);
%}
//-----------------------------------------------------------------
// Direct raw moves between float and general registers using VIS3.
// ins_pipe(faddF_reg);
instruct MoveF2I_reg_reg(iRegI dst, regF src) %{
predicate(UseVIS >= 3);
match(Set dst (MoveF2I src));
// Convert a double to an int in a float register.
// If the double is a NAN, stuff a zero in instead.
instruct convD2I_helper(regF dst, regD src, flagsRegF0 fcc0) %{
effect(DEF dst, USE src, KILL fcc0);
format %{ "FCMPd fcc0,$src,$src\t! check for NAN\n\t"
"FBO,pt fcc0,skip\t! branch on ordered, predict taken\n\t"
"FDTOI $src,$dst\t! convert in delay slot\n\t"
"FITOS $dst,$dst\t! change NaN/max-int to valid float\n\t"
"FSUBs $dst,$dst,$dst\t! cleared only if nan\n"
"skip:" %}
ins_encode(form_d2i_helper(src,dst));
ins_pipe(fcvtD2I);
%}
instruct convD2I_reg(stackSlotI dst, regD src) %{
match(Set dst (ConvD2I src));
ins_cost(DEFAULT_COST*2 + MEMORY_REF_COST*2 + BRANCH_COST);
expand %{
regF tmp;
convD2I_helper(tmp, src);
regF_to_stkI(dst, tmp);
format %{ "MOVSTOUW $src,$dst\t! MoveF2I" %}
ins_encode %{
__ movstouw($src$$FloatRegister, $dst$$Register);
%}
%}
// Convert a double to a long in a double register.
// If the double is a NAN, stuff a zero in instead.
instruct convD2L_helper(regD dst, regD src, flagsRegF0 fcc0) %{
effect(DEF dst, USE src, KILL fcc0);
format %{ "FCMPd fcc0,$src,$src\t! check for NAN\n\t"
"FBO,pt fcc0,skip\t! branch on ordered, predict taken\n\t"
"FDTOX $src,$dst\t! convert in delay slot\n\t"
"FXTOD $dst,$dst\t! change NaN/max-long to valid double\n\t"
"FSUBd $dst,$dst,$dst\t! cleared only if nan\n"
"skip:" %}
ins_encode(form_d2l_helper(src,dst));
ins_pipe(fcvtD2L);
%}
// Double to Long conversion
instruct convD2L_reg(stackSlotL dst, regD src) %{
match(Set dst (ConvD2L src));
ins_cost(DEFAULT_COST*2 + MEMORY_REF_COST*2 + BRANCH_COST);
expand %{
regD tmp;
convD2L_helper(tmp, src);
regD_to_stkL(dst, tmp);
%}
%}
instruct convF2D_reg(regD dst, regF src) %{
match(Set dst (ConvF2D src));
format %{ "FSTOD $src,$dst" %}
opcode(Assembler::fpop1_op3, Assembler::arith_op, Assembler::fstod_opf);
ins_encode(form3_opf_rs2F_rdD(src, dst));
ins_pipe(fcvtF2D);
%}
instruct convF2I_helper(regF dst, regF src, flagsRegF0 fcc0) %{
effect(DEF dst, USE src, KILL fcc0);
format %{ "FCMPs fcc0,$src,$src\t! check for NAN\n\t"
"FBO,pt fcc0,skip\t! branch on ordered, predict taken\n\t"
"FSTOI $src,$dst\t! convert in delay slot\n\t"
"FITOS $dst,$dst\t! change NaN/max-int to valid float\n\t"
"FSUBs $dst,$dst,$dst\t! cleared only if nan\n"
"skip:" %}
ins_encode(form_f2i_helper(src,dst));
ins_pipe(fcvtF2I);
%}
instruct convF2I_reg(stackSlotI dst, regF src) %{
match(Set dst (ConvF2I src));
ins_cost(DEFAULT_COST*2 + MEMORY_REF_COST*2 + BRANCH_COST);
expand %{
regF tmp;
convF2I_helper(tmp, src);
regF_to_stkI(dst, tmp);
%}
%}
instruct convF2L_helper(regD dst, regF src, flagsRegF0 fcc0) %{
effect(DEF dst, USE src, KILL fcc0);
format %{ "FCMPs fcc0,$src,$src\t! check for NAN\n\t"
"FBO,pt fcc0,skip\t! branch on ordered, predict taken\n\t"
"FSTOX $src,$dst\t! convert in delay slot\n\t"
"FXTOD $dst,$dst\t! change NaN/max-long to valid double\n\t"
"FSUBd $dst,$dst,$dst\t! cleared only if nan\n"
"skip:" %}
ins_encode(form_f2l_helper(src,dst));
ins_pipe(fcvtF2L);
%}
// Float to Long conversion
instruct convF2L_reg(stackSlotL dst, regF src) %{
match(Set dst (ConvF2L src));
ins_cost(DEFAULT_COST*2 + MEMORY_REF_COST*2 + BRANCH_COST);
expand %{
regD tmp;
convF2L_helper(tmp, src);
regD_to_stkL(dst, tmp);
%}
%}
instruct convI2D_helper(regD dst, regF tmp) %{
effect(USE tmp, DEF dst);
format %{ "FITOD $tmp,$dst" %}
opcode(Assembler::fpop1_op3, Assembler::arith_op, Assembler::fitod_opf);
ins_encode(form3_opf_rs2F_rdD(tmp, dst));
ins_pipe(fcvtI2D);
%}
instruct convI2D_reg(stackSlotI src, regD dst) %{
match(Set dst (ConvI2D src));
ins_cost(DEFAULT_COST + MEMORY_REF_COST);
expand %{
regF tmp;
stkI_to_regF( tmp, src);
convI2D_helper( dst, tmp);
%}
%}
instruct convI2D_mem( regD_low dst, memory mem ) %{
match(Set dst (ConvI2D (LoadI mem)));
ins_cost(DEFAULT_COST + MEMORY_REF_COST);
size(8);
format %{ "LDF $mem,$dst\n\t"
"FITOD $dst,$dst" %}
opcode(Assembler::ldf_op3, Assembler::fitod_opf);
ins_encode(simple_form3_mem_reg( mem, dst ), form3_convI2F(dst, dst));
ins_pipe(floadF_mem);
%}
instruct convI2F_helper(regF dst, regF tmp) %{
effect(DEF dst, USE tmp);
format %{ "FITOS $tmp,$dst" %}
opcode(Assembler::fpop1_op3, Assembler::arith_op, Assembler::fitos_opf);
ins_encode(form3_opf_rs2F_rdF(tmp, dst));
ins_pipe(fcvtI2F);
%}
instruct convI2F_reg( regF dst, stackSlotI src ) %{
match(Set dst (ConvI2F src));
ins_cost(DEFAULT_COST + MEMORY_REF_COST);
expand %{
regF tmp;
stkI_to_regF(tmp,src);
convI2F_helper(dst, tmp);
%}
%}
instruct convI2F_mem( regF dst, memory mem ) %{
match(Set dst (ConvI2F (LoadI mem)));
ins_cost(DEFAULT_COST + MEMORY_REF_COST);
size(8);
format %{ "LDF $mem,$dst\n\t"
"FITOS $dst,$dst" %}
opcode(Assembler::ldf_op3, Assembler::fitos_opf);
ins_encode(simple_form3_mem_reg( mem, dst ), form3_convI2F(dst, dst));
ins_pipe(floadF_mem);
%}
instruct convI2L_reg(iRegL dst, iRegI src) %{
match(Set dst (ConvI2L src));
size(4);
format %{ "SRA $src,0,$dst\t! int->long" %}
opcode(Assembler::sra_op3, Assembler::arith_op);
ins_encode( form3_rs1_rs2_rd( src, R_G0, dst ) );
ins_pipe(ialu_reg_reg);
%}
// Zero-extend convert int to long
instruct convI2L_reg_zex(iRegL dst, iRegI src, immL_32bits mask ) %{
match(Set dst (AndL (ConvI2L src) mask) );
size(4);
format %{ "SRL $src,0,$dst\t! zero-extend int to long" %}
opcode(Assembler::srl_op3, Assembler::arith_op);
ins_encode( form3_rs1_rs2_rd( src, R_G0, dst ) );
instruct MoveI2F_reg_reg(regF dst, iRegI src) %{
predicate(UseVIS >= 3);
match(Set dst (MoveI2F src));
format %{ "MOVWTOS $src,$dst\t! MoveI2F" %}
ins_encode %{
__ movwtos($src$$Register, $dst$$FloatRegister);
%}
ins_pipe(ialu_reg_reg);
%}
// Zero-extend long
instruct zerox_long(iRegL dst, iRegL src, immL_32bits mask ) %{
match(Set dst (AndL src mask) );
size(4);
format %{ "SRL $src,0,$dst\t! zero-extend long" %}
opcode(Assembler::srl_op3, Assembler::arith_op);
ins_encode( form3_rs1_rs2_rd( src, R_G0, dst ) );
instruct MoveD2L_reg_reg(iRegL dst, regD src) %{
predicate(UseVIS >= 3);
match(Set dst (MoveD2L src));
format %{ "MOVDTOX $src,$dst\t! MoveD2L" %}
ins_encode %{
__ movdtox(as_DoubleFloatRegister($src$$reg), $dst$$Register);
%}
ins_pipe(ialu_reg_reg);
%}
instruct MoveL2D_reg_reg(regD dst, iRegL src) %{
predicate(UseVIS >= 3);
match(Set dst (MoveL2D src));
format %{ "MOVXTOD $src,$dst\t! MoveL2D" %}
ins_encode %{
__ movxtod($src$$Register, as_DoubleFloatRegister($dst$$reg));
%}
ins_pipe(ialu_reg_reg);
%}
// Raw moves between float and general registers using stack.
instruct MoveF2I_stack_reg(iRegI dst, stackSlotF src) %{
match(Set dst (MoveF2I src));
effect(DEF dst, USE src);
@ -8427,7 +8285,7 @@ instruct MoveF2I_reg_stack(stackSlotI dst, regF src) %{
ins_cost(MEMORY_REF_COST);
size(4);
format %{ "STF $src,$dst\t!MoveF2I" %}
format %{ "STF $src,$dst\t! MoveF2I" %}
opcode(Assembler::stf_op3);
ins_encode(simple_form3_mem_reg(dst, src));
ins_pipe(fstoreF_stk_reg);
@ -8439,7 +8297,7 @@ instruct MoveI2F_reg_stack(stackSlotF dst, iRegI src) %{
ins_cost(MEMORY_REF_COST);
size(4);
format %{ "STW $src,$dst\t!MoveI2F" %}
format %{ "STW $src,$dst\t! MoveI2F" %}
opcode(Assembler::stw_op3);
ins_encode(simple_form3_mem_reg( dst, src ) );
ins_pipe(istore_mem_reg);
@ -8451,7 +8309,7 @@ instruct MoveD2L_reg_stack(stackSlotL dst, regD src) %{
ins_cost(MEMORY_REF_COST);
size(4);
format %{ "STDF $src,$dst\t!MoveD2L" %}
format %{ "STDF $src,$dst\t! MoveD2L" %}
opcode(Assembler::stdf_op3);
ins_encode(simple_form3_mem_reg(dst, src));
ins_pipe(fstoreD_stk_reg);
@ -8463,13 +8321,290 @@ instruct MoveL2D_reg_stack(stackSlotD dst, iRegL src) %{
ins_cost(MEMORY_REF_COST);
size(4);
format %{ "STX $src,$dst\t!MoveL2D" %}
format %{ "STX $src,$dst\t! MoveL2D" %}
opcode(Assembler::stx_op3);
ins_encode(simple_form3_mem_reg( dst, src ) );
ins_pipe(istore_mem_reg);
%}
//----------Arithmetic Conversion Instructions---------------------------------
// The conversions operations are all Alpha sorted. Please keep it that way!
instruct convD2F_reg(regF dst, regD src) %{
match(Set dst (ConvD2F src));
size(4);
format %{ "FDTOS $src,$dst" %}
opcode(Assembler::fpop1_op3, Assembler::arith_op, Assembler::fdtos_opf);
ins_encode(form3_opf_rs2D_rdF(src, dst));
ins_pipe(fcvtD2F);
%}
// Convert a double to an int in a float register.
// If the double is a NAN, stuff a zero in instead.
instruct convD2I_helper(regF dst, regD src, flagsRegF0 fcc0) %{
effect(DEF dst, USE src, KILL fcc0);
format %{ "FCMPd fcc0,$src,$src\t! check for NAN\n\t"
"FBO,pt fcc0,skip\t! branch on ordered, predict taken\n\t"
"FDTOI $src,$dst\t! convert in delay slot\n\t"
"FITOS $dst,$dst\t! change NaN/max-int to valid float\n\t"
"FSUBs $dst,$dst,$dst\t! cleared only if nan\n"
"skip:" %}
ins_encode(form_d2i_helper(src,dst));
ins_pipe(fcvtD2I);
%}
instruct convD2I_stk(stackSlotI dst, regD src) %{
match(Set dst (ConvD2I src));
ins_cost(DEFAULT_COST*2 + MEMORY_REF_COST*2 + BRANCH_COST);
expand %{
regF tmp;
convD2I_helper(tmp, src);
regF_to_stkI(dst, tmp);
%}
%}
instruct convD2I_reg(iRegI dst, regD src) %{
predicate(UseVIS >= 3);
match(Set dst (ConvD2I src));
ins_cost(DEFAULT_COST*2 + BRANCH_COST);
expand %{
regF tmp;
convD2I_helper(tmp, src);
MoveF2I_reg_reg(dst, tmp);
%}
%}
// Convert a double to a long in a double register.
// If the double is a NAN, stuff a zero in instead.
instruct convD2L_helper(regD dst, regD src, flagsRegF0 fcc0) %{
effect(DEF dst, USE src, KILL fcc0);
format %{ "FCMPd fcc0,$src,$src\t! check for NAN\n\t"
"FBO,pt fcc0,skip\t! branch on ordered, predict taken\n\t"
"FDTOX $src,$dst\t! convert in delay slot\n\t"
"FXTOD $dst,$dst\t! change NaN/max-long to valid double\n\t"
"FSUBd $dst,$dst,$dst\t! cleared only if nan\n"
"skip:" %}
ins_encode(form_d2l_helper(src,dst));
ins_pipe(fcvtD2L);
%}
instruct convD2L_stk(stackSlotL dst, regD src) %{
match(Set dst (ConvD2L src));
ins_cost(DEFAULT_COST*2 + MEMORY_REF_COST*2 + BRANCH_COST);
expand %{
regD tmp;
convD2L_helper(tmp, src);
regD_to_stkL(dst, tmp);
%}
%}
instruct convD2L_reg(iRegL dst, regD src) %{
predicate(UseVIS >= 3);
match(Set dst (ConvD2L src));
ins_cost(DEFAULT_COST*2 + BRANCH_COST);
expand %{
regD tmp;
convD2L_helper(tmp, src);
MoveD2L_reg_reg(dst, tmp);
%}
%}
instruct convF2D_reg(regD dst, regF src) %{
match(Set dst (ConvF2D src));
format %{ "FSTOD $src,$dst" %}
opcode(Assembler::fpop1_op3, Assembler::arith_op, Assembler::fstod_opf);
ins_encode(form3_opf_rs2F_rdD(src, dst));
ins_pipe(fcvtF2D);
%}
// Convert a float to an int in a float register.
// If the float is a NAN, stuff a zero in instead.
instruct convF2I_helper(regF dst, regF src, flagsRegF0 fcc0) %{
effect(DEF dst, USE src, KILL fcc0);
format %{ "FCMPs fcc0,$src,$src\t! check for NAN\n\t"
"FBO,pt fcc0,skip\t! branch on ordered, predict taken\n\t"
"FSTOI $src,$dst\t! convert in delay slot\n\t"
"FITOS $dst,$dst\t! change NaN/max-int to valid float\n\t"
"FSUBs $dst,$dst,$dst\t! cleared only if nan\n"
"skip:" %}
ins_encode(form_f2i_helper(src,dst));
ins_pipe(fcvtF2I);
%}
instruct convF2I_stk(stackSlotI dst, regF src) %{
match(Set dst (ConvF2I src));
ins_cost(DEFAULT_COST*2 + MEMORY_REF_COST*2 + BRANCH_COST);
expand %{
regF tmp;
convF2I_helper(tmp, src);
regF_to_stkI(dst, tmp);
%}
%}
instruct convF2I_reg(iRegI dst, regF src) %{
predicate(UseVIS >= 3);
match(Set dst (ConvF2I src));
ins_cost(DEFAULT_COST*2 + BRANCH_COST);
expand %{
regF tmp;
convF2I_helper(tmp, src);
MoveF2I_reg_reg(dst, tmp);
%}
%}
// Convert a float to a long in a float register.
// If the float is a NAN, stuff a zero in instead.
instruct convF2L_helper(regD dst, regF src, flagsRegF0 fcc0) %{
effect(DEF dst, USE src, KILL fcc0);
format %{ "FCMPs fcc0,$src,$src\t! check for NAN\n\t"
"FBO,pt fcc0,skip\t! branch on ordered, predict taken\n\t"
"FSTOX $src,$dst\t! convert in delay slot\n\t"
"FXTOD $dst,$dst\t! change NaN/max-long to valid double\n\t"
"FSUBd $dst,$dst,$dst\t! cleared only if nan\n"
"skip:" %}
ins_encode(form_f2l_helper(src,dst));
ins_pipe(fcvtF2L);
%}
instruct convF2L_stk(stackSlotL dst, regF src) %{
match(Set dst (ConvF2L src));
ins_cost(DEFAULT_COST*2 + MEMORY_REF_COST*2 + BRANCH_COST);
expand %{
regD tmp;
convF2L_helper(tmp, src);
regD_to_stkL(dst, tmp);
%}
%}
instruct convF2L_reg(iRegL dst, regF src) %{
predicate(UseVIS >= 3);
match(Set dst (ConvF2L src));
ins_cost(DEFAULT_COST*2 + BRANCH_COST);
expand %{
regD tmp;
convF2L_helper(tmp, src);
MoveD2L_reg_reg(dst, tmp);
%}
%}
instruct convI2D_helper(regD dst, regF tmp) %{
effect(USE tmp, DEF dst);
format %{ "FITOD $tmp,$dst" %}
opcode(Assembler::fpop1_op3, Assembler::arith_op, Assembler::fitod_opf);
ins_encode(form3_opf_rs2F_rdD(tmp, dst));
ins_pipe(fcvtI2D);
%}
instruct convI2D_stk(stackSlotI src, regD dst) %{
match(Set dst (ConvI2D src));
ins_cost(DEFAULT_COST + MEMORY_REF_COST);
expand %{
regF tmp;
stkI_to_regF(tmp, src);
convI2D_helper(dst, tmp);
%}
%}
instruct convI2D_reg(regD_low dst, iRegI src) %{
predicate(UseVIS >= 3);
match(Set dst (ConvI2D src));
expand %{
regF tmp;
MoveI2F_reg_reg(tmp, src);
convI2D_helper(dst, tmp);
%}
%}
instruct convI2D_mem(regD_low dst, memory mem) %{
match(Set dst (ConvI2D (LoadI mem)));
ins_cost(DEFAULT_COST + MEMORY_REF_COST);
size(8);
format %{ "LDF $mem,$dst\n\t"
"FITOD $dst,$dst" %}
opcode(Assembler::ldf_op3, Assembler::fitod_opf);
ins_encode(simple_form3_mem_reg( mem, dst ), form3_convI2F(dst, dst));
ins_pipe(floadF_mem);
%}
instruct convI2F_helper(regF dst, regF tmp) %{
effect(DEF dst, USE tmp);
format %{ "FITOS $tmp,$dst" %}
opcode(Assembler::fpop1_op3, Assembler::arith_op, Assembler::fitos_opf);
ins_encode(form3_opf_rs2F_rdF(tmp, dst));
ins_pipe(fcvtI2F);
%}
instruct convI2F_stk(regF dst, stackSlotI src) %{
match(Set dst (ConvI2F src));
ins_cost(DEFAULT_COST + MEMORY_REF_COST);
expand %{
regF tmp;
stkI_to_regF(tmp,src);
convI2F_helper(dst, tmp);
%}
%}
instruct convI2F_reg(regF dst, iRegI src) %{
predicate(UseVIS >= 3);
match(Set dst (ConvI2F src));
ins_cost(DEFAULT_COST);
expand %{
regF tmp;
MoveI2F_reg_reg(tmp, src);
convI2F_helper(dst, tmp);
%}
%}
instruct convI2F_mem( regF dst, memory mem ) %{
match(Set dst (ConvI2F (LoadI mem)));
ins_cost(DEFAULT_COST + MEMORY_REF_COST);
size(8);
format %{ "LDF $mem,$dst\n\t"
"FITOS $dst,$dst" %}
opcode(Assembler::ldf_op3, Assembler::fitos_opf);
ins_encode(simple_form3_mem_reg( mem, dst ), form3_convI2F(dst, dst));
ins_pipe(floadF_mem);
%}
instruct convI2L_reg(iRegL dst, iRegI src) %{
match(Set dst (ConvI2L src));
size(4);
format %{ "SRA $src,0,$dst\t! int->long" %}
opcode(Assembler::sra_op3, Assembler::arith_op);
ins_encode( form3_rs1_rs2_rd( src, R_G0, dst ) );
ins_pipe(ialu_reg_reg);
%}
// Zero-extend convert int to long
instruct convI2L_reg_zex(iRegL dst, iRegI src, immL_32bits mask ) %{
match(Set dst (AndL (ConvI2L src) mask) );
size(4);
format %{ "SRL $src,0,$dst\t! zero-extend int to long" %}
opcode(Assembler::srl_op3, Assembler::arith_op);
ins_encode( form3_rs1_rs2_rd( src, R_G0, dst ) );
ins_pipe(ialu_reg_reg);
%}
// Zero-extend long
instruct zerox_long(iRegL dst, iRegL src, immL_32bits mask ) %{
match(Set dst (AndL src mask) );
size(4);
format %{ "SRL $src,0,$dst\t! zero-extend long" %}
opcode(Assembler::srl_op3, Assembler::arith_op);
ins_encode( form3_rs1_rs2_rd( src, R_G0, dst ) );
ins_pipe(ialu_reg_reg);
%}
//-----------
// Long to Double conversion using V8 opcodes.
// Still useful because cheetah traps and becomes
@ -8589,7 +8724,7 @@ instruct convL2D_helper(regD dst, regD tmp) %{
ins_pipe(fcvtL2D);
%}
instruct convL2D_reg_fast_fxtof(regD dst, stackSlotL src) %{
instruct convL2D_stk_fast_fxtof(regD dst, stackSlotL src) %{
predicate(VM_Version::has_fast_fxtof());
match(Set dst (ConvL2D src));
ins_cost(DEFAULT_COST + 3 * MEMORY_REF_COST);
@ -8600,10 +8735,15 @@ instruct convL2D_reg_fast_fxtof(regD dst, stackSlotL src) %{
%}
%}
//-----------
// Long to Float conversion using V8 opcodes.
// Still useful because cheetah traps and becomes
// amazingly slow for some common numbers.
instruct convL2D_reg(regD dst, iRegL src) %{
predicate(UseVIS >= 3);
match(Set dst (ConvL2D src));
expand %{
regD tmp;
MoveL2D_reg_reg(tmp, src);
convL2D_helper(dst, tmp);
%}
%}
// Long to Float conversion using fast fxtof
instruct convL2F_helper(regF dst, regD tmp) %{
@ -8615,7 +8755,7 @@ instruct convL2F_helper(regF dst, regD tmp) %{
ins_pipe(fcvtL2F);
%}
instruct convL2F_reg_fast_fxtof(regF dst, stackSlotL src) %{
instruct convL2F_stk_fast_fxtof(regF dst, stackSlotL src) %{
match(Set dst (ConvL2F src));
ins_cost(DEFAULT_COST + MEMORY_REF_COST);
expand %{
@ -8624,6 +8764,18 @@ instruct convL2F_reg_fast_fxtof(regF dst, stackSlotL src) %{
convL2F_helper(dst, tmp);
%}
%}
instruct convL2F_reg(regF dst, iRegL src) %{
predicate(UseVIS >= 3);
match(Set dst (ConvL2F src));
ins_cost(DEFAULT_COST);
expand %{
regD tmp;
MoveL2D_reg_reg(tmp, src);
convL2F_helper(dst, tmp);
%}
%}
//-----------
instruct convL2I_reg(iRegI dst, iRegL src) %{

View File

@ -440,7 +440,8 @@ class StubGenerator: public StubCodeGenerator {
#undef __
#define __ masm->
address generate_throw_exception(const char* name, address runtime_entry, bool restore_saved_exception_pc) {
address generate_throw_exception(const char* name, address runtime_entry, bool restore_saved_exception_pc,
Register arg1 = noreg, Register arg2 = noreg) {
#ifdef ASSERT
int insts_size = VerifyThread ? 1 * K : 600;
#else
@ -476,6 +477,13 @@ class StubGenerator: public StubCodeGenerator {
__ set_last_Java_frame(last_java_sp, G0);
if (VerifyThread) __ mov(G2_thread, O0); // about to be smashed; pass early
__ save_thread(noreg);
if (arg1 != noreg) {
assert(arg2 != O1, "clobbered");
__ mov(arg1, O1);
}
if (arg2 != noreg) {
__ mov(arg2, O2);
}
// do the call
BLOCK_COMMENT("call runtime_entry");
__ call(runtime_entry, relocInfo::runtime_call_type);
@ -3240,6 +3248,14 @@ class StubGenerator: public StubCodeGenerator {
StubRoutines::_atomic_cmpxchg_long_entry = generate_atomic_cmpxchg_long();
StubRoutines::_atomic_add_ptr_entry = StubRoutines::_atomic_add_entry;
#endif // COMPILER2 !=> _LP64
// Build this early so it's available for the interpreter. The
// stub expects the required and actual type to already be in O1
// and O2 respectively.
StubRoutines::_throw_WrongMethodTypeException_entry =
generate_throw_exception("WrongMethodTypeException throw_exception",
CAST_FROM_FN_PTR(address, SharedRuntime::throw_WrongMethodTypeException),
false, G5_method_type, G3_method_handle);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -44,11 +44,6 @@ enum /* platform_dependent_constants */ {
code_size2 = 20000 // simply increase if too small (assembler will crash if too small)
};
// MethodHandles adapters
enum method_handles_platform_dependent_constants {
method_handles_adapters_code_size = 15000
};
class Sparc {
friend class StubGenerator;

View File

@ -128,24 +128,6 @@ address TemplateInterpreterGenerator::generate_ClassCastException_handler() {
}
// Arguments are: required type in G5_method_type, and
// failing object (or NULL) in G3_method_handle.
address TemplateInterpreterGenerator::generate_WrongMethodType_handler() {
address entry = __ pc();
// expression stack must be empty before entering the VM if an exception
// happened
__ empty_expression_stack();
// load exception object
__ call_VM(Oexception,
CAST_FROM_FN_PTR(address,
InterpreterRuntime::throw_WrongMethodTypeException),
G5_method_type, // required
G3_method_handle); // actual
__ should_not_reach_here();
return entry;
}
address TemplateInterpreterGenerator::generate_ArrayIndexOutOfBounds_handler(const char* name) {
address entry = __ pc();
// expression stack must be empty before entering the VM if an exception happened
@ -1712,7 +1694,7 @@ int AbstractInterpreter::layout_activation(methodOop method,
int computed_sp_adjustment = (delta > 0) ? round_to(delta, WordsPerLong) : 0;
*interpreter_frame->register_addr(I5_savedSP) = (intptr_t) (fp + computed_sp_adjustment) - STACK_BIAS;
} else {
assert(caller->is_compiled_frame() || caller->is_entry_frame(), "only possible cases");
assert(caller->is_compiled_frame() || caller->is_entry_frame() || caller->is_ricochet_frame(), "only possible cases");
// Don't have Lesp available; lay out locals block in the caller
// adjacent to the register window save area.
//

View File

@ -266,7 +266,7 @@ void TemplateTable::sipush() {
void TemplateTable::ldc(bool wide) {
transition(vtos, vtos);
Label call_ldc, notInt, notString, notClass, exit;
Label call_ldc, notInt, isString, notString, notClass, exit;
if (wide) {
__ get_2_byte_integer_at_bcp(1, G3_scratch, O1, InterpreterMacroAssembler::Unsigned);
@ -317,8 +317,11 @@ void TemplateTable::ldc(bool wide) {
__ bind(notInt);
// __ cmp(O2, JVM_CONSTANT_String);
__ brx(Assembler::equal, true, Assembler::pt, isString);
__ delayed()->cmp(O2, JVM_CONSTANT_Object);
__ brx(Assembler::notEqual, true, Assembler::pt, notString);
__ delayed()->ldf(FloatRegisterImpl::S, O0, O1, Ftos_f);
__ bind(isString);
__ ld_ptr(O0, O1, Otos_i);
__ verify_oop(Otos_i);
__ push(atos);

View File

@ -144,6 +144,18 @@ void VM_Version::initialize() {
// buf is started with ", " or is empty
_features_str = strdup(strlen(buf) > 2 ? buf + 2 : buf);
// UseVIS is set to the smallest of what hardware supports and what
// the command line requires. I.e., you cannot set UseVIS to 3 on
// older UltraSparc which do not support it.
if (UseVIS > 3) UseVIS=3;
if (UseVIS < 0) UseVIS=0;
if (!has_vis3()) // Drop to 2 if no VIS3 support
UseVIS = MIN2((intx)2,UseVIS);
if (!has_vis2()) // Drop to 1 if no VIS2 support
UseVIS = MIN2((intx)1,UseVIS);
if (!has_vis1()) // Drop to 0 if no VIS1 support
UseVIS = 0;
#ifndef PRODUCT
if (PrintMiscellaneous && Verbose) {
tty->print("Allocation: ");

View File

@ -3804,6 +3804,14 @@ void Assembler::addq(Register dst, Register src) {
emit_arith(0x03, 0xC0, dst, src);
}
void Assembler::andq(Address dst, int32_t imm32) {
InstructionMark im(this);
prefixq(dst);
emit_byte(0x81);
emit_operand(rsp, dst, 4);
emit_long(imm32);
}
void Assembler::andq(Register dst, int32_t imm32) {
(void) prefixq_and_encode(dst->encoding());
emit_arith(0x81, 0xE0, dst, imm32);
@ -5090,7 +5098,7 @@ void MacroAssembler::debug32(int rdi, int rsi, int rbp, int rsp, int rbx, int rd
} else {
ttyLocker ttyl;
::tty->print_cr("=============== DEBUG MESSAGE: %s ================\n", msg);
assert(false, "DEBUG MESSAGE");
assert(false, err_msg("DEBUG MESSAGE: %s", msg));
}
ThreadStateTransition::transition(thread, _thread_in_vm, saved_state);
}
@ -5653,6 +5661,7 @@ void MacroAssembler::debug64(char* msg, int64_t pc, int64_t regs[]) {
ttyLocker ttyl;
::tty->print_cr("=============== DEBUG MESSAGE: %s ================\n",
msg);
assert(false, err_msg("DEBUG MESSAGE: %s", msg));
}
}
@ -5890,6 +5899,53 @@ void MacroAssembler::call_VM(Register oop_result,
call_VM(oop_result, last_java_sp, entry_point, 3, check_exceptions);
}
void MacroAssembler::super_call_VM(Register oop_result,
Register last_java_sp,
address entry_point,
int number_of_arguments,
bool check_exceptions) {
Register thread = LP64_ONLY(r15_thread) NOT_LP64(noreg);
MacroAssembler::call_VM_base(oop_result, thread, last_java_sp, entry_point, number_of_arguments, check_exceptions);
}
void MacroAssembler::super_call_VM(Register oop_result,
Register last_java_sp,
address entry_point,
Register arg_1,
bool check_exceptions) {
pass_arg1(this, arg_1);
super_call_VM(oop_result, last_java_sp, entry_point, 1, check_exceptions);
}
void MacroAssembler::super_call_VM(Register oop_result,
Register last_java_sp,
address entry_point,
Register arg_1,
Register arg_2,
bool check_exceptions) {
LP64_ONLY(assert(arg_1 != c_rarg2, "smashed arg"));
pass_arg2(this, arg_2);
pass_arg1(this, arg_1);
super_call_VM(oop_result, last_java_sp, entry_point, 2, check_exceptions);
}
void MacroAssembler::super_call_VM(Register oop_result,
Register last_java_sp,
address entry_point,
Register arg_1,
Register arg_2,
Register arg_3,
bool check_exceptions) {
LP64_ONLY(assert(arg_1 != c_rarg3, "smashed arg"));
LP64_ONLY(assert(arg_2 != c_rarg3, "smashed arg"));
pass_arg3(this, arg_3);
LP64_ONLY(assert(arg_1 != c_rarg2, "smashed arg"));
pass_arg2(this, arg_2);
pass_arg1(this, arg_1);
super_call_VM(oop_result, last_java_sp, entry_point, 3, check_exceptions);
}
void MacroAssembler::call_VM_base(Register oop_result,
Register java_thread,
Register last_java_sp,

View File

@ -779,6 +779,7 @@ private:
void andl(Register dst, Address src);
void andl(Register dst, Register src);
void andq(Address dst, int32_t imm32);
void andq(Register dst, int32_t imm32);
void andq(Register dst, Address src);
void andq(Register dst, Register src);
@ -1660,6 +1661,14 @@ class MacroAssembler: public Assembler {
Register arg_1, Register arg_2, Register arg_3,
bool check_exceptions = true);
// These always tightly bind to MacroAssembler::call_VM_base
// bypassing the virtual implementation
void super_call_VM(Register oop_result, Register last_java_sp, address entry_point, int number_of_arguments = 0, bool check_exceptions = true);
void super_call_VM(Register oop_result, Register last_java_sp, address entry_point, Register arg_1, bool check_exceptions = true);
void super_call_VM(Register oop_result, Register last_java_sp, address entry_point, Register arg_1, Register arg_2, bool check_exceptions = true);
void super_call_VM(Register oop_result, Register last_java_sp, address entry_point, Register arg_1, Register arg_2, Register arg_3, bool check_exceptions = true);
void super_call_VM(Register oop_result, Register last_java_sp, address entry_point, Register arg_1, Register arg_2, Register arg_3, Register arg_4, bool check_exceptions = true);
void call_VM_leaf(address entry_point,
int number_of_arguments = 0);
void call_VM_leaf(address entry_point,

View File

@ -47,7 +47,7 @@
static jlong* double_quadword(jlong *adr, jlong lo, jlong hi) {
// Use the expression (adr)&(~0xF) to provide 128-bits aligned address
// of 128-bits operands for SSE instructions.
jlong *operand = (jlong*)(((long)adr)&((long)(~0xF)));
jlong *operand = (jlong*)(((intptr_t)adr) & ((intptr_t)(~0xF)));
// Store the value to a 128-bits operand.
operand[0] = lo;
operand[1] = hi;
@ -3113,7 +3113,6 @@ void LIR_Assembler::emit_arraycopy(LIR_OpArrayCopy* op) {
// reload the register args properly if we go slow path. Yuck
// These are proper for the calling convention
store_parameter(length, 2);
store_parameter(dst_pos, 1);
store_parameter(dst, 0);
@ -3351,12 +3350,15 @@ void LIR_Assembler::emit_arraycopy(LIR_OpArrayCopy* op) {
__ jcc(Assembler::notEqual, *stub->entry());
}
#ifndef _LP64
// save caller save registers
store_parameter(rax, 2);
store_parameter(rcx, 1);
store_parameter(rdx, 0);
// Spill because stubs can use any register they like and it's
// easier to restore just those that we care about.
store_parameter(dst, 0);
store_parameter(dst_pos, 1);
store_parameter(length, 2);
store_parameter(src_pos, 3);
store_parameter(src, 4);
#ifndef _LP64
__ movptr(tmp, dst_klass_addr);
__ movptr(tmp, Address(tmp, objArrayKlass::element_klass_offset_in_bytes() + sizeof(oopDesc)));
__ push(tmp);
@ -3372,17 +3374,6 @@ void LIR_Assembler::emit_arraycopy(LIR_OpArrayCopy* op) {
#else
__ movl2ptr(length, length); //higher 32bits must be null
// save caller save registers: copy them to callee save registers
__ mov(rbx, rdx);
__ mov(r13, r8);
__ mov(r14, r9);
#ifndef _WIN64
store_parameter(rsi, 1);
store_parameter(rcx, 0);
// on WIN64 other incoming parameters are in rdi and rsi saved
// across the call
#endif
__ lea(c_rarg0, Address(src, src_pos, scale, arrayOopDesc::base_offset_in_bytes(basic_type)));
assert_different_registers(c_rarg0, dst, dst_pos, length);
__ lea(c_rarg1, Address(dst, dst_pos, scale, arrayOopDesc::base_offset_in_bytes(basic_type)));
@ -3432,25 +3423,13 @@ void LIR_Assembler::emit_arraycopy(LIR_OpArrayCopy* op) {
__ xorl(tmp, -1);
#ifndef _LP64
// restore caller save registers
assert_different_registers(tmp, rdx, rcx, rax); // result of stub will be lost
__ movptr(rdx, Address(rsp, 0*BytesPerWord));
__ movptr(rcx, Address(rsp, 1*BytesPerWord));
__ movptr(rax, Address(rsp, 2*BytesPerWord));
#else
// restore caller save registers
__ mov(rdx, rbx);
__ mov(r8, r13);
__ mov(r9, r14);
#ifndef _WIN64
assert_different_registers(tmp, rdx, r8, r9, rcx, rsi); // result of stub will be lost
__ movptr(rcx, Address(rsp, 0*BytesPerWord));
__ movptr(rsi, Address(rsp, 1*BytesPerWord));
#else
assert_different_registers(tmp, rdx, r8, r9); // result of stub will be lost
#endif
#endif
// Restore previously spilled arguments
__ movptr (dst, Address(rsp, 0*BytesPerWord));
__ movptr (dst_pos, Address(rsp, 1*BytesPerWord));
__ movptr (length, Address(rsp, 2*BytesPerWord));
__ movptr (src_pos, Address(rsp, 3*BytesPerWord));
__ movptr (src, Address(rsp, 4*BytesPerWord));
__ subl(length, tmp);
__ addl(src_pos, tmp);

View File

@ -45,6 +45,7 @@ inline frame::frame(intptr_t* sp, intptr_t* fp, address pc) {
_pc = pc;
assert(pc != NULL, "no pc?");
_cb = CodeCache::find_blob(pc);
adjust_unextended_sp();
address original_pc = nmethod::get_deopt_original_pc(this);
if (original_pc != NULL) {
@ -92,6 +93,7 @@ inline frame::frame(intptr_t* sp, intptr_t* fp) {
// assert(_pc != NULL, "no pc?");
_cb = CodeCache::find_blob(_pc);
adjust_unextended_sp();
address original_pc = nmethod::get_deopt_original_pc(this);
if (original_pc != NULL) {

View File

@ -43,8 +43,8 @@ class ICache : public AbstractICache {
#ifdef AMD64
enum {
stub_size = 64, // Size of the icache flush stub in bytes
line_size = 32, // Icache line size in bytes
log2_line_size = 5 // log2(line_size)
line_size = 64, // Icache line size in bytes
log2_line_size = 6 // log2(line_size)
};
// Use default implementation

View File

@ -403,9 +403,9 @@ void InterpreterMacroAssembler::jump_from_interpreted(Register method, Register
// interp_only_mode if these events CAN be enabled.
get_thread(temp);
// interp_only is an int, on little endian it is sufficient to test the byte only
// Is a cmpl faster (ce
// Is a cmpl faster?
cmpb(Address(temp, JavaThread::interp_only_mode_offset()), 0);
jcc(Assembler::zero, run_compiled_code);
jccb(Assembler::zero, run_compiled_code);
jmp(Address(method, methodOopDesc::interpreter_entry_offset()));
bind(run_compiled_code);
}

View File

@ -402,7 +402,7 @@ void InterpreterMacroAssembler::jump_from_interpreted(Register method, Register
// interp_only is an int, on little endian it is sufficient to test the byte only
// Is a cmpl faster?
cmpb(Address(r15_thread, JavaThread::interp_only_mode_offset()), 0);
jcc(Assembler::zero, run_compiled_code);
jccb(Assembler::zero, run_compiled_code);
jmp(Address(method, methodOopDesc::interpreter_entry_offset()));
bind(run_compiled_code);
}

View File

@ -24,6 +24,7 @@
#include "precompiled.hpp"
#include "interpreter/interpreter.hpp"
#include "interpreter/interpreterRuntime.hpp"
#include "memory/allocation.inline.hpp"
#include "prims/methodHandles.hpp"
@ -37,6 +38,11 @@
#define BIND(label) bind(label); BLOCK_COMMENT(#label ":")
// Workaround for C++ overloading nastiness on '0' for RegisterOrConstant.
static RegisterOrConstant constant(int value) {
return RegisterOrConstant(value);
}
address MethodHandleEntry::start_compiled_entry(MacroAssembler* _masm,
address interpreted_entry) {
// Just before the actual machine code entry point, allocate space
@ -139,9 +145,9 @@ oop MethodHandles::RicochetFrame::compute_saved_args_layout(bool read_cache, boo
void MethodHandles::RicochetFrame::generate_ricochet_blob(MacroAssembler* _masm,
// output params:
int* frame_size_in_words,
int* bounce_offset,
int* exception_offset) {
int* exception_offset,
int* frame_size_in_words) {
(*frame_size_in_words) = RicochetFrame::frame_size_in_bytes() / wordSize;
address start = __ pc();
@ -366,7 +372,7 @@ void MethodHandles::load_stack_move(MacroAssembler* _masm,
Register rdi_stack_move,
Register rcx_amh,
bool might_be_negative) {
BLOCK_COMMENT("load_stack_move");
BLOCK_COMMENT("load_stack_move {");
Address rcx_amh_conversion(rcx_amh, java_lang_invoke_AdapterMethodHandle::conversion_offset_in_bytes());
__ movl(rdi_stack_move, rcx_amh_conversion);
__ sarl(rdi_stack_move, CONV_STACK_MOVE_SHIFT);
@ -387,9 +393,10 @@ void MethodHandles::load_stack_move(MacroAssembler* _masm,
__ stop("load_stack_move of garbage value");
__ BIND(L_ok);
}
BLOCK_COMMENT("} load_stack_move");
}
#ifndef PRODUCT
#ifdef ASSERT
void MethodHandles::RicochetFrame::verify_offsets() {
// Check compatibility of this struct with the more generally used offsets of class frame:
int ebp_off = sender_link_offset_in_bytes(); // offset from struct base to local rbp value
@ -539,6 +546,28 @@ void MethodHandles::verify_klass(MacroAssembler* _masm,
}
#endif //ASSERT
void MethodHandles::jump_from_method_handle(MacroAssembler* _masm, Register method, Register temp) {
if (JvmtiExport::can_post_interpreter_events()) {
Label run_compiled_code;
// JVMTI events, such as single-stepping, are implemented partly by avoiding running
// compiled code in threads for which the event is enabled. Check here for
// interp_only_mode if these events CAN be enabled.
#ifdef _LP64
Register rthread = r15_thread;
#else
Register rthread = temp;
__ get_thread(rthread);
#endif
// interp_only is an int, on little endian it is sufficient to test the byte only
// Is a cmpl faster?
__ cmpb(Address(rthread, JavaThread::interp_only_mode_offset()), 0);
__ jccb(Assembler::zero, run_compiled_code);
__ jmp(Address(method, methodOopDesc::interpreter_entry_offset()));
__ bind(run_compiled_code);
}
__ jmp(Address(method, methodOopDesc::from_interpreted_offset()));
}
// Code generation
address MethodHandles::generate_method_handle_interpreter_entry(MacroAssembler* _masm) {
// rbx: methodOop
@ -555,13 +584,11 @@ address MethodHandles::generate_method_handle_interpreter_entry(MacroAssembler*
// emit WrongMethodType path first, to enable jccb back-branch from main path
Label wrong_method_type;
__ bind(wrong_method_type);
Label invoke_generic_slow_path;
Label invoke_generic_slow_path, invoke_exact_error_path;
assert(methodOopDesc::intrinsic_id_size_in_bytes() == sizeof(u1), "");;
__ cmpb(Address(rbx_method, methodOopDesc::intrinsic_id_offset_in_bytes()), (int) vmIntrinsics::_invokeExact);
__ jcc(Assembler::notEqual, invoke_generic_slow_path);
__ push(rax_mtype); // required mtype
__ push(rcx_recv); // bad mh (1st stacked argument)
__ jump(ExternalAddress(Interpreter::throw_WrongMethodType_entry()));
__ jmp(invoke_exact_error_path);
// here's where control starts out:
__ align(CodeEntryAlignment);
@ -595,6 +622,11 @@ address MethodHandles::generate_method_handle_interpreter_entry(MacroAssembler*
__ jump_to_method_handle_entry(rcx_recv, rdi_temp);
// error path for invokeExact (only)
__ bind(invoke_exact_error_path);
// Stub wants expected type in rax and the actual type in rcx
__ jump(ExternalAddress(StubRoutines::throw_WrongMethodTypeException_entry()));
// for invokeGeneric (only), apply argument and result conversions on the fly
__ bind(invoke_generic_slow_path);
#ifdef ASSERT
@ -632,11 +664,6 @@ address MethodHandles::generate_method_handle_interpreter_entry(MacroAssembler*
return entry_point;
}
// Workaround for C++ overloading nastiness on '0' for RegisterOrConstant.
static RegisterOrConstant constant(int value) {
return RegisterOrConstant(value);
}
// Helper to insert argument slots into the stack.
// arg_slots must be a multiple of stack_move_unit() and < 0
// rax_argslot is decremented to point to the new (shifted) location of the argslot
@ -1115,9 +1142,6 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan
guarantee(java_lang_invoke_MethodHandle::vmentry_offset_in_bytes() != 0, "must have offsets");
// some handy addresses
Address rbx_method_fie( rbx, methodOopDesc::from_interpreted_offset() );
Address rbx_method_fce( rbx, methodOopDesc::from_compiled_offset() );
Address rcx_mh_vmtarget( rcx_recv, java_lang_invoke_MethodHandle::vmtarget_offset_in_bytes() );
Address rcx_dmh_vmindex( rcx_recv, java_lang_invoke_DirectMethodHandle::vmindex_offset_in_bytes() );
@ -1147,7 +1171,7 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan
trace_method_handle(_masm, entry_name(ek));
BLOCK_COMMENT(entry_name(ek));
BLOCK_COMMENT(err_msg("Entry %s {", entry_name(ek)));
switch ((int) ek) {
case _raise_exception:
@ -1158,32 +1182,24 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan
assert(raise_exception_method(), "must be set");
assert(raise_exception_method()->from_compiled_entry(), "method must be linked");
const Register rdi_pc = rax;
__ pop(rdi_pc); // caller PC
const Register rax_pc = rax;
__ pop(rax_pc); // caller PC
__ mov(rsp, saved_last_sp); // cut the stack back to where the caller started
Register rbx_method = rbx_temp;
Label L_no_method;
// FIXME: fill in _raise_exception_method with a suitable java.lang.invoke method
__ movptr(rbx_method, ExternalAddress((address) &_raise_exception_method));
__ testptr(rbx_method, rbx_method);
__ jccb(Assembler::zero, L_no_method);
const int jobject_oop_offset = 0;
__ movptr(rbx_method, Address(rbx_method, jobject_oop_offset)); // dereference the jobject
__ testptr(rbx_method, rbx_method);
__ jccb(Assembler::zero, L_no_method);
__ verify_oop(rbx_method);
NOT_LP64(__ push(rarg2_required));
__ push(rdi_pc); // restore caller PC
__ jmp(rbx_method_fce); // jump to compiled entry
__ movptr(rsi, rsp);
__ subptr(rsp, 3 * wordSize);
__ push(rax_pc); // restore caller PC
// Do something that is at least causes a valid throw from the interpreter.
__ bind(L_no_method);
__ push(rarg2_required);
__ push(rarg1_actual);
__ jump(ExternalAddress(Interpreter::throw_WrongMethodType_entry()));
__ movptr(__ argument_address(constant(2)), rarg0_code);
__ movptr(__ argument_address(constant(1)), rarg1_actual);
__ movptr(__ argument_address(constant(0)), rarg2_required);
jump_from_method_handle(_masm, rbx_method, rax);
}
break;
@ -1202,7 +1218,7 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan
__ null_check(rcx_recv);
__ verify_oop(rcx_recv);
}
__ jmp(rbx_method_fie);
jump_from_method_handle(_masm, rbx_method, rax);
}
break;
@ -1235,7 +1251,7 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan
__ movptr(rbx_method, vtable_entry_addr);
__ verify_oop(rbx_method);
__ jmp(rbx_method_fie);
jump_from_method_handle(_masm, rbx_method, rax);
}
break;
@ -1270,7 +1286,7 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan
no_such_interface);
__ verify_oop(rbx_method);
__ jmp(rbx_method_fie);
jump_from_method_handle(_masm, rbx_method, rax);
__ hlt();
__ bind(no_such_interface);
@ -1292,7 +1308,7 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan
case _bound_int_direct_mh:
case _bound_long_direct_mh:
{
bool direct_to_method = (ek >= _bound_ref_direct_mh);
const bool direct_to_method = (ek >= _bound_ref_direct_mh);
BasicType arg_type = ek_bound_mh_arg_type(ek);
int arg_slots = type2size[arg_type];
@ -1318,7 +1334,7 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan
Register rbx_method = rbx_temp;
__ load_heap_oop(rbx_method, rcx_mh_vmtarget);
__ verify_oop(rbx_method);
__ jmp(rbx_method_fie);
jump_from_method_handle(_masm, rbx_method, rax);
} else {
__ load_heap_oop(rcx_recv, rcx_mh_vmtarget);
__ verify_oop(rcx_recv);
@ -1632,14 +1648,16 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan
// rax = src_addr + swap_bytes
// rbx = dest_addr
// while (rax <= rbx) *(rax - swap_bytes) = *(rax + 0), rax++;
__ addptr(rbx_destslot, wordSize);
// dest_slot denotes an exclusive upper limit
int limit_bias = OP_ROT_ARGS_DOWN_LIMIT_BIAS;
if (limit_bias != 0)
__ addptr(rbx_destslot, - limit_bias * wordSize);
move_arg_slots_down(_masm,
Address(rax_argslot, swap_slots * wordSize),
rbx_destslot,
-swap_slots,
rax_argslot, rdx_temp);
__ subptr(rbx_destslot, wordSize);
__ subptr(rbx_destslot, swap_slots * wordSize);
}
// pop the original first chunk into the destination slot, now free
for (int i = 0; i < swap_slots; i++) {
@ -1929,7 +1947,7 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan
// In the non-retaining case, this might move keep2 either up or down.
// We don't have to copy the whole | RF... collect | complex,
// but we must adjust RF.saved_args_base.
// Also, from now on, we will forget about the origial copy of |collect|.
// Also, from now on, we will forget about the original copy of |collect|.
// If we are retaining it, we will treat it as part of |keep2|.
// For clarity we will define |keep3| = |collect|keep2| or |keep2|.
@ -1986,7 +2004,7 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan
// Net shift (&new_argv - &old_argv) is (close_count - open_count).
bool zero_open_count = (open_count == 0); // remember this bit of info
if (move_keep3 && fix_arg_base) {
// It will be easier t have everything in one register:
// It will be easier to have everything in one register:
if (close_count.is_register()) {
// Deduct open_count from close_count register to get a clean +/- value.
__ subptr(close_count.as_register(), open_count);
@ -2396,6 +2414,7 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan
__ nop();
return;
}
BLOCK_COMMENT(err_msg("} Entry %s", entry_name(ek)));
__ hlt();
address me_cookie = MethodHandleEntry::start_compiled_entry(_masm, interp_entry);

View File

@ -25,6 +25,11 @@
// Platform-specific definitions for method handles.
// These definitions are inlined into class MethodHandles.
// Adapters
enum /* platform_dependent_constants */ {
adapter_code_size = NOT_LP64(30000 DEBUG_ONLY(+ 10000)) LP64_ONLY(80000 DEBUG_ONLY(+ 120000))
};
public:
// The stack just after the recursive call from a ricochet frame
@ -188,7 +193,9 @@ class RicochetFrame {
static void generate_ricochet_blob(MacroAssembler* _masm,
// output params:
int* frame_size_in_words, int* bounce_offset, int* exception_offset);
int* bounce_offset,
int* exception_offset,
int* frame_size_in_words);
static void enter_ricochet_frame(MacroAssembler* _masm,
Register rcx_recv,
@ -284,6 +291,10 @@ public:
"reference is a MH");
}
// Similar to InterpreterMacroAssembler::jump_from_interpreted.
// Takes care of special dispatch from single stepping too.
static void jump_from_method_handle(MacroAssembler* _masm, Register method, Register temp);
static void trace_method_handle(MacroAssembler* _masm, const char* adaptername) PRODUCT_RETURN;
static Register saved_last_sp_register() {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1998, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -42,8 +42,6 @@
#define __ masm->
ExceptionBlob* OptoRuntime::_exception_blob;
//------------------------------generate_exception_blob---------------------------
// creates exception blob at the end
// Using exception blob, this code is jumped from a compiled method.

View File

@ -42,18 +42,6 @@
#endif
#define __ masm->
#ifdef COMPILER2
UncommonTrapBlob *SharedRuntime::_uncommon_trap_blob;
#endif // COMPILER2
DeoptimizationBlob *SharedRuntime::_deopt_blob;
SafepointBlob *SharedRuntime::_polling_page_safepoint_handler_blob;
SafepointBlob *SharedRuntime::_polling_page_return_handler_blob;
RuntimeStub* SharedRuntime::_wrong_method_blob;
RuntimeStub* SharedRuntime::_ic_miss_blob;
RuntimeStub* SharedRuntime::_resolve_opt_virtual_call_blob;
RuntimeStub* SharedRuntime::_resolve_virtual_call_blob;
RuntimeStub* SharedRuntime::_resolve_static_call_blob;
const int StackAlignmentInSlots = StackAlignmentInBytes / VMRegImpl::stack_slot_size;
@ -2253,31 +2241,6 @@ uint SharedRuntime::out_preserve_stack_slots() {
return 0;
}
//----------------------------generate_ricochet_blob---------------------------
void SharedRuntime::generate_ricochet_blob() {
if (!EnableInvokeDynamic) return; // leave it as a null
// allocate space for the code
ResourceMark rm;
// setup code generation tools
CodeBuffer buffer("ricochet_blob", 256, 256);
MacroAssembler* masm = new MacroAssembler(&buffer);
int frame_size_in_words = -1, bounce_offset = -1, exception_offset = -1;
MethodHandles::RicochetFrame::generate_ricochet_blob(masm, &frame_size_in_words, &bounce_offset, &exception_offset);
// -------------
// make sure all code is generated
masm->flush();
// failed to generate?
if (frame_size_in_words < 0 || bounce_offset < 0 || exception_offset < 0) {
assert(false, "bad ricochet blob");
return;
}
_ricochet_blob = RicochetBlob::create(&buffer, bounce_offset, exception_offset, frame_size_in_words);
}
//------------------------------generate_deopt_blob----------------------------
void SharedRuntime::generate_deopt_blob() {
@ -2816,7 +2779,7 @@ void SharedRuntime::generate_uncommon_trap_blob() {
// setup oopmap, and calls safepoint code to stop the compiled code for
// a safepoint.
//
static SafepointBlob* generate_handler_blob(address call_ptr, bool cause_return) {
SafepointBlob* SharedRuntime::generate_handler_blob(address call_ptr, bool cause_return) {
// Account for thread arg in our frame
const int additional_words = 1;
@ -2913,7 +2876,7 @@ static SafepointBlob* generate_handler_blob(address call_ptr, bool cause_return)
// but since this is generic code we don't know what they are and the caller
// must do any gc of the args.
//
static RuntimeStub* generate_resolve_blob(address destination, const char* name) {
RuntimeStub* SharedRuntime::generate_resolve_blob(address destination, const char* name) {
assert (StubRoutines::forward_exception_entry() != NULL, "must be generated before");
// allocate space for the code
@ -2995,36 +2958,3 @@ static RuntimeStub* generate_resolve_blob(address destination, const char* name)
// frame_size_words or bytes??
return RuntimeStub::new_runtime_stub(name, &buffer, frame_complete, frame_size_words, oop_maps, true);
}
void SharedRuntime::generate_stubs() {
_wrong_method_blob = generate_resolve_blob(CAST_FROM_FN_PTR(address, SharedRuntime::handle_wrong_method),
"wrong_method_stub");
_ic_miss_blob = generate_resolve_blob(CAST_FROM_FN_PTR(address, SharedRuntime::handle_wrong_method_ic_miss),
"ic_miss_stub");
_resolve_opt_virtual_call_blob = generate_resolve_blob(CAST_FROM_FN_PTR(address, SharedRuntime::resolve_opt_virtual_call_C),
"resolve_opt_virtual_call");
_resolve_virtual_call_blob = generate_resolve_blob(CAST_FROM_FN_PTR(address, SharedRuntime::resolve_virtual_call_C),
"resolve_virtual_call");
_resolve_static_call_blob = generate_resolve_blob(CAST_FROM_FN_PTR(address, SharedRuntime::resolve_static_call_C),
"resolve_static_call");
_polling_page_safepoint_handler_blob =
generate_handler_blob(CAST_FROM_FN_PTR(address,
SafepointSynchronize::handle_polling_page_exception), false);
_polling_page_return_handler_blob =
generate_handler_blob(CAST_FROM_FN_PTR(address,
SafepointSynchronize::handle_polling_page_exception), true);
generate_ricochet_blob();
generate_deopt_blob();
#ifdef COMPILER2
generate_uncommon_trap_blob();
#endif // COMPILER2
}

View File

@ -41,24 +41,10 @@
#include "opto/runtime.hpp"
#endif
DeoptimizationBlob *SharedRuntime::_deopt_blob;
#ifdef COMPILER2
UncommonTrapBlob *SharedRuntime::_uncommon_trap_blob;
ExceptionBlob *OptoRuntime::_exception_blob;
#endif // COMPILER2
SafepointBlob *SharedRuntime::_polling_page_safepoint_handler_blob;
SafepointBlob *SharedRuntime::_polling_page_return_handler_blob;
RuntimeStub* SharedRuntime::_wrong_method_blob;
RuntimeStub* SharedRuntime::_ic_miss_blob;
RuntimeStub* SharedRuntime::_resolve_opt_virtual_call_blob;
RuntimeStub* SharedRuntime::_resolve_virtual_call_blob;
RuntimeStub* SharedRuntime::_resolve_static_call_blob;
#define __ masm->
const int StackAlignmentInSlots = StackAlignmentInBytes / VMRegImpl::stack_slot_size;
#define __ masm->
class SimpleRuntimeFrame {
public:
@ -2530,32 +2516,6 @@ uint SharedRuntime::out_preserve_stack_slots() {
}
//----------------------------generate_ricochet_blob---------------------------
void SharedRuntime::generate_ricochet_blob() {
if (!EnableInvokeDynamic) return; // leave it as a null
// allocate space for the code
ResourceMark rm;
// setup code generation tools
CodeBuffer buffer("ricochet_blob", 512, 512);
MacroAssembler* masm = new MacroAssembler(&buffer);
int frame_size_in_words = -1, bounce_offset = -1, exception_offset = -1;
MethodHandles::RicochetFrame::generate_ricochet_blob(masm, &frame_size_in_words, &bounce_offset, &exception_offset);
// -------------
// make sure all code is generated
masm->flush();
// failed to generate?
if (frame_size_in_words < 0 || bounce_offset < 0 || exception_offset < 0) {
assert(false, "bad ricochet blob");
return;
}
_ricochet_blob = RicochetBlob::create(&buffer, bounce_offset, exception_offset, frame_size_in_words);
}
//------------------------------generate_deopt_blob----------------------------
void SharedRuntime::generate_deopt_blob() {
// Allocate space for the code
@ -3046,7 +3006,7 @@ void SharedRuntime::generate_uncommon_trap_blob() {
// Generate a special Compile2Runtime blob that saves all registers,
// and setup oopmap.
//
static SafepointBlob* generate_handler_blob(address call_ptr, bool cause_return) {
SafepointBlob* SharedRuntime::generate_handler_blob(address call_ptr, bool cause_return) {
assert(StubRoutines::forward_exception_entry() != NULL,
"must be generated before");
@ -3132,7 +3092,7 @@ static SafepointBlob* generate_handler_blob(address call_ptr, bool cause_return)
// but since this is generic code we don't know what they are and the caller
// must do any gc of the args.
//
static RuntimeStub* generate_resolve_blob(address destination, const char* name) {
RuntimeStub* SharedRuntime::generate_resolve_blob(address destination, const char* name) {
assert (StubRoutines::forward_exception_entry() != NULL, "must be generated before");
// allocate space for the code
@ -3209,38 +3169,6 @@ static RuntimeStub* generate_resolve_blob(address destination, const char* name)
}
void SharedRuntime::generate_stubs() {
_wrong_method_blob = generate_resolve_blob(CAST_FROM_FN_PTR(address, SharedRuntime::handle_wrong_method),
"wrong_method_stub");
_ic_miss_blob = generate_resolve_blob(CAST_FROM_FN_PTR(address, SharedRuntime::handle_wrong_method_ic_miss),
"ic_miss_stub");
_resolve_opt_virtual_call_blob = generate_resolve_blob(CAST_FROM_FN_PTR(address, SharedRuntime::resolve_opt_virtual_call_C),
"resolve_opt_virtual_call");
_resolve_virtual_call_blob = generate_resolve_blob(CAST_FROM_FN_PTR(address, SharedRuntime::resolve_virtual_call_C),
"resolve_virtual_call");
_resolve_static_call_blob = generate_resolve_blob(CAST_FROM_FN_PTR(address, SharedRuntime::resolve_static_call_C),
"resolve_static_call");
_polling_page_safepoint_handler_blob =
generate_handler_blob(CAST_FROM_FN_PTR(address,
SafepointSynchronize::handle_polling_page_exception), false);
_polling_page_return_handler_blob =
generate_handler_blob(CAST_FROM_FN_PTR(address,
SafepointSynchronize::handle_polling_page_exception), true);
generate_ricochet_blob();
generate_deopt_blob();
#ifdef COMPILER2
generate_uncommon_trap_blob();
#endif // COMPILER2
}
#ifdef COMPILER2
// This is here instead of runtime_x86_64.cpp because it uses SimpleRuntimeFrame
//

View File

@ -2151,6 +2151,8 @@ class StubGenerator: public StubCodeGenerator {
// if they expect all registers to be preserved.
enum layout {
thread_off, // last_java_sp
arg1_off,
arg2_off,
rbp_off, // callee saved register
ret_pc,
framesize
@ -2185,7 +2187,7 @@ class StubGenerator: public StubCodeGenerator {
// either at call sites or otherwise assume that stack unwinding will be initiated,
// so caller saved registers were assumed volatile in the compiler.
address generate_throw_exception(const char* name, address runtime_entry,
bool restore_saved_exception_pc) {
bool restore_saved_exception_pc, Register arg1 = noreg, Register arg2 = noreg) {
int insts_size = 256;
int locs_size = 32;
@ -2218,6 +2220,13 @@ class StubGenerator: public StubCodeGenerator {
// push java thread (becomes first argument of C function)
__ movptr(Address(rsp, thread_off * wordSize), java_thread);
if (arg1 != noreg) {
__ movptr(Address(rsp, arg1_off * wordSize), arg1);
}
if (arg2 != noreg) {
assert(arg1 != noreg, "missing reg arg");
__ movptr(Address(rsp, arg2_off * wordSize), arg2);
}
// Set up last_Java_sp and last_Java_fp
__ set_last_Java_frame(java_thread, rsp, rbp, NULL);
@ -2309,6 +2318,12 @@ class StubGenerator: public StubCodeGenerator {
CAST_FROM_FN_PTR(address, SharedRuntime::d2i));
StubRoutines::_d2l_wrapper = generate_d2i_wrapper(T_LONG,
CAST_FROM_FN_PTR(address, SharedRuntime::d2l));
// Build this early so it's available for the interpreter
StubRoutines::_throw_WrongMethodTypeException_entry =
generate_throw_exception("WrongMethodTypeException throw_exception",
CAST_FROM_FN_PTR(address, SharedRuntime::throw_WrongMethodTypeException),
false, rax, rcx);
}

View File

@ -2934,7 +2934,9 @@ class StubGenerator: public StubCodeGenerator {
// caller saved registers were assumed volatile in the compiler.
address generate_throw_exception(const char* name,
address runtime_entry,
bool restore_saved_exception_pc) {
bool restore_saved_exception_pc,
Register arg1 = noreg,
Register arg2 = noreg) {
// Information about frame layout at time of blocking runtime call.
// Note that we only have to preserve callee-saved registers since
// the compilers are responsible for supplying a continuation point
@ -2980,6 +2982,13 @@ class StubGenerator: public StubCodeGenerator {
__ set_last_Java_frame(rsp, rbp, NULL);
// Call runtime
if (arg1 != noreg) {
assert(arg2 != c_rarg1, "clobbered");
__ movptr(c_rarg1, arg1);
}
if (arg2 != noreg) {
__ movptr(c_rarg2, arg2);
}
__ movptr(c_rarg0, r15_thread);
BLOCK_COMMENT("call runtime_entry");
__ call(RuntimeAddress(runtime_entry));
@ -3052,6 +3061,14 @@ class StubGenerator: public StubCodeGenerator {
StubRoutines::x86::_get_previous_fp_entry = generate_get_previous_fp();
StubRoutines::x86::_verify_mxcsr_entry = generate_verify_mxcsr();
// Build this early so it's available for the interpreter. Stub
// expects the required and actual types as register arguments in
// j_rarg0 and j_rarg1 respectively.
StubRoutines::_throw_WrongMethodTypeException_entry =
generate_throw_exception("WrongMethodTypeException throw_exception",
CAST_FROM_FN_PTR(address, SharedRuntime::throw_WrongMethodTypeException),
false, rax, rcx);
}
void generate_all() {

View File

@ -34,11 +34,6 @@ enum platform_dependent_constants {
code_size2 = 22000 // simply increase if too small (assembler will crash if too small)
};
// MethodHandles adapters
enum method_handles_platform_dependent_constants {
method_handles_adapters_code_size = 30000 DEBUG_ONLY(+ 10000)
};
class x86 {
friend class StubGenerator;
friend class VMStructs;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -36,11 +36,6 @@ enum platform_dependent_constants {
code_size2 = 22000 // simply increase if too small (assembler will crash if too small)
};
// MethodHandles adapters
enum method_handles_platform_dependent_constants {
method_handles_adapters_code_size = 80000 DEBUG_ONLY(+ 120000)
};
class x86 {
friend class StubGenerator;

View File

@ -112,32 +112,6 @@ address TemplateInterpreterGenerator::generate_ClassCastException_handler() {
return entry;
}
// Arguments are: required type at TOS+4, failing object (or NULL) at TOS.
address TemplateInterpreterGenerator::generate_WrongMethodType_handler() {
address entry = __ pc();
__ pop(rbx); // actual failing object is at TOS
__ pop(rax); // required type is at TOS+4
__ verify_oop(rbx);
__ verify_oop(rax);
// Various method handle types use interpreter registers as temps.
__ restore_bcp();
__ restore_locals();
// Expression stack must be empty before entering the VM for an exception.
__ empty_expression_stack();
__ empty_FPU_stack();
__ call_VM(noreg,
CAST_FROM_FN_PTR(address,
InterpreterRuntime::throw_WrongMethodTypeException),
// pass required type, failing object (or NULL)
rax, rbx);
return entry;
}
address TemplateInterpreterGenerator::generate_exception_handler_common(const char* name, const char* message, bool pass_oop) {
assert(!pass_oop || message == NULL, "either oop or message but not both");
address entry = __ pc();

View File

@ -120,31 +120,6 @@ address TemplateInterpreterGenerator::generate_ClassCastException_handler() {
return entry;
}
// Arguments are: required type at TOS+8, failing object (or NULL) at TOS+4.
address TemplateInterpreterGenerator::generate_WrongMethodType_handler() {
address entry = __ pc();
__ pop(c_rarg2); // failing object is at TOS
__ pop(c_rarg1); // required type is at TOS+8
__ verify_oop(c_rarg1);
__ verify_oop(c_rarg2);
// Various method handle types use interpreter registers as temps.
__ restore_bcp();
__ restore_locals();
// Expression stack must be empty before entering the VM for an exception.
__ empty_expression_stack();
__ call_VM(noreg,
CAST_FROM_FN_PTR(address,
InterpreterRuntime::throw_WrongMethodTypeException),
// pass required type, failing object (or NULL)
c_rarg1, c_rarg2);
return entry;
}
address TemplateInterpreterGenerator::generate_exception_handler_common(
const char* name, const char* message, bool pass_oop) {
assert(!pass_oop || message == NULL, "either oop or message but not both");

View File

@ -373,15 +373,17 @@ void TemplateTable::ldc(bool wide) {
__ jcc(Assembler::equal, L);
__ cmpl(rdx, JVM_CONSTANT_String);
__ jcc(Assembler::equal, L);
__ cmpl(rdx, JVM_CONSTANT_Object);
__ jcc(Assembler::equal, L);
__ stop("unexpected tag type in ldc");
__ bind(L);
}
#endif
Label isOop;
// atos and itos
// String is only oop type we will see here
__ cmpl(rdx, JVM_CONSTANT_String);
__ jccb(Assembler::equal, isOop);
// Integer is only non-oop type we will see here
__ cmpl(rdx, JVM_CONSTANT_Integer);
__ jccb(Assembler::notEqual, isOop);
__ movl(rax, Address(rcx, rbx, Address::times_ptr, base_offset));
__ push(itos);
__ jmp(Done);

View File

@ -385,6 +385,8 @@ void TemplateTable::ldc(bool wide) {
__ jcc(Assembler::equal, L);
__ cmpl(rdx, JVM_CONSTANT_String);
__ jcc(Assembler::equal, L);
__ cmpl(rdx, JVM_CONSTANT_Object);
__ jcc(Assembler::equal, L);
__ stop("unexpected tag type in ldc");
__ bind(L);
}

View File

@ -321,6 +321,20 @@ void VM_Version::get_processor_features() {
if (UseSSE < 2) UseSSE = 2;
#endif
#ifdef AMD64
// flush_icache_stub have to be generated first.
// That is why Icache line size is hard coded in ICache class,
// see icache_x86.hpp. It is also the reason why we can't use
// clflush instruction in 32-bit VM since it could be running
// on CPU which does not support it.
//
// The only thing we can do is to verify that flushed
// ICache::line_size has correct value.
guarantee(_cpuid_info.std_cpuid1_edx.bits.clflush != 0, "clflush is not supported");
// clflush_size is size in quadwords (8 bytes).
guarantee(_cpuid_info.std_cpuid1_ebx.bits.clflush_size == 8, "such clflush size is not supported");
#endif
// If the OS doesn't support SSE, we can't use this feature even if the HW does
if (!os::supports_sse())
_cpuFeatures &= ~(CPU_SSE|CPU_SSE2|CPU_SSE3|CPU_SSSE3|CPU_SSE4A|CPU_SSE4_1|CPU_SSE4_2);

View File

@ -91,7 +91,9 @@ public:
cmpxchg8 : 1,
: 6,
cmov : 1,
: 7,
: 3,
clflush : 1,
: 3,
mmx : 1,
fxsr : 1,
sse : 1,

View File

@ -830,6 +830,17 @@ void encode_CopyXD( CodeBuffer &cbuf, int dst_encoding, int src_encoding ) {
}
}
// This could be in MacroAssembler but it's fairly C2 specific
void emit_cmpfp_fixup(MacroAssembler& _masm) {
Label exit;
__ jccb(Assembler::noParity, exit);
__ pushf();
__ andq(Address(rsp, 0), 0xffffff2b);
__ popf();
__ bind(exit);
__ nop(); // (target for branch to avoid branch to branch)
}
//=============================================================================
const bool Matcher::constant_table_absolute_addressing = true;
@ -2173,27 +2184,9 @@ encode %{
emit_rm(cbuf, 0x3, $dst$$reg & 7, $src$$reg & 7);
%}
enc_class cmpfp_fixup()
%{
// jnp,s exit
emit_opcode(cbuf, 0x7B);
emit_d8(cbuf, 0x0A);
// pushfq
emit_opcode(cbuf, 0x9C);
// andq $0xffffff2b, (%rsp)
emit_opcode(cbuf, Assembler::REX_W);
emit_opcode(cbuf, 0x81);
emit_opcode(cbuf, 0x24);
emit_opcode(cbuf, 0x24);
emit_d32(cbuf, 0xffffff2b);
// popfq
emit_opcode(cbuf, 0x9D);
// nop (target for branch to avoid branch to branch)
emit_opcode(cbuf, 0x90);
enc_class cmpfp_fixup() %{
MacroAssembler _masm(&cbuf);
emit_cmpfp_fixup(_masm);
%}
enc_class cmpfp3(rRegI dst)
@ -3179,50 +3172,6 @@ encode %{
emit_rm(cbuf, 0x3, 0x0, dstenc);
%}
enc_class enc_cmpLTP(no_rcx_RegI p, no_rcx_RegI q, no_rcx_RegI y,
rcx_RegI tmp)
%{
// cadd_cmpLT
int tmpReg = $tmp$$reg;
int penc = $p$$reg;
int qenc = $q$$reg;
int yenc = $y$$reg;
// subl $p,$q
if (penc < 8) {
if (qenc >= 8) {
emit_opcode(cbuf, Assembler::REX_B);
}
} else {
if (qenc < 8) {
emit_opcode(cbuf, Assembler::REX_R);
} else {
emit_opcode(cbuf, Assembler::REX_RB);
}
}
emit_opcode(cbuf, 0x2B);
emit_rm(cbuf, 0x3, penc & 7, qenc & 7);
// sbbl $tmp, $tmp
emit_opcode(cbuf, 0x1B);
emit_rm(cbuf, 0x3, tmpReg, tmpReg);
// andl $tmp, $y
if (yenc >= 8) {
emit_opcode(cbuf, Assembler::REX_B);
}
emit_opcode(cbuf, 0x23);
emit_rm(cbuf, 0x3, tmpReg, yenc & 7);
// addl $p,$tmp
if (penc >= 8) {
emit_opcode(cbuf, Assembler::REX_R);
}
emit_opcode(cbuf, 0x03);
emit_rm(cbuf, 0x3, penc & 7, tmpReg);
%}
// Compare the lonogs and set -1, 0, or 1 into dst
enc_class cmpl3_flag(rRegL src1, rRegL src2, rRegI dst)
@ -10206,9 +10155,7 @@ instruct cmpLTMask0(rRegI dst, immI0 zero, rFlagsReg cr)
%}
instruct cadd_cmpLTMask(rRegI p, rRegI q, rRegI y,
rRegI tmp,
rFlagsReg cr)
instruct cadd_cmpLTMask(rRegI p, rRegI q, rRegI y, rRegI tmp, rFlagsReg cr)
%{
match(Set p (AddI (AndI (CmpLTMask p q) y) (SubI p q)));
effect(TEMP tmp, KILL cr);
@ -10218,25 +10165,19 @@ instruct cadd_cmpLTMask(rRegI p, rRegI q, rRegI y,
"sbbl $tmp, $tmp\n\t"
"andl $tmp, $y\n\t"
"addl $p, $tmp" %}
ins_encode(enc_cmpLTP(p, q, y, tmp));
ins_encode %{
Register Rp = $p$$Register;
Register Rq = $q$$Register;
Register Ry = $y$$Register;
Register Rt = $tmp$$Register;
__ subl(Rp, Rq);
__ sbbl(Rt, Rt);
__ andl(Rt, Ry);
__ addl(Rp, Rt);
%}
ins_pipe(pipe_cmplt);
%}
/* If I enable this, I encourage spilling in the inner loop of compress.
instruct cadd_cmpLTMask_mem( rRegI p, rRegI q, memory y, rRegI tmp, rFlagsReg cr )
%{
match(Set p (AddI (AndI (CmpLTMask p q) (LoadI y)) (SubI p q)));
effect( TEMP tmp, KILL cr );
ins_cost(400);
format %{ "SUB $p,$q\n\t"
"SBB RCX,RCX\n\t"
"AND RCX,$y\n\t"
"ADD $p,RCX" %}
ins_encode( enc_cmpLTP_mem(p,q,y,tmp) );
%}
*/
//---------- FP Instructions------------------------------------------------
instruct cmpF_cc_reg(rFlagsRegU cr, regF src1, regF src2)
@ -10305,14 +10246,8 @@ instruct cmpF_cc_imm(rFlagsRegU cr, regF src, immF con) %{
"popfq\n"
"exit: nop\t# avoid branch to branch" %}
ins_encode %{
Label L_exit;
__ ucomiss($src$$XMMRegister, $constantaddress($con));
__ jcc(Assembler::noParity, L_exit);
__ pushf();
__ andq(rsp, 0xffffff2b);
__ popf();
__ bind(L_exit);
__ nop();
emit_cmpfp_fixup(_masm);
%}
ins_pipe(pipe_slow);
%}
@ -10393,14 +10328,8 @@ instruct cmpD_cc_imm(rFlagsRegU cr, regD src, immD con) %{
"popfq\n"
"exit: nop\t# avoid branch to branch" %}
ins_encode %{
Label L_exit;
__ ucomisd($src$$XMMRegister, $constantaddress($con));
__ jcc(Assembler::noParity, L_exit);
__ pushf();
__ andq(rsp, 0xffffff2b);
__ popf();
__ bind(L_exit);
__ nop();
emit_cmpfp_fixup(_masm);
%}
ins_pipe(pipe_slow);
%}

View File

@ -657,7 +657,7 @@ int CppInterpreter::method_handle_entry(methodOop method,
if (!is_exact) {
if (method->intrinsic_id() == vmIntrinsics::_invokeExact) {
CALL_VM_NOCHECK_NOFIX(
InterpreterRuntime::throw_WrongMethodTypeException(
SharedRuntime::throw_WrongMethodTypeException(
thread, method_type, mhtype));
// NB all oops trashed!
assert(HAS_PENDING_EXCEPTION, "should do");
@ -673,7 +673,7 @@ int CppInterpreter::method_handle_entry(methodOop method,
oop adapter = java_lang_invoke_MethodTypeForm::genericInvoker(form);
if (adapter == NULL) {
CALL_VM_NOCHECK_NOFIX(
InterpreterRuntime::throw_WrongMethodTypeException(
SharedRuntime::throw_WrongMethodTypeException(
thread, method_type, mhtype));
// NB all oops trashed!
assert(HAS_PENDING_EXCEPTION, "should do");

View File

@ -169,7 +169,35 @@ sigset_t SR_sigset;
/* Used to protect dlsym() calls */
static pthread_mutex_t dl_mutex;
////////////////////////////////////////////////////////////////////////////////
#ifdef JAVASE_EMBEDDED
class MemNotifyThread: public Thread {
friend class VMStructs;
public:
virtual void run();
private:
static MemNotifyThread* _memnotify_thread;
int _fd;
public:
// Constructor
MemNotifyThread(int fd);
// Tester
bool is_memnotify_thread() const { return true; }
// Printing
char* name() const { return (char*)"Linux MemNotify Thread"; }
// Returns the single instance of the MemNotifyThread
static MemNotifyThread* memnotify_thread() { return _memnotify_thread; }
// Create and start the single instance of MemNotifyThread
static void start();
};
#endif // JAVASE_EMBEDDED
// utility functions
static int SR_initialize();
@ -2085,6 +2113,14 @@ void os::print_os_info(outputStream* st) {
st->cr();
}
void os::pd_print_cpu_info(outputStream* st) {
st->print("\n/proc/cpuinfo:\n");
if (!_print_ascii_file("/proc/cpuinfo", st)) {
st->print(" <Not Available>");
}
st->cr();
}
void os::print_memory_info(outputStream* st) {
st->print("Memory:");
@ -4237,7 +4273,16 @@ jint os::init_2(void)
}
// this is called at the end of vm_initialization
void os::init_3(void) { }
void os::init_3(void)
{
#ifdef JAVASE_EMBEDDED
// Start the MemNotifyThread
if (LowMemoryProtection) {
MemNotifyThread::start();
}
return;
#endif
}
// Mark the polling page as unreadable
void os::make_polling_page_unreadable(void) {
@ -5360,3 +5405,78 @@ bool os::is_headless_jre() {
return true;
}
#ifdef JAVASE_EMBEDDED
//
// A thread to watch the '/dev/mem_notify' device, which will tell us when the OS is running low on memory.
//
MemNotifyThread* MemNotifyThread::_memnotify_thread = NULL;
// ctor
//
MemNotifyThread::MemNotifyThread(int fd): Thread() {
assert(memnotify_thread() == NULL, "we can only allocate one MemNotifyThread");
_fd = fd;
if (os::create_thread(this, os::os_thread)) {
_memnotify_thread = this;
os::set_priority(this, NearMaxPriority);
os::start_thread(this);
}
}
// Where all the work gets done
//
void MemNotifyThread::run() {
assert(this == memnotify_thread(), "expected the singleton MemNotifyThread");
// Set up the select arguments
fd_set rfds;
if (_fd != -1) {
FD_ZERO(&rfds);
FD_SET(_fd, &rfds);
}
// Now wait for the mem_notify device to wake up
while (1) {
// Wait for the mem_notify device to signal us..
int rc = select(_fd+1, _fd != -1 ? &rfds : NULL, NULL, NULL, NULL);
if (rc == -1) {
perror("select!\n");
break;
} else if (rc) {
//ssize_t free_before = os::available_memory();
//tty->print ("Notified: Free: %dK \n",os::available_memory()/1024);
// The kernel is telling us there is not much memory left...
// try to do something about that
// If we are not already in a GC, try one.
if (!Universe::heap()->is_gc_active()) {
Universe::heap()->collect(GCCause::_allocation_failure);
//ssize_t free_after = os::available_memory();
//tty->print ("Post-Notify: Free: %dK\n",free_after/1024);
//tty->print ("GC freed: %dK\n", (free_after - free_before)/1024);
}
// We might want to do something like the following if we find the GC's are not helping...
// Universe::heap()->size_policy()->set_gc_time_limit_exceeded(true);
}
}
}
//
// See if the /dev/mem_notify device exists, and if so, start a thread to monitor it.
//
void MemNotifyThread::start() {
int fd;
fd = open ("/dev/mem_notify", O_RDONLY, 0);
if (fd < 0) {
return;
}
if (memnotify_thread() == NULL) {
new MemNotifyThread(fd);
}
}
#endif // JAVASE_EMBEDDED

View File

@ -2317,6 +2317,10 @@ static bool check_addr0(outputStream* st) {
return status;
}
void os::pd_print_cpu_info(outputStream* st) {
// Nothing to do for now.
}
void os::print_memory_info(outputStream* st) {
st->print("Memory:");
st->print(" %dk page", os::vm_page_size()>>10);

View File

@ -1720,6 +1720,10 @@ void os::print_os_info(outputStream* st) {
st->cr();
}
void os::pd_print_cpu_info(outputStream* st) {
// Nothing to do for now.
}
void os::print_memory_info(outputStream* st) {
st->print("Memory:");
st->print(" %dk page", os::vm_page_size()>>10);

View File

@ -33,6 +33,28 @@ void MacroAssembler::int3() {
call(RuntimeAddress(CAST_FROM_FN_PTR(address, os::breakpoint)));
}
#ifdef MINIMIZE_RAM_USAGE
void MacroAssembler::get_thread(Register thread) {
// call pthread_getspecific
// void * pthread_getspecific(pthread_key_t key);
if (thread != rax) push(rax);
push(rcx);
push(rdx);
push(ThreadLocalStorage::thread_index());
call(RuntimeAddress(CAST_FROM_FN_PTR(address, pthread_getspecific)));
increment(rsp, wordSize);
pop(rdx);
pop(rcx);
if (thread != rax) {
mov(thread, rax);
pop(rax);
}
}
#else
void MacroAssembler::get_thread(Register thread) {
movl(thread, rsp);
shrl(thread, PAGE_SHIFT);
@ -43,6 +65,7 @@ void MacroAssembler::get_thread(Register thread) {
movptr(thread, tls);
}
#endif // MINIMIZE_RAM_USAGE
#else
void MacroAssembler::int3() {
call(RuntimeAddress(CAST_FROM_FN_PTR(address, os::breakpoint)));

View File

@ -52,25 +52,20 @@
// MADV_DONTNEED on Linux keeps the virtual memory mapping, but zaps the
// physical memory page (i.e. similar to MADV_FREE on Solaris).
#ifndef AMD64
#if !defined(AMD64) && !defined(MINIMIZE_RAM_USAGE)
Thread* ThreadLocalStorage::_sp_map[1UL << (SP_BITLENGTH - PAGE_SHIFT)];
#endif // !AMD64
void ThreadLocalStorage::generate_code_for_get_thread() {
// nothing we can do here for user-level thread
}
void ThreadLocalStorage::pd_init() {
#ifndef AMD64
assert(align_size_down(os::vm_page_size(), PAGE_SIZE) == os::vm_page_size(),
"page size must be multiple of PAGE_SIZE");
#endif // !AMD64
}
void ThreadLocalStorage::pd_set_thread(Thread* thread) {
os::thread_local_storage_at_put(ThreadLocalStorage::thread_index(), thread);
#ifndef AMD64
address stack_top = os::current_stack_base();
size_t stack_size = os::current_stack_size();
@ -88,5 +83,17 @@ void ThreadLocalStorage::pd_set_thread(Thread* thread) {
"thread exited without detaching from VM??");
_sp_map[(uintptr_t)p >> PAGE_SHIFT] = thread;
}
#endif // !AMD64
}
#else
void ThreadLocalStorage::generate_code_for_get_thread() {
// nothing we can do here for user-level thread
}
void ThreadLocalStorage::pd_init() {
}
void ThreadLocalStorage::pd_set_thread(Thread* thread) {
os::thread_local_storage_at_put(ThreadLocalStorage::thread_index(), thread);
}
#endif // !AMD64 && !MINIMIZE_RAM_USAGE

View File

@ -27,28 +27,32 @@
// Processor dependent parts of ThreadLocalStorage
#ifndef AMD64
#if !defined(AMD64) && !defined(MINIMIZE_RAM_USAGE)
// map stack pointer to thread pointer - see notes in threadLS_linux_x86.cpp
#define SP_BITLENGTH 32
#define PAGE_SHIFT 12
#define PAGE_SIZE (1UL << PAGE_SHIFT)
static Thread* _sp_map[1UL << (SP_BITLENGTH - PAGE_SHIFT)];
#endif // !AMD64
public:
#ifndef AMD64
static Thread** sp_map_addr() { return _sp_map; }
#endif // !AMD64
static Thread* thread() {
#ifdef AMD64
return (Thread*) os::thread_local_storage_at(thread_index());
#else
uintptr_t sp;
__asm__ volatile ("movl %%esp, %0" : "=r" (sp));
return _sp_map[sp >> PAGE_SHIFT];
#endif // AMD64
}
#else
public:
static Thread* thread() {
return (Thread*) os::thread_local_storage_at(thread_index());
}
#endif // AMD64 || MINIMIZE_RAM_USAGE
#endif // OS_CPU_LINUX_X86_VM_THREADLS_LINUX_X86_HPP

View File

@ -75,8 +75,16 @@ will build the Win32 cross compiled version of hsdis based on 2.19.1.
* Installing
Products are named like build/$OS-$LIBARCH/hsdis-$LIBARCH.so. You can
install them on your LD_LIBRARY_PATH, or inside of your JRE next to
$LIBARCH/libjvm.so.
install them on your LD_LIBRARY_PATH, or inside of your JRE/JDK. The
search path in the JVM is:
1. <home>/jre/lib/<arch>/<vm>/libhsdis-<arch>.so
2. <home>/jre/lib/<arch>/<vm>/hsdis-<arch>.so
3. <home>/jre/lib/<arch>/hsdis-<arch>.so
4. hsdis-<arch>.so (using LD_LIBRARY_PATH)
Note that there's a bug in hotspot versions prior to hs22 that causes
steps 2 and 3 to fail when used with JDK7.
Now test:

View File

@ -2812,6 +2812,13 @@ void ADLParser::ins_encode_parse_block(InstructForm& inst) {
params->add_entry(param);
}
// Check for duplicate ins_encode sections after parsing the block
// so that parsing can continue and find any other errors.
if (inst._insencode != NULL) {
parse_err(SYNERR, "Multiple ins_encode sections defined\n");
return;
}
// Set encode class of this instruction.
inst._insencode = encrule;
}
@ -3044,6 +3051,13 @@ void ADLParser::ins_encode_parse(InstructForm& inst) {
next_char(); // move past ';'
skipws(); // be friendly to oper_parse()
// Check for duplicate ins_encode sections after parsing the block
// so that parsing can continue and find any other errors.
if (inst._insencode != NULL) {
parse_err(SYNERR, "Multiple ins_encode sections defined\n");
return;
}
// Debug Stuff
if (_AD._adl_debug > 1) fprintf(stderr,"Instruction Encode: %s\n", ec_name);

View File

@ -33,6 +33,7 @@
#include "compiler/compileBroker.hpp"
#include "interpreter/bytecode.hpp"
#include "runtime/sharedRuntime.hpp"
#include "runtime/compilationPolicy.hpp"
#include "utilities/bitMap.inline.hpp"
class BlockListBuilder VALUE_OBJ_CLASS_SPEC {
@ -3395,8 +3396,8 @@ void GraphBuilder::fill_sync_handler(Value lock, BlockBegin* sync_handler, bool
bool GraphBuilder::try_inline_full(ciMethod* callee, bool holder_known) {
assert(!callee->is_native(), "callee must not be native");
if (count_backedges() && callee->has_loops()) {
INLINE_BAILOUT("too complex for tiered");
if (CompilationPolicy::policy()->should_not_inline(compilation()->env(), callee)) {
INLINE_BAILOUT("inlining prohibited by policy");
}
// first perform tests of things it's not possible to inline
if (callee->has_exception_handlers() &&

View File

@ -2799,7 +2799,7 @@ void LIRGenerator::do_Invoke(Invoke* x) {
// Load CallSite object from constant pool cache.
__ oop2reg(cpcache->constant_encoding(), tmp);
__ load(new LIR_Address(tmp, call_site_offset, T_OBJECT), tmp);
__ move_wide(new LIR_Address(tmp, call_site_offset, T_OBJECT), tmp);
// Load target MethodHandle from CallSite object.
__ load(new LIR_Address(tmp, java_lang_invoke_CallSite::target_offset_in_bytes(), T_OBJECT), receiver);

View File

@ -642,7 +642,7 @@ void NullCheckVisitor::do_NewInstance (NewInstance* x) { nce()->handle_Ne
void NullCheckVisitor::do_NewTypeArray (NewTypeArray* x) { nce()->handle_NewArray(x); }
void NullCheckVisitor::do_NewObjectArray (NewObjectArray* x) { nce()->handle_NewArray(x); }
void NullCheckVisitor::do_NewMultiArray (NewMultiArray* x) { nce()->handle_NewArray(x); }
void NullCheckVisitor::do_CheckCast (CheckCast* x) {}
void NullCheckVisitor::do_CheckCast (CheckCast* x) { nce()->clear_last_explicit_null_check(); }
void NullCheckVisitor::do_InstanceOf (InstanceOf* x) {}
void NullCheckVisitor::do_MonitorEnter (MonitorEnter* x) { nce()->handle_AccessMonitor(x); }
void NullCheckVisitor::do_MonitorExit (MonitorExit* x) { nce()->handle_AccessMonitor(x); }

View File

@ -383,8 +383,10 @@ JRT_ENTRY(void, Runtime1::post_jvmti_exception_throw(JavaThread* thread))
}
JRT_END
// This is a helper to allow us to safepoint but allow the outer entry
// to be safepoint free if we need to do an osr
// counter_overflow() is called from within C1-compiled methods. The enclosing method is the method
// associated with the top activation record. The inlinee (that is possibly included in the enclosing
// method) method oop is passed as an argument. In order to do that it is embedded in the code as
// a constant.
static nmethod* counter_overflow_helper(JavaThread* THREAD, int branch_bci, methodOopDesc* m) {
nmethod* osr_nm = NULL;
methodHandle method(THREAD, m);
@ -420,7 +422,7 @@ static nmethod* counter_overflow_helper(JavaThread* THREAD, int branch_bci, meth
bci = branch_bci + offset;
}
osr_nm = CompilationPolicy::policy()->event(enclosing_method, method, branch_bci, bci, level, THREAD);
osr_nm = CompilationPolicy::policy()->event(enclosing_method, method, branch_bci, bci, level, nm, THREAD);
return osr_nm;
}

View File

@ -36,6 +36,7 @@ class ciCallProfile : StackObj {
private:
// Fields are initialized directly by ciMethod::call_profile_at_bci.
friend class ciMethod;
friend class ciMethodHandle;
enum { MorphismLimit = 2 }; // Max call site's morphism we care about
int _limit; // number of receivers have been determined
@ -58,10 +59,10 @@ private:
public:
// Note: The following predicates return false for invalid profiles:
bool has_receiver(int i) { return _limit > i; }
int morphism() { return _morphism; }
bool has_receiver(int i) const { return _limit > i; }
int morphism() const { return _morphism; }
int count() { return _count; }
int count() const { return _count; }
int receiver_count(int i) {
assert(i < _limit, "out of Call Profile MorphismLimit");
return _receiver_count[i];

View File

@ -50,6 +50,7 @@
#include "oops/oop.inline.hpp"
#include "oops/oop.inline2.hpp"
#include "prims/jvmtiExport.hpp"
#include "prims/methodHandleWalk.hpp"
#include "runtime/init.hpp"
#include "runtime/reflection.hpp"
#include "runtime/sharedRuntime.hpp"
@ -371,6 +372,7 @@ bool ciEnv::check_klass_accessibility(ciKlass* accessing_klass,
// ------------------------------------------------------------------
// ciEnv::get_klass_by_name_impl
ciKlass* ciEnv::get_klass_by_name_impl(ciKlass* accessing_klass,
constantPoolHandle cpool,
ciSymbol* name,
bool require_local) {
ASSERT_IN_VM;
@ -386,7 +388,7 @@ ciKlass* ciEnv::get_klass_by_name_impl(ciKlass* accessing_klass,
sym->utf8_length()-2,
KILL_COMPILE_ON_FATAL_(_unloaded_ciinstance_klass));
ciSymbol* strippedname = get_symbol(strippedsym);
return get_klass_by_name_impl(accessing_klass, strippedname, require_local);
return get_klass_by_name_impl(accessing_klass, cpool, strippedname, require_local);
}
// Check for prior unloaded klass. The SystemDictionary's answers
@ -443,6 +445,7 @@ ciKlass* ciEnv::get_klass_by_name_impl(ciKlass* accessing_klass,
// Get element ciKlass recursively.
ciKlass* elem_klass =
get_klass_by_name_impl(accessing_klass,
cpool,
get_symbol(elem_sym),
require_local);
if (elem_klass != NULL && elem_klass->is_loaded()) {
@ -451,6 +454,19 @@ ciKlass* ciEnv::get_klass_by_name_impl(ciKlass* accessing_klass,
}
}
if (found_klass() == NULL && !cpool.is_null() && cpool->has_preresolution()) {
// Look inside the constant pool for pre-resolved class entries.
for (int i = cpool->length() - 1; i >= 1; i--) {
if (cpool->tag_at(i).is_klass()) {
klassOop kls = cpool->resolved_klass_at(i);
if (Klass::cast(kls)->name() == sym) {
found_klass = KlassHandle(THREAD, kls);
break;
}
}
}
}
if (found_klass() != NULL) {
// Found it. Build a CI handle.
return get_object(found_klass())->as_klass();
@ -468,6 +484,7 @@ ciKlass* ciEnv::get_klass_by_name(ciKlass* accessing_klass,
ciSymbol* klass_name,
bool require_local) {
GUARDED_VM_ENTRY(return get_klass_by_name_impl(accessing_klass,
constantPoolHandle(),
klass_name,
require_local);)
}
@ -508,13 +525,14 @@ ciKlass* ciEnv::get_klass_by_index_impl(constantPoolHandle cpool,
if (klass.is_null()) {
// Not found in constant pool. Use the name to do the lookup.
ciKlass* k = get_klass_by_name_impl(accessor,
cpool,
get_symbol(klass_name),
false);
// Calculate accessibility the hard way.
if (!k->is_loaded()) {
is_accessible = false;
} else if (k->loader() != accessor->loader() &&
get_klass_by_name_impl(accessor, k->name(), true) == NULL) {
get_klass_by_name_impl(accessor, cpool, k->name(), true) == NULL) {
// Loaded only remotely. Not linked yet.
is_accessible = false;
} else {
@ -565,7 +583,7 @@ ciConstant ciEnv::get_constant_by_index_impl(constantPoolHandle cpool,
index = cpc_entry->constant_pool_index();
oop obj = cpc_entry->f1();
if (obj != NULL) {
assert(obj->is_instance(), "must be an instance");
assert(obj->is_instance() || obj->is_array(), "must be a Java reference");
ciObject* ciobj = get_object(obj);
return ciConstant(T_OBJECT, ciobj);
}
@ -607,7 +625,7 @@ ciConstant ciEnv::get_constant_by_index_impl(constantPoolHandle cpool,
return ciConstant(T_OBJECT, klass->java_mirror());
} else if (tag.is_object()) {
oop obj = cpool->object_at(index);
assert(obj->is_instance(), "must be an instance");
assert(obj->is_instance() || obj->is_array(), "must be a Java reference");
ciObject* ciobj = get_object(obj);
return ciConstant(T_OBJECT, ciobj);
} else if (tag.is_method_type()) {
@ -729,9 +747,35 @@ ciMethod* ciEnv::get_method_by_index_impl(constantPoolHandle cpool,
Symbol* name_sym = cpool->name_ref_at(index);
Symbol* sig_sym = cpool->signature_ref_at(index);
if (cpool->has_preresolution()
|| (holder == ciEnv::MethodHandle_klass() &&
methodOopDesc::is_method_handle_invoke_name(name_sym))) {
// Short-circuit lookups for JSR 292-related call sites.
// That is, do not rely only on name-based lookups, because they may fail
// if the names are not resolvable in the boot class loader (7056328).
switch (bc) {
case Bytecodes::_invokevirtual:
case Bytecodes::_invokeinterface:
case Bytecodes::_invokespecial:
case Bytecodes::_invokestatic:
{
methodOop m = constantPoolOopDesc::method_at_if_loaded(cpool, index, bc);
if (m != NULL) {
return get_object(m)->as_method();
}
}
}
}
if (holder_is_accessible) { // Our declared holder is loaded.
instanceKlass* lookup = declared_holder->get_instanceKlass();
methodOop m = lookup_method(accessor->get_instanceKlass(), lookup, name_sym, sig_sym, bc);
if (m != NULL &&
(bc == Bytecodes::_invokestatic
? instanceKlass::cast(m->method_holder())->is_not_initialized()
: !instanceKlass::cast(m->method_holder())->is_loaded())) {
m = NULL;
}
if (m != NULL) {
// We found the method.
return get_object(m)->as_method();
@ -1046,7 +1090,7 @@ void ciEnv::register_method(ciMethod* target,
// ciEnv::find_system_klass
ciKlass* ciEnv::find_system_klass(ciSymbol* klass_name) {
VM_ENTRY_MARK;
return get_klass_by_name_impl(NULL, klass_name, false);
return get_klass_by_name_impl(NULL, constantPoolHandle(), klass_name, false);
}
// ------------------------------------------------------------------

View File

@ -137,6 +137,7 @@ private:
// Implementation methods for loading and constant pool access.
ciKlass* get_klass_by_name_impl(ciKlass* accessing_klass,
constantPoolHandle cpool,
ciSymbol* klass_name,
bool require_local);
ciKlass* get_klass_by_index_impl(constantPoolHandle cpool,

View File

@ -287,7 +287,7 @@ ciType* ciField::compute_type() {
}
ciType* ciField::compute_type_impl() {
ciKlass* type = CURRENT_ENV->get_klass_by_name_impl(_holder, _signature, false);
ciKlass* type = CURRENT_ENV->get_klass_by_name_impl(_holder, constantPoolHandle(), _signature, false);
if (!type->is_primitive_type() && is_shared()) {
// We must not cache a pointer to an unshared type, in a shared field.
bool type_is_also_shared = false;

View File

@ -125,7 +125,8 @@ ciMethod::ciMethod(methodHandle h_m) : ciObject(h_m) {
_name = env->get_symbol(h_m()->name());
_holder = env->get_object(h_m()->method_holder())->as_instance_klass();
ciSymbol* sig_symbol = env->get_symbol(h_m()->signature());
_signature = new (env->arena()) ciSignature(_holder, sig_symbol);
constantPoolHandle cpool = h_m()->constants();
_signature = new (env->arena()) ciSignature(_holder, cpool, sig_symbol);
_method_data = NULL;
// Take a snapshot of these values, so they will be commensurate with the MDO.
if (ProfileInterpreter || TieredCompilation) {
@ -152,7 +153,7 @@ ciMethod::ciMethod(ciInstanceKlass* holder,
// These fields are always filled in.
_name = name;
_holder = holder;
_signature = new (CURRENT_ENV->arena()) ciSignature(_holder, signature);
_signature = new (CURRENT_ENV->arena()) ciSignature(_holder, constantPoolHandle(), signature);
_intrinsic_id = vmIntrinsics::_none;
_liveness = NULL;
_can_be_statically_bound = false;
@ -1009,6 +1010,12 @@ int ciMethod::comp_level() {
return 0;
}
int ciMethod::highest_osr_comp_level() {
check_is_loaded();
VM_ENTRY_MARK;
return get_methodOop()->highest_osr_comp_level();
}
// ------------------------------------------------------------------
// ciMethod::instructions_size
//

View File

@ -158,6 +158,7 @@ class ciMethod : public ciObject {
int interpreter_throwout_count() const { check_is_loaded(); return _interpreter_throwout_count; }
int comp_level();
int highest_osr_comp_level();
Bytecodes::Code java_code_at_bci(int bci) {
address bcp = code() + bci;

View File

@ -41,9 +41,19 @@ ciMethod* ciMethodHandle::get_adapter_impl(bool is_invokedynamic) const {
VM_ENTRY_MARK;
Handle h(get_oop());
methodHandle callee(_callee->get_methodOop());
assert(callee->is_method_handle_invoke(), "");
oop mt1 = callee->method_handle_type();
oop mt2 = java_lang_invoke_MethodHandle::type(h());
if (!java_lang_invoke_MethodType::equals(mt1, mt2)) {
if (PrintMiscellaneous && (Verbose || WizardMode)) {
tty->print_cr("ciMethodHandle::get_adapter: types not equal");
mt1->print(); mt2->print();
}
return NULL;
}
// We catch all exceptions here that could happen in the method
// handle compiler and stop the VM.
MethodHandleCompiler mhc(h, callee, _profile->count(), is_invokedynamic, THREAD);
MethodHandleCompiler mhc(h, callee->name(), callee->signature(), _profile.count(), is_invokedynamic, THREAD);
if (!HAS_PENDING_EXCEPTION) {
methodHandle m = mhc.compile(THREAD);
if (!HAS_PENDING_EXCEPTION) {
@ -53,7 +63,7 @@ ciMethod* ciMethodHandle::get_adapter_impl(bool is_invokedynamic) const {
if (PrintMiscellaneous && (Verbose || WizardMode)) {
tty->print("*** ciMethodHandle::get_adapter => ");
PENDING_EXCEPTION->print();
tty->print("*** get_adapter (%s): ", is_invokedynamic ? "indy" : "mh"); ((ciObject*)this)->print(); //@@
tty->print("*** get_adapter (%s): ", is_invokedynamic ? "indy" : "mh"); ((ciObject*)this)->print();
}
CLEAR_PENDING_EXCEPTION;
return NULL;

View File

@ -36,7 +36,7 @@ class ciMethodHandle : public ciInstance {
private:
ciMethod* _callee;
ciMethod* _caller;
ciCallProfile* _profile;
ciCallProfile _profile;
// Return an adapter for this MethodHandle.
ciMethod* get_adapter_impl(bool is_invokedynamic) const;
@ -49,8 +49,7 @@ public:
ciMethodHandle(instanceHandle h_i) :
ciInstance(h_i),
_callee(NULL),
_caller(NULL),
_profile(NULL)
_caller(NULL)
{}
// What kind of ciObject is this?
@ -58,7 +57,7 @@ public:
void set_callee(ciMethod* m) { _callee = m; }
void set_caller(ciMethod* m) { _caller = m; }
void set_call_profile(ciCallProfile* profile) { _profile = profile; }
void set_call_profile(ciCallProfile profile) { _profile = profile; }
// Return an adapter for a MethodHandle call.
ciMethod* get_method_handle_adapter() const { return get_adapter(false); }

View File

@ -93,6 +93,7 @@ ciKlass* ciObjArrayKlass::element_klass() {
// element klass by name.
_element_klass = CURRENT_THREAD_ENV->get_klass_by_name_impl(
this,
constantPoolHandle(),
construct_array_name(base_element_klass()->name(),
dimension() - 1),
false);

View File

@ -187,7 +187,7 @@ jobject ciObject::constant_encoding() {
// ciObject::can_be_constant
bool ciObject::can_be_constant() {
if (ScavengeRootsInCode >= 1) return true; // now everybody can encode as a constant
return handle() == NULL || !is_scavengable();
return handle() == NULL || is_perm();
}
// ------------------------------------------------------------------
@ -204,7 +204,7 @@ bool ciObject::should_be_constant() {
return true;
}
}
return handle() == NULL || !is_scavengable();
return handle() == NULL || is_perm();
}

View File

@ -108,7 +108,7 @@ public:
int hash();
// Tells if this oop has an encoding as a constant.
// True if is_scavengable is false.
// True if is_perm is true.
// Also true if ScavengeRootsInCode is non-zero.
// If it does not have an encoding, the compiler is responsible for
// making other arrangements for dealing with the oop.
@ -116,7 +116,7 @@ public:
bool can_be_constant();
// Tells if this oop should be made a constant.
// True if is_scavengable is false or ScavengeRootsInCode > 1.
// True if is_perm is true or ScavengeRootsInCode > 1.
bool should_be_constant();
// Is this object guaranteed to be in the permanent part of the heap?

View File

@ -35,7 +35,7 @@
// ------------------------------------------------------------------
// ciSignature::ciSignature
ciSignature::ciSignature(ciKlass* accessing_klass, ciSymbol* symbol) {
ciSignature::ciSignature(ciKlass* accessing_klass, constantPoolHandle cpool, ciSymbol* symbol) {
ASSERT_IN_VM;
EXCEPTION_CONTEXT;
_accessing_klass = accessing_klass;
@ -64,7 +64,7 @@ ciSignature::ciSignature(ciKlass* accessing_klass, ciSymbol* symbol) {
CLEAR_PENDING_EXCEPTION;
} else {
ciSymbol* klass_name = env->get_symbol(name);
type = env->get_klass_by_name_impl(_accessing_klass, klass_name, false);
type = env->get_klass_by_name_impl(_accessing_klass, cpool, klass_name, false);
}
}
_types->append(type);

View File

@ -44,7 +44,7 @@ private:
friend class ciMethod;
ciSignature(ciKlass* accessing_klass, ciSymbol* signature);
ciSignature(ciKlass* accessing_klass, constantPoolHandle cpool, ciSymbol* signature);
void get_all_klasses();

View File

@ -3287,9 +3287,9 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name,
// Fields allocation: oops fields in super and sub classes are together.
if( nonstatic_field_size > 0 && super_klass() != NULL &&
super_klass->nonstatic_oop_map_size() > 0 ) {
int map_size = super_klass->nonstatic_oop_map_size();
int map_count = super_klass->nonstatic_oop_map_count();
OopMapBlock* first_map = super_klass->start_of_nonstatic_oop_maps();
OopMapBlock* last_map = first_map + map_size - 1;
OopMapBlock* last_map = first_map + map_count - 1;
int next_offset = last_map->offset() + (last_map->count() * heapOopSize);
if (next_offset == next_nonstatic_field_offset) {
allocation_style = 0; // allocate oops first

View File

@ -1258,7 +1258,6 @@ class BacktraceBuilder: public StackObj {
objArrayOop _methods;
typeArrayOop _bcis;
int _index;
bool _dirty;
No_Safepoint_Verifier _nsv;
public:
@ -1272,37 +1271,13 @@ class BacktraceBuilder: public StackObj {
};
// constructor for new backtrace
BacktraceBuilder(TRAPS): _methods(NULL), _bcis(NULL), _head(NULL), _dirty(false) {
BacktraceBuilder(TRAPS): _methods(NULL), _bcis(NULL), _head(NULL) {
expand(CHECK);
_backtrace = _head;
_index = 0;
}
void flush() {
// The following appears to have been an optimization to save from
// doing a barrier for each individual store into the _methods array,
// but rather to do it for the entire array after the series of writes.
// That optimization seems to have been lost when compressed oops was
// implemented. However, the extra card-marks below was left in place,
// but is now redundant because the individual stores into the
// _methods array already execute the barrier code. CR 6918185 has
// been filed so the original code may be restored by deferring the
// barriers until after the entire sequence of stores, thus re-enabling
// the intent of the original optimization. In the meantime the redundant
// card mark below is now disabled.
if (_dirty && _methods != NULL) {
#if 0
BarrierSet* bs = Universe::heap()->barrier_set();
assert(bs->has_write_ref_array_opt(), "Barrier set must have ref array opt");
bs->write_ref_array((HeapWord*)_methods->base(), _methods->length());
#endif
_dirty = false;
}
}
void expand(TRAPS) {
flush();
objArrayHandle old_head(THREAD, _head);
Pause_No_Safepoint_Verifier pnsv(&_nsv);
@ -1328,7 +1303,6 @@ class BacktraceBuilder: public StackObj {
}
oop backtrace() {
flush();
return _backtrace();
}
@ -1342,7 +1316,6 @@ class BacktraceBuilder: public StackObj {
_methods->obj_at_put(_index, method);
_bcis->ushort_at_put(_index, bci);
_index++;
_dirty = true;
}
methodOop current_method() {
@ -2574,6 +2547,18 @@ Symbol* java_lang_invoke_MethodType::as_signature(oop mt, bool intern_if_not_fou
return name;
}
bool java_lang_invoke_MethodType::equals(oop mt1, oop mt2) {
if (rtype(mt1) != rtype(mt2))
return false;
if (ptype_count(mt1) != ptype_count(mt2))
return false;
for (int i = ptype_count(mt1) - 1; i >= 0; i--) {
if (ptype(mt1, i) != ptype(mt2, i))
return false;
}
return true;
}
oop java_lang_invoke_MethodType::rtype(oop mt) {
assert(is_instance(mt), "must be a MethodType");
return mt->obj_field(_rtype_offset);

View File

@ -1079,6 +1079,8 @@ class java_lang_invoke_MethodType: AllStatic {
return obj != NULL && obj->klass() == SystemDictionary::MethodType_klass();
}
static bool equals(oop mt1, oop mt2);
// Accessors for code generation:
static int rtype_offset_in_bytes() { return _rtype_offset; }
static int ptypes_offset_in_bytes() { return _ptypes_offset; }

View File

@ -2367,6 +2367,8 @@ methodOop SystemDictionary::find_method_handle_invoke(Symbol* name,
// Link m to his method type, if it is suitably generic.
oop mtform = java_lang_invoke_MethodType::form(mt());
if (mtform != NULL && mt() == java_lang_invoke_MethodTypeForm::erasedType(mtform)
// vmlayout must be an invokeExact:
&& name_id == vmSymbols::VM_SYMBOL_ENUM_NAME(invokeExact_name)
&& java_lang_invoke_MethodTypeForm::vmlayout_offset_in_bytes() > 0) {
java_lang_invoke_MethodTypeForm::init_vmlayout(mtform, m());
}

View File

@ -152,6 +152,7 @@ class SymbolPropertyTable;
template(DirectMethodHandle_klass, java_lang_invoke_DirectMethodHandle, Pre_JSR292) \
template(MethodType_klass, java_lang_invoke_MethodType, Pre_JSR292) \
template(MethodTypeForm_klass, java_lang_invoke_MethodTypeForm, Pre_JSR292) \
template(BootstrapMethodError_klass, java_lang_BootstrapMethodError, Pre_JSR292) \
template(WrongMethodTypeException_klass, java_lang_invoke_WrongMethodTypeException, Pre_JSR292) \
template(CallSite_klass, java_lang_invoke_CallSite, Pre_JSR292) \
/* Note: MethodHandle must be first, and CallSite last in group */ \

View File

@ -148,6 +148,7 @@
template(java_lang_InstantiationException, "java/lang/InstantiationException") \
template(java_lang_InstantiationError, "java/lang/InstantiationError") \
template(java_lang_InterruptedException, "java/lang/InterruptedException") \
template(java_lang_BootstrapMethodError, "java/lang/BootstrapMethodError") \
template(java_lang_LinkageError, "java/lang/LinkageError") \
template(java_lang_NegativeArraySizeException, "java/lang/NegativeArraySizeException") \
template(java_lang_NoSuchFieldException, "java/lang/NoSuchFieldException") \

View File

@ -1810,7 +1810,7 @@ public:
void maybe_print(oop* p) {
if (_print_nm == NULL) return;
if (!_detected_scavenge_root) _print_nm->print_on(tty, "new scavenge root");
tty->print_cr(""PTR_FORMAT"[offset=%d] detected non-perm oop "PTR_FORMAT" (found at "PTR_FORMAT")",
tty->print_cr(""PTR_FORMAT"[offset=%d] detected scavengable oop "PTR_FORMAT" (found at "PTR_FORMAT")",
_print_nm, (int)((intptr_t)p - (intptr_t)_print_nm),
(intptr_t)(*p), (intptr_t)p);
(*p)->print();
@ -1832,7 +1832,9 @@ void nmethod::preserve_callee_argument_oops(frame fr, const RegisterMap *reg_map
if (!method()->is_native()) {
SimpleScopeDesc ssd(this, fr.pc());
Bytecode_invoke call(ssd.method(), ssd.bci());
bool has_receiver = call.has_receiver();
// compiled invokedynamic call sites have an implicit receiver at
// resolution time, so make sure it gets GC'ed.
bool has_receiver = !call.is_invokestatic();
Symbol* signature = call.signature();
fr.oops_compiled_arguments_do(signature, has_receiver, reg_map, f);
}
@ -2311,7 +2313,7 @@ public:
_nm->print_nmethod(true);
_ok = false;
}
tty->print_cr("*** non-perm oop "PTR_FORMAT" found at "PTR_FORMAT" (offset %d)",
tty->print_cr("*** scavengable oop "PTR_FORMAT" found at "PTR_FORMAT" (offset %d)",
(intptr_t)(*p), (intptr_t)p, (int)((intptr_t)p - (intptr_t)_nm));
(*p)->print();
}
@ -2324,7 +2326,7 @@ void nmethod::verify_scavenge_root_oops() {
DebugScavengeRoot debug_scavenge_root(this);
oops_do(&debug_scavenge_root);
if (!debug_scavenge_root.ok())
fatal("found an unadvertised bad non-perm oop in the code cache");
fatal("found an unadvertised bad scavengable oop in the code cache");
}
assert(scavenge_root_not_marked(), "");
}

View File

@ -109,7 +109,7 @@ class xmlStream;
class nmethod : public CodeBlob {
friend class VMStructs;
friend class NMethodSweeper;
friend class CodeCache; // non-perm oops
friend class CodeCache; // scavengable oops
private:
// Shared fields for all nmethod's
methodOop _method;
@ -466,17 +466,17 @@ public:
bool is_at_poll_return(address pc);
bool is_at_poll_or_poll_return(address pc);
// Non-perm oop support
// Scavengable oop support
bool on_scavenge_root_list() const { return (_scavenge_root_state & 1) != 0; }
protected:
enum { npl_on_list = 0x01, npl_marked = 0x10 };
void set_on_scavenge_root_list() { _scavenge_root_state = npl_on_list; }
enum { sl_on_list = 0x01, sl_marked = 0x10 };
void set_on_scavenge_root_list() { _scavenge_root_state = sl_on_list; }
void clear_on_scavenge_root_list() { _scavenge_root_state = 0; }
// assertion-checking and pruning logic uses the bits of _scavenge_root_state
#ifndef PRODUCT
void set_scavenge_root_marked() { _scavenge_root_state |= npl_marked; }
void clear_scavenge_root_marked() { _scavenge_root_state &= ~npl_marked; }
bool scavenge_root_not_marked() { return (_scavenge_root_state &~ npl_on_list) == 0; }
void set_scavenge_root_marked() { _scavenge_root_state |= sl_marked; }
void clear_scavenge_root_marked() { _scavenge_root_state &= ~sl_marked; }
bool scavenge_root_not_marked() { return (_scavenge_root_state &~ sl_on_list) == 0; }
// N.B. there is no positive marked query, and we only use the not_marked query for asserts.
#endif //PRODUCT
nmethod* scavenge_root_link() const { return _scavenge_root_link; }

View File

@ -44,7 +44,7 @@ address PcDesc::real_pc(const nmethod* code) const {
void PcDesc::print(nmethod* code) {
#ifndef PRODUCT
ResourceMark rm;
tty->print_cr("PcDesc(pc=0x%lx offset=%x):", real_pc(code), pc_offset());
tty->print_cr("PcDesc(pc=0x%lx offset=%x bits=%x):", real_pc(code), pc_offset(), _flags.bits);
if (scope_decode_offset() == DebugInformationRecorder::serialized_null) {
return;

View File

@ -300,12 +300,23 @@ void CompileTask::print_compilation_impl(outputStream* st, methodOop method, int
st->print("%7d ", (int) st->time_stamp().milliseconds()); // print timestamp
st->print("%4d ", compile_id); // print compilation number
// For unloaded methods the transition to zombie occurs after the
// method is cleared so it's impossible to report accurate
// information for that case.
bool is_synchronized = false;
bool has_exception_handler = false;
bool is_native = false;
if (method != NULL) {
is_synchronized = method->is_synchronized();
has_exception_handler = method->has_exception_handler();
is_native = method->is_native();
}
// method attributes
const char compile_type = is_osr_method ? '%' : ' ';
const char sync_char = method->is_synchronized() ? 's' : ' ';
const char exception_char = method->has_exception_handler() ? '!' : ' ';
const char sync_char = is_synchronized ? 's' : ' ';
const char exception_char = has_exception_handler ? '!' : ' ';
const char blocking_char = is_blocking ? 'b' : ' ';
const char native_char = method->is_native() ? 'n' : ' ';
const char native_char = is_native ? 'n' : ' ';
// print method attributes
st->print("%c%c%c%c%c ", compile_type, sync_char, exception_char, blocking_char, native_char);
@ -316,11 +327,15 @@ void CompileTask::print_compilation_impl(outputStream* st, methodOop method, int
}
st->print(" "); // more indent
method->print_short_name(st);
if (is_osr_method) {
st->print(" @ %d", osr_bci);
if (method == NULL) {
st->print("(method)");
} else {
method->print_short_name(st);
if (is_osr_method) {
st->print(" @ %d", osr_bci);
}
st->print(" (%d bytes)", method->code_size());
}
st->print(" (%d bytes)", method->code_size());
if (msg != NULL) {
st->print(" %s", msg);

View File

@ -78,21 +78,46 @@ bool Disassembler::load_library() {
char buf[JVM_MAXPATHLEN];
os::jvm_path(buf, sizeof(buf));
int jvm_offset = -1;
int lib_offset = -1;
{
// Match "jvm[^/]*" in jvm_path.
const char* base = buf;
const char* p = strrchr(buf, '/');
if (p != NULL) lib_offset = p - base + 1;
p = strstr(p ? p : base, "jvm");
if (p != NULL) jvm_offset = p - base;
}
// Find the disassembler shared library.
// Search for several paths derived from libjvm, in this order:
// 1. <home>/jre/lib/<arch>/<vm>/libhsdis-<arch>.so (for compatibility)
// 2. <home>/jre/lib/<arch>/<vm>/hsdis-<arch>.so
// 3. <home>/jre/lib/<arch>/hsdis-<arch>.so
// 4. hsdis-<arch>.so (using LD_LIBRARY_PATH)
if (jvm_offset >= 0) {
// Find the disassembler next to libjvm.so.
// 1. <home>/jre/lib/<arch>/<vm>/libhsdis-<arch>.so
strcpy(&buf[jvm_offset], hsdis_library_name);
strcat(&buf[jvm_offset], os::dll_file_extension());
_library = os::dll_load(buf, ebuf, sizeof ebuf);
if (_library == NULL) {
// 2. <home>/jre/lib/<arch>/<vm>/hsdis-<arch>.so
strcpy(&buf[lib_offset], hsdis_library_name);
strcat(&buf[lib_offset], os::dll_file_extension());
_library = os::dll_load(buf, ebuf, sizeof ebuf);
}
if (_library == NULL) {
// 3. <home>/jre/lib/<arch>/hsdis-<arch>.so
buf[lib_offset - 1] = '\0';
const char* p = strrchr(buf, '/');
if (p != NULL) {
lib_offset = p - buf + 1;
strcpy(&buf[lib_offset], hsdis_library_name);
strcat(&buf[lib_offset], os::dll_file_extension());
_library = os::dll_load(buf, ebuf, sizeof ebuf);
}
}
}
if (_library == NULL) {
// Try a free-floating lookup.
// 4. hsdis-<arch>.so (using LD_LIBRARY_PATH)
strcpy(&buf[0], hsdis_library_name);
strcat(&buf[0], os::dll_file_extension());
_library = os::dll_load(buf, ebuf, sizeof ebuf);
@ -249,7 +274,13 @@ address decode_env::handle_event(const char* event, address arg) {
return arg;
}
} else if (match(event, "mach")) {
output()->print_cr("[Disassembling for mach='%s']", arg);
static char buffer[32] = { 0, };
if (strcmp(buffer, (const char*)arg) != 0 ||
strlen((const char*)arg) > sizeof(buffer) - 1) {
// Only print this when the mach changes
strncpy(buffer, (const char*)arg, sizeof(buffer) - 1);
output()->print_cr("[Disassembling for mach='%s']", arg);
}
} else if (match(event, "format bytes-per-line")) {
_bytes_per_line = (int) (intptr_t) arg;
} else {

View File

@ -638,7 +638,9 @@ void DerivedPointerTable::add(oop *derived_loc, oop *base_loc) {
assert(*derived_loc != (oop)base_loc, "location already added");
assert(_list != NULL, "list must exist");
intptr_t offset = value_of_loc(derived_loc) - value_of_loc(base_loc);
assert(offset >= -1000000, "wrong derived pointer info");
// This assert is invalid because derived pointers can be
// arbitrarily far away from their base.
// assert(offset >= -1000000, "wrong derived pointer info");
if (TraceDerivedPointers) {
tty->print_cr(

View File

@ -1833,8 +1833,6 @@ CompactibleFreeListSpace::removeChunkFromIndexedFreeList(FreeChunk* fc) {
}
)
_indexedFreeList[size].removeChunk(fc);
debug_only(fc->clearNext());
debug_only(fc->clearPrev());
NOT_PRODUCT(
if (FLSVerifyIndexTable) {
verifyIndexedFreeList(size);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -407,6 +407,11 @@ class CompactibleFreeListSpace: public CompactibleSpace {
void save_sweep_limit() {
_sweep_limit = BlockOffsetArrayUseUnallocatedBlock ?
unallocated_block() : end();
if (CMSTraceSweeper) {
gclog_or_tty->print_cr(">>>>> Saving sweep limit " PTR_FORMAT
" for space [" PTR_FORMAT "," PTR_FORMAT ") <<<<<<",
_sweep_limit, bottom(), end());
}
}
NOT_PRODUCT(
void clear_sweep_limit() { _sweep_limit = NULL; }

View File

@ -2716,6 +2716,10 @@ void CMSCollector::gc_epilogue(bool full) {
bitMapLock()->unlock();
releaseFreelistLocks();
if (!CleanChunkPoolAsync) {
Chunk::clean_chunk_pool();
}
_between_prologue_and_epilogue = false; // ready for next cycle
}
@ -7888,60 +7892,64 @@ SweepClosure::SweepClosure(CMSCollector* collector,
assert(_limit >= _sp->bottom() && _limit <= _sp->end(),
"sweep _limit out of bounds");
if (CMSTraceSweeper) {
gclog_or_tty->print("\n====================\nStarting new sweep\n");
gclog_or_tty->print_cr("\n====================\nStarting new sweep with limit " PTR_FORMAT,
_limit);
}
}
// We need this destructor to reclaim any space at the end
// of the space, which do_blk below may not yet have added back to
// the free lists.
void SweepClosure::print_on(outputStream* st) const {
tty->print_cr("_sp = [" PTR_FORMAT "," PTR_FORMAT ")",
_sp->bottom(), _sp->end());
tty->print_cr("_limit = " PTR_FORMAT, _limit);
tty->print_cr("_freeFinger = " PTR_FORMAT, _freeFinger);
NOT_PRODUCT(tty->print_cr("_last_fc = " PTR_FORMAT, _last_fc);)
tty->print_cr("_inFreeRange = %d, _freeRangeInFreeLists = %d, _lastFreeRangeCoalesced = %d",
_inFreeRange, _freeRangeInFreeLists, _lastFreeRangeCoalesced);
}
#ifndef PRODUCT
// Assertion checking only: no useful work in product mode --
// however, if any of the flags below become product flags,
// you may need to review this code to see if it needs to be
// enabled in product mode.
SweepClosure::~SweepClosure() {
assert_lock_strong(_freelistLock);
assert(_limit >= _sp->bottom() && _limit <= _sp->end(),
"sweep _limit out of bounds");
// Flush any remaining coterminal free run as a single
// coalesced chunk to the appropriate free list.
if (inFreeRange()) {
assert(freeFinger() < _limit, "freeFinger points too high");
flush_cur_free_chunk(freeFinger(), pointer_delta(_limit, freeFinger()));
if (CMSTraceSweeper) {
gclog_or_tty->print("Sweep: last chunk: ");
gclog_or_tty->print("put_free_blk 0x%x ("SIZE_FORMAT") [coalesced:"SIZE_FORMAT"]\n",
freeFinger(), pointer_delta(_limit, freeFinger()), lastFreeRangeCoalesced());
}
} // else nothing to flush
NOT_PRODUCT(
if (Verbose && PrintGC) {
gclog_or_tty->print("Collected "SIZE_FORMAT" objects, "
SIZE_FORMAT " bytes",
_numObjectsFreed, _numWordsFreed*sizeof(HeapWord));
gclog_or_tty->print_cr("\nLive "SIZE_FORMAT" objects, "
SIZE_FORMAT" bytes "
"Already free "SIZE_FORMAT" objects, "SIZE_FORMAT" bytes",
_numObjectsLive, _numWordsLive*sizeof(HeapWord),
_numObjectsAlreadyFree, _numWordsAlreadyFree*sizeof(HeapWord));
size_t totalBytes = (_numWordsFreed + _numWordsLive + _numWordsAlreadyFree) *
sizeof(HeapWord);
gclog_or_tty->print_cr("Total sweep: "SIZE_FORMAT" bytes", totalBytes);
warning("inFreeRange() should have been reset; dumping state of SweepClosure");
print();
ShouldNotReachHere();
}
if (Verbose && PrintGC) {
gclog_or_tty->print("Collected "SIZE_FORMAT" objects, " SIZE_FORMAT " bytes",
_numObjectsFreed, _numWordsFreed*sizeof(HeapWord));
gclog_or_tty->print_cr("\nLive "SIZE_FORMAT" objects, "
SIZE_FORMAT" bytes "
"Already free "SIZE_FORMAT" objects, "SIZE_FORMAT" bytes",
_numObjectsLive, _numWordsLive*sizeof(HeapWord),
_numObjectsAlreadyFree, _numWordsAlreadyFree*sizeof(HeapWord));
size_t totalBytes = (_numWordsFreed + _numWordsLive + _numWordsAlreadyFree)
* sizeof(HeapWord);
gclog_or_tty->print_cr("Total sweep: "SIZE_FORMAT" bytes", totalBytes);
if (PrintCMSStatistics && CMSVerifyReturnedBytes) {
size_t indexListReturnedBytes = _sp->sumIndexedFreeListArrayReturnedBytes();
size_t dictReturnedBytes = _sp->dictionary()->sumDictReturnedBytes();
size_t returnedBytes = indexListReturnedBytes + dictReturnedBytes;
gclog_or_tty->print("Returned "SIZE_FORMAT" bytes", returnedBytes);
gclog_or_tty->print(" Indexed List Returned "SIZE_FORMAT" bytes",
indexListReturnedBytes);
gclog_or_tty->print_cr(" Dictionary Returned "SIZE_FORMAT" bytes",
dictReturnedBytes);
}
if (PrintCMSStatistics && CMSVerifyReturnedBytes) {
size_t indexListReturnedBytes = _sp->sumIndexedFreeListArrayReturnedBytes();
size_t dictReturnedBytes = _sp->dictionary()->sumDictReturnedBytes();
size_t returnedBytes = indexListReturnedBytes + dictReturnedBytes;
gclog_or_tty->print("Returned "SIZE_FORMAT" bytes", returnedBytes);
gclog_or_tty->print(" Indexed List Returned "SIZE_FORMAT" bytes",
indexListReturnedBytes);
gclog_or_tty->print_cr(" Dictionary Returned "SIZE_FORMAT" bytes",
dictReturnedBytes);
}
)
// Now, in debug mode, just null out the sweep_limit
NOT_PRODUCT(_sp->clear_sweep_limit();)
}
if (CMSTraceSweeper) {
gclog_or_tty->print("end of sweep\n================\n");
gclog_or_tty->print_cr("end of sweep with _limit = " PTR_FORMAT "\n================",
_limit);
}
}
#endif // PRODUCT
void SweepClosure::initialize_free_range(HeapWord* freeFinger,
bool freeRangeInFreeLists) {
@ -8001,15 +8009,17 @@ size_t SweepClosure::do_blk_careful(HeapWord* addr) {
// we started the sweep, it may no longer be one because heap expansion
// may have caused us to coalesce the block ending at the address _limit
// with a newly expanded chunk (this happens when _limit was set to the
// previous _end of the space), so we may have stepped past _limit; see CR 6977970.
// previous _end of the space), so we may have stepped past _limit:
// see the following Zeno-like trail of CRs 6977970, 7008136, 7042740.
if (addr >= _limit) { // we have swept up to or past the limit: finish up
assert(_limit >= _sp->bottom() && _limit <= _sp->end(),
"sweep _limit out of bounds");
assert(addr < _sp->end(), "addr out of bounds");
// Flush any remaining coterminal free run as a single
// Flush any free range we might be holding as a single
// coalesced chunk to the appropriate free list.
if (inFreeRange()) {
assert(freeFinger() < _limit, "finger points too high");
assert(freeFinger() >= _sp->bottom() && freeFinger() < _limit,
err_msg("freeFinger() " PTR_FORMAT" is out-of-bounds", freeFinger()));
flush_cur_free_chunk(freeFinger(),
pointer_delta(addr, freeFinger()));
if (CMSTraceSweeper) {
@ -8033,7 +8043,16 @@ size_t SweepClosure::do_blk_careful(HeapWord* addr) {
res = fc->size();
do_already_free_chunk(fc);
debug_only(_sp->verifyFreeLists());
assert(res == fc->size(), "Don't expect the size to change");
// If we flush the chunk at hand in lookahead_and_flush()
// and it's coalesced with a preceding chunk, then the
// process of "mangling" the payload of the coalesced block
// will cause erasure of the size information from the
// (erstwhile) header of all the coalesced blocks but the
// first, so the first disjunct in the assert will not hold
// in that specific case (in which case the second disjunct
// will hold).
assert(res == fc->size() || ((HeapWord*)fc) + res >= _limit,
"Otherwise the size info doesn't change at this step");
NOT_PRODUCT(
_numObjectsAlreadyFree++;
_numWordsAlreadyFree += res;
@ -8103,7 +8122,7 @@ size_t SweepClosure::do_blk_careful(HeapWord* addr) {
//
void SweepClosure::do_already_free_chunk(FreeChunk* fc) {
size_t size = fc->size();
const size_t size = fc->size();
// Chunks that cannot be coalesced are not in the
// free lists.
if (CMSTestInFreeList && !fc->cantCoalesce()) {
@ -8112,7 +8131,7 @@ void SweepClosure::do_already_free_chunk(FreeChunk* fc) {
}
// a chunk that is already free, should not have been
// marked in the bit map
HeapWord* addr = (HeapWord*) fc;
HeapWord* const addr = (HeapWord*) fc;
assert(!_bitMap->isMarked(addr), "free chunk should be unmarked");
// Verify that the bit map has no bits marked between
// addr and purported end of this block.
@ -8149,7 +8168,7 @@ void SweepClosure::do_already_free_chunk(FreeChunk* fc) {
}
} else {
// the midst of a free range, we are coalescing
debug_only(record_free_block_coalesced(fc);)
print_free_block_coalesced(fc);
if (CMSTraceSweeper) {
gclog_or_tty->print(" -- pick up free block 0x%x (%d)\n", fc, size);
}
@ -8173,6 +8192,10 @@ void SweepClosure::do_already_free_chunk(FreeChunk* fc) {
}
}
}
// Note that if the chunk is not coalescable (the else arm
// below), we unconditionally flush, without needing to do
// a "lookahead," as we do below.
if (inFreeRange()) lookahead_and_flush(fc, size);
} else {
// Code path common to both original and adaptive free lists.
@ -8191,8 +8214,8 @@ size_t SweepClosure::do_garbage_chunk(FreeChunk* fc) {
// This is a chunk of garbage. It is not in any free list.
// Add it to a free list or let it possibly be coalesced into
// a larger chunk.
HeapWord* addr = (HeapWord*) fc;
size_t size = CompactibleFreeListSpace::adjustObjectSize(oop(addr)->size());
HeapWord* const addr = (HeapWord*) fc;
const size_t size = CompactibleFreeListSpace::adjustObjectSize(oop(addr)->size());
if (_sp->adaptive_freelists()) {
// Verify that the bit map has no bits marked between
@ -8205,7 +8228,6 @@ size_t SweepClosure::do_garbage_chunk(FreeChunk* fc) {
// start of a new free range
assert(size > 0, "A free range should have a size");
initialize_free_range(addr, false);
} else {
// this will be swept up when we hit the end of the
// free range
@ -8235,6 +8257,9 @@ size_t SweepClosure::do_garbage_chunk(FreeChunk* fc) {
// addr and purported end of just dead object.
_bitMap->verifyNoOneBitsInRange(addr + 1, addr + size);
}
assert(_limit >= addr + size,
"A freshly garbage chunk can't possibly straddle over _limit");
if (inFreeRange()) lookahead_and_flush(fc, size);
return size;
}
@ -8284,8 +8309,8 @@ size_t SweepClosure::do_live_chunk(FreeChunk* fc) {
(!_collector->should_unload_classes()
|| oop(addr)->is_parsable()),
"Should be an initialized object");
// Note that there are objects used during class redefinition
// (e.g., merge_cp in VM_RedefineClasses::merge_cp_and_rewrite()
// Note that there are objects used during class redefinition,
// e.g. merge_cp in VM_RedefineClasses::merge_cp_and_rewrite(),
// which are discarded with their is_conc_safe state still
// false. These object may be floating garbage so may be
// seen here. If they are floating garbage their size
@ -8307,7 +8332,7 @@ void SweepClosure::do_post_free_or_garbage_chunk(FreeChunk* fc,
size_t chunkSize) {
// do_post_free_or_garbage_chunk() should only be called in the case
// of the adaptive free list allocator.
bool fcInFreeLists = fc->isFree();
const bool fcInFreeLists = fc->isFree();
assert(_sp->adaptive_freelists(), "Should only be used in this case.");
assert((HeapWord*)fc <= _limit, "sweep invariant");
if (CMSTestInFreeList && fcInFreeLists) {
@ -8318,11 +8343,11 @@ void SweepClosure::do_post_free_or_garbage_chunk(FreeChunk* fc,
gclog_or_tty->print_cr(" -- pick up another chunk at 0x%x (%d)", fc, chunkSize);
}
HeapWord* addr = (HeapWord*) fc;
HeapWord* const fc_addr = (HeapWord*) fc;
bool coalesce;
size_t left = pointer_delta(addr, freeFinger());
size_t right = chunkSize;
const size_t left = pointer_delta(fc_addr, freeFinger());
const size_t right = chunkSize;
switch (FLSCoalescePolicy) {
// numeric value forms a coalition aggressiveness metric
case 0: { // never coalesce
@ -8355,15 +8380,15 @@ void SweepClosure::do_post_free_or_garbage_chunk(FreeChunk* fc,
// If the chunk is in a free range and either we decided to coalesce above
// or the chunk is near the large block at the end of the heap
// (isNearLargestChunk() returns true), then coalesce this chunk.
bool doCoalesce = inFreeRange() &&
(coalesce || _g->isNearLargestChunk((HeapWord*)fc));
const bool doCoalesce = inFreeRange()
&& (coalesce || _g->isNearLargestChunk(fc_addr));
if (doCoalesce) {
// Coalesce the current free range on the left with the new
// chunk on the right. If either is on a free list,
// it must be removed from the list and stashed in the closure.
if (freeRangeInFreeLists()) {
FreeChunk* ffc = (FreeChunk*)freeFinger();
assert(ffc->size() == pointer_delta(addr, freeFinger()),
FreeChunk* const ffc = (FreeChunk*)freeFinger();
assert(ffc->size() == pointer_delta(fc_addr, freeFinger()),
"Size of free range is inconsistent with chunk size.");
if (CMSTestInFreeList) {
assert(_sp->verifyChunkInFreeLists(ffc),
@ -8380,13 +8405,14 @@ void SweepClosure::do_post_free_or_garbage_chunk(FreeChunk* fc,
_sp->removeFreeChunkFromFreeLists(fc);
}
set_lastFreeRangeCoalesced(true);
print_free_block_coalesced(fc);
} else { // not in a free range and/or should not coalesce
// Return the current free range and start a new one.
if (inFreeRange()) {
// In a free range but cannot coalesce with the right hand chunk.
// Put the current free range into the free lists.
flush_cur_free_chunk(freeFinger(),
pointer_delta(addr, freeFinger()));
pointer_delta(fc_addr, freeFinger()));
}
// Set up for new free range. Pass along whether the right hand
// chunk is in the free lists.
@ -8394,6 +8420,42 @@ void SweepClosure::do_post_free_or_garbage_chunk(FreeChunk* fc,
}
}
// Lookahead flush:
// If we are tracking a free range, and this is the last chunk that
// we'll look at because its end crosses past _limit, we'll preemptively
// flush it along with any free range we may be holding on to. Note that
// this can be the case only for an already free or freshly garbage
// chunk. If this block is an object, it can never straddle
// over _limit. The "straddling" occurs when _limit is set at
// the previous end of the space when this cycle started, and
// a subsequent heap expansion caused the previously co-terminal
// free block to be coalesced with the newly expanded portion,
// thus rendering _limit a non-block-boundary making it dangerous
// for the sweeper to step over and examine.
void SweepClosure::lookahead_and_flush(FreeChunk* fc, size_t chunk_size) {
assert(inFreeRange(), "Should only be called if currently in a free range.");
HeapWord* const eob = ((HeapWord*)fc) + chunk_size;
assert(_sp->used_region().contains(eob - 1),
err_msg("eob = " PTR_FORMAT " out of bounds wrt _sp = [" PTR_FORMAT "," PTR_FORMAT ")"
" when examining fc = " PTR_FORMAT "(" SIZE_FORMAT ")",
_limit, _sp->bottom(), _sp->end(), fc, chunk_size));
if (eob >= _limit) {
assert(eob == _limit || fc->isFree(), "Only a free chunk should allow us to cross over the limit");
if (CMSTraceSweeper) {
gclog_or_tty->print_cr("_limit " PTR_FORMAT " reached or crossed by block "
"[" PTR_FORMAT "," PTR_FORMAT ") in space "
"[" PTR_FORMAT "," PTR_FORMAT ")",
_limit, fc, eob, _sp->bottom(), _sp->end());
}
// Return the storage we are tracking back into the free lists.
if (CMSTraceSweeper) {
gclog_or_tty->print_cr("Flushing ... ");
}
assert(freeFinger() < eob, "Error");
flush_cur_free_chunk( freeFinger(), pointer_delta(eob, freeFinger()));
}
}
void SweepClosure::flush_cur_free_chunk(HeapWord* chunk, size_t size) {
assert(inFreeRange(), "Should only be called if currently in a free range.");
assert(size > 0,
@ -8419,6 +8481,8 @@ void SweepClosure::flush_cur_free_chunk(HeapWord* chunk, size_t size) {
}
_sp->addChunkAndRepairOffsetTable(chunk, size,
lastFreeRangeCoalesced());
} else if (CMSTraceSweeper) {
gclog_or_tty->print_cr("Already in free list: nothing to flush");
}
set_inFreeRange(false);
set_freeRangeInFreeLists(false);
@ -8477,13 +8541,14 @@ void SweepClosure::do_yield_work(HeapWord* addr) {
bool debug_verifyChunkInFreeLists(FreeChunk* fc) {
return debug_cms_space->verifyChunkInFreeLists(fc);
}
#endif
void SweepClosure::record_free_block_coalesced(FreeChunk* fc) const {
void SweepClosure::print_free_block_coalesced(FreeChunk* fc) const {
if (CMSTraceSweeper) {
gclog_or_tty->print("Sweep:coal_free_blk 0x%x (%d)\n", fc, fc->size());
gclog_or_tty->print_cr("Sweep:coal_free_blk " PTR_FORMAT " (" SIZE_FORMAT ")",
fc, fc->size());
}
}
#endif
// CMSIsAliveClosure
bool CMSIsAliveClosure::do_object_b(oop obj) {

View File

@ -1701,9 +1701,9 @@ class SweepClosure: public BlkClosureCareful {
CMSCollector* _collector; // collector doing the work
ConcurrentMarkSweepGeneration* _g; // Generation being swept
CompactibleFreeListSpace* _sp; // Space being swept
HeapWord* _limit;// the address at which the sweep should stop because
// we do not expect blocks eligible for sweeping past
// that address.
HeapWord* _limit;// the address at or above which the sweep should stop
// because we do not expect newly garbage blocks
// eligible for sweeping past that address.
Mutex* _freelistLock; // Free list lock (in space)
CMSBitMap* _bitMap; // Marking bit map (in
// generation)
@ -1750,6 +1750,10 @@ class SweepClosure: public BlkClosureCareful {
void do_post_free_or_garbage_chunk(FreeChunk *fc, size_t chunkSize);
// Process a free chunk during sweeping.
void do_already_free_chunk(FreeChunk *fc);
// Work method called when processing an already free or a
// freshly garbage chunk to do a lookahead and possibly a
// premptive flush if crossing over _limit.
void lookahead_and_flush(FreeChunk* fc, size_t chunkSize);
// Process a garbage chunk during sweeping.
size_t do_garbage_chunk(FreeChunk *fc);
// Process a live chunk during sweeping.
@ -1758,8 +1762,6 @@ class SweepClosure: public BlkClosureCareful {
// Accessors.
HeapWord* freeFinger() const { return _freeFinger; }
void set_freeFinger(HeapWord* v) { _freeFinger = v; }
size_t freeRangeSize() const { return _freeRangeSize; }
void set_freeRangeSize(size_t v) { _freeRangeSize = v; }
bool inFreeRange() const { return _inFreeRange; }
void set_inFreeRange(bool v) { _inFreeRange = v; }
bool lastFreeRangeCoalesced() const { return _lastFreeRangeCoalesced; }
@ -1779,14 +1781,16 @@ class SweepClosure: public BlkClosureCareful {
void do_yield_work(HeapWord* addr);
// Debugging/Printing
void record_free_block_coalesced(FreeChunk* fc) const PRODUCT_RETURN;
void print_free_block_coalesced(FreeChunk* fc) const;
public:
SweepClosure(CMSCollector* collector, ConcurrentMarkSweepGeneration* g,
CMSBitMap* bitMap, bool should_yield);
~SweepClosure();
~SweepClosure() PRODUCT_RETURN;
size_t do_blk_careful(HeapWord* addr);
void print() const { print_on(tty); }
void print_on(outputStream *st) const;
};
// Closures related to weak references processing

View File

@ -114,17 +114,11 @@ class FreeChunk VALUE_OBJ_CLASS_SPEC {
linkNext(ptr);
if (ptr != NULL) ptr->linkPrev(this);
}
void linkAfterNonNull(FreeChunk* ptr) {
assert(ptr != NULL, "precondition violation");
linkNext(ptr);
ptr->linkPrev(this);
}
void linkNext(FreeChunk* ptr) { _next = ptr; }
void linkPrev(FreeChunk* ptr) {
LP64_ONLY(if (UseCompressedOops) _prev = ptr; else)
_prev = (FreeChunk*)((intptr_t)ptr | 0x1);
}
void clearPrev() { _prev = NULL; }
void clearNext() { _next = NULL; }
void markNotFree() {
// Set _prev (klass) to null before (if) clearing the mark word below

View File

@ -300,8 +300,21 @@ void FreeList::verify_stats() const {
// dictionary for example, this might be the first block and
// in that case there would be no place that we could record
// the stats (which are kept in the block itself).
assert(_allocation_stats.prevSweep() + _allocation_stats.splitBirths() + 1 // Total Stock + 1
>= _allocation_stats.splitDeaths() + (ssize_t)count(), "Conservation Principle");
assert((_allocation_stats.prevSweep() + _allocation_stats.splitBirths()
+ _allocation_stats.coalBirths() + 1) // Total Production Stock + 1
>= (_allocation_stats.splitDeaths() + _allocation_stats.coalDeaths()
+ (ssize_t)count()), // Total Current Stock + depletion
err_msg("FreeList " PTR_FORMAT " of size " SIZE_FORMAT
" violates Conservation Principle: "
"prevSweep(" SIZE_FORMAT ")"
" + splitBirths(" SIZE_FORMAT ")"
" + coalBirths(" SIZE_FORMAT ") + 1 >= "
" splitDeaths(" SIZE_FORMAT ")"
" coalDeaths(" SIZE_FORMAT ")"
" + count(" SSIZE_FORMAT ")",
this, _size, _allocation_stats.prevSweep(), _allocation_stats.splitBirths(),
_allocation_stats.splitBirths(), _allocation_stats.splitDeaths(),
_allocation_stats.coalDeaths(), count()));
}
void FreeList::assert_proper_lock_protection_work() const {

File diff suppressed because it is too large Load Diff

View File

@ -131,22 +131,22 @@ class CMBitMap : public CMBitMapRO {
void mark(HeapWord* addr) {
assert(_bmStartWord <= addr && addr < (_bmStartWord + _bmWordSize),
"outside underlying space?");
_bm.at_put(heapWordToOffset(addr), true);
_bm.set_bit(heapWordToOffset(addr));
}
void clear(HeapWord* addr) {
assert(_bmStartWord <= addr && addr < (_bmStartWord + _bmWordSize),
"outside underlying space?");
_bm.at_put(heapWordToOffset(addr), false);
_bm.clear_bit(heapWordToOffset(addr));
}
bool parMark(HeapWord* addr) {
assert(_bmStartWord <= addr && addr < (_bmStartWord + _bmWordSize),
"outside underlying space?");
return _bm.par_at_put(heapWordToOffset(addr), true);
return _bm.par_set_bit(heapWordToOffset(addr));
}
bool parClear(HeapWord* addr) {
assert(_bmStartWord <= addr && addr < (_bmStartWord + _bmWordSize),
"outside underlying space?");
return _bm.par_at_put(heapWordToOffset(addr), false);
return _bm.par_clear_bit(heapWordToOffset(addr));
}
void markRange(MemRegion mr);
void clearAll();
@ -605,10 +605,10 @@ public:
void mark_stack_pop(oop* arr, int max, int* n) {
_markStack.par_pop_arr(arr, max, n);
}
size_t mark_stack_size() { return _markStack.size(); }
size_t mark_stack_size() { return _markStack.size(); }
size_t partial_mark_stack_size_target() { return _markStack.maxElems()/3; }
bool mark_stack_overflow() { return _markStack.overflow(); }
bool mark_stack_empty() { return _markStack.isEmpty(); }
bool mark_stack_overflow() { return _markStack.overflow(); }
bool mark_stack_empty() { return _markStack.isEmpty(); }
// (Lock-free) Manipulation of the region stack
bool region_stack_push_lock_free(MemRegion mr) {
@ -736,12 +736,14 @@ public:
// will dump the contents of its reference fields, as well as
// liveness information for the object and its referents. The dump
// will be written to a file with the following name:
// G1PrintReachableBaseFile + "." + str. use_prev_marking decides
// whether the prev (use_prev_marking == true) or next
// (use_prev_marking == false) marking information will be used to
// determine the liveness of each object / referent. If all is true,
// all objects in the heap will be dumped, otherwise only the live
// ones. In the dump the following symbols / abbreviations are used:
// G1PrintReachableBaseFile + "." + str.
// vo decides whether the prev (vo == UsePrevMarking), the next
// (vo == UseNextMarking) marking information, or the mark word
// (vo == UseMarkWord) will be used to determine the liveness of
// each object / referent.
// If all is true, all objects in the heap will be dumped, otherwise
// only the live ones. In the dump the following symbols / breviations
// are used:
// M : an explicitly live object (its bitmap bit is set)
// > : an implicitly live object (over tams)
// O : an object outside the G1 heap (typically: in the perm gen)
@ -749,7 +751,7 @@ public:
// AND MARKED : indicates that an object is both explicitly and
// implicitly live (it should be one or the other, not both)
void print_reachable(const char* str,
bool use_prev_marking, bool all) PRODUCT_RETURN;
VerifyOption vo, bool all) PRODUCT_RETURN;
// Clear the next marking bitmap (will be called concurrently).
void clearNextBitmap();
@ -809,10 +811,19 @@ public:
// It indicates that a new collection set is being chosen.
void newCSet();
// It registers a collection set heap region with CM. This is used
// to determine whether any heap regions are located above the finger.
void registerCSetRegion(HeapRegion* hr);
// Resets the region fields of any active CMTask whose region fields
// are in the collection set (i.e. the region currently claimed by
// the CMTask will be evacuated and may be used, subsequently, as
// an alloc region). When this happens the region fields in the CMTask
// are stale and, hence, should be cleared causing the worker thread
// to claim a new region.
void reset_active_task_region_fields_in_cset();
// Registers the maximum region-end associated with a set of
// regions with CM. Again this is used to determine whether any
// heap regions are located above the finger.
@ -822,8 +833,9 @@ public:
// _min_finger then we need to gray objects.
// This routine is like registerCSetRegion but for an entire
// collection of regions.
if (max_finger > _min_finger)
if (max_finger > _min_finger) {
_should_gray_objects = true;
}
}
// Returns "true" if at least one mark has been completed.
@ -869,14 +881,18 @@ public:
// The following indicate whether a given verbose level has been
// set. Notice that anything above stats is conditional to
// _MARKING_VERBOSE_ having been set to 1
bool verbose_stats()
{ return _verbose_level >= stats_verbose; }
bool verbose_low()
{ return _MARKING_VERBOSE_ && _verbose_level >= low_verbose; }
bool verbose_medium()
{ return _MARKING_VERBOSE_ && _verbose_level >= medium_verbose; }
bool verbose_high()
{ return _MARKING_VERBOSE_ && _verbose_level >= high_verbose; }
bool verbose_stats() {
return _verbose_level >= stats_verbose;
}
bool verbose_low() {
return _MARKING_VERBOSE_ && _verbose_level >= low_verbose;
}
bool verbose_medium() {
return _MARKING_VERBOSE_ && _verbose_level >= medium_verbose;
}
bool verbose_high() {
return _MARKING_VERBOSE_ && _verbose_level >= high_verbose;
}
};
// A class representing a marking task.
@ -919,7 +935,7 @@ private:
double _start_time_ms;
// the oop closure used for iterations over oops
OopClosure* _oop_closure;
G1CMOopClosure* _cm_oop_closure;
// the region this task is scanning, NULL if we're not scanning any
HeapRegion* _curr_region;
@ -1039,9 +1055,6 @@ private:
void setup_for_region(HeapRegion* hr);
// it brings up-to-date the limit of the region
void update_region_limit();
// it resets the local fields after a task has finished scanning a
// region
void giveup_current_region();
// called when either the words scanned or the refs visited limit
// has been reached
@ -1055,8 +1068,9 @@ private:
// respective limit and calls reached_limit() if they have
void check_limits() {
if (_words_scanned >= _words_scanned_limit ||
_refs_reached >= _refs_reached_limit)
_refs_reached >= _refs_reached_limit) {
reached_limit();
}
}
// this is supposed to be called regularly during a marking step as
// it checks a bunch of conditions that might cause the marking step
@ -1094,6 +1108,11 @@ public:
// exit the termination protocol after it's entered it.
virtual bool should_exit_termination();
// Resets the local region fields after a task has finished scanning a
// region; or when they have become stale as a result of the region
// being evacuated.
void giveup_current_region();
HeapWord* finger() { return _finger; }
bool has_aborted() { return _has_aborted; }
@ -1111,32 +1130,17 @@ public:
// Clears any recorded partially scanned region
void clear_aborted_region() { set_aborted_region(MemRegion()); }
void set_oop_closure(OopClosure* oop_closure) {
_oop_closure = oop_closure;
}
void set_cm_oop_closure(G1CMOopClosure* cm_oop_closure);
// It grays the object by marking it and, if necessary, pushing it
// on the local queue
void deal_with_reference(oop obj);
inline void deal_with_reference(oop obj);
// It scans an object and visits its children.
void scan_object(oop obj) {
assert(_nextMarkBitMap->isMarked((HeapWord*) obj), "invariant");
if (_cm->verbose_high())
gclog_or_tty->print_cr("[%d] we're scanning object "PTR_FORMAT,
_task_id, (void*) obj);
size_t obj_size = obj->size();
_words_scanned += obj_size;
obj->oop_iterate(_oop_closure);
statsOnly( ++_objs_scanned );
check_limits();
}
void scan_object(oop obj);
// It pushes an object on the local queue.
void push(oop obj);
inline void push(oop obj);
// These two move entries to/from the global stack.
void move_entries_to_global_stack();

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